1package inliner 2 3import ( 4 "fmt" 5 "regexp" 6 "strings" 7 8 "github.com/aymerick/douceur/css" 9) 10 11const ( 12 inlineFakeSelector = "*INLINE*" 13 14 // Regular expressions borrowed from premailer: 15 // https://github.com/premailer/css_parser/blob/master/lib/css_parser/regexps.rb 16 nonIDAttributesAndPseudoClassesRegexpConst = `(?i)(\.[\w]+)|\[(\w+)|(\:(link|visited|active|hover|focus|lang|target|enabled|disabled|checked|indeterminate|root|nth-child|nth-last-child|nth-of-type|nth-last-of-type|first-child|last-child|first-of-type|last-of-type|only-child|only-of-type|empty|contains))` 17 elementsAndPseudoElementsRegexpConst = `(?i)((^|[\s\+\>\~]+)[\w]+|\:{1,2}(after|before|first-letter|first-line|selection))` 18) 19 20var ( 21 nonIDAttrAndPseudoClassesRegexp *regexp.Regexp 22 elementsAndPseudoElementsRegexp *regexp.Regexp 23) 24 25// StyleRule represents a Qualifier Rule for a uniq selector 26type StyleRule struct { 27 // The style rule selector 28 Selector string 29 30 // The style rule properties 31 Declarations []*css.Declaration 32 33 // Selector specificity 34 Specificity int 35} 36 37func init() { 38 nonIDAttrAndPseudoClassesRegexp, _ = regexp.Compile(nonIDAttributesAndPseudoClassesRegexpConst) 39 elementsAndPseudoElementsRegexp, _ = regexp.Compile(elementsAndPseudoElementsRegexpConst) 40} 41 42// NewStyleRule instanciates a new StyleRule 43func NewStyleRule(selector string, declarations []*css.Declaration) *StyleRule { 44 return &StyleRule{ 45 Selector: selector, 46 Declarations: declarations, 47 Specificity: ComputeSpecificity(selector), 48 } 49} 50 51// Returns the string representation of a style rule 52func (styleRule *StyleRule) String() string { 53 result := "" 54 55 result += styleRule.Selector 56 57 if len(styleRule.Declarations) == 0 { 58 result += ";" 59 } else { 60 result += " {\n" 61 62 for _, decl := range styleRule.Declarations { 63 result += fmt.Sprintf(" %s\n", decl.String()) 64 } 65 66 result += "}" 67 } 68 69 return result 70} 71 72// ComputeSpecificity computes style rule specificity 73// 74// cf. http://www.w3.org/TR/selectors/#specificity 75func ComputeSpecificity(selector string) int { 76 result := 0 77 78 if selector == inlineFakeSelector { 79 result += 1000 80 } 81 82 result += 100 * strings.Count(selector, "#") 83 result += 10 * len(nonIDAttrAndPseudoClassesRegexp.FindAllStringSubmatch(selector, -1)) 84 result += len(elementsAndPseudoElementsRegexp.FindAllStringSubmatch(selector, -1)) 85 86 return result 87} 88