UNPKG

@wordpress/block-library

Version:
8 lines (7 loc) 10.5 kB
{ "version": 3, "sources": ["../../src/list-item/utils.js"], "sourcesContent": ["import { store as blockEditorStore } from '@wordpress/block-editor';\nimport { cloneBlock } from '@wordpress/blocks';\n\n/**\n * The previous sibling to nest a list item under when indenting, or undefined\n * for the first item, which has no sibling to nest under.\n *\n * @param {Object} select The block editor store's selectors.\n * @param {string} clientId The list item's client ID.\n *\n * @return {string|undefined} The client ID to nest the item under.\n */\nexport function getIndentTarget( select, clientId ) {\n\treturn select.getPreviousBlockClientId( clientId );\n}\n\n/**\n * The ancestor list item the given item's list is nested in when outdenting, or\n * undefined at the top level, where there is nothing to outdent to.\n *\n * @param {Object} select The block editor store's selectors.\n * @param {string} clientId The list item's client ID.\n *\n * @return {string|undefined} The ancestor list item's client ID.\n */\nexport function getOutdentTarget( select, clientId ) {\n\tconst listId = select.getBlockRootClientId( clientId );\n\tconst parentListItemId = select.getBlockRootClientId( listId );\n\tif (\n\t\t! parentListItemId ||\n\t\tselect.getBlockName( parentListItemId ) !== 'core/list-item'\n\t) {\n\t\treturn undefined;\n\t}\n\treturn parentListItemId;\n}\n\n/**\n * Moves blocks into a list item's nested list, keeping their client IDs. If the\n * list item has no nested list yet, one is created from the source list so it\n * inherits its attributes.\n *\n * @param {Object} registry The data registry.\n * @param {string[]} clientIds The blocks to move.\n * @param {string} sourceListId The list the blocks currently live in, also\n * cloned when a nested list has to be created.\n * @param {string} listItemId The list item to nest the blocks under.\n */\nexport function moveBlocksToNestedList(\n\tregistry,\n\tclientIds,\n\tsourceListId,\n\tlistItemId\n) {\n\tconst { getBlockOrder, getBlock } = registry.select( blockEditorStore );\n\tconst { moveBlocksToPosition, removeBlocks, insertBlock } =\n\t\tregistry.dispatch( blockEditorStore );\n\t// A list item can hold more than one nested list; append to the last one,\n\t// the same subtree a reader sees at the end of the item.\n\tconst nestedLists = getBlockOrder( listItemId );\n\tconst nestedListId = nestedLists[ nestedLists.length - 1 ];\n\n\tif ( nestedListId ) {\n\t\tmoveBlocksToPosition( clientIds, sourceListId, nestedListId );\n\t\treturn;\n\t}\n\n\t// Insert the list with the items already inside: an empty list would be\n\t// scaffolded with the list block type's template, and moving into a freshly\n\t// created list would fail its canInsert check. Cloning the source list keeps\n\t// its attributes; passing the items as inner blocks keeps their client IDs.\n\tconst nestedList = cloneBlock(\n\t\tgetBlock( sourceListId ),\n\t\t{},\n\t\tclientIds.map( ( id ) => getBlock( id ) )\n\t);\n\t// Remove and re-insert in one batch so the blocks are never momentarily\n\t// detached. A caller batch nests harmlessly: only the outermost flushes.\n\tregistry.batch( () => {\n\t\tremoveBlocks( clientIds, false );\n\t\tinsertBlock( nestedList, 0, listItemId, false );\n\t} );\n}\n\n/**\n * Indents the selected list items, nesting them under the previous sibling of\n * the given item. Defaults to the first selected item.\n *\n * @param {Object} registry The data registry.\n * @param {string} [clientId] The list item providing the sibling to nest under.\n *\n * @return {boolean} Whether the items were indented.\n */\nexport function indentListItems( registry, clientId ) {\n\tconst select = registry.select( blockEditorStore );\n\tconst {\n\t\tgetBlockRootClientId,\n\t\tgetSelectedBlockClientIds,\n\t\tgetSelectionStart,\n\t\tgetSelectionEnd,\n\t\thasMultiSelection,\n\t\tgetMultiSelectedBlockClientIds,\n\t} = select;\n\tconst { selectionChange, multiSelect } =\n\t\tregistry.dispatch( blockEditorStore );\n\n\tconst _hasMultiSelection = hasMultiSelection();\n\tconst clientIds = _hasMultiSelection\n\t\t? getMultiSelectedBlockClientIds()\n\t\t: getSelectedBlockClientIds();\n\n\tif ( clientId === undefined ) {\n\t\tclientId = clientIds[ 0 ];\n\t}\n\n\tconst previousSiblingId = getIndentTarget( select, clientId );\n\n\t// Can't indent the first item: there is no sibling to nest it under.\n\tif ( ! previousSiblingId ) {\n\t\treturn false;\n\t}\n\n\tconst rootClientId = getBlockRootClientId( clientId );\n\t// Read the selection before the move: creating a nested list removes and\n\t// re-inserts the items, which drops it.\n\tconst selectionStart = getSelectionStart();\n\tconst selectionEnd = getSelectionEnd();\n\n\tregistry.batch( () => {\n\t\tmoveBlocksToNestedList(\n\t\t\tregistry,\n\t\t\tclientIds,\n\t\t\trootClientId,\n\t\t\tpreviousSiblingId\n\t\t);\n\n\t\t// Put the selection back on the same blocks (client IDs are kept).\n\t\tif ( ! _hasMultiSelection ) {\n\t\t\tselectionChange(\n\t\t\t\tclientIds[ 0 ],\n\t\t\t\tselectionEnd.attributeKey,\n\t\t\t\tselectionEnd.clientId === selectionStart.clientId\n\t\t\t\t\t? selectionStart.offset\n\t\t\t\t\t: selectionEnd.offset,\n\t\t\t\tselectionEnd.offset\n\t\t\t);\n\t\t} else {\n\t\t\tmultiSelect( clientIds[ 0 ], clientIds[ clientIds.length - 1 ] );\n\t\t}\n\t} );\n\n\treturn true;\n}\n\n/**\n * Outdents list items, moving them up a level. Defaults to the selected items;\n * a specific set can be passed, e.g. to outdent an item's children.\n *\n * @param {Object} registry The data registry.\n * @param {string[]|string} [clientIds] The list items to outdent.\n *\n * @return {boolean} Whether the items were outdented.\n */\nexport function outdentListItems( registry, clientIds ) {\n\tconst select = registry.select( blockEditorStore );\n\tconst {\n\t\tgetBlockRootClientId,\n\t\tgetBlockName,\n\t\tgetBlockOrder,\n\t\tgetBlockIndex,\n\t\tgetSelectedBlockClientIds,\n\t} = select;\n\tconst { moveBlocksToPosition, removeBlock, multiSelect } =\n\t\tregistry.dispatch( blockEditorStore );\n\n\tif ( clientIds === undefined ) {\n\t\tclientIds = getSelectedBlockClientIds();\n\t}\n\n\tif ( ! Array.isArray( clientIds ) ) {\n\t\tclientIds = [ clientIds ];\n\t}\n\n\tif ( ! clientIds.length ) {\n\t\treturn false;\n\t}\n\n\tconst firstClientId = clientIds[ 0 ];\n\n\t// Can't outdent if it's not a list item.\n\tif ( getBlockName( firstClientId ) !== 'core/list-item' ) {\n\t\treturn false;\n\t}\n\n\t// Can't outdent if it's at the top level.\n\tconst parentListItemId = getOutdentTarget( select, firstClientId );\n\tif ( ! parentListItemId ) {\n\t\treturn false;\n\t}\n\n\tconst parentListId = getBlockRootClientId( firstClientId );\n\tconst lastClientId = clientIds[ clientIds.length - 1 ];\n\tconst order = getBlockOrder( parentListId );\n\tconst followingListItems = order.slice( getBlockIndex( lastClientId ) + 1 );\n\n\tregistry.batch( () => {\n\t\tif ( followingListItems.length ) {\n\t\t\t// Nest the items that follow under the outdented item so they keep\n\t\t\t// their place below it.\n\t\t\tmoveBlocksToNestedList(\n\t\t\t\tregistry,\n\t\t\t\tfollowingListItems,\n\t\t\t\tparentListId,\n\t\t\t\tfirstClientId\n\t\t\t);\n\t\t}\n\t\tmoveBlocksToPosition(\n\t\t\tclientIds,\n\t\t\tparentListId,\n\t\t\tgetBlockRootClientId( parentListItemId ),\n\t\t\tgetBlockIndex( parentListItemId ) + 1\n\t\t);\n\t\tif ( ! getBlockOrder( parentListId ).length ) {\n\t\t\tconst shouldSelectParent = false;\n\t\t\tremoveBlock( parentListId, shouldSelectParent );\n\t\t}\n\n\t\t// Reset the lingering partial cross-block range to a whole block\n\t\t// selection. A single caret is preserved by the store on its own.\n\t\tif ( clientIds.length > 1 ) {\n\t\t\tmultiSelect( firstClientId, lastClientId );\n\t\t}\n\t} );\n\n\treturn true;\n}\n"], "mappings": "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", "names": [] }