Rev 1318 | Blame | Compare with Previous | Last modification | View Log | RSS feed
/*Copyright (c) 2004-2006, The Dojo FoundationAll Rights Reserved.Licensed under the Academic Free License version 2.1 or above OR themodified BSD license. For more information on Dojo licensing, see:http://dojotoolkit.org/community/licensing.shtml*/dojo.provide("dojo.cal.iCalendar");dojo.require("dojo.lang.common");dojo.require("dojo.cal.textDirectory");dojo.require("dojo.date.common");dojo.require("dojo.date.serialize");dojo.cal.iCalendar.fromText = function (text) {var properties = dojo.cal.textDirectory.tokenise(text);var calendars = [];for (var i = 0, begun = false; i < properties.length; i++) {var prop = properties[i];if (!begun) {if (prop.name == "BEGIN" && prop.value == "VCALENDAR") {begun = true;var calbody = [];}} else {if (prop.name == "END" && prop.value == "VCALENDAR") {calendars.push(new dojo.cal.iCalendar.VCalendar(calbody));begun = false;} else {calbody.push(prop);}}}return calendars;};dojo.cal.iCalendar.Component = function (body) {if (!this.name) {this.name = "COMPONENT";}this.properties = [];this.components = [];if (body) {for (var i = 0, context = ""; i < body.length; i++) {if (context == "") {if (body[i].name == "BEGIN") {context = body[i].value;var childprops = [];} else {this.addProperty(new dojo.cal.iCalendar.Property(body[i]));}} else {if (body[i].name == "END" && body[i].value == context) {if (context == "VEVENT") {this.addComponent(new dojo.cal.iCalendar.VEvent(childprops));} else {if (context == "VTIMEZONE") {this.addComponent(new dojo.cal.iCalendar.VTimeZone(childprops));} else {if (context == "VTODO") {this.addComponent(new dojo.cal.iCalendar.VTodo(childprops));} else {if (context == "VJOURNAL") {this.addComponent(new dojo.cal.iCalendar.VJournal(childprops));} else {if (context == "VFREEBUSY") {this.addComponent(new dojo.cal.iCalendar.VFreeBusy(childprops));} else {if (context == "STANDARD") {this.addComponent(new dojo.cal.iCalendar.Standard(childprops));} else {if (context == "DAYLIGHT") {this.addComponent(new dojo.cal.iCalendar.Daylight(childprops));} else {if (context == "VALARM") {this.addComponent(new dojo.cal.iCalendar.VAlarm(childprops));} else {dojo.unimplemented("dojo.cal.iCalendar." + context);}}}}}}}}context = "";} else {childprops.push(body[i]);}}}if (this._ValidProperties) {this.postCreate();}}};dojo.extend(dojo.cal.iCalendar.Component, {addProperty:function (prop) {this.properties.push(prop);this[prop.name.toLowerCase()] = prop;}, addComponent:function (prop) {this.components.push(prop);}, postCreate:function () {for (var x = 0; x < this._ValidProperties.length; x++) {var evtProperty = this._ValidProperties[x];var found = false;for (var y = 0; y < this.properties.length; y++) {var prop = this.properties[y];var propName = prop.name.toLowerCase();if (dojo.lang.isArray(evtProperty)) {var alreadySet = false;for (var z = 0; z < evtProperty.length; z++) {var evtPropertyName = evtProperty[z].name.toLowerCase();if ((this[evtPropertyName]) && (evtPropertyName != propName)) {alreadySet = true;}}if (!alreadySet) {this[propName] = prop;}} else {if (propName == evtProperty.name.toLowerCase()) {found = true;if (evtProperty.occurance == 1) {this[propName] = prop;} else {found = true;if (!dojo.lang.isArray(this[propName])) {this[propName] = [];}this[propName].push(prop);}}}}if (evtProperty.required && !found) {dojo.debug("iCalendar - " + this.name + ": Required Property not found: " + evtProperty.name);}}if (dojo.lang.isArray(this.rrule)) {for (var x = 0; x < this.rrule.length; x++) {var rule = this.rrule[x].value;this.rrule[x].cache = function () {};var temp = rule.split(";");for (var y = 0; y < temp.length; y++) {var pair = temp[y].split("=");var key = pair[0].toLowerCase();var val = pair[1];if ((key == "freq") || (key == "interval") || (key == "until")) {this.rrule[x][key] = val;} else {var valArray = val.split(",");this.rrule[x][key] = valArray;}}}this.recurring = true;}}, toString:function () {return "[iCalendar.Component; " + this.name + ", " + this.properties.length + " properties, " + this.components.length + " components]";}});dojo.cal.iCalendar.Property = function (prop) {this.name = prop.name;this.group = prop.group;this.params = prop.params;this.value = prop.value;};dojo.extend(dojo.cal.iCalendar.Property, {toString:function () {return "[iCalenday.Property; " + this.name + ": " + this.value + "]";}});var _P = function (n, oc, req) {return {name:n, required:(req) ? true : false, occurance:(oc == "*" || !oc) ? -1 : oc};};dojo.cal.iCalendar.VCalendar = function (calbody) {this.name = "VCALENDAR";this.recurring = [];this.nonRecurringEvents = function () {};dojo.cal.iCalendar.Component.call(this, calbody);};dojo.inherits(dojo.cal.iCalendar.VCalendar, dojo.cal.iCalendar.Component);dojo.extend(dojo.cal.iCalendar.VCalendar, {addComponent:function (prop) {this.components.push(prop);if (prop.name.toLowerCase() == "vevent") {if (prop.rrule) {this.recurring.push(prop);} else {var startDate = prop.getDate();var month = startDate.getMonth() + 1;var dateString = month + "-" + startDate.getDate() + "-" + startDate.getFullYear();if (!dojo.lang.isArray(this[dateString])) {this.nonRecurringEvents[dateString] = [];}this.nonRecurringEvents[dateString].push(prop);}}}, preComputeRecurringEvents:function (until) {var calculatedEvents = function () {};for (var x = 0; x < this.recurring.length; x++) {var dates = this.recurring[x].getDates(until);for (var y = 0; y < dates.length; y++) {var month = dates[y].getMonth() + 1;var dateStr = month + "-" + dates[y].getDate() + "-" + dates[y].getFullYear();if (!dojo.lang.isArray(calculatedEvents[dateStr])) {calculatedEvents[dateStr] = [];}if (!dojo.lang.inArray(calculatedEvents[dateStr], this.recurring[x])) {calculatedEvents[dateStr].push(this.recurring[x]);}}}this.recurringEvents = calculatedEvents;}, getEvents:function (date) {var events = [];var recur = [];var nonRecur = [];var month = date.getMonth() + 1;var dateStr = month + "-" + date.getDate() + "-" + date.getFullYear();if (dojo.lang.isArray(this.nonRecurringEvents[dateStr])) {nonRecur = this.nonRecurringEvents[dateStr];dojo.debug("Number of nonRecurring Events: " + nonRecur.length);}if (dojo.lang.isArray(this.recurringEvents[dateStr])) {recur = this.recurringEvents[dateStr];}events = recur.concat(nonRecur);if (events.length > 0) {return events;}return null;}});var StandardProperties = [_P("dtstart", 1, true), _P("tzoffsetto", 1, true), _P("tzoffsetfrom", 1, true), _P("comment"), _P("rdate"), _P("rrule"), _P("tzname")];dojo.cal.iCalendar.Standard = function (body) {this.name = "STANDARD";this._ValidProperties = StandardProperties;dojo.cal.iCalendar.Component.call(this, body);};dojo.inherits(dojo.cal.iCalendar.Standard, dojo.cal.iCalendar.Component);var DaylightProperties = [_P("dtstart", 1, true), _P("tzoffsetto", 1, true), _P("tzoffsetfrom", 1, true), _P("comment"), _P("rdate"), _P("rrule"), _P("tzname")];dojo.cal.iCalendar.Daylight = function (body) {this.name = "DAYLIGHT";this._ValidProperties = DaylightProperties;dojo.cal.iCalendar.Component.call(this, body);};dojo.inherits(dojo.cal.iCalendar.Daylight, dojo.cal.iCalendar.Component);var VEventProperties = [_P("class", 1), _P("created", 1), _P("description", 1), _P("dtstart", 1), _P("geo", 1), _P("last-mod", 1), _P("location", 1), _P("organizer", 1), _P("priority", 1), _P("dtstamp", 1), _P("seq", 1), _P("status", 1), _P("summary", 1), _P("transp", 1), _P("uid", 1), _P("url", 1), _P("recurid", 1), [_P("dtend", 1), _P("duration", 1)], _P("attach"), _P("attendee"), _P("categories"), _P("comment"), _P("contact"), _P("exdate"), _P("exrule"), _P("rstatus"), _P("related"), _P("resources"), _P("rdate"), _P("rrule")];dojo.cal.iCalendar.VEvent = function (body) {this._ValidProperties = VEventProperties;this.name = "VEVENT";dojo.cal.iCalendar.Component.call(this, body);this.recurring = false;this.startDate = dojo.date.fromIso8601(this.dtstart.value);};dojo.inherits(dojo.cal.iCalendar.VEvent, dojo.cal.iCalendar.Component);dojo.extend(dojo.cal.iCalendar.VEvent, {getDates:function (until) {var dtstart = this.getDate();var recurranceSet = [];var weekdays = ["su", "mo", "tu", "we", "th", "fr", "sa"];var order = {"daily":1, "weekly":2, "monthly":3, "yearly":4, "byday":1, "bymonthday":1, "byweekno":2, "bymonth":3, "byyearday":4};for (var x = 0; x < this.rrule.length; x++) {var rrule = this.rrule[x];var freq = rrule.freq.toLowerCase();var interval = 1;if (rrule.interval > interval) {interval = rrule.interval;}var set = [];var freqInt = order[freq];if (rrule.until) {var tmpUntil = dojo.date.fromIso8601(rrule.until);} else {var tmpUntil = until;}if (tmpUntil > until) {tmpUntil = until;}if (dtstart < tmpUntil) {var expandingRules = function () {};var cullingRules = function () {};expandingRules.length = 0;cullingRules.length = 0;switch (freq) {case "yearly":var nextDate = new Date(dtstart);set.push(nextDate);while (nextDate < tmpUntil) {nextDate.setYear(nextDate.getFullYear() + interval);tmpDate = new Date(nextDate);if (tmpDate < tmpUntil) {set.push(tmpDate);}}break;case "monthly":nextDate = new Date(dtstart);set.push(nextDate);while (nextDate < tmpUntil) {nextDate.setMonth(nextDate.getMonth() + interval);var tmpDate = new Date(nextDate);if (tmpDate < tmpUntil) {set.push(tmpDate);}}break;case "weekly":nextDate = new Date(dtstart);set.push(nextDate);while (nextDate < tmpUntil) {nextDate.setDate(nextDate.getDate() + (7 * interval));var tmpDate = new Date(nextDate);if (tmpDate < tmpUntil) {set.push(tmpDate);}}break;case "daily":nextDate = new Date(dtstart);set.push(nextDate);while (nextDate < tmpUntil) {nextDate.setDate(nextDate.getDate() + interval);var tmpDate = new Date(nextDate);if (tmpDate < tmpUntil) {set.push(tmpDate);}}break;}if ((rrule["bymonth"]) && (order["bymonth"] < freqInt)) {for (var z = 0; z < rrule["bymonth"].length; z++) {if (z == 0) {for (var zz = 0; zz < set.length; zz++) {set[zz].setMonth(rrule["bymonth"][z] - 1);}} else {var subset = [];for (var zz = 0; zz < set.length; zz++) {var newDate = new Date(set[zz]);newDate.setMonth(rrule[z]);subset.push(newDate);}tmp = set.concat(subset);set = tmp;}}}if (rrule["byweekno"] && !rrule["bymonth"]) {dojo.debug("TODO: no support for byweekno yet");}if (rrule["byyearday"] && !rrule["bymonth"] && !rrule["byweekno"]) {if (rrule["byyearday"].length > 1) {var regex = "([+-]?)([0-9]{1,3})";for (var z = 1; x < rrule["byyearday"].length; z++) {var regexResult = rrule["byyearday"][z].match(regex);if (z == 1) {for (var zz = 0; zz < set.length; zz++) {if (regexResult[1] == "-") {dojo.date.setDayOfYear(set[zz], 366 - regexResult[2]);} else {dojo.date.setDayOfYear(set[zz], regexResult[2]);}}} else {var subset = [];for (var zz = 0; zz < set.length; zz++) {var newDate = new Date(set[zz]);if (regexResult[1] == "-") {dojo.date.setDayOfYear(newDate, 366 - regexResult[2]);} else {dojo.date.setDayOfYear(newDate, regexResult[2]);}subset.push(newDate);}tmp = set.concat(subset);set = tmp;}}}}if (rrule["bymonthday"] && (order["bymonthday"] < freqInt)) {if (rrule["bymonthday"].length > 0) {var regex = "([+-]?)([0-9]{1,3})";for (var z = 0; z < rrule["bymonthday"].length; z++) {var regexResult = rrule["bymonthday"][z].match(regex);if (z == 0) {for (var zz = 0; zz < set.length; zz++) {if (regexResult[1] == "-") {if (regexResult[2] < dojo.date.getDaysInMonth(set[zz])) {set[zz].setDate(dojo.date.getDaysInMonth(set[zz]) - regexResult[2]);}} else {if (regexResult[2] < dojo.date.getDaysInMonth(set[zz])) {set[zz].setDate(regexResult[2]);}}}} else {var subset = [];for (var zz = 0; zz < set.length; zz++) {var newDate = new Date(set[zz]);if (regexResult[1] == "-") {if (regexResult[2] < dojo.date.getDaysInMonth(set[zz])) {newDate.setDate(dojo.date.getDaysInMonth(set[zz]) - regexResult[2]);}} else {if (regexResult[2] < dojo.date.getDaysInMonth(set[zz])) {newDate.setDate(regexResult[2]);}}subset.push(newDate);}tmp = set.concat(subset);set = tmp;}}}}if (rrule["byday"] && (order["byday"] < freqInt)) {if (rrule["bymonth"]) {if (rrule["byday"].length > 0) {var regex = "([+-]?)([0-9]{0,1}?)([A-Za-z]{1,2})";for (var z = 0; z < rrule["byday"].length; z++) {var regexResult = rrule["byday"][z].match(regex);var occurance = regexResult[2];var day = regexResult[3].toLowerCase();if (z == 0) {for (var zz = 0; zz < set.length; zz++) {if (regexResult[1] == "-") {var numDaysFound = 0;var lastDayOfMonth = dojo.date.getDaysInMonth(set[zz]);var daysToSubtract = 1;set[zz].setDate(lastDayOfMonth);if (weekdays[set[zz].getDay()] == day) {numDaysFound++;daysToSubtract = 7;}daysToSubtract = 1;while (numDaysFound < occurance) {set[zz].setDate(set[zz].getDate() - daysToSubtract);if (weekdays[set[zz].getDay()] == day) {numDaysFound++;daysToSubtract = 7;}}} else {if (occurance) {var numDaysFound = 0;set[zz].setDate(1);var daysToAdd = 1;if (weekdays[set[zz].getDay()] == day) {numDaysFound++;daysToAdd = 7;}while (numDaysFound < occurance) {set[zz].setDate(set[zz].getDate() + daysToAdd);if (weekdays[set[zz].getDay()] == day) {numDaysFound++;daysToAdd = 7;}}} else {var numDaysFound = 0;var subset = [];lastDayOfMonth = new Date(set[zz]);var daysInMonth = dojo.date.getDaysInMonth(set[zz]);lastDayOfMonth.setDate(daysInMonth);set[zz].setDate(1);if (weekdays[set[zz].getDay()] == day) {numDaysFound++;}var tmpDate = new Date(set[zz]);daysToAdd = 1;while (tmpDate.getDate() < lastDayOfMonth) {if (weekdays[tmpDate.getDay()] == day) {numDaysFound++;if (numDaysFound == 1) {set[zz] = tmpDate;} else {subset.push(tmpDate);tmpDate = new Date(tmpDate);daysToAdd = 7;tmpDate.setDate(tmpDate.getDate() + daysToAdd);}} else {tmpDate.setDate(tmpDate.getDate() + daysToAdd);}}var t = set.concat(subset);set = t;}}}} else {var subset = [];for (var zz = 0; zz < set.length; zz++) {var newDate = new Date(set[zz]);if (regexResult[1] == "-") {if (regexResult[2] < dojo.date.getDaysInMonth(set[zz])) {newDate.setDate(dojo.date.getDaysInMonth(set[zz]) - regexResult[2]);}} else {if (regexResult[2] < dojo.date.getDaysInMonth(set[zz])) {newDate.setDate(regexResult[2]);}}subset.push(newDate);}tmp = set.concat(subset);set = tmp;}}}} else {dojo.debug("TODO: byday within a yearly rule without a bymonth");}}dojo.debug("TODO: Process BYrules for units larger than frequency");var tmp = recurranceSet.concat(set);recurranceSet = tmp;}}recurranceSet.push(dtstart);return recurranceSet;}, getDate:function () {return dojo.date.fromIso8601(this.dtstart.value);}});var VTimeZoneProperties = [_P("tzid", 1, true), _P("last-mod", 1), _P("tzurl", 1)];dojo.cal.iCalendar.VTimeZone = function (body) {this.name = "VTIMEZONE";this._ValidProperties = VTimeZoneProperties;dojo.cal.iCalendar.Component.call(this, body);};dojo.inherits(dojo.cal.iCalendar.VTimeZone, dojo.cal.iCalendar.Component);var VTodoProperties = [_P("class", 1), _P("completed", 1), _P("created", 1), _P("description", 1), _P("dtstart", 1), _P("geo", 1), _P("last-mod", 1), _P("location", 1), _P("organizer", 1), _P("percent", 1), _P("priority", 1), _P("dtstamp", 1), _P("seq", 1), _P("status", 1), _P("summary", 1), _P("uid", 1), _P("url", 1), _P("recurid", 1), [_P("due", 1), _P("duration", 1)], _P("attach"), _P("attendee"), _P("categories"), _P("comment"), _P("contact"), _P("exdate"), _P("exrule"), _P("rstatus"), _P("related"), _P("resources"), _P("rdate"), _P("rrule")];dojo.cal.iCalendar.VTodo = function (body) {this.name = "VTODO";this._ValidProperties = VTodoProperties;dojo.cal.iCalendar.Component.call(this, body);};dojo.inherits(dojo.cal.iCalendar.VTodo, dojo.cal.iCalendar.Component);var VJournalProperties = [_P("class", 1), _P("created", 1), _P("description", 1), _P("dtstart", 1), _P("last-mod", 1), _P("organizer", 1), _P("dtstamp", 1), _P("seq", 1), _P("status", 1), _P("summary", 1), _P("uid", 1), _P("url", 1), _P("recurid", 1), _P("attach"), _P("attendee"), _P("categories"), _P("comment"), _P("contact"), _P("exdate"), _P("exrule"), _P("related"), _P("rstatus"), _P("rdate"), _P("rrule")];dojo.cal.iCalendar.VJournal = function (body) {this.name = "VJOURNAL";this._ValidProperties = VJournalProperties;dojo.cal.iCalendar.Component.call(this, body);};dojo.inherits(dojo.cal.iCalendar.VJournal, dojo.cal.iCalendar.Component);var VFreeBusyProperties = [_P("contact"), _P("dtstart", 1), _P("dtend"), _P("duration"), _P("organizer", 1), _P("dtstamp", 1), _P("uid", 1), _P("url", 1), _P("attendee"), _P("comment"), _P("freebusy"), _P("rstatus")];dojo.cal.iCalendar.VFreeBusy = function (body) {this.name = "VFREEBUSY";this._ValidProperties = VFreeBusyProperties;dojo.cal.iCalendar.Component.call(this, body);};dojo.inherits(dojo.cal.iCalendar.VFreeBusy, dojo.cal.iCalendar.Component);var VAlarmProperties = [[_P("action", 1, true), _P("trigger", 1, true), [_P("duration", 1), _P("repeat", 1)], _P("attach", 1)], [_P("action", 1, true), _P("description", 1, true), _P("trigger", 1, true), [_P("duration", 1), _P("repeat", 1)]], [_P("action", 1, true), _P("description", 1, true), _P("trigger", 1, true), _P("summary", 1, true), _P("attendee", "*", true), [_P("duration", 1), _P("repeat", 1)], _P("attach", 1)], [_P("action", 1, true), _P("attach", 1, true), _P("trigger", 1, true), [_P("duration", 1), _P("repeat", 1)], _P("description", 1)]];dojo.cal.iCalendar.VAlarm = function (body) {this.name = "VALARM";this._ValidProperties = VAlarmProperties;dojo.cal.iCalendar.Component.call(this, body);};dojo.inherits(dojo.cal.iCalendar.VAlarm, dojo.cal.iCalendar.Component);