aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Lal <james@lightsofapollo.com>2012-06-27 16:58:05 +0200
committerJames Lal <james@lightsofapollo.com>2012-06-27 16:58:05 +0200
commit5e731c14d9fca4e99ac73f020d69008431ef4f81 (patch)
tree297270d9a71a242ae368f2e4303fbcb63a50ed23
parent24932d09294ab7a80b9c00ff505bc2823f1a65d1 (diff)
downloadjsCalDAV-5e731c14d9fca4e99ac73f020d69008431ef4f81.tar.gz
working calendar queries
-rw-r--r--lib/webcals/ical.js (renamed from lib/webcals/ics.js)43
-rw-r--r--lib/webcals/request/calendar_query.js23
-rw-r--r--lib/webcals/sax/dav_response.js21
-rw-r--r--lib/webcals/templates/calendar_data.js6
-rw-r--r--lib/webcals/templates/calendar_filter.js4
-rw-r--r--samples/xml/propget.xml3
-rw-r--r--samples/xml/req_calendar_query.xml15
-rw-r--r--test/webcals/ical_test.js (renamed from test/webcals/ics_test.js)2
-rw-r--r--test/webcals/request/calendar_query_test.js23
-rw-r--r--test/webcals/request/propfind_test.js2
-rw-r--r--test/webcals/sax/dav_response_test.js2
-rw-r--r--test/webcals/templates/calendar_data_test.js9
-rw-r--r--test/webcals/templates/calendar_filter_test.js8
13 files changed, 114 insertions, 47 deletions
diff --git a/lib/webcals/ics.js b/lib/webcals/ical.js
index 91f549b..45cef83 100644
--- a/lib/webcals/ics.js
+++ b/lib/webcals/ical.js
@@ -1,29 +1,21 @@
-/**
-@namespace
-*/
(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.
- function ForAll(x, fn) {
- if (!(x instanceof Array)) {
- fn(x);
- return;
- }
- for (var n = 0; n < x.length; ++n)
- fn(x[n]);
- }
/* 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, success, error) {
+ function ParseICal(text) {
// Parse the text into an object graph
- var lines = text.replace('\r', '').split('\n');
+ var lines = text.replace(/\r/g, '').split('\n');
var tos = Object.create(null);
var stack = [tos];
@@ -64,15 +56,18 @@
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')) {
+ 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)
- return error('invalid format');
+
+ if (!matches) {
+ throw new Error('invalid format');
+ }
+
var prop = matches[1].toLowerCase();
var params = matches[2];
var value = matches[3];
@@ -87,9 +82,11 @@
tos = stack[stack.length - 1];
if (stack.length == 1) {
var cal = stack[0];
- if (typeof cal.vcalendar != 'object' || cal.vcalendar instanceof Array)
- return error('single vcalendar object expected');
- return success(cal.vcalendar);
+ if (typeof cal.vcalendar !== 'object' || cal.vcalendar instanceof Array) {
+ throw new Error('single vcalendar object expected');
+ }
+
+ return cal.vcalendar;
}
break;
default:
@@ -97,7 +94,7 @@
break;
}
}
- return error('unexpected end of file');
+ throw new Error('unexpected end of file');
}
function Value(v) {
@@ -113,7 +110,7 @@
// Parse a time specification.
function ParseDateTime(v) {
var dt = Value(v);
- if (Parameter(v, 'VALUE') == 'DATE') {
+ if (Parameter(v, 'VALUE') === 'DATE') {
// 20081202
return new Date(dt.substr(0, 4), dt.substr(4, 2), dt.substr(6, 2));
}
@@ -125,8 +122,9 @@
var hour = dt.substr(9, 2);
var min = dt.substr(11, 2);
var sec = dt.substr(13, 2);
- if (dt[15] == 'Z')
+ if (dt[15] == 'Z') {
return new Date(Date.UTC(year, month, day, hour, min, sec));
+ }
return new Date(year, month, day, hour, min, sec);
}
@@ -138,3 +136,4 @@
[Webcals('ics'), Webcals] :
[module, require('./webcals')]
));
+
diff --git a/lib/webcals/request/calendar_query.js b/lib/webcals/request/calendar_query.js
index b39853f..b9a350d 100644
--- a/lib/webcals/request/calendar_query.js
+++ b/lib/webcals/request/calendar_query.js
@@ -2,6 +2,7 @@
var Propfind = ns.require('request/propfind');
var CalendarData = ns.require('templates/calendar_data');
+ var CalendarFilter = ns.require('templates/calendar_filter');
/**
* Creates a calendar query request.
@@ -17,16 +18,30 @@
this.xhr.headers['Depth'] = this.depth || 1;
this.xhr.method = 'REPORT';
this.fields = new CalendarData();
- this.template.rootTag = 'calendar-query';
+ this.filters = new CalendarFilter();
+
+ this.template.rootTag = ['caldav', 'calendar-query'];
}
CalendarQuery.prototype = {
__proto__: Propfind.prototype,
_createPayload: function() {
- var props = this._props.join('');
- props += this.fields.render(this.template);
- var content = this.template.tag('prop', props);
+ var content;
+ var props;
+
+ props = this._props.join('');
+
+ if (this.fields) {
+ props += this.fields.render(this.template);
+ }
+
+ content = this.template.tag('prop', props);
+
+ if (this.filters) {
+ content += this.filters.render(this.template);
+ }
+
return this.template.render(content);
}
diff --git a/lib/webcals/sax/dav_response.js b/lib/webcals/sax/dav_response.js
index 638951e..26d3453 100644
--- a/lib/webcals/sax/dav_response.js
+++ b/lib/webcals/sax/dav_response.js
@@ -3,6 +3,7 @@
var HTTP_STATUS = /([0-9]{3,3})/;
var Base = ns.require('sax/base');
+ var ParseICal = ns.require('ical');
var TextHandler = Base.create({
name: 'text',
@@ -21,6 +22,24 @@
}
});
+ var CalendarDataHandler = Base.create({
+ name: 'calendar data',
+
+ //don't add text only elements
+ //to the stack as objects
+ onopentag: null,
+ onclosetag: null,
+
+ //add the value to the parent
+ //value where key is local tag name
+ //and value is the text.
+ ontext: function(data) {
+ var handler = this.handler;
+ this.current[this.currentTag[handler.tagField]] = ParseICal(data);
+ }
+ });
+
+
var HrefHandler = Base.create({
name: 'href',
@@ -108,6 +127,7 @@
'DAV:/status': HttpStatusHandler,
'DAV:/resourcetype': ArrayHandler,
'DAV:/principal-URL': HrefHandler,
+ 'urn:ietf:params:xml:ns:caldav/calendar-data': CalendarDataHandler,
'DAV:/value': TextHandler,
'urn:ietf:params:xml:ns:caldav/calendar-home-set': HrefHandler,
'urn:ietf:params:xml:ns:caldav/calendar-user-address-set': HrefHandler
@@ -186,4 +206,3 @@
[Webcals('sax/dav_response'), Webcals] :
[module, require('../webcals')]
));
-
diff --git a/lib/webcals/templates/calendar_data.js b/lib/webcals/templates/calendar_data.js
index a0c0938..a652303 100644
--- a/lib/webcals/templates/calendar_data.js
+++ b/lib/webcals/templates/calendar_data.js
@@ -1,6 +1,7 @@
(function(module, ns) {
function CalendarData() {
+ this._hasItems = false;
this.struct = {};
}
@@ -18,6 +19,7 @@
*/
select: function(type, list) {
var struct = this.struct;
+ this._hasItems = true;
if (!(type in struct)) {
struct[type] = [];
@@ -76,6 +78,10 @@
* @return {String} <calendardata /> xml output.
*/
render: function(template) {
+ if (!this._hasItems) {
+ return template.tag(['caldav', this.rootName]);
+ }
+
var struct = this.struct;
var output = template.tag(
['caldav', this.rootName],
diff --git a/lib/webcals/templates/calendar_filter.js b/lib/webcals/templates/calendar_filter.js
index 15cfc8c..05bd742 100644
--- a/lib/webcals/templates/calendar_filter.js
+++ b/lib/webcals/templates/calendar_filter.js
@@ -10,7 +10,7 @@
__proto__: CalendarData.prototype,
- filter: CalendarData.prototype.select,
+ add: CalendarData.prototype.select,
compName: 'comp-filter',
rootName: 'filter'
@@ -21,7 +21,7 @@
}.apply(
this,
(this.Webcals) ?
- [Webcals('templates/calendar_data'), Webcals] :
+ [Webcals('templates/calendar_filter'), Webcals] :
[module, require('../webcals')]
));
diff --git a/samples/xml/propget.xml b/samples/xml/propget.xml
index c8487b2..2db1aa2 100644
--- a/samples/xml/propget.xml
+++ b/samples/xml/propget.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<D:multistatus xmlns:D="DAV:">
+<D:multistatus xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:response>
@@ -40,5 +40,4 @@
</D:propstat>
</D:response>
-
</D:multistatus>
diff --git a/samples/xml/req_calendar_query.xml b/samples/xml/req_calendar_query.xml
new file mode 100644
index 0000000..e983706
--- /dev/null
+++ b/samples/xml/req_calendar_query.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<C:calendar-query xmlns:D="DAV:"
+ xmlns:C="urn:ietf:params:xml:ns:caldav">
+ <D:prop>
+ <D:getetag />
+ </D:prop>
+ <C:filter>
+ <C:comp-filter name="VCALENDAR">
+ <C:comp-filter name="VEVENT">
+ <C:time-range start="20120626T125608Z"
+ end="20120926T125608Z"/>
+ </C:comp-filter>
+ </C:comp-filter>
+ </C:filter>
+</C:calendar-query>
diff --git a/test/webcals/ics_test.js b/test/webcals/ical_test.js
index af1192e..ed9af4a 100644
--- a/test/webcals/ics_test.js
+++ b/test/webcals/ical_test.js
@@ -1,5 +1,5 @@
var fs = require('fs'),
- ics = requireLib('ics'),
+ ics = requireLib('ical'),
data = fs.readFileSync(__dirname + '/../../data/test.data', 'utf8');
suite('webcals/ics', function() {
diff --git a/test/webcals/request/calendar_query_test.js b/test/webcals/request/calendar_query_test.js
index f960e15..b1a167d 100644
--- a/test/webcals/request/calendar_query_test.js
+++ b/test/webcals/request/calendar_query_test.js
@@ -2,11 +2,12 @@ requireRequest();
requireLib('request/propfind');
requireLib('request/calendar_query');
-suite('webcals/request/propfind', function() {
+suite('webcals/request/calendar_query', function() {
var Propfind,
- CalendarData,
FakeXhr,
+ CalendarData,
CalendarQuery,
+ CalendarFilter,
Xhr,
Template,
oldXhrClass,
@@ -18,6 +19,7 @@ suite('webcals/request/propfind', function() {
suiteSetup(function() {
Propfind = Webcals.require('request/propfind');
CalendarData = Webcals.require('templates/calendar_data');
+ CalendarFilter = Webcals.require('templates/calendar_filter');
CalendarQuery = Webcals.require('request/calendar_query');
SaxResponse = Webcals.require('sax/dav_response');
FakeXhr = Webcals.require('support/fake_xhr');
@@ -44,13 +46,15 @@ suite('webcals/request/propfind', function() {
assert.equal(subject.xhr.method, 'REPORT');
assert.instanceOf(subject.fields, CalendarData);
+ assert.instanceOf(subject.filters, CalendarFilter);
});
test('#_createPayload', function() {
subject.prop('getetag');
subject.fields.select('VEVENT', ['NAME']);
+ subject.filters.add('VEVENT', true);
- var tags = [
+ var props = [
'<N0:getetag />',
'<N1:calendar-data>',
'<N1:comp name="VCALENDAR">',
@@ -61,12 +65,19 @@ suite('webcals/request/propfind', function() {
'</N1:calendar-data>'
].join('');
+ var filter = [
+ '<N1:comp-filter name="VCALENDAR">',
+ '<N1:comp-filter name="VEVENT" />',
+ '</N1:comp-filter>'
+ ].join('');
+
var expected = [
subject.template.doctype,
- '<N0:calendar-query xmlns:N0="DAV:" ',
+ '<N1:calendar-query xmlns:N0="DAV:" ',
'xmlns:N1="urn:ietf:params:xml:ns:caldav">',
- '<N0:prop>', tags, '</N0:prop>',
- '</N0:calendar-query>'
+ '<N0:prop>', props, '</N0:prop>',
+ '<N1:filter>', filter, '</N1:filter>',
+ '</N1:calendar-query>'
].join('');
assert.equal(subject._createPayload(), expected);
diff --git a/test/webcals/request/propfind_test.js b/test/webcals/request/propfind_test.js
index 6d2dbe7..1f152b0 100644
--- a/test/webcals/request/propfind_test.js
+++ b/test/webcals/request/propfind_test.js
@@ -72,8 +72,6 @@ suite('webcals/request/propfind', function() {
var result = subject._createPayload();
- console.log(result);
-
assert.equal(subject._createPayload(), expected);
});
diff --git a/test/webcals/sax/dav_response_test.js b/test/webcals/sax/dav_response_test.js
index 1279b84..f91fcef 100644
--- a/test/webcals/sax/dav_response_test.js
+++ b/test/webcals/sax/dav_response_test.js
@@ -1,6 +1,7 @@
requireLib('sax');
requireLib('sax/base');
requireLib('sax/dav_response');
+requireLib('ical');
suite('webcals/sax/dav_response', function() {
@@ -61,6 +62,7 @@ suite('webcals/sax/dav_response', function() {
value: {}
}
}
+
};
test('output', function(done) {
diff --git a/test/webcals/templates/calendar_data_test.js b/test/webcals/templates/calendar_data_test.js
index 5223f18..1828b39 100644
--- a/test/webcals/templates/calendar_data_test.js
+++ b/test/webcals/templates/calendar_data_test.js
@@ -52,11 +52,16 @@ suite('webcals/templates/calendar_data', function() {
'</N0:calendar-data>'
].join('');
- setup(function() {
- select();
+ test('without items', function() {
+ var output = subject.render(template);
+ assert.equal(
+ output,
+ '<N0:calendar-data />'
+ );
});
test('output', function() {
+ select();
var output = subject.render(template);
assert.equal(output, expected);
});
diff --git a/test/webcals/templates/calendar_filter_test.js b/test/webcals/templates/calendar_filter_test.js
index 517e78a..d79883b 100644
--- a/test/webcals/templates/calendar_filter_test.js
+++ b/test/webcals/templates/calendar_filter_test.js
@@ -1,7 +1,8 @@
requireRequest();
requireLib('templates/calendar_data');
+requireLib('templates/calendar_filter');
-suite('webcals/templates/calendar_data', function() {
+suite('webcals/templates/calendar_filter', function() {
var CalendarFilter;
var Template;
@@ -9,7 +10,7 @@ suite('webcals/templates/calendar_data', function() {
var template;
function filter() {
- subject.filter('VEVENT', true);
+ subject.add('VEVENT', true);
}
suiteSetup(function() {
@@ -44,9 +45,6 @@ suite('webcals/templates/calendar_data', function() {
test('output', function() {
var output = subject.render(template);
- console.log();
- console.log(output)
- console.log();
assert.equal(output, expected);
});
});