/* 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/.
* Portions Copyright (C) Philipp Kewisch */
import ICALParse from "./parse.js";
import Component from "./component.js";
import Event from "./event.js";
import Timezone from "./timezone.js";
/**
* The ComponentParser is used to process a String or jCal Object,
* firing callbacks for various found components, as well as completion.
*
* @example
* var options = {
* // when false no events will be emitted for type
* parseEvent: true,
* parseTimezone: true
* };
*
* var parser = new ICAL.ComponentParser(options);
*
* parser.onevent(eventComponent) {
* //...
* }
*
* // ontimezone, etc...
*
* parser.oncomplete = function() {
*
* };
*
* parser.process(stringOrComponent);
*
* @memberof ICAL
*/
class ComponentParser {
/**
* Creates a new ICAL.ComponentParser instance.
*
* @param {Object=} options Component parser options
* @param {Boolean} options.parseEvent Whether events should be parsed
* @param {Boolean} options.parseTimezeone Whether timezones should be parsed
*/
constructor(options) {
if (typeof(options) === 'undefined') {
options = {};
}
for (let [key, value] of Object.entries(options)) {
this[key] = value;
}
}
/**
* When true, parse events
*
* @type {Boolean}
*/
parseEvent = true;
/**
* When true, parse timezones
*
* @type {Boolean}
*/
parseTimezone = true;
/* SAX like events here for reference */
/**
* Fired when parsing is complete
* @callback
*/
oncomplete = /* c8 ignore next */ function() {};
/**
* Fired if an error occurs during parsing.
*
* @callback
* @param {Error} err details of error
*/
onerror = /* c8 ignore next */ function(err) {};
/**
* Fired when a top level component (VTIMEZONE) is found
*
* @callback
* @param {Timezone} component Timezone object
*/
ontimezone = /* c8 ignore next */ function(component) {};
/**
* Fired when a top level component (VEVENT) is found.
*
* @callback
* @param {Event} component Top level component
*/
onevent = /* c8 ignore next */ function(component) {};
/**
* Process a string or parse ical object. This function itself will return
* nothing but will start the parsing process.
*
* Events must be registered prior to calling this method.
*
* @param {Component|String|Object} ical The component to process,
* either in its final form, as a jCal Object, or string representation
*/
process(ical) {
//TODO: this is sync now in the future we will have a incremental parser.
if (typeof(ical) === 'string') {
ical = ICALParse(ical);
}
if (!(ical instanceof Component)) {
ical = new Component(ical);
}
let components = ical.getAllSubcomponents();
let i = 0;
let len = components.length;
let component;
for (; i < len; i++) {
component = components[i];
switch (component.name) {
case 'vtimezone':
if (this.parseTimezone) {
let tzid = component.getFirstPropertyValue('tzid');
if (tzid) {
this.ontimezone(new Timezone({
tzid: tzid,
component: component
}));
}
}
break;
case 'vevent':
if (this.parseEvent) {
this.onevent(new Event(component));
}
break;
default:
continue;
}
}
//XXX: ideally we should do a "nextTick" here
// so in all cases this is actually async.
this.oncomplete();
}
}
export default ComponentParser;