ref: 52ebaa6c60bf90f3b7b326b94723c1999ea99655
parent: c9c7b73c0740cf8d6bdd6469226b4d4b2001cb9e
author: Philip Silva <philip.silva@protonmail.com>
date: Sun Feb 7 16:35:35 EST 2021
take mutation events into account
--- a/browser/browser.go
+++ b/browser/browser.go
@@ -492,6 +492,7 @@
if !consumed {return
}
+ log.Infof("click processed")offset := scroller.Offset
browser.Website.html = res
--- a/browser/experimental.go
+++ b/browser/experimental.go
@@ -120,12 +120,12 @@
})
}
-func processJS2(d *domino.Domino, scripts []string) (resHtm string, err error) {+func processJS2(d *domino.Domino, scripts []string) (resHtm string, changed bool, err error) {initialized := false
for _, script := range scripts { if _, err := d.Exec/*6*/(script, !initialized); err != nil { if strings.Contains(err.Error(), "halt at") {- return "", fmt.Errorf("execution halted: %w", err)+ return "", false, fmt.Errorf("execution halted: %w", err)}
log.Errorf("exec <script>: %v", err)}
@@ -133,12 +133,12 @@
}
if err = d.CloseDoc(); err != nil {- return "", fmt.Errorf("close doc: %w", err)+ return "", false, fmt.Errorf("close doc: %w", err)}
- resHtm, changed, err := d.TrackChanges()
+ resHtm, changed, err = d.TrackChanges()
if err != nil {- return "", fmt.Errorf("track changes: %w", err)+ return "", false, fmt.Errorf("track changes: %w", err)}
log.Printf("processJS: changed = %v", changed)return
--- a/browser/experimental_test.go
+++ b/browser/experimental_test.go
@@ -53,7 +53,7 @@
`$('body').hide()`,`throw 'fail';`,
}
- h, err = processJS2(d, scripts)
+ h, _, err = processJS2(d, scripts)
if err != nil { t.Errorf(err.Error()) } t.Logf("h = %+v", h) if !strings.Contains(h, `<body style="display: none;">`) {--- a/browser/website.go
+++ b/browser/website.go
@@ -122,17 +122,14 @@
}
w.d = domino.NewDomino(w.html, browser, nt)
w.d.Start()
- jsProcessed, err := processJS2(w.d, codes)
- if err == nil {- if w.html != jsProcessed {- log.Infof("html changed")- }
+ jsProcessed, changed, err := processJS2(w.d, codes)
+ if changed && err == nil {w.html = jsProcessed
if debugPrintHtml { log.Printf("%v\n", jsProcessed)}
doc, nodeMap = pass(w.html, csss...)
- } else {+ } else if err != nil { log.Errorf("JS error: %v", err)}
log.Infof("JS pipeline end")--- a/domino/domino.go
+++ b/domino/domino.go
@@ -31,6 +31,12 @@
log = l
}
+type Mutation struct {+ time.Time
+ Type int
+ Sel string
+}
+
type Domino struct {fetcher opossum.Fetcher
loop *eventloop.EventLoop
@@ -37,7 +43,7 @@
html string
nt *nodes.Node
outputHtml string
- domChanged chan int
+ domChange chan Mutation
}
func NewDomino(html string, fetcher opossum.Fetcher, nt *nodes.Node) (d *Domino) {@@ -45,6 +51,7 @@
html: html,
fetcher: fetcher,
nt: nt,
+ domChange: make(chan Mutation, 100),
}
return
}
@@ -144,7 +151,12 @@
window.location.href = 'http://example.com';
var ___fq;
___fq = function(pre, el) {- var i, p = el.parentElement;
+ var i, p;
+
+ if (!el) {+ return undefined;
+ }
+ p = el.parentElement;
if (p) { for (i = 0; i < p.children.length; i++) {@@ -156,6 +168,11 @@
return el.tagName;
}
};
+ document._setMutationHandler(function(a) {+ // a provides attributes type, target and node or attr
+ // (cf Object.keys(a))
+ opossum.mutated(a.type, ___fq('yolo', a.target));+ });
window.getComputedStyle = function(el, pseudo) {this.el = el;
this.getPropertyValue = function(prop) {@@ -254,6 +271,7 @@
Referrer func() string `json:"referrer"`
Style func(string, string, string, string) string `json:"style"`
XHR func(string, string, map[string]string, string, func(string, string)) `json:"xhr"`
+ Mutated func(int, string) `json:"mutated"`
}
vm.SetFieldNameMapper(goja.TagFieldNameMapper("json", true))@@ -274,6 +292,7 @@
return res[0].Css(prop)
},
XHR: d.xhr,
+ Mutated: d.mutated,
})
}
@@ -341,7 +360,7 @@
// CloseDoc fires DOMContentLoaded to trigger $(document).ready(..)
func (d *Domino) CloseDoc() (err error) {- _, err = d.Exec("document.close();", false)+ _, err = d.Exec("if (this.document) document.close();", false)return
}
@@ -394,11 +413,23 @@
}
func (d *Domino) TrackChanges() (html string, changed bool, err error) {- html, err = d.Exec("document.querySelector('html').innerHTML;", false)- if err != nil {- return
+ outer:
+ for {+ select {+ case m := <-d.domChange:
+ log.Infof("mutation received @ %v for %v", m.Time, m.Sel)+ changed = true
+ default:
+ break outer
+ }
}
- changed = d.outputHtml != html
+
+ if changed {+ html, err = d.Exec("document.querySelector('html').innerHTML;", false)+ if err != nil {+ return
+ }
+ }
d.outputHtml = html
return
}
@@ -526,6 +557,21 @@
return
}
cb(string(bs), "")
+}
+
+func (d *Domino) mutated(t int, q string) {+ m := Mutation{+ Time: time.Now(),
+ Type: t,
+ Sel: q,
+ }
+ log.Infof("mutation received: %+v", m)+ select {+ case d.domChange <- m:
+ default:
+ // TODO: that's not supposed to happen
+ log.Errorf("dom changes backlog full")+ }
}
// AJAX:
--- a/domino/domino_test.go
+++ b/domino/domino_test.go
@@ -395,9 +395,6 @@
if err != nil {t.Fatalf(err.Error())
}
- if html == "" {- t.Fatalf(err.Error())
- }
if changed == true {t.Fatal()
}
@@ -406,9 +403,6 @@
if err != nil {t.Fatalf(err.Error())
}
- if html == "" {- t.Fatalf(err.Error())
- }
if changed == true {t.Fatal()
}
@@ -652,5 +646,31 @@
t.Fatalf("%v", err)}
t.Logf("res=%v", res)+ d.Stop()
+}
+
+func TestMutationEvents(t *testing.T) {+ buf, err := ioutil.ReadFile("jquery-3.5.1.js")+ if err != nil {+ t.Fatalf("%v", err)+ }
+ d := NewDomino(simpleHTML, nil, nil)
+ d.Start()
+ script := `
+ $('h1').hide();+ $('h1').show();+ `
+ _, err = d.Exec(string(buf) + ";" + script, true)
+ if err != nil {+ t.Fatalf("%v", err)+ }
+ if err = d.CloseDoc(); err != nil {+ t.Fatalf("%v", err)+ }
+ res, err := d.Exec("$('h1').attr('style')", false)+ t.Logf("res=%v", res)+ if err != nil {+ t.Fatalf("%v", err)+ }
d.Stop()
}
--
⑨