UNPKG

@prisma-cms/front-editor

Version:
214 lines 9.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const react_1 = require("react"); const react_2 = require("react"); // import CSSTransform from '../../../Tag/HtmlTag/CSSTransform' const nodeToEditorComponentObject_1 = require("../helpers/nodeToEditorComponentObject"); const interfaces_1 = require("../interfaces"); // TODO make generic // type P = EditorComponentProps // let updateCount = 0; /** * Хук для отслеживания изменений на HTML-элементе. * В какой момент должен срабатывать? Главное условие: выбрасываемые им изменения * не должны вызывать повторный апдейт этой же ноды, чтобы не возникало рекурсии. * То есть нужен флаг, который бы сигнализировал когда можно отслеживать DOM и отдавать изменения. */ const useMutationObserver = (container, // updateObject: EditorComponent["updateObject"], // setNewContent: React.Dispatch<React.SetStateAction<HtmlTagProps['object']['components']>> setNewContent, editMode) => { // const [newContent, setNewContent] = useState<HtmlTagProps['object']['components']>([]); // const context = useContext(Context); // console.log('useMutationObserver context', context); // console.log('newContent', newContent); // const saveChanges = useCallback(() => { // console.log('saveChanges newContent', newContent); // console.log('saveChanges updateObject', updateObject); // updateObject({ // components: newContent, // }); // setNewContent([]); // return true; // }, [newContent, updateObject]); const [contentEditable, setContentEditable] = react_1.useState(false); // const [selection, setSelection] = useState<Selection | null>(global.document?.getSelection() ?? null); // const [selection, setSelection] = useState<Selection | null>(null); // const closestInSelection = useCallback(<T extends HTMLElement>(selector: string): T | null => { // if (!selection?.focusNode) { // return null // } // let node: Node | null | undefined = selection.focusNode // if (node.nodeType === Node.TEXT_NODE) { // node = selection.focusNode?.parentNode // } // if (node && node instanceof Element) { // return node.closest(selector) // } // return null // }, [selection]); // TODO Надо будет перепроверить логику const onClick = react_2.useCallback((event) => { // const container = ref.current; /** * Prevent if already in edit mode */ if (contentEditable || !container) { return; } const composedPath = event.composedPath(); let canBeEditable = true; composedPath.every((path) => { // console.log("composedPath forEach path", path); var _a; // console.log("composedPath forEach path contenteditable", path instanceof HTMLElement && path.attributes.getNamedItem("contenteditable")?.value); /** * Break reduce on current container */ if (path === container) { return false; } // if (path instanceof HTMLElement && path.attributes.getNamedItem("contenteditable")?.value === "false") { if (path instanceof HTMLElement) { const contenteditable = (_a = path.attributes.getNamedItem('contenteditable')) === null || _a === void 0 ? void 0 : _a.value; if (contenteditable === 'false') { canBeEditable = false; return false; } } return true; }); /** * Prevent edit if not editable */ if (!canBeEditable) { return; } setContentEditable(true); event.currentTarget instanceof HTMLElement && event.currentTarget.focus(); // event.currentTarget.focus(); }, [container, contentEditable]); /** * Manager selection */ // const onSelectionChange = useCallback((_event) => { // console.log('onSelectionChange _event', _event); // // const container = ref.current; // const selection2 = document.getSelection() // if (selection2 && container && selection2.containsNode(container, true)) { // setSelection(selection2); // } // else { // setSelection(null); // } // }, [container]); // useEffect(() => { // document.addEventListener('selectionchange', onSelectionChange); // return () => { // document.removeEventListener('selectionchange', onSelectionChange); // } // }, [onSelectionChange]); react_2.useEffect(() => { // const container = ref.current; /** * Пока отключаем Этот блок */ // TODO Перепроверить логику if (editMode !== interfaces_1.ContentProxyEditMode.HTML) { return; } container === null || container === void 0 ? void 0 : container.addEventListener('click', onClick); return () => { container === null || container === void 0 ? void 0 : container.removeEventListener('click', onClick); }; }, [container, contentEditable, editMode, onClick]); react_2.useEffect(() => { // const container = ref.current; const onBlur = (_event) => { // TODO Add update handler // setContentEditable(false); }; container === null || container === void 0 ? void 0 : container.addEventListener('blur', onBlur); return () => { container === null || container === void 0 ? void 0 : container.removeEventListener('blur', onBlur); }; }, [container]); // const updateContent = useCallback(nodeToEditorComponentObject, []) const makeNewContent = react_2.useCallback(nodeToEditorComponentObject_1.nodeChildsToEditorComponentObjectComponents, []); const onChangeDom = react_2.useCallback((container) => { // updateCount++; // if (updateCount > 10) { // return; // } const content = makeNewContent(container); const { components } = content; // components && updateObject({ components }) // console.log('onChangeDom makeNewContent context', context); // console.log('onChangeDom makeNewContent context?.setNewContent', context?.setNewContent); components && setNewContent(components); }, [makeNewContent, setNewContent]); react_2.useEffect(() => { if (!container || editMode !== interfaces_1.ContentProxyEditMode.HTML) { return; } const config = { attributes: true, childList: true, subtree: true, characterData: true, }; // Create an observer instance linked to the callback function // const observer = new MutationObserver(this.onDOMSubtreeModified); const observer = new MutationObserver((changes) => { // console.log('onDomChanged changes', changes); // console.log('onDomChanged container.outerHTML', container.outerHTML); /** * Filter changes. Get only from editable container */ const nodes = changes.filter(({ target }) => { // if (target === container) { // return false; // } var _a; let node = target; // console.log('onDomChanged node', node); let success = false; // let parent: (Node & ParentNode) | null = target.parentNode; let i = 0; // eslint-disable-next-line no-cond-assign while (node && i < 100) { i++; if (!node) { break; } if (node === container) { success = true; break; } if (node instanceof HTMLElement && ((_a = node.attributes.getNamedItem('contenteditable')) === null || _a === void 0 ? void 0 : _a.value) === 'false') { // console.log("while parent", i, node, node.attributes.getNamedItem("contenteditable")?.value); break; } node = node === null || node === void 0 ? void 0 : node.parentNode; // break; } // console.log("parent", parent); return success; }); /** * If have changes on content, update state */ if (nodes.length) { onChangeDom(container); } }); // Start observing the target node for configured mutations observer.observe(container, config); return () => { observer.disconnect(); }; }, [container, editMode, onChangeDom]); }; exports.default = useMutationObserver; //# sourceMappingURL=useMutationObserver.js.map