mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-06-14 12:02:31 +03:00
Imported at 0.17.1, Modified to work in-app. Added & configured test dependancies. Tests need to be altered to avoid using non-included deps including react dependancies.
126 lines
3.5 KiB
TypeScript
126 lines
3.5 KiB
TypeScript
/**
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
*/
|
|
|
|
import type {ElementNode} from '.';
|
|
import type {LexicalEditor} from './LexicalEditor';
|
|
import type {EditorState} from './LexicalEditorState';
|
|
import type {NodeKey, NodeMap} from './LexicalNode';
|
|
|
|
import {$isElementNode} from '.';
|
|
import {cloneDecorators} from './LexicalUtils';
|
|
|
|
export function $garbageCollectDetachedDecorators(
|
|
editor: LexicalEditor,
|
|
pendingEditorState: EditorState,
|
|
): void {
|
|
const currentDecorators = editor._decorators;
|
|
const pendingDecorators = editor._pendingDecorators;
|
|
let decorators = pendingDecorators || currentDecorators;
|
|
const nodeMap = pendingEditorState._nodeMap;
|
|
let key;
|
|
|
|
for (key in decorators) {
|
|
if (!nodeMap.has(key)) {
|
|
if (decorators === currentDecorators) {
|
|
decorators = cloneDecorators(editor);
|
|
}
|
|
|
|
delete decorators[key];
|
|
}
|
|
}
|
|
}
|
|
|
|
type IntentionallyMarkedAsDirtyElement = boolean;
|
|
|
|
function $garbageCollectDetachedDeepChildNodes(
|
|
node: ElementNode,
|
|
parentKey: NodeKey,
|
|
prevNodeMap: NodeMap,
|
|
nodeMap: NodeMap,
|
|
nodeMapDelete: Array<NodeKey>,
|
|
dirtyNodes: Map<NodeKey, IntentionallyMarkedAsDirtyElement>,
|
|
): void {
|
|
let child = node.getFirstChild();
|
|
|
|
while (child !== null) {
|
|
const childKey = child.__key;
|
|
// TODO Revise condition below, redundant? LexicalNode already cleans up children when moving Nodes
|
|
if (child.__parent === parentKey) {
|
|
if ($isElementNode(child)) {
|
|
$garbageCollectDetachedDeepChildNodes(
|
|
child,
|
|
childKey,
|
|
prevNodeMap,
|
|
nodeMap,
|
|
nodeMapDelete,
|
|
dirtyNodes,
|
|
);
|
|
}
|
|
|
|
// If we have created a node and it was dereferenced, then also
|
|
// remove it from out dirty nodes Set.
|
|
if (!prevNodeMap.has(childKey)) {
|
|
dirtyNodes.delete(childKey);
|
|
}
|
|
nodeMapDelete.push(childKey);
|
|
}
|
|
child = child.getNextSibling();
|
|
}
|
|
}
|
|
|
|
export function $garbageCollectDetachedNodes(
|
|
prevEditorState: EditorState,
|
|
editorState: EditorState,
|
|
dirtyLeaves: Set<NodeKey>,
|
|
dirtyElements: Map<NodeKey, IntentionallyMarkedAsDirtyElement>,
|
|
): void {
|
|
const prevNodeMap = prevEditorState._nodeMap;
|
|
const nodeMap = editorState._nodeMap;
|
|
// Store dirtyElements in a queue for later deletion; deleting dirty subtrees too early will
|
|
// hinder accessing .__next on child nodes
|
|
const nodeMapDelete: Array<NodeKey> = [];
|
|
|
|
for (const [nodeKey] of dirtyElements) {
|
|
const node = nodeMap.get(nodeKey);
|
|
if (node !== undefined) {
|
|
// Garbage collect node and its children if they exist
|
|
if (!node.isAttached()) {
|
|
if ($isElementNode(node)) {
|
|
$garbageCollectDetachedDeepChildNodes(
|
|
node,
|
|
nodeKey,
|
|
prevNodeMap,
|
|
nodeMap,
|
|
nodeMapDelete,
|
|
dirtyElements,
|
|
);
|
|
}
|
|
// If we have created a node and it was dereferenced, then also
|
|
// remove it from out dirty nodes Set.
|
|
if (!prevNodeMap.has(nodeKey)) {
|
|
dirtyElements.delete(nodeKey);
|
|
}
|
|
nodeMapDelete.push(nodeKey);
|
|
}
|
|
}
|
|
}
|
|
for (const nodeKey of nodeMapDelete) {
|
|
nodeMap.delete(nodeKey);
|
|
}
|
|
|
|
for (const nodeKey of dirtyLeaves) {
|
|
const node = nodeMap.get(nodeKey);
|
|
if (node !== undefined && !node.isAttached()) {
|
|
if (!prevNodeMap.has(nodeKey)) {
|
|
dirtyLeaves.delete(nodeKey);
|
|
}
|
|
nodeMap.delete(nodeKey);
|
|
}
|
|
}
|
|
}
|