activeadmin_selectize 0.1.3 → 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
- SHA1:
3
- metadata.gz: 67f51638f236de90ef8fafc38b0bbe0ed8b9597c
4
- data.tar.gz: 14f578d393f4889cf25c0ffdf096163899337d65
2
+ SHA256:
3
+ metadata.gz: 06b3852d7ee6dc49a82ee9dd2f1e9e8a92f7468e00e3a1855f45a3c2817fb08c
4
+ data.tar.gz: a580d91fe49e0c38c7846239dcadd88a205547df8dd4ffd7f3d90a54fa946fec
5
5
  SHA512:
6
- metadata.gz: 7eff3c556c2db4eee3e6e294ef0a4513656ad8ac4226193c4b694857f79a93a1f50cf7feb67a06f9c6bab468a60fdc4f8a039a885ad180cea24669d9ae1d6747
7
- data.tar.gz: 72f6eaf2a6d0c7626915ee6116df4b8c39073b2c04ffed195a082be1225954a6b48c068183f6d43b766416b249635492053ac081b10585cb02cc098c587cd49d
6
+ metadata.gz: a91f8488a1725cb376113cd9754e1035f29dfb4d310b55012a3d097220133234b843d8b6af2d26a79767ae0919e2233271d30dbdc532219d1f9ad811f51ee2c1
7
+ data.tar.gz: 5ed2c330f0150dc43fe161b944bc655496da02da53d501d7a29a2a51a4aaede5797c431a5cf876efeb0e02f9efbf6269a074b93779f3d437510cf4f1407f0882
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2014 Mark Fariburn, Praxitar Ltd
1
+ Copyright (c) 2017 Mattia Roccoberton
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -1,18 +1,17 @@
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
 
5
5
  Features:
6
- - nice select inputs
7
- - items search
8
- - AJAX content loading
9
- - improve many-to-many / one-to-many selection
6
+ - nice select inputs;
7
+ - items search;
8
+ - AJAX content loading;
9
+ - improve many-to-many / one-to-many selection.
10
10
 
11
11
  ## Install
12
12
 
13
13
  - Add to your Gemfile:
14
14
  `gem 'activeadmin_selectize'`
15
- - Add _jquery-rails_ gem or include jQuery manually
16
15
  - Execute bundle
17
16
  - Add at the end of your ActiveAdmin styles (_app/assets/stylesheets/active_admin.scss_):
18
17
  `@import 'activeadmin/selectize_input';`
@@ -25,7 +24,7 @@ Features:
25
24
 
26
25
  Why 2 separated scripts? In this way you can include a different version of Selectize.js if you like.
27
26
 
28
- ## Example
27
+ ## Examples
29
28
 
30
29
  Example 1: an Article model with a many-to-many relation with Tag model:
31
30
 
@@ -49,6 +48,39 @@ end
49
48
  end
50
49
  ```
51
50
 
51
+ Example 2: using selectize in filters:
52
+
53
+ ```ruby
54
+ # Without remote items (no AJAX):
55
+ filter :name_eq, as: :selectize, collection: Author.all.pluck( :name, :name )
56
+ # With remote items:
57
+ filter :tags_id_eq, as: :selectize, collection: [], input_html: { 'data-opt-remote': '/admin/tags.json', 'data-opt-text': 'name', 'data-opt-value': 'id', 'data-opts': '{"dropdownParent":"body"}', placeholder: 'Search a tag...' }
58
+ ```
59
+
60
+ ## Notes
61
+
62
+ - In ActiveAdmin json routes should be enabled by default, this behavior is controlled by *download_links* option for index action. Example:
63
+
64
+ ```rb
65
+ index download_links: [:csv, :json] do
66
+ # ...
67
+ end
68
+ ```
69
+
70
+ You can customize the JSON response overriding the *as_json* method of the model:
71
+
72
+ ```rb
73
+ def as_json( options = nil )
74
+ super({ only: [:id], methods: [:fullname] }.merge(options || {}))
75
+ end
76
+ ```
77
+
78
+ - If the select items "gets cut" by the container try adding: `'data-opts': '{"dropdownParent":"body"}'`
79
+
80
+ - Alternative syntax to pass data attributes: `input_html: { data: { opts: '{}' } }`
81
+
82
+ - To use this plugins with ActiveAdmin 1.x please use the version 0.1.6
83
+
52
84
  ## Options
53
85
 
54
86
  Pass the required options using `input_html`.
@@ -62,9 +94,15 @@ Alternative syntax:
62
94
 
63
95
  - **data-opts**: overrides Selectize options - example: `'data-opts': '{"highlight":true,"plugins":[]}'`
64
96
 
97
+ ## Do you like it? Star it!
98
+
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
+
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
+
65
103
  ## Contributors
66
104
 
67
- - [Mattia Roccoberton](http://blocknot.es) - creator, maintainer
105
+ - [Mattia Roccoberton](http://blocknot.es): author
68
106
 
69
107
  ## License
70
108
 
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,3829 +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.4)
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
- if (node.nodeType === 3) {
674
- var pos = node.data.search(regex);
675
- if (pos >= 0 && node.data.length > 0) {
676
- var match = node.data.match(regex);
677
- var spannode = document.createElement('span');
678
- spannode.className = 'highlight';
679
- var middlebit = node.splitText(pos);
680
- var endbit = middlebit.splitText(match[0].length);
681
- var middleclone = middlebit.cloneNode(true);
682
- spannode.appendChild(middleclone);
683
- middlebit.parentNode.replaceChild(spannode, middlebit);
684
- skip = 1;
685
- }
686
- } else if (node.nodeType === 1 && node.childNodes && !/(script|style)/i.test(node.tagName)) {
687
- for (var i = 0; i < node.childNodes.length; ++i) {
688
- i += highlight(node.childNodes[i]);
689
- }
690
- }
691
- return skip;
692
- };
693
-
694
- return $element.each(function() {
695
- highlight(this);
696
- });
697
- };
698
-
699
- /**
700
- * removeHighlight fn copied from highlight v5 and
701
- * edited to remove with() and pass js strict mode
702
- */
703
- $.fn.removeHighlight = function() {
704
- return this.find("span.highlight").each(function() {
705
- this.parentNode.firstChild.nodeName;
706
- var parent = this.parentNode;
707
- parent.replaceChild(this.firstChild, this);
708
- parent.normalize();
709
- }).end();
710
- };
711
-
712
-
713
- var MicroEvent = function() {};
714
- MicroEvent.prototype = {
715
- on: function(event, fct){
716
- this._events = this._events || {};
717
- this._events[event] = this._events[event] || [];
718
- this._events[event].push(fct);
719
- },
720
- off: function(event, fct){
721
- var n = arguments.length;
722
- if (n === 0) return delete this._events;
723
- if (n === 1) return delete this._events[event];
724
-
725
- this._events = this._events || {};
726
- if (event in this._events === false) return;
727
- this._events[event].splice(this._events[event].indexOf(fct), 1);
728
- },
729
- trigger: function(event /* , args... */){
730
- this._events = this._events || {};
731
- if (event in this._events === false) return;
732
- for (var i = 0; i < this._events[event].length; i++){
733
- this._events[event][i].apply(this, Array.prototype.slice.call(arguments, 1));
734
- }
735
- }
736
- };
737
-
738
- /**
739
- * Mixin will delegate all MicroEvent.js function in the destination object.
740
- *
741
- * - MicroEvent.mixin(Foobar) will make Foobar able to use MicroEvent
742
- *
743
- * @param {object} the object which will support MicroEvent
744
- */
745
- MicroEvent.mixin = function(destObject){
746
- var props = ['on', 'off', 'trigger'];
747
- for (var i = 0; i < props.length; i++){
748
- destObject.prototype[props[i]] = MicroEvent.prototype[props[i]];
749
- }
750
- };
751
-
752
- var IS_MAC = /Mac/.test(navigator.userAgent);
753
-
754
- var KEY_A = 65;
755
- var KEY_COMMA = 188;
756
- var KEY_RETURN = 13;
757
- var KEY_ESC = 27;
758
- var KEY_LEFT = 37;
759
- var KEY_UP = 38;
760
- var KEY_P = 80;
761
- var KEY_RIGHT = 39;
762
- var KEY_DOWN = 40;
763
- var KEY_N = 78;
764
- var KEY_BACKSPACE = 8;
765
- var KEY_DELETE = 46;
766
- var KEY_SHIFT = 16;
767
- var KEY_CMD = IS_MAC ? 91 : 17;
768
- var KEY_CTRL = IS_MAC ? 18 : 17;
769
- var KEY_TAB = 9;
770
-
771
- var TAG_SELECT = 1;
772
- var TAG_INPUT = 2;
773
-
774
- // for now, android support in general is too spotty to support validity
775
- var SUPPORTS_VALIDITY_API = !/android/i.test(window.navigator.userAgent) && !!document.createElement('input').validity;
776
-
777
-
778
- var isset = function(object) {
779
- return typeof object !== 'undefined';
780
- };
781
-
782
- /**
783
- * Converts a scalar to its best string representation
784
- * for hash keys and HTML attribute values.
785
- *
786
- * Transformations:
787
- * 'str' -> 'str'
788
- * null -> ''
789
- * undefined -> ''
790
- * true -> '1'
791
- * false -> '0'
792
- * 0 -> '0'
793
- * 1 -> '1'
794
- *
795
- * @param {string} value
796
- * @returns {string|null}
797
- */
798
- var hash_key = function(value) {
799
- if (typeof value === 'undefined' || value === null) return null;
800
- if (typeof value === 'boolean') return value ? '1' : '0';
801
- return value + '';
802
- };
803
-
804
- /**
805
- * Escapes a string for use within HTML.
806
- *
807
- * @param {string} str
808
- * @returns {string}
809
- */
810
- var escape_html = function(str) {
811
- return (str + '')
812
- .replace(/&/g, '&amp;')
813
- .replace(/</g, '&lt;')
814
- .replace(/>/g, '&gt;')
815
- .replace(/"/g, '&quot;');
816
- };
817
-
818
- /**
819
- * Escapes "$" characters in replacement strings.
820
- *
821
- * @param {string} str
822
- * @returns {string}
823
- */
824
- var escape_replace = function(str) {
825
- return (str + '').replace(/\$/g, '$$$$');
826
- };
827
-
828
- var hook = {};
829
-
830
- /**
831
- * Wraps `method` on `self` so that `fn`
832
- * is invoked before the original method.
833
- *
834
- * @param {object} self
835
- * @param {string} method
836
- * @param {function} fn
837
- */
838
- hook.before = function(self, method, fn) {
839
- var original = self[method];
840
- self[method] = function() {
841
- fn.apply(self, arguments);
842
- return original.apply(self, arguments);
843
- };
844
- };
845
-
846
- /**
847
- * Wraps `method` on `self` so that `fn`
848
- * is invoked after the original method.
849
- *
850
- * @param {object} self
851
- * @param {string} method
852
- * @param {function} fn
853
- */
854
- hook.after = function(self, method, fn) {
855
- var original = self[method];
856
- self[method] = function() {
857
- var result = original.apply(self, arguments);
858
- fn.apply(self, arguments);
859
- return result;
860
- };
861
- };
862
-
863
- /**
864
- * Wraps `fn` so that it can only be invoked once.
865
- *
866
- * @param {function} fn
867
- * @returns {function}
868
- */
869
- var once = function(fn) {
870
- var called = false;
871
- return function() {
872
- if (called) return;
873
- called = true;
874
- fn.apply(this, arguments);
875
- };
876
- };
877
-
878
- /**
879
- * Wraps `fn` so that it can only be called once
880
- * every `delay` milliseconds (invoked on the falling edge).
881
- *
882
- * @param {function} fn
883
- * @param {int} delay
884
- * @returns {function}
885
- */
886
- var debounce = function(fn, delay) {
887
- var timeout;
888
- return function() {
889
- var self = this;
890
- var args = arguments;
891
- window.clearTimeout(timeout);
892
- timeout = window.setTimeout(function() {
893
- fn.apply(self, args);
894
- }, delay);
895
- };
896
- };
897
-
898
- /**
899
- * Debounce all fired events types listed in `types`
900
- * while executing the provided `fn`.
901
- *
902
- * @param {object} self
903
- * @param {array} types
904
- * @param {function} fn
905
- */
906
- var debounce_events = function(self, types, fn) {
907
- var type;
908
- var trigger = self.trigger;
909
- var event_args = {};
910
-
911
- // override trigger method
912
- self.trigger = function() {
913
- var type = arguments[0];
914
- if (types.indexOf(type) !== -1) {
915
- event_args[type] = arguments;
916
- } else {
917
- return trigger.apply(self, arguments);
918
- }
919
- };
920
-
921
- // invoke provided function
922
- fn.apply(self, []);
923
- self.trigger = trigger;
924
-
925
- // trigger queued events
926
- for (type in event_args) {
927
- if (event_args.hasOwnProperty(type)) {
928
- trigger.apply(self, event_args[type]);
929
- }
930
- }
931
- };
932
-
933
- /**
934
- * A workaround for http://bugs.jquery.com/ticket/6696
935
- *
936
- * @param {object} $parent - Parent element to listen on.
937
- * @param {string} event - Event name.
938
- * @param {string} selector - Descendant selector to filter by.
939
- * @param {function} fn - Event handler.
940
- */
941
- var watchChildEvent = function($parent, event, selector, fn) {
942
- $parent.on(event, selector, function(e) {
943
- var child = e.target;
944
- while (child && child.parentNode !== $parent[0]) {
945
- child = child.parentNode;
946
- }
947
- e.currentTarget = child;
948
- return fn.apply(this, [e]);
949
- });
950
- };
951
-
952
- /**
953
- * Determines the current selection within a text input control.
954
- * Returns an object containing:
955
- * - start
956
- * - length
957
- *
958
- * @param {object} input
959
- * @returns {object}
960
- */
961
- var getSelection = function(input) {
962
- var result = {};
963
- if ('selectionStart' in input) {
964
- result.start = input.selectionStart;
965
- result.length = input.selectionEnd - result.start;
966
- } else if (document.selection) {
967
- input.focus();
968
- var sel = document.selection.createRange();
969
- var selLen = document.selection.createRange().text.length;
970
- sel.moveStart('character', -input.value.length);
971
- result.start = sel.text.length - selLen;
972
- result.length = selLen;
973
- }
974
- return result;
975
- };
976
-
977
- /**
978
- * Copies CSS properties from one element to another.
979
- *
980
- * @param {object} $from
981
- * @param {object} $to
982
- * @param {array} properties
983
- */
984
- var transferStyles = function($from, $to, properties) {
985
- var i, n, styles = {};
986
- if (properties) {
987
- for (i = 0, n = properties.length; i < n; i++) {
988
- styles[properties[i]] = $from.css(properties[i]);
989
- }
990
- } else {
991
- styles = $from.css();
992
- }
993
- $to.css(styles);
994
- };
995
-
996
- /**
997
- * Measures the width of a string within a
998
- * parent element (in pixels).
999
- *
1000
- * @param {string} str
1001
- * @param {object} $parent
1002
- * @returns {int}
1003
- */
1004
- var measureString = function(str, $parent) {
1005
- if (!str) {
1006
- return 0;
1007
- }
1008
-
1009
- var $test = $('<test>').css({
1010
- position: 'absolute',
1011
- top: -99999,
1012
- left: -99999,
1013
- width: 'auto',
1014
- padding: 0,
1015
- whiteSpace: 'pre'
1016
- }).text(str).appendTo('body');
1017
-
1018
- transferStyles($parent, $test, [
1019
- 'letterSpacing',
1020
- 'fontSize',
1021
- 'fontFamily',
1022
- 'fontWeight',
1023
- 'textTransform'
1024
- ]);
1025
-
1026
- var width = $test.width();
1027
- $test.remove();
1028
-
1029
- return width;
1030
- };
1031
-
1032
- /**
1033
- * Sets up an input to grow horizontally as the user
1034
- * types. If the value is changed manually, you can
1035
- * trigger the "update" handler to resize:
1036
- *
1037
- * $input.trigger('update');
1038
- *
1039
- * @param {object} $input
1040
- */
1041
- var autoGrow = function($input) {
1042
- var currentWidth = null;
1043
-
1044
- var update = function(e, options) {
1045
- var value, keyCode, printable, placeholder, width;
1046
- var shift, character, selection;
1047
- e = e || window.event || {};
1048
- options = options || {};
1049
-
1050
- if (e.metaKey || e.altKey) return;
1051
- if (!options.force && $input.data('grow') === false) return;
1052
-
1053
- value = $input.val();
1054
- if (e.type && e.type.toLowerCase() === 'keydown') {
1055
- keyCode = e.keyCode;
1056
- printable = (
1057
- (keyCode >= 97 && keyCode <= 122) || // a-z
1058
- (keyCode >= 65 && keyCode <= 90) || // A-Z
1059
- (keyCode >= 48 && keyCode <= 57) || // 0-9
1060
- keyCode === 32 // space
1061
- );
1062
-
1063
- if (keyCode === KEY_DELETE || keyCode === KEY_BACKSPACE) {
1064
- selection = getSelection($input[0]);
1065
- if (selection.length) {
1066
- value = value.substring(0, selection.start) + value.substring(selection.start + selection.length);
1067
- } else if (keyCode === KEY_BACKSPACE && selection.start) {
1068
- value = value.substring(0, selection.start - 1) + value.substring(selection.start + 1);
1069
- } else if (keyCode === KEY_DELETE && typeof selection.start !== 'undefined') {
1070
- value = value.substring(0, selection.start) + value.substring(selection.start + 1);
1071
- }
1072
- } else if (printable) {
1073
- shift = e.shiftKey;
1074
- character = String.fromCharCode(e.keyCode);
1075
- if (shift) character = character.toUpperCase();
1076
- else character = character.toLowerCase();
1077
- value += character;
1078
- }
1079
- }
1080
-
1081
- placeholder = $input.attr('placeholder');
1082
- if (!value && placeholder) {
1083
- value = placeholder;
1084
- }
1085
-
1086
- width = measureString(value, $input) + 4;
1087
- if (width !== currentWidth) {
1088
- currentWidth = width;
1089
- $input.width(width);
1090
- $input.triggerHandler('resize');
1091
- }
1092
- };
1093
-
1094
- $input.on('keydown keyup update blur', update);
1095
- update();
1096
- };
1097
-
1098
- var domToString = function(d) {
1099
- var tmp = document.createElement('div');
1100
-
1101
- tmp.appendChild(d.cloneNode(true));
1102
-
1103
- return tmp.innerHTML;
1104
- };
1105
-
1106
- var logError = function(message, options){
1107
- if(!options) options = {};
1108
- var component = "Selectize";
1109
-
1110
- console.error(component + ": " + message)
1111
-
1112
- if(options.explanation){
1113
- // console.group is undefined in <IE11
1114
- if(console.group) console.group();
1115
- console.error(options.explanation);
1116
- if(console.group) console.groupEnd();
1117
- }
1118
- }
1119
-
1120
-
1121
- var Selectize = function($input, settings) {
1122
- var key, i, n, dir, input, self = this;
1123
- input = $input[0];
1124
- input.selectize = self;
1125
-
1126
- // detect rtl environment
1127
- var computedStyle = window.getComputedStyle && window.getComputedStyle(input, null);
1128
- dir = computedStyle ? computedStyle.getPropertyValue('direction') : input.currentStyle && input.currentStyle.direction;
1129
- dir = dir || $input.parents('[dir]:first').attr('dir') || '';
1130
-
1131
- // setup default state
1132
- $.extend(self, {
1133
- order : 0,
1134
- settings : settings,
1135
- $input : $input,
1136
- tabIndex : $input.attr('tabindex') || '',
1137
- tagType : input.tagName.toLowerCase() === 'select' ? TAG_SELECT : TAG_INPUT,
1138
- rtl : /rtl/i.test(dir),
1139
-
1140
- eventNS : '.selectize' + (++Selectize.count),
1141
- highlightedValue : null,
1142
- isOpen : false,
1143
- isDisabled : false,
1144
- isRequired : $input.is('[required]'),
1145
- isInvalid : false,
1146
- isLocked : false,
1147
- isFocused : false,
1148
- isInputHidden : false,
1149
- isSetup : false,
1150
- isShiftDown : false,
1151
- isCmdDown : false,
1152
- isCtrlDown : false,
1153
- ignoreFocus : false,
1154
- ignoreBlur : false,
1155
- ignoreHover : false,
1156
- hasOptions : false,
1157
- currentResults : null,
1158
- lastValue : '',
1159
- caretPos : 0,
1160
- loading : 0,
1161
- loadedSearches : {},
1162
-
1163
- $activeOption : null,
1164
- $activeItems : [],
1165
-
1166
- optgroups : {},
1167
- options : {},
1168
- userOptions : {},
1169
- items : [],
1170
- renderCache : {},
1171
- onSearchChange : settings.loadThrottle === null ? self.onSearchChange : debounce(self.onSearchChange, settings.loadThrottle)
1172
- });
1173
-
1174
- // search system
1175
- self.sifter = new Sifter(this.options, {diacritics: settings.diacritics});
1176
-
1177
- // build options table
1178
- if (self.settings.options) {
1179
- for (i = 0, n = self.settings.options.length; i < n; i++) {
1180
- self.registerOption(self.settings.options[i]);
1181
- }
1182
- delete self.settings.options;
1183
- }
1184
-
1185
- // build optgroup table
1186
- if (self.settings.optgroups) {
1187
- for (i = 0, n = self.settings.optgroups.length; i < n; i++) {
1188
- self.registerOptionGroup(self.settings.optgroups[i]);
1189
- }
1190
- delete self.settings.optgroups;
1191
- }
1192
-
1193
- // option-dependent defaults
1194
- self.settings.mode = self.settings.mode || (self.settings.maxItems === 1 ? 'single' : 'multi');
1195
- if (typeof self.settings.hideSelected !== 'boolean') {
1196
- self.settings.hideSelected = self.settings.mode === 'multi';
1197
- }
1198
-
1199
- self.initializePlugins(self.settings.plugins);
1200
- self.setupCallbacks();
1201
- self.setupTemplates();
1202
- self.setup();
1203
- };
1204
-
1205
- // mixins
1206
- // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1207
-
1208
- MicroEvent.mixin(Selectize);
1209
-
1210
- if(typeof MicroPlugin !== "undefined"){
1211
- MicroPlugin.mixin(Selectize);
1212
- }else{
1213
- logError("Dependency MicroPlugin is missing",
1214
- {explanation:
1215
- "Make sure you either: (1) are using the \"standalone\" "+
1216
- "version of Selectize, or (2) require MicroPlugin before you "+
1217
- "load Selectize."}
1218
- );
1219
- }
1220
-
1221
-
1222
- // methods
1223
- // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1224
-
1225
- $.extend(Selectize.prototype, {
1226
-
1227
- /**
1228
- * Creates all elements and sets up event bindings.
1229
- */
1230
- setup: function() {
1231
- var self = this;
1232
- var settings = self.settings;
1233
- var eventNS = self.eventNS;
1234
- var $window = $(window);
1235
- var $document = $(document);
1236
- var $input = self.$input;
1237
-
1238
- var $wrapper;
1239
- var $control;
1240
- var $control_input;
1241
- var $dropdown;
1242
- var $dropdown_content;
1243
- var $dropdown_parent;
1244
- var inputMode;
1245
- var timeout_blur;
1246
- var timeout_focus;
1247
- var classes;
1248
- var classes_plugins;
1249
- var inputId;
1250
-
1251
- inputMode = self.settings.mode;
1252
- classes = $input.attr('class') || '';
1253
-
1254
- $wrapper = $('<div>').addClass(settings.wrapperClass).addClass(classes).addClass(inputMode);
1255
- $control = $('<div>').addClass(settings.inputClass).addClass('items').appendTo($wrapper);
1256
- $control_input = $('<input type="text" autocomplete="off" />').appendTo($control).attr('tabindex', $input.is(':disabled') ? '-1' : self.tabIndex);
1257
- $dropdown_parent = $(settings.dropdownParent || $wrapper);
1258
- $dropdown = $('<div>').addClass(settings.dropdownClass).addClass(inputMode).hide().appendTo($dropdown_parent);
1259
- $dropdown_content = $('<div>').addClass(settings.dropdownContentClass).appendTo($dropdown);
1260
-
1261
- if(inputId = $input.attr('id')) {
1262
- $control_input.attr('id', inputId + '-selectized');
1263
- $("label[for='"+inputId+"']").attr('for', inputId + '-selectized');
1264
- }
1265
-
1266
- if(self.settings.copyClassesToDropdown) {
1267
- $dropdown.addClass(classes);
1268
- }
1269
-
1270
- $wrapper.css({
1271
- width: $input[0].style.width
1272
- });
1273
-
1274
- if (self.plugins.names.length) {
1275
- classes_plugins = 'plugin-' + self.plugins.names.join(' plugin-');
1276
- $wrapper.addClass(classes_plugins);
1277
- $dropdown.addClass(classes_plugins);
1278
- }
1279
-
1280
- if ((settings.maxItems === null || settings.maxItems > 1) && self.tagType === TAG_SELECT) {
1281
- $input.attr('multiple', 'multiple');
1282
- }
1283
-
1284
- if (self.settings.placeholder) {
1285
- $control_input.attr('placeholder', settings.placeholder);
1286
- }
1287
-
1288
- // if splitOn was not passed in, construct it from the delimiter to allow pasting universally
1289
- if (!self.settings.splitOn && self.settings.delimiter) {
1290
- var delimiterEscaped = self.settings.delimiter.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
1291
- self.settings.splitOn = new RegExp('\\s*' + delimiterEscaped + '+\\s*');
1292
- }
1293
-
1294
- if ($input.attr('autocorrect')) {
1295
- $control_input.attr('autocorrect', $input.attr('autocorrect'));
1296
- }
1297
-
1298
- if ($input.attr('autocapitalize')) {
1299
- $control_input.attr('autocapitalize', $input.attr('autocapitalize'));
1300
- }
1301
-
1302
- self.$wrapper = $wrapper;
1303
- self.$control = $control;
1304
- self.$control_input = $control_input;
1305
- self.$dropdown = $dropdown;
1306
- self.$dropdown_content = $dropdown_content;
1307
-
1308
- $dropdown.on('mouseenter', '[data-selectable]', function() { return self.onOptionHover.apply(self, arguments); });
1309
- $dropdown.on('mousedown click', '[data-selectable]', function() { return self.onOptionSelect.apply(self, arguments); });
1310
- watchChildEvent($control, 'mousedown', '*:not(input)', function() { return self.onItemSelect.apply(self, arguments); });
1311
- autoGrow($control_input);
1312
-
1313
- $control.on({
1314
- mousedown : function() { return self.onMouseDown.apply(self, arguments); },
1315
- click : function() { return self.onClick.apply(self, arguments); }
1316
- });
1317
-
1318
- $control_input.on({
1319
- mousedown : function(e) { e.stopPropagation(); },
1320
- keydown : function() { return self.onKeyDown.apply(self, arguments); },
1321
- keyup : function() { return self.onKeyUp.apply(self, arguments); },
1322
- keypress : function() { return self.onKeyPress.apply(self, arguments); },
1323
- resize : function() { self.positionDropdown.apply(self, []); },
1324
- blur : function() { return self.onBlur.apply(self, arguments); },
1325
- focus : function() { self.ignoreBlur = false; return self.onFocus.apply(self, arguments); },
1326
- paste : function() { return self.onPaste.apply(self, arguments); }
1327
- });
1328
-
1329
- $document.on('keydown' + eventNS, function(e) {
1330
- self.isCmdDown = e[IS_MAC ? 'metaKey' : 'ctrlKey'];
1331
- self.isCtrlDown = e[IS_MAC ? 'altKey' : 'ctrlKey'];
1332
- self.isShiftDown = e.shiftKey;
1333
- });
1334
-
1335
- $document.on('keyup' + eventNS, function(e) {
1336
- if (e.keyCode === KEY_CTRL) self.isCtrlDown = false;
1337
- if (e.keyCode === KEY_SHIFT) self.isShiftDown = false;
1338
- if (e.keyCode === KEY_CMD) self.isCmdDown = false;
1339
- });
1340
-
1341
- $document.on('mousedown' + eventNS, function(e) {
1342
- if (self.isFocused) {
1343
- // prevent events on the dropdown scrollbar from causing the control to blur
1344
- if (e.target === self.$dropdown[0] || e.target.parentNode === self.$dropdown[0]) {
1345
- return false;
1346
- }
1347
- // blur on click outside
1348
- if (!self.$control.has(e.target).length && e.target !== self.$control[0]) {
1349
- self.blur(e.target);
1350
- }
1351
- }
1352
- });
1353
-
1354
- $window.on(['scroll' + eventNS, 'resize' + eventNS].join(' '), function() {
1355
- if (self.isOpen) {
1356
- self.positionDropdown.apply(self, arguments);
1357
- }
1358
- });
1359
- $window.on('mousemove' + eventNS, function() {
1360
- self.ignoreHover = false;
1361
- });
1362
-
1363
- // store original children and tab index so that they can be
1364
- // restored when the destroy() method is called.
1365
- this.revertSettings = {
1366
- $children : $input.children().detach(),
1367
- tabindex : $input.attr('tabindex')
1368
- };
1369
-
1370
- $input.attr('tabindex', -1).hide().after(self.$wrapper);
1371
-
1372
- if ($.isArray(settings.items)) {
1373
- self.setValue(settings.items);
1374
- delete settings.items;
1375
- }
1376
-
1377
- // feature detect for the validation API
1378
- if (SUPPORTS_VALIDITY_API) {
1379
- $input.on('invalid' + eventNS, function(e) {
1380
- e.preventDefault();
1381
- self.isInvalid = true;
1382
- self.refreshState();
1383
- });
1384
- }
1385
-
1386
- self.updateOriginalInput();
1387
- self.refreshItems();
1388
- self.refreshState();
1389
- self.updatePlaceholder();
1390
- self.isSetup = true;
1391
-
1392
- if ($input.is(':disabled')) {
1393
- self.disable();
1394
- }
1395
-
1396
- self.on('change', this.onChange);
1397
-
1398
- $input.data('selectize', self);
1399
- $input.addClass('selectized');
1400
- self.trigger('initialize');
1401
-
1402
- // preload options
1403
- if (settings.preload === true) {
1404
- self.onSearchChange('');
1405
- }
1406
-
1407
- },
1408
-
1409
- /**
1410
- * Sets up default rendering functions.
1411
- */
1412
- setupTemplates: function() {
1413
- var self = this;
1414
- var field_label = self.settings.labelField;
1415
- var field_optgroup = self.settings.optgroupLabelField;
1416
-
1417
- var templates = {
1418
- 'optgroup': function(data) {
1419
- return '<div class="optgroup">' + data.html + '</div>';
1420
- },
1421
- 'optgroup_header': function(data, escape) {
1422
- return '<div class="optgroup-header">' + escape(data[field_optgroup]) + '</div>';
1423
- },
1424
- 'option': function(data, escape) {
1425
- return '<div class="option">' + escape(data[field_label]) + '</div>';
1426
- },
1427
- 'item': function(data, escape) {
1428
- return '<div class="item">' + escape(data[field_label]) + '</div>';
1429
- },
1430
- 'option_create': function(data, escape) {
1431
- return '<div class="create">Add <strong>' + escape(data.input) + '</strong>&hellip;</div>';
1432
- }
1433
- };
1434
-
1435
- self.settings.render = $.extend({}, templates, self.settings.render);
1436
- },
1437
-
1438
- /**
1439
- * Maps fired events to callbacks provided
1440
- * in the settings used when creating the control.
1441
- */
1442
- setupCallbacks: function() {
1443
- var key, fn, callbacks = {
1444
- 'initialize' : 'onInitialize',
1445
- 'change' : 'onChange',
1446
- 'item_add' : 'onItemAdd',
1447
- 'item_remove' : 'onItemRemove',
1448
- 'clear' : 'onClear',
1449
- 'option_add' : 'onOptionAdd',
1450
- 'option_remove' : 'onOptionRemove',
1451
- 'option_clear' : 'onOptionClear',
1452
- 'optgroup_add' : 'onOptionGroupAdd',
1453
- 'optgroup_remove' : 'onOptionGroupRemove',
1454
- 'optgroup_clear' : 'onOptionGroupClear',
1455
- 'dropdown_open' : 'onDropdownOpen',
1456
- 'dropdown_close' : 'onDropdownClose',
1457
- 'type' : 'onType',
1458
- 'load' : 'onLoad',
1459
- 'focus' : 'onFocus',
1460
- 'blur' : 'onBlur'
1461
- };
1462
-
1463
- for (key in callbacks) {
1464
- if (callbacks.hasOwnProperty(key)) {
1465
- fn = this.settings[callbacks[key]];
1466
- if (fn) this.on(key, fn);
1467
- }
1468
- }
1469
- },
1470
-
1471
- /**
1472
- * Triggered when the main control element
1473
- * has a click event.
1474
- *
1475
- * @param {object} e
1476
- * @return {boolean}
1477
- */
1478
- onClick: function(e) {
1479
- var self = this;
1480
-
1481
- // necessary for mobile webkit devices (manual focus triggering
1482
- // is ignored unless invoked within a click event)
1483
- if (!self.isFocused) {
1484
- self.focus();
1485
- e.preventDefault();
1486
- }
1487
- },
1488
-
1489
- /**
1490
- * Triggered when the main control element
1491
- * has a mouse down event.
1492
- *
1493
- * @param {object} e
1494
- * @return {boolean}
1495
- */
1496
- onMouseDown: function(e) {
1497
- var self = this;
1498
- var defaultPrevented = e.isDefaultPrevented();
1499
- var $target = $(e.target);
1500
-
1501
- if (self.isFocused) {
1502
- // retain focus by preventing native handling. if the
1503
- // event target is the input it should not be modified.
1504
- // otherwise, text selection within the input won't work.
1505
- if (e.target !== self.$control_input[0]) {
1506
- if (self.settings.mode === 'single') {
1507
- // toggle dropdown
1508
- self.isOpen ? self.close() : self.open();
1509
- } else if (!defaultPrevented) {
1510
- self.setActiveItem(null);
1511
- }
1512
- return false;
1513
- }
1514
- } else {
1515
- // give control focus
1516
- if (!defaultPrevented) {
1517
- window.setTimeout(function() {
1518
- self.focus();
1519
- }, 0);
1520
- }
1521
- }
1522
- },
1523
-
1524
- /**
1525
- * Triggered when the value of the control has been changed.
1526
- * This should propagate the event to the original DOM
1527
- * input / select element.
1528
- */
1529
- onChange: function() {
1530
- this.$input.trigger('change');
1531
- },
1532
-
1533
- /**
1534
- * Triggered on <input> paste.
1535
- *
1536
- * @param {object} e
1537
- * @returns {boolean}
1538
- */
1539
- onPaste: function(e) {
1540
- var self = this;
1541
-
1542
- if (self.isFull() || self.isInputHidden || self.isLocked) {
1543
- e.preventDefault();
1544
- return;
1545
- }
1546
-
1547
- // If a regex or string is included, this will split the pasted
1548
- // input and create Items for each separate value
1549
- if (self.settings.splitOn) {
1550
-
1551
- // Wait for pasted text to be recognized in value
1552
- setTimeout(function() {
1553
- var pastedText = self.$control_input.val();
1554
- if(!pastedText.match(self.settings.splitOn)){ return }
1555
-
1556
- var splitInput = $.trim(pastedText).split(self.settings.splitOn);
1557
- for (var i = 0, n = splitInput.length; i < n; i++) {
1558
- self.createItem(splitInput[i]);
1559
- }
1560
- }, 0);
1561
- }
1562
- },
1563
-
1564
- /**
1565
- * Triggered on <input> keypress.
1566
- *
1567
- * @param {object} e
1568
- * @returns {boolean}
1569
- */
1570
- onKeyPress: function(e) {
1571
- if (this.isLocked) return e && e.preventDefault();
1572
- var character = String.fromCharCode(e.keyCode || e.which);
1573
- if (this.settings.create && this.settings.mode === 'multi' && character === this.settings.delimiter) {
1574
- this.createItem();
1575
- e.preventDefault();
1576
- return false;
1577
- }
1578
- },
1579
-
1580
- /**
1581
- * Triggered on <input> keydown.
1582
- *
1583
- * @param {object} e
1584
- * @returns {boolean}
1585
- */
1586
- onKeyDown: function(e) {
1587
- var isInput = e.target === this.$control_input[0];
1588
- var self = this;
1589
-
1590
- if (self.isLocked) {
1591
- if (e.keyCode !== KEY_TAB) {
1592
- e.preventDefault();
1593
- }
1594
- return;
1595
- }
1596
-
1597
- switch (e.keyCode) {
1598
- case KEY_A:
1599
- if (self.isCmdDown) {
1600
- self.selectAll();
1601
- return;
1602
- }
1603
- break;
1604
- case KEY_ESC:
1605
- if (self.isOpen) {
1606
- e.preventDefault();
1607
- e.stopPropagation();
1608
- self.close();
1609
- }
1610
- return;
1611
- case KEY_N:
1612
- if (!e.ctrlKey || e.altKey) break;
1613
- case KEY_DOWN:
1614
- if (!self.isOpen && self.hasOptions) {
1615
- self.open();
1616
- } else if (self.$activeOption) {
1617
- self.ignoreHover = true;
1618
- var $next = self.getAdjacentOption(self.$activeOption, 1);
1619
- if ($next.length) self.setActiveOption($next, true, true);
1620
- }
1621
- e.preventDefault();
1622
- return;
1623
- case KEY_P:
1624
- if (!e.ctrlKey || e.altKey) break;
1625
- case KEY_UP:
1626
- if (self.$activeOption) {
1627
- self.ignoreHover = true;
1628
- var $prev = self.getAdjacentOption(self.$activeOption, -1);
1629
- if ($prev.length) self.setActiveOption($prev, true, true);
1630
- }
1631
- e.preventDefault();
1632
- return;
1633
- case KEY_RETURN:
1634
- if (self.isOpen && self.$activeOption) {
1635
- self.onOptionSelect({currentTarget: self.$activeOption});
1636
- e.preventDefault();
1637
- }
1638
- return;
1639
- case KEY_LEFT:
1640
- self.advanceSelection(-1, e);
1641
- return;
1642
- case KEY_RIGHT:
1643
- self.advanceSelection(1, e);
1644
- return;
1645
- case KEY_TAB:
1646
- if (self.settings.selectOnTab && self.isOpen && self.$activeOption) {
1647
- self.onOptionSelect({currentTarget: self.$activeOption});
1648
-
1649
- // Default behaviour is to jump to the next field, we only want this
1650
- // if the current field doesn't accept any more entries
1651
- if (!self.isFull()) {
1652
- e.preventDefault();
1653
- }
1654
- }
1655
- if (self.settings.create && self.createItem()) {
1656
- e.preventDefault();
1657
- }
1658
- return;
1659
- case KEY_BACKSPACE:
1660
- case KEY_DELETE:
1661
- self.deleteSelection(e);
1662
- return;
1663
- }
1664
-
1665
- if ((self.isFull() || self.isInputHidden) && !(IS_MAC ? e.metaKey : e.ctrlKey)) {
1666
- e.preventDefault();
1667
- return;
1668
- }
1669
- },
1670
-
1671
- /**
1672
- * Triggered on <input> keyup.
1673
- *
1674
- * @param {object} e
1675
- * @returns {boolean}
1676
- */
1677
- onKeyUp: function(e) {
1678
- var self = this;
1679
-
1680
- if (self.isLocked) return e && e.preventDefault();
1681
- var value = self.$control_input.val() || '';
1682
- if (self.lastValue !== value) {
1683
- self.lastValue = value;
1684
- self.onSearchChange(value);
1685
- self.refreshOptions();
1686
- self.trigger('type', value);
1687
- }
1688
- },
1689
-
1690
- /**
1691
- * Invokes the user-provide option provider / loader.
1692
- *
1693
- * Note: this function is debounced in the Selectize
1694
- * constructor (by `settings.loadThrottle` milliseconds)
1695
- *
1696
- * @param {string} value
1697
- */
1698
- onSearchChange: function(value) {
1699
- var self = this;
1700
- var fn = self.settings.load;
1701
- if (!fn) return;
1702
- if (self.loadedSearches.hasOwnProperty(value)) return;
1703
- self.loadedSearches[value] = true;
1704
- self.load(function(callback) {
1705
- fn.apply(self, [value, callback]);
1706
- });
1707
- },
1708
-
1709
- /**
1710
- * Triggered on <input> focus.
1711
- *
1712
- * @param {object} e (optional)
1713
- * @returns {boolean}
1714
- */
1715
- onFocus: function(e) {
1716
- var self = this;
1717
- var wasFocused = self.isFocused;
1718
-
1719
- if (self.isDisabled) {
1720
- self.blur();
1721
- e && e.preventDefault();
1722
- return false;
1723
- }
1724
-
1725
- if (self.ignoreFocus) return;
1726
- self.isFocused = true;
1727
- if (self.settings.preload === 'focus') self.onSearchChange('');
1728
-
1729
- if (!wasFocused) self.trigger('focus');
1730
-
1731
- if (!self.$activeItems.length) {
1732
- self.showInput();
1733
- self.setActiveItem(null);
1734
- self.refreshOptions(!!self.settings.openOnFocus);
1735
- }
1736
-
1737
- self.refreshState();
1738
- },
1739
-
1740
- /**
1741
- * Triggered on <input> blur.
1742
- *
1743
- * @param {object} e
1744
- * @param {Element} dest
1745
- */
1746
- onBlur: function(e, dest) {
1747
- var self = this;
1748
- if (!self.isFocused) return;
1749
- self.isFocused = false;
1750
-
1751
- if (self.ignoreFocus) {
1752
- return;
1753
- } else if (!self.ignoreBlur && document.activeElement === self.$dropdown_content[0]) {
1754
- // necessary to prevent IE closing the dropdown when the scrollbar is clicked
1755
- self.ignoreBlur = true;
1756
- self.onFocus(e);
1757
- return;
1758
- }
1759
-
1760
- var deactivate = function() {
1761
- self.close();
1762
- self.setTextboxValue('');
1763
- self.setActiveItem(null);
1764
- self.setActiveOption(null);
1765
- self.setCaret(self.items.length);
1766
- self.refreshState();
1767
-
1768
- // IE11 bug: element still marked as active
1769
- dest && dest.focus && dest.focus();
1770
-
1771
- self.ignoreFocus = false;
1772
- self.trigger('blur');
1773
- };
1774
-
1775
- self.ignoreFocus = true;
1776
- if (self.settings.create && self.settings.createOnBlur) {
1777
- self.createItem(null, false, deactivate);
1778
- } else {
1779
- deactivate();
1780
- }
1781
- },
1782
-
1783
- /**
1784
- * Triggered when the user rolls over
1785
- * an option in the autocomplete dropdown menu.
1786
- *
1787
- * @param {object} e
1788
- * @returns {boolean}
1789
- */
1790
- onOptionHover: function(e) {
1791
- if (this.ignoreHover) return;
1792
- this.setActiveOption(e.currentTarget, false);
1793
- },
1794
-
1795
- /**
1796
- * Triggered when the user clicks on an option
1797
- * in the autocomplete dropdown menu.
1798
- *
1799
- * @param {object} e
1800
- * @returns {boolean}
1801
- */
1802
- onOptionSelect: function(e) {
1803
- var value, $target, $option, self = this;
1804
-
1805
- if (e.preventDefault) {
1806
- e.preventDefault();
1807
- e.stopPropagation();
1808
- }
1809
-
1810
- $target = $(e.currentTarget);
1811
- if ($target.hasClass('create')) {
1812
- self.createItem(null, function() {
1813
- if (self.settings.closeAfterSelect) {
1814
- self.close();
1815
- }
1816
- });
1817
- } else {
1818
- value = $target.attr('data-value');
1819
- if (typeof value !== 'undefined') {
1820
- self.lastQuery = null;
1821
- self.setTextboxValue('');
1822
- self.addItem(value);
1823
- if (self.settings.closeAfterSelect) {
1824
- self.close();
1825
- } else if (!self.settings.hideSelected && e.type && /mouse/.test(e.type)) {
1826
- self.setActiveOption(self.getOption(value));
1827
- }
1828
- }
1829
- }
1830
- },
1831
-
1832
- /**
1833
- * Triggered when the user clicks on an item
1834
- * that has been selected.
1835
- *
1836
- * @param {object} e
1837
- * @returns {boolean}
1838
- */
1839
- onItemSelect: function(e) {
1840
- var self = this;
1841
-
1842
- if (self.isLocked) return;
1843
- if (self.settings.mode === 'multi') {
1844
- e.preventDefault();
1845
- self.setActiveItem(e.currentTarget, e);
1846
- }
1847
- },
1848
-
1849
- /**
1850
- * Invokes the provided method that provides
1851
- * results to a callback---which are then added
1852
- * as options to the control.
1853
- *
1854
- * @param {function} fn
1855
- */
1856
- load: function(fn) {
1857
- var self = this;
1858
- var $wrapper = self.$wrapper.addClass(self.settings.loadingClass);
1859
-
1860
- self.loading++;
1861
- fn.apply(self, [function(results) {
1862
- self.loading = Math.max(self.loading - 1, 0);
1863
- if (results && results.length) {
1864
- self.addOption(results);
1865
- self.refreshOptions(self.isFocused && !self.isInputHidden);
1866
- }
1867
- if (!self.loading) {
1868
- $wrapper.removeClass(self.settings.loadingClass);
1869
- }
1870
- self.trigger('load', results);
1871
- }]);
1872
- },
1873
-
1874
- /**
1875
- * Sets the input field of the control to the specified value.
1876
- *
1877
- * @param {string} value
1878
- */
1879
- setTextboxValue: function(value) {
1880
- var $input = this.$control_input;
1881
- var changed = $input.val() !== value;
1882
- if (changed) {
1883
- $input.val(value).triggerHandler('update');
1884
- this.lastValue = value;
1885
- }
1886
- },
1887
-
1888
- /**
1889
- * Returns the value of the control. If multiple items
1890
- * can be selected (e.g. <select multiple>), this returns
1891
- * an array. If only one item can be selected, this
1892
- * returns a string.
1893
- *
1894
- * @returns {mixed}
1895
- */
1896
- getValue: function() {
1897
- if (this.tagType === TAG_SELECT && this.$input.attr('multiple')) {
1898
- return this.items;
1899
- } else {
1900
- return this.items.join(this.settings.delimiter);
1901
- }
1902
- },
1903
-
1904
- /**
1905
- * Resets the selected items to the given value.
1906
- *
1907
- * @param {mixed} value
1908
- */
1909
- setValue: function(value, silent) {
1910
- var events = silent ? [] : ['change'];
1911
-
1912
- debounce_events(this, events, function() {
1913
- this.clear(silent);
1914
- this.addItems(value, silent);
1915
- });
1916
- },
1917
-
1918
- /**
1919
- * Sets the selected item.
1920
- *
1921
- * @param {object} $item
1922
- * @param {object} e (optional)
1923
- */
1924
- setActiveItem: function($item, e) {
1925
- var self = this;
1926
- var eventName;
1927
- var i, idx, begin, end, item, swap;
1928
- var $last;
1929
-
1930
- if (self.settings.mode === 'single') return;
1931
- $item = $($item);
1932
-
1933
- // clear the active selection
1934
- if (!$item.length) {
1935
- $(self.$activeItems).removeClass('active');
1936
- self.$activeItems = [];
1937
- if (self.isFocused) {
1938
- self.showInput();
1939
- }
1940
- return;
1941
- }
1942
-
1943
- // modify selection
1944
- eventName = e && e.type.toLowerCase();
1945
-
1946
- if (eventName === 'mousedown' && self.isShiftDown && self.$activeItems.length) {
1947
- $last = self.$control.children('.active:last');
1948
- begin = Array.prototype.indexOf.apply(self.$control[0].childNodes, [$last[0]]);
1949
- end = Array.prototype.indexOf.apply(self.$control[0].childNodes, [$item[0]]);
1950
- if (begin > end) {
1951
- swap = begin;
1952
- begin = end;
1953
- end = swap;
1954
- }
1955
- for (i = begin; i <= end; i++) {
1956
- item = self.$control[0].childNodes[i];
1957
- if (self.$activeItems.indexOf(item) === -1) {
1958
- $(item).addClass('active');
1959
- self.$activeItems.push(item);
1960
- }
1961
- }
1962
- e.preventDefault();
1963
- } else if ((eventName === 'mousedown' && self.isCtrlDown) || (eventName === 'keydown' && this.isShiftDown)) {
1964
- if ($item.hasClass('active')) {
1965
- idx = self.$activeItems.indexOf($item[0]);
1966
- self.$activeItems.splice(idx, 1);
1967
- $item.removeClass('active');
1968
- } else {
1969
- self.$activeItems.push($item.addClass('active')[0]);
1970
- }
1971
- } else {
1972
- $(self.$activeItems).removeClass('active');
1973
- self.$activeItems = [$item.addClass('active')[0]];
1974
- }
1975
-
1976
- // ensure control has focus
1977
- self.hideInput();
1978
- if (!this.isFocused) {
1979
- self.focus();
1980
- }
1981
- },
1982
-
1983
- /**
1984
- * Sets the selected item in the dropdown menu
1985
- * of available options.
1986
- *
1987
- * @param {object} $object
1988
- * @param {boolean} scroll
1989
- * @param {boolean} animate
1990
- */
1991
- setActiveOption: function($option, scroll, animate) {
1992
- var height_menu, height_item, y;
1993
- var scroll_top, scroll_bottom;
1994
- var self = this;
1995
-
1996
- if (self.$activeOption) self.$activeOption.removeClass('active');
1997
- self.$activeOption = null;
1998
-
1999
- $option = $($option);
2000
- if (!$option.length) return;
2001
-
2002
- self.$activeOption = $option.addClass('active');
2003
-
2004
- if (scroll || !isset(scroll)) {
2005
-
2006
- height_menu = self.$dropdown_content.height();
2007
- height_item = self.$activeOption.outerHeight(true);
2008
- scroll = self.$dropdown_content.scrollTop() || 0;
2009
- y = self.$activeOption.offset().top - self.$dropdown_content.offset().top + scroll;
2010
- scroll_top = y;
2011
- scroll_bottom = y - height_menu + height_item;
2012
-
2013
- if (y + height_item > height_menu + scroll) {
2014
- self.$dropdown_content.stop().animate({scrollTop: scroll_bottom}, animate ? self.settings.scrollDuration : 0);
2015
- } else if (y < scroll) {
2016
- self.$dropdown_content.stop().animate({scrollTop: scroll_top}, animate ? self.settings.scrollDuration : 0);
2017
- }
2018
-
2019
- }
2020
- },
2021
-
2022
- /**
2023
- * Selects all items (CTRL + A).
2024
- */
2025
- selectAll: function() {
2026
- var self = this;
2027
- if (self.settings.mode === 'single') return;
2028
-
2029
- self.$activeItems = Array.prototype.slice.apply(self.$control.children(':not(input)').addClass('active'));
2030
- if (self.$activeItems.length) {
2031
- self.hideInput();
2032
- self.close();
2033
- }
2034
- self.focus();
2035
- },
2036
-
2037
- /**
2038
- * Hides the input element out of view, while
2039
- * retaining its focus.
2040
- */
2041
- hideInput: function() {
2042
- var self = this;
2043
-
2044
- self.setTextboxValue('');
2045
- self.$control_input.css({opacity: 0, position: 'absolute', left: self.rtl ? 10000 : -10000});
2046
- self.isInputHidden = true;
2047
- },
2048
-
2049
- /**
2050
- * Restores input visibility.
2051
- */
2052
- showInput: function() {
2053
- this.$control_input.css({opacity: 1, position: 'relative', left: 0});
2054
- this.isInputHidden = false;
2055
- },
2056
-
2057
- /**
2058
- * Gives the control focus.
2059
- */
2060
- focus: function() {
2061
- var self = this;
2062
- if (self.isDisabled) return;
2063
-
2064
- self.ignoreFocus = true;
2065
- self.$control_input[0].focus();
2066
- window.setTimeout(function() {
2067
- self.ignoreFocus = false;
2068
- self.onFocus();
2069
- }, 0);
2070
- },
2071
-
2072
- /**
2073
- * Forces the control out of focus.
2074
- *
2075
- * @param {Element} dest
2076
- */
2077
- blur: function(dest) {
2078
- this.$control_input[0].blur();
2079
- this.onBlur(null, dest);
2080
- },
2081
-
2082
- /**
2083
- * Returns a function that scores an object
2084
- * to show how good of a match it is to the
2085
- * provided query.
2086
- *
2087
- * @param {string} query
2088
- * @param {object} options
2089
- * @return {function}
2090
- */
2091
- getScoreFunction: function(query) {
2092
- return this.sifter.getScoreFunction(query, this.getSearchOptions());
2093
- },
2094
-
2095
- /**
2096
- * Returns search options for sifter (the system
2097
- * for scoring and sorting results).
2098
- *
2099
- * @see https://github.com/brianreavis/sifter.js
2100
- * @return {object}
2101
- */
2102
- getSearchOptions: function() {
2103
- var settings = this.settings;
2104
- var sort = settings.sortField;
2105
- if (typeof sort === 'string') {
2106
- sort = [{field: sort}];
2107
- }
2108
-
2109
- return {
2110
- fields : settings.searchField,
2111
- conjunction : settings.searchConjunction,
2112
- sort : sort
2113
- };
2114
- },
2115
-
2116
- /**
2117
- * Searches through available options and returns
2118
- * a sorted array of matches.
2119
- *
2120
- * Returns an object containing:
2121
- *
2122
- * - query {string}
2123
- * - tokens {array}
2124
- * - total {int}
2125
- * - items {array}
2126
- *
2127
- * @param {string} query
2128
- * @returns {object}
2129
- */
2130
- search: function(query) {
2131
- var i, value, score, result, calculateScore;
2132
- var self = this;
2133
- var settings = self.settings;
2134
- var options = this.getSearchOptions();
2135
-
2136
- // validate user-provided result scoring function
2137
- if (settings.score) {
2138
- calculateScore = self.settings.score.apply(this, [query]);
2139
- if (typeof calculateScore !== 'function') {
2140
- throw new Error('Selectize "score" setting must be a function that returns a function');
2141
- }
2142
- }
2143
-
2144
- // perform search
2145
- if (query !== self.lastQuery) {
2146
- self.lastQuery = query;
2147
- result = self.sifter.search(query, $.extend(options, {score: calculateScore}));
2148
- self.currentResults = result;
2149
- } else {
2150
- result = $.extend(true, {}, self.currentResults);
2151
- }
2152
-
2153
- // filter out selected items
2154
- if (settings.hideSelected) {
2155
- for (i = result.items.length - 1; i >= 0; i--) {
2156
- if (self.items.indexOf(hash_key(result.items[i].id)) !== -1) {
2157
- result.items.splice(i, 1);
2158
- }
2159
- }
2160
- }
2161
-
2162
- return result;
2163
- },
2164
-
2165
- /**
2166
- * Refreshes the list of available options shown
2167
- * in the autocomplete dropdown menu.
2168
- *
2169
- * @param {boolean} triggerDropdown
2170
- */
2171
- refreshOptions: function(triggerDropdown) {
2172
- var i, j, k, n, groups, groups_order, option, option_html, optgroup, optgroups, html, html_children, has_create_option;
2173
- var $active, $active_before, $create;
2174
-
2175
- if (typeof triggerDropdown === 'undefined') {
2176
- triggerDropdown = true;
2177
- }
2178
-
2179
- var self = this;
2180
- var query = $.trim(self.$control_input.val());
2181
- var results = self.search(query);
2182
- var $dropdown_content = self.$dropdown_content;
2183
- var active_before = self.$activeOption && hash_key(self.$activeOption.attr('data-value'));
2184
-
2185
- // build markup
2186
- n = results.items.length;
2187
- if (typeof self.settings.maxOptions === 'number') {
2188
- n = Math.min(n, self.settings.maxOptions);
2189
- }
2190
-
2191
- // render and group available options individually
2192
- groups = {};
2193
- groups_order = [];
2194
-
2195
- for (i = 0; i < n; i++) {
2196
- option = self.options[results.items[i].id];
2197
- option_html = self.render('option', option);
2198
- optgroup = option[self.settings.optgroupField] || '';
2199
- optgroups = $.isArray(optgroup) ? optgroup : [optgroup];
2200
-
2201
- for (j = 0, k = optgroups && optgroups.length; j < k; j++) {
2202
- optgroup = optgroups[j];
2203
- if (!self.optgroups.hasOwnProperty(optgroup)) {
2204
- optgroup = '';
2205
- }
2206
- if (!groups.hasOwnProperty(optgroup)) {
2207
- groups[optgroup] = document.createDocumentFragment();
2208
- groups_order.push(optgroup);
2209
- }
2210
- groups[optgroup].appendChild(option_html);
2211
- }
2212
- }
2213
-
2214
- // sort optgroups
2215
- if (this.settings.lockOptgroupOrder) {
2216
- groups_order.sort(function(a, b) {
2217
- var a_order = self.optgroups[a].$order || 0;
2218
- var b_order = self.optgroups[b].$order || 0;
2219
- return a_order - b_order;
2220
- });
2221
- }
2222
-
2223
- // render optgroup headers & join groups
2224
- html = document.createDocumentFragment();
2225
- for (i = 0, n = groups_order.length; i < n; i++) {
2226
- optgroup = groups_order[i];
2227
- if (self.optgroups.hasOwnProperty(optgroup) && groups[optgroup].childNodes.length) {
2228
- // render the optgroup header and options within it,
2229
- // then pass it to the wrapper template
2230
- html_children = document.createDocumentFragment();
2231
- html_children.appendChild(self.render('optgroup_header', self.optgroups[optgroup]));
2232
- html_children.appendChild(groups[optgroup]);
2233
-
2234
- html.appendChild(self.render('optgroup', $.extend({}, self.optgroups[optgroup], {
2235
- html: domToString(html_children),
2236
- dom: html_children
2237
- })));
2238
- } else {
2239
- html.appendChild(groups[optgroup]);
2240
- }
2241
- }
2242
-
2243
- $dropdown_content.html(html);
2244
-
2245
- // highlight matching terms inline
2246
- if (self.settings.highlight && results.query.length && results.tokens.length) {
2247
- $dropdown_content.removeHighlight();
2248
- for (i = 0, n = results.tokens.length; i < n; i++) {
2249
- highlight($dropdown_content, results.tokens[i].regex);
2250
- }
2251
- }
2252
-
2253
- // add "selected" class to selected options
2254
- if (!self.settings.hideSelected) {
2255
- for (i = 0, n = self.items.length; i < n; i++) {
2256
- self.getOption(self.items[i]).addClass('selected');
2257
- }
2258
- }
2259
-
2260
- // add create option
2261
- has_create_option = self.canCreate(query);
2262
- if (has_create_option) {
2263
- $dropdown_content.prepend(self.render('option_create', {input: query}));
2264
- $create = $($dropdown_content[0].childNodes[0]);
2265
- }
2266
-
2267
- // activate
2268
- self.hasOptions = results.items.length > 0 || has_create_option;
2269
- if (self.hasOptions) {
2270
- if (results.items.length > 0) {
2271
- $active_before = active_before && self.getOption(active_before);
2272
- if ($active_before && $active_before.length) {
2273
- $active = $active_before;
2274
- } else if (self.settings.mode === 'single' && self.items.length) {
2275
- $active = self.getOption(self.items[0]);
2276
- }
2277
- if (!$active || !$active.length) {
2278
- if ($create && !self.settings.addPrecedence) {
2279
- $active = self.getAdjacentOption($create, 1);
2280
- } else {
2281
- $active = $dropdown_content.find('[data-selectable]:first');
2282
- }
2283
- }
2284
- } else {
2285
- $active = $create;
2286
- }
2287
- self.setActiveOption($active);
2288
- if (triggerDropdown && !self.isOpen) { self.open(); }
2289
- } else {
2290
- self.setActiveOption(null);
2291
- if (triggerDropdown && self.isOpen) { self.close(); }
2292
- }
2293
- },
2294
-
2295
- /**
2296
- * Adds an available option. If it already exists,
2297
- * nothing will happen. Note: this does not refresh
2298
- * the options list dropdown (use `refreshOptions`
2299
- * for that).
2300
- *
2301
- * Usage:
2302
- *
2303
- * this.addOption(data)
2304
- *
2305
- * @param {object|array} data
2306
- */
2307
- addOption: function(data) {
2308
- var i, n, value, self = this;
2309
-
2310
- if ($.isArray(data)) {
2311
- for (i = 0, n = data.length; i < n; i++) {
2312
- self.addOption(data[i]);
2313
- }
2314
- return;
2315
- }
2316
-
2317
- if (value = self.registerOption(data)) {
2318
- self.userOptions[value] = true;
2319
- self.lastQuery = null;
2320
- self.trigger('option_add', value, data);
2321
- }
2322
- },
2323
-
2324
- /**
2325
- * Registers an option to the pool of options.
2326
- *
2327
- * @param {object} data
2328
- * @return {boolean|string}
2329
- */
2330
- registerOption: function(data) {
2331
- var key = hash_key(data[this.settings.valueField]);
2332
- if (typeof key === 'undefined' || key === null || this.options.hasOwnProperty(key)) return false;
2333
- data.$order = data.$order || ++this.order;
2334
- this.options[key] = data;
2335
- return key;
2336
- },
2337
-
2338
- /**
2339
- * Registers an option group to the pool of option groups.
2340
- *
2341
- * @param {object} data
2342
- * @return {boolean|string}
2343
- */
2344
- registerOptionGroup: function(data) {
2345
- var key = hash_key(data[this.settings.optgroupValueField]);
2346
- if (!key) return false;
2347
-
2348
- data.$order = data.$order || ++this.order;
2349
- this.optgroups[key] = data;
2350
- return key;
2351
- },
2352
-
2353
- /**
2354
- * Registers a new optgroup for options
2355
- * to be bucketed into.
2356
- *
2357
- * @param {string} id
2358
- * @param {object} data
2359
- */
2360
- addOptionGroup: function(id, data) {
2361
- data[this.settings.optgroupValueField] = id;
2362
- if (id = this.registerOptionGroup(data)) {
2363
- this.trigger('optgroup_add', id, data);
2364
- }
2365
- },
2366
-
2367
- /**
2368
- * Removes an existing option group.
2369
- *
2370
- * @param {string} id
2371
- */
2372
- removeOptionGroup: function(id) {
2373
- if (this.optgroups.hasOwnProperty(id)) {
2374
- delete this.optgroups[id];
2375
- this.renderCache = {};
2376
- this.trigger('optgroup_remove', id);
2377
- }
2378
- },
2379
-
2380
- /**
2381
- * Clears all existing option groups.
2382
- */
2383
- clearOptionGroups: function() {
2384
- this.optgroups = {};
2385
- this.renderCache = {};
2386
- this.trigger('optgroup_clear');
2387
- },
2388
-
2389
- /**
2390
- * Updates an option available for selection. If
2391
- * it is visible in the selected items or options
2392
- * dropdown, it will be re-rendered automatically.
2393
- *
2394
- * @param {string} value
2395
- * @param {object} data
2396
- */
2397
- updateOption: function(value, data) {
2398
- var self = this;
2399
- var $item, $item_new;
2400
- var value_new, index_item, cache_items, cache_options, order_old;
2401
-
2402
- value = hash_key(value);
2403
- value_new = hash_key(data[self.settings.valueField]);
2404
-
2405
- // sanity checks
2406
- if (value === null) return;
2407
- if (!self.options.hasOwnProperty(value)) return;
2408
- if (typeof value_new !== 'string') throw new Error('Value must be set in option data');
2409
-
2410
- order_old = self.options[value].$order;
2411
-
2412
- // update references
2413
- if (value_new !== value) {
2414
- delete self.options[value];
2415
- index_item = self.items.indexOf(value);
2416
- if (index_item !== -1) {
2417
- self.items.splice(index_item, 1, value_new);
2418
- }
2419
- }
2420
- data.$order = data.$order || order_old;
2421
- self.options[value_new] = data;
2422
-
2423
- // invalidate render cache
2424
- cache_items = self.renderCache['item'];
2425
- cache_options = self.renderCache['option'];
2426
-
2427
- if (cache_items) {
2428
- delete cache_items[value];
2429
- delete cache_items[value_new];
2430
- }
2431
- if (cache_options) {
2432
- delete cache_options[value];
2433
- delete cache_options[value_new];
2434
- }
2435
-
2436
- // update the item if it's selected
2437
- if (self.items.indexOf(value_new) !== -1) {
2438
- $item = self.getItem(value);
2439
- $item_new = $(self.render('item', data));
2440
- if ($item.hasClass('active')) $item_new.addClass('active');
2441
- $item.replaceWith($item_new);
2442
- }
2443
-
2444
- // invalidate last query because we might have updated the sortField
2445
- self.lastQuery = null;
2446
-
2447
- // update dropdown contents
2448
- if (self.isOpen) {
2449
- self.refreshOptions(false);
2450
- }
2451
- },
2452
-
2453
- /**
2454
- * Removes a single option.
2455
- *
2456
- * @param {string} value
2457
- * @param {boolean} silent
2458
- */
2459
- removeOption: function(value, silent) {
2460
- var self = this;
2461
- value = hash_key(value);
2462
-
2463
- var cache_items = self.renderCache['item'];
2464
- var cache_options = self.renderCache['option'];
2465
- if (cache_items) delete cache_items[value];
2466
- if (cache_options) delete cache_options[value];
2467
-
2468
- delete self.userOptions[value];
2469
- delete self.options[value];
2470
- self.lastQuery = null;
2471
- self.trigger('option_remove', value);
2472
- self.removeItem(value, silent);
2473
- },
2474
-
2475
- /**
2476
- * Clears all options.
2477
- */
2478
- clearOptions: function() {
2479
- var self = this;
2480
-
2481
- self.loadedSearches = {};
2482
- self.userOptions = {};
2483
- self.renderCache = {};
2484
- self.options = self.sifter.items = {};
2485
- self.lastQuery = null;
2486
- self.trigger('option_clear');
2487
- self.clear();
2488
- },
2489
-
2490
- /**
2491
- * Returns the jQuery element of the option
2492
- * matching the given value.
2493
- *
2494
- * @param {string} value
2495
- * @returns {object}
2496
- */
2497
- getOption: function(value) {
2498
- return this.getElementWithValue(value, this.$dropdown_content.find('[data-selectable]'));
2499
- },
2500
-
2501
- /**
2502
- * Returns the jQuery element of the next or
2503
- * previous selectable option.
2504
- *
2505
- * @param {object} $option
2506
- * @param {int} direction can be 1 for next or -1 for previous
2507
- * @return {object}
2508
- */
2509
- getAdjacentOption: function($option, direction) {
2510
- var $options = this.$dropdown.find('[data-selectable]');
2511
- var index = $options.index($option) + direction;
2512
-
2513
- return index >= 0 && index < $options.length ? $options.eq(index) : $();
2514
- },
2515
-
2516
- /**
2517
- * Finds the first element with a "data-value" attribute
2518
- * that matches the given value.
2519
- *
2520
- * @param {mixed} value
2521
- * @param {object} $els
2522
- * @return {object}
2523
- */
2524
- getElementWithValue: function(value, $els) {
2525
- value = hash_key(value);
2526
-
2527
- if (typeof value !== 'undefined' && value !== null) {
2528
- for (var i = 0, n = $els.length; i < n; i++) {
2529
- if ($els[i].getAttribute('data-value') === value) {
2530
- return $($els[i]);
2531
- }
2532
- }
2533
- }
2534
-
2535
- return $();
2536
- },
2537
-
2538
- /**
2539
- * Returns the jQuery element of the item
2540
- * matching the given value.
2541
- *
2542
- * @param {string} value
2543
- * @returns {object}
2544
- */
2545
- getItem: function(value) {
2546
- return this.getElementWithValue(value, this.$control.children());
2547
- },
2548
-
2549
- /**
2550
- * "Selects" multiple items at once. Adds them to the list
2551
- * at the current caret position.
2552
- *
2553
- * @param {string} value
2554
- * @param {boolean} silent
2555
- */
2556
- addItems: function(values, silent) {
2557
- var items = $.isArray(values) ? values : [values];
2558
- for (var i = 0, n = items.length; i < n; i++) {
2559
- this.isPending = (i < n - 1);
2560
- this.addItem(items[i], silent);
2561
- }
2562
- },
2563
-
2564
- /**
2565
- * "Selects" an item. Adds it to the list
2566
- * at the current caret position.
2567
- *
2568
- * @param {string} value
2569
- * @param {boolean} silent
2570
- */
2571
- addItem: function(value, silent) {
2572
- var events = silent ? [] : ['change'];
2573
-
2574
- debounce_events(this, events, function() {
2575
- var $item, $option, $options;
2576
- var self = this;
2577
- var inputMode = self.settings.mode;
2578
- var i, active, value_next, wasFull;
2579
- value = hash_key(value);
2580
-
2581
- if (self.items.indexOf(value) !== -1) {
2582
- if (inputMode === 'single') self.close();
2583
- return;
2584
- }
2585
-
2586
- if (!self.options.hasOwnProperty(value)) return;
2587
- if (inputMode === 'single') self.clear(silent);
2588
- if (inputMode === 'multi' && self.isFull()) return;
2589
-
2590
- $item = $(self.render('item', self.options[value]));
2591
- wasFull = self.isFull();
2592
- self.items.splice(self.caretPos, 0, value);
2593
- self.insertAtCaret($item);
2594
- if (!self.isPending || (!wasFull && self.isFull())) {
2595
- self.refreshState();
2596
- }
2597
-
2598
- if (self.isSetup) {
2599
- $options = self.$dropdown_content.find('[data-selectable]');
2600
-
2601
- // update menu / remove the option (if this is not one item being added as part of series)
2602
- if (!self.isPending) {
2603
- $option = self.getOption(value);
2604
- value_next = self.getAdjacentOption($option, 1).attr('data-value');
2605
- self.refreshOptions(self.isFocused && inputMode !== 'single');
2606
- if (value_next) {
2607
- self.setActiveOption(self.getOption(value_next));
2608
- }
2609
- }
2610
-
2611
- // hide the menu if the maximum number of items have been selected or no options are left
2612
- if (!$options.length || self.isFull()) {
2613
- self.close();
2614
- } else {
2615
- self.positionDropdown();
2616
- }
2617
-
2618
- self.updatePlaceholder();
2619
- self.trigger('item_add', value, $item);
2620
- self.updateOriginalInput({silent: silent});
2621
- }
2622
- });
2623
- },
2624
-
2625
- /**
2626
- * Removes the selected item matching
2627
- * the provided value.
2628
- *
2629
- * @param {string} value
2630
- */
2631
- removeItem: function(value, silent) {
2632
- var self = this;
2633
- var $item, i, idx;
2634
-
2635
- $item = (value instanceof $) ? value : self.getItem(value);
2636
- value = hash_key($item.attr('data-value'));
2637
- i = self.items.indexOf(value);
2638
-
2639
- if (i !== -1) {
2640
- $item.remove();
2641
- if ($item.hasClass('active')) {
2642
- idx = self.$activeItems.indexOf($item[0]);
2643
- self.$activeItems.splice(idx, 1);
2644
- }
2645
-
2646
- self.items.splice(i, 1);
2647
- self.lastQuery = null;
2648
- if (!self.settings.persist && self.userOptions.hasOwnProperty(value)) {
2649
- self.removeOption(value, silent);
2650
- }
2651
-
2652
- if (i < self.caretPos) {
2653
- self.setCaret(self.caretPos - 1);
2654
- }
2655
-
2656
- self.refreshState();
2657
- self.updatePlaceholder();
2658
- self.updateOriginalInput({silent: silent});
2659
- self.positionDropdown();
2660
- self.trigger('item_remove', value, $item);
2661
- }
2662
- },
2663
-
2664
- /**
2665
- * Invokes the `create` method provided in the
2666
- * selectize options that should provide the data
2667
- * for the new item, given the user input.
2668
- *
2669
- * Once this completes, it will be added
2670
- * to the item list.
2671
- *
2672
- * @param {string} value
2673
- * @param {boolean} [triggerDropdown]
2674
- * @param {function} [callback]
2675
- * @return {boolean}
2676
- */
2677
- createItem: function(input, triggerDropdown) {
2678
- var self = this;
2679
- var caret = self.caretPos;
2680
- input = input || $.trim(self.$control_input.val() || '');
2681
-
2682
- var callback = arguments[arguments.length - 1];
2683
- if (typeof callback !== 'function') callback = function() {};
2684
-
2685
- if (typeof triggerDropdown !== 'boolean') {
2686
- triggerDropdown = true;
2687
- }
2688
-
2689
- if (!self.canCreate(input)) {
2690
- callback();
2691
- return false;
2692
- }
2693
-
2694
- self.lock();
2695
-
2696
- var setup = (typeof self.settings.create === 'function') ? this.settings.create : function(input) {
2697
- var data = {};
2698
- data[self.settings.labelField] = input;
2699
- data[self.settings.valueField] = input;
2700
- return data;
2701
- };
2702
-
2703
- var create = once(function(data) {
2704
- self.unlock();
2705
-
2706
- if (!data || typeof data !== 'object') return callback();
2707
- var value = hash_key(data[self.settings.valueField]);
2708
- if (typeof value !== 'string') return callback();
2709
-
2710
- self.setTextboxValue('');
2711
- self.addOption(data);
2712
- self.setCaret(caret);
2713
- self.addItem(value);
2714
- self.refreshOptions(triggerDropdown && self.settings.mode !== 'single');
2715
- callback(data);
2716
- });
2717
-
2718
- var output = setup.apply(this, [input, create]);
2719
- if (typeof output !== 'undefined') {
2720
- create(output);
2721
- }
2722
-
2723
- return true;
2724
- },
2725
-
2726
- /**
2727
- * Re-renders the selected item lists.
2728
- */
2729
- refreshItems: function() {
2730
- this.lastQuery = null;
2731
-
2732
- if (this.isSetup) {
2733
- this.addItem(this.items);
2734
- }
2735
-
2736
- this.refreshState();
2737
- this.updateOriginalInput();
2738
- },
2739
-
2740
- /**
2741
- * Updates all state-dependent attributes
2742
- * and CSS classes.
2743
- */
2744
- refreshState: function() {
2745
- this.refreshValidityState();
2746
- this.refreshClasses();
2747
- },
2748
-
2749
- /**
2750
- * Update the `required` attribute of both input and control input.
2751
- *
2752
- * The `required` property needs to be activated on the control input
2753
- * for the error to be displayed at the right place. `required` also
2754
- * needs to be temporarily deactivated on the input since the input is
2755
- * hidden and can't show errors.
2756
- */
2757
- refreshValidityState: function() {
2758
- if (!this.isRequired) return false;
2759
-
2760
- var invalid = !this.items.length;
2761
-
2762
- this.isInvalid = invalid;
2763
- this.$control_input.prop('required', invalid);
2764
- this.$input.prop('required', !invalid);
2765
- },
2766
-
2767
- /**
2768
- * Updates all state-dependent CSS classes.
2769
- */
2770
- refreshClasses: function() {
2771
- var self = this;
2772
- var isFull = self.isFull();
2773
- var isLocked = self.isLocked;
2774
-
2775
- self.$wrapper
2776
- .toggleClass('rtl', self.rtl);
2777
-
2778
- self.$control
2779
- .toggleClass('focus', self.isFocused)
2780
- .toggleClass('disabled', self.isDisabled)
2781
- .toggleClass('required', self.isRequired)
2782
- .toggleClass('invalid', self.isInvalid)
2783
- .toggleClass('locked', isLocked)
2784
- .toggleClass('full', isFull).toggleClass('not-full', !isFull)
2785
- .toggleClass('input-active', self.isFocused && !self.isInputHidden)
2786
- .toggleClass('dropdown-active', self.isOpen)
2787
- .toggleClass('has-options', !$.isEmptyObject(self.options))
2788
- .toggleClass('has-items', self.items.length > 0);
2789
-
2790
- self.$control_input.data('grow', !isFull && !isLocked);
2791
- },
2792
-
2793
- /**
2794
- * Determines whether or not more items can be added
2795
- * to the control without exceeding the user-defined maximum.
2796
- *
2797
- * @returns {boolean}
2798
- */
2799
- isFull: function() {
2800
- return this.settings.maxItems !== null && this.items.length >= this.settings.maxItems;
2801
- },
2802
-
2803
- /**
2804
- * Refreshes the original <select> or <input>
2805
- * element to reflect the current state.
2806
- */
2807
- updateOriginalInput: function(opts) {
2808
- var i, n, options, label, self = this;
2809
- opts = opts || {};
2810
-
2811
- if (self.tagType === TAG_SELECT) {
2812
- options = [];
2813
- for (i = 0, n = self.items.length; i < n; i++) {
2814
- label = self.options[self.items[i]][self.settings.labelField] || '';
2815
- options.push('<option value="' + escape_html(self.items[i]) + '" selected="selected">' + escape_html(label) + '</option>');
2816
- }
2817
- if (!options.length && !this.$input.attr('multiple')) {
2818
- options.push('<option value="" selected="selected"></option>');
2819
- }
2820
- self.$input.html(options.join(''));
2821
- } else {
2822
- self.$input.val(self.getValue());
2823
- self.$input.attr('value',self.$input.val());
2824
- }
2825
-
2826
- if (self.isSetup) {
2827
- if (!opts.silent) {
2828
- self.trigger('change', self.$input.val());
2829
- }
2830
- }
2831
- },
2832
-
2833
- /**
2834
- * Shows/hide the input placeholder depending
2835
- * on if there items in the list already.
2836
- */
2837
- updatePlaceholder: function() {
2838
- if (!this.settings.placeholder) return;
2839
- var $input = this.$control_input;
2840
-
2841
- if (this.items.length) {
2842
- $input.removeAttr('placeholder');
2843
- } else {
2844
- $input.attr('placeholder', this.settings.placeholder);
2845
- }
2846
- $input.triggerHandler('update', {force: true});
2847
- },
2848
-
2849
- /**
2850
- * Shows the autocomplete dropdown containing
2851
- * the available options.
2852
- */
2853
- open: function() {
2854
- var self = this;
2855
-
2856
- if (self.isLocked || self.isOpen || (self.settings.mode === 'multi' && self.isFull())) return;
2857
- self.focus();
2858
- self.isOpen = true;
2859
- self.refreshState();
2860
- self.$dropdown.css({visibility: 'hidden', display: 'block'});
2861
- self.positionDropdown();
2862
- self.$dropdown.css({visibility: 'visible'});
2863
- self.trigger('dropdown_open', self.$dropdown);
2864
- },
2865
-
2866
- /**
2867
- * Closes the autocomplete dropdown menu.
2868
- */
2869
- close: function() {
2870
- var self = this;
2871
- var trigger = self.isOpen;
2872
-
2873
- if (self.settings.mode === 'single' && self.items.length) {
2874
- self.hideInput();
2875
- self.$control_input.blur(); // close keyboard on iOS
2876
- }
2877
-
2878
- self.isOpen = false;
2879
- self.$dropdown.hide();
2880
- self.setActiveOption(null);
2881
- self.refreshState();
2882
-
2883
- if (trigger) self.trigger('dropdown_close', self.$dropdown);
2884
- },
2885
-
2886
- /**
2887
- * Calculates and applies the appropriate
2888
- * position of the dropdown.
2889
- */
2890
- positionDropdown: function() {
2891
- var $control = this.$control;
2892
- var offset = this.settings.dropdownParent === 'body' ? $control.offset() : $control.position();
2893
- offset.top += $control.outerHeight(true);
2894
-
2895
- this.$dropdown.css({
2896
- width : $control.outerWidth(),
2897
- top : offset.top,
2898
- left : offset.left
2899
- });
2900
- },
2901
-
2902
- /**
2903
- * Resets / clears all selected items
2904
- * from the control.
2905
- *
2906
- * @param {boolean} silent
2907
- */
2908
- clear: function(silent) {
2909
- var self = this;
2910
-
2911
- if (!self.items.length) return;
2912
- self.$control.children(':not(input)').remove();
2913
- self.items = [];
2914
- self.lastQuery = null;
2915
- self.setCaret(0);
2916
- self.setActiveItem(null);
2917
- self.updatePlaceholder();
2918
- self.updateOriginalInput({silent: silent});
2919
- self.refreshState();
2920
- self.showInput();
2921
- self.trigger('clear');
2922
- },
2923
-
2924
- /**
2925
- * A helper method for inserting an element
2926
- * at the current caret position.
2927
- *
2928
- * @param {object} $el
2929
- */
2930
- insertAtCaret: function($el) {
2931
- var caret = Math.min(this.caretPos, this.items.length);
2932
- if (caret === 0) {
2933
- this.$control.prepend($el);
2934
- } else {
2935
- $(this.$control[0].childNodes[caret]).before($el);
2936
- }
2937
- this.setCaret(caret + 1);
2938
- },
2939
-
2940
- /**
2941
- * Removes the current selected item(s).
2942
- *
2943
- * @param {object} e (optional)
2944
- * @returns {boolean}
2945
- */
2946
- deleteSelection: function(e) {
2947
- var i, n, direction, selection, values, caret, option_select, $option_select, $tail;
2948
- var self = this;
2949
-
2950
- direction = (e && e.keyCode === KEY_BACKSPACE) ? -1 : 1;
2951
- selection = getSelection(self.$control_input[0]);
2952
-
2953
- if (self.$activeOption && !self.settings.hideSelected) {
2954
- option_select = self.getAdjacentOption(self.$activeOption, -1).attr('data-value');
2955
- }
2956
-
2957
- // determine items that will be removed
2958
- values = [];
2959
-
2960
- if (self.$activeItems.length) {
2961
- $tail = self.$control.children('.active:' + (direction > 0 ? 'last' : 'first'));
2962
- caret = self.$control.children(':not(input)').index($tail);
2963
- if (direction > 0) { caret++; }
2964
-
2965
- for (i = 0, n = self.$activeItems.length; i < n; i++) {
2966
- values.push($(self.$activeItems[i]).attr('data-value'));
2967
- }
2968
- if (e) {
2969
- e.preventDefault();
2970
- e.stopPropagation();
2971
- }
2972
- } else if ((self.isFocused || self.settings.mode === 'single') && self.items.length) {
2973
- if (direction < 0 && selection.start === 0 && selection.length === 0) {
2974
- values.push(self.items[self.caretPos - 1]);
2975
- } else if (direction > 0 && selection.start === self.$control_input.val().length) {
2976
- values.push(self.items[self.caretPos]);
2977
- }
2978
- }
2979
-
2980
- // allow the callback to abort
2981
- if (!values.length || (typeof self.settings.onDelete === 'function' && self.settings.onDelete.apply(self, [values]) === false)) {
2982
- return false;
2983
- }
2984
-
2985
- // perform removal
2986
- if (typeof caret !== 'undefined') {
2987
- self.setCaret(caret);
2988
- }
2989
- while (values.length) {
2990
- self.removeItem(values.pop());
2991
- }
2992
-
2993
- self.showInput();
2994
- self.positionDropdown();
2995
- self.refreshOptions(true);
2996
-
2997
- // select previous option
2998
- if (option_select) {
2999
- $option_select = self.getOption(option_select);
3000
- if ($option_select.length) {
3001
- self.setActiveOption($option_select);
3002
- }
3003
- }
3004
-
3005
- return true;
3006
- },
3007
-
3008
- /**
3009
- * Selects the previous / next item (depending
3010
- * on the `direction` argument).
3011
- *
3012
- * > 0 - right
3013
- * < 0 - left
3014
- *
3015
- * @param {int} direction
3016
- * @param {object} e (optional)
3017
- */
3018
- advanceSelection: function(direction, e) {
3019
- var tail, selection, idx, valueLength, cursorAtEdge, $tail;
3020
- var self = this;
3021
-
3022
- if (direction === 0) return;
3023
- if (self.rtl) direction *= -1;
3024
-
3025
- tail = direction > 0 ? 'last' : 'first';
3026
- selection = getSelection(self.$control_input[0]);
3027
-
3028
- if (self.isFocused && !self.isInputHidden) {
3029
- valueLength = self.$control_input.val().length;
3030
- cursorAtEdge = direction < 0
3031
- ? selection.start === 0 && selection.length === 0
3032
- : selection.start === valueLength;
3033
-
3034
- if (cursorAtEdge && !valueLength) {
3035
- self.advanceCaret(direction, e);
3036
- }
3037
- } else {
3038
- $tail = self.$control.children('.active:' + tail);
3039
- if ($tail.length) {
3040
- idx = self.$control.children(':not(input)').index($tail);
3041
- self.setActiveItem(null);
3042
- self.setCaret(direction > 0 ? idx + 1 : idx);
3043
- }
3044
- }
3045
- },
3046
-
3047
- /**
3048
- * Moves the caret left / right.
3049
- *
3050
- * @param {int} direction
3051
- * @param {object} e (optional)
3052
- */
3053
- advanceCaret: function(direction, e) {
3054
- var self = this, fn, $adj;
3055
-
3056
- if (direction === 0) return;
3057
-
3058
- fn = direction > 0 ? 'next' : 'prev';
3059
- if (self.isShiftDown) {
3060
- $adj = self.$control_input[fn]();
3061
- if ($adj.length) {
3062
- self.hideInput();
3063
- self.setActiveItem($adj);
3064
- e && e.preventDefault();
3065
- }
3066
- } else {
3067
- self.setCaret(self.caretPos + direction);
3068
- }
3069
- },
3070
-
3071
- /**
3072
- * Moves the caret to the specified index.
3073
- *
3074
- * @param {int} i
3075
- */
3076
- setCaret: function(i) {
3077
- var self = this;
3078
-
3079
- if (self.settings.mode === 'single') {
3080
- i = self.items.length;
3081
- } else {
3082
- i = Math.max(0, Math.min(self.items.length, i));
3083
- }
3084
-
3085
- if(!self.isPending) {
3086
- // the input must be moved by leaving it in place and moving the
3087
- // siblings, due to the fact that focus cannot be restored once lost
3088
- // on mobile webkit devices
3089
- var j, n, fn, $children, $child;
3090
- $children = self.$control.children(':not(input)');
3091
- for (j = 0, n = $children.length; j < n; j++) {
3092
- $child = $($children[j]).detach();
3093
- if (j < i) {
3094
- self.$control_input.before($child);
3095
- } else {
3096
- self.$control.append($child);
3097
- }
3098
- }
3099
- }
3100
-
3101
- self.caretPos = i;
3102
- },
3103
-
3104
- /**
3105
- * Disables user input on the control. Used while
3106
- * items are being asynchronously created.
3107
- */
3108
- lock: function() {
3109
- this.close();
3110
- this.isLocked = true;
3111
- this.refreshState();
3112
- },
3113
-
3114
- /**
3115
- * Re-enables user input on the control.
3116
- */
3117
- unlock: function() {
3118
- this.isLocked = false;
3119
- this.refreshState();
3120
- },
3121
-
3122
- /**
3123
- * Disables user input on the control completely.
3124
- * While disabled, it cannot receive focus.
3125
- */
3126
- disable: function() {
3127
- var self = this;
3128
- self.$input.prop('disabled', true);
3129
- self.$control_input.prop('disabled', true).prop('tabindex', -1);
3130
- self.isDisabled = true;
3131
- self.lock();
3132
- },
3133
-
3134
- /**
3135
- * Enables the control so that it can respond
3136
- * to focus and user input.
3137
- */
3138
- enable: function() {
3139
- var self = this;
3140
- self.$input.prop('disabled', false);
3141
- self.$control_input.prop('disabled', false).prop('tabindex', self.tabIndex);
3142
- self.isDisabled = false;
3143
- self.unlock();
3144
- },
3145
-
3146
- /**
3147
- * Completely destroys the control and
3148
- * unbinds all event listeners so that it can
3149
- * be garbage collected.
3150
- */
3151
- destroy: function() {
3152
- var self = this;
3153
- var eventNS = self.eventNS;
3154
- var revertSettings = self.revertSettings;
3155
-
3156
- self.trigger('destroy');
3157
- self.off();
3158
- self.$wrapper.remove();
3159
- self.$dropdown.remove();
3160
-
3161
- self.$input
3162
- .html('')
3163
- .append(revertSettings.$children)
3164
- .removeAttr('tabindex')
3165
- .removeClass('selectized')
3166
- .attr({tabindex: revertSettings.tabindex})
3167
- .show();
3168
-
3169
- self.$control_input.removeData('grow');
3170
- self.$input.removeData('selectize');
3171
-
3172
- $(window).off(eventNS);
3173
- $(document).off(eventNS);
3174
- $(document.body).off(eventNS);
3175
-
3176
- delete self.$input[0].selectize;
3177
- },
3178
-
3179
- /**
3180
- * A helper method for rendering "item" and
3181
- * "option" templates, given the data.
3182
- *
3183
- * @param {string} templateName
3184
- * @param {object} data
3185
- * @returns {string}
3186
- */
3187
- render: function(templateName, data) {
3188
- var value, id, label;
3189
- var html = '';
3190
- var cache = false;
3191
- var self = this;
3192
- var regex_tag = /^[\t \r\n]*<([a-z][a-z0-9\-_]*(?:\:[a-z][a-z0-9\-_]*)?)/i;
3193
-
3194
- if (templateName === 'option' || templateName === 'item') {
3195
- value = hash_key(data[self.settings.valueField]);
3196
- cache = !!value;
3197
- }
3198
-
3199
- // pull markup from cache if it exists
3200
- if (cache) {
3201
- if (!isset(self.renderCache[templateName])) {
3202
- self.renderCache[templateName] = {};
3203
- }
3204
- if (self.renderCache[templateName].hasOwnProperty(value)) {
3205
- return self.renderCache[templateName][value];
3206
- }
3207
- }
3208
-
3209
- // render markup
3210
- html = $(self.settings.render[templateName].apply(this, [data, escape_html]));
3211
-
3212
- // add mandatory attributes
3213
- if (templateName === 'option' || templateName === 'option_create') {
3214
- html.attr('data-selectable', '');
3215
- }
3216
- else if (templateName === 'optgroup') {
3217
- id = data[self.settings.optgroupValueField] || '';
3218
- html.attr('data-group', id);
3219
- }
3220
- if (templateName === 'option' || templateName === 'item') {
3221
- html.attr('data-value', value || '');
3222
- }
3223
-
3224
- // update cache
3225
- if (cache) {
3226
- self.renderCache[templateName][value] = html[0];
3227
- }
3228
-
3229
- return html[0];
3230
- },
3231
-
3232
- /**
3233
- * Clears the render cache for a template. If
3234
- * no template is given, clears all render
3235
- * caches.
3236
- *
3237
- * @param {string} templateName
3238
- */
3239
- clearCache: function(templateName) {
3240
- var self = this;
3241
- if (typeof templateName === 'undefined') {
3242
- self.renderCache = {};
3243
- } else {
3244
- delete self.renderCache[templateName];
3245
- }
3246
- },
3247
-
3248
- /**
3249
- * Determines whether or not to display the
3250
- * create item prompt, given a user input.
3251
- *
3252
- * @param {string} input
3253
- * @return {boolean}
3254
- */
3255
- canCreate: function(input) {
3256
- var self = this;
3257
- if (!self.settings.create) return false;
3258
- var filter = self.settings.createFilter;
3259
- return input.length
3260
- && (typeof filter !== 'function' || filter.apply(self, [input]))
3261
- && (typeof filter !== 'string' || new RegExp(filter).test(input))
3262
- && (!(filter instanceof RegExp) || filter.test(input));
3263
- }
3264
-
3265
- });
3266
-
3267
-
3268
- Selectize.count = 0;
3269
- Selectize.defaults = {
3270
- options: [],
3271
- optgroups: [],
3272
-
3273
- plugins: [],
3274
- delimiter: ',',
3275
- splitOn: null, // regexp or string for splitting up values from a paste command
3276
- persist: true,
3277
- diacritics: true,
3278
- create: false,
3279
- createOnBlur: false,
3280
- createFilter: null,
3281
- highlight: true,
3282
- openOnFocus: true,
3283
- maxOptions: 1000,
3284
- maxItems: null,
3285
- hideSelected: null,
3286
- addPrecedence: false,
3287
- selectOnTab: false,
3288
- preload: false,
3289
- allowEmptyOption: false,
3290
- closeAfterSelect: false,
3291
-
3292
- scrollDuration: 60,
3293
- loadThrottle: 300,
3294
- loadingClass: 'loading',
3295
-
3296
- dataAttr: 'data-data',
3297
- optgroupField: 'optgroup',
3298
- valueField: 'value',
3299
- labelField: 'text',
3300
- optgroupLabelField: 'label',
3301
- optgroupValueField: 'value',
3302
- lockOptgroupOrder: false,
3303
-
3304
- sortField: '$order',
3305
- searchField: ['text'],
3306
- searchConjunction: 'and',
3307
-
3308
- mode: null,
3309
- wrapperClass: 'selectize-control',
3310
- inputClass: 'selectize-input',
3311
- dropdownClass: 'selectize-dropdown',
3312
- dropdownContentClass: 'selectize-dropdown-content',
3313
-
3314
- dropdownParent: null,
3315
-
3316
- copyClassesToDropdown: true,
3317
-
3318
- /*
3319
- load : null, // function(query, callback) { ... }
3320
- score : null, // function(search) { ... }
3321
- onInitialize : null, // function() { ... }
3322
- onChange : null, // function(value) { ... }
3323
- onItemAdd : null, // function(value, $item) { ... }
3324
- onItemRemove : null, // function(value) { ... }
3325
- onClear : null, // function() { ... }
3326
- onOptionAdd : null, // function(value, data) { ... }
3327
- onOptionRemove : null, // function(value) { ... }
3328
- onOptionClear : null, // function() { ... }
3329
- onOptionGroupAdd : null, // function(id, data) { ... }
3330
- onOptionGroupRemove : null, // function(id) { ... }
3331
- onOptionGroupClear : null, // function() { ... }
3332
- onDropdownOpen : null, // function($dropdown) { ... }
3333
- onDropdownClose : null, // function($dropdown) { ... }
3334
- onType : null, // function(str) { ... }
3335
- onDelete : null, // function(values) { ... }
3336
- */
3337
-
3338
- render: {
3339
- /*
3340
- item: null,
3341
- optgroup: null,
3342
- optgroup_header: null,
3343
- option: null,
3344
- option_create: null
3345
- */
3346
- }
3347
- };
3348
-
3349
-
3350
- $.fn.selectize = function(settings_user) {
3351
- var defaults = $.fn.selectize.defaults;
3352
- var settings = $.extend({}, defaults, settings_user);
3353
- var attr_data = settings.dataAttr;
3354
- var field_label = settings.labelField;
3355
- var field_value = settings.valueField;
3356
- var field_optgroup = settings.optgroupField;
3357
- var field_optgroup_label = settings.optgroupLabelField;
3358
- var field_optgroup_value = settings.optgroupValueField;
3359
-
3360
- /**
3361
- * Initializes selectize from a <input type="text"> element.
3362
- *
3363
- * @param {object} $input
3364
- * @param {object} settings_element
3365
- */
3366
- var init_textbox = function($input, settings_element) {
3367
- var i, n, values, option;
3368
-
3369
- var data_raw = $input.attr(attr_data);
3370
-
3371
- if (!data_raw) {
3372
- var value = $.trim($input.val() || '');
3373
- if (!settings.allowEmptyOption && !value.length) return;
3374
- values = value.split(settings.delimiter);
3375
- for (i = 0, n = values.length; i < n; i++) {
3376
- option = {};
3377
- option[field_label] = values[i];
3378
- option[field_value] = values[i];
3379
- settings_element.options.push(option);
3380
- }
3381
- settings_element.items = values;
3382
- } else {
3383
- settings_element.options = JSON.parse(data_raw);
3384
- for (i = 0, n = settings_element.options.length; i < n; i++) {
3385
- settings_element.items.push(settings_element.options[i][field_value]);
3386
- }
3387
- }
3388
- };
3389
-
3390
- /**
3391
- * Initializes selectize from a <select> element.
3392
- *
3393
- * @param {object} $input
3394
- * @param {object} settings_element
3395
- */
3396
- var init_select = function($input, settings_element) {
3397
- var i, n, tagName, $children, order = 0;
3398
- var options = settings_element.options;
3399
- var optionsMap = {};
3400
-
3401
- var readData = function($el) {
3402
- var data = attr_data && $el.attr(attr_data);
3403
- if (typeof data === 'string' && data.length) {
3404
- return JSON.parse(data);
3405
- }
3406
- return null;
3407
- };
3408
-
3409
- var addOption = function($option, group) {
3410
- $option = $($option);
3411
-
3412
- var value = hash_key($option.val());
3413
- if (!value && !settings.allowEmptyOption) return;
3414
-
3415
- // if the option already exists, it's probably been
3416
- // duplicated in another optgroup. in this case, push
3417
- // the current group to the "optgroup" property on the
3418
- // existing option so that it's rendered in both places.
3419
- if (optionsMap.hasOwnProperty(value)) {
3420
- if (group) {
3421
- var arr = optionsMap[value][field_optgroup];
3422
- if (!arr) {
3423
- optionsMap[value][field_optgroup] = group;
3424
- } else if (!$.isArray(arr)) {
3425
- optionsMap[value][field_optgroup] = [arr, group];
3426
- } else {
3427
- arr.push(group);
3428
- }
3429
- }
3430
- return;
3431
- }
3432
-
3433
- var option = readData($option) || {};
3434
- option[field_label] = option[field_label] || $option.text();
3435
- option[field_value] = option[field_value] || value;
3436
- option[field_optgroup] = option[field_optgroup] || group;
3437
-
3438
- optionsMap[value] = option;
3439
- options.push(option);
3440
-
3441
- if ($option.is(':selected')) {
3442
- settings_element.items.push(value);
3443
- }
3444
- };
3445
-
3446
- var addGroup = function($optgroup) {
3447
- var i, n, id, optgroup, $options;
3448
-
3449
- $optgroup = $($optgroup);
3450
- id = $optgroup.attr('label');
3451
-
3452
- if (id) {
3453
- optgroup = readData($optgroup) || {};
3454
- optgroup[field_optgroup_label] = id;
3455
- optgroup[field_optgroup_value] = id;
3456
- settings_element.optgroups.push(optgroup);
3457
- }
3458
-
3459
- $options = $('option', $optgroup);
3460
- for (i = 0, n = $options.length; i < n; i++) {
3461
- addOption($options[i], id);
3462
- }
3463
- };
3464
-
3465
- settings_element.maxItems = $input.attr('multiple') ? null : 1;
3466
-
3467
- $children = $input.children();
3468
- for (i = 0, n = $children.length; i < n; i++) {
3469
- tagName = $children[i].tagName.toLowerCase();
3470
- if (tagName === 'optgroup') {
3471
- addGroup($children[i]);
3472
- } else if (tagName === 'option') {
3473
- addOption($children[i]);
3474
- }
3475
- }
3476
- };
3477
-
3478
- return this.each(function() {
3479
- if (this.selectize) return;
3480
-
3481
- var instance;
3482
- var $input = $(this);
3483
- var tag_name = this.tagName.toLowerCase();
3484
- var placeholder = $input.attr('placeholder') || $input.attr('data-placeholder');
3485
- if (!placeholder && !settings.allowEmptyOption) {
3486
- placeholder = $input.children('option[value=""]').text();
3487
- }
3488
-
3489
- var settings_element = {
3490
- 'placeholder' : placeholder,
3491
- 'options' : [],
3492
- 'optgroups' : [],
3493
- 'items' : []
3494
- };
3495
-
3496
- if (tag_name === 'select') {
3497
- init_select($input, settings_element);
3498
- } else {
3499
- init_textbox($input, settings_element);
3500
- }
3501
-
3502
- instance = new Selectize($input, $.extend(true, {}, defaults, settings_element, settings_user));
3503
- });
3504
- };
3505
-
3506
- $.fn.selectize.defaults = Selectize.defaults;
3507
- $.fn.selectize.support = {
3508
- validity: SUPPORTS_VALIDITY_API
3509
- };
3510
-
3511
-
3512
- Selectize.define('drag_drop', function(options) {
3513
- if (!$.fn.sortable) throw new Error('The "drag_drop" plugin requires jQuery UI "sortable".');
3514
- if (this.settings.mode !== 'multi') return;
3515
- var self = this;
3516
-
3517
- self.lock = (function() {
3518
- var original = self.lock;
3519
- return function() {
3520
- var sortable = self.$control.data('sortable');
3521
- if (sortable) sortable.disable();
3522
- return original.apply(self, arguments);
3523
- };
3524
- })();
3525
-
3526
- self.unlock = (function() {
3527
- var original = self.unlock;
3528
- return function() {
3529
- var sortable = self.$control.data('sortable');
3530
- if (sortable) sortable.enable();
3531
- return original.apply(self, arguments);
3532
- };
3533
- })();
3534
-
3535
- self.setup = (function() {
3536
- var original = self.setup;
3537
- return function() {
3538
- original.apply(this, arguments);
3539
-
3540
- var $control = self.$control.sortable({
3541
- items: '[data-value]',
3542
- forcePlaceholderSize: true,
3543
- disabled: self.isLocked,
3544
- start: function(e, ui) {
3545
- ui.placeholder.css('width', ui.helper.css('width'));
3546
- $control.css({overflow: 'visible'});
3547
- },
3548
- stop: function() {
3549
- $control.css({overflow: 'hidden'});
3550
- var active = self.$activeItems ? self.$activeItems.slice() : null;
3551
- var values = [];
3552
- $control.children('[data-value]').each(function() {
3553
- values.push($(this).attr('data-value'));
3554
- });
3555
- self.setValue(values);
3556
- self.setActiveItem(active);
3557
- }
3558
- });
3559
- };
3560
- })();
3561
-
3562
- });
3563
-
3564
- Selectize.define('dropdown_header', function(options) {
3565
- var self = this;
3566
-
3567
- options = $.extend({
3568
- title : 'Untitled',
3569
- headerClass : 'selectize-dropdown-header',
3570
- titleRowClass : 'selectize-dropdown-header-title',
3571
- labelClass : 'selectize-dropdown-header-label',
3572
- closeClass : 'selectize-dropdown-header-close',
3573
-
3574
- html: function(data) {
3575
- return (
3576
- '<div class="' + data.headerClass + '">' +
3577
- '<div class="' + data.titleRowClass + '">' +
3578
- '<span class="' + data.labelClass + '">' + data.title + '</span>' +
3579
- '<a href="javascript:void(0)" class="' + data.closeClass + '">&times;</a>' +
3580
- '</div>' +
3581
- '</div>'
3582
- );
3583
- }
3584
- }, options);
3585
-
3586
- self.setup = (function() {
3587
- var original = self.setup;
3588
- return function() {
3589
- original.apply(self, arguments);
3590
- self.$dropdown_header = $(options.html(options));
3591
- self.$dropdown.prepend(self.$dropdown_header);
3592
- };
3593
- })();
3594
-
3595
- });
3596
-
3597
- Selectize.define('optgroup_columns', function(options) {
3598
- var self = this;
3599
-
3600
- options = $.extend({
3601
- equalizeWidth : true,
3602
- equalizeHeight : true
3603
- }, options);
3604
-
3605
- this.getAdjacentOption = function($option, direction) {
3606
- var $options = $option.closest('[data-group]').find('[data-selectable]');
3607
- var index = $options.index($option) + direction;
3608
-
3609
- return index >= 0 && index < $options.length ? $options.eq(index) : $();
3610
- };
3611
-
3612
- this.onKeyDown = (function() {
3613
- var original = self.onKeyDown;
3614
- return function(e) {
3615
- var index, $option, $options, $optgroup;
3616
-
3617
- if (this.isOpen && (e.keyCode === KEY_LEFT || e.keyCode === KEY_RIGHT)) {
3618
- self.ignoreHover = true;
3619
- $optgroup = this.$activeOption.closest('[data-group]');
3620
- index = $optgroup.find('[data-selectable]').index(this.$activeOption);
3621
-
3622
- if(e.keyCode === KEY_LEFT) {
3623
- $optgroup = $optgroup.prev('[data-group]');
3624
- } else {
3625
- $optgroup = $optgroup.next('[data-group]');
3626
- }
3627
-
3628
- $options = $optgroup.find('[data-selectable]');
3629
- $option = $options.eq(Math.min($options.length - 1, index));
3630
- if ($option.length) {
3631
- this.setActiveOption($option);
3632
- }
3633
- return;
3634
- }
3635
-
3636
- return original.apply(this, arguments);
3637
- };
3638
- })();
3639
-
3640
- var getScrollbarWidth = function() {
3641
- var div;
3642
- var width = getScrollbarWidth.width;
3643
- var doc = document;
3644
-
3645
- if (typeof width === 'undefined') {
3646
- div = doc.createElement('div');
3647
- div.innerHTML = '<div style="width:50px;height:50px;position:absolute;left:-50px;top:-50px;overflow:auto;"><div style="width:1px;height:100px;"></div></div>';
3648
- div = div.firstChild;
3649
- doc.body.appendChild(div);
3650
- width = getScrollbarWidth.width = div.offsetWidth - div.clientWidth;
3651
- doc.body.removeChild(div);
3652
- }
3653
- return width;
3654
- };
3655
-
3656
- var equalizeSizes = function() {
3657
- var i, n, height_max, width, width_last, width_parent, $optgroups;
3658
-
3659
- $optgroups = $('[data-group]', self.$dropdown_content);
3660
- n = $optgroups.length;
3661
- if (!n || !self.$dropdown_content.width()) return;
3662
-
3663
- if (options.equalizeHeight) {
3664
- height_max = 0;
3665
- for (i = 0; i < n; i++) {
3666
- height_max = Math.max(height_max, $optgroups.eq(i).height());
3667
- }
3668
- $optgroups.css({height: height_max});
3669
- }
3670
-
3671
- if (options.equalizeWidth) {
3672
- width_parent = self.$dropdown_content.innerWidth() - getScrollbarWidth();
3673
- width = Math.round(width_parent / n);
3674
- $optgroups.css({width: width});
3675
- if (n > 1) {
3676
- width_last = width_parent - width * (n - 1);
3677
- $optgroups.eq(n - 1).css({width: width_last});
3678
- }
3679
- }
3680
- };
3681
-
3682
- if (options.equalizeHeight || options.equalizeWidth) {
3683
- hook.after(this, 'positionDropdown', equalizeSizes);
3684
- hook.after(this, 'refreshOptions', equalizeSizes);
3685
- }
3686
-
3687
-
3688
- });
3689
-
3690
- Selectize.define('remove_button', function(options) {
3691
- options = $.extend({
3692
- label : '&times;',
3693
- title : 'Remove',
3694
- className : 'remove',
3695
- append : true
3696
- }, options);
3697
-
3698
- var singleClose = function(thisRef, options) {
3699
-
3700
- options.className = 'remove-single';
3701
-
3702
- var self = thisRef;
3703
- var html = '<a href="javascript:void(0)" class="' + options.className + '" tabindex="-1" title="' + escape_html(options.title) + '">' + options.label + '</a>';
3704
-
3705
- /**
3706
- * Appends an element as a child (with raw HTML).
3707
- *
3708
- * @param {string} html_container
3709
- * @param {string} html_element
3710
- * @return {string}
3711
- */
3712
- var append = function(html_container, html_element) {
3713
- return html_container + html_element;
3714
- };
3715
-
3716
- thisRef.setup = (function() {
3717
- var original = self.setup;
3718
- return function() {
3719
- // override the item rendering method to add the button to each
3720
- if (options.append) {
3721
- var id = $(self.$input.context).attr('id');
3722
- var selectizer = $('#'+id);
3723
-
3724
- var render_item = self.settings.render.item;
3725
- self.settings.render.item = function(data) {
3726
- return append(render_item.apply(thisRef, arguments), html);
3727
- };
3728
- }
3729
-
3730
- original.apply(thisRef, arguments);
3731
-
3732
- // add event listener
3733
- thisRef.$control.on('click', '.' + options.className, function(e) {
3734
- e.preventDefault();
3735
- if (self.isLocked) return;
3736
-
3737
- self.clear();
3738
- });
3739
-
3740
- };
3741
- })();
3742
- };
3743
-
3744
- var multiClose = function(thisRef, options) {
3745
-
3746
- var self = thisRef;
3747
- var html = '<a href="javascript:void(0)" class="' + options.className + '" tabindex="-1" title="' + escape_html(options.title) + '">' + options.label + '</a>';
3748
-
3749
- /**
3750
- * Appends an element as a child (with raw HTML).
3751
- *
3752
- * @param {string} html_container
3753
- * @param {string} html_element
3754
- * @return {string}
3755
- */
3756
- var append = function(html_container, html_element) {
3757
- var pos = html_container.search(/(<\/[^>]+>\s*)$/);
3758
- return html_container.substring(0, pos) + html_element + html_container.substring(pos);
3759
- };
3760
-
3761
- thisRef.setup = (function() {
3762
- var original = self.setup;
3763
- return function() {
3764
- // override the item rendering method to add the button to each
3765
- if (options.append) {
3766
- var render_item = self.settings.render.item;
3767
- self.settings.render.item = function(data) {
3768
- return append(render_item.apply(thisRef, arguments), html);
3769
- };
3770
- }
3771
-
3772
- original.apply(thisRef, arguments);
3773
-
3774
- // add event listener
3775
- thisRef.$control.on('click', '.' + options.className, function(e) {
3776
- e.preventDefault();
3777
- if (self.isLocked) return;
3778
-
3779
- var $item = $(e.currentTarget).parent();
3780
- self.setActiveItem($item);
3781
- if (self.deleteSelection()) {
3782
- self.setCaret(self.items.length);
3783
- }
3784
- });
3785
-
3786
- };
3787
- })();
3788
- };
3789
-
3790
- if (this.settings.mode === 'single') {
3791
- singleClose(this, options);
3792
- return;
3793
- } else {
3794
- multiClose(this, options);
3795
- }
3796
- });
3797
-
3798
-
3799
- Selectize.define('restore_on_backspace', function(options) {
3800
- var self = this;
3801
-
3802
- options.text = options.text || function(option) {
3803
- return option[this.settings.labelField];
3804
- };
3805
-
3806
- this.onKeyDown = (function() {
3807
- var original = self.onKeyDown;
3808
- return function(e) {
3809
- var index, option;
3810
- if (e.keyCode === KEY_BACKSPACE && this.$control_input.val() === '' && !this.$activeItems.length) {
3811
- index = this.caretPos - 1;
3812
- if (index >= 0 && index < this.items.length) {
3813
- option = this.options[this.items[index]];
3814
- if (this.deleteSelection(e)) {
3815
- this.setTextboxValue(options.text.apply(this, [option]));
3816
- this.refreshOptions(true);
3817
- }
3818
- e.preventDefault();
3819
- return;
3820
- }
3821
- }
3822
- return original.apply(this, arguments);
3823
- };
3824
- })();
3825
- });
3826
-
3827
-
3828
- return Selectize;
3829
- }));
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});