pickadate-rails4 3.5.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +63 -0
- data/Rakefile +26 -0
- data/assets/javascripts/pickadate/legacy.js +140 -0
- data/assets/javascripts/pickadate/picker.date.js +1354 -0
- data/assets/javascripts/pickadate/picker.js +1163 -0
- data/assets/javascripts/pickadate/picker.time.js +1013 -0
- data/assets/javascripts/pickadate/translations/NAMING.md +19 -0
- data/assets/javascripts/pickadate/translations/ar.js +16 -0
- data/assets/javascripts/pickadate/translations/bg_BG.js +17 -0
- data/assets/javascripts/pickadate/translations/bs_BA.js +17 -0
- data/assets/javascripts/pickadate/translations/ca_ES.js +18 -0
- data/assets/javascripts/pickadate/translations/cs_CZ.js +17 -0
- data/assets/javascripts/pickadate/translations/da_DK.js +18 -0
- data/assets/javascripts/pickadate/translations/de_DE.js +18 -0
- data/assets/javascripts/pickadate/translations/el_GR.js +17 -0
- data/assets/javascripts/pickadate/translations/es_ES.js +18 -0
- data/assets/javascripts/pickadate/translations/et_EE.js +17 -0
- data/assets/javascripts/pickadate/translations/eu_ES.js +17 -0
- data/assets/javascripts/pickadate/translations/fa_ir.js +19 -0
- data/assets/javascripts/pickadate/translations/fi_FI.js +17 -0
- data/assets/javascripts/pickadate/translations/fr_FR.js +22 -0
- data/assets/javascripts/pickadate/translations/gl_ES.js +17 -0
- data/assets/javascripts/pickadate/translations/he_IL.js +16 -0
- data/assets/javascripts/pickadate/translations/hi_IN.js +20 -0
- data/assets/javascripts/pickadate/translations/hr_HR.js +17 -0
- data/assets/javascripts/pickadate/translations/hu_HU.js +17 -0
- data/assets/javascripts/pickadate/translations/id_ID.js +17 -0
- data/assets/javascripts/pickadate/translations/is_IS.js +17 -0
- data/assets/javascripts/pickadate/translations/it_IT.js +24 -0
- data/assets/javascripts/pickadate/translations/ja_JP.js +17 -0
- data/assets/javascripts/pickadate/translations/ko_KR.js +17 -0
- data/assets/javascripts/pickadate/translations/lt_LT.js +24 -0
- data/assets/javascripts/pickadate/translations/lv_LV.js +13 -0
- data/assets/javascripts/pickadate/translations/nb_NO.js +18 -0
- data/assets/javascripts/pickadate/translations/ne_NP.js +17 -0
- data/assets/javascripts/pickadate/translations/nl_NL.js +18 -0
- data/assets/javascripts/pickadate/translations/no_NO.js +13 -0
- data/assets/javascripts/pickadate/translations/pl_PL.js +18 -0
- data/assets/javascripts/pickadate/translations/pt_BR.js +17 -0
- data/assets/javascripts/pickadate/translations/pt_PT.js +17 -0
- data/assets/javascripts/pickadate/translations/ro_RO.js +17 -0
- data/assets/javascripts/pickadate/translations/ru_RU.js +18 -0
- data/assets/javascripts/pickadate/translations/sk_SK.js +18 -0
- data/assets/javascripts/pickadate/translations/sl_SI.js +18 -0
- data/assets/javascripts/pickadate/translations/sv_SE.js +22 -0
- data/assets/javascripts/pickadate/translations/th_TH.js +16 -0
- data/assets/javascripts/pickadate/translations/tr_TR.js +18 -0
- data/assets/javascripts/pickadate/translations/uk_UA.js +17 -0
- data/assets/javascripts/pickadate/translations/vi_VN.js +15 -0
- data/assets/javascripts/pickadate/translations/zh_CN.js +18 -0
- data/assets/javascripts/pickadate/translations/zh_TW.js +18 -0
- data/assets/stylesheets/pickadate/classic.css +99 -0
- data/assets/stylesheets/pickadate/classic.date.css +301 -0
- data/assets/stylesheets/pickadate/classic.time.css +132 -0
- data/assets/stylesheets/pickadate/default.css +168 -0
- data/assets/stylesheets/pickadate/default.date.css +301 -0
- data/assets/stylesheets/pickadate/default.time.css +126 -0
- data/assets/stylesheets/pickadate/rtl.css +29 -0
- data/lib/pickadate-rails.rb +7 -0
- data/lib/pickadate-rails/version.rb +3 -0
- data/pickadate-rails.gemspec +25 -0
- metadata +152 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c2b07638ae43a31b9008c372f055be715b07d83a
|
4
|
+
data.tar.gz: 3474a5e1058ced4b63e25f63f167865efe219a5c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f478c91603bea731c76deb6bab9bce5ab90bc3de290290299134e219ef67a8722b9ff2abe1c840a3514e304b12b314f2e0465892cda41981c348e40b53652e6a
|
7
|
+
data.tar.gz: 61d4740c429ef29b4d1864b079c110dc36f2458bfbed132f9ccfe6d28aaee8344220a9ee9ecb514ae3857a091e8567ea9e09acfe4d8de351325495062c22585c
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Jeff Fraser
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
# Pickadate-Rails
|
2
|
+
|
3
|
+
## Pickadate Version: 3.5.6
|
4
|
+
|
5
|
+
Easily add [pickadate.js](https://github.com/amsul/pickadate.js) to your Rails 4+ application using the asset pipeline. This is a fork from https://github.com/veracross/pickadate-rails, so make sure to check their code out.
|
6
|
+
|
7
|
+
My version differ that it works only with Rails 4+, and it updates itself using github directly.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
gem 'pickadate-rails'
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
Pickadate has a number of files associated with it. They are documented on the [pickadate repository](https://github.com/amsul/pickadate.js). Files in this gem are namespaced into a `pickadate` folder, and otherwise match the filenames from the pickadate repo.
|
22
|
+
|
23
|
+
### Add the desired files to your javascript/coffeescript
|
24
|
+
Often done in `application.js`:
|
25
|
+
|
26
|
+
//= require pickadate/picker # required
|
27
|
+
//= require pickadate/picker.date # for the date picker
|
28
|
+
//= require pickadate/picker.time # for the time picker
|
29
|
+
|
30
|
+
### Add the stylesheets for the theme you want
|
31
|
+
Often done in `application.css`.
|
32
|
+
|
33
|
+
For the default theme:
|
34
|
+
|
35
|
+
*= require pickadate/default
|
36
|
+
*= require pickadate/default.date
|
37
|
+
*= require pickadate/default.time
|
38
|
+
|
39
|
+
For the classic theme:
|
40
|
+
|
41
|
+
*= require pickadate/classic
|
42
|
+
*= require pickadate/classic.date
|
43
|
+
*= require pickadate/classic.time
|
44
|
+
|
45
|
+
### Localization
|
46
|
+
|
47
|
+
Translations are available by loading them in your javascript/coffeescript file. For example, in `application.js`
|
48
|
+
|
49
|
+
//= require pickadate/translations/bg_BG
|
50
|
+
|
51
|
+
## Versioning
|
52
|
+
|
53
|
+
Starting with version 3.5.2.0 of this gem, we have switched to matching the gem version with pickadate's current version number. We'll use the tiny version number for changes to the gem itself. Therefore, the gem version jumps from 1.5 (bundling pickadate 3.5) to 3.5.2.0 (bundling pickadate 3.5.2).
|
54
|
+
|
55
|
+
## Updating
|
56
|
+
|
57
|
+
1. Run `rake pickadate:download`
|
58
|
+
2. Update `lib/pickadate-rails/version`
|
59
|
+
3. Update the version number in the Readme
|
60
|
+
4. Create a pull request
|
61
|
+
|
62
|
+
## License
|
63
|
+
Pickadate itself and this gem are under the MIT license.
|
data/Rakefile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
|
3
|
+
namespace :pickadate do
|
4
|
+
desc "Download latest assets"
|
5
|
+
task :download do
|
6
|
+
require 'fileutils'
|
7
|
+
|
8
|
+
system "git clone https://github.com/amsul/pickadate.js tmp/pickadate.zip || rm -rf tmp/pickadate.js"
|
9
|
+
# system "unzip tmp/pickadate.zip -d tmp/"
|
10
|
+
# system "rm tmp/pickadate.zip"
|
11
|
+
|
12
|
+
Dir["tmp/pickadate*/lib/picker*.js"].each do |file|
|
13
|
+
FileUtils.cp file, "assets/javascripts/pickadate/#{File.basename(file)}", preserve: false
|
14
|
+
end
|
15
|
+
|
16
|
+
Dir["tmp/pickadate*/lib/translations/*.js"].each do |file|
|
17
|
+
FileUtils.cp file, "assets/javascripts/pickadate/translations/#{File.basename(file)}", preserve: false
|
18
|
+
end
|
19
|
+
|
20
|
+
Dir["tmp/pickadate*/lib/themes/*"].each do |file|
|
21
|
+
FileUtils.cp file, "assets/stylesheets/pickadate/#{File.basename(file)}", preserve: false
|
22
|
+
end
|
23
|
+
|
24
|
+
system "rm -rf tmp/pickadate*"
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
|
2
|
+
/*jshint
|
3
|
+
asi: true,
|
4
|
+
unused: true,
|
5
|
+
boss: true,
|
6
|
+
loopfunc: true,
|
7
|
+
eqnull: true
|
8
|
+
*/
|
9
|
+
|
10
|
+
|
11
|
+
/*!
|
12
|
+
* Legacy browser support
|
13
|
+
*/
|
14
|
+
|
15
|
+
// isArray support
|
16
|
+
if ( !Array.isArray ) {
|
17
|
+
Array.isArray = function( value ) {
|
18
|
+
return {}.toString.call( value ) == '[object Array]'
|
19
|
+
}
|
20
|
+
}
|
21
|
+
|
22
|
+
|
23
|
+
// Map array support
|
24
|
+
if ( ![].map ) {
|
25
|
+
Array.prototype.map = function ( callback, self ) {
|
26
|
+
var array = this, len = array.length, newArray = new Array( len )
|
27
|
+
for ( var i = 0; i < len; i++ ) {
|
28
|
+
if ( i in array ) {
|
29
|
+
newArray[ i ] = callback.call( self, array[ i ], i, array )
|
30
|
+
}
|
31
|
+
}
|
32
|
+
return newArray
|
33
|
+
}
|
34
|
+
}
|
35
|
+
|
36
|
+
|
37
|
+
// Filter array support
|
38
|
+
if ( ![].filter ) {
|
39
|
+
Array.prototype.filter = function( callback ) {
|
40
|
+
if ( this == null ) throw new TypeError()
|
41
|
+
var t = Object( this ), len = t.length >>> 0
|
42
|
+
if ( typeof callback != 'function' ) throw new TypeError()
|
43
|
+
var newArray = [], thisp = arguments[ 1 ]
|
44
|
+
for ( var i = 0; i < len; i++ ) {
|
45
|
+
if ( i in t ) {
|
46
|
+
var val = t[ i ]
|
47
|
+
if ( callback.call( thisp, val, i, t ) ) newArray.push( val )
|
48
|
+
}
|
49
|
+
}
|
50
|
+
return newArray
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
|
55
|
+
// Index of array support
|
56
|
+
if ( ![].indexOf ) {
|
57
|
+
Array.prototype.indexOf = function( searchElement ) {
|
58
|
+
if ( this == null ) throw new TypeError()
|
59
|
+
var t = Object( this ), len = t.length >>> 0
|
60
|
+
if ( len === 0 ) return -1
|
61
|
+
var n = 0
|
62
|
+
if ( arguments.length > 1 ) {
|
63
|
+
n = Number( arguments[ 1 ] )
|
64
|
+
if ( n != n ) {
|
65
|
+
n = 0
|
66
|
+
}
|
67
|
+
else if ( n !== 0 && n != Infinity && n != -Infinity ) {
|
68
|
+
n = ( n > 0 || -1 ) * Math.floor( Math.abs( n ) )
|
69
|
+
}
|
70
|
+
}
|
71
|
+
if ( n >= len ) return -1
|
72
|
+
var k = n >= 0 ? n : Math.max( len - Math.abs( n ), 0 )
|
73
|
+
for ( ; k < len; k++ ) {
|
74
|
+
if ( k in t && t[ k ] === searchElement ) return k
|
75
|
+
}
|
76
|
+
return -1
|
77
|
+
}
|
78
|
+
}
|
79
|
+
|
80
|
+
|
81
|
+
/*!
|
82
|
+
* Cross-Browser Split 1.1.1
|
83
|
+
* Copyright 2007-2012 Steven Levithan <stevenlevithan.com>
|
84
|
+
* Available under the MIT License
|
85
|
+
* http://blog.stevenlevithan.com/archives/cross-browser-split
|
86
|
+
*/
|
87
|
+
var nativeSplit = String.prototype.split, compliantExecNpcg = /()??/.exec('')[1] === undefined
|
88
|
+
String.prototype.split = function(separator, limit) {
|
89
|
+
var str = this
|
90
|
+
if (Object.prototype.toString.call(separator) !== '[object RegExp]') {
|
91
|
+
return nativeSplit.call(str, separator, limit)
|
92
|
+
}
|
93
|
+
var output = [],
|
94
|
+
flags = (separator.ignoreCase ? 'i' : '') +
|
95
|
+
(separator.multiline ? 'm' : '') +
|
96
|
+
(separator.extended ? 'x' : '') +
|
97
|
+
(separator.sticky ? 'y' : ''),
|
98
|
+
lastLastIndex = 0,
|
99
|
+
separator2, match, lastIndex, lastLength
|
100
|
+
separator = new RegExp(separator.source, flags + 'g')
|
101
|
+
str += ''
|
102
|
+
if (!compliantExecNpcg) {
|
103
|
+
separator2 = new RegExp('^' + separator.source + '$(?!\\s)', flags)
|
104
|
+
}
|
105
|
+
limit = limit === undefined ? -1 >>> 0 : limit >>> 0
|
106
|
+
while (match = separator.exec(str)) {
|
107
|
+
lastIndex = match.index + match[0].length
|
108
|
+
if (lastIndex > lastLastIndex) {
|
109
|
+
output.push(str.slice(lastLastIndex, match.index))
|
110
|
+
if (!compliantExecNpcg && match.length > 1) {
|
111
|
+
match[0].replace(separator2, function () {
|
112
|
+
for (var i = 1; i < arguments.length - 2; i++) {
|
113
|
+
if (arguments[i] === undefined) {
|
114
|
+
match[i] = undefined
|
115
|
+
}
|
116
|
+
}
|
117
|
+
})
|
118
|
+
}
|
119
|
+
if (match.length > 1 && match.index < str.length) {
|
120
|
+
Array.prototype.push.apply(output, match.slice(1))
|
121
|
+
}
|
122
|
+
lastLength = match[0].length
|
123
|
+
lastLastIndex = lastIndex
|
124
|
+
if (output.length >= limit) {
|
125
|
+
break
|
126
|
+
}
|
127
|
+
}
|
128
|
+
if (separator.lastIndex === match.index) {
|
129
|
+
separator.lastIndex++
|
130
|
+
}
|
131
|
+
}
|
132
|
+
if (lastLastIndex === str.length) {
|
133
|
+
if (lastLength || !separator.test('')) {
|
134
|
+
output.push('')
|
135
|
+
}
|
136
|
+
} else {
|
137
|
+
output.push(str.slice(lastLastIndex))
|
138
|
+
}
|
139
|
+
return output.length > limit ? output.slice(0, limit) : output
|
140
|
+
}
|
@@ -0,0 +1,1354 @@
|
|
1
|
+
/*!
|
2
|
+
* Date picker for pickadate.js v3.5.6
|
3
|
+
* http://amsul.github.io/pickadate.js/date.htm
|
4
|
+
*/
|
5
|
+
|
6
|
+
(function ( factory ) {
|
7
|
+
|
8
|
+
// AMD.
|
9
|
+
if ( typeof define == 'function' && define.amd )
|
10
|
+
define( ['picker', 'jquery'], factory )
|
11
|
+
|
12
|
+
// Node.js/browserify.
|
13
|
+
else if ( typeof exports == 'object' )
|
14
|
+
module.exports = factory( require('./picker.js'), require('jquery') )
|
15
|
+
|
16
|
+
// Browser globals.
|
17
|
+
else factory( Picker, jQuery )
|
18
|
+
|
19
|
+
}(function( Picker, $ ) {
|
20
|
+
|
21
|
+
|
22
|
+
/**
|
23
|
+
* Globals and constants
|
24
|
+
*/
|
25
|
+
var DAYS_IN_WEEK = 7,
|
26
|
+
WEEKS_IN_CALENDAR = 6,
|
27
|
+
_ = Picker._
|
28
|
+
|
29
|
+
|
30
|
+
|
31
|
+
/**
|
32
|
+
* The date picker constructor
|
33
|
+
*/
|
34
|
+
function DatePicker( picker, settings ) {
|
35
|
+
|
36
|
+
var calendar = this,
|
37
|
+
element = picker.$node[ 0 ],
|
38
|
+
elementValue = element.value,
|
39
|
+
elementDataValue = picker.$node.data( 'value' ),
|
40
|
+
valueString = elementDataValue || elementValue,
|
41
|
+
formatString = elementDataValue ? settings.formatSubmit : settings.format,
|
42
|
+
isRTL = function() {
|
43
|
+
|
44
|
+
return element.currentStyle ?
|
45
|
+
|
46
|
+
// For IE.
|
47
|
+
element.currentStyle.direction == 'rtl' :
|
48
|
+
|
49
|
+
// For normal browsers.
|
50
|
+
getComputedStyle( picker.$root[0] ).direction == 'rtl'
|
51
|
+
}
|
52
|
+
|
53
|
+
calendar.settings = settings
|
54
|
+
calendar.$node = picker.$node
|
55
|
+
|
56
|
+
// The queue of methods that will be used to build item objects.
|
57
|
+
calendar.queue = {
|
58
|
+
min: 'measure create',
|
59
|
+
max: 'measure create',
|
60
|
+
now: 'now create',
|
61
|
+
select: 'parse create validate',
|
62
|
+
highlight: 'parse navigate create validate',
|
63
|
+
view: 'parse create validate viewset',
|
64
|
+
disable: 'deactivate',
|
65
|
+
enable: 'activate'
|
66
|
+
}
|
67
|
+
|
68
|
+
// The component's item object.
|
69
|
+
calendar.item = {}
|
70
|
+
|
71
|
+
calendar.item.clear = null
|
72
|
+
calendar.item.disable = ( settings.disable || [] ).slice( 0 )
|
73
|
+
calendar.item.enable = -(function( collectionDisabled ) {
|
74
|
+
return collectionDisabled[ 0 ] === true ? collectionDisabled.shift() : -1
|
75
|
+
})( calendar.item.disable )
|
76
|
+
|
77
|
+
calendar.
|
78
|
+
set( 'min', settings.min ).
|
79
|
+
set( 'max', settings.max ).
|
80
|
+
set( 'now' )
|
81
|
+
|
82
|
+
// When there’s a value, set the `select`, which in turn
|
83
|
+
// also sets the `highlight` and `view`.
|
84
|
+
if ( valueString ) {
|
85
|
+
calendar.set( 'select', valueString, {
|
86
|
+
format: formatString,
|
87
|
+
defaultValue: true
|
88
|
+
})
|
89
|
+
}
|
90
|
+
|
91
|
+
// If there’s no value, default to highlighting “today”.
|
92
|
+
else {
|
93
|
+
calendar.
|
94
|
+
set( 'select', null ).
|
95
|
+
set( 'highlight', calendar.item.now )
|
96
|
+
}
|
97
|
+
|
98
|
+
|
99
|
+
// The keycode to movement mapping.
|
100
|
+
calendar.key = {
|
101
|
+
40: 7, // Down
|
102
|
+
38: -7, // Up
|
103
|
+
39: function() { return isRTL() ? -1 : 1 }, // Right
|
104
|
+
37: function() { return isRTL() ? 1 : -1 }, // Left
|
105
|
+
go: function( timeChange ) {
|
106
|
+
var highlightedObject = calendar.item.highlight,
|
107
|
+
targetDate = new Date( highlightedObject.year, highlightedObject.month, highlightedObject.date + timeChange )
|
108
|
+
calendar.set(
|
109
|
+
'highlight',
|
110
|
+
targetDate,
|
111
|
+
{ interval: timeChange }
|
112
|
+
)
|
113
|
+
this.render()
|
114
|
+
}
|
115
|
+
}
|
116
|
+
|
117
|
+
|
118
|
+
// Bind some picker events.
|
119
|
+
picker.
|
120
|
+
on( 'render', function() {
|
121
|
+
picker.$root.find( '.' + settings.klass.selectMonth ).on( 'change', function() {
|
122
|
+
var value = this.value
|
123
|
+
if ( value ) {
|
124
|
+
picker.set( 'highlight', [ picker.get( 'view' ).year, value, picker.get( 'highlight' ).date ] )
|
125
|
+
picker.$root.find( '.' + settings.klass.selectMonth ).trigger( 'focus' )
|
126
|
+
}
|
127
|
+
})
|
128
|
+
picker.$root.find( '.' + settings.klass.selectYear ).on( 'change', function() {
|
129
|
+
var value = this.value
|
130
|
+
if ( value ) {
|
131
|
+
picker.set( 'highlight', [ value, picker.get( 'view' ).month, picker.get( 'highlight' ).date ] )
|
132
|
+
picker.$root.find( '.' + settings.klass.selectYear ).trigger( 'focus' )
|
133
|
+
}
|
134
|
+
})
|
135
|
+
}, 1 ).
|
136
|
+
on( 'open', function() {
|
137
|
+
var includeToday = ''
|
138
|
+
if ( calendar.disabled( calendar.get('now') ) ) {
|
139
|
+
includeToday = ':not(.' + settings.klass.buttonToday + ')'
|
140
|
+
}
|
141
|
+
picker.$root.find( 'button' + includeToday + ', select' ).attr( 'disabled', false )
|
142
|
+
}, 1 ).
|
143
|
+
on( 'close', function() {
|
144
|
+
picker.$root.find( 'button, select' ).attr( 'disabled', true )
|
145
|
+
}, 1 )
|
146
|
+
|
147
|
+
} //DatePicker
|
148
|
+
|
149
|
+
|
150
|
+
/**
|
151
|
+
* Set a datepicker item object.
|
152
|
+
*/
|
153
|
+
DatePicker.prototype.set = function( type, value, options ) {
|
154
|
+
|
155
|
+
var calendar = this,
|
156
|
+
calendarItem = calendar.item
|
157
|
+
|
158
|
+
// If the value is `null` just set it immediately.
|
159
|
+
if ( value === null ) {
|
160
|
+
if ( type == 'clear' ) type = 'select'
|
161
|
+
calendarItem[ type ] = value
|
162
|
+
return calendar
|
163
|
+
}
|
164
|
+
|
165
|
+
// Otherwise go through the queue of methods, and invoke the functions.
|
166
|
+
// Update this as the time unit, and set the final value as this item.
|
167
|
+
// * In the case of `enable`, keep the queue but set `disable` instead.
|
168
|
+
// And in the case of `flip`, keep the queue but set `enable` instead.
|
169
|
+
calendarItem[ ( type == 'enable' ? 'disable' : type == 'flip' ? 'enable' : type ) ] = calendar.queue[ type ].split( ' ' ).map( function( method ) {
|
170
|
+
value = calendar[ method ]( type, value, options )
|
171
|
+
return value
|
172
|
+
}).pop()
|
173
|
+
|
174
|
+
// Check if we need to cascade through more updates.
|
175
|
+
if ( type == 'select' ) {
|
176
|
+
calendar.set( 'highlight', calendarItem.select, options )
|
177
|
+
}
|
178
|
+
else if ( type == 'highlight' ) {
|
179
|
+
calendar.set( 'view', calendarItem.highlight, options )
|
180
|
+
}
|
181
|
+
else if ( type.match( /^(flip|min|max|disable|enable)$/ ) ) {
|
182
|
+
if ( calendarItem.select && calendar.disabled( calendarItem.select ) ) {
|
183
|
+
calendar.set( 'select', calendarItem.select, options )
|
184
|
+
}
|
185
|
+
if ( calendarItem.highlight && calendar.disabled( calendarItem.highlight ) ) {
|
186
|
+
calendar.set( 'highlight', calendarItem.highlight, options )
|
187
|
+
}
|
188
|
+
}
|
189
|
+
|
190
|
+
return calendar
|
191
|
+
} //DatePicker.prototype.set
|
192
|
+
|
193
|
+
|
194
|
+
/**
|
195
|
+
* Get a datepicker item object.
|
196
|
+
*/
|
197
|
+
DatePicker.prototype.get = function( type ) {
|
198
|
+
return this.item[ type ]
|
199
|
+
} //DatePicker.prototype.get
|
200
|
+
|
201
|
+
|
202
|
+
/**
|
203
|
+
* Create a picker date object.
|
204
|
+
*/
|
205
|
+
DatePicker.prototype.create = function( type, value, options ) {
|
206
|
+
|
207
|
+
var isInfiniteValue,
|
208
|
+
calendar = this
|
209
|
+
|
210
|
+
// If there’s no value, use the type as the value.
|
211
|
+
value = value === undefined ? type : value
|
212
|
+
|
213
|
+
|
214
|
+
// If it’s infinity, update the value.
|
215
|
+
if ( value == -Infinity || value == Infinity ) {
|
216
|
+
isInfiniteValue = value
|
217
|
+
}
|
218
|
+
|
219
|
+
// If it’s an object, use the native date object.
|
220
|
+
else if ( $.isPlainObject( value ) && _.isInteger( value.pick ) ) {
|
221
|
+
value = value.obj
|
222
|
+
}
|
223
|
+
|
224
|
+
// If it’s an array, convert it into a date and make sure
|
225
|
+
// that it’s a valid date – otherwise default to today.
|
226
|
+
else if ( $.isArray( value ) ) {
|
227
|
+
value = new Date( value[ 0 ], value[ 1 ], value[ 2 ] )
|
228
|
+
value = _.isDate( value ) ? value : calendar.create().obj
|
229
|
+
}
|
230
|
+
|
231
|
+
// If it’s a number or date object, make a normalized date.
|
232
|
+
else if ( _.isInteger( value ) || _.isDate( value ) ) {
|
233
|
+
value = calendar.normalize( new Date( value ), options )
|
234
|
+
}
|
235
|
+
|
236
|
+
// If it’s a literal true or any other case, set it to now.
|
237
|
+
else /*if ( value === true )*/ {
|
238
|
+
value = calendar.now( type, value, options )
|
239
|
+
}
|
240
|
+
|
241
|
+
// Return the compiled object.
|
242
|
+
return {
|
243
|
+
year: isInfiniteValue || value.getFullYear(),
|
244
|
+
month: isInfiniteValue || value.getMonth(),
|
245
|
+
date: isInfiniteValue || value.getDate(),
|
246
|
+
day: isInfiniteValue || value.getDay(),
|
247
|
+
obj: isInfiniteValue || value,
|
248
|
+
pick: isInfiniteValue || value.getTime()
|
249
|
+
}
|
250
|
+
} //DatePicker.prototype.create
|
251
|
+
|
252
|
+
|
253
|
+
/**
|
254
|
+
* Create a range limit object using an array, date object,
|
255
|
+
* literal “true”, or integer relative to another time.
|
256
|
+
*/
|
257
|
+
DatePicker.prototype.createRange = function( from, to ) {
|
258
|
+
|
259
|
+
var calendar = this,
|
260
|
+
createDate = function( date ) {
|
261
|
+
if ( date === true || $.isArray( date ) || _.isDate( date ) ) {
|
262
|
+
return calendar.create( date )
|
263
|
+
}
|
264
|
+
return date
|
265
|
+
}
|
266
|
+
|
267
|
+
// Create objects if possible.
|
268
|
+
if ( !_.isInteger( from ) ) {
|
269
|
+
from = createDate( from )
|
270
|
+
}
|
271
|
+
if ( !_.isInteger( to ) ) {
|
272
|
+
to = createDate( to )
|
273
|
+
}
|
274
|
+
|
275
|
+
// Create relative dates.
|
276
|
+
if ( _.isInteger( from ) && $.isPlainObject( to ) ) {
|
277
|
+
from = [ to.year, to.month, to.date + from ];
|
278
|
+
}
|
279
|
+
else if ( _.isInteger( to ) && $.isPlainObject( from ) ) {
|
280
|
+
to = [ from.year, from.month, from.date + to ];
|
281
|
+
}
|
282
|
+
|
283
|
+
return {
|
284
|
+
from: createDate( from ),
|
285
|
+
to: createDate( to )
|
286
|
+
}
|
287
|
+
} //DatePicker.prototype.createRange
|
288
|
+
|
289
|
+
|
290
|
+
/**
|
291
|
+
* Check if a date unit falls within a date range object.
|
292
|
+
*/
|
293
|
+
DatePicker.prototype.withinRange = function( range, dateUnit ) {
|
294
|
+
range = this.createRange(range.from, range.to)
|
295
|
+
return dateUnit.pick >= range.from.pick && dateUnit.pick <= range.to.pick
|
296
|
+
}
|
297
|
+
|
298
|
+
|
299
|
+
/**
|
300
|
+
* Check if two date range objects overlap.
|
301
|
+
*/
|
302
|
+
DatePicker.prototype.overlapRanges = function( one, two ) {
|
303
|
+
|
304
|
+
var calendar = this
|
305
|
+
|
306
|
+
// Convert the ranges into comparable dates.
|
307
|
+
one = calendar.createRange( one.from, one.to )
|
308
|
+
two = calendar.createRange( two.from, two.to )
|
309
|
+
|
310
|
+
return calendar.withinRange( one, two.from ) || calendar.withinRange( one, two.to ) ||
|
311
|
+
calendar.withinRange( two, one.from ) || calendar.withinRange( two, one.to )
|
312
|
+
}
|
313
|
+
|
314
|
+
|
315
|
+
/**
|
316
|
+
* Get the date today.
|
317
|
+
*/
|
318
|
+
DatePicker.prototype.now = function( type, value, options ) {
|
319
|
+
value = new Date()
|
320
|
+
if ( options && options.rel ) {
|
321
|
+
value.setDate( value.getDate() + options.rel )
|
322
|
+
}
|
323
|
+
return this.normalize( value, options )
|
324
|
+
}
|
325
|
+
|
326
|
+
|
327
|
+
/**
|
328
|
+
* Navigate to next/prev month.
|
329
|
+
*/
|
330
|
+
DatePicker.prototype.navigate = function( type, value, options ) {
|
331
|
+
|
332
|
+
var targetDateObject,
|
333
|
+
targetYear,
|
334
|
+
targetMonth,
|
335
|
+
targetDate,
|
336
|
+
isTargetArray = $.isArray( value ),
|
337
|
+
isTargetObject = $.isPlainObject( value ),
|
338
|
+
viewsetObject = this.item.view/*,
|
339
|
+
safety = 100*/
|
340
|
+
|
341
|
+
|
342
|
+
if ( isTargetArray || isTargetObject ) {
|
343
|
+
|
344
|
+
if ( isTargetObject ) {
|
345
|
+
targetYear = value.year
|
346
|
+
targetMonth = value.month
|
347
|
+
targetDate = value.date
|
348
|
+
}
|
349
|
+
else {
|
350
|
+
targetYear = +value[0]
|
351
|
+
targetMonth = +value[1]
|
352
|
+
targetDate = +value[2]
|
353
|
+
}
|
354
|
+
|
355
|
+
// If we’re navigating months but the view is in a different
|
356
|
+
// month, navigate to the view’s year and month.
|
357
|
+
if ( options && options.nav && viewsetObject && viewsetObject.month !== targetMonth ) {
|
358
|
+
targetYear = viewsetObject.year
|
359
|
+
targetMonth = viewsetObject.month
|
360
|
+
}
|
361
|
+
|
362
|
+
// Figure out the expected target year and month.
|
363
|
+
targetDateObject = new Date( targetYear, targetMonth + ( options && options.nav ? options.nav : 0 ), 1 )
|
364
|
+
targetYear = targetDateObject.getFullYear()
|
365
|
+
targetMonth = targetDateObject.getMonth()
|
366
|
+
|
367
|
+
// If the month we’re going to doesn’t have enough days,
|
368
|
+
// keep decreasing the date until we reach the month’s last date.
|
369
|
+
while ( /*safety &&*/ new Date( targetYear, targetMonth, targetDate ).getMonth() !== targetMonth ) {
|
370
|
+
targetDate -= 1
|
371
|
+
/*safety -= 1
|
372
|
+
if ( !safety ) {
|
373
|
+
throw 'Fell into an infinite loop while navigating to ' + new Date( targetYear, targetMonth, targetDate ) + '.'
|
374
|
+
}*/
|
375
|
+
}
|
376
|
+
|
377
|
+
value = [ targetYear, targetMonth, targetDate ]
|
378
|
+
}
|
379
|
+
|
380
|
+
return value
|
381
|
+
} //DatePicker.prototype.navigate
|
382
|
+
|
383
|
+
|
384
|
+
/**
|
385
|
+
* Normalize a date by setting the hours to midnight.
|
386
|
+
*/
|
387
|
+
DatePicker.prototype.normalize = function( value/*, options*/ ) {
|
388
|
+
value.setHours( 0, 0, 0, 0 )
|
389
|
+
return value
|
390
|
+
}
|
391
|
+
|
392
|
+
|
393
|
+
/**
|
394
|
+
* Measure the range of dates.
|
395
|
+
*/
|
396
|
+
DatePicker.prototype.measure = function( type, value/*, options*/ ) {
|
397
|
+
|
398
|
+
var calendar = this
|
399
|
+
|
400
|
+
// If it’s anything false-y, remove the limits.
|
401
|
+
if ( !value ) {
|
402
|
+
value = type == 'min' ? -Infinity : Infinity
|
403
|
+
}
|
404
|
+
|
405
|
+
// If it’s a string, parse it.
|
406
|
+
else if ( typeof value == 'string' ) {
|
407
|
+
value = calendar.parse( type, value )
|
408
|
+
}
|
409
|
+
|
410
|
+
// If it's an integer, get a date relative to today.
|
411
|
+
else if ( _.isInteger( value ) ) {
|
412
|
+
value = calendar.now( type, value, { rel: value } )
|
413
|
+
}
|
414
|
+
|
415
|
+
return value
|
416
|
+
} ///DatePicker.prototype.measure
|
417
|
+
|
418
|
+
|
419
|
+
/**
|
420
|
+
* Create a viewset object based on navigation.
|
421
|
+
*/
|
422
|
+
DatePicker.prototype.viewset = function( type, dateObject/*, options*/ ) {
|
423
|
+
return this.create([ dateObject.year, dateObject.month, 1 ])
|
424
|
+
}
|
425
|
+
|
426
|
+
|
427
|
+
/**
|
428
|
+
* Validate a date as enabled and shift if needed.
|
429
|
+
*/
|
430
|
+
DatePicker.prototype.validate = function( type, dateObject, options ) {
|
431
|
+
|
432
|
+
var calendar = this,
|
433
|
+
|
434
|
+
// Keep a reference to the original date.
|
435
|
+
originalDateObject = dateObject,
|
436
|
+
|
437
|
+
// Make sure we have an interval.
|
438
|
+
interval = options && options.interval ? options.interval : 1,
|
439
|
+
|
440
|
+
// Check if the calendar enabled dates are inverted.
|
441
|
+
isFlippedBase = calendar.item.enable === -1,
|
442
|
+
|
443
|
+
// Check if we have any enabled dates after/before now.
|
444
|
+
hasEnabledBeforeTarget, hasEnabledAfterTarget,
|
445
|
+
|
446
|
+
// The min & max limits.
|
447
|
+
minLimitObject = calendar.item.min,
|
448
|
+
maxLimitObject = calendar.item.max,
|
449
|
+
|
450
|
+
// Check if we’ve reached the limit during shifting.
|
451
|
+
reachedMin, reachedMax,
|
452
|
+
|
453
|
+
// Check if the calendar is inverted and at least one weekday is enabled.
|
454
|
+
hasEnabledWeekdays = isFlippedBase && calendar.item.disable.filter( function( value ) {
|
455
|
+
|
456
|
+
// If there’s a date, check where it is relative to the target.
|
457
|
+
if ( $.isArray( value ) ) {
|
458
|
+
var dateTime = calendar.create( value ).pick
|
459
|
+
if ( dateTime < dateObject.pick ) hasEnabledBeforeTarget = true
|
460
|
+
else if ( dateTime > dateObject.pick ) hasEnabledAfterTarget = true
|
461
|
+
}
|
462
|
+
|
463
|
+
// Return only integers for enabled weekdays.
|
464
|
+
return _.isInteger( value )
|
465
|
+
}).length/*,
|
466
|
+
|
467
|
+
safety = 100*/
|
468
|
+
|
469
|
+
|
470
|
+
|
471
|
+
// Cases to validate for:
|
472
|
+
// [1] Not inverted and date disabled.
|
473
|
+
// [2] Inverted and some dates enabled.
|
474
|
+
// [3] Not inverted and out of range.
|
475
|
+
//
|
476
|
+
// Cases to **not** validate for:
|
477
|
+
// • Navigating months.
|
478
|
+
// • Not inverted and date enabled.
|
479
|
+
// • Inverted and all dates disabled.
|
480
|
+
// • ..and anything else.
|
481
|
+
if ( !options || (!options.nav && !options.defaultValue) ) if (
|
482
|
+
/* 1 */ ( !isFlippedBase && calendar.disabled( dateObject ) ) ||
|
483
|
+
/* 2 */ ( isFlippedBase && calendar.disabled( dateObject ) && ( hasEnabledWeekdays || hasEnabledBeforeTarget || hasEnabledAfterTarget ) ) ||
|
484
|
+
/* 3 */ ( !isFlippedBase && (dateObject.pick <= minLimitObject.pick || dateObject.pick >= maxLimitObject.pick) )
|
485
|
+
) {
|
486
|
+
|
487
|
+
|
488
|
+
// When inverted, flip the direction if there aren’t any enabled weekdays
|
489
|
+
// and there are no enabled dates in the direction of the interval.
|
490
|
+
if ( isFlippedBase && !hasEnabledWeekdays && ( ( !hasEnabledAfterTarget && interval > 0 ) || ( !hasEnabledBeforeTarget && interval < 0 ) ) ) {
|
491
|
+
interval *= -1
|
492
|
+
}
|
493
|
+
|
494
|
+
|
495
|
+
// Keep looping until we reach an enabled date.
|
496
|
+
while ( /*safety &&*/ calendar.disabled( dateObject ) ) {
|
497
|
+
|
498
|
+
/*safety -= 1
|
499
|
+
if ( !safety ) {
|
500
|
+
throw 'Fell into an infinite loop while validating ' + dateObject.obj + '.'
|
501
|
+
}*/
|
502
|
+
|
503
|
+
|
504
|
+
// If we’ve looped into the next/prev month with a large interval, return to the original date and flatten the interval.
|
505
|
+
if ( Math.abs( interval ) > 1 && ( dateObject.month < originalDateObject.month || dateObject.month > originalDateObject.month ) ) {
|
506
|
+
dateObject = originalDateObject
|
507
|
+
interval = interval > 0 ? 1 : -1
|
508
|
+
}
|
509
|
+
|
510
|
+
|
511
|
+
// If we’ve reached the min/max limit, reverse the direction, flatten the interval and set it to the limit.
|
512
|
+
if ( dateObject.pick <= minLimitObject.pick ) {
|
513
|
+
reachedMin = true
|
514
|
+
interval = 1
|
515
|
+
dateObject = calendar.create([
|
516
|
+
minLimitObject.year,
|
517
|
+
minLimitObject.month,
|
518
|
+
minLimitObject.date + (dateObject.pick === minLimitObject.pick ? 0 : -1)
|
519
|
+
])
|
520
|
+
}
|
521
|
+
else if ( dateObject.pick >= maxLimitObject.pick ) {
|
522
|
+
reachedMax = true
|
523
|
+
interval = -1
|
524
|
+
dateObject = calendar.create([
|
525
|
+
maxLimitObject.year,
|
526
|
+
maxLimitObject.month,
|
527
|
+
maxLimitObject.date + (dateObject.pick === maxLimitObject.pick ? 0 : 1)
|
528
|
+
])
|
529
|
+
}
|
530
|
+
|
531
|
+
|
532
|
+
// If we’ve reached both limits, just break out of the loop.
|
533
|
+
if ( reachedMin && reachedMax ) {
|
534
|
+
break
|
535
|
+
}
|
536
|
+
|
537
|
+
|
538
|
+
// Finally, create the shifted date using the interval and keep looping.
|
539
|
+
dateObject = calendar.create([ dateObject.year, dateObject.month, dateObject.date + interval ])
|
540
|
+
}
|
541
|
+
|
542
|
+
} //endif
|
543
|
+
|
544
|
+
|
545
|
+
// Return the date object settled on.
|
546
|
+
return dateObject
|
547
|
+
} //DatePicker.prototype.validate
|
548
|
+
|
549
|
+
|
550
|
+
/**
|
551
|
+
* Check if a date is disabled.
|
552
|
+
*/
|
553
|
+
DatePicker.prototype.disabled = function( dateToVerify ) {
|
554
|
+
|
555
|
+
var
|
556
|
+
calendar = this,
|
557
|
+
|
558
|
+
// Filter through the disabled dates to check if this is one.
|
559
|
+
isDisabledMatch = calendar.item.disable.filter( function( dateToDisable ) {
|
560
|
+
|
561
|
+
// If the date is a number, match the weekday with 0index and `firstDay` check.
|
562
|
+
if ( _.isInteger( dateToDisable ) ) {
|
563
|
+
return dateToVerify.day === ( calendar.settings.firstDay ? dateToDisable : dateToDisable - 1 ) % 7
|
564
|
+
}
|
565
|
+
|
566
|
+
// If it’s an array or a native JS date, create and match the exact date.
|
567
|
+
if ( $.isArray( dateToDisable ) || _.isDate( dateToDisable ) ) {
|
568
|
+
return dateToVerify.pick === calendar.create( dateToDisable ).pick
|
569
|
+
}
|
570
|
+
|
571
|
+
// If it’s an object, match a date within the “from” and “to” range.
|
572
|
+
if ( $.isPlainObject( dateToDisable ) ) {
|
573
|
+
return calendar.withinRange( dateToDisable, dateToVerify )
|
574
|
+
}
|
575
|
+
})
|
576
|
+
|
577
|
+
// If this date matches a disabled date, confirm it’s not inverted.
|
578
|
+
isDisabledMatch = isDisabledMatch.length && !isDisabledMatch.filter(function( dateToDisable ) {
|
579
|
+
return $.isArray( dateToDisable ) && dateToDisable[3] == 'inverted' ||
|
580
|
+
$.isPlainObject( dateToDisable ) && dateToDisable.inverted
|
581
|
+
}).length
|
582
|
+
|
583
|
+
// Check the calendar “enabled” flag and respectively flip the
|
584
|
+
// disabled state. Then also check if it’s beyond the min/max limits.
|
585
|
+
return calendar.item.enable === -1 ? !isDisabledMatch : isDisabledMatch ||
|
586
|
+
dateToVerify.pick < calendar.item.min.pick ||
|
587
|
+
dateToVerify.pick > calendar.item.max.pick
|
588
|
+
|
589
|
+
} //DatePicker.prototype.disabled
|
590
|
+
|
591
|
+
|
592
|
+
/**
|
593
|
+
* Parse a string into a usable type.
|
594
|
+
*/
|
595
|
+
DatePicker.prototype.parse = function( type, value, options ) {
|
596
|
+
|
597
|
+
var calendar = this,
|
598
|
+
parsingObject = {}
|
599
|
+
|
600
|
+
// If it’s already parsed, we’re good.
|
601
|
+
if ( !value || typeof value != 'string' ) {
|
602
|
+
return value
|
603
|
+
}
|
604
|
+
|
605
|
+
// We need a `.format` to parse the value with.
|
606
|
+
if ( !( options && options.format ) ) {
|
607
|
+
options = options || {}
|
608
|
+
options.format = calendar.settings.format
|
609
|
+
}
|
610
|
+
|
611
|
+
// Convert the format into an array and then map through it.
|
612
|
+
calendar.formats.toArray( options.format ).map( function( label ) {
|
613
|
+
|
614
|
+
var
|
615
|
+
// Grab the formatting label.
|
616
|
+
formattingLabel = calendar.formats[ label ],
|
617
|
+
|
618
|
+
// The format length is from the formatting label function or the
|
619
|
+
// label length without the escaping exclamation (!) mark.
|
620
|
+
formatLength = formattingLabel ? _.trigger( formattingLabel, calendar, [ value, parsingObject ] ) : label.replace( /^!/, '' ).length
|
621
|
+
|
622
|
+
// If there's a format label, split the value up to the format length.
|
623
|
+
// Then add it to the parsing object with appropriate label.
|
624
|
+
if ( formattingLabel ) {
|
625
|
+
parsingObject[ label ] = value.substr( 0, formatLength )
|
626
|
+
}
|
627
|
+
|
628
|
+
// Update the value as the substring from format length to end.
|
629
|
+
value = value.substr( formatLength )
|
630
|
+
})
|
631
|
+
|
632
|
+
// Compensate for month 0index.
|
633
|
+
return [
|
634
|
+
parsingObject.yyyy || parsingObject.yy,
|
635
|
+
+( parsingObject.mm || parsingObject.m ) - 1,
|
636
|
+
parsingObject.dd || parsingObject.d
|
637
|
+
]
|
638
|
+
} //DatePicker.prototype.parse
|
639
|
+
|
640
|
+
|
641
|
+
/**
|
642
|
+
* Various formats to display the object in.
|
643
|
+
*/
|
644
|
+
DatePicker.prototype.formats = (function() {
|
645
|
+
|
646
|
+
// Return the length of the first word in a collection.
|
647
|
+
function getWordLengthFromCollection( string, collection, dateObject ) {
|
648
|
+
|
649
|
+
// Grab the first word from the string.
|
650
|
+
// Regex pattern from http://stackoverflow.com/q/150033
|
651
|
+
var word = string.match( /[^\x00-\x7F]+|\w+/ )[ 0 ]
|
652
|
+
|
653
|
+
// If there's no month index, add it to the date object
|
654
|
+
if ( !dateObject.mm && !dateObject.m ) {
|
655
|
+
dateObject.m = collection.indexOf( word ) + 1
|
656
|
+
}
|
657
|
+
|
658
|
+
// Return the length of the word.
|
659
|
+
return word.length
|
660
|
+
}
|
661
|
+
|
662
|
+
// Get the length of the first word in a string.
|
663
|
+
function getFirstWordLength( string ) {
|
664
|
+
return string.match( /\w+/ )[ 0 ].length
|
665
|
+
}
|
666
|
+
|
667
|
+
return {
|
668
|
+
|
669
|
+
d: function( string, dateObject ) {
|
670
|
+
|
671
|
+
// If there's string, then get the digits length.
|
672
|
+
// Otherwise return the selected date.
|
673
|
+
return string ? _.digits( string ) : dateObject.date
|
674
|
+
},
|
675
|
+
dd: function( string, dateObject ) {
|
676
|
+
|
677
|
+
// If there's a string, then the length is always 2.
|
678
|
+
// Otherwise return the selected date with a leading zero.
|
679
|
+
return string ? 2 : _.lead( dateObject.date )
|
680
|
+
},
|
681
|
+
ddd: function( string, dateObject ) {
|
682
|
+
|
683
|
+
// If there's a string, then get the length of the first word.
|
684
|
+
// Otherwise return the short selected weekday.
|
685
|
+
return string ? getFirstWordLength( string ) : this.settings.weekdaysShort[ dateObject.day ]
|
686
|
+
},
|
687
|
+
dddd: function( string, dateObject ) {
|
688
|
+
|
689
|
+
// If there's a string, then get the length of the first word.
|
690
|
+
// Otherwise return the full selected weekday.
|
691
|
+
return string ? getFirstWordLength( string ) : this.settings.weekdaysFull[ dateObject.day ]
|
692
|
+
},
|
693
|
+
m: function( string, dateObject ) {
|
694
|
+
|
695
|
+
// If there's a string, then get the length of the digits
|
696
|
+
// Otherwise return the selected month with 0index compensation.
|
697
|
+
return string ? _.digits( string ) : dateObject.month + 1
|
698
|
+
},
|
699
|
+
mm: function( string, dateObject ) {
|
700
|
+
|
701
|
+
// If there's a string, then the length is always 2.
|
702
|
+
// Otherwise return the selected month with 0index and leading zero.
|
703
|
+
return string ? 2 : _.lead( dateObject.month + 1 )
|
704
|
+
},
|
705
|
+
mmm: function( string, dateObject ) {
|
706
|
+
|
707
|
+
var collection = this.settings.monthsShort
|
708
|
+
|
709
|
+
// If there's a string, get length of the relevant month from the short
|
710
|
+
// months collection. Otherwise return the selected month from that collection.
|
711
|
+
return string ? getWordLengthFromCollection( string, collection, dateObject ) : collection[ dateObject.month ]
|
712
|
+
},
|
713
|
+
mmmm: function( string, dateObject ) {
|
714
|
+
|
715
|
+
var collection = this.settings.monthsFull
|
716
|
+
|
717
|
+
// If there's a string, get length of the relevant month from the full
|
718
|
+
// months collection. Otherwise return the selected month from that collection.
|
719
|
+
return string ? getWordLengthFromCollection( string, collection, dateObject ) : collection[ dateObject.month ]
|
720
|
+
},
|
721
|
+
yy: function( string, dateObject ) {
|
722
|
+
|
723
|
+
// If there's a string, then the length is always 2.
|
724
|
+
// Otherwise return the selected year by slicing out the first 2 digits.
|
725
|
+
return string ? 2 : ( '' + dateObject.year ).slice( 2 )
|
726
|
+
},
|
727
|
+
yyyy: function( string, dateObject ) {
|
728
|
+
|
729
|
+
// If there's a string, then the length is always 4.
|
730
|
+
// Otherwise return the selected year.
|
731
|
+
return string ? 4 : dateObject.year
|
732
|
+
},
|
733
|
+
|
734
|
+
// Create an array by splitting the formatting string passed.
|
735
|
+
toArray: function( formatString ) { return formatString.split( /(d{1,4}|m{1,4}|y{4}|yy|!.)/g ) },
|
736
|
+
|
737
|
+
// Format an object into a string using the formatting options.
|
738
|
+
toString: function ( formatString, itemObject ) {
|
739
|
+
var calendar = this
|
740
|
+
return calendar.formats.toArray( formatString ).map( function( label ) {
|
741
|
+
return _.trigger( calendar.formats[ label ], calendar, [ 0, itemObject ] ) || label.replace( /^!/, '' )
|
742
|
+
}).join( '' )
|
743
|
+
}
|
744
|
+
}
|
745
|
+
})() //DatePicker.prototype.formats
|
746
|
+
|
747
|
+
|
748
|
+
|
749
|
+
|
750
|
+
/**
|
751
|
+
* Check if two date units are the exact.
|
752
|
+
*/
|
753
|
+
DatePicker.prototype.isDateExact = function( one, two ) {
|
754
|
+
|
755
|
+
var calendar = this
|
756
|
+
|
757
|
+
// When we’re working with weekdays, do a direct comparison.
|
758
|
+
if (
|
759
|
+
( _.isInteger( one ) && _.isInteger( two ) ) ||
|
760
|
+
( typeof one == 'boolean' && typeof two == 'boolean' )
|
761
|
+
) {
|
762
|
+
return one === two
|
763
|
+
}
|
764
|
+
|
765
|
+
// When we’re working with date representations, compare the “pick” value.
|
766
|
+
if (
|
767
|
+
( _.isDate( one ) || $.isArray( one ) ) &&
|
768
|
+
( _.isDate( two ) || $.isArray( two ) )
|
769
|
+
) {
|
770
|
+
return calendar.create( one ).pick === calendar.create( two ).pick
|
771
|
+
}
|
772
|
+
|
773
|
+
// When we’re working with range objects, compare the “from” and “to”.
|
774
|
+
if ( $.isPlainObject( one ) && $.isPlainObject( two ) ) {
|
775
|
+
return calendar.isDateExact( one.from, two.from ) && calendar.isDateExact( one.to, two.to )
|
776
|
+
}
|
777
|
+
|
778
|
+
return false
|
779
|
+
}
|
780
|
+
|
781
|
+
|
782
|
+
/**
|
783
|
+
* Check if two date units overlap.
|
784
|
+
*/
|
785
|
+
DatePicker.prototype.isDateOverlap = function( one, two ) {
|
786
|
+
|
787
|
+
var calendar = this,
|
788
|
+
firstDay = calendar.settings.firstDay ? 1 : 0
|
789
|
+
|
790
|
+
// When we’re working with a weekday index, compare the days.
|
791
|
+
if ( _.isInteger( one ) && ( _.isDate( two ) || $.isArray( two ) ) ) {
|
792
|
+
one = one % 7 + firstDay
|
793
|
+
return one === calendar.create( two ).day + 1
|
794
|
+
}
|
795
|
+
if ( _.isInteger( two ) && ( _.isDate( one ) || $.isArray( one ) ) ) {
|
796
|
+
two = two % 7 + firstDay
|
797
|
+
return two === calendar.create( one ).day + 1
|
798
|
+
}
|
799
|
+
|
800
|
+
// When we’re working with range objects, check if the ranges overlap.
|
801
|
+
if ( $.isPlainObject( one ) && $.isPlainObject( two ) ) {
|
802
|
+
return calendar.overlapRanges( one, two )
|
803
|
+
}
|
804
|
+
|
805
|
+
return false
|
806
|
+
}
|
807
|
+
|
808
|
+
|
809
|
+
/**
|
810
|
+
* Flip the “enabled” state.
|
811
|
+
*/
|
812
|
+
DatePicker.prototype.flipEnable = function(val) {
|
813
|
+
var itemObject = this.item
|
814
|
+
itemObject.enable = val || (itemObject.enable == -1 ? 1 : -1)
|
815
|
+
}
|
816
|
+
|
817
|
+
|
818
|
+
/**
|
819
|
+
* Mark a collection of dates as “disabled”.
|
820
|
+
*/
|
821
|
+
DatePicker.prototype.deactivate = function( type, datesToDisable ) {
|
822
|
+
|
823
|
+
var calendar = this,
|
824
|
+
disabledItems = calendar.item.disable.slice(0)
|
825
|
+
|
826
|
+
|
827
|
+
// If we’re flipping, that’s all we need to do.
|
828
|
+
if ( datesToDisable == 'flip' ) {
|
829
|
+
calendar.flipEnable()
|
830
|
+
}
|
831
|
+
|
832
|
+
else if ( datesToDisable === false ) {
|
833
|
+
calendar.flipEnable(1)
|
834
|
+
disabledItems = []
|
835
|
+
}
|
836
|
+
|
837
|
+
else if ( datesToDisable === true ) {
|
838
|
+
calendar.flipEnable(-1)
|
839
|
+
disabledItems = []
|
840
|
+
}
|
841
|
+
|
842
|
+
// Otherwise go through the dates to disable.
|
843
|
+
else {
|
844
|
+
|
845
|
+
datesToDisable.map(function( unitToDisable ) {
|
846
|
+
|
847
|
+
var matchFound
|
848
|
+
|
849
|
+
// When we have disabled items, check for matches.
|
850
|
+
// If something is matched, immediately break out.
|
851
|
+
for ( var index = 0; index < disabledItems.length; index += 1 ) {
|
852
|
+
if ( calendar.isDateExact( unitToDisable, disabledItems[index] ) ) {
|
853
|
+
matchFound = true
|
854
|
+
break
|
855
|
+
}
|
856
|
+
}
|
857
|
+
|
858
|
+
// If nothing was found, add the validated unit to the collection.
|
859
|
+
if ( !matchFound ) {
|
860
|
+
if (
|
861
|
+
_.isInteger( unitToDisable ) ||
|
862
|
+
_.isDate( unitToDisable ) ||
|
863
|
+
$.isArray( unitToDisable ) ||
|
864
|
+
( $.isPlainObject( unitToDisable ) && unitToDisable.from && unitToDisable.to )
|
865
|
+
) {
|
866
|
+
disabledItems.push( unitToDisable )
|
867
|
+
}
|
868
|
+
}
|
869
|
+
})
|
870
|
+
}
|
871
|
+
|
872
|
+
// Return the updated collection.
|
873
|
+
return disabledItems
|
874
|
+
} //DatePicker.prototype.deactivate
|
875
|
+
|
876
|
+
|
877
|
+
/**
|
878
|
+
* Mark a collection of dates as “enabled”.
|
879
|
+
*/
|
880
|
+
DatePicker.prototype.activate = function( type, datesToEnable ) {
|
881
|
+
|
882
|
+
var calendar = this,
|
883
|
+
disabledItems = calendar.item.disable,
|
884
|
+
disabledItemsCount = disabledItems.length
|
885
|
+
|
886
|
+
// If we’re flipping, that’s all we need to do.
|
887
|
+
if ( datesToEnable == 'flip' ) {
|
888
|
+
calendar.flipEnable()
|
889
|
+
}
|
890
|
+
|
891
|
+
else if ( datesToEnable === true ) {
|
892
|
+
calendar.flipEnable(1)
|
893
|
+
disabledItems = []
|
894
|
+
}
|
895
|
+
|
896
|
+
else if ( datesToEnable === false ) {
|
897
|
+
calendar.flipEnable(-1)
|
898
|
+
disabledItems = []
|
899
|
+
}
|
900
|
+
|
901
|
+
// Otherwise go through the disabled dates.
|
902
|
+
else {
|
903
|
+
|
904
|
+
datesToEnable.map(function( unitToEnable ) {
|
905
|
+
|
906
|
+
var matchFound,
|
907
|
+
disabledUnit,
|
908
|
+
index,
|
909
|
+
isExactRange
|
910
|
+
|
911
|
+
// Go through the disabled items and try to find a match.
|
912
|
+
for ( index = 0; index < disabledItemsCount; index += 1 ) {
|
913
|
+
|
914
|
+
disabledUnit = disabledItems[index]
|
915
|
+
|
916
|
+
// When an exact match is found, remove it from the collection.
|
917
|
+
if ( calendar.isDateExact( disabledUnit, unitToEnable ) ) {
|
918
|
+
matchFound = disabledItems[index] = null
|
919
|
+
isExactRange = true
|
920
|
+
break
|
921
|
+
}
|
922
|
+
|
923
|
+
// When an overlapped match is found, add the “inverted” state to it.
|
924
|
+
else if ( calendar.isDateOverlap( disabledUnit, unitToEnable ) ) {
|
925
|
+
if ( $.isPlainObject( unitToEnable ) ) {
|
926
|
+
unitToEnable.inverted = true
|
927
|
+
matchFound = unitToEnable
|
928
|
+
}
|
929
|
+
else if ( $.isArray( unitToEnable ) ) {
|
930
|
+
matchFound = unitToEnable
|
931
|
+
if ( !matchFound[3] ) matchFound.push( 'inverted' )
|
932
|
+
}
|
933
|
+
else if ( _.isDate( unitToEnable ) ) {
|
934
|
+
matchFound = [ unitToEnable.getFullYear(), unitToEnable.getMonth(), unitToEnable.getDate(), 'inverted' ]
|
935
|
+
}
|
936
|
+
break
|
937
|
+
}
|
938
|
+
}
|
939
|
+
|
940
|
+
// If a match was found, remove a previous duplicate entry.
|
941
|
+
if ( matchFound ) for ( index = 0; index < disabledItemsCount; index += 1 ) {
|
942
|
+
if ( calendar.isDateExact( disabledItems[index], unitToEnable ) ) {
|
943
|
+
disabledItems[index] = null
|
944
|
+
break
|
945
|
+
}
|
946
|
+
}
|
947
|
+
|
948
|
+
// In the event that we’re dealing with an exact range of dates,
|
949
|
+
// make sure there are no “inverted” dates because of it.
|
950
|
+
if ( isExactRange ) for ( index = 0; index < disabledItemsCount; index += 1 ) {
|
951
|
+
if ( calendar.isDateOverlap( disabledItems[index], unitToEnable ) ) {
|
952
|
+
disabledItems[index] = null
|
953
|
+
break
|
954
|
+
}
|
955
|
+
}
|
956
|
+
|
957
|
+
// If something is still matched, add it into the collection.
|
958
|
+
if ( matchFound ) {
|
959
|
+
disabledItems.push( matchFound )
|
960
|
+
}
|
961
|
+
})
|
962
|
+
}
|
963
|
+
|
964
|
+
// Return the updated collection.
|
965
|
+
return disabledItems.filter(function( val ) { return val != null })
|
966
|
+
} //DatePicker.prototype.activate
|
967
|
+
|
968
|
+
|
969
|
+
/**
|
970
|
+
* Create a string for the nodes in the picker.
|
971
|
+
*/
|
972
|
+
DatePicker.prototype.nodes = function( isOpen ) {
|
973
|
+
|
974
|
+
var
|
975
|
+
calendar = this,
|
976
|
+
settings = calendar.settings,
|
977
|
+
calendarItem = calendar.item,
|
978
|
+
nowObject = calendarItem.now,
|
979
|
+
selectedObject = calendarItem.select,
|
980
|
+
highlightedObject = calendarItem.highlight,
|
981
|
+
viewsetObject = calendarItem.view,
|
982
|
+
disabledCollection = calendarItem.disable,
|
983
|
+
minLimitObject = calendarItem.min,
|
984
|
+
maxLimitObject = calendarItem.max,
|
985
|
+
|
986
|
+
|
987
|
+
// Create the calendar table head using a copy of weekday labels collection.
|
988
|
+
// * We do a copy so we don't mutate the original array.
|
989
|
+
tableHead = (function( collection, fullCollection ) {
|
990
|
+
|
991
|
+
// If the first day should be Monday, move Sunday to the end.
|
992
|
+
if ( settings.firstDay ) {
|
993
|
+
collection.push( collection.shift() )
|
994
|
+
fullCollection.push( fullCollection.shift() )
|
995
|
+
}
|
996
|
+
|
997
|
+
// Create and return the table head group.
|
998
|
+
return _.node(
|
999
|
+
'thead',
|
1000
|
+
_.node(
|
1001
|
+
'tr',
|
1002
|
+
_.group({
|
1003
|
+
min: 0,
|
1004
|
+
max: DAYS_IN_WEEK - 1,
|
1005
|
+
i: 1,
|
1006
|
+
node: 'th',
|
1007
|
+
item: function( counter ) {
|
1008
|
+
return [
|
1009
|
+
collection[ counter ],
|
1010
|
+
settings.klass.weekdays,
|
1011
|
+
'scope=col title="' + fullCollection[ counter ] + '"'
|
1012
|
+
]
|
1013
|
+
}
|
1014
|
+
})
|
1015
|
+
)
|
1016
|
+
) //endreturn
|
1017
|
+
})( ( settings.showWeekdaysFull ? settings.weekdaysFull : settings.weekdaysShort ).slice( 0 ), settings.weekdaysFull.slice( 0 ) ), //tableHead
|
1018
|
+
|
1019
|
+
|
1020
|
+
// Create the nav for next/prev month.
|
1021
|
+
createMonthNav = function( next ) {
|
1022
|
+
|
1023
|
+
// Otherwise, return the created month tag.
|
1024
|
+
return _.node(
|
1025
|
+
'div',
|
1026
|
+
' ',
|
1027
|
+
settings.klass[ 'nav' + ( next ? 'Next' : 'Prev' ) ] + (
|
1028
|
+
|
1029
|
+
// If the focused month is outside the range, disabled the button.
|
1030
|
+
( next && viewsetObject.year >= maxLimitObject.year && viewsetObject.month >= maxLimitObject.month ) ||
|
1031
|
+
( !next && viewsetObject.year <= minLimitObject.year && viewsetObject.month <= minLimitObject.month ) ?
|
1032
|
+
' ' + settings.klass.navDisabled : ''
|
1033
|
+
),
|
1034
|
+
'data-nav=' + ( next || -1 ) + ' ' +
|
1035
|
+
_.ariaAttr({
|
1036
|
+
role: 'button',
|
1037
|
+
controls: calendar.$node[0].id + '_table'
|
1038
|
+
}) + ' ' +
|
1039
|
+
'title="' + (next ? settings.labelMonthNext : settings.labelMonthPrev ) + '"'
|
1040
|
+
) //endreturn
|
1041
|
+
}, //createMonthNav
|
1042
|
+
|
1043
|
+
|
1044
|
+
// Create the month label.
|
1045
|
+
createMonthLabel = function() {
|
1046
|
+
|
1047
|
+
var monthsCollection = settings.showMonthsShort ? settings.monthsShort : settings.monthsFull
|
1048
|
+
|
1049
|
+
// If there are months to select, add a dropdown menu.
|
1050
|
+
if ( settings.selectMonths ) {
|
1051
|
+
|
1052
|
+
return _.node( 'select',
|
1053
|
+
_.group({
|
1054
|
+
min: 0,
|
1055
|
+
max: 11,
|
1056
|
+
i: 1,
|
1057
|
+
node: 'option',
|
1058
|
+
item: function( loopedMonth ) {
|
1059
|
+
|
1060
|
+
return [
|
1061
|
+
|
1062
|
+
// The looped month and no classes.
|
1063
|
+
monthsCollection[ loopedMonth ], 0,
|
1064
|
+
|
1065
|
+
// Set the value and selected index.
|
1066
|
+
'value=' + loopedMonth +
|
1067
|
+
( viewsetObject.month == loopedMonth ? ' selected' : '' ) +
|
1068
|
+
(
|
1069
|
+
(
|
1070
|
+
( viewsetObject.year == minLimitObject.year && loopedMonth < minLimitObject.month ) ||
|
1071
|
+
( viewsetObject.year == maxLimitObject.year && loopedMonth > maxLimitObject.month )
|
1072
|
+
) ?
|
1073
|
+
' disabled' : ''
|
1074
|
+
)
|
1075
|
+
]
|
1076
|
+
}
|
1077
|
+
}),
|
1078
|
+
settings.klass.selectMonth,
|
1079
|
+
( isOpen ? '' : 'disabled' ) + ' ' +
|
1080
|
+
_.ariaAttr({ controls: calendar.$node[0].id + '_table' }) + ' ' +
|
1081
|
+
'title="' + settings.labelMonthSelect + '"'
|
1082
|
+
)
|
1083
|
+
}
|
1084
|
+
|
1085
|
+
// If there's a need for a month selector
|
1086
|
+
return _.node( 'div', monthsCollection[ viewsetObject.month ], settings.klass.month )
|
1087
|
+
}, //createMonthLabel
|
1088
|
+
|
1089
|
+
|
1090
|
+
// Create the year label.
|
1091
|
+
createYearLabel = function() {
|
1092
|
+
|
1093
|
+
var focusedYear = viewsetObject.year,
|
1094
|
+
|
1095
|
+
// If years selector is set to a literal "true", set it to 5. Otherwise
|
1096
|
+
// divide in half to get half before and half after focused year.
|
1097
|
+
numberYears = settings.selectYears === true ? 5 : ~~( settings.selectYears / 2 )
|
1098
|
+
|
1099
|
+
// If there are years to select, add a dropdown menu.
|
1100
|
+
if ( numberYears ) {
|
1101
|
+
|
1102
|
+
var
|
1103
|
+
minYear = minLimitObject.year,
|
1104
|
+
maxYear = maxLimitObject.year,
|
1105
|
+
lowestYear = focusedYear - numberYears,
|
1106
|
+
highestYear = focusedYear + numberYears
|
1107
|
+
|
1108
|
+
// If the min year is greater than the lowest year, increase the highest year
|
1109
|
+
// by the difference and set the lowest year to the min year.
|
1110
|
+
if ( minYear > lowestYear ) {
|
1111
|
+
highestYear += minYear - lowestYear
|
1112
|
+
lowestYear = minYear
|
1113
|
+
}
|
1114
|
+
|
1115
|
+
// If the max year is less than the highest year, decrease the lowest year
|
1116
|
+
// by the lower of the two: available and needed years. Then set the
|
1117
|
+
// highest year to the max year.
|
1118
|
+
if ( maxYear < highestYear ) {
|
1119
|
+
|
1120
|
+
var availableYears = lowestYear - minYear,
|
1121
|
+
neededYears = highestYear - maxYear
|
1122
|
+
|
1123
|
+
lowestYear -= availableYears > neededYears ? neededYears : availableYears
|
1124
|
+
highestYear = maxYear
|
1125
|
+
}
|
1126
|
+
|
1127
|
+
return _.node( 'select',
|
1128
|
+
_.group({
|
1129
|
+
min: lowestYear,
|
1130
|
+
max: highestYear,
|
1131
|
+
i: 1,
|
1132
|
+
node: 'option',
|
1133
|
+
item: function( loopedYear ) {
|
1134
|
+
return [
|
1135
|
+
|
1136
|
+
// The looped year and no classes.
|
1137
|
+
loopedYear, 0,
|
1138
|
+
|
1139
|
+
// Set the value and selected index.
|
1140
|
+
'value=' + loopedYear + ( focusedYear == loopedYear ? ' selected' : '' )
|
1141
|
+
]
|
1142
|
+
}
|
1143
|
+
}),
|
1144
|
+
settings.klass.selectYear,
|
1145
|
+
( isOpen ? '' : 'disabled' ) + ' ' + _.ariaAttr({ controls: calendar.$node[0].id + '_table' }) + ' ' +
|
1146
|
+
'title="' + settings.labelYearSelect + '"'
|
1147
|
+
)
|
1148
|
+
}
|
1149
|
+
|
1150
|
+
// Otherwise just return the year focused
|
1151
|
+
return _.node( 'div', focusedYear, settings.klass.year )
|
1152
|
+
} //createYearLabel
|
1153
|
+
|
1154
|
+
|
1155
|
+
// Create and return the entire calendar.
|
1156
|
+
return _.node(
|
1157
|
+
'div',
|
1158
|
+
( settings.selectYears ? createYearLabel() + createMonthLabel() : createMonthLabel() + createYearLabel() ) +
|
1159
|
+
createMonthNav() + createMonthNav( 1 ),
|
1160
|
+
settings.klass.header
|
1161
|
+
) + _.node(
|
1162
|
+
'table',
|
1163
|
+
tableHead +
|
1164
|
+
_.node(
|
1165
|
+
'tbody',
|
1166
|
+
_.group({
|
1167
|
+
min: 0,
|
1168
|
+
max: WEEKS_IN_CALENDAR - 1,
|
1169
|
+
i: 1,
|
1170
|
+
node: 'tr',
|
1171
|
+
item: function( rowCounter ) {
|
1172
|
+
|
1173
|
+
// If Monday is the first day and the month starts on Sunday, shift the date back a week.
|
1174
|
+
var shiftDateBy = settings.firstDay && calendar.create([ viewsetObject.year, viewsetObject.month, 1 ]).day === 0 ? -7 : 0
|
1175
|
+
|
1176
|
+
return [
|
1177
|
+
_.group({
|
1178
|
+
min: DAYS_IN_WEEK * rowCounter - viewsetObject.day + shiftDateBy + 1, // Add 1 for weekday 0index
|
1179
|
+
max: function() {
|
1180
|
+
return this.min + DAYS_IN_WEEK - 1
|
1181
|
+
},
|
1182
|
+
i: 1,
|
1183
|
+
node: 'td',
|
1184
|
+
item: function( targetDate ) {
|
1185
|
+
|
1186
|
+
// Convert the time date from a relative date to a target date.
|
1187
|
+
targetDate = calendar.create([ viewsetObject.year, viewsetObject.month, targetDate + ( settings.firstDay ? 1 : 0 ) ])
|
1188
|
+
|
1189
|
+
var isSelected = selectedObject && selectedObject.pick == targetDate.pick,
|
1190
|
+
isHighlighted = highlightedObject && highlightedObject.pick == targetDate.pick,
|
1191
|
+
isDisabled = disabledCollection && calendar.disabled( targetDate ) || targetDate.pick < minLimitObject.pick || targetDate.pick > maxLimitObject.pick,
|
1192
|
+
formattedDate = _.trigger( calendar.formats.toString, calendar, [ settings.format, targetDate ] )
|
1193
|
+
|
1194
|
+
return [
|
1195
|
+
_.node(
|
1196
|
+
'div',
|
1197
|
+
targetDate.date,
|
1198
|
+
(function( klasses ) {
|
1199
|
+
|
1200
|
+
// Add the `infocus` or `outfocus` classes based on month in view.
|
1201
|
+
klasses.push( viewsetObject.month == targetDate.month ? settings.klass.infocus : settings.klass.outfocus )
|
1202
|
+
|
1203
|
+
// Add the `today` class if needed.
|
1204
|
+
if ( nowObject.pick == targetDate.pick ) {
|
1205
|
+
klasses.push( settings.klass.now )
|
1206
|
+
}
|
1207
|
+
|
1208
|
+
// Add the `selected` class if something's selected and the time matches.
|
1209
|
+
if ( isSelected ) {
|
1210
|
+
klasses.push( settings.klass.selected )
|
1211
|
+
}
|
1212
|
+
|
1213
|
+
// Add the `highlighted` class if something's highlighted and the time matches.
|
1214
|
+
if ( isHighlighted ) {
|
1215
|
+
klasses.push( settings.klass.highlighted )
|
1216
|
+
}
|
1217
|
+
|
1218
|
+
// Add the `disabled` class if something's disabled and the object matches.
|
1219
|
+
if ( isDisabled ) {
|
1220
|
+
klasses.push( settings.klass.disabled )
|
1221
|
+
}
|
1222
|
+
|
1223
|
+
return klasses.join( ' ' )
|
1224
|
+
})([ settings.klass.day ]),
|
1225
|
+
'data-pick=' + targetDate.pick + ' ' + _.ariaAttr({
|
1226
|
+
role: 'gridcell',
|
1227
|
+
label: formattedDate,
|
1228
|
+
selected: isSelected && calendar.$node.val() === formattedDate ? true : null,
|
1229
|
+
activedescendant: isHighlighted ? true : null,
|
1230
|
+
disabled: isDisabled ? true : null
|
1231
|
+
})
|
1232
|
+
),
|
1233
|
+
'',
|
1234
|
+
_.ariaAttr({ role: 'presentation' })
|
1235
|
+
] //endreturn
|
1236
|
+
}
|
1237
|
+
})
|
1238
|
+
] //endreturn
|
1239
|
+
}
|
1240
|
+
})
|
1241
|
+
),
|
1242
|
+
settings.klass.table,
|
1243
|
+
'id="' + calendar.$node[0].id + '_table' + '" ' + _.ariaAttr({
|
1244
|
+
role: 'grid',
|
1245
|
+
controls: calendar.$node[0].id,
|
1246
|
+
readonly: true
|
1247
|
+
})
|
1248
|
+
) +
|
1249
|
+
|
1250
|
+
// * For Firefox forms to submit, make sure to set the buttons’ `type` attributes as “button”.
|
1251
|
+
_.node(
|
1252
|
+
'div',
|
1253
|
+
_.node( 'button', settings.today, settings.klass.buttonToday,
|
1254
|
+
'type=button data-pick=' + nowObject.pick +
|
1255
|
+
( isOpen && !calendar.disabled(nowObject) ? '' : ' disabled' ) + ' ' +
|
1256
|
+
_.ariaAttr({ controls: calendar.$node[0].id }) ) +
|
1257
|
+
_.node( 'button', settings.clear, settings.klass.buttonClear,
|
1258
|
+
'type=button data-clear=1' +
|
1259
|
+
( isOpen ? '' : ' disabled' ) + ' ' +
|
1260
|
+
_.ariaAttr({ controls: calendar.$node[0].id }) ) +
|
1261
|
+
_.node('button', settings.close, settings.klass.buttonClose,
|
1262
|
+
'type=button data-close=true ' +
|
1263
|
+
( isOpen ? '' : ' disabled' ) + ' ' +
|
1264
|
+
_.ariaAttr({ controls: calendar.$node[0].id }) ),
|
1265
|
+
settings.klass.footer
|
1266
|
+
) //endreturn
|
1267
|
+
} //DatePicker.prototype.nodes
|
1268
|
+
|
1269
|
+
|
1270
|
+
|
1271
|
+
|
1272
|
+
/**
|
1273
|
+
* The date picker defaults.
|
1274
|
+
*/
|
1275
|
+
DatePicker.defaults = (function( prefix ) {
|
1276
|
+
|
1277
|
+
return {
|
1278
|
+
|
1279
|
+
// The title label to use for the month nav buttons
|
1280
|
+
labelMonthNext: 'Next month',
|
1281
|
+
labelMonthPrev: 'Previous month',
|
1282
|
+
|
1283
|
+
// The title label to use for the dropdown selectors
|
1284
|
+
labelMonthSelect: 'Select a month',
|
1285
|
+
labelYearSelect: 'Select a year',
|
1286
|
+
|
1287
|
+
// Months and weekdays
|
1288
|
+
monthsFull: [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ],
|
1289
|
+
monthsShort: [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ],
|
1290
|
+
weekdaysFull: [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' ],
|
1291
|
+
weekdaysShort: [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ],
|
1292
|
+
|
1293
|
+
// Today and clear
|
1294
|
+
today: 'Today',
|
1295
|
+
clear: 'Clear',
|
1296
|
+
close: 'Close',
|
1297
|
+
|
1298
|
+
// Picker close behavior
|
1299
|
+
closeOnSelect: true,
|
1300
|
+
closeOnClear: true,
|
1301
|
+
|
1302
|
+
// The format to show on the `input` element
|
1303
|
+
format: 'd mmmm, yyyy',
|
1304
|
+
|
1305
|
+
// Classes
|
1306
|
+
klass: {
|
1307
|
+
|
1308
|
+
table: prefix + 'table',
|
1309
|
+
|
1310
|
+
header: prefix + 'header',
|
1311
|
+
|
1312
|
+
navPrev: prefix + 'nav--prev',
|
1313
|
+
navNext: prefix + 'nav--next',
|
1314
|
+
navDisabled: prefix + 'nav--disabled',
|
1315
|
+
|
1316
|
+
month: prefix + 'month',
|
1317
|
+
year: prefix + 'year',
|
1318
|
+
|
1319
|
+
selectMonth: prefix + 'select--month',
|
1320
|
+
selectYear: prefix + 'select--year',
|
1321
|
+
|
1322
|
+
weekdays: prefix + 'weekday',
|
1323
|
+
|
1324
|
+
day: prefix + 'day',
|
1325
|
+
disabled: prefix + 'day--disabled',
|
1326
|
+
selected: prefix + 'day--selected',
|
1327
|
+
highlighted: prefix + 'day--highlighted',
|
1328
|
+
now: prefix + 'day--today',
|
1329
|
+
infocus: prefix + 'day--infocus',
|
1330
|
+
outfocus: prefix + 'day--outfocus',
|
1331
|
+
|
1332
|
+
footer: prefix + 'footer',
|
1333
|
+
|
1334
|
+
buttonClear: prefix + 'button--clear',
|
1335
|
+
buttonToday: prefix + 'button--today',
|
1336
|
+
buttonClose: prefix + 'button--close'
|
1337
|
+
}
|
1338
|
+
}
|
1339
|
+
})( Picker.klasses().picker + '__' )
|
1340
|
+
|
1341
|
+
|
1342
|
+
|
1343
|
+
|
1344
|
+
|
1345
|
+
/**
|
1346
|
+
* Extend the picker to add the date picker.
|
1347
|
+
*/
|
1348
|
+
Picker.extend( 'pickadate', DatePicker )
|
1349
|
+
|
1350
|
+
|
1351
|
+
}));
|
1352
|
+
|
1353
|
+
|
1354
|
+
|