diff --git a/app/src/block/popover.ts b/app/src/block/popover.ts
index ba917e5e3..ec287d47f 100644
--- a/app/src/block/popover.ts
+++ b/app/src/block/popover.ts
@@ -28,12 +28,7 @@ export const initBlockPopover = (app: App) => {
let tooltipClass = "";
let tip = aElement.getAttribute("aria-label");
if (aElement.classList.contains("av__cell")) {
- if (aElement.classList.contains("av__cell--header")) {
- const textElement = aElement.querySelector(".av__celltext");
- if (textElement.scrollWidth > textElement.clientWidth + 2) {
- tip = getCellText(aElement);
- }
- } else {
+ if (!aElement.classList.contains("av__cell--header")) {
if (aElement.firstElementChild?.getAttribute("data-type") === "url") {
if (aElement.firstElementChild.textContent.indexOf("...") > -1) {
tip = Lute.EscapeHTMLStr(aElement.firstElementChild.getAttribute("data-href"));
diff --git a/app/src/protyle/render/av/col.ts b/app/src/protyle/render/av/col.ts
index 58d1db549..b653ac93d 100644
--- a/app/src/protyle/render/av/col.ts
+++ b/app/src/protyle/render/av/col.ts
@@ -15,6 +15,7 @@ import * as dayjs from "dayjs";
import {setPosition} from "../../../util/setPosition";
import {duplicateNameAddOne} from "../../../util/functions";
import {Dialog} from "../../../dialog";
+import {escapeAttr} from "../../../util/escape";
export const duplicateCol = (options: {
protyle: IProtyle,
@@ -575,35 +576,60 @@ export const showColMenu = (protyle: IProtyle, blockElement: Element, cellElemen
const avID = blockElement.getAttribute("data-av-id");
const blockID = blockElement.getAttribute("data-node-id");
const oldValue = cellElement.querySelector(".av__celltext").textContent.trim();
+ const oldDesc = cellElement.dataset.desc;
const menu = new Menu("av-header-cell", () => {
const newValue = (menu.element.querySelector(".b3-text-field") as HTMLInputElement).value;
- if (newValue === oldValue) {
- return;
+ if (newValue !== oldValue) {
+ transaction(protyle, [{
+ action: "updateAttrViewCol",
+ id: colId,
+ avID,
+ name: newValue,
+ type,
+ }], [{
+ action: "updateAttrViewCol",
+ id: colId,
+ avID,
+ name: oldValue,
+ type,
+ }]);
+ updateAttrViewCellAnimation(blockElement.querySelector(`.av__row--header .av__cell[data-col-id="${colId}"]`), undefined, {name: newValue});
+ }
+ const newDesc = menu.element.querySelector("textarea").value;
+ if (newDesc !== oldDesc) {
+ transaction(protyle, [{
+ action: "setAttrViewColDesc",
+ id: colId,
+ avID,
+ data: newDesc,
+ }], [{
+ action: "setAttrViewColDesc",
+ id: colId,
+ avID,
+ data: oldDesc,
+ }]);
}
- transaction(protyle, [{
- action: "updateAttrViewCol",
- id: colId,
- avID,
- name: newValue,
- type,
- }], [{
- action: "updateAttrViewCol",
- id: colId,
- avID,
- name: oldValue,
- type,
- }]);
- updateAttrViewCellAnimation(blockElement.querySelector(`.av__row--header .av__cell[data-col-id="${colId}"]`), undefined, {name: newValue});
// https://github.com/siyuan-note/siyuan/issues/9862
focusBlock(blockElement);
});
menu.addItem({
- iconHTML: ``,
+ iconHTML: '',
type: "readonly",
- label: ``,
+ label: `
`,
bind(element) {
const iconElement = element.querySelector(".b3-menu__avemoji") as HTMLElement;
- iconElement.setAttribute("data-icon", cellElement.dataset.icon);
iconElement.addEventListener("click", (event) => {
const rect = iconElement.getBoundingClientRect();
openEmojiPanel("", "av", {
@@ -623,14 +649,32 @@ export const showColMenu = (protyle: IProtyle, blockElement: Element, cellElemen
avID,
data: cellElement.dataset.icon,
}]);
- iconElement.setAttribute("data-icon", unicode);
+ iconElement.dataset.icon = unicode;
iconElement.innerHTML = unicode ? unicode2Emoji(unicode) : ``;
updateAttrViewCellAnimation(blockElement.querySelector(`.av__row--header .av__cell[data-col-id="${colId}"]`), undefined, {icon: unicode});
}, iconElement.querySelector("img"));
event.preventDefault();
event.stopPropagation();
});
- element.querySelector("input").addEventListener("keydown", (event: KeyboardEvent) => {
+ const inputElement = element.querySelector("input");
+ inputElement.addEventListener("keydown", (event: KeyboardEvent) => {
+ if (event.isComposing) {
+ return;
+ }
+ if (event.key === "Enter") {
+ menu.close();
+ event.preventDefault();
+ }
+ });
+ const descElement = element.querySelector('textarea');
+ inputElement.nextElementSibling.addEventListener("click", () => {
+ const descPanelElement = descElement.parentElement
+ descPanelElement.classList.toggle("fn__none");
+ if (!descPanelElement.classList.contains("fn__none")) {
+ descElement.focus();
+ }
+ })
+ descElement.addEventListener("keydown", (event: KeyboardEvent) => {
if (event.isComposing) {
return;
}
diff --git a/app/src/protyle/render/av/render.ts b/app/src/protyle/render/av/render.ts
index 8cbe910eb..1559d14bc 100644
--- a/app/src/protyle/render/av/render.ts
+++ b/app/src/protyle/render/av/render.ts
@@ -10,6 +10,7 @@ import {getCalcValue} from "./calc";
import {renderAVAttribute} from "./blockAttr";
import {showMessage} from "../../../dialog/message";
import {addClearButton} from "../../../util/addClearButton";
+import {escapeAriaLabel, escapeAttr, escapeHtml} from "../../../util/escape";
export const avRender = (element: Element, protyle: IProtyle, cb?: () => void, viewID?: string) => {
let avElements: Element[] = [];
@@ -130,11 +131,13 @@ export const avRender = (element: Element, protyle: IProtyle, cb?: () => void, v
if (column.hidden) {
return;
}
- tableHTML += ``;
@@ -199,9 +202,9 @@ ${cell.color ? `color:${cell.color};` : ""}">${renderCell(cell.value, rowIndex)}
let tabHTML = "";
let viewData: IAVView;
response.data.views.forEach((item: IAVView) => {
- tabHTML += `" class="ariaLabel item${item.id === response.data.viewID ? " item--focus" : ""}">
+ tabHTML += `
" class="ariaLabel item${item.id === response.data.viewID ? " item--focus" : ""}">
${item.icon ? unicode2Emoji(item.icon, "item__graphic", true) : ''}
- ${item.name}
+ ${escapeHtml(item.name)}
`;
if (item.id === response.data.viewID) {
viewData = item;
diff --git a/app/src/protyle/render/av/view.ts b/app/src/protyle/render/av/view.ts
index 22dd0e8e3..2d24a8065 100644
--- a/app/src/protyle/render/av/view.ts
+++ b/app/src/protyle/render/av/view.ts
@@ -6,6 +6,7 @@ import {focusBlock} from "../../util/selection";
import {Constants} from "../../../constants";
import {upDownHint} from "../../../util/upDownHint";
import {avRender} from "./render";
+import {escapeAriaLabel, escapeAttr} from "../../../util/escape";
export const openViewMenu = (options: { protyle: IProtyle, blockElement: HTMLElement, element: HTMLElement }) => {
if (options.protyle.disabled) {
@@ -120,9 +121,13 @@ export const bindViewEvent = (options: {
}
});
inputElement.select();
- const descElement = options.menuElement.querySelector('.b3-text-field[data-type="desc"]') as HTMLInputElement;
+ const descElement = options.menuElement.querySelector('.b3-text-field[data-type="desc"]') as HTMLTextAreaElement;
inputElement.nextElementSibling.addEventListener("click", () => {
- descElement.parentElement.classList.toggle("fn__none");
+ const descPanelElement = descElement.parentElement
+ descPanelElement.classList.toggle("fn__none");
+ if (!descPanelElement.classList.contains("fn__none")) {
+ descElement.focus();
+ }
})
descElement.addEventListener("blur", () => {
if (descElement.value !== descElement.dataset.value) {
@@ -196,14 +201,14 @@ export const getViewHTML = (data: IAV) => {
diff --git a/app/src/protyle/wysiwyg/transaction.ts b/app/src/protyle/wysiwyg/transaction.ts
index 6732a78fa..b9a38a450 100644
--- a/app/src/protyle/wysiwyg/transaction.ts
+++ b/app/src/protyle/wysiwyg/transaction.ts
@@ -743,7 +743,7 @@ export const onTransaction = (protyle: IProtyle, operation: IOperation, isUndo:
"replaceAttrViewBlock", "updateAttrViewColTemplate", "setAttrViewColPin", "addAttrViewView", "setAttrViewColIcon",
"removeAttrViewView", "setAttrViewViewName", "setAttrViewViewIcon", "duplicateAttrViewView", "sortAttrViewView",
"updateAttrViewColRelation", "setAttrViewPageSize", "updateAttrViewColRollup", "sortAttrViewKey",
- "duplicateAttrViewKey", "setAttrViewViewDesc"].includes(operation.action)) {
+ "duplicateAttrViewKey", "setAttrViewViewDesc", "setAttrViewColDesc"].includes(operation.action)) {
refreshAV(protyle, operation);
return;
}
diff --git a/app/src/types/index.d.ts b/app/src/types/index.d.ts
index a2ee8c0c9..defcbeb53 100644
--- a/app/src/types/index.d.ts
+++ b/app/src/types/index.d.ts
@@ -54,6 +54,7 @@ type TOperation =
| "setAttrViewColDate"
| "unbindAttrViewBlock"
| "setAttrViewViewDesc"
+ | "setAttrViewColDesc"
type TBazaarType = "templates" | "icons" | "widgets" | "themes" | "plugins"
type TCardType = "doc" | "notebook" | "all"
type TEventBus = "ws-main" | "sync-start" | "sync-end" | "sync-fail" |
@@ -799,6 +800,7 @@ interface IAVColumn {
icon: string,
id: string,
name: string,
+ desc: string,
wrap: boolean,
pin: boolean,
hidden: boolean,