Added OpenURL function, optimisation

This commit is contained in:
Alexei Anoshenko 2022-08-18 18:18:36 +03:00
parent 705a9c0e37
commit 7c860c54b9
12 changed files with 106 additions and 59 deletions

View File

@ -1,12 +1,13 @@
# v0.9.0 # v0.9.0
* Requared go 1.18 * Requires go 1.18 or higher
* The "interface{}" type replaced by "any" * The "interface{}" type replaced by "any"
* Added "overflow", "arrow", "arrow-align", "arrow-size", "arrow-width", and "arrow-offset" properties * Added "overflow", "arrow", "arrow-align", "arrow-size", "arrow-width", and "arrow-offset" properties
* Added "@ruiArrowSize" and "@ruiArrowWidth" constants to the default theme * Added "@ruiArrowSize" and "@ruiArrowWidth" constants to the default theme
* Added Transition, Transitions, and SetTransition functions to the ViewStyle interface * Added Transition, Transitions, and SetTransition functions to the ViewStyle interface
* Added GetOverflow, IsTimingFunctionValid, and GetTransitions functions * Added GetOverflow, IsTimingFunctionValid, and GetTransitions functions
* Changed GetTransition functions * Changed GetTransition functions
* Added the OpenURL function to the Session interface
# v0.8.0 # v0.8.0

View File

@ -400,7 +400,7 @@ func (animation *animationData) animationCSS(session Session) string {
buffer.WriteString(animation.keyFramesName) buffer.WriteString(animation.keyFramesName)
if duration, _ := floatProperty(animation, Duration, session, 1); duration > 0 { if duration, ok := floatProperty(animation, Duration, session, 1); ok && duration > 0 {
buffer.WriteString(fmt.Sprintf(" %gs ", duration)) buffer.WriteString(fmt.Sprintf(" %gs ", duration))
} else { } else {
buffer.WriteString(" 1s ") buffer.WriteString(" 1s ")
@ -408,7 +408,7 @@ func (animation *animationData) animationCSS(session Session) string {
buffer.WriteString(animation.timingFunctionCSS(session)) buffer.WriteString(animation.timingFunctionCSS(session))
if delay, _ := floatProperty(animation, Delay, session, 0); delay > 0 { if delay, ok := floatProperty(animation, Delay, session, 0); ok && delay > 0 {
buffer.WriteString(fmt.Sprintf(" %gs", delay)) buffer.WriteString(fmt.Sprintf(" %gs", delay))
} else { } else {
buffer.WriteString(" 0s") buffer.WriteString(" 0s")
@ -438,7 +438,7 @@ func (animation *animationData) animationCSS(session Session) string {
func (animation *animationData) transitionCSS(buffer *strings.Builder, session Session) { func (animation *animationData) transitionCSS(buffer *strings.Builder, session Session) {
if duration, _ := floatProperty(animation, Duration, session, 1); duration > 0 { if duration, ok := floatProperty(animation, Duration, session, 1); ok && duration > 0 {
buffer.WriteString(fmt.Sprintf(" %gs ", duration)) buffer.WriteString(fmt.Sprintf(" %gs ", duration))
} else { } else {
buffer.WriteString(" 1s ") buffer.WriteString(" 1s ")
@ -446,7 +446,7 @@ func (animation *animationData) transitionCSS(buffer *strings.Builder, session S
buffer.WriteString(animation.timingFunctionCSS(session)) buffer.WriteString(animation.timingFunctionCSS(session))
if delay, _ := floatProperty(animation, Delay, session, 0); delay > 0 { if delay, ok := floatProperty(animation, Delay, session, 0); ok && delay > 0 {
buffer.WriteString(fmt.Sprintf(" %gs", delay)) buffer.WriteString(fmt.Sprintf(" %gs", delay))
} }
} }

View File

@ -114,12 +114,13 @@ func (picker *numberPickerData) set(tag string, value any) bool {
oldValue := GetNumberPickerValue(picker, "") oldValue := GetNumberPickerValue(picker, "")
min, max := GetNumberPickerMinMax(picker, "") min, max := GetNumberPickerMinMax(picker, "")
if picker.setFloatProperty(NumberPickerValue, value, min, max) { if picker.setFloatProperty(NumberPickerValue, value, min, max) {
if newValue := GetNumberPickerValue(picker, ""); oldValue != newValue { if f, ok := floatProperty(picker, NumberPickerValue, picker.Session(), min); ok && f != oldValue {
newValue, _ := floatTextProperty(picker, NumberPickerValue, picker.Session(), min)
if picker.created { if picker.created {
picker.session.runScript(fmt.Sprintf(`setInputValue('%s', '%f')`, picker.htmlID(), newValue)) picker.session.runScript(fmt.Sprintf(`setInputValue('%s', '%s')`, picker.htmlID(), newValue))
} }
for _, listener := range picker.numberChangedListeners { for _, listener := range picker.numberChangedListeners {
listener(picker, newValue) listener(picker, f)
} }
picker.propertyChangedEvent(tag) picker.propertyChangedEvent(tag)
} }
@ -239,7 +240,7 @@ func (picker *numberPickerData) handleCommand(self View, command string, data Da
if text, ok := data.PropertyValue("text"); ok { if text, ok := data.PropertyValue("text"); ok {
if value, err := strconv.ParseFloat(text, 32); err == nil { if value, err := strconv.ParseFloat(text, 32); err == nil {
oldValue := GetNumberPickerValue(picker, "") oldValue := GetNumberPickerValue(picker, "")
picker.properties[NumberPickerValue] = value picker.properties[NumberPickerValue] = text
if value != oldValue { if value != oldValue {
for _, listener := range picker.numberChangedListeners { for _, listener := range picker.numberChangedListeners {
listener(picker, value) listener(picker, value)

View File

@ -1,6 +1,7 @@
package rui package rui
import ( import (
"fmt"
"strconv" "strconv"
"strings" "strings"
) )
@ -238,6 +239,30 @@ func floatProperty(properties Properties, tag string, session Session, defaultVa
return valueToFloat(properties.getRaw(tag), session, defaultValue) return valueToFloat(properties.getRaw(tag), session, defaultValue)
} }
func valueToFloatText(value any, session Session, defaultValue float64) (string, bool) {
if value != nil {
switch value := value.(type) {
case float64:
return fmt.Sprintf("%g", value), true
case string:
if text, ok := session.resolveConstants(value); ok {
if _, err := strconv.ParseFloat(text, 64); err != nil {
ErrorLog(err.Error())
return fmt.Sprintf("%g", defaultValue), false
}
return text, true
}
}
}
return fmt.Sprintf("%g", defaultValue), false
}
func floatTextProperty(properties Properties, tag string, session Session, defaultValue float64) (string, bool) {
return valueToFloatText(properties.getRaw(tag), session, defaultValue)
}
func valueToRange(value any, session Session) (Range, bool) { func valueToRange(value any, session Session) (Range, bool) {
if value != nil { if value != nil {
switch value := value.(type) { switch value := value.(type) {

View File

@ -730,6 +730,12 @@ func (properties *propertyList) setFloatProperty(tag string, value any, min, max
ErrorLog(err.Error()) ErrorLog(err.Error())
return false return false
} }
if f < min || f > max {
ErrorLogF(`"%T" out of range of "%s" property`, value, tag)
return false
}
properties.properties[tag] = value
return true
case float32: case float32:
f = float64(value) f = float64(value)

View File

@ -2,6 +2,7 @@ package rui
import ( import (
"fmt" "fmt"
"net/url"
"strconv" "strconv"
"strings" "strings"
) )
@ -69,6 +70,8 @@ type Session interface {
DownloadFile(path string) DownloadFile(path string)
//DownloadFileData downloads (saves) on the client side a file with a specified name and specified content. //DownloadFileData downloads (saves) on the client side a file with a specified name and specified content.
DownloadFileData(filename string, data []byte) DownloadFileData(filename string, data []byte)
// OpenURL opens the url in the new browser tab
OpenURL(url string)
registerAnimation(props []AnimatedProperty) string registerAnimation(props []AnimatedProperty) string
@ -448,3 +451,11 @@ func (session *sessionData) SetTitleColor(color Color) {
func (session *sessionData) RemoteAddr() string { func (session *sessionData) RemoteAddr() string {
return session.brige.remoteAddr() return session.brige.remoteAddr()
} }
func (session *sessionData) OpenURL(urlStr string) {
if _, err := url.ParseRequestURI(urlStr); err != nil {
ErrorLog(err.Error())
return
}
session.runScript(`window.open("` + urlStr + `", "_blank");`)
}

View File

@ -622,7 +622,7 @@ func (table *tableViewData) propertyChanged(tag string) {
updateProperty(htmlID, "tabindex", "0", session) updateProperty(htmlID, "tabindex", "0", session)
updateProperty(htmlID, "onfocus", "tableViewFocusEvent(this, event)", session) updateProperty(htmlID, "onfocus", "tableViewFocusEvent(this, event)", session)
updateProperty(htmlID, "onblur", "tableViewBlurEvent(this, event)", session) updateProperty(htmlID, "onblur", "tableViewBlurEvent(this, event)", session)
updateProperty(htmlID, "data-selection", "cell", session) updateProperty(htmlID, "data-selection", "row", session)
updateProperty(htmlID, "data-focusitemstyle", table.currentStyle(), session) updateProperty(htmlID, "data-focusitemstyle", table.currentStyle(), session)
updateProperty(htmlID, "data-bluritemstyle", table.currentInactiveStyle(), session) updateProperty(htmlID, "data-bluritemstyle", table.currentInactiveStyle(), session)

View File

@ -1,7 +1,6 @@
package rui package rui
import ( import (
"fmt"
"strings" "strings"
) )
@ -90,9 +89,9 @@ func (player *videoPlayerData) set(tag string, value any) bool {
if player.mediaPlayerData.set(tag, value) { if player.mediaPlayerData.set(tag, value) {
session := player.Session() session := player.Session()
updateSize := func(cssTag string) { updateSize := func(cssTag string) {
if size, ok := floatProperty(player, tag, session, 0); ok { if size, ok := floatTextProperty(player, tag, session, 0); ok {
if size > 0 { if size != "0" {
updateProperty(player.htmlID(), cssTag, fmt.Sprintf("%g", size), session) updateProperty(player.htmlID(), cssTag, size, session)
} else { } else {
removeProperty(player.htmlID(), cssTag, session) removeProperty(player.htmlID(), cssTag, session)
} }
@ -122,12 +121,16 @@ func (player *videoPlayerData) htmlProperties(self View, buffer *strings.Builder
session := player.Session() session := player.Session()
if size, ok := floatProperty(player, VideoWidth, session, 0); ok && size > 0 { if size, ok := floatTextProperty(player, VideoWidth, session, 0); ok && size != "0" {
buffer.WriteString(fmt.Sprintf(` width="%g"`, size)) buffer.WriteString(` width="`)
buffer.WriteString(size)
buffer.WriteString(`"`)
} }
if size, ok := floatProperty(player, VideoHeight, session, 0); ok && size > 0 { if size, ok := floatTextProperty(player, VideoHeight, session, 0); ok && size != "0" {
buffer.WriteString(fmt.Sprintf(` height="%g"`, size)) buffer.WriteString(` height="`)
buffer.WriteString(size)
buffer.WriteString(`"`)
} }
if url, ok := stringProperty(player, Poster, session); ok && url != "" { if url, ok := stringProperty(player, Poster, session); ok && url != "" {

View File

@ -655,8 +655,8 @@ func viewPropertyChanged(view *viewData, tag string) {
for _, floatTag := range []string{Opacity, ScaleX, ScaleY, ScaleZ, RotateX, RotateY, RotateZ} { for _, floatTag := range []string{Opacity, ScaleX, ScaleY, ScaleZ, RotateX, RotateY, RotateZ} {
if tag == floatTag { if tag == floatTag {
if f, ok := floatProperty(view, floatTag, session, 0); ok { if f, ok := floatTextProperty(view, floatTag, session, 0); ok {
updateCSSProperty(htmlID, floatTag, strconv.FormatFloat(f, 'g', -1, 64), session) updateCSSProperty(htmlID, floatTag, f, session)
} }
return return
} }

View File

@ -180,20 +180,22 @@ func (filter *viewFilter) cssStyle(session Session) string {
buffer := allocStringBuilder() buffer := allocStringBuilder()
defer freeStringBuilder(buffer) defer freeStringBuilder(buffer)
if value, ok := floatProperty(filter, Blur, session, 0); ok { if value, ok := floatTextProperty(filter, Blur, session, 0); ok {
size := SizeUnit{Type: SizeInPixel, Value: value}
buffer.WriteString(Blur) buffer.WriteString(Blur)
buffer.WriteRune('(') buffer.WriteRune('(')
buffer.WriteString(size.cssString("0px")) buffer.WriteString(value)
buffer.WriteRune(')') buffer.WriteString("px)")
} }
for _, tag := range []string{Brightness, Contrast, Saturate, Grayscale, Invert, Opacity, Sepia} { for _, tag := range []string{Brightness, Contrast, Saturate, Grayscale, Invert, Opacity, Sepia} {
if value, ok := floatProperty(filter, tag, session, 0); ok { if value, ok := floatTextProperty(filter, tag, session, 0); ok {
if buffer.Len() > 0 { if buffer.Len() > 0 {
buffer.WriteRune(' ') buffer.WriteRune(' ')
} }
buffer.WriteString(fmt.Sprintf("%s(%g%%)", tag, value)) buffer.WriteString(tag)
buffer.WriteRune('(')
buffer.WriteString(value)
buffer.WriteString("%)")
} }
} }

View File

@ -1,9 +1,5 @@
package rui package rui
import (
"strconv"
)
const ( const (
// Perspective is the name of the SizeUnit property that determines the distance between the z = 0 plane // Perspective is the name of the SizeUnit property that determines the distance between the z = 0 plane
// and the user in order to give a 3D-positioned element some perspective. Each 3D element // and the user in order to give a 3D-positioned element some perspective. Each 3D element
@ -104,20 +100,6 @@ func getTranslate(style Properties, session Session) (SizeUnit, SizeUnit, SizeUn
return x, y, z return x, y, z
} }
func getScale(style Properties, session Session) (float64, float64, float64, bool) {
scaleX, okX := floatProperty(style, ScaleX, session, 1)
scaleY, okY := floatProperty(style, ScaleY, session, 1)
scaleZ, okZ := floatProperty(style, ScaleZ, session, 1)
return scaleX, scaleY, scaleZ, okX || okY || okZ
}
func getRotateVector(style Properties, session Session) (float64, float64, float64) {
rotateX, _ := floatProperty(style, RotateX, session, 1)
rotateY, _ := floatProperty(style, RotateY, session, 1)
rotateZ, _ := floatProperty(style, RotateZ, session, 1)
return rotateX, rotateY, rotateZ
}
func (style *viewStyle) transform(session Session) string { func (style *viewStyle) transform(session Session) string {
buffer := allocStringBuilder() buffer := allocStringBuilder()
@ -133,7 +115,10 @@ func (style *viewStyle) transform(session Session) string {
} }
x, y, z := getTranslate(style, session) x, y, z := getTranslate(style, session)
scaleX, scaleY, scaleZ, scaleOK := getScale(style, session)
scaleX, okScaleX := floatTextProperty(style, ScaleX, session, 1)
scaleY, okScaleY := floatTextProperty(style, ScaleY, session, 1)
if getTransform3D(style, session) { if getTransform3D(style, session) {
if x.Type != Auto || y.Type != Auto || z.Type != Auto { if x.Type != Auto || y.Type != Auto || z.Type != Auto {
if buffer.Len() > 0 { if buffer.Len() > 0 {
@ -148,30 +133,34 @@ func (style *viewStyle) transform(session Session) string {
buffer.WriteRune(')') buffer.WriteRune(')')
} }
if scaleOK { scaleZ, okScaleZ := floatTextProperty(style, ScaleZ, session, 1)
if okScaleX || okScaleY || okScaleZ {
if buffer.Len() > 0 { if buffer.Len() > 0 {
buffer.WriteRune(' ') buffer.WriteRune(' ')
} }
buffer.WriteString(`scale3d(`) buffer.WriteString(`scale3d(`)
buffer.WriteString(strconv.FormatFloat(scaleX, 'g', -1, 64)) buffer.WriteString(scaleX)
buffer.WriteRune(',') buffer.WriteRune(',')
buffer.WriteString(strconv.FormatFloat(scaleY, 'g', -1, 64)) buffer.WriteString(scaleY)
buffer.WriteRune(',') buffer.WriteRune(',')
buffer.WriteString(strconv.FormatFloat(scaleZ, 'g', -1, 64)) buffer.WriteString(scaleZ)
buffer.WriteRune(')') buffer.WriteRune(')')
} }
if angle, ok := angleProperty(style, Rotate, session); ok { if angle, ok := angleProperty(style, Rotate, session); ok {
rotateX, rotateY, rotateZ := getRotateVector(style, session) rotateX, _ := floatTextProperty(style, RotateX, session, 1)
rotateY, _ := floatTextProperty(style, RotateY, session, 1)
rotateZ, _ := floatTextProperty(style, RotateZ, session, 1)
if buffer.Len() > 0 { if buffer.Len() > 0 {
buffer.WriteRune(' ') buffer.WriteRune(' ')
} }
buffer.WriteString(`rotate3d(`) buffer.WriteString(`rotate3d(`)
buffer.WriteString(strconv.FormatFloat(rotateX, 'g', -1, 64)) buffer.WriteString(rotateX)
buffer.WriteRune(',') buffer.WriteRune(',')
buffer.WriteString(strconv.FormatFloat(rotateY, 'g', -1, 64)) buffer.WriteString(rotateY)
buffer.WriteRune(',') buffer.WriteRune(',')
buffer.WriteString(strconv.FormatFloat(rotateZ, 'g', -1, 64)) buffer.WriteString(rotateZ)
buffer.WriteRune(',') buffer.WriteRune(',')
buffer.WriteString(angle.cssString()) buffer.WriteString(angle.cssString())
buffer.WriteRune(')') buffer.WriteRune(')')
@ -189,14 +178,14 @@ func (style *viewStyle) transform(session Session) string {
buffer.WriteRune(')') buffer.WriteRune(')')
} }
if scaleOK { if okScaleX || okScaleY {
if buffer.Len() > 0 { if buffer.Len() > 0 {
buffer.WriteRune(' ') buffer.WriteRune(' ')
} }
buffer.WriteString(`scale(`) buffer.WriteString(`scale(`)
buffer.WriteString(strconv.FormatFloat(scaleX, 'g', -1, 64)) buffer.WriteString(scaleX)
buffer.WriteRune(',') buffer.WriteRune(',')
buffer.WriteString(strconv.FormatFloat(scaleY, 'g', -1, 64)) buffer.WriteString(scaleY)
buffer.WriteRune(')') buffer.WriteRune(')')
} }

View File

@ -368,7 +368,9 @@ func GetTextWeight(view View, subviewID string) int {
} }
// GetTextAlign returns a text align of the subview. Returns one of next values: // GetTextAlign returns a text align of the subview. Returns one of next values:
//
// LeftAlign = 0, RightAlign = 1, CenterAlign = 2, JustifyAlign = 3 // LeftAlign = 0, RightAlign = 1, CenterAlign = 2, JustifyAlign = 3
//
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
func GetTextAlign(view View, subviewID string) int { func GetTextAlign(view View, subviewID string) int {
return enumStyledProperty(view, subviewID, TextAlign, LeftAlign, true) return enumStyledProperty(view, subviewID, TextAlign, LeftAlign, true)
@ -601,7 +603,11 @@ func GetScale(view View, subviewID string) (float64, float64, float64) {
if view == nil { if view == nil {
return 1, 1, 1 return 1, 1, 1
} }
x, y, z, _ := getScale(view, view.Session())
session := view.Session()
x, _ := floatProperty(view, ScaleX, session, 1)
y, _ := floatProperty(view, ScaleY, session, 1)
z, _ := floatProperty(view, ScaleZ, session, 1)
return x, y, z return x, y, z
} }
@ -615,8 +621,11 @@ func GetRotate(view View, subviewID string) (float64, float64, float64, AngleUni
return 0, 0, 0, AngleUnit{Value: 0, Type: Radian} return 0, 0, 0, AngleUnit{Value: 0, Type: Radian}
} }
session := view.Session()
angle, _ := angleProperty(view, Rotate, view.Session()) angle, _ := angleProperty(view, Rotate, view.Session())
rotateX, rotateY, rotateZ := getRotateVector(view, view.Session()) rotateX, _ := floatProperty(view, RotateX, session, 1)
rotateY, _ := floatProperty(view, RotateY, session, 1)
rotateZ, _ := floatProperty(view, RotateZ, session, 1)
return rotateX, rotateY, rotateZ, angle return rotateX, rotateY, rotateZ, angle
} }