shithub: mycel

Download patch

ref: 1ed39a3b5cabe073caf56302a1cfc21b11767653
parent: 3614c592baf9201189b264b61f5aa2e7bb477c68
author: Philip Silva <philip.silva@protonmail.com>
date: Tue Jan 12 15:00:25 EST 2021

textarea

--- a/browser/browser.go
+++ b/browser/browser.go
@@ -202,6 +202,7 @@
 	n       *nodes.Node
 	IsLink bool
 	Click  func() duit.Event
+	Changed func(*Element)
 }
 
 func NewElement(ui duit.UI, n *nodes.Node) *Element {
@@ -378,6 +379,54 @@
 	)
 }
 
+func NewTextArea(n *nodes.Node) *Element {
+	t := strings.TrimSpace(nodes.ContentFrom(*n))
+	formatted := ""
+	lines := strings.Split(t, "\n")
+	for _, line := range lines {
+		formatted += line + "\n"
+	}
+	edit := &duit.Edit{
+		Font: Style.Font(),
+		Keys: func(k rune, m draw.Mouse) (e duit.Event) {
+			// e.Consumed = true
+			return
+		},
+	}
+	edit.Append([]byte(formatted))
+
+	el := NewElement(
+		&duit.Box{
+			Kids:   duit.NewKids(edit),
+			Height: (int(n.FontSize()) + 4) * (len(lines)+2),
+		},
+		n,
+	)
+	el.Changed = func(e *Element) {
+		ed := e.UI.(*duit.Box).Kids[0].UI.(*duit.Edit)
+
+		tt, err := ed.Text()
+		if err != nil {
+			log.Errorf("edit changed: %v", err)
+			return
+		}
+
+		e.n.SetText(string(tt))
+	}
+
+	return el
+}
+
+func (el *Element) Key(dui *duit.DUI, self *duit.Kid, k rune, m draw.Mouse, orig image.Point) (r duit.Result) {
+	r = el.UI.Key(dui, self, k, m, orig)
+
+	if el.Changed != nil {
+		el.Changed(el)
+	}
+
+	return
+}
+
 func (el *Element) Mouse(dui *duit.DUI, self *duit.Kid, m draw.Mouse, origM draw.Mouse, orig image.Point) (r duit.Result) {
 	if el == nil {
 		return
@@ -781,23 +830,23 @@
 	return tr
 }
 
-func grepBody(n *html.Node) *html.Node {
-	var body *html.Node
+func grep(n *html.Node, tag string) *html.Node {
+	var t *html.Node
 
 	if n.Type == html.ElementNode {
-		if n.Data == "body" {
+		if n.Data == tag {
 			return n
 		}
 	}
 
 	for c := n.FirstChild; c != nil; c = c.NextSibling {
-		res := grepBody(c)
+		res := grep(c, tag)
 		if res != nil {
-			body = res
+			t = res
 		}
 	}
 
-	return body
+	return t
 }
 
 func NodeToBox(r int, b *Browser, n *nodes.Node) *Element {
@@ -822,6 +871,8 @@
 			} else {
 				return nil
 			}
+		case "textarea":
+			return NewTextArea(n)
 		case "button":
 			if t := attr(*n.DomSubtree, "type"); t == "" || t == "submit" {
 				return NewSubmitButton(b, n)
@@ -1011,10 +1062,11 @@
 	case *duit.Label:
 	case *ColoredLabel:
 		traverseTree(r+1, v.Label, f)
-	case *duit.Button:
 	case *Image:
 		traverseTree(r+1, v.Image, f)
 	case *duit.Field:
+	case *duit.Edit:
+	case *duit.Button:
 	case *CodeView:
 	default:
 		panic(fmt.Sprintf("unknown: %+v", v))
--- a/browser/browser_test.go
+++ b/browser/browser_test.go
@@ -83,7 +83,7 @@
 		t.Fatalf(err.Error())
 	}
 	nodeMap := make(map[*html.Node]style.Map)
-	body := grepBody(doc)
+	body := grep(doc, "body")
 	b := &Browser{}
 	b.client = &http.Client{}
 	browser = b
--- a/browser/website.go
+++ b/browser/website.go
@@ -147,7 +147,7 @@
 	}
 	log.Printf("%v html nodes found...", countHtmlNodes(doc))
 
-	body := grepBody(doc)
+	body := grep(doc, "body")
 
 	log.Printf("Layout website...")
 	scroller = duit.NewScroll(
@@ -171,19 +171,30 @@
 
 func formData(n, submitBtn *html.Node) (data url.Values) {
 	data = make(url.Values)
-	if n.Data == "input" {
+	nm := attr(*n, "name")
+
+	switch n.Data {
+	case "input":
 		if attr(*n, "type") == "submit" && n != submitBtn {
 			return
 		}
-		if k := attr(*n, "name"); k != "" {
-			data.Set(k, attr(*n, "value"))
+		if nm != "" {
+			data.Set(nm, attr(*n, "value"))
 		}
+	case "textarea":
+		nn := nodes.NewNodeTree(n, style.Map{}, make(map[*html.Node]style.Map), nil)
+
+		if nm != "" {
+			data.Set(nm, nodes.ContentFrom(*nn))
+		}
 	}
+
 	for c := n.FirstChild; c != nil; c = c.NextSibling {
 		for k, vs := range formData(c, submitBtn) {
 			data.Set(k, vs[0]) // TODO: what aboot the rest?
 		}
 	}
+
 	return
 }
 
--- /dev/null
+++ b/browser/website_test.go
@@ -1,0 +1,25 @@
+package browser
+
+import (
+	"golang.org/x/net/html"
+	"strings"
+	"testing"
+)
+
+func TestFormData(t *testing.T) {
+	htm := `<form>
+		<input name=a value=1>
+		<textarea name=b>2</textarea>
+	</form>`
+	doc, err := html.Parse(
+		strings.NewReader(string(htm)),
+	)
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+	f := grep(doc, "form")
+	data := formData(f, nil)
+	if len(data) != 2 {
+		t.Fatalf("%+v", f)
+	}
+}
--- a/go.sum
+++ b/go.sum
@@ -2,7 +2,6 @@
 github.com/PuerkitoBio/goquery v1.6.0/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
 github.com/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5zzsLTo=
 github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
-github.com/chris-ramon/douceur v0.2.0 h1:IDMEdxlEUUBYBKE4z/mJnFyVXox+MjuEVDJNN27glkU=
 github.com/chris-ramon/douceur v0.2.1-0.20160603235419-f3463056cd52 h1:xJWyi77j4VQwdeo6bO3wQSQ7o7yVwEM0ZvwXpyKHZZ8=
 github.com/chris-ramon/douceur v0.2.1-0.20160603235419-f3463056cd52/go.mod h1:wDW5xjJdeoMm1mRt4sD4c/LbF/mWdEpRXQKjTR8nIBE=
 github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk=
@@ -27,8 +26,6 @@
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/mjl-/duit v0.0.0-20200330125617-580cb0b2843f h1:eGFou1VfXmiti7EMQED6BIzfALMYi6/fBMIRL4usKfw=
 github.com/mjl-/duit v0.0.0-20200330125617-580cb0b2843f/go.mod h1:OlRagobzQ97GoM+WaQ5kyzdyts952BFYsuY5bMyv9tw=
-github.com/mjl-/go v0.0.0-20180429123528-fafada5f286e h1:M6KcUwCT34dkXLeYORteGPNguMsAaYkE/IBGKRGXFUI=
-github.com/mjl-/go v0.0.0-20180429123528-fafada5f286e/go.mod h1:G+1evjukGD/lUyIfAq/sr0YX5EcukfBUeA+tFPF5JUA=
 github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
 github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
 github.com/psilva261/css v0.1.0 h1:lzQtXIUKSdH7s6Vi4SeOt1YnTWFY2O/H//rujTGcu10=
--- a/nodes/nodes.go
+++ b/nodes/nodes.go
@@ -210,3 +210,32 @@
 	return b.String(), err
 }
 
+// SetText by replacing child nodes with a TextNode containing t.
+func (n *Node) SetText(t string) {
+	d := n.DomSubtree
+
+	if len(n.Children) != 1 || n.Type() != html.TextNode {
+		for d.FirstChild != nil {
+			d.RemoveChild(d.FirstChild)
+		}
+
+		c := &html.Node{
+			Parent: d,
+			Type: html.TextNode,
+		}
+		d.FirstChild = c
+
+		n.Children = []*Node{
+			&Node{
+				DomSubtree: c,
+				Wrappable: true,
+				Parent: n,
+			},
+		}
+	}
+	
+	n.Children[0].Text = t
+	n.Children[0].DomSubtree.Data = t
+	
+	return
+}
--- a/nodes/nodes_test.go
+++ b/nodes/nodes_test.go
@@ -32,4 +32,18 @@
 	p := nt.Children[0].Children[1].Children[1]
 	a := p.Children[5]
 	if q := a.QueryRef(); q != "p a" { t.Fatalf("%v", q) }
-}
\ No newline at end of file
+}
+
+func TestSetText(t *testing.T) {
+	buf := strings.NewReader("<textarea>initial</textarea>")
+	doc, err := html.Parse(buf)
+	if err != nil { t.Fatalf(err.Error()) }
+	n := NewNodeTree(doc, style.Map{}, make(map[*html.Node]style.Map), nil)
+	if s := ContentFrom(*n); s != "initial" {
+		t.Fatalf(s)
+	}
+	n.SetText("123")
+	if s := ContentFrom(*n); s != "123" {
+		t.Fatalf(s)
+	}
+}