Skip to content

Commit f63bc70

Browse files
SteveTheTechiemlh758
authored andcommitted
Filter Code Refactor & Fix Scroll on Focus Issues (#761)
* Minor Code Refactor 1. Make filterRules a local variable. 2. Remove the unneeded multiselect() call to get the instance. 3. Save class names in variables that can be obfuscated away. 4. Decrease unneeded jQuery function calls. * Fix scroll on focus issues Fixes #195 Fixes #551 This fixes undesired scrolling issues caused by focusing an element that is only partially visible.
1 parent 5d42519 commit f63bc70

File tree

2 files changed

+46
-26
lines changed

2 files changed

+46
-26
lines changed

src/jquery.multiselect.filter.js

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,23 @@
1818

1919
// "{{term}}" is a placeholder below for where the search term
2020
// would be inserted in the resulting regular expression.
21-
filterRules = {
22-
'contains': '{{term}}',
23-
'beginsWith': '^{{term}}',
24-
'endsWith': '{{term}}$',
25-
'exactMatch': '^{{term}}$',
26-
'containsNumber': '\d',
27-
'isNumeric': '^\d+$',
28-
'isNonNumeric': '^\D+$'
21+
var filterRules = {
22+
contains: '{{term}}',
23+
beginsWith: '^{{term}}',
24+
endsWith: '{{term}}$',
25+
exactMatch: '^{{term}}$',
26+
containsNumber: '\d',
27+
isNumeric: '^\d+$',
28+
isNonNumeric: '^\D+$'
2929
};
3030

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+
3138
//Courtesy of underscore.js
3239
function debounce(func, wait, immediate) {
3340
var timeout;
@@ -75,10 +82,10 @@
7582
var $element = this.element;
7683

7784
// get the multiselect instance -- instance() method no longer supported -- use data()
78-
this.instance = $element.multiselect().data('ech-multiselect');
85+
this.instance = $element.data('ech-multiselect');
7986

8087
// store header; add filter class so the close/check all/uncheck all links can be positioned correctly
81-
this.$header = this.instance.$menu.find('.ui-multiselect-header').addClass('ui-multiselect-hasfilter');
88+
this.$header = this.instance.$menu.find(headerSelector).addClass(hasFilterClass);
8289

8390
// wrapper $element
8491
this.$input = $(document.createElement('input'))
@@ -131,7 +138,7 @@
131138

132139
var $label = $(document.createElement('label')).text(opts.label).append(this.$input);
133140
this.$wrapper = $(document.createElement('div'))
134-
.addClass(' ui-multiselect-filter')
141+
.addClass(filterClass)
135142
.append($label)
136143
.prependTo(this.$header);
137144

@@ -170,36 +177,33 @@
170177
var searchGroups = !!this.options.searchGroups;
171178
var $checkboxes = this.instance.$checkboxes;
172179
var cache = this.cache; // Cached text() object
173-
var optgroupClass = "ui-multiselect-optgroup";
174-
var hiddenClass = 'ui-multiselect-excluded';
175180

176181
this.$rows.toggleClass(hiddenClass, !!term);
177182
var filteredInputs = $checkboxes.children().map(function(x) {
178-
var $this = $(this);
179-
var $groupItems = $this;
183+
var elem = this;
184+
var $groupItems = $(elem);
180185
var groupShown = false;
181186

182187
// Account for optgroups
183188
// If we are searching in option group labels and we match an optgroup label,
184189
// then show all its children and return all its inputs also.
185-
if ($this.hasClass(optgroupClass)) {
186-
var $groupItems = $this.find('li');
190+
if (elem.classList.contains(optgroupClass)) {
191+
var $groupItems = $groupItems.find('li');
187192
if (searchGroups && regex.test( cache[x] ) ) {
188-
$this.removeClass(hiddenClass);
193+
elem.classList.remove(hiddenClass);
189194
$groupItems.removeClass(hiddenClass);
190195
return $groupItems.find('input').get();
191196
}
192197
}
193198

194199
return $groupItems.map(function(y) {
195-
var $listItem = $(this);
196200
if ( regex.test( cache[x + '.' + y] ) ) {
197201
// Show the opt group heading if needed
198202
if (!groupShown) {
199-
$this.removeClass(hiddenClass);
203+
elem.classList.remove(hiddenClass);
200204
groupShown = true;
201205
}
202-
$listItem.removeClass(hiddenClass);
206+
this.classList.remove(hiddenClass);
203207
return this.getElementsByTagName('input')[0];
204208
}
205209
return null;
@@ -228,13 +232,13 @@
228232
this.instance.$checkboxes.children().each(function(x) {
229233
var $element = $(this);
230234
// Account for optgroups
231-
if ($element.hasClass('ui-multiselect-optgroup')) {
235+
if (this.classList.contains(optgroupClass)) {
232236
// Single number keys are the option labels
233-
cache[x] = $element.children('a').text();
237+
cache[x] = this.getElementsByClassName(groupLabelClass)[0].textContent;
234238
$element = $element.find('li');
235239
}
236240
$element.each(function(y) {
237-
cache[x + '.' + y] = $(this).text();
241+
cache[x + '.' + y] = this.textContent;
238242
});
239243
});
240244
this.cache = cache;
@@ -257,7 +261,7 @@
257261
destroy: function() {
258262
$.Widget.prototype.destroy.call(this);
259263
this.$input.val('').trigger("keyup").off('keydown input search');
260-
this.instance.$menu.find('.ui-multiselect-header').removeClass('ui-multiselect-hasfilter');
264+
this.instance.$menu.find(headerSelector).removeClass(hasFilterClass);
261265
this.$wrapper.remove();
262266
}
263267
});

src/jquery.multiselect.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -731,8 +731,19 @@
731731
// option label
732732
.on('mouseenter.multiselect', 'label', function() {
733733
if (!this.classList.contains('ui-state-disabled')) {
734+
var checkboxes = self.$checkboxes[0];
735+
var scrollLeft = checkboxes.scrollLeft;
736+
var scrollTop = checkboxes.scrollTop;
737+
var scrollX = window.scrollX;
738+
var scrollY = window.scrollY;
739+
734740
self.$labels.removeClass('ui-state-hover');
735741
$(this).addClass('ui-state-hover').find('input').focus();
742+
743+
// Restore scroll positions if altered by setting input focus
744+
checkboxes.scrollLeft = scrollLeft;
745+
checkboxes.scrollTop = scrollTop;
746+
window.scrollTo(scrollX, scrollY);
736747
}
737748
})
738749
// Keyboard navigation of the menu
@@ -1363,6 +1374,8 @@
13631374
var speed = this.speed;
13641375
var options = this.options;
13651376
var effect = options.openEffect;
1377+
var scrollX = window.scrollX;
1378+
var scrollY = window.scrollY;
13661379

13671380
// figure out opening effects/speeds
13681381
if (effect && effect.constructor == Array) {
@@ -1401,6 +1414,9 @@
14011414
$header.find('a').first().trigger('focus');
14021415
}
14031416

1417+
// Restore window scroll position if altered by setting element focus
1418+
window.scrollTo(scrollX, scrollY);
1419+
14041420
$button.addClass('ui-state-active');
14051421
this._isOpen = true;
14061422
this._trigger('open');
@@ -1675,7 +1691,7 @@
16751691
* @returns {array} List of option groups that are collapsed
16761692
*/
16771693
getCollapsed: function() {
1678-
return this.$checkboxes.find('.ui-multiselect-optgroup');
1694+
return this.$checkboxes.find('.ui-multiselect-collapsed');
16791695
},
16801696

16811697
/**

0 commit comments

Comments
 (0)