Vanessa 2024-06-05 22:50:53 +08:00
parent bb1314c66f
commit bd264d7104
6 changed files with 179 additions and 123 deletions

View file

@ -730,7 +730,7 @@
"insertImgURL": "插入图片链接",
"insertIframeURL": "插入 IFrame 链接",
"context": "上下文",
"dockTip": "\n单击 展开/最小化\n右键 调整位置",
"dockTip": "\n单击 <span class='ft__on-surface ft__nowrap'>展开/最小化</span>\n右键/拖拽 <span class='ft__on-surface ft__nowrap'>调整位置</span>",
"shadow": "投影",
"hollow": "镂空",
"attrValue1": "属性值留空则会自动删除该属性",

View file

@ -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 {

View file

@ -87,7 +87,7 @@ export class Dock {
}
}
if (!showDock) {
this.element.firstElementChild.innerHTML = `<span class="dock__item dock__item--pin b3-tooltips b3-tooltips__${this.getClassDirect(0)}" aria-label="${this.pin ? window.siyuan.languages.unpin : window.siyuan.languages.pin}">
this.element.firstElementChild.innerHTML = `<span class="dock__item dock__item--pin ariaLabel" aria-label="${this.pin ? window.siyuan.languages.unpin : window.siyuan.languages.pin}">
<svg><use xlink:href="#icon${this.pin ? "Unpin" : "Pin"}"></use></svg>
</span>`;
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 += `<span data-height="${item.size.height}" data-width="${item.size.width}" data-type="${item.type}" data-index="${index}" data-hotkey="${item.hotkey || ""}" data-hotkeyLangId="${item.hotkeyLangId || ""}" data-title="${item.title}" class="dock__item${item.show ? " dock__item--active" : ""} b3-tooltips b3-tooltips__${this.getClassDirect(index)}" aria-label="${item.title} ${item.hotkey ? updateHotkeyTip(item.hotkey) : ""}${window.siyuan.languages.dockTip}">
html += `<span data-height="${item.size.height}" data-width="${item.size.width}" data-type="${item.type}" data-index="${index}" data-hotkey="${item.hotkey || ""}" data-hotkeyLangId="${item.hotkeyLangId || ""}" data-title="${item.title}" class="dock__item${item.show ? " dock__item--active" : ""} ariaLabel" aria-label="<span style='white-space:pre'>${item.title} ${item.hotkey ? updateHotkeyTip(item.hotkey) : ""}${window.siyuan.languages.dockTip}</span>">
<svg><use xlink:href="#${item.icon}"></use></svg>
</span>`;
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}<span class="dock__item dock__item--pin b3-tooltips b3-tooltips__${this.getClassDirect(index)}" aria-label="${this.pin ? window.siyuan.languages.unpin : window.siyuan.languages.pin}">
this.element.firstElementChild.innerHTML = `${html}<span class="dock__item dock__item--pin ariaLabel" aria-label="${this.pin ? window.siyuan.languages.unpin : window.siyuan.languages.pin}">
<svg><use xlink:href="#icon${this.pin ? "Unpin" : "Pin"}"></use></svg>
</span>`;
}

View file

@ -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", "<wbr>");
}
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);
}
};
}

View file

@ -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;

View file

@ -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", "<wbr>");
}
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;