From bd410e730341f42bf95d8dc4d40c6ad72f1d7da2 Mon Sep 17 00:00:00 2001 From: AllenFang Date: Wed, 15 Aug 2018 22:51:44 +0800 Subject: [PATCH] refine selection consumer --- packages/react-bootstrap-table2/src/body.js | 98 ++++---- .../src/bootstrap-table.js | 34 +-- .../src/contexts/index.js | 33 ++- .../src/contexts/selection-context.js | 229 ++++++++++-------- packages/react-bootstrap-table2/src/header.js | 11 +- .../src/props-resolver/index.js | 61 ----- .../src/row-aggregator.js | 140 +++++++++++ .../src/row-event-delegater.js | 64 +---- .../src/row-selection/row-binder.js | 57 +++++ .../selection-header-cell-binder.js | 8 + packages/react-bootstrap-table2/src/row.js | 36 +-- 11 files changed, 411 insertions(+), 360 deletions(-) create mode 100644 packages/react-bootstrap-table2/src/row-aggregator.js create mode 100644 packages/react-bootstrap-table2/src/row-selection/row-binder.js create mode 100644 packages/react-bootstrap-table2/src/row-selection/selection-header-cell-binder.js diff --git a/packages/react-bootstrap-table2/src/body.js b/packages/react-bootstrap-table2/src/body.js index 7b29989..eb4138a 100644 --- a/packages/react-bootstrap-table2/src/body.js +++ b/packages/react-bootstrap-table2/src/body.js @@ -3,13 +3,14 @@ import React from 'react'; import PropTypes from 'prop-types'; -import cs from 'classnames'; import _ from './utils'; import Row from './row'; +import RowAggregator from './row-aggregator'; import ExpandRow from './row-expand/expand-row'; import RowSection from './row-section'; import Const from './const'; +import bindSelection from './row-selection/row-binder'; const Body = (props) => { const { @@ -21,18 +22,12 @@ const Body = (props) => { visibleColumnSize, cellEdit, selectRow, - selectedRowKeys, rowStyle, rowClasses, rowEvents, expandRow } = props; - const { - bgColor, - nonSelectable - } = selectRow; - let content; if (isEmpty) { @@ -42,62 +37,54 @@ const Body = (props) => { } content = ; } else { + let RowComponent = Row; const nonEditableRows = cellEdit.nonEditableRows || []; + const selectRowEnabled = selectRow.mode !== Const.ROW_SELECT_DISABLED; + const expandRowEnabled = !!expandRow; + + if (selectRowEnabled) { + RowComponent = bindSelection(RowAggregator); + } + content = data.map((row, index) => { const key = _.get(row, keyField); const editable = !(nonEditableRows.length > 0 && nonEditableRows.indexOf(key) > -1); - const selected = selectRow.mode !== Const.ROW_SELECT_DISABLED - ? selectedRowKeys.includes(key) - : null; - const attrs = rowEvents || {}; - let style = _.isFunction(rowStyle) ? rowStyle(row, index) : rowStyle; - let classes = (_.isFunction(rowClasses) ? rowClasses(row, index) : rowClasses); - if (selected) { - const selectedStyle = _.isFunction(selectRow.style) - ? selectRow.style(row, index) - : selectRow.style; + const style = _.isFunction(rowStyle) ? rowStyle(row, index) : rowStyle; + const classes = (_.isFunction(rowClasses) ? rowClasses(row, index) : rowClasses); - const selectedClasses = _.isFunction(selectRow.classes) - ? selectRow.classes(row, index) - : selectRow.classes; - - style = { - ...style, - ...selectedStyle - }; - classes = cs(classes, selectedClasses); - - if (bgColor) { - style = style || {}; - style.backgroundColor = _.isFunction(bgColor) ? bgColor(row, index) : bgColor; - } - } - - const selectable = !nonSelectable || !nonSelectable.includes(key); - const expandable = expandRow && !expandRow.nonExpandable.includes(key); - const expanded = expandRow && expandRow.expanded.includes(key); + // refine later + const expanded = expandRowEnabled && expandRow.expanded.includes(key); + // refine later const result = [ - + selectRowEnabled || expandRowEnabled ? + : + ]; if (expanded) { @@ -124,8 +111,7 @@ Body.propTypes = { keyField: PropTypes.string.isRequired, data: PropTypes.array.isRequired, columns: PropTypes.array.isRequired, - selectRow: PropTypes.object, - selectedRowKeys: PropTypes.array + selectRow: PropTypes.object }; export default Body; diff --git a/packages/react-bootstrap-table2/src/bootstrap-table.js b/packages/react-bootstrap-table2/src/bootstrap-table.js index b0d4779..aada564 100644 --- a/packages/react-bootstrap-table2/src/bootstrap-table.js +++ b/packages/react-bootstrap-table2/src/bootstrap-table.js @@ -9,7 +9,6 @@ import Caption from './caption'; import Body from './body'; import PropsBaseResolver from './props-resolver'; import Const from './const'; -import { getSelectionSummary } from './store/selection'; class BootstrapTable extends PropsBaseResolver(Component) { constructor(props) { @@ -56,7 +55,7 @@ class BootstrapTable extends PropsBaseResolver(Component) { rowClasses, wrapperClasses, rowEvents, - selected + selectRow } = this.props; const tableWrapperClass = cs('react-bootstrap-table', wrapperClasses); @@ -68,18 +67,6 @@ class BootstrapTable extends PropsBaseResolver(Component) { 'table-condensed': condensed }, classes); - const cellSelectionInfo = this.resolveSelectRowProps({ - onRowSelect: this.props.onRowSelect - }); - - const { allRowsSelected, allRowsNotSelected } = getSelectionSummary(data, keyField, selected); - const headerCellSelectionInfo = this.resolveSelectRowPropsForHeader({ - onAllRowsSelect: this.props.onAllRowsSelect, - selected, - allRowsSelected, - allRowsNotSelected - }); - const tableCaption = (caption && { caption }); const expandRow = this.resolveExpandRowProps(); @@ -95,7 +82,7 @@ class BootstrapTable extends PropsBaseResolver(Component) { onSort={ this.props.onSort } onFilter={ this.props.onFilter } onExternalFilter={ this.props.onExternalFilter } - selectRow={ headerCellSelectionInfo } + selectRow={ selectRow } expandRow={ expandRow } /> } if (props.selectRow) { - this.SelectionContext = createSelectionContext(dataOperator); + this.SelectionContext = SelectionContext; } if (props.expandRow) { @@ -62,13 +62,11 @@ const withContext = Base => searchProps, sortProps, paginationProps, - expandProps, - selectionProps + expandProps ) => ( this.table = n } { ...this.props } - { ...selectionProps } { ...sortProps } { ...cellEditProps } { ...filterProps } @@ -96,20 +94,17 @@ const withContext = Base => selectRow={ this.props.selectRow } data={ rootProps.getData(filterProps, searchProps, sortProps, paginationProps) } > - - { - selectionProps => base( - rootProps, - cellEditProps, - filterProps, - searchProps, - sortProps, - paginationProps, - expandProps, - selectionProps - ) - } - + { + base( + rootProps, + cellEditProps, + filterProps, + searchProps, + sortProps, + paginationProps, + expandProps + ) + } ); } diff --git a/packages/react-bootstrap-table2/src/contexts/selection-context.js b/packages/react-bootstrap-table2/src/contexts/selection-context.js index 12a7af8..964b704 100644 --- a/packages/react-bootstrap-table2/src/contexts/selection-context.js +++ b/packages/react-bootstrap-table2/src/contexts/selection-context.js @@ -3,113 +3,132 @@ import React from 'react'; import PropTypes from 'prop-types'; import Const from '../const'; -export default ( - dataOperator -) => { - const SelectionContext = React.createContext(); +import dataOperator from '../store/operators'; +import { getSelectionSummary } from '../store/selection'; - class SelectionProvider extends React.Component { - static propTypes = { - children: PropTypes.node.isRequired, - data: PropTypes.array.isRequired, - keyField: PropTypes.string.isRequired - } +const SelectionContext = React.createContext(); +class SelectionProvider extends React.Component { + static propTypes = { + children: PropTypes.node.isRequired, + data: PropTypes.array.isRequired, + keyField: PropTypes.string.isRequired + } - constructor(props) { - super(props); - if (props.registerExposedAPI) { - const getSelected = () => this.getSelected(); - props.registerExposedAPI(getSelected); - } - } - - state = { selected: (this.props.selectRow && this.props.selectRow.selected) || [] }; - - componentWillReceiveProps(nextProps) { - if (nextProps.selectRow) { - this.setState(() => ({ - selected: nextProps.selectRow.selected || this.state.selected - })); - } - } - - // exposed API - getSelected() { - return this.state.selected; - } - - handleRowSelect = (rowKey, checked, rowIndex, e) => { - const { data, keyField, selectRow: { mode, onSelect } } = this.props; - const { ROW_SELECT_SINGLE } = Const; - - let currSelected = [...this.state.selected]; - - if (mode === ROW_SELECT_SINGLE) { // when select mode is radio - currSelected = [rowKey]; - } else if (checked) { // when select mode is checkbox - currSelected.push(rowKey); - } else { - currSelected = currSelected.filter(value => value !== rowKey); - } - - if (onSelect) { - const row = dataOperator.getRowByRowId(data, keyField, rowKey); - onSelect(row, checked, rowIndex, e); - } - - this.setState(() => ({ selected: currSelected })); - } - - handleAllRowsSelect = (e, isUnSelect) => { - const { - data, - keyField, - selectRow: { - onSelectAll, - nonSelectable - } - } = this.props; - const { selected } = this.state; - - let currSelected; - - if (!isUnSelect) { - currSelected = selected.concat(dataOperator.selectableKeys(data, keyField, nonSelectable)); - } else { - currSelected = selected.filter(s => typeof data.find(d => d[keyField] === s) === 'undefined'); - } - - if (onSelectAll) { - onSelectAll( - !isUnSelect, - dataOperator.getSelectedRows( - data, - keyField, - isUnSelect ? this.state.selected : currSelected - ), - e - ); - } - - this.setState(() => ({ selected: currSelected })); - } - - render() { - return ( - - { this.props.children } - - ); + constructor(props) { + super(props); + if (props.registerExposedAPI) { + const getSelected = () => this.getSelected(); + props.registerExposedAPI(getSelected); } } - return { - Provider: SelectionProvider, - Consumer: SelectionContext.Consumer - }; + + state = { selected: (this.props.selectRow && this.props.selectRow.selected) || [] }; + + componentWillReceiveProps(nextProps) { + if (nextProps.selectRow) { + this.setState(() => ({ + selected: nextProps.selectRow.selected || this.state.selected + })); + } + } + + // exposed API + getSelected() { + return this.state.selected; + } + + handleRowSelect = (rowKey, checked, rowIndex, e) => { + const { data, keyField, selectRow: { mode, onSelect } } = this.props; + const { ROW_SELECT_SINGLE } = Const; + + let currSelected = [...this.state.selected]; + + if (mode === ROW_SELECT_SINGLE) { // when select mode is radio + currSelected = [rowKey]; + } else if (checked) { // when select mode is checkbox + currSelected.push(rowKey); + } else { + currSelected = currSelected.filter(value => value !== rowKey); + } + + if (onSelect) { + const row = dataOperator.getRowByRowId(data, keyField, rowKey); + onSelect(row, checked, rowIndex, e); + } + + this.setState(() => ({ selected: currSelected })); + } + + handleAllRowsSelect = (e, isUnSelect) => { + const { + data, + keyField, + selectRow: { + onSelectAll, + nonSelectable + } + } = this.props; + const { selected } = this.state; + + let currSelected; + + if (!isUnSelect) { + currSelected = selected.concat(dataOperator.selectableKeys(data, keyField, nonSelectable)); + } else { + currSelected = selected.filter(s => typeof data.find(d => d[keyField] === s) === 'undefined'); + } + + if (onSelectAll) { + onSelectAll( + !isUnSelect, + dataOperator.getSelectedRows( + data, + keyField, + isUnSelect ? this.state.selected : currSelected + ), + e + ); + } + + this.setState(() => ({ selected: currSelected })); + } + + render() { + const { + allRowsSelected, + allRowsNotSelected + } = getSelectionSummary( + this.props.data, + this.props.keyField, + this.state.selected + ); + + let checkedStatus; + + // checkbox status depending on selected rows counts + if (allRowsSelected) checkedStatus = Const.CHECKBOX_STATUS_CHECKED; + else if (allRowsNotSelected) checkedStatus = Const.CHECKBOX_STATUS_UNCHECKED; + else checkedStatus = Const.CHECKBOX_STATUS_INDETERMINATE; + + return ( + + { this.props.children } + + ); + } +} + +export default { + Provider: SelectionProvider, + Consumer: SelectionContext.Consumer }; diff --git a/packages/react-bootstrap-table2/src/header.js b/packages/react-bootstrap-table2/src/header.js index 4549343..9120c77 100644 --- a/packages/react-bootstrap-table2/src/header.js +++ b/packages/react-bootstrap-table2/src/header.js @@ -6,6 +6,7 @@ import Const from './const'; import HeaderCell from './header-cell'; import SelectionHeaderCell from './row-selection/selection-header-cell'; import ExpandHeaderCell from './row-expand/expand-header-cell'; +import bindSelection from './row-selection/selection-header-cell-binder'; const Header = (props) => { const { ROW_SELECT_DISABLED } = Const; @@ -23,6 +24,12 @@ const Header = (props) => { bootstrap4 } = props; + let SelectionHeaderCellComp = () => {}; + + if (selectRow) { + SelectionHeaderCellComp = bindSelection(SelectionHeaderCell); + } + return ( @@ -35,8 +42,8 @@ const Header = (props) => { /> : null } { - (selectRow.mode !== ROW_SELECT_DISABLED && !selectRow.hideSelectColumn) - ? : null + (selectRow.mode !== ROW_SELECT_DISABLED && !selectRow.hideSelectColumn) ? + : null } { columns.map((column, i) => { diff --git a/packages/react-bootstrap-table2/src/props-resolver/index.js b/packages/react-bootstrap-table2/src/props-resolver/index.js index 2154ce3..105c3ea 100644 --- a/packages/react-bootstrap-table2/src/props-resolver/index.js +++ b/packages/react-bootstrap-table2/src/props-resolver/index.js @@ -1,7 +1,5 @@ import ColumnResolver from './column-resolver'; import ExpandRowResolver from './expand-row-resolver'; -import Const from '../const'; -import _ from '../utils'; export default ExtendBase => class TableResolver extends @@ -19,63 +17,4 @@ export default ExtendBase => isEmpty() { return this.props.data.length === 0; } - - /** - * props resolver for cell selection - * @param {Object} options - addtional options like callback which are about to merge into props - * - * @returns {Object} result - props for cell selections - * @returns {String} result.mode - input type of row selection or disabled. - */ - resolveSelectRowProps(options) { - const { selectRow } = this.props; - const { ROW_SELECT_DISABLED } = Const; - - if (_.isDefined(selectRow)) { - return { - ...selectRow, - ...options - }; - } - - return { - mode: ROW_SELECT_DISABLED - }; - } - - /** - * props resolver for header cell selection - * @param {Object} options - addtional options like callback which are about to merge into props - * - * @returns {Object} result - props for cell selections - * @returns {String} result.mode - input type of row selection or disabled. - * @returns {String} result.checkedStatus - checkbox status depending on selected rows counts - */ - resolveSelectRowPropsForHeader(options = {}) { - const { selectRow } = this.props; - const { allRowsSelected, allRowsNotSelected, ...rest } = options; - const { - ROW_SELECT_DISABLED, CHECKBOX_STATUS_CHECKED, - CHECKBOX_STATUS_INDETERMINATE, CHECKBOX_STATUS_UNCHECKED - } = Const; - - if (_.isDefined(selectRow)) { - let checkedStatus; - - // checkbox status depending on selected rows counts - if (allRowsSelected) checkedStatus = CHECKBOX_STATUS_CHECKED; - else if (allRowsNotSelected) checkedStatus = CHECKBOX_STATUS_UNCHECKED; - else checkedStatus = CHECKBOX_STATUS_INDETERMINATE; - - return { - ...selectRow, - ...rest, - checkedStatus - }; - } - - return { - mode: ROW_SELECT_DISABLED - }; - } }; diff --git a/packages/react-bootstrap-table2/src/row-aggregator.js b/packages/react-bootstrap-table2/src/row-aggregator.js new file mode 100644 index 0000000..fc36355 --- /dev/null +++ b/packages/react-bootstrap-table2/src/row-aggregator.js @@ -0,0 +1,140 @@ +/* eslint react/prop-types: 0 */ +/* eslint react/no-array-index-key: 0 */ +import React from 'react'; +import PropTypes from 'prop-types'; +import _ from './utils'; +import Row from './row'; +import ExpandCell from './row-expand/expand-cell'; +import SelectionCell from './row-selection/selection-cell'; + +export default class RowAggregator extends React.Component { + static propTypes = { + attrs: PropTypes.object + } + static defaultProps = { + attrs: {} + } + + constructor(props) { + super(props); + this.clickNum = 0; + this.createClickEventHandler = this.createClickEventHandler.bind(this); + } + + createClickEventHandler(cb) { + return (e) => { + const { + row, + selected, + keyField, + selectable, + expandable, + rowIndex, + expanded, + expandRow, + selectRow, + cellEdit: { + mode, + DBCLICK_TO_CELL_EDIT, + DELAY_FOR_DBCLICK + } + } = this.props; + + const clickFn = () => { + if (cb) { + cb(e, row, rowIndex); + } + const key = _.get(row, keyField); + if (expandRow && expandable) { + expandRow.onRowExpand(key, !expanded, rowIndex, e); + } + if (selectable) { + selectRow.onRowSelect(key, !selected, rowIndex, e); + } + }; + + if (mode === DBCLICK_TO_CELL_EDIT && selectRow.clickToEdit) { + this.clickNum += 1; + _.debounce(() => { + if (this.clickNum === 1) { + clickFn(); + } + this.clickNum = 0; + }, DELAY_FOR_DBCLICK)(); + } else { + clickFn(); + } + }; + } + + render() { + const { + row, + columns, + keyField, + rowIndex, + style, + className, + attrs, + cellEdit, + selectRow, + expandRow, + selected, + selectable, + expandRowEnabled + } = this.props; + + const key = _.get(row, keyField); + const { hideSelectColumn } = selectRow; + const { showExpandColumn } = expandRow || {}; + + const nonEditableRows = cellEdit.nonEditableRows || []; + const editable = !(nonEditableRows.length > 0 && nonEditableRows.indexOf(key) > -1); + // const expandable = expandRowEnabled && !expandRow.nonExpandable.includes(key); + const expanded = expandRowEnabled && expandRow.expanded.includes(key); + + const newAttrs = { ...attrs }; + if (selectRow.clickToSelect || expandRowEnabled) { + newAttrs.onClick = this.createClickEventHandler(attrs.onClick); + } + + return ( + + { + showExpandColumn ? ( + + ) : null + } + { + !hideSelectColumn + ? ( + + ) + : null + } + + ); + } +} diff --git a/packages/react-bootstrap-table2/src/row-event-delegater.js b/packages/react-bootstrap-table2/src/row-event-delegater.js index ee62606..4727134 100644 --- a/packages/react-bootstrap-table2/src/row-event-delegater.js +++ b/packages/react-bootstrap-table2/src/row-event-delegater.js @@ -1,6 +1,3 @@ -import _ from './utils'; -import Const from './const'; - const events = [ 'onClick', 'onDoubleClick', @@ -15,7 +12,6 @@ export default ExtendBase => super(props); this.clickNum = 0; this.createDefaultEventHandler = this.createDefaultEventHandler.bind(this); - this.createClickEventHandler = this.createClickEventHandler.bind(this); } createDefaultEventHandler(cb) { @@ -25,65 +21,11 @@ export default ExtendBase => }; } - createClickEventHandler(cb) { - return (e) => { - const { - row, - selected, - keyField, - selectable, - expandable, - rowIndex, - expanded, - expandRow, - selectRow, - cellEdit: { - mode, - DBCLICK_TO_CELL_EDIT, - DELAY_FOR_DBCLICK - } - } = this.props; - - const clickFn = () => { - if (cb) { - cb(e, row, rowIndex); - } - const key = _.get(row, keyField); - if (expandRow && expandable) { - expandRow.onRowExpand(key, !expanded, rowIndex, e); - } - if (selectRow.mode !== Const.ROW_SELECT_DISABLED && selectable) { - selectRow.onRowSelect(key, !selected, rowIndex, e); - } - }; - - if (mode === DBCLICK_TO_CELL_EDIT && selectRow.clickToEdit) { - this.clickNum += 1; - _.debounce(() => { - if (this.clickNum === 1) { - clickFn(); - } - this.clickNum = 0; - }, DELAY_FOR_DBCLICK)(); - } else { - clickFn(); - } - }; - } - delegate(attrs = {}) { - const newAttrs = {}; - const { expandRow, selectRow } = this.props; - if (expandRow || (selectRow && selectRow.clickToSelect)) { - newAttrs.onClick = this.createClickEventHandler(attrs.onClick); - } + const newAttrs = { ...attrs }; Object.keys(attrs).forEach((attr) => { - if (!newAttrs[attr]) { - if (events.includes(attr)) { - newAttrs[attr] = this.createDefaultEventHandler(attrs[attr]); - } else { - newAttrs[attr] = attrs[attr]; - } + if (events.includes(attr)) { + newAttrs[attr] = this.createDefaultEventHandler(attrs[attr]); } }); return newAttrs; diff --git a/packages/react-bootstrap-table2/src/row-selection/row-binder.js b/packages/react-bootstrap-table2/src/row-selection/row-binder.js new file mode 100644 index 0000000..f0ad227 --- /dev/null +++ b/packages/react-bootstrap-table2/src/row-selection/row-binder.js @@ -0,0 +1,57 @@ +/* eslint react/prop-types: 0 */ +import React from 'react'; +import cs from 'classnames'; +import _ from '../utils'; +import SelectionContext from '../contexts/selection-context'; + +export default (Component) => { + const renderWithSelection = (props, selectRow) => { + const key = _.get(props.row, props.keyField); + const selected = selectRow.selected.includes(key); + const selectable = !selectRow.nonSelectable || !selectRow.nonSelectable.includes(key); + + let { + style, + className + } = props; + + if (selected) { + const selectedStyle = _.isFunction(selectRow.style) + ? selectRow.style(props.row, props.rowIndex) + : selectRow.style; + + const selectedClasses = _.isFunction(selectRow.classes) + ? selectRow.classes(props.row, props.rowIndex) + : selectRow.classes; + + style = { + ...style, + ...selectedStyle + }; + className = cs(className, selectedClasses); + + if (selectRow.bgColor) { + style = style || {}; + style.backgroundColor = _.isFunction(selectRow.bgColor) + ? selectRow.bgColor(props.row, props.rowIndex) + : selectRow.bgColor; + } + } + + return ( + + ); + }; + return props => ( + + { selectRow => renderWithSelection(props, selectRow) } + + ); +}; diff --git a/packages/react-bootstrap-table2/src/row-selection/selection-header-cell-binder.js b/packages/react-bootstrap-table2/src/row-selection/selection-header-cell-binder.js new file mode 100644 index 0000000..de7d3c3 --- /dev/null +++ b/packages/react-bootstrap-table2/src/row-selection/selection-header-cell-binder.js @@ -0,0 +1,8 @@ +import React from 'react'; +import SelectionContext from '../contexts/selection-context'; + +export default Component => () => ( + + { selectRow => } + +); diff --git a/packages/react-bootstrap-table2/src/row.js b/packages/react-bootstrap-table2/src/row.js index e3254b5..8de768f 100644 --- a/packages/react-bootstrap-table2/src/row.js +++ b/packages/react-bootstrap-table2/src/row.js @@ -5,10 +5,7 @@ import PropTypes from 'prop-types'; import _ from './utils'; import Cell from './cell'; -import SelectionCell from './row-selection/selection-cell'; -import ExpandCell from './row-expand/expand-cell'; import eventDelegater from './row-event-delegater'; -import Const from './const'; class Row extends eventDelegater(Component) { render() { @@ -21,11 +18,6 @@ class Row extends eventDelegater(Component) { style, attrs, cellEdit, - selected, - selectRow, - expanded, - expandRow, - selectable, editable: editableRow } = this.props; @@ -39,37 +31,11 @@ class Row extends eventDelegater(Component) { DBCLICK_TO_CELL_EDIT, ...rest } = cellEdit; - - const key = _.get(row, keyField); - const { hideSelectColumn } = selectRow; - const { showExpandColumn } = expandRow || {}; const trAttrs = this.delegate(attrs); return ( - { - showExpandColumn ? ( - - ) : null - } - { - (selectRow.mode !== Const.ROW_SELECT_DISABLED && !hideSelectColumn) - ? ( - - ) - : null - } + { this.props.children } { columns.map((column, index) => { if (!column.hidden) {