Vanessa 2023-07-31 21:39:38 +08:00
parent 4478829b33
commit e694d2e8bb

View file

@ -1,10 +1,9 @@
/// #if !BROWSER /// #if !BROWSER
import {shell} from "electron"; import {shell} from "electron";
/// #endif /// #endif
import {getDockByType} from "../layout/util";
import {confirmDialog} from "../dialog/confirmDialog"; import {confirmDialog} from "../dialog/confirmDialog";
import {getSearch, isMobile, isValidAttrName} from "../util/functions"; import {getSearch, isMobile, isValidAttrName} from "../util/functions";
import {isLocalPath, movePathTo, moveToPath, pathPosix} from "../util/pathName"; import {isLocalPath, movePathTo, moveToPath, pathPosix, setNotebookName} from "../util/pathName";
import {MenuItem} from "./Menu"; import {MenuItem} from "./Menu";
import {saveExport} from "../protyle/export"; import {saveExport} from "../protyle/export";
import {openByMobile, writeText} from "../protyle/util/compatibility"; import {openByMobile, writeText} from "../protyle/util/compatibility";
@ -12,30 +11,22 @@ import {fetchPost, fetchSyncPost} from "../util/fetch";
import {hideMessage, showMessage} from "../dialog/message"; import {hideMessage, showMessage} from "../dialog/message";
import {Dialog} from "../dialog"; import {Dialog} from "../dialog";
import {focusBlock, focusByRange, getEditorRange} from "../protyle/util/selection"; import {focusBlock, focusByRange, getEditorRange} from "../protyle/util/selection";
import {updateTransaction} from "../protyle/wysiwyg/transaction";
/// #if !MOBILE /// #if !MOBILE
import {getAllModels} from "../layout/getAll";
import {Bookmark} from "../layout/dock/Bookmark";
import {openAsset, openBy} from "../editor/util"; import {openAsset, openBy} from "../editor/util";
/// #endif /// #endif
import {rename, replaceFileName} from "../editor/rename"; import {rename, replaceFileName} from "../editor/rename";
import {matchHotKey} from "../protyle/util/hotKey";
import * as dayjs from "dayjs"; import * as dayjs from "dayjs";
import {Constants} from "../constants"; import {Constants} from "../constants";
import {exportImage} from "../protyle/export/util"; import {exportImage} from "../protyle/export/util";
import {App} from "../index"; import {App} from "../index";
import {renderAVAttribute} from "../protyle/render/av/render"; import {renderAVAttribute} from "../protyle/render/av/render";
const bindAttrInput = (inputElement: HTMLInputElement, confirmElement: Element) => { const bindAttrInput = (inputElement: HTMLInputElement, id: string) => {
inputElement.addEventListener("keydown", (event) => { inputElement.addEventListener("change", () => {
if (event.isComposing) { fetchPost("/api/attr/setBlockAttrs", {
return; id,
} attrs: {[inputElement.dataset.name]: inputElement.value}
if (matchHotKey("⌘↩", event)) { });
confirmElement.dispatchEvent(new CustomEvent("click", {detail: "confirm"}));
event.stopPropagation();
event.preventDefault();
}
}); });
}; };
@ -158,7 +149,7 @@ export const openFileWechatNotify = (protyle: IProtyle) => {
}); });
}; };
const genAttr = (attrs: IObject, focusName = "bookmark", cb: (dialog: Dialog, rms: string[]) => void) => { const genAttr = (attrs: IObject, focusName = "bookmark") => {
let customHTML = ""; let customHTML = "";
let notifyHTML = ""; let notifyHTML = "";
let hasAV = false; let hasAV = false;
@ -175,14 +166,6 @@ const genAttr = (attrs: IObject, focusName = "bookmark", cb: (dialog: Dialog, rm
</label>`; </label>`;
} else if (item.indexOf("custom-av") > -1) { } else if (item.indexOf("custom-av") > -1) {
hasAV = true; hasAV = true;
// avHTML += `<label class="b3-label b3-label--noborder">
// <div class="fn__flex">
// <span class="fn__flex-1">${item.replace("custom-", "")}</span>
// <span data-action="remove" class="block__icon block__icon--show"><svg><use xlink:href="#iconMin"></use></svg></span>
// </div>
// <div class="fn__hr"></div>
// <textarea class="b3-text-field fn__block" rows="1" data-name="${item}">${attrs[item]}</textarea>
// </label>`;
} else if (item.indexOf("custom") > -1) { } else if (item.indexOf("custom") > -1) {
customHTML += `<label class="b3-label b3-label--noborder"> customHTML += `<label class="b3-label b3-label--noborder">
<div class="fn__flex"> <div class="fn__flex">
@ -252,10 +235,6 @@ const genAttr = (attrs: IObject, focusName = "bookmark", cb: (dialog: Dialog, rm
</div> </div>
</div> </div>
</div> </div>
<div class="b3-dialog__action">
<button data-action="closeDialog" class="b3-button b3-button--cancel">${window.siyuan.languages.cancel}</button><div class="fn__space"></div>
<button data-action="confirm" class="b3-button b3-button--text">${window.siyuan.languages.confirm}</button>
</div>
</div>`, </div>`,
destroyCallback() { destroyCallback() {
focusByRange(range); focusByRange(range);
@ -264,13 +243,8 @@ const genAttr = (attrs: IObject, focusName = "bookmark", cb: (dialog: Dialog, rm
(dialog.element.querySelector('.b3-text-field[data-name="bookmark"]') as HTMLInputElement).value = attrs.bookmark || ""; (dialog.element.querySelector('.b3-text-field[data-name="bookmark"]') as HTMLInputElement).value = attrs.bookmark || "";
(dialog.element.querySelector('.b3-text-field[data-name="name"]') as HTMLInputElement).value = attrs.name || ""; (dialog.element.querySelector('.b3-text-field[data-name="name"]') as HTMLInputElement).value = attrs.name || "";
(dialog.element.querySelector('.b3-text-field[data-name="alias"]') as HTMLInputElement).value = attrs.alias || ""; (dialog.element.querySelector('.b3-text-field[data-name="alias"]') as HTMLInputElement).value = attrs.alias || "";
const removeAttrs: string[] = [];
dialog.element.addEventListener("click", (event) => { dialog.element.addEventListener("click", (event) => {
let target = event.target as HTMLElement; let target = event.target as HTMLElement;
if (typeof event.detail === "string" && event.detail === "confirm") {
cb(dialog, removeAttrs);
return;
}
while (!target.isSameNode(dialog.element)) { while (!target.isSameNode(dialog.element)) {
const type = target.dataset.action; const type = target.dataset.action;
if (target.classList.contains("item--full")) { if (target.classList.contains("item--full")) {
@ -287,9 +261,10 @@ const genAttr = (attrs: IObject, focusName = "bookmark", cb: (dialog: Dialog, rm
} }
}); });
} else if (type === "remove") { } else if (type === "remove") {
if (target.previousElementSibling.tagName === "SPAN") { fetchPost("/api/attr/setBlockAttrs", {
removeAttrs.push(target.parentElement.parentElement.querySelector("textarea").getAttribute("data-name")); id: attrs.id,
} attrs: {[target.previousElementSibling.textContent]: ""}
});
target.parentElement.parentElement.remove(); target.parentElement.parentElement.remove();
event.stopPropagation(); event.stopPropagation();
event.preventDefault(); event.preventDefault();
@ -321,26 +296,46 @@ const genAttr = (attrs: IObject, focusName = "bookmark", cb: (dialog: Dialog, rm
event.preventDefault(); event.preventDefault();
break; break;
} else if (type === "addCustom") { } else if (type === "addCustom") {
target.parentElement.insertAdjacentHTML("beforebegin", `<div class="b3-label b3-label--noborder"> const addDialog = new Dialog({
title: window.siyuan.languages.attrName,
content: `<div class="b3-dialog__content"><input class="b3-text-field fn__block" value=""></div>
<div class="b3-dialog__action">
<button class="b3-button b3-button--cancel">${window.siyuan.languages.cancel}</button><div class="fn__space"></div>
<button class="b3-button b3-button--text">${window.siyuan.languages.confirm}</button>
</div>`,
width: isMobile() ? "92vw" : "520px",
});
const inputElement = addDialog.element.querySelector("input") as HTMLInputElement;
const btnsElement = addDialog.element.querySelectorAll(".b3-button");
dialog.bindInput(inputElement, () => {
(btnsElement[1] as HTMLButtonElement).click();
});
inputElement.focus();
inputElement.select();
btnsElement[0].addEventListener("click", () => {
addDialog.destroy();
});
btnsElement[1].addEventListener("click", () => {
if (!isValidAttrName(inputElement.value)) {
showMessage(window.siyuan.languages.attrName + " <b>" + inputElement.value + "</b> " + window.siyuan.languages.invalid)
return false;
}
target.parentElement.insertAdjacentHTML("beforebegin", `<div class="b3-label b3-label--noborder">
<div class="fn__flex"> <div class="fn__flex">
<input placeholder="${window.siyuan.languages.attrName}" class="b3-text-field"> <span class="fn__flex-1">${inputElement.value}</span>
<span class="fn__flex-1"></span>
<span data-action="remove" class="block__icon block__icon--show"><svg><use xlink:href="#iconMin"></use></svg></span> <span data-action="remove" class="block__icon block__icon--show"><svg><use xlink:href="#iconMin"></use></svg></span>
</div> </div>
<div class="fn__hr"></div> <div class="fn__hr"></div>
<textarea class="b3-text-field fn__block" rows="1" placeholder="${window.siyuan.languages.attrValue1}"></textarea> <textarea data-name="${inputElement.value}" class="b3-text-field fn__block" rows="1" placeholder="${window.siyuan.languages.attrValue1}"></textarea>
</div>`); </div>`);
const inputElements = dialog.element.querySelectorAll(".b3-text-field") as NodeListOf<HTMLInputElement>; const valueElement = target.parentElement.previousElementSibling.querySelector(".b3-text-field") as HTMLInputElement;
inputElements[inputElements.length - 2].focus(); valueElement.focus();
bindAttrInput(inputElements[inputElements.length - 1], dialog.element); bindAttrInput(valueElement, attrs.id);
bindAttrInput(inputElements[inputElements.length - 2], dialog.element); addDialog.destroy();
});
event.stopPropagation(); event.stopPropagation();
event.preventDefault(); event.preventDefault();
break; break;
} else if (type === "closeDialog") {
dialog.destroy();
} else if (type === "confirm") {
cb(dialog, removeAttrs);
} }
target = target.parentElement; target = target.parentElement;
} }
@ -349,74 +344,76 @@ const genAttr = (attrs: IObject, focusName = "bookmark", cb: (dialog: Dialog, rm
if (focusName === item.getAttribute("data-name")) { if (focusName === item.getAttribute("data-name")) {
item.focus(); item.focus();
} }
bindAttrInput(item, dialog.element); bindAttrInput(item, attrs.id);
}); });
}; };
export const openFileAttr = (attrs: IObject, id: string, focusName = "bookmark") => { export const openFileAttr = (attrs: IObject, id: string, focusName = "bookmark") => {
genAttr(attrs, focusName, (dialog) => { genAttr(attrs, focusName,
let nodeAttrHTML = ""; // (dialog) => {
let errorTip = ""; // let nodeAttrHTML = "";
const attrsResult: IObject = {}; // let errorTip = "";
dialog.element.querySelectorAll(".b3-text-field").forEach((item: HTMLInputElement) => { // const attrsResult: IObject = {};
let name = item.getAttribute("data-name"); // dialog.element.querySelectorAll(".b3-text-field").forEach((item: HTMLInputElement) => {
if (!name) { // let name = item.getAttribute("data-name");
if (item.tagName === "INPUT") { // if (!name) {
return; // if (item.tagName === "INPUT") {
} // return;
name = "custom-" + (item.parentElement.querySelector(".b3-text-field") as HTMLInputElement).value; // }
} // name = "custom-" + (item.parentElement.querySelector(".b3-text-field") as HTMLInputElement).value;
if (item.value.trim()) { // }
if (!isValidAttrName(name)) { // if (item.value.trim()) {
errorTip += name.replace(/^custom-/, "") + ", "; // if (!isValidAttrName(name)) {
return; // errorTip += name.replace(/^custom-/, "") + ", ";
} // return;
attrsResult[name] = item.value; // }
const escapeHTML = Lute.EscapeHTMLStr(item.value); // attrsResult[name] = item.value;
if (name === "bookmark") { // const escapeHTML = Lute.EscapeHTMLStr(item.value);
nodeAttrHTML += `<div class="protyle-attr--bookmark">${escapeHTML}</div>`; // if (name === "bookmark") {
} else if (name === "name") { // nodeAttrHTML += `<div class="protyle-attr--bookmark">${escapeHTML}</div>`;
nodeAttrHTML += `<div class="protyle-attr--name"><svg><use xlink:href="#iconN"></use></svg>${escapeHTML}</div>`; // } else if (name === "name") {
} else if (name === "alias") { // nodeAttrHTML += `<div class="protyle-attr--name"><svg><use xlink:href="#iconN"></use></svg>${escapeHTML}</div>`;
nodeAttrHTML += `<div class="protyle-attr--alias"><svg><use xlink:href="#iconA"></use></svg>${escapeHTML}</div>`; // } else if (name === "alias") {
} else if (name === "memo") { // nodeAttrHTML += `<div class="protyle-attr--alias"><svg><use xlink:href="#iconA"></use></svg>${escapeHTML}</div>`;
nodeAttrHTML += `<div class="protyle-attr--memo b3-tooltips b3-tooltips__sw" aria-label="${escapeHTML}"><svg><use xlink:href="#iconM"></use></svg></div>`; // } else if (name === "memo") {
} // nodeAttrHTML += `<div class="protyle-attr--memo b3-tooltips b3-tooltips__sw" aria-label="${escapeHTML}"><svg><use xlink:href="#iconM"></use></svg></div>`;
} // }
}); // }
if (errorTip) { // });
showMessage(errorTip.substr(0, errorTip.length - 2) + " " + window.siyuan.languages.invalid); // if (errorTip) {
} // showMessage(errorTip.substr(0, errorTip.length - 2) + " " + window.siyuan.languages.invalid);
/// #if !MOBILE // }
getAllModels().editor.forEach(item => { // /// #if !MOBILE
if (item.editor.protyle.block.rootID === id) { // getAllModels().editor.forEach(item => {
const refElement = item.editor.protyle.title.element.querySelector(".protyle-attr--refcount"); // if (item.editor.protyle.block.rootID === id) {
if (refElement) { // const refElement = item.editor.protyle.title.element.querySelector(".protyle-attr--refcount");
nodeAttrHTML += refElement.outerHTML; // if (refElement) {
} // nodeAttrHTML += refElement.outerHTML;
item.editor.protyle.title.element.querySelector(".protyle-attr").innerHTML = nodeAttrHTML; // }
item.editor.protyle.wysiwyg.renderCustom(attrsResult); // item.editor.protyle.title.element.querySelector(".protyle-attr").innerHTML = nodeAttrHTML;
} // item.editor.protyle.wysiwyg.renderCustom(attrsResult);
// https://github.com/siyuan-note/siyuan/issues/6398 // }
item.editor.protyle.wysiwyg.element.querySelectorAll(`[data-type~="block-ref"][data-id="${id}"][data-subtype="d"]`).forEach(item => { // // https://github.com/siyuan-note/siyuan/issues/6398
fetchPost("/api/block/getRefText", {id: id}, (response) => { // item.editor.protyle.wysiwyg.element.querySelectorAll(`[data-type~="block-ref"][data-id="${id}"][data-subtype="d"]`).forEach(item => {
item.innerHTML = response.data; // fetchPost("/api/block/getRefText", {id: id}, (response) => {
}); // item.innerHTML = response.data;
}); // });
}); // });
/// #endif // });
fetchPost("/api/attr/resetBlockAttrs", {id, attrs: attrsResult}, () => { // /// #endif
/// #if !MOBILE // fetchPost("/api/attr/resetBlockAttrs", {id, attrs: attrsResult}, () => {
if (attrsResult.bookmark !== attrs.bookmark) { // /// #if !MOBILE
const bookmark = getDockByType("bookmark").data.bookmark; // if (attrsResult.bookmark !== attrs.bookmark) {
if (bookmark instanceof Bookmark) { // const bookmark = getDockByType("bookmark").data.bookmark;
bookmark.update(); // if (bookmark instanceof Bookmark) {
} // bookmark.update();
} // }
/// #endif // }
}); // /// #endif
dialog.destroy(); // });
}); // dialog.destroy();
// }
);
}; };
export const openAttr = (nodeElement: Element, protyle: IProtyle, focusName = "bookmark") => { export const openAttr = (nodeElement: Element, protyle: IProtyle, focusName = "bookmark") => {
@ -425,71 +422,73 @@ export const openAttr = (nodeElement: Element, protyle: IProtyle, focusName = "b
} }
const id = nodeElement.getAttribute("data-node-id"); const id = nodeElement.getAttribute("data-node-id");
fetchPost("/api/attr/getBlockAttrs", {id}, (response) => { fetchPost("/api/attr/getBlockAttrs", {id}, (response) => {
genAttr(response.data, focusName, (dialog, removeAttrs) => { genAttr(response.data, focusName,
let nodeAttrHTML = ""; // (dialog, removeAttrs) => {
const oldHTML = nodeElement.outerHTML; // let nodeAttrHTML = "";
let errorTip = ""; // const oldHTML = nodeElement.outerHTML;
dialog.element.querySelectorAll(".b3-text-field").forEach((item: HTMLInputElement) => { // let errorTip = "";
let name = item.getAttribute("data-name"); // dialog.element.querySelectorAll(".b3-text-field").forEach((item: HTMLInputElement) => {
if (!name) { // let name = item.getAttribute("data-name");
if (item.tagName === "INPUT") { // if (!name) {
return; // if (item.tagName === "INPUT") {
} // return;
name = "custom-" + (item.parentElement.querySelector(".b3-text-field") as HTMLInputElement).value; // }
} // name = "custom-" + (item.parentElement.querySelector(".b3-text-field") as HTMLInputElement).value;
if (item.value.trim()) { // }
if (!isValidAttrName(name)) { // if (item.value.trim()) {
errorTip += name.replace(/^custom-/, "") + ", "; // if (!isValidAttrName(name)) {
return; // errorTip += name.replace(/^custom-/, "") + ", ";
} // return;
if (removeAttrs.includes(name)) { // }
removeAttrs.find((rmAttr, index) => { // if (removeAttrs.includes(name)) {
if (rmAttr === name) { // removeAttrs.find((rmAttr, index) => {
removeAttrs.splice(index, 1); // if (rmAttr === name) {
return true; // removeAttrs.splice(index, 1);
} // return true;
}); // }
} // });
const escapeHTML = Lute.EscapeHTMLStr(item.value); // }
nodeElement.setAttribute(name, escapeHTML); // const escapeHTML = Lute.EscapeHTMLStr(item.value);
if (name === "bookmark") { // nodeElement.setAttribute(name, escapeHTML);
/// #if !MOBILE // if (name === "bookmark") {
if (escapeHTML !== response.data.bookmark) { // /// #if !MOBILE
const bookmark = getDockByType("bookmark").data.bookmark; // if (escapeHTML !== response.data.bookmark) {
if (bookmark instanceof Bookmark) { // const bookmark = getDockByType("bookmark").data.bookmark;
setTimeout(() => { // if (bookmark instanceof Bookmark) {
bookmark.update(); // setTimeout(() => {
}, 219); // bookmark.update();
} // }, 219);
} // }
/// #endif // }
nodeAttrHTML += `<div class="protyle-attr--bookmark">${escapeHTML}</div>`; // /// #endif
} else if (name === "name") { // nodeAttrHTML += `<div class="protyle-attr--bookmark">${escapeHTML}</div>`;
nodeAttrHTML += `<div class="protyle-attr--name"><svg><use xlink:href="#iconN"></use></svg>${escapeHTML}</div>`; // } else if (name === "name") {
} else if (name === "alias") { // nodeAttrHTML += `<div class="protyle-attr--name"><svg><use xlink:href="#iconN"></use></svg>${escapeHTML}</div>`;
nodeAttrHTML += `<div class="protyle-attr--alias"><svg><use xlink:href="#iconA"></use></svg>${escapeHTML}</div>`; // } else if (name === "alias") {
} else if (name === "memo") { // nodeAttrHTML += `<div class="protyle-attr--alias"><svg><use xlink:href="#iconA"></use></svg>${escapeHTML}</div>`;
nodeAttrHTML += `<div class="protyle-attr--memo b3-tooltips b3-tooltips__sw" aria-label="${escapeHTML}"><svg><use xlink:href="#iconM"></use></svg></div>`; // } else if (name === "memo") {
} // nodeAttrHTML += `<div class="protyle-attr--memo b3-tooltips b3-tooltips__sw" aria-label="${escapeHTML}"><svg><use xlink:href="#iconM"></use></svg></div>`;
} else { // }
nodeElement.removeAttribute(name); // } else {
} // nodeElement.removeAttribute(name);
}); // }
removeAttrs.forEach(item => { // });
nodeElement.removeAttribute(item); // removeAttrs.forEach(item => {
}); // nodeElement.removeAttribute(item);
if (errorTip) { // });
showMessage(errorTip.substr(0, errorTip.length - 2) + " " + window.siyuan.languages.invalid); // if (errorTip) {
} // showMessage(errorTip.substr(0, errorTip.length - 2) + " " + window.siyuan.languages.invalid);
const refElement = nodeElement.lastElementChild.querySelector(".protyle-attr--refcount"); // }
if (refElement) { // const refElement = nodeElement.lastElementChild.querySelector(".protyle-attr--refcount");
nodeAttrHTML += refElement.outerHTML; // if (refElement) {
} // nodeAttrHTML += refElement.outerHTML;
nodeElement.lastElementChild.innerHTML = nodeAttrHTML + Constants.ZWSP; // }
nodeElement.setAttribute("updated", dayjs().format("YYYYMMDDHHmmss")); // nodeElement.lastElementChild.innerHTML = nodeAttrHTML + Constants.ZWSP;
updateTransaction(protyle, id, nodeElement.outerHTML, oldHTML); // nodeElement.setAttribute("updated", dayjs().format("YYYYMMDDHHmmss"));
dialog.destroy(); // updateTransaction(protyle, id, nodeElement.outerHTML, oldHTML);
}); // dialog.destroy();
// }
);
}); });
}; };