@@ -40,9 +40,11 @@ const createView = props => {
4040
4141 const cols = ( paneIndex ) => ( row , rowIndex ) => {
4242 const col = row . columns [ paneIndex ] || { } ;
43- const selected = props . selectedIndex === rowIndex ;
4443 const colIcon = col . icon ? h ( Icon , col . icon ) : null ;
4544 const children = [ h ( 'span' , { } , [ typeof col === 'object' ? col . label : col ] ) ] ;
45+ const selected = props . multiselect
46+ ? props . selectedIndex . indexOf ( rowIndex ) !== - 1
47+ : props . selectedIndex === rowIndex ;
4648
4749 if ( colIcon ) {
4850 children . unshift ( colIcon ) ;
@@ -52,11 +54,11 @@ const createView = props => {
5254 key : row . key ,
5355 'data-has-icon' : col . icon ? true : undefined ,
5456 class : 'osjs-gui-list-view-cell' + ( selected ? ' osjs__active' : '' ) ,
55- ontouchstart : ( ev ) => tapper ( ev , ( ) => props . onactivate ( { data : row . data , index : rowIndex , ev} ) ) ,
56- ondblclick : ( ev ) => props . onactivate ( { data : row . data , index : rowIndex , ev} ) ,
57- onclick : ( ev ) => props . onselect ( { data : row . data , index : rowIndex , ev} ) ,
58- oncontextmenu : ( ev ) => props . oncontextmenu ( { data : row . data , index : rowIndex , ev} ) ,
59- oncreate : ( el ) => props . oncreate ( { data : row . data , index : rowIndex , el} )
57+ ontouchstart : ( ev ) => tapper ( ev , ( ) => props . onactivate ( { index : rowIndex , ev} ) ) ,
58+ ondblclick : ( ev ) => props . onactivate ( { index : rowIndex , ev} ) ,
59+ onclick : ( ev ) => props . onselect ( { index : rowIndex , ev} ) ,
60+ oncontextmenu : ( ev ) => props . oncontextmenu ( { index : rowIndex , ev} ) ,
61+ oncreate : ( el ) => props . oncreate ( { index : rowIndex , el} )
6062 } , children ) ;
6163 } ;
6264
@@ -86,7 +88,11 @@ const createView = props => {
8688 } ,
8789 oncreate : el => ( el . scrollTop = props . scrollTop ) ,
8890 onupdate : el => {
89- if ( props . selectedIndex < 0 ) {
91+ const notSelected = props . multiselect
92+ ? props . selectedIndex . length === 0
93+ : props . selectedIndex < 0 ;
94+
95+ if ( notSelected ) {
9096 el . scrollTop = props . scrollTop ;
9197 }
9298 }
@@ -99,25 +105,101 @@ export const ListView = props => h(Element, Object.assign({
99105
100106export const listView = ( {
101107 component : ( state , actions ) => {
108+ const createSelection = index => {
109+ if ( state . multiselect ) {
110+ const foundIndex = state . selectedIndex . indexOf ( index ) ;
111+ const newSelection = [ ...state . selectedIndex ] ;
112+ if ( foundIndex === - 1 ) {
113+ newSelection . push ( index ) ;
114+ } else {
115+ newSelection . splice ( foundIndex , 1 ) ;
116+ }
117+
118+ return newSelection ;
119+ }
120+
121+ return state . selectedIndex ;
122+ } ;
123+
124+ /**
125+ * Creates a range of indexes from start to end
126+ * @param {Number } start
127+ * @param {Number } end
128+ * @return {Array }
129+ */
130+ const createSelectionRange = ( start , end ) => {
131+ // Swaps start and end if start is greater than end
132+ if ( start > end ) {
133+ [ start , end ] = [ end , start ] ;
134+ }
135+
136+ const indices = [
137+ ...state . selectedIndex ,
138+ // Generates a range of indexes from start to end
139+ ...Array . from ( { length : end - start + 1 } , ( _ , i ) => i + start )
140+ ] ;
141+
142+ // Remove duplicates from the array
143+ return [ ...new Set ( indices ) ] ;
144+ } ;
145+
146+ const getSelection = ( index , ev ) => {
147+ const selected = state . multiselect
148+ ? ( ev . shiftKey
149+ ? createSelectionRange ( state . previousSelectedIndex , index )
150+ : ev . ctrlKey
151+ ? createSelection ( index )
152+ : [ index ] )
153+ : index ;
154+
155+ const data = state . multiselect
156+ ? selected . map ( ( item ) => state . rows [ item ] . data )
157+ : state . rows [ selected ] . data ;
158+
159+ // Store the previous index in the state to use for calculating the
160+ // range if the shift key is pressed
161+ if ( state . multiselect ) {
162+ actions . setPreviousSelectedIndex ( index ) ;
163+ }
164+
165+ return { selected, data} ;
166+ } ;
167+
168+ const clearCurrentSelection = ( index ) => {
169+ const selected = state . multiselect ? [ ] : - 1 ;
170+
171+ const data = state . multiselect
172+ ? state . selectedIndex . map ( ( item ) => state . rows [ item ] . data )
173+ : state . rows [ index ] . data ;
174+
175+ return { selected, data} ;
176+ } ;
177+
102178 const newProps = Object . assign ( {
179+ multiselect : false ,
103180 zebra : true ,
104181 columns : [ ] ,
105182 rows : [ ] ,
106- onselect : ( { data, index, ev} ) => {
107- actions . select ( { data, index, ev} ) ;
108- actions . setSelectedIndex ( index ) ;
183+ onselect : ( { index, ev} ) => {
184+ const { selected, data} = getSelection ( index , ev ) ;
185+ actions . select ( { data, index, ev, selected} ) ;
186+ actions . setSelectedIndex ( selected ) ;
109187 } ,
110- onactivate : ( { data, index, ev} ) => {
111- actions . activate ( { data, index, ev} ) ;
112- actions . setSelectedIndex ( - 1 ) ;
188+ onactivate : ( { index, ev} ) => {
189+ const { selected, data} = clearCurrentSelection ( index ) ;
190+ actions . activate ( { data, index, ev, selected} ) ;
191+ actions . setSelectedIndex ( selected ) ;
113192 } ,
114- oncontextmenu : ( { data, index, ev} ) => {
193+ oncontextmenu : ( { index, ev} ) => {
194+ const { selected, data} = getSelection ( index , ev ) ;
195+
115196 actions . select ( { data, index, ev} ) ;
116- actions . contextmenu ( { data, index, ev} ) ;
117- actions . setSelectedIndex ( index ) ;
197+ actions . contextmenu ( { data, index, ev, selected } ) ;
198+ actions . setSelectedIndex ( selected ) ;
118199 } ,
119- oncreate : ( args ) => {
120- actions . created ( args ) ;
200+ oncreate : ( { index, el} ) => {
201+ const data = state . rows [ index ] . data ;
202+ actions . created ( { index, el, data} ) ;
121203 } ,
122204 onscroll : ( ev ) => {
123205 actions . scroll ( ev ) ;
@@ -128,7 +210,7 @@ export const listView = ({
128210 } ,
129211
130212 state : state => Object . assign ( {
131- selectedIndex : - 1 ,
213+ selectedIndex : state . multiselect ? [ ] : - 1 ,
132214 scrollTop : 0
133215 } , state ) ,
134216
@@ -141,6 +223,7 @@ export const listView = ({
141223 setRows : rows => ( { rows} ) ,
142224 setColumns : columns => ( { columns} ) ,
143225 setScrollTop : scrollTop => state => ( { scrollTop} ) ,
144- setSelectedIndex : selectedIndex => state => ( { selectedIndex} )
226+ setSelectedIndex : selectedIndex => ( { selectedIndex} ) ,
227+ setPreviousSelectedIndex : previousSelectedIndex => ( { previousSelectedIndex} ) ,
145228 } , actions || { } )
146229} ) ;
0 commit comments