materialize-sass 0.100.2 → 0.100.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,51 +1,55 @@
1
1
  /*!
2
- * pickadate.js v3.5.0, 2014/04/13
2
+ * pickadate.js v3.6.1, 2019/03/15
3
3
  * By Amsul, http://amsul.ca
4
4
  * Hosted on http://amsul.github.io/pickadate.js
5
5
  * Licensed under MIT
6
6
  */
7
7
 
8
- (function (factory) {
8
+ (function ( factory ) {
9
9
 
10
- Materialize.Picker = factory(jQuery);
11
- })(function ($) {
10
+ Materialize.Picker = factory( jQuery )
11
+ })(function( $ ) {
12
12
 
13
- var $window = $(window);
14
- var $document = $(document);
15
- var $html = $(document.documentElement);
13
+ var $window = $( window )
14
+ var $document = $( document )
15
+ var $html = $( document.documentElement )
16
+ var supportsTransitions = document.documentElement.style.transition != null
16
17
 
17
- /**
18
- * The picker constructor that creates a blank picker.
19
- */
20
- function PickerConstructor(ELEMENT, NAME, COMPONENT, OPTIONS) {
21
18
 
22
- // If there’s no element, return the picker constructor.
23
- if (!ELEMENT) return PickerConstructor;
19
+ /**
20
+ * The picker constructor that creates a blank picker.
21
+ */
22
+ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) {
23
+
24
+ // If there’s no element, return the picker constructor.
25
+ if ( !ELEMENT ) return PickerConstructor
26
+
24
27
 
25
- var IS_DEFAULT_THEME = false,
28
+ var
29
+ IS_DEFAULT_THEME = false,
26
30
 
27
31
 
28
32
  // The state of the picker.
29
33
  STATE = {
30
- id: ELEMENT.id || 'P' + Math.abs(~~(Math.random() * new Date()))
34
+ id: ELEMENT.id || 'P' + Math.abs( ~~(Math.random() * new Date()) )
31
35
  },
32
36
 
33
37
 
34
38
  // Merge the defaults and options passed.
35
- SETTINGS = COMPONENT ? $.extend(true, {}, COMPONENT.defaults, OPTIONS) : OPTIONS || {},
39
+ SETTINGS = COMPONENT ? $.extend( true, {}, COMPONENT.defaults, OPTIONS ) : OPTIONS || {},
36
40
 
37
41
 
38
42
  // Merge the default classes with the settings classes.
39
- CLASSES = $.extend({}, PickerConstructor.klasses(), SETTINGS.klass),
43
+ CLASSES = $.extend( {}, PickerConstructor.klasses(), SETTINGS.klass ),
40
44
 
41
45
 
42
46
  // The element node wrapper into a jQuery object.
43
- $ELEMENT = $(ELEMENT),
47
+ $ELEMENT = $( ELEMENT ),
44
48
 
45
49
 
46
50
  // Pseudo picker constructor.
47
- PickerInstance = function () {
48
- return this.start();
51
+ PickerInstance = function() {
52
+ return this.start()
49
53
  },
50
54
 
51
55
 
@@ -56,46 +60,66 @@
56
60
 
57
61
  $node: $ELEMENT,
58
62
 
63
+
59
64
  /**
60
65
  * Initialize everything
61
66
  */
62
- start: function () {
67
+ start: function() {
63
68
 
64
69
  // If it’s already started, do nothing.
65
- if (STATE && STATE.start) return P;
70
+ if ( STATE && STATE.start ) return P
71
+
66
72
 
67
73
  // Update the picker states.
68
- STATE.methods = {};
69
- STATE.start = true;
70
- STATE.open = false;
71
- STATE.type = ELEMENT.type;
74
+ STATE.methods = {}
75
+ STATE.start = true
76
+ STATE.open = false
77
+ STATE.type = ELEMENT.type
78
+
72
79
 
73
80
  // Confirm focus state, convert into text input to remove UA stylings,
74
81
  // and set as readonly to prevent keyboard popup.
75
- ELEMENT.autofocus = ELEMENT == getActiveElement();
76
- ELEMENT.readOnly = !SETTINGS.editable;
77
- ELEMENT.id = ELEMENT.id || STATE.id;
78
- if (ELEMENT.type != 'text') {
79
- ELEMENT.type = 'text';
82
+ ELEMENT.autofocus = ELEMENT == getActiveElement()
83
+ ELEMENT.readOnly = !SETTINGS.editable
84
+ ELEMENT.id = ELEMENT.id || STATE.id
85
+ if ( ELEMENT.type != 'text' ) {
86
+ ELEMENT.type = 'text'
80
87
  }
81
88
 
89
+
82
90
  // Create a new picker component with the settings.
83
- P.component = new COMPONENT(P, SETTINGS);
91
+ P.component = new COMPONENT(P, SETTINGS)
92
+
93
+
94
+ // Create the picker root and then prepare it.
95
+ P.$root = $( '<div class="' + CLASSES.picker + '" id="' + ELEMENT.id + '_root" />' )
96
+ prepareElementRoot()
97
+
98
+
99
+ // Create the picker holder and then prepare it.
100
+ P.$holder = $( createWrappedComponent() ).appendTo( P.$root )
101
+ prepareElementHolder()
84
102
 
85
- // Create the picker root with a holder and then prepare it.
86
- P.$root = $(PickerConstructor._.node('div', createWrappedComponent(), CLASSES.picker, 'id="' + ELEMENT.id + '_root" tabindex="0"'));
87
- prepareElementRoot();
88
103
 
89
104
  // If there’s a format for the hidden input element, create the element.
90
- if (SETTINGS.formatSubmit) {
91
- prepareElementHidden();
105
+ if ( SETTINGS.formatSubmit ) {
106
+ prepareElementHidden()
92
107
  }
93
108
 
109
+
94
110
  // Prepare the input element.
95
- prepareElement();
111
+ prepareElement()
112
+
113
+
114
+ // Insert the hidden input as specified in the settings.
115
+ if ( SETTINGS.containerHidden ) $( SETTINGS.containerHidden ).append( P._hidden )
116
+ else $ELEMENT.after( P._hidden )
117
+
96
118
 
97
119
  // Insert the root as specified in the settings.
98
- if (SETTINGS.container) $(SETTINGS.container).append(P.$root);else $ELEMENT.before(P.$root);
120
+ if ( SETTINGS.container ) $( SETTINGS.container ).append( P.$root )
121
+ else $ELEMENT.after( P.$root )
122
+
99
123
 
100
124
  // Bind the default component and settings events.
101
125
  P.on({
@@ -112,116 +136,126 @@
112
136
  open: SETTINGS.onOpen,
113
137
  close: SETTINGS.onClose,
114
138
  set: SETTINGS.onSet
115
- });
139
+ })
140
+
116
141
 
117
142
  // Once we’re all set, check the theme in use.
118
- IS_DEFAULT_THEME = isUsingDefaultTheme(P.$root.children()[0]);
143
+ IS_DEFAULT_THEME = isUsingDefaultTheme( P.$holder[0] )
144
+
119
145
 
120
146
  // If the element has autofocus, open the picker.
121
- if (ELEMENT.autofocus) {
122
- P.open();
147
+ if ( ELEMENT.autofocus ) {
148
+ P.open()
123
149
  }
124
150
 
151
+
125
152
  // Trigger queued the “start” and “render” events.
126
- return P.trigger('start').trigger('render');
153
+ return P.trigger( 'start' ).trigger( 'render' )
127
154
  }, //start
128
155
 
129
156
 
130
157
  /**
131
158
  * Render a new picker
132
159
  */
133
- render: function (entireComponent) {
160
+ render: function( entireComponent ) {
134
161
 
135
162
  // Insert a new component holder in the root or box.
136
- if (entireComponent) P.$root.html(createWrappedComponent());else P.$root.find('.' + CLASSES.box).html(P.component.nodes(STATE.open));
163
+ if ( entireComponent ) {
164
+ P.$holder = $( createWrappedComponent() )
165
+ prepareElementHolder()
166
+ P.$root.html( P.$holder )
167
+ }
168
+ else P.$root.find( '.' + CLASSES.box ).html( P.component.nodes( STATE.open ) )
137
169
 
138
170
  // Trigger the queued “render” events.
139
- return P.trigger('render');
171
+ return P.trigger( 'render' )
140
172
  }, //render
141
173
 
142
174
 
143
175
  /**
144
176
  * Destroy everything
145
177
  */
146
- stop: function () {
178
+ stop: function() {
147
179
 
148
180
  // If it’s already stopped, do nothing.
149
- if (!STATE.start) return P;
181
+ if ( !STATE.start ) return P
150
182
 
151
183
  // Then close the picker.
152
- P.close();
184
+ P.close()
153
185
 
154
186
  // Remove the hidden field.
155
- if (P._hidden) {
156
- P._hidden.parentNode.removeChild(P._hidden);
187
+ if ( P._hidden ) {
188
+ P._hidden.parentNode.removeChild( P._hidden )
157
189
  }
158
190
 
159
191
  // Remove the root.
160
- P.$root.remove();
192
+ P.$root.remove()
161
193
 
162
194
  // Remove the input class, remove the stored data, and unbind
163
195
  // the events (after a tick for IE - see `P.close`).
164
- $ELEMENT.removeClass(CLASSES.input).removeData(NAME);
165
- setTimeout(function () {
166
- $ELEMENT.off('.' + STATE.id);
167
- }, 0);
196
+ $ELEMENT.removeClass( CLASSES.input ).removeData( NAME )
197
+ setTimeout( function() {
198
+ $ELEMENT.off( '.' + STATE.id )
199
+ }, 0)
168
200
 
169
201
  // Restore the element state
170
- ELEMENT.type = STATE.type;
171
- ELEMENT.readOnly = false;
202
+ ELEMENT.type = STATE.type
203
+ ELEMENT.readOnly = false
172
204
 
173
205
  // Trigger the queued “stop” events.
174
- P.trigger('stop');
206
+ P.trigger( 'stop' )
175
207
 
176
208
  // Reset the picker states.
177
- STATE.methods = {};
178
- STATE.start = false;
209
+ STATE.methods = {}
210
+ STATE.start = false
179
211
 
180
- return P;
212
+ return P
181
213
  }, //stop
182
214
 
183
215
 
184
216
  /**
185
217
  * Open up the picker
186
218
  */
187
- open: function (dontGiveFocus) {
219
+ open: function( dontGiveFocus ) {
188
220
 
189
221
  // If it’s already open, do nothing.
190
- if (STATE.open) return P;
222
+ if ( STATE.open ) return P
191
223
 
192
224
  // Add the “active” class.
193
- $ELEMENT.addClass(CLASSES.active);
194
- aria(ELEMENT, 'expanded', true);
225
+ $ELEMENT.addClass( CLASSES.active )
226
+ aria( ELEMENT, 'expanded', true )
195
227
 
196
228
  // * A Firefox bug, when `html` has `overflow:hidden`, results in
197
229
  // killing transitions :(. So add the “opened” state on the next tick.
198
230
  // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=625289
199
- setTimeout(function () {
231
+ setTimeout( function() {
200
232
 
201
233
  // Add the “opened” class to the picker root.
202
- P.$root.addClass(CLASSES.opened);
203
- aria(P.$root[0], 'hidden', false);
204
- }, 0);
234
+ P.$root.addClass( CLASSES.opened )
235
+ aria( P.$root[0], 'hidden', false )
236
+
237
+ }, 0 )
205
238
 
206
239
  // If we have to give focus, bind the element and doc events.
207
- if (dontGiveFocus !== false) {
240
+ if ( dontGiveFocus !== false ) {
208
241
 
209
242
  // Set it as open.
210
- STATE.open = true;
243
+ STATE.open = true
211
244
 
212
245
  // Prevent the page from scrolling.
213
- if (IS_DEFAULT_THEME) {
214
- $html.css('overflow', 'hidden').css('padding-right', '+=' + getScrollbarWidth());
246
+ if ( IS_DEFAULT_THEME ) {
247
+ $('body').
248
+ css( 'overflow', 'hidden' ).
249
+ css( 'padding-right', '+=' + getScrollbarWidth() )
215
250
  }
216
251
 
217
252
  // Pass focus to the root element’s jQuery object.
218
- // * Workaround for iOS8 to bring the picker’s root into view.
219
- P.$root.eq(0).focus();
253
+ focusPickerOnceOpened()
220
254
 
221
255
  // Bind the document events.
222
- $document.on('click.' + STATE.id + ' focusin.' + STATE.id, function (event) {
256
+ $document.on( 'click.' + STATE.id + ' focusin.' + STATE.id, function( event ) {
223
257
 
224
- var target = event.target;
258
+ var target = getRealEventTarget( event, ELEMENT )
225
259
 
226
260
  // If the target of the event is not the element, close the picker picker.
227
261
  // * Don’t worry about clicks or focusins on the root because those don’t bubble up.
@@ -230,321 +264,345 @@
230
264
  // * In Firefox stopPropagation() doesn’t prevent right-click events from bubbling,
231
265
  // which causes the picker to unexpectedly close when right-clicking it. So make
232
266
  // sure the event wasn’t a right-click.
233
- if (target != ELEMENT && target != document && event.which != 3) {
267
+ // * In Chrome 62 and up, password autofill causes a simulated focusin event which
268
+ // closes the picker.
269
+ if ( ! event.isSimulated && target != ELEMENT && target != document && event.which != 3 ) {
234
270
 
235
271
  // If the target was the holder that covers the screen,
236
272
  // keep the element focused to maintain tabindex.
237
- P.close(target === P.$root.children()[0]);
273
+ P.close( target === P.$holder[0] )
238
274
  }
239
- }).on('keydown.' + STATE.id, function (event) {
240
275
 
241
- var
242
- // Get the keycode.
243
- keycode = event.keyCode,
276
+ }).on( 'keydown.' + STATE.id, function( event ) {
244
277
 
278
+ var
279
+ // Get the keycode.
280
+ keycode = event.keyCode,
245
281
 
246
- // Translate that to a selection change.
247
- keycodeToMove = P.component.key[keycode],
282
+ // Translate that to a selection change.
283
+ keycodeToMove = P.component.key[ keycode ],
248
284
 
285
+ // Grab the target.
286
+ target = getRealEventTarget( event, ELEMENT )
249
287
 
250
- // Grab the target.
251
- target = event.target;
252
288
 
253
289
  // On escape, close the picker and give focus.
254
- if (keycode == 27) {
255
- P.close(true);
290
+ if ( keycode == 27 ) {
291
+ P.close( true )
256
292
  }
257
293
 
258
- // Check if there is a key movement or “enter” keypress on the element.
259
- else if (target == P.$root[0] && (keycodeToMove || keycode == 13)) {
260
294
 
261
- // Prevent the default action to stop page movement.
262
- event.preventDefault();
295
+ // Check if there is a key movement or “enter” keypress on the element.
296
+ else if ( target == P.$holder[0] && ( keycodeToMove || keycode == 13 ) ) {
263
297
 
264
- // Trigger the key movement action.
265
- if (keycodeToMove) {
266
- PickerConstructor._.trigger(P.component.key.go, P, [PickerConstructor._.trigger(keycodeToMove)]);
267
- }
298
+ // Prevent the default action to stop page movement.
299
+ event.preventDefault()
268
300
 
269
- // On “enter”, if the highlighted item isn’t disabled, set the value and close.
270
- else if (!P.$root.find('.' + CLASSES.highlighted).hasClass(CLASSES.disabled)) {
271
- P.set('select', P.component.item.highlight);
272
- if (SETTINGS.closeOnSelect) {
273
- P.close(true);
274
- }
275
- }
301
+ // Trigger the key movement action.
302
+ if ( keycodeToMove ) {
303
+ PickerConstructor._.trigger( P.component.key.go, P, [ PickerConstructor._.trigger( keycodeToMove ) ] )
276
304
  }
277
305
 
278
- // If the target is within the root and “enter” is pressed,
279
- // prevent the default action and trigger a click on the target instead.
280
- else if ($.contains(P.$root[0], target) && keycode == 13) {
281
- event.preventDefault();
282
- target.click();
306
+ // On “enter”, if the highlighted item isn’t disabled, set the value and close.
307
+ else if ( !P.$root.find( '.' + CLASSES.highlighted ).hasClass( CLASSES.disabled ) ) {
308
+ P.set( 'select', P.component.item.highlight )
309
+ if ( SETTINGS.closeOnSelect ) {
310
+ P.close( true )
283
311
  }
284
- });
312
+ }
313
+ }
314
+
315
+
316
+ // If the target is within the root and “enter” is pressed,
317
+ // prevent the default action and trigger a click on the target instead.
318
+ else if ( $.contains( P.$root[0], target ) && keycode == 13 ) {
319
+ event.preventDefault()
320
+ target.click()
321
+ }
322
+ })
285
323
  }
286
324
 
287
325
  // Trigger the queued “open” events.
288
- return P.trigger('open');
326
+ return P.trigger( 'open' )
289
327
  }, //open
290
328
 
291
329
 
292
330
  /**
293
331
  * Close the picker
294
332
  */
295
- close: function (giveFocus) {
333
+ close: function( giveFocus ) {
296
334
 
297
335
  // If we need to give focus, do it before changing states.
298
- if (giveFocus) {
299
- // ....ah yes! It would’ve been incomplete without a crazy workaround for IE :|
300
- // The focus is triggered *after* the close has completed - causing it
301
- // to open again. So unbind and rebind the event at the next tick.
302
- P.$root.off('focus.toOpen').eq(0).focus();
303
- setTimeout(function () {
304
- P.$root.on('focus.toOpen', handleFocusToOpenEvent);
305
- }, 0);
336
+ if ( giveFocus ) {
337
+ if ( SETTINGS.editable ) {
338
+ ELEMENT.focus()
339
+ }
340
+ else {
341
+ // ....ah yes! It would’ve been incomplete without a crazy workaround for IE :|
342
+ // The focus is triggered *after* the close has completed - causing it
343
+ // to open again. So unbind and rebind the event at the next tick.
344
+ P.$holder.off( 'focus.toOpen' ).focus()
345
+ setTimeout( function() {
346
+ P.$holder.on( 'focus.toOpen', handleFocusToOpenEvent )
347
+ }, 0 )
348
+ }
306
349
  }
307
350
 
308
351
  // Remove the “active” class.
309
- $ELEMENT.removeClass(CLASSES.active);
310
- aria(ELEMENT, 'expanded', false);
352
+ $ELEMENT.removeClass( CLASSES.active )
353
+ aria( ELEMENT, 'expanded', false )
311
354
 
312
355
  // * A Firefox bug, when `html` has `overflow:hidden`, results in
313
356
  // killing transitions :(. So remove the “opened” state on the next tick.
314
357
  // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=625289
315
- setTimeout(function () {
358
+ setTimeout( function() {
316
359
 
317
360
  // Remove the “opened” and “focused” class from the picker root.
318
- P.$root.removeClass(CLASSES.opened + ' ' + CLASSES.focused);
319
- aria(P.$root[0], 'hidden', true);
320
- }, 0);
361
+ P.$root.removeClass( CLASSES.opened + ' ' + CLASSES.focused )
362
+ aria( P.$root[0], 'hidden', true )
363
+
364
+ }, 0 )
321
365
 
322
366
  // If it’s already closed, do nothing more.
323
- if (!STATE.open) return P;
367
+ if ( !STATE.open ) return P
324
368
 
325
369
  // Set it as closed.
326
- STATE.open = false;
370
+ STATE.open = false
327
371
 
328
372
  // Allow the page to scroll.
329
- if (IS_DEFAULT_THEME) {
330
- $html.css('overflow', '').css('padding-right', '-=' + getScrollbarWidth());
373
+ if ( IS_DEFAULT_THEME ) {
374
+ $('body').
375
+ css( 'overflow', '' ).
376
+ css( 'padding-right', '-=' + getScrollbarWidth() )
331
377
  }
332
378
 
333
379
  // Unbind the document events.
334
- $document.off('.' + STATE.id);
380
+ $document.off( '.' + STATE.id )
335
381
 
336
382
  // Trigger the queued “close” events.
337
- return P.trigger('close');
383
+ return P.trigger( 'close' )
338
384
  }, //close
339
385
 
340
386
 
341
387
  /**
342
388
  * Clear the values
343
389
  */
344
- clear: function (options) {
345
- return P.set('clear', null, options);
390
+ clear: function( options ) {
391
+ return P.set( 'clear', null, options )
346
392
  }, //clear
347
393
 
348
394
 
349
395
  /**
350
396
  * Set something
351
397
  */
352
- set: function (thing, value, options) {
398
+ set: function( thing, value, options ) {
353
399
 
354
- var thingItem,
355
- thingValue,
356
- thingIsObject = $.isPlainObject(thing),
357
- thingObject = thingIsObject ? thing : {};
400
+ var thingItem, thingValue,
401
+ thingIsObject = $.isPlainObject( thing ),
402
+ thingObject = thingIsObject ? thing : {}
358
403
 
359
404
  // Make sure we have usable options.
360
- options = thingIsObject && $.isPlainObject(value) ? value : options || {};
405
+ options = thingIsObject && $.isPlainObject( value ) ? value : options || {}
361
406
 
362
- if (thing) {
407
+ if ( thing ) {
363
408
 
364
409
  // If the thing isn’t an object, make it one.
365
- if (!thingIsObject) {
366
- thingObject[thing] = value;
410
+ if ( !thingIsObject ) {
411
+ thingObject[ thing ] = value
367
412
  }
368
413
 
369
414
  // Go through the things of items to set.
370
- for (thingItem in thingObject) {
415
+ for ( thingItem in thingObject ) {
371
416
 
372
417
  // Grab the value of the thing.
373
- thingValue = thingObject[thingItem];
418
+ thingValue = thingObject[ thingItem ]
374
419
 
375
420
  // First, if the item exists and there’s a value, set it.
376
- if (thingItem in P.component.item) {
377
- if (thingValue === undefined) thingValue = null;
378
- P.component.set(thingItem, thingValue, options);
421
+ if ( thingItem in P.component.item ) {
422
+ if ( thingValue === undefined ) thingValue = null
423
+ P.component.set( thingItem, thingValue, options )
379
424
  }
380
425
 
381
426
  // Then, check to update the element value and broadcast a change.
382
- if (thingItem == 'select' || thingItem == 'clear') {
383
- $ELEMENT.val(thingItem == 'clear' ? '' : P.get(thingItem, SETTINGS.format)).trigger('change');
427
+ if ( ( thingItem == 'select' || thingItem == 'clear' ) && SETTINGS.updateInput ) {
428
+ $ELEMENT.
429
+ val( thingItem == 'clear' ? '' : P.get( thingItem, SETTINGS.format ) ).
430
+ trigger( 'change' )
384
431
  }
385
432
  }
386
433
 
387
434
  // Render a new picker.
388
- P.render();
435
+ P.render()
389
436
  }
390
437
 
391
438
  // When the method isn’t muted, trigger queued “set” events and pass the `thingObject`.
392
- return options.muted ? P : P.trigger('set', thingObject);
439
+ return options.muted ? P : P.trigger( 'set', thingObject )
393
440
  }, //set
394
441
 
395
442
 
396
443
  /**
397
444
  * Get something
398
445
  */
399
- get: function (thing, format) {
446
+ get: function( thing, format ) {
400
447
 
401
448
  // Make sure there’s something to get.
402
- thing = thing || 'value';
449
+ thing = thing || 'value'
403
450
 
404
451
  // If a picker state exists, return that.
405
- if (STATE[thing] != null) {
406
- return STATE[thing];
452
+ if ( STATE[ thing ] != null ) {
453
+ return STATE[ thing ]
407
454
  }
408
455
 
409
456
  // Return the submission value, if that.
410
- if (thing == 'valueSubmit') {
411
- if (P._hidden) {
412
- return P._hidden.value;
457
+ if ( thing == 'valueSubmit' ) {
458
+ if ( P._hidden ) {
459
+ return P._hidden.value
413
460
  }
414
- thing = 'value';
461
+ thing = 'value'
415
462
  }
416
463
 
417
464
  // Return the value, if that.
418
- if (thing == 'value') {
419
- return ELEMENT.value;
465
+ if ( thing == 'value' ) {
466
+ return ELEMENT.value
420
467
  }
421
468
 
422
469
  // Check if a component item exists, return that.
423
- if (thing in P.component.item) {
424
- if (typeof format == 'string') {
425
- var thingValue = P.component.get(thing);
426
- return thingValue ? PickerConstructor._.trigger(P.component.formats.toString, P.component, [format, thingValue]) : '';
470
+ if ( thing in P.component.item ) {
471
+ if ( typeof format == 'string' ) {
472
+ var thingValue = P.component.get( thing )
473
+ return thingValue ?
474
+ PickerConstructor._.trigger(
475
+ P.component.formats.toString,
476
+ P.component,
477
+ [ format, thingValue ]
478
+ ) : ''
427
479
  }
428
- return P.component.get(thing);
480
+ return P.component.get( thing )
429
481
  }
430
482
  }, //get
431
483
 
432
484
 
485
+
433
486
  /**
434
487
  * Bind events on the things.
435
488
  */
436
- on: function (thing, method, internal) {
489
+ on: function( thing, method, internal ) {
437
490
 
438
- var thingName,
439
- thingMethod,
440
- thingIsObject = $.isPlainObject(thing),
441
- thingObject = thingIsObject ? thing : {};
491
+ var thingName, thingMethod,
492
+ thingIsObject = $.isPlainObject( thing ),
493
+ thingObject = thingIsObject ? thing : {}
442
494
 
443
- if (thing) {
495
+ if ( thing ) {
444
496
 
445
497
  // If the thing isn’t an object, make it one.
446
- if (!thingIsObject) {
447
- thingObject[thing] = method;
498
+ if ( !thingIsObject ) {
499
+ thingObject[ thing ] = method
448
500
  }
449
501
 
450
502
  // Go through the things to bind to.
451
- for (thingName in thingObject) {
503
+ for ( thingName in thingObject ) {
452
504
 
453
505
  // Grab the method of the thing.
454
- thingMethod = thingObject[thingName];
506
+ thingMethod = thingObject[ thingName ]
455
507
 
456
508
  // If it was an internal binding, prefix it.
457
- if (internal) {
458
- thingName = '_' + thingName;
509
+ if ( internal ) {
510
+ thingName = '_' + thingName
459
511
  }
460
512
 
461
513
  // Make sure the thing methods collection exists.
462
- STATE.methods[thingName] = STATE.methods[thingName] || [];
514
+ STATE.methods[ thingName ] = STATE.methods[ thingName ] || []
463
515
 
464
516
  // Add the method to the relative method collection.
465
- STATE.methods[thingName].push(thingMethod);
517
+ STATE.methods[ thingName ].push( thingMethod )
466
518
  }
467
519
  }
468
520
 
469
- return P;
521
+ return P
470
522
  }, //on
471
523
 
472
524
 
525
+
473
526
  /**
474
527
  * Unbind events on the things.
475
528
  */
476
- off: function () {
477
- var i,
478
- thingName,
529
+ off: function() {
530
+ var i, thingName,
479
531
  names = arguments;
480
- for (i = 0, namesCount = names.length; i < namesCount; i += 1) {
481
- thingName = names[i];
482
- if (thingName in STATE.methods) {
483
- delete STATE.methods[thingName];
532
+ for ( i = 0, namesCount = names.length; i < namesCount; i += 1 ) {
533
+ thingName = names[i]
534
+ if ( thingName in STATE.methods ) {
535
+ delete STATE.methods[thingName]
484
536
  }
485
537
  }
486
- return P;
538
+ return P
487
539
  },
488
540
 
541
+
489
542
  /**
490
543
  * Fire off method events.
491
544
  */
492
- trigger: function (name, data) {
493
- var _trigger = function (name) {
494
- var methodList = STATE.methods[name];
495
- if (methodList) {
496
- methodList.map(function (method) {
497
- PickerConstructor._.trigger(method, P, [data]);
498
- });
545
+ trigger: function( name, data ) {
546
+ var _trigger = function( name ) {
547
+ var methodList = STATE.methods[ name ]
548
+ if ( methodList ) {
549
+ methodList.map( function( method ) {
550
+ PickerConstructor._.trigger( method, P, [ data ] )
551
+ })
499
552
  }
500
- };
501
- _trigger('_' + name);
502
- _trigger(name);
503
- return P;
553
+ }
554
+ _trigger( '_' + name )
555
+ _trigger( name )
556
+ return P
504
557
  } //trigger
505
- //PickerInstance.prototype
558
+ } //PickerInstance.prototype
506
559
 
507
560
 
508
- /**
509
- * Wrap the picker holder components together.
510
- */
511
- };function createWrappedComponent() {
561
+ /**
562
+ * Wrap the picker holder components together.
563
+ */
564
+ function createWrappedComponent() {
512
565
 
513
- // Create a picker wrapper holder
514
- return PickerConstructor._.node('div',
566
+ // Create a picker wrapper holder
567
+ return PickerConstructor._.node( 'div',
515
568
 
516
569
  // Create a picker wrapper node
517
- PickerConstructor._.node('div',
570
+ PickerConstructor._.node( 'div',
518
571
 
519
- // Create a picker frame
520
- PickerConstructor._.node('div',
572
+ // Create a picker frame
573
+ PickerConstructor._.node( 'div',
521
574
 
522
- // Create a picker box node
523
- PickerConstructor._.node('div',
575
+ // Create a picker box node
576
+ PickerConstructor._.node( 'div',
524
577
 
525
- // Create the components nodes.
526
- P.component.nodes(STATE.open),
578
+ // Create the components nodes.
579
+ P.component.nodes( STATE.open ),
527
580
 
528
- // The picker box class
529
- CLASSES.box),
581
+ // The picker box class
582
+ CLASSES.box
583
+ ),
530
584
 
531
- // Picker wrap class
532
- CLASSES.wrap),
585
+ // Picker wrap class
586
+ CLASSES.wrap
587
+ ),
533
588
 
534
- // Picker frame class
535
- CLASSES.frame),
589
+ // Picker frame class
590
+ CLASSES.frame
591
+ ),
536
592
 
537
593
  // Picker holder class
538
- CLASSES.holder); //endreturn
539
- } //createWrappedComponent
594
+ CLASSES.holder,
540
595
 
596
+ 'tabindex="-1"'
597
+ ) //endreturn
598
+ } //createWrappedComponent
541
599
 
542
- /**
543
- * Prepare the input element with all bindings.
544
- */
545
- function prepareElement() {
600
+ /**
601
+ * Prepare the input element with all bindings.
602
+ */
603
+ function prepareElement() {
546
604
 
547
- $ELEMENT.
605
+ $ELEMENT.
548
606
 
549
607
  // Store the picker data by component name.
550
608
  data(NAME, P).
@@ -552,483 +610,587 @@
552
610
  // Add the “input” class name.
553
611
  addClass(CLASSES.input).
554
612
 
555
- // Remove the tabindex.
556
- attr('tabindex', -1).
557
-
558
613
  // If there’s a `data-value`, update the value of the element.
559
- val($ELEMENT.data('value') ? P.get('select', SETTINGS.format) : ELEMENT.value);
614
+ val( $ELEMENT.data('value') ?
615
+ P.get('select', SETTINGS.format) :
616
+ ELEMENT.value
617
+ ).
560
618
 
561
- // Only bind keydown events if the element isn’t editable.
562
- if (!SETTINGS.editable) {
619
+ // On focus/click, open the picker.
620
+ on( 'focus.' + STATE.id + ' click.' + STATE.id,
621
+ debounce(function(event) {
622
+ event.preventDefault()
623
+ P.open()
624
+ }, 50))
563
625
 
564
- $ELEMENT.
626
+ // Only bind keydown events if the element isn’t editable.
627
+ if ( !SETTINGS.editable ) {
565
628
 
566
- // On focus/click, focus onto the root to open it up.
567
- on('focus.' + STATE.id + ' click.' + STATE.id, function (event) {
568
- event.preventDefault();
569
- P.$root.eq(0).focus();
570
- }).
629
+ $ELEMENT.
571
630
 
572
631
  // Handle keyboard event based on the picker being opened or not.
573
- on('keydown.' + STATE.id, handleKeydownEvent);
574
- }
575
-
576
- // Update the aria attributes.
577
- aria(ELEMENT, {
578
- haspopup: true,
579
- expanded: false,
580
- readonly: false,
581
- owns: ELEMENT.id + '_root'
582
- });
632
+ on( 'keydown.' + STATE.id, handleKeydownEvent )
583
633
  }
584
634
 
585
- /**
586
- * Prepare the root picker element with all bindings.
587
- */
588
- function prepareElementRoot() {
589
635
 
590
- P.$root.on({
636
+ // Update the aria attributes.
637
+ aria(ELEMENT, {
638
+ haspopup: true,
639
+ expanded: false,
640
+ readonly: false,
641
+ owns: ELEMENT.id + '_root'
642
+ })
643
+ }
644
+
645
+
646
+ /**
647
+ * Prepare the root picker element with all bindings.
648
+ */
649
+ function prepareElementRoot() {
650
+ aria( P.$root[0], 'hidden', true )
651
+ }
652
+
653
+
654
+ /**
655
+ * Prepare the holder picker element with all bindings.
656
+ */
657
+ function prepareElementHolder() {
658
+
659
+ P.$holder.
660
+
661
+ on({
591
662
 
592
663
  // For iOS8.
593
664
  keydown: handleKeydownEvent,
594
665
 
595
- // When something within the root is focused, stop from bubbling
666
+ 'focus.toOpen': handleFocusToOpenEvent,
667
+
668
+ blur: function() {
669
+ // Remove the “target” class.
670
+ $ELEMENT.removeClass( CLASSES.target )
671
+ },
672
+
673
+ // When something within the holder is focused, stop from bubbling
596
674
  // to the doc and remove the “focused” state from the root.
597
- focusin: function (event) {
598
- P.$root.removeClass(CLASSES.focused);
599
- event.stopPropagation();
675
+ focusin: function( event ) {
676
+ P.$root.removeClass( CLASSES.focused )
677
+ event.stopPropagation()
600
678
  },
601
679
 
602
- // When something within the root holder is clicked, stop it
680
+ // When something within the holder is clicked, stop it
603
681
  // from bubbling to the doc.
604
- 'mousedown click': function (event) {
682
+ 'mousedown click': function( event ) {
605
683
 
606
- var target = event.target;
684
+ var target = getRealEventTarget( event, ELEMENT )
607
685
 
608
686
  // Make sure the target isn’t the root holder so it can bubble up.
609
- if (target != P.$root.children()[0]) {
687
+ if ( target != P.$holder[0] ) {
610
688
 
611
- event.stopPropagation();
689
+ event.stopPropagation()
612
690
 
613
691
  // * For mousedown events, cancel the default action in order to
614
692
  // prevent cases where focus is shifted onto external elements
615
693
  // when using things like jQuery mobile or MagnificPopup (ref: #249 & #120).
616
694
  // Also, for Firefox, don’t prevent action on the `option` element.
617
- if (event.type == 'mousedown' && !$(target).is('input, select, textarea, button, option')) {
695
+ if ( event.type == 'mousedown' && !$( target ).is( 'input, select, textarea, button, option' )) {
618
696
 
619
- event.preventDefault();
697
+ event.preventDefault()
620
698
 
621
- // Re-focus onto the root so that users can click away
699
+ // Re-focus onto the holder so that users can click away
622
700
  // from elements focused within the picker.
623
- P.$root.eq(0).focus();
701
+ P.$holder.eq(0).focus()
624
702
  }
625
703
  }
626
704
  }
627
- }).
628
705
 
629
- // Add/remove the “target” class on focus and blur.
630
- on({
631
- focus: function () {
632
- $ELEMENT.addClass(CLASSES.target);
633
- },
634
- blur: function () {
635
- $ELEMENT.removeClass(CLASSES.target);
636
- }
637
706
  }).
638
707
 
639
- // Open the picker and adjust the root “focused” state
640
- on('focus.toOpen', handleFocusToOpenEvent).
641
-
642
708
  // If there’s a click on an actionable element, carry out the actions.
643
- on('click', '[data-pick], [data-nav], [data-clear], [data-close]', function () {
709
+ on( 'click', '[data-pick], [data-nav], [data-clear], [data-close]', function() {
644
710
 
645
- var $target = $(this),
711
+ var $target = $( this ),
646
712
  targetData = $target.data(),
647
- targetDisabled = $target.hasClass(CLASSES.navDisabled) || $target.hasClass(CLASSES.disabled),
648
-
713
+ targetDisabled = $target.hasClass( CLASSES.navDisabled ) || $target.hasClass( CLASSES.disabled ),
649
714
 
650
- // * For IE, non-focusable elements can be active elements as well
651
- // (http://stackoverflow.com/a/2684561).
652
- activeElement = getActiveElement();
653
- activeElement = activeElement && (activeElement.type || activeElement.href) && activeElement;
715
+ // * For IE, non-focusable elements can be active elements as well
716
+ // (http://stackoverflow.com/a/2684561).
717
+ activeElement = getActiveElement()
718
+ activeElement = activeElement && ( (activeElement.type || activeElement.href ) ? activeElement : null);
654
719
 
655
720
  // If it’s disabled or nothing inside is actively focused, re-focus the element.
656
- if (targetDisabled || activeElement && !$.contains(P.$root[0], activeElement)) {
657
- P.$root.eq(0).focus();
721
+ if ( targetDisabled || activeElement && !$.contains( P.$root[0], activeElement ) ) {
722
+ P.$holder.eq(0).focus()
658
723
  }
659
724
 
660
725
  // If something is superficially changed, update the `highlight` based on the `nav`.
661
- if (!targetDisabled && targetData.nav) {
662
- P.set('highlight', P.component.item.highlight, { nav: targetData.nav });
726
+ if ( !targetDisabled && targetData.nav ) {
727
+ P.set( 'highlight', P.component.item.highlight, { nav: targetData.nav } )
663
728
  }
664
729
 
665
730
  // If something is picked, set `select` then close with focus.
666
- else if (!targetDisabled && 'pick' in targetData) {
667
- P.set('select', targetData.pick);
668
- if (SETTINGS.closeOnSelect) {
669
- P.close(true);
670
- }
731
+ else if ( !targetDisabled && 'pick' in targetData ) {
732
+ P.set( 'select', targetData.pick )
733
+ if ( SETTINGS.closeOnSelect ) {
734
+ P.close( true )
671
735
  }
736
+ }
672
737
 
673
- // If a “clear” button is pressed, empty the values and close with focus.
674
- else if (targetData.clear) {
675
- P.clear();
676
- if (SETTINGS.closeOnSelect) {
677
- P.close(true);
678
- }
679
- } else if (targetData.close) {
680
- P.close(true);
681
- }
682
- }); //P.$root
738
+ // If a “clear” button is pressed, empty the values and close with focus.
739
+ else if ( targetData.clear ) {
740
+ P.clear()
741
+ if ( SETTINGS.closeOnClear ) {
742
+ P.close( true )
743
+ }
744
+ }
683
745
 
684
- aria(P.$root[0], 'hidden', true);
685
- }
746
+ else if ( targetData.close ) {
747
+ P.close( true )
748
+ }
749
+
750
+ }) //P.$holder
686
751
 
687
- /**
688
- * Prepare the hidden input element along with all bindings.
689
- */
690
- function prepareElementHidden() {
752
+ }
691
753
 
692
- var name;
693
754
 
694
- if (SETTINGS.hiddenName === true) {
695
- name = ELEMENT.name;
696
- ELEMENT.name = '';
697
- } else {
698
- name = [typeof SETTINGS.hiddenPrefix == 'string' ? SETTINGS.hiddenPrefix : '', typeof SETTINGS.hiddenSuffix == 'string' ? SETTINGS.hiddenSuffix : '_submit'];
699
- name = name[0] + ELEMENT.name + name[1];
700
- }
755
+ /**
756
+ * Prepare the hidden input element along with all bindings.
757
+ */
758
+ function prepareElementHidden() {
701
759
 
702
- P._hidden = $('<input ' + 'type=hidden ' +
760
+ var name
761
+
762
+ if ( SETTINGS.hiddenName === true ) {
763
+ name = ELEMENT.name
764
+ ELEMENT.name = ''
765
+ }
766
+ else {
767
+ name = [
768
+ typeof SETTINGS.hiddenPrefix == 'string' ? SETTINGS.hiddenPrefix : '',
769
+ typeof SETTINGS.hiddenSuffix == 'string' ? SETTINGS.hiddenSuffix : '_submit'
770
+ ]
771
+ name = name[0] + ELEMENT.name + name[1]
772
+ }
773
+
774
+ P._hidden = $(
775
+ '<input ' +
776
+ 'type=hidden ' +
703
777
 
704
778
  // Create the name using the original input’s with a prefix and suffix.
705
- 'name="' + name + '"' + (
779
+ 'name="' + name + '"' +
706
780
 
707
781
  // If the element has a value, set the hidden value as well.
708
- $ELEMENT.data('value') || ELEMENT.value ? ' value="' + P.get('select', SETTINGS.formatSubmit) + '"' : '') + '>')[0];
782
+ (
783
+ $ELEMENT.data('value') || ELEMENT.value ?
784
+ ' value="' + P.get('select', SETTINGS.formatSubmit) + '"' :
785
+ ''
786
+ ) +
787
+ '>'
788
+ )[0]
709
789
 
710
- $ELEMENT.
790
+ $ELEMENT.
711
791
 
712
792
  // If the value changes, update the hidden input with the correct format.
713
- on('change.' + STATE.id, function () {
714
- P._hidden.value = ELEMENT.value ? P.get('select', SETTINGS.formatSubmit) : '';
715
- });
793
+ on('change.' + STATE.id, function() {
794
+ P._hidden.value = ELEMENT.value ?
795
+ P.get('select', SETTINGS.formatSubmit) :
796
+ ''
797
+ })
798
+ }
799
+
716
800
 
717
- // Insert the hidden input as specified in the settings.
718
- if (SETTINGS.container) $(SETTINGS.container).append(P._hidden);else $ELEMENT.before(P._hidden);
801
+ // Wait for transitions to end before focusing the holder. Otherwise, while
802
+ // using the `container` option, the view jumps to the container.
803
+ function focusPickerOnceOpened() {
804
+
805
+ if (IS_DEFAULT_THEME && supportsTransitions) {
806
+ P.$holder.find('.' + CLASSES.frame).one('transitionend', function() {
807
+ P.$holder.eq(0).focus()
808
+ })
809
+ }
810
+ else {
811
+ setTimeout(function() {
812
+ P.$holder.eq(0).focus()
813
+ }, 0)
719
814
  }
815
+ }
816
+
817
+
818
+ function handleFocusToOpenEvent(event) {
720
819
 
721
- // For iOS8.
722
- function handleKeydownEvent(event) {
820
+ // Stop the event from propagating to the doc.
821
+ event.stopPropagation()
723
822
 
724
- var keycode = event.keyCode,
823
+ // Add the “target” class.
824
+ $ELEMENT.addClass( CLASSES.target )
725
825
 
826
+ // Add the “focused” class to the root.
827
+ P.$root.addClass( CLASSES.focused )
828
+
829
+ // And then finally open the picker.
830
+ P.open()
831
+ }
832
+
833
+
834
+ // For iOS8.
835
+ function handleKeydownEvent( event ) {
836
+
837
+ var keycode = event.keyCode,
726
838
 
727
839
  // Check if one of the delete keys was pressed.
728
- isKeycodeDelete = /^(8|46)$/.test(keycode);
840
+ isKeycodeDelete = /^(8|46)$/.test(keycode)
729
841
 
730
- // For some reason IE clears the input value on “escape”.
731
- if (keycode == 27) {
732
- P.close();
733
- return false;
734
- }
842
+ // For some reason IE clears the input value on “escape”.
843
+ if ( keycode == 27 ) {
844
+ P.close( true )
845
+ return false
846
+ }
735
847
 
736
- // Check if `space` or `delete` was pressed or the picker is closed with a key movement.
737
- if (keycode == 32 || isKeycodeDelete || !STATE.open && P.component.key[keycode]) {
848
+ // Check if `space` or `delete` was pressed or the picker is closed with a key movement.
849
+ if ( keycode == 32 || isKeycodeDelete || !STATE.open && P.component.key[keycode] ) {
738
850
 
739
- // Prevent it from moving the page and bubbling to doc.
740
- event.preventDefault();
741
- event.stopPropagation();
851
+ // Prevent it from moving the page and bubbling to doc.
852
+ event.preventDefault()
853
+ event.stopPropagation()
742
854
 
743
- // If `delete` was pressed, clear the values and close the picker.
744
- // Otherwise open the picker.
745
- if (isKeycodeDelete) {
746
- P.clear().close();
747
- } else {
748
- P.open();
749
- }
750
- }
855
+ // If `delete` was pressed, clear the values and close the picker.
856
+ // Otherwise open the picker.
857
+ if ( isKeycodeDelete ) { P.clear().close() }
858
+ else { P.open() }
751
859
  }
860
+ }
752
861
 
753
- // Separated for IE
754
- function handleFocusToOpenEvent(event) {
755
862
 
756
- // Stop the event from propagating to the doc.
757
- event.stopPropagation();
863
+ // Return a new picker instance.
864
+ return new PickerInstance()
865
+ } //PickerConstructor
758
866
 
759
- // If it’s a focus event, add the “focused” class to the root.
760
- if (event.type == 'focus') {
761
- P.$root.addClass(CLASSES.focused);
762
- }
763
867
 
764
- // And then finally open the picker.
765
- P.open();
766
- }
767
868
 
768
- // Return a new picker instance.
769
- return new PickerInstance();
770
- } //PickerConstructor
869
+ /**
870
+ * The default classes and prefix to use for the HTML classes.
871
+ */
872
+ PickerConstructor.klasses = function( prefix ) {
873
+ prefix = prefix || 'picker'
874
+ return {
771
875
 
876
+ picker: prefix,
877
+ opened: prefix + '--opened',
878
+ focused: prefix + '--focused',
772
879
 
773
- /**
774
- * The default classes and prefix to use for the HTML classes.
775
- */
776
- PickerConstructor.klasses = function (prefix) {
777
- prefix = prefix || 'picker';
778
- return {
880
+ input: prefix + '__input',
881
+ active: prefix + '__input--active',
882
+ target: prefix + '__input--target',
779
883
 
780
- picker: prefix,
781
- opened: prefix + '--opened',
782
- focused: prefix + '--focused',
884
+ holder: prefix + '__holder',
783
885
 
784
- input: prefix + '__input',
785
- active: prefix + '__input--active',
786
- target: prefix + '__input--target',
886
+ frame: prefix + '__frame',
887
+ wrap: prefix + '__wrap',
787
888
 
788
- holder: prefix + '__holder',
889
+ box: prefix + '__box'
890
+ }
891
+ } //PickerConstructor.klasses
789
892
 
790
- frame: prefix + '__frame',
791
- wrap: prefix + '__wrap',
792
893
 
793
- box: prefix + '__box'
794
- };
795
- }; //PickerConstructor.klasses
796
894
 
895
+ /**
896
+ * Check if the default theme is being used.
897
+ */
898
+ function isUsingDefaultTheme( element ) {
797
899
 
798
- /**
799
- * Check if the default theme is being used.
800
- */
801
- function isUsingDefaultTheme(element) {
900
+ var theme,
901
+ prop = 'position'
802
902
 
803
- var theme,
804
- prop = 'position';
903
+ // For IE.
904
+ if ( element.currentStyle ) {
905
+ theme = element.currentStyle[prop]
906
+ }
805
907
 
806
- // For IE.
807
- if (element.currentStyle) {
808
- theme = element.currentStyle[prop];
809
- }
908
+ // For normal browsers.
909
+ else if ( window.getComputedStyle ) {
910
+ theme = getComputedStyle( element )[prop]
911
+ }
810
912
 
811
- // For normal browsers.
812
- else if (window.getComputedStyle) {
813
- theme = getComputedStyle(element)[prop];
814
- }
913
+ return theme == 'fixed'
914
+ }
815
915
 
816
- return theme == 'fixed';
916
+
917
+
918
+ /**
919
+ * Get the width of the browser’s scrollbar.
920
+ * Taken from: https://github.com/VodkaBears/Remodal/blob/master/src/jquery.remodal.js
921
+ */
922
+ function getScrollbarWidth() {
923
+
924
+ if ( $html.height() <= $window.height() ) {
925
+ return 0
817
926
  }
818
927
 
819
- /**
820
- * Get the width of the browser’s scrollbar.
821
- * Taken from: https://github.com/VodkaBears/Remodal/blob/master/src/jquery.remodal.js
822
- */
823
- function getScrollbarWidth() {
928
+ var $outer = $( '<div style="visibility:hidden;width:100px" />' ).
929
+ appendTo( 'body' )
824
930
 
825
- if ($html.height() <= $window.height()) {
826
- return 0;
827
- }
931
+ // Get the width without scrollbars.
932
+ var widthWithoutScroll = $outer[0].offsetWidth
933
+
934
+ // Force adding scrollbars.
935
+ $outer.css( 'overflow', 'scroll' )
936
+
937
+ // Add the inner div.
938
+ var $inner = $( '<div style="width:100%" />' ).appendTo( $outer )
828
939
 
829
- var $outer = $('<div style="visibility:hidden;width:100px" />').appendTo('body');
940
+ // Get the width with scrollbars.
941
+ var widthWithScroll = $inner[0].offsetWidth
830
942
 
831
- // Get the width without scrollbars.
832
- var widthWithoutScroll = $outer[0].offsetWidth;
943
+ // Remove the divs.
944
+ $outer.remove()
833
945
 
834
- // Force adding scrollbars.
835
- $outer.css('overflow', 'scroll');
946
+ // Return the difference between the widths.
947
+ return widthWithoutScroll - widthWithScroll
948
+ }
836
949
 
837
- // Add the inner div.
838
- var $inner = $('<div style="width:100%" />').appendTo($outer);
839
950
 
840
- // Get the width with scrollbars.
841
- var widthWithScroll = $inner[0].offsetWidth;
842
951
 
843
- // Remove the divs.
844
- $outer.remove();
952
+ /**
953
+ * Get the target element from the event.
954
+ * If ELEMENT is supplied and present in the event path (ELEMENT is ancestor of the target),
955
+ * returns ELEMENT instead
956
+ */
957
+ function getRealEventTarget( event, ELEMENT ) {
958
+
959
+ var path = []
845
960
 
846
- // Return the difference between the widths.
847
- return widthWithoutScroll - widthWithScroll;
961
+ if ( event.path ) {
962
+ path = event.path
848
963
  }
849
964
 
965
+ if ( event.originalEvent && event.originalEvent.path ) {
966
+ path = event.originalEvent.path
967
+ }
968
+
969
+ if ( path && path.length > 0 ) {
970
+ if ( ELEMENT && path.indexOf( ELEMENT ) >= 0 ) {
971
+ return ELEMENT
972
+ } else {
973
+ return path[0]
974
+ }
975
+ }
976
+
977
+ return event.target
978
+ }
979
+
980
+ // taken from https://davidwalsh.name/javascript-debounce-function
981
+ function debounce(func, wait, immediate) {
982
+ var timeout;
983
+ return function() {
984
+ var context = this, args = arguments;
985
+ var later = function() {
986
+ timeout = null;
987
+ if (!immediate) func.apply(context, args);
988
+ };
989
+ var callNow = immediate && !timeout;
990
+ clearTimeout(timeout);
991
+ timeout = setTimeout(later, wait);
992
+ if (callNow) func.apply(context, args);
993
+ };
994
+ }
995
+
996
+ /**
997
+ * PickerConstructor helper methods.
998
+ */
999
+ PickerConstructor._ = {
1000
+
850
1001
  /**
851
- * PickerConstructor helper methods.
1002
+ * Create a group of nodes. Expects:
1003
+ * `
1004
+ {
1005
+ min: {Integer},
1006
+ max: {Integer},
1007
+ i: {Integer},
1008
+ node: {String},
1009
+ item: {Function}
1010
+ }
1011
+ * `
852
1012
  */
853
- PickerConstructor._ = {
854
-
855
- /**
856
- * Create a group of nodes. Expects:
857
- * `
858
- {
859
- min: {Integer},
860
- max: {Integer},
861
- i: {Integer},
862
- node: {String},
863
- item: {Function}
864
- }
865
- * `
866
- */
867
- group: function (groupObject) {
1013
+ group: function( groupObject ) {
868
1014
 
869
- var
1015
+ var
870
1016
  // Scope for the looped object
871
1017
  loopObjectScope,
872
1018
 
873
-
874
1019
  // Create the nodes list
875
1020
  nodesList = '',
876
1021
 
877
-
878
1022
  // The counter starts from the `min`
879
- counter = PickerConstructor._.trigger(groupObject.min, groupObject);
1023
+ counter = PickerConstructor._.trigger( groupObject.min, groupObject )
880
1024
 
881
- // Loop from the `min` to `max`, incrementing by `i`
882
- for (; counter <= PickerConstructor._.trigger(groupObject.max, groupObject, [counter]); counter += groupObject.i) {
883
1025
 
884
- // Trigger the `item` function within scope of the object
885
- loopObjectScope = PickerConstructor._.trigger(groupObject.item, groupObject, [counter]);
1026
+ // Loop from the `min` to `max`, incrementing by `i`
1027
+ for ( ; counter <= PickerConstructor._.trigger( groupObject.max, groupObject, [ counter ] ); counter += groupObject.i ) {
886
1028
 
887
- // Splice the subgroup and create nodes out of the sub nodes
888
- nodesList += PickerConstructor._.node(groupObject.node, loopObjectScope[0], // the node
889
- loopObjectScope[1], // the classes
890
- loopObjectScope[2] // the attributes
891
- );
892
- }
1029
+ // Trigger the `item` function within scope of the object
1030
+ loopObjectScope = PickerConstructor._.trigger( groupObject.item, groupObject, [ counter ] )
893
1031
 
894
- // Return the list of nodes
895
- return nodesList;
896
- }, //group
1032
+ // Splice the subgroup and create nodes out of the sub nodes
1033
+ nodesList += PickerConstructor._.node(
1034
+ groupObject.node,
1035
+ loopObjectScope[ 0 ], // the node
1036
+ loopObjectScope[ 1 ], // the classes
1037
+ loopObjectScope[ 2 ] // the attributes
1038
+ )
1039
+ }
897
1040
 
1041
+ // Return the list of nodes
1042
+ return nodesList
1043
+ }, //group
898
1044
 
899
- /**
900
- * Create a dom node string
901
- */
902
- node: function (wrapper, item, klass, attribute) {
903
1045
 
904
- // If the item is false-y, just return an empty string
905
- if (!item) return '';
1046
+ /**
1047
+ * Create a dom node string
1048
+ */
1049
+ node: function( wrapper, item, klass, attribute ) {
906
1050
 
907
- // If the item is an array, do a join
908
- item = $.isArray(item) ? item.join('') : item;
1051
+ // If the item is false-y, just return an empty string
1052
+ if ( !item ) return ''
909
1053
 
910
- // Check for the class
911
- klass = klass ? ' class="' + klass + '"' : '';
1054
+ // If the item is an array, do a join
1055
+ item = $.isArray( item ) ? item.join( '' ) : item
912
1056
 
913
- // Check for any attributes
914
- attribute = attribute ? ' ' + attribute : '';
1057
+ // Check for the class
1058
+ klass = klass ? ' class="' + klass + '"' : ''
915
1059
 
916
- // Return the wrapped item
917
- return '<' + wrapper + klass + attribute + '>' + item + '</' + wrapper + '>';
918
- }, //node
1060
+ // Check for any attributes
1061
+ attribute = attribute ? ' ' + attribute : ''
919
1062
 
1063
+ // Return the wrapped item
1064
+ return '<' + wrapper + klass + attribute + '>' + item + '</' + wrapper + '>'
1065
+ }, //node
920
1066
 
921
- /**
922
- * Lead numbers below 10 with a zero.
923
- */
924
- lead: function (number) {
925
- return (number < 10 ? '0' : '') + number;
926
- },
927
1067
 
928
- /**
929
- * Trigger a function otherwise return the value.
930
- */
931
- trigger: function (callback, scope, args) {
932
- return typeof callback == 'function' ? callback.apply(scope, args || []) : callback;
933
- },
1068
+ /**
1069
+ * Lead numbers below 10 with a zero.
1070
+ */
1071
+ lead: function( number ) {
1072
+ return ( number < 10 ? '0': '' ) + number
1073
+ },
934
1074
 
935
- /**
936
- * If the second character is a digit, length is 2 otherwise 1.
937
- */
938
- digits: function (string) {
939
- return (/\d/.test(string[1]) ? 2 : 1
940
- );
941
- },
942
1075
 
943
- /**
944
- * Tell if something is a date object.
945
- */
946
- isDate: function (value) {
947
- return {}.toString.call(value).indexOf('Date') > -1 && this.isInteger(value.getDate());
948
- },
1076
+ /**
1077
+ * Trigger a function otherwise return the value.
1078
+ */
1079
+ trigger: function( callback, scope, args ) {
1080
+ return typeof callback == 'function' ? callback.apply( scope, args || [] ) : callback
1081
+ },
949
1082
 
950
- /**
951
- * Tell if something is an integer.
952
- */
953
- isInteger: function (value) {
954
- return {}.toString.call(value).indexOf('Number') > -1 && value % 1 === 0;
955
- },
956
1083
 
957
- /**
958
- * Create ARIA attribute strings.
959
- */
960
- ariaAttr: ariaAttr //PickerConstructor._
1084
+ /**
1085
+ * If the second character is a digit, length is 2 otherwise 1.
1086
+ */
1087
+ digits: function( string ) {
1088
+ return ( /\d/ ).test( string[ 1 ] ) ? 2 : 1
1089
+ },
961
1090
 
962
1091
 
963
- /**
964
- * Extend the picker with a component and defaults.
965
- */
966
- };PickerConstructor.extend = function (name, Component) {
1092
+ /**
1093
+ * Tell if something is a date object.
1094
+ */
1095
+ isDate: function( value ) {
1096
+ return {}.toString.call( value ).indexOf( 'Date' ) > -1 && this.isInteger( value.getDate() )
1097
+ },
967
1098
 
968
- // Extend jQuery.
969
- $.fn[name] = function (options, action) {
970
1099
 
971
- // Grab the component data.
972
- var componentData = this.data(name);
1100
+ /**
1101
+ * Tell if something is an integer.
1102
+ */
1103
+ isInteger: function( value ) {
1104
+ return {}.toString.call( value ).indexOf( 'Number' ) > -1 && value % 1 === 0
1105
+ },
973
1106
 
974
- // If the picker is requested, return the data object.
975
- if (options == 'picker') {
976
- return componentData;
977
- }
978
1107
 
979
- // If the component data exists and `options` is a string, carry out the action.
980
- if (componentData && typeof options == 'string') {
981
- return PickerConstructor._.trigger(componentData[options], componentData, [action]);
982
- }
1108
+ /**
1109
+ * Create ARIA attribute strings.
1110
+ */
1111
+ ariaAttr: ariaAttr
1112
+ } //PickerConstructor._
983
1113
 
984
- // Otherwise go through each matched element and if the component
985
- // doesn’t exist, create a new picker using `this` element
986
- // and merging the defaults and options with a deep copy.
987
- return this.each(function () {
988
- var $this = $(this);
989
- if (!$this.data(name)) {
990
- new PickerConstructor(this, name, Component, options);
991
- }
992
- });
993
- };
994
1114
 
995
- // Set the defaults.
996
- $.fn[name].defaults = Component.defaults;
997
- }; //PickerConstructor.extend
998
1115
 
1116
+ /**
1117
+ * Extend the picker with a component and defaults.
1118
+ */
1119
+ PickerConstructor.extend = function( name, Component ) {
1120
+
1121
+ // Extend jQuery.
1122
+ $.fn[ name ] = function( options, action ) {
1123
+
1124
+ // Grab the component data.
1125
+ var componentData = this.data( name )
1126
+
1127
+ // If the picker is requested, return the data object.
1128
+ if ( options == 'picker' ) {
1129
+ return componentData
1130
+ }
1131
+
1132
+ // If the component data exists and `options` is a string, carry out the action.
1133
+ if ( componentData && typeof options == 'string' ) {
1134
+ return PickerConstructor._.trigger( componentData[ options ], componentData, [ action ] )
1135
+ }
999
1136
 
1000
- function aria(element, attribute, value) {
1001
- if ($.isPlainObject(attribute)) {
1002
- for (var key in attribute) {
1003
- ariaSet(element, key, attribute[key]);
1137
+ // Otherwise go through each matched element and if the component
1138
+ // doesn’t exist, create a new picker using `this` element
1139
+ // and merging the defaults and options with a deep copy.
1140
+ return this.each( function() {
1141
+ var $this = $( this )
1142
+ if ( !$this.data( name ) ) {
1143
+ new PickerConstructor( this, name, Component, options )
1004
1144
  }
1005
- } else {
1006
- ariaSet(element, attribute, value);
1145
+ })
1146
+ }
1147
+
1148
+ // Set the defaults.
1149
+ $.fn[ name ].defaults = Component.defaults
1150
+ } //PickerConstructor.extend
1151
+
1152
+
1153
+
1154
+ function aria(element, attribute, value) {
1155
+ if ( $.isPlainObject(attribute) ) {
1156
+ for ( var key in attribute ) {
1157
+ ariaSet(element, key, attribute[key])
1007
1158
  }
1008
1159
  }
1009
- function ariaSet(element, attribute, value) {
1010
- element.setAttribute((attribute == 'role' ? '' : 'aria-') + attribute, value);
1160
+ else {
1161
+ ariaSet(element, attribute, value)
1011
1162
  }
1012
- function ariaAttr(attribute, data) {
1013
- if (!$.isPlainObject(attribute)) {
1014
- attribute = { attribute: data };
1015
- }
1016
- data = '';
1017
- for (var key in attribute) {
1018
- var attr = (key == 'role' ? '' : 'aria-') + key,
1019
- attrVal = attribute[key];
1020
- data += attrVal == null ? '' : attr + '="' + attribute[key] + '"';
1021
- }
1022
- return data;
1163
+ }
1164
+ function ariaSet(element, attribute, value) {
1165
+ element.setAttribute(
1166
+ (attribute == 'role' ? '' : 'aria-') + attribute,
1167
+ value
1168
+ )
1169
+ }
1170
+ function ariaAttr(attribute, data) {
1171
+ if ( !$.isPlainObject(attribute) ) {
1172
+ attribute = { attribute: data }
1023
1173
  }
1024
-
1025
- // IE8 bug throws an error for activeElements within iframes.
1026
- function getActiveElement() {
1027
- try {
1028
- return document.activeElement;
1029
- } catch (err) {}
1174
+ data = ''
1175
+ for ( var key in attribute ) {
1176
+ var attr = (key == 'role' ? '' : 'aria-') + key,
1177
+ attrVal = attribute[key]
1178
+ data += attrVal == null ? '' : attr + '="' + attribute[key] + '"'
1030
1179
  }
1180
+ return data
1181
+ }
1182
+
1183
+ // IE8 bug throws an error for activeElements within iframes.
1184
+ function getActiveElement() {
1185
+ try {
1186
+ return document.activeElement
1187
+ } catch ( err ) { }
1188
+ }
1189
+
1190
+
1191
+
1192
+ // Expose the picker constructor.
1193
+ return PickerConstructor
1194
+
1031
1195
 
1032
- // Expose the picker constructor.
1033
- return PickerConstructor;
1034
1196
  });