66
|
1 package gcss
|
|
2
|
|
3 import (
|
|
4 "bytes"
|
|
5 "fmt"
|
|
6 "io"
|
|
7 "strings"
|
|
8 )
|
|
9
|
|
10 // selector represents a selector of CSS.
|
|
11 type selector struct {
|
|
12 elementBase
|
|
13 name string
|
|
14 }
|
|
15
|
|
16 // WriteTo writes the selector to the writer.
|
|
17 func (sel *selector) WriteTo(w io.Writer) (int64, error) {
|
|
18 return sel.writeTo(w, nil)
|
|
19 }
|
|
20
|
|
21 // writeTo writes the selector to the writer.
|
|
22 func (sel *selector) writeTo(w io.Writer, params map[string]string) (int64, error) {
|
|
23 bf := new(bytes.Buffer)
|
|
24
|
|
25 // Write the declarations.
|
|
26 if len(sel.decs) > 0 || sel.hasMixinDecs() {
|
|
27 bf.WriteString(sel.names())
|
|
28 bf.WriteString(openBrace)
|
|
29
|
|
30 // Writing to the bytes.Buffer never returns an error.
|
|
31 sel.writeDecsTo(bf, params)
|
|
32
|
|
33 bf.WriteString(closeBrace)
|
|
34 }
|
|
35
|
|
36 // Write the child selectors.
|
|
37 for _, childSel := range sel.sels {
|
|
38 // Writing to the bytes.Buffer never returns an error.
|
|
39 childSel.writeTo(bf, params)
|
|
40 }
|
|
41
|
|
42 // Write the mixin's selectors.
|
|
43 for _, mi := range sel.mixins {
|
|
44 sels, prms := mi.selsParams()
|
|
45
|
|
46 for _, sl := range sels {
|
|
47 sl.parent = sel
|
|
48 // Writing to the bytes.Buffer never returns an error.
|
|
49 sl.writeTo(bf, prms)
|
|
50 }
|
|
51 }
|
|
52
|
|
53 n, err := w.Write(bf.Bytes())
|
|
54
|
|
55 return int64(n), err
|
|
56 }
|
|
57
|
|
58 // names returns the selector names.
|
|
59 func (sel *selector) names() string {
|
|
60 bf := new(bytes.Buffer)
|
|
61
|
|
62 switch parent := sel.parent.(type) {
|
|
63 case nil, *atRule:
|
|
64 for _, name := range strings.Split(sel.name, comma) {
|
|
65 if bf.Len() > 0 {
|
|
66 bf.WriteString(comma)
|
|
67 }
|
|
68
|
|
69 bf.WriteString(strings.TrimSpace(name))
|
|
70 }
|
|
71 case *selector:
|
|
72 for _, parentS := range strings.Split(parent.names(), comma) {
|
|
73 for _, s := range strings.Split(sel.name, comma) {
|
|
74 if bf.Len() > 0 {
|
|
75 bf.WriteString(comma)
|
|
76 }
|
|
77
|
|
78 s = strings.TrimSpace(s)
|
|
79
|
|
80 if strings.Index(s, ampersand) != -1 {
|
|
81 bf.WriteString(strings.Replace(s, ampersand, parentS, -1))
|
|
82 } else {
|
|
83 bf.WriteString(parentS)
|
|
84 bf.WriteString(space)
|
|
85 bf.WriteString(s)
|
|
86 }
|
|
87 }
|
|
88 }
|
|
89 }
|
|
90
|
|
91 return bf.String()
|
|
92 }
|
|
93
|
|
94 // newSelector creates and returns a selector.
|
|
95 func newSelector(ln *line, parent element) (*selector, error) {
|
|
96 name := strings.TrimSpace(ln.s)
|
|
97
|
|
98 if strings.HasSuffix(name, openBrace) {
|
|
99 return nil, fmt.Errorf("selector must not end with %q [line: %d]", openBrace, ln.no)
|
|
100 }
|
|
101
|
|
102 if strings.HasSuffix(name, closeBrace) {
|
|
103 return nil, fmt.Errorf("selector must not end with %q [line: %d]", closeBrace, ln.no)
|
|
104 }
|
|
105
|
|
106 return &selector{
|
|
107 elementBase: newElementBase(ln, parent),
|
|
108 name: name,
|
|
109 }, nil
|
|
110 }
|