diff --git a/app/src/protyle/render/av/action.ts b/app/src/protyle/render/av/action.ts index 97bc74e0e..257881b25 100644 --- a/app/src/protyle/render/av/action.ts +++ b/app/src/protyle/render/av/action.ts @@ -110,6 +110,10 @@ export const avClick = (protyle: IProtyle, event: MouseEvent & { target: HTMLEle const cellElement = hasClosestByClassName(event.target, "av__cell"); if (cellElement && !cellElement.parentElement.classList.contains("av__row--header")) { + cellElement.parentElement.parentElement.querySelectorAll(".av__row--select").forEach(item => { + item.querySelector(".av__firstcol use").setAttribute("xlink:href", "#iconUncheck"); + item.classList.remove("av__row--select"); + }); popTextCell(protyle, [cellElement]); event.preventDefault(); event.stopPropagation(); diff --git a/app/src/protyle/render/av/cell.ts b/app/src/protyle/render/av/cell.ts index a3324ac5e..a1cce89c9 100644 --- a/app/src/protyle/render/av/cell.ts +++ b/app/src/protyle/render/av/cell.ts @@ -292,8 +292,7 @@ export const popTextCell = (protyle: IProtyle, cellElements: HTMLElement[]) => { } else if (type === "number") { html = ``; } else if (["select", "mSelect"].includes(type) && blockElement) { - // TODO - openMenuPanel(protyle, blockElement, "select", {cellElement: cellElements[0]}); + openMenuPanel(protyle, blockElement, "select", {cellElements}); return; } window.siyuan.menus.menu.remove(); diff --git a/app/src/protyle/render/av/openMenuPanel.ts b/app/src/protyle/render/av/openMenuPanel.ts index 118ee2c1a..82821574d 100644 --- a/app/src/protyle/render/av/openMenuPanel.ts +++ b/app/src/protyle/render/av/openMenuPanel.ts @@ -44,7 +44,7 @@ export const openMenuPanel = (protyle: IProtyle, const menuElement = avPanelElement.lastElementChild as HTMLElement; const tabRect = blockElement.querySelector(".layout-tab-bar").getBoundingClientRect(); if (type === "select") { - const cellRect = options.cellElement.getBoundingClientRect(); + const cellRect = options.cellElements[options.cellElements.length - 1].getBoundingClientRect(); setPosition(menuElement, cellRect.left, cellRect.bottom, cellRect.height); bindSelectEvent(protyle, data, menuElement, options); menuElement.querySelector("input").select(); @@ -82,7 +82,8 @@ export const openMenuPanel = (protyle: IProtyle, } else if (targetElement.querySelector('[data-type="removeFilter"]')) { type = "filters"; } else if (targetElement.querySelector('[data-type="setSelectCol"]')) { - const changeData = data.view.columns.find((column) => column.id === options.cellElement.dataset.colId).options; + const colId = options.cellElements[0].dataset.colId; + const changeData = data.view.columns.find((column) => column.id === colId).options; const oldData = Object.assign([], changeData); let targetOption: { name: string, color: string }; changeData.find((option, index: number) => { @@ -103,12 +104,12 @@ export const openMenuPanel = (protyle: IProtyle, }); transaction(protyle, [{ action: "updateAttrViewColOptions", - id: options.cellElement.dataset.colId, + id: colId, avID: data.id, data: changeData, }], [{ action: "updateAttrViewColOptions", - id: options.cellElement.dataset.colId, + id: colId, avID: data.id, data: oldData, }]); diff --git a/app/src/protyle/render/av/select.ts b/app/src/protyle/render/av/select.ts index 4311bc806..326443c52 100644 --- a/app/src/protyle/render/av/select.ts +++ b/app/src/protyle/render/av/select.ts @@ -43,66 +43,62 @@ const filterSelectHTML = (key: string, options: { name: string, color: string }[ }; export const removeSelectCell = (protyle: IProtyle, data: IAV, options: { - cellElement: HTMLElement + cellElements: HTMLElement[] }, target: HTMLElement) => { if (!target) { return; } - const rowID = options.cellElement.parentElement.dataset.id; - const colId = options.cellElement.dataset.colId; - const cellId = options.cellElement.dataset.id; - let colData: IAVColumn; - data.view.columns.find((item: IAVColumn) => { - if (item.id === colId) { - colData = item; - return; - } - }); - if (!colData.options) { - colData.options = []; - } - let cellData: IAVCell; - data.view.rows.find(row => { - if (row.id === rowID) { - row.cells.find(cell => { - if (cell.id === cellId) { - cellData = cell; - return true; - } - }); - return true; - } - }); - const oldValue = Object.assign([], cellData.value.mSelect); - cellData.value.mSelect?.find((item: { content: string }, index: number) => { - if (item.content === target.dataset.content) { - cellData.value.mSelect.splice(index, 1); - return true; - } - }); - target.remove(); + const colId = options.cellElements[0].dataset.colId; + const doOperations: IOperation[] = [] + const undoOperations: IOperation[] = [] + options.cellElements.forEach(item => { + const rowID = item.parentElement.dataset.id; + const cellId = item.dataset.id; + let cellData: IAVCell; + data.view.rows.find(row => { + if (row.id === rowID) { + row.cells.find(cell => { + if (cell.id === cellId) { + cellData = cell; + return true; + } + }); + return true; + } + }); + const oldValue = Object.assign([], cellData.value.mSelect); + cellData.value.mSelect?.find((item: { content: string }, index: number) => { + if (item.content === target.dataset.content) { + cellData.value.mSelect.splice(index, 1); + return true; + } + }); - transaction(protyle, [{ - action: "updateAttrViewCell", - id: cellId, - keyID: colId, - rowID, - avID: data.id, - data: cellData.value - }], [{ - action: "updateAttrViewCell", - id: cellId, - keyID: colId, - rowID, - avID: data.id, - data: { - [colData.type]: oldValue - } - }]); + doOperations.push({ + action: "updateAttrViewCell", + id: cellId, + keyID: colId, + rowID, + avID: data.id, + data: cellData.value + }) + undoOperations.push({ + action: "updateAttrViewCell", + id: cellId, + keyID: colId, + rowID, + avID: data.id, + data: { + mSelect: oldValue + } + }) + }) + transaction(protyle, doOperations, undoOperations); + target.remove(); }; export const setSelectCol = (protyle: IProtyle, data: IAV, options: { - cellElement: HTMLElement; + cellElements: HTMLElement[]; }, target: HTMLElement,) => { const menuElement = hasClosestByClassName(target, "b3-menu"); if (!menuElement) { @@ -145,9 +141,9 @@ export const setSelectCol = (protyle: IProtyle, data: IAV, options: { } }); data.view.rows.find(row => { - if (row.id === options.cellElement.parentElement.dataset.id) { + if (row.id === options.cellElements[0].parentElement.dataset.id) { row.cells.find(cell => { - if (cell.id === options.cellElement.dataset.id) { + if (cell.id === options.cellElements[0].dataset.id) { cell.value.mSelect.find((item) => { if (item.content === name) { item.content = inputElement.value; @@ -166,7 +162,7 @@ export const setSelectCol = (protyle: IProtyle, data: IAV, options: { if (menu.isOpen) { return; } - const colId = options.cellElement.dataset.colId; + const colId = options.cellElements[0].dataset.colId; menu.addItem({ iconHTML: "", label: `` @@ -202,9 +198,9 @@ export const setSelectCol = (protyle: IProtyle, data: IAV, options: { } }); data.view.rows.find(row => { - if (row.id === options.cellElement.parentElement.dataset.id) { + if (row.id === options.cellElements[0].parentElement.dataset.id) { row.cells.find(cell => { - if (cell.id === options.cellElement.dataset.id) { + if (cell.id === options.cellElements[0].dataset.id) { cell.value.mSelect.find((item, index) => { if (item.content === newName) { cell.value.mSelect.splice(index, 1); @@ -269,9 +265,9 @@ export const setSelectCol = (protyle: IProtyle, data: IAV, options: { } }); data.view.rows.find(row => { - if (row.id === options.cellElement.parentElement.dataset.id) { + if (row.id === options.cellElements[0].parentElement.dataset.id) { row.cells.find(cell => { - if (cell.id === options.cellElement.dataset.id) { + if (cell.id === options.cellElements[0].dataset.id) { cell.value.mSelect.find((item) => { if (item.content === name) { item.content = inputElement.value; @@ -305,10 +301,10 @@ export const setSelectCol = (protyle: IProtyle, data: IAV, options: { }; export const bindSelectEvent = (protyle: IProtyle, data: IAV, menuElement: HTMLElement, options: { - cellElement: HTMLElement + cellElements: HTMLElement[] }) => { const inputElement = menuElement.querySelector("input"); - const colId = options.cellElement.dataset.colId; + const colId = options.cellElements[0].dataset.colId; let colData: IAVColumn; data.view.columns.find((item: IAVColumn) => { if (item.id === colId) { @@ -350,13 +346,24 @@ export const bindSelectEvent = (protyle: IProtyle, data: IAV, menuElement: HTMLE }; export const addSelectColAndCell = (protyle: IProtyle, data: IAV, options: { - cellElement: HTMLElement + cellElements: HTMLElement[] }, currentElement: HTMLElement, menuElement: HTMLElement) => { - const rowID = options.cellElement.parentElement.dataset.id; - const colId = options.cellElement.dataset.colId; + let hasSelected = false; + Array.from(menuElement.querySelectorAll(".b3-chips .b3-chip")).find((item: HTMLElement) => { + if (item.dataset.content === currentElement.dataset.name) { + hasSelected = true; + return true; + } + }) + if (hasSelected) { + menuElement.querySelector("input").focus(); + return; + } + + const colId = options.cellElements[0].dataset.colId; let cellIndex = 0; - Array.from(options.cellElement.parentElement.querySelectorAll(".av__cell")).find((item: HTMLElement, index) => { - if (item.dataset.id === options.cellElement.dataset.id) { + Array.from(options.cellElements[0].parentElement.querySelectorAll(".av__cell")).find((item: HTMLElement, index) => { + if (item.dataset.id === options.cellElements[0].dataset.id) { cellIndex = index; return true; } @@ -365,82 +372,60 @@ export const addSelectColAndCell = (protyle: IProtyle, data: IAV, options: { data.view.columns.find((item: IAVColumn) => { if (item.id === colId) { colData = item; + if (!colData.options) { + colData.options = []; + } return; } }); - if (!colData.options) { - colData.options = []; - } - let cellData: IAVCell; - data.view.rows.find(row => { - if (row.id === rowID) { - cellData = row.cells[cellIndex]; - // 为空时 cellId 每次请求都不一致 - cellData.id = options.cellElement.dataset.id; - if (!cellData.value || !cellData.value.mSelect) { - cellData.value = {mSelect: []} as IAVCellValue; + + const cellDoOperations: IOperation[] = [] + const cellUndoOperations: IOperation[] = [] + options.cellElements.forEach(item => { + let cellData: IAVCell; + const rowID = item.parentElement.dataset.id; + data.view.rows.find(row => { + if (row.id === rowID) { + cellData = row.cells[cellIndex]; + // 为空时 cellId 每次请求都不一致 + cellData.id = item.dataset.id; + if (!cellData.value || !cellData.value.mSelect) { + cellData.value = {mSelect: []} as IAVCellValue; + } + return true; } - return true; - } - }); - - let hasSelected = false; - cellData.value.mSelect.find((item) => { - if (item.content === currentElement.dataset.name) { - hasSelected = true; - return true; - } - }); - if (hasSelected) { - menuElement.querySelector("input").focus(); - return; - } - - const oldValue = Object.assign([], cellData.value.mSelect); - if (colData.type === "mSelect") { - cellData.value.mSelect.push({ - color: currentElement.dataset.color, - content: currentElement.dataset.name }); - } else { - cellData.value.mSelect = [{ - color: currentElement.dataset.color, - content: currentElement.dataset.name - }]; - } - if (currentElement.querySelector(".b3-menu__accelerator")) { - colData.options.push({ - color: currentElement.dataset.color, - name: currentElement.dataset.name - }); - transaction(protyle, [{ - action: "updateAttrViewColOptions", - id: colId, - avID: data.id, - data: colData.options - }, { + const oldValue = Object.assign([], cellData.value.mSelect); + if (colData.type === "mSelect") { + let hasOption = false; + cellData.value.mSelect.find((item) => { + if (item.content === currentElement.dataset.name) { + hasOption = true + return true + } + }); + if (!hasOption) { + cellData.value.mSelect.push({ + color: currentElement.dataset.color, + content: currentElement.dataset.name + }); + } + } else { + cellData.value.mSelect = [{ + color: currentElement.dataset.color, + content: currentElement.dataset.name + }]; + } + cellDoOperations.push({ action: "updateAttrViewCell", id: cellData.id, keyID: colId, rowID, avID: data.id, data: cellData.value - }], [{ - action: "removeAttrViewColOption", - id: colId, - avID: data.id, - data: currentElement.dataset.name, - }]); - } else { - transaction(protyle, [{ - action: "updateAttrViewCell", - id: cellData.id, - keyID: colId, - rowID, - avID: data.id, - data: cellData.value - }], [{ + }) + cellUndoOperations.push({ action: "updateAttrViewCell", id: cellData.id, keyID: colId, @@ -449,7 +434,28 @@ export const addSelectColAndCell = (protyle: IProtyle, data: IAV, options: { data: { [colData.type]: oldValue } + }) + }) + + if (currentElement.querySelector(".b3-menu__accelerator")) { + colData.options.push({ + color: currentElement.dataset.color, + name: currentElement.dataset.name + }); + cellDoOperations.splice(0, 0, { + action: "updateAttrViewColOptions", + id: colId, + avID: data.id, + data: colData.options + }) + transaction(protyle, cellDoOperations, [{ + action: "removeAttrViewColOption", + id: colId, + avID: data.id, + data: currentElement.dataset.name, }]); + } else { + transaction(protyle, cellDoOperations, cellUndoOperations); } if (colData.type === "select") { menuElement.parentElement.remove(); @@ -460,28 +466,58 @@ export const addSelectColAndCell = (protyle: IProtyle, data: IAV, options: { } }; -export const getSelectHTML = (data: IAVTable, options: { cellElement: HTMLElement }) => { - const cellId = options.cellElement.dataset.id; - const colId = options.cellElement.dataset["colId"]; +export const getSelectHTML = (data: IAVTable, options: { cellElements: HTMLElement[] }) => { + const colId = options.cellElements[0].dataset["colId"]; const colData = data.columns.find(item => { if (item.id === colId) { return item; } }); + + const commonOptions: { content: string, color: string }[][] = [] + const allUniqueOptions: { content: string, color: string }[] = [] + options.cellElements.forEach((cellElement) => { + data.rows.find(row => { + if (cellElement.parentElement.dataset.id === row.id) { + const commonOption: { content: string, color: string }[] = [] + row.cells.find(cell => { + if (cell.id === cellElement.dataset.id) { + if (cell.value && cell.value.mSelect) { + cell.value.mSelect.forEach((item: { content: string, color: string }) => { + commonOption.push(item) + allUniqueOptions.push(item) + }); + } + return true; + } + }); + commonOptions.push(commonOption) + return true; + } + }); + }); + let selectedHTML = ""; - data.rows.find(row => { - if (options.cellElement.parentElement.dataset.id === row.id) { - row.cells.find(cell => { - if (cell.id === cellId && cell.value) { - cell.value.mSelect?.forEach((item: { content: string, color: string }) => { - selectedHTML += `
${item.content}
`; - }); + allUniqueOptions.forEach((unique) => { + let everyRowHas = true + commonOptions.find(item => { + let hasContent = false + item.find((option) => { + if (option.content === unique.content) { + hasContent = true return true; } - }); - return true; + }) + if (!hasContent) { + everyRowHas = false + return true + } + }) + if (everyRowHas && selectedHTML.indexOf(`data-content="${unique.content}"`) === -1) { + selectedHTML += `
${unique.content}
`; } }); + return `
${selectedHTML}