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
}