selectize-rails 0.6.14 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -25,20 +25,27 @@ In your `application.css`, include the following:
25
25
 
26
26
  ```css
27
27
  *= require selectize
28
+ *= require selectize.default
28
29
  ```
29
30
 
31
+ ### Themes
32
+
33
+ To include additional theme's you can replace the `selectize.default` for on of the [theme files](https://github.com/brianreavis/selectize.js/tree/master/dist/css)
34
+
35
+
30
36
  ## Examples
31
37
 
32
38
  See the [demo page of Brian Reavis](http://brianreavis.github.io/selectize.js/) for examples how to use the plugin
33
39
 
34
40
  ## Changes
35
41
 
36
- | Version | Notes |
37
- | -------:| ----------------------------------------------------------------------------------- |
38
- | 0.6.14 | Update to v0.6.14 of selectize.js |
39
- | 0.6.4 | Update to v0.6.4 of selectize.js |
40
- | 0.6.1 | Update and set gem version equal to selectize.js version |
41
- | 0.1.0 | Initial release |
42
+ | Version | Notes |
43
+ | -------:| ----------------------------------------------------------- |
44
+ | 0.7.0 | Update to v0.7.0 of selectize.js |
45
+ | 0.6.14 | Update to v0.6.14 of selectize.js |
46
+ | 0.6.4 | Update to v0.6.4 of selectize.js |
47
+ | 0.6.1 | Update and set gem version equal to selectize.js version |
48
+ | 0.1.0 | Initial release |
42
49
 
43
50
  ## License
44
51
 
@@ -1,5 +1,5 @@
1
1
  module Selectize
2
2
  module Rails
3
- VERSION = "0.6.14"
3
+ VERSION = "0.7.0"
4
4
  end
5
5
  end
@@ -6,9 +6,9 @@ git clone https://github.com/brianreavis/selectize.js.git tmp_vendor
6
6
 
7
7
  # Copy files
8
8
  echo "Copying selectize.js"
9
- cp tmp_vendor/selectize.js vendor/assets/javascripts/selectize.js
10
- echo "Copying selectize.css"
11
- cp tmp_vendor/selectize.css vendor/assets/stylesheets/selectize.css
9
+ cp tmp_vendor/dist/js/selectize.js vendor/assets/javascripts/selectize.js
10
+ echo "Copying css files"
11
+ cp tmp_vendor/dist/css/*.css vendor/assets/stylesheets/
12
12
 
13
13
  # Delete vendor repo
14
14
  echo "Removing cloned vendor repo"
@@ -1,30 +1,35 @@
1
- /*! selectize.js - v0.6.14 | https://github.com/brianreavis/selectize.js | Apache License (v2) */
2
-
3
- (function(factory) {
4
- if (typeof exports === 'object') {
5
- factory(require('jquery'));
6
- } else if (typeof define === 'function' && define.amd) {
7
- define(['jquery'], factory);
1
+ /**
2
+ * selectize.js (v0.7.0)
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 <brian@thirdroute.com>
15
+ */
16
+
17
+ /*jshint curly:false */
18
+ /*jshint browser:true */
19
+
20
+ (function(root, factory) {
21
+ if (typeof define === 'function' && define.amd) {
22
+ define(['sifter','microplugin'], factory);
8
23
  } else {
9
- factory(jQuery);
24
+ root.Selectize = factory(root.Sifter, root.MicroPlugin);
10
25
  }
11
- }(function ($) {
12
- "use strict";
13
-
14
- /* --- file: "src/contrib/highlight.js" --- */
15
-
16
- /**
17
- * highlight v3 | MIT license | Johann Burkard <jb@eaio.com>
18
- * Highlights arbitrary terms in a node.
19
- *
20
- * - Modified by Marshal <beatgates@gmail.com> 2011-6-24 (added regex)
21
- * - Modified by Brian Reavis <brian@thirdroute.com> 2012-8-27 (cleanup)
22
- */
26
+ }(this, function(Sifter, MicroPlugin) {
27
+ 'use strict';
23
28
 
24
29
  var highlight = function($element, pattern) {
25
30
  if (typeof pattern === 'string' && !pattern.length) return;
26
31
  var regex = (typeof pattern === 'string') ? new RegExp(pattern, 'i') : pattern;
27
-
32
+
28
33
  var highlight = function(node) {
29
34
  var skip = 0;
30
35
  if (node.nodeType === 3) {
@@ -47,32 +52,12 @@
47
52
  }
48
53
  return skip;
49
54
  };
50
-
55
+
51
56
  return $element.each(function() {
52
57
  highlight(this);
53
58
  });
54
59
  };
55
-
56
- var unhighlight = function($element) {
57
- return $element.find('span.highlight').each(function() {
58
- var parent = this.parentNode;
59
- parent.replaceChild(parent.firstChild, parent);
60
- parent.normalize();
61
- }).end();
62
- };
63
-
64
- /* --- file: "src/contrib/microevent.js" --- */
65
-
66
- /**
67
- * MicroEvent - to make any js object an event emitter
68
- *
69
- * - pure javascript - server compatible, browser compatible
70
- * - dont rely on the browser doms
71
- * - super simple - you get it immediatly, no mistery, no magic involved
72
- *
73
- * @author Jerome Etienne (https://github.com/jeromeetienne)
74
- */
75
-
60
+
76
61
  var MicroEvent = function() {};
77
62
  MicroEvent.prototype = {
78
63
  on: function(event, fct){
@@ -81,6 +66,10 @@
81
66
  this._events[event].push(fct);
82
67
  },
83
68
  off: function(event, fct){
69
+ var n = arguments.length;
70
+ if (n === 0) return delete this._events;
71
+ if (n === 1) return delete this._events[event];
72
+
84
73
  this._events = this._events || {};
85
74
  if (event in this._events === false) return;
86
75
  this._events[event].splice(this._events[event].indexOf(fct), 1);
@@ -93,41 +82,23 @@
93
82
  }
94
83
  }
95
84
  };
96
-
85
+
97
86
  /**
98
- * Mixin will delegate all MicroEvent.js function in the destination object.
99
- *
100
- * - MicroEvent.mixin(Foobar) will make Foobar able to use MicroEvent
101
- *
102
- * @param {object} the object which will support MicroEvent
103
- */
87
+ * Mixin will delegate all MicroEvent.js function in the destination object.
88
+ *
89
+ * - MicroEvent.mixin(Foobar) will make Foobar able to use MicroEvent
90
+ *
91
+ * @param {object} the object which will support MicroEvent
92
+ */
104
93
  MicroEvent.mixin = function(destObject){
105
94
  var props = ['on', 'off', 'trigger'];
106
95
  for (var i = 0; i < props.length; i++){
107
96
  destObject.prototype[props[i]] = MicroEvent.prototype[props[i]];
108
97
  }
109
98
  };
110
-
111
- /* --- file: "src/constants.js" --- */
112
-
113
- /**
114
- * selectize - A highly customizable select control with autocomplete.
115
- * Copyright (c) 2013 Brian Reavis & contributors
116
- *
117
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
118
- * file except in compliance with the License. You may obtain a copy of the License at:
119
- * http://www.apache.org/licenses/LICENSE-2.0
120
- *
121
- * Unless required by applicable law or agreed to in writing, software distributed under
122
- * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
123
- * ANY KIND, either express or implied. See the License for the specific language
124
- * governing permissions and limitations under the License.
125
- *
126
- * @author Brian Reavis <brian@thirdroute.com>
127
- */
128
-
99
+
129
100
  var IS_MAC = /Mac/.test(navigator.userAgent);
130
-
101
+
131
102
  var KEY_A = 65;
132
103
  var KEY_COMMA = 188;
133
104
  var KEY_RETURN = 13;
@@ -142,141 +113,42 @@
142
113
  var KEY_CMD = IS_MAC ? 91 : 17;
143
114
  var KEY_CTRL = IS_MAC ? 18 : 17;
144
115
  var KEY_TAB = 9;
145
-
116
+
146
117
  var TAG_SELECT = 1;
147
118
  var TAG_INPUT = 2;
148
-
149
- var DIACRITICS = {
150
- 'a': '[aÀÁÂÃÄÅàáâãäå]',
151
- 'c': '[cÇç]',
152
- 'e': '[eÈÉÊËèéêë]',
153
- 'i': '[iÌÍÎÏìíîï]',
154
- 'n': '[nÑñ]',
155
- 'o': '[oÒÓÔÕÕÖØòóôõöø]',
156
- 's': '[sŠš]',
157
- 'u': '[uÙÚÛÜùúûü]',
158
- 'y': '[yŸÿý]',
159
- 'z': '[zŽž]'
160
- };
161
-
162
- /* --- file: "src/plugins.js" --- */
163
-
164
- var Plugins = {};
165
-
166
- Plugins.mixin = function(Interface, interfaceName) {
167
- Interface.plugins = {};
168
-
169
- /**
170
- * Initializes the provided functions.
171
- * Acceptable formats:
172
- *
173
- * List (without options):
174
- * ['a', 'b', 'c']
175
- *
176
- * List (with options)
177
- * {'a': { ... }, 'b': { ... }, 'c': { ... }}
178
- *
179
- * @param {mixed} plugins
180
- */
181
- Interface.prototype.loadPlugins = function(plugins) {
182
- var i, n, key;
183
- this.plugins = [];
184
- this.pluginSettings = {};
185
-
186
- if ($.isArray(plugins)) {
187
- for (i = 0, n = plugins.length; i < n; i++) {
188
- this.loadPlugin(plugins[i]);
189
- }
190
- } else if (plugins) {
191
- this.pluginSettings = $.extend({}, plugins);
192
- for (key in plugins) {
193
- if (plugins.hasOwnProperty(key)) {
194
- this.loadPlugin(key);
195
- }
196
- }
197
- }
198
- };
199
-
200
- /**
201
- * Initializes a plugin.
202
- *
203
- * @param {string} name
204
- */
205
- Interface.prototype.loadPlugin = function(name) {
206
- var plugin, i, n;
207
-
208
- if (this.plugins.indexOf(name) !== -1) return;
209
- if (!Interface.plugins.hasOwnProperty(name)) {
210
- throw new Error(interfaceName + ' unable to find "' + name + '" plugin');
211
- }
212
-
213
- plugin = Interface.plugins[name];
214
-
215
- // initialize plugin and dependencies
216
- this.plugins.push(name);
217
- for (i = 0, n = plugin.dependencies.length; i < n; i++) {
218
- this.loadPlugin(plugin.dependencies[i]);
219
- }
220
- plugin.fn.apply(this, [this.pluginSettings[name] || {}]);
221
- };
222
-
223
- /**
224
- * Registers a plugin.
225
- *
226
- * @param {string} name
227
- * @param {array} dependencies (optional)
228
- * @param {function} fn
229
- */
230
- Interface.registerPlugin = function(name) {
231
- var args = arguments;
232
- Interface.plugins[name] = {
233
- 'name' : name,
234
- 'fn' : args[args.length - 1],
235
- 'dependencies' : args.length === 3 ? args[1] : []
236
- };
237
- };
238
- };
239
-
240
- /* --- file: "src/utils.js" --- */
241
-
242
- /**
243
- * Determines if the provided value has been defined.
244
- *
245
- * @param {mixed} object
246
- * @returns {boolean}
247
- */
119
+
248
120
  var isset = function(object) {
249
121
  return typeof object !== 'undefined';
250
122
  };
251
-
123
+
252
124
  /**
253
- * Converts a scalar to its best string representation
254
- * for hash keys and HTML attribute values.
255
- *
256
- * Transformations:
257
- * 'str' -> 'str'
258
- * null -> ''
259
- * undefined -> ''
260
- * true -> '1'
261
- * false -> '0'
262
- * 0 -> '0'
263
- * 1 -> '1'
264
- *
265
- * @param {string} value
266
- * @returns {string}
267
- */
125
+ * Converts a scalar to its best string representation
126
+ * for hash keys and HTML attribute values.
127
+ *
128
+ * Transformations:
129
+ * 'str' -> 'str'
130
+ * null -> ''
131
+ * undefined -> ''
132
+ * true -> '1'
133
+ * false -> '0'
134
+ * 0 -> '0'
135
+ * 1 -> '1'
136
+ *
137
+ * @param {string} value
138
+ * @returns {string}
139
+ */
268
140
  var hash_key = function(value) {
269
141
  if (typeof value === 'undefined' || value === null) return '';
270
142
  if (typeof value === 'boolean') return value ? '1' : '0';
271
143
  return value + '';
272
144
  };
273
-
145
+
274
146
  /**
275
- * Escapes a string for use within HTML.
276
- *
277
- * @param {string} str
278
- * @returns {string}
279
- */
147
+ * Escapes a string for use within HTML.
148
+ *
149
+ * @param {string} str
150
+ * @returns {string}
151
+ */
280
152
  var escape_html = function(str) {
281
153
  return (str + '')
282
154
  .replace(/&/g, '&amp;')
@@ -284,38 +156,28 @@
284
156
  .replace(/>/g, '&gt;')
285
157
  .replace(/"/g, '&quot;');
286
158
  };
287
-
288
- /**
289
- * Escapes a string for use within regular expressions.
290
- *
291
- * @param {string} str
292
- * @returns {string}
293
- */
294
- var escape_regex = function(str) {
295
- return (str + '').replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1');
296
- };
297
-
159
+
298
160
  /**
299
- * Escapes quotation marks with backslashes. Useful
300
- * for escaping values for use in CSS attribute selectors.
301
- *
302
- * @param {string} str
303
- * @return {string}
304
- */
161
+ * Escapes quotation marks with backslashes. Useful
162
+ * for escaping values for use in CSS attribute selectors.
163
+ *
164
+ * @param {string} str
165
+ * @return {string}
166
+ */
305
167
  var escape_quotes = function(str) {
306
168
  return str.replace(/(['"])/g, '\\$1');
307
169
  };
308
-
170
+
309
171
  var hook = {};
310
-
172
+
311
173
  /**
312
- * Wraps `method` on `self` so that `fn`
313
- * is invoked before the original method.
314
- *
315
- * @param {object} self
316
- * @param {string} method
317
- * @param {function} fn
318
- */
174
+ * Wraps `method` on `self` so that `fn`
175
+ * is invoked before the original method.
176
+ *
177
+ * @param {object} self
178
+ * @param {string} method
179
+ * @param {function} fn
180
+ */
319
181
  hook.before = function(self, method, fn) {
320
182
  var original = self[method];
321
183
  self[method] = function() {
@@ -323,15 +185,15 @@
323
185
  return original.apply(self, arguments);
324
186
  };
325
187
  };
326
-
188
+
327
189
  /**
328
- * Wraps `method` on `self` so that `fn`
329
- * is invoked after the original method.
330
- *
331
- * @param {object} self
332
- * @param {string} method
333
- * @param {function} fn
334
- */
190
+ * Wraps `method` on `self` so that `fn`
191
+ * is invoked after the original method.
192
+ *
193
+ * @param {object} self
194
+ * @param {string} method
195
+ * @param {function} fn
196
+ */
335
197
  hook.after = function(self, method, fn) {
336
198
  var original = self[method];
337
199
  self[method] = function() {
@@ -340,15 +202,15 @@
340
202
  return result;
341
203
  };
342
204
  };
343
-
205
+
344
206
  /**
345
- * Builds a hash table out of an array of
346
- * objects, using the specified `key` within
347
- * each object.
348
- *
349
- * @param {string} key
350
- * @param {mixed} objects
351
- */
207
+ * Builds a hash table out of an array of
208
+ * objects, using the specified `key` within
209
+ * each object.
210
+ *
211
+ * @param {string} key
212
+ * @param {mixed} objects
213
+ */
352
214
  var build_hash_table = function(key, objects) {
353
215
  if (!$.isArray(objects)) return objects;
354
216
  var i, n, table = {};
@@ -359,13 +221,13 @@
359
221
  }
360
222
  return table;
361
223
  };
362
-
224
+
363
225
  /**
364
- * Wraps `fn` so that it can only be invoked once.
365
- *
366
- * @param {function} fn
367
- * @returns {function}
368
- */
226
+ * Wraps `fn` so that it can only be invoked once.
227
+ *
228
+ * @param {function} fn
229
+ * @returns {function}
230
+ */
369
231
  var once = function(fn) {
370
232
  var called = false;
371
233
  return function() {
@@ -374,15 +236,15 @@
374
236
  fn.apply(this, arguments);
375
237
  };
376
238
  };
377
-
239
+
378
240
  /**
379
- * Wraps `fn` so that it can only be called once
380
- * every `delay` milliseconds (invoked on the falling edge).
381
- *
382
- * @param {function} fn
383
- * @param {int} delay
384
- * @returns {function}
385
- */
241
+ * Wraps `fn` so that it can only be called once
242
+ * every `delay` milliseconds (invoked on the falling edge).
243
+ *
244
+ * @param {function} fn
245
+ * @param {int} delay
246
+ * @returns {function}
247
+ */
386
248
  var debounce = function(fn, delay) {
387
249
  var timeout;
388
250
  return function() {
@@ -394,20 +256,20 @@
394
256
  }, delay);
395
257
  };
396
258
  };
397
-
259
+
398
260
  /**
399
- * Debounce all fired events types listed in `types`
400
- * while executing the provided `fn`.
401
- *
402
- * @param {object} self
403
- * @param {array} types
404
- * @param {function} fn
405
- */
261
+ * Debounce all fired events types listed in `types`
262
+ * while executing the provided `fn`.
263
+ *
264
+ * @param {object} self
265
+ * @param {array} types
266
+ * @param {function} fn
267
+ */
406
268
  var debounce_events = function(self, types, fn) {
407
269
  var type;
408
270
  var trigger = self.trigger;
409
271
  var event_args = {};
410
-
272
+
411
273
  // override trigger method
412
274
  self.trigger = function() {
413
275
  var type = arguments[0];
@@ -417,11 +279,11 @@
417
279
  return trigger.apply(self, arguments);
418
280
  }
419
281
  };
420
-
282
+
421
283
  // invoke provided function
422
284
  fn.apply(self, []);
423
285
  self.trigger = trigger;
424
-
286
+
425
287
  // trigger queued events
426
288
  for (type in event_args) {
427
289
  if (event_args.hasOwnProperty(type)) {
@@ -429,15 +291,15 @@
429
291
  }
430
292
  }
431
293
  };
432
-
294
+
433
295
  /**
434
- * A workaround for http://bugs.jquery.com/ticket/6696
435
- *
436
- * @param {object} $parent - Parent element to listen on.
437
- * @param {string} event - Event name.
438
- * @param {string} selector - Descendant selector to filter by.
439
- * @param {function} fn - Event handler.
440
- */
296
+ * A workaround for http://bugs.jquery.com/ticket/6696
297
+ *
298
+ * @param {object} $parent - Parent element to listen on.
299
+ * @param {string} event - Event name.
300
+ * @param {string} selector - Descendant selector to filter by.
301
+ * @param {function} fn - Event handler.
302
+ */
441
303
  var watchChildEvent = function($parent, event, selector, fn) {
442
304
  $parent.on(event, selector, function(e) {
443
305
  var child = e.target;
@@ -448,16 +310,16 @@
448
310
  return fn.apply(this, [e]);
449
311
  });
450
312
  };
451
-
313
+
452
314
  /**
453
- * Determines the current selection within a text input control.
454
- * Returns an object containing:
455
- * - start
456
- * - length
457
- *
458
- * @param {object} input
459
- * @returns {object}
460
- */
315
+ * Determines the current selection within a text input control.
316
+ * Returns an object containing:
317
+ * - start
318
+ * - length
319
+ *
320
+ * @param {object} input
321
+ * @returns {object}
322
+ */
461
323
  var getSelection = function(input) {
462
324
  var result = {};
463
325
  if ('selectionStart' in input) {
@@ -473,14 +335,14 @@
473
335
  }
474
336
  return result;
475
337
  };
476
-
338
+
477
339
  /**
478
- * Copies CSS properties from one element to another.
479
- *
480
- * @param {object} $from
481
- * @param {object} $to
482
- * @param {array} properties
483
- */
340
+ * Copies CSS properties from one element to another.
341
+ *
342
+ * @param {object} $from
343
+ * @param {object} $to
344
+ * @param {array} properties
345
+ */
484
346
  var transferStyles = function($from, $to, properties) {
485
347
  var i, n, styles = {};
486
348
  if (properties) {
@@ -492,15 +354,15 @@
492
354
  }
493
355
  $to.css(styles);
494
356
  };
495
-
357
+
496
358
  /**
497
- * Measures the width of a string within a
498
- * parent element (in pixels).
499
- *
500
- * @param {string} str
501
- * @param {object} $parent
502
- * @returns {int}
503
- */
359
+ * Measures the width of a string within a
360
+ * parent element (in pixels).
361
+ *
362
+ * @param {string} str
363
+ * @param {object} $parent
364
+ * @returns {int}
365
+ */
504
366
  var measureString = function(str, $parent) {
505
367
  var $test = $('<test>').css({
506
368
  position: 'absolute',
@@ -510,7 +372,7 @@
510
372
  padding: 0,
511
373
  whiteSpace: 'nowrap'
512
374
  }).text(str).appendTo('body');
513
-
375
+
514
376
  transferStyles($parent, $test, [
515
377
  'letterSpacing',
516
378
  'fontSize',
@@ -518,31 +380,31 @@
518
380
  'fontWeight',
519
381
  'textTransform'
520
382
  ]);
521
-
383
+
522
384
  var width = $test.width();
523
385
  $test.remove();
524
-
386
+
525
387
  return width;
526
388
  };
527
-
389
+
528
390
  /**
529
- * Sets up an input to grow horizontally as the user
530
- * types. If the value is changed manually, you can
531
- * trigger the "update" handler to resize:
532
- *
533
- * $input.trigger('update');
534
- *
535
- * @param {object} $input
536
- */
391
+ * Sets up an input to grow horizontally as the user
392
+ * types. If the value is changed manually, you can
393
+ * trigger the "update" handler to resize:
394
+ *
395
+ * $input.trigger('update');
396
+ *
397
+ * @param {object} $input
398
+ */
537
399
  var autoGrow = function($input) {
538
400
  var update = function(e) {
539
401
  var value, keyCode, printable, placeholder, width;
540
402
  var shift, character, selection;
541
403
  e = e || window.event || {};
542
-
404
+
543
405
  if (e.metaKey || e.altKey) return;
544
406
  if ($input.data('grow') === false) return;
545
-
407
+
546
408
  value = $input.val();
547
409
  if (e.type && e.type.toLowerCase() === 'keydown') {
548
410
  keyCode = e.keyCode;
@@ -550,9 +412,9 @@
550
412
  (keyCode >= 97 && keyCode <= 122) || // a-z
551
413
  (keyCode >= 65 && keyCode <= 90) || // A-Z
552
414
  (keyCode >= 48 && keyCode <= 57) || // 0-9
553
- keyCode == 32 // space
415
+ keyCode === 32 // space
554
416
  );
555
-
417
+
556
418
  if (keyCode === KEY_DELETE || keyCode === KEY_BACKSPACE) {
557
419
  selection = getSelection($input[0]);
558
420
  if (selection.length) {
@@ -570,51 +432,34 @@
570
432
  value += character;
571
433
  }
572
434
  }
573
-
435
+
574
436
  placeholder = $input.attr('placeholder') || '';
575
437
  if (!value.length && placeholder.length) {
576
438
  value = placeholder;
577
439
  }
578
-
440
+
579
441
  width = measureString(value, $input) + 4;
580
442
  if (width !== $input.width()) {
581
443
  $input.width(width);
582
444
  $input.triggerHandler('resize');
583
445
  }
584
446
  };
585
-
447
+
586
448
  $input.on('keydown keyup update blur', update);
587
449
  update();
588
450
  };
589
-
590
- /* --- file: "src/selectize.js" --- */
591
-
592
- /**
593
- * selectize.js
594
- * Copyright (c) 2013 Brian Reavis & contributors
595
- *
596
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
597
- * file except in compliance with the License. You may obtain a copy of the License at:
598
- * http://www.apache.org/licenses/LICENSE-2.0
599
- *
600
- * Unless required by applicable law or agreed to in writing, software distributed under
601
- * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
602
- * ANY KIND, either express or implied. See the License for the specific language
603
- * governing permissions and limitations under the License.
604
- *
605
- * @author Brian Reavis <brian@thirdroute.com>
606
- */
607
-
451
+
608
452
  var Selectize = function($input, settings) {
609
453
  var key, i, n, self = this;
610
454
  $input[0].selectize = self;
611
-
455
+
612
456
  // setup default state
613
457
  $.extend(self, {
614
458
  settings : settings,
615
459
  $input : $input,
616
460
  tagType : $input[0].tagName.toLowerCase() === 'select' ? TAG_SELECT : TAG_INPUT,
617
-
461
+
462
+ eventNS : '.selectize' + (++Selectize.count),
618
463
  highlightedValue : null,
619
464
  isOpen : false,
620
465
  isDisabled : false,
@@ -634,10 +479,10 @@
634
479
  caretPos : 0,
635
480
  loading : 0,
636
481
  loadedSearches : {},
637
-
482
+
638
483
  $activeOption : null,
639
484
  $activeItems : [],
640
-
485
+
641
486
  optgroups : {},
642
487
  options : {},
643
488
  userOptions : {},
@@ -645,43 +490,50 @@
645
490
  renderCache : {},
646
491
  onSearchChange : debounce(self.onSearchChange, settings.loadThrottle)
647
492
  });
648
-
493
+
494
+ // search system
495
+ self.sifter = new Sifter(this.options, {diacritics: settings.diacritics});
496
+
649
497
  // build options table
650
498
  $.extend(self.options, build_hash_table(settings.valueField, settings.options));
651
499
  delete self.settings.options;
652
-
500
+
653
501
  // build optgroup table
654
502
  $.extend(self.optgroups, build_hash_table(settings.optgroupValueField, settings.optgroups));
655
503
  delete self.settings.optgroups;
656
-
504
+
657
505
  // option-dependent defaults
658
506
  self.settings.mode = self.settings.mode || (self.settings.maxItems === 1 ? 'single' : 'multi');
659
507
  if (typeof self.settings.hideSelected !== 'boolean') {
660
508
  self.settings.hideSelected = self.settings.mode === 'multi';
661
509
  }
662
-
663
- self.loadPlugins(self.settings.plugins);
510
+
511
+ self.initializePlugins(self.settings.plugins);
664
512
  self.setupCallbacks();
665
513
  self.setup();
666
514
  };
667
-
515
+
668
516
  // mixins
669
517
  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
670
-
518
+
671
519
  MicroEvent.mixin(Selectize);
672
- Plugins.mixin(Selectize, 'Selectize');
673
-
520
+ MicroPlugin.mixin(Selectize);
521
+
674
522
  // methods
675
523
  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
676
-
524
+
677
525
  $.extend(Selectize.prototype, {
678
-
526
+
679
527
  /**
680
528
  * Creates all elements and sets up event bindings.
681
529
  */
682
530
  setup: function() {
683
- var self = this;
684
- var settings = self.settings;
531
+ var self = this;
532
+ var settings = self.settings;
533
+ var eventNS = self.eventNS;
534
+ var $window = $(window);
535
+ var $document = $(document);
536
+
685
537
  var $wrapper;
686
538
  var $control;
687
539
  var $control_input;
@@ -693,43 +545,44 @@
693
545
  var timeout_focus;
694
546
  var tab_index;
695
547
  var classes;
696
-
548
+ var classes_plugins;
549
+
550
+ inputMode = self.settings.mode;
697
551
  tab_index = self.$input.attr('tabindex') || '';
698
552
  classes = self.$input.attr('class') || '';
699
- $wrapper = $('<div>').addClass(settings.theme).addClass(settings.wrapperClass).addClass(classes);
700
- $control = $('<div>').addClass(settings.inputClass).addClass('items').toggleClass('has-options', !$.isEmptyObject(self.options)).appendTo($wrapper);
701
- $control_input = $('<input type="text">').appendTo($control).attr('tabindex',tab_index);
553
+
554
+ $wrapper = $('<div>').addClass(settings.wrapperClass).addClass(classes).addClass(inputMode);
555
+ $control = $('<div>').addClass(settings.inputClass).addClass('items').appendTo($wrapper);
556
+ $control_input = $('<input type="text">').appendTo($control).attr('tabindex', tab_index);
702
557
  $dropdown_parent = $(settings.dropdownParent || $wrapper);
703
- $dropdown = $('<div>').addClass(settings.dropdownClass).hide().appendTo($dropdown_parent);
558
+ $dropdown = $('<div>').addClass(settings.dropdownClass).addClass(classes).addClass(inputMode).hide().appendTo($dropdown_parent);
704
559
  $dropdown_content = $('<div>').addClass(settings.dropdownContentClass).appendTo($dropdown);
705
-
560
+
706
561
  $wrapper.css({
707
562
  width: self.$input[0].style.width,
708
563
  display: self.$input.css('display')
709
564
  });
710
-
711
- if (self.plugins.length) {
712
- $wrapper.addClass('plugin-' + self.plugins.join(' plugin-'));
565
+
566
+ if (self.plugins.names.length) {
567
+ classes_plugins = 'plugin-' + self.plugins.names.join(' plugin-');
568
+ $wrapper.addClass(classes_plugins);
569
+ $dropdown.addClass(classes_plugins);
713
570
  }
714
-
715
- inputMode = self.settings.mode;
716
- $wrapper.toggleClass('single', inputMode === 'single');
717
- $wrapper.toggleClass('multi', inputMode === 'multi');
718
-
571
+
719
572
  if ((settings.maxItems === null || settings.maxItems > 1) && self.tagType === TAG_SELECT) {
720
573
  self.$input.attr('multiple', 'multiple');
721
574
  }
722
-
575
+
723
576
  if (self.settings.placeholder) {
724
577
  $control_input.attr('placeholder', settings.placeholder);
725
578
  }
726
-
579
+
727
580
  self.$wrapper = $wrapper;
728
581
  self.$control = $control;
729
582
  self.$control_input = $control_input;
730
583
  self.$dropdown = $dropdown;
731
584
  self.$dropdown_content = $dropdown_content;
732
-
585
+
733
586
  $control.on('mousedown', function(e) {
734
587
  if (!e.isDefaultPrevented()) {
735
588
  window.setTimeout(function() {
@@ -737,7 +590,7 @@
737
590
  }, 0);
738
591
  }
739
592
  });
740
-
593
+
741
594
  // necessary for mobile webkit devices (manual focus triggering
742
595
  // is ignored unless invoked within a click event)
743
596
  $control.on('click', function(e) {
@@ -745,12 +598,12 @@
745
598
  self.focus(true);
746
599
  }
747
600
  });
748
-
601
+
749
602
  $dropdown.on('mouseenter', '[data-selectable]', function() { return self.onOptionHover.apply(self, arguments); });
750
603
  $dropdown.on('mousedown', '[data-selectable]', function() { return self.onOptionSelect.apply(self, arguments); });
751
604
  watchChildEvent($control, 'mousedown', '*:not(input)', function() { return self.onItemSelect.apply(self, arguments); });
752
605
  autoGrow($control_input);
753
-
606
+
754
607
  $control_input.on({
755
608
  mousedown : function(e) { e.stopPropagation(); },
756
609
  keydown : function() { return self.onKeyDown.apply(self, arguments); },
@@ -760,73 +613,72 @@
760
613
  blur : function() { return self.onBlur.apply(self, arguments); },
761
614
  focus : function() { return self.onFocus.apply(self, arguments); }
762
615
  });
763
-
764
- $(document).on({
765
- keydown: function(e) {
766
- self.isCmdDown = e[IS_MAC ? 'metaKey' : 'ctrlKey'];
767
- self.isCtrlDown = e[IS_MAC ? 'altKey' : 'ctrlKey'];
768
- self.isShiftDown = e.shiftKey;
769
- },
770
- keyup: function(e) {
771
- if (e.keyCode === KEY_CTRL) self.isCtrlDown = false;
772
- if (e.keyCode === KEY_SHIFT) self.isShiftDown = false;
773
- if (e.keyCode === KEY_CMD) self.isCmdDown = false;
774
- },
775
- mousedown: function(e) {
776
- if (self.isFocused) {
777
- // prevent events on the dropdown scrollbar from causing the control to blur
778
- if (e.target === self.$dropdown[0] || e.target.parentNode === self.$dropdown[0]) {
779
- var ignoreFocus = self.ignoreFocus;
780
- self.ignoreFocus = true;
781
- window.setTimeout(function() {
782
- self.ignoreFocus = ignoreFocus;
783
- self.focus(false);
784
- }, 0);
785
- return;
786
- }
787
- // blur on click outside
788
- if (!self.$control.has(e.target).length && e.target !== self.$control[0]) {
789
- self.blur();
790
- }
616
+
617
+ $document.on('keydown' + eventNS, function(e) {
618
+ self.isCmdDown = e[IS_MAC ? 'metaKey' : 'ctrlKey'];
619
+ self.isCtrlDown = e[IS_MAC ? 'altKey' : 'ctrlKey'];
620
+ self.isShiftDown = e.shiftKey;
621
+ });
622
+
623
+ $document.on('keyup' + eventNS, function(e) {
624
+ if (e.keyCode === KEY_CTRL) self.isCtrlDown = false;
625
+ if (e.keyCode === KEY_SHIFT) self.isShiftDown = false;
626
+ if (e.keyCode === KEY_CMD) self.isCmdDown = false;
627
+ });
628
+
629
+ $document.on('mousedown' + eventNS, function(e) {
630
+ if (self.isFocused) {
631
+ // prevent events on the dropdown scrollbar from causing the control to blur
632
+ if (e.target === self.$dropdown[0] || e.target.parentNode === self.$dropdown[0]) {
633
+ var ignoreFocus = self.ignoreFocus;
634
+ self.ignoreFocus = true;
635
+ window.setTimeout(function() {
636
+ self.ignoreFocus = ignoreFocus;
637
+ self.focus(false);
638
+ }, 0);
639
+ return;
640
+ }
641
+ // blur on click outside
642
+ if (!self.$control.has(e.target).length && e.target !== self.$control[0]) {
643
+ self.blur();
791
644
  }
792
645
  }
793
646
  });
794
-
795
- $(window).on({
796
- 'scroll resize': function() {
797
- if (self.isOpen) {
798
- self.positionDropdown.apply(self, arguments);
799
- }
800
- },
801
- 'mousemove': function() {
802
- self.ignoreHover = false;
647
+
648
+ $window.on(['scroll' + eventNS, 'resize' + eventNS].join(' '), function() {
649
+ if (self.isOpen) {
650
+ self.positionDropdown.apply(self, arguments);
803
651
  }
804
652
  });
805
-
653
+ $window.on('mousemove' + eventNS, function() {
654
+ self.ignoreHover = false;
655
+ });
656
+
806
657
  self.$input.attr('tabindex',-1).hide().after(self.$wrapper);
807
-
658
+
808
659
  if ($.isArray(settings.items)) {
809
660
  self.setValue(settings.items);
810
661
  delete settings.items;
811
662
  }
812
-
663
+
813
664
  self.updateOriginalInput();
814
665
  self.refreshItems();
666
+ self.refreshClasses();
815
667
  self.updatePlaceholder();
816
668
  self.isSetup = true;
817
-
669
+
818
670
  if (self.$input.is(':disabled')) {
819
671
  self.disable();
820
672
  }
821
-
673
+
822
674
  self.trigger('initialize');
823
-
675
+
824
676
  // preload options
825
677
  if (settings.preload) {
826
678
  self.onSearchChange('');
827
679
  }
828
680
  },
829
-
681
+
830
682
  /**
831
683
  * Maps fired events to callbacks provided
832
684
  * in the settings used when creating the control.
@@ -845,7 +697,7 @@
845
697
  'dropdown_close' : 'onDropdownClose',
846
698
  'type' : 'onType'
847
699
  };
848
-
700
+
849
701
  for (key in callbacks) {
850
702
  if (callbacks.hasOwnProperty(key)) {
851
703
  fn = this.settings[callbacks[key]];
@@ -853,7 +705,7 @@
853
705
  }
854
706
  }
855
707
  },
856
-
708
+
857
709
  /**
858
710
  * Triggers a callback defined in the user-provided settings.
859
711
  * Events: onItemAdd, onOptionAdd, etc
@@ -867,7 +719,7 @@
867
719
  this.settings[event].apply(this, args);
868
720
  }
869
721
  },
870
-
722
+
871
723
  /**
872
724
  * Triggered on <input> keypress.
873
725
  *
@@ -883,7 +735,7 @@
883
735
  return false;
884
736
  }
885
737
  },
886
-
738
+
887
739
  /**
888
740
  * Triggered on <input> keydown.
889
741
  *
@@ -893,14 +745,14 @@
893
745
  onKeyDown: function(e) {
894
746
  var isInput = e.target === this.$control_input[0];
895
747
  var self = this;
896
-
748
+
897
749
  if (self.isLocked) {
898
750
  if (e.keyCode !== KEY_TAB) {
899
751
  e.preventDefault();
900
752
  }
901
753
  return;
902
754
  }
903
-
755
+
904
756
  switch (e.keyCode) {
905
757
  case KEY_A:
906
758
  if (self.isCmdDown) {
@@ -957,7 +809,7 @@
957
809
  return;
958
810
  }
959
811
  },
960
-
812
+
961
813
  /**
962
814
  * Triggered on <input> keyup.
963
815
  *
@@ -966,7 +818,7 @@
966
818
  */
967
819
  onKeyUp: function(e) {
968
820
  var self = this;
969
-
821
+
970
822
  if (self.isLocked) return e && e.preventDefault();
971
823
  var value = self.$control_input.val() || '';
972
824
  if (self.lastValue !== value) {
@@ -976,7 +828,7 @@
976
828
  self.trigger('type', value);
977
829
  }
978
830
  },
979
-
831
+
980
832
  /**
981
833
  * Invokes the user-provide option provider / loader.
982
834
  *
@@ -995,7 +847,7 @@
995
847
  fn.apply(self, [value, callback]);
996
848
  });
997
849
  },
998
-
850
+
999
851
  /**
1000
852
  * Triggered on <input> focus.
1001
853
  *
@@ -1004,7 +856,7 @@
1004
856
  */
1005
857
  onFocus: function(e) {
1006
858
  var self = this;
1007
-
859
+
1008
860
  self.isInputFocused = true;
1009
861
  self.isFocused = true;
1010
862
  if (self.isDisabled) {
@@ -1012,16 +864,16 @@
1012
864
  e.preventDefault();
1013
865
  return false;
1014
866
  }
1015
-
867
+
1016
868
  if (self.ignoreFocus) return;
1017
869
  if (self.settings.preload === 'focus') self.onSearchChange('');
1018
-
870
+
1019
871
  self.showInput();
1020
872
  self.setActiveItem(null);
1021
873
  self.refreshOptions(!!self.settings.openOnFocus);
1022
874
  self.refreshClasses();
1023
875
  },
1024
-
876
+
1025
877
  /**
1026
878
  * Triggered on <input> blur.
1027
879
  *
@@ -1032,7 +884,7 @@
1032
884
  var self = this;
1033
885
  self.isInputFocused = false;
1034
886
  if (self.ignoreFocus) return;
1035
-
887
+
1036
888
  self.close();
1037
889
  self.setTextboxValue('');
1038
890
  self.setActiveItem(null);
@@ -1041,7 +893,7 @@
1041
893
  self.isFocused = false;
1042
894
  self.refreshClasses();
1043
895
  },
1044
-
896
+
1045
897
  /**
1046
898
  * Triggered when the user rolls over
1047
899
  * an option in the autocomplete dropdown menu.
@@ -1053,7 +905,7 @@
1053
905
  if (this.ignoreHover) return;
1054
906
  this.setActiveOption(e.currentTarget, false);
1055
907
  },
1056
-
908
+
1057
909
  /**
1058
910
  * Triggered when the user clicks on an option
1059
911
  * in the autocomplete dropdown menu.
@@ -1063,11 +915,11 @@
1063
915
  */
1064
916
  onOptionSelect: function(e) {
1065
917
  var value, $target, $option, self = this;
1066
-
918
+
1067
919
  e.preventDefault && e.preventDefault();
1068
920
  e.stopPropagation && e.stopPropagation();
1069
921
  self.focus(false);
1070
-
922
+
1071
923
  $target = $(e.currentTarget);
1072
924
  if ($target.hasClass('create')) {
1073
925
  self.createItem();
@@ -1082,7 +934,7 @@
1082
934
  }
1083
935
  }
1084
936
  },
1085
-
937
+
1086
938
  /**
1087
939
  * Triggered when the user clicks on an item
1088
940
  * that has been selected.
@@ -1092,7 +944,7 @@
1092
944
  */
1093
945
  onItemSelect: function(e) {
1094
946
  var self = this;
1095
-
947
+
1096
948
  if (self.settings.mode === 'multi') {
1097
949
  e.preventDefault();
1098
950
  self.setActiveItem(e.currentTarget, e);
@@ -1100,7 +952,7 @@
1100
952
  self.hideInput();
1101
953
  }
1102
954
  },
1103
-
955
+
1104
956
  /**
1105
957
  * Invokes the provided method that provides
1106
958
  * results to a callback---which are then added
@@ -1111,7 +963,7 @@
1111
963
  load: function(fn) {
1112
964
  var self = this;
1113
965
  var $wrapper = self.$wrapper.addClass('loading');
1114
-
966
+
1115
967
  self.loading++;
1116
968
  fn.apply(self, [function(results) {
1117
969
  self.loading = Math.max(self.loading - 1, 0);
@@ -1126,7 +978,7 @@
1126
978
  self.trigger('load', results);
1127
979
  }]);
1128
980
  },
1129
-
981
+
1130
982
  /**
1131
983
  * Sets the input field of the control to the specified value.
1132
984
  *
@@ -1136,7 +988,7 @@
1136
988
  this.$control_input.val(value).triggerHandler('update');
1137
989
  this.lastValue = value;
1138
990
  },
1139
-
991
+
1140
992
  /**
1141
993
  * Returns the value of the control. If multiple items
1142
994
  * can be selected (e.g. <select multiple>), this returns
@@ -1152,7 +1004,7 @@
1152
1004
  return this.items.join(this.settings.delimiter);
1153
1005
  }
1154
1006
  },
1155
-
1007
+
1156
1008
  /**
1157
1009
  * Resets the selected items to the given value.
1158
1010
  *
@@ -1167,7 +1019,7 @@
1167
1019
  }
1168
1020
  });
1169
1021
  },
1170
-
1022
+
1171
1023
  /**
1172
1024
  * Sets the selected item.
1173
1025
  *
@@ -1179,9 +1031,9 @@
1179
1031
  var eventName;
1180
1032
  var i, idx, begin, end, item, swap;
1181
1033
  var $last;
1182
-
1034
+
1183
1035
  $item = $($item);
1184
-
1036
+
1185
1037
  // clear the active selection
1186
1038
  if (!$item.length) {
1187
1039
  $(self.$activeItems).removeClass('active');
@@ -1189,10 +1041,10 @@
1189
1041
  self.isFocused = self.isInputFocused;
1190
1042
  return;
1191
1043
  }
1192
-
1044
+
1193
1045
  // modify selection
1194
1046
  eventName = e && e.type.toLowerCase();
1195
-
1047
+
1196
1048
  if (eventName === 'mousedown' && self.isShiftDown && self.$activeItems.length) {
1197
1049
  $last = self.$control.children('.active:last');
1198
1050
  begin = Array.prototype.indexOf.apply(self.$control[0].childNodes, [$last[0]]);
@@ -1222,10 +1074,10 @@
1222
1074
  $(self.$activeItems).removeClass('active');
1223
1075
  self.$activeItems = [$item.addClass('active')[0]];
1224
1076
  }
1225
-
1077
+
1226
1078
  self.isFocused = !!self.$activeItems.length || self.isInputFocused;
1227
1079
  },
1228
-
1080
+
1229
1081
  /**
1230
1082
  * Sets the selected item in the dropdown menu
1231
1083
  * of available options.
@@ -1238,33 +1090,33 @@
1238
1090
  var height_menu, height_item, y;
1239
1091
  var scroll_top, scroll_bottom;
1240
1092
  var self = this;
1241
-
1093
+
1242
1094
  if (self.$activeOption) self.$activeOption.removeClass('active');
1243
1095
  self.$activeOption = null;
1244
-
1096
+
1245
1097
  $option = $($option);
1246
1098
  if (!$option.length) return;
1247
-
1099
+
1248
1100
  self.$activeOption = $option.addClass('active');
1249
-
1101
+
1250
1102
  if (scroll || !isset(scroll)) {
1251
-
1103
+
1252
1104
  height_menu = self.$dropdown_content.height();
1253
1105
  height_item = self.$activeOption.outerHeight(true);
1254
1106
  scroll = self.$dropdown_content.scrollTop() || 0;
1255
1107
  y = self.$activeOption.offset().top - self.$dropdown_content.offset().top + scroll;
1256
1108
  scroll_top = y;
1257
1109
  scroll_bottom = y - height_menu + height_item;
1258
-
1110
+
1259
1111
  if (y + height_item > height_menu - scroll) {
1260
1112
  self.$dropdown_content.stop().animate({scrollTop: scroll_bottom}, animate ? self.settings.scrollDuration : 0);
1261
1113
  } else if (y < scroll) {
1262
1114
  self.$dropdown_content.stop().animate({scrollTop: scroll_top}, animate ? self.settings.scrollDuration : 0);
1263
1115
  }
1264
-
1116
+
1265
1117
  }
1266
1118
  },
1267
-
1119
+
1268
1120
  /**
1269
1121
  * Selects all items (CTRL + A).
1270
1122
  */
@@ -1273,20 +1125,20 @@
1273
1125
  this.isFocused = true;
1274
1126
  if (this.$activeItems.length) this.hideInput();
1275
1127
  },
1276
-
1128
+
1277
1129
  /**
1278
1130
  * Hides the input element out of view, while
1279
1131
  * retaining its focus.
1280
1132
  */
1281
1133
  hideInput: function() {
1282
1134
  var self = this;
1283
-
1135
+
1284
1136
  self.close();
1285
1137
  self.setTextboxValue('');
1286
1138
  self.$control_input.css({opacity: 0, position: 'absolute', left: -10000});
1287
1139
  self.isInputHidden = true;
1288
1140
  },
1289
-
1141
+
1290
1142
  /**
1291
1143
  * Restores input visibility.
1292
1144
  */
@@ -1294,7 +1146,7 @@
1294
1146
  this.$control_input.css({opacity: 1, position: 'relative', left: 0});
1295
1147
  this.isInputHidden = false;
1296
1148
  },
1297
-
1149
+
1298
1150
  /**
1299
1151
  * Gives the control focus. If "trigger" is falsy,
1300
1152
  * focus handlers won't be fired--causing the focus
@@ -1304,7 +1156,7 @@
1304
1156
  */
1305
1157
  focus: function(trigger) {
1306
1158
  var self = this;
1307
-
1159
+
1308
1160
  if (self.isDisabled) return;
1309
1161
  self.ignoreFocus = true;
1310
1162
  self.$control_input[0].focus();
@@ -1314,132 +1166,48 @@
1314
1166
  if (trigger) self.onFocus();
1315
1167
  }, 0);
1316
1168
  },
1317
-
1169
+
1318
1170
  /**
1319
1171
  * Forces the control out of focus.
1320
1172
  */
1321
1173
  blur: function() {
1322
1174
  this.$control_input.trigger('blur');
1323
1175
  },
1324
-
1176
+
1325
1177
  /**
1326
- * Splits a search string into an array of
1327
- * individual regexps to be used to match results.
1178
+ * Returns a function that scores an object
1179
+ * to show how good of a match it is to the
1180
+ * provided query.
1328
1181
  *
1329
1182
  * @param {string} query
1330
- * @returns {array}
1183
+ * @param {object} options
1184
+ * @return {function}
1331
1185
  */
1332
- parseSearchTokens: function(query) {
1333
- query = $.trim(String(query || '').toLowerCase());
1334
- if (!query || !query.length) return [];
1335
-
1336
- var i, n, regex, letter;
1337
- var tokens = [];
1338
- var words = query.split(/ +/);
1339
-
1340
- for (i = 0, n = words.length; i < n; i++) {
1341
- regex = escape_regex(words[i]);
1342
- if (this.settings.diacritics) {
1343
- for (letter in DIACRITICS) {
1344
- if (DIACRITICS.hasOwnProperty(letter)) {
1345
- regex = regex.replace(new RegExp(letter, 'g'), DIACRITICS[letter]);
1346
- }
1347
- }
1348
- }
1349
- tokens.push({
1350
- string : words[i],
1351
- regex : new RegExp(regex, 'i')
1352
- });
1353
- }
1354
-
1355
- return tokens;
1186
+ getScoreFunction: function(query) {
1187
+ return this.sifter.getScoreFunction(query, this.getSearchOptions());
1356
1188
  },
1357
-
1189
+
1358
1190
  /**
1359
- * Returns a function to be used to score individual results.
1360
- * Results will be sorted by the score (descending). Scores less
1361
- * than or equal to zero (no match) will not be included in the results.
1191
+ * Returns search options for sifter (the system
1192
+ * for scoring and sorting results).
1362
1193
  *
1363
- * @param {object} data
1364
- * @param {object} search
1365
- * @returns {function}
1194
+ * @see https://github.com/brianreavis/sifter.js
1195
+ * @return {object}
1366
1196
  */
1367
- getScoreFunction: function(search) {
1368
- var self = this;
1369
- var tokens = search.tokens;
1370
-
1371
- var calculateFieldScore = (function() {
1372
- if (!tokens.length) {
1373
- return function() { return 0; };
1374
- } else if (tokens.length === 1) {
1375
- return function(value) {
1376
- var score, pos;
1377
-
1378
- value = String(value || '').toLowerCase();
1379
- pos = value.search(tokens[0].regex);
1380
- if (pos === -1) return 0;
1381
- score = tokens[0].string.length / value.length;
1382
- if (pos === 0) score += 0.5;
1383
- return score;
1384
- };
1385
- } else {
1386
- return function(value) {
1387
- var score, pos, i, j;
1388
-
1389
- value = String(value || '').toLowerCase();
1390
- score = 0;
1391
- for (i = 0, j = tokens.length; i < j; i++) {
1392
- pos = value.search(tokens[i].regex);
1393
- if (pos === -1) return 0;
1394
- if (pos === 0) score += 0.5;
1395
- score += tokens[i].string.length / value.length;
1396
- }
1397
- return score / tokens.length;
1398
- };
1399
- }
1400
- })();
1401
-
1402
- var calculateScore = (function() {
1403
- var fields = self.settings.searchField;
1404
- if (typeof fields === 'string') {
1405
- fields = [fields];
1406
- }
1407
- if (!fields || !fields.length) {
1408
- return function() { return 0; };
1409
- } else if (fields.length === 1) {
1410
- var field = fields[0];
1411
- return function(data) {
1412
- if (!data.hasOwnProperty(field)) return 0;
1413
- return calculateFieldScore(data[field]);
1414
- };
1415
- } else {
1416
- return function(data) {
1417
- var n = 0;
1418
- var score = 0;
1419
- for (var i = 0, j = fields.length; i < j; i++) {
1420
- if (data.hasOwnProperty(fields[i])) {
1421
- score += calculateFieldScore(data[fields[i]]);
1422
- n++;
1423
- }
1424
- }
1425
- return score / n;
1426
- };
1427
- }
1428
- })();
1429
-
1430
- return calculateScore;
1197
+ getSearchOptions: function() {
1198
+ var settings = this.settings;
1199
+ var fields = settings.searchField;
1200
+
1201
+ return {
1202
+ fields : $.isArray(fields) ? fields : [fields],
1203
+ sort : settings.sortField,
1204
+ direction : settings.sortDirection,
1205
+ };
1431
1206
  },
1432
-
1207
+
1433
1208
  /**
1434
1209
  * Searches through available options and returns
1435
- * a sorted array of matches. Includes options that
1436
- * have already been selected.
1437
- *
1438
- * The `settings` parameter can contain:
1439
- *
1440
- * - searchField
1441
- * - sortField
1442
- * - sortDirection
1210
+ * a sorted array of matches.
1443
1211
  *
1444
1212
  * Returns an object containing:
1445
1213
  *
@@ -1449,109 +1217,43 @@
1449
1217
  * - items {array}
1450
1218
  *
1451
1219
  * @param {string} query
1452
- * @param {object} settings
1453
1220
  * @returns {object}
1454
1221
  */
1455
- search: function(query, settings) {
1456
- var self = this;
1457
- var value, score, search, calculateScore;
1458
-
1459
- settings = settings || {};
1460
- query = $.trim(String(query || '').toLowerCase());
1461
-
1222
+ search: function(query) {
1223
+ var i, value, score, result, calculateScore;
1224
+ var self = this;
1225
+ var settings = self.settings;
1226
+ var options = this.getSearchOptions();
1227
+
1228
+ // validate user-provided result scoring function
1229
+ if (settings.score) {
1230
+ calculateScore = self.settings.score.apply(this, [query]);
1231
+ if (typeof calculateScore !== 'function') {
1232
+ throw new Error('Selectize "score" setting must be a function that returns a function');
1233
+ }
1234
+ }
1235
+
1236
+ // perform search
1462
1237
  if (query !== self.lastQuery) {
1463
1238
  self.lastQuery = query;
1464
-
1465
- search = {
1466
- query : query,
1467
- tokens : self.parseSearchTokens(query),
1468
- total : 0,
1469
- items : []
1470
- };
1471
-
1472
- // generate result scoring function
1473
- if (self.settings.score) {
1474
- calculateScore = self.settings.score.apply(this, [search]);
1475
- if (typeof calculateScore !== 'function') {
1476
- throw new Error('Selectize "score" setting must be a function that returns a function');
1477
- }
1478
- } else {
1479
- calculateScore = self.getScoreFunction(search);
1480
- }
1481
-
1482
- // perform search and sort
1483
- if (query.length) {
1484
- for (value in self.options) {
1485
- if (self.options.hasOwnProperty(value)) {
1486
- score = calculateScore(self.options[value]);
1487
- if (score > 0) {
1488
- search.items.push({
1489
- score: score,
1490
- value: value
1491
- });
1492
- }
1493
- }
1494
- }
1495
- search.items.sort(function(a, b) {
1496
- return b.score - a.score;
1497
- });
1498
- } else {
1499
- for (value in self.options) {
1500
- if (self.options.hasOwnProperty(value)) {
1501
- search.items.push({
1502
- score: 1,
1503
- value: value
1504
- });
1505
- }
1506
- }
1507
- if (self.settings.sortField) {
1508
- search.items.sort((function() {
1509
- var field = self.settings.sortField;
1510
- var multiplier = self.settings.sortDirection === 'desc' ? -1 : 1;
1511
- return function(a, b) {
1512
- a = a && String(self.options[a.value][field] || '').toLowerCase();
1513
- b = b && String(self.options[b.value][field] || '').toLowerCase();
1514
- if (a > b) return 1 * multiplier;
1515
- if (b > a) return -1 * multiplier;
1516
- return 0;
1517
- };
1518
- })());
1519
- }
1520
- }
1521
- self.currentResults = search;
1239
+ result = self.sifter.search(query, $.extend(options, {score: calculateScore}));
1240
+ self.currentResults = result;
1522
1241
  } else {
1523
- search = $.extend(true, {}, self.currentResults);
1524
- }
1525
-
1526
- // apply limits and return
1527
- return self.prepareResults(search, settings);
1528
- },
1529
-
1530
- /**
1531
- * Filters out any items that have already been selected
1532
- * and applies search limits.
1533
- *
1534
- * @param {object} results
1535
- * @param {object} settings
1536
- * @returns {object}
1537
- */
1538
- prepareResults: function(search, settings) {
1539
- if (this.settings.hideSelected) {
1540
- for (var i = search.items.length - 1; i >= 0; i--) {
1541
- if (this.items.indexOf(String(search.items[i].value)) !== -1) {
1542
- search.items.splice(i, 1);
1242
+ result = $.extend(true, {}, self.currentResults);
1243
+ }
1244
+
1245
+ // filter out selected items
1246
+ if (settings.hideSelected) {
1247
+ for (i = result.items.length - 1; i >= 0; i--) {
1248
+ if (self.items.indexOf(hash_key(result.items[i].id)) !== -1) {
1249
+ result.items.splice(i, 1);
1543
1250
  }
1544
1251
  }
1545
1252
  }
1546
-
1547
- search.total = search.items.length;
1548
- if (typeof settings.limit === 'number') {
1549
- search.items = search.items.slice(0, settings.limit);
1550
- }
1551
-
1552
- return search;
1253
+
1254
+ return result;
1553
1255
  },
1554
-
1256
+
1555
1257
  /**
1556
1258
  * Refreshes the list of available options shown
1557
1259
  * in the autocomplete dropdown menu.
@@ -1562,24 +1264,24 @@
1562
1264
  if (typeof triggerDropdown === 'undefined') {
1563
1265
  triggerDropdown = true;
1564
1266
  }
1565
-
1267
+
1566
1268
  var self = this;
1567
1269
  var i, n, groups, groups_order, option, optgroup, html, html_children;
1568
1270
  var hasCreateOption;
1569
1271
  var query = self.$control_input.val();
1570
- var results = self.search(query, {});
1272
+ var results = self.search(query);
1571
1273
  var $active, $create;
1572
1274
  var $dropdown_content = self.$dropdown_content;
1573
-
1275
+
1574
1276
  // build markup
1575
1277
  n = results.items.length;
1576
1278
  if (typeof self.settings.maxOptions === 'number') {
1577
1279
  n = Math.min(n, self.settings.maxOptions);
1578
1280
  }
1579
-
1281
+
1580
1282
  // render and group available options individually
1581
1283
  groups = {};
1582
-
1284
+
1583
1285
  if (self.settings.optgroupOrder) {
1584
1286
  groups_order = self.settings.optgroupOrder;
1585
1287
  for (i = 0; i < groups_order.length; i++) {
@@ -1588,9 +1290,9 @@
1588
1290
  } else {
1589
1291
  groups_order = [];
1590
1292
  }
1591
-
1293
+
1592
1294
  for (i = 0; i < n; i++) {
1593
- option = self.options[results.items[i].value];
1295
+ option = self.options[results.items[i].id];
1594
1296
  optgroup = option[self.settings.optgroupField] || '';
1595
1297
  if (!self.optgroups.hasOwnProperty(optgroup)) {
1596
1298
  optgroup = '';
@@ -1601,7 +1303,7 @@
1601
1303
  }
1602
1304
  groups[optgroup].push(self.render('option', option));
1603
1305
  }
1604
-
1306
+
1605
1307
  // render optgroup headers & join groups
1606
1308
  html = [];
1607
1309
  for (i = 0, n = groups_order.length; i < n; i++) {
@@ -1618,30 +1320,30 @@
1618
1320
  html.push(groups[optgroup].join(''));
1619
1321
  }
1620
1322
  }
1621
-
1323
+
1622
1324
  $dropdown_content.html(html.join(''));
1623
-
1325
+
1624
1326
  // highlight matching terms inline
1625
1327
  if (self.settings.highlight && results.query.length && results.tokens.length) {
1626
1328
  for (i = 0, n = results.tokens.length; i < n; i++) {
1627
1329
  highlight($dropdown_content, results.tokens[i].regex);
1628
1330
  }
1629
1331
  }
1630
-
1332
+
1631
1333
  // add "selected" class to selected options
1632
1334
  if (!self.settings.hideSelected) {
1633
1335
  for (i = 0, n = self.items.length; i < n; i++) {
1634
1336
  self.getOption(self.items[i]).addClass('selected');
1635
1337
  }
1636
1338
  }
1637
-
1339
+
1638
1340
  // add create option
1639
1341
  hasCreateOption = self.settings.create && results.query.length;
1640
1342
  if (hasCreateOption) {
1641
1343
  $dropdown_content.prepend(self.render('option_create', {input: query}));
1642
1344
  $create = $($dropdown_content[0].childNodes[0]);
1643
1345
  }
1644
-
1346
+
1645
1347
  // activate
1646
1348
  self.hasOptions = results.items.length > 0 || hasCreateOption;
1647
1349
  if (self.hasOptions) {
@@ -1661,7 +1363,7 @@
1661
1363
  if (triggerDropdown && self.isOpen) { self.close(); }
1662
1364
  }
1663
1365
  },
1664
-
1366
+
1665
1367
  /**
1666
1368
  * Adds an available option. If it already exists,
1667
1369
  * nothing will happen. Note: this does not refresh
@@ -1670,31 +1372,29 @@
1670
1372
  *
1671
1373
  * Usage:
1672
1374
  *
1673
- * this.addOption(value, data)
1674
1375
  * this.addOption(data)
1675
1376
  *
1676
- * @param {string} value
1677
1377
  * @param {object} data
1678
1378
  */
1679
- addOption: function(value, data) {
1680
- var i, n, optgroup, self = this;
1681
-
1682
- if ($.isArray(value)) {
1683
- for (i = 0, n = value.length; i < n; i++) {
1684
- self.addOption(value[i][self.settings.valueField], value[i]);
1379
+ addOption: function(data) {
1380
+ var i, n, optgroup, value, self = this;
1381
+
1382
+ if ($.isArray(data)) {
1383
+ for (i = 0, n = data.length; i < n; i++) {
1384
+ self.addOption(data[i]);
1685
1385
  }
1686
1386
  return;
1687
1387
  }
1688
-
1689
- value = hash_key(value);
1690
- if (self.options.hasOwnProperty(value)) return;
1691
-
1388
+
1389
+ value = hash_key(data[self.settings.valueField]);
1390
+ if (!value || self.options.hasOwnProperty(value)) return;
1391
+
1692
1392
  self.userOptions[value] = true;
1693
1393
  self.options[value] = data;
1694
1394
  self.lastQuery = null;
1695
1395
  self.trigger('option_add', value, data);
1696
1396
  },
1697
-
1397
+
1698
1398
  /**
1699
1399
  * Registers a new optgroup for options
1700
1400
  * to be bucketed into.
@@ -1706,7 +1406,7 @@
1706
1406
  this.optgroups[id] = data;
1707
1407
  this.trigger('optgroup_add', value, data);
1708
1408
  },
1709
-
1409
+
1710
1410
  /**
1711
1411
  * Updates an option available for selection. If
1712
1412
  * it is visible in the selected items or options
@@ -1719,14 +1419,14 @@
1719
1419
  var self = this;
1720
1420
  var $item, $item_new;
1721
1421
  var value_new, index_item, cache_items, cache_options;
1722
-
1422
+
1723
1423
  value = hash_key(value);
1724
1424
  value_new = hash_key(data[self.settings.valueField]);
1725
-
1425
+
1726
1426
  // sanity checks
1727
1427
  if (!self.options.hasOwnProperty(value)) return;
1728
1428
  if (!value_new) throw new Error('Value must be set in option data');
1729
-
1429
+
1730
1430
  // update references
1731
1431
  if (value_new !== value) {
1732
1432
  delete self.options[value];
@@ -1736,11 +1436,11 @@
1736
1436
  }
1737
1437
  }
1738
1438
  self.options[value_new] = data;
1739
-
1439
+
1740
1440
  // invalidate render cache
1741
1441
  cache_items = self.renderCache['item'];
1742
1442
  cache_options = self.renderCache['option'];
1743
-
1443
+
1744
1444
  if (isset(cache_items)) {
1745
1445
  delete cache_items[value];
1746
1446
  delete cache_items[value_new];
@@ -1749,7 +1449,7 @@
1749
1449
  delete cache_options[value];
1750
1450
  delete cache_options[value_new];
1751
1451
  }
1752
-
1452
+
1753
1453
  // update the item if it's selected
1754
1454
  if (self.items.indexOf(value_new) !== -1) {
1755
1455
  $item = self.getItem(value);
@@ -1757,13 +1457,13 @@
1757
1457
  if ($item.hasClass('active')) $item_new.addClass('active');
1758
1458
  $item.replaceWith($item_new);
1759
1459
  }
1760
-
1460
+
1761
1461
  // update dropdown contents
1762
1462
  if (self.isOpen) {
1763
1463
  self.refreshOptions(false);
1764
1464
  }
1765
1465
  },
1766
-
1466
+
1767
1467
  /**
1768
1468
  * Removes a single option.
1769
1469
  *
@@ -1771,7 +1471,7 @@
1771
1471
  */
1772
1472
  removeOption: function(value) {
1773
1473
  var self = this;
1774
-
1474
+
1775
1475
  value = hash_key(value);
1776
1476
  delete self.userOptions[value];
1777
1477
  delete self.options[value];
@@ -1779,21 +1479,21 @@
1779
1479
  self.trigger('option_remove', value);
1780
1480
  self.removeItem(value);
1781
1481
  },
1782
-
1482
+
1783
1483
  /**
1784
1484
  * Clears all options.
1785
1485
  */
1786
1486
  clearOptions: function() {
1787
1487
  var self = this;
1788
-
1488
+
1789
1489
  self.loadedSearches = {};
1790
1490
  self.userOptions = {};
1791
- self.options = {};
1491
+ self.options = self.sifter.items = {};
1792
1492
  self.lastQuery = null;
1793
1493
  self.trigger('option_clear');
1794
1494
  self.clear();
1795
1495
  },
1796
-
1496
+
1797
1497
  /**
1798
1498
  * Returns the jQuery element of the option
1799
1499
  * matching the given value.
@@ -1805,7 +1505,7 @@
1805
1505
  value = hash_key(value);
1806
1506
  return value ? this.$dropdown_content.find('[data-selectable]').filter('[data-value="' + escape_quotes(value) + '"]:first') : $();
1807
1507
  },
1808
-
1508
+
1809
1509
  /**
1810
1510
  * Returns the jQuery element of the next or
1811
1511
  * previous selectable option.
@@ -1817,10 +1517,10 @@
1817
1517
  getAdjacentOption: function($option, direction) {
1818
1518
  var $options = this.$dropdown.find('[data-selectable]');
1819
1519
  var index = $options.index($option) + direction;
1820
-
1520
+
1821
1521
  return index >= 0 && index < $options.length ? $options.eq(index) : $();
1822
1522
  },
1823
-
1523
+
1824
1524
  /**
1825
1525
  * Returns the jQuery element of the item
1826
1526
  * matching the given value.
@@ -1831,7 +1531,7 @@
1831
1531
  getItem: function(value) {
1832
1532
  return this.$control.children('[data-value="' + escape_quotes(hash_key(value)) + '"]');
1833
1533
  },
1834
-
1534
+
1835
1535
  /**
1836
1536
  * "Selects" an item. Adds it to the list
1837
1537
  * at the current caret position.
@@ -1845,20 +1545,20 @@
1845
1545
  var inputMode = self.settings.mode;
1846
1546
  var i, active, options, value_next;
1847
1547
  value = hash_key(value);
1848
-
1548
+
1849
1549
  if (inputMode === 'single') self.clear();
1850
1550
  if (inputMode === 'multi' && self.isFull()) return;
1851
1551
  if (self.items.indexOf(value) !== -1) return;
1852
1552
  if (!self.options.hasOwnProperty(value)) return;
1853
-
1553
+
1854
1554
  $item = $(self.render('item', self.options[value]));
1855
1555
  self.items.splice(self.caretPos, 0, value);
1856
1556
  self.insertAtCaret($item);
1857
1557
  self.refreshClasses();
1858
-
1558
+
1859
1559
  if (self.isSetup) {
1860
1560
  options = self.$dropdown_content.find('[data-selectable]');
1861
-
1561
+
1862
1562
  // update menu / remove the option
1863
1563
  $option = self.getOption(value);
1864
1564
  value_next = self.getAdjacentOption($option, 1).attr('data-value');
@@ -1866,14 +1566,14 @@
1866
1566
  if (value_next) {
1867
1567
  self.setActiveOption(self.getOption(value_next));
1868
1568
  }
1869
-
1569
+
1870
1570
  // hide the menu if the maximum number of items have been selected or no options are left
1871
1571
  if (!options.length || (self.settings.maxItems !== null && self.items.length >= self.settings.maxItems)) {
1872
1572
  self.close();
1873
1573
  } else {
1874
1574
  self.positionDropdown();
1875
1575
  }
1876
-
1576
+
1877
1577
  // restore focus to input
1878
1578
  if (self.isFocused) {
1879
1579
  window.setTimeout(function() {
@@ -1886,14 +1586,14 @@
1886
1586
  }
1887
1587
  }, 0);
1888
1588
  }
1889
-
1589
+
1890
1590
  self.updatePlaceholder();
1891
1591
  self.trigger('item_add', value, $item);
1892
1592
  self.updateOriginalInput();
1893
1593
  }
1894
1594
  });
1895
1595
  },
1896
-
1596
+
1897
1597
  /**
1898
1598
  * Removes the selected item matching
1899
1599
  * the provided value.
@@ -1903,28 +1603,28 @@
1903
1603
  removeItem: function(value) {
1904
1604
  var self = this;
1905
1605
  var $item, i, idx;
1906
-
1606
+
1907
1607
  $item = (typeof value === 'object') ? value : self.getItem(value);
1908
1608
  value = hash_key($item.attr('data-value'));
1909
1609
  i = self.items.indexOf(value);
1910
-
1610
+
1911
1611
  if (i !== -1) {
1912
1612
  $item.remove();
1913
1613
  if ($item.hasClass('active')) {
1914
1614
  idx = self.$activeItems.indexOf($item[0]);
1915
1615
  self.$activeItems.splice(idx, 1);
1916
1616
  }
1917
-
1617
+
1918
1618
  self.items.splice(i, 1);
1919
1619
  self.lastQuery = null;
1920
1620
  if (!self.settings.persist && self.userOptions.hasOwnProperty(value)) {
1921
1621
  self.removeOption(value);
1922
1622
  }
1923
-
1623
+
1924
1624
  if (i < self.caretPos) {
1925
1625
  self.setCaret(self.caretPos - 1);
1926
1626
  }
1927
-
1627
+
1928
1628
  self.refreshClasses();
1929
1629
  self.updatePlaceholder();
1930
1630
  self.updateOriginalInput();
@@ -1932,7 +1632,7 @@
1932
1632
  self.trigger('item_remove', value);
1933
1633
  }
1934
1634
  },
1935
-
1635
+
1936
1636
  /**
1937
1637
  * Invokes the `create` method provided in the
1938
1638
  * selectize options that should provide the data
@@ -1947,52 +1647,52 @@
1947
1647
  var caret = self.caretPos;
1948
1648
  if (!input.length) return;
1949
1649
  self.lock();
1950
-
1650
+
1951
1651
  var setup = (typeof self.settings.create === 'function') ? this.settings.create : function(input) {
1952
1652
  var data = {};
1953
1653
  data[self.settings.labelField] = input;
1954
1654
  data[self.settings.valueField] = input;
1955
1655
  return data;
1956
1656
  };
1957
-
1657
+
1958
1658
  var create = once(function(data) {
1959
1659
  self.unlock();
1960
1660
  self.focus(false);
1961
-
1661
+
1962
1662
  if (!data || typeof data !== 'object') return;
1963
1663
  var value = hash_key(data[self.settings.valueField]);
1964
1664
  if (!value) return;
1965
-
1665
+
1966
1666
  self.setTextboxValue('');
1967
- self.addOption(value, data);
1667
+ self.addOption(data);
1968
1668
  self.setCaret(caret);
1969
1669
  self.addItem(value);
1970
1670
  self.refreshOptions(self.settings.mode !== 'single');
1971
1671
  self.focus(false);
1972
1672
  });
1973
-
1673
+
1974
1674
  var output = setup.apply(this, [input, create]);
1975
1675
  if (typeof output !== 'undefined') {
1976
1676
  create(output);
1977
1677
  }
1978
1678
  },
1979
-
1679
+
1980
1680
  /**
1981
1681
  * Re-renders the selected item lists.
1982
1682
  */
1983
1683
  refreshItems: function() {
1984
1684
  this.lastQuery = null;
1985
-
1685
+
1986
1686
  if (this.isSetup) {
1987
1687
  for (var i = 0; i < this.items.length; i++) {
1988
1688
  this.addItem(this.items);
1989
1689
  }
1990
1690
  }
1991
-
1691
+
1992
1692
  this.refreshClasses();
1993
1693
  this.updateOriginalInput();
1994
1694
  },
1995
-
1695
+
1996
1696
  /**
1997
1697
  * Updates all state-dependent CSS classes.
1998
1698
  */
@@ -2006,10 +1706,11 @@
2006
1706
  .toggleClass('locked', isLocked)
2007
1707
  .toggleClass('full', isFull).toggleClass('not-full', !isFull)
2008
1708
  .toggleClass('dropdown-active', self.isOpen)
1709
+ .toggleClass('has-options', !$.isEmptyObject(self.options))
2009
1710
  .toggleClass('has-items', self.items.length > 0);
2010
1711
  this.$control_input.data('grow', !isFull && !isLocked);
2011
1712
  },
2012
-
1713
+
2013
1714
  /**
2014
1715
  * Determines whether or not more items can be added
2015
1716
  * to the control without exceeding the user-defined maximum.
@@ -2019,14 +1720,14 @@
2019
1720
  isFull: function() {
2020
1721
  return this.settings.maxItems !== null && this.items.length >= this.settings.maxItems;
2021
1722
  },
2022
-
1723
+
2023
1724
  /**
2024
1725
  * Refreshes the original <select> or <input>
2025
1726
  * element to reflect the current state.
2026
1727
  */
2027
1728
  updateOriginalInput: function() {
2028
1729
  var i, n, options, self = this;
2029
-
1730
+
2030
1731
  if (self.$input[0].tagName.toLowerCase() === 'select') {
2031
1732
  options = [];
2032
1733
  for (i = 0, n = self.items.length; i < n; i++) {
@@ -2039,13 +1740,13 @@
2039
1740
  } else {
2040
1741
  self.$input.val(self.getValue());
2041
1742
  }
2042
-
1743
+
2043
1744
  self.$input.trigger('change');
2044
1745
  if (self.isSetup) {
2045
1746
  self.trigger('change', self.$input.val());
2046
1747
  }
2047
1748
  },
2048
-
1749
+
2049
1750
  /**
2050
1751
  * Shows/hide the input placeholder depending
2051
1752
  * on if there items in the list already.
@@ -2053,7 +1754,7 @@
2053
1754
  updatePlaceholder: function() {
2054
1755
  if (!this.settings.placeholder) return;
2055
1756
  var $input = this.$control_input;
2056
-
1757
+
2057
1758
  if (this.items.length) {
2058
1759
  $input.removeAttr('placeholder');
2059
1760
  } else {
@@ -2061,14 +1762,14 @@
2061
1762
  }
2062
1763
  $input.triggerHandler('update');
2063
1764
  },
2064
-
1765
+
2065
1766
  /**
2066
1767
  * Shows the autocomplete dropdown containing
2067
1768
  * the available options.
2068
1769
  */
2069
1770
  open: function() {
2070
1771
  var self = this;
2071
-
1772
+
2072
1773
  if (self.isLocked || self.isOpen || (self.settings.mode === 'multi' && self.isFull())) return;
2073
1774
  self.focus(true);
2074
1775
  self.isOpen = true;
@@ -2078,13 +1779,13 @@
2078
1779
  self.$dropdown.css({visibility: 'visible'});
2079
1780
  self.trigger('dropdown_open', this.$dropdown);
2080
1781
  },
2081
-
1782
+
2082
1783
  /**
2083
1784
  * Closes the autocomplete dropdown menu.
2084
1785
  */
2085
1786
  close: function() {
2086
1787
  var self = this;
2087
-
1788
+
2088
1789
  if (!self.isOpen) return;
2089
1790
  self.$dropdown.hide();
2090
1791
  self.setActiveOption(null);
@@ -2092,7 +1793,7 @@
2092
1793
  self.refreshClasses();
2093
1794
  self.trigger('dropdown_close', self.$dropdown);
2094
1795
  },
2095
-
1796
+
2096
1797
  /**
2097
1798
  * Calculates and applies the appropriate
2098
1799
  * position of the dropdown.
@@ -2101,21 +1802,21 @@
2101
1802
  var $control = this.$control;
2102
1803
  var offset = this.settings.dropdownParent === 'body' ? $control.offset() : $control.position();
2103
1804
  offset.top += $control.outerHeight(true);
2104
-
1805
+
2105
1806
  this.$dropdown.css({
2106
1807
  width : $control.outerWidth(),
2107
1808
  top : offset.top,
2108
1809
  left : offset.left
2109
1810
  });
2110
1811
  },
2111
-
1812
+
2112
1813
  /**
2113
1814
  * Resets / clears all selected items
2114
1815
  * from the control.
2115
1816
  */
2116
1817
  clear: function() {
2117
1818
  var self = this;
2118
-
1819
+
2119
1820
  if (!self.items.length) return;
2120
1821
  self.$control.children(':not(input)').remove();
2121
1822
  self.items = [];
@@ -2126,7 +1827,7 @@
2126
1827
  self.showInput();
2127
1828
  self.trigger('clear');
2128
1829
  },
2129
-
1830
+
2130
1831
  /**
2131
1832
  * A helper method for inserting an element
2132
1833
  * at the current caret position.
@@ -2142,7 +1843,7 @@
2142
1843
  }
2143
1844
  this.setCaret(caret + 1);
2144
1845
  },
2145
-
1846
+
2146
1847
  /**
2147
1848
  * Removes the current selected item(s).
2148
1849
  *
@@ -2152,22 +1853,22 @@
2152
1853
  deleteSelection: function(e) {
2153
1854
  var i, n, direction, selection, values, caret, option_select, $option_select, $tail;
2154
1855
  var self = this;
2155
-
1856
+
2156
1857
  direction = (e && e.keyCode === KEY_BACKSPACE) ? -1 : 1;
2157
1858
  selection = getSelection(self.$control_input[0]);
2158
-
1859
+
2159
1860
  if (self.$activeOption && !self.settings.hideSelected) {
2160
1861
  option_select = self.getAdjacentOption(self.$activeOption, -1).attr('data-value');
2161
1862
  }
2162
-
1863
+
2163
1864
  // determine items that will be removed
2164
1865
  values = [];
2165
-
1866
+
2166
1867
  if (self.$activeItems.length) {
2167
1868
  $tail = self.$control.children('.active:' + (direction > 0 ? 'last' : 'first'));
2168
1869
  caret = self.$control.children(':not(input)').index($tail);
2169
1870
  if (direction > 0) { caret++; }
2170
-
1871
+
2171
1872
  for (i = 0, n = self.$activeItems.length; i < n; i++) {
2172
1873
  values.push($(self.$activeItems[i]).attr('data-value'));
2173
1874
  }
@@ -2182,12 +1883,12 @@
2182
1883
  values.push(self.items[self.caretPos]);
2183
1884
  }
2184
1885
  }
2185
-
1886
+
2186
1887
  // allow the callback to abort
2187
1888
  if (!values.length || (typeof self.settings.onDelete === 'function' && self.settings.onDelete(values) === false)) {
2188
1889
  return false;
2189
1890
  }
2190
-
1891
+
2191
1892
  // perform removal
2192
1893
  if (typeof caret !== 'undefined') {
2193
1894
  self.setCaret(caret);
@@ -2195,10 +1896,10 @@
2195
1896
  while (values.length) {
2196
1897
  self.removeItem(values.pop());
2197
1898
  }
2198
-
1899
+
2199
1900
  self.showInput();
2200
1901
  self.refreshOptions(true);
2201
-
1902
+
2202
1903
  // select previous option
2203
1904
  if (option_select) {
2204
1905
  $option_select = self.getOption(option_select);
@@ -2206,10 +1907,10 @@
2206
1907
  self.setActiveOption($option_select);
2207
1908
  }
2208
1909
  }
2209
-
1910
+
2210
1911
  return true;
2211
1912
  },
2212
-
1913
+
2213
1914
  /**
2214
1915
  * Selects the previous / next item (depending
2215
1916
  * on the `direction` argument).
@@ -2223,18 +1924,18 @@
2223
1924
  advanceSelection: function(direction, e) {
2224
1925
  var tail, selection, idx, valueLength, cursorAtEdge, $tail;
2225
1926
  var self = this;
2226
-
1927
+
2227
1928
  if (direction === 0) return;
2228
-
1929
+
2229
1930
  tail = direction > 0 ? 'last' : 'first';
2230
1931
  selection = getSelection(self.$control_input[0]);
2231
-
1932
+
2232
1933
  if (self.isInputFocused && !self.isInputHidden) {
2233
1934
  valueLength = self.$control_input.val().length;
2234
1935
  cursorAtEdge = direction < 0
2235
1936
  ? selection.start === 0 && selection.length === 0
2236
1937
  : selection.start === valueLength;
2237
-
1938
+
2238
1939
  if (cursorAtEdge && !valueLength) {
2239
1940
  self.advanceCaret(direction, e);
2240
1941
  }
@@ -2248,7 +1949,7 @@
2248
1949
  }
2249
1950
  }
2250
1951
  },
2251
-
1952
+
2252
1953
  /**
2253
1954
  * Moves the caret left / right.
2254
1955
  *
@@ -2270,7 +1971,7 @@
2270
1971
  self.setCaret(self.caretPos + direction);
2271
1972
  }
2272
1973
  },
2273
-
1974
+
2274
1975
  /**
2275
1976
  * Moves the caret to the specified index.
2276
1977
  *
@@ -2278,13 +1979,13 @@
2278
1979
  */
2279
1980
  setCaret: function(i) {
2280
1981
  var self = this;
2281
-
1982
+
2282
1983
  if (self.settings.mode === 'single') {
2283
1984
  i = self.items.length;
2284
1985
  } else {
2285
1986
  i = Math.max(0, Math.min(self.items.length, i));
2286
1987
  }
2287
-
1988
+
2288
1989
  // the input must be moved by leaving it in place and moving the
2289
1990
  // siblings, due to the fact that focus cannot be restored once lost
2290
1991
  // on mobile webkit devices
@@ -2298,10 +1999,10 @@
2298
1999
  self.$control.append($child);
2299
2000
  }
2300
2001
  }
2301
-
2002
+
2302
2003
  self.caretPos = i;
2303
2004
  },
2304
-
2005
+
2305
2006
  /**
2306
2007
  * Disables user input on the control. Used while
2307
2008
  * items are being asynchronously created.
@@ -2311,7 +2012,7 @@
2311
2012
  this.isLocked = true;
2312
2013
  this.refreshClasses();
2313
2014
  },
2314
-
2015
+
2315
2016
  /**
2316
2017
  * Re-enables user input on the control.
2317
2018
  */
@@ -2319,25 +2020,51 @@
2319
2020
  this.isLocked = false;
2320
2021
  this.refreshClasses();
2321
2022
  },
2322
-
2023
+
2323
2024
  /**
2324
2025
  * Disables user input on the control completely.
2325
2026
  * While disabled, it cannot receive focus.
2326
2027
  */
2327
2028
  disable: function() {
2328
- this.isDisabled = true;
2329
- this.lock();
2029
+ var self = this;
2030
+ self.$input.prop('disabled', true);
2031
+ self.isDisabled = true;
2032
+ self.lock();
2330
2033
  },
2331
-
2034
+
2332
2035
  /**
2333
2036
  * Enables the control so that it can respond
2334
2037
  * to focus and user input.
2335
2038
  */
2336
2039
  enable: function() {
2337
- this.isDisabled = false;
2338
- this.unlock();
2040
+ var self = this;
2041
+ self.$input.prop('disabled', false);
2042
+ self.isDisabled = false;
2043
+ self.unlock();
2339
2044
  },
2340
-
2045
+
2046
+ /**
2047
+ * Completely destroys the control and
2048
+ * unbinds all event listeners so that it can
2049
+ * be garbage collected.
2050
+ */
2051
+ destroy: function() {
2052
+ var self = this;
2053
+ var eventNS = self.eventNS;
2054
+
2055
+ self.trigger('destroy');
2056
+ self.off();
2057
+ self.$wrapper.remove();
2058
+ self.$dropdown.remove();
2059
+ self.$input.show();
2060
+
2061
+ $(window).off(eventNS);
2062
+ $(document).off(eventNS);
2063
+ $(document.body).off(eventNS);
2064
+
2065
+ delete self.$input[0].selectize;
2066
+ },
2067
+
2341
2068
  /**
2342
2069
  * A helper method for rendering "item" and
2343
2070
  * "option" templates, given the data.
@@ -2351,13 +2078,13 @@
2351
2078
  var html = '';
2352
2079
  var cache = false;
2353
2080
  var self = this;
2354
- var regex_tag = /^[\ ]*<([a-z][a-z0-9\-_]*(?:\:[a-z][a-z0-9\-_]*)?)/i;
2355
-
2081
+ var regex_tag = /^[\t ]*<([a-z][a-z0-9\-_]*(?:\:[a-z][a-z0-9\-_]*)?)/i;
2082
+
2356
2083
  if (templateName === 'option' || templateName === 'item') {
2357
2084
  value = hash_key(data[self.settings.valueField]);
2358
2085
  cache = !!value;
2359
2086
  }
2360
-
2087
+
2361
2088
  // pull markup from cache if it exists
2362
2089
  if (cache) {
2363
2090
  if (!isset(self.renderCache[templateName])) {
@@ -2367,7 +2094,7 @@
2367
2094
  return self.renderCache[templateName][value];
2368
2095
  }
2369
2096
  }
2370
-
2097
+
2371
2098
  // render markup
2372
2099
  if (self.settings.render && typeof self.settings.render[templateName] === 'function') {
2373
2100
  html = self.settings.render[templateName].apply(this, [data, escape_html]);
@@ -2392,7 +2119,7 @@
2392
2119
  break;
2393
2120
  }
2394
2121
  }
2395
-
2122
+
2396
2123
  // add mandatory attributes
2397
2124
  if (templateName === 'option' || templateName === 'option_create') {
2398
2125
  html = html.replace(regex_tag, '<$1 data-selectable');
@@ -2404,17 +2131,18 @@
2404
2131
  if (templateName === 'option' || templateName === 'item') {
2405
2132
  html = html.replace(regex_tag, '<$1 data-value="' + escape_html(value || '') + '"');
2406
2133
  }
2407
-
2134
+
2408
2135
  // update cache
2409
2136
  if (cache) {
2410
2137
  self.renderCache[templateName][value] = html;
2411
2138
  }
2412
-
2139
+
2413
2140
  return html;
2414
2141
  }
2415
-
2142
+
2416
2143
  });
2417
-
2144
+
2145
+ Selectize.count = 0;
2418
2146
  Selectize.defaults = {
2419
2147
  plugins: [],
2420
2148
  delimiter: ',',
@@ -2427,10 +2155,10 @@
2427
2155
  maxItems: null,
2428
2156
  hideSelected: null,
2429
2157
  preload: false,
2430
-
2158
+
2431
2159
  scrollDuration: 60,
2432
2160
  loadThrottle: 300,
2433
-
2161
+
2434
2162
  dataAttr: 'data-data',
2435
2163
  optgroupField: 'optgroup',
2436
2164
  sortField: null,
@@ -2441,16 +2169,15 @@
2441
2169
  optgroupValueField: 'value',
2442
2170
  optgroupOrder: null,
2443
2171
  searchField: ['text'],
2444
-
2172
+
2445
2173
  mode: null,
2446
- theme: 'default',
2447
2174
  wrapperClass: 'selectize-control',
2448
2175
  inputClass: 'selectize-input',
2449
2176
  dropdownClass: 'selectize-dropdown',
2450
2177
  dropdownContentClass: 'selectize-dropdown-content',
2451
-
2178
+
2452
2179
  dropdownParent: null,
2453
-
2180
+
2454
2181
  /*
2455
2182
  load : null, // function(query, callback) { ... }
2456
2183
  score : null, // function(search) { ... }
@@ -2467,7 +2194,7 @@
2467
2194
  onType : null, // function(str) { ... }
2468
2195
  onDelete : null, // function(values) { ... }
2469
2196
  */
2470
-
2197
+
2471
2198
  render: {
2472
2199
  /*
2473
2200
  item: null,
@@ -2478,15 +2205,13 @@
2478
2205
  */
2479
2206
  }
2480
2207
  };
2481
-
2482
- /* --- file: "src/selectize.jquery.js" --- */
2483
-
2208
+
2484
2209
  $.fn.selectize = function(settings) {
2485
2210
  settings = settings || {};
2486
-
2211
+
2487
2212
  var defaults = $.fn.selectize.defaults;
2488
2213
  var dataAttr = settings.dataAttr || defaults.dataAttr;
2489
-
2214
+
2490
2215
  /**
2491
2216
  * Initializes selectize from a <input type="text"> element.
2492
2217
  *
@@ -2496,7 +2221,7 @@
2496
2221
  var init_textbox = function($input, settings_element) {
2497
2222
  var i, n, values, value = $.trim($input.val() || '');
2498
2223
  if (!value.length) return;
2499
-
2224
+
2500
2225
  values = value.split(settings.delimiter || defaults.delimiter);
2501
2226
  for (i = 0, n = values.length; i < n; i++) {
2502
2227
  settings_element.options[values[i]] = {
@@ -2504,10 +2229,10 @@
2504
2229
  'value' : values[i]
2505
2230
  };
2506
2231
  }
2507
-
2232
+
2508
2233
  settings_element.items = values;
2509
2234
  };
2510
-
2235
+
2511
2236
  /**
2512
2237
  * Initializes selectize from a <select> element.
2513
2238
  *
@@ -2518,7 +2243,7 @@
2518
2243
  var i, n, tagName;
2519
2244
  var $children;
2520
2245
  settings_element.maxItems = !!$input.attr('multiple') ? null : 1;
2521
-
2246
+
2522
2247
  var readData = function($el) {
2523
2248
  var data = dataAttr && $el.attr(dataAttr);
2524
2249
  if (typeof data === 'string' && data.length) {
@@ -2526,13 +2251,13 @@
2526
2251
  }
2527
2252
  return null;
2528
2253
  };
2529
-
2254
+
2530
2255
  var addOption = function($option, group) {
2531
2256
  $option = $($option);
2532
-
2257
+
2533
2258
  var value = $option.attr('value') || '';
2534
2259
  if (!value.length) return;
2535
-
2260
+
2536
2261
  settings_element.options[value] = readData($option) || {
2537
2262
  'text' : $option.text(),
2538
2263
  'value' : value,
@@ -2542,23 +2267,23 @@
2542
2267
  settings_element.items.push(value);
2543
2268
  }
2544
2269
  };
2545
-
2270
+
2546
2271
  var addGroup = function($optgroup) {
2547
2272
  var i, n, $options = $('option', $optgroup);
2548
2273
  $optgroup = $($optgroup);
2549
-
2274
+
2550
2275
  var id = $optgroup.attr('label');
2551
2276
  if (id && id.length) {
2552
2277
  settings_element.optgroups[id] = readData($optgroup) || {
2553
2278
  'label': id
2554
2279
  };
2555
2280
  }
2556
-
2281
+
2557
2282
  for (i = 0, n = $options.length; i < n; i++) {
2558
2283
  addOption($options[i], id);
2559
2284
  }
2560
2285
  };
2561
-
2286
+
2562
2287
  $children = $input.children();
2563
2288
  for (i = 0, n = $children.length; i < n; i++) {
2564
2289
  tagName = $children[i].tagName.toLowerCase();
@@ -2569,7 +2294,7 @@
2569
2294
  }
2570
2295
  }
2571
2296
  };
2572
-
2297
+
2573
2298
  return this.each(function() {
2574
2299
  var instance;
2575
2300
  var $input = $(this);
@@ -2580,49 +2305,31 @@
2580
2305
  'optgroups' : {},
2581
2306
  'items' : []
2582
2307
  };
2583
-
2308
+
2584
2309
  if (tag_name === 'select') {
2585
2310
  init_select($input, settings_element);
2586
2311
  } else {
2587
2312
  init_textbox($input, settings_element);
2588
2313
  }
2589
-
2314
+
2590
2315
  instance = new Selectize($input, $.extend(true, {}, defaults, settings_element, settings));
2591
2316
  $input.data('selectize', instance);
2592
2317
  $input.addClass('selectized');
2593
2318
  });
2594
2319
  };
2595
-
2320
+
2596
2321
  $.fn.selectize.defaults = Selectize.defaults;
2597
-
2598
- /* --- file: "src/plugins/drag_drop/plugin.js" --- */
2599
-
2600
- /**
2601
- * Plugin: "drag_drop" (selectize.js)
2602
- * Copyright (c) 2013 Brian Reavis & contributors
2603
- *
2604
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
2605
- * file except in compliance with the License. You may obtain a copy of the License at:
2606
- * http://www.apache.org/licenses/LICENSE-2.0
2607
- *
2608
- * Unless required by applicable law or agreed to in writing, software distributed under
2609
- * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
2610
- * ANY KIND, either express or implied. See the License for the specific language
2611
- * governing permissions and limitations under the License.
2612
- *
2613
- * @author Brian Reavis <brian@thirdroute.com>
2614
- */
2615
-
2616
- Selectize.registerPlugin('drag_drop', function(options) {
2617
- if (!$.fn.sortable) throw new Error('The "drag_drop" Selectize plugin requires jQuery UI "sortable".');
2322
+
2323
+ Selectize.define('drag_drop', function(options) {
2324
+ if (!$.fn.sortable) throw new Error('The "drag_drop" plugin requires jQuery UI "sortable".');
2618
2325
  if (this.settings.mode !== 'multi') return;
2619
2326
  var self = this;
2620
-
2327
+
2621
2328
  this.setup = (function() {
2622
2329
  var original = self.setup;
2623
2330
  return function() {
2624
2331
  original.apply(this, arguments);
2625
-
2332
+
2626
2333
  var $control = this.$control.sortable({
2627
2334
  items: '[data-value]',
2628
2335
  forcePlaceholderSize: true,
@@ -2643,37 +2350,19 @@
2643
2350
  });
2644
2351
  };
2645
2352
  })();
2646
-
2353
+
2647
2354
  });
2648
-
2649
- /* --- file: "src/plugins/dropdown_header/plugin.js" --- */
2650
-
2651
- /**
2652
- * Plugin: "dropdown_header" (selectize.js)
2653
- * Copyright (c) 2013 Brian Reavis & contributors
2654
- *
2655
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
2656
- * file except in compliance with the License. You may obtain a copy of the License at:
2657
- * http://www.apache.org/licenses/LICENSE-2.0
2658
- *
2659
- * Unless required by applicable law or agreed to in writing, software distributed under
2660
- * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
2661
- * ANY KIND, either express or implied. See the License for the specific language
2662
- * governing permissions and limitations under the License.
2663
- *
2664
- * @author Brian Reavis <brian@thirdroute.com>
2665
- */
2666
-
2667
- Selectize.registerPlugin('dropdown_header', function(options) {
2355
+
2356
+ Selectize.define('dropdown_header', function(options) {
2668
2357
  var self = this;
2669
-
2358
+
2670
2359
  options = $.extend({
2671
2360
  title : 'Untitled',
2672
2361
  headerClass : 'selectize-dropdown-header',
2673
2362
  titleRowClass : 'selectize-dropdown-header-title',
2674
2363
  labelClass : 'selectize-dropdown-header-label',
2675
2364
  closeClass : 'selectize-dropdown-header-close',
2676
-
2365
+
2677
2366
  html: function(data) {
2678
2367
  return (
2679
2368
  '<div class="' + data.headerClass + '">' +
@@ -2685,7 +2374,7 @@
2685
2374
  );
2686
2375
  }
2687
2376
  }, options);
2688
-
2377
+
2689
2378
  self.setup = (function() {
2690
2379
  var original = self.setup;
2691
2380
  return function() {
@@ -2694,58 +2383,40 @@
2694
2383
  self.$dropdown.prepend(self.$dropdown_header);
2695
2384
  };
2696
2385
  })();
2697
-
2386
+
2698
2387
  });
2699
-
2700
- /* --- file: "src/plugins/optgroup_columns/plugin.js" --- */
2701
-
2702
- /**
2703
- * Plugin: "optgroup_columns" (selectize.js)
2704
- * Copyright (c) 2013 Simon Hewitt & contributors
2705
- *
2706
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
2707
- * file except in compliance with the License. You may obtain a copy of the License at:
2708
- * http://www.apache.org/licenses/LICENSE-2.0
2709
- *
2710
- * Unless required by applicable law or agreed to in writing, software distributed under
2711
- * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
2712
- * ANY KIND, either express or implied. See the License for the specific language
2713
- * governing permissions and limitations under the License.
2714
- *
2715
- * @author Simon Hewitt <si@sjhewitt.co.uk>
2716
- */
2717
-
2718
- Selectize.registerPlugin('optgroup_columns', function(options) {
2388
+
2389
+ Selectize.define('optgroup_columns', function(options) {
2719
2390
  var self = this;
2720
-
2391
+
2721
2392
  options = $.extend({
2722
2393
  equalizeWidth : true,
2723
2394
  equalizeHeight : true
2724
2395
  }, options);
2725
-
2396
+
2726
2397
  this.getAdjacentOption = function($option, direction) {
2727
2398
  var $options = $option.closest('[data-group]').find('[data-selectable]');
2728
2399
  var index = $options.index($option) + direction;
2729
-
2400
+
2730
2401
  return index >= 0 && index < $options.length ? $options.eq(index) : $();
2731
2402
  };
2732
-
2403
+
2733
2404
  this.onKeyDown = (function() {
2734
2405
  var original = self.onKeyDown;
2735
2406
  return function(e) {
2736
2407
  var index, $option, $options, $optgroup;
2737
-
2408
+
2738
2409
  if (this.isOpen && (e.keyCode === KEY_LEFT || e.keyCode === KEY_RIGHT)) {
2739
2410
  self.ignoreHover = true;
2740
2411
  $optgroup = this.$activeOption.closest('[data-group]');
2741
2412
  index = $optgroup.find('[data-selectable]').index(this.$activeOption);
2742
-
2413
+
2743
2414
  if(e.keyCode === KEY_LEFT) {
2744
2415
  $optgroup = $optgroup.prev('[data-group]');
2745
2416
  } else {
2746
2417
  $optgroup = $optgroup.next('[data-group]');
2747
2418
  }
2748
-
2419
+
2749
2420
  $options = $optgroup.find('[data-selectable]');
2750
2421
  $option = $options.eq(Math.min($options.length - 1, index));
2751
2422
  if ($option.length) {
@@ -2753,18 +2424,18 @@
2753
2424
  }
2754
2425
  return;
2755
2426
  }
2756
-
2427
+
2757
2428
  return original.apply(this, arguments);
2758
2429
  };
2759
2430
  })();
2760
-
2431
+
2761
2432
  var equalizeSizes = function() {
2762
2433
  var i, n, height_max, width, width_last, width_parent, $optgroups;
2763
-
2434
+
2764
2435
  $optgroups = $('[data-group]', self.$dropdown_content);
2765
2436
  n = $optgroups.length;
2766
2437
  if (!n || !self.$dropdown_content.width()) return;
2767
-
2438
+
2768
2439
  if (options.equalizeHeight) {
2769
2440
  height_max = 0;
2770
2441
  for (i = 0; i < n; i++) {
@@ -2772,7 +2443,7 @@
2772
2443
  }
2773
2444
  $optgroups.css({height: height_max});
2774
2445
  }
2775
-
2446
+
2776
2447
  if (options.equalizeWidth) {
2777
2448
  width_parent = self.$dropdown_content.innerWidth();
2778
2449
  width = Math.round(width_parent / n);
@@ -2783,42 +2454,24 @@
2783
2454
  }
2784
2455
  }
2785
2456
  };
2786
-
2457
+
2787
2458
  if (options.equalizeHeight || options.equalizeWidth) {
2788
2459
  hook.after(this, 'positionDropdown', equalizeSizes);
2789
2460
  hook.after(this, 'refreshOptions', equalizeSizes);
2790
2461
  }
2791
-
2792
-
2462
+
2463
+
2793
2464
  });
2794
-
2795
- /* --- file: "src/plugins/remove_button/plugin.js" --- */
2796
-
2797
- /**
2798
- * Plugin: "remove_button" (selectize.js)
2799
- * Copyright (c) 2013 Brian Reavis & contributors
2800
- *
2801
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
2802
- * file except in compliance with the License. You may obtain a copy of the License at:
2803
- * http://www.apache.org/licenses/LICENSE-2.0
2804
- *
2805
- * Unless required by applicable law or agreed to in writing, software distributed under
2806
- * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
2807
- * ANY KIND, either express or implied. See the License for the specific language
2808
- * governing permissions and limitations under the License.
2809
- *
2810
- * @author Brian Reavis <brian@thirdroute.com>
2811
- */
2812
-
2813
- Selectize.registerPlugin('remove_button', function(options) {
2465
+
2466
+ Selectize.define('remove_button', function(options) {
2814
2467
  var self = this;
2815
-
2468
+
2816
2469
  // override the item rendering method to add a "x" to each
2817
2470
  this.settings.render.item = function(data) {
2818
2471
  var label = data[self.settings.labelField];
2819
2472
  return '<div class="item">' + label + ' <a href="javascript:void(0)" class="remove" tabindex="-1" title="Remove">&times;</a></div>';
2820
2473
  };
2821
-
2474
+
2822
2475
  // override the setup method to add an extra "click" handler
2823
2476
  // that listens for mousedown events on the "x"
2824
2477
  this.setup = (function() {
@@ -2835,34 +2488,16 @@
2835
2488
  });
2836
2489
  };
2837
2490
  })();
2838
-
2491
+
2839
2492
  });
2840
-
2841
- /* --- file: "src/plugins/restore_on_backspace/plugin.js" --- */
2842
-
2843
- /**
2844
- * Plugin: "restore_on_backspace" (selectize.js)
2845
- * Copyright (c) 2013 Brian Reavis & contributors
2846
- *
2847
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
2848
- * file except in compliance with the License. You may obtain a copy of the License at:
2849
- * http://www.apache.org/licenses/LICENSE-2.0
2850
- *
2851
- * Unless required by applicable law or agreed to in writing, software distributed under
2852
- * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
2853
- * ANY KIND, either express or implied. See the License for the specific language
2854
- * governing permissions and limitations under the License.
2855
- *
2856
- * @author Brian Reavis <brian@thirdroute.com>
2857
- */
2858
-
2859
- Selectize.registerPlugin('restore_on_backspace', function(options) {
2493
+
2494
+ Selectize.define('restore_on_backspace', function(options) {
2860
2495
  var self = this;
2861
-
2496
+
2862
2497
  options.text = options.text || function(option) {
2863
2498
  return option[this.settings.labelField];
2864
2499
  };
2865
-
2500
+
2866
2501
  this.onKeyDown = (function(e) {
2867
2502
  var original = self.onKeyDown;
2868
2503
  return function(e) {
@@ -2885,5 +2520,4 @@
2885
2520
  });
2886
2521
 
2887
2522
  return Selectize;
2888
-
2889
- }));
2523
+ }));