Forum Discussion

PerBonomi's avatar
7 years ago

Float replies that aren't a solution, but are important, within a topic

Saw a Product Idea for this, so I thought I'd share my custom solution. Perhaps not for the faint of heart, but when you get it working it'll be fun :)

 

This adds an option to all the replies in a topic, which lets you float them to the top. Like Solutions, but not marked as such. Sometimes you want to float a reply to make it easier to find and stand out, without implying that it's a solution.

 

Looks like this:

 

 

You will need three things for this:

  1. Component that shows the floated reply
  2. Option in the reply's message options to float it
  3. Endpoint to make the magic work

And they are these:

 

One:

(I removed my CSS, but just reply here if you'd like to have it and I'll send it over. It'd just take a lot of space here).

<#assign topic_id = page.context.message.uniqueId/>

<#-- insert your preferred method of testing a user's role here -->
if user has role:
	<#assign usercanUnfloat = true/>
else
	<#assign usercanUnfloat = false/>
/if

<#-- ask Lithium to add a metadata field for messages -->
<#assign float_ids = restadmin("/messages/id/${topic_id}/metadata/key/spotify.floated_replies").value/>
<#if float_ids != ""> <#-- if this topic has floated replies -->
	<#list float_ids?split(",") as msg_id>
		<#if msg_id != "">
			<#assign query_msg = restadmin("2.0","/search?q=" + "SELECT view_href,author.id,author.login,current_revision.last_edit_time,search_snippet,body FROM messages WHERE id = '${msg_id}'"?url) />
			<#list query_msg.data.items as q>
				<#assign author_id = q.author.id/>
				<#assign author_login = q.author.login/>
				<#assign msg_url = q.view_href/>
				<#assign msg_post_time_date = q.current_revision.last_edit_time?number_to_datetime?datetime?string[cust_user_date_format]/>
				<#assign msg_post_time_time = q.current_revision.last_edit_time?number_to_datetime?datetime?string[cust_user_time_format]/>
				<#attempt>
					<#assign msg_body = q.search_snippet/>
				<#recover>
					<#assign msg_body = q.body/>
				</#attempt>
				<#assign query_author = restadmin("2.0","/search?q=" + "SELECT view_href,rank,avatar.message FROM users WHERE id = '${author_id}'"?url) />
				<#list query_author.data.items as a>
					<#assign author_url = a.view_href/>
					<#assign author_avatar = a.avatar.message/>
					<#assign author_rank_name = a.rank.name/>
					<#if a.rank.bold == true>
						<#assign author_rank_bold = "bold"/>
					<#else>
						<#assign author_rank_bold = "normal"/>
					</#if>
					<#assign author_rank_color = a.rank.color/>
					<#attempt>
						<#assign author_rank_icon_url = a.rank.icon_left/>
						<#assign show_icon = true/>
					<#recover>
						<#assign show_icon = false/>
					</#attempt>
					<div class="cust-floater-container">
						<div class="cust-floater-message">
							<div class="lia-quilt-column lia-quilt-column-24 lia-quilt-column-single lia-quilt-column-header-content">
								<div class="lia-quilt-column-alley lia-quilt-column-alley-single">
									<div class="lia-message-author-avatar lia-component-user-avatar">
										<div class="UserAvatar lia-user-avatar lia-component-common-widget-user-avatar">	
											<a class="UserAvatar lia-link-navigation" tabindex="-1" target="_self" href="${author_url}"><img class="lia-user-avatar-message" title="${author_login}" alt="${author_login}" src="${author_avatar}"></a>
										</div>
									</div>
									<div class="lia-message-author-username lia-component-user-name">
										<span class="UserName lia-user-name lia-user-rank-${author_rank_name?replace(' ','-')}">
										<a class="lia-link-navigation lia-page-link lia-user-name-link" style="color:#${author_rank_color}" target="_self" href="${author_url}"><span class="">${author_login}</span></a>
										</span>
									</div>
									<div class="lia-message-author-rank lia-component-author-rank-name">${author_rank_name}</div>
									<p class="lia-message-dates lia-message-post-date lia-component-post-date-last-edited">
										<span class="DateTime lia-message-posted-on lia-component-common-widget-date">
											<span class="local-date">‎${msg_post_time_date}</span>
											<span class="local-time">${msg_post_time_time}</span>
										</span>
									</p>
									<#-- button to let users un-float this reply -->
									<#if usercanUnfloat == true>
										<div class="lia-message-unfloat">
											<#-- create an endpoint that will edit the topic's metadata field and remove the id of this floated reply -->
											<a class="lia-link-navigation lia-page-link" href="ENDPOINT_URL_HERE?msgId=${msg_id}&topicId=${topic_id}&do=remove&url=${http.request.url}">Un-Float as Top Answer</a>
										</div>
									</#if>
								</div>
							</div>
							<div class="lia-message-body-wrapper lia-component-message-view-widget-body">
								<div id="bodydisplay" class="lia-message-body">
									<div class="lia-message-body-content">
										${msg_body}
									</div>
								</div>
								<#-- the floated reply shows a snippet, just in case the floated reply is one looong post. This links to the full reply. -->
								<div class="cust-readmore"><a href="${msg_url}">Read more</a></div>
							</div>
						</div>	
					</div>	
				</#list>
			</#list>
		</#if>
	</#list>

</#if>

Two:

(I added this to the Forum Topic Page and the Idea Page. You might need to tweak the JavaScript to work with your specific layout and classes)

<#-- insert your preferred method of testing a user's role here -->
<#-- if user has role: -->

<#if userIsAdminMod == true>
	<#attempt>
			<#assign topic_id = page.context.message.uniqueId/>
			<#assign float_ids = restadmin("/messages/id/${topic_id}/metadata/key/spotify.floated_replies").value/>
			<@liaAddScript>
			<#if float_ids == "">
				var arFloats = new Array();
			<#else>
				var arFloats = [${float_ids?trim}];
			</#if>
			$(document).ready(function() {
				$(".lia-component-reply-list .lia-message-view, .CommentList .lia-message-view").each(function () {			
					var obj_msg = $(this);
					var obj_href = obj_msg.attr('class');
					var UidIndex = obj_href.indexOf("message-uid-");
					if(UidIndex != -1) {
						UidIndex = UidIndex + 12;
						var msg_id = obj_href.slice(UidIndex, obj_href.length);
					} else {
						var msg_id = 0;
					}
					if(arFloats.indexOf(parseInt(msg_id)) == -1) {
						var action_do = 'add';
						var action_text = 'Float';
					} else {
						var action_do = 'remove';
						var action_text = 'Un-Float';
					}
					var obj_add = '<li><a class="lia-link-navigation cust-action-float-message" rel="nofollow" href="/spotify/plugins/custom/spotify/spotify/end_float_reply?msgId=' + msg_id + '&topicId=${topic_id}&do=' + action_do +'&url=${http.request.url}">' + action_text + ' as Top Answer</a></li>' +
						'<li class="cust-item-float-sep" aria-hidden="true"><span class="lia-separator lia-component-common-widget-link-separator"><span class="lia-separator-post"></span><span class="lia-separator-pre"></span></span></li>';
						
					obj_msg.find(".lia-component-forums-action-highlight-message").each(function() {
						obj_menu_item = $(this).parent('li');
						obj_menu_item.before( obj_add );
					});
				});
			});
			</@liaAddScript>
	<#recover>
	</#attempt>
</#if>

Three:

(The endpoint that makes it all work. Turned out smaller than I thought it would).

<#-- insert your preferred method of testing a user's role here -->
<#-- if user has role: -->

<#if userIsAdminMod == true>
	<#assign status = ""/>
	<#assign msg_id = http.request.parameters.name.get("msgId", "")?string />
	<#assign topic_id = http.request.parameters.name.get("topicId", "")?string />
	<#assign action = http.request.parameters.name.get("do", "")?string />
	<#assign return_url = http.request.parameters.name.get("url", "")?string />
	<#if msg_id != "" && topic_id != "" && action != "">
		<#assign float_ids = restadmin("/messages/id/${topic_id}/metadata/key/spotify.floated_replies").value/>
		<#assign float_ids_seq = []/>
		<#if action == "add">
			<#if float_ids == "">
				<#assign float_ids_new = msg_id/>
			<#else>
				<#list float_ids?split(",") as f_id>
					<#if f_id != "" && f_id?number != msg_id?number>
						<#assign float_ids_seq = float_ids_seq + [f_id]/>
					</#if>
				</#list>
				<#assign float_ids_seq = float_ids_seq + [msg_id]/>
				<#if (float_ids_seq?size > 2)>
					<#assign float_ids_seq_new = []/>
					<#list float_ids_seq?reverse as f_id>
						<#if (f_id_index < 2)>
							<#assign float_ids_seq_new = float_ids_seq_new + [f_id]/>
						</#if>
					</#list>
					<#assign float_ids_new = float_ids_seq_new?join(",")/>
				<#else>
					<#assign float_ids_new = float_ids_seq?join(",")/>
				</#if>
			</#if>
		<#elseif action == "remove">
			<#list float_ids?split(",")?reverse as f_id>
				<#if f_id != "" && f_id?number != msg_id?number>
					<#assign float_ids_seq = float_ids_seq + [f_id]/>
				</#if>
			</#list>
			<#if (float_ids_seq?size > 0)>
				<#assign float_ids_new = float_ids_seq?join(",")/>
			<#else>
				<#assign float_ids_new = ""/>
			</#if>	
		</#if>
		<#if float_ids_new??>
			<#assign result = restadmin("/messages/id/${topic_id}/metadata/key/spotify.floated_replies/set?value=${float_ids_new}")/>
		</#if>
	</#if>
	<script>
	<#if result?? && result.error?has_content>
				history.replaceState( {} , 'Float Message', '${return_url}' );
				window.history.back();
	<#else>
				history.replaceState( {} , 'Float Message', '${return_url}' );
				window.history.back();
	</#if>
	</script>
</#if>
  • PerBonomi- Thanks for sharing wonderful code.

     

    The fourth thing you can add to it

    1. Ccomponent that shows the floated reply
    2. Option in the reply's message options to float it
    3. Eendpoint to make the magic work
    4. Metadata field for messages (Raise a ticket to lithium support for this)

    In your case, the metadata name is spotify.floated_replies which will be different for every community e.g demo.floated_replies etc. 

     

     

  • ClaudiusH's avatar
    ClaudiusH
    Khoros Alumni (Retired)
    Thanks for sharing the code, Per.

    Going a bit beyond the developer scope here:
    Which member type is allowed in your community to float messages?
    I can see it being used in support scenarios for "we are investigating" status updates. Any other situations this is useful?
    • PerBonomi's avatar
      PerBonomi
      Boss

      We let Admins, Moderators and higher tier Super Users float.

       

      I think it mainly came about because we have many threads that are very long and we regularly have customers complaining that we're not responding, even though we, for example, responded two pages (1 day) ago. For those buried staff responses it's very helpful.