⌈⌋ ⎇ branch:  Bitrhythm


Artifact Content

Artifact d41167ae7edf5b9e061a8554d7b24f9b9394f0c1c966a2cf5e28071723878b4a:


'use strict';


// 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 matches ? matches.length : 0;
    }

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

      selector = '*';
      console.log(selector);
      console.log(matcher);
      var result = el.webkitMatchesSelector('*');
      //return matcher(selector);
      return result;
    }

    // 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
            part = part.replace(PSEUDO_ELEMENTS_RE, '');
            // find all pseudo-classes
            match = _find(part, PSEUDO_CLASSES_RE);
            score[1] += match;
            // and remove them
            part = part.replace(PSEUDO_CLASSES_RE, '');
            // find all attributes
            match = _find(part, ATTR_RE);
            score[1] += match;
            // and remove them
            part = part.replace(ATTR_RE, '');
            // find all IDs
            match = _find(part, ID_RE);
            score[0] += match;
            // and remove them
            part = part.replace(ID_RE, '');
            // find all classes
            match = _find(part, CLASS_RE);
            score[1] += match;
            // and remove them
            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;
        selector = selectors.shift();
        while (selector) {
          if (matchesSelector(element, selector)) {
              score = calculateScore(selector);
              result = score > result ? score : result;
          }
          selector = selectors.shift();
        }
        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
    var getCSSRules = function(element) {
         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
        sheet = style_sheets.shift();
        while (sheet) {
            // get the style rules of this sheet
            rules = getSheetRules(sheet);
            // loop the rules in order of appearance
            rule = rules.shift();
            while (rule) {
                // 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;
                }

                // check if this element matches this rule's selector
                if (matchesSelector(element, rule.selectorText)) {
                    // push the rule to the results set
                    result.push(rule);
                }
                rule = rules.shift();
            }
            sheet = style_sheets.shift();
        }
        // sort according to specificity
        return sortBySpecificity(element, result);
    };
//  }


exports.parseSize = function(element) {
  let rules = getCSSRules(element);
  console.log(rules);
};