mirror of
https://github.com/siyuan-note/siyuan.git
synced 2026-01-15 21:25:28 +01:00
This commit is contained in:
parent
251e73b845
commit
338c359013
9 changed files with 183 additions and 153 deletions
|
|
@ -8,6 +8,8 @@ import {Constants} from "../constants";
|
|||
import {Dialog} from "../dialog";
|
||||
import {showMessage} from "../dialog/message";
|
||||
import {isMobile} from "../util/functions";
|
||||
import {confirmDialog} from "../dialog/confirmDialog";
|
||||
import prettyBytes from "pretty-bytes";
|
||||
|
||||
export const initAnno = (element: HTMLElement, pdf: any) => {
|
||||
getConfig(pdf);
|
||||
|
|
@ -738,13 +740,19 @@ const copyAnno = (idPath: string, fileName: string, pdf: any) => {
|
|||
fetch(imageDataURL).then((response) => {
|
||||
return response.blob();
|
||||
}).then((blob) => {
|
||||
const formData = new FormData();
|
||||
const imageName = content + ".png";
|
||||
formData.append("file[]", blob, imageName);
|
||||
formData.append("skipIfDuplicated", "true");
|
||||
fetchPost(Constants.UPLOAD_ADDRESS, formData, (response) => {
|
||||
writeText(`<<${idPath} "${content}">>
|
||||
let msg = "";
|
||||
if (Constants.SIZE_UPLOAD_TIP_SIZE <= blob.size) {
|
||||
msg = window.siyuan.languages.uploadFileTooLarge.replace("${x}", imageName).replace("${y}", prettyBytes(blob.size, {binary: true}));
|
||||
}
|
||||
confirmDialog(msg ? window.siyuan.languages.upload : "", msg, () => {
|
||||
const formData = new FormData();
|
||||
formData.append("file[]", blob, imageName);
|
||||
formData.append("skipIfDuplicated", "true");
|
||||
fetchPost(Constants.UPLOAD_ADDRESS, formData, (response) => {
|
||||
writeText(`<<${idPath} "${content}">>
|
||||
`);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ export abstract class Constants {
|
|||
|
||||
// size
|
||||
public static readonly SIZE_DATABASE_MAZ_SIZE: number = 102400;
|
||||
public static readonly SIZE_UPLOAD_TIP_SIZE: number = 256 * 1024 * 1024;
|
||||
public static readonly SIZE_SCROLL_TB: number = 24;
|
||||
public static readonly SIZE_SCROLL_STEP: number = 256;
|
||||
public static readonly SIZE_LINK_TEXT_MAX: number = 64;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ import * as dayjs from "dayjs";
|
|||
import {getColId} from "./col";
|
||||
import {getFieldIdByCellElement} from "./row";
|
||||
import {getCompressURL, removeCompressURL} from "../../../util/image";
|
||||
import {confirmDialog} from "../../../dialog/confirmDialog";
|
||||
import prettyBytes from "pretty-bytes";
|
||||
|
||||
export const bindAssetEvent = (options: {
|
||||
protyle: IProtyle,
|
||||
|
|
@ -420,40 +422,51 @@ ${window.siyuan.languages.title}
|
|||
menu.element.querySelector("textarea").focus();
|
||||
};
|
||||
|
||||
export const dragUpload = (files: string[], protyle: IProtyle, cellElement: HTMLElement) => {
|
||||
const msgId = showMessage(window.siyuan.languages.uploading, 0);
|
||||
fetchPost("/api/asset/insertLocalAssets", {
|
||||
assetPaths: files,
|
||||
isUpload: true,
|
||||
id: protyle.block.rootID
|
||||
}, (response) => {
|
||||
const blockElement = hasClosestBlock(cellElement);
|
||||
if (blockElement) {
|
||||
hideMessage(msgId);
|
||||
const addValue: IAVCellAssetValue[] = [];
|
||||
Object.keys(response.data.succMap).forEach(key => {
|
||||
const type = pathPosix().extname(key).toLowerCase();
|
||||
const name = key.substring(0, key.length - type.length);
|
||||
if (Constants.SIYUAN_ASSETS_IMAGE.includes(type)) {
|
||||
addValue.push({
|
||||
type: "image",
|
||||
name,
|
||||
content: response.data.succMap[key],
|
||||
});
|
||||
} else {
|
||||
addValue.push({
|
||||
type: "file",
|
||||
name,
|
||||
content: response.data.succMap[key],
|
||||
});
|
||||
}
|
||||
});
|
||||
updateAssetCell({
|
||||
protyle,
|
||||
blockElement,
|
||||
cellElements: [cellElement],
|
||||
addValue
|
||||
});
|
||||
export const dragUpload = (files: ILocalFiles[], protyle: IProtyle, cellElement: HTMLElement) => {
|
||||
let msg = "";
|
||||
const assetPaths: string[] = [];
|
||||
files.forEach(item => {
|
||||
if (item.size && Constants.SIZE_UPLOAD_TIP_SIZE <= item.size) {
|
||||
msg += window.siyuan.languages.uploadFileTooLarge.replace("${x}", item.path).replace("${y}", prettyBytes(item.size, {binary: true})) + "<br>";
|
||||
}
|
||||
assetPaths.push(item.path);
|
||||
});
|
||||
|
||||
confirmDialog(msg ? window.siyuan.languages.upload : "", msg, () => {
|
||||
const msgId = showMessage(window.siyuan.languages.uploading, 0);
|
||||
fetchPost("/api/asset/insertLocalAssets", {
|
||||
assetPaths,
|
||||
isUpload: true,
|
||||
id: protyle.block.rootID
|
||||
}, (response) => {
|
||||
const blockElement = hasClosestBlock(cellElement);
|
||||
if (blockElement) {
|
||||
hideMessage(msgId);
|
||||
const addValue: IAVCellAssetValue[] = [];
|
||||
Object.keys(response.data.succMap).forEach(key => {
|
||||
const type = pathPosix().extname(key).toLowerCase();
|
||||
const name = key.substring(0, key.length - type.length);
|
||||
if (Constants.SIYUAN_ASSETS_IMAGE.includes(type)) {
|
||||
addValue.push({
|
||||
type: "image",
|
||||
name,
|
||||
content: response.data.succMap[key],
|
||||
});
|
||||
} else {
|
||||
addValue.push({
|
||||
type: "file",
|
||||
name,
|
||||
content: response.data.succMap[key],
|
||||
});
|
||||
}
|
||||
});
|
||||
updateAssetCell({
|
||||
protyle,
|
||||
blockElement,
|
||||
cellElements: [cellElement],
|
||||
addValue
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -275,9 +275,12 @@ class="fn__flex-1 fn__flex${["url", "text", "number", "email", "phone", "block"]
|
|||
const cellElement = element.querySelector(".custom-attr__avvalue--active") as HTMLElement;
|
||||
if (cellElement) {
|
||||
if (event.dataTransfer.types[0] === "Files" && !isBrowser()) {
|
||||
const files: string[] = [];
|
||||
const files: ILocalFiles[] = [];
|
||||
for (let i = 0; i < event.dataTransfer.files.length; i++) {
|
||||
files.push(webUtils.getPathForFile(event.dataTransfer.files[i]));
|
||||
files.push({
|
||||
path: webUtils.getPathForFile(event.dataTransfer.files[i]),
|
||||
size: event.dataTransfer.files[i].size
|
||||
});
|
||||
}
|
||||
dragUpload(files, protyle, cellElement);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ import {hasClosestBlock} from "../util/hasClosest";
|
|||
import {getContenteditableElement} from "../wysiwyg/getBlock";
|
||||
import {getTypeByCellElement, updateCellsValue} from "../render/av/cell";
|
||||
import {scrollCenter} from "../../util/highlightById";
|
||||
import {confirmDialog} from "../../dialog/confirmDialog";
|
||||
import prettyBytes from "pretty-bytes";
|
||||
|
||||
interface FileWithPath extends File {
|
||||
path: string;
|
||||
|
|
@ -213,53 +215,39 @@ const genUploadedLabel = (responseText: string, protyle: IProtyle) => {
|
|||
}, hasImage ? 0 : Constants.TIMEOUT_LOAD);
|
||||
};
|
||||
|
||||
export const uploadLocalFiles = (files: string[], protyle: IProtyle, isUpload: boolean) => {
|
||||
const msgId = showMessage(window.siyuan.languages.uploading, 0);
|
||||
fetchPost("/api/asset/insertLocalAssets", {
|
||||
assetPaths: files,
|
||||
isUpload,
|
||||
id: protyle.block.rootID
|
||||
}, (response) => {
|
||||
hideMessage(msgId);
|
||||
let tip = "";
|
||||
Object.keys(response.data.succMap).forEach(name => {
|
||||
if (response.data.succMap[name].startsWith("file:")) {
|
||||
tip += name + ", ";
|
||||
}
|
||||
});
|
||||
if (tip) {
|
||||
showMessage(window.siyuan.languages.dndFolderTip.replace("${x}", `<b>${tip.substring(0, tip.length - 2)}</b>`));
|
||||
export const uploadLocalFiles = (files: ILocalFiles[], protyle: IProtyle, isUpload: boolean) => {
|
||||
let msg = "";
|
||||
const assetPaths: string[] = [];
|
||||
files.forEach(item => {
|
||||
if (item.size && Constants.SIZE_UPLOAD_TIP_SIZE <= item.size) {
|
||||
msg += window.siyuan.languages.uploadFileTooLarge.replace("${x}", item.path).replace("${y}", prettyBytes(item.size, {binary: true})) + "<br>";
|
||||
}
|
||||
genUploadedLabel(JSON.stringify(response), protyle);
|
||||
assetPaths.push(item.path);
|
||||
});
|
||||
|
||||
confirmDialog(msg ? window.siyuan.languages.upload : "", msg, () => {
|
||||
const msgId = showMessage(window.siyuan.languages.uploading, 0);
|
||||
fetchPost("/api/asset/insertLocalAssets", {
|
||||
assetPaths,
|
||||
isUpload,
|
||||
id: protyle.block.rootID
|
||||
}, (response) => {
|
||||
hideMessage(msgId);
|
||||
let tip = "";
|
||||
Object.keys(response.data.succMap).forEach(name => {
|
||||
if (response.data.succMap[name].startsWith("file:")) {
|
||||
tip += name + ", ";
|
||||
}
|
||||
});
|
||||
if (tip) {
|
||||
showMessage(window.siyuan.languages.dndFolderTip.replace("${x}", `<b>${tip.substring(0, tip.length - 2)}</b>`));
|
||||
}
|
||||
genUploadedLabel(JSON.stringify(response), protyle);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
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[]
|
||||
let fileList = [];
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
|
|
@ -269,7 +257,7 @@ export const uploadFiles = (protyle: IProtyle, files: FileList | DataTransferIte
|
|||
}
|
||||
if (0 === fileItem.size && "" === fileItem.type && -1 === fileItem.name.indexOf(".")) {
|
||||
// 文件夹
|
||||
uploadLocalFiles([(fileItem as FileWithPath).path], protyle, false);
|
||||
uploadLocalFiles([{path: (fileItem as FileWithPath).path, size: null}], protyle, false);
|
||||
} else {
|
||||
fileList.push(fileItem);
|
||||
}
|
||||
|
|
@ -319,65 +307,71 @@ export const uploadFiles = (protyle: IProtyle, files: FileList | DataTransferIte
|
|||
for (const key of Object.keys(extraData)) {
|
||||
formData.append(key, extraData[key]);
|
||||
}
|
||||
|
||||
let msg = "";
|
||||
for (let i = 0, iMax = validateResult.files.length; i < iMax; i++) {
|
||||
formData.append(protyle.options.upload.fieldName, validateResult.files[i]);
|
||||
}
|
||||
formData.append("id", protyle.block.rootID);
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", protyle.options.upload.url);
|
||||
if (protyle.options.upload.token) {
|
||||
xhr.setRequestHeader("X-Upload-Token", protyle.options.upload.token);
|
||||
}
|
||||
if (protyle.options.upload.withCredentials) {
|
||||
xhr.withCredentials = true;
|
||||
if (Constants.SIZE_UPLOAD_TIP_SIZE <= validateResult.files[i].size) {
|
||||
msg += window.siyuan.languages.uploadFileTooLarge.replace("${x}", validateResult.files[i].name).replace("${y}", prettyBytes(validateResult.files[i].size, {binary: true})) + "<br>";
|
||||
}
|
||||
}
|
||||
|
||||
protyle.upload.isUploading = true;
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
protyle.upload.isUploading = false;
|
||||
if (!document.body.contains(protyle.element)) {
|
||||
// 网络较慢时,页签已经关闭
|
||||
destroy(protyle);
|
||||
formData.append("id", protyle.block.rootID);
|
||||
confirmDialog(msg ? window.siyuan.languages.upload : "", msg, () => {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", protyle.options.upload.url);
|
||||
if (protyle.options.upload.token) {
|
||||
xhr.setRequestHeader("X-Upload-Token", protyle.options.upload.token);
|
||||
}
|
||||
if (protyle.options.upload.withCredentials) {
|
||||
xhr.withCredentials = true;
|
||||
}
|
||||
|
||||
protyle.upload.isUploading = true;
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
protyle.upload.isUploading = false;
|
||||
if (!document.body.contains(protyle.element)) {
|
||||
// 网络较慢时,页签已经关闭
|
||||
destroy(protyle);
|
||||
return;
|
||||
}
|
||||
if (xhr.status === 200) {
|
||||
hideMessage(validateResult.msgId);
|
||||
if (protyle.options.upload.success) {
|
||||
protyle.options.upload.success(editorElement, xhr.responseText);
|
||||
} else if (successCB) {
|
||||
successCB(xhr.responseText);
|
||||
} else {
|
||||
let responseText = xhr.responseText;
|
||||
if (protyle.options.upload.format) {
|
||||
responseText = protyle.options.upload.format(files as File [], xhr.responseText);
|
||||
}
|
||||
genUploadedLabel(responseText, protyle);
|
||||
}
|
||||
} else if (xhr.status === 0) {
|
||||
showMessage(window.siyuan.languages.fileTypeError);
|
||||
} else {
|
||||
if (protyle.options.upload.error) {
|
||||
protyle.options.upload.error(xhr.responseText);
|
||||
} else {
|
||||
showMessage(xhr.responseText);
|
||||
}
|
||||
}
|
||||
if (element) {
|
||||
element.value = "";
|
||||
}
|
||||
protyle.upload.element.style.display = "none";
|
||||
}
|
||||
};
|
||||
xhr.upload.onprogress = (event: ProgressEvent) => {
|
||||
if (!event.lengthComputable) {
|
||||
return;
|
||||
}
|
||||
if (xhr.status === 200) {
|
||||
hideMessage(validateResult.msgId);
|
||||
if (protyle.options.upload.success) {
|
||||
protyle.options.upload.success(editorElement, xhr.responseText);
|
||||
} else if (successCB) {
|
||||
successCB(xhr.responseText);
|
||||
} else {
|
||||
let responseText = xhr.responseText;
|
||||
if (protyle.options.upload.format) {
|
||||
responseText = protyle.options.upload.format(files as File [], xhr.responseText);
|
||||
}
|
||||
genUploadedLabel(responseText, protyle);
|
||||
}
|
||||
} else if (xhr.status === 0) {
|
||||
showMessage(window.siyuan.languages.fileTypeError);
|
||||
} else {
|
||||
if (protyle.options.upload.error) {
|
||||
protyle.options.upload.error(xhr.responseText);
|
||||
} else {
|
||||
showMessage(xhr.responseText);
|
||||
}
|
||||
}
|
||||
if (element) {
|
||||
element.value = "";
|
||||
}
|
||||
protyle.upload.element.style.display = "none";
|
||||
}
|
||||
};
|
||||
xhr.upload.onprogress = (event: ProgressEvent) => {
|
||||
if (!event.lengthComputable) {
|
||||
return;
|
||||
}
|
||||
const progress = event.loaded / event.total * 100;
|
||||
protyle.upload.element.style.display = "block";
|
||||
const progressBar = protyle.upload.element;
|
||||
progressBar.style.width = progress + "%";
|
||||
};
|
||||
xhr.send(formData);
|
||||
const progress = event.loaded / event.total * 100;
|
||||
protyle.upload.element.style.display = "block";
|
||||
const progressBar = protyle.upload.element;
|
||||
progressBar.style.width = progress + "%";
|
||||
};
|
||||
xhr.send(formData);
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -122,13 +122,13 @@ export const readText = () => {
|
|||
/// #if !BROWSER
|
||||
export const getLocalFiles = async () => {
|
||||
// 不再支持 PC 浏览器 https://github.com/siyuan-note/siyuan/issues/7206
|
||||
let localFiles: string[] = [];
|
||||
let localFiles: ILocalFiles[] = [];
|
||||
if ("darwin" === window.siyuan.config.system.os) {
|
||||
const xmlString = clipboard.read("NSFilenamesPboardType");
|
||||
const domParser = new DOMParser();
|
||||
const xmlDom = domParser.parseFromString(xmlString, "application/xml");
|
||||
Array.from(xmlDom.getElementsByTagName("string")).forEach(item => {
|
||||
localFiles.push(item.childNodes[0].nodeValue);
|
||||
localFiles.push({path: item.childNodes[0].nodeValue, size: null});
|
||||
});
|
||||
} else {
|
||||
const xmlString = await fetchSyncPost("/api/clipboard/readFilePaths", {});
|
||||
|
|
|
|||
|
|
@ -1149,9 +1149,12 @@ export const dropEvent = (protyle: IProtyle, editorElement: HTMLElement) => {
|
|||
if (!avElement) {
|
||||
focusByRange(getRangeByPoint(event.clientX, event.clientY));
|
||||
if (event.dataTransfer.types[0] === "Files" && !isBrowser()) {
|
||||
const files: string[] = [];
|
||||
const files: ILocalFiles[] = [];
|
||||
for (let i = 0; i < event.dataTransfer.files.length; i++) {
|
||||
files.push(webUtils.getPathForFile(event.dataTransfer.files[i]));
|
||||
files.push({
|
||||
path: webUtils.getPathForFile(event.dataTransfer.files[i]),
|
||||
size: event.dataTransfer.files[i].size
|
||||
});
|
||||
}
|
||||
uploadLocalFiles(files, protyle, !event.altKey);
|
||||
} else {
|
||||
|
|
@ -1162,9 +1165,12 @@ export const dropEvent = (protyle: IProtyle, editorElement: HTMLElement) => {
|
|||
const cellElement = hasClosestByClassName(event.target, "av__cell");
|
||||
if (cellElement) {
|
||||
if (getTypeByCellElement(cellElement) === "mAsset" && event.dataTransfer.types[0] === "Files" && !isBrowser()) {
|
||||
const files: string[] = [];
|
||||
const files: ILocalFiles[] = [];
|
||||
for (let i = 0; i < event.dataTransfer.files.length; i++) {
|
||||
files.push(webUtils.getPathForFile(event.dataTransfer.files[i]));
|
||||
files.push({
|
||||
path: webUtils.getPathForFile(event.dataTransfer.files[i]),
|
||||
size: event.dataTransfer.files[i].size
|
||||
});
|
||||
}
|
||||
dragUpload(files, protyle, cellElement);
|
||||
clearSelect(["cell"], avElement);
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ export const pasteEscaped = async (protyle: IProtyle, nodeElement: Element) => {
|
|||
};
|
||||
|
||||
export const pasteAsPlainText = async (protyle: IProtyle) => {
|
||||
let localFiles: string[] = [];
|
||||
let localFiles: ILocalFiles[] = [];
|
||||
/// #if !BROWSER
|
||||
localFiles = await getLocalFiles();
|
||||
if (localFiles.length > 0) {
|
||||
|
|
@ -214,24 +214,24 @@ export const restoreLuteMarkdownSyntax = (protyle: IProtyle) => {
|
|||
protyle.lute.SetMark(window.siyuan.config.editor.markdown.inlineMark);
|
||||
};
|
||||
|
||||
const readLocalFile = async (protyle: IProtyle, localFiles: string[]) => {
|
||||
const readLocalFile = async (protyle: IProtyle, localFiles: ILocalFiles[]) => {
|
||||
if (protyle && protyle.app && protyle.app.plugins) {
|
||||
for (let i = 0; i < protyle.app.plugins.length; i++) {
|
||||
const response: { files: string[] } = await new Promise((resolve) => {
|
||||
const response: { localFiles: ILocalFiles[] } = await new Promise((resolve) => {
|
||||
const emitResult = protyle.app.plugins[i].eventBus.emit("paste", {
|
||||
protyle,
|
||||
resolve,
|
||||
textHTML: "",
|
||||
textPlain: "",
|
||||
siyuanHTML: "",
|
||||
files: localFiles
|
||||
localFiles
|
||||
});
|
||||
if (emitResult) {
|
||||
resolve(undefined);
|
||||
}
|
||||
});
|
||||
if (response?.files) {
|
||||
localFiles = response.files;
|
||||
if (response?.localFiles) {
|
||||
localFiles = response.localFiles;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -277,7 +277,7 @@ export const paste = async (protyle: IProtyle, event: (ClipboardEvent | DragEven
|
|||
|
||||
/// #if !BROWSER
|
||||
if (!siyuanHTML && !textHTML && !textPlain && ("clipboardData" in event)) {
|
||||
const localFiles: string[] = await getLocalFiles();
|
||||
const localFiles: ILocalFiles[] = await getLocalFiles();
|
||||
if (localFiles.length > 0) {
|
||||
readLocalFile(protyle, localFiles);
|
||||
return;
|
||||
|
|
|
|||
7
app/src/types/index.d.ts
vendored
7
app/src/types/index.d.ts
vendored
|
|
@ -286,12 +286,17 @@ interface Window {
|
|||
destroyTheme(): Promise<void>;
|
||||
}
|
||||
|
||||
interface ILocalFiles {
|
||||
path: string,
|
||||
size: number
|
||||
}
|
||||
|
||||
interface IClipboardData {
|
||||
textHTML?: string,
|
||||
textPlain?: string,
|
||||
siyuanHTML?: string,
|
||||
files?: File[],
|
||||
localFiles?: string[]
|
||||
localFiles?: ILocalFiles[],
|
||||
}
|
||||
|
||||
interface IRefDefs {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue