import {Menu} from "../../../plugin/Menu"; import {unicode2Emoji} from "../../../emoji"; import {transaction} from "../../wysiwyg/transaction"; import {openMenuPanel} from "./openMenuPanel"; import {focusBlock} from "../../util/selection"; import {Constants} from "../../../constants"; import {upDownHint} from "../../../util/upDownHint"; import {avRender} from "./render"; import {escapeAriaLabel, escapeAttr, escapeHtml} from "../../../util/escape"; export const openViewMenu = (options: { protyle: IProtyle, blockElement: HTMLElement, element: HTMLElement }) => { if (options.protyle.disabled) { return; } const menu = new Menu("av-view"); if (menu.isOpen) { return; } menu.addItem({ id: "rename", icon: "iconEdit", label: window.siyuan.languages.rename, click() { document.querySelector(".av__panel")?.remove(); openMenuPanel({ protyle: options.protyle, blockElement: options.blockElement, type: "config", cb: (avPanelElement) => { (avPanelElement.querySelector('.b3-text-field[data-type="name"]') as HTMLInputElement).focus(); } }); } }); menu.addItem({ id: "config", icon: "iconSettings", label: window.siyuan.languages.config, click() { document.querySelector(".av__panel")?.remove(); openMenuPanel({ protyle: options.protyle, blockElement: options.blockElement, type: "config" }); } }); menu.addSeparator(); menu.addItem({ id: "duplicate", icon: "iconCopy", label: window.siyuan.languages.duplicate, click() { document.querySelector(".av__panel")?.remove(); const id = Lute.NewNodeID(); transaction(options.protyle, [{ action: "duplicateAttrViewView", avID: options.blockElement.dataset.avId, previousID: options.element.dataset.id, id, blockID: options.blockElement.dataset.nodeId }], [{ action: "removeAttrViewView", avID: options.blockElement.dataset.avId, id, blockID: options.blockElement.dataset.nodeId }]); options.blockElement.setAttribute(Constants.CUSTOM_SY_AV_VIEW, id); } }); if (options.blockElement.querySelectorAll(".layout-tab-bar .item").length > 1) { menu.addItem({ id: "delete", icon: "iconTrashcan", label: window.siyuan.languages.delete, click() { document.querySelector(".av__panel")?.remove(); transaction(options.protyle, [{ action: "removeAttrViewView", avID: options.blockElement.dataset.avId, id: options.element.dataset.id, blockID: options.blockElement.dataset.nodeId }]); } }); } const rect = options.element.getBoundingClientRect(); menu.open({ x: rect.left, y: rect.bottom }); }; export const bindViewEvent = (options: { protyle: IProtyle, data: IAV, menuElement: HTMLElement blockElement: Element }) => { const inputElement = options.menuElement.querySelector('.b3-text-field[data-type="name"]') as HTMLInputElement; inputElement.addEventListener("blur", () => { if (inputElement.value !== inputElement.dataset.value) { transaction(options.protyle, [{ action: "setAttrViewViewName", avID: options.data.id, id: options.data.viewID, data: inputElement.value }], [{ action: "setAttrViewViewName", avID: options.data.id, id: options.data.viewID, data: inputElement.dataset.value }]); inputElement.dataset.value = inputElement.value; } }); inputElement.addEventListener("keydown", (event) => { if (event.isComposing) { return; } if (event.key === "Enter") { event.preventDefault(); inputElement.blur(); options.menuElement.parentElement.remove(); } }); inputElement.select(); inputElement.value = inputElement.dataset.value; const descElement = options.menuElement.querySelector('.b3-text-field[data-type="desc"]') as HTMLTextAreaElement; inputElement.nextElementSibling.addEventListener("click", () => { const descPanelElement = descElement.parentElement; descPanelElement.classList.toggle("fn__none"); if (!descPanelElement.classList.contains("fn__none")) { descElement.focus(); } }); descElement.addEventListener("blur", () => { if (descElement.value !== descElement.dataset.value) { transaction(options.protyle, [{ action: "setAttrViewViewDesc", avID: options.data.id, id: options.data.viewID, data: descElement.value }], [{ action: "setAttrViewViewDesc", avID: options.data.id, id: options.data.viewID, data: descElement.dataset.value }]); descElement.dataset.value = descElement.value; } }); descElement.addEventListener("keydown", (event) => { if (event.isComposing) { return; } if (event.key === "Enter") { event.preventDefault(); descElement.blur(); options.menuElement.parentElement.remove(); } }); descElement.addEventListener("input", () => { inputElement.nextElementSibling.setAttribute("aria-label", descElement.value ? escapeHtml(descElement.value) : window.siyuan.languages.addDesc); }); }; export const getViewHTML = (data: IAV) => { const view = data.view; let fields: IAVColumn[]; if (data.viewType === "table") { fields = (view as IAVTable).columns; } else if (data.viewType === "gallery") { fields = (view as IAVGallery).fields; } return `
`; }; export const bindSwitcherEvent = (options: { protyle: IProtyle, menuElement: Element, blockElement: Element }) => { const inputElement = options.menuElement.querySelector(".b3-text-field") as HTMLInputElement; inputElement.focus(); inputElement.addEventListener("keydown", (event) => { event.stopPropagation(); if (event.isComposing) { return; } upDownHint(options.menuElement.querySelector(".fn__flex-1"), event, "b3-menu__item--current"); if (event.key === "Enter") { const currentElement = options.menuElement.querySelector(".b3-menu__item--current") as HTMLElement; if (currentElement) { options.blockElement.removeAttribute("data-render"); avRender(options.blockElement, options.protyle, undefined, currentElement.dataset.id); options.menuElement.remove(); focusBlock(options.blockElement); } } else if (event.key === "Escape") { options.menuElement.remove(); focusBlock(options.blockElement); } }); inputElement.addEventListener("input", (event: InputEvent) => { if (event.isComposing) { return; } filterSwitcher(options.menuElement); }); inputElement.addEventListener("compositionend", () => { filterSwitcher(options.menuElement); }); }; const filterSwitcher = (menuElement: Element) => { const inputElement = menuElement.querySelector(".b3-text-field") as HTMLInputElement; const key = inputElement.value; menuElement.querySelectorAll('.b3-menu__item[draggable="true"]').forEach(item => { if (!key || (key.toLowerCase().indexOf(item.textContent.trim().toLowerCase()) > -1 || item.textContent.trim().toLowerCase().indexOf(key.toLowerCase()) > -1)) { item.classList.remove("fn__none"); } else { item.classList.add("fn__none"); item.classList.remove("b3-menu__item--current"); } }); if (!menuElement.querySelector(".b3-menu__item--current")) { menuElement.querySelector(".fn__flex-1 .b3-menu__item:not(.fn__none)")?.classList.add("b3-menu__item--current"); } }; export const getSwitcherHTML = (views: IAVView[], viewId: string) => { let html = ""; views.forEach((item) => { html += ``; }); return `
${html}
`; }; export const addView = (protyle: IProtyle, blockElement: Element) => { const id = Lute.NewNodeID(); const avID = blockElement.getAttribute("data-av-id"); const viewElement = blockElement.querySelector(".av__views"); const addMenu = new Menu(undefined, () => { viewElement.classList.remove("av__views--show"); }); addMenu.addItem({ icon: "iconTable", label: window.siyuan.languages.table, click() { transaction(protyle, [{ action: "addAttrViewView", avID, id, blockID: blockElement.getAttribute("data-node-id") }], [{ action: "removeAttrViewView", avID, id, blockID: blockElement.getAttribute("data-node-id") }]); blockElement.setAttribute(Constants.CUSTOM_SY_AV_VIEW, id); blockElement.setAttribute("data-av-type", "table"); } }); addMenu.addItem({ icon: "iconGallery", label: window.siyuan.languages.gallery, click() { transaction(protyle, [{ action: "addAttrViewView", avID, layout: "gallery", id, blockID: blockElement.getAttribute("data-node-id") }], [{ action: "removeAttrViewView", layout: "gallery", avID, id, blockID: blockElement.getAttribute("data-node-id") }]); blockElement.setAttribute(Constants.CUSTOM_SY_AV_VIEW, id); blockElement.setAttribute("data-av-type", "gallery"); } }); viewElement.classList.add("av__views--show"); const addRect = viewElement.querySelector('.block__icon[data-type="av-add"]')?.getBoundingClientRect(); addMenu.open({ x: addRect.left, y: addRect.bottom + 8 }); }; export const getViewIcon = (type: string) => { switch (type) { case "table": return "iconTable"; case "gallery": return "iconGallery"; } }; export const getViewName = (type: string) => { switch (type) { case "table": return window.siyuan.languages.table; case "gallery": return window.siyuan.languages.gallery; } };