cssom-papandreou
Version:
CSS Object Model implementation and CSS parser
131 lines (116 loc) • 4.16 kB
JavaScript
//.CommonJS
var CSSOM = {
StyleSheet: require("./StyleSheet").StyleSheet,
CSSStyleRule: require("./CSSStyleRule").CSSStyleRule,
CSSRule: require("./CSSRule").CSSRule
};
///CommonJS
/**
* @constructor
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleSheet
*/
CSSOM.CSSStyleSheet = function CSSStyleSheet() {
CSSOM.StyleSheet.call(this);
this.cssRules = [];
};
CSSOM.CSSStyleSheet.prototype = new CSSOM.StyleSheet();
CSSOM.CSSStyleSheet.prototype.constructor = CSSOM.CSSStyleSheet;
/**
* Used to insert a new rule into the style sheet. The new rule now becomes part of the cascade.
*
* sheet = new Sheet("body {margin: 0}")
* sheet.toString()
* -> "body{margin:0;}"
* sheet.insertRule("img {border: none}", 0)
* -> 0
* sheet.toString()
* -> "img{border:none;}body{margin:0;}"
*
* @param {string} rule
* @param {number} index
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleSheet-insertRule
* @return {number} The index within the style sheet's rule collection of the newly inserted rule.
*/
CSSOM.CSSStyleSheet.prototype.insertRule = function(rule, index) {
if (index < 0 || index > this.cssRules.length) {
throw new RangeError("INDEX_SIZE_ERR");
}
var cssRule = CSSOM.parse(rule).cssRules[0];
cssRule.parentStyleSheet = this;
this.cssRules.splice(index, 0, cssRule);
return index;
};
/**
* Used to delete a rule from the style sheet.
*
* sheet = new Sheet("img{border:none} body{margin:0}")
* sheet.toString()
* -> "img{border:none;}body{margin:0;}"
* sheet.deleteRule(0)
* sheet.toString()
* -> "body{margin:0;}"
*
* @param {number} index within the style sheet's rule list of the rule to remove.
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleSheet-deleteRule
*/
CSSOM.CSSStyleSheet.prototype.deleteRule = function(index) {
if (index < 0 || index >= this.cssRules.length) {
throw new RangeError("INDEX_SIZE_ERR");
}
this.cssRules.splice(index, 1);
};
/**
* NON-STANDARD
* @return {string} serialize stylesheet
*/
CSSOM.CSSStyleSheet.prototype.toString = function() {
var result = "";
var rules = this.cssRules;
function serializeRuleBodyWithoutIsContinuation(cssRule) {
var isContinuation = cssRule.style.getPropertyValue('is-continuation');
result;
if (isContinuation) {
rules[i].style.removeProperty('is-continuation');
}
result = cssRule.style.cssText;
if (isContinuation) {
rules[i].style.setProperty('is-continuation', isContinuation);
}
return result;
}
for (var i=0; i<rules.length; i++) {
if (rules[i].type === CSSOM.CSSRule.STYLE_RULE) { // STYLE_RULE
result += rules[i].selectorText + " {";
if (rules[i].style) {
result += serializeRuleBodyWithoutIsContinuation(rules[i]);
}
while (i + 1 < rules.length && rules[i + 1].type === CSSOM.CSSRule.STYLE_RULE && rules[i + 1].selectorText === rules[i].selectorText && rules[i + 1].style && rules[i + 1].style.getPropertyValue('is-continuation') === 'yes') {
i += 1;
result += " " + serializeRuleBodyWithoutIsContinuation(rules[i]);
}
result += "}\n";
} else if (rules[i].type === CSSOM.CSSRule.FONT_FACE_RULE) {
result += "@font-face {";
if (rules[i].style) {
result += serializeRuleBodyWithoutIsContinuation(rules[i]);
}
var fontFamily = rules[i].style.getPropertyValue('font-family');
while (fontFamily && i + 1 < rules.length && rules[i + 1].type === CSSOM.CSSRule.FONT_FACE_RULE && rules[i + 1].style && rules[i + 1].style.getPropertyValue('is-continuation') === 'yes' && rules[i + 1].style.getPropertyValue('font-family') === fontFamily) {
i += 1;
if (rules[i].style) {
rules[i].style.removeProperty('font-family');
result += " " + serializeRuleBodyWithoutIsContinuation(rules[i]);
rules[i].style.setProperty('font-family', fontFamily);
}
}
result += "}\n";
} else {
result += rules[i].cssText + "\n";
}
}
return result;
};
//.CommonJS
exports.CSSStyleSheet = CSSOM.CSSStyleSheet;
CSSOM.parse = require('./parse').parse; // Cannot be included sooner due to the mutual dependency between parse.js and CSSStyleSheet.js
///CommonJS