mirror of https://github.com/anoshenko/rui.git
367 lines
8.7 KiB
Go
367 lines
8.7 KiB
Go
package rui
|
|
|
|
import "strings"
|
|
|
|
type ParentView interface {
|
|
// Views return a list of child views
|
|
Views() []View
|
|
}
|
|
|
|
// ViewsContainer - mutable list-container of Views
|
|
type ViewsContainer interface {
|
|
View
|
|
ParentView
|
|
// Append appends a view to the end of the list of a view children
|
|
Append(view View)
|
|
// Insert inserts a view to the "index" position in the list of a view children
|
|
Insert(view View, index int)
|
|
// Remove removes a view from the list of a view children and return it
|
|
RemoveView(index int) View
|
|
// ViewIndex returns the index of view, -1 overwise
|
|
ViewIndex(view View) int
|
|
}
|
|
|
|
type viewsContainerData struct {
|
|
viewData
|
|
views []View
|
|
}
|
|
|
|
// Init initialize fields of ViewsContainer by default values
|
|
func (container *viewsContainerData) init(session Session) {
|
|
container.viewData.init(session)
|
|
container.tag = "ViewsContainer"
|
|
container.views = []View{}
|
|
}
|
|
|
|
func (container *viewsContainerData) String() string {
|
|
return getViewString(container)
|
|
}
|
|
|
|
func (container *viewsContainerData) setParentID(parentID string) {
|
|
container.viewData.setParentID(parentID)
|
|
htmlID := container.htmlID()
|
|
for _, view := range container.views {
|
|
view.setParentID(htmlID)
|
|
}
|
|
}
|
|
|
|
// Views return a list of child views
|
|
func (container *viewsContainerData) Views() []View {
|
|
if container.views == nil {
|
|
container.views = []View{}
|
|
} else if count := len(container.views); count > 0 {
|
|
views := make([]View, count)
|
|
copy(views, container.views)
|
|
return views
|
|
}
|
|
return []View{}
|
|
}
|
|
|
|
// Append appends a view to the end of the list of a view children
|
|
func (container *viewsContainerData) Append(view View) {
|
|
if view != nil {
|
|
htmlID := container.htmlID()
|
|
view.setParentID(htmlID)
|
|
if container.views == nil || len(container.views) == 0 {
|
|
container.views = []View{view}
|
|
} else {
|
|
container.views = append(container.views, view)
|
|
}
|
|
updateInnerHTML(container.htmlID(), container.session)
|
|
container.propertyChangedEvent(Content)
|
|
}
|
|
}
|
|
|
|
// Insert inserts a view to the "index" position in the list of a view children
|
|
func (container *viewsContainerData) Insert(view View, index int) {
|
|
if view != nil {
|
|
htmlID := container.htmlID()
|
|
if container.views == nil || index < 0 || index >= len(container.views) {
|
|
container.Append(view)
|
|
} else if index > 0 {
|
|
view.setParentID(htmlID)
|
|
container.views = append(container.views[:index], append([]View{view}, container.views[index:]...)...)
|
|
updateInnerHTML(container.htmlID(), container.session)
|
|
container.propertyChangedEvent(Content)
|
|
} else {
|
|
view.setParentID(htmlID)
|
|
container.views = append([]View{view}, container.views...)
|
|
updateInnerHTML(container.htmlID(), container.session)
|
|
container.propertyChangedEvent(Content)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Remove removes view from list and return it
|
|
func (container *viewsContainerData) RemoveView(index int) View {
|
|
if container.views == nil {
|
|
container.views = []View{}
|
|
return nil
|
|
}
|
|
|
|
count := len(container.views)
|
|
if index < 0 || index >= count {
|
|
return nil
|
|
}
|
|
|
|
view := container.views[index]
|
|
if index == 0 {
|
|
container.views = container.views[1:]
|
|
} else if index == count-1 {
|
|
container.views = container.views[:index]
|
|
} else {
|
|
container.views = append(container.views[:index], container.views[index+1:]...)
|
|
}
|
|
|
|
view.setParentID("")
|
|
updateInnerHTML(container.htmlID(), container.session)
|
|
container.propertyChangedEvent(Content)
|
|
return view
|
|
}
|
|
|
|
func (container *viewsContainerData) ViewIndex(view View) int {
|
|
for index, v := range container.views {
|
|
if v == view {
|
|
return index
|
|
}
|
|
}
|
|
return -1
|
|
}
|
|
|
|
func (container *viewsContainerData) cssStyle(self View, builder cssBuilder) {
|
|
container.viewData.cssStyle(self, builder)
|
|
builder.add(`overflow`, `auto`)
|
|
}
|
|
|
|
func (container *viewsContainerData) htmlSubviews(self View, buffer *strings.Builder) {
|
|
if container.views != nil {
|
|
for _, view := range container.views {
|
|
viewHTML(view, buffer)
|
|
}
|
|
}
|
|
}
|
|
|
|
func viewFromTextValue(text string, session Session) View {
|
|
if strings.Contains(text, "{") && strings.Contains(text, "}") {
|
|
data := ParseDataText(text)
|
|
if data != nil {
|
|
if view := CreateViewFromObject(session, data); view != nil {
|
|
return view
|
|
}
|
|
}
|
|
}
|
|
return NewTextView(session, Params{Text: text})
|
|
}
|
|
|
|
func (container *viewsContainerData) Remove(tag string) {
|
|
container.remove(strings.ToLower(tag))
|
|
}
|
|
|
|
func (container *viewsContainerData) remove(tag string) {
|
|
switch tag {
|
|
case Content:
|
|
if container.views == nil || len(container.views) > 0 {
|
|
container.views = []View{}
|
|
updateInnerHTML(container.htmlID(), container.Session())
|
|
}
|
|
container.propertyChangedEvent(Content)
|
|
|
|
case Disabled:
|
|
if _, ok := container.properties[Disabled]; ok {
|
|
delete(container.properties, Disabled)
|
|
if container.views != nil {
|
|
for _, view := range container.views {
|
|
view.Remove(Disabled)
|
|
}
|
|
}
|
|
container.propertyChangedEvent(tag)
|
|
}
|
|
|
|
default:
|
|
container.viewData.remove(tag)
|
|
}
|
|
}
|
|
|
|
func (container *viewsContainerData) Set(tag string, value any) bool {
|
|
return container.set(strings.ToLower(tag), value)
|
|
}
|
|
|
|
func (container *viewsContainerData) set(tag string, value any) bool {
|
|
if value == nil {
|
|
container.remove(tag)
|
|
return true
|
|
}
|
|
|
|
switch tag {
|
|
case Content:
|
|
// do nothing
|
|
|
|
case Disabled:
|
|
oldDisabled := IsDisabled(container)
|
|
if container.viewData.Set(Disabled, value) {
|
|
disabled := IsDisabled(container)
|
|
if oldDisabled != disabled {
|
|
if container.views != nil {
|
|
for _, view := range container.views {
|
|
view.Set(Disabled, disabled)
|
|
}
|
|
}
|
|
}
|
|
container.propertyChangedEvent(tag)
|
|
return true
|
|
}
|
|
return false
|
|
|
|
default:
|
|
return container.viewData.set(tag, value)
|
|
}
|
|
|
|
session := container.Session()
|
|
switch value := value.(type) {
|
|
case View:
|
|
container.views = []View{value}
|
|
|
|
case []View:
|
|
container.views = value
|
|
|
|
case string:
|
|
container.views = []View{viewFromTextValue(value, session)}
|
|
|
|
case []string:
|
|
views := []View{}
|
|
for _, text := range value {
|
|
views = append(views, viewFromTextValue(text, session))
|
|
}
|
|
container.views = views
|
|
|
|
case []any:
|
|
views := []View{}
|
|
for _, v := range value {
|
|
switch v := v.(type) {
|
|
case View:
|
|
views = append(views, v)
|
|
|
|
case string:
|
|
views = append(views, viewFromTextValue(v, session))
|
|
|
|
default:
|
|
notCompatibleType(tag, value)
|
|
return false
|
|
}
|
|
}
|
|
container.views = views
|
|
|
|
case DataObject:
|
|
if view := CreateViewFromObject(session, value); view != nil {
|
|
container.views = []View{view}
|
|
} else {
|
|
return false
|
|
}
|
|
|
|
case []DataValue:
|
|
views := []View{}
|
|
for _, data := range value {
|
|
if data.IsObject() {
|
|
if view := CreateViewFromObject(session, data.Object()); view != nil {
|
|
views = append(views, view)
|
|
}
|
|
} else {
|
|
views = append(views, viewFromTextValue(data.Value(), session))
|
|
}
|
|
}
|
|
container.views = views
|
|
|
|
default:
|
|
notCompatibleType(tag, value)
|
|
return false
|
|
}
|
|
|
|
htmlID := container.htmlID()
|
|
for _, view := range container.views {
|
|
view.setParentID(htmlID)
|
|
}
|
|
|
|
if container.created {
|
|
updateInnerHTML(htmlID, container.session)
|
|
}
|
|
|
|
container.propertyChangedEvent(Content)
|
|
return true
|
|
}
|
|
|
|
func (container *viewsContainerData) Get(tag string) any {
|
|
return container.get(strings.ToLower(tag))
|
|
}
|
|
|
|
func (container *viewsContainerData) get(tag string) any {
|
|
switch tag {
|
|
case Content:
|
|
return container.views
|
|
|
|
default:
|
|
return container.viewData.get(tag)
|
|
}
|
|
}
|
|
|
|
// AppendView appends a view to the end of the list of a view children
|
|
func AppendView(rootView View, containerID string, view View) bool {
|
|
var container ViewsContainer = nil
|
|
if containerID != "" {
|
|
container = ViewsContainerByID(rootView, containerID)
|
|
} else {
|
|
if cont, ok := rootView.(ViewsContainer); ok {
|
|
container = cont
|
|
} else {
|
|
ErrorLogF(`Unable to add a view to "%s"`, rootView.Tag())
|
|
}
|
|
}
|
|
|
|
if container != nil {
|
|
container.Append(view)
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// Insert inserts a view to the "index" position in the list of a view children
|
|
func InsertView(rootView View, containerID string, view View, index int) bool {
|
|
var container ViewsContainer = nil
|
|
if containerID != "" {
|
|
container = ViewsContainerByID(rootView, containerID)
|
|
} else {
|
|
if cont, ok := rootView.(ViewsContainer); ok {
|
|
container = cont
|
|
} else {
|
|
ErrorLogF(`Unable to add a view to "%s"`, rootView.Tag())
|
|
}
|
|
}
|
|
|
|
if container != nil {
|
|
container.Insert(view, index)
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// Remove removes a view from the list of a view children and return it
|
|
func RemoveView(rootView View, containerID string, index int) View {
|
|
var container ViewsContainer = nil
|
|
if containerID != "" {
|
|
container = ViewsContainerByID(rootView, containerID)
|
|
} else {
|
|
if cont, ok := rootView.(ViewsContainer); ok {
|
|
container = cont
|
|
} else {
|
|
ErrorLogF(`Unable to add a view to "%s"`, rootView.Tag())
|
|
}
|
|
}
|
|
|
|
if container != nil {
|
|
return container.RemoveView(index)
|
|
}
|
|
|
|
return nil
|
|
}
|