PageSourceSearch

https://1939.ru/assets/components/msearch2/js/web/custom.js

js 1939.ru collected 2026-10-02 17:55:11 UTC 50,798 bytes, 1,320 lines download raw bytes

1mse2Config = mse2Config || {};
2var mSearch2 = {
3    initialized: false,
4    loading: false,
5    reached: false,
6    options: {
7        wrapper: '#mse2_mfilter',
8
9        results: '#mse2_results',
10        total: '#mse2_total',
11        limit: '#mse2_limit',
12        slider: '.mse2_number_slider',
13
14        filters: '#mse2_filters',
15        filter_title: '.filter_title',
16        filter_wrapper: 'fieldset',
17
18        pagination: '.mse2_pagination',
19        pagination_link: '.mse2_pagination a',
20
21        sort: '#mse2_sort',
22        sort_link: '#mse2_sort a',
23
24        tpl: '#mse2_tpl',
25        tpl_link: '#mse2_tpl a',
26
27        selected: '#mse2_selected',
28        selected_tpl: '<a href="#" data-id="_id_" class="mse2_selected_link"><em>_title_</em><sup>x</sup></a>',
29        selected_wrapper_tpl: '<strong>_title_:</strong>',
30        selected_filters_delimeter: '; ',
31        selected_values_delimeter: ' ',
32
33        more: '.btn_more',
34        more_tpl: '<div class="text-center"><button class="btn btn-default btn_more">' + mse2Config['moreText'] + '</button></div>',
35
36        active_class: 'active',
37        disabled_class: 'disabled',
38        disabled_class_fieldsets: 'disabled_fieldsets',
39        loading_class: 'loading',
40        prefix: 'mse2_',
41        suggestion: 'sup', // inside filter item, e.g. #mse2_filters
42        autoLoad: true,
43    },
44    sliders: {},
45    numbers: {},
46    selections: {},
47    elements: ['filters', 'results', 'pagination', 'total', 'sort', 'selected', 'limit', 'tpl'],
48    initialize: function (selector) {
49        if (this.initialized) {
50            return false;
51        }
52        var i;
53        if (mse2Config['filterOptions'] != undefined && Object.keys(mse2Config['filterOptions']).length > 0) {
54            for (i in mse2Config['filterOptions']) {
55                if (mse2Config['filterOptions'].hasOwnProperty(i)) {
56                    this.options[i] = mse2Config['filterOptions'][i];
57                }
58            }
59        }
60        for (i in this.elements) {
61            if (this.elements.hasOwnProperty(i)) {
62                var elem = this.elements[i];
63                this[elem] = $(selector).find(this.options[elem]);
64            }
65        }
66        // Get ready for old chunk
67        if (this['pagination'].length == 0) {
68            this.options['pagination'] = '#mse2_pagination';
69            this.options['pagination_link'] = '#mse2_pagination a';
70            this['pagination'] = $(selector).find(this.options['pagination']);
71        }
72        this.handlePagination();
73        this.handleSort();
74        this.handleTpl();
75        this.handleNumbers();
76        this.handleSlider();
77        this.handleLimit();
78
79        var submit = $(this.options.filters + ' [type="submit"]');
80        if (this.options.autoLoad) {
81            $(document).on('change', this.options.filters, function () {
82                return mSearch2.submit();
83            });
84            submit.addClass('hidden');
85        }
86        else {
87            submit.removeClass('hidden');
88        }
89
90        $(document).on('submit', this.options.filters, function () {
91            return mSearch2.submit();
92        });
93
94        this.btn_reset = $(this.options.filters + ' [type="reset"]');
95        $(document).on('reset', this.options.filters, function () {
96            return mSearch2.reset();
97        });
98        if (Object.keys(this.startParams).length) {
99            this.btn_reset.removeClass('hidden');
100        }
101
102        if (this.selected) {
103            this.selections[this.selected.text().replace(/\s+$/, '').replace(/:$/, '')] = [];
104            var selectors = [
105                this.options.filters + ' input[type="checkbox"]',
106                this.options.filters + ' input[type="radio"]',
107                this.options.filters + ' select'
108            ];
109            $(document).on('change', selectors.join(', '), function () {
110                mSearch2.handleSelected($(this));
111            });
112
113            selectors = [
114                'input[type="checkbox"]:checked',
115                'input[type="radio"]:checked',
116                'select'
117            ];
118            this.filters.find(selectors.join(', ')).each(function () {
119                mSearch2.handleSelected($(this));
120            });
121
122            $(document).on('click', this.options.selected + ' a', function () {
123                var id = $(this).data('id').replace(mse2Config['filter_delimeter'], "\\" + mse2Config['filter_delimeter']);
124                var elem = $('#' + id);
125                if (elem[0]) {
126                    switch (elem[0].tagName) {
127                        case 'INPUT':
128                            elem.prop('checked', false).trigger('change');
129                            break;
130                        case 'SELECT':
131                            elem.val(elem.find('option:first').prop('value')).trigger('change');
132                            break;
133                    }
134                }
135                return false;
136            });
137        }
138        mSearch2.setEmptyFieldsets();
139        mSearch2.setTotal(this.total.text());
140
141        if (!mSearch2.Hash.oldbrowser()) {
142            history.replaceState({mSearch2: window.location.href}, '', document.location.href);
143        }
144        window.setTimeout(function() {
145            $(window).on('popstate', function (e) {
146                if (e.originalEvent.state && e.originalEvent.state['mSearch2']) {
147                    var params = {};
148                    var tmp = e.originalEvent.state['mSearch2'].split('?');
149                    if (tmp[1]) {
150                        tmp = tmp[1].split('&');
151                        for (var i in tmp) {
152                            if (tmp.hasOwnProperty(i)) {
153                                var tmp2 = tmp[i].split('=');
154                                params[tmp2[0]] = tmp2[1];
155                            }
156                        }
157                    }
158                    mSearch2.setFilters(params);
159                    mSearch2.load(params);
160                }
161            });
162        }, 1000);
163
164        this.initialized = true;
165    },
166
167    handlePagination: function () {
168        var pcre = new RegExp(mse2Config['pageVar'] + '[=|\/](\\d+)');
169        switch (mse2Config['mode']) {
170            case 'button':
171                this.pagination.hide();
172                // Add more button
173                this.results.after(this.options['more_tpl']);
174                var more = $(this.options['more']);
175
176                var has_results = false;
177                $(this.options['pagination_link']).each(function () {
178                    var href = $(this).prop('href');
179                    var match = href.match(pcre);
180                    var page = !match ? 1 : match[1];
181                    if (page > mse2Config['page']) {
182                        has_results = true;
183                        return false;
184                    }
185                });
186                if (!has_results) {
187                    more.hide();
188                }
189                if (mse2Config['page'] > 1) {
190                    mse2Config['page'] = '';
191                    mSearch2.Hash.remove('page');
192                    mSearch2.load();
193                }
194
195                $(document).on('click', this.options['wrapper'] + ' ' + this.options['more'], function (e) {
196                    e.preventDefault();
197                    mSearch2.addPage();
198                });
199                break;
200
201            case 'scroll':
202                this.pagination.hide();
203                var wrapper = $(this.options['wrapper']);
204                var $window = $(window);
205                $window.on('scroll', function () {
206                    if (!mSearch2.reached && $window.scrollTop() > wrapper.height() - $window.height()) {
207                        mSearch2.reached = true;
208                        mSearch2.addPage();
209                    }
210                });
211
212                if (mse2Config['page'] > 1) {
213                    mse2Config['page'] = '';
214                    mSearch2.Hash.remove('page');
215                    mSearch2.load();
216                }
217                break;
218
219            default:
220                $(document).on('click', this.options.pagination_link, function () {
221                    if (!$(this).hasClass(mSearch2.options.active_class)) {
222                        $(mSearch2.options.pagination).removeClass(mSearch2.options.active_class);
223                        $(this).addClass(mSearch2.options.active_class);
224
225                        var tmp = $(this).prop('href').match(pcre);
226                        var page = tmp && tmp[1] ? Number(tmp[1]) : 1;
227                        mse2Config['page'] = (page != mse2Config['start_page']) ? page : '';
228
229                        var params = mSearch2.getFilters();
230                        mSearch2.Hash.set(params);
231                        mSearch2.load(params, function () {
232                            $('html, body').animate({
233                                scrollTop: $(mSearch2.options.wrapper).position().top || 0
234                            }, 0);
235                        });
236                    }
237
238                    return false;
239                });
240        }
241    },
242
243    handleSort: function () {
244        var params = this.Hash.get();
245        if (params.sort) {
246            var sorts = params.sort.split(mse2Config['values_delimeter']);
247            for (var i = 0; i < sorts.length; i++) {
248                var tmp = sorts[i].split(mse2Config['method_delimeter']);
249                if (tmp[0] && tmp[1]) {
250                    $(this.options.sort_link + '[data-sort="' + tmp[0] + '"]').data('dir', tmp[1]).attr('data-dir', tmp[1]).addClass(this.options.active_class);
251                }
252            }
253        }
254
255        $(document).on('click', this.options.sort_link, function () {
256            if ($(this).hasClass(mSearch2.options.active_class) && $(this).data('dir') == '') {
257                return false;
258            }
259            $(mSearch2.options.sort_link).removeClass(mSearch2.options.active_class);
260            $(this).addClass(mSearch2.options.active_class);
261            var dir;
262            if ($(this).data('dir') == '') {
263                dir = $(this).data('default');
264            }
265            else {
266                dir = $(this).data('dir') == 'desc'
267                    ? 'asc'
268                    : 'desc';
269            }
270            $(mSearch2.options.sort_link).data('dir', '').attr('data-dir', '');
271            $(this).data('dir', dir).attr('data-dir', dir);
272
273            var sort = $(this).data('sort');
274            if (dir) {
275                sort = sort.replace(
276                    new RegExp(mse2Config['method_delimeter'] + '.*?' + mse2Config['values_delimeter']),
277                    mse2Config['method_delimeter'] + dir + mse2Config['values_delimeter']
278                );
279                sort += mse2Config['method_delimeter'] + dir;
280            }
281            mse2Config['sort'] = (sort != mse2Config['start_sort']) ? sort : '';
282            var params = mSearch2.getFilters();
283            if (mse2Config['page'] > 1 && (mse2Config['mode'] == 'scroll' || mse2Config['mode'] == 'button')) {
284                mse2Config['page'] = '';
285                delete(params['page']);
286            }
287            mSearch2.Hash.set(params);
288            mSearch2.load(params);
289
290            return false;
291        });
292    },
293
294    handleTpl: function () {
295        $(document).on('click', this.options.tpl_link, function () {
296            if (!$(this).hasClass(mSearch2.options.active_class)) {
297                $(mSearch2.options.tpl_link).removeClass(mSearch2.options.active_class);
298                $(this).addClass(mSearch2.options.active_class);
299
300                var tpl = $(this).data('tpl');
301                mse2Config['tpl'] = (tpl != mse2Config['start_tpl'] && tpl != 0) ? tpl : '';
302
303                var params = mSearch2.getFilters();
304                if (mse2Config['page'] > 1 && (mse2Config['mode'] == 'scroll' || mse2Config['mode'] == 'button')) {
305                    mse2Config['page'] = '';
306                    delete(params['page']);
307                }
308                mSearch2.Hash.set(params);
309                mSearch2.load(params);
310            }
311
312            return false;
313        });
314    },
315
316    handleSlider: function () {
317        if (!$(mSearch2.options.slider).length) {
318            return false;
319        }
320        else if (!$.ui || !$.ui.slider) {
321            return mSearch2.loadJQUI(mSearch2.handleSlider);
322        }
323        $(mSearch2.options.slider).each(function () {
324            var $this = $(this);
325            var fieldset = $(this).parents('fieldset');
326            var imin = fieldset.find('input:first');
327            var imax = fieldset.find('input:last');
328            var vmin = Number(imin.attr('value'));
329            var vmax = Number(imax.attr('value'));
330            // Check for decimals
331            var ival = imin.val();
332            var decimal = ival.indexOf('.') != -1;
333            var decimals = decimal
334                ? Number(ival.substr(ival.indexOf('.') + 1).length)
335                : 0;
336            var delimiter = 1;
337            for (var i = 1; i <= decimals; i++) {
338                delimiter *= 10;
339            }
340
341            var name = imin.prop('name');
342            $this.slider({
343                min: vmin,
344                max: vmax,
345                values: [vmin, vmax],
346                range: true,
347                step: 1 / delimiter,
348                stop: function (e, ui) {
349                    imin.val(ui.values[0].toFixed(decimals));
350                    imax.val(ui.values[1].toFixed(decimals));
351                    imin.add(imax).trigger('change');
352                    mSearch2.sliders[name]['user_changed'] = true;
353                },
354                change: function (e, ui) {
355                    if (mSearch2.sliders[name] != undefined && mSearch2.sliders[name]['values'] != undefined) {
356                        mSearch2.sliders[name]['changed'] = mSearch2.sliders[name]['values'][0] != ui.values[0].toFixed(decimals) ||
357                            mSearch2.sliders[name]['values'][1] != ui.values[1].toFixed(decimals);
358                    }
359                },
360                slide: function (e, ui) {
361                    if (decimal) {
362                        imin.val(ui.values[0].toFixed(decimals));
363                        imax.val(ui.values[1].toFixed(decimals));
364                    } else {
365                        imin.val(ui.values[0]);
366                        imax.val(ui.values[1]);
367                    }
368                }
369            });
370
371            var changed = mSearch2.Hash.get()[name] !== undefined;
372            mSearch2.sliders[name] = {
373                changed: changed,
374                user_changed: changed
375            };
376
377            var values = mSearch2.Hash.get();
378            if (values[name]) {
379                var tmp = values[name].split(mse2Config['values_delimeter']);
380                if (tmp[0].match(/(?!^-)[^0-9\.]/g)) {
381                    tmp[0] = tmp[0].replace(/(?!^-)[^0-9\.]/g, '');
382                }
383                if (tmp.length > 1) {
384                    if (tmp[1].match(/(?!^-)[^0-9\.]/g)) {
385                        tmp[1] = tmp[1].replace(/(?!^-)[^0-9\.]/g, '');
386                    }
387                }
388                imin.val(tmp[0]);
389                imax.val(tmp.length > 1 ? tmp[1] : tmp[0]);
390            }
391
392            //imin.attr('readonly', true);
393            imin.attr('data-decimal', decimals);
394            imin.on('change keyup input click', function (e) {
395                if (this.value.match(/(?!^-)[^0-9\.]/g)) {
396                    this.value = this.value.replace(/(?!^-)[^0-9\.]/g, '');
397                }
398                if (e.type != 'keyup' && e.type != 'input') {
399                    if (this.value > vmax) {
400                        this.value = vmax;
401                    }
402                    else if (this.value < vmin) {
403                        this.value = vmin;
404                    }
405                }
406                if (e.type == 'change') {
407                    mSearch2.sliders[name]['user_changed'] = true;
408                }
409                $this.slider('values', 0, this.value);
410            });
411            //imax.attr('readonly', true);
412            imax.attr('data-decimal', decimals);
413            imax.on('change keyup input click', function (e) {
414                if (this.value.match(/(?!^-)[^0-9\.]/g)) {
415                    this.value = this.value.replace(/(?!^-)[^0-9\.]/g, '');
416                }
417                if (e.type != 'keyup' && e.type != 'input') {
418                    if (this.value > vmax) {
419                        this.value = vmax;
420                    }
421                    else if (this.value < vmin) {
422                        this.value = vmin;
423                    }
424                }
425                $this.slider('values', 1, this.value);
426            });
427
428            if (values[name]) {
429                imin.add(imax).trigger('click');
430            }
431
432            mSearch2.sliders[name]['values'] = [vmin, vmax];
433        });
434        return true;
435    },
436
437    handleLimit: function () {
438        $(document).on('change', this.options.limit, function () {
439            var limit = $(this).val();
440            mse2Config['page'] = '';
441            if (limit == mse2Config['start_limit']) {
442                mse2Config['limit'] = '';
443            }
444            else {
445                mse2Config['limit'] = limit;
446            }
447            var params = mSearch2.getFilters();
448            if (mse2Config['page'] > 1 && (mse2Config['mode'] == 'scroll' || mse2Config['mode'] == 'button')) {
449                mse2Config['page'] = '';
450                delete(params['page']);
451            }
452            mSearch2.Hash.set(params);
453            mSearch2.load(params);
454        });
455    },
456
457    handleSelected: function (input) {
458        if (!input[0]) {
459            return;
460        }
461        var id = input.prop('id');
462        var title = '';
463        var elem;
464
465        var filter = input.parents(this.options['filter_wrapper']);
466        var filter_title = '';
467        var tmp;
468        if (filter.length) {
469            tmp = filter.find(this.options['filter_title']);
470            if (tmp.length > 0) {
471                filter_title = tmp.text();
472            }
473        }
474        if (filter_title == '') {
475            //noinspection LoopStatementThatDoesntLoopJS
476            for (filter_title in this.selections) {
477                break;
478            }
479        }
480
481        switch (input[0].tagName) {
482            case 'INPUT':
483                var label = mSearch2.filters.find('label[for="' + input.prop('id') + '"]');
484                var match = label.html().match(/>(.*?)</);
485                if (match && match[1]) {
486                    title = match[1].replace(/(\s+$)/, '');
487                }
488                $('[data-id="' + id + '"]', this.selected).remove();
489                if (input.is(':checked')) {
490                    elem = this.options['selected_tpl']
491                        .replace('[[+id]]', id).replace('[[+title]]', title)
492                        .replace('_id_', id).replace('_title_', title);
493                }
494                break;
495
496            case 'SELECT':
497                var option = input.find('option:selected');
498                $('[data-id="' + id + '"]', this.selected).remove();
499                if (input.val() != '') {
500                    title = ' ' + option.text().replace(/(\(.*\)$)/, '');
501                    elem = this.options['selected_tpl']
502                        .replace('[[+id]]', id).replace('[[+title]]', title)
503                        .replace('_id_', id).replace('_title_', title);
504                }
505                break;
506        }
507
508        if (elem != undefined) {
509            if (this.selections[filter_title] == undefined || input[0].type == 'radio') {
510                this.selections[filter_title] = {};
511            }
512            this.selections[filter_title][id] = elem;
513        }
514        else if (this.selections[filter_title] != undefined && this.selections[filter_title][id] != undefined) {
515            delete this.selections[filter_title][id];
516        }
517
518        this.selected.html('');
519        var count = 0;
520        var selected = [];
521        for (var i in this.selections) {
522            if (!this.selections.hasOwnProperty(i) || !Object.keys(this.selections).length) {
523                continue;
524            }
525            if (Object.keys(this.selections[i]).length) {
526                tmp = [];
527                for (var i2 in this.selections[i]) {
528                    if (!this.selections[i].hasOwnProperty(i2)) {
529                        continue;
530                    }
531                    tmp.push(this.selections[i][i2]);
532                    count++;
533                }
534                title = this.options['selected_wrapper_tpl']
535                    .replace('[[+title]]', i)
536                    .replace('_title_', i);
537                selected.push(title + tmp.join(this.options['selected_values_delimeter']));
538            }
539        }
540
541        if (count) {
542            this.selected.append(selected.join(this.options['selected_filters_delimeter'])).show();
543        }
544        else {
545            this.selected.hide();
546        }
547    },
548
549    handleNumbers: function () {
550        var groups = {};
551        $('input[type="text"],input[type="number"]', mSearch2.filters).each(function() {
552            var $this = $(this);
553            var name = $this.attr('name');
554            if (groups[name] == undefined) {
555                groups[name] = [$this];
556            } else {
557                groups[name].push($this);
558            }
559        });
560
561        var data = this.Hash.get();
562        for (var name in groups) {
563            if (!groups.hasOwnProperty(name)) {
564                continue;
565            }
566            var group = groups[name];
567            if (group.length == 2) {
568                var $min = group[0];
569                var $max = group[1];
570                var vmin = $min.val();
571                var vmax = $max.val();
572                $min.attr('data-original-value', vmin);
573                $max.attr('data-original-value', vmax);
574                this.numbers[name] = {
575                    values: [vmin, vmax],
576                };
577                if (data[name] != undefined) {
578                    var values = data[name].split(mse2Config['values_delimeter']);
579                    if (values.length == 2) {
580                        $min.val(values[0]);
581                        $max.val(values[1]);
582                    }
583                }
584            }
585        }
586    },
587
588    load: function (params, callback, append) {
589        if (this.loading) {
590            return false;
591        } else {
592            this.loading = true;
593        }
594        if (Object.keys(params).length) {
595            this.btn_reset.removeClass('hidden');
596        } else {
597            this.btn_reset.addClass('hidden');
598        }
599        if (!params || !Object.keys(params).length) {
600            params = this.getFilters();
601        }
602        params.action = 'filter';
603        params.pageId = mse2Config['pageId'];
604
605        this.beforeLoad();
606        params.key = mse2Config['key'];
607        //noinspection JSUnresolvedFunction
608        $.post(mse2Config['actionUrl'], params, function (response) {
609            mSearch2.loading = false;
610            mSearch2.afterLoad();
611            if (response['success']) {
612                mSearch2.Message.success(response['message']);
613                mSearch2.pagination.html(response['data']['pagination']);
614                if (append) {
615                    mSearch2.results.append(response['data']['results']);
616                }
617                else {
618                    mSearch2.results.html(response['data']['results']);
619                }
620
621                if (mse2Config['mode'] == 'button') {
622                    if (response['data']['pages'] == response['data']['page']) {
623                        $(mSearch2.options['more']).hide();
624                    }
625                    else {
626                        $(mSearch2.options['more']).show();
627                    }
628                }
629                else if (mse2Config['mode'] == 'scroll') {
630                    mSearch2.reached = response['data']['pages'] == response['data']['page'];
631                }
632
633                mSearch2.setTotal(response['data']['total']);
634                if (callback && $.isFunction(callback)) {
635                    callback.call(this, response, params);
636                }
637                mSearch2.setSuggestions(response['data']['suggestions']);
638                mSearch2.setEmptyFieldsets();
639                if (response['data'].log) {
640                    $('.mFilterLog').html(response['data'].log);
641                }
642                mSearch2.updateTitle(response['data']);
643                $(document).trigger('mse2_load', response);
644            }
645            else {
646                mSearch2.Message.error(response['message']);
647            }
648        }, 'json');
649    },
650
651    getFilters: function () {
652        var params = {};
653        // Disabled friendly urls
654        var hash = this.Hash.get();
655        if (hash[mse2Config['idVar']] != undefined) {
656            params[mse2Config['idVar']] = hash[mse2Config['idVar']];
657        }
658        // Other params
659        if (mse2Config[mse2Config['queryVar']] != '') {
660            params[mse2Config['queryVar']] = mse2Config[mse2Config['queryVar']];
661        }
662        if (mse2Config[mse2Config['parentsVar']] != '') {
663            params[mse2Config['parentsVar']] = mse2Config[mse2Config['parentsVar']];
664        }
665        if (mse2Config['sort'] != '') {
666            params.sort = mse2Config['sort'];
667        }
668        if (mse2Config['tpl'] != '') {
669            params.tpl = mse2Config['tpl'];
670        }
671        if (mse2Config['page'] > 0) {
672            params.page = mse2Config['page'];
673        }
674        if (mse2Config['limit'] > 0) {
675            params.limit = mse2Config['limit'];
676        }
677        // Filters
678        $.map(this.filters.serializeArray(), function (n) {
679            if (n.value === '') {
680                return;
681            }
682            if (params[n.name]) {
683                params[n.name] += mse2Config['values_delimeter'] + n.value;
684            }
685            else {
686                params[n.name] = n.value;
687            }
688        });
689        var i;
690        for (i in this.sliders) {
691            if (this.sliders.hasOwnProperty(i) && params[i]) {
692                if (!this.sliders[i]['changed']) {
693                    delete params[i];
694                }
695            }
696        }
697        for (i in this.numbers) {
698            if (this.numbers.hasOwnProperty(i) && params[i]) {
699                if (this.numbers[i]['values'].join(mse2Config['values_delimeter']) == params[i]) {
700                    delete params[i];
701                }
702            }
703        }
704
705        return params;
706    },
707
708    setFilters: function (params) {
709        if (!params) {
710            params = {};
711        }
712        for (var i in this.elements) {
713            if (!this.elements.hasOwnProperty(i)) {
714                continue;
715            }
716            var elem = this.elements[i];
717            if (typeof(this[elem]) == 'undefined') {
718                continue;
719            }
720            var item, name, values, val, type;
721            switch (elem) {
722                case 'limit':
723                    if (params['limit'] == undefined) {
724                        this.limit.val(mse2Config['start_limit']);
725                        mse2Config['limit'] = '';
726                    }
727                    else {
728                        this.limit.val(params['limit']);
729                    }
730                    break;
731                case 'pagination':
732                    mse2Config['page'] = params['page'] == undefined
733                        ? ''
734                        : params['page'];
735                    break;
736                case 'sort':
737                    var sorts = {};
738                    values = params['sort'];
739                    if (values == undefined) {
740                        values = mse2Config['start_sort'];
741                        mse2Config['sort'] = '';
742                    }
743                    if (typeof(values) != 'object' && values != '') {
744                        values = values.split(mse2Config['values_delimeter']);
745                        for (i in values) {
746                            if (!values.hasOwnProperty(i)) {
747                                continue;
748                            }
749                            name = values[i].split(mse2Config['method_delimeter']);
750                            if (name[0] && name[1]) {
751                                sorts[name[0]] = name[1];
752                            }
753                        }
754                    }
755                    $(document).find(this.options['sort_link']).each(function () {
756                        item = $(this);
757                        name = item.data('sort');
758                        if (sorts[name]) {
759                            item.data('dir', sorts[name]).attr('data-dir', sorts[name]);
760                            item.addClass(mSearch2.options['active_class']);
761                        }
762                        else {
763                            item.data('dir', '').attr('data-dir', '');
764                            item.removeClass(mSearch2.options['active_class']);
765                        }
766                    });
767                    break;
768                case 'tpl':
769                    values = params['tpl'] != undefined
770                        ? params['tpl']
771                        : 0;
772                    $(document).find(this.options['tpl_link']).each(function () {
773                        item = $(this);
774                        if (item.data('tpl') == values) {
775                            item.addClass(mSearch2.options['active_class']);
776                            mse2Config['tpl'] = values;
777                        }
778                        else {
779                            item.removeClass(mSearch2.options['active_class']);
780                        }
781                    });
782                    break;
783                case 'filters':
784                    this['filters'].find('input').each(function () {
785                        item = $(this);
786                        name = item.prop('name');
787                        type = item.prop('type');
788                        values = params[name];
789                        if (values != undefined && typeof(values) != 'object') {
790                            values = values.split(mse2Config['values_delimeter']);
791                        }
792                        switch (type) {
793                            case 'checkbox':
794                            case 'radio':
795                                var checked = item.is(':checked');
796                                if (params[name] != undefined) {
797                                    item.prop('checked', values.indexOf(String(item.val())) != -1);
798                                }
799                                else {
800                                    item.prop('checked', false);
801                                }
802                                if (item.is(':checked') != checked) {
803                                    mSearch2.handleSelected(item);
804                                }
805                                break;
806                            default:
807                                if (mSearch2.sliders[name]) {
808                                    if (item.prop('id').match(/.*?_0$/)) {
809                                        val = (values != undefined && values[0] != undefined)
810                                            ? values[0]
811                                            : mSearch2.sliders[name]['values'][0];
812                                    }
813                                    else {
814                                        val = (values != undefined && values[1] != undefined)
815                                            ? values[1]
816                                            : mSearch2.sliders[name]['values'][1];
817                                    }
818                                    if (val != item.val()) {
819                                        item.val(val).trigger('click');
820                                    }
821                                } else {
822                                    var original = item.data('original-value');
823                                    if (original != undefined) {
824                                        item.val(original);
825                                    }
826                                }
827                        }
828                    });
829                    this['filters'].find('select').each(function () {
830                        item = $(this);
831                        name = item.prop('name');
832                        type = item.prop('type');
833                        values = params[name];
834                        if (values != undefined) {
835                            if (typeof(values) != 'object') {
836                                values = values.split(mse2Config['values_delimeter']);
837                            }
838                            item.find('option').each(function () {
839                                var option = $(this);
840                                val = option.prop('value');
841                                var selected = option.is(':selected');
842                                $(this).prop('selected', values.indexOf(String(val)) != -1);
843                                if (option.is(':selected') != selected) {
844                                    mSearch2.handleSelected(item);
845                                }
846                            });
847                        }
848                        else {
849                            item.val('');
850                        }
851                        /*
852                         if (params[name] != undefined) {
853                         item.prop('checked', values.indexOf(String(item.val())) != -1);
854                         }
855                         else {
856                         item.prop('checked', false);
857                         }
858                         */
859                    });
860                    break;
861            }
862        }
863    },
864
865    setSuggestions: function (suggestions) {
866        var aliases = mse2Config['aliases'] || {};
867        var remove = [];
868        var alias, value;
869        for (var filter in suggestions) {
870            if (!suggestions.hasOwnProperty(filter)) {
871                continue;
872            }
873            var is_slider = typeof(this.sliders[filter]) != 'undefined';
874            var is_number = typeof(this.numbers[filter]) != 'undefined';
875            var arr = suggestions[filter];
876            alias = filter;
877            if (typeof(aliases[filter]) != 'undefined') {
878                filter = aliases[filter];
879            }
880            var count, selector, input;
881            if (is_slider && !this.sliders[alias]['user_changed']) {
882                var vmin = null;
883                var vmax = null;
884                for (value in arr) {
885                    if (!arr.hasOwnProperty(value)) {
886                        continue;
887                    }
888                    count = arr[value];
889                    if (typeof(count) != 'number') {
890                        continue;
891                    }
892                    if (count > 0 && (vmin === null || vmin > value)) {
893                        vmin = Number(value);
894                    }
895                    if (count > 0 && vmax < value) {
896                        vmax = Number(value);
897                    }
898                }
899                if (vmin == null && vmax == null) {
900                    remove.push(alias);
901                }
902                selector = filter.replace(mse2Config['filter_delimeter'], "\\" + mse2Config['filter_delimeter']);
903                var imin = $('#' + mSearch2.options.prefix + selector + '_0', mSearch2.filters);
904                if (imin.length) {
905                    if (vmin == null) {
906                        vmin = Number(imin.data('original-value'));
907                    }
908                    imin.val(vmin.toFixed(imin.data('decimals'))).trigger('click');
909                }
910                var imax = $('#' + mSearch2.options.prefix + selector + '_1', mSearch2.filters);
911                if (imax.length) {
912                    if (vmax == null) {
913                        vmax = Number(imax.data('original-value'));
914                    }
915                    imax.val(vmax.toFixed(imax.data('decimals'))).trigger('click');
916                }
917                this.sliders[alias]['values'] = [vmin, vmax];
918                this.sliders[alias]['changed'] = false;
919            }
920            else if (is_number) {
921                // Do nothing
922            }
923            else {
924                for (value in arr) {
925                    if (!arr.hasOwnProperty(value)) {
926                        continue;
927                    }
928                    count = arr[value];
929                    selector = filter.replace(mse2Config['filter_delimeter'], "\\" + mse2Config['filter_delimeter']);
930                    input = $('#' + mSearch2.options.prefix + selector, mSearch2.filters).find('[value="' + value.replace(/&quot;/g, '\\"') + '"]');
931                    if (!input[0]) {
932                        continue;
933                    }
934
935                    switch (input[0].tagName) {
936                        case 'INPUT':
937                            var proptype = input.prop('type');
938                            if (proptype != 'checkbox' && proptype != 'radio') {
939                                continue;
940                            }
941                            var label = $('#' + mSearch2.options.prefix + selector, mSearch2.filters).find('label[for="' + input.prop('id') + '"]');
942                            var elem = input.parent().find(mSearch2.options.suggestion);
943                            elem.text(count);
944
945                            if (count == 0) {
946                                if (input.is(':not(:checked)')) {
947                                    input.prop('disabled', true);
948                                    label.addClass(mSearch2.options.disabled_class);
949                                    mSearch2.handleSelected(input);
950                                }
951                            }
952                            else {
953                                input.prop('disabled', false);
954                                label.removeClass(mSearch2.options.disabled_class);
955                            }
956
957                            if (input.is(':checked')) {
958                                elem.hide();
959                            }
960                            else {
961                                elem.show();
962                            }
963                            break;
964
965                        case 'OPTION':
966                            var text = input.text();
967                            var matches = text.match(/\([^\)]+\)$/);
968                            var src = matches
969                                ? matches[0]
970                                : '';
971                            var dst = '';
972
973                            if (!count) {
974                                input.prop('disabled', true).addClass(mSearch2.options.disabled_class);
975                                /*
976                                 if (input.is(':selected')) {
977                                 input.prop('selected', false);
978                                 mSearch2.handleSelected(input);
979                                 }
980                                 */
981                            }
982                            else {
983                                dst = ' (' + count + ')';
984                                input.prop('disabled', false).removeClass(mSearch2.options.disabled_class);
985                            }
986
987                            if (input.is(':selected')) {
988                                dst = '';
989                            }
990
991                            if (src) {
992                                text = text.replace(src, dst);
993                            }
994                            else {
995                                text += dst;
996                            }
997                            input.text(text);
998
999                            mSearch2.handleSelected(input.parent());
1000                            break;
1001                    }
1002                }
1003            }
1004        }
1005    },
1006
1007    setEmptyFieldsets: function () {
1008        this.filters.find('fieldset').each(function () {
1009            var all_children_disabled = $(this).find('label:not(.' + mSearch2.options.disabled_class + ')').length == 0;
1010            if (all_children_disabled) {
1011                $(this).addClass(mSearch2.options.disabled_class_fieldsets);
1012            }
1013            if (!all_children_disabled && $(this).hasClass(mSearch2.options.disabled_class_fieldsets)) {
1014                $(this).removeClass(mSearch2.options.disabled_class_fieldsets);
1015            }
1016        });
1017    },
1018
1019    setTotal: function (total) {
1020        if (this.total.length != 0) {
1021            console.log(total)
1022            if (!total || total == 0) {
1023                this.total.parent().hide();
1024                this.limit.parent().hide();
1025                this.sort.hide();
1026                this.total.text(0);
1027            }
1028            else {
1029                this.total.parent().show();
1030                this.limit.parent().show();
1031                this.sort.show();
1032                this.total.text(total);
1033            }
1034        }
1035    },
1036
1037    beforeLoad: function () {
1038        $(this.options['wrapper']).addClass(this.options['loading_class']);
1039        this.results.css('opacity', .5);
1040        $(this.options.pagination_link).addClass(this.options.active_class);
1041        this.filters.find('input, select').prop('readonly', true).addClass(this.options.disabled_class);
1042    },
1043
1044    afterLoad: function () {
1045        $(this.options['wrapper']).removeClass(this.options['loading_class']);
1046        this.results.css('opacity', 1);
1047        this.filters.find('.' + this.options.disabled_class).prop('readonly', false).removeClass(this.options.disabled_class);
1048    },
1049
1050    loadJQUI: function (callback, parameters) {
1051        $('<link/>', {
1052            rel: 'stylesheet',
1053            type: 'text/css',
1054            href: mse2Config['cssUrl'] + 'jquery-ui/jquery-ui.min.css'
1055        }).appendTo('head');
1056
1057        return $.getScript(mse2Config['jsUrl'] + 'lib/jquery-ui-touch.min.js', function () {
1058            if (typeof callback == 'function') {
1059                callback(parameters);
1060            }
1061        });
1062    },
1063
1064    submit: function (params) {
1065        if (this.loading) {
1066            return false;
1067        }
1068        else if (!params || !Object.keys(params).length) {
1069            params = this.getFilters();
1070        }
1071        else {
1072            delete(params['action']);
1073            delete(params['key']);
1074            delete(params['pageId']);
1075        }
1076        delete(params['page']);
1077
1078        var action = $(this.options.filters).attr('action');
1079        if (!mSearch2.options.autoLoad) {
1080            var vars = '';
1081            for (var i in params) {
1082                if (params.hasOwnProperty(i)) {
1083                    vars += '&' + i + '=' + params[i];
1084                }
1085            }
1086            if (!action.match(/\?/)) {
1087                document.location = action + vars.replace(/^&/, '?');
1088            }
1089            else {
1090                document.location = action + vars;
1091            }
1092            return false;
1093        }
1094        else {
1095            mse2Config['page'] = '';
1096            mSearch2.Hash.set(params);
1097            mSearch2.load(params);
1098            return false;
1099        }
1100    },
1101
1102    reset: function () {
1103        if (this.loading) {
1104            return false;
1105        }
1106        this.Hash.clear();
1107        this.setFilters();
1108        for (var value in this.sliders) {
1109            if (this.sliders.hasOwnProperty(value)) {
1110                this.sliders[value]['changed'] =
1111                this.sliders[value]['user_changed'] = false;
1112            }
1113        }
1114
1115        return this.submit();
1116    },
1117
1118    addPage: function () {
1119        var pcre = new RegExp(mse2Config['pageVar'] + '[=|\/](\\d+)');
1120        var current = mse2Config['page'] || 1;
1121        $(this.options['pagination_link']).each(function () {
1122            var href = $(this).prop('href');
1123            var match = href.match(pcre);
1124            var page = !match ? 1 : Number(match[1]);
1125            if (page > current) {
1126                mse2Config['page'] = (page != mse2Config['start_page']) ? page : '';
1127                var tmp = mSearch2.getFilters();
1128                delete(tmp['page']);
1129                mSearch2.Hash.set(tmp);
1130
1131                var params = mSearch2.getFilters();
1132                mSearch2.load(params, null, true);
1133                return false;
1134            }
1135        });
1136    },
1137
1138    updateTitle: function (response) {
1139        if (typeof(pdoTitle) == 'undefined') {
1140            return;
1141        }
1142        var $title = $('title');
1143        var separator = pdoTitle['separator'] || ' / ';
1144        var tpl = pdoTitle['tpl'];
1145
1146        var title = [];
1147        var items = $title.text().split(separator);
1148        var pcre = new RegExp('^' + tpl.split(' ')[0] + ' ');
1149        for (var i = 0; i < items.length; i++) {
1150            if (i === 1 && response['page'] && response['page'] > 1) {
1151                title.push(tpl.replace('{page}', response['page']).replace('{pageCount}', response['pages']));
1152            }
1153            if (!items[i].match(pcre)) {
1154                title.push(items[i]);
1155            }
1156        }
1157        $title.text(title.join(separator));
1158    },
1159
1160};
1161
1162mSearch2.Form = {
1163    initialized: false,
1164    initialize: function (selector) {
1165        if (this.initialized || typeof(mse2FormConfig) == 'undefined') {
1166            return false;
1167        }
1168        $(selector).each(function () {
1169            var form = $(this);
1170            var config = mse2FormConfig[form.data('key')];
1171            var cache = {};
1172
1173            if (config.autocomplete == '0' || config.autocomplete == 'false') {
1174                return false;
1175            }
1176            else if (!$.ui || !$.ui.autocomplete) {
1177                return mSearch2.loadJQUI(mSearch2.Form.initialize, selector);
1178            }
1179
1180            form.find('input[name="' + config['queryVar'] + '"]').autocomplete({
1181                source: function (request, callback) {
1182                    if (request.term in cache) {
1183                        callback(cache[request.term]);
1184                        return;
1185                    }
1186                    var data = {
1187                        action: 'search',
1188                        key: form.data('key'),
1189                        pageId: config.pageId
1190                    };
1191                    data[config['queryVar']] = request.term;
1192                    //noinspection JSUnresolvedFunction
1193                    $.post(mse2Config['actionUrl'], data, function (response) {
1194                        if (response['data']['log']) {
1195                            $('.mSearchFormLog').html(response['data']['log']);
1196                        }
1197                        else {
1198                            $('.mSearchFormLog').html('');
1199                        }
1200                        cache[request.term] = response['data']['results'];
1201                        callback(response['data']['results'])
1202                    }, 'json');
1203                },
1204                minLength: config['minQuery'] || 3,
1205                select: function (event, ui) {
1206                    if (ui.item.url) {
1207                        document.location.href = ui.item.url;
1208                    }
1209                    else {
1210                        setTimeout(function () {
1211                            form.submit();
1212                        }, 100);
1213                    }
1214                }
1215            }).data("ui-autocomplete")._renderItem =
1216                function (ul, item) {
1217                    return $('<li>')
1218                        .data("item.autocomplete", item)
1219                        .addClass("mse2-ac-wrapper")
1220                        .append($("<div>").addClass('mse2-ac-link').html(item.label))
1221                        //.append("<a class=\"mse2-ac-link\">" + item.label + "</a>")
1222                        .appendTo(ul);
1223                };
1224
1225            //noinspection JSPotentiallyInvalidConstructorUsage,JSUnresolvedVariable
1226            jQuery.ui.autocomplete.prototype._resizeMenu = function () {
1227                var ul = this.menu.element;
1228                ul.outerWidth(this.element.outerWidth());
1229            };
1230
1231            return true;
1232        });
1233        this.initialized = true;
1234    }
1235};
1236
1237mSearch2.Message = {
1238    success: function (message) {
1239    },
1240    error: function (message) {
1241        alert(message);
1242    }
1243};
1244
1245mSearch2.Hash = {
1246    get: function () {
1247        var vars = {}, hash, splitter, hashes;
1248        if (!this.oldbrowser()) {
1249            var pos = window.location.href.indexOf('?');
1250            hashes = (pos != -1) ? decodeURIComponent(window.location.href.substr(pos + 1)) : '';
1251            splitter = '&';
1252        }
1253        else {
1254            hashes = decodeURIComponent(window.location.hash.substr(1));
1255            splitter = '/';
1256        }
1257
1258        if (hashes.length == 0) {
1259            return vars;
1260        }
1261        else {
1262            hashes = hashes.split(splitter);
1263        }
1264
1265        for (var i in hashes) {
1266            if (hashes.hasOwnProperty(i)) {
1267                hash = hashes[i].split('=');
1268                if (typeof hash[1] == 'undefined') {
1269                    vars['anchor'] = hash[0];
1270                }
1271                else {
1272                    vars[hash[0]] = hash[1];
1273                }
1274            }
1275        }
1276        return vars;
1277    },
1278    set: function (vars) {
1279        var hash = '';
1280        var i;
1281        for (i in vars) {
1282            if (vars.hasOwnProperty(i)) {
1283                hash += '&' + i + '=' + vars[i];
1284            }
1285        }
1286        if (!this.oldbrowser()) {
1287            if (hash.length != 0) {
1288                hash = '?' + hash.substr(1);
1289                var specialChars = {"%": "%25", "+": "%2B"};
1290                for (i in specialChars) {
1291                    if (specialChars.hasOwnProperty(i) && hash.indexOf(i) !== -1) {
1292                        hash = hash.replace(new RegExp('\\' + i, 'g'), specialChars[i]);
1293                    }
1294                }
1295            }
1296            window.history.pushState({mSearch2: document.location.pathname + hash}, '', document.location.pathname + hash);
1297        }
1298        else {
1299            window.location.hash = hash.substr(1);
1300        }
1301    },
1302    add: function (key, val) {
1303        var hash = this.get();
1304        hash[key] = val;
1305        this.set(hash);
1306    },
1307    remove: function (key) {
1308        var hash = this.get();
1309        delete hash[key];
1310        this.set(hash);
1311    },
1312    clear: function () {
1313        this.set({});
1314    },
1315    oldbrowser: function () {
1316        return !(window.history && history.pushState);
1317    }
1318};
1319
1320mSearch2.startParams = mSearch2.Hash.get();

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.