You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by jk...@apache.org on 2014/04/27 15:53:51 UTC
[2/3] git commit: TAP5-2229: make the DatePicker JavaScript an AMD
module
TAP5-2229: make the DatePicker JavaScript an AMD module
Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/70d4efbc
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/70d4efbc
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/70d4efbc
Branch: refs/heads/master
Commit: 70d4efbce0b90dd34b20b7872e5fbe6572a248d1
Parents: f65adf6
Author: Jochen Kemnade <jo...@web.de>
Authored: Sun Apr 27 13:08:40 2014 +0200
Committer: Jochen Kemnade <jo...@web.de>
Committed: Sun Apr 27 13:08:40 2014 +0200
----------------------------------------------------------------------
.../META-INF/modules/t5/core/datefield.coffee | 17 +-
.../tapestry5/corelib/components/DateField.java | 3 +-
.../tapestry5/datepicker_106/js/datepicker.js | 744 ------------------
.../META-INF/modules/t5/core/datepicker.js | 766 +++++++++++++++++++
4 files changed, 777 insertions(+), 753 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/70d4efbc/tapestry-core/src/main/coffeescript/META-INF/modules/t5/core/datefield.coffee
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/coffeescript/META-INF/modules/t5/core/datefield.coffee b/tapestry-core/src/main/coffeescript/META-INF/modules/t5/core/datefield.coffee
index bb3a6b5..aca4653 100644
--- a/tapestry-core/src/main/coffeescript/META-INF/modules/t5/core/datefield.coffee
+++ b/tapestry-core/src/main/coffeescript/META-INF/modules/t5/core/datefield.coffee
@@ -15,8 +15,8 @@
# ## t5/core/datefield
#
# Provides support for the `core/DateField` component.
-define ["./dom", "./events", "./messages", "./ajax", "underscore", "./fields"],
- (dom, events, messages, ajax, _) ->
+define ["./dom", "./events", "./messages", "./ajax", "underscore", "./datepicker", "./fields"],
+ (dom, events, messages, ajax, _, DatePicker) ->
# Translate from the provided order (SUNDAY = 0, MONDAY = 1), to
@@ -24,18 +24,18 @@ define ["./dom", "./events", "./messages", "./ajax", "underscore", "./fields"],
serverFirstDay = parseInt messages "date-symbols.first-day"
datePickerFirstDay = if serverFirstDay is 0 then 6 else serverFirstDay - 1
- # Loalize a few other things.
- DatePicker.months = (messages "date-symbols.months").split ","
+ # Localize a few other things.
days = (messages "date-symbols.days").split ","
# Shuffle sunday to the end, so that monday is first.
days.push days.shift()
- DatePicker.days = _.map days, (name) -> name.substr(0, 1).toLowerCase()
+ monthsLabels = (messages "date-symbols.months").split ","
+ daysLabels = _.map days, (name) -> name.substr(0, 1).toLowerCase()
+ todayLabel = messages "core-datefield-today"
+ noneLabel = messages "core-datefield-none"
- DatePicker.TODAY = messages "core-datefield-today"
- DatePicker.NONE = messages "core-datefield-none"
# Track the active popup; only one allowed at a time. May look to rework this
# later so that there's just one popup and it is moved around the viewport, or
@@ -114,6 +114,9 @@ define ["./dom", "./events", "./messages", "./ajax", "underscore", "./fields"],
createPopup: ->
@datePicker = new DatePicker()
@datePicker.setFirstWeekDay datePickerFirstDay
+
+ @datePicker.setLocalizations monthsLabels, daysLabels, todayLabel, noneLabel
+
@popup = dom.create("div", { class: "datefield-popup well"}).append @datePicker.create()
@container.insertAfter @popup
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/70d4efbc/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/DateField.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/DateField.java b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/DateField.java
index 286a845..b55cc7b 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/DateField.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/DateField.java
@@ -50,8 +50,7 @@ import java.util.Locale;
* @see TextField
*/
// TODO: More testing; see https://issues.apache.org/jira/browse/TAPESTRY-1844
-@Import(library = "${tapestry.datepicker}/js/datepicker.js",
- stylesheet = "${tapestry.datepicker}/css/datepicker.css",
+@Import(stylesheet = "${tapestry.datepicker}/css/datepicker.css",
module = "t5/core/datefield")
@Events(EventConstants.VALIDATE)
public class DateField extends AbstractField
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/70d4efbc/tapestry-core/src/main/resources/META-INF/assets/tapestry5/datepicker_106/js/datepicker.js
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/resources/META-INF/assets/tapestry5/datepicker_106/js/datepicker.js b/tapestry-core/src/main/resources/META-INF/assets/tapestry5/datepicker_106/js/datepicker.js
deleted file mode 100644
index a0b6321..0000000
--- a/tapestry-core/src/main/resources/META-INF/assets/tapestry5/datepicker_106/js/datepicker.js
+++ /dev/null
@@ -1,744 +0,0 @@
-/*----------------------------------------------------------------------------\
-| Date Picker 1.06 |
-|-----------------------------------------------------------------------------|
-| Created by Erik Arvidsson |
-| (http://webfx.eae.net/contact.html#erik) |
-| For WebFX (http://webfx.eae.net/) |
-|-----------------------------------------------------------------------------|
-| A DOM based Date Picker |
-|-----------------------------------------------------------------------------|
-| Copyright (c) 1999, 2002, 2002, 2003, 2004, 2006 Erik Arvidsson |
-|-----------------------------------------------------------------------------|
-| Licensed under the Apache License, Version 2.0 (the "License"); you may not |
-| use this file except in compliance with the License. You may obtain a copy |
-| of the License at http://www.apache.org/licenses/LICENSE-2.0 |
-| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
-| Unless required by applicable law or agreed to in writing, software |
-| distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
-| WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
-| License for the specific language governing permissions and limitations |
-| under the License. |
-|-----------------------------------------------------------------------------|
-| Dependencies: datepicker.css Date picker style declarations |
-|-----------------------------------------------------------------------------|
-| 2002-02-10 | Changed _update method to only update the text nodes instead |
-| | rewriting the entire table. Also added support for mouse wheel |
-| | in IE6. |
-| 2002-01-14 | Cleaned up for 1.0 public version |
-| 2002-01-15 | Replace all innerHTML calls with DOM1 methods |
-| 2002-01-18 | Minor IE6 bug that occured when dragging the mouse |
-| 2002-01-19 | Added a popup that is shown when the user clicks on the month. |
-| | This allows navigation to 6 adjacent months. |
-| 2002-04-10 | Fixed a bug that occured in the popup when a date was selected |
-| | that caused surroundung months to "overflow" |
-| | This had the effect that one could get two October months |
-| | listed. |
-| 2002-09-06 | I had missed one place were window was used instead of |
-| | doc.parentWindow |
-| 2003-08-28 | Added support for ensurin no date overflow when changing |
-| | months. |
-| 2004-01-10 | Adding type on the buttons to ensure they are not submit |
-| | buttons. Minor CSS change for CSS2 |
-| 2006-05-28 | Changed license to Apache Software License 2.0. |
-| 2011-07-27 | Separated "selected date" and "calendar date" concepts. |
-| | Selected date is the date specifically selected by the user to |
-| | put into the form field. Calendar date reflects the currently |
-| | displayed month. These are often, but not always, the same |
-| | value. Separating them simplifies a lot of logic and resolves |
-| | TAP5-1409. Also somewhat smarter for whether to trigger |
-| | onselect when clicking "today" (and/or "none") |
-| 2012-11-11 | Minor changes to integrate into a page with Twitter Bootstrap, |
-| | and to support localizing the Today/None buttons. |
-| 2013-08-29 | More changes to adapt to Bootstrap 3 style |
-|-----------------------------------------------------------------------------|
-| Created 2001-10-?? | All changes are in the log above. | Updated 2006-05-28 |
-\----------------------------------------------------------------------------*/
-
-// The DatePicker constructor
-// oDate : Date Optional argument representing the date to select
-// Note: some minor modifications for Tapestry, to work well as a popup.
-function DatePicker(oDate)
-{
- // check arguments
- if (arguments.length == 0)
- {
- this._selectedDate = null;
- this._calendarDate = new Date;
- this._selectedInited = false;
- }
- else
- {
- this._selectedDate = oDate;
- if (!oDate)
- {
- this._calendarDate = new Date;
- } else
- {
- this._calendarDate = new Date(oDate);
- }
- this._selectedInited = true;
-
- }
-
- this._matrix = [[],[],[],[],[],[],[]];
- this._showNone = true;
- this._showToday = true;
- this._firstWeekDay = 0; // start week with monday according to standards
- this._redWeekDay = 6; // sunday is the default red day.
-}
-
-// two static fields describing the name of the months abd days
-DatePicker.months = [
- "January", "February", "March", "April",
- "May", "June", "July", "August",
- "September", "October", "November", "December"];
-DatePicker.days = ["m", "t", "w", "t", "f", "s", "s"];
-
-// Allow these to be localized
-DatePicker.TODAY = "Today"
-DatePicker.NONE = "None"
-
-
-// Function invoked whenever the selected date changes, whether by
-// navigation or when the user selects a date.
-DatePicker.prototype.onchange = function ()
-{
-};
-
-// onselect is more specified than onchange, and is triggered only when the user makes a specific selection
-// using the calendar (rather than navigating to a new month). For Tapestry,
-// this will dismiss the popup.
-DatePicker.prototype.onselect = function()
-{
-}
-
-
-// create the nodes inside the date picker
-DatePicker.prototype.create = function (doc)
-{
- if (doc == null) doc = document;
-
- this._document = doc;
-
- // create elements
- this._el = doc.createElement("div");
- this._el.className = "datePicker";
-
- // header
- var div = doc.createElement("div");
- div.className = "header";
- this._el.appendChild(div);
-
- var headerTable = doc.createElement("table");
- headerTable.className = "headerTable";
- headerTable.cellSpacing = 0;
- div.appendChild(headerTable);
-
- var tBody = doc.createElement("tbody");
- headerTable.appendChild(tBody);
-
- var tr = doc.createElement("tr");
- tBody.appendChild(tr);
-
- var td = doc.createElement("td");
- this._previousMonth = doc.createElement("button");
- this._previousMonth.className = "btn btn-default btn-xs previousButton";
- this._previousMonth.setAttribute("type", "button");
- var icon = doc.createElement("span");
- icon.className = "glyphicon glyphicon-chevron-left";
- this._previousMonth.appendChild(icon);
- td.appendChild(this._previousMonth);
- tr.appendChild(td);
-
- td = doc.createElement("td");
- td.className = "labelContainer";
- tr.appendChild(td);
-
- this._topLabel = doc.createElement("a");
- this._topLabel.className = "topLabel";
- this._topLabel.href = "#";
- this._topLabel.appendChild(doc.createTextNode(String.fromCharCode(160)));
- td.appendChild(this._topLabel);
-
- this._labelPopup = doc.createElement("div");
- this._labelPopup.className = "labelPopup";
- // no insertion
-
- td = doc.createElement("td");
- this._nextMonth = doc.createElement("button");
- this._nextMonth.className = "btn btn-default btn-xs nextButton";
- this._nextMonth.setAttribute("type", "button");
- icon = doc.createElement("span");
- icon.className = "glyphicon glyphicon-chevron-right";
- this._nextMonth.appendChild(icon);
-
- td.appendChild(this._nextMonth);
- tr.appendChild(td);
-
- // grid
- div = doc.createElement("div");
- div.className = "grid";
- this._el.appendChild(div);
- this._table = div;
-
- // footer
- div = doc.createElement("div");
- div.className = "footer";
- this._el.appendChild(div);
-
- var footerTable = doc.createElement("table");
- footerTable.className = "footerTable";
- footerTable.cellSpacing = 0;
- div.appendChild(footerTable);
-
- tBody = doc.createElement("tbody");
- footerTable.appendChild(tBody);
-
- tr = doc.createElement("tr");
- tBody.appendChild(tr);
-
- td = doc.createElement("td");
- this._todayButton = doc.createElement("button");
- this._todayButton.className = "btn btn-default btn-xs";
- this._todayButton.setAttribute("type", "button");
- this._todayButton.appendChild(doc.createTextNode(DatePicker.TODAY));
- td.appendChild(this._todayButton);
- tr.appendChild(td);
-
- td = doc.createElement("td");
- td.className = "filler";
- td.appendChild(doc.createTextNode(String.fromCharCode(160)));
- tr.appendChild(td);
-
- td = doc.createElement("td");
- this._noneButton = doc.createElement("button");
- this._noneButton.className = "btn btn-default btn-xs";
- this._noneButton.setAttribute("type", "button");
- this._noneButton.appendChild(doc.createTextNode(DatePicker.NONE));
- td.appendChild(this._noneButton);
- tr.appendChild(td);
-
-
- this._createTable(doc);
-
- this._updateTable();
- this._setTopLabel();
-
- if (!this._showNone)
- this._noneButton.style.visibility = "hidden";
- if (!this._showToday)
- this._todayButton.style.visibility = "hidden";
-
- // IE55+ extension
- this._previousMonth.hideFocus = true;
- this._nextMonth.hideFocus = true;
- this._todayButton.hideFocus = true;
- this._noneButton.hideFocus = true;
- // end IE55+ extension
-
- // hook up events
- var dp = this;
- // buttons
- this._previousMonth.onclick = function ()
- {
- dp.goToPreviousMonth();
- };
- this._nextMonth.onclick = function ()
- {
- dp.goToNextMonth();
- };
- this._todayButton.onclick = function ()
- {
- dp.goToToday();
- };
- this._noneButton.onclick = function ()
- {
- //this should always clear the date and trigger onselected...
- dp.setDate(null, true);
- };
-
- this._el.onselectstart = function ()
- {
- return false;
- };
-
- this._table.onclick = function (e)
- {
- // find event
- if (e == null) e = doc.parentWindow.event;
-
- // find td
- var el = e.target != null ? e.target : e.srcElement;
- while (el.nodeType != 1)
- el = el.parentNode;
- while (el != null && el.tagName && el.tagName.toLowerCase() != "td")
- el = el.parentNode;
-
- // if no td found, return
- if (el == null || el.tagName == null || el.tagName.toLowerCase() != "td")
- return;
-
- var d = new Date(dp._calendarDate);
- var n = Number(el.firstChild.data);
- if (isNaN(n) || n <= 0 || n == null)
- return;
-
- d.setDate(n);
- dp.setDate(d);
- };
-
- // show popup
- this._topLabel.onclick = function (e)
- {
- dp._showLabelPopup();
- return false;
- };
-
- this._el.onkeydown = function (e)
- {
- if (e == null) e = doc.parentWindow.event;
- var kc = e.keyCode != null ? e.keyCode : e.charCode;
-
- if (kc < 37 || kc > 40) return true;
-
- var d = new Date(dp._calendarDate).valueOf();
- if (kc == 37) // left
- d -= 24 * 60 * 60 * 1000;
- else if (kc == 39) // right
- d += 24 * 60 * 60 * 1000;
- else if (kc == 38) // up
- d -= 7 * 24 * 60 * 60 * 1000;
- else if (kc == 40) // down
- d += 7 * 24 * 60 * 60 * 1000;
-
- dp.setCalendarDate(new Date(d));
- return false;
- }
-
- // ie6 extension
- this._el.onmousewheel = function (e)
- {
- if (e == null) e = doc.parentWindow.event;
- var n = - e.wheelDelta / 120;
- var d = new Date(dp._calendarDate);
- var m = d.getMonth() + n;
- d.setMonth(m);
-
-
- dp.setCalendarDate(d);
-
- return false;
- }
-
- doc.onclick = function (e) {
- var targ;
-
- // find event
- if (e == null) e = doc.parentWindow.event;
-
- if (e.target) targ = e.target;
- else if (e.srcElement) targ = e.srcElement;
- // find classname 'datePicker' as parent
- var insideDatePicker = null;
- var parent = targ.parentNode;
- while (parent != null) {
- if (parent.className == 'datePicker' || parent.className == 'labelPopup') {
- insideDatePicker = parent;
- break;
- }
- parent = parent.parentNode;
- }
- }
- return this._el;
-};
-
-DatePicker.prototype.setCalendarDate = function(oDate)
-{
- if (oDate != null)
- {
- //note that calendarDate should never be null!
- this._calendarDate = oDate;
- }
- this._hideLabelPopup();
- this._setTopLabel();
- this._updateTable();
-}
-
-DatePicker.prototype.setDate = function (oDate, forceOnSelect)
-{
-
- // if null then set None
- if (oDate == null)
- {
- //if _selectedDate isn't null, then this is an actual change...
- //but if it /is/ null, we have to see if we were inited or not. If we weren't inited, then we're
- //setting this to null now, and we shouldn't fire a select...
- //but the problem occurs on subsequent... hm...
- if (this._selectedDate != null)
- {
- this._selectedDate = null;
- if (typeof this.onchange == "function")
- this.onchange();
- this.onselect();
- } else if (forceOnSelect)
- this.onselect();
- //note: setDate must inherently set the calendar date
- this._selectedInited=true;
- this.setCalendarDate(null);
-
- return;
- }
-
- // if string or number create a Date object
- if (typeof oDate == "string" || typeof oDate == "number")
- {
- oDate = new Date(oDate);
- }
-
- // do not update if not really changed
- if (this._selectedDate == null || !this._datesAreSame(this._selectedDate, oDate))
- {
- this._selectedDate = new Date(oDate);
-
- if (typeof this.onchange == "function")
- this.onchange();
-
- //so if _selectedInited is false, then the value is different only because we set the value programmatically, post-initialization.
- //that handles the creation + set event. Subsequent reveals will set it to whatever _selectedDate already was, so it's handled.
- if (this._selectedInited)
- this.onselect();
- else
- this._selectedInited=true;
- } else if (forceOnSelect)
- this.onselect();
- //note: setDate must inherently set the calendar date
- this.setCalendarDate(oDate);
-
-}
-
-
-DatePicker.prototype.getDate = function ()
-{
- if (!this._selectedDate) return null;
- return new Date(this._selectedDate); // create a new instance
-}
-
-// creates the table elements and inserts them into the date picker
-DatePicker.prototype._createTable = function (doc)
-{
- var str, i;
- var rows = 6;
- var cols = 7;
- var currentWeek = 0;
-
- var table = doc.createElement("table");
- table.className = "gridTable";
- table.cellSpacing = 0;
-
- var tBody = doc.createElement("tbody");
- table.appendChild(tBody);
-
- // days row
- var tr = doc.createElement("tr");
- tr.className = "daysRow";
-
- var td, tn;
- var nbsp = String.fromCharCode(160);
- for (i = 0; i < cols; i++)
- {
- td = doc.createElement("td");
- td.appendChild(doc.createTextNode(nbsp));
- tr.appendChild(td);
- }
- tBody.appendChild(tr);
-
- // upper line
- tr = doc.createElement("tr");
- td = doc.createElement("td");
- td.className = "upperLine";
- td.colSpan = 7;
- tr.appendChild(td);
- tBody.appendChild(tr);
-
- // rest
- for (i = 0; i < rows; i++)
- {
- tr = doc.createElement("tr");
- for (var j = 0; j < cols; j++)
- {
- td = doc.createElement("td");
- td.appendChild(doc.createTextNode(nbsp));
- tr.appendChild(td);
- }
- tBody.appendChild(tr);
- }
- str += "</table>";
-
- if (this._table != null)
- this._table.appendChild(table)
-};
-// this method updates all the text nodes inside the table as well
-// as all the classNames on the tds
-DatePicker.prototype._updateTable = function ()
-{
- // if no element no need to continue
- if (this._table == null) return;
-
- var i;
- var str = "";
- var rows = 6;
- var cols = 7;
- var currentWeek = 0;
-
- var cells = new Array(rows);
- this._matrix = new Array(rows)
- for (i = 0; i < rows; i++)
- {
- cells[i] = new Array(cols);
- this._matrix[i] = new Array(cols);
- }
-
- // Set the tmpDate to this month
- var tmpDate = new Date(this._calendarDate.getFullYear(),
- this._calendarDate.getMonth(), 1);
- var today = new Date();
- // go thorugh all days this month and store the text
- // and the class name in the cells matrix
- for (i = 1; i < 32; i++)
- {
- tmpDate.setDate(i);
- // convert to ISO, Monday is 0 and 6 is Sunday
- var weekDay = ( tmpDate.getDay() + 6 ) % 7;
- var colIndex = ( weekDay - this._firstWeekDay + 7 ) % 7;
- if (tmpDate.getMonth() == this._calendarDate.getMonth())
- {
-
- var isToday = this._datesAreSame(tmpDate, today);
-
- cells[currentWeek][colIndex] = { text: "", className: "" };
-
- if (this._datesAreSame(this._selectedDate, tmpDate))
- cells[currentWeek][colIndex].className += "selected ";
- if (isToday)
- cells[currentWeek][colIndex].className += "today ";
- if (( tmpDate.getDay() + 6 ) % 7 == this._redWeekDay) // ISO
- cells[currentWeek][colIndex].className += "red";
-
- cells[currentWeek][colIndex].text =
- this._matrix[currentWeek][colIndex] = tmpDate.getDate();
-
- if (colIndex == 6)
- currentWeek++;
- }
- }
-
- // fix day letter order if not standard
- var weekDays = DatePicker.days;
- if (this._firstWeekDay != 0)
- {
- weekDays = new Array(7);
- for (i = 0; i < 7; i++)
- weekDays[i] = DatePicker.days[ (i + this._firstWeekDay) % 7];
- }
-
- // update text in days row
- var tds = this._table.firstChild.tBodies[0].rows[0].cells;
- for (i = 0; i < cols; i++)
- tds[i].firstChild.data = weekDays[i];
-
- // update the text nodes and class names
- var trs = this._table.firstChild.tBodies[0].rows;
- var tmpCell;
- var nbsp = String.fromCharCode(160);
- for (var y = 0; y < rows; y++)
- {
- for (var x = 0; x < cols; x++)
- {
- tmpCell = trs[y + 2].cells[x];
- if (typeof cells[y][x] != "undefined")
- {
- tmpCell.className = cells[y][x].className;
- tmpCell.firstChild.data = cells[y][x].text;
- }
- else
- {
- tmpCell.className = "";
- tmpCell.firstChild.data = nbsp;
- }
- }
- }
-}
-
-// sets the label showing the year and selected month
-DatePicker.prototype._setTopLabel = function ()
-{
- var str = this._calendarDate.getFullYear() + " " + DatePicker.months[ this._calendarDate.getMonth() ];
- if (this._topLabel != null)
- this._topLabel.lastChild.data = str;
-}
-
-DatePicker.prototype.goToNextMonth = function ()
-{
- var d = new Date(this._calendarDate);
- d.setDate(Math.min(d.getDate(), DatePicker.getDaysPerMonth(d.getMonth() + 1,
- d.getFullYear()))); // no need to catch dec -> jan for the year
- d.setMonth(d.getMonth() + 1);
- this.setCalendarDate(d);
-}
-
-DatePicker.prototype.goToPreviousMonth = function ()
-{
- var d = new Date(this._calendarDate);
- d.setDate(Math.min(d.getDate(), DatePicker.getDaysPerMonth(d.getMonth() - 1,
- d.getFullYear()))); // no need to catch jan -> dec for the year
- d.setMonth(d.getMonth() - 1);
- this.setCalendarDate(d);
-}
-
-DatePicker.prototype.goToToday = function ()
-{
- //note: small tweak here so that clicking the "Today" button will properly update the selected date and trigger selected
- //but note that we want this behavior iff "today" is already selected and visible.
- //For instance: If you're looking at some date months away from today and want to jump back to today AND today is the selectedDate
- //then we don't want that to close the calendar.
- var today = new Date();
- var forceOnSelect=false;
- if (this._selectedDate == null || (this._datesAreSame(today, this._selectedDate) && this._calendarDate.getMonth() == today.getMonth() && this._calendarDate.getFullYear() == today.getFullYear())) {
- //then go ahead and force the selection...
- forceOnSelect=true;
- }
- this.setDate(new Date(), forceOnSelect);//note that setDate calls setCalendarDate...
-}
-
-DatePicker.prototype.setShowToday = function (bShowToday)
-{
- if (typeof bShowToday == "string")
- bShowToday = !/false|0|no/i.test(bShowToday);
-
- if (this._todayButton != null)
- this._todayButton.style.visibility = bShowToday ? "visible" : "hidden";
- this._showToday = bShowToday;
-}
-
-DatePicker.prototype.getShowToday = function ()
-{
- return this._showToday;
-}
-
-DatePicker.prototype.setShowNone = function (bShowNone)
-{
- if (typeof bShowNone == "string")
- bShowNone = !/false|0|no/i.test(bShowNone);
-
- if (this._noneButton != null)
- this._noneButton.style.visibility = bShowNone ? "visible" : "hidden";
- this._showNone = bShowNone;
-}
-
-DatePicker.prototype.getShowNone = function ()
-{
- return this._showNone;
-}
-
-// 0 is monday and 6 is sunday as in the ISO standard
-DatePicker.prototype.setFirstWeekDay = function (nFirstWeekDay)
-{
- if (this._firstWeekDay != nFirstWeekDay)
- {
- this._firstWeekDay = nFirstWeekDay;
- this._updateTable();
- }
-}
-
-DatePicker.prototype.getFirstWeekDay = function ()
-{
- return this._firstWeekDay;
-}
-
-// 0 is monday and 6 is sunday as in the ISO standard
-DatePicker.prototype.setRedWeekDay = function (nRedWeekDay)
-{
- if (this._redWeekDay != nRedWeekDay)
- {
- this._redWeekDay = nRedWeekDay;
- this._updateTable();
- }
-}
-
-DatePicker.prototype.getRedWeekDay = function ()
-{
- return this._redWeekDay;
-}
-
-
-DatePicker.prototype._showLabelPopup = function ()
-{
-
- var dateContext = function (dp, d)
- {
- return function (e)
- {
- dp._hideLabelPopup();
- dp.setCalendarDate(d);
- return false;
- };
- };
-
- var dp = this;
-
- // clear all old elements in the popup
- while (this._labelPopup.hasChildNodes())
- this._labelPopup.removeChild(this._labelPopup.firstChild);
-
- var a, tmp, tmp2;
- for (var i = -3; i < 4; i++)
- {
- tmp = new Date(this._calendarDate);
- tmp2 = new Date(this._calendarDate); // need another tmp to catch year change when checking leap
- tmp2.setDate(1);
- tmp2.setMonth(tmp2.getMonth() + i);
- tmp.setDate(Math.min(tmp.getDate(), DatePicker.getDaysPerMonth(tmp.getMonth() + i,
- tmp2.getFullYear())));
- tmp.setMonth(tmp.getMonth() + i);
-
- a = this._document.createElement("a");
- a.href = "javascript:void 0;";
- a.onclick = dateContext(dp, tmp);
- a.appendChild(this._document.createTextNode(tmp.getFullYear() + " " +
- DatePicker.months[ tmp.getMonth() ]));
- if (i == 0)
- a.className = "selected";
- this._labelPopup.appendChild(a);
- }
-
- this._topLabel.parentNode.insertBefore(this._labelPopup, this._topLabel.parentNode.firstChild);
-};
-
-DatePicker.prototype._hideLabelPopup = function ()
-{
- if (this._labelPopup.parentNode)
- this._labelPopup.parentNode.removeChild(this._labelPopup);
-};
-
-DatePicker.prototype._datesAreSame = function(d1,d2)
-{
- if (d1 == null && d2 == null)
- return true;
- else if (d1 == null)
- return false;
- else if (d2 == null)
- return false;
- return d1.getDate() == d2.getDate() && d1.getMonth() == d2.getMonth() && d1.getFullYear() == d2.getFullYear();
-}
-
-DatePicker._daysPerMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
-DatePicker.getDaysPerMonth = function (nMonth, nYear)
-{
- nMonth = (nMonth + 12) % 12;
- var res = DatePicker._daysPerMonth[nMonth];
- if (nMonth == 1)
- {
- res += nYear % 4 == 0 && !(nYear % 400 == 0) ? 1 : 0;
- }
- return res;
-};
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/70d4efbc/tapestry-core/src/main/resources/META-INF/modules/t5/core/datepicker.js
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/resources/META-INF/modules/t5/core/datepicker.js b/tapestry-core/src/main/resources/META-INF/modules/t5/core/datepicker.js
new file mode 100644
index 0000000..f76d1c8
--- /dev/null
+++ b/tapestry-core/src/main/resources/META-INF/modules/t5/core/datepicker.js
@@ -0,0 +1,766 @@
+/*----------------------------------------------------------------------------\
+| Date Picker 1.06 |
+|-----------------------------------------------------------------------------|
+| Created by Erik Arvidsson |
+| (http://webfx.eae.net/contact.html#erik) |
+| For WebFX (http://webfx.eae.net/) |
+|-----------------------------------------------------------------------------|
+| A DOM based Date Picker |
+|-----------------------------------------------------------------------------|
+| Copyright (c) 1999, 2002, 2002, 2003, 2004, 2006 Erik Arvidsson |
+|-----------------------------------------------------------------------------|
+| Licensed under the Apache License, Version 2.0 (the "License"); you may not |
+| use this file except in compliance with the License. You may obtain a copy |
+| of the License at http://www.apache.org/licenses/LICENSE-2.0 |
+| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
+| Unless required by applicable law or agreed to in writing, software |
+| distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
+| WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
+| License for the specific language governing permissions and limitations |
+| under the License. |
+|-----------------------------------------------------------------------------|
+| Dependencies: datepicker.css Date picker style declarations |
+|-----------------------------------------------------------------------------|
+| 2002-02-10 | Changed _update method to only update the text nodes instead |
+| | rewriting the entire table. Also added support for mouse wheel |
+| | in IE6. |
+| 2002-01-14 | Cleaned up for 1.0 public version |
+| 2002-01-15 | Replace all innerHTML calls with DOM1 methods |
+| 2002-01-18 | Minor IE6 bug that occured when dragging the mouse |
+| 2002-01-19 | Added a popup that is shown when the user clicks on the month. |
+| | This allows navigation to 6 adjacent months. |
+| 2002-04-10 | Fixed a bug that occured in the popup when a date was selected |
+| | that caused surroundung months to "overflow" |
+| | This had the effect that one could get two October months |
+| | listed. |
+| 2002-09-06 | I had missed one place were window was used instead of |
+| | doc.parentWindow |
+| 2003-08-28 | Added support for ensurin no date overflow when changing |
+| | months. |
+| 2004-01-10 | Adding type on the buttons to ensure they are not submit |
+| | buttons. Minor CSS change for CSS2 |
+| 2006-05-28 | Changed license to Apache Software License 2.0. |
+| 2011-07-27 | Separated "selected date" and "calendar date" concepts. |
+| | Selected date is the date specifically selected by the user to |
+| | put into the form field. Calendar date reflects the currently |
+| | displayed month. These are often, but not always, the same |
+| | value. Separating them simplifies a lot of logic and resolves |
+| | TAP5-1409. Also somewhat smarter for whether to trigger |
+| | onselect when clicking "today" (and/or "none") |
+| 2012-11-11 | Minor changes to integrate into a page with Twitter Bootstrap, |
+| | and to support localizing the Today/None buttons. |
+| 2013-08-29 | More changes to adapt to Bootstrap 3 style |
+| 2014-04-27 | Wrap the datepicker script into an AMD module |
+|-----------------------------------------------------------------------------|
+| Created 2001-10-?? | All changes are in the log above. | Updated 2006-05-28 |
+\----------------------------------------------------------------------------*/
+
+define([], function(){
+ //The DatePicker constructor
+ //oDate : Date Optional argument representing the date to select
+ //Note: some minor modifications for Tapestry, to work well as a popup.
+ function DatePicker(oDate)
+ {
+ // check arguments
+ if (arguments.length == 0)
+ {
+ this._selectedDate = null;
+ this._calendarDate = new Date;
+ this._selectedInited = false;
+ }
+ else
+ {
+ this._selectedDate = oDate;
+ if (!oDate)
+ {
+ this._calendarDate = new Date;
+ } else
+ {
+ this._calendarDate = new Date(oDate);
+ }
+ this._selectedInited = true;
+
+ }
+
+ this._matrix = [[],[],[],[],[],[],[]];
+ this._showNone = true;
+ this._showToday = true;
+ this._firstWeekDay = 0; // start week with monday according to standards
+ this._redWeekDay = 6; // sunday is the default red day.
+ // the names of the months and days
+ this._months = [
+ "January", "February", "March", "April",
+ "May", "June", "July", "August",
+ "September", "October", "November", "December"];
+ this._days = ["m", "t", "w", "t", "f", "s", "s"];
+
+ // Allow these to be localized
+ this._todayLabel = "Today";
+ this._noneLabel = "None";
+
+ }
+
+ // Function invoked whenever the selected date changes, whether by
+ // navigation or when the user selects a date.
+ DatePicker.prototype.onchange = function ()
+ {
+ };
+
+ // onselect is more specified than onchange, and is triggered only when the user makes a specific selection
+ // using the calendar (rather than navigating to a new month). For Tapestry,
+ // this will dismiss the popup.
+ DatePicker.prototype.onselect = function()
+ {
+ }
+
+
+ // create the nodes inside the date picker
+ DatePicker.prototype.create = function (doc)
+ {
+ if (doc == null) doc = document;
+
+ this._document = doc;
+
+ // create elements
+ this._el = doc.createElement("div");
+ this._el.className = "datePicker";
+
+ // header
+ var div = doc.createElement("div");
+ div.className = "header";
+ this._el.appendChild(div);
+
+ var headerTable = doc.createElement("table");
+ headerTable.className = "headerTable";
+ headerTable.cellSpacing = 0;
+ div.appendChild(headerTable);
+
+ var tBody = doc.createElement("tbody");
+ headerTable.appendChild(tBody);
+
+ var tr = doc.createElement("tr");
+ tBody.appendChild(tr);
+
+ var td = doc.createElement("td");
+ this._previousMonth = doc.createElement("button");
+ this._previousMonth.className = "btn btn-default btn-xs previousButton";
+ this._previousMonth.setAttribute("type", "button");
+ var icon = doc.createElement("span");
+ icon.className = "glyphicon glyphicon-chevron-left";
+ this._previousMonth.appendChild(icon);
+ td.appendChild(this._previousMonth);
+ tr.appendChild(td);
+
+ td = doc.createElement("td");
+ td.className = "labelContainer";
+ tr.appendChild(td);
+
+ this._topLabel = doc.createElement("a");
+ this._topLabel.className = "topLabel";
+ this._topLabel.href = "#";
+ this._topLabel.appendChild(doc.createTextNode(String.fromCharCode(160)));
+ td.appendChild(this._topLabel);
+
+ this._labelPopup = doc.createElement("div");
+ this._labelPopup.className = "labelPopup";
+ // no insertion
+
+ td = doc.createElement("td");
+ this._nextMonth = doc.createElement("button");
+ this._nextMonth.className = "btn btn-default btn-xs nextButton";
+ this._nextMonth.setAttribute("type", "button");
+ icon = doc.createElement("span");
+ icon.className = "glyphicon glyphicon-chevron-right";
+ this._nextMonth.appendChild(icon);
+
+ td.appendChild(this._nextMonth);
+ tr.appendChild(td);
+
+ // grid
+ div = doc.createElement("div");
+ div.className = "grid";
+ this._el.appendChild(div);
+ this._table = div;
+
+ // footer
+ div = doc.createElement("div");
+ div.className = "footer";
+ this._el.appendChild(div);
+
+ var footerTable = doc.createElement("table");
+ footerTable.className = "footerTable";
+ footerTable.cellSpacing = 0;
+ div.appendChild(footerTable);
+
+ tBody = doc.createElement("tbody");
+ footerTable.appendChild(tBody);
+
+ tr = doc.createElement("tr");
+ tBody.appendChild(tr);
+
+ td = doc.createElement("td");
+ this._todayButton = doc.createElement("button");
+ this._todayButton.className = "btn btn-default btn-xs";
+ this._todayButton.setAttribute("type", "button");
+ this._todayButton.appendChild(doc.createTextNode(this._todayLabel));
+ td.appendChild(this._todayButton);
+ tr.appendChild(td);
+
+ td = doc.createElement("td");
+ td.className = "filler";
+ td.appendChild(doc.createTextNode(String.fromCharCode(160)));
+ tr.appendChild(td);
+
+ td = doc.createElement("td");
+ this._noneButton = doc.createElement("button");
+ this._noneButton.className = "btn btn-default btn-xs";
+ this._noneButton.setAttribute("type", "button");
+ this._noneButton.appendChild(doc.createTextNode(this._noneLabel));
+ td.appendChild(this._noneButton);
+ tr.appendChild(td);
+
+
+ this._createTable(doc);
+
+ this._updateTable();
+ this._setTopLabel();
+
+ if (!this._showNone)
+ this._noneButton.style.visibility = "hidden";
+ if (!this._showToday)
+ this._todayButton.style.visibility = "hidden";
+
+ // IE55+ extension
+ this._previousMonth.hideFocus = true;
+ this._nextMonth.hideFocus = true;
+ this._todayButton.hideFocus = true;
+ this._noneButton.hideFocus = true;
+ // end IE55+ extension
+
+ // hook up events
+ var dp = this;
+ // buttons
+ this._previousMonth.onclick = function ()
+ {
+ dp.goToPreviousMonth();
+ };
+ this._nextMonth.onclick = function ()
+ {
+ dp.goToNextMonth();
+ };
+ this._todayButton.onclick = function ()
+ {
+ dp.goToToday();
+ };
+ this._noneButton.onclick = function ()
+ {
+ //this should always clear the date and trigger onselected...
+ dp.setDate(null, true);
+ };
+
+ this._el.onselectstart = function ()
+ {
+ return false;
+ };
+
+ this._table.onclick = function (e)
+ {
+ // find event
+ if (e == null) e = doc.parentWindow.event;
+
+ // find td
+ var el = e.target != null ? e.target : e.srcElement;
+ while (el.nodeType != 1)
+ el = el.parentNode;
+ while (el != null && el.tagName && el.tagName.toLowerCase() != "td")
+ el = el.parentNode;
+
+ // if no td found, return
+ if (el == null || el.tagName == null || el.tagName.toLowerCase() != "td")
+ return;
+
+ var d = new Date(dp._calendarDate);
+ var n = Number(el.firstChild.data);
+ if (isNaN(n) || n <= 0 || n == null)
+ return;
+
+ d.setDate(n);
+ dp.setDate(d);
+ };
+
+ // show popup
+ this._topLabel.onclick = function (e)
+ {
+ dp._showLabelPopup();
+ return false;
+ };
+
+ this._el.onkeydown = function (e)
+ {
+ if (e == null) e = doc.parentWindow.event;
+ var kc = e.keyCode != null ? e.keyCode : e.charCode;
+
+ if (kc < 37 || kc > 40) return true;
+
+ var d = new Date(dp._calendarDate).valueOf();
+ if (kc == 37) // left
+ d -= 24 * 60 * 60 * 1000;
+ else if (kc == 39) // right
+ d += 24 * 60 * 60 * 1000;
+ else if (kc == 38) // up
+ d -= 7 * 24 * 60 * 60 * 1000;
+ else if (kc == 40) // down
+ d += 7 * 24 * 60 * 60 * 1000;
+
+ dp.setCalendarDate(new Date(d));
+ return false;
+ }
+
+ // ie6 extension
+ this._el.onmousewheel = function (e)
+ {
+ if (e == null) e = doc.parentWindow.event;
+ var n = - e.wheelDelta / 120;
+ var d = new Date(dp._calendarDate);
+ var m = d.getMonth() + n;
+ d.setMonth(m);
+
+
+ dp.setCalendarDate(d);
+
+ return false;
+ }
+
+ doc.onclick = function (e) {
+ var targ;
+
+ // find event
+ if (e == null) e = doc.parentWindow.event;
+
+ if (e.target) targ = e.target;
+ else if (e.srcElement) targ = e.srcElement;
+ // find classname 'datePicker' as parent
+ var insideDatePicker = null;
+ var parent = targ.parentNode;
+ while (parent != null) {
+ if (parent.className == 'datePicker' || parent.className == 'labelPopup') {
+ insideDatePicker = parent;
+ break;
+ }
+ parent = parent.parentNode;
+ }
+ }
+ return this._el;
+ };
+
+ DatePicker.prototype.setCalendarDate = function(oDate)
+ {
+ if (oDate != null)
+ {
+ //note that calendarDate should never be null!
+ this._calendarDate = oDate;
+ }
+ this._hideLabelPopup();
+ this._setTopLabel();
+ this._updateTable();
+ }
+
+ DatePicker.prototype.setDate = function (oDate, forceOnSelect)
+ {
+
+ // if null then set None
+ if (oDate == null)
+ {
+ //if _selectedDate isn't null, then this is an actual change...
+ //but if it /is/ null, we have to see if we were inited or not. If we weren't inited, then we're
+ //setting this to null now, and we shouldn't fire a select...
+ //but the problem occurs on subsequent... hm...
+ if (this._selectedDate != null)
+ {
+ this._selectedDate = null;
+ if (typeof this.onchange == "function")
+ this.onchange();
+ this.onselect();
+ } else if (forceOnSelect)
+ this.onselect();
+ //note: setDate must inherently set the calendar date
+ this._selectedInited=true;
+ this.setCalendarDate(null);
+
+ return;
+ }
+
+ // if string or number create a Date object
+ if (typeof oDate == "string" || typeof oDate == "number")
+ {
+ oDate = new Date(oDate);
+ }
+
+ // do not update if not really changed
+ if (this._selectedDate == null || !this._datesAreSame(this._selectedDate, oDate))
+ {
+ this._selectedDate = new Date(oDate);
+
+ if (typeof this.onchange == "function")
+ this.onchange();
+
+ //so if _selectedInited is false, then the value is different only because we set the value programmatically, post-initialization.
+ //that handles the creation + set event. Subsequent reveals will set it to whatever _selectedDate already was, so it's handled.
+ if (this._selectedInited)
+ this.onselect();
+ else
+ this._selectedInited=true;
+ } else if (forceOnSelect)
+ this.onselect();
+ //note: setDate must inherently set the calendar date
+ this.setCalendarDate(oDate);
+
+ }
+
+
+ DatePicker.prototype.getDate = function ()
+ {
+ if (!this._selectedDate) return null;
+ return new Date(this._selectedDate); // create a new instance
+ }
+
+ // creates the table elements and inserts them into the date picker
+ DatePicker.prototype._createTable = function (doc)
+ {
+ var str, i;
+ var rows = 6;
+ var cols = 7;
+ var currentWeek = 0;
+
+ var table = doc.createElement("table");
+ table.className = "gridTable";
+ table.cellSpacing = 0;
+
+ var tBody = doc.createElement("tbody");
+ table.appendChild(tBody);
+
+ // days row
+ var tr = doc.createElement("tr");
+ tr.className = "daysRow";
+
+ var td, tn;
+ var nbsp = String.fromCharCode(160);
+ for (i = 0; i < cols; i++)
+ {
+ td = doc.createElement("td");
+ td.appendChild(doc.createTextNode(nbsp));
+ tr.appendChild(td);
+ }
+ tBody.appendChild(tr);
+
+ // upper line
+ tr = doc.createElement("tr");
+ td = doc.createElement("td");
+ td.className = "upperLine";
+ td.colSpan = 7;
+ tr.appendChild(td);
+ tBody.appendChild(tr);
+
+ // rest
+ for (i = 0; i < rows; i++)
+ {
+ tr = doc.createElement("tr");
+ for (var j = 0; j < cols; j++)
+ {
+ td = doc.createElement("td");
+ td.appendChild(doc.createTextNode(nbsp));
+ tr.appendChild(td);
+ }
+ tBody.appendChild(tr);
+ }
+ str += "</table>";
+
+ if (this._table != null)
+ this._table.appendChild(table)
+ };
+ // this method updates all the text nodes inside the table as well
+ // as all the classNames on the tds
+ DatePicker.prototype._updateTable = function ()
+ {
+ // if no element no need to continue
+ if (this._table == null) return;
+
+ var i;
+ var str = "";
+ var rows = 6;
+ var cols = 7;
+ var currentWeek = 0;
+
+ var cells = new Array(rows);
+ this._matrix = new Array(rows)
+ for (i = 0; i < rows; i++)
+ {
+ cells[i] = new Array(cols);
+ this._matrix[i] = new Array(cols);
+ }
+
+ // Set the tmpDate to this month
+ var tmpDate = new Date(this._calendarDate.getFullYear(),
+ this._calendarDate.getMonth(), 1);
+ var today = new Date();
+ // go thorugh all days this month and store the text
+ // and the class name in the cells matrix
+ for (i = 1; i < 32; i++)
+ {
+ tmpDate.setDate(i);
+ // convert to ISO, Monday is 0 and 6 is Sunday
+ var weekDay = ( tmpDate.getDay() + 6 ) % 7;
+ var colIndex = ( weekDay - this._firstWeekDay + 7 ) % 7;
+ if (tmpDate.getMonth() == this._calendarDate.getMonth())
+ {
+
+ var isToday = this._datesAreSame(tmpDate, today);
+
+ cells[currentWeek][colIndex] = { text: "", className: "" };
+
+ if (this._datesAreSame(this._selectedDate, tmpDate))
+ cells[currentWeek][colIndex].className += "selected ";
+ if (isToday)
+ cells[currentWeek][colIndex].className += "today ";
+ if (( tmpDate.getDay() + 6 ) % 7 == this._redWeekDay) // ISO
+ cells[currentWeek][colIndex].className += "red";
+
+ cells[currentWeek][colIndex].text =
+ this._matrix[currentWeek][colIndex] = tmpDate.getDate();
+
+ if (colIndex == 6)
+ currentWeek++;
+ }
+ }
+
+ // fix day letter order if not standard
+ var weekDays = this._days;
+ if (this._firstWeekDay != 0)
+ {
+ weekDays = new Array(7);
+ for (i = 0; i < 7; i++)
+ weekDays[i] = this._days[ (i + this._firstWeekDay) % 7];
+ }
+
+ // update text in days row
+ var tds = this._table.firstChild.tBodies[0].rows[0].cells;
+ for (i = 0; i < cols; i++)
+ tds[i].firstChild.data = weekDays[i];
+
+ // update the text nodes and class names
+ var trs = this._table.firstChild.tBodies[0].rows;
+ var tmpCell;
+ var nbsp = String.fromCharCode(160);
+ for (var y = 0; y < rows; y++)
+ {
+ for (var x = 0; x < cols; x++)
+ {
+ tmpCell = trs[y + 2].cells[x];
+ if (typeof cells[y][x] != "undefined")
+ {
+ tmpCell.className = cells[y][x].className;
+ tmpCell.firstChild.data = cells[y][x].text;
+ }
+ else
+ {
+ tmpCell.className = "";
+ tmpCell.firstChild.data = nbsp;
+ }
+ }
+ }
+ }
+
+ // sets the label showing the year and selected month
+ DatePicker.prototype._setTopLabel = function ()
+ {
+ var str = this._calendarDate.getFullYear() + " " + this._months[ this._calendarDate.getMonth() ];
+ if (this._topLabel != null)
+ this._topLabel.lastChild.data = str;
+ }
+
+ DatePicker.prototype.goToNextMonth = function ()
+ {
+ var d = new Date(this._calendarDate);
+ d.setDate(Math.min(d.getDate(), DatePicker.getDaysPerMonth(d.getMonth() + 1,
+ d.getFullYear()))); // no need to catch dec -> jan for the year
+ d.setMonth(d.getMonth() + 1);
+ this.setCalendarDate(d);
+ }
+
+ DatePicker.prototype.goToPreviousMonth = function ()
+ {
+ var d = new Date(this._calendarDate);
+ d.setDate(Math.min(d.getDate(), DatePicker.getDaysPerMonth(d.getMonth() - 1,
+ d.getFullYear()))); // no need to catch jan -> dec for the year
+ d.setMonth(d.getMonth() - 1);
+ this.setCalendarDate(d);
+ }
+
+ DatePicker.prototype.goToToday = function ()
+ {
+ //note: small tweak here so that clicking the "Today" button will properly update the selected date and trigger selected
+ //but note that we want this behavior iff "today" is already selected and visible.
+ //For instance: If you're looking at some date months away from today and want to jump back to today AND today is the selectedDate
+ //then we don't want that to close the calendar.
+ var today = new Date();
+ var forceOnSelect=false;
+ if (this._selectedDate == null || (this._datesAreSame(today, this._selectedDate) && this._calendarDate.getMonth() == today.getMonth() && this._calendarDate.getFullYear() == today.getFullYear())) {
+ //then go ahead and force the selection...
+ forceOnSelect=true;
+ }
+ this.setDate(new Date(), forceOnSelect);//note that setDate calls setCalendarDate...
+ }
+
+ DatePicker.prototype.setShowToday = function (bShowToday)
+ {
+ if (typeof bShowToday == "string")
+ bShowToday = !/false|0|no/i.test(bShowToday);
+
+ if (this._todayButton != null)
+ this._todayButton.style.visibility = bShowToday ? "visible" : "hidden";
+ this._showToday = bShowToday;
+ }
+
+ DatePicker.prototype.getShowToday = function ()
+ {
+ return this._showToday;
+ }
+
+ DatePicker.prototype.setShowNone = function (bShowNone)
+ {
+ if (typeof bShowNone == "string")
+ bShowNone = !/false|0|no/i.test(bShowNone);
+
+ if (this._noneButton != null)
+ this._noneButton.style.visibility = bShowNone ? "visible" : "hidden";
+ this._showNone = bShowNone;
+ }
+
+ DatePicker.prototype.getShowNone = function ()
+ {
+ return this._showNone;
+ }
+
+ // 0 is monday and 6 is sunday as in the ISO standard
+ DatePicker.prototype.setFirstWeekDay = function (nFirstWeekDay)
+ {
+ if (this._firstWeekDay != nFirstWeekDay)
+ {
+ this._firstWeekDay = nFirstWeekDay;
+ this._updateTable();
+ }
+ }
+
+ DatePicker.prototype.getFirstWeekDay = function ()
+ {
+ return this._firstWeekDay;
+ }
+
+ // 0 is monday and 6 is sunday as in the ISO standard
+ DatePicker.prototype.setRedWeekDay = function (nRedWeekDay)
+ {
+ if (this._redWeekDay != nRedWeekDay)
+ {
+ this._redWeekDay = nRedWeekDay;
+ this._updateTable();
+ }
+ }
+
+ DatePicker.prototype.getRedWeekDay = function ()
+ {
+ return this._redWeekDay;
+ }
+
+
+ DatePicker.prototype.setLocalizations = function(monthNames, dayNames, todayLabel, noneLabel)
+ {
+ this._months = monthNames;
+ this._days = dayNames;
+ this._todayLabel = todayLabel;
+ this._noneLabel = noneLabel;
+ if (this._todayButton != null)
+ {
+ this._todayButton.innerHTML = todayLabel;
+ }
+ if (this._noneButton != null)
+ {
+ this._noneButton.innerHTML = noneLabel;
+ }
+ this._updateTable();
+ }
+
+ DatePicker.prototype._showLabelPopup = function ()
+ {
+
+ var dateContext = function (dp, d)
+ {
+ return function (e)
+ {
+ dp._hideLabelPopup();
+ dp.setCalendarDate(d);
+ return false;
+ };
+ };
+
+ var dp = this;
+
+ // clear all old elements in the popup
+ while (this._labelPopup.hasChildNodes())
+ this._labelPopup.removeChild(this._labelPopup.firstChild);
+
+ var a, tmp, tmp2;
+ for (var i = -3; i < 4; i++)
+ {
+ tmp = new Date(this._calendarDate);
+ tmp2 = new Date(this._calendarDate); // need another tmp to catch year change when checking leap
+ tmp2.setDate(1);
+ tmp2.setMonth(tmp2.getMonth() + i);
+ tmp.setDate(Math.min(tmp.getDate(), DatePicker.getDaysPerMonth(tmp.getMonth() + i,
+ tmp2.getFullYear())));
+ tmp.setMonth(tmp.getMonth() + i);
+
+ a = this._document.createElement("a");
+ a.href = "javascript:void 0;";
+ a.onclick = dateContext(dp, tmp);
+ a.appendChild(this._document.createTextNode(tmp.getFullYear() + " " +
+ this._months[ tmp.getMonth() ]));
+ if (i == 0)
+ a.className = "selected";
+ this._labelPopup.appendChild(a);
+ }
+
+ this._topLabel.parentNode.insertBefore(this._labelPopup, this._topLabel.parentNode.firstChild);
+ };
+
+ DatePicker.prototype._hideLabelPopup = function ()
+ {
+ if (this._labelPopup.parentNode)
+ this._labelPopup.parentNode.removeChild(this._labelPopup);
+ };
+
+ DatePicker.prototype._datesAreSame = function(d1,d2)
+ {
+ if (d1 == null && d2 == null)
+ return true;
+ else if (d1 == null)
+ return false;
+ else if (d2 == null)
+ return false;
+ return d1.getDate() == d2.getDate() && d1.getMonth() == d2.getMonth() && d1.getFullYear() == d2.getFullYear();
+ }
+
+ DatePicker._daysPerMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
+ DatePicker.getDaysPerMonth = function (nMonth, nYear)
+ {
+ nMonth = (nMonth + 12) % 12;
+ var res = DatePicker._daysPerMonth[nMonth];
+ if (nMonth == 1)
+ {
+ res += nYear % 4 == 0 && !(nYear % 400 == 0) ? 1 : 0;
+ }
+ return res;
+ };
+ return DatePicker;
+
+});
+