mirror of https://github.com/anoshenko/rui.git
Work with rui data files has been redesigned
This commit is contained in:
parent
d6d243458c
commit
6e703f0692
144
animation.go
144
animation.go
|
|
@ -245,12 +245,16 @@ func parseAnimation(obj DataObject) AnimationProperty {
|
||||||
animation := new(animationData)
|
animation := new(animationData)
|
||||||
animation.init()
|
animation.init()
|
||||||
|
|
||||||
for node := range obj.Properties() {
|
for tag, node := range obj.Properties() {
|
||||||
tag := PropertyName(node.Tag())
|
switch node.Type() {
|
||||||
if node.Type() == TextNode {
|
case TextDataValue:
|
||||||
animation.Set(tag, node.Text())
|
animation.Set(PropertyName(tag), node.String())
|
||||||
} else {
|
|
||||||
animation.Set(tag, node)
|
case ObjectDataValue:
|
||||||
|
animation.Set(PropertyName(tag), node.Object())
|
||||||
|
|
||||||
|
case ArrayDataValue:
|
||||||
|
animation.Set(PropertyName(tag), node.Array())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return animation
|
return animation
|
||||||
|
|
@ -418,6 +422,47 @@ func normalizeAnimation(tag PropertyName) PropertyName {
|
||||||
}
|
}
|
||||||
|
|
||||||
func animationSet(properties Properties, tag PropertyName, value any) []PropertyName {
|
func animationSet(properties Properties, tag PropertyName, value any) []PropertyName {
|
||||||
|
|
||||||
|
parseObject := func(obj DataObject) (AnimatedProperty, bool) {
|
||||||
|
result := AnimatedProperty{}
|
||||||
|
for tag, value := range obj.Properties() {
|
||||||
|
if value.Type() == TextDataValue {
|
||||||
|
propTag := strings.ToLower(tag)
|
||||||
|
switch propTag {
|
||||||
|
case "from", "0", "0%":
|
||||||
|
result.From = value.String()
|
||||||
|
|
||||||
|
case "to", "100", "100%":
|
||||||
|
result.To = value.String()
|
||||||
|
|
||||||
|
default:
|
||||||
|
tagLen := len(propTag)
|
||||||
|
if tagLen > 0 && propTag[tagLen-1] == '%' {
|
||||||
|
propTag = propTag[:tagLen-1]
|
||||||
|
}
|
||||||
|
n, err := strconv.Atoi(propTag)
|
||||||
|
if err != nil {
|
||||||
|
ErrorLog(err.Error())
|
||||||
|
} else if n < 0 || n > 100 {
|
||||||
|
ErrorLogF(`key-frame "%d" is out of range`, n)
|
||||||
|
} else {
|
||||||
|
if result.KeyFrames == nil {
|
||||||
|
result.KeyFrames = map[int]any{n: value.String()}
|
||||||
|
} else {
|
||||||
|
result.KeyFrames[n] = value.String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(obj.Tag()) > 0 {
|
||||||
|
result.Tag = PropertyName(obj.Tag())
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, result.From != nil && result.To != nil
|
||||||
|
}
|
||||||
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case ID:
|
case ID:
|
||||||
if text, ok := value.(string); ok {
|
if text, ok := value.(string); ok {
|
||||||
|
|
@ -486,61 +531,16 @@ func animationSet(properties Properties, tag PropertyName, value any) []Property
|
||||||
ErrorLog("[]AnimatedProperty is empty")
|
ErrorLog("[]AnimatedProperty is empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
case DataNode:
|
case DataObject:
|
||||||
parseObject := func(obj DataObject) (AnimatedProperty, bool) {
|
if prop, ok := parseObject(value); ok {
|
||||||
result := AnimatedProperty{}
|
|
||||||
for node := range obj.Properties() {
|
|
||||||
if node.Type() == TextNode {
|
|
||||||
propTag := strings.ToLower(node.Tag())
|
|
||||||
switch propTag {
|
|
||||||
case "from", "0", "0%":
|
|
||||||
result.From = node.Text()
|
|
||||||
|
|
||||||
case "to", "100", "100%":
|
|
||||||
result.To = node.Text()
|
|
||||||
|
|
||||||
default:
|
|
||||||
tagLen := len(propTag)
|
|
||||||
if tagLen > 0 && propTag[tagLen-1] == '%' {
|
|
||||||
propTag = propTag[:tagLen-1]
|
|
||||||
}
|
|
||||||
n, err := strconv.Atoi(propTag)
|
|
||||||
if err != nil {
|
|
||||||
ErrorLog(err.Error())
|
|
||||||
} else if n < 0 || n > 100 {
|
|
||||||
ErrorLogF(`key-frame "%d" is out of range`, n)
|
|
||||||
} else {
|
|
||||||
if result.KeyFrames == nil {
|
|
||||||
result.KeyFrames = map[int]any{n: node.Text()}
|
|
||||||
} else {
|
|
||||||
result.KeyFrames[n] = node.Text()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(obj.Tag()) > 0 {
|
|
||||||
result.Tag = PropertyName(obj.Tag())
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.From != nil && result.To != nil {
|
|
||||||
return result, true
|
|
||||||
}
|
|
||||||
return result, false
|
|
||||||
}
|
|
||||||
|
|
||||||
switch value.Type() {
|
|
||||||
case ObjectNode:
|
|
||||||
if prop, ok := parseObject(value.Object()); ok {
|
|
||||||
properties.setRaw(tag, []AnimatedProperty{prop})
|
properties.setRaw(tag, []AnimatedProperty{prop})
|
||||||
return []PropertyName{tag}
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
|
|
||||||
case ArrayNode:
|
case DataArray:
|
||||||
props := []AnimatedProperty{}
|
props := []AnimatedProperty{}
|
||||||
for val := range value.ArrayElements() {
|
for val := range value.Elements() {
|
||||||
if val.IsObject() {
|
if val.Type() == ObjectDataValue {
|
||||||
if prop, ok := parseObject(val.Object()); ok {
|
if prop, ok := parseObject(val.Object()); ok {
|
||||||
props = append(props, prop)
|
props = append(props, prop)
|
||||||
}
|
}
|
||||||
|
|
@ -553,6 +553,17 @@ func animationSet(properties Properties, tag PropertyName, value any) []Property
|
||||||
return []PropertyName{tag}
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case DataValue:
|
||||||
|
switch value.Type() {
|
||||||
|
case TextDataValue:
|
||||||
|
return animationSet(properties, tag, value.String())
|
||||||
|
|
||||||
|
case ObjectDataValue:
|
||||||
|
return animationSet(properties, tag, value.Object())
|
||||||
|
|
||||||
|
case ArrayDataValue:
|
||||||
|
return animationSet(properties, tag, value.Array())
|
||||||
|
|
||||||
default:
|
default:
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
}
|
}
|
||||||
|
|
@ -1088,25 +1099,38 @@ func setAnimationProperty(properties Properties, tag PropertyName, value any) bo
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
case DataNode:
|
case DataArray:
|
||||||
animations := []AnimationProperty{}
|
animations := []AnimationProperty{}
|
||||||
result := true
|
result := true
|
||||||
for i := range value.ArraySize() {
|
for val := range value.Elements() {
|
||||||
if obj := value.ArrayElement(i).Object(); obj != nil {
|
if obj := val.Object(); obj != nil {
|
||||||
if anim := parseAnimation(obj); anim.hasAnimatedProperty() {
|
if anim := parseAnimation(obj); anim.hasAnimatedProperty() {
|
||||||
animations = append(animations, anim)
|
animations = append(animations, anim)
|
||||||
} else {
|
} else {
|
||||||
result = false
|
result = false
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
notCompatibleType(tag, value.ArrayElement(i))
|
notCompatibleType(tag, val)
|
||||||
result = false
|
result = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if result && len(animations) > 0 {
|
if result && len(animations) > 0 {
|
||||||
set(animations)
|
set(animations)
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
case DataValue:
|
||||||
|
switch value.Type() {
|
||||||
|
case TextDataValue:
|
||||||
|
return setAnimationProperty(properties, tag, value.String())
|
||||||
|
|
||||||
|
case ObjectDataValue:
|
||||||
|
return setAnimationProperty(properties, tag, value.Object())
|
||||||
|
|
||||||
|
case ArrayDataValue:
|
||||||
|
return setAnimationProperty(properties, tag, value.Array())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
|
|
|
||||||
|
|
@ -157,7 +157,7 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (view *viewData) handleTransitionEvents(tag PropertyName, data DataObject) {
|
func (view *viewData) handleTransitionEvents(tag PropertyName, data DataObject) {
|
||||||
if propertyName, ok := data.PropertyValue("property"); ok {
|
if propertyName, ok := data.PropertyText("property"); ok {
|
||||||
property := PropertyName(propertyName)
|
property := PropertyName(propertyName)
|
||||||
if tag == TransitionEndEvent || tag == TransitionCancelEvent {
|
if tag == TransitionEndEvent || tag == TransitionCancelEvent {
|
||||||
if animation, ok := view.singleTransition[property]; ok {
|
if animation, ok := view.singleTransition[property]; ok {
|
||||||
|
|
@ -177,7 +177,7 @@ func (view *viewData) handleTransitionEvents(tag PropertyName, data DataObject)
|
||||||
func (view *viewData) handleAnimationEvents(tag PropertyName, data DataObject) {
|
func (view *viewData) handleAnimationEvents(tag PropertyName, data DataObject) {
|
||||||
if listeners := getOneArgEventListeners[View, string](view, nil, tag); len(listeners) > 0 {
|
if listeners := getOneArgEventListeners[View, string](view, nil, tag); len(listeners) > 0 {
|
||||||
id := ""
|
id := ""
|
||||||
if name, ok := data.PropertyValue("name"); ok {
|
if name, ok := data.PropertyText("name"); ok {
|
||||||
for _, animation := range GetAnimation(view) {
|
for _, animation := range GetAnimation(view) {
|
||||||
if name == animation.animationName() {
|
if name == animation.animationName() {
|
||||||
id, _ = stringProperty(animation, ID, view.Session())
|
id, _ = stringProperty(animation, ID, view.Session())
|
||||||
|
|
|
||||||
|
|
@ -272,7 +272,7 @@ func (app *application) sseHandler(w http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSessionID(obj DataObject) (int, bool) {
|
func getSessionID(obj DataObject) (int, bool) {
|
||||||
sessionText, ok := obj.PropertyValue("session")
|
sessionText, ok := obj.PropertyText("session")
|
||||||
if !ok {
|
if !ok {
|
||||||
ErrorLog(`"session" key not found`)
|
ErrorLog(`"session" key not found`)
|
||||||
return 0, false
|
return 0, false
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,10 @@ type backgroundElement struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func createBackground(obj DataObject) BackgroundElement {
|
func createBackground(obj DataObject) BackgroundElement {
|
||||||
|
if obj == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
var result BackgroundElement = nil
|
var result BackgroundElement = nil
|
||||||
|
|
||||||
switch obj.Tag() {
|
switch obj.Tag() {
|
||||||
|
|
@ -66,11 +70,9 @@ func createBackground(obj DataObject) BackgroundElement {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
for node := range obj.Properties() {
|
for tag, text := range obj.TextProperties() {
|
||||||
if node.Type() == TextNode {
|
if text != "" {
|
||||||
if value := node.Text(); value != "" {
|
result.Set(PropertyName(tag), text)
|
||||||
result.Set(PropertyName(node.Tag()), value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -96,30 +98,47 @@ func parseBackgroundValue(value any) []BackgroundElement {
|
||||||
case []BackgroundElement:
|
case []BackgroundElement:
|
||||||
return value
|
return value
|
||||||
|
|
||||||
case []DataValue:
|
case DataValue:
|
||||||
background := []BackgroundElement{}
|
switch value.Type() {
|
||||||
for _, el := range value {
|
case TextDataValue:
|
||||||
if el.IsObject() {
|
if element := parseBackgroundText(value.String()); element != nil {
|
||||||
if element := createBackground(el.Object()); element != nil {
|
return []BackgroundElement{element}
|
||||||
|
}
|
||||||
|
|
||||||
|
case ObjectDataValue:
|
||||||
|
if element := createBackground(value.Object()); element != nil {
|
||||||
|
return []BackgroundElement{element}
|
||||||
|
}
|
||||||
|
|
||||||
|
case ArrayDataValue:
|
||||||
|
if array := value.Array(); array != nil {
|
||||||
|
background := make([]BackgroundElement, 0, array.Size())
|
||||||
|
for element := range array.Elements() {
|
||||||
|
switch element.Type() {
|
||||||
|
case ObjectDataValue:
|
||||||
|
if element := createBackground(element.Object()); element != nil {
|
||||||
background = append(background, element)
|
background = append(background, element)
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
} else if element := parseBackgroundText(el.Value()); element != nil {
|
|
||||||
|
case TextDataValue:
|
||||||
|
if element := parseBackgroundText(element.String()); element != nil {
|
||||||
background = append(background, element)
|
background = append(background, element)
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case ArrayDataValue:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return background
|
return background
|
||||||
|
}
|
||||||
case DataObject:
|
|
||||||
if element := createBackground(value); element != nil {
|
|
||||||
return []BackgroundElement{element}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case []DataObject:
|
case []DataObject:
|
||||||
background := []BackgroundElement{}
|
background := make([]BackgroundElement, 0, len(value))
|
||||||
for _, obj := range value {
|
for _, obj := range value {
|
||||||
if element := createBackground(obj); element != nil {
|
if element := createBackground(obj); element != nil {
|
||||||
background = append(background, element)
|
background = append(background, element)
|
||||||
|
|
@ -164,7 +183,6 @@ func parseBackgroundValue(value any) []BackgroundElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return elements
|
return elements
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
28
border.go
28
border.go
|
|
@ -205,16 +205,13 @@ func newBorderProperty(value any) BorderProperty {
|
||||||
case BorderProperty:
|
case BorderProperty:
|
||||||
return value
|
return value
|
||||||
|
|
||||||
case DataNode:
|
case DataValue:
|
||||||
if value.Type() == ObjectNode {
|
if value.Type() == ObjectDataValue {
|
||||||
_ = border.setBorderObject(value.Object())
|
_ = border.setBorderObject(value.Object())
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
case DataObject:
|
|
||||||
_ = border.setBorderObject(value)
|
|
||||||
|
|
||||||
case ViewBorder:
|
case ViewBorder:
|
||||||
border.properties[Style] = value.Style
|
border.properties[Style] = value.Style
|
||||||
border.properties[Width] = value.Width
|
border.properties[Width] = value.Width
|
||||||
|
|
@ -434,17 +431,20 @@ func (border *borderProperty) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (border *borderProperty) setBorderObject(obj DataObject) bool {
|
func (border *borderProperty) setBorderObject(obj DataObject) bool {
|
||||||
|
if obj == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
result := true
|
result := true
|
||||||
for node := range obj.Properties() {
|
for tag, node := range obj.Properties() {
|
||||||
tag := PropertyName(node.Tag())
|
|
||||||
switch node.Type() {
|
switch node.Type() {
|
||||||
case TextNode:
|
case TextDataValue:
|
||||||
if borderSet(border, tag, node.Text()) == nil {
|
if borderSet(border, PropertyName(tag), node.String()) == nil {
|
||||||
result = false
|
result = false
|
||||||
}
|
}
|
||||||
|
|
||||||
case ObjectNode:
|
case ObjectDataValue:
|
||||||
if borderSet(border, tag, node.Object()) == nil {
|
if borderSet(border, PropertyName(tag), node.Object()) == nil {
|
||||||
result = false
|
result = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -535,21 +535,21 @@ func borderSet(properties Properties, tag PropertyName, value any) []PropertyNam
|
||||||
|
|
||||||
setSingleBorderObject := func(prefix PropertyName, obj DataObject) []PropertyName {
|
setSingleBorderObject := func(prefix PropertyName, obj DataObject) []PropertyName {
|
||||||
result := []PropertyName{}
|
result := []PropertyName{}
|
||||||
if text, ok := obj.PropertyValue(string(Style)); ok {
|
if text, ok := obj.PropertyText(string(Style)); ok {
|
||||||
props := setEnumProperty(properties, prefix+"-style", text, enumProperties[BorderStyle].values)
|
props := setEnumProperty(properties, prefix+"-style", text, enumProperties[BorderStyle].values)
|
||||||
if props == nil {
|
if props == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
result = append(result, props...)
|
result = append(result, props...)
|
||||||
}
|
}
|
||||||
if text, ok := obj.PropertyValue(string(ColorTag)); ok {
|
if text, ok := obj.PropertyText(string(ColorTag)); ok {
|
||||||
props := setColorProperty(properties, prefix+"-color", text)
|
props := setColorProperty(properties, prefix+"-color", text)
|
||||||
if props == nil && len(result) == 0 {
|
if props == nil && len(result) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
result = append(result, props...)
|
result = append(result, props...)
|
||||||
}
|
}
|
||||||
if text, ok := obj.PropertyValue("width"); ok {
|
if text, ok := obj.PropertyText("width"); ok {
|
||||||
props := setSizeProperty(properties, prefix+"-width", text)
|
props := setSizeProperty(properties, prefix+"-width", text)
|
||||||
if props == nil && len(result) == 0 {
|
if props == nil && len(result) == 0 {
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -265,7 +265,7 @@ func setBoundsProperty(properties Properties, tag PropertyName, value any) []Pro
|
||||||
case DataObject:
|
case DataObject:
|
||||||
bounds := NewBoundsProperty(nil)
|
bounds := NewBoundsProperty(nil)
|
||||||
for _, tag := range []PropertyName{Top, Right, Bottom, Left} {
|
for _, tag := range []PropertyName{Top, Right, Bottom, Left} {
|
||||||
if text, ok := value.PropertyValue(string(tag)); ok {
|
if text, ok := value.PropertyText(string(tag)); ok {
|
||||||
if !bounds.Set(tag, text) {
|
if !bounds.Set(tag, text) {
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ func TestBoundsSet(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tag := range []string{"padding-left", "padding-top", "padding-right", "padding-bottom"} {
|
for _, tag := range []string{"padding-left", "padding-top", "padding-right", "padding-bottom"} {
|
||||||
if old, ok := obj.PropertyValue(tag); ok {
|
if old, ok := obj.PropertyText(tag); ok {
|
||||||
ignoreTestLog = true
|
ignoreTestLog = true
|
||||||
obj.SetPropertyValue(tag, "x")
|
obj.SetPropertyValue(tag, "x")
|
||||||
if bounds.setProperty(obj, "padding", session) {
|
if bounds.setProperty(obj, "padding", session) {
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,7 @@ func (storage *clientStorageData) RemoveAll() {
|
||||||
|
|
||||||
func (storage *clientStorageData) handleEvent(command string, data DataObject) {
|
func (storage *clientStorageData) handleEvent(command string, data DataObject) {
|
||||||
request := 0
|
request := 0
|
||||||
if text, ok := data.PropertyValue("request"); ok {
|
if text, ok := data.PropertyText("request"); ok {
|
||||||
var err error
|
var err error
|
||||||
if request, err = strconv.Atoi(text); err != nil {
|
if request, err = strconv.Atoi(text); err != nil {
|
||||||
ErrorLog(err.Error())
|
ErrorLog(err.Error())
|
||||||
|
|
@ -126,7 +126,7 @@ func (storage *clientStorageData) handleEvent(command string, data DataObject) {
|
||||||
|
|
||||||
switch command {
|
switch command {
|
||||||
case "storageError":
|
case "storageError":
|
||||||
if text, ok := data.PropertyValue("error"); ok {
|
if text, ok := data.PropertyText("error"); ok {
|
||||||
ErrorLog(text)
|
ErrorLog(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -137,7 +137,7 @@ func (storage *clientStorageData) handleEvent(command string, data DataObject) {
|
||||||
}
|
}
|
||||||
delete(storage.getResult, request)
|
delete(storage.getResult, request)
|
||||||
|
|
||||||
text, ok := data.PropertyValue("values")
|
text, ok := data.PropertyText("values")
|
||||||
if !ok {
|
if !ok {
|
||||||
ErrorLog("'values' property not found (command: storageValues)")
|
ErrorLog("'values' property not found (command: storageValues)")
|
||||||
return
|
return
|
||||||
|
|
|
||||||
10
clipShape.go
10
clipShape.go
|
|
@ -582,7 +582,7 @@ func parseClipShapeProperty(obj DataObject) ClipShapeProperty {
|
||||||
clip := new(insetClipData)
|
clip := new(insetClipData)
|
||||||
clip.init()
|
clip.init()
|
||||||
for _, tag := range []PropertyName{Top, Right, Bottom, Left, Radius, RadiusX, RadiusY} {
|
for _, tag := range []PropertyName{Top, Right, Bottom, Left, Radius, RadiusX, RadiusY} {
|
||||||
if value, ok := obj.PropertyValue(string(tag)); ok {
|
if value, ok := obj.PropertyText(string(tag)); ok {
|
||||||
insetClipDataSet(clip, tag, value)
|
insetClipDataSet(clip, tag, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -592,7 +592,7 @@ func parseClipShapeProperty(obj DataObject) ClipShapeProperty {
|
||||||
clip := new(circleClipData)
|
clip := new(circleClipData)
|
||||||
clip.init()
|
clip.init()
|
||||||
for _, tag := range []PropertyName{X, Y, Radius} {
|
for _, tag := range []PropertyName{X, Y, Radius} {
|
||||||
if value, ok := obj.PropertyValue(string(tag)); ok {
|
if value, ok := obj.PropertyText(string(tag)); ok {
|
||||||
circleClipDataSet(clip, tag, value)
|
circleClipDataSet(clip, tag, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -602,7 +602,7 @@ func parseClipShapeProperty(obj DataObject) ClipShapeProperty {
|
||||||
clip := new(ellipseClipData)
|
clip := new(ellipseClipData)
|
||||||
clip.init()
|
clip.init()
|
||||||
for _, tag := range []PropertyName{X, Y, RadiusX, RadiusY} {
|
for _, tag := range []PropertyName{X, Y, RadiusX, RadiusY} {
|
||||||
if value, ok := obj.PropertyValue(string(tag)); ok {
|
if value, ok := obj.PropertyText(string(tag)); ok {
|
||||||
ellipseClipDataSet(clip, tag, value)
|
ellipseClipDataSet(clip, tag, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -611,7 +611,7 @@ func parseClipShapeProperty(obj DataObject) ClipShapeProperty {
|
||||||
case "polygon":
|
case "polygon":
|
||||||
clip := new(polygonClipData)
|
clip := new(polygonClipData)
|
||||||
clip.init()
|
clip.init()
|
||||||
if value, ok := obj.PropertyValue(string(Points)); ok {
|
if value, ok := obj.PropertyText(string(Points)); ok {
|
||||||
polygonClipDataSet(clip, Points, value)
|
polygonClipDataSet(clip, Points, value)
|
||||||
}
|
}
|
||||||
return clip
|
return clip
|
||||||
|
|
@ -645,7 +645,7 @@ func setClipShapePropertyProperty(properties Properties, tag PropertyName, value
|
||||||
}
|
}
|
||||||
|
|
||||||
case DataValue:
|
case DataValue:
|
||||||
if value.IsObject() {
|
if value.Type() == ObjectDataValue {
|
||||||
if clip := parseClipShapeProperty(value.Object()); clip != nil {
|
if clip := parseClipShapeProperty(value.Object()); clip != nil {
|
||||||
properties.setRaw(tag, clip)
|
properties.setRaw(tag, clip)
|
||||||
return []PropertyName{tag}
|
return []PropertyName{tag}
|
||||||
|
|
|
||||||
10
color.go
10
color.go
|
|
@ -222,20 +222,20 @@ func parseColorPair(obj DataObject) (ColorPair, bool) {
|
||||||
var err error
|
var err error
|
||||||
result := ColorPair{}
|
result := ColorPair{}
|
||||||
|
|
||||||
for property := range obj.Properties() {
|
for tag, property := range obj.Properties() {
|
||||||
if property.Type() != TextNode {
|
if property.Type() != TextDataValue {
|
||||||
return ColorPair{}, false
|
return ColorPair{}, false
|
||||||
}
|
}
|
||||||
|
|
||||||
switch property.Tag() {
|
switch tag {
|
||||||
case "light":
|
case "light":
|
||||||
result.Light, err = stringToColor(property.Text())
|
result.Light, err = stringToColor(property.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ColorPair{}, false
|
return ColorPair{}, false
|
||||||
}
|
}
|
||||||
|
|
||||||
case "dark":
|
case "dark":
|
||||||
result.Dark, err = stringToColor(property.Text())
|
result.Dark, err = stringToColor(property.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ColorPair{}, false
|
return ColorPair{}, false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -159,7 +159,7 @@ func (picker *colorPickerData) htmlProperties(self View, buffer *strings.Builder
|
||||||
func (picker *colorPickerData) handleCommand(self View, command PropertyName, data DataObject) bool {
|
func (picker *colorPickerData) handleCommand(self View, command PropertyName, data DataObject) bool {
|
||||||
switch command {
|
switch command {
|
||||||
case "textChanged":
|
case "textChanged":
|
||||||
if text, ok := data.PropertyValue("text"); ok {
|
if text, ok := data.PropertyText("text"); ok {
|
||||||
if color, ok := StringToColor(text); ok {
|
if color, ok := StringToColor(text); ok {
|
||||||
oldColor := GetColorPickerValue(picker)
|
oldColor := GetColorPickerValue(picker)
|
||||||
picker.setRaw(ColorPickerValue, color)
|
picker.setRaw(ColorPickerValue, color)
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ func newColumnSeparatorProperty(value any) ColumnSeparatorProperty {
|
||||||
separator := new(columnSeparatorProperty)
|
separator := new(columnSeparatorProperty)
|
||||||
separator.init()
|
separator.init()
|
||||||
for _, tag := range []PropertyName{Style, Width, ColorTag} {
|
for _, tag := range []PropertyName{Style, Width, ColorTag} {
|
||||||
if val, ok := value.PropertyValue(string(tag)); ok && val != "" {
|
if val, ok := value.PropertyText(string(tag)); ok && val != "" {
|
||||||
propertiesSet(separator, tag, value)
|
propertiesSet(separator, tag, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
600
data.go
600
data.go
|
|
@ -3,387 +3,131 @@ package rui
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"iter"
|
"os"
|
||||||
"slices"
|
"slices"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode"
|
"unicode"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DataValue interface of a data node value
|
// DataValueType defines the type of DataNode
|
||||||
type DataValue interface {
|
type DataValueType int
|
||||||
// IsObject returns "true" if data value is an object
|
|
||||||
IsObject() bool
|
|
||||||
|
|
||||||
// Object returns data value as a data object
|
// Constants which are used to describe a value type, see [DataValue]
|
||||||
Object() DataObject
|
|
||||||
|
|
||||||
// Value returns value as a string
|
|
||||||
Value() string
|
|
||||||
}
|
|
||||||
|
|
||||||
// DataObject interface of a data object
|
|
||||||
type DataObject interface {
|
|
||||||
DataValue
|
|
||||||
|
|
||||||
// Tag returns data object tag
|
|
||||||
Tag() string
|
|
||||||
|
|
||||||
// Properties() returns an iterator to access the properties
|
|
||||||
Properties() iter.Seq[DataNode]
|
|
||||||
|
|
||||||
// PropertyCount returns properties count
|
|
||||||
PropertyCount() int
|
|
||||||
|
|
||||||
// Property returns a data node corresponding to a property with specific index
|
|
||||||
Property(index int) DataNode
|
|
||||||
|
|
||||||
// PropertyByTag returns a data node corresponding to a property tag
|
|
||||||
PropertyByTag(tag string) DataNode
|
|
||||||
|
|
||||||
// PropertyValue returns a string value of a property with a specific tag
|
|
||||||
PropertyValue(tag string) (string, bool)
|
|
||||||
|
|
||||||
// PropertyObject returns an object value of a property with a specific tag
|
|
||||||
PropertyObject(tag string) DataObject
|
|
||||||
|
|
||||||
// SetPropertyValue sets a string value of a property with a specific tag
|
|
||||||
SetPropertyValue(tag, value string)
|
|
||||||
|
|
||||||
// SetPropertyObject sets an object value of a property with a specific tag
|
|
||||||
SetPropertyObject(tag string, object DataObject)
|
|
||||||
|
|
||||||
// ToParams create a params(map) representation of a data object
|
|
||||||
ToParams() Params
|
|
||||||
|
|
||||||
// PropertyByTag removes a data node corresponding to a property tag and returns it
|
|
||||||
RemovePropertyByTag(tag string) DataNode
|
|
||||||
}
|
|
||||||
|
|
||||||
// DataNodeType defines the type of DataNode
|
|
||||||
type DataNodeType int
|
|
||||||
|
|
||||||
// Constants which are used to describe a node type, see [DataNode]
|
|
||||||
const (
|
const (
|
||||||
// TextNode - node is the pair "tag - text value". Syntax: <tag> = <text>
|
// TextDataValue - the DataValue value is a string.
|
||||||
TextNode DataNodeType = 0
|
// The String() method of DataValue interface is used to access the value.
|
||||||
// ObjectNode - node is the pair "tag - object". Syntax: <tag> = <object name>{...}
|
TextDataValue DataValueType = 0
|
||||||
ObjectNode DataNodeType = 1
|
|
||||||
// ArrayNode - node is the pair "tag - object". Syntax: <tag> = [...]
|
// ObjectDataValue - the DataValue value is a object.
|
||||||
ArrayNode DataNodeType = 2
|
// The Object() method of DataValue interface is used to access the object.
|
||||||
|
ObjectDataValue DataValueType = 1
|
||||||
|
|
||||||
|
// ArrayDataNode - the DataValue value is an array of DataValue.
|
||||||
|
// The Array() method of DataValue interface is used to access the array.
|
||||||
|
ArrayDataValue DataValueType = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
// DataNode interface of a data node
|
// DataValue interface of a data node value
|
||||||
type DataNode interface {
|
type DataValue interface {
|
||||||
// Tag returns a tag name
|
fmt.Stringer
|
||||||
Tag() string
|
|
||||||
|
|
||||||
// Type returns a node type. Possible values are TextNode, ObjectNode and ArrayNode
|
writeToBuffer(buffer *strings.Builder, indent string)
|
||||||
Type() DataNodeType
|
|
||||||
|
|
||||||
// Text returns node text
|
// IsObject returns "true" if data value is an object
|
||||||
Text() string
|
Type() DataValueType
|
||||||
|
|
||||||
// Object returns node as object if that node type is an object
|
// Object returns data value as a data object if Type() == ObjectDataValue, and nil otherwise.
|
||||||
Object() DataObject
|
Object() DataObject
|
||||||
|
|
||||||
// ArraySize returns array size if that node type is an array
|
// Array returns data value as a data array if Type() == ArrayDataValue, and nil otherwise.
|
||||||
ArraySize() int
|
Array() DataArray
|
||||||
|
|
||||||
// ArrayElement returns a value of an array if that node type is an array
|
|
||||||
ArrayElement(index int) DataValue
|
|
||||||
|
|
||||||
// ArrayElements returns an array of objects if that node is an array
|
|
||||||
Array() []DataValue
|
|
||||||
|
|
||||||
// ArrayElements returns an iterator to access the array elements of objects if that node is an array
|
|
||||||
ArrayElements() iter.Seq[DataValue]
|
|
||||||
|
|
||||||
// ArrayAsParams returns an array of a params(map) if that node is an array
|
|
||||||
ArrayAsParams() []Params
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
type dataStringValue struct {
|
type dataStringValue struct {
|
||||||
value string
|
text string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (value *dataStringValue) Value() string {
|
// NewTextData creates an DataValue object of TextDataValue type.
|
||||||
return value.value
|
//
|
||||||
|
// The argument is converted to a string using the following functions:
|
||||||
|
// - int: strconv.FormatInt(value, 10)
|
||||||
|
// - uint: strconv.FormatUint(value, 10)
|
||||||
|
// - bool: fmt.Sprintf("%t", value)
|
||||||
|
// - float: fmt.Sprintf("%g", value)
|
||||||
|
func NewTextData[T string | int | int8 | int16 | int32 | int64 |
|
||||||
|
uint | uint8 | uint16 | uint32 | uint64 | bool | float32 | float64](value T) DataValue {
|
||||||
|
|
||||||
|
data := new(dataStringValue)
|
||||||
|
switch value := any(value).(type) {
|
||||||
|
case string:
|
||||||
|
data.text = value
|
||||||
|
|
||||||
|
case int:
|
||||||
|
data.text = strconv.FormatInt(int64(value), 10)
|
||||||
|
|
||||||
|
case int8:
|
||||||
|
data.text = strconv.FormatInt(int64(value), 10)
|
||||||
|
|
||||||
|
case int16:
|
||||||
|
data.text = strconv.FormatInt(int64(value), 10)
|
||||||
|
|
||||||
|
case int32:
|
||||||
|
data.text = strconv.FormatInt(int64(value), 10)
|
||||||
|
|
||||||
|
case int64:
|
||||||
|
data.text = strconv.FormatInt(value, 10)
|
||||||
|
|
||||||
|
case uint:
|
||||||
|
data.text = strconv.FormatUint(uint64(value), 10)
|
||||||
|
|
||||||
|
case uint8:
|
||||||
|
data.text = strconv.FormatUint(uint64(value), 10)
|
||||||
|
|
||||||
|
case uint16:
|
||||||
|
data.text = strconv.FormatUint(uint64(value), 10)
|
||||||
|
|
||||||
|
case uint32:
|
||||||
|
data.text = strconv.FormatUint(uint64(value), 10)
|
||||||
|
|
||||||
|
case uint64:
|
||||||
|
data.text = strconv.FormatUint(uint64(value), 10)
|
||||||
|
|
||||||
|
case bool:
|
||||||
|
data.text = fmt.Sprintf("%t", value)
|
||||||
|
|
||||||
|
case float32:
|
||||||
|
data.text = fmt.Sprintf("%g", float64(value))
|
||||||
|
|
||||||
|
case float64:
|
||||||
|
data.text = fmt.Sprintf("%g", value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (value *dataStringValue) IsObject() bool {
|
return data
|
||||||
return false
|
}
|
||||||
|
|
||||||
|
func (value *dataStringValue) String() string {
|
||||||
|
return value.text
|
||||||
|
}
|
||||||
|
|
||||||
|
func (value *dataStringValue) writeToBuffer(buffer *strings.Builder, indent string) {
|
||||||
|
writeRuiText(buffer, value.text, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (value *dataStringValue) Type() DataValueType {
|
||||||
|
return TextDataValue
|
||||||
}
|
}
|
||||||
|
|
||||||
func (value *dataStringValue) Object() DataObject {
|
func (value *dataStringValue) Object() DataObject {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
func (value *dataStringValue) Array() DataArray {
|
||||||
type dataObject struct {
|
|
||||||
tag string
|
|
||||||
property []DataNode
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewDataObject create new DataObject with the tag and empty property list
|
|
||||||
func NewDataObject(tag string) DataObject {
|
|
||||||
obj := new(dataObject)
|
|
||||||
obj.tag = tag
|
|
||||||
obj.property = []DataNode{}
|
|
||||||
return obj
|
|
||||||
}
|
|
||||||
|
|
||||||
func (object *dataObject) Value() string {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (object *dataObject) IsObject() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (object *dataObject) Object() DataObject {
|
|
||||||
return object
|
|
||||||
}
|
|
||||||
|
|
||||||
func (object *dataObject) Tag() string {
|
|
||||||
return object.tag
|
|
||||||
}
|
|
||||||
|
|
||||||
func (object *dataObject) Properties() iter.Seq[DataNode] {
|
|
||||||
return func(yield func(DataNode) bool) {
|
|
||||||
for _, node := range object.property {
|
|
||||||
if !yield(node) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (object *dataObject) PropertyCount() int {
|
|
||||||
if object.property != nil {
|
|
||||||
return len(object.property)
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (object *dataObject) Property(index int) DataNode {
|
|
||||||
if object.property == nil || index < 0 || index >= len(object.property) {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return object.property[index]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (object *dataObject) PropertyByTag(tag string) DataNode {
|
|
||||||
if object.property != nil {
|
|
||||||
for _, node := range object.property {
|
|
||||||
if node.Tag() == tag {
|
|
||||||
return node
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (object *dataObject) RemovePropertyByTag(tag string) DataNode {
|
|
||||||
if object.property != nil {
|
|
||||||
index := slices.IndexFunc(object.property, func(node DataNode) bool {
|
|
||||||
return node.Tag() == tag
|
|
||||||
})
|
|
||||||
|
|
||||||
if index >= 0 {
|
|
||||||
node := object.property[index]
|
|
||||||
|
|
||||||
switch index {
|
|
||||||
case 0:
|
|
||||||
object.property = object.property[1:]
|
|
||||||
|
|
||||||
case len(object.property) - 1:
|
|
||||||
object.property = object.property[:len(object.property)-1]
|
|
||||||
|
|
||||||
default:
|
|
||||||
object.property = append(object.property[:index], object.property[index+1:]...)
|
|
||||||
}
|
|
||||||
|
|
||||||
return node
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (object *dataObject) PropertyValue(tag string) (string, bool) {
|
|
||||||
if node := object.PropertyByTag(tag); node != nil && node.Type() == TextNode {
|
|
||||||
return node.Text(), true
|
|
||||||
}
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (object *dataObject) PropertyObject(tag string) DataObject {
|
|
||||||
if node := object.PropertyByTag(tag); node != nil && node.Type() == ObjectNode {
|
|
||||||
return node.Object()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (object *dataObject) setNode(node DataNode) {
|
|
||||||
if len(object.property) == 0 {
|
|
||||||
object.property = []DataNode{node}
|
|
||||||
} else {
|
|
||||||
tag := node.Tag()
|
|
||||||
for i, p := range object.property {
|
|
||||||
if p.Tag() == tag {
|
|
||||||
object.property[i] = node
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object.property = append(object.property, node)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetPropertyValue - set a string property with tag by value
|
|
||||||
func (object *dataObject) SetPropertyValue(tag, value string) {
|
|
||||||
val := new(dataStringValue)
|
|
||||||
val.value = value
|
|
||||||
node := new(dataNode)
|
|
||||||
node.tag = tag
|
|
||||||
node.value = val
|
|
||||||
object.setNode(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetPropertyObject - set a property with tag by object
|
|
||||||
func (object *dataObject) SetPropertyObject(tag string, obj DataObject) {
|
|
||||||
if obj != nil {
|
|
||||||
node := new(dataNode)
|
|
||||||
node.tag = tag
|
|
||||||
node.value = obj
|
|
||||||
object.setNode(node)
|
|
||||||
} else {
|
|
||||||
object.RemovePropertyByTag(tag)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (object *dataObject) ToParams() Params {
|
|
||||||
params := Params{}
|
|
||||||
for _, node := range object.property {
|
|
||||||
switch node.Type() {
|
|
||||||
case TextNode:
|
|
||||||
if text := node.Text(); text != "" {
|
|
||||||
params[PropertyName(node.Tag())] = text
|
|
||||||
}
|
|
||||||
|
|
||||||
case ObjectNode:
|
|
||||||
if obj := node.Object(); obj != nil {
|
|
||||||
params[PropertyName(node.Tag())] = node.Object()
|
|
||||||
}
|
|
||||||
|
|
||||||
case ArrayNode:
|
|
||||||
array := []any{}
|
|
||||||
for i := range node.ArraySize() {
|
|
||||||
if data := node.ArrayElement(i); data != nil {
|
|
||||||
if data.IsObject() {
|
|
||||||
if obj := data.Object(); obj != nil {
|
|
||||||
array = append(array, obj)
|
|
||||||
}
|
|
||||||
} else if text := data.Value(); text != "" {
|
|
||||||
array = append(array, text)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(array) > 0 {
|
|
||||||
params[PropertyName(node.Tag())] = array
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return params
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
type dataNode struct {
|
|
||||||
tag string
|
|
||||||
value DataValue
|
|
||||||
array []DataValue
|
|
||||||
}
|
|
||||||
|
|
||||||
func (node *dataNode) Tag() string {
|
|
||||||
return node.tag
|
|
||||||
}
|
|
||||||
|
|
||||||
func (node *dataNode) Type() DataNodeType {
|
|
||||||
if node.array != nil {
|
|
||||||
return ArrayNode
|
|
||||||
}
|
|
||||||
if node.value.IsObject() {
|
|
||||||
return ObjectNode
|
|
||||||
}
|
|
||||||
return TextNode
|
|
||||||
}
|
|
||||||
|
|
||||||
func (node *dataNode) Text() string {
|
|
||||||
if node.value != nil {
|
|
||||||
return node.value.Value()
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (node *dataNode) Object() DataObject {
|
|
||||||
if node.value != nil {
|
|
||||||
return node.value.Object()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (node *dataNode) ArraySize() int {
|
|
||||||
if node.array != nil {
|
|
||||||
return len(node.array)
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (node *dataNode) ArrayElement(index int) DataValue {
|
|
||||||
if node.array != nil && index >= 0 && index < len(node.array) {
|
|
||||||
return node.array[index]
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (node *dataNode) Array() []DataValue {
|
|
||||||
if node.array != nil {
|
|
||||||
return slices.Clone(node.array)
|
|
||||||
}
|
|
||||||
return []DataValue{node.value}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (node *dataNode) ArrayElements() iter.Seq[DataValue] {
|
|
||||||
return func(yield func(DataValue) bool) {
|
|
||||||
if node.array != nil {
|
|
||||||
for _, element := range node.array {
|
|
||||||
if !yield(element) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
yield(node.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (node *dataNode) ArrayAsParams() []Params {
|
|
||||||
result := []Params{}
|
|
||||||
if node.array != nil {
|
|
||||||
for _, data := range node.array {
|
|
||||||
if data.IsObject() {
|
|
||||||
if obj := data.Object(); obj != nil {
|
|
||||||
if params := obj.ToParams(); len(params) > 0 {
|
|
||||||
result = append(result, params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
type dataParser struct {
|
type dataParser struct {
|
||||||
data []rune
|
data []rune
|
||||||
size int
|
size int
|
||||||
|
|
@ -446,6 +190,14 @@ func (parser *dataParser) skipSpaces(skipNewLine bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (parser *dataParser) skipSpacesAndCommas() {
|
||||||
|
parser.skipSpaces(true)
|
||||||
|
for parser.data[parser.pos] == ',' && parser.pos < parser.size {
|
||||||
|
parser.pos++
|
||||||
|
parser.skipSpaces(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (parser *dataParser) parseTag() (string, error) {
|
func (parser *dataParser) parseTag() (string, error) {
|
||||||
parser.skipSpaces(true)
|
parser.skipSpaces(true)
|
||||||
startPos := parser.pos
|
startPos := parser.pos
|
||||||
|
|
@ -593,62 +345,53 @@ func (parser *dataParser) stopSymbol(symbol rune) bool {
|
||||||
slices.Contains([]rune{'=', '{', '}', '[', ']', ',', ' ', '\t', '\n', '\'', '"', '`', '/'}, symbol)
|
slices.Contains([]rune{'=', '{', '}', '[', ']', ',', ' ', '\t', '\n', '\'', '"', '`', '/'}, symbol)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (parser *dataParser) parseNode() (DataNode, error) {
|
func (parser *dataParser) parseNode() (string, DataValue, error) {
|
||||||
var tag string
|
|
||||||
var err error
|
|
||||||
|
|
||||||
if tag, err = parser.parseTag(); err != nil {
|
tag, err := parser.parseTag()
|
||||||
return nil, err
|
if err != nil {
|
||||||
|
return "", nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
parser.skipSpaces(true)
|
parser.skipSpaces(true)
|
||||||
if parser.data[parser.pos] != '=' {
|
if parser.data[parser.pos] != '=' {
|
||||||
return nil, fmt.Errorf("expected '=' after a tag name (line: %d, position: %d)", parser.line, parser.pos-parser.lineStart)
|
return "", nil, fmt.Errorf("expected '=' after a tag name (line: %d, position: %d)", parser.line, parser.pos-parser.lineStart)
|
||||||
}
|
}
|
||||||
|
|
||||||
parser.pos++
|
parser.pos++
|
||||||
parser.skipSpaces(true)
|
parser.skipSpaces(true)
|
||||||
switch parser.data[parser.pos] {
|
switch parser.data[parser.pos] {
|
||||||
case '[':
|
case '[':
|
||||||
node := new(dataNode)
|
array, err := parser.parseArray()
|
||||||
node.tag = tag
|
if err != nil {
|
||||||
|
return "", nil, err
|
||||||
if node.array, err = parser.parseArray(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
return node, nil
|
return tag, NewDataArray(array), nil
|
||||||
|
|
||||||
case '{':
|
case '{':
|
||||||
node := new(dataNode)
|
obj, err := parser.parseObject("_")
|
||||||
node.tag = tag
|
if err != nil {
|
||||||
if node.value, err = parser.parseObject("_"); err != nil {
|
return "", nil, err
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
return node, nil
|
return tag, obj, nil
|
||||||
|
|
||||||
case '}', ']', '=':
|
case '}', ']', '=':
|
||||||
return nil, fmt.Errorf(`expected '[', '{' or a tag name after '=' (line: %d, position: %d)`, parser.line, parser.pos-parser.lineStart)
|
return "", nil, fmt.Errorf(`expected '[', '{' or a tag name after '=' (line: %d, position: %d)`, parser.line, parser.pos-parser.lineStart)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
var str string
|
text, err := parser.parseTag()
|
||||||
if str, err = parser.parseTag(); err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return "", nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
node := new(dataNode)
|
|
||||||
node.tag = tag
|
|
||||||
|
|
||||||
if parser.data[parser.pos] == '{' {
|
if parser.data[parser.pos] == '{' {
|
||||||
if node.value, err = parser.parseObject(str); err != nil {
|
obj, err := parser.parseObject(text)
|
||||||
return nil, err
|
if err != nil {
|
||||||
|
return "", nil, err
|
||||||
}
|
}
|
||||||
} else {
|
return tag, obj, nil
|
||||||
val := new(dataStringValue)
|
|
||||||
val.value = str
|
|
||||||
node.value = val
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return node, nil
|
return tag, NewTextData(text), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -658,9 +401,7 @@ func (parser *dataParser) parseObject(tag string) (DataObject, error) {
|
||||||
}
|
}
|
||||||
parser.pos++
|
parser.pos++
|
||||||
|
|
||||||
obj := new(dataObject)
|
obj := NewDataObject(tag)
|
||||||
obj.tag = tag
|
|
||||||
obj.property = []DataNode{}
|
|
||||||
|
|
||||||
for parser.pos < parser.size {
|
for parser.pos < parser.size {
|
||||||
parser.skipSpaces(true)
|
parser.skipSpaces(true)
|
||||||
|
|
@ -670,29 +411,29 @@ func (parser *dataParser) parseObject(tag string) (DataObject, error) {
|
||||||
return obj, nil
|
return obj, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
node, err := parser.parseNode()
|
property, value, err := parser.parseNode()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
obj.SetProperty(property, value)
|
||||||
|
|
||||||
obj.property = append(obj.property, node)
|
switch parser.data[parser.pos] {
|
||||||
if parser.data[parser.pos] == '}' {
|
case '}':
|
||||||
parser.pos++
|
parser.pos++
|
||||||
parser.skipSpaces(true)
|
parser.skipSpaces(true)
|
||||||
return obj, nil
|
return obj, nil
|
||||||
} else if parser.data[parser.pos] != ',' && parser.data[parser.pos] != '\n' {
|
|
||||||
|
case ',':
|
||||||
|
parser.pos++
|
||||||
|
|
||||||
|
case '\n':
|
||||||
|
// do nothing
|
||||||
|
|
||||||
|
default:
|
||||||
return nil, fmt.Errorf(`expected '}', '\n' or ',' (line: %d, position: %d)`, parser.line, parser.pos-parser.lineStart)
|
return nil, fmt.Errorf(`expected '}', '\n' or ',' (line: %d, position: %d)`, parser.line, parser.pos-parser.lineStart)
|
||||||
}
|
}
|
||||||
|
|
||||||
if parser.data[parser.pos] != '\n' {
|
parser.skipSpacesAndCommas()
|
||||||
parser.pos++
|
|
||||||
}
|
|
||||||
|
|
||||||
parser.skipSpaces(true)
|
|
||||||
for parser.data[parser.pos] == ',' {
|
|
||||||
parser.pos++
|
|
||||||
parser.skipSpaces(true)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, errors.New("unexpected end of text")
|
return nil, errors.New("unexpected end of text")
|
||||||
|
|
@ -704,23 +445,18 @@ func (parser *dataParser) parseArray() ([]DataValue, error) {
|
||||||
|
|
||||||
array := []DataValue{}
|
array := []DataValue{}
|
||||||
|
|
||||||
|
parser.skipSpacesAndCommas()
|
||||||
for parser.pos < parser.size {
|
for parser.pos < parser.size {
|
||||||
parser.skipSpaces(true)
|
if parser.data[parser.pos] != ']' {
|
||||||
for parser.data[parser.pos] == ',' && parser.pos < parser.size {
|
if parser.data[parser.pos] == '[' {
|
||||||
parser.pos++
|
|
||||||
parser.skipSpaces(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
if parser.pos >= parser.size {
|
subarray, err := parser.parseArray()
|
||||||
break
|
if err != nil {
|
||||||
}
|
return nil, err
|
||||||
|
|
||||||
if parser.data[parser.pos] == ']' {
|
|
||||||
parser.pos++
|
|
||||||
parser.skipSpaces(true)
|
|
||||||
return array, nil
|
|
||||||
}
|
}
|
||||||
|
array = append(array, NewDataArray(subarray))
|
||||||
|
|
||||||
|
} else {
|
||||||
tag, err := parser.parseTag()
|
tag, err := parser.parseTag()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -733,35 +469,36 @@ func (parser *dataParser) parseArray() ([]DataValue, error) {
|
||||||
}
|
}
|
||||||
array = append(array, obj)
|
array = append(array, obj)
|
||||||
} else {
|
} else {
|
||||||
val := new(dataStringValue)
|
array = append(array, NewTextData(tag))
|
||||||
val.value = tag
|
}
|
||||||
array = append(array, val)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch parser.data[parser.pos] {
|
switch parser.data[parser.pos] {
|
||||||
case ']', ',', '\n':
|
case ']':
|
||||||
|
parser.pos++
|
||||||
|
parser.skipSpaces(true)
|
||||||
|
return array, nil
|
||||||
|
|
||||||
|
case '\n':
|
||||||
|
// do nothing
|
||||||
|
|
||||||
|
case ',':
|
||||||
|
parser.pos++
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf(`expected ']' or ',' (line: %d, position: %d)`, parser.line, parser.pos-parser.lineStart)
|
return nil, fmt.Errorf(`expected ']' or ',' (line: %d, position: %d)`, parser.line, parser.pos-parser.lineStart)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
parser.skipSpacesAndCommas()
|
||||||
if data[pos] == ']' {
|
|
||||||
pos++
|
|
||||||
skipSpaces()
|
|
||||||
return array, nil
|
|
||||||
} else if data[pos] != ',' {
|
|
||||||
return nil, fmt.Errorf("Expected ']' or ',' (line: %d, position: %d)", line, pos-lineStart)
|
|
||||||
}
|
|
||||||
pos++
|
|
||||||
skipSpaces()
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, errors.New("unexpected end of text")
|
return nil, errors.New("unexpected end of text")
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseDataText - parse text and return DataNode
|
// ParseDataText parses a text.
|
||||||
|
// If successful, it returns a DataObject and nil as the second element;
|
||||||
|
// otherwise, it returns nil and an error.
|
||||||
func ParseDataText(text string) (DataObject, error) {
|
func ParseDataText(text string) (DataObject, error) {
|
||||||
|
|
||||||
if strings.ContainsAny(text, "\r") {
|
if strings.ContainsAny(text, "\r") {
|
||||||
|
|
@ -783,3 +520,16 @@ func ParseDataText(text string) (DataObject, error) {
|
||||||
}
|
}
|
||||||
return parser.parseObject(tag)
|
return parser.parseObject(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReadDataObject reads a text file from the specified path, parses it.
|
||||||
|
// If successful, it returns a DataObject and nil as the second element;
|
||||||
|
// otherwise, it returns nil and an error.
|
||||||
|
func ReadDataObject(path string) (DataObject, error) {
|
||||||
|
data, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
debugLog(err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ParseDataText(string(data))
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,404 @@
|
||||||
|
package rui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"iter"
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DataValue interface of a data node value
|
||||||
|
type DataArray interface {
|
||||||
|
DataValue
|
||||||
|
|
||||||
|
// Size returns returns the size of the array.
|
||||||
|
Size() int
|
||||||
|
|
||||||
|
// Element returns a value of an array element.
|
||||||
|
Element(index int) DataValue
|
||||||
|
|
||||||
|
// Slice returns an all element as a slice. The returned slice is a copy of the data.
|
||||||
|
// Modifying the slice does not affect the internal structure of the DataArray.
|
||||||
|
Slice() []DataValue
|
||||||
|
|
||||||
|
// Elements returns an iterator to access the array elements
|
||||||
|
Elements() iter.Seq[DataValue]
|
||||||
|
|
||||||
|
// ElementsWithIndices returns an iterator to access the array elements with itheir indices
|
||||||
|
ElementsWithIndices() iter.Seq2[int, DataValue]
|
||||||
|
|
||||||
|
// TextElements returns an iterator for accessing the text elements of the array.
|
||||||
|
// Elements of type DataArray and DataObject are skipped.
|
||||||
|
TextElements() iter.Seq[string]
|
||||||
|
|
||||||
|
// Append adds the specified elements to the end of the array.
|
||||||
|
//
|
||||||
|
// All nil elements are skipped (not added to the array).
|
||||||
|
Append(values ...DataValue)
|
||||||
|
|
||||||
|
// Append adds the specified elements to the end of the array.
|
||||||
|
AppendText(values ...string)
|
||||||
|
|
||||||
|
// Append adds the specified elements to the end of the array.
|
||||||
|
AppendInt(values ...int)
|
||||||
|
|
||||||
|
// Append adds the specified elements to the end of the array.
|
||||||
|
AppendFloat(values ...float64)
|
||||||
|
|
||||||
|
// Append adds the specified elements to the end of the array.
|
||||||
|
AppendArray(array DataArray)
|
||||||
|
|
||||||
|
// Insert inserts the specified elements into the array starting at the element with index.
|
||||||
|
//
|
||||||
|
// All nil elements are skipped (not added to the array).
|
||||||
|
//
|
||||||
|
// If index < 0 then the elements are inserted at the beginning of the array.
|
||||||
|
//
|
||||||
|
// If the index is greater than the array size, the elements are inserted at the end of the array.
|
||||||
|
Insert(index int, values ...DataValue)
|
||||||
|
|
||||||
|
// Insert inserts the specified elements into the array starting at the element with index.
|
||||||
|
//
|
||||||
|
// If index < 0 then the elements are inserted at the beginning of the array.
|
||||||
|
//
|
||||||
|
// If the index is greater than the array size, the elements are inserted at the end of the array.
|
||||||
|
InsertText(index int, values ...string)
|
||||||
|
|
||||||
|
// Insert inserts the specified elements into the array starting at the element with index.
|
||||||
|
//
|
||||||
|
// If index < 0 then the elements are inserted at the beginning of the array.
|
||||||
|
//
|
||||||
|
// If the index is greater than the array size, the elements are inserted at the end of the array.
|
||||||
|
InsertInt(index int, values ...int)
|
||||||
|
|
||||||
|
// Insert inserts the specified elements into the array starting at the element with index.
|
||||||
|
//
|
||||||
|
// If index < 0 then the elements are inserted at the beginning of the array.
|
||||||
|
//
|
||||||
|
// If the index is greater than the array size, the elements are inserted at the end of the array.
|
||||||
|
InsertFloat(index int, values ...float64)
|
||||||
|
|
||||||
|
// Remove removes the element at the specified index from the array and returns it. It returns nil if the index is out of bounds.
|
||||||
|
Remove(index int) DataValue
|
||||||
|
|
||||||
|
// RemoveN removes count elements from the array starting at the specified index and returns them.
|
||||||
|
// It returns empty array if the index is out of bounds.
|
||||||
|
RemoveN(index int, count int) []DataValue
|
||||||
|
|
||||||
|
// SingleLineString returns how the result of the String() method will be formatted.
|
||||||
|
//
|
||||||
|
// If result is true, then all array elements are output on a single line (separated by ", ").
|
||||||
|
//
|
||||||
|
// If result is false, then each array element is output on a new line.
|
||||||
|
SingleLineString() bool
|
||||||
|
|
||||||
|
// SetSingleLineString Determines how the result of the String() method is formatted.
|
||||||
|
//
|
||||||
|
// If argument is true, then all array elements are output on a single line (separated by ", ").
|
||||||
|
//
|
||||||
|
// If argument is false, then each array element is output on a new line.
|
||||||
|
SetSingleLineString(flag bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
type dataArrayDataValue struct {
|
||||||
|
array []DataValue
|
||||||
|
singleLineString bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDataArray creates an DataValue object of ArrayDataValue type.
|
||||||
|
//
|
||||||
|
// When creating the object, all nil elements are skipped (not added to the array).
|
||||||
|
func NewDataArray(array []DataValue) DataArray {
|
||||||
|
data := new(dataArrayDataValue)
|
||||||
|
|
||||||
|
if array == nil {
|
||||||
|
data.array = []DataValue{}
|
||||||
|
} else {
|
||||||
|
data.array = make([]DataValue, 0, len(array))
|
||||||
|
for _, element := range array {
|
||||||
|
if element != nil {
|
||||||
|
data.array = append(data.array, element)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDataArrayOf creates an DataValue object of ArrayDataValue type.
|
||||||
|
//
|
||||||
|
// When creating the object, all nil elements are skipped (not added to the array).
|
||||||
|
func NewDataArrayOf(array ...DataValue) DataArray {
|
||||||
|
data := new(dataArrayDataValue)
|
||||||
|
|
||||||
|
data.array = make([]DataValue, 0, len(array))
|
||||||
|
for _, element := range array {
|
||||||
|
if element != nil {
|
||||||
|
data.array = append(data.array, element)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTexDataArray creates a DataArray object (an DataValue object of ArrayDataValue type).
|
||||||
|
//
|
||||||
|
// All elements of the argument are converted to DataValue using the NewDataText function.
|
||||||
|
func NewTextDataArray[T string | int | int8 | int16 | int32 | int64 |
|
||||||
|
uint | uint8 | uint16 | uint32 | uint64 | bool | float32 | float64](array []T) DataArray {
|
||||||
|
data := new(dataArrayDataValue)
|
||||||
|
|
||||||
|
if array == nil {
|
||||||
|
data.array = []DataValue{}
|
||||||
|
} else {
|
||||||
|
data.array = make([]DataValue, 0, len(array))
|
||||||
|
for _, element := range array {
|
||||||
|
data.array = append(data.array, NewTextData(element))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(data.array) < 10 {
|
||||||
|
data.singleLineString = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTextDataArrayOf creates a DataArray object (an DataValue object of ArrayDataValue type).
|
||||||
|
//
|
||||||
|
// All arguments are converted to DataValue using the NewDataText function.
|
||||||
|
func NewTextDataArrayOf[T string | int | int8 | int16 | int32 | int64 |
|
||||||
|
uint | uint8 | uint16 | uint32 | uint64 | bool | float32 | float64](values ...T) DataArray {
|
||||||
|
data := new(dataArrayDataValue)
|
||||||
|
|
||||||
|
data.array = make([]DataValue, 0, len(values))
|
||||||
|
for _, element := range values {
|
||||||
|
data.array = append(data.array, NewTextData(element))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(data.array) < 10 {
|
||||||
|
data.singleLineString = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
func (value *dataArrayDataValue) String() string {
|
||||||
|
buffer := allocStringBuilder()
|
||||||
|
defer freeStringBuilder(buffer)
|
||||||
|
|
||||||
|
value.writeToBuffer(buffer, "")
|
||||||
|
|
||||||
|
return buffer.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (value *dataArrayDataValue) writeToBuffer(buffer *strings.Builder, indent string) {
|
||||||
|
|
||||||
|
if len(value.array) == 0 {
|
||||||
|
buffer.WriteString("[]")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
indent2 := indent + "\t"
|
||||||
|
|
||||||
|
if value.singleLineString {
|
||||||
|
|
||||||
|
lead := "["
|
||||||
|
for _, element := range value.array {
|
||||||
|
buffer.WriteString(lead)
|
||||||
|
element.writeToBuffer(buffer, indent2)
|
||||||
|
lead = ", "
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
buffer.WriteString("[\n")
|
||||||
|
for _, element := range value.array {
|
||||||
|
buffer.WriteString(indent2)
|
||||||
|
element.writeToBuffer(buffer, indent2)
|
||||||
|
buffer.WriteString(",\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.WriteString(indent)
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.WriteString("]")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (value *dataArrayDataValue) Type() DataValueType {
|
||||||
|
return ArrayDataValue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (value *dataArrayDataValue) Object() DataObject {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (value *dataArrayDataValue) Array() DataArray {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (value *dataArrayDataValue) Size() int {
|
||||||
|
return len(value.array)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (value *dataArrayDataValue) Element(index int) DataValue {
|
||||||
|
if index >= 0 && index < len(value.array) {
|
||||||
|
return value.array[index]
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (value *dataArrayDataValue) Slice() []DataValue {
|
||||||
|
return slices.Clone(value.array)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (value *dataArrayDataValue) Elements() iter.Seq[DataValue] {
|
||||||
|
return func(yield func(DataValue) bool) {
|
||||||
|
for _, element := range value.array {
|
||||||
|
if !yield(element) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (value *dataArrayDataValue) TextElements() iter.Seq[string] {
|
||||||
|
return func(yield func(string) bool) {
|
||||||
|
for _, element := range value.array {
|
||||||
|
if element.Type() == TextDataValue {
|
||||||
|
if !yield(element.String()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (value *dataArrayDataValue) ElementsWithIndices() iter.Seq2[int, DataValue] {
|
||||||
|
return func(yield func(int, DataValue) bool) {
|
||||||
|
for i, element := range value.array {
|
||||||
|
if !yield(i, element) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (value *dataArrayDataValue) Append(data ...DataValue) {
|
||||||
|
for _, d := range data {
|
||||||
|
if d != nil {
|
||||||
|
value.array = append(value.array, d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (value *dataArrayDataValue) AppendText(values ...string) {
|
||||||
|
for _, v := range values {
|
||||||
|
value.array = append(value.array, NewTextData(v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (value *dataArrayDataValue) AppendInt(values ...int) {
|
||||||
|
for _, v := range values {
|
||||||
|
value.array = append(value.array, NewTextData(v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (value *dataArrayDataValue) AppendFloat(values ...float64) {
|
||||||
|
for _, v := range values {
|
||||||
|
value.array = append(value.array, NewTextData(v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (value *dataArrayDataValue) AppendArray(array DataArray) {
|
||||||
|
if array != nil {
|
||||||
|
for d := range array.Elements() {
|
||||||
|
value.array = append(value.array, d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (value *dataArrayDataValue) Insert(index int, data ...DataValue) {
|
||||||
|
if index >= len(value.array) {
|
||||||
|
value.Append(data...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if index < 0 {
|
||||||
|
index = 0
|
||||||
|
}
|
||||||
|
value.array = slices.Insert(value.array, index, data...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (value *dataArrayDataValue) InsertText(index int, values ...string) {
|
||||||
|
data := make([]DataValue, len(values))
|
||||||
|
for i, v := range values {
|
||||||
|
data[i] = NewTextData(v)
|
||||||
|
}
|
||||||
|
value.Insert(index, data...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (value *dataArrayDataValue) InsertInt(index int, values ...int) {
|
||||||
|
data := make([]DataValue, len(values))
|
||||||
|
for i, v := range values {
|
||||||
|
data[i] = NewTextData(v)
|
||||||
|
}
|
||||||
|
value.Insert(index, data...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (value *dataArrayDataValue) InsertFloat(index int, values ...float64) {
|
||||||
|
data := make([]DataValue, len(values))
|
||||||
|
for i, v := range values {
|
||||||
|
data[i] = NewTextData(v)
|
||||||
|
}
|
||||||
|
value.Insert(index, data...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (value *dataArrayDataValue) Remove(index int) DataValue {
|
||||||
|
size := len(value.array)
|
||||||
|
if index < 0 || index >= size {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
result := value.array[index]
|
||||||
|
switch index {
|
||||||
|
case 0:
|
||||||
|
value.array = value.array[1:]
|
||||||
|
|
||||||
|
case size - 1:
|
||||||
|
value.array = value.array[:index]
|
||||||
|
|
||||||
|
default:
|
||||||
|
value.array = append(value.array[:index], value.array[index+1:]...)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (value *dataArrayDataValue) RemoveN(index int, count int) []DataValue {
|
||||||
|
size := len(value.array)
|
||||||
|
if index < 0 || index >= size {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if index+count >= size {
|
||||||
|
result := value.array[index:]
|
||||||
|
value.array = value.array[:index]
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
result := value.array[index : index+count]
|
||||||
|
if index == 0 {
|
||||||
|
value.array = value.array[count:]
|
||||||
|
} else {
|
||||||
|
value.array = append(value.array[:index], value.array[index+count:]...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (value *dataArrayDataValue) SetSingleLineString(flag bool) {
|
||||||
|
value.singleLineString = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (value *dataArrayDataValue) SingleLineString() bool {
|
||||||
|
return value.singleLineString
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
package rui
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestDataArray(t *testing.T) {
|
||||||
|
array := NewTextDataArrayOf(0, 1, 2, 3, 4, 5)
|
||||||
|
array.SetSingleLineString(true)
|
||||||
|
|
||||||
|
if array.String() != "[0, 1, 2, 3, 4, 5]" {
|
||||||
|
t.Error(`NewTextDataArrayOf(0, 1, 2, 3, 4, 5) fail. Result: ` + array.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
array.AppendInt(6, 7)
|
||||||
|
if array.String() != "[0, 1, 2, 3, 4, 5, 6, 7]" {
|
||||||
|
t.Error(`array.AppendInt(6, 7) fail. Result: ` + array.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
array.InsertInt(0, 8, 9)
|
||||||
|
if array.String() != "[8, 9, 0, 1, 2, 3, 4, 5, 6, 7]" {
|
||||||
|
t.Error(`array.InsertInt(0, 8, 9) fail. Result: ` + array.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
array.InsertInt(2, 10, 11, 12)
|
||||||
|
if array.String() != "[8, 9, 10, 11, 12, 0, 1, 2, 3, 4, 5, 6, 7]" {
|
||||||
|
t.Error(`array.InsertInt(2, 10, 11, 12) fail. Result: ` + array.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
array.InsertInt(100, 13, 14)
|
||||||
|
if array.String() != "[8, 9, 10, 11, 12, 0, 1, 2, 3, 4, 5, 6, 7, 13, 14]" {
|
||||||
|
t.Error(`array.InsertInt(100, 13, 14) fail. Result: ` + array.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
array.Remove(0)
|
||||||
|
if array.String() != "[9, 10, 11, 12, 0, 1, 2, 3, 4, 5, 6, 7, 13, 14]" {
|
||||||
|
t.Error(`array.Remove(0) fail. Result: ` + array.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
array.Remove(1)
|
||||||
|
if array.String() != "[9, 11, 12, 0, 1, 2, 3, 4, 5, 6, 7, 13, 14]" {
|
||||||
|
t.Error(`array.Remove(1) fail. Result: ` + array.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
array.Remove(12)
|
||||||
|
if array.String() != "[9, 11, 12, 0, 1, 2, 3, 4, 5, 6, 7, 13]" {
|
||||||
|
t.Error(`array.Remove(12) fail. Result: ` + array.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
array.RemoveN(0, 2)
|
||||||
|
if array.String() != "[12, 0, 1, 2, 3, 4, 5, 6, 7, 13]" {
|
||||||
|
t.Error(`array.RemoveN(0, 2) fail. Result: ` + array.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
array.RemoveN(1, 3)
|
||||||
|
if array.String() != "[12, 3, 4, 5, 6, 7, 13]" {
|
||||||
|
t.Error(`array.RemoveN(1, 3) fail. Result: ` + array.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
array.RemoveN(5, 12)
|
||||||
|
if array.String() != "[12, 3, 4, 5, 6]" {
|
||||||
|
t.Error(`array.RemoveN(5, 12) fail. Result: ` + array.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
17
dataList.go
17
dataList.go
|
|
@ -127,14 +127,21 @@ func anyToStringArray(value any, dateTimeFormat string) ([]string, bool) {
|
||||||
case []string:
|
case []string:
|
||||||
return value, true
|
return value, true
|
||||||
|
|
||||||
case []DataValue:
|
case DataValue:
|
||||||
items := make([]string, 0, len(value))
|
switch value.Type() {
|
||||||
for _, val := range value {
|
case TextDataValue:
|
||||||
if !val.IsObject() {
|
return []string{value.String()}, true
|
||||||
items = append(items, val.Value())
|
|
||||||
|
case ArrayDataValue:
|
||||||
|
array := value.Array()
|
||||||
|
items := make([]string, 0, array.Size())
|
||||||
|
for val := range array.Elements() {
|
||||||
|
if val.Type() == TextDataValue {
|
||||||
|
items = append(items, val.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return items, true
|
return items, true
|
||||||
|
}
|
||||||
|
|
||||||
case []fmt.Stringer:
|
case []fmt.Stringer:
|
||||||
items := make([]string, len(value))
|
items := make([]string, len(value))
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,217 @@
|
||||||
|
package rui
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
type TestDataXY struct {
|
||||||
|
X float32
|
||||||
|
Y float64
|
||||||
|
}
|
||||||
|
type TestDataObjectStruct struct {
|
||||||
|
Items []string `rui:"id=items"`
|
||||||
|
Items2 [2]string
|
||||||
|
Int_a []int `rui:"id=intArray"`
|
||||||
|
Int_a2 [3]int
|
||||||
|
Int8_a []int8
|
||||||
|
Int16_a []int16
|
||||||
|
Int32_a []int32
|
||||||
|
Int64_a []int64
|
||||||
|
Uint_a []uint
|
||||||
|
Uint8_a []uint8
|
||||||
|
Uint16_a []uint16
|
||||||
|
Uint32_a []uint32
|
||||||
|
Uint64_a []uint64
|
||||||
|
Float32_a []float32
|
||||||
|
Float32_a2 [3]float32
|
||||||
|
Float64_a []float64
|
||||||
|
Bool_a []bool
|
||||||
|
Bool_a2 [2]bool
|
||||||
|
Text string `rui:"id=text"`
|
||||||
|
Int int `rui:"id=int"`
|
||||||
|
Int8 int `rui:"id=int8"`
|
||||||
|
Int16 int `rui:"id=int16"`
|
||||||
|
Int32 int `rui:"id=int32"`
|
||||||
|
Int64 int `rui:"id=int64"`
|
||||||
|
Uint uint `rui:"id=uint"`
|
||||||
|
Uint8 uint `rui:"id=uint8"`
|
||||||
|
Uint16 uint `rui:"id=uint16"`
|
||||||
|
Uint32 uint `rui:"id=uint32"`
|
||||||
|
Uint64 uint `rui:"id=uint64"`
|
||||||
|
Float32 float32
|
||||||
|
Float64 float64
|
||||||
|
Flag bool
|
||||||
|
B TestDataXY
|
||||||
|
Struct_a []TestDataXY
|
||||||
|
Struct_a2 [2]TestDataXY
|
||||||
|
Matrix [][]int
|
||||||
|
Matrix2 [2][]int
|
||||||
|
Matrix3 [][3]int
|
||||||
|
Matrix4 [2][3]int
|
||||||
|
Map map[string]int
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDataObject(t *testing.T) {
|
||||||
|
|
||||||
|
data := TestDataObjectStruct{
|
||||||
|
Items: []string{"Item 1", "Item2"},
|
||||||
|
Items2: [2]string{"Item 3", "Item4"},
|
||||||
|
Int_a: []int{-1, 2, 3},
|
||||||
|
Int_a2: [3]int{0, 1, 2},
|
||||||
|
Int8_a: []int8{4, 5, 6},
|
||||||
|
Int16_a: []int16{7, 8, 9},
|
||||||
|
Int32_a: []int32{10, 11, 12},
|
||||||
|
Int64_a: []int64{13, 14, 15},
|
||||||
|
Uint_a: []uint{1, 2, 3},
|
||||||
|
Uint8_a: []uint8{4, 5, 6},
|
||||||
|
Uint16_a: []uint16{7, 8, 9},
|
||||||
|
Uint32_a: []uint32{10, 11, 12},
|
||||||
|
Uint64_a: []uint64{13, 14, 15},
|
||||||
|
Float32_a: []float32{1.5, 2, 3},
|
||||||
|
Float32_a2: [3]float32{2.5, 3.5, 4},
|
||||||
|
Float64_a: []float64{1, 2.5, 3},
|
||||||
|
Bool_a: []bool{false, true},
|
||||||
|
Bool_a2: [2]bool{true, false},
|
||||||
|
Text: "text",
|
||||||
|
Int: -1,
|
||||||
|
Int8: 0,
|
||||||
|
Int16: 1,
|
||||||
|
Int32: 2,
|
||||||
|
Int64: 3,
|
||||||
|
Uint: 5,
|
||||||
|
Uint8: 6,
|
||||||
|
Uint16: 7,
|
||||||
|
Uint32: 8,
|
||||||
|
Uint64: 9,
|
||||||
|
Float32: 10.5,
|
||||||
|
Float64: 11.5,
|
||||||
|
Flag: true,
|
||||||
|
B: TestDataXY{X: 4, Y: 5.5},
|
||||||
|
Struct_a: []TestDataXY{{X: 1, Y: 2}, {X: 3, Y: 4}},
|
||||||
|
Struct_a2: [2]TestDataXY{{X: 5, Y: 6}, {X: 7, Y: 8}},
|
||||||
|
Matrix: [][]int{
|
||||||
|
{1, 2, 3},
|
||||||
|
{4, 5},
|
||||||
|
},
|
||||||
|
Matrix2: [2][]int{
|
||||||
|
{21, 22, 23},
|
||||||
|
{24, 25},
|
||||||
|
},
|
||||||
|
Matrix3: [][3]int{
|
||||||
|
{31, 32, 33},
|
||||||
|
{34, 35, 36},
|
||||||
|
},
|
||||||
|
Matrix4: [2][3]int{
|
||||||
|
{41, 42, 43},
|
||||||
|
{44, 45, 46},
|
||||||
|
},
|
||||||
|
Map: map[string]int{
|
||||||
|
"key 1": 12,
|
||||||
|
"key2": 25,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
obj := NewDataObjectFromStruct(&data)
|
||||||
|
if obj == nil {
|
||||||
|
t.Error(`NewDataObjectFromStruct fail`)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := `TestDataObjectStruct{
|
||||||
|
items = ["Item 1", Item2],
|
||||||
|
Items2 = ["Item 3", Item4],
|
||||||
|
intArray = [-1, 2, 3],
|
||||||
|
Int_a2 = [0, 1, 2],
|
||||||
|
Int8_a = [4, 5, 6],
|
||||||
|
Int16_a = [7, 8, 9],
|
||||||
|
Int32_a = [10, 11, 12],
|
||||||
|
Int64_a = [13, 14, 15],
|
||||||
|
Uint_a = [1, 2, 3],
|
||||||
|
Uint8_a = [4, 5, 6],
|
||||||
|
Uint16_a = [7, 8, 9],
|
||||||
|
Uint32_a = [10, 11, 12],
|
||||||
|
Uint64_a = [13, 14, 15],
|
||||||
|
Float32_a = [1.5, 2, 3],
|
||||||
|
Float32_a2 = [2.5, 3.5, 4],
|
||||||
|
Float64_a = [1, 2.5, 3],
|
||||||
|
Bool_a = [false, true],
|
||||||
|
Bool_a2 = [true, false],
|
||||||
|
text = text,
|
||||||
|
int = -1,
|
||||||
|
int8 = 0,
|
||||||
|
int16 = 1,
|
||||||
|
int32 = 2,
|
||||||
|
int64 = 3,
|
||||||
|
uint = 5,
|
||||||
|
uint8 = 6,
|
||||||
|
uint16 = 7,
|
||||||
|
uint32 = 8,
|
||||||
|
uint64 = 9,
|
||||||
|
Float32 = 10.5,
|
||||||
|
Float64 = 11.5,
|
||||||
|
Flag = true,
|
||||||
|
B = TestDataXY{
|
||||||
|
X = 4,
|
||||||
|
Y = 5.5,
|
||||||
|
},
|
||||||
|
Struct_a = [
|
||||||
|
TestDataXY{
|
||||||
|
X = 1,
|
||||||
|
Y = 2,
|
||||||
|
},
|
||||||
|
TestDataXY{
|
||||||
|
X = 3,
|
||||||
|
Y = 4,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
Struct_a2 = [
|
||||||
|
TestDataXY{
|
||||||
|
X = 5,
|
||||||
|
Y = 6,
|
||||||
|
},
|
||||||
|
TestDataXY{
|
||||||
|
X = 7,
|
||||||
|
Y = 8,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
Matrix = [
|
||||||
|
[1, 2, 3],
|
||||||
|
[4, 5],
|
||||||
|
],
|
||||||
|
Matrix2 = [
|
||||||
|
[21, 22, 23],
|
||||||
|
[24, 25],
|
||||||
|
],
|
||||||
|
Matrix3 = [
|
||||||
|
[31, 32, 33],
|
||||||
|
[34, 35, 36],
|
||||||
|
],
|
||||||
|
Matrix4 = [
|
||||||
|
[41, 42, 43],
|
||||||
|
[44, 45, 46],
|
||||||
|
],
|
||||||
|
Map = _{
|
||||||
|
"key 1" = 12,
|
||||||
|
key2 = 25,
|
||||||
|
},
|
||||||
|
}`
|
||||||
|
|
||||||
|
if mapObject := obj.PropertyObject("Map"); mapObject != nil {
|
||||||
|
mapObject.SetSortedTags(true)
|
||||||
|
}
|
||||||
|
if str := obj.String(); str != expected {
|
||||||
|
t.Error("NewDataObjectFromStruct result is fail:\n" + str)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var s TestDataObjectStruct
|
||||||
|
obj.ToStruct(&s)
|
||||||
|
|
||||||
|
obj2 := NewDataObjectFromStruct(s)
|
||||||
|
|
||||||
|
if mapObject := obj2.PropertyObject("Map"); mapObject != nil {
|
||||||
|
mapObject.SetSortedTags(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
if str := obj2.String(); str != expected {
|
||||||
|
t.Error("CopyToStruct result is fail:\n" + str)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
package rui
|
|
||||||
|
|
||||||
/*
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestDataWriter(t *testing.T) {
|
|
||||||
w := NewDataWriter()
|
|
||||||
w.StartObject("root")
|
|
||||||
w.WriteStringKey("key1", "text")
|
|
||||||
w.WriteStringKey("key2", "text 2")
|
|
||||||
w.WriteStringKey("key 3", "text4")
|
|
||||||
w.WriteStringsKey("key4", []string{"text4.1", "text4.2", "text4.3"}, '|')
|
|
||||||
w.WriteStringsKey("key5", []string{"text5.1", "text5.2", "text5.3"}, ',')
|
|
||||||
w.WriteColorKey("color", Color(0x7FD18243))
|
|
||||||
w.WriteColorsKey("colors", []Color{Color(0x7FD18243), Color(0xFF817263)}, ',')
|
|
||||||
w.WriteIntKey("int", 43)
|
|
||||||
w.WriteIntsKey("ints", []int{111, 222, 333}, '|')
|
|
||||||
|
|
||||||
w.StartObjectKey("obj", "xxx")
|
|
||||||
w.WriteSizeUnitKey("size", Px(16))
|
|
||||||
w.WriteSizeUnitsKey("sizes", []SizeUnit{Px(8), Percent(100)}, ',')
|
|
||||||
w.StartArray("array")
|
|
||||||
w.WriteStringToArray("text")
|
|
||||||
w.WriteColorToArray(Color(0x23456789))
|
|
||||||
w.WriteIntToArray(1)
|
|
||||||
w.WriteSizeUnitToArray(Inch(2))
|
|
||||||
w.FinishArray()
|
|
||||||
w.WriteBoundsKey("bounds1", Bounds{Px(8), Px(8), Px(8), Px(8)})
|
|
||||||
w.WriteBoundsKey("bounds2", Bounds{Px(8), Pt(12), Mm(4.5), Inch(1.2)})
|
|
||||||
w.FinishObject() // xxx
|
|
||||||
|
|
||||||
w.FinishObject() // root
|
|
||||||
|
|
||||||
text := w.String()
|
|
||||||
expected := `root {
|
|
||||||
key1 = text,
|
|
||||||
key2 = "text 2",
|
|
||||||
"key 3" = text4,
|
|
||||||
key4 = text4.1|text4.2|text4.3,
|
|
||||||
key5 = "text5.1,text5.2,text5.3",
|
|
||||||
color = #7FD18243,
|
|
||||||
colors = "#7FD18243,#FF817263",
|
|
||||||
int = 43,
|
|
||||||
ints = 111|222|333,
|
|
||||||
obj = xxx {
|
|
||||||
size = 16px,
|
|
||||||
sizes = "8px,100%",
|
|
||||||
array = [
|
|
||||||
text,
|
|
||||||
#23456789,
|
|
||||||
1,
|
|
||||||
2in
|
|
||||||
],
|
|
||||||
bounds1 = 8px,
|
|
||||||
bounds2 = "8px,12pt,4.5mm,1.2in"
|
|
||||||
}
|
|
||||||
}`
|
|
||||||
|
|
||||||
if text != expected {
|
|
||||||
t.Error("DataWriter test fail. Result:\n`" + text + "`\nExpected:\n`" + expected + "`")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
144
data_test.go
144
data_test.go
|
|
@ -30,27 +30,23 @@ func TestParseDataText(t *testing.T) {
|
||||||
if obj.Tag() != "obj1" {
|
if obj.Tag() != "obj1" {
|
||||||
t.Error(`obj.Tag() != "obj1"`)
|
t.Error(`obj.Tag() != "obj1"`)
|
||||||
}
|
}
|
||||||
if !obj.IsObject() {
|
if obj.Type() != ObjectDataValue {
|
||||||
t.Error(`!obj.IsObject()`)
|
t.Error(`obj.Type() != ObjectDataValue`)
|
||||||
}
|
}
|
||||||
if obj.PropertyCount() != 4 {
|
if obj.PropertyCount() != 4 {
|
||||||
t.Error(`obj.PropertyCount() != 4`)
|
t.Error(`obj.PropertyCount() != 4`)
|
||||||
}
|
}
|
||||||
|
|
||||||
if obj.Property(-1) != nil {
|
if val, ok := obj.PropertyText("key1"); !ok || val != "val1" {
|
||||||
t.Error(`obj.Property(-1) != nil`)
|
t.Errorf(`obj.PropertyText("key1") result: ("%s",%v)`, val, ok)
|
||||||
}
|
}
|
||||||
|
|
||||||
if val, ok := obj.PropertyValue("key1"); !ok || val != "val1" {
|
if val, ok := obj.PropertyText("key3"); !ok || val != "\n \t \\ \r \" ' \x4F\x4e \u01Ea" {
|
||||||
t.Errorf(`obj.PropertyValue("key1") result: ("%s",%v)`, val, ok)
|
t.Errorf(`obj.PropertyText("key3") result: ("%s",%v)`, val, ok)
|
||||||
}
|
}
|
||||||
|
|
||||||
if val, ok := obj.PropertyValue("key3"); !ok || val != "\n \t \\ \r \" ' \x4F\x4e \u01Ea" {
|
if val, ok := obj.PropertyText("key4"); !ok || val != `\n \t \\ \r \" ' \x8F \UF80a` {
|
||||||
t.Errorf(`obj.PropertyValue("key3") result: ("%s",%v)`, val, ok)
|
t.Errorf(`obj.PropertyText("key4") result: ("%s",%v)`, val, ok)
|
||||||
}
|
|
||||||
|
|
||||||
if val, ok := obj.PropertyValue("key4"); !ok || val != `\n \t \\ \r \" ' \x8F \UF80a` {
|
|
||||||
t.Errorf(`obj.PropertyValue("key4") result: ("%s",%v)`, val, ok)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if o := obj.PropertyObject("key2"); o == nil {
|
if o := obj.PropertyObject("key2"); o == nil {
|
||||||
|
|
@ -65,47 +61,41 @@ func TestParseDataText(t *testing.T) {
|
||||||
t.Error(`obj.PropertyObject("key5") != nil`)
|
t.Error(`obj.PropertyObject("key5") != nil`)
|
||||||
}
|
}
|
||||||
|
|
||||||
if val, ok := obj.PropertyValue("key2"); ok {
|
if val, ok := obj.PropertyText("key2"); ok {
|
||||||
t.Errorf(`obj.PropertyValue("key2") result: ("%s",%v)`, val, ok)
|
t.Errorf(`obj.PropertyText("key2") result: ("%s",%v)`, val, ok)
|
||||||
}
|
}
|
||||||
|
|
||||||
if val, ok := obj.PropertyValue("key5"); ok {
|
if val, ok := obj.PropertyText("key5"); ok {
|
||||||
t.Errorf(`obj.PropertyValue("key5") result: ("%s",%v)`, val, ok)
|
t.Errorf(`obj.PropertyText("key5") result: ("%s",%v)`, val, ok)
|
||||||
}
|
}
|
||||||
|
|
||||||
testKey := func(obj DataObject, index int, tag string, nodeType DataNodeType) DataNode {
|
testKey := func(obj DataObject, tag string, nodeType DataValueType) DataValue {
|
||||||
key := obj.Property(index)
|
key := obj.Property(tag)
|
||||||
if key == nil {
|
if key == nil {
|
||||||
t.Errorf(`%s.Property(%d) == nil`, obj.Tag(), index)
|
t.Errorf(`%s.Property(%s) == nil`, obj.Tag(), tag)
|
||||||
} else {
|
} else if key.Type() != nodeType {
|
||||||
if key.Tag() != tag {
|
|
||||||
t.Errorf(`%s.Property(%d).Tag() != "%s"`, obj.Tag(), index, tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
if key.Type() != nodeType {
|
|
||||||
switch nodeType {
|
switch nodeType {
|
||||||
case TextNode:
|
case TextDataValue:
|
||||||
t.Errorf(`%s.Property(%d) is not text`, obj.Tag(), index)
|
t.Errorf(`%s.Property(%s) is not text`, obj.Tag(), tag)
|
||||||
|
|
||||||
case ObjectNode:
|
case ObjectDataValue:
|
||||||
t.Errorf(`%s.Property(%d) is not object`, obj.Tag(), index)
|
t.Errorf(`%s.Property(%s) is not object`, obj.Tag(), tag)
|
||||||
|
|
||||||
case ArrayNode:
|
case ArrayDataValue:
|
||||||
t.Errorf(`%s.Property(%d) is not array`, obj.Tag(), index)
|
t.Errorf(`%s.Property(%s) is not array`, obj.Tag(), tag)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return key
|
return key
|
||||||
}
|
}
|
||||||
|
|
||||||
if key := testKey(obj, 0, "key1", TextNode); key != nil {
|
if key := testKey(obj, "key1", TextDataValue); key != nil {
|
||||||
if key.Text() != "val1" {
|
if key.String() != "val1" {
|
||||||
t.Error(`key1.Value() != "val1"`)
|
t.Error(`key1.Value() != "val1"`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if key := testKey(obj, 1, "key2", ObjectNode); key != nil {
|
if key := testKey(obj, "key2", ObjectDataValue); key != nil {
|
||||||
o := key.Object()
|
o := key.Object()
|
||||||
if o == nil {
|
if o == nil {
|
||||||
t.Error(`key2.Value().Object() == nil`)
|
t.Error(`key2.Value().Object() == nil`)
|
||||||
|
|
@ -116,61 +106,83 @@ func TestParseDataText(t *testing.T) {
|
||||||
|
|
||||||
type testKeyData struct {
|
type testKeyData struct {
|
||||||
tag string
|
tag string
|
||||||
nodeType DataNodeType
|
nodeType DataValueType
|
||||||
}
|
}
|
||||||
|
|
||||||
data := []testKeyData{
|
data := []testKeyData{
|
||||||
{tag: "key2.1", nodeType: ArrayNode},
|
{tag: "key2.1", nodeType: ArrayDataValue},
|
||||||
{tag: "key 2.2", nodeType: TextNode},
|
{tag: "key 2.2", nodeType: TextDataValue},
|
||||||
{tag: "key2.3", nodeType: ObjectNode},
|
{tag: "key2.3", nodeType: ObjectDataValue},
|
||||||
{tag: "key2.4", nodeType: ObjectNode},
|
{tag: "key2.4", nodeType: ObjectDataValue},
|
||||||
{tag: "key2.5", nodeType: ArrayNode},
|
{tag: "key2.5", nodeType: ArrayDataValue},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, d := range data {
|
for _, d := range data {
|
||||||
testKey(o, i, d.tag, d.nodeType)
|
testKey(o, d.tag, d.nodeType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
node1 := obj.Property(1)
|
node1 := obj.Property("key2")
|
||||||
if node1 == nil {
|
if node1 == nil {
|
||||||
t.Error("obj.Property(1) != nil")
|
t.Error("obj.Property(\"key2\") == nil")
|
||||||
} else if node1.Type() != ObjectNode {
|
} else if node1.Type() != ObjectDataValue {
|
||||||
t.Error("obj.Property(1).Type() != ObjectNode")
|
t.Error("obj.Property(\"key2\").Type() != ObjectNode")
|
||||||
} else if obj := node1.Object(); obj != nil {
|
} else if obj := node1.Object(); obj != nil {
|
||||||
if key := obj.Property(0); key != nil {
|
if key := obj.Property("key2.1"); key != nil {
|
||||||
if key.Type() != ArrayNode {
|
if key.Type() != ArrayDataValue {
|
||||||
t.Error("obj.Property(1).Object().Property(0)..Type() != ArrayNode")
|
t.Error("obj.Property(\"key2\").Object().Property(\"key2.1\").Type() != ArrayNode")
|
||||||
} else {
|
} else {
|
||||||
if key.ArraySize() != 3 {
|
array := key.Array()
|
||||||
t.Error("obj.Property(1).Object().Property(0).ArraySize() != 3")
|
if array == nil {
|
||||||
|
t.Error("obj.Property(\"key2\").Object().Property(\"key2.1\").Array() == nil")
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if array.Size() != 3 {
|
||||||
|
t.Error("obj.Property(\"key2\").Object().Property(\"key2.1\").Array().Size() != 3")
|
||||||
}
|
}
|
||||||
|
|
||||||
if e := key.ArrayElement(0); e == nil {
|
for i, tp := range []DataValueType{TextDataValue, ObjectDataValue, ObjectDataValue} {
|
||||||
t.Error("obj.Property(1).Object().Property(0).ArrayElement(0) == nil")
|
if e := array.Element(i); e == nil {
|
||||||
} else if e.IsObject() {
|
t.Error("obj.Property(\"key2\").Object().Property(\"key2.1\").Array().Element(0) == nil")
|
||||||
t.Error("obj.Property(1).Object().Property(0).ArrayElement(0).IsObject() == true")
|
} else if e.Type() != tp {
|
||||||
|
t.Errorf("obj.Property(\"key2\").Object().Property(\"key2.1\").Array().Element(0).Type() != %d", tp)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if e := key.ArrayElement(2); e == nil {
|
if e := array.Element(3); e != nil {
|
||||||
t.Error("obj.Property(1).Object().Property(0).ArrayElement(2) == nil")
|
t.Error("obj.Property(\"key2\").Object().Property(\"key2.1\").Array().Element(3) != nil")
|
||||||
} else if !e.IsObject() {
|
|
||||||
t.Error("obj.Property(1).Object().Property(0).ArrayElement(2).IsObject() == false")
|
|
||||||
} else if e.Value() != "" {
|
|
||||||
t.Error(`obj.Property(1).Object().Property(0).ArrayElement(2).Value() != ""`)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if e := key.ArrayElement(3); e != nil {
|
|
||||||
t.Error("obj.Property(1).Object().Property(0).ArrayElement(3) != nil")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
t.Error("obj.Property(1).Object() == nil")
|
t.Error("obj.Property(\"key 2.2\").Object() == nil")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expected := `obj1{
|
||||||
|
key1 = val1,
|
||||||
|
key2 = obj2{
|
||||||
|
key2.1 = [
|
||||||
|
val2.1,
|
||||||
|
obj2.2{},
|
||||||
|
obj2.3{},
|
||||||
|
],
|
||||||
|
"key 2.2" = "val 2.2",
|
||||||
|
key2.3 = _{},
|
||||||
|
key2.4 = obj2.3{
|
||||||
|
text = " ",
|
||||||
|
},
|
||||||
|
key2.5 = [],
|
||||||
|
},
|
||||||
|
key3 = "\n \t \\ \r \" ' ON Ǫ",
|
||||||
|
key4 = "\\n \\t \\\\ \\r \\\" ' \\x8F \\UF80a",
|
||||||
|
}`
|
||||||
|
if expected != obj.String() {
|
||||||
|
t.Error("obj.String() result fail")
|
||||||
|
}
|
||||||
|
|
||||||
failText := []string{
|
failText := []string{
|
||||||
" ",
|
" ",
|
||||||
"obj[]",
|
"obj[]",
|
||||||
|
|
|
||||||
|
|
@ -343,7 +343,7 @@ func (picker *datePickerData) htmlProperties(self View, buffer *strings.Builder)
|
||||||
func (picker *datePickerData) handleCommand(self View, command PropertyName, data DataObject) bool {
|
func (picker *datePickerData) handleCommand(self View, command PropertyName, data DataObject) bool {
|
||||||
switch command {
|
switch command {
|
||||||
case "textChanged":
|
case "textChanged":
|
||||||
if text, ok := data.PropertyValue("text"); ok {
|
if text, ok := data.PropertyText("text"); ok {
|
||||||
if value, err := time.Parse(dateFormat, text); err == nil {
|
if value, err := time.Parse(dateFormat, text); err == nil {
|
||||||
oldValue := GetDatePickerValue(picker)
|
oldValue := GetDatePickerValue(picker)
|
||||||
picker.setRaw(DatePickerValue, value)
|
picker.setRaw(DatePickerValue, value)
|
||||||
|
|
|
||||||
|
|
@ -228,7 +228,7 @@ func (event *DragAndDropEvent) init(session Session, data DataObject) {
|
||||||
event.MouseEvent.init(data)
|
event.MouseEvent.init(data)
|
||||||
|
|
||||||
event.Data = map[string]string{}
|
event.Data = map[string]string{}
|
||||||
if value, ok := data.PropertyValue("data"); ok {
|
if value, ok := data.PropertyText("data"); ok {
|
||||||
for line := range strings.SplitSeq(value, ";") {
|
for line := range strings.SplitSeq(value, ";") {
|
||||||
if mimeData, data, ok := strings.Cut(line, ":"); ok {
|
if mimeData, data, ok := strings.Cut(line, ":"); ok {
|
||||||
mime, err := base64.StdEncoding.DecodeString(mimeData)
|
mime, err := base64.StdEncoding.DecodeString(mimeData)
|
||||||
|
|
@ -246,11 +246,11 @@ func (event *DragAndDropEvent) init(session Session, data DataObject) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if targetId, ok := data.PropertyValue("target"); ok {
|
if targetId, ok := data.PropertyText("target"); ok {
|
||||||
event.Target = session.viewByHTMLID(targetId)
|
event.Target = session.viewByHTMLID(targetId)
|
||||||
}
|
}
|
||||||
|
|
||||||
if effect, ok := data.PropertyValue("effect-allowed"); ok {
|
if effect, ok := data.PropertyText("effect-allowed"); ok {
|
||||||
for i, value := range []string{"undefined", "copy", "move", "copyMove", "link", "copyLink", "linkMove", "all"} {
|
for i, value := range []string{"undefined", "copy", "move", "copyMove", "link", "copyLink", "linkMove", "all"} {
|
||||||
if value == effect {
|
if value == effect {
|
||||||
event.EffectAllowed = i
|
event.EffectAllowed = i
|
||||||
|
|
@ -259,7 +259,7 @@ func (event *DragAndDropEvent) init(session Session, data DataObject) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if effect, ok := data.PropertyValue("drop-effect"); ok && effect != "" {
|
if effect, ok := data.PropertyText("drop-effect"); ok && effect != "" {
|
||||||
for i, value := range []string{"none", "copy", "move", "", "link"} {
|
for i, value := range []string{"none", "copy", "move", "", "link"} {
|
||||||
if value == effect {
|
if value == effect {
|
||||||
event.DropEffect = i
|
event.DropEffect = i
|
||||||
|
|
|
||||||
|
|
@ -188,15 +188,17 @@ func parseIndicesArray(value any) ([]any, bool) {
|
||||||
case string:
|
case string:
|
||||||
return parseIndicesArray(strings.Split(value, ","))
|
return parseIndicesArray(strings.Split(value, ","))
|
||||||
|
|
||||||
case []DataValue:
|
case DataValue:
|
||||||
items := make([]string, 0, len(value))
|
if array := value.Array(); array != nil {
|
||||||
for _, val := range value {
|
items := make([]string, 0, array.Size())
|
||||||
if !val.IsObject() {
|
for val := range array.Elements() {
|
||||||
items = append(items, val.Value())
|
if val.Type() == TextDataValue {
|
||||||
|
items = append(items, val.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return parseIndicesArray(items)
|
return parseIndicesArray(items)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
@ -242,7 +244,7 @@ func (list *dropDownListData) htmlProperties(self View, buffer *strings.Builder)
|
||||||
func (list *dropDownListData) handleCommand(self View, command PropertyName, data DataObject) bool {
|
func (list *dropDownListData) handleCommand(self View, command PropertyName, data DataObject) bool {
|
||||||
switch command {
|
switch command {
|
||||||
case "itemSelected":
|
case "itemSelected":
|
||||||
if text, ok := data.PropertyValue("number"); ok {
|
if text, ok := data.PropertyText("number"); ok {
|
||||||
if number, err := strconv.Atoi(text); err == nil {
|
if number, err := strconv.Atoi(text); err == nil {
|
||||||
items := GetDropDownItems(list)
|
items := GetDropDownItems(list)
|
||||||
if GetCurrent(list) != number && number >= 0 && number < len(items) {
|
if GetCurrent(list) != number && number >= 0 && number < len(items) {
|
||||||
|
|
|
||||||
|
|
@ -387,7 +387,7 @@ func (edit *editViewData) handleCommand(self View, command PropertyName, data Da
|
||||||
switch command {
|
switch command {
|
||||||
case "textChanged":
|
case "textChanged":
|
||||||
oldText := GetText(edit)
|
oldText := GetText(edit)
|
||||||
if text, ok := data.PropertyValue("text"); ok {
|
if text, ok := data.PropertyText("text"); ok {
|
||||||
edit.setRaw(Text, text)
|
edit.setRaw(Text, text)
|
||||||
if text != oldText {
|
if text != oldText {
|
||||||
edit.textChanged(text, oldText)
|
edit.textChanged(text, oldText)
|
||||||
|
|
|
||||||
|
|
@ -88,24 +88,23 @@ type filePickerData struct {
|
||||||
//loader map[int]func(FileInfo, []byte)
|
//loader map[int]func(FileInfo, []byte)
|
||||||
}
|
}
|
||||||
|
|
||||||
func dataToFileInfo(node DataValue) FileInfo {
|
func dataToFileInfo(obj DataObject) FileInfo {
|
||||||
var file FileInfo
|
var file FileInfo
|
||||||
if obj := node.Object(); obj != nil {
|
file.Name, _ = obj.PropertyText("name")
|
||||||
file.Name, _ = obj.PropertyValue("name")
|
file.MimeType, _ = obj.PropertyText("mime-type")
|
||||||
file.MimeType, _ = obj.PropertyValue("mime-type")
|
|
||||||
|
|
||||||
if size, ok := obj.PropertyValue("size"); ok {
|
if size, ok := obj.PropertyText("size"); ok {
|
||||||
if n, err := strconv.ParseInt(size, 10, 64); err == nil {
|
if n, err := strconv.ParseInt(size, 10, 64); err == nil {
|
||||||
file.Size = n
|
file.Size = n
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if value, ok := obj.PropertyValue("last-modified"); ok {
|
if value, ok := obj.PropertyText("last-modified"); ok {
|
||||||
if n, err := strconv.ParseInt(value, 10, 64); err == nil {
|
if n, err := strconv.ParseInt(value, 10, 64); err == nil {
|
||||||
file.LastModified = time.UnixMilli(n)
|
file.LastModified = time.UnixMilli(n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return file
|
return file
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -273,16 +272,25 @@ func (picker *filePickerData) htmlProperties(self View, buffer *strings.Builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseFilesTag(data DataObject) []FileInfo {
|
func parseFilesTag(data DataObject) []FileInfo {
|
||||||
if node := data.PropertyByTag("files"); node != nil && node.Type() == ArrayNode {
|
if node := data.Property("files"); node != nil {
|
||||||
count := node.ArraySize()
|
switch node.Type() {
|
||||||
files := make([]FileInfo, count)
|
case ArrayDataValue:
|
||||||
for i := range count {
|
if array := node.Array(); array != nil {
|
||||||
if value := node.ArrayElement(i); value != nil {
|
files := make([]FileInfo, 0, array.Size())
|
||||||
files[i] = dataToFileInfo(value)
|
for value := range array.Elements() {
|
||||||
|
if obj := value.Object(); obj != nil {
|
||||||
|
files = append(files, dataToFileInfo(obj))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return files
|
return files
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case ObjectDataValue:
|
||||||
|
if obj := node.Object(); obj != nil {
|
||||||
|
return []FileInfo{dataToFileInfo(obj)}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
19
filter.go
19
filter.go
|
|
@ -171,13 +171,12 @@ func NewFilterProperty(params Params) FilterProperty {
|
||||||
func newFilterProperty(obj DataObject) FilterProperty {
|
func newFilterProperty(obj DataObject) FilterProperty {
|
||||||
filter := new(filterData)
|
filter := new(filterData)
|
||||||
filter.init()
|
filter.init()
|
||||||
for node := range obj.Properties() {
|
for tag, node := range obj.Properties() {
|
||||||
tag := node.Tag()
|
|
||||||
switch node.Type() {
|
switch node.Type() {
|
||||||
case TextNode:
|
case TextDataValue:
|
||||||
filter.Set(PropertyName(tag), node.Text())
|
filter.Set(PropertyName(tag), node.String())
|
||||||
|
|
||||||
case ObjectNode:
|
case ObjectDataValue:
|
||||||
if tag == string(HueRotate) {
|
if tag == string(HueRotate) {
|
||||||
// TODO
|
// TODO
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -286,15 +285,9 @@ func setFilterProperty(properties Properties, tag PropertyName, value any) []Pro
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case DataObject:
|
|
||||||
if filter := newFilterProperty(value); filter != nil {
|
|
||||||
properties.setRaw(tag, filter)
|
|
||||||
return []PropertyName{tag}
|
|
||||||
}
|
|
||||||
|
|
||||||
case DataValue:
|
case DataValue:
|
||||||
if value.IsObject() {
|
if obj := value.Object(); obj != nil {
|
||||||
if filter := newFilterProperty(value.Object()); filter != nil {
|
if filter := newFilterProperty(obj); filter != nil {
|
||||||
properties.setRaw(tag, filter)
|
properties.setRaw(tag, filter)
|
||||||
return []PropertyName{tag}
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
go.mod
2
go.mod
|
|
@ -1,6 +1,6 @@
|
||||||
module github.com/anoshenko/rui
|
module github.com/anoshenko/rui
|
||||||
|
|
||||||
go 1.24
|
go 1.26
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/gorilla/websocket v1.5.3
|
github.com/gorilla/websocket v1.5.3
|
||||||
|
|
|
||||||
|
|
@ -189,20 +189,22 @@ func setGridCellSize(properties Properties, tag PropertyName, value any) []Prope
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
case []DataValue:
|
case DataValue:
|
||||||
count := len(value)
|
array := value.Array()
|
||||||
if count == 0 {
|
if array == nil || array.Size() == 0 {
|
||||||
invalidPropertyValue(tag, value)
|
invalidPropertyValue(tag, value)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
values := make([]string, count)
|
|
||||||
for i, val := range value {
|
values := make([]string, 0, array.Size())
|
||||||
if val.IsObject() {
|
for val := range array.Elements() {
|
||||||
|
if val.Type() != TextDataValue {
|
||||||
invalidPropertyValue(tag, value)
|
invalidPropertyValue(tag, value)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
values[i] = val.Value()
|
values = append(values, val.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
if !setValues(values) {
|
if !setValues(values) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
10
image.go
10
image.go
|
|
@ -101,15 +101,15 @@ func (manager *imageManager) imageLoaded(obj DataObject) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if url, ok := obj.PropertyValue("url"); ok {
|
if url, ok := obj.PropertyText("url"); ok {
|
||||||
if image, ok := manager.images[url]; ok {
|
if image, ok := manager.images[url]; ok {
|
||||||
image.loadingStatus = ImageReady
|
image.loadingStatus = ImageReady
|
||||||
if width, ok := obj.PropertyValue("width"); ok {
|
if width, ok := obj.PropertyText("width"); ok {
|
||||||
if w, err := strconv.ParseFloat(width, 64); err == nil {
|
if w, err := strconv.ParseFloat(width, 64); err == nil {
|
||||||
image.width = w
|
image.width = w
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if height, ok := obj.PropertyValue("height"); ok {
|
if height, ok := obj.PropertyText("height"); ok {
|
||||||
if h, err := strconv.ParseFloat(height, 64); err == nil {
|
if h, err := strconv.ParseFloat(height, 64); err == nil {
|
||||||
image.height = h
|
image.height = h
|
||||||
}
|
}
|
||||||
|
|
@ -127,11 +127,11 @@ func (manager *imageManager) imageLoadError(obj DataObject) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if url, ok := obj.PropertyValue("url"); ok {
|
if url, ok := obj.PropertyText("url"); ok {
|
||||||
if image, ok := manager.images[url]; ok {
|
if image, ok := manager.images[url]; ok {
|
||||||
delete(manager.images, url)
|
delete(manager.images, url)
|
||||||
|
|
||||||
text, _ := obj.PropertyValue("message")
|
text, _ := obj.PropertyText("message")
|
||||||
image.setLoadingError(text)
|
image.setLoadingError(text)
|
||||||
|
|
||||||
if image.listener != nil {
|
if image.listener != nil {
|
||||||
|
|
|
||||||
|
|
@ -315,7 +315,7 @@ func (imageView *imageViewData) handleCommand(self View, command PropertyName, d
|
||||||
case "imageViewLoaded":
|
case "imageViewLoaded":
|
||||||
imageView.naturalWidth = dataFloatProperty(data, "natural-width")
|
imageView.naturalWidth = dataFloatProperty(data, "natural-width")
|
||||||
imageView.naturalHeight = dataFloatProperty(data, "natural-height")
|
imageView.naturalHeight = dataFloatProperty(data, "natural-height")
|
||||||
imageView.currentSrc, _ = data.PropertyValue("current-src")
|
imageView.currentSrc, _ = data.PropertyText("current-src")
|
||||||
|
|
||||||
for _, listener := range getNoArgEventListeners[ImageView](imageView, nil, LoadedEvent) {
|
for _, listener := range getNoArgEventListeners[ImageView](imageView, nil, LoadedEvent) {
|
||||||
listener.Run(imageView)
|
listener.Run(imageView)
|
||||||
|
|
|
||||||
10
keyEvents.go
10
keyEvents.go
|
|
@ -416,14 +416,12 @@ type KeyEvent struct {
|
||||||
|
|
||||||
func (event *KeyEvent) init(data DataObject) {
|
func (event *KeyEvent) init(data DataObject) {
|
||||||
getBool := func(tag string) bool {
|
getBool := func(tag string) bool {
|
||||||
if value, ok := data.PropertyValue(tag); ok && value == "1" {
|
value, ok := data.PropertyText(tag)
|
||||||
return true
|
return ok && value == "1"
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
event.Key, _ = data.PropertyValue("key")
|
event.Key, _ = data.PropertyText("key")
|
||||||
code, _ := data.PropertyValue("code")
|
code, _ := data.PropertyText("code")
|
||||||
event.Code = KeyCode(code)
|
event.Code = KeyCode(code)
|
||||||
event.TimeStamp = getTimeStamp(data)
|
event.TimeStamp = getTimeStamp(data)
|
||||||
event.Repeat = getBool("repeat")
|
event.Repeat = getBool("repeat")
|
||||||
|
|
|
||||||
52
listView.go
52
listView.go
|
|
@ -354,36 +354,62 @@ func (listView *listViewData) setItems(value any) []PropertyName {
|
||||||
case []string:
|
case []string:
|
||||||
adapter = NewTextListAdapter(value, nil)
|
adapter = NewTextListAdapter(value, nil)
|
||||||
|
|
||||||
case []DataValue:
|
case DataValue:
|
||||||
|
switch value.Type() {
|
||||||
|
case ObjectDataValue:
|
||||||
|
if view := CreateViewFromObject(session, value.Object(), nil); view != nil {
|
||||||
|
adapter = NewViewListAdapter([]View{view})
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
case TextDataValue:
|
||||||
|
adapter = NewTextListAdapter([]string{value.String()}, nil)
|
||||||
|
|
||||||
|
case ArrayDataValue:
|
||||||
|
array := value.Array()
|
||||||
|
if array == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
hasObject := false
|
hasObject := false
|
||||||
for _, val := range value {
|
for val := range array.Elements() {
|
||||||
if val.IsObject() {
|
switch val.Type() {
|
||||||
|
case ObjectDataValue:
|
||||||
hasObject = true
|
hasObject = true
|
||||||
break
|
|
||||||
|
case ArrayDataValue:
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if hasObject {
|
if hasObject {
|
||||||
items := make([]View, len(value))
|
items := make([]View, 0, array.Size())
|
||||||
for i, val := range value {
|
for val := range array.Elements() {
|
||||||
if val.IsObject() {
|
switch val.Type() {
|
||||||
|
case TextDataValue:
|
||||||
|
items = append(items, NewTextView(session, Params{Text: val.String()}))
|
||||||
|
|
||||||
|
case ObjectDataValue:
|
||||||
if view := CreateViewFromObject(session, val.Object(), nil); view != nil {
|
if view := CreateViewFromObject(session, val.Object(), nil); view != nil {
|
||||||
items[i] = view
|
items = append(items, view)
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
items[i] = NewTextView(session, Params{Text: val.Value()})
|
default:
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
adapter = NewViewListAdapter(items)
|
adapter = NewViewListAdapter(items)
|
||||||
} else {
|
} else {
|
||||||
items := make([]string, len(value))
|
items := make([]string, array.Size())
|
||||||
for i, val := range value {
|
for val := range array.Elements() {
|
||||||
items[i] = val.Value()
|
items = append(items, val.String())
|
||||||
}
|
}
|
||||||
adapter = NewTextListAdapter(items, nil)
|
adapter = NewTextListAdapter(items, nil)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
case []any:
|
case []any:
|
||||||
items := make([]View, len(value))
|
items := make([]View, len(value))
|
||||||
|
|
|
||||||
|
|
@ -659,7 +659,9 @@ func (player *mediaPlayerData) setFunc(tag PropertyName, value any) []PropertyNa
|
||||||
}
|
}
|
||||||
|
|
||||||
func setMediaPlayerSource(properties Properties, value any) []PropertyName {
|
func setMediaPlayerSource(properties Properties, value any) []PropertyName {
|
||||||
|
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
|
|
||||||
case string:
|
case string:
|
||||||
src := MediaSource{Url: value, MimeType: ""}
|
src := MediaSource{Url: value, MimeType: ""}
|
||||||
properties.setRaw(Source, []MediaSource{src})
|
properties.setRaw(Source, []MediaSource{src})
|
||||||
|
|
@ -670,31 +672,56 @@ func setMediaPlayerSource(properties Properties, value any) []PropertyName {
|
||||||
case []MediaSource:
|
case []MediaSource:
|
||||||
properties.setRaw(Source, value)
|
properties.setRaw(Source, value)
|
||||||
|
|
||||||
case DataObject:
|
case DataValue:
|
||||||
url, ok := value.PropertyValue("src")
|
switch value.Type() {
|
||||||
|
case ObjectDataValue:
|
||||||
|
obj := value.Object()
|
||||||
|
if obj == nil {
|
||||||
|
invalidPropertyValue(Source, value)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
url, ok := obj.PropertyText("src")
|
||||||
if !ok || url == "" {
|
if !ok || url == "" {
|
||||||
invalidPropertyValue(Source, value)
|
invalidPropertyValue(Source, value)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
mimeType, _ := value.PropertyValue("mime-type")
|
mimeType, _ := obj.PropertyText("mime-type")
|
||||||
src := MediaSource{Url: url, MimeType: mimeType}
|
src := MediaSource{Url: url, MimeType: mimeType}
|
||||||
properties.setRaw(Source, []MediaSource{src})
|
properties.setRaw(Source, []MediaSource{src})
|
||||||
|
|
||||||
case []DataValue:
|
case ArrayDataValue:
|
||||||
src := []MediaSource{}
|
array := value.Array()
|
||||||
for _, val := range value {
|
if array == nil {
|
||||||
if val.IsObject() {
|
invalidPropertyValue(Source, value)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
src := make([]MediaSource, 0, array.Size())
|
||||||
|
for val := range array.Elements() {
|
||||||
|
switch val.Type() {
|
||||||
|
case ObjectDataValue:
|
||||||
obj := val.Object()
|
obj := val.Object()
|
||||||
if url, ok := obj.PropertyValue("src"); ok && url != "" {
|
if obj == nil {
|
||||||
mimeType, _ := obj.PropertyValue("mime-type")
|
invalidPropertyValue(Source, value)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if url, ok := obj.PropertyText("src"); ok && url != "" {
|
||||||
|
mimeType, _ := obj.PropertyText("mime-type")
|
||||||
src = append(src, MediaSource{Url: url, MimeType: mimeType})
|
src = append(src, MediaSource{Url: url, MimeType: mimeType})
|
||||||
} else {
|
} else {
|
||||||
invalidPropertyValue(Source, value)
|
invalidPropertyValue(Source, value)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
src = append(src, MediaSource{Url: val.Value(), MimeType: ""})
|
case TextDataValue:
|
||||||
|
src = append(src, MediaSource{Url: val.String(), MimeType: ""})
|
||||||
|
|
||||||
|
default:
|
||||||
|
invalidPropertyValue(Source, value)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -704,6 +731,15 @@ func setMediaPlayerSource(properties Properties, value any) []PropertyName {
|
||||||
}
|
}
|
||||||
properties.setRaw(Source, src)
|
properties.setRaw(Source, src)
|
||||||
|
|
||||||
|
case TextDataValue:
|
||||||
|
src := MediaSource{Url: value.String(), MimeType: ""}
|
||||||
|
properties.setRaw(Source, []MediaSource{src})
|
||||||
|
|
||||||
|
default:
|
||||||
|
invalidPropertyValue(Source, value)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
notCompatibleType(Source, value)
|
notCompatibleType(Source, value)
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -1019,7 +1055,7 @@ func (player *mediaPlayerData) handleCommand(self View, command PropertyName, da
|
||||||
if value := player.getRaw(command); value != nil {
|
if value := player.getRaw(command); value != nil {
|
||||||
if listeners, ok := value.([]mediaPlayerErrorListener); ok {
|
if listeners, ok := value.([]mediaPlayerErrorListener); ok {
|
||||||
code, _ := dataIntProperty(data, "code")
|
code, _ := dataIntProperty(data, "code")
|
||||||
message, _ := data.PropertyValue("message")
|
message, _ := data.PropertyText("message")
|
||||||
for _, listener := range listeners {
|
for _, listener := range listeners {
|
||||||
listener.Run(player, code, message)
|
listener.Run(player, code, message)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -245,7 +245,7 @@ type MouseEvent struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTimeStamp(data DataObject) uint64 {
|
func getTimeStamp(data DataObject) uint64 {
|
||||||
if value, ok := data.PropertyValue("timeStamp"); ok {
|
if value, ok := data.PropertyText("timeStamp"); ok {
|
||||||
if index := strings.Index(value, "."); index > 0 {
|
if index := strings.Index(value, "."); index > 0 {
|
||||||
value = value[:index]
|
value = value[:index]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -286,7 +286,7 @@ func (picker *numberPickerData) htmlProperties(self View, buffer *strings.Builde
|
||||||
func (picker *numberPickerData) handleCommand(self View, command PropertyName, data DataObject) bool {
|
func (picker *numberPickerData) handleCommand(self View, command PropertyName, data DataObject) bool {
|
||||||
switch command {
|
switch command {
|
||||||
case "textChanged":
|
case "textChanged":
|
||||||
if text, ok := data.PropertyValue("text"); ok {
|
if text, ok := data.PropertyText("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.setRaw(NumberPickerValue, text)
|
picker.setRaw(NumberPickerValue, text)
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,7 @@ func setOutlineProperty(properties Properties, value any) []PropertyName {
|
||||||
case DataObject:
|
case DataObject:
|
||||||
outline := NewOutlineProperty(nil)
|
outline := NewOutlineProperty(nil)
|
||||||
for _, tag := range []PropertyName{Style, Width, ColorTag} {
|
for _, tag := range []PropertyName{Style, Width, ColorTag} {
|
||||||
if text, ok := value.PropertyValue(string(tag)); ok && text != "" {
|
if text, ok := value.PropertyText(string(tag)); ok && text != "" {
|
||||||
outline.Set(tag, text)
|
outline.Set(tag, text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -177,7 +177,7 @@ func (event *PointerEvent) init(data DataObject) {
|
||||||
event.TiltX = dataFloatProperty(data, "tiltX")
|
event.TiltX = dataFloatProperty(data, "tiltX")
|
||||||
event.TiltY = dataFloatProperty(data, "tiltY")
|
event.TiltY = dataFloatProperty(data, "tiltY")
|
||||||
event.Twist = dataFloatProperty(data, "twist")
|
event.Twist = dataFloatProperty(data, "twist")
|
||||||
value, _ := data.PropertyValue("pointerType")
|
value, _ := data.PropertyText("pointerType")
|
||||||
event.PointerType = value
|
event.PointerType = value
|
||||||
event.IsPrimary = dataBoolProperty(data, "isPrimary")
|
event.IsPrimary = dataBoolProperty(data, "isPrimary")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
40
popup.go
40
popup.go
|
|
@ -939,15 +939,15 @@ func (popup *popupData) setButtons(value any) bool {
|
||||||
popupButtonFromObject := func(obj DataObject) popupButton {
|
popupButtonFromObject := func(obj DataObject) popupButton {
|
||||||
var button popupButton
|
var button popupButton
|
||||||
|
|
||||||
button.title, _ = obj.PropertyValue(string(Title))
|
button.title, _ = obj.PropertyText(string(Title))
|
||||||
|
|
||||||
if text, ok := obj.PropertyValue("type"); ok {
|
if text, ok := obj.PropertyText("type"); ok {
|
||||||
text, _ = popup.session.resolveConstants(text)
|
text, _ = popup.session.resolveConstants(text)
|
||||||
t, _ := enumStringToInt(text, []string{"normal", "default", "cancel"}, true)
|
t, _ := enumStringToInt(text, []string{"normal", "default", "cancel"}, true)
|
||||||
button.buttonType = PopupButtonType(t)
|
button.buttonType = PopupButtonType(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
if fn, ok := obj.PropertyValue("click"); ok {
|
if fn, ok := obj.PropertyText("click"); ok {
|
||||||
button.onClick = newPopupListenerBinding(fn, true)
|
button.onClick = newPopupListenerBinding(fn, true)
|
||||||
} else if button.buttonType == CancelButton {
|
} else if button.buttonType == CancelButton {
|
||||||
button.onClick = newPopupListener0(popup.Dismiss)
|
button.onClick = newPopupListener0(popup.Dismiss)
|
||||||
|
|
@ -984,22 +984,38 @@ func (popup *popupData) setButtons(value any) bool {
|
||||||
case []popupButton:
|
case []popupButton:
|
||||||
popup.setRaw(Buttons, value)
|
popup.setRaw(Buttons, value)
|
||||||
|
|
||||||
case DataObject:
|
case DataValue:
|
||||||
popup.setRaw(Buttons, []popupButton{popupButtonFromObject(value)})
|
switch value.Type() {
|
||||||
|
case ObjectDataValue:
|
||||||
|
obj := value.Object()
|
||||||
|
if obj == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
popup.setRaw(Buttons, []popupButton{popupButtonFromObject(obj)})
|
||||||
|
|
||||||
case []DataValue:
|
case ArrayDataValue:
|
||||||
buttons := make([]popupButton, 0, len(value))
|
array := value.Array()
|
||||||
for _, val := range value {
|
if array == nil {
|
||||||
if val.IsObject() {
|
return false
|
||||||
buttons = append(buttons, popupButtonFromObject(val.Object()))
|
}
|
||||||
|
|
||||||
|
buttons := make([]popupButton, 0, array.Size())
|
||||||
|
for val := range array.Elements() {
|
||||||
|
if obj := val.Object(); obj != nil {
|
||||||
|
buttons = append(buttons, popupButtonFromObject(obj))
|
||||||
} else {
|
} else {
|
||||||
notCompatibleType(Buttons, val)
|
notCompatibleType(Buttons, val)
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(buttons) > 0 {
|
if len(buttons) > 0 {
|
||||||
popup.setRaw(Buttons, buttons)
|
popup.setRaw(Buttons, buttons)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
case []any:
|
case []any:
|
||||||
buttons := make([]popupButton, 0, len(value))
|
buttons := make([]popupButton, 0, len(value))
|
||||||
for _, val := range value {
|
for _, val := range value {
|
||||||
|
|
@ -1570,8 +1586,8 @@ func CreatePopupFromObject(session Session, object DataObject, binding any) Popu
|
||||||
popup.session = session
|
popup.session = session
|
||||||
popup.hotkeys = map[string]func(Popup){}
|
popup.hotkeys = map[string]func(Popup){}
|
||||||
|
|
||||||
for key, value := range object.ToParams() {
|
for key, value := range object.Properties() {
|
||||||
popup.Set(key, value)
|
popup.Set(PropertyName(key), value)
|
||||||
}
|
}
|
||||||
|
|
||||||
if binding != nil {
|
if binding != nil {
|
||||||
|
|
|
||||||
|
|
@ -149,28 +149,33 @@ func (properties *propertyList) writeToBuffer(buffer *strings.Builder,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
func parseProperties(properties Properties, object DataObject) {
|
func parseProperties(properties Properties, object DataObject) {
|
||||||
for node := range object.Properties() {
|
for tag, node := range object.Properties() {
|
||||||
switch node.Type() {
|
switch node.Type() {
|
||||||
case TextNode:
|
case TextDataValue:
|
||||||
properties.Set(PropertyName(node.Tag()), node.Text())
|
properties.Set(PropertyName(tag), node.String())
|
||||||
|
|
||||||
case ObjectNode:
|
case ObjectDataValue:
|
||||||
properties.Set(PropertyName(node.Tag()), node.Object())
|
properties.Set(PropertyName(tag), node.Object())
|
||||||
|
|
||||||
case ArrayNode:
|
case ArrayDataValue:
|
||||||
switch node.ArraySize() {
|
array := node.Array()
|
||||||
|
if array == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch array.Size() {
|
||||||
case 0:
|
case 0:
|
||||||
// do nothing
|
// do nothing
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
if v := node.ArrayElement(0); v.IsObject() {
|
if v := array.Element(0); v.Type() == TextDataValue {
|
||||||
properties.Set(PropertyName(node.Tag()), v.Object())
|
properties.Set(PropertyName(tag), v.String())
|
||||||
} else {
|
} else {
|
||||||
properties.Set(PropertyName(node.Tag()), v.Value())
|
properties.Set(PropertyName(tag), v)
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
properties.Set(PropertyName(node.Tag()), node.Array())
|
properties.Set(PropertyName(tag), array)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -978,7 +978,7 @@ func setRadiusProperty(properties Properties, value any) []PropertyName {
|
||||||
radius := NewRadiusProperty(nil)
|
radius := NewRadiusProperty(nil)
|
||||||
for _, tag := range []PropertyName{X, Y, TopLeft, TopRight, BottomLeft, BottomRight, TopLeftX, TopLeftY,
|
for _, tag := range []PropertyName{X, Y, TopLeft, TopRight, BottomLeft, BottomRight, TopLeftX, TopLeftY,
|
||||||
TopRightX, TopRightY, BottomLeftX, BottomLeftY, BottomRightX, BottomRightY} {
|
TopRightX, TopRightY, BottomLeftX, BottomLeftY, BottomRightX, BottomRightY} {
|
||||||
if value, ok := value.PropertyValue(string(tag)); ok {
|
if value, ok := value.PropertyText(string(tag)); ok {
|
||||||
radius.Set(tag, value)
|
radius.Set(tag, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
43
session.go
43
session.go
|
|
@ -701,7 +701,7 @@ func (session *sessionData) handleAnswer(command string, data DataObject) bool {
|
||||||
|
|
||||||
func (session *sessionData) handleRootSize(data DataObject) {
|
func (session *sessionData) handleRootSize(data DataObject) {
|
||||||
getValue := func(tag string) int {
|
getValue := func(tag string) int {
|
||||||
if value, ok := data.PropertyValue(tag); ok {
|
if value, ok := data.PropertyText(tag); ok {
|
||||||
float, err := strconv.ParseFloat(value, 64)
|
float, err := strconv.ParseFloat(value, 64)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return int(float)
|
return int(float)
|
||||||
|
|
@ -722,12 +722,17 @@ func (session *sessionData) handleRootSize(data DataObject) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *sessionData) handleResize(data DataObject) {
|
func (session *sessionData) handleResize(data DataObject) {
|
||||||
if node := data.PropertyByTag("views"); node != nil && node.Type() == ArrayNode {
|
array := data.PropertyArray("views")
|
||||||
for el := range node.ArrayElements() {
|
if array == nil {
|
||||||
if el.IsObject() {
|
ErrorLog(`Resize event error: invalid "views" property`)
|
||||||
obj := el.Object()
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for el := range array.Elements() {
|
||||||
|
if obj := el.Object(); obj != nil {
|
||||||
|
|
||||||
getFloat := func(tag string) float64 {
|
getFloat := func(tag string) float64 {
|
||||||
if value, ok := obj.PropertyValue(tag); ok {
|
if value, ok := obj.PropertyText(tag); ok {
|
||||||
f, err := strconv.ParseFloat(value, 64)
|
f, err := strconv.ParseFloat(value, 64)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return f
|
return f
|
||||||
|
|
@ -738,7 +743,8 @@ func (session *sessionData) handleResize(data DataObject) {
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
if viewID, ok := obj.PropertyValue("id"); ok {
|
|
||||||
|
if viewID, ok := obj.PropertyText("id"); ok {
|
||||||
if n := strings.IndexRune(viewID, '-'); n > 0 {
|
if n := strings.IndexRune(viewID, '-'); n > 0 {
|
||||||
if view := session.viewByHTMLID(viewID[:n]); view != nil {
|
if view := session.viewByHTMLID(viewID[:n]); view != nil {
|
||||||
view.onItemResize(view, viewID[n+1:], getFloat("x"), getFloat("y"), getFloat("width"), getFloat("height"))
|
view.onItemResize(view, viewID[n+1:], getFloat("x"), getFloat("y"), getFloat("width"), getFloat("height"))
|
||||||
|
|
@ -758,39 +764,36 @@ func (session *sessionData) handleResize(data DataObject) {
|
||||||
ErrorLog(`Resize event error: views element is not object`)
|
ErrorLog(`Resize event error: views element is not object`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
ErrorLog(`Resize event error: invalid "views" property`)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *sessionData) handleSessionInfo(params DataObject) {
|
func (session *sessionData) handleSessionInfo(params DataObject) {
|
||||||
if value, ok := params.PropertyValue("touch"); ok {
|
if value, ok := params.PropertyText("touch"); ok {
|
||||||
session.touchScreen = (value == "1" || value == "true")
|
session.touchScreen = (value == "1" || value == "true")
|
||||||
}
|
}
|
||||||
|
|
||||||
if value, ok := params.PropertyValue("user-agent"); ok {
|
if value, ok := params.PropertyText("user-agent"); ok {
|
||||||
session.userAgent = value
|
session.userAgent = value
|
||||||
}
|
}
|
||||||
|
|
||||||
if value, ok := params.PropertyValue("direction"); ok {
|
if value, ok := params.PropertyText("direction"); ok {
|
||||||
if value == "rtl" {
|
if value == "rtl" {
|
||||||
session.textDirection = RightToLeftDirection
|
session.textDirection = RightToLeftDirection
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if value, ok := params.PropertyValue("language"); ok {
|
if value, ok := params.PropertyText("language"); ok {
|
||||||
session.language = value
|
session.language = value
|
||||||
}
|
}
|
||||||
|
|
||||||
if value, ok := params.PropertyValue("languages"); ok {
|
if value, ok := params.PropertyText("languages"); ok {
|
||||||
session.languages = strings.Split(value, ",")
|
session.languages = strings.Split(value, ",")
|
||||||
}
|
}
|
||||||
|
|
||||||
if value, ok := params.PropertyValue("dark"); ok {
|
if value, ok := params.PropertyText("dark"); ok {
|
||||||
session.darkTheme = (value == "1" || value == "true")
|
session.darkTheme = (value == "1" || value == "true")
|
||||||
}
|
}
|
||||||
|
|
||||||
if value, ok := params.PropertyValue("pixel-ratio"); ok {
|
if value, ok := params.PropertyText("pixel-ratio"); ok {
|
||||||
if f, err := strconv.ParseFloat(value, 64); err != nil {
|
if f, err := strconv.ParseFloat(value, 64); err != nil {
|
||||||
ErrorLog(err.Error())
|
ErrorLog(err.Error())
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -798,7 +801,7 @@ func (session *sessionData) handleSessionInfo(params DataObject) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if value, ok := params.PropertyValue("light-dark"); ok {
|
if value, ok := params.PropertyText("light-dark"); ok {
|
||||||
session.lightDark = (value == "1" || value == "true")
|
session.lightDark = (value == "1" || value == "true")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -818,7 +821,7 @@ func (session *sessionData) handleEvent(command string, data DataObject) {
|
||||||
session.onResume()
|
session.onResume()
|
||||||
|
|
||||||
case "timer":
|
case "timer":
|
||||||
if text, ok := data.PropertyValue("timerID"); ok {
|
if text, ok := data.PropertyText("timerID"); ok {
|
||||||
timerID, err := strconv.Atoi(text)
|
timerID, err := strconv.Atoi(text)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if fn, ok := session.timers[timerID]; ok {
|
if fn, ok := session.timers[timerID]; ok {
|
||||||
|
|
@ -843,7 +846,7 @@ func (session *sessionData) handleEvent(command string, data DataObject) {
|
||||||
session.handleSessionInfo(data)
|
session.handleSessionInfo(data)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if viewID, ok := data.PropertyValue("id"); ok {
|
if viewID, ok := data.PropertyText("id"); ok {
|
||||||
if viewID != "body" {
|
if viewID != "body" {
|
||||||
if view := session.viewByHTMLID(viewID); view != nil {
|
if view := session.viewByHTMLID(viewID); view != nil {
|
||||||
view.handleCommand(view, PropertyName(command), data)
|
view.handleCommand(view, PropertyName(command), data)
|
||||||
|
|
|
||||||
33
shadow.go
33
shadow.go
|
|
@ -289,16 +289,39 @@ func setShadowProperty(properties Properties, tag PropertyName, value any) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
case DataValue:
|
case DataValue:
|
||||||
if !value.IsObject() {
|
switch value.Type() {
|
||||||
|
case ObjectDataValue:
|
||||||
|
obj := value.Object()
|
||||||
|
if obj == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
properties.setRaw(tag, []ShadowProperty{parseShadowProperty(obj)})
|
||||||
|
|
||||||
|
case ArrayDataValue:
|
||||||
|
array := value.Array()
|
||||||
|
if array == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
shadows := make([]ShadowProperty, 0, array.Size())
|
||||||
|
for data := range array.Elements() {
|
||||||
|
if obj := data.Object(); obj != nil {
|
||||||
|
shadows = append(shadows, parseShadowProperty(obj))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(shadows) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
properties.setRaw(tag, shadows)
|
||||||
|
|
||||||
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
properties.setRaw(tag, []ShadowProperty{parseShadowProperty(value.Object())})
|
|
||||||
|
|
||||||
case []DataValue:
|
case []DataValue:
|
||||||
shadows := []ShadowProperty{}
|
shadows := make([]ShadowProperty, 0, len(value))
|
||||||
for _, data := range value {
|
for _, data := range value {
|
||||||
if data.IsObject() {
|
if obj := data.Object(); obj != nil {
|
||||||
shadows = append(shadows, parseShadowProperty(data.Object()))
|
shadows = append(shadows, parseShadowProperty(obj))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(shadows) == 0 {
|
if len(shadows) == 0 {
|
||||||
|
|
|
||||||
12
strings.go
12
strings.go
|
|
@ -62,10 +62,8 @@ func loadStringResources(text string) {
|
||||||
table = map[string]string{}
|
table = map[string]string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
for prop := range obj.Properties() {
|
for tag, text := range obj.TextProperties() {
|
||||||
if prop.Type() == TextNode {
|
table[tag] = text
|
||||||
table[prop.Tag()] = prop.Text()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stringResources[lang] = table
|
stringResources[lang] = table
|
||||||
|
|
@ -73,9 +71,9 @@ func loadStringResources(text string) {
|
||||||
|
|
||||||
tag := data.Tag()
|
tag := data.Tag()
|
||||||
if tag == "strings" {
|
if tag == "strings" {
|
||||||
for prop := range data.Properties() {
|
for tag, prop := range data.Properties() {
|
||||||
if prop.Type() == ObjectNode {
|
if prop.Type() == ObjectDataValue {
|
||||||
parseStrings(prop.Object(), prop.Tag())
|
parseStrings(prop.Object(), tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
40
tableView.go
40
tableView.go
|
|
@ -643,11 +643,33 @@ func (table *tableViewData) setFunc(tag PropertyName, value any) []PropertyName
|
||||||
setLineStyle := func() []PropertyName {
|
setLineStyle := func() []PropertyName {
|
||||||
params := []Params{}
|
params := []Params{}
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
|
case Params:
|
||||||
|
params = []Params{value}
|
||||||
|
|
||||||
case []Params:
|
case []Params:
|
||||||
params = value
|
params = value
|
||||||
|
|
||||||
case DataNode:
|
case DataValue:
|
||||||
params = value.ArrayAsParams()
|
switch value.Type() {
|
||||||
|
case ObjectDataValue:
|
||||||
|
if obj := value.Object(); obj != nil {
|
||||||
|
if objParams := obj.ToParams(); len(objParams) > 0 {
|
||||||
|
params = []Params{objParams}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case ArrayDataValue:
|
||||||
|
if array := value.Array(); array != nil {
|
||||||
|
params = make([]Params, 0, array.Size())
|
||||||
|
for element := range array.Elements() {
|
||||||
|
if obj := element.Object(); obj != nil {
|
||||||
|
if objParams := obj.ToParams(); len(objParams) > 0 {
|
||||||
|
params = append(params, objParams)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
notCompatibleType(tag, params)
|
notCompatibleType(tag, params)
|
||||||
|
|
@ -751,20 +773,18 @@ func (table *tableViewData) setFunc(tag PropertyName, value any) []PropertyName
|
||||||
|
|
||||||
case DataObject:
|
case DataObject:
|
||||||
params := Params{}
|
params := Params{}
|
||||||
for prop := range value.Properties() {
|
for tag, prop := range value.TextProperties() {
|
||||||
if prop.Type() == TextNode {
|
params[PropertyName(tag)] = prop
|
||||||
params[PropertyName(prop.Tag())] = prop.Text()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return table.setFunc(tag, params)
|
return table.setFunc(tag, params)
|
||||||
|
|
||||||
case DataNode:
|
case DataValue:
|
||||||
switch value.Type() {
|
switch value.Type() {
|
||||||
case ObjectNode:
|
case ObjectDataValue:
|
||||||
return table.setFunc(tag, value.Object())
|
return table.setFunc(tag, value.Object())
|
||||||
|
|
||||||
case TextNode:
|
case TextDataValue:
|
||||||
table.setRaw(tag, value.Text())
|
table.setRaw(tag, value.String())
|
||||||
|
|
||||||
default:
|
default:
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
|
|
|
||||||
|
|
@ -703,7 +703,7 @@ func (tabsLayout *tabsLayoutData) htmlSubviews(self View, buffer *strings.Builde
|
||||||
func (tabsLayout *tabsLayoutData) handleCommand(self View, command PropertyName, data DataObject) bool {
|
func (tabsLayout *tabsLayoutData) handleCommand(self View, command PropertyName, data DataObject) bool {
|
||||||
switch command {
|
switch command {
|
||||||
case "tabClick":
|
case "tabClick":
|
||||||
if numberText, ok := data.PropertyValue("number"); ok {
|
if numberText, ok := data.PropertyText("number"); ok {
|
||||||
if number, err := strconv.Atoi(numberText); err == nil {
|
if number, err := strconv.Atoi(numberText); err == nil {
|
||||||
current := GetCurrent(tabsLayout)
|
current := GetCurrent(tabsLayout)
|
||||||
if current != number {
|
if current != number {
|
||||||
|
|
@ -716,7 +716,7 @@ func (tabsLayout *tabsLayoutData) handleCommand(self View, command PropertyName,
|
||||||
return true
|
return true
|
||||||
|
|
||||||
case "tabCloseClick":
|
case "tabCloseClick":
|
||||||
if numberText, ok := data.PropertyValue("number"); ok {
|
if numberText, ok := data.PropertyText("number"); ok {
|
||||||
if number, err := strconv.Atoi(numberText); err == nil {
|
if number, err := strconv.Atoi(numberText); err == nil {
|
||||||
for _, listener := range getOneArgEventListeners[TabsLayout, int](tabsLayout, nil, TabCloseEvent) {
|
for _, listener := range getOneArgEventListeners[TabsLayout, int](tabsLayout, nil, TabCloseEvent) {
|
||||||
listener.Run(tabsLayout, number)
|
listener.Run(tabsLayout, number)
|
||||||
|
|
|
||||||
85
theme.go
85
theme.go
|
|
@ -709,119 +709,92 @@ func (theme *theme) addText(themeText string) bool {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ErrorLog(err.Error())
|
ErrorLog(err.Error())
|
||||||
return false
|
return false
|
||||||
} else if !data.IsObject() || data.Tag() != "theme" {
|
} else if data.Tag() != "theme" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
objToStyle := func(obj DataObject) ViewStyle {
|
objToStyle := func(obj DataObject) ViewStyle {
|
||||||
params := Params{}
|
params := Params{}
|
||||||
for node := range obj.Properties() {
|
for tag, node := range obj.Properties() {
|
||||||
switch node.Type() {
|
switch node.Type() {
|
||||||
case ArrayNode:
|
case ArrayDataValue:
|
||||||
params[PropertyName(node.Tag())] = node.Array()
|
params[PropertyName(tag)] = node.Array()
|
||||||
|
|
||||||
case ObjectNode:
|
case ObjectDataValue:
|
||||||
params[PropertyName(node.Tag())] = node.Object()
|
params[PropertyName(tag)] = node.Object()
|
||||||
|
|
||||||
default:
|
default:
|
||||||
params[PropertyName(node.Tag())] = node.Text()
|
params[PropertyName(tag)] = node.String()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NewViewStyle(params)
|
return NewViewStyle(params)
|
||||||
}
|
}
|
||||||
|
|
||||||
for d := range data.Properties() {
|
for tag, d := range data.Properties() {
|
||||||
switch tag := d.Tag(); tag {
|
switch tag {
|
||||||
case "name":
|
case "name":
|
||||||
if d.Type() == TextNode {
|
if d.Type() == TextDataValue {
|
||||||
if text := d.Text(); text != "" {
|
if text := d.String(); text != "" {
|
||||||
theme.name = text
|
theme.name = text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case "constants":
|
case "constants":
|
||||||
if d.Type() == ObjectNode {
|
|
||||||
if obj := d.Object(); obj != nil {
|
if obj := d.Object(); obj != nil {
|
||||||
for prop := range obj.Properties() {
|
for propTag, text := range obj.TextProperties() {
|
||||||
if prop.Type() == TextNode {
|
theme.constants[propTag] = text
|
||||||
theme.constants[prop.Tag()] = prop.Text()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case "constants:touch":
|
case "constants:touch":
|
||||||
if d.Type() == ObjectNode {
|
|
||||||
if obj := d.Object(); obj != nil {
|
if obj := d.Object(); obj != nil {
|
||||||
for prop := range obj.Properties() {
|
for propTag, text := range obj.TextProperties() {
|
||||||
if prop.Type() == TextNode {
|
theme.touchConstants[propTag] = text
|
||||||
theme.touchConstants[prop.Tag()] = prop.Text()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case "colors":
|
case "colors":
|
||||||
if d.Type() == ObjectNode {
|
|
||||||
if obj := d.Object(); obj != nil {
|
if obj := d.Object(); obj != nil {
|
||||||
for prop := range obj.Properties() {
|
for propTag, text := range obj.TextProperties() {
|
||||||
if prop.Type() == TextNode {
|
theme.colors[propTag] = text
|
||||||
theme.colors[prop.Tag()] = prop.Text()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case "colors:dark":
|
case "colors:dark":
|
||||||
if d.Type() == ObjectNode {
|
|
||||||
if obj := d.Object(); obj != nil {
|
if obj := d.Object(); obj != nil {
|
||||||
for prop := range obj.Properties() {
|
for propTag, text := range obj.TextProperties() {
|
||||||
if prop.Type() == TextNode {
|
theme.darkColors[propTag] = text
|
||||||
theme.darkColors[prop.Tag()] = prop.Text()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case "images":
|
case "images":
|
||||||
if d.Type() == ObjectNode {
|
|
||||||
if obj := d.Object(); obj != nil {
|
if obj := d.Object(); obj != nil {
|
||||||
for prop := range obj.Properties() {
|
for propTag, text := range obj.TextProperties() {
|
||||||
if prop.Type() == TextNode {
|
theme.images[propTag] = text
|
||||||
theme.images[prop.Tag()] = prop.Text()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case "images:dark":
|
case "images:dark":
|
||||||
if d.Type() == ObjectNode {
|
|
||||||
if obj := d.Object(); obj != nil {
|
if obj := d.Object(); obj != nil {
|
||||||
for prop := range obj.Properties() {
|
for propTag, text := range obj.TextProperties() {
|
||||||
if prop.Type() == TextNode {
|
theme.darkImages[propTag] = text
|
||||||
theme.darkImages[prop.Tag()] = prop.Text()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case "styles":
|
case "styles":
|
||||||
if d.Type() == ArrayNode {
|
if array := d.Array(); array != nil {
|
||||||
arraySize := d.ArraySize()
|
for element := range array.Elements() {
|
||||||
for k := range arraySize {
|
|
||||||
if element := d.ArrayElement(k); element != nil && element.IsObject() {
|
|
||||||
if obj := element.Object(); obj != nil {
|
if obj := element.Object(); obj != nil {
|
||||||
theme.styles[obj.Tag()] = objToStyle(obj)
|
theme.styles[obj.Tag()] = objToStyle(obj)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if d.Type() == ArrayNode && strings.HasPrefix(tag, "styles:") {
|
if d.Type() == ArrayDataValue && strings.HasPrefix(tag, "styles:") {
|
||||||
if rule, ok := parseMediaRule(tag); ok {
|
if rule, ok := parseMediaRule(tag); ok {
|
||||||
arraySize := d.ArraySize()
|
if array := d.Array(); array != nil {
|
||||||
for k := range arraySize {
|
for element := range array.Elements() {
|
||||||
if element := d.ArrayElement(k); element != nil && element.IsObject() {
|
|
||||||
if obj := element.Object(); obj != nil {
|
if obj := element.Object(); obj != nil {
|
||||||
rule.styles[obj.Tag()] = objToStyle(obj)
|
rule.styles[obj.Tag()] = objToStyle(obj)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -318,7 +318,7 @@ func (picker *timePickerData) htmlProperties(self View, buffer *strings.Builder)
|
||||||
func (picker *timePickerData) handleCommand(self View, command PropertyName, data DataObject) bool {
|
func (picker *timePickerData) handleCommand(self View, command PropertyName, data DataObject) bool {
|
||||||
switch command {
|
switch command {
|
||||||
case "textChanged":
|
case "textChanged":
|
||||||
if text, ok := data.PropertyValue("text"); ok {
|
if text, ok := data.PropertyText("text"); ok {
|
||||||
if value, ok := stringToTime(text); ok {
|
if value, ok := stringToTime(text); ok {
|
||||||
oldValue := GetTimePickerValue(picker)
|
oldValue := GetTimePickerValue(picker)
|
||||||
picker.setRaw(TimePickerValue, value)
|
picker.setRaw(TimePickerValue, value)
|
||||||
|
|
|
||||||
|
|
@ -154,29 +154,28 @@ func (event *TouchEvent) init(data DataObject) {
|
||||||
|
|
||||||
event.Touches = []Touch{}
|
event.Touches = []Touch{}
|
||||||
event.TimeStamp = getTimeStamp(data)
|
event.TimeStamp = getTimeStamp(data)
|
||||||
if node := data.PropertyByTag("touches"); node != nil && node.Type() == ArrayNode {
|
if array := data.PropertyArray("touches"); array != nil {
|
||||||
for i := range node.ArraySize() {
|
for element := range array.Elements() {
|
||||||
if element := node.ArrayElement(i); element != nil && element.IsObject() {
|
|
||||||
if obj := element.Object(); obj != nil {
|
if obj := element.Object(); obj != nil {
|
||||||
var touch Touch
|
touch := Touch{
|
||||||
if value, ok := obj.PropertyValue("identifier"); ok {
|
X: dataFloatProperty(obj, "x"),
|
||||||
|
Y: dataFloatProperty(obj, "y"),
|
||||||
|
ClientX: dataFloatProperty(obj, "clientX"),
|
||||||
|
ClientY: dataFloatProperty(obj, "clientY"),
|
||||||
|
ScreenX: dataFloatProperty(obj, "screenX"),
|
||||||
|
ScreenY: dataFloatProperty(obj, "screenY"),
|
||||||
|
RadiusX: dataFloatProperty(obj, "radiusX"),
|
||||||
|
RadiusY: dataFloatProperty(obj, "radiusY"),
|
||||||
|
RotationAngle: dataFloatProperty(obj, "rotationAngle"),
|
||||||
|
Force: dataFloatProperty(obj, "force"),
|
||||||
|
}
|
||||||
|
if value, ok := obj.PropertyText("identifier"); ok {
|
||||||
touch.Identifier, _ = strconv.Atoi(value)
|
touch.Identifier, _ = strconv.Atoi(value)
|
||||||
}
|
}
|
||||||
touch.X = dataFloatProperty(obj, "x")
|
|
||||||
touch.Y = dataFloatProperty(obj, "y")
|
|
||||||
touch.ClientX = dataFloatProperty(obj, "clientX")
|
|
||||||
touch.ClientY = dataFloatProperty(obj, "clientY")
|
|
||||||
touch.ScreenX = dataFloatProperty(obj, "screenX")
|
|
||||||
touch.ScreenY = dataFloatProperty(obj, "screenY")
|
|
||||||
touch.RadiusX = dataFloatProperty(obj, "radiusX")
|
|
||||||
touch.RadiusY = dataFloatProperty(obj, "radiusY")
|
|
||||||
touch.RotationAngle = dataFloatProperty(obj, "rotationAngle")
|
|
||||||
touch.Force = dataFloatProperty(obj, "force")
|
|
||||||
event.Touches = append(event.Touches, touch)
|
event.Touches = append(event.Touches, touch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
event.CtrlKey = dataBoolProperty(data, "ctrlKey")
|
event.CtrlKey = dataBoolProperty(data, "ctrlKey")
|
||||||
event.ShiftKey = dataBoolProperty(data, "shiftKey")
|
event.ShiftKey = dataBoolProperty(data, "shiftKey")
|
||||||
event.AltKey = dataBoolProperty(data, "altKey")
|
event.AltKey = dataBoolProperty(data, "altKey")
|
||||||
|
|
|
||||||
11
transform.go
11
transform.go
|
|
@ -352,9 +352,9 @@ func valueToTransformProperty(value any) TransformProperty {
|
||||||
parseObject := func(obj DataObject) TransformProperty {
|
parseObject := func(obj DataObject) TransformProperty {
|
||||||
transform := NewTransformProperty(nil)
|
transform := NewTransformProperty(nil)
|
||||||
ok := true
|
ok := true
|
||||||
for prop := range obj.Properties() {
|
for tag, prop := range obj.Properties() {
|
||||||
if prop.Type() == TextNode {
|
if prop.Type() == TextDataValue {
|
||||||
if !transform.Set(PropertyName(prop.Tag()), prop.Text()) {
|
if !transform.Set(PropertyName(tag), prop.String()) {
|
||||||
ok = false
|
ok = false
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -372,10 +372,7 @@ func valueToTransformProperty(value any) TransformProperty {
|
||||||
case TransformProperty:
|
case TransformProperty:
|
||||||
return value
|
return value
|
||||||
|
|
||||||
case DataObject:
|
case DataValue:
|
||||||
return parseObject(value)
|
|
||||||
|
|
||||||
case DataNode:
|
|
||||||
if obj := value.Object(); obj != nil {
|
if obj := value.Object(); obj != nil {
|
||||||
return parseObject(obj)
|
return parseObject(obj)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
57
utils.go
57
utils.go
|
|
@ -54,7 +54,7 @@ func GetLocalIP() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func dataIntProperty(data DataObject, tag string) (int, bool) {
|
func dataIntProperty(data DataObject, tag string) (int, bool) {
|
||||||
if value, ok := data.PropertyValue(tag); ok {
|
if value, ok := data.PropertyText(tag); ok {
|
||||||
if n, err := strconv.Atoi(value); err == nil {
|
if n, err := strconv.Atoi(value); err == nil {
|
||||||
return n, true
|
return n, true
|
||||||
}
|
}
|
||||||
|
|
@ -63,14 +63,14 @@ func dataIntProperty(data DataObject, tag string) (int, bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func dataBoolProperty(data DataObject, tag string) bool {
|
func dataBoolProperty(data DataObject, tag string) bool {
|
||||||
if value, ok := data.PropertyValue(tag); ok && value == "1" {
|
if value, ok := data.PropertyText(tag); ok && value == "1" {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func dataFloatProperty(data DataObject, tag string) float64 {
|
func dataFloatProperty(data DataObject, tag string) float64 {
|
||||||
if value, ok := data.PropertyValue(tag); ok {
|
if value, ok := data.PropertyText(tag); ok {
|
||||||
if n, err := strconv.ParseFloat(value, 64); err == nil {
|
if n, err := strconv.ParseFloat(value, 64); err == nil {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
@ -136,3 +136,54 @@ func writeStrings(buffer *strings.Builder, strs ...string) {
|
||||||
buffer.WriteString(str)
|
buffer.WriteString(str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isQuotesNeeded(text string) bool {
|
||||||
|
switch len(text) {
|
||||||
|
case 0:
|
||||||
|
return true
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
simple := (text[0] >= '0' && text[0] <= '9') || (text[0] >= 'A' && text[0] <= 'Z') ||
|
||||||
|
(text[0] >= 'a' && text[0] <= 'z') || text[0] == '_'
|
||||||
|
return !simple
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ch := range text {
|
||||||
|
if (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') ||
|
||||||
|
ch == '+' || ch == '-' || ch == '@' || ch == '/' || ch == '_' || ch == '.' ||
|
||||||
|
ch == ':' || ch == '#' || ch == '%' || ch == 'π' || ch == '°' {
|
||||||
|
} else {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func replaceEscapeSymbols(text string) string {
|
||||||
|
replace := []struct{ old, new string }{
|
||||||
|
{old: "\\", new: `\\`},
|
||||||
|
{old: "\t", new: `\t`},
|
||||||
|
{old: "\r", new: `\r`},
|
||||||
|
{old: "\n", new: `\n`},
|
||||||
|
{old: "\"", new: `\"`},
|
||||||
|
}
|
||||||
|
for _, s := range replace {
|
||||||
|
text = strings.ReplaceAll(text, s.old, s.new)
|
||||||
|
}
|
||||||
|
return text
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeRuiText(buffer *strings.Builder, text string, objectName bool) {
|
||||||
|
if isQuotesNeeded(text) || (objectName && strings.Contains(text, "/")) {
|
||||||
|
if strings.ContainsAny(text, "\\\t\r\n\"") {
|
||||||
|
text = replaceEscapeSymbols(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.WriteRune('"')
|
||||||
|
buffer.WriteString(text)
|
||||||
|
buffer.WriteRune('"')
|
||||||
|
} else {
|
||||||
|
buffer.WriteString(text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
58
view.go
58
view.go
|
|
@ -424,12 +424,11 @@ func (view *viewData) setFunc(tag PropertyName, value any) []PropertyName {
|
||||||
return []PropertyName{Binding}
|
return []PropertyName{Binding}
|
||||||
|
|
||||||
case changeListeners:
|
case changeListeners:
|
||||||
switch value := value.(type) {
|
if value, ok := value.(DataObject); ok {
|
||||||
case DataObject:
|
for tag, node := range value.Properties() {
|
||||||
for node := range value.Properties() {
|
if node.Type() == TextDataValue {
|
||||||
if node.Type() == TextNode {
|
if text := node.String(); text != "" {
|
||||||
if text := node.Text(); text != "" {
|
view.changeListener[PropertyName(tag)] = newOneArgListenerBinding[View, PropertyName](text)
|
||||||
view.changeListener[PropertyName(node.Tag())] = newOneArgListenerBinding[View, PropertyName](text)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -437,11 +436,6 @@ func (view *viewData) setFunc(tag PropertyName, value any) []PropertyName {
|
||||||
view.setRaw(changeListeners, view.changeListener)
|
view.setRaw(changeListeners, view.changeListener)
|
||||||
}
|
}
|
||||||
return []PropertyName{tag}
|
return []PropertyName{tag}
|
||||||
|
|
||||||
case DataNode:
|
|
||||||
if value.Type() == ObjectNode {
|
|
||||||
return view.setFunc(tag, value.Object())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return []PropertyName{}
|
return []PropertyName{}
|
||||||
|
|
||||||
|
|
@ -548,11 +542,17 @@ func (view *viewData) setFunc(tag PropertyName, value any) []PropertyName {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case DataObject:
|
case DataValue:
|
||||||
|
switch value.Type() {
|
||||||
|
case TextDataValue:
|
||||||
|
return view.setFunc(DragData, value.String())
|
||||||
|
|
||||||
|
case ObjectDataValue:
|
||||||
|
if obj := value.Object(); obj != nil {
|
||||||
data := map[string]string{}
|
data := map[string]string{}
|
||||||
for node := range value.Properties() {
|
for tag, node := range obj.Properties() {
|
||||||
if node.Type() == TextNode {
|
if node.Type() == TextDataValue {
|
||||||
data[node.Tag()] = node.Text()
|
data[tag] = node.String()
|
||||||
} else {
|
} else {
|
||||||
invalidPropertyValue(DragData, value)
|
invalidPropertyValue(DragData, value)
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -563,23 +563,11 @@ func (view *viewData) setFunc(tag PropertyName, value any) []PropertyName {
|
||||||
} else {
|
} else {
|
||||||
view.setRaw(DragData, data)
|
view.setRaw(DragData, data)
|
||||||
}
|
}
|
||||||
|
return []PropertyName{DragData}
|
||||||
case DataNode:
|
}
|
||||||
switch value.Type() {
|
|
||||||
case TextNode:
|
|
||||||
return view.setFunc(DragData, value.Text())
|
|
||||||
|
|
||||||
case ObjectNode:
|
|
||||||
return view.setFunc(DragData, value.Object())
|
|
||||||
}
|
}
|
||||||
invalidPropertyValue(DragData, value)
|
invalidPropertyValue(DragData, value)
|
||||||
return nil
|
return []PropertyName{}
|
||||||
|
|
||||||
case DataValue:
|
|
||||||
if value.IsObject() {
|
|
||||||
return view.setFunc(DragData, value.Object())
|
|
||||||
}
|
|
||||||
return view.setFunc(DragData, value.Value())
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
notCompatibleType(DragData, value)
|
notCompatibleType(DragData, value)
|
||||||
|
|
@ -1205,14 +1193,14 @@ func (view *viewData) handleCommand(self View, command PropertyName, data DataOb
|
||||||
view.onScroll(view, dataFloatProperty(data, "x"), dataFloatProperty(data, "y"), dataFloatProperty(data, "width"), dataFloatProperty(data, "height"))
|
view.onScroll(view, dataFloatProperty(data, "x"), dataFloatProperty(data, "y"), dataFloatProperty(data, "width"), dataFloatProperty(data, "height"))
|
||||||
|
|
||||||
case "widthChanged":
|
case "widthChanged":
|
||||||
if value, ok := data.PropertyValue("width"); ok {
|
if value, ok := data.PropertyText("width"); ok {
|
||||||
if width, ok := StringToSizeUnit(value); ok {
|
if width, ok := StringToSizeUnit(value); ok {
|
||||||
self.setRaw(Width, width)
|
self.setRaw(Width, width)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case "heightChanged":
|
case "heightChanged":
|
||||||
if value, ok := data.PropertyValue("height"); ok {
|
if value, ok := data.PropertyText("height"); ok {
|
||||||
if height, ok := StringToSizeUnit(value); ok {
|
if height, ok := StringToSizeUnit(value); ok {
|
||||||
self.setRaw(Height, height)
|
self.setRaw(Height, height)
|
||||||
}
|
}
|
||||||
|
|
@ -1221,7 +1209,7 @@ func (view *viewData) handleCommand(self View, command PropertyName, data DataOb
|
||||||
/*
|
/*
|
||||||
case "resize":
|
case "resize":
|
||||||
floatProperty := func(tag string) float64 {
|
floatProperty := func(tag string) float64 {
|
||||||
if value, ok := data.PropertyValue(tag); ok {
|
if value, ok := data.PropertyText(tag); ok {
|
||||||
if result, err := strconv.ParseFloat(value, 64); err == nil {
|
if result, err := strconv.ParseFloat(value, 64); err == nil {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
@ -1240,7 +1228,7 @@ func (view *viewData) handleCommand(self View, command PropertyName, data DataOb
|
||||||
if listener := view.fileLoader[key]; listener != nil {
|
if listener := view.fileLoader[key]; listener != nil {
|
||||||
delete(view.fileLoader, key)
|
delete(view.fileLoader, key)
|
||||||
|
|
||||||
if base64Data, ok := data.PropertyValue("data"); ok {
|
if base64Data, ok := data.PropertyText("data"); ok {
|
||||||
if index := strings.LastIndex(base64Data, ","); index >= 0 {
|
if index := strings.LastIndex(base64Data, ","); index >= 0 {
|
||||||
base64Data = base64Data[index+1:]
|
base64Data = base64Data[index+1:]
|
||||||
}
|
}
|
||||||
|
|
@ -1258,7 +1246,7 @@ func (view *viewData) handleCommand(self View, command PropertyName, data DataOb
|
||||||
file := dataToFileInfo(data)
|
file := dataToFileInfo(data)
|
||||||
key := file.key()
|
key := file.key()
|
||||||
|
|
||||||
if error, ok := data.PropertyValue("error"); ok {
|
if error, ok := data.PropertyText("error"); ok {
|
||||||
ErrorLogF(`Load "%s" file error: %s`, file.Name, error)
|
ErrorLogF(`Load "%s" file error: %s`, file.Name, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -78,14 +78,19 @@ func RegisterViewCreator(tag string, creator func(Session) View) bool {
|
||||||
// If the function fails, it returns nil and an error message is written to the log.
|
// If the function fails, it returns nil and an error message is written to the log.
|
||||||
func CreateViewFromObject(session Session, object DataObject, binding any) View {
|
func CreateViewFromObject(session Session, object DataObject, binding any) View {
|
||||||
if session == nil {
|
if session == nil {
|
||||||
ErrorLog(`Session must not be nil`)
|
ErrorLog(`CreateViewFromObject: session must not be nil`)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if object == nil {
|
||||||
|
ErrorLog(`CreateViewFromObject: object must not be nil`)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
tag := object.Tag()
|
tag := object.Tag()
|
||||||
creator, ok := viewCreators()[strings.ToLower(tag)]
|
creator, ok := viewCreators()[strings.ToLower(tag)]
|
||||||
if !ok {
|
if !ok {
|
||||||
ErrorLog(`Unknown view type "` + tag + `"`)
|
ErrorLog(`CreateViewFromObject: unknown view type "` + tag + `"`)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
81
viewStyle.go
81
viewStyle.go
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"unicode"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ViewStyle interface of the style of view
|
// ViewStyle interface of the style of view
|
||||||
|
|
@ -566,68 +565,8 @@ func viewStyleGet(style Properties, tag PropertyName) any {
|
||||||
return style.getRaw(tag)
|
return style.getRaw(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func isQuotesNeeded(text string) bool {
|
|
||||||
if len(text) == 1 {
|
|
||||||
simple := (text[0] >= '0' && text[0] <= '9') || (text[0] >= 'A' && text[0] <= 'Z') || (text[0] >= 'a' && text[0] <= 'z')
|
|
||||||
return !simple
|
|
||||||
} else {
|
|
||||||
for _, ch := range text {
|
|
||||||
if (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') ||
|
|
||||||
ch == '+' || ch == '-' || ch == '@' || ch == '/' || ch == '_' || ch == '.' ||
|
|
||||||
ch == ':' || ch == '#' || ch == '%' || ch == 'π' || ch == '°' {
|
|
||||||
} else {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func isQuotesNeededForObjectName(name string) bool {
|
|
||||||
for _, char := range name {
|
|
||||||
if unicode.IsSpace(char) ||
|
|
||||||
slices.Contains([]rune{'=', '{', '}', '[', ']', ',', ' ', '\t', '\n', '\'', '"', '`', '/'}, char) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func replaceEscapeSymbols(text string) string {
|
|
||||||
replace := []struct{ old, new string }{
|
|
||||||
{old: "\\", new: `\\`},
|
|
||||||
{old: "\t", new: `\t`},
|
|
||||||
{old: "\r", new: `\r`},
|
|
||||||
{old: "\n", new: `\n`},
|
|
||||||
{old: "\"", new: `\"`},
|
|
||||||
}
|
|
||||||
for _, s := range replace {
|
|
||||||
text = strings.ReplaceAll(text, s.old, s.new)
|
|
||||||
}
|
|
||||||
return text
|
|
||||||
}
|
|
||||||
|
|
||||||
func propertyValueToString(tag PropertyName, value any, indent string) string {
|
func propertyValueToString(tag PropertyName, value any, indent string) string {
|
||||||
|
|
||||||
writeString := func(buffer *strings.Builder, text string) string {
|
|
||||||
if isQuotesNeeded(text) {
|
|
||||||
writeStrings(buffer, `"`, replaceEscapeSymbols(text), `"`)
|
|
||||||
} else {
|
|
||||||
buffer.WriteString(text)
|
|
||||||
}
|
|
||||||
return text
|
|
||||||
}
|
|
||||||
|
|
||||||
writeObjectNameString := func(buffer *strings.Builder, text string) string {
|
|
||||||
textEscaped := replaceEscapeSymbols(text)
|
|
||||||
if isQuotesNeededForObjectName(textEscaped) {
|
|
||||||
writeStrings(buffer, `"`, textEscaped, `"`)
|
|
||||||
} else {
|
|
||||||
buffer.WriteString(text)
|
|
||||||
}
|
|
||||||
return text
|
|
||||||
}
|
|
||||||
|
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
case string:
|
case string:
|
||||||
if tag == Text || tag == Title || tag == Summary || isQuotesNeeded(value) {
|
if tag == Text || tag == Title || tag == Summary || isQuotesNeeded(value) {
|
||||||
|
|
@ -652,7 +591,7 @@ func propertyValueToString(tag PropertyName, value any, indent string) string {
|
||||||
lead := "["
|
lead := "["
|
||||||
for _, text := range value {
|
for _, text := range value {
|
||||||
buffer.WriteString(lead)
|
buffer.WriteString(lead)
|
||||||
writeString(buffer, text)
|
writeRuiText(buffer, text, false)
|
||||||
lead = ", "
|
lead = ", "
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -660,7 +599,7 @@ func propertyValueToString(tag PropertyName, value any, indent string) string {
|
||||||
for _, text := range value {
|
for _, text := range value {
|
||||||
buffer.WriteString(indent)
|
buffer.WriteString(indent)
|
||||||
buffer.WriteRune('\t')
|
buffer.WriteRune('\t')
|
||||||
writeString(buffer, text)
|
writeRuiText(buffer, text, false)
|
||||||
buffer.WriteString(",\n")
|
buffer.WriteString(",\n")
|
||||||
}
|
}
|
||||||
buffer.WriteString(indent)
|
buffer.WriteString(indent)
|
||||||
|
|
@ -683,9 +622,9 @@ func propertyValueToString(tag PropertyName, value any, indent string) string {
|
||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
buffer.WriteString(indent)
|
buffer.WriteString(indent)
|
||||||
buffer.WriteRune('\t')
|
buffer.WriteRune('\t')
|
||||||
writeObjectNameString(buffer, key)
|
writeRuiText(buffer, key, true)
|
||||||
buffer.WriteString(" = ")
|
buffer.WriteString(" = ")
|
||||||
writeString(buffer, value[key])
|
writeRuiText(buffer, value[key], false)
|
||||||
buffer.WriteString(",\n")
|
buffer.WriteString(",\n")
|
||||||
}
|
}
|
||||||
buffer.WriteString(indent)
|
buffer.WriteString(indent)
|
||||||
|
|
@ -1006,9 +945,9 @@ func propertyValueToString(tag PropertyName, value any, indent string) string {
|
||||||
for key, listener := range value {
|
for key, listener := range value {
|
||||||
if text, ok := listener.(string); ok && text != "" {
|
if text, ok := listener.(string); ok && text != "" {
|
||||||
buffer.WriteString(indent2)
|
buffer.WriteString(indent2)
|
||||||
writeString(buffer, string(key))
|
writeRuiText(buffer, string(key), true)
|
||||||
buffer.WriteString(" = ")
|
buffer.WriteString(" = ")
|
||||||
writeString(buffer, text)
|
writeRuiText(buffer, text, false)
|
||||||
buffer.WriteString(",\n")
|
buffer.WriteString(",\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1029,7 +968,7 @@ func propertyValueToString(tag PropertyName, value any, indent string) string {
|
||||||
buffer.WriteString("[\n")
|
buffer.WriteString("[\n")
|
||||||
for _, button := range value {
|
for _, button := range value {
|
||||||
buffer.WriteString(lead)
|
buffer.WriteString(lead)
|
||||||
writeString(buffer, button.title)
|
writeRuiText(buffer, button.title, false)
|
||||||
switch button.buttonType {
|
switch button.buttonType {
|
||||||
case CancelButton:
|
case CancelButton:
|
||||||
buffer.WriteString(`, type = cancel`)
|
buffer.WriteString(`, type = cancel`)
|
||||||
|
|
@ -1040,7 +979,7 @@ func propertyValueToString(tag PropertyName, value any, indent string) string {
|
||||||
if button.onClick != nil {
|
if button.onClick != nil {
|
||||||
if text, ok := button.onClick.rawListener().(string); ok {
|
if text, ok := button.onClick.rawListener().(string); ok {
|
||||||
buffer.WriteString(`, click = `)
|
buffer.WriteString(`, click = `)
|
||||||
writeString(buffer, text)
|
writeRuiText(buffer, text, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buffer.WriteString(" },\n")
|
buffer.WriteString(" },\n")
|
||||||
|
|
@ -1062,7 +1001,7 @@ func propertyValueToString(tag PropertyName, value any, indent string) string {
|
||||||
buffer.WriteString("[\n")
|
buffer.WriteString("[\n")
|
||||||
for _, button := range value {
|
for _, button := range value {
|
||||||
buffer.WriteString(lead)
|
buffer.WriteString(lead)
|
||||||
writeString(buffer, button.Title)
|
writeRuiText(buffer, button.Title, false)
|
||||||
switch button.Type {
|
switch button.Type {
|
||||||
case CancelButton:
|
case CancelButton:
|
||||||
buffer.WriteString(`, type = cancel`)
|
buffer.WriteString(`, type = cancel`)
|
||||||
|
|
@ -1073,7 +1012,7 @@ func propertyValueToString(tag PropertyName, value any, indent string) string {
|
||||||
|
|
||||||
if button.Binding != "" {
|
if button.Binding != "" {
|
||||||
buffer.WriteString(`, click = `)
|
buffer.WriteString(`, click = `)
|
||||||
writeString(buffer, button.Binding)
|
writeRuiText(buffer, button.Binding, true)
|
||||||
}
|
}
|
||||||
buffer.WriteString(" },\n")
|
buffer.WriteString(" },\n")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,23 +54,24 @@ func setTransitionProperty(properties Properties, value any) bool {
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|
||||||
case DataNode:
|
case DataValue:
|
||||||
switch value.Type() {
|
switch value.Type() {
|
||||||
case ObjectNode:
|
case ObjectDataValue:
|
||||||
if setObject(value.Object()) {
|
if setObject(value.Object()) {
|
||||||
properties.setRaw(Transition, transitions)
|
properties.setRaw(Transition, transitions)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|
||||||
case ArrayNode:
|
case ArrayDataValue:
|
||||||
for i := range value.ArraySize() {
|
if array := value.Array(); array != nil {
|
||||||
if obj := value.ArrayElement(i).Object(); obj != nil {
|
for element := range array.Elements() {
|
||||||
|
if obj := element.Object(); obj != nil {
|
||||||
if !setObject(obj) {
|
if !setObject(obj) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
notCompatibleType(Transition, value.ArrayElement(i))
|
notCompatibleType(Transition, element)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -81,6 +82,7 @@ func setTransitionProperty(properties Properties, value any) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
notCompatibleType(Transition, value)
|
notCompatibleType(Transition, value)
|
||||||
return false
|
return false
|
||||||
|
|
@ -268,12 +270,17 @@ func viewStyleSet(style Properties, tag PropertyName, value any) []PropertyName
|
||||||
case Params:
|
case Params:
|
||||||
style.setRaw(tag, value)
|
style.setRaw(tag, value)
|
||||||
|
|
||||||
case DataObject:
|
case DataValue:
|
||||||
if params := value.ToParams(); len(params) > 0 {
|
if obj := value.Object(); obj != nil {
|
||||||
|
if params := obj.ToParams(); len(params) > 0 {
|
||||||
style.setRaw(tag, params)
|
style.setRaw(tag, params)
|
||||||
} else {
|
} else {
|
||||||
style.setRaw(tag, nil)
|
style.setRaw(tag, nil)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
notCompatibleType(tag, value)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
|
|
@ -289,23 +296,16 @@ func viewStyleSet(style Properties, tag PropertyName, value any) []PropertyName
|
||||||
case Params:
|
case Params:
|
||||||
style.setRaw(tag, value)
|
style.setRaw(tag, value)
|
||||||
|
|
||||||
case DataObject:
|
case DataValue:
|
||||||
if params := value.ToParams(); len(params) > 0 {
|
|
||||||
style.setRaw(tag, params)
|
|
||||||
} else {
|
|
||||||
style.setRaw(tag, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
case DataNode:
|
|
||||||
switch value.Type() {
|
switch value.Type() {
|
||||||
case TextNode:
|
case TextDataValue:
|
||||||
if text := value.Text(); text != "" {
|
if text := value.String(); text != "" {
|
||||||
style.setRaw(tag, text)
|
style.setRaw(tag, text)
|
||||||
} else {
|
} else {
|
||||||
style.setRaw(tag, nil)
|
style.setRaw(tag, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
case ObjectNode:
|
case ObjectDataValue:
|
||||||
if obj := value.Object(); obj != nil {
|
if obj := value.Object(); obj != nil {
|
||||||
if params := obj.ToParams(); len(params) > 0 {
|
if params := obj.ToParams(); len(params) > 0 {
|
||||||
style.setRaw(tag, params)
|
style.setRaw(tag, params)
|
||||||
|
|
|
||||||
|
|
@ -219,7 +219,7 @@ func (container *viewsContainerData) htmlSubviews(self View, buffer *strings.Bui
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func viewFromTextValue(text string, session Session) View {
|
func viewFromTextDataValue(text string, session Session) View {
|
||||||
if data, err := ParseDataText(text); err == nil {
|
if data, err := ParseDataText(text); err == nil {
|
||||||
if view := CreateViewFromObject(session, data, nil); view != nil {
|
if view := CreateViewFromObject(session, data, nil); view != nil {
|
||||||
return view
|
return view
|
||||||
|
|
@ -299,12 +299,12 @@ func (container *viewsContainerData) setContent(value any) bool {
|
||||||
container.views = value
|
container.views = value
|
||||||
|
|
||||||
case string:
|
case string:
|
||||||
container.views = []View{viewFromTextValue(value, session)}
|
container.views = []View{viewFromTextDataValue(value, session)}
|
||||||
|
|
||||||
case []string:
|
case []string:
|
||||||
views := []View{}
|
views := []View{}
|
||||||
for _, text := range value {
|
for _, text := range value {
|
||||||
views = append(views, viewFromTextValue(text, session))
|
views = append(views, viewFromTextDataValue(text, session))
|
||||||
}
|
}
|
||||||
container.views = views
|
container.views = views
|
||||||
|
|
||||||
|
|
@ -316,7 +316,7 @@ func (container *viewsContainerData) setContent(value any) bool {
|
||||||
views = append(views, v)
|
views = append(views, v)
|
||||||
|
|
||||||
case string:
|
case string:
|
||||||
views = append(views, viewFromTextValue(v, session))
|
views = append(views, viewFromTextDataValue(v, session))
|
||||||
|
|
||||||
default:
|
default:
|
||||||
notCompatibleType(Content, value)
|
notCompatibleType(Content, value)
|
||||||
|
|
@ -332,19 +332,36 @@ func (container *viewsContainerData) setContent(value any) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
case []DataValue:
|
case DataArray:
|
||||||
views := []View{}
|
views := []View{}
|
||||||
for _, data := range value {
|
for data := range value.Elements() {
|
||||||
if data.IsObject() {
|
switch data.Type() {
|
||||||
|
case ObjectDataValue:
|
||||||
if view := CreateViewFromObject(session, data.Object(), nil); view != nil {
|
if view := CreateViewFromObject(session, data.Object(), nil); view != nil {
|
||||||
views = append(views, view)
|
views = append(views, view)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
views = append(views, viewFromTextValue(data.Value(), session))
|
case TextDataValue:
|
||||||
|
views = append(views, viewFromTextDataValue(data.String(), session))
|
||||||
|
|
||||||
|
case ArrayDataValue:
|
||||||
|
// not supported
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
container.views = views
|
container.views = views
|
||||||
|
|
||||||
|
case DataValue:
|
||||||
|
switch value.Type() {
|
||||||
|
case ObjectDataValue:
|
||||||
|
return container.setContent(value.Object())
|
||||||
|
|
||||||
|
case TextDataValue:
|
||||||
|
return container.setContent(value.String())
|
||||||
|
|
||||||
|
case ArrayDataValue:
|
||||||
|
return container.setContent(value.Array())
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
notCompatibleType(Content, value)
|
notCompatibleType(Content, value)
|
||||||
return false
|
return false
|
||||||
|
|
|
||||||
|
|
@ -270,7 +270,7 @@ func (bridge *wasmBridge) htmlPropertyValue(htmlID, name string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bridge *wasmBridge) answerReceived(answer DataObject) {
|
func (bridge *wasmBridge) answerReceived(answer DataObject) {
|
||||||
if text, ok := answer.PropertyValue("answerID"); ok {
|
if text, ok := answer.PropertyText("answerID"); ok {
|
||||||
if id, err := strconv.Atoi(text); err == nil {
|
if id, err := strconv.Atoi(text); err == nil {
|
||||||
if chanel, ok := bridge.answer[id]; ok {
|
if chanel, ok := bridge.answer[id]; ok {
|
||||||
chanel <- answer
|
chanel <- answer
|
||||||
|
|
|
||||||
|
|
@ -423,7 +423,7 @@ func (bridge *webBridge) canvasTextMetrics(htmlID, font, text string) TextMetric
|
||||||
|
|
||||||
func (bridge *webBridge) htmlPropertyValue(htmlID, name string) string {
|
func (bridge *webBridge) htmlPropertyValue(htmlID, name string) string {
|
||||||
if data, ok := bridge.remoteValue("getPropertyValue", htmlID, name); ok {
|
if data, ok := bridge.remoteValue("getPropertyValue", htmlID, name); ok {
|
||||||
if value, ok := data.PropertyValue("value"); ok {
|
if value, ok := data.PropertyText("value"); ok {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -431,7 +431,7 @@ func (bridge *webBridge) htmlPropertyValue(htmlID, name string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bridge *webBridge) answerReceived(answer DataObject) {
|
func (bridge *webBridge) answerReceived(answer DataObject) {
|
||||||
if text, ok := answer.PropertyValue("answerID"); ok {
|
if text, ok := answer.PropertyText("answerID"); ok {
|
||||||
if id, err := strconv.Atoi(text); err == nil {
|
if id, err := strconv.Atoi(text); err == nil {
|
||||||
if chanel, ok := bridge.answer[id]; ok {
|
if chanel, ok := bridge.answer[id]; ok {
|
||||||
chanel <- answer
|
chanel <- answer
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue