From 0433f460e48e377331fab2846b6e8e05450b65de Mon Sep 17 00:00:00 2001 From: Alexei Anoshenko <2277098+anoshenko@users.noreply.github.com> Date: Sun, 22 Jun 2025 21:04:01 +0300 Subject: [PATCH] Added change listener binding --- colorPicker.go | 2 +- customView.go | 4 +-- data.go | 13 +++++--- data_test.go | 4 +-- datePicker.go | 2 +- detailsView.go | 2 +- dropDownList.go | 2 +- editView.go | 2 +- events.go | 7 ++-- events1arg.go | 10 +++--- events2arg.go | 19 ++++++----- gridLayout.go | 5 +-- listLayout.go | 5 +-- listView.go | 4 +-- mediaPlayer.go | 22 ++++++------- numberPicker.go | 2 +- stackLayout.go | 19 ++--------- tableView.go | 4 +-- tabsLayout.go | 12 ++----- timePicker.go | 2 +- view.go | 81 ++++++++++++++++++++++++++++++++++++++--------- viewStyle.go | 25 +++++++++++++++ viewsContainer.go | 17 +++++----- 23 files changed, 163 insertions(+), 102 deletions(-) diff --git a/colorPicker.go b/colorPicker.go index 66ecf34..eddd1fa 100644 --- a/colorPicker.go +++ b/colorPicker.go @@ -160,7 +160,7 @@ func (picker *colorPickerData) handleCommand(self View, command PropertyName, da listener.Run(picker, color, oldColor) } if listener, ok := picker.changeListener[ColorPickerValue]; ok { - listener(picker, ColorPickerValue) + listener.Run(picker, ColorPickerValue) } } } diff --git a/customView.go b/customView.go index 35411d6..75b75e3 100644 --- a/customView.go +++ b/customView.go @@ -98,8 +98,8 @@ func (customView *CustomViewData) SetParams(params Params) bool { } // SetChangeListener set the function to track the change of the View property -func (customView *CustomViewData) SetChangeListener(tag PropertyName, listener func(View, PropertyName)) { - customView.superView.SetChangeListener(tag, listener) +func (customView *CustomViewData) SetChangeListener(tag PropertyName, listener any) bool { + return customView.superView.SetChangeListener(tag, listener) } // Remove removes the property with name defined by the argument diff --git a/data.go b/data.go index fa87fa7..ae7f74a 100644 --- a/data.go +++ b/data.go @@ -49,14 +49,17 @@ type DataObject interface { ToParams() Params } +// DataNodeType defines the type of DataNode +type DataNodeType int + // Constants which are used to describe a node type, see [DataNode] const ( // TextNode - node is the pair "tag - text value". Syntax: = - TextNode = 0 + TextNode DataNodeType = 0 // ObjectNode - node is the pair "tag - object". Syntax: = {...} - ObjectNode = 1 + ObjectNode DataNodeType = 1 // ArrayNode - node is the pair "tag - object". Syntax: = [...] - ArrayNode = 2 + ArrayNode DataNodeType = 2 ) // DataNode interface of a data node @@ -65,7 +68,7 @@ type DataNode interface { Tag() string // Type returns a node type. Possible values are TextNode, ObjectNode and ArrayNode - Type() int + Type() DataNodeType // Text returns node text Text() string @@ -253,7 +256,7 @@ func (node *dataNode) Tag() string { return node.tag } -func (node *dataNode) Type() int { +func (node *dataNode) Type() DataNodeType { if node.array != nil { return ArrayNode } diff --git a/data_test.go b/data_test.go index 806e318..2ab257a 100644 --- a/data_test.go +++ b/data_test.go @@ -75,7 +75,7 @@ func TestParseDataText(t *testing.T) { t.Errorf(`obj.PropertyValue("key5") result: ("%s",%v)`, val, ok) } - testKey := func(obj DataObject, index int, tag string, nodeType int) DataNode { + testKey := func(obj DataObject, index int, tag string, nodeType DataNodeType) DataNode { key := obj.Property(index) if key == nil { t.Errorf(`%s.Property(%d) == nil`, obj.Tag(), index) @@ -118,7 +118,7 @@ func TestParseDataText(t *testing.T) { type testKeyData struct { tag string - nodeType int + nodeType DataNodeType } data := []testKeyData{ diff --git a/datePicker.go b/datePicker.go index 3cfe639..f923686 100644 --- a/datePicker.go +++ b/datePicker.go @@ -352,7 +352,7 @@ func (picker *datePickerData) handleCommand(self View, command PropertyName, dat listener.Run(picker, value, oldValue) } if listener, ok := picker.changeListener[DatePickerValue]; ok { - listener(picker, DatePickerValue) + listener.Run(picker, DatePickerValue) } } } diff --git a/detailsView.go b/detailsView.go index 2296083..48701d5 100644 --- a/detailsView.go +++ b/detailsView.go @@ -193,7 +193,7 @@ func (detailsView *detailsViewData) handleCommand(self View, command PropertyNam if n, ok := dataIntProperty(data, "open"); ok { detailsView.properties[Expanded] = (n != 0) if listener, ok := detailsView.changeListener[Expanded]; ok { - listener(detailsView, Expanded) + listener.Run(detailsView, Expanded) } } return true diff --git a/dropDownList.go b/dropDownList.go index 1dd6802..a639bf2 100644 --- a/dropDownList.go +++ b/dropDownList.go @@ -249,7 +249,7 @@ func (list *dropDownListData) handleCommand(self View, command PropertyName, dat listener.Run(list, number, old) } if listener, ok := list.changeListener[Current]; ok { - listener(list, Current) + listener.Run(list, Current) } } } else { diff --git a/editView.go b/editView.go index 5040e29..d318a44 100644 --- a/editView.go +++ b/editView.go @@ -272,7 +272,7 @@ func (edit *editViewData) textChanged(newText, oldText string) { listener.Run(edit, newText, oldText) } if listener, ok := edit.changeListener[Text]; ok { - listener(edit, Text) + listener.Run(edit, Text) } } diff --git a/events.go b/events.go index 204fe0f..05484f4 100644 --- a/events.go +++ b/events.go @@ -139,8 +139,7 @@ func (data *noArgListenerBinding[V]) Run(view V) { args = []reflect.Value{} case 1: - inType := methodType.In(0) - if inType == reflect.TypeOf(view) { + if equalType(methodType.In(0), reflect.TypeOf(view)) { args = []reflect.Value{reflect.ValueOf(view)} } } @@ -152,6 +151,10 @@ func (data *noArgListenerBinding[V]) Run(view V) { } } +func equalType(inType reflect.Type, argType reflect.Type) bool { + return inType == argType || (inType.Kind() == reflect.Interface && argType.Implements(inType)) +} + func (data *noArgListenerBinding[V]) rawListener() any { return data.name } diff --git a/events1arg.go b/events1arg.go index 02ad212..8a5217c 100644 --- a/events1arg.go +++ b/events1arg.go @@ -106,6 +106,7 @@ func (data *oneArgListenerBinding[V, E]) Run(view V, event E) { } methodType := method.Type() + var args []reflect.Value = nil switch methodType.NumIn() { case 0: @@ -113,14 +114,15 @@ func (data *oneArgListenerBinding[V, E]) Run(view V, event E) { case 1: inType := methodType.In(0) - if inType == reflect.TypeOf(view) { - args = []reflect.Value{reflect.ValueOf(view)} - } else if inType == reflect.TypeOf(event) { + if equalType(inType, reflect.TypeOf(event)) { args = []reflect.Value{reflect.ValueOf(event)} + } else if equalType(inType, reflect.TypeOf(view)) { + args = []reflect.Value{reflect.ValueOf(view)} } case 2: - if methodType.In(0) == reflect.TypeOf(view) && methodType.In(1) == reflect.TypeOf(event) { + if equalType(methodType.In(0), reflect.TypeOf(view)) && + equalType(methodType.In(1), reflect.TypeOf(event)) { args = []reflect.Value{reflect.ValueOf(view), reflect.ValueOf(event)} } } diff --git a/events2arg.go b/events2arg.go index 54aeea2..475e03c 100644 --- a/events2arg.go +++ b/events2arg.go @@ -140,6 +140,7 @@ func (data *twoArgListenerBinding[V, E]) Run(view V, arg1 E, arg2 E) { } methodType := method.Type() + var args []reflect.Value = nil switch methodType.NumIn() { case 0: @@ -147,23 +148,25 @@ func (data *twoArgListenerBinding[V, E]) Run(view V, arg1 E, arg2 E) { case 1: inType := methodType.In(0) - if inType == reflect.TypeOf(view) { - args = []reflect.Value{reflect.ValueOf(view)} - } else if inType == reflect.TypeOf(arg1) { + if equalType(inType, reflect.TypeOf(arg1)) { args = []reflect.Value{reflect.ValueOf(arg1)} + } else if equalType(inType, reflect.TypeOf(view)) { + args = []reflect.Value{reflect.ValueOf(view)} } case 2: - valType := reflect.TypeOf(arg1) - if methodType.In(0) == reflect.TypeOf(view) && methodType.In(1) == valType { + inType0 := methodType.In(0) + inType1 := methodType.In(1) + if equalType(inType0, reflect.TypeOf(view)) && equalType(inType1, reflect.TypeOf(arg1)) { args = []reflect.Value{reflect.ValueOf(view), reflect.ValueOf(arg1)} - } else if methodType.In(0) == valType && methodType.In(1) == valType { + } else if equalType(inType0, reflect.TypeOf(arg1)) && equalType(inType1, reflect.TypeOf(arg2)) { args = []reflect.Value{reflect.ValueOf(arg1), reflect.ValueOf(arg2)} } case 3: - valType := reflect.TypeOf(arg1) - if methodType.In(0) == reflect.TypeOf(view) && methodType.In(1) == valType && methodType.In(2) == valType { + if equalType(methodType.In(0), reflect.TypeOf(view)) && + equalType(methodType.In(1), reflect.TypeOf(arg1)) && + equalType(methodType.In(2), reflect.TypeOf(arg2)) { args = []reflect.Value{reflect.ValueOf(view), reflect.ValueOf(arg1), reflect.ValueOf(arg2)} } } diff --git a/gridLayout.go b/gridLayout.go index 619d416..88f4573 100644 --- a/gridLayout.go +++ b/gridLayout.go @@ -458,10 +458,7 @@ func (gridLayout *gridLayoutData) UpdateGridContent() { if gridLayout.created { updateInnerHTML(gridLayout.htmlID(), gridLayout.session) } - - if listener, ok := gridLayout.changeListener[Content]; ok { - listener(gridLayout, Content) - } + gridLayout.contentChanged() } } diff --git a/listLayout.go b/listLayout.go index 48366e8..2952a0c 100644 --- a/listLayout.go +++ b/listLayout.go @@ -196,10 +196,7 @@ func (listLayout *listLayoutData) UpdateContent() { if listLayout.created { updateInnerHTML(listLayout.htmlID(), listLayout.session) } - - if listener, ok := listLayout.changeListener[Content]; ok { - listener(listLayout, Content) - } + listLayout.contentChanged() } } diff --git a/listView.go b/listView.go index e55d4a3..f685114 100644 --- a/listView.go +++ b/listView.go @@ -963,7 +963,7 @@ func (listView *listViewData) handleCurrent(number int) { listener.Run(listView, number) } if listener, ok := listView.changeListener[Current]; ok { - listener(listView, Current) + listener.Run(listView, Current) } } @@ -1022,7 +1022,7 @@ func (listView *listViewData) onItemClick(number int) { setArrayPropertyValue(listView, Checked, checkedItem) if listener, ok := listView.changeListener[Checked]; ok { - listener(listView, Checked) + listener.Run(listView, Checked) } for _, listener := range getOneArgEventListeners[ListView, []int](listView, nil, ListItemCheckedEvent) { diff --git a/mediaPlayer.go b/mediaPlayer.go index c2a48de..a6f1976 100644 --- a/mediaPlayer.go +++ b/mediaPlayer.go @@ -1430,32 +1430,32 @@ func (data *mediaPlayerErrorListenerBinding) Run(player MediaPlayer, code int, m args = []reflect.Value{} case 1: - switch methodType.In(0) { - case reflect.TypeOf(player): + inType := methodType.In(0) + if equalType(inType, reflect.TypeOf(player)) { args = []reflect.Value{reflect.ValueOf(player)} - case reflect.TypeOf(code): + } else if equalType(inType, reflect.TypeOf(code)) { args = []reflect.Value{reflect.ValueOf(code)} - case reflect.TypeOf(message): + } else if equalType(inType, reflect.TypeOf(message)) { args = []reflect.Value{reflect.ValueOf(message)} } case 2: in0 := methodType.In(0) in1 := methodType.In(1) - if in0 == reflect.TypeOf(player) { - if in1 == reflect.TypeOf(code) { + if equalType(in0, reflect.TypeOf(player)) { + if equalType(in1, reflect.TypeOf(code)) { args = []reflect.Value{reflect.ValueOf(player), reflect.ValueOf(code)} - } else if in1 == reflect.TypeOf(message) { + } else if equalType(in1, reflect.TypeOf(message)) { args = []reflect.Value{reflect.ValueOf(player), reflect.ValueOf(message)} } - } else if in0 == reflect.TypeOf(code) && in1 == reflect.TypeOf(message) { + } else if equalType(in0, reflect.TypeOf(code)) && equalType(in1, reflect.TypeOf(message)) { args = []reflect.Value{reflect.ValueOf(code), reflect.ValueOf(message)} } case 3: - if methodType.In(0) == reflect.TypeOf(player) && - methodType.In(1) == reflect.TypeOf(code) && - methodType.In(2) == reflect.TypeOf(message) { + if equalType(methodType.In(0), reflect.TypeOf(player)) && + equalType(methodType.In(1), reflect.TypeOf(code)) && + equalType(methodType.In(2), reflect.TypeOf(message)) { args = []reflect.Value{ reflect.ValueOf(player), reflect.ValueOf(code), diff --git a/numberPicker.go b/numberPicker.go index a2ec402..b7f44c9 100644 --- a/numberPicker.go +++ b/numberPicker.go @@ -284,7 +284,7 @@ func (picker *numberPickerData) handleCommand(self View, command PropertyName, d listener.Run(picker, value, oldValue) } if listener, ok := picker.changeListener[NumberPickerValue]; ok { - listener(picker, NumberPickerValue) + listener.Run(picker, NumberPickerValue) } } } diff --git a/stackLayout.go b/stackLayout.go index 327bc5c..ed9caef 100644 --- a/stackLayout.go +++ b/stackLayout.go @@ -610,12 +610,6 @@ func (layout *stackLayoutData) moveToFrontByIndex(index int, onShow []func(View) session.updateCSSProperty(peekPageID, "transform", transformCSS) } -func (layout *stackLayoutData) contentChanged() { - if listener, ok := layout.changeListener[Content]; ok { - listener(layout, Content) - } -} - func (layout *stackLayoutData) RemovePeek() View { return layout.RemoveView(len(layout.views) - 1) } @@ -683,9 +677,7 @@ func (layout *stackLayoutData) Append(view View) { } session.appendToInnerHTML(stackID, buffer.String()) - if listener, ok := layout.changeListener[Content]; ok { - listener(layout, Content) - } + layout.contentChanged() } } @@ -721,9 +713,7 @@ func (layout *stackLayoutData) Insert(view View, index int) { session := layout.Session() session.appendToInnerHTML(stackID, buffer.String()) - if listener, ok := layout.changeListener[Content]; ok { - listener(layout, Content) - } + layout.contentChanged() } // Remove removes view from list and return it @@ -754,10 +744,7 @@ func (layout *stackLayoutData) RemoveView(index int) View { } layout.Session().callFunc("removeView", view.htmlID()+"page") - - if listener, ok := layout.changeListener[Content]; ok { - listener(layout, Content) - } + layout.contentChanged() return view } diff --git a/tableView.go b/tableView.go index 20c147e..3fabef2 100644 --- a/tableView.go +++ b/tableView.go @@ -1676,7 +1676,7 @@ func (table *tableViewData) handleCommand(self View, command PropertyName, data current.Row = row table.setRaw(Current, current.Row) if listener, ok := table.changeListener[Current]; ok { - listener(table, Current) + listener.Run(table, Current) } for _, listener := range getOneArgEventListeners[TableView, int](table, nil, TableRowSelectedEvent) { @@ -1693,7 +1693,7 @@ func (table *tableViewData) handleCommand(self View, command PropertyName, data current.Column = column table.setRaw(Current, current.Row) if listener, ok := table.changeListener[Current]; ok { - listener(table, Current) + listener.Run(table, Current) } for _, listener := range getTwoArgEventListeners[TableView, int](table, nil, TableCellSelectedEvent) { diff --git a/tabsLayout.go b/tabsLayout.go index 07bc95c..c11eb97 100644 --- a/tabsLayout.go +++ b/tabsLayout.go @@ -403,9 +403,7 @@ func (tabsLayout *tabsLayoutData) Append(view View) { view.SetChangeListener(TabCloseButton, tabsLayout.updateTabCloseButton) if tabsLayout.created { updateInnerHTML(tabsLayout.htmlID(), tabsLayout.Session()) - if listener, ok := tabsLayout.changeListener[Content]; ok { - listener(tabsLayout, Content) - } + tabsLayout.contentChanged() tabsLayout.Set(Current, len(tabsLayout.views)-1) } } @@ -429,9 +427,7 @@ func (tabsLayout *tabsLayoutData) currentChanged(newCurrent, oldCurrent int) { for _, listener := range getTwoArgEventListeners[TabsLayout, int](tabsLayout, nil, CurrentTabChangedEvent) { listener.Run(tabsLayout, newCurrent, oldCurrent) } - if listener, ok := tabsLayout.changeListener[Current]; ok { - listener(tabsLayout, Current) - } + tabsLayout.contentChanged() } // Remove removes view from list and return it @@ -457,9 +453,7 @@ func (tabsLayout *tabsLayoutData) RemoveView(index int) View { tabsLayout.Set(Current, newCurrent) } updateInnerHTML(tabsLayout.htmlID(), tabsLayout.Session()) - if listener, ok := tabsLayout.changeListener[Content]; ok { - listener(tabsLayout, Content) - } + tabsLayout.contentChanged() } else if newCurrent != oldCurrent { tabsLayout.setRaw(Current, newCurrent) } diff --git a/timePicker.go b/timePicker.go index 2b35e8a..db7261e 100644 --- a/timePicker.go +++ b/timePicker.go @@ -324,7 +324,7 @@ func (picker *timePickerData) handleCommand(self View, command PropertyName, dat listener.Run(picker, value, oldValue) } if listener, ok := picker.changeListener[TimePickerValue]; ok { - listener(picker, TimePickerValue) + listener.Run(picker, TimePickerValue) } } diff --git a/view.go b/view.go index 92a7107..44ebe6b 100644 --- a/view.go +++ b/view.go @@ -30,6 +30,8 @@ func (frame Frame) Bottom() float64 { return frame.Top + frame.Height } +const changeListeners PropertyName = "change-listeners" + // View represents a base view interface type View interface { ViewStyle @@ -66,8 +68,18 @@ type View interface { // a description of the error is written to the log SetAnimated(tag PropertyName, value any, animation AnimationProperty) bool - // SetChangeListener set the function to track the change of the View property - SetChangeListener(tag PropertyName, listener func(View, PropertyName)) + // SetChangeListener set the function (the second argument) to track the change of the View property (the first argument). + // + // Allowed listener function formats: + // + // func(view rui.View, property rui.PropertyName) + // func(view rui.View) + // func(property rui.PropertyName) + // func() + // string + // + // If the second argument is given as a string, it specifies the name of the binding function. + SetChangeListener(tag PropertyName, listener any) bool // HasFocus returns 'true' if the view has focus HasFocus() bool @@ -110,7 +122,7 @@ type viewData struct { _htmlID string parentID string systemClass string - changeListener map[PropertyName]func(View, PropertyName) + changeListener map[PropertyName]oneArgListener[View, PropertyName] singleTransition map[PropertyName]AnimationProperty addCSS map[string]string frame Frame @@ -162,7 +174,7 @@ func (view *viewData) init(session Session) { view.changed = view.propertyChanged view.tag = "View" view.session = session - view.changeListener = map[PropertyName]func(View, PropertyName){} + view.changeListener = map[PropertyName]oneArgListener[View, PropertyName]{} view.addCSS = map[string]string{} //view.animation = map[string]AnimationEndListener{} view.singleTransition = map[PropertyName]AnimationProperty{} @@ -242,11 +254,8 @@ func (view *viewData) Remove(tag PropertyName) { if view.created && len(changedTags) > 0 { for _, tag := range changedTags { view.changed(tag) - } - - for _, tag := range changedTags { if listener, ok := view.changeListener[tag]; ok { - listener(view, tag) + listener.Run(view, tag) } } } @@ -273,11 +282,8 @@ func (view *viewData) Set(tag PropertyName, value any) bool { if view.created && len(changedTags) > 0 { for _, tag := range changedTags { view.changed(tag) - } - - for _, tag := range changedTags { if listener, ok := view.changeListener[tag]; ok { - listener(view, tag) + listener.Run(view, tag) } } } @@ -295,7 +301,8 @@ func normalizeViewTag(tag PropertyName) PropertyName { } func (view *viewData) getFunc(tag PropertyName) any { - if tag == ID { + switch tag { + case ID: if id := view.ID(); id != "" { return id } else { @@ -361,6 +368,29 @@ func (view *viewData) setFunc(tag PropertyName, value any) []PropertyName { view.setRaw(Binding, value) return []PropertyName{Binding} + case changeListeners: + switch value := value.(type) { + case DataObject: + for i := range value.PropertyCount() { + node := value.Property(i) + if node.Type() == TextNode { + if text := node.Text(); text != "" { + view.changeListener[PropertyName(node.Tag())] = newOneArgListenerBinding[View, PropertyName](text) + } + } + } + if len(view.changeListener) > 0 { + view.setRaw(changeListeners, view.changeListener) + } + return []PropertyName{tag} + + case DataNode: + if value.Type() == ObjectNode { + return view.setFunc(tag, value.Object()) + } + } + return []PropertyName{} + case Animation: oldAnimations := []AnimationProperty{} if val := view.getRaw(Animation); val != nil { @@ -1251,12 +1281,33 @@ func (view *viewData) handleCommand(self View, command PropertyName, data DataOb } -func (view *viewData) SetChangeListener(tag PropertyName, listener func(View, PropertyName)) { +func (view *viewData) SetChangeListener(tag PropertyName, listener any) bool { if listener == nil { delete(view.changeListener, tag) } else { - view.changeListener[tag] = listener + switch listener := listener.(type) { + case func(): + view.changeListener[tag] = newOneArgListener0[View, PropertyName](listener) + + case func(View): + view.changeListener[tag] = newOneArgListenerV[View, PropertyName](listener) + + case func(PropertyName): + view.changeListener[tag] = newOneArgListenerE[View](listener) + + case func(View, PropertyName): + view.changeListener[tag] = newOneArgListenerVE(listener) + + case string: + view.changeListener[tag] = newOneArgListenerBinding[View, PropertyName](listener) + + default: + return false + } + + view.setRaw(changeListeners, view.changeListener) } + return true } func (view *viewData) HasFocus() bool { diff --git a/viewStyle.go b/viewStyle.go index 3d417c0..db488bb 100644 --- a/viewStyle.go +++ b/viewStyle.go @@ -661,6 +661,14 @@ func supportedPropertyValue(value any) bool { case []mediaPlayerErrorListener: return getMediaPlayerErrorListenerBinding(value) != "" + case map[PropertyName]oneArgListener[View, PropertyName]: + for _, listener := range value { + if text, ok := listener.rawListener().(string); ok && text != "" { + return true + } + } + return false + default: return false } @@ -978,6 +986,23 @@ func writePropertyValue(buffer *strings.Builder, tag PropertyName, value any, in case []mediaPlayerErrorListener: buffer.WriteString(getMediaPlayerErrorListenerBinding(value)) + + case map[PropertyName]oneArgListener[View, PropertyName]: + buffer.WriteString("_{") + for key, listener := range value { + if text, ok := listener.rawListener().(string); ok && text != "" { + buffer.WriteRune('\n') + buffer.WriteString(indent) + buffer.WriteRune('\t') + writeString(string(key)) + buffer.WriteString(" = ") + writeString(text) + buffer.WriteRune(',') + } + buffer.WriteRune('\n') + buffer.WriteString(indent) + buffer.WriteRune('}') + } } } diff --git a/viewsContainer.go b/viewsContainer.go index 162c778..c004b42 100644 --- a/viewsContainer.go +++ b/viewsContainer.go @@ -85,10 +85,13 @@ func (container *viewsContainerData) Append(view View) { viewHTML(view, buffer, "") container.Session().appendToInnerHTML(container.htmlID(), buffer.String()) + container.contentChanged() + } +} - if listener, ok := container.changeListener[Content]; ok { - listener(container, Content) - } +func (container *viewsContainerData) contentChanged() { + if listener, ok := container.changeListener[Content]; ok { + listener.Run(container, Content) } } @@ -113,9 +116,7 @@ func (container *viewsContainerData) insert(view View, index int) bool { func (container *viewsContainerData) Insert(view View, index int) { if container.insert(view, index) && container.created { updateInnerHTML(container.htmlID(), container.Session()) - if listener, ok := container.changeListener[Content]; ok { - listener(container, Content) - } + container.contentChanged() } } @@ -149,9 +150,7 @@ func (container *viewsContainerData) RemoveView(index int) View { view := container.removeView(index) if view != nil && container.created { container.Session().callFunc("removeView", view.htmlID()) - if listener, ok := container.changeListener[Content]; ok { - listener(container, Content) - } + container.contentChanged() } return view }