2023-05-07 23:38:03 +08:00
|
|
|
|
import {focusBlock, focusByRange, getRangeByPoint} from "./selection";
|
2023-10-26 23:17:27 +08:00
|
|
|
|
import {
|
|
|
|
|
|
hasClosestBlock,
|
|
|
|
|
|
hasClosestByAttribute,
|
|
|
|
|
|
hasClosestByClassName,
|
|
|
|
|
|
hasClosestByTag,
|
2024-09-22 19:43:10 +08:00
|
|
|
|
hasTopClosestByAttribute,
|
|
|
|
|
|
isInEmbedBlock
|
2023-10-26 23:17:27 +08:00
|
|
|
|
} from "./hasClosest";
|
2022-05-26 15:18:53 +08:00
|
|
|
|
import {Constants} from "../../constants";
|
|
|
|
|
|
import {paste} from "./paste";
|
2024-08-10 17:11:49 +08:00
|
|
|
|
import {cancelSB, genEmptyElement, genSBElement, insertEmptyBlock} from "../../block/util";
|
2024-10-18 22:46:41 +08:00
|
|
|
|
import {transaction, turnsIntoOneTransaction} from "../wysiwyg/transaction";
|
2022-05-26 15:18:53 +08:00
|
|
|
|
import {getTopAloneElement} from "../wysiwyg/getBlock";
|
|
|
|
|
|
import {updateListOrder} from "../wysiwyg/list";
|
|
|
|
|
|
import {fetchPost, fetchSyncPost} from "../../util/fetch";
|
|
|
|
|
|
import {onGet} from "./onGet";
|
2022-06-30 15:56:44 +08:00
|
|
|
|
/// #if !MOBILE
|
2024-06-17 00:37:12 +08:00
|
|
|
|
import {getAllEditor} from "../../layout/getAll";
|
2022-06-30 15:56:44 +08:00
|
|
|
|
import {updatePanelByEditor} from "../../editor/util";
|
|
|
|
|
|
/// #endif
|
2023-06-07 10:36:20 +08:00
|
|
|
|
import {blockRender} from "../render/blockRender";
|
2022-08-24 14:46:39 +08:00
|
|
|
|
import {uploadLocalFiles} from "../upload";
|
|
|
|
|
|
import {insertHTML} from "./insertHTML";
|
2022-10-07 10:41:36 +08:00
|
|
|
|
import {isBrowser} from "../../util/functions";
|
2022-11-22 15:54:47 +08:00
|
|
|
|
import {hideElements} from "../ui/hideElements";
|
2023-10-13 11:08:56 +08:00
|
|
|
|
import {insertAttrViewBlockAnimation} from "../render/av/row";
|
2023-10-29 19:06:01 +08:00
|
|
|
|
import {dragUpload} from "../render/av/asset";
|
2024-03-08 21:37:42 +08:00
|
|
|
|
import * as dayjs from "dayjs";
|
2024-05-27 22:47:41 +08:00
|
|
|
|
import {zoomOut} from "../../menus/protyle";
|
2024-10-16 22:25:53 +08:00
|
|
|
|
/// #if !BROWSER
|
|
|
|
|
|
import {webUtils} from "electron";
|
|
|
|
|
|
/// #endif
|
2025-06-30 12:26:47 +08:00
|
|
|
|
import {addDragFill, getTypeByCellElement} from "../render/av/cell";
|
2025-01-29 23:25:43 +08:00
|
|
|
|
import {processClonePHElement} from "../render/util";
|
2025-06-18 11:50:33 +08:00
|
|
|
|
import {insertGalleryItemAnimation} from "../render/av/gallery/item";
|
2025-06-20 10:58:34 +08:00
|
|
|
|
import {clearSelect} from "./clearSelect";
|
2025-07-08 23:29:36 +08:00
|
|
|
|
import {dragoverTab} from "../render/av/view";
|
2022-05-26 15:18:53 +08:00
|
|
|
|
|
2022-11-24 00:44:20 +08:00
|
|
|
|
const moveToNew = (protyle: IProtyle, sourceElements: Element[], targetElement: Element, newSourceElement: Element,
|
|
|
|
|
|
isSameDoc: boolean, isBottom: boolean, isCopy: boolean) => {
|
|
|
|
|
|
let topSourceElement;
|
|
|
|
|
|
const targetId = targetElement.getAttribute("data-node-id");
|
2022-11-25 23:09:16 +08:00
|
|
|
|
const newSourceId = newSourceElement.getAttribute("data-node-id");
|
2022-11-24 00:44:20 +08:00
|
|
|
|
const doOperations: IOperation[] = [];
|
|
|
|
|
|
const undoOperations: IOperation[] = [];
|
|
|
|
|
|
targetElement.insertAdjacentElement(isBottom ? "afterend" : "beforebegin", newSourceElement);
|
|
|
|
|
|
if (isBottom) {
|
|
|
|
|
|
doOperations.push({
|
|
|
|
|
|
action: "insert",
|
|
|
|
|
|
data: newSourceElement.outerHTML,
|
|
|
|
|
|
id: newSourceId,
|
|
|
|
|
|
previousID: targetId,
|
2022-11-25 23:09:16 +08:00
|
|
|
|
});
|
2022-11-24 00:44:20 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
doOperations.push({
|
|
|
|
|
|
action: "insert",
|
|
|
|
|
|
data: newSourceElement.outerHTML,
|
|
|
|
|
|
id: newSourceId,
|
|
|
|
|
|
nextID: targetId,
|
2022-11-25 23:09:16 +08:00
|
|
|
|
});
|
2022-11-24 00:44:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
sourceElements.reverse().forEach((item, index) => {
|
2022-11-25 23:09:16 +08:00
|
|
|
|
const itemId = item.getAttribute("data-node-id");
|
2022-11-24 00:44:20 +08:00
|
|
|
|
if (index === sourceElements.length - 1) {
|
|
|
|
|
|
topSourceElement = getTopAloneElement(item);
|
2025-07-23 12:21:59 +08:00
|
|
|
|
if (topSourceElement === item) {
|
2022-11-24 00:44:20 +08:00
|
|
|
|
topSourceElement = undefined;
|
2024-11-16 12:03:08 +08:00
|
|
|
|
// 单个缩放或反链面板中的列表项拖拽到包含该列表的编辑器中会导致残留的 list
|
|
|
|
|
|
Array.from(protyle.wysiwyg.element.querySelectorAll(`[data-node-id="${item.getAttribute("data-node-id")}"]`)).find((targetItem: HTMLElement) => {
|
|
|
|
|
|
if (!isInEmbedBlock(targetItem) && targetItem.parentElement.querySelectorAll(".li").length === 1) {
|
|
|
|
|
|
topSourceElement = targetItem.parentElement;
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
2022-11-24 00:44:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2022-11-25 23:09:16 +08:00
|
|
|
|
const copyId = Lute.NewNodeID();
|
2022-11-24 00:44:20 +08:00
|
|
|
|
if (isCopy) {
|
|
|
|
|
|
undoOperations.push({
|
|
|
|
|
|
action: "delete",
|
|
|
|
|
|
id: copyId,
|
|
|
|
|
|
});
|
|
|
|
|
|
} else {
|
|
|
|
|
|
undoOperations.push({
|
|
|
|
|
|
action: "move",
|
|
|
|
|
|
id: itemId,
|
|
|
|
|
|
previousID: item.previousElementSibling?.getAttribute("data-node-id"),
|
|
|
|
|
|
parentID: item.parentElement.getAttribute("data-node-id") || protyle.block.rootID,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!isSameDoc && !isCopy) {
|
|
|
|
|
|
// 打开两个相同的文档
|
|
|
|
|
|
const sameElement = protyle.wysiwyg.element.querySelector(`[data-node-id="${itemId}"]`);
|
|
|
|
|
|
if (sameElement) {
|
|
|
|
|
|
sameElement.remove();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (isCopy) {
|
|
|
|
|
|
const copyElement = item.cloneNode(true) as HTMLElement;
|
|
|
|
|
|
copyElement.setAttribute("data-node-id", copyId);
|
|
|
|
|
|
copyElement.querySelectorAll("[data-node-id]").forEach((e) => {
|
|
|
|
|
|
const newId = Lute.NewNodeID();
|
|
|
|
|
|
e.setAttribute("data-node-id", newId);
|
|
|
|
|
|
e.setAttribute("updated", newId.split("-")[0]);
|
|
|
|
|
|
});
|
|
|
|
|
|
newSourceElement.insertAdjacentElement("afterbegin", copyElement);
|
|
|
|
|
|
doOperations.push({
|
|
|
|
|
|
action: "insert",
|
|
|
|
|
|
id: copyId,
|
|
|
|
|
|
data: copyElement.outerHTML,
|
|
|
|
|
|
parentID: newSourceId,
|
|
|
|
|
|
});
|
|
|
|
|
|
} else {
|
|
|
|
|
|
newSourceElement.insertAdjacentElement("afterbegin", item);
|
|
|
|
|
|
doOperations.push({
|
|
|
|
|
|
action: "move",
|
|
|
|
|
|
id: itemId,
|
|
|
|
|
|
parentID: newSourceId,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
undoOperations.reverse();
|
|
|
|
|
|
if (newSourceElement.getAttribute("data-subtype") === "o") {
|
|
|
|
|
|
undoOperations.splice(0, 0, {
|
|
|
|
|
|
action: "update",
|
|
|
|
|
|
id: newSourceId,
|
|
|
|
|
|
data: newSourceElement.outerHTML
|
|
|
|
|
|
});
|
|
|
|
|
|
updateListOrder(newSourceElement, 1);
|
|
|
|
|
|
doOperations.push({
|
|
|
|
|
|
action: "update",
|
|
|
|
|
|
id: newSourceId,
|
|
|
|
|
|
data: newSourceElement.outerHTML
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
undoOperations.push({
|
|
|
|
|
|
action: "delete",
|
|
|
|
|
|
id: newSourceId,
|
|
|
|
|
|
});
|
|
|
|
|
|
return {
|
|
|
|
|
|
doOperations,
|
|
|
|
|
|
undoOperations,
|
|
|
|
|
|
topSourceElement,
|
|
|
|
|
|
};
|
2022-11-25 23:09:16 +08:00
|
|
|
|
};
|
2022-11-24 00:44:20 +08:00
|
|
|
|
|
2022-11-23 22:05:29 +08:00
|
|
|
|
const moveTo = async (protyle: IProtyle, sourceElements: Element[], targetElement: Element,
|
|
|
|
|
|
isSameDoc: boolean, position: InsertPosition, isCopy: boolean) => {
|
2022-11-22 21:54:52 +08:00
|
|
|
|
let topSourceElement;
|
|
|
|
|
|
const doOperations: IOperation[] = [];
|
|
|
|
|
|
const undoOperations: IOperation[] = [];
|
|
|
|
|
|
const foldHeadingIds: { id: string, parentID: string }[] = [];
|
|
|
|
|
|
const targetId = targetElement.getAttribute("data-node-id");
|
|
|
|
|
|
let tempTargetElement = targetElement;
|
2022-11-22 18:50:00 +08:00
|
|
|
|
sourceElements.reverse().forEach((item, index) => {
|
2022-11-22 11:02:04 +08:00
|
|
|
|
const id = item.getAttribute("data-node-id");
|
2022-11-22 21:54:52 +08:00
|
|
|
|
const parentID = item.parentElement.getAttribute("data-node-id") || protyle.block.rootID;
|
2022-11-22 11:02:04 +08:00
|
|
|
|
if (index === sourceElements.length - 1) {
|
|
|
|
|
|
topSourceElement = getTopAloneElement(item);
|
2025-07-23 12:21:59 +08:00
|
|
|
|
if (topSourceElement === item) {
|
2022-11-22 11:02:04 +08:00
|
|
|
|
topSourceElement = undefined;
|
|
|
|
|
|
} else if (topSourceElement.contains(item) && topSourceElement.contains(targetElement)) {
|
|
|
|
|
|
// * * 1 列表项拖拽到父级列表项下 https://ld246.com/article/1665448570858
|
|
|
|
|
|
topSourceElement = targetElement;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2022-12-28 15:10:43 +08:00
|
|
|
|
if (isCopy && item.getAttribute("data-type") === "NodeHeading" && item.getAttribute("fold") === "1") {
|
2022-11-22 11:02:04 +08:00
|
|
|
|
item.removeAttribute("fold");
|
2022-12-28 15:10:43 +08:00
|
|
|
|
foldHeadingIds.push({id, parentID});
|
2022-11-22 11:02:04 +08:00
|
|
|
|
}
|
2022-11-25 23:09:16 +08:00
|
|
|
|
let copyId;
|
|
|
|
|
|
let copyElement;
|
2022-11-23 22:05:29 +08:00
|
|
|
|
if (isCopy) {
|
|
|
|
|
|
copyId = Lute.NewNodeID();
|
|
|
|
|
|
undoOperations.push({
|
|
|
|
|
|
action: "delete",
|
|
|
|
|
|
id: copyId,
|
|
|
|
|
|
});
|
|
|
|
|
|
} else {
|
|
|
|
|
|
undoOperations.push({
|
|
|
|
|
|
action: "move",
|
|
|
|
|
|
id,
|
|
|
|
|
|
previousID: item.previousElementSibling?.getAttribute("data-node-id"),
|
|
|
|
|
|
parentID,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!isSameDoc && !isCopy) {
|
2022-11-22 11:02:04 +08:00
|
|
|
|
// 打开两个相同的文档
|
|
|
|
|
|
const sameElement = protyle.wysiwyg.element.querySelector(`[data-node-id="${id}"]`);
|
|
|
|
|
|
if (sameElement) {
|
|
|
|
|
|
sameElement.remove();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2022-11-23 22:05:29 +08:00
|
|
|
|
|
|
|
|
|
|
if (isCopy) {
|
|
|
|
|
|
copyElement = item.cloneNode(true) as HTMLElement;
|
|
|
|
|
|
copyElement.setAttribute("data-node-id", copyId);
|
|
|
|
|
|
copyElement.querySelectorAll("[data-node-id]").forEach((e) => {
|
|
|
|
|
|
const newId = Lute.NewNodeID();
|
|
|
|
|
|
e.setAttribute("data-node-id", newId);
|
|
|
|
|
|
e.setAttribute("updated", newId.split("-")[0]);
|
|
|
|
|
|
});
|
|
|
|
|
|
tempTargetElement.insertAdjacentElement(position, copyElement);
|
|
|
|
|
|
doOperations.push({
|
|
|
|
|
|
action: "insert",
|
|
|
|
|
|
id: copyId,
|
|
|
|
|
|
data: copyElement.outerHTML,
|
2023-01-16 23:44:44 +08:00
|
|
|
|
previousID: position === "afterend" ? targetId : copyElement.previousElementSibling?.getAttribute("data-node-id"), // 不能使用常量,移动后会被修改
|
|
|
|
|
|
parentID: copyElement.parentElement?.getAttribute("data-node-id") || protyle.block.parentID || protyle.block.rootID,
|
2022-11-23 22:05:29 +08:00
|
|
|
|
});
|
|
|
|
|
|
} else {
|
|
|
|
|
|
tempTargetElement.insertAdjacentElement(position, item);
|
|
|
|
|
|
doOperations.push({
|
|
|
|
|
|
action: "move",
|
|
|
|
|
|
id,
|
|
|
|
|
|
previousID: position === "afterend" ? targetId : item.previousElementSibling?.getAttribute("data-node-id"), // 不能使用常量,移动后会被修改
|
|
|
|
|
|
parentID: item.parentElement?.getAttribute("data-node-id") || protyle.block.parentID || protyle.block.rootID,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2022-11-22 18:50:00 +08:00
|
|
|
|
if (position !== "afterend") {
|
2022-11-23 22:05:29 +08:00
|
|
|
|
tempTargetElement = isCopy ? copyElement : item;
|
2022-11-22 18:50:00 +08:00
|
|
|
|
}
|
2022-11-22 21:54:52 +08:00
|
|
|
|
});
|
2022-11-22 11:02:04 +08:00
|
|
|
|
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,
|
|
|
|
|
|
});
|
2022-11-22 21:54:52 +08:00
|
|
|
|
});
|
2022-11-22 11:02:04 +08:00
|
|
|
|
undoOperations.push({
|
|
|
|
|
|
action: "foldHeading",
|
|
|
|
|
|
id: childrenItem.id,
|
|
|
|
|
|
data: "remove"
|
|
|
|
|
|
});
|
|
|
|
|
|
doOperations.push({
|
|
|
|
|
|
action: "unfoldHeading",
|
|
|
|
|
|
id: childrenItem.id,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
return {
|
|
|
|
|
|
doOperations,
|
|
|
|
|
|
undoOperations,
|
|
|
|
|
|
topSourceElement,
|
2022-11-22 21:54:52 +08:00
|
|
|
|
};
|
|
|
|
|
|
};
|
2022-11-22 11:02:04 +08:00
|
|
|
|
|
2022-11-24 00:44:20 +08:00
|
|
|
|
const dragSb = async (protyle: IProtyle, sourceElements: Element[], targetElement: Element, isBottom: boolean,
|
|
|
|
|
|
direct: "col" | "row", isCopy: boolean) => {
|
2022-05-26 15:18:53 +08:00
|
|
|
|
const isSameDoc = protyle.element.contains(sourceElements[0]);
|
|
|
|
|
|
|
|
|
|
|
|
let newSourceElement: HTMLElement;
|
|
|
|
|
|
if (sourceElements[0].getAttribute("data-type") === "NodeListItem" && targetElement.getAttribute("data-type") !== "NodeListItem") {
|
|
|
|
|
|
newSourceElement = document.createElement("div");
|
|
|
|
|
|
newSourceElement.setAttribute("data-node-id", Lute.NewNodeID());
|
|
|
|
|
|
newSourceElement.setAttribute("data-type", "NodeList");
|
|
|
|
|
|
newSourceElement.setAttribute("data-subtype", sourceElements[0].getAttribute("data-subtype"));
|
|
|
|
|
|
newSourceElement.className = "list";
|
|
|
|
|
|
newSourceElement.insertAdjacentHTML("beforeend", `<div class="protyle-attr" contenteditable="false">${Constants.ZWSP}</div>`);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const undoOperations: IOperation[] = [{
|
|
|
|
|
|
action: "move",
|
|
|
|
|
|
id: targetElement.getAttribute("data-node-id"),
|
|
|
|
|
|
previousID: targetElement.previousElementSibling?.getAttribute("data-node-id"),
|
2022-10-10 10:57:39 +08:00
|
|
|
|
parentID: targetElement.parentElement?.getAttribute("data-node-id") || protyle.block.parentID || protyle.block.rootID
|
2022-05-26 15:18:53 +08:00
|
|
|
|
}];
|
|
|
|
|
|
let topSourceElement: Element;
|
|
|
|
|
|
let oldSourceParentElement = sourceElements[0].parentElement;
|
|
|
|
|
|
const sbElement = genSBElement(direct);
|
|
|
|
|
|
targetElement.parentElement.replaceChild(sbElement, targetElement);
|
|
|
|
|
|
const doOperations: IOperation[] = [{
|
|
|
|
|
|
action: "insert",
|
|
|
|
|
|
data: sbElement.outerHTML,
|
|
|
|
|
|
id: sbElement.getAttribute("data-node-id"),
|
2022-10-14 17:38:20 +08:00
|
|
|
|
nextID: sbElement.nextElementSibling?.getAttribute("data-node-id"),
|
2022-05-26 15:18:53 +08:00
|
|
|
|
previousID: sbElement.previousElementSibling?.getAttribute("data-node-id"),
|
2022-10-10 10:57:39 +08:00
|
|
|
|
parentID: sbElement.parentElement.getAttribute("data-node-id") || protyle.block.parentID || protyle.block.rootID
|
2022-05-26 15:18:53 +08:00
|
|
|
|
}];
|
2024-10-18 22:46:41 +08:00
|
|
|
|
let hasFoldHeading = false;
|
2022-05-26 15:18:53 +08:00
|
|
|
|
if (newSourceElement) {
|
2022-11-25 23:09:16 +08:00
|
|
|
|
const newSourceId = newSourceElement.getAttribute("data-node-id");
|
2022-05-26 15:18:53 +08:00
|
|
|
|
sbElement.insertAdjacentElement("afterbegin", targetElement);
|
|
|
|
|
|
doOperations.push({
|
|
|
|
|
|
action: "move",
|
|
|
|
|
|
id: targetElement.getAttribute("data-node-id"),
|
|
|
|
|
|
parentID: sbElement.getAttribute("data-node-id")
|
|
|
|
|
|
});
|
|
|
|
|
|
if (isBottom) {
|
|
|
|
|
|
targetElement.insertAdjacentElement("afterend", newSourceElement);
|
|
|
|
|
|
doOperations.push({
|
|
|
|
|
|
action: "insert",
|
|
|
|
|
|
data: newSourceElement.outerHTML,
|
2022-11-24 00:44:20 +08:00
|
|
|
|
id: newSourceId,
|
2022-05-26 15:18:53 +08:00
|
|
|
|
previousID: targetElement.getAttribute("data-node-id"),
|
|
|
|
|
|
});
|
|
|
|
|
|
} else {
|
|
|
|
|
|
targetElement.insertAdjacentElement("beforebegin", newSourceElement);
|
|
|
|
|
|
doOperations.push({
|
|
|
|
|
|
action: "insert",
|
|
|
|
|
|
data: newSourceElement.outerHTML,
|
2022-11-24 00:44:20 +08:00
|
|
|
|
id: newSourceId,
|
2022-10-14 17:38:20 +08:00
|
|
|
|
nextID: targetElement.getAttribute("data-node-id"),
|
2022-05-26 15:18:53 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
sourceElements.reverse().forEach((item, index) => {
|
|
|
|
|
|
if (index === sourceElements.length - 1) {
|
|
|
|
|
|
topSourceElement = getTopAloneElement(item);
|
2025-07-23 12:21:59 +08:00
|
|
|
|
if (topSourceElement === item) {
|
2022-05-26 15:18:53 +08:00
|
|
|
|
topSourceElement = undefined;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2022-11-25 23:09:16 +08:00
|
|
|
|
const copyId = Lute.NewNodeID();
|
2022-11-24 00:44:20 +08:00
|
|
|
|
if (isCopy) {
|
|
|
|
|
|
undoOperations.push({
|
|
|
|
|
|
action: "delete",
|
|
|
|
|
|
id: copyId
|
|
|
|
|
|
});
|
|
|
|
|
|
} else {
|
|
|
|
|
|
undoOperations.push({
|
|
|
|
|
|
action: "move",
|
|
|
|
|
|
id: item.getAttribute("data-node-id"),
|
|
|
|
|
|
previousID: item.previousElementSibling?.getAttribute("data-node-id"),
|
|
|
|
|
|
parentID: item.parentElement.getAttribute("data-node-id") || protyle.block.rootID,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!isSameDoc && !isCopy) {
|
2022-05-26 15:18:53 +08:00
|
|
|
|
// 打开两个相同的文档
|
|
|
|
|
|
const sameElement = protyle.wysiwyg.element.querySelector(`[data-node-id="${item.getAttribute("data-node-id")}"]`);
|
|
|
|
|
|
if (sameElement) {
|
|
|
|
|
|
sameElement.remove();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2022-11-24 00:44:20 +08:00
|
|
|
|
if (isCopy) {
|
|
|
|
|
|
const copyElement = item.cloneNode(true) as HTMLElement;
|
|
|
|
|
|
copyElement.setAttribute("data-node-id", copyId);
|
|
|
|
|
|
copyElement.querySelectorAll("[data-node-id]").forEach((e) => {
|
|
|
|
|
|
const newId = Lute.NewNodeID();
|
|
|
|
|
|
e.setAttribute("data-node-id", newId);
|
|
|
|
|
|
e.setAttribute("updated", newId.split("-")[0]);
|
|
|
|
|
|
});
|
|
|
|
|
|
newSourceElement.insertAdjacentElement("afterbegin", copyElement);
|
|
|
|
|
|
doOperations.push({
|
|
|
|
|
|
action: "insert",
|
|
|
|
|
|
id: copyId,
|
|
|
|
|
|
data: copyElement.outerHTML,
|
|
|
|
|
|
parentID: newSourceId,
|
|
|
|
|
|
});
|
|
|
|
|
|
} else {
|
|
|
|
|
|
newSourceElement.insertAdjacentElement("afterbegin", item);
|
|
|
|
|
|
doOperations.push({
|
|
|
|
|
|
action: "move",
|
|
|
|
|
|
id: item.getAttribute("data-node-id"),
|
|
|
|
|
|
parentID: newSourceId,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2022-05-26 15:18:53 +08:00
|
|
|
|
});
|
|
|
|
|
|
undoOperations.reverse();
|
|
|
|
|
|
undoOperations.push({
|
|
|
|
|
|
action: "delete",
|
2022-11-24 00:44:20 +08:00
|
|
|
|
id: newSourceId,
|
2022-05-26 15:18:53 +08:00
|
|
|
|
});
|
|
|
|
|
|
} else {
|
2022-11-22 21:54:52 +08:00
|
|
|
|
const foldHeadingIds: { id: string, parentID: string }[] = [];
|
|
|
|
|
|
let afterPreviousID;
|
2022-05-26 15:18:53 +08:00
|
|
|
|
sourceElements.reverse().forEach((item, index) => {
|
2022-11-22 11:02:04 +08:00
|
|
|
|
const id = item.getAttribute("data-node-id");
|
2022-11-22 21:54:52 +08:00
|
|
|
|
const parentID = item.parentElement.getAttribute("data-node-id") || protyle.block.rootID;
|
2022-05-26 15:18:53 +08:00
|
|
|
|
if (index === sourceElements.length - 1) {
|
|
|
|
|
|
topSourceElement = getTopAloneElement(item);
|
2025-07-23 12:21:59 +08:00
|
|
|
|
if (topSourceElement === item) {
|
2022-05-26 15:18:53 +08:00
|
|
|
|
topSourceElement = undefined;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2022-11-25 23:09:16 +08:00
|
|
|
|
const copyId = Lute.NewNodeID();
|
2022-11-22 15:54:47 +08:00
|
|
|
|
if (index === 0) {
|
2022-11-24 00:44:20 +08:00
|
|
|
|
afterPreviousID = isCopy ? copyId : id;
|
2022-11-22 15:54:47 +08:00
|
|
|
|
}
|
2024-10-18 22:46:41 +08:00
|
|
|
|
if (item.getAttribute("data-type") === "NodeHeading" && item.getAttribute("fold") === "1") {
|
|
|
|
|
|
if (isCopy) {
|
|
|
|
|
|
item.removeAttribute("fold");
|
|
|
|
|
|
foldHeadingIds.push({id, parentID});
|
|
|
|
|
|
}
|
|
|
|
|
|
hasFoldHeading = true;
|
2022-11-22 11:02:04 +08:00
|
|
|
|
}
|
2022-11-24 00:44:20 +08:00
|
|
|
|
if (isCopy) {
|
|
|
|
|
|
undoOperations.push({
|
|
|
|
|
|
action: "delete",
|
|
|
|
|
|
id: copyId,
|
|
|
|
|
|
});
|
|
|
|
|
|
} else {
|
|
|
|
|
|
undoOperations.push({
|
|
|
|
|
|
action: "move",
|
|
|
|
|
|
id,
|
|
|
|
|
|
previousID: item.previousElementSibling?.getAttribute("data-node-id"),
|
|
|
|
|
|
parentID
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!isSameDoc && !isCopy) {
|
2022-05-26 15:18:53 +08:00
|
|
|
|
// 打开两个相同的文档
|
2022-11-22 11:02:04 +08:00
|
|
|
|
const sameElement = protyle.wysiwyg.element.querySelector(`[data-node-id="${id}"]`);
|
2022-05-26 15:18:53 +08:00
|
|
|
|
if (sameElement) {
|
|
|
|
|
|
sameElement.remove();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2022-11-24 00:44:20 +08:00
|
|
|
|
if (isCopy) {
|
|
|
|
|
|
const copyElement = item.cloneNode(true) as HTMLElement;
|
|
|
|
|
|
copyElement.setAttribute("data-node-id", copyId);
|
|
|
|
|
|
copyElement.querySelectorAll("[data-node-id]").forEach((e) => {
|
|
|
|
|
|
const newId = Lute.NewNodeID();
|
|
|
|
|
|
e.setAttribute("data-node-id", newId);
|
|
|
|
|
|
e.setAttribute("updated", newId.split("-")[0]);
|
|
|
|
|
|
});
|
|
|
|
|
|
sbElement.insertAdjacentElement("afterbegin", copyElement);
|
|
|
|
|
|
doOperations.push({
|
|
|
|
|
|
action: "insert",
|
|
|
|
|
|
id: copyId,
|
|
|
|
|
|
data: copyElement.outerHTML,
|
|
|
|
|
|
parentID: sbElement.getAttribute("data-node-id"),
|
|
|
|
|
|
});
|
|
|
|
|
|
} else {
|
|
|
|
|
|
sbElement.insertAdjacentElement("afterbegin", item);
|
|
|
|
|
|
doOperations.push({
|
|
|
|
|
|
action: "move",
|
|
|
|
|
|
id,
|
|
|
|
|
|
parentID: sbElement.getAttribute("data-node-id"),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2022-05-26 15:18:53 +08:00
|
|
|
|
});
|
|
|
|
|
|
undoOperations.reverse();
|
2022-11-22 11:02:04 +08:00
|
|
|
|
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,
|
|
|
|
|
|
});
|
2022-11-22 21:54:52 +08:00
|
|
|
|
});
|
2022-11-22 11:02:04 +08:00
|
|
|
|
if (j === 0) {
|
2022-11-22 21:54:52 +08:00
|
|
|
|
afterPreviousID = headingIds.data[0];
|
2022-11-22 11:02:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
undoOperations.push({
|
|
|
|
|
|
action: "foldHeading",
|
|
|
|
|
|
id: childrenItem.id,
|
|
|
|
|
|
data: "remove"
|
|
|
|
|
|
});
|
|
|
|
|
|
doOperations.push({
|
|
|
|
|
|
action: "unfoldHeading",
|
|
|
|
|
|
id: childrenItem.id,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2022-05-26 15:18:53 +08:00
|
|
|
|
if (isBottom) {
|
|
|
|
|
|
sbElement.insertAdjacentElement("afterbegin", targetElement);
|
|
|
|
|
|
doOperations.push({
|
|
|
|
|
|
action: "move",
|
|
|
|
|
|
id: targetElement.getAttribute("data-node-id"),
|
|
|
|
|
|
parentID: sbElement.getAttribute("data-node-id")
|
|
|
|
|
|
});
|
2022-11-22 11:02:04 +08:00
|
|
|
|
} else {
|
2022-11-22 15:54:47 +08:00
|
|
|
|
sbElement.lastElementChild.insertAdjacentElement("beforebegin", targetElement);
|
2022-11-22 11:02:04 +08:00
|
|
|
|
doOperations.push({
|
|
|
|
|
|
action: "move",
|
|
|
|
|
|
id: targetElement.getAttribute("data-node-id"),
|
2022-11-22 15:54:47 +08:00
|
|
|
|
previousID: afterPreviousID
|
2022-11-22 11:02:04 +08:00
|
|
|
|
});
|
2022-05-26 15:18:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
undoOperations.push({
|
|
|
|
|
|
action: "delete",
|
|
|
|
|
|
id: sbElement.getAttribute("data-node-id"),
|
|
|
|
|
|
});
|
|
|
|
|
|
// https://github.com/siyuan-note/insider/issues/536
|
2022-11-24 00:44:20 +08:00
|
|
|
|
if (!isCopy && oldSourceParentElement && oldSourceParentElement.classList.contains("list") &&
|
2022-05-26 15:18:53 +08:00
|
|
|
|
oldSourceParentElement.getAttribute("data-subtype") === "o" &&
|
2025-07-23 13:08:38 +08:00
|
|
|
|
oldSourceParentElement !== sourceElements[0].parentElement && oldSourceParentElement.childElementCount > 1) {
|
2022-05-26 15:18:53 +08:00
|
|
|
|
Array.from(oldSourceParentElement.children).forEach((item) => {
|
|
|
|
|
|
if (item.classList.contains("protyle-attr")) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2022-08-27 23:29:27 +08:00
|
|
|
|
// 撤销更新不能位于最后,否则又更新为最新结果 https://github.com/siyuan-note/siyuan/issues/5725
|
|
|
|
|
|
undoOperations.splice(0, 0, {
|
2022-05-26 15:18:53 +08:00
|
|
|
|
action: "update",
|
|
|
|
|
|
id: item.getAttribute("data-node-id"),
|
|
|
|
|
|
data: item.outerHTML
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
updateListOrder(oldSourceParentElement, 1);
|
|
|
|
|
|
Array.from(oldSourceParentElement.children).forEach((item) => {
|
|
|
|
|
|
if (item.classList.contains("protyle-attr")) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
doOperations.push({
|
|
|
|
|
|
action: "update",
|
|
|
|
|
|
id: item.getAttribute("data-node-id"),
|
|
|
|
|
|
data: item.outerHTML
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
// 删除空元素
|
2022-11-24 00:44:20 +08:00
|
|
|
|
if (!isCopy && topSourceElement) {
|
2022-05-26 15:18:53 +08:00
|
|
|
|
doOperations.push({
|
|
|
|
|
|
action: "delete",
|
|
|
|
|
|
id: topSourceElement.getAttribute("data-node-id"),
|
|
|
|
|
|
});
|
|
|
|
|
|
undoOperations.splice(0, 0, {
|
|
|
|
|
|
action: "insert",
|
|
|
|
|
|
data: topSourceElement.outerHTML,
|
|
|
|
|
|
id: topSourceElement.getAttribute("data-node-id"),
|
|
|
|
|
|
previousID: topSourceElement.previousElementSibling?.getAttribute("data-node-id"),
|
2022-10-10 10:57:39 +08:00
|
|
|
|
parentID: topSourceElement.parentElement?.getAttribute("data-node-id") || protyle.block.parentID || protyle.block.rootID
|
2022-05-26 15:18:53 +08:00
|
|
|
|
});
|
|
|
|
|
|
if (!isSameDoc) {
|
|
|
|
|
|
// 打开两个相同的文档
|
|
|
|
|
|
const sameElement = protyle.wysiwyg.element.querySelector(`[data-node-id="${topSourceElement.getAttribute("data-node-id")}"]`);
|
|
|
|
|
|
if (sameElement) {
|
|
|
|
|
|
sameElement.remove();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
oldSourceParentElement = topSourceElement.parentElement;
|
|
|
|
|
|
topSourceElement.remove();
|
|
|
|
|
|
}
|
2022-11-24 00:44:20 +08:00
|
|
|
|
if (!isCopy && oldSourceParentElement && oldSourceParentElement.classList.contains("sb") && oldSourceParentElement.childElementCount === 2) {
|
2022-06-15 23:31:57 +08:00
|
|
|
|
// 拖拽后,sb 只剩下一个元素
|
2024-06-17 00:37:12 +08:00
|
|
|
|
if (isSameDoc) {
|
2025-04-01 17:05:15 +08:00
|
|
|
|
const sbData = await cancelSB(protyle, oldSourceParentElement);
|
2024-06-17 00:37:12 +08:00
|
|
|
|
doOperations.push(sbData.doOperations[0], sbData.doOperations[1]);
|
|
|
|
|
|
undoOperations.splice(0, 0, sbData.undoOperations[0], sbData.undoOperations[1]);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
/// #if !MOBILE
|
|
|
|
|
|
const otherProtyleElement = hasClosestByClassName(oldSourceParentElement, "protyle", true);
|
|
|
|
|
|
if (otherProtyleElement) {
|
2025-04-03 15:13:01 +08:00
|
|
|
|
const allEditor = getAllEditor();
|
2025-04-01 17:05:15 +08:00
|
|
|
|
for (let i = 0; i < allEditor.length; i++) {
|
2025-07-23 12:21:59 +08:00
|
|
|
|
if (allEditor[i].protyle.element === otherProtyleElement) {
|
2025-04-01 17:05:15 +08:00
|
|
|
|
const otherSbData = await cancelSB(allEditor[i].protyle, oldSourceParentElement);
|
2024-06-17 00:37:12 +08:00
|
|
|
|
doOperations.push(otherSbData.doOperations[0], otherSbData.doOperations[1]);
|
|
|
|
|
|
undoOperations.splice(0, 0, otherSbData.undoOperations[0], otherSbData.undoOperations[1]);
|
|
|
|
|
|
// 需清空操作栈,否则撤销到移动出去的块的操作会抛异常
|
2025-04-01 17:05:15 +08:00
|
|
|
|
allEditor[i].protyle.undo.clear();
|
2024-06-17 00:37:12 +08:00
|
|
|
|
return true;
|
|
|
|
|
|
}
|
2025-04-01 17:05:15 +08:00
|
|
|
|
}
|
2024-06-17 00:37:12 +08:00
|
|
|
|
}
|
|
|
|
|
|
/// #endif
|
|
|
|
|
|
}
|
2022-11-24 00:44:20 +08:00
|
|
|
|
} else if (!isCopy && oldSourceParentElement && oldSourceParentElement.classList.contains("protyle-wysiwyg") && oldSourceParentElement.innerHTML === "") {
|
2022-06-30 15:56:44 +08:00
|
|
|
|
/// #if !MOBILE
|
2022-05-26 15:18:53 +08:00
|
|
|
|
// 拖拽后,根文档原内容为空,且不为悬浮窗
|
|
|
|
|
|
const protyleElement = hasClosestByClassName(oldSourceParentElement, "protyle", true);
|
2024-06-17 00:37:12 +08:00
|
|
|
|
if (protyleElement) {
|
|
|
|
|
|
getAllEditor().find(item => {
|
2025-07-23 12:21:59 +08:00
|
|
|
|
if (item.protyle.element === protyleElement) {
|
2024-06-17 00:37:12 +08:00
|
|
|
|
if (item.protyle.block.id === item.protyle.block.rootID) {
|
|
|
|
|
|
const newId = Lute.NewNodeID();
|
|
|
|
|
|
doOperations.splice(0, 0, {
|
|
|
|
|
|
action: "insert",
|
|
|
|
|
|
id: newId,
|
|
|
|
|
|
data: genEmptyElement(false, false, newId).outerHTML,
|
|
|
|
|
|
parentID: item.protyle.block.parentID
|
|
|
|
|
|
});
|
|
|
|
|
|
undoOperations.splice(0, 0, {
|
|
|
|
|
|
action: "delete",
|
|
|
|
|
|
id: newId,
|
|
|
|
|
|
});
|
|
|
|
|
|
} else {
|
|
|
|
|
|
zoomOut({protyle: item.protyle, id: item.protyle.block.rootID});
|
|
|
|
|
|
}
|
|
|
|
|
|
return true;
|
2024-05-27 22:47:41 +08:00
|
|
|
|
}
|
2024-06-17 00:37:12 +08:00
|
|
|
|
});
|
2022-05-26 15:18:53 +08:00
|
|
|
|
}
|
2022-06-30 15:56:44 +08:00
|
|
|
|
/// #endif
|
2022-05-26 15:18:53 +08:00
|
|
|
|
}
|
2022-11-24 00:44:20 +08:00
|
|
|
|
if (isSameDoc || isCopy) {
|
2022-05-26 15:18:53 +08:00
|
|
|
|
transaction(protyle, doOperations, undoOperations);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 跨文档不支持撤销
|
|
|
|
|
|
transaction(protyle, doOperations);
|
|
|
|
|
|
}
|
2024-10-19 23:01:09 +08:00
|
|
|
|
if (!isCopy && direct === "col") {
|
|
|
|
|
|
if (targetElement.getAttribute("data-type") === "NodeHeading" && targetElement.getAttribute("fold") === "1") {
|
|
|
|
|
|
turnsIntoOneTransaction({
|
|
|
|
|
|
protyle,
|
|
|
|
|
|
selectsElement: [targetElement],
|
|
|
|
|
|
type: "BlocksMergeSuperBlock",
|
|
|
|
|
|
level: "row"
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
if ((sourceElements.length > 1 || hasFoldHeading)) {
|
|
|
|
|
|
turnsIntoOneTransaction({
|
|
|
|
|
|
protyle,
|
|
|
|
|
|
selectsElement: sourceElements.reverse(),
|
|
|
|
|
|
type: "BlocksMergeSuperBlock",
|
|
|
|
|
|
level: "row"
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2024-10-18 22:46:41 +08:00
|
|
|
|
}
|
2022-05-26 15:18:53 +08:00
|
|
|
|
focusBlock(sourceElements[0]);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2022-11-23 22:05:29 +08:00
|
|
|
|
const dragSame = async (protyle: IProtyle, sourceElements: Element[], targetElement: Element, isBottom: boolean, isCopy: boolean) => {
|
2022-05-26 15:18:53 +08:00
|
|
|
|
const isSameDoc = protyle.element.contains(sourceElements[0]);
|
|
|
|
|
|
const doOperations: IOperation[] = [];
|
|
|
|
|
|
const undoOperations: IOperation[] = [];
|
|
|
|
|
|
|
|
|
|
|
|
let newSourceElement: HTMLElement;
|
|
|
|
|
|
if (sourceElements[0].getAttribute("data-type") === "NodeListItem" && targetElement.getAttribute("data-type") !== "NodeListItem") {
|
|
|
|
|
|
newSourceElement = document.createElement("div");
|
|
|
|
|
|
newSourceElement.setAttribute("data-node-id", Lute.NewNodeID());
|
|
|
|
|
|
newSourceElement.setAttribute("data-type", "NodeList");
|
|
|
|
|
|
newSourceElement.setAttribute("data-subtype", sourceElements[0].getAttribute("data-subtype"));
|
|
|
|
|
|
newSourceElement.className = "list";
|
|
|
|
|
|
newSourceElement.insertAdjacentHTML("beforeend", `<div class="protyle-attr" contenteditable="false">${Constants.ZWSP}</div>`);
|
|
|
|
|
|
}
|
|
|
|
|
|
let topSourceElement: Element;
|
|
|
|
|
|
let oldSourceParentElement = sourceElements[0].parentElement;
|
|
|
|
|
|
if (isBottom) {
|
|
|
|
|
|
if (newSourceElement) {
|
2022-11-24 00:44:20 +08:00
|
|
|
|
const moveToResult = moveToNew(protyle, sourceElements, targetElement, newSourceElement, isSameDoc, isBottom, isCopy);
|
|
|
|
|
|
doOperations.push(...moveToResult.doOperations);
|
|
|
|
|
|
undoOperations.push(...moveToResult.undoOperations);
|
|
|
|
|
|
topSourceElement = moveToResult.topSourceElement;
|
2022-05-26 15:18:53 +08:00
|
|
|
|
} else {
|
2022-11-23 22:05:29 +08:00
|
|
|
|
const moveToResult = await moveTo(protyle, sourceElements, targetElement, isSameDoc, "afterend", isCopy);
|
2022-11-22 11:02:04 +08:00
|
|
|
|
doOperations.push(...moveToResult.doOperations);
|
|
|
|
|
|
undoOperations.push(...moveToResult.undoOperations);
|
|
|
|
|
|
topSourceElement = moveToResult.topSourceElement;
|
2022-05-26 15:18:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
if (newSourceElement) {
|
2022-11-24 00:44:20 +08:00
|
|
|
|
const moveToResult = moveToNew(protyle, sourceElements, targetElement, newSourceElement, isSameDoc, isBottom, isCopy);
|
|
|
|
|
|
doOperations.push(...moveToResult.doOperations);
|
|
|
|
|
|
undoOperations.push(...moveToResult.undoOperations);
|
|
|
|
|
|
topSourceElement = moveToResult.topSourceElement;
|
2022-05-26 15:18:53 +08:00
|
|
|
|
} else {
|
2022-11-23 22:05:29 +08:00
|
|
|
|
const moveToResult = await moveTo(protyle, sourceElements, targetElement, isSameDoc, "beforebegin", isCopy);
|
2022-11-22 11:02:04 +08:00
|
|
|
|
doOperations.push(...moveToResult.doOperations);
|
|
|
|
|
|
undoOperations.push(...moveToResult.undoOperations);
|
|
|
|
|
|
topSourceElement = moveToResult.topSourceElement;
|
2022-05-26 15:18:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (targetElement.getAttribute("data-type") === "NodeListItem" && targetElement.getAttribute("data-subtype") === "o") {
|
|
|
|
|
|
// https://github.com/siyuan-note/insider/issues/536
|
|
|
|
|
|
Array.from(targetElement.parentElement.children).forEach((item) => {
|
|
|
|
|
|
if (item.classList.contains("protyle-attr")) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
undoOperations.splice(0, 0, {
|
|
|
|
|
|
action: "update",
|
|
|
|
|
|
id: item.getAttribute("data-node-id"),
|
|
|
|
|
|
data: item.outerHTML
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
updateListOrder(targetElement.parentElement, 1);
|
|
|
|
|
|
Array.from(targetElement.parentElement.children).forEach((item) => {
|
|
|
|
|
|
if (item.classList.contains("protyle-attr")) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
doOperations.push({
|
|
|
|
|
|
action: "update",
|
|
|
|
|
|
id: item.getAttribute("data-node-id"),
|
|
|
|
|
|
data: item.outerHTML
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2022-11-23 22:05:29 +08:00
|
|
|
|
if (!isCopy &&
|
2023-07-31 15:29:23 +08:00
|
|
|
|
isSameDoc && // 同一文档分屏后,oldSourceParentElement 已经被移走,不可再 update https://github.com/siyuan-note/siyuan/issues/8863
|
2022-11-23 22:05:29 +08:00
|
|
|
|
oldSourceParentElement && oldSourceParentElement.classList.contains("list") &&
|
2022-05-26 15:18:53 +08:00
|
|
|
|
oldSourceParentElement.getAttribute("data-subtype") === "o" &&
|
2025-07-23 13:08:38 +08:00
|
|
|
|
oldSourceParentElement !== sourceElements[0].parentElement && oldSourceParentElement.childElementCount > 1) {
|
2022-05-26 15:18:53 +08:00
|
|
|
|
Array.from(oldSourceParentElement.children).forEach((item) => {
|
|
|
|
|
|
if (item.classList.contains("protyle-attr")) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (oldSourceParentElement.contains(targetElement)) {
|
|
|
|
|
|
undoOperations.splice(0, 0, {
|
|
|
|
|
|
action: "update",
|
|
|
|
|
|
id: item.getAttribute("data-node-id"),
|
|
|
|
|
|
data: item.outerHTML
|
|
|
|
|
|
});
|
|
|
|
|
|
} else {
|
|
|
|
|
|
undoOperations.splice(targetElement.parentElement.childElementCount - 1, 0, {
|
|
|
|
|
|
action: "update",
|
|
|
|
|
|
id: item.getAttribute("data-node-id"),
|
|
|
|
|
|
data: item.outerHTML
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
updateListOrder(oldSourceParentElement, 1);
|
|
|
|
|
|
Array.from(oldSourceParentElement.children).forEach((item) => {
|
|
|
|
|
|
if (item.classList.contains("protyle-attr")) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
doOperations.push({
|
|
|
|
|
|
action: "update",
|
|
|
|
|
|
id: item.getAttribute("data-node-id"),
|
|
|
|
|
|
data: item.outerHTML
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 删除空元素
|
2022-11-23 22:05:29 +08:00
|
|
|
|
if (!isCopy && topSourceElement) {
|
2022-05-26 15:18:53 +08:00
|
|
|
|
doOperations.push({
|
|
|
|
|
|
action: "delete",
|
|
|
|
|
|
id: topSourceElement.getAttribute("data-node-id"),
|
|
|
|
|
|
});
|
|
|
|
|
|
undoOperations.splice(0, 0, {
|
|
|
|
|
|
action: "insert",
|
|
|
|
|
|
data: topSourceElement.outerHTML,
|
|
|
|
|
|
id: topSourceElement.getAttribute("data-node-id"),
|
|
|
|
|
|
previousID: topSourceElement.previousElementSibling?.getAttribute("data-node-id"),
|
2022-10-10 10:57:39 +08:00
|
|
|
|
parentID: topSourceElement.parentElement?.getAttribute("data-node-id") || protyle.block.parentID || protyle.block.rootID
|
2022-05-26 15:18:53 +08:00
|
|
|
|
});
|
|
|
|
|
|
oldSourceParentElement = topSourceElement.parentElement;
|
|
|
|
|
|
topSourceElement.remove();
|
|
|
|
|
|
if (!isSameDoc) {
|
|
|
|
|
|
// 打开两个相同的文档
|
|
|
|
|
|
const sameElement = protyle.wysiwyg.element.querySelector(`[data-node-id="${topSourceElement.getAttribute("data-node-id")}"]`);
|
|
|
|
|
|
if (sameElement) {
|
|
|
|
|
|
sameElement.remove();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2022-11-23 22:05:29 +08:00
|
|
|
|
if (!isCopy && oldSourceParentElement && oldSourceParentElement.classList.contains("sb") && oldSourceParentElement.childElementCount === 2) {
|
2022-06-15 23:31:57 +08:00
|
|
|
|
// 拖拽后,sb 只剩下一个元素
|
2024-06-17 00:37:12 +08:00
|
|
|
|
if (isSameDoc) {
|
2025-04-01 17:05:15 +08:00
|
|
|
|
const sbData = await cancelSB(protyle, oldSourceParentElement);
|
2024-06-17 00:37:12 +08:00
|
|
|
|
doOperations.push(sbData.doOperations[0], sbData.doOperations[1]);
|
|
|
|
|
|
undoOperations.splice(0, 0, sbData.undoOperations[0], sbData.undoOperations[1]);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
/// #if !MOBILE
|
|
|
|
|
|
const otherProtyleElement = hasClosestByClassName(oldSourceParentElement, "protyle", true);
|
|
|
|
|
|
if (otherProtyleElement) {
|
2025-04-03 15:13:01 +08:00
|
|
|
|
const allEditor = getAllEditor();
|
2025-04-01 17:05:15 +08:00
|
|
|
|
for (let i = 0; i < allEditor.length; i++) {
|
2025-07-23 12:21:59 +08:00
|
|
|
|
if (allEditor[i].protyle.element === otherProtyleElement) {
|
2025-04-01 17:05:15 +08:00
|
|
|
|
const otherSbData = await cancelSB(allEditor[i].protyle, oldSourceParentElement);
|
2024-06-17 00:37:12 +08:00
|
|
|
|
doOperations.push(otherSbData.doOperations[0], otherSbData.doOperations[1]);
|
|
|
|
|
|
undoOperations.splice(0, 0, otherSbData.undoOperations[0], otherSbData.undoOperations[1]);
|
|
|
|
|
|
// 需清空操作栈,否则撤销到移动出去的块的操作会抛异常
|
2025-04-01 17:05:15 +08:00
|
|
|
|
allEditor[i].protyle.undo.clear();
|
2024-06-17 00:37:12 +08:00
|
|
|
|
}
|
2025-04-01 17:05:15 +08:00
|
|
|
|
}
|
2024-06-17 00:37:12 +08:00
|
|
|
|
}
|
|
|
|
|
|
/// #endif
|
|
|
|
|
|
}
|
2022-11-23 22:05:29 +08:00
|
|
|
|
} else if (!isCopy && oldSourceParentElement && oldSourceParentElement.classList.contains("protyle-wysiwyg") && oldSourceParentElement.childElementCount === 0) {
|
2022-06-30 15:56:44 +08:00
|
|
|
|
/// #if !MOBILE
|
2024-06-17 00:37:12 +08:00
|
|
|
|
// 拖拽后,根文档原内容为空
|
2022-05-26 15:18:53 +08:00
|
|
|
|
const protyleElement = hasClosestByClassName(oldSourceParentElement, "protyle", true);
|
2024-06-17 00:37:12 +08:00
|
|
|
|
if (protyleElement) {
|
|
|
|
|
|
getAllEditor().find(item => {
|
2025-07-23 12:21:59 +08:00
|
|
|
|
if (item.protyle.element === protyleElement) {
|
2024-06-17 00:37:12 +08:00
|
|
|
|
if (item.protyle.block.id === item.protyle.block.rootID) {
|
|
|
|
|
|
const newId = Lute.NewNodeID();
|
|
|
|
|
|
doOperations.splice(0, 0, {
|
|
|
|
|
|
action: "insert",
|
|
|
|
|
|
id: newId,
|
|
|
|
|
|
data: genEmptyElement(false, false, newId).outerHTML,
|
|
|
|
|
|
parentID: item.protyle.block.parentID
|
|
|
|
|
|
});
|
|
|
|
|
|
undoOperations.splice(0, 0, {
|
|
|
|
|
|
action: "delete",
|
|
|
|
|
|
id: newId,
|
|
|
|
|
|
});
|
|
|
|
|
|
} else {
|
|
|
|
|
|
zoomOut({protyle: item.protyle, id: item.protyle.block.rootID});
|
|
|
|
|
|
}
|
|
|
|
|
|
return true;
|
2024-05-27 22:47:41 +08:00
|
|
|
|
}
|
2024-06-17 00:37:12 +08:00
|
|
|
|
});
|
2022-05-26 15:18:53 +08:00
|
|
|
|
}
|
2022-06-30 15:56:44 +08:00
|
|
|
|
/// #endif
|
2022-05-26 15:18:53 +08:00
|
|
|
|
}
|
2022-11-23 22:05:29 +08:00
|
|
|
|
if (isSameDoc || isCopy) {
|
2022-05-26 15:18:53 +08:00
|
|
|
|
transaction(protyle, doOperations, undoOperations);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 跨文档不支持撤销
|
|
|
|
|
|
transaction(protyle, doOperations);
|
|
|
|
|
|
}
|
2024-10-18 22:46:41 +08:00
|
|
|
|
let hasFoldHeading = false;
|
|
|
|
|
|
sourceElements.find(item => {
|
|
|
|
|
|
if (item.getAttribute("data-type") === "NodeHeading" && item.getAttribute("fold") === "1") {
|
|
|
|
|
|
hasFoldHeading = true;
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
2024-10-21 22:41:07 +08:00
|
|
|
|
});
|
2024-10-18 22:46:41 +08:00
|
|
|
|
if (!isCopy && (sourceElements.length > 1 || hasFoldHeading) &&
|
|
|
|
|
|
sourceElements[0].parentElement.classList.contains("sb") &&
|
|
|
|
|
|
sourceElements[0].parentElement.getAttribute("data-sb-layout") === "col") {
|
|
|
|
|
|
turnsIntoOneTransaction({
|
|
|
|
|
|
protyle,
|
|
|
|
|
|
selectsElement: sourceElements.reverse(),
|
|
|
|
|
|
type: "BlocksMergeSuperBlock",
|
|
|
|
|
|
level: "row"
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2022-05-26 15:18:53 +08:00
|
|
|
|
focusBlock(sourceElements[0]);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2023-06-01 20:50:49 +08:00
|
|
|
|
export const dropEvent = (protyle: IProtyle, editorElement: HTMLElement) => {
|
2022-05-26 15:18:53 +08:00
|
|
|
|
editorElement.addEventListener("dragstart", (event) => {
|
2025-07-03 10:11:03 +08:00
|
|
|
|
if (protyle.disabled) {
|
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
|
event.stopPropagation();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-06-29 22:34:08 +08:00
|
|
|
|
let target = event.target as HTMLElement;
|
2025-07-15 18:07:28 +08:00
|
|
|
|
if (target.classList?.contains("av__gallery-img")) {
|
2025-06-29 22:34:08 +08:00
|
|
|
|
target = hasClosestByClassName(target, "av__gallery-item") as HTMLElement;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!target) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2022-05-26 15:18:53 +08:00
|
|
|
|
if (target.tagName === "IMG") {
|
|
|
|
|
|
window.siyuan.dragElement = undefined;
|
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-06-29 22:34:08 +08:00
|
|
|
|
|
2023-07-01 20:41:35 +08:00
|
|
|
|
if (target.classList) {
|
2022-06-06 10:42:05 +08:00
|
|
|
|
if (hasClosestByClassName(target, "protyle-wysiwyg__embed")) {
|
|
|
|
|
|
window.siyuan.dragElement = undefined;
|
|
|
|
|
|
event.preventDefault();
|
2025-07-08 23:29:36 +08:00
|
|
|
|
} else if (target.parentElement.parentElement.classList.contains("av__views")) {
|
|
|
|
|
|
window.siyuan.dragElement = target;
|
|
|
|
|
|
target.style.width = target.clientWidth + "px";
|
|
|
|
|
|
target.style.opacity = ".36";
|
|
|
|
|
|
event.dataTransfer.setData(`${Constants.SIYUAN_DROP_GUTTER}NodeAttributeView${Constants.ZWSP}ViewTab${Constants.ZWSP}${[target.previousElementSibling?.getAttribute("data-id")]}`,
|
|
|
|
|
|
target.outerHTML);
|
|
|
|
|
|
return;
|
2023-07-01 20:41:35 +08:00
|
|
|
|
} else if (target.classList.contains("protyle-action")) {
|
2025-02-03 17:31:32 +08:00
|
|
|
|
target.parentElement.classList.add("protyle-wysiwyg--select");
|
2025-01-29 23:25:43 +08:00
|
|
|
|
const ghostElement = document.createElement("div");
|
2025-01-29 23:43:58 +08:00
|
|
|
|
ghostElement.className = protyle.wysiwyg.element.className;
|
2025-01-29 23:25:43 +08:00
|
|
|
|
ghostElement.append(processClonePHElement(target.parentElement.cloneNode(true) as Element));
|
|
|
|
|
|
ghostElement.setAttribute("style", `position:fixed;opacity:.1;width:${target.parentElement.clientWidth}px;padding:0;`);
|
|
|
|
|
|
document.body.append(ghostElement);
|
2025-01-29 23:43:58 +08:00
|
|
|
|
event.dataTransfer.setDragImage(ghostElement, 0, 0);
|
2025-01-29 23:25:43 +08:00
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
ghostElement.remove();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2023-07-01 23:15:21 +08:00
|
|
|
|
window.siyuan.dragElement = protyle.wysiwyg.element;
|
|
|
|
|
|
event.dataTransfer.setData(`${Constants.SIYUAN_DROP_GUTTER}NodeListItem${Constants.ZWSP}${target.parentElement.getAttribute("data-subtype")}${Constants.ZWSP}${[target.parentElement.getAttribute("data-node-id")]}`,
|
|
|
|
|
|
protyle.wysiwyg.element.innerHTML);
|
|
|
|
|
|
return;
|
2024-01-14 12:09:42 +08:00
|
|
|
|
} else if (target.classList.contains("av__cell--header")) {
|
|
|
|
|
|
window.siyuan.dragElement = target;
|
|
|
|
|
|
event.dataTransfer.setData(`${Constants.SIYUAN_DROP_GUTTER}NodeAttributeView${Constants.ZWSP}Col${Constants.ZWSP}${[target.getAttribute("data-col-id")]}`,
|
|
|
|
|
|
target.outerHTML);
|
2023-07-01 20:41:35 +08:00
|
|
|
|
return;
|
2025-06-18 11:50:33 +08:00
|
|
|
|
} else if (target.classList.contains("av__gallery-item")) {
|
2025-06-26 12:07:08 +08:00
|
|
|
|
const blockElement = hasClosestBlock(target);
|
|
|
|
|
|
if (blockElement) {
|
2025-07-07 15:41:34 +08:00
|
|
|
|
if (blockElement.querySelector('.block__icon[data-type="av-sort"]')?.classList.contains("block__icon--active")) {
|
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
|
event.stopPropagation();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-07-01 13:27:45 +08:00
|
|
|
|
target.classList.add("av__gallery-item--select");
|
2025-06-30 12:39:38 +08:00
|
|
|
|
const ghostElement = document.createElement("div");
|
2025-07-01 13:27:45 +08:00
|
|
|
|
ghostElement.className = "protyle-wysiwyg protyle-wysiwyg--attr " + target.parentElement.className;
|
|
|
|
|
|
blockElement.querySelectorAll(".av__gallery-item--select").forEach(item => {
|
|
|
|
|
|
const cloneItem = processClonePHElement(item.cloneNode(true) as Element);
|
|
|
|
|
|
cloneItem.setAttribute("style", `width:${item.clientWidth}px;;height:${item.clientHeight}px;`);
|
|
|
|
|
|
cloneItem.querySelector(".av__gallery-fields").setAttribute("style", "background-color: var(--b3-theme-background)");
|
|
|
|
|
|
ghostElement.append(cloneItem);
|
|
|
|
|
|
});
|
2025-07-02 17:33:16 +08:00
|
|
|
|
ghostElement.setAttribute("style", "top:100vh;position:fixed;opacity:.1;padding:0");
|
2025-06-30 12:39:38 +08:00
|
|
|
|
document.body.append(ghostElement);
|
|
|
|
|
|
event.dataTransfer.setDragImage(ghostElement, -10, -10);
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
ghostElement.remove();
|
|
|
|
|
|
});
|
|
|
|
|
|
window.siyuan.dragElement = target;
|
2025-06-26 12:07:08 +08:00
|
|
|
|
const selectIds: string[] = [];
|
|
|
|
|
|
blockElement.querySelectorAll(".av__gallery-item--select").forEach(item => {
|
|
|
|
|
|
selectIds.push(item.getAttribute("data-id"));
|
|
|
|
|
|
});
|
2025-06-29 22:34:08 +08:00
|
|
|
|
if (selectIds.length === 0) {
|
|
|
|
|
|
selectIds.push(target.getAttribute("data-id"));
|
|
|
|
|
|
}
|
2025-06-26 12:07:08 +08:00
|
|
|
|
event.dataTransfer.setData(`${Constants.SIYUAN_DROP_GUTTER}NodeAttributeView${Constants.ZWSP}GalleryItem${Constants.ZWSP}${selectIds}`,
|
2025-07-01 13:27:45 +08:00
|
|
|
|
ghostElement.outerHTML);
|
2025-06-26 12:07:08 +08:00
|
|
|
|
}
|
2025-06-18 11:50:33 +08:00
|
|
|
|
return;
|
2022-06-06 10:42:05 +08:00
|
|
|
|
}
|
2022-05-26 15:18:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
// 选中编辑器中的文字进行拖拽
|
|
|
|
|
|
event.dataTransfer.setData(Constants.SIYUAN_DROP_EDITOR, Constants.SIYUAN_DROP_EDITOR);
|
|
|
|
|
|
protyle.element.style.userSelect = "auto";
|
|
|
|
|
|
document.onmousemove = null;
|
|
|
|
|
|
document.onmouseup = null;
|
|
|
|
|
|
});
|
|
|
|
|
|
editorElement.addEventListener("drop", async (event: DragEvent & { target: HTMLElement }) => {
|
2024-09-22 22:42:32 +08:00
|
|
|
|
counter = 0;
|
2022-10-31 15:52:01 +08:00
|
|
|
|
if (protyle.disabled || event.dataTransfer.getData(Constants.SIYUAN_DROP_EDITOR)) {
|
|
|
|
|
|
// 只读模式/编辑器内选中文字拖拽
|
2022-10-13 00:48:27 +08:00
|
|
|
|
event.preventDefault();
|
|
|
|
|
|
event.stopPropagation();
|
2022-05-26 15:18:53 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2023-02-17 15:34:38 +08:00
|
|
|
|
let gutterType = "";
|
|
|
|
|
|
for (const item of event.dataTransfer.items) {
|
|
|
|
|
|
if (item.type.startsWith(Constants.SIYUAN_DROP_GUTTER)) {
|
|
|
|
|
|
gutterType = item.type;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-07-08 23:29:36 +08:00
|
|
|
|
if (gutterType.startsWith(`${Constants.SIYUAN_DROP_GUTTER}NodeAttributeView${Constants.ZWSP}ViewTab${Constants.ZWSP}`.toLowerCase())) {
|
|
|
|
|
|
const blockElement = hasClosestBlock(window.siyuan.dragElement);
|
|
|
|
|
|
if (blockElement) {
|
|
|
|
|
|
const avID = blockElement.getAttribute("data-av-id");
|
|
|
|
|
|
const blockID = blockElement.getAttribute("data-node-id");
|
|
|
|
|
|
const id = window.siyuan.dragElement.getAttribute("data-id");
|
|
|
|
|
|
transaction(protyle, [{
|
|
|
|
|
|
action: "sortAttrViewView",
|
|
|
|
|
|
avID,
|
|
|
|
|
|
blockID,
|
|
|
|
|
|
id,
|
2025-07-09 16:27:23 +08:00
|
|
|
|
previousID: window.siyuan.dragElement.previousElementSibling?.getAttribute("data-id"),
|
|
|
|
|
|
data: "unRefresh" // 不需要重新渲染
|
2025-07-08 23:29:36 +08:00
|
|
|
|
}], [{
|
|
|
|
|
|
action: "sortAttrViewView",
|
|
|
|
|
|
avID,
|
|
|
|
|
|
blockID,
|
|
|
|
|
|
id,
|
|
|
|
|
|
previousID: gutterType.split(Constants.ZWSP).pop()
|
|
|
|
|
|
}]);
|
|
|
|
|
|
}
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2023-10-26 23:17:27 +08:00
|
|
|
|
const targetElement = editorElement.querySelector(".dragover__left, .dragover__right, .dragover__bottom, .dragover__top");
|
|
|
|
|
|
if (targetElement) {
|
2025-02-24 23:35:22 +08:00
|
|
|
|
targetElement.classList.remove("dragover");
|
2023-10-26 23:17:27 +08:00
|
|
|
|
targetElement.removeAttribute("select-start");
|
|
|
|
|
|
targetElement.removeAttribute("select-end");
|
|
|
|
|
|
}
|
2023-02-17 15:34:38 +08:00
|
|
|
|
if (gutterType) {
|
2022-09-01 20:24:06 +08:00
|
|
|
|
// gutter 或反链面板拖拽
|
2022-10-02 11:16:44 +08:00
|
|
|
|
const sourceElements: Element[] = [];
|
2023-02-17 15:46:46 +08:00
|
|
|
|
const gutterTypes = gutterType.replace(Constants.SIYUAN_DROP_GUTTER, "").split(Constants.ZWSP);
|
2023-02-17 15:34:38 +08:00
|
|
|
|
const selectedIds = gutterTypes[2].split(",");
|
2024-08-10 17:11:49 +08:00
|
|
|
|
if (event.altKey || event.shiftKey) {
|
|
|
|
|
|
if (event.y > protyle.wysiwyg.element.lastElementChild.getBoundingClientRect().bottom) {
|
|
|
|
|
|
insertEmptyBlock(protyle, "afterend", protyle.wysiwyg.element.lastElementChild.getAttribute("data-node-id"));
|
|
|
|
|
|
} else {
|
|
|
|
|
|
const range = getRangeByPoint(event.clientX, event.clientY);
|
|
|
|
|
|
if (hasClosestByAttribute(range.startContainer, "data-type", "NodeBlockQueryEmbed")) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
focusByRange(range);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2022-10-02 11:16:44 +08:00
|
|
|
|
if (event.altKey) {
|
2022-10-03 16:22:18 +08:00
|
|
|
|
let html = "";
|
2022-10-02 11:16:44 +08:00
|
|
|
|
for (let i = 0; i < selectedIds.length; i++) {
|
|
|
|
|
|
const response = await fetchSyncPost("/api/block/getRefText", {id: selectedIds[i]});
|
2024-12-05 17:53:57 +08:00
|
|
|
|
html += protyle.lute.Md2BlockDOM(`((${selectedIds[i]} '${response.data}'))`);
|
2022-05-26 15:18:53 +08:00
|
|
|
|
}
|
2022-10-02 11:16:44 +08:00
|
|
|
|
insertHTML(html, protyle);
|
|
|
|
|
|
} else if (event.shiftKey) {
|
2022-10-03 16:22:18 +08:00
|
|
|
|
let html = "";
|
2022-10-02 11:16:44 +08:00
|
|
|
|
selectedIds.forEach(item => {
|
2022-10-03 16:22:18 +08:00
|
|
|
|
html += `{{select * from blocks where id='${item}'}}\n`;
|
|
|
|
|
|
});
|
2022-11-14 23:14:44 +08:00
|
|
|
|
insertHTML(protyle.lute.SpinBlockDOM(html), protyle, true);
|
2022-10-02 11:16:44 +08:00
|
|
|
|
blockRender(protyle, protyle.wysiwyg.element);
|
2023-06-16 11:36:50 +08:00
|
|
|
|
} else if (targetElement && targetElement.className.indexOf("dragover__") > -1) {
|
2023-02-17 15:46:46 +08:00
|
|
|
|
let queryClass = "";
|
2023-02-17 15:34:38 +08:00
|
|
|
|
selectedIds.forEach(item => {
|
2023-02-20 09:16:54 +08:00
|
|
|
|
queryClass += `[data-node-id="${item}"],`;
|
2023-02-17 15:34:38 +08:00
|
|
|
|
});
|
|
|
|
|
|
if (window.siyuan.dragElement) {
|
|
|
|
|
|
window.siyuan.dragElement.querySelectorAll(queryClass.substring(0, queryClass.length - 1)).forEach(elementItem => {
|
2024-07-25 17:55:25 +08:00
|
|
|
|
if (!isInEmbedBlock(elementItem)) {
|
2023-02-17 15:34:38 +08:00
|
|
|
|
sourceElements.push(elementItem);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
2024-12-25 21:16:40 +08:00
|
|
|
|
} else if (window.siyuan.config.system.workspaceDir.toLowerCase() === gutterTypes[3]) {
|
|
|
|
|
|
// 跨窗口拖拽
|
|
|
|
|
|
// 不能跨工作区域拖拽 https://github.com/siyuan-note/siyuan/issues/13582
|
2023-02-17 15:46:46 +08:00
|
|
|
|
const targetProtyleElement = document.createElement("template");
|
2023-02-22 09:08:54 +08:00
|
|
|
|
targetProtyleElement.innerHTML = `<div>${event.dataTransfer.getData(gutterType)}</div>`;
|
2023-02-17 15:34:38 +08:00
|
|
|
|
targetProtyleElement.content.querySelectorAll(queryClass.substring(0, queryClass.length - 1)).forEach(elementItem => {
|
2024-07-25 17:55:25 +08:00
|
|
|
|
if (!isInEmbedBlock(elementItem)) {
|
2023-02-17 15:34:38 +08:00
|
|
|
|
sourceElements.push(elementItem);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-03-03 10:39:58 +08:00
|
|
|
|
const sourceIds: string [] = [];
|
2024-04-20 22:43:25 +08:00
|
|
|
|
const srcs: IOperationSrcs[] = [];
|
2023-02-17 15:34:38 +08:00
|
|
|
|
sourceElements.forEach(item => {
|
2025-02-24 23:35:22 +08:00
|
|
|
|
item.classList.remove("protyle-wysiwyg--hl");
|
2023-02-17 15:34:38 +08:00
|
|
|
|
item.removeAttribute("select-start");
|
|
|
|
|
|
item.removeAttribute("select-end");
|
|
|
|
|
|
// 反链提及有高亮,如果拖拽到正文的话,应移除
|
|
|
|
|
|
item.querySelectorAll('[data-type="search-mark"]').forEach(markItem => {
|
|
|
|
|
|
markItem.outerHTML = markItem.innerHTML;
|
|
|
|
|
|
});
|
2024-04-23 13:29:32 +08:00
|
|
|
|
const id = item.getAttribute("data-node-id");
|
2024-04-20 22:43:25 +08:00
|
|
|
|
sourceIds.push(id);
|
|
|
|
|
|
srcs.push({
|
|
|
|
|
|
id,
|
|
|
|
|
|
isDetached: false,
|
2024-04-23 13:29:32 +08:00
|
|
|
|
});
|
2023-02-17 15:34:38 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
2022-11-22 21:54:52 +08:00
|
|
|
|
hideElements(["gutter"], protyle);
|
2023-09-28 14:09:39 +08:00
|
|
|
|
|
|
|
|
|
|
const targetClass = targetElement.className.split(" ");
|
2023-10-26 23:17:27 +08:00
|
|
|
|
targetElement.classList.remove("dragover__bottom", "dragover__top", "dragover__left", "dragover__right");
|
2023-09-28 14:09:39 +08:00
|
|
|
|
|
2023-07-01 23:32:03 +08:00
|
|
|
|
if (targetElement.classList.contains("av__cell")) {
|
|
|
|
|
|
const blockElement = hasClosestBlock(targetElement);
|
2023-09-28 14:09:39 +08:00
|
|
|
|
if (blockElement) {
|
|
|
|
|
|
const avID = blockElement.getAttribute("data-av-id");
|
2023-11-14 12:58:45 +08:00
|
|
|
|
let previousID = "";
|
|
|
|
|
|
if (targetClass.includes("dragover__left")) {
|
|
|
|
|
|
if (targetElement.previousElementSibling) {
|
|
|
|
|
|
if (targetElement.previousElementSibling.classList.contains("av__colsticky")) {
|
2023-11-14 23:18:18 +08:00
|
|
|
|
previousID = targetElement.previousElementSibling.lastElementChild.getAttribute("data-col-id");
|
2023-11-14 12:58:45 +08:00
|
|
|
|
} else {
|
2023-11-14 23:18:18 +08:00
|
|
|
|
previousID = targetElement.previousElementSibling.getAttribute("data-col-id");
|
2023-11-14 12:58:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
2023-11-14 23:18:18 +08:00
|
|
|
|
previousID = targetElement.getAttribute("data-col-id");
|
2023-11-14 12:58:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
let oldPreviousID = "";
|
|
|
|
|
|
const rowElement = hasClosestByClassName(targetElement, "av__row");
|
|
|
|
|
|
if (rowElement) {
|
2023-11-14 23:18:18 +08:00
|
|
|
|
const oldPreviousElement = rowElement.querySelector(`[data-col-id="${gutterTypes[2]}"`)?.previousElementSibling;
|
2023-11-14 12:58:45 +08:00
|
|
|
|
if (oldPreviousElement) {
|
|
|
|
|
|
if (oldPreviousElement.classList.contains("av__colsticky")) {
|
2023-11-14 23:18:18 +08:00
|
|
|
|
oldPreviousID = oldPreviousElement.lastElementChild.getAttribute("data-col-id");
|
2023-11-14 12:58:45 +08:00
|
|
|
|
} else {
|
2023-11-14 23:18:18 +08:00
|
|
|
|
oldPreviousID = oldPreviousElement.getAttribute("data-col-id");
|
2023-11-14 12:58:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-04-18 19:48:09 +08:00
|
|
|
|
if (previousID !== oldPreviousID && previousID !== gutterTypes[2]) {
|
|
|
|
|
|
transaction(protyle, [{
|
|
|
|
|
|
action: "sortAttrViewCol",
|
|
|
|
|
|
avID,
|
|
|
|
|
|
previousID,
|
|
|
|
|
|
id: gutterTypes[2],
|
|
|
|
|
|
blockID: blockElement.dataset.nodeId,
|
|
|
|
|
|
}], [{
|
|
|
|
|
|
action: "sortAttrViewCol",
|
|
|
|
|
|
avID,
|
|
|
|
|
|
previousID: oldPreviousID,
|
|
|
|
|
|
id: gutterTypes[2],
|
|
|
|
|
|
blockID: blockElement.dataset.nodeId,
|
|
|
|
|
|
}]);
|
|
|
|
|
|
}
|
2023-06-08 18:21:10 +08:00
|
|
|
|
}
|
2023-09-28 14:09:39 +08:00
|
|
|
|
} else if (targetElement.classList.contains("av__row")) {
|
2025-06-18 11:50:33 +08:00
|
|
|
|
// 拖拽到属性视图 table 内
|
2023-09-28 14:09:39 +08:00
|
|
|
|
const blockElement = hasClosestBlock(targetElement);
|
2024-12-27 21:54:22 +08:00
|
|
|
|
if (blockElement) {
|
2023-09-28 14:09:39 +08:00
|
|
|
|
let previousID = "";
|
|
|
|
|
|
if (targetClass.includes("dragover__bottom")) {
|
|
|
|
|
|
previousID = targetElement.getAttribute("data-id") || "";
|
|
|
|
|
|
} else {
|
|
|
|
|
|
previousID = targetElement.previousElementSibling?.getAttribute("data-id") || "";
|
|
|
|
|
|
}
|
|
|
|
|
|
const avID = blockElement.getAttribute("data-av-id");
|
2023-12-21 00:33:48 +08:00
|
|
|
|
if (gutterTypes[0] === "nodeattributeviewrowmenu") {
|
2023-09-28 14:09:39 +08:00
|
|
|
|
// 行内拖拽
|
|
|
|
|
|
const doOperations: IOperation[] = [];
|
|
|
|
|
|
const undoOperations: IOperation[] = [];
|
2024-06-03 11:43:37 +08:00
|
|
|
|
const undoPreviousId = blockElement.querySelector(`.av__row[data-id="${selectedIds[0]}"]`).previousElementSibling.getAttribute("data-id") || "";
|
2025-07-28 10:22:40 +08:00
|
|
|
|
const targetGroupID = targetElement.parentElement.getAttribute("data-group-id");
|
2023-09-28 14:09:39 +08:00
|
|
|
|
selectedIds.reverse().forEach(item => {
|
2024-04-18 19:48:09 +08:00
|
|
|
|
if (previousID !== item && undoPreviousId !== previousID) {
|
2025-07-28 10:22:40 +08:00
|
|
|
|
const groupID = blockElement.querySelector(`.av__row[data-id="${selectedIds[0]}"]`).parentElement.getAttribute("data-group-id");
|
2024-04-17 23:43:03 +08:00
|
|
|
|
doOperations.push({
|
|
|
|
|
|
action: "sortAttrViewRow",
|
|
|
|
|
|
avID,
|
|
|
|
|
|
previousID,
|
|
|
|
|
|
id: item,
|
|
|
|
|
|
blockID: blockElement.dataset.nodeId,
|
2025-07-28 10:22:40 +08:00
|
|
|
|
groupID,
|
|
|
|
|
|
targetGroupID,
|
2024-04-17 23:43:03 +08:00
|
|
|
|
});
|
|
|
|
|
|
undoOperations.push({
|
|
|
|
|
|
action: "sortAttrViewRow",
|
|
|
|
|
|
avID,
|
|
|
|
|
|
previousID: undoPreviousId,
|
|
|
|
|
|
id: item,
|
|
|
|
|
|
blockID: blockElement.dataset.nodeId,
|
2025-07-28 10:22:40 +08:00
|
|
|
|
groupID: targetGroupID,
|
|
|
|
|
|
targetGroupID: groupID,
|
2024-04-17 23:43:03 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
2023-09-28 14:09:39 +08:00
|
|
|
|
});
|
|
|
|
|
|
transaction(protyle, doOperations, undoOperations);
|
|
|
|
|
|
} else {
|
2024-03-08 21:37:42 +08:00
|
|
|
|
const newUpdated = dayjs().format("YYYYMMDDHHmmss");
|
2025-07-28 12:42:32 +08:00
|
|
|
|
const groupID = targetElement.parentElement.getAttribute("data-group-id");
|
2023-09-28 14:09:39 +08:00
|
|
|
|
transaction(protyle, [{
|
|
|
|
|
|
action: "insertAttrViewBlock",
|
|
|
|
|
|
avID,
|
|
|
|
|
|
previousID,
|
2024-04-20 22:43:25 +08:00
|
|
|
|
srcs,
|
2025-07-27 19:10:43 +08:00
|
|
|
|
blockID: blockElement.dataset.nodeId,
|
2025-07-28 12:42:32 +08:00
|
|
|
|
groupID
|
2024-03-08 21:37:42 +08:00
|
|
|
|
}, {
|
|
|
|
|
|
action: "doUpdateUpdated",
|
|
|
|
|
|
id: blockElement.dataset.nodeId,
|
|
|
|
|
|
data: newUpdated,
|
2023-09-28 14:09:39 +08:00
|
|
|
|
}], [{
|
|
|
|
|
|
action: "removeAttrViewBlock",
|
|
|
|
|
|
srcIDs: sourceIds,
|
|
|
|
|
|
avID,
|
2024-03-08 21:37:42 +08:00
|
|
|
|
}, {
|
|
|
|
|
|
action: "doUpdateUpdated",
|
|
|
|
|
|
id: blockElement.dataset.nodeId,
|
|
|
|
|
|
data: blockElement.getAttribute("updated")
|
2023-09-28 14:09:39 +08:00
|
|
|
|
}]);
|
2024-03-08 21:37:42 +08:00
|
|
|
|
blockElement.setAttribute("updated", newUpdated);
|
2025-07-28 12:42:32 +08:00
|
|
|
|
insertAttrViewBlockAnimation({
|
|
|
|
|
|
protyle,
|
|
|
|
|
|
blockElement,
|
|
|
|
|
|
srcIDs: sourceIds,
|
|
|
|
|
|
previousId: previousID,
|
|
|
|
|
|
groupID
|
|
|
|
|
|
});
|
2023-09-28 14:09:39 +08:00
|
|
|
|
}
|
2022-10-02 11:16:44 +08:00
|
|
|
|
}
|
2025-06-26 11:11:14 +08:00
|
|
|
|
} else if (targetElement.classList.contains("av__gallery-item") || targetElement.classList.contains("av__gallery-add")) {
|
2025-06-18 11:50:33 +08:00
|
|
|
|
// 拖拽到属性视图 gallery 内
|
|
|
|
|
|
const blockElement = hasClosestBlock(targetElement);
|
|
|
|
|
|
if (blockElement) {
|
|
|
|
|
|
let previousID = "";
|
|
|
|
|
|
if (targetClass.includes("dragover__right")) {
|
|
|
|
|
|
previousID = targetElement.getAttribute("data-id") || "";
|
|
|
|
|
|
} else {
|
|
|
|
|
|
previousID = targetElement.previousElementSibling?.getAttribute("data-id") || "";
|
|
|
|
|
|
}
|
|
|
|
|
|
const avID = blockElement.getAttribute("data-av-id");
|
|
|
|
|
|
if (gutterTypes[1] === "galleryitem" && gutterTypes[0] === "nodeattributeview") {
|
|
|
|
|
|
// gallery item 内部拖拽
|
|
|
|
|
|
const doOperations: IOperation[] = [];
|
|
|
|
|
|
const undoOperations: IOperation[] = [];
|
2025-06-23 11:28:00 +08:00
|
|
|
|
const undoPreviousId = blockElement.querySelector(`.av__gallery-item[data-id="${selectedIds[0]}"]`).previousElementSibling?.getAttribute("data-id") || "";
|
2025-07-28 10:22:40 +08:00
|
|
|
|
const targetGroupID = targetElement.parentElement.getAttribute("data-group-id");
|
2025-06-18 11:50:33 +08:00
|
|
|
|
selectedIds.reverse().forEach(item => {
|
|
|
|
|
|
if (previousID !== item && undoPreviousId !== previousID) {
|
2025-07-28 10:22:40 +08:00
|
|
|
|
const groupID = blockElement.querySelector(`.av__row[data-id="${selectedIds[0]}"]`).parentElement.getAttribute("data-group-id");
|
2025-06-18 11:50:33 +08:00
|
|
|
|
doOperations.push({
|
|
|
|
|
|
action: "sortAttrViewRow",
|
|
|
|
|
|
avID,
|
|
|
|
|
|
previousID,
|
|
|
|
|
|
id: item,
|
|
|
|
|
|
blockID: blockElement.dataset.nodeId,
|
2025-07-28 10:22:40 +08:00
|
|
|
|
groupID,
|
|
|
|
|
|
targetGroupID,
|
2025-06-18 11:50:33 +08:00
|
|
|
|
});
|
|
|
|
|
|
undoOperations.push({
|
|
|
|
|
|
action: "sortAttrViewRow",
|
|
|
|
|
|
avID,
|
|
|
|
|
|
previousID: undoPreviousId,
|
|
|
|
|
|
id: item,
|
|
|
|
|
|
blockID: blockElement.dataset.nodeId,
|
2025-07-28 10:22:40 +08:00
|
|
|
|
groupID: targetGroupID,
|
|
|
|
|
|
targetGroupID: groupID,
|
2025-06-18 11:50:33 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
transaction(protyle, doOperations, undoOperations);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
const newUpdated = dayjs().format("YYYYMMDDHHmmss");
|
|
|
|
|
|
transaction(protyle, [{
|
|
|
|
|
|
action: "insertAttrViewBlock",
|
|
|
|
|
|
avID,
|
|
|
|
|
|
previousID,
|
|
|
|
|
|
srcs,
|
2025-07-27 19:10:43 +08:00
|
|
|
|
blockID: blockElement.dataset.nodeId,
|
|
|
|
|
|
groupID: targetElement.parentElement.getAttribute("data-group-id")
|
2025-06-18 11:50:33 +08:00
|
|
|
|
}, {
|
|
|
|
|
|
action: "doUpdateUpdated",
|
|
|
|
|
|
id: blockElement.dataset.nodeId,
|
|
|
|
|
|
data: newUpdated,
|
|
|
|
|
|
}], [{
|
|
|
|
|
|
action: "removeAttrViewBlock",
|
|
|
|
|
|
srcIDs: sourceIds,
|
|
|
|
|
|
avID,
|
|
|
|
|
|
}, {
|
|
|
|
|
|
action: "doUpdateUpdated",
|
|
|
|
|
|
id: blockElement.dataset.nodeId,
|
|
|
|
|
|
data: blockElement.getAttribute("updated")
|
|
|
|
|
|
}]);
|
|
|
|
|
|
blockElement.setAttribute("updated", newUpdated);
|
|
|
|
|
|
insertGalleryItemAnimation({
|
|
|
|
|
|
protyle,
|
|
|
|
|
|
blockElement,
|
|
|
|
|
|
srcIDs: sourceIds,
|
|
|
|
|
|
previousId: previousID
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-11-10 12:26:07 +08:00
|
|
|
|
} else if (sourceElements.length > 0) {
|
2023-09-28 14:09:39 +08:00
|
|
|
|
if (targetElement.parentElement.getAttribute("data-type") === "NodeSuperBlock" &&
|
|
|
|
|
|
targetElement.parentElement.getAttribute("data-sb-layout") === "col") {
|
|
|
|
|
|
if (targetClass.includes("dragover__left") || targetClass.includes("dragover__right")) {
|
2023-11-12 12:28:20 +08:00
|
|
|
|
// Mac 上 ⌘ 无法进行拖拽
|
2023-09-28 14:09:39 +08:00
|
|
|
|
dragSame(protyle, sourceElements, targetElement, targetClass.includes("dragover__right"), event.ctrlKey);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
dragSb(protyle, sourceElements, targetElement, targetClass.includes("dragover__bottom"), "row", event.ctrlKey);
|
|
|
|
|
|
}
|
2022-10-02 11:16:44 +08:00
|
|
|
|
} else {
|
2023-09-28 14:09:39 +08:00
|
|
|
|
if (targetClass.includes("dragover__left") || targetClass.includes("dragover__right")) {
|
|
|
|
|
|
dragSb(protyle, sourceElements, targetElement, targetClass.includes("dragover__right"), "col", event.ctrlKey);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
dragSame(protyle, sourceElements, targetElement, targetClass.includes("dragover__bottom"), event.ctrlKey);
|
|
|
|
|
|
}
|
2022-10-02 11:16:44 +08:00
|
|
|
|
}
|
2024-07-03 22:51:46 +08:00
|
|
|
|
|
|
|
|
|
|
// https://github.com/siyuan-note/siyuan/issues/10528#issuecomment-2205165824
|
|
|
|
|
|
editorElement.querySelectorAll(".protyle-wysiwyg--empty").forEach(item => {
|
|
|
|
|
|
item.classList.remove("protyle-wysiwyg--empty");
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2023-09-28 14:09:39 +08:00
|
|
|
|
// 超级块内嵌入块无面包屑,需重新渲染 https://github.com/siyuan-note/siyuan/issues/7574
|
|
|
|
|
|
sourceElements.forEach(item => {
|
|
|
|
|
|
if (item.getAttribute("data-type") === "NodeBlockQueryEmbed") {
|
|
|
|
|
|
item.removeAttribute("data-render");
|
|
|
|
|
|
blockRender(protyle, item);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
if (targetElement.getAttribute("data-type") === "NodeBlockQueryEmbed") {
|
|
|
|
|
|
targetElement.removeAttribute("data-render");
|
|
|
|
|
|
blockRender(protyle, targetElement);
|
2023-03-05 14:18:23 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-12-16 23:12:10 +08:00
|
|
|
|
dragoverElement = undefined;
|
2022-05-26 15:18:53 +08:00
|
|
|
|
}
|
2024-10-09 22:52:41 +08:00
|
|
|
|
} else if (event.dataTransfer.getData(Constants.SIYUAN_DROP_FILE)?.split("-").length > 1) {
|
2022-05-26 15:18:53 +08:00
|
|
|
|
// 文件树拖拽
|
2022-11-21 23:36:49 +08:00
|
|
|
|
const ids = event.dataTransfer.getData(Constants.SIYUAN_DROP_FILE).split(",");
|
2025-06-26 11:44:25 +08:00
|
|
|
|
if (!event.altKey && (!targetElement || (
|
|
|
|
|
|
!targetElement.classList.contains("av__row") && !targetElement.classList.contains("av__gallery-item") &&
|
|
|
|
|
|
!targetElement.classList.contains("av__gallery-add")
|
|
|
|
|
|
))) {
|
2024-10-09 22:52:41 +08:00
|
|
|
|
if (event.y > protyle.wysiwyg.element.lastElementChild.getBoundingClientRect().bottom) {
|
|
|
|
|
|
insertEmptyBlock(protyle, "afterend", protyle.wysiwyg.element.lastElementChild.getAttribute("data-node-id"));
|
|
|
|
|
|
} else {
|
|
|
|
|
|
const range = getRangeByPoint(event.clientX, event.clientY);
|
|
|
|
|
|
if (hasClosestByAttribute(range.startContainer, "data-type", "NodeBlockQueryEmbed")) {
|
|
|
|
|
|
return;
|
2023-09-28 14:09:39 +08:00
|
|
|
|
} else {
|
2024-10-09 22:52:41 +08:00
|
|
|
|
focusByRange(range);
|
2023-09-28 14:09:39 +08:00
|
|
|
|
}
|
2023-07-31 14:18:19 +08:00
|
|
|
|
}
|
2024-10-09 22:52:41 +08:00
|
|
|
|
let html = "";
|
2023-09-28 14:09:39 +08:00
|
|
|
|
for (let i = 0; i < ids.length; i++) {
|
2025-02-18 09:37:46 +08:00
|
|
|
|
if (ids.length > 1) {
|
|
|
|
|
|
html += "* ";
|
|
|
|
|
|
}
|
2024-10-09 22:52:41 +08:00
|
|
|
|
const response = await fetchSyncPost("/api/block/getRefText", {id: ids[i]});
|
2025-02-18 09:37:46 +08:00
|
|
|
|
html += `((${ids[i]} '${response.data}'))`;
|
|
|
|
|
|
if (ids.length > 1 && i !== ids.length - 1) {
|
|
|
|
|
|
html += "\n";
|
|
|
|
|
|
}
|
2024-10-09 22:52:41 +08:00
|
|
|
|
}
|
2025-02-18 09:37:46 +08:00
|
|
|
|
insertHTML(protyle.lute.Md2BlockDOM(html), protyle);
|
2024-10-09 22:52:41 +08:00
|
|
|
|
} else if (targetElement && !protyle.options.backlinkData && targetElement.className.indexOf("dragover__") > -1) {
|
|
|
|
|
|
const scrollTop = protyle.contentElement.scrollTop;
|
2025-06-26 11:44:25 +08:00
|
|
|
|
if (targetElement.classList.contains("av__row") ||
|
|
|
|
|
|
targetElement.classList.contains("av__gallery-item") ||
|
|
|
|
|
|
targetElement.classList.contains("av__gallery-add")) {
|
2024-10-09 22:52:41 +08:00
|
|
|
|
// 拖拽到属性视图内
|
|
|
|
|
|
const blockElement = hasClosestBlock(targetElement);
|
|
|
|
|
|
if (blockElement) {
|
|
|
|
|
|
let previousID = "";
|
|
|
|
|
|
if (targetElement.classList.contains("dragover__bottom")) {
|
|
|
|
|
|
previousID = targetElement.getAttribute("data-id") || "";
|
2025-06-26 11:44:25 +08:00
|
|
|
|
} else if (targetElement.classList.contains("dragover__top")) {
|
|
|
|
|
|
previousID = targetElement.previousElementSibling?.getAttribute("data-id") || "";
|
|
|
|
|
|
} else if (targetElement.classList.contains("dragover__left")) {
|
2024-10-09 22:52:41 +08:00
|
|
|
|
previousID = targetElement.previousElementSibling?.getAttribute("data-id") || "";
|
2025-06-26 11:44:25 +08:00
|
|
|
|
} else if (targetElement.classList.contains("dragover__right")) {
|
|
|
|
|
|
previousID = targetElement.getAttribute("data-id") || "";
|
2024-10-09 22:52:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
const avID = blockElement.getAttribute("data-av-id");
|
|
|
|
|
|
const newUpdated = dayjs().format("YYYYMMDDHHmmss");
|
|
|
|
|
|
const srcs: IOperationSrcs[] = [];
|
2025-07-28 12:42:32 +08:00
|
|
|
|
const groupID = targetElement.parentElement.getAttribute("data-group-id");
|
2024-10-09 22:52:41 +08:00
|
|
|
|
ids.forEach(id => {
|
|
|
|
|
|
srcs.push({
|
|
|
|
|
|
id,
|
|
|
|
|
|
isDetached: false,
|
|
|
|
|
|
});
|
2023-09-28 14:09:39 +08:00
|
|
|
|
});
|
2024-10-09 22:52:41 +08:00
|
|
|
|
transaction(protyle, [{
|
|
|
|
|
|
action: "insertAttrViewBlock",
|
|
|
|
|
|
avID,
|
|
|
|
|
|
previousID,
|
|
|
|
|
|
srcs,
|
|
|
|
|
|
blockID: blockElement.dataset.nodeId,
|
2025-07-28 12:42:32 +08:00
|
|
|
|
groupID
|
2024-10-09 22:52:41 +08:00
|
|
|
|
}, {
|
|
|
|
|
|
action: "doUpdateUpdated",
|
|
|
|
|
|
id: blockElement.dataset.nodeId,
|
|
|
|
|
|
data: newUpdated,
|
|
|
|
|
|
}], [{
|
|
|
|
|
|
action: "removeAttrViewBlock",
|
|
|
|
|
|
srcIDs: ids,
|
|
|
|
|
|
avID,
|
|
|
|
|
|
}, {
|
|
|
|
|
|
action: "doUpdateUpdated",
|
|
|
|
|
|
id: blockElement.dataset.nodeId,
|
|
|
|
|
|
data: blockElement.getAttribute("updated")
|
|
|
|
|
|
}]);
|
2025-07-28 12:42:32 +08:00
|
|
|
|
insertAttrViewBlockAnimation({
|
|
|
|
|
|
protyle,
|
|
|
|
|
|
blockElement,
|
|
|
|
|
|
srcIDs: ids,
|
|
|
|
|
|
previousId: previousID,
|
|
|
|
|
|
groupID
|
|
|
|
|
|
});
|
2024-10-09 22:52:41 +08:00
|
|
|
|
blockElement.setAttribute("updated", newUpdated);
|
2023-09-28 14:09:39 +08:00
|
|
|
|
}
|
2024-10-09 22:52:41 +08:00
|
|
|
|
} else {
|
2024-12-13 09:49:10 +08:00
|
|
|
|
if (targetElement.classList.contains("dragover__bottom")) {
|
|
|
|
|
|
for (let i = ids.length - 1; i > -1; i--) {
|
|
|
|
|
|
if (ids[i]) {
|
|
|
|
|
|
await fetchSyncPost("/api/filetree/doc2Heading", {
|
|
|
|
|
|
srcID: ids[i],
|
|
|
|
|
|
after: true,
|
|
|
|
|
|
targetID: targetElement.getAttribute("data-node-id"),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
for (let i = 0; i < ids.length; i++) {
|
|
|
|
|
|
if (ids[i]) {
|
|
|
|
|
|
await fetchSyncPost("/api/filetree/doc2Heading", {
|
|
|
|
|
|
srcID: ids[i],
|
|
|
|
|
|
after: false,
|
|
|
|
|
|
targetID: targetElement.getAttribute("data-node-id"),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2024-10-09 22:52:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-12-13 09:49:10 +08:00
|
|
|
|
|
2024-10-09 22:52:41 +08:00
|
|
|
|
fetchPost("/api/filetree/getDoc", {
|
|
|
|
|
|
id: protyle.block.id,
|
|
|
|
|
|
size: window.siyuan.config.editor.dynamicLoadBlocks,
|
|
|
|
|
|
}, getResponse => {
|
|
|
|
|
|
onGet({data: getResponse, protyle});
|
|
|
|
|
|
/// #if !MOBILE
|
|
|
|
|
|
// 文档标题互转后,需更新大纲
|
|
|
|
|
|
updatePanelByEditor({
|
|
|
|
|
|
protyle,
|
|
|
|
|
|
focus: false,
|
|
|
|
|
|
pushBackStack: false,
|
|
|
|
|
|
reload: true,
|
|
|
|
|
|
resize: false,
|
|
|
|
|
|
});
|
|
|
|
|
|
/// #endif
|
|
|
|
|
|
// 文档标题互转后,编辑区会跳转到开头 https://github.com/siyuan-note/siyuan/issues/2939
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
protyle.contentElement.scrollTop = scrollTop;
|
|
|
|
|
|
protyle.scroll.lastScrollTop = scrollTop - 1;
|
|
|
|
|
|
}, Constants.TIMEOUT_LOAD);
|
2022-11-04 20:57:53 +08:00
|
|
|
|
});
|
2024-10-09 22:52:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
targetElement.classList.remove("dragover__bottom", "dragover__top", "dragover__left", "dragover__right");
|
2023-09-28 14:09:39 +08:00
|
|
|
|
}
|
2022-05-26 15:18:53 +08:00
|
|
|
|
} else if (!window.siyuan.dragElement && (event.dataTransfer.types[0] === "Files" || event.dataTransfer.types.includes("text/html"))) {
|
|
|
|
|
|
// 外部文件拖入编辑器中或者编辑器内选中文字拖拽
|
2023-10-29 19:06:01 +08:00
|
|
|
|
// https://github.com/siyuan-note/siyuan/issues/9544
|
2023-10-31 09:46:19 +08:00
|
|
|
|
const avElement = hasClosestByClassName(event.target, "av");
|
2023-10-29 19:06:01 +08:00
|
|
|
|
if (!avElement) {
|
|
|
|
|
|
focusByRange(getRangeByPoint(event.clientX, event.clientY));
|
|
|
|
|
|
if (event.dataTransfer.types[0] === "Files" && !isBrowser()) {
|
|
|
|
|
|
const files: string[] = [];
|
|
|
|
|
|
for (let i = 0; i < event.dataTransfer.files.length; i++) {
|
2024-10-16 22:25:53 +08:00
|
|
|
|
files.push(webUtils.getPathForFile(event.dataTransfer.files[i]));
|
2023-10-29 19:06:01 +08:00
|
|
|
|
}
|
|
|
|
|
|
uploadLocalFiles(files, protyle, !event.altKey);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
paste(protyle, event);
|
2022-08-24 14:46:39 +08:00
|
|
|
|
}
|
2025-06-20 10:58:34 +08:00
|
|
|
|
clearSelect(["av", "img"], protyle.wysiwyg.element);
|
2022-08-24 14:46:39 +08:00
|
|
|
|
} else {
|
2023-10-31 09:46:19 +08:00
|
|
|
|
const cellElement = hasClosestByClassName(event.target, "av__cell");
|
2023-10-29 19:06:01 +08:00
|
|
|
|
if (cellElement) {
|
2025-06-30 12:26:47 +08:00
|
|
|
|
if (getTypeByCellElement(cellElement) === "mAsset" && event.dataTransfer.types[0] === "Files" && !isBrowser()) {
|
2023-10-29 19:06:01 +08:00
|
|
|
|
const files: string[] = [];
|
|
|
|
|
|
for (let i = 0; i < event.dataTransfer.files.length; i++) {
|
2024-10-16 22:25:53 +08:00
|
|
|
|
files.push(webUtils.getPathForFile(event.dataTransfer.files[i]));
|
2023-10-29 19:06:01 +08:00
|
|
|
|
}
|
2024-05-15 11:17:34 +08:00
|
|
|
|
dragUpload(files, protyle, cellElement);
|
2025-06-30 12:26:47 +08:00
|
|
|
|
clearSelect(["cell"], avElement);
|
2023-10-29 19:06:01 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2022-08-24 14:46:39 +08:00
|
|
|
|
}
|
2022-05-26 15:18:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
if (window.siyuan.dragElement) {
|
|
|
|
|
|
window.siyuan.dragElement.style.opacity = "";
|
|
|
|
|
|
window.siyuan.dragElement = undefined;
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
let dragoverElement: Element;
|
2022-12-14 15:29:23 +08:00
|
|
|
|
let disabledPosition: string;
|
2022-05-26 15:18:53 +08:00
|
|
|
|
editorElement.addEventListener("dragover", (event: DragEvent & { target: HTMLElement }) => {
|
2024-03-25 10:23:03 +08:00
|
|
|
|
if (protyle.disabled || event.dataTransfer.types.includes(Constants.SIYUAN_DROP_EDITOR)) {
|
2023-12-07 22:09:51 +08:00
|
|
|
|
event.preventDefault();
|
|
|
|
|
|
event.stopPropagation();
|
2024-03-25 10:23:03 +08:00
|
|
|
|
event.dataTransfer.dropEffect = "none";
|
2023-12-07 22:09:51 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-07-08 23:29:36 +08:00
|
|
|
|
let gutterType = "";
|
|
|
|
|
|
for (const item of event.dataTransfer.items) {
|
|
|
|
|
|
if (item.type.startsWith(Constants.SIYUAN_DROP_GUTTER)) {
|
|
|
|
|
|
gutterType = item.type;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (gutterType.startsWith(`${Constants.SIYUAN_DROP_GUTTER}NodeAttributeView${Constants.ZWSP}ViewTab${Constants.ZWSP}`.toLowerCase())) {
|
|
|
|
|
|
dragoverTab(event);
|
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2023-12-05 12:01:41 +08:00
|
|
|
|
const contentRect = protyle.contentElement.getBoundingClientRect();
|
2025-07-08 23:29:36 +08:00
|
|
|
|
if (!hasClosestByClassName(event.target, "av__cell") &&
|
|
|
|
|
|
(event.clientY < contentRect.top + Constants.SIZE_SCROLL_TB || event.clientY > contentRect.bottom - Constants.SIZE_SCROLL_TB)) {
|
2023-12-05 12:01:41 +08:00
|
|
|
|
protyle.contentElement.scroll({
|
|
|
|
|
|
top: protyle.contentElement.scrollTop + (event.clientY < contentRect.top + Constants.SIZE_SCROLL_TB ? -Constants.SIZE_SCROLL_STEP : Constants.SIZE_SCROLL_STEP),
|
|
|
|
|
|
behavior: "smooth"
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2024-11-29 11:32:47 +08:00
|
|
|
|
let targetElement: HTMLElement | false;
|
2022-09-01 20:24:06 +08:00
|
|
|
|
// 设置了的话 drop 就无法监听 shift/control event.dataTransfer.dropEffect = "move";
|
2024-10-22 11:35:52 +08:00
|
|
|
|
if (event.dataTransfer.types.includes("Files")) {
|
2024-11-29 11:32:47 +08:00
|
|
|
|
targetElement = hasClosestByClassName(event.target, "av__cell");
|
|
|
|
|
|
if (targetElement && targetElement.getAttribute("data-dtype") === "mAsset" &&
|
|
|
|
|
|
!targetElement.classList.contains("av__cell--header")) {
|
|
|
|
|
|
event.preventDefault(); // 不使用导致无法触发 drop
|
2025-07-23 13:08:38 +08:00
|
|
|
|
if (dragoverElement && targetElement === dragoverElement) {
|
2024-11-29 11:32:47 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
const blockElement = hasClosestBlock(targetElement);
|
|
|
|
|
|
if (blockElement) {
|
2025-06-20 10:58:34 +08:00
|
|
|
|
clearSelect(["cell", "row"], protyle.wysiwyg.element);
|
2024-11-29 11:32:47 +08:00
|
|
|
|
targetElement.classList.add("av__cell--select");
|
2025-06-30 12:26:47 +08:00
|
|
|
|
if (blockElement.getAttribute("data-av-type") !== "gallery") {
|
|
|
|
|
|
addDragFill(targetElement);
|
|
|
|
|
|
}
|
2024-11-29 11:32:47 +08:00
|
|
|
|
dragoverElement = targetElement;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-10-22 11:35:52 +08:00
|
|
|
|
// 使用 event.preventDefault(); 会导致无光标 https://github.com/siyuan-note/siyuan/issues/12857
|
2022-05-26 15:18:53 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-07-08 23:29:36 +08:00
|
|
|
|
|
2023-02-17 15:34:38 +08:00
|
|
|
|
if (!gutterType && !window.siyuan.dragElement) {
|
2022-11-01 18:19:17 +08:00
|
|
|
|
// https://github.com/siyuan-note/siyuan/issues/6436
|
|
|
|
|
|
event.preventDefault();
|
2022-05-26 15:18:53 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2024-11-28 11:47:48 +08:00
|
|
|
|
const fileTreeIds = (event.dataTransfer.types.includes(Constants.SIYUAN_DROP_FILE) && window.siyuan.dragElement) ? window.siyuan.dragElement.innerText : "";
|
2024-11-29 09:11:13 +08:00
|
|
|
|
if (event.shiftKey || (event.altKey && fileTreeIds.indexOf("-") === -1)) {
|
2025-06-18 11:50:33 +08:00
|
|
|
|
const targetAssetElement = hasClosestBlock(event.target);
|
|
|
|
|
|
if (targetAssetElement) {
|
|
|
|
|
|
targetAssetElement.classList.remove("dragover__top", "protyle-wysiwyg--select", "dragover__bottom", "dragover__left", "dragover__right");
|
|
|
|
|
|
targetAssetElement.removeAttribute("select-start");
|
|
|
|
|
|
targetAssetElement.removeAttribute("select-end");
|
2025-02-24 18:33:21 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
// https://github.com/siyuan-note/siyuan/issues/14177
|
|
|
|
|
|
editorElement.querySelectorAll(".dragover__top, .protyle-wysiwyg--select, .dragover__bottom, .dragover__left, .dragover__right").forEach((item: HTMLElement) => {
|
|
|
|
|
|
item.classList.remove("dragover__top", "protyle-wysiwyg--select", "dragover__bottom", "dragover__left", "dragover__right");
|
|
|
|
|
|
item.removeAttribute("select-start");
|
|
|
|
|
|
item.removeAttribute("select-end");
|
|
|
|
|
|
});
|
2022-09-01 20:24:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
// 编辑器内文字拖拽或资源文件拖拽或按住 alt/shift 拖拽反链图标进入编辑器时不能运行 event.preventDefault(), 否则无光标; 需放在 !window.siyuan.dragElement 之后
|
2022-05-26 15:18:53 +08:00
|
|
|
|
event.preventDefault();
|
2025-06-26 11:11:14 +08:00
|
|
|
|
targetElement = hasClosestByClassName(event.target, "av__gallery-item") || hasClosestByClassName(event.target, "av__gallery-add") ||
|
2025-06-18 11:50:33 +08:00
|
|
|
|
hasClosestByClassName(event.target, "av__row") || hasClosestByClassName(event.target, "av__row--util") ||
|
|
|
|
|
|
hasClosestBlock(event.target);
|
2025-06-26 11:11:14 +08:00
|
|
|
|
if (targetElement && targetElement.getAttribute("data-av-type") === "gallery" && event.target.classList.contains("av__gallery")) {
|
2025-06-18 11:50:33 +08:00
|
|
|
|
// 拖拽到属性视图 gallery 内,但没选中 item
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2023-10-26 23:17:27 +08:00
|
|
|
|
const point = {x: event.clientX, y: event.clientY, className: ""};
|
2024-09-21 00:36:19 +08:00
|
|
|
|
|
|
|
|
|
|
// 超级块中有a,b两个段落块,移动到 ab 之间的间隙 targetElement 会变为超级块,需修正为 a
|
|
|
|
|
|
if (targetElement && (targetElement.classList.contains("bq") || targetElement.classList.contains("sb") || targetElement.classList.contains("list") || targetElement.classList.contains("li"))) {
|
2024-09-24 09:02:25 +08:00
|
|
|
|
let prevElement = hasClosestBlock(document.elementFromPoint(point.x, point.y - 6));
|
2024-09-21 00:36:19 +08:00
|
|
|
|
while (prevElement && targetElement.contains(prevElement)) {
|
|
|
|
|
|
if (prevElement.nextElementSibling?.getAttribute("data-node-id")) {
|
|
|
|
|
|
targetElement = prevElement;
|
|
|
|
|
|
}
|
|
|
|
|
|
prevElement = prevElement.parentElement;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-10-26 23:17:27 +08:00
|
|
|
|
if (!targetElement) {
|
|
|
|
|
|
if (event.clientY > editorElement.lastElementChild.getBoundingClientRect().bottom) {
|
|
|
|
|
|
// 命中底部
|
|
|
|
|
|
targetElement = editorElement.lastElementChild as HTMLElement;
|
2023-10-27 00:04:23 +08:00
|
|
|
|
point.className = "dragover__bottom";
|
2023-10-26 23:17:27 +08:00
|
|
|
|
} else if (event.clientY < editorElement.firstElementChild.getBoundingClientRect().top) {
|
|
|
|
|
|
// 命中顶部
|
2023-10-27 00:04:23 +08:00
|
|
|
|
targetElement = editorElement.firstElementChild as HTMLElement;
|
|
|
|
|
|
point.className = "dragover__top";
|
2023-12-05 12:01:41 +08:00
|
|
|
|
} else if (contentRect) {
|
|
|
|
|
|
const editorPosition = {
|
|
|
|
|
|
left: contentRect.left + parseInt(editorElement.style.paddingLeft),
|
2023-12-16 23:12:10 +08:00
|
|
|
|
right: contentRect.left + protyle.contentElement.clientWidth - parseInt(editorElement.style.paddingRight)
|
2023-12-05 12:01:41 +08:00
|
|
|
|
};
|
2023-10-26 23:17:27 +08:00
|
|
|
|
if (event.clientX < editorPosition.left) {
|
|
|
|
|
|
// 左侧
|
|
|
|
|
|
point.x = editorPosition.left;
|
|
|
|
|
|
point.className = "dragover__left";
|
2023-10-27 11:34:53 +08:00
|
|
|
|
} else if (event.clientX >= editorPosition.right) {
|
2023-10-26 23:17:27 +08:00
|
|
|
|
// 右侧
|
|
|
|
|
|
point.x = editorPosition.right - 6;
|
|
|
|
|
|
point.className = "dragover__right";
|
|
|
|
|
|
}
|
|
|
|
|
|
targetElement = document.elementFromPoint(point.x, point.y) as HTMLElement;
|
|
|
|
|
|
if (targetElement.classList.contains("protyle-wysiwyg")) {
|
|
|
|
|
|
// 命中间隙
|
|
|
|
|
|
targetElement = document.elementFromPoint(point.x, point.y - 6) as HTMLElement;
|
|
|
|
|
|
}
|
|
|
|
|
|
targetElement = hasTopClosestByAttribute(targetElement, "data-node-id", null);
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if (targetElement && targetElement.classList.contains("list")) {
|
|
|
|
|
|
if (gutterType && gutterType.replace(Constants.SIYUAN_DROP_GUTTER, "").split(Constants.ZWSP)[0] !== "nodelistitem") {
|
|
|
|
|
|
targetElement = hasClosestBlock(document.elementFromPoint(event.clientX, event.clientY - 6));
|
|
|
|
|
|
} else {
|
|
|
|
|
|
targetElement = hasClosestByClassName(document.elementFromPoint(event.clientX, event.clientY - 6), "li");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-11-10 12:26:07 +08:00
|
|
|
|
if (gutterType && gutterType.startsWith(`${Constants.SIYUAN_DROP_GUTTER}NodeAttributeView${Constants.ZWSP}Col${Constants.ZWSP}`.toLowerCase())) {
|
|
|
|
|
|
// 表头只能拖拽到当前 av 的表头中
|
|
|
|
|
|
targetElement = hasClosestByClassName(event.target, "av__cell");
|
2023-11-14 12:58:45 +08:00
|
|
|
|
if (targetElement) {
|
2023-11-14 23:18:18 +08:00
|
|
|
|
const targetRowElement = hasClosestByClassName(targetElement, "av__row--header");
|
|
|
|
|
|
const dragRowElement = hasClosestByClassName(window.siyuan.dragElement, "av__row--header");
|
2025-07-23 13:08:38 +08:00
|
|
|
|
if (targetElement === window.siyuan.dragElement || !targetRowElement || !dragRowElement ||
|
|
|
|
|
|
(targetRowElement && dragRowElement && targetRowElement !== dragRowElement)
|
2023-11-14 12:58:45 +08:00
|
|
|
|
) {
|
|
|
|
|
|
targetElement = false;
|
|
|
|
|
|
}
|
2023-11-10 12:26:07 +08:00
|
|
|
|
}
|
2023-12-21 00:33:48 +08:00
|
|
|
|
} else if (targetElement && gutterType && gutterType.startsWith(`${Constants.SIYUAN_DROP_GUTTER}NodeAttributeViewRowMenu${Constants.ZWSP}`.toLowerCase())) {
|
2023-11-10 12:26:07 +08:00
|
|
|
|
// 行只能拖拽当前 av 中
|
2024-09-19 22:37:12 +08:00
|
|
|
|
if ((!targetElement.classList.contains("av__row") && !targetElement.classList.contains("av__row--util")) ||
|
2024-12-25 21:16:40 +08:00
|
|
|
|
(window.siyuan.dragElement && !window.siyuan.dragElement.contains(targetElement))) {
|
2023-11-10 12:26:07 +08:00
|
|
|
|
targetElement = false;
|
|
|
|
|
|
}
|
2025-06-18 11:50:33 +08:00
|
|
|
|
} else if (targetElement && gutterType && gutterType.startsWith(`${Constants.SIYUAN_DROP_GUTTER}NodeAttributeView${Constants.ZWSP}GalleryItem${Constants.ZWSP}`.toLowerCase())) {
|
|
|
|
|
|
// gallery item 只能拖拽当前 av 中
|
|
|
|
|
|
const galleryElement = hasClosestByClassName(event.target, "av__gallery");
|
2025-06-18 18:04:10 +08:00
|
|
|
|
if (targetElement.classList.contains("av") || !galleryElement ||
|
2025-07-23 13:08:38 +08:00
|
|
|
|
!galleryElement.contains(window.siyuan.dragElement) || targetElement === window.siyuan.dragElement) {
|
2025-06-18 11:50:33 +08:00
|
|
|
|
targetElement = false;
|
2025-06-24 19:52:55 +08:00
|
|
|
|
editorElement.querySelectorAll(".dragover__left, .dragover__right").forEach((item: HTMLElement) => {
|
|
|
|
|
|
item.classList.remove("dragover__left", "dragover__right");
|
|
|
|
|
|
});
|
2025-06-18 11:50:33 +08:00
|
|
|
|
}
|
2023-11-10 12:26:07 +08:00
|
|
|
|
}
|
2025-06-26 11:11:14 +08:00
|
|
|
|
|
2023-11-10 12:26:07 +08:00
|
|
|
|
if (!targetElement) {
|
2022-05-26 15:18:53 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-06-26 11:44:25 +08:00
|
|
|
|
const isNotAvItem = !targetElement.classList.contains("av__row") &&
|
|
|
|
|
|
!targetElement.classList.contains("av__row--util") &&
|
|
|
|
|
|
!targetElement.classList.contains("av__gallery-item") &&
|
|
|
|
|
|
!targetElement.classList.contains("av__gallery-add");
|
2025-07-23 13:08:38 +08:00
|
|
|
|
if (targetElement && dragoverElement && targetElement === dragoverElement) {
|
2022-05-26 15:18:53 +08:00
|
|
|
|
// 性能优化,目标为同一个元素不再进行校验
|
|
|
|
|
|
const nodeRect = targetElement.getBoundingClientRect();
|
2024-09-18 12:57:04 +08:00
|
|
|
|
editorElement.querySelectorAll(".dragover__left, .dragover__right, .dragover__bottom, .dragover__top, .dragover").forEach((item: HTMLElement) => {
|
|
|
|
|
|
item.classList.remove("dragover__top", "dragover__bottom", "dragover__left", "dragover__right", "dragover");
|
2023-10-26 23:17:27 +08:00
|
|
|
|
item.removeAttribute("select-start");
|
|
|
|
|
|
item.removeAttribute("select-end");
|
|
|
|
|
|
});
|
2024-11-29 09:11:13 +08:00
|
|
|
|
// 文档树拖拽限制
|
2025-06-26 11:44:25 +08:00
|
|
|
|
if (fileTreeIds.indexOf("-") > -1 && isNotAvItem) {
|
2024-11-29 09:11:13 +08:00
|
|
|
|
if (!event.altKey) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
} else if (fileTreeIds.split(",").includes(protyle.block.rootID) && event.altKey) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-03-02 18:33:03 +08:00
|
|
|
|
if (targetElement.getAttribute("data-type") === "NodeAttributeView" && hasClosestByTag(event.target, "TD")) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2023-10-26 23:17:27 +08:00
|
|
|
|
if (point.className) {
|
2024-09-21 00:36:19 +08:00
|
|
|
|
targetElement.classList.add(point.className);
|
|
|
|
|
|
addDragover(targetElement);
|
2023-10-26 23:17:27 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2024-11-27 23:03:50 +08:00
|
|
|
|
// 忘记为什么要限定文档树的拖拽了,先放开 https://github.com/siyuan-note/siyuan/pull/13284#issuecomment-2503853135
|
|
|
|
|
|
if (targetElement.getAttribute("data-type") === "NodeListItem") {
|
2022-05-26 15:18:53 +08:00
|
|
|
|
if (event.clientY > nodeRect.top + nodeRect.height / 2) {
|
2024-09-21 00:36:19 +08:00
|
|
|
|
targetElement.classList.add("dragover__bottom");
|
|
|
|
|
|
addDragover(targetElement);
|
2023-09-28 13:38:26 +08:00
|
|
|
|
} else if (!targetElement.classList.contains("av__row--header")) {
|
2024-09-21 00:36:19 +08:00
|
|
|
|
targetElement.classList.add("dragover__top");
|
|
|
|
|
|
addDragover(targetElement);
|
2022-05-26 15:18:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-07-01 23:15:21 +08:00
|
|
|
|
if (targetElement.classList.contains("av__cell")) {
|
|
|
|
|
|
if (event.clientX < nodeRect.left + nodeRect.width / 2 && event.clientX > nodeRect.left &&
|
2025-07-23 13:08:38 +08:00
|
|
|
|
!targetElement.classList.contains("av__row") && targetElement.previousElementSibling !== window.siyuan.dragElement) {
|
2023-10-26 10:12:58 +08:00
|
|
|
|
targetElement.classList.add("dragover__left");
|
2023-10-27 11:34:53 +08:00
|
|
|
|
} else if (event.clientX > nodeRect.right - nodeRect.width / 2 && event.clientX <= nodeRect.right + 1 &&
|
2025-07-23 13:08:38 +08:00
|
|
|
|
!targetElement.classList.contains("av__row") && targetElement !== window.siyuan.dragElement.previousElementSibling) {
|
|
|
|
|
|
if (window.siyuan.dragElement.previousElementSibling.classList.contains("av__colsticky") &&
|
|
|
|
|
|
targetElement === window.siyuan.dragElement.previousElementSibling.lastElementChild) {
|
2024-04-22 14:51:17 +08:00
|
|
|
|
// 拖拽到固定列的最后一个元素
|
|
|
|
|
|
} else {
|
|
|
|
|
|
targetElement.classList.add("dragover__right");
|
|
|
|
|
|
}
|
2023-07-01 23:15:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-06-26 11:11:14 +08:00
|
|
|
|
// gallery
|
2025-06-18 11:50:33 +08:00
|
|
|
|
if (targetElement.classList.contains("av__gallery-item")) {
|
|
|
|
|
|
const midLeft = nodeRect.left + nodeRect.width / 2;
|
|
|
|
|
|
if (event.clientX < midLeft && event.clientX > nodeRect.left - 13) {
|
|
|
|
|
|
targetElement.classList.add("dragover__left");
|
|
|
|
|
|
} else if (event.clientX > midLeft && event.clientX <= nodeRect.right + 13) {
|
|
|
|
|
|
targetElement.classList.add("dragover__right");
|
|
|
|
|
|
}
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-06-26 11:11:14 +08:00
|
|
|
|
if (targetElement.classList.contains("av__gallery-add")) {
|
|
|
|
|
|
targetElement.classList.add("dragover__left");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-10-27 11:34:53 +08:00
|
|
|
|
if (event.clientX < nodeRect.left + 32 && event.clientX >= nodeRect.left - 1 &&
|
2023-06-08 18:21:10 +08:00
|
|
|
|
!targetElement.classList.contains("av__row")) {
|
2024-09-21 00:36:19 +08:00
|
|
|
|
targetElement.classList.add("dragover__left");
|
|
|
|
|
|
addDragover(targetElement);
|
2023-06-08 18:21:10 +08:00
|
|
|
|
} else if (event.clientX > nodeRect.right - 32 && event.clientX < nodeRect.right &&
|
|
|
|
|
|
!targetElement.classList.contains("av__row")) {
|
2024-09-21 00:36:19 +08:00
|
|
|
|
targetElement.classList.add("dragover__right");
|
|
|
|
|
|
addDragover(targetElement);
|
2024-08-18 22:55:29 +08:00
|
|
|
|
} else if (targetElement.classList.contains("av__row--header")) {
|
2024-09-19 22:37:12 +08:00
|
|
|
|
targetElement.classList.add("dragover__bottom");
|
2024-08-18 22:55:29 +08:00
|
|
|
|
} else if (targetElement.classList.contains("av__row--util")) {
|
2024-09-19 22:37:12 +08:00
|
|
|
|
targetElement.previousElementSibling.classList.add("dragover__bottom");
|
2022-05-26 15:18:53 +08:00
|
|
|
|
} else {
|
2022-12-14 15:29:23 +08:00
|
|
|
|
if (event.clientY > nodeRect.top + nodeRect.height / 2 && disabledPosition !== "bottom") {
|
2024-09-19 22:37:12 +08:00
|
|
|
|
targetElement.classList.add("dragover__bottom");
|
2024-09-21 00:36:19 +08:00
|
|
|
|
addDragover(targetElement);
|
2022-12-14 15:29:23 +08:00
|
|
|
|
} else if (disabledPosition !== "top") {
|
2024-09-19 22:37:12 +08:00
|
|
|
|
targetElement.classList.add("dragover__top");
|
2024-09-21 00:36:19 +08:00
|
|
|
|
addDragover(targetElement);
|
2022-05-26 15:18:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2024-11-29 09:11:13 +08:00
|
|
|
|
|
2022-11-12 00:18:42 +08:00
|
|
|
|
if (fileTreeIds.indexOf("-") > -1) {
|
2025-06-26 11:44:25 +08:00
|
|
|
|
if (fileTreeIds.split(",").includes(protyle.block.rootID) && isNotAvItem && event.altKey) {
|
2022-11-12 00:18:42 +08:00
|
|
|
|
dragoverElement = undefined;
|
2024-11-29 09:11:13 +08:00
|
|
|
|
editorElement.querySelectorAll(".dragover__left, .dragover__right, .dragover__bottom, .dragover__top, .dragover").forEach((item: HTMLElement) => {
|
|
|
|
|
|
item.classList.remove("dragover__top", "dragover__bottom", "dragover__left", "dragover__right", "dragover");
|
|
|
|
|
|
item.removeAttribute("select-start");
|
|
|
|
|
|
item.removeAttribute("select-end");
|
|
|
|
|
|
});
|
2022-11-12 00:18:42 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
dragoverElement = targetElement;
|
|
|
|
|
|
}
|
2022-05-26 15:18:53 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-06-18 18:04:10 +08:00
|
|
|
|
|
2023-02-17 15:34:38 +08:00
|
|
|
|
if (gutterType) {
|
2022-12-15 10:41:43 +08:00
|
|
|
|
disabledPosition = "";
|
2022-05-26 15:18:53 +08:00
|
|
|
|
// gutter 文档内拖拽限制
|
|
|
|
|
|
// 排除自己及子孙
|
2023-02-17 15:46:46 +08:00
|
|
|
|
const gutterTypes = gutterType.replace(Constants.SIYUAN_DROP_GUTTER, "").split(Constants.ZWSP);
|
2023-07-01 23:15:21 +08:00
|
|
|
|
if (gutterTypes[0] === "nodeattributeview" && gutterTypes[1] === "col" && targetElement.getAttribute("data-id") === gutterTypes[2]) {
|
|
|
|
|
|
// 表头不能拖到自己上
|
2025-06-18 18:04:10 +08:00
|
|
|
|
clearDragoverElement(dragoverElement);
|
2023-07-01 23:15:21 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2024-04-22 14:51:17 +08:00
|
|
|
|
if (gutterTypes[0] === "nodeattributeviewrowmenu" && gutterTypes[2] === targetElement.getAttribute("data-id")) {
|
|
|
|
|
|
// 行不能拖到自己上
|
2025-06-18 18:04:10 +08:00
|
|
|
|
clearDragoverElement(dragoverElement);
|
2024-04-22 14:51:17 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2023-02-17 15:34:38 +08:00
|
|
|
|
const isSelf = gutterTypes[2].split(",").find((item: string) => {
|
2023-07-01 23:15:21 +08:00
|
|
|
|
if (item && hasClosestByAttribute(targetElement as HTMLElement, "data-node-id", item)) {
|
2022-05-26 15:18:53 +08:00
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
2025-01-30 15:02:48 +08:00
|
|
|
|
if (isSelf && "nodeattributeviewrowmenu" !== gutterTypes[0]) {
|
2025-06-18 18:04:10 +08:00
|
|
|
|
clearDragoverElement(dragoverElement);
|
2022-05-26 15:18:53 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2024-07-25 17:55:25 +08:00
|
|
|
|
if (isInEmbedBlock(targetElement)) {
|
2022-05-26 15:18:53 +08:00
|
|
|
|
// 不允许托入嵌入块
|
2025-06-18 18:04:10 +08:00
|
|
|
|
clearDragoverElement(dragoverElement);
|
2022-05-26 15:18:53 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2023-02-17 15:34:38 +08:00
|
|
|
|
if (gutterTypes[0] === "nodelistitem" &&
|
|
|
|
|
|
gutterTypes[1] !== targetElement.getAttribute("data-subtype") &&
|
|
|
|
|
|
"NodeListItem" === targetElement.getAttribute("data-type")) {
|
2022-05-26 15:18:53 +08:00
|
|
|
|
// 排除类型不同的列表项
|
2025-06-18 18:04:10 +08:00
|
|
|
|
clearDragoverElement(dragoverElement);
|
2022-05-26 15:18:53 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2023-02-17 15:34:38 +08:00
|
|
|
|
if (gutterTypes[0] !== "nodelistitem" && targetElement.getAttribute("data-type") === "NodeListItem") {
|
2022-05-26 15:18:53 +08:00
|
|
|
|
// 非列表项不能拖入列表项周围
|
2025-06-18 18:04:10 +08:00
|
|
|
|
clearDragoverElement(dragoverElement);
|
2022-05-26 15:18:53 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2023-02-17 15:34:38 +08:00
|
|
|
|
if (gutterTypes[0] === "nodelistitem" && targetElement.parentElement.classList.contains("li") &&
|
|
|
|
|
|
targetElement.previousElementSibling?.classList.contains("protyle-action")) {
|
2022-12-14 15:29:23 +08:00
|
|
|
|
// 列表项不能拖入列表项中第一个元素之上
|
2022-12-15 10:41:43 +08:00
|
|
|
|
disabledPosition = "top";
|
2022-12-14 15:29:23 +08:00
|
|
|
|
}
|
2023-02-17 15:34:38 +08:00
|
|
|
|
if (gutterTypes[0] === "nodelistitem" && targetElement.nextElementSibling?.classList.contains("list")) {
|
2022-12-14 15:29:23 +08:00
|
|
|
|
// 列表项不能拖入列表上方块的下面
|
2022-12-15 10:41:43 +08:00
|
|
|
|
disabledPosition = "bottom";
|
2022-12-14 15:29:23 +08:00
|
|
|
|
}
|
2023-07-02 22:47:25 +08:00
|
|
|
|
if (targetElement && targetElement.classList.contains("av__row--header")) {
|
|
|
|
|
|
// 块不能拖在表头上
|
|
|
|
|
|
disabledPosition = "top";
|
|
|
|
|
|
}
|
2023-07-01 20:41:35 +08:00
|
|
|
|
dragoverElement = targetElement;
|
2022-05-26 15:18:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
});
|
2024-09-24 09:02:25 +08:00
|
|
|
|
let counter = 0;
|
2024-09-22 19:43:10 +08:00
|
|
|
|
editorElement.addEventListener("dragleave", (event: DragEvent & { target: HTMLElement }) => {
|
2023-12-07 22:09:51 +08:00
|
|
|
|
if (protyle.disabled) {
|
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
|
event.stopPropagation();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2024-09-22 19:43:10 +08:00
|
|
|
|
counter--;
|
|
|
|
|
|
if (counter === 0) {
|
|
|
|
|
|
editorElement.querySelectorAll(".dragover__left, .dragover__right, .dragover__bottom, .dragover__top, .dragover").forEach((item: HTMLElement) => {
|
|
|
|
|
|
item.classList.remove("dragover__top", "dragover__bottom", "dragover__left", "dragover__right", "dragover");
|
|
|
|
|
|
});
|
2024-10-11 14:55:29 +08:00
|
|
|
|
dragoverElement = undefined;
|
2024-09-22 19:43:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
editorElement.addEventListener("dragenter", (event) => {
|
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
|
counter++;
|
2022-05-26 15:18:53 +08:00
|
|
|
|
});
|
2025-07-08 23:29:36 +08:00
|
|
|
|
editorElement.addEventListener("dragend", () => {
|
|
|
|
|
|
if (window.siyuan.dragElement) {
|
|
|
|
|
|
window.siyuan.dragElement.style.opacity = "";
|
|
|
|
|
|
window.siyuan.dragElement = undefined;
|
2025-07-09 16:27:23 +08:00
|
|
|
|
document.onmousemove = null;
|
2025-07-08 23:29:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
});
|
2022-05-26 15:18:53 +08:00
|
|
|
|
};
|
2024-09-21 00:36:19 +08:00
|
|
|
|
|
|
|
|
|
|
const addDragover = (element: HTMLElement) => {
|
|
|
|
|
|
if (element.classList.contains("sb") ||
|
|
|
|
|
|
element.classList.contains("li") ||
|
|
|
|
|
|
element.classList.contains("list") ||
|
|
|
|
|
|
element.classList.contains("bq")) {
|
2024-09-24 09:02:25 +08:00
|
|
|
|
element.classList.add("dragover");
|
2024-09-21 00:36:19 +08:00
|
|
|
|
}
|
2024-09-24 09:02:25 +08:00
|
|
|
|
};
|
2025-06-18 18:04:10 +08:00
|
|
|
|
|
|
|
|
|
|
// https://github.com/siyuan-note/siyuan/issues/12651
|
|
|
|
|
|
const clearDragoverElement = (element: Element) => {
|
|
|
|
|
|
if (element) {
|
|
|
|
|
|
element.classList.remove("dragover__top", "dragover__bottom", "dragover__left", "dragover__right", "dragover");
|
|
|
|
|
|
element = undefined;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|