|
1 |
| -/*! selectize.js - v0.2.4 | https://github.com/brianreavis/selectize.js | Apache License (v2) */ |
| 1 | +/*! selectize.js - v0.3.0 | https://github.com/brianreavis/selectize.js | Apache License (v2) */ |
2 | 2 |
|
3 | 3 | (function(factory) {
|
4 | 4 | if (typeof exports === 'object') {
|
|
81 | 81 |
|
82 | 82 | var IS_MAC = /Mac/.test(navigator.userAgent);
|
83 | 83 |
|
| 84 | + var KEY_A = 65; |
84 | 85 | var KEY_COMMA = 188;
|
85 | 86 | var KEY_RETURN = 13;
|
86 | 87 | var KEY_ESC = 27;
|
|
316 | 317 |
|
317 | 318 | this.highlightedValue = null;
|
318 | 319 | this.isOpen = false;
|
| 320 | + this.isDisabled = false; |
319 | 321 | this.isLocked = false;
|
320 | 322 | this.isFocused = false;
|
321 | 323 | this.isInputFocused = false;
|
322 | 324 | this.isInputHidden = false;
|
323 | 325 | this.isSetup = false;
|
324 | 326 | this.isShiftDown = false;
|
| 327 | + this.isCmdDown = false; |
325 | 328 | this.isCtrlDown = false;
|
326 | 329 | this.ignoreFocus = false;
|
327 | 330 | this.hasOptions = false;
|
|
430 | 433 |
|
431 | 434 | $(document).on({
|
432 | 435 | keydown: function(e) {
|
| 436 | + self.isCmdDown = e[IS_MAC ? 'metaKey' : 'ctrlKey']; |
433 | 437 | self.isCtrlDown = e[IS_MAC ? 'altKey' : 'ctrlKey'];
|
434 | 438 | self.isShiftDown = e.shiftKey;
|
435 | 439 | if (self.isFocused && !self.isLocked) {
|
|
484 | 488 | this.updatePlaceholder();
|
485 | 489 | this.isSetup = true;
|
486 | 490 |
|
| 491 | + if (this.$input.is(':disabled')) { |
| 492 | + this.disable(); |
| 493 | + } |
| 494 | + |
487 | 495 | // preload options
|
488 | 496 | if (this.settings.preload) {
|
489 | 497 | this.onSearchChange('');
|
|
538 | 546 | }
|
539 | 547 |
|
540 | 548 | switch (keyCode) {
|
| 549 | + case KEY_A: |
| 550 | + if (this.isCmdDown) { |
| 551 | + this.selectAll(); |
| 552 | + e.preventDefault(); |
| 553 | + return; |
| 554 | + } |
| 555 | + break; |
541 | 556 | case KEY_ESC:
|
542 | 557 | this.blur();
|
543 | 558 | return;
|
|
549 | 564 | if ($next.length) this.setActiveOption($next, true, true);
|
550 | 565 | }
|
551 | 566 | e.preventDefault();
|
552 |
| - break; |
| 567 | + return; |
553 | 568 | case KEY_UP:
|
554 | 569 | if (this.$activeOption) {
|
555 | 570 | var $prev = this.$activeOption.prev();
|
556 | 571 | if ($prev.length) this.setActiveOption($prev, true, true);
|
557 | 572 | }
|
558 | 573 | e.preventDefault();
|
559 |
| - break; |
| 574 | + return; |
560 | 575 | case KEY_RETURN:
|
561 | 576 | if (this.$activeOption) {
|
562 | 577 | this.onOptionSelect({currentTarget: this.$activeOption});
|
563 | 578 | }
|
564 | 579 | e.preventDefault();
|
565 |
| - break; |
| 580 | + return; |
566 | 581 | case KEY_LEFT:
|
567 | 582 | this.advanceSelection(-1, e);
|
568 |
| - break; |
| 583 | + return; |
569 | 584 | case KEY_RIGHT:
|
570 | 585 | this.advanceSelection(1, e);
|
571 |
| - break; |
| 586 | + return; |
572 | 587 | case KEY_TAB:
|
573 | 588 | if (this.settings.create && $.trim(this.$control_input.val()).length) {
|
574 | 589 | this.createItem();
|
575 | 590 | e.preventDefault();
|
576 | 591 | }
|
577 |
| - break; |
| 592 | + return; |
578 | 593 | case KEY_BACKSPACE:
|
579 | 594 | case KEY_DELETE:
|
580 | 595 | this.deleteSelection(e);
|
581 |
| - break; |
582 |
| - default: |
583 |
| - if (this.isFull() || this.isInputHidden) { |
584 |
| - e.preventDefault(); |
585 |
| - return; |
586 |
| - } |
| 596 | + return; |
| 597 | + } |
| 598 | + if (this.isFull() || this.isInputHidden) { |
| 599 | + e.preventDefault(); |
| 600 | + return; |
587 | 601 | }
|
588 | 602 | };
|
589 | 603 |
|
|
613 | 627 | * @param {string} value
|
614 | 628 | */
|
615 | 629 | Selectize.prototype.onSearchChange = function(value) {
|
616 |
| - if (!this.settings.load) return; |
617 |
| - if (this.loadedSearches.hasOwnProperty(value)) return; |
618 | 630 | var self = this;
|
619 |
| - var $wrapper = this.$wrapper.addClass('loading'); |
620 |
| - |
621 |
| - this.loading++; |
622 |
| - this.loadedSearches[value] = true; |
623 |
| - this.settings.load.apply(this, [value, function(results) { |
624 |
| - self.loading = Math.max(self.loading - 1, 0); |
625 |
| - if (results && results.length) { |
626 |
| - self.addOption(results); |
627 |
| - self.refreshOptions(false); |
628 |
| - if (self.isInputFocused) self.open(); |
629 |
| - } |
630 |
| - if (!self.loading) { |
631 |
| - $wrapper.removeClass('loading'); |
632 |
| - } |
633 |
| - }]); |
| 631 | + var fn = self.settings.load; |
| 632 | + if (!fn) return; |
| 633 | + if (self.loadedSearches.hasOwnProperty(value)) return; |
| 634 | + self.loadedSearches[value] = true; |
| 635 | + self.load(function(callback) { |
| 636 | + fn.apply(self, [value, callback]); |
| 637 | + }); |
634 | 638 | };
|
635 | 639 |
|
636 | 640 | /**
|
|
642 | 646 | Selectize.prototype.onFocus = function(e) {
|
643 | 647 | this.isInputFocused = true;
|
644 | 648 | this.isFocused = true;
|
| 649 | + if (this.isDisabled) { |
| 650 | + this.blur(); |
| 651 | + e.preventDefault(); |
| 652 | + return false; |
| 653 | + } |
645 | 654 | if (this.ignoreFocus) return;
|
646 | 655 |
|
647 | 656 | this.showInput();
|
|
723 | 732 | }
|
724 | 733 | };
|
725 | 734 |
|
| 735 | + /** |
| 736 | + * Invokes the provided method that provides |
| 737 | + * results to a callback---which are then added |
| 738 | + * as options to the control. |
| 739 | + * |
| 740 | + * @param {function} fn |
| 741 | + */ |
| 742 | + Selectize.prototype.load = function(fn) { |
| 743 | + var self = this; |
| 744 | + var $wrapper = self.$wrapper.addClass('loading'); |
| 745 | + |
| 746 | + self.loading++; |
| 747 | + fn.apply(self, [function(results) { |
| 748 | + self.loading = Math.max(self.loading - 1, 0); |
| 749 | + if (results && results.length) { |
| 750 | + self.addOption(results); |
| 751 | + self.refreshOptions(false); |
| 752 | + if (self.isInputFocused) self.open(); |
| 753 | + } |
| 754 | + if (!self.loading) { |
| 755 | + $wrapper.removeClass('loading'); |
| 756 | + } |
| 757 | + self.trigger('onLoad', results); |
| 758 | + }]); |
| 759 | + }; |
| 760 | + |
726 | 761 | /**
|
727 | 762 | * Sets the input field of the control to the specified value.
|
728 | 763 | *
|
|
859 | 894 | }
|
860 | 895 | };
|
861 | 896 |
|
| 897 | + /** |
| 898 | + * Selects all items (CTRL + A). |
| 899 | + */ |
| 900 | + Selectize.prototype.selectAll = function() { |
| 901 | + this.$activeItems = Array.prototype.slice.apply(this.$control.children(':not(input)').addClass('active')); |
| 902 | + this.isFocused = true; |
| 903 | + if (this.$activeItems.length) this.hideInput(); |
| 904 | + }; |
| 905 | + |
862 | 906 | /**
|
863 | 907 | * Hides the input element out of view, while
|
864 | 908 | * retaining its focus.
|
865 | 909 | */
|
866 | 910 | Selectize.prototype.hideInput = function() {
|
| 911 | + this.close(); |
867 | 912 | this.setTextboxValue('');
|
868 | 913 | this.$control_input.css({opacity: 0, position: 'absolute', left: -10000});
|
869 | 914 | this.isInputHidden = true;
|
|
885 | 930 | * @param {boolean} trigger
|
886 | 931 | */
|
887 | 932 | Selectize.prototype.focus = function(trigger) {
|
| 933 | + if (this.isDisabled) return; |
888 | 934 | var self = this;
|
889 | 935 | self.ignoreFocus = true;
|
890 | 936 | self.$control_input[0].focus();
|
|
1198 | 1244 | * the options list dropdown (use `refreshOptions`
|
1199 | 1245 | * for that).
|
1200 | 1246 | *
|
| 1247 | + * Usage: |
| 1248 | + * |
| 1249 | + * this.addOption(value, data) |
| 1250 | + * this.addOption(data) |
| 1251 | + * |
1201 | 1252 | * @param {string} value
|
1202 | 1253 | * @param {object} data
|
1203 | 1254 | */
|
|
1244 | 1295 | };
|
1245 | 1296 |
|
1246 | 1297 | /**
|
1247 |
| - * Removes an option. |
| 1298 | + * Removes a single option. |
1248 | 1299 | *
|
1249 | 1300 | * @param {string} value
|
1250 | 1301 | */
|
|
1254 | 1305 | delete this.options[value];
|
1255 | 1306 | this.lastQuery = null;
|
1256 | 1307 | this.trigger('onOptionRemove', value);
|
| 1308 | + this.removeItem(value); |
| 1309 | + }; |
| 1310 | + |
| 1311 | + /** |
| 1312 | + * Clears all options. |
| 1313 | + */ |
| 1314 | + Selectize.prototype.clearOptions = function() { |
| 1315 | + this.loadedSearches = {}; |
| 1316 | + this.userOptions = {}; |
| 1317 | + this.options = {}; |
| 1318 | + this.lastQuery = null; |
| 1319 | + this.trigger('onOptionClear'); |
| 1320 | + this.clear(); |
1257 | 1321 | };
|
1258 | 1322 |
|
1259 | 1323 | /**
|
|
1456 | 1520 | Selectize.prototype.refreshClasses = function() {
|
1457 | 1521 | var isFull = this.isFull();
|
1458 | 1522 | var isLocked = this.isLocked;
|
1459 |
| - this.$control.toggleClass('locked', isLocked); |
1460 |
| - this.$control.toggleClass('full', isFull).toggleClass('not-full', !isFull); |
1461 |
| - this.$control.toggleClass('has-items', this.items.length > 0); |
| 1523 | + this.$control |
| 1524 | + .toggleClass('disabled', this.isDisabled) |
| 1525 | + .toggleClass('locked', isLocked) |
| 1526 | + .toggleClass('full', isFull).toggleClass('not-full', !isFull) |
| 1527 | + .toggleClass('has-items', this.items.length > 0); |
1462 | 1528 | this.$control_input.data('grow', !isFull && !isLocked);
|
1463 | 1529 | };
|
1464 | 1530 |
|
|
1534 | 1600 | if (!this.isOpen) return;
|
1535 | 1601 | this.$dropdown.hide();
|
1536 | 1602 | this.$control.removeClass('dropdown-active');
|
| 1603 | + this.setActiveOption(null); |
1537 | 1604 | this.isOpen = false;
|
1538 | 1605 | this.trigger('onDropdownClose', this.$dropdown);
|
1539 | 1606 | };
|
|
1566 | 1633 | this.updatePlaceholder();
|
1567 | 1634 | this.updateOriginalInput();
|
1568 | 1635 | this.refreshClasses();
|
| 1636 | + this.showInput(); |
1569 | 1637 | this.trigger('onClear');
|
1570 | 1638 | };
|
1571 | 1639 |
|
|
1741 | 1809 | this.refreshClasses();
|
1742 | 1810 | };
|
1743 | 1811 |
|
| 1812 | + /** |
| 1813 | + * Disables user input on the control completely. |
| 1814 | + * While disabled, it cannot receive focus. |
| 1815 | + */ |
| 1816 | + Selectize.prototype.disable = function() { |
| 1817 | + this.isDisabled = true; |
| 1818 | + this.lock(); |
| 1819 | + }; |
| 1820 | + |
| 1821 | + /** |
| 1822 | + * Enables the control so that it can respond |
| 1823 | + * to focus and user input. |
| 1824 | + */ |
| 1825 | + Selectize.prototype.enable = function() { |
| 1826 | + this.isDisabled = false; |
| 1827 | + this.unlock(); |
| 1828 | + }; |
| 1829 | + |
1744 | 1830 | /**
|
1745 | 1831 | * A helper method for rendering "item" and
|
1746 | 1832 | * "option" templates, given the data.
|
|
1833 | 1919 | onClear : null, // function() { ... }
|
1834 | 1920 | onOptionAdd : null, // function(value, data) { ... }
|
1835 | 1921 | onOptionRemove : null, // function(value) { ... }
|
| 1922 | + onOptionClear : null, // function() { ... } |
1836 | 1923 | onDropdownOpen : null, // function($dropdown) { ... }
|
1837 | 1924 | onDropdownClose : null, // function($dropdown) { ... }
|
1838 | 1925 | onType : null, // function(str) { ... }
|
|
0 commit comments