shithub: mycel

Download patch

ref: ac32db32e14093022a4e363f808659191ce43cca
parent: a5d269cda172e9612b99a5efca2e8d414dee3771
author: Philip Silva <philip.silva@protonmail.com>
date: Sat Jan 30 18:30:47 EST 2021

gcs

--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2020, Philip Silva <philip.silva@protonmail.com>
+Copyright (c) 2020-2021, Philip Silva <philip.silva@protonmail.com>
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
--- a/browser/website.go
+++ b/browser/website.go
@@ -120,7 +120,7 @@
 			log.Infof("Stop existing JS instance")
 			w.d.Stop()
 		}
-		w.d = domino.NewDomino(w.html)
+		w.d = domino.NewDomino(w.html, nt)
 		w.d.Start()
 		jsProcessed, err := processJS2(w.d, nt, codes)
 		if err == nil {
--- a/domino/domino.go
+++ b/domino/domino.go
@@ -29,13 +29,15 @@
 	initialized bool
 	loop       *eventloop.EventLoop
 	html       string
+	nt           *nodes.Node
 	outputHtml string
 	domChanged chan int
 }
 
-func NewDomino(html string) (d *Domino) {
+func NewDomino(html string, nt *nodes.Node) (d *Domino) {
 	d = &Domino{
 		html: html,
+		nt: nt,
 	}
 	return
 }
@@ -119,9 +121,28 @@
 		window.self = window;
 		addEventListener = function() {};
 		window.location.href = 'http://example.com';
-		window.getComputedStyle = function() {
-			// stub
-		}
+		var ___fq;
+		___fq = function(pre, el) {
+			var i, p = el.parentElement;
+
+			if (p) {
+				for (i = 0; i < p.children.length; i++) {
+					if (p.children[i] === el) {
+						return ___fq('', p) + ' > :nth-child(' + (i+1) + ')';
+					}
+				}
+			} else {
+				return el.tagName;
+			}
+		};
+		window.getComputedStyle = function(el, pseudo) {
+			this.el = el;
+			this.getPropertyValue = function(prop) {
+				return opossum.style(___fq('', el), pseudo, prop, arguments[2]);
+			};
+			return this;
+		};
+		Element.prototype.getClientRects = function() { /* I'm a stub */ return []; }
 		window.screen = {
 			width: 1280,
 			height: 1024
@@ -169,6 +190,7 @@
 					Buf  string `json:"buf"`
 					HTML string `json:"html"`
 					Referrer func() string `json:"referrer"`
+					Style func(string, string, string, string) string `json:"style"`
 				}
 
 				vm.SetFieldNameMapper(goja.TagFieldNameMapper("json", true))
@@ -176,6 +198,18 @@
 					HTML: d.html,
 					Buf:  "yolo",
 					Referrer: func() string { return "https://example.com" },
+					Style: func(sel, pseudo, prop, prop2 string) string {
+						res, err := d.nt.Query(sel)
+						if err != nil {
+							log.Errorf("query %v: %v", sel, err)
+							return ""
+						}
+						if len(res) != 1 {
+							log.Errorf("query %v: %v", res, err)
+							return ""
+						}
+						return res[0].Css(prop)
+					},
 				})
 			}
 
--- a/domino/domino_test.go
+++ b/domino/domino_test.go
@@ -3,6 +3,9 @@
 import (
 	"io/ioutil"
 	"github.com/psilva261/opossum/logger"
+	"github.com/psilva261/opossum/nodes"
+	"github.com/psilva261/opossum/style"
+	"golang.org/x/net/html"
 	"strings"
 	"testing"
 )
@@ -16,15 +19,16 @@
 `
 
 func init() {
+	f := false
 	t := true
 	DebugDumpJS = &t
-	logger.Quiet = &t
+	logger.Quiet = &f
 	logger.Init()
 	log = &logger.Logger{Debug: true}
 }
 
 func TestSimple(t *testing.T) {
-	d := NewDomino(simpleHTML)
+	d := NewDomino(simpleHTML, nil)
 	d.Start()
 	s := `
 	var state = 'empty';
@@ -52,7 +56,7 @@
 }
 
 func TestGlobals(t *testing.T) {
-	d := NewDomino(simpleHTML)
+	d := NewDomino(simpleHTML, nil)
 	d.Start()
 }
 
@@ -61,15 +65,9 @@
 	if err != nil {
 		t.Fatalf("%v", err)
 	}
-	d := NewDomino(simpleHTML)
+	d := NewDomino(simpleHTML, nil)
 	d.Start()
 	script := `
-	console.log('Hello!!');
-	//console.log(window.jQuery);
-	console.log(this);
-	Object.assign(this, window);
-	//console.log(this.jQuery);
-	console.log($);
 	$(document).ready(function() {
 		gfgf
 		console.log('yolo');
@@ -95,12 +93,72 @@
 	d.Stop()
 }
 
+func TestJQueryHide(t *testing.T) {
+	buf, err := ioutil.ReadFile("jquery-3.5.1.js")
+	if err != nil {
+		t.Fatalf("%v", err)
+	}
+	d := NewDomino(simpleHTML, nil)
+	d.Start()
+	script := `
+	$(document).ready(function() {
+		$('h1').hide();
+	});
+	`
+	_, err = d.Exec(string(buf) + ";" + script, true)
+	if 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)
+	}
+	if res != "display: none;" {
+		t.Fatal()
+	}
+	d.Stop()
+}
+
+func TestJQueryCss(t *testing.T) {
+	buf, err := ioutil.ReadFile("jquery-3.5.1.js")
+	if err != nil {
+		t.Fatalf("%v", err)
+	}
+	h := `
+	<html>
+	<body>
+	<h1 id="title" style="display: inline-block;">Hello</h1>
+	</body>
+	</html>
+	`
+	d := NewDomino(h, nil)
+	r := strings.NewReader(h)
+	doc, err := html.Parse(r)
+	if err != nil { t.Fatalf(err.Error()) }
+	d.nt = nodes.NewNodeTree(doc, style.Map{}, make(map[*html.Node]style.Map), nil)
+	d.Start()
+	_, err = d.Exec(string(buf), true)
+	if err != nil {
+		t.Fatalf("%v", err)
+	}
+	res, err := d.Exec("$('h1').css('display')", false)
+	t.Logf("res=%v", res)
+	if err != nil {
+		t.Fatalf("%v", err)
+	}
+	if res != "inline-block" {
+		t.Fatal()
+	}
+	d.Stop()
+}
+
 func TestGodoc(t *testing.T) {
 	buf, err := ioutil.ReadFile("godoc/pkg.html")
 	if err != nil {
 		t.Fatalf("%v", err)
 	}
-	d := NewDomino(string(buf))
+	d := NewDomino(string(buf), nil)
 	d.Start()
 	script := `
 	Object.assign(this, window);
@@ -124,7 +182,7 @@
 	if err != nil {
 		t.Fatalf("%v", err)
 	}
-	d := NewDomino(string(buf))
+	d := NewDomino(string(buf), nil)
 	d.Start()
 	script := `
 	Object.assign(this, window);
@@ -170,7 +228,7 @@
     //elem.dispatchEvent(event);
     console.log(window.location.href);
 	`
-	d := NewDomino(simpleHTML)
+	d := NewDomino(simpleHTML, nil)
 	d.Start()
 	_, err = d.Exec(SCRIPT, true)
 	if err != nil {
@@ -206,7 +264,7 @@
     	});
     });
 	`
-	d := NewDomino(simpleHTML)
+	d := NewDomino(simpleHTML, nil)
 	d.Start()
 	_, err = d.Exec(SCRIPT, true)
 	if err != nil {
@@ -268,7 +326,7 @@
     //elem.dispatchEvent(event);
     console.log(window.location.href);
 	`
-	d := NewDomino(simpleHTML)
+	d := NewDomino(simpleHTML, nil)
 	d.Start()
 	_, err = d.Exec(SCRIPT, true)
 	if err != nil {
@@ -292,7 +350,7 @@
 }
 
 func TestTrackChanges(t *testing.T) {
-	d := NewDomino(simpleHTML)
+	d := NewDomino(simpleHTML, nil)
 	d.Start()
 	_, err := d.Exec(``, true)
 	if err != nil {
@@ -415,7 +473,7 @@
 }*/
 
 func TestES6(t *testing.T) {
-	d := NewDomino(simpleHTML)
+	d := NewDomino(simpleHTML, nil)
 	d.Start()
 	script := `
 	console.log('Hello!!');
@@ -437,7 +495,7 @@
 }
 
 func TestWindowParent(t *testing.T) {
-	d := NewDomino(simpleHTML)
+	d := NewDomino(simpleHTML, nil)
 	d.Start()
 	script := `
 	console.log('Hello!!')
@@ -458,7 +516,7 @@
 }
 
 func TestReferrer(t *testing.T) {
-	d := NewDomino(simpleHTML)
+	d := NewDomino(simpleHTML, nil)
 	d.Start()
 	script := `
 	document.referrer;
--- a/nodes/experimental.go
+++ b/nodes/experimental.go
@@ -1,10 +1,39 @@
 package nodes
 
 import (
-	//"golang.org/x/net/html"
-	//"opossum/style"
-	//"strings"
+	"fmt"
+	"github.com/andybalholm/cascadia"
+	"golang.org/x/net/html"
 )
+
+func (n *Node) Query(s string) (ns []*Node, err error) {
+	cs, err := cascadia.Compile(s)
+	if err != nil {
+		return nil, fmt.Errorf("cssSel compile %v: %w", s, err)
+	}
+	var m func(doc *html.Node, nn *Node) *Node
+	m = func(doc *html.Node, nn *Node) *Node {
+		if nn.DomSubtree == doc {
+			return nn
+		}
+		for _, c := range nn.Children {
+			if res := m(doc, c); res != nil {
+				return res
+			}
+		}
+		return nil
+	}
+	if n == nil {
+		return nil, fmt.Errorf("nil node tree")
+	}
+	for _, el := range cascadia.QueryAll(n.DomSubtree, cs) {
+		if res := m(el, n); res != nil {
+			ns = append(ns, res)
+		}
+	}
+	return
+}
+
 func (n *Node) NumVClusters() (m int) {
 	if n.IsFlex() {
 		if n.IsFlexDirectionRow() {
--- /dev/null
+++ b/nodes/experimental_test.go
@@ -1,0 +1,32 @@
+package nodes
+
+import (
+	"golang.org/x/net/html"
+	"github.com/psilva261/opossum/style"
+	"strings"
+	"testing"
+)
+
+func TestQuery(t *testing.T) {
+	buf := strings.NewReader(`
+	<html>
+		<body>
+			<p>
+				<b>bold stuff</b>
+				<i>italic stuff</i>
+				<a>link</a>
+			</p>
+		</body>
+	</html>`)
+	doc, err := html.Parse(buf)
+	if err != nil { t.Fatalf(err.Error()) }
+	nt := NewNodeTree(doc, style.Map{}, make(map[*html.Node]style.Map), nil)
+	res, _ := nt.Query("b")
+	if len(res) != 1 || res[0].Data() != "b" {
+		t.Errorf("%+v", res)
+	}
+	res, _ = nt.Query("HTML > :nth-child(2) > :nth-child(1) > :nth-child(2)")
+	if len(res) != 1 || res[0].Data() != "i" {
+		t.Errorf("%+v", res[0])
+	}
+}
\ No newline at end of file