import {Menu} from "../../../plugin/Menu"; import {unicode2Emoji} from "../../../emoji"; import {transaction} from "../../wysiwyg/transaction"; import {openMenuPanel} from "./openMenuPanel"; import {focusBlock} from "../../util/selection"; import {upDownHint} from "../../../util/upDownHint"; import {escapeAriaLabel, escapeAttr, escapeHtml} from "../../../util/escape"; import {hasClosestByClassName} from "../../util/hasClosest"; import {Constants} from "../../../constants"; 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 }]); } }); 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; const fields = getFieldsByData(data); 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) { transaction(options.protyle, [{ action: "setAttrViewBlockView", blockID: options.blockElement.getAttribute("data-node-id"), id: currentElement.dataset.id, avID: options.blockElement.getAttribute("data-av-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") }]); } }); 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") }]); } }); 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; } }; export const getFieldsByData = (data: IAV) => { return data.viewType === "table" ? (data.view as IAVTable).columns : (data.view as IAVGallery).fields; }; export const dragoverTab = (event: DragEvent) => { const viewTabElement = window.siyuan.dragElement.parentElement; if (viewTabElement.scrollWidth > viewTabElement.clientWidth) { const viewTabRect = viewTabElement.getBoundingClientRect(); if (event.clientX < viewTabRect.left) { viewTabElement.scroll({ left: viewTabElement.scrollLeft - Constants.SIZE_SCROLL_STEP, behavior: "smooth" }); } else if (event.clientX > viewTabRect.right) { viewTabElement.scroll({ left: viewTabElement.scrollLeft + Constants.SIZE_SCROLL_STEP, behavior: "smooth" }); } } const target = hasClosestByClassName(document.elementFromPoint(event.clientX, window.siyuan.dragElement.getBoundingClientRect().top + 10), "item"); if (!target) { return; } if (!viewTabElement.isSameNode(window.siyuan.dragElement.parentElement) || target.isSameNode(window.siyuan.dragElement)) { return; } const targetRect = target.getBoundingClientRect(); if (targetRect.left + targetRect.width / 2 < event.clientX) { if (target.nextElementSibling?.isSameNode(window.siyuan.dragElement)) { return; } target.after(window.siyuan.dragElement); } else { if (target.previousElementSibling?.isSameNode(window.siyuan.dragElement)) { return; } target.before(window.siyuan.dragElement); } };