mirror of
https://github.com/siyuan-note/siyuan.git
synced 2025-12-22 17:40:13 +01:00
This commit is contained in:
parent
504d3f6155
commit
f42873c893
4 changed files with 164 additions and 15 deletions
|
|
@ -70,6 +70,13 @@ const genCellValueByElement = (colType: TAVCol, cellElement: HTMLElement) => {
|
|||
checked: cellElement.querySelector("use").getAttribute("xlink:href") === "#iconCheck" ? true : false
|
||||
}
|
||||
};
|
||||
}else if (colType === "relation") {
|
||||
cellValue = {
|
||||
type: colType,
|
||||
relation: {
|
||||
blockIDs: Array.from(cellElement.querySelectorAll("span")).map((item: HTMLElement) => item.getAttribute("data-id")),
|
||||
}
|
||||
};
|
||||
}
|
||||
if (colType === "block") {
|
||||
cellValue.isDetached = cellElement.dataset.detached === "true";
|
||||
|
|
@ -156,6 +163,13 @@ export const genCellValue = (colType: TAVCol, value: string | any) => {
|
|||
checked: value ? true : false
|
||||
}
|
||||
};
|
||||
}else if (colType === "relation") {
|
||||
cellValue = {
|
||||
type: colType,
|
||||
relation: {
|
||||
blockIDs: value as string[],
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
if (colType === "block") {
|
||||
|
|
@ -258,6 +272,8 @@ export const popTextCell = (protyle: IProtyle, cellElements: HTMLElement[], type
|
|||
openMenuPanel({protyle, blockElement, type: "date", cellElements});
|
||||
} else if (type === "checkbox") {
|
||||
updateCellValueByInput(protyle, type, cellElements);
|
||||
} else if (type === "relation") {
|
||||
openMenuPanel({protyle, blockElement, type: "relation", cellElements});
|
||||
}
|
||||
if (!hasClosestByClassName(cellElements[0], "custom-attr")) {
|
||||
cellElements[0].classList.add("av__cell--select");
|
||||
|
|
@ -464,7 +480,7 @@ const updateCellValueByInput = (protyle: IProtyle, type: TAVCol, cellElements: H
|
|||
});
|
||||
};
|
||||
|
||||
export const updateCellsValue = (protyle: IProtyle, nodeElement: HTMLElement, value = "") => {
|
||||
export const updateCellsValue = (protyle: IProtyle, nodeElement: HTMLElement, value: string | any = "") => {
|
||||
const doOperations: IOperation[] = [];
|
||||
const undoOperations: IOperation[] = [];
|
||||
|
||||
|
|
@ -583,6 +599,10 @@ 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 === "relation") {
|
||||
cellValue?.relation?.contents?.forEach((item, index) => {
|
||||
text += `<span data-id="${cellValue?.relation?.blockIDs[index]}">${item}</span>`;
|
||||
})
|
||||
}
|
||||
if (["text", "template", "url", "email", "phone", "number", "date", "created", "updated"].includes(cellValue.type) &&
|
||||
cellValue && cellValue[cellValue.type as "url"].content) {
|
||||
|
|
|
|||
|
|
@ -26,14 +26,14 @@ import {removeBlock} from "../../wysiwyg/remove";
|
|||
import {getEditorRange} from "../../util/selection";
|
||||
import {avRender} from "./render";
|
||||
import {setPageSize} from "./row";
|
||||
import {openSearchAV, updateRelation} from "./relation";
|
||||
import {bindRelationEvent, getRelationHTML, openSearchAV, setRelationCell, updateRelation} from "./relation";
|
||||
|
||||
export const openMenuPanel = (options: {
|
||||
protyle: IProtyle,
|
||||
blockElement: Element,
|
||||
type: "select" | "properties" | "config" | "sorts" | "filters" | "edit" | "date" | "asset" | "switcher",
|
||||
type: "select" | "properties" | "config" | "sorts" | "filters" | "edit" | "date" | "asset" | "switcher" | "relation",
|
||||
colId?: string, // for edit
|
||||
cellElements?: HTMLElement[], // for select & date
|
||||
cellElements?: HTMLElement[], // for select & date & relation & asset
|
||||
cb?: (avPanelElement: Element) => void
|
||||
}) => {
|
||||
let avPanelElement = document.querySelector(".av__panel");
|
||||
|
|
@ -67,6 +67,17 @@ 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 === "relation") {
|
||||
html = getRelationHTML(data, options.cellElements);
|
||||
if (!html) {
|
||||
openMenuPanel({
|
||||
protyle: options.protyle,
|
||||
blockElement: options.blockElement,
|
||||
type: "edit",
|
||||
colId: options.cellElements[0].dataset.colId
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
document.body.insertAdjacentHTML("beforeend", `<div class="av__panel" style="z-index: ${++window.siyuan.zIndex}">
|
||||
|
|
@ -76,7 +87,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"].includes(options.type)) {
|
||||
if (["select", "date", "asset", "relation"].includes(options.type)) {
|
||||
const cellRect = options.cellElements[options.cellElements.length - 1].getBoundingClientRect();
|
||||
if (options.type === "select") {
|
||||
bindSelectEvent(options.protyle, data, menuElement, options.cellElements);
|
||||
|
|
@ -86,12 +97,16 @@ export const openMenuPanel = (options: {
|
|||
bindAssetEvent({protyle: options.protyle, data, menuElement, cellElements: options.cellElements});
|
||||
setTimeout(() => {
|
||||
setPosition(menuElement, cellRect.left, cellRect.bottom, cellRect.height);
|
||||
}, Constants.TIMEOUT_LOAD); // 等待图片加载
|
||||
}, Constants.TIMEOUT_LOAD); // 等待加载
|
||||
} else if (options.type === "relation") {
|
||||
bindRelationEvent({protyle: options.protyle, data, menuElement, cellElements: options.cellElements});
|
||||
}
|
||||
if (["select", "date"].includes(options.type)) {
|
||||
if (["select", "date", "relation"].includes(options.type)) {
|
||||
const inputElement = menuElement.querySelector("input");
|
||||
if (inputElement) {
|
||||
inputElement.select();
|
||||
inputElement.focus();
|
||||
}
|
||||
setPosition(menuElement, cellRect.left, cellRect.bottom, cellRect.height);
|
||||
}
|
||||
} else {
|
||||
|
|
@ -861,6 +876,11 @@ export const openMenuPanel = (options: {
|
|||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
break;
|
||||
} else if (type === "setRelationCell") {
|
||||
setRelationCell(options.protyle, data, options.blockElement as HTMLElement, target);
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
break;
|
||||
} else if (type === "addColOptionOrCell") {
|
||||
addColOptionOrCell(options.protyle, data, options.cellElements, target, menuElement);
|
||||
window.siyuan.menus.menu.remove();
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import {upDownHint} from "../../../util/upDownHint";
|
|||
import {fetchPost} from "../../../util/fetch";
|
||||
import {escapeHtml} from "../../../util/escape";
|
||||
import {transaction} from "../../wysiwyg/transaction";
|
||||
import {updateCellsValue} from "./cell";
|
||||
|
||||
const genSearchList = (element: Element, keyword: string, avId: string, cb?: () => void) => {
|
||||
fetchPost("/api/av/searchAttributeView", {keyword}, (response) => {
|
||||
|
|
@ -150,3 +151,105 @@ export const toggleUpdateRelationBtn = (menuItemsElement: HTMLElement, avId: str
|
|||
btnElement.classList.remove("fn__none");
|
||||
}
|
||||
}
|
||||
|
||||
export const bindRelationEvent = (options: {
|
||||
protyle: IProtyle,
|
||||
data: IAV,
|
||||
menuElement: HTMLElement,
|
||||
cellElements: HTMLElement[]
|
||||
}) => {
|
||||
const hasIds = options.menuElement.textContent.split(",");
|
||||
fetchPost("/api/av/renderAttributeView", {
|
||||
id: options.menuElement.firstElementChild.getAttribute("data-av-id"),
|
||||
}, response => {
|
||||
const avData = response.data as IAV;
|
||||
let cellIndex = 0
|
||||
avData.view.columns.find((item, index) => {
|
||||
if (item.type === "block") {
|
||||
cellIndex = index
|
||||
return;
|
||||
}
|
||||
})
|
||||
let html = ""
|
||||
let selectHTML = ""
|
||||
avData.view.rows.forEach((item) => {
|
||||
const text = item.cells[cellIndex].value.block.content || item.cells[cellIndex].value.block.id;
|
||||
if (hasIds.includes(item.id)) {
|
||||
selectHTML += `<button data-id="${item.id}" data-type="setRelationCell" data-type="setRelationCell" class="b3-menu__item" draggable="true">
|
||||
<svg class="b3-menu__icon"><use xlink:href="#iconDrag"></use></svg>
|
||||
<span class="b3-menu__label">${text}</span>
|
||||
</button>`
|
||||
} else {
|
||||
html += `<button data-id="${item.id}" class="b3-menu__item" data-type="setRelationCell">
|
||||
<span class="b3-menu__label">${text}</span>
|
||||
</button>`
|
||||
}
|
||||
})
|
||||
const empty = `<button class="b3-menu__item">
|
||||
<span class="b3-menu__label">${window.siyuan.languages.emptyContent}</span>
|
||||
</button>`
|
||||
options.menuElement.innerHTML = `<div class="b3-menu__items">${selectHTML || empty}
|
||||
<button class="b3-menu__separator"></button>
|
||||
${html || empty}</div>`
|
||||
})
|
||||
}
|
||||
|
||||
export const getRelationHTML = (data: IAV, cellElements?: HTMLElement[]) => {
|
||||
let colRelationData: IAVCellRelationValue
|
||||
data.view.columns.find(item => {
|
||||
if (item.id === cellElements[0].dataset.colId) {
|
||||
colRelationData = item.relation
|
||||
return true;
|
||||
}
|
||||
})
|
||||
if (colRelationData && colRelationData.avID) {
|
||||
let ids = ""
|
||||
cellElements[0].querySelectorAll("span").forEach((item) => {
|
||||
ids += `${item.getAttribute("data-id")},`;
|
||||
});
|
||||
return `<span data-av-id="${colRelationData.avID}">${ids}</span>`
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
export const setRelationCell = (protyle: IProtyle, data: IAV, nodeElement: HTMLElement, target: HTMLElement) => {
|
||||
const menuElement = hasClosestByClassName(target, "b3-menu__items");
|
||||
if (!menuElement) {
|
||||
return
|
||||
}
|
||||
const ids: string[] = [];
|
||||
Array.from(menuElement.children).forEach((item) => {
|
||||
const id = item.getAttribute("data-id")
|
||||
if (item.getAttribute("draggable") && id) {
|
||||
ids.push(id);
|
||||
}
|
||||
})
|
||||
const empty = `<button class="b3-menu__item">
|
||||
<span class="b3-menu__label">${window.siyuan.languages.emptyContent}</span>
|
||||
</button>`
|
||||
const targetId = target.getAttribute("data-id")
|
||||
const separatorElement = menuElement.querySelector(".b3-menu__separator");
|
||||
if (target.getAttribute("draggable")) {
|
||||
if (!separatorElement.nextElementSibling.getAttribute("data-id")) {
|
||||
separatorElement.nextElementSibling.remove();
|
||||
}
|
||||
ids.splice(ids.indexOf(targetId), 1);
|
||||
separatorElement.after(target);
|
||||
// TODO
|
||||
if (!separatorElement.previousElementSibling) {
|
||||
separatorElement.insertAdjacentHTML("beforebegin", empty);
|
||||
}
|
||||
} else {
|
||||
if (!separatorElement.previousElementSibling.getAttribute("data-id")) {
|
||||
separatorElement.previousElementSibling.remove();
|
||||
}
|
||||
ids.push(targetId);
|
||||
separatorElement.before(target);
|
||||
// TODO
|
||||
if (!separatorElement.nextElementSibling) {
|
||||
separatorElement.insertAdjacentHTML("afterend", empty);
|
||||
}
|
||||
}
|
||||
updateCellsValue(protyle, nodeElement, ids);
|
||||
};
|
||||
|
|
|
|||
16
app/src/types/index.d.ts
vendored
16
app/src/types/index.d.ts
vendored
|
|
@ -1084,11 +1084,7 @@ interface IAVColumn {
|
|||
name: string,
|
||||
color: string,
|
||||
}[],
|
||||
relation?: {
|
||||
avID: string
|
||||
backKeyID: string
|
||||
isTwoWay: boolean
|
||||
}
|
||||
relation?: IAVCellRelationValue
|
||||
}
|
||||
|
||||
interface IAVRow {
|
||||
|
|
@ -1138,6 +1134,10 @@ interface IAVCellValue {
|
|||
checkbox?: {
|
||||
checked: boolean
|
||||
}
|
||||
relation?: {
|
||||
blockIDs: string[]
|
||||
contents?: string[]
|
||||
}
|
||||
date?: IAVCellDateValue
|
||||
created?: IAVCellDateValue
|
||||
updated?: IAVCellDateValue
|
||||
|
|
@ -1162,3 +1162,9 @@ interface IAVCellAssetValue {
|
|||
name: string,
|
||||
type: "file" | "image"
|
||||
}
|
||||
|
||||
interface IAVCellRelationValue {
|
||||
avID: string
|
||||
backKeyID: string
|
||||
isTwoWay: boolean
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue