ref: 62b73b4e51b6d2db873956a9df9671e9cc2116c4
parent: 7c284bdddd481c95525f88e1a989bd512088b4a2
author: Philip Silva <[email protected]>
date: Sat Jan 8 21:25:07 EST 2022
more up-to-date css lib
--- a/browser/browser_test.go
+++ b/browser/browser_test.go
@@ -3,7 +3,6 @@
import (
"9fans.net/go/draw"
"fmt"
- "github.com/chris-ramon/douceur/css"
"github.com/mjl-/duit"
"github.com/psilva261/opossum/browser/duitx"
"github.com/psilva261/opossum/logger"
@@ -69,11 +68,11 @@
h3 := nt.Find("h3")
m := style.Map{
- Declarations: make(map[string]css.Declaration),
+ Declarations: make(map[string]style.Declaration),
}
- m.Declarations["display"] = css.Declaration{
- Property: "display",
- Value: d,
+ m.Declarations["display"] = style.Declaration{
+ Prop: "display",
+ Val: d,
}
h1.Map = m
h2.Map = m
--- a/browser/fs/experimental.go
+++ b/browser/fs/experimental.go
@@ -197,7 +197,7 @@
var v string
for p, d := range st.cs.Declarations {
if p == k {
- v = d.Value
+ v = d.Val
}
}
return []byte(v)
--- a/go.mod
+++ b/go.mod
@@ -8,10 +8,6 @@
replace github.com/mjl-/duit v0.0.0-20200330125617-580cb0b2843f => github.com/psilva261/duit v0.0.0-20210802155600-7e8fedefa7ba
-exclude github.com/aymerick/douceur v0.1.0
-
-exclude github.com/aymerick/douceur v0.2.0
-
exclude github.com/hanwen/go-fuse v1.0.0
exclude github.com/hanwen/go-fuse/v2 v2.0.3
@@ -19,12 +15,11 @@
require (
9fans.net/go v0.0.2
github.com/andybalholm/cascadia v1.3.1
- github.com/chris-ramon/douceur v0.2.1-0.20160603235419-f3463056cd52
- github.com/gorilla/css v1.0.0 // indirect
github.com/knusbaum/go9p v1.18.0
github.com/mjl-/duit v0.0.0-20200330125617-580cb0b2843f
github.com/srwiley/oksvg v0.0.0-20211120171407-1837d6608d8c
github.com/srwiley/rasterx v0.0.0-20210519020934-456a8d69b780
+ github.com/tdewolff/parse/v2 v2.5.26
golang.org/x/image v0.0.0-20211028202545-6944b10bf410
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8
golang.org/x/text v0.3.7
--- a/go.sum
+++ b/go.sum
@@ -2,8 +2,6 @@
github.com/Plan9-Archive/libauth v0.0.0-20180917063427-d1ca9e94969d/go.mod h1:UKp8dv9aeaZoQFWin7eQXtz89iHly1YAFZNn3MCutmQ=
github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c=
github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
-github.com/chris-ramon/douceur v0.2.1-0.20160603235419-f3463056cd52 h1:xJWyi77j4VQwdeo6bO3wQSQ7o7yVwEM0ZvwXpyKHZZ8=
-github.com/chris-ramon/douceur v0.2.1-0.20160603235419-f3463056cd52/go.mod h1:wDW5xjJdeoMm1mRt4sD4c/LbF/mWdEpRXQKjTR8nIBE=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21 h1:OJyUGMJTzHTd1XQp98QTaHernxMYzRaOasRir9hUlFQ=
@@ -10,8 +8,6 @@
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
github.com/fhs/mux9p v0.3.1 h1:x1UswUWZoA9vrA02jfisndCq3xQm+wrQUxUt5N99E08=
github.com/fhs/mux9p v0.3.1/go.mod h1:F4hwdenmit0WDoNVT2VMWlLJrBVCp/8UhzJa7scfjEQ=
-github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
-github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
github.com/knusbaum/go9p v1.18.0 h1:/Y67RNvNKX1ZV1IOdnO1lIetiF0X+CumOyvEc0011GI=
github.com/knusbaum/go9p v1.18.0/go.mod h1:HtMoJKqZUe1Oqag5uJqG5RKQ9gWPSP+wolsnLLv44r8=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -27,6 +23,10 @@
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/tdewolff/parse/v2 v2.5.26 h1:a/q3lwDCi4GIQ+sSbs4UOHuObhqp8GHAhfqop/zDyQQ=
+github.com/tdewolff/parse/v2 v2.5.26/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1Ik++q4zyho=
+github.com/tdewolff/test v1.0.6 h1:76mzYJQ83Op284kMT+63iCNCI7NEERsIN8dLM+RiKr4=
+github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
golang.org/x/image v0.0.0-20211028202545-6944b10bf410 h1:hTftEOvwiOq2+O8k2D5/Q7COC7k5Qcrgc2TFURJYnvQ=
golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8 h1:/6y1LfuqNuQdHAm0jjtPtgRcxIxjVZgm5OTu8/QhZvk=
--- a/nodes/nodes.go
+++ b/nodes/nodes.go
@@ -3,7 +3,6 @@
import (
"bytes"
"fmt"
- "github.com/chris-ramon/douceur/css"
"github.com/psilva261/opossum/logger"
"github.com/psilva261/opossum/style"
"golang.org/x/net/html"
@@ -30,7 +29,7 @@
// First applies the parent style and at the end the local style attribute's style is attached.
func NewNodeTree(doc *html.Node, ps style.Map, nodeMap map[*html.Node]style.Map, parent *Node) (n *Node) {
ncs := style.Map{
- Declarations: make(map[string]css.Declaration),
+ Declarations: make(map[string]style.Declaration),
}
ncs = ps.ApplyChildStyle(ncs, false)
@@ -58,9 +57,9 @@
n.Wrappable = doc.Type == html.TextNode || doc.Data == "span" // TODO: probably this list needs to be extended
if doc.Type == html.TextNode {
n.Text = filterText(doc.Data)
- n.Map.Declarations["display"] = css.Declaration{
- Property: "display",
- Value: "inline",
+ n.Map.Declarations["display"] = style.Declaration{
+ Prop: "display",
+ Val: "inline",
}
}
i := 0
@@ -395,7 +394,7 @@
if len(n.Map.Declarations) > 0 {
l := make([]string, 0, 2)
for k, d := range n.Map.Declarations {
- s := fmt.Sprintf("%v=%v", k, d.Value)
+ s := fmt.Sprintf("%v=%v", k, d.Val)
if d.Important {
s += "!"
}
--- a/opossum_test.go
+++ /dev/null
@@ -1,16 +1,0 @@
-package opossum
-
-import (
- "testing"
-
- "github.com/chris-ramon/douceur/parser"
-)
-
-// aymerick douceur issues #6
-func TestInfiniteLoop(t *testing.T) {
- parser.Parse(`
-@media ( __desktop ) {
- background-color: red;
-}
-`)
-}
--- /dev/null
+++ b/style/css.go
@@ -1,0 +1,121 @@
+package style
+
+import (
+ "fmt"
+ "github.com/psilva261/opossum/logger"
+ "github.com/tdewolff/parse/v2"
+ "github.com/tdewolff/parse/v2/css"
+ "io"
+ "strings"
+)
+
+type Sheet struct {
+ Rules []Rule
+}
+
+type Rule struct {
+ Prelude string
+ Selectors []Selector
+ Declarations []Declaration
+
+ Rules []Rule
+}
+
+type Selector struct {
+ Val string
+}
+
+type Declaration struct {
+ Important bool
+ Prop string
+ Val string
+}
+
+func Parse(rd io.Reader, inline bool) (s Sheet, err error) {
+ s.Rules = make([]Rule, 0, 1000)
+ stack := make([]Rule, 0, 2)
+ selectors := make([]Selector, 0, 1)
+ p := css.NewParser(parse.NewInput(rd), inline)
+ if inline {
+ stack = append(stack, Rule{})
+ defer func() {
+ s.Rules = append(s.Rules, stack[0])
+ }()
+ }
+ for {
+ gt, _, data := p.Next()
+ switch gt {
+ case css.ErrorGrammar:
+ if err := p.Err(); err == io.EOF {
+ return s, nil
+ } else {
+ return s, fmt.Errorf("next: %v", err)
+ }
+ break
+ case css.QualifiedRuleGrammar:
+ sel := Selector{}
+ for _, val := range p.Values() {
+ sel.Val += string(val.Data)
+ }
+ selectors = append(selectors, sel)
+ case css.AtRuleGrammar, css.BeginAtRuleGrammar, css.BeginRulesetGrammar, css.DeclarationGrammar, css.CustomPropertyGrammar:
+ var d Declaration
+ if gt == css.BeginRulesetGrammar || gt == css.BeginAtRuleGrammar || gt == css.AtRuleGrammar {
+ // TODO: why also gt == css.AtRuleGrammar? some sites crash otherwise
+ stack = append(stack, Rule{})
+ }
+ r := &(stack[len(stack)-1])
+ if gt == css.DeclarationGrammar || gt == css.CustomPropertyGrammar {
+ d.Prop = string(data)
+ }
+ if gt == css.BeginAtRuleGrammar {
+ r.Prelude = string(data)
+ }
+ vals := p.Values()
+ for i, val := range vals {
+ if gt == css.DeclarationGrammar || gt == css.CustomPropertyGrammar {
+ if string(val.Data) == "!" && len(vals) == i+2 && string(vals[i+1].Data) == "important" {
+ d.Important = true
+ break
+ } else {
+ d.Val += string(val.Data)
+ }
+ } else if gt == css.BeginRulesetGrammar {
+ if len(selectors) == 0 {
+ sel := Selector{
+ Val: string(val.Data),
+ }
+ selectors = append(selectors, sel)
+ } else {
+ selectors[len(selectors)-1].Val += string(val.Data)
+ }
+ } else if gt == css.BeginAtRuleGrammar {
+ r.Prelude += string(val.Data)
+ } else {
+ }
+ }
+ if gt == css.DeclarationGrammar || gt == css.CustomPropertyGrammar {
+ d.Val = strings.TrimSpace(d.Val)
+ r.Declarations = append(r.Declarations, d)
+ }
+ case css.EndRulesetGrammar, css.EndAtRuleGrammar:
+ var r Rule
+ if len(stack) == 1 {
+ r, stack = stack[len(stack)-1], stack[:len(stack)-1]
+ r.Selectors = append([]Selector{}, selectors...)
+ s.Rules = append(s.Rules, r)
+ } else {
+ p := &(stack[len(stack)-2])
+ r, stack = stack[len(stack)-1], stack[:len(stack)-1]
+ r.Selectors = append([]Selector{}, selectors...)
+ p.Rules = append(p.Rules, r)
+ }
+
+ selectors = make([]Selector, 0, 1)
+ case css.CommentGrammar:
+ default:
+ log.Errorf("unknown token type %+v", gt)
+ }
+ }
+ return
+}
--- /dev/null
+++ b/style/css_test.go
@@ -1,0 +1,183 @@
+package style
+
+import (
+ "bytes"
+ "testing"
+)
+
+func TestParseInline(t *testing.T) {
+ b := bytes.NewBufferString("color: red;")
+ s, err := Parse(b, true)
+ if err != nil {
+ t.Fatalf("%v", err)
+ }
+ t.Logf("s: %+v", s)
+ if len(s.Rules) != 1 {
+ t.Fail()
+ }
+ r := s.Rules[0]
+ if len(r.Declarations) != 1 {
+ t.Fail()
+ }
+ d := r.Declarations[0]
+ if d.Prop != "color" || d.Val != "red" {
+ t.Fail()
+ }
+}
+
+func TestParseMin(t *testing.T) {
+ b := bytes.NewBufferString(`
+ h1 {
+ font-weight: bold;
+ font-size: 100px;
+ }
+ p, quote, a < b, div {
+ color: grey !important;
+ }
+ :root {
+ --emph: red;
+ --h: 10px;
+ }
+
+ b {
+ color: var(--emph);
+ }
+ `)
+ s, err := Parse(b, false)
+ if err != nil {
+ t.Fatalf("%v", err)
+ }
+ t.Logf("s: %+v", s)
+ if len(s.Rules) != 4 {
+ t.Fatalf("%+v", s)
+ }
+ r := s.Rules[0]
+ if len(r.Declarations) != 2 || len(r.Selectors) != 1 || r.Selectors[0].Val != "h1" {
+ t.Fatalf("%+v", r)
+ }
+ d := r.Declarations[0]
+ if d.Prop != "font-weight" || d.Val != "bold" || d.Important {
+ t.Fatalf("%+v", d)
+ }
+ r = s.Rules[1]
+ if len(r.Declarations) != 1 || len(r.Selectors) != 3 {
+ t.Fatalf("%+v", r)
+ }
+ d = r.Declarations[0]
+ if d.Prop != "color" || d.Val != "grey" || !d.Important {
+ t.Fatalf("%+v", d)
+ }
+ r = s.Rules[2]
+ if len(r.Declarations) != 2 || len(r.Selectors) != 1 || r.Selectors[0].Val != ":root" {
+ t.Fatalf("%+v", r)
+ }
+ d = r.Declarations[0]
+ if d.Prop != "--emph" || d.Val != "red" {
+ t.Fatalf("%+v %+v", r, d)
+ }
+}
+
+func TestParseMedia(t *testing.T) {
+ b := bytes.NewBufferString(`
+ @media only screen and (max-width: 600px) {
+ body {
+ background-color: lightblue;
+ }
+ }
+ `)
+ s, err := Parse(b, false)
+ if err != nil {
+ t.Fatalf("%v", err)
+ }
+ t.Logf("s: %+v", s)
+ t.Logf("s.Rules[0].Prelude: %+v", s.Rules[0].Prelude)
+ //t.Logf("s.Rules[0].Prelude: %+v", s.Rules[0].Rules[0].Prelude)
+ if len(s.Rules) != 1 {
+ t.Fatalf("%+v", s)
+ }
+ r := s.Rules[0]
+ if len(r.Declarations) != 0 || len(r.Selectors) > 0 {
+ t.Fatalf("%+v", r)
+ }
+ d := r.Rules[0].Declarations[0]
+ if d.Prop != "background-color" || d.Val != "lightblue" {
+ t.Fatalf("%+v", d)
+ }
+}
+
+func TestParseComment(t *testing.T) {
+ b := bytes.NewBufferString(`
+ h1 {
+ font-weight: bold;
+ font-size: 100px;
+ }
+ /* grey text */
+ p {
+ color: grey !important;
+ }
+ `)
+ s, err := Parse(b, false)
+ if err != nil {
+ t.Fatalf("%v", err)
+ }
+ t.Logf("s: %+v", s)
+ if len(s.Rules) != 2 {
+ t.Fatalf("%v", s)
+ }
+ r := s.Rules[0]
+ if len(r.Declarations) != 2 || r.Selectors[0].Val != "h1" {
+ t.Fatalf("%v", r)
+ }
+ d := r.Declarations[0]
+ if d.Prop != "font-weight" || d.Val != "bold" {
+ t.Fatalf("%v", d)
+ }
+ r = s.Rules[1]
+ if len(r.Declarations) != 1 || r.Selectors[0].Val != "p" {
+ t.Fatalf("%v", r)
+ }
+ d = r.Declarations[0]
+ if d.Prop != "color" || d.Val != "grey" || !d.Important {
+ t.Fatalf("%v", d)
+ }
+}
+
+func TestParseQual(t *testing.T) {
+ b := bytes.NewBufferString(`
+ h1 {
+ font-weight: bold;
+ font-size: 100px;
+ }
+ p {
+ color: grey !important;
+ }
+ a[href] {
+ color: blue;
+ margin-right: 2px;
+ }
+ `)
+ s, err := Parse(b, false)
+ if err != nil {
+ t.Fatalf("%v", err)
+ }
+ t.Logf("s: %+v", s)
+ if len(s.Rules) != 3 {
+ t.Fail()
+ }
+ r := s.Rules[0]
+ if len(r.Declarations) != 2 || r.Selectors[0].Val != "h1" {
+ t.Fail()
+ }
+ d := r.Declarations[0]
+ if d.Prop != "font-weight" || d.Val != "bold" {
+ t.Fail()
+ }
+ r = s.Rules[2]
+ if len(r.Declarations) != 2 || r.Selectors[0].Val != "a[href]" {
+ t.Fatalf("%+v", r)
+ }
+ d = r.Declarations[0]
+ if d.Prop != "color" || d.Val != "blue" {
+ t.Fail()
+ }
+}
--- a/style/experimental.go
+++ b/style/experimental.go
@@ -3,7 +3,6 @@
import (
"9fans.net/go/draw"
"fmt"
- "github.com/chris-ramon/douceur/css"
"github.com/mjl-/duit"
"github.com/psilva261/opossum"
"github.com/psilva261/opossum/img"
@@ -20,10 +19,10 @@
}
var TextNode = Map{
- Declarations: map[string]css.Declaration{
- "display": css.Declaration{
- Property: "display",
- Value: "inline",
+ Declarations: map[string]Declaration{
+ "display": Declaration{
+ Prop: "display",
+ Val: "inline",
},
},
}
@@ -62,7 +61,7 @@
func (cs Map) backgroundColor() (c draw.Color, ok bool) {
d, ok := cs.Declarations["background-color"]
if ok {
- c, ok = colorHex(d.Value)
+ c, ok = colorHex(d.Val)
if !ok {
return
}
@@ -70,7 +69,7 @@
}
d, ok = cs.Declarations["background"]
if ok {
- c, ok = colorHex(d.Value)
+ c, ok = colorHex(d.Val)
if !ok {
return
}
@@ -99,7 +98,7 @@
if !ok {
return
}
- v := strings.TrimSpace(d.Value)
+ v := strings.TrimSpace(d.Val)
if strings.HasPrefix(v, "linear-gradient(") {
v = strings.TrimPrefix(v, "linear-gradient(")
} else {
@@ -155,8 +154,8 @@
return draw.Color(cc)
}
-func backgroundImageUrl(decl css.Declaration) (url string, ok bool) {
- if v := decl.Value; strings.Contains(v, "url(") && strings.Contains(v, ")") {
+func backgroundImageUrl(decl Declaration) (url string, ok bool) {
+ if v := decl.Val; strings.Contains(v, "url(") && strings.Contains(v, ")") {
v = strings.ReplaceAll(v, `"`, "")
v = strings.ReplaceAll(v, `'`, "")
from := strings.Index(v, "url(")
--- a/style/experimental_test.go
+++ b/style/experimental_test.go
@@ -2,7 +2,6 @@
import (
"9fans.net/go/draw"
- "github.com/chris-ramon/douceur/css"
"github.com/psilva261/opossum/logger"
"testing"
)
@@ -15,8 +14,8 @@
suffix := ""
for _, quote := range []string{"", "'", `"`} {
url := "/foo.png"
- decl := css.Declaration{
- Value: "url(" + quote + url + quote + ")" + suffix,
+ decl := Declaration{
+ Val: "url(" + quote + url + quote + ")" + suffix,
}
imgUrl, ok := backgroundImageUrl(decl)
if !ok {
@@ -36,12 +35,12 @@
for _, k := range []string{"background", "background-color"} {
m := Map{
- Declarations: make(map[string]css.Declaration),
+ Declarations: make(map[string]Declaration),
}
for hex, d := range colors {
- m.Declarations[k] = css.Declaration{
- Property: k,
- Value: hex,
+ m.Declarations[k] = Declaration{
+ Prop: k,
+ Val: hex,
}
if b, ok := m.backgroundColor(); !ok || b != d {
@@ -59,11 +58,11 @@
}
for v, cc := range values {
m := Map{
- Declarations: make(map[string]css.Declaration),
+ Declarations: make(map[string]Declaration),
}
- m.Declarations["background"] = css.Declaration{
- Property: "background",
- Value: v,
+ m.Declarations["background"] = Declaration{
+ Prop: "background",
+ Val: v,
}
c, ok := m.backgroundGradient()
if !ok {
--- a/style/stylesheets.go
+++ b/style/stylesheets.go
@@ -5,8 +5,6 @@
"bytes"
"fmt"
"github.com/andybalholm/cascadia"
- "github.com/chris-ramon/douceur/css"
- "github.com/chris-ramon/douceur/parser"
"github.com/mjl-/duit"
"github.com/psilva261/opossum/logger"
"golang.org/x/image/colornames"
@@ -25,8 +23,8 @@
var dui *duit.DUI
var availableFontNames []string
-var rMinWidth = regexp.MustCompile(`min-width: (\d+)(px|em|rem)`)
-var rMaxWidth = regexp.MustCompile(`max-width: (\d+)(px|em|rem)`)
+var rMinWidth = regexp.MustCompile(`min-width:\s*(\d+)(px|em|rem)`)
+var rMaxWidth = regexp.MustCompile(`max-width:\s*(\d+)(px|em|rem)`)
const FontBaseSize = 11.0
@@ -118,20 +116,20 @@
}
m = make(map[*html.Node]Map)
for n, rs := range mr {
- ds := make(map[string]css.Declaration)
+ ds := make(map[string]Declaration)
for _, r := range rs {
for _, d := range r.Declarations {
- if exist, ok := ds[d.Property]; ok && smaller(*d, exist) {
+ if exist, ok := ds[d.Prop]; ok && smaller(d, exist) {
continue
}
- if strings.HasPrefix(d.Value, "var(") {
- v := strings.TrimPrefix(d.Value, "var(")
+ if strings.HasPrefix(d.Val, "var(") {
+ v := strings.TrimPrefix(d.Val, "var(")
v = strings.TrimSuffix(v, ")")
if vv, ok := rv[v]; ok {
- d.Value = vv
+ d.Val = vv
}
}
- ds[d.Property] = *d
+ ds[d.Prop] = d
}
}
m[n] = Map{Declarations: ds}
@@ -139,46 +137,37 @@
return
}
-func smaller(d, dd css.Declaration) bool {
+func smaller(d, dd Declaration) bool {
return dd.Important
}
func compile(v string) (cs cascadia.Selector, err error) {
- l := strings.Split(v, " ")
- for _, s := range l {
- s = strings.TrimSpace(s)
- if strings.HasSuffix(s, ":") {
- // TODO: selectors like .selector: would crash otherwise
- err = fmt.Errorf("unsupported selector: %v", s)
- return
- }
- }
return cascadia.Compile(v)
}
-func FetchNodeRules(doc *html.Node, cssText string, windowWidth int) (m map[*html.Node][]*css.Rule, rVars map[string]string, err error) {
- m = make(map[*html.Node][]*css.Rule)
+func FetchNodeRules(doc *html.Node, cssText string, windowWidth int) (m map[*html.Node][]Rule, rVars map[string]string, err error) {
+ m = make(map[*html.Node][]Rule)
rVars = make(map[string]string)
- s, err := parser.Parse(cssText)
+ s, err := Parse(strings.NewReader(cssText), false)
if err != nil {
- return nil, nil, fmt.Errorf("douceur parse: %w", err)
+ return nil, nil, fmt.Errorf("parse: %w", err)
}
- processRule := func(m map[*html.Node][]*css.Rule, r *css.Rule) (err error) {
+ processRule := func(m map[*html.Node][]Rule, r Rule) (err error) {
for _, sel := range r.Selectors {
- if sel.Value == ":root" {
+ if sel.Val == ":root" {
for _, d := range r.Declarations {
- rVars[d.Property] = d.Value
+ rVars[d.Prop] = d.Val
}
}
- cs, err := compile(sel.Value)
+ cs, err := compile(sel.Val)
if err != nil {
- log.Printf("cssSel compile %v: %v", sel.Value, err)
+ log.Printf("cssSel compile %v: %v", sel.Val, err)
continue
}
for _, el := range cascadia.QueryAll(doc, cs) {
existing, ok := m[el]
if !ok {
- existing = make([]*css.Rule, 0, 3)
+ existing = make([]Rule, 0, 3)
}
existing = append(existing, r)
m[el] = existing
@@ -233,13 +222,13 @@
}
type Map struct {
- Declarations map[string]css.Declaration
+ Declarations map[string]Declaration
DomTree `json:"-"`
}
func NewMap(n *html.Node) Map {
s := Map{
- Declarations: make(map[string]css.Declaration),
+ Declarations: make(map[string]Declaration),
}
for _, a := range n.Attr {
@@ -248,8 +237,13 @@
if !strings.HasSuffix(v, ";") {
v += ";"
}
- decls, err := parser.ParseDeclarations(v)
+ st, err := Parse(strings.NewReader(v), true)
+ var decls []Declaration
+ if len(st.Rules) > 0 {
+ decls = st.Rules[0].Declarations
+ }
+
if err != nil {
log.Printf("could not parse '%v'", a.Val)
break
@@ -256,7 +250,7 @@
}
for _, d := range decls {
- s.Declarations[d.Property] = *d
+ s.Declarations[d.Prop] = d
}
} else if a.Key == "height" || a.Key == "width" {
v := a.Val
@@ -265,14 +259,14 @@
v += "px"
}
- s.Declarations[a.Key] = css.Declaration{
- Property: a.Key,
- Value: v,
+ s.Declarations[a.Key] = Declaration{
+ Prop: a.Key,
+ Val: v,
}
} else if a.Key == "bgcolor" {
- s.Declarations["background-color"] = css.Declaration{
- Property: "background-color",
- Value: a.Val,
+ s.Declarations["background-color"] = Declaration{
+ Prop: "background-color",
+ Val: a.Val,
}
}
}
@@ -281,7 +275,7 @@
}
func (cs Map) ApplyChildStyle(ccs Map, copyAll bool) (res Map) {
- res.Declarations = make(map[string]css.Declaration)
+ res.Declarations = make(map[string]Declaration)
for k, v := range cs.Declarations {
switch k {
@@ -296,7 +290,7 @@
}
// overwrite with higher prio child props
for k, v := range ccs.Declarations {
- if v.Value == "inherit" {
+ if v.Val == "inherit" {
continue
}
res.Declarations[k] = v
@@ -361,21 +355,21 @@
func (cs Map) FontSize() float64 {
fs, ok := cs.Declarations["font-size"]
- if !ok || fs.Value == "" {
+ if !ok || fs.Val == "" {
return FontBaseSize
}
- if len(fs.Value) <= 2 {
- log.Printf("error parsing font size %v", fs.Value)
+ if len(fs.Val) <= 2 {
+ log.Printf("error parsing font size %v", fs.Val)
return FontBaseSize
}
- numStr := fs.Value[0 : len(fs.Value)-2]
+ numStr := fs.Val[0 : len(fs.Val)-2]
f, err := strconv.ParseFloat(numStr, 64)
if err != nil {
- log.Printf("error parsing font size %v", fs.Value)
+ log.Printf("error parsing font size %v", fs.Val)
return FontBaseSize
}
- if strings.HasSuffix(fs.Value, "em") {
+ if strings.HasSuffix(fs.Val, "em") {
f *= FontBaseSize
}
return f
@@ -388,7 +382,7 @@
func (cs Map) Color() draw.Color {
if d, ok := cs.Declarations["color"]; ok {
- if h, ok := colorHex(d.Value); ok {
+ if h, ok := colorHex(d.Val); ok {
c := draw.Color(h)
return c
}
@@ -486,13 +480,13 @@
func (cs Map) IsInline() bool {
propVal, ok := cs.Declarations["float"]
- if ok && propVal.Value == "left" {
+ if ok && propVal.Val == "left" {
return true
}
propVal, ok = cs.Declarations["display"]
if ok {
- return propVal.Value == "inline" ||
- propVal.Value == "inline-block"
+ return propVal.Val == "inline" ||
+ propVal.Val == "inline-block"
}
return false
}
@@ -499,21 +493,21 @@
func (cs Map) IsDisplayNone() bool {
propVal, ok := cs.Declarations["display"]
- if ok && propVal.Value == "none" {
+ if ok && propVal.Val == "none" {
return true
}
/*propVal, ok = cs.Declarations["position"]
- if ok && propVal.Value == "fixed" {
+ if ok && propVal.Val == "fixed" {
return true
}*/
propVal, ok = cs.Declarations["clip"]
- if ok && strings.ReplaceAll(propVal.Value, " ", "") == "rect(1px,1px,1px,1px)" {
+ if ok && strings.ReplaceAll(propVal.Val, " ", "") == "rect(1px,1px,1px,1px)" {
return true
}
propVal, ok = cs.Declarations["width"]
- if ok && propVal.Value == "1px" {
+ if ok && propVal.Val == "1px" {
propVal, ok = cs.Declarations["height"]
- if ok && propVal.Value == "1px" {
+ if ok && propVal.Val == "1px" {
return true
}
}
@@ -523,7 +517,7 @@
func (cs Map) IsFlex() bool {
propVal, ok := cs.Declarations["display"]
if ok {
- return propVal.Value == "flex"
+ return propVal.Val == "flex"
}
return false
}
@@ -531,7 +525,7 @@
func (cs Map) IsFlexDirectionRow() bool {
propVal, ok := cs.Declarations["flex-direction"]
if ok {
- switch propVal.Value {
+ switch propVal.Val {
case "row":
return true
case "column":
@@ -545,7 +539,7 @@
// margin-top, ...-right, ...-bottom, ...-left.
func (cs *Map) Tlbr(key string) (s duit.Space, err error) {
if all, ok := cs.Declarations[key]; ok {
- parts := strings.Split(all.Value, " ")
+ parts := strings.Split(all.Val, " ")
nums := make([]int, len(parts))
for i, p := range parts {
if f, _, err := length(cs, p); err == nil {
@@ -702,7 +696,7 @@
func (cs *Map) Height() int {
d, ok := cs.Declarations["height"]
if ok {
- f, _, err := length(cs, d.Value)
+ f, _, err := length(cs, d.Val)
if err != nil {
log.Errorf("cannot parse height: %v", err)
}
@@ -715,7 +709,7 @@
w := cs.width()
if w > 0 {
if d, ok := cs.Declarations["max-width"]; ok {
- f, _, err := length(&cs, d.Value)
+ f, _, err := length(&cs, d.Val)
if err != nil {
log.Errorf("cannot parse width: %v", err)
}
@@ -730,7 +724,7 @@
func (cs Map) width() int {
d, ok := cs.Declarations["width"]
if ok {
- f, _, err := length(&cs, d.Value)
+ f, _, err := length(&cs, d.Val)
if err != nil {
log.Errorf("cannot parse width: %v", err)
}
@@ -762,7 +756,7 @@
if !ok {
return ""
}
- return d.Value
+ return d.Val
}
func (cs *Map) CssPx(propName string) (l int, err error) {
@@ -770,7 +764,7 @@
if !ok {
return 0, fmt.Errorf("property doesn't exist")
}
- f, _, err := length(cs, d.Value)
+ f, _, err := length(cs, d.Val)
if err != nil {
return 0, err
}
@@ -779,8 +773,8 @@
}
func (cs Map) SetCss(k, v string) {
- cs.Declarations[k] = css.Declaration{
- Property: k,
- Value: v,
+ cs.Declarations[k] = Declaration{
+ Prop: k,
+ Val: v,
}
}
--- a/style/stylesheets_test.go
+++ b/style/stylesheets_test.go
@@ -1,7 +1,6 @@
package style
import (
- "github.com/chris-ramon/douceur/css"
"github.com/mjl-/duit"
"github.com/psilva261/opossum/logger"
"golang.org/x/net/html"
@@ -103,10 +102,10 @@
if w == 400 {
_ = m[body][0]
- if v := m[body][0].Declarations[0].Value; v != "lightblue" {
+ if v := m[body][0].Declarations[0].Val; v != "lightblue" {
t.Fatalf("%v", v)
}
- t.Logf("%v", m[body][0].Name)
+ t.Logf("%v", m[body][0])
} else {
if _, ok := m[body]; ok {
t.Fatalf("body ok")
@@ -197,7 +196,7 @@
h2 := grep(doc, "h2")
m := NewMap(h2)
- if m.Declarations["color"].Value != "green" {
+ if m.Declarations["color"].Val != "green" {
t.Errorf("%+v", m)
}
}
@@ -220,10 +219,10 @@
}
func TestSmaller(t *testing.T) {
- d := css.Declaration{
+ d := Declaration{
Important: false,
}
- dd := css.Declaration{
+ dd := Declaration{
Important: true,
}
if !smaller(d, dd) {
@@ -233,18 +232,18 @@
func TestApplyChildStyleInherit(t *testing.T) {
parent := Map{
- Declarations: make(map[string]css.Declaration),
+ Declarations: make(map[string]Declaration),
}
- parent.Declarations["height"] = css.Declaration{
- Property: "height",
- Value: "80px",
+ parent.Declarations["height"] = Declaration{
+ Prop: "height",
+ Val: "80px",
}
child := Map{
- Declarations: make(map[string]css.Declaration),
+ Declarations: make(map[string]Declaration),
}
res := parent.ApplyChildStyle(child, true)
- if v := res.Declarations["height"].Value; v != "80px" {
+ if v := res.Declarations["height"].Val; v != "80px" {
t.Fatalf(v)
}
}
@@ -251,22 +250,22 @@
func TestApplyChildStyleInherit2(t *testing.T) {
parent := Map{
- Declarations: make(map[string]css.Declaration),
+ Declarations: make(map[string]Declaration),
}
child := Map{
- Declarations: make(map[string]css.Declaration),
+ Declarations: make(map[string]Declaration),
}
- parent.Declarations["font-size"] = css.Declaration{
- Property: "font-size",
- Value: "12pt",
+ parent.Declarations["font-size"] = Declaration{
+ Prop: "font-size",
+ Val: "12pt",
}
- child.Declarations["font-size"] = css.Declaration{
- Property: "font-size",
- Value: "inherit",
+ child.Declarations["font-size"] = Declaration{
+ Prop: "font-size",
+ Val: "inherit",
}
res := parent.ApplyChildStyle(child, true)
- if v := res.Declarations["font-size"].Value; v != "12pt" {
+ if v := res.Declarations["font-size"].Val; v != "12pt" {
t.Fatalf(v)
}
}
@@ -339,11 +338,11 @@
}
for v, exp := range cases {
m := Map{
- Declarations: make(map[string]css.Declaration),
+ Declarations: make(map[string]Declaration),
}
- m.Declarations["margin"] = css.Declaration{
- Property: "margin",
- Value: v,
+ m.Declarations["margin"] = Declaration{
+ Prop: "margin",
+ Val: v,
}
s, err := m.Tlbr("margin")
if err != nil {
@@ -403,7 +402,7 @@
}
d := nm[b]
t.Logf("d=%+v", d)
- if d.Declarations["color"].Value != "red" {
- t.Fail()
+ if d.Declarations["color"].Val != "red" {
+ t.Fatalf("%+v", d.Declarations)
}
}