diff --git a/NEWS b/NEWS
index 1e64cf736..629313fcd 100644
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,7 @@ Enhancements
- SOGo version is now displayed in preferences window (#2612)
- added the SOGoMaximumSyncWindowSize system default to overwrite the
maximum number of items returned during an ActiveSync sync operation
+- updated datepicker
Bug fixes
- fixed saved HTML content of draft when attaching a file
diff --git a/UI/WebServerResources/UIxAppointmentEditor.js b/UI/WebServerResources/UIxAppointmentEditor.js
index 98af88261..24c2c92b1 100644
--- a/UI/WebServerResources/UIxAppointmentEditor.js
+++ b/UI/WebServerResources/UIxAppointmentEditor.js
@@ -293,8 +293,11 @@ function setEndDate(newEndDate) {
function onAdjustTime(event) {
var endDate = window.getEndDate();
var startDate = window.getStartDate();
-
- if ($(this).readAttribute("id").startsWith("start")) {
+ var input = $(this);
+ if (input.tagName != 'INPUT')
+ input = input.down('input');
+
+ if (input.id.startsWith("start")) {
// Start date was changed
if (startDate == null) {
var oldStartDate = window.getShadowStartDate();
@@ -350,15 +353,15 @@ function initTimeWidgets(widgets) {
this.timeWidgets = widgets;
if (widgets['start']['date']) {
- jQuery(widgets['start']['date']).closest('.date').datepicker({autoclose: true, weekStart: firstDayOfWeek});
- jQuery(widgets['start']['date']).change(onAdjustTime);
+ jQuery(widgets['start']['date']).closest('.date').datepicker({autoclose: true, weekStart: firstDayOfWeek})
+ .on('changeDate', onAdjustTime);
widgets['start']['time'].on("time:change", onAdjustTime);
widgets['start']['time'].addInterface(SOGoTimePickerInterface);
}
if (widgets['end']['date']) {
- jQuery(widgets['end']['date']).closest('.date').datepicker({autoclose: true, weekStart: firstDayOfWeek});
- jQuery(widgets['end']['date']).change(onAdjustTime);
+ jQuery(widgets['end']['date']).closest('.date').datepicker({autoclose: true, weekStart: firstDayOfWeek})
+ .on('changeDate', onAdjustTime);
widgets['end']['time'].on("time:change", onAdjustTime);
widgets['end']['time'].addInterface(SOGoTimePickerInterface);
}
diff --git a/UI/WebServerResources/UIxContactEditor.js b/UI/WebServerResources/UIxContactEditor.js
index 2ea317035..0488cb154 100644
--- a/UI/WebServerResources/UIxContactEditor.js
+++ b/UI/WebServerResources/UIxContactEditor.js
@@ -1,25 +1,25 @@
/* -*- Mode: js2-mode; tab-width: 4; c-label-minimum-indentation: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
- Copyright (C) 2005 SKYRIX Software AG
- Copyright (C) 2006-2011 Inverse
+ Copyright (C) 2005 SKYRIX Software AG
+ Copyright (C) 2006-2011 Inverse
- This file is part of OpenGroupware.org.
+ This file is part of OpenGroupware.org.
- OGo is free software; you can redistribute it and/or modify it under
- the terms of the GNU Lesser General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any
- later version.
+ OGo is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
- OGo is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
- License for more details.
+ OGo is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
- You should have received a copy of the GNU Lesser General Public
- License along with OGo; see the file COPYING. If not, write to the
- Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA.
+ You should have received a copy of the GNU Lesser General Public
+ License along with OGo; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
*/
var dateRegex = /^(([0-9]{2})?[0-9])?[0-9]-[0-9]?[0-9]-[0-9]?[0-9]$/;
@@ -78,38 +78,35 @@ function copyContact(type, email, uid, sn, displayname,
};
function validateContactEditor() {
- var rc = true;
+ var rc = true;
- var e = $('mail');
- if (e.value.length > 0
- && !emailRE.test(e.value)) {
- alert(_("invalidemailwarn"));
- rc = false;
- }
+ var e = $('mail');
+ if (e.value.length > 0
+ && !emailRE.test(e.value)) {
+ alert(_("invalidemailwarn"));
+ rc = false;
+ }
- e = $('mozillasecondemail');
- if (e.value.length > 0
- && !emailRE.test(e.value)) {
- alert(_("invalidemailwarn"));
- rc = false;
- }
- return rc
+ e = $('mozillasecondemail');
+ if (e.value.length > 0
+ && !emailRE.test(e.value)) {
+ alert(_("invalidemailwarn"));
+ rc = false;
+ }
+ return rc
}
-this.initTimeWidgets = function (widgets) {
- this.timeWidgets = widgets;
- var firstDay = new Date();
- firstDay.setFullYear(1900,0,1);
- var lastDay = new Date();
-
- jQuery(widgets['birthday']['date']).closest('.date').datepicker({autoclose: true,
- weekStart: 0,
- endDate: lastDay,
- startDate: firstDay,
- setStartDate: lastDay,
- startView: 2,
- position: "below-shifted-left"});
-};
+function initTimeWidget(input) {
+ var firstDay = new Date();
+ firstDay.setFullYear(1900,0,1);
+ var lastDay = new Date();
+
+ jQuery(input).closest('.date').datepicker({autoclose: true,
+ endDate: lastDay,
+ startDate: firstDay,
+ setStartDate: lastDay,
+ startView: 2})
+}
function onDisplaynameKeyDown() {
var fn = $("displayname");
@@ -269,43 +266,41 @@ function onEmptyCategoryClick(event) {
}
function initEditorForm() {
- var tabsContainer = $("editorTabs");
- var controller = new SOGoTabsController();
- controller.attachToTabsContainer(tabsContainer);
+ var tabsContainer = $("editorTabs");
+ var controller = new SOGoTabsController();
+ controller.attachToTabsContainer(tabsContainer);
- displaynameChanged = ($("displayname").value.length > 0);
- $("displayname").onkeydown = onDisplaynameKeyDown;
- $("sn").onkeyup = onDisplaynameNewValue;
- $("givenname").onkeyup = onDisplaynameNewValue;
+ displaynameChanged = ($("displayname").value.length > 0);
+ $("displayname").onkeydown = onDisplaynameKeyDown;
+ $("sn").onkeyup = onDisplaynameNewValue;
+ $("givenname").onkeyup = onDisplaynameNewValue;
- $("cancelButton").observe("click", onEditorCancelClick);
- var submitButton = $("submitButton");
- if (submitButton) {
- submitButton.observe("click", onEditorSubmitClick);
- }
-
- Event.observe(document, "keydown", onDocumentKeydown);
-
- if (typeof(gCategories) != "undefined") {
- regenerateCategoriesMenu();
- }
- var catsInput = $("jsonContactCategories");
- if (catsInput && catsInput.value.length > 0) {
- var contactCats = $(catsInput.value.evalJSON(false));
- for (var i = 0; i < contactCats.length; i++) {
- appendCategoryInput(contactCats[i]);
+ $("cancelButton").observe("click", onEditorCancelClick);
+ var submitButton = $("submitButton");
+ if (submitButton) {
+ submitButton.observe("click", onEditorSubmitClick);
}
- }
- var emptyCategory = $("emptyCategory");
- if (emptyCategory) {
- emptyCategory.tabIndex = 10000;
- emptyCategory.observe("click", onEmptyCategoryClick);
- }
-
- var widgets = {'birthday': {'date': $("birthdayDate")}};
- initTimeWidgets(widgets);
+ Event.observe(document, "keydown", onDocumentKeydown);
+ if (typeof(gCategories) != "undefined") {
+ regenerateCategoriesMenu();
+ }
+ var catsInput = $("jsonContactCategories");
+ if (catsInput && catsInput.value.length > 0) {
+ var contactCats = $(catsInput.value.evalJSON(false));
+ for (var i = 0; i < contactCats.length; i++) {
+ appendCategoryInput(contactCats[i]);
+ }
+ }
+
+ var emptyCategory = $("emptyCategory");
+ if (emptyCategory) {
+ emptyCategory.tabIndex = 10000;
+ emptyCategory.observe("click", onEmptyCategoryClick);
+ }
+
+ initTimeWidget($("birthdayDate"));
}
document.observe("dom:loaded", initEditorForm);
diff --git a/UI/WebServerResources/UIxTaskEditor.js b/UI/WebServerResources/UIxTaskEditor.js
index be1be3eb9..38e0d0d30 100644
--- a/UI/WebServerResources/UIxTaskEditor.js
+++ b/UI/WebServerResources/UIxTaskEditor.js
@@ -3,169 +3,101 @@
var contactSelectorAction = 'calendars-contacts';
function uixEarlierDate(date1, date2) {
- // can this be done in a sane way?
- if (date1 && date2) {
- if (date1.getYear() < date2.getYear()) return date1;
- if (date1.getYear() > date2.getYear()) return date2;
- // same year
- if (date1.getMonth() < date2.getMonth()) return date1;
- if (date1.getMonth() > date2.getMonth()) return date2;
- // same month
- if (date1.getDate() < date2.getDate()) return date1;
- if (date1.getDate() > date2.getDate()) return date2;
- }
- // same day
- return null;
+ // can this be done in a sane way?
+ if (date1 && date2) {
+ if (date1.getYear() < date2.getYear()) return date1;
+ if (date1.getYear() > date2.getYear()) return date2;
+ // same year
+ if (date1.getMonth() < date2.getMonth()) return date1;
+ if (date1.getMonth() > date2.getMonth()) return date2;
+ // same month
+ if (date1.getDate() < date2.getDate()) return date1;
+ if (date1.getDate() > date2.getDate()) return date2;
+ }
+ // same day
+ return null;
}
function validateDate(which, label) {
- var result, dateValue;
+ var result, dateValue;
- dateValue = this._getDate(which);
- if (dateValue == null) {
- alert(label);
- result = false;
- } else
- result = dateValue;
+ dateValue = this._getDate(which);
+ if (dateValue == null) {
+ alert(label);
+ result = false;
+ } else
+ result = dateValue;
- return result;
+ return result;
}
function validateTaskEditor() {
- var e, startdate, enddate, tmpdate;
+ var e, startdate, enddate, tmpdate;
- e = document.getElementById('summary');
- if (e.value.length == 0
- && !confirm(labels.validate_notitle))
- return false;
+ e = document.getElementById('summary');
+ if (e.value.length == 0
+ && !confirm(labels.validate_notitle))
+ return false;
- e = document.getElementById('startTime_date');
- if (!e.disabled) {
- startdate = validateDate('start', labels.validate_invalid_startdate);
- if (!startdate)
- return false;
- }
-
- e = document.getElementById('dueTime_date');
- if (!e.disabled) {
- enddate = validateDate('due', labels.validate_invalid_enddate);
- if (!enddate)
- return false;
- }
-
- if (startdate && enddate) {
- tmpdate = uixEarlierDate(startdate, enddate);
- if (tmpdate == enddate) {
- // window.alert(cuicui);
- alert(labels.validate_endbeforestart);
- return false;
+ e = document.getElementById('startTime_date');
+ if (!e.disabled) {
+ startdate = validateDate('start', labels.validate_invalid_startdate);
+ if (!startdate)
+ return false;
}
- else if (tmpdate == null /* means: same date */) {
- // TODO: check time
- var startHour, startMinute, endHour, endMinute;
- var matches;
+ e = document.getElementById('dueTime_date');
+ if (!e.disabled) {
+ enddate = validateDate('due', labels.validate_invalid_enddate);
+ if (!enddate)
+ return false;
+ }
+
+ if (startdate && enddate) {
+ tmpdate = uixEarlierDate(startdate, enddate);
+ if (tmpdate == enddate) {
+ alert(labels.validate_endbeforestart);
+ return false;
+ }
+ else if (tmpdate == null /* means: same date */) {
+ // TODO: check time
+
+ var startHour, startMinute, endHour, endMinute;
+ var matches;
- matches = document.forms[0]['startTime_time'].value.match(/([0-9]+):([0-9]+)/);
- if (matches) {
- startHour = parseInt(matches[1]);
- startMinute = parseInt(matches[2]);
- matches = document.forms[0]['dueTime_time'].value.match(/([0-9]+):([0-9]+)/);
+ matches = document.forms[0]['startTime_time'].value.match(/([0-9]+):([0-9]+)/);
if (matches) {
- endHour = parseInt(matches[1]);
- endMinute = parseInt(matches[2]);
+ startHour = parseInt(matches[1]);
+ startMinute = parseInt(matches[2]);
+ matches = document.forms[0]['dueTime_time'].value.match(/([0-9]+):([0-9]+)/);
+ if (matches) {
+ endHour = parseInt(matches[1]);
+ endMinute = parseInt(matches[2]);
- if (startHour > endHour) {
- alert(labels.validate_endbeforestart);
- return false;
- }
- else if (startHour == endHour) {
- if (startMinute > endMinute) {
+ if (startHour > endHour) {
alert(labels.validate_endbeforestart);
return false;
}
+ else if (startHour == endHour) {
+ if (startMinute > endMinute) {
+ alert(labels.validate_endbeforestart);
+ return false;
+ }
+ }
+ }
+ else {
+ alert(labels.validate_invalid_enddate);
+ return false;
}
}
else {
- alert(labels.validate_invalid_enddate);
+ alert(labels.validate_invalid_startdate);
return false;
}
}
- else {
- alert(labels.validate_invalid_startdate);
- return false;
- }
- }
- }
-
- return true;
-}
-
-function toggleDetails() {
- var div = $("details");
- var buttons = $("buttons");
- var buttonsHeight = buttons.clientHeight * 3;
-
- if (div.style.visibility) {
- div.style.visibility = null;
- window.resizeBy(0, -(div.clientHeight + buttonsHeight));
- $("detailsButton").innerHTML = _("Show Details");
- } else {
- div.style.visibility = 'visible;';
- window.resizeBy(0, (div.clientHeight + buttonsHeight));
- $("detailsButton").innerHTML = _("Hide Details");
- }
-
- return false;
-}
-
-function toggleCycleVisibility(node, nodeName, hiddenValue) {
- var spanNode = $(nodeName);
- var newVisibility = ((node.value == hiddenValue) ? null : 'visible;');
- spanNode.style.visibility = newVisibility;
-
- if (nodeName == 'cycleSelectionFirstLevel') {
- var otherSpanNode = $('cycleSelectionSecondLevel');
- if (!newVisibility)
- {
- otherSpanNode.superVisibility = otherSpanNode.style.visibility;
- otherSpanNode.style.visibility = null;
- }
- else
- {
- otherSpanNode.style.visibility = otherSpanNode.superVisibility;
- otherSpanNode.superVisibility = null;
- }
- }
-}
-
-function addContact(tag, fullContactName, contactId, contactName, contactEmail) {
- var uids = $('uixselector-participants-uidList');
- log ("contactId: " + contactId);
- if (contactId)
- {
- var re = new RegExp("(^|,)" + contactId + "($|,)");
-
- log ("uids: " + uids);
- if (!re.test(uids.value))
- {
- log ("no match... realling adding");
- if (uids.value.length > 0)
- uids.value += ',' + contactId;
- else
- uids.value = contactId;
-
- var names = $('uixselector-participants-display');
- names.innerHTML += ('
'
- + contactName + '');
- }
- else
- log ("match... ignoring contact");
}
- return false;
+ return true;
}
function onTimeControlCheck(checkBox) {
@@ -184,140 +116,141 @@ function onTimeControlCheck(checkBox) {
}
function saveEvent(sender) {
- if (validateTaskEditor())
- document.forms['editform'].submit();
+ if (validateTaskEditor())
+ document.forms['editform'].submit();
- return false;
+ return false;
}
function startDayAsShortString() {
- return dayAsShortDateString($('startTime_date'));
+ return dayAsShortDateString($('startTime_date'));
}
function dueDayAsShortString() {
- return dayAsShortDateString($('dueTime_date'));
+ return dayAsShortDateString($('dueTime_date'));
}
this._getDate = function(which) {
- var date = window.timeWidgets[which]['date'].inputAsDate();
- var time = window.timeWidgets[which]['time'].value.split(":");
- date.setHours(time[0]);
- date.setMinutes(time[1]);
+ var date = window.timeWidgets[which]['date'].inputAsDate();
+ var time = window.timeWidgets[which]['time'].value.split(":");
+ date.setHours(time[0]);
+ date.setMinutes(time[1]);
- if (isNaN(date.getTime()))
- return null;
+ if (isNaN(date.getTime()))
+ return null;
- return date;
+ return date;
};
this._getShadowDate = function(which) {
- var date = window.timeWidgets[which]['date'].getAttribute("shadow-value").asDate();
- var time = window.timeWidgets[which]['time'].getAttribute("shadow-value").split(":");
- date.setHours(time[0]);
- date.setMinutes(time[1]);
+ var date = window.timeWidgets[which]['date'].getAttribute("shadow-value").asDate();
+ var time = window.timeWidgets[which]['time'].getAttribute("shadow-value").split(":");
+ date.setHours(time[0]);
+ date.setMinutes(time[1]);
- return date;
+ return date;
};
this.getStartDate = function() {
- return this._getDate('start');
+ return this._getDate('start');
};
this.getDueDate = function() {
- return this._getDate('due');
+ return this._getDate('due');
};
this.getShadowStartDate = function() {
- return this._getShadowDate('start');
+ return this._getShadowDate('start');
};
this.getShadowDueDate = function() {
- return this._getShadowDate('due');
+ return this._getShadowDate('due');
};
this._setDate = function(which, newDate) {
- window.timeWidgets[which]['date'].setInputAsDate(newDate);
- window.timeWidgets[which]['time'].value = newDate.getDisplayHoursString();
+ window.timeWidgets[which]['date'].setInputAsDate(newDate);
+ window.timeWidgets[which]['time'].value = newDate.getDisplayHoursString();
- // Update date picker
- var dateComponent = jQuery(window.timeWidgets[which]['date']).closest('.date');
- dateComponent.data('date', window.timeWidgets[which]['date'].value);
- dateComponent.datepicker('update');
+ // Update date picker
+ var dateComponent = jQuery(window.timeWidgets[which]['date']).closest('.date');
+ dateComponent.data('date', window.timeWidgets[which]['date'].value);
+ dateComponent.datepicker('update');
};
this.setStartDate = function(newStartDate) {
- this._setDate('start', newStartDate);
+ this._setDate('start', newStartDate);
};
this.setDueDate = function(newDueDate) {
- this._setDate('due', newDueDate);
+ this._setDate('due', newDueDate);
};
this.onAdjustTime = function(event) {
- onAdjustDueTime(event);
+ onAdjustDueTime(event);
};
this.onAdjustDueTime = function(event) {
- if (!window.timeWidgets['due']['date'].disabled) {
- var dateDelta = (window.getStartDate().valueOf()
- - window.getShadowStartDate().valueOf());
- var newDueDate = new Date(window.getDueDate().valueOf() + dateDelta);
- window.setDueDate(newDueDate);
- }
- window.timeWidgets['start']['date'].updateShadowValue();
- window.timeWidgets['start']['time'].updateShadowValue();
+ if (!window.timeWidgets['due']['date'].disabled) {
+ var dateDelta = (window.getStartDate().valueOf()
+ - window.getShadowStartDate().valueOf());
+ var newDueDate = new Date(window.getDueDate().valueOf() + dateDelta);
+ window.setDueDate(newDueDate);
+ }
+ window.timeWidgets['start']['date'].updateShadowValue();
+ window.timeWidgets['start']['time'].updateShadowValue();
};
this.initTimeWidgets = function (widgets) {
- this.timeWidgets = widgets;
-
- jQuery(widgets['start']['date']).closest('.date').datepicker({autoclose: true, weekStart: firstDayOfWeek});
- jQuery(widgets['due']['date']).closest('.date').datepicker({autoclose: true, weekStart: firstDayOfWeek});
- jQuery('#statusTime_date').closest('.date').datepicker({autoclose: true, weekStart: firstDayOfWeek});
+ this.timeWidgets = widgets;
- jQuery(widgets['start']['date']).change(onAdjustTime);
- widgets['start']['time'].on("time:change", onAdjustDueTime);
- widgets['start']['time'].addInterface(SOGoTimePickerInterface);
- widgets['due']['time'].addInterface(SOGoTimePickerInterface);
+ jQuery(widgets['start']['date']).closest('.date').datepicker({autoclose: true, weekStart: firstDayOfWeek})
+ .on('changeDate', onAdjustTime);
+ widgets['start']['time'].on("time:change", onAdjustDueTime);
+ widgets['start']['time'].addInterface(SOGoTimePickerInterface);
+
+ jQuery(widgets['due']['date']).closest('.date').datepicker({autoclose: true, weekStart: firstDayOfWeek});
+ widgets['due']['time'].addInterface(SOGoTimePickerInterface);
+
+ jQuery('#statusTime_date').closest('.date').datepicker({autoclose: true, weekStart: firstDayOfWeek});
};
-
+
function onStatusListChange(event) {
- var value = $("statusList").value;
- var statusTimeDate = $("statusTime_date");
- var statusPercent = $("statusPercent");
+ var value = $("statusList").value;
+ var statusTimeDate = $("statusTime_date");
+ var statusPercent = $("statusPercent");
- if (value == "WONoSelectionString") {
- statusTimeDate.disabled = true;
- statusPercent.disabled = true;
- statusPercent.value = "";
- }
- else if (value == "0") {
- statusTimeDate.disabled = true;
- statusPercent.disabled = false;
- }
- else if (value == "1") {
- statusTimeDate.disabled = true;
- statusPercent.disabled = false;
- }
- else if (value == "2") {
- statusTimeDate.disabled = false;
- statusPercent.disabled = false;
- statusPercent.value = "100";
- }
- else if (value == "3") {
- statusTimeDate.disabled = true;
- statusPercent.disabled = true;
- }
- else {
- statusTimeDate.disabled = true;
- }
+ if (value == "WONoSelectionString") {
+ statusTimeDate.disabled = true;
+ statusPercent.disabled = true;
+ statusPercent.value = "";
+ }
+ else if (value == "0") {
+ statusTimeDate.disabled = true;
+ statusPercent.disabled = false;
+ }
+ else if (value == "1") {
+ statusTimeDate.disabled = true;
+ statusPercent.disabled = false;
+ }
+ else if (value == "2") {
+ statusTimeDate.disabled = false;
+ statusPercent.disabled = false;
+ statusPercent.value = "100";
+ }
+ else if (value == "3") {
+ statusTimeDate.disabled = true;
+ statusPercent.disabled = true;
+ }
+ else {
+ statusTimeDate.disabled = true;
+ }
}
function initializeStatusLine() {
- var statusList = $("statusList");
- if (statusList) {
- statusList.observe("change", onStatusListChange);
- }
+ var statusList = $("statusList");
+ if (statusList) {
+ statusList.observe("change", onStatusListChange);
+ }
}
function onTaskEditorLoad() {
diff --git a/UI/WebServerResources/datepicker.css b/UI/WebServerResources/datepicker.css
index 16d10d4be..6f061df8b 100644
--- a/UI/WebServerResources/datepicker.css
+++ b/UI/WebServerResources/datepicker.css
@@ -8,39 +8,75 @@
*
*/
.datepicker {
- top: 0;
- left: 0;
padding: 4px;
- margin-top: 1px;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
+ direction: ltr;
/*.dow {
border-top: 1px solid #ddd !important;
}*/
-
}
-.datepicker:before {
+.datepicker-inline {
+ width: 220px;
+}
+.datepicker.datepicker-rtl {
+ direction: rtl;
+}
+.datepicker.datepicker-rtl table tr td span {
+ float: right;
+}
+.datepicker-dropdown {
+ top: 0;
+ left: 0;
+}
+.datepicker-dropdown:before {
content: '';
display: inline-block;
border-left: 7px solid transparent;
border-right: 7px solid transparent;
border-bottom: 7px solid #ccc;
+ border-top: 0;
border-bottom-color: rgba(0, 0, 0, 0.2);
position: absolute;
- top: -7px;
- left: 6px;
}
-.datepicker:after {
+.datepicker-dropdown:after {
content: '';
display: inline-block;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-bottom: 6px solid #ffffff;
+ border-top: 0;
position: absolute;
- top: -6px;
+}
+.datepicker-dropdown.datepicker-orient-left:before {
+ left: 6px;
+}
+.datepicker-dropdown.datepicker-orient-left:after {
left: 7px;
}
+.datepicker-dropdown.datepicker-orient-right:before {
+ right: 6px;
+}
+.datepicker-dropdown.datepicker-orient-right:after {
+ right: 7px;
+}
+.datepicker-dropdown.datepicker-orient-top:before {
+ top: -7px;
+}
+.datepicker-dropdown.datepicker-orient-top:after {
+ top: -6px;
+}
+.datepicker-dropdown.datepicker-orient-bottom:before {
+ bottom: -7px;
+ border-bottom: 0;
+ border-top: 7px solid #999;
+}
+.datepicker-dropdown.datepicker-orient-bottom:after {
+ bottom: -6px;
+ border-bottom: 0;
+ border-top: 6px solid #ffffff;
+}
.datepicker > div {
display: none;
}
@@ -55,6 +91,12 @@
}
.datepicker table {
margin: 0;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
}
.datepicker td,
.datepicker th {
@@ -64,25 +106,31 @@
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
+ border: none;
}
-.datepicker td.day:hover {
+.table-striped .datepicker table tr td,
+.table-striped .datepicker table tr th {
+ background-color: transparent;
+}
+.datepicker table tr td.day:hover,
+.datepicker table tr td.day.focused {
background: #eeeeee;
cursor: pointer;
}
-.datepicker td.old,
-.datepicker td.new {
+.datepicker table tr td.old,
+.datepicker table tr td.new {
color: #999999;
}
-.datepicker td.disabled,
-.datepicker td.disabled:hover {
+.datepicker table tr td.disabled,
+.datepicker table tr td.disabled:hover {
background: none;
color: #999999;
cursor: default;
}
-.datepicker td.today,
-.datepicker td.today:hover,
-.datepicker td.today.disabled,
-.datepicker td.today.disabled:hover {
+.datepicker table tr td.today,
+.datepicker table tr td.today:hover,
+.datepicker table tr td.today.disabled,
+.datepicker table tr td.today.disabled:hover {
background-color: #fde19a;
background-image: -moz-linear-gradient(top, #fdd49a, #fdf59a);
background-image: -ms-linear-gradient(top, #fdd49a, #fdf59a);
@@ -94,53 +142,112 @@
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdd49a', endColorstr='#fdf59a', GradientType=0);
border-color: #fdf59a #fdf59a #fbed50;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
- filter: progid:dximagetransform.microsoft.gradient(enabled=false);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
+ color: #000;
}
-.datepicker td.today:hover,
-.datepicker td.today:hover:hover,
-.datepicker td.today.disabled:hover,
-.datepicker td.today.disabled:hover:hover,
-.datepicker td.today:active,
-.datepicker td.today:hover:active,
-.datepicker td.today.disabled:active,
-.datepicker td.today.disabled:hover:active,
-.datepicker td.today.active,
-.datepicker td.today:hover.active,
-.datepicker td.today.disabled.active,
-.datepicker td.today.disabled:hover.active,
-.datepicker td.today.disabled,
-.datepicker td.today:hover.disabled,
-.datepicker td.today.disabled.disabled,
-.datepicker td.today.disabled:hover.disabled,
-.datepicker td.today[disabled],
-.datepicker td.today:hover[disabled],
-.datepicker td.today.disabled[disabled],
-.datepicker td.today.disabled:hover[disabled] {
+.datepicker table tr td.today:hover,
+.datepicker table tr td.today:hover:hover,
+.datepicker table tr td.today.disabled:hover,
+.datepicker table tr td.today.disabled:hover:hover,
+.datepicker table tr td.today:active,
+.datepicker table tr td.today:hover:active,
+.datepicker table tr td.today.disabled:active,
+.datepicker table tr td.today.disabled:hover:active,
+.datepicker table tr td.today.active,
+.datepicker table tr td.today:hover.active,
+.datepicker table tr td.today.disabled.active,
+.datepicker table tr td.today.disabled:hover.active,
+.datepicker table tr td.today.disabled,
+.datepicker table tr td.today:hover.disabled,
+.datepicker table tr td.today.disabled.disabled,
+.datepicker table tr td.today.disabled:hover.disabled,
+.datepicker table tr td.today[disabled],
+.datepicker table tr td.today:hover[disabled],
+.datepicker table tr td.today.disabled[disabled],
+.datepicker table tr td.today.disabled:hover[disabled] {
background-color: #fdf59a;
}
-.datepicker td.today:active,
-.datepicker td.today:hover:active,
-.datepicker td.today.disabled:active,
-.datepicker td.today.disabled:hover:active,
-.datepicker td.today.active,
-.datepicker td.today:hover.active,
-.datepicker td.today.disabled.active,
-.datepicker td.today.disabled:hover.active {
+.datepicker table tr td.today:active,
+.datepicker table tr td.today:hover:active,
+.datepicker table tr td.today.disabled:active,
+.datepicker table tr td.today.disabled:hover:active,
+.datepicker table tr td.today.active,
+.datepicker table tr td.today:hover.active,
+.datepicker table tr td.today.disabled.active,
+.datepicker table tr td.today.disabled:hover.active {
background-color: #fbf069 \9;
}
-.datepicker td.range,
-.datepicker td.range:hover,
-.datepicker td.range.disabled,
-.datepicker td.range.disabled:hover {
+.datepicker table tr td.today:hover:hover {
+ color: #000;
+}
+.datepicker table tr td.today.active:hover {
+ color: #fff;
+}
+.datepicker table tr td.range,
+.datepicker table tr td.range:hover,
+.datepicker table tr td.range.disabled,
+.datepicker table tr td.range.disabled:hover {
background: #eeeeee;
-webkit-border-radius: 0;
-moz-border-radius: 0;
border-radius: 0;
}
-.datepicker td.selected,
-.datepicker td.selected:hover,
-.datepicker td.selected.disabled,
-.datepicker td.selected.disabled:hover {
+.datepicker table tr td.range.today,
+.datepicker table tr td.range.today:hover,
+.datepicker table tr td.range.today.disabled,
+.datepicker table tr td.range.today.disabled:hover {
+ background-color: #f3d17a;
+ background-image: -moz-linear-gradient(top, #f3c17a, #f3e97a);
+ background-image: -ms-linear-gradient(top, #f3c17a, #f3e97a);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f3c17a), to(#f3e97a));
+ background-image: -webkit-linear-gradient(top, #f3c17a, #f3e97a);
+ background-image: -o-linear-gradient(top, #f3c17a, #f3e97a);
+ background-image: linear-gradient(top, #f3c17a, #f3e97a);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f3c17a', endColorstr='#f3e97a', GradientType=0);
+ border-color: #f3e97a #f3e97a #edde34;
+ border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
+ -webkit-border-radius: 0;
+ -moz-border-radius: 0;
+ border-radius: 0;
+}
+.datepicker table tr td.range.today:hover,
+.datepicker table tr td.range.today:hover:hover,
+.datepicker table tr td.range.today.disabled:hover,
+.datepicker table tr td.range.today.disabled:hover:hover,
+.datepicker table tr td.range.today:active,
+.datepicker table tr td.range.today:hover:active,
+.datepicker table tr td.range.today.disabled:active,
+.datepicker table tr td.range.today.disabled:hover:active,
+.datepicker table tr td.range.today.active,
+.datepicker table tr td.range.today:hover.active,
+.datepicker table tr td.range.today.disabled.active,
+.datepicker table tr td.range.today.disabled:hover.active,
+.datepicker table tr td.range.today.disabled,
+.datepicker table tr td.range.today:hover.disabled,
+.datepicker table tr td.range.today.disabled.disabled,
+.datepicker table tr td.range.today.disabled:hover.disabled,
+.datepicker table tr td.range.today[disabled],
+.datepicker table tr td.range.today:hover[disabled],
+.datepicker table tr td.range.today.disabled[disabled],
+.datepicker table tr td.range.today.disabled:hover[disabled] {
+ background-color: #f3e97a;
+}
+.datepicker table tr td.range.today:active,
+.datepicker table tr td.range.today:hover:active,
+.datepicker table tr td.range.today.disabled:active,
+.datepicker table tr td.range.today.disabled:hover:active,
+.datepicker table tr td.range.today.active,
+.datepicker table tr td.range.today:hover.active,
+.datepicker table tr td.range.today.disabled.active,
+.datepicker table tr td.range.today.disabled:hover.active {
+ background-color: #efe24b \9;
+}
+.datepicker table tr td.selected,
+.datepicker table tr td.selected:hover,
+.datepicker table tr td.selected.disabled,
+.datepicker table tr td.selected.disabled:hover {
background-color: #9e9e9e;
background-image: -moz-linear-gradient(top, #b3b3b3, #808080);
background-image: -ms-linear-gradient(top, #b3b3b3, #808080);
@@ -152,46 +259,46 @@
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#b3b3b3', endColorstr='#808080', GradientType=0);
border-color: #808080 #808080 #595959;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
- filter: progid:dximagetransform.microsoft.gradient(enabled=false);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
color: #fff;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}
-.datepicker td.selected:hover,
-.datepicker td.selected:hover:hover,
-.datepicker td.selected.disabled:hover,
-.datepicker td.selected.disabled:hover:hover,
-.datepicker td.selected:active,
-.datepicker td.selected:hover:active,
-.datepicker td.selected.disabled:active,
-.datepicker td.selected.disabled:hover:active,
-.datepicker td.selected.active,
-.datepicker td.selected:hover.active,
-.datepicker td.selected.disabled.active,
-.datepicker td.selected.disabled:hover.active,
-.datepicker td.selected.disabled,
-.datepicker td.selected:hover.disabled,
-.datepicker td.selected.disabled.disabled,
-.datepicker td.selected.disabled:hover.disabled,
-.datepicker td.selected[disabled],
-.datepicker td.selected:hover[disabled],
-.datepicker td.selected.disabled[disabled],
-.datepicker td.selected.disabled:hover[disabled] {
+.datepicker table tr td.selected:hover,
+.datepicker table tr td.selected:hover:hover,
+.datepicker table tr td.selected.disabled:hover,
+.datepicker table tr td.selected.disabled:hover:hover,
+.datepicker table tr td.selected:active,
+.datepicker table tr td.selected:hover:active,
+.datepicker table tr td.selected.disabled:active,
+.datepicker table tr td.selected.disabled:hover:active,
+.datepicker table tr td.selected.active,
+.datepicker table tr td.selected:hover.active,
+.datepicker table tr td.selected.disabled.active,
+.datepicker table tr td.selected.disabled:hover.active,
+.datepicker table tr td.selected.disabled,
+.datepicker table tr td.selected:hover.disabled,
+.datepicker table tr td.selected.disabled.disabled,
+.datepicker table tr td.selected.disabled:hover.disabled,
+.datepicker table tr td.selected[disabled],
+.datepicker table tr td.selected:hover[disabled],
+.datepicker table tr td.selected.disabled[disabled],
+.datepicker table tr td.selected.disabled:hover[disabled] {
background-color: #808080;
}
-.datepicker td.selected:active,
-.datepicker td.selected:hover:active,
-.datepicker td.selected.disabled:active,
-.datepicker td.selected.disabled:hover:active,
-.datepicker td.selected.active,
-.datepicker td.selected:hover.active,
-.datepicker td.selected.disabled.active,
-.datepicker td.selected.disabled:hover.active {
+.datepicker table tr td.selected:active,
+.datepicker table tr td.selected:hover:active,
+.datepicker table tr td.selected.disabled:active,
+.datepicker table tr td.selected.disabled:hover:active,
+.datepicker table tr td.selected.active,
+.datepicker table tr td.selected:hover.active,
+.datepicker table tr td.selected.disabled.active,
+.datepicker table tr td.selected.disabled:hover.active {
background-color: #666666 \9;
}
-.datepicker td.active,
-.datepicker td.active:hover,
-.datepicker td.active.disabled,
-.datepicker td.active.disabled:hover {
+.datepicker table tr td.active,
+.datepicker table tr td.active:hover,
+.datepicker table tr td.active.disabled,
+.datepicker table tr td.active.disabled:hover {
background-color: #006dcc;
background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
background-image: -ms-linear-gradient(top, #0088cc, #0044cc);
@@ -203,43 +310,43 @@
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);
border-color: #0044cc #0044cc #002a80;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
- filter: progid:dximagetransform.microsoft.gradient(enabled=false);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
color: #fff;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}
-.datepicker td.active:hover,
-.datepicker td.active:hover:hover,
-.datepicker td.active.disabled:hover,
-.datepicker td.active.disabled:hover:hover,
-.datepicker td.active:active,
-.datepicker td.active:hover:active,
-.datepicker td.active.disabled:active,
-.datepicker td.active.disabled:hover:active,
-.datepicker td.active.active,
-.datepicker td.active:hover.active,
-.datepicker td.active.disabled.active,
-.datepicker td.active.disabled:hover.active,
-.datepicker td.active.disabled,
-.datepicker td.active:hover.disabled,
-.datepicker td.active.disabled.disabled,
-.datepicker td.active.disabled:hover.disabled,
-.datepicker td.active[disabled],
-.datepicker td.active:hover[disabled],
-.datepicker td.active.disabled[disabled],
-.datepicker td.active.disabled:hover[disabled] {
+.datepicker table tr td.active:hover,
+.datepicker table tr td.active:hover:hover,
+.datepicker table tr td.active.disabled:hover,
+.datepicker table tr td.active.disabled:hover:hover,
+.datepicker table tr td.active:active,
+.datepicker table tr td.active:hover:active,
+.datepicker table tr td.active.disabled:active,
+.datepicker table tr td.active.disabled:hover:active,
+.datepicker table tr td.active.active,
+.datepicker table tr td.active:hover.active,
+.datepicker table tr td.active.disabled.active,
+.datepicker table tr td.active.disabled:hover.active,
+.datepicker table tr td.active.disabled,
+.datepicker table tr td.active:hover.disabled,
+.datepicker table tr td.active.disabled.disabled,
+.datepicker table tr td.active.disabled:hover.disabled,
+.datepicker table tr td.active[disabled],
+.datepicker table tr td.active:hover[disabled],
+.datepicker table tr td.active.disabled[disabled],
+.datepicker table tr td.active.disabled:hover[disabled] {
background-color: #0044cc;
}
-.datepicker td.active:active,
-.datepicker td.active:hover:active,
-.datepicker td.active.disabled:active,
-.datepicker td.active.disabled:hover:active,
-.datepicker td.active.active,
-.datepicker td.active:hover.active,
-.datepicker td.active.disabled.active,
-.datepicker td.active.disabled:hover.active {
+.datepicker table tr td.active:active,
+.datepicker table tr td.active:hover:active,
+.datepicker table tr td.active.disabled:active,
+.datepicker table tr td.active.disabled:hover:active,
+.datepicker table tr td.active.active,
+.datepicker table tr td.active:hover.active,
+.datepicker table tr td.active.disabled.active,
+.datepicker table tr td.active.disabled:hover.active {
background-color: #003399 \9;
}
-.datepicker td span {
+.datepicker table tr td span {
display: block;
width: 23%;
height: 54px;
@@ -251,19 +358,19 @@
-moz-border-radius: 4px;
border-radius: 4px;
}
-.datepicker td span:hover {
+.datepicker table tr td span:hover {
background: #eeeeee;
}
-.datepicker td span.disabled,
-.datepicker td span.disabled:hover {
+.datepicker table tr td span.disabled,
+.datepicker table tr td span.disabled:hover {
background: none;
color: #999999;
cursor: default;
}
-.datepicker td span.active,
-.datepicker td span.active:hover,
-.datepicker td span.active.disabled,
-.datepicker td span.active.disabled:hover {
+.datepicker table tr td span.active,
+.datepicker table tr td span.active:hover,
+.datepicker table tr td span.active.disabled,
+.datepicker table tr td span.active.disabled:hover {
background-color: #006dcc;
background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
background-image: -ms-linear-gradient(top, #0088cc, #0044cc);
@@ -275,59 +382,69 @@
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);
border-color: #0044cc #0044cc #002a80;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
- filter: progid:dximagetransform.microsoft.gradient(enabled=false);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
color: #fff;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}
-.datepicker td span.active:hover,
-.datepicker td span.active:hover:hover,
-.datepicker td span.active.disabled:hover,
-.datepicker td span.active.disabled:hover:hover,
-.datepicker td span.active:active,
-.datepicker td span.active:hover:active,
-.datepicker td span.active.disabled:active,
-.datepicker td span.active.disabled:hover:active,
-.datepicker td span.active.active,
-.datepicker td span.active:hover.active,
-.datepicker td span.active.disabled.active,
-.datepicker td span.active.disabled:hover.active,
-.datepicker td span.active.disabled,
-.datepicker td span.active:hover.disabled,
-.datepicker td span.active.disabled.disabled,
-.datepicker td span.active.disabled:hover.disabled,
-.datepicker td span.active[disabled],
-.datepicker td span.active:hover[disabled],
-.datepicker td span.active.disabled[disabled],
-.datepicker td span.active.disabled:hover[disabled] {
+.datepicker table tr td span.active:hover,
+.datepicker table tr td span.active:hover:hover,
+.datepicker table tr td span.active.disabled:hover,
+.datepicker table tr td span.active.disabled:hover:hover,
+.datepicker table tr td span.active:active,
+.datepicker table tr td span.active:hover:active,
+.datepicker table tr td span.active.disabled:active,
+.datepicker table tr td span.active.disabled:hover:active,
+.datepicker table tr td span.active.active,
+.datepicker table tr td span.active:hover.active,
+.datepicker table tr td span.active.disabled.active,
+.datepicker table tr td span.active.disabled:hover.active,
+.datepicker table tr td span.active.disabled,
+.datepicker table tr td span.active:hover.disabled,
+.datepicker table tr td span.active.disabled.disabled,
+.datepicker table tr td span.active.disabled:hover.disabled,
+.datepicker table tr td span.active[disabled],
+.datepicker table tr td span.active:hover[disabled],
+.datepicker table tr td span.active.disabled[disabled],
+.datepicker table tr td span.active.disabled:hover[disabled] {
background-color: #0044cc;
}
-.datepicker td span.active:active,
-.datepicker td span.active:hover:active,
-.datepicker td span.active.disabled:active,
-.datepicker td span.active.disabled:hover:active,
-.datepicker td span.active.active,
-.datepicker td span.active:hover.active,
-.datepicker td span.active.disabled.active,
-.datepicker td span.active.disabled:hover.active {
+.datepicker table tr td span.active:active,
+.datepicker table tr td span.active:hover:active,
+.datepicker table tr td span.active.disabled:active,
+.datepicker table tr td span.active.disabled:hover:active,
+.datepicker table tr td span.active.active,
+.datepicker table tr td span.active:hover.active,
+.datepicker table tr td span.active.disabled.active,
+.datepicker table tr td span.active.disabled:hover.active {
background-color: #003399 \9;
}
-.datepicker td span.old {
+.datepicker table tr td span.old,
+.datepicker table tr td span.new {
color: #999999;
}
-.datepicker th.switch {
+.datepicker th.datepicker-switch {
width: 145px;
}
.datepicker thead tr:first-child th,
-.datepicker tfoot tr:first-child th {
+.datepicker tfoot tr th {
cursor: pointer;
}
.datepicker thead tr:first-child th:hover,
-.datepicker tfoot tr:first-child th:hover {
+.datepicker tfoot tr th:hover {
background: #eeeeee;
}
+.datepicker .cw {
+ font-size: 10px;
+ width: 12px;
+ padding: 0 2px 0 5px;
+ vertical-align: middle;
+}
+.datepicker thead tr:first-child th.cw {
+ cursor: default;
+ background-color: transparent;
+}
.input-append.date .add-on i,
.input-prepend.date .add-on i {
- display: block;
cursor: pointer;
width: 16px;
height: 16px;
@@ -349,10 +466,10 @@
display: inline-block;
width: auto;
min-width: 16px;
- height: 18px;
+ height: 20px;
padding: 4px 5px;
font-weight: normal;
- line-height: 18px;
+ line-height: 20px;
text-align: center;
text-shadow: 0 1px 0 #ffffff;
vertical-align: middle;
@@ -387,19 +504,11 @@
color: #333333;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 13px;
- line-height: 18px;
+ line-height: 20px;
}
.datepicker.dropdown-menu th,
-.datepicker.dropdown-menu td {
+.datepicker.datepicker-inline th,
+.datepicker.dropdown-menu td,
+.datepicker.datepicker-inline td {
padding: 4px 5px;
}
-.datepicker .prev,
-.datepicker .next {
- font-style: normal;
-}
-.datepicker .prev:after {
- content: "«";
-}
-.datepicker .next:after {
- content: "»";
-}
diff --git a/UI/WebServerResources/datepicker.js b/UI/WebServerResources/datepicker.js
index 91aa6c029..5d6277feb 100644
--- a/UI/WebServerResources/datepicker.js
+++ b/UI/WebServerResources/datepicker.js
@@ -1,10 +1,11 @@
/* =========================================================
* bootstrap-datepicker.js
- * http://www.eyecon.ro/bootstrap-datepicker
+ * Repo: https://github.com/eternicode/bootstrap-datepicker/
+ * Demo: http://eternicode.github.io/bootstrap-datepicker/
+ * Docs: http://bootstrap-datepicker.readthedocs.org/
+ * Forked from http://www.eyecon.ro/bootstrap-datepicker
* =========================================================
- * Copyright 2012 Stefan Petre
- * Improvements by Andrew Rowls
- * Adapted for SOGo translation by Francis Lachapelle
+ * Started by Stefan Petre; improvements by Andrew Rowls + contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,286 +20,815 @@
* limitations under the License.
* ========================================================= */
-!function( $ ) {
+(function($, undefined){
+
+ var $window = $(window);
function UTCDate(){
return new Date(Date.UTC.apply(Date, arguments));
}
+ function UTCToday(){
+ var today = new Date();
+ return UTCDate(today.getFullYear(), today.getMonth(), today.getDate());
+ }
+ function alias(method){
+ return function(){
+ return this[method].apply(this, arguments);
+ };
+ }
+
+ var DateArray = (function(){
+ var extras = {
+ get: function(i){
+ return this.slice(i)[0];
+ },
+ contains: function(d){
+ // Array.indexOf is not cross-browser;
+ // $.inArray doesn't work with Dates
+ var val = d && d.valueOf();
+ for (var i=0, l=this.length; i < l; i++)
+ if (this[i].valueOf() === val)
+ return i;
+ return -1;
+ },
+ remove: function(i){
+ this.splice(i,1);
+ },
+ replace: function(new_array){
+ if (!new_array)
+ return;
+ if (!$.isArray(new_array))
+ new_array = [new_array];
+ this.clear();
+ this.push.apply(this, new_array);
+ },
+ clear: function(){
+ this.length = 0;
+ },
+ copy: function(){
+ var a = new DateArray();
+ a.replace(this);
+ return a;
+ }
+ };
+
+ return function(){
+ var a = [];
+ a.push.apply(a, arguments);
+ $.extend(a, extras);
+ return a;
+ };
+ })();
+
// Picker object
- var Datepicker = function(element, options) {
- var that = this;
+ var Datepicker = function(element, options){
+ this.dates = new DateArray();
+ this.viewDate = UTCToday();
+ this.focusDate = null;
+
+ this._process_options(options);
this.element = $(element);
- this.position = options.position||this.element.data('position');
- this.format = DPGlobal.parseFormat(options.format||this.element.data('date-format')||'mm/dd/yyyy');
- this.picker = $(DPGlobal.template).addClass(this.position)
- .appendTo('body')
- .on({click: $.proxy(this.click, this)});
+ this.isInline = false;
this.isInput = this.element.is('input');
- this.component = this.element.is('.date') ? this.element.find('.add-on') : false;
+ this.component = this.element.is('.date') ? this.element.find('.add-on, .input-group-addon, .btn') : false;
this.hasInput = this.component && this.element.find('input').length;
- if(this.component && this.component.length === 0)
+ if (this.component && this.component.length === 0)
this.component = false;
- if (this.isInput) {
- this.element.on({
- focus: $.proxy(this.show, this),
- keyup: $.proxy(this.update, this),
- keydown: $.proxy(this.keydown, this)
- });
+ this.picker = $(DPGlobal.template);
+ this._buildEvents();
+ this._attachEvents();
+
+ if (this.isInline){
+ this.picker.addClass('datepicker-inline').appendTo(this.element);
}
- else {
- if (this.component && this.hasInput){
- // For components that are not readonly, allow keyboard nav
- this.element.find('input').on({
- focus: $.proxy(this.show, this),
- keyup: $.proxy(this.update, this),
- keydown: $.proxy(this.keydown, this)
- });
- this.component.on('click', $.proxy(this.show, this));
- }
- else {
- this.element.on('click', $.proxy(this.show, this));
- }
+ else {
+ this.picker.addClass('datepicker-dropdown dropdown-menu');
}
- $(document).on('mousedown', function (e) {
- // Clicked outside the datepicker, hide it
- if ($(e.target).closest('.datepicker').length == 0) {
- that.hide();
- }
- });
-
- this.autoclose = false;
- if ('autoclose' in options) {
- this.autoclose = options.autoclose;
- }
- else if ('dateAutoclose' in this.element.data()) {
- this.autoclose = this.element.data('date-autoclose');
+ if (this.o.rtl){
+ this.picker.addClass('datepicker-rtl');
}
- this.keyboardNavigation = true;
- if ('keyboardNavigation' in options) {
- this.keyboardNavigation = options.keyboardNavigation;
- }
- else if ('dateKeyboardNavigation' in this.element.data()) {
- this.keyboardNavigation = this.element.data('date-keyboard-navigation');
- }
+ this.viewMode = this.o.startView;
- switch(options.startView || this.element.data('date-start-view')){
- case 2:
- case 'decade':
- this.viewMode = this.startViewMode = 2;
- break;
- case 1:
- case 'year':
- this.viewMode = this.startViewMode = 1;
- break;
- case 0:
- case 'month':
- default:
- this.viewMode = this.startViewMode = 0;
- break;
- }
+ if (this.o.calendarWeeks)
+ this.picker.find('tfoot th.today')
+ .attr('colspan', function(i, val){
+ return parseInt(val) + 1;
+ });
+
+ this._allow_update = false;
+
+ this.setStartDate(this._o.startDate);
+ this.setEndDate(this._o.endDate);
+ this.setDaysOfWeekDisabled(this.o.daysOfWeekDisabled);
- this.weekStart = ((options.weekStart||this.element.data('date-weekstart')||0) % 7);
- this.weekEnd = ((this.weekStart + 6) % 7);
- this.startDate = -Infinity;
- this.endDate = Infinity;
- this.setStartDate(options.startDate||this.element.data('date-startdate'));
- this.setEndDate(options.endDate||this.element.data('date-enddate'));
this.fillDow();
this.fillMonths();
+
+ this._allow_update = true;
+
this.update();
this.showMode();
+
+ if (this.isInline){
+ this.show();
+ }
};
Datepicker.prototype = {
constructor: Datepicker,
- show: function(e) {
- this.picker.show();
- this.height = this.component ? this.component.outerHeight() : this.element.outerHeight();
- this.update();
- this.place();
- $(window).on('resize', $.proxy(this.place, this));
- if (e ) {
- e.stopPropagation();
- e.preventDefault();
+ _process_options: function(opts){
+ // Store raw options for reference
+ this._o = $.extend({}, this._o, opts);
+ // Processed options
+ var o = this.o = $.extend({}, this._o);
+
+ // Check if "de-DE" style date is available, if not language should
+ // fallback to 2 letter code eg "de"
+ var lang = o.language;
+ if (!dates[lang]){
+ lang = lang.split('-')[0];
+ if (!dates[lang])
+ lang = defaults.language;
}
+ o.language = lang;
+
+ switch (o.startView){
+ case 2:
+ case 'decade':
+ o.startView = 2;
+ break;
+ case 1:
+ case 'year':
+ o.startView = 1;
+ break;
+ default:
+ o.startView = 0;
+ }
+
+ switch (o.minViewMode){
+ case 1:
+ case 'months':
+ o.minViewMode = 1;
+ break;
+ case 2:
+ case 'years':
+ o.minViewMode = 2;
+ break;
+ default:
+ o.minViewMode = 0;
+ }
+
+ o.startView = Math.max(o.startView, o.minViewMode);
+
+ // true, false, or Number > 0
+ if (o.multidate !== true){
+ o.multidate = Number(o.multidate) || false;
+ if (o.multidate !== false)
+ o.multidate = Math.max(0, o.multidate);
+ else
+ o.multidate = 1;
+ }
+ o.multidateSeparator = String(o.multidateSeparator);
+
+ o.weekStart %= 7;
+ o.weekEnd = ((o.weekStart + 6) % 7);
+
+ var format = DPGlobal.parseFormat(o.format);
+ if (o.startDate !== -Infinity){
+ if (!!o.startDate){
+ if (o.startDate instanceof Date)
+ o.startDate = this._local_to_utc(this._zero_time(o.startDate));
+ else
+ o.startDate = DPGlobal.parseDate(o.startDate, format, o.language);
+ }
+ else {
+ o.startDate = -Infinity;
+ }
+ }
+ if (o.endDate !== Infinity){
+ if (!!o.endDate){
+ if (o.endDate instanceof Date)
+ o.endDate = this._local_to_utc(this._zero_time(o.endDate));
+ else
+ o.endDate = DPGlobal.parseDate(o.endDate, format, o.language);
+ }
+ else {
+ o.endDate = Infinity;
+ }
+ }
+
+ o.daysOfWeekDisabled = o.daysOfWeekDisabled||[];
+ if (!$.isArray(o.daysOfWeekDisabled))
+ o.daysOfWeekDisabled = o.daysOfWeekDisabled.split(/[,\s]*/);
+ o.daysOfWeekDisabled = $.map(o.daysOfWeekDisabled, function(d){
+ return parseInt(d, 10);
+ });
+
+ var plc = String(o.orientation).toLowerCase().split(/\s+/g),
+ _plc = o.orientation.toLowerCase();
+ plc = $.grep(plc, function(word){
+ return (/^auto|left|right|top|bottom$/).test(word);
+ });
+ o.orientation = {x: 'auto', y: 'auto'};
+ if (!_plc || _plc === 'auto')
+ ; // no action
+ else if (plc.length === 1){
+ switch (plc[0]){
+ case 'top':
+ case 'bottom':
+ o.orientation.y = plc[0];
+ break;
+ case 'left':
+ case 'right':
+ o.orientation.x = plc[0];
+ break;
+ }
+ }
+ else {
+ _plc = $.grep(plc, function(word){
+ return (/^left|right$/).test(word);
+ });
+ o.orientation.x = _plc[0] || 'auto';
+
+ _plc = $.grep(plc, function(word){
+ return (/^top|bottom$/).test(word);
+ });
+ o.orientation.y = _plc[0] || 'auto';
+ }
+ },
+ _events: [],
+ _secondaryEvents: [],
+ _applyEvents: function(evs){
+ for (var i=0, el, ch, ev; i < evs.length; i++){
+ el = evs[i][0];
+ if (evs[i].length === 2){
+ ch = undefined;
+ ev = evs[i][1];
+ }
+ else if (evs[i].length === 3){
+ ch = evs[i][1];
+ ev = evs[i][2];
+ }
+ el.on(ev, ch);
+ }
+ },
+ _unapplyEvents: function(evs){
+ for (var i=0, el, ev, ch; i < evs.length; i++){
+ el = evs[i][0];
+ if (evs[i].length === 2){
+ ch = undefined;
+ ev = evs[i][1];
+ }
+ else if (evs[i].length === 3){
+ ch = evs[i][1];
+ ev = evs[i][2];
+ }
+ el.off(ev, ch);
+ }
+ },
+ _buildEvents: function(){
+ if (this.isInput){ // single input
+ this._events = [
+ [this.element, {
+ focus: $.proxy(this.show, this),
+ keyup: $.proxy(function(e){
+ if ($.inArray(e.keyCode, [27,37,39,38,40,32,13,9]) === -1)
+ this.update();
+ }, this),
+ keydown: $.proxy(this.keydown, this)
+ }]
+ ];
+ }
+ else if (this.component && this.hasInput){ // component: input + button
+ this._events = [
+ // For components that are not readonly, allow keyboard nav
+ [this.element.find('input'), {
+ focus: $.proxy(this.show, this),
+ keyup: $.proxy(function(e){
+ if ($.inArray(e.keyCode, [27,37,39,38,40,32,13,9]) === -1)
+ this.update();
+ }, this),
+ keydown: $.proxy(this.keydown, this)
+ }],
+ [this.component, {
+ click: $.proxy(this.show, this)
+ }]
+ ];
+ }
+ else if (this.element.is('div')){ // inline datepicker
+ this.isInline = true;
+ }
+ else {
+ this._events = [
+ [this.element, {
+ click: $.proxy(this.show, this)
+ }]
+ ];
+ }
+ this._events.push(
+ // Component: listen for blur on element descendants
+ [this.element, '*', {
+ blur: $.proxy(function(e){
+ this._focused_from = e.target;
+ }, this)
+ }],
+ // Input: listen for blur on element
+ [this.element, {
+ blur: $.proxy(function(e){
+ this._focused_from = e.target;
+ }, this)
+ }]
+ );
+
+ this._secondaryEvents = [
+ [this.picker, {
+ click: $.proxy(this.click, this)
+ }],
+ [$(window), {
+ resize: $.proxy(this.place, this)
+ }],
+ [$(document), {
+ 'mousedown touchstart': $.proxy(function(e){
+ // Clicked outside the datepicker, hide it
+ if (!(
+ this.element.is(e.target) ||
+ this.element.find(e.target).length ||
+ this.picker.is(e.target) ||
+ this.picker.find(e.target).length
+ )){
+ this.hide();
+ }
+ }, this)
+ }]
+ ];
+ },
+ _attachEvents: function(){
+ this._detachEvents();
+ this._applyEvents(this._events);
+ },
+ _detachEvents: function(){
+ this._unapplyEvents(this._events);
+ },
+ _attachSecondaryEvents: function(){
+ this._detachSecondaryEvents();
+ this._applyEvents(this._secondaryEvents);
+ },
+ _detachSecondaryEvents: function(){
+ this._unapplyEvents(this._secondaryEvents);
+ },
+ _trigger: function(event, altdate){
+ var date = altdate || this.dates.get(-1),
+ local_date = this._utc_to_local(date);
+
this.element.trigger({
- type: 'show',
- date: this.date
+ type: event,
+ date: local_date,
+ dates: $.map(this.dates, this._utc_to_local),
+ format: $.proxy(function(ix, format){
+ if (arguments.length === 0){
+ ix = this.dates.length - 1;
+ format = this.o.format;
+ }
+ else if (typeof ix === 'string'){
+ format = ix;
+ ix = this.dates.length - 1;
+ }
+ format = format || this.o.format;
+ var date = this.dates.get(ix);
+ return DPGlobal.formatDate(date, format, this.o.language);
+ }, this)
});
},
- hide: function(e){
- this.picker.hide();
- $(window).off('resize', this.place);
- this.viewMode = this.startViewMode;
- this.showMode();
- if (!this.isInput) {
- $(document).off('mousedown', this.hide);
- }
- if (e && e.currentTarget.value)
- this.setValue();
+ show: function(){
+ if (!this.isInline)
+ this.picker.appendTo('body');
+ this.picker.show();
+ this.place();
+ this._attachSecondaryEvents();
+ this._trigger('show');
},
- setValue: function() {
- var formatted = DPGlobal.formatDate(this.date, this.format);
- if (!this.isInput) {
- if (this.component){
- this.element.find('input').prop('value', formatted);
- }
- this.element.data('date', formatted);
- } else {
- this.element.prop('value', formatted);
+ hide: function(){
+ if (this.isInline)
+ return;
+ if (!this.picker.is(':visible'))
+ return;
+ this.focusDate = null;
+ this.picker.hide().detach();
+ this._detachSecondaryEvents();
+ this.viewMode = this.o.startView;
+ this.showMode();
+
+ if (
+ this.o.forceParse &&
+ (
+ this.isInput && this.element.val() ||
+ this.hasInput && this.element.find('input').val()
+ )
+ )
+ this.setValue();
+ //this._trigger('hide');
+ },
+
+ remove: function(){
+ this.hide();
+ this._detachEvents();
+ this._detachSecondaryEvents();
+ this.picker.remove();
+ delete this.element.data().datepicker;
+ if (!this.isInput){
+ delete this.element.data().date;
}
},
+ _utc_to_local: function(utc){
+ return utc && new Date(utc.getTime() + (utc.getTimezoneOffset()*60000));
+ },
+ _local_to_utc: function(local){
+ return local && new Date(local.getTime() - (local.getTimezoneOffset()*60000));
+ },
+ _zero_time: function(local){
+ return local && new Date(local.getFullYear(), local.getMonth(), local.getDate());
+ },
+ _zero_utc_time: function(utc){
+ return utc && new Date(Date.UTC(utc.getUTCFullYear(), utc.getUTCMonth(), utc.getUTCDate()));
+ },
+
+ getDates: function(){
+ return $.map(this.dates, this._utc_to_local);
+ },
+
+ getUTCDates: function(){
+ return $.map(this.dates, function(d){
+ return new Date(d);
+ });
+ },
+
+ getDate: function(){
+ return this._utc_to_local(this.getUTCDate());
+ },
+
+ getUTCDate: function(){
+ return new Date(this.dates.get(-1));
+ },
+
+ setDates: function(){
+ var args = $.isArray(arguments[0]) ? arguments[0] : arguments;
+ this.update.apply(this, args);
+ this._trigger('changeDate');
+ this.setValue();
+ },
+
+ setUTCDates: function(){
+ var args = $.isArray(arguments[0]) ? arguments[0] : arguments;
+ this.update.apply(this, $.map(args, this._utc_to_local));
+ this._trigger('changeDate');
+ this.setValue();
+ },
+
+ setDate: alias('setDates'),
+ setUTCDate: alias('setUTCDates'),
+
+ setValue: function(){
+ var formatted = this.getFormattedDate();
+ if (!this.isInput){
+ if (this.component){
+ this.element.find('input').val(formatted).change();
+ }
+ }
+ else {
+ this.element.val(formatted).change();
+ }
+ },
+
+ getFormattedDate: function(format){
+ if (format === undefined)
+ format = this.o.format;
+
+ var lang = this.o.language;
+ return $.map(this.dates, function(d){
+ return DPGlobal.formatDate(d, format, lang);
+ }).join(this.o.multidateSeparator);
+ },
+
setStartDate: function(startDate){
- this.startDate = startDate||-Infinity;
- if (this.startDate !== -Infinity) {
- this.startDate = DPGlobal.parseDate(this.startDate, this.format);
- }
+ this._process_options({startDate: startDate});
this.update();
this.updateNavArrows();
},
setEndDate: function(endDate){
- this.endDate = endDate||Infinity;
- if (this.endDate !== Infinity) {
- this.endDate = DPGlobal.parseDate(this.endDate, this.format);
- }
+ this._process_options({endDate: endDate});
+ this.update();
+ this.updateNavArrows();
+ },
+
+ setDaysOfWeekDisabled: function(daysOfWeekDisabled){
+ this._process_options({daysOfWeekDisabled: daysOfWeekDisabled});
this.update();
this.updateNavArrows();
},
place: function(){
- var zIndex = parseInt(this.element.parents().filter(function() {
- return $(this).css('z-index') != 'auto';
- }).first().css('z-index'))+10;
- var offset = this.component ? this.component.offset() : this.element.offset();
- var width = this.component ? this.component.width() : this.element.width();
- if (this.position == 'bellow')
- this.picker.css({top: offset.top + this.height,
- left: offset.left,
- right: 'auto',
- zIndex: zIndex
- });
-
- if (this.position == 'below-shifted-left')
- this.picker.css({top: offset.top + this.height,
- left: offset.left - 83,
- right: 'auto',
- zIndex: zIndex
- });
- else // above
- this.picker.css({ top: offset.top - this.height - this.picker.outerHeight(),
- right: window.width() - offset.left - width,
- left: 'auto',
- zIndex: zIndex
- });
+ if (this.isInline)
+ return;
+ var calendarWidth = this.picker.outerWidth(),
+ calendarHeight = this.picker.outerHeight(),
+ visualPadding = 10,
+ windowWidth = $window.width(),
+ windowHeight = $window.height(),
+ scrollTop = $window.scrollTop();
+
+ var zIndex = parseInt(this.element.parents().filter(function(){
+ return $(this).css('z-index') !== 'auto';
+ }).first().css('z-index'))+10;
+ var offset = this.component ? this.component.parent().offset() : this.element.offset();
+ var height = this.component ? this.component.outerHeight(true) : this.element.outerHeight(false);
+ var width = this.component ? this.component.outerWidth(true) : this.element.outerWidth(false);
+ var left = offset.left,
+ top = offset.top;
+
+ this.picker.removeClass(
+ 'datepicker-orient-top datepicker-orient-bottom '+
+ 'datepicker-orient-right datepicker-orient-left'
+ );
+
+ if (this.o.orientation.x !== 'auto'){
+ this.picker.addClass('datepicker-orient-' + this.o.orientation.x);
+ if (this.o.orientation.x === 'right')
+ left -= calendarWidth - width;
+ }
+ // auto x orientation is best-placement: if it crosses a window
+ // edge, fudge it sideways
+ else {
+ // Default to left
+ this.picker.addClass('datepicker-orient-left');
+ if (offset.left < 0)
+ left -= offset.left - visualPadding;
+ else if (offset.left + calendarWidth > windowWidth)
+ left = windowWidth - calendarWidth - visualPadding;
+ }
+
+ // auto y orientation is best-situation: top or bottom, no fudging,
+ // decision based on which shows more of the calendar
+ var yorient = this.o.orientation.y,
+ top_overflow, bottom_overflow;
+ if (yorient === 'auto'){
+ top_overflow = -scrollTop + offset.top - calendarHeight;
+ bottom_overflow = scrollTop + windowHeight - (offset.top + height + calendarHeight);
+ if (Math.max(top_overflow, bottom_overflow) === bottom_overflow)
+ yorient = 'top';
+ else
+ yorient = 'bottom';
+ }
+ this.picker.addClass('datepicker-orient-' + yorient);
+ if (yorient === 'top')
+ top += height;
+ else
+ top -= calendarHeight + parseInt(this.picker.css('padding-top'));
+
+ this.picker.css({
+ top: top,
+ left: left,
+ zIndex: zIndex
+ });
},
+ _allow_update: true,
update: function(){
- this.date = DPGlobal.parseDate(
- this.isInput ? this.element.prop('value') : this.element.data('date') || this.element.find('input').prop('value'),
- this.format
- );
- if (this.date < this.startDate) {
- this.viewDate = new Date(this.startDate);
- } else if (this.date > this.endDate) {
- this.viewDate = new Date(this.endDate);
- } else {
- this.viewDate = new Date(this.date);
+ if (!this._allow_update)
+ return;
+
+ var oldDates = this.dates.copy(),
+ dates = [],
+ fromArgs = false;
+ if (arguments.length){
+ $.each(arguments, $.proxy(function(i, date){
+ if (date instanceof Date)
+ date = this._local_to_utc(date);
+ dates.push(date);
+ }, this));
+ fromArgs = true;
}
+ else {
+ dates = this.isInput
+ ? this.element.val()
+ : this.element.data('date') || this.element.find('input').val();
+ if (dates && this.o.multidate)
+ dates = dates.split(this.o.multidateSeparator);
+ else
+ dates = [dates];
+ delete this.element.data().date;
+ }
+
+ dates = $.map(dates, $.proxy(function(date){
+ return DPGlobal.parseDate(date, this.o.format, this.o.language);
+ }, this));
+ dates = $.grep(dates, $.proxy(function(date){
+ return (
+ date < this.o.startDate ||
+ date > this.o.endDate ||
+ !date
+ );
+ }, this), true);
+ this.dates.replace(dates);
+
+ if (this.dates.length)
+ this.viewDate = new Date(this.dates.get(-1));
+ else if (this.viewDate < this.o.startDate)
+ this.viewDate = new Date(this.o.startDate);
+ else if (this.viewDate > this.o.endDate)
+ this.viewDate = new Date(this.o.endDate);
+
+ if (fromArgs){
+ // setting date by clicking
+ this.setValue();
+ }
+ else if (dates.length){
+ // setting date by typing
+ if (String(oldDates) !== String(this.dates))
+ this._trigger('changeDate');
+ }
+ if (!this.dates.length && oldDates.length)
+ this._trigger('clearDate');
+
this.fill();
},
fillDow: function(){
- var dowCnt = this.weekStart;
- var html = '';
- while (dowCnt < this.weekStart + 7) {
- html += '| '+_('a2_'+dates.days[(dowCnt++)%7])+' | ';
+ var dowCnt = this.o.weekStart,
+ html = '
';
+ if (this.o.calendarWeeks){
+ var cell = '| | ';
+ html += cell;
+ this.picker.find('.datepicker-days thead tr:first-child').prepend(cell);
+ }
+ while (dowCnt < this.o.weekStart + 7){
+ html += ''+_(dates[this.o.language].daysMin[(dowCnt++)%7])+' | ';
}
html += '
';
this.picker.find('.datepicker-days thead').append(html);
},
fillMonths: function(){
- var html = '';
- var i = 0
- while (i < 12) {
- html += ''+_(dates.monthsShort[i++])+'';
+ var html = '',
+ i = 0;
+ while (i < 12){
+ html += ''+_(dates[this.o.language].monthsShort[i++])+'';
}
this.picker.find('.datepicker-months td').html(html);
},
- fill: function() {
+ setRange: function(range){
+ if (!range || !range.length)
+ delete this.range;
+ else
+ this.range = $.map(range, function(d){
+ return d.valueOf();
+ });
+ this.fill();
+ },
+
+ getClassNames: function(date){
+ var cls = [],
+ year = this.viewDate.getUTCFullYear(),
+ month = this.viewDate.getUTCMonth(),
+ today = new Date();
+ if (date.getUTCFullYear() < year || (date.getUTCFullYear() === year && date.getUTCMonth() < month)){
+ cls.push('old');
+ }
+ else if (date.getUTCFullYear() > year || (date.getUTCFullYear() === year && date.getUTCMonth() > month)){
+ cls.push('new');
+ }
+ if (this.focusDate && date.valueOf() === this.focusDate.valueOf())
+ cls.push('focused');
+ // Compare internal UTC date with local today, not UTC today
+ if (this.o.todayHighlight &&
+ date.getUTCFullYear() === today.getFullYear() &&
+ date.getUTCMonth() === today.getMonth() &&
+ date.getUTCDate() === today.getDate()){
+ cls.push('today');
+ }
+ if (this.dates.contains(date) !== -1)
+ cls.push('active');
+ if (date.valueOf() < this.o.startDate || date.valueOf() > this.o.endDate ||
+ $.inArray(date.getUTCDay(), this.o.daysOfWeekDisabled) !== -1){
+ cls.push('disabled');
+ }
+ if (this.range){
+ if (date > this.range[0] && date < this.range[this.range.length-1]){
+ cls.push('range');
+ }
+ if ($.inArray(date.valueOf(), this.range) !== -1){
+ cls.push('selected');
+ }
+ }
+ return cls;
+ },
+
+ fill: function(){
var d = new Date(this.viewDate),
year = d.getUTCFullYear(),
month = d.getUTCMonth(),
- startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
- startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
- endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
- endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
- currentDate = this.date.valueOf();
- this.picker.find('.datepicker-days th:eq(1)')
- .text(_(dates.months[month])+' '+year);
+ startYear = this.o.startDate !== -Infinity ? this.o.startDate.getUTCFullYear() : -Infinity,
+ startMonth = this.o.startDate !== -Infinity ? this.o.startDate.getUTCMonth() : -Infinity,
+ endYear = this.o.endDate !== Infinity ? this.o.endDate.getUTCFullYear() : Infinity,
+ endMonth = this.o.endDate !== Infinity ? this.o.endDate.getUTCMonth() : Infinity,
+ todaytxt = _(dates[this.o.language].today) || dates['en'].today || '',
+ cleartxt = _(dates[this.o.language].clear) || dates['en'].clear || '',
+ tooltip;
+ this.picker.find('.datepicker-days thead th.datepicker-switch')
+ .text(_(dates[this.o.language].months[month])+' '+year);
+ this.picker.find('tfoot th.today')
+ .text(todaytxt)
+ .toggle(this.o.todayBtn !== false);
+ this.picker.find('tfoot th.clear')
+ .text(cleartxt)
+ .toggle(this.o.clearBtn !== false);
this.updateNavArrows();
this.fillMonths();
- var prevMonth = UTCDate(year, month-1, 28,0,0,0,0),
+ var prevMonth = UTCDate(year, month-1, 28),
day = DPGlobal.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
prevMonth.setUTCDate(day);
- prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
+ prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.o.weekStart + 7)%7);
var nextMonth = new Date(prevMonth);
nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
nextMonth = nextMonth.valueOf();
var html = [];
var clsName;
- while(prevMonth.valueOf() < nextMonth) {
- if (prevMonth.getUTCDay() == this.weekStart) {
+ while (prevMonth.valueOf() < nextMonth){
+ if (prevMonth.getUTCDay() === this.o.weekStart){
html.push('');
+ if (this.o.calendarWeeks){
+ // ISO 8601: First week contains first thursday.
+ // ISO also states week starts on Monday, but we can be more abstract here.
+ var
+ // Start of current week: based on weekstart/current date
+ ws = new Date(+prevMonth + (this.o.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
+ // Thursday of this week
+ th = new Date(Number(ws) + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
+ // First Thursday of year, year from thursday
+ yth = new Date(Number(yth = UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
+ // Calendar week: ms between thursdays, div ms per day, div 7 days
+ calWeek = (th - yth) / 864e5 / 7 + 1;
+ html.push('| '+ calWeek +' | ');
+
+ }
}
- clsName = '';
- if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
- clsName += ' old';
- } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
- clsName += ' new';
+ clsName = this.getClassNames(prevMonth);
+ clsName.push('day');
+
+ if (this.o.beforeShowDay !== $.noop){
+ var before = this.o.beforeShowDay(this._utc_to_local(prevMonth));
+ if (before === undefined)
+ before = {};
+ else if (typeof(before) === 'boolean')
+ before = {enabled: before};
+ else if (typeof(before) === 'string')
+ before = {classes: before};
+ if (before.enabled === false)
+ clsName.push('disabled');
+ if (before.classes)
+ clsName = clsName.concat(before.classes.split(/\s+/));
+ if (before.tooltip)
+ tooltip = before.tooltip;
}
- if (prevMonth.valueOf() == currentDate) {
- clsName += ' active';
- }
- if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate) {
- clsName += ' disabled';
- }
- html.push(''+prevMonth.getUTCDate() + ' | ');
- if (prevMonth.getUTCDay() == this.weekEnd) {
+
+ clsName = $.unique(clsName);
+ html.push(''+prevMonth.getUTCDate() + ' | ');
+ if (prevMonth.getUTCDay() === this.o.weekEnd){
html.push('
');
}
prevMonth.setUTCDate(prevMonth.getUTCDate()+1);
}
this.picker.find('.datepicker-days tbody').empty().append(html.join(''));
- var currentYear = this.date.getUTCFullYear();
var months = this.picker.find('.datepicker-months')
.find('th:eq(1)')
.text(year)
.end()
.find('span').removeClass('active');
- if (currentYear == year) {
- months.eq(this.date.getUTCMonth()).addClass('active');
- }
- if (year < startYear || year > endYear) {
+
+ $.each(this.dates, function(i, d){
+ if (d.getUTCFullYear() === year)
+ months.eq(d.getUTCMonth()).addClass('active');
+ });
+
+ if (year < startYear || year > endYear){
months.addClass('disabled');
}
- if (year == startYear) {
+ if (year === startYear){
months.slice(0, startMonth).addClass('disabled');
}
- if (year == endYear) {
+ if (year === endYear){
months.slice(endMonth+1).addClass('disabled');
}
@@ -310,90 +840,139 @@
.end()
.find('td');
year -= 1;
- for (var i = -1; i < 11; i++) {
- html += ''+year+'';
+ var years = $.map(this.dates, function(d){
+ return d.getUTCFullYear();
+ }),
+ classes;
+ for (var i = -1; i < 11; i++){
+ classes = ['year'];
+ if (i === -1)
+ classes.push('old');
+ else if (i === 10)
+ classes.push('new');
+ if ($.inArray(year, years) !== -1)
+ classes.push('active');
+ if (year < startYear || year > endYear)
+ classes.push('disabled');
+ html += ''+year+'';
year += 1;
}
yearCont.html(html);
},
- updateNavArrows: function() {
+ updateNavArrows: function(){
+ if (!this._allow_update)
+ return;
+
var d = new Date(this.viewDate),
year = d.getUTCFullYear(),
month = d.getUTCMonth();
- switch (this.viewMode) {
+ switch (this.viewMode){
case 0:
- if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
+ if (this.o.startDate !== -Infinity && year <= this.o.startDate.getUTCFullYear() && month <= this.o.startDate.getUTCMonth()){
this.picker.find('.prev').css({visibility: 'hidden'});
- } else {
+ }
+ else {
this.picker.find('.prev').css({visibility: 'visible'});
}
- if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
+ if (this.o.endDate !== Infinity && year >= this.o.endDate.getUTCFullYear() && month >= this.o.endDate.getUTCMonth()){
this.picker.find('.next').css({visibility: 'hidden'});
- } else {
+ }
+ else {
this.picker.find('.next').css({visibility: 'visible'});
}
break;
case 1:
case 2:
- if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
+ if (this.o.startDate !== -Infinity && year <= this.o.startDate.getUTCFullYear()){
this.picker.find('.prev').css({visibility: 'hidden'});
- } else {
+ }
+ else {
this.picker.find('.prev').css({visibility: 'visible'});
}
- if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
+ if (this.o.endDate !== Infinity && year >= this.o.endDate.getUTCFullYear()){
this.picker.find('.next').css({visibility: 'hidden'});
- } else {
+ }
+ else {
this.picker.find('.next').css({visibility: 'visible'});
}
break;
}
},
- click: function(e) {
- e.stopPropagation();
+ click: function(e){
e.preventDefault();
- var target = $(e.target).closest('span, td, th');
- if (target.length == 1) {
- switch(target[0].nodeName.toLowerCase()) {
+ var target = $(e.target).closest('span, td, th'),
+ year, month, day;
+ if (target.length === 1){
+ switch (target[0].nodeName.toLowerCase()){
case 'th':
- switch(target[0].className) {
- case 'switch':
+ switch (target[0].className){
+ case 'datepicker-switch':
this.showMode(1);
break;
case 'prev':
case 'next':
- var dir = DPGlobal.modes[this.viewMode].navStep * (target[0].className == 'prev' ? -1 : 1);
- switch(this.viewMode){
+ var dir = DPGlobal.modes[this.viewMode].navStep * (target[0].className === 'prev' ? -1 : 1);
+ switch (this.viewMode){
case 0:
this.viewDate = this.moveMonth(this.viewDate, dir);
+ this._trigger('changeMonth', this.viewDate);
break;
case 1:
case 2:
this.viewDate = this.moveYear(this.viewDate, dir);
+ if (this.viewMode === 1)
+ this._trigger('changeYear', this.viewDate);
break;
}
this.fill();
break;
+ case 'today':
+ var date = new Date();
+ date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
+
+ this.showMode(-2);
+ var which = this.o.todayBtn === 'linked' ? null : 'view';
+ this._setDate(date, which);
+ break;
+ case 'clear':
+ var element;
+ if (this.isInput)
+ element = this.element;
+ else if (this.component)
+ element = this.element.find('input');
+ if (element)
+ element.val("").change();
+ this.update();
+ this._trigger('changeDate');
+ if (this.o.autoclose)
+ this.hide();
+ break;
}
break;
case 'span':
- if (!target.is('.disabled')) {
+ if (!target.is('.disabled')){
this.viewDate.setUTCDate(1);
- if (target.is('.month')) {
- var month = target.parent().find('span').index(target);
+ if (target.is('.month')){
+ day = 1;
+ month = target.parent().find('span').index(target);
+ year = this.viewDate.getUTCFullYear();
this.viewDate.setUTCMonth(month);
- this.element.trigger({
- type: 'changeMonth',
- date: this.viewDate
- });
- } else {
- var year = parseInt(target.text(), 10)||0;
+ this._trigger('changeMonth', this.viewDate);
+ if (this.o.minViewMode === 1){
+ this._setDate(UTCDate(year, month, day));
+ }
+ }
+ else {
+ day = 1;
+ month = 0;
+ year = parseInt(target.text(), 10)||0;
this.viewDate.setUTCFullYear(year);
- this.element.trigger({
- type: 'changeYear',
- date: this.viewDate
- });
+ this._trigger('changeYear', this.viewDate);
+ if (this.o.minViewMode === 2){
+ this._setDate(UTCDate(year, month, day));
+ }
}
this.showMode(-1);
this.fill();
@@ -401,80 +980,118 @@
break;
case 'td':
if (target.is('.day') && !target.is('.disabled')){
- var day = parseInt(target.text(), 10)||1;
- var year = this.viewDate.getUTCFullYear(),
- month = this.viewDate.getUTCMonth();
- if (target.is('.old')) {
- if (month == 0) {
+ day = parseInt(target.text(), 10)||1;
+ year = this.viewDate.getUTCFullYear();
+ month = this.viewDate.getUTCMonth();
+ if (target.is('.old')){
+ if (month === 0){
month = 11;
year -= 1;
- } else {
+ }
+ else {
month -= 1;
}
- } else if (target.is('.new')) {
- if (month == 11) {
+ }
+ else if (target.is('.new')){
+ if (month === 11){
month = 0;
year += 1;
- } else {
+ }
+ else {
month += 1;
}
}
- this.date = UTCDate(year, month, day,0,0,0,0);
- this.viewDate = UTCDate(year, month, day,0,0,0,0);
- this.fill();
- this.setValue();
- this.element.trigger({
- type: 'changeDate',
- date: this.date
- });
- var element;
- if (this.isInput) {
- element = this.element;
- } else if (this.component){
- element = this.element.find('input');
- }
- if (element) {
- element.change();
- if (this.autoclose) {
- this.hide();
- }
- }
+ this._setDate(UTCDate(year, month, day));
}
break;
}
}
+ if (this.picker.is(':visible') && this._focused_from){
+ $(this._focused_from).focus();
+ }
+ delete this._focused_from;
+ },
+
+ _toggle_multidate: function(date){
+ var ix = this.dates.contains(date);
+ if (!date){
+ this.dates.clear();
+ }
+ else if (ix !== -1){
+ this.dates.remove(ix);
+ }
+ else {
+ this.dates.push(date);
+ }
+ if (typeof this.o.multidate === 'number')
+ while (this.dates.length > this.o.multidate)
+ this.dates.remove(0);
+ },
+
+ _setDate: function(date, which){
+ if (!which || which === 'date')
+ this._toggle_multidate(date && new Date(date));
+ if (!which || which === 'view')
+ this.viewDate = date && new Date(date);
+
+ this.fill();
+ this.setValue();
+ this._trigger('changeDate');
+ var element;
+ if (this.isInput){
+ element = this.element;
+ }
+ else if (this.component){
+ element = this.element.find('input');
+ }
+ if (element){
+ element.change();
+ }
+ if (this.o.autoclose && (!which || which === 'date')){
+ this.hide();
+ }
},
moveMonth: function(date, dir){
- if (!dir) return date;
+ if (!date)
+ return undefined;
+ if (!dir)
+ return date;
var new_date = new Date(date.valueOf()),
day = new_date.getUTCDate(),
month = new_date.getUTCMonth(),
mag = Math.abs(dir),
new_month, test;
dir = dir > 0 ? 1 : -1;
- if (mag == 1){
- test = dir == -1
+ if (mag === 1){
+ test = dir === -1
// If going back one month, make sure month is not current month
// (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
- ? function(){ return new_date.getUTCMonth() == month; }
+ ? function(){
+ return new_date.getUTCMonth() === month;
+ }
// If going forward one month, make sure month is as expected
// (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
- : function(){ return new_date.getUTCMonth() != new_month; };
+ : function(){
+ return new_date.getUTCMonth() !== new_month;
+ };
new_month = month + dir;
new_date.setUTCMonth(new_month);
// Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
if (new_month < 0 || new_month > 11)
new_month = (new_month + 12) % 12;
- } else {
+ }
+ else {
// For magnitudes >1, move one month at a time...
- for (var i=0; i= this.startDate && date <= this.endDate;
+ return date >= this.o.startDate && date <= this.o.endDate;
},
keydown: function(e){
if (this.picker.is(':not(:visible)')){
- if (e.keyCode == 27) // allow escape to hide and re-show picker
+ if (e.keyCode === 27) // allow escape to hide and re-show picker
this.show();
return;
}
var dateChanged = false,
- dir, day, month,
- newDate, newViewDate;
- switch(e.keyCode){
+ dir, newDate, newViewDate,
+ focusDate = this.focusDate || this.viewDate;
+ switch (e.keyCode){
case 27: // escape
- this.hide();
+ if (this.focusDate){
+ this.focusDate = null;
+ this.viewDate = this.dates.get(-1) || this.viewDate;
+ this.fill();
+ }
+ else
+ this.hide();
e.preventDefault();
break;
case 37: // left
case 39: // right
- if (!this.keyboardNavigation) break;
- dir = e.keyCode == 37 ? -1 : 1;
+ if (!this.o.keyboardNavigation)
+ break;
+ dir = e.keyCode === 37 ? -1 : 1;
if (e.ctrlKey){
- newDate = this.moveYear(this.date, dir);
- newViewDate = this.moveYear(this.viewDate, dir);
- } else if (e.shiftKey){
- newDate = this.moveMonth(this.date, dir);
- newViewDate = this.moveMonth(this.viewDate, dir);
- } else {
- newDate = new Date(this.date);
- newDate.setUTCDate(this.date.getUTCDate() + dir);
- newViewDate = new Date(this.viewDate);
- newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
+ newDate = this.moveYear(this.dates.get(-1) || UTCToday(), dir);
+ newViewDate = this.moveYear(focusDate, dir);
+ this._trigger('changeYear', this.viewDate);
+ }
+ else if (e.shiftKey){
+ newDate = this.moveMonth(this.dates.get(-1) || UTCToday(), dir);
+ newViewDate = this.moveMonth(focusDate, dir);
+ this._trigger('changeMonth', this.viewDate);
+ }
+ else {
+ newDate = new Date(this.dates.get(-1) || UTCToday());
+ newDate.setUTCDate(newDate.getUTCDate() + dir);
+ newViewDate = new Date(focusDate);
+ newViewDate.setUTCDate(focusDate.getUTCDate() + dir);
}
if (this.dateWithinRange(newDate)){
- this.date = newDate;
- this.viewDate = newViewDate;
+ this.focusDate = this.viewDate = newViewDate;
this.setValue();
- this.update();
+ this.fill();
e.preventDefault();
- dateChanged = true;
}
break;
case 38: // up
case 40: // down
- if (!this.keyboardNavigation) break;
- dir = e.keyCode == 38 ? -1 : 1;
+ if (!this.o.keyboardNavigation)
+ break;
+ dir = e.keyCode === 38 ? -1 : 1;
if (e.ctrlKey){
- newDate = this.moveYear(this.date, dir);
- newViewDate = this.moveYear(this.viewDate, dir);
- } else if (e.shiftKey){
- newDate = this.moveMonth(this.date, dir);
- newViewDate = this.moveMonth(this.viewDate, dir);
- } else {
- newDate = new Date(this.date);
- newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
- newViewDate = new Date(this.viewDate);
- newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
+ newDate = this.moveYear(this.dates.get(-1) || UTCToday(), dir);
+ newViewDate = this.moveYear(focusDate, dir);
+ this._trigger('changeYear', this.viewDate);
+ }
+ else if (e.shiftKey){
+ newDate = this.moveMonth(this.dates.get(-1) || UTCToday(), dir);
+ newViewDate = this.moveMonth(focusDate, dir);
+ this._trigger('changeMonth', this.viewDate);
+ }
+ else {
+ newDate = new Date(this.dates.get(-1) || UTCToday());
+ newDate.setUTCDate(newDate.getUTCDate() + dir * 7);
+ newViewDate = new Date(focusDate);
+ newViewDate.setUTCDate(focusDate.getUTCDate() + dir * 7);
}
if (this.dateWithinRange(newDate)){
- this.date = newDate;
- this.viewDate = newViewDate;
+ this.focusDate = this.viewDate = newViewDate;
this.setValue();
- this.update();
+ this.fill();
e.preventDefault();
- dateChanged = true;
}
break;
+ case 32: // spacebar
+ // Spacebar is used in manually typing dates in some formats.
+ // As such, its behavior should not be hijacked.
+ break;
case 13: // enter
- this.hide();
- e.preventDefault();
+ focusDate = this.focusDate || this.dates.get(-1) || this.viewDate;
+ this._toggle_multidate(focusDate);
+ dateChanged = true;
+ this.focusDate = null;
+ this.viewDate = this.dates.get(-1) || this.viewDate;
+ this.setValue();
+ this.fill();
+ if (this.picker.is(':visible')){
+ e.preventDefault();
+ if (this.o.autoclose)
+ this.hide();
+ }
break;
case 9: // tab
+ this.focusDate = null;
+ this.viewDate = this.dates.get(-1) || this.viewDate;
+ this.fill();
this.hide();
break;
}
if (dateChanged){
- this.element.trigger({
- type: 'changeDate',
- date: this.date
- });
+ if (this.dates.length)
+ this._trigger('changeDate');
+ else
+ this._trigger('clearDate');
var element;
- if (this.isInput) {
+ if (this.isInput){
element = this.element;
- } else if (this.component){
+ }
+ else if (this.component){
element = this.element.find('input');
}
- if (element) {
+ if (element){
element.change();
}
}
},
- showMode: function(dir) {
- if (dir) {
- this.viewMode = Math.max(0, Math.min(2, this.viewMode + dir));
+ showMode: function(dir){
+ if (dir){
+ this.viewMode = Math.max(this.o.minViewMode, Math.min(2, this.viewMode + dir));
}
- this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show();
+ this.picker
+ .find('>div')
+ .hide()
+ .filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName)
+ .css('display', 'block');
this.updateNavArrows();
}
};
- $.fn.datepicker = function ( option ) {
- var args = Array.apply(null, arguments);
- args.shift();
- return this.each(function () {
- var $this = $(this),
- data = $this.data('datepicker'),
- options = typeof option == 'object' && option;
- if (!data) {
- $this.data('datepicker', (data = new Datepicker(this, $.extend({}, $.fn.datepicker.defaults,options))));
- }
- if (typeof option == 'string' && typeof data[option] == 'function') {
- data[option].apply(data, args);
- }
+ var DateRangePicker = function(element, options){
+ this.element = $(element);
+ this.inputs = $.map(options.inputs, function(i){
+ return i.jquery ? i[0] : i;
});
+ delete options.inputs;
+
+ $(this.inputs)
+ .datepicker(options)
+ .bind('changeDate', $.proxy(this.dateUpdated, this));
+
+ this.pickers = $.map(this.inputs, function(i){
+ return $(i).data('datepicker');
+ });
+ this.updateDates();
+ };
+ DateRangePicker.prototype = {
+ updateDates: function(){
+ this.dates = $.map(this.pickers, function(i){
+ return i.getUTCDate();
+ });
+ this.updateRanges();
+ },
+ updateRanges: function(){
+ var range = $.map(this.dates, function(d){
+ return d.valueOf();
+ });
+ $.each(this.pickers, function(i, p){
+ p.setRange(range);
+ });
+ },
+ dateUpdated: function(e){
+ // `this.updating` is a workaround for preventing infinite recursion
+ // between `changeDate` triggering and `setUTCDate` calling. Until
+ // there is a better mechanism.
+ if (this.updating)
+ return;
+ this.updating = true;
+
+ var dp = $(e.target).data('datepicker'),
+ new_date = dp.getUTCDate(),
+ i = $.inArray(e.target, this.inputs),
+ l = this.inputs.length;
+ if (i === -1)
+ return;
+
+ $.each(this.pickers, function(i, p){
+ if (!p.getUTCDate())
+ p.setUTCDate(new_date);
+ });
+
+ if (new_date < this.dates[i]){
+ // Date being moved earlier/left
+ while (i >= 0 && new_date < this.dates[i]){
+ this.pickers[i--].setUTCDate(new_date);
+ }
+ }
+ else if (new_date > this.dates[i]){
+ // Date being moved later/right
+ while (i < l && new_date > this.dates[i]){
+ this.pickers[i++].setUTCDate(new_date);
+ }
+ }
+ this.updateDates();
+
+ delete this.updating;
+ },
+ remove: function(){
+ $.map(this.pickers, function(p){ p.remove(); });
+ delete this.element.data().datepicker;
+ }
};
- $.fn.datepicker.defaults = {
+ function opts_from_el(el, prefix){
+ // Derive options from element data-attrs
+ var data = $(el).data(),
+ out = {}, inkey,
+ replace = new RegExp('^' + prefix.toLowerCase() + '([A-Z])');
+ prefix = new RegExp('^' + prefix.toLowerCase());
+ function re_lower(_,a){
+ return a.toLowerCase();
+ }
+ for (var key in data)
+ if (prefix.test(key)){
+ inkey = key.replace(replace, re_lower);
+ out[inkey] = data[key];
+ }
+ return out;
+ }
+
+ function opts_from_locale(lang){
+ // Derive options from locale plugins
+ var out = {};
+ // Check if "de-DE" style date is available, if not language should
+ // fallback to 2 letter code eg "de"
+ if (!dates[lang]){
+ lang = lang.split('-')[0];
+ if (!dates[lang])
+ return;
+ }
+ var d = dates[lang];
+ $.each(locale_opts, function(i,k){
+ if (k in d)
+ out[k] = d[k];
+ });
+ return out;
+ }
+
+ var old = $.fn.datepicker;
+ $.fn.datepicker = function(option){
+ var args = Array.apply(null, arguments);
+ args.shift();
+ var internal_return;
+ this.each(function(){
+ var $this = $(this),
+ data = $this.data('datepicker'),
+ options = typeof option === 'object' && option;
+ if (!data){
+ var elopts = opts_from_el(this, 'date'),
+ // Preliminary otions
+ xopts = $.extend({}, defaults, elopts, options),
+ locopts = opts_from_locale(xopts.language),
+ // Options priority: js args, data-attrs, locales, defaults
+ opts = $.extend({}, defaults, locopts, elopts, options);
+ if ($this.is('.input-daterange') || opts.inputs){
+ var ropts = {
+ inputs: opts.inputs || $this.find('input').toArray()
+ };
+ $this.data('datepicker', (data = new DateRangePicker(this, $.extend(opts, ropts))));
+ }
+ else {
+ $this.data('datepicker', (data = new Datepicker(this, opts)));
+ }
+ }
+ if (typeof option === 'string' && typeof data[option] === 'function'){
+ internal_return = data[option].apply(data, args);
+ if (internal_return !== undefined)
+ return false;
+ }
+ });
+ if (internal_return !== undefined)
+ return internal_return;
+ else
+ return this;
};
+
+ var defaults = $.fn.datepicker.defaults = {
+ autoclose: false,
+ beforeShowDay: $.noop,
+ calendarWeeks: false,
+ clearBtn: false,
+ daysOfWeekDisabled: [],
+ endDate: Infinity,
+ forceParse: true,
+ format: 'mm/dd/yyyy',
+ keyboardNavigation: true,
+ language: 'en',
+ minViewMode: 0,
+ multidate: false,
+ multidateSeparator: ',',
+ orientation: "auto",
+ rtl: false,
+ startDate: -Infinity,
+ startView: 0,
+ todayBtn: false,
+ todayHighlight: false,
+ weekStart: 0
+ };
+ var locale_opts = $.fn.datepicker.locale_opts = [
+ 'format',
+ 'rtl',
+ 'weekStart'
+ ];
$.fn.datepicker.Constructor = Datepicker;
var dates = $.fn.datepicker.dates = {
+ en: {
days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
- monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
- }
+ monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+ today: "Today",
+ clear: "Clear"
+ }
+ };
var DPGlobal = {
modes: [
@@ -635,35 +1445,40 @@
navFnc: 'FullYear',
navStep: 10
}],
- isLeapYear: function (year) {
- return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0))
+ isLeapYear: function(year){
+ return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0));
},
- getDaysInMonth: function (year, month) {
- return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]
+ getDaysInMonth: function(year, month){
+ return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
},
- validParts: /dd?|mm?|MM?|yy(?:yy)?/g,
- nonpunctuation: /[^ -\/:-@\[-`{-~\t\n\r]+/g,
+ validParts: /dd?|DD?|mm?|MM?|yy(?:yy)?/g,
+ nonpunctuation: /[^ -\/:-@\[\u3400-\u9fff-`{-~\t\n\r]+/g,
parseFormat: function(format){
// IE treats \0 as a string end in inputs (truncating the value),
// so it's a bad format delimiter, anyway
var separators = format.replace(this.validParts, '\0').split('\0'),
parts = format.match(this.validParts);
- if (!separators || !separators.length || !parts || parts.length == 0){
+ if (!separators || !separators.length || !parts || parts.length === 0){
throw new Error("Invalid date format.");
}
return {separators: separators, parts: parts};
},
- parseDate: function(date, format) {
- if (date instanceof Date) return date;
- if (/^[-+]\d+[dmwy]([\s,]+[-+]\d+[dmwy])*$/.test(date)) {
- var part_re = /([-+]\d+)([dmwy])/,
- parts = date.match(/([-+]\d+)([dmwy])/g),
- part, dir;
+ parseDate: function(date, format, language){
+ if (!date)
+ return undefined;
+ if (date instanceof Date)
+ return date;
+ if (typeof format === 'string')
+ format = DPGlobal.parseFormat(format);
+ var part_re = /([\-+]\d+)([dmwy])/,
+ parts = date.match(/([\-+]\d+)([dmwy])/g),
+ part, dir, i;
+ if (/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/.test(date)){
date = new Date();
- for (var i=0; i'+
''+
- ' | '+
- ' | '+
- ' | '+
+ '« | '+
+ ' | '+
+ '» | '+
'
'+
'',
- contTemplate: ' |
'
+ contTemplate: ' |
',
+ footTemplate: ''+
+ ''+
+ ' | '+
+ '
'+
+ ''+
+ ' | '+
+ '
'+
+ ''
};
- DPGlobal.template = '