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

View file

@ -1,10 +1,9 @@
/// #if !BROWSER
import {shell} from "electron";
/// #endif
import {getDockByType} from "../layout/util";
import {confirmDialog} from "../dialog/confirmDialog";
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 {saveExport} from "../protyle/export";
import {openByMobile, writeText} from "../protyle/util/compatibility";
@ -12,30 +11,22 @@ import {fetchPost, fetchSyncPost} from "../util/fetch";
import {hideMessage, showMessage} from "../dialog/message";
import {Dialog} from "../dialog";
import {focusBlock, focusByRange, getEditorRange} from "../protyle/util/selection";
import {updateTransaction} from "../protyle/wysiwyg/transaction";
/// #if !MOBILE
import {getAllModels} from "../layout/getAll";
import {Bookmark} from "../layout/dock/Bookmark";
import {openAsset, openBy} from "../editor/util";
/// #endif
import {rename, replaceFileName} from "../editor/rename";
import {matchHotKey} from "../protyle/util/hotKey";
import * as dayjs from "dayjs";
import {Constants} from "../constants";
import {exportImage} from "../protyle/export/util";
import {App} from "../index";
import {renderAVAttribute} from "../protyle/render/av/render";
const bindAttrInput = (inputElement: HTMLInputElement, confirmElement: Element) => {
inputElement.addEventListener("keydown", (event) => {
if (event.isComposing) {
return;
}
if (matchHotKey("⌘↩", event)) {
confirmElement.dispatchEvent(new CustomEvent("click", {detail: "confirm"}));
event.stopPropagation();
event.preventDefault();
}
const bindAttrInput = (inputElement: HTMLInputElement, id: string) => {
inputElement.addEventListener("change", () => {
fetchPost("/api/attr/setBlockAttrs", {
id,
attrs: {[inputElement.dataset.name]: inputElement.value}
});
});
};
@ -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 notifyHTML = "";
let hasAV = false;
@ -175,14 +166,6 @@ const genAttr = (attrs: IObject, focusName = "bookmark", cb: (dialog: Dialog, rm
</label>`;
} else if (item.indexOf("custom-av") > -1) {
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) {
customHTML += `<label class="b3-label b3-label--noborder">
<div class="fn__flex">
@ -252,10 +235,6 @@ const genAttr = (attrs: IObject, focusName = "bookmark", cb: (dialog: Dialog, rm
</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>`,
destroyCallback() {
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="name"]') as HTMLInputElement).value = attrs.name || "";
(dialog.element.querySelector('.b3-text-field[data-name="alias"]') as HTMLInputElement).value = attrs.alias || "";
const removeAttrs: string[] = [];
dialog.element.addEventListener("click", (event) => {
let target = event.target as HTMLElement;
if (typeof event.detail === "string" && event.detail === "confirm") {
cb(dialog, removeAttrs);
return;
}
while (!target.isSameNode(dialog.element)) {
const type = target.dataset.action;
if (target.classList.contains("item--full")) {
@ -287,9 +261,10 @@ const genAttr = (attrs: IObject, focusName = "bookmark", cb: (dialog: Dialog, rm
}
});
} else if (type === "remove") {
if (target.previousElementSibling.tagName === "SPAN") {
removeAttrs.push(target.parentElement.parentElement.querySelector("textarea").getAttribute("data-name"));
}
fetchPost("/api/attr/setBlockAttrs", {
id: attrs.id,
attrs: {[target.previousElementSibling.textContent]: ""}
});
target.parentElement.parentElement.remove();
event.stopPropagation();
event.preventDefault();
@ -321,26 +296,46 @@ const genAttr = (attrs: IObject, focusName = "bookmark", cb: (dialog: Dialog, rm
event.preventDefault();
break;
} 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">
<input placeholder="${window.siyuan.languages.attrName}" class="b3-text-field">
<span class="fn__flex-1"></span>
<span class="fn__flex-1">${inputElement.value}</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" 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>`);
const inputElements = dialog.element.querySelectorAll(".b3-text-field") as NodeListOf<HTMLInputElement>;
inputElements[inputElements.length - 2].focus();
bindAttrInput(inputElements[inputElements.length - 1], dialog.element);
bindAttrInput(inputElements[inputElements.length - 2], dialog.element);
const valueElement = target.parentElement.previousElementSibling.querySelector(".b3-text-field") as HTMLInputElement;
valueElement.focus();
bindAttrInput(valueElement, attrs.id);
addDialog.destroy();
});
event.stopPropagation();
event.preventDefault();
break;
} else if (type === "closeDialog") {
dialog.destroy();
} else if (type === "confirm") {
cb(dialog, removeAttrs);
}
target = target.parentElement;
}
@ -349,74 +344,76 @@ const genAttr = (attrs: IObject, focusName = "bookmark", cb: (dialog: Dialog, rm
if (focusName === item.getAttribute("data-name")) {
item.focus();
}
bindAttrInput(item, dialog.element);
bindAttrInput(item, attrs.id);
});
};
export const openFileAttr = (attrs: IObject, id: string, focusName = "bookmark") => {
genAttr(attrs, focusName, (dialog) => {
let nodeAttrHTML = "";
let errorTip = "";
const attrsResult: IObject = {};
dialog.element.querySelectorAll(".b3-text-field").forEach((item: HTMLInputElement) => {
let name = item.getAttribute("data-name");
if (!name) {
if (item.tagName === "INPUT") {
return;
}
name = "custom-" + (item.parentElement.querySelector(".b3-text-field") as HTMLInputElement).value;
}
if (item.value.trim()) {
if (!isValidAttrName(name)) {
errorTip += name.replace(/^custom-/, "") + ", ";
return;
}
attrsResult[name] = item.value;
const escapeHTML = Lute.EscapeHTMLStr(item.value);
if (name === "bookmark") {
nodeAttrHTML += `<div class="protyle-attr--bookmark">${escapeHTML}</div>`;
} else if (name === "name") {
nodeAttrHTML += `<div class="protyle-attr--name"><svg><use xlink:href="#iconN"></use></svg>${escapeHTML}</div>`;
} else if (name === "alias") {
nodeAttrHTML += `<div class="protyle-attr--alias"><svg><use xlink:href="#iconA"></use></svg>${escapeHTML}</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 !MOBILE
getAllModels().editor.forEach(item => {
if (item.editor.protyle.block.rootID === id) {
const refElement = item.editor.protyle.title.element.querySelector(".protyle-attr--refcount");
if (refElement) {
nodeAttrHTML += refElement.outerHTML;
}
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 => {
fetchPost("/api/block/getRefText", {id: id}, (response) => {
item.innerHTML = response.data;
});
});
});
/// #endif
fetchPost("/api/attr/resetBlockAttrs", {id, attrs: attrsResult}, () => {
/// #if !MOBILE
if (attrsResult.bookmark !== attrs.bookmark) {
const bookmark = getDockByType("bookmark").data.bookmark;
if (bookmark instanceof Bookmark) {
bookmark.update();
}
}
/// #endif
});
dialog.destroy();
});
genAttr(attrs, focusName,
// (dialog) => {
// let nodeAttrHTML = "";
// let errorTip = "";
// const attrsResult: IObject = {};
// dialog.element.querySelectorAll(".b3-text-field").forEach((item: HTMLInputElement) => {
// let name = item.getAttribute("data-name");
// if (!name) {
// if (item.tagName === "INPUT") {
// return;
// }
// name = "custom-" + (item.parentElement.querySelector(".b3-text-field") as HTMLInputElement).value;
// }
// if (item.value.trim()) {
// if (!isValidAttrName(name)) {
// errorTip += name.replace(/^custom-/, "") + ", ";
// return;
// }
// attrsResult[name] = item.value;
// const escapeHTML = Lute.EscapeHTMLStr(item.value);
// if (name === "bookmark") {
// nodeAttrHTML += `<div class="protyle-attr--bookmark">${escapeHTML}</div>`;
// } else if (name === "name") {
// nodeAttrHTML += `<div class="protyle-attr--name"><svg><use xlink:href="#iconN"></use></svg>${escapeHTML}</div>`;
// } else if (name === "alias") {
// nodeAttrHTML += `<div class="protyle-attr--alias"><svg><use xlink:href="#iconA"></use></svg>${escapeHTML}</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 !MOBILE
// getAllModels().editor.forEach(item => {
// if (item.editor.protyle.block.rootID === id) {
// const refElement = item.editor.protyle.title.element.querySelector(".protyle-attr--refcount");
// if (refElement) {
// nodeAttrHTML += refElement.outerHTML;
// }
// 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 => {
// fetchPost("/api/block/getRefText", {id: id}, (response) => {
// item.innerHTML = response.data;
// });
// });
// });
// /// #endif
// fetchPost("/api/attr/resetBlockAttrs", {id, attrs: attrsResult}, () => {
// /// #if !MOBILE
// if (attrsResult.bookmark !== attrs.bookmark) {
// const bookmark = getDockByType("bookmark").data.bookmark;
// if (bookmark instanceof Bookmark) {
// bookmark.update();
// }
// }
// /// #endif
// });
// dialog.destroy();
// }
);
};
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");
fetchPost("/api/attr/getBlockAttrs", {id}, (response) => {
genAttr(response.data, focusName, (dialog, removeAttrs) => {
let nodeAttrHTML = "";
const oldHTML = nodeElement.outerHTML;
let errorTip = "";
dialog.element.querySelectorAll(".b3-text-field").forEach((item: HTMLInputElement) => {
let name = item.getAttribute("data-name");
if (!name) {
if (item.tagName === "INPUT") {
return;
}
name = "custom-" + (item.parentElement.querySelector(".b3-text-field") as HTMLInputElement).value;
}
if (item.value.trim()) {
if (!isValidAttrName(name)) {
errorTip += name.replace(/^custom-/, "") + ", ";
return;
}
if (removeAttrs.includes(name)) {
removeAttrs.find((rmAttr, index) => {
if (rmAttr === name) {
removeAttrs.splice(index, 1);
return true;
}
});
}
const escapeHTML = Lute.EscapeHTMLStr(item.value);
nodeElement.setAttribute(name, escapeHTML);
if (name === "bookmark") {
/// #if !MOBILE
if (escapeHTML !== response.data.bookmark) {
const bookmark = getDockByType("bookmark").data.bookmark;
if (bookmark instanceof Bookmark) {
setTimeout(() => {
bookmark.update();
}, 219);
}
}
/// #endif
nodeAttrHTML += `<div class="protyle-attr--bookmark">${escapeHTML}</div>`;
} else if (name === "name") {
nodeAttrHTML += `<div class="protyle-attr--name"><svg><use xlink:href="#iconN"></use></svg>${escapeHTML}</div>`;
} else if (name === "alias") {
nodeAttrHTML += `<div class="protyle-attr--alias"><svg><use xlink:href="#iconA"></use></svg>${escapeHTML}</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);
}
});
removeAttrs.forEach(item => {
nodeElement.removeAttribute(item);
});
if (errorTip) {
showMessage(errorTip.substr(0, errorTip.length - 2) + " " + window.siyuan.languages.invalid);
}
const refElement = nodeElement.lastElementChild.querySelector(".protyle-attr--refcount");
if (refElement) {
nodeAttrHTML += refElement.outerHTML;
}
nodeElement.lastElementChild.innerHTML = nodeAttrHTML + Constants.ZWSP;
nodeElement.setAttribute("updated", dayjs().format("YYYYMMDDHHmmss"));
updateTransaction(protyle, id, nodeElement.outerHTML, oldHTML);
dialog.destroy();
});
genAttr(response.data, focusName,
// (dialog, removeAttrs) => {
// let nodeAttrHTML = "";
// const oldHTML = nodeElement.outerHTML;
// let errorTip = "";
// dialog.element.querySelectorAll(".b3-text-field").forEach((item: HTMLInputElement) => {
// let name = item.getAttribute("data-name");
// if (!name) {
// if (item.tagName === "INPUT") {
// return;
// }
// name = "custom-" + (item.parentElement.querySelector(".b3-text-field") as HTMLInputElement).value;
// }
// if (item.value.trim()) {
// if (!isValidAttrName(name)) {
// errorTip += name.replace(/^custom-/, "") + ", ";
// return;
// }
// if (removeAttrs.includes(name)) {
// removeAttrs.find((rmAttr, index) => {
// if (rmAttr === name) {
// removeAttrs.splice(index, 1);
// return true;
// }
// });
// }
// const escapeHTML = Lute.EscapeHTMLStr(item.value);
// nodeElement.setAttribute(name, escapeHTML);
// if (name === "bookmark") {
// /// #if !MOBILE
// if (escapeHTML !== response.data.bookmark) {
// const bookmark = getDockByType("bookmark").data.bookmark;
// if (bookmark instanceof Bookmark) {
// setTimeout(() => {
// bookmark.update();
// }, 219);
// }
// }
// /// #endif
// nodeAttrHTML += `<div class="protyle-attr--bookmark">${escapeHTML}</div>`;
// } else if (name === "name") {
// nodeAttrHTML += `<div class="protyle-attr--name"><svg><use xlink:href="#iconN"></use></svg>${escapeHTML}</div>`;
// } else if (name === "alias") {
// nodeAttrHTML += `<div class="protyle-attr--alias"><svg><use xlink:href="#iconA"></use></svg>${escapeHTML}</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);
// }
// });
// removeAttrs.forEach(item => {
// nodeElement.removeAttribute(item);
// });
// if (errorTip) {
// showMessage(errorTip.substr(0, errorTip.length - 2) + " " + window.siyuan.languages.invalid);
// }
// const refElement = nodeElement.lastElementChild.querySelector(".protyle-attr--refcount");
// if (refElement) {
// nodeAttrHTML += refElement.outerHTML;
// }
// nodeElement.lastElementChild.innerHTML = nodeAttrHTML + Constants.ZWSP;
// nodeElement.setAttribute("updated", dayjs().format("YYYYMMDDHHmmss"));
// updateTransaction(protyle, id, nodeElement.outerHTML, oldHTML);
// dialog.destroy();
// }
);
});
};