diff --git a/src/parser.js b/src/parser.js index 7c184580..46c671f3 100644 --- a/src/parser.js +++ b/src/parser.js @@ -342,28 +342,67 @@ * @private */ function getGlobalStylesForElement(element) { - var nodeName = element.nodeName, - className = element.getAttribute('class'), - id = element.getAttribute('id'), - styles = { }; - + var styles = { }; + for (var rule in fabric.cssRules) { - var ruleMatchesElement = (className && new RegExp('^\\.' + className).test(rule)) || - (id && new RegExp('^#' + id).test(rule)) || - (new RegExp('^' + nodeName).test(rule)); - - if (ruleMatchesElement) { + if (elementMatchesRule(element, rule.split(' '))) { for (var property in fabric.cssRules[rule]) { - var attr = normalizeAttr(property), - value = normalizeValue(attr, fabric.cssRules[rule][property]); - styles[attr] = value; + styles[property] = fabric.cssRules[rule][property]; } } } - return styles; } + /** + * @private + */ + function elementMatchesRule(element, selectors) { + var firstMatching, parentMatching = true; + //start from rightmost selector. + firstMatching = selectorMatches(element, selectors.pop()); + if (firstMatching && selectors.length) { + parentMatching = doesSomeParentMatch(element, selectors); + } + return firstMatching && parentMatching && (selectors.length === 0); + } + + function doesSomeParentMatch(element, selectors) { + var selector, parentMatching = true; + while (element.parentNode && element.parentNode.nodeType === 1 && selectors.length) { + if (parentMatching) { + selector = selectors.pop(); + } + element = element.parentNode; + parentMatching = selectorMatches(element, selector); + } + return selectors.length === 0; + } + /** + * @private + */ + function selectorMatches(element, selector) { + var nodeName = element.nodeName, + classNames = element.getAttribute('class'), + id = element.getAttribute('id'), matcher; + // i check if a selector matches slicing away part from it. + // if i get empty string i should match + matcher = new RegExp('^' + nodeName, 'i'); + selector = selector.replace(matcher, ''); + if (id && selector.length) { + matcher = new RegExp('#' + id + '(?![a-zA-Z\\-]+)', 'i'); + selector = selector.replace(matcher, ''); + } + if (classNames && selector.length) { + classNames = classNames.split(' '); + for (var i = classNames.length; i--;) { + matcher = new RegExp('\\.' + classNames[i] + '(?![a-zA-Z\\-]+)', 'i'); + selector = selector.replace(matcher, ''); + } + } + return selector.length === 0; + } + /** * @private */ @@ -753,8 +792,7 @@ */ getCSSRules: function(doc) { var styles = doc.getElementsByTagName('style'), - allRules = { }, - rules; + allRules = { }, rules; // very crude parsing of style contents for (var i = 0, len = styles.length; i < len; i++) { @@ -767,25 +805,23 @@ rules = rules.map(function(rule) { return rule.trim(); }); rules.forEach(function(rule) { - var match = rule.match(/([\s\S]*?)\s*\{([^}]*)\}/); - rule = match[1]; - var declaration = match[2].trim(), - propertyValuePairs = declaration.replace(/;$/, '').split(/\s*;\s*/); - if (!allRules[rule]) { - allRules[rule] = { }; - } + var match = rule.match(/([\s\S]*?)\s*\{([^}]*)\}/), + ruleObj = { }, declaration = match[2].trim(), + propertyValuePairs = declaration.replace(/;$/, '').split(/\s*;\s*/); for (var i = 0, len = propertyValuePairs.length; i < len; i++) { var pair = propertyValuePairs[i].split(/\s*:\s*/), - property = pair[0], - value = pair[1]; - - allRules[rule][property] = value; + property = normalizeAttr(pair[0]), + value = normalizeValue(property,pair[1],pair[0]); + ruleObj[property] = value; } + rule = match[1]; + rule.split(',').forEach(function(_rule) { + allRules[_rule.trim()] = fabric.util.object.clone(ruleObj); + }); }); } - return allRules; },