rui_orig/dropDownList.go

339 lines
8.5 KiB
Go
Raw Normal View History

2021-09-07 17:36:50 +03:00
package rui
import (
"strconv"
"strings"
)
2022-08-31 22:22:19 +03:00
// DropDownEvent is the constant for "drop-down-event" property tag.
//
// Used by `DropDownList`.
// Occur when a list item becomes selected.
//
// General listener format:
// `func(list rui.DropDownList, index int)`.
//
// where:
// list - Interface of a drop down list which generated this event,
// index - Index of a newly selected item.
//
// Allowed listener formats:
2024-11-13 12:56:39 +03:00
const DropDownEvent PropertyName = "drop-down-event"
2021-09-07 17:36:50 +03:00
// DropDownList represent a DropDownList view
2021-09-07 17:36:50 +03:00
type DropDownList interface {
View
}
type dropDownListData struct {
viewData
}
// NewDropDownList create new DropDownList object and return it
func NewDropDownList(session Session, params Params) DropDownList {
view := new(dropDownListData)
view.init(session)
2021-09-07 17:36:50 +03:00
setInitParams(view, params)
return view
}
func newDropDownList(session Session) View {
2024-11-13 12:56:39 +03:00
return new(dropDownListData)
2021-09-07 17:36:50 +03:00
}
func (list *dropDownListData) init(session Session) {
list.viewData.init(session)
2021-09-07 17:36:50 +03:00
list.tag = "DropDownList"
2024-04-23 18:24:51 +03:00
list.hasHtmlDisabled = true
2024-11-13 12:56:39 +03:00
list.normalize = normalizeDropDownListTag
list.set = dropDownListSet
list.changed = dropDownListPropertyChanged
2022-05-22 12:54:02 +03:00
}
func (list *dropDownListData) Focusable() bool {
return true
}
2024-11-13 12:56:39 +03:00
func normalizeDropDownListTag(tag PropertyName) PropertyName {
tag = defaultNormalize(tag)
if tag == "separators" {
return ItemSeparators
}
return tag
2021-09-07 17:36:50 +03:00
}
2024-11-13 12:56:39 +03:00
func dropDownListSet(view View, tag PropertyName, value any) []PropertyName {
2021-09-07 17:36:50 +03:00
switch tag {
case Items:
2024-11-13 12:56:39 +03:00
if items, ok := anyToStringArray(value, ""); ok {
return setArrayPropertyValue(view, tag, items)
}
2024-11-13 12:56:39 +03:00
notCompatibleType(Items, value)
return nil
2024-11-13 12:56:39 +03:00
case DisabledItems, ItemSeparators:
if items, ok := parseIndicesArray(value); ok {
return setArrayPropertyValue(view, tag, items)
}
2024-11-13 12:56:39 +03:00
notCompatibleType(tag, value)
return nil
2021-09-07 17:36:50 +03:00
case DropDownEvent:
2024-11-13 12:56:39 +03:00
return setEventWithOldListener[DropDownList, int](view, tag, value)
case Current:
2024-11-13 12:56:39 +03:00
if view, ok := view.(View); ok {
view.setRaw("old-current", GetCurrent(view))
2021-09-07 17:36:50 +03:00
}
2024-11-13 12:56:39 +03:00
return setIntProperty(view, Current, value)
2021-09-07 17:36:50 +03:00
}
2024-11-13 12:56:39 +03:00
return viewSet(view, tag, value)
2021-09-07 17:36:50 +03:00
}
2024-11-13 12:56:39 +03:00
func dropDownListPropertyChanged(view View, tag PropertyName) {
2021-09-07 17:36:50 +03:00
switch tag {
2024-11-13 12:56:39 +03:00
case Items, DisabledItems, ItemSeparators:
updateInnerHTML(view.htmlID(), view.Session())
2021-09-07 17:36:50 +03:00
case Current:
2024-11-13 12:56:39 +03:00
current := GetCurrent(view)
view.Session().callFunc("selectDropDownListItem", view.htmlID(), current)
2021-09-07 17:36:50 +03:00
2024-11-13 12:56:39 +03:00
if list, ok := view.(DropDownList); ok {
oldCurrent := -1
if value := view.getRaw("old-current"); value != nil {
if n, ok := value.(int); ok {
oldCurrent = n
}
2021-09-07 17:36:50 +03:00
}
2024-11-13 12:56:39 +03:00
for _, listener := range GetDropDownListeners(view) {
listener(list, current, oldCurrent)
}
}
2024-05-18 18:57:41 +03:00
2024-11-13 12:56:39 +03:00
default:
viewPropertyChanged(view, tag)
2024-05-18 18:57:41 +03:00
}
}
func intArrayToStringArray[T int | uint | int8 | uint8 | int16 | uint16 | int32 | uint32 | int64 | uint64](array []T) []string {
items := make([]string, len(array))
for i, val := range array {
items[i] = strconv.Itoa(int(val))
}
return items
}
2024-11-13 12:56:39 +03:00
func parseIndicesArray(value any) ([]any, bool) {
2021-09-07 17:36:50 +03:00
switch value := value.(type) {
2024-11-13 12:56:39 +03:00
case int:
return []any{value}, true
2024-05-18 18:57:41 +03:00
case []int:
items := make([]any, len(value))
for i, n := range value {
items[i] = n
}
return items, true
2022-07-26 18:36:00 +03:00
case []any:
2024-11-13 12:56:39 +03:00
items := make([]any, 0, len(value))
for _, val := range value {
if val != nil {
switch val := val.(type) {
case string:
if isConstantName(val) {
items = append(items, val)
} else if n, err := strconv.Atoi(val); err == nil {
items = append(items, n)
} else {
return nil, false
}
2024-11-13 12:56:39 +03:00
default:
if n, ok := isInt(val); ok {
items = append(items, n)
} else {
return nil, false
}
}
}
}
return items, true
2024-11-13 12:56:39 +03:00
case []string:
items := make([]any, 0, len(value))
for _, str := range value {
if str = strings.Trim(str, " \t"); str != "" {
if isConstantName(str) {
items = append(items, str)
} else if n, err := strconv.Atoi(str); err == nil {
items = append(items, n)
} else {
return nil, false
}
}
}
return items, true
2024-11-13 12:56:39 +03:00
case string:
return parseIndicesArray(strings.Split(value, ","))
case []DataValue:
2024-11-13 12:56:39 +03:00
items := make([]string, 0, len(value))
for _, val := range value {
if !val.IsObject() {
items = append(items, val.Value())
}
}
2024-11-13 12:56:39 +03:00
return parseIndicesArray(items)
}
return nil, false
}
2021-09-07 17:36:50 +03:00
func (list *dropDownListData) htmlTag() string {
return "select"
}
func (list *dropDownListData) htmlSubviews(self View, buffer *strings.Builder) {
2024-11-13 12:56:39 +03:00
if items := GetDropDownItems(list); len(items) > 0 {
current := GetCurrent(list)
notTranslate := GetNotTranslate(list)
disabledItems := GetDropDownDisabledItems(list)
separators := GetDropDownItemSeparators(list)
2024-11-13 12:56:39 +03:00
for i, item := range items {
disabled := false
for _, index := range disabledItems {
if i == index {
disabled = true
break
}
}
if disabled {
buffer.WriteString("<option disabled>")
} else if i == current {
2021-09-07 17:36:50 +03:00
buffer.WriteString("<option selected>")
} else {
buffer.WriteString("<option>")
}
if !notTranslate {
item, _ = list.session.GetString(item)
}
buffer.WriteString(item)
buffer.WriteString("</option>")
for _, index := range separators {
if i == index {
buffer.WriteString("<hr>")
break
}
}
2021-09-07 17:36:50 +03:00
}
}
}
func (list *dropDownListData) htmlProperties(self View, buffer *strings.Builder) {
list.viewData.htmlProperties(self, buffer)
buffer.WriteString(` size="1" onchange="dropDownListEvent(this, event)"`)
}
2024-11-13 12:56:39 +03:00
func (list *dropDownListData) handleCommand(self View, command PropertyName, data DataObject) bool {
2021-09-07 17:36:50 +03:00
switch command {
case "itemSelected":
if text, ok := data.PropertyValue("number"); ok {
if number, err := strconv.Atoi(text); err == nil {
2024-11-13 12:56:39 +03:00
items := GetDropDownItems(list)
if GetCurrent(list) != number && number >= 0 && number < len(items) {
old := GetCurrent(list)
2021-09-07 17:36:50 +03:00
list.properties[Current] = number
2024-11-13 12:56:39 +03:00
for _, listener := range GetDropDownListeners(list) {
listener(list, number, old)
}
2021-09-07 17:36:50 +03:00
}
} else {
ErrorLog(err.Error())
}
}
default:
return list.viewData.handleCommand(self, command, data)
}
return true
}
// GetDropDownListeners returns the "drop-down-event" listener list. If there are no listeners then the empty list is returned.
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
func GetDropDownListeners(view View, subviewID ...string) []func(DropDownList, int, int) {
return getEventWithOldListeners[DropDownList, int](view, subviewID, DropDownEvent)
2021-09-07 17:36:50 +03:00
}
// GetDropDownItems return the DropDownList items list.
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
func GetDropDownItems(view View, subviewID ...string) []string {
if len(subviewID) > 0 && subviewID[0] != "" {
view = ViewByID(view, subviewID[0])
2021-09-07 17:36:50 +03:00
}
if view != nil {
2024-11-13 12:56:39 +03:00
if value := view.Get(Items); value != nil {
if items, ok := value.([]string); ok {
return items
}
2021-09-07 17:36:50 +03:00
}
}
return []string{}
}
2024-11-13 12:56:39 +03:00
func getIndicesArray(view View, tag PropertyName) []int {
if view != nil {
if value := view.Get(tag); value != nil {
2022-07-26 18:36:00 +03:00
if values, ok := value.([]any); ok {
count := len(values)
if count > 0 {
result := make([]int, 0, count)
for _, value := range values {
switch value := value.(type) {
case int:
result = append(result, value)
case string:
if value != "" && value[0] == '@' {
if val, ok := view.Session().Constant(value[1:]); ok {
if n, err := strconv.Atoi(val); err == nil {
result = append(result, n)
}
}
}
}
}
return result
}
}
}
}
return []int{}
}
// GetDropDownDisabledItems return an array of disabled(non selectable) items indices of DropDownList.
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
func GetDropDownDisabledItems(view View, subviewID ...string) []int {
if len(subviewID) > 0 && subviewID[0] != "" {
view = ViewByID(view, subviewID[0])
}
return getIndicesArray(view, DisabledItems)
}
// GetDropDownItemSeparators return an array of indices of DropDownList items after which a separator should be added.
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
func GetDropDownItemSeparators(view View, subviewID ...string) []int {
if len(subviewID) > 0 && subviewID[0] != "" {
view = ViewByID(view, subviewID[0])
}
return getIndicesArray(view, ItemSeparators)
}