Skip to content

Instantly share code, notes, and snippets.

@ssafejava
Forked from ydaniv/mozGetMatchedCSSRules.js
Last active November 6, 2022 06:24

Revisions

  1. ssafejava revised this gist Sep 18, 2013. 1 changed file with 10 additions and 4 deletions.
    14 changes: 10 additions & 4 deletions mozGetMatchedCSSRules.js
    Original file line number Diff line number Diff line change
    @@ -71,7 +71,7 @@ if ( typeof window.getMatchedCSSRules !== 'function' ) {
    var selectors = selector_text.split(','),
    selector, score, result = 0;
    while ( selector = selectors.shift() ) {
    if ( element.mozMatchesSelector(selector) ) {
    if ( _matchesSelector(element, selector) ) {
    score = calculateScore(selector);
    result = score > result ? score : result;
    }
    @@ -88,6 +88,13 @@ if ( typeof window.getMatchedCSSRules !== 'function' ) {
    return rules.sort(compareSpecificity);
    }

    // Find correct matchesSelector impl
    function matchesSelector (el, selector) {
    var matcher = el.matchesSelector || el.mozMatchesSelector ||
    el.webkitMatchesSelector || el.oMatchesSelector || el.msMatchesSelector;
    return matcher(selector);
    }

    //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*/) {
    @@ -118,10 +125,9 @@ if ( typeof window.getMatchedCSSRules !== 'function' ) {
    // and skip it
    continue
    }

    // check if this element matches this rule's selector
    var matches = element.matchesSelector || element.mozMatchesSelector ||
    element.webkitMatchesSelector || element.oMatchesSelector || element.msMatchesSelector;
    if ( matches(rule.selectorText) ) {
    if ( matchesSelector(element, rule.selectorText) ) {
    // push the rule to the results set
    result.push(rule);
    }
  2. ssafejava revised this gist Sep 18, 2013. 1 changed file with 3 additions and 2 deletions.
    5 changes: 3 additions & 2 deletions mozGetMatchedCSSRules.js
    Original file line number Diff line number Diff line change
    @@ -118,9 +118,10 @@ if ( typeof window.getMatchedCSSRules !== 'function' ) {
    // and skip it
    continue
    }
    //TODO: for now only polyfilling Gecko
    // check if this element matches this rule's selector
    if ( element.mozMatchesSelector(rule.selectorText) ) {
    var matches = element.matchesSelector || element.mozMatchesSelector ||
    element.webkitMatchesSelector || element.oMatchesSelector || element.msMatchesSelector;
    if ( matches(rule.selectorText) ) {
    // push the rule to the results set
    result.push(rule);
    }
  3. @ydaniv ydaniv revised this gist Nov 8, 2012. 1 changed file with 5 additions and 5 deletions.
    10 changes: 5 additions & 5 deletions mozGetMatchedCSSRules.js
    Original file line number Diff line number Diff line change
    @@ -39,27 +39,27 @@ if ( typeof window.getMatchedCSSRules !== 'function' ) {
    match = _find(part, PSEUDO_ELEMENTS_RE);
    score[2] = match;
    // and remove them
    match && part.replace(PSEUDO_ELEMENTS_RE, '');
    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.replace(PSEUDO_CLASSES_RE, '');
    match && (part = part.replace(PSEUDO_CLASSES_RE, ''));
    // find all attributes
    match = _find(part, ATTR_RE);
    score[1] += match;
    // and remove them
    match && part.replace(ATTR_RE, '');
    match && (part = part.replace(ATTR_RE, ''));
    // find all IDs
    match = _find(part, ID_RE);
    score[0] = match;
    // and remove them
    match && part.replace(ID_RE, '');
    match && (part = part.replace(ID_RE, ''));
    // find all classes
    match = _find(part, CLASS_RE);
    score[1] += match;
    // and remove them
    match && part.replace(CLASS_RE, '');
    match && (part = part.replace(CLASS_RE, ''));
    // find all elements
    score[2] += _find(part, ELEMENT_RE);
    }
  4. @ydaniv ydaniv revised this gist Sep 19, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion mozGetMatchedCSSRules.js
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    // polyfill window.getMatchedCSSRules()
    // polyfill window.getMatchedCSSRules() in FireFox 6+
    if ( typeof window.getMatchedCSSRules !== 'function' ) {
    var ELEMENT_RE = /[\w-]+/g,
    ID_RE = /#[\w-]+/g,
  5. @ydaniv ydaniv revised this gist Sep 19, 2012. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions mozGetMatchedCSSRules.js
    Original file line number Diff line number Diff line change
    @@ -18,7 +18,7 @@ if ( typeof window.getMatchedCSSRules !== 'function' ) {
    // 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 && ! global.matchMedia(sheet_media).matches ) return [];
    if ( sheet_media && sheet_media.length && ! window.matchMedia(sheet_media).matches ) return [];
    // get the style rules of this sheet
    return toArray(stylesheet.cssRules);
    }
    @@ -90,12 +90,12 @@ if ( typeof window.getMatchedCSSRules !== 'function' ) {

    //TODO: not supporting 2nd argument for selecting pseudo elements
    //TODO: not supporting 3rd argument for checking author style sheets only
    global.getMatchedCSSRules = function (element /*, pseudo, author_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(global.document.styleSheets);
    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
  6. @ydaniv ydaniv revised this gist Sep 19, 2012. 1 changed file with 123 additions and 36 deletions.
    159 changes: 123 additions & 36 deletions mozGetMatchedCSSRules.js
    Original file line number Diff line number Diff line change
    @@ -1,45 +1,132 @@
    // polyfill window.getMatchedCSSRules()
    if ( typeof window.getMatchedCSSRules !== 'function' ) {
    //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 = [].slice.call(document.styleSheets);

    while ( sheet = style_sheets.shift() ) {
    sheet_media = sheet.media.mediaText;
    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 ( sheet.disabled ) continue;
    if ( stylesheet.disabled ) return [];
    // if this sheet's media is specified and doesn't match the viewport then skip it
    if ( sheet_media.length && ! window.matchMedia(sheet_media).matches ) continue;
    if ( sheet_media && sheet_media.length && ! global.matchMedia(sheet_media).matches ) return [];
    // get the style rules of this sheet
    rules = [].slice.call(sheet.cssRules);
    // loop the rules
    while ( rule = rules.shift() ) {
    // if this is an @import rule
    if ( rule.stylesheet ) {
    // add imported stylesheet to the stylesheets array
    style_sheets.push(rule.stylesheet);
    // and skip this rule
    continue;
    }
    else if ( rule.media ) {
    // add this rule to the stylesheets array since it quacks like a stylesheet (has media & cssRules attibutes)
    style_sheets.push(rule);
    // 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);
    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.replace(PSEUDO_ELEMENTS_RE, '');
    // find all pseudo-classes
    match = _find(part, PSEUDO_CLASSES_RE);
    score[1] = match;
    // and remove them
    match && part.replace(PSEUDO_CLASSES_RE, '');
    // find all attributes
    match = _find(part, ATTR_RE);
    score[1] += match;
    // and remove them
    match && part.replace(ATTR_RE, '');
    // find all IDs
    match = _find(part, ID_RE);
    score[0] = match;
    // and remove them
    match && part.replace(ID_RE, '');
    // find all classes
    match = _find(part, CLASS_RE);
    score[1] += match;
    // and remove them
    match && 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);
    }
    return result;
    };

    //TODO: not supporting 2nd argument for selecting pseudo elements
    //TODO: not supporting 3rd argument for checking author style sheets only
    global.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(global.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);
    };
    }
  7. @ydaniv ydaniv revised this gist Jul 7, 2012. 1 changed file with 15 additions and 3 deletions.
    18 changes: 15 additions & 3 deletions mozGetMatchedCSSRules.js
    Original file line number Diff line number Diff line change
    @@ -13,13 +13,25 @@ if ( typeof window.getMatchedCSSRules !== 'function' ) {
    sheet_media = sheet.media.mediaText;
    // if this sheet is disabled skip it
    if ( sheet.disabled ) continue;
    // if this sheet's media is specified and is NOT all or screen then skip it
    if ( sheet_media.length &&
    ! (~ sheet_media.indexOf('screen') || ~ sheet_media.indexOf('all')) ) continue;
    // if this sheet's media is specified and doesn't match the viewport then skip it
    if ( sheet_media.length && ! window.matchMedia(sheet_media).matches ) continue;
    // get the style rules of this sheet
    rules = [].slice.call(sheet.cssRules);
    // loop the rules
    while ( rule = rules.shift() ) {
    // if this is an @import rule
    if ( rule.stylesheet ) {
    // add imported stylesheet to the stylesheets array
    style_sheets.push(rule.stylesheet);
    // and skip this rule
    continue;
    }
    else if ( rule.media ) {
    // add this rule to the stylesheets array since it quacks like a stylesheet (has media & cssRules attibutes)
    style_sheets.push(rule);
    // and skip it
    continue;
    }
    //TODO: for now only polyfilling Gecko
    // check if this element matches this rule's selector
    if ( element.mozMatchesSelector(rule.selectorText) ) {
  8. @ydaniv ydaniv revised this gist Jul 2, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion mozGetMatchedCSSRules.js
    Original file line number Diff line number Diff line change
    @@ -10,7 +10,7 @@ if ( typeof window.getMatchedCSSRules !== 'function' ) {
    style_sheets = [].slice.call(document.styleSheets);

    while ( sheet = style_sheets.shift() ) {
    sheet_media = sheet.media;
    sheet_media = sheet.media.mediaText;
    // if this sheet is disabled skip it
    if ( sheet.disabled ) continue;
    // if this sheet's media is specified and is NOT all or screen then skip it
  9. @ydaniv ydaniv revised this gist Jul 2, 2012. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions mozGetMatchedCSSRules.js
    Original file line number Diff line number Diff line change
    @@ -2,12 +2,12 @@
    if ( typeof window.getMatchedCSSRules !== 'function' ) {
    //TODO: not supporting 2nd argument for selecting pseudo elements
    //TODO: not supporting 3rd argument for checking author style sheets only
    global.getMatchedCSSRules = function (element /*, pseudo, author_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 = [].slice.call(window.document.styleSheets);
    style_sheets = [].slice.call(document.styleSheets);

    while ( sheet = style_sheets.shift() ) {
    sheet_media = sheet.media;
  10. @ydaniv ydaniv created this gist Jul 2, 2012.
    33 changes: 33 additions & 0 deletions mozGetMatchedCSSRules.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,33 @@
    // polyfill window.getMatchedCSSRules()
    if ( typeof window.getMatchedCSSRules !== 'function' ) {
    //TODO: not supporting 2nd argument for selecting pseudo elements
    //TODO: not supporting 3rd argument for checking author style sheets only
    global.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 = [].slice.call(window.document.styleSheets);

    while ( sheet = style_sheets.shift() ) {
    sheet_media = sheet.media;
    // if this sheet is disabled skip it
    if ( sheet.disabled ) continue;
    // if this sheet's media is specified and is NOT all or screen then skip it
    if ( sheet_media.length &&
    ! (~ sheet_media.indexOf('screen') || ~ sheet_media.indexOf('all')) ) continue;
    // get the style rules of this sheet
    rules = [].slice.call(sheet.cssRules);
    // loop the rules
    while ( rule = rules.shift() ) {
    //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);
    }
    }
    }
    return result;
    };
    }