256 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			256 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 
								 | 
							
								/*********************************************************************
							 | 
						||
| 
								 | 
							
								 * This is a fork from the CSS Style Declaration part of
							 | 
						||
| 
								 | 
							
								 * https://github.com/NV/CSSOM
							 | 
						||
| 
								 | 
							
								 ********************************************************************/
							 | 
						||
| 
								 | 
							
								'use strict';
							 | 
						||
| 
								 | 
							
								var CSSOM = require('cssom');
							 | 
						||
| 
								 | 
							
								var allProperties = require('./allProperties');
							 | 
						||
| 
								 | 
							
								var allExtraProperties = require('./allExtraProperties');
							 | 
						||
| 
								 | 
							
								var implementedProperties = require('./implementedProperties');
							 | 
						||
| 
								 | 
							
								var { dashedToCamelCase } = require('./parsers');
							 | 
						||
| 
								 | 
							
								var getBasicPropertyDescriptor = require('./utils/getBasicPropertyDescriptor');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * @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 lowercaseName = name.toLowerCase();
							 | 
						||
| 
								 | 
							
								    if (!allProperties.has(lowercaseName) && !allExtraProperties.has(lowercaseName)) {
							 | 
						||
| 
								 | 
							
								      return;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    this[lowercaseName] = value;
							 | 
						||
| 
								 | 
							
								    this._importants[lowercaseName] = 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];
							 | 
						||
| 
								 | 
							
								    delete this._importants[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,
							 | 
						||
| 
								 | 
							
								  },
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								require('./properties')(CSSStyleDeclaration.prototype);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								allProperties.forEach(function(property) {
							 | 
						||
| 
								 | 
							
								  if (!implementedProperties.has(property)) {
							 | 
						||
| 
								 | 
							
								    var declaration = getBasicPropertyDescriptor(property);
							 | 
						||
| 
								 | 
							
								    Object.defineProperty(CSSStyleDeclaration.prototype, property, declaration);
							 | 
						||
| 
								 | 
							
								    Object.defineProperty(CSSStyleDeclaration.prototype, dashedToCamelCase(property), declaration);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								allExtraProperties.forEach(function(property) {
							 | 
						||
| 
								 | 
							
								  if (!implementedProperties.has(property)) {
							 | 
						||
| 
								 | 
							
								    var declaration = getBasicPropertyDescriptor(property);
							 | 
						||
| 
								 | 
							
								    Object.defineProperty(CSSStyleDeclaration.prototype, property, declaration);
							 | 
						||
| 
								 | 
							
								    Object.defineProperty(CSSStyleDeclaration.prototype, dashedToCamelCase(property), declaration);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								exports.CSSStyleDeclaration = CSSStyleDeclaration;
							 |