This commit is contained in:
Vanessa 2023-09-24 17:53:28 +08:00
parent 17055347db
commit 435ad45cb5
14 changed files with 258 additions and 186 deletions

View file

@ -149,7 +149,7 @@ export const openFileWechatNotify = (protyle: IProtyle) => {
}); });
}; };
export const openFileAttr = (attrs: IObject, focusName = "bookmark") => { export const openFileAttr = (attrs: IObject, focusName = "bookmark", protyle?: IProtyle) => {
let customHTML = ""; let customHTML = "";
let notifyHTML = ""; let notifyHTML = "";
let hasAV = false; let hasAV = false;
@ -187,7 +187,7 @@ export const openFileAttr = (attrs: IObject, focusName = "bookmark") => {
<span class="item__text">${window.siyuan.languages.builtIn}</span> <span class="item__text">${window.siyuan.languages.builtIn}</span>
<span class="fn__flex-1"></span> <span class="fn__flex-1"></span>
</div> </div>
<div class="item item--full${hasAV ? "" : " fn__none"}" data-type="av"> <div class="item item--full${hasAV ? "" : " fn__none"}" data-type="NodeAttributeView">
<span class="fn__flex-1"></span> <span class="fn__flex-1"></span>
<span class="item__text">${window.siyuan.languages.database}</span> <span class="item__text">${window.siyuan.languages.database}</span>
<span class="fn__flex-1"></span> <span class="fn__flex-1"></span>
@ -225,7 +225,7 @@ export const openFileAttr = (attrs: IObject, focusName = "bookmark") => {
</label> </label>
${notifyHTML} ${notifyHTML}
</div> </div>
<div data-type="av" class="fn__none custom-attr"></div> <div data-type="NodeAttributeView" class="fn__none custom-attr" data-av-id="${attrs["custom-avs"]}" data-node-id="${attrs.id}"></div>
<div data-type="custom" class="fn__none custom-attr"> <div data-type="custom" class="fn__none custom-attr">
${customHTML} ${customHTML}
<div class="b3-label"> <div class="b3-label">
@ -252,8 +252,8 @@ export const openFileAttr = (attrs: IObject, focusName = "bookmark") => {
target.classList.add("item--focus"); target.classList.add("item--focus");
dialog.element.querySelectorAll(".custom-attr").forEach((item: HTMLElement) => { dialog.element.querySelectorAll(".custom-attr").forEach((item: HTMLElement) => {
if (item.dataset.type === target.dataset.type) { if (item.dataset.type === target.dataset.type) {
if (item.dataset.type === "av" && item.innerHTML === "") { if (item.dataset.type === "NodeAttributeView" && item.innerHTML === "") {
renderAVAttribute(item, attrs.id); renderAVAttribute(item, attrs.id, protyle);
} }
item.classList.remove("fn__none"); item.classList.remove("fn__none");
} else { } else {
@ -349,13 +349,13 @@ export const openFileAttr = (attrs: IObject, focusName = "bookmark") => {
}); });
}; };
export const openAttr = (nodeElement: Element, focusName = "bookmark") => { export const openAttr = (nodeElement: Element, focusName = "bookmark", protyle?: IProtyle) => {
if (nodeElement.getAttribute("data-type") === "NodeThematicBreak") { if (nodeElement.getAttribute("data-type") === "NodeThematicBreak") {
return; return;
} }
const id = nodeElement.getAttribute("data-node-id"); const id = nodeElement.getAttribute("data-node-id");
fetchPost("/api/attr/getBlockAttrs", {id}, (response) => { fetchPost("/api/attr/getBlockAttrs", {id}, (response) => {
openFileAttr(response.data, focusName); openFileAttr(response.data, focusName, protyle);
}); });
}; };

View file

@ -88,7 +88,7 @@ export class Breadcrumb {
fetchPost("/api/block/getDocInfo", { fetchPost("/api/block/getDocInfo", {
id: protyle.block.rootID id: protyle.block.rootID
}, (response) => { }, (response) => {
openFileAttr(response.data.ial); openFileAttr(response.data.ial, "bookmark", protyle);
}); });
} else { } else {
const targetRect = target.getBoundingClientRect(); const targetRect = target.getBoundingClientRect();

View file

@ -211,7 +211,7 @@ export class Gutter {
} }
foldElement.classList.remove("protyle-wysiwyg--hl"); foldElement.classList.remove("protyle-wysiwyg--hl");
} else if (window.siyuan.shiftIsPressed && !protyle.disabled) { } else if (window.siyuan.shiftIsPressed && !protyle.disabled) {
openAttr(protyle.wysiwyg.element.querySelector(`[data-node-id="${id}"]`)); openAttr(protyle.wysiwyg.element.querySelector(`[data-node-id="${id}"]`), "bookmark", protyle);
} else { } else {
this.renderMenu(protyle, buttonElement); this.renderMenu(protyle, buttonElement);
// https://ld246.com/article/1648433751993 // https://ld246.com/article/1648433751993
@ -1478,7 +1478,7 @@ export class Gutter {
icon: "iconAttr", icon: "iconAttr",
accelerator: window.siyuan.config.keymap.editor.general.attr.custom + "/" + updateHotkeyTip("⇧Click"), accelerator: window.siyuan.config.keymap.editor.general.attr.custom + "/" + updateHotkeyTip("⇧Click"),
click() { click() {
openAttr(nodeElement); openAttr(nodeElement, "bookmark", protyle);
} }
}).element); }).element);
} }

View file

@ -140,7 +140,7 @@ export class Title {
fetchPost("/api/block/getDocInfo", { fetchPost("/api/block/getDocInfo", {
id: protyle.block.rootID id: protyle.block.rootID
}, (response) => { }, (response) => {
openFileAttr(response.data.ial); openFileAttr(response.data.ial, "bookmark", protyle);
}); });
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
@ -179,7 +179,7 @@ export class Title {
fetchPost("/api/block/getDocInfo", { fetchPost("/api/block/getDocInfo", {
id: protyle.block.rootID id: protyle.block.rootID
}, (response) => { }, (response) => {
openFileAttr(response.data.ial); openFileAttr(response.data.ial, "bookmark", protyle);
}); });
} else { } else {
const iconRect = iconElement.getBoundingClientRect(); const iconRect = iconElement.getBoundingClientRect();

View file

@ -92,7 +92,7 @@ export const openTitleMenu = (protyle: IProtyle, position: {
icon: "iconAttr", icon: "iconAttr",
accelerator: window.siyuan.config.keymap.editor.general.attr.custom + "/" + updateHotkeyTip("⇧Click"), accelerator: window.siyuan.config.keymap.editor.general.attr.custom + "/" + updateHotkeyTip("⇧Click"),
click() { click() {
openFileAttr(response.data.ial); openFileAttr(response.data.ial, "bookmark", protyle);
} }
}).element); }).element);
window.siyuan.menus.menu.append(new MenuItem({ window.siyuan.menus.menu.append(new MenuItem({

View file

@ -10,6 +10,7 @@ import {MenuItem} from "../../../menus/Menu";
import {exportAsset} from "../../../menus/util"; import {exportAsset} from "../../../menus/util";
import {setPosition} from "../../../util/setPosition"; import {setPosition} from "../../../util/setPosition";
import {previewImage} from "../../preview/image"; import {previewImage} from "../../preview/image";
import {genAVValueHTML} from "./blockAttr";
export const bindAssetEvent = (options: { export const bindAssetEvent = (options: {
protyle: IProtyle, protyle: IProtyle,
@ -104,14 +105,13 @@ export const updateAssetCell = (options: {
addUpdateValue?: IAVCellAssetValue[], addUpdateValue?: IAVCellAssetValue[],
removeContent?: string removeContent?: string
}) => { }) => {
let cellIndex = 0; let cellIndex: number;
Array.from(options.cellElements[0].parentElement.querySelectorAll(".av__cell")).find((item: HTMLElement, index) => { Array.from(options.cellElements[0].parentElement.querySelectorAll(".av__cell")).find((item: HTMLElement, index) => {
if (item.dataset.id === options.cellElements[0].dataset.id) { if (item.dataset.id === options.cellElements[0].dataset.id) {
cellIndex = index; cellIndex = index;
return true; return true;
} }
}); });
const colId = options.cellElements[0].dataset.colId; const colId = options.cellElements[0].dataset.colId;
const cellDoOperations: IOperation[] = []; const cellDoOperations: IOperation[] = [];
const cellUndoOperations: IOperation[] = []; const cellUndoOperations: IOperation[] = [];
@ -121,11 +121,19 @@ export const updateAssetCell = (options: {
const rowID = item.parentElement.dataset.id; const rowID = item.parentElement.dataset.id;
options.data.view.rows.find(row => { options.data.view.rows.find(row => {
if (row.id === rowID) { if (row.id === rowID) {
cellData = row.cells[cellIndex]; if (typeof cellIndex === "number") {
// 为空时 cellId 每次请求都不一致 cellData = row.cells[cellIndex];
cellData.id = item.dataset.id; // 为空时 cellId 每次请求都不一致
if (!cellData.value || !cellData.value.mAsset) { cellData.id = item.dataset.id;
cellData.value = {mAsset: []} as IAVCellValue; if (!cellData.value || !cellData.value.mAsset) {
cellData.value = {mAsset: []} as IAVCellValue;
}
} else {
cellData = row.cells.find(cellItem => {
if (cellItem.id === item.dataset.id) {
return true;
}
});
} }
return true; return true;
} }
@ -188,14 +196,18 @@ export const updateAssetCell = (options: {
mAsset: oldValue mAsset: oldValue
} }
}); });
updateAttrViewCellAnimation(item); if (item.classList.contains("custom-attr__avvalue")) {
item.innerHTML = genAVValueHTML(cellData.value)
} else {
updateAttrViewCellAnimation(item);
}
}); });
transaction(options.protyle, cellDoOperations, cellUndoOperations); transaction(options.protyle, cellDoOperations, cellUndoOperations);
const menuElement = document.querySelector(".av__panel > .b3-menu") as HTMLElement; const menuElement = document.querySelector(".av__panel > .b3-menu") as HTMLElement;
if (menuElement) { if (menuElement) {
menuElement.innerHTML = getAssetHTML(options.data.view, options.cellElements); menuElement.innerHTML = getAssetHTML(options.data.view, options.cellElements);
bindAssetEvent({protyle: options.protyle, data: options.data, menuElement, cellElements: options.cellElements}); bindAssetEvent({protyle: options.protyle, data: options.data, menuElement, cellElements: options.cellElements});
const cellRect = options.protyle.wysiwyg.element.querySelector(`.av__cell[data-id="${options.cellElements[0].dataset.id}"]`).getBoundingClientRect(); const cellRect = (options.cellElements[0].classList.contains("custom-attr__avvalue") ? options.cellElements[0] : options.protyle.wysiwyg.element.querySelector(`.av__cell[data-id="${options.cellElements[0].dataset.id}"]`)).getBoundingClientRect();
setTimeout(() => { setTimeout(() => {
setPosition(menuElement, cellRect.left, cellRect.bottom, cellRect.height); setPosition(menuElement, cellRect.left, cellRect.bottom, cellRect.height);
}, Constants.TIMEOUT_LOAD); // 等待图片加载 }, Constants.TIMEOUT_LOAD); // 等待图片加载
@ -251,7 +263,7 @@ export const editAssetItem = (protyle: IProtyle, data: IAV, cellElements: HTMLEl
}); });
} }
}); });
openMenu(protyle.app, linkAddress, false, true); openMenu(protyle ? protyle.app : window.siyuan.ws.app, linkAddress, false, true);
/// #if !BROWSER /// #if !BROWSER
if (linkAddress?.startsWith("assets/")) { if (linkAddress?.startsWith("assets/")) {
window.siyuan.menus.menu.append(new MenuItem(exportAsset(linkAddress)).element); window.siyuan.menus.menu.append(new MenuItem(exportAsset(linkAddress)).element);
@ -302,7 +314,7 @@ export const addAssetLink = (protyle: IProtyle, data: IAV, cellElements: HTMLEle
const rect = target.getBoundingClientRect(); const rect = target.getBoundingClientRect();
menu.open({ menu.open({
x: rect.right, x: rect.right,
y: rect.bottom, y: rect.top,
w: rect.width, w: rect.width,
h: rect.height, h: rect.height,
}); });

View file

@ -5,8 +5,9 @@ import {hasClosestByAttribute} from "../../util/hasClosest";
import {Menu} from "../../../plugin/Menu"; import {Menu} from "../../../plugin/Menu";
import {Constants} from "../../../constants"; import {Constants} from "../../../constants";
import * as dayjs from "dayjs"; import * as dayjs from "dayjs";
import {popTextCell} from "./cell";
const genAVValueHTML = (value: IAVCellValue) => { export const genAVValueHTML = (value: IAVCellValue) => {
let html = ""; let html = "";
switch (value.type) { switch (value.type) {
case "text": case "text":
@ -57,7 +58,156 @@ const genAVValueHTML = (value: IAVCellValue) => {
return html; return html;
}; };
export const renderAVAttribute = (element: HTMLElement, id: string) => { const popDateMenu = (dateElement: HTMLElement) => {
const dateMenu = new Menu("custom-attr-av-date", () => {
const textElements = window.siyuan.menus.menu.element.querySelectorAll(".b3-text-field") as NodeListOf<HTMLInputElement>;
const hasEndDate = (window.siyuan.menus.menu.element.querySelector(".b3-switch") as HTMLInputElement).checked;
fetchPost("/api/av/setAttributeViewBlockAttr", {
avID: dateElement.dataset.avId,
keyID: dateElement.dataset.colId,
rowID: dateElement.dataset.blockId,
cellID: dateElement.dataset.id,
value: {
date: {
isNotEmpty: textElements[0].value !== "",
isNotEmpty2: textElements[1].value !== "",
content: new Date(textElements[0].value).getTime(),
content2: new Date(textElements[1].value).getTime(),
hasEndDate
}
}
});
let dataHTML = "";
if (textElements[0].value !== "") {
dataHTML = `<span data-content="${new Date(textElements[0].value).getTime()}">${dayjs(textElements[0].value).format("YYYY-MM-DD HH:mm")}</span>`;
}
if (hasEndDate && textElements[0].value !== "" && textElements[1].value !== "") {
dataHTML += `<svg class="custom-attr__avarrow"><use xlink:href="#iconForward"></use></svg><span data-content="${new Date(textElements[1].value).getTime()}">${dayjs(textElements[1].value).format("YYYY-MM-DD HH:mm")}</span>`;
}
dateElement.innerHTML = dataHTML;
});
if (dateMenu.isOpen) {
return;
}
const hasEndDate = dateElement.querySelector("svg");
const timeElements = dateElement.querySelectorAll("span");
dateMenu.addItem({
iconHTML: "",
label: `<input value="${timeElements[0] ? dayjs(parseInt(timeElements[0].dataset.content)).format("YYYY-MM-DDTHH:mm") : ""}" type="datetime-local" class="b3-text-field fn__size200" style="margin: 4px 0">`
});
dateMenu.addItem({
iconHTML: "",
label: `<input value="${timeElements[1] ? dayjs(parseInt(timeElements[1].dataset.content)).format("YYYY-MM-DDTHH:mm") : ""}" type="datetime-local" class="b3-text-field fn__size200${hasEndDate ? "" : " fn__none"}" style="margin: 4px 0">`
});
dateMenu.addSeparator();
dateMenu.addItem({
iconHTML: "",
label: `<label class="fn__flex">
<span>${window.siyuan.languages.endDate}</span>
<span class="fn__space fn__flex-1"></span>
<input type="checkbox" class="b3-switch fn__flex-center"${hasEndDate ? " checked" : ""}>
</label>`,
click(element, event) {
const switchElement = element.querySelector(".b3-switch") as HTMLInputElement;
if ((event.target as HTMLElement).tagName !== "INPUT") {
switchElement.checked = !switchElement.checked;
} else {
switchElement.outerHTML = `<input type="checkbox" class="b3-switch fn__flex-center"${switchElement.checked ? " checked" : ""}>`;
}
window.siyuan.menus.menu.element.querySelectorAll('[type="datetime-local"]')[1].classList.toggle("fn__none");
return true;
}
});
dateMenu.addSeparator();
dateMenu.addItem({
icon: "iconTrashcan",
label: window.siyuan.languages.clear,
click() {
const textElements = window.siyuan.menus.menu.element.querySelectorAll(".b3-text-field") as NodeListOf<HTMLInputElement>;
textElements[0].value = "";
textElements[1].value = "";
(window.siyuan.menus.menu.element.querySelector(".b3-switch") as HTMLInputElement).checked = false;
}
});
const datetRect = dateElement.getBoundingClientRect();
dateMenu.open({
x: datetRect.left,
y: datetRect.bottom
});
}
const popSelectMenu = (mSelectElement: HTMLElement) => {
const mSelectMenu = new Menu("custom-attr-av-select", () => {
const mSelect: { content: string, color: string }[] = [];
let mSelectHTML = "";
window.siyuan.menus.menu.element.querySelectorAll(".svg").forEach(item => {
const chipElement = item.parentElement.previousElementSibling.firstElementChild as HTMLElement;
const content = chipElement.textContent.trim();
const color = chipElement.dataset.color;
mSelect.push({
content,
color
});
mSelectHTML += `<span class="b3-chip b3-chip--middle" style="background-color:var(--b3-font-background${color});color:var(--b3-font-color${color})">${content}</span>`;
});
fetchPost("/api/av/setAttributeViewBlockAttr", {
avID: mSelectElement.dataset.avId,
keyID: mSelectElement.dataset.colId,
rowID: mSelectElement.dataset.blockId,
cellID: mSelectElement.dataset.id,
value: {
mSelect
}
});
mSelectElement.innerHTML = mSelectHTML;
});
if (mSelectMenu.isOpen) {
return;
}
const names: string[] = [];
mSelectElement.querySelectorAll(".b3-chip").forEach(item => {
names.push(item.textContent.trim());
});
JSON.parse(mSelectElement.dataset.options || "").forEach((item: { name: string, color: string }) => {
mSelectMenu.addItem({
iconHTML: "",
label: `<span class="b3-chip" data-color="${item.color}" style="height:24px;background-color:var(--b3-font-background${item.color});color:var(--b3-font-color${item.color})">
<span class="fn__ellipsis">${item.name}</span>
</span>`,
accelerator: names.includes(item.name) ? '<svg class="svg" style="height: 30px; float: left;"><use xlink:href="#iconSelect"></use></svg>' : Constants.ZWSP,
click(element) {
const acceleratorElement = element.querySelector(".b3-menu__accelerator");
if (mSelectElement.dataset.type === "select") {
window.siyuan.menus.menu.element.querySelectorAll(".b3-menu__accelerator").forEach(itemElement => {
if (itemElement.isSameNode(acceleratorElement)) {
if (acceleratorElement.querySelector("svg")) {
acceleratorElement.innerHTML = "";
} else {
acceleratorElement.innerHTML = '<svg class="svg" style="height: 30px; float: left;"><use xlink:href="#iconSelect"></use></svg>';
}
} else {
itemElement.innerHTML = "";
}
});
return false;
}
if (acceleratorElement.querySelector("svg")) {
acceleratorElement.innerHTML = "";
} else {
acceleratorElement.innerHTML = '<svg class="svg" style="height: 30px; float: left;"><use xlink:href="#iconSelect"></use></svg>';
}
return true;
}
});
});
const mSelecttRect = mSelectElement.getBoundingClientRect();
mSelectMenu.open({
x: mSelecttRect.left,
y: mSelecttRect.bottom
});
}
export const renderAVAttribute = (element: HTMLElement, id: string, protyle?: IProtyle) => {
fetchPost("/api/av/getAttributeViewKeys", {id}, (response) => { fetchPost("/api/av/getAttributeViewKeys", {id}, (response) => {
let html = ""; let html = "";
response.data.forEach((table: { response.data.forEach((table: {
@ -77,12 +227,12 @@ export const renderAVAttribute = (element: HTMLElement, id: string) => {
<span>${table.avName || window.siyuan.languages.database}</span> <span>${table.avName || window.siyuan.languages.database}</span>
</div>`; </div>`;
table.keyValues?.forEach(item => { table.keyValues?.forEach(item => {
html += `<div class="block__icons"> html += `<div class="block__icons" data-id="${id}">
<div class="block__logo"> <div class="block__logo">
<svg><use xlink:href="#${getColIconByType(item.key.type)}"></use></svg> <svg><use xlink:href="#${getColIconByType(item.key.type)}"></use></svg>
<span>${item.key.name}</span> <span>${item.key.name}</span>
</div> </div>
<div data-av-id="${table.avID}" data-key-id="${item.values[0].keyID}" data-block-id="${item.values[0].blockID}" data-id="${item.values[0].id}" data-type="${item.values[0].type}" <div data-av-id="${table.avID}" data-col-id="${item.values[0].keyID}" data-block-id="${item.values[0].blockID}" data-id="${item.values[0].id}" data-type="${item.values[0].type}"
data-options="${item.key?.options ? escapeAttr(JSON.stringify(item.key.options)) : "[]"}" data-options="${item.key?.options ? escapeAttr(JSON.stringify(item.key.options)) : "[]"}"
class="fn__flex-1 fn__flex${["url", "text", "number", "email", "phone"].includes(item.values[0].type) ? "" : " custom-attr__avvalue"}"> class="fn__flex-1 fn__flex${["url", "text", "number", "email", "phone"].includes(item.values[0].type) ? "" : " custom-attr__avvalue"}">
${genAVValueHTML(item.values[0])} ${genAVValueHTML(item.values[0])}
@ -95,155 +245,21 @@ class="fn__flex-1 fn__flex${["url", "text", "number", "email", "phone"].includes
const target = event.target as HTMLElement; const target = event.target as HTMLElement;
const dateElement = hasClosestByAttribute(target, "data-type", "date"); const dateElement = hasClosestByAttribute(target, "data-type", "date");
if (dateElement) { if (dateElement) {
const dateMenu = new Menu("custom-attr-av-date", () => { popDateMenu(dateElement);
const textElements = window.siyuan.menus.menu.element.querySelectorAll(".b3-text-field") as NodeListOf<HTMLInputElement>;
const hasEndDate = (window.siyuan.menus.menu.element.querySelector(".b3-switch") as HTMLInputElement).checked;
fetchPost("/api/av/setAttributeViewBlockAttr", {
avID: dateElement.dataset.avId,
keyID: dateElement.dataset.keyId,
rowID: dateElement.dataset.blockId,
cellID: dateElement.dataset.id,
value: {
date: {
isNotEmpty: textElements[0].value !== "",
isNotEmpty2: textElements[1].value !== "",
content: new Date(textElements[0].value).getTime(),
content2: new Date(textElements[1].value).getTime(),
hasEndDate
}
}
});
let dataHTML = "";
if (textElements[0].value !== "") {
dataHTML = `<span data-content="${new Date(textElements[0].value).getTime()}">${dayjs(textElements[0].value).format("YYYY-MM-DD HH:mm")}</span>`;
}
if (hasEndDate && textElements[0].value !== "" && textElements[1].value !== "") {
dataHTML += `<svg class="custom-attr__avarrow"><use xlink:href="#iconForward"></use></svg><span data-content="${new Date(textElements[1].value).getTime()}">${dayjs(textElements[1].value).format("YYYY-MM-DD HH:mm")}</span>`;
}
dateElement.innerHTML = dataHTML;
});
if (dateMenu.isOpen) {
return;
}
const hasEndDate = dateElement.querySelector("svg");
const timeElements = dateElement.querySelectorAll("span");
dateMenu.addItem({
iconHTML: "",
label: `<input value="${timeElements[0] ? dayjs(parseInt(timeElements[0].dataset.content)).format("YYYY-MM-DDTHH:mm") : ""}" type="datetime-local" class="b3-text-field fn__size200" style="margin: 4px 0">`
});
dateMenu.addItem({
iconHTML: "",
label: `<input value="${timeElements[1] ? dayjs(parseInt(timeElements[1].dataset.content)).format("YYYY-MM-DDTHH:mm") : ""}" type="datetime-local" class="b3-text-field fn__size200${hasEndDate ? "" : " fn__none"}" style="margin: 4px 0">`
});
dateMenu.addSeparator();
dateMenu.addItem({
iconHTML: "",
label: `<label class="fn__flex">
<span>${window.siyuan.languages.endDate}</span>
<span class="fn__space fn__flex-1"></span>
<input type="checkbox" class="b3-switch fn__flex-center"${hasEndDate ? " checked" : ""}>
</label>`,
click(element, event) {
const switchElement = element.querySelector(".b3-switch") as HTMLInputElement;
if ((event.target as HTMLElement).tagName !== "INPUT") {
switchElement.checked = !switchElement.checked;
} else {
switchElement.outerHTML = `<input type="checkbox" class="b3-switch fn__flex-center"${switchElement.checked ? " checked" : ""}>`;
}
window.siyuan.menus.menu.element.querySelectorAll('[type="datetime-local"]')[1].classList.toggle("fn__none");
return true;
}
});
dateMenu.addSeparator();
dateMenu.addItem({
icon: "iconTrashcan",
label: window.siyuan.languages.clear,
click() {
const textElements = window.siyuan.menus.menu.element.querySelectorAll(".b3-text-field") as NodeListOf<HTMLInputElement>;
textElements[0].value = "";
textElements[1].value = "";
(window.siyuan.menus.menu.element.querySelector(".b3-switch") as HTMLInputElement).checked = false;
}
});
const datetRect = dateElement.getBoundingClientRect();
dateMenu.open({
x: datetRect.left,
y: datetRect.bottom
});
event.stopPropagation(); event.stopPropagation();
event.preventDefault(); event.preventDefault();
return; return;
} }
const mSelectElement = hasClosestByAttribute(target, "data-type", "select") || hasClosestByAttribute(target, "data-type", "mSelect"); const mSelectElement = hasClosestByAttribute(target, "data-type", "select") || hasClosestByAttribute(target, "data-type", "mSelect");
if (mSelectElement) { if (mSelectElement) {
const mSelectMenu = new Menu("custom-attr-av-select", () => { popSelectMenu(mSelectElement);
const mSelect: { content: string, color: string }[] = []; event.stopPropagation();
let mSelectHTML = ""; event.preventDefault();
window.siyuan.menus.menu.element.querySelectorAll(".svg").forEach(item => { return;
const chipElement = item.parentElement.previousElementSibling.firstElementChild as HTMLElement; }
const content = chipElement.textContent.trim(); const mAssetElement = hasClosestByAttribute(target, "data-type", "mAsset");
const color = chipElement.dataset.color; if (mAssetElement) {
mSelect.push({ popTextCell(protyle, [mAssetElement], "mAsset");
content,
color
});
mSelectHTML += `<span class="b3-chip b3-chip--middle" style="background-color:var(--b3-font-background${color});color:var(--b3-font-color${color})">${content}</span>`;
});
fetchPost("/api/av/setAttributeViewBlockAttr", {
avID: mSelectElement.dataset.avId,
keyID: mSelectElement.dataset.keyId,
rowID: mSelectElement.dataset.blockId,
cellID: mSelectElement.dataset.id,
value: {
mSelect
}
});
mSelectElement.innerHTML = mSelectHTML;
});
if (mSelectMenu.isOpen) {
return;
}
const names: string[] = [];
mSelectElement.querySelectorAll(".b3-chip").forEach(item => {
names.push(item.textContent.trim());
});
JSON.parse(mSelectElement.dataset.options || "").forEach((item: { name: string, color: string }) => {
mSelectMenu.addItem({
iconHTML: "",
label: `<span class="b3-chip" data-color="${item.color}" style="height:24px;background-color:var(--b3-font-background${item.color});color:var(--b3-font-color${item.color})">
<span class="fn__ellipsis">${item.name}</span>
</span>`,
accelerator: names.includes(item.name) ? '<svg class="svg" style="height: 30px; float: left;"><use xlink:href="#iconSelect"></use></svg>' : Constants.ZWSP,
click(element) {
const acceleratorElement = element.querySelector(".b3-menu__accelerator");
if (mSelectElement.dataset.type === "select") {
window.siyuan.menus.menu.element.querySelectorAll(".b3-menu__accelerator").forEach(itemElement => {
if (itemElement.isSameNode(acceleratorElement)) {
if (acceleratorElement.querySelector("svg")) {
acceleratorElement.innerHTML = "";
} else {
acceleratorElement.innerHTML = '<svg class="svg" style="height: 30px; float: left;"><use xlink:href="#iconSelect"></use></svg>';
}
} else {
itemElement.innerHTML = "";
}
});
return false;
}
if (acceleratorElement.querySelector("svg")) {
acceleratorElement.innerHTML = "";
} else {
acceleratorElement.innerHTML = '<svg class="svg" style="height: 30px; float: left;"><use xlink:href="#iconSelect"></use></svg>';
}
return true;
}
});
});
const mSelecttRect = mSelectElement.getBoundingClientRect();
mSelectMenu.open({
x: mSelecttRect.left,
y: mSelecttRect.bottom
});
event.stopPropagation(); event.stopPropagation();
event.preventDefault(); event.preventDefault();
return; return;
@ -267,7 +283,7 @@ class="fn__flex-1 fn__flex${["url", "text", "number", "email", "phone"].includes
} }
fetchPost("/api/av/setAttributeViewBlockAttr", { fetchPost("/api/av/setAttributeViewBlockAttr", {
avID: item.parentElement.dataset.avId, avID: item.parentElement.dataset.avId,
keyID: item.parentElement.dataset.keyId, keyID: item.parentElement.dataset.colId,
rowID: item.parentElement.dataset.blockId, rowID: item.parentElement.dataset.blockId,
cellID: item.parentElement.dataset.id, cellID: item.parentElement.dataset.id,
value value

View file

@ -339,8 +339,10 @@ export const openCalcMenu = (protyle: IProtyle, calcElement: HTMLElement) => {
menu.open({x: calcRect.left, y: calcRect.bottom, h: calcRect.height}); menu.open({x: calcRect.left, y: calcRect.bottom, h: calcRect.height});
}; };
export const popTextCell = (protyle: IProtyle, cellElements: HTMLElement[]) => { export const popTextCell = (protyle: IProtyle, cellElements: HTMLElement[], type?: TAVCol) => {
const type = cellElements[0].parentElement.parentElement.firstElementChild.querySelector(`[data-col-id="${cellElements[0].getAttribute("data-col-id")}"]`).getAttribute("data-dtype") as TAVCol; if (!type) {
type = cellElements[0].parentElement.parentElement.firstElementChild.querySelector(`[data-col-id="${cellElements[0].getAttribute("data-col-id")}"]`).getAttribute("data-dtype") as TAVCol;
}
if (type === "block") { if (type === "block") {
return; return;
} }

View file

@ -58,7 +58,7 @@ export const openMenuPanel = (options: {
</div>`); </div>`);
avPanelElement = document.querySelector(".av__panel"); avPanelElement = document.querySelector(".av__panel");
const menuElement = avPanelElement.lastElementChild as HTMLElement; const menuElement = avPanelElement.lastElementChild as HTMLElement;
const tabRect = options.blockElement.querySelector(".layout-tab-bar").getBoundingClientRect(); const tabRect = options.blockElement.querySelector(".layout-tab-bar")?.getBoundingClientRect();
if (["select", "date", "asset"].includes(options.type)) { if (["select", "date", "asset"].includes(options.type)) {
const cellRect = options.cellElements[options.cellElements.length - 1].getBoundingClientRect(); const cellRect = options.cellElements[options.cellElements.length - 1].getBoundingClientRect();
if (options.type === "select") { if (options.type === "select") {
@ -94,7 +94,12 @@ export const openMenuPanel = (options: {
window.siyuan.dragElement.style.opacity = ""; window.siyuan.dragElement.style.opacity = "";
const sourceElement = window.siyuan.dragElement; const sourceElement = window.siyuan.dragElement;
window.siyuan.dragElement = undefined; window.siyuan.dragElement = undefined;
if (options.protyle.disabled) { if (options.protyle && options.protyle.disabled) {
event.preventDefault();
event.stopPropagation();
return;
}
if (!options.protyle && window.siyuan.config.readonly) {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
return; return;

View file

@ -152,6 +152,31 @@ export const uploadLocalFiles = (files: string[], protyle: IProtyle, isUpload: b
}; };
export const uploadFiles = (protyle: IProtyle, files: FileList | DataTransferItemList | File[], element?: HTMLInputElement, successCB?: (res: string) => void) => { export const uploadFiles = (protyle: IProtyle, files: FileList | DataTransferItemList | File[], element?: HTMLInputElement, successCB?: (res: string) => void) => {
// 文档书中点开属性->数据库后的变更操作
if (!protyle) {
const formData = new FormData();
for (let i = 0, iMax = files.length; i < iMax; i++) {
formData.append("file[]", files[i] as File);
}
const xhr = new XMLHttpRequest();
xhr.open("POST", Constants.UPLOAD_ADDRESS);
xhr.onreadystatechange = () => {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200) {
successCB(xhr.responseText);
} else if (xhr.status === 0) {
showMessage(window.siyuan.languages.fileTypeError);
} else {
showMessage(xhr.responseText);
}
if (element) {
element.value = "";
}
}
};
xhr.send(formData);
return;
}
// FileList | DataTransferItemList | File[] => File[] // FileList | DataTransferItemList | File[] => File[]
let fileList = []; let fileList = [];
for (let i = 0; i < files.length; i++) { for (let i = 0; i < files.length; i++) {

View file

@ -17,9 +17,9 @@ export const commonClick = (event: MouseEvent & {
/// #endif /// #endif
} else { } else {
if (data) { if (data) {
openFileAttr(data, "bookmark"); openFileAttr(data, "bookmark", protyle);
} else { } else {
openAttr(attrBookmarkElement.parentElement.parentElement, "bookmark"); openAttr(attrBookmarkElement.parentElement.parentElement, "bookmark", protyle);
} }
} }
event.stopPropagation(); event.stopPropagation();
@ -34,9 +34,9 @@ export const commonClick = (event: MouseEvent & {
/// #endif /// #endif
} else { } else {
if (data) { if (data) {
openFileAttr(data, "name"); openFileAttr(data, "name", protyle);
} else { } else {
openAttr(attrNameElement.parentElement.parentElement, "name"); openAttr(attrNameElement.parentElement.parentElement, "name", protyle);
} }
} }
event.stopPropagation(); event.stopPropagation();
@ -51,9 +51,9 @@ export const commonClick = (event: MouseEvent & {
/// #endif /// #endif
} else { } else {
if (data) { if (data) {
openFileAttr(data, "alias"); openFileAttr(data, "alias", protyle);
} else { } else {
openAttr(attrAliasElement.parentElement.parentElement, "alias"); openAttr(attrAliasElement.parentElement.parentElement, "alias", protyle);
} }
} }
event.stopPropagation(); event.stopPropagation();
@ -68,9 +68,9 @@ export const commonClick = (event: MouseEvent & {
/// #endif /// #endif
} else { } else {
if (data) { if (data) {
openFileAttr(data, "memo"); openFileAttr(data, "memo", protyle);
} else { } else {
openAttr(attrMemoElement.parentElement.parentElement, "memo"); openAttr(attrMemoElement.parentElement.parentElement, "memo", protyle);
} }
} }
event.stopPropagation(); event.stopPropagation();

View file

@ -1978,7 +1978,7 @@ export class WYSIWYG {
} }
hideElements(["gutter"], protyle); hideElements(["gutter"], protyle);
} else if (event.shiftKey && !protyle.disabled) { } else if (event.shiftKey && !protyle.disabled) {
openAttr(actionElement.parentElement); openAttr(actionElement.parentElement, "bookmark", protyle);
} else if (ctrlIsPressed) { } else if (ctrlIsPressed) {
zoomOut({protyle, id: actionId}); zoomOut({protyle, id: actionId});
} else { } else {

View file

@ -1056,7 +1056,7 @@ export const keydown = (protyle: IProtyle, editorElement: HTMLElement) => {
} else { } else {
actionElement = topElement; actionElement = topElement;
} }
openAttr(actionElement); openAttr(actionElement, "bookmark", protyle);
} else { } else {
const oldHTML = topElement.outerHTML; const oldHTML = topElement.outerHTML;
const name = Lute.EscapeHTMLStr(selectText); const name = Lute.EscapeHTMLStr(selectText);

View file

@ -945,6 +945,18 @@ const updateRef = (protyle: IProtyle, id: string, index = 0) => {
let transactionsTimeout: number; let transactionsTimeout: number;
export const transaction = (protyle: IProtyle, doOperations: IOperation[], undoOperations?: IOperation[]) => { export const transaction = (protyle: IProtyle, doOperations: IOperation[], undoOperations?: IOperation[]) => {
if (!protyle) {
// 文档书中点开属性->数据库后的变更操作
fetchPost("/api/transactions", {
session: Constants.SIYUAN_APPID,
app: Constants.SIYUAN_APPID,
transactions: [{
doOperations
}]
});
return;
}
const lastTransaction = window.siyuan.transactions[window.siyuan.transactions.length - 1]; const lastTransaction = window.siyuan.transactions[window.siyuan.transactions.length - 1];
let needDebounce = false; let needDebounce = false;
const time = new Date().getTime(); const time = new Date().getTime();