|
635 | 635 | })); |
636 | 636 |
|
637 | 637 | /** |
638 | | - * selectize.js (v0.12.4) |
| 638 | + * selectize.js (v0.12.6) |
639 | 639 | * Copyright (c) 2013–2015 Brian Reavis & contributors |
640 | 640 | * |
641 | 641 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this |
|
670 | 670 |
|
671 | 671 | var highlight = function(node) { |
672 | 672 | var skip = 0; |
| 673 | + // Wrap matching part of text node with highlighting <span>, e.g. |
| 674 | + // Soccer -> <span class="highlight">Soc</span>cer for regex = /soc/i |
673 | 675 | if (node.nodeType === 3) { |
674 | 676 | var pos = node.data.search(regex); |
675 | 677 | if (pos >= 0 && node.data.length > 0) { |
|
683 | 685 | middlebit.parentNode.replaceChild(spannode, middlebit); |
684 | 686 | skip = 1; |
685 | 687 | } |
686 | | - } else if (node.nodeType === 1 && node.childNodes && !/(script|style)/i.test(node.tagName)) { |
| 688 | + } |
| 689 | + // Recurse element node, looking for child text nodes to highlight, unless element |
| 690 | + // is childless, <script>, <style>, or already highlighted: <span class="hightlight"> |
| 691 | + else if (node.nodeType === 1 && node.childNodes && !/(script|style)/i.test(node.tagName) && ( node.className !== 'highlight' || node.tagName !== 'SPAN' )) { |
687 | 692 | for (var i = 0; i < node.childNodes.length; ++i) { |
688 | 693 | i += highlight(node.childNodes[i]); |
689 | 694 | } |
|
1006 | 1011 | return 0; |
1007 | 1012 | } |
1008 | 1013 |
|
1009 | | - var $test = $('<test>').css({ |
1010 | | - position: 'absolute', |
1011 | | - top: -99999, |
1012 | | - left: -99999, |
1013 | | - width: 'auto', |
1014 | | - padding: 0, |
1015 | | - whiteSpace: 'pre' |
1016 | | - }).text(str).appendTo('body'); |
| 1014 | + if (!Selectize.$testInput) { |
| 1015 | + Selectize.$testInput = $('<span />').css({ |
| 1016 | + position: 'absolute', |
| 1017 | + top: -99999, |
| 1018 | + left: -99999, |
| 1019 | + width: 'auto', |
| 1020 | + padding: 0, |
| 1021 | + whiteSpace: 'pre' |
| 1022 | + }).appendTo('body'); |
| 1023 | + } |
| 1024 | + |
| 1025 | + Selectize.$testInput.text(str); |
1017 | 1026 |
|
1018 | | - transferStyles($parent, $test, [ |
| 1027 | + transferStyles($parent, Selectize.$testInput, [ |
1019 | 1028 | 'letterSpacing', |
1020 | 1029 | 'fontSize', |
1021 | 1030 | 'fontFamily', |
1022 | 1031 | 'fontWeight', |
1023 | 1032 | 'textTransform' |
1024 | 1033 | ]); |
1025 | 1034 |
|
1026 | | - var width = $test.width(); |
1027 | | - $test.remove(); |
1028 | | - |
1029 | | - return width; |
| 1035 | + return Selectize.$testInput.width(); |
1030 | 1036 | }; |
1031 | 1037 |
|
1032 | 1038 | /** |
|
1054 | 1060 | if (e.type && e.type.toLowerCase() === 'keydown') { |
1055 | 1061 | keyCode = e.keyCode; |
1056 | 1062 | printable = ( |
1057 | | - (keyCode >= 97 && keyCode <= 122) || // a-z |
1058 | | - (keyCode >= 65 && keyCode <= 90) || // A-Z |
1059 | 1063 | (keyCode >= 48 && keyCode <= 57) || // 0-9 |
| 1064 | + (keyCode >= 65 && keyCode <= 90) || // a-z |
| 1065 | + (keyCode >= 96 && keyCode <= 111) || // numpad 0-9, numeric operators |
| 1066 | + (keyCode >= 186 && keyCode <= 222) || // semicolon, equal, comma, dash, etc. |
1060 | 1067 | keyCode === 32 // space |
1061 | 1068 | ); |
1062 | 1069 |
|
|
1139 | 1146 |
|
1140 | 1147 | eventNS : '.selectize' + (++Selectize.count), |
1141 | 1148 | highlightedValue : null, |
| 1149 | + isBlurring : false, |
1142 | 1150 | isOpen : false, |
1143 | 1151 | isDisabled : false, |
1144 | 1152 | isRequired : $input.is('[required]'), |
|
1298 | 1306 | if ($input.attr('autocapitalize')) { |
1299 | 1307 | $control_input.attr('autocapitalize', $input.attr('autocapitalize')); |
1300 | 1308 | } |
| 1309 | + $control_input[0].type = $input[0].type; |
1301 | 1310 |
|
1302 | 1311 | self.$wrapper = $wrapper; |
1303 | 1312 | self.$control = $control; |
1304 | 1313 | self.$control_input = $control_input; |
1305 | 1314 | self.$dropdown = $dropdown; |
1306 | 1315 | self.$dropdown_content = $dropdown_content; |
1307 | 1316 |
|
| 1317 | + $dropdown.on('mouseenter mousedown click', '[data-disabled]>[data-selectable]', function(e) { e.stopImmediatePropagation(); }); |
1308 | 1318 | $dropdown.on('mouseenter', '[data-selectable]', function() { return self.onOptionHover.apply(self, arguments); }); |
1309 | 1319 | $dropdown.on('mousedown click', '[data-selectable]', function() { return self.onOptionSelect.apply(self, arguments); }); |
1310 | 1320 | watchChildEvent($control, 'mousedown', '*:not(input)', function() { return self.onItemSelect.apply(self, arguments); }); |
|
1480 | 1490 |
|
1481 | 1491 | // necessary for mobile webkit devices (manual focus triggering |
1482 | 1492 | // is ignored unless invoked within a click event) |
1483 | | - if (!self.isFocused) { |
| 1493 | + // also necessary to reopen a dropdown that has been closed by |
| 1494 | + // closeAfterSelect |
| 1495 | + if (!self.isFocused || !self.isOpen) { |
1484 | 1496 | self.focus(); |
1485 | 1497 | e.preventDefault(); |
1486 | 1498 | } |
|
1768 | 1780 | // IE11 bug: element still marked as active |
1769 | 1781 | dest && dest.focus && dest.focus(); |
1770 | 1782 |
|
| 1783 | + self.isBlurring = false; |
1771 | 1784 | self.ignoreFocus = false; |
1772 | 1785 | self.trigger('blur'); |
1773 | 1786 | }; |
1774 | 1787 |
|
| 1788 | + self.isBlurring = true; |
1775 | 1789 | self.ignoreFocus = true; |
1776 | 1790 | if (self.settings.create && self.settings.createOnBlur) { |
1777 | 1791 | self.createItem(null, false, deactivate); |
|
2109 | 2123 | return { |
2110 | 2124 | fields : settings.searchField, |
2111 | 2125 | conjunction : settings.searchConjunction, |
2112 | | - sort : sort |
| 2126 | + sort : sort, |
| 2127 | + nesting : settings.nesting |
2113 | 2128 | }; |
2114 | 2129 | }, |
2115 | 2130 |
|
|
2243 | 2258 | $dropdown_content.html(html); |
2244 | 2259 |
|
2245 | 2260 | // highlight matching terms inline |
2246 | | - if (self.settings.highlight && results.query.length && results.tokens.length) { |
| 2261 | + if (self.settings.highlight) { |
2247 | 2262 | $dropdown_content.removeHighlight(); |
2248 | | - for (i = 0, n = results.tokens.length; i < n; i++) { |
2249 | | - highlight($dropdown_content, results.tokens[i].regex); |
| 2263 | + if (results.query.length && results.tokens.length) { |
| 2264 | + for (i = 0, n = results.tokens.length; i < n; i++) { |
| 2265 | + highlight($dropdown_content, results.tokens[i].regex); |
| 2266 | + } |
2250 | 2267 | } |
2251 | 2268 | } |
2252 | 2269 |
|
|
2481 | 2498 | self.loadedSearches = {}; |
2482 | 2499 | self.userOptions = {}; |
2483 | 2500 | self.renderCache = {}; |
2484 | | - self.options = self.sifter.items = {}; |
| 2501 | + var options = self.options; |
| 2502 | + $.each(self.options, function(key, value) { |
| 2503 | + if(self.items.indexOf(key) == -1) { |
| 2504 | + delete options[key]; |
| 2505 | + } |
| 2506 | + }); |
| 2507 | + self.options = self.sifter.items = options; |
2485 | 2508 | self.lastQuery = null; |
2486 | 2509 | self.trigger('option_clear'); |
2487 | | - self.clear(); |
2488 | 2510 | }, |
2489 | 2511 |
|
2490 | 2512 | /** |
|
2554 | 2576 | * @param {boolean} silent |
2555 | 2577 | */ |
2556 | 2578 | addItems: function(values, silent) { |
| 2579 | + this.buffer = document.createDocumentFragment(); |
| 2580 | + |
| 2581 | + var childNodes = this.$control[0].childNodes; |
| 2582 | + for (var i = 0; i < childNodes.length; i++) { |
| 2583 | + this.buffer.appendChild(childNodes[i]); |
| 2584 | + } |
| 2585 | + |
2557 | 2586 | var items = $.isArray(values) ? values : [values]; |
2558 | 2587 | for (var i = 0, n = items.length; i < n; i++) { |
2559 | 2588 | this.isPending = (i < n - 1); |
2560 | 2589 | this.addItem(items[i], silent); |
2561 | 2590 | } |
| 2591 | + |
| 2592 | + var control = this.$control[0]; |
| 2593 | + control.insertBefore(this.buffer, control.firstChild); |
| 2594 | + |
| 2595 | + this.buffer = null; |
2562 | 2596 | }, |
2563 | 2597 |
|
2564 | 2598 | /** |
|
2611 | 2645 | // hide the menu if the maximum number of items have been selected or no options are left |
2612 | 2646 | if (!$options.length || self.isFull()) { |
2613 | 2647 | self.close(); |
2614 | | - } else { |
| 2648 | + } else if (!self.isPending) { |
2615 | 2649 | self.positionDropdown(); |
2616 | 2650 | } |
2617 | 2651 |
|
2618 | 2652 | self.updatePlaceholder(); |
2619 | 2653 | self.trigger('item_add', value, $item); |
2620 | | - self.updateOriginalInput({silent: silent}); |
| 2654 | + |
| 2655 | + if (!self.isPending) { |
| 2656 | + self.updateOriginalInput({silent: silent}); |
| 2657 | + } |
2621 | 2658 | } |
2622 | 2659 | }); |
2623 | 2660 | }, |
|
2872 | 2909 |
|
2873 | 2910 | if (self.settings.mode === 'single' && self.items.length) { |
2874 | 2911 | self.hideInput(); |
2875 | | - self.$control_input.blur(); // close keyboard on iOS |
| 2912 | + |
| 2913 | + // Do not trigger blur while inside a blur event, |
| 2914 | + // this fixes some weird tabbing behavior in FF and IE. |
| 2915 | + // See #1164 |
| 2916 | + if (!self.isBlurring) { |
| 2917 | + self.$control_input.blur(); // close keyboard on iOS |
| 2918 | + } |
2876 | 2919 | } |
2877 | 2920 |
|
2878 | 2921 | self.isOpen = false; |
|
2893 | 2936 | offset.top += $control.outerHeight(true); |
2894 | 2937 |
|
2895 | 2938 | this.$dropdown.css({ |
2896 | | - width : $control.outerWidth(), |
| 2939 | + width : $control[0].getBoundingClientRect().width, |
2897 | 2940 | top : offset.top, |
2898 | 2941 | left : offset.left |
2899 | 2942 | }); |
|
2929 | 2972 | */ |
2930 | 2973 | insertAtCaret: function($el) { |
2931 | 2974 | var caret = Math.min(this.caretPos, this.items.length); |
| 2975 | + var el = $el[0]; |
| 2976 | + var target = this.buffer || this.$control[0]; |
| 2977 | + |
2932 | 2978 | if (caret === 0) { |
2933 | | - this.$control.prepend($el); |
| 2979 | + target.insertBefore(el, target.firstChild); |
2934 | 2980 | } else { |
2935 | | - $(this.$control[0].childNodes[caret]).before($el); |
| 2981 | + target.insertBefore(el, target.childNodes[caret]); |
2936 | 2982 | } |
| 2983 | + |
2937 | 2984 | this.setCaret(caret + 1); |
2938 | 2985 | }, |
2939 | 2986 |
|
|
3169 | 3216 | self.$control_input.removeData('grow'); |
3170 | 3217 | self.$input.removeData('selectize'); |
3171 | 3218 |
|
| 3219 | + if (--Selectize.count == 0 && Selectize.$testInput) { |
| 3220 | + Selectize.$testInput.remove(); |
| 3221 | + Selectize.$testInput = undefined; |
| 3222 | + } |
| 3223 | + |
3172 | 3224 | $(window).off(eventNS); |
3173 | 3225 | $(document).off(eventNS); |
3174 | 3226 | $(document.body).off(eventNS); |
|
3211 | 3263 |
|
3212 | 3264 | // add mandatory attributes |
3213 | 3265 | if (templateName === 'option' || templateName === 'option_create') { |
3214 | | - html.attr('data-selectable', ''); |
| 3266 | + if (!data[self.settings.disabledField]) { |
| 3267 | + html.attr('data-selectable', ''); |
| 3268 | + } |
3215 | 3269 | } |
3216 | 3270 | else if (templateName === 'optgroup') { |
3217 | 3271 | id = data[self.settings.optgroupValueField] || ''; |
3218 | 3272 | html.attr('data-group', id); |
| 3273 | + if(data[self.settings.disabledField]) { |
| 3274 | + html.attr('data-disabled', ''); |
| 3275 | + } |
3219 | 3276 | } |
3220 | 3277 | if (templateName === 'option' || templateName === 'item') { |
3221 | 3278 | html.attr('data-value', value || ''); |
|
3297 | 3354 | optgroupField: 'optgroup', |
3298 | 3355 | valueField: 'value', |
3299 | 3356 | labelField: 'text', |
| 3357 | + disabledField: 'disabled', |
3300 | 3358 | optgroupLabelField: 'label', |
3301 | 3359 | optgroupValueField: 'value', |
3302 | 3360 | lockOptgroupOrder: false, |
|
3353 | 3411 | var attr_data = settings.dataAttr; |
3354 | 3412 | var field_label = settings.labelField; |
3355 | 3413 | var field_value = settings.valueField; |
| 3414 | + var field_disabled = settings.disabledField; |
3356 | 3415 | var field_optgroup = settings.optgroupField; |
3357 | 3416 | var field_optgroup_label = settings.optgroupLabelField; |
3358 | 3417 | var field_optgroup_value = settings.optgroupValueField; |
|
3433 | 3492 | var option = readData($option) || {}; |
3434 | 3493 | option[field_label] = option[field_label] || $option.text(); |
3435 | 3494 | option[field_value] = option[field_value] || value; |
| 3495 | + option[field_disabled] = option[field_disabled] || $option.prop('disabled'); |
3436 | 3496 | option[field_optgroup] = option[field_optgroup] || group; |
3437 | 3497 |
|
3438 | 3498 | optionsMap[value] = option; |
|
3453 | 3513 | optgroup = readData($optgroup) || {}; |
3454 | 3514 | optgroup[field_optgroup_label] = id; |
3455 | 3515 | optgroup[field_optgroup_value] = id; |
| 3516 | + optgroup[field_disabled] = $optgroup.prop('disabled'); |
3456 | 3517 | settings_element.optgroups.push(optgroup); |
3457 | 3518 | } |
3458 | 3519 |
|
|
3710 | 3771 | * @return {string} |
3711 | 3772 | */ |
3712 | 3773 | var append = function(html_container, html_element) { |
3713 | | - return html_container + html_element; |
| 3774 | + return $('<span>').append(html_container) |
| 3775 | + .append(html_element); |
3714 | 3776 | }; |
3715 | 3777 |
|
3716 | 3778 | thisRef.setup = (function() { |
|
0 commit comments