HEX
Server: Microsoft-IIS/8.5
System: Windows NT YDAWBH120 6.3 build 9600 (Windows Server 2012 R2 Standard Edition) AMD64
User: tentjecom_web (0)
PHP: 7.4.14
Disabled: NONE
Upload Files
File: D:/HostingSpaces/RMourik/bassol.nl/CMS/CMSWebParts/SmartSearch/SearchBox_files/PredictiveSearch.js
function PredictiveSearchExtender(clientID, textBoxID, resultsHolderID, minChars, selectionEnabled, selectedCssClass, resultsCssClass) {

    var me = this;

    this.clientID = clientID;
    this.resultsID = 'results_' + clientID;
    this.textBoxID = textBoxID;
    this.resultsHolderID = resultsHolderID;

    this.minChars = minChars;
    this.selectedCssClass = selectedCssClass;
    this.resultsCssClass = resultsCssClass;
    this.selectionEnabled = selectionEnabled;

    this.timeout = undefined;
    this.hideTimeout = undefined;
    this.doNotHide = false;
    this.selectedResult = -1;
    this.lastSearchQuery = '';

    this.RecieveSearchResults = function (arg, context) {
        me.selectedResult = -1; //unselect result
        me.lastSearchQuery = context; // save last completed query

        $cmsj('#' + me.resultsID).html(arg);  //insert results 

        // register hover event handler to each result
        if (me.selectionEnabled) {
            $cmsj('#' + me.resultsID + ' > :not(.nonSelectable)').hover(
                function () {
                    $cmsj('#' + me.resultsID + ' > *').removeClass(me.selectedCssClass);
                    $cmsj(this).addClass(me.selectedCssClass);
                    me.selectedResult = $cmsj('#' + me.resultsID + ' > :not(.nonSelectable)').index($cmsj(this));
                }, function () { }
            );

            $cmsj('#' + me.resultsID + ' > .nonSelectable').hover(
                function () {
                    $cmsj('#' + me.resultsID + ' > *').removeClass(me.selectedCssClass);
                }, function () { }
            );
        }

        // show results
        if (arg != '') {
            $cmsj('#' + me.resultsID).show();
        } else {
            $cmsj('#' + me.resultsID).hide();
        }
    };

    this.HideResults = function () {
        $cmsj('#' + me.resultsID).hide();
    };

    // navigates the results when down arrow key is pressed
    this.MoveSelectedDown = function () {
        var searchResultsDiv = $cmsj('#' + me.resultsID);
        var searchResults = $cmsj('#' + me.resultsID + ' > :not(.nonSelectable)');

        if (searchResultsDiv.is(':visible')) { // results are visible - navigate results
            if (me.selectedResult + 1 <= searchResults.length - 1) { // result is not the last
                me.selectedResult++;
                searchResults.removeClass(me.selectedCssClass);
                searchResults.eq(me.selectedResult).addClass(me.selectedCssClass);
            } else { // result is the last - unselect result (loop)
                me.selectedResult = -1;
                searchResults.removeClass(me.selectedCssClass);
            }
        } else if (searchResultsDiv.html() != '') { // show results
            me.selectedResult = 0;
            searchResults.removeClass(me.selectedCssClass);
            searchResults.eq(me.selectedResult).addClass(me.selectedCssClass);
            searchResultsDiv.show();
        }
    };

    // navigates the results when up arrow key is pressed
    this.MoveSelectedUp = function () {
        var searchResults = $cmsj('#' + me.resultsID + ' > :not(.nonSelectable)');

        if (me.selectedResult > 0) { // result is not first - navigate
            me.selectedResult--;
            searchResults.removeClass(me.selectedCssClass);
            searchResults.eq(me.selectedResult).addClass(me.selectedCssClass);
        } else if (me.selectedResult == 0) { // result is first - unselect result
            me.selectedResult = -1;
            searchResults.removeClass(me.selectedCssClass);
        } else if (me.selectedResult == -1) { // no result is selected - loop (start drom bottom)
            me.selectedResult = searchResults.length - 1;
            searchResults.removeClass(me.selectedCssClass);
            searchResults.eq(me.selectedResult).addClass(me.selectedCssClass);
        }
    };

    // character was typed in search text box
    this.KeyChanged = function () {
        var query = $cmsj('#' + me.textBoxID).val(); // get the search query

        if (me.timeout) { clearTimeout(me.timeout); } // if call timeout is set, reset it (cancel the search)

        if (query.length >= me.minChars) { // query is long enough
            if (query !== me.lastSearchQuery) // query is different from the last query
            {
                me.timeout = setTimeout(function () { me.CallPredictiveSearch(query, query); }, 500); // set call timeout (start the search countdown)
            }
        } else { // query is not long enough - hide results
            me.timeout = setTimeout(function () {
                $cmsj('#' + me.resultsID).html('').hide();
                me.lastSearchQuery = '';
            }, 500);
        }
    };

    // redirects to selected result 
    // tries to find href attribute and redirects to ist's URL
    this.RedirectToResult = function (e) {
        var selectedResultElem = $cmsj('#' + me.resultsID + ' .' + me.selectedCssClass); // get selected result 

        if (selectedResultElem.length == 1) { // selected result is found and only one result is selected
            var href = '';
            href = selectedResultElem.attr('href'); // search for href in result element

            // search for href in childs elements 
            if (href == undefined || href == '') {
                href = selectedResultElem.find('[href]').attr('href');
            }

            // go to search result
            if (href != undefined && href != '') {
                e.preventDefault();
                document.location.href = href;
            }
        }
    };

    // startup
    $cmsj(function () {

        // inserts results div to seach holder element
        $cmsj('#' + me.resultsHolderID).html('<div id=\'' + me.resultsID + '\' class=\'' + me.resultsCssClass  + '\'></div>');
    
        // hides the results
        me.HideResults();

        // disables autocomplete for search text box
        $cmsj('#' + me.textBoxID).attr('autocomplete', 'off') 
        .keyup(me.KeyChanged) // search query text change is registered on keyup because on keydown text is not written in the textbox
        .keydown(function (e) { // keydown because we want to support loop (key is not up while looping)
            switch (e.keyCode) {
                case 38: // up
                    if (me.selectionEnabled) { me.MoveSelectedUp(); }
                    e.preventDefault();
                    break;
                case 40: // down
                    if (me.selectionEnabled) { me.MoveSelectedDown(); }
                    e.preventDefault();
                    break;
                case 27: //escape
                    $cmsj('#' + me.resultsID).hide();
                    break;
            }
        })
        .bind('keypress keydown keyup', function(e) { // enter
            if (e.keyCode == 13) { me.RedirectToResult(e); }
        })
        .blur(function () { // registers blur event - when focus from search text box is lost, hide the results
            if (!me.doNotHide) { // check if focus was lost on purpuse, results shouldn't be hidden in that case
                if (me.hideTimeout) { clearTimeout(me.hideTimeout); } // results are not hidden immidiately (effects)
                me.hideTimeout = setTimeout(function () { me.HideResults(); }, 300);
            }
        });

        // when mouse is pressed in the results element area, prevent the results from hidding
        $cmsj('#' + me.resultsID).mousedown(function () {
            me.doNotHide = true;
        })
        // when mouse is released, check if hiding is disabled (mouse was pressed in the results area)
        // and enable hidding and restore focus to text box. 
        .mouseup(function () { 
            if (me.doNotHide) {
                me.doNotHide = false;
                $cmsj('#' + me.textBoxID).focus();
            }
        })
        // when mouse was pressed in the results area and mouse leaves the results area enable hiding and restore focus
        .mouseleave(function () {
            if (me.doNotHide) {
                me.doNotHide = false;
                $cmsj('#' + me.textBoxID).focus();
            }
        });
    });
}