2021-09-07 17:36:50 +03:00
|
|
|
package rui
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
DateChangedEvent = "date-changed"
|
|
|
|
DatePickerMin = "date-picker-min"
|
|
|
|
DatePickerMax = "date-picker-max"
|
|
|
|
DatePickerStep = "date-picker-step"
|
|
|
|
DatePickerValue = "date-picker-value"
|
|
|
|
dateFormat = "2006-01-02"
|
|
|
|
)
|
|
|
|
|
|
|
|
// DatePicker - DatePicker view
|
|
|
|
type DatePicker interface {
|
|
|
|
View
|
|
|
|
}
|
|
|
|
|
|
|
|
type datePickerData struct {
|
|
|
|
viewData
|
|
|
|
dateChangedListeners []func(DatePicker, time.Time)
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewDatePicker create new DatePicker object and return it
|
|
|
|
func NewDatePicker(session Session, params Params) DatePicker {
|
|
|
|
view := new(datePickerData)
|
|
|
|
view.Init(session)
|
|
|
|
setInitParams(view, params)
|
|
|
|
return view
|
|
|
|
}
|
|
|
|
|
|
|
|
func newDatePicker(session Session) View {
|
|
|
|
return NewDatePicker(session, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (picker *datePickerData) Init(session Session) {
|
|
|
|
picker.viewData.Init(session)
|
|
|
|
picker.tag = "DatePicker"
|
|
|
|
picker.dateChangedListeners = []func(DatePicker, time.Time){}
|
|
|
|
}
|
|
|
|
|
2022-05-22 12:54:02 +03:00
|
|
|
func (picker *datePickerData) String() string {
|
|
|
|
return getViewString(picker)
|
|
|
|
}
|
|
|
|
|
2022-01-15 01:20:04 +03:00
|
|
|
func (picker *datePickerData) Focusable() bool {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2021-09-07 17:36:50 +03:00
|
|
|
func (picker *datePickerData) normalizeTag(tag string) string {
|
|
|
|
tag = strings.ToLower(tag)
|
|
|
|
switch tag {
|
|
|
|
case Type, Min, Max, Step, Value:
|
|
|
|
return "date-picker-" + tag
|
|
|
|
}
|
|
|
|
|
|
|
|
return tag
|
|
|
|
}
|
|
|
|
|
|
|
|
func (picker *datePickerData) Remove(tag string) {
|
|
|
|
picker.remove(picker.normalizeTag(tag))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (picker *datePickerData) remove(tag string) {
|
|
|
|
switch tag {
|
|
|
|
case DateChangedEvent:
|
|
|
|
if len(picker.dateChangedListeners) > 0 {
|
|
|
|
picker.dateChangedListeners = []func(DatePicker, time.Time){}
|
2021-11-20 11:15:28 +03:00
|
|
|
picker.propertyChangedEvent(tag)
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
2021-11-20 11:15:28 +03:00
|
|
|
return
|
2021-09-07 17:36:50 +03:00
|
|
|
|
|
|
|
case DatePickerMin:
|
|
|
|
delete(picker.properties, DatePickerMin)
|
2021-11-20 11:15:28 +03:00
|
|
|
if picker.created {
|
|
|
|
removeProperty(picker.htmlID(), Min, picker.session)
|
|
|
|
}
|
2021-09-07 17:36:50 +03:00
|
|
|
|
|
|
|
case DatePickerMax:
|
|
|
|
delete(picker.properties, DatePickerMax)
|
2021-11-20 11:15:28 +03:00
|
|
|
if picker.created {
|
|
|
|
removeProperty(picker.htmlID(), Max, picker.session)
|
|
|
|
}
|
2021-09-07 17:36:50 +03:00
|
|
|
|
|
|
|
case DatePickerStep:
|
2022-05-03 18:34:26 +03:00
|
|
|
delete(picker.properties, DatePickerStep)
|
2021-11-20 11:15:28 +03:00
|
|
|
if picker.created {
|
|
|
|
removeProperty(picker.htmlID(), Step, picker.session)
|
|
|
|
}
|
2021-09-07 17:36:50 +03:00
|
|
|
|
|
|
|
case DatePickerValue:
|
2021-11-20 11:15:28 +03:00
|
|
|
if _, ok := picker.properties[DatePickerValue]; ok {
|
|
|
|
delete(picker.properties, DatePickerValue)
|
|
|
|
date := GetDatePickerValue(picker, "")
|
|
|
|
if picker.created {
|
|
|
|
picker.session.runScript(fmt.Sprintf(`setInputValue('%s', '%s')`, picker.htmlID(), date.Format(dateFormat)))
|
|
|
|
}
|
|
|
|
for _, listener := range picker.dateChangedListeners {
|
|
|
|
listener(picker, date)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return
|
|
|
|
}
|
2021-09-07 17:36:50 +03:00
|
|
|
|
|
|
|
default:
|
|
|
|
picker.viewData.remove(tag)
|
2021-11-20 11:15:28 +03:00
|
|
|
return
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
2021-11-20 11:15:28 +03:00
|
|
|
picker.propertyChangedEvent(tag)
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func (picker *datePickerData) Set(tag string, value interface{}) bool {
|
|
|
|
return picker.set(picker.normalizeTag(tag), value)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (picker *datePickerData) set(tag string, value interface{}) bool {
|
|
|
|
if value == nil {
|
|
|
|
picker.remove(tag)
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
setTimeValue := func(tag string) (time.Time, bool) {
|
|
|
|
switch value := value.(type) {
|
|
|
|
case time.Time:
|
|
|
|
picker.properties[tag] = value
|
|
|
|
return value, true
|
|
|
|
|
|
|
|
case string:
|
|
|
|
if text, ok := picker.Session().resolveConstants(value); ok {
|
|
|
|
if date, err := time.Parse(dateFormat, text); err == nil {
|
|
|
|
picker.properties[tag] = value
|
|
|
|
return date, true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
notCompatibleType(tag, value)
|
|
|
|
return time.Now(), false
|
|
|
|
}
|
|
|
|
|
|
|
|
switch tag {
|
|
|
|
case DatePickerMin:
|
|
|
|
old, oldOK := getDateProperty(picker, DatePickerMin, Min)
|
|
|
|
if date, ok := setTimeValue(DatePickerMin); ok {
|
|
|
|
if !oldOK || date != old {
|
2021-11-20 11:15:28 +03:00
|
|
|
if picker.created {
|
|
|
|
updateProperty(picker.htmlID(), Min, date.Format(dateFormat), picker.session)
|
|
|
|
}
|
|
|
|
picker.propertyChangedEvent(tag)
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
case DatePickerMax:
|
|
|
|
old, oldOK := getDateProperty(picker, DatePickerMax, Max)
|
|
|
|
if date, ok := setTimeValue(DatePickerMax); ok {
|
|
|
|
if !oldOK || date != old {
|
2021-11-20 11:15:28 +03:00
|
|
|
if picker.created {
|
|
|
|
updateProperty(picker.htmlID(), Max, date.Format(dateFormat), picker.session)
|
|
|
|
}
|
|
|
|
picker.propertyChangedEvent(tag)
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
case DatePickerStep:
|
|
|
|
oldStep := GetDatePickerStep(picker, "")
|
|
|
|
if picker.setIntProperty(DatePickerStep, value) {
|
2021-11-20 11:15:28 +03:00
|
|
|
if step := GetDatePickerStep(picker, ""); oldStep != step {
|
|
|
|
if picker.created {
|
|
|
|
if step > 0 {
|
|
|
|
updateProperty(picker.htmlID(), Step, strconv.Itoa(step), picker.session)
|
|
|
|
} else {
|
|
|
|
removeProperty(picker.htmlID(), Step, picker.session)
|
|
|
|
}
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
2021-11-20 11:15:28 +03:00
|
|
|
picker.propertyChangedEvent(tag)
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
case DatePickerValue:
|
|
|
|
oldDate := GetDatePickerValue(picker, "")
|
2022-05-03 18:34:26 +03:00
|
|
|
if date, ok := setTimeValue(DatePickerValue); ok {
|
2021-09-07 17:36:50 +03:00
|
|
|
if date != oldDate {
|
2021-11-20 11:15:28 +03:00
|
|
|
if picker.created {
|
|
|
|
picker.session.runScript(fmt.Sprintf(`setInputValue('%s', '%s')`, picker.htmlID(), date.Format(dateFormat)))
|
|
|
|
}
|
2021-09-07 17:36:50 +03:00
|
|
|
for _, listener := range picker.dateChangedListeners {
|
|
|
|
listener(picker, date)
|
|
|
|
}
|
2021-11-20 11:15:28 +03:00
|
|
|
picker.propertyChangedEvent(tag)
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
case DateChangedEvent:
|
|
|
|
switch value := value.(type) {
|
|
|
|
case func(DatePicker, time.Time):
|
|
|
|
picker.dateChangedListeners = []func(DatePicker, time.Time){value}
|
|
|
|
|
|
|
|
case func(time.Time):
|
|
|
|
fn := func(view 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(view DatePicker, date time.Time) {
|
|
|
|
val(date)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
picker.dateChangedListeners = listeners
|
|
|
|
|
|
|
|
case []interface{}:
|
|
|
|
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(view DatePicker, date time.Time) {
|
|
|
|
val(date)
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
notCompatibleType(tag, val)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
picker.dateChangedListeners = listeners
|
|
|
|
}
|
2021-11-20 11:15:28 +03:00
|
|
|
picker.propertyChangedEvent(tag)
|
2021-09-07 17:36:50 +03:00
|
|
|
return true
|
|
|
|
|
|
|
|
default:
|
2021-11-20 11:15:28 +03:00
|
|
|
return picker.viewData.set(tag, value)
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
func (picker *datePickerData) Get(tag string) interface{} {
|
|
|
|
return picker.get(picker.normalizeTag(tag))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (picker *datePickerData) get(tag string) interface{} {
|
|
|
|
switch tag {
|
|
|
|
case DateChangedEvent:
|
|
|
|
return picker.dateChangedListeners
|
|
|
|
|
|
|
|
default:
|
|
|
|
return picker.viewData.get(tag)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (picker *datePickerData) htmlTag() string {
|
|
|
|
return "input"
|
|
|
|
}
|
|
|
|
|
|
|
|
func (picker *datePickerData) htmlProperties(self View, buffer *strings.Builder) {
|
|
|
|
picker.viewData.htmlProperties(self, buffer)
|
|
|
|
|
|
|
|
buffer.WriteString(` type="date"`)
|
|
|
|
|
|
|
|
if min, ok := getDateProperty(picker, DatePickerMin, Min); ok {
|
|
|
|
buffer.WriteString(` min="`)
|
|
|
|
buffer.WriteString(min.Format(dateFormat))
|
|
|
|
buffer.WriteByte('"')
|
|
|
|
}
|
|
|
|
|
|
|
|
if max, ok := getDateProperty(picker, DatePickerMax, Max); ok {
|
|
|
|
buffer.WriteString(` max="`)
|
|
|
|
buffer.WriteString(max.Format(dateFormat))
|
|
|
|
buffer.WriteByte('"')
|
|
|
|
}
|
|
|
|
|
|
|
|
if step, ok := intProperty(picker, DatePickerStep, picker.Session(), 0); ok && step > 0 {
|
|
|
|
buffer.WriteString(` step="`)
|
|
|
|
buffer.WriteString(strconv.Itoa(step))
|
|
|
|
buffer.WriteByte('"')
|
|
|
|
}
|
|
|
|
|
|
|
|
buffer.WriteString(` value="`)
|
|
|
|
buffer.WriteString(GetDatePickerValue(picker, "").Format(dateFormat))
|
|
|
|
buffer.WriteByte('"')
|
|
|
|
|
|
|
|
buffer.WriteString(` oninput="editViewInputEvent(this)"`)
|
2022-04-15 15:41:44 +03:00
|
|
|
if picker.getRaw(ClickEvent) == nil {
|
|
|
|
buffer.WriteString(` onclick="stopEventPropagation(this, event)"`)
|
|
|
|
}
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func (picker *datePickerData) htmlDisabledProperties(self View, buffer *strings.Builder) {
|
2021-11-20 11:15:28 +03:00
|
|
|
if IsDisabled(self, "") {
|
2021-09-07 17:36:50 +03:00
|
|
|
buffer.WriteString(` disabled`)
|
|
|
|
}
|
|
|
|
picker.viewData.htmlDisabledProperties(self, buffer)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (picker *datePickerData) handleCommand(self View, command string, data DataObject) bool {
|
|
|
|
switch command {
|
|
|
|
case "textChanged":
|
|
|
|
if text, ok := data.PropertyValue("text"); ok {
|
|
|
|
if value, err := time.Parse(dateFormat, text); err == nil {
|
|
|
|
oldValue := GetDatePickerValue(picker, "")
|
|
|
|
picker.properties[DatePickerValue] = value
|
|
|
|
if value != oldValue {
|
|
|
|
for _, listener := range picker.dateChangedListeners {
|
|
|
|
listener(picker, value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
return picker.viewData.handleCommand(self, command, data)
|
|
|
|
}
|
|
|
|
|
|
|
|
func getDateProperty(view View, mainTag, shortTag string) (time.Time, bool) {
|
|
|
|
valueToTime := func(value interface{}) (time.Time, bool) {
|
|
|
|
if value != nil {
|
|
|
|
switch value := value.(type) {
|
|
|
|
case time.Time:
|
|
|
|
return value, true
|
|
|
|
|
|
|
|
case string:
|
|
|
|
if text, ok := view.Session().resolveConstants(value); ok {
|
|
|
|
if result, err := time.Parse(dateFormat, text); err == nil {
|
|
|
|
return result, true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return time.Now(), false
|
|
|
|
}
|
|
|
|
|
|
|
|
if view != nil {
|
|
|
|
if result, ok := valueToTime(view.getRaw(mainTag)); ok {
|
|
|
|
return result, true
|
|
|
|
}
|
|
|
|
|
2022-05-23 15:22:14 +03:00
|
|
|
if value := valueFromStyle(view, shortTag); value != nil {
|
2021-09-07 17:36:50 +03:00
|
|
|
if result, ok := valueToTime(value); ok {
|
|
|
|
return result, true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return time.Now(), false
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetDatePickerMin returns the min date of DatePicker subview and "true" as the second value if the min date is set,
|
|
|
|
// "false" as the second value otherwise.
|
|
|
|
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
|
|
|
func GetDatePickerMin(view View, subviewID string) (time.Time, bool) {
|
|
|
|
if subviewID != "" {
|
|
|
|
view = ViewByID(view, subviewID)
|
|
|
|
}
|
|
|
|
if view != nil {
|
|
|
|
return getDateProperty(view, DatePickerMin, Min)
|
|
|
|
}
|
|
|
|
return time.Now(), false
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetDatePickerMax returns the max date of DatePicker subview and "true" as the second value if the min date is set,
|
|
|
|
// "false" as the second value otherwise.
|
|
|
|
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
|
|
|
func GetDatePickerMax(view View, subviewID string) (time.Time, bool) {
|
|
|
|
if subviewID != "" {
|
|
|
|
view = ViewByID(view, subviewID)
|
|
|
|
}
|
|
|
|
if view != nil {
|
|
|
|
return getDateProperty(view, DatePickerMax, Max)
|
|
|
|
}
|
|
|
|
return time.Now(), false
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetDatePickerStep returns the date changing step in days of DatePicker subview.
|
|
|
|
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
|
|
|
func GetDatePickerStep(view View, subviewID string) int {
|
|
|
|
if subviewID != "" {
|
|
|
|
view = ViewByID(view, subviewID)
|
|
|
|
}
|
|
|
|
if view != nil {
|
|
|
|
if result, _ := intStyledProperty(view, DatePickerStep, 0); result >= 0 {
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetDatePickerValue returns the date of DatePicker subview.
|
|
|
|
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
|
|
|
func GetDatePickerValue(view View, subviewID string) time.Time {
|
|
|
|
if subviewID != "" {
|
|
|
|
view = ViewByID(view, subviewID)
|
|
|
|
}
|
|
|
|
if view == nil {
|
|
|
|
return time.Now()
|
|
|
|
}
|
|
|
|
date, _ := getDateProperty(view, DatePickerValue, Value)
|
|
|
|
return date
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetDateChangedListeners returns the DateChangedListener list of an DatePicker subview.
|
|
|
|
// 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){}
|
|
|
|
}
|