diff --git a/mozilla/calendar/base/content/calendar-event-dialog.js b/mozilla/calendar/base/content/calendar-event-dialog.js
index e83cb4dabae..f0a6abd9e27 100644
--- a/mozilla/calendar/base/content/calendar-event-dialog.js
+++ b/mozilla/calendar/base/content/calendar-event-dialog.js
@@ -78,10 +78,6 @@ function onLoad()
// update the accept button
updateAccept();
- // disabling recurring todo until bug 328197 is fixed
- if (isToDo(window.calendarItem))
- disableElement("item-recurrence");
-
// update datetime pickers
updateDueDate();
updateEntryDate();
@@ -243,6 +239,9 @@ function loadDialog(item)
setElementValue("item-recurrence", "true", "disabled");
setElementValue("set-recurrence", "true", "disabled");
setElementValue("item-calendar", "true", "disabled");
+
+ // don't allow to revoke the entrydate of recurring todo's.
+ disableElement("todo-has-entrydate");
} else if (item.recurrenceInfo)
setElementValue("item-recurrence", "true", "checked");
@@ -295,6 +294,10 @@ function saveDialog(item)
jsDateToDateTime(getElementValue("todo-entrydate")) : null;
if (entryDate) {
entryDate = entryDate.getInTimezone(kDefaultTimezone);
+ } else {
+ // no entrydate, no recurrence
+ item.recurrenceInfo = null;
+ window.recurrenceInfo = null;
}
setItemProperty(item, "entryDate", entryDate);
@@ -486,14 +489,13 @@ function onEndTimeChange()
}
function updateAccept()
{
+ var enableAccept = true;
+
var kDefaultTimezone = calendarDefaultTimezone();
- var acceptButton = document.getElementById("calendar-event-dialog").getButton("accept");
var title = getElementValue("item-title");
if (title.length == 0)
- acceptButton.setAttribute("disabled", "true");
- else if (acceptButton.getAttribute("disabled"))
- acceptButton.removeAttribute("disabled");
+ enableAccept = false;
// don't allow for end dates to be before start dates
var startDate;
@@ -524,14 +526,21 @@ function updateAccept()
jsDateToDateTime(getElementValue("todo-entrydate")) : null;
endDate = getElementValue("todo-has-duedate", "checked") ?
jsDateToDateTime(getElementValue("todo-duedate")) : null;
+
+ var taskRepeatWarning = document.getElementById("task-repeat-warning");
+ if (!startDate && getElementValue("item-recurrence", "checked")) {
+ enableAccept = false;
+ taskRepeatWarning.removeAttribute("hidden");
+ } else {
+ taskRepeatWarning.setAttribute("hidden", "true");
+ }
}
var timeWarning = document.getElementById("end-time-warning");
if (endDate && startDate && endDate.compare(startDate) == -1) {
- acceptButton.setAttribute("disabled", "true");
+ enableAccept = false;
timeWarning.removeAttribute("hidden");
} else {
- acceptButton.removeAttribute("disabled");
timeWarning.setAttribute("hidden", "true");
}
@@ -541,12 +550,20 @@ function updateAccept()
document.getElementById("read-only-cal").setAttribute("hidden",
!cal.readOnly);
if (gReadOnlyMode || cal.readOnly) {
- acceptButton.setAttribute("disabled", "true");
+ enableAccept = false;
}
if (!updateTaskAlarmWarnings()) {
- acceptButton.setAttribute("disabled", "true");
+ enableAccept = false;
}
+
+ var acceptButton = document.getElementById("calendar-event-dialog").getButton("accept");
+ if (!enableAccept) {
+ acceptButton.setAttribute("disabled", "true");
+ } else if (acceptButton.getAttribute("disabled")) {
+ acceptButton.removeAttribute("disabled");
+ }
+
return;
}
@@ -639,6 +656,8 @@ function updateRecurrence()
} else {
setElementValue("set-recurrence", "true", "disabled");
}
+
+ updateAccept();
}
var prevAlarmItem = null;
@@ -691,6 +710,21 @@ function editRecurrence()
args.calendarEvent = window.calendarItem;
args.recurrenceInfo = window.recurrenceInfo || args.calendarEvent.recurrenceInfo;
+ var kDefaultTimezone = calendarDefaultTimezone();
+ if (isEvent(window.calendarItem)) {
+ var startDate = jsDateToDateTime(getElementValue("event-starttime")).getInTimezone(kDefaultTimezone);
+ if (getElementValue("event-all-day", "checked")) {
+ startDate.isDate = true;
+ startDate.normalize();
+ }
+ args.startDate = startDate;
+ } else if (isToDo(window.calendarItem)) {
+ if (!getElementValue("todo-has-entrydate", "checked")) {
+ return;
+ }
+ args.startDate = jsDateToDateTime(getElementValue("todo-entrydate")).getInTimezone(kDefaultTimezone);
+ }
+
var savedWindow = window;
args.onOk = function(recurrenceInfo) {
savedWindow.recurrenceInfo = recurrenceInfo;
diff --git a/mozilla/calendar/base/content/calendar-event-dialog.xul b/mozilla/calendar/base/content/calendar-event-dialog.xul
index edc1f69915d..21c3b5e385e 100644
--- a/mozilla/calendar/base/content/calendar-event-dialog.xul
+++ b/mozilla/calendar/base/content/calendar-event-dialog.xul
@@ -137,6 +137,8 @@
+
diff --git a/mozilla/calendar/base/content/calendar-recurrence-dialog.js b/mozilla/calendar/base/content/calendar-recurrence-dialog.js
index 04458859d43..e7e1b56710b 100644
--- a/mozilla/calendar/base/content/calendar-recurrence-dialog.js
+++ b/mozilla/calendar/base/content/calendar-recurrence-dialog.js
@@ -43,6 +43,7 @@ function onLoad()
window.onAcceptCallback = args.onOk;
window.calendarEvent = args.calendarEvent;
window.originalRecurrenceInfo = args.recurrenceInfo;
+ window.startDate = args.startDate;
loadDialog();
@@ -82,34 +83,34 @@ function loadDialog()
var props = sbs.createBundle("chrome://calendar/locale/dateFormat.properties");
// Set label to '15th day of the month'
- var nthstr = props.GetStringFromName("ordinal.suffix."+window.calendarEvent.startDate.day);
- var str = props.formatStringFromName("recurNthDay", [window.calendarEvent.startDate.day, nthstr], 2);
+ var nthstr = props.GetStringFromName("ordinal.suffix."+window.startDate.day);
+ var str = props.formatStringFromName("recurNthDay", [window.startDate.day, nthstr], 2);
document.getElementById("monthly-nth-day").label = str;
// Set label to 'second week of the month'
- var monthWeekNum = Math.floor(window.calendarEvent.startDate.day / 7) + 1;
+ var monthWeekNum = Math.floor(window.startDate.day / 7) + 1;
nthstr = props.GetStringFromName("ordinal.name."+monthWeekNum);
- var daystr = props.GetStringFromName("day."+(window.calendarEvent.startDate.weekday+1)+".name");
+ var daystr = props.GetStringFromName("day."+(window.startDate.weekday+1)+".name");
str = props.formatStringFromName("recurNthWeek", [nthstr, daystr], 2);
document.getElementById("monthly-nth-week").label = str;
// Set two values needed to create the real rrule later
- document.getElementById("monthly-nth-week").day = window.calendarEvent.startDate.weekday;
+ document.getElementById("monthly-nth-week").day = window.startDate.weekday;
document.getElementById("monthly-nth-week").week = monthWeekNum;
// If this is the last friday of the month, set label to 'last friday of the month'
// (Or any other day, ofcourse.) Otherwise, hide last option
- var monthLength = window.calendarEvent.startDate.endOfMonth.day;
- var isLastWeek = (monthLength - window.calendarEvent.startDate.day) < 7;
+ var monthLength = window.startDate.endOfMonth.day;
+ var isLastWeek = (monthLength - window.startDate.day) < 7;
document.getElementById("monthly-last-week").hidden = !isLastWeek;
- var isLastDay = (monthLength == window.calendarEvent.startDate.day);
+ var isLastDay = (monthLength == window.startDate.day);
document.getElementById("monthly-last-day").hidden = !isLastDay;
if (isLastWeek) {
str = props.formatStringFromName("recurLast", [daystr], 1);
document.getElementById("monthly-last-week").label = str;
}
- document.getElementById("monthly-last-week").day = window.calendarEvent.startDate.weekday;
+ document.getElementById("monthly-last-week").day = window.startDate.weekday;
if (!window.originalRecurrenceInfo)
return;
@@ -243,7 +244,7 @@ function saveDialog()
var recurtype = getElementValue("monthly-type");
switch (recurtype) {
case "nth-day":
- recRule.setComponent("BYMONTHDAY", 1, [window.calendarEvent.startDate.day]);
+ recRule.setComponent("BYMONTHDAY", 1, [window.startDate.day]);
break;
case "nth-week":
var el = document.getElementById('monthly-nth-week');
diff --git a/mozilla/calendar/base/public/calITodo.idl b/mozilla/calendar/base/public/calITodo.idl
index c3b79db6d58..32657dde8d0 100644
--- a/mozilla/calendar/base/public/calITodo.idl
+++ b/mozilla/calendar/base/public/calITodo.idl
@@ -94,5 +94,12 @@ interface calITodo : calIItemBase
// IN-PROCESS.) It's not clear that we want any more magic than a simple
// property to control "all complete" vs "not complete in any way".
attribute boolean isCompleted;
+
+ /**
+ * The duration of the todo, which is defined as dueDate - entryDate.
+ * Please note that null is returned if either entryDate or
+ * dueDate don't exist.
+ */
+ readonly attribute calIDuration duration;
};
diff --git a/mozilla/calendar/base/src/calRecurrenceInfo.js b/mozilla/calendar/base/src/calRecurrenceInfo.js
index e89fdef1601..d6d9fe3698b 100644
--- a/mozilla/calendar/base/src/calRecurrenceInfo.js
+++ b/mozilla/calendar/base/src/calRecurrenceInfo.js
@@ -358,7 +358,13 @@ calRecurrenceInfo.prototype = {
}
// is our end date within the range?
- var dtend = ex.item.getProperty("DTEND");
+ var name = "DTEND";
+ if (ex.item instanceof Components.interfaces.calITodo)
+ name = "DUE";
+ var dtend = ex.item.getProperty(name);
+ if (!dtend)
+ return;
+
if ((!aRangeStart || aRangeStart.compare(dtend) <= 0) &&
(!aRangeEnd || aRangeEnd.compare(dtend) > 0))
{
@@ -471,7 +477,12 @@ calRecurrenceInfo.prototype = {
var proxy = this.getExceptionFor(aRecurrenceId, false);
if (!proxy) {
var duration = null;
- if (this.mBaseItem.hasProperty("DTEND"))
+
+ var name = "DTEND";
+ if (this.mBaseItem instanceof Components.interfaces.calITodo)
+ name = "DUE";
+
+ if (this.mBaseItem.hasProperty(name))
duration = this.mBaseItem.duration;
proxy = this.mBaseItem.createProxy();
@@ -480,7 +491,7 @@ calRecurrenceInfo.prototype = {
if (duration) {
var enddate = aRecurrenceId.clone();
enddate.addDuration(duration);
- proxy.setProperty("DTEND", enddate);
+ proxy.setProperty(name, enddate);
}
if (!this.mBaseItem.isMutable)
proxy.makeImmutable();
@@ -678,6 +689,17 @@ calRecurrenceInfo.prototype = {
// in case we're about to modify a parentItem (aka 'folded' item), we need
// to modify the recurrenceId's of all possibly existing exceptions as well.
onStartDateChange: function (aNewStartTime, aOldStartTime) {
+
+ // passing null for the new starttime would indicate an error condition,
+ // since having a recurrence without a starttime is invalid.
+ if (!aNewStartTime) {
+ throw Components.results.NS_ERROR_INVALID_ARG;
+ }
+
+ // no need to check for changes if there's no previous starttime.
+ if (!aOldStartTime) {
+ return;
+ }
// convert both dates to UTC since subtractDate is not timezone aware.
aOldStartTime = aOldStartTime.getInTimezone("UTC");
diff --git a/mozilla/calendar/base/src/calTodo.js b/mozilla/calendar/base/src/calTodo.js
index 5123d7335ba..45570b8b88e 100644
--- a/mozilla/calendar/base/src/calTodo.js
+++ b/mozilla/calendar/base/src/calTodo.js
@@ -159,6 +159,14 @@ calTodo.prototype = {
}
},
+ get duration() {
+ if (!this.entryDate)
+ return null;
+ if (!this.dueDate)
+ return null;
+ return this.entryDate.subtractDate(this.dueDate);
+ },
+
get recurrenceStartDate() {
return this.entryDate;
},