ref: 89d4bc312ff9a8639a4bf912f36e1a48e8a4e113
parent: df986b4853ae85c9e12bb773a6293bfcf23a8ea2
author: Philip Silva <philip.silva@protonmail.com>
date: Sun Oct 10 07:13:41 EDT 2021
add dom tree as fs
--- a/browser/browser.go
+++ b/browser/browser.go
@@ -220,7 +220,7 @@
}
if src == "" {
- return nil, fmt.Errorf("no src in %+v", n.Attrs)
+ return nil, fmt.Errorf("no src in %+v", n.DomSubtree.Attr)
}
if i, cached = imageCache[src]; !cached {
--- a/browser/experimental_test.go
+++ b/browser/experimental_test.go
@@ -44,7 +44,7 @@
`$('body').hide()`,
`throw 'fail';`,
}
- fs.DOM = nt
+ fs.SetDOM(nt)
fs.Update(h, nil, scripts)
js.NewJS(h, nil, nt)
js.Start()
--- /dev/null
+++ b/browser/fs/experimental.go
@@ -1,0 +1,146 @@
+package fs
+
+import (
+ "bytes"
+ "fmt"
+ "github.com/knusbaum/go9p/fs"
+ "github.com/knusbaum/go9p/proto"
+ "github.com/psilva261/opossum/logger"
+ "github.com/psilva261/opossum/nodes"
+ "golang.org/x/net/html"
+)
+
+// Node such that one obtains a file structure like
+//
+// /0
+// /0/attrs
+// /0/html
+// /0/tag
+// /0/0
+// ...
+// /0/1
+// ...
+// ...
+//
+// (dir structure stolen from domfs)
+type Node struct {
+ name string
+ nt *nodes.Node
+}
+
+func (n Node) Stat() (s proto.Stat) {
+ s = *oFS.NewStat(n.name, un, gn, 0700)
+ s.Mode |= proto.DMDIR
+ // qtype bits should be consistent with Stat mode.
+ s.Qid.Qtype = uint8(s.Mode >> 24)
+ return
+}
+
+func (n Node) WriteStat(s *proto.Stat) error {
+ return nil
+}
+
+func (n Node) SetParent(p fs.Dir) {
+}
+
+func (n Node) Parent() fs.Dir {
+ return nil
+}
+
+func (n Node) Children() (cs map[string]fs.FSNode) {
+ cs = make(map[string]fs.FSNode)
+ if n.nt == nil {
+ return
+ }
+ for i, c := range n.nt.Children {
+ ddn := fmt.Sprintf("%v", i)
+ cs[ddn] = &Node{
+ name: ddn,
+ nt: c,
+ }
+ }
+ if n.nt.Type() == html.ElementNode {
+ cs["tag"] = n.tag()
+ cs["attrs"] = Attrs{attrs: &n.nt.DomSubtree.Attr}
+ cs["html"] = n.html()
+ }
+
+ return
+}
+
+func (n Node) tag() fs.FSNode {
+ return fs.NewDynamicFile(
+ oFS.NewStat("tag", un, gn, 0666),
+ func() []byte {
+ return []byte(n.nt.Data())
+ },
+ )
+}
+
+func (n Node) html() fs.FSNode {
+ return fs.NewDynamicFile(
+ oFS.NewStat("html", un, gn, 0666),
+ func() []byte {
+ buf := bytes.NewBufferString("")
+ if err := html.Render(buf, n.nt.DomSubtree); err != nil {
+ log.Errorf("render: %v", err)
+ return []byte{}
+ }
+ return []byte(buf.String())
+ },
+ )
+}
+
+func (n Node) AddChild(fs.FSNode) error {
+ return nil
+}
+
+func (n Node) DeleteChild(name string) error {
+ return fmt.Errorf("no removal possible")
+}
+
+type Attrs struct {
+ attrs *[]html.Attribute
+}
+
+func (as Attrs) Stat() (s proto.Stat) {
+ s = *oFS.NewStat("attrs", un, gn, 0500)
+ s.Mode |= proto.DMDIR
+ // qtype bits should be consistent with Stat mode.
+ s.Qid.Qtype = uint8(s.Mode >> 24)
+ return
+}
+
+func (as Attrs) WriteStat(s *proto.Stat) error {
+ return nil
+}
+
+func (as Attrs) SetParent(p fs.Dir) {
+}
+
+func (as Attrs) Parent() fs.Dir {
+ return nil
+}
+
+func (as Attrs) Children() (cs map[string]fs.FSNode) {
+ log.Infof("Attrs#Children()")
+ cs = make(map[string]fs.FSNode)
+ ff := func(k string) fs.FSNode {
+ return fs.NewDynamicFile(
+ oFS.NewStat(k, un, gn, 0666),
+ func() []byte {
+ var v string
+ for _, a := range *as.attrs {
+ if a.Key == k {
+ v = a.Val
+ }
+ }
+ return []byte(v)
+ },
+ )
+ }
+ for _, attr := range *as.attrs {
+ cs[attr.Key] = ff(attr.Key)
+ }
+ return
+}
--- a/browser/fs/fs.go
+++ b/browser/fs/fs.go
@@ -25,21 +25,27 @@
gn string
cssDir *fs.StaticDir
jsDir *fs.StaticDir
- html string
- DOM Queryable
+ htm string
+ rt *Node
Client *http.Client
Fetcher opossum.Fetcher
)
-type Queryable interface {
- Query(q string) ([]*nodes.Node, error)
-}
-
func init() {
mu = &sync.RWMutex{}
c = sync.NewCond(mu)
+ SetDOM(nil)
}
+func SetDOM(d *nodes.Node) {
+ if rt == nil {
+ rt = &Node{
+ name: "0",
+ }
+ }
+ rt.nt = d
+}
+
func Srv9p() {
c.L.Lock()
var root *fs.StaticDir
@@ -64,7 +70,7 @@
mu.RLock()
defer mu.RUnlock()
- return []byte(html)
+ return []byte(htm)
},
)
root.AddChild(h)
@@ -87,6 +93,7 @@
q := fs.NewListenFile(oFS.NewStat("query", un, gn, 0600))
root.AddChild(q)
lq := (*fs.ListenFileListener)(q)
+ root.AddChild(rt)
go Query(lq)
if Client != nil {
xhr := fs.NewListenFile(oFS.NewStat("xhr", un, gn, 0600))
@@ -125,11 +132,11 @@
}
l = strings.TrimSpace(l)
- if DOM == nil {
+ if rt.nt == nil {
log.Infof("DOM is nil")
return
}
- nodes, err := DOM.Query(l)
+ nodes, err := rt.nt.Query(l)
if err != nil {
log.Errorf("query nodes: %v", err)
return
@@ -190,7 +197,7 @@
}
}
-func Update(htm string, css []string, js []string) {
+func Update(html string, css []string, js []string) {
c.L.Lock()
defer c.L.Unlock()
@@ -198,7 +205,7 @@
c.Wait()
}
- html = htm
+ htm = html
if cssDir != nil {
for name := range cssDir.Children() {
cssDir.DeleteChild(name)
--- a/browser/website.go
+++ b/browser/website.go
@@ -99,7 +99,7 @@
}
scripts = js.Scripts(nt, downloads)
fs.Update(htm, csss, scripts)
- fs.DOM = nt
+ fs.SetDOM(nt)
log.Infof("JS pipeline start")
js.Stop()
jsProcessed, changed, err := processJS2()
@@ -152,7 +152,7 @@
}
fs.Update(htm, csss, scripts)
- fs.DOM = nt
+ fs.SetDOM(nt)
log.Flush()
}
--- a/js/js.go
+++ b/js/js.go
@@ -193,7 +193,7 @@
isJS := true
src := ""
- for _, a := range n.Attrs {
+ for _, a := range n.DomSubtree.Attr {
switch strings.ToLower(a.Key) {
case "type":
t, err := opossum.NewContentType(a.Val, nil)
--- a/js/js_test.go
+++ b/js/js_test.go
@@ -41,7 +41,7 @@
t.Fatalf(err.Error())
}
nt := nodes.NewNodeTree(doc, style.Map{}, make(map[*html.Node]style.Map), nil)
- fs.DOM = nt
+ fs.SetDOM(nt)
fs.Update(simpleHTML, nil, []string{string(buf), script})
NewJS(simpleHTML, nil, nil)
--- a/nodes/nodes.go
+++ b/nodes/nodes.go
@@ -14,7 +14,6 @@
DomSubtree *html.Node `json:"-"`
Text string
Wrappable bool
- Attrs []html.Attribute
style.Map
Children []*Node
parent *Node `json:"-"`
@@ -46,7 +45,6 @@
}
n = &Node{
DomSubtree: doc,
- Attrs: doc.Attr,
Map: ncs,
Children: make([]*Node, 0, 2),
parent: parent,
@@ -147,7 +145,7 @@
}
func (n *Node) Attr(k string) string {
- for _, a := range n.Attrs {
+ for _, a := range n.DomSubtree.Attr {
if a.Key == k {
return a.Val
}
@@ -156,7 +154,7 @@
}
func (n *Node) HasAttr(k string) bool {
- for _, a := range n.Attrs {
+ for _, a := range n.DomSubtree.Attr {
if a.Key == k {
return true
}