@quillforms/block-editor
Version:
434 lines (416 loc) • 13.1 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
exports.flattenBlocks = flattenBlocks;
var _lodash = require("lodash");
var _constants = require("./constants");
var _blocks = require("@quillforms/blocks");
/* eslint-disable no-nested-ternary */
/**
* External dependencies
*/
/**
* Internal Dependencies
*/
const generateBlockId = () => {
return Math.random().toString(36).substr(2, 9);
};
/**
* Sort blocks. We should have welcome screens at first then others then thankyou screens.
*
* @param {Object} blocks The blocks array.
*
* @return { Object } The sorted blocks
*/
function sortBlocks(blocks) {
const priority = ['WELCOME_SCREENS', 'OTHERS', 'THANKYOU_SCREENS'];
blocks.sort((a, b) => {
const getCategory = block => {
switch (block.name) {
case 'welcome-screen':
return 'WELCOME_SCREENS';
case 'thankyou-screen':
return 'THANKYOU_SCREENS';
default:
return 'OTHERS';
}
};
const ap = priority.indexOf(getCategory(a));
const bp = priority.indexOf(getCategory(b));
return ap - bp;
});
return blocks;
}
// Initial State
const initialState = {
currentBlockId: undefined,
currentChildBlockId: undefined,
blocks: []
};
// /**
// * Utility returning an object with an empty object value for each key.
// *
// * @param {string[]} objectKeys Keys to fill.
// * @return {Object} Object filled with empty object as values for each clientId.
// */
// const fillKeysWithEmptyObject = (
// objectKeys: string[]
// ): Record< string, {} > => {
// return objectKeys.reduce( ( result, key ) => {
// result[ key ] = {};
// return result;
// }, {} );
// };
/**
* Helper method to iterate through all blocks, recursing into inner blocks,
* applying a transformation function to each one.
* Returns a flattened object with the transformed blocks.
*
* @param {FormBlocks} blocks Blocks to flatten.
*
* @param transform
* @return {Array} Flattened object.
*/
function flattenBlocks(blocks, transform = _lodash.identity) {
const result = [];
const stack = [...blocks];
while (stack.length) {
// @ts-expect-error
const {
innerBlocks,
...block
} = stack.shift();
if (innerBlocks) {
(0, _lodash.forEach)(innerBlocks, ($block, index) => {
innerBlocks[index] = {
...$block,
parentId: block.id
};
});
stack.push(...innerBlocks);
}
result[block.id] = transform(block);
}
return result;
}
/**
* Reducer returning the form object.
*
* @param { BlockEditorPureState} state Current state.
* @param {BlockEditorActionTypes} action Dispatched action.
*
* @return {BlockEditorPureState} Updated state.
*/
const BlockEditorReducer = (state = initialState, action) => {
switch (action.type) {
// SET UP STORE
case _constants.SETUP_STORE:
{
const {
initialPayload
} = action;
if (initialPayload.length > 0 && !state.currentBlockId) {
return {
blocks: initialPayload,
currentBlockId: initialPayload[0].id,
currentChildBlockId: undefined
};
}
return {
...state,
blocks: initialPayload
};
}
case _constants.SET_BLOCKS:
{
const {
blocks
} = action;
return {
...state,
blocks
};
}
case 'REPLACE_BLOCK_NAME':
{
const {
blockId,
name,
parentId
} = action;
const blocks = [...state.blocks];
let blockIndex;
let parentIndex;
if (typeof parentId !== 'undefined') {
parentIndex = blocks.findIndex(item => item.id === parentId);
if (parentIndex !== -1 && (0, _lodash.size)(blocks[parentIndex]?.innerBlocks) > 0) {
blockIndex = blocks[parentIndex]?.innerBlocks?.findIndex(item => item.id === blockId);
} else {
return state;
}
} else {
blockIndex = blocks.findIndex(item => item.id === blockId);
}
// const blockIndex = blocks.findIndex((block) => block.id === blockId);
if (blockIndex === -1 || parentId && (parentIndex === -1 || !blocks[parentIndex]?.innerBlocks)) {
return state;
}
if (parentId && parentIndex > -1) {
blocks[parentIndex].innerBlocks[blockIndex].name = name;
blocks[parentIndex].innerBlocks[blockIndex].attributes = (0, _blocks.sanitizeBlockAttributes)(name, blocks[parentIndex].innerBlocks[blockIndex].attributes);
} else {
blocks[blockIndex].name = name;
if (blocks[blockIndex].name === 'group' && (0, _lodash.size)(blocks[blockIndex].innerBlocks) === 0) {
blocks[blockIndex].innerBlocks = [{
name: 'short-text',
id: generateBlockId(),
attributes: {}
}];
}
blocks[blockIndex].attributes = (0, _blocks.sanitizeBlockAttributes)(name, blocks[blockIndex]?.attributes);
}
return {
...state,
blocks: sortBlocks(blocks)
};
}
// SET BLOCK ATTRIBUTES
case _constants.SET_BLOCK_ATTRIBUTES:
{
const {
blockId,
attributes,
parentId
} = action;
let parentIndex;
// Get block index within its category.
let $blocks = [...state.blocks];
if (!$blocks) {
return state;
}
if (typeof parentId !== 'undefined' && parentId !== blockId) {
parentIndex = $blocks.findIndex(block => {
return block.id === parentId;
});
$blocks = [...state.blocks][parentIndex]?.innerBlocks;
}
if (!$blocks) {
return state;
}
const blockIndex = $blocks.findIndex(block => {
return block.id === blockId;
});
// Ignore updates if block isn't known.
if (blockIndex === -1) {
return state;
}
// Consider as updates only changed values
// const nextAttributes = reduce(
// { ...attributes },
// ( result, value, key ) => {
// if ( value !== result[ key ] ) {
// result = getMutateSafeObject(
// state.blocks[ blockIndex ],
// result
// );
// result[ key ] = value;
// }
// return result;
// },
// state.blocks[ blockIndex ].attributes
// );
const nextAttributes = {
...(0, _lodash.cloneDeep)($blocks[blockIndex].attributes),
...(0, _lodash.cloneDeep)(attributes)
};
// // Skip update if nothing has been changed. The reference will
// // match the original block if `reduce` had no changed values.
// if ( nextAttributes === state.blocks[ blockIndex ].attributes ) {
// return state;
// }
$blocks[blockIndex].attributes = nextAttributes;
const blocks = [...state.blocks];
if (typeof parentIndex !== 'undefined') {
blocks[parentIndex].innerBlocks = $blocks;
$blocks = blocks;
}
return {
...state,
blocks: $blocks
};
}
case _constants.REORDER_BLOCKS:
{
const {
sourceIndex,
destinationIndex,
parentSourceIndex,
parentDestIndex
} = action;
// Create deep copy of blocks
const newBlocks = JSON.parse(JSON.stringify(state.blocks));
// Get source block and remove it from original position
let sourceBlock;
if (typeof parentSourceIndex === 'undefined') {
sourceBlock = {
...newBlocks[sourceIndex]
};
newBlocks.splice(sourceIndex, 1);
} else {
sourceBlock = {
...newBlocks[parentSourceIndex].innerBlocks[sourceIndex]
};
newBlocks[parentSourceIndex].innerBlocks.splice(sourceIndex, 1);
}
// Insert block at new position
if (typeof parentDestIndex === 'undefined') {
// Insert at root level
newBlocks.splice(destinationIndex, 0, sourceBlock);
} else {
// Insert into group
if (!newBlocks[parentDestIndex].innerBlocks) {
newBlocks[parentDestIndex].innerBlocks = [];
}
newBlocks[parentDestIndex].innerBlocks.splice(destinationIndex, 0, sourceBlock);
}
return {
...state,
blocks: newBlocks
};
}
// INSERT NEW FORM BLOCK
case _constants.INSERT_BLOCK:
{
const {
block,
destinationIndex,
parent
} = action;
const blocks = [...state.blocks];
const index = destinationIndex;
let parentBlock = undefined;
if (index === undefined || index < 0) {
return state;
}
if (!parent) {
blocks.splice(index, 0, {
...block
});
} else {
const parentIndex = blocks.findIndex($block => $block.id === parent);
parentBlock = blocks[parentIndex];
if (!blocks[parentIndex].innerBlocks) {
blocks[parentIndex].innerBlocks = [];
}
blocks[parentIndex]?.innerBlocks?.splice(index, 0, {
...block
});
}
return {
...state,
blocks: sortBlocks(blocks),
currentBlockId: parentBlock ? parentBlock.id : block.id,
currentChildBlockId: parentBlock ? block.id : undefined
};
}
// DELETE FORM BLOCK
case _constants.DELETE_BLOCK:
{
const {
blockId,
parentId
} = action;
const originalBlocks = [...state.blocks];
let parentIndex;
let blocks = originalBlocks;
if (!blocks) {
return state;
}
if (typeof parentId !== 'undefined') {
var _blocks$parentIndex$i;
parentIndex = blocks.findIndex(item => item.id === parentId);
if (blocks) blocks = (_blocks$parentIndex$i = blocks?.[parentIndex]?.innerBlocks) !== null && _blocks$parentIndex$i !== void 0 ? _blocks$parentIndex$i : [];
}
// Get block index.
const blockIndex = blocks.findIndex(item => item.id === blockId);
// If block isn't found.
if (blockIndex === -1) {
return state;
}
const nextBlock = blocks[blockIndex + 1];
const prevBlock = blocks[blockIndex - 1];
blocks.splice(blockIndex, 1);
const newCurrentBlockId = nextBlock ? nextBlock.id : prevBlock ? prevBlock.id : undefined;
if (typeof parentIndex !== 'undefined') {
const $blocks = originalBlocks;
$blocks[parentIndex].innerBlocks = blocks;
blocks = $blocks;
}
const newState = {
...state,
currentBlockId: typeof parentIndex === 'undefined' ? newCurrentBlockId : state.currentBlockId,
currentChildBlockId: typeof parentIndex === 'undefined' ? undefined : newCurrentBlockId,
blocks
};
return newState;
}
// SET CURRENT BLOCK
case _constants.SET_CURRENT_BLOCK:
{
const {
blockId
} = action;
const blockIndex = state.blocks.findIndex(item => item.id === blockId);
// If block isn't found.
if (blockIndex === -1) {
return state;
}
if (blockId === state.currentBlockId) return state;
return {
...state,
currentBlockId: blockId,
currentChildBlockId: undefined
};
}
// SET CURRENT CHILD BLOCK
case _constants.SET_CURRENT_CHILD_BLOCK:
{
const {
blockId
} = action;
if (blockId === state.currentChildBlockId) {
return state;
}
// const parentblockIndex = state.blocks.findIndex(
// ( item ) => item.id === state.currentBlockId
// );
// // If block isn't found.
// if (
// parentblockIndex === -1 ||
// typeof parentblockIndex === 'undefined' ||
// state.blocks.length === 0 ||
// ! state.blocks[ parentblockIndex ]
// ) {
// return state;
// }
// const childBlockIndex = state.blocks[
// parentblockIndex
// ]?.innerBlocks?.findIndex(
// ( item ) => item.id === state.currentBlockId
// );
// if ( childBlockIndex === -1 ) {
// return state;
// }
return {
...state,
currentChildBlockId: blockId
};
}
}
return state;
};
const BlockEditorReducerWithHigherOrder = BlockEditorReducer;
var _default = exports.default = BlockEditorReducerWithHigherOrder;
//# sourceMappingURL=reducer.js.map