MyCo/inc/lib/pickadate/picker.time.js

1014 lines
31 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*!
* Time picker for pickadate.js v3.5.6
* http://amsul.github.io/pickadate.js/time.htm
*/
(function ( factory ) {
// AMD.
if ( typeof define == 'function' && define.amd )
define( ['picker', 'jquery'], factory )
// Node.js/browserify.
else if ( typeof exports == 'object' )
module.exports = factory( require('./picker.js'), require('jquery') )
// Browser globals.
else factory( Picker, jQuery )
}(function( Picker, $ ) {
/**
* Globals and constants
*/
var HOURS_IN_DAY = 24,
MINUTES_IN_HOUR = 60,
HOURS_TO_NOON = 12,
MINUTES_IN_DAY = HOURS_IN_DAY * MINUTES_IN_HOUR,
_ = Picker._
/**
* The time picker constructor
*/
function TimePicker( picker, settings ) {
var clock = this,
elementValue = picker.$node[ 0 ].value,
elementDataValue = picker.$node.data( 'value' ),
valueString = elementDataValue || elementValue,
formatString = elementDataValue ? settings.formatSubmit : settings.format
clock.settings = settings
clock.$node = picker.$node
// The queue of methods that will be used to build item objects.
clock.queue = {
interval: 'i',
min: 'measure create',
max: 'measure create',
now: 'now create',
select: 'parse create validate',
highlight: 'parse create validate',
view: 'parse create validate',
disable: 'deactivate',
enable: 'activate'
}
// The component's item object.
clock.item = {}
clock.item.clear = null
clock.item.interval = settings.interval || 30
clock.item.disable = ( settings.disable || [] ).slice( 0 )
clock.item.enable = -(function( collectionDisabled ) {
return collectionDisabled[ 0 ] === true ? collectionDisabled.shift() : -1
})( clock.item.disable )
clock.
set( 'min', settings.min ).
set( 'max', settings.max ).
set( 'now' )
// When theres a value, set the `select`, which in turn
// also sets the `highlight` and `view`.
if ( valueString ) {
clock.set( 'select', valueString, {
format: formatString
})
}
// If theres no value, default to highlighting “today”.
else {
clock.
set( 'select', null ).
set( 'highlight', clock.item.now )
}
// The keycode to movement mapping.
clock.key = {
40: 1, // Down
38: -1, // Up
39: 1, // Right
37: -1, // Left
go: function( timeChange ) {
clock.set(
'highlight',
clock.item.highlight.pick + timeChange * clock.item.interval,
{ interval: timeChange * clock.item.interval }
)
this.render()
}
}
// Bind some picker events.
picker.
on( 'render', function() {
var $pickerHolder = picker.$root.children(),
$viewset = $pickerHolder.find( '.' + settings.klass.viewset ),
vendors = function( prop ) {
return ['webkit', 'moz', 'ms', 'o', ''].map(function( vendor ) {
return ( vendor ? '-' + vendor + '-' : '' ) + prop
})
},
animations = function( $el, state ) {
vendors( 'transform' ).map(function( prop ) {
$el.css( prop, state )
})
vendors( 'transition' ).map(function( prop ) {
$el.css( prop, state )
})
}
if ( $viewset.length ) {
animations( $pickerHolder, 'none' )
$pickerHolder[ 0 ].scrollTop = ~~$viewset.position().top - ( $viewset[ 0 ].clientHeight * 2 )
animations( $pickerHolder, '' )
}
}, 1 ).
on( 'open', function() {
picker.$root.find( 'button' ).attr( 'disabled', false )
}, 1 ).
on( 'close', function() {
picker.$root.find( 'button' ).attr( 'disabled', true )
}, 1 )
} //TimePicker
/**
* Set a timepicker item object.
*/
TimePicker.prototype.set = function( type, value, options ) {
var clock = this,
clockItem = clock.item
// If the value is `null` just set it immediately.
if ( value === null ) {
if ( type == 'clear' ) type = 'select'
clockItem[ type ] = value
return clock
}
// Otherwise go through the queue of methods, and invoke the functions.
// Update this as the time unit, and set the final value as this item.
// * In the case of `enable`, keep the queue but set `disable` instead.
// And in the case of `flip`, keep the queue but set `enable` instead.
clockItem[ ( type == 'enable' ? 'disable' : type == 'flip' ? 'enable' : type ) ] = clock.queue[ type ].split( ' ' ).map( function( method ) {
value = clock[ method ]( type, value, options )
return value
}).pop()
// Check if we need to cascade through more updates.
if ( type == 'select' ) {
clock.set( 'highlight', clockItem.select, options )
}
else if ( type == 'highlight' ) {
clock.set( 'view', clockItem.highlight, options )
}
else if ( type == 'interval' ) {
clock.
set( 'min', clockItem.min, options ).
set( 'max', clockItem.max, options )
}
else if ( type.match( /^(flip|min|max|disable|enable)$/ ) ) {
if ( clockItem.select && clock.disabled( clockItem.select ) ) {
clock.set( 'select', value, options )
}
if ( clockItem.highlight && clock.disabled( clockItem.highlight ) ) {
clock.set( 'highlight', value, options )
}
if ( type == 'min' ) {
clock.set( 'max', clockItem.max, options )
}
}
return clock
} //TimePicker.prototype.set
/**
* Get a timepicker item object.
*/
TimePicker.prototype.get = function( type ) {
return this.item[ type ]
} //TimePicker.prototype.get
/**
* Create a picker time object.
*/
TimePicker.prototype.create = function( type, value, options ) {
var clock = this
// If theres no value, use the type as the value.
value = value === undefined ? type : value
// If its a date object, convert it into an array.
if ( _.isDate( value ) ) {
value = [ value.getHours(), value.getMinutes() ]
}
// If its an object, use the “pick” value.
if ( $.isPlainObject( value ) && _.isInteger( value.pick ) ) {
value = value.pick
}
// If its an array, convert it into minutes.
else if ( $.isArray( value ) ) {
value = +value[ 0 ] * MINUTES_IN_HOUR + (+value[ 1 ])
}
// If no valid value is passed, set it to “now”.
else if ( !_.isInteger( value ) ) {
value = clock.now( type, value, options )
}
// If were setting the max, make sure its greater than the min.
if ( type == 'max' && value < clock.item.min.pick ) {
value += MINUTES_IN_DAY
}
// If the value doesnt fall directly on the interval,
// add one interval to indicate it as “passed”.
if ( type != 'min' && type != 'max' && (value - clock.item.min.pick) % clock.item.interval !== 0 ) {
value += clock.item.interval
}
// Normalize it into a “reachable” interval.
value = clock.normalize( type, value, options )
// Return the compiled object.
return {
// Divide to get hours from minutes.
hour: ~~( HOURS_IN_DAY + value / MINUTES_IN_HOUR ) % HOURS_IN_DAY,
// The remainder is the minutes.
mins: ( MINUTES_IN_HOUR + value % MINUTES_IN_HOUR ) % MINUTES_IN_HOUR,
// The time in total minutes.
time: ( MINUTES_IN_DAY + value ) % MINUTES_IN_DAY,
// Reference to the “relative” value to pick.
pick: value % MINUTES_IN_DAY
}
} //TimePicker.prototype.create
/**
* Create a range limit object using an array, date object,
* literal “true”, or integer relative to another time.
*/
TimePicker.prototype.createRange = function( from, to ) {
var clock = this,
createTime = function( time ) {
if ( time === true || $.isArray( time ) || _.isDate( time ) ) {
return clock.create( time )
}
return time
}
// Create objects if possible.
if ( !_.isInteger( from ) ) {
from = createTime( from )
}
if ( !_.isInteger( to ) ) {
to = createTime( to )
}
// Create relative times.
if ( _.isInteger( from ) && $.isPlainObject( to ) ) {
from = [ to.hour, to.mins + ( from * clock.settings.interval ) ];
}
else if ( _.isInteger( to ) && $.isPlainObject( from ) ) {
to = [ from.hour, from.mins + ( to * clock.settings.interval ) ];
}
return {
from: createTime( from ),
to: createTime( to )
}
} //TimePicker.prototype.createRange
/**
* Check if a time unit falls within a time range object.
*/
TimePicker.prototype.withinRange = function( range, timeUnit ) {
range = this.createRange(range.from, range.to)
return timeUnit.pick >= range.from.pick && timeUnit.pick <= range.to.pick
}
/**
* Check if two time range objects overlap.
*/
TimePicker.prototype.overlapRanges = function( one, two ) {
var clock = this
// Convert the ranges into comparable times.
one = clock.createRange( one.from, one.to )
two = clock.createRange( two.from, two.to )
return clock.withinRange( one, two.from ) || clock.withinRange( one, two.to ) ||
clock.withinRange( two, one.from ) || clock.withinRange( two, one.to )
}
/**
* Get the time relative to now.
*/
TimePicker.prototype.now = function( type, value/*, options*/ ) {
var interval = this.item.interval,
date = new Date(),
nowMinutes = date.getHours() * MINUTES_IN_HOUR + date.getMinutes(),
isValueInteger = _.isInteger( value ),
isBelowInterval
// Make sure “now” falls within the interval range.
nowMinutes -= nowMinutes % interval
// Check if the difference is less than the interval itself.
isBelowInterval = value < 0 && interval * value + nowMinutes <= -interval
// Add an interval because the time has “passed”.
nowMinutes += type == 'min' && isBelowInterval ? 0 : interval
// If the value is a number, adjust by that many intervals.
if ( isValueInteger ) {
nowMinutes += interval * (
isBelowInterval && type != 'max' ?
value + 1 :
value
)
}
// Return the final calculation.
return nowMinutes
} //TimePicker.prototype.now
/**
* Normalize minutes to be “reachable” based on the min and interval.
*/
TimePicker.prototype.normalize = function( type, value/*, options*/ ) {
var interval = this.item.interval,
minTime = this.item.min && this.item.min.pick || 0
// If setting min time, dont shift anything.
// Otherwise get the value and min difference and then
// normalize the difference with the interval.
value -= type == 'min' ? 0 : ( value - minTime ) % interval
// Return the adjusted value.
return value
} //TimePicker.prototype.normalize
/**
* Measure the range of minutes.
*/
TimePicker.prototype.measure = function( type, value, options ) {
var clock = this
// If its anything false-y, set it to the default.
if ( !value ) {
value = type == 'min' ? [ 0, 0 ] : [ HOURS_IN_DAY - 1, MINUTES_IN_HOUR - 1 ]
}
// If its a string, parse it.
if ( typeof value == 'string' ) {
value = clock.parse( type, value )
}
// If its a literal true, or an integer, make it relative to now.
else if ( value === true || _.isInteger( value ) ) {
value = clock.now( type, value, options )
}
// If its an object already, just normalize it.
else if ( $.isPlainObject( value ) && _.isInteger( value.pick ) ) {
value = clock.normalize( type, value.pick, options )
}
return value
} ///TimePicker.prototype.measure
/**
* Validate an object as enabled.
*/
TimePicker.prototype.validate = function( type, timeObject, options ) {
var clock = this,
interval = options && options.interval ? options.interval : clock.item.interval
// Check if the object is disabled.
if ( clock.disabled( timeObject ) ) {
// Shift with the interval until we reach an enabled time.
timeObject = clock.shift( timeObject, interval )
}
// Scope the object into range.
timeObject = clock.scope( timeObject )
// Do a second check to see if we landed on a disabled min/max.
// In that case, shift using the opposite interval as before.
if ( clock.disabled( timeObject ) ) {
timeObject = clock.shift( timeObject, interval * -1 )
}
// Return the final object.
return timeObject
} //TimePicker.prototype.validate
/**
* Check if an object is disabled.
*/
TimePicker.prototype.disabled = function( timeToVerify ) {
var clock = this,
// Filter through the disabled times to check if this is one.
isDisabledMatch = clock.item.disable.filter( function( timeToDisable ) {
// If the time is a number, match the hours.
if ( _.isInteger( timeToDisable ) ) {
return timeToVerify.hour == timeToDisable
}
// If its an array, create the object and match the times.
if ( $.isArray( timeToDisable ) || _.isDate( timeToDisable ) ) {
return timeToVerify.pick == clock.create( timeToDisable ).pick
}
// If its an object, match a time within the “from” and “to” range.
if ( $.isPlainObject( timeToDisable ) ) {
return clock.withinRange( timeToDisable, timeToVerify )
}
})
// If this time matches a disabled time, confirm its not inverted.
isDisabledMatch = isDisabledMatch.length && !isDisabledMatch.filter(function( timeToDisable ) {
return $.isArray( timeToDisable ) && timeToDisable[2] == 'inverted' ||
$.isPlainObject( timeToDisable ) && timeToDisable.inverted
}).length
// If the clock is "enabled" flag is flipped, flip the condition.
return clock.item.enable === -1 ? !isDisabledMatch : isDisabledMatch ||
timeToVerify.pick < clock.item.min.pick ||
timeToVerify.pick > clock.item.max.pick
} //TimePicker.prototype.disabled
/**
* Shift an object by an interval until we reach an enabled object.
*/
TimePicker.prototype.shift = function( timeObject, interval ) {
var clock = this,
minLimit = clock.item.min.pick,
maxLimit = clock.item.max.pick/*,
safety = 1000*/
interval = interval || clock.item.interval
// Keep looping as long as the time is disabled.
while ( /*safety &&*/ clock.disabled( timeObject ) ) {
/*safety -= 1
if ( !safety ) {
throw 'Fell into an infinite loop while shifting to ' + timeObject.hour + ':' + timeObject.mins + '.'
}*/
// Increase/decrease the time by the interval and keep looping.
timeObject = clock.create( timeObject.pick += interval )
// If we've looped beyond the limits, break out of the loop.
if ( timeObject.pick <= minLimit || timeObject.pick >= maxLimit ) {
break
}
}
// Return the final object.
return timeObject
} //TimePicker.prototype.shift
/**
* Scope an object to be within range of min and max.
*/
TimePicker.prototype.scope = function( timeObject ) {
var minLimit = this.item.min.pick,
maxLimit = this.item.max.pick
return this.create( timeObject.pick > maxLimit ? maxLimit : timeObject.pick < minLimit ? minLimit : timeObject )
} //TimePicker.prototype.scope
/**
* Parse a string into a usable type.
*/
TimePicker.prototype.parse = function( type, value, options ) {
var hour, minutes, isPM, item, parseValue,
clock = this,
parsingObject = {}
// If its already parsed, were good.
if ( !value || typeof value != 'string' ) {
return value
}
// We need a `.format` to parse the value with.
if ( !( options && options.format ) ) {
options = options || {}
options.format = clock.settings.format
}
// Convert the format into an array and then map through it.
clock.formats.toArray( options.format ).map( function( label ) {
var
substring,
// Grab the formatting label.
formattingLabel = clock.formats[ label ],
// The format length is from the formatting label function or the
// label length without the escaping exclamation (!) mark.
formatLength = formattingLabel ?
_.trigger( formattingLabel, clock, [ value, parsingObject ] ) :
label.replace( /^!/, '' ).length
// If there's a format label, split the value up to the format length.
// Then add it to the parsing object with appropriate label.
if ( formattingLabel ) {
substring = value.substr( 0, formatLength )
parsingObject[ label ] = substring.match(/^\d+$/) ? +substring : substring
}
// Update the time value as the substring from format length to end.
value = value.substr( formatLength )
})
// Grab the hour and minutes from the parsing object.
for ( item in parsingObject ) {
parseValue = parsingObject[item]
if ( _.isInteger(parseValue) ) {
if ( item.match(/^(h|hh)$/i) ) {
hour = parseValue
if ( item == 'h' || item == 'hh' ) {
hour %= 12
}
}
else if ( item == 'i' ) {
minutes = parseValue
}
}
else if ( item.match(/^a$/i) && parseValue.match(/^p/i) && ('h' in parsingObject || 'hh' in parsingObject) ) {
isPM = true
}
}
// Calculate it in minutes and return.
return (isPM ? hour + 12 : hour) * MINUTES_IN_HOUR + minutes
} //TimePicker.prototype.parse
/**
* Various formats to display the object in.
*/
TimePicker.prototype.formats = {
h: function( string, timeObject ) {
// If there's string, then get the digits length.
// Otherwise return the selected hour in "standard" format.
return string ? _.digits( string ) : timeObject.hour % HOURS_TO_NOON || HOURS_TO_NOON
},
hh: function( string, timeObject ) {
// If there's a string, then the length is always 2.
// Otherwise return the selected hour in "standard" format with a leading zero.
return string ? 2 : _.lead( timeObject.hour % HOURS_TO_NOON || HOURS_TO_NOON )
},
H: function( string, timeObject ) {
// If there's string, then get the digits length.
// Otherwise return the selected hour in "military" format as a string.
return string ? _.digits( string ) : '' + ( timeObject.hour % 24 )
},
HH: function( string, timeObject ) {
// If there's string, then get the digits length.
// Otherwise return the selected hour in "military" format with a leading zero.
return string ? _.digits( string ) : _.lead( timeObject.hour % 24 )
},
i: function( string, timeObject ) {
// If there's a string, then the length is always 2.
// Otherwise return the selected minutes.
return string ? 2 : _.lead( timeObject.mins )
},
a: function( string, timeObject ) {
// If there's a string, then the length is always 4.
// Otherwise check if it's more than "noon" and return either am/pm.
return string ? 4 : MINUTES_IN_DAY / 2 > timeObject.time % MINUTES_IN_DAY ? 'a.m.' : 'p.m.'
},
A: function( string, timeObject ) {
// If there's a string, then the length is always 2.
// Otherwise check if it's more than "noon" and return either am/pm.
return string ? 2 : MINUTES_IN_DAY / 2 > timeObject.time % MINUTES_IN_DAY ? 'AM' : 'PM'
},
// Create an array by splitting the formatting string passed.
toArray: function( formatString ) { return formatString.split( /(h{1,2}|H{1,2}|i|a|A|!.)/g ) },
// Format an object into a string using the formatting options.
toString: function ( formatString, itemObject ) {
var clock = this
return clock.formats.toArray( formatString ).map( function( label ) {
return _.trigger( clock.formats[ label ], clock, [ 0, itemObject ] ) || label.replace( /^!/, '' )
}).join( '' )
}
} //TimePicker.prototype.formats
/**
* Check if two time units are the exact.
*/
TimePicker.prototype.isTimeExact = function( one, two ) {
var clock = this
// When were working with minutes, do a direct comparison.
if (
( _.isInteger( one ) && _.isInteger( two ) ) ||
( typeof one == 'boolean' && typeof two == 'boolean' )
) {
return one === two
}
// When were working with time representations, compare the “pick” value.
if (
( _.isDate( one ) || $.isArray( one ) ) &&
( _.isDate( two ) || $.isArray( two ) )
) {
return clock.create( one ).pick === clock.create( two ).pick
}
// When were working with range objects, compare the “from” and “to”.
if ( $.isPlainObject( one ) && $.isPlainObject( two ) ) {
return clock.isTimeExact( one.from, two.from ) && clock.isTimeExact( one.to, two.to )
}
return false
}
/**
* Check if two time units overlap.
*/
TimePicker.prototype.isTimeOverlap = function( one, two ) {
var clock = this
// When were working with an integer, compare the hours.
if ( _.isInteger( one ) && ( _.isDate( two ) || $.isArray( two ) ) ) {
return one === clock.create( two ).hour
}
if ( _.isInteger( two ) && ( _.isDate( one ) || $.isArray( one ) ) ) {
return two === clock.create( one ).hour
}
// When were working with range objects, check if the ranges overlap.
if ( $.isPlainObject( one ) && $.isPlainObject( two ) ) {
return clock.overlapRanges( one, two )
}
return false
}
/**
* Flip the “enabled” state.
*/
TimePicker.prototype.flipEnable = function(val) {
var itemObject = this.item
itemObject.enable = val || (itemObject.enable == -1 ? 1 : -1)
}
/**
* Mark a collection of times as “disabled”.
*/
TimePicker.prototype.deactivate = function( type, timesToDisable ) {
var clock = this,
disabledItems = clock.item.disable.slice(0)
// If were flipping, thats all we need to do.
if ( timesToDisable == 'flip' ) {
clock.flipEnable()
}
else if ( timesToDisable === false ) {
clock.flipEnable(1)
disabledItems = []
}
else if ( timesToDisable === true ) {
clock.flipEnable(-1)
disabledItems = []
}
// Otherwise go through the times to disable.
else {
timesToDisable.map(function( unitToDisable ) {
var matchFound
// When we have disabled items, check for matches.
// If something is matched, immediately break out.
for ( var index = 0; index < disabledItems.length; index += 1 ) {
if ( clock.isTimeExact( unitToDisable, disabledItems[index] ) ) {
matchFound = true
break
}
}
// If nothing was found, add the validated unit to the collection.
if ( !matchFound ) {
if (
_.isInteger( unitToDisable ) ||
_.isDate( unitToDisable ) ||
$.isArray( unitToDisable ) ||
( $.isPlainObject( unitToDisable ) && unitToDisable.from && unitToDisable.to )
) {
disabledItems.push( unitToDisable )
}
}
})
}
// Return the updated collection.
return disabledItems
} //TimePicker.prototype.deactivate
/**
* Mark a collection of times as “enabled”.
*/
TimePicker.prototype.activate = function( type, timesToEnable ) {
var clock = this,
disabledItems = clock.item.disable,
disabledItemsCount = disabledItems.length
// If were flipping, thats all we need to do.
if ( timesToEnable == 'flip' ) {
clock.flipEnable()
}
else if ( timesToEnable === true ) {
clock.flipEnable(1)
disabledItems = []
}
else if ( timesToEnable === false ) {
clock.flipEnable(-1)
disabledItems = []
}
// Otherwise go through the disabled times.
else {
timesToEnable.map(function( unitToEnable ) {
var matchFound,
disabledUnit,
index,
isRangeMatched
// Go through the disabled items and try to find a match.
for ( index = 0; index < disabledItemsCount; index += 1 ) {
disabledUnit = disabledItems[index]
// When an exact match is found, remove it from the collection.
if ( clock.isTimeExact( disabledUnit, unitToEnable ) ) {
matchFound = disabledItems[index] = null
isRangeMatched = true
break
}
// When an overlapped match is found, add the “inverted” state to it.
else if ( clock.isTimeOverlap( disabledUnit, unitToEnable ) ) {
if ( $.isPlainObject( unitToEnable ) ) {
unitToEnable.inverted = true
matchFound = unitToEnable
}
else if ( $.isArray( unitToEnable ) ) {
matchFound = unitToEnable
if ( !matchFound[2] ) matchFound.push( 'inverted' )
}
else if ( _.isDate( unitToEnable ) ) {
matchFound = [ unitToEnable.getFullYear(), unitToEnable.getMonth(), unitToEnable.getDate(), 'inverted' ]
}
break
}
}
// If a match was found, remove a previous duplicate entry.
if ( matchFound ) for ( index = 0; index < disabledItemsCount; index += 1 ) {
if ( clock.isTimeExact( disabledItems[index], unitToEnable ) ) {
disabledItems[index] = null
break
}
}
// In the event that were dealing with an overlap of range times,
// make sure there are no “inverted” times because of it.
if ( isRangeMatched ) for ( index = 0; index < disabledItemsCount; index += 1 ) {
if ( clock.isTimeOverlap( disabledItems[index], unitToEnable ) ) {
disabledItems[index] = null
break
}
}
// If something is still matched, add it into the collection.
if ( matchFound ) {
disabledItems.push( matchFound )
}
})
}
// Return the updated collection.
return disabledItems.filter(function( val ) { return val != null })
} //TimePicker.prototype.activate
/**
* The division to use for the range intervals.
*/
TimePicker.prototype.i = function( type, value/*, options*/ ) {
return _.isInteger( value ) && value > 0 ? value : this.item.interval
}
/**
* Create a string for the nodes in the picker.
*/
TimePicker.prototype.nodes = function( isOpen ) {
var
clock = this,
settings = clock.settings,
selectedObject = clock.item.select,
highlightedObject = clock.item.highlight,
viewsetObject = clock.item.view,
disabledCollection = clock.item.disable
return _.node(
'ul',
_.group({
min: clock.item.min.pick,
max: clock.item.max.pick,
i: clock.item.interval,
node: 'li',
item: function( loopedTime ) {
loopedTime = clock.create( loopedTime )
var timeMinutes = loopedTime.pick,
isSelected = selectedObject && selectedObject.pick == timeMinutes,
isHighlighted = highlightedObject && highlightedObject.pick == timeMinutes,
isDisabled = disabledCollection && clock.disabled( loopedTime ),
formattedTime = _.trigger( clock.formats.toString, clock, [ settings.format, loopedTime ] )
return [
_.trigger( clock.formats.toString, clock, [ _.trigger( settings.formatLabel, clock, [ loopedTime ] ) || settings.format, loopedTime ] ),
(function( klasses ) {
if ( isSelected ) {
klasses.push( settings.klass.selected )
}
if ( isHighlighted ) {
klasses.push( settings.klass.highlighted )
}
if ( viewsetObject && viewsetObject.pick == timeMinutes ) {
klasses.push( settings.klass.viewset )
}
if ( isDisabled ) {
klasses.push( settings.klass.disabled )
}
return klasses.join( ' ' )
})( [ settings.klass.listItem ] ),
'data-pick=' + loopedTime.pick + ' ' + _.ariaAttr({
role: 'option',
label: formattedTime,
selected: isSelected && clock.$node.val() === formattedTime ? true : null,
activedescendant: isHighlighted ? true : null,
disabled: isDisabled ? true : null
})
]
}
}) +
// * For Firefox forms to submit, make sure to set the buttons `type` attribute as “button”.
_.node(
'li',
_.node(
'button',
settings.clear,
settings.klass.buttonClear,
'type=button data-clear=1' + ( isOpen ? '' : ' disabled' ) + ' ' +
_.ariaAttr({ controls: clock.$node[0].id })
),
'', _.ariaAttr({ role: 'presentation' })
),
settings.klass.list,
_.ariaAttr({ role: 'listbox', controls: clock.$node[0].id })
)
} //TimePicker.prototype.nodes
/**
* Extend the picker to add the component with the defaults.
*/
TimePicker.defaults = (function( prefix ) {
return {
// Clear
clear: 'Clear',
// The format to show on the `input` element
format: 'h:i A',
// The interval between each time
interval: 30,
// Picker close behavior
closeOnSelect: true,
closeOnClear: true,
// Classes
klass: {
picker: prefix + ' ' + prefix + '--time',
holder: prefix + '__holder',
list: prefix + '__list',
listItem: prefix + '__list-item',
disabled: prefix + '__list-item--disabled',
selected: prefix + '__list-item--selected',
highlighted: prefix + '__list-item--highlighted',
viewset: prefix + '__list-item--viewset',
now: prefix + '__list-item--now',
buttonClear: prefix + '__button--clear'
}
}
})( Picker.klasses().picker )
/**
* Extend the picker to add the time picker.
*/
Picker.extend( 'pickatime', TimePicker )
}));