package rui import ( "fmt" "strconv" "strings" ) // Constants for [TableView] specific properties and events const ( // TableVerticalAlign is the constant for "table-vertical-align" property tag. // // Used by `TableView`. // Set the vertical alignment of the content inside a table cell. // // Supported types: `int`, `string`. // // Values: // `0`(`TopAlign`) or "top" - Top alignment. // `1`(`BottomAlign`) or "bottom" - Bottom alignment. // `2`(`CenterAlign`) or "center" - Center alignment. // `3`(`StretchAlign`) or "stretch" - Work as baseline alignment, see below. // `4`(`BaselineAlign`) or "baseline" - Baseline alignment. TableVerticalAlign PropertyName = "table-vertical-align" // HeadHeight is the constant for "head-height" property tag. // // Used by `TableView`. // Sets the number of rows in the table header. The default value is `0` (no header). // // Supported types: `int`, `string`. // // Values: // `0` or "0" - No header. // > `0` or > "0" - Number of rows act as a header. HeadHeight PropertyName = "head-height" // HeadStyle is the constant for "head-style" property tag. // // Used by `TableView`. // Set the header style name or description of style properties. // // Supported types: `string`, `Params`. // // Internal type is either `string` or `Params`. // // Conversion rules: // `string` - must contain style name defined in resources. // `Params` - must contain style properties. HeadStyle PropertyName = "head-style" // FootHeight is the constant for "foot-height" property tag. // // Used by `TableView`. // Sets the number of rows in the table footer. The default value is `0` (no footer). // // Supported types: `int`, `string`. // // Values: // `0` or "0" - No footer. // > `0` or > "0" - Number of rows act as a footer. FootHeight PropertyName = "foot-height" // FootStyle is the constant for "foot-style" property tag. // // Used by `TableView`. // Set the footer style name or description of style properties. // // Supported types: `string`, `Params`. // // Internal type is either `string` or `Params`. // // Conversion rules: // `string` - must contain style name defined in resources. // `Params` - must contain style properties. FootStyle PropertyName = "foot-style" // RowSpan is the constant for "row-span" property tag. // // Used by `TableView`. // Set the number of table row to span. Used only when specifying cell parameters in the implementation of // `TableCellStyle`. // // Supported types: `int`, `string`. // // Values: // `0` or "0" - No merging will be applied. // > `0` or > "0" - Number of rows including current one to be merged together. RowSpan PropertyName = "row-span" // ColumnSpan is the constant for "column-span" property tag. // // Used by `TableView`. // Sets the number of table column cells to be merged together. Used only when specifying cell parameters in the // implementation of `TableCellStyle`. // // Supported types: `int`, `string`. // // Values: // `0` or "0" - No merging will be applied. // > `0` or > "0" - Number of columns including current one to be merged together. ColumnSpan PropertyName = "column-span" // RowStyle is the constant for "row-style" property tag. // // Used by `TableView`. // Set the adapter which specifies styles of each table row. // // Supported types: `TableRowStyle`, `[]Params`. // // Internal type is `TableRowStyle`, other types converted to it during assignment. // See `TableRowStyle` description for more details. RowStyle PropertyName = "row-style" // ColumnStyle is the constant for "column-style" property tag. // // Used by `TableView`. // Set the adapter which specifies styles of each table column. // // Supported types: `TableColumnStyle`, `[]Params`. // // Internal type is `TableColumnStyle`, other types converted to it during assignment. // See `TableColumnStyle` description for more details. ColumnStyle PropertyName = "column-style" // CellStyle is the constant for "cell-style" property tag. // // Used by `TableView`. // Set the adapter which specifies styles of each table cell. This property can be assigned only by an implementation of // `TableCellStyle` interface. // // Supported types: `TableCellStyle`. CellStyle PropertyName = "cell-style" // CellPadding is the constant for "cell-padding" property tag. // // Used by `TableView`. // Sets the padding area on all four sides of a table cell at once. An element's padding area is the space between its // content and its border. // // Supported types: `BoundsProperty`, `Bounds`, `SizeUnit`, `float32`, `float64`, `int`. // // Internal type is `BoundsProperty`, other types converted to it during assignment. // See `BoundsProperty`, `Bounds` and `SizeUnit` description for more details. CellPadding PropertyName = "cell-padding" // CellPaddingLeft is the constant for "cell-padding-left" property tag. // // Used by `TableView`. // Set the width of the padding area to the left of a cell content. An element's padding area is the space between its // content and its border. // // Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`. // // Internal type is `SizeUnit`, other types converted to it during assignment. // See `SizeUnit` description for more details. CellPaddingLeft PropertyName = "cell-padding-left" // CellPaddingRight is the constant for "cell-padding-right" property tag. // // Used by `TableView`. // Set the width of the padding area to the left of a cell content. An element's padding area is the space between its // content and its border. // // Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`. // // Internal type is `SizeUnit`, other types converted to it during assignment. // See `SizeUnit` description for more details. CellPaddingRight PropertyName = "cell-padding-right" // CellPaddingTop is the constant for "cell-padding-top" property tag. // // Used by `TableView`. // Set the height of the padding area to the top of a cell content. An element's padding area is the space between its // content and its border. // // Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`. // // Internal type is `SizeUnit`, other types converted to it during assignment. // See `SizeUnit` description for more details. CellPaddingTop PropertyName = "cell-padding-top" // CellPaddingBottom is the constant for "cell-padding-bottom" property tag. // // Used by `TableView`. // Set the height of the padding area to the bottom of a cell content. // // Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`. // // Internal type is `SizeUnit`, other types converted to it during assignment. // See `SizeUnit` description for more details. CellPaddingBottom PropertyName = "cell-padding-bottom" // CellBorder is the constant for "cell-border" property tag. // // Used by `TableView`. // Set a table cell's border. It sets the values of a border width, style, and color. Can also be used when setting // parameters in properties "row-style", "column-style", "foot-style" and "head-style". // // Supported types: `BorderProperty`, `ViewBorder`, `ViewBorders`. // // Internal type is `BorderProperty`, other types converted to it during assignment. // See `BorderProperty`, `ViewBorder` and `ViewBorders` description for more details. CellBorder PropertyName = "cell-border" // CellBorderLeft is the constant for "cell-border-left" property tag. // // Used by `TableView`. // Set a view's left border. It sets the values of a border width, style, and color. This property can be assigned a value // of `BorderProperty`, `ViewBorder` types or `BorderProperty` text representation. // // Supported types: `ViewBorder`, `BorderProperty`, `string`. // // Internal type is `BorderProperty`, other types converted to it during assignment. // See `ViewBorder` and `BorderProperty` description for more details. CellBorderLeft PropertyName = "cell-border-left" // CellBorderRight is the constant for "cell-border-right" property tag. // // Used by `TableView`. // Set a view's right border. It sets the values of a border width, style, and color. This property can be assigned a // value of `BorderProperty`, `ViewBorder` types or `BorderProperty` text representation. // // Supported types: `ViewBorder`, `BorderProperty`, `string`. // // Internal type is `BorderProperty`, other types converted to it during assignment. // See `ViewBorder` and `BorderProperty` description for more details. CellBorderRight PropertyName = "cell-border-right" // CellBorderTop is the constant for "cell-border-top" property tag. // // Used by `TableView`. // Set a view's top border. It sets the values of a border width, style, and color. This property can be assigned a value // of `BorderProperty`, `ViewBorder` types or `BorderProperty` text representation. // // Supported types: `ViewBorder`, `BorderProperty`, `string`. // // Internal type is `BorderProperty`, other types converted to it during assignment. // See `ViewBorder` and `BorderProperty` description for more details. CellBorderTop PropertyName = "cell-border-top" // CellBorderBottom is the constant for "cell-border-bottom" property tag. // // Used by `TableView`. // Set a view's bottom border. It sets the values of a border width, style, and color. // // Supported types: `ViewBorder`, `BorderProperty`, `string`. // // Internal type is `BorderProperty`, other types converted to it during assignment. // See `ViewBorder` and `BorderProperty` description for more details. CellBorderBottom PropertyName = "cell-border-bottom" // CellBorderStyle is the constant for "cell-border-style" property tag. // // Used by `TableView`. // Set the line style for all four sides of a table cell's border. Default value is "none". // // Supported types: `int`, `string`. // // Values: // `0`(`NoneLine`) or "none" - The border will not be drawn. // `1`(`SolidLine`) or "solid" - Solid line as a border. // `2`(`DashedLine`) or "dashed" - Dashed line as a border. // `3`(`DottedLine`) or "dotted" - Dotted line as a border. // `4`(`DoubleLine`) or "double" - Double line as a border. CellBorderStyle PropertyName = "cell-border-style" // CellBorderLeftStyle is the constant for "cell-border-left-style" property tag. // // Used by `TableView`. // Set the line style of a table cell's left border. Default value is "none". // // Supported types: `int`, `string`. // // Values: // `0`(`NoneLine`) or "none" - The border will not be drawn. // `1`(`SolidLine`) or "solid" - Solid line as a border. // `2`(`DashedLine`) or "dashed" - Dashed line as a border. // `3`(`DottedLine`) or "dotted" - Dotted line as a border. // `4`(`DoubleLine`) or "double" - Double line as a border. CellBorderLeftStyle PropertyName = "cell-border-left-style" // CellBorderRightStyle is the constant for "cell-border-right-style" property tag. // // Used by `TableView`. // Set the line style of a table cell's right border. Default value is "none". // // Supported types: `int`, `string`. // // Values: // `0`(`NoneLine`) or "none" - The border will not be drawn. // `1`(`SolidLine`) or "solid" - Solid line as a border. // `2`(`DashedLine`) or "dashed" - Dashed line as a border. // `3`(`DottedLine`) or "dotted" - Dotted line as a border. // `4`(`DoubleLine`) or "double" - Double line as a border. CellBorderRightStyle PropertyName = "cell-border-right-style" // CellBorderTopStyle is the constant for "cell-border-top-style" property tag. // // Used by `TableView`. // Set the line style of a table cell's top border. Default value is "none". // // Supported types: `int`, `string`. // // Values: // `0`(`NoneLine`) or "none" - The border will not be drawn. // `1`(`SolidLine`) or "solid" - Solid line as a border. // `2`(`DashedLine`) or "dashed" - Dashed line as a border. // `3`(`DottedLine`) or "dotted" - Dotted line as a border. // `4`(`DoubleLine`) or "double" - Double line as a border. CellBorderTopStyle PropertyName = "cell-border-top-style" // CellBorderBottomStyle is the constant for "cell-border-bottom-style" property tag. // // Used by `TableView`. // Sets the line style of a table cell's bottom border. Default value is "none". // // Supported types: `int`, `string`. // // Values: // `0`(`NoneLine`) or "none" - The border will not be drawn. // `1`(`SolidLine`) or "solid" - Solid line as a border. // `2`(`DashedLine`) or "dashed" - Dashed line as a border. // `3`(`DottedLine`) or "dotted" - Dotted line as a border. // `4`(`DoubleLine`) or "double" - Double line as a border. CellBorderBottomStyle PropertyName = "cell-border-bottom-style" // CellBorderWidth is the constant for "cell-border-width" property tag. // // Used by `TableView`. // Set the line width for all four sides of a table cell's border. // // Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`. // // Internal type is `SizeUnit`, other types converted to it during assignment. // See `SizeUnit` description for more details. CellBorderWidth PropertyName = "cell-border-width" // CellBorderLeftWidth is the constant for "cell-border-left-width" property tag. // // Used by `TableView`. // Set the line width of a table cell's left border. // // Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`. // // Internal type is `SizeUnit`, other types converted to it during assignment. // See `SizeUnit` description for more details. CellBorderLeftWidth PropertyName = "cell-border-left-width" // CellBorderRightWidth is the constant for "cell-border-right-width" property tag. // // Used by `TableView`. // Set the line width of a table cell's right border. // // Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`. // // Internal type is `SizeUnit`, other types converted to it during assignment. // See `SizeUnit` description for more details. CellBorderRightWidth PropertyName = "cell-border-right-width" // CellBorderTopWidth is the constant for "cell-border-top-width" property tag. // // Used by `TableView`. // Set the line width of a table cell's top border. // // Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`. // // Internal type is `SizeUnit`, other types converted to it during assignment. // See `SizeUnit` description for more details. CellBorderTopWidth PropertyName = "cell-border-top-width" // CellBorderBottomWidth is the constant for "cell-border-bottom-width" property tag. // // Used by `TableView`. // Set the line width of a table cell's bottom border. // // Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`. // // Internal type is `SizeUnit`, other types converted to it during assignment. // See `SizeUnit` description for more details. CellBorderBottomWidth PropertyName = "cell-border-bottom-width" // CellBorderColor is the constant for "cell-border-color" property tag. // // Used by `TableView`. // Set the line color for all four sides of a table cell's border. // // Supported types: `Color`, `string`. // // Internal type is `Color`, other types converted to it during assignment. // See `Color` description for more details. CellBorderColor PropertyName = "cell-border-color" // CellBorderLeftColor is the constant for "cell-border-left-color" property tag. // // Used by `TableView`. // Set the line color of a table cell's left border. // // Supported types: `Color`, `string`. // // Internal type is `Color`, other types converted to it during assignment. // See `Color` description for more details. CellBorderLeftColor PropertyName = "cell-border-left-color" // CellBorderRightColor is the constant for "cell-border-right-color" property tag. // // Used by `TableView`. // Set the line color of a table cell's right border. // // Supported types: `Color`, `string`. // // Internal type is `Color`, other types converted to it during assignment. // See `Color` description for more details. CellBorderRightColor PropertyName = "cell-border-right-color" // CellBorderTopColor is the constant for "cell-border-top-color" property tag. // // Used by `TableView`. // Set the line color of a table cell's top border. // // Supported types: `Color`, `string`. // // Internal type is `Color`, other types converted to it during assignment. // See `Color` description for more details. CellBorderTopColor PropertyName = "cell-border-top-color" // CellBorderBottomColor is the constant for "cell-border-bottom-color" property tag. // // Used by `TableView`. // Set the line color of a table cell's bottom border. // // Supported types: `Color`, `string`. // // Internal type is `Color`, other types converted to it during assignment. // See `Color` description for more details. CellBorderBottomColor PropertyName = "cell-border-bottom-color" // SelectionMode is the constant for "selection-mode" property tag. // // Used by `TableView`. // Sets the mode of the table elements selection. Default value is "none". // // Supported types: `int`, `string`. // // Values: // `0`(`NoneSelection`) or "none" - Table elements are not selectable. The table cannot receive input focus. // `1`(`CellSelection`) or "cell" - One table cell can be selected(highlighted). The cell is selected interactively using the mouse or keyboard(using the cursor keys). // `2`(`RowSelection`) or "row" - The entire table row can be selected (highlighted). The row is selected interactively using the mouse or keyboard (using the cursor keys). SelectionMode PropertyName = "selection-mode" // TableCellClickedEvent is the constant for "table-cell-clicked" property tag. // // Used by `TableView`. // Occur when the user clicks on a table cell. // // General listener format: // `func(table rui.TableView, row, col int)`. // // where: // table - Interface of a table view which generated this event, // row - Row of the clicked cell, // col - Column of the clicked cell. // // Allowed listener formats: // `func(row, col int)`. TableCellClickedEvent PropertyName = "table-cell-clicked" // TableCellSelectedEvent is the constant for "table-cell-selected" property tag. // // Used by `TableView`. // Occur when a table cell becomes selected. // // General listener format: // `func(table rui.TableView, row, col int)`. // // where: // table - Interface of a table view which generated this event, // row - Row of the selected cell, // col - Column of the selected cell. // // Allowed listener formats: // `func(row, col int)`. TableCellSelectedEvent PropertyName = "table-cell-selected" // TableRowClickedEvent is the constant for "table-row-clicked" property tag. // // Used by `TableView`. // Occur when the user clicks on a table row. // // General listener format: // `func(table rui.TableView, row int)`. // // where: // table - Interface of a table view which generated this event, // row - Clicked row. // // Allowed listener formats: // `func(row int)`. TableRowClickedEvent PropertyName = "table-row-clicked" // TableRowSelectedEvent is the constant for "table-row-selected" property tag. // // Used by `TableView`. // Occur when a table row becomes selected. // // General listener format: // `func(table rui.TableView, row int)`. // // where: // table - Interface of a table view which generated this event, // row - Selected row. // // Allowed listener formats: // `func(row int)`. TableRowSelectedEvent PropertyName = "table-row-selected" // AllowSelection is the constant for "allow-selection" property tag. // // Used by `TableView`. // Set the adapter which specifies whether cell/row selection is allowed. This property can be assigned by an // implementation of `TableAllowCellSelection` or `TableAllowRowSelection` interface. // // Supported types: `TableAllowCellSelection`, `TableAllowRowSelection`. // // Internal type is either `TableAllowCellSelection`, `TableAllowRowSelection`, see their description for more details. AllowSelection PropertyName = "allow-selection" ) // Constants which represent values of "selection-mode" property of a [TableView] const ( // NoneSelection the selection is forbidden. NoneSelection = 0 // CellSelection the selection of a single cell only is enabled. CellSelection = 1 // RowSelection the selection of a table row only is enabled. RowSelection = 2 ) // CellIndex defines coordinates of the [TableView] cell type CellIndex struct { Row, Column int } // TableView represents a TableView view type TableView interface { View ParentView // ReloadTableData forces the table view to reload all data and redraw the entire table ReloadTableData() // ReloadCell forces the table view to reload the data for a specific cell and redraw it ReloadCell(row, column int) // CellFrame returns the frame of a specific cell, describing its position and size within the table view CellFrame(row, column int) Frame } type tableViewData struct { viewData cellViews []View cellFrame []Frame } type tableCellView struct { viewData } // NewTableView create new TableView object and return it func NewTableView(session Session, params Params) TableView { view := new(tableViewData) view.init(session) setInitParams(view, params) return view } func newTableView(session Session) View { return new(tableViewData) // NewTableView(session, nil) } // Init initialize fields of TableView by default values func (table *tableViewData) init(session Session) { table.viewData.init(session) table.tag = "TableView" table.cellViews = []View{} table.cellFrame = []Frame{} /* table.cellSelectedListener = []func(TableView, int, int){} table.cellClickedListener = []func(TableView, int, int){} table.rowSelectedListener = []func(TableView, int){} table.rowClickedListener = []func(TableView, int){} table.current.Row = -1 table.current.Column = -1 */ table.normalize = normalizeTableViewTag table.set = tableViewSet table.changed = tableViewPropertyChanged } func normalizeTableViewTag(tag PropertyName) PropertyName { switch tag = defaultNormalize(tag); tag { case "top-cell-padding": tag = CellPaddingTop case "right-cell-padding": tag = CellPaddingRight case "bottom-cell-padding": tag = CellPaddingBottom case "left-cell-padding": tag = CellPaddingLeft } return tag } func (table *tableViewData) Focusable() bool { return GetTableSelectionMode(table) != NoneSelection } func tableViewSet(view View, tag PropertyName, value any) []PropertyName { setLineStyle := func() []PropertyName { params := []Params{} switch value := value.(type) { case []Params: params = value case DataNode: params = value.ArrayAsParams() default: notCompatibleType(tag, params) return nil } if len(params) > 0 { style := new(simpleTableLineStyle) style.params = params view.setRaw(tag, style) } else if view.getRaw(tag) != nil { view.setRaw(tag, nil) } else { return []PropertyName{} } return []PropertyName{tag} } switch tag { case Content: switch val := value.(type) { case TableAdapter: view.setRaw(Content, value) case [][]any: view.setRaw(Content, NewSimpleTableAdapter(val)) case [][]string: view.setRaw(Content, NewTextTableAdapter(val)) default: notCompatibleType(tag, value) return nil } return []PropertyName{tag} case TableCellClickedEvent, TableCellSelectedEvent: return setEventWithOldListener[TableView, int](view, tag, value) case TableRowClickedEvent, TableRowSelectedEvent: return setViewEventListener[TableView, int](view, tag, value) case CellStyle: if style, ok := value.(TableCellStyle); ok { view.setRaw(tag, style) return []PropertyName{tag} } notCompatibleType(tag, value) return nil case RowStyle: if style, ok := value.(TableRowStyle); ok { view.setRaw(tag, style) return []PropertyName{tag} } return setLineStyle() case ColumnStyle: if style, ok := value.(TableColumnStyle); ok { view.setRaw(tag, style) return []PropertyName{tag} } return setLineStyle() case HeadHeight, FootHeight: switch value := value.(type) { case string: if isConstantName(value) { view.setRaw(tag, value) } else if n, err := strconv.Atoi(value); err == nil { view.setRaw(tag, n) } else { ErrorLog(err.Error()) notCompatibleType(tag, value) return nil } default: if n, ok := isInt(value); ok { view.setRaw(tag, n) } else { notCompatibleType(tag, value) return nil } } return []PropertyName{tag} case HeadStyle, FootStyle: switch value := value.(type) { case string: view.setRaw(tag, value) case Params: if len(value) > 0 { view.setRaw(tag, value) } else if view.getRaw(tag) != nil { view.setRaw(tag, nil) } else { return []PropertyName{} } case DataObject: params := Params{} for k := 0; k < value.PropertyCount(); k++ { if prop := value.Property(k); prop != nil && prop.Type() == TextNode { params[PropertyName(prop.Tag())] = prop.Text() } } return tableViewSet(view, tag, params) case DataNode: switch value.Type() { case ObjectNode: return tableViewSet(view, tag, value.Object()) case TextNode: view.setRaw(tag, value.Text()) default: notCompatibleType(tag, value) return nil } default: notCompatibleType(tag, value) return nil } return []PropertyName{tag} case AllowSelection: switch value.(type) { case TableAllowCellSelection: view.setRaw(tag, value) case TableAllowRowSelection: view.setRaw(tag, value) default: notCompatibleType(tag, value) return nil } return []PropertyName{tag} case Current: current := CellIndex{Row: -1, Column: -1} switch value := value.(type) { case CellIndex: current = value case DataObject: if row, ok := dataIntProperty(value, "row"); ok { current.Row = row } if column, ok := dataIntProperty(value, "column"); ok { current.Column = column } case string: if strings.Contains(value, ",") { if values := strings.Split(value, ","); len(values) == 2 { var n = []int{0, 0} for i := 0; i < 2; i++ { var err error if n[i], err = strconv.Atoi(values[i]); err != nil { ErrorLog(err.Error()) return nil } } current.Row = n[0] current.Column = n[1] } else { notCompatibleType(tag, value) return nil } } else { n, err := strconv.Atoi(value) if err != nil { ErrorLog(err.Error()) return nil } current.Row = n } default: if n, ok := isInt(value); ok { current.Row = n } else { notCompatibleType(tag, value) return nil } } view.setRaw(Current, current) return []PropertyName{tag} } return viewSet(view, tag, value) } func tableViewPropertyChanged(view View, tag PropertyName) { htmlID := view.htmlID() session := view.Session() switch tag { case Content, TableVerticalAlign, RowStyle, ColumnStyle, CellStyle, CellPadding, CellBorder, HeadHeight, HeadStyle, FootHeight, FootStyle, CellPaddingTop, CellPaddingRight, CellPaddingBottom, CellPaddingLeft, TableCellClickedEvent, TableCellSelectedEvent, TableRowClickedEvent, TableRowSelectedEvent, AllowSelection, AccentColor: ReloadTableViewData(view) case Current: switch GetTableSelectionMode(view) { case CellSelection: current := tableViewCurrent(view) session.callFunc("setTableCellCursorByID", htmlID, current.Row, current.Column) case RowSelection: session.callFunc("setTableRowCursorByID", htmlID, tableViewCurrent(view).Row) } case Gap: gap, ok := sizeProperty(view, Gap, session) if !ok || gap.Type == Auto || gap.Value <= 0 { session.updateCSSProperty(htmlID, "border-spacing", "0") session.updateCSSProperty(htmlID, "border-collapse", "collapse") } else { session.updateCSSProperty(htmlID, "border-spacing", gap.cssString("0", session)) session.updateCSSProperty(htmlID, "border-collapse", "separate") } case SelectionMode: switch GetTableSelectionMode(view) { case CellSelection: tabIndex, _ := intProperty(view, TabIndex, session, 0) session.updateProperty(htmlID, "tabindex", tabIndex) session.updateProperty(htmlID, "onfocus", "tableViewFocusEvent(this, event)") session.updateProperty(htmlID, "onblur", "tableViewBlurEvent(this, event)") session.updateProperty(htmlID, "data-selection", "cell") session.updateProperty(htmlID, "data-focusitemstyle", tableViewCurrentStyle(view)) session.updateProperty(htmlID, "data-bluritemstyle", tableViewCurrentInactiveStyle(view)) current := tableViewCurrent(view) if current.Row >= 0 && current.Column >= 0 { session.updateProperty(htmlID, "data-current", tableViewCellID(view, current.Row, current.Column)) } else { session.removeProperty(htmlID, "data-current") } session.updateProperty(htmlID, "onkeydown", "tableViewCellKeyDownEvent(this, event)") case RowSelection: tabIndex, _ := intProperty(view, TabIndex, session, 0) session.updateProperty(htmlID, "tabindex", tabIndex) session.updateProperty(htmlID, "onfocus", "tableViewFocusEvent(this, event)") session.updateProperty(htmlID, "onblur", "tableViewBlurEvent(this, event)") session.updateProperty(htmlID, "data-selection", "row") session.updateProperty(htmlID, "data-focusitemstyle", tableViewCurrentStyle(view)) session.updateProperty(htmlID, "data-bluritemstyle", tableViewCurrentInactiveStyle(view)) current := tableViewCurrent(view) if current.Row >= 0 { session.updateProperty(htmlID, "data-current", tableViewRowID(view, current.Row)) } else { session.removeProperty(htmlID, "data-current") } session.updateProperty(htmlID, "onkeydown", "tableViewRowKeyDownEvent(this, event)") default: // NoneSelection if tabIndex, ok := intProperty(view, TabIndex, session, -1); !ok || tabIndex < 0 { session.removeProperty(htmlID, "tabindex") } for _, prop := range []string{"data-current", "onfocus", "onblur", "onkeydown", "data-selection"} { session.removeProperty(htmlID, prop) } } updateInnerHTML(htmlID, session) default: viewPropertyChanged(view, tag) } } func tableViewCurrentStyle(view View) string { if value := view.getRaw(CurrentStyle); value != nil { if style, ok := value.(string); ok { if style, ok = view.Session().resolveConstants(style); ok { return style } } } if value := valueFromStyle(view, CurrentStyle); value != nil { if style, ok := value.(string); ok { if style, ok = view.Session().resolveConstants(style); ok { return style } } } return "ruiCurrentTableCellFocused" } func tableViewCurrentInactiveStyle(view View) string { if value := view.getRaw(CurrentInactiveStyle); value != nil { if style, ok := value.(string); ok { if style, ok = view.Session().resolveConstants(style); ok { return style } } } if value := valueFromStyle(view, CurrentInactiveStyle); value != nil { if style, ok := value.(string); ok { if style, ok = view.Session().resolveConstants(style); ok { return style } } } return "ruiCurrentTableCell" } /* func (table *tableViewData) valueToCellListeners(value any) []func(TableView, int, int) { if value == nil { return []func(TableView, int, int){} } switch value := value.(type) { case func(TableView, int, int): return []func(TableView, int, int){value} case func(int, int): fn := func(_ TableView, row, column int) { value(row, column) } return []func(TableView, int, int){fn} case []func(TableView, int, int): return value case []func(int, int): listeners := make([]func(TableView, int, int), len(value)) for i, val := range value { if val == nil { return nil } listeners[i] = func(_ TableView, row, column int) { val(row, column) } } return listeners case []any: listeners := make([]func(TableView, int, int), len(value)) for i, val := range value { if val == nil { return nil } switch val := val.(type) { case func(TableView, int, int): listeners[i] = val case func(int, int): listeners[i] = func(_ TableView, row, column int) { val(row, column) } default: return nil } } return listeners } return nil } */ func (table *tableViewData) htmlTag() string { return "table" } func tableViewRowID(view View, index int) string { return fmt.Sprintf("%s-%d", view.htmlID(), index) } func tableViewCellID(view View, row, column int) string { return fmt.Sprintf("%s-%d-%d", view.htmlID(), row, column) } func (table *tableViewData) htmlProperties(self View, buffer *strings.Builder) { if content := GetTableContent(table); content != nil { buffer.WriteString(` data-rows="`) buffer.WriteString(strconv.Itoa(content.RowCount())) buffer.WriteString(`" data-columns="`) buffer.WriteString(strconv.Itoa(content.ColumnCount())) buffer.WriteRune('"') } if selectionMode := GetTableSelectionMode(table); selectionMode != NoneSelection { buffer.WriteString(` onfocus="tableViewFocusEvent(this, event)" onblur="tableViewBlurEvent(this, event)" data-focusitemstyle="`) buffer.WriteString(tableViewCurrentStyle(table)) buffer.WriteString(`" data-bluritemstyle="`) buffer.WriteString(tableViewCurrentInactiveStyle(table)) buffer.WriteRune('"') current := tableViewCurrent(table) switch selectionMode { case RowSelection: buffer.WriteString(` data-selection="row" onkeydown="tableViewRowKeyDownEvent(this, event)"`) if current.Row >= 0 { buffer.WriteString(` data-current="`) buffer.WriteString(tableViewRowID(table, current.Row)) buffer.WriteRune('"') } case CellSelection: buffer.WriteString(` data-selection="cell" onkeydown="tableViewCellKeyDownEvent(this, event)"`) if current.Row >= 0 && current.Column >= 0 { buffer.WriteString(` data-current="`) buffer.WriteString(tableViewCellID(table, current.Row, current.Column)) buffer.WriteRune('"') } } } table.viewData.htmlProperties(self, buffer) } func (table *tableViewData) htmlSubviews(self View, buffer *strings.Builder) { table.cellViews = []View{} table.cellFrame = []Frame{} adapter := GetTableContent(table) if adapter == nil { return } rowCount := adapter.RowCount() columnCount := adapter.ColumnCount() if rowCount == 0 || columnCount == 0 { return } table.cellFrame = make([]Frame, rowCount*columnCount) rowStyle := GetTableRowStyle(table) cellStyle := GetTableCellStyle(table) session := table.Session() current := tableViewCurrent(table) if !session.ignoreViewUpdates() { session.setIgnoreViewUpdates(true) defer session.setIgnoreViewUpdates(false) } cssBuilder := viewCSSBuilder{buffer: allocStringBuilder()} defer freeStringBuilder(cssBuilder.buffer) view := newTableCellView(session) ignoreCells := []struct{ row, column int }{} selectionMode := GetTableSelectionMode(table) var allowCellSelection TableAllowCellSelection = nil if allow, ok := adapter.(TableAllowCellSelection); ok { allowCellSelection = allow } if value := table.getRaw(AllowSelection); value != nil { if style, ok := value.(TableAllowCellSelection); ok { allowCellSelection = style } } var allowRowSelection TableAllowRowSelection = nil if allow, ok := adapter.(TableAllowRowSelection); ok { allowRowSelection = allow } if value := table.getRaw(AllowSelection); value != nil { if style, ok := value.(TableAllowRowSelection); ok { allowRowSelection = style } } vAlignCss := enumProperties[TableVerticalAlign].cssValues vAlignValue := GetTableVerticalAlign(table) if vAlignValue < 0 || vAlignValue >= len(vAlignCss) { vAlignValue = 0 } vAlign := vAlignCss[vAlignValue] tableCSS := func(startRow, endRow int, cellTag string, cellBorder BorderProperty, cellPadding BoundsProperty) { //var namedColors []NamedColor = nil for row := startRow; row < endRow; row++ { cssBuilder.buffer.Reset() if rowStyle != nil { if styles := rowStyle.RowStyle(row); styles != nil { view.Clear() for tag, value := range styles { view.Set(tag, value) } view.cssStyle(view, &cssBuilder) } } buffer.WriteString(`