Fix bug 869407 - Part 1 - ical.js backend - Add JS wrapper objects. r=mmecca
This commit is contained in:
Родитель
ed7900f713
Коммит
ca768b125e
|
@ -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@&appABI=%APP_ABI%&appOS=%APP_OS%&locale=%APP_LOCALE%&appVersion=%APP_VERSION%&appID=%APP_ID%</em:updateURL>
|
||||
#endif
|
||||
|
|
Загрузка…
Ссылка в новой задаче