pickadate-rails 1.0.0
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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +61 -0
- data/Rakefile +26 -0
- data/lib/pickadate-rails.rb +7 -0
- data/lib/pickadate-rails/version.rb +3 -0
- data/pickadate-rails.gemspec +25 -0
- data/vendor/assets/javascripts/pickadate/picker.date.js +925 -0
- data/vendor/assets/javascripts/pickadate/picker.js +785 -0
- data/vendor/assets/javascripts/pickadate/picker.time.js +651 -0
- data/vendor/assets/javascripts/pickadate/translations/bg_BG.js +13 -0
- data/vendor/assets/javascripts/pickadate/translations/bs_BA.js +13 -0
- data/vendor/assets/javascripts/pickadate/translations/ca_ES.js +13 -0
- data/vendor/assets/javascripts/pickadate/translations/cs_CZ.js +13 -0
- data/vendor/assets/javascripts/pickadate/translations/da_DK.js +13 -0
- data/vendor/assets/javascripts/pickadate/translations/de_DE.js +13 -0
- data/vendor/assets/javascripts/pickadate/translations/el_GR.js +13 -0
- data/vendor/assets/javascripts/pickadate/translations/es_ES.js +13 -0
- data/vendor/assets/javascripts/pickadate/translations/et_EE.js +13 -0
- data/vendor/assets/javascripts/pickadate/translations/eu_ES.js +13 -0
- data/vendor/assets/javascripts/pickadate/translations/fi_FI.js +13 -0
- data/vendor/assets/javascripts/pickadate/translations/fr_FR.js +13 -0
- data/vendor/assets/javascripts/pickadate/translations/he_IL.js +12 -0
- data/vendor/assets/javascripts/pickadate/translations/hr_HR.js +13 -0
- data/vendor/assets/javascripts/pickadate/translations/hu_HU.js +13 -0
- data/vendor/assets/javascripts/pickadate/translations/id_ID.js +13 -0
- data/vendor/assets/javascripts/pickadate/translations/it_IT.js +13 -0
- data/vendor/assets/javascripts/pickadate/translations/nl_NL.js +13 -0
- data/vendor/assets/javascripts/pickadate/translations/no_NO.js +13 -0
- data/vendor/assets/javascripts/pickadate/translations/pl_PL.js +13 -0
- data/vendor/assets/javascripts/pickadate/translations/pt_BR.js +12 -0
- data/vendor/assets/javascripts/pickadate/translations/pt_PT.js +12 -0
- data/vendor/assets/javascripts/pickadate/translations/ro_RO.js +13 -0
- data/vendor/assets/javascripts/pickadate/translations/ru_RU.js +13 -0
- data/vendor/assets/javascripts/pickadate/translations/sk_SK.js +13 -0
- data/vendor/assets/javascripts/pickadate/translations/sv_SE.js +13 -0
- data/vendor/assets/javascripts/pickadate/translations/th_TH.js +12 -0
- data/vendor/assets/javascripts/pickadate/translations/tr_TR.js +13 -0
- data/vendor/assets/javascripts/pickadate/translations/uk_UA.js +13 -0
- data/vendor/assets/javascripts/pickadate/translations/zh_CN.js +13 -0
- data/vendor/assets/stylesheets/pickadate/classic.css +159 -0
- data/vendor/assets/stylesheets/pickadate/classic.date.css +332 -0
- data/vendor/assets/stylesheets/pickadate/classic.time.css +198 -0
- data/vendor/assets/stylesheets/pickadate/default.css +234 -0
- data/vendor/assets/stylesheets/pickadate/default.date.css +332 -0
- data/vendor/assets/stylesheets/pickadate/default.time.css +193 -0
- 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
|
+
|