Package not found. Please check the package name and try again.
jquery-monthpicker-rails 0.0.1
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/README.md +17 -0
- data/jquery-monthpicker-rails.gemspec +22 -0
- data/lib/jquery-monthpicker-rails.rb +1 -0
- data/lib/jquery/monthpicker/rails.rb +2 -0
- data/lib/jquery/monthpicker/rails/engine.rb +8 -0
- data/lib/jquery/monthpicker/rails/version.rb +7 -0
- data/vendor/assets/javascripts/jquery.ui.monthpicker.js +1451 -0
- metadata +86 -0
data/README.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# jquery-monthpicker-rails
|
|
2
|
+
|
|
3
|
+
This gem packages the jQuery Monthpicker assets for the Rails 3.1+ asset pipeline.
|
|
4
|
+
|
|
5
|
+
# Usage
|
|
6
|
+
|
|
7
|
+
In your Gemfile, add:
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
gem "jquery-monthpicker-rails"
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Then require the javascript in your application.js
|
|
14
|
+
|
|
15
|
+
```js
|
|
16
|
+
//= require jquery.ui.monthpicker
|
|
17
|
+
```
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
require File.expand_path('../lib/jquery/monthpicker/rails/version', __FILE__)
|
|
3
|
+
|
|
4
|
+
Gem::Specification.new do |s|
|
|
5
|
+
s.name = "jquery-monthpicker-rails"
|
|
6
|
+
s.version = Jquery::Monthpicker::Rails::VERSION
|
|
7
|
+
s.authors = ["Charles Maresh"]
|
|
8
|
+
s.email = ["cmaresh@gmail.com"]
|
|
9
|
+
s.homepage = "https://github.com/cmaresh/jquery-monthpicker-rails"
|
|
10
|
+
s.summary = "jQuery Monthpicker packaged for the Rails asset pipeline"
|
|
11
|
+
s.description = "jQuery Monthpicker's JavaScript files packaged for the Rails 3.1+ asset pipeline"
|
|
12
|
+
s.license = "MIT"
|
|
13
|
+
|
|
14
|
+
s.required_rubygems_version = ">= 1.3.6"
|
|
15
|
+
|
|
16
|
+
s.add_dependency "railties", ">= 3.1.0"
|
|
17
|
+
s.add_dependency "jquery-ui-rails", ">= 3.0"
|
|
18
|
+
|
|
19
|
+
s.files = `git ls-files`.split("\n").reject { |f| f =~ /^testapp/ }
|
|
20
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
|
21
|
+
s.require_path = 'lib'
|
|
22
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require "jquery/monthpicker/rails"
|
|
@@ -0,0 +1,1451 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* jQuery UI Monthpicker
|
|
3
|
+
*
|
|
4
|
+
* MIT License
|
|
5
|
+
* Copyright (c) 2011, Julien Poumailloux
|
|
6
|
+
*
|
|
7
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
* in the Software without restriction, including without limitation the rights
|
|
10
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
* copies of the Software, and to permit persons to whom the Software i
|
|
12
|
+
* furnished to do so, subject to the following conditions:
|
|
13
|
+
*
|
|
14
|
+
* The above copyright notice and this permission notice shall be included in
|
|
15
|
+
* all copies or substantial portions of the Software.
|
|
16
|
+
*
|
|
17
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
23
|
+
* THE SOFTWARE.
|
|
24
|
+
*/
|
|
25
|
+
(function ($) {
|
|
26
|
+
|
|
27
|
+
$.extend($.ui, { monthpicker: { version: "@VERSION" } });
|
|
28
|
+
|
|
29
|
+
var PROP_NAME = 'monthpicker';
|
|
30
|
+
var instActive;
|
|
31
|
+
|
|
32
|
+
/* Month picker manager.
|
|
33
|
+
Use the singleton instance of this class, $.monthpicker, to interact with the date picker.
|
|
34
|
+
Settings for (groups of) month pickers are maintained in an instance object,
|
|
35
|
+
allowing multiple different settings on the same page. */
|
|
36
|
+
|
|
37
|
+
function Monthpicker() {
|
|
38
|
+
this.uuid = 0;
|
|
39
|
+
this._keyEvent = false; // If the last event was a key event
|
|
40
|
+
this._curInst = null; // The current instance in use
|
|
41
|
+
this._disabledInputs = []; // List of date picker inputs that have been disabled
|
|
42
|
+
this._monthpickerShowing = false; // True if the popup picker is showing , false if not
|
|
43
|
+
this._mainDivId = 'ui-monthpicker-div'; // The ID of the main monthpicker division
|
|
44
|
+
this._triggerClass = 'ui-monthpicker-trigger'; // The name of the trigger marker class
|
|
45
|
+
this._dialogClass = 'ui-monthpicker-dialog'; // The name of the dialog marker class
|
|
46
|
+
this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
|
|
47
|
+
this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
|
|
48
|
+
this.regional = []; // Available regional settings, indexed by language code
|
|
49
|
+
this.regional[''] = { // Default regional settings
|
|
50
|
+
closeText: "Done", // Display text for close link
|
|
51
|
+
prevText: 'Prev', // Display text for previous month link
|
|
52
|
+
nextText: 'Next', // Display text for next month link
|
|
53
|
+
currentText: "Current", // Display text for current month link
|
|
54
|
+
monthNames: ['January','February','March','April','May','June',
|
|
55
|
+
'July','August','September','October','November','December'], // Names of months for drop-down and formatting
|
|
56
|
+
monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], // For formatting
|
|
57
|
+
dateFormat: 'mm/yy',
|
|
58
|
+
isRTL: false,
|
|
59
|
+
yearSuffix: '' // Additional text to append to the year in the month headers
|
|
60
|
+
};
|
|
61
|
+
this._defaults = { // Global defaults for all the date picker instances
|
|
62
|
+
showOn: 'focus', // 'focus' for popup on focus,
|
|
63
|
+
// 'button' for trigger button, or 'both' for either
|
|
64
|
+
showAnim: 'fadeIn', // Name of jQuery animation for popup
|
|
65
|
+
showButtonPanel: false, // True to show button panel, false to not show it
|
|
66
|
+
appendText: "", // Display text following the input box, e.g. showing the format
|
|
67
|
+
buttonText: '...', // Text for trigger button
|
|
68
|
+
buttonImage: '', // URL for trigger button image
|
|
69
|
+
gotoCurrent: false, // True if today link goes back to current selection instead
|
|
70
|
+
changeYear: false, // True if year can be selected directly, false if only prev/next
|
|
71
|
+
navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
|
|
72
|
+
yearRange: 'c-10:c+10', // Range of years to display in drop-down,
|
|
73
|
+
// either relative to today's year (-nn:+nn), relative to currently displayed year
|
|
74
|
+
// (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
|
|
75
|
+
beforeShow: null, // Function that takes an input field and
|
|
76
|
+
// returns a set of custom settings for the date picker
|
|
77
|
+
onSelect: null, // Define a callback function when a date is selected
|
|
78
|
+
onChangeYear: null, // Define a callback function when the year is changed
|
|
79
|
+
onClose: null, // Define a callback function when the monthpicker is closed
|
|
80
|
+
stepYears: 1, // Number of months to step back/forward
|
|
81
|
+
stepBigYears: 3, // Number of months to step back/forward
|
|
82
|
+
defaultDate: null, // Used when field is blank: actual date,
|
|
83
|
+
minDate: null, // The earliest selectable date, or null for no limit
|
|
84
|
+
maxDate: null, // The latest selectable date, or null for no limit
|
|
85
|
+
altField: '', // Selector for an alternate field to store selected dates into
|
|
86
|
+
altFormat: '', // The date format to use for the alternate field
|
|
87
|
+
disabled: false // The initial disabled state
|
|
88
|
+
};
|
|
89
|
+
$.extend(this._defaults, this.regional['']);
|
|
90
|
+
this.dpDiv = bindHover($('<div id="' + this._mainDivId + '" class="ui-monthpicker ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>'));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
$.extend(Monthpicker.prototype, {
|
|
94
|
+
/* Class name added to elements to indicate already configured with a date picker. */
|
|
95
|
+
markerClassName: 'hasMonthpicker',
|
|
96
|
+
|
|
97
|
+
/* Debug logging (if enabled). */
|
|
98
|
+
log: function () {
|
|
99
|
+
if (this.debug)
|
|
100
|
+
console.log.apply('', arguments);
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
// TODO rename to "widget" when switching to widget factory
|
|
104
|
+
_widgetMonthpicker: function() {
|
|
105
|
+
return this.dpDiv;
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
/* Override the default settings for all instances of the date picker.
|
|
109
|
+
* @param settings object - the new settings to use as defaults (anonymous object)
|
|
110
|
+
* @return the manager object
|
|
111
|
+
*/
|
|
112
|
+
setDefaults: function(settings) {
|
|
113
|
+
extendRemove(this._defaults, settings || {});
|
|
114
|
+
return this;
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
/* Retrieve the instance data for the target control.
|
|
119
|
+
@param target element - the target input field or division or span
|
|
120
|
+
@return object - the associated instance data
|
|
121
|
+
@throws error if a jQuery problem getting data */
|
|
122
|
+
_getInst: function(target) {
|
|
123
|
+
try {
|
|
124
|
+
return $.data(target, PROP_NAME);
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
throw 'Missing instance data for this monthpicker';
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
|
|
131
|
+
/* Get a setting value, defaulting if necessary. */
|
|
132
|
+
_get: function(inst, name) {
|
|
133
|
+
return inst.settings[name] !== undefined ?
|
|
134
|
+
inst.settings[name] : this._defaults[name];
|
|
135
|
+
},
|
|
136
|
+
|
|
137
|
+
/* Attach the month picker to a jQuery selection.
|
|
138
|
+
@param target element - the target input field or division or span
|
|
139
|
+
@param settings object - the new settings to use for this month picker instance (anonymous) */
|
|
140
|
+
_attachMonthpicker: function(target, settings) {
|
|
141
|
+
// check for settings on the control itself - in namespace 'month:'
|
|
142
|
+
var inlineSettings = null;
|
|
143
|
+
for (var attrName in this._defaults) {
|
|
144
|
+
var attrValue = target.getAttribute('month:' + attrName);
|
|
145
|
+
if (attrValue) {
|
|
146
|
+
inlineSettings = inlineSettings || {};
|
|
147
|
+
try {
|
|
148
|
+
inlineSettings[attrName] = eval(attrValue);
|
|
149
|
+
} catch (err) {
|
|
150
|
+
inlineSettings[attrName] = attrValue;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
var nodeName = target.nodeName.toLowerCase();
|
|
155
|
+
if (!target.id) {
|
|
156
|
+
this.uuid += 1;
|
|
157
|
+
target.id = 'dp' + this.uuid;
|
|
158
|
+
}
|
|
159
|
+
var inst = this._newInst($(target));
|
|
160
|
+
inst.settings = $.extend({}, settings || {}, inlineSettings || {});
|
|
161
|
+
if (nodeName == 'input') {
|
|
162
|
+
this._connectMonthpicker(target, inst);
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
|
|
166
|
+
/* Create a new instance object. */
|
|
167
|
+
_newInst: function(target) {
|
|
168
|
+
var id = target[0].id.replace(/([^A-Za-z0-9_-])/g, '\\\\$1'); // escape jQuery meta chars
|
|
169
|
+
return {id: id, input: target, // associated target
|
|
170
|
+
selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
|
|
171
|
+
drawMonth: 0, drawYear: 0, // month being drawn
|
|
172
|
+
dpDiv: this.dpDiv // presentation div
|
|
173
|
+
};
|
|
174
|
+
},
|
|
175
|
+
|
|
176
|
+
/* Attach the date picker to an input field. */
|
|
177
|
+
_connectMonthpicker: function(target, inst) {
|
|
178
|
+
var input = $(target);
|
|
179
|
+
inst.append = $([]);
|
|
180
|
+
inst.trigger = $([]);
|
|
181
|
+
if (input.hasClass(this.markerClassName))
|
|
182
|
+
return;
|
|
183
|
+
this._attachments(input, inst);
|
|
184
|
+
input.addClass(this.markerClassName).keydown(this._doKeyDown).
|
|
185
|
+
keypress(this._doKeyPress).keyup(this._doKeyUp).
|
|
186
|
+
bind("setData.monthpicker", function(event, key, value) {
|
|
187
|
+
inst.settings[key] = value;
|
|
188
|
+
}).bind("getData.monthpicker", function(event, key) {
|
|
189
|
+
return this._get(inst, key);
|
|
190
|
+
});
|
|
191
|
+
//this._autoSize(inst);
|
|
192
|
+
$.data(target, PROP_NAME, inst);
|
|
193
|
+
//If disabled option is true, disable the monthpicker once it has been attached to the input (see ticket #5665)
|
|
194
|
+
if( inst.settings.disabled ) {
|
|
195
|
+
this._disableMonthpicker( target );
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
|
|
199
|
+
/* Make attachments based on settings. */
|
|
200
|
+
_attachments: function(input, inst) {
|
|
201
|
+
var appendText = this._get(inst, "appendText"),
|
|
202
|
+
isRTL = this._get(inst, "isRTL");
|
|
203
|
+
|
|
204
|
+
if (appendText) {
|
|
205
|
+
inst.append = $("<span class='" + this._appendClass + "'>" + appendText + "</span>");
|
|
206
|
+
input[isRTL ? "before" : "after"](inst.append);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
input.unbind('focus', this._showMonthpicker);
|
|
210
|
+
if (inst.trigger)
|
|
211
|
+
inst.trigger.remove();
|
|
212
|
+
var showOn = this._get(inst, 'showOn');
|
|
213
|
+
if (showOn == 'focus' || showOn == 'both') // pop-up month picker when in the marked field
|
|
214
|
+
input.focus(this._showMonthpicker);
|
|
215
|
+
if (showOn === "button" || showOn === "both") { // pop-up month picker when button clicked
|
|
216
|
+
buttonText = this._get(inst, "buttonText");
|
|
217
|
+
buttonImage = this._get(inst, "buttonImage");
|
|
218
|
+
inst.trigger = $(this._get(inst, "buttonImageOnly") ?
|
|
219
|
+
$("<img/>").addClass(this._triggerClass).
|
|
220
|
+
attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
|
|
221
|
+
$("<button type='button'></button>").addClass(this._triggerClass).
|
|
222
|
+
html(!buttonImage ? buttonText : $("<img/>").attr(
|
|
223
|
+
{ src:buttonImage, alt:buttonText, title:buttonText })));
|
|
224
|
+
input[isRTL ? "before" : "after"](inst.trigger);
|
|
225
|
+
inst.trigger.click(function() {
|
|
226
|
+
if ($.monthpicker._monthpickerShowing && $.monthpicker._lastInput === input[0]) {
|
|
227
|
+
$.monthpicker._hideMonthpicker();
|
|
228
|
+
} else if ($.monthpicker._monthpickerShowing && $.monthpicker._lastInput !== input[0]) {
|
|
229
|
+
$.monthpicker._hideMonthpicker();
|
|
230
|
+
$.monthpicker._showMonthpicker(input[0]);
|
|
231
|
+
} else {
|
|
232
|
+
$.monthpicker._showMonthpicker(input[0]);
|
|
233
|
+
}
|
|
234
|
+
return false;
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
},
|
|
238
|
+
|
|
239
|
+
/* Close month picker if clicked elsewhere. */
|
|
240
|
+
_checkExternalClick: function(event) {
|
|
241
|
+
if (!$.monthpicker._curInst)
|
|
242
|
+
return;
|
|
243
|
+
|
|
244
|
+
var $target = $(event.target),
|
|
245
|
+
inst = $.monthpicker._getInst($target[0]);
|
|
246
|
+
|
|
247
|
+
if ( ( ( $target[0].id != $.monthpicker._mainDivId &&
|
|
248
|
+
$target.parents('#' + $.monthpicker._mainDivId).length == 0 &&
|
|
249
|
+
!$target.hasClass($.monthpicker.markerClassName) &&
|
|
250
|
+
!$target.hasClass($.monthpicker._triggerClass) &&
|
|
251
|
+
$.monthpicker._monthpickerShowing ) ) ||
|
|
252
|
+
( $target.hasClass($.monthpicker.markerClassName) && $.monthpicker._curInst != inst ) )
|
|
253
|
+
$.monthpicker._hideMonthpicker();
|
|
254
|
+
},
|
|
255
|
+
|
|
256
|
+
/* Pop-up the month picker for a given input field.
|
|
257
|
+
If false returned from beforeShow event handler do not show.
|
|
258
|
+
@param input element - the input field attached to the date picker or
|
|
259
|
+
event - if triggered by focus */
|
|
260
|
+
_showMonthpicker: function(input) {
|
|
261
|
+
input = input.target || input;
|
|
262
|
+
if (input.nodeName.toLowerCase() != 'input') // find from button/image trigger
|
|
263
|
+
input = $('input', input.parentNode)[0];
|
|
264
|
+
if ($.monthpicker._isDisabledMonthpicker(input) || $.monthpicker._lastInput == input) // already here
|
|
265
|
+
return;
|
|
266
|
+
var inst = $.monthpicker._getInst(input);
|
|
267
|
+
if ($.monthpicker._curInst && $.monthpicker._curInst != inst) {
|
|
268
|
+
$.monthpicker._curInst.dpDiv.stop(true, true);
|
|
269
|
+
if ( inst && $.monthpicker._monthpickerShowing ) {
|
|
270
|
+
$.monthpicker._hideMonthpicker( $.monthpicker._curInst.input[0] );
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
var beforeShow = $.monthpicker._get(inst, 'beforeShow');
|
|
274
|
+
var beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {};
|
|
275
|
+
if(beforeShowSettings === false){
|
|
276
|
+
//false
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
extendRemove(inst.settings, beforeShowSettings);
|
|
280
|
+
inst.lastVal = null;
|
|
281
|
+
$.monthpicker._lastInput = input;
|
|
282
|
+
$.monthpicker._setDateFromField(inst);
|
|
283
|
+
if ($.monthpicker._inDialog) // hide cursor
|
|
284
|
+
input.value = '';
|
|
285
|
+
if (!$.monthpicker._pos) { // position below input
|
|
286
|
+
$.monthpicker._pos = $.monthpicker._findPos(input);
|
|
287
|
+
$.monthpicker._pos[1] += input.offsetHeight; // add the height
|
|
288
|
+
}
|
|
289
|
+
var isFixed = false;
|
|
290
|
+
$(input).parents().each(function() {
|
|
291
|
+
isFixed |= $(this).css('position') == 'fixed';
|
|
292
|
+
return !isFixed;
|
|
293
|
+
});
|
|
294
|
+
if (isFixed && $.browser.opera) { // correction for Opera when fixed and scrolled
|
|
295
|
+
$.monthpicker._pos[0] -= document.documentElement.scrollLeft;
|
|
296
|
+
$.monthpicker._pos[1] -= document.documentElement.scrollTop;
|
|
297
|
+
}
|
|
298
|
+
var offset = {left: $.monthpicker._pos[0], top: $.monthpicker._pos[1]};
|
|
299
|
+
$.monthpicker._pos = null;
|
|
300
|
+
//to avoid flashes on Firefox
|
|
301
|
+
inst.dpDiv.empty();
|
|
302
|
+
// determine sizing offscreen
|
|
303
|
+
inst.dpDiv.css({position: 'absolute', display: 'block', top: '-1000px'});
|
|
304
|
+
$.monthpicker._updateMonthpicker(inst);
|
|
305
|
+
// fix width for dynamic number of date pickers
|
|
306
|
+
// and adjust position before showing
|
|
307
|
+
offset = $.monthpicker._checkOffset(inst, offset, isFixed);
|
|
308
|
+
inst.dpDiv.css({position: ($.monthpicker._inDialog && $.blockUI ?
|
|
309
|
+
'static' : (isFixed ? 'fixed' : 'absolute')), display: 'none',
|
|
310
|
+
left: offset.left + 'px', top: offset.top + 'px'});
|
|
311
|
+
var showAnim = $.monthpicker._get(inst, 'showAnim');
|
|
312
|
+
var duration = $.monthpicker._get(inst, 'duration');
|
|
313
|
+
var postProcess = function() {
|
|
314
|
+
var cover = inst.dpDiv.find('iframe.ui-monthpicker-cover'); // IE6- only
|
|
315
|
+
if( !! cover.length ){
|
|
316
|
+
var borders = $.monthpicker._getBorders(inst.dpDiv);
|
|
317
|
+
cover.css({left: -borders[0], top: -borders[1],
|
|
318
|
+
width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()});
|
|
319
|
+
}
|
|
320
|
+
};
|
|
321
|
+
inst.dpDiv.zIndex($(input).zIndex()+1);
|
|
322
|
+
$.monthpicker._monthpickerShowing = true;
|
|
323
|
+
|
|
324
|
+
if ($.effects && $.effects[showAnim])
|
|
325
|
+
inst.dpDiv.show(showAnim, $.monthpicker._get(inst, 'showOptions'), duration, postProcess);
|
|
326
|
+
else
|
|
327
|
+
inst.dpDiv[showAnim || 'show']((showAnim ? duration : null), postProcess);
|
|
328
|
+
if (!showAnim || !duration)
|
|
329
|
+
postProcess();
|
|
330
|
+
if (inst.input.is(':visible') && !inst.input.is(':disabled'))
|
|
331
|
+
inst.input.focus();
|
|
332
|
+
$.monthpicker._curInst = inst;
|
|
333
|
+
},
|
|
334
|
+
|
|
335
|
+
/* Generate the date picker content. */
|
|
336
|
+
_updateMonthpicker: function(inst) {
|
|
337
|
+
|
|
338
|
+
var self = this;
|
|
339
|
+
self.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
|
|
340
|
+
var borders = $.monthpicker._getBorders(inst.dpDiv);
|
|
341
|
+
instActive = inst; // for delegate hover events
|
|
342
|
+
inst.dpDiv.empty().append(this._generateHTML(inst));
|
|
343
|
+
this._attachHandlers(inst);
|
|
344
|
+
var cover = inst.dpDiv.find('iframe.ui-monthpicker-cover'); // IE6- only
|
|
345
|
+
if( !!cover.length ){ //avoid call to outerXXXX() when not in IE6
|
|
346
|
+
cover.css({left: -borders[0], top: -borders[1], width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()})
|
|
347
|
+
}
|
|
348
|
+
inst.dpDiv.find('.' + this._dayOverClass + ' a').mouseover();
|
|
349
|
+
|
|
350
|
+
if (inst == $.monthpicker._curInst && $.monthpicker._monthpickerShowing && inst.input &&
|
|
351
|
+
// #6694 - don't focus the input if it's already focused
|
|
352
|
+
// this breaks the change event in IE
|
|
353
|
+
inst.input.is(':visible') && !inst.input.is(':disabled') && inst.input[0] != document.activeElement)
|
|
354
|
+
inst.input.focus();
|
|
355
|
+
// deffered render of the years select (to avoid flashes on Firefox)
|
|
356
|
+
if( inst.yearshtml ){
|
|
357
|
+
var origyearshtml = inst.yearshtml;
|
|
358
|
+
setTimeout(function(){
|
|
359
|
+
//assure that inst.yearshtml didn't change.
|
|
360
|
+
if( origyearshtml === inst.yearshtml && inst.yearshtml ){
|
|
361
|
+
inst.dpDiv.find('select.ui-monthpicker-year:first').replaceWith(inst.yearshtml);
|
|
362
|
+
}
|
|
363
|
+
origyearshtml = inst.yearshtml = null;
|
|
364
|
+
}, 0);
|
|
365
|
+
}
|
|
366
|
+
},
|
|
367
|
+
|
|
368
|
+
/* Trigger custom callback of onClose. */
|
|
369
|
+
_triggerOnClose: function(inst) {
|
|
370
|
+
var onClose = this._get(inst, 'onClose');
|
|
371
|
+
if (onClose)
|
|
372
|
+
onClose.apply((inst.input ? inst.input[0] : null),
|
|
373
|
+
[(inst.input ? inst.input.val() : ''), inst]);
|
|
374
|
+
},
|
|
375
|
+
|
|
376
|
+
/* Hide the month picker from view.
|
|
377
|
+
@param input element - the input field attached to the month picker */
|
|
378
|
+
_hideMonthpicker: function(input) {
|
|
379
|
+
var inst = this._curInst;
|
|
380
|
+
if (!inst || (input && inst != $.data(input, PROP_NAME)))
|
|
381
|
+
return;
|
|
382
|
+
if (this._monthpickerShowing) {
|
|
383
|
+
var showAnim = this._get(inst, 'showAnim');
|
|
384
|
+
var duration = this._get(inst, 'duration');
|
|
385
|
+
var postProcess = function() {
|
|
386
|
+
$.monthpicker._tidyDialog(inst);
|
|
387
|
+
$.monthpicker._curInst = null;
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
if ( $.effects && $.effects[ showAnim ] )
|
|
391
|
+
inst.dpDiv.hide(showAnim, $.monthpicker._get(inst, 'showOptions'), duration, postProcess);
|
|
392
|
+
else
|
|
393
|
+
inst.dpDiv[(showAnim == 'slideDown' ? 'slideUp' :
|
|
394
|
+
(showAnim == 'fadeIn' ? 'fadeOut' : 'hide'))]((showAnim ? duration : null), postProcess);
|
|
395
|
+
if (!showAnim)
|
|
396
|
+
postProcess();
|
|
397
|
+
$.monthpicker._triggerOnClose(inst);
|
|
398
|
+
this._monthpickerShowing = false;
|
|
399
|
+
this._lastInput = null;
|
|
400
|
+
if (this._inDialog) {
|
|
401
|
+
this._dialogInput.css({ position: 'absolute', left: '0', top: '-100px' });
|
|
402
|
+
if ($.blockUI) {
|
|
403
|
+
$.unblockUI();
|
|
404
|
+
$('body').append(this.dpDiv);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
this._inDialog = false;
|
|
408
|
+
}
|
|
409
|
+
},
|
|
410
|
+
|
|
411
|
+
/* Handle keystrokes. */
|
|
412
|
+
_doKeyDown: function(event) {
|
|
413
|
+
var onSelect, dateStr, sel,
|
|
414
|
+
inst = $.monthpicker._getInst(event.target),
|
|
415
|
+
handled = true,
|
|
416
|
+
isRTL = inst.dpDiv.is(".ui-datepicker-rtl");
|
|
417
|
+
|
|
418
|
+
inst._keyEvent = true;
|
|
419
|
+
if ($.monthpicker._monthpickerShowing) {
|
|
420
|
+
switch (event.keyCode) {
|
|
421
|
+
case 9: $.monthpicker._hideMonthpicker();
|
|
422
|
+
handled = false;
|
|
423
|
+
break; // hide on tab out
|
|
424
|
+
case 13: sel = $("td." + $.monthpicker._dayOverClass + ":not(." +
|
|
425
|
+
$.monthpicker._currentClass + ")", inst.dpDiv);
|
|
426
|
+
|
|
427
|
+
if (sel[0]) {
|
|
428
|
+
$.monthpicker._selectMonth(event.target, inst.selectedYear, inst.selectedMonth, sel[0]);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
onSelect = $.monthpicker._get(inst, "onSelect");
|
|
432
|
+
if (onSelect) {
|
|
433
|
+
dateStr = $.monthpicker._formatDate(inst);
|
|
434
|
+
|
|
435
|
+
// trigger custom callback
|
|
436
|
+
onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);
|
|
437
|
+
} else {
|
|
438
|
+
$.monthpicker._hideMonthpicker();
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
return false; // don't submit the form
|
|
442
|
+
case 27: $.monthpicker._hideMonthpicker();
|
|
443
|
+
break; // hide on escape
|
|
444
|
+
case 33: $.monthpicker._adjustDate(event.target, (event.ctrlKey ?
|
|
445
|
+
-$.monthpicker._get(inst, "stepBigYears") :
|
|
446
|
+
-$.monthpicker._get(inst, "stepYears")), "Y");
|
|
447
|
+
break; // previous year on page up/+ ctrl
|
|
448
|
+
case 34: $.monthpicker._adjustDate(event.target, (event.ctrlKey ?
|
|
449
|
+
+$.monthpicker._get(inst, "stepBigYears") :
|
|
450
|
+
+$.monthpicker._get(inst, "stepYears")), "Y");
|
|
451
|
+
break; // next year on page down/+ ctrl
|
|
452
|
+
case 35: if (event.ctrlKey || event.metaKey) {
|
|
453
|
+
$.monthpicker._clearDate(event.target);
|
|
454
|
+
}
|
|
455
|
+
handled = event.ctrlKey || event.metaKey;
|
|
456
|
+
break; // clear on ctrl or command +end
|
|
457
|
+
case 36: if (event.ctrlKey || event.metaKey) {
|
|
458
|
+
$.monthpicker._gotoCurrent(event.target);
|
|
459
|
+
}
|
|
460
|
+
handled = event.ctrlKey || event.metaKey;
|
|
461
|
+
break; // current on ctrl or command +home
|
|
462
|
+
case 37: if (event.ctrlKey || event.metaKey) {
|
|
463
|
+
$.monthpicker._adjustDate(event.target, (isRTL ? +1 : -1), "M");
|
|
464
|
+
}
|
|
465
|
+
handled = event.ctrlKey || event.metaKey;
|
|
466
|
+
// -1 month on ctrl or command +left
|
|
467
|
+
if (event.originalEvent.altKey) {
|
|
468
|
+
$.monthpicker._adjustDate(event.target, (event.ctrlKey ?
|
|
469
|
+
-$.monthpicker._get(inst, "stepBigYears") :
|
|
470
|
+
-$.monthpicker._get(inst, "stepYears")), "Y");
|
|
471
|
+
}
|
|
472
|
+
// next year on alt +left on Mac
|
|
473
|
+
break;
|
|
474
|
+
case 38: if (event.ctrlKey || event.metaKey) {
|
|
475
|
+
$.monthpicker._adjustDate(event.target, -3, "M");
|
|
476
|
+
}
|
|
477
|
+
handled = event.ctrlKey || event.metaKey;
|
|
478
|
+
break; // -1 quarter on ctrl or command +up
|
|
479
|
+
case 39: if (event.ctrlKey || event.metaKey) {
|
|
480
|
+
$.monthpicker._adjustDate(event.target, (isRTL ? -1 : +1), "M");
|
|
481
|
+
}
|
|
482
|
+
handled = event.ctrlKey || event.metaKey;
|
|
483
|
+
// +1 month on ctrl or command +right
|
|
484
|
+
if (event.originalEvent.altKey) {
|
|
485
|
+
$.monthpicker._adjustDate(event.target, (event.ctrlKey ?
|
|
486
|
+
+$.monthpicker._get(inst, "stepBigYears") :
|
|
487
|
+
+$.monthpicker._get(inst, "stepYears")), "Y");
|
|
488
|
+
}
|
|
489
|
+
// next year on alt +right
|
|
490
|
+
break;
|
|
491
|
+
case 40: if (event.ctrlKey || event.metaKey) {
|
|
492
|
+
$.monthpicker._adjustDate(event.target, +3, "M");
|
|
493
|
+
}
|
|
494
|
+
handled = event.ctrlKey || event.metaKey;
|
|
495
|
+
break; // +1 quarter on ctrl or command +down
|
|
496
|
+
default: handled = false;
|
|
497
|
+
}
|
|
498
|
+
} else if (event.keyCode === 36 && event.ctrlKey) { // display the date picker on ctrl+home
|
|
499
|
+
$.monthpicker._showMonthpicker(this);
|
|
500
|
+
} else {
|
|
501
|
+
handled = false;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
if (handled) {
|
|
505
|
+
event.preventDefault();
|
|
506
|
+
event.stopPropagation();
|
|
507
|
+
}
|
|
508
|
+
},
|
|
509
|
+
|
|
510
|
+
/* Is the first field in a jQuery collection disabled as a monthpicker?
|
|
511
|
+
@param target element - the target input field or division or span
|
|
512
|
+
@return boolean - true if disabled, false if enabled */
|
|
513
|
+
_isDisabledMonthpicker: function(target) {
|
|
514
|
+
if (!target) {
|
|
515
|
+
return false;
|
|
516
|
+
}
|
|
517
|
+
for (var i = 0; i < this._disabledInputs.length; i++) {
|
|
518
|
+
if (this._disabledInputs[i] == target)
|
|
519
|
+
return true;
|
|
520
|
+
}
|
|
521
|
+
return false;
|
|
522
|
+
},
|
|
523
|
+
|
|
524
|
+
/* Tidy up after a dialog display. */
|
|
525
|
+
_tidyDialog: function(inst) {
|
|
526
|
+
inst.dpDiv.removeClass(this._dialogClass).unbind('.ui-monthpicker-calendar');
|
|
527
|
+
},
|
|
528
|
+
|
|
529
|
+
/* Retrieve the size of left and top borders for an element.
|
|
530
|
+
@param elem (jQuery object) the element of interest
|
|
531
|
+
@return (number[2]) the left and top borders */
|
|
532
|
+
_getBorders: function(elem) {
|
|
533
|
+
var convert = function(value) {
|
|
534
|
+
return {thin: 1, medium: 2, thick: 3}[value] || value;
|
|
535
|
+
};
|
|
536
|
+
return [parseFloat(convert(elem.css('border-left-width'))),
|
|
537
|
+
parseFloat(convert(elem.css('border-top-width')))];
|
|
538
|
+
},
|
|
539
|
+
|
|
540
|
+
/* Check positioning to remain on screen. */
|
|
541
|
+
_checkOffset: function(inst, offset, isFixed) {
|
|
542
|
+
var dpWidth = inst.dpDiv.outerWidth();
|
|
543
|
+
var dpHeight = inst.dpDiv.outerHeight();
|
|
544
|
+
var inputWidth = inst.input ? inst.input.outerWidth() : 0;
|
|
545
|
+
var inputHeight = inst.input ? inst.input.outerHeight() : 0;
|
|
546
|
+
var viewWidth = document.documentElement.clientWidth + $(document).scrollLeft();
|
|
547
|
+
var viewHeight = document.documentElement.clientHeight + $(document).scrollTop();
|
|
548
|
+
|
|
549
|
+
offset.left -= (isFixed && offset.left == inst.input.offset().left) ? $(document).scrollLeft() : 0;
|
|
550
|
+
offset.top -= (isFixed && offset.top == (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;
|
|
551
|
+
|
|
552
|
+
// now check if monthpicker is showing outside window viewport - move to a better place if so.
|
|
553
|
+
offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
|
|
554
|
+
Math.abs(offset.left + dpWidth - viewWidth) : 0);
|
|
555
|
+
offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
|
|
556
|
+
Math.abs(dpHeight + inputHeight) : 0);
|
|
557
|
+
|
|
558
|
+
return offset;
|
|
559
|
+
},
|
|
560
|
+
|
|
561
|
+
/* Find an object's position on the screen. */
|
|
562
|
+
_findPos: function(obj) {
|
|
563
|
+
var inst = this._getInst(obj);
|
|
564
|
+
while (obj && (obj.type == 'hidden' || obj.nodeType != 1 || $.expr.filters.hidden(obj))) {
|
|
565
|
+
obj = obj['nextSibling'];
|
|
566
|
+
}
|
|
567
|
+
var position = $(obj).offset();
|
|
568
|
+
return [position.left, position.top];
|
|
569
|
+
},
|
|
570
|
+
|
|
571
|
+
/* Adjust one of the month sub-fields. */
|
|
572
|
+
_adjustDate: function(id, offset, period) {
|
|
573
|
+
var target = $(id);
|
|
574
|
+
var inst = this._getInst(target[0]);
|
|
575
|
+
if (this._isDisabledMonthpicker(target[0])) {
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
578
|
+
this._adjustInstDate(inst, offset, period);
|
|
579
|
+
this._updateMonthpicker(inst);
|
|
580
|
+
},
|
|
581
|
+
|
|
582
|
+
/* Adjust one of the date sub-fields. */
|
|
583
|
+
_adjustInstDate: function(inst, offset, period) {
|
|
584
|
+
var year = inst.drawYear + (period == 'Y' ? offset : 0);
|
|
585
|
+
var month = Math.min(inst.selectedMonth, 12) + (period === "M" ? offset : 0);
|
|
586
|
+
var date = this._restrictMinMax(inst, new Date(year, month, 1));
|
|
587
|
+
inst.drawYear = inst.selectedYear = date.getFullYear();
|
|
588
|
+
inst.selectedMonth = date.getMonth();
|
|
589
|
+
|
|
590
|
+
if (period == 'Y') {
|
|
591
|
+
this._notifyChange(inst);
|
|
592
|
+
}
|
|
593
|
+
},
|
|
594
|
+
|
|
595
|
+
/* Notify change of month/year. */
|
|
596
|
+
_notifyChange: function(inst) {
|
|
597
|
+
var onChange = this._get(inst, 'onChangeYear');
|
|
598
|
+
if (onChange)
|
|
599
|
+
onChange.apply((inst.input ? inst.input[0] : null), [inst.selectedYear, inst]);
|
|
600
|
+
},
|
|
601
|
+
|
|
602
|
+
/* Detach a datepicker from its control.
|
|
603
|
+
* @param target element - the target input field or division or span
|
|
604
|
+
*/
|
|
605
|
+
_destroyMonthpicker: function(target) {
|
|
606
|
+
var nodeName,
|
|
607
|
+
$target = $(target),
|
|
608
|
+
inst = $.data(target, PROP_NAME);
|
|
609
|
+
|
|
610
|
+
if (!$target.hasClass(this.markerClassName)) {
|
|
611
|
+
return;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
nodeName = target.nodeName.toLowerCase();
|
|
615
|
+
$.removeData(target, PROP_NAME);
|
|
616
|
+
if (nodeName === "input") {
|
|
617
|
+
inst.append.remove();
|
|
618
|
+
inst.trigger.remove();
|
|
619
|
+
$target.removeClass(this.markerClassName).
|
|
620
|
+
unbind("focus", this._showMonthpicker).
|
|
621
|
+
unbind("keydown", this._doKeyDown).
|
|
622
|
+
unbind("keypress", this._doKeyPress).
|
|
623
|
+
unbind("keyup", this._doKeyUp);
|
|
624
|
+
} else if (nodeName === "div" || nodeName === "span") {
|
|
625
|
+
$target.removeClass(this.markerClassName).empty();
|
|
626
|
+
}
|
|
627
|
+
},
|
|
628
|
+
|
|
629
|
+
/* Enable the date picker to a jQuery selection.
|
|
630
|
+
@param target element - the target input field or division or span */
|
|
631
|
+
_enableMonthpicker: function(target) {
|
|
632
|
+
var $target = $(target);
|
|
633
|
+
var inst = $.data(target, PROP_NAME);
|
|
634
|
+
if (!$target.hasClass(this.markerClassName)) {
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
var nodeName = target.nodeName.toLowerCase();
|
|
638
|
+
if (nodeName == 'input') {
|
|
639
|
+
target.disabled = false;
|
|
640
|
+
inst.trigger.filter('button').
|
|
641
|
+
each(function() { this.disabled = false; }).end().
|
|
642
|
+
filter('img').css({opacity: '1.0', cursor: ''});
|
|
643
|
+
}
|
|
644
|
+
this._disabledInputs = $.map(this._disabledInputs,
|
|
645
|
+
function(value) { return (value == target ? null : value); }); // delete entry
|
|
646
|
+
},
|
|
647
|
+
|
|
648
|
+
/* Disable the month picker to a jQuery selection.
|
|
649
|
+
@param target element - the target input field or division or span */
|
|
650
|
+
_disableMonthpicker: function(target) {
|
|
651
|
+
var $target = $(target);
|
|
652
|
+
var inst = $.data(target, PROP_NAME);
|
|
653
|
+
if (!$target.hasClass(this.markerClassName)) {
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
var nodeName = target.nodeName.toLowerCase();
|
|
657
|
+
if (nodeName == 'input') {
|
|
658
|
+
target.disabled = true;
|
|
659
|
+
inst.trigger.filter('button').
|
|
660
|
+
each(function() { this.disabled = true; }).end().
|
|
661
|
+
filter('img').css({opacity: '0.5', cursor: 'default'});
|
|
662
|
+
}
|
|
663
|
+
this._disabledInputs = $.map(this._disabledInputs,
|
|
664
|
+
function(value) { return (value == target ? null : value); }); // delete entry
|
|
665
|
+
this._disabledInputs[this._disabledInputs.length] = target;
|
|
666
|
+
},
|
|
667
|
+
|
|
668
|
+
/* Generate the HTML for the current state of the date picker. */
|
|
669
|
+
_generateHTML: function(inst) {
|
|
670
|
+
var printDate, hideIfNoPrevNext;
|
|
671
|
+
|
|
672
|
+
hideIfNoPrevNext = false;
|
|
673
|
+
var today = new Date();
|
|
674
|
+
today = new Date(today.getFullYear(), today.getMonth(), today.getDate()); // clear time
|
|
675
|
+
var currentDate = (!inst.currentMonth ? new Date(9999, 9, 9) :
|
|
676
|
+
new Date(inst.currentYear, inst.currentMonth, 1));
|
|
677
|
+
var html = '';
|
|
678
|
+
var year = currentDate && currentDate.year ? currentDate.year : 2011;
|
|
679
|
+
var prevText = this._get(inst, 'prevText');
|
|
680
|
+
var nextText = this._get(inst, 'nextText');
|
|
681
|
+
var stepYears = this._get(inst, 'stepYears');
|
|
682
|
+
var monthNames = this._get(inst, 'monthNames');
|
|
683
|
+
var monthNamesShort = this._get(inst, 'monthNamesShort');
|
|
684
|
+
var drawYear = inst.drawYear;
|
|
685
|
+
var showButtonPanel = this._get(inst, "showButtonPanel");
|
|
686
|
+
var isRTL = this._get(inst, "isRTL");
|
|
687
|
+
var defaultDate = this._getDefaultDate(inst);
|
|
688
|
+
var navigationAsDateFormat = this._get(inst, "navigationAsDateFormat");
|
|
689
|
+
defaultDate.setDate(1);
|
|
690
|
+
|
|
691
|
+
prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
|
|
692
|
+
new Date(drawYear - stepYears, 1, 1),
|
|
693
|
+
this._getFormatConfig(inst)));
|
|
694
|
+
nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
|
|
695
|
+
new Date(drawYear + stepYears, 1, 1),
|
|
696
|
+
this._getFormatConfig(inst)));
|
|
697
|
+
|
|
698
|
+
var prev = (this._canAdjustYear(inst, -1, drawYear) ?
|
|
699
|
+
"<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
|
|
700
|
+
" title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>" :
|
|
701
|
+
(hideIfNoPrevNext ? "" : "<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='"+ prevText +"'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>"));
|
|
702
|
+
|
|
703
|
+
var next = (this._canAdjustYear(inst, +1, drawYear) ?
|
|
704
|
+
"<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
|
|
705
|
+
" title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>" :
|
|
706
|
+
(hideIfNoPrevNext ? "" : "<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='"+ nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>"));
|
|
707
|
+
|
|
708
|
+
html += '<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix ui-corner-all">' +
|
|
709
|
+
prev + next + this._generateYearHeader(inst, drawYear) + // draw year header
|
|
710
|
+
'</div><table class="ui-datepicker-calendar"><tbody>';
|
|
711
|
+
|
|
712
|
+
// draw months table
|
|
713
|
+
for(var month = 0; month <= 11; month++) {
|
|
714
|
+
if (month % 3 === 0) {
|
|
715
|
+
html += '<tr>';
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
printDate = new Date(drawYear, month, 1);
|
|
719
|
+
var selectedDate = new Date(drawYear, inst.selectedMonth, 1);
|
|
720
|
+
|
|
721
|
+
html += '<td class="'
|
|
722
|
+
+ (drawYear == inst.currentYear && month == inst.currentMonth ? " " + this._currentClass : "") // highlight selected month
|
|
723
|
+
+ ((month === inst.selectedMonth && drawYear === inst.selectedYear && inst._keyEvent) || // user pressed key
|
|
724
|
+
(defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime()) ?
|
|
725
|
+
// or defaultDate is current printedDate and defaultDate is selectedDate
|
|
726
|
+
" " + this._dayOverClass : "") // highlight selected day
|
|
727
|
+
+ '" data-month="' + month + '" data-year="' + drawYear + '" data-handler="selectMonth" data-event="click">'
|
|
728
|
+
+ '<a class="ui-state-default'
|
|
729
|
+
+ (drawYear == inst.currentYear && month == inst.currentMonth ? ' ui-state-active' : '') // highlight selected month
|
|
730
|
+
+ (drawYear == today.getFullYear() && month == today.getMonth() ? ' ui-state-highlight' : '') // highlight today (if different)
|
|
731
|
+
+ '" href="#">' + (inst.settings && inst.settings.monthNamesShort ? inst.settings.monthNamesShort[month] : this._defaults.monthNamesShort[month]) + '</a>' + '</td>'; // display selectable date
|
|
732
|
+
|
|
733
|
+
if (month % 3 === 2) {
|
|
734
|
+
html += '</tr>';
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
html += '</tbody></table>';
|
|
738
|
+
|
|
739
|
+
var controls = "<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>" +
|
|
740
|
+
this._get(inst, "closeText") + "</button>";
|
|
741
|
+
|
|
742
|
+
var currentText = this._get(inst, "currentText");
|
|
743
|
+
var gotoDate = (this._get(inst, "gotoCurrent") && inst.currentMonth ? currentDate : today);
|
|
744
|
+
currentText = (!navigationAsDateFormat ? currentText :
|
|
745
|
+
this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
|
|
746
|
+
|
|
747
|
+
var buttonPanel = (showButtonPanel) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + (isRTL ? controls : "") +
|
|
748
|
+
"<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='current' data-event='click'" +
|
|
749
|
+
">" + currentText + "</button>" + (isRTL ? "" : controls) + "</div>" : "";
|
|
750
|
+
|
|
751
|
+
html += buttonPanel;
|
|
752
|
+
|
|
753
|
+
return html;
|
|
754
|
+
},
|
|
755
|
+
|
|
756
|
+
/* Generate the year header. */
|
|
757
|
+
_generateYearHeader: function(inst, drawYear) {
|
|
758
|
+
var changeYear = this._get(inst, 'changeYear');
|
|
759
|
+
var html = '<div class="ui-datepicker-title">';
|
|
760
|
+
// year selection
|
|
761
|
+
if ( !inst.yearshtml ) {
|
|
762
|
+
inst.yearshtml = '';
|
|
763
|
+
|
|
764
|
+
if (changeYear) {
|
|
765
|
+
// determine range of years to display
|
|
766
|
+
var years = this._get(inst, 'yearRange').split(':');
|
|
767
|
+
var thisYear = new Date().getFullYear();
|
|
768
|
+
var determineYear = function(value) {
|
|
769
|
+
var year = (value.match(/c[+-].*/) ? drawYear + parseInt(value.substring(1), 10) :
|
|
770
|
+
(value.match(/[+-].*/) ? thisYear + parseInt(value, 10) :
|
|
771
|
+
parseInt(value, 10)));
|
|
772
|
+
return (isNaN(year) ? thisYear : year);
|
|
773
|
+
};
|
|
774
|
+
var year = determineYear(years[0]);
|
|
775
|
+
var endYear = Math.max(year, determineYear(years[1] || ''));
|
|
776
|
+
|
|
777
|
+
inst.yearshtml += '<select class="ui-datepicker-year" ' +
|
|
778
|
+
"data-handler='selectYear' data-event='change'>";
|
|
779
|
+
|
|
780
|
+
for (; year <= endYear; year++) {
|
|
781
|
+
inst.yearshtml += '<option value="' + year + '"' +
|
|
782
|
+
(year == drawYear ? ' selected="selected"' : '') +
|
|
783
|
+
'>' + year + '</option>';
|
|
784
|
+
}
|
|
785
|
+
inst.yearshtml += '</select>';
|
|
786
|
+
} else {
|
|
787
|
+
inst.yearshtml += '<span class="ui-datepicker-year">' + drawYear + '</span>';
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
html += inst.yearshtml;
|
|
791
|
+
inst.yearshtml = null;
|
|
792
|
+
}
|
|
793
|
+
html += this._get(inst, 'yearSuffix');
|
|
794
|
+
html += '</div>'; // Close monthpicker_header
|
|
795
|
+
return html;
|
|
796
|
+
},
|
|
797
|
+
|
|
798
|
+
/* Provide the configuration settings for formatting/parsing. */
|
|
799
|
+
_getFormatConfig: function(inst) {
|
|
800
|
+
var shortYearCutoff = this._get(inst, 'shortYearCutoff');
|
|
801
|
+
shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff :
|
|
802
|
+
new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
|
|
803
|
+
return {shortYearCutoff: shortYearCutoff,
|
|
804
|
+
dayNamesShort: this._get(inst, 'dayNamesShort'), dayNames: this._get(inst, 'dayNames'),
|
|
805
|
+
monthNamesShort: this._get(inst, 'monthNamesShort'), monthNames: this._get(inst, 'monthNames')};
|
|
806
|
+
},
|
|
807
|
+
|
|
808
|
+
/* Parse existing date and initialise date picker. */
|
|
809
|
+
_setDateFromField: function(inst, noDefault) {
|
|
810
|
+
if (inst.input.val() == inst.lastVal) {
|
|
811
|
+
return;
|
|
812
|
+
}
|
|
813
|
+
var dateFormat = this._get(inst, 'dateFormat');
|
|
814
|
+
var dates = inst.lastVal = inst.input ? inst.input.val() : null;
|
|
815
|
+
var date, defaultDate;
|
|
816
|
+
date = defaultDate = this._getDefaultDate(inst);
|
|
817
|
+
var settings = this._getFormatConfig(inst);
|
|
818
|
+
try {
|
|
819
|
+
date = this.parseDate(dateFormat, dates, settings) || defaultDate;
|
|
820
|
+
} catch (event) {
|
|
821
|
+
this.log(event);
|
|
822
|
+
dates = (noDefault ? '' : dates);
|
|
823
|
+
}
|
|
824
|
+
inst.selectedMonth = date.getMonth();
|
|
825
|
+
inst.drawYear = inst.selectedYear = date.getFullYear();
|
|
826
|
+
inst.currentMonth = (dates ? date.getMonth() : 0);
|
|
827
|
+
inst.currentYear = (dates ? date.getFullYear() : 0);
|
|
828
|
+
this._adjustInstDate(inst);
|
|
829
|
+
},
|
|
830
|
+
|
|
831
|
+
/* Retrieve the default date shown on opening. */
|
|
832
|
+
_getDefaultDate: function(inst) {
|
|
833
|
+
return this._restrictMinMax(inst,
|
|
834
|
+
this._determineDate(inst, this._get(inst, 'defaultDate'), new Date()));
|
|
835
|
+
},
|
|
836
|
+
|
|
837
|
+
/* A date may be specified as an exact value or a relative one. */
|
|
838
|
+
_determineDate: function(inst, date, defaultDate) {
|
|
839
|
+
var offsetNumeric = function(offset) {
|
|
840
|
+
var date = new Date();
|
|
841
|
+
date.setDate(1);
|
|
842
|
+
date.setMonth(date.getMonth() + offset);
|
|
843
|
+
return date;
|
|
844
|
+
};
|
|
845
|
+
var offsetString = function(offset) {
|
|
846
|
+
try {
|
|
847
|
+
return $.monthpicker.parseDate($.monthpicker._get(inst, 'dateFormat'),
|
|
848
|
+
offset, $.monthpicker._getFormatConfig(inst));
|
|
849
|
+
}
|
|
850
|
+
catch (e) {
|
|
851
|
+
// Ignore
|
|
852
|
+
}
|
|
853
|
+
var date = (offset.toLowerCase().match(/^c/) ?
|
|
854
|
+
$.monthpicker._getDate(inst) : null) || new Date();
|
|
855
|
+
var year = date.getFullYear();
|
|
856
|
+
var month = date.getMonth();
|
|
857
|
+
var day = 1;
|
|
858
|
+
var pattern = /([+-]?[0-9]+)\s*(m|M|y|Y)?/g;
|
|
859
|
+
var matches = pattern.exec(offset);
|
|
860
|
+
while (matches) {
|
|
861
|
+
switch (matches[2] || 'm') {
|
|
862
|
+
case 'm' : case 'M' :
|
|
863
|
+
month += parseInt(matches[1],10);
|
|
864
|
+
day = 1
|
|
865
|
+
break;
|
|
866
|
+
case 'y': case 'Y' :
|
|
867
|
+
year += parseInt(matches[1],10);
|
|
868
|
+
day = 1
|
|
869
|
+
break;
|
|
870
|
+
}
|
|
871
|
+
matches = pattern.exec(offset);
|
|
872
|
+
}
|
|
873
|
+
return new Date(year, month, day);
|
|
874
|
+
};
|
|
875
|
+
var newDate = (date == null || date === '' ? defaultDate : (typeof date == 'string' ? offsetString(date) :
|
|
876
|
+
(typeof date == 'number' ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime()))));
|
|
877
|
+
newDate = (newDate && newDate.toString() == 'Invalid Date' ? defaultDate : newDate);
|
|
878
|
+
if (newDate) {
|
|
879
|
+
newDate.setHours(0);
|
|
880
|
+
newDate.setMinutes(0);
|
|
881
|
+
newDate.setSeconds(0);
|
|
882
|
+
newDate.setMilliseconds(0);
|
|
883
|
+
}
|
|
884
|
+
return newDate;
|
|
885
|
+
},
|
|
886
|
+
|
|
887
|
+
/* Determine the current maximum date - ensure no time components are set. */
|
|
888
|
+
_getMinMaxDate: function(inst, minMax) {
|
|
889
|
+
return this._determineDate(inst, this._get(inst, minMax + 'Date'), null);
|
|
890
|
+
},
|
|
891
|
+
|
|
892
|
+
/* Ensure a date is within any min/max bounds. */
|
|
893
|
+
_restrictMinMax: function(inst, date) {
|
|
894
|
+
var minDate = this._getMinMaxDate(inst, 'min');
|
|
895
|
+
var maxDate = this._getMinMaxDate(inst, 'max');
|
|
896
|
+
var newDate = (minDate && date < minDate ? minDate : date);
|
|
897
|
+
newDate = (maxDate && newDate > maxDate ? maxDate : newDate);
|
|
898
|
+
return newDate;
|
|
899
|
+
},
|
|
900
|
+
|
|
901
|
+
/* Determines if we should allow a "next/prev" year display change. */
|
|
902
|
+
_canAdjustYear: function(inst, offset, curYear) {
|
|
903
|
+
var date = new Date(curYear + offset, 1, 1);
|
|
904
|
+
return this._isInRange(inst, date);
|
|
905
|
+
},
|
|
906
|
+
|
|
907
|
+
/* Is the given date in the accepted range? */
|
|
908
|
+
_isInRange: function(inst, date) {
|
|
909
|
+
var yearSplit, currentYear,
|
|
910
|
+
minDate = this._getMinMaxDate(inst, "min"),
|
|
911
|
+
maxDate = this._getMinMaxDate(inst, "max"),
|
|
912
|
+
minYear = null,
|
|
913
|
+
maxYear = null,
|
|
914
|
+
years = this._get(inst, "yearRange");
|
|
915
|
+
if (years){
|
|
916
|
+
yearSplit = years.split(":");
|
|
917
|
+
currentYear = new Date().getFullYear();
|
|
918
|
+
minYear = parseInt(yearSplit[0], 10);
|
|
919
|
+
maxYear = parseInt(yearSplit[1], 10);
|
|
920
|
+
if ( yearSplit[0].match(/[+\-].*/) ) {
|
|
921
|
+
minYear += currentYear;
|
|
922
|
+
}
|
|
923
|
+
if ( yearSplit[1].match(/[+\-].*/) ) {
|
|
924
|
+
maxYear += currentYear;
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
return ((!minDate || date.getTime() >= minDate.getTime()) &&
|
|
929
|
+
(!maxDate || date.getTime() <= maxDate.getTime()) &&
|
|
930
|
+
(!minYear || date.getFullYear() >= minYear) &&
|
|
931
|
+
(!maxYear || date.getFullYear() <= maxYear));
|
|
932
|
+
},
|
|
933
|
+
|
|
934
|
+
/* Action for selecting a new month/year. */
|
|
935
|
+
_selectYear: function(id, select, period) {
|
|
936
|
+
var target = $(id);
|
|
937
|
+
var inst = this._getInst(target[0]);
|
|
938
|
+
inst['selected' + (period == 'M' ? 'Month' : 'Year')] =
|
|
939
|
+
inst['draw' + (period == 'M' ? 'Month' : 'Year')] =
|
|
940
|
+
parseInt(select.options[select.selectedIndex].value,10);
|
|
941
|
+
this._notifyChange(inst);
|
|
942
|
+
this._adjustDate(target);
|
|
943
|
+
},
|
|
944
|
+
|
|
945
|
+
/* Action for current link. */
|
|
946
|
+
_gotoCurrent: function(id) {
|
|
947
|
+
var date,
|
|
948
|
+
target = $(id),
|
|
949
|
+
inst = this._getInst(target[0]);
|
|
950
|
+
|
|
951
|
+
if (this._get(inst, "gotoCurrent") && inst.currentYear) {
|
|
952
|
+
inst.selectedDay = inst.currentDay;
|
|
953
|
+
inst.drawMonth = inst.selectedMonth = inst.currentMonth;
|
|
954
|
+
inst.drawYear = inst.selectedYear = inst.currentYear;
|
|
955
|
+
} else {
|
|
956
|
+
date = new Date();
|
|
957
|
+
inst.selectedDay = date.getDate();
|
|
958
|
+
inst.drawMonth = inst.selectedMonth = date.getMonth();
|
|
959
|
+
inst.drawYear = inst.selectedYear = date.getFullYear();
|
|
960
|
+
}
|
|
961
|
+
this._notifyChange(inst);
|
|
962
|
+
this._adjustDate(target);
|
|
963
|
+
},
|
|
964
|
+
|
|
965
|
+
/* Action for selecting a month. */
|
|
966
|
+
_selectMonth: function(id, year, month, td) {
|
|
967
|
+
var target = $(id);
|
|
968
|
+
var inst = this._getInst(target[0]);
|
|
969
|
+
|
|
970
|
+
if ($(td).hasClass(this._unselectableClass) || this._isDisabledMonthpicker(target[0])) {
|
|
971
|
+
return;
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
inst.selectedMonth = inst.currentMonth = month;
|
|
975
|
+
inst.selectedYear = inst.currentYear = year;
|
|
976
|
+
this._selectDate(id, this._formatDate(inst, inst.currentMonth, inst.currentYear));
|
|
977
|
+
},
|
|
978
|
+
|
|
979
|
+
/* Parse a string value into a date object.
|
|
980
|
+
See formatDate below for the possible formats.
|
|
981
|
+
|
|
982
|
+
@param format string - the expected format of the date
|
|
983
|
+
@param value string - the date in the above format
|
|
984
|
+
@param settings Object - attributes include:
|
|
985
|
+
shortYearCutoff number - the cutoff year for determining the century (optional)
|
|
986
|
+
monthNamesShort string[12] - abbreviated names of the months (optional)
|
|
987
|
+
monthNames string[12] - names of the months (optional)
|
|
988
|
+
@return Date - the extracted date value or null if value is blank */
|
|
989
|
+
parseDate: function (format, value, settings) {
|
|
990
|
+
if (format == null || value == null)
|
|
991
|
+
throw 'Invalid arguments';
|
|
992
|
+
value = (typeof value == 'object' ? value.toString() : value + '');
|
|
993
|
+
if (value == '')
|
|
994
|
+
return null;
|
|
995
|
+
var shortYearCutoff = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff;
|
|
996
|
+
shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff :
|
|
997
|
+
new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
|
|
998
|
+
var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort;
|
|
999
|
+
var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames;
|
|
1000
|
+
var year = -1;
|
|
1001
|
+
var month = -1;
|
|
1002
|
+
var literal = false;
|
|
1003
|
+
// Check whether a format character is doubled
|
|
1004
|
+
var lookAhead = function(match) {
|
|
1005
|
+
var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
|
|
1006
|
+
if (matches)
|
|
1007
|
+
iFormat++;
|
|
1008
|
+
return matches;
|
|
1009
|
+
};
|
|
1010
|
+
// Extract a number from the string value
|
|
1011
|
+
var getNumber = function(match) {
|
|
1012
|
+
var isDoubled = lookAhead(match);
|
|
1013
|
+
var size = (match == '@' ? 14 : (match == '!' ? 20 :
|
|
1014
|
+
(match == 'y' && isDoubled ? 4 : (match == 'o' ? 3 : 2))));
|
|
1015
|
+
var digits = new RegExp('^\\d{1,' + size + '}');
|
|
1016
|
+
var num = value.substring(iValue).match(digits);
|
|
1017
|
+
if (!num)
|
|
1018
|
+
throw 'Missing number at position ' + iValue;
|
|
1019
|
+
iValue += num[0].length;
|
|
1020
|
+
return parseInt(num[0], 10);
|
|
1021
|
+
};
|
|
1022
|
+
// Extract a name from the string value and convert to an index
|
|
1023
|
+
var getName = function(match, shortNames, longNames) {
|
|
1024
|
+
var names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) {
|
|
1025
|
+
return [ [k, v] ];
|
|
1026
|
+
}).sort(function (a, b) {
|
|
1027
|
+
return -(a[1].length - b[1].length);
|
|
1028
|
+
});
|
|
1029
|
+
var index = -1;
|
|
1030
|
+
$.each(names, function (i, pair) {
|
|
1031
|
+
var name = pair[1];
|
|
1032
|
+
if (value.substr(iValue, name.length).toLowerCase() == name.toLowerCase()) {
|
|
1033
|
+
index = pair[0];
|
|
1034
|
+
iValue += name.length;
|
|
1035
|
+
return false;
|
|
1036
|
+
}
|
|
1037
|
+
});
|
|
1038
|
+
if (index != -1)
|
|
1039
|
+
return index + 1;
|
|
1040
|
+
else
|
|
1041
|
+
throw 'Unknown name at position ' + iValue;
|
|
1042
|
+
};
|
|
1043
|
+
// Confirm that a literal character matches the string value
|
|
1044
|
+
var checkLiteral = function() {
|
|
1045
|
+
if (value.charAt(iValue) != format.charAt(iFormat))
|
|
1046
|
+
throw 'Unexpected literal at position ' + iValue;
|
|
1047
|
+
iValue++;
|
|
1048
|
+
};
|
|
1049
|
+
var iValue = 0;
|
|
1050
|
+
for (var iFormat = 0; iFormat < format.length; iFormat++) {
|
|
1051
|
+
if (literal)
|
|
1052
|
+
if (format.charAt(iFormat) == "'" && !lookAhead("'"))
|
|
1053
|
+
literal = false;
|
|
1054
|
+
else
|
|
1055
|
+
checkLiteral();
|
|
1056
|
+
else
|
|
1057
|
+
switch (format.charAt(iFormat)) {
|
|
1058
|
+
case 'm':
|
|
1059
|
+
month = getNumber('m');
|
|
1060
|
+
break;
|
|
1061
|
+
case 'M':
|
|
1062
|
+
month = getName('M', monthNamesShort, monthNames);
|
|
1063
|
+
break;
|
|
1064
|
+
case 'y':
|
|
1065
|
+
year = getNumber('y');
|
|
1066
|
+
break;
|
|
1067
|
+
case '@':
|
|
1068
|
+
var date = new Date(getNumber('@'));
|
|
1069
|
+
year = date.getFullYear();
|
|
1070
|
+
month = date.getMonth() + 1;
|
|
1071
|
+
day = date.getDate();
|
|
1072
|
+
break;
|
|
1073
|
+
case '!':
|
|
1074
|
+
var date = new Date((getNumber('!') - this._ticksTo1970) / 10000);
|
|
1075
|
+
year = date.getFullYear();
|
|
1076
|
+
month = date.getMonth() + 1;
|
|
1077
|
+
break;
|
|
1078
|
+
case "'":
|
|
1079
|
+
if (lookAhead("'"))
|
|
1080
|
+
checkLiteral();
|
|
1081
|
+
else
|
|
1082
|
+
literal = true;
|
|
1083
|
+
break;
|
|
1084
|
+
default:
|
|
1085
|
+
checkLiteral();
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
if (iValue < value.length){
|
|
1089
|
+
throw "Extra/unparsed characters found in date: " + value.substring(iValue);
|
|
1090
|
+
}
|
|
1091
|
+
if (year == -1)
|
|
1092
|
+
year = new Date().getFullYear();
|
|
1093
|
+
else if (year < 100)
|
|
1094
|
+
year += new Date().getFullYear() - new Date().getFullYear() % 100 +
|
|
1095
|
+
(year <= shortYearCutoff ? 0 : -100);
|
|
1096
|
+
var date = new Date(year, month - 1, 1);
|
|
1097
|
+
if (date.getFullYear() != year || date.getMonth() + 1 != month || date.getDate() != 1)
|
|
1098
|
+
throw 'Invalid date'; // E.g. 31/02/00
|
|
1099
|
+
return date;
|
|
1100
|
+
},
|
|
1101
|
+
|
|
1102
|
+
/* Format a date object into a string value.
|
|
1103
|
+
The format can be combinations of the following:
|
|
1104
|
+
d - day of month (no leading zero)
|
|
1105
|
+
dd - day of month (two digit)
|
|
1106
|
+
o - day of year (no leading zeros)
|
|
1107
|
+
oo - day of year (three digit)
|
|
1108
|
+
D - day name short
|
|
1109
|
+
DD - day name long
|
|
1110
|
+
m - month of year (no leading zero)
|
|
1111
|
+
mm - month of year (two digit)
|
|
1112
|
+
M - month name short
|
|
1113
|
+
MM - month name long
|
|
1114
|
+
y - year (two digit)
|
|
1115
|
+
yy - year (four digit)
|
|
1116
|
+
@ - Unix timestamp (ms since 01/01/1970)
|
|
1117
|
+
! - Windows ticks (100ns since 01/01/0001)
|
|
1118
|
+
'...' - literal text
|
|
1119
|
+
'' - single quote
|
|
1120
|
+
|
|
1121
|
+
@param format string - the desired format of the date
|
|
1122
|
+
@param date Date - the date value to format
|
|
1123
|
+
@param settings Object - attributes include:
|
|
1124
|
+
dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
|
|
1125
|
+
dayNames string[7] - names of the days from Sunday (optional)
|
|
1126
|
+
monthNamesShort string[12] - abbreviated names of the months (optional)
|
|
1127
|
+
monthNames string[12] - names of the months (optional)
|
|
1128
|
+
@return string - the date in the above format */
|
|
1129
|
+
formatDate: function (format, date, settings) {
|
|
1130
|
+
if (!date)
|
|
1131
|
+
return '';
|
|
1132
|
+
var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort;
|
|
1133
|
+
var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames;
|
|
1134
|
+
// Check whether a format character is doubled
|
|
1135
|
+
var lookAhead = function(match) {
|
|
1136
|
+
var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
|
|
1137
|
+
if (matches)
|
|
1138
|
+
iFormat++;
|
|
1139
|
+
return matches;
|
|
1140
|
+
};
|
|
1141
|
+
// Format a number, with leading zero if necessary
|
|
1142
|
+
var formatNumber = function(match, value, len) {
|
|
1143
|
+
var num = '' + value;
|
|
1144
|
+
if (lookAhead(match))
|
|
1145
|
+
while (num.length < len)
|
|
1146
|
+
num = '0' + num;
|
|
1147
|
+
return num;
|
|
1148
|
+
};
|
|
1149
|
+
// Format a name, short or long as requested
|
|
1150
|
+
var formatName = function(match, value, shortNames, longNames) {
|
|
1151
|
+
return (lookAhead(match) ? longNames[value] : shortNames[value]);
|
|
1152
|
+
};
|
|
1153
|
+
var output = '';
|
|
1154
|
+
var literal = false;
|
|
1155
|
+
if (date)
|
|
1156
|
+
for (var iFormat = 0; iFormat < format.length; iFormat++) {
|
|
1157
|
+
if (literal)
|
|
1158
|
+
if (format.charAt(iFormat) == "'" && !lookAhead("'"))
|
|
1159
|
+
literal = false;
|
|
1160
|
+
else
|
|
1161
|
+
output += format.charAt(iFormat);
|
|
1162
|
+
else
|
|
1163
|
+
switch (format.charAt(iFormat)) {
|
|
1164
|
+
case 'm':
|
|
1165
|
+
output += formatNumber('m', date.getMonth() + 1, 2);
|
|
1166
|
+
break;
|
|
1167
|
+
case 'M':
|
|
1168
|
+
output += formatName('M', date.getMonth(), monthNamesShort, monthNames);
|
|
1169
|
+
break;
|
|
1170
|
+
case 'y':
|
|
1171
|
+
output += (lookAhead('y') ? date.getFullYear() :
|
|
1172
|
+
(date.getYear() % 100 < 10 ? '0' : '') + date.getYear() % 100);
|
|
1173
|
+
break;
|
|
1174
|
+
case '@':
|
|
1175
|
+
output += date.getTime();
|
|
1176
|
+
break;
|
|
1177
|
+
case '!':
|
|
1178
|
+
output += date.getTime() * 10000 + this._ticksTo1970;
|
|
1179
|
+
break;
|
|
1180
|
+
case "'":
|
|
1181
|
+
if (lookAhead("'"))
|
|
1182
|
+
output += "'";
|
|
1183
|
+
else
|
|
1184
|
+
literal = true;
|
|
1185
|
+
break;
|
|
1186
|
+
default:
|
|
1187
|
+
output += format.charAt(iFormat);
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
return output;
|
|
1191
|
+
},
|
|
1192
|
+
|
|
1193
|
+
/* Erase the input field and hide the date picker. */
|
|
1194
|
+
_clearDate: function(id) {
|
|
1195
|
+
var target = $(id);
|
|
1196
|
+
this._selectDate(target, "");
|
|
1197
|
+
},
|
|
1198
|
+
|
|
1199
|
+
/* Update the input field with the selected date. */
|
|
1200
|
+
_selectDate: function(id, dateStr) {
|
|
1201
|
+
var target = $(id);
|
|
1202
|
+
var inst = this._getInst(target[0]);
|
|
1203
|
+
dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
|
|
1204
|
+
if (inst.input)
|
|
1205
|
+
inst.input.val(dateStr);
|
|
1206
|
+
this._updateAlternate(inst);
|
|
1207
|
+
var onSelect = this._get(inst, 'onSelect');
|
|
1208
|
+
if (onSelect)
|
|
1209
|
+
onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback
|
|
1210
|
+
else if (inst.input)
|
|
1211
|
+
inst.input.trigger('change'); // fire the change event
|
|
1212
|
+
this._hideMonthpicker();
|
|
1213
|
+
this._lastInput = inst.input[0];
|
|
1214
|
+
if (typeof(inst.input[0]) != 'object')
|
|
1215
|
+
inst.input.focus(); // restore focus
|
|
1216
|
+
this._lastInput = null;
|
|
1217
|
+
},
|
|
1218
|
+
|
|
1219
|
+
/* Update any alternate field to synchronise with the main field. */
|
|
1220
|
+
_updateAlternate: function(inst) {
|
|
1221
|
+
var altField = this._get(inst, 'altField');
|
|
1222
|
+
if (altField) { // update alternate field too
|
|
1223
|
+
var altFormat = this._get(inst, 'altFormat') || this._get(inst, 'dateFormat');
|
|
1224
|
+
var date = this._getDate(inst);
|
|
1225
|
+
var dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));
|
|
1226
|
+
$(altField).each(function() { $(this).val(dateStr); });
|
|
1227
|
+
}
|
|
1228
|
+
},
|
|
1229
|
+
|
|
1230
|
+
/* Set the date(s) directly. */
|
|
1231
|
+
_setDate: function(inst, date, noChange) {
|
|
1232
|
+
var clear = !date,
|
|
1233
|
+
origMonth = inst.selectedMonth,
|
|
1234
|
+
origYear = inst.selectedYear,
|
|
1235
|
+
newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date()));
|
|
1236
|
+
|
|
1237
|
+
inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
|
|
1238
|
+
inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
|
|
1239
|
+
if ((origYear !== inst.selectedYear) && !noChange) {
|
|
1240
|
+
this._notifyChange(inst);
|
|
1241
|
+
}
|
|
1242
|
+
this._adjustInstDate(inst);
|
|
1243
|
+
if (inst.input) {
|
|
1244
|
+
inst.input.val(clear ? "" : this._formatDate(inst));
|
|
1245
|
+
}
|
|
1246
|
+
},
|
|
1247
|
+
|
|
1248
|
+
/* Set the dates for a jQuery selection.
|
|
1249
|
+
* @param target element - the target input field or division or span
|
|
1250
|
+
* @param date Date - the new date
|
|
1251
|
+
*/
|
|
1252
|
+
_setDateMonthpicker: function(target, date) {
|
|
1253
|
+
var inst = this._getInst(target);
|
|
1254
|
+
if (inst) {
|
|
1255
|
+
this._setDate(inst, date);
|
|
1256
|
+
this._updateMonthpicker(inst);
|
|
1257
|
+
this._updateAlternate(inst);
|
|
1258
|
+
}
|
|
1259
|
+
},
|
|
1260
|
+
|
|
1261
|
+
_getDate: function(inst) {
|
|
1262
|
+
var date = (!inst.currentYear || (inst.input && inst.input.val() === "") ? null :
|
|
1263
|
+
new Date(inst.currentYear, inst.currentMonth, 1));
|
|
1264
|
+
|
|
1265
|
+
return date;
|
|
1266
|
+
},
|
|
1267
|
+
|
|
1268
|
+
/* Attach the onxxx handlers. These are declared statically so
|
|
1269
|
+
* they work with static code transformers like Caja.
|
|
1270
|
+
*/
|
|
1271
|
+
_attachHandlers: function(inst) {
|
|
1272
|
+
var stepYears = this._get(inst, "stepYears"),
|
|
1273
|
+
id = "#" + inst.id.replace( /\\\\/g, "\\" );
|
|
1274
|
+
inst.dpDiv.find("[data-handler]").map(function () {
|
|
1275
|
+
var handler = {
|
|
1276
|
+
prev: function () {
|
|
1277
|
+
$.monthpicker._adjustDate(id, -stepYears, "Y");
|
|
1278
|
+
},
|
|
1279
|
+
next: function () {
|
|
1280
|
+
$.monthpicker._adjustDate(id, +stepYears, "Y");
|
|
1281
|
+
},
|
|
1282
|
+
hide: function () {
|
|
1283
|
+
$.monthpicker._hideMonthpicker();
|
|
1284
|
+
},
|
|
1285
|
+
current: function () {
|
|
1286
|
+
$.monthpicker._gotoCurrent(id);
|
|
1287
|
+
},
|
|
1288
|
+
selectMonth: function () {
|
|
1289
|
+
$.monthpicker._selectMonth(id, +this.getAttribute("data-year"), +this.getAttribute("data-month"), this);
|
|
1290
|
+
return false;
|
|
1291
|
+
},
|
|
1292
|
+
selectYear: function () {
|
|
1293
|
+
$.monthpicker._selectYear(id, this, "Y");
|
|
1294
|
+
return false;
|
|
1295
|
+
}
|
|
1296
|
+
};
|
|
1297
|
+
$(this).bind(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]);
|
|
1298
|
+
});
|
|
1299
|
+
},
|
|
1300
|
+
|
|
1301
|
+
/* Update or retrieve the settings for a month picker attached to an input field or division.
|
|
1302
|
+
* @param target element - the target input field or division or span
|
|
1303
|
+
* @param name object - the new settings to update or
|
|
1304
|
+
* string - the name of the setting to change or retrieve,
|
|
1305
|
+
* when retrieving also "all" for all instance settings or
|
|
1306
|
+
* "defaults" for all global defaults
|
|
1307
|
+
* @param value any - the new value for the setting
|
|
1308
|
+
* (omit if above is an object or to retrieve a value)
|
|
1309
|
+
*/
|
|
1310
|
+
_optionMonthpicker: function(target, name, value) {
|
|
1311
|
+
var settings, date, minDate, maxDate,
|
|
1312
|
+
inst = this._getInst(target);
|
|
1313
|
+
|
|
1314
|
+
if (arguments.length === 2 && typeof name === "string") {
|
|
1315
|
+
return (name === "defaults" ? $.extend({}, $.monthpicker._defaults) :
|
|
1316
|
+
(inst ? (name === "all" ? $.extend({}, inst.settings) :
|
|
1317
|
+
this._get(inst, name)) : null));
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
settings = name || {};
|
|
1321
|
+
if (typeof name === "string") {
|
|
1322
|
+
settings = {};
|
|
1323
|
+
settings[name] = value;
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
if (inst) {
|
|
1327
|
+
if (this._curInst === inst) {
|
|
1328
|
+
this._hideMonthpicker();
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
date = this._getDateMonthpicker(target, true);
|
|
1332
|
+
minDate = this._getMinMaxDate(inst, "min");
|
|
1333
|
+
maxDate = this._getMinMaxDate(inst, "max");
|
|
1334
|
+
extendRemove(inst.settings, settings);
|
|
1335
|
+
// reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
|
|
1336
|
+
if (minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined) {
|
|
1337
|
+
inst.settings.minDate = this._formatDate(inst, minDate);
|
|
1338
|
+
}
|
|
1339
|
+
if (maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined) {
|
|
1340
|
+
inst.settings.maxDate = this._formatDate(inst, maxDate);
|
|
1341
|
+
}
|
|
1342
|
+
if ( "disabled" in settings ) {
|
|
1343
|
+
if ( settings.disabled ) {
|
|
1344
|
+
this._disableMonthpicker(target);
|
|
1345
|
+
} else {
|
|
1346
|
+
this._enableMonthpicker(target);
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
this._attachments($(target), inst);
|
|
1350
|
+
this._setDate(inst, date);
|
|
1351
|
+
this._updateAlternate(inst);
|
|
1352
|
+
this._updateMonthpicker(inst);
|
|
1353
|
+
}
|
|
1354
|
+
},
|
|
1355
|
+
|
|
1356
|
+
|
|
1357
|
+
/* Get the date(s) for the first entry in a jQuery selection.
|
|
1358
|
+
* @param target element - the target input field or division or span
|
|
1359
|
+
* @return Date - the current date
|
|
1360
|
+
*/
|
|
1361
|
+
_getDateMonthpicker: function(target, noDefault) {
|
|
1362
|
+
var inst = this._getInst(target);
|
|
1363
|
+
if (inst && !inst.inline) {
|
|
1364
|
+
this._setDateFromField(inst, noDefault);
|
|
1365
|
+
}
|
|
1366
|
+
return (inst ? this._getDate(inst) : null);
|
|
1367
|
+
},
|
|
1368
|
+
|
|
1369
|
+
/* Format the given date for display. */
|
|
1370
|
+
_formatDate: function(inst, month, year) {
|
|
1371
|
+
if (!month) {
|
|
1372
|
+
inst.currentMonth = inst.selectedMonth;
|
|
1373
|
+
inst.currentYear = inst.selectedYear;
|
|
1374
|
+
}
|
|
1375
|
+
var date = (month ? (typeof month == 'object' ? month :
|
|
1376
|
+
new Date(year, month, 1)) :
|
|
1377
|
+
new Date(inst.currentYear, inst.currentMonth, 1));
|
|
1378
|
+
return this.formatDate(this._get(inst, 'dateFormat'), date, this._getFormatConfig(inst));
|
|
1379
|
+
}
|
|
1380
|
+
});
|
|
1381
|
+
|
|
1382
|
+
/* jQuery extend now ignores nulls! */
|
|
1383
|
+
function extendRemove(target, props) {
|
|
1384
|
+
$.extend(target, props);
|
|
1385
|
+
for (var name in props)
|
|
1386
|
+
if (props[name] == null || props[name] == undefined)
|
|
1387
|
+
target[name] = props[name];
|
|
1388
|
+
return target;
|
|
1389
|
+
};
|
|
1390
|
+
|
|
1391
|
+
/*
|
|
1392
|
+
* Bind hover events for monthpicker elements.
|
|
1393
|
+
* Done via delegate so the binding only occurs once in the lifetime of the parent div.
|
|
1394
|
+
* Global instActive, set by _updateMonthpicker allows the handlers to find their way back to the active picker.
|
|
1395
|
+
*/
|
|
1396
|
+
function bindHover(dpDiv) {
|
|
1397
|
+
var selector = '.ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a';
|
|
1398
|
+
return dpDiv.delegate(selector, 'mouseout', function() {
|
|
1399
|
+
$(this).removeClass('ui-state-hover');
|
|
1400
|
+
if (this.className.indexOf('ui-datepicker-prev') != -1) $(this).removeClass('ui-datepicker-prev-hover');
|
|
1401
|
+
if (this.className.indexOf('ui-datepicker-next') != -1) $(this).removeClass('ui-datepicker-next-hover');
|
|
1402
|
+
})
|
|
1403
|
+
.delegate(selector, 'mouseover', function(){
|
|
1404
|
+
if (!$.monthpicker._isDisabledMonthpicker( instActive.input[0])) {
|
|
1405
|
+
$(this).parents('.ui-datepicker-calendar').find('a').removeClass('ui-state-hover');
|
|
1406
|
+
$(this).addClass('ui-state-hover');
|
|
1407
|
+
if (this.className.indexOf('ui-datepicker-prev') != -1) $(this).addClass('ui-datepicker-prev-hover');
|
|
1408
|
+
if (this.className.indexOf('ui-datepicker-next') != -1) $(this).addClass('ui-datepicker-next-hover');
|
|
1409
|
+
}
|
|
1410
|
+
});
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
/* Invoke the monthpicker functionality.
|
|
1414
|
+
@param options Object - settings for attaching new monthpicker functionality
|
|
1415
|
+
@return jQuery object */
|
|
1416
|
+
$.fn.monthpicker = function(options){
|
|
1417
|
+
|
|
1418
|
+
/* Verify an empty collection wasn't passed */
|
|
1419
|
+
if ( !this.length ) {
|
|
1420
|
+
return this;
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
/* Initialise the date picker. */
|
|
1424
|
+
if (!$.monthpicker.initialized) {
|
|
1425
|
+
$(document).mousedown($.monthpicker._checkExternalClick).
|
|
1426
|
+
find('body').append($.monthpicker.dpDiv);
|
|
1427
|
+
$.monthpicker.initialized = true;
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1430
|
+
var otherArgs = Array.prototype.slice.call(arguments, 1);
|
|
1431
|
+
if (typeof options === "string" && (options === "isDisabled" || options === "getDate" || options === "widget")) {
|
|
1432
|
+
return $.monthpicker["_" + options + "Monthpicker"].
|
|
1433
|
+
apply($.monthpicker, [this[0]].concat(otherArgs));
|
|
1434
|
+
}
|
|
1435
|
+
if (options === "option" && arguments.length === 2 && typeof arguments[1] === "string") {
|
|
1436
|
+
return $.monthpicker["_" + options + "Monthpicker"].
|
|
1437
|
+
apply($.monthpicker, [this[0]].concat(otherArgs));
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
return this.each(function() {
|
|
1441
|
+
typeof options === 'string' ?
|
|
1442
|
+
$.monthpicker['_' + options + 'Monthpicker'].
|
|
1443
|
+
apply($.monthpicker, [this].concat(otherArgs)) :
|
|
1444
|
+
$.monthpicker._attachMonthpicker(this, options);
|
|
1445
|
+
});
|
|
1446
|
+
};
|
|
1447
|
+
|
|
1448
|
+
$.monthpicker = new Monthpicker(); // singleton instance
|
|
1449
|
+
$.monthpicker.initialized = false;
|
|
1450
|
+
|
|
1451
|
+
})(jQuery);
|