游畅
2022-04-08 b8e5fb6c5b2a5334e471f97018d6f67367e31815
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/* jshint forin:true, noarg:true, noempty:true, eqeqeq:true, boss:true, undef:true, curly:true, browser:true, jquery:true */
/*
 * jQuery MultiSelect UI Widget Filtering Plugin 1.5pre
 * Copyright (c) 2012 Eric Hynds
 *
 * http://www.erichynds.com/jquery/jquery-ui-multiselect-widget/
 *
 * Depends:
 *   - jQuery UI MultiSelect widget
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 */
(function($) {
  var rEscape = /[\-\[\]{}()*+?.,\\\^$|#\s]/g;
 
  $.widget('ech.multiselectfilter', {
 
    options: {
      label: 'Filter:',
      width: null, /* override default width set in css file (px). null will inherit */
      placeholder: 'Enter keywords',
      autoReset: false
    },
 
    _create: function() {
      var opts = this.options;
      var elem = $(this.element);
 
      // get the multiselect instance
      var instance = (this.instance = (elem.data('echMultiselect') || elem.data("multiselect")));
 
      // store header; add filter class so the close/check all/uncheck all links can be positioned correctly
      var header = (this.header = instance.menu.find('.ui-multiselect-header').addClass('ui-multiselect-hasfilter'));
 
      // wrapper elem
      var wrapper = (this.wrapper = $('<div class="ui-multiselect-filter">' + (opts.label.length ? opts.label : '') + '<input placeholder="'+opts.placeholder+'" type="search"' + (/\d/.test(opts.width) ? 'style="width:'+opts.width+'px"' : '') + ' /></div>').prependTo(this.header));
 
      // reference to the actual inputs
      this.inputs = instance.menu.find('input[type="checkbox"], input[type="radio"]');
 
      // build the input box
      this.input = wrapper.find('input').bind({
        keydown: function(e) {
          // prevent the enter key from submitting the form / closing the widget
          if(e.which === 13) {
            e.preventDefault();
          }
        },
        keyup: $.proxy(this._handler, this),
        click: $.proxy(this._handler, this)
      });
 
      // cache input values for searching
      this.updateCache();
 
      // rewrite internal _toggleChecked fn so that when checkAll/uncheckAll is fired,
      // only the currently filtered elements are checked
      instance._toggleChecked = function(flag, group) {
        var $inputs = (group && group.length) ?  group : this.labels.find('input');
        var _self = this;
 
        // do not include hidden elems if the menu isn't open.
        var selector = instance._isOpen ?  ':disabled, :hidden' : ':disabled';
 
        $inputs = $inputs
          .not(selector)
          .each(this._toggleState('checked', flag));
 
        // update text
        this.update();
 
        // gather an array of the values that actually changed
        var values = $inputs.map(function() {
          return this.value;
        }).get();
 
        // select option tags
        this.element.find('option').filter(function() {
          if(!this.disabled && $.inArray(this.value, values) > -1) {
            _self._toggleState('selected', flag).call(this);
          }
        });
 
        // trigger the change event on the select
        if($inputs.length) {
          this.element.trigger('change');
        }
      };
 
      // rebuild cache when multiselect is updated
      var doc = $(document).bind('multiselectrefresh', $.proxy(function() {
        this.updateCache();
        this._handler();
      }, this));
 
      // automatically reset the widget on close?
      if(this.options.autoReset) {
        doc.bind('multiselectclose', $.proxy(this._reset, this));
      }
    },
 
    // thx for the logic here ben alman
    _handler: function(e) {
      var term = $.trim(this.input[0].value.toLowerCase()),
 
      // speed up lookups
      rows = this.rows, inputs = this.inputs, cache = this.cache;
 
      if(!term) {
        rows.show();
      } else {
        rows.hide();
 
        var regex = new RegExp(term.replace(rEscape, "\\$&"), 'gi');
 
        this._trigger("filter", e, $.map(cache, function(v, i) {
          if(v.search(regex) !== -1) {
            rows.eq(i).show();
            return inputs.get(i);
          }
 
          return null;
        }));
      }
 
      // show/hide optgroups
      this.instance.menu.find(".ui-multiselect-optgroup-label").each(function() {
        var $this = $(this);
        var isVisible = $this.nextUntil('.ui-multiselect-optgroup-label').filter(function() {
          return $.css(this, "display") !== 'none';
        }).length;
 
        $this[isVisible ? 'show' : 'hide']();
      });
    },
 
    _reset: function() {
      this.input.val('').trigger('keyup');
    },
 
    updateCache: function() {
      // each list item
      this.rows = this.instance.menu.find(".ui-multiselect-checkboxes li:not(.ui-multiselect-optgroup-label)");
 
      // cache
      this.cache = this.element.children().map(function() {
        var elem = $(this);
 
        // account for optgroups
        if(this.tagName.toLowerCase() === "optgroup") {
          elem = elem.children();
        }
 
        return elem.map(function() {
          return this.innerHTML.toLowerCase();
        }).get();
      }).get();
    },
 
    widget: function() {
      return this.wrapper;
    },
 
    destroy: function() {
      $.Widget.prototype.destroy.call(this);
      this.input.val('').trigger("keyup");
      this.wrapper.remove();
    }
  });
 
})(jQuery);