diff --git a/app/src/boot/globalEvent/keydown.ts b/app/src/boot/globalEvent/keydown.ts
index 56e076532..93993134f 100644
--- a/app/src/boot/globalEvent/keydown.ts
+++ b/app/src/boot/globalEvent/keydown.ts
@@ -1259,12 +1259,6 @@ export const windowKeyDown = (app: App, event: KeyboardEvent) => {
return;
}
- const avElement = document.querySelector(".av__panel");
- if (avElement) {
- avElement.remove();
- return;
- }
-
if (!window.siyuan.menus.menu.element.classList.contains("fn__none")) {
if (window.siyuan.dialogs.length > 0 &&
window.siyuan.menus.menu.element.style.zIndex < (window.siyuan.dialogs[0].element.querySelector(".b3-dialog") as HTMLElement).style.zIndex) {
@@ -1280,6 +1274,13 @@ export const windowKeyDown = (app: App, event: KeyboardEvent) => {
return;
}
+ // 需放在 menus 后,否则资源列中添加资源会先关闭菜单
+ const avElement = document.querySelector(".av__panel");
+ if (avElement) {
+ avElement.remove();
+ return;
+ }
+
// remove blockpopover
const maxEditLevels: { [key: string]: number } = {oid: 0};
window.siyuan.blockPanels.forEach((item) => {
diff --git a/app/src/menus/protyle.ts b/app/src/menus/protyle.ts
index ce6b3a400..069d19d1d 100644
--- a/app/src/menus/protyle.ts
+++ b/app/src/menus/protyle.ts
@@ -1,4 +1,9 @@
-import {hasClosestBlock, hasClosestByMatchTag} from "../protyle/util/hasClosest";
+import {
+ hasClosestBlock,
+ hasClosestByAttribute,
+ hasClosestByClassName,
+ hasClosestByMatchTag
+} from "../protyle/util/hasClosest";
import {MenuItem} from "./Menu";
import {focusBlock, focusByRange, focusByWbr, getEditorRange, selectAll,} from "../protyle/util/selection";
import {
@@ -46,6 +51,142 @@ import {emitOpenMenu} from "../plugin/EventBus";
import {openMobileFileById} from "../mobile/editor";
import {openBacklink, openGraph} from "../layout/dock/util";
import {updateHeader} from "../protyle/render/av/row";
+import {renderAssetsPreview} from "../asset/renderAssets";
+import {upDownHint} from "../util/upDownHint";
+import {hintRenderAssets} from "../protyle/hint/extend";
+import {Menu} from "../plugin/Menu";
+
+const renderAssetList = (element: Element, k: string, position: IPosition, exts: string[] = []) => {
+ fetchPost("/api/search/searchAsset", {
+ k,
+ exts
+ }, (response) => {
+ let searchHTML = "";
+ response.data.forEach((item: { path: string, hName: string }, index: number) => {
+ searchHTML += `
`;
+ });
+
+ const listElement = element.querySelector(".b3-list");
+ const previewElement = element.querySelector("#preview");
+ const inputElement = element.querySelector("input");
+ listElement.innerHTML = searchHTML || `${window.siyuan.languages.emptyContent}`;
+ if (response.data.length > 0) {
+ previewElement.innerHTML = renderAssetsPreview(response.data[0].path);
+ } else {
+ previewElement.innerHTML = window.siyuan.languages.emptyContent;
+ }
+ /// #if MOBILE
+ window.siyuan.menus.menu.fullscreen();
+ /// #else
+ window.siyuan.menus.menu.popup(position);
+ /// #endif
+ if (!k) {
+ inputElement.select();
+ }
+ });
+}
+
+export const assetMenu = (protyle: IProtyle, position: IPosition, callback?: (url: string) => void, exts?: string[]) => {
+ window.siyuan.menus.menu.remove();
+ const menu = new Menu()
+ menu.addItem({
+ iconHTML: "",
+ type: "readonly",
+ label: ``,
+ bind(element) {
+ element.style.maxWidth = "none";
+ const listElement = element.querySelector(".b3-list");
+ const previewElement = element.querySelector("#preview");
+ listElement.addEventListener("mouseover", (event) => {
+ const target = event.target as HTMLElement;
+ const hoverItemElement = hasClosestByClassName(target, "b3-list-item");
+ if (!hoverItemElement) {
+ return;
+ }
+ previewElement.innerHTML = renderAssetsPreview(hoverItemElement.getAttribute("data-value"));
+ });
+ const inputElement = element.querySelector("input");
+ inputElement.addEventListener("keydown", (event: KeyboardEvent) => {
+ if (event.isComposing) {
+ return;
+ }
+ const isEmpty = element.querySelector(".b3-list--empty");
+ if (!isEmpty) {
+ const currentElement = upDownHint(listElement, event);
+ if (currentElement) {
+ previewElement.innerHTML = renderAssetsPreview(currentElement.getAttribute("data-value"));
+ event.stopPropagation();
+ }
+ }
+
+ if (event.key === "Enter") {
+ if (!isEmpty) {
+ const currentURL = element.querySelector(".b3-list-item--focus").getAttribute("data-value");
+ if (callback) {
+ callback(currentURL);
+ } else {
+ hintRenderAssets(currentURL, protyle);
+ window.siyuan.menus.menu.remove();
+ }
+ } else if (!callback) {
+ window.siyuan.menus.menu.remove();
+ focusByRange(protyle.toolbar.range);
+ }
+ // 空行处插入 mp3 会多一个空的 mp3 块
+ event.preventDefault();
+ event.stopPropagation();
+ } else if (event.key === "Escape") {
+ if (!callback) {
+ focusByRange(protyle.toolbar.range);
+ }
+ }
+ });
+ inputElement.addEventListener("input", (event) => {
+ event.stopPropagation();
+ renderAssetList(element, inputElement.value, position, exts);
+ });
+ element.lastElementChild.addEventListener("click", (event) => {
+ const target = event.target as HTMLElement;
+ const previousElement = hasClosestByAttribute(target, "data-type", "previous");
+ if (previousElement) {
+ inputElement.dispatchEvent(new KeyboardEvent("keydown", {key: "ArrowUp"}));
+ event.stopPropagation();
+ return;
+ }
+ const nextElement = hasClosestByAttribute(target, "data-type", "next");
+ if (nextElement) {
+ inputElement.dispatchEvent(new KeyboardEvent("keydown", {key: "ArrowDown"}));
+ event.stopPropagation();
+ return;
+ }
+ const listItemElement = hasClosestByClassName(target, "b3-list-item");
+ if (listItemElement) {
+ event.stopPropagation();
+ const currentURL = listItemElement.getAttribute("data-value");
+ if (callback) {
+ callback(currentURL);
+ } else {
+ hintRenderAssets(currentURL, protyle);
+ window.siyuan.menus.menu.remove();
+ }
+ }
+ });
+ renderAssetList(element, "", position, exts);
+ }
+ })
+}
export const fileAnnotationRefMenu = (protyle: IProtyle, refElement: HTMLElement) => {
const nodeElement = hasClosestBlock(refElement);
diff --git a/app/src/protyle/header/Background.ts b/app/src/protyle/header/Background.ts
index ce468b462..085b3ae41 100644
--- a/app/src/protyle/header/Background.ts
+++ b/app/src/protyle/header/Background.ts
@@ -13,6 +13,7 @@ import {popSearch} from "../../mobile/menu/search";
import {getEventName} from "../util/compatibility";
import {Dialog} from "../../dialog";
import {Constants} from "../../constants";
+import {assetMenu} from "../../menus/protyle";
const bgs = [
"background:radial-gradient(black 3px, transparent 4px),radial-gradient(black 3px, transparent 4px),linear-gradient(#fff 4px, transparent 0),linear-gradient(45deg, transparent 74px, transparent 75px, #a4a4a4 75px, #a4a4a4 76px, transparent 77px, transparent 109px),linear-gradient(-45deg, transparent 75px, transparent 76px, #a4a4a4 76px, #a4a4a4 77px, transparent 78px, transparent 109px),#fff;background-size: 109px 109px, 109px 109px,100% 6px, 109px 109px, 109px 109px;background-position: 54px 55px, 0px 0px, 0px 0px, 0px 0px, 0px 0px;",
@@ -303,10 +304,10 @@ export class Background {
break;
} else if (type === "asset") {
const rect = target.getBoundingClientRect();
- protyle.toolbar.showAssets(protyle, {
- x: rect.right - 798,
+ assetMenu(protyle, {
+ x: target.parentElement.getBoundingClientRect().right,
y: rect.bottom + 8,
- isLeft: false,
+ isLeft: true,
}, (url) => {
this.ial["title-img"] = `background-image:url("${url}")`;
this.render(this.ial, protyle.block.rootID);
diff --git a/app/src/protyle/hint/index.ts b/app/src/protyle/hint/index.ts
index e8fdc8cc5..d66d4b8aa 100644
--- a/app/src/protyle/hint/index.ts
+++ b/app/src/protyle/hint/index.ts
@@ -16,7 +16,7 @@ import {getContenteditableElement, hasNextSibling, hasPreviousSibling} from "../
import {transaction, updateTransaction} from "../wysiwyg/transaction";
import {insertHTML} from "../util/insertHTML";
import {highlightRender} from "../render/highlightRender";
-import {imgMenu} from "../../menus/protyle";
+import {assetMenu, imgMenu} from "../../menus/protyle";
import {hideElements} from "../ui/hideElements";
import {fetchPost} from "../../util/fetch";
import {getDisplayName, pathPosix} from "../../util/pathName";
@@ -608,7 +608,7 @@ ${genHintItemHTML(item)}
this.fixImageCursor(range);
protyle.toolbar.range = range;
const rangePosition = getSelectionPosition(nodeElement, range);
- protyle.toolbar.showAssets(protyle, {x: rangePosition.left, y: rangePosition.top + 26, w: 0, h: 26});
+ assetMenu(protyle, {x: rangePosition.left, y: rangePosition.top + 26, w: 0, h: 26});
updateTransaction(protyle, id, nodeElement.outerHTML, html);
return;
} else if (value === Constants.ZWSP + 3) {
diff --git a/app/src/protyle/render/av/openMenuPanel.ts b/app/src/protyle/render/av/openMenuPanel.ts
index 5141306e2..9750b76cb 100644
--- a/app/src/protyle/render/av/openMenuPanel.ts
+++ b/app/src/protyle/render/av/openMenuPanel.ts
@@ -20,6 +20,7 @@ import {getSearch} from "../../../util/functions";
import {openAsset} from "../../../editor/util";
/// #endif
import {previewImage} from "../../preview/image";
+import {assetMenu} from "../../../menus/protyle";
export const openMenuPanel = (options: {
protyle: IProtyle,
@@ -613,7 +614,7 @@ export const openMenuPanel = (options: {
id: options.colId,
avID,
name,
- type: target.dataset.oldType as TAVCol,
+ type: target.dataset.oldType as TAVCol,
}]);
}
avPanelElement.remove();
@@ -755,7 +756,7 @@ export const openMenuPanel = (options: {
break;
} else if (type === "addAssetExist") {
const rect = target.getBoundingClientRect();
- options.protyle.toolbar.showAssets(options.protyle, {
+ assetMenu(options.protyle, {
x: rect.right,
y: rect.bottom,
w: target.parentElement.clientWidth + 8,
@@ -782,7 +783,7 @@ export const openMenuPanel = (options: {
type: "addUpdate",
addUpdateValue: [value]
});
- hideElements(["util"], options.protyle);
+ window.siyuan.menus.menu.remove();
});
event.preventDefault();
event.stopPropagation();
diff --git a/app/src/protyle/toolbar/index.ts b/app/src/protyle/toolbar/index.ts
index 52cdca5e4..a46e3b940 100644
--- a/app/src/protyle/toolbar/index.ts
+++ b/app/src/protyle/toolbar/index.ts
@@ -1522,136 +1522,6 @@ export class Toolbar {
});
}
- private renderAssetList(listElement: Element, previewElement: Element, k: string, position: IPosition, exts: string[] = []) {
- fetchPost("/api/search/searchAsset", {
- k,
- exts
- }, (response) => {
- let searchHTML = "";
- response.data.forEach((item: { path: string, hName: string }, index: number) => {
- searchHTML += ``;
- });
- listElement.innerHTML = searchHTML || `${window.siyuan.languages.emptyContent}`;
- if (response.data.length > 0) {
- previewElement.innerHTML = renderAssetsPreview(response.data[0].path);
- }
- /// #if !MOBILE
- setPosition(this.subElement, position.x, position.y, position.h, position.w);
- /// #endif
- });
- }
-
- public showAssets(protyle: IProtyle, position: IPosition, callback?: (url: string) => void, exts: string[] = []) {
- hideElements(["hint"], protyle);
- window.siyuan.menus.menu.remove();
- this.subElement.style.width = "";
- this.subElement.style.padding = "";
- this.subElement.innerHTML = ``;
- const listElement = this.subElement.querySelector(".b3-list");
- const previewElement = this.subElement.firstElementChild.lastElementChild;
- listElement.addEventListener("mouseover", (event) => {
- const target = event.target as HTMLElement;
- const hoverItemElement = hasClosestByClassName(target, "b3-list-item");
- if (!hoverItemElement) {
- return;
- }
- previewElement.innerHTML = renderAssetsPreview(hoverItemElement.getAttribute("data-value"));
- });
- const inputElement = this.subElement.querySelector("input");
- inputElement.addEventListener("keydown", (event: KeyboardEvent) => {
- event.stopPropagation();
- if (event.isComposing) {
- return;
- }
- const isEmpty = this.subElement.querySelector(".b3-list--empty");
- if (!isEmpty) {
- const currentElement = upDownHint(listElement, event);
- if (currentElement) {
- previewElement.innerHTML = renderAssetsPreview(currentElement.getAttribute("data-value"));
- }
- }
-
- if (event.key === "Enter") {
- if (!isEmpty) {
- const currentURL = this.subElement.querySelector(".b3-list-item--focus").getAttribute("data-value");
- if (callback) {
- callback(currentURL);
- } else {
- hintRenderAssets(currentURL, protyle);
- }
- } else if (!callback) {
- focusByRange(this.range);
- }
- this.subElement.classList.add("fn__none");
- // 空行处插入 mp3 会多一个空的 mp3 块
- event.preventDefault();
- } else if (event.key === "Escape") {
- this.subElement.classList.add("fn__none");
- if (!callback) {
- focusByRange(this.range);
- }
- }
- });
- inputElement.addEventListener("input", (event) => {
- event.stopPropagation();
- this.renderAssetList(listElement, previewElement, inputElement.value, position, exts);
- });
- this.subElement.lastElementChild.addEventListener("click", (event) => {
- const target = event.target as HTMLElement;
- const previousElement = hasClosestByAttribute(target, "data-type", "previous");
- if (previousElement) {
- inputElement.dispatchEvent(new KeyboardEvent("keydown", {key: "ArrowUp"}));
- event.stopPropagation();
- return;
- }
- const nextElement = hasClosestByAttribute(target, "data-type", "next");
- if (nextElement) {
- inputElement.dispatchEvent(new KeyboardEvent("keydown", {key: "ArrowDown"}));
- event.stopPropagation();
- return;
- }
- if (target.classList.contains("b3-list--empty")) {
- this.subElement.classList.add("fn__none");
- if (!callback) {
- focusByRange(this.range);
- }
- event.stopPropagation();
- return;
- }
- const listItemElement = hasClosestByClassName(target, "b3-list-item");
- if (listItemElement) {
- event.stopPropagation();
- const currentURL = listItemElement.getAttribute("data-value");
- if (callback) {
- callback(currentURL);
- } else {
- hintRenderAssets(currentURL, protyle);
- }
- }
- });
- this.subElement.style.zIndex = (++window.siyuan.zIndex).toString();
- this.subElement.classList.remove("fn__none");
- this.subElementCloseCB = undefined;
- /// #if MOBILE
- setPosition(this.subElement, 0, 0);
- /// #endif
- this.element.classList.add("fn__none");
- inputElement.select();
- this.renderAssetList(listElement, previewElement, "", position, exts);
- }
-
public showContent(protyle: IProtyle, range: Range, nodeElement: Element) {
this.range = range;
hideElements(["hint"], protyle);