pickadate-rails 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +61 -0
  6. data/Rakefile +26 -0
  7. data/lib/pickadate-rails.rb +7 -0
  8. data/lib/pickadate-rails/version.rb +3 -0
  9. data/pickadate-rails.gemspec +25 -0
  10. data/vendor/assets/javascripts/pickadate/picker.date.js +925 -0
  11. data/vendor/assets/javascripts/pickadate/picker.js +785 -0
  12. data/vendor/assets/javascripts/pickadate/picker.time.js +651 -0
  13. data/vendor/assets/javascripts/pickadate/translations/bg_BG.js +13 -0
  14. data/vendor/assets/javascripts/pickadate/translations/bs_BA.js +13 -0
  15. data/vendor/assets/javascripts/pickadate/translations/ca_ES.js +13 -0
  16. data/vendor/assets/javascripts/pickadate/translations/cs_CZ.js +13 -0
  17. data/vendor/assets/javascripts/pickadate/translations/da_DK.js +13 -0
  18. data/vendor/assets/javascripts/pickadate/translations/de_DE.js +13 -0
  19. data/vendor/assets/javascripts/pickadate/translations/el_GR.js +13 -0
  20. data/vendor/assets/javascripts/pickadate/translations/es_ES.js +13 -0
  21. data/vendor/assets/javascripts/pickadate/translations/et_EE.js +13 -0
  22. data/vendor/assets/javascripts/pickadate/translations/eu_ES.js +13 -0
  23. data/vendor/assets/javascripts/pickadate/translations/fi_FI.js +13 -0
  24. data/vendor/assets/javascripts/pickadate/translations/fr_FR.js +13 -0
  25. data/vendor/assets/javascripts/pickadate/translations/he_IL.js +12 -0
  26. data/vendor/assets/javascripts/pickadate/translations/hr_HR.js +13 -0
  27. data/vendor/assets/javascripts/pickadate/translations/hu_HU.js +13 -0
  28. data/vendor/assets/javascripts/pickadate/translations/id_ID.js +13 -0
  29. data/vendor/assets/javascripts/pickadate/translations/it_IT.js +13 -0
  30. data/vendor/assets/javascripts/pickadate/translations/nl_NL.js +13 -0
  31. data/vendor/assets/javascripts/pickadate/translations/no_NO.js +13 -0
  32. data/vendor/assets/javascripts/pickadate/translations/pl_PL.js +13 -0
  33. data/vendor/assets/javascripts/pickadate/translations/pt_BR.js +12 -0
  34. data/vendor/assets/javascripts/pickadate/translations/pt_PT.js +12 -0
  35. data/vendor/assets/javascripts/pickadate/translations/ro_RO.js +13 -0
  36. data/vendor/assets/javascripts/pickadate/translations/ru_RU.js +13 -0
  37. data/vendor/assets/javascripts/pickadate/translations/sk_SK.js +13 -0
  38. data/vendor/assets/javascripts/pickadate/translations/sv_SE.js +13 -0
  39. data/vendor/assets/javascripts/pickadate/translations/th_TH.js +12 -0
  40. data/vendor/assets/javascripts/pickadate/translations/tr_TR.js +13 -0
  41. data/vendor/assets/javascripts/pickadate/translations/uk_UA.js +13 -0
  42. data/vendor/assets/javascripts/pickadate/translations/zh_CN.js +13 -0
  43. data/vendor/assets/stylesheets/pickadate/classic.css +159 -0
  44. data/vendor/assets/stylesheets/pickadate/classic.date.css +332 -0
  45. data/vendor/assets/stylesheets/pickadate/classic.time.css +198 -0
  46. data/vendor/assets/stylesheets/pickadate/default.css +234 -0
  47. data/vendor/assets/stylesheets/pickadate/default.date.css +332 -0
  48. data/vendor/assets/stylesheets/pickadate/default.time.css +193 -0
  49. metadata +134 -0
@@ -0,0 +1,785 @@
1
+
2
+ /*!
3
+ * pickadate.js v3.0.3, 2013/05/23
4
+ * By Amsul, http://amsul.ca
5
+ * Hosted on http://amsul.github.io/pickadate.js
6
+ * Licensed under MIT
7
+ */
8
+
9
+ /*jshint
10
+ debug: true,
11
+ devel: true,
12
+ browser: true,
13
+ asi: true,
14
+ unused: true,
15
+ boss: true,
16
+ eqnull: true
17
+ */
18
+
19
+
20
+ // Create a global scope.
21
+ window.Picker = (function( $, $document, undefined ) {
22
+
23
+
24
+ /**
25
+ * The picker constructor that creates a blank picker.
26
+ */
27
+ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) {
28
+
29
+ // If there’s no element, return the picker constructor.
30
+ if ( !ELEMENT ) return PickerConstructor
31
+
32
+
33
+ var
34
+ // The state of the picker.
35
+ STATE = {
36
+ id: Math.abs( ~~( Math.random() * 1e9 ) )
37
+ },
38
+
39
+
40
+ // Merge the defaults and options passed.
41
+ SETTINGS = COMPONENT ? $.extend( true, {}, COMPONENT.defaults, OPTIONS ) : OPTIONS || {},
42
+
43
+
44
+ // Merge the default classes with the settings classes.
45
+ CLASSES = $.extend( {}, PickerConstructor.klasses(), SETTINGS.klass ),
46
+
47
+
48
+ // The element node wrapper into a jQuery object.
49
+ $ELEMENT = $( ELEMENT ),
50
+
51
+
52
+ // Pseudo picker constructor.
53
+ PickerInstance = function() {
54
+ return this.start()
55
+ },
56
+
57
+
58
+ // The picker prototype.
59
+ P = PickerInstance.prototype = {
60
+
61
+ constructor: PickerInstance,
62
+
63
+ $node: $ELEMENT,
64
+
65
+
66
+ /**
67
+ * Initialize everything
68
+ */
69
+ start: function() {
70
+
71
+ // If it’s already started, do nothing.
72
+ if ( STATE && STATE.start ) return P
73
+
74
+
75
+ // Update the picker states.
76
+ STATE.methods = {}
77
+ STATE.start = true
78
+ STATE.open = false
79
+ STATE.type = ELEMENT.type
80
+
81
+
82
+ // Confirm focus state, save original type, convert into text input
83
+ // to remove UA stylings, and set as readonly to prevent keyboard popup.
84
+ ELEMENT.autofocus = ELEMENT == document.activeElement
85
+ ELEMENT.type = 'text'
86
+ ELEMENT.readOnly = true
87
+
88
+
89
+ // Create a new picker component with the settings.
90
+ P.component = new COMPONENT( P, SETTINGS )
91
+
92
+
93
+ // Create the picker root with a new wrapped holder and bind the events.
94
+ P.$root = $( PickerConstructor._.node( 'div', createWrappedComponent(), CLASSES.picker ) ).on({
95
+
96
+ // When something within the root is focused, stop from bubbling
97
+ // to the doc and remove the “focused” state from the root.
98
+ focusin: function( event ) {
99
+ P.$root.removeClass( CLASSES.focused )
100
+ event.stopPropagation()
101
+ },
102
+
103
+ // If the event is not on the root holder, stop it from bubbling to the doc.
104
+ mousedown: function( event ) {
105
+ if ( event.target != P.$root.children()[ 0 ] ) {
106
+ event.stopPropagation()
107
+ }
108
+ },
109
+
110
+ // When something within the root holder is clicked, handle the various event.
111
+ click: function( event ) {
112
+
113
+ var target = event.target,
114
+ $target = target.attributes.length ? $( target ) : $( target ).closest( '[data-pick]' ),
115
+ targetData = $target.data()
116
+
117
+ // If the event is not on the root holder itself, handle the clicks within.
118
+ if ( target != P.$root.children()[ 0 ] ) {
119
+
120
+ // Stop it from propagating to the doc.
121
+ event.stopPropagation()
122
+
123
+ // If nothing inside is actively focused, re-focus the element.
124
+ if ( !P.$root.find( document.activeElement ).length ) {
125
+ ELEMENT.focus()
126
+ }
127
+
128
+ // If something is superficially changed, update the `highlight` based on the `nav`.
129
+ if ( targetData.nav && !$target.hasClass( CLASSES.navDisabled ) ) {
130
+ P.set( 'highlight', P.component.item.highlight, { nav: targetData.nav } )
131
+ }
132
+
133
+ // If something is picked, set `select` then close with focus.
134
+ else if ( PickerConstructor._.isInteger( targetData.pick ) && !$target.hasClass( CLASSES.disabled ) ) {
135
+ P.set( 'select', targetData.pick ).close( true )
136
+ }
137
+
138
+ // If a “clear” button is pressed, empty the values and close with focus.
139
+ else if ( targetData.clear ) {
140
+ P.clear().close( true )
141
+ }
142
+ }
143
+ }
144
+ }) //P.$root
145
+
146
+
147
+ // If there’s a format for the hidden input element, create the element
148
+ // using the name of the original input plus suffix. Otherwise set it to null.
149
+ // If the element has a value, use either the `data-value` or `value`.
150
+ P._hidden = SETTINGS.formatSubmit ? $( '<input type=hidden name=' + ELEMENT.name + ( SETTINGS.hiddenSuffix || '_submit' ) + ( $ELEMENT.data( 'value' ) ? ' value="' + PickerConstructor._.trigger( P.component.formats.toString, P.component, [ SETTINGS.formatSubmit, P.component.item.select ] ) + '"' : '' ) + '>' )[ 0 ] : undefined
151
+
152
+
153
+ // Add the class and bind the events on the element.
154
+ $ELEMENT.addClass( CLASSES.input ).
155
+
156
+ // On focus/click, open the picker and adjust the root “focused” state.
157
+ on( 'focus.P' + STATE.id + ' click.P' + STATE.id, focusToOpen ).
158
+
159
+ // If the value changes, update the hidden input with the correct format.
160
+ on( 'change.P' + STATE.id, function() {
161
+ if ( P._hidden ) {
162
+ P._hidden.value = ELEMENT.value ? PickerConstructor._.trigger( P.component.formats.toString, P.component, [ SETTINGS.formatSubmit, P.component.item.select ] ) : ''
163
+ }
164
+ }).
165
+
166
+ // Handle keyboard event based on the picker being opened or not.
167
+ on( 'keydown.P' + STATE.id, function( event ) {
168
+
169
+ var keycode = event.keyCode,
170
+
171
+ // Check if one of the delete keys was pressed.
172
+ isKeycodeDelete = /^(8|46)$/.test( keycode )
173
+
174
+ // For some reason IE clears the input value on “escape”.
175
+ if ( keycode == 27 ) {
176
+ P.close()
177
+ return false
178
+ }
179
+
180
+ // Check if `space` or `delete` was pressed or the picker is closed with a key movement.
181
+ if ( keycode == 32 || isKeycodeDelete || !STATE.open && P.component.key[ keycode ] ) {
182
+
183
+ // Prevent it from moving the page and bubbling to doc.
184
+ event.preventDefault()
185
+ event.stopPropagation()
186
+
187
+ // If `delete` was pressed, clear the values and close the picker.
188
+ // Otherwise open the picker.
189
+ if ( isKeycodeDelete ) { P.clear().close() }
190
+ else { P.open() }
191
+ }
192
+ }).
193
+
194
+ // If there’s a `data-value`, update the value of the element.
195
+ val( $ELEMENT.data( 'value' ) ? PickerConstructor._.trigger( P.component.formats.toString, P.component, [ SETTINGS.format, P.component.item.select ] ) : ELEMENT.value ).
196
+
197
+ // Insert the root and hidden input after the element.
198
+ after( P.$root, P._hidden ).
199
+
200
+ // Store the picker data by component name.
201
+ data( NAME, P )
202
+
203
+
204
+ // Bind the default component and settings events.
205
+ P.on({
206
+ start: P.component.onStart,
207
+ render: P.component.onRender,
208
+ stop: P.component.onStop,
209
+ open: P.component.onOpen,
210
+ close: P.component.onClose,
211
+ set: P.component.onSet
212
+ }).on({
213
+ start: SETTINGS.onStart,
214
+ render: SETTINGS.onRender,
215
+ stop: SETTINGS.onStop,
216
+ open: SETTINGS.onOpen,
217
+ close: SETTINGS.onClose,
218
+ set: SETTINGS.onSet
219
+ })
220
+
221
+
222
+ // If the element has autofocus, open the picker.
223
+ if ( ELEMENT.autofocus ) {
224
+ P.open()
225
+ }
226
+
227
+
228
+ // Trigger queued the “start” and “render” events.
229
+ return P.trigger( 'start' ).trigger( 'render' )
230
+ }, //start
231
+
232
+
233
+ /**
234
+ * Render a new picker within the root
235
+ */
236
+ render: function() {
237
+
238
+ // Insert a new component holder in the root.
239
+ P.$root.html( createWrappedComponent() )
240
+
241
+ // Trigger the queued “render” events.
242
+ return P.trigger( 'render' )
243
+ }, //render
244
+
245
+
246
+ /**
247
+ * Destroy everything
248
+ */
249
+ stop: function() {
250
+
251
+ // If it’s already stopped, do nothing.
252
+ if ( !STATE.start ) return P
253
+
254
+ // Then close the picker.
255
+ P.close()
256
+
257
+ // Remove the hidden field.
258
+ if ( P._hidden ) {
259
+ P._hidden.parentNode.removeChild( P._hidden )
260
+ }
261
+
262
+ // Remove the root.
263
+ P.$root.remove()
264
+
265
+ // Remove the input class, unbind the events, and remove the stored data.
266
+ $ELEMENT.removeClass( CLASSES.input ).off( '.P' + STATE.id ).removeData( NAME )
267
+
268
+ // Restore the element state
269
+ ELEMENT.type = STATE.type
270
+ ELEMENT.readOnly = false
271
+
272
+ // Trigger the queued “stop” events.
273
+ P.trigger( 'stop' )
274
+
275
+ // Reset the picker states.
276
+ STATE.methods = {}
277
+ STATE.start = false
278
+
279
+ return P
280
+ }, //stop
281
+
282
+
283
+ /*
284
+ * Open up the picker
285
+ */
286
+ open: function( dontGiveFocus ) {
287
+
288
+ // If it’s already open, do nothing.
289
+ if ( STATE.open ) return P
290
+
291
+ // Add the “active” class.
292
+ $ELEMENT.addClass( CLASSES.active )
293
+
294
+ // Add the “opened” class to the picker root.
295
+ P.$root.addClass( CLASSES.opened )
296
+
297
+ // If we have to give focus, bind the element and doc events.
298
+ if ( dontGiveFocus !== false ) {
299
+
300
+ // Set it as open.
301
+ STATE.open = true
302
+
303
+ // Pass focus to the element’s jQuery object.
304
+ $ELEMENT.focus()
305
+
306
+ // Bind the document events.
307
+ $document.on( 'click.P' + STATE.id + ' focusin.P' + STATE.id, function( event ) {
308
+
309
+ // If the target of the event is not the element, close the picker picker.
310
+ // * Don’t worry about clicks or focusins on the root because those don’t bubble up.
311
+ // Also, for Firefox, a click on an `option` element bubbles up directly
312
+ // to the doc. So make sure the target wasn't the doc.
313
+ if ( event.target != ELEMENT && event.target != document ) P.close()
314
+
315
+ }).on( 'keydown.P' + STATE.id, function( event ) {
316
+
317
+ var
318
+ // Get the keycode.
319
+ keycode = event.keyCode,
320
+
321
+ // Translate that to a selection change.
322
+ keycodeToMove = P.component.key[ keycode ],
323
+
324
+ // Grab the target.
325
+ target = event.target
326
+
327
+
328
+ // On escape, close the picker and give focus.
329
+ if ( keycode == 27 ) {
330
+ P.close( true )
331
+ }
332
+
333
+
334
+ // Check if there is a key movement or “enter” keypress on the element.
335
+ else if ( target == ELEMENT && ( keycodeToMove || keycode == 13 ) ) {
336
+
337
+ // Prevent the default action to stop page movement.
338
+ event.preventDefault()
339
+
340
+ // Trigger the key movement action.
341
+ if ( keycodeToMove ) {
342
+ PickerConstructor._.trigger( P.component.key.go, P, [ keycodeToMove ] )
343
+ }
344
+
345
+ // On “enter”, if the highlighted item isn’t disabled, set the value and close.
346
+ else if ( !P.$root.find( '.' + CLASSES.highlighted ).hasClass( CLASSES.disabled ) ) {
347
+ P.set( 'select', P.component.item.highlight ).close()
348
+ }
349
+ }
350
+
351
+
352
+ // If the target is within the root and “enter” is pressed,
353
+ // prevent the default action and trigger a click on the target instead.
354
+ else if ( P.$root.find( target ).length && keycode == 13 ) {
355
+ event.preventDefault()
356
+ target.click()
357
+ }
358
+ })
359
+ }
360
+
361
+ // Trigger the queued “open” events.
362
+ return P.trigger( 'open' )
363
+ }, //open
364
+
365
+
366
+ /**
367
+ * Close the picker
368
+ */
369
+ close: function( giveFocus ) {
370
+
371
+ // If we need to give focus, do it before changing states.
372
+ if ( giveFocus ) {
373
+ // ....ah yes! It would’ve been incomplete without a crazy workaround for IE :|
374
+ // The focus is triggered *after* the close has completed - causing it
375
+ // to open again. So unbind and rebind the event at the next tick.
376
+ $ELEMENT.off( 'focus.P' + STATE.id ).focus()
377
+ setTimeout( function() {
378
+ $ELEMENT.on( 'focus.P' + STATE.id, focusToOpen )
379
+ }, 0 )
380
+ }
381
+
382
+ // Remove the “active” class.
383
+ $ELEMENT.removeClass( CLASSES.active )
384
+
385
+ // Remove the “opened” and “focused” class from the picker root.
386
+ P.$root.removeClass( CLASSES.opened + ' ' + CLASSES.focused )
387
+
388
+ // If it’s open, update the state.
389
+ if ( STATE.open ) {
390
+
391
+ // Set it as closed.
392
+ STATE.open = false
393
+
394
+ // Unbind the document events.
395
+ $document.off( '.P' + STATE.id )
396
+ }
397
+
398
+ // Trigger the queued “close” events.
399
+ return P.trigger( 'close' )
400
+ }, //close
401
+
402
+
403
+ /**
404
+ * Clear the values
405
+ */
406
+ clear: function() {
407
+ return P.set( 'clear' )
408
+ }, //clear
409
+
410
+
411
+ /**
412
+ * Set something
413
+ */
414
+ set: function( thing, value, options ) {
415
+
416
+ var thingItem, thingValue,
417
+ thingIsObject = PickerConstructor._.isObject( thing ),
418
+ thingObject = thingIsObject ? thing : {}
419
+
420
+ if ( thing ) {
421
+
422
+ // If the thing isn’t an object, make it one.
423
+ if ( !thingIsObject ) {
424
+ thingObject[ thing ] = value
425
+ }
426
+
427
+ // Go through the things of items to set.
428
+ for ( thingItem in thingObject ) {
429
+
430
+ // Grab the value of the thing.
431
+ thingValue = thingObject[ thingItem ]
432
+
433
+ // First, if the item exists and there’s a value, set it.
434
+ if ( P.component.item[ thingItem ] ) {
435
+ P.component.set( thingItem, thingValue, options || {} )
436
+ }
437
+
438
+ // Then, check to update the element value and broadcast a change.
439
+ if ( thingItem == 'select' || thingItem == 'clear' ) {
440
+ $ELEMENT.val( thingItem == 'clear' ? '' :
441
+ PickerConstructor._.trigger( P.component.formats.toString, P.component, [ SETTINGS.format, P.component.get( thingItem ) ] )
442
+ ).trigger( 'change' )
443
+ }
444
+ }
445
+
446
+ // Render a new picker.
447
+ P.render()
448
+ }
449
+
450
+ // Trigger queued “set” events and pass the `thingObject`.
451
+ return P.trigger( 'set', thingObject )
452
+ }, //set
453
+
454
+
455
+ /**
456
+ * Get something
457
+ */
458
+ get: function( thing, format ) {
459
+
460
+ // Make sure there’s something to get.
461
+ thing = thing || 'value'
462
+
463
+ // If a picker state exists, return that.
464
+ if ( STATE[ thing ] != null ) {
465
+ return STATE[ thing ]
466
+ }
467
+
468
+ // Return the value, if that.
469
+ if ( thing == 'value' ) {
470
+ return ELEMENT.value
471
+ }
472
+
473
+ // Check if a component item exists, return that.
474
+ if ( P.component.item[ thing ] ) {
475
+ if ( typeof format == 'string' ) {
476
+ return PickerConstructor._.trigger( P.component.formats.toString, P.component, [ format, P.component.get( thing ) ] )
477
+ }
478
+ return P.component.get( thing )
479
+ }
480
+ }, //get
481
+
482
+
483
+
484
+ /**
485
+ * Bind events on the things.
486
+ */
487
+ on: function( thing, method ) {
488
+
489
+ var thingName, thingMethod,
490
+ thingIsObject = PickerConstructor._.isObject( thing ),
491
+ thingObject = thingIsObject ? thing : {}
492
+
493
+ if ( thing ) {
494
+
495
+ // If the thing isn’t an object, make it one.
496
+ if ( !thingIsObject ) {
497
+ thingObject[ thing ] = method
498
+ }
499
+
500
+ // Go through the things to bind to.
501
+ for ( thingName in thingObject ) {
502
+
503
+ // Grab the method of the thing.
504
+ thingMethod = thingObject[ thingName ]
505
+
506
+ // Make sure the thing methods collection exists.
507
+ STATE.methods[ thingName ] = STATE.methods[ thingName ] || []
508
+
509
+ // Add the method to the relative method collection.
510
+ STATE.methods[ thingName ].push( thingMethod )
511
+ }
512
+ }
513
+
514
+ return P
515
+ }, //on
516
+
517
+
518
+ /**
519
+ * Fire off method events.
520
+ */
521
+ trigger: function( name, data ) {
522
+ var methodList = STATE.methods[ name ]
523
+ if ( methodList ) {
524
+ methodList.map( function( method ) {
525
+ PickerConstructor._.trigger( method, P, [ data ] )
526
+ })
527
+ }
528
+ return P
529
+ } //trigger
530
+ } //PickerInstance.prototype
531
+
532
+
533
+ /**
534
+ * Wrap the picker holder components together.
535
+ */
536
+ function createWrappedComponent() {
537
+
538
+ // Create a picker wrapper holder
539
+ return PickerConstructor._.node( 'div',
540
+
541
+ // Create a picker wrapper node
542
+ PickerConstructor._.node( 'div',
543
+
544
+ // Create a picker frame
545
+ PickerConstructor._.node( 'div',
546
+
547
+ // Create a picker box node
548
+ PickerConstructor._.node( 'div',
549
+
550
+ // Create the components nodes.
551
+ P.component.nodes( STATE.open ),
552
+
553
+ // The picker box class
554
+ CLASSES.box
555
+ ),
556
+
557
+ // Picker wrap class
558
+ CLASSES.wrap
559
+ ),
560
+
561
+ // Picker frame class
562
+ CLASSES.frame
563
+ ),
564
+
565
+ // Picker holder class
566
+ CLASSES.holder
567
+ ) //endreturn
568
+ } //createWrappedComponent
569
+
570
+
571
+ // Separated for IE
572
+ function focusToOpen( event ) {
573
+
574
+ // Stop the event from propagating to the doc.
575
+ event.stopPropagation()
576
+
577
+ // If it’s a focus event, add the “focused” class to the root.
578
+ if ( event.type == 'focus' ) P.$root.addClass( CLASSES.focused )
579
+
580
+ // And then finally open the picker.
581
+ P.open()
582
+ }
583
+
584
+
585
+ // Return a new picker instance.
586
+ return new PickerInstance()
587
+ } //PickerConstructor
588
+
589
+
590
+
591
+ /**
592
+ * The default classes and prefix to use for the HTML classes.
593
+ */
594
+ PickerConstructor.klasses = function( prefix ) {
595
+ prefix = prefix || 'picker'
596
+ return {
597
+
598
+ picker: prefix,
599
+ opened: prefix + '--opened',
600
+ focused: prefix + '--focused',
601
+
602
+ input: prefix + '__input',
603
+ active: prefix + '__input--active',
604
+
605
+ holder: prefix + '__holder',
606
+
607
+ frame: prefix + '__frame',
608
+ wrap: prefix + '__wrap',
609
+
610
+ box: prefix + '__box'
611
+ }
612
+ } //PickerConstructor.klasses
613
+
614
+
615
+
616
+ /**
617
+ * PickerConstructor helper methods.
618
+ */
619
+ PickerConstructor._ = {
620
+
621
+ /**
622
+ * Create a group of nodes. Expects:
623
+ * `
624
+ {
625
+ min: {Integer},
626
+ max: {Integer},
627
+ i: {Integer},
628
+ node: {String},
629
+ item: {Function}
630
+ }
631
+ * `
632
+ */
633
+ group: function( groupObject ) {
634
+
635
+ var
636
+ // Scope for the looped object
637
+ loopObjectScope,
638
+
639
+ // Create the nodes list
640
+ nodesList = '',
641
+
642
+ // The counter starts from the `min`
643
+ counter = PickerConstructor._.trigger( groupObject.min, groupObject )
644
+
645
+
646
+ // Loop from the `min` to `max`, incrementing by `i`
647
+ for ( ; counter <= PickerConstructor._.trigger( groupObject.max, groupObject, [ counter ] ); counter += groupObject.i ) {
648
+
649
+ // Trigger the `item` function within scope of the object
650
+ loopObjectScope = PickerConstructor._.trigger( groupObject.item, groupObject, [ counter ] )
651
+
652
+ // Splice the subgroup and create nodes out of the sub nodes
653
+ nodesList += PickerConstructor._.node(
654
+ groupObject.node,
655
+ loopObjectScope[ 0 ], // the node
656
+ loopObjectScope[ 1 ], // the classes
657
+ loopObjectScope[ 2 ] // the attributes
658
+ )
659
+ }
660
+
661
+ // Return the list of nodes
662
+ return nodesList
663
+ }, //group
664
+
665
+
666
+ /**
667
+ * Create a dom node string
668
+ */
669
+ node: function( wrapper, item, klass, attribute ) {
670
+
671
+ // If the item is false-y, just return an empty string
672
+ if ( !item ) return ''
673
+
674
+ // If the item is an array, do a join
675
+ item = Array.isArray( item ) ? item.join( '' ) : item
676
+
677
+ // Check for the class
678
+ klass = klass ? ' class="' + klass + '"' : ''
679
+
680
+ // Check for any attributes
681
+ attribute = attribute ? ' ' + attribute : ''
682
+
683
+ // Return the wrapped item
684
+ return '<' + wrapper + klass + attribute + '>' + item + '</' + wrapper + '>'
685
+ }, //node
686
+
687
+
688
+ /**
689
+ * Lead numbers below 10 with a zero.
690
+ */
691
+ lead: function( number ) {
692
+ return ( number < 10 ? '0': '' ) + number
693
+ },
694
+
695
+
696
+ /**
697
+ * Trigger a function otherwise return the value.
698
+ */
699
+ trigger: function( callback, scope, args ) {
700
+ return typeof callback == 'function' ? callback.apply( scope, args || [] ) : callback
701
+ },
702
+
703
+
704
+ /**
705
+ * If the second character is a digit, length is 2 otherwise 1.
706
+ */
707
+ digits: function( string ) {
708
+ return ( /\d/ ).test( string[ 1 ] ) ? 2 : 1
709
+ },
710
+
711
+
712
+ /**
713
+ * Tell if something is an object.
714
+ */
715
+ isObject: function( value ) {
716
+ return {}.toString.call( value ).indexOf( 'Object' ) > -1
717
+ },
718
+
719
+
720
+ /**
721
+ * Tell if something is a date object.
722
+ */
723
+ isDate: function( value ) {
724
+ return {}.toString.call( value ).indexOf( 'Date' ) > -1
725
+ },
726
+
727
+
728
+ /**
729
+ * Tell if something is an integer.
730
+ */
731
+ isInteger: function( value ) {
732
+ return {}.toString.call( value ).indexOf( 'Number' ) > -1 && value % 1 === 0
733
+ }
734
+ } //PickerConstructor._
735
+
736
+
737
+
738
+ /**
739
+ * Extend the picker with a component and defaults.
740
+ */
741
+ PickerConstructor.extend = function( name, Component ) {
742
+
743
+ // Extend jQuery.
744
+ $.fn[ name ] = function( options, action ) {
745
+
746
+ // Grab the component data.
747
+ var componentData = this.data( name )
748
+
749
+ // If the picker is requested, return the data object.
750
+ if ( options == 'picker' ) {
751
+ return componentData
752
+ }
753
+
754
+ // If the component data exists and `options` is a string, carry out the action.
755
+ if ( componentData && typeof options == 'string' ) {
756
+ PickerConstructor._.trigger( componentData[ options ], componentData, [ action ] )
757
+ return this
758
+ }
759
+
760
+ // Otherwise go through each matched element and if the component
761
+ // doesn’t exist, create a new picker using `this` element
762
+ // and merging the defaults and options with a deep copy.
763
+ return this.each( function() {
764
+ var $this = $( this )
765
+ if ( !$this.data( name ) ) {
766
+ new PickerConstructor( this, name, Component, options )
767
+ }
768
+ })
769
+ }
770
+
771
+ // Set the defaults.
772
+ $.fn[ name ].defaults = Component.defaults
773
+ } //PickerConstructor.extend
774
+
775
+
776
+
777
+ // Return the picker constructor.
778
+ return PickerConstructor
779
+
780
+
781
+ // Close the global scope.
782
+ })( jQuery, jQuery( document ) );
783
+
784
+
785
+