Widget logic

Unsolved Technical Support
  • Hi - I'd like to display a message based on specific criteria using the widgets.

    For example.

    1. Get the user who created the original post (effectively, asked a question)
    2. Ensure we are in a category where Q&A has been enabled
    3. Compare that to the logged in user - if it's the same, then we trigger the widget message which is effectively asking them to choose a best answer

    Any pointers ?

    Thanks

  • I think the best way is to create a new widget with all that custom logic. The widgets are given the data that is used to render the page so it is easy to determine if you are in a topic and get the original poster. The logged in user is also passed into so you can compare it. Here is some sample code.

    Widget.renderQnAWidget = async function (widget) {
    	const tplData = widget.templateData;
    	const isQuestion = parseInt(tplData.isQuestion, 10) === 1;
    	const isSolved = parseInt(tplData.isSolved, 10) === 1;
    	// dont render widget if we are not on a topic or topic is not a question or it is already solved
    	if (!tplData.template.topic || !isQuestion || isSolved) {
    		return null;
    	}
    	const originalPoster = parseInt(tplData.uid, 10);
    	if (originalPoster === parseInt(widget.uid, 10)) {
    		widget.html = 'Please select an answer';
    	}
    	return null;
    };
    
  • @baris Thanks. Can you give me an idea of how I can use this - is it just a case of dropping into a new HTML widget using <script> tags ?

  • No, this would have to go into a new or existing plugin. It is essentially a new widget with custom logic that would live on the server side. Like the widgets we have in nodebb-widget-essentials.

  • @baris Ok, thanks.

  • @baris Seems I can do most of this in a standard HTML widget - I'm only missing the OP ID and the logged in user ID for analysis in relation to triggering the message or not - an example below

    <!-- IF isQuestion -->
    <!-- IF !isSolved -->
    <div class="bmacmain">
    <div class="card"><h5 class="card-header">Did this topic help you?</h5><div class="card-body">
    <div class="bmacmessage">Please don't forget to click on "Mark this post as the correct answer" whenever the information provided helps you. Original posters help the community find answers faster by identifying the correct answer. 
    </div>
    </div>
    </div></div>
    <br>
    <style>
    #bmac {
    display: none;
    }
    </style>
    <!-- ENDIF !isQuestion -->
    <!-- ENDIF !isSolved -->
    
  • You can try {{{ if (uid === loggedInUser.uid)}}} some text{{{ end }}} as long as your theme is providing the loggedInUser object. Like harmony and persona.

  • @baris Thanks. This works 🙂

    <!-- IF isQuestion -->
    <!-- IF !isSolved -->
    < script > 
    {{ if (uid === loggedInUser.uid) }} 
    </script> 
    <div class = "bmacmain" > 
    <div class = "card" > 
    <h5 class = "card-header" > Did this topic help you ? < /h5>
    <div class="card-body"> 
    <div class = "bmacmessage" > Please don 't forget to click on "Mark this post as the correct answer" whenever the information provided helps you. Original posters help the community find answers faster by identifying the correct answer.  < /div> 
    </div> 
    </div>
    </div> 
    <br> 
    <script> 
    {{ end }} 
    </script>
    <!-- ENDIF !isQuestion -->
    <!-- ENDIF !isSolved -->
    
  • Hmm - not working entirely - it is triggering no matter who the OP is

    <script>
    {{{ if (uid === loggedInUser.uid) }}}
    </script>
    <!-- IF isQuestion -->
    <!-- IF !isSolved -->
    <div class="bmacmain">
    <div class="card"><h5 class="card-header">Did you get the answer you needed?</h5><div class="card-body">
    <div class="bmacmessage">Hey <span class="topicUsername" ><span class="username"></span></span>. It looks as though there have been one or more replies to your original post. <br>If a provided answer resolved an issue for you, Could you please take a moment, and select "Mark this post as the correct answer" in the corresponding response?  <br><br>By doing this, it means that original posters help the rest of the community find answers to previously asked questions by identifying the correct answer. 
    </div>
    </div>
    </div></div>
    <br>
    <!-- ENDIF !isQuestion -->
    <!-- ENDIF !isSolved -->
    <script>
    {{{ end }}}
    </script>
    

    Still lookin at this, but any thoughts ?

  • You don't have to put that in <script> tags. It is valid benchpress so you can use something like this.

    {{{ if (uid == loggedInUser.uid) }}}
    {{{ if isQuestion }}}
    {{{ if !isSolved }}}
    <div class="bmacmain">
    <div class="card"><h5 class="card-header">Did you get the answer you needed?</h5><div class="card-body">
    <div class="bmacmessage">Hey <span class="topicUsername" ><span class="username"></span></span>. It looks as though there have been one or more replies to your original post. <br>If a provided answer resolved an issue for you, Could you please take a moment, and select "Mark this post as the correct answer" in the corresponding response?  <br><br>By doing this, it means that original posters help the rest of the community find answers to previously asked questions by identifying the correct answer. 
    </div>
    </div>
    </div></div>
    <br>
    {{{ end }}}
    {{{ end }}}
    {{{ end }}}
    
    
  • @baris of course. Forgot. Let me try that

    Edit - works perfectly. Thanks

  • I would recommend combining those ifs:

    {{{ if (((uid == loggedInUser.uid) && isQuestion) && !isSolved) }}}

  • @PitaJ yes, that would be more efficient I expect. Thanks


Suggested Topics


  • 0 Votes
    3 Posts
    352 Views

    I have enabled the plugin. Is there any issues related to plugin version or the search is database(mongo/redis) dependent? Need help.

  • Javascript HTML Widget

    Technical Support
    9
    0 Votes
    9 Posts
    3k Views

    @julian said in Javascript HTML Widget:

    Nice site, looks a lot like our community forum

    Ha! Thanks! Just need some users now! 🙂

  • 0 Votes
    1 Posts
    872 Views

    GitHub - rauchg/slackin: Public Slack organizations made easy

    Public Slack organizations made easy. Contribute to rauchg/slackin development by creating an account on GitHub.

    favicon

    GitHub (github.com)

    I'm trying to add the badge it adds to a widget, but it doesn't load/can't find the script tag. Currently I'm using this:

    <script async defer src="https://slack.yourdomain.com/slackin.js"></script>

    Content of slackin.js

    (function(){ // give up and resort to `target=_blank` // if we're not modern enough if (!document.body.getBoundingClientRect || !document.body.querySelectorAll || !window.postMessage) { return; } // search for a script tag pointing to slackin.js function search(){ var replaced = 0; var scripts = document.querySelectorAll('script'); var script; for (var i = 0; i < scripts.length; i++) { script = scripts[i]; if (!script.src) continue; if (/\/slackin\.js(\?.*)?$/.test(script.src)) { // replace script with iframe replace(script); // we abort the search for subsequent // slackin.js executions to exhaust // the queue return true; } } } var LARGE; // boolean for large/small mode, from query param // replace the script tag with an iframe function replace(script){ var parent = script.parentNode; if (!parent) return; LARGE = /\?large/.test(script.src); var iframe = document.createElement('iframe'); var iframePath = '/iframe' + (LARGE ? '?large' : ''); iframe.src = script.src.replace(/\/slackin\.js.*/, iframePath); iframe.style.borderWidth = 0; iframe.className = '__slackin'; // a decent aproximation that we adjust later // once we have the knowledge of the actual // numbers of users, based on a user count // of 3 digits by 3 digits iframe.style.width = (LARGE ? 190 : 140) + 'px'; // height depends on target size iframe.style.height = (LARGE ? 30 : 20) + 'px'; // hidden by default to avoid flicker iframe.style.visibility = 'hidden'; parent.insertBefore(iframe, script); parent.removeChild(script); // setup iframe RPC iframe.onload = function(){ setup(iframe); }; } // setup an "RPC" channel between iframe and us function setup(iframe){ var id = Math.random() * (1 << 24) | 0; iframe.contentWindow.postMessage('slackin:' + id, '*'); window.addEventListener('message', function(e){ if (typeof e.data !== 'string') return; // show dialog upon click if ('slackin-click:' + id === e.data) { showDialog(iframe); } // update width var wp = 'slackin-width:' + id + ':'; if (wp === e.data.substr(0, wp.length)) { var width = e.data.substr(wp.length); iframe.style.width = width + 'px'; // ensure it's shown (since first time hidden) iframe.style.visibility = 'visible'; } // redirect to URL var redir = 'slackin-redirect:' + id + ':'; if (redir === e.data.substr(0, redir.length)) { location.href = e.data.substr(redir.length); } }); } // show the dialog around the iframe // by, yes, creating a new iframe var showing = false; function showDialog(iframe){ if (showing) return; showing = true; if (LARGE) { unitSize = '14px'; arrowHeight = 13; } else { unitSize = '10px'; arrowHeight = 9; } // container div var div = document.createElement('div'); div.className = '__slackin'; div.style.fontSize = unitSize; div.style.border = '.1em solid #D6D6D6'; div.style.padding = '0'; div.style.margin = '0'; div.style.lineHeight = '0'; div.style.backgroundColor = '#FAFAFA'; div.style.width = '25em'; div.style.height = '15.5em'; div.style.position = 'absolute'; div.style.left = '-10000px'; div.style.top = '-10000px'; div.style.borderRadius = '.4em'; div.style.padding = '.4em'; div.style.boxSizing = 'content-box'; // new iframe var ni = document.createElement('iframe'); ni.className = '__slackin'; ni.style.width = '25em'; ni.style.height = '15.5em'; ni.style.borderWidth = 0; ni.src = iframe.src.replace('iframe', 'iframe/dialog'); ni.onload = function(){ setup(ni); window.addEventListener('scroll', dposition); window.addEventListener('resize', dposition); position(); }; // arrows var a1 = document.createElement('div'); var a2 = document.createElement('div'); [a1, a2].forEach(function(a){ a.style.border = 'solid transparent'; a.style.pointerEvents = 'none'; a.style.width = '0'; a.style.height = '0'; a.style.margin = '0'; a.style.padding = '0'; a.style.position = 'absolute'; a.style.display = 'inline'; }); a1.style.borderColor = 'rgba(214, 214, 214, 0)'; a2.style.borderColor = 'rgba(250, 250, 250, 0)'; a1.style.borderWidth = '.7em'; a1.style.marginLeft = '-.65em'; a2.style.borderWidth = '.6em'; a2.style.marginLeft = '-.6em'; // append div.appendChild(a1); div.appendChild(a2); div.appendChild(ni); document.body.appendChild(div); function position(){ [div, a1, a2].forEach(function(el){ el.style.left = ''; el.style.right = ''; el.style.bottom = ''; el.style.top = ''; }); var divPos = div.getBoundingClientRect(); var iframePos = iframe.getBoundingClientRect(); var divHeight = divPos.height + arrowHeight; var st = document.body.scrollTop; var sl = document.body.scrollLeft; var iw = window.innerWidth; var ih = window.innerHeight; var iframeTop = iframePos.top + st; var iframeLeft = iframePos.left + sl; // position vertically / arrows if (st + iframePos.bottom + divHeight > st + ih) { div.style.top = (iframeTop - divHeight) + 'px'; a1.style.top = a2.style.top = '100%'; a1.style.borderBottomColor = 'rgba(214, 214, 214, 0)'; a2.style.borderBottomColor = 'rgba(250, 250, 250, 0)'; a1.style.borderTopColor = '#d6d6d6'; a2.style.borderTopColor = '#fafafa'; } else { div.style.top = (iframeTop + iframePos.height + arrowHeight) + 'px'; a1.style.bottom = a2.style.bottom = '100%'; a1.style.borderTopColor = 'rgba(214, 214, 214, 0)'; a2.style.borderTopColor = 'rgba(250, 250, 250, 0)'; a1.style.borderBottomColor = '#d6d6d6'; a2.style.borderBottomColor = '#fafafa'; } // position horizontally var left = iframePos.left + Math.round(iframePos.width / 2) - Math.round(divPos.width / 2); if (left < sl) left = sl; if (left + divPos.width > sl + iw) { left = sl + iw - divPos.width; } div.style.left = left + 'px'; a1.style.left = a2.style.left = (iframeLeft - left + Math.round(iframePos.width / 2)) + 'px'; } // debounced positionining var timer; function dposition(){ clearTimeout(timer); timer = setTimeout(position, 100); } function hide(){ showing = false; window.removeEventListener('scroll', dposition); window.removeEventListener('resize', dposition); document.body.removeChild(div); document.documentElement.removeEventListener('click', click, true); } function click(ev){ if ('__slackin' != ev.target.className) { hide(); } } document.documentElement.addEventListener('click', click, true); } var found = search(); if (!found) setTimeout(search, 5000); })();

    If anyone here could help me getting this to work in a widget, I would be really thankful!
    Thanks.

  • 6 Votes
    5 Posts
    2k Views

    @nicolas is this still being updated?

    Thanks

  • 0 Votes
    10 Posts
    4k Views

    It is loggedIn everywhere now. https://github.com/NodeBB/NodeBB/issues/1900