Skip to content

Commit afb33c1

Browse files
committed
add option to create a styled select but retain the default drop down functionality on mobile devices
1 parent 73ead6e commit afb33c1

File tree

6 files changed

+360
-157
lines changed

6 files changed

+360
-157
lines changed

public/jquery.selectric.js

Lines changed: 75 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
* /,'
1010
* /'
1111
*
12-
* Selectric ϟ v1.10.1 (Sep 22 2016) - http://lcdsantos.github.io/jQuery-Selectric/
12+
* Selectric ϟ v1.10.1 (Sep 23 2016) - http://lcdsantos.github.io/jQuery-Selectric/
1313
*
1414
* Copyright (c) 2016 Leonardo Santos; MIT License
1515
*
@@ -45,7 +45,7 @@
4545

4646
var pluginName = 'selectric';
4747
var classList = 'Input Items Open Disabled TempShow HideSelect Wrapper Focus Hover Responsive Above Scroll Group GroupLabel';
48-
var bindSufix = '.sl';
48+
var eventNamespaceSuffix = '.sl';
4949

5050
var chars = ['a', 'e', 'i', 'o', 'u', 'n', 'c', 'y'];
5151
var diacritics = [
@@ -249,12 +249,13 @@
249249
_this.classes = _this.getClassNames();
250250

251251
// Create elements
252-
var input = $('<input/>', { 'class': _this.classes.input, 'readonly': _this.utils.isMobile() });
253-
var items = $('<div/>', { 'class': _this.classes.items, 'tabindex': -1 });
254-
var itemsScroll = $('<div/>', { 'class': _this.classes.scroll });
255-
var wrapper = $('<div/>', { 'class': _this.classes.prefix, 'html': _this.options.arrowButtonMarkup });
256-
var label = $('<span/>', { 'class': 'label' });
257-
var outerWrapper = _this.$element.wrap('<div/>').parent().append(wrapper.prepend(label), items, input);
252+
var input = $('<input/>', { 'class': _this.classes.input, 'readonly': _this.utils.isMobile() });
253+
var items = $('<div/>', { 'class': _this.classes.items, 'tabindex': -1 });
254+
var itemsScroll = $('<div/>', { 'class': _this.classes.scroll });
255+
var wrapper = $('<div/>', { 'class': _this.classes.prefix, 'html': _this.options.arrowButtonMarkup });
256+
var label = $('<span/>', { 'class': 'label' });
257+
var outerWrapper = _this.$element.wrap('<div/>').parent().append(wrapper.prepend(label), items, input);
258+
var hideSelectWrapper = $('<div/>', { 'class': _this.classes.hideselect });
258259

259260
_this.elements = {
260261
input : input,
@@ -265,9 +266,18 @@
265266
outerWrapper : outerWrapper
266267
};
267268

269+
if (_this.options.nativeOnMobile && _this.utils.isMobile()) {
270+
_this.elements.input = undefined;
271+
hideSelectWrapper.addClass(_this.classes.prefix + '-is-native');
272+
273+
_this.$element.on('change', function () {
274+
_this.refresh();
275+
});
276+
}
277+
268278
_this.$element
269279
.on(_this.eventTriggers)
270-
.wrap('<div class="' + _this.classes.hideselect + '"/>');
280+
.wrap(hideSelectWrapper);
271281

272282
_this.originalTabindex = _this.$element.prop('tabindex');
273283
_this.$element.prop('tabindex', false);
@@ -551,9 +561,9 @@
551561
.add(_this.$element)
552562
.add(_this.elements.outerWrapper)
553563
.add(_this.elements.input)
554-
.off(bindSufix);
564+
.off(eventNamespaceSuffix);
555565

556-
_this.elements.outerWrapper.on('mouseenter' + bindSufix + ' mouseleave' + bindSufix, function(e) {
566+
_this.elements.outerWrapper.on('mouseenter' + eventNamespaceSuffix + ' mouseleave' + eventNamespaceSuffix, function(e) {
557567
$(this).toggleClass(_this.classes.hover, e.type === 'mouseenter');
558568

559569
// Delay close effect when openOnHover is true
@@ -569,52 +579,56 @@
569579
});
570580

571581
// Toggle open/close
572-
_this.elements.wrapper.on('click' + bindSufix, function(e) {
582+
_this.elements.wrapper.on('click' + eventNamespaceSuffix, function(e) {
573583
_this.state.opened ? _this.close() : _this.open(e);
574584
});
575585

576-
// Translate original element focus event to dummy input
577-
_this.$element.on('focus' + bindSufix, function() {
578-
_this.elements.input.focus();
579-
});
580-
581-
_this.elements.input
582-
.prop({ tabindex: _this.originalTabindex, disabled: false })
583-
.on('keydown' + bindSufix, $.proxy(_this.handleKeys, _this))
584-
.on('focusin' + bindSufix, function(e) {
585-
_this.elements.outerWrapper.addClass(_this.classes.focus);
586+
// Translate original element focus event to dummy input.
587+
// Disabled on mobile devices because the default option list isn't
588+
// shown due the fact that hidden input gets focused
589+
if ( !(_this.options.nativeOnMobile && _this.utils.isMobile()) ) {
590+
_this.$element.on('focus' + eventNamespaceSuffix, function() {
591+
_this.elements.input.focus();
592+
});
586593

587-
// Prevent the flicker when focusing out and back again in the browser window
588-
_this.elements.input.one('blur', function() {
589-
_this.elements.input.blur();
590-
});
594+
_this.elements.input
595+
.prop({ tabindex: _this.originalTabindex, disabled: false })
596+
.on('keydown' + eventNamespaceSuffix, $.proxy(_this.handleKeys, _this))
597+
.on('focusin' + eventNamespaceSuffix, function(e) {
598+
_this.elements.outerWrapper.addClass(_this.classes.focus);
591599

592-
if ( _this.options.openOnFocus && !_this.state.opened ) {
593-
_this.open(e);
594-
}
595-
})
596-
.on('focusout' + bindSufix, function() {
597-
_this.elements.outerWrapper.removeClass(_this.classes.focus);
598-
})
599-
.on('input propertychange', function() {
600-
var val = _this.elements.input.val();
601-
602-
// Clear search
603-
clearTimeout(_this.resetStr);
604-
_this.resetStr = setTimeout(function() {
605-
_this.elements.input.val('');
606-
}, _this.options.keySearchTimeout);
607-
608-
if ( val.length ) {
609-
// Search in select options
610-
$.each(_this.items, function(i, elm) {
611-
if ( new RegExp('^' + _this.utils.escapeRegExp(val), 'i').test(elm.slug) && !elm.disabled ) {
612-
_this.highlight(i);
613-
return false;
614-
}
600+
// Prevent the flicker when focusing out and back again in the browser window
601+
_this.elements.input.one('blur', function() {
602+
_this.elements.input.blur();
615603
});
616-
}
617-
});
604+
605+
if ( _this.options.openOnFocus && !_this.state.opened ) {
606+
_this.open(e);
607+
}
608+
})
609+
.on('focusout' + eventNamespaceSuffix, function() {
610+
_this.elements.outerWrapper.removeClass(_this.classes.focus);
611+
})
612+
.on('input propertychange', function() {
613+
var val = _this.elements.input.val();
614+
615+
// Clear search
616+
clearTimeout(_this.resetStr);
617+
_this.resetStr = setTimeout(function() {
618+
_this.elements.input.val('');
619+
}, _this.options.keySearchTimeout);
620+
621+
if ( val.length ) {
622+
// Search in select options
623+
$.each(_this.items, function(i, elm) {
624+
if ( new RegExp('^' + _this.utils.escapeRegExp(val), 'i').test(elm.slug) && !elm.disabled ) {
625+
_this.highlight(i);
626+
return false;
627+
}
628+
});
629+
}
630+
});
631+
}
618632

619633
_this.$li.on({
620634
// Prevent <input> blur on Chrome
@@ -790,6 +804,10 @@
790804
open: function(e) {
791805
var _this = this;
792806

807+
if ( _this.options.nativeOnMobile && _this.utils.isMobile()) {
808+
return false;
809+
}
810+
793811
_this.utils.triggerCallback('BeforeOpen', _this);
794812

795813
if ( e ) {
@@ -819,16 +837,16 @@
819837
// Delayed binds events on Document to make label clicks work
820838
setTimeout(function() {
821839
$doc
822-
.on('click' + bindSufix, $.proxy(_this.close, _this))
823-
.on('scroll' + bindSufix, $.proxy(_this.isInViewport, _this));
840+
.on('click' + eventNamespaceSuffix, $.proxy(_this.close, _this))
841+
.on('scroll' + eventNamespaceSuffix, $.proxy(_this.isInViewport, _this));
824842
}, 1);
825843

826844
_this.isInViewport();
827845

828846
// Prevent window scroll when using mouse wheel inside items box
829847
if ( _this.options.preventWindowScroll ) {
830848
/* istanbul ignore next */
831-
$doc.on('mousewheel' + bindSufix + ' DOMMouseScroll' + bindSufix, '.' + _this.classes.scroll, function(e) {
849+
$doc.on('mousewheel' + eventNamespaceSuffix + ' DOMMouseScroll' + eventNamespaceSuffix, '.' + _this.classes.scroll, function(e) {
832850
var orgEvent = e.originalEvent;
833851
var scrollTop = $(this).scrollTop();
834852
var deltaY = 0;
@@ -859,7 +877,7 @@
859877
_this.utils.triggerCallback('BeforeClose', _this);
860878

861879
// Remove custom events on document
862-
$doc.off(bindSufix);
880+
$doc.off(eventNamespaceSuffix);
863881

864882
// Remove visible class to hide options box
865883
_this.elements.outerWrapper.removeClass(_this.classes.open);
@@ -983,7 +1001,7 @@
9831001
_this.$element.removeData(pluginName).removeData('value');
9841002
}
9851003

986-
_this.$element.prop('tabindex', _this.originalTabindex).off(bindSufix).off(_this.eventTriggers).unwrap().unwrap();
1004+
_this.$element.prop('tabindex', _this.originalTabindex).off(eventNamespaceSuffix).off(_this.eventTriggers).unwrap().unwrap();
9871005

9881006
_this.state.enabled = false;
9891007
}
@@ -1047,6 +1065,7 @@
10471065
keySearchTimeout : 500,
10481066
arrowButtonMarkup : '<b class="button">&#x25be;</b>',
10491067
disableOnMobile : true,
1068+
nativeOnMobile : true,
10501069
openOnFocus : true,
10511070
openOnHover : false,
10521071
hoverIntentTimeout : 500,

0 commit comments

Comments
 (0)