Add a listener for changing a property value

This commit is contained in:
anoshenko 2021-11-20 11:15:28 +03:00
parent 584983b818
commit 7e2804f002
30 changed files with 1024 additions and 555 deletions

View File

@ -53,6 +53,7 @@ func (canvasView *canvasViewData) remove(tag string) {
if tag == DrawFunction { if tag == DrawFunction {
canvasView.drawer = nil canvasView.drawer = nil
canvasView.Redraw() canvasView.Redraw()
canvasView.propertyChangedEvent(tag)
} else { } else {
canvasView.viewData.remove(tag) canvasView.viewData.remove(tag)
} }
@ -73,6 +74,7 @@ func (canvasView *canvasViewData) set(tag string, value interface{}) bool {
return false return false
} }
canvasView.Redraw() canvasView.Redraw()
canvasView.propertyChangedEvent(tag)
return true return true
} }

View File

@ -57,13 +57,16 @@ func (button *checkboxData) Get(tag string) interface{} {
} }
func (button *checkboxData) Set(tag string, value interface{}) bool { func (button *checkboxData) Set(tag string, value interface{}) bool {
switch strings.ToLower(tag) { return button.set(tag, value)
}
func (button *checkboxData) set(tag string, value interface{}) bool {
switch tag {
case CheckboxChangedEvent: case CheckboxChangedEvent:
ok := button.setChangedListener(value) if !button.setChangedListener(value) {
if !ok {
notCompatibleType(tag, value) notCompatibleType(tag, value)
return false
} }
return ok
case Checked: case Checked:
oldChecked := button.checked() oldChecked := button.checked()
@ -76,46 +79,60 @@ func (button *checkboxData) Set(tag string, value interface{}) bool {
button.changedCheckboxState(checked) button.changedCheckboxState(checked)
} }
} }
return true
case CheckboxHorizontalAlign, CheckboxVerticalAlign: case CheckboxHorizontalAlign, CheckboxVerticalAlign:
if button.setEnumProperty(tag, value, enumProperties[tag].values) { if !button.setEnumProperty(tag, value, enumProperties[tag].values) {
if button.created { return false
htmlID := button.htmlID() }
updateCSSStyle(htmlID, button.session) if button.created {
updateInnerHTML(htmlID, button.session) htmlID := button.htmlID()
} updateCSSStyle(htmlID, button.session)
return true updateInnerHTML(htmlID, button.session)
} }
return false
case VerticalAlign: case VerticalAlign:
if button.setEnumProperty(tag, value, enumProperties[tag].values) { if !button.setEnumProperty(tag, value, enumProperties[tag].values) {
if button.created { return false
updateCSSProperty(button.htmlID()+"content", "align-items", button.cssVerticalAlign(), button.session) }
} if button.created {
return true updateCSSProperty(button.htmlID()+"content", "align-items", button.cssVerticalAlign(), button.session)
} }
return false
case HorizontalAlign: case HorizontalAlign:
if button.setEnumProperty(tag, value, enumProperties[tag].values) { if !button.setEnumProperty(tag, value, enumProperties[tag].values) {
if button.created { return false
updateCSSProperty(button.htmlID()+"content", "justify-items", button.cssHorizontalAlign(), button.session) }
} if button.created {
return true updateCSSProperty(button.htmlID()+"content", "justify-items", button.cssHorizontalAlign(), button.session)
} }
return false
case CellVerticalAlign, CellHorizontalAlign, CellWidth, CellHeight: case CellVerticalAlign, CellHorizontalAlign, CellWidth, CellHeight:
return false return false
default:
return button.viewsContainerData.set(tag, value)
} }
return button.viewsContainerData.Set(tag, value) button.propertyChangedEvent(tag)
return true
} }
func (button *checkboxData) Remove(tag string) { func (button *checkboxData) Remove(tag string) {
switch strings.ToLower(tag) { button.remove(strings.ToLower(tag))
}
func (button *checkboxData) remove(tag string) {
switch tag {
case ClickEvent:
if !button.viewsContainerData.set(ClickEvent, checkboxClickListener) {
delete(button.properties, tag)
}
case KeyDownEvent:
if !button.viewsContainerData.set(KeyDownEvent, checkboxKeyListener) {
delete(button.properties, tag)
}
case CheckboxChangedEvent: case CheckboxChangedEvent:
if len(button.checkedListeners) > 0 { if len(button.checkedListeners) > 0 {
button.checkedListeners = []func(Checkbox, bool){} button.checkedListeners = []func(Checkbox, bool){}
@ -124,27 +141,35 @@ func (button *checkboxData) Remove(tag string) {
case Checked: case Checked:
oldChecked := button.checked() oldChecked := button.checked()
delete(button.properties, tag) delete(button.properties, tag)
if oldChecked { if button.created && oldChecked {
button.changedCheckboxState(false) button.changedCheckboxState(false)
} }
case CheckboxHorizontalAlign, CheckboxVerticalAlign: case CheckboxHorizontalAlign, CheckboxVerticalAlign:
delete(button.properties, tag) delete(button.properties, tag)
htmlID := button.htmlID() if button.created {
updateCSSStyle(htmlID, button.session) htmlID := button.htmlID()
updateInnerHTML(htmlID, button.session) updateCSSStyle(htmlID, button.session)
updateInnerHTML(htmlID, button.session)
}
case VerticalAlign: case VerticalAlign:
delete(button.properties, tag) delete(button.properties, tag)
updateCSSProperty(button.htmlID()+"content", "align-items", button.cssVerticalAlign(), button.session) if button.created {
updateCSSProperty(button.htmlID()+"content", "align-items", button.cssVerticalAlign(), button.session)
}
case HorizontalAlign: case HorizontalAlign:
delete(button.properties, tag) delete(button.properties, tag)
updateCSSProperty(button.htmlID()+"content", "justify-items", button.cssHorizontalAlign(), button.session) if button.created {
updateCSSProperty(button.htmlID()+"content", "justify-items", button.cssHorizontalAlign(), button.session)
}
default: default:
button.viewsContainerData.Remove(tag) button.viewsContainerData.remove(tag)
return
} }
button.propertyChangedEvent(tag)
} }
func (button *checkboxData) checked() bool { func (button *checkboxData) checked() bool {

View File

@ -56,7 +56,10 @@ func (picker *colorPickerData) Remove(tag string) {
func (picker *colorPickerData) remove(tag string) { func (picker *colorPickerData) remove(tag string) {
switch tag { switch tag {
case ColorChangedEvent: case ColorChangedEvent:
picker.colorChangedListeners = []func(ColorPicker, Color){} if len(picker.colorChangedListeners) > 0 {
picker.colorChangedListeners = []func(ColorPicker, Color){}
picker.propertyChangedEvent(tag)
}
case ColorPickerValue: case ColorPickerValue:
oldColor := GetColorPickerValue(picker, "") oldColor := GetColorPickerValue(picker, "")
@ -131,15 +134,13 @@ func (picker *colorPickerData) set(tag string, value interface{}) bool {
} }
picker.colorChangedListeners = listeners picker.colorChangedListeners = listeners
} }
picker.propertyChangedEvent(tag)
return true return true
case ColorPickerValue: case ColorPickerValue:
oldColor := GetColorPickerValue(picker, "") oldColor := GetColorPickerValue(picker, "")
if picker.setColorProperty(ColorPickerValue, value) { if picker.setColorProperty(ColorPickerValue, value) {
newValue := GetColorPickerValue(picker, "") picker.colorChanged(oldColor)
if oldColor != newValue {
picker.colorChanged(oldColor)
}
return true return true
} }
@ -150,12 +151,14 @@ func (picker *colorPickerData) set(tag string, value interface{}) bool {
} }
func (picker *colorPickerData) colorChanged(oldColor Color) { func (picker *colorPickerData) colorChanged(oldColor Color) {
newColor := GetColorPickerValue(picker, "") if newColor := GetColorPickerValue(picker, ""); oldColor != newColor {
if oldColor != newColor { if picker.created {
picker.session.runScript(fmt.Sprintf(`setInputValue('%s', '%s')`, picker.htmlID(), newColor.rgbString())) picker.session.runScript(fmt.Sprintf(`setInputValue('%s', '%s')`, picker.htmlID(), newColor.rgbString()))
}
for _, listener := range picker.colorChangedListeners { for _, listener := range picker.colorChangedListeners {
listener(picker, newColor) listener(picker, newColor)
} }
picker.propertyChangedEvent(ColorTag)
} }
} }
@ -188,7 +191,7 @@ func (picker *colorPickerData) htmlProperties(self View, buffer *strings.Builder
} }
func (picker *colorPickerData) htmlDisabledProperties(self View, buffer *strings.Builder) { func (picker *colorPickerData) htmlDisabledProperties(self View, buffer *strings.Builder) {
if IsDisabled(self) { if IsDisabled(self, "") {
buffer.WriteString(` disabled`) buffer.WriteString(` disabled`)
} }
picker.viewData.htmlDisabledProperties(self, buffer) picker.viewData.htmlDisabledProperties(self, buffer)

View File

@ -82,12 +82,14 @@ func (columnLayout *columnLayoutData) Remove(tag string) {
func (columnLayout *columnLayoutData) remove(tag string) { func (columnLayout *columnLayoutData) remove(tag string) {
columnLayout.viewsContainerData.remove(tag) columnLayout.viewsContainerData.remove(tag)
switch tag { if columnLayout.created {
case ColumnCount, ColumnWidth, ColumnGap: switch tag {
updateCSSProperty(columnLayout.htmlID(), tag, "", columnLayout.Session()) case ColumnCount, ColumnWidth, ColumnGap:
updateCSSProperty(columnLayout.htmlID(), tag, "", columnLayout.Session())
case ColumnSeparator: case ColumnSeparator:
updateCSSProperty(columnLayout.htmlID(), "column-rule", "", columnLayout.Session()) updateCSSProperty(columnLayout.htmlID(), "column-rule", "", columnLayout.Session())
}
} }
} }
@ -101,22 +103,11 @@ func (columnLayout *columnLayoutData) set(tag string, value interface{}) bool {
return true return true
} }
switch tag { if !columnLayout.viewsContainerData.set(tag, value) {
case ColumnCount:
if columnLayout.setIntProperty(tag, value) {
session := columnLayout.Session()
if count, ok := intProperty(columnLayout, tag, session, 0); ok && count > 0 {
updateCSSProperty(columnLayout.htmlID(), tag, strconv.Itoa(count), session)
} else {
updateCSSProperty(columnLayout.htmlID(), tag, "auto", session)
}
return true
}
return false return false
} }
ok := columnLayout.viewsContainerData.set(tag, value) if columnLayout.created {
if ok {
switch tag { switch tag {
case ColumnSeparator: case ColumnSeparator:
css := "" css := ""
@ -126,9 +117,17 @@ func (columnLayout *columnLayoutData) set(tag string, value interface{}) bool {
css = separator.cssValue(columnLayout.Session()) css = separator.cssValue(columnLayout.Session())
} }
updateCSSProperty(columnLayout.htmlID(), "column-rule", css, session) updateCSSProperty(columnLayout.htmlID(), "column-rule", css, session)
case ColumnCount:
session := columnLayout.Session()
if count, ok := intProperty(columnLayout, tag, session, 0); ok && count > 0 {
updateCSSProperty(columnLayout.htmlID(), tag, strconv.Itoa(count), session)
} else {
updateCSSProperty(columnLayout.htmlID(), tag, "auto", session)
}
} }
} }
return ok return true
} }
// GetColumnCount returns int value which specifies number of columns into which the content of // GetColumnCount returns int value which specifies number of columns into which the content of

View File

@ -68,6 +68,10 @@ func (customView *CustomViewData) SetAnimated(tag string, value interface{}, ani
return customView.superView.SetAnimated(tag, value, animation) return customView.superView.SetAnimated(tag, value, animation)
} }
func (customView *CustomViewData) SetChangeListener(tag string, listener func(View, string)) {
customView.superView.SetChangeListener(tag, listener)
}
// Remove removes the property with name defined by the argument // Remove removes the property with name defined by the argument
func (customView *CustomViewData) Remove(tag string) { func (customView *CustomViewData) Remove(tag string) {
customView.superView.Remove(tag) customView.superView.Remove(tag)

View File

@ -63,28 +63,47 @@ func (picker *datePickerData) remove(tag string) {
case DateChangedEvent: case DateChangedEvent:
if len(picker.dateChangedListeners) > 0 { if len(picker.dateChangedListeners) > 0 {
picker.dateChangedListeners = []func(DatePicker, time.Time){} picker.dateChangedListeners = []func(DatePicker, time.Time){}
picker.propertyChangedEvent(tag)
} }
return
case DatePickerMin: case DatePickerMin:
delete(picker.properties, DatePickerMin) delete(picker.properties, DatePickerMin)
removeProperty(picker.htmlID(), Min, picker.session) if picker.created {
removeProperty(picker.htmlID(), Min, picker.session)
}
case DatePickerMax: case DatePickerMax:
delete(picker.properties, DatePickerMax) delete(picker.properties, DatePickerMax)
removeProperty(picker.htmlID(), Max, picker.session) if picker.created {
removeProperty(picker.htmlID(), Max, picker.session)
}
case DatePickerStep: case DatePickerStep:
delete(picker.properties, DatePickerMax) delete(picker.properties, DatePickerMax)
removeProperty(picker.htmlID(), Step, picker.session) if picker.created {
removeProperty(picker.htmlID(), Step, picker.session)
}
case DatePickerValue: case DatePickerValue:
delete(picker.properties, DatePickerValue) if _, ok := picker.properties[DatePickerValue]; ok {
updateProperty(picker.htmlID(), Value, time.Now().Format(dateFormat), picker.session) delete(picker.properties, DatePickerValue)
date := GetDatePickerValue(picker, "")
if picker.created {
picker.session.runScript(fmt.Sprintf(`setInputValue('%s', '%s')`, picker.htmlID(), date.Format(dateFormat)))
}
for _, listener := range picker.dateChangedListeners {
listener(picker, date)
}
} else {
return
}
default: default:
picker.viewData.remove(tag) picker.viewData.remove(tag)
picker.propertyChanged(tag) return
} }
picker.propertyChangedEvent(tag)
} }
func (picker *datePickerData) Set(tag string, value interface{}) bool { func (picker *datePickerData) Set(tag string, value interface{}) bool {
@ -98,7 +117,6 @@ func (picker *datePickerData) set(tag string, value interface{}) bool {
} }
setTimeValue := func(tag string) (time.Time, bool) { setTimeValue := func(tag string) (time.Time, bool) {
//old, oldOK := getDateProperty(picker, tag, shortTag)
switch value := value.(type) { switch value := value.(type) {
case time.Time: case time.Time:
picker.properties[tag] = value picker.properties[tag] = value
@ -122,7 +140,10 @@ func (picker *datePickerData) set(tag string, value interface{}) bool {
old, oldOK := getDateProperty(picker, DatePickerMin, Min) old, oldOK := getDateProperty(picker, DatePickerMin, Min)
if date, ok := setTimeValue(DatePickerMin); ok { if date, ok := setTimeValue(DatePickerMin); ok {
if !oldOK || date != old { if !oldOK || date != old {
updateProperty(picker.htmlID(), Min, date.Format(dateFormat), picker.session) if picker.created {
updateProperty(picker.htmlID(), Min, date.Format(dateFormat), picker.session)
}
picker.propertyChangedEvent(tag)
} }
return true return true
} }
@ -131,7 +152,10 @@ func (picker *datePickerData) set(tag string, value interface{}) bool {
old, oldOK := getDateProperty(picker, DatePickerMax, Max) old, oldOK := getDateProperty(picker, DatePickerMax, Max)
if date, ok := setTimeValue(DatePickerMax); ok { if date, ok := setTimeValue(DatePickerMax); ok {
if !oldOK || date != old { if !oldOK || date != old {
updateProperty(picker.htmlID(), Max, date.Format(dateFormat), picker.session) if picker.created {
updateProperty(picker.htmlID(), Max, date.Format(dateFormat), picker.session)
}
picker.propertyChangedEvent(tag)
} }
return true return true
} }
@ -139,13 +163,15 @@ func (picker *datePickerData) set(tag string, value interface{}) bool {
case DatePickerStep: case DatePickerStep:
oldStep := GetDatePickerStep(picker, "") oldStep := GetDatePickerStep(picker, "")
if picker.setIntProperty(DatePickerStep, value) { if picker.setIntProperty(DatePickerStep, value) {
step := GetDatePickerStep(picker, "") if step := GetDatePickerStep(picker, ""); oldStep != step {
if oldStep != step { if picker.created {
if step > 0 { if step > 0 {
updateProperty(picker.htmlID(), Step, strconv.Itoa(step), picker.session) updateProperty(picker.htmlID(), Step, strconv.Itoa(step), picker.session)
} else { } else {
removeProperty(picker.htmlID(), Step, picker.session) removeProperty(picker.htmlID(), Step, picker.session)
}
} }
picker.propertyChangedEvent(tag)
} }
return true return true
} }
@ -153,11 +179,14 @@ func (picker *datePickerData) set(tag string, value interface{}) bool {
case DatePickerValue: case DatePickerValue:
oldDate := GetDatePickerValue(picker, "") oldDate := GetDatePickerValue(picker, "")
if date, ok := setTimeValue(DatePickerMax); ok { if date, ok := setTimeValue(DatePickerMax); ok {
picker.session.runScript(fmt.Sprintf(`setInputValue('%s', '%s')`, picker.htmlID(), date.Format(dateFormat)))
if date != oldDate { if date != oldDate {
if picker.created {
picker.session.runScript(fmt.Sprintf(`setInputValue('%s', '%s')`, picker.htmlID(), date.Format(dateFormat)))
}
for _, listener := range picker.dateChangedListeners { for _, listener := range picker.dateChangedListeners {
listener(picker, date) listener(picker, date)
} }
picker.propertyChangedEvent(tag)
} }
return true return true
} }
@ -214,13 +243,11 @@ func (picker *datePickerData) set(tag string, value interface{}) bool {
} }
picker.dateChangedListeners = listeners picker.dateChangedListeners = listeners
} }
picker.propertyChangedEvent(tag)
return true return true
default: default:
if picker.viewData.set(tag, value) { return picker.viewData.set(tag, value)
picker.propertyChanged(tag)
return true
}
} }
return false return false
} }
@ -274,7 +301,7 @@ func (picker *datePickerData) htmlProperties(self View, buffer *strings.Builder)
} }
func (picker *datePickerData) htmlDisabledProperties(self View, buffer *strings.Builder) { func (picker *datePickerData) htmlDisabledProperties(self View, buffer *strings.Builder) {
if IsDisabled(self) { if IsDisabled(self, "") {
buffer.WriteString(` disabled`) buffer.WriteString(` disabled`)
} }
picker.viewData.htmlDisabledProperties(self, buffer) picker.viewData.htmlDisabledProperties(self, buffer)

View File

@ -57,14 +57,24 @@ func createTextStyleDemo(session rui.Session) rui.View {
return nil return nil
} }
rui.Set(view, "textStyleFont", rui.DropDownEvent, func(number int) { rui.SetChangeListener(view, "textStyleFont", rui.Current, func(v rui.View, tag string) {
fonts := []string{"", "serif", "sans-serif", "\"Courier new\", monospace", "cursive", "fantasy"} fonts := []string{"", "serif", "sans-serif", "\"Courier new\", monospace", "cursive", "fantasy"}
if number > 0 && number < len(fonts) { if number := rui.GetDropDownCurrent(v, ""); number > 0 && number < len(fonts) {
rui.Set(view, "textStyleText", rui.FontName, fonts[number]) rui.Set(view, "textStyleText", rui.FontName, fonts[number])
} else { } else {
rui.Set(view, "textStyleText", rui.FontName, nil) rui.Set(view, "textStyleText", rui.FontName, nil)
} }
}) })
/*
rui.Set(view, "textStyleFont", rui.DropDownEvent, func(number int) {
fonts := []string{"", "serif", "sans-serif", "\"Courier new\", monospace", "cursive", "fantasy"}
if number > 0 && number < len(fonts) {
rui.Set(view, "textStyleText", rui.FontName, fonts[number])
} else {
rui.Set(view, "textStyleText", rui.FontName, nil)
}
})
*/
rui.Set(view, "textStyleSize", rui.DropDownEvent, func(number int) { rui.Set(view, "textStyleSize", rui.DropDownEvent, func(number int) {
sizes := []string{"1em", "14pt", "12px", "1.5em"} sizes := []string{"1em", "14pt", "12px", "1.5em"}

View File

@ -2,6 +2,8 @@ package rui
import "strings" import "strings"
// TODO Expanded event
const ( const (
// Summary is the constant for the "summary" property tag. // Summary is the constant for the "summary" property tag.
// The contents of the "summary" property are used as the label for the disclosure widget. // The contents of the "summary" property are used as the label for the disclosure widget.
@ -45,18 +47,14 @@ func (detailsView *detailsViewData) Remove(tag string) {
} }
func (detailsView *detailsViewData) remove(tag string) { func (detailsView *detailsViewData) remove(tag string) {
if _, ok := detailsView.properties[tag]; ok { detailsView.viewsContainerData.remove(tag)
if detailsView.created {
switch tag { switch tag {
case Summary: case Summary:
delete(detailsView.properties, tag)
updateInnerHTML(detailsView.htmlID(), detailsView.Session()) updateInnerHTML(detailsView.htmlID(), detailsView.Session())
case Expanded: case Expanded:
delete(detailsView.properties, tag)
removeProperty(detailsView.htmlID(), "open", detailsView.Session()) removeProperty(detailsView.htmlID(), "open", detailsView.Session())
default:
detailsView.viewsContainerData.remove(tag)
} }
} }
} }
@ -66,6 +64,11 @@ func (detailsView *detailsViewData) Set(tag string, value interface{}) bool {
} }
func (detailsView *detailsViewData) set(tag string, value interface{}) bool { func (detailsView *detailsViewData) set(tag string, value interface{}) bool {
if value == nil {
detailsView.remove(tag)
return true
}
switch tag { switch tag {
case Summary: case Summary:
switch value := value.(type) { switch value := value.(type) {
@ -86,23 +89,29 @@ func (detailsView *detailsViewData) set(tag string, value interface{}) bool {
notCompatibleType(tag, value) notCompatibleType(tag, value)
return false return false
} }
updateInnerHTML(detailsView.htmlID(), detailsView.Session()) if detailsView.created {
return true updateInnerHTML(detailsView.htmlID(), detailsView.Session())
}
case Expanded: case Expanded:
if detailsView.setBoolProperty(tag, value) { if !detailsView.setBoolProperty(tag, value) {
notCompatibleType(tag, value)
return false
}
if detailsView.created {
if IsDetailsExpanded(detailsView, "") { if IsDetailsExpanded(detailsView, "") {
updateProperty(detailsView.htmlID(), "open", "", detailsView.Session()) updateProperty(detailsView.htmlID(), "open", "", detailsView.Session())
} else { } else {
removeProperty(detailsView.htmlID(), "open", detailsView.Session()) removeProperty(detailsView.htmlID(), "open", detailsView.Session())
} }
return true
} }
notCompatibleType(tag, value)
return false default:
return detailsView.viewsContainerData.Set(tag, value)
} }
return detailsView.viewsContainerData.Set(tag, value) detailsView.propertyChangedEvent(tag)
return true
} }
func (detailsView *detailsViewData) Get(tag string) interface{} { func (detailsView *detailsViewData) Get(tag string) interface{} {

View File

@ -48,19 +48,31 @@ func (list *dropDownListData) remove(tag string) {
case Items: case Items:
if len(list.items) > 0 { if len(list.items) > 0 {
list.items = []string{} list.items = []string{}
updateInnerHTML(list.htmlID(), list.session) if list.created {
updateInnerHTML(list.htmlID(), list.session)
}
list.propertyChangedEvent(tag)
} }
case Current:
list.set(Current, 0)
case DropDownEvent: case DropDownEvent:
if len(list.dropDownListener) > 0 { if len(list.dropDownListener) > 0 {
list.dropDownListener = []func(DropDownList, int){} list.dropDownListener = []func(DropDownList, int){}
list.propertyChangedEvent(tag)
}
case Current:
oldCurrent := GetDropDownCurrent(list, "")
delete(list.properties, Current)
if oldCurrent != 0 {
if list.created {
list.session.runScript(fmt.Sprintf(`selectDropDownListItem('%s', %d)`, list.htmlID(), 0))
}
list.onSelectedItemChanged(0)
} }
default: default:
list.viewData.remove(tag) list.viewData.remove(tag)
return
} }
} }
@ -73,23 +85,22 @@ func (list *dropDownListData) set(tag string, value interface{}) bool {
case Items: case Items:
return list.setItems(value) return list.setItems(value)
case DropDownEvent:
return list.setDropDownListener(value)
case Current: case Current:
oldCurrent := GetDropDownCurrent(list, "") oldCurrent := GetDropDownCurrent(list, "")
if !list.setIntProperty(Current, value) { if !list.setIntProperty(Current, value) {
return false return false
} }
if !list.session.ignoreViewUpdates() { if current := GetDropDownCurrent(list, ""); oldCurrent != current {
current := GetDropDownCurrent(list, "") if list.created {
if oldCurrent != current {
list.session.runScript(fmt.Sprintf(`selectDropDownListItem('%s', %d)`, list.htmlID(), current)) list.session.runScript(fmt.Sprintf(`selectDropDownListItem('%s', %d)`, list.htmlID(), current))
list.onSelectedItemChanged(current)
} }
list.onSelectedItemChanged(current)
} }
return true return true
case DropDownEvent:
return list.setDropDownListener(value)
} }
return list.viewData.set(tag, value) return list.viewData.set(tag, value)
@ -160,9 +171,11 @@ func (list *dropDownListData) setItems(value interface{}) bool {
return false return false
} }
if !list.session.ignoreViewUpdates() { if list.created {
updateInnerHTML(list.htmlID(), list.session) updateInnerHTML(list.htmlID(), list.session)
} }
list.propertyChangedEvent(Items)
return true return true
} }
@ -170,17 +183,14 @@ func (list *dropDownListData) setDropDownListener(value interface{}) bool {
switch value := value.(type) { switch value := value.(type) {
case func(DropDownList, int): case func(DropDownList, int):
list.dropDownListener = []func(DropDownList, int){value} list.dropDownListener = []func(DropDownList, int){value}
return true
case func(int): case func(int):
list.dropDownListener = []func(DropDownList, int){func(list DropDownList, index int) { list.dropDownListener = []func(DropDownList, int){func(list DropDownList, index int) {
value(index) value(index)
}} }}
return true
case []func(DropDownList, int): case []func(DropDownList, int):
list.dropDownListener = value list.dropDownListener = value
return true
case []func(int): case []func(int):
listeners := make([]func(DropDownList, int), len(value)) listeners := make([]func(DropDownList, int), len(value))
@ -194,7 +204,6 @@ func (list *dropDownListData) setDropDownListener(value interface{}) bool {
} }
} }
list.dropDownListener = listeners list.dropDownListener = listeners
return true
case []interface{}: case []interface{}:
listeners := make([]func(DropDownList, int), len(value)) listeners := make([]func(DropDownList, int), len(value))
@ -216,13 +225,16 @@ func (list *dropDownListData) setDropDownListener(value interface{}) bool {
notCompatibleType(DropDownEvent, value) notCompatibleType(DropDownEvent, value)
return false return false
} }
list.dropDownListener = listeners
} }
return true list.dropDownListener = listeners
default:
notCompatibleType(DropDownEvent, value)
return false
} }
notCompatibleType(DropDownEvent, value) list.propertyChangedEvent(DropDownEvent)
return false return true
} }
func (list *dropDownListData) Get(tag string) interface{} { func (list *dropDownListData) Get(tag string) interface{} {
@ -280,7 +292,7 @@ func (list *dropDownListData) htmlProperties(self View, buffer *strings.Builder)
func (list *dropDownListData) htmlDisabledProperties(self View, buffer *strings.Builder) { func (list *dropDownListData) htmlDisabledProperties(self View, buffer *strings.Builder) {
list.viewData.htmlDisabledProperties(self, buffer) list.viewData.htmlDisabledProperties(self, buffer)
if IsDisabled(list) { if IsDisabled(list, "") {
buffer.WriteString(`disabled`) buffer.WriteString(`disabled`)
} }
} }
@ -289,6 +301,7 @@ func (list *dropDownListData) onSelectedItemChanged(number int) {
for _, listener := range list.dropDownListener { for _, listener := range list.dropDownListener {
listener(list, number) listener(list, number)
} }
list.propertyChangedEvent(Current)
} }
func (list *dropDownListData) handleCommand(self View, command string, data DataObject) bool { func (list *dropDownListData) handleCommand(self View, command string, data DataObject) bool {

View File

@ -84,63 +84,98 @@ func (edit *editViewData) Remove(tag string) {
} }
func (edit *editViewData) remove(tag string) { func (edit *editViewData) remove(tag string) {
if _, ok := edit.properties[tag]; ok { _, exists := edit.properties[tag]
switch tag { switch tag {
case Hint: case Hint:
if exists {
delete(edit.properties, Hint) delete(edit.properties, Hint)
removeProperty(edit.htmlID(), "placeholder", edit.session) if edit.created {
removeProperty(edit.htmlID(), "placeholder", edit.session)
case MaxLength:
delete(edit.properties, MaxLength)
removeProperty(edit.htmlID(), "maxlength", edit.session)
case ReadOnly, Spellcheck:
delete(edit.properties, tag)
updateBoolProperty(edit.htmlID(), tag, false, edit.session)
case EditTextChangedEvent:
if len(edit.textChangeListeners) > 0 {
edit.textChangeListeners = []func(EditView, string){}
} }
edit.propertyChangedEvent(tag)
}
case Text: case MaxLength:
if exists {
delete(edit.properties, MaxLength)
if edit.created {
removeProperty(edit.htmlID(), "maxlength", edit.session)
}
edit.propertyChangedEvent(tag)
}
case ReadOnly, Spellcheck:
if exists {
delete(edit.properties, tag)
if edit.created {
updateBoolProperty(edit.htmlID(), tag, false, edit.session)
}
edit.propertyChangedEvent(tag)
}
case EditTextChangedEvent:
if len(edit.textChangeListeners) > 0 {
edit.textChangeListeners = []func(EditView, string){}
edit.propertyChangedEvent(tag)
}
case Text:
if exists {
oldText := GetText(edit, "") oldText := GetText(edit, "")
delete(edit.properties, tag) delete(edit.properties, tag)
if oldText != "" { if oldText != "" {
edit.textChanged("") edit.textChanged("")
edit.session.runScript(fmt.Sprintf(`setInputValue('%s', '%s')`, edit.htmlID(), "")) if edit.created {
edit.session.runScript(fmt.Sprintf(`setInputValue('%s', '%s')`, edit.htmlID(), ""))
}
} }
}
case EditViewPattern: case EditViewPattern:
if exists {
oldText := GetEditViewPattern(edit, "") oldText := GetEditViewPattern(edit, "")
delete(edit.properties, tag) delete(edit.properties, tag)
if oldText != "" { if oldText != "" {
removeProperty(edit.htmlID(), Pattern, edit.session) if edit.created {
removeProperty(edit.htmlID(), Pattern, edit.session)
}
edit.propertyChangedEvent(tag)
} }
}
case EditViewType: case EditViewType:
if exists {
oldType := GetEditViewType(edit, "") oldType := GetEditViewType(edit, "")
delete(edit.properties, tag) delete(edit.properties, tag)
if oldType != 0 { if oldType != 0 {
updateInnerHTML(edit.parentHTMLID(), edit.session) if edit.created {
updateInnerHTML(edit.parentHTMLID(), edit.session)
}
edit.propertyChangedEvent(tag)
} }
}
case Wrap: case Wrap:
if exists {
oldWrap := IsEditViewWrap(edit, "") oldWrap := IsEditViewWrap(edit, "")
delete(edit.properties, tag) delete(edit.properties, tag)
if GetEditViewType(edit, "") == MultiLineText { if GetEditViewType(edit, "") == MultiLineText {
if wrap := IsEditViewWrap(edit, ""); wrap != oldWrap { if wrap := IsEditViewWrap(edit, ""); wrap != oldWrap {
if wrap { if edit.created {
updateProperty(edit.htmlID(), "wrap", "soft", edit.session) if wrap {
} else { updateProperty(edit.htmlID(), "wrap", "soft", edit.session)
updateProperty(edit.htmlID(), "wrap", "off", edit.session) } else {
updateProperty(edit.htmlID(), "wrap", "off", edit.session)
}
} }
edit.propertyChangedEvent(tag)
} }
} }
default:
edit.viewData.remove(tag)
} }
default:
edit.viewData.remove(tag)
return
} }
} }
@ -161,14 +196,16 @@ func (edit *editViewData) set(tag string, value interface{}) bool {
edit.properties[Text] = text edit.properties[Text] = text
if text = GetText(edit, ""); oldText != text { if text = GetText(edit, ""); oldText != text {
edit.textChanged(text) edit.textChanged(text)
if GetEditViewType(edit, "") == MultiLineText { if edit.created {
updateInnerHTML(edit.htmlID(), edit.Session()) if GetEditViewType(edit, "") == MultiLineText {
} else { updateInnerHTML(edit.htmlID(), edit.Session())
text = strings.ReplaceAll(text, `"`, `\"`) } else {
text = strings.ReplaceAll(text, `'`, `\'`) text = strings.ReplaceAll(text, `"`, `\"`)
text = strings.ReplaceAll(text, "\n", `\n`) text = strings.ReplaceAll(text, `'`, `\'`)
text = strings.ReplaceAll(text, "\r", `\r`) text = strings.ReplaceAll(text, "\n", `\n`)
edit.session.runScript(fmt.Sprintf(`setInputValue('%s', '%s')`, edit.htmlID(), text)) text = strings.ReplaceAll(text, "\r", `\r`)
edit.session.runScript(fmt.Sprintf(`setInputValue('%s', '%s')`, edit.htmlID(), text))
}
} }
} }
return true return true
@ -180,11 +217,14 @@ func (edit *editViewData) set(tag string, value interface{}) bool {
if text, ok := value.(string); ok { if text, ok := value.(string); ok {
edit.properties[Hint] = text edit.properties[Hint] = text
if text = GetHint(edit, ""); oldText != text { if text = GetHint(edit, ""); oldText != text {
if text != "" { if edit.created {
updateProperty(edit.htmlID(), "placeholder", text, edit.session) if text != "" {
} else { updateProperty(edit.htmlID(), "placeholder", text, edit.session)
removeProperty(edit.htmlID(), "placeholder", edit.session) } else {
removeProperty(edit.htmlID(), "placeholder", edit.session)
}
} }
edit.propertyChangedEvent(tag)
} }
return true return true
} }
@ -194,11 +234,14 @@ func (edit *editViewData) set(tag string, value interface{}) bool {
oldMaxLength := GetMaxLength(edit, "") oldMaxLength := GetMaxLength(edit, "")
if edit.setIntProperty(MaxLength, value) { if edit.setIntProperty(MaxLength, value) {
if maxLength := GetMaxLength(edit, ""); maxLength != oldMaxLength { if maxLength := GetMaxLength(edit, ""); maxLength != oldMaxLength {
if maxLength > 0 { if edit.created {
updateProperty(edit.htmlID(), "maxlength", strconv.Itoa(maxLength), edit.session) if maxLength > 0 {
} else { updateProperty(edit.htmlID(), "maxlength", strconv.Itoa(maxLength), edit.session)
removeProperty(edit.htmlID(), "maxlength", edit.session) } else {
removeProperty(edit.htmlID(), "maxlength", edit.session)
}
} }
edit.propertyChangedEvent(tag)
} }
return true return true
} }
@ -206,18 +249,24 @@ func (edit *editViewData) set(tag string, value interface{}) bool {
case ReadOnly: case ReadOnly:
if edit.setBoolProperty(ReadOnly, value) { if edit.setBoolProperty(ReadOnly, value) {
if IsReadOnly(edit, "") { if edit.created {
updateProperty(edit.htmlID(), ReadOnly, "", edit.session) if IsReadOnly(edit, "") {
} else { updateProperty(edit.htmlID(), ReadOnly, "", edit.session)
removeProperty(edit.htmlID(), ReadOnly, edit.session) } else {
removeProperty(edit.htmlID(), ReadOnly, edit.session)
}
} }
edit.propertyChangedEvent(tag)
return true return true
} }
return false return false
case Spellcheck: case Spellcheck:
if edit.setBoolProperty(Spellcheck, value) { if edit.setBoolProperty(Spellcheck, value) {
updateBoolProperty(edit.htmlID(), Spellcheck, IsSpellcheck(edit, ""), edit.session) if edit.created {
updateBoolProperty(edit.htmlID(), Spellcheck, IsSpellcheck(edit, ""), edit.session)
}
edit.propertyChangedEvent(tag)
return true return true
} }
return false return false
@ -227,11 +276,14 @@ func (edit *editViewData) set(tag string, value interface{}) bool {
if text, ok := value.(string); ok { if text, ok := value.(string); ok {
edit.properties[Pattern] = text edit.properties[Pattern] = text
if text = GetEditViewPattern(edit, ""); oldText != text { if text = GetEditViewPattern(edit, ""); oldText != text {
if text != "" { if edit.created {
updateProperty(edit.htmlID(), Pattern, text, edit.session) if text != "" {
} else { updateProperty(edit.htmlID(), Pattern, text, edit.session)
removeProperty(edit.htmlID(), Pattern, edit.session) } else {
removeProperty(edit.htmlID(), Pattern, edit.session)
}
} }
edit.propertyChangedEvent(tag)
} }
return true return true
} }
@ -241,7 +293,10 @@ func (edit *editViewData) set(tag string, value interface{}) bool {
oldType := GetEditViewType(edit, "") oldType := GetEditViewType(edit, "")
if edit.setEnumProperty(EditViewType, value, enumProperties[EditViewType].values) { if edit.setEnumProperty(EditViewType, value, enumProperties[EditViewType].values) {
if GetEditViewType(edit, "") != oldType { if GetEditViewType(edit, "") != oldType {
updateInnerHTML(edit.parentHTMLID(), edit.session) if edit.created {
updateInnerHTML(edit.parentHTMLID(), edit.session)
}
edit.propertyChangedEvent(tag)
} }
return true return true
} }
@ -252,11 +307,14 @@ func (edit *editViewData) set(tag string, value interface{}) bool {
if edit.setBoolProperty(Wrap, value) { if edit.setBoolProperty(Wrap, value) {
if GetEditViewType(edit, "") == MultiLineText { if GetEditViewType(edit, "") == MultiLineText {
if wrap := IsEditViewWrap(edit, ""); wrap != oldWrap { if wrap := IsEditViewWrap(edit, ""); wrap != oldWrap {
if wrap { if edit.created {
updateProperty(edit.htmlID(), "wrap", "soft", edit.session) if wrap {
} else { updateProperty(edit.htmlID(), "wrap", "soft", edit.session)
updateProperty(edit.htmlID(), "wrap", "off", edit.session) } else {
updateProperty(edit.htmlID(), "wrap", "off", edit.session)
}
} }
edit.propertyChangedEvent(tag)
} }
} }
return true return true
@ -268,6 +326,7 @@ func (edit *editViewData) set(tag string, value interface{}) bool {
if !ok { if !ok {
notCompatibleType(tag, value) notCompatibleType(tag, value)
} }
edit.propertyChangedEvent(tag)
return ok return ok
} }
@ -363,6 +422,7 @@ func (edit *editViewData) textChanged(newText string) {
for _, listener := range edit.textChangeListeners { for _, listener := range edit.textChangeListeners {
listener(edit, newText) listener(edit, newText)
} }
edit.propertyChangedEvent(Text)
} }
func (edit *editViewData) htmlTag() string { func (edit *editViewData) htmlTag() string {
@ -446,7 +506,7 @@ func (edit *editViewData) htmlProperties(self View, buffer *strings.Builder) {
} }
func (edit *editViewData) htmlDisabledProperties(self View, buffer *strings.Builder) { func (edit *editViewData) htmlDisabledProperties(self View, buffer *strings.Builder) {
if IsDisabled(self) { if IsDisabled(self, "") {
buffer.WriteString(` disabled`) buffer.WriteString(` disabled`)
} }
edit.viewData.htmlDisabledProperties(self, buffer) edit.viewData.htmlDisabledProperties(self, buffer)

View File

@ -114,7 +114,17 @@ func (picker *filePickerData) Remove(tag string) {
func (picker *filePickerData) remove(tag string) { func (picker *filePickerData) remove(tag string) {
switch tag { switch tag {
case FileSelectedEvent: case FileSelectedEvent:
picker.fileSelectedListeners = []func(FilePicker, []FileInfo){} if len(picker.fileSelectedListeners) > 0 {
picker.fileSelectedListeners = []func(FilePicker, []FileInfo){}
picker.propertyChangedEvent(tag)
}
case Accept:
delete(picker.properties, tag)
if picker.created {
removeProperty(picker.htmlID(), "accept", picker.Session())
}
picker.propertyChangedEvent(tag)
default: default:
picker.viewData.remove(tag) picker.viewData.remove(tag)
@ -184,6 +194,7 @@ func (picker *filePickerData) set(tag string, value interface{}) bool {
} }
picker.fileSelectedListeners = listeners picker.fileSelectedListeners = listeners
} }
picker.propertyChangedEvent(tag)
return true return true
case Accept: case Accept:
@ -218,6 +229,15 @@ func (picker *filePickerData) set(tag string, value interface{}) bool {
notCompatibleType(tag, value) notCompatibleType(tag, value)
return false return false
} }
if picker.created {
if css := picker.acceptCSS(); css != "" {
updateProperty(picker.htmlID(), "accept", css, picker.Session())
} else {
removeProperty(picker.htmlID(), "accept", picker.Session())
}
}
picker.propertyChangedEvent(tag)
return true return true
default: default:
@ -271,7 +291,7 @@ func (picker *filePickerData) htmlProperties(self View, buffer *strings.Builder)
} }
func (picker *filePickerData) htmlDisabledProperties(self View, buffer *strings.Builder) { func (picker *filePickerData) htmlDisabledProperties(self View, buffer *strings.Builder) {
if IsDisabled(self) { if IsDisabled(self, "") {
buffer.WriteString(` disabled`) buffer.WriteString(` disabled`)
} }
picker.viewData.htmlDisabledProperties(self, buffer) picker.viewData.htmlDisabledProperties(self, buffer)

View File

@ -216,19 +216,22 @@ func (gridLayout *gridLayoutData) remove(tag string) {
if tag == Gap { if tag == Gap {
gridLayout.remove(GridRowGap) gridLayout.remove(GridRowGap)
gridLayout.remove(GridColumnGap) gridLayout.remove(GridColumnGap)
gridLayout.propertyChangedEvent(Gap)
return return
} }
gridLayout.viewsContainerData.remove(tag) gridLayout.viewsContainerData.remove(tag)
switch tag { if gridLayout.created {
case CellWidth: switch tag {
updateCSSProperty(gridLayout.htmlID(), `grid-template-columns`, case CellWidth:
gridLayout.gridCellSizesCSS(CellWidth, gridLayout.session), gridLayout.session) updateCSSProperty(gridLayout.htmlID(), `grid-template-columns`,
gridLayout.gridCellSizesCSS(CellWidth, gridLayout.session), gridLayout.session)
case CellHeight: case CellHeight:
updateCSSProperty(gridLayout.htmlID(), `grid-template-rows`, updateCSSProperty(gridLayout.htmlID(), `grid-template-rows`,
gridLayout.gridCellSizesCSS(CellHeight, gridLayout.session), gridLayout.session) gridLayout.gridCellSizesCSS(CellHeight, gridLayout.session), gridLayout.session)
}
} }
} }
@ -243,19 +246,25 @@ func (gridLayout *gridLayoutData) set(tag string, value interface{}) bool {
} }
if tag == Gap { if tag == Gap {
return gridLayout.set(GridRowGap, value) && gridLayout.set(GridColumnGap, value) if gridLayout.set(GridRowGap, value) && gridLayout.set(GridColumnGap, value) {
gridLayout.propertyChangedEvent(Gap)
return true
}
return false
} }
if gridLayout.viewsContainerData.set(tag, value) { if gridLayout.viewsContainerData.set(tag, value) {
switch tag { if gridLayout.created {
case CellWidth: switch tag {
updateCSSProperty(gridLayout.htmlID(), `grid-template-columns`, case CellWidth:
gridLayout.gridCellSizesCSS(CellWidth, gridLayout.session), gridLayout.session) updateCSSProperty(gridLayout.htmlID(), `grid-template-columns`,
gridLayout.gridCellSizesCSS(CellWidth, gridLayout.session), gridLayout.session)
case CellHeight: case CellHeight:
updateCSSProperty(gridLayout.htmlID(), `grid-template-rows`, updateCSSProperty(gridLayout.htmlID(), `grid-template-rows`,
gridLayout.gridCellSizesCSS(CellHeight, gridLayout.session), gridLayout.session) gridLayout.gridCellSizesCSS(CellHeight, gridLayout.session), gridLayout.session)
}
} }
return true return true
} }

View File

@ -67,7 +67,7 @@ func (imageView *imageViewData) normalizeTag(tag string) string {
case HorizontalAlign: case HorizontalAlign:
tag = ImageHorizontalAlign tag = ImageHorizontalAlign
case altProperty: case altTag:
tag = AltText tag = AltText
} }
return tag return tag
@ -79,16 +79,18 @@ func (imageView *imageViewData) Remove(tag string) {
func (imageView *imageViewData) remove(tag string) { func (imageView *imageViewData) remove(tag string) {
imageView.viewData.remove(tag) imageView.viewData.remove(tag)
switch tag { if imageView.created {
case Source: switch tag {
updateProperty(imageView.htmlID(), "src", "", imageView.session) case Source:
removeProperty(imageView.htmlID(), "srcset", imageView.session) updateProperty(imageView.htmlID(), "src", "", imageView.session)
removeProperty(imageView.htmlID(), "srcset", imageView.session)
case AltText: case AltText:
updateInnerHTML(imageView.htmlID(), imageView.session) updateInnerHTML(imageView.htmlID(), imageView.session)
case ImageVerticalAlign, ImageHorizontalAlign: case ImageVerticalAlign, ImageHorizontalAlign:
updateCSSStyle(imageView.htmlID(), imageView.session) updateCSSStyle(imageView.htmlID(), imageView.session)
}
} }
} }
@ -106,29 +108,37 @@ func (imageView *imageViewData) set(tag string, value interface{}) bool {
case Source: case Source:
if text, ok := value.(string); ok { if text, ok := value.(string); ok {
imageView.properties[Source] = text imageView.properties[Source] = text
updateProperty(imageView.htmlID(), "src", text, imageView.session) if imageView.created {
if srcset := imageView.srcSet(text); srcset != "" { updateProperty(imageView.htmlID(), "src", text, imageView.session)
updateProperty(imageView.htmlID(), "srcset", srcset, imageView.session) if srcset := imageView.srcSet(text); srcset != "" {
} else { updateProperty(imageView.htmlID(), "srcset", srcset, imageView.session)
removeProperty(imageView.htmlID(), "srcset", imageView.session) } else {
removeProperty(imageView.htmlID(), "srcset", imageView.session)
}
} }
imageView.propertyChangedEvent(Source)
return true return true
} }
notCompatibleType(tag, value) notCompatibleType(Source, value)
case AltText: case AltText:
if text, ok := value.(string); ok { if text, ok := value.(string); ok {
imageView.properties[AltText] = text imageView.properties[AltText] = text
updateInnerHTML(imageView.htmlID(), imageView.session) if imageView.created {
updateInnerHTML(imageView.htmlID(), imageView.session)
}
imageView.propertyChangedEvent(Source)
return true return true
} }
notCompatibleType(tag, value) notCompatibleType(tag, value)
default: default:
if imageView.viewData.set(tag, value) { if imageView.viewData.set(tag, value) {
switch tag { if imageView.created {
case ImageVerticalAlign, ImageHorizontalAlign: switch tag {
updateCSSStyle(imageView.htmlID(), imageView.session) case ImageVerticalAlign, ImageHorizontalAlign:
updateCSSStyle(imageView.htmlID(), imageView.session)
}
} }
return true return true
} }

View File

@ -77,7 +77,7 @@ func (adapter *viewListAdapter) ListItem(index int, session Session) View {
func (adapter *viewListAdapter) IsListItemEnabled(index int) bool { func (adapter *viewListAdapter) IsListItemEnabled(index int) bool {
if index >= 0 && index < len(adapter.items) { if index >= 0 && index < len(adapter.items) {
return !IsDisabled(adapter.items[index]) return !IsDisabled(adapter.items[index], "")
} }
return true return true
} }

View File

@ -55,9 +55,11 @@ func (listLayout *listLayoutData) Remove(tag string) {
func (listLayout *listLayoutData) remove(tag string) { func (listLayout *listLayoutData) remove(tag string) {
listLayout.viewsContainerData.remove(tag) listLayout.viewsContainerData.remove(tag)
switch tag { if listLayout.created {
case Orientation, Wrap, HorizontalAlign, VerticalAlign: switch tag {
updateCSSStyle(listLayout.htmlID(), listLayout.session) case Orientation, Wrap, HorizontalAlign, VerticalAlign:
updateCSSStyle(listLayout.htmlID(), listLayout.session)
}
} }
} }
@ -72,9 +74,11 @@ func (listLayout *listLayoutData) set(tag string, value interface{}) bool {
} }
if listLayout.viewsContainerData.set(tag, value) { if listLayout.viewsContainerData.set(tag, value) {
switch tag { if listLayout.created {
case Orientation, Wrap, HorizontalAlign, VerticalAlign: switch tag {
updateCSSStyle(listLayout.htmlID(), listLayout.session) case Orientation, Wrap, HorizontalAlign, VerticalAlign:
updateCSSStyle(listLayout.htmlID(), listLayout.session)
}
} }
return true return true
} }

View File

@ -114,46 +114,71 @@ func (listView *listViewData) Remove(tag string) {
func (listView *listViewData) remove(tag string) { func (listView *listViewData) remove(tag string) {
switch tag { switch tag {
case Checked: case Checked:
listView.checkedItem = []int{} if len(listView.checkedItem) > 0 {
updateInnerHTML(listView.htmlID(), listView.session) listView.checkedItem = []int{}
if listView.created {
updateInnerHTML(listView.htmlID(), listView.session)
}
listView.propertyChangedEvent(tag)
}
case Items: case Items:
listView.adapter = nil if listView.adapter != nil {
updateInnerHTML(listView.htmlID(), listView.session) listView.adapter = nil
if listView.created {
updateInnerHTML(listView.htmlID(), listView.session)
}
listView.propertyChangedEvent(tag)
}
case Orientation, Wrap: case Orientation, Wrap:
delete(listView.properties, tag) if _, ok := listView.properties[tag]; ok {
updateCSSStyle(listView.htmlID(), listView.session) delete(listView.properties, tag)
if listView.created {
updateCSSStyle(listView.htmlID(), listView.session)
}
listView.propertyChangedEvent(tag)
}
case Current: case Current:
current := GetListViewCurrent(listView, "") current := GetListViewCurrent(listView, "")
delete(listView.properties, tag) delete(listView.properties, tag)
updateInnerHTML(listView.htmlID(), listView.session) if listView.created {
updateInnerHTML(listView.htmlID(), listView.session)
}
if current != -1 { if current != -1 {
for _, listener := range listView.selectedListeners { for _, listener := range listView.selectedListeners {
listener(listView, -1) listener(listView, -1)
} }
listView.propertyChangedEvent(tag)
} }
case ItemWidth, ItemHeight, ItemHorizontalAlign, ItemVerticalAlign, ItemCheckbox, case ItemWidth, ItemHeight, ItemHorizontalAlign, ItemVerticalAlign, ItemCheckbox,
CheckboxHorizontalAlign, CheckboxVerticalAlign, ListItemStyle, CurrentStyle, CurrentInactiveStyle: CheckboxHorizontalAlign, CheckboxVerticalAlign, ListItemStyle, CurrentStyle, CurrentInactiveStyle:
if _, ok := listView.properties[tag]; ok {
delete(listView.properties, tag) delete(listView.properties, tag)
updateInnerHTML(listView.htmlID(), listView.session) if listView.created {
updateInnerHTML(listView.htmlID(), listView.session)
}
listView.propertyChangedEvent(tag)
}
case ListItemClickedEvent: case ListItemClickedEvent:
if len(listView.clickedListeners) > 0 { if len(listView.clickedListeners) > 0 {
listView.clickedListeners = []func(ListView, int){} listView.clickedListeners = []func(ListView, int){}
listView.propertyChangedEvent(tag)
} }
case ListItemSelectedEvent: case ListItemSelectedEvent:
if len(listView.selectedListeners) > 0 { if len(listView.selectedListeners) > 0 {
listView.selectedListeners = []func(ListView, int){} listView.selectedListeners = []func(ListView, int){}
listView.propertyChangedEvent(tag)
} }
case ListItemCheckedEvent: case ListItemCheckedEvent:
if len(listView.checkedListeners) > 0 { if len(listView.checkedListeners) > 0 {
listView.checkedListeners = []func(ListView, []int){} listView.checkedListeners = []func(ListView, []int){}
listView.propertyChangedEvent(tag)
} }
default: default:
@ -171,10 +196,7 @@ func (listView *listViewData) set(tag string, value interface{}) bool {
return true return true
} }
result := false
switch tag { switch tag {
case ListItemClickedEvent: case ListItemClickedEvent:
listeners := listView.valueToItemListeners(value) listeners := listView.valueToItemListeners(value)
if listeners == nil { if listeners == nil {
@ -182,6 +204,7 @@ func (listView *listViewData) set(tag string, value interface{}) bool {
return false return false
} }
listView.clickedListeners = listeners listView.clickedListeners = listeners
listView.propertyChangedEvent(tag)
return true return true
case ListItemSelectedEvent: case ListItemSelectedEvent:
@ -191,44 +214,56 @@ func (listView *listViewData) set(tag string, value interface{}) bool {
return false return false
} }
listView.selectedListeners = listeners listView.selectedListeners = listeners
listView.propertyChangedEvent(tag)
return true return true
case ListItemCheckedEvent: case ListItemCheckedEvent:
return listView.setItemCheckedEvent(value) if !listView.setItemCheckedEvent(value) {
return false
}
listView.propertyChangedEvent(tag)
return true
case Checked: case Checked:
return listView.setChecked(value) if !listView.setChecked(value) {
return false
}
case Items: case Items:
result = listView.setItems(value) if !listView.setItems(value) {
return false
}
case Current: case Current:
oldCurrent := GetListViewCurrent(listView, "") oldCurrent := GetListViewCurrent(listView, "")
if listView.setIntProperty(Current, value) { if !listView.setIntProperty(Current, value) {
current := GetListViewCurrent(listView, "") return false
if oldCurrent != current { }
updateInnerHTML(listView.htmlID(), listView.session) current := GetListViewCurrent(listView, "")
for _, listener := range listView.selectedListeners { if oldCurrent == current {
listener(listView, current)
}
}
return true return true
} }
case Orientation, Wrap, VerticalAlign, HorizontalAlign, Style, StyleDisabled: for _, listener := range listView.selectedListeners {
result = listView.viewData.set(tag, value) listener(listView, current)
}
case ItemWidth, ItemHeight: case Orientation, Wrap, VerticalAlign, HorizontalAlign, Style, StyleDisabled, ItemWidth, ItemHeight:
result = listView.setSizeProperty(tag, value) result := listView.viewData.set(tag, value)
if result && listView.created {
updateInnerHTML(listView.htmlID(), listView.session)
}
return result
case ItemHorizontalAlign, ItemVerticalAlign, ItemCheckbox, CheckboxHorizontalAlign, CheckboxVerticalAlign: case ItemHorizontalAlign, ItemVerticalAlign, ItemCheckbox, CheckboxHorizontalAlign, CheckboxVerticalAlign:
result = listView.setEnumProperty(tag, value, enumProperties[tag].values) if !listView.setEnumProperty(tag, value, enumProperties[tag].values) {
return false
}
case ListItemStyle, CurrentStyle, CurrentInactiveStyle: case ListItemStyle, CurrentStyle, CurrentInactiveStyle:
switch value := value.(type) { switch value := value.(type) {
case string: case string:
listView.properties[tag] = value listView.properties[tag] = value
result = true
default: default:
notCompatibleType(tag, value) notCompatibleType(tag, value)
@ -239,11 +274,11 @@ func (listView *listViewData) set(tag string, value interface{}) bool {
return listView.viewData.set(tag, value) return listView.viewData.set(tag, value)
} }
if result { if listView.created {
updateInnerHTML(listView.htmlID(), listView.session) updateInnerHTML(listView.htmlID(), listView.session)
} }
listView.propertyChangedEvent(tag)
return result return true
} }
func (listView *listViewData) setItemCheckedEvent(value interface{}) bool { func (listView *listViewData) setItemCheckedEvent(value interface{}) bool {
@ -1054,13 +1089,17 @@ func (listView *listViewData) handleCommand(self View, command string, data Data
for _, listener := range listView.selectedListeners { for _, listener := range listView.selectedListeners {
listener(listView, number) listener(listView, number)
} }
listView.propertyChangedEvent(Current)
} }
} }
case "itemUnselected": case "itemUnselected":
delete(listView.properties, Current) if _, ok := listView.properties[Current]; ok {
for _, listener := range listView.selectedListeners { delete(listView.properties, Current)
listener(listView, -1) for _, listener := range listView.selectedListeners {
listener(listView, -1)
}
listView.propertyChangedEvent(Current)
} }
case "itemClick": case "itemClick":
@ -1075,7 +1114,7 @@ func (listView *listViewData) handleCommand(self View, command string, data Data
func (listView *listViewData) onItemClick() { func (listView *listViewData) onItemClick() {
current := GetListViewCurrent(listView, "") current := GetListViewCurrent(listView, "")
if current >= 0 && !IsDisabled(listView) { if current >= 0 && !IsDisabled(listView, "") {
checkbox := GetListViewCheckbox(listView, "") checkbox := GetListViewCheckbox(listView, "")
m: m:
switch checkbox { switch checkbox {
@ -1115,6 +1154,7 @@ func (listView *listViewData) onItemClick() {
for _, listener := range listView.checkedListeners { for _, listener := range listView.checkedListeners {
listener(listView, listView.checkedItem) listener(listView, listView.checkedItem)
} }
listView.propertyChangedEvent(Checked)
} }
for _, listener := range listView.clickedListeners { for _, listener := range listView.clickedListeners {
listener(listView, current) listener(listView, current)

View File

@ -173,20 +173,8 @@ func (player *mediaPlayerData) Remove(tag string) {
} }
func (player *mediaPlayerData) remove(tag string) { func (player *mediaPlayerData) remove(tag string) {
switch tag { player.viewData.remove(tag)
player.propertyChanged(tag)
case Controls, Loop, Muted, Preload, AbortEvent, LoadStartEvent, PlayerErrorEvent,
CanPlayEvent, CanPlayThroughEvent, CompleteEvent, DurationChangedEvent,
EmptiedEvent, EndedEvent, LoadedDataEvent, LoadedMetadataEvent, PauseEvent, PlayEvent,
PlayingEvent, RateChangedEvent, SeekedEvent, SeekingEvent, StalledEvent, SuspendEvent,
ProgressEvent, TimeUpdateEvent, VolumeChangedEvent, WaitingEvent:
player.viewData.remove(tag)
player.propertyChanged(tag)
default:
player.viewData.remove(tag)
}
} }
func (player *mediaPlayerData) Set(tag string, value interface{}) bool { func (player *mediaPlayerData) Set(tag string, value interface{}) bool {
@ -216,6 +204,7 @@ func (player *mediaPlayerData) set(tag string, value interface{}) bool {
player.properties[tag] = listeners player.properties[tag] = listeners
} }
player.propertyChanged(tag) player.propertyChanged(tag)
player.propertyChangedEvent(tag)
return true return true
} }
notCompatibleType(tag, value) notCompatibleType(tag, value)
@ -228,6 +217,7 @@ func (player *mediaPlayerData) set(tag string, value interface{}) bool {
player.properties[tag] = listeners player.properties[tag] = listeners
} }
player.propertyChanged(tag) player.propertyChanged(tag)
player.propertyChangedEvent(tag)
return true return true
} }
notCompatibleType(tag, value) notCompatibleType(tag, value)
@ -240,6 +230,7 @@ func (player *mediaPlayerData) set(tag string, value interface{}) bool {
player.properties[tag] = listeners player.properties[tag] = listeners
} }
player.propertyChanged(tag) player.propertyChanged(tag)
player.propertyChangedEvent(tag)
return true return true
} }
notCompatibleType(tag, value) notCompatibleType(tag, value)
@ -247,14 +238,14 @@ func (player *mediaPlayerData) set(tag string, value interface{}) bool {
case Source: case Source:
if player.setSource(value) { if player.setSource(value) {
player.propertyChanged(tag) player.propertyChanged(tag)
player.propertyChangedEvent(tag)
return true return true
} }
default: default:
if player.viewData.set(tag, value) { return player.viewData.set(tag, value)
return true
}
} }
return false return false
} }
@ -657,89 +648,88 @@ func playerEvents() []struct{ tag, cssTag string } {
} }
func (player *mediaPlayerData) propertyChanged(tag string) { func (player *mediaPlayerData) propertyChanged(tag string) {
switch tag { if player.created {
case Controls, Loop: switch tag {
value, _ := boolProperty(player, tag, player.Session()) case Controls, Loop:
if value { value, _ := boolProperty(player, tag, player.Session())
updateBoolProperty(player.htmlID(), tag, value, player.Session()) if value {
} else { updateBoolProperty(player.htmlID(), tag, value, player.Session())
removeProperty(player.htmlID(), tag, player.Session()) } else {
} removeProperty(player.htmlID(), tag, player.Session())
case Muted:
value, _ := boolProperty(player, tag, player.Session())
if value {
player.Session().runScript("setMediaMuted('" + player.htmlID() + "', true)")
} else {
player.Session().runScript("setMediaMuted('" + player.htmlID() + "', false)")
}
case Preload:
value, _ := enumProperty(player, tag, player.Session(), 0)
values := enumProperties[Preload].values
updateProperty(player.htmlID(), tag, values[value], player.Session())
case AbortEvent, CanPlayEvent, CanPlayThroughEvent, CompleteEvent, EmptiedEvent,
EndedEvent, LoadedDataEvent, LoadedMetadataEvent, PauseEvent, PlayEvent, PlayingEvent, ProgressEvent,
LoadStartEvent, SeekedEvent, SeekingEvent, StalledEvent, SuspendEvent, WaitingEvent:
for _, event := range playerEvents() {
if event.tag == tag {
if value := player.getRaw(event.tag); value != nil {
switch value := value.(type) {
case []func(MediaPlayer):
if len(value) > 0 {
fn := fmt.Sprintf(`playerEvent(this, "%s")`, event.tag)
updateProperty(player.htmlID(), event.cssTag, fn, player.Session())
return
}
}
}
updateProperty(player.htmlID(), tag, "", player.Session())
break
} }
} case Muted:
case TimeUpdateEvent: value, _ := boolProperty(player, tag, player.Session())
if value := player.getRaw(tag); value != nil { if value {
updateProperty(player.htmlID(), "ontimeupdate", "playerTimeUpdatedEvent(this)", player.Session()) player.Session().runScript("setMediaMuted('" + player.htmlID() + "', true)")
} else { } else {
updateProperty(player.htmlID(), "ontimeupdate", "", player.Session()) player.Session().runScript("setMediaMuted('" + player.htmlID() + "', false)")
} }
case VolumeChangedEvent: case Preload:
if value := player.getRaw(tag); value != nil { value, _ := enumProperty(player, tag, player.Session(), 0)
updateProperty(player.htmlID(), "onvolumechange", "playerVolumeChangedEvent(this)", player.Session()) values := enumProperties[Preload].values
} else { updateProperty(player.htmlID(), tag, values[value], player.Session())
updateProperty(player.htmlID(), "onvolumechange", "", player.Session())
case AbortEvent, CanPlayEvent, CanPlayThroughEvent, CompleteEvent, EmptiedEvent,
EndedEvent, LoadedDataEvent, LoadedMetadataEvent, PauseEvent, PlayEvent, PlayingEvent, ProgressEvent,
LoadStartEvent, SeekedEvent, SeekingEvent, StalledEvent, SuspendEvent, WaitingEvent:
for _, event := range playerEvents() {
if event.tag == tag {
if value := player.getRaw(event.tag); value != nil {
switch value := value.(type) {
case []func(MediaPlayer):
if len(value) > 0 {
fn := fmt.Sprintf(`playerEvent(this, "%s")`, event.tag)
updateProperty(player.htmlID(), event.cssTag, fn, player.Session())
return
}
}
}
updateProperty(player.htmlID(), tag, "", player.Session())
break
}
}
case TimeUpdateEvent:
if value := player.getRaw(tag); value != nil {
updateProperty(player.htmlID(), "ontimeupdate", "playerTimeUpdatedEvent(this)", player.Session())
} else {
updateProperty(player.htmlID(), "ontimeupdate", "", player.Session())
}
case VolumeChangedEvent:
if value := player.getRaw(tag); value != nil {
updateProperty(player.htmlID(), "onvolumechange", "playerVolumeChangedEvent(this)", player.Session())
} else {
updateProperty(player.htmlID(), "onvolumechange", "", player.Session())
}
case DurationChangedEvent:
if value := player.getRaw(tag); value != nil {
updateProperty(player.htmlID(), "ondurationchange", "playerDurationChangedEvent(this)", player.Session())
} else {
updateProperty(player.htmlID(), "ondurationchange", "", player.Session())
}
case RateChangedEvent:
if value := player.getRaw(tag); value != nil {
updateProperty(player.htmlID(), "onratechange", "playerRateChangedEvent(this)", player.Session())
} else {
updateProperty(player.htmlID(), "onratechange", "", player.Session())
}
case PlayerErrorEvent:
if value := player.getRaw(tag); value != nil {
updateProperty(player.htmlID(), "onerror", "playerErrorEvent(this)", player.Session())
} else {
updateProperty(player.htmlID(), "onerror", "", player.Session())
}
case Source:
updateInnerHTML(player.htmlID(), player.Session())
} }
case DurationChangedEvent:
if value := player.getRaw(tag); value != nil {
updateProperty(player.htmlID(), "ondurationchange", "playerDurationChangedEvent(this)", player.Session())
} else {
updateProperty(player.htmlID(), "ondurationchange", "", player.Session())
}
case RateChangedEvent:
if value := player.getRaw(tag); value != nil {
updateProperty(player.htmlID(), "onratechange", "playerRateChangedEvent(this)", player.Session())
} else {
updateProperty(player.htmlID(), "onratechange", "", player.Session())
}
case PlayerErrorEvent:
if value := player.getRaw(tag); value != nil {
updateProperty(player.htmlID(), "onerror", "playerErrorEvent(this)", player.Session())
} else {
updateProperty(player.htmlID(), "onerror", "", player.Session())
}
case Source:
updateInnerHTML(player.htmlID(), player.Session())
default:
player.viewData.propertyChanged(tag)
} }
} }

View File

@ -69,6 +69,7 @@ func (picker *numberPickerData) remove(tag string) {
case NumberChangedEvent: case NumberChangedEvent:
if len(picker.numberChangedListeners) > 0 { if len(picker.numberChangedListeners) > 0 {
picker.numberChangedListeners = []func(NumberPicker, float64){} picker.numberChangedListeners = []func(NumberPicker, float64){}
picker.propertyChangedEvent(tag)
} }
default: default:
@ -135,18 +136,21 @@ func (picker *numberPickerData) set(tag string, value interface{}) bool {
} }
picker.numberChangedListeners = listeners picker.numberChangedListeners = listeners
} }
picker.propertyChangedEvent(tag)
return true return true
case NumberPickerValue: case NumberPickerValue:
oldValue := GetNumberPickerValue(picker, "") oldValue := GetNumberPickerValue(picker, "")
min, max := GetNumberPickerMinMax(picker, "") min, max := GetNumberPickerMinMax(picker, "")
if picker.setFloatProperty(NumberPickerValue, value, min, max) { if picker.setFloatProperty(NumberPickerValue, value, min, max) {
newValue := GetNumberPickerValue(picker, "") if newValue := GetNumberPickerValue(picker, ""); oldValue != newValue {
if oldValue != newValue { if picker.created {
picker.session.runScript(fmt.Sprintf(`setInputValue('%s', '%f')`, picker.htmlID(), newValue)) picker.session.runScript(fmt.Sprintf(`setInputValue('%s', '%f')`, picker.htmlID(), newValue))
}
for _, listener := range picker.numberChangedListeners { for _, listener := range picker.numberChangedListeners {
listener(picker, newValue) listener(picker, newValue)
} }
picker.propertyChangedEvent(tag)
} }
return true return true
} }
@ -161,34 +165,36 @@ func (picker *numberPickerData) set(tag string, value interface{}) bool {
} }
func (picker *numberPickerData) propertyChanged(tag string) { func (picker *numberPickerData) propertyChanged(tag string) {
switch tag { if picker.created {
case NumberPickerType: switch tag {
if GetNumberPickerType(picker, "") == NumberSlider { case NumberPickerType:
updateProperty(picker.htmlID(), "type", "range", picker.session) if GetNumberPickerType(picker, "") == NumberSlider {
} else { updateProperty(picker.htmlID(), "type", "range", picker.session)
updateProperty(picker.htmlID(), "type", "number", picker.session) } else {
} updateProperty(picker.htmlID(), "type", "number", picker.session)
}
case NumberPickerMin: case NumberPickerMin:
min, _ := GetNumberPickerMinMax(picker, "") min, _ := GetNumberPickerMinMax(picker, "")
updateProperty(picker.htmlID(), Min, strconv.FormatFloat(min, 'f', -1, 32), picker.session) updateProperty(picker.htmlID(), Min, strconv.FormatFloat(min, 'f', -1, 32), picker.session)
case NumberPickerMax: case NumberPickerMax:
_, max := GetNumberPickerMinMax(picker, "") _, max := GetNumberPickerMinMax(picker, "")
updateProperty(picker.htmlID(), Max, strconv.FormatFloat(max, 'f', -1, 32), picker.session) updateProperty(picker.htmlID(), Max, strconv.FormatFloat(max, 'f', -1, 32), picker.session)
case NumberPickerStep: case NumberPickerStep:
if step := GetNumberPickerStep(picker, ""); step > 0 { if step := GetNumberPickerStep(picker, ""); step > 0 {
updateProperty(picker.htmlID(), Step, strconv.FormatFloat(step, 'f', -1, 32), picker.session) updateProperty(picker.htmlID(), Step, strconv.FormatFloat(step, 'f', -1, 32), picker.session)
} else { } else {
updateProperty(picker.htmlID(), Step, "any", picker.session) updateProperty(picker.htmlID(), Step, "any", picker.session)
} }
case NumberPickerValue: case NumberPickerValue:
value := GetNumberPickerValue(picker, "") value := GetNumberPickerValue(picker, "")
picker.session.runScript(fmt.Sprintf(`setInputValue('%s', '%f')`, picker.htmlID(), value)) picker.session.runScript(fmt.Sprintf(`setInputValue('%s', '%f')`, picker.htmlID(), value))
for _, listener := range picker.numberChangedListeners { for _, listener := range picker.numberChangedListeners {
listener(picker, value) listener(picker, value)
}
} }
} }
} }
@ -246,7 +252,7 @@ func (picker *numberPickerData) htmlProperties(self View, buffer *strings.Builde
} }
func (picker *numberPickerData) htmlDisabledProperties(self View, buffer *strings.Builder) { func (picker *numberPickerData) htmlDisabledProperties(self View, buffer *strings.Builder) {
if IsDisabled(self) { if IsDisabled(self, "") {
buffer.WriteString(` disabled`) buffer.WriteString(` disabled`)
} }
picker.viewData.htmlDisabledProperties(self, buffer) picker.viewData.htmlDisabledProperties(self, buffer)

View File

@ -58,12 +58,14 @@ func (progress *progressBarData) remove(tag string) {
} }
func (progress *progressBarData) propertyChanged(tag string) { func (progress *progressBarData) propertyChanged(tag string) {
switch tag { if progress.created {
case ProgressBarMax: switch tag {
updateProperty(progress.htmlID(), Max, strconv.FormatFloat(GetProgressBarMax(progress, ""), 'f', -1, 32), progress.session) case ProgressBarMax:
updateProperty(progress.htmlID(), Max, strconv.FormatFloat(GetProgressBarMax(progress, ""), 'f', -1, 32), progress.session)
case ProgressBarValue: case ProgressBarValue:
updateProperty(progress.htmlID(), Value, strconv.FormatFloat(GetProgressBarValue(progress, ""), 'f', -1, 32), progress.session) updateProperty(progress.htmlID(), Value, strconv.FormatFloat(GetProgressBarValue(progress, ""), 'f', -1, 32), progress.session)
}
} }
} }

View File

@ -367,8 +367,8 @@ const (
// CenterY is the constant for the "center-x" property tag. // CenterY is the constant for the "center-x" property tag.
CenterY = "center-y" CenterY = "center-y"
// AltText is the constant for the "alt-text" property tag. // AltText is the constant for the "alt-text" property tag.
AltText = "alt-text" AltText = "alt-text"
altProperty = "alt" altTag = "alt"
// AvoidBreak is the constant for the "avoid-break" property tag. // AvoidBreak is the constant for the "avoid-break" property tag.
// The "avoid-break" bool property sets how region breaks should behave inside a generated box. // The "avoid-break" bool property sets how region breaks should behave inside a generated box.
// If the property value is "true" then fvoids any break from being inserted within the principal box. // If the property value is "true" then fvoids any break from being inserted within the principal box.

View File

@ -65,6 +65,7 @@ var intProperties = []string{
FootHeight, FootHeight,
RowSpan, RowSpan,
ColumnSpan, ColumnSpan,
ColumnCount,
} }
var floatProperties = map[string]struct{ min, max float64 }{ var floatProperties = map[string]struct{ min, max float64 }{

View File

@ -75,8 +75,11 @@ func (resizable *resizableData) remove(tag string) {
oldSide := resizable.getSide() oldSide := resizable.getSide()
delete(resizable.properties, Side) delete(resizable.properties, Side)
if oldSide != resizable.getSide() { if oldSide != resizable.getSide() {
updateInnerHTML(resizable.htmlID(), resizable.Session()) if resizable.created {
resizable.updateResizeBorderWidth() updateInnerHTML(resizable.htmlID(), resizable.Session())
resizable.updateResizeBorderWidth()
}
resizable.propertyChangedEvent(tag)
} }
case ResizeBorderWidth: case ResizeBorderWidth:
@ -84,12 +87,16 @@ func (resizable *resizableData) remove(tag string) {
delete(resizable.properties, ResizeBorderWidth) delete(resizable.properties, ResizeBorderWidth)
if !w.Equal(resizable.resizeBorderWidth()) { if !w.Equal(resizable.resizeBorderWidth()) {
resizable.updateResizeBorderWidth() resizable.updateResizeBorderWidth()
resizable.propertyChangedEvent(tag)
} }
case Content: case Content:
if len(resizable.content) > 0 { if len(resizable.content) > 0 {
resizable.content = []View{} resizable.content = []View{}
updateInnerHTML(resizable.htmlID(), resizable.Session()) if resizable.created {
updateInnerHTML(resizable.htmlID(), resizable.Session())
}
resizable.propertyChangedEvent(tag)
} }
default: default:
@ -110,20 +117,25 @@ func (resizable *resizableData) set(tag string, value interface{}) bool {
switch tag { switch tag {
case Side: case Side:
oldSide := resizable.getSide() oldSide := resizable.getSide()
ok := resizable.setSide(value) if !resizable.setSide(value) {
if ok && oldSide != resizable.getSide() {
updateInnerHTML(resizable.htmlID(), resizable.Session())
resizable.updateResizeBorderWidth()
} else {
notCompatibleType(tag, value) notCompatibleType(tag, value)
return false
} }
return ok if oldSide != resizable.getSide() {
if resizable.created {
updateInnerHTML(resizable.htmlID(), resizable.Session())
resizable.updateResizeBorderWidth()
}
resizable.propertyChangedEvent(tag)
}
return true
case ResizeBorderWidth: case ResizeBorderWidth:
w := resizable.resizeBorderWidth() w := resizable.resizeBorderWidth()
ok := resizable.setSizeProperty(tag, value) ok := resizable.setSizeProperty(tag, value)
if ok && !w.Equal(resizable.resizeBorderWidth()) { if ok && !w.Equal(resizable.resizeBorderWidth()) {
resizable.updateResizeBorderWidth() resizable.updateResizeBorderWidth()
resizable.propertyChangedEvent(tag)
} }
return ok return ok
@ -139,18 +151,25 @@ func (resizable *resizableData) set(tag string, value interface{}) bool {
case DataObject: case DataObject:
if view := CreateViewFromObject(resizable.Session(), value); view != nil { if view := CreateViewFromObject(resizable.Session(), value); view != nil {
newContent = view newContent = view
} else {
return false
} }
default:
notCompatibleType(tag, value)
return false
} }
if newContent != nil { if len(resizable.content) == 0 {
if len(resizable.content) == 0 { resizable.content = []View{newContent}
resizable.content = []View{newContent} } else {
} else { resizable.content[0] = newContent
resizable.content[0] = newContent
}
updateInnerHTML(resizable.htmlID(), resizable.Session())
return true
} }
if resizable.created {
updateInnerHTML(resizable.htmlID(), resizable.Session())
}
resizable.propertyChangedEvent(tag)
return true
case CellWidth, CellHeight, GridRowGap, GridColumnGap, CellVerticalAlign, CellHorizontalAlign: case CellWidth, CellHeight, GridRowGap, GridColumnGap, CellVerticalAlign, CellHorizontalAlign:
ErrorLogF(`Not supported "%s" property`, tag) ErrorLogF(`Not supported "%s" property`, tag)
@ -306,12 +325,14 @@ func (resizable *resizableData) resizeBorderWidth() SizeUnit {
} }
func (resizable *resizableData) updateResizeBorderWidth() { func (resizable *resizableData) updateResizeBorderWidth() {
htmlID := resizable.htmlID() if resizable.created {
session := resizable.Session() htmlID := resizable.htmlID()
column, row := resizable.cellSizeCSS() session := resizable.Session()
column, row := resizable.cellSizeCSS()
updateCSSProperty(htmlID, "grid-template-columns", column, session) updateCSSProperty(htmlID, "grid-template-columns", column, session)
updateCSSProperty(htmlID, "grid-template-rows", row, session) updateCSSProperty(htmlID, "grid-template-rows", row, session)
}
} }
func (resizable *resizableData) cellSizeCSS() (string, string) { func (resizable *resizableData) cellSizeCSS() (string, string) {

View File

@ -6,6 +6,8 @@ import (
"strings" "strings"
) )
// TODO PeekChangedEvent
const ( const (
// DefaultAnimation - default animation of StackLayout push // DefaultAnimation - default animation of StackLayout push
DefaultAnimation = 0 DefaultAnimation = 0
@ -93,23 +95,33 @@ func (layout *stackLayoutData) popFinished(view View, tag string) {
} }
func (layout *stackLayoutData) Set(tag string, value interface{}) bool { func (layout *stackLayoutData) Set(tag string, value interface{}) bool {
if strings.ToLower(tag) == TransitionEndEvent { return layout.set(strings.ToLower(tag), value)
}
func (layout *stackLayoutData) set(tag string, value interface{}) bool {
if tag == TransitionEndEvent {
listeners, ok := valueToAnimationListeners(value) listeners, ok := valueToAnimationListeners(value)
if ok { if ok {
listeners = append(listeners, layout.pushFinished) listeners = append(listeners, layout.pushFinished)
listeners = append(listeners, layout.popFinished) listeners = append(listeners, layout.popFinished)
layout.properties[TransitionEndEvent] = listeners layout.properties[TransitionEndEvent] = listeners
layout.propertyChangedEvent(TransitionEndEvent)
} }
return ok return ok
} }
return layout.viewsContainerData.Set(tag, value) return layout.viewsContainerData.set(tag, value)
} }
func (layout *stackLayoutData) Remove(tag string) { func (layout *stackLayoutData) Remove(tag string) {
if strings.ToLower(tag) == TransitionEndEvent { layout.remove(strings.ToLower(tag))
}
func (layout *stackLayoutData) remove(tag string) {
if tag == TransitionEndEvent {
layout.properties[TransitionEndEvent] = []func(View, string){layout.pushFinished, layout.popFinished} layout.properties[TransitionEndEvent] = []func(View, string){layout.pushFinished, layout.popFinished}
layout.propertyChangedEvent(TransitionEndEvent)
} else { } else {
layout.viewsContainerData.Remove(tag) layout.viewsContainerData.remove(tag)
} }
} }
@ -238,6 +250,7 @@ func (layout *stackLayoutData) Push(view View, animation int, onPushFinished fun
layout.views = append(layout.views, view) layout.views = append(layout.views, view)
view.setParentID(htmlID) view.setParentID(htmlID)
layout.propertyChangedEvent(Content)
} }
func (layout *stackLayoutData) Pop(animation int, onPopFinished func(View)) bool { func (layout *stackLayoutData) Pop(animation int, onPopFinished func(View)) bool {
@ -286,6 +299,7 @@ func (layout *stackLayoutData) Pop(animation int, onPopFinished func(View)) bool
} }
updateCSSProperty(htmlID+"pop", "transform", value, layout.session) updateCSSProperty(htmlID+"pop", "transform", value, layout.session)
layout.propertyChangedEvent(Content)
return true return true
} }

View File

@ -168,35 +168,51 @@ func (table *tableViewData) Init(session Session) {
table.tag = "TableView" table.tag = "TableView"
} }
func (table *tableViewData) normalizeTag(tag string) string {
switch tag = strings.ToLower(tag); tag {
case "top-cell-padding":
tag = CellPaddingTop
case "right-cell-padding":
tag = CellPaddingRight
case "bottom-cell-padding":
tag = CellPaddingBottom
case "left-cell-padding":
tag = CellPaddingLeft
}
return tag
}
func (table *tableViewData) Get(tag string) interface{} { func (table *tableViewData) Get(tag string) interface{} {
return table.get(strings.ToLower(tag)) return table.get(table.normalizeTag(tag))
} }
func (table *tableViewData) Remove(tag string) { func (table *tableViewData) Remove(tag string) {
table.remove(strings.ToLower(tag)) table.remove(table.normalizeTag(tag))
} }
func (table *tableViewData) remove(tag string) { func (table *tableViewData) remove(tag string) {
switch tag { switch tag {
case CellPaddingTop, CellPaddingRight, CellPaddingBottom, CellPaddingLeft:
case CellPaddingTop, CellPaddingRight, CellPaddingBottom, CellPaddingLeft,
"top-cell-padding", "right-cell-padding", "bottom-cell-padding", "left-cell-padding":
table.removeBoundsSide(CellPadding, tag) table.removeBoundsSide(CellPadding, tag)
table.propertyChanged(tag)
case Gap, CellBorder, CellPadding, RowStyle, ColumnStyle, CellStyle, case Gap, CellBorder, CellPadding, RowStyle, ColumnStyle, CellStyle,
HeadHeight, HeadStyle, FootHeight, FootStyle: HeadHeight, HeadStyle, FootHeight, FootStyle:
delete(table.properties, tag) if _, ok := table.properties[tag]; ok {
delete(table.properties, tag)
table.propertyChanged(tag)
}
default: default:
table.viewData.remove(tag) table.viewData.remove(tag)
return
} }
table.propertyChanged(tag)
} }
func (table *tableViewData) Set(tag string, value interface{}) bool { func (table *tableViewData) Set(tag string, value interface{}) bool {
return table.set(strings.ToLower(tag), value) return table.set(table.normalizeTag(tag), value)
} }
func (table *tableViewData) set(tag string, value interface{}) bool { func (table *tableViewData) set(tag string, value interface{}) bool {
@ -307,8 +323,7 @@ func (table *tableViewData) set(tag string, value interface{}) bool {
return false return false
} }
case CellPaddingTop, CellPaddingRight, CellPaddingBottom, CellPaddingLeft, case CellPaddingTop, CellPaddingRight, CellPaddingBottom, CellPaddingLeft:
"top-cell-padding", "right-cell-padding", "bottom-cell-padding", "left-cell-padding":
if !table.setBoundsSide(CellPadding, tag, value) { if !table.setBoundsSide(CellPadding, tag, value) {
return false return false
} }
@ -336,26 +351,27 @@ func (table *tableViewData) set(tag string, value interface{}) bool {
} }
func (table *tableViewData) propertyChanged(tag string) { func (table *tableViewData) propertyChanged(tag string) {
switch tag { if table.created {
case Content, RowStyle, ColumnStyle, CellStyle, CellPadding, CellBorder, switch tag {
HeadHeight, HeadStyle, FootHeight, FootStyle, case Content, RowStyle, ColumnStyle, CellStyle, CellPadding, CellBorder,
CellPaddingTop, CellPaddingRight, CellPaddingBottom, CellPaddingLeft, HeadHeight, HeadStyle, FootHeight, FootStyle,
"top-cell-padding", "right-cell-padding", "bottom-cell-padding", "left-cell-padding": CellPaddingTop, CellPaddingRight, CellPaddingBottom, CellPaddingLeft:
table.ReloadTableData() table.ReloadTableData()
case Gap: case Gap:
htmlID := table.htmlID() htmlID := table.htmlID()
session := table.Session() session := table.Session()
gap, ok := sizeProperty(table, Gap, session) gap, ok := sizeProperty(table, Gap, session)
if !ok || gap.Type == Auto || gap.Value <= 0 { if !ok || gap.Type == Auto || gap.Value <= 0 {
updateCSSProperty(htmlID, "border-spacing", "0", session) updateCSSProperty(htmlID, "border-spacing", "0", session)
updateCSSProperty(htmlID, "border-collapse", "collapse", session) updateCSSProperty(htmlID, "border-collapse", "collapse", session)
} else { } else {
updateCSSProperty(htmlID, "border-spacing", gap.cssString("0"), session) updateCSSProperty(htmlID, "border-spacing", gap.cssString("0"), session)
updateCSSProperty(htmlID, "border-collapse", "separate", session) updateCSSProperty(htmlID, "border-collapse", "separate", session)
}
} }
} }
table.propertyChangedEvent(tag)
} }
func (table *tableViewData) htmlTag() string { func (table *tableViewData) htmlTag() string {

View File

@ -123,15 +123,26 @@ func (tabsLayout *tabsLayoutData) Remove(tag string) {
func (tabsLayout *tabsLayoutData) remove(tag string) { func (tabsLayout *tabsLayoutData) remove(tag string) {
switch tag { switch tag {
case CurrentTabChangedEvent: case CurrentTabChangedEvent:
tabsLayout.tabListener = []func(TabsLayout, int, int){} if len(tabsLayout.tabListener) > 0 {
tabsLayout.tabListener = []func(TabsLayout, int, int){}
tabsLayout.propertyChangedEvent(tag)
}
return
case TabCloseEvent: case TabCloseEvent:
tabsLayout.tabCloseListener = []func(TabsLayout, int){} if len(tabsLayout.tabCloseListener) > 0 {
tabsLayout.tabCloseListener = []func(TabsLayout, int){}
tabsLayout.propertyChangedEvent(tag)
}
return
case Current: case Current:
oldCurrent := tabsLayout.currentItem() oldCurrent := tabsLayout.currentItem()
delete(tabsLayout.properties, Current) delete(tabsLayout.properties, Current)
if !tabsLayout.session.ignoreViewUpdates() && oldCurrent != 0 { if oldCurrent == 0 {
return
}
if tabsLayout.created {
tabsLayout.session.runScript(fmt.Sprintf("activateTab(%v, %d);", tabsLayout.htmlID(), 0)) tabsLayout.session.runScript(fmt.Sprintf("activateTab(%v, %d);", tabsLayout.htmlID(), 0))
for _, listener := range tabsLayout.tabListener { for _, listener := range tabsLayout.tabListener {
listener(tabsLayout, 0, oldCurrent) listener(tabsLayout, 0, oldCurrent)
@ -140,7 +151,7 @@ func (tabsLayout *tabsLayoutData) remove(tag string) {
case Tabs: case Tabs:
delete(tabsLayout.properties, Tabs) delete(tabsLayout.properties, Tabs)
if !tabsLayout.session.ignoreViewUpdates() { if tabsLayout.created {
htmlID := tabsLayout.htmlID() htmlID := tabsLayout.htmlID()
updateProperty(htmlID, inactiveTabStyle, tabsLayout.inactiveTabStyle(), tabsLayout.session) updateProperty(htmlID, inactiveTabStyle, tabsLayout.inactiveTabStyle(), tabsLayout.session)
updateProperty(htmlID, activeTabStyle, tabsLayout.activeTabStyle(), tabsLayout.session) updateProperty(htmlID, activeTabStyle, tabsLayout.activeTabStyle(), tabsLayout.session)
@ -150,7 +161,7 @@ func (tabsLayout *tabsLayoutData) remove(tag string) {
case TabStyle, CurrentTabStyle: case TabStyle, CurrentTabStyle:
delete(tabsLayout.properties, tag) delete(tabsLayout.properties, tag)
if !tabsLayout.session.ignoreViewUpdates() { if tabsLayout.created {
htmlID := tabsLayout.htmlID() htmlID := tabsLayout.htmlID()
updateProperty(htmlID, inactiveTabStyle, tabsLayout.inactiveTabStyle(), tabsLayout.session) updateProperty(htmlID, inactiveTabStyle, tabsLayout.inactiveTabStyle(), tabsLayout.session)
updateProperty(htmlID, activeTabStyle, tabsLayout.activeTabStyle(), tabsLayout.session) updateProperty(htmlID, activeTabStyle, tabsLayout.activeTabStyle(), tabsLayout.session)
@ -159,13 +170,16 @@ func (tabsLayout *tabsLayoutData) remove(tag string) {
case TabCloseButton: case TabCloseButton:
delete(tabsLayout.properties, tag) delete(tabsLayout.properties, tag)
if !tabsLayout.session.ignoreViewUpdates() { if tabsLayout.created {
updateInnerHTML(tabsLayout.htmlID(), tabsLayout.session) updateInnerHTML(tabsLayout.htmlID(), tabsLayout.session)
} }
default: default:
tabsLayout.viewsContainerData.remove(tag) tabsLayout.viewsContainerData.remove(tag)
return
} }
tabsLayout.propertyChangedEvent(tag)
} }
func (tabsLayout *tabsLayoutData) Set(tag string, value interface{}) bool { func (tabsLayout *tabsLayoutData) Set(tag string, value interface{}) bool {
@ -201,13 +215,14 @@ func (tabsLayout *tabsLayoutData) set(tag string, value interface{}) bool {
return false return false
} }
if !tabsLayout.session.ignoreViewUpdates() { current := tabsLayout.currentItem()
current := tabsLayout.currentItem() if oldCurrent == current {
if oldCurrent != current { return true
tabsLayout.session.runScript(fmt.Sprintf("activateTab(%v, %d);", tabsLayout.htmlID(), current)) }
for _, listener := range tabsLayout.tabListener { if tabsLayout.created {
listener(tabsLayout, current, oldCurrent) tabsLayout.session.runScript(fmt.Sprintf("activateTab(%v, %d);", tabsLayout.htmlID(), current))
} for _, listener := range tabsLayout.tabListener {
listener(tabsLayout, current, oldCurrent)
} }
} }
@ -215,7 +230,7 @@ func (tabsLayout *tabsLayoutData) set(tag string, value interface{}) bool {
if !tabsLayout.setEnumProperty(Tabs, value, enumProperties[Tabs].values) { if !tabsLayout.setEnumProperty(Tabs, value, enumProperties[Tabs].values) {
return false return false
} }
if !tabsLayout.session.ignoreViewUpdates() { if tabsLayout.created {
htmlID := tabsLayout.htmlID() htmlID := tabsLayout.htmlID()
updateProperty(htmlID, inactiveTabStyle, tabsLayout.inactiveTabStyle(), tabsLayout.session) updateProperty(htmlID, inactiveTabStyle, tabsLayout.inactiveTabStyle(), tabsLayout.session)
updateProperty(htmlID, activeTabStyle, tabsLayout.activeTabStyle(), tabsLayout.session) updateProperty(htmlID, activeTabStyle, tabsLayout.activeTabStyle(), tabsLayout.session)
@ -235,7 +250,7 @@ func (tabsLayout *tabsLayoutData) set(tag string, value interface{}) bool {
return false return false
} }
if !tabsLayout.session.ignoreViewUpdates() { if tabsLayout.created {
htmlID := tabsLayout.htmlID() htmlID := tabsLayout.htmlID()
updateProperty(htmlID, inactiveTabStyle, tabsLayout.inactiveTabStyle(), tabsLayout.session) updateProperty(htmlID, inactiveTabStyle, tabsLayout.inactiveTabStyle(), tabsLayout.session)
updateProperty(htmlID, activeTabStyle, tabsLayout.activeTabStyle(), tabsLayout.session) updateProperty(htmlID, activeTabStyle, tabsLayout.activeTabStyle(), tabsLayout.session)
@ -246,7 +261,7 @@ func (tabsLayout *tabsLayoutData) set(tag string, value interface{}) bool {
if !tabsLayout.setBoolProperty(tag, value) { if !tabsLayout.setBoolProperty(tag, value) {
return false return false
} }
if !tabsLayout.session.ignoreViewUpdates() { if tabsLayout.created {
updateInnerHTML(tabsLayout.htmlID(), tabsLayout.session) updateInnerHTML(tabsLayout.htmlID(), tabsLayout.session)
} }
@ -254,6 +269,7 @@ func (tabsLayout *tabsLayoutData) set(tag string, value interface{}) bool {
return tabsLayout.viewsContainerData.set(tag, value) return tabsLayout.viewsContainerData.set(tag, value)
} }
tabsLayout.propertyChangedEvent(tag)
return true return true
} }
@ -905,6 +921,7 @@ func (tabsLayout *tabsLayoutData) handleCommand(self View, command string, data
for _, listener := range tabsLayout.tabListener { for _, listener := range tabsLayout.tabListener {
listener(tabsLayout, number, current) listener(tabsLayout, number, current)
} }
tabsLayout.propertyChangedEvent(Current)
} }
} }
} }

View File

@ -43,12 +43,14 @@ func (textView *textViewData) Remove(tag string) {
func (textView *textViewData) remove(tag string) { func (textView *textViewData) remove(tag string) {
textView.viewData.remove(tag) textView.viewData.remove(tag)
switch tag { if textView.created {
case Text: switch tag {
updateInnerHTML(textView.htmlID(), textView.session) case Text:
updateInnerHTML(textView.htmlID(), textView.session)
case TextOverflow: case TextOverflow:
textView.textOverflowUpdated() textView.textOverflowUpdated()
}
} }
} }
@ -90,16 +92,24 @@ func (textView *textViewData) set(tag string, value interface{}) bool {
return false return false
} }
} }
updateInnerHTML(textView.htmlID(), textView.session) if textView.created {
return true updateInnerHTML(textView.htmlID(), textView.session)
}
case TextOverflow: case TextOverflow:
if textView.viewData.set(tag, value) { if !textView.viewData.set(tag, value) {
return false
}
if textView.created {
textView.textOverflowUpdated() textView.textOverflowUpdated()
} }
default:
return textView.viewData.set(tag, value)
} }
return textView.viewData.set(tag, value) textView.propertyChangedEvent(tag)
return true
} }
func (textView *textViewData) textOverflowUpdated() { func (textView *textViewData) textOverflowUpdated() {

View File

@ -63,28 +63,47 @@ func (picker *timePickerData) remove(tag string) {
case TimeChangedEvent: case TimeChangedEvent:
if len(picker.timeChangedListeners) > 0 { if len(picker.timeChangedListeners) > 0 {
picker.timeChangedListeners = []func(TimePicker, time.Time){} picker.timeChangedListeners = []func(TimePicker, time.Time){}
picker.propertyChangedEvent(tag)
} }
return
case TimePickerMin: case TimePickerMin:
delete(picker.properties, TimePickerMin) delete(picker.properties, TimePickerMin)
removeProperty(picker.htmlID(), Min, picker.session) if picker.created {
removeProperty(picker.htmlID(), Min, picker.session)
}
case TimePickerMax: case TimePickerMax:
delete(picker.properties, TimePickerMax) delete(picker.properties, TimePickerMax)
removeProperty(picker.htmlID(), Max, picker.session) if picker.created {
removeProperty(picker.htmlID(), Max, picker.session)
}
case TimePickerStep: case TimePickerStep:
delete(picker.properties, TimePickerMax) delete(picker.properties, TimePickerMax)
removeProperty(picker.htmlID(), Step, picker.session) if picker.created {
removeProperty(picker.htmlID(), Step, picker.session)
}
case TimePickerValue: case TimePickerValue:
delete(picker.properties, TimePickerValue) if _, ok := picker.properties[TimePickerValue]; ok {
updateProperty(picker.htmlID(), Value, time.Now().Format(timeFormat), picker.session) delete(picker.properties, TimePickerValue)
time := GetTimePickerValue(picker, "")
if picker.created {
picker.session.runScript(fmt.Sprintf(`setInputValue('%s', '%s')`, picker.htmlID(), time.Format(timeFormat)))
}
for _, listener := range picker.timeChangedListeners {
listener(picker, time)
}
} else {
return
}
default: default:
picker.viewData.remove(tag) picker.viewData.remove(tag)
picker.propertyChanged(tag) return
} }
picker.propertyChangedEvent(tag)
} }
func (picker *timePickerData) Set(tag string, value interface{}) bool { func (picker *timePickerData) Set(tag string, value interface{}) bool {
@ -121,7 +140,10 @@ func (picker *timePickerData) set(tag string, value interface{}) bool {
old, oldOK := getTimeProperty(picker, TimePickerMin, Min) old, oldOK := getTimeProperty(picker, TimePickerMin, Min)
if time, ok := setTimeValue(TimePickerMin); ok { if time, ok := setTimeValue(TimePickerMin); ok {
if !oldOK || time != old { if !oldOK || time != old {
updateProperty(picker.htmlID(), Min, time.Format(timeFormat), picker.session) if picker.created {
updateProperty(picker.htmlID(), Min, time.Format(timeFormat), picker.session)
}
picker.propertyChangedEvent(tag)
} }
return true return true
} }
@ -130,7 +152,10 @@ func (picker *timePickerData) set(tag string, value interface{}) bool {
old, oldOK := getTimeProperty(picker, TimePickerMax, Max) old, oldOK := getTimeProperty(picker, TimePickerMax, Max)
if time, ok := setTimeValue(TimePickerMax); ok { if time, ok := setTimeValue(TimePickerMax); ok {
if !oldOK || time != old { if !oldOK || time != old {
updateProperty(picker.htmlID(), Max, time.Format(timeFormat), picker.session) if picker.created {
updateProperty(picker.htmlID(), Max, time.Format(timeFormat), picker.session)
}
picker.propertyChangedEvent(tag)
} }
return true return true
} }
@ -138,13 +163,15 @@ func (picker *timePickerData) set(tag string, value interface{}) bool {
case TimePickerStep: case TimePickerStep:
oldStep := GetTimePickerStep(picker, "") oldStep := GetTimePickerStep(picker, "")
if picker.setIntProperty(TimePickerStep, value) { if picker.setIntProperty(TimePickerStep, value) {
step := GetTimePickerStep(picker, "") if step := GetTimePickerStep(picker, ""); oldStep != step {
if oldStep != step { if picker.created {
if step > 0 { if step > 0 {
updateProperty(picker.htmlID(), Step, strconv.Itoa(step), picker.session) updateProperty(picker.htmlID(), Step, strconv.Itoa(step), picker.session)
} else { } else {
removeProperty(picker.htmlID(), Step, picker.session) removeProperty(picker.htmlID(), Step, picker.session)
}
} }
picker.propertyChangedEvent(tag)
} }
return true return true
} }
@ -152,11 +179,14 @@ func (picker *timePickerData) set(tag string, value interface{}) bool {
case TimePickerValue: case TimePickerValue:
oldTime := GetTimePickerValue(picker, "") oldTime := GetTimePickerValue(picker, "")
if time, ok := setTimeValue(TimePickerMax); ok { if time, ok := setTimeValue(TimePickerMax); ok {
picker.session.runScript(fmt.Sprintf(`setInputValue('%s', '%s')`, picker.htmlID(), time.Format(timeFormat)))
if time != oldTime { if time != oldTime {
if picker.created {
picker.session.runScript(fmt.Sprintf(`setInputValue('%s', '%s')`, picker.htmlID(), time.Format(timeFormat)))
}
for _, listener := range picker.timeChangedListeners { for _, listener := range picker.timeChangedListeners {
listener(picker, time) listener(picker, time)
} }
picker.propertyChangedEvent(tag)
} }
return true return true
} }
@ -167,8 +197,8 @@ func (picker *timePickerData) set(tag string, value interface{}) bool {
picker.timeChangedListeners = []func(TimePicker, time.Time){value} picker.timeChangedListeners = []func(TimePicker, time.Time){value}
case func(time.Time): case func(time.Time):
fn := func(view TimePicker, date time.Time) { fn := func(view TimePicker, time time.Time) {
value(date) value(time)
} }
picker.timeChangedListeners = []func(TimePicker, time.Time){fn} picker.timeChangedListeners = []func(TimePicker, time.Time){fn}
@ -183,8 +213,8 @@ func (picker *timePickerData) set(tag string, value interface{}) bool {
return false return false
} }
listeners[i] = func(view TimePicker, date time.Time) { listeners[i] = func(view TimePicker, time time.Time) {
val(date) val(time)
} }
} }
picker.timeChangedListeners = listeners picker.timeChangedListeners = listeners
@ -202,8 +232,8 @@ func (picker *timePickerData) set(tag string, value interface{}) bool {
listeners[i] = val listeners[i] = val
case func(time.Time): case func(time.Time):
listeners[i] = func(view TimePicker, date time.Time) { listeners[i] = func(view TimePicker, time time.Time) {
val(date) val(time)
} }
default: default:
@ -213,13 +243,11 @@ func (picker *timePickerData) set(tag string, value interface{}) bool {
} }
picker.timeChangedListeners = listeners picker.timeChangedListeners = listeners
} }
picker.propertyChangedEvent(tag)
return true return true
default: default:
if picker.viewData.set(tag, value) { return picker.viewData.set(tag, value)
picker.propertyChanged(tag)
return true
}
} }
return false return false
} }
@ -273,7 +301,7 @@ func (picker *timePickerData) htmlProperties(self View, buffer *strings.Builder)
} }
func (picker *timePickerData) htmlDisabledProperties(self View, buffer *strings.Builder) { func (picker *timePickerData) htmlDisabledProperties(self View, buffer *strings.Builder) {
if IsDisabled(self) { if IsDisabled(self, "") {
buffer.WriteString(` disabled`) buffer.WriteString(` disabled`)
} }
picker.viewData.htmlDisabledProperties(self, buffer) picker.viewData.htmlDisabledProperties(self, buffer)

150
view.go
View File

@ -57,6 +57,8 @@ type View interface {
// a description of the error is written to the log // a description of the error is written to the log
SetAnimated(tag string, value interface{}, animation Animation) bool SetAnimated(tag string, value interface{}, animation Animation) bool
SetChangeListener(tag string, listener func(View, string))
handleCommand(self View, command string, data DataObject) bool handleCommand(self View, command string, data DataObject) bool
//updateEventHandlers() //updateEventHandlers()
htmlClass(disabled bool) string htmlClass(disabled bool) string
@ -87,6 +89,7 @@ type viewData struct {
_htmlID string _htmlID string
parentID string parentID string
systemClass string systemClass string
changeListener map[string]func(View, string)
singleTransition map[string]Animation singleTransition map[string]Animation
addCSS map[string]string addCSS map[string]string
frame Frame frame Frame
@ -129,6 +132,7 @@ func (view *viewData) Init(session Session) {
view.viewStyle.init() view.viewStyle.init()
view.tag = "View" view.tag = "View"
view.session = session view.session = session
view.changeListener = map[string]func(View, string){}
view.addCSS = map[string]string{} view.addCSS = map[string]string{}
//view.animation = map[string]AnimationEndListener{} //view.animation = map[string]AnimationEndListener{}
view.singleTransition = map[string]Animation{} view.singleTransition = map[string]Animation{}
@ -186,7 +190,7 @@ func (view *viewData) remove(tag string) {
case Style, StyleDisabled: case Style, StyleDisabled:
if _, ok := view.properties[tag]; ok { if _, ok := view.properties[tag]; ok {
delete(view.properties, tag) delete(view.properties, tag)
updateProperty(view.htmlID(), "class", view.htmlClass(IsDisabled(view)), view.session) updateProperty(view.htmlID(), "class", view.htmlClass(IsDisabled(view, "")), view.session)
} }
case FocusEvent, LostFocusEvent: case FocusEvent, LostFocusEvent:
@ -221,8 +225,62 @@ func (view *viewData) remove(tag string) {
default: default:
view.viewStyle.remove(tag) view.viewStyle.remove(tag)
view.propertyChanged(tag) viewPropertyChanged(view, tag)
} }
view.propertyChangedEvent(tag)
}
func (view *viewData) propertyChangedEvent(tag string) {
if listener, ok := view.changeListener[tag]; ok {
listener(view, tag)
}
switch tag {
case BorderLeft, BorderRight, BorderTop, BorderBottom,
BorderStyle, BorderLeftStyle, BorderRightStyle, BorderTopStyle, BorderBottomStyle,
BorderColor, BorderLeftColor, BorderRightColor, BorderTopColor, BorderBottomColor,
BorderWidth, BorderLeftWidth, BorderRightWidth, BorderTopWidth, BorderBottomWidth:
tag = Border
case CellBorderStyle, CellBorderColor, CellBorderWidth,
CellBorderLeft, CellBorderLeftStyle, CellBorderLeftColor, CellBorderLeftWidth,
CellBorderRight, CellBorderRightStyle, CellBorderRightColor, CellBorderRightWidth,
CellBorderTop, CellBorderTopStyle, CellBorderTopColor, CellBorderTopWidth,
CellBorderBottom, CellBorderBottomStyle, CellBorderBottomColor, CellBorderBottomWidth:
tag = CellBorder
case OutlineColor, OutlineStyle, OutlineWidth:
tag = Outline
case RadiusX, RadiusY, RadiusTopLeft, RadiusTopLeftX, RadiusTopLeftY,
RadiusTopRight, RadiusTopRightX, RadiusTopRightY,
RadiusBottomLeft, RadiusBottomLeftX, RadiusBottomLeftY,
RadiusBottomRight, RadiusBottomRightX, RadiusBottomRightY:
tag = Radius
case MarginTop, MarginRight, MarginBottom, MarginLeft,
"top-margin", "right-margin", "bottom-margin", "left-margin":
tag = Margin
case PaddingTop, PaddingRight, PaddingBottom, PaddingLeft,
"top-padding", "right-padding", "bottom-padding", "left-padding":
tag = Padding
case CellPaddingTop, CellPaddingRight, CellPaddingBottom, CellPaddingLeft:
tag = CellPadding
case ColumnSeparatorStyle, ColumnSeparatorWidth, ColumnSeparatorColor:
tag = ColumnSeparator
default:
return
}
if listener, ok := view.changeListener[tag]; ok {
listener(view, tag)
}
} }
func (view *viewData) Set(tag string, value interface{}) bool { func (view *viewData) Set(tag string, value interface{}) bool {
@ -235,64 +293,71 @@ func (view *viewData) set(tag string, value interface{}) bool {
return true return true
} }
result := func(res bool) bool {
if res {
view.propertyChangedEvent(tag)
}
return res
}
switch tag { switch tag {
case ID: case ID:
if text, ok := value.(string); ok { text, ok := value.(string)
view.viewID = text if !ok {
return true notCompatibleType(ID, value)
return false
} }
notCompatibleType(ID, value) view.viewID = text
return false
case Style, StyleDisabled: case Style, StyleDisabled:
if text, ok := value.(string); ok { text, ok := value.(string)
view.properties[tag] = text if !ok {
//updateInnerHTML(view.parentID, view.session) notCompatibleType(ID, value)
if view.created { return false
updateProperty(view.htmlID(), "class", view.htmlClass(IsDisabled(view)), view.session) }
} view.properties[tag] = text
return true if view.created {
updateProperty(view.htmlID(), "class", view.htmlClass(IsDisabled(view, "")), view.session)
} }
notCompatibleType(ID, value)
return false
case FocusEvent, LostFocusEvent: case FocusEvent, LostFocusEvent:
return view.setFocusListener(tag, value) return result(view.setFocusListener(tag, value))
case KeyDownEvent, KeyUpEvent: case KeyDownEvent, KeyUpEvent:
return view.setKeyListener(tag, value) return result(view.setKeyListener(tag, value))
case ClickEvent, DoubleClickEvent, MouseDown, MouseUp, MouseMove, MouseOut, MouseOver, ContextMenuEvent: case ClickEvent, DoubleClickEvent, MouseDown, MouseUp, MouseMove, MouseOut, MouseOver, ContextMenuEvent:
return view.setMouseListener(tag, value) return result(view.setMouseListener(tag, value))
case PointerDown, PointerUp, PointerMove, PointerOut, PointerOver, PointerCancel: case PointerDown, PointerUp, PointerMove, PointerOut, PointerOver, PointerCancel:
return view.setPointerListener(tag, value) return result(view.setPointerListener(tag, value))
case TouchStart, TouchEnd, TouchMove, TouchCancel: case TouchStart, TouchEnd, TouchMove, TouchCancel:
return view.setTouchListener(tag, value) return result(view.setTouchListener(tag, value))
case TransitionRunEvent, TransitionStartEvent, TransitionEndEvent, TransitionCancelEvent: case TransitionRunEvent, TransitionStartEvent, TransitionEndEvent, TransitionCancelEvent:
return view.setTransitionListener(tag, value) return result(view.setTransitionListener(tag, value))
case AnimationStartEvent, AnimationEndEvent, AnimationIterationEvent, AnimationCancelEvent: case AnimationStartEvent, AnimationEndEvent, AnimationIterationEvent, AnimationCancelEvent:
return view.setAnimationListener(tag, value) return result(view.setAnimationListener(tag, value))
case ResizeEvent, ScrollEvent: case ResizeEvent, ScrollEvent:
return view.setFrameListener(tag, value) return result(view.setFrameListener(tag, value))
}
if view.viewStyle.set(tag, value) { default:
if view.created { if !view.viewStyle.set(tag, value) {
view.propertyChanged(tag) return false
}
if view.created {
viewPropertyChanged(view, tag)
} }
return true
} }
return false view.propertyChangedEvent(tag)
return true
} }
func (view *viewData) propertyChanged(tag string) { func viewPropertyChanged(view *viewData, tag string) {
if view.updateTransformProperty(tag) { if view.updateTransformProperty(tag) {
return return
} }
@ -446,7 +511,7 @@ func (view *viewData) propertyChanged(tag string) {
case Strikethrough, Overline, Underline: case Strikethrough, Overline, Underline:
updateCSSProperty(htmlID, "text-decoration", view.cssTextDecoration(session), session) updateCSSProperty(htmlID, "text-decoration", view.cssTextDecoration(session), session)
for _, tag2 := range []string{TextLineColor, TextLineStyle, TextLineThickness} { for _, tag2 := range []string{TextLineColor, TextLineStyle, TextLineThickness} {
view.propertyChanged(tag2) viewPropertyChanged(view, tag2)
} }
return return
@ -568,7 +633,7 @@ func (view *viewData) htmlProperties(self View, buffer *strings.Builder) {
} }
func (view *viewData) htmlDisabledProperties(self View, buffer *strings.Builder) { func (view *viewData) htmlDisabledProperties(self View, buffer *strings.Builder) {
if IsDisabled(self) { if IsDisabled(self, "") {
buffer.WriteString(` data-disabled="1"`) buffer.WriteString(` data-disabled="1"`)
} else { } else {
buffer.WriteString(` data-disabled="0"`) buffer.WriteString(` data-disabled="0"`)
@ -583,7 +648,7 @@ func viewHTML(view View, buffer *strings.Builder) {
buffer.WriteString(view.htmlID()) buffer.WriteString(view.htmlID())
buffer.WriteRune('"') buffer.WriteRune('"')
disabled := IsDisabled(view) disabled := IsDisabled(view, "")
if cls := view.htmlClass(disabled); cls != "" { if cls := view.htmlClass(disabled); cls != "" {
buffer.WriteString(` class="`) buffer.WriteString(` class="`)
@ -660,7 +725,7 @@ func (view *viewData) handleCommand(self View, command string, data DataObject)
switch command { switch command {
case KeyDownEvent, KeyUpEvent: case KeyDownEvent, KeyUpEvent:
if !IsDisabled(self) { if !IsDisabled(self, "") {
handleKeyEvents(self, command, data) handleKeyEvents(self, command, data)
} }
@ -767,13 +832,10 @@ func (view *viewData) String() string {
return writer.finish() return writer.finish()
} }
// IsDisabled returns "true" if the view is disabled func (view *viewData) SetChangeListener(tag string, listener func(View, string)) {
func IsDisabled(view View) bool { if listener == nil {
if disabled, _ := boolProperty(view, Disabled, view.Session()); disabled { delete(view.changeListener, tag)
return true } else {
view.changeListener[tag] = listener
} }
if parent := view.Parent(); parent != nil {
return IsDisabled(parent)
}
return false
} }

View File

@ -4,7 +4,13 @@ package rui
// The type of return value depends on the property. // The type of return value depends on the property.
// If the subview don't exists or the property is not set then nil is returned. // If the subview don't exists or the property is not set then nil is returned.
func Get(rootView View, viewID, tag string) interface{} { func Get(rootView View, viewID, tag string) interface{} {
if view := ViewByID(rootView, viewID); view != nil { var view View
if viewID != "" {
view = ViewByID(rootView, viewID)
} else {
view = rootView
}
if view != nil {
return view.Get(tag) return view.Get(tag)
} }
return nil return nil
@ -14,12 +20,29 @@ func Get(rootView View, viewID, tag string) interface{} {
// true - success, // true - success,
// false - error (incompatible type or invalid format of a string value, see AppLog). // false - error (incompatible type or invalid format of a string value, see AppLog).
func Set(rootView View, viewID, tag string, value interface{}) bool { func Set(rootView View, viewID, tag string, value interface{}) bool {
if view := ViewByID(rootView, viewID); view != nil { var view View
if viewID != "" {
view = ViewByID(rootView, viewID)
} else {
view = rootView
}
if view != nil {
return view.Set(tag, value) return view.Set(tag, value)
} }
return false return false
} }
// SetChangeListener sets a listener for changing a subview property value.
// If the second argument (subviewID) is "" then a listener for the first argument (view) is set
func SetChangeListener(view View, viewID, tag string, listener func(View, string)) {
if viewID != "" {
view = ViewByID(view, viewID)
}
if view != nil {
view.SetChangeListener(tag, listener)
}
}
// SetParams sets properties with name "tag" of the "rootView" subview. Result: // SetParams sets properties with name "tag" of the "rootView" subview. Result:
// true - all properties were set successful, // true - all properties were set successful,
// false - error (incompatible type or invalid format of a string value, see AppLog). // false - error (incompatible type or invalid format of a string value, see AppLog).
@ -36,6 +59,22 @@ func SetParams(rootView View, viewID string, params Params) bool {
return result return result
} }
// IsDisabled returns "true" if the subview is disabled
// If the second argument (subviewID) is "" then a state of the first argument (view) is returned
func IsDisabled(view View, subviewID string) bool {
if subviewID != "" {
view = ViewByID(view, subviewID)
}
if disabled, _ := boolProperty(view, Disabled, view.Session()); disabled {
return true
}
if parent := view.Parent(); parent != nil {
return IsDisabled(parent, "")
}
return false
}
// GetSemantics returns the subview semantics. Valid semantics values are // GetSemantics returns the subview semantics. Valid semantics values are
// DefaultSemantics (0), ArticleSemantics (1), SectionSemantics (2), AsideSemantics (3), // DefaultSemantics (0), ArticleSemantics (1), SectionSemantics (2), AsideSemantics (3),
// HeaderSemantics (4), MainSemantics (5), FooterSemantics (6), NavigationSemantics (7), // HeaderSemantics (4), MainSemantics (5), FooterSemantics (6), NavigationSemantics (7),
@ -926,7 +965,7 @@ func valueFromStyle(view View, tag string) (string, bool) {
return "", false return "", false
} }
if IsDisabled(view) { if IsDisabled(view, "") {
if value, ok := getValue(StyleDisabled); ok { if value, ok := getValue(StyleDisabled); ok {
return value, true return value, true
} }

View File

@ -39,16 +39,6 @@ func (container *viewsContainerData) setParentID(parentID string) {
} }
} }
// SetDisabled set the View disabled state
func (container *viewsContainerData) SetDisabled(disabled bool) {
container.viewData.Set(Disabled, disabled)
if container.views != nil {
for _, view := range container.views {
view.Set(Disabled, disabled)
}
}
}
// Views return a list of child views // Views return a list of child views
func (container *viewsContainerData) Views() []View { func (container *viewsContainerData) Views() []View {
if container.views == nil { if container.views == nil {
@ -68,6 +58,7 @@ func (container *viewsContainerData) Append(view View) {
container.views = append(container.views, view) container.views = append(container.views, view)
} }
updateInnerHTML(container.htmlID(), container.session) updateInnerHTML(container.htmlID(), container.session)
container.propertyChangedEvent(Content)
} }
} }
@ -81,10 +72,12 @@ func (container *viewsContainerData) Insert(view View, index uint) {
view.setParentID(htmlID) view.setParentID(htmlID)
container.views = append(container.views[:index], append([]View{view}, container.views[index:]...)...) container.views = append(container.views[:index], append([]View{view}, container.views[index:]...)...)
updateInnerHTML(container.htmlID(), container.session) updateInnerHTML(container.htmlID(), container.session)
container.propertyChangedEvent(Content)
} else { } else {
view.setParentID(htmlID) view.setParentID(htmlID)
container.views = append([]View{view}, container.views...) container.views = append([]View{view}, container.views...)
updateInnerHTML(container.htmlID(), container.session) updateInnerHTML(container.htmlID(), container.session)
container.propertyChangedEvent(Content)
} }
} }
} }
@ -112,6 +105,7 @@ func (container *viewsContainerData) RemoveView(index uint) View {
view.setParentID("") view.setParentID("")
updateInnerHTML(container.htmlID(), container.session) updateInnerHTML(container.htmlID(), container.session)
container.propertyChangedEvent(Content)
return view return view
} }
@ -151,6 +145,18 @@ func (container *viewsContainerData) remove(tag string) {
container.views = []View{} container.views = []View{}
updateInnerHTML(container.htmlID(), container.Session()) updateInnerHTML(container.htmlID(), container.Session())
} }
container.propertyChangedEvent(Content)
case Disabled:
if _, ok := container.properties[Disabled]; ok {
delete(container.properties, Disabled)
if container.views != nil {
for _, view := range container.views {
view.Remove(Disabled)
}
}
container.propertyChangedEvent(tag)
}
default: default:
container.viewData.remove(tag) container.viewData.remove(tag)
@ -167,7 +173,27 @@ func (container *viewsContainerData) set(tag string, value interface{}) bool {
return true return true
} }
if tag != Content { switch tag {
case Content:
// do nothing
case Disabled:
oldDisabled := IsDisabled(container, "")
if container.viewData.Set(Disabled, value) {
disabled := IsDisabled(container, "")
if oldDisabled != disabled {
if container.views != nil {
for _, view := range container.views {
view.Set(Disabled, disabled)
}
}
}
container.propertyChangedEvent(tag)
return true
}
return false
default:
return container.viewData.set(tag, value) return container.viewData.set(tag, value)
} }
@ -239,6 +265,8 @@ func (container *viewsContainerData) set(tag string, value interface{}) bool {
if container.created { if container.created {
updateInnerHTML(htmlID, container.session) updateInnerHTML(htmlID, container.session)
} }
container.propertyChangedEvent(Content)
return true return true
} }