mirror of
https://github.com/zadam/trilium.git
synced 2025-03-01 14:22:32 +01:00
drag & drop multi file upload to note tree
This commit is contained in:
parent
b25deea21d
commit
936f85c09e
@ -13,6 +13,8 @@ const LABEL_DEFINITION = 'label-definition';
|
|||||||
const RELATION = 'relation';
|
const RELATION = 'relation';
|
||||||
const RELATION_DEFINITION = 'relation-definition';
|
const RELATION_DEFINITION = 'relation-definition';
|
||||||
|
|
||||||
|
const STRING_MIME_TYPES = ["application/x-javascript"];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This represents a Note which is a central object in the Trilium Notes project.
|
* This represents a Note which is a central object in the Trilium Notes project.
|
||||||
*
|
*
|
||||||
@ -132,7 +134,9 @@ class Note extends Entity {
|
|||||||
|
|
||||||
/** @returns {boolean} true if the note has string content (not binary) */
|
/** @returns {boolean} true if the note has string content (not binary) */
|
||||||
isStringNote() {
|
isStringNote() {
|
||||||
return ["text", "code", "relation-map", "search"].includes(this.type) || this.mime.startsWith('text/');
|
return ["text", "code", "relation-map", "search"].includes(this.type)
|
||||||
|
|| this.mime.startsWith('text/')
|
||||||
|
|| STRING_MIME_TYPES.includes(this.mime);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @returns {string} JS script environment - either "frontend" or "backend" */
|
/** @returns {string} JS script environment - either "frontend" or "backend" */
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import treeService from './tree.js';
|
import treeService from './tree.js';
|
||||||
import treeChangesService from './branches.js';
|
import treeChangesService from './branches.js';
|
||||||
|
import fileService from '../services/file.js';
|
||||||
|
|
||||||
const dragAndDropSetup = {
|
const dragAndDropSetup = {
|
||||||
autoExpandMS: 600,
|
autoExpandMS: 600,
|
||||||
@ -32,23 +33,28 @@ const dragAndDropSetup = {
|
|||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
dragEnter: (node, data) => true, // allow drop on any node
|
dragEnter: (node, data) => true, // allow drop on any node
|
||||||
|
dragOver: (node, data) => true,
|
||||||
dragDrop: (node, data) => {
|
dragDrop: (node, data) => {
|
||||||
// This function MUST be defined to enable dropping of items on the tree.
|
const dataTransfer = data.dataTransfer;
|
||||||
// data.hitMode is 'before', 'after', or 'over'.
|
|
||||||
|
|
||||||
const selectedNodes = treeService.getSelectedNodes();
|
if (dataTransfer && dataTransfer.files && dataTransfer.files.length > 0) {
|
||||||
|
fileService.uploadFiles(node.data.noteId, dataTransfer.files);
|
||||||
if (data.hitMode === "before") {
|
|
||||||
treeChangesService.moveBeforeNode(selectedNodes, node);
|
|
||||||
}
|
|
||||||
else if (data.hitMode === "after") {
|
|
||||||
treeChangesService.moveAfterNode(selectedNodes, node);
|
|
||||||
}
|
|
||||||
else if (data.hitMode === "over") {
|
|
||||||
treeChangesService.moveToNode(selectedNodes, node);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new Error("Unknown hitMode=" + data.hitMode);
|
// This function MUST be defined to enable dropping of items on the tree.
|
||||||
|
// data.hitMode is 'before', 'after', or 'over'.
|
||||||
|
|
||||||
|
const selectedNodes = treeService.getSelectedNodes();
|
||||||
|
|
||||||
|
if (data.hitMode === "before") {
|
||||||
|
treeChangesService.moveBeforeNode(selectedNodes, node);
|
||||||
|
} else if (data.hitMode === "after") {
|
||||||
|
treeChangesService.moveAfterNode(selectedNodes, node);
|
||||||
|
} else if (data.hitMode === "over") {
|
||||||
|
treeChangesService.moveToNode(selectedNodes, node);
|
||||||
|
} else {
|
||||||
|
throw new Error("Unknown hitMode=" + data.hitMode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -161,7 +161,7 @@ function registerEntrypoints() {
|
|||||||
|
|
||||||
$("#note-title").bind('keydown', 'return', () => $("#note-detail-text").focus());
|
$("#note-title").bind('keydown', 'return', () => $("#note-detail-text").focus());
|
||||||
|
|
||||||
$("#upload-file-button").click(fileService.uploadFile);
|
$("#upload-file-button").click(fileService.openUploadFileDialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -2,32 +2,46 @@ import noteDetailService from "./note_detail.js";
|
|||||||
import treeService from "./tree.js";
|
import treeService from "./tree.js";
|
||||||
import server from "./server.js";
|
import server from "./server.js";
|
||||||
|
|
||||||
function uploadFile() {
|
function openUploadFileDialog() {
|
||||||
$("#file-upload").trigger('click');
|
$("#file-upload").trigger('click');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function uploadFiles(parentNoteId, files) {
|
||||||
|
let noteId;
|
||||||
|
|
||||||
|
for (const file of files) {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('upload', file);
|
||||||
|
|
||||||
|
const resp = await $.ajax({
|
||||||
|
url: baseApiUrl + 'notes/' + parentNoteId + '/upload',
|
||||||
|
headers: server.getHeaders(),
|
||||||
|
data: formData,
|
||||||
|
type: 'POST',
|
||||||
|
contentType: false, // NEEDED, DON'T OMIT THIS
|
||||||
|
processData: false, // NEEDED, DON'T OMIT THIS
|
||||||
|
});
|
||||||
|
|
||||||
|
noteId = resp.noteId;
|
||||||
|
}
|
||||||
|
|
||||||
|
await treeService.reload();
|
||||||
|
|
||||||
|
await treeService.activateNote(noteId);
|
||||||
|
}
|
||||||
|
|
||||||
$("#file-upload").change(async function() {
|
$("#file-upload").change(async function() {
|
||||||
const formData = new FormData();
|
const files = Array.from(this.files); // clone since we'll reset it just below
|
||||||
formData.append('upload', this.files[0]);
|
|
||||||
|
|
||||||
// this is done to reset the field otherwise triggering import same file again would not work
|
// this is done to reset the field otherwise triggering import same file again would not work
|
||||||
// https://github.com/zadam/trilium/issues/388
|
// https://github.com/zadam/trilium/issues/388
|
||||||
$("#file-upload").val('');
|
$("#file-upload").val('');
|
||||||
|
|
||||||
const resp = await $.ajax({
|
const parentNoteId = noteDetailService.getCurrentNoteId();
|
||||||
url: baseApiUrl + 'notes/' + noteDetailService.getCurrentNoteId() + '/upload',
|
await uploadFiles(parentNoteId, files);
|
||||||
headers: server.getHeaders(),
|
|
||||||
data: formData,
|
|
||||||
type: 'POST',
|
|
||||||
contentType: false, // NEEDED, DON'T OMIT THIS
|
|
||||||
processData: false, // NEEDED, DON'T OMIT THIS
|
|
||||||
});
|
|
||||||
|
|
||||||
await treeService.reload();
|
|
||||||
|
|
||||||
await treeService.activateNote(resp.noteId);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
uploadFile
|
openUploadFileDialog,
|
||||||
|
uploadFiles
|
||||||
}
|
}
|
@ -27,8 +27,13 @@ async function show() {
|
|||||||
$fileSize.text((attributeMap.fileSize || "?") + " bytes");
|
$fileSize.text((attributeMap.fileSize || "?") + " bytes");
|
||||||
$fileType.text(currentNote.mime);
|
$fileType.text(currentNote.mime);
|
||||||
|
|
||||||
$previewRow.toggle(!!currentNote.noteContent.content);
|
if (currentNote.noteContent && currentNote.noteContent.content) {
|
||||||
$previewContent.text(currentNote.noteContent.content);
|
$previewRow.show();
|
||||||
|
$previewContent.text(currentNote.noteContent.content);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$previewRow.hide();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$downloadButton.click(() => utils.download(getFileUrl()));
|
$downloadButton.click(() => utils.download(getFileUrl()));
|
||||||
|
2
src/public/libraries/ckeditor/ckeditor.js
vendored
2
src/public/libraries/ckeditor/ckeditor.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -9,7 +9,7 @@
|
|||||||
<div id="note-detail-text" class="note-detail-component" tabindex="10000"></div>
|
<div id="note-detail-text" class="note-detail-component" tabindex="10000"></div>
|
||||||
|
|
||||||
<div id="note-detail-code" class="note-detail-component"></div>
|
<div id="note-detail-code" class="note-detail-component"></div>
|
||||||
<input type="file" id="file-upload" style="display: none" />
|
<input type="file" id="file-upload" multiple style="display: none" />
|
||||||
|
|
||||||
<% include search.ejs %>
|
<% include search.ejs %>
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user