squab 1.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/LICENSE.md +13 -0
  2. data/README.md +4 -0
  3. data/bin/squab +4 -0
  4. data/defaults.yaml +5 -0
  5. data/lib/squab.rb +2 -0
  6. data/lib/squab/db.rb +37 -0
  7. data/lib/squab/events.rb +301 -0
  8. data/lib/squab/web.rb +231 -0
  9. data/public/api.html +66 -0
  10. data/public/css/anytime.css +777 -0
  11. data/public/css/bootstrap-responsive.css +1058 -0
  12. data/public/css/bootstrap-responsive.min.css +9 -0
  13. data/public/css/bootstrap.css +5774 -0
  14. data/public/css/bootstrap.min.css +9 -0
  15. data/public/css/docs.css +1001 -0
  16. data/public/css/normalize.css +406 -0
  17. data/public/css/pickadate/default.css +240 -0
  18. data/public/css/pickadate/default.date.css +332 -0
  19. data/public/css/prettify.css +30 -0
  20. data/public/css/squab.css +307 -0
  21. data/public/events.html +85 -0
  22. data/public/img/glyphicons-halflings-white.png +0 -0
  23. data/public/img/glyphicons-halflings.png +0 -0
  24. data/public/js/collection/events.js +74 -0
  25. data/public/js/lib/backbone-min.js +4 -0
  26. data/public/js/lib/datejs/core.js +48 -0
  27. data/public/js/lib/datejs/date-en-US.js +145 -0
  28. data/public/js/lib/jquery-latest.js +9440 -0
  29. data/public/js/lib/lodash.min.js +48 -0
  30. data/public/js/lib/pickadate/legacy.js +140 -0
  31. data/public/js/lib/pickadate/picker.date.js +957 -0
  32. data/public/js/lib/pickadate/picker.js +791 -0
  33. data/public/js/lib/typeahead.min.js +7 -0
  34. data/public/js/model/event.js +38 -0
  35. data/public/js/router.js +38 -0
  36. data/public/js/squab.js +6 -0
  37. data/public/js/view/day_view.js +22 -0
  38. data/public/js/view/event_view.js +14 -0
  39. data/public/js/view/events_view.js +46 -0
  40. data/public/js/view/search_view.js +130 -0
  41. metadata +220 -0
@@ -0,0 +1,791 @@
1
+
2
+ /*!
3
+ * pickadate.js v3.2.0, 2013/08/15
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 hidden input after the element.
198
+ after( P._hidden ).
199
+
200
+ // Store the picker data by component name.
201
+ data( NAME, P )
202
+
203
+
204
+ // Insert the root as specified in the settings.
205
+ if ( SETTINGS.container ) $( SETTINGS.container ).append( P.$root )
206
+ else $ELEMENT.after( P.$root )
207
+
208
+
209
+ // Bind the default component and settings events.
210
+ P.on({
211
+ start: P.component.onStart,
212
+ render: P.component.onRender,
213
+ stop: P.component.onStop,
214
+ open: P.component.onOpen,
215
+ close: P.component.onClose,
216
+ set: P.component.onSet
217
+ }).on({
218
+ start: SETTINGS.onStart,
219
+ render: SETTINGS.onRender,
220
+ stop: SETTINGS.onStop,
221
+ open: SETTINGS.onOpen,
222
+ close: SETTINGS.onClose,
223
+ set: SETTINGS.onSet
224
+ })
225
+
226
+
227
+ // If the element has autofocus, open the picker.
228
+ if ( ELEMENT.autofocus ) {
229
+ P.open()
230
+ }
231
+
232
+
233
+ // Trigger queued the “start” and “render” events.
234
+ return P.trigger( 'start' ).trigger( 'render' )
235
+ }, //start
236
+
237
+
238
+ /**
239
+ * Render a new picker
240
+ */
241
+ render: function( entireComponent ) {
242
+
243
+ // Insert a new component holder in the root or box.
244
+ if ( entireComponent ) P.$root.html( createWrappedComponent() )
245
+ else P.$root.find( '.' + CLASSES.box ).html( P.component.nodes( STATE.open ) )
246
+
247
+ // Trigger the queued “render” events.
248
+ return P.trigger( 'render' )
249
+ }, //render
250
+
251
+
252
+ /**
253
+ * Destroy everything
254
+ */
255
+ stop: function() {
256
+
257
+ // If it’s already stopped, do nothing.
258
+ if ( !STATE.start ) return P
259
+
260
+ // Then close the picker.
261
+ P.close()
262
+
263
+ // Remove the hidden field.
264
+ if ( P._hidden ) {
265
+ P._hidden.parentNode.removeChild( P._hidden )
266
+ }
267
+
268
+ // Remove the root.
269
+ P.$root.remove()
270
+
271
+ // Remove the input class, unbind the events, and remove the stored data.
272
+ $ELEMENT.removeClass( CLASSES.input ).off( '.P' + STATE.id ).removeData( NAME )
273
+
274
+ // Restore the element state
275
+ ELEMENT.type = STATE.type
276
+ ELEMENT.readOnly = false
277
+
278
+ // Trigger the queued “stop” events.
279
+ P.trigger( 'stop' )
280
+
281
+ // Reset the picker states.
282
+ STATE.methods = {}
283
+ STATE.start = false
284
+
285
+ return P
286
+ }, //stop
287
+
288
+
289
+ /*
290
+ * Open up the picker
291
+ */
292
+ open: function( dontGiveFocus ) {
293
+
294
+ // If it’s already open, do nothing.
295
+ if ( STATE.open ) return P
296
+
297
+ // Add the “active” class.
298
+ $ELEMENT.addClass( CLASSES.active )
299
+
300
+ // Add the “opened” class to the picker root.
301
+ P.$root.addClass( CLASSES.opened )
302
+
303
+ // If we have to give focus, bind the element and doc events.
304
+ if ( dontGiveFocus !== false ) {
305
+
306
+ // Set it as open.
307
+ STATE.open = true
308
+
309
+ // Pass focus to the element’s jQuery object.
310
+ $ELEMENT.focus()
311
+
312
+ // Bind the document events.
313
+ $document.on( 'click.P' + STATE.id + ' focusin.P' + STATE.id, function( event ) {
314
+
315
+ // If the target of the event is not the element, close the picker picker.
316
+ // * Don’t worry about clicks or focusins on the root because those don’t bubble up.
317
+ // Also, for Firefox, a click on an `option` element bubbles up directly
318
+ // to the doc. So make sure the target wasn't the doc.
319
+ if ( event.target != ELEMENT && event.target != document ) P.close()
320
+
321
+ }).on( 'keydown.P' + STATE.id, function( event ) {
322
+
323
+ var
324
+ // Get the keycode.
325
+ keycode = event.keyCode,
326
+
327
+ // Translate that to a selection change.
328
+ keycodeToMove = P.component.key[ keycode ],
329
+
330
+ // Grab the target.
331
+ target = event.target
332
+
333
+
334
+ // On escape, close the picker and give focus.
335
+ if ( keycode == 27 ) {
336
+ P.close( true )
337
+ }
338
+
339
+
340
+ // Check if there is a key movement or “enter” keypress on the element.
341
+ else if ( target == ELEMENT && ( keycodeToMove || keycode == 13 ) ) {
342
+
343
+ // Prevent the default action to stop page movement.
344
+ event.preventDefault()
345
+
346
+ // Trigger the key movement action.
347
+ if ( keycodeToMove ) {
348
+ PickerConstructor._.trigger( P.component.key.go, P, [ keycodeToMove ] )
349
+ }
350
+
351
+ // On “enter”, if the highlighted item isn’t disabled, set the value and close.
352
+ else if ( !P.$root.find( '.' + CLASSES.highlighted ).hasClass( CLASSES.disabled ) ) {
353
+ P.set( 'select', P.component.item.highlight ).close()
354
+ }
355
+ }
356
+
357
+
358
+ // If the target is within the root and “enter” is pressed,
359
+ // prevent the default action and trigger a click on the target instead.
360
+ else if ( P.$root.find( target ).length && keycode == 13 ) {
361
+ event.preventDefault()
362
+ target.click()
363
+ }
364
+ })
365
+ }
366
+
367
+ // Trigger the queued “open” events.
368
+ return P.trigger( 'open' )
369
+ }, //open
370
+
371
+
372
+ /**
373
+ * Close the picker
374
+ */
375
+ close: function( giveFocus ) {
376
+
377
+ // If we need to give focus, do it before changing states.
378
+ if ( giveFocus ) {
379
+ // ....ah yes! It would’ve been incomplete without a crazy workaround for IE :|
380
+ // The focus is triggered *after* the close has completed - causing it
381
+ // to open again. So unbind and rebind the event at the next tick.
382
+ $ELEMENT.off( 'focus.P' + STATE.id ).focus()
383
+ setTimeout( function() {
384
+ $ELEMENT.on( 'focus.P' + STATE.id, focusToOpen )
385
+ }, 0 )
386
+ }
387
+
388
+ // Remove the “active” class.
389
+ $ELEMENT.removeClass( CLASSES.active )
390
+
391
+ // Remove the “opened” and “focused” class from the picker root.
392
+ P.$root.removeClass( CLASSES.opened + ' ' + CLASSES.focused )
393
+
394
+ // If it’s open, update the state.
395
+ if ( STATE.open ) {
396
+
397
+ // Set it as closed.
398
+ STATE.open = false
399
+
400
+ // Unbind the document events.
401
+ $document.off( '.P' + STATE.id )
402
+ }
403
+
404
+ // Trigger the queued “close” events.
405
+ return P.trigger( 'close' )
406
+ }, //close
407
+
408
+
409
+ /**
410
+ * Clear the values
411
+ */
412
+ clear: function() {
413
+ return P.set( 'clear' )
414
+ }, //clear
415
+
416
+
417
+ /**
418
+ * Set something
419
+ */
420
+ set: function( thing, value, options ) {
421
+
422
+ var thingItem, thingValue,
423
+ thingIsObject = PickerConstructor._.isObject( thing ),
424
+ thingObject = thingIsObject ? thing : {}
425
+
426
+ if ( thing ) {
427
+
428
+ // If the thing isn’t an object, make it one.
429
+ if ( !thingIsObject ) {
430
+ thingObject[ thing ] = value
431
+ }
432
+
433
+ // Go through the things of items to set.
434
+ for ( thingItem in thingObject ) {
435
+
436
+ // Grab the value of the thing.
437
+ thingValue = thingObject[ thingItem ]
438
+
439
+ // First, if the item exists and there’s a value, set it.
440
+ if ( P.component.item[ thingItem ] ) {
441
+ P.component.set( thingItem, thingValue, options || {} )
442
+ }
443
+
444
+ // Then, check to update the element value and broadcast a change.
445
+ if ( thingItem == 'select' || thingItem == 'clear' ) {
446
+ $ELEMENT.val( thingItem == 'clear' ? '' :
447
+ PickerConstructor._.trigger( P.component.formats.toString, P.component, [ SETTINGS.format, P.component.get( thingItem ) ] )
448
+ ).trigger( 'change' )
449
+ }
450
+ }
451
+
452
+ // Render a new picker.
453
+ P.render()
454
+ }
455
+
456
+ // Trigger queued “set” events and pass the `thingObject`.
457
+ return P.trigger( 'set', thingObject )
458
+ }, //set
459
+
460
+
461
+ /**
462
+ * Get something
463
+ */
464
+ get: function( thing, format ) {
465
+
466
+ // Make sure there’s something to get.
467
+ thing = thing || 'value'
468
+
469
+ // If a picker state exists, return that.
470
+ if ( STATE[ thing ] != null ) {
471
+ return STATE[ thing ]
472
+ }
473
+
474
+ // Return the value, if that.
475
+ if ( thing == 'value' ) {
476
+ return ELEMENT.value
477
+ }
478
+
479
+ // Check if a component item exists, return that.
480
+ if ( P.component.item[ thing ] ) {
481
+ if ( typeof format == 'string' ) {
482
+ return PickerConstructor._.trigger( P.component.formats.toString, P.component, [ format, P.component.get( thing ) ] )
483
+ }
484
+ return P.component.get( thing )
485
+ }
486
+ }, //get
487
+
488
+
489
+
490
+ /**
491
+ * Bind events on the things.
492
+ */
493
+ on: function( thing, method ) {
494
+
495
+ var thingName, thingMethod,
496
+ thingIsObject = PickerConstructor._.isObject( thing ),
497
+ thingObject = thingIsObject ? thing : {}
498
+
499
+ if ( thing ) {
500
+
501
+ // If the thing isn’t an object, make it one.
502
+ if ( !thingIsObject ) {
503
+ thingObject[ thing ] = method
504
+ }
505
+
506
+ // Go through the things to bind to.
507
+ for ( thingName in thingObject ) {
508
+
509
+ // Grab the method of the thing.
510
+ thingMethod = thingObject[ thingName ]
511
+
512
+ // Make sure the thing methods collection exists.
513
+ STATE.methods[ thingName ] = STATE.methods[ thingName ] || []
514
+
515
+ // Add the method to the relative method collection.
516
+ STATE.methods[ thingName ].push( thingMethod )
517
+ }
518
+ }
519
+
520
+ return P
521
+ }, //on
522
+
523
+
524
+ /**
525
+ * Fire off method events.
526
+ */
527
+ trigger: function( name, data ) {
528
+ var methodList = STATE.methods[ name ]
529
+ if ( methodList ) {
530
+ methodList.map( function( method ) {
531
+ PickerConstructor._.trigger( method, P, [ data ] )
532
+ })
533
+ }
534
+ return P
535
+ } //trigger
536
+ } //PickerInstance.prototype
537
+
538
+
539
+ /**
540
+ * Wrap the picker holder components together.
541
+ */
542
+ function createWrappedComponent() {
543
+
544
+ // Create a picker wrapper holder
545
+ return PickerConstructor._.node( 'div',
546
+
547
+ // Create a picker wrapper node
548
+ PickerConstructor._.node( 'div',
549
+
550
+ // Create a picker frame
551
+ PickerConstructor._.node( 'div',
552
+
553
+ // Create a picker box node
554
+ PickerConstructor._.node( 'div',
555
+
556
+ // Create the components nodes.
557
+ P.component.nodes( STATE.open ),
558
+
559
+ // The picker box class
560
+ CLASSES.box
561
+ ),
562
+
563
+ // Picker wrap class
564
+ CLASSES.wrap
565
+ ),
566
+
567
+ // Picker frame class
568
+ CLASSES.frame
569
+ ),
570
+
571
+ // Picker holder class
572
+ CLASSES.holder
573
+ ) //endreturn
574
+ } //createWrappedComponent
575
+
576
+
577
+ // Separated for IE
578
+ function focusToOpen( event ) {
579
+
580
+ // Stop the event from propagating to the doc.
581
+ event.stopPropagation()
582
+
583
+ // If it’s a focus event, add the “focused” class to the root.
584
+ if ( event.type == 'focus' ) P.$root.addClass( CLASSES.focused )
585
+
586
+ // And then finally open the picker.
587
+ P.open()
588
+ }
589
+
590
+
591
+ // Return a new picker instance.
592
+ return new PickerInstance()
593
+ } //PickerConstructor
594
+
595
+
596
+
597
+ /**
598
+ * The default classes and prefix to use for the HTML classes.
599
+ */
600
+ PickerConstructor.klasses = function( prefix ) {
601
+ prefix = prefix || 'picker'
602
+ return {
603
+
604
+ picker: prefix,
605
+ opened: prefix + '--opened',
606
+ focused: prefix + '--focused',
607
+
608
+ input: prefix + '__input',
609
+ active: prefix + '__input--active',
610
+
611
+ holder: prefix + '__holder',
612
+
613
+ frame: prefix + '__frame',
614
+ wrap: prefix + '__wrap',
615
+
616
+ box: prefix + '__box'
617
+ }
618
+ } //PickerConstructor.klasses
619
+
620
+
621
+
622
+ /**
623
+ * PickerConstructor helper methods.
624
+ */
625
+ PickerConstructor._ = {
626
+
627
+ /**
628
+ * Create a group of nodes. Expects:
629
+ * `
630
+ {
631
+ min: {Integer},
632
+ max: {Integer},
633
+ i: {Integer},
634
+ node: {String},
635
+ item: {Function}
636
+ }
637
+ * `
638
+ */
639
+ group: function( groupObject ) {
640
+
641
+ var
642
+ // Scope for the looped object
643
+ loopObjectScope,
644
+
645
+ // Create the nodes list
646
+ nodesList = '',
647
+
648
+ // The counter starts from the `min`
649
+ counter = PickerConstructor._.trigger( groupObject.min, groupObject )
650
+
651
+
652
+ // Loop from the `min` to `max`, incrementing by `i`
653
+ for ( ; counter <= PickerConstructor._.trigger( groupObject.max, groupObject, [ counter ] ); counter += groupObject.i ) {
654
+
655
+ // Trigger the `item` function within scope of the object
656
+ loopObjectScope = PickerConstructor._.trigger( groupObject.item, groupObject, [ counter ] )
657
+
658
+ // Splice the subgroup and create nodes out of the sub nodes
659
+ nodesList += PickerConstructor._.node(
660
+ groupObject.node,
661
+ loopObjectScope[ 0 ], // the node
662
+ loopObjectScope[ 1 ], // the classes
663
+ loopObjectScope[ 2 ] // the attributes
664
+ )
665
+ }
666
+
667
+ // Return the list of nodes
668
+ return nodesList
669
+ }, //group
670
+
671
+
672
+ /**
673
+ * Create a dom node string
674
+ */
675
+ node: function( wrapper, item, klass, attribute ) {
676
+
677
+ // If the item is false-y, just return an empty string
678
+ if ( !item ) return ''
679
+
680
+ // If the item is an array, do a join
681
+ item = Array.isArray( item ) ? item.join( '' ) : item
682
+
683
+ // Check for the class
684
+ klass = klass ? ' class="' + klass + '"' : ''
685
+
686
+ // Check for any attributes
687
+ attribute = attribute ? ' ' + attribute : ''
688
+
689
+ // Return the wrapped item
690
+ return '<' + wrapper + klass + attribute + '>' + item + '</' + wrapper + '>'
691
+ }, //node
692
+
693
+
694
+ /**
695
+ * Lead numbers below 10 with a zero.
696
+ */
697
+ lead: function( number ) {
698
+ return ( number < 10 ? '0': '' ) + number
699
+ },
700
+
701
+
702
+ /**
703
+ * Trigger a function otherwise return the value.
704
+ */
705
+ trigger: function( callback, scope, args ) {
706
+ return typeof callback == 'function' ? callback.apply( scope, args || [] ) : callback
707
+ },
708
+
709
+
710
+ /**
711
+ * If the second character is a digit, length is 2 otherwise 1.
712
+ */
713
+ digits: function( string ) {
714
+ return ( /\d/ ).test( string[ 1 ] ) ? 2 : 1
715
+ },
716
+
717
+
718
+ /**
719
+ * Tell if something is an object.
720
+ */
721
+ isObject: function( value ) {
722
+ return {}.toString.call( value ).indexOf( 'Object' ) > -1
723
+ },
724
+
725
+
726
+ /**
727
+ * Tell if something is a date object.
728
+ */
729
+ isDate: function( value ) {
730
+ return {}.toString.call( value ).indexOf( 'Date' ) > -1 && this.isInteger( value.getDate() )
731
+ },
732
+
733
+
734
+ /**
735
+ * Tell if something is an integer.
736
+ */
737
+ isInteger: function( value ) {
738
+ return {}.toString.call( value ).indexOf( 'Number' ) > -1 && value % 1 === 0
739
+ }
740
+ } //PickerConstructor._
741
+
742
+
743
+
744
+ /**
745
+ * Extend the picker with a component and defaults.
746
+ */
747
+ PickerConstructor.extend = function( name, Component ) {
748
+
749
+ // Extend jQuery.
750
+ $.fn[ name ] = function( options, action ) {
751
+
752
+ // Grab the component data.
753
+ var componentData = this.data( name )
754
+
755
+ // If the picker is requested, return the data object.
756
+ if ( options == 'picker' ) {
757
+ return componentData
758
+ }
759
+
760
+ // If the component data exists and `options` is a string, carry out the action.
761
+ if ( componentData && typeof options == 'string' ) {
762
+ PickerConstructor._.trigger( componentData[ options ], componentData, [ action ] )
763
+ return this
764
+ }
765
+
766
+ // Otherwise go through each matched element and if the component
767
+ // doesn’t exist, create a new picker using `this` element
768
+ // and merging the defaults and options with a deep copy.
769
+ return this.each( function() {
770
+ var $this = $( this )
771
+ if ( !$this.data( name ) ) {
772
+ new PickerConstructor( this, name, Component, options )
773
+ }
774
+ })
775
+ }
776
+
777
+ // Set the defaults.
778
+ $.fn[ name ].defaults = Component.defaults
779
+ } //PickerConstructor.extend
780
+
781
+
782
+
783
+ // Return the picker constructor.
784
+ return PickerConstructor
785
+
786
+
787
+ // Close the global scope.
788
+ })( jQuery, jQuery( document ) );
789
+
790
+
791
+