Fix bug 869407 - Part 1 - ical.js backend - Add JS wrapper objects. r=mmecca

This commit is contained in:
Philipp Kewisch 2013-05-12 12:10:51 +02:00
Родитель ed7900f713
Коммит ca768b125e
11 изменённых файлов: 969 добавлений и 1 удалений

Просмотреть файл

@ -0,0 +1,47 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DEPTH = @DEPTH@
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
NO_COMPONENTS_MANIFEST = 1
EXTRA_COMPONENTS = calICALJSComponents.js
BACKEND_MANIFESTS = icaljs.manifest
DEFINES += -DXPIDL_MODULE=$(XPIDL_MODULE)
NO_JS_MANIFEST = 1
NO_INTERFACES_MANIFEST = 1
EXTRA_SCRIPTS = \
calDateTime.js \
calDuration.js \
calICSService-worker.js \
calICSService.js \
calPeriod.js \
calRecurrenceRule.js \
$(NULL)
# Use NSINSTALL to make the directory, as there's no mtime to preserve.
libs:: $(EXTRA_SCRIPTS)
if test ! -d $(FINAL_TARGET)/calendar-js; then $(NSINSTALL) -D $(FINAL_TARGET)/calendar-js; fi
$(INSTALL) $^ $(FINAL_TARGET)/calendar-js
libs:: $(BACKEND_MANIFESTS)
$(EXIT_ON_ERROR) \
$(NSINSTALL) -D $(FINAL_TARGET)/components; \
for i in $^; do \
fname=`basename $$i`; \
dest=$(FINAL_TARGET)/components/$${fname}; \
$(RM) -f $$dest; \
$(PYTHON) $(MOZILLA_SRCDIR)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) $$i > $$dest; \
done
# The install target must use SYSINSTALL, which is NSINSTALL in copy mode.
install:: $(EXTRA_SCRIPTS)
$(call install_cmd,$(IFLAGS1) $^ $(DESTDIR)$(mozappdir)/calendar-js)
include $(topsrcdir)/config/rules.mk

Просмотреть файл

@ -0,0 +1,123 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Components.utils.import("resource://calendar/modules/ical.js");
Components.utils.import("resource://calendar/modules/calUtils.jsm");
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
const UNIX_TIME_TO_PRTIME = 1000000;
function calDateTime(innerObject) {
this.wrappedJSObject = this;
this.innerObject = innerObject || ICAL.Time.epochTime.clone();
}
const calDateTimeInterfaces = [Components.interfaces.calIDateTime];
const calDateTimeClassID = Components.ID("{36783242-ec94-4d8a-9248-d2679edd55b9}");
calDateTime.prototype = {
QueryInterface: XPCOMUtils.generateQI(calDateTimeInterfaces),
classID: calDateTimeClassID,
classInfo: XPCOMUtils.generateCI({
contractID: "@mozilla.org/calendar/datetime;1",
classDescription: "Describes a Date/Time Object",
classID: calDateTimeClassID,
interfaces: calDateTimeInterfaces
}),
isMutable: true,
makeImmutable: function() this.isMutable = false,
clone: function() new calDateTime(this.innerObject.clone()),
isValid: true,
innerObject: null,
get nativeTime() this.innerObject.toUnixTime() * UNIX_TIME_TO_PRTIME,
set nativeTime(val) this.innerObject.fromUnixTime(val / UNIX_TIME_TO_PRTIME),
get year() this.innerObject.year,
set year(val) this.innerObject.year = val,
get month() this.innerObject.month - 1,
set month(val) this.innerObject.month = val + 1,
get day() this.innerObject.day,
set day(val) this.innerObject.day = val,
get hour() this.innerObject.hour,
set hour(val) this.innerObject.hour = val,
get minute() this.innerObject.minute,
set minute(val) this.innerObject.minute = val,
get second() this.innerObject.second,
set second(val) this.innerObject.second = val,
get timezone() new calICALJSTimezone(this.innerObject.zone),
set timezone(val) unwrapSetter(ICAL.Timezone, val, function(val) {
return this.innerObject.zone = val;
}, this),
resetTo: function (yr,mo,dy,hr,mi,sc,tz) {
this.innerObject.fromData({
year: yr, month: mo + 1, day: dy,
hour: hr, minute: mi, second: sc,
});
this.timezone = tz;
},
reset: function() this.innerObject.reset(),
get timezoneOffset() this.innerObject.utcOffset(),
get isDate() this.innerObject.isDate,
set isDate(val) this.innerObject.isDate = val,
get weekday() this.innerObject.dayOfWeek() - 1,
get yearday() this.innerObject.dayOfYear(),
toString: function() this.innerObject.toString(),
getInTimezone: unwrap(ICAL.Timezone, function(val) {
return new calDateTime(this.innerObject.convertToZone(val));
}),
addDuration: unwrap(ICAL.Duration, function(val) {
this.innerObject.addDuration(val);
}),
subtractDate: unwrap(ICAL.Time, function(val) {
return new calDuration(this.innerObject.subtractDate(val));
}),
compare: unwrap(ICAL.Time, function(val) {
if (this.innerObject.isDate != val.isDate) {
// Lightning expects 20120101 and 20120101T010101 to be equal
tz = (this.innerObject.isDate ? val.zone : this.innerObject.zone);
return this.innerObject.compareDateOnlyTz(val, tz);
} else {
// If both are dates or date-times, then just do the normal compare
return this.innerObject.compare(val);
}
}),
get startOfWeek() new calDateTime(this.innerObject.startOfWeek()),
get endOfWeek() new calDateTime(this.innerObject.endOfWeek()),
get startOfMonth() new calDateTime(this.innerObject.startOfMonth()),
get endOfMonth() new calDateTime(this.innerObject.endOfMonth()),
get startOfYear() new calDateTime(this.innerObject.startOfYear()),
get endOfYear() new calDateTime(this.innerObject.endOfYear()),
get icalString() this.innerObject.toICALString(),
set icalString(val) {
let jcalString;
if (val.length > 10) {
jcalString = ICAL.design.value["date-time"].fromICAL(val);
} else {
jcalString = ICAL.design.value.date.fromICAL(val);
}
this.innerObject = ICAL.Time.fromString(jcalString);
},
get jsDate() this.innerObject.toJSDate(),
set jsDate(val) this.innerObject.fromJSDate(val, true)
};

Просмотреть файл

@ -0,0 +1,67 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Components.utils.import("resource://calendar/modules/ical.js");
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
function calDuration(innerObject) {
this.innerObject = innerObject || new ICAL.Duration();
this.wrappedJSObject = this;
}
const calDurationInterfaces = [Components.interfaces.calIDuration];
const calDurationClassID = Components.ID("{7436f480-c6fc-4085-9655-330b1ee22288}");
calDuration.prototype = {
QueryInterface: XPCOMUtils.generateQI(calDurationInterfaces),
classID: calDurationClassID,
classInfo: XPCOMUtils.generateCI({
contractID: "@mozilla.org/calendar/duration;1",
classDescription: "Calendar Duration Object",
classID: calDurationClassID,
interfaces: calDurationInterfaces
}),
get icalDuration() this.innerObject,
set icalDuration(val) this.innerObject = val,
isMutable: true,
makeImmutable: function() this.isMutable = false,
clone: function() new calDuration(this.innerObject.clone()),
get isNegative() this.innerObject.isNegative,
set isNegative(val) this.innerObject.isNegative = val,
get weeks() this.innerObject.weeks,
set weeks(val) this.innerObject.weeks = val,
get days() this.innerObject.days,
set days(val) this.innerObject.days = val,
get hours() this.innerObject.hours,
set hours(val) this.innerObject.hours = val,
get minutes() this.innerObject.minutes,
set minutes(val) this.innerObject.minutes = val,
get seconds() this.innerObject.seconds,
set seconds(val) this.innerObject.seconds = val,
get inSeconds() this.innerObject.toSeconds(),
set inSeconds(val) this.innerObject.fromSeconds(val),
addDuration: unwrap(ICAL.Duration, function(val) {
this.innerObject.fromSeconds(this.innerObject.toSeconds() + val.toSeconds());
}),
compare: unwrap(ICAL.Duration, function(val) {
return this.innerObject.compare(val);
}),
reset: function() this.innerObject.reset(),
normalize: function() this.innerObject.normalize(),
toString: function() this.innerObject.toString(),
get icalString() this.innerObject.toString(),
set icalString(val) this.innerObject = ICAL.Duration.fromString(val)
};

Просмотреть файл

@ -0,0 +1,28 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Components.utils.import("resource://calendar/modules/calUtils.jsm");
const scriptLoadOrder = [
"calTimezone.js",
"calDateTime.js",
"calDuration.js",
"calICSService.js",
"calPeriod.js",
"calRecurrenceRule.js",
];
function getComponents() {
return [
calDateTime,
calDuration,
calIcalComponent,
calIcalProperty,
calICSService,
calPeriod,
calRecurrenceRule,
];
}
var NSGetFactory = cal.loadingNSGetFactory(scriptLoadOrder, getComponents, this);

Просмотреть файл

@ -0,0 +1,23 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* ChromeWorker for parseICSAsync method in calICSService.js
*/
const NS_OK = 0;
const NS_ERROR_FAILURE = 2147500037;
const ICS_ERROR_BASE = 2152333568;
importScripts("resource://calendar/modules/ical.js");
onmessage = function onmessage(event) {
try {
let comp = ICAL.parse(event.data);
postMessage({ rc: NS_OK, data: comp });
} catch (e) {
postMessage({ rc: NS_ERROR_FAILURE, data: "Exception occurred: " + e});
}
close();
}

Просмотреть файл

@ -0,0 +1,455 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Components.utils.import("resource://calendar/modules/ical.js");
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
Components.utils.import("resource://calendar/modules/calUtils.jsm");
function calIcalProperty(innerObject) {
this.innerObject = innerObject || new ICAL.Property();
this.wrappedJSObject = this;
}
const calIcalPropertyInterfaces = [Components.interfaces.calIIcalProperty];
const calIcalPropertyClassID = Components.ID("{423ac3f0-f612-48b3-953f-47f7f8fd705b}");
calIcalProperty.prototype = {
QueryInterface: XPCOMUtils.generateQI(calIcalPropertyInterfaces),
classID: calIcalPropertyClassID,
classInfo: XPCOMUtils.generateCI({
contractID: "@mozilla.org/calendar/ical-property;1",
classDescription: "Wrapper for a libical property",
classID: calIcalPropertyClassID,
interfaces: calIcalPropertyInterfaces
}),
get icalString() this.innerObject.toICAL() + ICAL.newLineChar,
get icalProperty() this.innerObject,
set icalProperty(val) this.innerObject = val,
get parent() this.innerObject.component,
toString: function() this.innerObject.toICAL(),
get value() {
let type = this.innerObject.type;
function stringifyValue(x) ICAL.stringify.value(x.toString(), type);
return this.innerObject.getValues().map(stringifyValue).join(",");
},
set value(val) {
var icalval = ICAL.parse._parseValue(val, this.innerObject.type);
this.innerObject.setValue(icalval);
return val;
},
get valueAsIcalString() this.value,
set valueAsIcalString(val) this.value = val,
get valueAsDatetime() {
let val = this.innerObject.getFirstValue();
return (val && val.icalclass == "icaltime" ? new calDateTime(val) : null);
},
set valueAsDatetime(val) unwrapSetter(ICAL.Time, val, function(val) {
this.innerObject.setValue(val);
}, this),
get propertyName() this.innerObject.name.toUpperCase(),
getParameter: function(name) {
// Unfortuantely getting the "VALUE" parameter won't work, since in
// jCal it has been translated to the value type id.
if (name == "VALUE") {
let propname = this.innerObject.name.toLowerCase();
if (propname in ICAL.design.property) {
let details = ICAL.design.property[propname];
if ('defaultType' in details &&
details.defaultType != this.innerObject.type) {
// Default type doesn't match object type, so we have a VALUE
// parameter
return this.innerObject.type.toUpperCase();
}
}
}
return this.innerObject.getParameter(name.toLowerCase());
},
setParameter: function(n, v) {
// Similar problems for setting the value parameter. Lightning code
// expects setting the value parameter to just change the value type
// and attempt to use the previous value as the new one. To do this in
// ICAL.js we need to save the value, reset the type and then try to
// set the value again.
if (n == "VALUE") {
let type = this.innerObject.type;
function stringifyValue(x) ICAL.stringify.value(x.toString(), type);
function reparseValue(x) ICAL.parse._parseValue(stringifyValue(x), v);
let oldValue;
let wasMultiValue = this.innerObject.isMultiValue;
if (wasMultiValue) {
oldValue = this.innerObject.getValues();
} else {
oldValue = [this.innerObject.getFirstValue()];
}
this.innerObject.resetType(v.toLowerCase());
try {
oldValue = oldValue.map(reparseValue);
} catch (e) {
// If there was an error reparsing the value, then just keep it
// empty.
oldValue = null;
}
if (oldValue) {
if (wasMultiValue && this.innerObject.isMultiValue) {
this.innerObject.setValues(oldValue);
} else if (oldValue) {
this.innerObject.setValue(oldValue.join(","));
}
}
} else {
this.innerObject.setParameter(n.toLowerCase(), v);
}
},
removeParameter: function(n) {
// Again, VALUE needs special handling. Removing the value parameter is
// kind of like resetting it to the default type. So find out the
// default type and then set the value parameter to it.
if (n == "VALUE") {
let propname = this.innerObject.name.toLowerCase();
if (propname in ICAL.design.property) {
let details = ICAL.design.property[propname];
if ('defaultType' in details) {
this.setParameter("VALUE", details.defaultType);
}
}
} else {
this.innerObject.removeParameter(n.toLowerCase());
}
},
clearXParameters: function() {
cal.WARN("calIICSService::clearXParameters is no longer implemented, " +
"please use removeParameter");
},
paramIterator: null,
getFirstParameterName: function() {
let innerObject = this.innerObject;
this.paramIterator = (function() {
let propname = innerObject.name.toLowerCase();
if (propname in ICAL.design.property) {
let details = ICAL.design.property[propname];
if ('defaultType' in details &&
details.defaultType != innerObject.type) {
// Default type doesn't match object type, so we have a VALUE
// parameter
yield "VALUE";
}
}
let paramNames = Object.keys(innerObject.jCal[1] || {});
for each (let name in paramNames) {
yield name.toUpperCase();
}
})();
return this.getNextParameterName();
},
getNextParameterName: function() {
if (this.paramIterator) {
try {
return this.paramIterator.next();
} catch (e if e instanceof StopIteration) {
this.paramIterator = null;
return null;
}
} else {
return this.getFirstParameterName();
}
}
};
function calIcalComponent(innerObject) {
this.innerObject = innerObject || new ICAL.Component();
this.wrappedJSObject = this;
}
const calIcalComponentInterfaces = [Components.interfaces.calIIcalComponent];
const calIcalComponentClassID = Components.ID("{51ac96fd-1279-4439-a85b-6947b37f4cea}");
calIcalComponent.prototype = {
QueryInterface: XPCOMUtils.generateQI(calIcalComponentInterfaces),
classID: calIcalComponentClassID,
classInfo: XPCOMUtils.generateCI({
contractID: "@mozilla.org/calendar/ical-component;1",
classDescription: "Wrapper for a icaljs component",
classID: calIcalComponentClassID,
interfaces: calIcalComponentInterfaces
}),
clone: function() new calIcalComponent(new ICAL.Component(this.innerObject.toJSON(), this.innerObject.component)),
get parent() wrapGetter(calIcalComponent, this.innerObject.parent),
get icalTimezone() this.innerObject.name == "vtimezone" ? this.innerObject : null,
get icalComponent() this.innerObject,
set icalComponent(val) this.innerObject = val,
componentIterator: null,
getFirstSubcomponent: function(kind) {
if (kind == "ANY") {
kind = null;
} else if (kind) {
kind = kind.toLowerCase();
}
let innerObject = this.innerObject;
this.componentIterator = (function() {
let comps = innerObject.getAllSubcomponents(kind);
for each (let comp in comps) {
yield new calIcalComponent(comp);
}
})();
return this.getNextSubcomponent(kind)
},
getNextSubcomponent: function(kind) {
if (this.componentIterator) {
try {
return this.componentIterator.next();
} catch (e if e instanceof StopIteration) {
this.componentIterator = null;
return null;
}
} else {
return this.getFirstSubcomponent(kind);
}
},
get componentType() this.innerObject.name.toUpperCase(),
get uid() this.innerObject.getFirstPropertyValue("uid"),
set uid(val) this.innerObject.updatePropertyWithValue("uid", val),
get prodid() this.innerObject.getFirstPropertyValue("prodid"),
set prodid(val) this.innerObject.updatePropertyWithValue("prodid", val),
get version() this.innerObject.getFirstPropertyValue("version"),
set version(val) this.innerObject.updatePropertyWithValue("version", val),
get method() this.innerObject.getFirstPropertyValue("method"),
set method(val) this.innerObject.updatePropertyWithValue("method", val),
get status() this.innerObject.getFirstPropertyValue("status"),
set status(val) this.innerObject.updatePropertyWithValue("status", val),
get summary() this.innerObject.getFirstPropertyValue("summary"),
set summary(val) this.innerObject.updatePropertyWithValue("summary", val),
get description() this.innerObject.getFirstPropertyValue("description"),
set description(val) this.innerObject.updatePropertyWithValue("description", val),
get location() this.innerObject.getFirstPropertyValue("location"),
set location(val) this.innerObject.updatePropertyWithValue("location", val),
get categories() this.innerObject.getFirstPropertyValue("categories"),
set categories(val) this.innerObject.updatePropertyWithValue("categories", val),
get URL() this.innerObject.getFirstPropertyValue("url"),
set URL(val) this.innerObject.updatePropertyWithValue("url", val),
get priority() {
// If there is no value for this integer property, then we must return
// the designated INVALID_VALUE.
const INVALID_VALUE = Components.interfaces.calIIcalComponent.INVALID_VALUE;
let prop = this.innerObject.getFirstProperty("priority");
let val = prop ? prop.getFirstValue() : null;
return (val === null ? INVALID_VALUE : val);
},
set priority(val) this.innerObject.updatePropertyWithValue("priority", val),
get startTime() wrapGetter(calDateTime, this.innerObject.getFirstPropertyValue("dtstart")),
set startTime(val) unwrapSetter(ICAL.Time, val, function(val) {
this.innerObject.updatePropertyWithValue("dtstart", val);
}, this),
get endTime() wrapGetter(calDateTime, this.innerObject.getFirstPropertyValue("dtend")),
set endTime(val) unwrapSetter(ICAL.Time, val, function(val) {
this.innerObject.updatePropertyWithValue("dtend", val);
}, this),
get duration() wrapGetter(calDuration, this.innerObject.getFirstPropertyValue("duration")),
get dueTime() wrapGetter(calDateTime, this.innerObject.getFirstPropertyValue("due")),
set dueTime(val) unwrapSetter(ICAL.Time, val, function(val) {
this.innerObject.updatePropertyWithValue("due", val);
}, this),
get stampTime() wrapGetter(calDateTime, this.innerObject.getFirstPropertyValue("dtstamp")),
set stampTime(val) unwrapSetter(ICAL.Time, val, function(val) {
this.innerObject.updatePropertyWithValue("dtstamp", val);
}, this),
get createdTime() wrapGetter(calDateTime, this.innerObject.getFirstPropertyValue("created")),
set createdTime(val) unwrapSetter(ICAL.Time, val, function(val) {
this.innerObject.updatePropertyWithValue("created", val);
}, this),
get completedTime() wrapGetter(calDateTime, this.innerObject.getFirstPropertyValue("completed")),
set completedTime(val) unwrapSetter(ICAL.Time, val, function(val) {
this.innerObject.updatePropertyWithValue("completed", val);
}, this),
get lastModified() wrapGetter(calDateTime, this.innerObject.getFirstPropertyValue("last-modified")),
set lastModified(val) unwrapSetter(ICAL.Time, val, function(val) {
this.innerObject.updatePropertyWithValue("last-modified", val);
}, this),
get recurrenceId() wrapGetter(calDateTime, this.innerObject.getFirstPropertyValue("recurrence-id")),
set recurrenceId(val) unwrapSetter(ICAL.Time, val, function(val) {
this.innerObject.updatePropertyWithValue("recurrence-id", val);
}, this),
serializeToICS: function() this.innerObject.toString() + ICAL.newLineChar,
toString: function() this.innerObject.toString(),
addSubcomponent: unwrap(ICAL.Component, function(comp) {
this.innerObject.addSubcomponent(comp);
}),
propertyIterator: null,
getFirstProperty: function getFirstProperty(kind) {
if (kind == "ANY") {
kind = null;
} else if (kind) {
kind = kind.toLowerCase();
}
let innerObject = this.innerObject;
this.propertyIterator = (function() {
let props = innerObject.getAllProperties(kind);
for each (var prop in props) {
let hell = prop.getValues();
if (hell.length > 1) {
// Uh oh, multiple property values. Our code expects each as one
// property. I hate API incompatibility!
for each (var devil in hell) {
var thisprop = new ICAL.Property(prop.toJSON(),
prop.component);
thisprop.removeAllValues();
thisprop.setValue(devil);
yield new calIcalProperty(thisprop);
}
} else {
yield new calIcalProperty(prop);
}
}
})();
return this.getNextProperty(kind);
},
getNextProperty: function getNextProperty(kind) {
if (this.propertyIterator) {
try {
return this.propertyIterator.next();
} catch (e if e instanceof StopIteration) {
this.propertyIterator = null;
return null;
}
} else {
return this.getFirstProperty(kind);
}
},
addProperty: unwrap(ICAL.Property, function(prop) this.innerObject.addProperty(prop)),
addTimezoneReference: function(tz) {
// This doesn't quite fit in with ical.js at the moment. ical.js should
// be able to figure this out internally.
},
getReferencedTimezones: function(aCount) {
// This doesn't quite fit in with ical.js at the moment. ical.js should
// be able to figure this out internally.
},
serializeToICSStream: function() {
let sstream = Components.classes["@mozilla.org/io/string-input-stream;1"]
.createInstance(Components.interfaces.nsIStringInputStream);
let data = this.innerObject.toString();
sstream.setData(data, data.length);
return sstream;
}
};
function calICSService() {
this.wrappedJSObject = this;
}
const calICSServiceInterfaces = [Components.interfaces.calIICSService];
const calICSServiceClassID = Components.ID("{c61cb903-4408-41b3-bc22-da0b27efdfe1}");
calICSService.prototype = {
QueryInterface: XPCOMUtils.generateQI(calICSServiceInterfaces),
classID: calICSServiceClassID,
classInfo: XPCOMUtils.generateCI({
contractID: "@mozilla.org/calendar/ics-service;1",
classDescription: "ICS component and property service",
classID: calICSServiceClassID,
interfaces: [Components.interfaces.calIICSService]
}),
parseICS: function parseICS(serialized, tzProvider) {
// TODO ical.js doesn't support tz providers, but this is usually null
// or our timezone service anyway.
let comp = ICAL.parse(serialized);
return new calIcalComponent(new ICAL.Component(comp[1]));
},
parseICSAsync: function parseICSAsync(serialized, tzProvider, listener) {
// There are way too many error checking messages here, but I had so
// much pain with this method that I don't want it to break again.
try {
let worker = new ChromeWorker("resource://calendar/calendar-js/calICSService-worker.js");
worker.onmessage = function(event) {
let rc = Components.results.NS_ERROR_FAILURE;
let icalComp = null;
try {
rc = event.data.rc;
icalComp = new calIcalComponent(new ICAL.Component(event.data.data[1]));
if (!Components.isSuccessCode(rc)) {
cal.ERROR("[calICSService] Error in parser worker: " + data);
}
} catch (e) {
cal.ERROR("[calICSService] Exception parsing item: " + e);
}
listener.onParsingComplete(rc, icalComp);
};
worker.onerror = function(event) {
cal.ERROR("[calICSService] Error in parser worker: " + event.message);
listener.onParsingComplete(Components.results.NS_ERROR_FAILURE, null);
};
worker.postMessage(serialized);
} catch (e) {
// If an error occurs above, the calling code will hang. Catch the exception just in case
cal.ERROR("[calICSService] Error starting parsing worker: " + e);
listener.onParsingComplete(Components.results.NS_ERROR_FAILURE, null);
}
},
createIcalComponent: function createIcalComponent(kind) {
return new calIcalComponent(new ICAL.Component(kind.toLowerCase()));
},
createIcalProperty: function createIcalProperty(kind) {
return new calIcalProperty(new ICAL.Property(kind.toLowerCase()));
},
createIcalPropertyFromString: function(str) {
if (!str.endsWith(ICAL.newLineChar)) {
str += ICAL.newLineChar;
}
let data = ICAL.parse("BEGIN:VCALENDAR\r\n" + str + "END:VCALENDAR");
let comp = new ICAL.Component(data[1]);
return new calIcalProperty(comp.getFirstProperty());
}
};

Просмотреть файл

@ -0,0 +1,57 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Components.utils.import("resource://calendar/modules/ical.js");
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
function calPeriod(innerObject) {
this.innerObject = innerObject || new ICAL.Period({});
this.wrappedJSObject = this;
}
const calPeriodInterfaces = [Components.interfaces.calIPeriod];
const calPeriodClassID = Components.ID("{394a281f-7299-45f7-8b1f-cce21258972f}");
calPeriod.prototype = {
QueryInterface: XPCOMUtils.generateQI(calPeriodInterfaces),
classID: calPeriodClassID,
classInfo: XPCOMUtils.generateCI({
contractID: "@mozilla.org/calendar/period;1",
classDescription: "A period between two dates",
classID: calPeriodClassID,
interfaces: calPeriodInterfaces
}),
isMutable: true,
innerObject: null,
get icalPeriod() this.innerObject,
set icalPeriod(val) this.innerObject = val,
makeImmutable: function() this.isMutable = false,
clone: function() new calPeriod(ICAL.Period.fromData(this.innerObject)),
get start() wrapGetter(calDateTime, this.innerObject.start),
set start(val) unwrapSetter(ICAL.Time, val, function(val) {
this.innerObject.start = val;
}, this),
get end() wrapGetter(calDateTime, this.innerObject.getEnd()),
set end(val) unwrapSetter(ICAL.Time, val, function(val) {
if (this.innerObject.duration) {
this.innerObject.duration = null;
}
this.innerObject.end = val;
}, this),
get duration() wrapGetter(calDuration, this.innerObject.getDuration()),
get icalString() this.innerObject.toICALString(),
set icalString(val) {
let str = ICAL.parse._parseValue(val, "period");
this.innerObject = ICAL.Period.fromString(str);
return val;
},
toString: function() this.innerObject.toString()
};

Просмотреть файл

@ -0,0 +1,149 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Components.utils.import("resource://calendar/modules/ical.js");
Components.utils.import("resource://calendar/modules/calUtils.jsm");
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
function calRecurrenceRule(innerObject) {
this.innerObject = innerObject || new ICAL.Recur();
this.wrappedJSObject = this;
}
const calRecurrenceRuleInterfaces = [Components.interfaces.calIRecurrenceRule];
const calRecurrenceRuleClassID = Components.ID("{df19281a-5389-4146-b941-798cb93a7f0d}");
calRecurrenceRule.prototype = {
QueryInterface: XPCOMUtils.generateQI(calRecurrenceRuleInterfaces),
classID: calRecurrenceRuleClassID,
classInfo: XPCOMUtils.generateCI({
contractID: "@mozilla.org/calendar/recurrence-rule;1",
classDescription: "Calendar Recurrence Rule",
classID: calRecurrenceRuleClassID,
interfaces: calRecurrenceRuleInterfaces
}),
innerObject: null,
isMutable: true,
makeImmutable: function() this.isMutable = false,
clone: function() new calRecurrenceRule(new ICAL.Recur(this.innerObject)),
isNegative: false, // We don't support EXRULE anymore
get isFinite() this.innerObject.isFinite(),
getNextOccurrence: function(aStartTime, aRecId) {
aStartTime = unwrapSingle(ICAL.Time, aStartTime);
aRecId = unwrapSingle(ICAL.Time, aRecId);
return wrapGetter(calDateTime, this.innerObject.getNextOccurrence(aStartTime, aRecId));
},
getOccurrences: function(aStartTime, aRangeStart, aRangeEnd, aMaxCount, aCount) {
aStartTime = unwrapSingle(ICAL.Time, aStartTime);
aRangeStart = unwrapSingle(ICAL.Time, aRangeStart);
aRangeEnd = unwrapSingle(ICAL.Time, aRangeEnd);
if (!aMaxCount && !aRangeEnd && this.count == 0 && this.until == null) {
throw Components.results.NS_ERROR_INVALID_ARG;
}
let occurrences = [];
let rangeStart = aRangeStart.clone();
rangeStart.isDate = false;
let dtend = null;
if (aRangeEnd) {
dtend = aRangeEnd.clone();
dtend.isDate = false;
// If the start of the recurrence is past the end, we have no dates
if (aStartTime.compare(dtend) >= 0) {
aCount.value = 0;
return [];
}
}
let iter = this.innerObject.iterator(aStartTime);
for (let next = iter.next(); next ; next = iter.next()) {
let dtNext = next.clone();
dtNext.isDate = false;
if (dtNext.compare(rangeStart) < 0) {
continue;
}
if (dtend && dtNext.compare(dtend) >= 0) {
break;
}
next = next.clone();
if (aStartTime.zone) {
next.zone = aStartTime.zone;
}
occurrences.push(new calDateTime(next));
if (aMaxCount && aMaxCount >= occurrences.length) {
break;
}
}
aCount.value = occurrences.length;
return occurrences;
},
get icalString() "RRULE:" + this.innerObject.toString() + ICAL.newLineChar,
set icalString(val) this.innerObject = ICAL.Recur.fromString(val.replace(/^RRULE:/i, "")),
get icalProperty() {
let prop = new ICAL.Property("rrule");
prop.setValue(this.innerObject);
return new calIcalProperty(prop);
},
set icalProperty(val) unwrapSetter(ICAL.Property, val, function(val) {
this.innerObject = val.getFirstValue();
}, this),
get type() this.innerObject.freq,
set type(val) this.innerObject.freq = val,
get interval() this.innerObject.interval,
set interval(val) this.innerObject.interval = val,
get count() {
if (!this.isByCount) {
throw Components.results.NS_ERROR_FAILURE;
}
return this.innerObject.count || -1;
},
set count(val) this.innerObject.count = (val && val > 0 ? val : null),
get untilDate() {
if (this.innerObject.until) {
return new calDateTime(this.innerObject.until);
} else {
return null;
}
},
set untilDate(val) unwrapSetter(ICAL.Time, val, function(val) {
this.innerObject.until = val;
}, this),
get isByCount() this.innerObject.isByCount(),
get weekStart() this.innerObject.wkst - 1,
set weekStart(val) this.innerObject.wkst = val + 1,
getComponent: function(aType, aCount) {
return this.innerObject.getComponent(aType, aCount)
.map(ICAL.Recur.icalDayToNumericDay);
},
setComponent: function(aType, aCount, aValues) {
let values = aValues.map(ICAL.Recur.numericDayToIcalDay);
this.innerObject.setComponent(aType, values);
}
};

Просмотреть файл

@ -0,0 +1,19 @@
component {36783242-ec94-4d8a-9248-d2679edd55b9} calICALJSComponents.js
contract @mozilla.org/calendar/datetime;1 {36783242-ec94-4d8a-9248-d2679edd55b9}
component {7436f480-c6fc-4085-9655-330b1ee22288} calICALJSComponents.js
contract @mozilla.org/calendar/duration;1 {7436f480-c6fc-4085-9655-330b1ee22288}
component {c61cb903-4408-41b3-bc22-da0b27efdfe1} calICALJSComponents.js
contract @mozilla.org/calendar/ics-service;1 {c61cb903-4408-41b3-bc22-da0b27efdfe1}
component {394a281f-7299-45f7-8b1f-cce21258972f} calICALJSComponents.js
contract @mozilla.org/calendar/period;1 {394a281f-7299-45f7-8b1f-cce21258972f}
component {df19281a-5389-4146-b941-798cb93a7f0d} calICALJSComponents.js
contract @mozilla.org/calendar/recurrence-rule;1 {df19281a-5389-4146-b941-798cb93a7f0d}
component {6702eb17-a968-4b43-b562-0d0c5f8e9eb5} calICALJSComponents.js
contract @mozilla.org/calendar/timezone;1 {6702eb17-a968-4b43-b562-0d0c5f8e9eb5}
#expand interfaces __XPIDL_MODULE__.xpt

Просмотреть файл

@ -5,4 +5,5 @@
DIRS = [
'libical',
'icaljs'
]

Просмотреть файл

@ -46,7 +46,6 @@
#endif
<em:iconURL>chrome://calendar/skin/cal-icon32.png</em:iconURL>
<em:optionsURL>chrome://messenger/content/preferences/preferences.xul</em:optionsURL>
<em:targetPlatform>@TARGET_PLATFORM@</em:targetPlatform>
#ifdef LIGHTNING_UPDATE_LOCATION
<em:updateURL>@LIGHTNING_UPDATE_LOCATION@?buildID=@GRE_BUILDID@&amp;appABI=%APP_ABI%&amp;appOS=%APP_OS%&amp;locale=%APP_LOCALE%&amp;appVersion=%APP_VERSION%&amp;appID=%APP_ID%</em:updateURL>
#endif