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 {
canvasView.drawer = nil
canvasView.Redraw()
canvasView.propertyChangedEvent(tag)
} else {
canvasView.viewData.remove(tag)
}
@ -73,6 +74,7 @@ func (canvasView *canvasViewData) set(tag string, value interface{}) bool {
return false
}
canvasView.Redraw()
canvasView.propertyChangedEvent(tag)
return true
}

View File

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

View File

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

View File

@ -82,12 +82,14 @@ func (columnLayout *columnLayoutData) Remove(tag string) {
func (columnLayout *columnLayoutData) remove(tag string) {
columnLayout.viewsContainerData.remove(tag)
switch tag {
case ColumnCount, ColumnWidth, ColumnGap:
updateCSSProperty(columnLayout.htmlID(), tag, "", columnLayout.Session())
if columnLayout.created {
switch tag {
case ColumnCount, ColumnWidth, ColumnGap:
updateCSSProperty(columnLayout.htmlID(), tag, "", columnLayout.Session())
case ColumnSeparator:
updateCSSProperty(columnLayout.htmlID(), "column-rule", "", columnLayout.Session())
case ColumnSeparator:
updateCSSProperty(columnLayout.htmlID(), "column-rule", "", columnLayout.Session())
}
}
}
@ -101,22 +103,11 @@ func (columnLayout *columnLayoutData) set(tag string, value interface{}) bool {
return true
}
switch tag {
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
}
if !columnLayout.viewsContainerData.set(tag, value) {
return false
}
ok := columnLayout.viewsContainerData.set(tag, value)
if ok {
if columnLayout.created {
switch tag {
case ColumnSeparator:
css := ""
@ -126,9 +117,17 @@ func (columnLayout *columnLayoutData) set(tag string, value interface{}) bool {
css = separator.cssValue(columnLayout.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

View File

@ -68,6 +68,10 @@ func (customView *CustomViewData) SetAnimated(tag string, value interface{}, ani
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
func (customView *CustomViewData) Remove(tag string) {
customView.superView.Remove(tag)

View File

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

View File

@ -57,14 +57,24 @@ func createTextStyleDemo(session rui.Session) rui.View {
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"}
if number > 0 && number < len(fonts) {
if number := rui.GetDropDownCurrent(v, ""); number > 0 && number < len(fonts) {
rui.Set(view, "textStyleText", rui.FontName, fonts[number])
} else {
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) {
sizes := []string{"1em", "14pt", "12px", "1.5em"}

View File

@ -2,6 +2,8 @@ package rui
import "strings"
// TODO Expanded event
const (
// Summary is the constant for the "summary" property tag.
// 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) {
if _, ok := detailsView.properties[tag]; ok {
detailsView.viewsContainerData.remove(tag)
if detailsView.created {
switch tag {
case Summary:
delete(detailsView.properties, tag)
updateInnerHTML(detailsView.htmlID(), detailsView.Session())
case Expanded:
delete(detailsView.properties, tag)
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 {
if value == nil {
detailsView.remove(tag)
return true
}
switch tag {
case Summary:
switch value := value.(type) {
@ -86,23 +89,29 @@ func (detailsView *detailsViewData) set(tag string, value interface{}) bool {
notCompatibleType(tag, value)
return false
}
updateInnerHTML(detailsView.htmlID(), detailsView.Session())
return true
if detailsView.created {
updateInnerHTML(detailsView.htmlID(), detailsView.Session())
}
case Expanded:
if detailsView.setBoolProperty(tag, value) {
if !detailsView.setBoolProperty(tag, value) {
notCompatibleType(tag, value)
return false
}
if detailsView.created {
if IsDetailsExpanded(detailsView, "") {
updateProperty(detailsView.htmlID(), "open", "", detailsView.Session())
} else {
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{} {

View File

@ -48,19 +48,31 @@ func (list *dropDownListData) remove(tag string) {
case Items:
if len(list.items) > 0 {
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:
if len(list.dropDownListener) > 0 {
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:
list.viewData.remove(tag)
return
}
}
@ -73,23 +85,22 @@ func (list *dropDownListData) set(tag string, value interface{}) bool {
case Items:
return list.setItems(value)
case DropDownEvent:
return list.setDropDownListener(value)
case Current:
oldCurrent := GetDropDownCurrent(list, "")
if !list.setIntProperty(Current, value) {
return false
}
if !list.session.ignoreViewUpdates() {
current := GetDropDownCurrent(list, "")
if oldCurrent != current {
if current := GetDropDownCurrent(list, ""); oldCurrent != current {
if list.created {
list.session.runScript(fmt.Sprintf(`selectDropDownListItem('%s', %d)`, list.htmlID(), current))
list.onSelectedItemChanged(current)
}
list.onSelectedItemChanged(current)
}
return true
case DropDownEvent:
return list.setDropDownListener(value)
}
return list.viewData.set(tag, value)
@ -160,9 +171,11 @@ func (list *dropDownListData) setItems(value interface{}) bool {
return false
}
if !list.session.ignoreViewUpdates() {
if list.created {
updateInnerHTML(list.htmlID(), list.session)
}
list.propertyChangedEvent(Items)
return true
}
@ -170,17 +183,14 @@ func (list *dropDownListData) setDropDownListener(value interface{}) bool {
switch value := value.(type) {
case func(DropDownList, int):
list.dropDownListener = []func(DropDownList, int){value}
return true
case func(int):
list.dropDownListener = []func(DropDownList, int){func(list DropDownList, index int) {
value(index)
}}
return true
case []func(DropDownList, int):
list.dropDownListener = value
return true
case []func(int):
listeners := make([]func(DropDownList, int), len(value))
@ -194,7 +204,6 @@ func (list *dropDownListData) setDropDownListener(value interface{}) bool {
}
}
list.dropDownListener = listeners
return true
case []interface{}:
listeners := make([]func(DropDownList, int), len(value))
@ -216,13 +225,16 @@ func (list *dropDownListData) setDropDownListener(value interface{}) bool {
notCompatibleType(DropDownEvent, value)
return false
}
list.dropDownListener = listeners
}
return true
list.dropDownListener = listeners
default:
notCompatibleType(DropDownEvent, value)
return false
}
notCompatibleType(DropDownEvent, value)
return false
list.propertyChangedEvent(DropDownEvent)
return true
}
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) {
list.viewData.htmlDisabledProperties(self, buffer)
if IsDisabled(list) {
if IsDisabled(list, "") {
buffer.WriteString(`disabled`)
}
}
@ -289,6 +301,7 @@ func (list *dropDownListData) onSelectedItemChanged(number int) {
for _, listener := range list.dropDownListener {
listener(list, number)
}
list.propertyChangedEvent(Current)
}
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) {
if _, ok := edit.properties[tag]; ok {
switch tag {
case Hint:
_, exists := edit.properties[tag]
switch tag {
case Hint:
if exists {
delete(edit.properties, Hint)
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){}
if edit.created {
removeProperty(edit.htmlID(), "placeholder", edit.session)
}
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, "")
delete(edit.properties, tag)
if oldText != "" {
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, "")
delete(edit.properties, tag)
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, "")
delete(edit.properties, tag)
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, "")
delete(edit.properties, tag)
if GetEditViewType(edit, "") == MultiLineText {
if wrap := IsEditViewWrap(edit, ""); wrap != oldWrap {
if wrap {
updateProperty(edit.htmlID(), "wrap", "soft", edit.session)
} else {
updateProperty(edit.htmlID(), "wrap", "off", edit.session)
if edit.created {
if wrap {
updateProperty(edit.htmlID(), "wrap", "soft", 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
if text = GetText(edit, ""); oldText != text {
edit.textChanged(text)
if GetEditViewType(edit, "") == MultiLineText {
updateInnerHTML(edit.htmlID(), edit.Session())
} else {
text = strings.ReplaceAll(text, `"`, `\"`)
text = strings.ReplaceAll(text, `'`, `\'`)
text = strings.ReplaceAll(text, "\n", `\n`)
text = strings.ReplaceAll(text, "\r", `\r`)
edit.session.runScript(fmt.Sprintf(`setInputValue('%s', '%s')`, edit.htmlID(), text))
if edit.created {
if GetEditViewType(edit, "") == MultiLineText {
updateInnerHTML(edit.htmlID(), edit.Session())
} else {
text = strings.ReplaceAll(text, `"`, `\"`)
text = strings.ReplaceAll(text, `'`, `\'`)
text = strings.ReplaceAll(text, "\n", `\n`)
text = strings.ReplaceAll(text, "\r", `\r`)
edit.session.runScript(fmt.Sprintf(`setInputValue('%s', '%s')`, edit.htmlID(), text))
}
}
}
return true
@ -180,11 +217,14 @@ func (edit *editViewData) set(tag string, value interface{}) bool {
if text, ok := value.(string); ok {
edit.properties[Hint] = text
if text = GetHint(edit, ""); oldText != text {
if text != "" {
updateProperty(edit.htmlID(), "placeholder", text, edit.session)
} else {
removeProperty(edit.htmlID(), "placeholder", edit.session)
if edit.created {
if text != "" {
updateProperty(edit.htmlID(), "placeholder", text, edit.session)
} else {
removeProperty(edit.htmlID(), "placeholder", edit.session)
}
}
edit.propertyChangedEvent(tag)
}
return true
}
@ -194,11 +234,14 @@ func (edit *editViewData) set(tag string, value interface{}) bool {
oldMaxLength := GetMaxLength(edit, "")
if edit.setIntProperty(MaxLength, value) {
if maxLength := GetMaxLength(edit, ""); maxLength != oldMaxLength {
if maxLength > 0 {
updateProperty(edit.htmlID(), "maxlength", strconv.Itoa(maxLength), edit.session)
} else {
removeProperty(edit.htmlID(), "maxlength", edit.session)
if edit.created {
if maxLength > 0 {
updateProperty(edit.htmlID(), "maxlength", strconv.Itoa(maxLength), edit.session)
} else {
removeProperty(edit.htmlID(), "maxlength", edit.session)
}
}
edit.propertyChangedEvent(tag)
}
return true
}
@ -206,18 +249,24 @@ func (edit *editViewData) set(tag string, value interface{}) bool {
case ReadOnly:
if edit.setBoolProperty(ReadOnly, value) {
if IsReadOnly(edit, "") {
updateProperty(edit.htmlID(), ReadOnly, "", edit.session)
} else {
removeProperty(edit.htmlID(), ReadOnly, edit.session)
if edit.created {
if IsReadOnly(edit, "") {
updateProperty(edit.htmlID(), ReadOnly, "", edit.session)
} else {
removeProperty(edit.htmlID(), ReadOnly, edit.session)
}
}
edit.propertyChangedEvent(tag)
return true
}
return false
case Spellcheck:
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 false
@ -227,11 +276,14 @@ func (edit *editViewData) set(tag string, value interface{}) bool {
if text, ok := value.(string); ok {
edit.properties[Pattern] = text
if text = GetEditViewPattern(edit, ""); oldText != text {
if text != "" {
updateProperty(edit.htmlID(), Pattern, text, edit.session)
} else {
removeProperty(edit.htmlID(), Pattern, edit.session)
if edit.created {
if text != "" {
updateProperty(edit.htmlID(), Pattern, text, edit.session)
} else {
removeProperty(edit.htmlID(), Pattern, edit.session)
}
}
edit.propertyChangedEvent(tag)
}
return true
}
@ -241,7 +293,10 @@ func (edit *editViewData) set(tag string, value interface{}) bool {
oldType := GetEditViewType(edit, "")
if edit.setEnumProperty(EditViewType, value, enumProperties[EditViewType].values) {
if GetEditViewType(edit, "") != oldType {
updateInnerHTML(edit.parentHTMLID(), edit.session)
if edit.created {
updateInnerHTML(edit.parentHTMLID(), edit.session)
}
edit.propertyChangedEvent(tag)
}
return true
}
@ -252,11 +307,14 @@ func (edit *editViewData) set(tag string, value interface{}) bool {
if edit.setBoolProperty(Wrap, value) {
if GetEditViewType(edit, "") == MultiLineText {
if wrap := IsEditViewWrap(edit, ""); wrap != oldWrap {
if wrap {
updateProperty(edit.htmlID(), "wrap", "soft", edit.session)
} else {
updateProperty(edit.htmlID(), "wrap", "off", edit.session)
if edit.created {
if wrap {
updateProperty(edit.htmlID(), "wrap", "soft", edit.session)
} else {
updateProperty(edit.htmlID(), "wrap", "off", edit.session)
}
}
edit.propertyChangedEvent(tag)
}
}
return true
@ -268,6 +326,7 @@ func (edit *editViewData) set(tag string, value interface{}) bool {
if !ok {
notCompatibleType(tag, value)
}
edit.propertyChangedEvent(tag)
return ok
}
@ -363,6 +422,7 @@ func (edit *editViewData) textChanged(newText string) {
for _, listener := range edit.textChangeListeners {
listener(edit, newText)
}
edit.propertyChangedEvent(Text)
}
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) {
if IsDisabled(self) {
if IsDisabled(self, "") {
buffer.WriteString(` disabled`)
}
edit.viewData.htmlDisabledProperties(self, buffer)

View File

@ -114,7 +114,17 @@ func (picker *filePickerData) Remove(tag string) {
func (picker *filePickerData) remove(tag string) {
switch tag {
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:
picker.viewData.remove(tag)
@ -184,6 +194,7 @@ func (picker *filePickerData) set(tag string, value interface{}) bool {
}
picker.fileSelectedListeners = listeners
}
picker.propertyChangedEvent(tag)
return true
case Accept:
@ -218,6 +229,15 @@ func (picker *filePickerData) set(tag string, value interface{}) bool {
notCompatibleType(tag, value)
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
default:
@ -271,7 +291,7 @@ func (picker *filePickerData) htmlProperties(self View, buffer *strings.Builder)
}
func (picker *filePickerData) htmlDisabledProperties(self View, buffer *strings.Builder) {
if IsDisabled(self) {
if IsDisabled(self, "") {
buffer.WriteString(` disabled`)
}
picker.viewData.htmlDisabledProperties(self, buffer)

View File

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

View File

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

View File

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

View File

@ -55,9 +55,11 @@ func (listLayout *listLayoutData) Remove(tag string) {
func (listLayout *listLayoutData) remove(tag string) {
listLayout.viewsContainerData.remove(tag)
switch tag {
case Orientation, Wrap, HorizontalAlign, VerticalAlign:
updateCSSStyle(listLayout.htmlID(), listLayout.session)
if listLayout.created {
switch tag {
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) {
switch tag {
case Orientation, Wrap, HorizontalAlign, VerticalAlign:
updateCSSStyle(listLayout.htmlID(), listLayout.session)
if listLayout.created {
switch tag {
case Orientation, Wrap, HorizontalAlign, VerticalAlign:
updateCSSStyle(listLayout.htmlID(), listLayout.session)
}
}
return true
}

View File

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

View File

@ -173,20 +173,8 @@ func (player *mediaPlayerData) Remove(tag string) {
}
func (player *mediaPlayerData) remove(tag string) {
switch 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)
}
player.viewData.remove(tag)
player.propertyChanged(tag)
}
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.propertyChanged(tag)
player.propertyChangedEvent(tag)
return true
}
notCompatibleType(tag, value)
@ -228,6 +217,7 @@ func (player *mediaPlayerData) set(tag string, value interface{}) bool {
player.properties[tag] = listeners
}
player.propertyChanged(tag)
player.propertyChangedEvent(tag)
return true
}
notCompatibleType(tag, value)
@ -240,6 +230,7 @@ func (player *mediaPlayerData) set(tag string, value interface{}) bool {
player.properties[tag] = listeners
}
player.propertyChanged(tag)
player.propertyChangedEvent(tag)
return true
}
notCompatibleType(tag, value)
@ -247,14 +238,14 @@ func (player *mediaPlayerData) set(tag string, value interface{}) bool {
case Source:
if player.setSource(value) {
player.propertyChanged(tag)
player.propertyChangedEvent(tag)
return true
}
default:
if player.viewData.set(tag, value) {
return true
}
return player.viewData.set(tag, value)
}
return false
}
@ -657,89 +648,88 @@ func playerEvents() []struct{ tag, cssTag string } {
}
func (player *mediaPlayerData) propertyChanged(tag string) {
switch tag {
case Controls, Loop:
value, _ := boolProperty(player, tag, player.Session())
if value {
updateBoolProperty(player.htmlID(), tag, value, 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
if player.created {
switch tag {
case Controls, Loop:
value, _ := boolProperty(player, tag, player.Session())
if value {
updateBoolProperty(player.htmlID(), tag, value, player.Session())
} else {
removeProperty(player.htmlID(), tag, player.Session())
}
}
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 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 VolumeChangedEvent:
if value := player.getRaw(tag); value != nil {
updateProperty(player.htmlID(), "onvolumechange", "playerVolumeChangedEvent(this)", player.Session())
} else {
updateProperty(player.htmlID(), "onvolumechange", "", player.Session())
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 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:
if len(picker.numberChangedListeners) > 0 {
picker.numberChangedListeners = []func(NumberPicker, float64){}
picker.propertyChangedEvent(tag)
}
default:
@ -135,18 +136,21 @@ func (picker *numberPickerData) set(tag string, value interface{}) bool {
}
picker.numberChangedListeners = listeners
}
picker.propertyChangedEvent(tag)
return true
case NumberPickerValue:
oldValue := GetNumberPickerValue(picker, "")
min, max := GetNumberPickerMinMax(picker, "")
if picker.setFloatProperty(NumberPickerValue, value, min, max) {
newValue := GetNumberPickerValue(picker, "")
if oldValue != newValue {
picker.session.runScript(fmt.Sprintf(`setInputValue('%s', '%f')`, picker.htmlID(), newValue))
if newValue := GetNumberPickerValue(picker, ""); oldValue != newValue {
if picker.created {
picker.session.runScript(fmt.Sprintf(`setInputValue('%s', '%f')`, picker.htmlID(), newValue))
}
for _, listener := range picker.numberChangedListeners {
listener(picker, newValue)
}
picker.propertyChangedEvent(tag)
}
return true
}
@ -161,34 +165,36 @@ func (picker *numberPickerData) set(tag string, value interface{}) bool {
}
func (picker *numberPickerData) propertyChanged(tag string) {
switch tag {
case NumberPickerType:
if GetNumberPickerType(picker, "") == NumberSlider {
updateProperty(picker.htmlID(), "type", "range", picker.session)
} else {
updateProperty(picker.htmlID(), "type", "number", picker.session)
}
if picker.created {
switch tag {
case NumberPickerType:
if GetNumberPickerType(picker, "") == NumberSlider {
updateProperty(picker.htmlID(), "type", "range", picker.session)
} else {
updateProperty(picker.htmlID(), "type", "number", picker.session)
}
case NumberPickerMin:
min, _ := GetNumberPickerMinMax(picker, "")
updateProperty(picker.htmlID(), Min, strconv.FormatFloat(min, 'f', -1, 32), picker.session)
case NumberPickerMin:
min, _ := GetNumberPickerMinMax(picker, "")
updateProperty(picker.htmlID(), Min, strconv.FormatFloat(min, 'f', -1, 32), picker.session)
case NumberPickerMax:
_, max := GetNumberPickerMinMax(picker, "")
updateProperty(picker.htmlID(), Max, strconv.FormatFloat(max, 'f', -1, 32), picker.session)
case NumberPickerMax:
_, max := GetNumberPickerMinMax(picker, "")
updateProperty(picker.htmlID(), Max, strconv.FormatFloat(max, 'f', -1, 32), picker.session)
case NumberPickerStep:
if step := GetNumberPickerStep(picker, ""); step > 0 {
updateProperty(picker.htmlID(), Step, strconv.FormatFloat(step, 'f', -1, 32), picker.session)
} else {
updateProperty(picker.htmlID(), Step, "any", picker.session)
}
case NumberPickerStep:
if step := GetNumberPickerStep(picker, ""); step > 0 {
updateProperty(picker.htmlID(), Step, strconv.FormatFloat(step, 'f', -1, 32), picker.session)
} else {
updateProperty(picker.htmlID(), Step, "any", picker.session)
}
case NumberPickerValue:
value := GetNumberPickerValue(picker, "")
picker.session.runScript(fmt.Sprintf(`setInputValue('%s', '%f')`, picker.htmlID(), value))
for _, listener := range picker.numberChangedListeners {
listener(picker, value)
case NumberPickerValue:
value := GetNumberPickerValue(picker, "")
picker.session.runScript(fmt.Sprintf(`setInputValue('%s', '%f')`, picker.htmlID(), value))
for _, listener := range picker.numberChangedListeners {
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) {
if IsDisabled(self) {
if IsDisabled(self, "") {
buffer.WriteString(` disabled`)
}
picker.viewData.htmlDisabledProperties(self, buffer)

View File

@ -58,12 +58,14 @@ func (progress *progressBarData) remove(tag string) {
}
func (progress *progressBarData) propertyChanged(tag string) {
switch tag {
case ProgressBarMax:
updateProperty(progress.htmlID(), Max, strconv.FormatFloat(GetProgressBarMax(progress, ""), 'f', -1, 32), progress.session)
if progress.created {
switch tag {
case ProgressBarMax:
updateProperty(progress.htmlID(), Max, strconv.FormatFloat(GetProgressBarMax(progress, ""), 'f', -1, 32), progress.session)
case ProgressBarValue:
updateProperty(progress.htmlID(), Value, strconv.FormatFloat(GetProgressBarValue(progress, ""), 'f', -1, 32), progress.session)
case ProgressBarValue:
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 = "center-y"
// AltText is the constant for the "alt-text" property tag.
AltText = "alt-text"
altProperty = "alt"
AltText = "alt-text"
altTag = "alt"
// 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.
// 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,
RowSpan,
ColumnSpan,
ColumnCount,
}
var floatProperties = map[string]struct{ min, max float64 }{

View File

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

View File

@ -6,6 +6,8 @@ import (
"strings"
)
// TODO PeekChangedEvent
const (
// DefaultAnimation - default animation of StackLayout push
DefaultAnimation = 0
@ -93,23 +95,33 @@ func (layout *stackLayoutData) popFinished(view View, tag string) {
}
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)
if ok {
listeners = append(listeners, layout.pushFinished)
listeners = append(listeners, layout.popFinished)
layout.properties[TransitionEndEvent] = listeners
layout.propertyChangedEvent(TransitionEndEvent)
}
return ok
}
return layout.viewsContainerData.Set(tag, value)
return layout.viewsContainerData.set(tag, value)
}
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.propertyChangedEvent(TransitionEndEvent)
} 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)
view.setParentID(htmlID)
layout.propertyChangedEvent(Content)
}
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)
layout.propertyChangedEvent(Content)
return true
}

View File

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

View File

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

View File

@ -63,28 +63,47 @@ func (picker *timePickerData) remove(tag string) {
case TimeChangedEvent:
if len(picker.timeChangedListeners) > 0 {
picker.timeChangedListeners = []func(TimePicker, time.Time){}
picker.propertyChangedEvent(tag)
}
return
case TimePickerMin:
delete(picker.properties, TimePickerMin)
removeProperty(picker.htmlID(), Min, picker.session)
if picker.created {
removeProperty(picker.htmlID(), Min, picker.session)
}
case TimePickerMax:
delete(picker.properties, TimePickerMax)
removeProperty(picker.htmlID(), Max, picker.session)
if picker.created {
removeProperty(picker.htmlID(), Max, picker.session)
}
case TimePickerStep:
delete(picker.properties, TimePickerMax)
removeProperty(picker.htmlID(), Step, picker.session)
if picker.created {
removeProperty(picker.htmlID(), Step, picker.session)
}
case TimePickerValue:
delete(picker.properties, TimePickerValue)
updateProperty(picker.htmlID(), Value, time.Now().Format(timeFormat), picker.session)
if _, ok := picker.properties[TimePickerValue]; ok {
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:
picker.viewData.remove(tag)
picker.propertyChanged(tag)
return
}
picker.propertyChangedEvent(tag)
}
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)
if time, ok := setTimeValue(TimePickerMin); ok {
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
}
@ -130,7 +152,10 @@ func (picker *timePickerData) set(tag string, value interface{}) bool {
old, oldOK := getTimeProperty(picker, TimePickerMax, Max)
if time, ok := setTimeValue(TimePickerMax); ok {
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
}
@ -138,13 +163,15 @@ func (picker *timePickerData) set(tag string, value interface{}) bool {
case TimePickerStep:
oldStep := GetTimePickerStep(picker, "")
if picker.setIntProperty(TimePickerStep, value) {
step := GetTimePickerStep(picker, "")
if oldStep != step {
if step > 0 {
updateProperty(picker.htmlID(), Step, strconv.Itoa(step), picker.session)
} else {
removeProperty(picker.htmlID(), Step, picker.session)
if step := GetTimePickerStep(picker, ""); oldStep != step {
if picker.created {
if step > 0 {
updateProperty(picker.htmlID(), Step, strconv.Itoa(step), picker.session)
} else {
removeProperty(picker.htmlID(), Step, picker.session)
}
}
picker.propertyChangedEvent(tag)
}
return true
}
@ -152,11 +179,14 @@ func (picker *timePickerData) set(tag string, value interface{}) bool {
case TimePickerValue:
oldTime := GetTimePickerValue(picker, "")
if time, ok := setTimeValue(TimePickerMax); ok {
picker.session.runScript(fmt.Sprintf(`setInputValue('%s', '%s')`, picker.htmlID(), time.Format(timeFormat)))
if time != oldTime {
if picker.created {
picker.session.runScript(fmt.Sprintf(`setInputValue('%s', '%s')`, picker.htmlID(), time.Format(timeFormat)))
}
for _, listener := range picker.timeChangedListeners {
listener(picker, time)
}
picker.propertyChangedEvent(tag)
}
return true
}
@ -167,8 +197,8 @@ func (picker *timePickerData) set(tag string, value interface{}) bool {
picker.timeChangedListeners = []func(TimePicker, time.Time){value}
case func(time.Time):
fn := func(view TimePicker, date time.Time) {
value(date)
fn := func(view TimePicker, time time.Time) {
value(time)
}
picker.timeChangedListeners = []func(TimePicker, time.Time){fn}
@ -183,8 +213,8 @@ func (picker *timePickerData) set(tag string, value interface{}) bool {
return false
}
listeners[i] = func(view TimePicker, date time.Time) {
val(date)
listeners[i] = func(view TimePicker, time time.Time) {
val(time)
}
}
picker.timeChangedListeners = listeners
@ -202,8 +232,8 @@ func (picker *timePickerData) set(tag string, value interface{}) bool {
listeners[i] = val
case func(time.Time):
listeners[i] = func(view TimePicker, date time.Time) {
val(date)
listeners[i] = func(view TimePicker, time time.Time) {
val(time)
}
default:
@ -213,13 +243,11 @@ func (picker *timePickerData) set(tag string, value interface{}) bool {
}
picker.timeChangedListeners = listeners
}
picker.propertyChangedEvent(tag)
return true
default:
if picker.viewData.set(tag, value) {
picker.propertyChanged(tag)
return true
}
return picker.viewData.set(tag, value)
}
return false
}
@ -273,7 +301,7 @@ func (picker *timePickerData) htmlProperties(self View, buffer *strings.Builder)
}
func (picker *timePickerData) htmlDisabledProperties(self View, buffer *strings.Builder) {
if IsDisabled(self) {
if IsDisabled(self, "") {
buffer.WriteString(` disabled`)
}
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
SetAnimated(tag string, value interface{}, animation Animation) bool
SetChangeListener(tag string, listener func(View, string))
handleCommand(self View, command string, data DataObject) bool
//updateEventHandlers()
htmlClass(disabled bool) string
@ -87,6 +89,7 @@ type viewData struct {
_htmlID string
parentID string
systemClass string
changeListener map[string]func(View, string)
singleTransition map[string]Animation
addCSS map[string]string
frame Frame
@ -129,6 +132,7 @@ func (view *viewData) Init(session Session) {
view.viewStyle.init()
view.tag = "View"
view.session = session
view.changeListener = map[string]func(View, string){}
view.addCSS = map[string]string{}
//view.animation = map[string]AnimationEndListener{}
view.singleTransition = map[string]Animation{}
@ -186,7 +190,7 @@ func (view *viewData) remove(tag string) {
case Style, StyleDisabled:
if _, ok := view.properties[tag]; ok {
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:
@ -221,8 +225,62 @@ func (view *viewData) remove(tag string) {
default:
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 {
@ -235,64 +293,71 @@ func (view *viewData) set(tag string, value interface{}) bool {
return true
}
result := func(res bool) bool {
if res {
view.propertyChangedEvent(tag)
}
return res
}
switch tag {
case ID:
if text, ok := value.(string); ok {
view.viewID = text
return true
text, ok := value.(string)
if !ok {
notCompatibleType(ID, value)
return false
}
notCompatibleType(ID, value)
return false
view.viewID = text
case Style, StyleDisabled:
if text, ok := value.(string); ok {
view.properties[tag] = text
//updateInnerHTML(view.parentID, view.session)
if view.created {
updateProperty(view.htmlID(), "class", view.htmlClass(IsDisabled(view)), view.session)
}
return true
text, ok := value.(string)
if !ok {
notCompatibleType(ID, value)
return false
}
view.properties[tag] = text
if view.created {
updateProperty(view.htmlID(), "class", view.htmlClass(IsDisabled(view, "")), view.session)
}
notCompatibleType(ID, value)
return false
case FocusEvent, LostFocusEvent:
return view.setFocusListener(tag, value)
return result(view.setFocusListener(tag, value))
case KeyDownEvent, KeyUpEvent:
return view.setKeyListener(tag, value)
return result(view.setKeyListener(tag, value))
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:
return view.setPointerListener(tag, value)
return result(view.setPointerListener(tag, value))
case TouchStart, TouchEnd, TouchMove, TouchCancel:
return view.setTouchListener(tag, value)
return result(view.setTouchListener(tag, value))
case TransitionRunEvent, TransitionStartEvent, TransitionEndEvent, TransitionCancelEvent:
return view.setTransitionListener(tag, value)
return result(view.setTransitionListener(tag, value))
case AnimationStartEvent, AnimationEndEvent, AnimationIterationEvent, AnimationCancelEvent:
return view.setAnimationListener(tag, value)
return result(view.setAnimationListener(tag, value))
case ResizeEvent, ScrollEvent:
return view.setFrameListener(tag, value)
}
return result(view.setFrameListener(tag, value))
if view.viewStyle.set(tag, value) {
if view.created {
view.propertyChanged(tag)
default:
if !view.viewStyle.set(tag, value) {
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) {
return
}
@ -446,7 +511,7 @@ func (view *viewData) propertyChanged(tag string) {
case Strikethrough, Overline, Underline:
updateCSSProperty(htmlID, "text-decoration", view.cssTextDecoration(session), session)
for _, tag2 := range []string{TextLineColor, TextLineStyle, TextLineThickness} {
view.propertyChanged(tag2)
viewPropertyChanged(view, tag2)
}
return
@ -568,7 +633,7 @@ func (view *viewData) htmlProperties(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"`)
} else {
buffer.WriteString(` data-disabled="0"`)
@ -583,7 +648,7 @@ func viewHTML(view View, buffer *strings.Builder) {
buffer.WriteString(view.htmlID())
buffer.WriteRune('"')
disabled := IsDisabled(view)
disabled := IsDisabled(view, "")
if cls := view.htmlClass(disabled); cls != "" {
buffer.WriteString(` class="`)
@ -660,7 +725,7 @@ func (view *viewData) handleCommand(self View, command string, data DataObject)
switch command {
case KeyDownEvent, KeyUpEvent:
if !IsDisabled(self) {
if !IsDisabled(self, "") {
handleKeyEvents(self, command, data)
}
@ -767,13 +832,10 @@ func (view *viewData) String() string {
return writer.finish()
}
// IsDisabled returns "true" if the view is disabled
func IsDisabled(view View) bool {
if disabled, _ := boolProperty(view, Disabled, view.Session()); disabled {
return true
func (view *viewData) SetChangeListener(tag string, listener func(View, string)) {
if listener == nil {
delete(view.changeListener, tag)
} 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.
// If the subview don't exists or the property is not set then nil is returned.
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 nil
@ -14,12 +20,29 @@ func Get(rootView View, viewID, tag string) interface{} {
// true - success,
// false - error (incompatible type or invalid format of a string value, see AppLog).
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 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:
// true - all properties were set successful,
// 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
}
// 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
// DefaultSemantics (0), ArticleSemantics (1), SectionSemantics (2), AsideSemantics (3),
// HeaderSemantics (4), MainSemantics (5), FooterSemantics (6), NavigationSemantics (7),
@ -926,7 +965,7 @@ func valueFromStyle(view View, tag string) (string, bool) {
return "", false
}
if IsDisabled(view) {
if IsDisabled(view, "") {
if value, ok := getValue(StyleDisabled); ok {
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
func (container *viewsContainerData) Views() []View {
if container.views == nil {
@ -68,6 +58,7 @@ func (container *viewsContainerData) Append(view View) {
container.views = append(container.views, view)
}
updateInnerHTML(container.htmlID(), container.session)
container.propertyChangedEvent(Content)
}
}
@ -81,10 +72,12 @@ func (container *viewsContainerData) Insert(view View, index uint) {
view.setParentID(htmlID)
container.views = append(container.views[:index], append([]View{view}, container.views[index:]...)...)
updateInnerHTML(container.htmlID(), container.session)
container.propertyChangedEvent(Content)
} else {
view.setParentID(htmlID)
container.views = append([]View{view}, container.views...)
updateInnerHTML(container.htmlID(), container.session)
container.propertyChangedEvent(Content)
}
}
}
@ -112,6 +105,7 @@ func (container *viewsContainerData) RemoveView(index uint) View {
view.setParentID("")
updateInnerHTML(container.htmlID(), container.session)
container.propertyChangedEvent(Content)
return view
}
@ -151,6 +145,18 @@ func (container *viewsContainerData) remove(tag string) {
container.views = []View{}
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:
container.viewData.remove(tag)
@ -167,7 +173,27 @@ func (container *viewsContainerData) set(tag string, value interface{}) bool {
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)
}
@ -239,6 +265,8 @@ func (container *viewsContainerData) set(tag string, value interface{}) bool {
if container.created {
updateInnerHTML(htmlID, container.session)
}
container.propertyChangedEvent(Content)
return true
}