Quellcode durchsuchen

:art: rollup cell menu

Vanessa vor 1 Jahr
Ursprung
Commit
5cd21dd855

+ 69 - 2
app/src/protyle/render/av/cell.ts

@@ -276,6 +276,8 @@ export const popTextCell = (protyle: IProtyle, cellElements: HTMLElement[], type
             updateCellValueByInput(protyle, type, cellElements);
         } else if (type === "relation") {
             openMenuPanel({protyle, blockElement, type: "relation", cellElements});
+        } else if (type === "rollup") {
+            openMenuPanel({protyle, blockElement, type: "rollup", cellElements, colId: cellElements[0].dataset.colId});
         }
         if (!hasClosestByClassName(cellElements[0], "custom-attr")) {
             cellElements[0].classList.add("av__cell--select");
@@ -644,8 +646,8 @@ export const renderCell = (cellValue: IAVCellValue, wrap: boolean) => {
     } else if (cellValue.type === "checkbox") {
         text += `<svg class="av__checkbox"><use xlink:href="#icon${cellValue?.checkbox?.checked ? "Check" : "Uncheck"}"></use></svg>`;
     } else if (cellValue.type === "rollup") {
-        cellValue?.rollup?.contents?.forEach((item) => {
-            text += renderCell(item, wrap);
+        cellValue?.rollup?.contents?.forEach((item, index) => {
+            text += renderRollup(item, wrap) + (index === cellValue.rollup.contents.length - 1 ? "" : " ,");
         });
     } else if (cellValue.type === "relation") {
         cellValue?.relation?.contents?.forEach((item, index) => {
@@ -659,6 +661,71 @@ export const renderCell = (cellValue: IAVCellValue, wrap: boolean) => {
     return text;
 };
 
+const renderRollup = (cellValue: IAVCellValue, wrap: boolean) => {
+    let text = ""
+    if (["text", "template"].includes(cellValue.type)) {
+        text = `<span class="av__celltext">${cellValue ? (cellValue[cellValue.type as "text"].content || "") : ""}</span>`;
+    } else if (["url", "email", "phone"].includes(cellValue.type)) {
+        const urlContent = cellValue ? cellValue[cellValue.type as "url"].content : "";
+        // https://github.com/siyuan-note/siyuan/issues/9291
+        let urlAttr = "";
+        if (cellValue.type === "url") {
+            urlAttr = ` data-href="${urlContent}"`;
+        }
+        text = `<span class="av__celltext av__celltext--url" data-type="${cellValue.type}"${urlAttr}>${urlContent}</span>`;
+    } else if (cellValue.type === "block") {
+        if (cellValue?.isDetached) {
+            text = `<span class="av__celltext">${cellValue.block.content || ""}</span>
+<span class="b3-chip b3-chip--info b3-chip--small" data-type="block-more">${window.siyuan.languages.more}</span>`;
+        } else {
+            text = `<span data-type="block-ref" data-id="${cellValue.block.id}" data-subtype="s" class="av__celltext av__celltext--ref">${cellValue.block.content || ""}</span>
+<span class="b3-chip b3-chip--info b3-chip--small popover__block" data-id="${cellValue.block.id}" data-type="block-more">${window.siyuan.languages.update}</span>`;
+        }
+    } else if (cellValue.type === "number") {
+        text = `<span style="float: right;${wrap ? "word-break: break-word;" : ""}" class="av__celltext">${cellValue?.number.formattedContent || cellValue?.number.content || ""}</span>`;
+    } else if (cellValue.type === "mSelect" || cellValue.type === "select") {
+        cellValue?.mSelect?.forEach((item) => {
+            text += `<span class="b3-chip" style="background-color:var(--b3-font-background${item.color});color:var(--b3-font-color${item.color})">${item.content}</span>`;
+        });
+    } else if (cellValue.type === "date") {
+        const dataValue = cellValue ? cellValue.date : null;
+        text = `<span class="av__celltext" data-value='${JSON.stringify(dataValue)}'>`;
+        if (dataValue && dataValue.isNotEmpty) {
+            text += dayjs(dataValue.content).format(dataValue.isNotTime ? "YYYY-MM-DD" : "YYYY-MM-DD HH:mm");
+        }
+        if (dataValue && dataValue.hasEndDate && dataValue.isNotEmpty && dataValue.isNotEmpty2) {
+            text += `<svg class="av__cellicon"><use xlink:href="#iconForward"></use></svg>${dayjs(dataValue.content2).format(dataValue.isNotTime ? "YYYY-MM-DD" : "YYYY-MM-DD HH:mm")}`;
+        }
+        text += "</span>";
+    } else if (["created", "updated"].includes(cellValue.type)) {
+        const dataValue = cellValue ? cellValue[cellValue.type as "date"] : null;
+        text = `<span class="av__celltext" data-value='${JSON.stringify(dataValue)}'>`;
+        if (dataValue && dataValue.isNotEmpty) {
+            text += dayjs(dataValue.content).format("YYYY-MM-DD HH:mm");
+        }
+        text += "</span>";
+    } else if (cellValue.type === "mAsset") {
+        cellValue?.mAsset?.forEach((item) => {
+            if (item.type === "image") {
+                text += `<img class="av__cellassetimg" src="${item.content}">`;
+            } else {
+                text += `<span class="b3-chip av__celltext--url" data-url="${item.content}">${item.name}</span>`;
+            }
+        });
+    } else if (cellValue.type === "checkbox") {
+        text += `<svg class="av__checkbox"><use xlink:href="#icon${cellValue?.checkbox?.checked ? "Check" : "Uncheck"}"></use></svg>`;
+    } else if (cellValue.type === "rollup") {
+        cellValue?.rollup?.contents?.forEach((item) => {
+            text += renderCell(item, wrap) + '<span class="fn__space"></span>';
+        });
+    } else if (cellValue.type === "relation") {
+        cellValue?.relation?.contents?.forEach((item, index) => {
+            text += `<span class="av__celltext--ref" style="margin-right: 8px" data-id="${cellValue?.relation?.blockIDs[index]}">${item}</span>`;
+        });
+    }
+    return text;
+}
+
 export const updateHeaderCell = (cellElement: HTMLElement, headerValue: {
     icon?: string,
     name?: string,

+ 3 - 46
app/src/protyle/render/av/col.ts

@@ -9,7 +9,7 @@ import {removeAttrViewColAnimation, updateAttrViewCellAnimation} from "./action"
 import {openEmojiPanel, unicode2Emoji} from "../../../emoji";
 import {focusBlock} from "../../util/selection";
 import {toggleUpdateRelationBtn} from "./relation";
-import {getNameByOperator} from "./calc";
+import {bindRollupEvent, getRollupHTML} from "./rollup";
 
 export const duplicateCol = (options: {
     protyle: IProtyle,
@@ -160,21 +160,7 @@ export const getEditHTML = (options: {
     <button style="margin: 4px 0 8px;" class="b3-button fn__block" data-type="updateRelation">${window.siyuan.languages.confirm}</button>
 </div>`;
     } else if (colData.type === "rollup") {
-        html += `<button class="b3-menu__item" data-type="goSearchRollupCol" data-old-value='${JSON.stringify(colData.rollup || {})}'>
-    <span class="b3-menu__label">${window.siyuan.languages.relation}</span>
-    <span class="b3-menu__accelerator"></span>
-    <svg class="b3-menu__icon b3-menu__icon--small"><use xlink:href="#iconRight"></use></svg>
-</button>
-<button class="b3-menu__item" data-type="goSearchRollupTarget">
-    <span class="b3-menu__label">${window.siyuan.languages.attr}</span>
-    <span class="b3-menu__accelerator"></span>
-    <svg class="b3-menu__icon b3-menu__icon--small"><use xlink:href="#iconRight"></use></svg>
-</button>
-<button class="b3-menu__item" data-type="goSearchRollupCalc">
-    <span class="b3-menu__label">${window.siyuan.languages.calc}</span>
-    <span class="b3-menu__accelerator">${getNameByOperator(colData.rollup?.calc?.operator)}</span>
-    <svg class="b3-menu__icon b3-menu__icon--small"><use xlink:href="#iconRight"></use></svg>
-</button>`;
+        html += getRollupHTML({colData});
     }
     return `<div class="b3-menu__items">
     ${html}
@@ -364,36 +350,7 @@ export const bindEditEvent = (options: {
             toggleUpdateRelationBtn(options.menuElement, avID);
         }
     }
-
-    const goSearchRollupColElement = options.menuElement.querySelector('[data-type="goSearchRollupCol"]') as HTMLElement;
-    if (goSearchRollupColElement) {
-        const oldValue = JSON.parse(goSearchRollupColElement.dataset.oldValue) as IAVCellRollupValue;
-        const goSearchRollupTargetElement = options.menuElement.querySelector('[data-type="goSearchRollupTarget"]') as HTMLElement;
-        let targetKeyAVId = ""
-        if (oldValue.relationKeyID) {
-            options.data.view.columns.find((item) => {
-                if (item.id === oldValue.relationKeyID) {
-                    goSearchRollupColElement.querySelector(".b3-menu__accelerator").textContent = item.name;
-                    targetKeyAVId = item.relation.avID;
-                    goSearchRollupTargetElement.dataset.avId = targetKeyAVId;
-                    return true;
-                }
-            })
-        }
-        if (oldValue.keyID && targetKeyAVId) {
-            fetchPost("/api/av/getAttributeView", {id: targetKeyAVId}, (response) => {
-                response.data.av.keyValues.find((item: { key: { id: string, name: string, type: TAVCol } }) => {
-                    if (item.key.id === oldValue.keyID) {
-                        goSearchRollupTargetElement.querySelector('.b3-menu__accelerator').textContent = item.key.name;
-                        const goSearchRollupCalcElement = options.menuElement.querySelector('[data-type="goSearchRollupCalc"]') as HTMLElement;
-                        goSearchRollupCalcElement.dataset.colType = item.key.type;
-                        goSearchRollupCalcElement.dataset.calc = oldValue.calc.operator;
-                        return true;
-                    }
-                });
-            });
-        }
-    }
+    bindRollupEvent(options);
 };
 
 export const getColNameByType = (type: TAVCol) => {

+ 11 - 7
app/src/protyle/render/av/openMenuPanel.ts

@@ -27,15 +27,15 @@ import {focusBlock, getEditorRange} from "../../util/selection";
 import {avRender} from "./render";
 import {setPageSize} from "./row";
 import {bindRelationEvent, getRelationHTML, openSearchAV, setRelationCell, updateRelation} from "./relation";
-import {goSearchRollupCol} from "./rollup";
+import {bindRollupEvent, getRollupHTML, goSearchRollupCol} from "./rollup";
 import {updateCellsValue} from "./cell";
 import {openCalcMenu} from "./calc";
 
 export const openMenuPanel = (options: {
     protyle: IProtyle,
     blockElement: Element,
-    type: "select" | "properties" | "config" | "sorts" | "filters" | "edit" | "date" | "asset" | "switcher" | "relation",
-    colId?: string, // for edit
+    type: "select" | "properties" | "config" | "sorts" | "filters" | "edit" | "date" | "asset" | "switcher" | "relation" | "rollup",
+    colId?: string, // for edit, rollup
     cellElements?: HTMLElement[],   // for select & date & relation & asset
     cb?: (avPanelElement: Element) => void
 }) => {
@@ -70,6 +70,8 @@ export const openMenuPanel = (options: {
             html = getEditHTML({protyle: options.protyle, data, colId: options.colId});
         } else if (options.type === "date") {
             html = getDateHTML(data.view, options.cellElements);
+        } else if (options.type === "rollup") {
+            html = `<div class="b3-menu__items">${getRollupHTML({data, cellElements: options.cellElements})}</div>`;
         } else if (options.type === "relation") {
             html = getRelationHTML(data, options.cellElements);
             if (!html) {
@@ -90,7 +92,7 @@ export const openMenuPanel = (options: {
         avPanelElement = document.querySelector(".av__panel");
         const menuElement = avPanelElement.lastElementChild as HTMLElement;
         const tabRect = options.blockElement.querySelector(".av__views")?.getBoundingClientRect();
-        if (["select", "date", "asset", "relation"].includes(options.type)) {
+        if (["select", "date", "asset", "relation", "rollup"].includes(options.type)) {
             const cellRect = options.cellElements[options.cellElements.length - 1].getBoundingClientRect();
             if (options.type === "select") {
                 bindSelectEvent(options.protyle, data, menuElement, options.cellElements, options.blockElement);
@@ -115,8 +117,10 @@ export const openMenuPanel = (options: {
                 }, Constants.TIMEOUT_LOAD);  // 等待加载
             } else if (options.type === "relation") {
                 bindRelationEvent({protyle: options.protyle, data, menuElement, cellElements: options.cellElements});
+            } else if (options.type === "rollup") {
+                bindRollupEvent({protyle: options.protyle, data, menuElement});
             }
-            if (["select", "date", "relation"].includes(options.type)) {
+            if (["select", "date", "relation", "rollup"].includes(options.type)) {
                 const inputElement = menuElement.querySelector("input");
                 if (inputElement) {
                     inputElement.select();
@@ -787,7 +791,7 @@ export const openMenuPanel = (options: {
                         data,
                         isRelation: true,
                         protyle: options.protyle,
-                        colId: menuElement.querySelector(".b3-menu__item").getAttribute("data-col-id")
+                        colId: options.colId || menuElement.querySelector(".b3-menu__item").getAttribute("data-col-id")
                     });
                     event.preventDefault();
                     event.stopPropagation();
@@ -798,7 +802,7 @@ export const openMenuPanel = (options: {
                         data,
                         isRelation: false,
                         protyle: options.protyle,
-                        colId: menuElement.querySelector(".b3-menu__item").getAttribute("data-col-id")
+                        colId: options.colId || menuElement.querySelector(".b3-menu__item").getAttribute("data-col-id")
                     });
                     event.preventDefault();
                     event.stopPropagation();

+ 66 - 0
app/src/protyle/render/av/rollup.ts

@@ -8,6 +8,7 @@ import {genIconHTML} from "../util";
 import {unicode2Emoji} from "../../../emoji";
 import {getColIconByType} from "./col";
 import {showMessage} from "../../../dialog/message";
+import {getNameByOperator} from "./calc";
 
 const updateCol = (options: {
     target: HTMLElement,
@@ -144,3 +145,68 @@ export const goSearchRollupCol = (options: {
     });
     menu.element.querySelector(".b3-menu__items").setAttribute("style", "overflow: initial");
 };
+
+export const getRollupHTML = (options: { data?: IAV, cellElements?: HTMLElement[], colData?: IAVColumn }) => {
+    let colData: IAVColumn;
+    if (options.colData) {
+        colData = options.colData;
+    } else {
+        options.data.view.columns.find((item) => {
+            if (item.id === options.cellElements[0].dataset.colId) {
+                colData = item;
+                return true;
+            }
+        });
+    }
+    return `<button class="b3-menu__item" data-type="goSearchRollupCol" data-old-value='${JSON.stringify(colData.rollup || {})}'>
+    <span class="b3-menu__label">${window.siyuan.languages.relation}</span>
+    <span class="b3-menu__accelerator"></span>
+    <svg class="b3-menu__icon b3-menu__icon--small"><use xlink:href="#iconRight"></use></svg>
+</button>
+<button class="b3-menu__item" data-type="goSearchRollupTarget">
+    <span class="b3-menu__label">${window.siyuan.languages.attr}</span>
+    <span class="b3-menu__accelerator"></span>
+    <svg class="b3-menu__icon b3-menu__icon--small"><use xlink:href="#iconRight"></use></svg>
+</button>
+<button class="b3-menu__item" data-type="goSearchRollupCalc">
+    <span class="b3-menu__label">${window.siyuan.languages.calc}</span>
+    <span class="b3-menu__accelerator">${getNameByOperator(colData.rollup?.calc?.operator)}</span>
+    <svg class="b3-menu__icon b3-menu__icon--small"><use xlink:href="#iconRight"></use></svg>
+</button>`
+}
+
+export const bindRollupEvent = (options:  {
+    protyle: IProtyle,
+    data: IAV,
+    menuElement: HTMLElement
+}) => {
+    const goSearchRollupColElement = options.menuElement.querySelector('[data-type="goSearchRollupCol"]') as HTMLElement;
+    if (goSearchRollupColElement) {
+        const oldValue = JSON.parse(goSearchRollupColElement.dataset.oldValue) as IAVCellRollupValue;
+        const goSearchRollupTargetElement = options.menuElement.querySelector('[data-type="goSearchRollupTarget"]') as HTMLElement;
+        let targetKeyAVId = ""
+        if (oldValue.relationKeyID) {
+            options.data.view.columns.find((item) => {
+                if (item.id === oldValue.relationKeyID) {
+                    goSearchRollupColElement.querySelector(".b3-menu__accelerator").textContent = item.name;
+                    targetKeyAVId = item.relation.avID;
+                    goSearchRollupTargetElement.dataset.avId = targetKeyAVId;
+                    return true;
+                }
+            })
+        }
+        if (oldValue.keyID && targetKeyAVId) {
+            fetchPost("/api/av/getAttributeView", {id: targetKeyAVId}, (response) => {
+                response.data.av.keyValues.find((item: { key: { id: string, name: string, type: TAVCol } }) => {
+                    if (item.key.id === oldValue.keyID) {
+                        goSearchRollupTargetElement.querySelector('.b3-menu__accelerator').textContent = item.key.name;
+                        const goSearchRollupCalcElement = options.menuElement.querySelector('[data-type="goSearchRollupCalc"]') as HTMLElement;
+                        goSearchRollupCalcElement.dataset.colType = item.key.type;
+                        goSearchRollupCalcElement.dataset.calc = oldValue.calc.operator;
+                        return true;
+                    }
+                });
+            });
+        }
+    }
+}