|
@@ -1,21 +1,8 @@
|
|
|
package vdom
|
|
|
|
|
|
-import (
|
|
|
- "reflect"
|
|
|
- "fmt"
|
|
|
-)
|
|
|
+import "kumachan/standalone/ctn"
|
|
|
|
|
|
|
|
|
-type Map interface {
|
|
|
- Has(string) bool
|
|
|
- Lookup(string) (interface{}, bool)
|
|
|
- ForEach(func(string,interface{}))
|
|
|
-}
|
|
|
-type EmptyMap struct {}
|
|
|
-func (_ EmptyMap) Has(string) bool { return false }
|
|
|
-func (_ EmptyMap) Lookup(string) (interface{},bool) { return nil, false }
|
|
|
-func (_ EmptyMap) ForEach(func(string,interface{})) {}
|
|
|
-
|
|
|
type Node struct {
|
|
|
Tag string
|
|
|
Props
|
|
@@ -27,33 +14,17 @@ type Props struct {
|
|
|
Styles *Styles
|
|
|
Events *Events
|
|
|
}
|
|
|
-type Attrs struct {
|
|
|
- // string -> string
|
|
|
- Data Map
|
|
|
-}
|
|
|
-type Styles struct {
|
|
|
- // string -> string
|
|
|
- Data Map
|
|
|
-}
|
|
|
-type Events struct {
|
|
|
- // string -> *EventHandler
|
|
|
- Data Map
|
|
|
-}
|
|
|
-var emptyAttrs = &Attrs { Data: EmptyMap {} }
|
|
|
-var emptyStyles = &Styles { Data: EmptyMap {} }
|
|
|
-var emptyEvents = &Events { Data: EmptyMap {} }
|
|
|
-var emptyContent = &Children {}
|
|
|
-func EmptyAttrs() *Attrs { return emptyAttrs }
|
|
|
-func EmptyStyles() *Styles { return emptyStyles }
|
|
|
-func EmptyEvents() *Events { return emptyEvents }
|
|
|
-func EmptyContent() Content { return emptyContent }
|
|
|
+type Attrs struct { Data ctn.Map[string,string] }
|
|
|
+type Styles struct { Data ctn.Map[string,string] }
|
|
|
+type Events struct { Data ctn.Map[string,*EventHandler] }
|
|
|
+type EventHandler struct { Handler interface{} }
|
|
|
|
|
|
-type Content interface { NodeContent() }
|
|
|
-func (impl *Text) NodeContent() {}
|
|
|
+type Content interface { impl(Content) }
|
|
|
+ func(*Text) impl(Content) {}
|
|
|
+ func(*Children) impl(Content) {
|
|
|
+}
|
|
|
type Text string
|
|
|
-func (impl *Children) NodeContent() {}
|
|
|
type Children ([] *Node)
|
|
|
-type EventHandler struct { Handler interface{} }
|
|
|
|
|
|
type DeltaNotifier struct {
|
|
|
ApplyStyle func(id string, key string, value string)
|
|
@@ -72,29 +43,6 @@ type DeltaNotifier struct {
|
|
|
MoveNode func(parent string, id string, pivot string)
|
|
|
}
|
|
|
|
|
|
-func assert(ok bool) {
|
|
|
- if !(ok) { panic("assertion failed") }
|
|
|
-}
|
|
|
-
|
|
|
-func get_addr(ptr interface{}) string {
|
|
|
- var n = reflect.ValueOf(ptr).Pointer()
|
|
|
- return string(fmt.Sprintf("%X", n))
|
|
|
-}
|
|
|
-
|
|
|
-func detach_all_events(ctx *DeltaNotifier, node *Node) {
|
|
|
- var node_id = get_addr(node)
|
|
|
- node.Events.Data.ForEach(func(name string, val interface{}) {
|
|
|
- var handler = val.(*EventHandler)
|
|
|
- ctx.DetachEvent(node_id, name, handler)
|
|
|
- })
|
|
|
- var children, has_children = node.Content.(*Children)
|
|
|
- if has_children {
|
|
|
- for _, child := range *children {
|
|
|
- detach_all_events(ctx, child)
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
func Diff(ctx *DeltaNotifier, parent *Node, old *Node, new *Node) {
|
|
|
assert(ctx != nil)
|
|
|
assert(old != nil || new != nil)
|
|
@@ -124,19 +72,17 @@ func Diff(ctx *DeltaNotifier, parent *Node, old *Node, new *Node) {
|
|
|
if new_styles == old_styles {
|
|
|
goto skip_styles
|
|
|
}
|
|
|
- old_styles.Data.ForEach(func(key string, _ interface{}) {
|
|
|
+ old_styles.Data.ForEach(func(key string, _ string) {
|
|
|
if !(new_styles.Data.Has(key)) {
|
|
|
ctx.EraseStyle(id, key)
|
|
|
}
|
|
|
})
|
|
|
}
|
|
|
- new_styles.Data.ForEach(func(key string, val_ interface{}) {
|
|
|
- var val = val_.(string)
|
|
|
+ new_styles.Data.ForEach(func(key string, val string) {
|
|
|
if old != nil {
|
|
|
- var old_val_, exists = old.Styles.Data.Lookup(key)
|
|
|
+ var old_val, exists = old.Styles.Data.Lookup(key)
|
|
|
if exists {
|
|
|
if exists {
|
|
|
- var old_val = old_val_.(string)
|
|
|
if old_val == val {
|
|
|
goto skip_this_style
|
|
|
}
|
|
@@ -153,24 +99,22 @@ func Diff(ctx *DeltaNotifier, parent *Node, old *Node, new *Node) {
|
|
|
if new_attrs == old_attrs {
|
|
|
goto skip_attrs
|
|
|
}
|
|
|
- old_attrs.Data.ForEach(func(name string, _ interface{}) {
|
|
|
+ old_attrs.Data.ForEach(func(name string, _ string) {
|
|
|
if !(new_attrs.Data.Has(name)) {
|
|
|
ctx.RemoveAttr(id, name)
|
|
|
}
|
|
|
})
|
|
|
}
|
|
|
- new_attrs.Data.ForEach(func(name string, val_ interface{}) {
|
|
|
- var val = val_.(string)
|
|
|
+ new_attrs.Data.ForEach(func(name string, new_val string) {
|
|
|
if old != nil {
|
|
|
- var old_val_, exists = old.Attrs.Data.Lookup(name)
|
|
|
+ var old_val, exists = old.Attrs.Data.Lookup(name)
|
|
|
if exists {
|
|
|
- var old_val = old_val_.(string)
|
|
|
- if old_val == val {
|
|
|
+ if old_val == new_val {
|
|
|
goto skip_this_attr
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- ctx.SetAttr(id, name, val)
|
|
|
+ ctx.SetAttr(id, name, new_val)
|
|
|
skip_this_attr:
|
|
|
})
|
|
|
skip_attrs:
|
|
@@ -180,29 +124,25 @@ func Diff(ctx *DeltaNotifier, parent *Node, old *Node, new *Node) {
|
|
|
if old_events == new_events {
|
|
|
goto skip_events
|
|
|
}
|
|
|
- old_events.Data.ForEach(func(key string, val interface{}) {
|
|
|
- var old_name = key
|
|
|
- var old_handler = val.(*EventHandler)
|
|
|
- var new_handler_, name_in_new = new_events.Data.Lookup(old_name)
|
|
|
+ old_events.Data.ForEach(func(name string, old_handler *EventHandler) {
|
|
|
+ var new_handler, name_in_new = new_events.Data.Lookup(name)
|
|
|
if name_in_new {
|
|
|
- var name = old_name
|
|
|
- var new_handler = new_handler_.(*EventHandler)
|
|
|
if new_handler == old_handler {
|
|
|
- goto skip_event_opts
|
|
|
+ goto skip_this_event
|
|
|
+ } else {
|
|
|
+ ctx.DetachEvent(id, name, old_handler)
|
|
|
+ ctx.AttachEvent(id, name, new_handler)
|
|
|
}
|
|
|
- ctx.DetachEvent(id, name, old_handler)
|
|
|
- ctx.AttachEvent(id, name, new_handler)
|
|
|
- skip_event_opts:
|
|
|
} else {
|
|
|
- ctx.DetachEvent(id, old_name, old_handler)
|
|
|
+ ctx.DetachEvent(id, name, old_handler)
|
|
|
}
|
|
|
+ skip_this_event:
|
|
|
})
|
|
|
}
|
|
|
- new_events.Data.ForEach(func(key string, val interface{}) {
|
|
|
- var new_name = key
|
|
|
- var new_handler = val.(*EventHandler)
|
|
|
+ new_events.Data.ForEach(func(new_name string, handler *EventHandler) {
|
|
|
if !(old != nil && old.Events.Data.Has(new_name)) {
|
|
|
- ctx.AttachEvent(id, new_name, new_handler)
|
|
|
+ var new_handler = handler
|
|
|
+ ctx.AttachEvent(id, new_name, new_handler)
|
|
|
}
|
|
|
})
|
|
|
skip_events:
|
|
@@ -296,4 +236,53 @@ func Diff(ctx *DeltaNotifier, parent *Node, old *Node, new *Node) {
|
|
|
skip_content:
|
|
|
}
|
|
|
}
|
|
|
+func detach_all_events(ctx *DeltaNotifier, node *Node) {
|
|
|
+ var node_id = get_addr(node)
|
|
|
+ node.Events.Data.ForEach(func(name string, handler *EventHandler) {
|
|
|
+ ctx.DetachEvent(node_id, name, handler)
|
|
|
+ })
|
|
|
+ var children, has_children = node.Content.(*Children)
|
|
|
+ if has_children {
|
|
|
+ for _, child := range *children {
|
|
|
+ detach_all_events(ctx, child)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+var emptyAttrs = &Attrs { ctn.MakeMap[string,string](ctn.StringCompare) }
|
|
|
+var emptyStyles = &Styles { ctn.MakeMap[string,string](ctn.StringCompare) }
|
|
|
+var emptyEvents = &Events { ctn.MakeMap[string,*EventHandler](ctn.StringCompare) }
|
|
|
+var emptyContent = &Children {}
|
|
|
+func EmptyAttrs() *Attrs { return emptyAttrs }
|
|
|
+func EmptyStyles() *Styles { return emptyStyles }
|
|
|
+func EmptyEvents() *Events { return emptyEvents }
|
|
|
+func EmptyContent() Content { return emptyContent }
|
|
|
+func (attrs *Attrs) MergedWith(another *Attrs) *Attrs {
|
|
|
+ const class = "class"
|
|
|
+ var draft = attrs.Data
|
|
|
+ another.Data.ForEach(func(key string, another_value string) {
|
|
|
+ var value = (func() string {
|
|
|
+ if key == class {
|
|
|
+ var this_value, exists = draft.Lookup(class)
|
|
|
+ if exists {
|
|
|
+ var merged_value = (this_value + " " + another_value)
|
|
|
+ return merged_value
|
|
|
+ } else {
|
|
|
+ return another_value
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ return another_value
|
|
|
+ }
|
|
|
+ })()
|
|
|
+ draft = draft.Inserted(key, value)
|
|
|
+ })
|
|
|
+ return &Attrs { draft }
|
|
|
+}
|
|
|
+func (styles *Styles) MergedWith(another *Styles) *Styles {
|
|
|
+ return &Styles { styles.Data.MergedWith(another.Data) }
|
|
|
+}
|
|
|
+func (events *Events) MergedWith(another *Events) *Events {
|
|
|
+ return &Events { events.Data.MergedWith(another.Data) }
|
|
|
+}
|
|
|
+
|
|
|
|