shithub: mycel

Download patch

ref: 09b964472704c60ee0aa9a34d00e82316b94f952
parent: ba613e27cf2a4a29fc5a8955f3f782d1881205f8
author: Philip Silva <philip.silva@protonmail.com>
date: Thu Mar 20 10:13:15 EDT 2025

unglobal browser variable

--- a/browser/browser.go
+++ b/browser/browser.go
@@ -64,7 +64,6 @@
 )
 
 var (
-	browser  *Browser
 	Style    = style.Map{}
 	dui      *duit.DUI
 	scroller *duitx.Scroll
@@ -94,7 +93,7 @@
 	}
 }
 
-func NewText(content []string, n *nodes.Node) (el []*Element) {
+func NewText(b *Browser, content []string, n *nodes.Node) (el []*Element) {
 	tt := strings.Join(content, " ")
 
 	// '\n' is nowhere visible
@@ -111,6 +110,7 @@
 		}
 
 		l := &Element{
+			b: b,
 			UI: NewLabel(t, n),
 			n:  n,
 		}
@@ -170,8 +170,8 @@
 	src string
 }
 
-func NewImage(n *nodes.Node) duit.UI {
-	img, err := newImage(n)
+func NewImage(b *Browser, n *nodes.Node) duit.UI {
+	img, err := newImage(b, n)
 	if err != nil {
 		log.Errorf("could not load image: %v", err)
 		return &duit.Label{}
@@ -179,7 +179,7 @@
 	return img
 }
 
-func newImage(n *nodes.Node) (ui duit.UI, err error) {
+func newImage(b *Browser, n *nodes.Node) (ui duit.UI, err error) {
 	var i *draw.Image
 	var cached bool
 	src := attr(*n.DomSubtree, "src")
@@ -223,7 +223,7 @@
 		mw = dui.Scale(mw)
 		w := dui.Scale(n.Width())
 		h := dui.Scale(n.Height())
-		i, err = img.Load(dui, browser, src, mw, w, h, false)
+		i, err = img.Load(dui, b, src, mw, w, h, false)
 		if err != nil {
 			return nil, fmt.Errorf("load image: %w", err)
 		}
@@ -232,6 +232,7 @@
 
 img_elem:
 	return NewElement(
+		b,
 		&Image{
 			Image: &duit.Image{
 				Image: i,
@@ -299,6 +300,7 @@
 
 type Element struct {
 	duit.UI
+	b       *Browser
 	n       *nodes.Node
 	orig    image.Point
 	IsLink  bool
@@ -309,7 +311,7 @@
 	rect image.Rectangle
 }
 
-func NewElement(ui duit.UI, n *nodes.Node) *Element {
+func NewElement(b *Browser, ui duit.UI, n *nodes.Node) *Element {
 	if ui == nil {
 		return nil
 	}
@@ -328,6 +330,7 @@
 	}
 
 	el := &Element{
+		b: b,
 		UI: ui,
 		n:  n,
 	}
@@ -524,10 +527,10 @@
 		Font:  n.Font(),
 		Click: click,
 	}
-	return NewElement(btn, n)
+	return NewElement(b, btn, n)
 }
 
-func NewInputField(n *nodes.Node) *Element {
+func NewInputField(b *Browser, n *nodes.Node) *Element {
 	t := attr(*n.DomSubtree, "type")
 	if n.Css("width") == "" && n.Css("max-width") == "" {
 		n.SetCss("max-width", "200px")
@@ -548,9 +551,9 @@
 				if f == nil {
 					return
 				}
-				if !browser.loading {
-					browser.loading = true
-					go browser.submit(f.DomSubtree, nil)
+				if !b.loading {
+					b.loading = true
+					go b.submit(f.DomSubtree, nil)
 				}
 				return duit.Event{
 					Consumed:   true,
@@ -561,10 +564,10 @@
 			return
 		},
 	}
-	return NewElement(f, n)
+	return NewElement(b, f, n)
 }
 
-func NewSelect(n *nodes.Node) *Element {
+func NewSelect(b *Browser, n *nodes.Node) *Element {
 	var l *duit.List
 	l = &duit.List{
 		Values: make([]*duit.ListValue, 0, len(n.Children)),
@@ -597,10 +600,10 @@
 	if n.Css("height") == "" {
 		n.SetCss("height", fmt.Sprintf("%vpx", 4*n.Font().Height))
 	}
-	return NewElement(duit.NewScroll(l), n)
+	return NewElement(b, duit.NewScroll(l), n)
 }
 
-func NewTextArea(n *nodes.Node) *Element {
+func NewTextArea(b *Browser, n *nodes.Node) *Element {
 	t := n.ContentString(true)
 	lines := len(strings.Split(t, "\n"))
 	edit := &duit.Edit{
@@ -616,7 +619,7 @@
 		n.SetCss("height", fmt.Sprintf("%vpx", (int(n.FontHeight())*(lines+2))))
 	}
 
-	el := NewElement(edit, n)
+	el := NewElement(b, edit, n)
 	el.Changed = func(e *Element) {
 		ed := e.UI.(*duitx.Box).Kids[0].UI.(*duit.Edit)
 
@@ -775,7 +778,7 @@
 			dui.WriteSnarf([]byte(s))
 		}
 	} else if selected > 0 && m.Buttons == 1 {
-		TraverseTree(browser.Website.UI, func(ui duit.UI) {
+		TraverseTree(el.b.Website.UI, func(ui duit.UI) {
 			l, ok := ui.(*duitx.Label)
 			if ok && l.Selected {
 				selected--
@@ -822,7 +825,7 @@
 			log.Errorf("trigger click %v: %v", q, err)
 		} else if consumed {
 			offset := scroller.Offset
-			browser.Website.layout(browser, res, ClickRelayout)
+			el.b.Website.layout(el.b, res, ClickRelayout)
 			scroller.Offset = offset
 			dui.MarkLayout(dui.Top.UI)
 			dui.MarkDraw(dui.Top.UI)
@@ -844,12 +847,12 @@
 		return
 	}
 
-	u, err := browser.LinkedUrl(href)
+	u, err := el.b.LinkedUrl(href)
 	if err != nil {
 		log.Errorf("makeLink from %v: %v", href, err)
 		return
 	}
-	f := browser.SetAndLoadUrl(u)
+	f := el.b.SetAndLoadUrl(u)
 	TraverseTree(el, func(ui duit.UI) {
 		el, ok := ui.(*Element)
 		if ok && el != nil {
@@ -932,7 +935,7 @@
 }
 
 // arrangeAbsolute positioned elements, if any
-func arrangeAbsolute(n *nodes.Node, elements ...*Element) (ael *Element, ok bool) {
+func arrangeAbsolute(b *Browser, n *nodes.Node, elements ...*Element) (ael *Element, ok bool) {
 	absolutes := make([]*Element, 0, 1)
 	other := make([]*Element, 0, len(elements))
 
@@ -954,7 +957,7 @@
 		log.Fatalf("%v", err)
 	}
 	uis := make([]duit.UI, 0, len(other)+1)
-	na := Arrange(n, other...)
+	na := Arrange(b, n, other...)
 	if na != nil {
 		uis = append(uis, na)
 	}
@@ -967,19 +970,20 @@
 	}
 	pl.Place = placeFunc(n.QueryRef(), pl)
 
-	return NewElement(pl, n), true
+	return NewElement(b, pl, n), true
 }
 
-func Arrange(n *nodes.Node, elements ...*Element) *Element {
-	if ael, ok := arrangeAbsolute(n, elements...); ok {
+func Arrange(b *Browser, n *nodes.Node, elements ...*Element) *Element {
+	if ael, ok := arrangeAbsolute(b, n, elements...); ok {
 		return ael
 	}
 
-	ui := horizontalSeq(n, true, elements)
+	ui := horizontalSeq(b, n, true, elements)
 	if ui == nil {
 		return nil
 	}
 	el := &Element{
+		b: b,
 		n:  n,
 		UI: ui,
 	}
@@ -987,7 +991,7 @@
 	return el
 }
 
-func horizontalSeq(parent *nodes.Node, wrap bool, es []*Element) duit.UI {
+func horizontalSeq(b *Browser, parent *nodes.Node, wrap bool, es []*Element) duit.UI {
 	if len(es) == 0 {
 		return nil
 	}
@@ -998,7 +1002,7 @@
 		if isLabel {
 			tts := strings.Split(label.Text, " ")
 			for _, t := range tts {
-				finalUis = append(finalUis, NewElement(&duit.Label{
+				finalUis = append(finalUis, NewElement(b, &duit.Label{
 					Text: t,
 					Font: label.Font,
 				}, el.n))
@@ -1010,11 +1014,11 @@
 		}
 	}
 
-	b, ok := newBoxElement(parent, true, finalUis...)
+	box, ok := newBoxElement(parent, true, finalUis...)
 	if !ok {
 		return nil
 	}
-	return b
+	return box
 }
 
 func duitDisplay(n *nodes.Node) duitx.Display {
@@ -1173,6 +1177,7 @@
 		}
 
 		return NewElement(
+			b,
 			&duitx.Grid{
 				Columns:  numCols,
 				Rows:     len(t.rows),
@@ -1193,17 +1198,17 @@
 			for _, col := range row.columns {
 				ui := NodeToBox(r+1, b, col)
 				if ui != nil {
-					el := NewElement(ui, col)
+					el := NewElement(b, ui, col)
 					rowEls = append(rowEls, el)
 				}
 			}
 
 			if len(rowEls) > 0 {
-				seq := horizontalSeq(nil, false, rowEls)
-				seqs = append(seqs, NewElement(seq, row.n))
+				seq := horizontalSeq(b, nil, false, rowEls)
+				seqs = append(seqs, NewElement(b, seq, row.n))
 			}
 		}
-		return NewElement(verticalSeq(seqs), n)
+		return NewElement(b, verticalSeq(seqs), n)
 	}
 }
 
@@ -1272,14 +1277,14 @@
 		case "input":
 			t := n.Attr("type")
 			if t == "" || t == "text" || t == "email" || t == "search" || t == "password" {
-				return NewInputField(n)
+				return NewInputField(b, n)
 			} else if t == "submit" {
 				return NewSubmitButton(b, n)
 			}
 		case "select":
-			return NewSelect(n)
+			return NewSelect(b, n)
 		case "textarea":
-			return NewTextArea(n)
+			return NewTextArea(b, n)
 		case "button":
 			if t := n.Attr("type"); t == "" || t == "submit" {
 				return NewSubmitButton(b, n)
@@ -1290,13 +1295,14 @@
 				Font: n.Font(),
 			}
 
-			return NewElement(btn, n)
+			return NewElement(b, btn, n)
 		case "table":
 			return NewTable(n).Element(r+1, b, n)
 		case "picture", "img", "svg":
-			return NewElement(NewImage(n), n)
+			return NewElement(b, NewImage(b, n), n)
 		case "pre":
 			return NewElement(
+				b,
 				NewCodeView(n.ContentString(true), n.Map),
 				n,
 			)
@@ -1316,7 +1322,7 @@
 				return InnerNodesToBox(r+1, b, n)
 			}
 
-			return NewElement(innerContent, n)
+			return NewElement(b, innerContent, n)
 		case "a":
 			var href = n.Attr("href")
 			var innerContent duit.UI
@@ -1331,7 +1337,7 @@
 			if innerContent == nil {
 				return nil
 			}
-			el := NewElement(innerContent, n)
+			el := NewElement(b, innerContent, n)
 			el.makeLink(href)
 			return el
 		case "noscript":
@@ -1348,7 +1354,7 @@
 		if text := n.ContentString(false); text != "" {
 			ui := NewLabel(text, n)
 
-			return NewElement(ui, n)
+			return NewElement(b, ui, n)
 		}
 	}
 
@@ -1375,15 +1381,15 @@
 			continue
 		}
 		if isWrapped(c) {
-			ls := NewText(c.Content(false), c)
+			ls := NewText(b, c.Content(false), c)
 			els = append(els, ls...)
 		} else if nodes.IsPureTextContent(*n) && n.IsInline() {
 			// Handle text wrapped in unwrappable tags like p, div, ...
-			ls := NewText(c.Content(false), items[0])
+			ls := NewText(b, c.Content(false), items[0])
 			if len(ls) == 0 {
 				continue
 			}
-			el := NewElement(horizontalSeq(c, true, ls), c)
+			el := NewElement(b, horizontalSeq(b, c, true, ls), c)
 			if el == nil {
 				continue
 			}
@@ -1397,7 +1403,7 @@
 		return nil
 	}
 
-	return Arrange(n, els...)
+	return Arrange(b, n, els...)
 }
 
 func TraverseTree(ui duit.UI, f func(ui duit.UI)) {
@@ -1536,16 +1542,15 @@
 			Transport: tr,
 		},
 		dui:      _dui,
-		Website:  &Website{},
 		LocCh:    make(chan string, 10),
 		StatusCh: make(chan string, 10),
 	}
+	b.Website = &Website{b: b}
 	u, err := url.Parse(initUrl)
 	if err != nil {
 		log.Fatalf("parse: %v", err)
 	}
 	b.History.Push(u, 0)
-	browser = b
 	b.Website.UI = &duit.Label{}
 	style.SetFetcher(b)
 	dui = _dui
@@ -1558,7 +1563,7 @@
 
 	if ExperimentalJsInsecure {
 		fs.Client = &http.Client{}
-		fs.Fetcher = browser
+		fs.Fetcher = b
 	}
 	go fs.Srv9p()
 
--- a/browser/browser_test.go
+++ b/browser/browser_test.go
@@ -46,6 +46,7 @@
 }
 
 func TestArrange(t *testing.T) {
+	b := &Browser{}
 	htm := `
 		<div>
 			<h1>title 1</h1>
@@ -83,7 +84,7 @@
 			&Element{n: h2},
 			&Element{n: h3},
 		}
-		v := Arrange(nt, es...)
+		v := Arrange(b, nt, es...)
 		for _, e := range es {
 			if e.n.IsInline() != (d == "inline") {
 				t.Fatalf("%+v", e)
@@ -174,7 +175,6 @@
 	body := grep(doc, "body")
 	b := &Browser{}
 	b.client = &http.Client{}
-	browser = b
 	u, err := url.Parse("https://example.com")
 	if err != nil {
 		log.Fatalf("parse: %v", err)
@@ -204,7 +204,6 @@
 	body := grep(doc, "body")
 	b := &Browser{}
 	b.client = &http.Client{}
-	browser = b
 	u, err := url.Parse("https://example.com")
 	if err != nil {
 		return nil, nil, fmt.Errorf("parse url: %w", err)
@@ -441,6 +440,7 @@
 }
 
 func TestTextArea(t *testing.T) {
+	b := &Browser{}
 	htm := `
 		<textarea height="100">
 		</textarea>
@@ -451,7 +451,7 @@
 	}
 
 	ta := nt.Find("textarea")
-	el := NewTextArea(ta)
+	el := NewTextArea(b, ta)
 	// Trigger key press to trigger call to changed
 	el.Key(nil, nil, 'a', draw.Mouse{}, image.Point{})
 }
--- a/browser/website.go
+++ b/browser/website.go
@@ -21,6 +21,7 @@
 )
 
 type Website struct {
+	b *Browser
 	duit.UI
 	mycel.ContentType
 }
@@ -27,7 +28,7 @@
 
 func (w *Website) layout(f mycel.Fetcher, htm string, layouting int) {
 	defer func() {
-		browser.StatusCh <- ""
+		w.b.StatusCh <- ""
 	}()
 	pass := func(htm string, csss ...string) (*html.Node, map[*html.Node]style.Map) {
 		if f.Ctx().Err() != nil {
@@ -143,7 +144,7 @@
 		scroller.Free()
 		scroller = nil
 	}
-	scroller = duitx.NewScroll(dui, NodeToBox(0, browser, nt))
+	scroller = duitx.NewScroll(dui, NodeToBox(0, w.b, nt))
 	numElements := 0
 	TraverseTree(scroller, func(ui duit.UI) {
 		numElements++
@@ -153,7 +154,7 @@
 	if numElements < 10 {
 		log.Errorf("Less than 10 elements layouted, seems css processing failed. Will layout without css")
 		nt = nodes.NewNodeTree(body, style.Map{}, make(map[*html.Node]style.Map), nil)
-		scroller = duitx.NewScroll(dui, NodeToBox(0, browser, nt))
+		scroller = duitx.NewScroll(dui, NodeToBox(0, w.b, nt))
 		w.UI = scroller
 	}