Vanessa 2024-01-21 12:21:31 +08:00
parent 9c28056204
commit ad39590205
7 changed files with 105 additions and 61 deletions

View file

@ -16,16 +16,13 @@
&__avheader {
border-bottom: 1px solid var(--b3-border-color);
padding: 8px;
color: var(--b3-protyle-inline-blockref-color);
opacity: .86;
transition: var(--b3-transition);
cursor: pointer;
.block__logo {
color: var(--b3-protyle-inline-blockref-color);
opacity: .86;
transition: var(--b3-transition);
cursor: pointer;
&:hover {
opacity: 1;
}
&:hover {
opacity: 1;
}
}

View file

@ -6,6 +6,7 @@ import {popTextCell} from "./cell";
import {hasClosestBlock, hasClosestByClassName} from "../../util/hasClosest";
import {unicode2Emoji} from "../../../emoji";
import {transaction} from "../../wysiwyg/transaction";
import {openMenuPanel} from "./openMenuPanel";
const genAVRollupHTML = (value: IAVCellValue) => {
let html = "";
@ -127,7 +128,7 @@ export const genAVValueHTML = (value: IAVCellValue) => {
return html;
};
export const renderAVAttribute = (element: HTMLElement, id: string, protyle: IProtyle) => {
export const renderAVAttribute = (element: HTMLElement, id: string, protyle: IProtyle, cb?: (element: HTMLElement) => void) => {
fetchPost("/api/av/getAttributeViewKeys", {id}, (response) => {
let html = "";
response.data.forEach((table: {
@ -154,17 +155,15 @@ export const renderAVAttribute = (element: HTMLElement, id: string, protyle: IPr
avName: string
}) => {
html += `<div data-av-id="${table.avID}" data-node-id="${id}" data-type="NodeAttributeView">
<div class="fn__flex custom-attr__avheader">
<div class="block__logo popover__block" data-id='${JSON.stringify(table.blockIDs)}'>
<svg class="block__logoicon"><use xlink:href="#iconDatabase"></use></svg><span>${table.avName || window.siyuan.languages.database}</span>
</div>
<div class="custom-attr__avheader block__logo popover__block" data-id='${JSON.stringify(table.blockIDs)}'>
<div class="fn__flex-1"></div>
<svg class="block__logoicon"><use xlink:href="#iconDatabase"></use></svg><span>${table.avName || window.siyuan.languages.database}</span>
<div class="fn__flex-1"></div>
<button data-type="addColumn" class="b3-button b3-button--outline"><svg><use xlink:href="#iconAdd"></use></svg>${window.siyuan.languages.addAttr}</button>
</div>`;
table.keyValues?.forEach(item => {
html += `<div class="block__icons av__row" data-id="${id}" data-col-id="${item.key.id}">
html += `<div class="block__icons av__row" data-col-id="${item.key.id}">
<div class="block__icon" draggable="true"><svg><use xlink:href="#iconDrag"></use></svg></div>
<div class="block__logo ariaLabel" data-position="parentW" aria-label="${escapeAttr(item.key.name)}"">
<div class="block__logo ariaLabel${item.values[0].type === "block" ? "" : " fn__pointer"}" data-type="editCol" data-position="parentW" aria-label="${escapeAttr(item.key.name)}"">
${item.key.icon ? unicode2Emoji(item.key.icon, "block__logoicon", true) : `<svg class="block__logoicon"><use xlink:href="#${getColIconByType(item.key.type)}"></use></svg>`}
<span>${item.key.name}</span>
</div>
@ -175,7 +174,12 @@ class="fn__flex-1 fn__flex${["url", "text", "number", "email", "phone", "block"]
</div>
</div>`;
});
html += "</div>";
html += `<div class="fn__hr"></div>
<div class="fn__flex">
<div class="fn__flex-1"></div>
<button data-type="addColumn" class="b3-button b3-button--outline"><svg><use xlink:href="#iconAdd"></use></svg>${window.siyuan.languages.addAttr}</button>
<div class="fn__space"></div>
</div></div>`;
});
if (element.innerHTML === "") {
let dragBlockElement: HTMLElement;
@ -203,7 +207,7 @@ class="fn__flex-1 fn__flex${["url", "text", "number", "email", "phone", "block"]
transaction(protyle, [{
action: "sortAttrViewCol",
avID: dragBlockElement.dataset.avId,
previousID:isBottom ? targetElement.dataset.colId : targetElement.previousElementSibling?.getAttribute("data-col-id"),
previousID: isBottom ? targetElement.dataset.colId : targetElement.previousElementSibling?.getAttribute("data-col-id"),
id: window.siyuan.dragElement.dataset.colId,
}, {
action: "sortAttrViewCol",
@ -255,6 +259,10 @@ class="fn__flex-1 fn__flex${["url", "text", "number", "email", "phone", "block"]
});
element.addEventListener("click", (event) => {
let target = event.target as HTMLElement;
const blockElement = hasClosestBlock(target);
if (!blockElement) {
return;
}
while (target && !element.isSameNode(target)) {
const type = target.getAttribute("data-type");
if (type === "date") {
@ -293,7 +301,8 @@ class="fn__flex-1 fn__flex${["url", "text", "number", "email", "phone", "block"]
event.preventDefault();
break;
} else if (type === "addColumn") {
const addMenu = addCol(protyle, hasClosestBlock(target) as HTMLElement, "");
const rowElements = blockElement.querySelectorAll(".av__row")
const addMenu = addCol(protyle, blockElement, rowElements[rowElements.length - 1].getAttribute("data-col-id"));
const addRect = target.getBoundingClientRect();
addMenu.open({
x: addRect.left,
@ -303,6 +312,18 @@ class="fn__flex-1 fn__flex${["url", "text", "number", "email", "phone", "block"]
event.stopPropagation();
event.preventDefault();
break;
} else if (type === "editCol") {
if (target.classList.contains("fn__pointer")) {
openMenuPanel({
protyle,
blockElement,
type: "edit",
colId: target.parentElement.dataset.colId
});
}
event.stopPropagation();
event.preventDefault();
break;
}
target = target.parentElement;
}
@ -334,5 +355,8 @@ class="fn__flex-1 fn__flex${["url", "text", "number", "email", "phone", "block"]
});
});
});
if (cb) {
cb(element);
}
});
};

View file

@ -84,7 +84,8 @@ export const duplicateCol = (options: {
export const getEditHTML = (options: {
protyle: IProtyle,
colId: string,
data: IAV
data: IAV,
isCustomAttr: boolean
}) => {
let colData: IAVColumn;
options.data.view.columns.find((item) => {
@ -94,7 +95,7 @@ export const getEditHTML = (options: {
}
});
let html = `<button class="b3-menu__item" data-type="nobg" data-col-id="${options.colId}">
<span class="block__icon" style="padding: 8px;margin-left: -4px;" data-type="go-properties">
<span class="block__icon${options.isCustomAttr ? " fn__none" : ""}" style="padding: 8px;margin-left: -4px;" data-type="go-properties">
<svg><use xlink:href="#iconLeft"></use></svg>
</span>
<span class="b3-menu__label ft__center">${window.siyuan.languages.edit}</span>
@ -165,7 +166,7 @@ export const getEditHTML = (options: {
return `<div class="b3-menu__items">
${html}
<button class="b3-menu__separator"></button>
<button class="b3-menu__item" data-type="${colData.hidden ? "showCol" : "hideCol"}">
<button class="b3-menu__item${options.isCustomAttr ? " fn__none" : ""}" data-type="${colData.hidden ? "showCol" : "hideCol"}">
<svg class="b3-menu__icon" style=""><use xlink:href="#icon${colData.hidden ? "Eye" : "Eyeoff"}"></use></svg>
<span class="b3-menu__label">${colData.hidden ? window.siyuan.languages.showCol : window.siyuan.languages.hideCol}</span>
</button>
@ -207,7 +208,8 @@ export const getEditHTML = (options: {
export const bindEditEvent = (options: {
protyle: IProtyle,
data: IAV,
menuElement: HTMLElement
menuElement: HTMLElement,
isCustomAttr: boolean
}) => {
const avID = options.data.id;
const colId = options.menuElement.querySelector(".b3-menu__item").getAttribute("data-col-id");
@ -316,8 +318,18 @@ export const bindEditEvent = (options: {
avID,
data: addOptionElement.value
}]);
options.menuElement.innerHTML = getEditHTML({protyle: options.protyle, colId, data: options.data});
bindEditEvent({protyle: options.protyle, menuElement: options.menuElement, data: options.data});
options.menuElement.innerHTML = getEditHTML({
protyle: options.protyle,
colId,
data: options.data,
isCustomAttr: options.isCustomAttr
});
bindEditEvent({
protyle: options.protyle,
menuElement: options.menuElement,
data: options.data,
isCustomAttr: options.isCustomAttr
});
(options.menuElement.querySelector('[data-type="addOption"]') as HTMLInputElement).focus();
}
});

View file

@ -50,6 +50,7 @@ export const openMenuPanel = (options: {
id: avID,
pageSize: parseInt(options.blockElement.getAttribute("data-page-size")) || undefined,
}, (response) => {
const isCustomAttr = !options.blockElement.classList.contains("av");
const data = response.data as IAV;
let html;
if (options.type === "config") {
@ -67,7 +68,7 @@ export const openMenuPanel = (options: {
} else if (options.type === "asset") {
html = getAssetHTML(options.cellElements);
} else if (options.type === "edit") {
html = getEditHTML({protyle: options.protyle, data, colId: options.colId});
html = getEditHTML({protyle: options.protyle, data, colId: options.colId, isCustomAttr});
} else if (options.type === "date") {
html = getDateHTML(data.view, options.cellElements);
} else if (options.type === "rollup") {
@ -75,14 +76,12 @@ export const openMenuPanel = (options: {
} else if (options.type === "relation") {
html = getRelationHTML(data, options.cellElements);
if (!html) {
if (options.blockElement.classList.contains("av")) {
openMenuPanel({
protyle: options.protyle,
blockElement: options.blockElement,
type: "edit",
colId: options.cellElements[0].dataset.colId
});
}
openMenuPanel({
protyle: options.protyle,
blockElement: options.blockElement,
type: "edit",
colId: options.cellElements[0].dataset.colId
});
return;
}
}
@ -93,7 +92,7 @@ export const openMenuPanel = (options: {
</div>`);
avPanelElement = document.querySelector(".av__panel");
const menuElement = avPanelElement.lastElementChild as HTMLElement;
const tabRect = options.blockElement.querySelector(".av__views")?.getBoundingClientRect();
const tabRect = options.blockElement.querySelector(`.av__views, .av__row[data-col-id="${options.colId}"] > .block__logo`)?.getBoundingClientRect();
if (["select", "date", "asset", "relation", "rollup"].includes(options.type)) {
const cellRect = options.cellElements[options.cellElements.length - 1].getBoundingClientRect();
if (options.type === "select") {
@ -135,7 +134,7 @@ export const openMenuPanel = (options: {
if (options.type === "sorts") {
bindSortsEvent(options.protyle, menuElement, data);
} else if (options.type === "edit") {
bindEditEvent({protyle: options.protyle, data, menuElement});
bindEditEvent({protyle: options.protyle, data, menuElement, isCustomAttr});
} else if (options.type === "config") {
bindViewEvent({protyle: options.protyle, data, menuElement});
}
@ -322,9 +321,10 @@ export const openMenuPanel = (options: {
menuElement.innerHTML = getEditHTML({
protyle: options.protyle,
data,
colId
colId,
isCustomAttr
});
bindEditEvent({protyle: options.protyle, data, menuElement});
bindEditEvent({protyle: options.protyle, data, menuElement, isCustomAttr});
}
return;
}
@ -678,7 +678,12 @@ export const openMenuPanel = (options: {
data: target.dataset.icon,
}]);
target.innerHTML = unicode ? unicode2Emoji(unicode) : `<svg><use xlink:href="#${getColIconByType(target.dataset.colType as TAVCol)}"></use></svg>`;
updateAttrViewCellAnimation(options.blockElement.querySelector(`.av__row--header .av__cell[data-col-id="${colId}"]`), undefined, {icon: unicode});
if (isCustomAttr) {
const iconElement = options.blockElement.querySelector(`.av__row[data-col-id="${colId}"] .block__logoicon`)
iconElement.outerHTML = unicode ? unicode2Emoji(unicode, "block__logoicon", true) : `<svg class="block__logoicon"><use xlink:href="#${getColIconByType(iconElement.nextElementSibling.getAttribute("data-type") as TAVCol)}"></use></svg>`;
} else {
updateAttrViewCellAnimation(options.blockElement.querySelector(`.av__row--header .av__cell[data-col-id="${colId}"]`), undefined, {icon: unicode});
}
target.dataset.icon = unicode;
});
event.preventDefault();
@ -744,9 +749,10 @@ export const openMenuPanel = (options: {
menuElement.innerHTML = getEditHTML({
protyle: options.protyle,
data,
colId: target.parentElement.dataset.id
colId: target.parentElement.dataset.id,
isCustomAttr
});
bindEditEvent({protyle: options.protyle, data, menuElement});
bindEditEvent({protyle: options.protyle, data, menuElement, isCustomAttr});
setPosition(menuElement, tabRect.right - menuElement.clientWidth, tabRect.bottom, tabRect.height);
event.preventDefault();
event.stopPropagation();
@ -854,9 +860,10 @@ export const openMenuPanel = (options: {
menuElement.innerHTML = getEditHTML({
protyle: options.protyle,
data,
colId
colId,
isCustomAttr
});
bindEditEvent({protyle: options.protyle, data, menuElement});
bindEditEvent({protyle: options.protyle, data, menuElement, isCustomAttr});
} else {
menuElement.innerHTML = getPropertiesHTML(data.view);
}
@ -883,9 +890,10 @@ export const openMenuPanel = (options: {
menuElement.innerHTML = getEditHTML({
protyle: options.protyle,
data,
colId
colId,
isCustomAttr
});
bindEditEvent({protyle: options.protyle, data, menuElement});
bindEditEvent({protyle: options.protyle, data, menuElement, isCustomAttr});
} else {
menuElement.innerHTML = getPropertiesHTML(data.view);
}
@ -935,7 +943,7 @@ export const openMenuPanel = (options: {
event.stopPropagation();
break;
} else if (type === "setColOption") {
setColOption(options.protyle, data, target, options.blockElement, options.cellElements);
setColOption(options.protyle, data, target, options.blockElement, isCustomAttr, options.cellElements);
event.preventDefault();
event.stopPropagation();
break;

View file

@ -296,12 +296,15 @@ export const refreshAV = (protyle: IProtyle, operation: IOperation) => {
if (operation.action === "addAttrViewCol" && isPulse) {
openMenuPanel({protyle, blockElement: item, type: "edit", colId: operation.id});
}
if (["updateAttrViewColRollup","updateAttrViewColTemplate", "updateAttrViewCell", "addAttrViewCol"].includes(operation.action)) {
const attrElement = document.querySelector(`.b3-dialog--open[data-key="${Constants.DIALOG_ATTR}"] div[data-av-id="${operation.avID}"]`) as HTMLElement;
if (attrElement) {
// 更新属性面板
renderAVAttribute(attrElement.parentElement, attrElement.dataset.nodeId, protyle);
}
const attrElement = document.querySelector(`.b3-dialog--open[data-key="${Constants.DIALOG_ATTR}"] div[data-av-id="${operation.avID}"]`) as HTMLElement;
if (attrElement) {
// 更新属性面板
renderAVAttribute(attrElement.parentElement, attrElement.dataset.nodeId, protyle, (newElment) => {
if (operation.action === "addAttrViewCol") {
openMenuPanel({protyle, blockElement: newElment.querySelector(`div[data-av-id="${operation.avID}"]`), type: "edit", colId: operation.id});
}
});
}
}, ["addAttrViewView", "duplicateAttrViewView"].includes(operation.action) ? operation.id :
(operation.action === "removeAttrViewView" ? null : undefined));

View file

@ -110,7 +110,7 @@ export const removeCellOption = (protyle: IProtyle, data: IAV, cellElements: HTM
target.remove();
};
export const setColOption = (protyle: IProtyle, data: IAV, target: HTMLElement, blockElement: Element, cellElements?: HTMLElement[]) => {
export const setColOption = (protyle: IProtyle, data: IAV, target: HTMLElement, blockElement: Element, isCustomAttr: boolean, cellElements?: HTMLElement[]) => {
const menuElement = hasClosestByClassName(target, "b3-menu");
if (!menuElement) {
return;
@ -168,8 +168,8 @@ export const setColOption = (protyle: IProtyle, data: IAV, target: HTMLElement,
}
});
if (!cellElements) {
menuElement.innerHTML = getEditHTML({protyle, data, colId});
bindEditEvent({protyle, data, menuElement});
menuElement.innerHTML = getEditHTML({protyle, data, colId, isCustomAttr});
bindEditEvent({protyle, data, menuElement, isCustomAttr});
} else {
cellElements.forEach((cellElement: HTMLMediaElement) => {
data.view.rows.find(row => {
@ -246,8 +246,8 @@ export const setColOption = (protyle: IProtyle, data: IAV, target: HTMLElement,
}
});
if (!cellElements) {
menuElement.innerHTML = getEditHTML({protyle, data, colId});
bindEditEvent({protyle, data, menuElement});
menuElement.innerHTML = getEditHTML({protyle, data, colId, isCustomAttr});
bindEditEvent({protyle, data, menuElement, isCustomAttr});
} else {
cellElements.forEach((cellElement: HTMLElement) => {
data.view.rows.find(row => {
@ -325,8 +325,8 @@ export const setColOption = (protyle: IProtyle, data: IAV, target: HTMLElement,
}
});
if (!cellElements) {
menuElement.innerHTML = getEditHTML({protyle, data, colId});
bindEditEvent({protyle, data, menuElement});
menuElement.innerHTML = getEditHTML({protyle, data, colId, isCustomAttr});
bindEditEvent({protyle, data, menuElement, isCustomAttr});
} else {
cellElements.forEach((cellElement: HTMLElement) => {
data.view.rows.find(row => {

View file

@ -722,7 +722,7 @@ export const onTransaction = (protyle: IProtyle, operation: IOperation, isUndo:
"updateAttrViewColOption", "updateAttrViewCell", "sortAttrViewRow", "sortAttrViewCol", "setAttrViewColHidden",
"setAttrViewColWrap", "setAttrViewColWidth", "removeAttrViewColOption", "setAttrViewName", "setAttrViewFilters",
"setAttrViewSorts", "setAttrViewColCalc", "removeAttrViewCol", "updateAttrViewColNumberFormat", "removeAttrViewBlock",
"replaceAttrViewBlock", "updateAttrViewColTemplate", "setAttrViewColPin", "addAttrViewView",
"replaceAttrViewBlock", "updateAttrViewColTemplate", "setAttrViewColPin", "addAttrViewView", "setAttrViewColIcon",
"removeAttrViewView", "setAttrViewViewName", "setAttrViewViewIcon", "duplicateAttrViewView", "sortAttrViewView",
"updateAttrViewColRelation", "setAttrViewPageSize", "updateAttrViewColRollup"].includes(operation.action)) {
refreshAV(protyle, operation);