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)
+ }
+}