From 01032d46b592f1f4fe277687181b4f3a1b746c1f Mon Sep 17 00:00:00 2001 From: Aaron Meese Date: Mon, 8 Aug 2022 15:22:38 -0400 Subject: [PATCH 1/6] Added multiselect to ListView --- src/components/ListView.js | 106 ++++++++++++++++++++++++++++++------- 1 file changed, 86 insertions(+), 20 deletions(-) diff --git a/src/components/ListView.js b/src/components/ListView.js index ebb8bf0..34e5201 100644 --- a/src/components/ListView.js +++ b/src/components/ListView.js @@ -40,9 +40,11 @@ const createView = props => { const cols = (paneIndex) => (row, rowIndex) => { const col = row.columns[paneIndex] || {}; - const selected = props.selectedIndex === rowIndex; const colIcon = col.icon ? h(Icon, col.icon) : null; const children = [h('span', {}, [typeof col === 'object' ? col.label : col])]; + const selected = props.multiselect + ? props.selectedIndex.indexOf(rowIndex) !== -1 + : props.selectedIndex === rowIndex; if (colIcon) { children.unshift(colIcon); @@ -52,11 +54,11 @@ const createView = props => { key: row.key, 'data-has-icon': col.icon ? true : undefined, class: 'osjs-gui-list-view-cell' + (selected ? ' osjs__active' : ''), - ontouchstart: (ev) => tapper(ev, () => props.onactivate({data: row.data, index: rowIndex, ev})), - ondblclick: (ev) => props.onactivate({data: row.data, index: rowIndex, ev}), - onclick: (ev) => props.onselect({data: row.data, index: rowIndex, ev}), - oncontextmenu: (ev) => props.oncontextmenu({data: row.data, index: rowIndex, ev}), - oncreate: (el) => props.oncreate({data: row.data, index: rowIndex, el}) + ontouchstart: (ev) => tapper(ev, () => props.onactivate({index: rowIndex, ev})), + ondblclick: (ev) => props.onactivate({index: rowIndex, ev}), + onclick: (ev) => props.onselect({index: rowIndex, ev}), + oncontextmenu: (ev) => props.oncontextmenu({index: rowIndex, ev}), + oncreate: (el) => props.oncreate({index: rowIndex, el}) }, children); }; @@ -86,7 +88,11 @@ const createView = props => { }, oncreate: el => (el.scrollTop = props.scrollTop), onupdate: el => { - if (props.selectedIndex < 0) { + const notSelected = props.multiselect + ? props.selectedIndex.length === 0 + : props.selectedIndex < 0; + + if (notSelected) { el.scrollTop = props.scrollTop; } } @@ -99,25 +105,85 @@ export const ListView = props => h(Element, Object.assign({ export const listView = ({ component: (state, actions) => { + // TODO: Ability to deselect with control and shift key + const createSelection = (index) => state.selectedIndex.indexOf(index) === -1 + ? [...state.selectedIndex, index] + : state.selectedIndex; + + /** + * Creates a range of indexes from start to end + * @param {Number} start + * @param {Number} end + * @return {Array} + */ + const createSelectionRange = (start, end) => { + // Swaps start and end if start is greater than end + if (start > end) [start, end] = [end, start]; + + const indices = [ + ...state.selectedIndex, + // Generates a range of indexes from start to end + ...Array.from({ length: end - start + 1 }, (_, i) => i + start) + ]; + + // Remove duplicates from the array + return [...new Set(indices)]; + } + + const getSelection = (index, ev) => { + const selected = state.multiselect + ? (ev.shiftKey + ? createSelectionRange(state.previousSelectedIndex, index) + : ev.ctrlKey + ? createSelection(index) + : [index]) + : index; + + const data = state.multiselect + ? selected.map((item) => state.rows[item].data) + : state.rows[selected].data; + + // Store the previous index in the state to use for calculating the + // range if the shift key is pressed + if (state.multiselect) state.previousSelectedIndex = index; + return { selected, data }; + }; + + const clearCurrentSelection = (index) => { + const selected = state.multiselect ? [] : -1; + + const data = state.multiselect + ? state.selectedIndex.map((item) => state.rows[item].data) + : state.rows[index].data; + + return { selected, data }; + }; + const newProps = Object.assign({ + multiselect: false, zebra: true, columns: [], rows: [], - onselect: ({data, index, ev}) => { - actions.select({data, index, ev}); - actions.setSelectedIndex(index); + onselect: ({index, ev}) => { + const {selected, data} = getSelection(index, ev); + actions.select({data, index, ev, selected}); + actions.setSelectedIndex(selected); }, - onactivate: ({data, index, ev}) => { - actions.activate({data, index, ev}); - actions.setSelectedIndex(-1); + onactivate: ({index, ev}) => { + const {selected, data} = clearCurrentSelection(index); + actions.activate({data, index, ev, selected}); + actions.setSelectedIndex(selected); }, - oncontextmenu: ({data, index, ev}) => { + oncontextmenu: ({index, ev}) => { + const {selected, data} = getSelection(index, ev); + actions.select({data, index, ev}); - actions.contextmenu({data, index, ev}); - actions.setSelectedIndex(index); + actions.contextmenu({data, index, ev, selected}); + actions.setSelectedIndex(selected); }, - oncreate: (args) => { - actions.created(args); + oncreate: ({index, el}) => { + const data = state.rows[index].data; + actions.created({index, el, data}); }, onscroll: (ev) => { actions.scroll(ev); @@ -128,7 +194,7 @@ export const listView = ({ }, state: state => Object.assign({ - selectedIndex: -1, + selectedIndex: state.multiselect ? [] : -1, scrollTop: 0 }, state), @@ -141,6 +207,6 @@ export const listView = ({ setRows: rows => ({rows}), setColumns: columns => ({columns}), setScrollTop: scrollTop => state => ({scrollTop}), - setSelectedIndex: selectedIndex => state => ({selectedIndex}) + setSelectedIndex: selectedIndex => ({selectedIndex}), }, actions || {}) }); From d081b803ce729452ff81e4c8967befb58f798613 Mon Sep 17 00:00:00 2001 From: Aaron Meese Date: Tue, 9 Aug 2022 18:36:47 -0400 Subject: [PATCH 2/6] Resolved eslint errors --- src/components/ListView.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/components/ListView.js b/src/components/ListView.js index 34e5201..0936138 100644 --- a/src/components/ListView.js +++ b/src/components/ListView.js @@ -118,12 +118,14 @@ export const listView = ({ */ const createSelectionRange = (start, end) => { // Swaps start and end if start is greater than end - if (start > end) [start, end] = [end, start]; + if (start > end) { + [start, end] = [end, start]; + } const indices = [ ...state.selectedIndex, // Generates a range of indexes from start to end - ...Array.from({ length: end - start + 1 }, (_, i) => i + start) + ...Array.from({length: end - start + 1}, (_, i) => i + start) ]; // Remove duplicates from the array @@ -145,8 +147,11 @@ export const listView = ({ // Store the previous index in the state to use for calculating the // range if the shift key is pressed - if (state.multiselect) state.previousSelectedIndex = index; - return { selected, data }; + if (state.multiselect) { + state.previousSelectedIndex = index; + } + + return {selected, data}; }; const clearCurrentSelection = (index) => { @@ -156,7 +161,7 @@ export const listView = ({ ? state.selectedIndex.map((item) => state.rows[item].data) : state.rows[index].data; - return { selected, data }; + return {selected, data}; }; const newProps = Object.assign({ From ac72abbdfa3f86d29c1fa1d7e2829f248492b444 Mon Sep 17 00:00:00 2001 From: Aaron Meese Date: Tue, 9 Aug 2022 18:40:25 -0400 Subject: [PATCH 3/6] Added semicolon --- src/components/ListView.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ListView.js b/src/components/ListView.js index 0936138..25d0108 100644 --- a/src/components/ListView.js +++ b/src/components/ListView.js @@ -130,7 +130,7 @@ export const listView = ({ // Remove duplicates from the array return [...new Set(indices)]; - } + }; const getSelection = (index, ev) => { const selected = state.multiselect From ca220fa331188ad9ead34a2e4e3582a746ccb144 Mon Sep 17 00:00:00 2001 From: Aaron Meese Date: Wed, 10 Aug 2022 15:29:44 -0400 Subject: [PATCH 4/6] Transition away from direct state manipulation --- src/components/ListView.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/ListView.js b/src/components/ListView.js index 25d0108..c85d0ca 100644 --- a/src/components/ListView.js +++ b/src/components/ListView.js @@ -148,7 +148,7 @@ export const listView = ({ // Store the previous index in the state to use for calculating the // range if the shift key is pressed if (state.multiselect) { - state.previousSelectedIndex = index; + actions.setPreviousSelectedIndex(index); } return {selected, data}; @@ -213,5 +213,6 @@ export const listView = ({ setColumns: columns => ({columns}), setScrollTop: scrollTop => state => ({scrollTop}), setSelectedIndex: selectedIndex => ({selectedIndex}), + setPreviousSelectedIndex: previousSelectedIndex => ({previousSelectedIndex}), }, actions || {}) }); From b907425ea8b2466f1330e1c7783e968914f36056 Mon Sep 17 00:00:00 2001 From: Aaron Meese Date: Wed, 10 Aug 2022 18:11:23 -0400 Subject: [PATCH 5/6] Resolved deselection TODO --- src/components/ListView.js | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/components/ListView.js b/src/components/ListView.js index c85d0ca..0d12853 100644 --- a/src/components/ListView.js +++ b/src/components/ListView.js @@ -105,10 +105,21 @@ export const ListView = props => h(Element, Object.assign({ export const listView = ({ component: (state, actions) => { - // TODO: Ability to deselect with control and shift key - const createSelection = (index) => state.selectedIndex.indexOf(index) === -1 - ? [...state.selectedIndex, index] - : state.selectedIndex; + const createSelection = index => { + if (state.multiselect) { + const foundIndex = state.selectedIndex.indexOf(index); + const newSelection = [...state.selectedIndex]; + if (foundIndex === -1) { + newSelection.push(index); + } else { + newSelection.splice(foundIndex, 1); + } + + return newSelection; + } + + return state.selectedIndex; + } /** * Creates a range of indexes from start to end From e74945b96c2a3b6ba1bf58d5ea5bfc0ba724d5c1 Mon Sep 17 00:00:00 2001 From: Aaron Meese Date: Wed, 10 Aug 2022 18:16:40 -0400 Subject: [PATCH 6/6] Semicolon added to resolve eslint error --- src/components/ListView.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ListView.js b/src/components/ListView.js index 0d12853..a7fd226 100644 --- a/src/components/ListView.js +++ b/src/components/ListView.js @@ -119,7 +119,7 @@ export const listView = ({ } return state.selectedIndex; - } + }; /** * Creates a range of indexes from start to end