Optimisation

This commit is contained in:
Alexei Anoshenko 2025-07-06 11:20:37 +03:00
parent 8066fb92ba
commit 73cc26b54e
27 changed files with 117 additions and 154 deletions

View File

@ -1,6 +1,7 @@
package rui
import (
"errors"
"fmt"
"math"
"strconv"
@ -86,6 +87,10 @@ func StringToAngleUnit(value string) (AngleUnit, bool) {
func stringToAngleUnit(value string) (AngleUnit, error) {
value = strings.ToLower(strings.Trim(value, " \t\n\r"))
if value == "" {
return AngleUnit{}, errors.New(`invalid AngleUnit value: ""`)
}
setValue := func(suffix string, unitType AngleUnitType) (AngleUnit, error) {
val, err := strconv.ParseFloat(value[:len(value)-len(suffix)], 64)
if err != nil {

View File

@ -65,16 +65,12 @@ func (point *BackgroundGradientAngle) color(session Session) (Color, bool) {
if point.Color != nil {
switch color := point.Color.(type) {
case string:
if color != "" {
if color[0] == '@' {
if clr, ok := session.Color(color[1:]); ok {
return clr, true
}
} else {
if clr, ok := StringToColor(color); ok {
return clr, true
}
if ok, constName := isConstantName(color); ok {
if clr, ok := session.Color(constName); ok {
return clr, true
}
} else if clr, ok := StringToColor(color); ok {
return clr, true
}
case Color:
@ -104,19 +100,15 @@ func (point *BackgroundGradientAngle) cssString(session Session, buffer *strings
if point.Angle != nil {
switch value := point.Angle.(type) {
case string:
if value != "" {
if value[0] == '@' {
if val, ok := session.Constant(value[1:]); ok {
value = val
} else {
return
}
if ok, constName := isConstantName(value); ok {
if value, ok = session.Constant(constName); !ok {
return
}
}
if angle, ok := StringToAngleUnit(value); ok {
buffer.WriteRune(' ')
buffer.WriteString(angle.cssString())
}
if angle, ok := StringToAngleUnit(value); ok {
buffer.WriteRune(' ')
buffer.WriteString(angle.cssString())
}
case AngleUnit:
@ -174,7 +166,7 @@ func backgroundConicGradientSet(properties Properties, tag PropertyName, value a
properties.setRaw(Gradient, vector)
return []PropertyName{tag}
}
} else if isConstantName(value) {
} else if ok, _ := isConstantName(value); ok {
properties.setRaw(Gradient, value)
return []PropertyName{tag}
}
@ -206,15 +198,6 @@ func backgroundConicGradientSet(properties Properties, tag PropertyName, value a
return propertiesSet(properties, tag, value)
}
func (gradient *backgroundConicGradient) stringToAngle(text string) (any, bool) {
if text == "" {
return nil, false
} else if text[0] == '@' {
return text, true
}
return StringToAngleUnit(text)
}
func (gradient *backgroundConicGradient) stringToGradientPoint(text string) (BackgroundGradientAngle, bool) {
var result BackgroundGradientAngle
colorText := ""
@ -231,7 +214,7 @@ func (gradient *backgroundConicGradient) stringToGradientPoint(text string) (Bac
return result, false
}
if colorText[0] == '@' {
if ok, _ := isConstantName(colorText); ok {
result.Color = colorText
} else if color, ok := StringToColor(colorText); ok {
result.Color = color
@ -240,7 +223,9 @@ func (gradient *backgroundConicGradient) stringToGradientPoint(text string) (Bac
}
if pointText != "" {
if angle, ok := gradient.stringToAngle(pointText); ok {
if ok, _ := isConstantName(pointText); ok {
result.Angle = pointText
} else if angle, ok := StringToAngleUnit(text); ok {
result.Angle = angle
} else {
return result, false

View File

@ -103,14 +103,14 @@ func backgroundGradientSet(properties Properties, tag PropertyName, value any) [
case Gradient:
switch value := value.(type) {
case string:
if value != "" {
if strings.Contains(value, " ") || strings.Contains(value, ",") {
if points := parseGradientText(value); len(points) >= 2 {
properties.setRaw(Gradient, points)
return []PropertyName{tag}
}
} else if value[0] == '@' {
properties.setRaw(Gradient, value)
if ok, _ := isConstantName(value); ok {
properties.setRaw(Gradient, value)
return []PropertyName{tag}
}
if strings.ContainsAny(value, " ,") {
if points := parseGradientText(value); len(points) >= 2 {
properties.setRaw(Gradient, points)
return []PropertyName{tag}
}
}
@ -168,7 +168,7 @@ func (point *BackgroundGradientPoint) setValue(text string) bool {
return false
}
if colorText[0] == '@' {
if ok, _ := isConstantName(colorText); ok {
point.Color = colorText
} else if color, ok := StringToColor(colorText); ok {
point.Color = color
@ -178,7 +178,7 @@ func (point *BackgroundGradientPoint) setValue(text string) bool {
if pointText == "" {
point.Pos = nil
} else if pointText[0] == '@' {
} else if ok, _ := isConstantName(pointText); ok {
point.Pos = pointText
} else if pos, ok := StringToSizeUnit(pointText); ok {
point.Pos = pos
@ -193,17 +193,10 @@ func (point *BackgroundGradientPoint) color(session Session) (Color, bool) {
if point.Color != nil {
switch color := point.Color.(type) {
case string:
if color != "" {
if color[0] == '@' {
if clr, ok := session.Color(color[1:]); ok {
return clr, true
}
} else {
if clr, ok := StringToColor(color); ok {
return clr, true
}
}
if ok, constName := isConstantName(color); ok {
return session.Color(constName)
}
return StringToColor(color)
case Color:
return color, true
@ -256,8 +249,8 @@ func (gradient *backgroundGradient) writeGradient(session Session, buffer *strin
switch value := value.(type) {
case string:
if value != "" && value[0] == '@' {
if text, ok := session.Constant(value[1:]); ok {
if ok, constName := isConstantName(value); ok {
if text, ok := session.Constant(constName); ok {
points = parseGradientText(text)
}
}

View File

@ -450,7 +450,7 @@ func polygonClipDataSet(properties Properties, tag PropertyName, value any) []Pr
for i, val := range value {
switch val := val.(type) {
case string:
if isConstantName(val) {
if ok, _ := isConstantName(val); ok {
points[i] = val
} else if size, ok := StringToSizeUnit(val); ok {
points[i] = size
@ -484,7 +484,7 @@ func polygonClipDataSet(properties Properties, tag PropertyName, value any) []Pr
points := make([]any, len(values))
for i, val := range values {
val = strings.Trim(val, " \t\n\r")
if isConstantName(val) {
if ok, _ := isConstantName(val); ok {
points[i] = val
} else if size, ok := StringToSizeUnit(val); ok {
points[i] = size
@ -634,7 +634,7 @@ func setClipShapePropertyProperty(properties Properties, tag PropertyName, value
return []PropertyName{tag}
case string:
if isConstantName(value) {
if ok, _ := isConstantName(value); ok {
properties.setRaw(tag, value)
return []PropertyName{tag}
}

View File

@ -159,9 +159,7 @@ func (picker *colorPickerData) handleCommand(self View, command PropertyName, da
for _, listener := range getTwoArgEventListeners[ColorPicker, Color](picker, nil, ColorChangedEvent) {
listener.Run(picker, color, oldColor)
}
if listener, ok := picker.changeListener[ColorPickerValue]; ok {
listener.Run(picker, ColorPickerValue)
}
picker.runChangeListener(ColorPickerValue)
}
}
}

View File

@ -207,7 +207,7 @@ func (picker *datePickerData) setFunc(tag PropertyName, value any) []PropertyNam
return []PropertyName{tag}
case string:
if isConstantName(value) {
if ok, _ := isConstantName(value); ok {
picker.setRaw(tag, value)
return []PropertyName{tag}
}
@ -351,9 +351,7 @@ func (picker *datePickerData) handleCommand(self View, command PropertyName, dat
for _, listener := range getTwoArgEventListeners[DatePicker, time.Time](picker, nil, DateChangedEvent) {
listener.Run(picker, value, oldValue)
}
if listener, ok := picker.changeListener[DatePickerValue]; ok {
listener.Run(picker, DatePickerValue)
}
picker.runChangeListener(DatePickerValue)
}
}
}

View File

@ -192,9 +192,7 @@ func (detailsView *detailsViewData) handleCommand(self View, command PropertyNam
if command == "details-open" {
if n, ok := dataIntProperty(data, "open"); ok {
detailsView.properties[Expanded] = (n != 0)
if listener, ok := detailsView.changeListener[Expanded]; ok {
listener.Run(detailsView, Expanded)
}
detailsView.runChangeListener(Expanded)
}
return true
}

View File

@ -608,8 +608,8 @@ func GetDragImage(view View, subviewID ...string) string {
if value != nil {
if img, ok := value.(string); ok {
img = strings.Trim(img, " \t")
if img != "" && img[0] == '@' {
if img, ok = view.Session().ImageConstant(img[1:]); ok {
if ok, constName := isConstantName(img); ok {
if img, ok = view.Session().ImageConstant(constName); ok {
return img
}
} else {

View File

@ -139,7 +139,7 @@ func parseIndicesArray(value any) ([]any, bool) {
if val != nil {
switch val := val.(type) {
case string:
if isConstantName(val) {
if ok, _ := isConstantName(val); ok {
items = append(items, val)
} else if n, err := strconv.Atoi(val); err == nil {
items = append(items, n)
@ -162,7 +162,7 @@ func parseIndicesArray(value any) ([]any, bool) {
items := make([]any, 0, len(value))
for _, str := range value {
if str = strings.Trim(str, " \t"); str != "" {
if isConstantName(str) {
if ok, _ := isConstantName(str); ok {
items = append(items, str)
} else if n, err := strconv.Atoi(str); err == nil {
items = append(items, n)
@ -248,9 +248,7 @@ func (list *dropDownListData) handleCommand(self View, command PropertyName, dat
for _, listener := range getTwoArgEventListeners[DropDownList, int](list, nil, DropDownEvent) {
listener.Run(list, number, old)
}
if listener, ok := list.changeListener[Current]; ok {
listener.Run(list, Current)
}
list.runChangeListener(Current)
}
} else {
ErrorLog(err.Error())
@ -308,8 +306,8 @@ func getIndicesArray(view View, tag PropertyName) []int {
result = append(result, value)
case string:
if value != "" && value[0] == '@' {
if val, ok := view.Session().Constant(value[1:]); ok {
if ok, constName := isConstantName(value); ok {
if val, ok := view.Session().Constant(constName); ok {
if n, err := strconv.Atoi(val); err == nil {
result = append(result, n)
}

View File

@ -271,9 +271,7 @@ func (edit *editViewData) textChanged(newText, oldText string) {
for _, listener := range getTwoArgEventListeners[EditView, string](edit, nil, EditTextChangedEvent) {
listener.Run(edit, newText, oldText)
}
if listener, ok := edit.changeListener[Text]; ok {
listener.Run(edit, Text)
}
edit.runChangeListener(Text)
}
func (edit *editViewData) htmlTag() string {

View File

@ -150,7 +150,7 @@ func setGridCellSize(properties Properties, tag PropertyName, value any) []Prope
sizes := make([]any, count)
for i, val := range values {
val = strings.Trim(val, " \t\n\r")
if isConstantName(val) {
if ok, _ := isConstantName(val); ok {
sizes[i] = val
} else if fn := parseSizeFunc(val); fn != nil {
sizes[i] = SizeUnit{Type: SizeFunction, Function: fn}
@ -162,7 +162,7 @@ func setGridCellSize(properties Properties, tag PropertyName, value any) []Prope
}
}
properties.setRaw(tag, sizes)
} else if isConstantName(values[0]) {
} else if ok, _ := isConstantName(values[0]); ok {
properties.setRaw(tag, values[0])
} else if size, err := stringToSizeUnit(values[0]); err == nil {
properties.setRaw(tag, size)
@ -220,7 +220,7 @@ func setGridCellSize(properties Properties, tag PropertyName, value any) []Prope
sizes[i] = val
case string:
if isConstantName(val) {
if ok, _ := isConstantName(val); ok {
sizes[i] = val
} else if size, err := stringToSizeUnit(val); err == nil {
sizes[i] = size
@ -458,7 +458,7 @@ func (gridLayout *gridLayoutData) UpdateGridContent() {
if gridLayout.created {
updateInnerHTML(gridLayout.htmlID(), gridLayout.session)
}
gridLayout.contentChanged()
gridLayout.runChangeListener(Content)
}
}

View File

@ -143,8 +143,8 @@ func (manager *imageManager) imageLoadError(obj DataObject) {
// LoadImage starts the async image loading by url
func LoadImage(url string, onLoaded func(Image), session Session) Image {
if url != "" && url[0] == '@' {
if image, ok := session.ImageConstant(url[1:]); ok {
if ok, constName := isConstantName(url); ok {
if image, ok := session.ImageConstant(constName); ok {
url = image
}
}

View File

@ -217,11 +217,11 @@ func (imageView *imageViewData) htmlTag() string {
}
func imageViewSrc(view View, src string) (string, string) {
if src != "" && src[0] == '@' {
if image, ok := view.Session().ImageConstant(src[1:]); ok {
if ok, constName := isConstantName(src); ok {
if image, ok := view.Session().ImageConstant(constName); ok {
src = image
} else {
src = ""
return "", ""
}
}

View File

@ -196,7 +196,7 @@ func (listLayout *listLayoutData) UpdateContent() {
if listLayout.created {
updateInnerHTML(listLayout.htmlID(), listLayout.session)
}
listLayout.contentChanged()
listLayout.runChangeListener(Content)
}
}

View File

@ -962,9 +962,7 @@ func (listView *listViewData) handleCurrent(number int) {
for _, listener := range getOneArgEventListeners[ListView, int](listView, nil, ListItemSelectedEvent) {
listener.Run(listView, number)
}
if listener, ok := listView.changeListener[Current]; ok {
listener.Run(listView, Current)
}
listView.runChangeListener(Current)
}
func (listView *listViewData) onItemClick(number int) {
@ -1021,9 +1019,7 @@ func (listView *listViewData) onItemClick(number int) {
}
setArrayPropertyValue(listView, Checked, checkedItem)
if listener, ok := listView.changeListener[Checked]; ok {
listener.Run(listView, Checked)
}
listView.runChangeListener(Checked)
for _, listener := range getOneArgEventListeners[ListView, []int](listView, nil, ListItemCheckedEvent) {
listener.Run(listView, checkedItem)

View File

@ -283,9 +283,7 @@ func (picker *numberPickerData) handleCommand(self View, command PropertyName, d
for _, listener := range getTwoArgEventListeners[NumberPicker, float64](picker, nil, NumberChangedEvent) {
listener.Run(picker, value, oldValue)
}
if listener, ok := picker.changeListener[NumberPickerValue]; ok {
listener.Run(picker, NumberPickerValue)
}
picker.runChangeListener(NumberPickerValue)
}
}
}

View File

@ -615,8 +615,8 @@ func (popup *popupData) Set(tag PropertyName, value any) bool {
popup.setRaw(Content, popup.contentView)
case string:
if len(value) > 0 && value[0] == '@' {
view := CreateViewFromResources(popup.session, value[1:])
if ok, constName := isConstantName(value); ok {
view := CreateViewFromResources(popup.session, constName)
if view != nil {
popup.contentView = view
break
@ -1107,8 +1107,8 @@ func (popup *popupData) createTitleView() GridLayout {
if value := popup.getRaw(Title); value != nil {
switch value := value.(type) {
case string:
if len(value) > 0 && value[0] == '@' {
title = CreateViewFromResources(session, value[1:])
if ok, constName := isConstantName(value); ok {
title = CreateViewFromResources(session, constName)
if title != nil {
break
}

View File

@ -18,8 +18,8 @@ func stringProperty(properties Properties, tag PropertyName, session Session) (s
func imageProperty(properties Properties, tag PropertyName, session Session) (string, bool) {
if value := properties.getRaw(tag); value != nil {
if text, ok := value.(string); ok {
if text != "" && text[0] == '@' {
if image, ok := session.ImageConstant(text[1:]); ok {
if ok, constName := isConstantName(text); ok {
if image, ok := session.ImageConstant(constName); ok {
return image, true
} else {
return "", false
@ -88,8 +88,8 @@ func valueToColor(value any, session Session) (Color, bool) {
return value, true
case string:
if len(value) > 1 && value[0] == '@' {
return session.Color(value[1:])
if ok, constName := isConstantName(value); ok {
return session.Color(constName)
}
return StringToColor(value)
}

View File

@ -511,10 +511,10 @@ func invalidPropertyValue(tag PropertyName, value any) {
ErrorLogF(`Invalid value "%v" of "%s" property`, value, string(tag))
}
func isConstantName(text string) bool {
func isConstantName(text string) (bool, string) {
len := len(text)
if len <= 1 || text[0] != '@' {
return false
return false, ""
}
if len > 2 {
@ -522,11 +522,14 @@ func isConstantName(text string) bool {
if (text[1] == '`' && text[last] == '`') ||
(text[1] == '"' && text[last] == '"') ||
(text[1] == '\'' && text[last] == '\'') {
return true
return true, text[2:last]
}
}
return !strings.ContainsAny(text, ",;|\"'`+(){}[]<>/\\*&%! \t\n\r")
if strings.ContainsAny(text, ",;|\"'`+(){}[]<>/\\*&%! \t\n\r") {
return false, ""
}
return true, text[1:]
}
func isInt(value any) (int, bool) {
@ -579,7 +582,7 @@ func setSimpleProperty(properties Properties, tag PropertyName, value any) bool
properties.setRaw(tag, nil)
return true
}
if isConstantName(text) {
if ok, _ := isConstantName(text); ok {
properties.setRaw(tag, text)
return true
}

View File

@ -234,7 +234,7 @@ func resizableSetSide(properties Properties, value any) []PropertyName {
val := strings.Trim(val, " \t\r\n")
values[i] = val
if val[0] == '@' {
if ok, _ := isConstantName(val); ok {
hasConst = true
} else if n, err := strconv.Atoi(val); err == nil {
if n < 1 || n > AllSides {
@ -262,7 +262,7 @@ func resizableSetSide(properties Properties, value any) []PropertyName {
return []PropertyName{Side}
}
} else if value[0] == '@' {
} else if ok, _ := isConstantName(value); ok {
properties.setRaw(Side, value)
return []PropertyName{Side}
} else if n, ok := validValues[value]; ok {

View File

@ -130,7 +130,7 @@ func (data *sizeFuncData) parseArgs(args []any, allowNumber bool) bool {
return false
}
if arg[0] == '@' {
if ok, _ := isConstantName(arg); ok {
data.args = append(data.args, arg)
} else if val, err := strconv.ParseFloat(arg, 64); err == nil {
return numberArg(i, val)

View File

@ -377,7 +377,7 @@ func (layout *stackLayoutData) transitionFinished(view View, tag PropertyName) {
}
}
delete(layout.onPushFinished, viewID)
layout.contentChanged()
layout.runChangeListener(Content)
}
case "pop":
@ -416,7 +416,7 @@ func (layout *stackLayoutData) transitionFinished(view View, tag PropertyName) {
session.removeProperty(pageID, "ontransitionend")
session.removeProperty(pageID, "ontransitioncancel")
session.finishUpdateScript(pageID)
layout.contentChanged()
layout.runChangeListener(Content)
if finished, ok := layout.onMoveFinished[viewID]; ok {
for _, listener := range finished.listener {
@ -566,7 +566,7 @@ func (layout *stackLayoutData) moveToFrontByIndex(index int, onShow []func(View)
if transform == nil {
session.updateCSSProperty(peekPageID, "visibility", "hidden")
session.updateCSSProperty(pageID, "visibility", "visible")
layout.contentChanged()
layout.runChangeListener(Content)
for _, listener := range onShow {
if listener != nil {
listener(view)
@ -677,7 +677,7 @@ func (layout *stackLayoutData) Append(view View) {
}
session.appendToInnerHTML(stackID, buffer.String())
layout.contentChanged()
layout.runChangeListener(Content)
}
}
@ -713,7 +713,7 @@ func (layout *stackLayoutData) Insert(view View, index int) {
session := layout.Session()
session.appendToInnerHTML(stackID, buffer.String())
layout.contentChanged()
layout.runChangeListener(Content)
}
// Remove removes view from list and return it
@ -744,7 +744,7 @@ func (layout *stackLayoutData) RemoveView(index int) View {
}
layout.Session().callFunc("removeView", view.htmlID()+"page")
layout.contentChanged()
layout.runChangeListener(Content)
return view
}
@ -839,7 +839,7 @@ func (layout *stackLayoutData) Pop(onPopFinished ...func(View)) bool {
view.setParentID("")
layout.views = layout.views[:peek]
layout.contentChanged()
layout.runChangeListener(Content)
layout.onPopFinished[view.htmlID()] = popFinished{
view: view,

View File

@ -695,7 +695,7 @@ func (table *tableViewData) setFunc(tag PropertyName, value any) []PropertyName
case HeadHeight, FootHeight:
switch value := value.(type) {
case string:
if isConstantName(value) {
if ok, _ := isConstantName(value); ok {
table.setRaw(tag, value)
} else if n, err := strconv.Atoi(value); err == nil {
table.setRaw(tag, n)
@ -1675,13 +1675,10 @@ func (table *tableViewData) handleCommand(self View, command PropertyName, data
if row, ok := dataIntProperty(data, "row"); ok && row != current.Row {
current.Row = row
table.setRaw(Current, current.Row)
if listener, ok := table.changeListener[Current]; ok {
listener.Run(table, Current)
}
for _, listener := range getOneArgEventListeners[TableView, int](table, nil, TableRowSelectedEvent) {
listener.Run(table, row)
}
table.runChangeListener(Current)
}
case "currentCell":
@ -1692,13 +1689,11 @@ func (table *tableViewData) handleCommand(self View, command PropertyName, data
current.Row = row
current.Column = column
table.setRaw(Current, current.Row)
if listener, ok := table.changeListener[Current]; ok {
listener.Run(table, Current)
}
for _, listener := range getTwoArgEventListeners[TableView, int](table, nil, TableCellSelectedEvent) {
listener.Run(table, row, column)
}
table.runChangeListener(Current)
}
}
}

View File

@ -403,7 +403,7 @@ func (tabsLayout *tabsLayoutData) Append(view View) {
view.SetChangeListener(TabCloseButton, tabsLayout.updateTabCloseButton)
if tabsLayout.created {
updateInnerHTML(tabsLayout.htmlID(), tabsLayout.Session())
tabsLayout.contentChanged()
tabsLayout.runChangeListener(Content)
tabsLayout.Set(Current, len(tabsLayout.views)-1)
}
}
@ -427,7 +427,7 @@ func (tabsLayout *tabsLayoutData) currentChanged(newCurrent, oldCurrent int) {
for _, listener := range getTwoArgEventListeners[TabsLayout, int](tabsLayout, nil, CurrentTabChangedEvent) {
listener.Run(tabsLayout, newCurrent, oldCurrent)
}
tabsLayout.contentChanged()
tabsLayout.runChangeListener(Current)
}
// Remove removes view from list and return it
@ -453,7 +453,7 @@ func (tabsLayout *tabsLayoutData) RemoveView(index int) View {
tabsLayout.Set(Current, newCurrent)
}
updateInnerHTML(tabsLayout.htmlID(), tabsLayout.Session())
tabsLayout.contentChanged()
tabsLayout.runChangeListener(Content)
} else if newCurrent != oldCurrent {
tabsLayout.setRaw(Current, newCurrent)
}

View File

@ -176,7 +176,7 @@ func (picker *timePickerData) setFunc(tag PropertyName, value any) []PropertyNam
return []PropertyName{tag}
case string:
if isConstantName(value) {
if ok, _ := isConstantName(value); ok {
picker.setRaw(tag, value)
return []PropertyName{tag}
}
@ -323,10 +323,7 @@ func (picker *timePickerData) handleCommand(self View, command PropertyName, dat
for _, listener := range getTwoArgEventListeners[TimePicker, time.Time](picker, nil, TimeChangedEvent) {
listener.Run(picker, value, oldValue)
}
if listener, ok := picker.changeListener[TimePickerValue]; ok {
listener.Run(picker, TimePickerValue)
}
picker.runChangeListener(TimePickerValue)
}
}
}

18
view.go
View File

@ -246,15 +246,19 @@ func (view *viewData) Focusable() bool {
return false
}
func (view *viewData) runChangeListener(tag PropertyName) {
if listener, ok := view.changeListener[tag]; ok {
listener.Run(view, tag)
}
}
func (view *viewData) Remove(tag PropertyName) {
changedTags := view.removeFunc(view.normalize(tag))
if view.created && len(changedTags) > 0 {
for _, tag := range changedTags {
view.changed(tag)
if listener, ok := view.changeListener[tag]; ok {
listener.Run(view, tag)
}
view.runChangeListener(tag)
}
}
}
@ -280,9 +284,7 @@ func (view *viewData) Set(tag PropertyName, value any) bool {
if view.created && len(changedTags) > 0 {
for _, tag := range changedTags {
view.changed(tag)
if listener, ok := view.changeListener[tag]; ok {
listener.Run(view, tag)
}
view.runChangeListener(tag)
}
}
@ -910,8 +912,8 @@ func (view *viewData) propertyChanged(tag PropertyName) {
case DragImage:
if img, ok := stringProperty(view, DragImage, session); ok && img != "" {
img = strings.Trim(img, " \t")
if img[0] == '@' {
img, ok = session.ImageConstant(img[1:])
if ok, constName := isConstantName(img); ok {
img, ok = session.ImageConstant(constName)
if !ok {
session.removeProperty(htmlID, "data-drag-image")
return

View File

@ -88,13 +88,7 @@ func (container *viewsContainerData) Append(view View) {
viewHTML(view, buffer, "")
container.Session().appendToInnerHTML(container.htmlID(), buffer.String())
container.contentChanged()
}
}
func (container *viewsContainerData) contentChanged() {
if listener, ok := container.changeListener[Content]; ok {
listener.Run(container, Content)
container.runChangeListener(Content)
}
}
@ -119,7 +113,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())
container.contentChanged()
container.runChangeListener(Content)
}
}
@ -153,7 +147,7 @@ func (container *viewsContainerData) RemoveView(index int) View {
view := container.removeView(index)
if view != nil && container.created {
container.Session().callFunc("removeView", view.htmlID())
container.contentChanged()
container.runChangeListener(Content)
}
return view
}
@ -190,6 +184,11 @@ func viewFromTextValue(text string, session Session) View {
return view
}
}
if ok, constName := isConstantName(text); ok {
if view := CreateViewFromResources(session, constName); view != nil {
return view
}
}
return NewTextView(session, Params{Text: text})
}