mirror of https://github.com/anoshenko/rui.git
				
				
				
			Added "data-list" property
This commit is contained in:
		
							parent
							
								
									fd516af017
								
							
						
					
					
						commit
						b4d1e34f21
					
				|  | @ -1,3 +1,7 @@ | |||
| # v0.13.0 | ||||
| * Added "data-list" property  | ||||
| * Bug fixing | ||||
| 
 | ||||
| # v0.14.0 | ||||
| * Added the ability to work without creating a WebSocket. Added NoSocket property to AppParams. | ||||
| * Added SocketAutoClose property to AppParams. | ||||
|  |  | |||
							
								
								
									
										60
									
								
								README-ru.md
								
								
								
								
							
							
						
						
									
										60
									
								
								README-ru.md
								
								
								
								
							|  | @ -3104,8 +3104,17 @@ string свойство "edit-view-pattern" (константа EditViewPattern) | |||
| текст переносится на новую строку. | ||||
| 
 | ||||
| Для изменения цвета каретки ввода текста используется Color свойство "caret-color" (константа CaretColor). | ||||
| Свойство "caret-color" может быть задано не только для EditView, но и для любого контейнера. В этом случае | ||||
| цвет каретки меняется для всех дочерних EditView помещенных в этот контейнер | ||||
| Свойство "caret-color" может быть задано не только для EditView, но и для любого контейнера.  | ||||
| В этом случае цвет каретки меняется для всех дочерних EditView помещенных в этот контейнер. | ||||
| 
 | ||||
| Свойство "data-list" (константа DataList) позволяет задать массив рекомендованных значений. | ||||
| Если задать свойство "data-list" то у редактора появиться выпадающее меню со списком  | ||||
| данных значений. В качестве значения данного свойство должен использоваться массив строк.  | ||||
| Например | ||||
| 
 | ||||
| 	editor := rui.NewEditView(session, rui.Params{ | ||||
| 		rui.DataList: []string{"Text 1", "Text 2", "Text 3"}, | ||||
| 	}) | ||||
| 
 | ||||
| Для получения значений свойств EditView могут использоваться следующие функции: | ||||
| 
 | ||||
|  | @ -3118,6 +3127,7 @@ string свойство "edit-view-pattern" (константа EditViewPattern) | |||
| 	func IsEditViewWrap(view View, subviewID ...string) bool | ||||
| 	func IsSpellcheck(view View, subviewID ...string) bool | ||||
| 	func GetCaretColor(view View, subviewID ...string) Color | ||||
| 	func GetDataList(view View, subviewID ...string) []string | ||||
| 
 | ||||
| Для отслеживания изменения текста используется событие "edit-text-changed" (константа | ||||
| EditTextChangedEvent). Основной слушатель события имеет следующий формат: | ||||
|  | @ -3190,6 +3200,30 @@ NumberPicker может работать в двух режимах: редак | |||
| 	func GetNumberPickerMinMax(view View, subviewID ...string) (float64, float64) | ||||
| 	func GetNumberPickerStep(view View, subviewID ...string) float64 | ||||
| 
 | ||||
| Свойство "data-list" (константа DataList) позволяет задать массив рекомендованных значений. | ||||
| Если задать свойство "data-list" в случае | ||||
| * если "number-picker-type" задано как NumberEditor, то у редактора появиться выпадающее меню со списком этих значений; | ||||
| * если "number-picker-type" задано как NumberSlider, то у слайдера будут отображены метки соответствующие этим значениям; | ||||
| 
 | ||||
| В качестве значения свойство "data-list" должен использоваться массив строк, целых чисел,  | ||||
| вещественных чисел или их комбинация. Например | ||||
| 
 | ||||
| 	editor1 := rui.NewNumberPicker(session, rui.Params{ | ||||
| 		rui.DataList: []string{"1", "2", "3"}, | ||||
| 	}) | ||||
| 
 | ||||
| 	editor2 := rui.NewNumberPicker(session, rui.Params{ | ||||
| 		rui.DataList: []int{1, 2, 3}, | ||||
| 	}) | ||||
| 
 | ||||
| 	editor3 := rui.NewNumberPicker(session, rui.Params{ | ||||
| 		rui.DataList: []any{"1", 2, 3.0}, | ||||
| 	}) | ||||
| 
 | ||||
| Получить значение свойства "data-list" можно с помощью функции | ||||
| 
 | ||||
| 	func GetDataList(view View, subviewID ...string) []string | ||||
| 
 | ||||
| Для отслеживания изменения вводимого значения используется событие "number-changed" (константа | ||||
| NumberChangedEvent).  Основной слушатель события имеет следующий формат: | ||||
| 
 | ||||
|  | @ -3244,6 +3278,17 @@ NumberChangedEvent).  Основной слушатель события име | |||
| 	func GetDatePickerMax(view View, subviewID ...string) (time.Time, bool) | ||||
| 	func GetDatePickerStep(view View, subviewID ...string) int | ||||
| 
 | ||||
| Свойство "data-list" (константа DataList) позволяет задать массив рекомендованных значений. | ||||
| Если задать свойство "data-list" то у редактора может появиться выпадающее меню со списком  | ||||
| данных значений. Некоторые браузеры могут игнорировать данное свойство, например Safari for macOS. | ||||
| 
 | ||||
| В качестве значения данного свойство должен использоваться массив строк в формате "YYYY-MM-DD".  | ||||
| Например | ||||
| 
 | ||||
| 	editor := rui.NewDatePicker(session, rui.Params{ | ||||
| 		rui.DataList: []string{"1990-09-02", "2010-05-24"}, | ||||
| 	}) | ||||
| 
 | ||||
| Для отслеживания изменения вводимого значения используется событие "date-changed" (константа | ||||
| DateChangedEvent).  Основной слушатель события имеет следующий формат: | ||||
| 
 | ||||
|  | @ -3298,6 +3343,17 @@ DateChangedEvent).  Основной слушатель события имее | |||
| 	func GetTimePickerMax(view View, subviewID ...string) (time.Time, bool) | ||||
| 	func GetTimePickerStep(view View, subviewID ...string) int | ||||
| 
 | ||||
| Свойство "data-list" (константа DataList) позволяет задать массив рекомендованных значений. | ||||
| Если задать свойство "data-list" то у редактора может появиться выпадающее меню со списком  | ||||
| данных значений. Некоторые браузеры могут игнорировать данное свойство, например Safari for macOS. | ||||
| 
 | ||||
| В качестве значения данного свойство должен использоваться массив строк в формате "HH:MM:SS" или "HH:MM".  | ||||
| Например | ||||
| 
 | ||||
| 	editor := rui.NewTimePicker(session, rui.Params{ | ||||
| 		rui.DataList: []string{"10:22", "08:00"}, | ||||
| 	}) | ||||
| 
 | ||||
| Для отслеживания изменения вводимого значения используется событие "time-changed" (константа | ||||
| TimeChangedEvent).  Основной слушатель события имеет следующий формат: | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										52
									
								
								README.md
								
								
								
								
							
							
						
						
									
										52
									
								
								README.md
								
								
								
								
							|  | @ -3079,6 +3079,14 @@ To change the color of the text input caret, use the Color property "caret-color | |||
| The "caret-color" property can be set not only for EditView, but for any container.  | ||||
| In this case, the color of the caret changes for all child EditViews placed in this container. | ||||
| 
 | ||||
| The "data-list" property (DataList constant) allows you to specify an array of recommended values. | ||||
| If you set the "data-list" property, the editor will have a drop-down menu with a list of these values. | ||||
| The value of this property must be an array of strings. For example | ||||
| 
 | ||||
| 	editor := rui.NewEditView(session, rui.Params{ | ||||
| 		rui.DataList: []string{"Text 1", "Text 2", "Text 3"}, | ||||
| 	}) | ||||
| 
 | ||||
| The following functions can be used to get the values of the properties of an EditView: | ||||
| 
 | ||||
| 	func GetText(view View, subviewID ...string) string | ||||
|  | @ -3090,6 +3098,7 @@ The following functions can be used to get the values of the properties of an Ed | |||
| 	func IsEditViewWrap(view View, subviewID ...string) bool | ||||
| 	func IsSpellcheck(view View, subviewID ...string) bool | ||||
| 	func GetCaretColor(view View, subviewID ...string) Color | ||||
| 	func GetDataList(view View, subviewID ...string) []string | ||||
| 
 | ||||
| The "edit-text-changed" event (EditTextChangedEvent constant) is used to track changes to the text.  | ||||
| The main event listener has the following format: | ||||
|  | @ -3161,6 +3170,29 @@ You can read the values of these properties using the functions: | |||
| 	func GetNumberPickerMinMax(view View, subviewID ...string) (float64, float64) | ||||
| 	func GetNumberPickerStep(view View, subviewID ...string) float64 | ||||
| 
 | ||||
| The "data-list" property (DataList constant) allows you to specify an array of recommended values. | ||||
| If you set the "data-list" property in case | ||||
| * if "number-picker-type" is set to NumberEditor, then the editor will have a drop-down menu with a list of these values; | ||||
| * if "number-picker-type" is set to NumberSlider, then the slider will display labels corresponding to these values; | ||||
| 
 | ||||
| The value of the "data-list" property must be an array of strings, integers, real numbers, or a combination of these. For example | ||||
| 
 | ||||
| 	editor1 := rui.NewNumberPicker(session, rui.Params{ | ||||
| 		rui.DataList: []string{"1", "2", "3"}, | ||||
| 	}) | ||||
| 
 | ||||
| 	editor2 := rui.NewNumberPicker(session, rui.Params{ | ||||
| 		rui.DataList: []int{1, 2, 3}, | ||||
| 	}) | ||||
| 
 | ||||
| 	editor3 := rui.NewNumberPicker(session, rui.Params{ | ||||
| 		rui.DataList: []any{"1", 2, 3.0}, | ||||
| 	}) | ||||
| 
 | ||||
| You can get the value of the "data-list" property using the function | ||||
| 
 | ||||
| 	func GetDataList(view View, subviewID ...string) []string | ||||
| 
 | ||||
| The "number-changed" event (NumberChangedEvent constant) is used to track the change in the entered value.  | ||||
| The main event listener has the following format: | ||||
| 
 | ||||
|  | @ -3216,6 +3248,16 @@ You can read the values of these properties using the functions: | |||
| 	func GetDatePickerMax(view View, subviewID ...string) (time.Time, bool) | ||||
| 	func GetDatePickerStep(view View, subviewID ...string) int | ||||
| 
 | ||||
| The "data-list" property (DataList constant) allows you to specify an array of recommended values. | ||||
| If you set the "data-list" property, the editor may have a drop-down menu with a list of these values. Some browsers may ignore this property, such as Safari for macOS. | ||||
| 
 | ||||
| The value of this property must be an array of strings in the format "YYYY-MM-DD". | ||||
| For example | ||||
| 
 | ||||
| 	editor := rui.NewDatePicker(session, rui.Params{ | ||||
| 		rui.DataList: []string{"1990-09-02", "2010-05-24"}, | ||||
| 	}) | ||||
| 
 | ||||
| The "date-changed" event (DateChangedEvent constant) is used to track the change in the entered value.  | ||||
| The main event listener has the following format: | ||||
| 
 | ||||
|  | @ -3271,6 +3313,16 @@ You can read the values of these properties using the functions: | |||
| 	func GetTimePickerMax(view View, subviewID ...string) (time.Time, bool) | ||||
| 	func GetTimePickerStep(view View, subviewID ...string) int | ||||
| 
 | ||||
| The "data-list" property (DataList constant) allows you to specify an array of recommended values. | ||||
| If you set the "data-list" property, the editor may have a drop-down menu with a list of these values. Some browsers may ignore this property, such as Safari for macOS. | ||||
| 
 | ||||
| The value of this property must be an array of strings in the format "HH:MM:SS" or "HH:MM". | ||||
| For example | ||||
| 
 | ||||
| 	editor := rui.NewTimePicker(session, rui.Params{ | ||||
| 		rui.DataList: []string{"1990-09-02", "2010-05-24"}, | ||||
| 	}) | ||||
| 
 | ||||
| The "time-changed" event (TimeChangedEvent constant) is used to track the change in the entered value.  | ||||
| The main event listener has the following format: | ||||
| 
 | ||||
|  |  | |||
|  | @ -16,6 +16,7 @@ type ColorPicker interface { | |||
| 
 | ||||
| type colorPickerData struct { | ||||
| 	viewData | ||||
| 	dataList | ||||
| 	colorChangedListeners []func(ColorPicker, Color, Color) | ||||
| } | ||||
| 
 | ||||
|  | @ -37,6 +38,7 @@ func (picker *colorPickerData) init(session Session) { | |||
| 	picker.hasHtmlDisabled = true | ||||
| 	picker.colorChangedListeners = []func(ColorPicker, Color, Color){} | ||||
| 	picker.properties[Padding] = Px(0) | ||||
| 	picker.dataListInit() | ||||
| } | ||||
| 
 | ||||
| func (picker *colorPickerData) String() string { | ||||
|  | @ -50,7 +52,7 @@ func (picker *colorPickerData) normalizeTag(tag string) string { | |||
| 		return ColorPickerValue | ||||
| 	} | ||||
| 
 | ||||
| 	return tag | ||||
| 	return picker.normalizeDataListTag(tag) | ||||
| } | ||||
| 
 | ||||
| func (picker *colorPickerData) Remove(tag string) { | ||||
|  | @ -70,6 +72,11 @@ func (picker *colorPickerData) remove(tag string) { | |||
| 		delete(picker.properties, ColorPickerValue) | ||||
| 		picker.colorChanged(oldColor) | ||||
| 
 | ||||
| 	case DataList: | ||||
| 		if len(picker.dataList.dataList) > 0 { | ||||
| 			picker.setDataList(picker, []string{}, true) | ||||
| 		} | ||||
| 
 | ||||
| 	default: | ||||
| 		picker.viewData.remove(tag) | ||||
| 	} | ||||
|  | @ -105,6 +112,9 @@ func (picker *colorPickerData) set(tag string, value any) bool { | |||
| 			return true | ||||
| 		} | ||||
| 
 | ||||
| 	case DataList: | ||||
| 		return picker.setDataList(picker, value, picker.created) | ||||
| 
 | ||||
| 	default: | ||||
| 		return picker.viewData.set(tag, value) | ||||
| 	} | ||||
|  | @ -132,6 +142,9 @@ func (picker *colorPickerData) get(tag string) any { | |||
| 	case ColorChangedEvent: | ||||
| 		return picker.colorChangedListeners | ||||
| 
 | ||||
| 	case DataList: | ||||
| 		return picker.dataList.dataList | ||||
| 
 | ||||
| 	default: | ||||
| 		return picker.viewData.get(tag) | ||||
| 	} | ||||
|  | @ -141,6 +154,10 @@ func (picker *colorPickerData) htmlTag() string { | |||
| 	return "input" | ||||
| } | ||||
| 
 | ||||
| func (picker *colorPickerData) htmlSubviews(self View, buffer *strings.Builder) { | ||||
| 	picker.dataListHtmlSubviews(self, buffer) | ||||
| } | ||||
| 
 | ||||
| func (picker *colorPickerData) htmlProperties(self View, buffer *strings.Builder) { | ||||
| 	picker.viewData.htmlProperties(self, buffer) | ||||
| 
 | ||||
|  | @ -152,6 +169,8 @@ func (picker *colorPickerData) htmlProperties(self View, buffer *strings.Builder | |||
| 	if picker.getRaw(ClickEvent) == nil { | ||||
| 		buffer.WriteString(` onclick="stopEventPropagation(this, event)"`) | ||||
| 	} | ||||
| 
 | ||||
| 	picker.dataListHtmlProperies(picker, buffer) | ||||
| } | ||||
| 
 | ||||
| func (picker *colorPickerData) handleCommand(self View, command string, data DataObject) bool { | ||||
|  |  | |||
|  | @ -0,0 +1,115 @@ | |||
| package rui | ||||
| 
 | ||||
| import "strings" | ||||
| 
 | ||||
| const ( | ||||
| 	// DataList is the constant for the "data-list" property tag.
 | ||||
| 	DataList = "data-list" | ||||
| ) | ||||
| 
 | ||||
| type dataList struct { | ||||
| 	dataList     []string | ||||
| 	dataListHtml bool | ||||
| } | ||||
| 
 | ||||
| func (list *dataList) dataListInit() { | ||||
| 	list.dataList = []string{} | ||||
| } | ||||
| 
 | ||||
| func (list *dataList) dataListID(view View) string { | ||||
| 	return view.htmlID() + "-datalist" | ||||
| } | ||||
| 
 | ||||
| func (list *dataList) normalizeDataListTag(tag string) string { | ||||
| 	switch tag { | ||||
| 	case "datalist": | ||||
| 		return DataList | ||||
| 	} | ||||
| 
 | ||||
| 	return tag | ||||
| } | ||||
| 
 | ||||
| func (list *dataList) setDataList(view View, value any, created bool) bool { | ||||
| 	items, ok := anyToStringArray(value) | ||||
| 	if !ok { | ||||
| 		notCompatibleType(DataList, value) | ||||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
| 	list.dataList = items | ||||
| 	if created { | ||||
| 		session := view.Session() | ||||
| 		dataListID := list.dataListID(view) | ||||
| 		buffer := allocStringBuilder() | ||||
| 		defer freeStringBuilder(buffer) | ||||
| 
 | ||||
| 		if list.dataListHtml { | ||||
| 			list.dataListItemsHtml(buffer) | ||||
| 			session.updateInnerHTML(dataListID, buffer.String()) | ||||
| 		} else { | ||||
| 			list.dataListHtmlCode(view, buffer) | ||||
| 			session.appendToInnerHTML(view.parentHTMLID(), buffer.String()) | ||||
| 			list.dataListHtml = true | ||||
| 			session.updateProperty(view.htmlID(), "list", dataListID) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| func (list *dataList) dataListHtmlSubviews(view View, buffer *strings.Builder) { | ||||
| 	if len(list.dataList) > 0 { | ||||
| 		list.dataListHtmlCode(view, buffer) | ||||
| 		list.dataListHtml = true | ||||
| 	} else { | ||||
| 		list.dataListHtml = false | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (list *dataList) dataListHtmlCode(view View, buffer *strings.Builder) { | ||||
| 	buffer.WriteString(`<datalist id="`) | ||||
| 	buffer.WriteString(list.dataListID(view)) | ||||
| 	buffer.WriteString(`">`) | ||||
| 	list.dataListItemsHtml(buffer) | ||||
| 	buffer.WriteString(`</datalist>`) | ||||
| } | ||||
| 
 | ||||
| func (list *dataList) dataListItemsHtml(buffer *strings.Builder) { | ||||
| 	for _, text := range list.dataList { | ||||
| 		if strings.ContainsRune(text, '"') { | ||||
| 			text = strings.ReplaceAll(text, `"`, `"`) | ||||
| 		} | ||||
| 		if strings.ContainsRune(text, '\n') { | ||||
| 			text = strings.ReplaceAll(text, "\n", `\n`) | ||||
| 		} | ||||
| 		buffer.WriteString(`<option value="`) | ||||
| 		buffer.WriteString(text) | ||||
| 		buffer.WriteString(`"></option>`) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (list *dataList) dataListHtmlProperies(view View, buffer *strings.Builder) { | ||||
| 	if len(list.dataList) > 0 { | ||||
| 		buffer.WriteString(` list="`) | ||||
| 		buffer.WriteString(list.dataListID(view)) | ||||
| 		buffer.WriteString(`"`) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // GetDataList returns the data list of an editor.
 | ||||
| // If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
 | ||||
| func GetDataList(view View, subviewID ...string) []string { | ||||
| 	if len(subviewID) > 0 && subviewID[0] != "" { | ||||
| 		view = ViewByID(view, subviewID[0]) | ||||
| 	} | ||||
| 
 | ||||
| 	if view != nil { | ||||
| 		if value := view.Get(DataList); value != nil { | ||||
| 			if list, ok := value.([]string); ok { | ||||
| 				return list | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return []string{} | ||||
| } | ||||
|  | @ -22,6 +22,7 @@ type DatePicker interface { | |||
| 
 | ||||
| type datePickerData struct { | ||||
| 	viewData | ||||
| 	dataList | ||||
| 	dateChangedListeners []func(DatePicker, time.Time, time.Time) | ||||
| } | ||||
| 
 | ||||
|  | @ -42,6 +43,7 @@ func (picker *datePickerData) init(session Session) { | |||
| 	picker.tag = "DatePicker" | ||||
| 	picker.hasHtmlDisabled = true | ||||
| 	picker.dateChangedListeners = []func(DatePicker, time.Time, time.Time){} | ||||
| 	picker.dataListInit() | ||||
| } | ||||
| 
 | ||||
| func (picker *datePickerData) String() string { | ||||
|  | @ -108,6 +110,11 @@ func (picker *datePickerData) remove(tag string) { | |||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 	case DataList: | ||||
| 		if len(picker.dataList.dataList) > 0 { | ||||
| 			picker.setDataList(picker, []string{}, true) | ||||
| 		} | ||||
| 
 | ||||
| 	default: | ||||
| 		picker.viewData.remove(tag) | ||||
| 		return | ||||
|  | @ -247,6 +254,9 @@ func (picker *datePickerData) set(tag string, value any) bool { | |||
| 		picker.propertyChangedEvent(tag) | ||||
| 		return true | ||||
| 
 | ||||
| 	case DataList: | ||||
| 		return picker.setDataList(picker, value, picker.created) | ||||
| 
 | ||||
| 	default: | ||||
| 		return picker.viewData.set(tag, value) | ||||
| 	} | ||||
|  | @ -262,6 +272,9 @@ func (picker *datePickerData) get(tag string) any { | |||
| 	case DateChangedEvent: | ||||
| 		return picker.dateChangedListeners | ||||
| 
 | ||||
| 	case DataList: | ||||
| 		return picker.dataList.dataList | ||||
| 
 | ||||
| 	default: | ||||
| 		return picker.viewData.get(tag) | ||||
| 	} | ||||
|  | @ -271,6 +284,10 @@ func (picker *datePickerData) htmlTag() string { | |||
| 	return "input" | ||||
| } | ||||
| 
 | ||||
| func (picker *datePickerData) htmlSubviews(self View, buffer *strings.Builder) { | ||||
| 	picker.dataListHtmlSubviews(self, buffer) | ||||
| } | ||||
| 
 | ||||
| func (picker *datePickerData) htmlProperties(self View, buffer *strings.Builder) { | ||||
| 	picker.viewData.htmlProperties(self, buffer) | ||||
| 
 | ||||
|  | @ -302,6 +319,8 @@ func (picker *datePickerData) htmlProperties(self View, buffer *strings.Builder) | |||
| 	if picker.getRaw(ClickEvent) == nil { | ||||
| 		buffer.WriteString(` onclick="stopEventPropagation(this, event)"`) | ||||
| 	} | ||||
| 
 | ||||
| 	picker.dataListHtmlProperies(picker, buffer) | ||||
| } | ||||
| 
 | ||||
| func (picker *datePickerData) handleCommand(self View, command string, data DataObject) bool { | ||||
|  |  | |||
							
								
								
									
										131
									
								
								dropDownList.go
								
								
								
								
							
							
						
						
									
										131
									
								
								dropDownList.go
								
								
								
								
							|  | @ -147,26 +147,129 @@ func (list *dropDownListData) set(tag string, value any) bool { | |||
| } | ||||
| 
 | ||||
| func (list *dropDownListData) setItems(value any) bool { | ||||
| 	items, ok := anyToStringArray(value) | ||||
| 	if !ok { | ||||
| 		notCompatibleType(Items, value) | ||||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
| 	list.items = items | ||||
| 	if list.created { | ||||
| 		updateInnerHTML(list.htmlID(), list.session) | ||||
| 	} | ||||
| 
 | ||||
| 	list.propertyChangedEvent(Items) | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| 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 | ||||
| } | ||||
| 
 | ||||
| func anyToStringArray(value any) ([]string, bool) { | ||||
| 
 | ||||
| 	switch value := value.(type) { | ||||
| 	case string: | ||||
| 		list.items = []string{value} | ||||
| 		return []string{value}, true | ||||
| 
 | ||||
| 	case []string: | ||||
| 		list.items = value | ||||
| 		return value, true | ||||
| 
 | ||||
| 	case []DataValue: | ||||
| 		list.items = make([]string, 0, len(value)) | ||||
| 		items := make([]string, 0, len(value)) | ||||
| 		for _, val := range value { | ||||
| 			if !val.IsObject() { | ||||
| 				list.items = append(list.items, val.Value()) | ||||
| 				items = append(items, val.Value()) | ||||
| 			} | ||||
| 		} | ||||
| 		return items, true | ||||
| 
 | ||||
| 	case []fmt.Stringer: | ||||
| 		list.items = make([]string, len(value)) | ||||
| 		items := make([]string, len(value)) | ||||
| 		for i, str := range value { | ||||
| 			list.items[i] = str.String() | ||||
| 			items[i] = str.String() | ||||
| 		} | ||||
| 		return items, true | ||||
| 
 | ||||
| 	case []Color: | ||||
| 		items := make([]string, len(value)) | ||||
| 		for i, str := range value { | ||||
| 			items[i] = str.String() | ||||
| 		} | ||||
| 		return items, true | ||||
| 
 | ||||
| 	case []SizeUnit: | ||||
| 		items := make([]string, len(value)) | ||||
| 		for i, str := range value { | ||||
| 			items[i] = str.String() | ||||
| 		} | ||||
| 		return items, true | ||||
| 
 | ||||
| 	case []AngleUnit: | ||||
| 		items := make([]string, len(value)) | ||||
| 		for i, str := range value { | ||||
| 			items[i] = str.String() | ||||
| 		} | ||||
| 		return items, true | ||||
| 
 | ||||
| 	case []float32: | ||||
| 		items := make([]string, len(value)) | ||||
| 		for i, val := range value { | ||||
| 			items[i] = fmt.Sprintf("%g", float64(val)) | ||||
| 		} | ||||
| 		return items, true | ||||
| 
 | ||||
| 	case []float64: | ||||
| 		items := make([]string, len(value)) | ||||
| 		for i, val := range value { | ||||
| 			items[i] = fmt.Sprintf("%g", val) | ||||
| 		} | ||||
| 		return items, true | ||||
| 
 | ||||
| 	case []int: | ||||
| 		return intArrayToStringArray(value), true | ||||
| 
 | ||||
| 	case []uint: | ||||
| 		return intArrayToStringArray(value), true | ||||
| 
 | ||||
| 	case []int8: | ||||
| 		return intArrayToStringArray(value), true | ||||
| 
 | ||||
| 	case []uint8: | ||||
| 		return intArrayToStringArray(value), true | ||||
| 
 | ||||
| 	case []int16: | ||||
| 		return intArrayToStringArray(value), true | ||||
| 
 | ||||
| 	case []uint16: | ||||
| 		return intArrayToStringArray(value), true | ||||
| 
 | ||||
| 	case []int32: | ||||
| 		return intArrayToStringArray(value), true | ||||
| 
 | ||||
| 	case []uint32: | ||||
| 		return intArrayToStringArray(value), true | ||||
| 
 | ||||
| 	case []int64: | ||||
| 		return intArrayToStringArray(value), true | ||||
| 
 | ||||
| 	case []uint64: | ||||
| 		return intArrayToStringArray(value), true | ||||
| 
 | ||||
| 	case []bool: | ||||
| 		items := make([]string, len(value)) | ||||
| 		for i, val := range value { | ||||
| 			if val { | ||||
| 				items[i] = "true" | ||||
| 			} else { | ||||
| 				items[i] = "false" | ||||
| 			} | ||||
| 		} | ||||
| 		return items, true | ||||
| 
 | ||||
| 	case []any: | ||||
| 		items := make([]string, 0, len(value)) | ||||
|  | @ -198,25 +301,15 @@ func (list *dropDownListData) setItems(value any) bool { | |||
| 				if n, ok := isInt(v); ok { | ||||
| 					items = append(items, strconv.Itoa(n)) | ||||
| 				} else { | ||||
| 					notCompatibleType(Items, value) | ||||
| 					return false | ||||
| 					return []string{}, false | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		list.items = items | ||||
| 
 | ||||
| 	default: | ||||
| 		notCompatibleType(Items, value) | ||||
| 		return false | ||||
| 		return items, true | ||||
| 	} | ||||
| 
 | ||||
| 	if list.created { | ||||
| 		updateInnerHTML(list.htmlID(), list.session) | ||||
| 	} | ||||
| 
 | ||||
| 	list.propertyChangedEvent(Items) | ||||
| 	return true | ||||
| 	return []string{}, false | ||||
| } | ||||
| 
 | ||||
| func (list *dropDownListData) setDisabledItems(value any) bool { | ||||
|  |  | |||
							
								
								
									
										28
									
								
								editView.go
								
								
								
								
							
							
						
						
									
										28
									
								
								editView.go
								
								
								
								
							|  | @ -8,10 +8,13 @@ import ( | |||
| const ( | ||||
| 	// EditTextChangedEvent is the constant for the "edit-text-changed" property tag.
 | ||||
| 	EditTextChangedEvent = "edit-text-changed" | ||||
| 
 | ||||
| 	// EditViewType is the constant for the "edit-view-type" property tag.
 | ||||
| 	EditViewType = "edit-view-type" | ||||
| 
 | ||||
| 	// EditViewPattern is the constant for the "edit-view-pattern" property tag.
 | ||||
| 	EditViewPattern = "edit-view-pattern" | ||||
| 
 | ||||
| 	// Spellcheck is the constant for the "spellcheck" property tag.
 | ||||
| 	Spellcheck = "spellcheck" | ||||
| ) | ||||
|  | @ -41,6 +44,7 @@ type EditView interface { | |||
| 
 | ||||
| type editViewData struct { | ||||
| 	viewData | ||||
| 	dataList | ||||
| 	textChangeListeners []func(EditView, string, string) | ||||
| } | ||||
| 
 | ||||
|  | @ -61,6 +65,7 @@ func (edit *editViewData) init(session Session) { | |||
| 	edit.hasHtmlDisabled = true | ||||
| 	edit.textChangeListeners = []func(EditView, string, string){} | ||||
| 	edit.tag = "EditView" | ||||
| 	edit.dataListInit() | ||||
| } | ||||
| 
 | ||||
| func (edit *editViewData) String() string { | ||||
|  | @ -87,7 +92,7 @@ func (edit *editViewData) normalizeTag(tag string) string { | |||
| 		return EditWrap | ||||
| 	} | ||||
| 
 | ||||
| 	return tag | ||||
| 	return edit.normalizeDataListTag(tag) | ||||
| } | ||||
| 
 | ||||
| func (edit *editViewData) Remove(tag string) { | ||||
|  | @ -184,9 +189,13 @@ func (edit *editViewData) remove(tag string) { | |||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 	case DataList: | ||||
| 		if len(edit.dataList.dataList) > 0 { | ||||
| 			edit.setDataList(edit, []string{}, true) | ||||
| 		} | ||||
| 
 | ||||
| 	default: | ||||
| 		edit.viewData.remove(tag) | ||||
| 		return | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | @ -324,6 +333,9 @@ func (edit *editViewData) set(tag string, value any) bool { | |||
| 		} | ||||
| 		return false | ||||
| 
 | ||||
| 	case DataList: | ||||
| 		return edit.setDataList(edit, value, edit.created) | ||||
| 
 | ||||
| 	case EditTextChangedEvent: | ||||
| 		listeners, ok := valueToEventWithOldListeners[EditView, string](value) | ||||
| 		if !ok { | ||||
|  | @ -345,8 +357,12 @@ func (edit *editViewData) Get(tag string) any { | |||
| } | ||||
| 
 | ||||
| func (edit *editViewData) get(tag string) any { | ||||
| 	if tag == EditTextChangedEvent { | ||||
| 	switch tag { | ||||
| 	case EditTextChangedEvent: | ||||
| 		return edit.textChangeListeners | ||||
| 
 | ||||
| 	case DataList: | ||||
| 		return edit.dataList.dataList | ||||
| 	} | ||||
| 	return edit.viewData.get(tag) | ||||
| } | ||||
|  | @ -383,6 +399,10 @@ func (edit *editViewData) htmlTag() string { | |||
| 	return "input" | ||||
| } | ||||
| 
 | ||||
| func (edit *editViewData) htmlSubviews(self View, buffer *strings.Builder) { | ||||
| 	edit.dataListHtmlSubviews(self, buffer) | ||||
| } | ||||
| 
 | ||||
| func (edit *editViewData) htmlProperties(self View, buffer *strings.Builder) { | ||||
| 	edit.viewData.htmlProperties(self, buffer) | ||||
| 
 | ||||
|  | @ -462,6 +482,8 @@ func (edit *editViewData) htmlProperties(self View, buffer *strings.Builder) { | |||
| 		buffer.WriteString(convertText(text)) | ||||
| 		buffer.WriteByte('"') | ||||
| 	} | ||||
| 
 | ||||
| 	edit.dataListHtmlProperies(edit, buffer) | ||||
| } | ||||
| 
 | ||||
| func (edit *editViewData) handleCommand(self View, command string, data DataObject) bool { | ||||
|  |  | |||
|  | @ -49,6 +49,7 @@ type NumberPicker interface { | |||
| 
 | ||||
| type numberPickerData struct { | ||||
| 	viewData | ||||
| 	dataList | ||||
| 	numberChangedListeners []func(NumberPicker, float64, float64) | ||||
| } | ||||
| 
 | ||||
|  | @ -69,6 +70,7 @@ func (picker *numberPickerData) init(session Session) { | |||
| 	picker.tag = "NumberPicker" | ||||
| 	picker.hasHtmlDisabled = true | ||||
| 	picker.numberChangedListeners = []func(NumberPicker, float64, float64){} | ||||
| 	picker.dataListInit() | ||||
| } | ||||
| 
 | ||||
| func (picker *numberPickerData) String() string { | ||||
|  | @ -86,7 +88,7 @@ func (picker *numberPickerData) normalizeTag(tag string) string { | |||
| 		return "number-picker-" + tag | ||||
| 	} | ||||
| 
 | ||||
| 	return tag | ||||
| 	return picker.normalizeDataListTag(tag) | ||||
| } | ||||
| 
 | ||||
| func (picker *numberPickerData) Remove(tag string) { | ||||
|  | @ -114,6 +116,11 @@ func (picker *numberPickerData) remove(tag string) { | |||
| 			picker.propertyChangedEvent(tag) | ||||
| 		} | ||||
| 
 | ||||
| 	case DataList: | ||||
| 		if len(picker.dataList.dataList) > 0 { | ||||
| 			picker.setDataList(picker, []string{}, true) | ||||
| 		} | ||||
| 
 | ||||
| 	default: | ||||
| 		picker.viewData.remove(tag) | ||||
| 		picker.propertyChanged(tag) | ||||
|  | @ -160,6 +167,9 @@ func (picker *numberPickerData) set(tag string, value any) bool { | |||
| 			return true | ||||
| 		} | ||||
| 
 | ||||
| 	case DataList: | ||||
| 		return picker.setDataList(picker, value, picker.created) | ||||
| 
 | ||||
| 	default: | ||||
| 		if picker.viewData.set(tag, value) { | ||||
| 			picker.propertyChanged(tag) | ||||
|  | @ -206,6 +216,9 @@ func (picker *numberPickerData) get(tag string) any { | |||
| 	case NumberChangedEvent: | ||||
| 		return picker.numberChangedListeners | ||||
| 
 | ||||
| 	case DataList: | ||||
| 		return picker.dataList.dataList | ||||
| 
 | ||||
| 	default: | ||||
| 		return picker.viewData.get(tag) | ||||
| 	} | ||||
|  | @ -215,6 +228,10 @@ func (picker *numberPickerData) htmlTag() string { | |||
| 	return "input" | ||||
| } | ||||
| 
 | ||||
| func (picker *numberPickerData) htmlSubviews(self View, buffer *strings.Builder) { | ||||
| 	picker.dataListHtmlSubviews(self, buffer) | ||||
| } | ||||
| 
 | ||||
| func (picker *numberPickerData) htmlProperties(self View, buffer *strings.Builder) { | ||||
| 	picker.viewData.htmlProperties(self, buffer) | ||||
| 
 | ||||
|  | @ -251,6 +268,8 @@ func (picker *numberPickerData) htmlProperties(self View, buffer *strings.Builde | |||
| 	buffer.WriteByte('"') | ||||
| 
 | ||||
| 	buffer.WriteString(` oninput="editViewInputEvent(this)"`) | ||||
| 
 | ||||
| 	picker.dataListHtmlProperies(picker, buffer) | ||||
| } | ||||
| 
 | ||||
| func (picker *numberPickerData) handleCommand(self View, command string, data DataObject) bool { | ||||
|  |  | |||
|  | @ -22,6 +22,7 @@ type TimePicker interface { | |||
| 
 | ||||
| type timePickerData struct { | ||||
| 	viewData | ||||
| 	dataList | ||||
| 	timeChangedListeners []func(TimePicker, time.Time, time.Time) | ||||
| } | ||||
| 
 | ||||
|  | @ -42,6 +43,7 @@ func (picker *timePickerData) init(session Session) { | |||
| 	picker.tag = "TimePicker" | ||||
| 	picker.hasHtmlDisabled = true | ||||
| 	picker.timeChangedListeners = []func(TimePicker, time.Time, time.Time){} | ||||
| 	picker.dataListInit() | ||||
| } | ||||
| 
 | ||||
| func (picker *timePickerData) String() string { | ||||
|  | @ -108,6 +110,11 @@ func (picker *timePickerData) remove(tag string) { | |||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 	case DataList: | ||||
| 		if len(picker.dataList.dataList) > 0 { | ||||
| 			picker.setDataList(picker, []string{}, true) | ||||
| 		} | ||||
| 
 | ||||
| 	default: | ||||
| 		picker.viewData.remove(tag) | ||||
| 		return | ||||
|  | @ -235,6 +242,9 @@ func (picker *timePickerData) set(tag string, value any) bool { | |||
| 		picker.propertyChangedEvent(tag) | ||||
| 		return true | ||||
| 
 | ||||
| 	case DataList: | ||||
| 		return picker.setDataList(picker, value, picker.created) | ||||
| 
 | ||||
| 	default: | ||||
| 		return picker.viewData.set(tag, value) | ||||
| 	} | ||||
|  | @ -250,6 +260,9 @@ func (picker *timePickerData) get(tag string) any { | |||
| 	case TimeChangedEvent: | ||||
| 		return picker.timeChangedListeners | ||||
| 
 | ||||
| 	case DataList: | ||||
| 		return picker.dataList.dataList | ||||
| 
 | ||||
| 	default: | ||||
| 		return picker.viewData.get(tag) | ||||
| 	} | ||||
|  | @ -259,6 +272,10 @@ func (picker *timePickerData) htmlTag() string { | |||
| 	return "input" | ||||
| } | ||||
| 
 | ||||
| func (picker *timePickerData) htmlSubviews(self View, buffer *strings.Builder) { | ||||
| 	picker.dataListHtmlSubviews(self, buffer) | ||||
| } | ||||
| 
 | ||||
| func (picker *timePickerData) htmlProperties(self View, buffer *strings.Builder) { | ||||
| 	picker.viewData.htmlProperties(self, buffer) | ||||
| 
 | ||||
|  | @ -290,6 +307,8 @@ func (picker *timePickerData) htmlProperties(self View, buffer *strings.Builder) | |||
| 	if picker.getRaw(ClickEvent) == nil { | ||||
| 		buffer.WriteString(` onclick="stopEventPropagation(this, event)"`) | ||||
| 	} | ||||
| 
 | ||||
| 	picker.dataListHtmlProperies(picker, buffer) | ||||
| } | ||||
| 
 | ||||
| func (picker *timePickerData) handleCommand(self View, command string, data DataObject) bool { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue