Skip to content

Commit

Permalink
Move selection within blocks reducer
Browse files Browse the repository at this point in the history
  • Loading branch information
ellatrix committed Jul 5, 2019
1 parent 21e2dce commit 7315f25
Show file tree
Hide file tree
Showing 5 changed files with 303 additions and 249 deletions.
278 changes: 144 additions & 134 deletions packages/block-editor/src/store/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,15 @@ function withPersistentBlockChange( reducer ) {
return ( state, action ) => {
let nextState = reducer( state, action );

const selectionActions = new Set( [ 'SELECTION_CHANGE', 'TOGGLE_SELECTION', 'SELECT_BLOCK', 'MULTI_SELECT', 'START_MULTI_SELECT', 'STOP_MULTI_SELECT', 'CLEAR_SELECTED_BLOCK' ] );

if ( selectionActions.has( action.type ) ) {
return {
...nextState,
isPersistentChange: false,
};
}

const isExplicitPersistentChange = action.type === 'MARK_LAST_CHANGE_AS_PERSISTENT';

// Defer to previous state value (or default) unless changing or
Expand Down Expand Up @@ -381,6 +390,139 @@ const withSaveReusableBlock = ( reducer ) => ( state, action ) => {
return reducer( state, action );
};

const BLOCK_SELECTION_EMPTY_OBJECT = {};
const BLOCK_SELECTION_INITIAL_STATE = {
start: BLOCK_SELECTION_EMPTY_OBJECT,
end: BLOCK_SELECTION_EMPTY_OBJECT,
isMultiSelecting: false,
isEnabled: true,
initialPosition: null,
};

/**
* Reducer returning the block selection's state.
*
* @param {Object} state Current state.
* @param {Object} action Dispatched action.
*
* @return {Object} Updated state.
*/
export function blockSelection( state = BLOCK_SELECTION_INITIAL_STATE, action ) {
switch ( action.type ) {
case 'CLEAR_SELECTED_BLOCK':
return BLOCK_SELECTION_INITIAL_STATE;
case 'START_MULTI_SELECT':
if ( state.isMultiSelecting ) {
return state;
}

return {
...state,
isMultiSelecting: true,
initialPosition: null,
};
case 'STOP_MULTI_SELECT':
if ( ! state.isMultiSelecting ) {
return state;
}

return {
...state,
isMultiSelecting: false,
initialPosition: null,
};
case 'MULTI_SELECT':
return {
...BLOCK_SELECTION_INITIAL_STATE,
isMultiSelecting: state.isMultiSelecting,
start: { clientId: action.start },
end: { clientId: action.end },
};
case 'SELECT_BLOCK':
if (
action.clientId === state.start.clientId &&
action.clientId === state.end.clientId
) {
return state;
}

return {
...BLOCK_SELECTION_INITIAL_STATE,
initialPosition: action.initialPosition,
start: { clientId: action.clientId },
end: { clientId: action.clientId },
};
case 'REPLACE_INNER_BLOCKS': // REPLACE_INNER_BLOCKS and INSERT_BLOCKS should follow the same logic.
case 'INSERT_BLOCKS': {
if ( action.updateSelection ) {
return {
...BLOCK_SELECTION_INITIAL_STATE,
start: { clientId: action.blocks[ 0 ].clientId },
end: { clientId: action.blocks[ 0 ].clientId },
};
}

return state;
}
case 'REMOVE_BLOCKS':
if (
! action.clientIds ||
! action.clientIds.length ||
action.clientIds.indexOf( state.start.clientId ) === -1
) {
return state;
}

return BLOCK_SELECTION_INITIAL_STATE;
case 'REPLACE_BLOCKS': {
if ( action.clientIds.indexOf( state.start.clientId ) === -1 ) {
return state;
}

const indexToSelect = action.indexToSelect || action.blocks.length - 1;
const blockToSelect = action.blocks[ indexToSelect ];

if ( ! blockToSelect ) {
return BLOCK_SELECTION_INITIAL_STATE;
}

if (
blockToSelect.clientId === state.start.clientId &&
blockToSelect.clientId === state.end.clientId
) {
return state;
}

return {
...BLOCK_SELECTION_INITIAL_STATE,
start: { clientId: blockToSelect.clientId },
end: { clientId: blockToSelect.clientId },
};
}
case 'TOGGLE_SELECTION':
return {
...BLOCK_SELECTION_INITIAL_STATE,
isEnabled: action.isSelectionEnabled,
};
case 'SELECTION_CHANGE':
return {
...BLOCK_SELECTION_INITIAL_STATE,
start: {
clientId: action.clientId,
attributeKey: action.attributeKey,
offset: action.startOffset,
},
end: {
clientId: action.clientId,
attributeKey: action.attributeKey,
offset: action.endOffset,
},
};
}

return state;
}

/**
* Reducer returning the blocks state.
*
Expand Down Expand Up @@ -656,6 +798,8 @@ export const blocks = flow(

return state;
},

selection: blockSelection,
} );

/**
Expand Down Expand Up @@ -698,139 +842,6 @@ export function isCaretWithinFormattedText( state = false, action ) {
return state;
}

const BLOCK_SELECTION_EMPTY_OBJECT = {};
const BLOCK_SELECTION_INITIAL_STATE = {
start: BLOCK_SELECTION_EMPTY_OBJECT,
end: BLOCK_SELECTION_EMPTY_OBJECT,
isMultiSelecting: false,
isEnabled: true,
initialPosition: null,
};

/**
* Reducer returning the block selection's state.
*
* @param {Object} state Current state.
* @param {Object} action Dispatched action.
*
* @return {Object} Updated state.
*/
export function blockSelection( state = BLOCK_SELECTION_INITIAL_STATE, action ) {
switch ( action.type ) {
case 'CLEAR_SELECTED_BLOCK':
return BLOCK_SELECTION_INITIAL_STATE;
case 'START_MULTI_SELECT':
if ( state.isMultiSelecting ) {
return state;
}

return {
...state,
isMultiSelecting: true,
initialPosition: null,
};
case 'STOP_MULTI_SELECT':
if ( ! state.isMultiSelecting ) {
return state;
}

return {
...state,
isMultiSelecting: false,
initialPosition: null,
};
case 'MULTI_SELECT':
return {
...BLOCK_SELECTION_INITIAL_STATE,
isMultiSelecting: state.isMultiSelecting,
start: { clientId: action.start },
end: { clientId: action.end },
};
case 'SELECT_BLOCK':
if (
action.clientId === state.start.clientId &&
action.clientId === state.end.clientId
) {
return state;
}

return {
...BLOCK_SELECTION_INITIAL_STATE,
initialPosition: action.initialPosition,
start: { clientId: action.clientId },
end: { clientId: action.clientId },
};
case 'REPLACE_INNER_BLOCKS': // REPLACE_INNER_BLOCKS and INSERT_BLOCKS should follow the same logic.
case 'INSERT_BLOCKS': {
if ( action.updateSelection ) {
return {
...BLOCK_SELECTION_INITIAL_STATE,
start: { clientId: action.blocks[ 0 ].clientId },
end: { clientId: action.blocks[ 0 ].clientId },
};
}

return state;
}
case 'REMOVE_BLOCKS':
if (
! action.clientIds ||
! action.clientIds.length ||
action.clientIds.indexOf( state.start.clientId ) === -1
) {
return state;
}

return BLOCK_SELECTION_INITIAL_STATE;
case 'REPLACE_BLOCKS': {
if ( action.clientIds.indexOf( state.start.clientId ) === -1 ) {
return state;
}

const indexToSelect = action.indexToSelect || action.blocks.length - 1;
const blockToSelect = action.blocks[ indexToSelect ];

if ( ! blockToSelect ) {
return BLOCK_SELECTION_INITIAL_STATE;
}

if (
blockToSelect.clientId === state.start.clientId &&
blockToSelect.clientId === state.end.clientId
) {
return state;
}

return {
...BLOCK_SELECTION_INITIAL_STATE,
start: { clientId: blockToSelect.clientId },
end: { clientId: blockToSelect.clientId },
};
}
case 'TOGGLE_SELECTION':
return {
...BLOCK_SELECTION_INITIAL_STATE,
isEnabled: action.isSelectionEnabled,
};
case 'SELECTION_CHANGE':
return {
...BLOCK_SELECTION_INITIAL_STATE,
start: {
clientId: action.clientId,
attributeKey: action.attributeKey,
offset: action.startOffset,
},
end: {
clientId: action.clientId,
attributeKey: action.attributeKey,
offset: action.endOffset,
},
};
}

return state;
}

export function blocksMode( state = {}, action ) {
if ( action.type === 'TOGGLE_BLOCK_MODE' ) {
const { clientId } = action;
Expand Down Expand Up @@ -987,7 +998,6 @@ export default combineReducers( {
blocks,
isTyping,
isCaretWithinFormattedText,
blockSelection,
blocksMode,
blockListSettings,
insertionPoint,
Expand Down
Loading

0 comments on commit 7315f25

Please sign in to comment.