From 61e1152f33e217e3ddb1464365867882a2308568 Mon Sep 17 00:00:00 2001 From: Alexei Anoshenko <2277098+anoshenko@users.noreply.github.com> Date: Thu, 3 Sep 2026 12:39:07 +0300 Subject: [PATCH] Optimisation --- animation.go | 87 ++++++++------------------------- application.go | 71 ++++++++++++--------------- backgroundConicGradient.go | 5 +- backgroundImage.go | 9 +--- backgroundRadialGradient.go | 38 +++------------ border.go | 4 +- canvas.go | 13 ++--- checkbox.go | 22 +++------ clipShape.go | 38 ++++----------- color.go | 6 +-- colorPicker.go | 7 +-- cssBuilder.go | 31 +++--------- dataList.go | 13 ++--- datePicker.go | 16 ++----- dragAndDrop.go | 12 ++--- dropDownList.go | 16 ++----- editView.go | 16 ++----- events.go | 5 +- filePicker.go | 4 +- filter.go | 15 ++---- focusEvents.go | 5 +- imageView.go | 12 ++--- listView.go | 95 ++++++++++--------------------------- mediaPlayer.go | 18 ++----- progressBar.go | 9 +--- properties.go | 20 ++------ radius.go | 60 ++++++++--------------- resizable.go | 44 +++++------------ sessionTheme.go | 7 +-- shadow.go | 19 ++------ stackLayout.go | 45 ++++-------------- tableView.go | 95 ++++++++++--------------------------- tabsLayout.go | 73 +++++++--------------------- theme.go | 8 +--- timePicker.go | 18 ++----- transform.go | 52 ++++---------------- utils.go | 6 +++ videoPlayer.go | 12 ++--- view.go | 44 ++++++----------- viewStyle.go | 20 ++------ webBridge.go | 64 +++++-------------------- 41 files changed, 303 insertions(+), 851 deletions(-) diff --git a/animation.go b/animation.go index 2326307..9133413 100644 --- a/animation.go +++ b/animation.go @@ -596,47 +596,30 @@ func (animation *animationData) String() string { if value := animation.getRaw(tag); value != nil { text := propertyValueToString(tag, value, "\t") if text != "" { - buffer.WriteString("\n\t") - buffer.WriteString(string(tag)) - buffer.WriteString(" = ") - buffer.WriteString(text) - buffer.WriteRune(',') + writeStrings(buffer, "\n\t", string(tag), " = ", text, `,`) } } } } writeProperty := func(prop AnimatedProperty, indent string) { - buffer.WriteString(string(prop.Tag)) - buffer.WriteString("{\n") - buffer.WriteString(indent) - buffer.WriteString("from = ") - buffer.WriteString(propertyValueToString("from", prop.From, indent)) - buffer.WriteString(",\n") - buffer.WriteString(indent) - buffer.WriteString("to = ") - buffer.WriteString(propertyValueToString("to", prop.To, indent)) + writeStrings(buffer, string(prop.Tag), + "{\n", indent, "from = ", propertyValueToString("from", prop.From, indent), + ",\n", indent, "to = ", propertyValueToString("to", prop.To, indent)) + for key, value := range prop.KeyFrames { tag := strconv.Itoa(key) + "%" text := propertyValueToString(PropertyName(tag), value, indent) if text != "" { - buffer.WriteString(",\n") - buffer.WriteString(indent) - buffer.WriteString(tag) - buffer.WriteString(" = ") - buffer.WriteString(text) + writeStrings(buffer, ",\n", indent, tag, " = ", text) } } - buffer.WriteString("\n") - buffer.WriteString(indent[1:]) - buffer.WriteString("}") + writeStrings(buffer, "\n", indent[1:], "}") } if props := animation.animatedProperties(); len(props) > 0 { - buffer.WriteString("\n\t") - buffer.WriteString(string(PropertyTag)) - buffer.WriteString(" = ") + writeStrings(buffer, "\n\t", string(PropertyTag), " = ") if len(props) > 1 { buffer.WriteString("[\n") for _, prop := range props { @@ -728,10 +711,7 @@ func (animation *animationData) writeTransitionString(tag PropertyName, buffer * if value := animation.getRaw(name); value != nil { text := propertyValueToString(name, value, "") if text != "" { - buffer.WriteString(lead) - buffer.WriteString(string(name)) - buffer.WriteString(" = ") - buffer.WriteString(text) + writeStrings(buffer, lead, string(name), " = ", text) lead = ", " return true } @@ -748,13 +728,9 @@ func (animation *animationData) writeTransitionString(tag PropertyName, buffer * if value := animation.getRaw(TimingFunction); value != nil { if timingFunction, ok := value.(string); ok && timingFunction != "" { - buffer.WriteString(lead) - buffer.WriteString(string(TimingFunction)) - buffer.WriteString(" = ") + writeStrings(buffer, lead, string(TimingFunction), " = ") if strings.ContainsAny(timingFunction, " ,()") { - buffer.WriteRune('"') - buffer.WriteString(timingFunction) - buffer.WriteRune('"') + writeStrings(buffer, `"`, timingFunction, `"`) } else { buffer.WriteString(timingFunction) } @@ -776,49 +752,30 @@ func (animation *animationData) writeAnimationString(tag PropertyName, buffer *s if value := animation.Get(tag); value != nil { text := propertyValueToString(tag, value, indent2) if text != "" { - buffer.WriteRune('\n') - buffer.WriteString(indent2) - buffer.WriteString(string(tag)) - buffer.WriteString(" = ") - buffer.WriteString(text) - buffer.WriteRune(',') + writeStrings(buffer, "\n", indent2, string(tag), " = ", text, ",") } } } } writeProperty := func(prop AnimatedProperty, indent string) { - buffer.WriteString(string(prop.Tag)) - buffer.WriteString("{\n") indent2 := indent + "\t" - buffer.WriteString(indent2) - buffer.WriteString("from = ") - buffer.WriteString(propertyValueToString("from", prop.From, indent2)) - buffer.WriteString(",\n") - buffer.WriteString(indent2) - buffer.WriteString("to = ") - buffer.WriteString(propertyValueToString("to", prop.To, indent2)) + writeStrings(buffer, string(prop.Tag), + "{\n", indent2, "from = ", propertyValueToString("from", prop.From, indent2), + ",\n", indent2, "to = ", propertyValueToString("to", prop.To, indent2)) + for key, value := range prop.KeyFrames { text := propertyValueToString(PropertyName(tag), value, indent2) if text != "" { - buffer.WriteString(",\n") - buffer.WriteString(indent2) - tag := strconv.Itoa(key) + "%" - buffer.WriteString(tag) - buffer.WriteString(" = ") - buffer.WriteString(text) + writeStrings(buffer, ",\n", indent2, strconv.Itoa(key), "% = ", text) } } - buffer.WriteString(",\n") - buffer.WriteString(indent) - buffer.WriteString("},") + + writeStrings(buffer, ",\n", indent, "},") } if props, ok := animation.Get(PropertyTag).([]AnimatedProperty); ok && props != nil && len(props) > 0 { - buffer.WriteRune('\n') - buffer.WriteString(indent2) - buffer.WriteString(string(PropertyTag)) - buffer.WriteString(" = ") + writeStrings(buffer, "\n", indent2, string(PropertyTag), " = ") if len(props) > 1 { buffer.WriteString("[\n") for _, prop := range props { @@ -832,9 +789,7 @@ func (animation *animationData) writeAnimationString(tag PropertyName, buffer *s writeProperty(props[0], indent2) } } - buffer.WriteRune('\n') - buffer.WriteString(indent) - buffer.WriteString("},\n") + writeStrings(buffer, "\n", indent, "},\n") } writeAnimation(animation, buffer, indent) diff --git a/application.go b/application.go index 8f634aa..8271323 100644 --- a/application.go +++ b/application.go @@ -69,59 +69,48 @@ type AppParams struct { } func getStartPage(buffer *strings.Builder, sessionID int, params AppParams) { - buffer.WriteString(` - - `) - buffer.WriteString(params.Title) - buffer.WriteString("") + writeStrings(buffer, ` + + `, params.Title, "") + if params.Icon != "" { - buffer.WriteString(` - `) + writeStrings(buffer, ` + `) } if params.TitleColor != 0 { - buffer.WriteString(` - `) + writeStrings(buffer, ` + `) } buffer.WriteString(` - - `) + + `) if params.GoogleFonts != "" { - buffer.WriteString(` - - - `) + writeStrings(buffer, ` + + + `) } - buffer.WriteString(` - - - - - -
- - + + +
+ + - - `) + +`) } diff --git a/backgroundConicGradient.go b/backgroundConicGradient.go index 1a73589..019411b 100644 --- a/backgroundConicGradient.go +++ b/backgroundConicGradient.go @@ -314,10 +314,7 @@ func (gradient *backgroundConicGradient) cssStyle(session Session) string { if comma { buffer.WriteRune(' ') } - buffer.WriteString("at ") - buffer.WriteString(x.cssString("50%", session)) - buffer.WriteString(" ") - buffer.WriteString(y.cssString("50%", session)) + writeStrings(buffer, "at ", x.cssString("50%", session), " ", y.cssString("50%", session)) comma = true } diff --git a/backgroundImage.go b/backgroundImage.go index 02dd7fa..db3198c 100644 --- a/backgroundImage.go +++ b/backgroundImage.go @@ -135,9 +135,7 @@ func (image *backgroundImage) cssStyle(session Session) string { buffer := allocStringBuilder() defer freeStringBuilder(buffer) - buffer.WriteString(`url(`) - buffer.WriteString(src) - buffer.WriteRune(')') + writeStrings(buffer, `url(`, src, ")") attachment, _ := enumProperty(image, Attachment, session, NoRepeat) values := enumProperties[Attachment].values @@ -177,10 +175,7 @@ func (image *backgroundImage) cssStyle(session Session) string { height, _ := sizeProperty(image, Height, session) if width.Type != Auto || height.Type != Auto { - buffer.WriteString(` / `) - buffer.WriteString(width.cssString("auto", session)) - buffer.WriteRune(' ') - buffer.WriteString(height.cssString("auto", session)) + writeStrings(buffer, ` / `, width.cssString("auto", session), " ", height.cssString("auto", session)) } } diff --git a/backgroundRadialGradient.go b/backgroundRadialGradient.go index 7712872..68345c1 100644 --- a/backgroundRadialGradient.go +++ b/backgroundRadialGradient.go @@ -227,18 +227,12 @@ func (gradient *backgroundRadialGradient) cssStyle(session Session) string { if text, ok := session.resolveConstants(value); ok { values := enumProperties[RadialGradientRadius] if n, ok := enumStringToInt(text, values.values, false); ok { - buffer.WriteString(shapeText) + writeStrings(buffer, shapeText, values.cssValues[n], " ") shapeText = "" - buffer.WriteString(values.cssValues[n]) - buffer.WriteString(" ") } else { if r, ok := StringToSizeUnit(text); ok && r.Type != Auto { - buffer.WriteString("ellipse ") + writeStrings(buffer, "ellipse ", r.cssString("", session), " ", r.cssString("", session), " ") shapeText = "" - buffer.WriteString(r.cssString("", session)) - buffer.WriteString(" ") - buffer.WriteString(r.cssString("", session)) - buffer.WriteString(" ") } else { ErrorLog(`Invalid radial gradient radius: ` + text) } @@ -250,29 +244,20 @@ func (gradient *backgroundRadialGradient) cssStyle(session Session) string { case int: values := enumProperties[RadialGradientRadius].cssValues if value >= 0 && value < len(values) { - buffer.WriteString(shapeText) + writeStrings(buffer, shapeText, values[value], " ") shapeText = "" - buffer.WriteString(values[value]) - buffer.WriteString(" ") } else { ErrorLogF(`Invalid radial gradient radius: %d`, value) } case SizeUnit: if value.Type != Auto { - buffer.WriteString("ellipse ") + writeStrings(buffer, "ellipse ", value.cssString("", session), " ", value.cssString("", session), " ") shapeText = "" - buffer.WriteString(value.cssString("", session)) - buffer.WriteString(" ") - buffer.WriteString(value.cssString("", session)) - buffer.WriteString(" ") } case []SizeUnit: - count := len(value) - if count > 2 { - count = 2 - } + count := max(len(value), 2) buffer.WriteString("ellipse ") shapeText = "" for i := range count { @@ -281,10 +266,7 @@ func (gradient *backgroundRadialGradient) cssStyle(session Session) string { } case []any: - count := len(value) - if count > 2 { - count = 2 - } + count := max(len(value), 2) buffer.WriteString("ellipse ") shapeText = "" for i := range count { @@ -316,13 +298,7 @@ func (gradient *backgroundRadialGradient) cssStyle(session Session) string { x, _ := sizeProperty(gradient, CenterX, session) y, _ := sizeProperty(gradient, CenterX, session) if x.Type != Auto || y.Type != Auto { - if shapeText != "" { - buffer.WriteString(shapeText) - } - buffer.WriteString("at ") - buffer.WriteString(x.cssString("50%", session)) - buffer.WriteString(" ") - buffer.WriteString(y.cssString("50%", session)) + writeStrings(buffer, shapeText, "at ", x.cssString("50%", session), " ", y.cssString("50%", session)) } else if shapeText != "" { buffer.WriteString(shapeText) } diff --git a/border.go b/border.go index 76456c3..27f2deb 100644 --- a/border.go +++ b/border.go @@ -386,9 +386,7 @@ func (border *borderProperty) writeString(buffer *strings.Builder, indent string if comma { buffer.WriteString(", ") } - buffer.WriteString(string(tag)) - buffer.WriteString(" = ") - buffer.WriteString(text) + writeStrings(buffer, string(tag), " = ", text) comma = true } } diff --git a/canvas.go b/canvas.go index 1f4b0bd..29571b8 100644 --- a/canvas.go +++ b/canvas.go @@ -615,19 +615,16 @@ func (canvas *canvasData) fontWithParams(name string, size SizeUnit, params Font case SizeInPercent: if params.LineHeight.Value != 100 { - buffer.WriteString("/") - buffer.WriteString(strconv.FormatFloat(params.LineHeight.Value/100, 'g', -1, 64)) + writeStrings(buffer, "/", strconv.FormatFloat(params.LineHeight.Value/100, 'g', -1, 64)) } case SizeInFraction: if params.LineHeight.Value != 1 { - buffer.WriteString("/") - buffer.WriteString(strconv.FormatFloat(params.LineHeight.Value, 'g', -1, 64)) + writeStrings(buffer, "/", strconv.FormatFloat(params.LineHeight.Value, 'g', -1, 64)) } default: - buffer.WriteString("/") - buffer.WriteString(params.LineHeight.cssString("", canvas.View().Session())) + writeStrings(buffer, "/", params.LineHeight.cssString("", canvas.View().Session())) } lead := " " @@ -636,9 +633,7 @@ func (canvas *canvasData) fontWithParams(name string, size SizeUnit, params Font buffer.WriteString(lead) lead = "," if strings.ContainsRune(font, ' ') { - buffer.WriteRune('"') - buffer.WriteString(font) - buffer.WriteRune('"') + writeStrings(buffer, `"`, font, `"`) } else { buffer.WriteString(font) } diff --git a/checkbox.go b/checkbox.go index c731186..43b7790 100644 --- a/checkbox.go +++ b/checkbox.go @@ -199,13 +199,11 @@ func (button *checkboxData) cssStyle(self View, builder cssBuilder) { } func checkboxHtml(button View, buffer *strings.Builder, checked bool) (int, int) { - //func (button *checkboxData) htmlCheckbox(buffer *strings.Builder, checked bool) (int, int) { + vAlign := GetCheckboxVerticalAlign(button) hAlign := GetCheckboxHorizontalAlign(button) - buffer.WriteString(`
`) + writeStrings(buffer, + " align-items: ", checkboxVerticalAlignCSS(button), `;`, + " justify-items: ", checkboxHorizontalAlignCSS(button), `;">`) button.viewsContainerData.htmlSubviews(self, buffer) buffer.WriteString(`
`) } diff --git a/clipShape.go b/clipShape.go index 77dc00a..00fe64b 100644 --- a/clipShape.go +++ b/clipShape.go @@ -249,9 +249,7 @@ func (clip *insetClipData) writeString(buffer *strings.Builder, indent string) { if comma { buffer.WriteString(", ") } - buffer.WriteString(string(tag)) - buffer.WriteString(" = ") - buffer.WriteString(text) + writeStrings(buffer, string(tag), " = ", text) comma = true } } @@ -325,9 +323,7 @@ func (clip *circleClipData) writeString(buffer *strings.Builder, indent string) if comma { buffer.WriteString(", ") } - buffer.WriteString(string(tag)) - buffer.WriteString(" = ") - buffer.WriteString(text) + writeStrings(buffer, string(tag), " = ", text) comma = true } } @@ -341,18 +337,12 @@ func (clip *circleClipData) cssStyle(session Session) string { buffer := allocStringBuilder() defer freeStringBuilder(buffer) - buffer.WriteString("circle(") r, _ := sizeProperty(clip, Radius, session) - buffer.WriteString(r.cssString("50%", session)) - - buffer.WriteString(" at ") x, _ := sizeProperty(clip, X, session) - buffer.WriteString(x.cssString("50%", session)) - buffer.WriteRune(' ') - y, _ := sizeProperty(clip, Y, session) - buffer.WriteString(y.cssString("50%", session)) - buffer.WriteRune(')') + + writeStrings(buffer, "circle(", r.cssString("50%", session), + " at ", x.cssString("50%", session), " ", y.cssString("50%", session), ")") return buffer.String() } @@ -405,9 +395,7 @@ func (clip *ellipseClipData) writeString(buffer *strings.Builder, indent string) if comma { buffer.WriteString(", ") } - buffer.WriteString(string(tag)) - buffer.WriteString(" = ") - buffer.WriteString(text) + writeStrings(buffer, string(tag), " = ", text) comma = true } } @@ -423,19 +411,11 @@ func (clip *ellipseClipData) cssStyle(session Session) string { rx, _ := sizeProperty(clip, RadiusX, session) ry, _ := sizeProperty(clip, RadiusX, session) - buffer.WriteString("ellipse(") - buffer.WriteString(rx.cssString("50%", session)) - buffer.WriteRune(' ') - buffer.WriteString(ry.cssString("50%", session)) - - buffer.WriteString(" at ") x, _ := sizeProperty(clip, X, session) - buffer.WriteString(x.cssString("50%", session)) - buffer.WriteRune(' ') - y, _ := sizeProperty(clip, Y, session) - buffer.WriteString(y.cssString("50%", session)) - buffer.WriteRune(')') + + writeStrings(buffer, "ellipse(", rx.cssString("50%", session), " ", ry.cssString("50%", session), + " at ", x.cssString("50%", session), " ", y.cssString("50%", session), ")") return buffer.String() } diff --git a/color.go b/color.go index cf8bd71..dcb1a44 100644 --- a/color.go +++ b/color.go @@ -209,11 +209,7 @@ func stringToColor(text string) (Color, error) { func writeColorCSS(buffer *strings.Builder, lightColor, darkColor Color, session Session) { if session.lightDarkSupport() { - buffer.WriteString("light-dark(") - buffer.WriteString(lightColor.cssString()) - buffer.WriteRune(',') - buffer.WriteString(darkColor.cssString()) - buffer.WriteRune(')') + writeStrings(buffer, "light-dark(", lightColor.cssString(), ",", darkColor.cssString(), ")") } else if session.DarkTheme() { buffer.WriteString(darkColor.cssString()) } else { diff --git a/colorPicker.go b/colorPicker.go index 0d063e2..29629fc 100644 --- a/colorPicker.go +++ b/colorPicker.go @@ -147,11 +147,8 @@ func (picker *colorPickerData) htmlSubviews(self View, buffer *strings.Builder) func (picker *colorPickerData) htmlProperties(self View, buffer *strings.Builder) { picker.viewData.htmlProperties(self, buffer) - buffer.WriteString(` type="color" value="`) - buffer.WriteString(GetColorPickerValue(picker).rgbString()) - buffer.WriteByte('"') - - buffer.WriteString(` oninput="editViewInputEvent(this)"`) + writeStrings(buffer, ` type="color" value="`, GetColorPickerValue(picker).rgbString(), `"`, + ` oninput="editViewInputEvent(this)"`) if picker.getRaw(ClickEvent) == nil { buffer.WriteString(` onclick="stopEventPropagation(this, event)"`) } diff --git a/cssBuilder.go b/cssBuilder.go index 7df91df..2b89d3f 100644 --- a/cssBuilder.go +++ b/cssBuilder.go @@ -88,10 +88,7 @@ func (builder *viewCSSBuilder) add(key, value string) { builder.buffer.WriteRune(' ') } - builder.buffer.WriteString(key) - builder.buffer.WriteString(": ") - builder.buffer.WriteString(value) - builder.buffer.WriteRune(';') + writeStrings(builder.buffer, key, ": ", value, ";") } } @@ -193,9 +190,7 @@ func (builder *cssStyleBuilder) startMedia(rule string) { if builder.buffer == nil { builder.init(0) } - builder.buffer.WriteString(`@media screen`) - builder.buffer.WriteString(rule) - builder.buffer.WriteString(` {\n`) + writeStrings(builder.buffer, `@media screen`, rule, ` {\n`) builder.media = true } @@ -247,9 +242,7 @@ func (builder *cssStyleBuilder) startAnimation(name string) { } builder.media = true - builder.buffer.WriteString(`\n@keyframes `) - builder.buffer.WriteString(name) - builder.buffer.WriteString(` {\n`) + writeStrings(builder.buffer, `\n@keyframes `, name, ` {\n`) } func (builder *cssStyleBuilder) endAnimation() { @@ -265,9 +258,7 @@ func (builder *cssStyleBuilder) startAnimationFrame(name string) { builder.init(0) } - builder.buffer.WriteString(`\t`) - builder.buffer.WriteString(name) - builder.buffer.WriteString(` {\n`) + writeStrings(builder.buffer, `\t`, name, ` {\n`) } func (builder *cssStyleBuilder) endAnimationFrame() { @@ -285,11 +276,7 @@ func (builder *cssStyleBuilder) add(key, value string) { if builder.media { builder.buffer.WriteString(`\t`) } - builder.buffer.WriteString(`\t`) - builder.buffer.WriteString(key) - builder.buffer.WriteString(`: `) - builder.buffer.WriteString(value) - builder.buffer.WriteString(`;\n`) + writeStrings(builder.buffer, `\t`, key, `: `, value, `;\n`) } } @@ -300,9 +287,7 @@ func (builder *cssStyleBuilder) addWriter(key string, writer func(buffer *string if builder.media { builder.buffer.WriteString(`\t`) } - builder.buffer.WriteString(`\t`) - builder.buffer.WriteString(key) - builder.buffer.WriteString(": ") + writeStrings(builder.buffer, `\t`, key, ": ") writer(builder.buffer) builder.buffer.WriteString(`;\n`) } @@ -318,9 +303,7 @@ func (builder *cssStyleBuilder) addValues(key, separator string, values ...strin if builder.media { builder.buffer.WriteString(`\t`) } - builder.buffer.WriteString(`\t`) - builder.buffer.WriteString(key) - builder.buffer.WriteString(`: `) + writeStrings(builder.buffer, `\t`, key, `: `) for i, value := range values { if i > 0 { builder.buffer.WriteString(separator) diff --git a/dataList.go b/dataList.go index 63e84b7..c631459 100644 --- a/dataList.go +++ b/dataList.go @@ -283,9 +283,8 @@ func getDataListProperty(properties Properties) []string { func dataListHtmlSubviews(view View, buffer *strings.Builder, normalizeItem func(text string, session Session) string) { if items := getDataListProperty(view); len(items) > 0 { session := view.Session() - buffer.WriteString(``) + + writeStrings(buffer, ``) for _, text := range items { text = normalizeItem(text, session) @@ -295,9 +294,7 @@ func dataListHtmlSubviews(view View, buffer *strings.Builder, normalizeItem func if strings.ContainsRune(text, '\n') { text = strings.ReplaceAll(text, "\n", `\n`) } - buffer.WriteString(``) + writeStrings(buffer, ``) } buffer.WriteString(``) } @@ -305,9 +302,7 @@ func dataListHtmlSubviews(view View, buffer *strings.Builder, normalizeItem func func dataListHtmlProperties(view View, buffer *strings.Builder) { if len(getDataListProperty(view)) > 0 { - buffer.WriteString(` list="`) - buffer.WriteString(dataListID(view)) - buffer.WriteString(`"`) + writeStrings(buffer, ` list="`, dataListID(view), `"`) } } diff --git a/datePicker.go b/datePicker.go index daaa0cb..25a5377 100644 --- a/datePicker.go +++ b/datePicker.go @@ -319,26 +319,18 @@ func (picker *datePickerData) htmlProperties(self View, buffer *strings.Builder) buffer.WriteString(` type="date"`) if min, ok := getDateProperty(picker, DatePickerMin, Min); ok { - buffer.WriteString(` min="`) - buffer.WriteString(min.Format(dateFormat)) - buffer.WriteByte('"') + writeStrings(buffer, ` min="`, min.Format(dateFormat), `"`) } if max, ok := getDateProperty(picker, DatePickerMax, Max); ok { - buffer.WriteString(` max="`) - buffer.WriteString(max.Format(dateFormat)) - buffer.WriteByte('"') + writeStrings(buffer, ` max="`, max.Format(dateFormat), `"`) } if step, ok := intProperty(picker, DatePickerStep, picker.Session(), 0); ok && step > 0 { - buffer.WriteString(` step="`) - buffer.WriteString(strconv.Itoa(step)) - buffer.WriteByte('"') + writeStrings(buffer, ` step="`, strconv.Itoa(step), `"`) } - buffer.WriteString(` value="`) - buffer.WriteString(GetDatePickerValue(picker).Format(dateFormat)) - buffer.WriteByte('"') + writeStrings(buffer, ` value="`, GetDatePickerValue(picker).Format(dateFormat), `"`) buffer.WriteString(` oninput="editViewInputEvent(this)"`) if picker.getRaw(ClickEvent) == nil { diff --git a/dragAndDrop.go b/dragAndDrop.go index 2409f1f..355292f 100644 --- a/dragAndDrop.go +++ b/dragAndDrop.go @@ -415,9 +415,7 @@ func dragAndDropHtml(view View, buffer *strings.Builder) { } if dragData := base64DragData(view); dragData != "" { - buffer.WriteString(`draggable="true" data-drag="`) - buffer.WriteString(dragData) - buffer.WriteString(`" ondragstart="dragStartEvent(this, event)" `) + writeStrings(buffer, `draggable="true" data-drag="`, dragData, `" ondragstart="dragStartEvent(this, event)" `) } else if len(getOneArgEventListeners[View, DragAndDropEvent](view, nil, DragStartEvent)) > 0 { buffer.WriteString(` ondragstart="dragStartEvent(this, event)" `) } @@ -444,9 +442,7 @@ func dragAndDropHtml(view View, buffer *strings.Builder) { } if img := GetDragImage(view); img != "" { - buffer.WriteString(` data-drag-image="`) - buffer.WriteString(img) - buffer.WriteString(`" `) + writeStrings(buffer, ` data-drag-image="`, img, `" `) } if f := GetDragImageXOffset(view); f != 0 { @@ -463,9 +459,7 @@ func dragAndDropHtml(view View, buffer *strings.Builder) { effects := []string{"undefined", "copy", "move", "copyMove", "link", "copyLink", "linkMove", "all"} if n := GetDropEffectAllowed(view); n > 0 && n < len(effects) { - buffer.WriteString(` data-drop-effect-allowed="`) - buffer.WriteString(effects[n]) - buffer.WriteString(`" `) + writeStrings(buffer, ` data-drop-effect-allowed="`, effects[n], `" `) } } diff --git a/dropDownList.go b/dropDownList.go index e3e8a23..3a1d00a 100644 --- a/dropDownList.go +++ b/dropDownList.go @@ -1,6 +1,7 @@ package rui import ( + "slices" "strconv" "strings" ) @@ -211,13 +212,7 @@ func (list *dropDownListData) htmlSubviews(self View, buffer *strings.Builder) { disabledItems := GetDropDownDisabledItems(list) separators := GetDropDownItemSeparators(list) for i, item := range items { - disabled := false - for _, index := range disabledItems { - if i == index { - disabled = true - break - } - } + disabled := slices.Contains(disabledItems, i) if disabled { buffer.WriteString("") - for _, index := range separators { - if i == index { - buffer.WriteString("
") - break - } + if slices.Contains(separators, i) { + buffer.WriteString("
") } } } diff --git a/editView.go b/editView.go index 48fc578..5f99947 100644 --- a/editView.go +++ b/editView.go @@ -352,9 +352,7 @@ func (edit *editViewData) htmlProperties(self View, buffer *strings.Builder) { } if maxLength := GetMaxLength(edit); maxLength > 0 { - buffer.WriteString(` maxlength="`) - buffer.WriteString(strconv.Itoa(maxLength)) - buffer.WriteByte('"') + writeStrings(buffer, ` maxlength="`, strconv.Itoa(maxLength), `"`) } convertText := func(text string) string { @@ -368,23 +366,17 @@ func (edit *editViewData) htmlProperties(self View, buffer *strings.Builder) { } if hint := GetHint(edit); hint != "" { - buffer.WriteString(` placeholder="`) - buffer.WriteString(convertText(hint)) - buffer.WriteByte('"') + writeStrings(buffer, ` placeholder="`, convertText(hint), `"`) } buffer.WriteString(` oninput="editViewInputEvent(this)"`) if pattern := GetEditViewPattern(edit); pattern != "" { - buffer.WriteString(` pattern="`) - buffer.WriteString(convertText(pattern)) - buffer.WriteByte('"') + writeStrings(buffer, ` pattern="`, convertText(pattern), `"`) } if editType != MultiLineText { if text := GetText(edit); text != "" { - buffer.WriteString(` value="`) - buffer.WriteString(convertText(text)) - buffer.WriteByte('"') + writeStrings(buffer, ` value="`, convertText(text), `"`) } } diff --git a/events.go b/events.go index 891fb48..7c1582c 100644 --- a/events.go +++ b/events.go @@ -45,10 +45,7 @@ func viewEventsHtml[T any](view View, events []PropertyName, buffer *strings.Bui for _, tag := range events { if js, ok := eventJsFunc[tag]; ok { if value := getOneArgEventListeners[View, T](view, nil, tag); len(value) > 0 { - buffer.WriteString(js.jsEvent) - buffer.WriteString(`="`) - buffer.WriteString(js.jsFunc) - buffer.WriteString(`(this, event)" `) + writeStrings(buffer, js.jsEvent, `="`, js.jsFunc, `(this, event)" `) } } } diff --git a/filePicker.go b/filePicker.go index 7bdd8f4..dcbbbb2 100644 --- a/filePicker.go +++ b/filePicker.go @@ -258,9 +258,7 @@ func (picker *filePickerData) htmlProperties(self View, buffer *strings.Builder) picker.viewData.htmlProperties(self, buffer) if accept := acceptPropertyCSS(picker); accept != "" { - buffer.WriteString(` accept="`) - buffer.WriteString(accept) - buffer.WriteRune('"') + writeStrings(buffer, ` accept="`, accept, `"`) } buffer.WriteString(` type="file"`) diff --git a/filter.go b/filter.go index b5889b2..814b594 100644 --- a/filter.go +++ b/filter.go @@ -236,10 +236,7 @@ func (filter *filterData) cssStyle(session Session) string { defer freeStringBuilder(buffer) if value, ok := floatTextProperty(filter, Blur, session, 0); ok { - buffer.WriteString(string(Blur)) - buffer.WriteRune('(') - buffer.WriteString(value) - buffer.WriteString("px)") + writeStrings(buffer, string(Blur), "(", value, "px)") } for _, tag := range []PropertyName{Brightness, Contrast, Saturate, Grayscale, Invert, Opacity, Sepia} { @@ -247,10 +244,7 @@ func (filter *filterData) cssStyle(session Session) string { if buffer.Len() > 0 { buffer.WriteRune(' ') } - buffer.WriteString(string(tag)) - buffer.WriteRune('(') - buffer.WriteString(value) - buffer.WriteString("%)") + writeStrings(buffer, string(tag), "(", value, "%)") } } @@ -258,10 +252,7 @@ func (filter *filterData) cssStyle(session Session) string { if buffer.Len() > 0 { buffer.WriteRune(' ') } - buffer.WriteString(string(HueRotate)) - buffer.WriteRune('(') - buffer.WriteString(value.cssString()) - buffer.WriteRune(')') + writeStrings(buffer, string(HueRotate), "(", value.cssString(), ")") } var lead string diff --git a/focusEvents.go b/focusEvents.go index 9d09ff8..58cc169 100644 --- a/focusEvents.go +++ b/focusEvents.go @@ -39,10 +39,7 @@ func focusEventsHtml(view View, buffer *strings.Builder) { if view.Focusable() { for _, tag := range []PropertyName{FocusEvent, LostFocusEvent} { if js, ok := eventJsFunc[tag]; ok { - buffer.WriteString(js.jsEvent) - buffer.WriteString(`="`) - buffer.WriteString(js.jsFunc) - buffer.WriteString(`(this, event)" `) + writeStrings(buffer, js.jsEvent, `="`, js.jsFunc, `(this, event)" `) } } } diff --git a/imageView.go b/imageView.go index c4efe29..a2c85cb 100644 --- a/imageView.go +++ b/imageView.go @@ -252,21 +252,15 @@ func (imageView *imageViewData) htmlProperties(self View, buffer *strings.Builde if imageResource, ok := imageProperty(imageView, Source, imageView.Session()); ok && imageResource != "" { if src, srcset := imageViewSrc(imageView, imageResource); src != "" { - buffer.WriteString(` src="`) - buffer.WriteString(src) - buffer.WriteString(`"`) + writeStrings(buffer, ` src="`, src, `"`) if srcset != "" { - buffer.WriteString(` srcset="`) - buffer.WriteString(srcset) - buffer.WriteString(`"`) + writeStrings(buffer, ` srcset="`, srcset, `"`) } } } if text := GetImageViewAltText(imageView); text != "" { - buffer.WriteString(` alt="`) - buffer.WriteString(text) - buffer.WriteString(`"`) + writeStrings(buffer, ` alt="`, text, `"`) } buffer.WriteString(` onload="imageLoaded(this, event)"`) diff --git a/listView.go b/listView.go index 117c4b5..d9aaf66 100644 --- a/listView.go +++ b/listView.go @@ -494,30 +494,22 @@ func (listView *listViewData) getItemFrames() []Frame { func (listView *listViewData) itemAlign(buffer *strings.Builder) { values := enumProperties[ItemHorizontalAlign].cssValues if hAlign := GetListItemHorizontalAlign(listView); hAlign >= 0 && hAlign < len(values) { - buffer.WriteString(" justify-items: ") - buffer.WriteString(values[hAlign]) - buffer.WriteRune(';') + writeStrings(buffer, " justify-items: ", values[hAlign], ";") } values = enumProperties[ItemVerticalAlign].cssValues if vAlign := GetListItemVerticalAlign(listView); vAlign >= 0 && vAlign < len(values) { - buffer.WriteString(" align-items: ") - buffer.WriteString(values[vAlign]) - buffer.WriteRune(';') + writeStrings(buffer, " align-items: ", values[vAlign], ";") } } func (listView *listViewData) itemSize(buffer *strings.Builder) { if itemWidth := GetListItemWidth(listView); itemWidth.Type != Auto { - buffer.WriteString(` min-width: `) - buffer.WriteString(itemWidth.cssString("", listView.Session())) - buffer.WriteRune(';') + writeStrings(buffer, ` min-width: `, itemWidth.cssString("", listView.Session()), ";") } if itemHeight := GetListItemHeight(listView); itemHeight.Type != Auto { - buffer.WriteString(` min-height: `) - buffer.WriteString(itemHeight.cssString("", listView.Session())) - buffer.WriteRune(';') + writeStrings(buffer, ` min-height: `, itemHeight.cssString("", listView.Session()), ";") } } @@ -610,9 +602,7 @@ func (listView *listViewData) checkboxItemDiv(hCheckboxAlign, vCheckboxAlign int } if gap, ok := sizeConstant(listView.session, "ruiCheckboxGap"); ok && gap.Type != Auto { - itemStyleBuilder.WriteString(` grid-gap: `) - itemStyleBuilder.WriteString(gap.cssString("auto", listView.Session())) - itemStyleBuilder.WriteRune(';') + writeStrings(itemStyleBuilder, ` grid-gap: `, gap.cssString("auto", listView.Session()), ";") } itemStyleBuilder.WriteString(`">`) @@ -690,12 +680,8 @@ func (listView *listViewData) checkboxSubviews(adapter ListAdapter, buffer *stri enabledItems := listView.itemEnabledAdapter(adapter) for i := range count { - buffer.WriteString(`
= 0 && current < adapter.ListSize() { - buffer.WriteString(` data-current="`) - buffer.WriteString(listView.htmlID()) - buffer.WriteRune('-') - buffer.WriteString(strconv.Itoa(current)) - buffer.WriteRune('"') + writeStrings(buffer, ` data-current="`, listView.htmlID(), "-", strconv.Itoa(current), `"`) } } listView.viewData.htmlProperties(self, buffer) @@ -852,15 +822,11 @@ func listDiv(listView View, buffer *strings.Builder) { buffer.WriteString(`
`) diff --git a/mediaPlayer.go b/mediaPlayer.go index 8b1e683..e80deea 100644 --- a/mediaPlayer.go +++ b/mediaPlayer.go @@ -946,13 +946,9 @@ func (player *mediaPlayerData) htmlSubviews(self View, buffer *strings.Builder) session := player.session for _, src := range sources { if url, ok := session.resolveConstants(src.Url); ok && url != "" { - buffer.WriteString(`') } @@ -972,18 +968,12 @@ func (player *mediaPlayerData) htmlProperties(self View, buffer *strings.Builder if value, ok := enumProperty(player, Preload, player.session, 0); ok { values := enumProperties[Preload].values - buffer.WriteString(` preload="`) - buffer.WriteString(values[value]) - buffer.WriteRune('"') + writeStrings(buffer, ` preload="`, values[value], `"`) } for tag, cssTag := range mediaPlayerEvents() { if value := player.getRaw(tag); value != nil { - buffer.WriteString(` `) - buffer.WriteString(cssTag) - buffer.WriteString(`="playerEvent(this, '`) - buffer.WriteString(string(tag)) - buffer.WriteString(`')"`) + writeStrings(buffer, ` `, cssTag, `="playerEvent(this, '`, string(tag), `')"`) } } diff --git a/progressBar.go b/progressBar.go index 723b583..2f121dc 100644 --- a/progressBar.go +++ b/progressBar.go @@ -91,13 +91,8 @@ func (progress *progressBarData) htmlTag() string { func (progress *progressBarData) htmlProperties(self View, buffer *strings.Builder) { progress.viewData.htmlProperties(self, buffer) - buffer.WriteString(` max="`) - buffer.WriteString(strconv.FormatFloat(GetProgressBarMax(progress), 'f', -1, 64)) - buffer.WriteByte('"') - - buffer.WriteString(` value="`) - buffer.WriteString(strconv.FormatFloat(GetProgressBarValue(progress), 'f', -1, 64)) - buffer.WriteByte('"') + writeStrings(buffer, ` max="`, strconv.FormatFloat(GetProgressBarMax(progress), 'f', -1, 64), `"`, + ` value="`, strconv.FormatFloat(GetProgressBarValue(progress), 'f', -1, 64), `"`) } // GetProgressBarMax returns the max value of ProgressBar subview. diff --git a/properties.go b/properties.go index 6df0f87..1463008 100644 --- a/properties.go +++ b/properties.go @@ -132,26 +132,19 @@ func (properties *propertyList) AllTags() []PropertyName { func (properties *propertyList) writeToBuffer(buffer *strings.Builder, indent string, objectTag string, tags []PropertyName) { - buffer.WriteString(objectTag) - buffer.WriteString(" {\n") - + writeStrings(buffer, objectTag, " {\n") indent2 := indent + "\t" for _, tag := range tags { if value, ok := properties.properties[tag]; ok { text := propertyValueToString(tag, value, indent2) if text != "" { - buffer.WriteString(indent2) - buffer.WriteString(string(tag)) - buffer.WriteString(" = ") - buffer.WriteString(text) - buffer.WriteString(",\n") + writeStrings(buffer, indent2, string(tag), " = ", text, ",\n") } } } - buffer.WriteString(indent) - buffer.WriteString("}") + writeStrings(buffer, indent, "}") } */ @@ -214,8 +207,7 @@ func (data *dataProperty) writeToBuffer(buffer *strings.Builder, indent string, data.mutex.Lock() defer data.mutex.Unlock() - buffer.WriteString(objectName) - buffer.WriteString("{ ") + writeStrings(buffer, objectName, "{ ") comma := false for _, tag := range tags { if value, ok := data.properties[tag]; ok { @@ -224,9 +216,7 @@ func (data *dataProperty) writeToBuffer(buffer *strings.Builder, indent string, if comma { buffer.WriteString(", ") } - buffer.WriteString(string(tag)) - buffer.WriteString(" = ") - buffer.WriteString(text) + writeStrings(buffer, string(tag), " = ", text) comma = true } } diff --git a/radius.go b/radius.go index d5168d9..56a1fdc 100644 --- a/radius.go +++ b/radius.go @@ -771,43 +771,31 @@ func (radius BoxRadius) String() string { buffer.WriteString("_{ ") if radius.TopLeftX.Equal(radius.TopLeftY) { - buffer.WriteString("top-left = ") - buffer.WriteString(radius.TopLeftX.String()) + writeStrings(buffer, "top-left = ", radius.TopLeftX.String()) } else { - buffer.WriteString("top-left-x = ") - buffer.WriteString(radius.TopLeftX.String()) - buffer.WriteString("top-left-y = ") - buffer.WriteString(radius.TopLeftY.String()) + writeStrings(buffer, "top-left-x = ", radius.TopLeftX.String(), + ", top-left-y = ", radius.TopLeftY.String()) } if radius.TopRightX.Equal(radius.TopRightY) { - buffer.WriteString(", top-right = ") - buffer.WriteString(radius.TopRightX.String()) + writeStrings(buffer, ", top-right = ", radius.TopRightX.String()) } else { - buffer.WriteString(", top-right-x = ") - buffer.WriteString(radius.TopRightX.String()) - buffer.WriteString(", top-right-y = ") - buffer.WriteString(radius.TopRightY.String()) + writeStrings(buffer, ", top-right-x = ", radius.TopRightX.String(), + ", top-right-y = ", radius.TopRightY.String()) } if radius.BottomLeftX.Equal(radius.BottomLeftY) { - buffer.WriteString(", bottom-left = ") - buffer.WriteString(radius.BottomLeftX.String()) + writeStrings(buffer, ", bottom-left = ", radius.BottomLeftX.String()) } else { - buffer.WriteString(", bottom-left-x = ") - buffer.WriteString(radius.BottomLeftX.String()) - buffer.WriteString(", bottom-left-y = ") - buffer.WriteString(radius.BottomLeftY.String()) + writeStrings(buffer, ", bottom-left-x = ", radius.BottomLeftX.String(), + ", bottom-left-y = ", radius.BottomLeftY.String()) } if radius.BottomRightX.Equal(radius.BottomRightY) { - buffer.WriteString(", bottom-right = ") - buffer.WriteString(radius.BottomRightX.String()) + writeStrings(buffer, ", bottom-right = ", radius.BottomRightX.String()) } else { - buffer.WriteString(", bottom-right-x = ") - buffer.WriteString(radius.BottomRightX.String()) - buffer.WriteString(", bottom-right-y = ") - buffer.WriteString(radius.BottomRightY.String()) + writeStrings(buffer, ", bottom-right-x = ", radius.BottomRightX.String(), + ", bottom-right-y = ", radius.BottomRightY.String()) } buffer.WriteString(" }") @@ -835,32 +823,24 @@ func (radius BoxRadius) cssValue(builder cssBuilder, session Session) { if radius.AllAnglesIsEqual() { if !radius.TopLeftX.Equal(radius.TopLeftY) { - buffer.WriteString(" / ") - buffer.WriteString(radius.TopLeftY.cssString("0", session)) + writeStrings(buffer, " / ", radius.TopLeftY.cssString("0", session)) } } else { - buffer.WriteRune(' ') - buffer.WriteString(radius.TopRightX.cssString("0", session)) - buffer.WriteRune(' ') - buffer.WriteString(radius.BottomRightX.cssString("0", session)) - buffer.WriteRune(' ') - buffer.WriteString(radius.BottomLeftX.cssString("0", session)) + writeStrings(buffer, " ", radius.TopRightX.cssString("0", session), + " ", radius.BottomRightX.cssString("0", session), + " ", radius.BottomLeftX.cssString("0", session)) if !radius.TopLeftX.Equal(radius.TopLeftY) || !radius.TopRightX.Equal(radius.TopRightY) || !radius.BottomLeftX.Equal(radius.BottomLeftY) || !radius.BottomRightX.Equal(radius.BottomRightY) { - buffer.WriteString(" / ") - buffer.WriteString(radius.TopLeftY.cssString("0", session)) - buffer.WriteRune(' ') - buffer.WriteString(radius.TopRightY.cssString("0", session)) - buffer.WriteRune(' ') - buffer.WriteString(radius.BottomRightY.cssString("0", session)) - buffer.WriteRune(' ') - buffer.WriteString(radius.BottomLeftY.cssString("0", session)) + writeStrings(buffer, " / ", radius.TopLeftY.cssString("0", session), + " ", radius.TopRightY.cssString("0", session), + " ", radius.BottomRightY.cssString("0", session), + " ", radius.BottomLeftY.cssString("0", session)) } } diff --git a/resizable.go b/resizable.go index bce4410..f95bb15 100644 --- a/resizable.go +++ b/resizable.go @@ -377,64 +377,44 @@ func (resizable *resizableData) htmlSubviews(self View, buffer *strings.Builder) top = 2 if leftSide { - buffer.WriteString(`
`) + writeStrings(buffer, `
`) if checked { buffer.WriteString(checkImage) } diff --git a/shadow.go b/shadow.go index 697f4c5..36841f3 100644 --- a/shadow.go +++ b/shadow.go @@ -224,14 +224,8 @@ func (shadow *shadowPropertyData) cssStyle(buffer *strings.Builder, session Sess buffer.WriteString("inset ") } - buffer.WriteString(offsetX.cssString("0", session)) - buffer.WriteByte(' ') - buffer.WriteString(offsetY.cssString("0", session)) - buffer.WriteByte(' ') - buffer.WriteString(blurRadius.cssString("0", session)) - buffer.WriteByte(' ') - buffer.WriteString(spreadRadius.cssString("0", session)) - buffer.WriteByte(' ') + writeStrings(buffer, offsetX.cssString("0", session), " ", offsetY.cssString("0", session), " ", + blurRadius.cssString("0", session), " ", spreadRadius.cssString("0", session), " ") writeColorCSS(buffer, lightColor, darkColor, session) return true } @@ -249,13 +243,8 @@ func (shadow *shadowPropertyData) cssTextStyle(buffer *strings.Builder, session return false } - buffer.WriteString(lead) - buffer.WriteString(offsetX.cssString("0", session)) - buffer.WriteByte(' ') - buffer.WriteString(offsetY.cssString("0", session)) - buffer.WriteByte(' ') - buffer.WriteString(blurRadius.cssString("0", session)) - buffer.WriteByte(' ') + writeStrings(buffer, lead, offsetX.cssString("0", session), " ", offsetY.cssString("0", session), + " ", blurRadius.cssString("0", session), " ") writeColorCSS(buffer, lightColor, darkColor, session) return true } diff --git a/stackLayout.go b/stackLayout.go index f811dda..1a9616d 100644 --- a/stackLayout.go +++ b/stackLayout.go @@ -585,11 +585,7 @@ func (layout *stackLayoutData) moveToFrontByIndex(index int, onShow []func(View) buffer := allocStringBuilder() defer freeStringBuilder(buffer) - buffer.WriteString(`stackTransitionEndEvent('`) - buffer.WriteString(layout.htmlID()) - buffer.WriteString(`', 'move-`) - buffer.WriteString(view.htmlID()) - buffer.WriteString(`', event)`) + writeStrings(buffer, `stackTransitionEndEvent('`, layout.htmlID(), `', 'move-`, view.htmlID(), `', event)`) listener := buffer.String() @@ -667,9 +663,7 @@ func (layout *stackLayoutData) Append(view View) { buffer := allocStringBuilder() defer freeStringBuilder(buffer) - buffer.WriteString(`
`) + writeStrings(buffer, `
`) viewHTML(view, buffer, "") buffer.WriteString(`
`) @@ -706,9 +700,7 @@ func (layout *stackLayoutData) Insert(view View, index int) { buffer := allocStringBuilder() defer freeStringBuilder(buffer) - buffer.WriteString(`