diff --git a/src/public/javascripts/services/attributes.js b/src/public/javascripts/services/attributes.js
index e1ca025fc..54f8702ef 100644
--- a/src/public/javascripts/services/attributes.js
+++ b/src/public/javascripts/services/attributes.js
@@ -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() {
diff --git a/src/public/javascripts/widgets/basic_widget.js b/src/public/javascripts/widgets/basic_widget.js
index 2f5c5a40b..4c2df5cb5 100644
--- a/src/public/javascripts/widgets/basic_widget.js
+++ b/src/public/javascripts/widgets/basic_widget.js
@@ -14,7 +14,7 @@ class BasicWidget extends Component {
/**
* for overriding
*/
- async doRender() {}
+ doRender() {}
toggle(show) {
this.$widget.toggle(show);
diff --git a/src/public/javascripts/widgets/detail/note_detail_code.js b/src/public/javascripts/widgets/detail/note_detail_code.js
index 4b5acc10b..50a6b5d82 100644
--- a/src/public/javascripts/widgets/detail/note_detail_code.js
+++ b/src/public/javascripts/widgets/detail/note_detail_code.js
@@ -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 = `
`;
-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);
}
}
diff --git a/src/public/javascripts/widgets/detail/note_detail_file.js b/src/public/javascripts/widgets/detail/note_detail_file.js
index 69321da7b..6060be826 100644
--- a/src/public/javascripts/widgets/detail/note_detail_file.js
+++ b/src/public/javascripts/widgets/detail/note_detail_file.js
@@ -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 = `
+
+
+
+ Note ID:
+
+
+
+ Original file name:
+
+
+
+ File type:
+
+
+
+ File size:
+
+
+
+ Preview:
+
+
+
+
+
+
+ Download
+
+ Open
+
+ Upload new revision
+
+
+
+
+
+
`;
+
+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() {}
diff --git a/src/views/details/file.ejs b/src/views/details/file.ejs
deleted file mode 100644
index dd96c9e4d..000000000
--- a/src/views/details/file.ejs
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
- Note ID:
-
-
-
- Original file name:
-
-
-
- File type:
-
-
-
- File size:
-
-
-
- Preview:
-
-
-
-
-
-
- Download
-
- Open
-
- Upload new revision
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/views/mobile.ejs b/src/views/mobile.ejs
index 2591c7f45..fd2971c16 100644
--- a/src/views/mobile.ejs
+++ b/src/views/mobile.ejs
@@ -66,8 +66,6 @@
<% include details/render.ejs %>
- <% include details/file.ejs %>
-
<% include details/image.ejs %>
<% include details/relation_map.ejs %>