forked from mbk-lab/rui_orig
2
0
Fork 0
rui/tabsLayout.go

942 lines
26 KiB
Go
Raw Normal View History

2021-09-07 17:36:50 +03:00
package rui
import (
"fmt"
"strconv"
"strings"
)
const (
2021-11-17 12:32:37 +03:00
// CurrentTabChangedEvent is the constant for "current-tab-changed" property tag.
// The "current-tab-changed" event occurs when the new tab becomes active.
// The main listener format: func(TabsLayout, int, int), where
// the second argument is the index of the new active tab,
// the third argument is the index of the old active tab.
CurrentTabChangedEvent = "current-tab-changed"
// Icon is the constant for "icon" property tag.
// The string "icon" property defines the icon name that is displayed in the tab.
Icon = "icon"
// TabCloseButton is the constant for "tab-close-button" property tag.
// The "tab-close-button" is the bool property. If it is "true" then a close button is displayed within the tab.
TabCloseButton = "tab-close-button"
// TabCloseEvent is the constant for "tab-close-event" property tag.
// The "tab-close-event" occurs when when the user clicks on the tab close button.
// The main listener format: func(TabsLayout, int), where the second argument is the index of the tab.
TabCloseEvent = "tab-close-event"
2021-09-07 17:36:50 +03:00
// TopTabs - tabs of TabsLayout are on the top
2021-11-17 12:32:37 +03:00
TopTabs = 0
2021-09-07 17:36:50 +03:00
// BottomTabs - tabs of TabsLayout are on the bottom
2021-11-17 12:32:37 +03:00
BottomTabs = 1
// LeftTabs - tabs of TabsLayout are on the left. Bookmarks are rotated counterclockwise 90 degrees.
LeftTabs = 2
// RightTabs - tabs of TabsLayout are on the right. Bookmarks are rotated clockwise 90 degrees.
RightTabs = 3
2021-09-07 17:36:50 +03:00
// LeftListTabs - tabs of TabsLayout are on the left
2021-11-17 12:32:37 +03:00
LeftListTabs = 4
2021-09-07 17:36:50 +03:00
// RightListTabs - tabs of TabsLayout are on the right
2021-11-17 12:32:37 +03:00
RightListTabs = 5
// HiddenTabs - tabs of TabsLayout are hidden
HiddenTabs = 6
2021-09-07 17:36:50 +03:00
2021-11-17 12:32:37 +03:00
inactiveTabStyle = "data-inactiveTabStyle"
activeTabStyle = "data-activeTabStyle"
)
2021-09-07 17:36:50 +03:00
// TabsLayout - multi-tab container of View
type TabsLayout interface {
ViewsContainer
2021-11-17 12:32:37 +03:00
ListAdapter
2021-09-07 17:36:50 +03:00
/*
// Current return the index of active tab
currentItem() int
// SetCurrent set the index of active tab
SetCurrent(current int)
// TabsLocation return the location of tabs. It returns one of the following values: HiddenTabs (0),
2021-11-04 21:13:34 +03:00
// TopTabs (1), BottomTabs (2), LeftTabs (3), RightTabs (4), LeftListTabs (5), RightListTabs (6)
2021-09-07 17:36:50 +03:00
tabsLocation() int
// TabsLocation set the location of tabs. Valid values: HiddenTabs (0), TopTabs (1),
2021-11-04 21:13:34 +03:00
// BottomTabs (2), LeftTabs (3), RightTabs (4), LeftListTabs (5), RightListTabs (6)
2021-09-07 17:36:50 +03:00
SetTabsLocation(location int)
// TabStyle() return styles of tab in the passive and the active state
TabStyle() (string, string)
SetTabStyle(tabStyle string, activeTabStyle string)
*/
}
type tabsLayoutData struct {
viewsContainerData
//currentTab, tabsLocation int
//tabStyle, activeTabStyle string
2021-11-17 12:32:37 +03:00
tabListener []func(TabsLayout, int, int)
tabCloseListener []func(TabsLayout, int)
2021-09-07 17:36:50 +03:00
}
// NewTabsLayout create new TabsLayout object and return it
func NewTabsLayout(session Session) TabsLayout {
view := new(tabsLayoutData)
view.Init(session)
return view
}
func newTabsLayout(session Session) View {
return NewTabsLayout(session)
}
// Init initialize fields of ViewsContainer by default values
func (tabsLayout *tabsLayoutData) Init(session Session) {
tabsLayout.viewsContainerData.Init(session)
tabsLayout.tag = "TabsLayout"
tabsLayout.systemClass = "ruiTabsLayout"
2021-11-17 12:32:37 +03:00
tabsLayout.tabListener = []func(TabsLayout, int, int){}
tabsLayout.tabCloseListener = []func(TabsLayout, int){}
2021-09-07 17:36:50 +03:00
}
func (tabsLayout *tabsLayoutData) currentItem() int {
result, _ := intProperty(tabsLayout, Current, tabsLayout.session, 0)
return result
}
2021-11-17 12:32:37 +03:00
func (tabsLayout *tabsLayoutData) Get(tag string) interface{} {
return tabsLayout.get(strings.ToLower(tag))
}
func (tabsLayout *tabsLayoutData) get(tag string) interface{} {
switch tag {
case CurrentTabChangedEvent:
return tabsLayout.tabListener
case TabCloseEvent:
return tabsLayout.tabCloseListener
}
return tabsLayout.viewsContainerData.get(tag)
}
func (tabsLayout *tabsLayoutData) Remove(tag string) {
tabsLayout.remove(strings.ToLower(tag))
}
func (tabsLayout *tabsLayoutData) remove(tag string) {
switch tag {
case CurrentTabChangedEvent:
if len(tabsLayout.tabListener) > 0 {
tabsLayout.tabListener = []func(TabsLayout, int, int){}
tabsLayout.propertyChangedEvent(tag)
}
return
2021-11-17 12:32:37 +03:00
case TabCloseEvent:
if len(tabsLayout.tabCloseListener) > 0 {
tabsLayout.tabCloseListener = []func(TabsLayout, int){}
tabsLayout.propertyChangedEvent(tag)
}
return
2021-11-17 12:32:37 +03:00
case Current:
oldCurrent := tabsLayout.currentItem()
delete(tabsLayout.properties, Current)
if oldCurrent == 0 {
return
}
if tabsLayout.created {
2021-11-17 12:32:37 +03:00
tabsLayout.session.runScript(fmt.Sprintf("activateTab(%v, %d);", tabsLayout.htmlID(), 0))
for _, listener := range tabsLayout.tabListener {
listener(tabsLayout, 0, oldCurrent)
}
}
case Tabs:
delete(tabsLayout.properties, Tabs)
if tabsLayout.created {
2021-11-17 12:32:37 +03:00
htmlID := tabsLayout.htmlID()
updateProperty(htmlID, inactiveTabStyle, tabsLayout.inactiveTabStyle(), tabsLayout.session)
updateProperty(htmlID, activeTabStyle, tabsLayout.activeTabStyle(), tabsLayout.session)
updateCSSStyle(htmlID, tabsLayout.session)
updateInnerHTML(htmlID, tabsLayout.session)
}
case TabStyle, CurrentTabStyle:
delete(tabsLayout.properties, tag)
if tabsLayout.created {
2021-11-17 12:32:37 +03:00
htmlID := tabsLayout.htmlID()
updateProperty(htmlID, inactiveTabStyle, tabsLayout.inactiveTabStyle(), tabsLayout.session)
updateProperty(htmlID, activeTabStyle, tabsLayout.activeTabStyle(), tabsLayout.session)
updateInnerHTML(htmlID, tabsLayout.session)
}
case TabCloseButton:
delete(tabsLayout.properties, tag)
if tabsLayout.created {
2021-11-17 12:32:37 +03:00
updateInnerHTML(tabsLayout.htmlID(), tabsLayout.session)
}
default:
tabsLayout.viewsContainerData.remove(tag)
return
2021-11-17 12:32:37 +03:00
}
tabsLayout.propertyChangedEvent(tag)
2021-11-17 12:32:37 +03:00
}
2021-09-07 17:36:50 +03:00
func (tabsLayout *tabsLayoutData) Set(tag string, value interface{}) bool {
2021-11-17 12:32:37 +03:00
return tabsLayout.set(strings.ToLower(tag), value)
}
func (tabsLayout *tabsLayoutData) set(tag string, value interface{}) bool {
if value == nil {
tabsLayout.remove(tag)
return true
}
2021-09-07 17:36:50 +03:00
switch tag {
2021-11-17 12:32:37 +03:00
case CurrentTabChangedEvent:
listeners := tabsLayout.valueToTabListeners(value)
if listeners == nil {
notCompatibleType(tag, value)
return false
}
tabsLayout.tabListener = listeners
case TabCloseEvent:
listeners := tabsLayout.valueToCloseListeners(value)
if listeners == nil {
notCompatibleType(tag, value)
return false
}
tabsLayout.tabCloseListener = listeners
2021-09-07 17:36:50 +03:00
case Current:
oldCurrent := tabsLayout.currentItem()
if !tabsLayout.setIntProperty(Current, value) {
return false
}
current := tabsLayout.currentItem()
if oldCurrent == current {
return true
}
if tabsLayout.created {
tabsLayout.session.runScript(fmt.Sprintf("activateTab(%v, %d);", tabsLayout.htmlID(), current))
for _, listener := range tabsLayout.tabListener {
listener(tabsLayout, current, oldCurrent)
2021-09-07 17:36:50 +03:00
}
}
case Tabs:
if !tabsLayout.setEnumProperty(Tabs, value, enumProperties[Tabs].values) {
return false
}
if tabsLayout.created {
2021-09-07 17:36:50 +03:00
htmlID := tabsLayout.htmlID()
2021-11-17 12:32:37 +03:00
updateProperty(htmlID, inactiveTabStyle, tabsLayout.inactiveTabStyle(), tabsLayout.session)
updateProperty(htmlID, activeTabStyle, tabsLayout.activeTabStyle(), tabsLayout.session)
2021-09-07 17:36:50 +03:00
updateCSSStyle(htmlID, tabsLayout.session)
updateInnerHTML(htmlID, tabsLayout.session)
}
case TabStyle, CurrentTabStyle:
2021-11-17 12:32:37 +03:00
if text, ok := value.(string); ok {
2021-09-07 17:36:50 +03:00
if text == "" {
delete(tabsLayout.properties, tag)
} else {
tabsLayout.properties[tag] = text
}
} else {
notCompatibleType(tag, value)
return false
}
if tabsLayout.created {
2021-09-07 17:36:50 +03:00
htmlID := tabsLayout.htmlID()
2021-11-17 12:32:37 +03:00
updateProperty(htmlID, inactiveTabStyle, tabsLayout.inactiveTabStyle(), tabsLayout.session)
updateProperty(htmlID, activeTabStyle, tabsLayout.activeTabStyle(), tabsLayout.session)
2021-09-07 17:36:50 +03:00
updateInnerHTML(htmlID, tabsLayout.session)
}
2021-11-17 12:32:37 +03:00
case TabCloseButton:
if !tabsLayout.setBoolProperty(tag, value) {
return false
}
if tabsLayout.created {
2021-11-17 12:32:37 +03:00
updateInnerHTML(tabsLayout.htmlID(), tabsLayout.session)
}
2021-09-07 17:36:50 +03:00
default:
2021-11-17 12:32:37 +03:00
return tabsLayout.viewsContainerData.set(tag, value)
2021-09-07 17:36:50 +03:00
}
tabsLayout.propertyChangedEvent(tag)
2021-09-07 17:36:50 +03:00
return true
}
2021-11-17 12:32:37 +03:00
func (tabsLayout *tabsLayoutData) valueToTabListeners(value interface{}) []func(TabsLayout, int, int) {
if value == nil {
return []func(TabsLayout, int, int){}
}
switch value := value.(type) {
case func(TabsLayout, int, int):
return []func(TabsLayout, int, int){value}
case func(TabsLayout, int):
fn := func(view TabsLayout, current, old int) {
value(view, current)
}
return []func(TabsLayout, int, int){fn}
case func(TabsLayout):
fn := func(view TabsLayout, current, old int) {
value(view)
}
return []func(TabsLayout, int, int){fn}
case func(int, int):
fn := func(view TabsLayout, current, old int) {
value(current, old)
}
return []func(TabsLayout, int, int){fn}
case func(int):
fn := func(view TabsLayout, current, old int) {
value(current)
}
return []func(TabsLayout, int, int){fn}
case func():
fn := func(view TabsLayout, current, old int) {
value()
}
return []func(TabsLayout, int, int){fn}
case []func(TabsLayout, int, int):
return value
case []func(TabsLayout, int):
listeners := make([]func(TabsLayout, int, int), len(value))
for i, val := range value {
if val == nil {
return nil
}
listeners[i] = func(view TabsLayout, current, old int) {
val(view, current)
}
}
return listeners
case []func(TabsLayout):
listeners := make([]func(TabsLayout, int, int), len(value))
for i, val := range value {
if val == nil {
return nil
}
listeners[i] = func(view TabsLayout, current, old int) {
val(view)
}
}
return listeners
case []func(int, int):
listeners := make([]func(TabsLayout, int, int), len(value))
for i, val := range value {
if val == nil {
return nil
}
listeners[i] = func(view TabsLayout, current, old int) {
val(current, old)
}
}
return listeners
case []func(int):
listeners := make([]func(TabsLayout, int, int), len(value))
for i, val := range value {
if val == nil {
return nil
}
listeners[i] = func(view TabsLayout, current, old int) {
val(current)
}
}
return listeners
case []func():
listeners := make([]func(TabsLayout, int, int), len(value))
for i, val := range value {
if val == nil {
return nil
}
listeners[i] = func(view TabsLayout, current, old int) {
val()
}
}
return listeners
case []interface{}:
listeners := make([]func(TabsLayout, int, int), len(value))
for i, val := range value {
if val == nil {
return nil
}
switch val := val.(type) {
case func(TabsLayout, int, int):
listeners[i] = val
case func(TabsLayout, int):
listeners[i] = func(view TabsLayout, current, old int) {
val(view, current)
}
case func(TabsLayout):
listeners[i] = func(view TabsLayout, current, old int) {
val(view)
}
case func(int, int):
listeners[i] = func(view TabsLayout, current, old int) {
val(current, old)
}
case func(int):
listeners[i] = func(view TabsLayout, current, old int) {
val(current)
}
case func():
listeners[i] = func(view TabsLayout, current, old int) {
val()
}
default:
return nil
}
}
return listeners
}
return nil
}
func (tabsLayout *tabsLayoutData) valueToCloseListeners(value interface{}) []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(view 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(view TabsLayout, index int) {
val(index)
}
}
return listeners
case []interface{}:
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(view TabsLayout, index int) {
val(index)
}
default:
return nil
}
}
return listeners
}
return nil
}
2021-09-07 17:36:50 +03:00
func (tabsLayout *tabsLayoutData) tabsLocation() int {
tabs, _ := enumProperty(tabsLayout, Tabs, tabsLayout.session, 0)
return tabs
}
func (tabsLayout *tabsLayoutData) inactiveTabStyle() string {
if style, ok := stringProperty(tabsLayout, TabStyle, tabsLayout.session); ok {
return style
}
switch tabsLayout.tabsLocation() {
case LeftTabs, RightTabs:
return "ruiInactiveVerticalTab"
}
return "ruiInactiveTab"
}
func (tabsLayout *tabsLayoutData) activeTabStyle() string {
if style, ok := stringProperty(tabsLayout, CurrentTabStyle, tabsLayout.session); ok {
return style
}
switch tabsLayout.tabsLocation() {
case LeftTabs, RightTabs:
return "ruiActiveVerticalTab"
}
return "ruiActiveTab"
}
2021-11-17 12:32:37 +03:00
func (tabsLayout *tabsLayoutData) ListSize() int {
if tabsLayout.views == nil {
tabsLayout.views = []View{}
}
return len(tabsLayout.views)
2021-09-07 17:36:50 +03:00
}
2021-11-17 12:32:37 +03:00
func (tabsLayout *tabsLayoutData) ListItem(index int, session Session) View {
if tabsLayout.views == nil {
tabsLayout.views = []View{}
}
2021-09-07 17:36:50 +03:00
2021-11-17 12:32:37 +03:00
if index < 0 || index >= len(tabsLayout.views) {
return NewTextView(session, Params{
Text: "Invalid index",
})
}
2021-09-07 17:36:50 +03:00
2021-11-17 12:32:37 +03:00
views := []View{}
page := tabsLayout.views[index]
if icon, ok := stringProperty(page, Icon, session); ok && icon != "" {
views = append(views, NewImageView(session, Params{
Source: icon,
Row: 0,
Column: 0,
}))
}
title, ok := stringProperty(page, Title, session)
if !ok || title == "" {
title = "No title"
}
if !GetNotTranslate(tabsLayout, "") {
title, _ = tabsLayout.Session().GetString(title)
}
views = append(views, NewTextView(session, Params{
Text: title,
Row: 0,
Column: 1,
}))
closeButton, _ := boolProperty(tabsLayout, TabCloseButton, tabsLayout.session)
if close, ok := boolProperty(page, TabCloseButton, tabsLayout.session); ok {
closeButton = close
2021-09-07 17:36:50 +03:00
}
2021-11-17 12:32:37 +03:00
if closeButton {
views = append(views, NewGridLayout(session, Params{
Style: "ruiTabCloseButton",
Row: 0,
Column: 2,
Content: "✕",
ClickEvent: func() {
// TODO close menu
for _, listener := range tabsLayout.tabCloseListener {
listener(tabsLayout, index)
}
},
}))
}
tabsHeight, _ := sizeConstant(session, "ruiTabHeight")
return NewGridLayout(session, Params{
Height: tabsHeight,
CellWidth: []SizeUnit{AutoSize(), Fr(1), AutoSize()},
CellVerticalAlign: CenterAlign,
GridRowGap: Px(8),
Content: views,
})
}
func (tabsLayout *tabsLayoutData) IsListItemEnabled(index int) bool {
return true
2021-09-07 17:36:50 +03:00
}
// Append appends view to the end of view list
func (tabsLayout *tabsLayoutData) Append(view View) {
if tabsLayout.views == nil {
tabsLayout.views = []View{}
}
2021-11-17 12:32:37 +03:00
if view != nil {
tabsLayout.viewsContainerData.Append(view)
if len(tabsLayout.views) == 1 {
tabsLayout.setIntProperty(Current, 0)
for _, listener := range tabsLayout.tabListener {
listener(tabsLayout, 0, -1)
}
2021-09-07 17:36:50 +03:00
}
2021-11-17 12:32:37 +03:00
updateInnerHTML(tabsLayout.htmlID(), tabsLayout.session)
2021-09-07 17:36:50 +03:00
}
}
// Insert inserts view to the "index" position in view list
func (tabsLayout *tabsLayoutData) Insert(view View, index uint) {
if tabsLayout.views == nil {
tabsLayout.views = []View{}
}
2021-11-17 12:32:37 +03:00
if view != nil {
tabsLayout.viewsContainerData.Insert(view, index)
current := tabsLayout.currentItem()
if current >= int(index) {
tabsLayout.Set(Current, current+1)
}
2021-09-07 17:36:50 +03:00
}
}
// Remove removes view from list and return it
func (tabsLayout *tabsLayoutData) RemoveView(index uint) View {
if tabsLayout.views == nil {
tabsLayout.views = []View{}
return nil
}
i := int(index)
count := len(tabsLayout.views)
if i >= count {
return nil
}
if count == 1 {
view := tabsLayout.views[0]
tabsLayout.views = []View{}
2021-11-17 12:32:37 +03:00
for _, listener := range tabsLayout.tabListener {
listener(tabsLayout, 0, 0)
2021-09-07 17:36:50 +03:00
}
return view
}
current := tabsLayout.currentItem()
removeCurrent := (i == current)
if i < current || (removeCurrent && i == count-1) {
tabsLayout.properties[Current] = current - 1
2021-11-17 12:32:37 +03:00
for _, listener := range tabsLayout.tabListener {
listener(tabsLayout, current-1, current)
2021-09-07 17:36:50 +03:00
}
}
return tabsLayout.viewsContainerData.RemoveView(index)
}
func (tabsLayout *tabsLayoutData) htmlProperties(self View, buffer *strings.Builder) {
tabsLayout.viewsContainerData.htmlProperties(self, buffer)
buffer.WriteString(` data-inactiveTabStyle="`)
buffer.WriteString(tabsLayout.inactiveTabStyle())
buffer.WriteString(`" data-activeTabStyle="`)
buffer.WriteString(tabsLayout.activeTabStyle())
buffer.WriteString(`" data-current="`)
buffer.WriteString(tabsLayout.htmlID())
buffer.WriteRune('-')
buffer.WriteString(strconv.Itoa(tabsLayout.currentItem()))
buffer.WriteRune('"')
}
func (tabsLayout *tabsLayoutData) cssStyle(self View, builder cssBuilder) {
tabsLayout.viewsContainerData.cssStyle(self, builder)
switch tabsLayout.tabsLocation() {
case TopTabs:
builder.add(`grid-template-rows`, `auto 1fr`)
case BottomTabs:
builder.add(`grid-template-rows`, `1fr auto`)
case LeftTabs, LeftListTabs:
builder.add(`grid-template-columns`, `auto 1fr`)
case RightTabs, RightListTabs:
builder.add(`grid-template-columns`, `1fr auto`)
}
}
func (tabsLayout *tabsLayoutData) htmlSubviews(self View, buffer *strings.Builder) {
if tabsLayout.views == nil {
return
}
//viewCount := len(tabsLayout.views)
current := tabsLayout.currentItem()
location := tabsLayout.tabsLocation()
tabsLayoutID := tabsLayout.htmlID()
if location != HiddenTabs {
tabsHeight, _ := sizeConstant(tabsLayout.session, "ruiTabHeight")
tabsSpace, _ := sizeConstant(tabsLayout.session, "ruiTabSpace")
rowLayout := false
buffer.WriteString(`<div style="display: flex;`)
switch location {
case LeftTabs, LeftListTabs, TopTabs:
buffer.WriteString(` grid-row-start: 1; grid-row-end: 2; grid-column-start: 1; grid-column-end: 2;`)
case RightTabs, RightListTabs:
buffer.WriteString(` grid-row-start: 1; grid-row-end: 2; grid-column-start: 2; grid-column-end: 3;`)
case BottomTabs:
buffer.WriteString(` grid-row-start: 2; grid-row-end: 3; grid-column-start: 1; grid-column-end: 2;`)
}
buffer.WriteString(` flex-flow: `)
switch location {
case LeftTabs, LeftListTabs, RightTabs, RightListTabs:
buffer.WriteString(`column nowrap; justify-content: flex-start; align-items: stretch;`)
default:
buffer.WriteString(`row nowrap; justify-content: flex-start; align-items: stretch;`)
if tabsHeight.Type != Auto {
buffer.WriteString(` height: `)
buffer.WriteString(tabsHeight.cssString(""))
buffer.WriteByte(';')
}
rowLayout = true
}
2021-11-17 12:32:37 +03:00
switch location {
case LeftTabs, RightTabs:
if tabsHeight.Type != Auto {
buffer.WriteString(` width: `)
buffer.WriteString(tabsHeight.cssString(""))
buffer.WriteByte(';')
}
}
2021-09-07 17:36:50 +03:00
var tabsPadding Bounds
2021-11-17 12:32:37 +03:00
if value, ok := tabsLayout.session.Constant("ruiTabsPadding"); ok {
2021-09-07 17:36:50 +03:00
if tabsPadding.parse(value, tabsLayout.session) {
if !tabsPadding.allFieldsAuto() {
buffer.WriteByte(' ')
buffer.WriteString(Padding)
buffer.WriteString(`: `)
tabsPadding.writeCSSString(buffer, "0")
buffer.WriteByte(';')
}
}
}
2021-11-17 12:32:37 +03:00
if tabsBackground, ok := tabsLayout.session.Color("ruiTabsBackgroundColor"); ok {
2021-09-07 17:36:50 +03:00
buffer.WriteString(` background-color: `)
buffer.WriteString(tabsBackground.cssString())
buffer.WriteByte(';')
}
buffer.WriteString(`">`)
inactiveStyle := tabsLayout.inactiveTabStyle()
activeStyle := tabsLayout.activeTabStyle()
notTranslate := GetNotTranslate(tabsLayout, "")
2021-11-17 12:32:37 +03:00
closeButton, _ := boolProperty(tabsLayout, TabCloseButton, tabsLayout.session)
tabMargin := ""
if tabsSpace.Type != Auto && tabsSpace.Value > 0 {
if rowLayout {
tabMargin = ` margin-right: ` + tabsSpace.cssString("") + ";"
} else {
tabMargin = ` margin-bottom: ` + tabsSpace.cssString("") + ";"
}
}
var tabStyle, titleDiv string
switch location {
case LeftTabs, RightTabs:
tabStyle = `display: grid; grid-template-rows: auto 1fr auto; align-items: center; justify-items: center; grid-row-gap: 8px;`
case LeftListTabs, RightListTabs:
tabStyle = `display: grid; grid-template-columns: auto 1fr auto; align-items: start; justify-items: center; grid-column-gap: 8px;`
default:
tabStyle = `display: grid; grid-template-columns: auto 1fr auto; align-items: center; justify-items: center; grid-column-gap: 8px;`
}
switch location {
case LeftListTabs, RightListTabs:
if tabsHeight.Type != Auto {
tabStyle += ` height: ` + tabsHeight.cssString("") + ";"
}
}
switch location {
case LeftTabs:
titleDiv = `<div style="writing-mode: vertical-lr; transform: rotate(180deg); grid-row-start: 2; grid-row-end: 3; grid-column-start: 1; grid-column-end: 2;">`
case RightTabs:
titleDiv = `<div style="writing-mode: vertical-lr; grid-row-start: 2; grid-row-end: 3; grid-column-start: 1; grid-column-end: 2;">`
default:
titleDiv = `<div style="grid-row-start: 1; grid-row-end: 2; grid-column-start: 2; grid-column-end: 3;">`
}
2021-09-07 17:36:50 +03:00
last := len(tabsLayout.views) - 1
for n, view := range tabsLayout.views {
2021-11-17 12:32:37 +03:00
icon, _ := stringProperty(view, Icon, tabsLayout.session)
title, _ := stringProperty(view, Title, tabsLayout.session)
2021-09-07 17:36:50 +03:00
if !notTranslate {
title, _ = tabsLayout.Session().GetString(title)
}
buffer.WriteString(`<div id="`)
buffer.WriteString(tabsLayoutID)
buffer.WriteByte('-')
buffer.WriteString(strconv.Itoa(n))
buffer.WriteString(`" class="`)
if n == current {
buffer.WriteString(activeStyle)
} else {
buffer.WriteString(inactiveStyle)
}
buffer.WriteString(`" tabindex="0" onclick="tabClickEvent(\'`)
buffer.WriteString(tabsLayoutID)
buffer.WriteString(`\', `)
buffer.WriteString(strconv.Itoa(n))
2021-11-17 12:32:37 +03:00
buffer.WriteString(`, event)" onclick="tabKeyClickEvent(\'`)
2021-09-07 17:36:50 +03:00
buffer.WriteString(tabsLayoutID)
buffer.WriteString(`\', `)
buffer.WriteString(strconv.Itoa(n))
2021-11-17 12:32:37 +03:00
buffer.WriteString(`, event)" style="`)
buffer.WriteString(tabStyle)
2021-09-07 17:36:50 +03:00
2021-11-17 12:32:37 +03:00
if n != last {
buffer.WriteString(tabMargin)
2021-09-07 17:36:50 +03:00
}
buffer.WriteString(`" data-container="`)
buffer.WriteString(tabsLayoutID)
buffer.WriteString(`" data-view="`)
buffer.WriteString(tabsLayoutID)
buffer.WriteString(`-page`)
buffer.WriteString(strconv.Itoa(n))
2021-11-17 12:32:37 +03:00
buffer.WriteString(`">`)
2021-09-07 17:36:50 +03:00
2021-11-17 12:32:37 +03:00
if icon != "" {
switch location {
case LeftTabs:
buffer.WriteString(`<img style="grid-row-start: 3; grid-row-end: 4; grid-column-start: 1; grid-column-end: 2;" src="`)
2021-09-07 17:36:50 +03:00
2021-11-17 12:32:37 +03:00
case RightTabs:
buffer.WriteString(`<img style="grid-row-start: 1; grid-row-end: 2; grid-column-start: 1; grid-column-end: 2;" src="`)
2021-09-07 17:36:50 +03:00
2021-11-17 12:32:37 +03:00
default:
buffer.WriteString(`<img style="grid-row-start: 1; grid-row-end: 2; grid-column-start: 1; grid-column-end: 2;" src="`)
}
buffer.WriteString(icon)
buffer.WriteString(`">`)
2021-09-07 17:36:50 +03:00
}
2021-11-17 12:32:37 +03:00
buffer.WriteString(titleDiv)
2021-09-07 17:36:50 +03:00
buffer.WriteString(title)
2021-11-17 12:32:37 +03:00
buffer.WriteString(`</div>`)
close, ok := boolProperty(view, TabCloseButton, tabsLayout.session)
if !ok {
close = closeButton
}
if close {
buffer.WriteString(`<div class="ruiTabCloseButton" onclick="tabCloseClickEvent(\'`)
buffer.WriteString(tabsLayoutID)
buffer.WriteString(`\', `)
buffer.WriteString(strconv.Itoa(n))
buffer.WriteString(`, event)" style="display: grid; `)
switch location {
case LeftTabs:
buffer.WriteString(`grid-row-start: 1; grid-row-end: 2; grid-column-start: 1; grid-column-end: 2;">`)
case RightTabs:
buffer.WriteString(`grid-row-start: 3; grid-row-end: 4; grid-column-start: 1; grid-column-end: 2;">`)
default:
buffer.WriteString(`grid-row-start: 1; grid-row-end: 2; grid-column-start: 3; grid-column-end: 4;">`)
}
buffer.WriteString(`✕</div>`)
}
buffer.WriteString(`</div>`)
2021-09-07 17:36:50 +03:00
}
buffer.WriteString(`</div>`)
}
for n, view := range tabsLayout.views {
buffer.WriteString(`<div id="`)
buffer.WriteString(tabsLayoutID)
buffer.WriteString(`-page`)
buffer.WriteString(strconv.Itoa(n))
switch location {
case LeftTabs, LeftListTabs:
buffer.WriteString(`" style="position: relative; grid-row-start: 1; grid-row-end: 2; grid-column-start: 2; grid-column-end: 3;`)
case TopTabs:
buffer.WriteString(`" style="position: relative; grid-row-start: 2; grid-row-end: 3; grid-column-start: 1; grid-column-end: 2;`)
default:
buffer.WriteString(`" style="position: relative; grid-row-start: 1; grid-row-end: 2; grid-column-start: 1; grid-column-end: 2;`)
}
if current != n {
buffer.WriteString(` display: none;`)
}
buffer.WriteString(`">`)
view.addToCSSStyle(map[string]string{`position`: `absolute`, `left`: `0`, `right`: `0`, `top`: `0`, `bottom`: `0`})
viewHTML(tabsLayout.views[n], buffer)
buffer.WriteString(`</div>`)
}
}
func (tabsLayout *tabsLayoutData) handleCommand(self View, command string, data DataObject) bool {
switch command {
case "tabClick":
if numberText, ok := data.PropertyValue("number"); ok {
if number, err := strconv.Atoi(numberText); err == nil {
current := tabsLayout.currentItem()
if current != number {
tabsLayout.properties[Current] = number
2021-11-17 12:32:37 +03:00
for _, listener := range tabsLayout.tabListener {
listener(tabsLayout, number, current)
2021-09-07 17:36:50 +03:00
}
tabsLayout.propertyChangedEvent(Current)
2021-09-07 17:36:50 +03:00
}
}
}
return true
2021-11-17 12:32:37 +03:00
case "tabCloseClick":
if numberText, ok := data.PropertyValue("number"); ok {
if number, err := strconv.Atoi(numberText); err == nil {
for _, listener := range tabsLayout.tabCloseListener {
listener(tabsLayout, number)
}
}
}
return true
2021-09-07 17:36:50 +03:00
}
return tabsLayout.viewsContainerData.handleCommand(self, command, data)
}