PageSourceSearch

https://hjemshop.dk/wp-content/plugins/ajax-search-for-woocommerce-premium/assets/js/search.js?ver=1.22.1

js hjemshop.dk collected 2026-10-10 01:05:57 UTC 158,625 bytes, 4,043 lines download raw bytes

1/**
2 *  Ajax Autocomplete for jQuery, version 1.2.27
3 *  (c) 2015 Tomas Kirda
4 *
5 *  Ajax Autocomplete for jQuery is freely distributable under the terms of an MIT-style license.
6 *  For details, see the web site: https://github.com/devbridge/jQuery-Autocomplete
7 *
8 *  Modified by Damian Góra: http://damiangora.com
9 *  Minify: https://www.toptal.com/developers/javascript-minifier/
10 */
11
12/*jslint  browser: true, white: true, single: true, this: true, multivar: true */
13/*global define, window, document, jQuery, exports, require */
14
15// Expose plugin as an AMD module if AMD loader is present:
16(function (factory) {
17    "use strict";
18    if (typeof define === 'function' && define.amd) {
19        // AMD. Register as an anonymous module.
20        define(['jquery'], factory);
21    } else if (typeof exports === 'object' && typeof require === 'function') {
22        // Browserify
23        factory(require('jquery'));
24    } else {
25        // Browser globals
26        factory(jQuery);
27    }
28}(function ($) {
29    'use strict';
30
31    var utils = (function () {
32            return {
33                escapeRegExChars: function (value) {
34                    return value.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&");
35                },
36                createNode: function (containerClass) {
37                    var div = document.createElement('div');
38                    div.className = containerClass;
39                    div.style.position = 'absolute';
40                    div.style.display = 'none';
41                    div.setAttribute('unselectable', 'on');
42                    return div;
43                },
44                highlight: function (suggestionValue, phrase) {
45
46                    if (dgwt_wcas.is_premium) {
47                        var i,
48                            tokens = phrase.split(/ /),
49                            highlighted = false,
50                            last = '';
51
52                        if (tokens) {
53                            last = tokens[tokens.length - 1];
54                            tokens = tokens.sort(function (a, b) {
55                                return b.length - a.length;
56                            });
57
58                            for (i = 0; i < tokens.length; i++) {
59                                if (tokens[i] && tokens[i].length >= 1) {
60
61                                    var token = tokens[i].replace(/[\^\@]/g, '');
62
63                                    if (token.length > 0) {
64                                        if (token.trim().length === 1 && tokens[i] !== last) {
65                                            var pattern = '((\\s|^)' + utils.escapeRegExChars(token.trim()) + '\\s)';
66                                        } else if (token.trim().length === 1 && tokens[i] === last) {
67                                            var pattern = '((\\s|^)' + utils.escapeRegExChars(token.trim()) + ')';
68                                        } else {
69                                            var pattern = '(' + utils.escapeRegExChars(token.trim()) + ')';
70                                        }
71
72                                        suggestionValue = suggestionValue.replace(new RegExp(pattern, 'gi'), '\^\^$1\@\@');
73                                        highlighted = true;
74                                    }
75                                }
76                            }
77                        }
78
79                        if (highlighted) {
80                            suggestionValue = suggestionValue.replace(/\^\^/g, '<strong>');
81                            suggestionValue = suggestionValue.replace(/@@/g, '<\/strong>');
82                        }
83
84
85                    } else {
86                        var pattern = '(' + utils.escapeRegExChars(phrase) + ')';
87                        suggestionValue = suggestionValue.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>');
88                    }
89
90                    return suggestionValue;
91                },
92                debounce: function (func, wait) {
93                    var timeout,
94                        debounceID = new Date().getUTCMilliseconds();
95
96                    // First query in the chain
97                    if (ajaxDebounceState.id.length === 0) {
98                        ajaxDebounceState.id = debounceID;
99                        func();
100                        return;
101                    }
102
103                    ajaxDebounceState.id = debounceID;
104
105                    timeout = setTimeout(function () {
106
107                        if (debounceID !== ajaxDebounceState.id) {
108                            clearTimeout(timeout);
109                            return;
110                        }
111
112                        // Last query in the chain
113                        func();
114                        ajaxDebounceState.id = '';
115
116                    }, wait);
117                },
118                mouseHoverDebounce: function (func, selector, wait) {
119                    var timeout;
120
121                    timeout = setTimeout(function () {
122
123                        if ($(selector + ':hover').length > 0) {
124                            func();
125                        } else {
126                            clearTimeout(timeout);
127                            return;
128                        }
129
130
131                    }, wait);
132                },
133                isTextSelected: function () {
134                    var selected = false,
135                        selObj = document.getSelection();
136
137                    if (typeof selObj == 'object') {
138                        if (selObj.toString().length > 0) {
139                            selected = true;
140                        }
141                    }
142                    return selected
143                },
144                getActiveInstance: function () {
145                    var $el = $('.dgwt-wcas-search-wrapp.dgwt-wcas-active'),
146                        instance;
147                    if ($el.length > 0) {
148                        $el.each(function () {
149                            var $input = $(this).find('.dgwt-wcas-search-input');
150                            if (typeof $input.data('autocomplete') == 'object') {
151                                instance = $input.data('autocomplete');
152                                return false;
153                            }
154                        });
155                    }
156
157                    return instance;
158                },
159                hashCode: function (s) {
160                    var h = 0, i = s.length;
161                    while (i > 0) {
162                        h = (h << 5) - h + s.charCodeAt(--i) | 0;
163                    }
164                    return h < 0 ? h * -1 : h;
165                },
166                isBrowser: function (browser) {
167                    return navigator.userAgent.indexOf(browser) !== -1;
168                },
169                isIOS: function () {
170                    return [
171                            'iPad Simulator',
172                            'iPhone Simulator',
173                            'iPod Simulator',
174                            'iPad',
175                            'iPhone',
176                            'iPod'
177                        ].includes(navigator.platform)
178                        // iPad on iOS 13 detection
179                        || (navigator.userAgent.includes("Mac") && "ontouchend" in document)
180                },
181                isIE11: function () {
182                    return !!navigator.userAgent.match(/Trident\/7\./);
183                },
184                setLocalStorageItem(key, value) {
185                    try {
186                        window.localStorage.setItem(
187                            key,
188                            JSON.stringify(value)
189                        );
190                    } catch (error) {
191                        // A more advanced implementation would handle the error case
192                    }
193                },
194                getLocalStorageItem(key, defaultValue) {
195                    try {
196                        const item = window.localStorage.getItem(key);
197                        return item ? JSON.parse(item) : defaultValue;
198                    } catch (error) {
199                        return defaultValue;
200                    }
201                },
202                removeLocalStorageItem(key) {
203                    try {
204                        window.localStorage.removeItem(key);
205                    } catch (error) {
206                    }
207                }
208            };
209        }()),
210        ajaxDebounceState = {
211            id: '',
212            callback: null,
213            ajaxSettings: null,
214            object: null,
215        },
216        keys = {
217            ESC: 27,
218            TAB: 9,
219            RETURN: 13,
220            LEFT: 37,
221            UP: 38,
222            RIGHT: 39,
223            DOWN: 40
224        },
225        noop = $.noop;
226
227    function DgwtWcasAutocompleteSearch(el, options) {
228        var that = this;
229
230        // Shared variables:
231        that.element = el;
232        that.el = $(el);
233        that.suggestions = [];
234        that.badQueries = [];
235        that.selectedIndex = -1;
236        that.currentValue = that.element.value;
237        that.timeoutId = null;
238        that.cachedResponse = {};
239        that.cachedDetails = {};
240        that.cachedPrices = {};
241        that.detailsRequestsSent = [];
242        that.onChangeTimeout = null;
243        that.onChange = null;
244        that.isLocal = false;
245        that.suggestionsContainer = null;
246        that.detailsContainer = null;
247        that.autoAligmentprocess = null;
248        that.noSuggestionsContainer = null;
249        that.latestActivateSource = '';
250        that.actionTriggerSource = '';
251        that.options = $.extend(true, {}, DgwtWcasAutocompleteSearch.defaults, options);
252        that.classes = {
253            selected: 'dgwt-wcas-suggestion-selected',
254            suggestion: 'dgwt-wcas-suggestion',
255            suggestionsContainerOrientTop: 'dgwt-wcas-suggestions-wrapp--top',
256            inputFilled: 'dgwt-wcas-search-filled',
257            darkenOverlayMounted: 'js-dgwt-wcas-search-darkoverl-mounted',
258            fixed: 'dgwt-wcas-suggestions-wrapp-fixed'
259        };
260        that.hint = null;
261        that.hintValue = '';
262        that.selection = null;
263        that.overlayMobileState = 'off';
264        that.overlayDarkenedState = 'off';
265        that.isMouseDownOnSearchElements = false;
266        that.isPreSuggestionsMode = false;
267
268        // Voice search
269        that.voiceSearchRecognition = null;
270        that.voiceSearchStarted = null;
271
272        // Search history
273        that.recentlyViewedProductsKey = 'fibosearch_recently_viewed_products';
274        that.recentlySearchedPhrasesKey = 'fibosearch_recently_searched_phrases';
275
276        // Initialize and set options:
277        that.initialize();
278        that.setOptions(options);
279
280    }
281
282    DgwtWcasAutocompleteSearch.utils = utils;
283
284    $.DgwtWcasAutocompleteSearch = DgwtWcasAutocompleteSearch;
285
286    DgwtWcasAutocompleteSearch.defaults = {
287        ajaxSettings: {},
288        autoSelectFirst: false,
289        appendTo: 'body',
290        serviceUrl: null,
291        lookup: null,
292        onSelect: null,
293        containerDetailsWidth: 'auto',
294        showDetailsPanel: false,
295        showImage: false,
296        showPrice: false,
297        showSKU: false,
298        showDescription: false,
299        showSaleBadge: false,
300        showFeaturedBadge: false,
301        dynamicPrices: false,
302        saleBadgeText: 'sale',
303        featuredBadgeText: 'featured',
304        minChars: 3,
305        maxHeight: 600,
306        dpusbBreakpoint: 550, // (details panel under search bar - breakpoint) If search bar width is lower than this option, suggestions wrapper and details panel will show under search bar with the same width
307        deferRequestBy: 0,
308        params: {},
309        formatResult: _formatResult,
310        delimiter: null,
311        zIndex: 999999999,
312        type: 'GET',
313        noCache: false,
314        isRtl: false,
315        onSearchStart: noop,
316        onSearchComplete: noop,
317        onSearchError: noop,
318        preserveInput: false,
319        searchFormClass: 'dgwt-wcas-search-wrapp',
320        containerClass: 'dgwt-wcas-suggestions-wrapp',
321        containerDetailsClass: 'dgwt-wcas-details-wrapp',
322        preSuggestionsWrappClass: 'dgwt-wcas-pre-suggestions-wrapp',
323        darkenedOverlayClass: 'dgwt-wcas-darkened-overlay',
324        searchInputClass: 'dgwt-wcas-search-input',
325        preloaderClass: 'dgwt-wcas-preloader',
326        closeTrigger: 'dgwt-wcas-close',
327        formClass: 'dgwt-wcas-search-form',
328        voiceSearchClass: 'dgwt-wcas-voice-search',
329        voiceSearchSupportedClass: 'dgwt-wcas-voice-search-supported',
330        voiceSearchActiveClass: 'dgwt-wcas-voice-search-active',
331        voiceSearchDisabledClass: 'dgwt-wcas-voice-search-disabled',
332        tabDisabled: false,
333        dataType: 'text',
334        currentRequest: null,
335        triggerSelectOnValidInput: true,
336        isPremium: false,
337        overlayMobile: false,
338        preventBadQueries: true,
339        lookupFilter: _lookupFilter,
340        paramName: 'query',
341        transformResult: _transformResult,
342        noSuggestionNotice: 'No results',
343        forceFixPosition: false,
344        positionFixed: false,
345        debounceWaitMs: 400,
346        sendGAEvents: true,
347        enableGASiteSearchModule: false,
348        showProductVendor: false,
349        disableHits: false,
350        disableSubmit: false,
351        voiceSearchEnabled: false,
352        voiceSearchLang: '',
353        showRecentlySearchedProducts: false,
354        showRecentlySearchedPhrases: false,
355    }
356
357    function _lookupFilter(suggestion, originalQuery, queryLowerCase) {
358        return suggestion.value.toLowerCase().indexOf(queryLowerCase) !== -1;
359    }
360
361    function _transformResult(response) {
362        return typeof response === 'string' ? JSON.parse(response) 
362: response;
363    }
364
365    function _formatResult(suggestionValue, currentValue, highlight, options) {
366        // Do not replace anything if there current value is empty
367        if (!currentValue) {
368            return suggestionValue;
369        }
370
371        if (highlight) {
372            suggestionValue = utils.highlight(suggestionValue, currentValue);
373        }
374
375        if (!options.convertHtml) {
376            return suggestionValue;
377        }
378
379        return suggestionValue.replace(/&/g, '&amp;')
380            .replace(/</g, '&lt;')
381            .replace(/>/g, '&gt;')
382            .replace(/"/g, '&quot;')
383            .replace(/'/g, '&apos;')
384            .replace(/&lt;sup/g, '<sup')
385            .replace(/&lt;\/sup/g, '</sup')
386            .replace(/sup&gt;/g, 'sup>')
387            .replace(/&lt;sub/g, '<sub')
388            .replace(/&lt;\/sub/g, '</sub')
389            .replace(/sub&gt;/g, 'sub>')
390            .replace(/&lt;br\s?\/?&gt;/g, '<br/>')
391            .replace(/&lt;(\/?(strong|b|br|span))&gt;/g, '<$1>')
392            .replace(/&lt;(strong|span)\s+class\s*=\s*&quot;([^&]+)&quot;&gt;/g, '<$1 class="$2">');
393    }
394
395    DgwtWcasAutocompleteSearch.prototype = {
396        initialize: function () {
397            var that = this;
398
399            // Remove autocomplete attribute to prevent native suggestions:
400            that.element.setAttribute('autocomplete', 'off');
401
402            that.options.params = that.applyCustomParams(that.options.params);
403
404            that.createContainers();
405
406            that.registerEventsSearchBar();
407            that.registerEventsSuggestions();
408            that.registerEventsDetailsPanel();
409            that.registerIconHandler();
410            that.registerFlexibleLayout();
411            that.initVoiceSearch();
412
413            that.fixPosition = function () {
414                that.adjustContainerWidth();
415                if (that.visible) {
416                    that.fixPositionSuggestions();
417                    if (that.canShowDetailsPanel()) {
418                        that.fixPositionDetailsPanel();
419                    }
420                }
421                that.positionOverlayDarkened();
422            };
423
424            // Fix position on resize
425            $(window).on('resize.autocomplete', function () {
426                var that = utils.getActiveInstance();
427                clearTimeout(window.dgwt_wcas.resizeOnlyOnce);
428                if (typeof that != 'undefined') {
429                    window.dgwt_wcas.resizeOnlyOnce = setTimeout(function () {
430                        that.fixPosition();
431                    }, 100);
432                }
433            });
434
435            // Fix position on scroll
436            $(window).on('scroll.autocomplete', function () {
437                var that = utils.getActiveInstance();
438                clearTimeout(window.dgwt_wcas.scrollOnlyOnce);
439                if (typeof that != 'undefined') {
440                    window.dgwt_wcas.scrollOnlyOnce = setTimeout(function () {
441                        that.fixPosition();
442                    }, 100);
443                }
444            });
445
446            // Trigger only when x axis is changed
447            var windowWidth = $(window).width();
448            $(window).on('resize.autocomplete', function () {
449                var newWidth = $(window).width();
450                if (newWidth != windowWidth) {
451                    that.toggleMobileOverlayMode();
452                    windowWidth = newWidth;
453                }
454            });
455
456            if (that.isBreakpointReached('mobile-overlay')) {
457                that.activateMobileOverlayMode();
458            }
459
460            that.hideAfterClickOutsideListener();
461
462            // Mark as initialized
463            that.suggestionsContainer.addClass('js-dgwt-wcas-initialized');
464
465            if (that.detailsContainer && that.detailsContainer.length > 0) {
466                that.detailsContainer.addClass('js-dgwt-wcas-initialized');
467            }
468        },
469        createContainers: function (type) {
470            var that = this,
471                options = that.options;
472
473            // Suggestions
474            if ($('.' + options.containerClass).length == 0) {
475
476                that.suggestionsContainer = $(DgwtWcasAutocompleteSearch.utils.createNode(options.containerClass));
477
478                that.suggestionsContainer.appendTo(options.appendTo || 'body');
479
480                that.suggestionsContainer.addClass('woocommerce');
481
482                // Add conditional classes
483                if (options.showImage === true) {
484                    that.suggestionsContainer.addClass('dgwt-wcas-has-img');
485                }
486
487                // Price
488                if (options.showPrice === true) {
489                    that.suggestionsContainer.addClass('dgwt-wcas-has-price');
490                }
491
492                // Description
493                if (options.showDescription === true) {
494                    that.suggestionsContainer.addClass('dgwt-wcas-has-desc');
495                }
496
497                // SKU
498                if (options.showSKU === true) {
499                    that.suggestionsContainer.addClass('dgwt-wcas-has-sku');
500                }
501
502                // Headings
503                if (options.showHeadings === true) {
504                    that.suggestionsContainer.addClass('dgwt-wcas-has-headings');
505                }
506
507            } else {
508
509                that.suggestionsContainer = $('.' + that.options.containerClass);
510
511            }
512
513            // Details Panel
514            if (that.canShowDetailsPanel()) {
515
516                if ($('.' + options.containerDetailsClass).length == 0) {
517                    that.detailsContainer = $(DgwtWcasAutocompleteSearch.utils.createNode(options.containerDetailsClass));
518                    that.detailsContainer.appendTo(options.appendTo || 'body');
519
520                    that.detailsContainer.addClass('woocommerce');
521                } else {
522
523                    that.detailsContainer = $('.' + options.containerDetailsClass);
524
525                }
526
527            }
528        },
529        registerEventsSearchBar: function () {
530            var that = this;
531
532            // The Control event that checks if other listeners work
533            that.el.on('fibosearch/ping', function () {
534                that.el.addClass('fibosearch-pong');
535            });
536
537            // Extra tasks on submit
538            that.getForm().on('submit.autocomplete', function (e) {
539
540                if (that.options.disableSubmit) {
541                    e.preventDefault();
542                    return false;
543                }
544
545                // Prevent submit empty form
546                var $input = $(this).find('.' + that.options.searchInputClass);
547                if ($input.length && $input.val().length === 0) {
548                    e.preventDefault();
549                    return false;
550                }
551
552                // If variation suggestion exist, click it instead submit search results page
553                if (that.suggestions.length > 0) {
554
555                    $.each(that.suggestions, function (i, suggestion) {
556
557                        if (
558                            typeof suggestion.type != 'undefined'
559                            && suggestion.type == 'product_variation'
560                        ) {
561                            that.select(i);
562                            e.preventDefault();
563                            return false;
564                        }
565                    });
566
567                }
568
569                if (that.options.showRecentlySearchedPhrases) {
570                    that.saveHistorySearches($input.val());
571                }
572
573                // Clean before submit
574                that.closeOverlayMobile();
575            });
576
577            // Position preloader
578            if (document.readyState === 'complete') {
579                that.positionPreloaderAndMic();
580            } else {
581                $(window).on('load', function () {
582                    that.positionPreloaderAndMic();
583                });
584            }
585
586            that.el.on('keydown.autocomplete', function (e) {
587                that.onKeyPress(e);
588            });
589            that.el.on('keyup.autocomplete', function (e) {
590                that.onKeyUp(e);
591            });
592            that.el.on('blur.autocomplete', function () {
593                that.onBlur();
594            });
595            that.el.on('focus.autocomplete', function (e) {
596                that.onFocus(e);
597            });
598            that.el.on('change.autocomplete', function (e) {
599                that.onKeyUp(e);
600            });
601            that.el.on('input.autocomplete', function (e) {
602                that.onKeyUp(e);
603            });
604
605        },
606        registerEventsSuggestions: function () {
607            var that = this,
608                suggestionSelector = '.' + that.classes.suggestion,
609                suggestionsContainer = that.getSuggestionsContainer();
610
611            // Register these events only once
612            if (suggestionsContainer.hasClass('js-dgwt-wcas-initialized')) {
613                return;
614            }
615
616            // Select suggestion and enable details panel on hovering over it
617            $(document).on('mouseenter.autocomplete', suggestionSelector, function () {
618                var that = utils.getActiveInstance();
619
620                if (typeof that == 'undefined') {
621                    return;
622                }
623
624                var currentIndex = $(this).data('index');
625                var selector = '.dgwt-wcas-suggestion[data-index="' + currentIndex + '"]';
626
627                var timeOffset = that.canShowDetailsPanel() ? 100 : 1;
628
629                if (that.selectedIndex != currentIndex) {
630
631                    if (that.suggestions[currentIndex].type == 'headline'
632                        || that.suggestions[currentIndex].type == 'headline-v2') {
633                        return;
634                    }
635
636                    utils.mouseHoverDebounce(function () {
637                        if (that.selectedIndex !== currentIndex) {
638                            that.latestActivateSource = 'mouse';
639                            that.getDetails(that.suggestions[currentIndex]);
640                            that.activate(currentIndex);
641                        }
642                    }, selector, timeOffset);
643
644                }
645            });
646
647            var alreadyClicked = false;
648            // Redirect to the new URL after click a suggestions
649            $(document).on('click.autocomplete', suggestionSelector, function (e) {
650                if (!alreadyClicked) {
651                    var that = utils.getActiveInstance();
652                    that.actionTriggerSource = 'click';
653
654                    alreadyClicked = true;
655                    setTimeout(function () {
656                        alreadyClicked = false;
657                    }, 500);
658
659                    if (typeof e.ctrlKey === 'undefined' || e.ctrlKey === false) {
660                        that.select($(this).data('index'));
661                        e.preventDefault();
662                    }
663                } else {
664                    e.preventDefault();
665                }
666            });
667
668            // FIX issue with touchpads for some laptops (marginal cases)
669            $(document).on('mousedown.autocomplete', suggestionSelector, function (e) {
670                var _this = this;
671                if (e.button === 0) {
672                    setTimeout(function () {
673                        if (!alreadyClicked) {
674                            var that = utils.getActiveInstance();
675                            that.select($(_this).data('index'));
676                        }
677                    }, 250);
678                }
679            });
680
681            // Mark cursor position for onBlur event
682            $('.' + that.options.containerClass).on('mousedown.autocomplete', function (e) {
683                var that = utils.getActiveInstance();
684                that.isMouseDownOnSearchElements = true;
685            });
686
687            $(document).on('click', '.js-dgwt-wcas-sugg-hist-clear', function () {
688                that.resetPreSuggestions();
689            });
690        },
691        registerEventsDetailsPanel: function () {
692            var that = this,
693                detailsContainer = that.getDetailsContainer();
694
695            if (!that.canShowDetailsPanel() || detailsContainer.hasClass('js-dgwt-wcas-initialized')) {
696                return;
697            }
698
699            // Update quantity
700            $(document).on('change.autocomplete', '[name="js-dgwt-wcas-quantity"]', function (e) {
701                var $input = $(this).closest('.js-dgwt-wcas-pd-addtc').find('[data-quantity]');
702                $input.attr('data-quantity', $(this).val());
703            });
704
705            // Mark cursor position for onBlur event
706            $('.' + that.options.containerDetailsClass).on('mousedown.autocomplete', function (e) {
707                var that = utils.getActiveInstance();
708                that.isMouseDownOnSearchElements = true;
709            });
710
711        },
712        registerIconHandler: function () {
713            var that = this,
714                $formWrapper = that.getFormWrapper(),
715                $form = that.getForm();
716
717            $formWrapper.on('click.autocomplete', '.js-dgwt-wcas-search-icon-handler', function (e) {
718
719                var $input = $formWrapper.find('.' + that.options.searchInputClass);
720
721                if ($formWrapper.hasClass('dgwt-wcas-layout-icon-open')) {
722                    that.hide();
723                    $form.hide(true);
724
725                    $formWrapper.removeClass('dgwt-wcas-layout-icon-open');
726
727
728                } else {
729                    var $arrow = $formWrapper.find('.dgwt-wcas-search-icon-arrow');
730                    $form.hide();
731                    $arrow.hide();
732                    $formWrapper.addClass('dgwt-wcas-layout-icon-open');
733                    that.positionIconSearchMode($formWrapper);
734
735                    $form.fadeIn(50, function () {
736                        $arrow.show();
737                        that.positionPreloaderAndMic($formWrapper);
738
739                        var textEnd = that.currentValue.length;
740                        if (textEnd > 0) {
741                            $input[0].setSelectionRange(textEnd, textEnd);
742                        }
743
744                        $input.focus();
745                    });
746
747                    setTimeout(function () {
748                        that.fixPosition();
749                    }, 110);
750
751                }
752
753            });
754
755            if ($('.js-dgwt-wcas-initialized').length == 0 && $('.js-dgwt-wcas-search-icon-handler').length > 0) {
756
757                $(document).on('click.autocomplete', function (event) {
758
759                    if ($('.dgwt-wcas-layout-icon-open').length) {
760
761                        var $target = $(event.target);
762
763                        if (!($target.closest('.' + that.options.searchFormClass).length > 0
764                            || $target.closest('.' + that.options.containerClass).length > 0
765                            || $target.closest('.' + that.options.containerDetailsClass).length > 0
766                        )) {
767                            that.hideIconModeSearch();
768                        }
769
770                    }
771                });
772            }
773        },
774        registerFlexibleLayout: function () {
775            var that = this;
776
777            // Trigger only when x axis is changed
778            var windowWidth = $(window).width();
779            $(window).on('resize.autocomplete', function () {
780                var newWidth = $(window).width();
781                if (newWidth != windowWidth) {
782                    that.reloadFlexibleLayout();
783                    windowWidth = newWidth;
784                }
785            });
786
787            if (document.readyState == 'complete') {
788                that.reloadFlexibleLayout();
789            } else {
790                $(window).on('load.autocomplete', function () {
791                    that.reloadFlexibleLayout();
792                });
793            }
794
795        },
796        activateMobileOverlayMode: function () {
797            var that = this,
798                $formWrapper = that.getFormWrapper();
799
800            if (
801                $formWrapper.hasClass('js-dgwt-wcas-mobile-overlay-enabled')
802                && !$formWrapper.find('.js-dgwt-wcas-enable-mobile-form').length
803            ) {
804
805                $formWrapper.prepend('<div class="js-dgwt-wcas-enable-mobile-form dgwt-wcas-enable-mobile-form"></div>');
806                $formWrapper.addClass('dgwt-wcas-mobile-overlay-trigger-active');
807
808                var $el = $formWrapper.find('.js-dgwt-wcas-enable-mobile-form');
809
810                $el.on('click.autocomplete', function (e) {
811
812                    if (that.options.mobileOverlayDelay > 0) {
813                        setTimeout(function () {
814                            that.showMobileOverlay();
815                        }, that.options.mobileOverlayDelay);
816                    } else {
817                        that.showMobileOverlay();
818                    }
819
820                });
821
822            }
823
824        },
825        deactivateMobileOverlayMode: function () {
826            var that = this,
827                $formWrapper = that.getFormWrapper(),
828                $suggestionsWrapper = that.getSuggestionsContainer();
829
830            var $el = $formWrapper.find('.js-dgwt-wcas-enable-mobile-form');
831
832            if ($formWrapper.hasClass('js-dgwt-wcas-mobile-overlay-enabled')
833                && $el.length
834            ) {
835                that.closeOverlayMobile();
836                $el.remove();
837                $formWrapper.removeClass('dgwt-wcas-mobile-overlay-trigger-active');
838            }
839
840        },
841        toggleMobileOverlayMode: function () {
842            var that = this,
843                $formWrapper = that.getFormWrapper(),
844                isMobOverlayEnabled = false;
845
846            // Break early if this search bar shouldn't open in overlay mobile mode
847            if (!$formWrapper.hasClass('js-dgwt-wcas-mobile-overlay-enabled')) {
848                return;
849            }
850
851            // Determine the search should open in mobile overlay
852            if ($formWrapper.find('.js-dgwt-wcas-enable-mobile-form').length) {
853                isMobOverlayEnabled = true;
854            }
855
856            // Toggled?
857            if (
858                (!isMobOverlayEnabled && that.isBreakpointReached('mobile-overlay'))
859                || (isMobOverlayEnabled && !that.isBreakpointReached('mobile-overlay'))
860            ) {
861
862                var $suggestionsWrapper = that.getSuggestionsContainer();
863
864                that.close(false);
865
866                if ($suggestionsWrapper.length) {
867                    $suggestionsWrapper.html('');
868                }
869
870                that.hideIconModeSearch();
871            }
872
873            // Activate overlay on mobile feature
874            if (!isMobOverlayEnabled && that.isBreakpointReached('mobile-overlay')) {
875                that.activateMobileOverlayMode();
876            }
877
878            // Deactivate overlay on mobile feature
879            if (isMobOverlayEnabled && !that.isBreakpointReached('mobile-overlay')) {
880                that.deactivateMobileOverlayMode();
881            }
882        },
883        showMobileOverlay: function () {
884            var that = this;
885
886            if (that.overlayMobileState === 'on') {
887                return;
888            }
889
890            that.overlayMobileState = 'on';
891
892            var zIndex = 99999999999,
893                $wrapper = that.getFormWrapper(),
894                $suggestionsWrapp = that.getSuggestionsContainer(),
895                $overlayWrap,
896                html = '';
897
898            $('html').addClass('dgwt-wcas-overlay-mobile-on');
899            $('html').addClass('dgwt-wcas-open-' + that.getSearchStyle());
900            html += '<div class="js-dgwt-wcas-overlay-mobile dgwt-wcas-overlay-mobile">';
901            html += '<div class="dgwt-wcas-om-bar js-dgwt-wcas-om-bar">';
902            html += '<button class="dgwt-wcas-om-return js-dgwt-wcas-om-return">'
903            if (typeof dgwt_wcas.back_icon == 'string') {
904                html += dgwt_wcas.back_icon;
905            }
906            html += '</button>';
907            html += '</div>';
908            html += '</div>';
909
910            // Create overlay
911            $(that.options.mobileOverlayWrapper).append(html);
912            $overlayWrap = $('.js-dgwt-wcas-overlay-mobile');
913            $overlayWrap.css('zIndex', zIndex);
914
915            $wrapper.after('<span class="js-dgwt-wcas-om-hook"></span>');
916            $wrapper.appendTo('.js-dgwt-wcas-om-bar');
917            $suggestionsWrapp.appendTo('.js-dgwt-wcas-om-bar');
918            $wrapper.addClass('dgwt-wcas-search-wrapp-mobile');
919
920            if ($wrapper.hasClass('dgwt-wcas-has-submit')) {
921                $wrapper.addClass('dgwt-wcas-has-submit-off');
922                $wrapper.removeClass('dgwt-wcas-has-submit');
923            }
924
925            $wrapper.find('.' + that.options.searchInputClass).focus();
926
927            $(document).on('click.autocomplete', '.js-dgwt-wcas-om-return', function (e) {
928                that.closeOverlayMobile($overlayWrap);
929            });
930            document.dispatchEvent(new CustomEvent('fibosearch/show-mobile-overlay', {
931                detail: that
932            }));
933        },
934        closeOverlayMobile: function ($overlayWrap) {
935            var that = this;
936
937            if (!$('html').hasClass('dgwt-wcas-overlay-mobile-on')) {
938                that.overlayMobileState = 'off';
939                return;
940            }
941
942            var $suggestionsWrapp = that.getSuggestionsContainer();
943
944            var $clonedForm = $('.js-dgwt-wcas-om-bar').find('.' + that.options.searchFormClass);
945
946            if ($clonedForm.hasClass('dgwt-wcas-has-submit-off')) {
947                $clonedForm.removeClass('dgwt-wcas-has-submit-off');
948                $clonedForm.addClass('dgwt-wcas-has-submit');
949            }
950
951            $clonedForm.removeClass('dgwt-wcas-search-wrapp-mobile');
952            $('html').removeClass('dgwt-wcas-overlay-mobile-on');
953            $('html').removeClass('dgwt-wcas-open-' + that.getSearchStyle());
954            $suggestionsWrapp.appendTo('body');
955            $suggestionsWrapp.removeAttr('body-scroll-lock-ignore');
956            $('.js-dgwt-wcas-om-hook').after($clonedForm);
957            $('.js-dgwt-wcas-overlay-mobile').remove();
958            $('.js-dgwt-wcas-om-hook').remove();
959
960            setTimeout(function () {
961                $clonedForm.find('.' + that.options.searchInputClass).val('');
962                var $closeBtn = $clonedForm.find('.dgwt-wcas-close');
963                if ($clonedForm.length > 0) {
964                    $closeBtn.removeClass('dgwt-wcas-close');
965                    $closeBtn.html('');
966                }
967
968                that.hide();
969
970            }, 150);
971
972
973            that.overlayMobileState = 'off';
974
975            document.dispatchEvent(new CustomEvent('fibosearch/hide-mobile-overlay', {
976                detail: that
977            }));
978        },
979        reloadFlexibleLayout: function () {
980            var that = this,
981                $searchWrapp = that.getFormWrapper(),
982                flexibleMode = 0;
983
984            /**
985             * flexibleMode
986             * 0 = not set
987             * 1 = Icon on mobile, search bar on desktop
988             * 2 = Icon on desktop, search bar on mobile
989             */
990
991            if ($searchWrapp.hasClass('js-dgwt-wcas-layout-icon-flexible')) {
992                flexibleMode = 1;
993            }
994
995            if ($searchWrapp.hasClass('js-dgwt-wcas-layout-icon-flexible-inv')) {
996                flexibleMode = 2;
997            }
998            if (flexibleMode > 0) {
999
1000                if (
1001                    (flexibleMode === 1 && that.isBreakpointReached('search-layout'))
1002                    || (flexibleMode === 2 && !that.isBreakpointReached('search-layout'))
1003                ) {
1004                    $searchWrapp.addClass('js-dgwt-wcas-layout-icon');
1005                    $searchWrapp.addClass('dgwt-wcas-layout-icon');
1006                } else {
1007                    $searchWrapp.removeClass('js-dgwt-wcas-layout-icon');
1008                    $searchWrapp.removeClass('dgwt-wcas-layout-icon');
1009                }
1010
1011                $searchWrapp.addClass('dgwt-wcas-layout-icon-flexible-loaded');
1012            }
1013        },
1014        onFocus: function (e) {
1015            var that = this,
1016                $formWrapper = that.getFormWrapper(),
1017                options = that.options;
1018            // Mark as active
1019            $('.' + options.searchFormClass).removeClass('dgwt-wcas-active');
1020            $formWrapper.addClass('dgwt-wcas-active');
1021
1022            // Mark as focus
1023            $('body').addClass('dgwt-wcas-focused');
1024            $formWrapper.addClass('dgwt-wcas-search-focused');
1025
1026            if ($(e.target).closest('.dgwt-wcas-search-wrapp-mobile').length == 0) {
1027                that.enableOverlayDarkened();
1028            }
1029
1030            that.fixPosition();
1031
1032            if (that.el.val().length === 0) {
1033                if (that.canShowPreSuggestions()) {
1034                    that.showPreSuggestions();
1035                }
1036            } else if (that.el.val().length >= that.options.minChars) {
1037                that.onValueChange();
1038            }
1039        },
1040        onBlur: function () {
1041            var that = this,
1042                options = that.options,
1043                value = that.el.val(),
1044                query = that.getQuery(value);
1045
1046            // Remove focused classes
1047            $('body').removeClass('dgwt-wcas-focused');
1048            $('.' + options.searchFormClass).removeClass('dgwt-wcas-search-focused');
1049
1050            if (!that.isMouseDownOnSearchElements) {
1051
1052                that.hide();
1053
1054                if (that.selection && that.currentValue !== query) {
1055                    (options.onInvalidateSelection || $.noop).call(that.element);
1056                }
1057            }
1058
1059            document.dispatchEvent(new CustomEvent('fibosearch/close', {
1060                detail: that
1061            }));
1062        },
1063        abortAjax: function () {
1064            var that = this;
1065            if (that.currentRequest) {
1066                that.currentRequest.abort();
1067                that.currentRequest = null;
1068            }
1069        },
1070        setOptions: function (suppliedOptions) {
1071            var that = this,
1072                $suggestionsContainer = that.getSuggestionsContainer(),
1073
1074                options = $.extend({}, that.options, suppliedOptions);
1075
1076            that.isLocal = Array.isArray(options.lookup);
1077
1078            if (that.isLocal) {
1079                options.lookup = that.verifySuggestionsFormat(options.lookup);
1080            }
1081
1082            $suggestionsContainer.css({
1083                'max-height': !that.canShowDetailsPanel() ? options.maxHeight + 'px' : 'none',
1084                'z-index': options.zIndex
1085            });
1086
1087            // Add classes
1088            if (that.canShowDetailsPanel()) {
1089                var $detailsContainer = that.getDetailsContainer();
1090
1091                $detailsContainer.css({
1092                    'z-index': (options.zIndex - 1)
1093                });
1094            }
1095
1096            options.onSearchComplete = function () {
1097                var $searchForm = that.getFormWrapper();
1098                $searchForm.removeClass('dgwt-wcas-processing');
1099                that.preloader('hide', 'form', 'dgwt-wcas-inner-preloader');
1100                that.showCloseButton();
1101            };
1102
1103            this.options = options;
1104        },
1105        clearCache: function () {
1106            this.cachedResponse = {};
1107            this.cachedDetails = {};
1108            this.cachedPrices = {};
1109            this.badQueries = [];
1110        },
1111        clear: function (cache) {
1112            if (cache) {
1113                this.clearCache();
1114            }
1115            this.currentValue = '';
1116            this.suggestions = [];
1117        },
1118        close: function (focus) {
1119            var that = this,
1120                $el = that.el.closest('.' + that.options.searchFormClass).find('.' + that.options.searchInputClass),
1121                $wrapp = that.getFormWrapper();
1122
1123            that.hide();
1124            that.clear(false);
1125            that.hideCloseButton();
1126            $el.val('');
1127            $wrapp.removeClass(that.classes.inputFilled);
1128
1129            if (focus) {
1130                $el.focus();
1131            }
1132        },
1133        fixPositionSuggestions: function () {
1134            var that = this,
1135                $suggestions = that.getSuggestionsContainer(),
1136                $formEl = that.getForm(),
1137                $input = that.el,
1138                formData = that.getElementInfo($formEl),
1139                inputData = that.getElementInfo($input),
1140                offset = {
1141                    top: inputData.top + inputData.height,
1142                    left: formData.left
1143                };
1144
1145            // Set different vertical coordinates when the search bar is in the fixed position
1146            if (that.ancestorHasPositionFixed($formEl)) {
1147                offset.top = inputData.topViewPort + inputData.height;
1148                $suggestions.addClass(that.classes.fixed);
1149            } else {
1150                $suggestions.removeClass(that.classes.fixed);
1151            }
1152
1153            that.getSuggestionsContainer().css(offset);
1154        },
1155        fixPositionDetailsPanel: function () {
1156            var that = this,
1157                $searchBar = that.getFormWrapper(),
1158                $suggestions = that.getSuggestionsContainer(),
1159                $detailsPanel = that.getDetailsContainer(),
1160                $formEl = that.getForm(),
1161                $input = that.el,
1162                formData = that.getElementInfo($formEl),
1163                inputData = that.getElementInfo($input),
1164                offset = {
1165                    top: inputData.top + inputData.height,
1166                    left: formData.left + $suggestions.outerWidth(false)
1167                };
1168
1169            // Set different vertical coordinate when the search bar is in the fixed position
1170            if (that.ancestorHasPositionFixed($searchBar)) {
1171                offset.top = inputData.topViewPort + inputData.height;
1172                $detailsPanel.addClass(that.classes.fixed);
1173            } else {
1174                $detailsPanel.removeClass(that.classes.fixed)
1175            }
1176
1177            // Stick the details panel to the right side of the suggestion wrapper and to the bottom border of the search form
1178            $detailsPanel.css(offset);
1179
1180            $('body').removeClass('dgwt-wcas-full-width dgwt-wcas-details-outside dgwt-wcas-details-right dgwt-wcas-details-left dgwt-wcas-details-notfit');
1181
1182            // Details Panel Mode 1: Both suggestions wrapper and details panel wrapper have the same width as the search bar
1183            if ($searchBar.outerWidth() >= that.options.dpusbBreakpoint) {
1184                $('body').addClass('dgwt-wcas-full-width');
1185
1186                if (that.options.isRtl === true) {
1187                    offset.left = formData.left + $detailsPanel.outerWidth(false);
1188                    $suggestions.css('left', offset.left);
1189                    $detailsPanel.css('left', formData.left);
1190                }
1191
1192                return;
1193            }
1194
1195            // Details Panel Mode 2: The suggestions' wrapper has the same width as the search bar.
1196            // Details panel clings to the left or right side of the suggestion wrapper.
1197            var windowWidth = $(window).width(),
1198                cDWidth = $detailsPanel.outerWidth(),
1199                cOffset = $detailsPanel.offset();
1200
1201            $('body').addClass('dgwt-wcas-details-outside dgwt-wcas-details-right');
1202
1203            // Is the details panel fits the space of the right side?
1204            // Not? Try to move to the left side
1205            if (windowWidth < (cOffset.left + cDWidth)) {
1206                $('body').removeClass('dgwt-wcas-details-right');
1207                $('body').addClass('dgwt-wcas-details-left');
1208                offset.left = $suggestions.offset().left - $detailsPanel.outerWidth(false);
1209                $detailsPanel.css('left', offset.left);
1210                cOffset = $detailsPanel.offset();
1211            }
1212
1213            // Is the details' panel fits the space of the left side?
1214            // Not? Try to hide it by adding class "dgwt-wcas-details-notfit"
1215            if (cOffset.left < 1) {
1216                $('body').removeClass('dgwt-wcas-details-left dgwt-wcas-details-right');
1217                $('body').addClass('dgwt-wcas-details-notfit');
1218            }
1219        },
1220        fixHeight: function () {
1221            var that = this;
1222
1223            if (!that.canShowDetailsPanel()) {
1224                return false;
1225            }
1226
1227            var $suggestionsWrapp = that.getSuggestionsContainer(),
1228                $detailsWrapp = that.getDetailsContainer();
1229
1230            $suggestionsWrapp.css('height', 'auto');
1231            $detailsWrapp.css('height', 'auto');
1232
1233            var sH = $suggestionsWrapp.outerHeight(false),
1234                dH = $detailsWrapp.outerHeight(false),
1235                minHeight = 340;
1236
1237            $suggestionsWrapp.find('.dgwt-wcas-suggestion:last-child').removeClass('dgwt-wcas-suggestion-no-border-bottom');
1238
1239            if (sH <= minHeight && dH <= minHeight) {
1240                return false;
1241            }
1242
1243            $suggestionsWrapp.find('.dgwt-wcas-suggestion:last-child').addClass('dgwt-wcas-suggestion-no-border-bottom');
1244
1245            if (dH < sH) {
1246                $detailsWrapp.css('height', (sH) + 'px');
1247            }
1248
1249            if (sH < dH) {
1250                $suggestionsWrapp.css('height', dH + 'px');
1251            }
1252
1253            return false;
1254        },
1255        automaticAlignment: function () {
1256            var that = this,
1257                $input = that.getFormWrapper().find('.dgwt-wcas-search-input'),
1258                $suggestionsContainer = that.getSuggestionsContainer(),
1259                $detailsWrapp = that.getDetailsContainer();
1260
1261            if (that.autoAligmentprocess != null) {
1262                return;
1263            }
1264
1265            var markers = [$input.width(), $suggestionsContainer.height()];
1266            if (that.canShowDetailsPanel()) {
1267                markers[2] = $detailsWrapp.height();
1268            }
1269
1270            that.autoAligmentprocess = setInterval(function () {
1271
1272                var newMarkers = [$input.width(), $suggestionsContainer.height()];
1273                if (that.canShowDetailsPanel()) {
1274                    newMarkers[2] = $detailsWrapp.height();
1275                }
1276
1277                for (var i = 0; i < markers.length; i++) {
1278
1279                    if (markers[i] != newMarkers[i]) {
1280
1281                        that.fixHeight();
1282                        that.fixPosition();
1283                        markers = newMarkers;
1284                        break;
1285                    }
1286                }
1287
1288
1289                if (that.canShowDetailsPanel()) {
1290
1291                    var innerDetailsHeight = $detailsWrapp.find('.dgwt-wcas-details-inner').height();
1292
1293
1294                    if ((innerDetailsHeight - $detailsWrapp.height()) > 2) {
1295                        that.fixHeight();
1296                    }
1297                }
1298
1299            }, 10);
1300
1301        },
1302        getElementInfo: function ($el) {
1303            var data = {},
1304                viewPort,
1305                offset;
1306
1307            viewPort = $el[0].getBoundingClientRect();
1308            offset = $el.offset();
1309
1310            data.left = offset.left;
1311            data.top = offset.top;
1312            data.width = $el.outerWidth(false);
1313            data.height = $el.outerHeight(false);
1314            data.right = data.left + data.width;
1315            data.bottom = data.top + data.height;
1316            data.topViewPort = viewPort.top;
1317            data.bottomViewPort = viewPort.top + data.height;
1318
1319            return data;
1320        },
1321        getFormWrapper: function () {
1322            var that = this;
1323            return that.el.closest('.' + that.options.searchFormClass);
1324        },
1325        getForm: function () {
1326            var that = this;
1327            return that.el.closest('.' + that.options.formClass);
1328        },
1329        getSuggestionsContainer: function () {
1330            var that = this;
1331            return $('.' + that.options.containerClass);
1332        },
1333        getDetailsContainer: function () {
1334            var that = this;
1335            return $('.' + that.options.containerDetailsClass);
1336        },
1337        scrollDownSuggestions: function () {
1338            var that = this,
1339                $el = that.getSuggestionsContainer();
1340            $el[0].scrollTop = $el[0].scrollHeight;
1341        },
1342        isCursorAtEnd: function () {
1343            var that = this,
1344                valLength = that.el.val().length,
1345                selectionStart = that.element.selectionStart,
1346                range;
1347
1348            if (typeof selectionStart === 'number') {
1349                return selectionStart === valLength;
1350            }
1351            if (document.selection) {
1352                range = document.selection.createRange();
1353                range.moveStart('character', -valLength);
1354                return valLength === range.text.length;
1355            }
1356            return true;
1357        },
1358        onKeyPress: function (e) {
1359            var that = this,
1360                $wrapp = that.getFormWrapper();
1361
1362            that.addActiveClassIfMissing();
1363
1364            // If suggestions are hidden and user presses arrow down, display suggestions:
1365            if (!that.visible && e.keyCode === keys.DOWN && that.currentValue) {
1366                that.suggest();
1367                return;
1368            }
1369
1370            if (!that.visible) {
1371                // Hide the search icon mode on ESC when there are no suggestions
1372                if (e.keyCode === keys.ESC && $wrapp.hasClass('dgwt-wcas-layout-icon-open')) {
1373                    that.hideIconModeSearch();
1374                }
1375
1376                // Hide the darkened overlay on ESC when there are no suggestions
1377                if (e.keyCode === keys.ESC && that.isMountedOverlayDarkened()) {
1378                    that.disableOverlayDarkened();
1379                    that.el.blur();
1380                }
1381
1382                return;
1383            }
1384
1385            // Open selected suggestion in new tab
1386            if ((e.ctrlKey || e.metaKey) && e.keyCode === keys.RETURN) {
1387                if (that.selectedIndex > -1) {
1388                    that.openInNewTab(that.selectedIndex);
1389                }
1390                return;
1391            }
1392
1393            switch (e.keyCode) {
1394                case keys.ESC:
1395                    that.close();
1396                    break;
1397                case keys.RIGHT:
1398                    if (that.hint && that.options.onHint && that.isCursorAtEnd()) {
1399                        that.selectHint();
1400                        break;
1401                    }
1402                    return;
1403                case keys.TAB:
1404                    break;
1405                case keys.RETURN:
1406
1407                    if (that.selectedIndex === -1) {
1408                        if (that.options.disableSubmit) {
1409                            return false;
1410                        }
1411                        that.hide();
1412                        return;
1413                    }
1414                    that.actionTriggerSource = 'enter';
1415                    that.select(that.selectedIndex);
1416                    break;
1417                case keys.UP:
1418                    that.moveUp();
1419                    break;
1420                case keys.DOWN:
1421                    that.moveDown();
1422                    break;
1423                default:
1424                    return;
1425            }
1426
1427            // Cancel event if function did not return:
1428            e.stopImmediatePropagation();
1429            e.preventDefault();
1430        },
1431        onKeyUp: function (e) {
1432            var that = this;
1433
1434            switch (e.keyCode) {
1435                case keys.UP:
1436                case keys.DOWN:
1437                    return;
1438            }
1439
1440            clearTimeout(that.onChangeTimeout);
1441
1442            if (that.currentValue !== that.el.val()) {
1443                if (that.options.deferRequestBy > 0) {
1444                    // Defer lookup in case when value changes very quickly:
1445                    that.onChangeTimeout = setTimeout(function () {
1446                        that.onValueChange();
1447                    }, that.options.deferRequestBy);
1448                } else {
1449                    that.onValueChange();
1450                }
1451            }
1452        },
1453        onValueChange: function () {
1454            if (this.ignoreValueChange) {
1455                this.ignoreValueChange = false;
1456                return;
1457            }
1458
1459            var that = this,
1460                options = that.options,
1461                value = that.el.val(),
1462                query = that.getQuery(value),
1463                $wrapp = that.getFormWrapper();
1464
1465            if (that.selection && that.currentValue !== query) {
1466                that.selection = null;
1467                (options.onInvalidateSelection || $.noop).call(that.element);
1468            }
1469
1470            clearTimeout(that.onChangeTimeout);
1471            that.currentValue = value;
1472            that.selectedIndex = -1;
1473
1474            // Check existing suggestion for the match before proceeding:
1475            if (options.triggerSelectOnValidInput && that.isExactMatch(query)) {
1476                that.select(0);
1477                return;
1478            }
1479
1480            // Mark as filled
1481            if (query.length > 0) {
1482                if (!$wrapp.hasClass(that.classes.inputFilled)) {
1483                    $wrapp.addClass(that.classes.inputFilled);
1484                }
1485            } else {
1486                $wrapp.removeClass(that.classes.inputFilled);
1487            }
1488
1489            if (query.length < options.minChars) {
1490
1491                if (that.canShowPreSuggestions() && query.length === 0) {
1492                    that.showPreSuggestions();
1493                } else {
1494                    that.hideCloseButton();
1495                    that.hide();
1496                }
1497            } else {
1498                that.getSuggestions(query);
1499            }
1500        },
1501        isExactMatch: function (query) {
1502            var suggestions = this.suggestions;
1503
1504            return (suggestions.length === 1 && suggestions[0].value.toLowerCase() === query.toLowerCase());
1505        },
1506        isNoResults: function (suggestions) {
1507            return suggestions.length === 1 && typeof suggestions[0].type !== 'undefined' && suggestions[0].type === 'no-results';
1508        },
1509        canShowDetailsPanel: function () {
1510            var that = this,
1511                show = that.options.showDetailsPanel;
1512
1513            if ($(window).width() < 768 || ('ontouchend' in document) || that.isPreSuggestionsMode) {
1514                show = false;
1515            }
1516            return show;
1517        },
1518        isBreakpointReached: function (context) {
1519            var that = this,
1520                breakpoint = 0;
1521
1522            switch (context) {
1523                case 'search-layout':
1524                    breakpoint = that.options.layoutBreakpoint;
1525                    if (that.isSetParam('layout_breakpoint')) {
1526                        breakpoint = Number.parseInt(that.getParam('layout_breakpoint'));
1527                    }
1528                    break;
1529                case 'mobile-overlay':
1530                    breakpoint = that.options.mobileOverlayBreakpoint;
1531                    if (that.isSetParam('mobile_overlay_breakpoint')) {
1532                        breakpoint = Number.parseInt(that.getParam('mobile_overlay_breakpoint'));
1533                    }
1534                    break;
1535            }
1536
1537            return $(window).width() <= breakpoint;
1538        },
1539        getQuery: function (value) {
1540            var delimiter = this.options.delimiter,
1541                parts;
1542
1543            if (!delimiter) {
1544                return value.trim();
1545            }
1546            parts = value.split(delimiter);
1547            return $.trim(parts[parts.length - 1]);
1548        },
1549        getSuggestionsLocal: function (query) {
1550            var that = this,
1551                options = that.options,
1552                queryLowerCase = query.toLowerCase(),
1553                filter = options.lookupFilter,
1554                limit = parseInt(options.lookupLimit, 10),
1555                data;
1556
1557            data = {
1558                suggestions: $.grep(options.lookup, function (suggestion) {
1559                    return filter(suggestion, query, queryLowerCase);
1560                })
1561            };
1562
1563            if (limit && data.suggestions.length > limit) {
1564                data.suggestions = data.suggestions.slice(0, limit);
1565            }
1566
1567            return data;
1568        },
1569        getSuggestions: function (q) {
1570            var response,
1571                that = this,
1572                options = that.options,
1573                serviceUrl = options.serviceUrl,
1574                searchForm = that.getFormWrapper(),
1575                params,
1576                cacheKey,
1577                ajaxSettings,
1578                iconSearchActive = that.isActiveIconModeSearch();
1579
1580            options.params[options.paramName] = q;
1581
1582            if (typeof dgwt_wcas.current_lang != 'undefined') {
1583                options.params['l'] = dgwt_wcas.current_lang;
1584            }
1585
1586            that.preloader('show', 'form', 'dgwt-wcas-inner-preloader');
1587            searchForm.addClass('dgwt-wcas-processing');
1588
1589            if (options.onSearchStart.call(that.element, options.params) === false) {
1590                return;
1591            }
1592
1593            params = options.ignoreParams ? null : options.params;
1594
1595            if ($.isFunction(options.lookup)) {
1596                options.lookup(q, function (data) {
1597                    that.suggestions = data.suggestions;
1598                    that.suggest();
1599                    that.selectFirstSuggestion(data.suggestions);
1600                    options.onSearchComplete.call(that.element, q, data.suggestions);
1601                });
1602                return;
1603            }
1604
1605            if (!$('body').hasClass('dgwt-wcas-open')) {
1606                document.dispatchEvent(new CustomEvent('fibosearch/open', {
1607                    detail: that
1608                }));
1609            }
1610
1611            if (that.isLocal) {
1612                response = that.getSuggestionsLocal(q);
1613            } else {
1614                if ($.isFunction(serviceUrl)) {
1615                    serviceUrl = serviceUrl.call(that.element, q);
1616                }
1617                cacheKey = serviceUrl + '?' + $.param(params || {});
1618                response = that.cachedResponse[cacheKey];
1619            }
1620
1621            if (response && Array.isArray(response.suggestions)) {
1622                that.suggestions = response.suggestions;
1623                that.suggest();
1624                that.selectFirstSuggestion(response.suggestions);
1625                options.onSearchComplete.call(that.element, q, response.suggestions);
1626
1627                if (that.isNoResults(response.suggestions)) {
1628                    document.dispatchEvent(new CustomEvent('fibosearch/no-results', {
1629                        detail: that
1630                    }));
1631                } else {
1632                    document.dispatchEvent(new CustomEvent('fibosearch/show-suggestions', {
1633                        detail: that
1634                    }));
1635                }
1636            } else if (!that.isBadQuery(q)) {
1637                that.abortAjax();
1638
1639                ajaxSettings = {
1640                    url: serviceUrl,
1641                    data: params,
1642                    type: options.type,
1643                    dataType: options.dataType
1644                };
1645
1646                $.extend(ajaxSettings, options.ajaxSettings);
1647
1648                ajaxDebounceState.object = that;
1649                ajaxDebounceState.ajaxSettings = ajaxSettings;
1650
1651                utils.debounce(function () {
1652
1653                    var that = ajaxDebounceState.object,
1654                        ajaxSettings = ajaxDebounceState.ajaxSettings;
1655
1656
1657                    that.currentRequest = $.ajax(ajaxSettings).done(function (data) {
1658
1659                        // Interrupt if the icon mode was closed in the meantime
1660                        if (iconSearchActive && !that.isActiveIconModeSearch()) {
1661                            return;
1662                        }
1663
1664                        var result;
1665                        that.currentRequest = null;
1666                        result = that.options.transformResult(data, q);
1667
1668                        if (typeof result.suggestions !== 'undefined') {
1669                            that.processResponse(result, q, cacheKey);
1670                            that.selectFirstSuggestion(result.suggestions);
1671
1672                            if (that.isNoResults(result.suggestions)) {
1673                                that.gaEvent(q, 'Autocomplete Search without results');
1674                            } else {
1675                                that.gaEvent(q, 'Autocomplete Search with results');
1676                            }
1677                        }
1678
1679                        that.fixPosition();
1680
1681                        that.options.onSearchComplete.call(that.element, q, result.suggestions);
1682
1683                        that.updatePrices();
1684
1685                        if (that.isNoResults(result.suggestions)) {
1686                            document.dispatchEvent(new CustomEvent('fibosearch/no-results', {
1687                                detail: that
1688                            }));
1689                        } else {
1690                            document.dispatchEvent(new CustomEvent('fibosearch/show-suggestions', {
1691                                detail: that
1692                            }));
1693                        }
1694                    }).fail(function (jqXHR, textStatus, errorThrown) {
1695                        that.options.onSearchError.call(that.element, q, jqXHR, textStatus, errorThrown);
1696                    });
1697
1698
1699                }, options.debounceWaitMs);
1700
1701
1702            } else {
1703                options.onSearchComplete.call(that.element, q, []);
1704            }
1705
1706        },
1707        getDetails: function (suggestion) {
1708            var that = this;
1709
1710            // Disable details panel
1711            if (!that.canShowDetailsPanel()) {
1712                return false;
1713            }
1714
1715            // Brake if there are no suggestions
1716            if (suggestion == null || typeof suggestion.type == 'undefined') {
1717                return;
1718            }
1719
1720            // Disable on more product suggestion
1721            if (typeof suggestion.type == 'string' && suggestion.type === 'more_products') {
1722                return;
1723            }
1724
1725            that.fixHeight();
1726
1727            var $containerDetails = that.getDetailsContainer(),
1728                currentObjectID = that.prepareSuggestionObjectID(suggestion),
1729                result;
1730
1731            // Check cache
1732            result = that.cachedDetails[currentObjectID];
1733
1734            if (result != null) {
1735
1736                // Load response from cache
1737                that.detailsPanelSetScene(currentObjectID);
1738                that.fixHeight();
1739                that.fixPosition();
1740
1741            } else {
1742
1743                var data = {
1744                    action: dgwt_wcas.action_result_details,
1745                    items: []
1746                };
1747
1748                $.each(that.suggestions, function (i, suggestion) {
1749
1750                    if (
1751                        typeof suggestion.type != 'undefined'
1752                        && suggestion.type != 'more_products'
1753                        && suggestion.type != 'headline'
1754                    ) {
1755                        var itemData = {
1756                            objectID: that.prepareSuggestionObjectID(suggestion),
1757                            value: suggestion.value != null ? suggestion.value : ''
1758                        };
1759                        data.items.push(itemData);
1760                    }
1761                });
1762
1763
1764                that.detailsPanelClearScene();
1765                that.preloader('show', 'details', '');
1766
1767                // Prevent duplicate ajax requests
1768                if ($.inArray(currentObjectID, that.detailsRequestsSent) != -1) {
1769                    return;
1770                } else {
1771                    that.detailsRequestsSent.push(currentObjectID);
1772                }
1773
1774                $.ajax({
1775                    data: data,
1776                    type: 'post',
1777                    url: dgwt_wcas.ajax_details_endpoint,
1778                    success: function (response) {
1779
1780                        var result = typeof response === 'string' ? JSON.parse(response) 
1780: response;
1781
1782                        if (typeof result.items != 'undefined') {
1783                            for (var i = 0; i < result.items.length; i++) {
1784                                var cacheKey = result.items[i]['objectID'];
1785                                that.cachedDetails[cacheKey] = {html: result.items[i]['html']}
1786                                that.detailsPanelAddToScene(cacheKey);
1787
1788                                if (typeof result.items[i]['price'] != 'undefined' && result.items[i]['price'].length > 0) {
1789                                    that.cachedPrices[cacheKey] = result.items[i]['price'];
1790                                }
1791                            }
1792                        }
1793
1794                        that.preloader('hide', 'details', '');
1795
1796                        var currentObjectID = that.prepareSuggestionObjectID(that.suggestions[that.selectedIndex]);
1797
1798                        if (that.cachedDetails[currentObjectID] != null) {
1799                            that.detailsPanelSetScene(currentObjectID);
1800                        } else {
1801                            // @TODO Maybe display some error or placeholder
1802                            that.detailsPanelClearScene();
1803                        }
1804                        that.fixPosition();
1805                        that.fixHeight();
1806
1807                        that.updatePrices(true);
1808                    },
1809                    error: function (jqXHR, exception) {
1810
1811                        that.preloader('hide', 'details', '');
1812
1813                        that.detailsPanelClearScene();
1814                        that.fixPosition();
1815                        that.fixHeight();
1816                    },
1817                });
1818            }
1819
1820            $(document).trigger('dgwtWcasDetailsPanelLoaded', that);
1821            document.dispatchEvent(new CustomEvent('fibosearch/show-details-panel', {
1822                detail: that
1823            }));
1824        },
1825        updatePrices: function (noAjax) {
1826            var that = this,
1827                i, j,
1828                productsToLoad = [];
1829
1830            if (!(that.options.showPrice && that.options.dynamicPrices)) {
1831                return;
1832            }
1833
1834            if (that.suggestions.length == 0) {
1835                return;
1836            }
1837
1838            for (i = 0; i < that.suggestions.length; i++) {
1839
1840                if (
1841                    typeof that.suggestions[i].type != 'undefined'
1842                    && (that.suggestions[i].type == 'product' || that.suggestions[i].type == 'product_variation')
1843                ) {
1844                    var key = 'product__' + that.suggestions[i].post_id;
1845
1846                    if (typeof that.cachedPrices[key] != 'undefined') {
1847
1848                        that.updatePrice(i, that.cachedPrices[key]);
1849
1850                    } else {
1851
1852                        that.applyPreloaderForPrice(i);
1853
1854                        productsToLoad.push(that.suggestions[i].post_id);
1855                    }
1856                }
1857
1858            }
1859
1860
1861            if (!noAjax && productsToLoad.length > 0) {
1862
1863                var data = {
1864                    action: typeof dgwt_wcas.action_get_prices == 'undefined' ? 'dgwt_wcas_get_prices' : dgwt_wcas.action_get_prices,
1865                    items: productsToLoad
1866                };
1867
1868                $.ajax({
1869                    data: data,
1870                    type: 'post',
1871                    url: dgwt_wcas.ajax_prices_endpoint,
1872                    success: function (response) {
1873
1874                        if (typeof response.success != 'undefined' && response.success && response.data.length > 0) {
1875                            for (i = 0; i < response.data.length; i++) {
1876
1877                                var postID = response.data[i].id,
1878                                    price = response.data[i].price;
1879
1880                                if (that.suggestions.length > 0) {
1881                                    for (j = 0; j < that.suggestions.length; j++) {
1882                                        if (
1883                                            typeof that.suggestions[j].type != 'undefined'
1884                                            && (that.suggestions[j].type == 'product' || that.suggestions[j].type == 'product_variation')
1885                                            && that.suggestions[j].post_id == postID
1886                                        ) {
1887
1888                                            var key = 'product__' + postID;
1889
1890                                            that.cachedPrices[key] = price;
1891
1892                                            that.updatePrice(j, price);
1893
1894                                        }
1895                                    }
1896                                }
1897                            }
1898                        }
1899
1900                    },
1901                    error: function (jqXHR, exception) {
1902
1903                    },
1904                });
1905
1906            }
1907
1908        },
1909        updatePrice: function (index, price) {
1910            var that = this;
1911
1912            if (typeof that.suggestions[index] != 'undefined') {
1913
1914                that.suggestions[index].price = price;
1915
1916                var $price = $('.dgwt-wcas-suggestions-wrapp').find('[data-index="' + index + '"] .dgwt-wcas-sp');
1917
1918                if ($price.length) {
1919                    $price.html(price);
1920                }
1921            }
1922
1923        },
1924        applyCustomParams: function (params) {
1925            var that = this;
1926
1927            // Custom params (global)
1928            if (typeof dgwt_wcas.custom_params == 'object') {
1929                var cp = dgwt_wcas.custom_params;
1930                for (var property in cp) {
1931                    params[property] = cp[property];
1932                }
1933            }
1934
1935            // Custom params (local)
1936            var inputCustomParams = that.el.data('custom-params');
1937
1938            if (typeof inputCustomParams === 'object') {
1939                for (var property in inputCustomParams) {
1940                    params[property] = inputCustomParams[property];
1941                }
1942            }
1943
1944            return params;
1945        },
1946        isSetParam: function (param) {
1947            var that = this;
1948            return typeof that.options.params[param] != 'undefined';
1949        },
1950        getParam: function (param) {
1951            var that = this;
1952            return that.isSetParam(param) ? that.options.params[param] : '';
1953        },
1954        applyPreloaderForPrice: function (index) {
1955            var that = this;
1956
1957            if (typeof that.suggestions[index] != 'undefined') {
1958                var $price = $('.dgwt-wcas-suggestions-wrapp').find('[data-index="' + index + '"] .dgwt-wcas-sp');
1959                if ($price.length) {
1960                    $price.html('<div class="dgwt-wcas-preloader-price"><div class="dgwt-wcas-preloader-price-inner"> <div></div><div></div><div></div></div></div>');
1961                }
1962            }
1963        },
1964        prepareSuggestionObjectID: function (suggestion) {
1965            var objectID = '';
1966
1967            if (typeof suggestion != 'undefined' && typeof suggestion.type != 'undefined') {
1968
1969                //Products and post types
1970                if (suggestion.post_id != null) {
1971                    objectID = suggestion.type + '__' + suggestion.post_id;
1972
1973                    if (suggestion.type === 'product_variation') {
1974                        objectID += '__' + suggestion.variation_id;
1975                    }
1976
1977                    // Post types
1978                    if (typeof suggestion.post_type != 'undefined') {
1979                        objectID = suggestion.type + '__' + suggestion.post_id + '__' + suggestion.post_type;
1980                    }
1981
1982                }
1983
1984                //Terms
1985                if (suggestion.term_id != null && suggestion.taxonomy != null) {
1986                    objectID = suggestion.type + '__' + suggestion.term_id + '__' + suggestion.taxonomy;
1987                }
1988            }
1989
1990            return objectID;
1991        },
1992        detailsPanelSetScene: function (objectID) {
1993            var that = this,
1994                $containerDetails = that.getDetailsContainer(),
1995                objectHash = utils.hashCode(objectID),
1996                $el = $containerDetails.find('.dgwt-wcas-details-inner[data-object="' + objectHash + '"]');
1997
1998            if ($el.length) {
1999                that.preloader('hide', 'details', '');
2000                that.detailsPanelClearScene();
2001                $el.addClass('dgwt-wcas-details-inner-active');
2002            }
2003        },
2004        detailsPanelAddToScene: function (objectID) {
2005            var that = this,
2006                $containerDetails = that.getDetailsContainer(),
2007                object = that.cachedDetails[objectID],
2008                objectHash = utils.hashCode(objectID),
2009                html = '';
2010
2011            if (typeof object != 'undefined' && typeof object.html == 'string') {
2012                html = object.html.replace('<div ', '<div data-object="' + objectHash + '" ');
2013            }
2014
2015            if ($containerDetails.find('.dgwt-wcas-details-inner[data-object="' + objectHash + '"]').length == 0) {
2016                $containerDetails.append(html);
2017            }
2018        },
2019        detailsPanelClearScene: function () {
2020            var that = this,
2021                $containerDetails = that.getDetailsContainer(),
2022                $views = $containerDetails.find('.dgwt-wcas-details-inner');
2023
2024            if ($views.length) {
2025                $views.removeClass('dgwt-wcas-details-inner-active');
2026            }
2027        },
2028        selectFirstSuggestion: function (suggestions) {
2029            var that = this,
2030                index = 0,
2031                noResults = false;
2032
2033            if (!that.canShowDetailsPanel()) {
2034                return;
2035            }
2036
2037            if (suggestions != 'undefined' && suggestions.length > 0) {
2038                $.each(that.suggestions, function (i, suggestion) {
2039
2040                    if (
2041                        typeof suggestion.type != 'undefined'
2042                        && suggestion.type != 'more_products'
2043                        && suggestion.type != 'headline'
2044                        && suggestion.type != 'headline-v2'
2045                        && suggestion.type != 'no-results'
2046                    ) {
2047                        index = i;
2048                        return false;
2049                    }
2050
2051                    if (typeof suggestion.type === 'undefined' || suggestion.type === 'no-results') {
2052                        noResults = true;
2053                    }
2054
2055                });
2056            }
2057
2058            if (noResults) {
2059                return;
2060            }
2061
2062            that.latestActivateSource = 'system';
2063            that.getDetails(suggestions[index]);
2064            that.activate(index);
2065        },
2066        isBadQuery: function (q) {
2067            if (!this.options.preventBadQueries) {
2068                return false;
2069            }
2070
2071            var badQueries = this.badQueries,
2072                i = badQueries.length;
2073
2074            while (i--) {
2075                if (q.indexOf(badQueries[i]) === 0) {
2076                    return true;
2077                }
2078            }
2079
2080            return false;
2081        },
2082        hide: function (clear) {
2083            var that = this,
2084                $suggestions = that.getSuggestionsContainer(),
2085                $detailsPanel = that.getDetailsContainer();
2086
2087            if ($.isFunction(that.options.onHide) && that.visible) {
2088                that.options.onHide.call(that.element, container);
2089            }
2090
2091            that.visible = false;
2092            that.selectedIndex = -1;
2093            clearTimeout(that.onChangeTimeout);
2094            $suggestions.hide();
2095            $suggestions.removeClass(that.classes.suggestionsContainerOrientTop);
2096            $suggestions.removeClass(that.classes.fixed);
2097
2098            if (that.canShowDetailsPanel()) {
2099                $detailsPanel.hide();
2100                $detailsPanel.removeClass(that.classes.fixed);
2101            }
2102
2103            that.hidePreSuggestions();
2104
2105            $('body').removeClass('dgwt-wcas-open');
2106            if (!$('html').hasClass('dgwt-wcas-overlay-mobile-on')) {
2107                $('html').removeClass('dgwt-wcas-open-' + that.getSearchStyle());
2108            }
2109            $('body').removeClass('dgwt-wcas-block-scroll');
2110            $('body').removeClass('dgwt-wcas-is-details');
2111            $('body').removeClass('dgwt-wcas-full-width');
2112            $('body').removeClass('dgwt-wcas-nores');
2113            $('body').removeClass('dgwt-wcas-details-outside');
2114            $('body').removeClass('dgwt-wcas-details-right');
2115            $('body').removeClass('dgwt-wcas-details-left');
2116
2117            if (that.autoAligmentprocess != null) {
2118                clearInterval(that.autoAligmentprocess);
2119                that.autoAligmentprocess = null;
2120            }
2121
2122            that.isMouseDownOnSearchElements = false;
2123
2124            if (typeof clear == 'boolean' && clear) {
2125
2126                that.hideCloseButton();
2127
2128                that.currentValue = '';
2129                that.suggestions = [];
2130
2131            }
2132        },
2133        positionIconSearchMode: function ($formWrapper) {
2134            var that = this,
2135                formLeftValue = -20,
2136                $form = that.getForm(),
2137                formWidth = $form.width(),
2138                windowWidth = $(window).width();
2139
2140            var iconLeftOffset = $formWrapper[0].getBoundingClientRect().left;
2141
2142            var iconLeftRatio = (iconLeftOffset + 10) / windowWidth;
2143
2144            formLeftValue = Math.floor(-1 * (formWidth * iconLeftRatio));
2145
2146            // Prevent shifting to the left more than the icon position (also positioned from the left)
2147            formLeftValue = Math.max(formLeftValue, -1 * iconLeftOffset);
2148
2149            $form.css({'left': formLeftValue + 'px'});
2150
2151        },
2152        isActiveIconModeSearch: function () {
2153            var active = false,
2154                $openedElements = $('.dgwt-wcas-layout-icon-open');
2155            if ($openedElements.length > 0) {
2156                active = true;
2157            }
2158            return active;
2159        },
2160        hideIconModeSearch: function () {
2161            var that = this;
2162
2163            if (that.isActiveIconModeSearch() && !utils.isTextSelected()) {
2164                $('.dgwt-wcas-layout-icon-open').removeClass('dgwt-wcas-layout-icon-open');
2165            }
2166        },
2167        hideAfterClickOutsideListener: function () {
2168            var that = this;
2169            if (!('ontouchend' in document)) {
2170
2171                $(document).mouseup(function (e) {
2172                    if (!that.visible) {
2173                        return;
2174                    }
2175
2176                    var outsideForm = !($(e.target).closest('.' + that.options.searchFormClass).length > 0 || $(e.target).hasClass(that.options.searchFormClass)),
2177                        outsideContainer = !($(e.target).closest('.' + that.options.containerClass).length > 0 || $(e.target).hasClass(that.options.containerClass));
2178
2179                    if (!that.canShowDetailsPanel()) {
2180
2181                        if (outsideForm && outsideContainer) {
2182                            that.hide();
2183                        }
2184
2185                    } else {
2186
2187                        var outsidecontainerDetails = !($(e.target).closest('.' + that.options.containerDetailsClass).length > 0 || $(e.target).hasClass(that.options.containerDetailsClass));
2188
2189                        if (outsideForm && outsideContainer && outsidecontainerDetails) {
2190                            that.hide();
2191                        }
2192
2193                    }
2194
2195                });
2196
2197            }
2198        },
2199        suggest: function () {
2200            if (!this.suggestions.length) {
2201                this.hide();
2202                return;
2203            }
2204
2205            var that = this,
2206                options = that.options,
2207                groupBy = options.groupBy,
2208                formatResult = options.formatResult,
2209                value = that.getQuery(that.currentValue),
2210                className = that.classes.suggestion,
2211                classSelected = that.classes.selected,
2212                container = that.getSuggestionsContainer(),
2213                containerDetails = that.getDetailsContainer(),
2214                noSuggestionsContainer = $(that.noSuggestionsContainer),
2215                beforeRender = options.beforeRender,
2216                html = '',
2217                category,
2218                formatGroup = function (suggestion, index) {
2219                    var currentCategory = suggestion.data[groupBy];
2220
2221                    if (category === currentCategory) {
2222                        return '';
2223                    }
2224
2225                    category = currentCategory;
2226
2227                    return '<div class="autocomplete-group"><strong>' + category + '</strong></div>';
2228                };
2229
2230            if (options.triggerSelectOnValidInput && that.isExactMatch(value)) {
2231                that.select(0);
2232                return;
2233            }
2234
2235            $('body').removeClass('dgwt-wcas-nores');
2236
2237            // Build suggestions inner HTML:
2238            $.each(that.suggestions, function (i, suggestion) {
2239
2240                var url = typeof suggestion.url == 'string' && suggestion.url.length ? suggestion.url : '#';
2241
2242                if (groupBy) {
2243                    html += formatGroup(suggestion, value, i);
2244                }
2245
2246                if (typeof suggestion.type == 'undefined' || (suggestion.type != 'product') && suggestion.type != 'product_variation') {
2247
2248                    var classes = className,
2249                        innerClass = 'dgwt-wcas-st',
2250                        prepend = '',
2251                        append = '',
2252                        title = '',
2253                        highlight = true,
2254                        isImg;
2255
2256                    if (suggestion.taxonomy === 'product_cat') {
2257                        classes += ' dgwt-wcas-suggestion-tax dgwt-wcas-suggestion-cat';
2258                        if (!options.showHeadings) {
2259                            prepend += '<span class="dgwt-wcas-st--direct-headline">' + dgwt_wcas.labels['tax_' + suggestion.taxonomy] + '</span>';
2260                        }
2261                        if (typeof suggestion.breadcrumbs != 'undefined' && suggestion.breadcrumbs) {
2262                            title = suggestion.breadcrumbs + ' &gt; ' + suggestion.value;
2263                            append += '<span class="dgwt-wcas-st-breadcrumbs"><span class="dgwt-wcas-st-label-in">' + dgwt_wcas.labels.in + ' </span>' + suggestion.breadcrumbs + '</span>';
2264                            //@TODO RTL support
2265                        }
2266
2267                    } else if (suggestion.taxonomy === 'product_tag') {
2268                        classes += ' dgwt-wcas-suggestion-tax dgwt-wcas-suggestion-tag';
2269                        if (!options.showHeadings) {
2270                            prepend += '<span class="dgwt-wcas-st--direct-headline">' + dgwt_wcas.labels['tax_' + suggestion.taxonomy] + '</span>';
2271                        }
2272                    } else if (options.isPremium && suggestion.taxonomy === options.taxonomyBrands) {
2273                        classes += ' dgwt-wcas-suggestion-tax dgwt-wcas-suggestion-brand';
2274                        if (!options.showHeadings) {
2275                            prepend += '<span class="dgwt-wcas-st--direct-headline">' + dgwt_wcas.labels['tax_' + suggestion.taxonomy] + '</span>';
2276                        }
2277                    } else if (options.isPremium && suggestion.type === 'taxonomy') {
2278                        classes += ' dgwt-wcas-suggestion-tax dgwt-wcas-suggestion-tax-' + suggestion.taxonomy;
2279                        if (!options.showHeadings) {
2280                            prepend += '<span class="dgwt-wcas-st--direct-headline">' + dgwt_wcas.labels['tax_' + suggestion.taxonomy] + '</span>';
2281                        }
2282                    } else if (options.isPremium && suggestion.type === 'vendor') {
2283                        classes += ' dgwt-wcas-suggestion-vendor dgwt-wcas-suggestion-vendor';
2284                        if (!options.showHeadings) {
2285                            prepend += '<span class="dgwt-wcas-st--direct-headline">' + dgwt_wcas.labels.vendor + '</span>';
2286                        }
2287                    } else if (options.isPremium && suggestion.type === 'post' && typeof suggestion.post_type !== 'undefined' && suggestion.post_type === 'post') {
2288                        classes += ' dgwt-wcas-suggestion-pt dgwt-wcas-suggestion-pt-post';
2289                        if (!options.showHeadings) {
2290                            prepend += '<span class="dgwt-wcas-st--direct-headline">' + dgwt_wcas.labels.post + '</span>';
2291                        }
2292                    } else if (options.isPremium && suggestion.type === 'post' && typeof suggestion.post_type !== 'undefined' && suggestion.post_type === 'page') {
2293                        classes += ' dgwt-wcas-suggestion-pt dgwt-wcas-suggestion-pt-page';
2294                        if (!options.showHeadings) {
2295                            prepend += '<span class="dgwt-wcas-st--direct-headline">' + dgwt_wcas.labels.page + '</span>';
2296                        }
2297                    } else if (suggestion.type === 'more_products') {
2298                        classes += ' js-dgwt-wcas-suggestion-more dgwt-wcas-suggestion-more';
2299                        innerClass = 'dgwt-wcas-st-more';
2300                        suggestion.value = dgwt_wcas.labels.show_more + '<span class="dgwt-wcas-st-more-total"> (' + suggestion.total + ')</span>';
2301                        highlight = false;
2302                    } else if (options.showHeadings && suggestion.type === 'headline') {
2303                        classes += ' js-dgwt-wcas-suggestion-headline dgwt-wcas-suggestion-headline';
2304                        if (typeof dgwt_wcas.labels[suggestion.value + '_plu'] != 'undefined') {
2305                            suggestion.value = dgwt_wcas.labels[suggestion.value + '_plu'];
2306                        }
2307                        highlight = false;
2308                    } else {
2309                        classes += ' dgwt-wcas-suggestion-nores';
2310                        suggestion.value = dgwt_wcas.labels.no_results;
2311                        highlight = false;
2312                        if (that.canShowDetailsPanel()) {
2313                            that.detailsPanelClearScene();
2314                        }
2315                        $('body').addClass('dgwt-wcas-nores');
2316                    }
2317
2318                    // Image
2319                    if (typeof suggestion.image_src != 'undefined' && suggestion.image_src) {
2320                        isImg = true;
2321                    }
2322
2323                    title = title.length > 0 ? ' title="' + title + '"' : '';
2324
2325                    html += '<a href="' + url + '" class="' + classes + '" data-index="' + i + '">';
2326
2327                    if (isImg) {
2328                        html += '<span class="dgwt-wcas-si"><img src="' + suggestion.image_src + '" /></span>';
2329                        html += '<div class="dgwt-wcas-content-wrapp">';
2330                    }
2331
2332                    html += '<span' + title + ' class="' + innerClass + '">';
2333
2334                    if (suggestion.type === 'vendor') {
2335                        html += '<span class="dgwt-wcas-st-title">' + prepend + formatResult(suggestion.value, value, highlight, options) + append + '</span>';
2336
2337                        // Vendor city
2338                        if (suggestion.shop_city) {
2339                            html += '<span class="dgwt-wcas-vendor-city"><span> - </span>' + formatResult(suggestion.shop_city, value, true, options) + '</span>';
2340                        }
2341
2342                        // Description
2343                        if (typeof suggestion.desc != 'undefined' && suggestion.desc) {
2344                            html += '<span class="dgwt-wcas-sd">' + formatResult(suggestion.desc, value, true, options) + '</span>';
2345                        }
2346
2347                    } else {
2348                        html += prepend + formatResult(suggestion.value, value, highlight, options) + append;
2349                    }
2350
2351                    html += '</span>';
2352
2353                    html += isImg ? '</div>' : '';
2354                    html += '</a>';
2355                } else {
2356
2357                    html += that.createProductSuggestion(suggestion, i);
2358
2359                }
2360            });
2361
2362            this.adjustContainerWidth();
2363
2364            noSuggestionsContainer.detach();
2365            container.html(html);
2366
2367            if ($.isFunction(beforeRender)) {
2368                beforeRender.call(that.element, container, that.suggestions);
2369            }
2370
2371            container.show();
2372
2373            // Add class on show
2374            $('body').addClass('dgwt-wcas-open');
2375            $('html').addClass('dgwt-wcas-open-' + that.getSearchStyle());
2376
2377            // Reset the latest mousedown position
2378            that.isMouseDownOnSearchElements = false;
2379
2380            that.automaticAlignment();
2381
2382            if (that.canShowDetailsPanel()) {
2383                $('body').addClass('dgwt-wcas-is-details');
2384                containerDetails.show();
2385                that.fixHeight();
2386            }
2387
2388            // Select first value by default:
2389            if (options.autoSelectFirst) {
2390                that.selectedIndex = 0;
2391                container.scrollTop(0);
2392                container.children('.' + className).first().addClass(classSelected);
2393            }
2394
2395            that.visible = true;
2396            that.fixPosition();
2397        },
2398        createProductSuggestion: function (suggestion, index, extClassName) {
2399            var that = this,
2400                html = '',
2401                parent = '',
2402                dataAttrs = '',
2403                options = that.options,
2404                className = that.classes.suggestion,
2405                isImg = false,
2406                value = that.getQuery(that.currentValue),
2407                formatResult = options.formatResult,
2408                url = typeof suggestion.url == 'string' && suggestion.url.length ? suggestion.url : '#';
2409
2410            if (typeof extClassName == 'string') {
2411                className += ' ' + extClassName;
2412            }
2413
2414            // Image
2415            if (options.showImage === true && typeof suggestion.thumb_html != 'undefined') {
2416                isImg = true;
2417            }
2418
2419            var sugVarClass = suggestion.type === 'product_variation' ? ' dgwt-wcas-suggestion-product-var' : '';
2420            // One suggestion HTML
2421            dataAttrs += typeof suggestion.post_id != 'undefined' ? 'data-post-id="' + suggestion.post_id + '" ' : '';
2422            dataAttrs += typeof suggestion.taxonomy != 'undefined' ? 'data-taxonomy="' + suggestion.taxonomy + '" ' : '';
2423            dataAttrs += typeof suggestion.term_id != 'undefined' ? 'data-term-id="' + suggestion.term_id + '" ' : '';
2424            html += '<a href="' + url + '" class="' + className + ' dgwt-wcas-suggestion-product' + sugVarClass + '" data-index="' + index + '" ' + dataAttrs + '>';
2425
2426            // Image
2427            if (isImg) {
2428                html += '<span class="dgwt-wcas-si">' + suggestion.thumb_html + '</span>';
2429            }
2430
2431
2432            html += isImg ? '<div class="dgwt-wcas-content-wrapp">' : '';
2433
2434
2435            // Open Title wrapper
2436            html += '<div class="dgwt-wcas-st">';
2437
2438            // Custom content before title (3rd party)
2439            if (typeof suggestion.title_before != 'undefined' && suggestion.title_before) {
2440                html += suggestion.title_before;
2441            }
2442
2443            // Title
2444            html += '<span class="dgwt-wcas-st-title">' + formatResult(suggestion.value, value, true, options) + parent + '</span>';
2445
2446            // Custom content after title (3rd party)
2447            if (typeof suggestion.title_after != 'undefined' && suggestion.title_after) {
2448                html += suggestion.title_after;
2449            }
2450
2451            // SKU
2452            if (options.showSKU === true && typeof suggestion.sku != 'undefined' && suggestion.sku.length > 0) {
2453                html += '<span class="dgwt-wcas-sku">(' + dgwt_wcas.labels.sku_label + ' ' + formatResult(suggestion.sku, value, true, options) + ')</span>';
2454            }
2455
2456            // Description
2457            if (options.showDescription === true && typeof suggestion.desc != 'undefined' && suggestion.desc) {
2458                html += '<span class="dgwt-wcas-sd">' + formatResult(suggestion.desc, value, true, options) + '</span>';
2459            }
2460
2461            // Vendor
2462            if (options.showProductVendor === true && typeof suggestion.vendor != 'undefined' && suggestion.vendor) {
2463                var vendorBody = '<span class="dgwt-wcas-product-vendor"><span class="dgwt-wcas-product-vendor-label">' + dgwt_wcas.labels.vendor_sold_by + ' </span>' + suggestion.vendor + '</span>'
2464
2465                if (typeof suggestion.vendor_url != 'undefined' && suggestion.vendor_url) {
2466                    // Since version v1.12.0 suggestions tag was changed from <div> to <a> and vendor links are no longer supported.
2467                    html += '<span class="dgwt-wcas-product-vendor-link" data-url="' + suggestion.vendor_url + '">' + vendorBody + '</span>';
2468                } else {
2469                    html += vendorBody;
2470                }
2471
2472            }
2473
2474            // Custom content after description (3rd party)
2475            if (typeof suggestion.content_after != 'undefined' && suggestion.content_after) {
2476                html += suggestion.content_after;
2477            }
2478
2479            // Close title wrapper
2480            html += '</div>';
2481
2482
2483            var showPrice = options.showPrice === true && typeof suggestion.price != 'undefined',
2484                showMetaBefore = typeof suggestion.meta_before != 'undefined',
2485                showMetaAfter = typeof suggestion.meta_after != 'undefined',
2486                showMeta = showPrice || showMetaBefore || showMetaAfter;
2487            // @todo show sale and featured badges
2488
2489            // Meta
2490            html += showMeta ? '<div class="dgwt-wcas-meta">' : '';
2491
2492            // Custom content before meta (3rd party)
2493            if (showMetaBefore) {
2494                html += suggestion.meta_before;
2495            }
2496
2497            // Price
2498            if (showPrice) {
2499                html += '<span class="dgwt-wcas-sp">' + suggestion.price + '</span>';
2500            }
2501
2502            // Custom content after meta (3rd party)
2503            if (showMetaAfter) {
2504                html += suggestion.meta_after;
2505            }
2506
2507            // Close Meta
2508            html += showMeta ? '</div>' : '';
2509
2510            html += isImg ? '</div>' : '';
2511            html += '</a>';
2512
2513            return html;
2514        },
2515        getSearchStyle: function () {
2516            var that = this,
2517                $searchWrapp = that.getFormWrapper(),
2518                style = 'solaris'; //Default style
2519
2520            $($searchWrapp.attr('class').split(/\s+/)).each(function (index) {
2521                if (/dgwt-wcas-style-/i.test(this)) {
2522                    style = this.replace(/dgwt-wcas-style-/i, '');
2523                }
2524            });
2525
2526            return style;
2527        },
2528        adjustContainerWidth: function () {
2529            var that = this,
2530                $searchBar = that.getFormWrapper(),
2531                $suggestions = that.getSuggestionsContainer(),
2532                $detailsPanel = that.getDetailsContainer(),
2533                $baseElement = that.getForm(),
2534                baseWidth = $baseElement.outerWidth();
2535
2536            if (!$searchBar.length) {
2537                return;
2538            }
2539
2540            // Mode 1 - suggestions wrapper width is the same as search bar width
2541            $suggestions.css('width', baseWidth + 'px');
2542
2543            // Mode 2 - keep the suggestions wrapper and the details panel together under the search bar
2544            if (that.canShowDetailsPanel() && baseWidth >= that.options.dpusbBreakpoint) {
2545                var measurementError = 0;
2546
2547                // Width 50:50
2548                $suggestions.css('width', baseWidth / 2);
2549                $detailsPanel.css('width', baseWidth / 2);
2550
2551                // Fix browsers subtleties such as calculating sizes as float numbers.
2552                measurementError = baseWidth - ($suggestions.outerWidth() + $detailsPanel.outerWidth());
2553                if (measurementError != 0) {
2554                    $detailsPanel.css('width', $detailsPanel.outerWidth() + measurementError);
2555                }
2556            }
2557        },
2558        positionPreloaderAndMic: function ($formWrapper) {
2559            var that = this;
2560
2561            var $submit = typeof $formWrapper == 'object' ? $formWrapper.find('.dgwt-wcas-search-submit') : $('.dgwt-wcas-search-submit');
2562
2563            if ($submit.length > 0) {
2564                $submit.each(function () {
2565                    var $preloader = $(this).closest('.dgwt-wcas-search-wrapp').find('.dgwt-wcas-preloader'),
2566                        isSolarisStyle = $(this).closest('.dgwt-wcas-search-wrapp').hasClass('dgwt-wcas-style-solaris'),
2567                        isVoiceSearchSupported = $(this).closest('.dgwt-wcas-search-wrapp').hasClass(that.options.voiceSearchSupportedClass),
2568                        $voiceSearch = $(this).closest('.dgwt-wcas-search-wrapp').find('.' + that.options.voiceSearchClass);
2569
2570                    if (isVoiceSearchSupported && isSolarisStyle) {
2571                        if (dgwt_wcas.is_rtl == 1) {
2572                            $voiceSearch.css('left', $(this).outerWidth() + 'px');
2573                        } else {
2574                            $voiceSearch.css('right', $(this).outerWidth() + 'px');
2575                        }
2576                    }
2577
2578                    if (dgwt_wcas.is_rtl == 1) {
2579                        $preloader.css('left', $(this).outerWidth() + 'px');
2580                    } else {
2581                        $preloader.css('right', $(this).outerWidth() + 'px');
2582                    }
2583
2584                });
2585            }
2586
2587        },
2588        /*
2589         * Manages preloader
2590         *
2591         * @param action (show or hide)
2592         * @param container (parent selector)
2593         * @param cssClass
2594         */
2595        preloader: function (action, place, cssClass) {
2596            var that = this,
2597                html,
2598                $container,
2599                defaultClass = 'dgwt-wcas-preloader-wrapp',
2600                cssClasses = cssClass == null ? defaultClass : defaultClass + ' ' + cssClass;
2601
2602            if (place === 'form') {
2603
2604                // Return early if the preloader is disable via the settings for a search bar
2605                if (dgwt_wcas.show_preloader != 1) {
2606                    return;
2607                }
2608
2609                $container = that.getFormWrapper().find('.dgwt-wcas-preloader');
2610            } else if (place === 'details') {
2611                $container = that.getDetailsContainer();
2612            }
2613
2614            if ($container.length == 0) {
2615                return;
2616            }
2617
2618            // Handle preloader for a search bar
2619            if (place === 'form') {
2620                if (action === 'hide') {
2621                    $container.removeClass(cssClass);
2622                    $container.html('');
2623                } else {
2624                    $container.addClass(cssClass);
2625                    if (typeof dgwt_wcas.preloader_icon == 'string') {
2626                        $container.html(dgwt_wcas.preloader_icon);
2627                    }
2628                }
2629                return;
2630            }
2631
2632            // Handle preloader for a details panel
2633            var $preloader = $container.find('.' + defaultClass);
2634
2635            // Action hide
2636            if (action === 'hide') {
2637                if ($preloader.length) {
2638                    $preloader.remove();
2639                }
2640                return
2641            }
2642
2643            // Action show
2644            if (action === 'show') {
2645                var rtlSuffix = that.options.isRtl ? '-rtl' : '';
2646                html = '<div class="' + cssClasses + '"><img class="dgwt-wcas-placeholder-preloader" src="' + dgwt_wcas.img_url + 'placeholder' + rtlSuffix + '.png" /></div>';
2647                that.detailsPanelClearScene();
2648                if ($preloader.length) {
2649                    $preloader.remove();
2650                }
2651                $container.prepend(html);
2652            }
2653        },
2654        verifySuggestionsFormat: function (suggestions) {
2655
2656            // If suggestions is string array, convert them to supp
2656orted format:
2657            if (suggestions.length && typeof suggestions[0] === 'string') {
2658                return $.map(suggestions, function (value) {
2659                    return {value: value, data: null};
2660                });
2661            }
2662
2663            return suggestions;
2664        },
2665        processResponse: function (result, originalQuery, cacheKey) {
2666            var that = this,
2667                options = that.options;
2668
2669            result.suggestions = that.verifySuggestionsFormat(result.suggestions);
2670
2671            // Cache results if cache is not disabled:
2672            if (!options.noCache) {
2673                that.cachedResponse[cacheKey] = result;
2674                if (options.preventBadQueries && !result.suggestions.length) {
2675                    that.badQueries.push(originalQuery);
2676                }
2677            }
2678
2679            // Return if originalQuery is not matching current query:
2680            if (originalQuery !== that.getQuery(that.currentValue)) {
2681                return;
2682            }
2683
2684            that.suggestions = result.suggestions;
2685            that.suggest();
2686        },
2687        activate: function (index) {
2688            var that = this,
2689                activeItem,
2690                selected = that.classes.selected,
2691                container = that.getSuggestionsContainer(),
2692                children = container.find('.' + that.classes.suggestion);
2693
2694            container.find('.' + selected).removeClass(selected);
2695
2696            that.selectedIndex = index;
2697
2698            if (that.selectedIndex !== -1 && children.length > that.selectedIndex) {
2699                activeItem = children.get(that.selectedIndex);
2700                $(activeItem).addClass(selected);
2701                return activeItem;
2702            }
2703
2704            return null;
2705        },
2706        selectHint: function () {
2707            var that = this,
2708                i = $.inArray(that.hint, that.suggestions);
2709
2710            that.select(i);
2711        },
2712        select: function (i) {
2713            var that = this;
2714
2715            if (that.options.disableHits) {
2716                return;
2717            }
2718
2719            // Break early if a "select" event isn't related to suggestions
2720            if (typeof that.suggestions[i] == 'undefined') {
2721                return;
2722            }
2723
2724            // Don't select if there is headline element
2725            if (typeof that.suggestions[i] != 'undefined'
2726                && (that.suggestions[i].type == 'headline' || that.suggestions[i].type == 'headline-v2')) {
2727                return;
2728            }
2729
2730            that.closeOverlayMobile();
2731            that.hide();
2732            that.onSelect(i);
2733        },
2734        moveUp: function () {
2735            var that = this;
2736
2737            if (that.selectedIndex === -1) {
2738                return;
2739            }
2740
2741            that.latestActivateSource = 'key';
2742
2743            if (that.selectedIndex === 0) {
2744                that.getSuggestionsContainer().children('.' + that.classes.suggestion).first().removeClass(that.classes.selected);
2745                that.selectedIndex = -1;
2746                that.ignoreValueChange = false;
2747                that.el.val(that.currentValue);
2748                return;
2749            }
2750
2751            that.adjustScroll(that.selectedIndex - 1, 'up');
2752        },
2753        moveDown: function () {
2754            var that = this;
2755
2756            if (that.selectedIndex === (that.suggestions.length - 1)) {
2757                return;
2758            }
2759
2760            that.latestActivateSource = 'key';
2761
2762            that.adjustScroll(that.selectedIndex + 1, 'down');
2763        },
2764        adjustScroll: function (index, direction) {
2765            var that = this;
2766
2767
2768            if (that.suggestions[index].type === 'headline') {
2769                index = direction === 'down' ? index + 1 : index - 1;
2770            }
2771
2772            if (typeof that.suggestions[index] == 'undefined') {
2773                return;
2774            }
2775
2776            var activeItem = that.activate(index);
2777
2778            that.getDetails(that.suggestions[index]);
2779
2780            if (that.suggestions[index].type === 'more_products') {
2781
2782                return;
2783            }
2784
2785            if (!activeItem || that.canShowDetailsPanel()) {
2786                return;
2787            }
2788
2789            var offsetTop,
2790                upperBound,
2791                lowerBound,
2792                $suggestionContainer = that.getSuggestionsContainer(),
2793                heightDelta = $(activeItem).outerHeight(false);
2794
2795            offsetTop = activeItem.offsetTop;
2796            upperBound = $suggestionContainer.scrollTop();
2797            lowerBound = upperBound + that.options.maxHeight - heightDelta;
2798
2799            if (offsetTop < upperBound) {
2800                $suggestionContainer.scrollTop(offsetTop);
2801            } else if (offsetTop > lowerBound) {
2802                $suggestionContainer.scrollTop(offsetTop - that.options.maxHeight + heightDelta);
2803            }
2804
2805            if (!that.options.preserveInput) {
2806                // During onBlur event, browser will trigger "change" event,
2807                // because value has changed, to avoid side effect ignore,
2808                // that event, so that correct suggestion can be selected
2809                // when clicking on suggestion with a mouse
2810                that.ignoreValueChange = true;
2811                //that.el.val(that.getValue(that.suggestions[index].value));
2812            }
2813        },
2814        onSelect: function (index) {
2815            var that = this,
2816                onSelectCallback = that.options.onSelect,
2817                suggestion = that.suggestions[index],
2818                forceSubmit = false;
2819
2820            if (typeof suggestion.type != 'undefined') {
2821                if (
2822                    suggestion.type === 'more_products'
2823                    || (that.actionTriggerSource === 'enter' && that.latestActivateSource != 'key' && suggestion.type != 'product_variation')
2824                ) {
2825                    that.el.closest('form').trigger('submit');
2826                    forceSubmit = true;
2827                }
2828
2829                if (suggestion.type === 'history-search') {
2830                    that.currentValue = that.getValue(suggestion.value);
2831                    if (that.currentValue !== that.el.val() && !that.options.preserveInput) {
2832                        that.el.val(that.currentValue.replace(/(<([^>]+)>)/gi, ' ').replace(/\s\s+/g, ' '));
2833                    }
2834                    that.el.closest('form').trigger('submit');
2835                    forceSubmit = true;
2836                }
2837
2838            }
2839
2840            if (suggestion.type === 'product' || suggestion.type === 'product_variation') {
2841                if (that.options.showRecentlySearchedProducts) {
2842                    that.saveHistoryProducts(suggestion);
2843                }
2844            }
2845
2846            if (!forceSubmit) {
2847
2848                that.currentValue = that.getValue(suggestion.value);
2849
2850                if (that.currentValue !== that.el.val() && !that.options.preserveInput) {
2851                    that.el.val(that.currentValue.replace(/(<([^>]+)>)/gi, ' ').replace(/\s\s+/g, ' '));
2852                }
2853
2854                if (suggestion.url.length > 0) {
2855                    window.location.href = suggestion.url;
2856                }
2857
2858                that.suggestions = [];
2859                that.selection = suggestion;
2860            }
2861
2862            if ($.isFunction(onSelectCallback)) {
2863                onSelectCallback.call(that.element, suggestion);
2864            }
2865        },
2866        openInNewTab: function (index) {
2867            var that = this,
2868                suggestion = that.suggestions[index];
2869            if (suggestion.url.length > 0) {
2870                window.open(suggestion.url, '_blank').focus();
2871            }
2872        },
2873        getValue: function (value) {
2874            var that = this,
2875                delimiter = that.options.delimiter,
2876                currentValue,
2877                parts;
2878
2879            if (!delimiter) {
2880                return value;
2881            }
2882
2883            currentValue = that.currentValue;
2884            parts = currentValue.split(delimiter);
2885
2886            if (parts.length === 1) {
2887                return value;
2888            }
2889
2890            return currentValue.substr(0, currentValue.length - parts[parts.length - 1].length) + value;
2891        },
2892        dispose: function () {
2893            var that = this,
2894                $el = that.el,
2895                $formWrapper = that.getFormWrapper(),
2896                $suggestionsWrapper = that.getSuggestionsContainer(),
2897                $mobileHandler = $formWrapper.find('.js-dgwt-wcas-enable-mobile-form');
2898
2899            // Remove all events
2900            if ($formWrapper.length) {
2901                var $items = $formWrapper.find('*');
2902                $items.each(function () {
2903                    $(this).off('.autocomplete');
2904                });
2905            }
2906
2907            $el.off('fibosearch/ping');
2908
2909            $formWrapper.off('click.autocomplete', '.js-dgwt-wcas-search-icon-handler');
2910
2911            $el.removeData('autocomplete');
2912            $(window).off('resize.autocomplete', that.fixPosition);
2913
2914            $formWrapper.removeClass('dgwt-wcas-active');
2915
2916            that.close(false);
2917
2918            // Remove mobile handler
2919            if ($mobileHandler.length) {
2920                $mobileHandler.remove();
2921            }
2922
2923            if ($suggestionsWrapper.length) {
2924                $suggestionsWrapper.html('');
2925            }
2926        },
2927        isMountedOverlayDarkened: function () {
2928            var that = this,
2929                $wrapp = that.getFormWrapper(),
2930                mounted = false;
2931
2932            if ($wrapp.hasClass(that.classes.darkenOverlayMounted)) {
2933                mounted = true;
2934            }
2935            return mounted;
2936        },
2937        enableOverlayDarkened: function () {
2938            var that = this,
2939                options = that.options,
2940                $formWrapper;
2941
2942            if (!that.isMountedOverlayDarkened()) {
2943                return;
2944            }
2945
2946            $formWrapper = that.getFormWrapper();
2947
2948            $formWrapper.addClass('dgwt-wcas-search-darkoverl-on');
2949            $('body').addClass('dgwt-wcas-darkoverl-on');
2950
2951            // Create node
2952            if ($('.' + options.darkenedOverlayClass).length == 0) {
2953                var html = '<div class="' + options.darkenedOverlayClass + '"><div></div><div></div><div></div><div></div></div>';
2954                $('body').append(html);
2955                var $darkenedOverlay = $('.' + that.options.darkenedOverlayClass);
2956
2957                that.positionOverlayDarkened();
2958
2959                $darkenedOverlay.on('click.autocomplete', function (e) {
2960                    that.disableOverlayDarkened();
2961                });
2962
2963            }
2964
2965            that.overlayDarkenedState = 'on';
2966
2967        },
2968        disableOverlayDarkened: function () {
2969            var that = this,
2970                options = that.options,
2971                $wrapps;
2972
2973            if (!that.isMountedOverlayDarkened()) {
2974                return;
2975            }
2976
2977            $wrapps = $('.dgwt-wcas-search-darkoverl-on');
2978
2979            if ($wrapps.length) {
2980                $wrapps.removeClass('dgwt-wcas-search-darkoverl-on');
2981            }
2982            $('body').removeClass('dgwt-wcas-darkoverl-on');
2983
2984
2985            var $el = $('.' + options.darkenedOverlayClass);
2986            if ($el.length > 0) {
2987                $el.remove();
2988                that.overlayDarkenedState = 'off';
2989            }
2990        },
2991        positionOverlayDarkened: function () {
2992            var that = this,
2993                fixed = false,
2994                $darkenedOverlay = $('.' + that.options.darkenedOverlayClass);
2995
2996            if ($darkenedOverlay.length > 0) {
2997
2998                if (that.ancestorHasPositionFixed(that.getFormWrapper())) {
2999                    fixed = true;
3000                    $darkenedOverlay.addClass('dgwt-wcas-suggestions-wrapp-fixed');
3001                } else {
3002                    $darkenedOverlay.removeClass('dgwt-wcas-suggestions-wrapp-fixed');
3003                }
3004
3005                $darkenedOverlay.children('div').each(function (i) {
3006                    that.positionOverlayDarkenedDiv($(this), i + 1, fixed);
3007                });
3008            }
3009        },
3010        positionOverlayDarkenedDiv: function ($el, orient, fixed) {
3011            var that = this,
3012                elData,
3013                $baseEl = that.getFormWrapper(),
3014                css,
3015                secureOffset = 200; // Secure buffer
3016
3017
3018            // Different position for search icon layout
3019            if ($baseEl.hasClass('js-dgwt-wcas-layout-icon')) {
3020                $baseEl = that.getForm();
3021            }
3022
3023            elData = that.getElementInfo($baseEl);
3024
3025            /**
3026             * Note 1: If fixed == true, it means position should be calculated related to screen,
3027             *         otherwise it will be calculated related to document
3028             *
3029             * Note 2: It concerns cases 1,3 and 4. 1px is subtracted to achieve an exact match of document height.
3030             *         I don't know why it's needed.
3031             */
3032
3033            switch (orient) {
3034                case 1:
3035                    css = {
3036                        left: (-secureOffset) + 'px',
3037                        top: (-secureOffset) + 'px',
3038                        width: (elData.left + secureOffset) + 'px',
3039                        height: ($(document).outerHeight(false) + secureOffset - 1) + 'px'
3040                    };
3041                    break;
3042                case 2:
3043                    var topSpan = fixed ? elData.topViewPort : elData.top;
3044                    css = {
3045                        left: (-secureOffset) + 'px',
3046                        top: (-secureOffset) + 'px',
3047                        width: ($(window).outerWidth(false) + secureOffset) + 'px',
3048                        height: (topSpan + secureOffset) + 'px',
3049                    };
3050                    break;
3051                case 3:
3052                    css = {
3053                        left: (elData.left + elData.width) + 'px',
3054                        top: (-secureOffset) + 'px',
3055                        width: ($(window).outerWidth(false) - elData.right) + 'px',
3056                        height: ($(document).outerHeight(false) + secureOffset - 1) + 'px'
3057                    };
3058                    break;
3059                case 4:
3060                    var topSpan = fixed ? elData.topViewPort : elData.top;
3061                    css = {
3062                        left: (-secureOffset) + 'px',
3063                        top: (topSpan + elData.height) + 'px',
3064                        width: ($(window).outerWidth(false) + secureOffset) + 'px',
3065                        height: ($(document).outerHeight(false) - elData.bottom - 1) + 'px'
3066                    };
3067                    break;
3068            }
3069
3070            if (css) {
3071                $el.css(css);
3072            }
3073        },
3074        showCloseButton: function () {
3075            var that = this,
3076                iconBody = typeof dgwt_wcas.close_icon != 'undefined' ? dgwt_wcas.close_icon : '',
3077                $actionsEl = that.getFormWrapper().find('.' + that.options.preloaderClass);
3078
3079            if (that.el.val().length < that.options.minChars) {
3080                return;
3081            }
3082
3083            // Click close icon
3084            if (!$actionsEl.hasClass(that.options.closeTrigger)) {
3085                $actionsEl.on('click.autocomplete', function () {
3086                    that.close(true);
3087                });
3088            }
3089
3090            $actionsEl.addClass(that.options.closeTrigger);
3091            $actionsEl.html(iconBody);
3092
3093        },
3094        hideCloseButton: function () {
3095            var that = this,
3096                $btn = that.getFormWrapper().find('.' + that.options.closeTrigger);
3097
3098            if ($btn.length) {
3099                $btn.removeClass(that.options.closeTrigger);
3100                $btn.html('');
3101            }
3102
3103            $btn.off('click.autocomplete');
3104        },
3105        canShowPreSuggestions: function () {
3106            var that = this,
3107                canShow = false;
3108
3109            if (that.options.showRecentlySearchedProducts || that.options.showRecentlySearchedPhrases) {
3110                canShow = true;
3111            }
3112
3113            return canShow;
3114        },
3115        showPreSuggestions: function () {
3116            var that = this,
3117                suggestionsIndex = 0,
3118                i,
3119                html = '',
3120                $suggestionsWrapper = that.getSuggestionsContainer(),
3121                $searchBar = that.getFormWrapper(),
3122                noHistory = true,
3123                historyProducts = [],
3124                historySearches = [],
3125                origShowImageOpt = that.options.showImage;
3126
3127            that.isPreSuggestionsMode = true;
3128
3129            that.suggestions = [];
3130            that.suggestionsContainer.addClass('dgwt-wcas-has-img');
3131            if (!origShowImageOpt) {
3132                that.suggestionsContainer.addClass('dgwt-wcas-has-img-forced');
3133            }
3134
3135            that.options.showImage = true;
3136
3137            if (that.options.showRecentlySearchedProducts) {
3138                historyProducts = utils.getLocalStorageItem(that.recentlyViewedProductsKey, []);
3139            }
3140
3141            if (that.options.showRecentlySearchedPhrases) {
3142                historySearches = utils.getLocalStorageItem(that.recentlySearchedPhrasesKey, []);
3143            }
3144
3145            // Break early if there is nothing to show
3146            if (historyProducts.length === 0 && historySearches.length === 0) {
3147                return;
3148            }
3149
3150            // Show headline
3151            that.suggestions.push({type: 'headline-v2', value: '',});
3152            html += '<span class="dgwt-wcas-suggestion dgwt-wcas-suggestion-headline-v2" data-index="' + suggestionsIndex + '">';
3153            if (typeof dgwt_wcas.labels['search_hist'] != 'undefined') {
3154                var label = dgwt_wcas.labels['search_hist'];
3155                label += ' <span class="js-dgwt-wcas-sugg-hist-clear dgwt-wcas-sugg-hist-clear">' + dgwt_wcas.labels['search_hist_clear'] + '</span>';
3156                html += '<span className="dgwt-wcas-st">' + label + '</span>';
3157            }
3158            html += '</span>';
3159            suggestionsIndex++;
3160
3161            // History: products
3162            if (historyProducts.length > 0) {
3163                for (i = 0; i < historyProducts.length; i++) {
3164                    html += that.createProductSuggestion(historyProducts[i], suggestionsIndex, 'dgwt-wcas-suggestion-history-product');
3165                    that.suggestions.push(historyProducts[i]);
3166                    suggestionsIndex++;
3167                }
3168            }
3169
3170
3171            // History: searches
3172            if (historySearches.length > 0) {
3173                for (i = 0; i < historySearches.length; i++) {
3174                    var suggestion = {
3175                        type: 'history-search',
3176                        value: historySearches[i],
3177                        url: '#',
3178                        thumb_html: dgwt_wcas.magnifier_icon
3179                    };
3180
3181                    if ($searchBar.hasClass('dgwt-wcas-style-pirx')) {
3182                        suggestion.thumb_html = dgwt_wcas.magnifier_icon_pirx;
3183                    }
3184
3185                    that.suggestions.push(suggestion);
3186
3187                    html += '<a href="' + suggestion.url + '" class="' + that.classes.suggestion + ' dgwt-wcas-suggestion-history-search" data-index="' + suggestionsIndex + '">';
3188                    html += '<span class="dgwt-wcas-si">' + suggestion.thumb_html + '</span>';
3189                    html += '<div class="dgwt-wcas-content-wrapp">';
3190                    html += '<div class="dgwt-wcas-st"><span class="dgwt-wcas-st-title">' + suggestion.value + '</span></div>'
3191                    html += '</div>';
3192                    html += '</a>';
3193
3194                    suggestionsIndex++;
3195                }
3196            }
3197
3198            // Show pre-suggestions
3199            $suggestionsWrapper.html(html);
3200            $suggestionsWrapper.show();
3201
3202            // Add class on show
3203            $('body').addClass('dgwt-wcas-open');
3204            $('body').addClass('dgwt-wcas-open-pre-suggestions');
3205            $('html').addClass('dgwt-wcas-open-' + that.getSearchStyle());
3206
3207            // Reset the latest mousedown position
3208            that.isMouseDownOnSearchElements = false;
3209
3210            that.visible = true;
3211            that.fixPosition();
3212            that.options.showImage = origShowImageOpt;
3213
3214
3215            document.dispatchEvent(new CustomEvent('fibosearch/open', {
3216                detail: that
3217            }));
3218
3219            document.dispatchEvent(new CustomEvent('fibosearch/show-pre-suggestions', {
3220                detail: that
3221            }));
3222        },
3223        resetPreSuggestions: function () {
3224            var that = this,
3225                $suggestionsWrapp = that.getSuggestionsContainer(),
3226                activeInstance = utils.getActiveInstance();
3227
3228            utils.removeLocalStorageItem(that.recentlyViewedProductsKey);
3229            utils.removeLocalStorageItem(that.recentlySearchedPhrasesKey);
3230
3231            that.suggestions = [];
3232            $suggestionsWrapp.html('');
3233            $('body').removeClass('dgwt-wcas-open-pre-suggestions');
3234
3235            activeInstance.el.focus();
3236        },
3237        hidePreSuggestions: function () {
3238            var that = this;
3239
3240            if (!that.options.showImage) {
3241                that.suggestionsContainer.removeClass('dgwt-wcas-has-img');
3242            }
3243            that.suggestionsContainer.removeClass('dgwt-wcas-has-img-forced');
3244
3245            that.isPreSuggestionsMode = false;
3246        },
3247        saveHistoryProducts: function (suggestion) {
3248            var that = this,
3249                viewedProducts = utils.getLocalStorageItem(that.recentlyViewedProductsKey, []);
3250
3251            viewedProducts = [suggestion, ...viewedProducts];
3252            viewedProducts = [...new Map(viewedProducts.map((item) => {
3253                if (typeof item['price'] != 'undefined') {
3254                    delete item['price'];
3255                }
3256
3257                if (!that.options.showImage) {
3258                    item['thumb_html'] = dgwt_wcas.history_icon;
3259                }
3260                return [item['post_id'], item];
3261            })).values()];
3262            utils.setLocalStorageItem(that.recentlyViewedProductsKey, viewedProducts.slice(0, 5));
3263        },
3264        saveHistorySearches: function (value) {
3265            var that = this,
3266                phrases = utils.getLocalStorageItem(that.recentlySearchedPhrasesKey, []);
3267
3268            phrases = [value, ...phrases];
3269            phrases = [...new Set(phrases)];
3270            utils.setLocalStorageItem(that.recentlySearchedPhrasesKey, phrases.slice(0, 5));
3271        },
3272        addActiveClassIfMissing: function () {
3273            var activeEl = document.activeElement;
3274            if (
3275                typeof activeEl == 'object'
3276                && $(activeEl).length
3277                && $(activeEl).hasClass('dgwt-wcas-search-input')
3278            ) {
3279
3280                var $search = $(activeEl).closest('.dgwt-wcas-search-wrapp');
3281
3282                if ($search.length && !$search.hasClass('dgwt-wcas-active')) {
3283                    $search.addClass('dgwt-wcas-active');
3284                }
3285            }
3286        },
3287        ancestorHasPositionFixed: function ($element) {
3288
3289            var $checkElements = $element.add($element.parents());
3290            var isFixed = false;
3291
3292            $checkElements.each(function () {
3293
3294                if ($(this).css("position") === "fixed") {
3295                    isFixed = true;
3296                    return false;
3297                }
3298            });
3299            return isFixed;
3300        },
3301        gaEvent: function (label, category) {
3302            var that = this;
3303            var gaObj = window.hasOwnProperty('GoogleAnalyticsObject') && window.hasOwnProperty(window['GoogleAnalyticsObject']) ? window[window['GoogleAnalyticsObject']] : false;
3304            if (that.options.sendGAEvents) {
3305                try {
3306                    if (typeof gtag !== 'undefined') {
3307                        gtag('event', 'autocomplete_search', {
3308                            'event_label': label,
3309                            'event_category': category
3310                        });
3311                    } else if (gaObj !== false) {
3312                        var tracker = gaObj.getAll()[0];
3313                        if (tracker) tracker.send({
3314                            hitType: 'event',
3315                            eventCategory: category,
3316                            eventAction: 'autocomplete_search',
3317                            eventLabel: label
3318                        });
3319                    }
3320                } catch (error) {
3321                }
3322            }
3323            if (that.options.enableGASiteSearchModule) {
3324                try {
3325                    if (typeof gtag !== 'undefined') {
3326                        gtag('event', 'page_view', {
3327                            'page_path': '/?s=' + encodeURI(label) + '&post_type=product&dgwt_wcas=1',
3328                        });
3329                    } else if (gaObj !== false) {
3330                        var tracker2 = gaObj.getAll()[0];
3331                        if (tracker2) {
3332                            tracker2.set('page', '/?s=' + encodeURI(label) + '&post_type=product&dgwt_wcas=1');
3333                            tracker2.send('pageview');
3334                        }
3335                    }
3336                } catch (error) {
3337                }
3338            }
3339
3340            $(document).trigger('dgwtWcasGAEvent', {'term': label, 'category': category});
3341        },
3342        initVoiceSearch: function () {
3343            var that = this;
3344            if (!that.options.voiceSearchEnabled) {
3345                return false;
3346            }
3347            var $formWrapper = that.getFormWrapper();
3348            var $input = $formWrapper.find('.' + that.options.searchInputClass);
3349            var $voiceSearch = $formWrapper.find('.' + that.options.voiceSearchClass);
3350
3351            var speechRecognition = false;
3352            if (typeof SpeechRecognition === "function") {
3353                speechRecognition = SpeechRecognition;
3354            } else if (typeof webkitSpeechRecognition === "function") {
3355                speechRecognition = webkitSpeechRecognition;
3356            }
3357            if (!speechRecognition) {
3358                return false;
3359            }
3360
3361            if (utils.isBrowser('Chrome') && utils.isIOS()) {
3362                // Chrome speech recognition on iPhone and iPad is not working well.
3363                return false;
3364            }
3365
3366            that.voiceSearchSetState('inactive', $voiceSearch);
3367            $formWrapper.addClass(that.options.voiceSearchSupportedClass);
3368
3369            that.voiceSearchRecognition = new speechRecognition();
3370            that.voiceSearchRecognition.lang = that.options.voiceSearchLang;
3371            that.voiceSearchRecognition.continuous = false;
3372            that.voiceSearchRecognition.interimResults = true;
3373            that.voiceSearchRecognition.maxAlternatives = 1;
3374
3375            $voiceSearch.on('click', function () {
3376                if (
3377                    $formWrapper.hasClass('dgwt-wcas-mobile-overlay-trigger-active') &&
3378                    !$('html').hasClass('dgwt-wcas-overlay-mobile-on')
3379                ) {
3380                    $formWrapper.find('.js-dgwt-wcas-enable-mobile-form').click();
3381                    $formWrapper.find('.' + that.options.searchInputClass).blur();
3382                }
3383                if (that.voiceSearchStarted) {
3384                    that.voiceSearchAbort();
3385                    return;
3386                }
3387                if (that.voiceSearchIsInitialized()) {
3388                    that.voiceSearchAbort();
3389                }
3390                that.voiceSearchRecognition.start();
3391            });
3392
3393            that.voiceSearchRecognition.onstart = function (event) {
3394                that.voiceSearchSetState('active', $voiceSearch);
3395            }
3396
3397            that.voiceSearchRecognition.onresult = function (event) {
3398                const result = event.results[0];
3399                const text = result[0].transcript;
3400                $input.val(text);
3401                if (result.isFinal) {
3402                    $input.trigger('change');
3403                    if (!('ontouchend' in document)) {
3404                        $input.focus();
3405                    }
3406                    that.voiceSearchSetState('inactive', $voiceSearch);
3407                }
3408            }
3409
3410            that.voiceSearchRecognition.onspeechend = function () {
3411                that.voiceSearchSetState('inactive', $voiceSearch);
3412                that.voiceSearchRecognition.stop();
3413            }
3414
3415            that.voiceSearchRecognition.onnomatch = function (event) {
3416                that.voiceSearchSetState('inactive', $voiceSearch);
3417            }
3418
3419            that.voiceSearchRecognition.onerror = function (event) {
3420                switch (event.error) {
3421                    case 'aborted':
3422                    case 'no-speech':
3423                        that.voiceSearchSetState('inactive', $voiceSearch);
3424                        break;
3425                    case 'network':
3426                        break;
3427                    case 'not-allowed':
3428                    case 'service-not-allowed':
3429                        that.voiceSearchSetState('off', $voiceSearch);
3430                        break;
3431                }
3432            }
3433        },
3434        voiceSearchAbort: function () {
3435            var that = this;
3436            if (that.voiceSearchIsInitialized()) {
3437                that.voiceSearchRecognition.abort();
3438                that.voiceSearchStarted = false;
3439            }
3440        },
3441        voiceSearchIsInitialized: function () {
3442            var that = this;
3443            return that.voiceSearchRecognition !== null;
3444        },
3445        voiceSearchSetState: function (state, $voiceSearch) {
3446            var that = this;
3447            switch (state) {
3448                case 'active':
3449                    that.voiceSearchStarted = true;
3450                    if (typeof dgwt_wcas.voice_search_active_icon == 'string') {
3451                        $voiceSearch.html(dgwt_wcas.voice_search_active_icon);
3452                    }
3453                    // $voiceSearch.removeClass(that.options.voiceSearchDisabledClass).addClass(that.options.voiceSearchActiveClass);
3454                    break;
3455                case 'inactive':
3456                    that.voiceSearchStarted = false;
vendor: 10,714 bytes, lines 3457-3697
3457                    if (typeof dgwt_wcas.voice_search_inactive_icon == 'string') {
3458                        $voiceSearch.html(dgwt_wcas.voice_search_inactive_icon);
3459                    }
3460                    // $voiceSearch.removeClass(that.options.voiceSearchActiveClass + ' ' + that.options.voiceSearchDisabledClass);
3461                    break;
3462                case 'off':
3463                    that.voiceSearchStarted = false;
3464                    // $voiceSearch.removeClass(that.options.voiceSearchActiveClass).addClass(that.options.voiceSearchDisabledClass);
3465                    if (typeof dgwt_wcas.voice_search_disabled_icon == 'string') {
3466                        $voiceSearch.html(dgwt_wcas.voice_search_disabled_icon);
3467                    }
3468                    break;
3469            }
3470        },
3471    };
3472
3473    // Create chainable jQuery plugin:
3474    $.fn.dgwtWcasAutocomplete = function (options, args) {
3475        var dataKey = 'autocomplete';
3476        // If function invoked without argument return
3477        // instance of the first matched element:
3478        if (!arguments.length) {
3479            return this.first().data(dataKey);
3480        }
3481
3482        return this.each(function () {
3483            var inputElement = $(this),
3484                instance = inputElement.data(dataKey);
3485
3486            if (typeof options === 'string') {
3487                if (instance && typeof instance[options] === 'function') {
3488                    instance[options](args);
3489                }
3490            } else {
3491                // If instance already exists, destroy it:
3492                if (instance && instance.dispose) {
3493                    instance.dispose();
3494                }
3495
3496                instance = new DgwtWcasAutocompleteSearch(this, options);
3497                inputElement.data(dataKey, instance);
3498            }
3499        });
3500    };
3501
3502    // Don't overwrite if it already exists
3503    if (!$.fn.autocomplete) {
3504        $.fn.autocomplete = $.fn.dgwtWcasAutocomplete;
3505    }
3506
3507    (function () {
3508        /*-----------------------------------------------------------------
3509        /* IE11 polyfills
3510        /*-----------------------------------------------------------------*/
3511        if (utils.isIE11()) {
3512            // https://polyfill.io/v3/polyfill.min.js?features=Array.prototype.includes%2CString.prototype.includes
3513            (function (self, undefined) {
3514                function Call(t, l) {
3515                    var n = arguments.length > 2 ? arguments[2] : [];
3516                    if (!1 === IsCallable(t)) throw new TypeError(Object.prototype.toString.call(t) + "is not a function.");
3517                    return t.apply(l, n)
3518                }
3519
3520                function CreateMethodProperty(e, r, t) {
3521                    var a = {value: t, writable: !0, enumerable: !1, configurable: !0};
3522                    Object.defineProperty(e, r, a)
3523                }
3524
3525                function Get(n, t) {
3526                    return n[t]
3527                }
3528
3529                function IsCallable(n) {
3530                    return "function" == typeof n
3531                }
3532
3533                function RequireObjectCoercible(e) {
3534                    if (null === e || e === undefined) throw TypeError(Object.prototype.toString.call(e) + " is not coercible to Object.");
3535                    return e
3536                }
3537
3538                function SameValueNonNumber(e, n) {
3539                    return e === n
3540                }
3541
3542                function ToBoolean(o) {
3543                    return Boolean(o)
3544                }
3545
3546                function ToObject(e) {
3547                    if (null === e || e === undefined) throw TypeError();
3548                    return Object(e)
3549                }
3550
3551                function GetV(t, e) {
3552                    return ToObject(t)[e]
3553                }
3554
3555                function GetMethod(e, n) {
3556                    var r = GetV(e, n);
3557                    if (null === r || r === undefined) return undefined;
3558                    if (!1 === IsCallable(r)) throw new TypeError("Method not callable: " + n);
3559                    return r
3560                }
3561
3562                function Type(e) {
3563                    switch (typeof e) {
3564                        case"undefined":
3565                            return "undefined";
3566                        case"boolean":
3567                            return "boolean";
3568                        case"number":
3569                            return "number";
3570                        case"string":
3571                            return "string";
3572                        case"symbol":
3573                            return "symbol";
3574                        default:
3575                            return null === e ? "null" : "Symbol" in self && (e instanceof self.Symbol || e.constructor === self.Symbol) ? "symbol" : "object"
3576                    }
3577                }
3578
3579                function IsRegExp(e) {
3580                    if ("object" !== Type(e)) return !1;
3581                    var n = "Symbol" in self && "match" in self.Symbol ? Get(e, self.Symbol.match) : undefined;
3582                    if (n !== undefined) return ToBoolean(n);
3583                    try {
3584                        var t = e.lastIndex;
3585                        return e.lastIndex = 0, RegExp.prototype.exec.call(e), !0
3586                    } catch (l) {
3587                    } finally {
3588                        e.lastIndex = t
3589                    }
3590                    return !1
3591                }
3592
3593                function OrdinaryToPrimitive(r, t) {
3594                    if ("string" === t) var e = ["toString", "valueOf"]; else e = ["valueOf", "toString"];
3595                    for (var i = 0; i < e.length; ++i) {
3596                        var n = e[i], a = Get(r, n);
3597                        if (IsCallable(a)) {
3598                            var o = Call(a, r);
3599                            if ("object" !== Type(o)) return o
3600                        }
3601                    }
3602                    throw new TypeError("Cannot convert to primitive.")
3603                }
3604
3605                function SameValueZero(n, e) {
3606                    return Type(n) === Type(e) && ("number" === Type(n) ? !(!isNaN(n) || !isNaN(e)) || (1 / n === Infinity && 1 / e == -Infinity || (1 / n == -Infinity && 1 / e === Infinity || n === e)) : SameValueNonNumber(n, e))
3607                }
3608
3609                function ToInteger(n) {
3610                    if ("symbol" === Type(n)) throw new TypeError("Cannot convert a Symbol value to a number");
3611                    var t = Number(n);
3612                    return isNaN(t) ? 0 : 1 / t === Infinity || 1 / t == -Infinity || t === Infinity || t === -Infinity ? t : (t < 0 ? -1 : 1) * Math.floor(Math.abs(t))
3613                }
3614
3615                function ToLength(n) {
3616                    var t = ToInteger(n);
3617                    return t <= 0 ? 0 : Math.min(t, Math.pow(2, 53) - 1)
3618                }
3619
3620                function ToPrimitive(e) {
3621                    var t = arguments.length > 1 ? arguments[1] : undefined;
3622                    if ("object" === Type(e)) {
3623                        if (arguments.length < 2) var i = "default"; else t === String ? i = "string" : t === Number && (i = "number");
3624                        var r = "function" == typeof self.Symbol && "symbol" == typeof self.Symbol.toPrimitive ? GetMethod(e, self.Symbol.toPrimitive) : undefined;
3625                        if (r !== undefined) {
3626                            var n = Call(r, e, [i]);
3627                            if ("object" !== Type(n)) return n;
3628                            throw new TypeError("Cannot convert exotic object to primitive.")
3629                        }
3630                        return "default" === i && (i = "number"), OrdinaryToPrimitive(e, i)
3631                    }
3632                    return e
3633                }
3634
3635                function ToString(t) {
3636                    switch (Type(t)) {
3637                        case"symbol":
3638                            throw new TypeError("Cannot convert a Symbol value to a string");
3639                        case"object":
3640                            return ToString(ToPrimitive(t, String));
3641                        default:
3642                            return String(t)
3643                    }
3644                }
3645
3646                CreateMethodProperty(Array.prototype, "includes", function e(r) {
3647                    "use strict";
3648                    var t = ToObject(this), o = ToLength(Get(t, "length"));
3649                    if (0 === o) return !1;
3650                    var n = ToInteger(arguments[1]);
3651                    if (n >= 0) var a = n; else (a = o + n) < 0 && (a = 0);
3652                    for (; a < o;) {
3653                        var i = Get(t, ToString(a));
3654                        if (SameValueZero(r, i)) return !0;
3655                        a += 1
3656                    }
3657                    return !1
3658                });
3659                CreateMethodProperty(String.prototype, "includes", function e(t) {
3660                    "use strict";
3661                    var r = arguments.length > 1 ? arguments[1] : undefined, n = RequireObjectCoercible(this),
3662                        i = ToString(n);
3663                    if (IsRegExp(t)) throw new TypeError("First argument to String.prototype.includes must not be a regular expression");
3664                    var o = ToString(t), g = ToInteger(r), a = i.length, p = Math.min(Math.max(g, 0), a);
3665                    return -1 !== String.prototype.indexOf.call(i, o, p)
3666                });
3667            })('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof global && global || {});
3668        }
3669
3670        // RUN
3671        $(document).ready(function () {
3672            "use strict";
3673
3674            /*-----------------------------------------------------------------
3675            /* Mobile detection
3676            /*-----------------------------------------------------------------*/
3677            if (utils.isIOS()) {
3678                $('html').addClass('dgwt-wcas-is-ios');
3679            }
3680
3681            /*-----------------------------------------------------------------
3682            /* Set some global variables
3683            /*-----------------------------------------------------------------*/
3684            window.dgwt_wcas.resizeOnlyOnce = null;
3685            window.dgwt_wcas.scrollOnlyOnce = null;
3686
3687            /*-----------------------------------------------------------------
3688            /* Fire autocomplete
3689            /*-----------------------------------------------------------------*/
3690
3691            window.dgwt_wcas.config = {
3692                minChars: dgwt_wcas.min_chars,
3693                width: dgwt_wcas.sug_width,
3694                autoSelectFirst: false,
3695                triggerSelectOnValidInput: false,
3696                serviceUrl: dgwt_wcas.ajax_search_endpoint,
3697                paramName: 's',
3698                showDetailsPanel: dgwt_wcas.show_details_panel == 1 ? true : false,
3699                showImage: dgwt_wcas.show_images == 1 ? true : false,
3700                showPrice: dgwt_wcas.show_price == 1 ? true : false,
3701                showDescription: dgwt_wcas.show_desc == 1 ? true : false,
3702                showSKU: dgwt_wcas.show_sku == 1 ? true : false,
3703                showSaleBadge: dgwt_wcas.show_sale_badge == 1 ? true : false,
3704                showFeaturedBadge: dgwt_wcas.show_featured_badge == 1 ? true : false,
3705                dynamicPrices: typeof dgwt_wcas.dynamic_prices != 'undefined' && dgwt_wcas.dynamic_prices ? true : false,
3706                saleBadgeText: dgwt_wcas.labels.sale_badge,
3707                featuredBadgeText: dgwt_wcas.labels.featured_badge,
3708                isRtl: dgwt_wcas.is_rtl == 1 ? true : false,
3709                showHeadings: dgwt_wcas.show_headings == 1 ? true : false,
3710                isPremium: dgwt_wcas.is_premium == 1 ? true : false,
3711                taxonomyBrands: dgwt_wcas.taxonomy_brands,
3712                layoutBreakpoint: dgwt_wcas.layout_breakpoint,
3713                mobileOverlayBreakpoint: dgwt_wcas.mobile_overlay_breakpoint,
3714                mobileOverlayWrapper: dgwt_wcas.mobile_overlay_wrapper,
3715                mobileOverlayDelay: dgwt_wcas.mobile_overlay_delay,
3716                debounceWaitMs: dgwt_wcas.debounce_wait_ms,
3717                sendGAEvents: dgwt_wcas.send_ga_events,
3718                convertHtml: dgwt_wcas.convert_html,
3719                enableGASiteSearchModule: dgwt_wcas.enable_ga_site_search_module,
3720                appendTo: typeof dgwt_wcas.suggestions_wrapper != 'undefined' ? dgwt_wcas.suggestions_wrapper : 'body',
3721                showProductVendor: typeof dgwt_wcas.show_product_vendor != 'undefined' && dgwt_wcas.show_product_vendor ? true : false,
3722                disableHits: typeof dgwt_wcas.disable_hits != 'undefined' && dgwt_wcas.disable_hits ? true : false,
3723                disableSubmit: typeof dgwt_wcas.disable_submit != 'undefined' && dgwt_wcas.disable_submit ? true : false,
3724                voiceSearchEnabled: typeof dgwt_wcas.voice_search_enabled != 'undefined' && dgwt_wcas.voice_search_enabled ? true : false,
3725                voiceSearchLang: typeof dgwt_wcas.voice_search_lang != 'undefined' ? dgwt_wcas.voice_search_lang : '',
3726                showRecentlySearchedProducts: typeof dgwt_wcas.show_recently_searched_products != 'undefined' ? dgwt_wcas.show_recently_searched_products : false,
3727                showRecentlySearchedPhrases: typeof dgwt_wcas.show_recently_searched_phrases != 'undefined' ? dgwt_wcas.show_recently_searched_phrases : false,
3728            };
3729
3730            $('.dgwt-wcas-search-input').dgwtWcasAutocomplete(window.dgwt_wcas.config);
3731
3732        });
3733
3734
3735        /**
3736         * UI Fixer. Fixes several known UX issues related to search bars
3737         */
3738        var UI_FIXER = {
3739            brokenSearchUi: typeof dgwt_wcas.fixer.broken_search_ui != 'undefined' && dgwt_wcas.fixer.broken_search_ui ? true : false,
3740            brokenSearchUiAjax: typeof dgwt_wcas.fixer.broken_search_ui_ajax != 'undefined' && dgwt_wcas.fixer.broken_search_ui_ajax ? true : false,
3741            brokenSearchUiHard: typeof dgwt_wcas.fixer.broken_search_ui_hard != 'undefined' && dgwt_wcas.fixer.broken_search_ui_hard ? true : false,
3742            brokenSearchElementorPopups: typeof dgwt_wcas.fixer.broken_search_elementor_popups != 'undefined' && dgwt_wcas.fixer.broken_search_elementor_popups ? true : false,
3743            brokenSearchJetMobileMenu: typeof dgwt_wcas.fixer.broken_search_jet_mobile_menu != 'undefined' && dgwt_wcas.fixer.broken_search_jet_mobile_menu ? true : false,
3744            brokenSearchBrowserBackArrow: typeof dgwt_wcas.fixer.broken_search_browsers_back_arrow != 'undefined' && dgwt_wcas.fixer.broken_search_browsers_back_arrow ? true : false,
3745            forceRefreshCheckout: typeof dgwt_wcas.fixer.force_refresh_checkout != 'undefined' && dgwt_wcas.fixer.force_refresh_checkout ? true : false,
3746            searchBars: [],
3747            init: function () {
3748                var that = this;
3749
3750                /**
3751                 * Fix broken search bars UI - first approach, after loading the page
3752                 * Some page builders can copy instances of search bar without events eg. mobile usage.
3753                 */
3754                if (that.brokenSearchUi) {
3755                    $(document).ready(function () {
3756                        that.fixBrokenSearchUi();
3757                    });
3758                }
3759
3760                /**
3761                 *
3762                 */
3763                if (that.brokenSearchUiAjax) {
3764                    that.fixBrokenSearchUiAjax();
3765                }
3766
3767                /**
3768                 * Repair search bars continuously
3769                 * May overload the browser. Disabled by default.
3770                 */
3771                if (that.brokenSearchUiHard) {
3772                    that.fixBrokenSearchUiHard();
3773                }
3774
3775                /**
3776                 * Fix Elementor popups
3777                 * Reinit the search bars after loading Elementor popup
3778                 */
3779                if (that.brokenSearchElementorPopups) {
3780                    $(document).ready(function () {
3781                        that.fixBrokenSearchOnElementorPopupsV1();
3782                        that.fixBrokenSearchOnElementorPopupsV2();
3783                    });
3784                }
3785
3786                /**
3787                 * Fix search bars displayed in Jet Smart Menu
3788                 * if there are duplicated inputs
3789                 */
3790                if (that.brokenSearchJetMobileMenu) {
3791                    $(window).on('load', function () {
3792                        that.fixSearchInJetMobileMenu();
3793                    });
3794                }
3795
3796                /**
3797                 * Fix broken search bars after click browser's back arrow.
3798                 * Not worked for some browsers especially Safari and FF
3799                 * Add dgwt-wcas-active class if wasn't added for some reason
3800                 */
3801                if (that.brokenSearchBrowserBackArrow) {
3802                    that.fixbrokenSearchBrowserBackArrow();
3803                }
3804
3805                /**
3806                 * Refreshing the content on the checkout page when a product is added to the cart from the search Details Panel
3807                 */
3808                if (that.forceRefreshCheckout) {
3809                    that.fixforceRefreshCheckout();
3810                }
3811            },
3812            fixBrokenSearchUi: function () {
3813                var that = this;
3814
3815                $(document).ready(function () {
3816                    setTimeout(function () {
3817                        that.pullAndReconditionSearchBars();
3818                    }, 50);
3819                });
3820
3821                $(window).on('load', function () {
3822                    setTimeout(function () {
3823                        that.pullAndReconditionSearchBars();
3824                    }, 500);
3825                });
3826            },
3827            fixBrokenSearchUiAjax: function () {
3828                var that = this;
3829                $(document).ajaxSuccess(function (event, request, settings) {
3830
3831                    // Exclude FiboSearch and WooCommerce AJAX requests
3832                    if (typeof settings.url == 'string' && new RegExp('search\.php|wc-ajax').test(settings.url)) {
3833                        return;
3834                    }
3835
3836                    if (typeof request.responseText == 'string' && request.responseText.includes('dgwt-wcas-search-input')) {
3837                        setTimeout(function () {
3838                            that.pullAndReconditionSearchBars();
3839                        }, 500);
3840                    }
3841                });
3842            },
3843            fixBrokenSearchUiHard: function () {
3844                var that = this;
3845                $(document).ready(function () {
3846
3847                    if (that.searchBars.length === 0) {
3848                        that.pullAndReconditionSearchBars();
3849                    }
3850
3851                    setInterval(function () {
3852                        that.pullAndReconditionSearchBars();
3853                    }, 1000);
3854                });
3855            },
3856            fixBrokenSearchOnElementorPopupsV1: function () {
3857                var that = this;
3858                $(document).on('elementor/popup/show', () => {
3859                    setTimeout(function () {
3860                        that.pullAndReconditionSearchBars();
3861                    }, 500);
3862                });
3863            },
3864            fixBrokenSearchOnElementorPopupsV2: function () {
3865                var that = this;
3866                $(document).ready(function () {
3867                    if (
3868                        typeof window.elementorFrontend != 'undefined'
3869                        && typeof window.elementorFrontend.documentsManager != 'undefined'
3870                        && typeof window.elementorFrontend.documentsManager.documents != 'undefined'
3871                    ) {
3872
3873                        $.each(elementorFrontend.documentsManager.documents, function (id, document) {
3874
3875                            if (typeof document.getModal != 'undefined' && document.getModal) {
3876
3877                                document.getModal().on('show', function () {
3878                                    setTimeout(function () {
3879                                        that.pullAndReconditionSearchBars();
3880                                    }, 500);
3881
3882                                });
3883                            }
3884                        });
3885                    }
3886                });
3887            },
3888            fixSearchInJetMobileMenu: function () {
3889                var that = this;
3890
3891                if ($('.jet-mobile-menu__toggle').length === 0) {
3892                    return;
3893                }
3894
3895                $(document).ajaxSend(function (event) {
3896
3897                    if (
3898                        typeof event.currentTarget != 'undefined'
3899                        && typeof event.currentTarget.activeElement == 'object'
3900                        && $(event.currentTarget.activeElement).hasClass('jet-mobile-menu__toggle')
3901                    ) {
3902
3903                        setTimeout(function () {
3904                            var $search = $(".jet-mobile-menu__container .dgwt-wcas-search-input");
3905
3906                            if ($search.length > 0) {
3907                                that.pullAndReconditionSearchBars();
3908                            }
3909
3910                        }, 500);
3911
3912                    }
3913                });
3914            },
3915            fixforceRefreshCheckout: function () {
3916                $(document.body).on('added_to_cart', function () {
3917                    if (
3918                        $(document.body).hasClass('woocommerce-checkout') &&
3919                        $('.dgwt-wcas-search-input').length > 0
3920                    ) {
3921                        $(document.body).trigger('update_checkout');
3922                    }
3923                });
3924            },
3925            fixbrokenSearchBrowserBackArrow: function () {
3926                $(window).on('load', function () {
3927                    var i = 0;
3928                    var interval = setInterval(function () {
3929
3930                        var activeEl = document.activeElement;
3931                        if (
3932                            typeof activeEl == 'object'
3933                            && $(activeEl).length
3934                            && $(activeEl).hasClass('dgwt-wcas-search-input')
3935                        ) {
3936
3937                            var $search = $(activeEl).closest('.dgwt-wcas-search-wrapp');
3938
3939                            if ($search.length && !$search.hasClass('dgwt-wcas-active')) {
3940                                $search.addClass('dgwt-wcas-active');
3941                                clearInterval(interval);
3942                            }
3943                        }
3944
3945                        // Stop after 5 seconds
3946                        if (i > 10) {
3947                            clearInterval(interval);
3948                        }
3949
3950                        i++;
3951
3952                    }, 500);
3953                });
3954            },
3955            pullAndReconditionSearchBars: function () {
3956                var that = this,
3957                    $inputs = $('.dgwt-wcas-search-input'),
3958                    firstPull = that.searchBars.length == 0;
3959
3960                if ($inputs.length > 0) {
3961                    $inputs.each(function () {
3962                        var $searchBar = $(this),
3963                            isNew = true,
3964                            i;
3965
3966                        // Check if this search bar is new one or not
3967                        if (that.searchBars.length > 0) {
3968                            for (i = 0; i < that.searchBars.length; i++) {
3969                                if ($searchBar[0] === that.searchBars[i][0]) {
3970                                    isNew = false;
3971                                    break;
3972                                }
3973                            }
3974                        }
3975
3976                        if (isNew) {
3977                            var changedId = false;
3978                            if (!that.hasUniqueId($searchBar)) {
3979                                that.makeUniqueID($searchBar);
3980                                changedId = true;
3981                            }
3982
3983                            if (!firstPull || !that.isInitialized($searchBar) || changedId) {
3984                                that.reinitSearchBar($searchBar)
3985                            }
3986
3987                            that.searchBars.push($searchBar);
3988                        }
3989
3990                        if (!that.hasEvents($searchBar)) {
3991                            that.reinitSearchBar($searchBar)
3992                        }
3993
3994                    });
3995                }
3996            },
3997            hasEvents: function ($searchBarInput) {
3998                var hasEvents = false;
3999                $searchBarInput.trigger('fibosearch/ping');
4000                if ($searchBarInput.hasClass('fibosearch-pong')) {
4001                    hasEvents = true;
4002                }
4003                $('.fibosearch-pong').removeClass('fibosearch-pong');
4004                return hasEvents;
4005            },
4006            isInitialized: function ($searchBarInput) {
4007                return typeof $searchBarInput.data('autocomplete') == 'object';
4008            },
4009            hasUniqueId: function ($searchBarInput) {
4010                var that = this,
4011                    unique = true;
4012                if (that.searchBars.length > 0) {
4013                    for (var i = 0; i < that.searchBars.length; i++) {
4014                        if ($searchBarInput.attr('id') === that.searchBars[i].attr('id')) {
4015                            unique = false;
4016                        }
4017                    }
4018                }
4019                return unique;
4020            },
4021            reinitSearchBar: function ($searchBarInput) {
4022                if (typeof $searchBarInput.data('autocomplete') == 'object') {
4023                    $searchBarInput.data('autocomplete').dispose();
4024                }
4025                $searchBarInput.dgwtWcasAutocomplete(window.dgwt_wcas.config);
4026            },
4027            makeUniqueID: function ($searchBarInput) {
4028                var newID = Math.random().toString(36).substring(2, 6);
4029                newID = 'dgwt-wcas-search-input-' + newID;
4030
4031                $searchBarInput.attr('id', newID);
4032                $searchBarInput.closest('form').find('label').attr('for', newID);
4033            },
4034        }
4035
4036        if (typeof dgwt_wcas.fixer.core == 'undefined') {
4037            dgwt_wcas.fixer.core = UI_FIXER;
4038            dgwt_wcas.fixer.core.init();
4039        }
4040
4041    }());
4042
4043}));

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.