@wordpress/block-editor
Version:
520 lines (519 loc) • 17.3 kB
JavaScript
// packages/block-editor/src/store/private-selectors.js
import { createSelector, createRegistrySelector } from "@wordpress/data";
import {
hasBlockSupport,
privateApis as blocksPrivateApis
} from "@wordpress/blocks";
import {
getBlockOrder,
getBlockParents,
getBlockEditingMode,
getSettings,
canInsertBlockType,
getBlockName,
getTemplateLock,
getClientIdsWithDescendants,
getBlockRootClientId,
getBlockAttributes
} from "./selectors.mjs";
import {
checkAllowListRecursive,
getAllPatternsDependants,
getInsertBlockTypeDependants,
getGrammar,
mapUserPattern
} from "./utils.mjs";
import { STORE_NAME } from "./constants.mjs";
import { unlock } from "../lock-unlock.mjs";
import {
selectBlockPatternsKey,
reusableBlocksSelectKey,
sectionRootClientIdKey,
isIsolatedEditorKey
} from "./private-keys.mjs";
import { BLOCK_VISIBILITY_VIEWPORTS } from "../components/block-visibility/constants.mjs";
import { getBlockSettings } from "./get-block-settings.mjs";
var { isContentBlock } = unlock(blocksPrivateApis);
function isBlockInterfaceHidden(state) {
return state.isBlockInterfaceHidden;
}
function getLastInsertedBlocksClientIds(state) {
return state?.lastBlockInserted?.clientIds;
}
function getBlockWithoutAttributes(state, clientId) {
return state.blocks.byClientId.get(clientId);
}
var isBlockSubtreeDisabled = (state, clientId) => {
const isChildSubtreeDisabled = (childClientId) => {
return getBlockEditingMode(state, childClientId) === "disabled" && getBlockOrder(state, childClientId).every(
isChildSubtreeDisabled
);
};
return getBlockOrder(state, clientId).every(isChildSubtreeDisabled);
};
function isContainerInsertableToInContentOnlyMode(state, blockName, rootClientId) {
const isBlockContentBlock = isContentBlock(blockName);
const rootBlockName = getBlockName(state, rootClientId);
const isContainerContentBlock = isContentBlock(rootBlockName);
const isRootBlockMain = getSectionRootClientId(state) === rootClientId;
return isRootBlockMain || isContainerContentBlock && isBlockContentBlock;
}
function getEnabledClientIdsTreeUnmemoized(state, rootClientId) {
const blockOrder = getBlockOrder(state, rootClientId);
const result = [];
for (const clientId of blockOrder) {
const innerBlocks = getEnabledClientIdsTreeUnmemoized(
state,
clientId
);
if (getBlockEditingMode(state, clientId) !== "disabled") {
result.push({ clientId, innerBlocks });
} else {
result.push(...innerBlocks);
}
}
return result;
}
var getEnabledClientIdsTree = createRegistrySelector(
() => createSelector(getEnabledClientIdsTreeUnmemoized, (state) => [
state.blocks.order,
state.derivedBlockEditingModes,
state.blocks.blockEditingModes
])
);
var getEnabledBlockParents = createSelector(
(state, clientId, ascending = false) => {
return getBlockParents(state, clientId, ascending).filter(
(parent) => getBlockEditingMode(state, parent) !== "disabled"
);
},
(state) => [
state.blocks.parents,
state.blocks.blockEditingModes,
state.settings.templateLock,
state.blockListSettings
]
);
function getRemovalPromptData(state) {
return state.removalPromptData;
}
function getBlockRemovalRules(state) {
return state.blockRemovalRules;
}
var getStyleOverrides = createSelector(
(state) => {
const clientIds = getClientIdsWithDescendants(state);
const clientIdMap = clientIds.reduce((acc, clientId, index) => {
acc[clientId] = index;
return acc;
}, {});
return [...state.styleOverrides].sort((overrideA, overrideB) => {
const [, { clientId: clientIdA }] = overrideA;
const [, { clientId: clientIdB }] = overrideB;
const aIndex = clientIdMap[clientIdA] ?? -1;
const bIndex = clientIdMap[clientIdB] ?? -1;
return aIndex - bIndex;
});
},
(state) => [state.blocks.order, state.styleOverrides]
);
function getRegisteredInserterMediaCategories(state) {
return state.registeredInserterMediaCategories;
}
var getInserterMediaCategories = createSelector(
(state) => {
const {
settings: {
inserterMediaCategories,
allowedMimeTypes,
enableOpenverseMediaCategory
},
registeredInserterMediaCategories
} = state;
if (!inserterMediaCategories && !registeredInserterMediaCategories.length || !allowedMimeTypes) {
return;
}
const coreInserterMediaCategoriesNames = inserterMediaCategories?.map(({ name }) => name) || [];
const mergedCategories = [
...inserterMediaCategories || [],
...(registeredInserterMediaCategories || []).filter(
({ name }) => !coreInserterMediaCategoriesNames.includes(name)
)
];
return mergedCategories.filter((category) => {
if (!enableOpenverseMediaCategory && category.name === "openverse") {
return false;
}
return Object.values(allowedMimeTypes).some(
(mimeType) => mimeType.startsWith(`${category.mediaType}/`)
);
});
},
(state) => [
state.settings.inserterMediaCategories,
state.settings.allowedMimeTypes,
state.settings.enableOpenverseMediaCategory,
state.registeredInserterMediaCategories
]
);
var hasAllowedPatterns = createRegistrySelector(
(select) => createSelector(
(state, rootClientId = null) => {
const { getAllPatterns: getAllPatterns2 } = unlock(select(STORE_NAME));
const patterns = getAllPatterns2();
const { allowedBlockTypes } = getSettings(state);
return patterns.some((pattern) => {
const { inserter = true } = pattern;
if (!inserter) {
return false;
}
const grammar = getGrammar(pattern);
return checkAllowListRecursive(grammar, allowedBlockTypes) && grammar.every(
({ name: blockName }) => canInsertBlockType(state, blockName, rootClientId)
);
});
},
(state, rootClientId) => [
...getAllPatternsDependants(select)(state),
...getInsertBlockTypeDependants(select)(state, rootClientId)
]
)
);
var getPatternBySlug = createRegistrySelector(
(select) => createSelector(
(state, patternName) => {
if (patternName?.startsWith("core/block/")) {
const _id = parseInt(
patternName.slice("core/block/".length),
10
);
const block = unlock(select(STORE_NAME)).getReusableBlocks().find(({ id }) => id === _id);
if (!block) {
return null;
}
return mapUserPattern(
block,
state.settings.__experimentalUserPatternCategories
);
}
return [
// This setting is left for back compat.
...state.settings.__experimentalBlockPatterns ?? [],
...state.settings[selectBlockPatternsKey]?.(select) ?? []
].find(({ name }) => name === patternName);
},
(state, patternName) => patternName?.startsWith("core/block/") ? [
unlock(select(STORE_NAME)).getReusableBlocks(),
state.settings.__experimentalReusableBlocks
] : [
state.settings.__experimentalBlockPatterns,
state.settings[selectBlockPatternsKey]?.(select)
]
)
);
var getAllPatterns = createRegistrySelector(
(select) => createSelector((state) => {
return [
...unlock(select(STORE_NAME)).getReusableBlocks().map(
(userPattern) => mapUserPattern(
userPattern,
state.settings.__experimentalUserPatternCategories
)
),
// This setting is left for back compat.
...state.settings.__experimentalBlockPatterns ?? [],
...state.settings[selectBlockPatternsKey]?.(select) ?? []
].filter(
(x, index, arr) => index === arr.findIndex((y) => x.name === y.name)
);
}, getAllPatternsDependants(select))
);
var EMPTY_ARRAY = [];
var getReusableBlocks = createRegistrySelector(
(select) => (state) => {
const reusableBlocksSelect = state.settings[reusableBlocksSelectKey];
return (reusableBlocksSelect ? reusableBlocksSelect(select) : state.settings.__experimentalReusableBlocks) ?? EMPTY_ARRAY;
}
);
function getLastFocus(state) {
return state.lastFocus;
}
function isDragging(state) {
return state.isDragging;
}
function getExpandedBlock(state) {
return state.expandedBlock;
}
var getContentLockingParent = (state, clientId) => {
let current = clientId;
let result;
while (!result && (current = state.blocks.parents.get(current))) {
if (getTemplateLock(state, current) === "contentOnly") {
result = current;
}
}
return result;
};
function isSectionBlockCandidate(state, clientId) {
const blockName = getBlockName(state, clientId);
if (blockName === "core/block") {
return true;
}
const attributes = getBlockAttributes(state, clientId);
const isTemplatePart = blockName === "core/template-part";
const isIsolatedEditor = state.settings?.[isIsolatedEditorKey];
const disableContentOnlyForUnsyncedPatterns = state.settings?.disableContentOnlyForUnsyncedPatterns;
const disableContentOnlyForTemplateParts = state.settings?.disableContentOnlyForTemplateParts;
if ((!disableContentOnlyForUnsyncedPatterns && attributes?.metadata?.patternName || isTemplatePart && !disableContentOnlyForTemplateParts) && !isIsolatedEditor) {
return true;
}
const hasContentOnlyTemplateLock = getTemplateLock(state, clientId) === "contentOnly";
const rootClientId = getBlockRootClientId(state, clientId);
const hasRootContentOnlyTemplateLock = getTemplateLock(state, rootClientId) === "contentOnly";
if (hasContentOnlyTemplateLock && !hasRootContentOnlyTemplateLock) {
return true;
}
return false;
}
var getParentSectionBlock = (state, clientId) => {
if (isWithinEditedContentOnlySection(state, clientId)) {
return void 0;
}
let current = clientId;
let result;
while (current = state.blocks.parents.get(current)) {
if (isSectionBlockCandidate(state, current)) {
result = current;
}
}
return result;
};
function isSectionBlock(state, clientId) {
if (isWithinEditedContentOnlySection(state, clientId) || getParentSectionBlock(state, clientId)) {
return false;
}
return isSectionBlockCandidate(state, clientId);
}
function getEditedContentOnlySection(state) {
return state.editedContentOnlySection;
}
function isWithinEditedContentOnlySection(state, clientId) {
if (!state.editedContentOnlySection) {
return false;
}
if (state.editedContentOnlySection === clientId) {
return true;
}
let current = clientId;
while (current = state.blocks.parents.get(current)) {
if (state.editedContentOnlySection === current) {
return true;
}
}
return false;
}
var getBlockStyles = createSelector(
(state, clientIds) => clientIds.reduce((styles, clientId) => {
styles[clientId] = state.blocks.attributes.get(clientId)?.style;
return styles;
}, {}),
(state, clientIds) => [
...clientIds.map(
(clientId) => state.blocks.attributes.get(clientId)?.style
)
]
);
function getSectionRootClientId(state) {
return state.settings?.[sectionRootClientIdKey];
}
function isZoomOut(state) {
return state.zoomLevel === "auto-scaled" || state.zoomLevel < 100;
}
function getZoomLevel(state) {
return state.zoomLevel;
}
function getClosestAllowedInsertionPoint(state, name, clientId = "") {
const blockNames = Array.isArray(name) ? name : [name];
const areBlockNamesAllowedInClientId = (id) => blockNames.every(
(currentName) => canInsertBlockType(state, currentName, id)
);
if (!clientId) {
if (areBlockNamesAllowedInClientId(clientId)) {
return clientId;
}
const sectionRootClientId = getSectionRootClientId(state);
if (sectionRootClientId && areBlockNamesAllowedInClientId(sectionRootClientId)) {
return sectionRootClientId;
}
return null;
}
let current = clientId;
while (current !== null && !areBlockNamesAllowedInClientId(current)) {
const parentClientId = getBlockRootClientId(state, current);
current = parentClientId;
}
return current;
}
function getClosestAllowedInsertionPointForPattern(state, pattern, clientId) {
const { allowedBlockTypes } = getSettings(state);
const isAllowed = checkAllowListRecursive(
getGrammar(pattern),
allowedBlockTypes
);
if (!isAllowed) {
return null;
}
const names = getGrammar(pattern).map(({ blockName: name }) => name);
return getClosestAllowedInsertionPoint(state, names, clientId);
}
function getInsertionPoint(state) {
return state.insertionPoint;
}
var isBlockHiddenAnywhere = (state, clientId) => {
const blockName = getBlockName(state, clientId);
if (!hasBlockSupport(blockName, "visibility", true)) {
return false;
}
const attributes = state.blocks.attributes.get(clientId);
const blockVisibility = attributes?.metadata?.blockVisibility;
if (blockVisibility === false) {
return true;
}
if (typeof blockVisibility?.viewport === "object" && blockVisibility?.viewport !== null) {
return Object.values(BLOCK_VISIBILITY_VIEWPORTS).some(
(viewport) => blockVisibility?.viewport?.[viewport.key] === false
);
}
return false;
};
var isBlockHiddenEverywhere = (state, clientId) => {
const blockName = getBlockName(state, clientId);
if (!hasBlockSupport(blockName, "visibility", true)) {
return false;
}
const attributes = state.blocks.attributes.get(clientId);
const blockVisibility = attributes?.metadata?.blockVisibility;
if (blockVisibility === false) {
return true;
}
return false;
};
var isBlockParentHiddenEverywhere = (state, clientId) => {
const parents = getBlockParents(state, clientId);
return parents.some(
(parentId) => isBlockHiddenEverywhere(state, parentId)
);
};
var isBlockHiddenAtViewport = (state, clientId, viewport) => {
if (isBlockHiddenEverywhere(state, clientId)) {
return true;
}
const attributes = state.blocks.attributes.get(clientId);
const blockVisibilityViewport = attributes?.metadata?.blockVisibility?.viewport;
if (typeof blockVisibilityViewport === "object" && blockVisibilityViewport !== null && typeof viewport === "string") {
return blockVisibilityViewport?.[viewport.toLowerCase()] === false;
}
return false;
};
var isBlockParentHiddenAtViewport = (state, clientId, viewport) => {
const parents = getBlockParents(state, clientId);
return parents.some(
(parentId) => isBlockHiddenAtViewport(state, parentId, viewport)
);
};
function hasBlockSpotlight(state) {
return !!state.hasBlockSpotlight || !!state.editedContentOnlySection;
}
function isEditLockedBlock(state, clientId) {
const attributes = getBlockAttributes(state, clientId);
return !!attributes?.lock?.edit;
}
function isMoveLockedBlock(state, clientId) {
const attributes = getBlockAttributes(state, clientId);
if (attributes?.lock?.move !== void 0) {
return !!attributes?.lock?.move;
}
const rootClientId = getBlockRootClientId(state, clientId);
const templateLock = getTemplateLock(state, rootClientId);
return templateLock === "all";
}
function isRemoveLockedBlock(state, clientId) {
const attributes = getBlockAttributes(state, clientId);
if (attributes?.lock?.remove !== void 0) {
return !!attributes?.lock?.remove;
}
const rootClientId = getBlockRootClientId(state, clientId);
const templateLock = getTemplateLock(state, rootClientId);
return templateLock === "all" || templateLock === "insert";
}
function isLockedBlock(state, clientId) {
return isEditLockedBlock(state, clientId) || isMoveLockedBlock(state, clientId) || isRemoveLockedBlock(state, clientId);
}
function isListViewContentPanelOpen(state) {
return state.listViewContentPanelOpen;
}
function isListViewPanelOpened(state, clientId) {
if (state.openedListViewPanels?.allOpen) {
return true;
}
return state.openedListViewPanels?.panels?.[clientId] === true;
}
function getListViewExpandRevision(state) {
return state.listViewExpandRevision || 0;
}
function getViewportModalClientIds(state) {
return state.viewportModalClientIds;
}
function getRequestedInspectorTab(state) {
return state.requestedInspectorTab;
}
export {
getAllPatterns,
getBlockRemovalRules,
getBlockSettings,
getBlockStyles,
getBlockWithoutAttributes,
getClosestAllowedInsertionPoint,
getClosestAllowedInsertionPointForPattern,
getContentLockingParent,
getEditedContentOnlySection,
getEnabledBlockParents,
getEnabledClientIdsTree,
getExpandedBlock,
getInserterMediaCategories,
getInsertionPoint,
getLastFocus,
getLastInsertedBlocksClientIds,
getListViewExpandRevision,
getParentSectionBlock,
getPatternBySlug,
getRegisteredInserterMediaCategories,
getRemovalPromptData,
getRequestedInspectorTab,
getReusableBlocks,
getSectionRootClientId,
getStyleOverrides,
getViewportModalClientIds,
getZoomLevel,
hasAllowedPatterns,
hasBlockSpotlight,
isBlockHiddenAnywhere,
isBlockHiddenAtViewport,
isBlockHiddenEverywhere,
isBlockInterfaceHidden,
isBlockParentHiddenAtViewport,
isBlockParentHiddenEverywhere,
isBlockSubtreeDisabled,
isContainerInsertableToInContentOnlyMode,
isDragging,
isEditLockedBlock,
isListViewContentPanelOpen,
isListViewPanelOpened,
isLockedBlock,
isMoveLockedBlock,
isRemoveLockedBlock,
isSectionBlock,
isWithinEditedContentOnlySection,
isZoomOut
};
//# sourceMappingURL=private-selectors.mjs.map