pikaday-gem 1.0.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.
- data/MIT-LICENSE +20 -0
- data/README.md +53 -0
- data/Rakefile +115 -0
- data/lib/pikaday-gem.rb +6 -0
- data/lib/pikaday-gem/version.rb +3 -0
- data/vendor/assets/javascripts/1.0.0/pikaday.js +816 -0
- data/vendor/assets/javascripts/pikaday.js +816 -0
- data/vendor/assets/stylesheets/1.0.0/pikaday.css +170 -0
- data/vendor/assets/stylesheets/pikaday.css +170 -0
- metadata +143 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2013 UC Berkeley - ETS
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# Pikaday Gem
|
2
|
+
[](http://badge.fury.io/rb/pikaday-gem) [](https://gemnasium.com/ets-berkeley-edu/pikaday-gem) [](https://codeclimate.com/github/ets-berkeley-edu/pikaday-gem)
|
3
|
+
|
4
|
+
[Pikaday datepicker][pikaday] as a Ruby gem.
|
5
|
+
|
6
|
+
## Getting Started
|
7
|
+
|
8
|
+
Add the gem to your Gemfile:
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
gem "pikaday-gem"
|
12
|
+
```
|
13
|
+
|
14
|
+
And run
|
15
|
+
|
16
|
+
```bash
|
17
|
+
bundle install
|
18
|
+
```
|
19
|
+
in the terminal to download the resources.
|
20
|
+
|
21
|
+
### Adding the files to your projects
|
22
|
+
|
23
|
+
In order for the files to load, you'll need to do add them.
|
24
|
+
|
25
|
+
`application.js`:
|
26
|
+
|
27
|
+
```javascript
|
28
|
+
//= require pikaday
|
29
|
+
```
|
30
|
+
|
31
|
+
`application.css`:
|
32
|
+
|
33
|
+
```css
|
34
|
+
*= require pikaday
|
35
|
+
```
|
36
|
+
|
37
|
+
and you should be good to go.
|
38
|
+
|
39
|
+
## Updating this plug-in
|
40
|
+
|
41
|
+
If you would like to update this gem you should take the following steps:
|
42
|
+
|
43
|
+
1. `rake download VERSION=X.X.X`. If you don't specify the version, it will get the latest one.
|
44
|
+
1. `rake tag VERSION=X.X.X` will tag the version you've specified as the standard version.
|
45
|
+
1. Make a Pull request
|
46
|
+
|
47
|
+
Then the maintainer of the gem will need to do the following steps:
|
48
|
+
|
49
|
+
1. Update the version [lib/pikaday-gem/version.rb](lib/pikaday-gem/version.rb)
|
50
|
+
1. Run ``gem build pikaday-gem.gemspec`` to package the gem
|
51
|
+
1. Once satisfied, push the gem up to RubyGems.org with ``gem push pikaday-gem-<VERSION>.gem``
|
52
|
+
|
53
|
+
[pikaday]: https://github.com/dbushell/Pikaday
|
data/Rakefile
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
+
end
|
7
|
+
|
8
|
+
Bundler::GemHelper.install_tasks
|
9
|
+
|
10
|
+
require 'rake'
|
11
|
+
require 'open-uri'
|
12
|
+
require 'json'
|
13
|
+
|
14
|
+
dir_assets = 'vendor/assets/'
|
15
|
+
dir_js = dir_assets + 'javascripts'
|
16
|
+
dir_css = dir_assets + 'stylesheets'
|
17
|
+
|
18
|
+
desc 'Downloads the pikaday CSS and JavaScript files from GitHub'
|
19
|
+
task :download do |t|
|
20
|
+
|
21
|
+
def create_dir dir, version
|
22
|
+
dir_name = File.join(dir, version)
|
23
|
+
Dir.mkdir(dir_name) unless Dir.exist?(dir_name)
|
24
|
+
end
|
25
|
+
|
26
|
+
def download_file url, dir, filename, version
|
27
|
+
Dir.chdir(File.join(dir, version)) do
|
28
|
+
if File.exists?(filename)
|
29
|
+
puts " #{dir + '/' + version + '/' + filename} already exists"
|
30
|
+
next
|
31
|
+
end
|
32
|
+
puts " #{url}"
|
33
|
+
open(filename, "w") { |file| file.write(open(url).read)}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Specify which version you want
|
38
|
+
version = ENV['VERSION']
|
39
|
+
version ||= 'latest'
|
40
|
+
puts "Target version: #{version.chomp('/')}"
|
41
|
+
|
42
|
+
# Get the different versions
|
43
|
+
tags_url = 'https://api.github.com/repos/dbushell/Pikaday/tags'
|
44
|
+
result = JSON.parse(open(tags_url).read)
|
45
|
+
versions = result.map { |item| item['name'] }
|
46
|
+
|
47
|
+
puts "Available versions: #{versions.inspect}"
|
48
|
+
|
49
|
+
# Figuring out which version to get
|
50
|
+
if versions.include? version
|
51
|
+
get_version = version
|
52
|
+
else
|
53
|
+
get_version = versions.first
|
54
|
+
|
55
|
+
if !(versions.include? version) && version != 'latest'
|
56
|
+
puts "Warning: The version you've specified: '#{version}' wasn't found, using the latest version instead: '#{get_version}'"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Get the right commit
|
61
|
+
commit = result.select { |item| item['name'] == get_version }.first['commit']['sha']
|
62
|
+
puts "We'll use the following commit to get the files: #{commit}"
|
63
|
+
|
64
|
+
# Creating the necessary directories
|
65
|
+
create_dir dir_js, get_version
|
66
|
+
create_dir dir_css, get_version
|
67
|
+
|
68
|
+
# Download the right files
|
69
|
+
url_root = 'https://raw.github.com/dbushell/Pikaday/' + commit + '/'
|
70
|
+
url_js = url_root + 'pikaday.js'
|
71
|
+
url_css = url_root + '/css/pikaday.css'
|
72
|
+
|
73
|
+
puts "Downloading... \n"
|
74
|
+
download_file url_js, dir_js, 'pikaday.js', get_version
|
75
|
+
download_file url_css, dir_css, 'pikaday.css', get_version
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
desc 'Tag the default file versions for asset helpers'
|
80
|
+
task :tag do |t|
|
81
|
+
Rake::Task['tag_default'].invoke
|
82
|
+
end
|
83
|
+
|
84
|
+
task :tag_default do |t|
|
85
|
+
|
86
|
+
def copy_files dir, version
|
87
|
+
Dir.entries(File.join(dir, version)).each do |file|
|
88
|
+
file_source = File.join(dir, version, file)
|
89
|
+
file_destination = File.join(dir, file)
|
90
|
+
if File.file?(file_source)
|
91
|
+
FileUtils.cp file_source, file_destination, { verbose: true }
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
version = ENV['VERSION']
|
97
|
+
version ||= 'latest'
|
98
|
+
|
99
|
+
puts "Target version: #{version.chomp('/')}"
|
100
|
+
|
101
|
+
Dir.chdir(dir_js) do
|
102
|
+
version_directories = Dir.glob("*").select { |fn| File.directory?(fn) }.sort.reverse
|
103
|
+
|
104
|
+
puts "Available versions: #{version_directories.inspect}"
|
105
|
+
if !(version_directories.include? version)
|
106
|
+
if version != 'latest'
|
107
|
+
puts "WARN: Specified version='#{version}' not found, setting to latest version: '#{version_directories.first}'"
|
108
|
+
end
|
109
|
+
version = version_directories.first
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
copy_files dir_js, version
|
114
|
+
copy_files dir_css, version
|
115
|
+
end
|
data/lib/pikaday-gem.rb
ADDED
@@ -0,0 +1,816 @@
|
|
1
|
+
/*!
|
2
|
+
* Pikaday
|
3
|
+
* Copyright © 2012 David Bushell | BSD & MIT license | http://dbushell.com/
|
4
|
+
*/
|
5
|
+
|
6
|
+
(function(window, document, undefined)
|
7
|
+
{
|
8
|
+
'use strict';
|
9
|
+
|
10
|
+
/**
|
11
|
+
* feature detection and helper functions
|
12
|
+
*/
|
13
|
+
var hasMoment = typeof window.moment === 'function',
|
14
|
+
|
15
|
+
hasEventListeners = !!window.addEventListener,
|
16
|
+
|
17
|
+
sto = window.setTimeout,
|
18
|
+
|
19
|
+
addEvent = function(el, e, callback, capture)
|
20
|
+
{
|
21
|
+
if (hasEventListeners) {
|
22
|
+
el.addEventListener(e, callback, !!capture);
|
23
|
+
} else {
|
24
|
+
el.attachEvent('on' + e, callback);
|
25
|
+
}
|
26
|
+
},
|
27
|
+
|
28
|
+
removeEvent = function(el, e, callback, capture)
|
29
|
+
{
|
30
|
+
if (hasEventListeners) {
|
31
|
+
el.removeEventListener(e, callback, !!capture);
|
32
|
+
} else {
|
33
|
+
el.detachEvent('on' + e, callback);
|
34
|
+
}
|
35
|
+
},
|
36
|
+
|
37
|
+
fireEvent = function(el, eventName, data)
|
38
|
+
{
|
39
|
+
var ev;
|
40
|
+
|
41
|
+
if (document.createEvent) {
|
42
|
+
ev = document.createEvent('HTMLEvents');
|
43
|
+
ev.initEvent(eventName, true, false);
|
44
|
+
ev = extend(ev, data);
|
45
|
+
el.dispatchEvent(ev);
|
46
|
+
} else if (document.createEventObject) {
|
47
|
+
ev = document.createEventObject();
|
48
|
+
ev = extend(ev, data);
|
49
|
+
el.fireEvent('on' + eventName, ev);
|
50
|
+
}
|
51
|
+
},
|
52
|
+
|
53
|
+
trim = function(str)
|
54
|
+
{
|
55
|
+
return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g,'');
|
56
|
+
},
|
57
|
+
|
58
|
+
hasClass = function(el, cn)
|
59
|
+
{
|
60
|
+
return (' ' + el.className + ' ').indexOf(' ' + cn + ' ') !== -1;
|
61
|
+
},
|
62
|
+
|
63
|
+
addClass = function(el, cn)
|
64
|
+
{
|
65
|
+
if (!hasClass(el, cn)) {
|
66
|
+
el.className = (el.className === '') ? cn : el.className + ' ' + cn;
|
67
|
+
}
|
68
|
+
},
|
69
|
+
|
70
|
+
removeClass = function(el, cn)
|
71
|
+
{
|
72
|
+
el.className = trim((' ' + el.className + ' ').replace(' ' + cn + ' ', ' '));
|
73
|
+
},
|
74
|
+
|
75
|
+
isArray = function(obj)
|
76
|
+
{
|
77
|
+
return (/Array/).test(Object.prototype.toString.call(obj));
|
78
|
+
},
|
79
|
+
|
80
|
+
isDate = function(obj)
|
81
|
+
{
|
82
|
+
return (/Date/).test(Object.prototype.toString.call(obj)) && !isNaN(obj.getTime());
|
83
|
+
},
|
84
|
+
|
85
|
+
isLeapYear = function(year)
|
86
|
+
{
|
87
|
+
// solution by Matti Virkkunen: http://stackoverflow.com/a/4881951
|
88
|
+
return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
|
89
|
+
},
|
90
|
+
|
91
|
+
getDaysInMonth = function(year, month)
|
92
|
+
{
|
93
|
+
return [31, isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
|
94
|
+
},
|
95
|
+
|
96
|
+
setToStartOfDay = function(date)
|
97
|
+
{
|
98
|
+
if (isDate(date)) date.setHours(0,0,0,0);
|
99
|
+
},
|
100
|
+
|
101
|
+
compareDates = function(a,b)
|
102
|
+
{
|
103
|
+
// weak date comparison (use setToStartOfDay(date) to ensure correct result)
|
104
|
+
return a.getTime() === b.getTime();
|
105
|
+
},
|
106
|
+
|
107
|
+
extend = function(to, from, overwrite)
|
108
|
+
{
|
109
|
+
var prop, hasProp;
|
110
|
+
for (prop in from) {
|
111
|
+
hasProp = to[prop] !== undefined;
|
112
|
+
if (hasProp && typeof from[prop] === 'object' && from[prop].nodeName === undefined) {
|
113
|
+
if (isDate(from[prop])) {
|
114
|
+
if (overwrite) {
|
115
|
+
to[prop] = new Date(from[prop].getTime());
|
116
|
+
}
|
117
|
+
}
|
118
|
+
else if (isArray(from[prop])) {
|
119
|
+
if (overwrite) {
|
120
|
+
to[prop] = from[prop].slice(0);
|
121
|
+
}
|
122
|
+
} else {
|
123
|
+
to[prop] = extend({}, from[prop], overwrite);
|
124
|
+
}
|
125
|
+
} else if (overwrite || !hasProp) {
|
126
|
+
to[prop] = from[prop];
|
127
|
+
}
|
128
|
+
}
|
129
|
+
return to;
|
130
|
+
},
|
131
|
+
|
132
|
+
|
133
|
+
/**
|
134
|
+
* defaults and localisation
|
135
|
+
*/
|
136
|
+
defaults = {
|
137
|
+
|
138
|
+
// bind the picker to a form field
|
139
|
+
field: null,
|
140
|
+
|
141
|
+
// automatically show/hide the picker on `field` focus (default `true` if `field` is set)
|
142
|
+
bound: undefined,
|
143
|
+
|
144
|
+
// the default output format for `.toString()` and `field` value
|
145
|
+
format: 'YYYY-MM-DD',
|
146
|
+
|
147
|
+
// the initial date to view when first opened
|
148
|
+
defaultDate: null,
|
149
|
+
|
150
|
+
// make the `defaultDate` the initial selected value
|
151
|
+
setDefaultDate: false,
|
152
|
+
|
153
|
+
// first day of week (0: Sunday, 1: Monday etc)
|
154
|
+
firstDay: 0,
|
155
|
+
|
156
|
+
// the minimum/earliest date that can be selected
|
157
|
+
minDate: null,
|
158
|
+
// the maximum/latest date that can be selected
|
159
|
+
maxDate: null,
|
160
|
+
|
161
|
+
// number of years either side, or array of upper/lower range
|
162
|
+
yearRange: 10,
|
163
|
+
|
164
|
+
// used internally (don't config outside)
|
165
|
+
minYear: 0,
|
166
|
+
maxYear: 9999,
|
167
|
+
minMonth: undefined,
|
168
|
+
maxMonth: undefined,
|
169
|
+
|
170
|
+
isRTL: false,
|
171
|
+
|
172
|
+
// how many months are visible (not implemented yet)
|
173
|
+
numberOfMonths: 1,
|
174
|
+
|
175
|
+
// internationalization
|
176
|
+
i18n: {
|
177
|
+
previousMonth : 'Previous Month',
|
178
|
+
nextMonth : 'Next Month',
|
179
|
+
months : ['January','February','March','April','May','June','July','August','September','October','November','December'],
|
180
|
+
//monthsShort : ['Jan_Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'],
|
181
|
+
weekdays : ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],
|
182
|
+
weekdaysShort : ['Sun','Mon','Tue','Wed','Thu','Fri','Sat']
|
183
|
+
},
|
184
|
+
|
185
|
+
// callback function
|
186
|
+
onSelect: null,
|
187
|
+
onOpen: null,
|
188
|
+
onClose: null,
|
189
|
+
onDraw: null
|
190
|
+
},
|
191
|
+
|
192
|
+
|
193
|
+
/**
|
194
|
+
* templating functions to abstract HTML rendering
|
195
|
+
*/
|
196
|
+
renderDayName = function(opts, day, abbr)
|
197
|
+
{
|
198
|
+
day += opts.firstDay;
|
199
|
+
while (day >= 7) {
|
200
|
+
day -= 7;
|
201
|
+
}
|
202
|
+
return abbr ? opts.i18n.weekdaysShort[day] : opts.i18n.weekdays[day];
|
203
|
+
},
|
204
|
+
|
205
|
+
renderDay = function(i, isSelected, isToday, isDisabled, isEmpty)
|
206
|
+
{
|
207
|
+
if (isEmpty) {
|
208
|
+
return '<td class="is-empty"></td>';
|
209
|
+
}
|
210
|
+
var arr = [];
|
211
|
+
if (isDisabled) {
|
212
|
+
arr.push('is-disabled');
|
213
|
+
}
|
214
|
+
if (isToday) {
|
215
|
+
arr.push('is-today');
|
216
|
+
}
|
217
|
+
if (isSelected) {
|
218
|
+
arr.push('is-selected');
|
219
|
+
}
|
220
|
+
return '<td data-day="' + i + '" class="' + arr.join(' ') + '"><button class="pika-button" type="button">' + i + '</button>' + '</td>';
|
221
|
+
},
|
222
|
+
|
223
|
+
renderRow = function(days, isRTL)
|
224
|
+
{
|
225
|
+
return '<tr>' + (isRTL ? days.reverse() : days).join('') + '</tr>';
|
226
|
+
},
|
227
|
+
|
228
|
+
renderBody = function(rows)
|
229
|
+
{
|
230
|
+
return '<tbody>' + rows.join('') + '</tbody>';
|
231
|
+
},
|
232
|
+
|
233
|
+
renderHead = function(opts)
|
234
|
+
{
|
235
|
+
var i, arr = [];
|
236
|
+
for (i = 0; i < 7; i++) {
|
237
|
+
arr.push('<th scope="col"><abbr title="' + renderDayName(opts, i) + '">' + renderDayName(opts, i, true) + '</abbr></th>');
|
238
|
+
}
|
239
|
+
return '<thead>' + (opts.isRTL ? arr.reverse() : arr).join('') + '</thead>';
|
240
|
+
},
|
241
|
+
|
242
|
+
renderTitle = function(instance)
|
243
|
+
{
|
244
|
+
var i, j, arr,
|
245
|
+
opts = instance._o,
|
246
|
+
month = instance._m,
|
247
|
+
year = instance._y,
|
248
|
+
isMinYear = year === opts.minYear,
|
249
|
+
isMaxYear = year === opts.maxYear,
|
250
|
+
html = '<div class="pika-title">',
|
251
|
+
prev = true,
|
252
|
+
next = true;
|
253
|
+
|
254
|
+
for (arr = [], i = 0; i < 12; i++) {
|
255
|
+
arr.push('<option value="' + i + '"' +
|
256
|
+
(i === month ? ' selected': '') +
|
257
|
+
((isMinYear && i < opts.minMonth) || (isMaxYear && i > opts.maxMonth) ? 'disabled' : '') + '>' +
|
258
|
+
opts.i18n.months[i] + '</option>');
|
259
|
+
}
|
260
|
+
html += '<div class="pika-label">' + opts.i18n.months[month] + '<select class="pika-select pika-select-month">' + arr.join('') + '</select></div>';
|
261
|
+
|
262
|
+
if (isArray(opts.yearRange)) {
|
263
|
+
i = opts.yearRange[0];
|
264
|
+
j = opts.yearRange[1] + 1;
|
265
|
+
} else {
|
266
|
+
i = year - opts.yearRange;
|
267
|
+
j = 1 + year + opts.yearRange;
|
268
|
+
}
|
269
|
+
|
270
|
+
for (arr = []; i < j && i <= opts.maxYear; i++) {
|
271
|
+
if (i >= opts.minYear) {
|
272
|
+
arr.push('<option value="' + i + '"' + (i === year ? ' selected': '') + '>' + (i) + '</option>');
|
273
|
+
}
|
274
|
+
}
|
275
|
+
html += '<div class="pika-label">' + year + '<select class="pika-select pika-select-year">' + arr.join('') + '</select></div>';
|
276
|
+
|
277
|
+
if (isMinYear && (month === 0 || opts.minMonth >= month)) {
|
278
|
+
prev = false;
|
279
|
+
}
|
280
|
+
|
281
|
+
if (isMaxYear && (month === 11 || opts.maxMonth <= month)) {
|
282
|
+
next = false;
|
283
|
+
}
|
284
|
+
|
285
|
+
html += '<button class="pika-prev' + (prev ? '' : ' is-disabled') + '" type="button">' + opts.i18n.previousMonth + '</button>';
|
286
|
+
html += '<button class="pika-next' + (next ? '' : ' is-disabled') + '" type="button">' + opts.i18n.nextMonth + '</button>';
|
287
|
+
|
288
|
+
return html += '</div>';
|
289
|
+
},
|
290
|
+
|
291
|
+
renderTable = function(opts, data)
|
292
|
+
{
|
293
|
+
return '<table cellpadding="0" cellspacing="0" class="pika-table">' + renderHead(opts) + renderBody(data) + '</table>';
|
294
|
+
};
|
295
|
+
|
296
|
+
|
297
|
+
/**
|
298
|
+
* Pikaday constructor
|
299
|
+
*/
|
300
|
+
window.Pikaday = function(options)
|
301
|
+
{
|
302
|
+
var self = this,
|
303
|
+
opts = self.config(options);
|
304
|
+
|
305
|
+
self._onMouseDown = function(e)
|
306
|
+
{
|
307
|
+
if (!self._v) {
|
308
|
+
return;
|
309
|
+
}
|
310
|
+
e = e || window.event;
|
311
|
+
var target = e.target || e.srcElement;
|
312
|
+
if (!target) {
|
313
|
+
return;
|
314
|
+
}
|
315
|
+
|
316
|
+
if (!hasClass(target, 'is-disabled')) {
|
317
|
+
if (hasClass(target, 'pika-button') && !hasClass(target, 'is-empty')) {
|
318
|
+
self.setDate(new Date(self._y, self._m, parseInt(target.innerHTML, 10)));
|
319
|
+
if (opts.bound) {
|
320
|
+
sto(function() {
|
321
|
+
self.hide();
|
322
|
+
}, 100);
|
323
|
+
}
|
324
|
+
return;
|
325
|
+
}
|
326
|
+
else if (hasClass(target, 'pika-prev')) {
|
327
|
+
self.prevMonth();
|
328
|
+
}
|
329
|
+
else if (hasClass(target, 'pika-next')) {
|
330
|
+
self.nextMonth();
|
331
|
+
}
|
332
|
+
}
|
333
|
+
if (!hasClass(target, 'pika-select')) {
|
334
|
+
if (e.preventDefault) {
|
335
|
+
e.preventDefault();
|
336
|
+
} else {
|
337
|
+
return e.returnValue = false;
|
338
|
+
}
|
339
|
+
} else {
|
340
|
+
self._c = true;
|
341
|
+
}
|
342
|
+
};
|
343
|
+
|
344
|
+
self._onChange = function(e)
|
345
|
+
{
|
346
|
+
e = e || window.event;
|
347
|
+
var target = e.target || e.srcElement;
|
348
|
+
if (!target) {
|
349
|
+
return;
|
350
|
+
}
|
351
|
+
if (hasClass(target, 'pika-select-month')) {
|
352
|
+
self.gotoMonth(target.value);
|
353
|
+
}
|
354
|
+
else if (hasClass(target, 'pika-select-year')) {
|
355
|
+
self.gotoYear(target.value);
|
356
|
+
}
|
357
|
+
};
|
358
|
+
|
359
|
+
self._onInputChange = function(e)
|
360
|
+
{
|
361
|
+
var date;
|
362
|
+
|
363
|
+
if (e.firedBy === self) {
|
364
|
+
return;
|
365
|
+
}
|
366
|
+
if (hasMoment) {
|
367
|
+
date = window.moment(opts.field.value, opts.format);
|
368
|
+
date = date ? date.toDate() : null;
|
369
|
+
}
|
370
|
+
else {
|
371
|
+
date = new Date(Date.parse(opts.field.value));
|
372
|
+
}
|
373
|
+
self.setDate(isDate(date) ? date : null);
|
374
|
+
if (!self._v) {
|
375
|
+
self.show();
|
376
|
+
}
|
377
|
+
};
|
378
|
+
|
379
|
+
self._onInputFocus = function(e)
|
380
|
+
{
|
381
|
+
self.show();
|
382
|
+
};
|
383
|
+
|
384
|
+
self._onInputClick = function(e)
|
385
|
+
{
|
386
|
+
self.show();
|
387
|
+
};
|
388
|
+
|
389
|
+
self._onInputBlur = function(e)
|
390
|
+
{
|
391
|
+
if (!self._c) {
|
392
|
+
self._b = sto(function() {
|
393
|
+
self.hide();
|
394
|
+
}, 50);
|
395
|
+
}
|
396
|
+
self._c = false;
|
397
|
+
};
|
398
|
+
|
399
|
+
self._onClick = function(e)
|
400
|
+
{
|
401
|
+
e = e || window.event;
|
402
|
+
var target = e.target || e.srcElement,
|
403
|
+
pEl = target;
|
404
|
+
if (!target) {
|
405
|
+
return;
|
406
|
+
}
|
407
|
+
if (!hasEventListeners && hasClass(target, 'pika-select')) {
|
408
|
+
if (!target.onchange) {
|
409
|
+
target.setAttribute('onchange', 'return;');
|
410
|
+
addEvent(target, 'change', self._onChange);
|
411
|
+
}
|
412
|
+
}
|
413
|
+
do {
|
414
|
+
if (hasClass(pEl, 'pika-single')) {
|
415
|
+
return;
|
416
|
+
}
|
417
|
+
}
|
418
|
+
while ((pEl = pEl.parentNode));
|
419
|
+
if (self._v && target !== opts.field) {
|
420
|
+
self.hide();
|
421
|
+
}
|
422
|
+
};
|
423
|
+
|
424
|
+
self.el = document.createElement('div');
|
425
|
+
self.el.className = 'pika-single' + (opts.isRTL ? ' is-rtl' : '');
|
426
|
+
|
427
|
+
addEvent(self.el, 'mousedown', self._onMouseDown, true);
|
428
|
+
addEvent(self.el, 'change', self._onChange);
|
429
|
+
|
430
|
+
if (opts.field) {
|
431
|
+
if (opts.bound) {
|
432
|
+
document.body.appendChild(self.el);
|
433
|
+
} else {
|
434
|
+
opts.field.parentNode.insertBefore(self.el, opts.field.nextSibling);
|
435
|
+
}
|
436
|
+
addEvent(opts.field, 'change', self._onInputChange);
|
437
|
+
|
438
|
+
if (!opts.defaultDate) {
|
439
|
+
if (hasMoment && opts.field.value) {
|
440
|
+
opts.defaultDate = window.moment(opts.field.value, opts.format).toDate();
|
441
|
+
} else {
|
442
|
+
opts.defaultDate = new Date(Date.parse(opts.field.value));
|
443
|
+
}
|
444
|
+
opts.setDefaultDate = true;
|
445
|
+
}
|
446
|
+
}
|
447
|
+
|
448
|
+
var defDate = opts.defaultDate;
|
449
|
+
|
450
|
+
if (isDate(defDate)) {
|
451
|
+
if (opts.setDefaultDate) {
|
452
|
+
self.setDate(defDate, true);
|
453
|
+
} else {
|
454
|
+
self.gotoDate(defDate);
|
455
|
+
}
|
456
|
+
} else {
|
457
|
+
self.gotoDate(new Date());
|
458
|
+
}
|
459
|
+
|
460
|
+
if (opts.bound) {
|
461
|
+
this.hide();
|
462
|
+
self.el.className += ' is-bound';
|
463
|
+
addEvent(opts.field, 'click', self._onInputClick);
|
464
|
+
addEvent(opts.field, 'focus', self._onInputFocus);
|
465
|
+
addEvent(opts.field, 'blur', self._onInputBlur);
|
466
|
+
} else {
|
467
|
+
this.show();
|
468
|
+
}
|
469
|
+
|
470
|
+
};
|
471
|
+
|
472
|
+
|
473
|
+
/**
|
474
|
+
* public Pikaday API
|
475
|
+
*/
|
476
|
+
window.Pikaday.prototype = {
|
477
|
+
|
478
|
+
|
479
|
+
/**
|
480
|
+
* configure functionality
|
481
|
+
*/
|
482
|
+
config: function(options)
|
483
|
+
{
|
484
|
+
if (!this._o) {
|
485
|
+
this._o = extend({}, defaults, true);
|
486
|
+
}
|
487
|
+
|
488
|
+
var opts = extend(this._o, options, true);
|
489
|
+
|
490
|
+
opts.isRTL = !!opts.isRTL;
|
491
|
+
|
492
|
+
opts.field = (opts.field && opts.field.nodeName) ? opts.field : null;
|
493
|
+
|
494
|
+
opts.bound = !!(opts.bound !== undefined ? opts.field && opts.bound : opts.field);
|
495
|
+
|
496
|
+
var nom = parseInt(opts.numberOfMonths, 10) || 1;
|
497
|
+
opts.numberOfMonths = nom > 4 ? 4 : nom;
|
498
|
+
|
499
|
+
if (!isDate(opts.minDate)) {
|
500
|
+
opts.minDate = false;
|
501
|
+
}
|
502
|
+
if (!isDate(opts.maxDate)) {
|
503
|
+
opts.maxDate = false;
|
504
|
+
}
|
505
|
+
if ((opts.minDate && opts.maxDate) && opts.maxDate < opts.minDate) {
|
506
|
+
opts.maxDate = opts.minDate = false;
|
507
|
+
}
|
508
|
+
if (opts.minDate) {
|
509
|
+
setToStartOfDay(opts.minDate);
|
510
|
+
opts.minYear = opts.minDate.getFullYear();
|
511
|
+
opts.minMonth = opts.minDate.getMonth();
|
512
|
+
}
|
513
|
+
if (opts.maxDate) {
|
514
|
+
setToStartOfDay(opts.maxDate);
|
515
|
+
opts.maxYear = opts.maxDate.getFullYear();
|
516
|
+
opts.maxMonth = opts.maxDate.getMonth();
|
517
|
+
}
|
518
|
+
|
519
|
+
if (isArray(opts.yearRange)) {
|
520
|
+
var fallback = new Date().getFullYear() - 10;
|
521
|
+
opts.yearRange[0] = parseInt(opts.yearRange[0], 10) || fallback;
|
522
|
+
opts.yearRange[1] = parseInt(opts.yearRange[1], 10) || fallback;
|
523
|
+
} else {
|
524
|
+
opts.yearRange = Math.abs(parseInt(opts.yearRange, 10)) || defaults.yearRange;
|
525
|
+
if (opts.yearRange > 100) {
|
526
|
+
opts.yearRange = 100;
|
527
|
+
}
|
528
|
+
}
|
529
|
+
|
530
|
+
return opts;
|
531
|
+
},
|
532
|
+
|
533
|
+
/**
|
534
|
+
* return a formatted string of the current selection (using Moment.js if available)
|
535
|
+
*/
|
536
|
+
toString: function(format)
|
537
|
+
{
|
538
|
+
return !isDate(this._d) ? '' : hasMoment ? window.moment(this._d).format(format || this._o.format) : this._d.toDateString();
|
539
|
+
},
|
540
|
+
|
541
|
+
/**
|
542
|
+
* return a Moment.js object of the current selection (if available)
|
543
|
+
*/
|
544
|
+
getMoment: function()
|
545
|
+
{
|
546
|
+
return hasMoment ? window.moment(this._d) : null;
|
547
|
+
},
|
548
|
+
|
549
|
+
/**
|
550
|
+
* set the current selection from a Moment.js object (if available)
|
551
|
+
*/
|
552
|
+
setMoment: function(date)
|
553
|
+
{
|
554
|
+
if (hasMoment && window.moment.isMoment(date)) {
|
555
|
+
this.setDate(date.toDate());
|
556
|
+
}
|
557
|
+
},
|
558
|
+
|
559
|
+
/**
|
560
|
+
* return a Date object of the current selection
|
561
|
+
*/
|
562
|
+
getDate: function()
|
563
|
+
{
|
564
|
+
return isDate(this._d) ? new Date(this._d.getTime()) : null;
|
565
|
+
},
|
566
|
+
|
567
|
+
/**
|
568
|
+
* set the current selection
|
569
|
+
*/
|
570
|
+
setDate: function(date, preventOnSelect)
|
571
|
+
{
|
572
|
+
if (!date) {
|
573
|
+
this._d = null;
|
574
|
+
return this.draw();
|
575
|
+
}
|
576
|
+
if (typeof date === 'string') {
|
577
|
+
date = new Date(Date.parse(date));
|
578
|
+
}
|
579
|
+
if (!isDate(date)) {
|
580
|
+
return;
|
581
|
+
}
|
582
|
+
|
583
|
+
var min = this._o.minDate,
|
584
|
+
max = this._o.maxDate;
|
585
|
+
|
586
|
+
if (isDate(min) && date < min) {
|
587
|
+
date = min;
|
588
|
+
} else if (isDate(max) && date > max) {
|
589
|
+
date = max;
|
590
|
+
}
|
591
|
+
|
592
|
+
this._d = new Date(date.getTime());
|
593
|
+
setToStartOfDay(this._d);
|
594
|
+
this.gotoDate(this._d);
|
595
|
+
|
596
|
+
if (this._o.field) {
|
597
|
+
this._o.field.value = this.toString();
|
598
|
+
fireEvent(this._o.field, "change", { firedBy: this });
|
599
|
+
}
|
600
|
+
if (!preventOnSelect && typeof this._o.onSelect === 'function') {
|
601
|
+
this._o.onSelect.call(this, this.getDate());
|
602
|
+
}
|
603
|
+
},
|
604
|
+
|
605
|
+
/**
|
606
|
+
* change view to a specific date
|
607
|
+
*/
|
608
|
+
gotoDate: function(date)
|
609
|
+
{
|
610
|
+
if (!isDate(date)) {
|
611
|
+
return;
|
612
|
+
}
|
613
|
+
this._y = date.getFullYear();
|
614
|
+
this._m = date.getMonth();
|
615
|
+
this.draw();
|
616
|
+
},
|
617
|
+
|
618
|
+
gotoToday: function()
|
619
|
+
{
|
620
|
+
this.gotoDate(new Date());
|
621
|
+
},
|
622
|
+
|
623
|
+
/**
|
624
|
+
* change view to a specific month (zero-index, e.g. 0: January)
|
625
|
+
*/
|
626
|
+
gotoMonth: function(month)
|
627
|
+
{
|
628
|
+
if (!isNaN( (month = parseInt(month, 10)) )) {
|
629
|
+
this._m = month < 0 ? 0 : month > 11 ? 11 : month;
|
630
|
+
this.draw();
|
631
|
+
}
|
632
|
+
},
|
633
|
+
|
634
|
+
nextMonth: function()
|
635
|
+
{
|
636
|
+
if (++this._m > 11) {
|
637
|
+
this._m = 0;
|
638
|
+
this._y++;
|
639
|
+
}
|
640
|
+
this.draw();
|
641
|
+
},
|
642
|
+
|
643
|
+
prevMonth: function()
|
644
|
+
{
|
645
|
+
if (--this._m < 0) {
|
646
|
+
this._m = 11;
|
647
|
+
this._y--;
|
648
|
+
}
|
649
|
+
this.draw();
|
650
|
+
},
|
651
|
+
|
652
|
+
/**
|
653
|
+
* change view to a specific full year (e.g. "2012")
|
654
|
+
*/
|
655
|
+
gotoYear: function(year)
|
656
|
+
{
|
657
|
+
if (!isNaN(year)) {
|
658
|
+
this._y = parseInt(year, 10);
|
659
|
+
this.draw();
|
660
|
+
}
|
661
|
+
},
|
662
|
+
|
663
|
+
/**
|
664
|
+
* refresh the HTML
|
665
|
+
*/
|
666
|
+
draw: function(force)
|
667
|
+
{
|
668
|
+
if (!this._v && !force) {
|
669
|
+
return;
|
670
|
+
}
|
671
|
+
var opts = this._o,
|
672
|
+
minYear = opts.minYear,
|
673
|
+
maxYear = opts.maxYear,
|
674
|
+
minMonth = opts.minMonth,
|
675
|
+
maxMonth = opts.maxMonth;
|
676
|
+
|
677
|
+
if (this._y <= minYear) {
|
678
|
+
this._y = minYear;
|
679
|
+
if (!isNaN(minMonth) && this._m < minMonth) {
|
680
|
+
this._m = minMonth;
|
681
|
+
}
|
682
|
+
}
|
683
|
+
if (this._y >= maxYear) {
|
684
|
+
this._y = maxYear;
|
685
|
+
if (!isNaN(maxMonth) && this._m > maxMonth) {
|
686
|
+
this._m = maxMonth;
|
687
|
+
}
|
688
|
+
}
|
689
|
+
|
690
|
+
this.el.innerHTML = renderTitle(this) + this.render(this._y, this._m);
|
691
|
+
|
692
|
+
if (opts.bound) {
|
693
|
+
var pEl = opts.field,
|
694
|
+
left = pEl.offsetLeft,
|
695
|
+
top = pEl.offsetTop + pEl.offsetHeight;
|
696
|
+
while((pEl = pEl.offsetParent)) {
|
697
|
+
left += pEl.offsetLeft;
|
698
|
+
top += pEl.offsetTop;
|
699
|
+
}
|
700
|
+
this.el.style.cssText = 'position:absolute;left:' + left + 'px;top:' + top + 'px;';
|
701
|
+
sto(function() {
|
702
|
+
opts.field.focus();
|
703
|
+
}, 1);
|
704
|
+
}
|
705
|
+
|
706
|
+
if (typeof this._o.onDraw === 'function') {
|
707
|
+
var self = this;
|
708
|
+
sto(function() {
|
709
|
+
self._o.onDraw.call(self);
|
710
|
+
}, 0);
|
711
|
+
}
|
712
|
+
},
|
713
|
+
|
714
|
+
/**
|
715
|
+
* render HTML for a particular month
|
716
|
+
*/
|
717
|
+
render: function(year, month)
|
718
|
+
{
|
719
|
+
var opts = this._o,
|
720
|
+
now = new Date(),
|
721
|
+
days = getDaysInMonth(year, month),
|
722
|
+
before = new Date(year, month, 1).getDay(),
|
723
|
+
data = [],
|
724
|
+
row = [];
|
725
|
+
setToStartOfDay(now);
|
726
|
+
if (opts.firstDay > 0) {
|
727
|
+
before -= opts.firstDay;
|
728
|
+
if (before < 0) {
|
729
|
+
before += 7;
|
730
|
+
}
|
731
|
+
}
|
732
|
+
var cells = days + before,
|
733
|
+
after = cells;
|
734
|
+
while(after > 7) {
|
735
|
+
after -= 7;
|
736
|
+
}
|
737
|
+
cells += 7 - after;
|
738
|
+
for (var i = 0, r = 0; i < cells; i++)
|
739
|
+
{
|
740
|
+
var day = new Date(year, month, 1 + (i - before)),
|
741
|
+
isDisabled = (opts.minDate && day < opts.minDate) || (opts.maxDate && day > opts.maxDate),
|
742
|
+
isSelected = isDate(this._d) ? compareDates(day, this._d) : false,
|
743
|
+
isToday = compareDates(day, now),
|
744
|
+
isEmpty = i < before || i >= (days + before);
|
745
|
+
|
746
|
+
row.push(renderDay(1 + (i - before), isSelected, isToday, isDisabled, isEmpty));
|
747
|
+
|
748
|
+
if (++r === 7) {
|
749
|
+
data.push(renderRow(row, opts.isRTL));
|
750
|
+
row = [];
|
751
|
+
r = 0;
|
752
|
+
}
|
753
|
+
}
|
754
|
+
return renderTable(opts, data);
|
755
|
+
},
|
756
|
+
|
757
|
+
isVisible: function()
|
758
|
+
{
|
759
|
+
return this._v;
|
760
|
+
},
|
761
|
+
|
762
|
+
show: function()
|
763
|
+
{
|
764
|
+
if (!this._v) {
|
765
|
+
if (this._o.bound) {
|
766
|
+
addEvent(document, 'click', this._onClick);
|
767
|
+
}
|
768
|
+
removeClass(this.el, 'is-hidden');
|
769
|
+
this._v = true;
|
770
|
+
this.draw();
|
771
|
+
if (typeof this._o.onOpen === 'function') {
|
772
|
+
this._o.onOpen.call(this);
|
773
|
+
}
|
774
|
+
}
|
775
|
+
},
|
776
|
+
|
777
|
+
hide: function()
|
778
|
+
{
|
779
|
+
var v = this._v;
|
780
|
+
if (v !== false) {
|
781
|
+
if (this._o.bound) {
|
782
|
+
removeEvent(document, 'click', this._onClick);
|
783
|
+
}
|
784
|
+
this.el.style.cssText = '';
|
785
|
+
addClass(this.el, 'is-hidden');
|
786
|
+
this._v = false;
|
787
|
+
if (v !== undefined && typeof this._o.onClose === 'function') {
|
788
|
+
this._o.onClose.call(this);
|
789
|
+
}
|
790
|
+
}
|
791
|
+
},
|
792
|
+
|
793
|
+
/**
|
794
|
+
* GAME OVER
|
795
|
+
*/
|
796
|
+
destroy: function()
|
797
|
+
{
|
798
|
+
this.hide();
|
799
|
+
removeEvent(this.el, 'mousedown', this._onMouseDown, true);
|
800
|
+
removeEvent(this.el, 'change', this._onChange);
|
801
|
+
if (this._o.field) {
|
802
|
+
removeEvent(this._o.field, 'change', this._onInputChange);
|
803
|
+
if (this._o.bound) {
|
804
|
+
removeEvent(this._o.field, 'click', this._onInputClick);
|
805
|
+
removeEvent(this._o.field, 'focus', this._onInputFocus);
|
806
|
+
removeEvent(this._o.field, 'blur', this._onInputBlur);
|
807
|
+
}
|
808
|
+
}
|
809
|
+
if (this.el.parentNode) {
|
810
|
+
this.el.parentNode.removeChild(this.el);
|
811
|
+
}
|
812
|
+
}
|
813
|
+
|
814
|
+
};
|
815
|
+
|
816
|
+
})(window, window.document);
|