This commit is contained in:
Vanessa 2022-06-15 23:05:14 +08:00
parent c533dd49a8
commit 9084fe20b0
4 changed files with 97 additions and 59 deletions

View file

@ -6,6 +6,50 @@ import {transaction, updateTransaction} from "../protyle/wysiwyg/transaction";
import {scrollCenter} from "../util/highlightById"; import {scrollCenter} from "../util/highlightById";
import {Constants} from "../constants"; import {Constants} from "../constants";
export const cancelSB = (protyle: IProtyle, nodeElement: Element) => {
const doOperations: IOperation[] = [];
const undoOperations: IOperation[] = [];
let previousId = nodeElement.previousElementSibling ? nodeElement.previousElementSibling.getAttribute("data-node-id") : undefined;
nodeElement.classList.remove("protyle-wysiwyg--select");
const id = nodeElement.getAttribute("data-node-id")
const sbElement = genSBElement(nodeElement.getAttribute("data-sb-layout"), id, nodeElement.lastElementChild.outerHTML);
undoOperations.push({
action: "insert",
id,
data: sbElement.outerHTML,
previousID: nodeElement.previousElementSibling ? nodeElement.previousElementSibling.getAttribute("data-node-id") : undefined,
parentID: nodeElement.parentElement.getAttribute("data-node-id") || protyle.block.parentID
});
Array.from(nodeElement.children).forEach((item, index) => {
if (index === nodeElement.childElementCount - 1) {
doOperations.push({
action: "delete",
id,
});
nodeElement.lastElementChild.remove();
nodeElement.outerHTML = nodeElement.innerHTML;
return;
}
doOperations.push({
action: "move",
id: item.getAttribute("data-node-id"),
previousID: previousId,
parentID: nodeElement.parentElement.getAttribute("data-node-id") || protyle.block.parentID
});
undoOperations.push({
action: "move",
id: item.getAttribute("data-node-id"),
previousID: item.previousElementSibling ? item.previousElementSibling.getAttribute("data-node-id") : undefined,
parentID: id
});
previousId = item.getAttribute("data-node-id");
});
return {
doOperations, undoOperations, previousId
}
}
export const genSBElement = (layout: string, id?: string, attrHTML?: string) => { export const genSBElement = (layout: string, id?: string, attrHTML?: string) => {
const sbElement = document.createElement("div"); const sbElement = document.createElement("div");
sbElement.setAttribute("data-node-id", id || Lute.NewNodeID()); sbElement.setAttribute("data-node-id", id || Lute.NewNodeID());

View file

@ -16,7 +16,7 @@ import {removeEmbed} from "../wysiwyg/removeEmbed";
import {getContenteditableElement, getTopAloneElement, isNotEditBlock} from "../wysiwyg/getBlock"; import {getContenteditableElement, getTopAloneElement, isNotEditBlock} from "../wysiwyg/getBlock";
import * as dayjs from "dayjs"; import * as dayjs from "dayjs";
import {fetchPost} from "../../util/fetch"; import {fetchPost} from "../../util/fetch";
import {genSBElement, insertEmptyBlock} from "../../block/util"; import {cancelSB, insertEmptyBlock} from "../../block/util";
import {scrollCenter} from "../../util/highlightById"; import {scrollCenter} from "../../util/highlightById";
import {isMobile} from "../../util/functions"; import {isMobile} from "../../util/functions";
import {confirmDialog} from "../../dialog/confirmDialog"; import {confirmDialog} from "../../dialog/confirmDialog";
@ -883,44 +883,9 @@ export class Gutter {
window.siyuan.menus.menu.append(new MenuItem({ window.siyuan.menus.menu.append(new MenuItem({
label: window.siyuan.languages.cancel + " " + window.siyuan.languages.superBlock, label: window.siyuan.languages.cancel + " " + window.siyuan.languages.superBlock,
click() { click() {
const doOperations: IOperation[] = []; const sbData = cancelSB(protyle, nodeElement);
const undoOperations: IOperation[] = []; transaction(protyle, sbData.doOperations, sbData.undoOperations);
let previousId = nodeElement.previousElementSibling ? nodeElement.previousElementSibling.getAttribute("data-node-id") : undefined; focusBlock(protyle.wysiwyg.element.querySelector(`[data-node-id="${sbData.previousId}"]`));
nodeElement.classList.remove("protyle-wysiwyg--select");
const sbElement = genSBElement(nodeElement.getAttribute("data-sb-layout"), id, nodeElement.lastElementChild.outerHTML);
undoOperations.push({
action: "insert",
id,
data: sbElement.outerHTML,
previousID: nodeElement.previousElementSibling ? nodeElement.previousElementSibling.getAttribute("data-node-id") : undefined,
parentID: nodeElement.parentElement.getAttribute("data-node-id") || protyle.block.parentID
});
Array.from(nodeElement.children).forEach((item, index) => {
if (index === nodeElement.childElementCount - 1) {
doOperations.push({
action: "delete",
id,
});
nodeElement.lastElementChild.remove();
nodeElement.outerHTML = nodeElement.innerHTML;
return;
}
doOperations.push({
action: "move",
id: item.getAttribute("data-node-id"),
previousID: previousId,
parentID: nodeElement.parentElement.getAttribute("data-node-id") || protyle.block.parentID
});
undoOperations.push({
action: "move",
id: item.getAttribute("data-node-id"),
previousID: item.previousElementSibling ? item.previousElementSibling.getAttribute("data-node-id") : undefined,
parentID: id
});
previousId = item.getAttribute("data-node-id");
});
transaction(protyle, doOperations, undoOperations);
focusBlock(protyle.wysiwyg.element.querySelector(`[data-node-id="${previousId}"]`));
hideElements(["gutter"], protyle); hideElements(["gutter"], protyle);
} }
}).element); }).element);

View file

@ -139,6 +139,7 @@ export const getTopAloneElement = (topSourceElement: Element) => {
} else if (topSourceElement.parentElement.getAttribute("data-type") === "NodeListItem" && topSourceElement.parentElement.childElementCount === 3) { } else if (topSourceElement.parentElement.getAttribute("data-type") === "NodeListItem" && topSourceElement.parentElement.childElementCount === 3) {
topSourceElement = topSourceElement.parentElement; topSourceElement = topSourceElement.parentElement;
} else { } else {
topSourceElement = getTopAloneElement(topSourceElement);
break; break;
} }
} }

View file

@ -8,7 +8,7 @@ import {
getTopEmptyElement, hasNextSibling getTopEmptyElement, hasNextSibling
} from "./getBlock"; } from "./getBlock";
import {transaction, updateTransaction} from "./transaction"; import {transaction, updateTransaction} from "./transaction";
import {genEmptyElement} from "../../block/util"; import {cancelSB, genEmptyElement} from "../../block/util";
import {listOutdent, updateListOrder} from "./list"; import {listOutdent, updateListOrder} from "./list";
import {setFold, zoomOut} from "../../menus/protyle"; import {setFold, zoomOut} from "../../menus/protyle";
import {preventScroll} from "../scroll/preventScroll"; import {preventScroll} from "../scroll/preventScroll";
@ -180,9 +180,11 @@ export const removeBlock = (protyle: IProtyle, blockElement: Element, range: Ran
let sideElement = selectElements[0].previousElementSibling || selectElements[selectElements.length - 1].nextElementSibling; let sideElement = selectElements[0].previousElementSibling || selectElements[selectElements.length - 1].nextElementSibling;
let listElement: Element; let listElement: Element;
let topElementId: string; let topElementId: string;
let topParentElement: Element
selectElements.find((item: HTMLElement) => { selectElements.find((item: HTMLElement) => {
item.classList.remove("protyle-wysiwyg--select"); item.classList.remove("protyle-wysiwyg--select");
const topElement = getTopAloneElement(item); const topElement = getTopAloneElement(item);
topParentElement = topElement.parentElement
topElementId = topElement.getAttribute("data-node-id"); topElementId = topElement.getAttribute("data-node-id");
const id = topElement.getAttribute("data-node-id"); const id = topElement.getAttribute("data-node-id");
deletes.push({ deletes.push({
@ -238,8 +240,7 @@ export const removeBlock = (protyle: IProtyle, blockElement: Element, range: Ran
zoomOut(protyle, protyle.block.parent2ID, protyle.block.parent2ID); zoomOut(protyle, protyle.block.parent2ID, protyle.block.parent2ID);
}, Constants.TIMEOUT_INPUT * 2 + 100); }, Constants.TIMEOUT_INPUT * 2 + 100);
} else { } else {
if ((sideElement.classList.contains("protyle-wysiwyg") && protyle.wysiwyg.element.childElementCount === 0) || if ((sideElement.classList.contains("protyle-wysiwyg") && protyle.wysiwyg.element.childElementCount === 0)) {
((sideElement.classList.contains("bq") || sideElement.classList.contains("sb")) && sideElement.childElementCount === 1)) {
const emptyElement = genEmptyElement(false, true, topElementId); const emptyElement = genEmptyElement(false, true, topElementId);
sideElement.insertAdjacentElement("afterbegin", emptyElement); sideElement.insertAdjacentElement("afterbegin", emptyElement);
deletes.push({ deletes.push({
@ -273,8 +274,14 @@ export const removeBlock = (protyle: IProtyle, blockElement: Element, range: Ran
} }
} }
if (deletes.length > 0) { if (deletes.length > 0) {
transaction(protyle, deletes, inserts.reverse()); if (topParentElement && topParentElement.getAttribute("data-type") === "NodeSuperBlock" && topParentElement.childElementCount === 2) {
const sbData = cancelSB(protyle, topParentElement);
transaction(protyle, deletes.concat(sbData.doOperations), sbData.undoOperations.concat(inserts.reverse()));
} else {
transaction(protyle, deletes, inserts.reverse());
}
} }
hideElements(["util"], protyle); hideElements(["util"], protyle);
return; return;
} }
@ -371,29 +378,42 @@ export const removeBlock = (protyle: IProtyle, blockElement: Element, range: Ran
return; return;
} }
const parentElement = blockElement.parentElement
const editableElement = getContenteditableElement(blockElement); const editableElement = getContenteditableElement(blockElement);
const previousLastElement = getLastBlock(previousElement) as HTMLElement; const previousLastElement = getLastBlock(previousElement) as HTMLElement;
const isSelectNode = previousLastElement && (previousLastElement.classList.contains("table") || previousLastElement.classList.contains("render-node") || previousLastElement.classList.contains("iframe") || previousLastElement.classList.contains("hr") || previousLastElement.classList.contains("code-block")); const isSelectNode = previousLastElement && (previousLastElement.classList.contains("table") || previousLastElement.classList.contains("render-node") || previousLastElement.classList.contains("iframe") || previousLastElement.classList.contains("hr") || previousLastElement.classList.contains("code-block"));
if (isSelectNode) { if (isSelectNode) {
if (previousLastElement.classList.contains("code-block")) { if (previousLastElement.classList.contains("code-block")) {
focusBlock(previousLastElement, undefined, false);
if (editableElement.textContent.trim() === "") { if (editableElement.textContent.trim() === "") {
const previousId = previousLastElement.getAttribute("data-node-id")
const id = blockElement.getAttribute("data-node-id"); const id = blockElement.getAttribute("data-node-id");
transaction(protyle, [{ const doOperations: IOperation[] = [{
action: "delete", action: "delete",
id, id,
}], [{ }]
const undoOperations: IOperation[] = [{
action: "insert", action: "insert",
data: blockElement.outerHTML, data: blockElement.outerHTML,
id: id, id: id,
previousID: previousLastElement.getAttribute("data-node-id") previousID: blockElement.previousElementSibling?.getAttribute("data-node-id"),
}]); parentID: blockElement.parentElement.getAttribute("data-node-id")
}]
blockElement.remove(); blockElement.remove();
// 取消超级块
if (parentElement.getAttribute("data-type") === "NodeSuperBlock" && parentElement.childElementCount === 2) {
const sbData = cancelSB(protyle, parentElement);
transaction(protyle, doOperations.concat(sbData.doOperations), sbData.undoOperations.concat(undoOperations));
} else {
transaction(protyle, doOperations, undoOperations);
}
focusBlock(protyle.wysiwyg.element.querySelector(`[data-node-id="${previousId}"]`), undefined, false);
} else {
focusBlock(previousLastElement, undefined, false);
} }
return; return;
} }
previousLastElement.classList.add("protyle-wysiwyg--select"); previousLastElement.classList.add("protyle-wysiwyg--select");
if (previousLastElement.getAttribute("data-type") === "NodeBlockQueryEmbed" || editableElement.textContent !== "" || protyle.wysiwyg.element.childElementCount === 2) { if (previousLastElement.getAttribute("data-type") === "NodeBlockQueryEmbed" || editableElement.textContent !== "") {
focusByRange(range); focusByRange(range);
return; return;
} }
@ -412,7 +432,12 @@ export const removeBlock = (protyle: IProtyle, blockElement: Element, range: Ran
data: removeElement.outerHTML, data: removeElement.outerHTML,
id: removeId, id: removeId,
// 不能使用 previousLastElement否则在超级块下的元素前删除撤销错误 // 不能使用 previousLastElement否则在超级块下的元素前删除撤销错误
previousID: previousElement.getAttribute("data-node-id"), previousID: blockElement.previousElementSibling?.getAttribute("data-node-id"),
parentID: parentElement.getAttribute("data-node-id")
}];
const doOperations: IOperation[] = [{
action: "delete",
id: removeId,
}]; }];
if (isSelectNode) { if (isSelectNode) {
@ -441,14 +466,17 @@ export const removeBlock = (protyle: IProtyle, blockElement: Element, range: Ran
// extractContents 内容过多时需要进行滚动条重置,否则位置会错位 // extractContents 内容过多时需要进行滚动条重置,否则位置会错位
protyle.contentElement.scrollTop = scroll; protyle.contentElement.scrollTop = scroll;
protyle.scroll.lastScrollTop = scroll - 1; protyle.scroll.lastScrollTop = scroll - 1;
doOperations.push({
action: "update",
data: previousLastElement.outerHTML,
id: newId,
})
} }
transaction(protyle, [{ if (parentElement.getAttribute("data-type") === "NodeSuperBlock" && parentElement.childElementCount === 2) {
action: "delete", const sbData = cancelSB(protyle, parentElement);
id: removeId, transaction(protyle, doOperations.concat(sbData.doOperations), sbData.undoOperations.concat(undoOperations));
}, { } else {
action: "update", transaction(protyle, doOperations, undoOperations);
data: previousLastElement.outerHTML, }
id: newId, focusByWbr(protyle.wysiwyg.element, range);
}], undoOperations);
focusByWbr(previousLastElement, range);
}; };