activeadmin_selectize 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 65196065418afcc65f66fef747771928871bd94b536cd50a48c3d26f2f459741
4
- data.tar.gz: 4482f5bc912b27d78829e3f500b89ebbc5da29a6a865488bd9d4e8ed24c7e024
3
+ metadata.gz: 06b3852d7ee6dc49a82ee9dd2f1e9e8a92f7468e00e3a1855f45a3c2817fb08c
4
+ data.tar.gz: a580d91fe49e0c38c7846239dcadd88a205547df8dd4ffd7f3d90a54fa946fec
5
5
  SHA512:
6
- metadata.gz: 8b4bb54aef9341528f49eb5f75fe87f10bfe73b18843e3be0efa46b1a1edd85a9ef2e68494be106417654d500c042b6bb9275b57e5d6b801e486ff7c24efb063
7
- data.tar.gz: 921915837ae63ff38b09f96de8ca3bc34c6238bfd76602ccc1f9be23d9c05730243f6032e7f55120429b647aa8afbd4909c936d417cbaac11c985896ab379f71
6
+ metadata.gz: a91f8488a1725cb376113cd9754e1035f29dfb4d310b55012a3d097220133234b843d8b6af2d26a79767ae0919e2233271d30dbdc532219d1f9ad811f51ee2c1
7
+ data.tar.gz: 5ed2c330f0150dc43fe161b944bc655496da02da53d501d7a29a2a51a4aaede5797c431a5cf876efeb0e02f9efbf6269a074b93779f3d437510cf4f1407f0882
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # ActiveAdmin Selectize [![Gem Version](https://badge.fury.io/rb/activeadmin_selectize.svg)](https://badge.fury.io/rb/activeadmin_selectize)
1
+ # ActiveAdmin Selectize [![Gem Version](https://badge.fury.io/rb/activeadmin_selectize.svg)](https://badge.fury.io/rb/activeadmin_selectize) [![CircleCI](https://circleci.com/gh/blocknotes/activeadmin_selectize.svg?style=svg)](https://circleci.com/gh/blocknotes/activeadmin_selectize)
2
2
 
3
3
  An Active Admin plugin to use [Selectize.js](http://selectize.github.io/selectize.js) (jQuery required).
4
4
 
@@ -96,9 +96,9 @@ Alternative syntax:
96
96
 
97
97
  ## Do you like it? Star it!
98
98
 
99
- If you use this component just star it. A developer is more motivated to improve a project when there is some interest.
99
+ If you use this component just star it. A developer is more motivated to improve a project when there is some interest. My other [Active Admin components](https://github.com/blocknotes?utf8=✓&tab=repositories&q=activeadmin&type=source).
100
100
 
101
- Take a look at [other ActiveAdmin components](https://github.com/blocknotes?utf8=✓&tab=repositories&q=activeadmin&type=source) that I made if you are curious.
101
+ Or consider offering me a coffee, it's a small thing but it is greatly appreciated: [about me](https://www.blocknot.es/about-me).
102
102
 
103
103
  ## Contributors
104
104
 
data/Rakefile CHANGED
@@ -1,3 +1,16 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
- require "bundler/gem_tasks"
3
+ require 'bundler/gem_tasks'
4
+
5
+ begin
6
+ require 'rspec/core/rake_task'
7
+
8
+ RSpec::Core::RakeTask.new(:spec) do |t|
9
+ # t.ruby_opts = %w[-w]
10
+ t.rspec_opts = ['--color', '--format documentation']
11
+ end
12
+
13
+ task default: :spec
14
+ rescue LoadError
15
+ puts '! LoadError: no RSpec available'
16
+ end
@@ -1,3891 +1,3 @@
1
- /**
2
- * sifter.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 <brian@thirdroute.com>
15
- */
1
+ /*! selectize.js - v0.13.3 | https://github.com/selectize/selectize.js | Apache License (v2) */
16
2
 
17
- (function(root, factory) {
18
- if (typeof define === 'function' && define.amd) {
19
- define('sifter', factory);
20
- } else if (typeof exports === 'object') {
21
- module.exports = factory();
22
- } else {
23
- root.Sifter = factory();
24
- }
25
- }(this, function() {
26
-
27
- /**
28
- * Textually searches arrays and hashes of objects
29
- * by property (or multiple properties). Designed
30
- * specifically for autocomplete.
31
- *
32
- * @constructor
33
- * @param {array|object} items
34
- * @param {object} items
35
- */
36
- var Sifter = function(items, settings) {
37
- this.items = items;
38
- this.settings = settings || {diacritics: true};
39
- };
40
-
41
- /**
42
- * Splits a search string into an array of individual
43
- * regexps to be used to match results.
44
- *
45
- * @param {string} query
46
- * @returns {array}
47
- */
48
- Sifter.prototype.tokenize = function(query) {
49
- query = trim(String(query || '').toLowerCase());
50
- if (!query || !query.length) return [];
51
-
52
- var i, n, regex, letter;
53
- var tokens = [];
54
- var words = query.split(/ +/);
55
-
56
- for (i = 0, n = words.length; i < n; i++) {
57
- regex = escape_regex(words[i]);
58
- if (this.settings.diacritics) {
59
- for (letter in DIACRITICS) {
60
- if (DIACRITICS.hasOwnProperty(letter)) {
61
- regex = regex.replace(new RegExp(letter, 'g'), DIACRITICS[letter]);
62
- }
63
- }
64
- }
65
- tokens.push({
66
- string : words[i],
67
- regex : new RegExp(regex, 'i')
68
- });
69
- }
70
-
71
- return tokens;
72
- };
73
-
74
- /**
75
- * Iterates over arrays and hashes.
76
- *
77
- * ```
78
- * this.iterator(this.items, function(item, id) {
79
- * // invoked for each item
80
- * });
81
- * ```
82
- *
83
- * @param {array|object} object
84
- */
85
- Sifter.prototype.iterator = function(object, callback) {
86
- var iterator;
87
- if (is_array(object)) {
88
- iterator = Array.prototype.forEach || function(callback) {
89
- for (var i = 0, n = this.length; i < n; i++) {
90
- callback(this[i], i, this);
91
- }
92
- };
93
- } else {
94
- iterator = function(callback) {
95
- for (var key in this) {
96
- if (this.hasOwnProperty(key)) {
97
- callback(this[key], key, this);
98
- }
99
- }
100
- };
101
- }
102
-
103
- iterator.apply(object, [callback]);
104
- };
105
-
106
- /**
107
- * Returns a function to be used to score individual results.
108
- *
109
- * Good matches will have a higher score than poor matches.
110
- * If an item is not a match, 0 will be returned by the function.
111
- *
112
- * @param {object|string} search
113
- * @param {object} options (optional)
114
- * @returns {function}
115
- */
116
- Sifter.prototype.getScoreFunction = function(search, options) {
117
- var self, fields, tokens, token_count, nesting;
118
-
119
- self = this;
120
- search = self.prepareSearch(search, options);
121
- tokens = search.tokens;
122
- fields = search.options.fields;
123
- token_count = tokens.length;
124
- nesting = search.options.nesting;
125
-
126
- /**
127
- * Calculates how close of a match the
128
- * given value is against a search token.
129
- *
130
- * @param {mixed} value
131
- * @param {object} token
132
- * @return {number}
133
- */
134
- var scoreValue = function(value, token) {
135
- var score, pos;
136
-
137
- if (!value) return 0;
138
- value = String(value || '');
139
- pos = value.search(token.regex);
140
- if (pos === -1) return 0;
141
- score = token.string.length / value.length;
142
- if (pos === 0) score += 0.5;
143
- return score;
144
- };
145
-
146
- /**
147
- * Calculates the score of an object
148
- * against the search query.
149
- *
150
- * @param {object} token
151
- * @param {object} data
152
- * @return {number}
153
- */
154
- var scoreObject = (function() {
155
- var field_count = fields.length;
156
- if (!field_count) {
157
- return function() { return 0; };
158
- }
159
- if (field_count === 1) {
160
- return function(token, data) {
161
- return scoreValue(getattr(data, fields[0], nesting), token);
162
- };
163
- }
164
- return function(token, data) {
165
- for (var i = 0, sum = 0; i < field_count; i++) {
166
- sum += scoreValue(getattr(data, fields[i], nesting), token);
167
- }
168
- return sum / field_count;
169
- };
170
- })();
171
-
172
- if (!token_count) {
173
- return function() { return 0; };
174
- }
175
- if (token_count === 1) {
176
- return function(data) {
177
- return scoreObject(tokens[0], data);
178
- };
179
- }
180
-
181
- if (search.options.conjunction === 'and') {
182
- return function(data) {
183
- var score;
184
- for (var i = 0, sum = 0; i < token_count; i++) {
185
- score = scoreObject(tokens[i], data);
186
- if (score <= 0) return 0;
187
- sum += score;
188
- }
189
- return sum / token_count;
190
- };
191
- } else {
192
- return function(data) {
193
- for (var i = 0, sum = 0; i < token_count; i++) {
194
- sum += scoreObject(tokens[i], data);
195
- }
196
- return sum / token_count;
197
- };
198
- }
199
- };
200
-
201
- /**
202
- * Returns a function that can be used to compare two
203
- * results, for sorting purposes. If no sorting should
204
- * be performed, `null` will be returned.
205
- *
206
- * @param {string|object} search
207
- * @param {object} options
208
- * @return function(a,b)
209
- */
210
- Sifter.prototype.getSortFunction = function(search, options) {
211
- var i, n, self, field, fields, fields_count, multiplier, multipliers, get_field, implicit_score, sort;
212
-
213
- self = this;
214
- search = self.prepareSearch(search, options);
215
- sort = (!search.query && options.sort_empty) || options.sort;
216
-
217
- /**
218
- * Fetches the specified sort field value
219
- * from a search result item.
220
- *
221
- * @param {string} name
222
- * @param {object} result
223
- * @return {mixed}
224
- */
225
- get_field = function(name, result) {
226
- if (name === '$score') return result.score;
227
- return getattr(self.items[result.id], name, options.nesting);
228
- };
229
-
230
- // parse options
231
- fields = [];
232
- if (sort) {
233
- for (i = 0, n = sort.length; i < n; i++) {
234
- if (search.query || sort[i].field !== '$score') {
235
- fields.push(sort[i]);
236
- }
237
- }
238
- }
239
-
240
- // the "$score" field is implied to be the primary
241
- // sort field, unless it's manually specified
242
- if (search.query) {
243
- implicit_score = true;
244
- for (i = 0, n = fields.length; i < n; i++) {
245
- if (fields[i].field === '$score') {
246
- implicit_score = false;
247
- break;
248
- }
249
- }
250
- if (implicit_score) {
251
- fields.unshift({field: '$score', direction: 'desc'});
252
- }
253
- } else {
254
- for (i = 0, n = fields.length; i < n; i++) {
255
- if (fields[i].field === '$score') {
256
- fields.splice(i, 1);
257
- break;
258
- }
259
- }
260
- }
261
-
262
- multipliers = [];
263
- for (i = 0, n = fields.length; i < n; i++) {
264
- multipliers.push(fields[i].direction === 'desc' ? -1 : 1);
265
- }
266
-
267
- // build function
268
- fields_count = fields.length;
269
- if (!fields_count) {
270
- return null;
271
- } else if (fields_count === 1) {
272
- field = fields[0].field;
273
- multiplier = multipliers[0];
274
- return function(a, b) {
275
- return multiplier * cmp(
276
- get_field(field, a),
277
- get_field(field, b)
278
- );
279
- };
280
- } else {
281
- return function(a, b) {
282
- var i, result, a_value, b_value, field;
283
- for (i = 0; i < fields_count; i++) {
284
- field = fields[i].field;
285
- result = multipliers[i] * cmp(
286
- get_field(field, a),
287
- get_field(field, b)
288
- );
289
- if (result) return result;
290
- }
291
- return 0;
292
- };
293
- }
294
- };
295
-
296
- /**
297
- * Parses a search query and returns an object
298
- * with tokens and fields ready to be populated
299
- * with results.
300
- *
301
- * @param {string} query
302
- * @param {object} options
303
- * @returns {object}
304
- */
305
- Sifter.prototype.prepareSearch = function(query, options) {
306
- if (typeof query === 'object') return query;
307
-
308
- options = extend({}, options);
309
-
310
- var option_fields = options.fields;
311
- var option_sort = options.sort;
312
- var option_sort_empty = options.sort_empty;
313
-
314
- if (option_fields && !is_array(option_fields)) options.fields = [option_fields];
315
- if (option_sort && !is_array(option_sort)) options.sort = [option_sort];
316
- if (option_sort_empty && !is_array(option_sort_empty)) options.sort_empty = [option_sort_empty];
317
-
318
- return {
319
- options : options,
320
- query : String(query || '').toLowerCase(),
321
- tokens : this.tokenize(query),
322
- total : 0,
323
- items : []
324
- };
325
- };
326
-
327
- /**
328
- * Searches through all items and returns a sorted array of matches.
329
- *
330
- * The `options` parameter can contain:
331
- *
332
- * - fields {string|array}
333
- * - sort {array}
334
- * - score {function}
335
- * - filter {bool}
336
- * - limit {integer}
337
- *
338
- * Returns an object containing:
339
- *
340
- * - options {object}
341
- * - query {string}
342
- * - tokens {array}
343
- * - total {int}
344
- * - items {array}
345
- *
346
- * @param {string} query
347
- * @param {object} options
348
- * @returns {object}
349
- */
350
- Sifter.prototype.search = function(query, options) {
351
- var self = this, value, score, search, calculateScore;
352
- var fn_sort;
353
- var fn_score;
354
-
355
- search = this.prepareSearch(query, options);
356
- options = search.options;
357
- query = search.query;
358
-
359
- // generate result scoring function
360
- fn_score = options.score || self.getScoreFunction(search);
361
-
362
- // perform search and sort
363
- if (query.length) {
364
- self.iterator(self.items, function(item, id) {
365
- score = fn_score(item);
366
- if (options.filter === false || score > 0) {
367
- search.items.push({'score': score, 'id': id});
368
- }
369
- });
370
- } else {
371
- self.iterator(self.items, function(item, id) {
372
- search.items.push({'score': 1, 'id': id});
373
- });
374
- }
375
-
376
- fn_sort = self.getSortFunction(search, options);
377
- if (fn_sort) search.items.sort(fn_sort);
378
-
379
- // apply limits
380
- search.total = search.items.length;
381
- if (typeof options.limit === 'number') {
382
- search.items = search.items.slice(0, options.limit);
383
- }
384
-
385
- return search;
386
- };
387
-
388
- // utilities
389
- // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
390
-
391
- var cmp = function(a, b) {
392
- if (typeof a === 'number' && typeof b === 'number') {
393
- return a > b ? 1 : (a < b ? -1 : 0);
394
- }
395
- a = asciifold(String(a || ''));
396
- b = asciifold(String(b || ''));
397
- if (a > b) return 1;
398
- if (b > a) return -1;
399
- return 0;
400
- };
401
-
402
- var extend = function(a, b) {
403
- var i, n, k, object;
404
- for (i = 1, n = arguments.length; i < n; i++) {
405
- object = arguments[i];
406
- if (!object) continue;
407
- for (k in object) {
408
- if (object.hasOwnProperty(k)) {
409
- a[k] = object[k];
410
- }
411
- }
412
- }
413
- return a;
414
- };
415
-
416
- /**
417
- * A property getter resolving dot-notation
418
- * @param {Object} obj The root object to fetch property on
419
- * @param {String} name The optionally dotted property name to fetch
420
- * @param {Boolean} nesting Handle nesting or not
421
- * @return {Object} The resolved property value
422
- */
423
- var getattr = function(obj, name, nesting) {
424
- if (!obj || !name) return;
425
- if (!nesting) return obj[name];
426
- var names = name.split(".");
427
- while(names.length && (obj = obj[names.shift()]));
428
- return obj;
429
- };
430
-
431
- var trim = function(str) {
432
- return (str + '').replace(/^\s+|\s+$|/g, '');
433
- };
434
-
435
- var escape_regex = function(str) {
436
- return (str + '').replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1');
437
- };
438
-
439
- var is_array = Array.isArray || (typeof $ !== 'undefined' && $.isArray) || function(object) {
440
- return Object.prototype.toString.call(object) === '[object Array]';
441
- };
442
-
443
- var DIACRITICS = {
444
- 'a': '[aḀḁĂăÂâǍǎȺⱥȦȧẠạÄäÀàÁáĀāÃãÅåąĄÃąĄ]',
445
- 'b': '[b␢βΒB฿𐌁ᛒ]',
446
- 'c': '[cĆćĈĉČčĊċC̄c̄ÇçḈḉȻȼƇƈɕᴄCc]',
447
- 'd': '[dĎďḊḋḐḑḌḍḒḓḎḏĐđD̦d̦ƉɖƊɗƋƌᵭᶁᶑȡᴅDdð]',
448
- 'e': '[eÉéÈèÊêḘḙĚěĔĕẼẽḚḛẺẻĖėËëĒēȨȩĘęᶒɆɇȄȅẾếỀềỄễỂểḜḝḖḗḔḕȆȇẸẹỆệⱸᴇEeɘǝƏƐε]',
449
- 'f': '[fƑƒḞḟ]',
450
- 'g': '[gɢ₲ǤǥĜĝĞğĢģƓɠĠġ]',
451
- 'h': '[hĤĥĦħḨḩẖẖḤḥḢḣɦʰǶƕ]',
452
- 'i': '[iÍíÌìĬĭÎîǏǐÏïḮḯĨĩĮįĪīỈỉȈȉȊȋỊịḬḭƗɨɨ̆ᵻᶖİiIıɪIi]',
453
- 'j': '[jȷĴĵɈɉʝɟʲ]',
454
- 'k': '[kƘƙꝀꝁḰḱǨǩḲḳḴḵκϰ₭]',
455
- 'l': '[lŁłĽľĻļĹĺḶḷḸḹḼḽḺḻĿŀȽƚⱠⱡⱢɫɬᶅɭȴʟLl]',
456
- 'n': '[nŃńǸǹŇňÑñṄṅŅņṆṇṊṋṈṉN̈n̈ƝɲȠƞᵰᶇɳȵɴNnŊŋ]',
457
- 'o': '[oØøÖöÓóÒòÔôǑǒŐőŎŏȮȯỌọƟɵƠơỎỏŌōÕõǪǫȌȍՕօ]',
458
- 'p': '[pṔṕṖṗⱣᵽƤƥᵱ]',
459
- 'q': '[qꝖꝗʠɊɋꝘꝙq̃]',
460
- 'r': '[rŔŕɌɍŘřŖŗṘṙȐȑȒȓṚṛⱤɽ]',
461
- 's': '[sŚśṠṡṢṣꞨꞩŜŝŠšŞşȘșS̈s̈]',
462
- 't': '[tŤťṪṫŢţṬṭƮʈȚțṰṱṮṯƬƭ]',
463
- 'u': '[uŬŭɄʉỤụÜüÚúÙùÛûǓǔŰűŬŭƯưỦủŪūŨũŲųȔȕ∪]',
464
- 'v': '[vṼṽṾṿƲʋꝞꝟⱱʋ]',
465
- 'w': '[wẂẃẀẁŴŵẄẅẆẇẈẉ]',
466
- 'x': '[xẌẍẊẋχ]',
467
- 'y': '[yÝýỲỳŶŷŸÿỸỹẎẏỴỵɎɏƳƴ]',
468
- 'z': '[zŹźẐẑŽžŻżẒẓẔẕƵƶ]'
469
- };
470
-
471
- var asciifold = (function() {
472
- var i, n, k, chunk;
473
- var foreignletters = '';
474
- var lookup = {};
475
- for (k in DIACRITICS) {
476
- if (DIACRITICS.hasOwnProperty(k)) {
477
- chunk = DIACRITICS[k].substring(2, DIACRITICS[k].length - 1);
478
- foreignletters += chunk;
479
- for (i = 0, n = chunk.length; i < n; i++) {
480
- lookup[chunk.charAt(i)] = k;
481
- }
482
- }
483
- }
484
- var regexp = new RegExp('[' + foreignletters + ']', 'g');
485
- return function(str) {
486
- return str.replace(regexp, function(foreignletter) {
487
- return lookup[foreignletter];
488
- }).toLowerCase();
489
- };
490
- })();
491
-
492
-
493
- // export
494
- // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
495
-
496
- return Sifter;
497
- }));
498
-
499
-
500
-
501
- /**
502
- * microplugin.js
503
- * Copyright (c) 2013 Brian Reavis & contributors
504
- *
505
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
506
- * file except in compliance with the License. You may obtain a copy of the License at:
507
- * http://www.apache.org/licenses/LICENSE-2.0
508
- *
509
- * Unless required by applicable law or agreed to in writing, software distributed under
510
- * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
511
- * ANY KIND, either express or implied. See the License for the specific language
512
- * governing permissions and limitations under the License.
513
- *
514
- * @author Brian Reavis <brian@thirdroute.com>
515
- */
516
-
517
- (function(root, factory) {
518
- if (typeof define === 'function' && define.amd) {
519
- define('microplugin', factory);
520
- } else if (typeof exports === 'object') {
521
- module.exports = factory();
522
- } else {
523
- root.MicroPlugin = factory();
524
- }
525
- }(this, function() {
526
- var MicroPlugin = {};
527
-
528
- MicroPlugin.mixin = function(Interface) {
529
- Interface.plugins = {};
530
-
531
- /**
532
- * Initializes the listed plugins (with options).
533
- * Acceptable formats:
534
- *
535
- * List (without options):
536
- * ['a', 'b', 'c']
537
- *
538
- * List (with options):
539
- * [{'name': 'a', options: {}}, {'name': 'b', options: {}}]
540
- *
541
- * Hash (with options):
542
- * {'a': { ... }, 'b': { ... }, 'c': { ... }}
543
- *
544
- * @param {mixed} plugins
545
- */
546
- Interface.prototype.initializePlugins = function(plugins) {
547
- var i, n, key;
548
- var self = this;
549
- var queue = [];
550
-
551
- self.plugins = {
552
- names : [],
553
- settings : {},
554
- requested : {},
555
- loaded : {}
556
- };
557
-
558
- if (utils.isArray(plugins)) {
559
- for (i = 0, n = plugins.length; i < n; i++) {
560
- if (typeof plugins[i] === 'string') {
561
- queue.push(plugins[i]);
562
- } else {
563
- self.plugins.settings[plugins[i].name] = plugins[i].options;
564
- queue.push(plugins[i].name);
565
- }
566
- }
567
- } else if (plugins) {
568
- for (key in plugins) {
569
- if (plugins.hasOwnProperty(key)) {
570
- self.plugins.settings[key] = plugins[key];
571
- queue.push(key);
572
- }
573
- }
574
- }
575
-
576
- while (queue.length) {
577
- self.require(queue.shift());
578
- }
579
- };
580
-
581
- Interface.prototype.loadPlugin = function(name) {
582
- var self = this;
583
- var plugins = self.plugins;
584
- var plugin = Interface.plugins[name];
585
-
586
- if (!Interface.plugins.hasOwnProperty(name)) {
587
- throw new Error('Unable to find "' + name + '" plugin');
588
- }
589
-
590
- plugins.requested[name] = true;
591
- plugins.loaded[name] = plugin.fn.apply(self, [self.plugins.settings[name] || {}]);
592
- plugins.names.push(name);
593
- };
594
-
595
- /**
596
- * Initializes a plugin.
597
- *
598
- * @param {string} name
599
- */
600
- Interface.prototype.require = function(name) {
601
- var self = this;
602
- var plugins = self.plugins;
603
-
604
- if (!self.plugins.loaded.hasOwnProperty(name)) {
605
- if (plugins.requested[name]) {
606
- throw new Error('Plugin has circular dependency ("' + name + '")');
607
- }
608
- self.loadPlugin(name);
609
- }
610
-
611
- return plugins.loaded[name];
612
- };
613
-
614
- /**
615
- * Registers a plugin.
616
- *
617
- * @param {string} name
618
- * @param {function} fn
619
- */
620
- Interface.define = function(name, fn) {
621
- Interface.plugins[name] = {
622
- 'name' : name,
623
- 'fn' : fn
624
- };
625
- };
626
- };
627
-
628
- var utils = {
629
- isArray: Array.isArray || function(vArg) {
630
- return Object.prototype.toString.call(vArg) === '[object Array]';
631
- }
632
- };
633
-
634
- return MicroPlugin;
635
- }));
636
-
637
- /**
638
- * selectize.js (v0.12.6)
639
- * Copyright (c) 2013–2015 Brian Reavis & contributors
640
- *
641
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
642
- * file except in compliance with the License. You may obtain a copy of the License at:
643
- * http://www.apache.org/licenses/LICENSE-2.0
644
- *
645
- * Unless required by applicable law or agreed to in writing, software distributed under
646
- * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
647
- * ANY KIND, either express or implied. See the License for the specific language
648
- * governing permissions and limitations under the License.
649
- *
650
- * @author Brian Reavis <brian@thirdroute.com>
651
- */
652
-
653
- /*jshint curly:false */
654
- /*jshint browser:true */
655
-
656
- (function(root, factory) {
657
- if (typeof define === 'function' && define.amd) {
658
- define('selectize', ['jquery','sifter','microplugin'], factory);
659
- } else if (typeof exports === 'object') {
660
- module.exports = factory(require('jquery'), require('sifter'), require('microplugin'));
661
- } else {
662
- root.Selectize = factory(root.jQuery, root.Sifter, root.MicroPlugin);
663
- }
664
- }(this, function($, Sifter, MicroPlugin) {
665
- 'use strict';
666
-
667
- var highlight = function($element, pattern) {
668
- if (typeof pattern === 'string' && !pattern.length) return;
669
- var regex = (typeof pattern === 'string') ? new RegExp(pattern, 'i') : pattern;
670
-
671
- var highlight = function(node) {
672
- var skip = 0;
673
- // Wrap matching part of text node with highlighting <span>, e.g.
674
- // Soccer -> <span class="highlight">Soc</span>cer for regex = /soc/i
675
- if (node.nodeType === 3) {
676
- var pos = node.data.search(regex);
677
- if (pos >= 0 && node.data.length > 0) {
678
- var match = node.data.match(regex);
679
- var spannode = document.createElement('span');
680
- spannode.className = 'highlight';
681
- var middlebit = node.splitText(pos);
682
- var endbit = middlebit.splitText(match[0].length);
683
- var middleclone = middlebit.cloneNode(true);
684
- spannode.appendChild(middleclone);
685
- middlebit.parentNode.replaceChild(spannode, middlebit);
686
- skip = 1;
687
- }
688
- }
689
- // Recurse element node, looking for child text nodes to highlight, unless element
690
- // is childless, <script>, <style>, or already highlighted: <span class="hightlight">
691
- else if (node.nodeType === 1 && node.childNodes && !/(script|style)/i.test(node.tagName) && ( node.className !== 'highlight' || node.tagName !== 'SPAN' )) {
692
- for (var i = 0; i < node.childNodes.length; ++i) {
693
- i += highlight(node.childNodes[i]);
694
- }
695
- }
696
- return skip;
697
- };
698
-
699
- return $element.each(function() {
700
- highlight(this);
701
- });
702
- };
703
-
704
- /**
705
- * removeHighlight fn copied from highlight v5 and
706
- * edited to remove with() and pass js strict mode
707
- */
708
- $.fn.removeHighlight = function() {
709
- return this.find("span.highlight").each(function() {
710
- this.parentNode.firstChild.nodeName;
711
- var parent = this.parentNode;
712
- parent.replaceChild(this.firstChild, this);
713
- parent.normalize();
714
- }).end();
715
- };
716
-
717
-
718
- var MicroEvent = function() {};
719
- MicroEvent.prototype = {
720
- on: function(event, fct){
721
- this._events = this._events || {};
722
- this._events[event] = this._events[event] || [];
723
- this._events[event].push(fct);
724
- },
725
- off: function(event, fct){
726
- var n = arguments.length;
727
- if (n === 0) return delete this._events;
728
- if (n === 1) return delete this._events[event];
729
-
730
- this._events = this._events || {};
731
- if (event in this._events === false) return;
732
- this._events[event].splice(this._events[event].indexOf(fct), 1);
733
- },
734
- trigger: function(event /* , args... */){
735
- this._events = this._events || {};
736
- if (event in this._events === false) return;
737
- for (var i = 0; i < this._events[event].length; i++){
738
- this._events[event][i].apply(this, Array.prototype.slice.call(arguments, 1));
739
- }
740
- }
741
- };
742
-
743
- /**
744
- * Mixin will delegate all MicroEvent.js function in the destination object.
745
- *
746
- * - MicroEvent.mixin(Foobar) will make Foobar able to use MicroEvent
747
- *
748
- * @param {object} the object which will support MicroEvent
749
- */
750
- MicroEvent.mixin = function(destObject){
751
- var props = ['on', 'off', 'trigger'];
752
- for (var i = 0; i < props.length; i++){
753
- destObject.prototype[props[i]] = MicroEvent.prototype[props[i]];
754
- }
755
- };
756
-
757
- var IS_MAC = /Mac/.test(navigator.userAgent);
758
-
759
- var KEY_A = 65;
760
- var KEY_COMMA = 188;
761
- var KEY_RETURN = 13;
762
- var KEY_ESC = 27;
763
- var KEY_LEFT = 37;
764
- var KEY_UP = 38;
765
- var KEY_P = 80;
766
- var KEY_RIGHT = 39;
767
- var KEY_DOWN = 40;
768
- var KEY_N = 78;
769
- var KEY_BACKSPACE = 8;
770
- var KEY_DELETE = 46;
771
- var KEY_SHIFT = 16;
772
- var KEY_CMD = IS_MAC ? 91 : 17;
773
- var KEY_CTRL = IS_MAC ? 18 : 17;
774
- var KEY_TAB = 9;
775
-
776
- var TAG_SELECT = 1;
777
- var TAG_INPUT = 2;
778
-
779
- // for now, android support in general is too spotty to support validity
780
- var SUPPORTS_VALIDITY_API = !/android/i.test(window.navigator.userAgent) && !!document.createElement('input').validity;
781
-
782
-
783
- var isset = function(object) {
784
- return typeof object !== 'undefined';
785
- };
786
-
787
- /**
788
- * Converts a scalar to its best string representation
789
- * for hash keys and HTML attribute values.
790
- *
791
- * Transformations:
792
- * 'str' -> 'str'
793
- * null -> ''
794
- * undefined -> ''
795
- * true -> '1'
796
- * false -> '0'
797
- * 0 -> '0'
798
- * 1 -> '1'
799
- *
800
- * @param {string} value
801
- * @returns {string|null}
802
- */
803
- var hash_key = function(value) {
804
- if (typeof value === 'undefined' || value === null) return null;
805
- if (typeof value === 'boolean') return value ? '1' : '0';
806
- return value + '';
807
- };
808
-
809
- /**
810
- * Escapes a string for use within HTML.
811
- *
812
- * @param {string} str
813
- * @returns {string}
814
- */
815
- var escape_html = function(str) {
816
- return (str + '')
817
- .replace(/&/g, '&amp;')
818
- .replace(/</g, '&lt;')
819
- .replace(/>/g, '&gt;')
820
- .replace(/"/g, '&quot;');
821
- };
822
-
823
- /**
824
- * Escapes "$" characters in replacement strings.
825
- *
826
- * @param {string} str
827
- * @returns {string}
828
- */
829
- var escape_replace = function(str) {
830
- return (str + '').replace(/\$/g, '$$$$');
831
- };
832
-
833
- var hook = {};
834
-
835
- /**
836
- * Wraps `method` on `self` so that `fn`
837
- * is invoked before the original method.
838
- *
839
- * @param {object} self
840
- * @param {string} method
841
- * @param {function} fn
842
- */
843
- hook.before = function(self, method, fn) {
844
- var original = self[method];
845
- self[method] = function() {
846
- fn.apply(self, arguments);
847
- return original.apply(self, arguments);
848
- };
849
- };
850
-
851
- /**
852
- * Wraps `method` on `self` so that `fn`
853
- * is invoked after the original method.
854
- *
855
- * @param {object} self
856
- * @param {string} method
857
- * @param {function} fn
858
- */
859
- hook.after = function(self, method, fn) {
860
- var original = self[method];
861
- self[method] = function() {
862
- var result = original.apply(self, arguments);
863
- fn.apply(self, arguments);
864
- return result;
865
- };
866
- };
867
-
868
- /**
869
- * Wraps `fn` so that it can only be invoked once.
870
- *
871
- * @param {function} fn
872
- * @returns {function}
873
- */
874
- var once = function(fn) {
875
- var called = false;
876
- return function() {
877
- if (called) return;
878
- called = true;
879
- fn.apply(this, arguments);
880
- };
881
- };
882
-
883
- /**
884
- * Wraps `fn` so that it can only be called once
885
- * every `delay` milliseconds (invoked on the falling edge).
886
- *
887
- * @param {function} fn
888
- * @param {int} delay
889
- * @returns {function}
890
- */
891
- var debounce = function(fn, delay) {
892
- var timeout;
893
- return function() {
894
- var self = this;
895
- var args = arguments;
896
- window.clearTimeout(timeout);
897
- timeout = window.setTimeout(function() {
898
- fn.apply(self, args);
899
- }, delay);
900
- };
901
- };
902
-
903
- /**
904
- * Debounce all fired events types listed in `types`
905
- * while executing the provided `fn`.
906
- *
907
- * @param {object} self
908
- * @param {array} types
909
- * @param {function} fn
910
- */
911
- var debounce_events = function(self, types, fn) {
912
- var type;
913
- var trigger = self.trigger;
914
- var event_args = {};
915
-
916
- // override trigger method
917
- self.trigger = function() {
918
- var type = arguments[0];
919
- if (types.indexOf(type) !== -1) {
920
- event_args[type] = arguments;
921
- } else {
922
- return trigger.apply(self, arguments);
923
- }
924
- };
925
-
926
- // invoke provided function
927
- fn.apply(self, []);
928
- self.trigger = trigger;
929
-
930
- // trigger queued events
931
- for (type in event_args) {
932
- if (event_args.hasOwnProperty(type)) {
933
- trigger.apply(self, event_args[type]);
934
- }
935
- }
936
- };
937
-
938
- /**
939
- * A workaround for http://bugs.jquery.com/ticket/6696
940
- *
941
- * @param {object} $parent - Parent element to listen on.
942
- * @param {string} event - Event name.
943
- * @param {string} selector - Descendant selector to filter by.
944
- * @param {function} fn - Event handler.
945
- */
946
- var watchChildEvent = function($parent, event, selector, fn) {
947
- $parent.on(event, selector, function(e) {
948
- var child = e.target;
949
- while (child && child.parentNode !== $parent[0]) {
950
- child = child.parentNode;
951
- }
952
- e.currentTarget = child;
953
- return fn.apply(this, [e]);
954
- });
955
- };
956
-
957
- /**
958
- * Determines the current selection within a text input control.
959
- * Returns an object containing:
960
- * - start
961
- * - length
962
- *
963
- * @param {object} input
964
- * @returns {object}
965
- */
966
- var getSelection = function(input) {
967
- var result = {};
968
- if ('selectionStart' in input) {
969
- result.start = input.selectionStart;
970
- result.length = input.selectionEnd - result.start;
971
- } else if (document.selection) {
972
- input.focus();
973
- var sel = document.selection.createRange();
974
- var selLen = document.selection.createRange().text.length;
975
- sel.moveStart('character', -input.value.length);
976
- result.start = sel.text.length - selLen;
977
- result.length = selLen;
978
- }
979
- return result;
980
- };
981
-
982
- /**
983
- * Copies CSS properties from one element to another.
984
- *
985
- * @param {object} $from
986
- * @param {object} $to
987
- * @param {array} properties
988
- */
989
- var transferStyles = function($from, $to, properties) {
990
- var i, n, styles = {};
991
- if (properties) {
992
- for (i = 0, n = properties.length; i < n; i++) {
993
- styles[properties[i]] = $from.css(properties[i]);
994
- }
995
- } else {
996
- styles = $from.css();
997
- }
998
- $to.css(styles);
999
- };
1000
-
1001
- /**
1002
- * Measures the width of a string within a
1003
- * parent element (in pixels).
1004
- *
1005
- * @param {string} str
1006
- * @param {object} $parent
1007
- * @returns {int}
1008
- */
1009
- var measureString = function(str, $parent) {
1010
- if (!str) {
1011
- return 0;
1012
- }
1013
-
1014
- if (!Selectize.$testInput) {
1015
- Selectize.$testInput = $('<span />').css({
1016
- position: 'absolute',
1017
- top: -99999,
1018
- left: -99999,
1019
- width: 'auto',
1020
- padding: 0,
1021
- whiteSpace: 'pre'
1022
- }).appendTo('body');
1023
- }
1024
-
1025
- Selectize.$testInput.text(str);
1026
-
1027
- transferStyles($parent, Selectize.$testInput, [
1028
- 'letterSpacing',
1029
- 'fontSize',
1030
- 'fontFamily',
1031
- 'fontWeight',
1032
- 'textTransform'
1033
- ]);
1034
-
1035
- return Selectize.$testInput.width();
1036
- };
1037
-
1038
- /**
1039
- * Sets up an input to grow horizontally as the user
1040
- * types. If the value is changed manually, you can
1041
- * trigger the "update" handler to resize:
1042
- *
1043
- * $input.trigger('update');
1044
- *
1045
- * @param {object} $input
1046
- */
1047
- var autoGrow = function($input) {
1048
- var currentWidth = null;
1049
-
1050
- var update = function(e, options) {
1051
- var value, keyCode, printable, placeholder, width;
1052
- var shift, character, selection;
1053
- e = e || window.event || {};
1054
- options = options || {};
1055
-
1056
- if (e.metaKey || e.altKey) return;
1057
- if (!options.force && $input.data('grow') === false) return;
1058
-
1059
- value = $input.val();
1060
- if (e.type && e.type.toLowerCase() === 'keydown') {
1061
- keyCode = e.keyCode;
1062
- printable = (
1063
- (keyCode >= 48 && keyCode <= 57) || // 0-9
1064
- (keyCode >= 65 && keyCode <= 90) || // a-z
1065
- (keyCode >= 96 && keyCode <= 111) || // numpad 0-9, numeric operators
1066
- (keyCode >= 186 && keyCode <= 222) || // semicolon, equal, comma, dash, etc.
1067
- keyCode === 32 // space
1068
- );
1069
-
1070
- if (keyCode === KEY_DELETE || keyCode === KEY_BACKSPACE) {
1071
- selection = getSelection($input[0]);
1072
- if (selection.length) {
1073
- value = value.substring(0, selection.start) + value.substring(selection.start + selection.length);
1074
- } else if (keyCode === KEY_BACKSPACE && selection.start) {
1075
- value = value.substring(0, selection.start - 1) + value.substring(selection.start + 1);
1076
- } else if (keyCode === KEY_DELETE && typeof selection.start !== 'undefined') {
1077
- value = value.substring(0, selection.start) + value.substring(selection.start + 1);
1078
- }
1079
- } else if (printable) {
1080
- shift = e.shiftKey;
1081
- character = String.fromCharCode(e.keyCode);
1082
- if (shift) character = character.toUpperCase();
1083
- else character = character.toLowerCase();
1084
- value += character;
1085
- }
1086
- }
1087
-
1088
- placeholder = $input.attr('placeholder');
1089
- if (!value && placeholder) {
1090
- value = placeholder;
1091
- }
1092
-
1093
- width = measureString(value, $input) + 4;
1094
- if (width !== currentWidth) {
1095
- currentWidth = width;
1096
- $input.width(width);
1097
- $input.triggerHandler('resize');
1098
- }
1099
- };
1100
-
1101
- $input.on('keydown keyup update blur', update);
1102
- update();
1103
- };
1104
-
1105
- var domToString = function(d) {
1106
- var tmp = document.createElement('div');
1107
-
1108
- tmp.appendChild(d.cloneNode(true));
1109
-
1110
- return tmp.innerHTML;
1111
- };
1112
-
1113
- var logError = function(message, options){
1114
- if(!options) options = {};
1115
- var component = "Selectize";
1116
-
1117
- console.error(component + ": " + message)
1118
-
1119
- if(options.explanation){
1120
- // console.group is undefined in <IE11
1121
- if(console.group) console.group();
1122
- console.error(options.explanation);
1123
- if(console.group) console.groupEnd();
1124
- }
1125
- }
1126
-
1127
-
1128
- var Selectize = function($input, settings) {
1129
- var key, i, n, dir, input, self = this;
1130
- input = $input[0];
1131
- input.selectize = self;
1132
-
1133
- // detect rtl environment
1134
- var computedStyle = window.getComputedStyle && window.getComputedStyle(input, null);
1135
- dir = computedStyle ? computedStyle.getPropertyValue('direction') : input.currentStyle && input.currentStyle.direction;
1136
- dir = dir || $input.parents('[dir]:first').attr('dir') || '';
1137
-
1138
- // setup default state
1139
- $.extend(self, {
1140
- order : 0,
1141
- settings : settings,
1142
- $input : $input,
1143
- tabIndex : $input.attr('tabindex') || '',
1144
- tagType : input.tagName.toLowerCase() === 'select' ? TAG_SELECT : TAG_INPUT,
1145
- rtl : /rtl/i.test(dir),
1146
-
1147
- eventNS : '.selectize' + (++Selectize.count),
1148
- highlightedValue : null,
1149
- isBlurring : false,
1150
- isOpen : false,
1151
- isDisabled : false,
1152
- isRequired : $input.is('[required]'),
1153
- isInvalid : false,
1154
- isLocked : false,
1155
- isFocused : false,
1156
- isInputHidden : false,
1157
- isSetup : false,
1158
- isShiftDown : false,
1159
- isCmdDown : false,
1160
- isCtrlDown : false,
1161
- ignoreFocus : false,
1162
- ignoreBlur : false,
1163
- ignoreHover : false,
1164
- hasOptions : false,
1165
- currentResults : null,
1166
- lastValue : '',
1167
- caretPos : 0,
1168
- loading : 0,
1169
- loadedSearches : {},
1170
-
1171
- $activeOption : null,
1172
- $activeItems : [],
1173
-
1174
- optgroups : {},
1175
- options : {},
1176
- userOptions : {},
1177
- items : [],
1178
- renderCache : {},
1179
- onSearchChange : settings.loadThrottle === null ? self.onSearchChange : debounce(self.onSearchChange, settings.loadThrottle)
1180
- });
1181
-
1182
- // search system
1183
- self.sifter = new Sifter(this.options, {diacritics: settings.diacritics});
1184
-
1185
- // build options table
1186
- if (self.settings.options) {
1187
- for (i = 0, n = self.settings.options.length; i < n; i++) {
1188
- self.registerOption(self.settings.options[i]);
1189
- }
1190
- delete self.settings.options;
1191
- }
1192
-
1193
- // build optgroup table
1194
- if (self.settings.optgroups) {
1195
- for (i = 0, n = self.settings.optgroups.length; i < n; i++) {
1196
- self.registerOptionGroup(self.settings.optgroups[i]);
1197
- }
1198
- delete self.settings.optgroups;
1199
- }
1200
-
1201
- // option-dependent defaults
1202
- self.settings.mode = self.settings.mode || (self.settings.maxItems === 1 ? 'single' : 'multi');
1203
- if (typeof self.settings.hideSelected !== 'boolean') {
1204
- self.settings.hideSelected = self.settings.mode === 'multi';
1205
- }
1206
-
1207
- self.initializePlugins(self.settings.plugins);
1208
- self.setupCallbacks();
1209
- self.setupTemplates();
1210
- self.setup();
1211
- };
1212
-
1213
- // mixins
1214
- // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1215
-
1216
- MicroEvent.mixin(Selectize);
1217
-
1218
- if(typeof MicroPlugin !== "undefined"){
1219
- MicroPlugin.mixin(Selectize);
1220
- }else{
1221
- logError("Dependency MicroPlugin is missing",
1222
- {explanation:
1223
- "Make sure you either: (1) are using the \"standalone\" "+
1224
- "version of Selectize, or (2) require MicroPlugin before you "+
1225
- "load Selectize."}
1226
- );
1227
- }
1228
-
1229
-
1230
- // methods
1231
- // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1232
-
1233
- $.extend(Selectize.prototype, {
1234
-
1235
- /**
1236
- * Creates all elements and sets up event bindings.
1237
- */
1238
- setup: function() {
1239
- var self = this;
1240
- var settings = self.settings;
1241
- var eventNS = self.eventNS;
1242
- var $window = $(window);
1243
- var $document = $(document);
1244
- var $input = self.$input;
1245
-
1246
- var $wrapper;
1247
- var $control;
1248
- var $control_input;
1249
- var $dropdown;
1250
- var $dropdown_content;
1251
- var $dropdown_parent;
1252
- var inputMode;
1253
- var timeout_blur;
1254
- var timeout_focus;
1255
- var classes;
1256
- var classes_plugins;
1257
- var inputId;
1258
-
1259
- inputMode = self.settings.mode;
1260
- classes = $input.attr('class') || '';
1261
-
1262
- $wrapper = $('<div>').addClass(settings.wrapperClass).addClass(classes).addClass(inputMode);
1263
- $control = $('<div>').addClass(settings.inputClass).addClass('items').appendTo($wrapper);
1264
- $control_input = $('<input type="text" autocomplete="off" />').appendTo($control).attr('tabindex', $input.is(':disabled') ? '-1' : self.tabIndex);
1265
- $dropdown_parent = $(settings.dropdownParent || $wrapper);
1266
- $dropdown = $('<div>').addClass(settings.dropdownClass).addClass(inputMode).hide().appendTo($dropdown_parent);
1267
- $dropdown_content = $('<div>').addClass(settings.dropdownContentClass).appendTo($dropdown);
1268
-
1269
- if(inputId = $input.attr('id')) {
1270
- $control_input.attr('id', inputId + '-selectized');
1271
- $("label[for='"+inputId+"']").attr('for', inputId + '-selectized');
1272
- }
1273
-
1274
- if(self.settings.copyClassesToDropdown) {
1275
- $dropdown.addClass(classes);
1276
- }
1277
-
1278
- $wrapper.css({
1279
- width: $input[0].style.width
1280
- });
1281
-
1282
- if (self.plugins.names.length) {
1283
- classes_plugins = 'plugin-' + self.plugins.names.join(' plugin-');
1284
- $wrapper.addClass(classes_plugins);
1285
- $dropdown.addClass(classes_plugins);
1286
- }
1287
-
1288
- if ((settings.maxItems === null || settings.maxItems > 1) && self.tagType === TAG_SELECT) {
1289
- $input.attr('multiple', 'multiple');
1290
- }
1291
-
1292
- if (self.settings.placeholder) {
1293
- $control_input.attr('placeholder', settings.placeholder);
1294
- }
1295
-
1296
- // if splitOn was not passed in, construct it from the delimiter to allow pasting universally
1297
- if (!self.settings.splitOn && self.settings.delimiter) {
1298
- var delimiterEscaped = self.settings.delimiter.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
1299
- self.settings.splitOn = new RegExp('\\s*' + delimiterEscaped + '+\\s*');
1300
- }
1301
-
1302
- if ($input.attr('autocorrect')) {
1303
- $control_input.attr('autocorrect', $input.attr('autocorrect'));
1304
- }
1305
-
1306
- if ($input.attr('autocapitalize')) {
1307
- $control_input.attr('autocapitalize', $input.attr('autocapitalize'));
1308
- }
1309
- $control_input[0].type = $input[0].type;
1310
-
1311
- self.$wrapper = $wrapper;
1312
- self.$control = $control;
1313
- self.$control_input = $control_input;
1314
- self.$dropdown = $dropdown;
1315
- self.$dropdown_content = $dropdown_content;
1316
-
1317
- $dropdown.on('mouseenter mousedown click', '[data-disabled]>[data-selectable]', function(e) { e.stopImmediatePropagation(); });
1318
- $dropdown.on('mouseenter', '[data-selectable]', function() { return self.onOptionHover.apply(self, arguments); });
1319
- $dropdown.on('mousedown click', '[data-selectable]', function() { return self.onOptionSelect.apply(self, arguments); });
1320
- watchChildEvent($control, 'mousedown', '*:not(input)', function() { return self.onItemSelect.apply(self, arguments); });
1321
- autoGrow($control_input);
1322
-
1323
- $control.on({
1324
- mousedown : function() { return self.onMouseDown.apply(self, arguments); },
1325
- click : function() { return self.onClick.apply(self, arguments); }
1326
- });
1327
-
1328
- $control_input.on({
1329
- mousedown : function(e) { e.stopPropagation(); },
1330
- keydown : function() { return self.onKeyDown.apply(self, arguments); },
1331
- keyup : function() { return self.onKeyUp.apply(self, arguments); },
1332
- keypress : function() { return self.onKeyPress.apply(self, arguments); },
1333
- resize : function() { self.positionDropdown.apply(self, []); },
1334
- blur : function() { return self.onBlur.apply(self, arguments); },
1335
- focus : function() { self.ignoreBlur = false; return self.onFocus.apply(self, arguments); },
1336
- paste : function() { return self.onPaste.apply(self, arguments); }
1337
- });
1338
-
1339
- $document.on('keydown' + eventNS, function(e) {
1340
- self.isCmdDown = e[IS_MAC ? 'metaKey' : 'ctrlKey'];
1341
- self.isCtrlDown = e[IS_MAC ? 'altKey' : 'ctrlKey'];
1342
- self.isShiftDown = e.shiftKey;
1343
- });
1344
-
1345
- $document.on('keyup' + eventNS, function(e) {
1346
- if (e.keyCode === KEY_CTRL) self.isCtrlDown = false;
1347
- if (e.keyCode === KEY_SHIFT) self.isShiftDown = false;
1348
- if (e.keyCode === KEY_CMD) self.isCmdDown = false;
1349
- });
1350
-
1351
- $document.on('mousedown' + eventNS, function(e) {
1352
- if (self.isFocused) {
1353
- // prevent events on the dropdown scrollbar from causing the control to blur
1354
- if (e.target === self.$dropdown[0] || e.target.parentNode === self.$dropdown[0]) {
1355
- return false;
1356
- }
1357
- // blur on click outside
1358
- if (!self.$control.has(e.target).length && e.target !== self.$control[0]) {
1359
- self.blur(e.target);
1360
- }
1361
- }
1362
- });
1363
-
1364
- $window.on(['scroll' + eventNS, 'resize' + eventNS].join(' '), function() {
1365
- if (self.isOpen) {
1366
- self.positionDropdown.apply(self, arguments);
1367
- }
1368
- });
1369
- $window.on('mousemove' + eventNS, function() {
1370
- self.ignoreHover = false;
1371
- });
1372
-
1373
- // store original children and tab index so that they can be
1374
- // restored when the destroy() method is called.
1375
- this.revertSettings = {
1376
- $children : $input.children().detach(),
1377
- tabindex : $input.attr('tabindex')
1378
- };
1379
-
1380
- $input.attr('tabindex', -1).hide().after(self.$wrapper);
1381
-
1382
- if ($.isArray(settings.items)) {
1383
- self.setValue(settings.items);
1384
- delete settings.items;
1385
- }
1386
-
1387
- // feature detect for the validation API
1388
- if (SUPPORTS_VALIDITY_API) {
1389
- $input.on('invalid' + eventNS, function(e) {
1390
- e.preventDefault();
1391
- self.isInvalid = true;
1392
- self.refreshState();
1393
- });
1394
- }
1395
-
1396
- self.updateOriginalInput();
1397
- self.refreshItems();
1398
- self.refreshState();
1399
- self.updatePlaceholder();
1400
- self.isSetup = true;
1401
-
1402
- if ($input.is(':disabled')) {
1403
- self.disable();
1404
- }
1405
-
1406
- self.on('change', this.onChange);
1407
-
1408
- $input.data('selectize', self);
1409
- $input.addClass('selectized');
1410
- self.trigger('initialize');
1411
-
1412
- // preload options
1413
- if (settings.preload === true) {
1414
- self.onSearchChange('');
1415
- }
1416
-
1417
- },
1418
-
1419
- /**
1420
- * Sets up default rendering functions.
1421
- */
1422
- setupTemplates: function() {
1423
- var self = this;
1424
- var field_label = self.settings.labelField;
1425
- var field_optgroup = self.settings.optgroupLabelField;
1426
-
1427
- var templates = {
1428
- 'optgroup': function(data) {
1429
- return '<div class="optgroup">' + data.html + '</div>';
1430
- },
1431
- 'optgroup_header': function(data, escape) {
1432
- return '<div class="optgroup-header">' + escape(data[field_optgroup]) + '</div>';
1433
- },
1434
- 'option': function(data, escape) {
1435
- return '<div class="option">' + escape(data[field_label]) + '</div>';
1436
- },
1437
- 'item': function(data, escape) {
1438
- return '<div class="item">' + escape(data[field_label]) + '</div>';
1439
- },
1440
- 'option_create': function(data, escape) {
1441
- return '<div class="create">Add <strong>' + escape(data.input) + '</strong>&hellip;</div>';
1442
- }
1443
- };
1444
-
1445
- self.settings.render = $.extend({}, templates, self.settings.render);
1446
- },
1447
-
1448
- /**
1449
- * Maps fired events to callbacks provided
1450
- * in the settings used when creating the control.
1451
- */
1452
- setupCallbacks: function() {
1453
- var key, fn, callbacks = {
1454
- 'initialize' : 'onInitialize',
1455
- 'change' : 'onChange',
1456
- 'item_add' : 'onItemAdd',
1457
- 'item_remove' : 'onItemRemove',
1458
- 'clear' : 'onClear',
1459
- 'option_add' : 'onOptionAdd',
1460
- 'option_remove' : 'onOptionRemove',
1461
- 'option_clear' : 'onOptionClear',
1462
- 'optgroup_add' : 'onOptionGroupAdd',
1463
- 'optgroup_remove' : 'onOptionGroupRemove',
1464
- 'optgroup_clear' : 'onOptionGroupClear',
1465
- 'dropdown_open' : 'onDropdownOpen',
1466
- 'dropdown_close' : 'onDropdownClose',
1467
- 'type' : 'onType',
1468
- 'load' : 'onLoad',
1469
- 'focus' : 'onFocus',
1470
- 'blur' : 'onBlur'
1471
- };
1472
-
1473
- for (key in callbacks) {
1474
- if (callbacks.hasOwnProperty(key)) {
1475
- fn = this.settings[callbacks[key]];
1476
- if (fn) this.on(key, fn);
1477
- }
1478
- }
1479
- },
1480
-
1481
- /**
1482
- * Triggered when the main control element
1483
- * has a click event.
1484
- *
1485
- * @param {object} e
1486
- * @return {boolean}
1487
- */
1488
- onClick: function(e) {
1489
- var self = this;
1490
-
1491
- // necessary for mobile webkit devices (manual focus triggering
1492
- // is ignored unless invoked within a click event)
1493
- // also necessary to reopen a dropdown that has been closed by
1494
- // closeAfterSelect
1495
- if (!self.isFocused || !self.isOpen) {
1496
- self.focus();
1497
- e.preventDefault();
1498
- }
1499
- },
1500
-
1501
- /**
1502
- * Triggered when the main control element
1503
- * has a mouse down event.
1504
- *
1505
- * @param {object} e
1506
- * @return {boolean}
1507
- */
1508
- onMouseDown: function(e) {
1509
- var self = this;
1510
- var defaultPrevented = e.isDefaultPrevented();
1511
- var $target = $(e.target);
1512
-
1513
- if (self.isFocused) {
1514
- // retain focus by preventing native handling. if the
1515
- // event target is the input it should not be modified.
1516
- // otherwise, text selection within the input won't work.
1517
- if (e.target !== self.$control_input[0]) {
1518
- if (self.settings.mode === 'single') {
1519
- // toggle dropdown
1520
- self.isOpen ? self.close() : self.open();
1521
- } else if (!defaultPrevented) {
1522
- self.setActiveItem(null);
1523
- }
1524
- return false;
1525
- }
1526
- } else {
1527
- // give control focus
1528
- if (!defaultPrevented) {
1529
- window.setTimeout(function() {
1530
- self.focus();
1531
- }, 0);
1532
- }
1533
- }
1534
- },
1535
-
1536
- /**
1537
- * Triggered when the value of the control has been changed.
1538
- * This should propagate the event to the original DOM
1539
- * input / select element.
1540
- */
1541
- onChange: function() {
1542
- this.$input.trigger('change');
1543
- },
1544
-
1545
- /**
1546
- * Triggered on <input> paste.
1547
- *
1548
- * @param {object} e
1549
- * @returns {boolean}
1550
- */
1551
- onPaste: function(e) {
1552
- var self = this;
1553
-
1554
- if (self.isFull() || self.isInputHidden || self.isLocked) {
1555
- e.preventDefault();
1556
- return;
1557
- }
1558
-
1559
- // If a regex or string is included, this will split the pasted
1560
- // input and create Items for each separate value
1561
- if (self.settings.splitOn) {
1562
-
1563
- // Wait for pasted text to be recognized in value
1564
- setTimeout(function() {
1565
- var pastedText = self.$control_input.val();
1566
- if(!pastedText.match(self.settings.splitOn)){ return }
1567
-
1568
- var splitInput = $.trim(pastedText).split(self.settings.splitOn);
1569
- for (var i = 0, n = splitInput.length; i < n; i++) {
1570
- self.createItem(splitInput[i]);
1571
- }
1572
- }, 0);
1573
- }
1574
- },
1575
-
1576
- /**
1577
- * Triggered on <input> keypress.
1578
- *
1579
- * @param {object} e
1580
- * @returns {boolean}
1581
- */
1582
- onKeyPress: function(e) {
1583
- if (this.isLocked) return e && e.preventDefault();
1584
- var character = String.fromCharCode(e.keyCode || e.which);
1585
- if (this.settings.create && this.settings.mode === 'multi' && character === this.settings.delimiter) {
1586
- this.createItem();
1587
- e.preventDefault();
1588
- return false;
1589
- }
1590
- },
1591
-
1592
- /**
1593
- * Triggered on <input> keydown.
1594
- *
1595
- * @param {object} e
1596
- * @returns {boolean}
1597
- */
1598
- onKeyDown: function(e) {
1599
- var isInput = e.target === this.$control_input[0];
1600
- var self = this;
1601
-
1602
- if (self.isLocked) {
1603
- if (e.keyCode !== KEY_TAB) {
1604
- e.preventDefault();
1605
- }
1606
- return;
1607
- }
1608
-
1609
- switch (e.keyCode) {
1610
- case KEY_A:
1611
- if (self.isCmdDown) {
1612
- self.selectAll();
1613
- return;
1614
- }
1615
- break;
1616
- case KEY_ESC:
1617
- if (self.isOpen) {
1618
- e.preventDefault();
1619
- e.stopPropagation();
1620
- self.close();
1621
- }
1622
- return;
1623
- case KEY_N:
1624
- if (!e.ctrlKey || e.altKey) break;
1625
- case KEY_DOWN:
1626
- if (!self.isOpen && self.hasOptions) {
1627
- self.open();
1628
- } else if (self.$activeOption) {
1629
- self.ignoreHover = true;
1630
- var $next = self.getAdjacentOption(self.$activeOption, 1);
1631
- if ($next.length) self.setActiveOption($next, true, true);
1632
- }
1633
- e.preventDefault();
1634
- return;
1635
- case KEY_P:
1636
- if (!e.ctrlKey || e.altKey) break;
1637
- case KEY_UP:
1638
- if (self.$activeOption) {
1639
- self.ignoreHover = true;
1640
- var $prev = self.getAdjacentOption(self.$activeOption, -1);
1641
- if ($prev.length) self.setActiveOption($prev, true, true);
1642
- }
1643
- e.preventDefault();
1644
- return;
1645
- case KEY_RETURN:
1646
- if (self.isOpen && self.$activeOption) {
1647
- self.onOptionSelect({currentTarget: self.$activeOption});
1648
- e.preventDefault();
1649
- }
1650
- return;
1651
- case KEY_LEFT:
1652
- self.advanceSelection(-1, e);
1653
- return;
1654
- case KEY_RIGHT:
1655
- self.advanceSelection(1, e);
1656
- return;
1657
- case KEY_TAB:
1658
- if (self.settings.selectOnTab && self.isOpen && self.$activeOption) {
1659
- self.onOptionSelect({currentTarget: self.$activeOption});
1660
-
1661
- // Default behaviour is to jump to the next field, we only want this
1662
- // if the current field doesn't accept any more entries
1663
- if (!self.isFull()) {
1664
- e.preventDefault();
1665
- }
1666
- }
1667
- if (self.settings.create && self.createItem()) {
1668
- e.preventDefault();
1669
- }
1670
- return;
1671
- case KEY_BACKSPACE:
1672
- case KEY_DELETE:
1673
- self.deleteSelection(e);
1674
- return;
1675
- }
1676
-
1677
- if ((self.isFull() || self.isInputHidden) && !(IS_MAC ? e.metaKey : e.ctrlKey)) {
1678
- e.preventDefault();
1679
- return;
1680
- }
1681
- },
1682
-
1683
- /**
1684
- * Triggered on <input> keyup.
1685
- *
1686
- * @param {object} e
1687
- * @returns {boolean}
1688
- */
1689
- onKeyUp: function(e) {
1690
- var self = this;
1691
-
1692
- if (self.isLocked) return e && e.preventDefault();
1693
- var value = self.$control_input.val() || '';
1694
- if (self.lastValue !== value) {
1695
- self.lastValue = value;
1696
- self.onSearchChange(value);
1697
- self.refreshOptions();
1698
- self.trigger('type', value);
1699
- }
1700
- },
1701
-
1702
- /**
1703
- * Invokes the user-provide option provider / loader.
1704
- *
1705
- * Note: this function is debounced in the Selectize
1706
- * constructor (by `settings.loadThrottle` milliseconds)
1707
- *
1708
- * @param {string} value
1709
- */
1710
- onSearchChange: function(value) {
1711
- var self = this;
1712
- var fn = self.settings.load;
1713
- if (!fn) return;
1714
- if (self.loadedSearches.hasOwnProperty(value)) return;
1715
- self.loadedSearches[value] = true;
1716
- self.load(function(callback) {
1717
- fn.apply(self, [value, callback]);
1718
- });
1719
- },
1720
-
1721
- /**
1722
- * Triggered on <input> focus.
1723
- *
1724
- * @param {object} e (optional)
1725
- * @returns {boolean}
1726
- */
1727
- onFocus: function(e) {
1728
- var self = this;
1729
- var wasFocused = self.isFocused;
1730
-
1731
- if (self.isDisabled) {
1732
- self.blur();
1733
- e && e.preventDefault();
1734
- return false;
1735
- }
1736
-
1737
- if (self.ignoreFocus) return;
1738
- self.isFocused = true;
1739
- if (self.settings.preload === 'focus') self.onSearchChange('');
1740
-
1741
- if (!wasFocused) self.trigger('focus');
1742
-
1743
- if (!self.$activeItems.length) {
1744
- self.showInput();
1745
- self.setActiveItem(null);
1746
- self.refreshOptions(!!self.settings.openOnFocus);
1747
- }
1748
-
1749
- self.refreshState();
1750
- },
1751
-
1752
- /**
1753
- * Triggered on <input> blur.
1754
- *
1755
- * @param {object} e
1756
- * @param {Element} dest
1757
- */
1758
- onBlur: function(e, dest) {
1759
- var self = this;
1760
- if (!self.isFocused) return;
1761
- self.isFocused = false;
1762
-
1763
- if (self.ignoreFocus) {
1764
- return;
1765
- } else if (!self.ignoreBlur && document.activeElement === self.$dropdown_content[0]) {
1766
- // necessary to prevent IE closing the dropdown when the scrollbar is clicked
1767
- self.ignoreBlur = true;
1768
- self.onFocus(e);
1769
- return;
1770
- }
1771
-
1772
- var deactivate = function() {
1773
- self.close();
1774
- self.setTextboxValue('');
1775
- self.setActiveItem(null);
1776
- self.setActiveOption(null);
1777
- self.setCaret(self.items.length);
1778
- self.refreshState();
1779
-
1780
- // IE11 bug: element still marked as active
1781
- dest && dest.focus && dest.focus();
1782
-
1783
- self.isBlurring = false;
1784
- self.ignoreFocus = false;
1785
- self.trigger('blur');
1786
- };
1787
-
1788
- self.isBlurring = true;
1789
- self.ignoreFocus = true;
1790
- if (self.settings.create && self.settings.createOnBlur) {
1791
- self.createItem(null, false, deactivate);
1792
- } else {
1793
- deactivate();
1794
- }
1795
- },
1796
-
1797
- /**
1798
- * Triggered when the user rolls over
1799
- * an option in the autocomplete dropdown menu.
1800
- *
1801
- * @param {object} e
1802
- * @returns {boolean}
1803
- */
1804
- onOptionHover: function(e) {
1805
- if (this.ignoreHover) return;
1806
- this.setActiveOption(e.currentTarget, false);
1807
- },
1808
-
1809
- /**
1810
- * Triggered when the user clicks on an option
1811
- * in the autocomplete dropdown menu.
1812
- *
1813
- * @param {object} e
1814
- * @returns {boolean}
1815
- */
1816
- onOptionSelect: function(e) {
1817
- var value, $target, $option, self = this;
1818
-
1819
- if (e.preventDefault) {
1820
- e.preventDefault();
1821
- e.stopPropagation();
1822
- }
1823
-
1824
- $target = $(e.currentTarget);
1825
- if ($target.hasClass('create')) {
1826
- self.createItem(null, function() {
1827
- if (self.settings.closeAfterSelect) {
1828
- self.close();
1829
- }
1830
- });
1831
- } else {
1832
- value = $target.attr('data-value');
1833
- if (typeof value !== 'undefined') {
1834
- self.lastQuery = null;
1835
- self.setTextboxValue('');
1836
- self.addItem(value);
1837
- if (self.settings.closeAfterSelect) {
1838
- self.close();
1839
- } else if (!self.settings.hideSelected && e.type && /mouse/.test(e.type)) {
1840
- self.setActiveOption(self.getOption(value));
1841
- }
1842
- }
1843
- }
1844
- },
1845
-
1846
- /**
1847
- * Triggered when the user clicks on an item
1848
- * that has been selected.
1849
- *
1850
- * @param {object} e
1851
- * @returns {boolean}
1852
- */
1853
- onItemSelect: function(e) {
1854
- var self = this;
1855
-
1856
- if (self.isLocked) return;
1857
- if (self.settings.mode === 'multi') {
1858
- e.preventDefault();
1859
- self.setActiveItem(e.currentTarget, e);
1860
- }
1861
- },
1862
-
1863
- /**
1864
- * Invokes the provided method that provides
1865
- * results to a callback---which are then added
1866
- * as options to the control.
1867
- *
1868
- * @param {function} fn
1869
- */
1870
- load: function(fn) {
1871
- var self = this;
1872
- var $wrapper = self.$wrapper.addClass(self.settings.loadingClass);
1873
-
1874
- self.loading++;
1875
- fn.apply(self, [function(results) {
1876
- self.loading = Math.max(self.loading - 1, 0);
1877
- if (results && results.length) {
1878
- self.addOption(results);
1879
- self.refreshOptions(self.isFocused && !self.isInputHidden);
1880
- }
1881
- if (!self.loading) {
1882
- $wrapper.removeClass(self.settings.loadingClass);
1883
- }
1884
- self.trigger('load', results);
1885
- }]);
1886
- },
1887
-
1888
- /**
1889
- * Sets the input field of the control to the specified value.
1890
- *
1891
- * @param {string} value
1892
- */
1893
- setTextboxValue: function(value) {
1894
- var $input = this.$control_input;
1895
- var changed = $input.val() !== value;
1896
- if (changed) {
1897
- $input.val(value).triggerHandler('update');
1898
- this.lastValue = value;
1899
- }
1900
- },
1901
-
1902
- /**
1903
- * Returns the value of the control. If multiple items
1904
- * can be selected (e.g. <select multiple>), this returns
1905
- * an array. If only one item can be selected, this
1906
- * returns a string.
1907
- *
1908
- * @returns {mixed}
1909
- */
1910
- getValue: function() {
1911
- if (this.tagType === TAG_SELECT && this.$input.attr('multiple')) {
1912
- return this.items;
1913
- } else {
1914
- return this.items.join(this.settings.delimiter);
1915
- }
1916
- },
1917
-
1918
- /**
1919
- * Resets the selected items to the given value.
1920
- *
1921
- * @param {mixed} value
1922
- */
1923
- setValue: function(value, silent) {
1924
- var events = silent ? [] : ['change'];
1925
-
1926
- debounce_events(this, events, function() {
1927
- this.clear(silent);
1928
- this.addItems(value, silent);
1929
- });
1930
- },
1931
-
1932
- /**
1933
- * Sets the selected item.
1934
- *
1935
- * @param {object} $item
1936
- * @param {object} e (optional)
1937
- */
1938
- setActiveItem: function($item, e) {
1939
- var self = this;
1940
- var eventName;
1941
- var i, idx, begin, end, item, swap;
1942
- var $last;
1943
-
1944
- if (self.settings.mode === 'single') return;
1945
- $item = $($item);
1946
-
1947
- // clear the active selection
1948
- if (!$item.length) {
1949
- $(self.$activeItems).removeClass('active');
1950
- self.$activeItems = [];
1951
- if (self.isFocused) {
1952
- self.showInput();
1953
- }
1954
- return;
1955
- }
1956
-
1957
- // modify selection
1958
- eventName = e && e.type.toLowerCase();
1959
-
1960
- if (eventName === 'mousedown' && self.isShiftDown && self.$activeItems.length) {
1961
- $last = self.$control.children('.active:last');
1962
- begin = Array.prototype.indexOf.apply(self.$control[0].childNodes, [$last[0]]);
1963
- end = Array.prototype.indexOf.apply(self.$control[0].childNodes, [$item[0]]);
1964
- if (begin > end) {
1965
- swap = begin;
1966
- begin = end;
1967
- end = swap;
1968
- }
1969
- for (i = begin; i <= end; i++) {
1970
- item = self.$control[0].childNodes[i];
1971
- if (self.$activeItems.indexOf(item) === -1) {
1972
- $(item).addClass('active');
1973
- self.$activeItems.push(item);
1974
- }
1975
- }
1976
- e.preventDefault();
1977
- } else if ((eventName === 'mousedown' && self.isCtrlDown) || (eventName === 'keydown' && this.isShiftDown)) {
1978
- if ($item.hasClass('active')) {
1979
- idx = self.$activeItems.indexOf($item[0]);
1980
- self.$activeItems.splice(idx, 1);
1981
- $item.removeClass('active');
1982
- } else {
1983
- self.$activeItems.push($item.addClass('active')[0]);
1984
- }
1985
- } else {
1986
- $(self.$activeItems).removeClass('active');
1987
- self.$activeItems = [$item.addClass('active')[0]];
1988
- }
1989
-
1990
- // ensure control has focus
1991
- self.hideInput();
1992
- if (!this.isFocused) {
1993
- self.focus();
1994
- }
1995
- },
1996
-
1997
- /**
1998
- * Sets the selected item in the dropdown menu
1999
- * of available options.
2000
- *
2001
- * @param {object} $object
2002
- * @param {boolean} scroll
2003
- * @param {boolean} animate
2004
- */
2005
- setActiveOption: function($option, scroll, animate) {
2006
- var height_menu, height_item, y;
2007
- var scroll_top, scroll_bottom;
2008
- var self = this;
2009
-
2010
- if (self.$activeOption) self.$activeOption.removeClass('active');
2011
- self.$activeOption = null;
2012
-
2013
- $option = $($option);
2014
- if (!$option.length) return;
2015
-
2016
- self.$activeOption = $option.addClass('active');
2017
-
2018
- if (scroll || !isset(scroll)) {
2019
-
2020
- height_menu = self.$dropdown_content.height();
2021
- height_item = self.$activeOption.outerHeight(true);
2022
- scroll = self.$dropdown_content.scrollTop() || 0;
2023
- y = self.$activeOption.offset().top - self.$dropdown_content.offset().top + scroll;
2024
- scroll_top = y;
2025
- scroll_bottom = y - height_menu + height_item;
2026
-
2027
- if (y + height_item > height_menu + scroll) {
2028
- self.$dropdown_content.stop().animate({scrollTop: scroll_bottom}, animate ? self.settings.scrollDuration : 0);
2029
- } else if (y < scroll) {
2030
- self.$dropdown_content.stop().animate({scrollTop: scroll_top}, animate ? self.settings.scrollDuration : 0);
2031
- }
2032
-
2033
- }
2034
- },
2035
-
2036
- /**
2037
- * Selects all items (CTRL + A).
2038
- */
2039
- selectAll: function() {
2040
- var self = this;
2041
- if (self.settings.mode === 'single') return;
2042
-
2043
- self.$activeItems = Array.prototype.slice.apply(self.$control.children(':not(input)').addClass('active'));
2044
- if (self.$activeItems.length) {
2045
- self.hideInput();
2046
- self.close();
2047
- }
2048
- self.focus();
2049
- },
2050
-
2051
- /**
2052
- * Hides the input element out of view, while
2053
- * retaining its focus.
2054
- */
2055
- hideInput: function() {
2056
- var self = this;
2057
-
2058
- self.setTextboxValue('');
2059
- self.$control_input.css({opacity: 0, position: 'absolute', left: self.rtl ? 10000 : -10000});
2060
- self.isInputHidden = true;
2061
- },
2062
-
2063
- /**
2064
- * Restores input visibility.
2065
- */
2066
- showInput: function() {
2067
- this.$control_input.css({opacity: 1, position: 'relative', left: 0});
2068
- this.isInputHidden = false;
2069
- },
2070
-
2071
- /**
2072
- * Gives the control focus.
2073
- */
2074
- focus: function() {
2075
- var self = this;
2076
- if (self.isDisabled) return;
2077
-
2078
- self.ignoreFocus = true;
2079
- self.$control_input[0].focus();
2080
- window.setTimeout(function() {
2081
- self.ignoreFocus = false;
2082
- self.onFocus();
2083
- }, 0);
2084
- },
2085
-
2086
- /**
2087
- * Forces the control out of focus.
2088
- *
2089
- * @param {Element} dest
2090
- */
2091
- blur: function(dest) {
2092
- this.$control_input[0].blur();
2093
- this.onBlur(null, dest);
2094
- },
2095
-
2096
- /**
2097
- * Returns a function that scores an object
2098
- * to show how good of a match it is to the
2099
- * provided query.
2100
- *
2101
- * @param {string} query
2102
- * @param {object} options
2103
- * @return {function}
2104
- */
2105
- getScoreFunction: function(query) {
2106
- return this.sifter.getScoreFunction(query, this.getSearchOptions());
2107
- },
2108
-
2109
- /**
2110
- * Returns search options for sifter (the system
2111
- * for scoring and sorting results).
2112
- *
2113
- * @see https://github.com/brianreavis/sifter.js
2114
- * @return {object}
2115
- */
2116
- getSearchOptions: function() {
2117
- var settings = this.settings;
2118
- var sort = settings.sortField;
2119
- if (typeof sort === 'string') {
2120
- sort = [{field: sort}];
2121
- }
2122
-
2123
- return {
2124
- fields : settings.searchField,
2125
- conjunction : settings.searchConjunction,
2126
- sort : sort,
2127
- nesting : settings.nesting
2128
- };
2129
- },
2130
-
2131
- /**
2132
- * Searches through available options and returns
2133
- * a sorted array of matches.
2134
- *
2135
- * Returns an object containing:
2136
- *
2137
- * - query {string}
2138
- * - tokens {array}
2139
- * - total {int}
2140
- * - items {array}
2141
- *
2142
- * @param {string} query
2143
- * @returns {object}
2144
- */
2145
- search: function(query) {
2146
- var i, value, score, result, calculateScore;
2147
- var self = this;
2148
- var settings = self.settings;
2149
- var options = this.getSearchOptions();
2150
-
2151
- // validate user-provided result scoring function
2152
- if (settings.score) {
2153
- calculateScore = self.settings.score.apply(this, [query]);
2154
- if (typeof calculateScore !== 'function') {
2155
- throw new Error('Selectize "score" setting must be a function that returns a function');
2156
- }
2157
- }
2158
-
2159
- // perform search
2160
- if (query !== self.lastQuery) {
2161
- self.lastQuery = query;
2162
- result = self.sifter.search(query, $.extend(options, {score: calculateScore}));
2163
- self.currentResults = result;
2164
- } else {
2165
- result = $.extend(true, {}, self.currentResults);
2166
- }
2167
-
2168
- // filter out selected items
2169
- if (settings.hideSelected) {
2170
- for (i = result.items.length - 1; i >= 0; i--) {
2171
- if (self.items.indexOf(hash_key(result.items[i].id)) !== -1) {
2172
- result.items.splice(i, 1);
2173
- }
2174
- }
2175
- }
2176
-
2177
- return result;
2178
- },
2179
-
2180
- /**
2181
- * Refreshes the list of available options shown
2182
- * in the autocomplete dropdown menu.
2183
- *
2184
- * @param {boolean} triggerDropdown
2185
- */
2186
- refreshOptions: function(triggerDropdown) {
2187
- var i, j, k, n, groups, groups_order, option, option_html, optgroup, optgroups, html, html_children, has_create_option;
2188
- var $active, $active_before, $create;
2189
-
2190
- if (typeof triggerDropdown === 'undefined') {
2191
- triggerDropdown = true;
2192
- }
2193
-
2194
- var self = this;
2195
- var query = $.trim(self.$control_input.val());
2196
- var results = self.search(query);
2197
- var $dropdown_content = self.$dropdown_content;
2198
- var active_before = self.$activeOption && hash_key(self.$activeOption.attr('data-value'));
2199
-
2200
- // build markup
2201
- n = results.items.length;
2202
- if (typeof self.settings.maxOptions === 'number') {
2203
- n = Math.min(n, self.settings.maxOptions);
2204
- }
2205
-
2206
- // render and group available options individually
2207
- groups = {};
2208
- groups_order = [];
2209
-
2210
- for (i = 0; i < n; i++) {
2211
- option = self.options[results.items[i].id];
2212
- option_html = self.render('option', option);
2213
- optgroup = option[self.settings.optgroupField] || '';
2214
- optgroups = $.isArray(optgroup) ? optgroup : [optgroup];
2215
-
2216
- for (j = 0, k = optgroups && optgroups.length; j < k; j++) {
2217
- optgroup = optgroups[j];
2218
- if (!self.optgroups.hasOwnProperty(optgroup)) {
2219
- optgroup = '';
2220
- }
2221
- if (!groups.hasOwnProperty(optgroup)) {
2222
- groups[optgroup] = document.createDocumentFragment();
2223
- groups_order.push(optgroup);
2224
- }
2225
- groups[optgroup].appendChild(option_html);
2226
- }
2227
- }
2228
-
2229
- // sort optgroups
2230
- if (this.settings.lockOptgroupOrder) {
2231
- groups_order.sort(function(a, b) {
2232
- var a_order = self.optgroups[a].$order || 0;
2233
- var b_order = self.optgroups[b].$order || 0;
2234
- return a_order - b_order;
2235
- });
2236
- }
2237
-
2238
- // render optgroup headers & join groups
2239
- html = document.createDocumentFragment();
2240
- for (i = 0, n = groups_order.length; i < n; i++) {
2241
- optgroup = groups_order[i];
2242
- if (self.optgroups.hasOwnProperty(optgroup) && groups[optgroup].childNodes.length) {
2243
- // render the optgroup header and options within it,
2244
- // then pass it to the wrapper template
2245
- html_children = document.createDocumentFragment();
2246
- html_children.appendChild(self.render('optgroup_header', self.optgroups[optgroup]));
2247
- html_children.appendChild(groups[optgroup]);
2248
-
2249
- html.appendChild(self.render('optgroup', $.extend({}, self.optgroups[optgroup], {
2250
- html: domToString(html_children),
2251
- dom: html_children
2252
- })));
2253
- } else {
2254
- html.appendChild(groups[optgroup]);
2255
- }
2256
- }
2257
-
2258
- $dropdown_content.html(html);
2259
-
2260
- // highlight matching terms inline
2261
- if (self.settings.highlight) {
2262
- $dropdown_content.removeHighlight();
2263
- if (results.query.length && results.tokens.length) {
2264
- for (i = 0, n = results.tokens.length; i < n; i++) {
2265
- highlight($dropdown_content, results.tokens[i].regex);
2266
- }
2267
- }
2268
- }
2269
-
2270
- // add "selected" class to selected options
2271
- if (!self.settings.hideSelected) {
2272
- for (i = 0, n = self.items.length; i < n; i++) {
2273
- self.getOption(self.items[i]).addClass('selected');
2274
- }
2275
- }
2276
-
2277
- // add create option
2278
- has_create_option = self.canCreate(query);
2279
- if (has_create_option) {
2280
- $dropdown_content.prepend(self.render('option_create', {input: query}));
2281
- $create = $($dropdown_content[0].childNodes[0]);
2282
- }
2283
-
2284
- // activate
2285
- self.hasOptions = results.items.length > 0 || has_create_option;
2286
- if (self.hasOptions) {
2287
- if (results.items.length > 0) {
2288
- $active_before = active_before && self.getOption(active_before);
2289
- if ($active_before && $active_before.length) {
2290
- $active = $active_before;
2291
- } else if (self.settings.mode === 'single' && self.items.length) {
2292
- $active = self.getOption(self.items[0]);
2293
- }
2294
- if (!$active || !$active.length) {
2295
- if ($create && !self.settings.addPrecedence) {
2296
- $active = self.getAdjacentOption($create, 1);
2297
- } else {
2298
- $active = $dropdown_content.find('[data-selectable]:first');
2299
- }
2300
- }
2301
- } else {
2302
- $active = $create;
2303
- }
2304
- self.setActiveOption($active);
2305
- if (triggerDropdown && !self.isOpen) { self.open(); }
2306
- } else {
2307
- self.setActiveOption(null);
2308
- if (triggerDropdown && self.isOpen) { self.close(); }
2309
- }
2310
- },
2311
-
2312
- /**
2313
- * Adds an available option. If it already exists,
2314
- * nothing will happen. Note: this does not refresh
2315
- * the options list dropdown (use `refreshOptions`
2316
- * for that).
2317
- *
2318
- * Usage:
2319
- *
2320
- * this.addOption(data)
2321
- *
2322
- * @param {object|array} data
2323
- */
2324
- addOption: function(data) {
2325
- var i, n, value, self = this;
2326
-
2327
- if ($.isArray(data)) {
2328
- for (i = 0, n = data.length; i < n; i++) {
2329
- self.addOption(data[i]);
2330
- }
2331
- return;
2332
- }
2333
-
2334
- if (value = self.registerOption(data)) {
2335
- self.userOptions[value] = true;
2336
- self.lastQuery = null;
2337
- self.trigger('option_add', value, data);
2338
- }
2339
- },
2340
-
2341
- /**
2342
- * Registers an option to the pool of options.
2343
- *
2344
- * @param {object} data
2345
- * @return {boolean|string}
2346
- */
2347
- registerOption: function(data) {
2348
- var key = hash_key(data[this.settings.valueField]);
2349
- if (typeof key === 'undefined' || key === null || this.options.hasOwnProperty(key)) return false;
2350
- data.$order = data.$order || ++this.order;
2351
- this.options[key] = data;
2352
- return key;
2353
- },
2354
-
2355
- /**
2356
- * Registers an option group to the pool of option groups.
2357
- *
2358
- * @param {object} data
2359
- * @return {boolean|string}
2360
- */
2361
- registerOptionGroup: function(data) {
2362
- var key = hash_key(data[this.settings.optgroupValueField]);
2363
- if (!key) return false;
2364
-
2365
- data.$order = data.$order || ++this.order;
2366
- this.optgroups[key] = data;
2367
- return key;
2368
- },
2369
-
2370
- /**
2371
- * Registers a new optgroup for options
2372
- * to be bucketed into.
2373
- *
2374
- * @param {string} id
2375
- * @param {object} data
2376
- */
2377
- addOptionGroup: function(id, data) {
2378
- data[this.settings.optgroupValueField] = id;
2379
- if (id = this.registerOptionGroup(data)) {
2380
- this.trigger('optgroup_add', id, data);
2381
- }
2382
- },
2383
-
2384
- /**
2385
- * Removes an existing option group.
2386
- *
2387
- * @param {string} id
2388
- */
2389
- removeOptionGroup: function(id) {
2390
- if (this.optgroups.hasOwnProperty(id)) {
2391
- delete this.optgroups[id];
2392
- this.renderCache = {};
2393
- this.trigger('optgroup_remove', id);
2394
- }
2395
- },
2396
-
2397
- /**
2398
- * Clears all existing option groups.
2399
- */
2400
- clearOptionGroups: function() {
2401
- this.optgroups = {};
2402
- this.renderCache = {};
2403
- this.trigger('optgroup_clear');
2404
- },
2405
-
2406
- /**
2407
- * Updates an option available for selection. If
2408
- * it is visible in the selected items or options
2409
- * dropdown, it will be re-rendered automatically.
2410
- *
2411
- * @param {string} value
2412
- * @param {object} data
2413
- */
2414
- updateOption: function(value, data) {
2415
- var self = this;
2416
- var $item, $item_new;
2417
- var value_new, index_item, cache_items, cache_options, order_old;
2418
-
2419
- value = hash_key(value);
2420
- value_new = hash_key(data[self.settings.valueField]);
2421
-
2422
- // sanity checks
2423
- if (value === null) return;
2424
- if (!self.options.hasOwnProperty(value)) return;
2425
- if (typeof value_new !== 'string') throw new Error('Value must be set in option data');
2426
-
2427
- order_old = self.options[value].$order;
2428
-
2429
- // update references
2430
- if (value_new !== value) {
2431
- delete self.options[value];
2432
- index_item = self.items.indexOf(value);
2433
- if (index_item !== -1) {
2434
- self.items.splice(index_item, 1, value_new);
2435
- }
2436
- }
2437
- data.$order = data.$order || order_old;
2438
- self.options[value_new] = data;
2439
-
2440
- // invalidate render cache
2441
- cache_items = self.renderCache['item'];
2442
- cache_options = self.renderCache['option'];
2443
-
2444
- if (cache_items) {
2445
- delete cache_items[value];
2446
- delete cache_items[value_new];
2447
- }
2448
- if (cache_options) {
2449
- delete cache_options[value];
2450
- delete cache_options[value_new];
2451
- }
2452
-
2453
- // update the item if it's selected
2454
- if (self.items.indexOf(value_new) !== -1) {
2455
- $item = self.getItem(value);
2456
- $item_new = $(self.render('item', data));
2457
- if ($item.hasClass('active')) $item_new.addClass('active');
2458
- $item.replaceWith($item_new);
2459
- }
2460
-
2461
- // invalidate last query because we might have updated the sortField
2462
- self.lastQuery = null;
2463
-
2464
- // update dropdown contents
2465
- if (self.isOpen) {
2466
- self.refreshOptions(false);
2467
- }
2468
- },
2469
-
2470
- /**
2471
- * Removes a single option.
2472
- *
2473
- * @param {string} value
2474
- * @param {boolean} silent
2475
- */
2476
- removeOption: function(value, silent) {
2477
- var self = this;
2478
- value = hash_key(value);
2479
-
2480
- var cache_items = self.renderCache['item'];
2481
- var cache_options = self.renderCache['option'];
2482
- if (cache_items) delete cache_items[value];
2483
- if (cache_options) delete cache_options[value];
2484
-
2485
- delete self.userOptions[value];
2486
- delete self.options[value];
2487
- self.lastQuery = null;
2488
- self.trigger('option_remove', value);
2489
- self.removeItem(value, silent);
2490
- },
2491
-
2492
- /**
2493
- * Clears all options.
2494
- */
2495
- clearOptions: function() {
2496
- var self = this;
2497
-
2498
- self.loadedSearches = {};
2499
- self.userOptions = {};
2500
- self.renderCache = {};
2501
- var options = self.options;
2502
- $.each(self.options, function(key, value) {
2503
- if(self.items.indexOf(key) == -1) {
2504
- delete options[key];
2505
- }
2506
- });
2507
- self.options = self.sifter.items = options;
2508
- self.lastQuery = null;
2509
- self.trigger('option_clear');
2510
- },
2511
-
2512
- /**
2513
- * Returns the jQuery element of the option
2514
- * matching the given value.
2515
- *
2516
- * @param {string} value
2517
- * @returns {object}
2518
- */
2519
- getOption: function(value) {
2520
- return this.getElementWithValue(value, this.$dropdown_content.find('[data-selectable]'));
2521
- },
2522
-
2523
- /**
2524
- * Returns the jQuery element of the next or
2525
- * previous selectable option.
2526
- *
2527
- * @param {object} $option
2528
- * @param {int} direction can be 1 for next or -1 for previous
2529
- * @return {object}
2530
- */
2531
- getAdjacentOption: function($option, direction) {
2532
- var $options = this.$dropdown.find('[data-selectable]');
2533
- var index = $options.index($option) + direction;
2534
-
2535
- return index >= 0 && index < $options.length ? $options.eq(index) : $();
2536
- },
2537
-
2538
- /**
2539
- * Finds the first element with a "data-value" attribute
2540
- * that matches the given value.
2541
- *
2542
- * @param {mixed} value
2543
- * @param {object} $els
2544
- * @return {object}
2545
- */
2546
- getElementWithValue: function(value, $els) {
2547
- value = hash_key(value);
2548
-
2549
- if (typeof value !== 'undefined' && value !== null) {
2550
- for (var i = 0, n = $els.length; i < n; i++) {
2551
- if ($els[i].getAttribute('data-value') === value) {
2552
- return $($els[i]);
2553
- }
2554
- }
2555
- }
2556
-
2557
- return $();
2558
- },
2559
-
2560
- /**
2561
- * Returns the jQuery element of the item
2562
- * matching the given value.
2563
- *
2564
- * @param {string} value
2565
- * @returns {object}
2566
- */
2567
- getItem: function(value) {
2568
- return this.getElementWithValue(value, this.$control.children());
2569
- },
2570
-
2571
- /**
2572
- * "Selects" multiple items at once. Adds them to the list
2573
- * at the current caret position.
2574
- *
2575
- * @param {string} value
2576
- * @param {boolean} silent
2577
- */
2578
- addItems: function(values, silent) {
2579
- this.buffer = document.createDocumentFragment();
2580
-
2581
- var childNodes = this.$control[0].childNodes;
2582
- for (var i = 0; i < childNodes.length; i++) {
2583
- this.buffer.appendChild(childNodes[i]);
2584
- }
2585
-
2586
- var items = $.isArray(values) ? values : [values];
2587
- for (var i = 0, n = items.length; i < n; i++) {
2588
- this.isPending = (i < n - 1);
2589
- this.addItem(items[i], silent);
2590
- }
2591
-
2592
- var control = this.$control[0];
2593
- control.insertBefore(this.buffer, control.firstChild);
2594
-
2595
- this.buffer = null;
2596
- },
2597
-
2598
- /**
2599
- * "Selects" an item. Adds it to the list
2600
- * at the current caret position.
2601
- *
2602
- * @param {string} value
2603
- * @param {boolean} silent
2604
- */
2605
- addItem: function(value, silent) {
2606
- var events = silent ? [] : ['change'];
2607
-
2608
- debounce_events(this, events, function() {
2609
- var $item, $option, $options;
2610
- var self = this;
2611
- var inputMode = self.settings.mode;
2612
- var i, active, value_next, wasFull;
2613
- value = hash_key(value);
2614
-
2615
- if (self.items.indexOf(value) !== -1) {
2616
- if (inputMode === 'single') self.close();
2617
- return;
2618
- }
2619
-
2620
- if (!self.options.hasOwnProperty(value)) return;
2621
- if (inputMode === 'single') self.clear(silent);
2622
- if (inputMode === 'multi' && self.isFull()) return;
2623
-
2624
- $item = $(self.render('item', self.options[value]));
2625
- wasFull = self.isFull();
2626
- self.items.splice(self.caretPos, 0, value);
2627
- self.insertAtCaret($item);
2628
- if (!self.isPending || (!wasFull && self.isFull())) {
2629
- self.refreshState();
2630
- }
2631
-
2632
- if (self.isSetup) {
2633
- $options = self.$dropdown_content.find('[data-selectable]');
2634
-
2635
- // update menu / remove the option (if this is not one item being added as part of series)
2636
- if (!self.isPending) {
2637
- $option = self.getOption(value);
2638
- value_next = self.getAdjacentOption($option, 1).attr('data-value');
2639
- self.refreshOptions(self.isFocused && inputMode !== 'single');
2640
- if (value_next) {
2641
- self.setActiveOption(self.getOption(value_next));
2642
- }
2643
- }
2644
-
2645
- // hide the menu if the maximum number of items have been selected or no options are left
2646
- if (!$options.length || self.isFull()) {
2647
- self.close();
2648
- } else if (!self.isPending) {
2649
- self.positionDropdown();
2650
- }
2651
-
2652
- self.updatePlaceholder();
2653
- self.trigger('item_add', value, $item);
2654
-
2655
- if (!self.isPending) {
2656
- self.updateOriginalInput({silent: silent});
2657
- }
2658
- }
2659
- });
2660
- },
2661
-
2662
- /**
2663
- * Removes the selected item matching
2664
- * the provided value.
2665
- *
2666
- * @param {string} value
2667
- */
2668
- removeItem: function(value, silent) {
2669
- var self = this;
2670
- var $item, i, idx;
2671
-
2672
- $item = (value instanceof $) ? value : self.getItem(value);
2673
- value = hash_key($item.attr('data-value'));
2674
- i = self.items.indexOf(value);
2675
-
2676
- if (i !== -1) {
2677
- $item.remove();
2678
- if ($item.hasClass('active')) {
2679
- idx = self.$activeItems.indexOf($item[0]);
2680
- self.$activeItems.splice(idx, 1);
2681
- }
2682
-
2683
- self.items.splice(i, 1);
2684
- self.lastQuery = null;
2685
- if (!self.settings.persist && self.userOptions.hasOwnProperty(value)) {
2686
- self.removeOption(value, silent);
2687
- }
2688
-
2689
- if (i < self.caretPos) {
2690
- self.setCaret(self.caretPos - 1);
2691
- }
2692
-
2693
- self.refreshState();
2694
- self.updatePlaceholder();
2695
- self.updateOriginalInput({silent: silent});
2696
- self.positionDropdown();
2697
- self.trigger('item_remove', value, $item);
2698
- }
2699
- },
2700
-
2701
- /**
2702
- * Invokes the `create` method provided in the
2703
- * selectize options that should provide the data
2704
- * for the new item, given the user input.
2705
- *
2706
- * Once this completes, it will be added
2707
- * to the item list.
2708
- *
2709
- * @param {string} value
2710
- * @param {boolean} [triggerDropdown]
2711
- * @param {function} [callback]
2712
- * @return {boolean}
2713
- */
2714
- createItem: function(input, triggerDropdown) {
2715
- var self = this;
2716
- var caret = self.caretPos;
2717
- input = input || $.trim(self.$control_input.val() || '');
2718
-
2719
- var callback = arguments[arguments.length - 1];
2720
- if (typeof callback !== 'function') callback = function() {};
2721
-
2722
- if (typeof triggerDropdown !== 'boolean') {
2723
- triggerDropdown = true;
2724
- }
2725
-
2726
- if (!self.canCreate(input)) {
2727
- callback();
2728
- return false;
2729
- }
2730
-
2731
- self.lock();
2732
-
2733
- var setup = (typeof self.settings.create === 'function') ? this.settings.create : function(input) {
2734
- var data = {};
2735
- data[self.settings.labelField] = input;
2736
- data[self.settings.valueField] = input;
2737
- return data;
2738
- };
2739
-
2740
- var create = once(function(data) {
2741
- self.unlock();
2742
-
2743
- if (!data || typeof data !== 'object') return callback();
2744
- var value = hash_key(data[self.settings.valueField]);
2745
- if (typeof value !== 'string') return callback();
2746
-
2747
- self.setTextboxValue('');
2748
- self.addOption(data);
2749
- self.setCaret(caret);
2750
- self.addItem(value);
2751
- self.refreshOptions(triggerDropdown && self.settings.mode !== 'single');
2752
- callback(data);
2753
- });
2754
-
2755
- var output = setup.apply(this, [input, create]);
2756
- if (typeof output !== 'undefined') {
2757
- create(output);
2758
- }
2759
-
2760
- return true;
2761
- },
2762
-
2763
- /**
2764
- * Re-renders the selected item lists.
2765
- */
2766
- refreshItems: function() {
2767
- this.lastQuery = null;
2768
-
2769
- if (this.isSetup) {
2770
- this.addItem(this.items);
2771
- }
2772
-
2773
- this.refreshState();
2774
- this.updateOriginalInput();
2775
- },
2776
-
2777
- /**
2778
- * Updates all state-dependent attributes
2779
- * and CSS classes.
2780
- */
2781
- refreshState: function() {
2782
- this.refreshValidityState();
2783
- this.refreshClasses();
2784
- },
2785
-
2786
- /**
2787
- * Update the `required` attribute of both input and control input.
2788
- *
2789
- * The `required` property needs to be activated on the control input
2790
- * for the error to be displayed at the right place. `required` also
2791
- * needs to be temporarily deactivated on the input since the input is
2792
- * hidden and can't show errors.
2793
- */
2794
- refreshValidityState: function() {
2795
- if (!this.isRequired) return false;
2796
-
2797
- var invalid = !this.items.length;
2798
-
2799
- this.isInvalid = invalid;
2800
- this.$control_input.prop('required', invalid);
2801
- this.$input.prop('required', !invalid);
2802
- },
2803
-
2804
- /**
2805
- * Updates all state-dependent CSS classes.
2806
- */
2807
- refreshClasses: function() {
2808
- var self = this;
2809
- var isFull = self.isFull();
2810
- var isLocked = self.isLocked;
2811
-
2812
- self.$wrapper
2813
- .toggleClass('rtl', self.rtl);
2814
-
2815
- self.$control
2816
- .toggleClass('focus', self.isFocused)
2817
- .toggleClass('disabled', self.isDisabled)
2818
- .toggleClass('required', self.isRequired)
2819
- .toggleClass('invalid', self.isInvalid)
2820
- .toggleClass('locked', isLocked)
2821
- .toggleClass('full', isFull).toggleClass('not-full', !isFull)
2822
- .toggleClass('input-active', self.isFocused && !self.isInputHidden)
2823
- .toggleClass('dropdown-active', self.isOpen)
2824
- .toggleClass('has-options', !$.isEmptyObject(self.options))
2825
- .toggleClass('has-items', self.items.length > 0);
2826
-
2827
- self.$control_input.data('grow', !isFull && !isLocked);
2828
- },
2829
-
2830
- /**
2831
- * Determines whether or not more items can be added
2832
- * to the control without exceeding the user-defined maximum.
2833
- *
2834
- * @returns {boolean}
2835
- */
2836
- isFull: function() {
2837
- return this.settings.maxItems !== null && this.items.length >= this.settings.maxItems;
2838
- },
2839
-
2840
- /**
2841
- * Refreshes the original <select> or <input>
2842
- * element to reflect the current state.
2843
- */
2844
- updateOriginalInput: function(opts) {
2845
- var i, n, options, label, self = this;
2846
- opts = opts || {};
2847
-
2848
- if (self.tagType === TAG_SELECT) {
2849
- options = [];
2850
- for (i = 0, n = self.items.length; i < n; i++) {
2851
- label = self.options[self.items[i]][self.settings.labelField] || '';
2852
- options.push('<option value="' + escape_html(self.items[i]) + '" selected="selected">' + escape_html(label) + '</option>');
2853
- }
2854
- if (!options.length && !this.$input.attr('multiple')) {
2855
- options.push('<option value="" selected="selected"></option>');
2856
- }
2857
- self.$input.html(options.join(''));
2858
- } else {
2859
- self.$input.val(self.getValue());
2860
- self.$input.attr('value',self.$input.val());
2861
- }
2862
-
2863
- if (self.isSetup) {
2864
- if (!opts.silent) {
2865
- self.trigger('change', self.$input.val());
2866
- }
2867
- }
2868
- },
2869
-
2870
- /**
2871
- * Shows/hide the input placeholder depending
2872
- * on if there items in the list already.
2873
- */
2874
- updatePlaceholder: function() {
2875
- if (!this.settings.placeholder) return;
2876
- var $input = this.$control_input;
2877
-
2878
- if (this.items.length) {
2879
- $input.removeAttr('placeholder');
2880
- } else {
2881
- $input.attr('placeholder', this.settings.placeholder);
2882
- }
2883
- $input.triggerHandler('update', {force: true});
2884
- },
2885
-
2886
- /**
2887
- * Shows the autocomplete dropdown containing
2888
- * the available options.
2889
- */
2890
- open: function() {
2891
- var self = this;
2892
-
2893
- if (self.isLocked || self.isOpen || (self.settings.mode === 'multi' && self.isFull())) return;
2894
- self.focus();
2895
- self.isOpen = true;
2896
- self.refreshState();
2897
- self.$dropdown.css({visibility: 'hidden', display: 'block'});
2898
- self.positionDropdown();
2899
- self.$dropdown.css({visibility: 'visible'});
2900
- self.trigger('dropdown_open', self.$dropdown);
2901
- },
2902
-
2903
- /**
2904
- * Closes the autocomplete dropdown menu.
2905
- */
2906
- close: function() {
2907
- var self = this;
2908
- var trigger = self.isOpen;
2909
-
2910
- if (self.settings.mode === 'single' && self.items.length) {
2911
- self.hideInput();
2912
-
2913
- // Do not trigger blur while inside a blur event,
2914
- // this fixes some weird tabbing behavior in FF and IE.
2915
- // See #1164
2916
- if (!self.isBlurring) {
2917
- self.$control_input.blur(); // close keyboard on iOS
2918
- }
2919
- }
2920
-
2921
- self.isOpen = false;
2922
- self.$dropdown.hide();
2923
- self.setActiveOption(null);
2924
- self.refreshState();
2925
-
2926
- if (trigger) self.trigger('dropdown_close', self.$dropdown);
2927
- },
2928
-
2929
- /**
2930
- * Calculates and applies the appropriate
2931
- * position of the dropdown.
2932
- */
2933
- positionDropdown: function() {
2934
- var $control = this.$control;
2935
- var offset = this.settings.dropdownParent === 'body' ? $control.offset() : $control.position();
2936
- offset.top += $control.outerHeight(true);
2937
-
2938
- this.$dropdown.css({
2939
- width : $control[0].getBoundingClientRect().width,
2940
- top : offset.top,
2941
- left : offset.left
2942
- });
2943
- },
2944
-
2945
- /**
2946
- * Resets / clears all selected items
2947
- * from the control.
2948
- *
2949
- * @param {boolean} silent
2950
- */
2951
- clear: function(silent) {
2952
- var self = this;
2953
-
2954
- if (!self.items.length) return;
2955
- self.$control.children(':not(input)').remove();
2956
- self.items = [];
2957
- self.lastQuery = null;
2958
- self.setCaret(0);
2959
- self.setActiveItem(null);
2960
- self.updatePlaceholder();
2961
- self.updateOriginalInput({silent: silent});
2962
- self.refreshState();
2963
- self.showInput();
2964
- self.trigger('clear');
2965
- },
2966
-
2967
- /**
2968
- * A helper method for inserting an element
2969
- * at the current caret position.
2970
- *
2971
- * @param {object} $el
2972
- */
2973
- insertAtCaret: function($el) {
2974
- var caret = Math.min(this.caretPos, this.items.length);
2975
- var el = $el[0];
2976
- var target = this.buffer || this.$control[0];
2977
-
2978
- if (caret === 0) {
2979
- target.insertBefore(el, target.firstChild);
2980
- } else {
2981
- target.insertBefore(el, target.childNodes[caret]);
2982
- }
2983
-
2984
- this.setCaret(caret + 1);
2985
- },
2986
-
2987
- /**
2988
- * Removes the current selected item(s).
2989
- *
2990
- * @param {object} e (optional)
2991
- * @returns {boolean}
2992
- */
2993
- deleteSelection: function(e) {
2994
- var i, n, direction, selection, values, caret, option_select, $option_select, $tail;
2995
- var self = this;
2996
-
2997
- direction = (e && e.keyCode === KEY_BACKSPACE) ? -1 : 1;
2998
- selection = getSelection(self.$control_input[0]);
2999
-
3000
- if (self.$activeOption && !self.settings.hideSelected) {
3001
- option_select = self.getAdjacentOption(self.$activeOption, -1).attr('data-value');
3002
- }
3003
-
3004
- // determine items that will be removed
3005
- values = [];
3006
-
3007
- if (self.$activeItems.length) {
3008
- $tail = self.$control.children('.active:' + (direction > 0 ? 'last' : 'first'));
3009
- caret = self.$control.children(':not(input)').index($tail);
3010
- if (direction > 0) { caret++; }
3011
-
3012
- for (i = 0, n = self.$activeItems.length; i < n; i++) {
3013
- values.push($(self.$activeItems[i]).attr('data-value'));
3014
- }
3015
- if (e) {
3016
- e.preventDefault();
3017
- e.stopPropagation();
3018
- }
3019
- } else if ((self.isFocused || self.settings.mode === 'single') && self.items.length) {
3020
- if (direction < 0 && selection.start === 0 && selection.length === 0) {
3021
- values.push(self.items[self.caretPos - 1]);
3022
- } else if (direction > 0 && selection.start === self.$control_input.val().length) {
3023
- values.push(self.items[self.caretPos]);
3024
- }
3025
- }
3026
-
3027
- // allow the callback to abort
3028
- if (!values.length || (typeof self.settings.onDelete === 'function' && self.settings.onDelete.apply(self, [values]) === false)) {
3029
- return false;
3030
- }
3031
-
3032
- // perform removal
3033
- if (typeof caret !== 'undefined') {
3034
- self.setCaret(caret);
3035
- }
3036
- while (values.length) {
3037
- self.removeItem(values.pop());
3038
- }
3039
-
3040
- self.showInput();
3041
- self.positionDropdown();
3042
- self.refreshOptions(true);
3043
-
3044
- // select previous option
3045
- if (option_select) {
3046
- $option_select = self.getOption(option_select);
3047
- if ($option_select.length) {
3048
- self.setActiveOption($option_select);
3049
- }
3050
- }
3051
-
3052
- return true;
3053
- },
3054
-
3055
- /**
3056
- * Selects the previous / next item (depending
3057
- * on the `direction` argument).
3058
- *
3059
- * > 0 - right
3060
- * < 0 - left
3061
- *
3062
- * @param {int} direction
3063
- * @param {object} e (optional)
3064
- */
3065
- advanceSelection: function(direction, e) {
3066
- var tail, selection, idx, valueLength, cursorAtEdge, $tail;
3067
- var self = this;
3068
-
3069
- if (direction === 0) return;
3070
- if (self.rtl) direction *= -1;
3071
-
3072
- tail = direction > 0 ? 'last' : 'first';
3073
- selection = getSelection(self.$control_input[0]);
3074
-
3075
- if (self.isFocused && !self.isInputHidden) {
3076
- valueLength = self.$control_input.val().length;
3077
- cursorAtEdge = direction < 0
3078
- ? selection.start === 0 && selection.length === 0
3079
- : selection.start === valueLength;
3080
-
3081
- if (cursorAtEdge && !valueLength) {
3082
- self.advanceCaret(direction, e);
3083
- }
3084
- } else {
3085
- $tail = self.$control.children('.active:' + tail);
3086
- if ($tail.length) {
3087
- idx = self.$control.children(':not(input)').index($tail);
3088
- self.setActiveItem(null);
3089
- self.setCaret(direction > 0 ? idx + 1 : idx);
3090
- }
3091
- }
3092
- },
3093
-
3094
- /**
3095
- * Moves the caret left / right.
3096
- *
3097
- * @param {int} direction
3098
- * @param {object} e (optional)
3099
- */
3100
- advanceCaret: function(direction, e) {
3101
- var self = this, fn, $adj;
3102
-
3103
- if (direction === 0) return;
3104
-
3105
- fn = direction > 0 ? 'next' : 'prev';
3106
- if (self.isShiftDown) {
3107
- $adj = self.$control_input[fn]();
3108
- if ($adj.length) {
3109
- self.hideInput();
3110
- self.setActiveItem($adj);
3111
- e && e.preventDefault();
3112
- }
3113
- } else {
3114
- self.setCaret(self.caretPos + direction);
3115
- }
3116
- },
3117
-
3118
- /**
3119
- * Moves the caret to the specified index.
3120
- *
3121
- * @param {int} i
3122
- */
3123
- setCaret: function(i) {
3124
- var self = this;
3125
-
3126
- if (self.settings.mode === 'single') {
3127
- i = self.items.length;
3128
- } else {
3129
- i = Math.max(0, Math.min(self.items.length, i));
3130
- }
3131
-
3132
- if(!self.isPending) {
3133
- // the input must be moved by leaving it in place and moving the
3134
- // siblings, due to the fact that focus cannot be restored once lost
3135
- // on mobile webkit devices
3136
- var j, n, fn, $children, $child;
3137
- $children = self.$control.children(':not(input)');
3138
- for (j = 0, n = $children.length; j < n; j++) {
3139
- $child = $($children[j]).detach();
3140
- if (j < i) {
3141
- self.$control_input.before($child);
3142
- } else {
3143
- self.$control.append($child);
3144
- }
3145
- }
3146
- }
3147
-
3148
- self.caretPos = i;
3149
- },
3150
-
3151
- /**
3152
- * Disables user input on the control. Used while
3153
- * items are being asynchronously created.
3154
- */
3155
- lock: function() {
3156
- this.close();
3157
- this.isLocked = true;
3158
- this.refreshState();
3159
- },
3160
-
3161
- /**
3162
- * Re-enables user input on the control.
3163
- */
3164
- unlock: function() {
3165
- this.isLocked = false;
3166
- this.refreshState();
3167
- },
3168
-
3169
- /**
3170
- * Disables user input on the control completely.
3171
- * While disabled, it cannot receive focus.
3172
- */
3173
- disable: function() {
3174
- var self = this;
3175
- self.$input.prop('disabled', true);
3176
- self.$control_input.prop('disabled', true).prop('tabindex', -1);
3177
- self.isDisabled = true;
3178
- self.lock();
3179
- },
3180
-
3181
- /**
3182
- * Enables the control so that it can respond
3183
- * to focus and user input.
3184
- */
3185
- enable: function() {
3186
- var self = this;
3187
- self.$input.prop('disabled', false);
3188
- self.$control_input.prop('disabled', false).prop('tabindex', self.tabIndex);
3189
- self.isDisabled = false;
3190
- self.unlock();
3191
- },
3192
-
3193
- /**
3194
- * Completely destroys the control and
3195
- * unbinds all event listeners so that it can
3196
- * be garbage collected.
3197
- */
3198
- destroy: function() {
3199
- var self = this;
3200
- var eventNS = self.eventNS;
3201
- var revertSettings = self.revertSettings;
3202
-
3203
- self.trigger('destroy');
3204
- self.off();
3205
- self.$wrapper.remove();
3206
- self.$dropdown.remove();
3207
-
3208
- self.$input
3209
- .html('')
3210
- .append(revertSettings.$children)
3211
- .removeAttr('tabindex')
3212
- .removeClass('selectized')
3213
- .attr({tabindex: revertSettings.tabindex})
3214
- .show();
3215
-
3216
- self.$control_input.removeData('grow');
3217
- self.$input.removeData('selectize');
3218
-
3219
- if (--Selectize.count == 0 && Selectize.$testInput) {
3220
- Selectize.$testInput.remove();
3221
- Selectize.$testInput = undefined;
3222
- }
3223
-
3224
- $(window).off(eventNS);
3225
- $(document).off(eventNS);
3226
- $(document.body).off(eventNS);
3227
-
3228
- delete self.$input[0].selectize;
3229
- },
3230
-
3231
- /**
3232
- * A helper method for rendering "item" and
3233
- * "option" templates, given the data.
3234
- *
3235
- * @param {string} templateName
3236
- * @param {object} data
3237
- * @returns {string}
3238
- */
3239
- render: function(templateName, data) {
3240
- var value, id, label;
3241
- var html = '';
3242
- var cache = false;
3243
- var self = this;
3244
- var regex_tag = /^[\t \r\n]*<([a-z][a-z0-9\-_]*(?:\:[a-z][a-z0-9\-_]*)?)/i;
3245
-
3246
- if (templateName === 'option' || templateName === 'item') {
3247
- value = hash_key(data[self.settings.valueField]);
3248
- cache = !!value;
3249
- }
3250
-
3251
- // pull markup from cache if it exists
3252
- if (cache) {
3253
- if (!isset(self.renderCache[templateName])) {
3254
- self.renderCache[templateName] = {};
3255
- }
3256
- if (self.renderCache[templateName].hasOwnProperty(value)) {
3257
- return self.renderCache[templateName][value];
3258
- }
3259
- }
3260
-
3261
- // render markup
3262
- html = $(self.settings.render[templateName].apply(this, [data, escape_html]));
3263
-
3264
- // add mandatory attributes
3265
- if (templateName === 'option' || templateName === 'option_create') {
3266
- if (!data[self.settings.disabledField]) {
3267
- html.attr('data-selectable', '');
3268
- }
3269
- }
3270
- else if (templateName === 'optgroup') {
3271
- id = data[self.settings.optgroupValueField] || '';
3272
- html.attr('data-group', id);
3273
- if(data[self.settings.disabledField]) {
3274
- html.attr('data-disabled', '');
3275
- }
3276
- }
3277
- if (templateName === 'option' || templateName === 'item') {
3278
- html.attr('data-value', value || '');
3279
- }
3280
-
3281
- // update cache
3282
- if (cache) {
3283
- self.renderCache[templateName][value] = html[0];
3284
- }
3285
-
3286
- return html[0];
3287
- },
3288
-
3289
- /**
3290
- * Clears the render cache for a template. If
3291
- * no template is given, clears all render
3292
- * caches.
3293
- *
3294
- * @param {string} templateName
3295
- */
3296
- clearCache: function(templateName) {
3297
- var self = this;
3298
- if (typeof templateName === 'undefined') {
3299
- self.renderCache = {};
3300
- } else {
3301
- delete self.renderCache[templateName];
3302
- }
3303
- },
3304
-
3305
- /**
3306
- * Determines whether or not to display the
3307
- * create item prompt, given a user input.
3308
- *
3309
- * @param {string} input
3310
- * @return {boolean}
3311
- */
3312
- canCreate: function(input) {
3313
- var self = this;
3314
- if (!self.settings.create) return false;
3315
- var filter = self.settings.createFilter;
3316
- return input.length
3317
- && (typeof filter !== 'function' || filter.apply(self, [input]))
3318
- && (typeof filter !== 'string' || new RegExp(filter).test(input))
3319
- && (!(filter instanceof RegExp) || filter.test(input));
3320
- }
3321
-
3322
- });
3323
-
3324
-
3325
- Selectize.count = 0;
3326
- Selectize.defaults = {
3327
- options: [],
3328
- optgroups: [],
3329
-
3330
- plugins: [],
3331
- delimiter: ',',
3332
- splitOn: null, // regexp or string for splitting up values from a paste command
3333
- persist: true,
3334
- diacritics: true,
3335
- create: false,
3336
- createOnBlur: false,
3337
- createFilter: null,
3338
- highlight: true,
3339
- openOnFocus: true,
3340
- maxOptions: 1000,
3341
- maxItems: null,
3342
- hideSelected: null,
3343
- addPrecedence: false,
3344
- selectOnTab: false,
3345
- preload: false,
3346
- allowEmptyOption: false,
3347
- closeAfterSelect: false,
3348
-
3349
- scrollDuration: 60,
3350
- loadThrottle: 300,
3351
- loadingClass: 'loading',
3352
-
3353
- dataAttr: 'data-data',
3354
- optgroupField: 'optgroup',
3355
- valueField: 'value',
3356
- labelField: 'text',
3357
- disabledField: 'disabled',
3358
- optgroupLabelField: 'label',
3359
- optgroupValueField: 'value',
3360
- lockOptgroupOrder: false,
3361
-
3362
- sortField: '$order',
3363
- searchField: ['text'],
3364
- searchConjunction: 'and',
3365
-
3366
- mode: null,
3367
- wrapperClass: 'selectize-control',
3368
- inputClass: 'selectize-input',
3369
- dropdownClass: 'selectize-dropdown',
3370
- dropdownContentClass: 'selectize-dropdown-content',
3371
-
3372
- dropdownParent: null,
3373
-
3374
- copyClassesToDropdown: true,
3375
-
3376
- /*
3377
- load : null, // function(query, callback) { ... }
3378
- score : null, // function(search) { ... }
3379
- onInitialize : null, // function() { ... }
3380
- onChange : null, // function(value) { ... }
3381
- onItemAdd : null, // function(value, $item) { ... }
3382
- onItemRemove : null, // function(value) { ... }
3383
- onClear : null, // function() { ... }
3384
- onOptionAdd : null, // function(value, data) { ... }
3385
- onOptionRemove : null, // function(value) { ... }
3386
- onOptionClear : null, // function() { ... }
3387
- onOptionGroupAdd : null, // function(id, data) { ... }
3388
- onOptionGroupRemove : null, // function(id) { ... }
3389
- onOptionGroupClear : null, // function() { ... }
3390
- onDropdownOpen : null, // function($dropdown) { ... }
3391
- onDropdownClose : null, // function($dropdown) { ... }
3392
- onType : null, // function(str) { ... }
3393
- onDelete : null, // function(values) { ... }
3394
- */
3395
-
3396
- render: {
3397
- /*
3398
- item: null,
3399
- optgroup: null,
3400
- optgroup_header: null,
3401
- option: null,
3402
- option_create: null
3403
- */
3404
- }
3405
- };
3406
-
3407
-
3408
- $.fn.selectize = function(settings_user) {
3409
- var defaults = $.fn.selectize.defaults;
3410
- var settings = $.extend({}, defaults, settings_user);
3411
- var attr_data = settings.dataAttr;
3412
- var field_label = settings.labelField;
3413
- var field_value = settings.valueField;
3414
- var field_disabled = settings.disabledField;
3415
- var field_optgroup = settings.optgroupField;
3416
- var field_optgroup_label = settings.optgroupLabelField;
3417
- var field_optgroup_value = settings.optgroupValueField;
3418
-
3419
- /**
3420
- * Initializes selectize from a <input type="text"> element.
3421
- *
3422
- * @param {object} $input
3423
- * @param {object} settings_element
3424
- */
3425
- var init_textbox = function($input, settings_element) {
3426
- var i, n, values, option;
3427
-
3428
- var data_raw = $input.attr(attr_data);
3429
-
3430
- if (!data_raw) {
3431
- var value = $.trim($input.val() || '');
3432
- if (!settings.allowEmptyOption && !value.length) return;
3433
- values = value.split(settings.delimiter);
3434
- for (i = 0, n = values.length; i < n; i++) {
3435
- option = {};
3436
- option[field_label] = values[i];
3437
- option[field_value] = values[i];
3438
- settings_element.options.push(option);
3439
- }
3440
- settings_element.items = values;
3441
- } else {
3442
- settings_element.options = JSON.parse(data_raw);
3443
- for (i = 0, n = settings_element.options.length; i < n; i++) {
3444
- settings_element.items.push(settings_element.options[i][field_value]);
3445
- }
3446
- }
3447
- };
3448
-
3449
- /**
3450
- * Initializes selectize from a <select> element.
3451
- *
3452
- * @param {object} $input
3453
- * @param {object} settings_element
3454
- */
3455
- var init_select = function($input, settings_element) {
3456
- var i, n, tagName, $children, order = 0;
3457
- var options = settings_element.options;
3458
- var optionsMap = {};
3459
-
3460
- var readData = function($el) {
3461
- var data = attr_data && $el.attr(attr_data);
3462
- if (typeof data === 'string' && data.length) {
3463
- return JSON.parse(data);
3464
- }
3465
- return null;
3466
- };
3467
-
3468
- var addOption = function($option, group) {
3469
- $option = $($option);
3470
-
3471
- var value = hash_key($option.val());
3472
- if (!value && !settings.allowEmptyOption) return;
3473
-
3474
- // if the option already exists, it's probably been
3475
- // duplicated in another optgroup. in this case, push
3476
- // the current group to the "optgroup" property on the
3477
- // existing option so that it's rendered in both places.
3478
- if (optionsMap.hasOwnProperty(value)) {
3479
- if (group) {
3480
- var arr = optionsMap[value][field_optgroup];
3481
- if (!arr) {
3482
- optionsMap[value][field_optgroup] = group;
3483
- } else if (!$.isArray(arr)) {
3484
- optionsMap[value][field_optgroup] = [arr, group];
3485
- } else {
3486
- arr.push(group);
3487
- }
3488
- }
3489
- return;
3490
- }
3491
-
3492
- var option = readData($option) || {};
3493
- option[field_label] = option[field_label] || $option.text();
3494
- option[field_value] = option[field_value] || value;
3495
- option[field_disabled] = option[field_disabled] || $option.prop('disabled');
3496
- option[field_optgroup] = option[field_optgroup] || group;
3497
-
3498
- optionsMap[value] = option;
3499
- options.push(option);
3500
-
3501
- if ($option.is(':selected')) {
3502
- settings_element.items.push(value);
3503
- }
3504
- };
3505
-
3506
- var addGroup = function($optgroup) {
3507
- var i, n, id, optgroup, $options;
3508
-
3509
- $optgroup = $($optgroup);
3510
- id = $optgroup.attr('label');
3511
-
3512
- if (id) {
3513
- optgroup = readData($optgroup) || {};
3514
- optgroup[field_optgroup_label] = id;
3515
- optgroup[field_optgroup_value] = id;
3516
- optgroup[field_disabled] = $optgroup.prop('disabled');
3517
- settings_element.optgroups.push(optgroup);
3518
- }
3519
-
3520
- $options = $('option', $optgroup);
3521
- for (i = 0, n = $options.length; i < n; i++) {
3522
- addOption($options[i], id);
3523
- }
3524
- };
3525
-
3526
- settings_element.maxItems = $input.attr('multiple') ? null : 1;
3527
-
3528
- $children = $input.children();
3529
- for (i = 0, n = $children.length; i < n; i++) {
3530
- tagName = $children[i].tagName.toLowerCase();
3531
- if (tagName === 'optgroup') {
3532
- addGroup($children[i]);
3533
- } else if (tagName === 'option') {
3534
- addOption($children[i]);
3535
- }
3536
- }
3537
- };
3538
-
3539
- return this.each(function() {
3540
- if (this.selectize) return;
3541
-
3542
- var instance;
3543
- var $input = $(this);
3544
- var tag_name = this.tagName.toLowerCase();
3545
- var placeholder = $input.attr('placeholder') || $input.attr('data-placeholder');
3546
- if (!placeholder && !settings.allowEmptyOption) {
3547
- placeholder = $input.children('option[value=""]').text();
3548
- }
3549
-
3550
- var settings_element = {
3551
- 'placeholder' : placeholder,
3552
- 'options' : [],
3553
- 'optgroups' : [],
3554
- 'items' : []
3555
- };
3556
-
3557
- if (tag_name === 'select') {
3558
- init_select($input, settings_element);
3559
- } else {
3560
- init_textbox($input, settings_element);
3561
- }
3562
-
3563
- instance = new Selectize($input, $.extend(true, {}, defaults, settings_element, settings_user));
3564
- });
3565
- };
3566
-
3567
- $.fn.selectize.defaults = Selectize.defaults;
3568
- $.fn.selectize.support = {
3569
- validity: SUPPORTS_VALIDITY_API
3570
- };
3571
-
3572
-
3573
- Selectize.define('drag_drop', function(options) {
3574
- if (!$.fn.sortable) throw new Error('The "drag_drop" plugin requires jQuery UI "sortable".');
3575
- if (this.settings.mode !== 'multi') return;
3576
- var self = this;
3577
-
3578
- self.lock = (function() {
3579
- var original = self.lock;
3580
- return function() {
3581
- var sortable = self.$control.data('sortable');
3582
- if (sortable) sortable.disable();
3583
- return original.apply(self, arguments);
3584
- };
3585
- })();
3586
-
3587
- self.unlock = (function() {
3588
- var original = self.unlock;
3589
- return function() {
3590
- var sortable = self.$control.data('sortable');
3591
- if (sortable) sortable.enable();
3592
- return original.apply(self, arguments);
3593
- };
3594
- })();
3595
-
3596
- self.setup = (function() {
3597
- var original = self.setup;
3598
- return function() {
3599
- original.apply(this, arguments);
3600
-
3601
- var $control = self.$control.sortable({
3602
- items: '[data-value]',
3603
- forcePlaceholderSize: true,
3604
- disabled: self.isLocked,
3605
- start: function(e, ui) {
3606
- ui.placeholder.css('width', ui.helper.css('width'));
3607
- $control.css({overflow: 'visible'});
3608
- },
3609
- stop: function() {
3610
- $control.css({overflow: 'hidden'});
3611
- var active = self.$activeItems ? self.$activeItems.slice() : null;
3612
- var values = [];
3613
- $control.children('[data-value]').each(function() {
3614
- values.push($(this).attr('data-value'));
3615
- });
3616
- self.setValue(values);
3617
- self.setActiveItem(active);
3618
- }
3619
- });
3620
- };
3621
- })();
3622
-
3623
- });
3624
-
3625
- Selectize.define('dropdown_header', function(options) {
3626
- var self = this;
3627
-
3628
- options = $.extend({
3629
- title : 'Untitled',
3630
- headerClass : 'selectize-dropdown-header',
3631
- titleRowClass : 'selectize-dropdown-header-title',
3632
- labelClass : 'selectize-dropdown-header-label',
3633
- closeClass : 'selectize-dropdown-header-close',
3634
-
3635
- html: function(data) {
3636
- return (
3637
- '<div class="' + data.headerClass + '">' +
3638
- '<div class="' + data.titleRowClass + '">' +
3639
- '<span class="' + data.labelClass + '">' + data.title + '</span>' +
3640
- '<a href="javascript:void(0)" class="' + data.closeClass + '">&times;</a>' +
3641
- '</div>' +
3642
- '</div>'
3643
- );
3644
- }
3645
- }, options);
3646
-
3647
- self.setup = (function() {
3648
- var original = self.setup;
3649
- return function() {
3650
- original.apply(self, arguments);
3651
- self.$dropdown_header = $(options.html(options));
3652
- self.$dropdown.prepend(self.$dropdown_header);
3653
- };
3654
- })();
3655
-
3656
- });
3657
-
3658
- Selectize.define('optgroup_columns', function(options) {
3659
- var self = this;
3660
-
3661
- options = $.extend({
3662
- equalizeWidth : true,
3663
- equalizeHeight : true
3664
- }, options);
3665
-
3666
- this.getAdjacentOption = function($option, direction) {
3667
- var $options = $option.closest('[data-group]').find('[data-selectable]');
3668
- var index = $options.index($option) + direction;
3669
-
3670
- return index >= 0 && index < $options.length ? $options.eq(index) : $();
3671
- };
3672
-
3673
- this.onKeyDown = (function() {
3674
- var original = self.onKeyDown;
3675
- return function(e) {
3676
- var index, $option, $options, $optgroup;
3677
-
3678
- if (this.isOpen && (e.keyCode === KEY_LEFT || e.keyCode === KEY_RIGHT)) {
3679
- self.ignoreHover = true;
3680
- $optgroup = this.$activeOption.closest('[data-group]');
3681
- index = $optgroup.find('[data-selectable]').index(this.$activeOption);
3682
-
3683
- if(e.keyCode === KEY_LEFT) {
3684
- $optgroup = $optgroup.prev('[data-group]');
3685
- } else {
3686
- $optgroup = $optgroup.next('[data-group]');
3687
- }
3688
-
3689
- $options = $optgroup.find('[data-selectable]');
3690
- $option = $options.eq(Math.min($options.length - 1, index));
3691
- if ($option.length) {
3692
- this.setActiveOption($option);
3693
- }
3694
- return;
3695
- }
3696
-
3697
- return original.apply(this, arguments);
3698
- };
3699
- })();
3700
-
3701
- var getScrollbarWidth = function() {
3702
- var div;
3703
- var width = getScrollbarWidth.width;
3704
- var doc = document;
3705
-
3706
- if (typeof width === 'undefined') {
3707
- div = doc.createElement('div');
3708
- div.innerHTML = '<div style="width:50px;height:50px;position:absolute;left:-50px;top:-50px;overflow:auto;"><div style="width:1px;height:100px;"></div></div>';
3709
- div = div.firstChild;
3710
- doc.body.appendChild(div);
3711
- width = getScrollbarWidth.width = div.offsetWidth - div.clientWidth;
3712
- doc.body.removeChild(div);
3713
- }
3714
- return width;
3715
- };
3716
-
3717
- var equalizeSizes = function() {
3718
- var i, n, height_max, width, width_last, width_parent, $optgroups;
3719
-
3720
- $optgroups = $('[data-group]', self.$dropdown_content);
3721
- n = $optgroups.length;
3722
- if (!n || !self.$dropdown_content.width()) return;
3723
-
3724
- if (options.equalizeHeight) {
3725
- height_max = 0;
3726
- for (i = 0; i < n; i++) {
3727
- height_max = Math.max(height_max, $optgroups.eq(i).height());
3728
- }
3729
- $optgroups.css({height: height_max});
3730
- }
3731
-
3732
- if (options.equalizeWidth) {
3733
- width_parent = self.$dropdown_content.innerWidth() - getScrollbarWidth();
3734
- width = Math.round(width_parent / n);
3735
- $optgroups.css({width: width});
3736
- if (n > 1) {
3737
- width_last = width_parent - width * (n - 1);
3738
- $optgroups.eq(n - 1).css({width: width_last});
3739
- }
3740
- }
3741
- };
3742
-
3743
- if (options.equalizeHeight || options.equalizeWidth) {
3744
- hook.after(this, 'positionDropdown', equalizeSizes);
3745
- hook.after(this, 'refreshOptions', equalizeSizes);
3746
- }
3747
-
3748
-
3749
- });
3750
-
3751
- Selectize.define('remove_button', function(options) {
3752
- options = $.extend({
3753
- label : '&times;',
3754
- title : 'Remove',
3755
- className : 'remove',
3756
- append : true
3757
- }, options);
3758
-
3759
- var singleClose = function(thisRef, options) {
3760
-
3761
- options.className = 'remove-single';
3762
-
3763
- var self = thisRef;
3764
- var html = '<a href="javascript:void(0)" class="' + options.className + '" tabindex="-1" title="' + escape_html(options.title) + '">' + options.label + '</a>';
3765
-
3766
- /**
3767
- * Appends an element as a child (with raw HTML).
3768
- *
3769
- * @param {string} html_container
3770
- * @param {string} html_element
3771
- * @return {string}
3772
- */
3773
- var append = function(html_container, html_element) {
3774
- return $('<span>').append(html_container)
3775
- .append(html_element);
3776
- };
3777
-
3778
- thisRef.setup = (function() {
3779
- var original = self.setup;
3780
- return function() {
3781
- // override the item rendering method to add the button to each
3782
- if (options.append) {
3783
- var id = $(self.$input.context).attr('id');
3784
- var selectizer = $('#'+id);
3785
-
3786
- var render_item = self.settings.render.item;
3787
- self.settings.render.item = function(data) {
3788
- return append(render_item.apply(thisRef, arguments), html);
3789
- };
3790
- }
3791
-
3792
- original.apply(thisRef, arguments);
3793
-
3794
- // add event listener
3795
- thisRef.$control.on('click', '.' + options.className, function(e) {
3796
- e.preventDefault();
3797
- if (self.isLocked) return;
3798
-
3799
- self.clear();
3800
- });
3801
-
3802
- };
3803
- })();
3804
- };
3805
-
3806
- var multiClose = function(thisRef, options) {
3807
-
3808
- var self = thisRef;
3809
- var html = '<a href="javascript:void(0)" class="' + options.className + '" tabindex="-1" title="' + escape_html(options.title) + '">' + options.label + '</a>';
3810
-
3811
- /**
3812
- * Appends an element as a child (with raw HTML).
3813
- *
3814
- * @param {string} html_container
3815
- * @param {string} html_element
3816
- * @return {string}
3817
- */
3818
- var append = function(html_container, html_element) {
3819
- var pos = html_container.search(/(<\/[^>]+>\s*)$/);
3820
- return html_container.substring(0, pos) + html_element + html_container.substring(pos);
3821
- };
3822
-
3823
- thisRef.setup = (function() {
3824
- var original = self.setup;
3825
- return function() {
3826
- // override the item rendering method to add the button to each
3827
- if (options.append) {
3828
- var render_item = self.settings.render.item;
3829
- self.settings.render.item = function(data) {
3830
- return append(render_item.apply(thisRef, arguments), html);
3831
- };
3832
- }
3833
-
3834
- original.apply(thisRef, arguments);
3835
-
3836
- // add event listener
3837
- thisRef.$control.on('click', '.' + options.className, function(e) {
3838
- e.preventDefault();
3839
- if (self.isLocked) return;
3840
-
3841
- var $item = $(e.currentTarget).parent();
3842
- self.setActiveItem($item);
3843
- if (self.deleteSelection()) {
3844
- self.setCaret(self.items.length);
3845
- }
3846
- });
3847
-
3848
- };
3849
- })();
3850
- };
3851
-
3852
- if (this.settings.mode === 'single') {
3853
- singleClose(this, options);
3854
- return;
3855
- } else {
3856
- multiClose(this, options);
3857
- }
3858
- });
3859
-
3860
-
3861
- Selectize.define('restore_on_backspace', function(options) {
3862
- var self = this;
3863
-
3864
- options.text = options.text || function(option) {
3865
- return option[this.settings.labelField];
3866
- };
3867
-
3868
- this.onKeyDown = (function() {
3869
- var original = self.onKeyDown;
3870
- return function(e) {
3871
- var index, option;
3872
- if (e.keyCode === KEY_BACKSPACE && this.$control_input.val() === '' && !this.$activeItems.length) {
3873
- index = this.caretPos - 1;
3874
- if (index >= 0 && index < this.items.length) {
3875
- option = this.options[this.items[index]];
3876
- if (this.deleteSelection(e)) {
3877
- this.setTextboxValue(options.text.apply(this, [option]));
3878
- this.refreshOptions(true);
3879
- }
3880
- e.preventDefault();
3881
- return;
3882
- }
3883
- }
3884
- return original.apply(this, arguments);
3885
- };
3886
- })();
3887
- });
3888
-
3889
-
3890
- return Selectize;
3891
- }));
3
+ !function(root,factory){"function"==typeof define&&define.amd?define("sifter",factory):"object"==typeof exports?module.exports=factory():root.Sifter=factory()}(this,function(){function Sifter(items,settings){this.items=items,this.settings=settings||{diacritics:!0}}Sifter.prototype.tokenize=function(query){if(!(query=trim(String(query||"").toLowerCase()))||!query.length)return[];for(var regex,letter,tokens=[],words=query.split(/ +/),i=0,n=words.length;i<n;i++){if(regex=escape_regex(words[i]),this.settings.diacritics)for(letter in DIACRITICS)DIACRITICS.hasOwnProperty(letter)&&(regex=regex.replace(new RegExp(letter,"g"),DIACRITICS[letter]));tokens.push({string:words[i],regex:new RegExp(regex,"i")})}return tokens},Sifter.prototype.iterator=function(object,callback){var iterator=is_array(object)?Array.prototype.forEach||function(callback){for(var i=0,n=this.length;i<n;i++)callback(this[i],i,this)}:function(callback){for(var key in this)this.hasOwnProperty(key)&&callback(this[key],key,this)};iterator.apply(object,[callback])},Sifter.prototype.getScoreFunction=function(search,options){var fields,tokens,token_count,nesting;search=this.prepareSearch(search,options),tokens=search.tokens,fields=search.options.fields,token_count=tokens.length,nesting=search.options.nesting;function scoreValue(score,token){var pos;return!score||-1===(pos=(score=String(score||"")).search(token.regex))?0:(score=token.string.length/score.length,0===pos&&(score+=.5),score)}var field_count,scoreObject=(field_count=fields.length)?1===field_count?function(token,data){return scoreValue(getattr(data,fields[0],nesting),token)}:function(token,data){for(var i=0,sum=0;i<field_count;i++)sum+=scoreValue(getattr(data,fields[i],nesting),token);return sum/field_count}:function(){return 0};return token_count?1===token_count?function(data){return scoreObject(tokens[0],data)}:"and"===search.options.conjunction?function(data){for(var score,i=0,sum=0;i<token_count;i++){if((score=scoreObject(tokens[i],data))<=0)return 0;sum+=score}return sum/token_count}:function(data){for(var i=0,sum=0;i<token_count;i++)sum+=scoreObject(tokens[i],data);return sum/token_count}:function(){return 0}},Sifter.prototype.getSortFunction=function(search,options){var i,n,field,fields_count,multiplier,multipliers,implicit_score,self=this,sort=!(search=self.prepareSearch(search,options)).query&&options.sort_empty||options.sort,get_field=function(name,result){return"$score"===name?result.score:getattr(self.items[result.id],name,options.nesting)},fields=[];if(sort)for(i=0,n=sort.length;i<n;i++)!search.query&&"$score"===sort[i].field||fields.push(sort[i]);if(search.query){for(implicit_score=!0,i=0,n=fields.length;i<n;i++)if("$score"===fields[i].field){implicit_score=!1;break}implicit_score&&fields.unshift({field:"$score",direction:"desc"})}else for(i=0,n=fields.length;i<n;i++)if("$score"===fields[i].field){fields.splice(i,1);break}for(multipliers=[],i=0,n=fields.length;i<n;i++)multipliers.push("desc"===fields[i].direction?-1:1);return(fields_count=fields.length)?1===fields_count?(field=fields[0].field,multiplier=multipliers[0],function(a,b){return multiplier*cmp(get_field(field,a),get_field(field,b))}):function(a,b){for(var result,i=0;i<fields_count;i++)if(result=fields[i].field,result=multipliers[i]*cmp(get_field(result,a),get_field(result,b)))return result;return 0}:null},Sifter.prototype.prepareSearch=function(query,options){if("object"==typeof query)return query;var option_fields=(options=extend({},options)).fields,option_sort=options.sort,option_sort_empty=options.sort_empty;return option_fields&&!is_array(option_fields)&&(options.fields=[option_fields]),option_sort&&!is_array(option_sort)&&(options.sort=[option_sort]),option_sort_empty&&!is_array(option_sort_empty)&&(options.sort_empty=[option_sort_empty]),{options:options,query:String(query||"").toLowerCase(),tokens:this.tokenize(query),total:0,items:[]}},Sifter.prototype.search=function(fn_sort,options){var score,fn_score,search=this.prepareSearch(fn_sort,options);return options=search.options,fn_sort=search.query,fn_score=options.score||this.getScoreFunction(search),fn_sort.length?this.iterator(this.items,function(item,id){score=fn_score(item),(!1===options.filter||0<score)&&search.items.push({score:score,id:id})}):this.iterator(this.items,function(item,id){search.items.push({score:1,id:id})}),(fn_sort=this.getSortFunction(search,options))&&search.items.sort(fn_sort),search.total=search.items.length,"number"==typeof options.limit&&(search.items=search.items.slice(0,options.limit)),search};var cmp=function(a,b){return"number"==typeof a&&"number"==typeof b?b<a?1:a<b?-1:0:(a=asciifold(String(a||"")),(b=asciifold(String(b||"")))<a?1:a<b?-1:0)},extend=function(a,b){for(var k,object,i=1,n=arguments.length;i<n;i++)if(object=arguments[i])for(k in object)object.hasOwnProperty(k)&&(a[k]=object[k]);return a},getattr=function(obj,name,nesting){if(obj&&name){if(!nesting)return obj[name];for(var names=name.split(".");names.length&&(obj=obj[names.shift()]););return obj}},trim=function(str){return(str+"").replace(/^\s+|\s+$|/g,"")},escape_regex=function(str){return(str+"").replace(/([.?*+^$[\]\\(){}|-])/g,"\\$1")},is_array=Array.isArray||"undefined"!=typeof $&&$.isArray||function(object){return"[object Array]"===Object.prototype.toString.call(object)},DIACRITICS={a:"[aḀḁĂăÂâǍǎȺⱥȦȧẠạÄäÀàÁáĀāÃãÅåąĄÃąĄ]",b:"[b␢βΒB฿𐌁ᛒ]",c:"[cĆćĈĉČčĊċC̄c̄ÇçḈḉȻȼƇƈɕᴄCc]",d:"[dĎďḊḋḐḑḌḍḒḓḎḏĐđD̦d̦ƉɖƊɗƋƌᵭᶁᶑȡᴅDdð]",e:"[eÉéÈèÊêḘḙĚěĔĕẼẽḚḛẺẻĖėËëĒēȨȩĘęᶒɆɇȄȅẾếỀềỄễỂểḜḝḖḗḔḕȆȇẸẹỆệⱸᴇEeɘǝƏƐε]",f:"[fƑƒḞḟ]",g:"[gɢ₲ǤǥĜĝĞğĢģƓɠĠġ]",h:"[hĤĥĦħḨḩẖẖḤḥḢḣɦʰǶƕ]",i:"[iÍíÌìĬĭÎîǏǐÏïḮḯĨĩĮįĪīỈỉȈȉȊȋỊịḬḭƗɨɨ̆ᵻᶖİiIıɪIi]",j:"[jȷĴĵɈɉʝɟʲ]",k:"[kƘƙꝀꝁḰḱǨǩḲḳḴḵκϰ₭]",l:"[lŁłĽľĻļĹĺḶḷḸḹḼḽḺḻĿŀȽƚⱠⱡⱢɫɬᶅɭȴʟLl]",n:"[nŃńǸǹŇňÑñṄṅŅņṆṇṊṋṈṉN̈n̈ƝɲȠƞᵰᶇɳȵɴNnŊŋ]",o:"[oØøÖöÓóÒòÔôǑǒŐőŎŏȮȯỌọƟɵƠơỎỏŌōÕõǪǫȌȍՕօ]",p:"[pṔṕṖṗⱣᵽƤƥᵱ]",q:"[qꝖꝗʠɊɋꝘꝙq̃]",r:"[rŔŕɌɍŘřŖŗṘṙȐȑȒȓṚṛⱤɽ]",s:"[sŚśṠṡṢṣꞨꞩŜŝŠšŞşȘșS̈s̈]",t:"[tŤťṪṫŢţṬṭƮʈȚțṰṱṮṯƬƭ]",u:"[uŬŭɄʉỤụÜüÚúÙùÛûǓǔŰűŬŭƯưỦủŪūŨũŲųȔȕ∪]",v:"[vṼṽṾṿƲʋꝞꝟⱱʋ]",w:"[wẂẃẀẁŴŵẄẅẆẇẈẉ]",x:"[xẌẍẊẋχ]",y:"[yÝýỲỳŶŷŸÿỸỹẎẏỴỵɎɏƳƴ]",z:"[zŹźẐẑŽžŻżẒẓẔẕƵƶ]"},asciifold=function(){var i,n,k,chunk,foreignletters="",lookup={};for(k in DIACRITICS)if(DIACRITICS.hasOwnProperty(k))for(foreignletters+=chunk=DIACRITICS[k].substring(2,DIACRITICS[k].length-1),i=0,n=chunk.length;i<n;i++)lookup[chunk.charAt(i)]=k;var regexp=new RegExp("["+foreignletters+"]","g");return function(str){return str.replace(regexp,function(foreignletter){return lookup[foreignletter]}).toLowerCase()}}();return Sifter}),function(root,factory){"function"==typeof define&&define.amd?define("microplugin",factory):"object"==typeof exports?module.exports=factory():root.MicroPlugin=factory()}(this,function(){var MicroPlugin={mixin:function(Interface){Interface.plugins={},Interface.prototype.initializePlugins=function(plugins){var i,n,key,queue=[];if(this.plugins={names:[],settings:{},requested:{},loaded:{}},utils.isArray(plugins))for(i=0,n=plugins.length;i<n;i++)"string"==typeof plugins[i]?queue.push(plugins[i]):(this.plugins.settings[plugins[i].name]=plugins[i].options,queue.push(plugins[i].name));else if(plugins)for(key in plugins)plugins.hasOwnProperty(key)&&(this.plugins.settings[key]=plugins[key],queue.push(key));for(;queue.length;)this.require(queue.shift())},Interface.prototype.loadPlugin=function(name){var plugins=this.plugins,plugin=Interface.plugins[name];if(!Interface.plugins.hasOwnProperty(name))throw new Error('Unable to find "'+name+'" plugin');plugins.requested[name]=!0,plugins.loaded[name]=plugin.fn.apply(this,[this.plugins.settings[name]||{}]),plugins.names.push(name)},Interface.prototype.require=function(name){var plugins=this.plugins;if(!this.plugins.loaded.hasOwnProperty(name)){if(plugins.requested[name])throw new Error('Plugin has circular dependency ("'+name+'")');this.loadPlugin(name)}return plugins.loaded[name]},Interface.define=function(name,fn){Interface.plugins[name]={name:name,fn:fn}}}},utils={isArray:Array.isArray||function(vArg){return"[object Array]"===Object.prototype.toString.call(vArg)}};return MicroPlugin}),function(root,factory){"function"==typeof define&&define.amd?define("selectize",["jquery","sifter","microplugin"],factory):"object"==typeof module&&"object"==typeof module.exports?module.exports=factory(require("jquery"),require("sifter"),require("microplugin")):root.Selectize=factory(root.jQuery,root.Sifter,root.MicroPlugin)}(this,function($,Sifter,MicroPlugin){"use strict";$.fn.removeHighlight=function(){return this.find("span.highlight").each(function(){this.parentNode.firstChild.nodeName;var parent=this.parentNode;parent.replaceChild(this.firstChild,this),parent.normalize()}).end()};function MicroEvent(){}MicroEvent.prototype={on:function(event,fct){this._events=this._events||{},this._events[event]=this._events[event]||[],this._events[event].push(fct)},off:function(event,fct){var n=arguments.length;return 0===n?delete this._events:1===n?delete this._events[event]:(this._events=this._events||{},void(event in this._events!=!1&&this._events[event].splice(this._events[event].indexOf(fct),1)))},trigger:function(event){if(this._events=this._events||{},event in this._events!=!1)for(var i=0;i<this._events[event].length;i++)this._events[event][i].apply(this,Array.prototype.slice.call(arguments,1))}},MicroEvent.mixin=function(destObject){for(var props=["on","off","trigger"],i=0;i<props.length;i++)destObject.prototype[props[i]]=MicroEvent.prototype[props[i]]};function isset(object){return void 0!==object}function hash_key(value){return null==value?null:"boolean"==typeof value?value?"1":"0":value+""}function escape_html(str){return(str+"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function debounce_events(self,types,fn){var type,trigger=self.trigger,event_args={};for(type in self.trigger=function(){var type=arguments[0];if(-1===types.indexOf(type))return trigger.apply(self,arguments);event_args[type]=arguments},fn.apply(self,[]),self.trigger=trigger,event_args)event_args.hasOwnProperty(type)&&trigger.apply(self,event_args[type])}function getSelection(input){var sel,selLen,result={};return void 0===input?console.warn("WARN getSelection cannot locate input control"):"selectionStart"in input?(result.start=input.selectionStart,result.length=input.selectionEnd-result.start):document.selection&&(input.focus(),sel=document.selection.createRange(),selLen=document.selection.createRange().text.length,sel.moveStart("character",-input.value.length),result.start=sel.text.length-selLen,result.length=selLen),result}function measureString(str,$parent){return str?(Selectize.$testInput||(Selectize.$testInput=$("<span />").css({position:"absolute",width:"auto",padding:0,whiteSpace:"pre"}),$("<div />").css({position:"absolute",width:0,height:0,overflow:"hidden"}).append(Selectize.$testInput).appendTo("body")),Selectize.$testInput.text(str),function($from,$to,properties){var i,n,styles={};if(properties)for(i=0,n=properties.length;i<n;i++)styles[properties[i]]=$from.css(properties[i]);else styles=$from.css();$to.css(styles)}($parent,Selectize.$testInput,["letterSpacing","fontSize","fontFamily","fontWeight","textTransform"]),Selectize.$testInput.width()):0}function autoGrow($input){function update(e,selection){var keyCode,width,shift,placeholder;selection=selection||{},(e=e||window.event||{}).metaKey||e.altKey||!selection.force&&!1===$input.data("grow")||(width=$input.val(),e.type&&"keydown"===e.type.toLowerCase()&&(shift=48<=(keyCode=e.keyCode)&&keyCode<=57||65<=keyCode&&keyCode<=90||96<=keyCode&&keyCode<=111||186<=keyCode&&keyCode<=222||32===keyCode,46===keyCode||8===keyCode?(selection=getSelection($input[0])).length?width=width.substring(0,selection.start)+width.substring(selection.start+selection.length):8===keyCode&&selection.start?width=width.substring(0,selection.start-1)+width.substring(selection.start+1):46===keyCode&&void 0!==selection.start&&(width=width.substring(0,selection.start)+width.substring(selection.start+1)):shift&&(shift=e.shiftKey,placeholder=String.fromCharCode(e.keyCode),width+=placeholder=shift?placeholder.toUpperCase():placeholder.toLowerCase())),placeholder=$input.attr("placeholder"),(width=measureString(width=!width&&placeholder?placeholder:width,$input)+4)!==currentWidth&&(currentWidth=width,$input.width(width),$input.triggerHandler("resize")))}var currentWidth=null;$input.on("keydown keyup update blur",update),update()}var message,options,IS_MAC=/Mac/.test(navigator.userAgent),KEY_CMD=IS_MAC?91:17,KEY_CTRL=IS_MAC?18:17,SUPPORTS_VALIDITY_API=!/android/i.test(window.navigator.userAgent)&&!!document.createElement("input").validity,hook={before:function(self,method,fn){var original=self[method];self[method]=function(){return fn.apply(self,arguments),original.apply(self,arguments)}},after:function(self,method,fn){var original=self[method];self[method]=function(){var result=original.apply(self,arguments);return fn.apply(self,arguments),result}}},Selectize=function($input,settings){var i,n,input=$input[0];input.selectize=this;var fn,delay,timeout,dir=window.getComputedStyle&&window.getComputedStyle(input,null);if(dir=(dir=dir?dir.getPropertyValue("direction"):input.currentStyle&&input.currentStyle.direction)||$input.parents("[dir]:first").attr("dir")||"",$.extend(this,{order:0,settings:settings,$input:$input,tabIndex:$input.attr("tabindex")||"",tagType:"select"===input.tagName.toLowerCase()?1:2,rtl:/rtl/i.test(dir),eventNS:".selectize"+ ++Selectize.count,highlightedValue:null,isBlurring:!1,isOpen:!1,isDisabled:!1,isRequired:$input.is("[required]"),isInvalid:!1,isLocked:!1,isFocused:!1,isInputHidden:!1,isSetup:!1,isShiftDown:!1,isCmdDown:!1,isCtrlDown:!1,ignoreFocus:!1,ignoreBlur:!1,ignoreHover:!1,hasOptions:!1,currentResults:null,lastValue:"",lastValidValue:"",caretPos:0,loading:0,loadedSearches:{},$activeOption:null,$activeItems:[],optgroups:{},options:{},userOptions:{},items:[],renderCache:{},onSearchChange:null===settings.loadThrottle?this.onSearchChange:(fn=this.onSearchChange,delay=settings.loadThrottle,function(){var self=this,args=arguments;window.clearTimeout(timeout),timeout=window.setTimeout(function(){fn.apply(self,args)},delay)})}),this.sifter=new Sifter(this.options,{diacritics:settings.diacritics}),this.settings.options){for(i=0,n=this.settings.options.length;i<n;i++)this.registerOption(this.settings.options[i]);delete this.settings.options}if(this.settings.optgroups){for(i=0,n=this.settings.optgroups.length;i<n;i++)this.registerOptionGroup(this.settings.optgroups[i]);delete this.settings.optgroups}this.settings.mode=this.settings.mode||(1===this.settings.maxItems?"single":"multi"),"boolean"!=typeof this.settings.hideSelected&&(this.settings.hideSelected="multi"===this.settings.mode),this.initializePlugins(this.settings.plugins),this.setupCallbacks(),this.setupTemplates(),this.setup()};return MicroEvent.mixin(Selectize),void 0!==MicroPlugin?MicroPlugin.mixin(Selectize):(message="Dependency MicroPlugin is missing",options=(options={explanation:'Make sure you either: (1) are using the "standalone" version of Selectize, or (2) require MicroPlugin before you load Selectize.'})||{},console.error("Selectize: "+message),options.explanation&&(console.group&&console.group(),console.error(options.explanation),console.group&&console.groupEnd())),$.extend(Selectize.prototype,{setup:function(){var delimiterEscaped,$parent,fn,self=this,settings=self.settings,eventNS=self.eventNS,$window=$(window),$document=$(document),$input=self.$input,event=self.settings.mode,classes=$input.attr("class")||"",$wrapper=$("<div>").addClass(settings.wrapperClass).addClass(classes).addClass(event),$control=$("<div>").addClass(settings.inputClass).addClass("items").appendTo($wrapper),$control_input=$('<input type="text" autocomplete="new-password" autofill="no" />').appendTo($control).attr("tabindex",$input.is(":disabled")?"-1":self.tabIndex),inputId=$(settings.dropdownParent||$wrapper),selector=$("<div>").addClass(settings.dropdownClass).addClass(event).hide().appendTo(inputId),event=$("<div>").addClass(settings.dropdownContentClass).attr("tabindex","-1").appendTo(selector);(inputId=$input.attr("id"))&&($control_input.attr("id",inputId+"-selectized"),$("label[for='"+inputId+"']").attr("for",inputId+"-selectized")),self.settings.copyClassesToDropdown&&selector.addClass(classes),$wrapper.css({width:$input[0].style.width}),self.plugins.names.length&&(delimiterEscaped="plugin-"+self.plugins.names.join(" plugin-"),$wrapper.addClass(delimiterEscaped),selector.addClass(delimiterEscaped)),(null===settings.maxItems||1<settings.maxItems)&&1===self.tagType&&$input.attr("multiple","multiple"),self.settings.placeholder&&$control_input.attr("placeholder",settings.placeholder),!self.settings.splitOn&&self.settings.delimiter&&(delimiterEscaped=self.settings.delimiter.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&"),self.settings.splitOn=new RegExp("\\s*"+delimiterEscaped+"+\\s*")),$input.attr("autocorrect")&&$control_input.attr("autocorrect",$input.attr("autocorrect")),$input.attr("autocapitalize")&&$control_input.attr("autocapitalize",$input.attr("autocapitalize")),$control_input[0].type=$input[0].type,self.$wrapper=$wrapper,self.$control=$control,self.$control_input=$control_input,self.$dropdown=selector,self.$dropdown_content=event,selector.on("mouseenter mousedown click","[data-disabled]>[data-selectable]",function(e){e.stopImmediatePropagation()}),selector.on("mouseenter","[data-selectable]",function(){return self.onOptionHover.apply(self,arguments)}),selector.on("mousedown click","[data-selectable]",function(){return self.onOptionSelect.apply(self,arguments)}),event="mousedown",selector="*:not(input)",fn=function(){return self.onItemSelect.apply(self,arguments)},($parent=$control).on(event,selector,function(e){for(var child=e.target;child&&child.parentNode!==$parent[0];)child=child.parentNode;return e.currentTarget=child,fn.apply(this,[e])}),autoGrow($control_input),$control.on({mousedown:function(){return self.onMouseDown.apply(self,arguments)},click:function(){return self.onClick.apply(self,arguments)}}),$control_input.on({mousedown:function(e){e.stopPropagation()},keydown:function(){return self.onKeyDown.apply(self,arguments)},keyup:function(){return self.onKeyUp.apply(self,arguments)},keypress:function(){return self.onKeyPress.apply(self,arguments)},resize:function(){self.positionDropdown.apply(self,[])},blur:function(){return self.onBlur.apply(self,arguments)},focus:function(){return self.ignoreBlur=!1,self.onFocus.apply(self,arguments)},paste:function(){return self.onPaste.apply(self,arguments)}}),$document.on("keydown"+eventNS,function(e){self.isCmdDown=e[IS_MAC?"metaKey":"ctrlKey"],self.isCtrlDown=e[IS_MAC?"altKey":"ctrlKey"],self.isShiftDown=e.shiftKey}),$document.on("keyup"+eventNS,function(e){e.keyCode===KEY_CTRL&&(self.isCtrlDown=!1),16===e.keyCode&&(self.isShiftDown=!1),e.keyCode===KEY_CMD&&(self.isCmdDown=!1)}),$document.on("mousedown"+eventNS,function(e){if(self.isFocused){if(e.target===self.$dropdown[0]||e.target.parentNode===self.$dropdown[0])return!1;self.$control.has(e.target).length||e.target===self.$control[0]||self.blur(e.target)}}),$window.on(["scroll"+eventNS,"resize"+eventNS].join(" "),function(){self.isOpen&&self.positionDropdown.apply(self,arguments)}),$window.on("mousemove"+eventNS,function(){self.ignoreHover=!1}),this.revertSettings={$children:$input.children().detach(),tabindex:$input.attr("tabindex")},$input.attr("tabindex",-1).hide().after(self.$wrapper),$.isArray(settings.items)&&(self.lastValidValue=settings.items,self.setValue(settings.items),delete settings.items),SUPPORTS_VALIDITY_API&&$input.on("invalid"+eventNS,function(e){e.preventDefault(),self.isInvalid=!0,self.refreshState()}),self.updateOriginalInput(),self.refreshItems(),self.refreshState(),self.updatePlaceholder(),self.isSetup=!0,$input.is(":disabled")&&self.disable(),self.on("change",this.onChange),$input.data("selectize",self),$input.addClass("selectized"),self.trigger("initialize"),!0===settings.preload&&self.onSearchChange("")},setupTemplates:function(){var field_label=this.settings.labelField,field_optgroup=this.settings.optgroupLabelField,templates={optgroup:function(data){return'<div class="optgroup">'+data.html+"</div>"},optgroup_header:function(data,escape){return'<div class="optgroup-header">'+escape(data[field_optgroup])+"</div>"},option:function(data,escape){return'<div class="option">'+escape(data[field_label])+"</div>"},item:function(data,escape){return'<div class="item">'+escape(data[field_label])+"</div>"},option_create:function(data,escape){return'<div class="create">Add <strong>'+escape(data.input)+"</strong>&hellip;</div>"}};this.settings.render=$.extend({},templates,this.settings.render)},setupCallbacks:function(){var key,fn,callbacks={initialize:"onInitialize",change:"onChange",item_add:"onItemAdd",item_remove:"onItemRemove",clear:"onClear",option_add:"onOptionAdd",option_remove:"onOptionRemove",option_clear:"onOptionClear",optgroup_add:"onOptionGroupAdd",optgroup_remove:"onOptionGroupRemove",optgroup_clear:"onOptionGroupClear",dropdown_open:"onDropdownOpen",dropdown_close:"onDropdownClose",type:"onType",load:"onLoad",focus:"onFocus",blur:"onBlur",dropdown_item_activate:"onDropdownItemActivate",dropdown_item_deactivate:"onDropdownItemDeactivate"};for(key in callbacks)callbacks.hasOwnProperty(key)&&(fn=this.settings[callbacks[key]])&&this.on(key,fn)},onClick:function(e){this.isFocused&&this.isOpen||(this.focus(),e.preventDefault())},onMouseDown:function(e){var self=this,defaultPrevented=e.isDefaultPrevented();$(e.target);if(self.isFocused){if(e.target!==self.$control_input[0])return"single"===self.settings.mode?self.isOpen?self.close():self.open():defaultPrevented||self.setActiveItem(null),!1}else defaultPrevented||window.setTimeout(function(){self.focus()},0)},onChange:function(){""!==this.getValue()&&(this.lastValidValue=this.getValue()),this.$input.trigger("input"),this.$input.trigger("change")},onPaste:function(e){var self=this;self.isFull()||self.isInputHidden||self.isLocked?e.preventDefault():self.settings.splitOn&&setTimeout(function(){var pastedText=self.$control_input.val();if(pastedText.match(self.settings.splitOn))for(var splitInput=$.trim(pastedText).split(self.settings.splitOn),i=0,n=splitInput.length;i<n;i++)self.createItem(splitInput[i])},0)},onKeyPress:function(e){if(this.isLocked)return e&&e.preventDefault();var character=String.fromCharCode(e.keyCode||e.which);return this.settings.create&&"multi"===this.settings.mode&&character===this.settings.delimiter?(this.createItem(),e.preventDefault(),!1):void 0},onKeyDown:function(e){var $prev;e.target,this.$control_input[0];if(this.isLocked)9!==e.keyCode&&e.preventDefault();else{switch(e.keyCode){case 65:if(this.isCmdDown)return void this.selectAll();break;case 27:return void(this.isOpen&&(e.preventDefault(),e.stopPropagation(),this.close()));case 78:if(!e.ctrlKey||e.altKey)break;case 40:return!this.isOpen&&this.hasOptions?this.open():this.$activeOption&&(this.ignoreHover=!0,($prev=this.getAdjacentOption(this.$activeOption,1)).length&&this.setActiveOption($prev,!0,!0)),void e.preventDefault();case 80:if(!e.ctrlKey||e.altKey)break;case 38:return this.$activeOption&&(this.ignoreHover=!0,($prev=this.getAdjacentOption(this.$activeOption,-1)).length&&this.setActiveOption($prev,!0,!0)),void e.preventDefault();case 13:return void(this.isOpen&&this.$activeOption&&(this.onOptionSelect({currentTarget:this.$activeOption}),e.preventDefault()));case 37:return void this.advanceSelection(-1,e);case 39:return void this.advanceSelection(1,e);case 9:return this.settings.selectOnTab&&this.isOpen&&this.$activeOption&&(this.onOptionSelect({currentTarget:this.$activeOption}),this.isFull()||e.preventDefault()),void(this.settings.create&&this.createItem()&&e.preventDefault());case 8:case 46:return void this.deleteSelection(e)}!this.isFull()&&!this.isInputHidden||(IS_MAC?e.metaKey:e.ctrlKey)||e.preventDefault()}},onKeyUp:function(value){if(this.isLocked)return value&&value.preventDefault();value=this.$control_input.val()||"";this.lastValue!==value&&(this.lastValue=value,this.onSearchChange(value),this.refreshOptions(),this.trigger("type",value))},onSearchChange:function(value){var self=this,fn=self.settings.load;fn&&(self.loadedSearches.hasOwnProperty(value)||(self.loadedSearches[value]=!0,self.load(function(callback){fn.apply(self,[value,callback])})))},onFocus:function(e){var wasFocused=this.isFocused;if(this.isDisabled)return this.blur(),e&&e.preventDefault(),!1;this.ignoreFocus||(this.isFocused=!0,"focus"===this.settings.preload&&this.onSearchChange(""),wasFocused||this.trigger("focus"),this.$activeItems.length||(this.showInput(),this.setActiveItem(null),this.refreshOptions(!!this.settings.openOnFocus)),this.refreshState())},onBlur:function(deactivate,dest){var self=this;if(self.isFocused&&(self.isFocused=!1,!self.ignoreFocus)){if(!self.ignoreBlur&&document.activeElement===self.$dropdown_content[0])return self.ignoreBlur=!0,void self.onFocus(deactivate);deactivate=function(){self.close(),self.setTextboxValue(""),self.setActiveItem(null),self.setActiveOption(null),self.setCaret(self.items.length),self.refreshState(),dest&&dest.focus&&dest.focus(),self.isBlurring=!1,self.ignoreFocus=!1,self.trigger("blur")};self.isBlurring=!0,self.ignoreFocus=!0,self.settings.create&&self.settings.createOnBlur?self.createItem(null,!1,deactivate):deactivate()}},onOptionHover:function(e){this.ignoreHover||this.setActiveOption(e.currentTarget,!1)},onOptionSelect:function(e){var value,self=this;e.preventDefault&&(e.preventDefault(),e.stopPropagation()),(value=$(e.currentTarget)).hasClass("create")?self.createItem(null,function(){self.settings.closeAfterSelect&&self.close()}):void 0!==(value=value.attr("data-value"))&&(self.lastQuery=null,self.setTextboxValue(""),self.addItem(value),self.settings.closeAfterSelect?self.close():!self.settings.hideSelected&&e.type&&/mouse/.test(e.type)&&self.setActiveOption(self.getOption(value)))},onItemSelect:function(e){this.isLocked||"multi"===this.settings.mode&&(e.preventDefault(),this.setActiveItem(e.currentTarget,e))},load:function(fn){var self=this,$wrapper=self.$wrapper.addClass(self.settings.loadingClass);self.loading++,fn.apply(self,[function(results){self.loading=Math.max(self.loading-1,0),results&&results.length&&(self.addOption(results),self.refreshOptions(self.isFocused&&!self.isInputHidden)),self.loading||$wrapper.removeClass(self.settings.loadingClass),self.trigger("load",results)}])},getTextboxValue:function(){return this.$control_input.val()},setTextboxValue:function(value){var $input=this.$control_input;$input.val()!==value&&($input.val(value).triggerHandler("update"),this.lastValue=value)},getValue:function(){return 1===this.tagType&&this.$input.attr("multiple")?this.items:this.items.join(this.settings.delimiter)},setValue:function(value,silent){debounce_events(this,silent?[]:["change"],function(){this.clear(silent),this.addItems(value,silent)})},setMaxItems:function(value){0===value&&(value=null),this.settings.maxItems=value,this.settings.mode=this.settings.mode||(1===this.settings.maxItems?"single":"multi"),this.refreshState()},setActiveItem:function($item,e){var i,idx,begin,end,item,swap;if("single"!==this.settings.mode){if(!($item=$($item)).length)return $(this.$activeItems).removeClass("active"),this.$activeItems=[],void(this.isFocused&&this.showInput());if("mousedown"===(idx=e&&e.type.toLowerCase())&&this.isShiftDown&&this.$activeItems.length){for(swap=this.$control.children(".active:last"),begin=Array.prototype.indexOf.apply(this.$control[0].childNodes,[swap[0]]),(end=Array.prototype.indexOf.apply(this.$control[0].childNodes,[$item[0]]))<begin&&(swap=begin,begin=end,end=swap),i=begin;i<=end;i++)item=this.$control[0].childNodes[i],-1===this.$activeItems.indexOf(item)&&($(item).addClass("active"),this.$activeItems.push(item));e.preventDefault()}else"mousedown"===idx&&this.isCtrlDown||"keydown"===idx&&this.isShiftDown?$item.hasClass("active")?(idx=this.$activeItems.indexOf($item[0]),this.$activeItems.splice(idx,1),$item.removeClass("active")):this.$activeItems.push($item.addClass("active")[0]):($(this.$activeItems).removeClass("active"),this.$activeItems=[$item.addClass("active")[0]]);this.hideInput(),this.isFocused||this.focus()}},setActiveOption:function(scroll_bottom,scroll,animate){var height_menu,height_item,y,scroll_top;this.$activeOption&&(this.$activeOption.removeClass("active"),this.trigger("dropdown_item_deactivate",this.$activeOption.attr("data-value"))),this.$activeOption=null,(scroll_bottom=$(scroll_bottom)).length&&(this.$activeOption=scroll_bottom.addClass("active"),this.isOpen&&this.trigger("dropdown_item_activate",this.$activeOption.attr("data-value")),!scroll&&isset(scroll)||(height_menu=this.$dropdown_content.height(),height_item=this.$activeOption.outerHeight(!0),scroll=this.$dropdown_content.scrollTop()||0,scroll_bottom=(scroll_top=y=this.$activeOption.offset().top-this.$dropdown_content.offset().top+scroll)-height_menu+height_item,height_menu+scroll<y+height_item?this.$dropdown_content.stop().animate({scrollTop:scroll_bottom},animate?this.settings.scrollDuration:0):y<scroll&&this.$dropdown_content.stop().animate({scrollTop:scroll_top},animate?this.settings.scrollDuration:0)))},selectAll:function(){"single"!==this.settings.mode&&(this.$activeItems=Array.prototype.slice.apply(this.$control.children(":not(input)").addClass("active")),this.$activeItems.length&&(this.hideInput(),this.close()),this.focus())},hideInput:function(){this.setTextboxValue(""),this.$control_input.css({opacity:0,position:"absolute",left:this.rtl?1e4:-1e4}),this.isInputHidden=!0},showInput:function(){this.$control_input.css({opacity:1,position:"relative",left:0}),this.isInputHidden=!1},focus:function(){var self=this;return self.isDisabled||(self.ignoreFocus=!0,self.$control_input[0].focus(),window.setTimeout(function(){self.ignoreFocus=!1,self.onFocus()},0)),self},blur:function(dest){return this.$control_input[0].blur(),this.onBlur(null,dest),this},getScoreFunction:function(query){return this.sifter.getScoreFunction(query,this.getSearchOptions())},getSearchOptions:function(){var settings=this.settings,sort=settings.sortField;return"string"==typeof sort&&(sort=[{field:sort}]),{fields:settings.searchField,conjunction:settings.searchConjunction,sort:sort,nesting:settings.nesting}},search:function(query){var i,result,calculateScore,settings=this.settings,options=this.getSearchOptions();if(settings.score&&"function"!=typeof(calculateScore=this.settings.score.apply(this,[query])))throw new Error('Selectize "score" setting must be a function that returns a function');if(query!==this.lastQuery?(this.lastQuery=query,result=this.sifter.search(query,$.extend(options,{score:calculateScore})),this.currentResults=result):result=$.extend(!0,{},this.currentResults),settings.hideSelected)for(i=result.items.length-1;0<=i;i--)-1!==this.items.indexOf(hash_key(result.items[i].id))&&result.items.splice(i,1);return result},refreshOptions:function(triggerDropdown){var i,j,k,groups,groups_order,option,option_html,optgroup,optgroups,html,html_children,has_create_option,$active,$create;void 0===triggerDropdown&&(triggerDropdown=!0);var d,tmp,self=this,query=$.trim(self.$control_input.val()),results=self.search(query),$dropdown_content=self.$dropdown_content,$active_before=self.$activeOption&&hash_key(self.$activeOption.attr("data-value")),n=results.items.length;for("number"==typeof self.settings.maxOptions&&(n=Math.min(n,self.settings.maxOptions)),groups={},groups_order=[],i=0;i<n;i++)for(option=self.options[results.items[i].id],option_html=self.render("option",option),optgroup=option[self.settings.optgroupField]||"",j=0,k=(optgroups=$.isArray(optgroup)?optgroup:[optgroup])&&optgroups.length;j<k;j++)optgroup=optgroups[j],self.optgroups.hasOwnProperty(optgroup)||(optgroup=""),groups.hasOwnProperty(optgroup)||(groups[optgroup]=document.createDocumentFragment(),groups_order.push(optgroup)),groups[optgroup].appendChild(option_html);for(this.settings.lockOptgroupOrder&&groups_order.sort(function(a,b){return(self.optgroups[a].$order||0)-(self.optgroups[b].$order||0)}),html=document.createDocumentFragment(),i=0,n=groups_order.length;i<n;i++)optgroup=groups_order[i],self.optgroups.hasOwnProperty(optgroup)&&groups[optgroup].childNodes.length?((html_children=document.createDocumentFragment()).appendChild(self.render("optgroup_header",self.optgroups[optgroup])),html_children.appendChild(groups[optgroup]),html.appendChild(self.render("optgroup",$.extend({},self.optgroups[optgroup],{html:(d=html_children,tmp=void 0,(tmp=document.createElement("div")).appendChild(d.cloneNode(!0)),tmp.innerHTML),dom:html_children})))):html.appendChild(groups[optgroup]);if($dropdown_content.html(html),self.settings.highlight&&($dropdown_content.removeHighlight(),results.query.length&&results.tokens.length))for(i=0,n=results.tokens.length;i<n;i++)!function($element,pattern){if("string"!=typeof pattern||pattern.length){var regex="string"==typeof pattern?new RegExp(pattern,"i"):pattern,highlight=function(node){var skip=0;if(3===node.nodeType){var spannode,middleclone,middlebit=node.data.search(regex);0<=middlebit&&0<node.data.length&&(middleclone=node.data.match(regex),(spannode=document.createElement("span")).className="highlight",(middlebit=node.splitText(middlebit)).splitText(middleclone[0].length),middleclone=middlebit.cloneNode(!0),spannode.appendChild(middleclone),middlebit.parentNode.replaceChild(spannode,middlebit),skip=1)}else if(1===node.nodeType&&node.childNodes&&!/(script|style)/i.test(node.tagName)&&("highlight"!==node.className||"SPAN"!==node.tagName))for(var i=0;i<node.childNodes.length;++i)i+=highlight(node.childNodes[i]);return skip};$element.each(function(){highlight(this)})}}($dropdown_content,results.tokens[i].regex);if(!self.settings.hideSelected)for(self.$dropdown.find(".selected").removeClass("selected"),i=0,n=self.items.length;i<n;i++)self.getOption(self.items[i]).addClass("selected");(has_create_option=self.canCreate(query))&&($dropdown_content.prepend(self.render("option_create",{input:query})),$create=$($dropdown_content[0].childNodes[0])),self.hasOptions=0<results.items.length||has_create_option,self.hasOptions?(0<results.items.length?(($active_before=$active_before&&self.getOption($active_before))&&$active_before.length?$active=$active_before:"single"===self.settings.mode&&self.items.length&&($active=self.getOption(self.items[0])),$active&&$active.length||($active=$create&&!self.settings.addPrecedence?self.getAdjacentOption($create,1):$dropdown_content.find("[data-selectable]:first"))):$active=$create,self.setActiveOption($active),triggerDropdown&&!self.isOpen&&self.open()):(self.setActiveOption(null),triggerDropdown&&self.isOpen&&self.close())},addOption:function(data){var i,n,value;if($.isArray(data))for(i=0,n=data.length;i<n;i++)this.addOption(data[i]);else(value=this.registerOption(data))&&(this.userOptions[value]=!0,this.lastQuery=null,this.trigger("option_add",value,data))},registerOption:function(data){var key=hash_key(data[this.settings.valueField]);return null!=key&&!this.options.hasOwnProperty(key)&&(data.$order=data.$order||++this.order,this.options[key]=data,key)},registerOptionGroup:function(data){var key=hash_key(data[this.settings.optgroupValueField]);return!!key&&(data.$order=data.$order||++this.order,this.optgroups[key]=data,key)},addOptionGroup:function(id,data){data[this.settings.optgroupValueField]=id,(id=this.registerOptionGroup(data))&&this.trigger("optgroup_add",id,data)},removeOptionGroup:function(id){this.optgroups.hasOwnProperty(id)&&(delete this.optgroups[id],this.renderCache={},this.trigger("optgroup_remove",id))},clearOptionGroups:function(){this.optgroups={},this.renderCache={},this.trigger("optgroup_clear")},updateOption:function($item,$item_new){var value_new,cache_items,cache_options;if($item=hash_key($item),value_new=hash_key($item_new[this.settings.valueField]),null!==$item&&this.options.hasOwnProperty($item)){if("string"!=typeof value_new)throw new Error("Value must be set in option data");cache_options=this.options[$item].$order,value_new!==$item&&(delete this.options[$item],-1!==(cache_items=this.items.indexOf($item))&&this.items.splice(cache_items,1,value_new)),$item_new.$order=$item_new.$order||cache_options,this.options[value_new]=$item_new,cache_items=this.renderCache.item,cache_options=this.renderCache.option,cache_items&&(delete cache_items[$item],delete cache_items[value_new]),cache_options&&(delete cache_options[$item],delete cache_options[value_new]),-1!==this.items.indexOf(value_new)&&($item=this.getItem($item),$item_new=$(this.render("item",$item_new)),$item.hasClass("active")&&$item_new.addClass("active"),$item.replaceWith($item_new)),this.lastQuery=null,this.isOpen&&this.refreshOptions(!1)}},removeOption:function(value,silent){value=hash_key(value);var cache_items=this.renderCache.item,cache_options=this.renderCache.option;cache_items&&delete cache_items[value],cache_options&&delete cache_options[value],delete this.userOptions[value],delete this.options[value],this.lastQuery=null,this.trigger("option_remove",value),this.removeItem(value,silent)},clearOptions:function(silent){var self=this;self.loadedSearches={},self.userOptions={},self.renderCache={};var options=self.options;$.each(self.options,function(key,value){-1==self.items.indexOf(key)&&delete options[key]}),self.options=self.sifter.items=options,self.lastQuery=null,self.trigger("option_clear"),self.clear(silent)},getOption:function(value){return this.getElementWithValue(value,this.$dropdown_content.find("[data-selectable]"))},getAdjacentOption:function($option,index){var $options=this.$dropdown.find("[data-selectable]"),index=$options.index($option)+index;return 0<=index&&index<$options.length?$options.eq(index):$()},getElementWithValue:function(value,$els){if(null!=(value=hash_key(value)))for(var i=0,n=$els.length;i<n;i++)if($els[i].getAttribute("data-value")===value)return $($els[i]);return $()},getElementWithTextContent:function(textContent,ignoreCase,$els){if(null!=(textContent=hash_key(textContent)))for(var i=0,n=$els.length;i<n;i++){var eleTextContent=$els[i].textContent;if(1==ignoreCase&&(eleTextContent=null!==eleTextContent?eleTextContent.toLowerCase():null,textContent=textContent.toLowerCase()),eleTextContent===textContent)return $($els[i])}return $()},getItem:function(value){return this.getElementWithValue(value,this.$control.children())},getFirstItemMatchedByTextContent:function(textContent,ignoreCase){return ignoreCase=null!==ignoreCase&&!0===ignoreCase,this.getElementWithTextContent(textContent,ignoreCase,this.$dropdown_content.find("[data-selectable]"))},addItems:function(control,silent){this.buffer=document.createDocumentFragment();for(var childNodes=this.$control[0].childNodes,i=0;i<childNodes.length;i++)this.buffer.appendChild(childNodes[i]);for(var items=$.isArray(control)?control:[control],i=0,n=items.length;i<n;i++)this.isPending=i<n-1,this.addItem(items[i],silent);control=this.$control[0];control.insertBefore(this.buffer,control.firstChild),this.buffer=null},addItem:function(value,silent){debounce_events(this,silent?[]:["change"],function(){var $item,$options,value_next,inputMode=this.settings.mode;value=hash_key(value),-1===this.items.indexOf(value)?this.options.hasOwnProperty(value)&&("single"===inputMode&&this.clear(silent),"multi"===inputMode&&this.isFull()||($item=$(this.render("item",this.options[value])),value_next=this.isFull(),this.items.splice(this.caretPos,0,value),this.insertAtCaret($item),this.isPending&&(value_next||!this.isFull())||this.refreshState(),this.isSetup&&($options=this.$dropdown_content.find("[data-selectable]"),this.isPending||(value_next=this.getOption(value),value_next=this.getAdjacentOption(value_next,1).attr("data-value"),this.refreshOptions(this.isFocused&&"single"!==inputMode),value_next&&this.setActiveOption(this.getOption(value_next))),!$options.length||this.isFull()?this.close():this.isPending||this.positionDropdown(),this.updatePlaceholder(),this.trigger("item_add",value,$item),this.isPending||this.updateOriginalInput({silent:silent})))):"single"===inputMode&&this.close()})},removeItem:function(value,silent){var i,idx,$item=value instanceof $?value:this.getItem(value);value=hash_key($item.attr("data-value")),-1!==(i=this.items.indexOf(value))&&(this.trigger("item_before_remove",value,$item),$item.remove(),$item.hasClass("active")&&(idx=this.$activeItems.indexOf($item[0]),this.$activeItems.splice(idx,1)),this.items.splice(i,1),this.lastQuery=null,!this.settings.persist&&this.userOptions.hasOwnProperty(value)&&this.removeOption(value,silent),i<this.caretPos&&this.setCaret(this.caretPos-1),this.refreshState(),this.updatePlaceholder(),this.updateOriginalInput({silent:silent}),this.positionDropdown(),this.trigger("item_remove",value,$item))},createItem:function(output,triggerDropdown){var self=this,caret=self.caretPos;output=output||$.trim(self.$control_input.val()||"");var callback=arguments[arguments.length-1];if("function"!=typeof callback&&(callback=function(){}),"boolean"!=typeof triggerDropdown&&(triggerDropdown=!0),!self.canCreate(output))return callback(),!1;self.lock();var fn,called,setup="function"==typeof self.settings.create?this.settings.create:function(input){var data={};return data[self.settings.labelField]=input,data[self.settings.valueField]=input,data},create=(called=!(fn=function(data){if(self.unlock(),!data||"object"!=typeof data)return callback();var value=hash_key(data[self.settings.valueField]);if("string"!=typeof value)return callback();self.setTextboxValue(""),self.addOption(data),self.setCaret(caret),self.addItem(value),self.refreshOptions(triggerDropdown&&"single"!==self.settings.mode),callback(data)}),function(){called||(called=!0,fn.apply(this,arguments))}),output=setup.apply(this,[output,create]);return void 0!==output&&create(output),!0},refreshItems:function(){this.lastQuery=null,this.isSetup&&this.addItem(this.items),this.refreshState(),this.updateOriginalInput()},refreshState:function(){this.refreshValidityState(),this.refreshClasses()},refreshValidityState:function(){if(!this.isRequired)return!1;var invalid=!this.items.length;this.isInvalid=invalid,this.$control_input.prop("required",invalid),this.$input.prop("required",!invalid)},refreshClasses:function(){var isFull=this.isFull(),isLocked=this.isLocked;this.$wrapper.toggleClass("rtl",this.rtl),this.$control.toggleClass("focus",this.isFocused).toggleClass("disabled",this.isDisabled).toggleClass("required",this.isRequired).toggleClass("invalid",this.isInvalid).toggleClass("locked",isLocked).toggleClass("full",isFull).toggleClass("not-full",!isFull).toggleClass("input-active",this.isFocused&&!this.isInputHidden).toggleClass("dropdown-active",this.isOpen).toggleClass("has-options",!$.isEmptyObject(this.options)).toggleClass("has-items",0<this.items.length),this.$control_input.data("grow",!isFull&&!isLocked)},isFull:function(){return null!==this.settings.maxItems&&this.items.length>=this.settings.maxItems},updateOriginalInput:function(opts){var i,n,options,label;if(opts=opts||{},1===this.tagType){for(options=[],i=0,n=this.items.length;i<n;i++)label=this.options[this.items[i]][this.settings.labelField]||"",options.push('<option value="'+escape_html(this.items[i])+'" selected="selected">'+escape_html(label)+"</option>");options.length||this.$input.attr("multiple")||options.push('<option value="" selected="selected"></option>'),this.$input.html(options.join(""))}else this.$input.val(this.getValue()),this.$input.attr("value",this.$input.val());this.isSetup&&(opts.silent||this.trigger("change",this.$input.val()))},updatePlaceholder:function(){var $input;this.settings.placeholder&&($input=this.$control_input,this.items.length?$input.removeAttr("placeholder"):$input.attr("placeholder",this.settings.placeholder),$input.triggerHandler("update",{force:!0}))},open:function(){this.isLocked||this.isOpen||"multi"===this.settings.mode&&this.isFull()||(this.focus(),this.isOpen=!0,this.refreshState(),this.$dropdown.css({visibility:"hidden",display:"block"}),this.positionDropdown(),this.$dropdown.css({visibility:"visible"}),this.trigger("dropdown_open",this.$dropdown))},close:function(){var trigger=this.isOpen;"single"===this.settings.mode&&this.items.length&&(this.hideInput(),this.isBlurring&&this.$control_input.blur()),this.isOpen=!1,this.$dropdown.hide(),this.setActiveOption(null),this.refreshState(),trigger&&this.trigger("dropdown_close",this.$dropdown)},positionDropdown:function(){var $control=this.$control,offset="body"===this.settings.dropdownParent?$control.offset():$control.position();offset.top+=$control.outerHeight(!0),this.$dropdown.css({width:$control[0].getBoundingClientRect().width,top:offset.top,left:offset.left})},clear:function(silent){this.items.length&&(this.$control.children(":not(input)").remove(),this.items=[],this.lastQuery=null,this.setCaret(0),this.setActiveItem(null),this.updatePlaceholder(),this.updateOriginalInput({silent:silent}),this.refreshState(),this.showInput(),this.trigger("clear"))},insertAtCaret:function(target){var caret=Math.min(this.caretPos,this.items.length),el=target[0],target=this.buffer||this.$control[0];0===caret?target.insertBefore(el,target.firstChild):target.insertBefore(el,target.childNodes[caret]),this.setCaret(caret+1)},deleteSelection:function(e){var i,n,values,option_select,$option_select,caret,direction=e&&8===e.keyCode?-1:1,selection=getSelection(this.$control_input[0]);if(this.$activeOption&&!this.settings.hideSelected&&(option_select=this.getAdjacentOption(this.$activeOption,-1).attr("data-value")),values=[],this.$activeItems.length){for(caret=this.$control.children(".active:"+(0<direction?"last":"first")),caret=this.$control.children(":not(input)").index(caret),0<direction&&caret++,i=0,n=this.$activeItems.length;i<n;i++)values.push($(this.$activeItems[i]).attr("data-value"));e&&(e.preventDefault(),e.stopPropagation())}else(this.isFocused||"single"===this.settings.mode)&&this.items.length&&(direction<0&&0===selection.start&&0===selection.length?values.push(this.items[this.caretPos-1]):0<direction&&selection.start===this.$control_input.val().length&&values.push(this.items[this.caretPos]));if(!values.length||"function"==typeof this.settings.onDelete&&!1===this.settings.onDelete.apply(this,[values]))return!1;for(void 0!==caret&&this.setCaret(caret);values.length;)this.removeItem(values.pop());return this.showInput(),this.positionDropdown(),this.refreshOptions(!0),option_select&&($option_select=this.getOption(option_select)).length&&this.setActiveOption($option_select),!0},advanceSelection:function(direction,e){var selection,valueLength,idx;0!==direction&&(this.rtl&&(direction*=-1),idx=0<direction?"last":"first",selection=getSelection(this.$control_input[0]),this.isFocused&&!this.isInputHidden?(valueLength=this.$control_input.val().length,(direction<0?0!==selection.start||0!==selection.length:selection.start!==valueLength)||valueLength||this.advanceCaret(direction,e)):(idx=this.$control.children(".active:"+idx)).length&&(idx=this.$control.children(":not(input)").index(idx),this.setActiveItem(null),this.setCaret(0<direction?idx+1:idx)))},advanceCaret:function(direction,e){var $adj;0!==direction&&($adj=0<direction?"next":"prev",this.isShiftDown?($adj=this.$control_input[$adj]()).length&&(this.hideInput(),this.setActiveItem($adj),e&&e.preventDefault()):this.setCaret(this.caretPos+direction))},setCaret:function(i){if(i="single"===this.settings.mode?this.items.length:Math.max(0,Math.min(this.items.length,i)),!this.isPending)for(var $child,$children=this.$control.children(":not(input)"),j=0,n=$children.length;j<n;j++)$child=$($children[j]).detach(),j<i?this.$control_input.before($child):this.$control.append($child);this.caretPos=i},lock:function(){this.close(),this.isLocked=!0,this.refreshState()},unlock:function(){this.isLocked=!1,this.refreshState()},disable:function(){this.$input.prop("disabled",!0),this.$control_input.prop("disabled",!0).prop("tabindex",-1),this.isDisabled=!0,this.lock()},enable:function(){this.$input.prop("disabled",!1),this.$control_input.prop("disabled",!1).prop("tabindex",this.tabIndex),this.isDisabled=!1,this.unlock()},destroy:function(){var eventNS=this.eventNS,revertSettings=this.revertSettings;this.trigger("destroy"),this.off(),this.$wrapper.remove(),this.$dropdown.remove(),this.$input.html("").append(revertSettings.$children).removeAttr("tabindex").removeClass("selectized").attr({tabindex:revertSettings.tabindex}).show(),this.$control_input.removeData("grow"),this.$input.removeData("selectize"),0==--Selectize.count&&Selectize.$testInput&&(Selectize.$testInput.remove(),Selectize.$testInput=void 0),$(window).off(eventNS),$(document).off(eventNS),$(document.body).off(eventNS),delete this.$input[0].selectize},render:function(templateName,data){var value,id,html="",cache=!1;return(cache="option"===templateName||"item"===templateName?!!(value=hash_key(data[this.settings.valueField])):cache)&&(isset(this.renderCache[templateName])||(this.renderCache[templateName]={}),this.renderCache[templateName].hasOwnProperty(value))?this.renderCache[templateName][value]:(html=$(this.settings.render[templateName].apply(this,[data,escape_html])),"option"===templateName||"option_create"===templateName?data[this.settings.disabledField]||html.attr("data-selectable",""):"optgroup"===templateName&&(id=data[this.settings.optgroupValueField]||"",html.attr("data-group",id),data[this.settings.disabledField]&&html.attr("data-disabled","")),"option"!==templateName&&"item"!==templateName||html.attr("data-value",value||""),cache&&(this.renderCache[templateName][value]=html[0]),html[0])},clearCache:function(templateName){void 0===templateName?this.renderCache={}:delete this.renderCache[templateName]},canCreate:function(input){if(!this.settings.create)return!1;var filter=this.settings.createFilter;return input.length&&("function"!=typeof filter||filter.apply(this,[input]))&&("string"!=typeof filter||new RegExp(filter).test(input))&&(!(filter instanceof RegExp)||filter.test(input))}}),Selectize.count=0,Selectize.defaults={options:[],optgroups:[],plugins:[],delimiter:",",splitOn:null,persist:!0,diacritics:!0,create:!1,createOnBlur:!1,createFilter:null,highlight:!0,openOnFocus:!0,maxOptions:1e3,maxItems:null,hideSelected:null,addPrecedence:!1,selectOnTab:!0,preload:!1,allowEmptyOption:!1,closeAfterSelect:!1,scrollDuration:60,loadThrottle:300,loadingClass:"loading",dataAttr:"data-data",optgroupField:"optgroup",valueField:"value",labelField:"text",disabledField:"disabled",optgroupLabelField:"label",optgroupValueField:"value",lockOptgroupOrder:!1,sortField:"$order",searchField:["text"],searchConjunction:"and",mode:null,wrapperClass:"selectize-control",inputClass:"selectize-input",dropdownClass:"selectize-dropdown",dropdownContentClass:"selectize-dropdown-content",dropdownParent:null,copyClassesToDropdown:!0,render:{}},$.fn.selectize=function(settings_user){function init_select($input,settings_element){function readData(data){return"string"==typeof(data=attr_data&&data.attr(attr_data))&&data.length?JSON.parse(data):null}function addOption($option,group){$option=$($option);var option,value=hash_key($option.val());(value||settings.allowEmptyOption)&&(optionsMap.hasOwnProperty(value)?group&&((option=optionsMap[value][field_optgroup])?$.isArray(option)?option.push(group):optionsMap[value][field_optgroup]=[option,group]:optionsMap[value][field_optgroup]=group):((option=readData($option)||{})[field_label]=option[field_label]||$option.text(),option[field_value]=option[field_value]||value,option[field_disabled]=option[field_disabled]||$option.prop("disabled"),option[field_optgroup]=option[field_optgroup]||group,optionsMap[value]=option,options.push(option),$option.is(":selected")&&settings_element.items.push(value)))}var i,n,tagName,$children,options=settings_element.options,optionsMap={};for(settings_element.maxItems=$input.attr("multiple")?null:1,i=0,n=($children=$input.children()).length;i<n;i++)"optgroup"===(tagName=$children[i].tagName.toLowerCase())?function($optgroup){var i,n,id,optgroup,$options;for((id=($optgroup=$($optgroup)).attr("label"))&&((optgroup=readData($optgroup)||{})[field_optgroup_label]=id,optgroup[field_optgroup_value]=id,optgroup[field_disabled]=$optgroup.prop("disabled"),settings_element.optgroups.push(optgroup)),i=0,n=($options=$("option",$optgroup)).length;i<n;i++)addOption($options[i],id)}($children[i]):"option"===tagName&&addOption($children[i])}var defaults=$.fn.selectize.defaults,settings=$.extend({},defaults,settings_user),attr_data=settings.dataAttr,field_label=settings.labelField,field_value=settings.valueField,field_disabled=settings.disabledField,field_optgroup=settings.optgroupField,field_optgroup_label=settings.optgroupLabelField,field_optgroup_value=settings.optgroupValueField;return this.each(function(){var $input,tag_name,settings_element;this.selectize||($input=$(this),tag_name=this.tagName.toLowerCase(),settings_element={placeholder:settings_element=!(settings_element=$input.attr("placeholder")||$input.attr("data-placeholder"))&&!settings.allowEmptyOption?$input.children('option[value=""]').text():settings_element,options:[],optgroups:[],items:[]},("select"===tag_name?init_select:function(value,settings_element){var i,n,values,option,data_raw=value.attr(attr_data);if(data_raw)for(settings_element.options=JSON.parse(data_raw),i=0,n=settings_element.options.length;i<n;i++)settings_element.items.push(settings_element.options[i][field_value]);else{value=$.trim(value.val()||"");if(settings.allowEmptyOption||value.length){for(i=0,n=(values=value.split(settings.delimiter)).length;i<n;i++)(option={})[field_label]=values[i],option[field_value]=values[i],settings_element.options.push(option);settings_element.items=values}}})($input,settings_element),new Selectize($input,$.extend(!0,{},defaults,settings_element,settings_user)))})},$.fn.selectize.defaults=Selectize.defaults,$.fn.selectize.support={validity:SUPPORTS_VALIDITY_API},Selectize.define("auto_select_on_type",function(options){var originalBlur,self=this;self.onBlur=(originalBlur=self.onBlur,function(e){var $matchedItem=self.getFirstItemMatchedByTextContent(self.lastValue,!0);return void 0!==$matchedItem.attr("data-value")&&self.getValue()!==$matchedItem.attr("data-value")&&self.setValue($matchedItem.attr("data-value")),originalBlur.apply(this,arguments)})}),Selectize.define("autofill_disable",function(options){var original,self=this;self.setup=(original=self.setup,function(){original.apply(self,arguments),self.$control_input.attr({autocomplete:"new-password",autofill:"no"})})}),Selectize.define("drag_drop",function(options){if(!$.fn.sortable)throw new Error('The "drag_drop" plugin requires jQuery UI "sortable".');var self,original;"multi"===this.settings.mode&&((self=this).lock=(original=self.lock,function(){var sortable=self.$control.data("sortable");return sortable&&sortable.disable(),original.apply(self,arguments)}),self.unlock=function(){var original=self.unlock;return function(){var sortable=self.$control.data("sortable");return sortable&&sortable.enable(),original.apply(self,arguments)}}(),self.setup=function(){var original=self.setup;return function(){original.apply(this,arguments);var $control=self.$control.sortable({items:"[data-value]",forcePlaceholderSize:!0,disabled:self.isLocked,start:function(e,ui){ui.placeholder.css("width",ui.helper.css("width")),$control.css({overflow:"visible"})},stop:function(){$control.css({overflow:"hidden"});var active=self.$activeItems?self.$activeItems.slice():null,values=[];$control.children("[data-value]").each(function(){values.push($(this).attr("data-value"))}),self.setValue(values),self.setActiveItem(active)}})}}())}),Selectize.define("dropdown_header",function(options){var original,self=this;options=$.extend({title:"Untitled",headerClass:"selectize-dropdown-header",titleRowClass:"selectize-dropdown-header-title",labelClass:"selectize-dropdown-header-label",closeClass:"selectize-dropdown-header-close",html:function(data){return'<div class="'+data.headerClass+'"><div class="'+data.titleRowClass+'"><span class="'+data.labelClass+'">'+data.title+'</span><a href="javascript:void(0)" class="'+data.closeClass+'">&times;</a></div></div>'}},options),self.setup=(original=self.setup,function(){original.apply(self,arguments),self.$dropdown_header=$(options.html(options)),self.$dropdown.prepend(self.$dropdown_header)})}),Selectize.define("optgroup_columns",function(options){var original,self=this;options=$.extend({equalizeWidth:!0,equalizeHeight:!0},options),this.getAdjacentOption=function($option,index){var $options=$option.closest("[data-group]").find("[data-selectable]"),index=$options.index($option)+index;return 0<=index&&index<$options.length?$options.eq(index):$()},this.onKeyDown=(original=self.onKeyDown,function(e){var $option,$options;return!this.isOpen||37!==e.keyCode&&39!==e.keyCode?original.apply(this,arguments):(self.ignoreHover=!0,$option=($options=this.$activeOption.closest("[data-group]")).find("[data-selectable]").index(this.$activeOption),void(($option=($options=($options=37===e.keyCode?$options.prev("[data-group]"):$options.next("[data-group]")).find("[data-selectable]")).eq(Math.min($options.length-1,$option))).length&&this.setActiveOption($option)))});function equalizeSizes(){var i,height_max,width_last,width_parent,$optgroups=$("[data-group]",self.$dropdown_content),n=$optgroups.length;if(n&&self.$dropdown_content.width()){if(options.equalizeHeight){for(i=height_max=0;i<n;i++)height_max=Math.max(height_max,$optgroups.eq(i).height());$optgroups.css({height:height_max})}options.equalizeWidth&&(width_parent=self.$dropdown_content.innerWidth()-getScrollbarWidth(),width_last=Math.round(width_parent/n),$optgroups.css({width:width_last}),1<n&&(width_last=width_parent-width_last*(n-1),$optgroups.eq(n-1).css({width:width_last})))}}var getScrollbarWidth=function(){var div,width=getScrollbarWidth.width,doc=document;return void 0===width&&((div=doc.createElement("div")).innerHTML='<div style="width:50px;height:50px;position:absolute;left:-50px;top:-50px;overflow:auto;"><div style="width:1px;height:100px;"></div></div>',div=div.firstChild,doc.body.appendChild(div),width=getScrollbarWidth.width=div.offsetWidth-div.clientWidth,doc.body.removeChild(div)),width};(options.equalizeHeight||options.equalizeWidth)&&(hook.after(this,"positionDropdown",equalizeSizes),hook.after(this,"refreshOptions",equalizeSizes))}),Selectize.define("remove_button",function(options){options=$.extend({label:"&times;",title:"Remove",className:"remove",append:!0},options);("single"===this.settings.mode?function(thisRef,options){options.className="remove-single";var original,self=thisRef,html='<a href="javascript:void(0)" class="'+options.className+'" tabindex="-1" title="'+escape_html(options.title)+'">'+options.label+"</a>";thisRef.setup=(original=self.setup,function(){var id,render_item;options.append&&(id=$(self.$input.context).attr("id"),$("#"+id),render_item=self.settings.render.item,self.settings.render.item=function(data){return html_container=render_item.apply(thisRef,arguments),html_element=html,$("<span>").append(html_container).append(html_element);var html_container,html_element}),original.apply(thisRef,arguments),thisRef.$control.on("click","."+options.className,function(e){e.preventDefault(),self.isLocked||self.clear()})})}:function(thisRef,options){var original,self=thisRef,html='<a href="javascript:void(0)" class="'+options.className+'" tabindex="-1" title="'+escape_html(options.title)+'">'+options.label+"</a>";thisRef.setup=(original=self.setup,function(){var render_item;options.append&&(render_item=self.settings.render.item,self.settings.render.item=function(data){return html_container=render_item.apply(thisRef,arguments),html_element=html,pos=html_container.search(/(<\/[^>]+>\s*)$/),html_container.substring(0,pos)+html_element+html_container.substring(pos);var html_container,html_element,pos}),original.apply(thisRef,arguments),thisRef.$control.on("click","."+options.className,function($item){if($item.preventDefault(),!self.isLocked){$item=$($item.currentTarget).parent();return self.setActiveItem($item),self.deleteSelection()&&self.setCaret(self.items.length),!1}})})})(this,options)}),Selectize.define("restore_on_backspace",function(options){var original,self=this;options.text=options.text||function(option){return option[this.settings.labelField]},this.onKeyDown=(original=self.onKeyDown,function(e){var option;return 8===e.keyCode&&""===this.$control_input.val()&&!this.$activeItems.length&&0<=(option=this.caretPos-1)&&option<this.items.length?(option=this.options[this.items[option]],this.deleteSelection(e)&&(this.setTextboxValue(options.text.apply(this,[option])),this.refreshOptions(!0)),void e.preventDefault()):original.apply(this,arguments)})}),Selectize.define("select_on_focus",function(options){var originalFocus,originalBlur,self=this;self.on("focus",(originalFocus=self.onFocus,function(e){var value=self.getItem(self.getValue()).text();return self.clear(),self.setTextboxValue(value),self.$control_input.select(),setTimeout(function(){self.settings.selectOnTab&&self.setActiveOption(self.getFirstItemMatchedByTextContent(value)),self.settings.score=null},0),originalFocus.apply(this,arguments)})),self.onBlur=(originalBlur=self.onBlur,function(e){return""===self.getValue()&&self.lastValidValue!==self.getValue()&&self.setValue(self.lastValidValue),setTimeout(function(){self.settings.score=function(){return function(){return 1}}},0),originalBlur.apply(this,arguments)}),self.settings.score=function(){return function(){return 1}}}),Selectize});