bootstrap_tokenfield_rails 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a99164ca4c75845c6e28ebbf78eeade419aedefe
|
4
|
+
data.tar.gz: b72c6367bc12f6d3bd9539888c076df50b28f02f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 92a5cd5a835202b06661c05920d01fe4b2d6e7e315e379240abdfcba0e2bec2e705aa3544f7e86d209c8efcca0e05f54f6c6e4e40652d5412fe46a9f41121bba
|
7
|
+
data.tar.gz: af2ed1bfee6c48ce218239f58903e704f69e8849bbeee818b73f93786a67eaff786dab9c47965f64e2c851c7cdb6b3b96d6b6e0f28bc8fbced31d1c873fca147
|
@@ -25,7 +25,7 @@
|
|
25
25
|
};
|
26
26
|
} else {
|
27
27
|
// Browser globals
|
28
|
-
factory(jQuery);
|
28
|
+
factory(jQuery, window);
|
29
29
|
}
|
30
30
|
}(function ($, window) {
|
31
31
|
|
@@ -63,9 +63,9 @@
|
|
63
63
|
}
|
64
64
|
|
65
65
|
var specialCharacters = ['\\', '$', '[', '{', '^', '.', '|', '?', '*', '+', '(', ')']
|
66
|
-
$.each(this._delimiters, function (index,
|
67
|
-
var pos = $.inArray(
|
68
|
-
if (pos >= 0) _self._delimiters[index] = '\\' +
|
66
|
+
$.each(this._delimiters, function (index, character) {
|
67
|
+
var pos = $.inArray(character, specialCharacters)
|
68
|
+
if (pos >= 0) _self._delimiters[index] = '\\' + character;
|
69
69
|
});
|
70
70
|
|
71
71
|
// Store original input width
|
@@ -102,7 +102,7 @@
|
|
102
102
|
|
103
103
|
// Create a new input
|
104
104
|
var id = this.$element.prop('id') || new Date().getTime() + '' + Math.floor((1 + Math.random()) * 100)
|
105
|
-
this.$input = $('<input type="
|
105
|
+
this.$input = $('<input type="'+this.options.inputType+'" class="token-input" autocomplete="off" />')
|
106
106
|
.appendTo( this.$wrapper )
|
107
107
|
.prop( 'placeholder', this.$element.prop('placeholder') )
|
108
108
|
.prop( 'id', id + '-tokenfield' )
|
@@ -134,6 +134,11 @@
|
|
134
134
|
this.disable();
|
135
135
|
}
|
136
136
|
|
137
|
+
// Set tokenfield readonly, if original input is readonly
|
138
|
+
if (this.$element.prop('readonly')) {
|
139
|
+
this.readonly();
|
140
|
+
}
|
141
|
+
|
137
142
|
// Set up mirror for input auto-sizing
|
138
143
|
this.$mirror = $('<span style="position:absolute; top:-999px; left:0; white-space:pre;"/>');
|
139
144
|
this.$input.css('min-width', this.options.minWidth + 'px')
|
@@ -159,7 +164,7 @@
|
|
159
164
|
this.update()
|
160
165
|
|
161
166
|
// Create initial tokens, if any
|
162
|
-
this.setTokens(this.options.tokens, false,
|
167
|
+
this.setTokens(this.options.tokens, false, ! this.$element.val() && this.options.tokens )
|
163
168
|
|
164
169
|
// Start listening to events
|
165
170
|
this.listen()
|
@@ -167,23 +172,28 @@
|
|
167
172
|
// Initialize autocomplete, if necessary
|
168
173
|
if ( ! $.isEmptyObject( this.options.autocomplete ) ) {
|
169
174
|
var side = this.textDirection === 'rtl' ? 'right' : 'left'
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
175
|
+
, autocompleteOptions = $.extend({
|
176
|
+
minLength: this.options.showAutocompleteOnFocus ? 0 : null,
|
177
|
+
position: { my: side + " top", at: side + " bottom", of: this.$wrapper }
|
178
|
+
}, this.options.autocomplete )
|
179
|
+
|
174
180
|
this.$input.autocomplete( autocompleteOptions )
|
175
181
|
}
|
176
182
|
|
177
183
|
// Initialize typeahead, if necessary
|
178
184
|
if ( ! $.isEmptyObject( this.options.typeahead ) ) {
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
185
|
+
|
186
|
+
var typeaheadOptions = this.options.typeahead
|
187
|
+
, defaults = {
|
188
|
+
minLength: this.options.showAutocompleteOnFocus ? 0 : null
|
189
|
+
}
|
190
|
+
, args = $.isArray( typeaheadOptions ) ? typeaheadOptions : [typeaheadOptions, typeaheadOptions]
|
191
|
+
|
192
|
+
args[0] = $.extend( {}, defaults, args[0] )
|
193
|
+
|
194
|
+
this.$input.typeahead.apply( this.$input, args )
|
183
195
|
this.typeahead = true
|
184
196
|
}
|
185
|
-
|
186
|
-
this.$element.trigger('tokenfield:initialize')
|
187
197
|
}
|
188
198
|
|
189
199
|
Tokenfield.prototype = {
|
@@ -191,130 +201,119 @@
|
|
191
201
|
constructor: Tokenfield
|
192
202
|
|
193
203
|
, createToken: function (attrs, triggerChange) {
|
204
|
+
var _self = this
|
205
|
+
|
194
206
|
if (typeof attrs === 'string') {
|
195
207
|
attrs = { value: attrs, label: attrs }
|
208
|
+
} else {
|
209
|
+
// Copy objects to prevent contamination of data sources.
|
210
|
+
attrs = $.extend( {}, attrs )
|
196
211
|
}
|
197
212
|
|
198
|
-
|
213
|
+
if (typeof triggerChange === 'undefined') {
|
199
214
|
triggerChange = true
|
200
|
-
|
215
|
+
}
|
201
216
|
|
202
|
-
|
203
|
-
|
204
|
-
|
217
|
+
// Normalize label and value
|
218
|
+
attrs.value = $.trim(attrs.value.toString());
|
219
|
+
attrs.label = attrs.label && attrs.label.length ? $.trim(attrs.label) : attrs.value
|
205
220
|
|
206
|
-
if
|
221
|
+
// Bail out if has no value or label, or label is too short
|
222
|
+
if (!attrs.value.length || !attrs.label.length || attrs.label.length <= this.options.minLength) return
|
207
223
|
|
224
|
+
// Bail out if maximum number of tokens is reached
|
208
225
|
if (this.options.limit && this.getTokens().length >= this.options.limit) return
|
209
226
|
|
210
227
|
// Allow changing token data before creating it
|
211
|
-
var
|
212
|
-
|
213
|
-
value: value,
|
214
|
-
label: label
|
215
|
-
}
|
216
|
-
this.$element.trigger( prepareEvent )
|
217
|
-
|
218
|
-
if (!prepareEvent.token) return
|
219
|
-
|
220
|
-
value = prepareEvent.token.value
|
221
|
-
label = prepareEvent.token.label
|
222
|
-
|
223
|
-
// Check for duplicates
|
224
|
-
if (!this.options.allowDuplicates && $.grep(this.getTokens(), function (token) {
|
225
|
-
return token.value === value
|
226
|
-
}).length) {
|
227
|
-
// Allow listening to when duplicates get prevented
|
228
|
-
var preventDuplicateEvent = $.Event('tokenfield:preventduplicate')
|
229
|
-
preventDuplicateEvent.token = {
|
230
|
-
value: value,
|
231
|
-
label: label
|
232
|
-
}
|
233
|
-
this.$element.trigger( preventDuplicateEvent )
|
234
|
-
// Add duplicate warning class to existing token for 250ms
|
235
|
-
var duplicate = this.$wrapper.find( '.token[data-value="' + value + '"]' ).addClass('duplicate')
|
236
|
-
setTimeout(function() {
|
237
|
-
duplicate.removeClass('duplicate');
|
238
|
-
}, 250)
|
239
|
-
return false
|
240
|
-
}
|
228
|
+
var createEvent = $.Event('tokenfield:createtoken', { attrs: attrs })
|
229
|
+
this.$element.trigger(createEvent)
|
241
230
|
|
242
|
-
|
243
|
-
|
231
|
+
// Bail out if there if attributes are empty or event was defaultPrevented
|
232
|
+
if (!createEvent.attrs || createEvent.isDefaultPrevented()) return
|
233
|
+
|
234
|
+
var $token = $('<div class="token" />')
|
244
235
|
.append('<span class="token-label" />')
|
245
236
|
.append('<a href="#" class="close" tabindex="-1">×</a>')
|
237
|
+
.data('attrs', attrs)
|
246
238
|
|
247
239
|
// Insert token into HTML
|
248
240
|
if (this.$input.hasClass('tt-input')) {
|
249
|
-
|
241
|
+
// If the input has typeahead enabled, insert token before it's parent
|
242
|
+
this.$input.parent().before( $token )
|
250
243
|
} else {
|
251
|
-
this.$input.before( token )
|
244
|
+
this.$input.before( $token )
|
252
245
|
}
|
246
|
+
|
247
|
+
// Temporarily set input width to minimum
|
253
248
|
this.$input.css('width', this.options.minWidth + 'px')
|
254
249
|
|
255
|
-
var tokenLabel = token.find('.token-label')
|
256
|
-
, closeButton = token.find('.close')
|
250
|
+
var $tokenLabel = $token.find('.token-label')
|
251
|
+
, $closeButton = $token.find('.close')
|
257
252
|
|
258
253
|
// Determine maximum possible token label width
|
259
254
|
if (!this.maxTokenWidth) {
|
260
255
|
this.maxTokenWidth =
|
261
|
-
this.$wrapper.width() - closeButton.outerWidth() -
|
262
|
-
parseInt(closeButton.css('margin-left'), 10) -
|
263
|
-
parseInt(closeButton.css('margin-right'), 10) -
|
264
|
-
parseInt(token.css('border-left-width'), 10) -
|
265
|
-
parseInt(token.css('border-right-width'), 10) -
|
266
|
-
parseInt(token.css('padding-left'), 10) -
|
267
|
-
parseInt(token.css('padding-right'), 10)
|
268
|
-
parseInt(tokenLabel.css('border-left-width'), 10) -
|
269
|
-
parseInt(tokenLabel.css('border-right-width'), 10) -
|
270
|
-
parseInt(tokenLabel.css('padding-left'), 10) -
|
271
|
-
parseInt(tokenLabel.css('padding-right'), 10)
|
272
|
-
parseInt(tokenLabel.css('margin-left'), 10) -
|
273
|
-
parseInt(tokenLabel.css('margin-right'), 10)
|
274
|
-
}
|
275
|
-
|
276
|
-
tokenLabel
|
277
|
-
.text(label)
|
256
|
+
this.$wrapper.width() - $closeButton.outerWidth() -
|
257
|
+
parseInt($closeButton.css('margin-left'), 10) -
|
258
|
+
parseInt($closeButton.css('margin-right'), 10) -
|
259
|
+
parseInt($token.css('border-left-width'), 10) -
|
260
|
+
parseInt($token.css('border-right-width'), 10) -
|
261
|
+
parseInt($token.css('padding-left'), 10) -
|
262
|
+
parseInt($token.css('padding-right'), 10)
|
263
|
+
parseInt($tokenLabel.css('border-left-width'), 10) -
|
264
|
+
parseInt($tokenLabel.css('border-right-width'), 10) -
|
265
|
+
parseInt($tokenLabel.css('padding-left'), 10) -
|
266
|
+
parseInt($tokenLabel.css('padding-right'), 10)
|
267
|
+
parseInt($tokenLabel.css('margin-left'), 10) -
|
268
|
+
parseInt($tokenLabel.css('margin-right'), 10)
|
269
|
+
}
|
270
|
+
|
271
|
+
$tokenLabel
|
272
|
+
.text(attrs.label)
|
278
273
|
.css('max-width', this.maxTokenWidth)
|
279
274
|
|
280
|
-
// Listen to events
|
281
|
-
token
|
275
|
+
// Listen to events on token
|
276
|
+
$token
|
282
277
|
.on('mousedown', function (e) {
|
283
|
-
if (_self.
|
278
|
+
if (_self._disabled || _self._readonly) return false
|
284
279
|
_self.preventDeactivation = true
|
285
280
|
})
|
286
281
|
.on('click', function (e) {
|
287
|
-
if (_self.
|
282
|
+
if (_self._disabled || _self._readonly) return false
|
288
283
|
_self.preventDeactivation = false
|
289
284
|
|
290
285
|
if (e.ctrlKey || e.metaKey) {
|
291
286
|
e.preventDefault()
|
292
|
-
return _self.toggle( token )
|
287
|
+
return _self.toggle( $token )
|
293
288
|
}
|
294
289
|
|
295
|
-
_self.activate( token, e.shiftKey, e.shiftKey )
|
290
|
+
_self.activate( $token, e.shiftKey, e.shiftKey )
|
296
291
|
})
|
297
292
|
.on('dblclick', function (e) {
|
298
|
-
if (_self.
|
299
|
-
_self.edit( token )
|
293
|
+
if (_self._disabled || _self._readonly || !_self.options.allowEditing ) return false
|
294
|
+
_self.edit( $token )
|
300
295
|
})
|
301
296
|
|
302
|
-
closeButton
|
297
|
+
$closeButton
|
303
298
|
.on('click', $.proxy(this.remove, this))
|
304
299
|
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
300
|
+
// Trigger createdtoken event on the original field
|
301
|
+
// indicating that the token is now in the DOM
|
302
|
+
this.$element.trigger($.Event('tokenfield:createdtoken', {
|
303
|
+
attrs: attrs,
|
304
|
+
relatedTarget: $token.get(0)
|
305
|
+
}))
|
309
306
|
|
310
|
-
|
311
|
-
changeEvent.initiator = 'tokenfield'
|
307
|
+
// Trigger change event on the original field
|
312
308
|
if (triggerChange) {
|
313
|
-
this.$element.val( this.getTokensList() ).trigger(
|
309
|
+
this.$element.val( this.getTokensList() ).trigger( $.Event('change', { initiator: 'tokenfield' }) )
|
314
310
|
}
|
311
|
+
|
312
|
+
// Update tokenfield dimensions
|
315
313
|
this.update()
|
316
314
|
|
317
|
-
|
315
|
+
// Return original element
|
316
|
+
return this.$element.get(0)
|
318
317
|
}
|
319
318
|
|
320
319
|
, setTokens: function (tokens, add, triggerChange) {
|
@@ -336,20 +335,17 @@
|
|
336
335
|
}
|
337
336
|
|
338
337
|
var _self = this
|
339
|
-
$.each(tokens, function (i,
|
340
|
-
_self.createToken(
|
338
|
+
$.each(tokens, function (i, attrs) {
|
339
|
+
_self.createToken(attrs, triggerChange)
|
341
340
|
})
|
342
341
|
|
343
342
|
return this.$element.get(0)
|
344
343
|
}
|
345
344
|
|
346
|
-
, getTokenData: function(token) {
|
347
|
-
var data = token.map(function() {
|
345
|
+
, getTokenData: function($token) {
|
346
|
+
var data = $token.map(function() {
|
348
347
|
var $token = $(this);
|
349
|
-
return
|
350
|
-
value: $token.attr('data-value'),
|
351
|
-
label: $token.find('.token-label').text()
|
352
|
-
}
|
348
|
+
return $token.data('attrs')
|
353
349
|
}).get();
|
354
350
|
|
355
351
|
if (data.length == 1) {
|
@@ -431,7 +427,7 @@
|
|
431
427
|
}
|
432
428
|
return false
|
433
429
|
})
|
434
|
-
.on('typeahead:selected', function (e, datum, dataset) {
|
430
|
+
.on('typeahead:selected typeahead:autocompleted', function (e, datum, dataset) {
|
435
431
|
// Create token
|
436
432
|
if (_self.createToken( datum )) {
|
437
433
|
_self.$input.typeahead('val', '')
|
@@ -440,13 +436,6 @@
|
|
440
436
|
}
|
441
437
|
}
|
442
438
|
})
|
443
|
-
.on('typeahead:autocompleted', function (e, datum, dataset) {
|
444
|
-
_self.createToken( _self.$input.val() )
|
445
|
-
_self.$input.typeahead('val', '')
|
446
|
-
if (_self.$input.data( 'edit' )) {
|
447
|
-
_self.unedit(true)
|
448
|
-
}
|
449
|
-
})
|
450
439
|
|
451
440
|
// Listen to window resize
|
452
441
|
$(window).on('resize', $.proxy(this.update, this ))
|
@@ -491,11 +480,11 @@
|
|
491
480
|
case 13: // enter
|
492
481
|
|
493
482
|
// We will handle creating tokens from autocomplete in autocomplete events
|
494
|
-
if (this.$input.data('ui-autocomplete') && this.$input.data('ui-autocomplete').menu.element.find("li:has(a.ui-state-focus)").length) break
|
483
|
+
if (this.$input.data('ui-autocomplete') && this.$input.data('ui-autocomplete').menu.element.find("li:has(a.ui-state-focus), li.ui-state-focus").length) break
|
495
484
|
|
496
485
|
// We will handle creating tokens from typeahead in typeahead events
|
497
486
|
if (this.$input.hasClass('tt-input') && this.$wrapper.find('.tt-cursor').length ) break
|
498
|
-
if (this.$input.hasClass('tt-input') && this.$wrapper.find('.tt-hint').val().length) break
|
487
|
+
if (this.$input.hasClass('tt-input') && this.$wrapper.find('.tt-hint').val() && this.$wrapper.find('.tt-hint').val().length) break
|
499
488
|
|
500
489
|
// Create token
|
501
490
|
if (this.$input.is(document.activeElement) && this.$input.val().length || this.$input.data('edit')) {
|
@@ -515,13 +504,13 @@
|
|
515
504
|
if (_self.$input.val().length > 0) return
|
516
505
|
|
517
506
|
direction += 'All'
|
518
|
-
var token = _self.$input.hasClass('tt-input') ? _self.$input.parent()[direction]('.token:first') : _self.$input[direction]('.token:first')
|
519
|
-
if (
|
507
|
+
var $token = _self.$input.hasClass('tt-input') ? _self.$input.parent()[direction]('.token:first') : _self.$input[direction]('.token:first')
|
508
|
+
if (!$token.length) return
|
520
509
|
|
521
510
|
_self.preventInputFocus = true
|
522
511
|
_self.preventDeactivation = true
|
523
512
|
|
524
|
-
_self.activate( token )
|
513
|
+
_self.activate( $token )
|
525
514
|
e.preventDefault()
|
526
515
|
|
527
516
|
} else {
|
@@ -536,16 +525,16 @@
|
|
536
525
|
if (_self.$input.is(document.activeElement)) {
|
537
526
|
if (_self.$input.val().length > 0) return
|
538
527
|
|
539
|
-
var token = _self.$input.hasClass('tt-input') ? _self.$input.parent()[direction + 'All']('.token:first') : _self.$input[direction + 'All']('.token:first')
|
540
|
-
if (
|
528
|
+
var $token = _self.$input.hasClass('tt-input') ? _self.$input.parent()[direction + 'All']('.token:first') : _self.$input[direction + 'All']('.token:first')
|
529
|
+
if (!$token.length) return
|
541
530
|
|
542
|
-
_self.activate( token )
|
531
|
+
_self.activate( $token )
|
543
532
|
}
|
544
533
|
|
545
534
|
var opposite = direction === 'prev' ? 'next' : 'prev'
|
546
535
|
, position = direction === 'prev' ? 'first' : 'last'
|
547
536
|
|
548
|
-
_self
|
537
|
+
_self.$firstActiveToken[opposite + 'All']('.token').each(function() {
|
549
538
|
_self.deactivate( $(this) )
|
550
539
|
})
|
551
540
|
|
@@ -557,11 +546,9 @@
|
|
557
546
|
}
|
558
547
|
|
559
548
|
, keypress: function(e) {
|
560
|
-
this.lastKeyPressCode = e.keyCode
|
561
|
-
this.lastKeyPressCharCode = e.charCode
|
562
549
|
|
563
550
|
// Comma
|
564
|
-
if ($.inArray( e.
|
551
|
+
if ($.inArray( e.which, this._triggerKeys) !== -1 && this.$input.is(document.activeElement)) {
|
565
552
|
if (this.$input.val()) {
|
566
553
|
this.createTokensFromInput(e)
|
567
554
|
}
|
@@ -580,11 +567,11 @@
|
|
580
567
|
if (this.$input.val().length || this.lastInputValue.length && this.lastKeyDown === 8) break
|
581
568
|
|
582
569
|
this.preventDeactivation = true
|
583
|
-
var
|
570
|
+
var $prevToken = this.$input.hasClass('tt-input') ? this.$input.parent().prevAll('.token:first') : this.$input.prevAll('.token:first')
|
584
571
|
|
585
|
-
if (
|
572
|
+
if (!$prevToken.length) break
|
586
573
|
|
587
|
-
this.activate(
|
574
|
+
this.activate( $prevToken )
|
588
575
|
} else {
|
589
576
|
this.remove(e)
|
590
577
|
}
|
@@ -603,7 +590,7 @@
|
|
603
590
|
|
604
591
|
if (this.$input.is(document.activeElement)) {
|
605
592
|
this.$wrapper.find('.active').removeClass('active')
|
606
|
-
this
|
593
|
+
this.$firstActiveToken = null
|
607
594
|
|
608
595
|
if (this.options.showAutocompleteOnFocus) {
|
609
596
|
this.search()
|
@@ -618,7 +605,7 @@
|
|
618
605
|
|
619
606
|
if (!this.preventDeactivation && !this.$element.is(document.activeElement)) {
|
620
607
|
this.$wrapper.find('.active').removeClass('active')
|
621
|
-
this
|
608
|
+
this.$firstActiveToken = null
|
622
609
|
}
|
623
610
|
|
624
611
|
if (!this.preventCreateTokens && (this.$input.data('edit') && !this.$input.is(document.activeElement) || this.options.createTokensOnBlur )) {
|
@@ -633,9 +620,11 @@
|
|
633
620
|
var _self = this
|
634
621
|
|
635
622
|
// Add tokens to existing ones
|
636
|
-
|
637
|
-
|
638
|
-
|
623
|
+
if (_self.options.allowPasting) {
|
624
|
+
setTimeout(function () {
|
625
|
+
_self.createTokensFromInput(e)
|
626
|
+
}, 1)
|
627
|
+
}
|
639
628
|
}
|
640
629
|
|
641
630
|
, change: function (e) {
|
@@ -671,52 +660,50 @@
|
|
671
660
|
|
672
661
|
, next: function (add) {
|
673
662
|
if (add) {
|
674
|
-
var
|
675
|
-
, deactivate =
|
663
|
+
var $firstActiveToken = this.$wrapper.find('.active:first')
|
664
|
+
, deactivate = $firstActiveToken && this.$firstActiveToken ? $firstActiveToken.index() < this.$firstActiveToken.index() : false
|
676
665
|
|
677
|
-
if (deactivate) return this.deactivate(
|
666
|
+
if (deactivate) return this.deactivate( $firstActiveToken )
|
678
667
|
}
|
679
668
|
|
680
|
-
var
|
681
|
-
,
|
669
|
+
var $lastActiveToken = this.$wrapper.find('.active:last')
|
670
|
+
, $nextToken = $lastActiveToken.nextAll('.token:first')
|
682
671
|
|
683
|
-
if (
|
672
|
+
if (!$nextToken.length) {
|
684
673
|
this.$input.focus()
|
685
674
|
return
|
686
675
|
}
|
687
676
|
|
688
|
-
this.activate(
|
677
|
+
this.activate($nextToken, add)
|
689
678
|
}
|
690
679
|
|
691
680
|
, prev: function (add) {
|
692
681
|
|
693
682
|
if (add) {
|
694
|
-
var
|
695
|
-
, deactivate =
|
683
|
+
var $lastActiveToken = this.$wrapper.find('.active:last')
|
684
|
+
, deactivate = $lastActiveToken && this.$firstActiveToken ? $lastActiveToken.index() > this.$firstActiveToken.index() : false
|
696
685
|
|
697
|
-
if (deactivate) return this.deactivate(
|
686
|
+
if (deactivate) return this.deactivate( $lastActiveToken )
|
698
687
|
}
|
699
688
|
|
700
|
-
var
|
701
|
-
,
|
689
|
+
var $firstActiveToken = this.$wrapper.find('.active:first')
|
690
|
+
, $prevToken = $firstActiveToken.prevAll('.token:first')
|
702
691
|
|
703
|
-
if (
|
704
|
-
|
692
|
+
if (!$prevToken.length) {
|
693
|
+
$prevToken = this.$wrapper.find('.token:first')
|
705
694
|
}
|
706
695
|
|
707
|
-
if (
|
696
|
+
if (!$prevToken.length && !add) {
|
708
697
|
this.$input.focus()
|
709
698
|
return
|
710
699
|
}
|
711
700
|
|
712
|
-
this.activate(
|
701
|
+
this.activate( $prevToken, add )
|
713
702
|
}
|
714
703
|
|
715
|
-
, activate: function (token, add, multi, remember) {
|
716
|
-
|
717
|
-
if (!token) return
|
704
|
+
, activate: function ($token, add, multi, remember) {
|
718
705
|
|
719
|
-
if (
|
706
|
+
if (!$token) return
|
720
707
|
|
721
708
|
if (typeof remember === 'undefined') var remember = true
|
722
709
|
|
@@ -727,17 +714,17 @@
|
|
727
714
|
if (!add) {
|
728
715
|
this.$wrapper.find('.active').removeClass('active')
|
729
716
|
if (remember) {
|
730
|
-
this
|
717
|
+
this.$firstActiveToken = $token
|
731
718
|
} else {
|
732
|
-
delete this
|
719
|
+
delete this.$firstActiveToken
|
733
720
|
}
|
734
721
|
}
|
735
722
|
|
736
|
-
if (multi && this
|
723
|
+
if (multi && this.$firstActiveToken) {
|
737
724
|
// Determine first active token and the current tokens indicies
|
738
725
|
// Account for the 1 hidden textarea by subtracting 1 from both
|
739
|
-
var i = this
|
740
|
-
, a = token.index() - 2
|
726
|
+
var i = this.$firstActiveToken.index() - 2
|
727
|
+
, a = $token.index() - 2
|
741
728
|
, _self = this
|
742
729
|
|
743
730
|
this.$wrapper.find('.token').slice( Math.min(i, a) + 1, Math.max(i, a) ).each( function() {
|
@@ -745,7 +732,7 @@
|
|
745
732
|
})
|
746
733
|
}
|
747
734
|
|
748
|
-
token.addClass('active')
|
735
|
+
$token.addClass('active')
|
749
736
|
this.$copyHelper.val( this.getTokensList( null, null, true ) ).select()
|
750
737
|
}
|
751
738
|
|
@@ -757,55 +744,51 @@
|
|
757
744
|
})
|
758
745
|
}
|
759
746
|
|
760
|
-
, deactivate: function(token) {
|
761
|
-
if (
|
747
|
+
, deactivate: function($token) {
|
748
|
+
if (!$token) return
|
762
749
|
|
763
|
-
token.removeClass('active')
|
750
|
+
$token.removeClass('active')
|
764
751
|
this.$copyHelper.val( this.getTokensList( null, null, true ) ).select()
|
765
752
|
}
|
766
753
|
|
767
|
-
, toggle: function(token) {
|
768
|
-
if (
|
754
|
+
, toggle: function($token) {
|
755
|
+
if (!$token) return
|
769
756
|
|
770
|
-
token.toggleClass('active')
|
757
|
+
$token.toggleClass('active')
|
771
758
|
this.$copyHelper.val( this.getTokensList( null, null, true ) ).select()
|
772
759
|
}
|
773
760
|
|
774
|
-
, edit: function (token) {
|
775
|
-
if (
|
761
|
+
, edit: function ($token) {
|
762
|
+
if (!$token) return
|
776
763
|
|
777
|
-
var
|
778
|
-
, label = token.find('.token-label').text()
|
764
|
+
var attrs = $token.data('attrs')
|
779
765
|
|
780
766
|
// Allow changing input value before editing
|
781
|
-
var
|
782
|
-
editEvent
|
783
|
-
value: value,
|
784
|
-
label: label
|
785
|
-
}
|
786
|
-
editEvent.relatedTarget = token.get(0)
|
767
|
+
var options = { attrs: attrs, relatedTarget: $token.get(0) }
|
768
|
+
var editEvent = $.Event('tokenfield:edittoken', options)
|
787
769
|
this.$element.trigger( editEvent )
|
788
770
|
|
789
|
-
if
|
790
|
-
|
791
|
-
value = editEvent.token.value
|
792
|
-
label = editEvent.token.label
|
771
|
+
// Edit event can be cancelled if default is prevented
|
772
|
+
if (editEvent.isDefaultPrevented()) return
|
793
773
|
|
794
|
-
token.find('.token-label').text(value)
|
795
|
-
var tokenWidth = token.outerWidth()
|
774
|
+
$token.find('.token-label').text(attrs.value)
|
775
|
+
var tokenWidth = $token.outerWidth()
|
796
776
|
|
797
777
|
var $_input = this.$input.hasClass('tt-input') ? this.$input.parent() : this.$input
|
798
778
|
|
799
|
-
token.replaceWith( $_input )
|
779
|
+
$token.replaceWith( $_input )
|
800
780
|
|
801
781
|
this.preventCreateTokens = true
|
802
782
|
|
803
|
-
this.$input.val( value )
|
783
|
+
this.$input.val( attrs.value )
|
804
784
|
.select()
|
805
785
|
.data( 'edit', true )
|
806
786
|
.width( tokenWidth )
|
807
787
|
|
808
788
|
this.update();
|
789
|
+
|
790
|
+
// Indicate that token is now being edited, and is replaced with an input field in the DOM
|
791
|
+
this.$element.trigger($.Event('tokenfield:editedtoken', options ))
|
809
792
|
}
|
810
793
|
|
811
794
|
, unedit: function (focus) {
|
@@ -829,31 +812,35 @@
|
|
829
812
|
}
|
830
813
|
|
831
814
|
, remove: function (e, direction) {
|
832
|
-
if (this.$input.is(document.activeElement) || this.
|
815
|
+
if (this.$input.is(document.activeElement) || this._disabled || this._readonly) return
|
833
816
|
|
834
|
-
var token = (e.type === 'click') ? $(e.target).closest('.token') : this.$wrapper.find('.token.active')
|
817
|
+
var $token = (e.type === 'click') ? $(e.target).closest('.token') : this.$wrapper.find('.token.active')
|
835
818
|
|
836
819
|
if (e.type !== 'click') {
|
837
820
|
if (!direction) var direction = 'prev'
|
838
821
|
this[direction]()
|
839
822
|
|
840
|
-
// Was
|
841
|
-
if (direction === 'prev') var firstToken = token.first().prevAll('.token:first').length === 0
|
823
|
+
// Was it the first token?
|
824
|
+
if (direction === 'prev') var firstToken = $token.first().prevAll('.token:first').length === 0
|
842
825
|
}
|
843
826
|
|
844
|
-
// Prepare events
|
827
|
+
// Prepare events and their options
|
828
|
+
var options = { attrs: this.getTokenData( $token ), relatedTarget: $token.get(0) }
|
829
|
+
, removeEvent = $.Event('tokenfield:removetoken', options)
|
830
|
+
|
831
|
+
this.$element.trigger(removeEvent);
|
845
832
|
|
846
|
-
|
847
|
-
removeEvent.
|
833
|
+
// Remove event can be intercepted and cancelled
|
834
|
+
if (removeEvent.isDefaultPrevented()) return
|
848
835
|
|
849
|
-
var
|
850
|
-
|
836
|
+
var removedEvent = $.Event('tokenfield:removedtoken', options)
|
837
|
+
, changeEvent = $.Event('change', { initiator: 'tokenfield' })
|
851
838
|
|
852
839
|
// Remove token from DOM
|
853
|
-
token.remove()
|
840
|
+
$token.remove()
|
854
841
|
|
855
842
|
// Trigger events
|
856
|
-
this.$element.val( this.getTokensList() ).trigger(
|
843
|
+
this.$element.val( this.getTokensList() ).trigger( removedEvent ).trigger( changeEvent )
|
857
844
|
|
858
845
|
// Focus, when necessary:
|
859
846
|
// When there are no more tokens, or if this was the first token
|
@@ -864,15 +851,19 @@
|
|
864
851
|
this.$input.css('width', this.options.minWidth + 'px')
|
865
852
|
this.update()
|
866
853
|
|
854
|
+
// Cancel original event handlers
|
867
855
|
e.preventDefault()
|
868
856
|
e.stopPropagation()
|
869
857
|
}
|
870
858
|
|
859
|
+
/**
|
860
|
+
* Update tokenfield dimensions
|
861
|
+
*/
|
871
862
|
, update: function (e) {
|
872
863
|
var value = this.$input.val()
|
873
|
-
,
|
874
|
-
,
|
875
|
-
, inputPadding =
|
864
|
+
, inputPaddingLeft = parseInt(this.$input.css('padding-left'), 10)
|
865
|
+
, inputPaddingRight = parseInt(this.$input.css('padding-right'), 10)
|
866
|
+
, inputPadding = inputPaddingLeft + inputPaddingRight
|
876
867
|
|
877
868
|
if (this.$input.data('edit')) {
|
878
869
|
|
@@ -891,16 +882,19 @@
|
|
891
882
|
this.$input.width( mirrorWidth )
|
892
883
|
}
|
893
884
|
else {
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
885
|
+
var w = (this.textDirection === 'rtl')
|
886
|
+
? this.$input.offset().left + this.$input.outerWidth() - this.$wrapper.offset().left - parseInt(this.$wrapper.css('padding-left'), 10) - inputPadding - 1
|
887
|
+
: this.$wrapper.offset().left + this.$wrapper.width() + parseInt(this.$wrapper.css('padding-left'), 10) - this.$input.offset().left - inputPadding;
|
888
|
+
//
|
889
|
+
// some usecases pre-render widget before attaching to DOM,
|
890
|
+
// dimensions returned by jquery will be NaN -> we default to 100%
|
891
|
+
// so placeholder won't be cut off.
|
892
|
+
isNaN(w) ? this.$input.width('100%') : this.$input.width(w);
|
899
893
|
}
|
900
894
|
}
|
901
895
|
|
902
896
|
, focusInput: function (e) {
|
903
|
-
if ($(e.target).closest('.token').length || $(e.target).closest('.token-input').length) return
|
897
|
+
if ( $(e.target).closest('.token').length || $(e.target).closest('.token-input').length || $(e.target).closest('.tt-dropdown-menu').length ) return
|
904
898
|
// Focus only after the current call stack has cleared,
|
905
899
|
// otherwise has no effect.
|
906
900
|
// Reason: mousedown is too early - input will lose focus
|
@@ -919,19 +913,28 @@
|
|
919
913
|
}
|
920
914
|
|
921
915
|
, disable: function () {
|
922
|
-
this.disabled
|
923
|
-
this.$input.prop('disabled', true);
|
924
|
-
this.$element.prop('disabled', true);
|
925
|
-
this.$wrapper.addClass('disabled');
|
916
|
+
this.setProperty('disabled', true);
|
926
917
|
}
|
927
918
|
|
928
919
|
, enable: function () {
|
929
|
-
this.disabled
|
930
|
-
|
931
|
-
|
932
|
-
|
920
|
+
this.setProperty('disabled', false);
|
921
|
+
}
|
922
|
+
|
923
|
+
, readonly: function () {
|
924
|
+
this.setProperty('readonly', true);
|
933
925
|
}
|
934
926
|
|
927
|
+
, writeable: function () {
|
928
|
+
this.setProperty('readonly', false);
|
929
|
+
}
|
930
|
+
|
931
|
+
, setProperty: function(property, value) {
|
932
|
+
this['_' + property] = value;
|
933
|
+
this.$input.prop(property, value);
|
934
|
+
this.$element.prop(property, value);
|
935
|
+
this.$wrapper[ value ? 'addClass' : 'removeClass' ](property);
|
936
|
+
}
|
937
|
+
|
935
938
|
, destroy: function() {
|
936
939
|
// Set field value
|
937
940
|
this.$element.val( this.getTokensList() );
|
@@ -939,7 +942,7 @@
|
|
939
942
|
this.$element.css( this.$element.data('original-styles') );
|
940
943
|
this.$element.prop( 'tabindex', this.$element.data('original-tabindex') );
|
941
944
|
|
942
|
-
// Re-route tokenfield
|
945
|
+
// Re-route tokenfield label to original input
|
943
946
|
var $label = $( 'label[for="' + this.$input.prop('id') + '"]' )
|
944
947
|
if ( $label.length ) {
|
945
948
|
$label.prop( 'for', this.$element.prop('id') )
|
@@ -949,15 +952,15 @@
|
|
949
952
|
this.$element.insertBefore( this.$wrapper );
|
950
953
|
|
951
954
|
// Remove tokenfield-related data
|
952
|
-
this.$element.removeData('original-styles')
|
953
|
-
|
954
|
-
|
955
|
+
this.$element.removeData('original-styles')
|
956
|
+
.removeData('original-tabindex')
|
957
|
+
.removeData('bs.tokenfield');
|
955
958
|
|
956
959
|
// Remove tokenfield from DOM
|
957
960
|
this.$wrapper.remove();
|
961
|
+
this.$mirror.remove();
|
958
962
|
|
959
963
|
var $_element = this.$element;
|
960
|
-
delete this;
|
961
964
|
|
962
965
|
return $_element;
|
963
966
|
}
|
@@ -985,7 +988,10 @@
|
|
985
988
|
args.shift()
|
986
989
|
value = data[option].apply(data, args)
|
987
990
|
} else {
|
988
|
-
if (!data && typeof option !== 'string' && !param)
|
991
|
+
if (!data && typeof option !== 'string' && !param) {
|
992
|
+
$this.data('bs.tokenfield', (data = new Tokenfield(this, options)))
|
993
|
+
$this.trigger('tokenfield:initialize')
|
994
|
+
}
|
989
995
|
}
|
990
996
|
})
|
991
997
|
|
@@ -995,15 +1001,16 @@
|
|
995
1001
|
$.fn.tokenfield.defaults = {
|
996
1002
|
minWidth: 60,
|
997
1003
|
minLength: 0,
|
998
|
-
allowDuplicates: false,
|
999
1004
|
allowEditing: true,
|
1005
|
+
allowPasting: true,
|
1000
1006
|
limit: 0,
|
1001
1007
|
autocomplete: {},
|
1002
1008
|
typeahead: {},
|
1003
1009
|
showAutocompleteOnFocus: false,
|
1004
1010
|
createTokensOnBlur: false,
|
1005
1011
|
delimiter: ',',
|
1006
|
-
beautify: true
|
1012
|
+
beautify: true,
|
1013
|
+
inputType: 'text'
|
1007
1014
|
}
|
1008
1015
|
|
1009
1016
|
$.fn.tokenfield.Constructor = Tokenfield
|
@@ -3,7 +3,7 @@
|
|
3
3
|
* https://github.com/sliptree/bootstrap-tokenfield
|
4
4
|
* Copyright 2013-2014 Sliptree and other contributors; Licensed MIT
|
5
5
|
*/
|
6
|
-
@-webkit-keyframes
|
6
|
+
@-webkit-keyframes blink {
|
7
7
|
0% {
|
8
8
|
border-color: #ededed;
|
9
9
|
}
|
@@ -11,7 +11,7 @@
|
|
11
11
|
border-color: #b94a48;
|
12
12
|
}
|
13
13
|
}
|
14
|
-
@-moz-keyframes
|
14
|
+
@-moz-keyframes blink {
|
15
15
|
0% {
|
16
16
|
border-color: #ededed;
|
17
17
|
}
|
@@ -19,7 +19,7 @@
|
|
19
19
|
border-color: #b94a48;
|
20
20
|
}
|
21
21
|
}
|
22
|
-
@keyframes
|
22
|
+
@keyframes blink {
|
23
23
|
0% {
|
24
24
|
border-color: #ededed;
|
25
25
|
}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bootstrap_tokenfield_rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Akash Devaraju
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-10-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -76,3 +76,4 @@ signing_key:
|
|
76
76
|
specification_version: 4
|
77
77
|
summary: A jQuery tagging / tokenizer input plugin for Twitter's Bootstrap
|
78
78
|
test_files: []
|
79
|
+
has_rdoc:
|