Refactoring and optimisation

This commit is contained in:
Alexei Anoshenko 2022-07-27 20:31:57 +03:00
parent ece1d04e4e
commit e23ad83b6c
23 changed files with 228 additions and 1765 deletions

View File

@ -51,131 +51,6 @@ const (
AnimationIterationEvent = "animation-iteration-event" AnimationIterationEvent = "animation-iteration-event"
) )
func valueToAnimationListeners(value any) ([]func(View, string), bool) {
if value == nil {
return nil, true
}
switch value := value.(type) {
case func(View, string):
return []func(View, string){value}, true
case func(string):
fn := func(_ View, event string) {
value(event)
}
return []func(View, string){fn}, true
case func(View):
fn := func(view View, _ string) {
value(view)
}
return []func(View, string){fn}, true
case func():
fn := func(View, string) {
value()
}
return []func(View, string){fn}, true
case []func(View, string):
if len(value) == 0 {
return nil, true
}
for _, fn := range value {
if fn == nil {
return nil, false
}
}
return value, true
case []func(string):
count := len(value)
if count == 0 {
return nil, true
}
listeners := make([]func(View, string), count)
for i, v := range value {
if v == nil {
return nil, false
}
listeners[i] = func(_ View, event string) {
v(event)
}
}
return listeners, true
case []func(View):
count := len(value)
if count == 0 {
return nil, true
}
listeners := make([]func(View, string), count)
for i, v := range value {
if v == nil {
return nil, false
}
listeners[i] = func(view View, _ string) {
v(view)
}
}
return listeners, true
case []func():
count := len(value)
if count == 0 {
return nil, true
}
listeners := make([]func(View, string), count)
for i, v := range value {
if v == nil {
return nil, false
}
listeners[i] = func(View, string) {
v()
}
}
return listeners, true
case []any:
count := len(value)
if count == 0 {
return nil, true
}
listeners := make([]func(View, string), count)
for i, v := range value {
if v == nil {
return nil, false
}
switch v := v.(type) {
case func(View, string):
listeners[i] = v
case func(string):
listeners[i] = func(_ View, event string) {
v(event)
}
case func(View):
listeners[i] = func(view View, _ string) {
v(view)
}
case func():
listeners[i] = func(View, string) {
v()
}
default:
return nil, false
}
}
return listeners, true
}
return nil, false
}
var transitionEvents = map[string]struct{ jsEvent, jsFunc string }{ var transitionEvents = map[string]struct{ jsEvent, jsFunc string }{
TransitionRunEvent: {jsEvent: "ontransitionrun", jsFunc: "transitionRunEvent"}, TransitionRunEvent: {jsEvent: "ontransitionrun", jsFunc: "transitionRunEvent"},
TransitionStartEvent: {jsEvent: "ontransitionstart", jsFunc: "transitionStartEvent"}, TransitionStartEvent: {jsEvent: "ontransitionstart", jsFunc: "transitionStartEvent"},
@ -184,7 +59,7 @@ var transitionEvents = map[string]struct{ jsEvent, jsFunc string }{
} }
func (view *viewData) setTransitionListener(tag string, value any) bool { func (view *viewData) setTransitionListener(tag string, value any) bool {
listeners, ok := valueToAnimationListeners(value) listeners, ok := valueToEventListeners[View, string](value)
if !ok { if !ok {
notCompatibleType(tag, value) notCompatibleType(tag, value)
return false return false
@ -212,20 +87,6 @@ func (view *viewData) removeTransitionListener(tag string) {
} }
} }
func getAnimationListeners(view View, subviewID string, tag string) []func(View, string) {
if subviewID != "" {
view = ViewByID(view, subviewID)
}
if view != nil {
if value := view.Get(tag); value != nil {
if result, ok := value.([]func(View, string)); ok {
return result
}
}
}
return []func(View, string){}
}
func transitionEventsHtml(view View, buffer *strings.Builder) { func transitionEventsHtml(view View, buffer *strings.Builder) {
for tag, js := range transitionEvents { for tag, js := range transitionEvents {
if value := view.getRaw(tag); value != nil { if value := view.getRaw(tag); value != nil {
@ -250,7 +111,7 @@ func (view *viewData) handleTransitionEvents(tag string, data DataObject) {
} }
} }
for _, listener := range getAnimationListeners(view, "", tag) { for _, listener := range getEventListeners[View, string](view, "", tag) {
listener(view, property) listener(view, property)
} }
} }
@ -264,7 +125,7 @@ var animationEvents = map[string]struct{ jsEvent, jsFunc string }{
} }
func (view *viewData) setAnimationListener(tag string, value any) bool { func (view *viewData) setAnimationListener(tag string, value any) bool {
listeners, ok := valueToAnimationListeners(value) listeners, ok := valueToEventListeners[View, string](value)
if !ok { if !ok {
notCompatibleType(tag, value) notCompatibleType(tag, value)
return false return false
@ -303,7 +164,7 @@ func animationEventsHtml(view View, buffer *strings.Builder) {
} }
func (view *viewData) handleAnimationEvents(tag string, data DataObject) { func (view *viewData) handleAnimationEvents(tag string, data DataObject) {
if listeners := getAnimationListeners(view, "", tag); len(listeners) > 0 { if listeners := getEventListeners[View, string](view, "", tag); len(listeners) > 0 {
id := "" id := ""
if name, ok := data.PropertyValue("name"); ok { if name, ok := data.PropertyValue("name"); ok {
for _, animation := range GetAnimation(view, "") { for _, animation := range GetAnimation(view, "") {
@ -322,54 +183,54 @@ func (view *viewData) handleAnimationEvents(tag string, data DataObject) {
// If there are no listeners then the empty list is returned. // If there are no listeners then the empty list is returned.
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
func GetTransitionRunListeners(view View, subviewID string) []func(View, string) { func GetTransitionRunListeners(view View, subviewID string) []func(View, string) {
return getAnimationListeners(view, subviewID, TransitionRunEvent) return getEventListeners[View, string](view, subviewID, TransitionRunEvent)
} }
// GetTransitionStartListeners returns the "transition-start-event" listener list. // GetTransitionStartListeners returns the "transition-start-event" listener list.
// If there are no listeners then the empty list is returned. // If there are no listeners then the empty list is returned.
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
func GetTransitionStartListeners(view View, subviewID string) []func(View, string) { func GetTransitionStartListeners(view View, subviewID string) []func(View, string) {
return getAnimationListeners(view, subviewID, TransitionStartEvent) return getEventListeners[View, string](view, subviewID, TransitionStartEvent)
} }
// GetTransitionEndListeners returns the "transition-end-event" listener list. // GetTransitionEndListeners returns the "transition-end-event" listener list.
// If there are no listeners then the empty list is returned. // If there are no listeners then the empty list is returned.
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
func GetTransitionEndListeners(view View, subviewID string) []func(View, string) { func GetTransitionEndListeners(view View, subviewID string) []func(View, string) {
return getAnimationListeners(view, subviewID, TransitionEndEvent) return getEventListeners[View, string](view, subviewID, TransitionEndEvent)
} }
// GetTransitionCancelListeners returns the "transition-cancel-event" listener list. // GetTransitionCancelListeners returns the "transition-cancel-event" listener list.
// If there are no listeners then the empty list is returned. // If there are no listeners then the empty list is returned.
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
func GetTransitionCancelListeners(view View, subviewID string) []func(View, string) { func GetTransitionCancelListeners(view View, subviewID string) []func(View, string) {
return getAnimationListeners(view, subviewID, TransitionCancelEvent) return getEventListeners[View, string](view, subviewID, TransitionCancelEvent)
} }
// GetAnimationStartListeners returns the "animation-start-event" listener list. // GetAnimationStartListeners returns the "animation-start-event" listener list.
// If there are no listeners then the empty list is returned. // If there are no listeners then the empty list is returned.
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
func GetAnimationStartListeners(view View, subviewID string) []func(View, string) { func GetAnimationStartListeners(view View, subviewID string) []func(View, string) {
return getAnimationListeners(view, subviewID, AnimationStartEvent) return getEventListeners[View, string](view, subviewID, AnimationStartEvent)
} }
// GetAnimationEndListeners returns the "animation-end-event" listener list. // GetAnimationEndListeners returns the "animation-end-event" listener list.
// If there are no listeners then the empty list is returned. // If there are no listeners then the empty list is returned.
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
func GetAnimationEndListeners(view View, subviewID string) []func(View, string) { func GetAnimationEndListeners(view View, subviewID string) []func(View, string) {
return getAnimationListeners(view, subviewID, AnimationEndEvent) return getEventListeners[View, string](view, subviewID, AnimationEndEvent)
} }
// GetAnimationCancelListeners returns the "animation-cancel-event" listener list. // GetAnimationCancelListeners returns the "animation-cancel-event" listener list.
// If there are no listeners then the empty list is returned. // If there are no listeners then the empty list is returned.
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
func GetAnimationCancelListeners(view View, subviewID string) []func(View, string) { func GetAnimationCancelListeners(view View, subviewID string) []func(View, string) {
return getAnimationListeners(view, subviewID, AnimationCancelEvent) return getEventListeners[View, string](view, subviewID, AnimationCancelEvent)
} }
// GetAnimationIterationListeners returns the "animation-iteration-event" listener list. // GetAnimationIterationListeners returns the "animation-iteration-event" listener list.
// If there are no listeners then the empty list is returned. // If there are no listeners then the empty list is returned.
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
func GetAnimationIterationListeners(view View, subviewID string) []func(View, string) { func GetAnimationIterationListeners(view View, subviewID string) []func(View, string) {
return getAnimationListeners(view, subviewID, AnimationIterationEvent) return getEventListeners[View, string](view, subviewID, AnimationIterationEvent)
} }

View File

@ -87,57 +87,14 @@ func (picker *colorPickerData) set(tag string, value any) bool {
switch tag { switch tag {
case ColorChangedEvent: case ColorChangedEvent:
switch value := value.(type) { listeners, ok := valueToEventListeners[ColorPicker, Color](value)
case func(ColorPicker, Color): if !ok {
picker.colorChangedListeners = []func(ColorPicker, Color){value} notCompatibleType(tag, value)
return false
case func(Color): } else if listeners == nil {
fn := func(_ ColorPicker, date Color) { listeners = []func(ColorPicker, Color){}
value(date)
}
picker.colorChangedListeners = []func(ColorPicker, Color){fn}
case []func(ColorPicker, Color):
picker.colorChangedListeners = value
case []func(Color):
listeners := make([]func(ColorPicker, Color), len(value))
for i, val := range value {
if val == nil {
notCompatibleType(tag, val)
return false
}
listeners[i] = func(_ ColorPicker, date Color) {
val(date)
}
}
picker.colorChangedListeners = listeners
case []any:
listeners := make([]func(ColorPicker, Color), len(value))
for i, val := range value {
if val == nil {
notCompatibleType(tag, val)
return false
}
switch val := val.(type) {
case func(ColorPicker, Color):
listeners[i] = val
case func(Color):
listeners[i] = func(_ ColorPicker, date Color) {
val(date)
}
default:
notCompatibleType(tag, val)
return false
}
}
picker.colorChangedListeners = listeners
} }
picker.colorChangedListeners = listeners
picker.propertyChangedEvent(tag) picker.propertyChangedEvent(tag)
return true return true
@ -249,15 +206,5 @@ func GetColorPickerValue(view View, subviewID string) Color {
// If there are no listeners then the empty list is returned // If there are no listeners then the empty list is returned
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
func GetColorChangedListeners(view View, subviewID string) []func(ColorPicker, Color) { func GetColorChangedListeners(view View, subviewID string) []func(ColorPicker, Color) {
if subviewID != "" { return getEventListeners[ColorPicker, Color](view, subviewID, ColorChangedEvent)
view = ViewByID(view, subviewID)
}
if view != nil {
if value := view.Get(ColorChangedEvent); value != nil {
if listeners, ok := value.([]func(ColorPicker, Color)); ok {
return listeners
}
}
}
return []func(ColorPicker, Color){}
} }

View File

@ -235,57 +235,14 @@ func (picker *datePickerData) set(tag string, value any) bool {
} }
case DateChangedEvent: case DateChangedEvent:
switch value := value.(type) { listeners, ok := valueToEventListeners[DatePicker, time.Time](value)
case func(DatePicker, time.Time): if !ok {
picker.dateChangedListeners = []func(DatePicker, time.Time){value} notCompatibleType(tag, value)
return false
case func(time.Time): } else if listeners == nil {
fn := func(_ DatePicker, date time.Time) { listeners = []func(DatePicker, time.Time){}
value(date)
}
picker.dateChangedListeners = []func(DatePicker, time.Time){fn}
case []func(DatePicker, time.Time):
picker.dateChangedListeners = value
case []func(time.Time):
listeners := make([]func(DatePicker, time.Time), len(value))
for i, val := range value {
if val == nil {
notCompatibleType(tag, val)
return false
}
listeners[i] = func(_ DatePicker, date time.Time) {
val(date)
}
}
picker.dateChangedListeners = listeners
case []any:
listeners := make([]func(DatePicker, time.Time), len(value))
for i, val := range value {
if val == nil {
notCompatibleType(tag, val)
return false
}
switch val := val.(type) {
case func(DatePicker, time.Time):
listeners[i] = val
case func(time.Time):
listeners[i] = func(_ DatePicker, date time.Time) {
val(date)
}
default:
notCompatibleType(tag, val)
return false
}
}
picker.dateChangedListeners = listeners
} }
picker.dateChangedListeners = listeners
picker.propertyChangedEvent(tag) picker.propertyChangedEvent(tag)
return true return true
@ -463,15 +420,5 @@ func GetDatePickerValue(view View, subviewID string) time.Time {
// If there are no listeners then the empty list is returned // If there are no listeners then the empty list is returned
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
func GetDateChangedListeners(view View, subviewID string) []func(DatePicker, time.Time) { func GetDateChangedListeners(view View, subviewID string) []func(DatePicker, time.Time) {
if subviewID != "" { return getEventListeners[DatePicker, time.Time](view, subviewID, DateChangedEvent)
view = ViewByID(view, subviewID)
}
if view != nil {
if value := view.Get(DateChangedEvent); value != nil {
if listeners, ok := value.([]func(DatePicker, time.Time)); ok {
return listeners
}
}
}
return []func(DatePicker, time.Time){}
} }

View File

@ -113,7 +113,16 @@ func (list *dropDownListData) set(tag string, value any) bool {
return list.setDisabledItems(value) return list.setDisabledItems(value)
case DropDownEvent: case DropDownEvent:
return list.setDropDownListener(value) listeners, ok := valueToEventListeners[DropDownList, int](value)
if !ok {
notCompatibleType(tag, value)
return false
} else if listeners == nil {
listeners = []func(DropDownList, int){}
}
list.dropDownListener = listeners
list.propertyChangedEvent(tag)
return true
case Current: case Current:
oldCurrent := GetCurrent(list, "") oldCurrent := GetCurrent(list, "")
@ -291,64 +300,6 @@ func (list *dropDownListData) setDisabledItems(value any) bool {
} }
func (list *dropDownListData) setDropDownListener(value any) bool {
switch value := value.(type) {
case func(DropDownList, int):
list.dropDownListener = []func(DropDownList, int){value}
case func(int):
list.dropDownListener = []func(DropDownList, int){func(_ DropDownList, index int) {
value(index)
}}
case []func(DropDownList, int):
list.dropDownListener = value
case []func(int):
listeners := make([]func(DropDownList, int), len(value))
for i, val := range value {
if val == nil {
notCompatibleType(DropDownEvent, value)
return false
}
listeners[i] = func(_ DropDownList, index int) {
val(index)
}
}
list.dropDownListener = listeners
case []any:
listeners := make([]func(DropDownList, int), len(value))
for i, val := range value {
if val == nil {
notCompatibleType(DropDownEvent, value)
return false
}
switch val := val.(type) {
case func(DropDownList, int):
listeners[i] = val
case func(int):
listeners[i] = func(_ DropDownList, index int) {
val(index)
}
default:
notCompatibleType(DropDownEvent, value)
return false
}
}
list.dropDownListener = listeners
default:
notCompatibleType(DropDownEvent, value)
return false
}
list.propertyChangedEvent(DropDownEvent)
return true
}
func (list *dropDownListData) Get(tag string) any { func (list *dropDownListData) Get(tag string) any {
return list.get(strings.ToLower(tag)) return list.get(strings.ToLower(tag))
} }

View File

@ -333,75 +333,29 @@ func (edit *editViewData) set(tag string, value any) bool {
return false return false
case EditTextChangedEvent: case EditTextChangedEvent:
ok := edit.setChangeListeners(value) listeners, ok := valueToEventListeners[EditView, string](value)
if !ok { if !ok {
notCompatibleType(tag, value) notCompatibleType(tag, value)
return false
} else if listeners == nil {
listeners = []func(EditView, string){}
} }
edit.textChangeListeners = listeners
edit.propertyChangedEvent(tag) edit.propertyChangedEvent(tag)
return ok return true
} }
return edit.viewData.set(tag, value) return edit.viewData.set(tag, value)
} }
func (edit *editViewData) setChangeListeners(value any) bool {
switch value := value.(type) {
case func(EditView, string):
edit.textChangeListeners = []func(EditView, string){value}
case func(string):
fn := func(_ EditView, text string) {
value(text)
}
edit.textChangeListeners = []func(EditView, string){fn}
case []func(EditView, string):
edit.textChangeListeners = value
case []func(string):
listeners := make([]func(EditView, string), len(value))
for i, v := range value {
if v == nil {
return false
}
listeners[i] = func(_ EditView, text string) {
v(text)
}
}
edit.textChangeListeners = listeners
case []any:
listeners := make([]func(EditView, string), len(value))
for i, v := range value {
if v == nil {
return false
}
switch v := v.(type) {
case func(EditView, string):
listeners[i] = v
case func(string):
listeners[i] = func(_ EditView, text string) {
v(text)
}
default:
return false
}
}
edit.textChangeListeners = listeners
default:
return false
}
return true
}
func (edit *editViewData) Get(tag string) any { func (edit *editViewData) Get(tag string) any {
return edit.get(edit.normalizeTag(tag)) return edit.get(edit.normalizeTag(tag))
} }
func (edit *editViewData) get(tag string) any { func (edit *editViewData) get(tag string) any {
if tag == EditTextChangedEvent {
return edit.textChangeListeners
}
return edit.viewData.get(tag) return edit.viewData.get(tag)
} }
@ -635,17 +589,7 @@ func IsSpellcheck(view View, subviewID string) bool {
// If there are no listeners then the empty list is returned // If there are no listeners then the empty list is returned
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
func GetTextChangedListeners(view View, subviewID string) []func(EditView, string) { func GetTextChangedListeners(view View, subviewID string) []func(EditView, string) {
if subviewID != "" { return getEventListeners[EditView, string](view, subviewID, EditTextChangedEvent)
view = ViewByID(view, subviewID)
}
if view != nil {
if value := view.Get(EditTextChangedEvent); value != nil {
if result, ok := value.([]func(EditView, string)); ok {
return result
}
}
}
return []func(EditView, string){}
} }
// GetEditViewType returns a value of the Type property of EditView. // GetEditViewType returns a value of the Type property of EditView.

View File

@ -151,57 +151,14 @@ func (picker *filePickerData) set(tag string, value any) bool {
switch tag { switch tag {
case FileSelectedEvent: case FileSelectedEvent:
switch value := value.(type) { listeners, ok := valueToEventListeners[FilePicker, []FileInfo](value)
case func(FilePicker, []FileInfo): if !ok {
picker.fileSelectedListeners = []func(FilePicker, []FileInfo){value} notCompatibleType(tag, value)
return false
case func([]FileInfo): } else if listeners == nil {
fn := func(_ FilePicker, files []FileInfo) { listeners = []func(FilePicker, []FileInfo){}
value(files)
}
picker.fileSelectedListeners = []func(FilePicker, []FileInfo){fn}
case []func(FilePicker, []FileInfo):
picker.fileSelectedListeners = value
case []func([]FileInfo):
listeners := make([]func(FilePicker, []FileInfo), len(value))
for i, val := range value {
if val == nil {
notCompatibleType(tag, val)
return false
}
listeners[i] = func(_ FilePicker, files []FileInfo) {
val(files)
}
}
picker.fileSelectedListeners = listeners
case []any:
listeners := make([]func(FilePicker, []FileInfo), len(value))
for i, val := range value {
if val == nil {
notCompatibleType(tag, val)
return false
}
switch val := val.(type) {
case func(FilePicker, []FileInfo):
listeners[i] = val
case func([]FileInfo):
listeners[i] = func(_ FilePicker, files []FileInfo) {
val(files)
}
default:
notCompatibleType(tag, val)
return false
}
}
picker.fileSelectedListeners = listeners
} }
picker.fileSelectedListeners = listeners
picker.propertyChangedEvent(tag) picker.propertyChangedEvent(tag)
return true return true
@ -436,15 +393,5 @@ func GetFilePickerAccept(view View, subviewID string) []string {
// If there are no listeners then the empty list is returned. // If there are no listeners then the empty list is returned.
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
func GetFileSelectedListeners(view View, subviewID string) []func(FilePicker, []FileInfo) { func GetFileSelectedListeners(view View, subviewID string) []func(FilePicker, []FileInfo) {
if subviewID != "" { return getEventListeners[FilePicker, []FileInfo](view, subviewID, FileSelectedEvent)
view = ViewByID(view, subviewID)
}
if view != nil {
if value := view.Get(FileSelectedEvent); value != nil {
if result, ok := value.([]func(FilePicker, []FileInfo)); ok {
return result
}
}
}
return []func(FilePicker, []FileInfo){}
} }

View File

@ -20,22 +20,22 @@ const (
LostFocusEvent = "lost-focus-event" LostFocusEvent = "lost-focus-event"
) )
func valueToFocusListeners(value any) ([]func(View), bool) { func valueToNoParamListeners[V View](value any) ([]func(V), bool) {
if value == nil { if value == nil {
return nil, true return nil, true
} }
switch value := value.(type) { switch value := value.(type) {
case func(View): case func(V):
return []func(View){value}, true return []func(V){value}, true
case func(): case func():
fn := func(View) { fn := func(V) {
value() value()
} }
return []func(View){fn}, true return []func(V){fn}, true
case []func(View): case []func(V):
if len(value) == 0 { if len(value) == 0 {
return nil, true return nil, true
} }
@ -51,12 +51,12 @@ func valueToFocusListeners(value any) ([]func(View), bool) {
if count == 0 { if count == 0 {
return nil, true return nil, true
} }
listeners := make([]func(View), count) listeners := make([]func(V), count)
for i, v := range value { for i, v := range value {
if v == nil { if v == nil {
return nil, false return nil, false
} }
listeners[i] = func(View) { listeners[i] = func(V) {
v() v()
} }
} }
@ -67,17 +67,17 @@ func valueToFocusListeners(value any) ([]func(View), bool) {
if count == 0 { if count == 0 {
return nil, true return nil, true
} }
listeners := make([]func(View), count) listeners := make([]func(V), count)
for i, v := range value { for i, v := range value {
if v == nil { if v == nil {
return nil, false return nil, false
} }
switch v := v.(type) { switch v := v.(type) {
case func(View): case func(V):
listeners[i] = v listeners[i] = v
case func(): case func():
listeners[i] = func(View) { listeners[i] = func(V) {
v() v()
} }
@ -97,7 +97,7 @@ var focusEvents = map[string]struct{ jsEvent, jsFunc string }{
} }
func (view *viewData) setFocusListener(tag string, value any) bool { func (view *viewData) setFocusListener(tag string, value any) bool {
listeners, ok := valueToFocusListeners(value) listeners, ok := valueToNoParamListeners[View](value)
if !ok { if !ok {
notCompatibleType(tag, value) notCompatibleType(tag, value)
return false return false

View File

@ -118,77 +118,6 @@ func (imageView *imageViewData) Set(tag string, value any) bool {
return imageView.set(imageView.normalizeTag(tag), value) return imageView.set(imageView.normalizeTag(tag), value)
} }
func valueToImageListeners(value any) ([]func(ImageView), bool) {
if value == nil {
return nil, true
}
switch value := value.(type) {
case func(ImageView):
return []func(ImageView){value}, true
case func():
fn := func(ImageView) {
value()
}
return []func(ImageView){fn}, true
case []func(ImageView):
if len(value) == 0 {
return nil, true
}
for _, fn := range value {
if fn == nil {
return nil, false
}
}
return value, true
case []func():
count := len(value)
if count == 0 {
return nil, true
}
listeners := make([]func(ImageView), count)
for i, v := range value {
if v == nil {
return nil, false
}
listeners[i] = func(ImageView) {
v()
}
}
return listeners, true
case []any:
count := len(value)
if count == 0 {
return nil, true
}
listeners := make([]func(ImageView), count)
for i, v := range value {
if v == nil {
return nil, false
}
switch v := v.(type) {
case func(ImageView):
listeners[i] = v
case func():
listeners[i] = func(ImageView) {
v()
}
default:
return nil, false
}
}
return listeners, true
}
return nil, false
}
func (imageView *imageViewData) set(tag string, value any) bool { func (imageView *imageViewData) set(tag string, value any) bool {
if value == nil { if value == nil {
imageView.remove(tag) imageView.remove(tag)
@ -228,8 +157,12 @@ func (imageView *imageViewData) set(tag string, value any) bool {
notCompatibleType(tag, value) notCompatibleType(tag, value)
case LoadedEvent, ErrorEvent: case LoadedEvent, ErrorEvent:
if listeners, ok := valueToImageListeners(value); ok { if listeners, ok := valueToNoParamListeners[ImageView](value); ok {
imageView.properties[tag] = listeners if listeners == nil {
delete(imageView.properties, tag)
} else {
imageView.properties[tag] = listeners
}
return true return true
} }

View File

@ -50,34 +50,52 @@ type KeyEvent struct {
MetaKey bool MetaKey bool
} }
func valueToKeyListeners(value any) ([]func(View, KeyEvent), bool) { func (event *KeyEvent) init(data DataObject) {
getBool := func(tag string) bool {
if value, ok := data.PropertyValue(tag); ok && value == "1" {
return true
}
return false
}
event.Key, _ = data.PropertyValue("key")
event.Code, _ = data.PropertyValue("code")
event.TimeStamp = getTimeStamp(data)
event.Repeat = getBool("repeat")
event.CtrlKey = getBool("ctrlKey")
event.ShiftKey = getBool("shiftKey")
event.AltKey = getBool("altKey")
event.MetaKey = getBool("metaKey")
}
func valueToEventListeners[V View, E any](value any) ([]func(V, E), bool) {
if value == nil { if value == nil {
return nil, true return nil, true
} }
switch value := value.(type) { switch value := value.(type) {
case func(View, KeyEvent): case func(V, E):
return []func(View, KeyEvent){value}, true return []func(V, E){value}, true
case func(KeyEvent): case func(E):
fn := func(_ View, event KeyEvent) { fn := func(_ V, event E) {
value(event) value(event)
} }
return []func(View, KeyEvent){fn}, true return []func(V, E){fn}, true
case func(View): case func(V):
fn := func(view View, _ KeyEvent) { fn := func(view V, _ E) {
value(view) value(view)
} }
return []func(View, KeyEvent){fn}, true return []func(V, E){fn}, true
case func(): case func():
fn := func(View, KeyEvent) { fn := func(V, E) {
value() value()
} }
return []func(View, KeyEvent){fn}, true return []func(V, E){fn}, true
case []func(View, KeyEvent): case []func(V, E):
if len(value) == 0 { if len(value) == 0 {
return nil, true return nil, true
} }
@ -88,33 +106,33 @@ func valueToKeyListeners(value any) ([]func(View, KeyEvent), bool) {
} }
return value, true return value, true
case []func(KeyEvent): case []func(E):
count := len(value) count := len(value)
if count == 0 { if count == 0 {
return nil, true return nil, true
} }
listeners := make([]func(View, KeyEvent), count) listeners := make([]func(V, E), count)
for i, v := range value { for i, v := range value {
if v == nil { if v == nil {
return nil, false return nil, false
} }
listeners[i] = func(_ View, event KeyEvent) { listeners[i] = func(_ V, event E) {
v(event) v(event)
} }
} }
return listeners, true return listeners, true
case []func(View): case []func(V):
count := len(value) count := len(value)
if count == 0 { if count == 0 {
return nil, true return nil, true
} }
listeners := make([]func(View, KeyEvent), count) listeners := make([]func(V, E), count)
for i, v := range value { for i, v := range value {
if v == nil { if v == nil {
return nil, false return nil, false
} }
listeners[i] = func(view View, _ KeyEvent) { listeners[i] = func(view V, _ E) {
v(view) v(view)
} }
} }
@ -125,12 +143,12 @@ func valueToKeyListeners(value any) ([]func(View, KeyEvent), bool) {
if count == 0 { if count == 0 {
return nil, true return nil, true
} }
listeners := make([]func(View, KeyEvent), count) listeners := make([]func(V, E), count)
for i, v := range value { for i, v := range value {
if v == nil { if v == nil {
return nil, false return nil, false
} }
listeners[i] = func(View, KeyEvent) { listeners[i] = func(V, E) {
v() v()
} }
} }
@ -141,27 +159,27 @@ func valueToKeyListeners(value any) ([]func(View, KeyEvent), bool) {
if count == 0 { if count == 0 {
return nil, true return nil, true
} }
listeners := make([]func(View, KeyEvent), count) listeners := make([]func(V, E), count)
for i, v := range value { for i, v := range value {
if v == nil { if v == nil {
return nil, false return nil, false
} }
switch v := v.(type) { switch v := v.(type) {
case func(View, KeyEvent): case func(V, E):
listeners[i] = v listeners[i] = v
case func(KeyEvent): case func(E):
listeners[i] = func(_ View, event KeyEvent) { listeners[i] = func(_ V, event E) {
v(event) v(event)
} }
case func(View): case func(V):
listeners[i] = func(view View, _ KeyEvent) { listeners[i] = func(view V, _ E) {
v(view) v(view)
} }
case func(): case func():
listeners[i] = func(View, KeyEvent) { listeners[i] = func(V, E) {
v() v()
} }
@ -181,7 +199,7 @@ var keyEvents = map[string]struct{ jsEvent, jsFunc string }{
} }
func (view *viewData) setKeyListener(tag string, value any) bool { func (view *viewData) setKeyListener(tag string, value any) bool {
listeners, ok := valueToKeyListeners(value) listeners, ok := valueToEventListeners[View, KeyEvent](value)
if !ok { if !ok {
notCompatibleType(tag, value) notCompatibleType(tag, value)
return false return false
@ -209,67 +227,48 @@ func (view *viewData) removeKeyListener(tag string) {
} }
} }
func getKeyListeners(view View, subviewID string, tag string) []func(View, KeyEvent) { func getEventListeners[V View, E any](view View, subviewID string, tag string) []func(V, E) {
if subviewID != "" { if subviewID != "" {
view = ViewByID(view, subviewID) view = ViewByID(view, subviewID)
} }
if view != nil { if view != nil {
if value := view.Get(tag); value != nil { if value := view.Get(tag); value != nil {
if result, ok := value.([]func(View, KeyEvent)); ok { if result, ok := value.([]func(V, E)); ok {
return result return result
} }
} }
} }
return []func(View, KeyEvent){} return []func(V, E){}
} }
func keyEventsHtml(view View, buffer *strings.Builder) { func keyEventsHtml(view View, buffer *strings.Builder) {
for tag, js := range keyEvents { for tag, js := range keyEvents {
if listeners := getKeyListeners(view, "", tag); len(listeners) > 0 { if listeners := getEventListeners[View, KeyEvent](view, "", tag); len(listeners) > 0 {
buffer.WriteString(js.jsEvent + `="` + js.jsFunc + `(this, event)" `) buffer.WriteString(js.jsEvent + `="` + js.jsFunc + `(this, event)" `)
} }
} }
} }
func handleKeyEvents(view View, tag string, data DataObject) { func handleKeyEvents(view View, tag string, data DataObject) {
listeners := getKeyListeners(view, "", tag) listeners := getEventListeners[View, KeyEvent](view, "", tag)
if len(listeners) == 0 { if len(listeners) > 0 {
return var event KeyEvent
} event.init(data)
getBool := func(tag string) bool { for _, listener := range listeners {
if value, ok := data.PropertyValue(tag); ok && value == "1" { listener(view, event)
return true
} }
return false
}
key, _ := data.PropertyValue("key")
code, _ := data.PropertyValue("code")
event := KeyEvent{
TimeStamp: getTimeStamp(data),
Key: key,
Code: code,
Repeat: getBool("repeat"),
CtrlKey: getBool("ctrlKey"),
ShiftKey: getBool("shiftKey"),
AltKey: getBool("altKey"),
MetaKey: getBool("metaKey"),
}
for _, listener := range listeners {
listener(view, event)
} }
} }
// GetKeyDownListeners returns the "key-down-event" listener list. If there are no listeners then the empty list is returned. // GetKeyDownListeners returns the "key-down-event" listener list. If there are no listeners then the empty list is returned.
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
func GetKeyDownListeners(view View, subviewID string) []func(View, KeyEvent) { func GetKeyDownListeners(view View, subviewID string) []func(View, KeyEvent) {
return getKeyListeners(view, subviewID, KeyDownEvent) return getEventListeners[View, KeyEvent](view, subviewID, KeyDownEvent)
} }
// GetKeyUpListeners returns the "key-up-event" listener list. If there are no listeners then the empty list is returned. // GetKeyUpListeners returns the "key-up-event" listener list. If there are no listeners then the empty list is returned.
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
func GetKeyUpListeners(view View, subviewID string) []func(View, KeyEvent) { func GetKeyUpListeners(view View, subviewID string) []func(View, KeyEvent) {
return getKeyListeners(view, subviewID, KeyUpEvent) return getEventListeners[View, KeyEvent](view, subviewID, KeyUpEvent)
} }

View File

@ -205,29 +205,38 @@ func (listView *listViewData) set(tag string, value any) bool {
switch tag { switch tag {
case ListItemClickedEvent: case ListItemClickedEvent:
listeners := listView.valueToItemListeners(value) listeners, ok := valueToEventListeners[ListView, int](value)
if listeners == nil { if !ok {
notCompatibleType(tag, value) notCompatibleType(tag, value)
return false return false
} else if listeners == nil {
listeners = []func(ListView, int){}
} }
listView.clickedListeners = listeners listView.clickedListeners = listeners
listView.propertyChangedEvent(tag) listView.propertyChangedEvent(tag)
return true return true
case ListItemSelectedEvent: case ListItemSelectedEvent:
listeners := listView.valueToItemListeners(value) listeners, ok := valueToEventListeners[ListView, int](value)
if listeners == nil { if !ok {
notCompatibleType(tag, value) notCompatibleType(tag, value)
return false return false
} else if listeners == nil {
listeners = []func(ListView, int){}
} }
listView.selectedListeners = listeners listView.selectedListeners = listeners
listView.propertyChangedEvent(tag) listView.propertyChangedEvent(tag)
return true return true
case ListItemCheckedEvent: case ListItemCheckedEvent:
if !listView.setItemCheckedEvent(value) { listeners, ok := valueToEventListeners[ListView, []int](value)
if !ok {
notCompatibleType(tag, value)
return false return false
} else if listeners == nil {
listeners = []func(ListView, []int){}
} }
listView.checkedListeners = listeners
listView.propertyChangedEvent(tag) listView.propertyChangedEvent(tag)
return true return true
@ -288,61 +297,6 @@ func (listView *listViewData) set(tag string, value any) bool {
return true return true
} }
func (listView *listViewData) setItemCheckedEvent(value any) bool {
switch value := value.(type) {
case func(ListView, []int):
listView.checkedListeners = []func(ListView, []int){value}
case func([]int):
fn := func(_ ListView, date []int) {
value(date)
}
listView.checkedListeners = []func(ListView, []int){fn}
case []func(ListView, []int):
listView.checkedListeners = value
case []func([]int):
listeners := make([]func(ListView, []int), len(value))
for i, val := range value {
if val == nil {
notCompatibleType(ListItemCheckedEvent, val)
return false
}
listeners[i] = func(_ ListView, date []int) {
val(date)
}
}
listView.checkedListeners = listeners
case []any:
listeners := make([]func(ListView, []int), len(value))
for i, val := range value {
if val == nil {
notCompatibleType(ListItemCheckedEvent, val)
return false
}
switch val := val.(type) {
case func(ListView, []int):
listeners[i] = val
case func([]int):
listeners[i] = func(_ ListView, checked []int) {
val(checked)
}
default:
notCompatibleType(ListItemCheckedEvent, val)
return false
}
}
listView.checkedListeners = listeners
}
return true
}
func (listView *listViewData) Get(tag string) any { func (listView *listViewData) Get(tag string) any {
return listView.get(listView.normalizeTag(tag)) return listView.get(listView.normalizeTag(tag))
} }
@ -460,61 +414,6 @@ func (listView *listViewData) setItems(value any) bool {
return true return true
} }
func (listView *listViewData) valueToItemListeners(value any) []func(ListView, int) {
if value == nil {
return []func(ListView, int){}
}
switch value := value.(type) {
case func(ListView, int):
return []func(ListView, int){value}
case func(int):
fn := func(_ ListView, index int) {
value(index)
}
return []func(ListView, int){fn}
case []func(ListView, int):
return value
case []func(int):
listeners := make([]func(ListView, int), len(value))
for i, val := range value {
if val == nil {
return nil
}
listeners[i] = func(_ ListView, index int) {
val(index)
}
}
return listeners
case []any:
listeners := make([]func(ListView, int), len(value))
for i, val := range value {
if val == nil {
return nil
}
switch val := val.(type) {
case func(ListView, int):
listeners[i] = val
case func(int):
listeners[i] = func(_ ListView, index int) {
val(index)
}
default:
return nil
}
}
return listeners
}
return nil
}
func (listView *listViewData) setChecked(value any) bool { func (listView *listViewData) setChecked(value any) bool {
var checked []int var checked []int
if value == nil { if value == nil {

View File

@ -205,7 +205,7 @@ func (player *mediaPlayerData) set(tag string, value any) bool {
case AbortEvent, CanPlayEvent, CanPlayThroughEvent, CompleteEvent, EmptiedEvent, LoadStartEvent, case AbortEvent, CanPlayEvent, CanPlayThroughEvent, CompleteEvent, EmptiedEvent, LoadStartEvent,
EndedEvent, LoadedDataEvent, LoadedMetadataEvent, PauseEvent, PlayEvent, PlayingEvent, EndedEvent, LoadedDataEvent, LoadedMetadataEvent, PauseEvent, PlayEvent, PlayingEvent,
ProgressEvent, SeekedEvent, SeekingEvent, StalledEvent, SuspendEvent, WaitingEvent: ProgressEvent, SeekedEvent, SeekingEvent, StalledEvent, SuspendEvent, WaitingEvent:
if listeners, ok := valueToPlayerListeners(value); ok { if listeners, ok := valueToNoParamListeners[MediaPlayer](value); ok {
if listeners == nil { if listeners == nil {
delete(player.properties, tag) delete(player.properties, tag)
} else { } else {
@ -218,7 +218,7 @@ func (player *mediaPlayerData) set(tag string, value any) bool {
notCompatibleType(tag, value) notCompatibleType(tag, value)
case DurationChangedEvent, RateChangedEvent, TimeUpdateEvent, VolumeChangedEvent: case DurationChangedEvent, RateChangedEvent, TimeUpdateEvent, VolumeChangedEvent:
if listeners, ok := valueToPlayerTimeListeners(value); ok { if listeners, ok := valueToEventListeners[MediaPlayer, float64](value); ok {
if listeners == nil { if listeners == nil {
delete(player.properties, tag) delete(player.properties, tag)
} else { } else {
@ -311,202 +311,6 @@ func (player *mediaPlayerData) setSource(value any) bool {
return true return true
} }
func valueToPlayerListeners(value any) ([]func(MediaPlayer), bool) {
if value == nil {
return nil, true
}
switch value := value.(type) {
case func(MediaPlayer):
return []func(MediaPlayer){value}, true
case func():
fn := func(MediaPlayer) {
value()
}
return []func(MediaPlayer){fn}, true
case []func(MediaPlayer):
if len(value) == 0 {
return nil, true
}
for _, fn := range value {
if fn == nil {
return nil, false
}
}
return value, true
case []func():
count := len(value)
if count == 0 {
return nil, true
}
listeners := make([]func(MediaPlayer), count)
for i, v := range value {
if v == nil {
return nil, false
}
listeners[i] = func(MediaPlayer) {
v()
}
}
return listeners, true
case []any:
count := len(value)
if count == 0 {
return nil, true
}
listeners := make([]func(MediaPlayer), count)
for i, v := range value {
if v == nil {
return nil, false
}
switch v := v.(type) {
case func(MediaPlayer):
listeners[i] = v
case func():
listeners[i] = func(MediaPlayer) {
v()
}
default:
return nil, false
}
}
return listeners, true
}
return nil, false
}
func valueToPlayerTimeListeners(value any) ([]func(MediaPlayer, float64), bool) {
if value == nil {
return nil, true
}
switch value := value.(type) {
case func(MediaPlayer, float64):
return []func(MediaPlayer, float64){value}, true
case func(float64):
fn := func(_ MediaPlayer, time float64) {
value(time)
}
return []func(MediaPlayer, float64){fn}, true
case func(MediaPlayer):
fn := func(player MediaPlayer, _ float64) {
value(player)
}
return []func(MediaPlayer, float64){fn}, true
case func():
fn := func(MediaPlayer, float64) {
value()
}
return []func(MediaPlayer, float64){fn}, true
case []func(MediaPlayer, float64):
if len(value) == 0 {
return nil, true
}
for _, fn := range value {
if fn == nil {
return nil, false
}
}
return value, true
case []func(float64):
count := len(value)
if count == 0 {
return nil, true
}
listeners := make([]func(MediaPlayer, float64), count)
for i, v := range value {
if v == nil {
return nil, false
}
listeners[i] = func(_ MediaPlayer, time float64) {
v(time)
}
}
return listeners, true
case []func(MediaPlayer):
count := len(value)
if count == 0 {
return nil, true
}
listeners := make([]func(MediaPlayer, float64), count)
for i, v := range value {
if v == nil {
return nil, false
}
listeners[i] = func(player MediaPlayer, _ float64) {
v(player)
}
}
return listeners, true
case []func():
count := len(value)
if count == 0 {
return nil, true
}
listeners := make([]func(MediaPlayer, float64), count)
for i, v := range value {
if v == nil {
return nil, false
}
listeners[i] = func(MediaPlayer, float64) {
v()
}
}
return listeners, true
case []any:
count := len(value)
if count == 0 {
return nil, true
}
listeners := make([]func(MediaPlayer, float64), count)
for i, v := range value {
if v == nil {
return nil, false
}
switch v := v.(type) {
case func(MediaPlayer, float64):
listeners[i] = v
case func(float64):
listeners[i] = func(_ MediaPlayer, time float64) {
v(time)
}
case func(MediaPlayer):
listeners[i] = func(player MediaPlayer, _ float64) {
v(player)
}
case func():
listeners[i] = func(MediaPlayer, float64) {
v()
}
default:
return nil, false
}
}
return listeners, true
}
return nil, false
}
func valueToPlayerErrorListeners(value any) ([]func(MediaPlayer, int, string), bool) { func valueToPlayerErrorListeners(value any) ([]func(MediaPlayer, int, string), bool) {
if value == nil { if value == nil {
return nil, true return nil, true

View File

@ -144,131 +144,6 @@ type MouseEvent struct {
MetaKey bool MetaKey bool
} }
func valueToMouseListeners(value any) ([]func(View, MouseEvent), bool) {
if value == nil {
return nil, true
}
switch value := value.(type) {
case func(View, MouseEvent):
return []func(View, MouseEvent){value}, true
case func(MouseEvent):
fn := func(_ View, event MouseEvent) {
value(event)
}
return []func(View, MouseEvent){fn}, true
case func(View):
fn := func(view View, _ MouseEvent) {
value(view)
}
return []func(View, MouseEvent){fn}, true
case func():
fn := func(View, MouseEvent) {
value()
}
return []func(View, MouseEvent){fn}, true
case []func(View, MouseEvent):
if len(value) == 0 {
return nil, true
}
for _, fn := range value {
if fn == nil {
return nil, false
}
}
return value, true
case []func(MouseEvent):
count := len(value)
if count == 0 {
return nil, true
}
listeners := make([]func(View, MouseEvent), count)
for i, v := range value {
if v == nil {
return nil, false
}
listeners[i] = func(_ View, event MouseEvent) {
v(event)
}
}
return listeners, true
case []func(View):
count := len(value)
if count == 0 {
return nil, true
}
listeners := make([]func(View, MouseEvent), count)
for i, v := range value {
if v == nil {
return nil, false
}
listeners[i] = func(view View, _ MouseEvent) {
v(view)
}
}
return listeners, true
case []func():
count := len(value)
if count == 0 {
return nil, true
}
listeners := make([]func(View, MouseEvent), count)
for i, v := range value {
if v == nil {
return nil, false
}
listeners[i] = func(View, MouseEvent) {
v()
}
}
return listeners, true
case []any:
count := len(value)
if count == 0 {
return nil, true
}
listeners := make([]func(View, MouseEvent), count)
for i, v := range value {
if v == nil {
return nil, false
}
switch v := v.(type) {
case func(View, MouseEvent):
listeners[i] = v
case func(MouseEvent):
listeners[i] = func(_ View, event MouseEvent) {
v(event)
}
case func(View):
listeners[i] = func(view View, _ MouseEvent) {
v(view)
}
case func():
listeners[i] = func(View, MouseEvent) {
v()
}
default:
return nil, false
}
}
return listeners, true
}
return nil, false
}
var mouseEvents = map[string]struct{ jsEvent, jsFunc string }{ var mouseEvents = map[string]struct{ jsEvent, jsFunc string }{
ClickEvent: {jsEvent: "onclick", jsFunc: "clickEvent"}, ClickEvent: {jsEvent: "onclick", jsFunc: "clickEvent"},
DoubleClickEvent: {jsEvent: "ondblclick", jsFunc: "doubleClickEvent"}, DoubleClickEvent: {jsEvent: "ondblclick", jsFunc: "doubleClickEvent"},
@ -281,7 +156,7 @@ var mouseEvents = map[string]struct{ jsEvent, jsFunc string }{
} }
func (view *viewData) setMouseListener(tag string, value any) bool { func (view *viewData) setMouseListener(tag string, value any) bool {
listeners, ok := valueToMouseListeners(value) listeners, ok := valueToEventListeners[View, MouseEvent](value)
if !ok { if !ok {
notCompatibleType(tag, value) notCompatibleType(tag, value)
return false return false
@ -309,20 +184,6 @@ func (view *viewData) removeMouseListener(tag string) {
} }
} }
func getMouseListeners(view View, subviewID string, tag string) []func(View, MouseEvent) {
if subviewID != "" {
view = ViewByID(view, subviewID)
}
if view != nil {
if value := view.Get(tag); value != nil {
if result, ok := value.([]func(View, MouseEvent)); ok {
return result
}
}
}
return []func(View, MouseEvent){}
}
func mouseEventsHtml(view View, buffer *strings.Builder) { func mouseEventsHtml(view View, buffer *strings.Builder) {
for tag, js := range mouseEvents { for tag, js := range mouseEvents {
if value := view.getRaw(tag); value != nil { if value := view.getRaw(tag); value != nil {
@ -363,64 +224,62 @@ func (event *MouseEvent) init(data DataObject) {
} }
func handleMouseEvents(view View, tag string, data DataObject) { func handleMouseEvents(view View, tag string, data DataObject) {
listeners := getMouseListeners(view, "", tag) listeners := getEventListeners[View, MouseEvent](view, "", tag)
if len(listeners) == 0 { if len(listeners) > 0 {
return var event MouseEvent
} event.init(data)
var event MouseEvent for _, listener := range listeners {
event.init(data) listener(view, event)
}
for _, listener := range listeners {
listener(view, event)
} }
} }
// GetClickListeners returns the "click-event" listener list. If there are no listeners then the empty list is returned. // GetClickListeners returns the "click-event" listener list. If there are no listeners then the empty list is returned.
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
func GetClickListeners(view View, subviewID string) []func(View, MouseEvent) { func GetClickListeners(view View, subviewID string) []func(View, MouseEvent) {
return getMouseListeners(view, subviewID, ClickEvent) return getEventListeners[View, MouseEvent](view, subviewID, ClickEvent)
} }
// GetDoubleClickListeners returns the "double-click-event" listener list. If there are no listeners then the empty list is returned. // GetDoubleClickListeners returns the "double-click-event" listener list. If there are no listeners then the empty list is returned.
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
func GetDoubleClickListeners(view View, subviewID string) []func(View, MouseEvent) { func GetDoubleClickListeners(view View, subviewID string) []func(View, MouseEvent) {
return getMouseListeners(view, subviewID, DoubleClickEvent) return getEventListeners[View, MouseEvent](view, subviewID, DoubleClickEvent)
} }
// GetContextMenuListeners returns the "context-menu" listener list. // GetContextMenuListeners returns the "context-menu" listener list.
// If there are no listeners then the empty list is returned. // If there are no listeners then the empty list is returned.
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
func GetContextMenuListeners(view View, subviewID string) []func(View, MouseEvent) { func GetContextMenuListeners(view View, subviewID string) []func(View, MouseEvent) {
return getMouseListeners(view, subviewID, ContextMenuEvent) return getEventListeners[View, MouseEvent](view, subviewID, ContextMenuEvent)
} }
// GetMouseDownListeners returns the "mouse-down" listener list. If there are no listeners then the empty list is returned. // GetMouseDownListeners returns the "mouse-down" listener list. If there are no listeners then the empty list is returned.
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
func GetMouseDownListeners(view View, subviewID string) []func(View, MouseEvent) { func GetMouseDownListeners(view View, subviewID string) []func(View, MouseEvent) {
return getMouseListeners(view, subviewID, MouseDown) return getEventListeners[View, MouseEvent](view, subviewID, MouseDown)
} }
// GetMouseUpListeners returns the "mouse-up" listener list. If there are no listeners then the empty list is returned. // GetMouseUpListeners returns the "mouse-up" listener list. If there are no listeners then the empty list is returned.
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
func GetMouseUpListeners(view View, subviewID string) []func(View, MouseEvent) { func GetMouseUpListeners(view View, subviewID string) []func(View, MouseEvent) {
return getMouseListeners(view, subviewID, MouseUp) return getEventListeners[View, MouseEvent](view, subviewID, MouseUp)
} }
// GetMouseMoveListeners returns the "mouse-move" listener list. If there are no listeners then the empty list is returned. // GetMouseMoveListeners returns the "mouse-move" listener list. If there are no listeners then the empty list is returned.
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
func GetMouseMoveListeners(view View, subviewID string) []func(View, MouseEvent) { func GetMouseMoveListeners(view View, subviewID string) []func(View, MouseEvent) {
return getMouseListeners(view, subviewID, MouseMove) return getEventListeners[View, MouseEvent](view, subviewID, MouseMove)
} }
// GetMouseOverListeners returns the "mouse-over" listener list. If there are no listeners then the empty list is returned. // GetMouseOverListeners returns the "mouse-over" listener list. If there are no listeners then the empty list is returned.
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
func GetMouseOverListeners(view View, subviewID string) []func(View, MouseEvent) { func GetMouseOverListeners(view View, subviewID string) []func(View, MouseEvent) {
return getMouseListeners(view, subviewID, MouseOver) return getEventListeners[View, MouseEvent](view, subviewID, MouseOver)
} }
// GetMouseOutListeners returns the "mouse-out" listener list. If there are no listeners then the empty list is returned. // GetMouseOutListeners returns the "mouse-out" listener list. If there are no listeners then the empty list is returned.
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
func GetMouseOutListeners(view View, subviewID string) []func(View, MouseEvent) { func GetMouseOutListeners(view View, subviewID string) []func(View, MouseEvent) {
return getMouseListeners(view, subviewID, MouseOut) return getEventListeners[View, MouseEvent](view, subviewID, MouseOut)
} }

View File

@ -99,52 +99,14 @@ func (picker *numberPickerData) set(tag string, value any) bool {
switch tag { switch tag {
case NumberChangedEvent: case NumberChangedEvent:
switch value := value.(type) { listeners, ok := valueToEventListeners[NumberPicker, float64](value)
case func(NumberPicker, float64): if !ok {
picker.numberChangedListeners = []func(NumberPicker, float64){value} notCompatibleType(tag, value)
return false
case func(float64): } else if listeners == nil {
fn := func(_ NumberPicker, newValue float64) { listeners = []func(NumberPicker, float64){}
value(newValue)
}
picker.numberChangedListeners = []func(NumberPicker, float64){fn}
case []func(NumberPicker, float64):
picker.numberChangedListeners = value
case []func(float64):
listeners := make([]func(NumberPicker, float64), len(value))
for i, val := range value {
if val == nil {
notCompatibleType(tag, val)
return false
}
listeners[i] = func(_ NumberPicker, newValue float64) {
val(newValue)
}
}
picker.numberChangedListeners = listeners
case []any:
listeners := make([]func(NumberPicker, float64), len(value))
for i, val := range value {
if val == nil {
notCompatibleType(tag, val)
return false
}
switch val := val.(type) {
case func(NumberPicker, float64):
listeners[i] = val
default:
notCompatibleType(tag, val)
return false
}
}
picker.numberChangedListeners = listeners
} }
picker.numberChangedListeners = listeners
picker.propertyChangedEvent(tag) picker.propertyChangedEvent(tag)
return true return true
@ -386,15 +348,5 @@ func GetNumberPickerValue(view View, subviewID string) float64 {
// If there are no listeners then the empty list is returned // If there are no listeners then the empty list is returned
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
func GetNumberChangedListeners(view View, subviewID string) []func(NumberPicker, float64) { func GetNumberChangedListeners(view View, subviewID string) []func(NumberPicker, float64) {
if subviewID != "" { return getEventListeners[NumberPicker, float64](view, subviewID, NumberChangedEvent)
view = ViewByID(view, subviewID)
}
if view != nil {
if value := view.Get(NumberChangedEvent); value != nil {
if listeners, ok := value.([]func(NumberPicker, float64)); ok {
return listeners
}
}
}
return []func(NumberPicker, float64){}
} }

View File

@ -87,131 +87,6 @@ type PointerEvent struct {
IsPrimary bool IsPrimary bool
} }
func valueToPointerListeners(value any) ([]func(View, PointerEvent), bool) {
if value == nil {
return nil, true
}
switch value := value.(type) {
case func(View, PointerEvent):
return []func(View, PointerEvent){value}, true
case func(PointerEvent):
fn := func(_ View, event PointerEvent) {
value(event)
}
return []func(View, PointerEvent){fn}, true
case func(View):
fn := func(view View, _ PointerEvent) {
value(view)
}
return []func(View, PointerEvent){fn}, true
case func():
fn := func(View, PointerEvent) {
value()
}
return []func(View, PointerEvent){fn}, true
case []func(View, PointerEvent):
if len(value) == 0 {
return nil, true
}
for _, fn := range value {
if fn == nil {
return nil, false
}
}
return value, true
case []func(PointerEvent):
count := len(value)
if count == 0 {
return nil, true
}
listeners := make([]func(View, PointerEvent), count)
for i, v := range value {
if v == nil {
return nil, false
}
listeners[i] = func(_ View, event PointerEvent) {
v(event)
}
}
return listeners, true
case []func(View):
count := len(value)
if count == 0 {
return nil, true
}
listeners := make([]func(View, PointerEvent), count)
for i, v := range value {
if v == nil {
return nil, false
}
listeners[i] = func(view View, _ PointerEvent) {
v(view)
}
}
return listeners, true
case []func():
count := len(value)
if count == 0 {
return nil, true
}
listeners := make([]func(View, PointerEvent), count)
for i, v := range value {
if v == nil {
return nil, false
}
listeners[i] = func(View, PointerEvent) {
v()
}
}
return listeners, true
case []any:
count := len(value)
if count == 0 {
return nil, true
}
listeners := make([]func(View, PointerEvent), count)
for i, v := range value {
if v == nil {
return nil, false
}
switch v := v.(type) {
case func(View, PointerEvent):
listeners[i] = v
case func(PointerEvent):
listeners[i] = func(_ View, event PointerEvent) {
v(event)
}
case func(View):
listeners[i] = func(view View, _ PointerEvent) {
v(view)
}
case func():
listeners[i] = func(View, PointerEvent) {
v()
}
default:
return nil, false
}
}
return listeners, true
}
return nil, false
}
var pointerEvents = map[string]struct{ jsEvent, jsFunc string }{ var pointerEvents = map[string]struct{ jsEvent, jsFunc string }{
PointerDown: {jsEvent: "onpointerdown", jsFunc: "pointerDownEvent"}, PointerDown: {jsEvent: "onpointerdown", jsFunc: "pointerDownEvent"},
PointerUp: {jsEvent: "onpointerup", jsFunc: "pointerUpEvent"}, PointerUp: {jsEvent: "onpointerup", jsFunc: "pointerUpEvent"},
@ -222,7 +97,7 @@ var pointerEvents = map[string]struct{ jsEvent, jsFunc string }{
} }
func (view *viewData) setPointerListener(tag string, value any) bool { func (view *viewData) setPointerListener(tag string, value any) bool {
listeners, ok := valueToPointerListeners(value) listeners, ok := valueToEventListeners[View, PointerEvent](value)
if !ok { if !ok {
notCompatibleType(tag, value) notCompatibleType(tag, value)
return false return false
@ -250,20 +125,6 @@ func (view *viewData) removePointerListener(tag string) {
} }
} }
func getPointerListeners(view View, subviewID string, tag string) []func(View, PointerEvent) {
if subviewID != "" {
view = ViewByID(view, subviewID)
}
if view != nil {
if value := view.Get(tag); value != nil {
if result, ok := value.([]func(View, PointerEvent)); ok {
return result
}
}
}
return []func(View, PointerEvent){}
}
func pointerEventsHtml(view View, buffer *strings.Builder) { func pointerEventsHtml(view View, buffer *strings.Builder) {
for tag, js := range pointerEvents { for tag, js := range pointerEvents {
if value := view.getRaw(tag); value != nil { if value := view.getRaw(tag); value != nil {
@ -291,7 +152,7 @@ func (event *PointerEvent) init(data DataObject) {
} }
func handlePointerEvents(view View, tag string, data DataObject) { func handlePointerEvents(view View, tag string, data DataObject) {
listeners := getPointerListeners(view, "", tag) listeners := getEventListeners[View, PointerEvent](view, "", tag)
if len(listeners) == 0 { if len(listeners) == 0 {
return return
} }
@ -307,35 +168,35 @@ func handlePointerEvents(view View, tag string, data DataObject) {
// GetPointerDownListeners returns the "pointer-down" listener list. If there are no listeners then the empty list is returned. // GetPointerDownListeners returns the "pointer-down" listener list. If there are no listeners then the empty list is returned.
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
func GetPointerDownListeners(view View, subviewID string) []func(View, PointerEvent) { func GetPointerDownListeners(view View, subviewID string) []func(View, PointerEvent) {
return getPointerListeners(view, subviewID, PointerDown) return getEventListeners[View, PointerEvent](view, subviewID, PointerDown)
} }
// GetPointerUpListeners returns the "pointer-up" listener list. If there are no listeners then the empty list is returned. // GetPointerUpListeners returns the "pointer-up" listener list. If there are no listeners then the empty list is returned.
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
func GetPointerUpListeners(view View, subviewID string) []func(View, PointerEvent) { func GetPointerUpListeners(view View, subviewID string) []func(View, PointerEvent) {
return getPointerListeners(view, subviewID, PointerUp) return getEventListeners[View, PointerEvent](view, subviewID, PointerUp)
} }
// GetPointerMoveListeners returns the "pointer-move" listener list. If there are no listeners then the empty list is returned. // GetPointerMoveListeners returns the "pointer-move" listener list. If there are no listeners then the empty list is returned.
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
func GetPointerMoveListeners(view View, subviewID string) []func(View, PointerEvent) { func GetPointerMoveListeners(view View, subviewID string) []func(View, PointerEvent) {
return getPointerListeners(view, subviewID, PointerMove) return getEventListeners[View, PointerEvent](view, subviewID, PointerMove)
} }
// GetPointerCancelListeners returns the "pointer-cancel" listener list. If there are no listeners then the empty list is returned. // GetPointerCancelListeners returns the "pointer-cancel" listener list. If there are no listeners then the empty list is returned.
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
func GetPointerCancelListeners(view View, subviewID string) []func(View, PointerEvent) { func GetPointerCancelListeners(view View, subviewID string) []func(View, PointerEvent) {
return getPointerListeners(view, subviewID, PointerCancel) return getEventListeners[View, PointerEvent](view, subviewID, PointerCancel)
} }
// GetPointerOverListeners returns the "pointer-over" listener list. If there are no listeners then the empty list is returned. // GetPointerOverListeners returns the "pointer-over" listener list. If there are no listeners then the empty list is returned.
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
func GetPointerOverListeners(view View, subviewID string) []func(View, PointerEvent) { func GetPointerOverListeners(view View, subviewID string) []func(View, PointerEvent) {
return getPointerListeners(view, subviewID, PointerOver) return getEventListeners[View, PointerEvent](view, subviewID, PointerOver)
} }
// GetPointerOutListeners returns the "pointer-out" listener list. If there are no listeners then the empty list is returned. // GetPointerOutListeners returns the "pointer-out" listener list. If there are no listeners then the empty list is returned.
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
func GetPointerOutListeners(view View, subviewID string) []func(View, PointerEvent) { func GetPointerOutListeners(view View, subviewID string) []func(View, PointerEvent) {
return getPointerListeners(view, subviewID, PointerOut) return getEventListeners[View, PointerEvent](view, subviewID, PointerOut)
} }

View File

@ -36,6 +36,10 @@ const (
// It occurs after the Popup disappears from the screen. // It occurs after the Popup disappears from the screen.
// The main listener for this event has the following format: func(Popup) // The main listener for this event has the following format: func(Popup)
DismissEvent = "dismiss-event" DismissEvent = "dismiss-event"
// PopupArrow is the constant for the "popup-arrow" property tag.
// Using the "popup-arrow" property you can add ...
PopupArrow = "popup-arrow"
) )
// PopupButton describes a button that will be placed at the bottom of the window. // PopupButton describes a button that will be placed at the bottom of the window.
@ -181,11 +185,10 @@ func (popup *popupData) init(view View, params Params) {
viewRow := 0 viewRow := 0
if title != nil || closeButton { if title != nil || closeButton {
viewRow = 1 viewRow = 1
titleHeight, _ := sizeConstant(popup.Session(), "ruiPopupTitleHeight")
titleView := NewGridLayout(session, Params{ titleView := NewGridLayout(session, Params{
Row: 0, Row: 0,
Style: titleStyle, Style: titleStyle,
CellWidth: []SizeUnit{Fr(1), titleHeight}, CellWidth: []any{Fr(1), "@ruiPopupTitleHeight"},
CellVerticalAlign: CenterAlign, CellVerticalAlign: CenterAlign,
PaddingLeft: Px(12), PaddingLeft: Px(12),
}) })
@ -195,8 +198,8 @@ func (popup *popupData) init(view View, params Params) {
if closeButton { if closeButton {
titleView.Append(NewGridLayout(session, Params{ titleView.Append(NewGridLayout(session, Params{
Column: 1, Column: 1,
Height: titleHeight, Height: "@ruiPopupTitleHeight",
Width: titleHeight, Width: "@ruiPopupTitleHeight",
CellHorizontalAlign: CenterAlign, CellHorizontalAlign: CenterAlign,
CellVerticalAlign: CenterAlign, CellVerticalAlign: CenterAlign,
TextSize: Px(20), TextSize: Px(20),

View File

@ -22,146 +22,18 @@ func (view *viewData) onItemResize(self View, index string, x, y, width, height
} }
func (view *viewData) setFrameListener(tag string, value any) bool { func (view *viewData) setFrameListener(tag string, value any) bool {
if value == nil { listeners, ok := valueToEventListeners[FilePicker, []FileInfo](value)
delete(view.properties, tag) if !ok {
return true
}
switch value := value.(type) {
case func(View, Frame):
view.properties[tag] = []func(View, Frame){value}
case []func(View, Frame):
if len(value) > 0 {
view.properties[tag] = value
} else {
delete(view.properties, tag)
return true
}
case func(Frame):
fn := func(_ View, frame Frame) {
value(frame)
}
view.properties[tag] = []func(View, Frame){fn}
case []func(Frame):
count := len(value)
if count == 0 {
delete(view.properties, tag)
return true
}
listeners := make([]func(View, Frame), count)
for i, val := range value {
if val == nil {
notCompatibleType(tag, val)
return false
}
listeners[i] = func(_ View, frame Frame) {
val(frame)
}
}
view.properties[tag] = listeners
case func(View):
fn := func(view View, _ Frame) {
value(view)
}
view.properties[tag] = []func(View, Frame){fn}
case []func(View):
count := len(value)
if count == 0 {
delete(view.properties, tag)
return true
}
listeners := make([]func(View, Frame), count)
for i, val := range value {
if val == nil {
notCompatibleType(tag, val)
return false
}
listeners[i] = func(view View, _ Frame) {
val(view)
}
}
view.properties[tag] = listeners
case func():
fn := func(View, Frame) {
value()
}
view.properties[tag] = []func(View, Frame){fn}
case []func():
count := len(value)
if count == 0 {
delete(view.properties, tag)
return true
}
listeners := make([]func(View, Frame), count)
for i, val := range value {
if val == nil {
notCompatibleType(tag, val)
return false
}
listeners[i] = func(View, Frame) {
val()
}
}
view.properties[tag] = listeners
case []any:
count := len(value)
if count == 0 {
delete(view.properties, tag)
return true
}
listeners := make([]func(View, Frame), count)
for i, val := range value {
if val == nil {
notCompatibleType(tag, val)
return false
}
switch val := val.(type) {
case func(View, Frame):
listeners[i] = val
case func(Frame):
listeners[i] = func(_ View, frame Frame) {
val(frame)
}
case func(View):
listeners[i] = func(view View, _ Frame) {
val(view)
}
case func():
listeners[i] = func(View, Frame) {
val()
}
default:
notCompatibleType(tag, val)
return false
}
}
view.properties[tag] = listeners
default:
notCompatibleType(tag, value) notCompatibleType(tag, value)
return false return false
} }
if listeners == nil {
delete(view.properties, tag)
} else {
view.properties[tag] = listeners
}
view.propertyChangedEvent(tag)
return true return true
} }
@ -204,15 +76,5 @@ func GetViewFrame(view View, subviewID string) Frame {
// GetResizeListeners returns the list of "resize-event" listeners. If there are no listeners then the empty list is returned // GetResizeListeners returns the list of "resize-event" listeners. If there are no listeners then the empty list is returned
// If the second argument (subviewID) is "" then the listeners list of the first argument (view) is returned // If the second argument (subviewID) is "" then the listeners list of the first argument (view) is returned
func GetResizeListeners(view View, subviewID string) []func(View, Frame) { func GetResizeListeners(view View, subviewID string) []func(View, Frame) {
if subviewID != "" { return getEventListeners[View, Frame](view, subviewID, ResizeEvent)
view = ViewByID(view, subviewID)
}
if view != nil {
if value := view.Get(ResizeEvent); value != nil {
if result, ok := value.([]func(View, Frame)); ok {
return result
}
}
}
return []func(View, Frame){}
} }

View File

@ -3,7 +3,7 @@ package rui
import "fmt" import "fmt"
// ScrollEvent is the constant for "scroll-event" property tag. // ScrollEvent is the constant for "scroll-event" property tag.
// The "resize-event" is fired when the content of the view is scrolled. // The "scroll-event" is fired when the content of the view is scrolled.
// The main listener format: // The main listener format:
// func(View, Frame). // func(View, Frame).
// The additional listener formats: // The additional listener formats:
@ -46,17 +46,7 @@ func GetViewScroll(view View, subviewID string) Frame {
// GetScrollListeners returns the list of "scroll-event" listeners. If there are no listeners then the empty list is returned // GetScrollListeners returns the list of "scroll-event" listeners. If there are no listeners then the empty list is returned
// If the second argument (subviewID) is "" then the listeners list of the first argument (view) is returned // If the second argument (subviewID) is "" then the listeners list of the first argument (view) is returned
func GetScrollListeners(view View, subviewID string) []func(View, Frame) { func GetScrollListeners(view View, subviewID string) []func(View, Frame) {
if subviewID != "" { return getEventListeners[View, Frame](view, subviewID, ResizeEvent)
view = ViewByID(view, subviewID)
}
if view != nil {
if value := view.Get(ScrollEvent); value != nil {
if result, ok := value.([]func(View, Frame)); ok {
return result
}
}
}
return []func(View, Frame){}
} }
// ScrollTo scrolls the view's content to the given position. // ScrollTo scrolls the view's content to the given position.

View File

@ -431,7 +431,7 @@ func (session *sessionData) handleViewEvent(command string, data DataObject) {
if view := session.viewByHTMLID(viewID); view != nil { if view := session.viewByHTMLID(viewID); view != nil {
view.handleCommand(view, command, data) view.handleCommand(view, command, data)
} }
} else { } else if command != "clickOutsidePopup" {
ErrorLog(`"id" property not found. Event: ` + command) ErrorLog(`"id" property not found. Event: ` + command)
} }
} }

View File

@ -109,8 +109,8 @@ func (layout *stackLayoutData) set(tag string, value any) bool {
switch tag { switch tag {
case TransitionEndEvent: case TransitionEndEvent:
listeners, ok := valueToAnimationListeners(value) listeners, ok := valueToEventListeners[View, string](value)
if ok { if ok && listeners != nil {
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

View File

@ -384,20 +384,24 @@ func (table *tableViewData) set(tag string, value any) bool {
table.cellSelectedListener = listeners table.cellSelectedListener = listeners
case TableRowClickedEvent: case TableRowClickedEvent:
listeners := table.valueToRowListeners(value) listeners, ok := valueToEventListeners[TableView, int](value)
if listeners == nil { if !ok {
notCompatibleType(tag, value) notCompatibleType(tag, value)
return false return false
} else if listeners == nil {
listeners = []func(TableView, int){}
} }
table.rowClickedListener = listeners table.rowClickedListener = listeners
case TableRowSelectedEvent: case TableRowSelectedEvent:
listeners := table.valueToRowListeners(value) listeners, ok := valueToEventListeners[TableView, int](value)
if listeners == nil { if !ok {
notCompatibleType(tag, value) notCompatibleType(tag, value)
return false return false
} else if listeners == nil {
listeners = []func(TableView, int){}
} }
table.rowSelectedListener = []func(TableView, int){} table.rowSelectedListener = listeners
case CellStyle: case CellStyle:
if style, ok := value.(TableCellStyle); ok { if style, ok := value.(TableCellStyle); ok {
@ -731,61 +735,6 @@ func (table *tableViewData) valueToCellListeners(value any) []func(TableView, in
return nil return nil
} }
func (table *tableViewData) valueToRowListeners(value any) []func(TableView, int) {
if value == nil {
return []func(TableView, int){}
}
switch value := value.(type) {
case func(TableView, int):
return []func(TableView, int){value}
case func(int):
fn := func(_ TableView, index int) {
value(index)
}
return []func(TableView, int){fn}
case []func(TableView, int):
return value
case []func(int):
listeners := make([]func(TableView, int), len(value))
for i, val := range value {
if val == nil {
return nil
}
listeners[i] = func(_ TableView, index int) {
val(index)
}
}
return listeners
case []any:
listeners := make([]func(TableView, int), len(value))
for i, val := range value {
if val == nil {
return nil
}
switch val := val.(type) {
case func(TableView, int):
listeners[i] = val
case func(int):
listeners[i] = func(_ TableView, index int) {
val(index)
}
default:
return nil
}
}
return listeners
}
return nil
}
func (table *tableViewData) htmlTag() string { func (table *tableViewData) htmlTag() string {
return "table" return "table"
} }

View File

@ -210,10 +210,12 @@ func (tabsLayout *tabsLayoutData) set(tag string, value any) bool {
tabsLayout.tabListener = listeners tabsLayout.tabListener = listeners
case TabCloseEvent: case TabCloseEvent:
listeners := tabsLayout.valueToCloseListeners(value) listeners, ok := valueToEventListeners[TabsLayout, int](value)
if listeners == nil { if !ok {
notCompatibleType(tag, value) notCompatibleType(tag, value)
return false return false
} else if listeners == nil {
listeners = []func(TabsLayout, int){}
} }
tabsLayout.tabCloseListener = listeners tabsLayout.tabCloseListener = listeners
@ -433,61 +435,6 @@ func (tabsLayout *tabsLayoutData) valueToTabListeners(value any) []func(TabsLayo
return nil return nil
} }
func (tabsLayout *tabsLayoutData) valueToCloseListeners(value any) []func(TabsLayout, int) {
if value == nil {
return []func(TabsLayout, int){}
}
switch value := value.(type) {
case func(TabsLayout, int):
return []func(TabsLayout, int){value}
case func(int):
fn := func(_ TabsLayout, index int) {
value(index)
}
return []func(TabsLayout, int){fn}
case []func(TabsLayout, int):
return value
case []func(int):
listeners := make([]func(TabsLayout, int), len(value))
for i, val := range value {
if val == nil {
return nil
}
listeners[i] = func(_ TabsLayout, index int) {
val(index)
}
}
return listeners
case []any:
listeners := make([]func(TabsLayout, int), len(value))
for i, val := range value {
if val == nil {
return nil
}
switch val := val.(type) {
case func(TabsLayout, int):
listeners[i] = val
case func(int):
listeners[i] = func(_ TabsLayout, index int) {
val(index)
}
default:
return nil
}
}
return listeners
}
return nil
}
func (tabsLayout *tabsLayoutData) tabsLocation() int { func (tabsLayout *tabsLayoutData) tabsLocation() int {
tabs, _ := enumProperty(tabsLayout, Tabs, tabsLayout.session, 0) tabs, _ := enumProperty(tabsLayout, Tabs, tabsLayout.session, 0)
return tabs return tabs

View File

@ -223,57 +223,14 @@ func (picker *timePickerData) set(tag string, value any) bool {
} }
case TimeChangedEvent: case TimeChangedEvent:
switch value := value.(type) { listeners, ok := valueToEventListeners[TimePicker, time.Time](value)
case func(TimePicker, time.Time): if !ok {
picker.timeChangedListeners = []func(TimePicker, time.Time){value} notCompatibleType(tag, value)
return false
case func(time.Time): } else if listeners == nil {
fn := func(_ TimePicker, time time.Time) { listeners = []func(TimePicker, time.Time){}
value(time)
}
picker.timeChangedListeners = []func(TimePicker, time.Time){fn}
case []func(TimePicker, time.Time):
picker.timeChangedListeners = value
case []func(time.Time):
listeners := make([]func(TimePicker, time.Time), len(value))
for i, val := range value {
if val == nil {
notCompatibleType(tag, val)
return false
}
listeners[i] = func(_ TimePicker, time time.Time) {
val(time)
}
}
picker.timeChangedListeners = listeners
case []any:
listeners := make([]func(TimePicker, time.Time), len(value))
for i, val := range value {
if val == nil {
notCompatibleType(tag, val)
return false
}
switch val := val.(type) {
case func(TimePicker, time.Time):
listeners[i] = val
case func(time.Time):
listeners[i] = func(_ TimePicker, time time.Time) {
val(time)
}
default:
notCompatibleType(tag, val)
return false
}
}
picker.timeChangedListeners = listeners
} }
picker.timeChangedListeners = listeners
picker.propertyChangedEvent(tag) picker.propertyChangedEvent(tag)
return true return true
@ -458,15 +415,5 @@ func GetTimePickerValue(view View, subviewID string) time.Time {
// If there are no listeners then the empty list is returned // If there are no listeners then the empty list is returned
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
func GetTimeChangedListeners(view View, subviewID string) []func(TimePicker, time.Time) { func GetTimeChangedListeners(view View, subviewID string) []func(TimePicker, time.Time) {
if subviewID != "" { return getEventListeners[TimePicker, time.Time](view, subviewID, TimeChangedEvent)
view = ViewByID(view, subviewID)
}
if view != nil {
if value := view.Get(TimeChangedEvent); value != nil {
if listeners, ok := value.([]func(TimePicker, time.Time)); ok {
return listeners
}
}
}
return []func(TimePicker, time.Time){}
} }

View File

@ -90,131 +90,6 @@ type TouchEvent struct {
MetaKey bool MetaKey bool
} }
func valueToTouchListeners(value any) ([]func(View, TouchEvent), bool) {
if value == nil {
return nil, true
}
switch value := value.(type) {
case func(View, TouchEvent):
return []func(View, TouchEvent){value}, true
case func(TouchEvent):
fn := func(_ View, event TouchEvent) {
value(event)
}
return []func(View, TouchEvent){fn}, true
case func(View):
fn := func(view View, _ TouchEvent) {
value(view)
}
return []func(View, TouchEvent){fn}, true
case func():
fn := func(View, TouchEvent) {
value()
}
return []func(View, TouchEvent){fn}, true
case []func(View, TouchEvent):
if len(value) == 0 {
return nil, true
}
for _, fn := range value {
if fn == nil {
return nil, false
}
}
return value, true
case []func(TouchEvent):
count := len(value)
if count == 0 {
return nil, true
}
listeners := make([]func(View, TouchEvent), count)
for i, v := range value {
if v == nil {
return nil, false
}
listeners[i] = func(_ View, event TouchEvent) {
v(event)
}
}
return listeners, true
case []func(View):
count := len(value)
if count == 0 {
return nil, true
}
listeners := make([]func(View, TouchEvent), count)
for i, v := range value {
if v == nil {
return nil, false
}
listeners[i] = func(view View, _ TouchEvent) {
v(view)
}
}
return listeners, true
case []func():
count := len(value)
if count == 0 {
return nil, true
}
listeners := make([]func(View, TouchEvent), count)
for i, v := range value {
if v == nil {
return nil, false
}
listeners[i] = func(View, TouchEvent) {
v()
}
}
return listeners, true
case []any:
count := len(value)
if count == 0 {
return nil, true
}
listeners := make([]func(View, TouchEvent), count)
for i, v := range value {
if v == nil {
return nil, false
}
switch v := v.(type) {
case func(View, TouchEvent):
listeners[i] = v
case func(TouchEvent):
listeners[i] = func(_ View, event TouchEvent) {
v(event)
}
case func(View):
listeners[i] = func(view View, _ TouchEvent) {
v(view)
}
case func():
listeners[i] = func(View, TouchEvent) {
v()
}
default:
return nil, false
}
}
return listeners, true
}
return nil, false
}
var touchEvents = map[string]struct{ jsEvent, jsFunc string }{ var touchEvents = map[string]struct{ jsEvent, jsFunc string }{
TouchStart: {jsEvent: "ontouchstart", jsFunc: "touchStartEvent"}, TouchStart: {jsEvent: "ontouchstart", jsFunc: "touchStartEvent"},
TouchEnd: {jsEvent: "ontouchend", jsFunc: "touchEndEvent"}, TouchEnd: {jsEvent: "ontouchend", jsFunc: "touchEndEvent"},
@ -223,7 +98,7 @@ var touchEvents = map[string]struct{ jsEvent, jsFunc string }{
} }
func (view *viewData) setTouchListener(tag string, value any) bool { func (view *viewData) setTouchListener(tag string, value any) bool {
listeners, ok := valueToTouchListeners(value) listeners, ok := valueToEventListeners[View, TouchEvent](value)
if !ok { if !ok {
notCompatibleType(tag, value) notCompatibleType(tag, value)
return false return false
@ -251,20 +126,6 @@ func (view *viewData) removeTouchListener(tag string) {
} }
} }
func getTouchListeners(view View, subviewID string, tag string) []func(View, TouchEvent) {
if subviewID != "" {
view = ViewByID(view, subviewID)
}
if view != nil {
if value := view.Get(tag); value != nil {
if result, ok := value.([]func(View, TouchEvent)); ok {
return result
}
}
}
return []func(View, TouchEvent){}
}
func touchEventsHtml(view View, buffer *strings.Builder) { func touchEventsHtml(view View, buffer *strings.Builder) {
for tag, js := range touchEvents { for tag, js := range touchEvents {
if value := view.getRaw(tag); value != nil { if value := view.getRaw(tag); value != nil {
@ -309,7 +170,7 @@ func (event *TouchEvent) init(data DataObject) {
} }
func handleTouchEvents(view View, tag string, data DataObject) { func handleTouchEvents(view View, tag string, data DataObject) {
listeners := getTouchListeners(view, "", tag) listeners := getEventListeners[View, TouchEvent](view, "", tag)
if len(listeners) == 0 { if len(listeners) == 0 {
return return
} }
@ -325,23 +186,23 @@ func handleTouchEvents(view View, tag string, data DataObject) {
// GetTouchStartListeners returns the "touch-start" listener list. If there are no listeners then the empty list is returned. // GetTouchStartListeners returns the "touch-start" listener list. If there are no listeners then the empty list is returned.
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
func GetTouchStartListeners(view View, subviewID string) []func(View, TouchEvent) { func GetTouchStartListeners(view View, subviewID string) []func(View, TouchEvent) {
return getTouchListeners(view, subviewID, TouchStart) return getEventListeners[View, TouchEvent](view, subviewID, TouchStart)
} }
// GetTouchEndListeners returns the "touch-end" listener list. If there are no listeners then the empty list is returned. // GetTouchEndListeners returns the "touch-end" listener list. If there are no listeners then the empty list is returned.
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
func GetTouchEndListeners(view View, subviewID string) []func(View, TouchEvent) { func GetTouchEndListeners(view View, subviewID string) []func(View, TouchEvent) {
return getTouchListeners(view, subviewID, TouchEnd) return getEventListeners[View, TouchEvent](view, subviewID, TouchEnd)
} }
// GetTouchMoveListeners returns the "touch-move" listener list. If there are no listeners then the empty list is returned. // GetTouchMoveListeners returns the "touch-move" listener list. If there are no listeners then the empty list is returned.
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
func GetTouchMoveListeners(view View, subviewID string) []func(View, TouchEvent) { func GetTouchMoveListeners(view View, subviewID string) []func(View, TouchEvent) {
return getTouchListeners(view, subviewID, TouchMove) return getEventListeners[View, TouchEvent](view, subviewID, TouchMove)
} }
// GetTouchCancelListeners returns the "touch-cancel" listener list. If there are no listeners then the empty list is returned. // GetTouchCancelListeners returns the "touch-cancel" listener list. If there are no listeners then the empty list is returned.
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
func GetTouchCancelListeners(view View, subviewID string) []func(View, TouchEvent) { func GetTouchCancelListeners(view View, subviewID string) []func(View, TouchEvent) {
return getTouchListeners(view, subviewID, TouchCancel) return getEventListeners[View, TouchEvent](view, subviewID, TouchCancel)
} }