From 7938755578a73b021f57f66d9b848cafe5eea55e Mon Sep 17 00:00:00 2001 From: Vanessa Date: Tue, 8 Jul 2025 23:29:36 +0800 Subject: [PATCH] :art: https://github.com/siyuan-note/siyuan/issues/11102 --- app/src/protyle/render/av/gallery/render.ts | 2 +- app/src/protyle/render/av/render.ts | 2 +- app/src/protyle/render/av/view.ts | 24 +++++++++ app/src/protyle/util/editorCommonEvent.ts | 57 ++++++++++++++++++--- 4 files changed, 76 insertions(+), 9 deletions(-) diff --git a/app/src/protyle/render/av/gallery/render.ts b/app/src/protyle/render/av/gallery/render.ts index feb519c64..403b13d4e 100644 --- a/app/src/protyle/render/av/gallery/render.ts +++ b/app/src/protyle/render/av/gallery/render.ts @@ -119,7 +119,7 @@ ${cell.color ? `color:${cell.color};` : ""}">${renderCell(cell.value, rowIndex, let tabHTML = ""; let viewData: IAVView; response.data.views.forEach((item: IAVView) => { - tabHTML += `
+ tabHTML += `
${item.icon ? unicode2Emoji(item.icon, "item__graphic", true) : ``} ${escapeHtml(item.name)}
`; diff --git a/app/src/protyle/render/av/render.ts b/app/src/protyle/render/av/render.ts index c0a41c0f4..b924cd049 100644 --- a/app/src/protyle/render/av/render.ts +++ b/app/src/protyle/render/av/render.ts @@ -213,7 +213,7 @@ ${cell.color ? `color:${cell.color};` : ""}">${renderCell(cell.value, rowIndex, let tabHTML = ""; let viewData: IAVView; response.data.views.forEach((item: IAVView) => { - tabHTML += `
+ tabHTML += `
${item.icon ? unicode2Emoji(item.icon, "item__graphic", true) : ``} ${escapeHtml(item.name)}
`; diff --git a/app/src/protyle/render/av/view.ts b/app/src/protyle/render/av/view.ts index cd5a4ef4f..c4b05ae95 100644 --- a/app/src/protyle/render/av/view.ts +++ b/app/src/protyle/render/av/view.ts @@ -5,6 +5,7 @@ import {openMenuPanel} from "./openMenuPanel"; import {focusBlock} from "../../util/selection"; import {upDownHint} from "../../../util/upDownHint"; import {escapeAriaLabel, escapeAttr, escapeHtml} from "../../../util/escape"; +import {hasClosestByClassName} from "../../util/hasClosest"; export const openViewMenu = (options: { protyle: IProtyle, blockElement: HTMLElement, element: HTMLElement }) => { if (options.protyle.disabled) { @@ -385,3 +386,26 @@ export const getViewName = (type: string) => { export const getFieldsByData = (data: IAV) => { return data.viewType === "table" ? (data.view as IAVTable).columns : (data.view as IAVGallery).fields; }; + +export const dragoverTab = (event: DragEvent) => { + const target = hasClosestByClassName(document.elementFromPoint(event.clientX, window.siyuan.dragElement.getBoundingClientRect().top + 10), "item"); + if (!target) { + return; + } + if (!target.parentElement.isSameNode(window.siyuan.dragElement.parentElement) || target.isSameNode(window.siyuan.dragElement)) { + return; + } + + const targetRect = target.getBoundingClientRect(); + if (targetRect.left + targetRect.width / 2 < event.clientX) { + if (target.nextElementSibling?.isSameNode(window.siyuan.dragElement)) { + return; + } + target.after(window.siyuan.dragElement); + } else { + if (target.previousElementSibling?.isSameNode(window.siyuan.dragElement)) { + return; + } + target.before(window.siyuan.dragElement); + } +}; diff --git a/app/src/protyle/util/editorCommonEvent.ts b/app/src/protyle/util/editorCommonEvent.ts index 36a32a5ec..6b574500a 100644 --- a/app/src/protyle/util/editorCommonEvent.ts +++ b/app/src/protyle/util/editorCommonEvent.ts @@ -35,6 +35,7 @@ import {addDragFill, getTypeByCellElement} from "../render/av/cell"; import {processClonePHElement} from "../render/util"; import {insertGalleryItemAnimation} from "../render/av/gallery/item"; import {clearSelect} from "./clearSelect"; +import {dragoverTab} from "../render/av/view"; const moveToNew = (protyle: IProtyle, sourceElements: Element[], targetElement: Element, newSourceElement: Element, isSameDoc: boolean, isBottom: boolean, isCopy: boolean) => { @@ -831,6 +832,13 @@ export const dropEvent = (protyle: IProtyle, editorElement: HTMLElement) => { if (hasClosestByClassName(target, "protyle-wysiwyg__embed")) { window.siyuan.dragElement = undefined; event.preventDefault(); + } 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; } else if (target.classList.contains("protyle-action")) { target.parentElement.classList.add("protyle-wysiwyg--select"); const ghostElement = document.createElement("div"); @@ -909,6 +917,28 @@ export const dropEvent = (protyle: IProtyle, editorElement: HTMLElement) => { gutterType = item.type; } } + 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, + previousID: window.siyuan.dragElement.previousElementSibling?.getAttribute("data-id") + }], [{ + action: "sortAttrViewView", + avID, + blockID, + id, + previousID: gutterType.split(Constants.ZWSP).pop() + }]); + } + return; + } const targetElement = editorElement.querySelector(".dragover__left, .dragover__right, .dragover__bottom, .dragover__top"); if (targetElement) { targetElement.classList.remove("dragover"); @@ -1366,8 +1396,20 @@ export const dropEvent = (protyle: IProtyle, editorElement: HTMLElement) => { event.dataTransfer.dropEffect = "none"; return; } + 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; + } const contentRect = protyle.contentElement.getBoundingClientRect(); - if (!hasClosestByClassName(event.target, "av__cell") && (event.clientY < contentRect.top + Constants.SIZE_SCROLL_TB || event.clientY > contentRect.bottom - Constants.SIZE_SCROLL_TB)) { + if (!hasClosestByClassName(event.target, "av__cell") && + (event.clientY < contentRect.top + Constants.SIZE_SCROLL_TB || event.clientY > contentRect.bottom - Constants.SIZE_SCROLL_TB)) { 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" @@ -1396,12 +1438,7 @@ export const dropEvent = (protyle: IProtyle, editorElement: HTMLElement) => { // 使用 event.preventDefault(); 会导致无光标 https://github.com/siyuan-note/siyuan/issues/12857 return; } - let gutterType = ""; - for (const item of event.dataTransfer.items) { - if (item.type.startsWith(Constants.SIYUAN_DROP_GUTTER)) { - gutterType = item.type; - } - } + if (!gutterType && !window.siyuan.dragElement) { // https://github.com/siyuan-note/siyuan/issues/6436 event.preventDefault(); @@ -1700,6 +1737,12 @@ export const dropEvent = (protyle: IProtyle, editorElement: HTMLElement) => { event.preventDefault(); counter++; }); + editorElement.addEventListener("dragend", () => { + if (window.siyuan.dragElement) { + window.siyuan.dragElement.style.opacity = ""; + window.siyuan.dragElement = undefined; + } + }); }; const addDragover = (element: HTMLElement) => {