From 50e18300545a97e61e6de6fbf19b53820ea15248 Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Thu, 30 May 2019 15:25:33 -0400 Subject: [PATCH 1/3] Block Editor: Maintain selection when multi-selection toggled --- packages/block-editor/src/store/reducer.js | 2 +- .../block-editor/src/store/test/reducer.js | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/packages/block-editor/src/store/reducer.js b/packages/block-editor/src/store/reducer.js index d9d0ecbdd28b64..58646e592d38c1 100644 --- a/packages/block-editor/src/store/reducer.js +++ b/packages/block-editor/src/store/reducer.js @@ -809,7 +809,7 @@ export function blockSelection( state = BLOCK_SELECTION_INITIAL_STATE, action ) } case 'TOGGLE_SELECTION': return { - ...BLOCK_SELECTION_INITIAL_STATE, + ...state, isEnabled: action.isSelectionEnabled, }; case 'SELECTION_CHANGE': diff --git a/packages/block-editor/src/store/test/reducer.js b/packages/block-editor/src/store/test/reducer.js index 7543fdad57dd8b..0cd6aef0481c61 100644 --- a/packages/block-editor/src/store/test/reducer.js +++ b/packages/block-editor/src/store/test/reducer.js @@ -1727,6 +1727,24 @@ describe( 'state', () => { expect( state1 ).toBe( original ); } ); + it( 'should maintain selection when toggling multi-selection', () => { + const original = deepFreeze( { + start: { clientId: 'ribs' }, + end: { clientId: 'ribs' }, + } ); + + const state = blockSelection( original, { + type: 'TOGGLE_SELECTION', + isSelectionEnabled: false, + } ); + + expect( state ).toEqual( { + start: { clientId: 'ribs' }, + end: { clientId: 'ribs' }, + isEnabled: false, + } ); + } ); + it( 'should unset multi selection', () => { const original = deepFreeze( { start: { clientId: 'ribs' }, end: { clientId: 'chicken' } } ); From 81e04f3cba02298768c32071e219ad936a1b5d4a Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Mon, 1 Jul 2019 14:17:40 -0400 Subject: [PATCH 2/3] Block Editor: Cancel multi-selecting state when toggling multi-selection --- packages/block-editor/src/store/reducer.js | 3 ++ .../block-editor/src/store/test/reducer.js | 44 +++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/packages/block-editor/src/store/reducer.js b/packages/block-editor/src/store/reducer.js index 58646e592d38c1..5972ab8006797f 100644 --- a/packages/block-editor/src/store/reducer.js +++ b/packages/block-editor/src/store/reducer.js @@ -811,6 +811,9 @@ export function blockSelection( state = BLOCK_SELECTION_INITIAL_STATE, action ) return { ...state, isEnabled: action.isSelectionEnabled, + isMultiSelecting: action.isSelectionEnabled ? + state.isMultiSelecting : + false, }; case 'SELECTION_CHANGE': return { diff --git a/packages/block-editor/src/store/test/reducer.js b/packages/block-editor/src/store/test/reducer.js index 0cd6aef0481c61..9ab02b1714c4b3 100644 --- a/packages/block-editor/src/store/test/reducer.js +++ b/packages/block-editor/src/store/test/reducer.js @@ -1731,6 +1731,27 @@ describe( 'state', () => { const original = deepFreeze( { start: { clientId: 'ribs' }, end: { clientId: 'ribs' }, + isMultiSelecting: false, + } ); + + const state = blockSelection( original, { + type: 'TOGGLE_SELECTION', + isSelectionEnabled: false, + } ); + + expect( state ).toEqual( { + start: { clientId: 'ribs' }, + end: { clientId: 'ribs' }, + isMultiSelecting: false, + isEnabled: false, + } ); + } ); + + it( 'should cancel multi-selection when disabling multi-selection', () => { + const original = deepFreeze( { + start: { clientId: 'ribs' }, + end: { clientId: 'ribs' }, + isMultiSelecting: true, } ); const state = blockSelection( original, { @@ -1742,6 +1763,29 @@ describe( 'state', () => { start: { clientId: 'ribs' }, end: { clientId: 'ribs' }, isEnabled: false, + isMultiSelecting: false, + } ); + } ); + + it( 'should preserve multi-selection when enabling multi-selection', () => { + [ true, false ].forEach( ( isMultiSelecting ) => { + const original = deepFreeze( { + start: { clientId: 'ribs' }, + end: { clientId: 'ribs' }, + isMultiSelecting, + } ); + + const state = blockSelection( original, { + type: 'TOGGLE_SELECTION', + isSelectionEnabled: true, + } ); + + expect( state ).toEqual( { + start: { clientId: 'ribs' }, + end: { clientId: 'ribs' }, + isEnabled: true, + isMultiSelecting, + } ); } ); } ); From 0be9feabe4b80fda369ffe6917358832794ed2e5 Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Mon, 1 Jul 2019 14:17:55 -0400 Subject: [PATCH 3/3] Block Editor: Document block selection state object --- packages/block-editor/src/store/reducer.js | 25 ++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/packages/block-editor/src/store/reducer.js b/packages/block-editor/src/store/reducer.js index 5972ab8006797f..06cb9c80deadf3 100644 --- a/packages/block-editor/src/store/reducer.js +++ b/packages/block-editor/src/store/reducer.js @@ -699,6 +699,27 @@ export function isCaretWithinFormattedText( state = false, action ) { } const BLOCK_SELECTION_EMPTY_OBJECT = {}; + +/** + * Initial state object for block selection. + * + * @property {Object} start Block anchor from which the selection + * begins. + * @property {Object} end Block extent to which the selection + * ends. + * @property {boolean} isMultiSelecting Flag representing whether a multi- + * selection interaction is in progress. + * @property {boolean} isEnabled Flag representing whether multi- + * selection is currently allowed. + * @property {number?} initialPosition For a changed selection, the position + * at which the caret should be placed. + * Either null (default position) or -1 + * (at the end of the block). + * + * @typedef {WPBlockSelectionState} + * + * @type {Object} + */ const BLOCK_SELECTION_INITIAL_STATE = { start: BLOCK_SELECTION_EMPTY_OBJECT, end: BLOCK_SELECTION_EMPTY_OBJECT, @@ -710,10 +731,10 @@ const BLOCK_SELECTION_INITIAL_STATE = { /** * Reducer returning the block selection's state. * - * @param {Object} state Current state. + * @param {WPBlockSelectionState} state Current state. * @param {Object} action Dispatched action. * - * @return {Object} Updated state. + * @return {WPBlockSelectionState} Updated state. */ export function blockSelection( state = BLOCK_SELECTION_INITIAL_STATE, action ) { switch ( action.type ) {