PageSourceSearch

https://www.theroyalarticles.com/javascript/datepicker.js

js theroyalarticles.com collected 2026-10-02 11:50:22 UTC 20,221 bytes, 639 lines download raw bytes

1/*----------------------------------------------------------------------------\
2|                              Date Picker 1.06                               |
3|-----------------------------------------------------------------------------|
4|                         Created by Erik Arvidsson                           |
5|                  (http://webfx.eae.net/contact.html#erik)                   |
6|                      For WebFX (http://webfx.eae.net/)                      |
7|-----------------------------------------------------------------------------|
8|                            A DOM based Date Picker                          |
9|-----------------------------------------------------------------------------|
10|       Copyright (c) 1999, 2002, 2002, 2003, 2004, 2006 Erik Arvidsson       |
11|-----------------------------------------------------------------------------|
12| Licensed under the Apache License, Version 2.0 (the "License"); you may not |
13| use this file except in compliance with the License.  You may obtain a copy |
14| of the License at http://www.apache.org/licenses/LICENSE-2.0                |
15| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
16| Unless  required  by  applicable law or  agreed  to  in  writing,  software |
17| distributed under the License is distributed on an  "AS IS" BASIS,  WITHOUT |
18| WARRANTIES OR  CONDITIONS OF ANY KIND,  either express or implied.  See the |
19| License  for the  specific language  governing permissions  and limitations |
20| under the License.                                                          |
21|-----------------------------------------------------------------------------|
22| Dependencies: datepicker.css      Date picker style declarations            |
23|-----------------------------------------------------------------------------|
24| 2002-02-10 | Changed _update method to only update the text nodes instead   |
25|            | rewriting the entire table. Also added support for mouse wheel |
26|            | in IE6.                                                        |
27| 2002-01-14 | Cleaned up for 1.0 public version                              |
28| 2002-01-15 | Replace all innerHTML calls with DOM1 methods                  |
29| 2002-01-18 | Minor IE6 bug that occured when dragging the mouse             |
30| 2002-01-19 | Added a popup that is shown when the user clicks on the month. |
31|            | This allows navigation to 6 adjacent months.                   |
32| 2002-04-10 | Fixed a bug that occured in the popup when a date was selected |
33|            | that caused surroundung months to "overflow"                   |
34|            | This had the effect that one could get two October months      |
35|            | listed.                                                        |
36| 2002-09-06 | I had missed one place were window was used instead of         |
37|            | doc.parentWindow                                               |
38| 2003-08-28 | Added support for ensurin no date overflow when changing       |
39|            | months.                                                        |
40| 2004-01-10 | Adding type on the buttons to ensure they are not submit       |
41|            | buttons. Minor CSS change for CSS2                             |
42| 2006-05-28 | Changed license to Apache Software License 2.0.                |
43|-----------------------------------------------------------------------------|
44| Created 2001-10-?? | All changes are in the log above. | Updated 2006-05-28 |
45\----------------------------------------------------------------------------*/
46
47// The DatePicker constructor
48// oDate : Date Optional argument representing the date to select
49function DatePicker( oDate ) {
50	// check arguments
51	if ( arguments.length == 0 ) {
52		this._selectedDate = new Date;
53		this._none = false;
54	}
55	else {
56		this._selectedDate = oDate || new Date();
57		this._none = oDate == null;
58	}
59
60	this._matrix = [[],[],[],[],[],[],[]];
61	this._showNone = true;
62	this._showToday = true;
63	this._firstWeekDay = 0;	// start week with monday according to standards
64	this._redWeekDay = 6;	// sunday is the default red day.
65
66	this._dontChangeNone = false;
67	this._hideCalendar = false;
68}
69
70// two static fields describing the name of the months abd days
71DatePicker.months = [
72	"January", "February", "March", "April",
73	"May", "June", "July", "August",
74	"September", "October", "November", "December"];
75DatePicker.days = ["m", "t", "w", "t", "f", "s", "s"];
76
77
78DatePicker.prototype.onchange = function () {};
79
80// create the nodes inside the date picker
81DatePicker.prototype.create = function ( doc ) {
82	if ( doc == null ) doc = document;
83
84	this._document = doc;
85
86	// create elements
87	this._el = doc.createElement( "div" );
88	this._el.className = "datePicker";
89
90	// header
91	var div = doc.createElement( "div" );
92	div.className = "dateheader";
93	this._el.appendChild( div );
94
95	var headerTable = doc.createElement( "table" );
96	headerTable.className = "headerTable";
97	headerTable.cellSpacing = 0;
98	div.appendChild( headerTable );
99
100	var tBody = doc.createElement( "tbody" );
101	headerTable.appendChild( tBody );
102
103	var tr = doc.createElement( "tr" );
104	tBody.appendChild( tr );
105
106	var td = doc.createElement( "td" );
107	this._previousMonth = doc.createElement( "button" );
108	this._previousMonth.className = "previousButton";
109	this._previousMonth.setAttribute("type", "button");
110	td.appendChild( this._previousMonth );
111	tr.appendChild( td );
112
113	td = doc.createElement( "td" );
114	td.className = "labelContainer";
115	tr.appendChild( td );
116
117	this._topLabel = doc.createElement( "a" );
118	this._topLabel.className = "topLabel";
119	this._topLabel.href = "#";
120	this._topLabel.appendChild( doc.createTextNode( String.fromCharCode( 160 ) ) );
121	td.appendChild( this._topLabel );
122
123	this._labelPopup = doc.createElement( "div" );
124	this._labelPopup.className = "labelPopup";
125	// no insertion
126
127	td = doc.createElement( "td" );
128	this._nextMonth = doc.createElement( "button" );
129	this._nextMonth.className = "nextButton";
130	this._nextMonth.setAttribute("type", "button");
131	td.appendChild( this._nextMonth );
132	tr.appendChild( td );
133
134	// grid
135	div = doc.createElement( "div" );
136	div.className = "grid";
137	this._el.appendChild( div );
138	this._table = div;
139
140	// footer
141	div = doc.createElement( "div" );
142	div.className = "datefooter";
143	this._el.appendChild( div );
144
145	var footerTable = doc.createElement( "table" );
146	footerTable.className = "footerTable";
147	footerTable.cellSpacing = 0;
148	div.appendChild( footerTable );
149
150	tBody = doc.createElement( "tbody" );
151	footerTable.appendChild( tBody );
152
153	tr = doc.createElement( "tr" );
154	tBody.appendChild( tr );
155
156	td = doc.createElement( "td" );
157	this._todayButton = doc.createElement( "button" );
158	this._todayButton.className = "todayButton";
159	this._todayButton.setAttribute("type", "button");
160	this._todayButton.appendChild( doc.createTextNode( "Today" ) );
161	td.appendChild( this._todayButton );
162	tr.appendChild( td );
163
164	td = doc.createElement( "td" );
165	td.className = "filler";
166	td.appendChild( doc.createTextNode( String.fromCharCode( 160 ) ) );
167	tr.appendChild( td );
168
169	td = doc.createElement( "td" );
170	this._noneButton = doc.createElement( "button" );
171	this._noneButton.className = "noneButton";
172	this._noneButton.setAttribute("type", "button");
173	this._noneButton.appendChild( doc.createTextNode( "None" ) );
174	td.appendChild( this._noneButton );
175	tr.appendChild( td );
176
177
178
179	this._createTable( doc );
180
181	this._updateTable();
182	this._setTopLabel();
183
184	if ( !this._showNone )
185		this._noneButton.style.visibility = "hidden";
186	if ( !this._showToday )
187		this._todayButton.style.visibility = "hidden";
188
189	// IE55+ extension
190	this._previousMonth.hideFocus = true;
191	this._nextMonth.hideFocus = true;
192	this._todayButton.hideFocus = true;
193	this._noneButton.hideFocus = true;
194	// end IE55+ extension
195
196	// hook up events
197	var dp = this;
198	// buttons
199	this._previousMonth.onclick = function () {
200		dp._hideCalendar = false;
201		dp._dontChangeNone = true;
202		dp.goToPreviousMonth();
203		dp._dontChangeNone = false;
204	};
205	this._nextMonth.onclick = function () {
206		this._hideCalendar = false;
207		dp._dontChangeNone = true;
208		dp.goToNextMonth();
209		dp._dontChangeNone = false;
210	};
211	this._todayButton.onclick = function () {
212		dp.goToToday();
213	};
214	this._noneButton.onclick = function () {
215		dp.setDate( null );
216	};
217
218	this._el.onselectstart = function () {
219		return false;
220	};
221
222	this._table.onclick = function ( e ) {
223		// find event
224		if ( e == null ) e = doc.parentWindow.event;
225
226		// find td
227		var el = e.target != null ? e.target : e.srcElement;
228		while ( el.nodeType != 1 )
229			el = el.parentNode;
230		while ( el != null && el.tagName && el.tagName.toLowerCase() != "td" )
231			el = el.parentNode;
232
233		// if no td found, return
234		if ( el == null || el.tagName == null || el.tagName.toLowerCase() != "td" )
235			return;
236
237		var d = new Date( dp._selectedDate );
238		var n = Number( el.firstChild.data );
239		if ( isNaN( n ) || n <= 0 || n == null )
240			return;
241		
242		dp._hideCalendar = true;
243		d.setDate( n );
244		dp.setDate( d );
245	};
246
247	// show popup
248	this._topLabel.onclick = function ( e ) {
249		dp._hideCalendar = false;
250		dp._showLabelPopup();
251		return false;
252	};
253
254	this._el.onkeydown = function ( e ) {
255		if ( e == null ) e = doc.parentWindow.event;
256		var kc = e.keyCode != null ? e.keyCode : e.charCode;
257
258		if ( kc < 37 || kc > 40 ) return true;
259
260		var d = new Date( dp._selectedDate ).valueOf();
261		if ( kc == 37 ) // left
262			d -= 24 * 60 * 60 * 1000;
263		else if ( kc == 39 ) // right
264			d += 24 * 60 * 60 * 1000;
265		else if ( kc == 38 ) // up
266			d -= 7 * 24 * 60 * 60 * 1000;
267		else if ( kc == 40 ) // down
268			d += 7 * 24 * 60 * 60 * 1000;
269		dp._hideCalendar = true;
270		dp.setDate( new Date( d ) );
271		return false;
272	}
273
274	// ie6 extension
275	this._el.onmousewheel = function ( e ) {
276		if ( e == null ) e = doc.parentWindow.event;
277		var n = - e.wheelDelta / 120;
278		var d = new Date( dp._selectedDate );
279		var m = d.getMonth() + n;
280		d.setMonth( m );
281
282
283		dp._dontChangeNone = true;
284		dp.setDate( d );
285		dp._dontChangeNone = false;
286
287		return false;
288	}
289
290	return this._el;
291};
292
293DatePicker.prototype.setDate = function ( oDate ) {
294
295	this._hideLabelPopup();
296
297	// if null then set None
298	if ( oDate == null ) {
299		if ( !this._none ) {
300			this._none = true;
301			this._setTopLabel();
302			this._updateTable();
303
304			if ( typeof this.onchange == "function" )
305				this.onchange();
306		}
307		return;
308	}
309
310	// if string or number create a Date object
311	if ( typeof oDate == "string" || typeof oDate == "number" ) {
312		oDate = new Date( oDate );
313	}
314
315
316	// do not update if not really changed
317	if ( this._selectedDate.getDate() != oDate.getDate() ||
318		this._selectedDate.getMonth() != oDate.getMonth() ||
319		this._selectedDate.getFullYear() != oDate.getFullYear() ||
320		this._none ) {
321
322		if ( !this._dontChangeNone )
323			this._none = false;
324
325		this._selectedDate = new Date( oDate );
326
327		this._setTopLabel();
328		this._updateTable();
329
330		
331	}
332	if ( typeof this.onchange == "function" && this._hideCalendar == true ){
333		
334		this.onchange();
335	}
336	if ( !this._dontChangeNone )
337		this._none = false;
338}
339
340
341DatePicker.prototype.getDate = function () {
342	if ( this._none ) return null;
343	return new Date( this._selectedDate );	// create a new instance
344}
345
346// creates the table elements and inserts them into the date picker
347DatePicker.prototype._createTable = function ( doc ) {
348	var str, i;
349	var rows = 6;
350	var cols = 7;
351	var currentWeek = 0;
352
353	var table = doc.createElement( "table" );
354	table.className = "gridTable";
355	table.cellSpacing = 0;
356
357	var tBody = doc.createElement( "tbody" );
358	table.appendChild( tBody );
359
360	// days row
361	var tr = doc.createElement( "tr" );
362	tr.className = "daysRow";
363
364	var td, tn;
365	var nbsp = String.fromCharCode( 160 );
366	for ( i = 0; i < cols; i++ ) {
367		td = doc.createElement( "td" );
368		td.appendChild( doc.createTextNode( nbsp ) );
369		tr.appendChild( td );
370	}
371	tBody.appendChild( tr );
372
373	// upper line
374	tr = doc.createElement( "tr" );
375	td = doc.createElement( "td" );
376	td.className = "upperLine";
377	td.colSpan = 7;
378	tr.appendChild( td );
379	tBody.appendChild( tr );
380
381	// rest
382	for ( i = 0; i < rows; i++ ) {
383		tr = doc.createElement( "tr" );
384		for ( var j = 0; j < cols; j++ ) {
385			td = doc.createElement( "td" );
386			td.appendChild( doc.createTextNode( nbsp ) );
387			tr.appendChild( td );
388		}
389		tBody.appendChild( tr );
390	}
391	str += "</table>";
392
393	if ( this._table != null )
394		this._table.appendChild( table )
395};
396// this method updates all the text nodes inside the table as well
397// as all the classNames on the tds
398DatePicker.prototype._updateTable = function () {
399	// if no element no need to continue
400	if ( this._table == null ) return;
401
402	var i;
403	var str = "";
404	var rows = 6;
405	var cols = 7;
406	var currentWeek = 0;
407
408	var cells = new Array( rows );
409	this._matrix = new Array( rows )
410	for ( i = 0; i < rows; i++ ) {
411		cells[i] = new Array( cols );
412		this._matrix[i] = new Array( cols );
413	}
414
415	// Set the tmpDate to this month
416	var tmpDate = new Date( this._selectedDate.getFullYear(),
417							this._selectedDate.getMonth(), 1 );
418	var today = new Date();
419	// go thorugh all days this month and store the text
420	// and the class name in the cells matrix
421	for ( i = 1; i < 32; i++ ) {
422		tmpDate.setDate( i );
423		// convert to ISO, Monday is 0 and 6 is Sunday
424		var weekDay = ( tmpDate.getDay() + 6 ) % 7;
425		var colIndex = ( weekDay - this._firstWeekDay + 7 ) % 7;
426		if ( tmpDate.getMonth() == this._selectedDate.getMonth() ) {
427
428			var isToday = tmpDate.getDate() == today.getDate() &&
429						tmpDate.getMonth() == today.getMonth() &&
430						tmpDate.getFullYear() == today.getFullYear();
431
432			cells[currentWeek][colIndex] = { text: "", className: "" };
433
434			if ( this._selectedDate.getDate() == tmpDate.getDate() && !this._none )
435				cells[currentWeek][colIndex].className += "selected ";
436			if ( isToday )
437				cells[currentWeek][colIndex].className += "today ";
438			if ( ( tmpDate.getDay() + 6 ) % 7 == this._redWeekDay ) // ISO
439				cells[currentWeek][colIndex].className += "red";
440
441			cells[currentWeek][colIndex].text =
442				this._matrix[currentWeek][colIndex] = tmpDate.getDate();
443
444			if ( colIndex == 6 )
445				currentWeek++;
446		}
447	}
448
449	// fix day letter order if not standard
450	var weekDays = DatePicker.days;
451	if (this._firstWeekDay != 0) {
452		weekDays = new Array(7);
453		for ( i = 0; i < 7; i++)
454			weekDays[i] = DatePicker.days[ (i + this._firstWeekDay) % 7];
455	}
456
457	// update text in days row
458	var tds = this._table.firstChild.tBodies[0].rows[0].cells;
459	for ( i = 0; i < cols; i++ )
460		tds[i].firstChild.data = weekDays[i];
461
462	// update the text nodes and class names
463	var trs = this._table.firstChild.tBodies[0].rows;
464	var tmpCell;
465	var nbsp = String.fromCharCode( 160 );
466	for ( var y = 0; y < rows; y++ ) {
467		for (var x = 0; x < cols; x++) {
468			tmpCell = trs[y + 2].cells[x];
469			if ( typeof cells[y][x] != "undefined" ) {
470				tmpCell.className = cells[y][x].className;
471				tmpCell.firstChild.data = cells[y][x].text;
472			}
473			else {
474				tmpCell.className = "";
475				tmpCell.firstChild.data = nbsp;
476			}
477		}
478	}
479}
480
481// sets the label showing the year and selected month
482DatePicker.prototype._setTopLabel = function () {
483	var str = this._selectedDate.getFullYear() + " " + DatePicker.months[ this._selectedDate.getMonth() ];
484	if ( this._topLabel != null )
485		this._topLabel.lastChild.data = str;
486}
487
488DatePicker.prototype.goToNextMonth = function () {
489	var d = new Date( this._selectedDate );
490	d.setDate( Math.min(d.getDate(), DatePicker.getDaysPerMonth(d.getMonth() + 1,
491		d.getFullYear())) ); // no need to catch dec -> jan for the year
492	d.setMonth( d.getMonth() + 1 );
493	this.setDate( d );
494}
495
496DatePicker.prototype.goToPreviousMonth = function () {
497	var d = new Date( this._selectedDate );
498	d.setDate( Math.min(d.getDate(), DatePicker.getDaysPerMonth(d.getMonth() - 1,
499		d.getFullYear())) ); // no need to catch jan -> dec for the year
500	d.setMonth( d.getMonth() - 1 );
501	this.setDate( d );
502}
503
504DatePicker.prototype.goToToday = function () {
505	if ( this._none )
506		// change the selectedDate to force update if none was true
507		this._selectedDate = new Date( this._selectedDate + 10000000000 );
508	this._none = false;
509	this.setDate( new Date() );
510}
511
512DatePicker.prototype.setShowToday = function ( bShowToday ) {
513	if ( typeof bShowToday == "string" )
514		bShowToday = !/false|0|no/i.test( bShowToday );
515
516	if ( this._todayButton != null )
517		this._todayButton.style.visibility = bShowToday ? "visible" : "hidden";
518	this._showToday = bShowToday;
519}
520
521DatePicker.prototype.getShowToday = function () {
522	return this._showToday;
523}
524
525DatePicker.prototype.setShowNone = function ( bShowNone ) {
526	if ( typeof bShowNone == "string" )
527		bShowNone = !/false|0|no/i.test( bShowNone );
528
529	if ( this._noneButton != null )
530		this._noneButton.style.visibility = bShowNone ? "visible" : "hidden";
531	this._showNone = bShowNone;
532}
533
534DatePicker.prototype.getShowNone = function () {
535	return this._showNone;
536}
537
538// 0 is monday and 6 is sunday as in the ISO standard
539DatePicker.prototype.setFirstWeekDay = function ( nFirstWeekDay ) {
540	if ( this._firstWeekDay != nFirstWeekDay ) {
541		this._firstWeekDay = nFirstWeekDay;
542		this._updateTable();
543	}
544}
545
546DatePicker.prototype.getFirstWeekDay = function () {
547	return this._firstWeekDay;
548}
549
550// 0 is monday and 6 is sunday as in the ISO standard
551DatePicker.prototype.setRedWeekDay = function ( nRedWeekDay ) {
552	if ( this._redWeekDay != nRedWeekDay ) {
553		this._redWeekDay = nRedWeekDay;
554		this._updateTable();
555	}
556}
557
558DatePicker.prototype.getRedWeekDay = function () {
559	return this._redWeekDay;
560}
561
562
563DatePicker.prototype._showLabelPopup = function () {
564
565	/*
566	this._labelPopup document.createElement( "DIV" );
567	div.className = "month-popup";
568	div.noWrap = true;
569	el.unselectable = div.unselectable = "on";
570	el.onselectstart = div.onselectstart = function () { return false; };
571	*/
572
573	var dateContext = function ( dp, d ) {
574		return function ( e ) {
575			dp._dontChangeNone = true;
576			dp._hideLabelPopup();
577			dp.setDate( d );
578			dp._dontChangeNone = false;
579			return false;
580		};
581	};
582
583	var dp = this;
584
585	// clear all old elements in the popup
586	while ( this._labelPopup.hasChildNodes() )
587		this._labelPopup.removeChild( this._labelPopup.firstChild );
588
589	var a, tmp, tmp2;
590	for ( var i = -3; i < 4; i++ ) {
591		tmp = new Date( this._selectedDate );
592		tmp2 = new Date( this._selectedDate );	// need another tmp to catch year change when checking leap
593		tmp2.setDate(1);
594		tmp2.setMonth( tmp2.getMonth() + i );
595		tmp.setDate( Math.min(tmp.getDate(), DatePicker.getDaysPerMonth(tmp.getMonth() + i,
596			tmp2.getFullYear())) );
597		tmp.setMonth( tmp.getMonth() + i );
598
599		a = this._document.createElement( "a" );
600		a.href = "javascript:void 0;";
601		a.onclick = dateContext( dp, tmp );
602		a.appendChild( this._document.createTextNode( tmp.getFullYear() + " " +
603									DatePicker.months[ tmp.getMonth() ] ) );
604		if ( i == 0 )
605			a.className = "selected";
606		this._labelPopup.appendChild( a );
607	}
608
609	this._topLabel.parentNode.insertBefore( this._labelPopup, this._topLabel.parentNode.firstChild );
610};
611
612DatePicker.prototype._hideLabelPopup = function () {
613	if ( this._labelPopup.parentNode )
614		this._labelPopup.parentNode.removeChild( this._labelPopup );
615};
616
617DatePicker._daysPerMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
618DatePicker.getDaysPerMonth = function (nMonth, nYear) {
619	nMonth = (nMonth + 12) % 12;
620	var res = DatePicker._daysPerMonth[nMonth];
621	if (nMonth == 1) {
622		res += nYear % 4 == 0 && !(nYear % 400 == 0) ? 1 : 0;
623	}
624	return res;
625};
626
627function getFullISODateString(d)
628{
629 var year = d.getFullYear();
630 var month = leadingZero(d.getMonth()+1);
631 var day = leadingZero(d.getDate());
632
633 var date = year+"-"+month+"-"+day;
634 return date;
635}
636
637function leadingZero(x){
638 return (x>9)?x:'0'+x;
639}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.