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.

Similar Topics in New Topic Creation

2 posters

Go down

Tutorial Similar Topics in New Topic Creation

Post by TheCrow Fri 6 Apr - 13:47

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!
TheCrow
TheCrow
Manager
Manager

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

https://www.inforumgr.com

Back to top Go down

Tutorial Re: Similar Topics in New Topic Creation

Post by SarkZKalie Thu 20 Sep - 11:23

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
SarkZKalie
SarkZKalie
Support Moderator
Support Moderator

Male Posts : 1443
Reputation : 220
Language : English

https://rotavn.forumotion.com/

Back to top Go down

Back to top

- Similar topics

 
Permissions in this forum:
You cannot reply to topics in this forum