All Downloads are FREE. Search and download functionalities are using the official Maven repository.

META-INF.resources.page_editor.app.components.LayoutBreadcrumbs.js Maven / Gradle / Ivy

The newest version!
/**
 * SPDX-FileCopyrightText: (c) 2000 Liferay, Inc. https://liferay.com
 * SPDX-License-Identifier: LGPL-2.1-or-later OR LicenseRef-Liferay-DXP-EULA-2.0.0-2023-06
 */

import ClayBreadcrumb from '@clayui/breadcrumb';
import {ReactPortal} from '@liferay/frontend-js-react-web';
import classNames from 'classnames';
import React, {useEffect, useMemo, useRef, useState} from 'react';
import {useDragLayer} from 'react-dnd';

import {ITEM_ACTIVATION_ORIGINS} from '../config/constants/itemActivationOrigins';
import {ITEM_TYPES} from '../config/constants/itemTypes';
import {LAYOUT_DATA_ITEM_TYPES} from '../config/constants/layoutDataItemTypes';
import {
	useActiveItemIds,
	useActiveItemType,
	useSelectItem,
} from '../contexts/ControlsContext';
import {useGlobalContext} from '../contexts/GlobalContext';
import {useSelectorCallback} from '../contexts/StoreContext';
import selectLayoutDataItemLabel from '../selectors/selectLayoutDataItemLabel';
import {deepEqual} from '../utils/checkDeepEqual';

const DROP_ZONE_BASE_LABEL = Liferay.Language.get('drop-zone');

/**
 * By default ClayBreadcrumbs leaves one item to each side of the breadcrumbs
 * Dropdown, plus the extra element that appears when the dropdown is needed.
 * @type {number}
 */
const ELLIPSIS_BUFFER_MARGIN = 4;

export function LayoutBreadcrumbs() {
	const activeItemIds = useActiveItemIds();

	const {isDragging} = useDragLayer((monitor) => ({
		isDragging: monitor.isDragging(),
	}));

	if (isDragging || activeItemIds.length > 1) {
		return null;
	}

	return ;
}

function LayoutBreadcrumbsContent() {
	const wrapperElement = useMemo(
		() => document.getElementById('wrapper'),
		[]
	);

	const breadcrumbItems = useBreadcrumbItems();
	const containerRef = useRef(null);
	const ellipsisBuffer = useEllipsisBuffer(breadcrumbItems, containerRef);

	useEffect(() => {
		if (!wrapperElement) {
			return;
		}

		wrapperElement.classList.add('page-editor__wrapper');

		wrapperElement.classList.toggle(
			'page-editor__wrapper--padded-block-end',
			breadcrumbItems.length
		);
	}, [wrapperElement, breadcrumbItems.length]);

	return wrapperElement ? (
		
			
) : null; } function useBreadcrumbItems() { const activeItemIds = useActiveItemIds(); const [activeItemId] = activeItemIds; const activeItemType = useActiveItemType(); const globalContext = useGlobalContext(); const selectItem = useSelectItem(); return useSelectorCallback( (state) => { const items = []; if (!activeItemId) { return items; } const addLayoutDataItems = (layoutDataItem) => { if ( !layoutDataItem || layoutDataItem.type === LAYOUT_DATA_ITEM_TYPES.root ) { return; } if ( layoutDataItem.type === LAYOUT_DATA_ITEM_TYPES.fragmentDropZone ) { const dropZoneId = document .querySelector(`[uuid="${layoutDataItem.itemId}"]`) ?.getAttribute('data-lfr-drop-zone-id'); items.push({ label: dropZoneId ? `${DROP_ZONE_BASE_LABEL} ${dropZoneId}` : DROP_ZONE_BASE_LABEL, }); } else { items.push({ label: selectLayoutDataItemLabel(state, layoutDataItem), onClick: () => selectItem(layoutDataItem.itemId, { itemType: ITEM_TYPES.layoutDataItem, origin: ITEM_ACTIVATION_ORIGINS.breadcrumbs, }), }); } addLayoutDataItems( state.layoutData.items[layoutDataItem.parentId] ); }; if (activeItemType === ITEM_TYPES.layoutDataItem) { addLayoutDataItems(state.layoutData.items[activeItemId]); } else if (activeItemType === ITEM_TYPES.editable) { const [, fragmentEntryLinkId, editableId] = activeItemId.match(/^([^-]+)-([^\n]+)$/); items.push({ label: editableId, onClick: () => selectItem(activeItemId, { itemType: ITEM_TYPES.editable, origin: ITEM_ACTIVATION_ORIGINS.breadcrumbs, }), }); const layoutDataItem = Object.values( state.layoutData.items ).find( (item) => item.type === LAYOUT_DATA_ITEM_TYPES.fragment && item.config.fragmentEntryLinkId === fragmentEntryLinkId ); addLayoutDataItems(layoutDataItem); } items.reverse(); if (items.length) { const lastItem = items[items.length - 1]; lastItem.active = true; } return items; }, [activeItemId, activeItemType, globalContext, selectItem], deepEqual ); } function useEllipsisBuffer(breacrumbItems, containerRef) { const [ellipsisBuffer, setEllipsisBuffer] = useState(0); useEffect(() => { const containerElement = containerRef.current; if (ellipsisBuffer !== 0) { return; } if (!breacrumbItems.length) { setEllipsisBuffer(1); return; } if (!containerElement) { setEllipsisBuffer(breacrumbItems.length); return; } const containerCopy = containerElement.cloneNode(true); const containerRect = containerElement.getBoundingClientRect(); containerCopy.style.opacity = '0'; containerCopy.style.pointerEvents = 'none'; containerCopy.style.height = `${containerRect.height}px`; containerCopy.style.width = `${containerRect.width}px`; const reduceEllipsisBuffer = () => { if (!document.body.contains(containerCopy)) { return; } const scrollContainer = containerCopy.firstElementChild; if (scrollContainer.clientWidth === scrollContainer.scrollWidth) { let nextEllipsisBuffer = containerCopy.querySelectorAll('.breadcrumb-item').length - ELLIPSIS_BUFFER_MARGIN; if (nextEllipsisBuffer <= 0) { nextEllipsisBuffer = breacrumbItems.length; } document.body.removeChild(containerCopy); setEllipsisBuffer(nextEllipsisBuffer); } else { const item = containerCopy.querySelector('.breadcrumb-item'); if (item) { item.parentElement.removeChild(item); requestAnimationFrame(reduceEllipsisBuffer); } else { document.body.removeChild(containerCopy); setEllipsisBuffer(breacrumbItems.length); } } }; document.body.appendChild(containerCopy); requestAnimationFrame(reduceEllipsisBuffer); return () => { if (document.body.contains(containerCopy)) { document.body.removeChild(containerCopy); } }; }, [containerRef, ellipsisBuffer, breacrumbItems.length]); return ellipsisBuffer; }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy