-
-
Save ydaniv/3033012 to your computer and use it in GitHub Desktop.
| // polyfill window.getMatchedCSSRules() in FireFox 6+ | |
| if ( typeof window.getMatchedCSSRules !== 'function' ) { | |
| var ELEMENT_RE = /[\w-]+/g, | |
| ID_RE = /#[\w-]+/g, | |
| CLASS_RE = /\.[\w-]+/g, | |
| ATTR_RE = /\[[^\]]+\]/g, | |
| // :not() pseudo-class does not add to specificity, but its content does as if it was outside it | |
| PSEUDO_CLASSES_RE = /\:(?!not)[\w-]+(\(.*\))?/g, | |
| PSEUDO_ELEMENTS_RE = /\:\:?(after|before|first-letter|first-line|selection)/g; | |
| // convert an array-like object to array | |
| function toArray (list) { | |
| return [].slice.call(list); | |
| } | |
| // handles extraction of `cssRules` as an `Array` from a stylesheet or something that behaves the same | |
| function getSheetRules (stylesheet) { | |
| var sheet_media = stylesheet.media && stylesheet.media.mediaText; | |
| // if this sheet is disabled skip it | |
| if ( stylesheet.disabled ) return []; | |
| // if this sheet's media is specified and doesn't match the viewport then skip it | |
| if ( sheet_media && sheet_media.length && ! window.matchMedia(sheet_media).matches ) return []; | |
| // get the style rules of this sheet | |
| return toArray(stylesheet.cssRules); | |
| } | |
| function _find (string, re) { | |
| var matches = string.match(re); | |
| return re ? re.length : 0; | |
| } | |
| // calculates the specificity of a given `selector` | |
| function calculateScore (selector) { | |
| var score = [0,0,0], | |
| parts = selector.split(' '), | |
| part, match; | |
| //TODO: clean the ':not' part since the last ELEMENT_RE will pick it up | |
| while ( part = parts.shift(), typeof part == 'string' ) { | |
| // find all pseudo-elements | |
| match = _find(part, PSEUDO_ELEMENTS_RE); | |
| score[2] = match; | |
| // and remove them | |
| match && (part = part.replace(PSEUDO_ELEMENTS_RE, '')); | |
| // find all pseudo-classes | |
| match = _find(part, PSEUDO_CLASSES_RE); | |
| score[1] = match; | |
| // and remove them | |
| match && (part = part.replace(PSEUDO_CLASSES_RE, '')); | |
| // find all attributes | |
| match = _find(part, ATTR_RE); | |
| score[1] += match; | |
| // and remove them | |
| match && (part = part.replace(ATTR_RE, '')); | |
| // find all IDs | |
| match = _find(part, ID_RE); | |
| score[0] = match; | |
| // and remove them | |
| match && (part = part.replace(ID_RE, '')); | |
| // find all classes | |
| match = _find(part, CLASS_RE); | |
| score[1] += match; | |
| // and remove them | |
| match && (part = part.replace(CLASS_RE, '')); | |
| // find all elements | |
| score[2] += _find(part, ELEMENT_RE); | |
| } | |
| return parseInt(score.join(''), 10); | |
| } | |
| // returns the heights possible specificity score an element can get from a give rule's selectorText | |
| function getSpecificityScore (element, selector_text) { | |
| var selectors = selector_text.split(','), | |
| selector, score, result = 0; | |
| while ( selector = selectors.shift() ) { | |
| if ( element.mozMatchesSelector(selector) ) { | |
| score = calculateScore(selector); | |
| result = score > result ? score : result; | |
| } | |
| } | |
| return result; | |
| } | |
| function sortBySpecificity (element, rules) { | |
| // comparing function that sorts CSSStyleRules according to specificity of their `selectorText` | |
| function compareSpecificity (a, b) { | |
| return getSpecificityScore(element, b.selectorText) - getSpecificityScore(element, a.selectorText); | |
| } | |
| return rules.sort(compareSpecificity); | |
| } | |
| //TODO: not supporting 2nd argument for selecting pseudo elements | |
| //TODO: not supporting 3rd argument for checking author style sheets only | |
| window.getMatchedCSSRules = function (element /*, pseudo, author_only*/) { | |
| var style_sheets, sheet, sheet_media, | |
| rules, rule, | |
| result = []; | |
| // get stylesheets and convert to a regular Array | |
| style_sheets = toArray(window.document.styleSheets); | |
| // assuming the browser hands us stylesheets in order of appearance | |
| // we iterate them from the beginning to follow proper cascade order | |
| while ( sheet = style_sheets.shift() ) { | |
| // get the style rules of this sheet | |
| rules = getSheetRules(sheet); | |
| // loop the rules in order of appearance | |
| while ( rule = rules.shift() ) { | |
| // if this is an @import rule | |
| if ( rule.styleSheet ) { | |
| // insert the imported stylesheet's rules at the beginning of this stylesheet's rules | |
| rules = getSheetRules(rule.styleSheet).concat(rules); | |
| // and skip this rule | |
| continue; | |
| } | |
| // if there's no stylesheet attribute BUT there IS a media attribute it's a media rule | |
| else if ( rule.media ) { | |
| // insert the contained rules of this media rule to the beginning of this stylesheet's rules | |
| rules = getSheetRules(rule).concat(rules); | |
| // and skip it | |
| continue | |
| } | |
| //TODO: for now only polyfilling Gecko | |
| // check if this element matches this rule's selector | |
| if ( element.mozMatchesSelector(rule.selectorText) ) { | |
| // push the rule to the results set | |
| result.push(rule); | |
| } | |
| } | |
| } | |
| // sort according to specificity | |
| return sortBySpecificity(element, result); | |
| }; | |
| } |
Wow, I haven't been around here for quite some time! Too bad Github doesn't send notifications for Gists.
@bobef you're probably right, I'm open to suggestions.
@ragulka I never got it, can you confirm if this is still happening and what OS and version?
@Tomas-M well obviously, moz* stands for Mozilla, also see the title:
Gecko only polyfill ...
I'm getting the security error using Firefox 28.0 on Windows 8.1. I think it may be related to these questions:
http://stackoverflow.com/questions/5323604/firefox-not-able-to-enumerate-document-stylesheets-cssrules
http://stackoverflow.com/questions/3211536/accessing-cross-domain-stylesheet-with-cssrules
None of my stylesheets are from another domain though.
@flangefrog can you verify there's not @import from a different domain in your stylesheets?
This can work in IE9+ as well. Somebody already forked it and implemented it it looks like: https://gist.github.com/ssafejava/6605832
cool!
I guess the webkit part is redundant since this is a polyfill to a webkit feature.
I'm getting the same a security error as ragulka