/********************************************************************* * This is a fork from the CSS Style Declaration part of * https://github.com/NV/CSSOM ********************************************************************/ "use strict"; var CSSOM = require('cssom'); var fs = require('fs'); var path = require('path'); var camelToDashed = require('./parsers').camelToDashed; var dashedToCamelCase = require('./parsers').dashedToCamelCase; /** * @constructor * @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleDeclaration */ var CSSStyleDeclaration = function CSSStyleDeclaration(onChangeCallback) { this._values = {}; this._importants = {}; this._length = 0; this._onChange = onChangeCallback || function () { return; }; }; CSSStyleDeclaration.prototype = { constructor: CSSStyleDeclaration, /** * * @param {string} name * @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleDeclaration-getPropertyValue * @return {string} the value of the property if it has been explicitly set for this declaration block. * Returns the empty string if the property has not been set. */ getPropertyValue: function (name) { if (!this._values.hasOwnProperty(name)) { return ""; } return this._values[name].toString(); }, /** * * @param {string} name * @param {string} value * @param {string} [priority=null] "important" or null * @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleDeclaration-setProperty */ setProperty: function (name, value, priority) { if (value === undefined) { return; } if (value === null || value === '') { this.removeProperty(name); return; } var camel_case = dashedToCamelCase(name); this[camel_case] = value; this._importants[name] = priority; }, _setProperty: function (name, value, priority) { if (value === undefined) { return; } if (value === null || value === '') { this.removeProperty(name); return; } if (this._values[name]) { // Property already exist. Overwrite it. var index = Array.prototype.indexOf.call(this, name); if (index < 0) { this[this._length] = name; this._length++; } } else { // New property. this[this._length] = name; this._length++; } this._values[name] = value; this._importants[name] = priority; this._onChange(this.cssText); }, /** * * @param {string} name * @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleDeclaration-removeProperty * @return {string} the value of the property if it has been explicitly set for this declaration block. * Returns the empty string if the property has not been set or the property name does not correspond to a known CSS property. */ removeProperty: function (name) { if (!this._values.hasOwnProperty(name)) { return ""; } var prevValue = this._values[name]; delete this._values[name]; var index = Array.prototype.indexOf.call(this, name); if (index < 0) { return prevValue; } // That's what WebKit and Opera do Array.prototype.splice.call(this, index, 1); // That's what Firefox does //this[index] = "" this._onChange(this.cssText); return prevValue; }, /** * * @param {String} name */ getPropertyPriority: function (name) { return this._importants[name] || ""; }, getPropertyCSSValue: function () { //FIXME return; }, /** * element.style.overflow = "auto" * element.style.getPropertyShorthand("overflow-x") * -> "overflow" */ getPropertyShorthand: function () { //FIXME return; }, isPropertyImplicit: function () { //FIXME return; }, /** * http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleDeclaration-item */ item: function (index) { index = parseInt(index, 10); if (index < 0 || index >= this._length) { return ''; } return this[index]; } }; Object.defineProperties(CSSStyleDeclaration.prototype, { cssText: { get: function () { var properties = []; var i; var name; var value; var priority; for (i = 0; i < this._length; i++) { name = this[i]; value = this.getPropertyValue(name); priority = this.getPropertyPriority(name); if (priority !== '') { priority = " !" + priority; } properties.push([name, ': ', value, priority, ';'].join('')); } return properties.join(' '); }, set: function (value) { var i; this._values = {}; Array.prototype.splice.call(this, 0, this._length); this._importants = {}; var dummyRule; try { dummyRule = CSSOM.parse('#bogus{' + value + '}').cssRules[0].style; } catch (err) { // malformed css, just return return; } var rule_length = dummyRule.length; var name; for (i = 0; i < rule_length; ++i) { name = dummyRule[i]; this.setProperty(dummyRule[i], dummyRule.getPropertyValue(name), dummyRule.getPropertyPriority(name)); } this._onChange(this.cssText); }, enumerable: true, configurable: true }, parentRule: { get: function () { return null; }, enumerable: true, configurable: true }, length: { get: function () { return this._length; }, /** * This deletes indices if the new length is less then the current * length. If the new length is more, it does nothing, the new indices * will be undefined until set. **/ set: function (value) { var i; for (i = value; i < this._length; i++) { delete this[i]; } this._length = value; }, enumerable: true, configurable: true }, 'float': { get: function () { return this.cssFloat; }, set: function (value) { this.cssFloat = value; }, enumerable: true, configurable: true } }); require('./properties')(CSSStyleDeclaration.prototype); exports.CSSStyleDeclaration = CSSStyleDeclaration;