mirror of
https://github.com/siyuan-note/siyuan.git
synced 2025-12-22 17:40:13 +01:00
🎨 rollup cell menu
This commit is contained in:
parent
68a720db83
commit
5cd21dd855
4 changed files with 149 additions and 55 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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) => {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue