PageSourceSearch

https://tdpanteon.ru/assets/components/msearch2/js/web/default.js

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