diff --git a/app/appearance/langs/zh_CN.json b/app/appearance/langs/zh_CN.json index 2775bb8a6..41c82d39b 100644 --- a/app/appearance/langs/zh_CN.json +++ b/app/appearance/langs/zh_CN.json @@ -730,7 +730,7 @@ "insertImgURL": "插入图片链接", "insertIframeURL": "插入 IFrame 链接", "context": "上下文", - "dockTip": "\n单击 展开/最小化\n右键 调整位置", + "dockTip": "\n单击 展开/最小化\n右键/拖拽 调整位置", "shadow": "投影", "hollow": "镂空", "attrValue1": "属性值留空则会自动删除该属性", diff --git a/app/src/boot/globalEvent/click.ts b/app/src/boot/globalEvent/click.ts index 46d2cd455..2c7cf0e3f 100644 --- a/app/src/boot/globalEvent/click.ts +++ b/app/src/boot/globalEvent/click.ts @@ -15,7 +15,6 @@ export const globalClick = (event: MouseEvent & { target: HTMLElement }) => { if (ghostElement.dataset.ghostType === "dock") { ghostElement.parentElement.querySelectorAll(".dock__item").forEach((item: HTMLElement) => { item.style.opacity = ""; - item.classList.add("b3-tooltips"); }); document.querySelector("#dockMoveItem")?.remove(); } else { diff --git a/app/src/layout/dock/index.ts b/app/src/layout/dock/index.ts index 43a4db214..174f04e2f 100644 --- a/app/src/layout/dock/index.ts +++ b/app/src/layout/dock/index.ts @@ -87,7 +87,7 @@ export class Dock { } } if (!showDock) { - this.element.firstElementChild.innerHTML = ` + this.element.firstElementChild.innerHTML = ` `; this.element.classList.add("fn__none"); @@ -157,7 +157,6 @@ export class Dock { moveEvent.stopPropagation(); if (!ghostElement) { item.style.opacity = "0.38"; - item.classList.remove("b3-tooltips"); ghostElement = item.cloneNode(true) as HTMLElement; ghostElement.setAttribute("data-ghost-type", "dock"); this.element.append(ghostElement); @@ -281,11 +280,10 @@ export class Dock { documentSelf.onselectstart = null; documentSelf.onselect = null; ghostElement?.remove(); - if (item.classList.contains("b3-tooltips")) { + if (item.style.opacity !== "0.38") { return; } item.style.opacity = ""; - item.classList.add("b3-tooltips"); if (!moveItem.classList.contains("fn__none")) { let dock; if (moveItem.parentElement.parentElement.id === "dockBottom") { @@ -773,8 +771,6 @@ export class Dock { delete sourceDock.data[type]; // 目标处理 - sourceElement.classList.remove("b3-tooltips__n", "b3-tooltips__ne", "b3-tooltips__nw", "b3-tooltips__s", "b3-tooltips__se", "b3-tooltips__sw", "b3-tooltips__e", "b3-tooltips__w"); - sourceElement.classList.add(`b3-tooltips__${this.getClassDirect(index)}`); sourceElement.setAttribute("data-index", index.toString()); if (previousType) { this.element.querySelector(`[data-type="${previousType}"]`).after(sourceElement); @@ -804,23 +800,6 @@ export class Dock { delete this.data[key]; } - private getClassDirect(index: number) { - let direct = "e"; - switch (this.position) { - case "Right": - direct = "w"; - break; - case "Bottom": - if (index === 0) { - direct = "ne"; - } else { - direct = "nw"; - } - break; - } - return direct; - } - public setSize() { const activesElement = this.element.querySelectorAll(".dock__item--active"); activesElement.forEach((item) => { @@ -860,7 +839,7 @@ export class Dock { if (typeof tabIndex === "undefined" && !TYPES.includes(item.type)) { return; } - html += ` + html += `"> `; this.data[item.type] = true; @@ -873,7 +852,7 @@ export class Dock { this.element.firstElementChild.lastElementChild.insertAdjacentHTML("beforebegin", html); } } else { - this.element.firstElementChild.innerHTML = `${html} + this.element.firstElementChild.innerHTML = `${html} `; } diff --git a/app/src/protyle/gutter/index.ts b/app/src/protyle/gutter/index.ts index 7f96d17c6..cbcecda2a 100644 --- a/app/src/protyle/gutter/index.ts +++ b/app/src/protyle/gutter/index.ts @@ -14,20 +14,19 @@ import {copyPlainText, isMac, isOnlyMeta, openByMobile, updateHotkeyTip, writeTe import { transaction, turnsIntoOneTransaction, - turnsIntoTransaction, + turnsIntoTransaction, turnsOneInto, updateBatchTransaction, updateTransaction } from "../wysiwyg/transaction"; import {removeBlock} from "../wysiwyg/remove"; -import {focusBlock, focusByRange, focusByWbr, getEditorRange} from "../util/selection"; +import {focusBlock, focusByRange, getEditorRange} from "../util/selection"; import {hideElements} from "../ui/hideElements"; -import {processRender} from "../util/processCode"; import {highlightRender} from "../render/highlightRender"; import {blockRender} from "../render/blockRender"; import {removeEmbed} from "../wysiwyg/removeEmbed"; import {getContenteditableElement, getTopAloneElement, isNotEditBlock} from "../wysiwyg/getBlock"; import * as dayjs from "dayjs"; -import {fetchPost, fetchSyncPost} from "../../util/fetch"; +import {fetchPost} from "../../util/fetch"; import { cancelSB, genEmptyElement, @@ -449,91 +448,8 @@ export class Gutter { icon: options.icon, label: options.label, accelerator: options.accelerator, - async click() { - if (!options.nodeElement.querySelector("wbr")) { - getContenteditableElement(options.nodeElement)?.insertAdjacentHTML("afterbegin", ""); - } - if (options.type === "CancelList" || options.type === "CancelBlockquote") { - for await(const item of options.nodeElement.querySelectorAll('[data-type="NodeHeading"][fold="1"]')) { - const itemId = item.getAttribute("data-node-id"); - item.removeAttribute("fold"); - const response = await fetchSyncPost("/api/transactions", { - session: options.protyle.id, - app: Constants.SIYUAN_APPID, - transactions: [{ - doOperations: [{ - action: "unfoldHeading", - id: itemId, - }], - undoOperations: [{ - action: "foldHeading", - id: itemId - }], - }] - }); - options.protyle.undo.add([{ - action: "unfoldHeading", - id: itemId, - }], [{ - action: "foldHeading", - id: itemId - }], options.protyle); - item.insertAdjacentHTML("afterend", response.data[0].doOperations[0].retData); - } - } - const oldHTML = options.nodeElement.outerHTML; - const previousId = options.nodeElement.previousElementSibling?.getAttribute("data-node-id"); - const parentId = options.nodeElement.parentElement.getAttribute("data-node-id") || options.protyle.block.parentID; - // @ts-ignore - const newHTML = options.protyle.lute[options.type](options.nodeElement.outerHTML, options.level); - options.nodeElement.outerHTML = newHTML; - if (options.type === "CancelList" || options.type === "CancelBlockquote") { - const tempElement = document.createElement("template"); - tempElement.innerHTML = newHTML; - const doOperations: IOperation[] = [{ - action: "delete", - id: options.id - }]; - const undoOperations: IOperation[] = []; - let tempPreviousId = previousId; - Array.from(tempElement.content.children).forEach((item) => { - const tempId = item.getAttribute("data-node-id"); - doOperations.push({ - action: "insert", - data: item.outerHTML, - id: tempId, - previousID: tempPreviousId, - parentID: parentId - }); - undoOperations.push({ - action: "delete", - id: tempId - }); - tempPreviousId = tempId; - }); - undoOperations.push({ - action: "insert", - data: oldHTML, - id: options.id, - previousID: previousId, - parentID: parentId - }); - transaction(options.protyle, doOperations, undoOperations); - } else { - updateTransaction(options.protyle, options.id, newHTML, oldHTML); - } - focusByWbr(options.protyle.wysiwyg.element, getEditorRange(options.protyle.wysiwyg.element)); - options.protyle.wysiwyg.element.querySelectorAll('[data-type~="block-ref"]').forEach(item => { - if (item.textContent === "") { - fetchPost("/api/block/getRefText", {id: item.getAttribute("data-id")}, (response) => { - item.innerHTML = response.data; - }); - } - }); - blockRender(options.protyle, options.protyle.wysiwyg.element); - processRender(options.protyle.wysiwyg.element); - highlightRender(options.protyle.wysiwyg.element); - avRender(options.protyle.wysiwyg.element, options.protyle); + click() { + turnsOneInto(options); } }; } diff --git a/app/src/protyle/wysiwyg/keydown.ts b/app/src/protyle/wysiwyg/keydown.ts index 33ac3fc9e..f200ff3ed 100644 --- a/app/src/protyle/wysiwyg/keydown.ts +++ b/app/src/protyle/wysiwyg/keydown.ts @@ -31,7 +31,13 @@ import { import {matchHotKey} from "../util/hotKey"; import {enter, softEnter} from "./enter"; import {fixTable} from "../util/table"; -import {turnsIntoOneTransaction, turnsIntoTransaction, updateBatchTransaction, updateTransaction} from "./transaction"; +import { + turnsIntoOneTransaction, + turnsIntoTransaction, + turnsOneInto, + updateBatchTransaction, + updateTransaction +} from "./transaction"; import {fontEvent} from "../toolbar/Font"; import {addSubList, listIndent, listOutdent} from "./list"; import {newFileContentBySelect, rename, replaceFileName} from "../../editor/rename"; @@ -1330,10 +1336,73 @@ export const keydown = (protyle: IProtyle, editorElement: HTMLElement) => { return true; } } - if (matchHotKey(window.siyuan.config.keymap.editor.insert.check.custom, event)) { - protyle.hint.splitChar = "/"; - protyle.hint.lastIndex = -1; - protyle.hint.fill("* [ ] " + Lute.Caret, protyle); + const isMatchList = matchHotKey(window.siyuan.config.keymap.editor.insert.list.custom, event) + const isMatchCheck = matchHotKey(window.siyuan.config.keymap.editor.insert.check.custom, event) + const isMatchOList = matchHotKey(window.siyuan.config.keymap.editor.insert["ordered-list"].custom, event) + if (isMatchList || isMatchOList || isMatchCheck) { + const selectsElement: HTMLElement[] = Array.from(protyle.wysiwyg.element.querySelectorAll(".protyle-wysiwyg--select")); + if (selectsElement.length === 0) { + protyle.hint.splitChar = "/"; + protyle.hint.lastIndex = -1; + protyle.hint.fill((isMatchCheck ? "* [ ] " : (isMatchList ? "* " : "1. ")) + Lute.Caret, protyle); + } else if (selectsElement.length === 1) { + const subType = selectsElement[0].dataset.subtype + const type = selectsElement[0].dataset.type + if (type === "NodeParagraph") { + turnsIntoOneTransaction({ + protyle, + selectsElement, + type: isMatchCheck ? "Blocks2TLs" : (isMatchList ? "Blocks2ULs" : "Blocks2OLs") + }); + } else if (type === "NodeList") { + const id = selectsElement[0].dataset.nodeId + if (subType === "o" && (isMatchList || isMatchCheck)) { + turnsOneInto({ + protyle, + nodeElement: selectsElement[0], + id, + type: isMatchCheck ? "UL2TL" : "OL2UL", + }); + } else if (subType === "t" && (isMatchList || isMatchOList)) { + turnsOneInto({ + protyle, + nodeElement: selectsElement[0], + id, + type: isMatchList ? "TL2UL" : "TL2OL", + }); + } else if (isMatchCheck || isMatchOList) { + turnsOneInto({ + protyle, + nodeElement: selectsElement[0], + id, + type: isMatchCheck ? "OL2TL" : "UL2OL", + }); + } + } + } else { + let isList = false; + let isContinue = false; + selectsElement.find((item, index) => { + if (item.classList.contains("li")) { + isList = true; + return true; + } + if (item.nextElementSibling && selectsElement[index + 1] && + item.nextElementSibling.isSameNode(selectsElement[index + 1])) { + isContinue = true; + } else if (index !== selectsElement.length - 1) { + isContinue = false; + return true; + } + }); + if (!isList && isContinue) { + turnsIntoOneTransaction({ + protyle, + selectsElement, + type: isMatchCheck ? "Blocks2TLs" : (isMatchList ? "Blocks2ULs" : "Blocks2OLs") + }); + } + } event.preventDefault(); event.stopPropagation(); return; diff --git a/app/src/protyle/wysiwyg/transaction.ts b/app/src/protyle/wysiwyg/transaction.ts index e7012be5c..e42cff9fa 100644 --- a/app/src/protyle/wysiwyg/transaction.ts +++ b/app/src/protyle/wysiwyg/transaction.ts @@ -1,6 +1,6 @@ -import {fetchPost} from "../../util/fetch"; +import {fetchPost, fetchSyncPost} from "../../util/fetch"; import {focusBlock, focusByWbr, focusSideBlock, getEditorRange} from "../util/selection"; -import {getTopAloneElement} from "./getBlock"; +import {getContenteditableElement, getTopAloneElement} from "./getBlock"; import {Constants} from "../../constants"; import {blockRender} from "../render/blockRender"; import {processRender} from "../util/processCode"; @@ -1025,6 +1025,99 @@ export const turnsIntoTransaction = (options: { hideElements(["gutter"], options.protyle); }; +export const turnsOneInto = async (options: { + protyle: IProtyle, + nodeElement: Element, + id: string, + type: string, + level?: number +}) => { + if (!options.nodeElement.querySelector("wbr")) { + getContenteditableElement(options.nodeElement)?.insertAdjacentHTML("afterbegin", ""); + } + if (options.type === "CancelList" || options.type === "CancelBlockquote") { + for await(const item of options.nodeElement.querySelectorAll('[data-type="NodeHeading"][fold="1"]')) { + const itemId = item.getAttribute("data-node-id"); + item.removeAttribute("fold"); + const response = await fetchSyncPost("/api/transactions", { + session: options.protyle.id, + app: Constants.SIYUAN_APPID, + transactions: [{ + doOperations: [{ + action: "unfoldHeading", + id: itemId, + }], + undoOperations: [{ + action: "foldHeading", + id: itemId + }], + }] + }); + options.protyle.undo.add([{ + action: "unfoldHeading", + id: itemId, + }], [{ + action: "foldHeading", + id: itemId + }], options.protyle); + item.insertAdjacentHTML("afterend", response.data[0].doOperations[0].retData); + } + } + const oldHTML = options.nodeElement.outerHTML; + const previousId = options.nodeElement.previousElementSibling?.getAttribute("data-node-id"); + const parentId = options.nodeElement.parentElement.getAttribute("data-node-id") || options.protyle.block.parentID; + // @ts-ignore + const newHTML = options.protyle.lute[options.type](options.nodeElement.outerHTML, options.level); + options.nodeElement.outerHTML = newHTML; + if (options.type === "CancelList" || options.type === "CancelBlockquote") { + const tempElement = document.createElement("template"); + tempElement.innerHTML = newHTML; + const doOperations: IOperation[] = [{ + action: "delete", + id: options.id + }]; + const undoOperations: IOperation[] = []; + let tempPreviousId = previousId; + Array.from(tempElement.content.children).forEach((item) => { + const tempId = item.getAttribute("data-node-id"); + doOperations.push({ + action: "insert", + data: item.outerHTML, + id: tempId, + previousID: tempPreviousId, + parentID: parentId + }); + undoOperations.push({ + action: "delete", + id: tempId + }); + tempPreviousId = tempId; + }); + undoOperations.push({ + action: "insert", + data: oldHTML, + id: options.id, + previousID: previousId, + parentID: parentId + }); + transaction(options.protyle, doOperations, undoOperations); + } else { + updateTransaction(options.protyle, options.id, newHTML, oldHTML); + } + focusByWbr(options.protyle.wysiwyg.element, getEditorRange(options.protyle.wysiwyg.element)); + options.protyle.wysiwyg.element.querySelectorAll('[data-type~="block-ref"]').forEach(item => { + if (item.textContent === "") { + fetchPost("/api/block/getRefText", {id: item.getAttribute("data-id")}, (response) => { + item.innerHTML = response.data; + }); + } + }); + blockRender(options.protyle, options.protyle.wysiwyg.element); + processRender(options.protyle.wysiwyg.element); + highlightRender(options.protyle.wysiwyg.element); + avRender(options.protyle.wysiwyg.element, options.protyle); +} + const updateRef = (protyle: IProtyle, id: string, index = 0) => { if (index > 6) { return;