datatables.net-datetime 1.1.2 → 1.3.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.
- package/datatables.net-datetime.1.3.0.nupkg +0 -0
- package/dist/dataTables.dateTime.js +162 -67
- package/dist/dataTables.dateTime.min.js +6 -43
- package/dist/dataTables.dateTime.min.mjs +6 -0
- package/dist/dataTables.dateTime.mjs +1628 -0
- package/docs/api/valFormat().xml +52 -0
- package/docs/option/buttons.today.xml +1 -1
- package/examples/initialisation/datetime.xml +1 -1
- package/examples/initialisation/dayjs.xml +7 -5
- package/examples/initialisation/luxon.xml +1 -1
- package/js/dataTables.dateTime.d.ts +60 -46
- package/js/dataTables.dateTime.js +144 -87
- package/make.sh +2 -1
- package/nuget.nuspec +1 -1
- package/package.json +2 -1
- package/test/api/dateTime.val().js +1 -1
- package/test/api/dateTime.valFormat()-luxon.js +83 -0
- package/test/api/dateTime.valFormat().js +83 -0
|
@@ -0,0 +1,1628 @@
|
|
|
1
|
+
/*! DateTime picker for DataTables.net v1.3.0
|
|
2
|
+
*
|
|
3
|
+
* © SpryMedia Ltd, all rights reserved.
|
|
4
|
+
* License: MIT datatables.net/license/mit
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import $ from 'jquery';
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @summary DateTime picker for DataTables.net
|
|
13
|
+
* @version 1.3.0
|
|
14
|
+
* @file dataTables.dateTime.js
|
|
15
|
+
* @author SpryMedia Ltd
|
|
16
|
+
* @contact www.datatables.net/contact
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
// Supported formatting and parsing libraries:
|
|
20
|
+
// * Moment
|
|
21
|
+
// * Luxon
|
|
22
|
+
// * DayJS
|
|
23
|
+
var dateLib;
|
|
24
|
+
|
|
25
|
+
/*
|
|
26
|
+
* This file provides a DateTime GUI picker (calendar and time input). Only the
|
|
27
|
+
* format YYYY-MM-DD is supported without additional software, but the end user
|
|
28
|
+
* experience can be greatly enhanced by including the momentjs, dayjs or luxon library
|
|
29
|
+
* which provide date / time parsing and formatting options.
|
|
30
|
+
*
|
|
31
|
+
* This functionality is required because the HTML5 date and datetime input
|
|
32
|
+
* types are not widely supported in desktop browsers.
|
|
33
|
+
*
|
|
34
|
+
* Constructed by using:
|
|
35
|
+
*
|
|
36
|
+
* new DateTime( input, opts )
|
|
37
|
+
*
|
|
38
|
+
* where `input` is the HTML input element to use and `opts` is an object of
|
|
39
|
+
* options based on the `DateTime.defaults` object.
|
|
40
|
+
*/
|
|
41
|
+
var DateTime = function ( input, opts ) {
|
|
42
|
+
// Attempt to auto detect the formatting library (if there is one). Having it in
|
|
43
|
+
// the constructor allows load order independence.
|
|
44
|
+
if (typeof dateLib === 'undefined') {
|
|
45
|
+
dateLib = window.moment
|
|
46
|
+
? window.moment
|
|
47
|
+
: window.dayjs
|
|
48
|
+
? window.dayjs
|
|
49
|
+
: window.luxon
|
|
50
|
+
? window.luxon
|
|
51
|
+
: null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
this.c = $.extend( true, {}, DateTime.defaults, opts );
|
|
55
|
+
var classPrefix = this.c.classPrefix;
|
|
56
|
+
var i18n = this.c.i18n;
|
|
57
|
+
|
|
58
|
+
// Only IS8601 dates are supported without moment, dayjs or luxon
|
|
59
|
+
if ( ! dateLib && this.c.format !== 'YYYY-MM-DD' ) {
|
|
60
|
+
throw "DateTime: Without momentjs, dayjs or luxon only the format 'YYYY-MM-DD' can be used";
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Min and max need to be `Date` objects in the config
|
|
64
|
+
if (typeof this.c.minDate === 'string') {
|
|
65
|
+
this.c.minDate = new Date(this.c.minDate);
|
|
66
|
+
}
|
|
67
|
+
if (typeof this.c.maxDate === 'string') {
|
|
68
|
+
this.c.maxDate = new Date(this.c.maxDate);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// DOM structure
|
|
72
|
+
var structure = $(
|
|
73
|
+
'<div class="'+classPrefix+'">'+
|
|
74
|
+
'<div class="'+classPrefix+'-date">'+
|
|
75
|
+
'<div class="'+classPrefix+'-title">'+
|
|
76
|
+
'<div class="'+classPrefix+'-iconLeft">'+
|
|
77
|
+
'<button type="button"></button>'+
|
|
78
|
+
'</div>'+
|
|
79
|
+
'<div class="'+classPrefix+'-iconRight">'+
|
|
80
|
+
'<button type="button"></button>'+
|
|
81
|
+
'</div>'+
|
|
82
|
+
'<div class="'+classPrefix+'-label">'+
|
|
83
|
+
'<span></span>'+
|
|
84
|
+
'<select class="'+classPrefix+'-month"></select>'+
|
|
85
|
+
'</div>'+
|
|
86
|
+
'<div class="'+classPrefix+'-label">'+
|
|
87
|
+
'<span></span>'+
|
|
88
|
+
'<select class="'+classPrefix+'-year"></select>'+
|
|
89
|
+
'</div>'+
|
|
90
|
+
'</div>'+
|
|
91
|
+
'<div class="'+classPrefix+'-buttons">'+
|
|
92
|
+
'<a class="'+classPrefix+'-clear"></a>'+
|
|
93
|
+
'<a class="'+classPrefix+'-today"></a>'+
|
|
94
|
+
'</div>'+
|
|
95
|
+
'<div class="'+classPrefix+'-calendar"></div>'+
|
|
96
|
+
'</div>'+
|
|
97
|
+
'<div class="'+classPrefix+'-time">'+
|
|
98
|
+
'<div class="'+classPrefix+'-hours"></div>'+
|
|
99
|
+
'<div class="'+classPrefix+'-minutes"></div>'+
|
|
100
|
+
'<div class="'+classPrefix+'-seconds"></div>'+
|
|
101
|
+
'</div>'+
|
|
102
|
+
'<div class="'+classPrefix+'-error"></div>'+
|
|
103
|
+
'</div>'
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
this.dom = {
|
|
107
|
+
container: structure,
|
|
108
|
+
date: structure.find( '.'+classPrefix+'-date' ),
|
|
109
|
+
title: structure.find( '.'+classPrefix+'-title' ),
|
|
110
|
+
calendar: structure.find( '.'+classPrefix+'-calendar' ),
|
|
111
|
+
time: structure.find( '.'+classPrefix+'-time' ),
|
|
112
|
+
error: structure.find( '.'+classPrefix+'-error' ),
|
|
113
|
+
buttons: structure.find( '.'+classPrefix+'-buttons' ),
|
|
114
|
+
clear: structure.find( '.'+classPrefix+'-clear' ),
|
|
115
|
+
today: structure.find( '.'+classPrefix+'-today' ),
|
|
116
|
+
previous: structure.find( '.'+classPrefix+'-iconLeft' ),
|
|
117
|
+
next: structure.find( '.'+classPrefix+'-iconRight' ),
|
|
118
|
+
input: $(input)
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
this.s = {
|
|
122
|
+
/** @type {Date} Date value that the picker has currently selected */
|
|
123
|
+
d: null,
|
|
124
|
+
|
|
125
|
+
/** @type {Date} Date of the calendar - might not match the value */
|
|
126
|
+
display: null,
|
|
127
|
+
|
|
128
|
+
/** @type {number} Used to select minutes in a range where the range base is itself unavailable */
|
|
129
|
+
minutesRange: null,
|
|
130
|
+
|
|
131
|
+
/** @type {number} Used to select minutes in a range where the range base is itself unavailable */
|
|
132
|
+
secondsRange: null,
|
|
133
|
+
|
|
134
|
+
/** @type {String} Unique namespace string for this instance */
|
|
135
|
+
namespace: 'dateime-'+(DateTime._instance++),
|
|
136
|
+
|
|
137
|
+
/** @type {Object} Parts of the picker that should be shown */
|
|
138
|
+
parts: {
|
|
139
|
+
date: this.c.format.match( /[YMD]|L(?!T)|l/ ) !== null,
|
|
140
|
+
time: this.c.format.match( /[Hhm]|LT|LTS/ ) !== null,
|
|
141
|
+
seconds: this.c.format.indexOf( 's' ) !== -1,
|
|
142
|
+
hours12: this.c.format.match( /[haA]/ ) !== null
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
this.dom.container
|
|
147
|
+
.append( this.dom.date )
|
|
148
|
+
.append( this.dom.time )
|
|
149
|
+
.append( this.dom.error );
|
|
150
|
+
|
|
151
|
+
this.dom.date
|
|
152
|
+
.append( this.dom.title )
|
|
153
|
+
.append( this.dom.buttons )
|
|
154
|
+
.append( this.dom.calendar );
|
|
155
|
+
|
|
156
|
+
this._constructor();
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
$.extend( DateTime.prototype, {
|
|
160
|
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
161
|
+
* Public
|
|
162
|
+
*/
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Destroy the control
|
|
166
|
+
*/
|
|
167
|
+
destroy: function () {
|
|
168
|
+
this._hide(true);
|
|
169
|
+
this.dom.container.off().empty();
|
|
170
|
+
this.dom.input
|
|
171
|
+
.removeAttr('autocomplete')
|
|
172
|
+
.off('.datetime');
|
|
173
|
+
},
|
|
174
|
+
|
|
175
|
+
errorMsg: function ( msg ) {
|
|
176
|
+
var error = this.dom.error;
|
|
177
|
+
|
|
178
|
+
if ( msg ) {
|
|
179
|
+
error.html( msg );
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
error.empty();
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return this;
|
|
186
|
+
},
|
|
187
|
+
|
|
188
|
+
hide: function () {
|
|
189
|
+
this._hide();
|
|
190
|
+
|
|
191
|
+
return this;
|
|
192
|
+
},
|
|
193
|
+
|
|
194
|
+
max: function ( date ) {
|
|
195
|
+
this.c.maxDate = typeof date === 'string'
|
|
196
|
+
? new Date(date)
|
|
197
|
+
: date;
|
|
198
|
+
|
|
199
|
+
this._optionsTitle();
|
|
200
|
+
this._setCalander();
|
|
201
|
+
|
|
202
|
+
return this;
|
|
203
|
+
},
|
|
204
|
+
|
|
205
|
+
min: function ( date ) {
|
|
206
|
+
this.c.minDate = typeof date === 'string'
|
|
207
|
+
? new Date(date)
|
|
208
|
+
: date;
|
|
209
|
+
|
|
210
|
+
this._optionsTitle();
|
|
211
|
+
this._setCalander();
|
|
212
|
+
|
|
213
|
+
return this;
|
|
214
|
+
},
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Check if an element belongs to this control
|
|
218
|
+
*
|
|
219
|
+
* @param {node} node Element to check
|
|
220
|
+
* @return {boolean} true if owned by this control, false otherwise
|
|
221
|
+
*/
|
|
222
|
+
owns: function ( node ) {
|
|
223
|
+
return $(node).parents().filter( this.dom.container ).length > 0;
|
|
224
|
+
},
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Get / set the value
|
|
228
|
+
*
|
|
229
|
+
* @param {string|Date} set Value to set
|
|
230
|
+
* @param {boolean} [write=true] Flag to indicate if the formatted value
|
|
231
|
+
* should be written into the input element
|
|
232
|
+
*/
|
|
233
|
+
val: function ( set, write ) {
|
|
234
|
+
if ( set === undefined ) {
|
|
235
|
+
return this.s.d;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if ( set instanceof Date ) {
|
|
239
|
+
this.s.d = this._dateToUtc( set );
|
|
240
|
+
}
|
|
241
|
+
else if ( set === null || set === '' ) {
|
|
242
|
+
this.s.d = null;
|
|
243
|
+
}
|
|
244
|
+
else if ( set === '--now' ) {
|
|
245
|
+
this.s.d = this._dateToUtc(new Date());
|
|
246
|
+
}
|
|
247
|
+
else if ( typeof set === 'string' ) {
|
|
248
|
+
this.s.d = this._convert(set, this.c.format, null);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if ( write || write === undefined ) {
|
|
252
|
+
if ( this.s.d ) {
|
|
253
|
+
this._writeOutput();
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
// The input value was not valid...
|
|
257
|
+
this.dom.input.val( set );
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Need something to display
|
|
262
|
+
this.s.display = this.s.d
|
|
263
|
+
? new Date( this.s.d.toString() )
|
|
264
|
+
: new Date();
|
|
265
|
+
|
|
266
|
+
// Set the day of the month to be 1 so changing between months doesn't
|
|
267
|
+
// run into issues when going from day 31 to 28 (for example)
|
|
268
|
+
this.s.display.setUTCDate( 1 );
|
|
269
|
+
|
|
270
|
+
// Update the display elements for the new value
|
|
271
|
+
this._setTitle();
|
|
272
|
+
this._setCalander();
|
|
273
|
+
this._setTime();
|
|
274
|
+
|
|
275
|
+
return this;
|
|
276
|
+
},
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Similar to `val()` but uses a given date / time format
|
|
280
|
+
*
|
|
281
|
+
* @param format Format to get the data as (getter) or that is input (setter)
|
|
282
|
+
* @param val Value to write (if undefined, used as a getter)
|
|
283
|
+
* @returns
|
|
284
|
+
*/
|
|
285
|
+
valFormat: function (format, val) {
|
|
286
|
+
if (! val) {
|
|
287
|
+
return this._convert(this.val(), null, format);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Convert from the format given here to the instance's configured format
|
|
291
|
+
this.val(
|
|
292
|
+
this._convert(val, format, null)
|
|
293
|
+
);
|
|
294
|
+
|
|
295
|
+
return this;
|
|
296
|
+
},
|
|
297
|
+
|
|
298
|
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
299
|
+
* Constructor
|
|
300
|
+
*/
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Build the control and assign initial event handlers
|
|
304
|
+
*
|
|
305
|
+
* @private
|
|
306
|
+
*/
|
|
307
|
+
_constructor: function () {
|
|
308
|
+
var that = this;
|
|
309
|
+
var classPrefix = this.c.classPrefix;
|
|
310
|
+
var last = this.dom.input.val();
|
|
311
|
+
|
|
312
|
+
var onChange = function () {
|
|
313
|
+
var curr = that.dom.input.val();
|
|
314
|
+
|
|
315
|
+
if (curr !== last) {
|
|
316
|
+
that.c.onChange.call( that, curr, that.s.d, that.dom.input );
|
|
317
|
+
last = curr;
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
if ( ! this.s.parts.date ) {
|
|
322
|
+
this.dom.date.css( 'display', 'none' );
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if ( ! this.s.parts.time ) {
|
|
326
|
+
this.dom.time.css( 'display', 'none' );
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if ( ! this.s.parts.seconds ) {
|
|
330
|
+
this.dom.time.children('div.'+classPrefix+'-seconds').remove();
|
|
331
|
+
this.dom.time.children('span').eq(1).remove();
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
if ( ! this.c.buttons.clear ) {
|
|
335
|
+
this.dom.clear.css( 'display', 'none' );
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
if ( ! this.c.buttons.today ) {
|
|
339
|
+
this.dom.today.css( 'display', 'none' );
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Render the options
|
|
343
|
+
this._optionsTitle();
|
|
344
|
+
|
|
345
|
+
$(document).on('i18n.dt', function (e, settings) {
|
|
346
|
+
if (settings.oLanguage.datetime) {
|
|
347
|
+
$.extend(true, that.c.i18n, settings.oLanguage.datetime);
|
|
348
|
+
that._optionsTitle();
|
|
349
|
+
}
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
// When attached to a hidden input, we always show the input picker, and
|
|
353
|
+
// do so inline
|
|
354
|
+
if (this.dom.input.attr('type') === 'hidden') {
|
|
355
|
+
this.dom.container.addClass('inline');
|
|
356
|
+
this.c.attachTo = 'input';
|
|
357
|
+
|
|
358
|
+
this.val( this.dom.input.val(), false );
|
|
359
|
+
this._show();
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// Set the initial value
|
|
363
|
+
if (last) {
|
|
364
|
+
this.val( last, false );
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// Trigger the display of the widget when clicking or focusing on the
|
|
368
|
+
// input element
|
|
369
|
+
this.dom.input
|
|
370
|
+
.attr('autocomplete', 'off')
|
|
371
|
+
.on('focus.datetime click.datetime', function () {
|
|
372
|
+
// If already visible - don't do anything
|
|
373
|
+
if ( that.dom.container.is(':visible') || that.dom.input.is(':disabled') ) {
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// In case the value has changed by text
|
|
378
|
+
that.val( that.dom.input.val(), false );
|
|
379
|
+
|
|
380
|
+
that._show();
|
|
381
|
+
} )
|
|
382
|
+
.on('keyup.datetime', function () {
|
|
383
|
+
// Update the calendar's displayed value as the user types
|
|
384
|
+
if ( that.dom.container.is(':visible') ) {
|
|
385
|
+
that.val( that.dom.input.val(), false );
|
|
386
|
+
}
|
|
387
|
+
} );
|
|
388
|
+
|
|
389
|
+
// Main event handlers for input in the widget
|
|
390
|
+
this.dom.container
|
|
391
|
+
.on( 'change', 'select', function () {
|
|
392
|
+
var select = $(this);
|
|
393
|
+
var val = select.val();
|
|
394
|
+
|
|
395
|
+
if ( select.hasClass(classPrefix+'-month') ) {
|
|
396
|
+
// Month select
|
|
397
|
+
that._correctMonth( that.s.display, val );
|
|
398
|
+
that._setTitle();
|
|
399
|
+
that._setCalander();
|
|
400
|
+
}
|
|
401
|
+
else if ( select.hasClass(classPrefix+'-year') ) {
|
|
402
|
+
// Year select
|
|
403
|
+
that.s.display.setUTCFullYear( val );
|
|
404
|
+
that._setTitle();
|
|
405
|
+
that._setCalander();
|
|
406
|
+
}
|
|
407
|
+
else if ( select.hasClass(classPrefix+'-hours') || select.hasClass(classPrefix+'-ampm') ) {
|
|
408
|
+
// Hours - need to take account of AM/PM input if present
|
|
409
|
+
if ( that.s.parts.hours12 ) {
|
|
410
|
+
var hours = $(that.dom.container).find('.'+classPrefix+'-hours').val() * 1;
|
|
411
|
+
var pm = $(that.dom.container).find('.'+classPrefix+'-ampm').val() === 'pm';
|
|
412
|
+
|
|
413
|
+
that.s.d.setUTCHours( hours === 12 && !pm ?
|
|
414
|
+
0 :
|
|
415
|
+
pm && hours !== 12 ?
|
|
416
|
+
hours + 12 :
|
|
417
|
+
hours
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
else {
|
|
421
|
+
that.s.d.setUTCHours( val );
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
that._setTime();
|
|
425
|
+
that._writeOutput( true );
|
|
426
|
+
|
|
427
|
+
onChange();
|
|
428
|
+
}
|
|
429
|
+
else if ( select.hasClass(classPrefix+'-minutes') ) {
|
|
430
|
+
// Minutes select
|
|
431
|
+
that.s.d.setUTCMinutes( val );
|
|
432
|
+
that._setTime();
|
|
433
|
+
that._writeOutput( true );
|
|
434
|
+
|
|
435
|
+
onChange();
|
|
436
|
+
}
|
|
437
|
+
else if ( select.hasClass(classPrefix+'-seconds') ) {
|
|
438
|
+
// Seconds select
|
|
439
|
+
that.s.d.setSeconds( val );
|
|
440
|
+
that._setTime();
|
|
441
|
+
that._writeOutput( true );
|
|
442
|
+
|
|
443
|
+
onChange();
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
that.dom.input.focus();
|
|
447
|
+
that._position();
|
|
448
|
+
} )
|
|
449
|
+
.on( 'click', function (e) {
|
|
450
|
+
var d = that.s.d;
|
|
451
|
+
var nodeName = e.target.nodeName.toLowerCase();
|
|
452
|
+
var target = nodeName === 'span' ?
|
|
453
|
+
e.target.parentNode :
|
|
454
|
+
e.target;
|
|
455
|
+
|
|
456
|
+
nodeName = target.nodeName.toLowerCase();
|
|
457
|
+
|
|
458
|
+
if ( nodeName === 'select' ) {
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
e.stopPropagation();
|
|
463
|
+
|
|
464
|
+
if ( nodeName === 'a' ) {
|
|
465
|
+
e.preventDefault();
|
|
466
|
+
|
|
467
|
+
if ($(target).hasClass(classPrefix+'-clear')) {
|
|
468
|
+
// Clear the value and don't change the display
|
|
469
|
+
that.s.d = null;
|
|
470
|
+
that.dom.input.val('');
|
|
471
|
+
that._writeOutput();
|
|
472
|
+
that._setCalander();
|
|
473
|
+
that._setTime();
|
|
474
|
+
|
|
475
|
+
onChange();
|
|
476
|
+
}
|
|
477
|
+
else if ($(target).hasClass(classPrefix+'-today')) {
|
|
478
|
+
// Don't change the value, but jump to the month
|
|
479
|
+
// containing today
|
|
480
|
+
that.s.display = new Date();
|
|
481
|
+
|
|
482
|
+
that._setTitle();
|
|
483
|
+
that._setCalander();
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
if ( nodeName === 'button' ) {
|
|
487
|
+
var button = $(target);
|
|
488
|
+
var parent = button.parent();
|
|
489
|
+
|
|
490
|
+
if ( parent.hasClass('disabled') && ! parent.hasClass('range') ) {
|
|
491
|
+
button.blur();
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
if ( parent.hasClass(classPrefix+'-iconLeft') ) {
|
|
496
|
+
// Previous month
|
|
497
|
+
that.s.display.setUTCMonth( that.s.display.getUTCMonth()-1 );
|
|
498
|
+
that._setTitle();
|
|
499
|
+
that._setCalander();
|
|
500
|
+
|
|
501
|
+
that.dom.input.focus();
|
|
502
|
+
}
|
|
503
|
+
else if ( parent.hasClass(classPrefix+'-iconRight') ) {
|
|
504
|
+
// Next month
|
|
505
|
+
that._correctMonth( that.s.display, that.s.display.getUTCMonth()+1 );
|
|
506
|
+
that._setTitle();
|
|
507
|
+
that._setCalander();
|
|
508
|
+
|
|
509
|
+
that.dom.input.focus();
|
|
510
|
+
}
|
|
511
|
+
else if ( button.parents('.'+classPrefix+'-time').length ) {
|
|
512
|
+
var val = button.data('value');
|
|
513
|
+
var unit = button.data('unit');
|
|
514
|
+
|
|
515
|
+
d = that._needValue();
|
|
516
|
+
|
|
517
|
+
if ( unit === 'minutes' ) {
|
|
518
|
+
if ( parent.hasClass('disabled') && parent.hasClass('range') ) {
|
|
519
|
+
that.s.minutesRange = val;
|
|
520
|
+
that._setTime();
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
523
|
+
else {
|
|
524
|
+
that.s.minutesRange = null;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
if ( unit === 'seconds' ) {
|
|
529
|
+
if ( parent.hasClass('disabled') && parent.hasClass('range') ) {
|
|
530
|
+
that.s.secondsRange = val;
|
|
531
|
+
that._setTime();
|
|
532
|
+
return;
|
|
533
|
+
}
|
|
534
|
+
else {
|
|
535
|
+
that.s.secondsRange = null;
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
// Specific to hours for 12h clock
|
|
540
|
+
if ( val === 'am' ) {
|
|
541
|
+
if ( d.getUTCHours() >= 12 ) {
|
|
542
|
+
val = d.getUTCHours() - 12;
|
|
543
|
+
}
|
|
544
|
+
else {
|
|
545
|
+
return;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
else if ( val === 'pm' ) {
|
|
549
|
+
if ( d.getUTCHours() < 12 ) {
|
|
550
|
+
val = d.getUTCHours() + 12;
|
|
551
|
+
}
|
|
552
|
+
else {
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
var set = unit === 'hours' ?
|
|
558
|
+
'setUTCHours' :
|
|
559
|
+
unit === 'minutes' ?
|
|
560
|
+
'setUTCMinutes' :
|
|
561
|
+
'setSeconds';
|
|
562
|
+
|
|
563
|
+
d[set]( val );
|
|
564
|
+
that._setCalander();
|
|
565
|
+
that._setTime();
|
|
566
|
+
that._writeOutput( true );
|
|
567
|
+
onChange();
|
|
568
|
+
}
|
|
569
|
+
else {
|
|
570
|
+
// Calendar click
|
|
571
|
+
d = that._needValue();
|
|
572
|
+
|
|
573
|
+
// Can't be certain that the current day will exist in
|
|
574
|
+
// the new month, and likewise don't know that the
|
|
575
|
+
// new day will exist in the old month, But 1 always
|
|
576
|
+
// does, so we can change the month without worry of a
|
|
577
|
+
// recalculation being done automatically by `Date`
|
|
578
|
+
d.setUTCDate( 1 );
|
|
579
|
+
d.setUTCFullYear( button.data('year') );
|
|
580
|
+
d.setUTCMonth( button.data('month') );
|
|
581
|
+
d.setUTCDate( button.data('day') );
|
|
582
|
+
|
|
583
|
+
that._writeOutput( true );
|
|
584
|
+
|
|
585
|
+
// Don't hide if there is a time picker, since we want to
|
|
586
|
+
// be able to select a time as well.
|
|
587
|
+
if ( ! that.s.parts.time ) {
|
|
588
|
+
// This is annoying but IE has some kind of async
|
|
589
|
+
// behaviour with focus and the focus from the above
|
|
590
|
+
// write would occur after this hide - resulting in the
|
|
591
|
+
// calendar opening immediately
|
|
592
|
+
setTimeout( function () {
|
|
593
|
+
that._hide();
|
|
594
|
+
}, 10 );
|
|
595
|
+
}
|
|
596
|
+
else {
|
|
597
|
+
that._setCalander();
|
|
598
|
+
that._setTime();
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
onChange();
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
else {
|
|
605
|
+
// Click anywhere else in the widget - return focus to the
|
|
606
|
+
// input element
|
|
607
|
+
that.dom.input.focus();
|
|
608
|
+
}
|
|
609
|
+
} );
|
|
610
|
+
},
|
|
611
|
+
|
|
612
|
+
|
|
613
|
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
614
|
+
* Private
|
|
615
|
+
*/
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* Compare the date part only of two dates - this is made super easy by the
|
|
619
|
+
* toDateString method!
|
|
620
|
+
*
|
|
621
|
+
* @param {Date} a Date 1
|
|
622
|
+
* @param {Date} b Date 2
|
|
623
|
+
* @private
|
|
624
|
+
*/
|
|
625
|
+
_compareDates: function( a, b ) {
|
|
626
|
+
// Can't use toDateString as that converts to local time
|
|
627
|
+
// luxon uses different method names so need to be able to call them
|
|
628
|
+
return this._isLuxon()
|
|
629
|
+
? dateLib.DateTime.fromJSDate(a).toUTC().toISODate() === dateLib.DateTime.fromJSDate(b).toUTC().toISODate()
|
|
630
|
+
: this._dateToUtcString(a) === this._dateToUtcString(b);
|
|
631
|
+
},
|
|
632
|
+
|
|
633
|
+
/**
|
|
634
|
+
* Convert from one format to another
|
|
635
|
+
*
|
|
636
|
+
* @param {string|Date} val Value
|
|
637
|
+
* @param {string|null} from Format to convert from. If null a `Date` must be given
|
|
638
|
+
* @param {string|null} to Format to convert to. If null a `Date` will be returned
|
|
639
|
+
* @returns {string|Date} Converted value
|
|
640
|
+
*/
|
|
641
|
+
_convert(val, from, to) {
|
|
642
|
+
if (! val) {
|
|
643
|
+
return val;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
if (! dateLib) {
|
|
647
|
+
// Note that in here from and to can either be null or YYYY-MM-DD
|
|
648
|
+
// They cannot be anything else
|
|
649
|
+
if ((! from && ! to) || (from && to)) {
|
|
650
|
+
// No conversion
|
|
651
|
+
return val;
|
|
652
|
+
}
|
|
653
|
+
else if (! from) {
|
|
654
|
+
// Date in, string back
|
|
655
|
+
return val.getUTCFullYear() +'-'+
|
|
656
|
+
this._pad(val.getUTCMonth() + 1) +'-'+
|
|
657
|
+
this._pad(val.getUTCDate());
|
|
658
|
+
}
|
|
659
|
+
else { // (! to)
|
|
660
|
+
// String in, date back
|
|
661
|
+
var match = val.match(/(\d{4})\-(\d{2})\-(\d{2})/ );
|
|
662
|
+
return match ?
|
|
663
|
+
new Date( Date.UTC(match[1], match[2]-1, match[3]) ) :
|
|
664
|
+
null;
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
else if (this._isLuxon()) {
|
|
668
|
+
// Luxon
|
|
669
|
+
var dtLux = val instanceof Date
|
|
670
|
+
? dateLib.DateTime.fromJSDate(val).toUTC()
|
|
671
|
+
: dateLib.DateTime.fromFormat(val, from);
|
|
672
|
+
|
|
673
|
+
if (! dtLux.isValid) {
|
|
674
|
+
return null;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
return to
|
|
678
|
+
? dtLux.toFormat(to)
|
|
679
|
+
: this._dateToUtc(dtLux.toJSDate());
|
|
680
|
+
}
|
|
681
|
+
else {
|
|
682
|
+
// Moment / DayJS
|
|
683
|
+
var dtMo = val instanceof Date
|
|
684
|
+
? dateLib.utc( val, undefined, this.c.locale, this.c.strict )
|
|
685
|
+
: dateLib.utc( val, from, this.c.locale, this.c.strict );
|
|
686
|
+
|
|
687
|
+
if (! dtMo.isValid()) {
|
|
688
|
+
return null;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
return to
|
|
692
|
+
? dtMo.format(to)
|
|
693
|
+
: dtMo.toDate();
|
|
694
|
+
}
|
|
695
|
+
},
|
|
696
|
+
|
|
697
|
+
/**
|
|
698
|
+
* When changing month, take account of the fact that some months don't have
|
|
699
|
+
* the same number of days. For example going from January to February you
|
|
700
|
+
* can have the 31st of Jan selected and just add a month since the date
|
|
701
|
+
* would still be 31, and thus drop you into March.
|
|
702
|
+
*
|
|
703
|
+
* @param {Date} date Date - will be modified
|
|
704
|
+
* @param {integer} month Month to set
|
|
705
|
+
* @private
|
|
706
|
+
*/
|
|
707
|
+
_correctMonth: function ( date, month ) {
|
|
708
|
+
var days = this._daysInMonth( date.getUTCFullYear(), month );
|
|
709
|
+
var correctDays = date.getUTCDate() > days;
|
|
710
|
+
|
|
711
|
+
date.setUTCMonth( month );
|
|
712
|
+
|
|
713
|
+
if ( correctDays ) {
|
|
714
|
+
date.setUTCDate( days );
|
|
715
|
+
date.setUTCMonth( month );
|
|
716
|
+
}
|
|
717
|
+
},
|
|
718
|
+
|
|
719
|
+
/**
|
|
720
|
+
* Get the number of days in a method. Based on
|
|
721
|
+
* http://stackoverflow.com/a/4881951 by Matti Virkkunen
|
|
722
|
+
*
|
|
723
|
+
* @param {integer} year Year
|
|
724
|
+
* @param {integer} month Month (starting at 0)
|
|
725
|
+
* @private
|
|
726
|
+
*/
|
|
727
|
+
_daysInMonth: function ( year, month ) {
|
|
728
|
+
//
|
|
729
|
+
var isLeap = ((year % 4) === 0 && ((year % 100) !== 0 || (year % 400) === 0));
|
|
730
|
+
var months = [31, (isLeap ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
731
|
+
|
|
732
|
+
return months[month];
|
|
733
|
+
},
|
|
734
|
+
|
|
735
|
+
/**
|
|
736
|
+
* Create a new date object which has the UTC values set to the local time.
|
|
737
|
+
* This allows the local time to be used directly for the library which
|
|
738
|
+
* always bases its calculations and display on UTC.
|
|
739
|
+
*
|
|
740
|
+
* @param {Date} s Date to "convert"
|
|
741
|
+
* @return {Date} Shifted date
|
|
742
|
+
*/
|
|
743
|
+
_dateToUtc: function ( s ) {
|
|
744
|
+
return new Date( Date.UTC(
|
|
745
|
+
s.getFullYear(), s.getMonth(), s.getDate(),
|
|
746
|
+
s.getHours(), s.getMinutes(), s.getSeconds()
|
|
747
|
+
) );
|
|
748
|
+
},
|
|
749
|
+
|
|
750
|
+
/**
|
|
751
|
+
* Create a UTC ISO8601 date part from a date object
|
|
752
|
+
*
|
|
753
|
+
* @param {Date} d Date to "convert"
|
|
754
|
+
* @return {string} ISO formatted date
|
|
755
|
+
*/
|
|
756
|
+
_dateToUtcString: function ( d ) {
|
|
757
|
+
// luxon uses different method names so need to be able to call them
|
|
758
|
+
return this._isLuxon()
|
|
759
|
+
? dateLib.DateTime.fromJSDate(d).toUTC().toISODate()
|
|
760
|
+
: d.getUTCFullYear()+'-'+
|
|
761
|
+
this._pad(d.getUTCMonth()+1)+'-'+
|
|
762
|
+
this._pad(d.getUTCDate());
|
|
763
|
+
},
|
|
764
|
+
|
|
765
|
+
/**
|
|
766
|
+
* Hide the control and remove events related to its display
|
|
767
|
+
*
|
|
768
|
+
* @private
|
|
769
|
+
*/
|
|
770
|
+
_hide: function (destroy) {
|
|
771
|
+
if (! destroy && this.dom.input.attr('type') === 'hidden') {
|
|
772
|
+
return;
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
var namespace = this.s.namespace;
|
|
776
|
+
|
|
777
|
+
this.dom.container.detach();
|
|
778
|
+
|
|
779
|
+
$(window).off( '.'+namespace );
|
|
780
|
+
$(document).off( 'keydown.'+namespace );
|
|
781
|
+
$('div.dataTables_scrollBody').off( 'scroll.'+namespace );
|
|
782
|
+
$('div.DTE_Body_Content').off( 'scroll.'+namespace );
|
|
783
|
+
$('body').off( 'click.'+namespace );
|
|
784
|
+
$(this.dom.input[0].offsetParent).off('.'+namespace);
|
|
785
|
+
},
|
|
786
|
+
|
|
787
|
+
/**
|
|
788
|
+
* Convert a 24 hour value to a 12 hour value
|
|
789
|
+
*
|
|
790
|
+
* @param {integer} val 24 hour value
|
|
791
|
+
* @return {integer} 12 hour value
|
|
792
|
+
* @private
|
|
793
|
+
*/
|
|
794
|
+
_hours24To12: function ( val ) {
|
|
795
|
+
return val === 0 ?
|
|
796
|
+
12 :
|
|
797
|
+
val > 12 ?
|
|
798
|
+
val - 12 :
|
|
799
|
+
val;
|
|
800
|
+
},
|
|
801
|
+
|
|
802
|
+
/**
|
|
803
|
+
* Generate the HTML for a single day in the calendar - this is basically
|
|
804
|
+
* and HTML cell with a button that has data attributes so we know what was
|
|
805
|
+
* clicked on (if it is clicked on) and a bunch of classes for styling.
|
|
806
|
+
*
|
|
807
|
+
* @param {object} day Day object from the `_htmlMonth` method
|
|
808
|
+
* @return {string} HTML cell
|
|
809
|
+
*/
|
|
810
|
+
_htmlDay: function( day )
|
|
811
|
+
{
|
|
812
|
+
if ( day.empty ) {
|
|
813
|
+
return '<td class="empty"></td>';
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
var classes = [ 'selectable' ];
|
|
817
|
+
var classPrefix = this.c.classPrefix;
|
|
818
|
+
|
|
819
|
+
if ( day.disabled ) {
|
|
820
|
+
classes.push( 'disabled' );
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
if ( day.today ) {
|
|
824
|
+
classes.push( 'now' );
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
if ( day.selected ) {
|
|
828
|
+
classes.push( 'selected' );
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
return '<td data-day="' + day.day + '" class="' + classes.join(' ') + '">' +
|
|
832
|
+
'<button class="'+classPrefix+'-button '+classPrefix+'-day" type="button" ' +'data-year="' + day.year + '" data-month="' + day.month + '" data-day="' + day.day + '">' +
|
|
833
|
+
'<span>'+day.day+'</span>'+
|
|
834
|
+
'</button>' +
|
|
835
|
+
'</td>';
|
|
836
|
+
},
|
|
837
|
+
|
|
838
|
+
|
|
839
|
+
/**
|
|
840
|
+
* Create the HTML for a month to be displayed in the calendar table.
|
|
841
|
+
*
|
|
842
|
+
* Based upon the logic used in Pikaday - MIT licensed
|
|
843
|
+
* Copyright (c) 2014 David Bushell
|
|
844
|
+
* https://github.com/dbushell/Pikaday
|
|
845
|
+
*
|
|
846
|
+
* @param {integer} year Year
|
|
847
|
+
* @param {integer} month Month (starting at 0)
|
|
848
|
+
* @return {string} Calendar month HTML
|
|
849
|
+
* @private
|
|
850
|
+
*/
|
|
851
|
+
_htmlMonth: function ( year, month ) {
|
|
852
|
+
var now = this._dateToUtc( new Date() ),
|
|
853
|
+
days = this._daysInMonth( year, month ),
|
|
854
|
+
before = new Date( Date.UTC(year, month, 1) ).getUTCDay(),
|
|
855
|
+
data = [],
|
|
856
|
+
row = [];
|
|
857
|
+
|
|
858
|
+
if ( this.c.firstDay > 0 ) {
|
|
859
|
+
before -= this.c.firstDay;
|
|
860
|
+
|
|
861
|
+
if (before < 0) {
|
|
862
|
+
before += 7;
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
var cells = days + before,
|
|
867
|
+
after = cells;
|
|
868
|
+
|
|
869
|
+
while ( after > 7 ) {
|
|
870
|
+
after -= 7;
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
cells += 7 - after;
|
|
874
|
+
|
|
875
|
+
var minDate = this.c.minDate;
|
|
876
|
+
var maxDate = this.c.maxDate;
|
|
877
|
+
|
|
878
|
+
if ( minDate ) {
|
|
879
|
+
minDate.setUTCHours(0);
|
|
880
|
+
minDate.setUTCMinutes(0);
|
|
881
|
+
minDate.setSeconds(0);
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
if ( maxDate ) {
|
|
885
|
+
maxDate.setUTCHours(23);
|
|
886
|
+
maxDate.setUTCMinutes(59);
|
|
887
|
+
maxDate.setSeconds(59);
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
for ( var i=0, r=0 ; i<cells ; i++ ) {
|
|
891
|
+
var day = new Date( Date.UTC(year, month, 1 + (i - before)) ),
|
|
892
|
+
selected = this.s.d ? this._compareDates(day, this.s.d) : false,
|
|
893
|
+
today = this._compareDates(day, now),
|
|
894
|
+
empty = i < before || i >= (days + before),
|
|
895
|
+
disabled = (minDate && day < minDate) ||
|
|
896
|
+
(maxDate && day > maxDate);
|
|
897
|
+
|
|
898
|
+
var disableDays = this.c.disableDays;
|
|
899
|
+
if ( Array.isArray( disableDays ) && $.inArray( day.getUTCDay(), disableDays ) !== -1 ) {
|
|
900
|
+
disabled = true;
|
|
901
|
+
}
|
|
902
|
+
else if ( typeof disableDays === 'function' && disableDays( day ) === true ) {
|
|
903
|
+
disabled = true;
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
var dayConfig = {
|
|
907
|
+
day: 1 + (i - before),
|
|
908
|
+
month: month,
|
|
909
|
+
year: year,
|
|
910
|
+
selected: selected,
|
|
911
|
+
today: today,
|
|
912
|
+
disabled: disabled,
|
|
913
|
+
empty: empty
|
|
914
|
+
};
|
|
915
|
+
|
|
916
|
+
row.push( this._htmlDay(dayConfig) );
|
|
917
|
+
|
|
918
|
+
if ( ++r === 7 ) {
|
|
919
|
+
if ( this.c.showWeekNumber ) {
|
|
920
|
+
row.unshift( this._htmlWeekOfYear(i - before, month, year) );
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
data.push( '<tr>'+row.join('')+'</tr>' );
|
|
924
|
+
row = [];
|
|
925
|
+
r = 0;
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
var classPrefix = this.c.classPrefix;
|
|
930
|
+
var className = classPrefix+'-table';
|
|
931
|
+
if ( this.c.showWeekNumber ) {
|
|
932
|
+
className += ' weekNumber';
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
// Show / hide month icons based on min/max
|
|
936
|
+
if ( minDate ) {
|
|
937
|
+
var underMin = minDate >= new Date( Date.UTC(year, month, 1, 0, 0, 0 ) );
|
|
938
|
+
|
|
939
|
+
this.dom.title.find('div.'+classPrefix+'-iconLeft')
|
|
940
|
+
.css( 'display', underMin ? 'none' : 'block' );
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
if ( maxDate ) {
|
|
944
|
+
var overMax = maxDate < new Date( Date.UTC(year, month+1, 1, 0, 0, 0 ) );
|
|
945
|
+
|
|
946
|
+
this.dom.title.find('div.'+classPrefix+'-iconRight')
|
|
947
|
+
.css( 'display', overMax ? 'none' : 'block' );
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
return '<table class="'+className+'">' +
|
|
951
|
+
'<thead>'+
|
|
952
|
+
this._htmlMonthHead() +
|
|
953
|
+
'</thead>'+
|
|
954
|
+
'<tbody>'+
|
|
955
|
+
data.join('') +
|
|
956
|
+
'</tbody>'+
|
|
957
|
+
'</table>';
|
|
958
|
+
},
|
|
959
|
+
|
|
960
|
+
/**
|
|
961
|
+
* Create the calendar table's header (week days)
|
|
962
|
+
*
|
|
963
|
+
* @return {string} HTML cells for the row
|
|
964
|
+
* @private
|
|
965
|
+
*/
|
|
966
|
+
_htmlMonthHead: function () {
|
|
967
|
+
var a = [];
|
|
968
|
+
var firstDay = this.c.firstDay;
|
|
969
|
+
var i18n = this.c.i18n;
|
|
970
|
+
|
|
971
|
+
// Take account of the first day shift
|
|
972
|
+
var dayName = function ( day ) {
|
|
973
|
+
day += firstDay;
|
|
974
|
+
|
|
975
|
+
while (day >= 7) {
|
|
976
|
+
day -= 7;
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
return i18n.weekdays[day];
|
|
980
|
+
};
|
|
981
|
+
|
|
982
|
+
// Empty cell in the header
|
|
983
|
+
if ( this.c.showWeekNumber ) {
|
|
984
|
+
a.push( '<th></th>' );
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
for ( var i=0 ; i<7 ; i++ ) {
|
|
988
|
+
a.push( '<th>'+dayName( i )+'</th>' );
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
return a.join('');
|
|
992
|
+
},
|
|
993
|
+
|
|
994
|
+
/**
|
|
995
|
+
* Create a cell that contains week of the year - ISO8601
|
|
996
|
+
*
|
|
997
|
+
* Based on https://stackoverflow.com/questions/6117814/ and
|
|
998
|
+
* http://techblog.procurios.nl/k/n618/news/view/33796/14863/
|
|
999
|
+
*
|
|
1000
|
+
* @param {integer} d Day of month
|
|
1001
|
+
* @param {integer} m Month of year (zero index)
|
|
1002
|
+
* @param {integer} y Year
|
|
1003
|
+
* @return {string}
|
|
1004
|
+
* @private
|
|
1005
|
+
*/
|
|
1006
|
+
_htmlWeekOfYear: function ( d, m, y ) {
|
|
1007
|
+
var date = new Date( y, m, d, 0, 0, 0, 0 );
|
|
1008
|
+
|
|
1009
|
+
// First week of the year always has 4th January in it
|
|
1010
|
+
date.setDate( date.getDate() + 4 - (date.getDay() || 7) );
|
|
1011
|
+
|
|
1012
|
+
var oneJan = new Date( y, 0, 1 );
|
|
1013
|
+
var weekNum = Math.ceil( ( ( (date - oneJan) / 86400000) + 1)/7 );
|
|
1014
|
+
|
|
1015
|
+
return '<td class="'+this.c.classPrefix+'-week">' + weekNum + '</td>';
|
|
1016
|
+
},
|
|
1017
|
+
|
|
1018
|
+
/**
|
|
1019
|
+
* Determine if Luxon is being used
|
|
1020
|
+
*
|
|
1021
|
+
* @returns Flag for Luxon
|
|
1022
|
+
*/
|
|
1023
|
+
_isLuxon: function () {
|
|
1024
|
+
return dateLib && dateLib.DateTime && dateLib.Duration && dateLib.Settings
|
|
1025
|
+
? true
|
|
1026
|
+
: false;
|
|
1027
|
+
},
|
|
1028
|
+
|
|
1029
|
+
/**
|
|
1030
|
+
* Check if the instance has a date object value - it might be null.
|
|
1031
|
+
* If is doesn't set one to now.
|
|
1032
|
+
* @returns A Date object
|
|
1033
|
+
* @private
|
|
1034
|
+
*/
|
|
1035
|
+
_needValue: function () {
|
|
1036
|
+
if ( ! this.s.d ) {
|
|
1037
|
+
this.s.d = this._dateToUtc( new Date() );
|
|
1038
|
+
|
|
1039
|
+
if (! this.s.parts.time) {
|
|
1040
|
+
this.s.d.setUTCHours(0);
|
|
1041
|
+
this.s.d.setUTCMinutes(0);
|
|
1042
|
+
this.s.d.setSeconds(0);
|
|
1043
|
+
this.s.d.setMilliseconds(0);
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
return this.s.d;
|
|
1048
|
+
},
|
|
1049
|
+
|
|
1050
|
+
/**
|
|
1051
|
+
* Create option elements from a range in an array
|
|
1052
|
+
*
|
|
1053
|
+
* @param {string} selector Class name unique to the select element to use
|
|
1054
|
+
* @param {array} values Array of values
|
|
1055
|
+
* @param {array} [labels] Array of labels. If given must be the same
|
|
1056
|
+
* length as the values parameter.
|
|
1057
|
+
* @private
|
|
1058
|
+
*/
|
|
1059
|
+
_options: function ( selector, values, labels ) {
|
|
1060
|
+
if ( ! labels ) {
|
|
1061
|
+
labels = values;
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
var select = this.dom.container.find('select.'+this.c.classPrefix+'-'+selector);
|
|
1065
|
+
select.empty();
|
|
1066
|
+
|
|
1067
|
+
for ( var i=0, ien=values.length ; i<ien ; i++ ) {
|
|
1068
|
+
select.append( '<option value="'+values[i]+'">'+labels[i]+'</option>' );
|
|
1069
|
+
}
|
|
1070
|
+
},
|
|
1071
|
+
|
|
1072
|
+
/**
|
|
1073
|
+
* Set an option and update the option's span pair (since the select element
|
|
1074
|
+
* has opacity 0 for styling)
|
|
1075
|
+
*
|
|
1076
|
+
* @param {string} selector Class name unique to the select element to use
|
|
1077
|
+
* @param {*} val Value to set
|
|
1078
|
+
* @private
|
|
1079
|
+
*/
|
|
1080
|
+
_optionSet: function ( selector, val ) {
|
|
1081
|
+
var select = this.dom.container.find('select.'+this.c.classPrefix+'-'+selector);
|
|
1082
|
+
var span = select.parent().children('span');
|
|
1083
|
+
|
|
1084
|
+
select.val( val );
|
|
1085
|
+
|
|
1086
|
+
var selected = select.find('option:selected');
|
|
1087
|
+
span.html( selected.length !== 0 ?
|
|
1088
|
+
selected.text() :
|
|
1089
|
+
this.c.i18n.unknown
|
|
1090
|
+
);
|
|
1091
|
+
},
|
|
1092
|
+
|
|
1093
|
+
/**
|
|
1094
|
+
* Create time options list.
|
|
1095
|
+
*
|
|
1096
|
+
* @param {string} unit Time unit - hours, minutes or seconds
|
|
1097
|
+
* @param {integer} count Count range - 12, 24 or 60
|
|
1098
|
+
* @param {integer} val Existing value for this unit
|
|
1099
|
+
* @param {integer[]} allowed Values allow for selection
|
|
1100
|
+
* @param {integer} range Override range
|
|
1101
|
+
* @private
|
|
1102
|
+
*/
|
|
1103
|
+
_optionsTime: function ( unit, count, val, allowed, range ) {
|
|
1104
|
+
var classPrefix = this.c.classPrefix;
|
|
1105
|
+
var container = this.dom.container.find('div.'+classPrefix+'-'+unit);
|
|
1106
|
+
var i, j;
|
|
1107
|
+
var render = count === 12 ?
|
|
1108
|
+
function (i) { return i; } :
|
|
1109
|
+
this._pad;
|
|
1110
|
+
var classPrefix = this.c.classPrefix;
|
|
1111
|
+
var className = classPrefix+'-table';
|
|
1112
|
+
var i18n = this.c.i18n;
|
|
1113
|
+
|
|
1114
|
+
if ( ! container.length ) {
|
|
1115
|
+
return;
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
var a = '';
|
|
1119
|
+
var span = 10;
|
|
1120
|
+
var button = function (value, label, className) {
|
|
1121
|
+
// Shift the value for PM
|
|
1122
|
+
if ( count === 12 && typeof value === 'number' ) {
|
|
1123
|
+
if (val >= 12 ) {
|
|
1124
|
+
value += 12;
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
if (value == 12) {
|
|
1128
|
+
value = 0;
|
|
1129
|
+
}
|
|
1130
|
+
else if (value == 24) {
|
|
1131
|
+
value = 12;
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
var selected = val === value || (value === 'am' && val < 12) || (value === 'pm' && val >= 12) ?
|
|
1136
|
+
'selected' :
|
|
1137
|
+
'';
|
|
1138
|
+
|
|
1139
|
+
if (typeof value === 'number' && allowed && $.inArray(value, allowed) === -1) {
|
|
1140
|
+
selected += ' disabled';
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
if ( className ) {
|
|
1144
|
+
selected += ' '+className;
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
return '<td class="selectable '+selected+'">' +
|
|
1148
|
+
'<button class="'+classPrefix+'-button '+classPrefix+'-day" type="button" data-unit="'+unit+'" data-value="'+value+ '">' +
|
|
1149
|
+
'<span>'+label+'</span>'+
|
|
1150
|
+
'</button>' +
|
|
1151
|
+
'</td>';
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
if ( count === 12 ) {
|
|
1155
|
+
// Hours with AM/PM
|
|
1156
|
+
a += '<tr>';
|
|
1157
|
+
|
|
1158
|
+
for ( i=1 ; i<=6 ; i++ ) {
|
|
1159
|
+
a += button(i, render(i));
|
|
1160
|
+
}
|
|
1161
|
+
a += button('am', i18n.amPm[0]);
|
|
1162
|
+
|
|
1163
|
+
a += '</tr>';
|
|
1164
|
+
a += '<tr>';
|
|
1165
|
+
|
|
1166
|
+
for ( i=7 ; i<=12 ; i++ ) {
|
|
1167
|
+
a += button(i, render(i));
|
|
1168
|
+
}
|
|
1169
|
+
a += button('pm', i18n.amPm[1]);
|
|
1170
|
+
a += '</tr>';
|
|
1171
|
+
|
|
1172
|
+
span = 7;
|
|
1173
|
+
}
|
|
1174
|
+
else if ( count === 24 ) {
|
|
1175
|
+
// Hours - 24
|
|
1176
|
+
var c = 0;
|
|
1177
|
+
for (j=0 ; j<4 ; j++ ) {
|
|
1178
|
+
a += '<tr>';
|
|
1179
|
+
for ( i=0 ; i<6 ; i++ ) {
|
|
1180
|
+
a += button(c, render(c));
|
|
1181
|
+
c++;
|
|
1182
|
+
}
|
|
1183
|
+
a += '</tr>';
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
span = 6;
|
|
1187
|
+
}
|
|
1188
|
+
else {
|
|
1189
|
+
// Minutes and seconds
|
|
1190
|
+
a += '<tr>';
|
|
1191
|
+
for (j=0 ; j<60 ; j+=10 ) {
|
|
1192
|
+
a += button(j, render(j), 'range');
|
|
1193
|
+
}
|
|
1194
|
+
a += '</tr>';
|
|
1195
|
+
|
|
1196
|
+
// Slight hack to allow for the different number of columns
|
|
1197
|
+
a += '</tbody></thead><table class="'+className+' '+className+'-nospace"><tbody>';
|
|
1198
|
+
|
|
1199
|
+
var start = range !== null
|
|
1200
|
+
? range
|
|
1201
|
+
: val === -1
|
|
1202
|
+
? 0
|
|
1203
|
+
: Math.floor( val / 10 )*10;
|
|
1204
|
+
|
|
1205
|
+
a += '<tr>';
|
|
1206
|
+
for (j=start+1 ; j<start+10 ; j++ ) {
|
|
1207
|
+
a += button(j, render(j));
|
|
1208
|
+
}
|
|
1209
|
+
a += '</tr>';
|
|
1210
|
+
|
|
1211
|
+
span = 6;
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
container
|
|
1215
|
+
.empty()
|
|
1216
|
+
.append(
|
|
1217
|
+
'<table class="'+className+'">'+
|
|
1218
|
+
'<thead><tr><th colspan="'+span+'">'+
|
|
1219
|
+
i18n[unit] +
|
|
1220
|
+
'</th></tr></thead>'+
|
|
1221
|
+
'<tbody>'+
|
|
1222
|
+
a+
|
|
1223
|
+
'</tbody>'+
|
|
1224
|
+
'</table>'
|
|
1225
|
+
);
|
|
1226
|
+
},
|
|
1227
|
+
|
|
1228
|
+
/**
|
|
1229
|
+
* Create the options for the month and year
|
|
1230
|
+
*
|
|
1231
|
+
* @param {integer} year Year
|
|
1232
|
+
* @param {integer} month Month (starting at 0)
|
|
1233
|
+
* @private
|
|
1234
|
+
*/
|
|
1235
|
+
_optionsTitle: function () {
|
|
1236
|
+
var i18n = this.c.i18n;
|
|
1237
|
+
var min = this.c.minDate;
|
|
1238
|
+
var max = this.c.maxDate;
|
|
1239
|
+
var minYear = min ? min.getFullYear() : null;
|
|
1240
|
+
var maxYear = max ? max.getFullYear() : null;
|
|
1241
|
+
|
|
1242
|
+
var i = minYear !== null ? minYear : new Date().getFullYear() - this.c.yearRange;
|
|
1243
|
+
var j = maxYear !== null ? maxYear : new Date().getFullYear() + this.c.yearRange;
|
|
1244
|
+
|
|
1245
|
+
this._options( 'month', this._range( 0, 11 ), i18n.months );
|
|
1246
|
+
this._options( 'year', this._range( i, j ) );
|
|
1247
|
+
|
|
1248
|
+
// Set the language strings in case any have changed
|
|
1249
|
+
this.dom.today.text(i18n.today).text(i18n.today);
|
|
1250
|
+
this.dom.clear.text(i18n.clear).text(i18n.clear);
|
|
1251
|
+
this.dom.previous
|
|
1252
|
+
.attr('title', i18n.previous)
|
|
1253
|
+
.children('button')
|
|
1254
|
+
.text(i18n.previous);
|
|
1255
|
+
this.dom.next
|
|
1256
|
+
.attr('title', i18n.next)
|
|
1257
|
+
.children('button')
|
|
1258
|
+
.text(i18n.next);
|
|
1259
|
+
},
|
|
1260
|
+
|
|
1261
|
+
/**
|
|
1262
|
+
* Simple two digit pad
|
|
1263
|
+
*
|
|
1264
|
+
* @param {integer} i Value that might need padding
|
|
1265
|
+
* @return {string|integer} Padded value
|
|
1266
|
+
* @private
|
|
1267
|
+
*/
|
|
1268
|
+
_pad: function ( i ) {
|
|
1269
|
+
return i<10 ? '0'+i : i;
|
|
1270
|
+
},
|
|
1271
|
+
|
|
1272
|
+
/**
|
|
1273
|
+
* Position the calendar to look attached to the input element
|
|
1274
|
+
* @private
|
|
1275
|
+
*/
|
|
1276
|
+
_position: function () {
|
|
1277
|
+
var offset = this.c.attachTo === 'input' ? this.dom.input.position() : this.dom.input.offset();
|
|
1278
|
+
var container = this.dom.container;
|
|
1279
|
+
var inputHeight = this.dom.input.outerHeight();
|
|
1280
|
+
|
|
1281
|
+
if (container.hasClass('inline')) {
|
|
1282
|
+
container.insertAfter( this.dom.input );
|
|
1283
|
+
return;
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
if ( this.s.parts.date && this.s.parts.time && $(window).width() > 550 ) {
|
|
1287
|
+
container.addClass('horizontal');
|
|
1288
|
+
}
|
|
1289
|
+
else {
|
|
1290
|
+
container.removeClass('horizontal');
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
if(this.c.attachTo === 'input') {
|
|
1294
|
+
container
|
|
1295
|
+
.css( {
|
|
1296
|
+
top: offset.top + inputHeight,
|
|
1297
|
+
left: offset.left
|
|
1298
|
+
} )
|
|
1299
|
+
.insertAfter( this.dom.input );
|
|
1300
|
+
}
|
|
1301
|
+
else {
|
|
1302
|
+
container
|
|
1303
|
+
.css( {
|
|
1304
|
+
top: offset.top + inputHeight,
|
|
1305
|
+
left: offset.left
|
|
1306
|
+
} )
|
|
1307
|
+
.appendTo( 'body' );
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
var calHeight = container.outerHeight();
|
|
1311
|
+
var calWidth = container.outerWidth();
|
|
1312
|
+
var scrollTop = $(window).scrollTop();
|
|
1313
|
+
|
|
1314
|
+
// Correct to the bottom
|
|
1315
|
+
if ( offset.top + inputHeight + calHeight - scrollTop > $(window).height() ) {
|
|
1316
|
+
var newTop = offset.top - calHeight;
|
|
1317
|
+
|
|
1318
|
+
container.css( 'top', newTop < 0 ? 0 : newTop );
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
// Correct to the right
|
|
1322
|
+
if ( calWidth + offset.left > $(window).width() ) {
|
|
1323
|
+
var newLeft = $(window).width() - calWidth;
|
|
1324
|
+
|
|
1325
|
+
// Account for elements which are inside a position absolute element
|
|
1326
|
+
if (this.c.attachTo === 'input') {
|
|
1327
|
+
newLeft -= $(container).offsetParent().offset().left;
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
container.css( 'left', newLeft < 0 ? 0 : newLeft );
|
|
1331
|
+
}
|
|
1332
|
+
},
|
|
1333
|
+
|
|
1334
|
+
/**
|
|
1335
|
+
* Create a simple array with a range of values
|
|
1336
|
+
*
|
|
1337
|
+
* @param {integer} start Start value (inclusive)
|
|
1338
|
+
* @param {integer} end End value (inclusive)
|
|
1339
|
+
* @param {integer} [inc=1] Increment value
|
|
1340
|
+
* @return {array} Created array
|
|
1341
|
+
* @private
|
|
1342
|
+
*/
|
|
1343
|
+
_range: function ( start, end, inc ) {
|
|
1344
|
+
var a = [];
|
|
1345
|
+
|
|
1346
|
+
if ( ! inc ) {
|
|
1347
|
+
inc = 1;
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
for ( var i=start ; i<=end ; i+=inc ) {
|
|
1351
|
+
a.push( i );
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
return a;
|
|
1355
|
+
},
|
|
1356
|
+
|
|
1357
|
+
/**
|
|
1358
|
+
* Redraw the calendar based on the display date - this is a destructive
|
|
1359
|
+
* operation
|
|
1360
|
+
*
|
|
1361
|
+
* @private
|
|
1362
|
+
*/
|
|
1363
|
+
_setCalander: function () {
|
|
1364
|
+
if ( this.s.display ) {
|
|
1365
|
+
this.dom.calendar
|
|
1366
|
+
.empty()
|
|
1367
|
+
.append( this._htmlMonth(
|
|
1368
|
+
this.s.display.getUTCFullYear(),
|
|
1369
|
+
this.s.display.getUTCMonth()
|
|
1370
|
+
) );
|
|
1371
|
+
}
|
|
1372
|
+
},
|
|
1373
|
+
|
|
1374
|
+
/**
|
|
1375
|
+
* Set the month and year for the calendar based on the current display date
|
|
1376
|
+
*
|
|
1377
|
+
* @private
|
|
1378
|
+
*/
|
|
1379
|
+
_setTitle: function () {
|
|
1380
|
+
this._optionSet( 'month', this.s.display.getUTCMonth() );
|
|
1381
|
+
this._optionSet( 'year', this.s.display.getUTCFullYear() );
|
|
1382
|
+
},
|
|
1383
|
+
|
|
1384
|
+
/**
|
|
1385
|
+
* Set the time based on the current value of the widget
|
|
1386
|
+
*
|
|
1387
|
+
* @private
|
|
1388
|
+
*/
|
|
1389
|
+
_setTime: function () {
|
|
1390
|
+
var that = this;
|
|
1391
|
+
var d = this.s.d;
|
|
1392
|
+
|
|
1393
|
+
// luxon uses different method names so need to be able to call them. This happens a few time later in this method too
|
|
1394
|
+
var luxDT = null
|
|
1395
|
+
if (this._isLuxon()) {
|
|
1396
|
+
luxDT = dateLib.DateTime.fromJSDate(d).toUTC();
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
var hours = luxDT != null
|
|
1400
|
+
? luxDT.hour
|
|
1401
|
+
: d
|
|
1402
|
+
? d.getUTCHours()
|
|
1403
|
+
: -1;
|
|
1404
|
+
|
|
1405
|
+
var allowed = function ( prop ) { // Backwards compt with `Increment` option
|
|
1406
|
+
return that.c[prop+'Available'] ?
|
|
1407
|
+
that.c[prop+'Available'] :
|
|
1408
|
+
that._range( 0, 59, that.c[prop+'Increment'] );
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
this._optionsTime( 'hours', this.s.parts.hours12 ? 12 : 24, hours, this.c.hoursAvailable )
|
|
1412
|
+
this._optionsTime(
|
|
1413
|
+
'minutes',
|
|
1414
|
+
60,
|
|
1415
|
+
luxDT != null
|
|
1416
|
+
? luxDT.minute
|
|
1417
|
+
: d
|
|
1418
|
+
? d.getUTCMinutes()
|
|
1419
|
+
: -1,
|
|
1420
|
+
allowed('minutes'),
|
|
1421
|
+
this.s.minutesRange
|
|
1422
|
+
);
|
|
1423
|
+
this._optionsTime(
|
|
1424
|
+
'seconds',
|
|
1425
|
+
60,
|
|
1426
|
+
luxDT != null
|
|
1427
|
+
? luxDT.second
|
|
1428
|
+
: d
|
|
1429
|
+
? d.getSeconds()
|
|
1430
|
+
: -1,
|
|
1431
|
+
allowed('seconds'),
|
|
1432
|
+
this.s.secondsRange
|
|
1433
|
+
);
|
|
1434
|
+
},
|
|
1435
|
+
|
|
1436
|
+
/**
|
|
1437
|
+
* Show the widget and add events to the document required only while it
|
|
1438
|
+
* is displayed
|
|
1439
|
+
*
|
|
1440
|
+
* @private
|
|
1441
|
+
*/
|
|
1442
|
+
_show: function () {
|
|
1443
|
+
var that = this;
|
|
1444
|
+
var namespace = this.s.namespace;
|
|
1445
|
+
|
|
1446
|
+
this._position();
|
|
1447
|
+
|
|
1448
|
+
// Need to reposition on scroll
|
|
1449
|
+
$(window).on( 'scroll.'+namespace+' resize.'+namespace, function () {
|
|
1450
|
+
that._position();
|
|
1451
|
+
} );
|
|
1452
|
+
|
|
1453
|
+
$('div.DTE_Body_Content').on( 'scroll.'+namespace, function () {
|
|
1454
|
+
that._position();
|
|
1455
|
+
} );
|
|
1456
|
+
|
|
1457
|
+
$('div.dataTables_scrollBody').on( 'scroll.'+namespace, function () {
|
|
1458
|
+
that._position();
|
|
1459
|
+
} );
|
|
1460
|
+
|
|
1461
|
+
var offsetParent = this.dom.input[0].offsetParent;
|
|
1462
|
+
|
|
1463
|
+
if ( offsetParent !== document.body ) {
|
|
1464
|
+
$(offsetParent).on( 'scroll.'+namespace, function () {
|
|
1465
|
+
that._position();
|
|
1466
|
+
} );
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
// On tab focus will move to a different field (no keyboard navigation
|
|
1470
|
+
// in the date picker - this might need to be changed).
|
|
1471
|
+
$(document).on( 'keydown.'+namespace, function (e) {
|
|
1472
|
+
if (
|
|
1473
|
+
e.keyCode === 9 || // tab
|
|
1474
|
+
e.keyCode === 27 || // esc
|
|
1475
|
+
e.keyCode === 13 // return
|
|
1476
|
+
) {
|
|
1477
|
+
that._hide();
|
|
1478
|
+
}
|
|
1479
|
+
} );
|
|
1480
|
+
|
|
1481
|
+
// Hide if clicking outside of the widget - but in a different click
|
|
1482
|
+
// event from the one that was used to trigger the show (bubble and
|
|
1483
|
+
// inline)
|
|
1484
|
+
setTimeout( function () {
|
|
1485
|
+
$('body').on( 'click.'+namespace, function (e) {
|
|
1486
|
+
var parents = $(e.target).parents();
|
|
1487
|
+
|
|
1488
|
+
if ( ! parents.filter( that.dom.container ).length && e.target !== that.dom.input[0] ) {
|
|
1489
|
+
that._hide();
|
|
1490
|
+
}
|
|
1491
|
+
} );
|
|
1492
|
+
}, 10 );
|
|
1493
|
+
},
|
|
1494
|
+
|
|
1495
|
+
/**
|
|
1496
|
+
* Write the formatted string to the input element this control is attached
|
|
1497
|
+
* to
|
|
1498
|
+
*
|
|
1499
|
+
* @private
|
|
1500
|
+
*/
|
|
1501
|
+
_writeOutput: function ( focus ) {
|
|
1502
|
+
var date = this.s.d;
|
|
1503
|
+
var out = '';
|
|
1504
|
+
|
|
1505
|
+
if (date) {
|
|
1506
|
+
out = this._convert(date, null, this.c.format);
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1509
|
+
this.dom.input
|
|
1510
|
+
.val( out )
|
|
1511
|
+
.trigger('change', {write: date});
|
|
1512
|
+
|
|
1513
|
+
if ( this.dom.input.attr('type') === 'hidden' ) {
|
|
1514
|
+
this.val(out, false);
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1517
|
+
if ( focus ) {
|
|
1518
|
+
this.dom.input.focus();
|
|
1519
|
+
}
|
|
1520
|
+
}
|
|
1521
|
+
} );
|
|
1522
|
+
|
|
1523
|
+
/**
|
|
1524
|
+
* Use a specificmoment compatible date library
|
|
1525
|
+
*/
|
|
1526
|
+
DateTime.use = function (lib) {
|
|
1527
|
+
dateLib = lib;
|
|
1528
|
+
};
|
|
1529
|
+
|
|
1530
|
+
/**
|
|
1531
|
+
* For generating unique namespaces
|
|
1532
|
+
*
|
|
1533
|
+
* @type {Number}
|
|
1534
|
+
* @private
|
|
1535
|
+
*/
|
|
1536
|
+
DateTime._instance = 0;
|
|
1537
|
+
|
|
1538
|
+
/**
|
|
1539
|
+
* Defaults for the date time picker
|
|
1540
|
+
*
|
|
1541
|
+
* @type {Object}
|
|
1542
|
+
*/
|
|
1543
|
+
DateTime.defaults = {
|
|
1544
|
+
attachTo: 'body',
|
|
1545
|
+
|
|
1546
|
+
buttons: {
|
|
1547
|
+
clear: false,
|
|
1548
|
+
today: false
|
|
1549
|
+
},
|
|
1550
|
+
|
|
1551
|
+
// Not documented - could be an internal property
|
|
1552
|
+
classPrefix: 'dt-datetime',
|
|
1553
|
+
|
|
1554
|
+
// function or array of ints
|
|
1555
|
+
disableDays: null,
|
|
1556
|
+
|
|
1557
|
+
// first day of the week (0: Sunday, 1: Monday, etc)
|
|
1558
|
+
firstDay: 1,
|
|
1559
|
+
|
|
1560
|
+
format: 'YYYY-MM-DD',
|
|
1561
|
+
|
|
1562
|
+
hoursAvailable: null,
|
|
1563
|
+
|
|
1564
|
+
i18n: {
|
|
1565
|
+
clear: 'Clear',
|
|
1566
|
+
previous: 'Previous',
|
|
1567
|
+
next: 'Next',
|
|
1568
|
+
months: [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ],
|
|
1569
|
+
weekdays: [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ],
|
|
1570
|
+
amPm: [ 'am', 'pm' ],
|
|
1571
|
+
hours: 'Hour',
|
|
1572
|
+
minutes: 'Minute',
|
|
1573
|
+
seconds: 'Second',
|
|
1574
|
+
unknown: '-',
|
|
1575
|
+
today: 'Today'
|
|
1576
|
+
},
|
|
1577
|
+
|
|
1578
|
+
maxDate: null,
|
|
1579
|
+
|
|
1580
|
+
minDate: null,
|
|
1581
|
+
|
|
1582
|
+
minutesAvailable: null,
|
|
1583
|
+
|
|
1584
|
+
minutesIncrement: 1, // deprecated
|
|
1585
|
+
|
|
1586
|
+
strict: true,
|
|
1587
|
+
|
|
1588
|
+
locale: 'en',
|
|
1589
|
+
|
|
1590
|
+
onChange: function () {},
|
|
1591
|
+
|
|
1592
|
+
secondsAvailable: null,
|
|
1593
|
+
|
|
1594
|
+
secondsIncrement: 1, // deprecated
|
|
1595
|
+
|
|
1596
|
+
// show the ISO week number at the head of the row
|
|
1597
|
+
showWeekNumber: false,
|
|
1598
|
+
|
|
1599
|
+
// overruled by max / min date
|
|
1600
|
+
yearRange: 25
|
|
1601
|
+
};
|
|
1602
|
+
|
|
1603
|
+
DateTime.version = '1.3.0';
|
|
1604
|
+
|
|
1605
|
+
// Global export - if no conflicts
|
|
1606
|
+
if (! window.DateTime) {
|
|
1607
|
+
window.DateTime = DateTime;
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
// Make available via jQuery
|
|
1611
|
+
$.fn.dtDateTime = function (options) {
|
|
1612
|
+
return this.each(function() {
|
|
1613
|
+
new DateTime(this, options);
|
|
1614
|
+
});
|
|
1615
|
+
}
|
|
1616
|
+
|
|
1617
|
+
// Attach to DataTables if present
|
|
1618
|
+
if ($.fn.dataTable) {
|
|
1619
|
+
$.fn.dataTable.DateTime = DateTime;
|
|
1620
|
+
$.fn.DataTable.DateTime = DateTime;
|
|
1621
|
+
|
|
1622
|
+
if ($.fn.dataTable.Editor) {
|
|
1623
|
+
$.fn.dataTable.Editor.DateTime = DateTime;
|
|
1624
|
+
}
|
|
1625
|
+
}
|
|
1626
|
+
|
|
1627
|
+
|
|
1628
|
+
export default DateTime;
|