Similar Topics in New Topic Creation Hitskin_logo Hitskin.com

This is a Hitskin.com skin preview
Install the skinReturn to the skin page

The forum of the forums
Would you like to react to this message? Create an account in a few clicks or log in to continue.
2 posters

    Similar Topics in New Topic Creation

    TheCrow
    TheCrow
    Manager
    Manager


    Male Posts : 6921
    Reputation : 795
    Language : Greek, English

    Tutorial Similar Topics in New Topic Creation

    Post by TheCrow April 6th 2018, 3:47 pm

    Similar Topics in New Topic Creation


    This code allows the users to see a list of similar topics while they are writing the title. It is ideal for support forums in which almost all answers are already solved. Here's an example of how it looks like:

    Similar Topics in New Topic Creation COVdLjLJ

    Everyone can adapt the code according to his/her forum. It can also be possible to adapt the code to any other version, although this would be up to the user, and this adaptation is not supported. By default the code works for phpBB3

    Installation


    ACP(Admin Control Panel) > Modules >  HTML & JAVASCRIPT > Javascript codes management > Javascript codes management
    Position: All pages

    Code:
       /* The following code is DOM-dependent. It may not work if you modify the posting structure in the forum templates */
     
        var FLRX = FLRX || {};
     
        FLRX.similarTopics = (function () {
     
            'use strict';
     
            let settings = { // default settings
                forums : [],
                searchIn : false,
                maxTopics : 5,
                wordMinLength: 4,
     
     
                autocomplete: false, // disable browser autocomplete from subject input
     
                /* Advanced settings */
                excludedCharacters : new RegExp(/[.,\/#!$%\^&\*¿?!¡;:{}\\=\-_`~"«“‘’”»()\[\]]/, 'g'), // The ignored characters from the topic title.
                dom : { // default settings (should work if left like this with unmodified templates)
     
                    /* Search page */
                    topicscontainer : '.forabg',
                    topic          : 'dd.dterm',
                    infocontainer  : '.span-tab',
                    titlelink      : '.topictitle',
                    userlink        : 'a[href^="/u"]',
                    forumlink      : 'a[href^="/f"]',
                    topicicon      : 'dl.icon',
     
                    /* structure */
                    visible        : 'visible',
     
                    /* posting page */
                    titleinput      : '#postingbox input[name="subject"]',
                    inputcontainer  : 'dl',
     
                    /* created elements */
                    maincontainer  : $('<div />', { id : 'similarTopics' }),
                    similartopiccont : $('<div />', { class : 'topic-container' }),
                    loadingelm      : $('<div />', { class : 'spinner' })
                                        .append($('<div/>', { class:'double-bounce1' }))
                                        .append($('<div/>', { class:'double-bounce2' })),
                    topicelmcont    : $('<div />', { class: 'topic' }),
                    topicelmtitle  : $('<div />', { class: 'topic-title' }),
                    topicdatacont  : $('<div />', { class: 'topic-data' }),
                    topicflags      : $('<div />', { class: 'topic-flags' }),
                    topiciconcont  : $('<div />', { class: 'topic-icon' }),
                    topicstatus    : $('<div />', { class: 'topic-status' }),
                    topicelminfo    : $('<div />', { class: 'topic-info' }),
                    topicauthor    : $('<span />', { class: 'topic-author', text: 'by ' }),
                    topicforum      : $('<span />', { class: 'topic-forum', text: ' in ' }),
                    similarstitle  : $('<h4 />', { class: 'similarTopics-title', text: 'You may be interested in checking this topics before opening a new one' }),
     
                },
            },
     
            structure = {},
     
            request,
     
            debounce = function(cb, delay) {
                let timeout;
                return function(...a) {
                    clearTimeout(timeout);
                    timeout = setTimeout( _ => { timeout = null;  cb.call(this, ...a);  }, delay);
                };
            },
     
            /* transforms a UTF8-encoded URI into Windows-1252 */
            sanitizeURI = function(uri) {
     
                /* For some reason Forumotion uses Windows-1252 encoding in search URIs.
                This workaround will only fix issues with Spanish characters */
     
                return uri.replace(/%C3%91/g, '%D1') // Ñ
                    .replace(/%C3%B1/g, '%F1') // ñ
                    .replace(/%C3%81/g, '%C1') // Á
                    .replace(/%C3%89/g, '%C9') // É
                    .replace(/%C3%8D/g, '%CD') // Í
                    .replace(/%C3%93/g, '%D3') // Ó
                    .replace(/%C3%9A/g, '%DA') // Ú
                    .replace(/%C3%9C/g, '%DC') // Ü
                    .replace(/%C3%A1/g, '%E1') // á
                    .replace(/%C3%A9/g, '%E9') // é
                    .replace(/%C3%AD/g, '%ED') // í
                    .replace(/%C3%B3/g, '%F3') // ó
                    .replace(/%C3%BA/g, '%FA') // ú
                    .replace(/%C3%BC/g, '%FC'); // ü
            },
     
            /* returns an object array (representation of topics) from a search URL synchronously */
            searchTopics = function(url, cb) {
                $.ajax({
                    url : url,
                }).done(function(data) {
                    let relatedTopics = [],
                        $forabg = $(settings.dom.topicscontainer, data);
                    if($forabg.length) {
                        $forabg.find(settings.dom.topic).slice(0, settings.maxTopics).each(function() {
                          
                            let $this = $(this),
                            $topictitle = $this.find(settings.dom.titlelink),
                            $spantab = $this.find(settings.dom.infocontainer),
                            $forumlink = $spantab.find(settings.dom.forumlink),
                            $userlink = $spantab.find(settings.dom.userlink),
                            $topicicon = $this.closest(settings.dom.topicicon);
     
                            relatedTopics.push({
                                title  : $topictitle.text().trim(),
                                url    : $topictitle.attr('href'),
                                icon  : $this.css('background-image').slice(4, -1),
                                status : $topicicon.css('background-image').length
                                            ? $topicicon.css('background-image').slice(4, -1)
                                            : false,
                                forum  : {
                                    name : $forumlink.text(),
                                    url  : $forumlink.attr('href'),
                                },
                                user  : {
                                    name : $userlink.text(),
                                    url  : $userlink.attr('href'),
                                },
                            });
                        });
                    }
     
                    cb.call(this, relatedTopics);
                }).fail(_ => {let up; throw up || false});
            },
     
            /* returns an array with the words of a string that fulfil conditions of settings.excludedCharacters */
            getWords = function(str) {
                return str.trim().replace(settings.excludedCharacters, '').split(' ').filter(elm => elm.length >= settings.wordMinLength);
            },
     
            /* updates the similar topics DOM structure with the ones in the input array */
            updateDOM = function(arr) {
     
                structure.topiccontainer.empty();
     
                if(arr.length) {
                    let docfrag = document.createDocumentFragment();
                    $.each(arr, function(index, topic) {
     
                        let $topicTitle = settings.dom.topicelmtitle.clone(),
                        $topicContainer = settings.dom.topicelmcont.clone(),
                        $topicInfo      = settings.dom.topicelminfo.clone(),
                        $topicauthor    = settings.dom.topicauthor.clone(),
                        $topicstatus    = settings.dom.topicstatus.clone(),
                        $topicforum    = settings.dom.topicforum.clone(),
                        $topicflags    = settings.dom.topicflags.clone(),
                        $topicdata      = settings.dom.topicdatacont.clone(),
                        $topicicon      = settings.dom.topiciconcont.clone(),
     
                        /* link creation */
                        $topicLink  = $('<a />', { href: topic.url, text: topic.title }),
                        $forumlink  = $('<a />', { href: topic.forum.url, text: topic.forum.name }),
                        $authorlink = $('<a />', { href: topic.user.url, text: topic.user.name });
     
                        $topicicon.css('background-image', `url('${ topic.icon }')`);
                        topic.status && $topicstatus.css('background-image', `url('${ topic.status }')`);
     
                        $topicauthor.append($authorlink);
                        $topicforum.append($forumlink);
                        $topicTitle.append($topicLink);
                        $topicInfo.append($topicauthor, $topicforum);
                        $topicdata.append($topicTitle, $topicInfo);
                        $topicflags.append($topicstatus, $topicicon);
                        $topicContainer.append($topicflags, $topicdata);
     
                        docfrag.append($topicContainer[0]);
     
                    });
                    structure.topiccontainer[0].appendChild(docfrag);
                  
                } else
                    structure.maincontainer.removeClass(settings.dom.visible);
                  
            },
     
            setLoadingStatus = function() {
                structure.loadingcontainer.addClass(settings.dom.visible);
                structure.recentstitle.removeClass(settings.dom.visible);
                structure.topiccontainer.removeClass(settings.dom.visible);
            },
            topicsRetrieved = function (){
                structure.loadingcontainer.removeClass(settings.dom.visible);
                structure.recentstitle.addClass(settings.dom.visible);
                structure.topiccontainer.addClass(settings.dom.visible);
            },
     
            searchAlgorithm = function(words, cb) {
                let params = {
                    search_where    : settings.searchIn || `f${/\?f=(\d+)/.exec(location.search)[1]}`,
                    show_results    : 'topics',
                    sort_by        : 0,
                    sort_dir        : 'DESC',
                    search_terms    : 'all',
                    search_keywords : words.join(' '),
                };
     
                searchTopics(`/search?${sanitizeURI($.param(params))}`, function(arr) {
                    let relatedTopics = arr;
     
                    if(relatedTopics.length < settings.maxTopics) {
                        params.search_terms = 'any';
                        searchTopics(`/search?${sanitizeURI($.param(params))}`, function(arr) {
                            let searchAnyWord = arr,
                            neededElms = settings.maxTopics - relatedTopics.length;
                            searchAnyWord = searchAnyWord.filter(elm => relatedTopics.find(e => e.url == elm.url) === undefined); // Ignore duplicates
                            relatedTopics = [...relatedTopics, ...searchAnyWord.slice(0, neededElms)];
     
                            cb.call(this, relatedTopics);
     
                        });
                    }
                  
                    cb.call(this, relatedTopics);
     
                });
     
            },
     
            /* main function */
            searchSimilarTopics = function($title) {
                let words = getWords($title.val());
              
     
                if(words.length == 0)
                    return;
     
                // for the first time, if it was hidden
                structure.maincontainer.addClass(settings.dom.visible);
     
                setLoadingStatus();
     
                searchAlgorithm(words, function(arr) {
                    updateDOM(arr);
                    topicsRetrieved();
                });
     
            },
            generateStructure = function($title) {
                let $similarTopics = settings.dom.maincontainer.clone(),
                $spinner = settings.dom.loadingelm.clone(),
                $topicsContainer = settings.dom.similartopiccont.clone(),
                $recentsTitle = settings.dom.similarstitle.clone();
              
                structure = {
                    maincontainer    : $similarTopics,
                    loadingcontainer : $spinner,
                    topiccontainer  : $topicsContainer,
                    recentstitle    : $recentsTitle,
                };
     
                $similarTopics.append($spinner, $recentsTitle, $topicsContainer);
     
                $title.closest(settings.dom.inputcontainer).after($similarTopics);
            },
            init = function(options) {
                $.extend(true, settings, options);
     
                let timeout,
                $title = $(settings.dom.titleinput);
     
                if(!settings.autocomplete)
                    $title.attr('autocomplete', 'off');
     
                // append the basic dom structure (should be hidden by default with CSS)
                generateStructure($title);
     
                $title.on('keypress', debounce(function(e) {
                    if(e.which !== 0)
                        searchSimilarTopics($title);
                }, 500));
     
            };
     
     
            /* API :-) */
            return {
                init : init,
            };
     
        })();
     
     
        !function() {
     
            const settings = {
                forums : [1,2,3,4,5,6,7], // Forum IDs (separated by comma) where the "Similar Topics" feature will be enabled. Set to true to enable the feature everywhere (not recommended).
                searchIn : '-1', // Where the searches will take place. Use -1 to search everywhere. If not set, it will search the forum where the topic is being created
                maxTopics : 5, // Maximum amount of topics shown
            };
     
     
            location.pathname == '/post' &&
            location.search.indexOf('&mode=newtopic') > -1 &&
            (settings.forums === true || settings.forums.some(id => location.search.indexOf(`?f=${id}`) > -1)) &&
            $(function() {
                FLRX.similarTopics.init(settings);
            });
     
        }();

    Now add this CSS code to your forum

    Code:
    #similarTopics{width:500px;background:#E1EBF2;padding:5px 10px;border-radius:5px;margin:5px 0 0 10em}
    #similarTopics,#similarTopics .spinner,#similarTopics .topic-container,#similarTopics .similarTopics-title{display:none}
    #similarTopics.visible,#similarTopics .spinner.visible,#similarTopics .similarTopics-title.visible,#similarTopics .topic-container.visible{display:block}
    #similarTopics .topic{display:flex;border-bottom:1px solid #fff;padding:5px 0;margin:5px 0}
    #similarTopics .topic:last-child{border-bottom:none}
    #similarTopics .topic-data{flex:1}
    #similarTopics .topic-flags{align-items:center;margin-right:10px;position:relative}
    #similarTopics .topic-icon{position:absolute;top:0;left:0;bottom:0;right:0;background:transparent 50% 50% no-repeat}
    #similarTopics .similarTopics-title{border-bottom:1px solid #0076b1;color:#0076b1;font-size:.9em;margin:.5em 0;text-transform:uppercase}
    #similarTopics .topic-status{width:27px;height:27px;background:transparent 0 0 no-repeat}

    At the beginning of the code there are several lines between brackets in the const settings definition. This is where you will be able to add several configuration lines (the lines that are already in the code are ones by default I have added). Next I will add a bit of a documentation to know what settings can you add.

    Documentation



    Here are all the settings you can add to the script. Please note all the options have the same format:

    Code:
    name: value,

    That means if you wanna add several options, the beginning of the script should look (more or less) like this:

    Code:
    const settings = {
        nameOption1: value,
        nameOption2: value,
        nameOption3: value,
    };

    WARNING: To add an option with its default value it's the same as not to add it.

    The options are the following:


    • forums



      When creating a topic in the forums the functionality will appear. A forum will be represented by its ID (the URL of the forum). The IDs will be between brackets separated by commas. For example:

      Code:
      forums: [1, 2, 3, 4, 5],

      Special cases:

      • []: Not turning on the feature in any forum (useless and self-defeating).
        Code:
        forums: [],


      Default value:
      Code:
      forums: [],

    • searchIn



      The forum or category where the search will be done. To identify which forum or category will be done, an ID will be used which is added after a  "c" for categories or a "f" for forums (between quote marks). For example, to search in the category with id 3, it would be:

      Code:
      searchIn: 'c3',

      There are special values:


      • false: Search in the same forum where the topic is being created.
      • '-1': Seach in all forum

      Value by default:
      Code:
      searchIn: false,

    • maxTopics



      Number of topics what will show. The minimum value is 3:

      Example:

      Code:
      maxTopics : 10,

      Value by default:
      Code:
      maxTopics : 5,


    • autocomplete



      Default value:

      Turn on or off the autocomplete of the field of the title (the suggestions of the browser). That is, to put the attribute autocomplete of the element input to on or off

      You can use the value "true" to be on, or "false" to not be.

      Example:

      Code:
      autocomplete : true,

      Default value:
      Code:
      autocomplete : false,

    • wordMinLength



      A minimum number of characters of a word to be taken into account in the search. Please note that because of the Forumotions limitations, it isn't possible to put less than 3.

      The value is a full number that can be between 4 to the maximum numbers of characters allowed by Forumotion.

      Example:

      Code:
      wordMinLength : 5,

      Default value:
      Code:
      wordMinLength : 4,



    There also exists options for advanced users. To use them it is neccesary to have JS and HTML knowledge.

    Advanced options:




    Similar Topics in New Topic Creation Thecro10
    Forum of the Forums

    Forumotion Rules | Tips & Tricks |
    FAQ | Did you forget your password?



    *** The Support Forum will never ask you for your email or password, so please do not post them anywhere! ***
    No support via PM!
    SarkZKalie
    SarkZKalie
    Support Moderator
    Support Moderator


    Male Posts : 1420
    Reputation : 220
    Language : English

    Tutorial Re: Similar Topics in New Topic Creation

    Post by SarkZKalie September 20th 2018, 1:23 pm

    The tutorial has been updated, included some new feature below :

    Added
    • PhpBB2, PhpBB3, PunBB, Invision and ModernBB as supported versions.
    • Latest version 1.1.2 by Flerex
    • Search topics in the whole forum
    • Max topics increased up to 50, from 5
    • Vertical scroll bar

    Note:
    Installation

    1) Add this to your CSS

    Code:
    #similarTopics{height:150px;width:600px;background:#E1EBF2;padding:5px 10px;border-radius:2px;margin:5px auto;overflow-x:hidden}
    #similarTopics,#similarTopics .spinner,#similarTopics .topic-container,#similarTopics .similarTopics-title{display:none}
    #similarTopics.visible,#similarTopics .spinner.visible,#similarTopics .similarTopics-title.visible,#similarTopics .topic-container.visible{display:block}
    #similarTopics .topic{display:flex;border-bottom:1px solid #fff;padding:5px 0;margin:5px 0}
    #similarTopics .topic:last-child{border-bottom:none}
    #similarTopics .topic-data{flex:1}
    #similarTopics .topic-flags{align-items:center;margin-right:10px;position:relative}
    #similarTopics .topic-icon{position:absolute;top:0;left:0;bottom:0;right:0;background:transparent 50% 50% no-repeat}
    #similarTopics .similarTopics-title{border-bottom:1px solid #0076b1;color:#0076b1;font-size:.9em;margin:.5em 0;text-transform:uppercase;display:block}
    #similarTopics .topic-status{width:27px;height:27px;background:transparent top center no-repeat}
    #similarTopics .topic-title{display: inline-block;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;width:500px}

    2) Host yourself a new one and you should let it works on the all page OR put this script in Admin Control Panel -> Display -> Templates -> Post & PMs -> posting_body template, before {SCEDITOR}.

    Code:
    <!-- Similar topics for Forumotion version PhpBB2 -->
    <script src="//rotaxvn.forumotion.com/10670.js" type="text/javascript"></script>
    Code:
    <!-- Similar topics for Forumotion version PhpBB3 -->
    <script src="//rotaxvn.forumotion.com/11026.js" type="text/javascript"></script>
    Code:
    <!-- Similar topics for Forumotion version PunBB -->
    <script src="//rotaxvn.forumotion.com/12820.js" type="text/javascript"></script>
    Code:
    <!-- Similar topics for Forumotion version Invision -->
    <script src="//rotaxvn.forumotion.com/13870.js" type="text/javascript"></script>
    Code:
    <!-- Similar topics for Forumotion version ModernBB -->
    <script src="//rotaxvn.forumotion.com/14908.js" type="text/javascript"></script>
    3) Don't forget to publish your new template.

    Enjoy

    This tutorial was created by Flerex
    Special thank to Sr.Smith from the Spanish Support Forum - who helped to convert this great script to PhpBB2 and Invision.



    Similar Topics in New Topic Creation Sarkzk10