PageSourceSearch

https://adm44.ru/local/templates/oiv-kostroma-template/scripts/sel…query.multiselect.filter.js?155968416810179

js adm44.ru collected 2026-10-02 07:31:10 UTC 10,179 bytes, 284 lines download raw bytes

1/* jshint forin:true, noarg:true, noempty:true, eqeqeq:true, boss:true, undef:true, curly:true, browser:true, jquery:true */
2/*
3 * jQuery MultiSelect UI Widget Filtering Plugin 3.0.0
4 * Copyright (c) 2012 Eric Hynds
5 *
6 * http://www.erichynds.com/jquery/jquery-ui-multiselect-widget/
7 *
8 * Depends:
9 *   - jQuery UI MultiSelect widget
10 *
11 * Dual licensed under the MIT and GPL licenses:
12 *   http://www.opensource.org/licenses/mit-license.php
13 *   http://www.gnu.org/licenses/gpl.html
14 *
15 */
16(function($) {
17  var rEscape = /[\-\[\]{}()*+?.,\\\^$|#\s]/g;
18
19  // "{{term}}" is a placeholder below for where the search term
20  // would be inserted in the resulting regular expression.
21  var filterRules = {
22      contains: '{{term}}',
23      beginsWith:  '^{{term}}',
24      endsWith:  '{{term}}$',
25      exactMatch:  '^{{term}}$',
26      containsNumber:  '\d',
27      isNumeric:  '^\d+$',
28      isNonNumeric:  '^\D+$'
29  };
30
31  var headerSelector = '.ui-multiselect-header';
32  var hasFilterClass = 'ui-multiselect-hasfilter';
33  var filterClass = 'ui-multiselect-filter';
34  var optgroupClass = 'ui-multiselect-optgroup';
35  var groupLabelClass = 'ui-multiselect-grouplabel';
36  var hiddenClass = 'ui-multiselect-excluded';
37
38  //Courtesy of underscore.js
39  function debounce(func, wait, immediate) {
40    var timeout;
41    return function() {
42      var context = this, args = arguments;
43      var later = function() {
44        timeout = null;
45        if (!immediate) {
46          func.apply(context, args);
47        }
48      };
49      var callNow = immediate && !timeout;
50      clearTimeout(timeout);
51      timeout = setTimeout(later, wait);
52      if (callNow) {
53        func.apply(context, args);
54      }
55    };
56  }
57
58  $.widget('ech.multiselectfilter', {
59
60    options: {
61      label: 'Filter:',                // (string) The label to show with the input
62      placeholder: 'Enter keywords',   // (string) The placeholder text to show in the input
63      filterRule: 'contains',          // (string) Either a named filter rule from above or a regular expression containing {{term}} as a placeholder
64      searchGroups: false,             // (true | false) If true, search option group labels and show an entire group on a match.
65      autoReset: false,                // (true | false) If true, clear the filter each time the widget menu is closed.
66      width: null,                     // (number) Override default width set in css file (px). null will inherit
67      debounceMS: 250                  // (number) Number of milleseconds to wait between running the search handler.
68    },
69
70   /**
71    * Performs widget creation
72    * Widget API has already set this.element and this.options for us
73    *   - Find the multiselect widget.
74    *   - Create the filter input
75    *   - Set up event handlers
76    *   - Insert in header
77    * - Create text cache
78    *   - Override toggleState
79    */
80    _create: function() {
81      var opts = this.options;
82      var $element = this.element;
83
84      // get the multiselect instance
85      this.instance = $element.data('ech-multiselect');
86
87      // store header; add filter class so the close/check all/uncheck all links can be positioned correctly
88      this.$header = this.instance.$menu.find(headerSelector).addClass(hasFilterClass);
89
90      // wrapper $element
91      this.$input = $(document.createElement('input'))
92        .attr({
93          placeholder: opts.placeholder,
94          type: "search"
95        })
96        .css({  width: (typeof opts.width === 'string')
97                       ? this.instance._parse2px(opts.width, this.$header).px + 'px'
98                       : (/\d/.test(opts.width) ? opts.width + 'px' : null)
99             });
100      this._bindInputEvents();
101      // automatically reset the widget on close?
102      if (this.options.autoReset) {
103        $element.on('multiselectbeforeclose', $.proxy(this._reset, this));
104      }        
105
106      var $label = $(document.createElement('label')).text(opts.label).append(this.$input).addClass('ui-multiselect-filter-label');
107      this.$wrapper = $(document.createElement('div'))
108                                .addClass(filterClass)
109                                .append($label)
110                                .prependTo(this.$header);
111
112      // If menu already opened, have to reset menu height since
113      // addition of the filter input changes the header height calc.
114      if (!!this.instance._isOpen) {
115         this.instance._setMenuHeight(true);
116      }
117
118      // cache input values for searching
119      this.updateCache();
120
121      // Change the normal _toggleChecked fxn behavior so that when checkAll/uncheckAll
122      // is fired, only the currently displayed filtered inputs are checked if filter entered.
123      var instance = this.instance;
124      var filter = this.$input[0];
125      instance._oldToggleChecked = instance._toggleChecked;
126      instance._toggleChecked = function(flag, group) {
127         instance._oldToggleChecked(flag, group, !!filter.value);
128      };
129    },
130
131    /**
132     * Binds keyboard events to the input
133     * This is where special behavior like ALT-R for reset is bound
134     */
135    _bindInputEvents: function() {
136      this.$input.on({
137        keydown: function(e) {
138          // prevent the enter key from submitting the form / closing the widget
139          if(e.which === 13)
140            e.preventDefault();
141          else if(e.which === 27) {
142            $element.multiselect('close');
143            e.preventDefault();
144          }
145          else if(e.which === 9 && e.shiftKey) {
146            $element.multiselect('close');
147            e.preventDefault();
148          }
149          else if(e.altKey) {
150            switch(e.which) {
151              case 82:
152                e.preventDefault();
153                $(this).val('').trigger('input', '');
154                break;
155              case 65:
156                $element.multiselect('checkAll');
157                break;
158              case 85:
159                $element.multiselect('uncheckAll');
160                break;
161              case 70:
162                $element.multiselect('flipAll');
163                break;
164              case 76:
165                $element.multiselect('instance').$labels.first().trigger("mouseenter");
166                break;
167            }
168          }
169        },
170        input: $.proxy(debounce(this._handler, this.options.debounceMS), this),
171        search: $.proxy(this._handler, this)
172      });
173    },
174
175   /**
176    * Handles searches as text is entered in the filter box.
177    * Uses a text cache to speed up searching.
178    * Debouncing is done to limit how often this is ran.
179    * Alternate filter rules can be used.
180    * Option group labels may be searched, also.
181    * @param (object) event object from original event.
182    */
183    _handler: function(e) {
184      var term = this.$input[0].value.toLowerCase().replace(/^\s+|\s+$/g,'');
185      var filterRule = this.options.filterRule || 'contains';
186      var regex = new RegExp( ( filterRules[filterRule] || filterRule ).replace('{{term}}', term.replace(rEscape, "\\$&")), 'i');
187      var searchGroups = !!this.options.searchGroups;
188      var $checkboxes = this.instance.$checkboxes;
189      var cache = this.cache;   // Cached text() object
190
191      this.$rows.toggleClass(hiddenClass, !!term);
192      var filteredInputs = $checkboxes.children().map(function(x) {
193        var elem = this;
194        var $groupItems = $(elem);
195        var groupShown = false;
196
197         // Account for optgroups
198         // If we are searching in option group labels and we match an optgroup label,
199         // then show all its children and return all its inputs also.
200        if (elem.classList.contains(optgroupClass)) {
201          var $groupItems = $groupItems.find('li');
202          if (searchGroups && regex.test( cache[x] ) ) {
203             elem.classList.remove(hiddenClass);
204             $groupItems.removeClass(hiddenClass);
205             return $groupItems.find('input').get();
206          }
207        }
208
209        return $groupItems.map(function(y) {
210          if ( regex.test( cache[x + '.' + y] ) ) {
211            // Show the opt group heading if needed
212            if (!groupShown) {
213               elem.classList.remove(hiddenClass);
214               groupShown = true;
215            }
216            this.classList.remove(hiddenClass);
217            return this.getElementsByTagName('input')[0];
218          }
219          return null;
220        });
221
222      });
223      if (term) {
224         this._trigger('filter', e, filteredInputs);
225      }
226      if (!this.instance.options.listbox && this.instance._isOpen) {
227         this.instance._setMenuHeight(true);
228         this.instance.position();
229      }
230      return;
231    },
232
233    _reset: function () {
234      this.$input.val('')
235      var event = document.createEvent('Event');
236      event.initEvent('reset', true, true);
237      this.$input.get(0).dispatchEvent(event)
238      this._handler(event)
239    },
240
241   /**
242    * Creates a text cache object from the widget options' text.
243    * @param (boolean) alsoRefresh causes the displayed search results to refresh.
244    */
245    updateCache: function(alsoRefresh) {
246      var cache = {};  // keys are like 0, 0.1, 1, 1.0, 1.1 etc.
247      this.instance.$checkboxes.children().each(function(x) {
248         var $element = $(this);
249         // Account for optgroups
250         if (this.classList.contains(optgroupClass)) {
251            // Single number keys are the option labels
252            cache[x] = this.getElementsByClassName(groupLabelClass)[0].textContent;
253            $element = $element.find('li');
254         }
255         $element.each(function(y) {
256            cache[x + '.' + y] = this.textContent;
257         });
258      });
259      this.cache = cache;
260      this.$rows = this.instance.$checkboxes.find('li');
261      if (!!alsoRefresh) {
262         this._handler();
263      }
264    },
265
266   /**
267    * Returns the input wrapper div
268    */
269    widget: function() {
270      return this.$wrapper;
271    },
272
273   /**
274    * Destroys this widget
275    */
276    destroy: function() {
277      $.Widget.prototype.destroy.call(this);
278      this.$input.val('').trigger("keyup").off('keydown input search');
279      this.instance.$menu.find(headerSelector).removeClass(hasFilterClass);
280      this.$wrapper.remove();
281    }
282  });
283
284})(jQuery);

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.