11import looseEqual from '../../../utils/loose-equal'
2+ import range from '../../../utils/range'
23import { isArray , arrayIncludes } from '../../../utils/array'
34import { getComponentConfig } from '../../../utils/config'
5+ import { isNumber } from '../../../utils/inspect'
46import sanitizeRow from './sanitize-row'
57
68export default {
@@ -11,7 +13,8 @@ export default {
1113 } ,
1214 selectMode : {
1315 type : String ,
14- default : 'multi'
16+ default : 'multi' ,
17+ validator : val => arrayIncludes ( [ 'range' , 'multi' , 'single' ] , val )
1518 } ,
1619 selectedVariant : {
1720 type : String ,
@@ -25,36 +28,42 @@ export default {
2528 }
2629 } ,
2730 computed : {
31+ isSelectable ( ) {
32+ return this . selectable && this . selectMode
33+ } ,
34+ selectableHasSelection ( ) {
35+ return (
36+ this . isSelectable &&
37+ this . selectedRows &&
38+ this . selectedRows . length > 0 &&
39+ this . selectedRows . some ( Boolean )
40+ )
41+ } ,
42+ selectableIsMultiSelect ( ) {
43+ return this . isSelectable && arrayIncludes ( [ 'range' , 'multi' ] , this . selectMode )
44+ } ,
2845 selectableTableClasses ( ) {
29- const selectable = this . selectable
30- const isSelecting = selectable && this . selectedRows && this . selectedRows . some ( Boolean )
3146 return {
32- 'b-table-selectable' : selectable ,
33- [ `b-table-select-${ this . selectMode } ` ] : selectable ,
34- 'b-table-selecting' : isSelecting
47+ 'b-table-selectable' : this . isSelectable ,
48+ [ `b-table-select-${ this . selectMode } ` ] : this . isSelectable ,
49+ 'b-table-selecting' : this . selectableHasSelection
3550 }
3651 } ,
3752 selectableTableAttrs ( ) {
3853 return {
39- 'aria-multiselectable' : this . selectableIsMultiSelect
40- }
41- } ,
42- selectableIsMultiSelect ( ) {
43- if ( this . selectable ) {
44- return arrayIncludes ( [ 'range' , 'multi' ] , this . selectMode ) ? 'true' : 'false'
45- } else {
46- return null
54+ 'aria-multiselectable' : ! this . isSelectable
55+ ? null
56+ : this . selectableIsMultiSelect
57+ ? 'true'
58+ : 'false'
4759 }
4860 }
4961 } ,
5062 watch : {
5163 computedItems ( newVal , oldVal ) {
5264 // Reset for selectable
53- // TODO: Should selectedLastClicked be reset here?
54- // As changes to _showDetails would trigger it to reset
55- this . selectedLastRow = - 1
5665 let equal = false
57- if ( this . selectable && this . selectedRows . length > 0 ) {
66+ if ( this . isSelectable && this . selectedRows . length > 0 ) {
5867 // Quick check against array length
5968 equal = isArray ( newVal ) && isArray ( oldVal ) && newVal . length === oldVal . length
6069 for ( let i = 0 ; equal && i < newVal . length ; i ++ ) {
@@ -74,9 +83,9 @@ export default {
7483 this . clearSelected ( )
7584 } ,
7685 selectedRows ( selectedRows , oldVal ) {
77- if ( this . selectable && ! looseEqual ( selectedRows , oldVal ) ) {
86+ if ( this . isSelectable && ! looseEqual ( selectedRows , oldVal ) ) {
7887 const items = [ ]
79- // forEach skips over non-existant indicies (on sparse arrays)
88+ // `. forEach()` skips over non-existent indices (on sparse arrays)
8089 selectedRows . forEach ( ( v , idx ) => {
8190 if ( v ) {
8291 items . push ( this . computedItems [ idx ] )
@@ -88,35 +97,67 @@ export default {
8897 } ,
8998 beforeMount ( ) {
9099 // Set up handlers
91- if ( this . selectable ) {
100+ if ( this . isSelectable ) {
92101 this . setSelectionHandlers ( true )
93102 }
94103 } ,
95104 methods : {
96- isRowSelected ( idx ) {
97- return Boolean ( this . selectedRows [ idx ] )
105+ // Public methods
106+ selectRow ( index ) {
107+ // Select a particular row (indexed based on computedItems)
108+ if (
109+ this . isSelectable &&
110+ isNumber ( index ) &&
111+ index >= 0 &&
112+ index < this . computedItems . length &&
113+ ! this . isRowSelected ( index )
114+ ) {
115+ const selectedRows = this . selectableIsMultiSelect ? this . selectedRows . slice ( ) : [ ]
116+ selectedRows [ index ] = true
117+ this . selectedLastClicked = - 1
118+ this . selectedRows = selectedRows
119+ }
98120 } ,
99- selectableRowClasses ( idx ) {
100- const rowSelected = this . isRowSelected ( idx )
101- const base = this . dark ? 'bg' : 'table'
102- const variant = this . selectedVariant
103- return {
104- 'b-table-row-selected' : this . selectable && rowSelected ,
105- [ ` ${ base } - ${ variant } ` ] : this . selectable && rowSelected && variant
121+ unselectRow ( index ) {
122+ // Un-select a particular row (indexed based on `computedItems` )
123+ if ( this . isSelectable && isNumber ( index ) && this . isRowSelected ( index ) ) {
124+ const selectedRows = this . selectedRows . slice ( )
125+ selectedRows [ index ] = false
126+ this . selectedLastClicked = - 1
127+ this . selectedRows = selectedRows
106128 }
107129 } ,
108- selectableRowAttrs ( idx ) {
109- return {
110- 'aria-selected' : ! this . selectable ? null : this . isRowSelected ( idx ) ? 'true' : 'false'
130+ selectAllRows ( ) {
131+ const length = this . computedItems . length
132+ if ( this . isSelectable && length > 0 ) {
133+ this . selectedLastClicked = - 1
134+ this . selectedRows = this . selectableIsMultiSelect ? range ( length ) . map ( i => true ) : [ true ]
111135 }
112136 } ,
137+ isRowSelected ( index ) {
138+ // Determine if a row is selected (indexed based on `computedItems`)
139+ return Boolean ( isNumber ( index ) && this . selectedRows [ index ] )
140+ } ,
113141 clearSelected ( ) {
114- const hasSelection = this . selectedRows . reduce ( ( prev , v ) => {
115- return prev || v
116- } , false )
117- if ( hasSelection ) {
118- this . selectedLastClicked = - 1
119- this . selectedRows = [ ]
142+ // Clear any active selected row(s)
143+ this . selectedLastClicked = - 1
144+ this . selectedRows = [ ]
145+ } ,
146+ // Internal private methods
147+ selectableRowClasses ( index ) {
148+ if ( this . isSelectable && this . isRowSelected ( index ) ) {
149+ const variant = this . selectedVariant
150+ return {
151+ 'b-table-row-selected' : true ,
152+ [ `${ this . dark ? 'bg' : 'table' } -${ variant } ` ] : variant
153+ }
154+ } else {
155+ return { }
156+ }
157+ } ,
158+ selectableRowAttrs ( index ) {
159+ return {
160+ 'aria-selected' : ! this . isSelectable ? null : this . isRowSelected ( index ) ? 'true' : 'false'
120161 }
121162 } ,
122163 setSelectionHandlers ( on ) {
@@ -129,20 +170,20 @@ export default {
129170 } ,
130171 selectionHandler ( item , index , evt ) {
131172 /* istanbul ignore if: should never happen */
132- if ( ! this . selectable ) {
173+ if ( ! this . isSelectable ) {
133174 // Don't do anything if table is not in selectable mode
134175 /* istanbul ignore next: should never happen */
135176 this . clearSelected ( )
136177 /* istanbul ignore next: should never happen */
137178 return
138179 }
180+ const selectMode = this . selectMode
139181 let selectedRows = this . selectedRows . slice ( )
140182 let selected = ! selectedRows [ index ]
141- const mode = this . selectMode
142- // Note 'multi' mode needs no special handling
143- if ( mode === 'single' ) {
183+ // Note 'multi' mode needs no special event handling
184+ if ( selectMode === 'single' ) {
144185 selectedRows = [ ]
145- } else if ( mode === 'range' ) {
186+ } else if ( selectMode === 'range' ) {
146187 if ( this . selectedLastRow > - 1 && evt . shiftKey ) {
147188 // range
148189 for (
@@ -155,7 +196,7 @@ export default {
155196 selected = true
156197 } else {
157198 if ( ! ( evt . ctrlKey || evt . metaKey ) ) {
158- // clear range selection if any
199+ // Clear range selection if any
159200 selectedRows = [ ]
160201 selected = true
161202 }
0 commit comments