ical.js-one.com
Version:
[](http://travis-ci.org/mozilla-comm/ical.js)
299 lines (257 loc) • 6.99 kB
JavaScript
ICAL.Property = (function() {
'use strict';
var NAME_INDEX = 0;
var PROP_INDEX = 1;
var TYPE_INDEX = 2;
var VALUE_INDEX = 3;
var design = ICAL.design;
/**
* Provides a nicer interface to any kind of property.
* Its important to note that mutations done in the wrapper
* directly effect (mutate) the jCal object used to initialize.
*
* Can also be used to create new properties by passing
* the name of the property (as a String).
*
*
* @param {Array|String} jCal raw jCal representation OR
* the new name of the property (when creating).
*
* @param {ICAL.Component} [parent] parent component.
*/
function Property(jCal, parent) {
if (typeof(jCal) === 'string') {
// because we a creating by name we need
// to find the type when creating the property.
var name = jCal;
if (name in design.property) {
var prop = design.property[name];
if ('defaultType' in prop) {
var type = prop.defaultType;
} else {
var type = design.defaultType;
}
} else {
var type = design.defaultType;
}
jCal = [name, {}, type];
}
this.jCal = jCal;
this.parent = parent || null;
this._updateType();
}
Property.prototype = {
get type() {
return this.jCal[TYPE_INDEX];
},
get name() {
return this.jCal[NAME_INDEX];
},
_updateType: function() {
if (this.type in design.value) {
var designType = design.value[this.type];
if ('decorate' in design.value[this.type]) {
this.isDecorated = true;
} else {
this.isDecorated = false;
}
if (this.name in design.property) {
if ('multiValue' in design.property[this.name]) {
this.isMultiValue = true;
} else {
this.isMultiValue = false;
}
}
}
},
/**
* Hydrate a single value.
*/
_hydrateValue: function(index) {
if (this._values && this._values[index]) {
return this._values[index];
}
// for the case where there is no value.
if (this.jCal.length <= (VALUE_INDEX + index)) {
return null;
}
if (this.isDecorated) {
if (!this._values) {
this._values = [];
}
return this._values[index] = this._decorate(
this.jCal[VALUE_INDEX + index]
);
} else {
return this.jCal[VALUE_INDEX + index];
}
},
_decorate: function(value) {
return design.value[this.type].decorate(value, this);
},
_undecorate: function(value) {
return design.value[this.type].undecorate(value, this);
},
_setDecoratedValue: function(value, index) {
if (!this._values) {
this._values = [];
}
if (typeof(value) === 'object' && 'icaltype' in value) {
// decorated value
this.jCal[VALUE_INDEX + index] = this._undecorate(value);
this._values[index] = value;
} else {
// undecorated value
this.jCal[VALUE_INDEX + index] = value;
this._values[index] = this._decorate(value);
}
},
/**
* Gets a param on the property.
*
* @param {String} name prop name (lowercase).
* @return {String} prop value.
*/
getParameter: function(name) {
return this.jCal[PROP_INDEX][name];
},
/**
* Sets a param on the property.
*
* @param {String} value property value.
*/
setParameter: function(name, value) {
this.jCal[PROP_INDEX][name] = value;
},
/**
* Removes a parameter
*
* @param {String} name prop name (lowercase).
*/
removeParameter: function(name) {
return delete this.jCal[PROP_INDEX][name];
},
/**
* Get the default type based on this property's name.
*
* @return {String} the default type for this property.
*/
getDefaultType: function() {
var name = this.name
if (name in design.property) {
var details = design.property[name];
if ('defaultType' in details) {
return details.defaultType;
}
}
return null;
},
/**
* Sets type of property and clears out any
* existing values of the current type.
*
* @param {String} type new iCAL type (see design.values).
*/
resetType: function(type) {
this.removeAllValues();
this.jCal[TYPE_INDEX] = type;
this._updateType();
},
/**
* Finds first property value.
*
* @return {String} first property value.
*/
getFirstValue: function() {
return this._hydrateValue(0);
},
/**
* Gets all values on the property.
*
* NOTE: this creates an array during each call.
*
* @return {Array} list of values.
*/
getValues: function() {
var len = this.jCal.length - VALUE_INDEX;
if (len < 1) {
// its possible for a property to have no value.
return [];
}
var i = 0;
var result = [];
for (; i < len; i++) {
result[i] = this._hydrateValue(i);
}
return result;
},
removeAllValues: function() {
if (this._values) {
this._values.length = 0;
}
this.jCal.length = 3;
},
/**
* Sets the values of the property.
* Will overwrite the existing values.
*
* @param {Array} values an array of values.
*/
setValues: function(values) {
if (!this.isMultiValue) {
throw new Error(
this.name + ': does not not support mulitValue.\n' +
'override isMultiValue'
);
}
var len = values.length;
var i = 0;
this.removeAllValues();
if (len > 0 &&
typeof(values[0]) === 'object' &&
'icaltype' in values[0]) {
this.resetType(values[0].icaltype);
}
if (this.isDecorated) {
for (; i < len; i++) {
this._setDecoratedValue(values[i], i);
}
} else {
for (; i < len; i++) {
this.jCal[VALUE_INDEX + i] = values[i];
}
}
},
/**
* Sets the current value of the property. If this is a multi-value
* property, all other values will be removed.
*
* @param {String|Object} value new prop value.
*/
setValue: function(value) {
this.removeAllValues();
if (typeof(value) === 'object' && 'icaltype' in value) {
this.resetType(value.icaltype);
}
if (this.isDecorated) {
this._setDecoratedValue(value, 0);
} else {
this.jCal[VALUE_INDEX] = value;
}
},
/**
* Returns the jCal representation of this property.
*
* @return {Object} jCal.
*/
toJSON: function() {
return this.jCal;
},
toICAL: function() {
return ICAL.stringify.property(
this.jCal
);
}
};
return Property;
}());