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