mirror of
				https://github.com/zadam/trilium.git
				synced 2025-11-03 20:06:08 +01:00 
			
		
		
		
	code and file note types now sort of work now as well
This commit is contained in:
		@@ -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 %>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user