mirror of https://github.com/anoshenko/rui.git
				
				
				
			Refactoring and optimisation
This commit is contained in:
		
							parent
							
								
									ece1d04e4e
								
							
						
					
					
						commit
						e23ad83b6c
					
				|  | @ -51,131 +51,6 @@ const ( | |||
| 	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 }{ | ||||
| 	TransitionRunEvent:    {jsEvent: "ontransitionrun", jsFunc: "transitionRunEvent"}, | ||||
| 	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 { | ||||
| 	listeners, ok := valueToAnimationListeners(value) | ||||
| 	listeners, ok := valueToEventListeners[View, string](value) | ||||
| 	if !ok { | ||||
| 		notCompatibleType(tag, value) | ||||
| 		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) { | ||||
| 	for tag, js := range transitionEvents { | ||||
| 		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) | ||||
| 		} | ||||
| 	} | ||||
|  | @ -264,7 +125,7 @@ var animationEvents = map[string]struct{ jsEvent, jsFunc string }{ | |||
| } | ||||
| 
 | ||||
| func (view *viewData) setAnimationListener(tag string, value any) bool { | ||||
| 	listeners, ok := valueToAnimationListeners(value) | ||||
| 	listeners, ok := valueToEventListeners[View, string](value) | ||||
| 	if !ok { | ||||
| 		notCompatibleType(tag, value) | ||||
| 		return false | ||||
|  | @ -303,7 +164,7 @@ func animationEventsHtml(view View, buffer *strings.Builder) { | |||
| } | ||||
| 
 | ||||
| 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 := "" | ||||
| 		if name, ok := data.PropertyValue("name"); ok { | ||||
| 			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 the second argument (subviewID) is "" then a value from the first argument (view) is returned.
 | ||||
| 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.
 | ||||
| // 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.
 | ||||
| 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.
 | ||||
| // 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.
 | ||||
| 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.
 | ||||
| // 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.
 | ||||
| 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.
 | ||||
| // 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.
 | ||||
| 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.
 | ||||
| // 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.
 | ||||
| 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.
 | ||||
| // 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.
 | ||||
| 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.
 | ||||
| // 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.
 | ||||
| func GetAnimationIterationListeners(view View, subviewID string) []func(View, string) { | ||||
| 	return getAnimationListeners(view, subviewID, AnimationIterationEvent) | ||||
| 	return getEventListeners[View, string](view, subviewID, AnimationIterationEvent) | ||||
| } | ||||
|  |  | |||
|  | @ -87,57 +87,14 @@ func (picker *colorPickerData) set(tag string, value any) bool { | |||
| 
 | ||||
| 	switch tag { | ||||
| 	case ColorChangedEvent: | ||||
| 		switch value := value.(type) { | ||||
| 		case func(ColorPicker, Color): | ||||
| 			picker.colorChangedListeners = []func(ColorPicker, Color){value} | ||||
| 
 | ||||
| 		case func(Color): | ||||
| 			fn := func(_ ColorPicker, date 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 | ||||
| 		listeners, ok := valueToEventListeners[ColorPicker, Color](value) | ||||
| 		if !ok { | ||||
| 			notCompatibleType(tag, value) | ||||
| 			return false | ||||
| 		} else if listeners == nil { | ||||
| 			listeners = []func(ColorPicker, Color){} | ||||
| 		} | ||||
| 		picker.colorChangedListeners = listeners | ||||
| 		picker.propertyChangedEvent(tag) | ||||
| 		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 the second argument (subviewID) is "" then a value from the first argument (view) is returned.
 | ||||
| func GetColorChangedListeners(view View, subviewID string) []func(ColorPicker, Color) { | ||||
| 	if subviewID != "" { | ||||
| 		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){} | ||||
| 	return getEventListeners[ColorPicker, Color](view, subviewID, ColorChangedEvent) | ||||
| } | ||||
|  |  | |||
|  | @ -235,57 +235,14 @@ func (picker *datePickerData) set(tag string, value any) bool { | |||
| 		} | ||||
| 
 | ||||
| 	case DateChangedEvent: | ||||
| 		switch value := value.(type) { | ||||
| 		case func(DatePicker, time.Time): | ||||
| 			picker.dateChangedListeners = []func(DatePicker, time.Time){value} | ||||
| 
 | ||||
| 		case func(time.Time): | ||||
| 			fn := func(_ DatePicker, date 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 | ||||
| 		listeners, ok := valueToEventListeners[DatePicker, time.Time](value) | ||||
| 		if !ok { | ||||
| 			notCompatibleType(tag, value) | ||||
| 			return false | ||||
| 		} else if listeners == nil { | ||||
| 			listeners = []func(DatePicker, time.Time){} | ||||
| 		} | ||||
| 		picker.dateChangedListeners = listeners | ||||
| 		picker.propertyChangedEvent(tag) | ||||
| 		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 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) { | ||||
| 	if subviewID != "" { | ||||
| 		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){} | ||||
| 	return getEventListeners[DatePicker, time.Time](view, subviewID, DateChangedEvent) | ||||
| } | ||||
|  |  | |||
|  | @ -113,7 +113,16 @@ func (list *dropDownListData) set(tag string, value any) bool { | |||
| 		return list.setDisabledItems(value) | ||||
| 
 | ||||
| 	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: | ||||
| 		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 { | ||||
| 	return list.get(strings.ToLower(tag)) | ||||
| } | ||||
|  |  | |||
							
								
								
									
										76
									
								
								editView.go
								
								
								
								
							
							
						
						
									
										76
									
								
								editView.go
								
								
								
								
							|  | @ -333,75 +333,29 @@ func (edit *editViewData) set(tag string, value any) bool { | |||
| 		return false | ||||
| 
 | ||||
| 	case EditTextChangedEvent: | ||||
| 		ok := edit.setChangeListeners(value) | ||||
| 		listeners, ok := valueToEventListeners[EditView, string](value) | ||||
| 		if !ok { | ||||
| 			notCompatibleType(tag, value) | ||||
| 			return false | ||||
| 		} else if listeners == nil { | ||||
| 			listeners = []func(EditView, string){} | ||||
| 		} | ||||
| 		edit.textChangeListeners = listeners | ||||
| 		edit.propertyChangedEvent(tag) | ||||
| 		return ok | ||||
| 		return true | ||||
| 	} | ||||
| 
 | ||||
| 	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 { | ||||
| 	return edit.get(edit.normalizeTag(tag)) | ||||
| } | ||||
| 
 | ||||
| func (edit *editViewData) get(tag string) any { | ||||
| 	if tag == EditTextChangedEvent { | ||||
| 		return edit.textChangeListeners | ||||
| 	} | ||||
| 	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 the second argument (subviewID) is "" then a value from the first argument (view) is returned.
 | ||||
| func GetTextChangedListeners(view View, subviewID string) []func(EditView, string) { | ||||
| 	if subviewID != "" { | ||||
| 		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){} | ||||
| 	return getEventListeners[EditView, string](view, subviewID, EditTextChangedEvent) | ||||
| } | ||||
| 
 | ||||
| // GetEditViewType returns a value of the Type property of EditView.
 | ||||
|  |  | |||
|  | @ -151,57 +151,14 @@ func (picker *filePickerData) set(tag string, value any) bool { | |||
| 
 | ||||
| 	switch tag { | ||||
| 	case FileSelectedEvent: | ||||
| 		switch value := value.(type) { | ||||
| 		case func(FilePicker, []FileInfo): | ||||
| 			picker.fileSelectedListeners = []func(FilePicker, []FileInfo){value} | ||||
| 
 | ||||
| 		case func([]FileInfo): | ||||
| 			fn := func(_ FilePicker, files []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 | ||||
| 		listeners, ok := valueToEventListeners[FilePicker, []FileInfo](value) | ||||
| 		if !ok { | ||||
| 			notCompatibleType(tag, value) | ||||
| 			return false | ||||
| 		} else if listeners == nil { | ||||
| 			listeners = []func(FilePicker, []FileInfo){} | ||||
| 		} | ||||
| 		picker.fileSelectedListeners = listeners | ||||
| 		picker.propertyChangedEvent(tag) | ||||
| 		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 the second argument (subviewID) is "" then a value from the first argument (view) is returned.
 | ||||
| func GetFileSelectedListeners(view View, subviewID string) []func(FilePicker, []FileInfo) { | ||||
| 	if subviewID != "" { | ||||
| 		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){} | ||||
| 	return getEventListeners[FilePicker, []FileInfo](view, subviewID, FileSelectedEvent) | ||||
| } | ||||
|  |  | |||
|  | @ -20,22 +20,22 @@ const ( | |||
| 	LostFocusEvent = "lost-focus-event" | ||||
| ) | ||||
| 
 | ||||
| func valueToFocusListeners(value any) ([]func(View), bool) { | ||||
| func valueToNoParamListeners[V View](value any) ([]func(V), bool) { | ||||
| 	if value == nil { | ||||
| 		return nil, true | ||||
| 	} | ||||
| 
 | ||||
| 	switch value := value.(type) { | ||||
| 	case func(View): | ||||
| 		return []func(View){value}, true | ||||
| 	case func(V): | ||||
| 		return []func(V){value}, true | ||||
| 
 | ||||
| 	case func(): | ||||
| 		fn := func(View) { | ||||
| 		fn := func(V) { | ||||
| 			value() | ||||
| 		} | ||||
| 		return []func(View){fn}, true | ||||
| 		return []func(V){fn}, true | ||||
| 
 | ||||
| 	case []func(View): | ||||
| 	case []func(V): | ||||
| 		if len(value) == 0 { | ||||
| 			return nil, true | ||||
| 		} | ||||
|  | @ -51,12 +51,12 @@ func valueToFocusListeners(value any) ([]func(View), bool) { | |||
| 		if count == 0 { | ||||
| 			return nil, true | ||||
| 		} | ||||
| 		listeners := make([]func(View), count) | ||||
| 		listeners := make([]func(V), count) | ||||
| 		for i, v := range value { | ||||
| 			if v == nil { | ||||
| 				return nil, false | ||||
| 			} | ||||
| 			listeners[i] = func(View) { | ||||
| 			listeners[i] = func(V) { | ||||
| 				v() | ||||
| 			} | ||||
| 		} | ||||
|  | @ -67,17 +67,17 @@ func valueToFocusListeners(value any) ([]func(View), bool) { | |||
| 		if count == 0 { | ||||
| 			return nil, true | ||||
| 		} | ||||
| 		listeners := make([]func(View), count) | ||||
| 		listeners := make([]func(V), count) | ||||
| 		for i, v := range value { | ||||
| 			if v == nil { | ||||
| 				return nil, false | ||||
| 			} | ||||
| 			switch v := v.(type) { | ||||
| 			case func(View): | ||||
| 			case func(V): | ||||
| 				listeners[i] = v | ||||
| 
 | ||||
| 			case func(): | ||||
| 				listeners[i] = func(View) { | ||||
| 				listeners[i] = func(V) { | ||||
| 					v() | ||||
| 				} | ||||
| 
 | ||||
|  | @ -97,7 +97,7 @@ var focusEvents = map[string]struct{ jsEvent, jsFunc string }{ | |||
| } | ||||
| 
 | ||||
| func (view *viewData) setFocusListener(tag string, value any) bool { | ||||
| 	listeners, ok := valueToFocusListeners(value) | ||||
| 	listeners, ok := valueToNoParamListeners[View](value) | ||||
| 	if !ok { | ||||
| 		notCompatibleType(tag, value) | ||||
| 		return false | ||||
|  |  | |||
							
								
								
									
										79
									
								
								imageView.go
								
								
								
								
							
							
						
						
									
										79
									
								
								imageView.go
								
								
								
								
							|  | @ -118,77 +118,6 @@ func (imageView *imageViewData) Set(tag string, value any) bool { | |||
| 	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 { | ||||
| 	if value == nil { | ||||
| 		imageView.remove(tag) | ||||
|  | @ -228,8 +157,12 @@ func (imageView *imageViewData) set(tag string, value any) bool { | |||
| 		notCompatibleType(tag, value) | ||||
| 
 | ||||
| 	case LoadedEvent, ErrorEvent: | ||||
| 		if listeners, ok := valueToImageListeners(value); ok { | ||||
| 			imageView.properties[tag] = listeners | ||||
| 		if listeners, ok := valueToNoParamListeners[ImageView](value); ok { | ||||
| 			if listeners == nil { | ||||
| 				delete(imageView.properties, tag) | ||||
| 			} else { | ||||
| 				imageView.properties[tag] = listeners | ||||
| 			} | ||||
| 			return true | ||||
| 		} | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										117
									
								
								keyEvents.go
								
								
								
								
							
							
						
						
									
										117
									
								
								keyEvents.go
								
								
								
								
							|  | @ -50,34 +50,52 @@ type KeyEvent struct { | |||
| 	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 { | ||||
| 		return nil, true | ||||
| 	} | ||||
| 
 | ||||
| 	switch value := value.(type) { | ||||
| 	case func(View, KeyEvent): | ||||
| 		return []func(View, KeyEvent){value}, true | ||||
| 	case func(V, E): | ||||
| 		return []func(V, E){value}, true | ||||
| 
 | ||||
| 	case func(KeyEvent): | ||||
| 		fn := func(_ View, event KeyEvent) { | ||||
| 	case func(E): | ||||
| 		fn := func(_ V, event E) { | ||||
| 			value(event) | ||||
| 		} | ||||
| 		return []func(View, KeyEvent){fn}, true | ||||
| 		return []func(V, E){fn}, true | ||||
| 
 | ||||
| 	case func(View): | ||||
| 		fn := func(view View, _ KeyEvent) { | ||||
| 	case func(V): | ||||
| 		fn := func(view V, _ E) { | ||||
| 			value(view) | ||||
| 		} | ||||
| 		return []func(View, KeyEvent){fn}, true | ||||
| 		return []func(V, E){fn}, true | ||||
| 
 | ||||
| 	case func(): | ||||
| 		fn := func(View, KeyEvent) { | ||||
| 		fn := func(V, E) { | ||||
| 			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 { | ||||
| 			return nil, true | ||||
| 		} | ||||
|  | @ -88,33 +106,33 @@ func valueToKeyListeners(value any) ([]func(View, KeyEvent), bool) { | |||
| 		} | ||||
| 		return value, true | ||||
| 
 | ||||
| 	case []func(KeyEvent): | ||||
| 	case []func(E): | ||||
| 		count := len(value) | ||||
| 		if count == 0 { | ||||
| 			return nil, true | ||||
| 		} | ||||
| 		listeners := make([]func(View, KeyEvent), count) | ||||
| 		listeners := make([]func(V, E), count) | ||||
| 		for i, v := range value { | ||||
| 			if v == nil { | ||||
| 				return nil, false | ||||
| 			} | ||||
| 			listeners[i] = func(_ View, event KeyEvent) { | ||||
| 			listeners[i] = func(_ V, event E) { | ||||
| 				v(event) | ||||
| 			} | ||||
| 		} | ||||
| 		return listeners, true | ||||
| 
 | ||||
| 	case []func(View): | ||||
| 	case []func(V): | ||||
| 		count := len(value) | ||||
| 		if count == 0 { | ||||
| 			return nil, true | ||||
| 		} | ||||
| 		listeners := make([]func(View, KeyEvent), count) | ||||
| 		listeners := make([]func(V, E), count) | ||||
| 		for i, v := range value { | ||||
| 			if v == nil { | ||||
| 				return nil, false | ||||
| 			} | ||||
| 			listeners[i] = func(view View, _ KeyEvent) { | ||||
| 			listeners[i] = func(view V, _ E) { | ||||
| 				v(view) | ||||
| 			} | ||||
| 		} | ||||
|  | @ -125,12 +143,12 @@ func valueToKeyListeners(value any) ([]func(View, KeyEvent), bool) { | |||
| 		if count == 0 { | ||||
| 			return nil, true | ||||
| 		} | ||||
| 		listeners := make([]func(View, KeyEvent), count) | ||||
| 		listeners := make([]func(V, E), count) | ||||
| 		for i, v := range value { | ||||
| 			if v == nil { | ||||
| 				return nil, false | ||||
| 			} | ||||
| 			listeners[i] = func(View, KeyEvent) { | ||||
| 			listeners[i] = func(V, E) { | ||||
| 				v() | ||||
| 			} | ||||
| 		} | ||||
|  | @ -141,27 +159,27 @@ func valueToKeyListeners(value any) ([]func(View, KeyEvent), bool) { | |||
| 		if count == 0 { | ||||
| 			return nil, true | ||||
| 		} | ||||
| 		listeners := make([]func(View, KeyEvent), count) | ||||
| 		listeners := make([]func(V, E), count) | ||||
| 		for i, v := range value { | ||||
| 			if v == nil { | ||||
| 				return nil, false | ||||
| 			} | ||||
| 			switch v := v.(type) { | ||||
| 			case func(View, KeyEvent): | ||||
| 			case func(V, E): | ||||
| 				listeners[i] = v | ||||
| 
 | ||||
| 			case func(KeyEvent): | ||||
| 				listeners[i] = func(_ View, event KeyEvent) { | ||||
| 			case func(E): | ||||
| 				listeners[i] = func(_ V, event E) { | ||||
| 					v(event) | ||||
| 				} | ||||
| 
 | ||||
| 			case func(View): | ||||
| 				listeners[i] = func(view View, _ KeyEvent) { | ||||
| 			case func(V): | ||||
| 				listeners[i] = func(view V, _ E) { | ||||
| 					v(view) | ||||
| 				} | ||||
| 
 | ||||
| 			case func(): | ||||
| 				listeners[i] = func(View, KeyEvent) { | ||||
| 				listeners[i] = func(V, E) { | ||||
| 					v() | ||||
| 				} | ||||
| 
 | ||||
|  | @ -181,7 +199,7 @@ var keyEvents = map[string]struct{ jsEvent, jsFunc string }{ | |||
| } | ||||
| 
 | ||||
| func (view *viewData) setKeyListener(tag string, value any) bool { | ||||
| 	listeners, ok := valueToKeyListeners(value) | ||||
| 	listeners, ok := valueToEventListeners[View, KeyEvent](value) | ||||
| 	if !ok { | ||||
| 		notCompatibleType(tag, value) | ||||
| 		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 != "" { | ||||
| 		view = ViewByID(view, subviewID) | ||||
| 	} | ||||
| 	if view != 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 []func(View, KeyEvent){} | ||||
| 	return []func(V, E){} | ||||
| } | ||||
| 
 | ||||
| func keyEventsHtml(view View, buffer *strings.Builder) { | ||||
| 	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)" `) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func handleKeyEvents(view View, tag string, data DataObject) { | ||||
| 	listeners := getKeyListeners(view, "", tag) | ||||
| 	if len(listeners) == 0 { | ||||
| 		return | ||||
| 	} | ||||
| 	listeners := getEventListeners[View, KeyEvent](view, "", tag) | ||||
| 	if len(listeners) > 0 { | ||||
| 		var event KeyEvent | ||||
| 		event.init(data) | ||||
| 
 | ||||
| 	getBool := func(tag string) bool { | ||||
| 		if value, ok := data.PropertyValue(tag); ok && value == "1" { | ||||
| 			return true | ||||
| 		for _, listener := range listeners { | ||||
| 			listener(view, event) | ||||
| 		} | ||||
| 		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.
 | ||||
| // 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) { | ||||
| 	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.
 | ||||
| // 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) { | ||||
| 	return getKeyListeners(view, subviewID, KeyUpEvent) | ||||
| 	return getEventListeners[View, KeyEvent](view, subviewID, KeyUpEvent) | ||||
| } | ||||
|  |  | |||
							
								
								
									
										129
									
								
								listView.go
								
								
								
								
							
							
						
						
									
										129
									
								
								listView.go
								
								
								
								
							|  | @ -205,29 +205,38 @@ func (listView *listViewData) set(tag string, value any) bool { | |||
| 
 | ||||
| 	switch tag { | ||||
| 	case ListItemClickedEvent: | ||||
| 		listeners := listView.valueToItemListeners(value) | ||||
| 		if listeners == nil { | ||||
| 		listeners, ok := valueToEventListeners[ListView, int](value) | ||||
| 		if !ok { | ||||
| 			notCompatibleType(tag, value) | ||||
| 			return false | ||||
| 		} else if listeners == nil { | ||||
| 			listeners = []func(ListView, int){} | ||||
| 		} | ||||
| 		listView.clickedListeners = listeners | ||||
| 		listView.propertyChangedEvent(tag) | ||||
| 		return true | ||||
| 
 | ||||
| 	case ListItemSelectedEvent: | ||||
| 		listeners := listView.valueToItemListeners(value) | ||||
| 		if listeners == nil { | ||||
| 		listeners, ok := valueToEventListeners[ListView, int](value) | ||||
| 		if !ok { | ||||
| 			notCompatibleType(tag, value) | ||||
| 			return false | ||||
| 		} else if listeners == nil { | ||||
| 			listeners = []func(ListView, int){} | ||||
| 		} | ||||
| 		listView.selectedListeners = listeners | ||||
| 		listView.propertyChangedEvent(tag) | ||||
| 		return true | ||||
| 
 | ||||
| 	case ListItemCheckedEvent: | ||||
| 		if !listView.setItemCheckedEvent(value) { | ||||
| 		listeners, ok := valueToEventListeners[ListView, []int](value) | ||||
| 		if !ok { | ||||
| 			notCompatibleType(tag, value) | ||||
| 			return false | ||||
| 		} else if listeners == nil { | ||||
| 			listeners = []func(ListView, []int){} | ||||
| 		} | ||||
| 		listView.checkedListeners = listeners | ||||
| 		listView.propertyChangedEvent(tag) | ||||
| 		return true | ||||
| 
 | ||||
|  | @ -288,61 +297,6 @@ func (listView *listViewData) set(tag string, value any) bool { | |||
| 	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 { | ||||
| 	return listView.get(listView.normalizeTag(tag)) | ||||
| } | ||||
|  | @ -460,61 +414,6 @@ func (listView *listViewData) setItems(value any) bool { | |||
| 	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 { | ||||
| 	var checked []int | ||||
| 	if value == nil { | ||||
|  |  | |||
							
								
								
									
										200
									
								
								mediaPlayer.go
								
								
								
								
							
							
						
						
									
										200
									
								
								mediaPlayer.go
								
								
								
								
							|  | @ -205,7 +205,7 @@ func (player *mediaPlayerData) set(tag string, value any) bool { | |||
| 	case AbortEvent, CanPlayEvent, CanPlayThroughEvent, CompleteEvent, EmptiedEvent, LoadStartEvent, | ||||
| 		EndedEvent, LoadedDataEvent, LoadedMetadataEvent, PauseEvent, PlayEvent, PlayingEvent, | ||||
| 		ProgressEvent, SeekedEvent, SeekingEvent, StalledEvent, SuspendEvent, WaitingEvent: | ||||
| 		if listeners, ok := valueToPlayerListeners(value); ok { | ||||
| 		if listeners, ok := valueToNoParamListeners[MediaPlayer](value); ok { | ||||
| 			if listeners == nil { | ||||
| 				delete(player.properties, tag) | ||||
| 			} else { | ||||
|  | @ -218,7 +218,7 @@ func (player *mediaPlayerData) set(tag string, value any) bool { | |||
| 		notCompatibleType(tag, value) | ||||
| 
 | ||||
| 	case DurationChangedEvent, RateChangedEvent, TimeUpdateEvent, VolumeChangedEvent: | ||||
| 		if listeners, ok := valueToPlayerTimeListeners(value); ok { | ||||
| 		if listeners, ok := valueToEventListeners[MediaPlayer, float64](value); ok { | ||||
| 			if listeners == nil { | ||||
| 				delete(player.properties, tag) | ||||
| 			} else { | ||||
|  | @ -311,202 +311,6 @@ func (player *mediaPlayerData) setSource(value any) bool { | |||
| 	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) { | ||||
| 	if value == nil { | ||||
| 		return nil, true | ||||
|  |  | |||
							
								
								
									
										173
									
								
								mouseEvents.go
								
								
								
								
							
							
						
						
									
										173
									
								
								mouseEvents.go
								
								
								
								
							|  | @ -144,131 +144,6 @@ type MouseEvent struct { | |||
| 	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 }{ | ||||
| 	ClickEvent:       {jsEvent: "onclick", jsFunc: "clickEvent"}, | ||||
| 	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 { | ||||
| 	listeners, ok := valueToMouseListeners(value) | ||||
| 	listeners, ok := valueToEventListeners[View, MouseEvent](value) | ||||
| 	if !ok { | ||||
| 		notCompatibleType(tag, value) | ||||
| 		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) { | ||||
| 	for tag, js := range mouseEvents { | ||||
| 		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) { | ||||
| 	listeners := getMouseListeners(view, "", tag) | ||||
| 	if len(listeners) == 0 { | ||||
| 		return | ||||
| 	} | ||||
| 	listeners := getEventListeners[View, MouseEvent](view, "", tag) | ||||
| 	if len(listeners) > 0 { | ||||
| 		var event MouseEvent | ||||
| 		event.init(data) | ||||
| 
 | ||||
| 	var event MouseEvent | ||||
| 	event.init(data) | ||||
| 
 | ||||
| 	for _, listener := range listeners { | ||||
| 		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.
 | ||||
| // 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) { | ||||
| 	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.
 | ||||
| // 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) { | ||||
| 	return getMouseListeners(view, subviewID, DoubleClickEvent) | ||||
| 	return getEventListeners[View, MouseEvent](view, subviewID, DoubleClickEvent) | ||||
| } | ||||
| 
 | ||||
| // GetContextMenuListeners returns the "context-menu" 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.
 | ||||
| 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.
 | ||||
| // 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) { | ||||
| 	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.
 | ||||
| // 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) { | ||||
| 	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.
 | ||||
| // 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) { | ||||
| 	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.
 | ||||
| // 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) { | ||||
| 	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.
 | ||||
| // 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) { | ||||
| 	return getMouseListeners(view, subviewID, MouseOut) | ||||
| 	return getEventListeners[View, MouseEvent](view, subviewID, MouseOut) | ||||
| } | ||||
|  |  | |||
|  | @ -99,52 +99,14 @@ func (picker *numberPickerData) set(tag string, value any) bool { | |||
| 
 | ||||
| 	switch tag { | ||||
| 	case NumberChangedEvent: | ||||
| 		switch value := value.(type) { | ||||
| 		case func(NumberPicker, float64): | ||||
| 			picker.numberChangedListeners = []func(NumberPicker, float64){value} | ||||
| 
 | ||||
| 		case func(float64): | ||||
| 			fn := func(_ NumberPicker, newValue 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 | ||||
| 		listeners, ok := valueToEventListeners[NumberPicker, float64](value) | ||||
| 		if !ok { | ||||
| 			notCompatibleType(tag, value) | ||||
| 			return false | ||||
| 		} else if listeners == nil { | ||||
| 			listeners = []func(NumberPicker, float64){} | ||||
| 		} | ||||
| 		picker.numberChangedListeners = listeners | ||||
| 		picker.propertyChangedEvent(tag) | ||||
| 		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 the second argument (subviewID) is "" then a value from the first argument (view) is returned.
 | ||||
| func GetNumberChangedListeners(view View, subviewID string) []func(NumberPicker, float64) { | ||||
| 	if subviewID != "" { | ||||
| 		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){} | ||||
| 	return getEventListeners[NumberPicker, float64](view, subviewID, NumberChangedEvent) | ||||
| } | ||||
|  |  | |||
							
								
								
									
										155
									
								
								pointerEvents.go
								
								
								
								
							
							
						
						
									
										155
									
								
								pointerEvents.go
								
								
								
								
							|  | @ -87,131 +87,6 @@ type PointerEvent struct { | |||
| 	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 }{ | ||||
| 	PointerDown:   {jsEvent: "onpointerdown", jsFunc: "pointerDownEvent"}, | ||||
| 	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 { | ||||
| 	listeners, ok := valueToPointerListeners(value) | ||||
| 	listeners, ok := valueToEventListeners[View, PointerEvent](value) | ||||
| 	if !ok { | ||||
| 		notCompatibleType(tag, value) | ||||
| 		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) { | ||||
| 	for tag, js := range pointerEvents { | ||||
| 		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) { | ||||
| 	listeners := getPointerListeners(view, "", tag) | ||||
| 	listeners := getEventListeners[View, PointerEvent](view, "", tag) | ||||
| 	if len(listeners) == 0 { | ||||
| 		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.
 | ||||
| // 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) { | ||||
| 	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.
 | ||||
| // 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) { | ||||
| 	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.
 | ||||
| // 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) { | ||||
| 	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.
 | ||||
| // 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) { | ||||
| 	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.
 | ||||
| // 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) { | ||||
| 	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.
 | ||||
| // 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) { | ||||
| 	return getPointerListeners(view, subviewID, PointerOut) | ||||
| 	return getEventListeners[View, PointerEvent](view, subviewID, PointerOut) | ||||
| } | ||||
|  |  | |||
							
								
								
									
										11
									
								
								popup.go
								
								
								
								
							
							
						
						
									
										11
									
								
								popup.go
								
								
								
								
							|  | @ -36,6 +36,10 @@ const ( | |||
| 	// It occurs after the Popup disappears from the screen.
 | ||||
| 	// The main listener for this event has the following format: func(Popup)
 | ||||
| 	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.
 | ||||
|  | @ -181,11 +185,10 @@ func (popup *popupData) init(view View, params Params) { | |||
| 	viewRow := 0 | ||||
| 	if title != nil || closeButton { | ||||
| 		viewRow = 1 | ||||
| 		titleHeight, _ := sizeConstant(popup.Session(), "ruiPopupTitleHeight") | ||||
| 		titleView := NewGridLayout(session, Params{ | ||||
| 			Row:               0, | ||||
| 			Style:             titleStyle, | ||||
| 			CellWidth:         []SizeUnit{Fr(1), titleHeight}, | ||||
| 			CellWidth:         []any{Fr(1), "@ruiPopupTitleHeight"}, | ||||
| 			CellVerticalAlign: CenterAlign, | ||||
| 			PaddingLeft:       Px(12), | ||||
| 		}) | ||||
|  | @ -195,8 +198,8 @@ func (popup *popupData) init(view View, params Params) { | |||
| 		if closeButton { | ||||
| 			titleView.Append(NewGridLayout(session, Params{ | ||||
| 				Column:              1, | ||||
| 				Height:              titleHeight, | ||||
| 				Width:               titleHeight, | ||||
| 				Height:              "@ruiPopupTitleHeight", | ||||
| 				Width:               "@ruiPopupTitleHeight", | ||||
| 				CellHorizontalAlign: CenterAlign, | ||||
| 				CellVerticalAlign:   CenterAlign, | ||||
| 				TextSize:            Px(20), | ||||
|  |  | |||
							
								
								
									
										156
									
								
								resizeEvent.go
								
								
								
								
							
							
						
						
									
										156
									
								
								resizeEvent.go
								
								
								
								
							|  | @ -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 { | ||||
| 	if value == nil { | ||||
| 		delete(view.properties, tag) | ||||
| 		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: | ||||
| 	listeners, ok := valueToEventListeners[FilePicker, []FileInfo](value) | ||||
| 	if !ok { | ||||
| 		notCompatibleType(tag, value) | ||||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
| 	if listeners == nil { | ||||
| 		delete(view.properties, tag) | ||||
| 	} else { | ||||
| 		view.properties[tag] = listeners | ||||
| 	} | ||||
| 	view.propertyChangedEvent(tag) | ||||
| 	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
 | ||||
| // 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) { | ||||
| 	if subviewID != "" { | ||||
| 		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){} | ||||
| 	return getEventListeners[View, Frame](view, subviewID, ResizeEvent) | ||||
| } | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ package rui | |||
| import "fmt" | ||||
| 
 | ||||
| // 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:
 | ||||
| //   func(View, Frame).
 | ||||
| // 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
 | ||||
| // 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) { | ||||
| 	if subviewID != "" { | ||||
| 		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){} | ||||
| 	return getEventListeners[View, Frame](view, subviewID, ResizeEvent) | ||||
| } | ||||
| 
 | ||||
| // ScrollTo scrolls the view's content to the given position.
 | ||||
|  |  | |||
|  | @ -431,7 +431,7 @@ func (session *sessionData) handleViewEvent(command string, data DataObject) { | |||
| 		if view := session.viewByHTMLID(viewID); view != nil { | ||||
| 			view.handleCommand(view, command, data) | ||||
| 		} | ||||
| 	} else { | ||||
| 	} else if command != "clickOutsidePopup" { | ||||
| 		ErrorLog(`"id" property not found. Event: ` + command) | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -109,8 +109,8 @@ func (layout *stackLayoutData) set(tag string, value any) bool { | |||
| 
 | ||||
| 	switch tag { | ||||
| 	case TransitionEndEvent: | ||||
| 		listeners, ok := valueToAnimationListeners(value) | ||||
| 		if ok { | ||||
| 		listeners, ok := valueToEventListeners[View, string](value) | ||||
| 		if ok && listeners != nil { | ||||
| 			listeners = append(listeners, layout.pushFinished) | ||||
| 			listeners = append(listeners, layout.popFinished) | ||||
| 			layout.properties[TransitionEndEvent] = listeners | ||||
|  |  | |||
							
								
								
									
										69
									
								
								tableView.go
								
								
								
								
							
							
						
						
									
										69
									
								
								tableView.go
								
								
								
								
							|  | @ -384,20 +384,24 @@ func (table *tableViewData) set(tag string, value any) bool { | |||
| 		table.cellSelectedListener = listeners | ||||
| 
 | ||||
| 	case TableRowClickedEvent: | ||||
| 		listeners := table.valueToRowListeners(value) | ||||
| 		if listeners == nil { | ||||
| 		listeners, ok := valueToEventListeners[TableView, int](value) | ||||
| 		if !ok { | ||||
| 			notCompatibleType(tag, value) | ||||
| 			return false | ||||
| 		} else if listeners == nil { | ||||
| 			listeners = []func(TableView, int){} | ||||
| 		} | ||||
| 		table.rowClickedListener = listeners | ||||
| 
 | ||||
| 	case TableRowSelectedEvent: | ||||
| 		listeners := table.valueToRowListeners(value) | ||||
| 		if listeners == nil { | ||||
| 		listeners, ok := valueToEventListeners[TableView, int](value) | ||||
| 		if !ok { | ||||
| 			notCompatibleType(tag, value) | ||||
| 			return false | ||||
| 		} else if listeners == nil { | ||||
| 			listeners = []func(TableView, int){} | ||||
| 		} | ||||
| 		table.rowSelectedListener = []func(TableView, int){} | ||||
| 		table.rowSelectedListener = listeners | ||||
| 
 | ||||
| 	case CellStyle: | ||||
| 		if style, ok := value.(TableCellStyle); ok { | ||||
|  | @ -731,61 +735,6 @@ func (table *tableViewData) valueToCellListeners(value any) []func(TableView, in | |||
| 	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 { | ||||
| 	return "table" | ||||
| } | ||||
|  |  | |||
|  | @ -210,10 +210,12 @@ func (tabsLayout *tabsLayoutData) set(tag string, value any) bool { | |||
| 		tabsLayout.tabListener = listeners | ||||
| 
 | ||||
| 	case TabCloseEvent: | ||||
| 		listeners := tabsLayout.valueToCloseListeners(value) | ||||
| 		if listeners == nil { | ||||
| 		listeners, ok := valueToEventListeners[TabsLayout, int](value) | ||||
| 		if !ok { | ||||
| 			notCompatibleType(tag, value) | ||||
| 			return false | ||||
| 		} else if listeners == nil { | ||||
| 			listeners = []func(TabsLayout, int){} | ||||
| 		} | ||||
| 		tabsLayout.tabCloseListener = listeners | ||||
| 
 | ||||
|  | @ -433,61 +435,6 @@ func (tabsLayout *tabsLayoutData) valueToTabListeners(value any) []func(TabsLayo | |||
| 	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 { | ||||
| 	tabs, _ := enumProperty(tabsLayout, Tabs, tabsLayout.session, 0) | ||||
| 	return tabs | ||||
|  |  | |||
|  | @ -223,57 +223,14 @@ func (picker *timePickerData) set(tag string, value any) bool { | |||
| 		} | ||||
| 
 | ||||
| 	case TimeChangedEvent: | ||||
| 		switch value := value.(type) { | ||||
| 		case func(TimePicker, time.Time): | ||||
| 			picker.timeChangedListeners = []func(TimePicker, time.Time){value} | ||||
| 
 | ||||
| 		case func(time.Time): | ||||
| 			fn := func(_ TimePicker, time 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 | ||||
| 		listeners, ok := valueToEventListeners[TimePicker, time.Time](value) | ||||
| 		if !ok { | ||||
| 			notCompatibleType(tag, value) | ||||
| 			return false | ||||
| 		} else if listeners == nil { | ||||
| 			listeners = []func(TimePicker, time.Time){} | ||||
| 		} | ||||
| 		picker.timeChangedListeners = listeners | ||||
| 		picker.propertyChangedEvent(tag) | ||||
| 		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 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) { | ||||
| 	if subviewID != "" { | ||||
| 		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){} | ||||
| 	return getEventListeners[TimePicker, time.Time](view, subviewID, TimeChangedEvent) | ||||
| } | ||||
|  |  | |||
							
								
								
									
										151
									
								
								touchEvents.go
								
								
								
								
							
							
						
						
									
										151
									
								
								touchEvents.go
								
								
								
								
							|  | @ -90,131 +90,6 @@ type TouchEvent struct { | |||
| 	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 }{ | ||||
| 	TouchStart:  {jsEvent: "ontouchstart", jsFunc: "touchStartEvent"}, | ||||
| 	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 { | ||||
| 	listeners, ok := valueToTouchListeners(value) | ||||
| 	listeners, ok := valueToEventListeners[View, TouchEvent](value) | ||||
| 	if !ok { | ||||
| 		notCompatibleType(tag, value) | ||||
| 		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) { | ||||
| 	for tag, js := range touchEvents { | ||||
| 		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) { | ||||
| 	listeners := getTouchListeners(view, "", tag) | ||||
| 	listeners := getEventListeners[View, TouchEvent](view, "", tag) | ||||
| 	if len(listeners) == 0 { | ||||
| 		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.
 | ||||
| // 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) { | ||||
| 	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.
 | ||||
| // 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) { | ||||
| 	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.
 | ||||
| // 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) { | ||||
| 	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.
 | ||||
| // 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) { | ||||
| 	return getTouchListeners(view, subviewID, TouchCancel) | ||||
| 	return getEventListeners[View, TouchEvent](view, subviewID, TouchCancel) | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue