mirror of
https://github.com/zadam/trilium.git
synced 2025-03-01 14:22:32 +01:00
code and file note types now sort of work now as well
This commit is contained in:
parent
4fdea77c57
commit
e355b449c4
@ -21,7 +21,12 @@ class Attributes extends Component {
|
||||
}
|
||||
|
||||
reloadAttributes() {
|
||||
this.attributePromise = server.get(`notes/${this.tabContext.note.noteId}/attributes`);
|
||||
if (this.tabContext.note) {
|
||||
this.attributePromise = server.get(`notes/${this.tabContext.note.noteId}/attributes`);
|
||||
}
|
||||
else {
|
||||
this.invalidateAttributes();
|
||||
}
|
||||
}
|
||||
|
||||
async refreshAttributes() {
|
||||
|
@ -14,7 +14,7 @@ class BasicWidget extends Component {
|
||||
/**
|
||||
* for overriding
|
||||
*/
|
||||
async doRender() {}
|
||||
doRender() {}
|
||||
|
||||
toggle(show) {
|
||||
this.$widget.toggle(show);
|
||||
|
@ -4,69 +4,68 @@ import toastService from "../../services/toast.js";
|
||||
import server from "../../services/server.js";
|
||||
import noteDetailService from "../../services/note_detail.js";
|
||||
import keyboardActionService from "../../services/keyboard_actions.js";
|
||||
import TabAwareWidget from "../tab_aware_widget.js";
|
||||
|
||||
const TPL = `
|
||||
<div class="note-detail-code note-detail-component">
|
||||
<div class="note-detail-code-editor"></div>
|
||||
</div>`;
|
||||
|
||||
class NoteDetailCode {
|
||||
class NoteDetailCode extends TabAwareWidget {
|
||||
doRender() {
|
||||
this.$widget = $(TPL);
|
||||
this.$editor = this.$widget.find('.note-detail-code-editor');
|
||||
this.$executeScriptButton = this.$widget.find(".execute-script-button");
|
||||
|
||||
/**
|
||||
* @param {TabContext} ctx
|
||||
*/
|
||||
constructor(ctx) {
|
||||
this.ctx = ctx;
|
||||
this.codeEditor = null;
|
||||
this.$component = ctx.$tabContent.find('.note-detail-code');
|
||||
this.$editorEl = this.$component.find('.note-detail-code-editor');
|
||||
this.$executeScriptButton = ctx.$tabContent.find(".execute-script-button");
|
||||
|
||||
keyboardActionService.setElementActionHandler(ctx.$tabContent, 'RunActiveNote', () => this.executeCurrentNote());
|
||||
keyboardActionService.setElementActionHandler(this.$widget, 'RunActiveNote', () => this.executeCurrentNote());
|
||||
|
||||
this.$executeScriptButton.on('click', () => this.executeCurrentNote());
|
||||
|
||||
this.initialized = this.initEditor();
|
||||
|
||||
return this.$widget;
|
||||
}
|
||||
|
||||
async render() {
|
||||
async initEditor() {
|
||||
await libraryLoader.requireLibrary(libraryLoader.CODE_MIRROR);
|
||||
|
||||
CodeMirror.keyMap.default["Shift-Tab"] = "indentLess";
|
||||
CodeMirror.keyMap.default["Tab"] = "indentMore";
|
||||
|
||||
if (!this.codeEditor) {
|
||||
CodeMirror.keyMap.default["Shift-Tab"] = "indentLess";
|
||||
CodeMirror.keyMap.default["Tab"] = "indentMore";
|
||||
// these conflict with backward/forward navigation shortcuts
|
||||
delete CodeMirror.keyMap.default["Alt-Left"];
|
||||
delete CodeMirror.keyMap.default["Alt-Right"];
|
||||
|
||||
// these conflict with backward/forward navigation shortcuts
|
||||
delete CodeMirror.keyMap.default["Alt-Left"];
|
||||
delete CodeMirror.keyMap.default["Alt-Right"];
|
||||
CodeMirror.modeURL = 'libraries/codemirror/mode/%N/%N.js';
|
||||
|
||||
CodeMirror.modeURL = 'libraries/codemirror/mode/%N/%N.js';
|
||||
|
||||
this.codeEditor = CodeMirror(this.$editorEl[0], {
|
||||
value: "",
|
||||
viewportMargin: Infinity,
|
||||
indentUnit: 4,
|
||||
matchBrackets: true,
|
||||
matchTags: {bothTags: true},
|
||||
highlightSelectionMatches: {showToken: /\w/, annotateScrollbar: false},
|
||||
lint: true,
|
||||
gutters: ["CodeMirror-lint-markers"],
|
||||
lineNumbers: true,
|
||||
tabindex: 100,
|
||||
// we linewrap partly also because without it horizontal scrollbar displays only when you scroll
|
||||
// all the way to the bottom of the note. With line wrap there's no horizontal scrollbar so no problem
|
||||
lineWrapping: true,
|
||||
dragDrop: false // with true the editor inlines dropped files which is not what we expect
|
||||
});
|
||||
|
||||
this.onNoteChange(() => this.ctx.noteChanged());
|
||||
}
|
||||
this.codeEditor = CodeMirror(this.$editor[0], {
|
||||
value: "",
|
||||
viewportMargin: Infinity,
|
||||
indentUnit: 4,
|
||||
matchBrackets: true,
|
||||
matchTags: {bothTags: true},
|
||||
highlightSelectionMatches: {showToken: /\w/, annotateScrollbar: false},
|
||||
lint: true,
|
||||
gutters: ["CodeMirror-lint-markers"],
|
||||
lineNumbers: true,
|
||||
tabindex: 100,
|
||||
// we linewrap partly also because without it horizontal scrollbar displays only when you scroll
|
||||
// all the way to the bottom of the note. With line wrap there's no horizontal scrollbar so no problem
|
||||
lineWrapping: true,
|
||||
dragDrop: false // with true the editor inlines dropped files which is not what we expect
|
||||
});
|
||||
|
||||
//this.onNoteChange(() => this.tabContext.noteChanged());
|
||||
}
|
||||
|
||||
refresh() {
|
||||
// lazy loading above can take time and tab might have been already switched to another note
|
||||
if (this.ctx.note && this.ctx.note.type === 'code') {
|
||||
if (this.tabContext.note && this.tabContext.note.type === 'code') {
|
||||
// CodeMirror breaks pretty badly on null so even though it shouldn't happen (guarded by consistency check)
|
||||
// we provide fallback
|
||||
this.codeEditor.setValue(this.ctx.note.content || "");
|
||||
this.codeEditor.setValue(this.tabContext.note.content || "");
|
||||
|
||||
const info = CodeMirror.findModeByMIME(this.ctx.note.mime);
|
||||
const info = CodeMirror.findModeByMIME(this.tabContext.note.mime);
|
||||
|
||||
if (info) {
|
||||
this.codeEditor.setOption("mode", info.mime);
|
||||
@ -78,7 +77,7 @@ class NoteDetailCode {
|
||||
}
|
||||
|
||||
show() {
|
||||
this.$component.show();
|
||||
this.$widget.show();
|
||||
|
||||
if (this.codeEditor) { // show can be called before render
|
||||
this.codeEditor.refresh();
|
||||
@ -95,19 +94,19 @@ class NoteDetailCode {
|
||||
|
||||
async executeCurrentNote() {
|
||||
// ctrl+enter is also used elsewhere so make sure we're running only when appropriate
|
||||
if (this.ctx.note.type !== 'code') {
|
||||
if (this.tabContext.note.type !== 'code') {
|
||||
return;
|
||||
}
|
||||
|
||||
// make sure note is saved so we load latest changes
|
||||
await noteDetailService.saveNotesIfChanged();
|
||||
|
||||
if (this.ctx.note.mime.endsWith("env=frontend")) {
|
||||
await bundleService.getAndExecuteBundle(this.ctx.note.noteId);
|
||||
if (this.tabContext.note.mime.endsWith("env=frontend")) {
|
||||
await bundleService.getAndExecuteBundle(this.tabContext.note.noteId);
|
||||
}
|
||||
|
||||
if (this.ctx.note.mime.endsWith("env=backend")) {
|
||||
await server.post('script/run/' + this.ctx.note.noteId);
|
||||
if (this.tabContext.note.mime.endsWith("env=backend")) {
|
||||
await server.post('script/run/' + this.tabContext.note.noteId);
|
||||
}
|
||||
|
||||
toastService.showMessage("Note executed");
|
||||
@ -124,7 +123,7 @@ class NoteDetailCode {
|
||||
}
|
||||
|
||||
scrollToTop() {
|
||||
this.$component.scrollTop(0);
|
||||
this.$widget.scrollTop(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,24 +2,60 @@ import utils from "../../services/utils.js";
|
||||
import server from "../../services/server.js";
|
||||
import toastService from "../../services/toast.js";
|
||||
import noteDetailService from "../../services/note_detail.js";
|
||||
import TabAwareWidget from "../tab_aware_widget.js";
|
||||
|
||||
class NoteDetailFile {
|
||||
/**
|
||||
* @param {TabContext} ctx
|
||||
*/
|
||||
constructor(ctx) {
|
||||
this.ctx = ctx;
|
||||
this.$component = ctx.$tabContent.find('.note-detail-file');
|
||||
this.$fileNoteId = ctx.$tabContent.find(".file-note-id");
|
||||
this.$fileName = ctx.$tabContent.find(".file-filename");
|
||||
this.$fileType = ctx.$tabContent.find(".file-filetype");
|
||||
this.$fileSize = ctx.$tabContent.find(".file-filesize");
|
||||
this.$previewRow = ctx.$tabContent.find(".file-preview-row");
|
||||
this.$previewContent = ctx.$tabContent.find(".file-preview-content");
|
||||
this.$downloadButton = ctx.$tabContent.find(".file-download");
|
||||
this.$openButton = ctx.$tabContent.find(".file-open");
|
||||
this.$uploadNewRevisionButton = ctx.$tabContent.find(".file-upload-new-revision");
|
||||
this.$uploadNewRevisionInput = ctx.$tabContent.find(".file-upload-new-revision-input");
|
||||
const TPL = `
|
||||
<div class="note-detail-file note-detail-component">
|
||||
<table class="file-table">
|
||||
<tr>
|
||||
<th>Note ID:</th>
|
||||
<td class="file-note-id"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Original file name:</th>
|
||||
<td class="file-filename"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>File type:</th>
|
||||
<td class="file-filetype"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>File size:</th>
|
||||
<td class="file-filesize"></td>
|
||||
</tr>
|
||||
<tr class="file-preview-row">
|
||||
<th>Preview:</th>
|
||||
<td>
|
||||
<pre class="file-preview-content"></pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<button class="file-download btn btn-sm btn-primary" type="button">Download</button>
|
||||
|
||||
<button class="file-open btn btn-sm btn-primary" type="button">Open</button>
|
||||
|
||||
<button class="file-upload-new-revision btn btn-sm btn-primary">Upload new revision</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<input type="file" class="file-upload-new-revision-input" style="display: none">
|
||||
</div>`;
|
||||
|
||||
class NoteDetailFile extends TabAwareWidget{
|
||||
doRender() {
|
||||
this.$widget = $(TPL);
|
||||
this.$fileNoteId = this.$widget.find(".file-note-id");
|
||||
this.$fileName = this.$widget.find(".file-filename");
|
||||
this.$fileType = this.$widget.find(".file-filetype");
|
||||
this.$fileSize = this.$widget.find(".file-filesize");
|
||||
this.$previewRow = this.$widget.find(".file-preview-row");
|
||||
this.$previewContent = this.$widget.find(".file-preview-content");
|
||||
this.$downloadButton = this.$widget.find(".file-download");
|
||||
this.$openButton = this.$widget.find(".file-open");
|
||||
this.$uploadNewRevisionButton = this.$widget.find(".file-upload-new-revision");
|
||||
this.$uploadNewRevisionInput = this.$widget.find(".file-upload-new-revision-input");
|
||||
|
||||
this.$downloadButton.on('click', () => utils.download(this.getFileUrl()));
|
||||
|
||||
@ -46,7 +82,7 @@ class NoteDetailFile {
|
||||
formData.append('upload', fileToUpload);
|
||||
|
||||
const result = await $.ajax({
|
||||
url: baseApiUrl + 'notes/' + this.ctx.note.noteId + '/file',
|
||||
url: baseApiUrl + 'notes/' + this.tabContext.note.noteId + '/file',
|
||||
headers: server.getHeaders(),
|
||||
data: formData,
|
||||
type: 'PUT',
|
||||
@ -64,33 +100,35 @@ class NoteDetailFile {
|
||||
toastService.showError("Upload of a new file revision failed.");
|
||||
}
|
||||
});
|
||||
|
||||
return this.$widget;
|
||||
}
|
||||
|
||||
async render() {
|
||||
const attributes = await server.get('notes/' + this.ctx.note.noteId + '/attributes');
|
||||
async refresh() {
|
||||
const attributes = await server.get('notes/' + this.tabContext.note.noteId + '/attributes');
|
||||
const attributeMap = utils.toObject(attributes, l => [l.name, l.value]);
|
||||
|
||||
this.$component.show();
|
||||
this.$widget.show();
|
||||
|
||||
this.$fileNoteId.text(this.ctx.note.noteId);
|
||||
this.$fileNoteId.text(this.tabContext.note.noteId);
|
||||
this.$fileName.text(attributeMap.originalFileName || "?");
|
||||
this.$fileSize.text(this.ctx.note.contentLength + " bytes");
|
||||
this.$fileType.text(this.ctx.note.mime);
|
||||
this.$fileSize.text(this.tabContext.note.contentLength + " bytes");
|
||||
this.$fileType.text(this.tabContext.note.mime);
|
||||
|
||||
if (this.ctx.note.content) {
|
||||
if (this.tabContext.note.content) {
|
||||
this.$previewRow.show();
|
||||
this.$previewContent.text(this.ctx.note.content);
|
||||
this.$previewContent.text(this.tabContext.note.content);
|
||||
}
|
||||
else {
|
||||
this.$previewRow.hide();
|
||||
}
|
||||
|
||||
// open doesn't work for protected notes since it works through browser which isn't in protected session
|
||||
this.$openButton.toggle(!this.ctx.note.isProtected);
|
||||
this.$openButton.toggle(!this.tabContext.note.isProtected);
|
||||
}
|
||||
|
||||
getFileUrl() {
|
||||
return utils.getUrlForDownload("api/notes/" + this.ctx.note.noteId + "/download");
|
||||
return utils.getUrlForDownload("api/notes/" + this.tabContext.note.noteId + "/download");
|
||||
}
|
||||
|
||||
show() {}
|
||||
|
@ -1,37 +0,0 @@
|
||||
<div class="note-detail-file note-detail-component">
|
||||
<table class="file-table">
|
||||
<tr>
|
||||
<th>Note ID:</th>
|
||||
<td class="file-note-id"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Original file name:</th>
|
||||
<td class="file-filename"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>File type:</th>
|
||||
<td class="file-filetype"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>File size:</th>
|
||||
<td class="file-filesize"></td>
|
||||
</tr>
|
||||
<tr class="file-preview-row">
|
||||
<th>Preview:</th>
|
||||
<td>
|
||||
<pre class="file-preview-content"></pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<button class="file-download btn btn-sm btn-primary" type="button">Download</button>
|
||||
|
||||
<button class="file-open btn btn-sm btn-primary" type="button">Open</button>
|
||||
|
||||
<button class="file-upload-new-revision btn btn-sm btn-primary">Upload new revision</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<input type="file" class="file-upload-new-revision-input" style="display: none">
|
||||
</div>
|
@ -66,8 +66,6 @@
|
||||
|
||||
<% include details/render.ejs %>
|
||||
|
||||
<% include details/file.ejs %>
|
||||
|
||||
<% include details/image.ejs %>
|
||||
|
||||
<% include details/relation_map.ejs %>
|
||||
|
Loading…
x
Reference in New Issue
Block a user