UNPKG

@quillforms/block-editor

Version:
322 lines (303 loc) 10.6 kB
/** * QuillForms Dependencies */ import { getBlockType } from '@quillforms/blocks'; import { identAlphabetically } from '@quillforms/utils'; /** * WordPress Dependencies */ import { select } from '@wordpress/data'; /** * External Dependencies */ import { forEach, findIndex, slice, pick, size } from 'lodash'; /** * Internal Dependencies */ /** * Returns form blocks objects. * * Note: it's important to memoize this selector to avoid return a new instance on each call. We use the block cache state * for each top-level block of the given block id. This way, the selector only refreshes * on changes to blocks associated with the given entity * * @param {State} state Editor state. * @param {boolean} withPartialSubmission Whether to include partial submission point or not. * * @return {FormBlocks} Form blocks. */ export const getBlocks = (state, withPartialSubmission = false) => { return state.blocks.filter(block => { if (withPartialSubmission) return true; return block.name !== 'partial-submission-point'; }); }; export const getBlocksWithPartialSubmission = state => { return state.blocks; }; /** * Returns all form blocks including inner blocks. * * * @param {State} state Editor state. * * @return {FormBlocks} Form blocks. */ export const getAllBlocks = state => { const blocks = state.blocks; const allBlocks = []; if (size(blocks) > 0) { forEach(blocks, block => { allBlocks.push(block); if (size(block?.innerBlocks) > 0) { forEach(block.innerBlocks, innerBlock => { allBlocks.push(innerBlock); }); } }); } return allBlocks; }; /** * Get welcome screens length. * * @param {State} state Global application state. * * @return {number} Welcome screens length */ export function getWelcomeScreensLength(state) { return state.blocks.filter(block => block.name === 'welcome-screen').length; } /** * Does Partial Submission Point Exist * * @param {State} state Global application state. * * @return {Boolean} Partial Submission Point * */ export const doesPartialSubmissionPointExist = state => { return state.blocks.some(block => block.name === 'partial-submission-point'); }; /** * Get block by id * * @param {State} state Global application state. * @param {string} id Block id * * @param blockId * @param parentIndex * @return {FormBlock} Block object */ export const getBlockById = (state, blockId, parentIndex = undefined) => { if (typeof parentIndex === 'undefined') { const block = state.blocks.find($block => $block.id === blockId); if (!block) return undefined; return block; } if (!state.blocks || !state.blocks[parentIndex] || !state.blocks[parentIndex].innerBlocks) { return undefined; } const block = state.blocks[parentIndex].innerBlocks?.find($block => $block.id === blockId); if (!block) return undefined; return block; }; /** * Get block order by id * * @param {State} state Global application state. * @param {string} id Block id * * @param parentIndex * @return {BlockOrder} Block order */ export const getBlockOrderById = (state, id, parentIndex = undefined) => { const formBlock = getBlockById(state, id, parentIndex); if (!formBlock) return undefined; const blockType = select('quillForms/blocks').getBlockTypes()[formBlock.name]; const orderableFields = select('quillForms/block-editor').getBlocksByCriteria({ editable: true, innerBlocks: true }, 'or'); let itemOrder; if (typeof parentIndex === 'undefined') { if (blockType.supports.editable === true || blockType.supports.innerBlocks === true) { const fieldIndex = orderableFields.findIndex(field => field.id === id); itemOrder = fieldIndex + 1; } else { const fieldIndex = state.blocks.filter(block => block.name === formBlock.name).findIndex(block => block.id === id); itemOrder = identAlphabetically(fieldIndex); } } else { const fieldIndex = state.blocks?.[parentIndex]?.innerBlocks?.findIndex(block => block.id === id); if (typeof fieldIndex !== 'undefined' && fieldIndex > -1) { const parentBlockId = state.blocks[parentIndex].id; const parentBlockOrder = getBlockOrderById(state, parentBlockId); itemOrder = parentBlockOrder + identAlphabetically(fieldIndex); } } return itemOrder; }; /** * Retruns the editable blocks -- Editable blocks are the blocks who have {editable} setting equals true * * @param {State} state Global application state. * * @return {FormBlock[]} Editable fields */ export function getEditableFields(state) { const blocks = getBlocks(state); return blocks.filter(block => { const blockType = select('quillForms/blocks').getBlockTypes()[block.name]; return blockType.supports.editable === true; }); } /** * Get block with multiple criteria. * * @param {Object} state Global application state. * @param {QFBlocksSupportsCriteria} criteria Multiple criteria according to which the blocks are filtered. * * @param operator * @return {Array} Filtered blocks according to criteria given */ export const getBlocksByCriteria = (state, criteria, operator = 'and') => { const blocks = getBlocks(state); const filteredCriteria = pick(criteria, ['logic', 'required', 'attachment', 'description', 'editable', 'numeric', 'innerBlocks']); return blocks.filter(block => { const blockType = select('quillForms/blocks').getBlockTypes()[block.name]; if (operator === 'and') return Object.entries(filteredCriteria).every(([key, val]) => typeof val === 'boolean' ? blockType.supports[key] === val : true); return Object.entries(filteredCriteria).some(([key, val]) => typeof val === 'boolean' ? blockType.supports[key] === val : true); }); }; /** * Get block with multiple criteria. * * @param {Object} state Global application state. * @param {QFBlocksSupportsCriteria} criteria Multiple criteria according to which the blocks are filtered. * * @param id * @param includeCurrentBlock * @return {Array} Filtered blocks according to criteria given */ export const getPreviousBlocksByCriteria = (state, criteria, id, includeCurrentBlock = false, relation = 'and') => { const blocks = getBlocks(state); const filteredCriteria = pick(criteria, ['logic', 'required', 'attachment', 'description', 'editable', 'innerBlocks', 'correctAnswers', 'points', 'numeric']); const blockIndex = findIndex(blocks, block => block.id === id); if (blockIndex > 0) { const prevFormBlocks = slice(blocks, 0, includeCurrentBlock ? blockIndex + 1 : blockIndex); return prevFormBlocks.filter(block => { const blockType = select('quillForms/blocks').getBlockTypes()[block.name]; if (relation === 'and') return Object.entries(filteredCriteria).every(([key, val]) => typeof val === 'boolean' ? blockType.supports[key] === val : true); return Object.entries(filteredCriteria).some(([key, val]) => typeof val === 'boolean' ? blockType.supports[key] === val : true); }); } return []; }; /** * Retruns the previous editable fields * Editable fields are the fields which have {editable} property equals true * * @param {State} state Global application state. * @param {string} id The block id. * * @return {FormBlockWithOrder[]} Previous editable fields */ export const getPreviousEditableFieldsWithOrder = (state, id) => { const prevEditableFields = []; const blocks = state.blocks; const blockIndex = findIndex(blocks, block => block.id === id); if (blockIndex > 0) { const prevFormBlocks = slice(blocks, 0, blockIndex); forEach(prevFormBlocks, (block, $prevBlockIndex) => { const blockType = getBlockType(block.name); if (blockType?.supports?.editable) { prevEditableFields.push({ ...block, order: getBlockOrderById(state, block.id) }); } if (blockType?.supports?.innerBlocks) { forEach(block.innerBlocks, innerBlock => { const innerBlockType = getBlockType(innerBlock.name); if (innerBlockType?.supports?.editable) { prevEditableFields.push({ ...innerBlock, order: getBlockOrderById(state, innerBlock.id, $prevBlockIndex) }); } }); } }); } return prevEditableFields; }; /** * Retruns the editable fields length * * @param {State} state Global application state. * * @return {number} Editable fields length */ export function getEditableFieldsLength(state) { return getEditableFields(state).length; } /** * Returns the current block id * * @param {State} state Global application state. * * @param parent * @return {?string} Current block id */ export function getCurrentBlockId(state) { return state.currentBlockId; } /** * Returns the current child block id * * @param {State} state Global application state. * * @return {?string} Current child block id */ export function getCurrentChildBlockId(state) { return state.currentChildBlockId; } /** * Returns the current block index * * @param {State} state Global application state. * * @return {number} Current block index */ export function getCurrentBlockIndex(state) { return state.blocks.findIndex(item => item.id === state.currentBlockId); } /** * Returns the current child block index * * @param {State} state Global application state. * * @return {number | undefined } Current block index */ export function getCurrentChildBlockIndex(state) { const parentBlockIndex = getCurrentBlockIndex(state); if (!state.blocks || state.blocks.length === 0 || typeof parentBlockIndex === 'undefined' || !state.blocks[parentBlockIndex]) { return undefined; } return state.blocks[parentBlockIndex]?.innerBlocks?.findIndex(item => item.id === state.currentChildBlockId); } /** * Returns the current form item * * @param {State} state Global application state. * * @return {FormBlock} Current block item */ export function getCurrentBlock(state) { let currentBlock; const currentBlockIndex = state.blocks.findIndex(item => item.id === state.currentBlockId); if (currentBlockIndex !== -1) currentBlock = state.blocks[currentBlockIndex]; return currentBlock; } //# sourceMappingURL=selectors.js.map