diff --git a/app/src/protyle/render/av/action.ts b/app/src/protyle/render/av/action.ts index 57d90458a..58c79b4c0 100644 --- a/app/src/protyle/render/av/action.ts +++ b/app/src/protyle/render/av/action.ts @@ -230,3 +230,25 @@ export const avContextmenu = (protyle: IProtyle, event: MouseEvent & { detail: a }); return true; }; + +export const updateAVName = (protyle: IProtyle, blockElement: Element) => { + const avId = blockElement.getAttribute("data-av-id"); + const nameElement = blockElement.querySelector(".av__title") as HTMLElement; + if (nameElement.textContent.trim() === nameElement.dataset.title.trim()) { + return; + } + transaction(protyle, [{ + action: "setAttrView", + id: avId, + data: { + name: nameElement.textContent.trim(), + } + }], [{ + action: "setAttrView", + id: avId, + data: { + name: nameElement.dataset.title, + } + }]) + nameElement.dataset.title = nameElement.textContent.trim(); +} diff --git a/app/src/protyle/render/av/render.ts b/app/src/protyle/render/av/render.ts index 7868bf213..89c56f243 100644 --- a/app/src/protyle/render/av/render.ts +++ b/app/src/protyle/render/av/render.ts @@ -105,7 +105,7 @@ ${cell.color ? `color:${cell.color};` : ""}">${text}<
-
${data.name || ""}
+
${data.name || ""}
@@ -137,7 +137,7 @@ export const refreshAV = (protyle: IProtyle, operation: IOperation) => { } lastElement = protyle.contentElement; lastParentID = operation.parentID; - const avId = operation.action === "setAttrView"?operation.id: operation.parentID + const avId = operation.action === "setAttrView" ? operation.id : operation.parentID if (operation.action === "addAttrViewCol") { Array.from(protyle.wysiwyg.element.querySelectorAll(`[data-av-id="${avId}"]`)).forEach((item: HTMLElement) => { item.removeAttribute("data-render"); @@ -156,6 +156,15 @@ export const refreshAV = (protyle: IProtyle, operation: IOperation) => { (rowItem.querySelector(`[data-index="${index}"]`) as HTMLElement).style.width = operation.data; }); }); + } else if (operation.action === "setAttrView" && typeof operation.data.name === "string") { + Array.from(protyle.wysiwyg.element.querySelectorAll(`[data-av-id="${avId}"]`)).forEach((item: HTMLElement) => { + const titleElement = item.querySelector(".av__title") as HTMLElement; + if (!titleElement || titleElement.textContent.trim() === operation.data.name) { + return; + } + titleElement.textContent = operation.data.name; + titleElement.dataset.title = operation.data.name; + }); } else { Array.from(protyle.wysiwyg.element.querySelectorAll(`[data-av-id="${avId}"]`)).forEach((item: HTMLElement) => { item.removeAttribute("data-render"); diff --git a/app/src/protyle/toolbar/index.ts b/app/src/protyle/toolbar/index.ts index 1af5949f3..d31c63179 100644 --- a/app/src/protyle/toolbar/index.ts +++ b/app/src/protyle/toolbar/index.ts @@ -75,7 +75,7 @@ export class Toolbar { public render(protyle: IProtyle, range: Range, event?: KeyboardEvent) { this.range = range; let nodeElement = hasClosestBlock(range.startContainer); - if (isMobile() || !nodeElement || protyle.disabled) { + if (isMobile() || !nodeElement || protyle.disabled || nodeElement.classList.contains("av")) { this.element.classList.add("fn__none"); return; } diff --git a/app/src/protyle/util/insertHTML.ts b/app/src/protyle/util/insertHTML.ts index bee1251b3..da32330f9 100644 --- a/app/src/protyle/util/insertHTML.ts +++ b/app/src/protyle/util/insertHTML.ts @@ -7,6 +7,8 @@ import {mathRender} from "../render/mathRender"; import {Constants} from "../../constants"; import {highlightRender} from "../render/highlightRender"; import {scrollCenter} from "../../util/highlightById"; +import {updateAVName} from "../render/av/action"; +import {readText} from "./compatibility"; export const insertHTML = (html: string, protyle: IProtyle, isBlock = false, // 移动端插入嵌入块时,获取到的 range 为旧值 @@ -31,6 +33,22 @@ export const insertHTML = (html: string, protyle: IProtyle, isBlock = false, if (!blockElement) { return; } + if (blockElement.classList.contains("av")) { + range.deleteContents(); + const text = readText(); + if (typeof text === "string") { + range.insertNode(document.createTextNode(text)); + range.collapse(false); + updateAVName(protyle, blockElement); + } else { + text.then((t) => { + range.insertNode(document.createTextNode(t)); + range.collapse(false); + updateAVName(protyle, blockElement); + }); + } + return; + } let id = blockElement.getAttribute("data-node-id"); range.insertNode(document.createElement("wbr")); let oldHTML = blockElement.outerHTML; diff --git a/app/src/protyle/wysiwyg/index.ts b/app/src/protyle/wysiwyg/index.ts index 3e8c13190..fb1b20fe0 100644 --- a/app/src/protyle/wysiwyg/index.ts +++ b/app/src/protyle/wysiwyg/index.ts @@ -75,7 +75,7 @@ import {getBacklinkHeadingMore, loadBreadcrumb} from "./renderBacklink"; import {removeSearchMark} from "../toolbar/util"; import {activeBlur, hideKeyboardToolbar} from "../../mobile/util/keyboardToolbar"; import {commonClick} from "./commonClick"; -import {avClick, avContextmenu} from "../render/av/action"; +import {avClick, avContextmenu, updateAVName} from "../render/av/action"; export class WYSIWYG { public lastHTMLs: { [key: string]: string } = {}; @@ -1037,8 +1037,6 @@ export class WYSIWYG { event.stopPropagation(); return; } - event.stopPropagation(); - event.preventDefault(); if (protyle.options.render.breadcrumb) { protyle.breadcrumb.hide(); @@ -1046,8 +1044,18 @@ export class WYSIWYG { const range = getEditorRange(protyle.wysiwyg.element); let nodeElement = hasClosestBlock(range.startContainer); if (!nodeElement) { + event.stopPropagation(); + event.preventDefault(); return; } + if (nodeElement.classList.contains("av")) { + updateAVName(protyle, nodeElement); + event.stopPropagation(); + return; + } + + event.stopPropagation(); + event.preventDefault(); const selectImgElement = nodeElement.querySelector(".img--select"); let selectElements = Array.from(protyle.wysiwyg.element.querySelectorAll(".protyle-wysiwyg--select")); if (selectElements.length === 0 && range.toString() === "" && !range.cloneContents().querySelector("img") && @@ -1309,7 +1317,7 @@ export class WYSIWYG { if (!isNotEditBlock(nodeElement) && !nodeElement.classList.contains("protyle-wysiwyg--select") && (isMobile() || event.detail.target || (beforeContextmenuRange && nodeElement.contains(beforeContextmenuRange.startContainer))) ) { - if (!isMobile() || protyle.toolbar?.element.classList.contains("fn__none")) { + if ((!isMobile() || protyle.toolbar?.element.classList.contains("fn__none")) && !nodeElement.classList.contains("av")) { contentMenu(protyle, nodeElement); window.siyuan.menus.menu.popup({x, y: y + 13, h: 26}); protyle.toolbar?.element.classList.add("fn__none"); @@ -1438,9 +1446,6 @@ export class WYSIWYG { }); this.element.addEventListener("compositionend", (event: InputEvent) => { - if ((event.target as HTMLElement).classList.contains("av__title")) { - return; - } event.stopPropagation(); isComposition = false; const range = getEditorRange(this.element); @@ -1467,8 +1472,7 @@ export class WYSIWYG { this.element.addEventListener("input", (event: InputEvent) => { const target = event.target as HTMLElement; - if (target.tagName === "VIDEO" || target.tagName === "AUDIO" || event.inputType === "historyRedo" || - target.classList.contains("av__title")) { + if (target.tagName === "VIDEO" || target.tagName === "AUDIO" || event.inputType === "historyRedo") { return; } if (event.inputType === "historyUndo") { diff --git a/app/src/protyle/wysiwyg/input.ts b/app/src/protyle/wysiwyg/input.ts index f5bc46b9d..533805ea2 100644 --- a/app/src/protyle/wysiwyg/input.ts +++ b/app/src/protyle/wysiwyg/input.ts @@ -12,12 +12,17 @@ import {hideElements} from "../ui/hideElements"; import {hasClosestByAttribute} from "../util/hasClosest"; import {fetchPost, fetchSyncPost} from "../../util/fetch"; import {headingTurnIntoList, turnIntoTaskList} from "./turnIntoList"; +import {updateAVName} from "../render/av/action"; export const input = async (protyle: IProtyle, blockElement: HTMLElement, range: Range, needRender = true) => { if (!blockElement.parentElement) { // 不同 windows 版本下输入法会多次触发 input,导致 outerhtml 赋值的块丢失 return; } + if (blockElement.classList.contains("av")) { + updateAVName(protyle, blockElement); + return; + } const editElement = getContenteditableElement(blockElement) as HTMLElement; const type = blockElement.getAttribute("data-type"); if (!editElement) { diff --git a/app/src/protyle/wysiwyg/keydown.ts b/app/src/protyle/wysiwyg/keydown.ts index bbe198b34..3ca8295dd 100644 --- a/app/src/protyle/wysiwyg/keydown.ts +++ b/app/src/protyle/wysiwyg/keydown.ts @@ -97,6 +97,12 @@ export const keydown = (protyle: IProtyle, editorElement: HTMLElement) => { if (!nodeElement) { return; } + if (nodeElement.classList.contains("av")) { + if (matchHotKey("⌘B", event) || matchHotKey("⌘I", event) || matchHotKey("⌘U", event)) { + event.preventDefault(); + } + return; + } if (nodeElement.classList.contains("protyle-wysiwyg--select") && !isCtrl(event) && !event.shiftKey && !event.altKey) { if (event.key.toLowerCase() === "a") { event.stopPropagation();