diff --git a/app/src/protyle/util/editorCommonEvent.ts b/app/src/protyle/util/editorCommonEvent.ts index e473cca2d..860ce89dc 100644 --- a/app/src/protyle/util/editorCommonEvent.ts +++ b/app/src/protyle/util/editorCommonEvent.ts @@ -44,10 +44,25 @@ const moveToNew = (protyle: IProtyle, sourceElements: Element[], targetElement: const newSourceId = newSourceElement.getAttribute("data-node-id"); const doOperations: IOperation[] = []; const undoOperations: IOperation[] = []; - targetElement.insertAdjacentElement(isBottom ? "afterend" : "beforebegin", newSourceElement); + let ignoreInsert = false; + if (isBottom && + targetElement.getAttribute("data-type") === "NodeHeading" && + targetElement.getAttribute("fold") === "1") { + ignoreInsert = true; + } else if (!isBottom && targetElement.previousElementSibling && + targetElement.previousElementSibling.getAttribute("data-type") === "NodeHeading" && + targetElement.previousElementSibling.getAttribute("fold") === "1") { + ignoreInsert = true; + } + if (!ignoreInsert) { + targetElement.insertAdjacentElement(isBottom ? "afterend" : "beforebegin", newSourceElement); + } if (isBottom) { doOperations.push({ action: "insert", + context: { + ignoreProcess: ignoreInsert.toString(), + }, data: newSourceElement.outerHTML, id: newSourceId, previousID: targetId, @@ -55,6 +70,9 @@ const moveToNew = (protyle: IProtyle, sourceElements: Element[], targetElement: } else { doOperations.push({ action: "insert", + context: { + ignoreProcess: ignoreInsert.toString(), + }, data: newSourceElement.outerHTML, id: newSourceId, nextID: targetId, @@ -139,6 +157,7 @@ const moveToNew = (protyle: IProtyle, sourceElements: Element[], targetElement: id: newSourceId, }); return { + ignoreInsert, doOperations, undoOperations, topSourceElement, @@ -150,9 +169,31 @@ const moveTo = async (protyle: IProtyle, sourceElements: Element[], targetElemen let topSourceElement; const doOperations: IOperation[] = []; const undoOperations: IOperation[] = []; - const foldHeadingIds: { id: string, parentID: string }[] = []; + const copyFoldHeadingIds: string[] = []; const targetId = targetElement.getAttribute("data-node-id"); let tempTargetElement = targetElement; + let ignoreInsert = ""; + if (position === "afterend" && + targetElement.getAttribute("data-type") === "NodeHeading" && + targetElement.getAttribute("fold") === "1") { + ignoreInsert = targetElement.getAttribute("data-subtype"); + } else if (position === "beforebegin" && targetElement.previousElementSibling && + targetElement.previousElementSibling.getAttribute("data-type") === "NodeHeading" && + targetElement.previousElementSibling.getAttribute("fold") === "1") { + ignoreInsert = targetElement.getAttribute("data-subtype"); + } + if (ignoreInsert) { + let breakIgnore = false; + sourceElements.forEach(item => { + if (item.getAttribute("data-type") === "NodeHeading" && + parseInt(item.getAttribute("data-subtype")) >= parseInt(ignoreInsert)) { + breakIgnore = true; + } + if (!breakIgnore) { + item.setAttribute("data-remove", "true"); + } + }); + } sourceElements.reverse().forEach((item, index) => { const id = item.getAttribute("data-node-id"); const parentID = item.parentElement.getAttribute("data-node-id") || protyle.block.rootID; @@ -166,8 +207,7 @@ const moveTo = async (protyle: IProtyle, sourceElements: Element[], targetElemen } } if (isCopy && item.getAttribute("data-type") === "NodeHeading" && item.getAttribute("fold") === "1") { - item.removeAttribute("fold"); - foldHeadingIds.push({id, parentID}); + copyFoldHeadingIds.push(id); } let copyId; let copyElement; @@ -193,7 +233,10 @@ const moveTo = async (protyle: IProtyle, sourceElements: Element[], targetElemen } } + const needInset = !ignoreInsert || (ignoreInsert && !item.hasAttribute("data-remove")); + if (isCopy) { + item.removeAttribute("data-remove"); copyElement = item.cloneNode(true) as HTMLElement; copyElement.setAttribute("data-node-id", copyId); copyElement.querySelectorAll("[data-node-id]").forEach((e) => { @@ -201,20 +244,30 @@ const moveTo = async (protyle: IProtyle, sourceElements: Element[], targetElemen e.setAttribute("data-node-id", newId); e.setAttribute("updated", newId.split("-")[0]); }); - tempTargetElement.insertAdjacentElement(position, copyElement); + if (needInset) { + tempTargetElement.insertAdjacentElement(position, copyElement); + } doOperations.push({ action: "insert", + context: { + ignoreProcess: (!needInset).toString(), + }, id: copyId, data: copyElement.outerHTML, - previousID: position === "afterend" ? targetId : copyElement.previousElementSibling?.getAttribute("data-node-id"), // 不能使用常量,移动后会被修改 + previousID: position === "afterend" ? targetId : (!needInset ? targetElement : copyElement).previousElementSibling?.getAttribute("data-node-id"), // 不能使用常量,移动后会被修改 parentID: copyElement.parentElement?.getAttribute("data-node-id") || protyle.block.parentID || protyle.block.rootID, }); } else { - tempTargetElement.insertAdjacentElement(position, item); + if (needInset) { + tempTargetElement.insertAdjacentElement(position, item); + } doOperations.push({ action: "move", + context: { + ignoreProcess: (!needInset).toString(), + }, id, - previousID: position === "afterend" ? targetId : item.previousElementSibling?.getAttribute("data-node-id"), // 不能使用常量,移动后会被修改 + previousID: position === "afterend" ? targetId : (!needInset ? targetElement : item).previousElementSibling?.getAttribute("data-node-id"), // 不能使用常量,移动后会被修改 parentID: item.parentElement?.getAttribute("data-node-id") || protyle.block.parentID || protyle.block.rootID, }); } @@ -222,29 +275,24 @@ const moveTo = async (protyle: IProtyle, sourceElements: Element[], targetElemen tempTargetElement = isCopy ? copyElement : item; } }); - undoOperations.reverse(); - for (let j = 0; j < foldHeadingIds.length; j++) { - const childrenItem = foldHeadingIds[j]; - const headingIds = await fetchSyncPost("/api/block/getHeadingChildrenIDs", {id: childrenItem.id}); - headingIds.data.reverse().forEach((headingId: string) => { - undoOperations.push({ - action: "move", - id: headingId, - previousID: childrenItem.id, - parentID: childrenItem.parentID, - }); - }); - undoOperations.push({ - action: "foldHeading", - id: childrenItem.id, - data: "remove" - }); - doOperations.push({ - action: "unfoldHeading", - id: childrenItem.id, + if (ignoreInsert) { + // 不能在上一个循环中移除,否则会影响位置的判断和 tempTargetElement + sourceElements.forEach(item => { + if (item.hasAttribute("data-remove")) { + item.remove(); + } }); } + undoOperations.reverse(); + for (let j = 0; j < copyFoldHeadingIds.length; j++) { + const childrenItem = copyFoldHeadingIds[j]; + const responseTransaction = await fetchSyncPost("/api/block/getHeadingInsertTransaction", {id: childrenItem}); + doOperations.push(...responseTransaction.data.doOperations); + undoOperations.push(...responseTransaction.data.undoOperations); + } + // debugger return { + ignoreInsert: ignoreInsert ? true : false, doOperations, undoOperations, topSourceElement, @@ -622,6 +670,7 @@ const dragSame = async (protyle: IProtyle, sourceElements: Element[], targetElem newSourceElement.insertAdjacentHTML("beforeend", `