diff options
author | James Lal <james@lightsofapollo.com> | 2012-07-06 08:13:15 -0700 |
---|---|---|
committer | James Lal <james@lightsofapollo.com> | 2012-07-06 08:13:15 -0700 |
commit | 20711f003e97a4a57d1e2838ba78a994c5faf6c0 (patch) | |
tree | b060e5de05a9ffefc2ec836469c087fffa99dcef /lib/caldav/ical.js | |
parent | c8e85fe1e0a1d2e15df580068244324ff536a23a (diff) | |
download | jsCalDAV-20711f003e97a4a57d1e2838ba78a994c5faf6c0.tar.gz |
webcals -> caldav rename (yes, back again)
Diffstat (limited to 'lib/caldav/ical.js')
-rw-r--r-- | lib/caldav/ical.js | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/lib/caldav/ical.js b/lib/caldav/ical.js new file mode 100644 index 0000000..a7da546 --- /dev/null +++ b/lib/caldav/ical.js @@ -0,0 +1,139 @@ +(function(module, ns) { + // Credit: Andreas Gal - I removed the callback / xhr logic + + // Iterate over all entries if x is an array, otherwise just call fn on x. + + /* Pattern for an individual entry: name:value */ + var ENTRY = /^([A-Za-z0-9-]+)((?:;[A-Za-z0-9-]+=(?:"[^"]+"|[^";:,]+)(?:,(?:"[^"]+"|[^";:,]+))*)*):(.*)$/; + + /* Pattern for an individual parameter: name=value[,value] */ + var PARAM = /;([A-Za-z0-9-]+)=((?:"[^"]+"|[^";:,]+)(?:,(?:"[^"]+"|[^";:,]+))*)/g; + + /* Pattern for an individual parameter value: value | "value" */ + var PARAM_VALUE = /,?("[^"]+"|[^";:,]+)/g; + + // Parse a calendar in iCal format. + function ParseICal(text) { + // Parse the text into an object graph + var lines = text.replace(/\r/g, '').split('\n'); + var tos = Object.create(null); + var stack = [tos]; + + // Parse parameters for an entry. Foramt: <param>=<pvalue>[;...] + function parseParams(params) { + var map = Object.create(null); + var param = PARAM.exec(params); + while (param) { + var values = []; + var value = PARAM_VALUE.exec(param[2]); + while (value) { + values.push(value[1].replace(/^"(.*)"$/, '$1')); + value = PARAM_VALUE.exec(param[2]); + } + map[param[1].toLowerCase()] = (values.length > 1 ? values : values[0]); + param = PARAM.exec(params); + } + return map; + } + + // Add a property to the current object. If a property with the same name + // already exists, turn it into an array. + function add(prop, value, params) { + if (params) + value = { parameters: parseParams(params), value: value }; + if (prop in tos) { + var previous = tos[prop]; + if (previous instanceof Array) { + previous.push(value); + return; + } + value = [previous, value]; + } + tos[prop] = value; + } + + for (var n = 0; n < lines.length; ++n) { + var line = lines[n]; + // check whether the line continues (next line stats with space or tab) + var nextLine; + while ((nextLine = lines[n+1]) && (nextLine[0] === ' ' || nextLine[0] === '\t')) { + line += nextLine.substr(1); + ++n; + continue; + } + // parse the entry, format is 'PROPERTY:VALUE' + var matches = ENTRY.exec(line); + + if (!matches) { + throw new Error('invalid format'); + } + + var prop = matches[1].toLowerCase(); + var params = matches[2]; + var value = matches[3]; + switch (prop) { + case 'begin': + var obj = Object.create(null); + add(value.toLowerCase(), obj); + stack.push(tos = obj); + break; + case 'end': + stack.pop(); + tos = stack[stack.length - 1]; + if (stack.length == 1) { + var cal = stack[0]; + if (typeof cal.vcalendar !== 'object' || cal.vcalendar instanceof Array) { + throw new Error('single vcalendar object expected'); + } + + return cal.vcalendar; + } + break; + default: + add(prop, value, params); + break; + } + } + throw new Error('unexpected end of file'); + } + + function Value(v) { + return (typeof v !== 'object') ? v : v.value; + } + + function Parameter(v, name) { + if (typeof v !== 'object') + return undefined; + return v.parameters[name]; + } + + // Parse a time specification. + function ParseDateTime(v) { + var dt = Value(v); + if (Parameter(v, 'VALUE') === 'DATE') { + // 20081202 + return new Date(dt.substr(0, 4), dt.substr(4, 2), dt.substr(6, 2)); + } + v = Value(v); + // 20120426T130000Z + var year = dt.substr(0, 4); + var month = dt.substr(4, 2) - 1; + var day = dt.substr(6, 2); + var hour = dt.substr(9, 2); + var min = dt.substr(11, 2); + var sec = dt.substr(13, 2); + if (dt[15] == 'Z') { + return new Date(Date.UTC(year, month, day, hour, min, sec)); + } + return new Date(year, month, day, hour, min, sec); + } + + module.exports = ParseICal; + +}.apply( + this, + (this.Caldav) ? + [Caldav('ical'), Caldav] : + [module, require('./caldav')] +)); + |