2005-05-28 14:08:44 +00:00
|
|
|
/* Copyright Mihai Bazon, 2002, 2003 | http://dynarch.com/mishoo/
|
|
|
|
|
* ---------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* The DHTML Calendar
|
|
|
|
|
*
|
|
|
|
|
* Details and latest version at:
|
|
|
|
|
* http://dynarch.com/mishoo/calendar.epl
|
|
|
|
|
*
|
|
|
|
|
* This script is distributed under the GNU Lesser General Public License.
|
|
|
|
|
* Read the entire license text here: http://www.gnu.org/licenses/lgpl.html
|
|
|
|
|
*
|
|
|
|
|
* This file defines helper functions for setting up the calendar. They are
|
|
|
|
|
* intended to help non-programmers get a working calendar on their site
|
|
|
|
|
* quickly. This script should not be seen as part of the calendar. It just
|
|
|
|
|
* shows you what one can do with the calendar, while in the same time
|
|
|
|
|
* providing a quick and simple method for setting it up. If you need
|
|
|
|
|
* exhaustive customization of the calendar creation process feel free to
|
|
|
|
|
* modify this code to suit your needs (this is recommended and much better
|
|
|
|
|
* than modifying calendar.js itself).
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// $Id: calendar-setup.js,v 1.25 2005/03/07 09:51:33 mishoo Exp $
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* This function "patches" an input field (or other element) to use a calendar
|
|
|
|
|
* widget for date selection.
|
|
|
|
|
*
|
|
|
|
|
* The "params" is a single object that can have the following properties:
|
|
|
|
|
*
|
|
|
|
|
* prop. name | description
|
|
|
|
|
* -------------------------------------------------------------------------------------------------
|
|
|
|
|
* inputField | the ID of an input field to store the date
|
|
|
|
|
* displayArea | the ID of a DIV or other element to show the date
|
|
|
|
|
* button | ID of a button or other element that will trigger the calendar
|
|
|
|
|
* eventName | event that will trigger the calendar, without the "on" prefix (default: "click")
|
|
|
|
|
* ifFormat | date format that will be stored in the input field
|
|
|
|
|
* daFormat | the date format that will be used to display the date in displayArea
|
|
|
|
|
* singleClick | (true/false) wether the calendar is in single click mode or not (default: true)
|
|
|
|
|
* firstDay | numeric: 0 to 6. "0" means display Sunday first, "1" means display Monday first, etc.
|
|
|
|
|
* align | alignment (default: "Br"); if you don't know what's this see the calendar documentation
|
|
|
|
|
* range | array with 2 elements. Default: [1900, 2999] -- the range of years available
|
|
|
|
|
* weekNumbers | (true/false) if it's true (default) the calendar will display week numbers
|
|
|
|
|
* flat | null or element ID; if not null the calendar will be a flat calendar having the parent with the given ID
|
|
|
|
|
* flatCallback | function that receives a JS Date object and returns an URL to point the browser to (for flat calendar)
|
|
|
|
|
* disableFunc | function that receives a JS Date object and should return true if that date has to be disabled in the calendar
|
|
|
|
|
* onSelect | function that gets called when a date is selected. You don't _have_ to supply this (the default is generally okay)
|
|
|
|
|
* onClose | function that gets called when the calendar is closed. [default]
|
|
|
|
|
* onUpdate | function that gets called after the date is updated in the input field. Receives a reference to the calendar.
|
|
|
|
|
* date | the date that the calendar will be initially displayed to
|
|
|
|
|
* showsTime | default: false; if true the calendar will include a time selector
|
|
|
|
|
* timeFormat | the time format; can be "12" or "24", default is "12"
|
|
|
|
|
* electric | if true (default) then given fields/date areas are updated for each move; otherwise they're updated only on close
|
|
|
|
|
* step | configures the step of the years in drop-down boxes; default: 2
|
|
|
|
|
* position | configures the calendar absolute position; default: null
|
|
|
|
|
* cache | if "true" (but default: "false") it will reuse the same calendar object, where possible
|
|
|
|
|
* showOthers | if "true" (but default: "false") it will show days from other months too
|
|
|
|
|
*
|
|
|
|
|
* None of them is required, they all have default values. However, if you
|
|
|
|
|
* pass none of "inputField", "displayArea" or "button" you'll get a warning
|
|
|
|
|
* saying "nothing to setup".
|
|
|
|
|
*/
|
|
|
|
|
Calendar.setup = function (params) {
|
2005-06-11 12:24:19 +00:00
|
|
|
function param_default(pname, def) { if (typeof params[pname] == "undefined") { params[pname] = def; } };
|
2005-05-28 14:08:44 +00:00
|
|
|
|
2005-06-11 12:24:19 +00:00
|
|
|
param_default("inputField", null);
|
|
|
|
|
param_default("displayArea", null);
|
|
|
|
|
param_default("button", null);
|
|
|
|
|
param_default("eventName", "click");
|
|
|
|
|
param_default("ifFormat", "%Y/%m/%d");
|
|
|
|
|
param_default("daFormat", "%Y/%m/%d");
|
|
|
|
|
param_default("singleClick", true);
|
|
|
|
|
param_default("disableFunc", null);
|
|
|
|
|
param_default("dateStatusFunc", params["disableFunc"]); // takes precedence if both are defined
|
|
|
|
|
param_default("dateText", null);
|
|
|
|
|
param_default("firstDay", null);
|
|
|
|
|
param_default("align", "Br");
|
|
|
|
|
param_default("range", [1900, 2999]);
|
|
|
|
|
param_default("weekNumbers", true);
|
|
|
|
|
param_default("flat", null);
|
|
|
|
|
param_default("flatCallback", null);
|
|
|
|
|
param_default("onSelect", null);
|
|
|
|
|
param_default("onClose", null);
|
|
|
|
|
param_default("onUpdate", null);
|
|
|
|
|
param_default("date", null);
|
|
|
|
|
param_default("showsTime", false);
|
|
|
|
|
param_default("timeFormat", "24");
|
|
|
|
|
param_default("electric", true);
|
|
|
|
|
param_default("step", 2);
|
|
|
|
|
param_default("position", null);
|
|
|
|
|
param_default("cache", false);
|
|
|
|
|
param_default("showOthers", false);
|
|
|
|
|
param_default("multiple", null);
|
2005-05-28 14:08:44 +00:00
|
|
|
|
2005-06-11 12:24:19 +00:00
|
|
|
var tmp = ["inputField", "displayArea", "button"];
|
|
|
|
|
for (var i in tmp) {
|
|
|
|
|
if (typeof params[tmp[i]] == "string") {
|
|
|
|
|
params[tmp[i]] = document.getElementById(params[tmp[i]]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!(params.flat || params.multiple || params.inputField || params.displayArea || params.button)) {
|
|
|
|
|
alert("Calendar.setup:\n Nothing to setup (no fields found). Please check your code");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2005-05-28 14:08:44 +00:00
|
|
|
|
2005-06-11 12:24:19 +00:00
|
|
|
function onSelect(cal) {
|
|
|
|
|
var p = cal.params;
|
|
|
|
|
var update = (cal.dateClicked || p.electric);
|
|
|
|
|
if (update && p.inputField) {
|
|
|
|
|
p.inputField.value = cal.date.print(p.ifFormat);
|
|
|
|
|
if (typeof p.inputField.onchange == "function")
|
|
|
|
|
p.inputField.onchange();
|
|
|
|
|
}
|
|
|
|
|
if (update && p.displayArea)
|
|
|
|
|
p.displayArea.innerHTML = cal.date.print(p.daFormat);
|
|
|
|
|
if (update && typeof p.onUpdate == "function")
|
|
|
|
|
p.onUpdate(cal);
|
|
|
|
|
if (update && p.flat) {
|
|
|
|
|
if (typeof p.flatCallback == "function")
|
|
|
|
|
p.flatCallback(cal);
|
|
|
|
|
}
|
|
|
|
|
if (update && p.singleClick && cal.dateClicked)
|
|
|
|
|
cal.callCloseHandler();
|
|
|
|
|
};
|
2005-05-28 14:08:44 +00:00
|
|
|
|
2005-06-11 12:24:19 +00:00
|
|
|
if (params.flat != null) {
|
|
|
|
|
if (typeof params.flat == "string")
|
|
|
|
|
params.flat = document.getElementById(params.flat);
|
|
|
|
|
if (!params.flat) {
|
|
|
|
|
alert("Calendar.setup:\n Flat specified but can't find parent.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
var cal = new Calendar(params.firstDay, params.date, params.onSelect || onSelect);
|
|
|
|
|
cal.showsOtherMonths = params.showOthers;
|
|
|
|
|
cal.showsTime = params.showsTime;
|
|
|
|
|
cal.time24 = (params.timeFormat == "24");
|
|
|
|
|
cal.params = params;
|
|
|
|
|
cal.weekNumbers = params.weekNumbers;
|
|
|
|
|
cal.setRange(params.range[0], params.range[1]);
|
|
|
|
|
cal.setDateStatusHandler(params.dateStatusFunc);
|
|
|
|
|
cal.getDateText = params.dateText;
|
|
|
|
|
if (params.ifFormat) {
|
|
|
|
|
cal.setDateFormat(params.ifFormat);
|
|
|
|
|
}
|
|
|
|
|
if (params.inputField && typeof params.inputField.value == "string") {
|
|
|
|
|
cal.parseDate(params.inputField.value);
|
|
|
|
|
}
|
|
|
|
|
cal.create(params.flat);
|
|
|
|
|
cal.show();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2005-05-28 14:08:44 +00:00
|
|
|
|
2005-06-11 12:24:19 +00:00
|
|
|
var triggerEl = params.button || params.displayArea || params.inputField;
|
|
|
|
|
triggerEl["on" + params.eventName] = function() {
|
|
|
|
|
var dateEl = params.inputField || params.displayArea;
|
|
|
|
|
var dateFmt = params.inputField ? params.ifFormat : params.daFormat;
|
|
|
|
|
var mustCreate = false;
|
|
|
|
|
var cal = window.calendar;
|
|
|
|
|
if (dateEl)
|
|
|
|
|
params.date = Date.parseDate(dateEl.value || dateEl.innerHTML, dateFmt);
|
|
|
|
|
if (!(cal && params.cache)) {
|
|
|
|
|
window.calendar = cal = new Calendar(params.firstDay,
|
|
|
|
|
params.date,
|
|
|
|
|
params.onSelect || onSelect,
|
|
|
|
|
params.onClose || function(cal) { cal.hide(); });
|
|
|
|
|
cal.showsTime = params.showsTime;
|
|
|
|
|
cal.time24 = (params.timeFormat == "24");
|
|
|
|
|
cal.weekNumbers = params.weekNumbers;
|
|
|
|
|
mustCreate = true;
|
|
|
|
|
} else {
|
|
|
|
|
if (params.date)
|
|
|
|
|
cal.setDate(params.date);
|
|
|
|
|
cal.hide();
|
|
|
|
|
}
|
|
|
|
|
if (params.multiple) {
|
|
|
|
|
cal.multiple = {};
|
|
|
|
|
for (var i = params.multiple.length; --i >= 0;) {
|
|
|
|
|
var d = params.multiple[i];
|
|
|
|
|
var ds = d.print("%Y%m%d");
|
|
|
|
|
cal.multiple[ds] = d;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
cal.showsOtherMonths = params.showOthers;
|
|
|
|
|
cal.yearStep = params.step;
|
|
|
|
|
cal.setRange(params.range[0], params.range[1]);
|
|
|
|
|
cal.params = params;
|
|
|
|
|
cal.setDateStatusHandler(params.dateStatusFunc);
|
|
|
|
|
cal.getDateText = params.dateText;
|
|
|
|
|
cal.setDateFormat(dateFmt);
|
|
|
|
|
if (mustCreate)
|
|
|
|
|
cal.create();
|
|
|
|
|
cal.refresh();
|
|
|
|
|
if (!params.position)
|
|
|
|
|
cal.showAtElement(params.button || params.displayArea || params.inputField, params.align);
|
|
|
|
|
else
|
|
|
|
|
cal.showAt(params.position[0], params.position[1]);
|
|
|
|
|
return false;
|
|
|
|
|
};
|
2005-05-28 14:08:44 +00:00
|
|
|
|
2006-11-21 05:10:32 +00:00
|
|
|
/* if (params.inputField) {
|
|
|
|
|
new DateDueKeyboardShortcutSupport(params.inputField, params.ifFormat, cal);
|
2006-04-23 06:23:03 +00:00
|
|
|
}
|
2006-11-21 05:10:32 +00:00
|
|
|
*/
|
2005-06-11 12:24:19 +00:00
|
|
|
return cal;
|
2005-05-28 14:08:44 +00:00
|
|
|
};
|
2006-04-23 06:23:03 +00:00
|
|
|
|
|
|
|
|
/* Adds keyboard shortcuts to the passed in date field:
|
|
|
|
|
*
|
|
|
|
|
* 't' input today's date
|
|
|
|
|
* '+' or '=' increment the date in the field by one day
|
|
|
|
|
* '-' decrement the date in the field by one day
|
|
|
|
|
*
|
|
|
|
|
* If the calendar is visible, the shortcuts play nicely with it. If not,
|
|
|
|
|
* they still work properly. Pressing '+' when no date is entered in the
|
|
|
|
|
* field will set the date to tomorrow, and likewise '-' with no date
|
|
|
|
|
* entered will set the date to yesterday.
|
|
|
|
|
*/
|
2007-01-06 10:06:33 +00:00
|
|
|
DateDueKeyboardShortcutSupport = Class.create();
|
2006-04-23 06:23:03 +00:00
|
|
|
DateDueKeyboardShortcutSupport.prototype = {
|
|
|
|
|
initialize: function(element, dateFormat) {
|
|
|
|
|
this.element = $(element);
|
|
|
|
|
this.dateFormat = dateFormat || "%Y/%m/%d";
|
|
|
|
|
Event.observe(this.element,'keypress',this.onkeypress.bindAsEventListener(this));
|
|
|
|
|
title = this.element.getAttributeNode("title");
|
|
|
|
|
tooltip = 'Shortcuts: [t] today; [-] previous day; [+] next day; Click to show calendar';
|
|
|
|
|
if (title && title.value)
|
|
|
|
|
{
|
|
|
|
|
this.element.setAttribute("title", title.value + ' (' + tooltip + ')');
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
this.element.setAttribute("title", tooltip);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
onkeypress: function(event) {
|
|
|
|
|
handled = true;
|
|
|
|
|
switch (this.getCharFromKeyPressEvent(event)) {
|
|
|
|
|
case "t":
|
|
|
|
|
this.setTextBoxToTodaysDate();
|
|
|
|
|
break;
|
|
|
|
|
case "+":
|
|
|
|
|
case "=":
|
|
|
|
|
this.setTextBoxToNextDay();
|
|
|
|
|
break;
|
|
|
|
|
case "-":
|
|
|
|
|
this.setTextBoxToPreviousDay();
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
handled = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (handled) {
|
|
|
|
|
this.cancel(event);
|
|
|
|
|
}
|
|
|
|
|
},
|
Started adding support for the Chronic library, to provide natural language date selections. You can now type phrases such as "tomorrow", "nov 10", "1 week hence", "10 days hence" and so on into the date box and these will be parsed into a valid date. I haven't managed to get proper validation working yet, but you'll get a live preview of the parsed date just below the input box.
What doesn't work yet:
* If you delete all characters in the date box, you'll get an error message. This will go away if you type more characters
* You'll get an error as above when the form is cleared and redisplayed after submission. Again, it will go away if you type anything in the box.
* Validation doesn't work, but the preview will display "Invalid date" if Chronic can't parse your phrase
* This isn't added to the edit form for actions yet.
Also partially fixed #394: the mobile interface works again, but you might get an error visiting the subsequent pages of a filtered view (i.e. viewing a single context or project). I'm not sure what's causing this, but it's on my list to fix.
git-svn-id: http://www.rousette.org.uk/svn/tracks-repos/trunk@332 a4c988fc-2ded-0310-b66e-134b36920a42
2006-10-25 15:35:08 +00:00
|
|
|
|
|
|
|
|
setTextBoxToChronicDate : function() {
|
|
|
|
|
today = new Date();
|
|
|
|
|
this.setDate(today);
|
|
|
|
|
},
|
|
|
|
|
|
2006-04-23 06:23:03 +00:00
|
|
|
setTextBoxToTodaysDate : function() {
|
|
|
|
|
today = new Date();
|
|
|
|
|
this.setDate(today);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
setTextBoxToNextDay : function() {
|
|
|
|
|
this.addDaysToTextBoxDate(1);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
setTextBoxToPreviousDay : function() {
|
|
|
|
|
this.addDaysToTextBoxDate(-1);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
addDaysToTextBoxDate : function(numDays) {
|
|
|
|
|
date = Date.parseDate(this.element.value, this.dateFormat);
|
|
|
|
|
date.setDate(date.getDate() + numDays);
|
|
|
|
|
this.setDate(date);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
setDate : function(date) {
|
|
|
|
|
this.element.value = date.print(this.dateFormat);
|
|
|
|
|
if (window.calendar) {
|
|
|
|
|
window.calendar.setDate(date);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
cancel : function(event) {
|
|
|
|
|
if (event.preventDefault) {
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
}
|
|
|
|
|
event.returnValue = false;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
getCharFromKeyPressEvent : function(event) {
|
|
|
|
|
var charCode = (event.charCode) ? event.charCode :
|
|
|
|
|
((event.keyCode) ? event.keyCode :
|
|
|
|
|
((event.which) ? event.which : 0));
|
|
|
|
|
return String.fromCharCode(charCode);
|
|
|
|
|
}
|
2007-01-06 10:06:33 +00:00
|
|
|
};
|