├── .gitignore ├── examples ├── images │ ├── bg.png │ ├── spinner.gif │ ├── check@2x.png │ ├── repo-forked.png │ └── repo-source.png ├── confirm.html ├── js │ ├── index.js │ └── es5.js ├── dynamic.html ├── required.html ├── performance.html ├── rtl.html ├── create-filter.html ├── lock.html ├── customization.html ├── css │ ├── stylesheet.css │ └── normalize.css ├── api.html ├── plugins.html ├── events.html ├── github.html ├── movies.html ├── cities.html ├── contacts.html └── optgroups.html ├── dist ├── less │ ├── plugins │ │ ├── optgroup_columns.less │ │ ├── drag_drop.less │ │ ├── dropdown_header.less │ │ └── remove_button.less │ ├── selectize.default.less │ ├── selectize.legacy.less │ ├── selectize.bootstrap3.less │ ├── selectize.bootstrap2.less │ └── selectize.less └── css │ └── selectize.css ├── src ├── plugins │ ├── optgroup_columns │ │ ├── plugin.less │ │ └── plugin.js │ ├── drag_drop │ │ ├── plugin.less │ │ └── plugin.js │ ├── dropdown_header │ │ ├── plugin.less │ │ └── plugin.js │ ├── remove_button │ │ ├── plugin.less │ │ └── plugin.js │ └── restore_on_backspace │ │ └── plugin.js ├── less │ ├── .wrapper.css │ ├── selectize.default.less │ ├── selectize.legacy.less │ ├── selectize.bootstrap3.less │ └── selectize.bootstrap2.less ├── constants.js ├── .wrapper.js ├── contrib │ ├── microevent.js │ └── highlight.js ├── defaults.js ├── selectize.jquery.js └── utils.js ├── test ├── support │ └── base.js ├── events_dom.js └── xss.js ├── Makefile ├── selectize.jquery.json ├── bower.json ├── .travis.yml ├── .github └── ISSUE_TEMPLATE.md ├── CHANGELOG.md ├── package.json ├── docs ├── plugins.md └── events.md ├── karma.conf.js ├── Gruntfile.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .DAV 3 | node_modules 4 | bower_components 5 | *.log -------------------------------------------------------------------------------- /examples/images/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmx/selectize.js/master/examples/images/bg.png -------------------------------------------------------------------------------- /examples/images/spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmx/selectize.js/master/examples/images/spinner.gif -------------------------------------------------------------------------------- /examples/images/check@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmx/selectize.js/master/examples/images/check@2x.png -------------------------------------------------------------------------------- /examples/images/repo-forked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmx/selectize.js/master/examples/images/repo-forked.png -------------------------------------------------------------------------------- /examples/images/repo-source.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmx/selectize.js/master/examples/images/repo-source.png -------------------------------------------------------------------------------- /dist/less/plugins/optgroup_columns.less: -------------------------------------------------------------------------------- 1 | .selectize-dropdown.plugin-optgroup_columns { 2 | .optgroup { 3 | border-right: 1px solid #f2f2f2; 4 | border-top: 0 none; 5 | float: left; 6 | .selectize-box-sizing(border-box); 7 | } 8 | .optgroup:last-child { 9 | border-right: 0 none; 10 | } 11 | .optgroup:before { 12 | display: none; 13 | } 14 | .optgroup-header { 15 | border-top: 0 none; 16 | } 17 | } -------------------------------------------------------------------------------- /src/plugins/optgroup_columns/plugin.less: -------------------------------------------------------------------------------- 1 | .selectize-dropdown.plugin-optgroup_columns { 2 | .optgroup { 3 | border-right: 1px solid #f2f2f2; 4 | border-top: 0 none; 5 | float: left; 6 | .selectize-box-sizing(border-box); 7 | } 8 | .optgroup:last-child { 9 | border-right: 0 none; 10 | } 11 | .optgroup:before { 12 | display: none; 13 | } 14 | .optgroup-header { 15 | border-top: 0 none; 16 | } 17 | } -------------------------------------------------------------------------------- /dist/less/plugins/drag_drop.less: -------------------------------------------------------------------------------- 1 | .selectize-control.plugin-drag_drop { 2 | &.multi > .selectize-input > div.ui-sortable-placeholder { 3 | visibility: visible !important; 4 | background: #f2f2f2 !important; 5 | background: rgba(0,0,0,0.06) !important; 6 | border: 0 none !important; 7 | .selectize-box-shadow(inset 0 0 12px 4px #fff); 8 | } 9 | .ui-sortable-placeholder::after { 10 | content: '!'; 11 | visibility: hidden; 12 | } 13 | .ui-sortable-helper { 14 | .selectize-box-shadow(0 2px 5px rgba(0,0,0,0.2)); 15 | } 16 | } -------------------------------------------------------------------------------- /src/plugins/drag_drop/plugin.less: -------------------------------------------------------------------------------- 1 | .selectize-control.plugin-drag_drop { 2 | &.multi > .selectize-input > div.ui-sortable-placeholder { 3 | visibility: visible !important; 4 | background: #f2f2f2 !important; 5 | background: rgba(0,0,0,0.06) !important; 6 | border: 0 none !important; 7 | .selectize-box-shadow(inset 0 0 12px 4px #fff); 8 | } 9 | .ui-sortable-placeholder::after { 10 | content: '!'; 11 | visibility: hidden; 12 | } 13 | .ui-sortable-helper { 14 | .selectize-box-shadow(0 2px 5px rgba(0,0,0,0.2)); 15 | } 16 | } -------------------------------------------------------------------------------- /dist/less/plugins/dropdown_header.less: -------------------------------------------------------------------------------- 1 | .selectize-dropdown-header { 2 | position: relative; 3 | padding: @selectize-padding-dropdown-item-y @selectize-padding-dropdown-item-x; 4 | border-bottom: 1px solid @selectize-color-border; 5 | background: mix(@selectize-color-dropdown, @selectize-color-border, 85%); 6 | .selectize-border-radius(@selectize-border-radius @selectize-border-radius 0 0); 7 | } 8 | .selectize-dropdown-header-close { 9 | position: absolute; 10 | right: @selectize-padding-dropdown-item-x; 11 | top: 50%; 12 | color: @selectize-color-text; 13 | opacity: 0.4; 14 | margin-top: -12px; 15 | line-height: 20px; 16 | font-size: 20px !important; 17 | } 18 | .selectize-dropdown-header-close:hover { 19 | color: darken(@selectize-color-text, 25%); 20 | } -------------------------------------------------------------------------------- /src/plugins/dropdown_header/plugin.less: -------------------------------------------------------------------------------- 1 | .selectize-dropdown-header { 2 | position: relative; 3 | padding: @selectize-padding-dropdown-item-y @selectize-padding-dropdown-item-x; 4 | border-bottom: 1px solid @selectize-color-border; 5 | background: mix(@selectize-color-dropdown, @selectize-color-border, 85%); 6 | .selectize-border-radius(@selectize-border-radius @selectize-border-radius 0 0); 7 | } 8 | .selectize-dropdown-header-close { 9 | position: absolute; 10 | right: @selectize-padding-dropdown-item-x; 11 | top: 50%; 12 | color: @selectize-color-text; 13 | opacity: 0.4; 14 | margin-top: -12px; 15 | line-height: 20px; 16 | font-size: 20px !important; 17 | } 18 | .selectize-dropdown-header-close:hover { 19 | color: darken(@selectize-color-text, 25%); 20 | } -------------------------------------------------------------------------------- /src/less/.wrapper.css: -------------------------------------------------------------------------------- 1 | /** 2 | * selectize.css (v@@version) 3 | * Copyright (c) 2013–2015 Brian Reavis & contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this 6 | * file except in compliance with the License. You may obtain a copy of the License at: 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under 10 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 11 | * ANY KIND, either express or implied. See the License for the specific language 12 | * governing permissions and limitations under the License. 13 | * 14 | * @author Brian Reavis 15 | */ 16 | 17 | @@css -------------------------------------------------------------------------------- /src/constants.js: -------------------------------------------------------------------------------- 1 | var IS_MAC = /Mac/.test(navigator.userAgent); 2 | 3 | var KEY_A = 65; 4 | var KEY_COMMA = 188; 5 | var KEY_RETURN = 13; 6 | var KEY_ESC = 27; 7 | var KEY_LEFT = 37; 8 | var KEY_UP = 38; 9 | var KEY_P = 80; 10 | var KEY_RIGHT = 39; 11 | var KEY_DOWN = 40; 12 | var KEY_N = 78; 13 | var KEY_BACKSPACE = 8; 14 | var KEY_DELETE = 46; 15 | var KEY_SHIFT = 16; 16 | var KEY_CMD = IS_MAC ? 91 : 17; 17 | var KEY_CTRL = IS_MAC ? 18 : 17; 18 | var KEY_TAB = 9; 19 | 20 | var TAG_SELECT = 1; 21 | var TAG_INPUT = 2; 22 | 23 | // for now, android support in general is too spotty to support validity 24 | var SUPPORTS_VALIDITY_API = !/android/i.test(window.navigator.userAgent) && !!document.createElement('input').validity; 25 | -------------------------------------------------------------------------------- /test/support/base.js: -------------------------------------------------------------------------------- 1 | window.expect = chai.expect; 2 | window.assert = chai.assert; 3 | window.has_focus = function(elem) { 4 | return !!(elem === document.activeElement); 5 | }; 6 | 7 | var sandbox = document.createElement('form'); 8 | document.body.appendChild(sandbox); 9 | 10 | window.setup_test = function(html, options, callback) { 11 | if (window.test_last) window.test_last.teardown(); 12 | 13 | var $select = $(html).appendTo(sandbox).selectize(options); 14 | var instance = $select[0].selectize; 15 | var test = window.test_last = { 16 | $select: $select, 17 | callback: callback, 18 | selectize: instance, 19 | teardown: function() { 20 | instance.destroy(); 21 | $select.remove(); 22 | window.test_last = null; 23 | } 24 | }; 25 | 26 | return test; 27 | }; 28 | 29 | after(function() { 30 | if (window.test_last) { 31 | window.test_last.teardown(); 32 | } 33 | }); 34 | 35 | $(sandbox).on('submit', function(e) { e.preventDefault(); }); -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: compile release test 2 | plugins=* 3 | GRUNT=node_modules/.bin/grunt 4 | 5 | all: compile 6 | test: 7 | npm test 8 | compile: 9 | $(GRUNT) --plugins=$(plugins) 10 | release: 11 | ifeq ($(strip $(version)),) 12 | @echo "\033[31mERROR:\033[0;39m No version provided." 13 | @echo "\033[1;30mmake release version=1.0.0\033[0;39m" 14 | else 15 | sed -i.bak 's/"version": "[^"]*"/"version": "$(version)"/' selectize.jquery.json 16 | sed -i.bak 's/"version": "[^"]*"/"version": "$(version)"/' package.json 17 | rm *.bak 18 | make compile 19 | npm test || exit 1 20 | cp dist/js/standalone/selectize.js ../.selectize.js 21 | git add . 22 | git commit -a -m "Released $(version)." 23 | git tag v$(version) 24 | git push origin master 25 | git push origin --tags 26 | npm publish 27 | git checkout gh-pages 28 | mv -f ../.selectize.js js/selectize.js 29 | git commit -a -m "Updated selectize.js to latest version." 30 | git push origin gh-pages 31 | git checkout master 32 | @echo "\033[32mv${version} released\033[0;39m" 33 | endif 34 | -------------------------------------------------------------------------------- /selectize.jquery.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "selectize", 3 | "version": "0.12.4", 4 | "title": "Selectize.js", 5 | "author": { 6 | "name": "Brian Reavis", 7 | "email": "brian@thirdroute.com", 8 | "url": "http://thirdroute.com" 9 | }, 10 | "keywords": ["select", "ui", "form", "input", "control", "autocomplete", "tagging", "tag"], 11 | "description": "Selectize is a jQuery-based custom UI control. Useful for tagging, contact lists, country selectors, etc.", 14 | "license": "Apache License, Version 2.0", 15 | "readmeFilename": "README.md", 16 | "repository": { 17 | "type": "git", 18 | "url": "git://github.com/selectize/selectize.js.git" 19 | }, 20 | "main": [ 21 | "dist/css/selectize.css", 22 | "dist/js/selectize.js" 23 | ], 24 | "ignore": [ 25 | "Makefile", 26 | "Gruntfile.js", 27 | "examples", 28 | "node_modules", 29 | "bower_components", 30 | "docs", 31 | "src", 32 | "test", 33 | ".travis.yml", 34 | "testem.json", 35 | "selectize.jquery.json", 36 | "*.sh", 37 | "package.json" 38 | ], 39 | "dependencies": { 40 | "jquery": ">=1.7.0", 41 | "microplugin": "0.0.x", 42 | "sifter": "0.5.x" 43 | }, 44 | "devDependencies": { 45 | "bootstrap2": "bootstrap#2", 46 | "bootstrap3": "bootstrap#3.2" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/plugins/remove_button/plugin.less: -------------------------------------------------------------------------------- 1 | .selectize-control.plugin-remove_button { 2 | [data-value] { 3 | position: relative; 4 | padding-right: 24px !important; 5 | } 6 | [data-value] .remove { 7 | z-index: 1; /* fixes ie bug (see #392) */ 8 | position: absolute; 9 | top: 0; 10 | right: 0; 11 | bottom: 0; 12 | width: 17px; 13 | text-align: center; 14 | font-weight: bold; 15 | font-size: 12px; 16 | color: inherit; 17 | text-decoration: none; 18 | vertical-align: middle; 19 | display: inline-block; 20 | padding: @selectize-padding-item-y 0 0 0; 21 | border-left: 1px solid @selectize-color-item-border; 22 | .selectize-border-radius(0 2px 2px 0); 23 | .selectize-box-sizing(border-box); 24 | } 25 | [data-value] .remove:hover { 26 | background: rgba(0,0,0,0.05); 27 | } 28 | [data-value].active .remove { 29 | border-left-color: @selectize-color-item-active-border; 30 | } 31 | .disabled [data-value] .remove:hover { 32 | background: none; 33 | } 34 | .disabled [data-value] .remove { 35 | border-left-color: lighten(desaturate(@selectize-color-item-border, 100%), @selectize-lighten-disabled-item-border); 36 | } 37 | .remove-single { 38 | position: absolute; 39 | right: 0; 40 | top: 0; 41 | font-size: 23px; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /dist/less/plugins/remove_button.less: -------------------------------------------------------------------------------- 1 | .selectize-control.plugin-remove_button { 2 | [data-value] { 3 | position: relative; 4 | padding-right: 24px !important; 5 | } 6 | [data-value] .remove { 7 | z-index: 1; /* fixes ie bug (see #392) */ 8 | position: absolute; 9 | top: 0; 10 | right: 0; 11 | bottom: 0; 12 | width: 17px; 13 | text-align: center; 14 | font-weight: bold; 15 | font-size: 12px; 16 | color: inherit; 17 | text-decoration: none; 18 | vertical-align: middle; 19 | display: inline-block; 20 | padding: @selectize-padding-item-y 0 0 0; 21 | border-left: 1px solid @selectize-color-item-border; 22 | .selectize-border-radius(0 2px 2px 0); 23 | .selectize-box-sizing(border-box); 24 | } 25 | [data-value] .remove:hover { 26 | background: rgba(0,0,0,0.05); 27 | } 28 | [data-value].active .remove { 29 | border-left-color: @selectize-color-item-active-border; 30 | } 31 | .disabled [data-value] .remove:hover { 32 | background: none; 33 | } 34 | .disabled [data-value] .remove { 35 | border-left-color: lighten(desaturate(@selectize-color-item-border, 100%), @selectize-lighten-disabled-item-border); 36 | } 37 | .remove-single { 38 | position: absolute; 39 | right: 28px; 40 | top: 6px; 41 | font-size: 23px; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | env: 3 | matrix: 4 | - TARGET=phantomjs 5 | - TARGET=saucelabs 6 | global: 7 | - secure: df9eTd6JkMOgdF3J3UInb0ouaDEbF4Y0sklmvwgBUs38yRvGQ3mucrzH13dCU0GYW8mM/H9euF7yG4/leWQHoUYdRJTDRy/sWXGvs6qg7DTkUXsmGyzv/5XxS86WTD5B9LbzB1hvRs5nzWeA1sFP6rpzGG6HwogM/+37ijRjKQQ= 8 | - secure: FI6ATM3Pngx0bowuYi5WHIDCe0R5ORlJWNsFxJyZLEusie+wZrRy9QbZsVvJGVYZJKAR9MFT3Ks494ou85lyfUnfvEnn+lX2DQ3Hsyz0xyBNoSvNkQbhZEsUr0TV+UGpCvSwYr6lYqXsBy6VxqyAkXDkqdVTAzMydq5ttGxszPU= 9 | - secure: "ctyTk+LdMsch1jTRLLTboJW2TsJCIRtXktEQ86JdGteg0YSvsqDj/LndUaaGZ2ZSR3sSJ1Q/YV1X0M0VizrzX5I7/3WnKViyeKygJ5sSbTuqkjwFa2sAAmrnmBv9JWofIc2XuRG3tfZv2fX6QMDy5PA72KGPBmGAw4S8WTxGkHQ=" 10 | matrix: 11 | allow_failures: 12 | - env: TARGET=saucelabs 13 | node_js: 14 | - '0.10' 15 | before_script: 16 | - npm install -g bower 17 | - npm install -g grunt-cli 18 | - npm install 19 | - make 20 | script: 21 | - export COMMIT_MESSAGE=$(git show -s --format=%B $TRAVIS_COMMIT | tr -d '\n') 22 | - export TRAVIS_CI=1 23 | - if [[ "${TARGET}" == "phantomjs" ]]; then npm test || exit 1; fi 24 | - if [[ "${TARGET}" == "saucelabs" ]]; then (for x in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; do export SAUCELABS_BATCH=$x; echo "Starting batch $x of 15"; npm test || true; done); fi 25 | -------------------------------------------------------------------------------- /src/.wrapper.js: -------------------------------------------------------------------------------- 1 | /** 2 | * selectize.js (v@@version) 3 | * Copyright (c) 2013–2015 Brian Reavis & contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this 6 | * file except in compliance with the License. You may obtain a copy of the License at: 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under 10 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 11 | * ANY KIND, either express or implied. See the License for the specific language 12 | * governing permissions and limitations under the License. 13 | * 14 | * @author Brian Reavis 15 | */ 16 | 17 | /*jshint curly:false */ 18 | /*jshint browser:true */ 19 | 20 | (function(root, factory) { 21 | if (typeof define === 'function' && define.amd) { 22 | define(['jquery','sifter','microplugin'], factory); 23 | } else if (typeof exports === 'object') { 24 | module.exports = factory(require('jquery'), require('sifter'), require('microplugin')); 25 | } else { 26 | root.Selectize = factory(root.jQuery, root.Sifter, root.MicroPlugin); 27 | } 28 | }(this, function($, Sifter, MicroPlugin) { 29 | 'use strict'; 30 | 31 | @@js 32 | 33 | return Selectize; 34 | })); -------------------------------------------------------------------------------- /examples/confirm.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Selectize.js Demo 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 |

Selectize.js

22 | 23 |
24 |

Confirm Delete

25 |
26 | 27 | 28 |
29 | 38 |
39 |
40 | 41 | 42 | -------------------------------------------------------------------------------- /src/plugins/restore_on_backspace/plugin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Plugin: "restore_on_backspace" (selectize.js) 3 | * Copyright (c) 2013 Brian Reavis & contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this 6 | * file except in compliance with the License. You may obtain a copy of the License at: 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under 10 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 11 | * ANY KIND, either express or implied. See the License for the specific language 12 | * governing permissions and limitations under the License. 13 | * 14 | * @author Brian Reavis 15 | */ 16 | 17 | Selectize.define('restore_on_backspace', function(options) { 18 | var self = this; 19 | 20 | options.text = options.text || function(option) { 21 | return option[this.settings.labelField]; 22 | }; 23 | 24 | this.onKeyDown = (function() { 25 | var original = self.onKeyDown; 26 | return function(e) { 27 | var index, option; 28 | if (e.keyCode === KEY_BACKSPACE && this.$control_input.val() === '' && !this.$activeItems.length) { 29 | index = this.caretPos - 1; 30 | if (index >= 0 && index < this.items.length) { 31 | option = this.options[this.items[index]]; 32 | if (this.deleteSelection(e)) { 33 | this.setTextboxValue(options.text.apply(this, [option])); 34 | this.refreshOptions(true); 35 | } 36 | e.preventDefault(); 37 | return; 38 | } 39 | } 40 | return original.apply(this, arguments); 41 | }; 42 | })(); 43 | }); 44 | -------------------------------------------------------------------------------- /src/contrib/microevent.js: -------------------------------------------------------------------------------- 1 | /** 2 | * MicroEvent - to make any js object an event emitter 3 | * 4 | * - pure javascript - server compatible, browser compatible 5 | * - dont rely on the browser doms 6 | * - super simple - you get it immediatly, no mistery, no magic involved 7 | * 8 | * @author Jerome Etienne (https://github.com/jeromeetienne) 9 | */ 10 | 11 | var MicroEvent = function() {}; 12 | MicroEvent.prototype = { 13 | on: function(event, fct){ 14 | this._events = this._events || {}; 15 | this._events[event] = this._events[event] || []; 16 | this._events[event].push(fct); 17 | }, 18 | off: function(event, fct){ 19 | var n = arguments.length; 20 | if (n === 0) return delete this._events; 21 | if (n === 1) return delete this._events[event]; 22 | 23 | this._events = this._events || {}; 24 | if (event in this._events === false) return; 25 | this._events[event].splice(this._events[event].indexOf(fct), 1); 26 | }, 27 | trigger: function(event /* , args... */){ 28 | this._events = this._events || {}; 29 | if (event in this._events === false) return; 30 | for (var i = 0; i < this._events[event].length; i++){ 31 | this._events[event][i].apply(this, Array.prototype.slice.call(arguments, 1)); 32 | } 33 | } 34 | }; 35 | 36 | /** 37 | * Mixin will delegate all MicroEvent.js function in the destination object. 38 | * 39 | * - MicroEvent.mixin(Foobar) will make Foobar able to use MicroEvent 40 | * 41 | * @param {object} the object which will support MicroEvent 42 | */ 43 | MicroEvent.mixin = function(destObject){ 44 | var props = ['on', 'off', 'trigger']; 45 | for (var i = 0; i < props.length; i++){ 46 | destObject.prototype[props[i]] = MicroEvent.prototype[props[i]]; 47 | } 48 | }; -------------------------------------------------------------------------------- /test/events_dom.js: -------------------------------------------------------------------------------- 1 | describe('DOM Events', function() { 2 | describe('"change"', function() { 3 | it('should be triggered once by addItem()', function(done) { 4 | var test = setup_test('', { 25 | valueField: 'value', 26 | labelField: 'value', 27 | options: [ 28 | {value: 'a'}, 29 | {value: 'b'}, 30 | ], 31 | items: ['a','b'] 32 | }); 33 | 34 | var counter = 0; 35 | test.$select.on('change', function() { counter++; }); 36 | test.selectize.removeItem('b'); 37 | 38 | window.setTimeout(function() { 39 | expect(counter).to.be.equal(1); 40 | done(); 41 | }, 0); 42 | }); 43 | it('should be triggered once by clear()', function(done) { 44 | var test = setup_test(' UI control. Useful for tagging, contact lists, country selectors, etc.", 15 | "version": "0.12.4", 16 | "author": "Brian Reavis ", 17 | "license": "Apache-2.0", 18 | "repository": { 19 | "type": "git", 20 | "url": "git://github.com/selectize/selectize.js.git" 21 | }, 22 | "dependencies": { 23 | "jquery": "^1.7.0", 24 | "microplugin": "0.0.3", 25 | "sifter": "^0.5.1" 26 | }, 27 | "devDependencies": { 28 | "chai": "^3.5.0", 29 | "grunt": "~1.0.1", 30 | "grunt-bower-task": "^0.4.0", 31 | "grunt-cli": "^1.2.0", 32 | "grunt-contrib-clean": "^1.0.0", 33 | "grunt-contrib-concat": "^1.0.1", 34 | "grunt-contrib-connect": "1.x", 35 | "grunt-contrib-copy": "^1.0.0", 36 | "grunt-contrib-less": "^1.4.0", 37 | "grunt-contrib-uglify": "^2.0.0", 38 | "grunt-contrib-watch": "1.x", 39 | "grunt-replace": "^1.0.1", 40 | "karma": "^1.3.0", 41 | "karma-chai": "^0.1.0", 42 | "karma-chrome-launcher": "^2.0.0", 43 | "karma-coverage": "^1.1.1", 44 | "karma-coveralls": "^1.1.2", 45 | "karma-firefox-launcher": "^1.0.0", 46 | "karma-mocha": "^1.3.0", 47 | "karma-mocha-reporter": "^2.2.0", 48 | "karma-phantomjs-launcher": "^1.0.1", 49 | "karma-safari-launcher": "^1.0.0", 50 | "karma-sauce-launcher": "^1.1.0", 51 | "mocha": "^3.1.0" 52 | }, 53 | "scripts": { 54 | "test": "karma start", 55 | "build": "make", 56 | "prestart": "npm run build", 57 | "start": "grunt serve", 58 | "grunt": "grunt" 59 | }, 60 | "engines": { 61 | "node": "*" 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /examples/dynamic.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Selectize.js Demo 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 |

Selectize.js

22 |
23 |

Dynamic Options

24 |

The options are created straight from an array.

25 |
26 | 27 | 28 |
29 | 45 |
46 |
47 | 48 | 49 | -------------------------------------------------------------------------------- /examples/required.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Selectize.js Demo 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 |

Selectize.js

22 | 23 |
24 |

Required Element

25 |
26 |
27 | 28 | 36 |
37 | 38 |
39 |
40 |
41 | 50 |
51 | 52 |
53 | 54 | 55 | -------------------------------------------------------------------------------- /test/xss.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | window.setup_xss_test = function(html, options, done) { 4 | window.xss = function() { 5 | window.clearTimeout(timeout); 6 | complete(new Error('Exploit executed')); 7 | }; 8 | 9 | var test = setup_test(html, options); 10 | var complete = function(err) { 11 | window.xss = function() {}; 12 | done(err); 13 | }; 14 | var timeout = window.setTimeout(complete, 75); 15 | return test; 16 | }; 17 | 18 | describe('XSS', function() { 19 | 20 | describe('Raw HTML in original input value', function() { 21 | it('should not trigger exploit', function(done) { 22 | setup_xss_test('', {}, done); 23 | }); 24 | }); 25 | 26 | describe('Raw HTML in optgroup label', function() { 27 | it('should not trigger exploit', function(done) { 28 | var test = setup_xss_test('', {}, done); 29 | test.selectize.refreshOptions(); 30 | test.selectize.open(); 31 | }); 32 | }); 33 | 34 | describe('Raw HTML in option label should not trigger exploit', function() { 35 | it('should not trigger exploit', function(done) { 36 | setup_xss_test('', { 37 | options: [ 38 | {value: '1', label: ''} 39 | ], 40 | items: ['1'], 41 | labelField: 'label', 42 | valueField: 'value' 43 | }, done); 44 | }); 45 | }); 46 | 47 | describe('Raw HTML in option value should not trigger exploit', function() { 48 | it('should not trigger exploit', function(done) { 49 | setup_xss_test('', { 50 | options: [ 51 | {value: '', label: '1'} 52 | ], 53 | items: [''], 54 | labelField: 'label', 55 | valueField: 'value' 56 | }, done); 57 | }); 58 | }); 59 | }); 60 | 61 | })(); -------------------------------------------------------------------------------- /examples/performance.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Selectize.js Demo 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 |

Selectize.js

22 |
23 |

Performance

24 |

This shows how it performs with 25,000 items.

25 |
26 | 27 | 28 |
29 | 56 |
57 |
58 | 59 | -------------------------------------------------------------------------------- /examples/rtl.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Selectize.js Demo 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 |

Selectize.js

22 | 23 |
24 |

Right-to-left Support (RTL)

25 |
26 | 27 | 28 |
29 | 35 |
36 | 37 |
38 |

Right-to-left Support (RTL) – Single

39 |
40 | 41 | 48 |
49 | 52 |
53 | 54 |
55 | 56 | 57 | -------------------------------------------------------------------------------- /src/contrib/highlight.js: -------------------------------------------------------------------------------- 1 | /** 2 | * highlight v3 | MIT license | Johann Burkard 3 | * Highlights arbitrary terms in a node. 4 | * 5 | * - Modified by Marshal 2011-6-24 (added regex) 6 | * - Modified by Brian Reavis 2012-8-27 (cleanup) 7 | */ 8 | 9 | var highlight = function($element, pattern) { 10 | if (typeof pattern === 'string' && !pattern.length) return; 11 | var regex = (typeof pattern === 'string') ? new RegExp(pattern, 'i') : pattern; 12 | 13 | var highlight = function(node) { 14 | var skip = 0; 15 | // Wrap matching part of text node with highlighting , e.g. 16 | // Soccer -> Soccer for regex = /soc/i 17 | if (node.nodeType === 3) { 18 | var pos = node.data.search(regex); 19 | if (pos >= 0 && node.data.length > 0) { 20 | var match = node.data.match(regex); 21 | var spannode = document.createElement('span'); 22 | spannode.className = 'highlight'; 23 | var middlebit = node.splitText(pos); 24 | var endbit = middlebit.splitText(match[0].length); 25 | var middleclone = middlebit.cloneNode(true); 26 | spannode.appendChild(middleclone); 27 | middlebit.parentNode.replaceChild(spannode, middlebit); 28 | skip = 1; 29 | } 30 | } 31 | // Recurse element node, looking for child text nodes to highlight, unless element 32 | // is childless, 16 | 17 | 18 | 19 | 20 |
21 |

Selectize.js

22 |
23 |

Create Filter

24 |

Examples of how to filter created results.

25 |
26 | 27 |

28 | 29 | 30 |
31 |
32 | 33 |

34 | 35 | 36 |
37 |
38 | 39 | 40 |
41 | 62 |
63 |
64 | 65 | 66 | -------------------------------------------------------------------------------- /examples/lock.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Selectize.js Demo 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 |

Selectize.js

22 |
23 |

Locking

24 |

Selectize controls can be locked to prevent user interaction.

25 |
26 | 27 | 32 |
33 |
34 | 35 | 40 |
41 |
42 | 43 | 48 |
49 |
50 | 51 | 56 |
57 | 63 |
64 |
65 | 66 | 67 | -------------------------------------------------------------------------------- /examples/customization.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Selectize.js Demo 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 34 | 35 | 36 |
37 |

Selectize.js

38 |
39 |

Customizing Appearance

40 |

Render items on your own & apply unique CSS styles.

41 |
42 | 43 | 44 |
45 | 78 |

TODO: explain how to bind events.

79 |
80 |
81 | 82 | 83 | -------------------------------------------------------------------------------- /examples/css/stylesheet.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 70px 0; 3 | padding: 0; 4 | font-family: Helvetica, arial, sans-serif; 5 | font-size: 15px; 6 | color: #454545; 7 | background: #fff url(../images/bg.png); 8 | text-shadow: 0 1px 0 rgba(0,0,0,0.02); 9 | -webkit-font-smoothing: antialiased; 10 | } 11 | a, a:visited { 12 | color: #3fabff; 13 | text-decoration: none; 14 | } 15 | a:hover { 16 | color: #008af5; 17 | } 18 | h1 { 19 | margin: 0; 20 | font-weight: 300; 21 | font-size: 35px; 22 | letter-spacing: -1px; 23 | } 24 | h2 { 25 | font-size: 15px; 26 | color: #a0a0a0; 27 | margin: 30px 0; 28 | } 29 | label { 30 | display: block; 31 | font-weight: bold; 32 | margin-bottom: 10px; 33 | } 34 | p, .control-group { 35 | margin: 0 0 20px 0; 36 | } 37 | .demo { 38 | border-bottom: 1px solid #e8e8e8; 39 | padding-top: 50px; 40 | padding-bottom: 50px; 41 | -webkit-border-radius: 3px; 42 | -moz-border-radius: 3px; 43 | border-radius: 3px; 44 | } 45 | .demo:last-child { 46 | border-bottom: 0 none; 47 | } 48 | .demo select, .demo input, .demo .selectize-control { 49 | width: 100%; 50 | } 51 | .demo > *:first-child { 52 | margin-top: 0; 53 | } 54 | .demo > *:last-child { 55 | margin-bottom: 0; 56 | } 57 | .demo .value { 58 | margin: 0 0 10px 0; 59 | font-size: 12px; 60 | } 61 | .demo .value span { 62 | font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace; 63 | } 64 | .theme-selector { 65 | margin-top: 10px; 66 | font-size: 13px; 67 | } 68 | .theme-selector:before { 69 | content: 'Themes: '; 70 | } 71 | .theme-selector a { 72 | margin: 0 5px; 73 | } 74 | .theme-selector a.active { 75 | color: #202020; 76 | font-weight: bold; 77 | } 78 | #wrapper { 79 | margin: 0; 80 | } 81 | #wrapper > * { 82 | padding-left: 100px; 83 | padding-right: 100px; 84 | } 85 | pre { 86 | background: #f8f8f8; 87 | border: 1px solid #f2f2f2; 88 | padding: 10px; 89 | font-size: 12px; 90 | font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace; 91 | -webkit-border-radius: 3px; 92 | -moz-border-radius: 3px; 93 | border-radius: 3px; 94 | } 95 | input[type=button] { 96 | margin: 0 10px 0 0; 97 | padding: 6px 10px; 98 | color: #606060; 99 | background: #e0e0e0; 100 | border: 0 none; 101 | width: auto; 102 | display: inline-block; 103 | -webkit-border-radius: 3px; 104 | -moz-border-radius: 3px; 105 | border-radius: 3px; 106 | -webkit-font-smoothing: antialiased; 107 | } 108 | .buttons { 109 | margin: 0 0 25px 0; 110 | } 111 | input[type=button]:hover { 112 | background: #dadada; 113 | } 114 | 115 | @media only screen and (max-width : 320px) { 116 | body { 117 | margin: 20px 0; 118 | } 119 | #wrapper { 120 | margin: 0; 121 | } 122 | #wrapper > * { 123 | padding-left: 10px; 124 | padding-right: 10px; 125 | } 126 | .demo { 127 | padding: 20px; 128 | -webkit-border-radius: 0; 129 | -moz-border-radius: 0; 130 | border-radius: 0; 131 | } 132 | } -------------------------------------------------------------------------------- /examples/api.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Selectize.js Demo 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 |

Selectize.js

22 |
23 |

API

24 |

Examples of how to interact with the control programmatically.

25 |
26 | 27 | 28 |
29 |
30 | 31 | 32 | 33 | 34 | 35 |
36 | 78 |
79 |
80 | 81 | 82 | -------------------------------------------------------------------------------- /docs/plugins.md: -------------------------------------------------------------------------------- 1 | ## Selectize API – Plugins 2 | 3 | Via the [microplugin](https://github.com/brianreavis/microplugin.js) interface, 4 | features can be added to Selectize without modifying the main library. 5 | This is great because it protects against code bloat, allows for lean builds, 6 | and allows for addons to be sanely isolated. The plugin system isn't meant 7 | to be sexy; it's lean, makes very few assumptions, and gives the developer 8 | complete control. 9 | 10 | [**Example Plugins**](../src/plugins) 11 | 12 | **A few notes:** 13 | - All plugins live in their own folders in ["src/plugins"](../src/plugins). 14 | - Plugin names should be in follow the format: `/[a-z_]+$` 15 | - JS source should live in a "plugin.js" file (required). 16 | - CSS should live in a "plugin.less" file (optional). It will be bundled at build time. 17 | - Plugins are initialized right before the control is setup. 18 | This means that if you want to listen for events on any of the control's 19 | elements, you should override the `setup()` method (see ["DOM Events"](#dom-events)). 20 | 21 | ### Boilerplate 22 | 23 | ```js 24 | Selectize.define('plugin_name', function(options) { 25 | // options: plugin-specific options 26 | // this: Selectize instance 27 | }); 28 | ``` 29 | 30 | #### Adding Dependencies 31 | 32 | ```js 33 | Selectize.define('plugin_name', function(options) { 34 | this.require('another_plugin'); 35 | }); 36 | ``` 37 | 38 | ## Overriding Methods 39 | 40 | Methods should be extended by [wrapping them](http://coreymaynard.com/blog/extending-a-javascript-function/): 41 | 42 | ```js 43 | var self = this; 44 | this.someMethod = (function() { 45 | var original = self.someMethod; 46 | return function() { 47 | // do your logic 48 | return original.apply(this, arguments); 49 | }; 50 | })(); 51 | ``` 52 | 53 | **Important:** If the method you're overriding returns a value, make sure the 54 | overridden function returns a value as well. 55 | 56 | ## DOM Events 57 | 58 | Because all elements for the control are created within the `setup()` method (which is 59 | invoked after the plugin initialized) events should be added by overriding the setup method, 60 | like so: 61 | 62 | ```js 63 | Selectize.define('plugin_name', function(options) { 64 | var self = this; 65 | 66 | // override the setup method to add an extra `click` handler 67 | this.setup = (function() { 68 | var original = self.setup; 69 | return function() { 70 | original.apply(this, arguments); 71 | this.$control.on('click', 'div', function(e) { 72 | alert('A div was clicked!'); 73 | }); 74 | }; 75 | })(); 76 | 77 | }); 78 | ``` 79 | 80 | ## Plugin Usage 81 | 82 | #### List (without options) 83 | 84 | ```js 85 | $('select').selectize({ 86 | plugins: ['plugin_a', 'plugin_b'] 87 | }); 88 | ``` 89 | 90 | #### List (with options) 91 | 92 | ```js 93 | $('select').selectize({ 94 | plugins: { 95 | 'plugin_a': { /* ... */ }, 96 | 'plugin_b': { /* ... */ } 97 | } 98 | }); 99 | ``` 100 | 101 | For a more detailed description of plugin option formats and how the plugin system works, check out the [microplugin](https://github.com/brianreavis/microplugin.js) documentation. 102 | -------------------------------------------------------------------------------- /src/plugins/optgroup_columns/plugin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Plugin: "optgroup_columns" (selectize.js) 3 | * Copyright (c) 2013 Simon Hewitt & contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this 6 | * file except in compliance with the License. You may obtain a copy of the License at: 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under 10 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 11 | * ANY KIND, either express or implied. See the License for the specific language 12 | * governing permissions and limitations under the License. 13 | * 14 | * @author Simon Hewitt 15 | */ 16 | 17 | Selectize.define('optgroup_columns', function(options) { 18 | var self = this; 19 | 20 | options = $.extend({ 21 | equalizeWidth : true, 22 | equalizeHeight : true 23 | }, options); 24 | 25 | this.getAdjacentOption = function($option, direction) { 26 | var $options = $option.closest('[data-group]').find('[data-selectable]'); 27 | var index = $options.index($option) + direction; 28 | 29 | return index >= 0 && index < $options.length ? $options.eq(index) : $(); 30 | }; 31 | 32 | this.onKeyDown = (function() { 33 | var original = self.onKeyDown; 34 | return function(e) { 35 | var index, $option, $options, $optgroup; 36 | 37 | if (this.isOpen && (e.keyCode === KEY_LEFT || e.keyCode === KEY_RIGHT)) { 38 | self.ignoreHover = true; 39 | $optgroup = this.$activeOption.closest('[data-group]'); 40 | index = $optgroup.find('[data-selectable]').index(this.$activeOption); 41 | 42 | if(e.keyCode === KEY_LEFT) { 43 | $optgroup = $optgroup.prev('[data-group]'); 44 | } else { 45 | $optgroup = $optgroup.next('[data-group]'); 46 | } 47 | 48 | $options = $optgroup.find('[data-selectable]'); 49 | $option = $options.eq(Math.min($options.length - 1, index)); 50 | if ($option.length) { 51 | this.setActiveOption($option); 52 | } 53 | return; 54 | } 55 | 56 | return original.apply(this, arguments); 57 | }; 58 | })(); 59 | 60 | var getScrollbarWidth = function() { 61 | var div; 62 | var width = getScrollbarWidth.width; 63 | var doc = document; 64 | 65 | if (typeof width === 'undefined') { 66 | div = doc.createElement('div'); 67 | div.innerHTML = '
'; 68 | div = div.firstChild; 69 | doc.body.appendChild(div); 70 | width = getScrollbarWidth.width = div.offsetWidth - div.clientWidth; 71 | doc.body.removeChild(div); 72 | } 73 | return width; 74 | }; 75 | 76 | var equalizeSizes = function() { 77 | var i, n, height_max, width, width_last, width_parent, $optgroups; 78 | 79 | $optgroups = $('[data-group]', self.$dropdown_content); 80 | n = $optgroups.length; 81 | if (!n || !self.$dropdown_content.width()) return; 82 | 83 | if (options.equalizeHeight) { 84 | height_max = 0; 85 | for (i = 0; i < n; i++) { 86 | height_max = Math.max(height_max, $optgroups.eq(i).height()); 87 | } 88 | $optgroups.css({height: height_max}); 89 | } 90 | 91 | if (options.equalizeWidth) { 92 | width_parent = self.$dropdown_content.innerWidth() - getScrollbarWidth(); 93 | width = Math.round(width_parent / n); 94 | $optgroups.css({width: width}); 95 | if (n > 1) { 96 | width_last = width_parent - width * (n - 1); 97 | $optgroups.eq(n - 1).css({width: width_last}); 98 | } 99 | } 100 | }; 101 | 102 | if (options.equalizeHeight || options.equalizeWidth) { 103 | hook.after(this, 'positionDropdown', equalizeSizes); 104 | hook.after(this, 'refreshOptions', equalizeSizes); 105 | } 106 | 107 | 108 | }); -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = function(config) { 2 | // workaround for https://github.com/karma-runner/karma-sauce-launcher/issues/40 3 | var saucelabsBatchID = Number(process.env.SAUCELABS_BATCH) - 1; 4 | var saucelabsConcurrency = 4; 5 | var saucelabsBrowsers = [ 6 | // mobile 7 | {platform: 'OS X 10.10', browserName: 'iPhone', version: '8.1'}, 8 | //{platform: 'OS X 10.10 ', browserName: 'iPhone', version: '6.0'}, 9 | {platform: 'OS X 10.10', browserName: 'iPad', version: '8.1'}, 10 | //{platform: 'OS X 10.10', browserName: 'iPad', version: '6.0'}, 11 | {platform: 'Linux', browserName: 'android', version: '4.4'}, 12 | {platform: 'Linux', browserName: 'android', version: '4.3'}, 13 | // desktop (safari) 14 | {platform: 'OS X 10.8', browserName: 'safari', version: 6}, 15 | {platform: 'OS X 10.9', browserName: 'safari', version: 7}, 16 | {platform: 'OS X 10.10', browserName: 'safari', version: 8}, 17 | // desktop (chrome) 18 | {platform: 'OS X 10.10', browserName: 'chrome', version: 39}, 19 | {platform: 'OS X 10.10', browserName: 'chrome', version: 38}, 20 | {platform: 'OS X 10.10', browserName: 'chrome', version: 37}, 21 | {platform: 'Windows 7', browserName: 'chrome', version: 39}, 22 | {platform: 'Windows 7', browserName: 'chrome', version: 38}, 23 | {platform: 'Windows 7', browserName: 'chrome', version: 37}, 24 | // desktop (firefox) 25 | {platform: 'Windows 7', browserName: 'firefox', version: 35}, 26 | {platform: 'Windows 8', browserName: 'firefox', version: 35}, 27 | {platform: 'OS X 10.10', browserName: 'firefox', version: 34}, 28 | {platform: 'OS X 10.10', browserName: 'firefox', version: 33}, 29 | {platform: 'OS X 10.10', browserName: 'firefox', version: 32}, 30 | // desktop (internet explorer) 31 | {platform: 'Windows 8', browserName: 'iexplore', version: 10}, 32 | {platform: 'Windows 8.1', browserName: 'iexplore', version: 11}, 33 | {platform: 'Windows 7', browserName: 'iexplore', version: 9} 34 | ]; 35 | 36 | if (process.env.TARGET === 'saucelabs') { 37 | saucelabsBrowsers = saucelabsBrowsers.slice(saucelabsBatchID * saucelabsConcurrency, saucelabsBatchID * saucelabsConcurrency + saucelabsConcurrency); 38 | if (!saucelabsBrowsers.length) process.exit(0); 39 | } 40 | 41 | var customLaunchers = {}; 42 | saucelabsBrowsers.forEach(function(browser, i) { 43 | browser.base = 'SauceLabs'; 44 | customLaunchers['SL_' + i] = browser; 45 | }); 46 | 47 | var targets = { 48 | 'saucelabs': Object.keys(customLaunchers), 49 | 'phantomjs': ['PhantomJS'] 50 | }; 51 | 52 | var reporters = ['mocha']; 53 | if (process.env.TRAVIS_CI) { 54 | reporters = process.env.TARGET === 'saucelabs' 55 | ? ['saucelabs', 'mocha'] 56 | : ['mocha', 'coverage', 'coveralls'] 57 | } 58 | 59 | var browsers = targets[process.env.TARGET || 'phantomjs']; 60 | if (process.env.BROWSERS) { 61 | browsers = process.env.BROWSERS.split(','); 62 | } 63 | 64 | config.set({ 65 | frameworks: ['mocha', 'chai'], 66 | files: [ 67 | 'dist/css/selectize.default.css', 68 | 'node_modules/jquery/dist/jquery.js', 69 | 'node_modules/microplugin/src/microplugin.js', 70 | 'node_modules/sifter/sifter.js', 71 | 'test/support/*.js', 72 | 'src/contrib/*.js', 73 | 'src/constants.js', 74 | 'src/utils.js', 75 | 'src/selectize.js', 76 | 'src/defaults.js', 77 | 'src/selectize.jquery.js', 78 | 'test/*.js' 79 | ], 80 | preprocessors: { 81 | 'src/*.js': ['coverage'] 82 | }, 83 | coverageReporter: { 84 | type: process.env.TRAVIS_CI && process.env.TARGET === 'phantomjs' ? 'lcov' : 'text-summary', 85 | dir: 'coverage/' 86 | }, 87 | sauceLabs: { 88 | recordVideo: false, 89 | startConnect: true, 90 | tunnelIdentifier: process.env.TRAVIS_JOB_NUMBER, 91 | build: process.env.TRAVIS_BUILD_NUMBER, 92 | testName: process.env.COMMIT_MESSAGE, 93 | tags: ['selectize', 'test'] 94 | }, 95 | customLaunchers: customLaunchers, 96 | reporters: reporters, 97 | port: 8888, 98 | colors: true, 99 | captureTimeout: 0, 100 | logLevel: config.LOG_INFO, 101 | browsers: browsers, 102 | browserDisconnectTolerance: 2, 103 | browserDisconnectTimeout: 10000, 104 | browserNoActivityTimeout: 120000, 105 | singleRun: true 106 | }); 107 | }; 108 | -------------------------------------------------------------------------------- /src/plugins/remove_button/plugin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Plugin: "remove_button" (selectize.js) 3 | * Copyright (c) 2013 Brian Reavis & contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this 6 | * file except in compliance with the License. You may obtain a copy of the License at: 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under 10 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 11 | * ANY KIND, either express or implied. See the License for the specific language 12 | * governing permissions and limitations under the License. 13 | * 14 | * @author Brian Reavis 15 | */ 16 | 17 | Selectize.define('remove_button', function(options) { 18 | options = $.extend({ 19 | label : '×', 20 | title : 'Remove', 21 | className : 'remove', 22 | append : true 23 | }, options); 24 | 25 | var singleClose = function(thisRef, options) { 26 | 27 | options.className = 'remove-single'; 28 | 29 | var self = thisRef; 30 | var html = '' + options.label + ''; 31 | 32 | /** 33 | * Appends an element as a child (with raw HTML). 34 | * 35 | * @param {string} html_container 36 | * @param {string} html_element 37 | * @return {string} 38 | */ 39 | var append = function(html_container, html_element) { 40 | return $('').append(html_container) 41 | .append(html_element); 42 | }; 43 | 44 | thisRef.setup = (function() { 45 | var original = self.setup; 46 | return function() { 47 | // override the item rendering method to add the button to each 48 | if (options.append) { 49 | var id = $(self.$input.context).attr('id'); 50 | var selectizer = $('#'+id); 51 | 52 | var render_item = self.settings.render.item; 53 | self.settings.render.item = function(data) { 54 | return append(render_item.apply(thisRef, arguments), html); 55 | }; 56 | } 57 | 58 | original.apply(thisRef, arguments); 59 | 60 | // add event listener 61 | thisRef.$control.on('click', '.' + options.className, function(e) { 62 | e.preventDefault(); 63 | if (self.isLocked) return; 64 | 65 | self.clear(); 66 | }); 67 | 68 | }; 69 | })(); 70 | }; 71 | 72 | var multiClose = function(thisRef, options) { 73 | 74 | var self = thisRef; 75 | var html = '' + options.label + ''; 76 | 77 | /** 78 | * Appends an element as a child (with raw HTML). 79 | * 80 | * @param {string} html_container 81 | * @param {string} html_element 82 | * @return {string} 83 | */ 84 | var append = function(html_container, html_element) { 85 | var pos = html_container.search(/(<\/[^>]+>\s*)$/); 86 | return html_container.substring(0, pos) + html_element + html_container.substring(pos); 87 | }; 88 | 89 | thisRef.setup = (function() { 90 | var original = self.setup; 91 | return function() { 92 | // override the item rendering method to add the button to each 93 | if (options.append) { 94 | var render_item = self.settings.render.item; 95 | self.settings.render.item = function(data) { 96 | return append(render_item.apply(thisRef, arguments), html); 97 | }; 98 | } 99 | 100 | original.apply(thisRef, arguments); 101 | 102 | // add event listener 103 | thisRef.$control.on('click', '.' + options.className, function(e) { 104 | e.preventDefault(); 105 | if (self.isLocked) return; 106 | 107 | var $item = $(e.currentTarget).parent(); 108 | self.setActiveItem($item); 109 | if (self.deleteSelection()) { 110 | self.setCaret(self.items.length); 111 | } 112 | }); 113 | 114 | }; 115 | })(); 116 | }; 117 | 118 | if (this.settings.mode === 'single') { 119 | singleClose(this, options); 120 | return; 121 | } else { 122 | multiClose(this, options); 123 | } 124 | }); 125 | -------------------------------------------------------------------------------- /examples/plugins.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Selectize.js Demo 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 |

Selectize.js

23 | 24 |
25 |

Plugin: "remove_button"

26 |
27 | 28 | 29 |
30 |
31 | 32 | 33 |
34 | 49 |
50 | 51 |
52 |

Plugin: "restore_on_backspace"

53 |
54 | 55 | 56 |
57 | 64 |
65 | 66 |
67 |

Plugin: "drag_drop"

68 |
69 | 70 | 71 |
72 |
73 | 74 | 75 |
76 | 83 |
84 | 85 |
86 |

Plugin: "dropdown_header"

87 |
88 | 89 | 103 |
104 | 115 |
116 |
117 | 118 | 119 | -------------------------------------------------------------------------------- /docs/events.md: -------------------------------------------------------------------------------- 1 | ## Selectize API – Events 2 | 3 | In the [usage documentation](usage.md), a few callbacks are listed that 4 | allow you to listen for certain events. Callbacks aren't always ideal though; 5 | specifically when you wish to have multiple handlers. 6 | 7 | Selectize instances have a basic event emitter interface that mimics jQuery, Backbone.js, et al: 8 | 9 | ```js 10 | var handler = function() { /* ... */ }; 11 | selectize.on('event_name', handler); 12 | selectize.off('event_name'); 13 | selectize.off('event_name', handler); 14 | ``` 15 | 16 | ### List of Events 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 |
EventParamsDescription
"initialize"Invoked once the control is completely initialized.
"change"valueInvoked when the value of the control changes.
"focus"Invoked when the control gains focus.
"blur"Invoked when the control loses focus.
"item_add"value, $itemInvoked when an item is selected.
"item_remove"value, $itemInvoked when an item is deselected.
"clear"Invoked when the control is manually cleared via the clear() method.
"option_add"value, dataInvoked when a new option is added to the available options list.
"option_remove"valueInvoked when an option is removed from the available options.
"option_clear"Invoked when all options are removed from the control.
"optgroup_add"id, dataInvoked when a new option is added to the available options list.
"optgroup_remove"idInvoked when an option group is removed.
"optgroup_clear"Invoked when all option groups are removed.
"dropdown_open"$dropdownInvoked when the dropdown opens.
"dropdown_close"$dropdownInvoked when the dropdown closes.
"type"strInvoked when the user types while filtering options.
"load"dataInvoked when new options have been loaded and added to the control (via the load option or load API method).
"destroy"Invoked right before the control is destroyed.
115 | -------------------------------------------------------------------------------- /examples/events.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Selectize.js Demo 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 |

Selectize.js Demos

22 |
23 |

Events

24 |

Check out the console for more details about each event.

25 |
26 | 27 | 81 |
82 |

Event Log

83 |

 84 | 				

Source

85 | 106 |
107 |
108 | 109 | 110 | -------------------------------------------------------------------------------- /examples/github.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Selectize.js Demo 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 94 | 95 | 96 |
97 |

Selectize.js

98 |
99 |

Loading + Custom Scoring

100 |

This demo shows how to integrate third-party data and override the scoring method.

101 |
102 | 103 | 104 |
105 | 150 |
151 |
152 | 153 | 154 | -------------------------------------------------------------------------------- /src/selectize.jquery.js: -------------------------------------------------------------------------------- 1 | $.fn.selectize = function(settings_user) { 2 | var defaults = $.fn.selectize.defaults; 3 | var settings = $.extend({}, defaults, settings_user); 4 | var attr_data = settings.dataAttr; 5 | var field_label = settings.labelField; 6 | var field_value = settings.valueField; 7 | var field_disabled = settings.disabledField; 8 | var field_optgroup = settings.optgroupField; 9 | var field_optgroup_label = settings.optgroupLabelField; 10 | var field_optgroup_value = settings.optgroupValueField; 11 | 12 | /** 13 | * Initializes selectize from a element. 14 | * 15 | * @param {object} $input 16 | * @param {object} settings_element 17 | */ 18 | var init_textbox = function($input, settings_element) { 19 | var i, n, values, option; 20 | 21 | var data_raw = $input.attr(attr_data); 22 | 23 | if (!data_raw) { 24 | var value = $.trim($input.val() || ''); 25 | if (!settings.allowEmptyOption && !value.length) return; 26 | values = value.split(settings.delimiter); 27 | for (i = 0, n = values.length; i < n; i++) { 28 | option = {}; 29 | option[field_label] = values[i]; 30 | option[field_value] = values[i]; 31 | settings_element.options.push(option); 32 | } 33 | settings_element.items = values; 34 | } else { 35 | settings_element.options = JSON.parse(data_raw); 36 | for (i = 0, n = settings_element.options.length; i < n; i++) { 37 | settings_element.items.push(settings_element.options[i][field_value]); 38 | } 39 | } 40 | }; 41 | 42 | /** 43 | * Initializes selectize from a 113 | 114 | 161 | 162 | 163 | 164 | 165 | -------------------------------------------------------------------------------- /examples/cities.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Selectize.js Demo 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 38 | 39 | 40 |
41 |

Selectize.js

42 |
43 |

State / City Selection

44 |

A demonstration showing how to use the API to cascade controls for a classic state / city selector.

45 |

Note: The API for fetching cities is a little spotty, so if it fails to list cities, that's the problem.

46 |
47 | 48 | 102 | 103 | 104 |
105 | 142 |
143 |
144 | 145 | 146 | -------------------------------------------------------------------------------- /dist/less/selectize.bootstrap2.less: -------------------------------------------------------------------------------- 1 | /** 2 | * selectize.bootstrap2.css (v0.12.4) - Bootstrap 2 Theme 3 | * Copyright (c) 2013–2015 Brian Reavis & contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this 6 | * file except in compliance with the License. You may obtain a copy of the License at: 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under 10 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 11 | * ANY KIND, either express or implied. See the License for the specific language 12 | * governing permissions and limitations under the License. 13 | * 14 | * @author Brian Reavis 15 | */ 16 | 17 | @import "selectize"; 18 | 19 | @selectize-font-family: @baseFontFamily; 20 | @selectize-font-size: @baseFontSize; 21 | @selectize-line-height: @baseLineHeight; 22 | 23 | @selectize-color-text: @textColor; 24 | @selectize-color-highlight: rgba(255,237,40,0.4); 25 | @selectize-color-input: @inputBackground; 26 | @selectize-color-input-full: @inputBackground; 27 | @selectize-color-disabled: @inputBackground; 28 | @selectize-color-item: @btnBackgroundHighlight; 29 | @selectize-color-item-border: @btnBorder; 30 | @selectize-color-item-active: @dropdownLinkBackgroundHover; 31 | @selectize-color-item-active-text: @dropdownLinkColorHover; 32 | @selectize-color-item-active-border: darken(@selectize-color-item-active, 5%); 33 | @selectize-color-optgroup: @dropdownBackground; 34 | @selectize-color-optgroup-text: @grayLight; 35 | @selectize-color-optgroup-border: @dropdownDividerTop; 36 | @selectize-color-dropdown: @dropdownBackground; 37 | @selectize-color-dropdown-border: @inputBorder; 38 | @selectize-color-dropdown-border-top: @dropdownDividerTop; 39 | @selectize-color-dropdown-item-active: @dropdownLinkBackgroundHover; 40 | @selectize-color-dropdown-item-active-text: @dropdownLinkColorHover; 41 | @selectize-color-dropdown-item-create-active-text: @dropdownLinkColorHover; 42 | @selectize-lighten-disabled-item: 8%; 43 | @selectize-lighten-disabled-item-text: 8%; 44 | @selectize-lighten-disabled-item-border: 8%; 45 | @selectize-opacity-disabled: 0.5; 46 | @selectize-shadow-input: none; 47 | @selectize-shadow-input-focus: inset 0 1px 2px rgba(0,0,0,0.15); 48 | @selectize-border-radius: @inputBorderRadius; 49 | 50 | @selectize-padding-x: 10px; 51 | @selectize-padding-y: 7px; 52 | @selectize-padding-dropdown-item-x: @selectize-padding-x; 53 | @selectize-padding-dropdown-item-y: 3px; 54 | @selectize-padding-item-x: 3px; 55 | @selectize-padding-item-y: 1px; 56 | @selectize-margin-item-x: 3px; 57 | @selectize-margin-item-y: 3px; 58 | @selectize-caret-margin: 0; 59 | 60 | @selectize-arrow-size: 5px; 61 | @selectize-arrow-color: @black; 62 | @selectize-arrow-offset: @selectize-padding-x + 5px; 63 | 64 | @selectize-width-item-border: 1px; 65 | 66 | .selectize-dropdown { 67 | margin: 2px 0 0 0; 68 | z-index: @zindexDropdown; 69 | border: 1px solid @dropdownBorder; 70 | border-radius: @baseBorderRadius; 71 | .box-shadow(0 5px 10px rgba(0,0,0,.2)); 72 | 73 | .optgroup-header { 74 | font-size: 11px; 75 | font-weight: bold; 76 | text-shadow: 0 1px 0 rgba(255,255,255,.5); 77 | text-transform: uppercase; 78 | } 79 | .optgroup:first-child:before { 80 | display: none; 81 | } 82 | .optgroup:before { 83 | content: ' '; 84 | display: block; 85 | .nav-divider(); 86 | margin-left: @selectize-padding-dropdown-item-x * -1; 87 | margin-right: @selectize-padding-dropdown-item-x * -1; 88 | } 89 | 90 | [data-selectable].active { 91 | #gradient > .vertical(@dropdownLinkBackgroundHover, darken(@dropdownLinkBackgroundHover, 5%)); 92 | } 93 | } 94 | 95 | .selectize-dropdown-content { 96 | padding: 5px 0; 97 | } 98 | 99 | .selectize-dropdown-header { 100 | padding: @selectize-padding-dropdown-item-y * 2 @selectize-padding-dropdown-item-x; 101 | } 102 | 103 | .selectize-input { 104 | .transition(~"border linear .2s, box-shadow linear .2s"); 105 | 106 | &.dropdown-active { 107 | .selectize-border-radius(@selectize-border-radius); 108 | } 109 | &.dropdown-active::before { 110 | display: none; 111 | } 112 | &.input-active, &.input-active:hover, .selectize-control.multi &.focus { 113 | background: @selectize-color-input !important; 114 | border-color: rgba(82,168,236,.8) !important; 115 | outline: 0 !important; 116 | outline: thin dotted \9 !important; 117 | .box-shadow(~"inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6)") !important; 118 | } 119 | } 120 | 121 | .selectize-control { 122 | &.single { 123 | .selectize-input { 124 | .buttonBackground(@btnBackground, @btnBackgroundHighlight, @grayDark, 0 1px 1px rgba(255,255,255,.75)); 125 | .box-shadow(~"inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05)"); 126 | &:hover { 127 | color: @grayDark; 128 | text-decoration: none; 129 | background-position: 0 -15px; 130 | .transition(background-position .1s linear); 131 | } 132 | &.disabled { 133 | background: @btnBackgroundHighlight !important; 134 | .box-shadow(none); 135 | } 136 | } 137 | } 138 | &.multi { 139 | .selectize-input { 140 | .box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); 141 | &.has-items { 142 | @padding-x: @selectize-padding-x - @selectize-padding-item-x; 143 | padding-left: @padding-x; 144 | padding-right: @padding-x; 145 | } 146 | } 147 | .selectize-input > div { 148 | .gradientBar(@btnBackground, @btnBackgroundHighlight, @selectize-color-item-text, none); 149 | *background-color: @selectize-color-item; 150 | border: @selectize-width-item-border solid @selectize-color-item-border; 151 | .border-radius(@baseBorderRadius); 152 | .box-shadow(~"inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05)"); 153 | &.active { 154 | .box-shadow(~"0 1px 2px rgba(0,0,0,.05)"); 155 | .gradientBar(@selectize-color-item-active, @selectize-color-item-active-border, @selectize-color-item-active-text, none); 156 | *background-color: @selectize-color-item-active; 157 | border: @selectize-width-item-border solid @dropdownLinkBackgroundHover; 158 | } 159 | } 160 | } 161 | } -------------------------------------------------------------------------------- /src/less/selectize.bootstrap2.less: -------------------------------------------------------------------------------- 1 | /** 2 | * selectize.bootstrap2.css (v@@version) - Bootstrap 2 Theme 3 | * Copyright (c) 2013–2015 Brian Reavis & contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this 6 | * file except in compliance with the License. You may obtain a copy of the License at: 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under 10 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 11 | * ANY KIND, either express or implied. See the License for the specific language 12 | * governing permissions and limitations under the License. 13 | * 14 | * @author Brian Reavis 15 | */ 16 | 17 | @import "selectize"; 18 | 19 | @selectize-font-family: @baseFontFamily; 20 | @selectize-font-size: @baseFontSize; 21 | @selectize-line-height: @baseLineHeight; 22 | 23 | @selectize-color-text: @textColor; 24 | @selectize-color-highlight: rgba(255,237,40,0.4); 25 | @selectize-color-input: @inputBackground; 26 | @selectize-color-input-full: @inputBackground; 27 | @selectize-color-disabled: @inputBackground; 28 | @selectize-color-item: @btnBackgroundHighlight; 29 | @selectize-color-item-border: @btnBorder; 30 | @selectize-color-item-active: @dropdownLinkBackgroundHover; 31 | @selectize-color-item-active-text: @dropdownLinkColorHover; 32 | @selectize-color-item-active-border: darken(@selectize-color-item-active, 5%); 33 | @selectize-color-optgroup: @dropdownBackground; 34 | @selectize-color-optgroup-text: @grayLight; 35 | @selectize-color-optgroup-border: @dropdownDividerTop; 36 | @selectize-color-dropdown: @dropdownBackground; 37 | @selectize-color-dropdown-border: @inputBorder; 38 | @selectize-color-dropdown-border-top: @dropdownDividerTop; 39 | @selectize-color-dropdown-item-active: @dropdownLinkBackgroundHover; 40 | @selectize-color-dropdown-item-active-text: @dropdownLinkColorHover; 41 | @selectize-color-dropdown-item-create-active-text: @dropdownLinkColorHover; 42 | @selectize-lighten-disabled-item: 8%; 43 | @selectize-lighten-disabled-item-text: 8%; 44 | @selectize-lighten-disabled-item-border: 8%; 45 | @selectize-opacity-disabled: 0.5; 46 | @selectize-shadow-input: none; 47 | @selectize-shadow-input-focus: inset 0 1px 2px rgba(0,0,0,0.15); 48 | @selectize-border-radius: @inputBorderRadius; 49 | 50 | @selectize-padding-x: 10px; 51 | @selectize-padding-y: 7px; 52 | @selectize-padding-dropdown-item-x: @selectize-padding-x; 53 | @selectize-padding-dropdown-item-y: 3px; 54 | @selectize-padding-item-x: 3px; 55 | @selectize-padding-item-y: 1px; 56 | @selectize-margin-item-x: 3px; 57 | @selectize-margin-item-y: 3px; 58 | @selectize-caret-margin: 0; 59 | 60 | @selectize-arrow-size: 5px; 61 | @selectize-arrow-color: @black; 62 | @selectize-arrow-offset: @selectize-padding-x + 5px; 63 | 64 | @selectize-width-item-border: 1px; 65 | 66 | .selectize-dropdown { 67 | margin: 2px 0 0 0; 68 | z-index: @zindexDropdown; 69 | border: 1px solid @dropdownBorder; 70 | border-radius: @baseBorderRadius; 71 | .box-shadow(0 5px 10px rgba(0,0,0,.2)); 72 | 73 | .optgroup-header { 74 | font-size: 11px; 75 | font-weight: bold; 76 | text-shadow: 0 1px 0 rgba(255,255,255,.5); 77 | text-transform: uppercase; 78 | } 79 | .optgroup:first-child:before { 80 | display: none; 81 | } 82 | .optgroup:before { 83 | content: ' '; 84 | display: block; 85 | .nav-divider(); 86 | margin-left: @selectize-padding-dropdown-item-x * -1; 87 | margin-right: @selectize-padding-dropdown-item-x * -1; 88 | } 89 | 90 | [data-selectable].active { 91 | #gradient > .vertical(@dropdownLinkBackgroundHover, darken(@dropdownLinkBackgroundHover, 5%)); 92 | } 93 | } 94 | 95 | .selectize-dropdown-content { 96 | padding: 5px 0; 97 | } 98 | 99 | .selectize-dropdown-header { 100 | padding: @selectize-padding-dropdown-item-y * 2 @selectize-padding-dropdown-item-x; 101 | } 102 | 103 | .selectize-input { 104 | .transition(~"border linear .2s, box-shadow linear .2s"); 105 | 106 | &.dropdown-active { 107 | .selectize-border-radius(@selectize-border-radius); 108 | } 109 | &.dropdown-active::before { 110 | display: none; 111 | } 112 | &.input-active, &.input-active:hover, .selectize-control.multi &.focus { 113 | background: @selectize-color-input !important; 114 | border-color: rgba(82,168,236,.8) !important; 115 | outline: 0 !important; 116 | outline: thin dotted \9 !important; 117 | .box-shadow(~"inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6)") !important; 118 | } 119 | } 120 | 121 | .selectize-control { 122 | &.single { 123 | .selectize-input { 124 | .buttonBackground(@btnBackground, @btnBackgroundHighlight, @grayDark, 0 1px 1px rgba(255,255,255,.75)); 125 | .box-shadow(~"inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05)"); 126 | &:hover { 127 | color: @grayDark; 128 | text-decoration: none; 129 | background-position: 0 -15px; 130 | .transition(background-position .1s linear); 131 | } 132 | &.disabled { 133 | background: @btnBackgroundHighlight !important; 134 | .box-shadow(none); 135 | } 136 | } 137 | } 138 | &.multi { 139 | .selectize-input { 140 | .box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); 141 | &.has-items { 142 | @padding-x: @selectize-padding-x - @selectize-padding-item-x; 143 | padding-left: @padding-x; 144 | padding-right: @padding-x; 145 | } 146 | } 147 | .selectize-input > div { 148 | .gradientBar(@btnBackground, @btnBackgroundHighlight, @selectize-color-item-text, none); 149 | *background-color: @selectize-color-item; 150 | border: @selectize-width-item-border solid @selectize-color-item-border; 151 | .border-radius(@baseBorderRadius); 152 | .box-shadow(~"inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05)"); 153 | &.active { 154 | .box-shadow(~"0 1px 2px rgba(0,0,0,.05)"); 155 | .gradientBar(@selectize-color-item-active, @selectize-color-item-active-border, @selectize-color-item-active-text, none); 156 | *background-color: @selectize-color-item-active; 157 | border: @selectize-width-item-border solid @dropdownLinkBackgroundHover; 158 | } 159 | } 160 | } 161 | } -------------------------------------------------------------------------------- /examples/contacts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Selectize.js Demo 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 71 | 72 | 73 |
74 |

Selectize.js

75 |
76 |

Email Contacts

77 |

An example showing how you might go about creating contact selector like those used in Email apps.

78 |
79 | 80 | 81 |
82 | 152 |
153 |
154 | 155 | 156 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | 3 | module.exports = function(grunt) { 4 | grunt.loadNpmTasks('grunt-bower-task'); 5 | grunt.loadNpmTasks('grunt-contrib-uglify'); 6 | grunt.loadNpmTasks('grunt-contrib-concat'); 7 | grunt.loadNpmTasks('grunt-contrib-clean'); 8 | grunt.loadNpmTasks('grunt-contrib-connect'); 9 | grunt.loadNpmTasks('grunt-contrib-copy'); 10 | grunt.loadNpmTasks('grunt-contrib-less'); 11 | grunt.loadNpmTasks('grunt-contrib-watch'); 12 | grunt.loadNpmTasks('grunt-replace'); 13 | 14 | grunt.registerTask('configure', [ 15 | 'clean:pre', 16 | 'bower:install', 17 | ]); 18 | 19 | grunt.registerTask('compile', [ 20 | 'copy:less', 21 | 'copy:less_plugins', 22 | 'concat:less_theme_dependencies', 23 | 'concat:less_plugins', 24 | 'concat:js', 25 | 'less:uncompressed', 26 | 'clean_bootstrap2_css', 27 | 'replace', 28 | 'build_standalone', 29 | 'uglify', 30 | 'clean:post', 31 | ]); 32 | 33 | grunt.registerTask('default', [ 34 | 'configure', 35 | 'compile' 36 | ]); 37 | 38 | grunt.registerTask('serve', [ 39 | 'connect', 40 | 'watch' 41 | ]) 42 | 43 | grunt.registerTask('clean_bootstrap2_css', 'Cleans CSS rules ocurring before the header comment.', function() { 44 | var file = 'dist/css/selectize.bootstrap2.css'; 45 | var source = fs.readFileSync(file, 'utf8'); 46 | grunt.file.write(file, source.replace(/^(.|\s)+?\/\*/m, '/*')); 47 | grunt.log.writeln('Cleaned "' + file + '".'); 48 | }); 49 | 50 | grunt.registerTask('build_standalone', '', function() { 51 | var files, i, n, source, name, path, modules = []; 52 | 53 | // amd definitions must be changed to be not anonymous 54 | // @see https://github.com/brianreavis/selectize.js/issues/89 55 | files = []; 56 | for (i = 0, n = files_js_dependencies.length; i < n; i++) { 57 | path = files_js_dependencies[i]; 58 | name = path.match(/([^\/]+?).js$/)[1]; 59 | source = grunt.file.read(path).replace('define(factory);', 'define(\'' + name + '\', factory);'); 60 | modules.push(source); 61 | } 62 | 63 | path = 'dist/js/selectize.js'; 64 | source = grunt.file.read(path).replace(/define\((.*?)factory\);/, 'define(\'selectize\', $1factory);'); 65 | modules.push(source); 66 | 67 | // write output 68 | path = 'dist/js/standalone/selectize.js'; 69 | grunt.file.write(path, modules.join('\n\n')); 70 | grunt.log.writeln('Built "' + path + '".'); 71 | }); 72 | 73 | var files_js = [ 74 | 'src/contrib/*.js', 75 | 'src/*.js', 76 | '!src/.wrapper.js', 77 | '!src/defaults.js', 78 | '!src/selectize.js', 79 | '!src/selectize.jquery.js', 80 | 'src/selectize.js', 81 | 'src/defaults.js', 82 | 'src/selectize.jquery.js', 83 | ]; 84 | 85 | var files_js_dependencies = [ 86 | 'node_modules/sifter/sifter.js', 87 | 'node_modules/microplugin/src/microplugin.js', 88 | ]; 89 | 90 | var less_imports = []; 91 | var less_plugin_files = []; 92 | 93 | // enumerate plugins 94 | (function() { 95 | var selector_plugins = grunt.option('plugins'); 96 | if (!selector_plugins) return; 97 | 98 | if (selector_plugins.indexOf(',') !== -1) { 99 | selector_plugins = '{' + selector_plugins.split(/\s*,\s*/).join(',') + '}'; 100 | } 101 | 102 | // javascript 103 | files_js.push('src/plugins/' + selector_plugins + '/*.js'); 104 | 105 | // less (css) 106 | var matched_files = grunt.file.expand(['src/plugins/' + selector_plugins + '/plugin.less']); 107 | for (var i = 0, n = matched_files.length; i < n; i++) { 108 | var plugin_name = matched_files[i].match(/src\/plugins\/(.+?)\//)[1]; 109 | less_imports.push('@import "plugins/' + plugin_name + '";'); 110 | less_plugin_files.push({src: matched_files[i], dest: 'dist/less/plugins/' + plugin_name + '.less'}); 111 | } 112 | })(); 113 | 114 | grunt.initConfig({ 115 | pkg: grunt.file.readJSON('package.json'), 116 | bower: { 117 | install: { 118 | options: { 119 | copy: false, 120 | clean: false, 121 | layout: 'byComponent', 122 | action: 'install' 123 | } 124 | } 125 | }, 126 | clean: { 127 | pre: ['dist'], 128 | post: ['**/*.tmp*'] 129 | }, 130 | copy: { 131 | less: { 132 | files: [{expand: true, flatten: true, src: ['src/less/*.less'], dest: 'dist/less'}] 133 | }, 134 | less_plugins: { 135 | files: less_plugin_files 136 | } 137 | }, 138 | replace: { 139 | options: {prefix: '@@'}, 140 | main: { 141 | options: { 142 | variables: { 143 | 'version': '<%= pkg.version %>', 144 | 'js': '<%= grunt.file.read("dist/js/selectize.js").replace(/\\n/g, "\\n\\t") %>', 145 | 'css': '<%= grunt.file.read("dist/css/selectize.css") %>', 146 | }, 147 | }, 148 | files: [ 149 | {src: ['src/.wrapper.js'], dest: 'dist/js/selectize.js'}, 150 | {src: ['src/less/.wrapper.css'], dest: 'dist/css/selectize.css'} 151 | ] 152 | }, 153 | css_post: { 154 | options: { 155 | variables: { 156 | 'version': '<%= pkg.version %>' 157 | }, 158 | }, 159 | files: [ 160 | {expand: true, flatten: false, src: ['dist/css/*.css'], dest: ''}, 161 | {expand: true, flatten: false, src: ['dist/less/*.less'], dest: ''}, 162 | {expand: true, flatten: false, src: ['dist/less/plugins/*.less'], dest: ''}, 163 | ] 164 | } 165 | }, 166 | less: { 167 | options: {}, 168 | uncompressed: { 169 | files: { 170 | 'dist/css/selectize.css': ['dist/less/selectize.less'], 171 | 'dist/css/selectize.default.css': ['dist/less/selectize.default.less'], 172 | 'dist/css/selectize.legacy.css': ['dist/less/selectize.legacy.less'], 173 | 'dist/css/selectize.bootstrap2.css': ['dist/less/selectize.bootstrap2.tmp.less'], 174 | 'dist/css/selectize.bootstrap3.css': ['dist/less/selectize.bootstrap3.tmp.less'] 175 | } 176 | } 177 | }, 178 | concat: { 179 | options: { 180 | stripBanners: true, 181 | separator: grunt.util.linefeed + grunt.util.linefeed 182 | }, 183 | js: { 184 | files: { 185 | 'dist/js/selectize.js': files_js, 186 | } 187 | }, 188 | less_plugins: { 189 | options: { 190 | banner: less_imports.join('\n') + grunt.util.linefeed + grunt.util.linefeed 191 | }, 192 | files: { 193 | 'dist/less/selectize.less': ['dist/less/selectize.less'] 194 | } 195 | }, 196 | less_theme_dependencies: { 197 | options: {stripBanners: false}, 198 | files: { 199 | 'dist/less/selectize.bootstrap2.tmp.less': [ 200 | 'bower_components/bootstrap2/less/variables.less', 201 | 'bower_components/bootstrap2/less/mixins.less', 202 | 'dist/less/selectize.bootstrap2.less' 203 | ], 204 | 'dist/less/selectize.bootstrap3.tmp.less': [ 205 | 'bower_components/bootstrap3/less/variables.less', 206 | 'bower_components/bootstrap3/less/mixins/nav-divider.less', 207 | 'dist/less/selectize.bootstrap3.less' 208 | ] 209 | } 210 | } 211 | }, 212 | connect: { 213 | keepalive: true 214 | }, 215 | uglify: { 216 | main: { 217 | options: { 218 | 'banner': '/*! selectize.js - v<%= pkg.version %> | https://github.com/selectize/selectize.js | Apache License (v2) */\n', 219 | 'report': 'gzip', 220 | 'ascii-only': true 221 | }, 222 | files: { 223 | 'dist/js/selectize.min.js': ['dist/js/selectize.js'], 224 | 'dist/js/standalone/selectize.min.js': ['dist/js/standalone/selectize.js'] 225 | } 226 | } 227 | }, 228 | watch: { 229 | files: [ 230 | 'src/**/*.js' 231 | ], 232 | tasks: [ 233 | 'concat:js', 234 | 'build_standalone' 235 | ] 236 | } 237 | }); 238 | }; 239 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | → Selectize is looking for [new members on the maintenance team](https://github.com/selectize/selectize.js/issues/752)! 2 | 3 | # selectize.js 4 | 5 | [![NPM version](http://img.shields.io/npm/v/selectize.svg?style=flat)](https://www.npmjs.org/package/selectize) 6 | [![CDNJS version](http://img.shields.io/cdnjs/v/selectize.js.svg?style=flat)](https://cdnjs.com/libraries/selectize.js) 7 | [![Build Status](http://img.shields.io/travis/selectize/selectize.js/master.svg?style=flat)](https://travis-ci.org/selectize/selectize.js) 8 | [![Coverage Status](http://img.shields.io/coveralls/selectize/selectize.js/master.svg?style=flat)](https://coveralls.io/r/selectize/selectize.js) 9 | 10 | Selectize is an extensible [jQuery](http://jquery.com/)-based custom <select> UI control. It's useful for tagging, contact lists, country selectors, and so on. It clocks in at around ~7kb (gzipped). The goal is to provide a solid & usable experience with a clean and powerful API. 11 | 12 | - [Demos](http://selectize.github.io/selectize.js/) 13 | - [Changelog](https://github.com/selectize/selectize.js/releases) 14 | - [Examples](examples/) 15 | - [Usage Documentation](docs/usage.md) 16 | - [API Documentation](docs/api.md) 17 | - [Plugin Documentation](docs/plugins.md) 18 | - [Browser Test Matrix](https://saucelabs.com/u/selectize) 19 | 20 | ### Features 21 | 22 | - **Smart Option Searching / Ranking**
Options are efficiently scored and sorted on-the-fly (using [sifter](https://github.com/brianreavis/sifter.js)). Want to search an item's title *and* description? No problem. 23 | - **Caret between items**
Order matters sometimes. Use the and arrow keys to move between selected items. 24 | - **Select & delete multiple items at once**
Hold down option on Mac or ctrl on Windows to select more than one item to delete. 25 | - **Díåcritîçs supported**
Great for international environments. 26 | - **Item creation**
Allow users to create items on the fly (async saving is supported; the control locks until the callback is fired). 27 | - **Remote data loading**
For when you have thousands of options and want them provided by the server as the user types. 28 | - **Clean API & code**
Interface with it and make modifications easily. Pull requests welcome! 29 | - **Extensible**
[Plugin API](docs/plugins.md) for developing custom features (uses [microplugin](https://github.com/brianreavis/microplugin.js)). 30 | - **Touch Support**
Plays nice with iOS 5+ devices. 31 | 32 | ### Dependencies 33 | 34 | - [jquery](https://github.com/jquery/jquery) (1.7 and greater) 35 | - [sifter](https://github.com/brianreavis/sifter.js) (bundled in ["standalone" build](dist/js/standalone)) 36 | - [microplugin](https://github.com/brianreavis/microplugin.js) (bundled in ["standalone" build](dist/js/standalone)) 37 | 38 | ### Installation and files 39 | 40 | All pre-built files needed to use Selectize can be found in the 41 | ["dist"](dist/) folder. 42 | 43 | If you're looking to get started with minimal fuss, include 44 | `standalone/selectize.min.js` (bundles Sifter and Microplugin 45 | dependencies – also available un-minifed for debugging, just remove the 46 | `.min` part) and `css/selectize.default.css`. 47 | 48 | Selectize is available at [cdnjs](https://cdnjs.com/libraries/selectize.js). 49 | 50 | - [**js/**](dist/js) 51 | - [**standalone/**](dist/js/standalone) 52 | - [selectize.js](dist/js/standalone/selectize.js) — With dependencies, minus jquery 53 | - [selectize.js](dist/js/selectize.js) — Without dependencies 54 | - [**less/**](dist/less) 55 | - [selectize.less](dist/less/selectize.less) — Core styles 56 | - [selectize.default.less](dist/less/selectize.default.less) — Default theme 57 | - [selectize.bootstrap2.less](dist/less/selectize.bootstrap2.less) — Bootstrap 2 theme 58 | - [selectize.bootstrap3.less](dist/less/selectize.bootstrap3.less) — Bootstrap 3 theme 59 | - [**plugins/**](dist/less/plugins) — Individual plugin styles 60 | - [**css/**](dist/css) 61 | - [selectize.css](dist/css/selectize.css) — Core styles 62 | - [selectize.default.css](dist/css/selectize.default.css) — Default theme (with core styles) 63 | - [selectize.bootstrap2.css](dist/css/selectize.bootstrap2.css) - Bootstrap 2 theme 64 | - [selectize.bootstrap3.css](dist/css/selectize.bootstrap3.css) - Bootstrap 3 theme 65 | 66 | ### Usage 67 | 68 | ```js 69 | $('select').selectize(options); 70 | ``` 71 | 72 | The available options are [documented here](docs/usage.md). 73 | 74 | #### IE8 Support 75 | 76 | To support Internet Explorer 8, [es5-shim](https://github.com/kriskowal/es5-shim/) must be added your page. 77 | 78 | ```html 79 | 80 | ``` 81 | 82 | ### Custom Builds 83 | 84 | By default, all [plugins](src/plugins) are included. To hand-pick what plugins (if any) to include, run [`grunt`](http://gruntjs.com/) with the "--plugins" flag. After this completes, grab the files you need from the ["dist"](dist) folder. 85 | 86 | ```sh 87 | # dependencies 88 | npm install 89 | 90 | # build selectize 91 | grunt --plugins= 92 | grunt --plugins=* 93 | grunt --plugins=remove_button,restore_on_backspace 94 | ``` 95 | 96 | ### Contributing 97 | When issuing a pull request: 98 | 99 | * please **do not include/commit changes in the `dist/` folder** to avoid 100 | merge conflicts. A good way to include the right files is to use 101 | `git gui` or `git add` when committing to select the files you want to 102 | add to your commit. 103 | 104 | * please **include tests** with your feature so that we're not tempted to 105 | break it in the future! 106 | 107 | Add an entry to the top of the CHANGELOG, and update the documentation 108 | in `docs/` as needed. (Refactors and documentation changes don't need a 109 | changelog entry.) 110 | 111 | Squash your commits together in one or a few complete, logical commits, 112 | with a concise and descriptive message. One commit means one 113 | feature/bugfix/thing that has changed, or a diff bringing the code one 114 | step forward to a better, working state. 115 | 116 | Once your commit is nice and clean, and you want to *discard the other 117 | changes*, you can use `git checkout .` (that will erase changes to 118 | tracked files) and `git clean [-i/--interactive]` (to erase untracked 119 | files). **However, be careful with those commands, as their function 120 | is to erase things/changes.** 121 | 122 | 123 | #### Tests 124 | Please ensure all the tests pass: 125 | 126 | ```sh 127 | $ npm test # phantomjs 128 | $ BROWSERS=Firefox npm test 129 | $ BROWSERS=Firefox,Chrome npm test 130 | $ BROWSERS=Firefox,Chrome,Safari npm test 131 | ``` 132 | 133 | #### Local environment 134 | To run Selectize locally: 135 | 136 | ```sh 137 | $ npm start 138 | ``` 139 | 140 | You can then run the examples in `http://localhost:8000/examples/`. 141 | 142 | However, be careful not to add the `dist/` files in your commit, as 143 | Grunt automatically regenerates the files in `dist/` as the source is 144 | changed. 145 | 146 | ## License 147 | 148 | Copyright © 2013–2016 [Brian Reavis](http://twitter.com/brianreavis) & [Contributors](https://github.com/selectize/selectize.js/graphs/contributors) 149 | 150 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0 151 | 152 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 153 | -------------------------------------------------------------------------------- /examples/optgroups.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Selectize.js Demo 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 31 | 32 | 33 |
34 |

Selectize.js

35 | 36 |
37 |

Optgroups (basic)

38 |
39 | 40 | 56 |
57 | 62 |
63 | 64 |
65 |

Optgroups (disabled)

66 |
67 | 68 | 84 |
85 | 90 |
91 | 92 |
93 |

Optgroups (repeated options)

94 |
95 | 96 | 107 |
108 | 113 |
114 | 115 |
116 |

Optgroups (programmatic)

117 |
118 | 119 | 120 |
121 | 152 |
153 | 154 |
155 |

Plugin: "optgroup_columns"

156 |
157 | 158 |
159 | 199 |
200 |
201 | 202 | 203 | -------------------------------------------------------------------------------- /examples/js/es5.js: -------------------------------------------------------------------------------- 1 | (function(o){"function"==typeof define?define(o):"function"==typeof YUI?YUI.add("es5",o):o()})(function(){function o(){}function v(a){a=+a;a!==a?a=0:0!==a&&(a!==1/0&&a!==-(1/0))&&(a=(0>>0;if(h(a)!="[object Function]")throw new TypeError;for(;++e>>0,f=Array(e);if(h(a)!="[object Function]")throw new TypeError(a+" is not a function");for(var g=0;g>>0,f=[],g;if(h(a)!="[object Function]")throw new TypeError(a+" is not a function");for(var i=0;i>>0;if(h(a)!="[object Function]")throw new TypeError(a+" is not a function");for(var f=0;f>>0;if(h(a)!="[object Function]")throw new TypeError(a+" is not a function");for(var f=0;f>>0;if(h(a)!="[object Function]")throw new TypeError(a+ 7 | " is not a function");if(!c&&arguments.length==1)throw new TypeError("reduce of empty array with no initial value");var e=0,f;if(arguments.length>=2)f=arguments[1];else{do{if(e in d){f=d[e++];break}if(++e>=c)throw new TypeError("reduce of empty array with no initial value");}while(1)}for(;e>>0;if(h(a)!= 8 | "[object Function]")throw new TypeError(a+" is not a function");if(!c&&arguments.length==1)throw new TypeError("reduceRight of empty array with no initial value");var e,c=c-1;if(arguments.length>=2)e=arguments[1];else{do{if(c in d){e=d[c--];break}if(--c<0)throw new TypeError("reduceRight of empty array with no initial value");}while(1)}do c in this&&(e=a.call(void 0,e,d[c],c,b));while(c--);return e});if(!Array.prototype.indexOf||-1!=[0,1].indexOf(1,2))Array.prototype.indexOf=function(a){var b=l&& 9 | h(this)=="[object String]"?this.split(""):n(this),d=b.length>>>0;if(!d)return-1;var c=0;arguments.length>1&&(c=v(arguments[1]));for(c=c>=0?c:Math.max(0,d+c);c>>0;if(!d)return-1;var c=d-1;arguments.length>1&&(c=Math.min(c,v(arguments[1])));for(c=c>=0?c:d-Math.abs(c);c>=0;c--)if(c in b&& 10 | a===b[c])return c;return-1};if(!Object.keys){var w=!0,x="toString toLocaleString valueOf hasOwnProperty isPrototypeOf propertyIsEnumerable constructor".split(" "),A=x.length,r;for(r in{toString:null})w=!1;Object.keys=function(a){if(typeof a!="object"&&typeof a!="function"||a===null)throw new TypeError("Object.keys called on a non-object");var b=[],d;for(d in a)t(a,d)&&b.push(d);if(w)for(d=0;d9999?"+":"")+("00000"+Math.abs(c)).slice(0<=c&&c<=9999?-4:-6);for(b=a.length;b--;){d=a[b];d<10&&(a[b]="0"+d)}return c+"-"+a.slice(0,2).join("-")+"T"+a.slice(2).join(":")+"."+("000"+this.getUTCMilliseconds()).slice(-3)+ 12 | "Z"};r=!1;try{r=Date.prototype.toJSON&&null===(new Date(NaN)).toJSON()&&-1!==(new Date(-621987552E5)).toJSON().indexOf("-000001")&&Date.prototype.toJSON.call({toISOString:function(){return true}})}catch(H){}r||(Date.prototype.toJSON=function(){var a=Object(this),b;a:if(s(a))b=a;else{b=a.valueOf;if(typeof b==="function"){b=b.call(a);if(s(b))break a}b=a.toString;if(typeof b==="function"){b=b.call(a);if(s(b))break a}throw new TypeError;}if(typeof b==="number"&&!isFinite(b))return null;b=a.toISOString; 13 | if(typeof b!="function")throw new TypeError("toISOString property is not callable");return b.call(a)});var g=Date,m=function(a,b,d,c,e,f,h){var i=arguments.length;if(this instanceof g){i=i==1&&String(a)===a?new g(m.parse(a)):i>=7?new g(a,b,d,c,e,f,h):i>=6?new g(a,b,d,c,e,f):i>=5?new g(a,b,d,c,e):i>=4?new g(a,b,d,c):i>=3?new g(a,b,d):i>=2?new g(a,b):i>=1?new g(a):new g;i.constructor=m;return i}return g.apply(this,arguments)},u=function(a,b){var d=b>1?1:0;return B[b]+Math.floor((a-1969+d)/4)-Math.floor((a- 14 | 1901+d)/100)+Math.floor((a-1601+d)/400)+365*(a-1970)},C=RegExp("^(\\d{4}|[+-]\\d{6})(?:-(\\d{2})(?:-(\\d{2})(?:T(\\d{2}):(\\d{2})(?::(\\d{2})(?:\\.(\\d{3}))?)?(Z|(?:([-+])(\\d{2}):(\\d{2})))?)?)?)?$"),B=[0,31,59,90,120,151,181,212,243,273,304,334,365],j;for(j in g)m[j]=g[j];m.now=g.now;m.UTC=g.UTC;m.prototype=g.prototype;m.prototype.constructor=m;m.parse=function(a){var b=C.exec(a);if(b){var d=Number(b[1]),c=Number(b[2]||1)-1,e=Number(b[3]||1)-1,f=Number(b[4]||0),h=Number(b[5]||0),i=Number(b[6]|| 15 | 0),j=Number(b[7]||0),m=!b[4]||b[8]?0:Number(new g(1970,0)),k=b[9]==="-"?1:-1,l=Number(b[10]||0),b=Number(b[11]||0);if(f<(h>0||i>0||j>0?24:25)&&h<60&&i<60&&j<1E3&&c>-1&&c<12&&l<24&&b<60&&e>-1&&e 'str' 17 | * null -> '' 18 | * undefined -> '' 19 | * true -> '1' 20 | * false -> '0' 21 | * 0 -> '0' 22 | * 1 -> '1' 23 | * 24 | * @param {string} value 25 | * @returns {string|null} 26 | */ 27 | var hash_key = function(value) { 28 | if (typeof value === 'undefined' || value === null) return null; 29 | if (typeof value === 'boolean') return value ? '1' : '0'; 30 | return value + ''; 31 | }; 32 | 33 | /** 34 | * Escapes a string for use within HTML. 35 | * 36 | * @param {string} str 37 | * @returns {string} 38 | */ 39 | var escape_html = function(str) { 40 | return (str + '') 41 | .replace(/&/g, '&') 42 | .replace(//g, '>') 44 | .replace(/"/g, '"'); 45 | }; 46 | 47 | /** 48 | * Escapes "$" characters in replacement strings. 49 | * 50 | * @param {string} str 51 | * @returns {string} 52 | */ 53 | var escape_replace = function(str) { 54 | return (str + '').replace(/\$/g, '$$$$'); 55 | }; 56 | 57 | var hook = {}; 58 | 59 | /** 60 | * Wraps `method` on `self` so that `fn` 61 | * is invoked before the original method. 62 | * 63 | * @param {object} self 64 | * @param {string} method 65 | * @param {function} fn 66 | */ 67 | hook.before = function(self, method, fn) { 68 | var original = self[method]; 69 | self[method] = function() { 70 | fn.apply(self, arguments); 71 | return original.apply(self, arguments); 72 | }; 73 | }; 74 | 75 | /** 76 | * Wraps `method` on `self` so that `fn` 77 | * is invoked after the original method. 78 | * 79 | * @param {object} self 80 | * @param {string} method 81 | * @param {function} fn 82 | */ 83 | hook.after = function(self, method, fn) { 84 | var original = self[method]; 85 | self[method] = function() { 86 | var result = original.apply(self, arguments); 87 | fn.apply(self, arguments); 88 | return result; 89 | }; 90 | }; 91 | 92 | /** 93 | * Wraps `fn` so that it can only be invoked once. 94 | * 95 | * @param {function} fn 96 | * @returns {function} 97 | */ 98 | var once = function(fn) { 99 | var called = false; 100 | return function() { 101 | if (called) return; 102 | called = true; 103 | fn.apply(this, arguments); 104 | }; 105 | }; 106 | 107 | /** 108 | * Wraps `fn` so that it can only be called once 109 | * every `delay` milliseconds (invoked on the falling edge). 110 | * 111 | * @param {function} fn 112 | * @param {int} delay 113 | * @returns {function} 114 | */ 115 | var debounce = function(fn, delay) { 116 | var timeout; 117 | return function() { 118 | var self = this; 119 | var args = arguments; 120 | window.clearTimeout(timeout); 121 | timeout = window.setTimeout(function() { 122 | fn.apply(self, args); 123 | }, delay); 124 | }; 125 | }; 126 | 127 | /** 128 | * Debounce all fired events types listed in `types` 129 | * while executing the provided `fn`. 130 | * 131 | * @param {object} self 132 | * @param {array} types 133 | * @param {function} fn 134 | */ 135 | var debounce_events = function(self, types, fn) { 136 | var type; 137 | var trigger = self.trigger; 138 | var event_args = {}; 139 | 140 | // override trigger method 141 | self.trigger = function() { 142 | var type = arguments[0]; 143 | if (types.indexOf(type) !== -1) { 144 | event_args[type] = arguments; 145 | } else { 146 | return trigger.apply(self, arguments); 147 | } 148 | }; 149 | 150 | // invoke provided function 151 | fn.apply(self, []); 152 | self.trigger = trigger; 153 | 154 | // trigger queued events 155 | for (type in event_args) { 156 | if (event_args.hasOwnProperty(type)) { 157 | trigger.apply(self, event_args[type]); 158 | } 159 | } 160 | }; 161 | 162 | /** 163 | * A workaround for http://bugs.jquery.com/ticket/6696 164 | * 165 | * @param {object} $parent - Parent element to listen on. 166 | * @param {string} event - Event name. 167 | * @param {string} selector - Descendant selector to filter by. 168 | * @param {function} fn - Event handler. 169 | */ 170 | var watchChildEvent = function($parent, event, selector, fn) { 171 | $parent.on(event, selector, function(e) { 172 | var child = e.target; 173 | while (child && child.parentNode !== $parent[0]) { 174 | child = child.parentNode; 175 | } 176 | e.currentTarget = child; 177 | return fn.apply(this, [e]); 178 | }); 179 | }; 180 | 181 | /** 182 | * Determines the current selection within a text input control. 183 | * Returns an object containing: 184 | * - start 185 | * - length 186 | * 187 | * @param {object} input 188 | * @returns {object} 189 | */ 190 | var getSelection = function(input) { 191 | var result = {}; 192 | if ('selectionStart' in input) { 193 | result.start = input.selectionStart; 194 | result.length = input.selectionEnd - result.start; 195 | } else if (document.selection) { 196 | input.focus(); 197 | var sel = document.selection.createRange(); 198 | var selLen = document.selection.createRange().text.length; 199 | sel.moveStart('character', -input.value.length); 200 | result.start = sel.text.length - selLen; 201 | result.length = selLen; 202 | } 203 | return result; 204 | }; 205 | 206 | /** 207 | * Copies CSS properties from one element to another. 208 | * 209 | * @param {object} $from 210 | * @param {object} $to 211 | * @param {array} properties 212 | */ 213 | var transferStyles = function($from, $to, properties) { 214 | var i, n, styles = {}; 215 | if (properties) { 216 | for (i = 0, n = properties.length; i < n; i++) { 217 | styles[properties[i]] = $from.css(properties[i]); 218 | } 219 | } else { 220 | styles = $from.css(); 221 | } 222 | $to.css(styles); 223 | }; 224 | 225 | /** 226 | * Measures the width of a string within a 227 | * parent element (in pixels). 228 | * 229 | * @param {string} str 230 | * @param {object} $parent 231 | * @returns {int} 232 | */ 233 | var measureString = function(str, $parent) { 234 | if (!str) { 235 | return 0; 236 | } 237 | 238 | var $test = $('').css({ 239 | position: 'absolute', 240 | top: -99999, 241 | left: -99999, 242 | width: 'auto', 243 | padding: 0, 244 | whiteSpace: 'pre' 245 | }).text(str).appendTo('body'); 246 | 247 | transferStyles($parent, $test, [ 248 | 'letterSpacing', 249 | 'fontSize', 250 | 'fontFamily', 251 | 'fontWeight', 252 | 'textTransform' 253 | ]); 254 | 255 | var width = $test.width(); 256 | $test.remove(); 257 | 258 | return width; 259 | }; 260 | 261 | /** 262 | * Sets up an input to grow horizontally as the user 263 | * types. If the value is changed manually, you can 264 | * trigger the "update" handler to resize: 265 | * 266 | * $input.trigger('update'); 267 | * 268 | * @param {object} $input 269 | */ 270 | var autoGrow = function($input) { 271 | var currentWidth = null; 272 | 273 | var update = function(e, options) { 274 | var value, keyCode, printable, placeholder, width; 275 | var shift, character, selection; 276 | e = e || window.event || {}; 277 | options = options || {}; 278 | 279 | if (e.metaKey || e.altKey) return; 280 | if (!options.force && $input.data('grow') === false) return; 281 | 282 | value = $input.val(); 283 | if (e.type && e.type.toLowerCase() === 'keydown') { 284 | keyCode = e.keyCode; 285 | printable = ( 286 | (keyCode >= 48 && keyCode <= 57) || // 0-9 287 | (keyCode >= 65 && keyCode <= 90) || // a-z 288 | (keyCode >= 96 && keyCode <= 111) || // numpad 0-9, numeric operators 289 | (keyCode >= 186 && keyCode <= 222) || // semicolon, equal, comma, dash, etc. 290 | keyCode === 32 // space 291 | ); 292 | 293 | if (keyCode === KEY_DELETE || keyCode === KEY_BACKSPACE) { 294 | selection = getSelection($input[0]); 295 | if (selection.length) { 296 | value = value.substring(0, selection.start) + value.substring(selection.start + selection.length); 297 | } else if (keyCode === KEY_BACKSPACE && selection.start) { 298 | value = value.substring(0, selection.start - 1) + value.substring(selection.start + 1); 299 | } else if (keyCode === KEY_DELETE && typeof selection.start !== 'undefined') { 300 | value = value.substring(0, selection.start) + value.substring(selection.start + 1); 301 | } 302 | } else if (printable) { 303 | shift = e.shiftKey; 304 | character = String.fromCharCode(e.keyCode); 305 | if (shift) character = character.toUpperCase(); 306 | else character = character.toLowerCase(); 307 | value += character; 308 | } 309 | } 310 | 311 | placeholder = $input.attr('placeholder'); 312 | if (!value && placeholder) { 313 | value = placeholder; 314 | } 315 | 316 | width = measureString(value, $input) + 4; 317 | if (width !== currentWidth) { 318 | currentWidth = width; 319 | $input.width(width); 320 | $input.triggerHandler('resize'); 321 | } 322 | }; 323 | 324 | $input.on('keydown keyup update blur', update); 325 | update(); 326 | }; 327 | 328 | var domToString = function(d) { 329 | var tmp = document.createElement('div'); 330 | 331 | tmp.appendChild(d.cloneNode(true)); 332 | 333 | return tmp.innerHTML; 334 | }; 335 | 336 | var logError = function(message, options){ 337 | if(!options) options = {}; 338 | var component = "Selectize"; 339 | 340 | console.error(component + ": " + message) 341 | 342 | if(options.explanation){ 343 | // console.group is undefined in 15 | */ 16 | 17 | .selectize-control.plugin-drag_drop.multi > .selectize-input > div.ui-sortable-placeholder { 18 | visibility: visible !important; 19 | background: #f2f2f2 !important; 20 | background: rgba(0, 0, 0, 0.06) !important; 21 | border: 0 none !important; 22 | -webkit-box-shadow: inset 0 0 12px 4px #ffffff; 23 | box-shadow: inset 0 0 12px 4px #ffffff; 24 | } 25 | .selectize-control.plugin-drag_drop .ui-sortable-placeholder::after { 26 | content: '!'; 27 | visibility: hidden; 28 | } 29 | .selectize-control.plugin-drag_drop .ui-sortable-helper { 30 | -webkit-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); 31 | box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); 32 | } 33 | .selectize-dropdown-header { 34 | position: relative; 35 | padding: 5px 8px; 36 | border-bottom: 1px solid #d0d0d0; 37 | background: #f8f8f8; 38 | -webkit-border-radius: 3px 3px 0 0; 39 | -moz-border-radius: 3px 3px 0 0; 40 | border-radius: 3px 3px 0 0; 41 | } 42 | .selectize-dropdown-header-close { 43 | position: absolute; 44 | right: 8px; 45 | top: 50%; 46 | color: #303030; 47 | opacity: 0.4; 48 | margin-top: -12px; 49 | line-height: 20px; 50 | font-size: 20px !important; 51 | } 52 | .selectize-dropdown-header-close:hover { 53 | color: #000000; 54 | } 55 | .selectize-dropdown.plugin-optgroup_columns .optgroup { 56 | border-right: 1px solid #f2f2f2; 57 | border-top: 0 none; 58 | float: left; 59 | -webkit-box-sizing: border-box; 60 | -moz-box-sizing: border-box; 61 | box-sizing: border-box; 62 | } 63 | .selectize-dropdown.plugin-optgroup_columns .optgroup:last-child { 64 | border-right: 0 none; 65 | } 66 | .selectize-dropdown.plugin-optgroup_columns .optgroup:before { 67 | display: none; 68 | } 69 | .selectize-dropdown.plugin-optgroup_columns .optgroup-header { 70 | border-top: 0 none; 71 | } 72 | .selectize-control.plugin-remove_button [data-value] { 73 | position: relative; 74 | padding-right: 24px !important; 75 | } 76 | .selectize-control.plugin-remove_button [data-value] .remove { 77 | z-index: 1; 78 | /* fixes ie bug (see #392) */ 79 | position: absolute; 80 | top: 0; 81 | right: 0; 82 | bottom: 0; 83 | width: 17px; 84 | text-align: center; 85 | font-weight: bold; 86 | font-size: 12px; 87 | color: inherit; 88 | text-decoration: none; 89 | vertical-align: middle; 90 | display: inline-block; 91 | padding: 2px 0 0 0; 92 | border-left: 1px solid #d0d0d0; 93 | -webkit-border-radius: 0 2px 2px 0; 94 | -moz-border-radius: 0 2px 2px 0; 95 | border-radius: 0 2px 2px 0; 96 | -webkit-box-sizing: border-box; 97 | -moz-box-sizing: border-box; 98 | box-sizing: border-box; 99 | } 100 | .selectize-control.plugin-remove_button [data-value] .remove:hover { 101 | background: rgba(0, 0, 0, 0.05); 102 | } 103 | .selectize-control.plugin-remove_button [data-value].active .remove { 104 | border-left-color: #cacaca; 105 | } 106 | .selectize-control.plugin-remove_button .disabled [data-value] .remove:hover { 107 | background: none; 108 | } 109 | .selectize-control.plugin-remove_button .disabled [data-value] .remove { 110 | border-left-color: #ffffff; 111 | } 112 | .selectize-control.plugin-remove_button .remove-single { 113 | position: absolute; 114 | right: 28px; 115 | top: 6px; 116 | font-size: 23px; 117 | } 118 | .selectize-control { 119 | position: relative; 120 | } 121 | .selectize-dropdown, 122 | .selectize-input, 123 | .selectize-input input { 124 | color: #303030; 125 | font-family: inherit; 126 | font-size: 13px; 127 | line-height: 18px; 128 | -webkit-font-smoothing: inherit; 129 | } 130 | .selectize-input, 131 | .selectize-control.single .selectize-input.input-active { 132 | background: #ffffff; 133 | cursor: text; 134 | display: inline-block; 135 | } 136 | .selectize-input { 137 | border: 1px solid #d0d0d0; 138 | padding: 8px 8px; 139 | display: inline-block; 140 | width: 100%; 141 | overflow: hidden; 142 | position: relative; 143 | z-index: 1; 144 | -webkit-box-sizing: border-box; 145 | -moz-box-sizing: border-box; 146 | box-sizing: border-box; 147 | -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.1); 148 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.1); 149 | -webkit-border-radius: 3px; 150 | -moz-border-radius: 3px; 151 | border-radius: 3px; 152 | } 153 | .selectize-control.multi .selectize-input.has-items { 154 | padding: 6px 8px 3px; 155 | } 156 | .selectize-input.full { 157 | background-color: #ffffff; 158 | } 159 | .selectize-input.disabled, 160 | .selectize-input.disabled * { 161 | cursor: default !important; 162 | } 163 | .selectize-input.focus { 164 | -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.15); 165 | box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.15); 166 | } 167 | .selectize-input.dropdown-active { 168 | -webkit-border-radius: 3px 3px 0 0; 169 | -moz-border-radius: 3px 3px 0 0; 170 | border-radius: 3px 3px 0 0; 171 | } 172 | .selectize-input > * { 173 | vertical-align: baseline; 174 | display: -moz-inline-stack; 175 | display: inline-block; 176 | zoom: 1; 177 | *display: inline; 178 | } 179 | .selectize-control.multi .selectize-input > div { 180 | cursor: pointer; 181 | margin: 0 3px 3px 0; 182 | padding: 2px 6px; 183 | background: #f2f2f2; 184 | color: #303030; 185 | border: 0 solid #d0d0d0; 186 | } 187 | .selectize-control.multi .selectize-input > div.active { 188 | background: #e8e8e8; 189 | color: #303030; 190 | border: 0 solid #cacaca; 191 | } 192 | .selectize-control.multi .selectize-input.disabled > div, 193 | .selectize-control.multi .selectize-input.disabled > div.active { 194 | color: #7d7d7d; 195 | background: #ffffff; 196 | border: 0 solid #ffffff; 197 | } 198 | .selectize-input > input { 199 | display: inline-block !important; 200 | padding: 0 !important; 201 | min-height: 0 !important; 202 | max-height: none !important; 203 | max-width: 100% !important; 204 | margin: 0 2px 0 0 !important; 205 | text-indent: 0 !important; 206 | border: 0 none !important; 207 | background: none !important; 208 | line-height: inherit !important; 209 | -webkit-user-select: auto !important; 210 | -webkit-box-shadow: none !important; 211 | box-shadow: none !important; 212 | } 213 | .selectize-input > input::-ms-clear { 214 | display: none; 215 | } 216 | .selectize-input > input:focus { 217 | outline: none !important; 218 | } 219 | .selectize-input::after { 220 | content: ' '; 221 | display: block; 222 | clear: left; 223 | } 224 | .selectize-input.dropdown-active::before { 225 | content: ' '; 226 | display: block; 227 | position: absolute; 228 | background: #f0f0f0; 229 | height: 1px; 230 | bottom: 0; 231 | left: 0; 232 | right: 0; 233 | } 234 | .selectize-dropdown { 235 | position: absolute; 236 | z-index: 10; 237 | border: 1px solid #d0d0d0; 238 | background: #ffffff; 239 | margin: -1px 0 0 0; 240 | border-top: 0 none; 241 | -webkit-box-sizing: border-box; 242 | -moz-box-sizing: border-box; 243 | box-sizing: border-box; 244 | -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); 245 | box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); 246 | -webkit-border-radius: 0 0 3px 3px; 247 | -moz-border-radius: 0 0 3px 3px; 248 | border-radius: 0 0 3px 3px; 249 | } 250 | .selectize-dropdown [data-selectable] { 251 | cursor: pointer; 252 | overflow: hidden; 253 | } 254 | .selectize-dropdown [data-selectable] .highlight { 255 | background: rgba(125, 168, 208, 0.2); 256 | -webkit-border-radius: 1px; 257 | -moz-border-radius: 1px; 258 | border-radius: 1px; 259 | } 260 | .selectize-dropdown [data-selectable], 261 | .selectize-dropdown .optgroup-header { 262 | padding: 5px 8px; 263 | } 264 | .selectize-dropdown .optgroup:first-child .optgroup-header { 265 | border-top: 0 none; 266 | } 267 | .selectize-dropdown .optgroup-header { 268 | color: #303030; 269 | background: #ffffff; 270 | cursor: default; 271 | } 272 | .selectize-dropdown .active { 273 | background-color: #f5fafd; 274 | color: #495c68; 275 | } 276 | .selectize-dropdown .active.create { 277 | color: #495c68; 278 | } 279 | .selectize-dropdown .create { 280 | color: rgba(48, 48, 48, 0.5); 281 | } 282 | .selectize-dropdown-content { 283 | overflow-y: auto; 284 | overflow-x: hidden; 285 | max-height: 200px; 286 | -webkit-overflow-scrolling: touch; 287 | } 288 | .selectize-control.single .selectize-input, 289 | .selectize-control.single .selectize-input input { 290 | cursor: pointer; 291 | } 292 | .selectize-control.single .selectize-input.input-active, 293 | .selectize-control.single .selectize-input.input-active input { 294 | cursor: text; 295 | } 296 | .selectize-control.single .selectize-input:after { 297 | content: ' '; 298 | display: block; 299 | position: absolute; 300 | top: 50%; 301 | right: 15px; 302 | margin-top: -3px; 303 | width: 0; 304 | height: 0; 305 | border-style: solid; 306 | border-width: 5px 5px 0 5px; 307 | border-color: #808080 transparent transparent transparent; 308 | } 309 | .selectize-control.single .selectize-input.dropdown-active:after { 310 | margin-top: -4px; 311 | border-width: 0 5px 5px 5px; 312 | border-color: transparent transparent #808080 transparent; 313 | } 314 | .selectize-control.rtl.single .selectize-input:after { 315 | left: 15px; 316 | right: auto; 317 | } 318 | .selectize-control.rtl .selectize-input > input { 319 | margin: 0 4px 0 -2px !important; 320 | } 321 | .selectize-control .selectize-input.disabled { 322 | opacity: 0.5; 323 | background-color: #fafafa; 324 | } 325 | -------------------------------------------------------------------------------- /dist/less/selectize.less: -------------------------------------------------------------------------------- 1 | @import "plugins/drag_drop"; 2 | @import "plugins/dropdown_header"; 3 | @import "plugins/optgroup_columns"; 4 | @import "plugins/remove_button"; 5 | 6 | // base styles 7 | 8 | @selectize-font-family: inherit; 9 | @selectize-font-smoothing: inherit; 10 | @selectize-font-size: 13px; 11 | @selectize-line-height: 18px; 12 | 13 | @selectize-color-text: #303030; 14 | @selectize-color-border: #d0d0d0; 15 | @selectize-color-highlight: rgba(125,168,208,0.2); 16 | @selectize-color-input: #fff; 17 | @selectize-color-input-full: @selectize-color-input; 18 | @selectize-color-disabled: #fafafa; 19 | @selectize-color-item: #f2f2f2; 20 | @selectize-color-item-text: @selectize-color-text; 21 | @selectize-color-item-border: #d0d0d0; 22 | @selectize-color-item-active: #e8e8e8; 23 | @selectize-color-item-active-text: @selectize-color-text; 24 | @selectize-color-item-active-border: #cacaca; 25 | @selectize-color-dropdown: #fff; 26 | @selectize-color-dropdown-border: @selectize-color-border; 27 | @selectize-color-dropdown-border-top: #f0f0f0; 28 | @selectize-color-dropdown-item-active: #f5fafd; 29 | @selectize-color-dropdown-item-active-text: #495c68; 30 | @selectize-color-dropdown-item-create-text: rgba(red(@selectize-color-text), green(@selectize-color-text), blue(@selectize-color-text), 0.5); 31 | @selectize-color-dropdown-item-create-active-text: @selectize-color-dropdown-item-active-text; 32 | @selectize-color-optgroup: @selectize-color-dropdown; 33 | @selectize-color-optgroup-text: @selectize-color-text; 34 | @selectize-lighten-disabled-item: 30%; 35 | @selectize-lighten-disabled-item-text: 30%; 36 | @selectize-lighten-disabled-item-border: 30%; 37 | @selectize-opacity-disabled: 0.5; 38 | 39 | @selectize-shadow-input: inset 0 1px 1px rgba(0,0,0,0.1); 40 | @selectize-shadow-input-focus: inset 0 1px 2px rgba(0,0,0,0.15); 41 | @selectize-border: 1px solid @selectize-color-border; 42 | @selectize-dropdown-border: 1px solid @selectize-color-dropdown-border; 43 | @selectize-border-radius: 3px; 44 | 45 | @selectize-width-item-border: 0; 46 | @selectize-max-height-dropdown: 200px; 47 | 48 | @selectize-padding-x: 8px; 49 | @selectize-padding-y: 8px; 50 | @selectize-padding-item-x: 6px; 51 | @selectize-padding-item-y: 2px; 52 | @selectize-padding-dropdown-item-x: @selectize-padding-x; 53 | @selectize-padding-dropdown-item-y: 5px; 54 | @selectize-margin-item-x: 3px; 55 | @selectize-margin-item-y: 3px; 56 | 57 | @selectize-arrow-size: 5px; 58 | @selectize-arrow-color: #808080; 59 | @selectize-arrow-offset: 15px; 60 | 61 | @selectize-caret-margin: 0 2px 0 0; 62 | @selectize-caret-margin-rtl: 0 4px 0 -2px; 63 | 64 | .selectize-border-radius (@radii) { 65 | -webkit-border-radius: @radii; 66 | -moz-border-radius: @radii; 67 | border-radius: @radii; 68 | } 69 | .selectize-unselectable () { 70 | -webkit-user-select: none; 71 | -moz-user-select: none; 72 | -ms-user-select: none; 73 | user-select: none; 74 | } 75 | .selectize-box-shadow (@shadow) { 76 | -webkit-box-shadow: @shadow; 77 | box-shadow: @shadow; 78 | } 79 | .selectize-box-sizing (@type: border-box) { 80 | -webkit-box-sizing: @type; 81 | -moz-box-sizing: @type; 82 | box-sizing: @type; 83 | } 84 | .selectize-vertical-gradient (@color-top, @color-bottom) { 85 | background-color: mix(@color-top, @color-bottom, 60%); 86 | background-image: -moz-linear-gradient(top, @color-top, @color-bottom); // FF 3.6+ 87 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(@color-top), to(@color-bottom)); // Safari 4+, Chrome 2+ 88 | background-image: -webkit-linear-gradient(top, @color-top, @color-bottom); // Safari 5.1+, Chrome 10+ 89 | background-image: -o-linear-gradient(top, @color-top, @color-bottom); // Opera 11.10 90 | background-image: linear-gradient(to bottom, @color-top, @color-bottom); // Standard, IE10 91 | background-repeat: repeat-x; 92 | filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",argb(@color-top),argb(@color-bottom))); // IE9 and down 93 | } 94 | 95 | .selectize-control { 96 | position: relative; 97 | } 98 | 99 | .selectize-dropdown, .selectize-input, .selectize-input input { 100 | color: @selectize-color-text; 101 | font-family: @selectize-font-family; 102 | font-size: @selectize-font-size; 103 | line-height: @selectize-line-height; 104 | -webkit-font-smoothing: @selectize-font-smoothing; 105 | } 106 | 107 | .selectize-input, .selectize-control.single .selectize-input.input-active { 108 | background: @selectize-color-input; 109 | cursor: text; 110 | display: inline-block; 111 | } 112 | 113 | .selectize-input { 114 | border: @selectize-border; 115 | padding: @selectize-padding-y @selectize-padding-x; 116 | display: inline-block; 117 | width: 100%; 118 | overflow: hidden; 119 | position: relative; 120 | z-index: 1; 121 | .selectize-box-sizing(border-box); 122 | .selectize-box-shadow(@selectize-shadow-input); 123 | .selectize-border-radius(@selectize-border-radius); 124 | 125 | .selectize-control.multi &.has-items { 126 | @padding-x: @selectize-padding-x; 127 | @padding-top: @selectize-padding-y - @selectize-padding-item-y - @selectize-width-item-border; 128 | @padding-bottom: @selectize-padding-y - @selectize-padding-item-y - @selectize-margin-item-y - @selectize-width-item-border; 129 | padding: @padding-top @padding-x @padding-bottom; 130 | } 131 | 132 | &.full { 133 | background-color: @selectize-color-input-full; 134 | } 135 | &.disabled, &.disabled * { 136 | cursor: default !important; 137 | } 138 | &.focus { 139 | .selectize-box-shadow(@selectize-shadow-input-focus); 140 | } 141 | &.dropdown-active { 142 | .selectize-border-radius(@selectize-border-radius @selectize-border-radius 0 0); 143 | } 144 | 145 | > * { 146 | vertical-align: baseline; 147 | display: -moz-inline-stack; 148 | display: inline-block; 149 | zoom: 1; 150 | *display: inline; 151 | } 152 | .selectize-control.multi & > div { 153 | cursor: pointer; 154 | margin: 0 @selectize-margin-item-x @selectize-margin-item-y 0; 155 | padding: @selectize-padding-item-y @selectize-padding-item-x; 156 | background: @selectize-color-item; 157 | color: @selectize-color-item-text; 158 | border: @selectize-width-item-border solid @selectize-color-item-border; 159 | 160 | &.active { 161 | background: @selectize-color-item-active; 162 | color: @selectize-color-item-active-text; 163 | border: @selectize-width-item-border solid @selectize-color-item-active-border; 164 | } 165 | } 166 | .selectize-control.multi &.disabled > div { 167 | &, &.active { 168 | color: lighten(desaturate(@selectize-color-item-text, 100%), @selectize-lighten-disabled-item-text); 169 | background: lighten(desaturate(@selectize-color-item, 100%), @selectize-lighten-disabled-item); 170 | border: @selectize-width-item-border solid lighten(desaturate(@selectize-color-item-border, 100%), @selectize-lighten-disabled-item-border); 171 | } 172 | } 173 | > input { 174 | &::-ms-clear { 175 | display: none; 176 | } 177 | display: inline-block !important; 178 | padding: 0 !important; 179 | min-height: 0 !important; 180 | max-height: none !important; 181 | max-width: 100% !important; 182 | margin: @selectize-caret-margin !important; 183 | text-indent: 0 !important; 184 | border: 0 none !important; 185 | background: none !important; 186 | line-height: inherit !important; 187 | -webkit-user-select: auto !important; 188 | .selectize-box-shadow(none) !important; 189 | &:focus { outline: none !important; } 190 | } 191 | } 192 | 193 | .selectize-input::after { 194 | content: ' '; 195 | display: block; 196 | clear: left; 197 | } 198 | 199 | .selectize-input.dropdown-active::before { 200 | content: ' '; 201 | display: block; 202 | position: absolute; 203 | background: @selectize-color-dropdown-border-top; 204 | height: 1px; 205 | bottom: 0; 206 | left: 0; 207 | right: 0; 208 | } 209 | 210 | .selectize-dropdown { 211 | position: absolute; 212 | z-index: 10; 213 | border: @selectize-dropdown-border; 214 | background: @selectize-color-dropdown; 215 | margin: -1px 0 0 0; 216 | border-top: 0 none; 217 | .selectize-box-sizing(border-box); 218 | .selectize-box-shadow(0 1px 3px rgba(0,0,0,0.1)); 219 | .selectize-border-radius(0 0 @selectize-border-radius @selectize-border-radius); 220 | 221 | [data-selectable] { 222 | cursor: pointer; 223 | overflow: hidden; 224 | .highlight { 225 | background: @selectize-color-highlight; 226 | .selectize-border-radius(1px); 227 | } 228 | } 229 | [data-selectable], .optgroup-header { 230 | padding: @selectize-padding-dropdown-item-y @selectize-padding-dropdown-item-x; 231 | } 232 | .optgroup:first-child .optgroup-header { 233 | border-top: 0 none; 234 | } 235 | .optgroup-header { 236 | color: @selectize-color-optgroup-text; 237 | background: @selectize-color-optgroup; 238 | cursor: default; 239 | } 240 | .active { 241 | background-color: @selectize-color-dropdown-item-active; 242 | color: @selectize-color-dropdown-item-active-text; 243 | &.create { 244 | color: @selectize-color-dropdown-item-create-active-text; 245 | } 246 | } 247 | .create { 248 | color: @selectize-color-dropdown-item-create-text; 249 | } 250 | } 251 | 252 | .selectize-dropdown-content { 253 | overflow-y: auto; 254 | overflow-x: hidden; 255 | max-height: @selectize-max-height-dropdown; 256 | -webkit-overflow-scrolling: touch; 257 | } 258 | 259 | .selectize-control.single .selectize-input { 260 | &, input { cursor: pointer; } 261 | &.input-active, &.input-active input { cursor: text; } 262 | 263 | &:after { 264 | content: ' '; 265 | display: block; 266 | position: absolute; 267 | top: 50%; 268 | right: @selectize-arrow-offset; 269 | margin-top: round((-1 * @selectize-arrow-size / 2)); 270 | width: 0; 271 | height: 0; 272 | border-style: solid; 273 | border-width: @selectize-arrow-size @selectize-arrow-size 0 @selectize-arrow-size; 274 | border-color: @selectize-arrow-color transparent transparent transparent; 275 | } 276 | &.dropdown-active:after { 277 | margin-top: @selectize-arrow-size * -0.8; 278 | border-width: 0 @selectize-arrow-size @selectize-arrow-size @selectize-arrow-size; 279 | border-color: transparent transparent @selectize-arrow-color transparent; 280 | } 281 | } 282 | 283 | .selectize-control.rtl { 284 | &.single .selectize-input:after { 285 | left: @selectize-arrow-offset; 286 | right: auto; 287 | } 288 | .selectize-input > input { 289 | margin: @selectize-caret-margin-rtl !important; 290 | } 291 | } 292 | 293 | .selectize-control .selectize-input.disabled { 294 | opacity: @selectize-opacity-disabled; 295 | background-color: @selectize-color-disabled; 296 | } 297 | --------------------------------------------------------------------------------