diff --git a/src/public/app/dialogs/note_revisions.js b/src/public/app/dialogs/note_revisions.js
deleted file mode 100644
index 520a1cc99..000000000
--- a/src/public/app/dialogs/note_revisions.js
+++ /dev/null
@@ -1,232 +0,0 @@
-import utils from '../services/utils.js';
-import server from '../services/server.js';
-import toastService from "../services/toast.js";
-import appContext from "../services/app_context.js";
-import libraryLoader from "../services/library_loader.js";
-import openService from "../services/open.js";
-import protectedSessionHolder from "../services/protected_session_holder.js";
-
-const $dialog = $("#note-revisions-dialog");
-const $list = $("#note-revision-list");
-const $listDropdown = $("#note-revision-list-dropdown");
-const $content = $("#note-revision-content");
-const $title = $("#note-revision-title");
-const $titleButtons = $("#note-revision-title-buttons");
-const $eraseAllRevisionsButton = $("#note-revisions-erase-all-revisions-button");
-
-$listDropdown.dropdown();
-
-$listDropdown.parent().on('hide.bs.dropdown', e => {
- // prevent closing dropdown by clicking outside
- if (e.clickEvent) {
- e.preventDefault();
- }
-});
-
-let revisionItems = [];
-let note;
-let noteRevisionId;
-
-export async function showCurrentNoteRevisions() {
- await showNoteRevisionsDialog(appContext.tabManager.getActiveContextNoteId());
-}
-
-export async function showNoteRevisionsDialog(noteId, noteRevisionId) {
- utils.openDialog($dialog);
-
- await loadNoteRevisions(noteId, noteRevisionId);
-}
-
-async function loadNoteRevisions(noteId, noteRevId) {
- $list.empty();
- $content.empty();
- $titleButtons.empty();
-
- note = appContext.tabManager.getActiveContextNote();
- revisionItems = await server.get(`notes/${noteId}/revisions`);
-
- for (const item of revisionItems) {
- $list.append(
- $('')
- .text(item.dateLastEdited.substr(0, 16) + ` (${item.contentLength} bytes)`)
- .attr('data-note-revision-id', item.noteRevisionId)
- .attr('title', 'This revision was last edited on ' + item.dateLastEdited)
- );
- }
-
- $listDropdown.dropdown('show');
-
- noteRevisionId = noteRevId;
-
- if (revisionItems.length > 0) {
- if (!noteRevisionId) {
- noteRevisionId = revisionItems[0].noteRevisionId;
- }
- } else {
- $title.text("No revisions for this note yet...");
- noteRevisionId = null;
- }
-
- $eraseAllRevisionsButton.toggle(revisionItems.length > 0);
-}
-
-$dialog.on('shown.bs.modal', () => {
- $list.find(`[data-note-revision-id="${noteRevisionId}"]`)
- .trigger('focus');
-});
-
-async function setContentPane() {
- const noteRevisionId = $list.find(".active").attr('data-note-revision-id');
-
- const revisionItem = revisionItems.find(r => r.noteRevisionId === noteRevisionId);
-
- $titleButtons.empty();
- $content.empty();
-
- $title.html(revisionItem.title);
-
- const $restoreRevisionButton = $('');
-
- $restoreRevisionButton.on('click', async () => {
- const confirmDialog = await import('../dialogs/confirm.js');
- const text = 'Do you want to restore this revision? This will overwrite current title/content of the note with this revision.';
-
- if (await confirmDialog.confirm(text)) {
- await server.put(`notes/${revisionItem.noteId}/restore-revision/${revisionItem.noteRevisionId}`);
-
- $dialog.modal('hide');
-
- toastService.showMessage('Note revision has been restored.');
- }
- });
-
- const $eraseRevisionButton = $('');
-
- $eraseRevisionButton.on('click', async () => {
- const confirmDialog = await import('../dialogs/confirm.js');
- const text = 'Do you want to delete this revision? This action will delete revision title and content, but still preserve revision metadata.';
-
- if (await confirmDialog.confirm(text)) {
- await server.remove(`notes/${revisionItem.noteId}/revisions/${revisionItem.noteRevisionId}`);
-
- loadNoteRevisions(revisionItem.noteId);
-
- toastService.showMessage('Note revision has been deleted.');
- }
- });
-
- if (!revisionItem.isProtected || protectedSessionHolder.isProtectedSessionAvailable()) {
- $titleButtons
- .append($restoreRevisionButton)
- .append(' ');
- }
-
- $titleButtons
- .append($eraseRevisionButton)
- .append(' ');
-
- const $downloadButton = $('');
-
- $downloadButton.on('click', () => openService.downloadNoteRevision(revisionItem.noteId, revisionItem.noteRevisionId));
-
- if (!revisionItem.isProtected || protectedSessionHolder.isProtectedSessionAvailable()) {
- $titleButtons.append($downloadButton);
- }
-
- const fullNoteRevision = await server.get(`notes/${revisionItem.noteId}/revisions/${revisionItem.noteRevisionId}`);
-
- if (revisionItem.type === 'text') {
- $content.html(fullNoteRevision.content);
-
- if ($content.find('span.math-tex').length > 0) {
- await libraryLoader.requireLibrary(libraryLoader.KATEX);
-
- renderMathInElement($content[0], {trust: true});
- }
- }
- else if (revisionItem.type === 'code') {
- $content.html($("").text(fullNoteRevision.content));
- }
- else if (revisionItem.type === 'image') {
- $content.html($("
")
- // reason why we put this inline as base64 is that we do not want to let user to copy this
- // as a URL to be used in a note. Instead if they copy and paste it into a note, it will be a uploaded as a new note
- .attr("src", `data:${note.mime};base64,` + fullNoteRevision.content)
- .css("max-width", "100%")
- .css("max-height", "100%"));
- }
- else if (revisionItem.type === 'file') {
- const $table = $("
").text("MIME: "), - $(" | ").text(revisionItem.mime) - )) - .append($(" | ||||||
---|---|---|---|---|---|---|---|
").text("File size:"), - $(" | ").text(revisionItem.contentLength + " bytes") - )); - - if (fullNoteRevision.content) { - $table.append($(" | ||||||
').append(
- $(' ').text("Preview:"),
- $('')
- .text(fullNoteRevision.content)
- )
- ));
- }
-
- $content.html($table);
- }
- else if (revisionItem.type === 'canvas') {
- /**
- * FIXME: We load a font called Virgil.wof2, which originates from excalidraw.com
- * REMOVE external dependency!!!! This is defined in the svg in defs.style
- */
- const content = fullNoteRevision.content;
-
- try {
- const data = JSON.parse(content)
- const svg = data.svg || "no svg present."
-
- /**
- * maxWidth: 100% use full width of container but do not enlarge!
- * height:auto to ensure that height scales with width
- */
- const $svgHtml = $(svg).css({maxWidth: "100%", height: "auto"});
- $content.html($(' ').append($svgHtml));
- } catch(err) {
- console.error("error parsing fullNoteRevision.content as JSON", fullNoteRevision.content, err);
- $content.html($(" ").text("Error parsing content. Please check console.error() for more details."));
- }
- }
- else {
- $content.text("Preview isn't available for this note type.");
- }
-}
-
-$eraseAllRevisionsButton.on('click', async () => {
- const confirmDialog = await import('../dialogs/confirm.js');
- const text = 'Do you want to delete all revisions of this note? This action will erase revision title and content, but still preserve revision metadata.';
-
- if (await confirmDialog.confirm(text)) {
- await server.remove(`notes/${note.noteId}/revisions`);
-
- $dialog.modal('hide');
-
- toastService.showMessage('Note revisions has been deleted.');
- }
-});
-
-$list.on('click', '.dropdown-item', e => {
- e.preventDefault();
- return false;
-});
-
-$list.on('focus', '.dropdown-item', e => {
- $list.find('.dropdown-item').each((i, el) => {
- $(el).toggleClass('active', el === e.target);
- });
-
- setContentPane();
-});
diff --git a/src/public/app/layouts/desktop_layout.js b/src/public/app/layouts/desktop_layout.js
index 163c0aeee..f44d292e5 100644
--- a/src/public/app/layouts/desktop_layout.js
+++ b/src/public/app/layouts/desktop_layout.js
@@ -69,6 +69,7 @@ import ImportDialog from "../widgets/dialogs/import.js";
import ExportDialog from "../widgets/dialogs/export.js";
import MarkdownImportDialog from "../widgets/dialogs/markdown_import.js";
import ProtectedSessionPasswordDialog from "../widgets/dialogs/protected_session_password.js";
+import NoteRevisionsDialog from "../widgets/dialogs/note_revisions.js";
export default class DesktopLayout {
constructor(customWidgets) {
@@ -212,6 +213,7 @@ export default class DesktopLayout {
.child(new ImportDialog())
.child(new ExportDialog())
.child(new MarkdownImportDialog())
- .child(new ProtectedSessionPasswordDialog());
+ .child(new ProtectedSessionPasswordDialog())
+ .child(new NoteRevisionsDialog());
}
}
diff --git a/src/public/app/services/entrypoints.js b/src/public/app/services/entrypoints.js
index a794232b7..44033f766 100644
--- a/src/public/app/services/entrypoints.js
+++ b/src/public/app/services/entrypoints.js
@@ -5,7 +5,6 @@ import server from "./server.js";
import appContext from "./app_context.js";
import Component from "../widgets/component.js";
import toastService from "./toast.js";
-import noteCreateService from "./note_create.js";
import ws from "./ws.js";
import bundleService from "./bundle.js";
@@ -19,18 +18,6 @@ export default class Entrypoints extends Component {
jQuery.hotkeys.options.filterContentEditable = false;
jQuery.hotkeys.options.filterTextInputs = false;
}
-
- $(document).on('click', "a[data-action='note-revision']", async event => {
- const linkEl = $(event.target);
- const noteId = linkEl.attr('data-note-path');
- const noteRevisionId = linkEl.attr('data-note-revision-id');
-
- const attributesDialog = await import("../dialogs/note_revisions.js");
-
- attributesDialog.showNoteRevisionsDialog(noteId, noteRevisionId);
-
- return false;
- });
}
openDevToolsCommand() {
diff --git a/src/public/app/services/note_tooltip.js b/src/public/app/services/note_tooltip.js
index c3c974c27..77ec358d6 100644
--- a/src/public/app/services/note_tooltip.js
+++ b/src/public/app/services/note_tooltip.js
@@ -22,8 +22,7 @@ async function mouseEnterHandler() {
const $link = $(this);
if ($link.hasClass("no-tooltip-preview")
- || $link.hasClass("disabled")
- || $link.attr("data-action") === 'note-revision') {
+ || $link.hasClass("disabled")) {
return;
}
diff --git a/src/public/app/services/root_command_executor.js b/src/public/app/services/root_command_executor.js
index 4a275c278..bbaacc67b 100644
--- a/src/public/app/services/root_command_executor.js
+++ b/src/public/app/services/root_command_executor.js
@@ -8,14 +8,6 @@ import options from "./options.js";
import froca from "./froca.js";
export default class RootCommandExecutor extends Component {
- showNoteRevisionsCommand() {
- import("../dialogs/note_revisions.js").then(d => d.showCurrentNoteRevisions());
- }
-
- pasteMarkdownIntoTextCommand() {
- import("../widgets/dialogs/markdown_import.js").then(d => d.importMarkdownInline());
- }
-
editReadOnlyNoteCommand() {
const noteContext = appContext.tabManager.getActiveContext();
noteContext.readOnlyTemporarilyDisabled = true;
diff --git a/src/public/app/widgets/dialogs/markdown_import.js b/src/public/app/widgets/dialogs/markdown_import.js
index d6b514136..bdba6796d 100644
--- a/src/public/app/widgets/dialogs/markdown_import.js
+++ b/src/public/app/widgets/dialogs/markdown_import.js
@@ -64,6 +64,10 @@ export default class MarkdownImportDialog extends BasicWidget {
toastService.showMessage("Markdown content has been imported into the document.");
}
+ async pasteMarkdownIntoTextEvent() {
+ await this.importMarkdownInlineEvent(); // BC with keyboard shortcuts command
+ }
+
async importMarkdownInlineEvent() {
if (appContext.tabManager.getActiveContextNoteType() !== 'text') {
return;
diff --git a/src/public/app/widgets/dialogs/note_revisions.js b/src/public/app/widgets/dialogs/note_revisions.js
new file mode 100644
index 000000000..cda66558d
--- /dev/null
+++ b/src/public/app/widgets/dialogs/note_revisions.js
@@ -0,0 +1,299 @@
+import utils from '../../services/utils.js';
+import server from '../../services/server.js';
+import toastService from "../../services/toast.js";
+import appContext from "../../services/app_context.js";
+import libraryLoader from "../../services/library_loader.js";
+import openService from "../../services/open.js";
+import protectedSessionHolder from "../../services/protected_session_holder.js";
+import BasicWidget from "../basic_widget.js";
+
+const TPL = `
+
+
+
+ `;
+
+export default class NoteRevisionsDialog extends BasicWidget {
+ constructor() {
+ super();
+
+ this.revisionItems = [];
+ this.note = null;
+ this.noteRevisionId = null;
+ }
+
+ doRender() {
+ this.$widget = $(TPL);
+ this.$list = this.$widget.find(".note-revision-list");
+ this.$listDropdown = this.$widget.find(".note-revision-list-dropdown");
+ this.$content = this.$widget.find(".note-revision-content");
+ this.$title = this.$widget.find(".note-revision-title");
+ this.$titleButtons = this.$widget.find(".note-revision-title-buttons");
+ this.$eraseAllRevisionsButton = this.$widget.find(".note-revisions-erase-all-revisions-button");
+
+ this.$listDropdown.dropdown();
+
+ this.$listDropdown.parent().on('hide.bs.dropdown', e => {
+ // prevent closing dropdown by clicking outside
+ if (e.clickEvent) {
+ e.preventDefault();
+ }
+ });
+
+ this.$widget.on('shown.bs.modal', () => {
+ this.$list.find(`[data-note-revision-id="${this.noteRevisionId}"]`)
+ .trigger('focus');
+ });
+
+ this.$eraseAllRevisionsButton.on('click', async () => {
+ const confirmDialog = await import('../../dialogs/confirm.js');
+ const text = 'Do you want to delete all revisions of this note? This action will erase revision title and content, but still preserve revision metadata.';
+
+ if (await confirmDialog.confirm(text)) {
+ await server.remove(`notes/${this.note.noteId}/revisions`);
+
+ this.$widget.modal('hide');
+
+ toastService.showMessage('Note revisions has been deleted.');
+ }
+ });
+
+ this.$list.on('click', '.dropdown-item', e => {
+ e.preventDefault();
+ return false;
+ });
+
+ this.$list.on('focus', '.dropdown-item', e => {
+ this.$list.find('.dropdown-item').each((i, el) => {
+ $(el).toggleClass('active', el === e.target);
+ });
+
+ this.setContentPane();
+ });
+ }
+
+ async showNoteRevisionsEvent({noteId = appContext.tabManager.getActiveContextNoteId()}) {
+ utils.openDialog(this.$widget);
+
+ await this.loadNoteRevisions(noteId);
+ }
+
+ async loadNoteRevisions(noteId) {
+ this.$list.empty();
+ this.$content.empty();
+ this.$titleButtons.empty();
+
+ this.note = appContext.tabManager.getActiveContextNote();
+ this.revisionItems = await server.get(`notes/${noteId}/revisions`);
+
+ for (const item of this.revisionItems) {
+ this.$list.append(
+ $('')
+ .text(item.dateLastEdited.substr(0, 16) + ` (${item.contentLength} bytes)`)
+ .attr('data-note-revision-id', item.noteRevisionId)
+ .attr('title', 'This revision was last edited on ' + item.dateLastEdited)
+ );
+ }
+
+ this.$listDropdown.dropdown('show');
+
+ if (this.revisionItems.length > 0) {
+ if (!this.noteRevisionId) {
+ this.noteRevisionId = this.revisionItems[0].noteRevisionId;
+ }
+ } else {
+ this.$title.text("No revisions for this note yet...");
+ this.noteRevisionId = null;
+ }
+
+ this.$eraseAllRevisionsButton.toggle(this.revisionItems.length > 0);
+ }
+
+ async setContentPane() {
+ const noteRevisionId = this.$list.find(".active").attr('data-note-revision-id');
+
+ const revisionItem = this.revisionItems.find(r => r.noteRevisionId === noteRevisionId);
+
+ this.$titleButtons.empty();
+ this.$content.empty();
+
+ this.$title.html(revisionItem.title);
+
+ const $restoreRevisionButton = $('');
+
+ $restoreRevisionButton.on('click', async () => {
+ const confirmDialog = await import('../../dialogs/confirm.js');
+ const text = 'Do you want to restore this revision? This will overwrite current title/content of the note with this revision.';
+
+ if (await confirmDialog.confirm(text)) {
+ await server.put(`notes/${revisionItem.noteId}/restore-revision/${revisionItem.noteRevisionId}`);
+
+ this.$widget.modal('hide');
+
+ toastService.showMessage('Note revision has been restored.');
+ }
+ });
+
+ const $eraseRevisionButton = $('');
+
+ $eraseRevisionButton.on('click', async () => {
+ const confirmDialog = await import('../../dialogs/confirm.js');
+ const text = 'Do you want to delete this revision? This action will delete revision title and content, but still preserve revision metadata.';
+
+ if (await confirmDialog.confirm(text)) {
+ await server.remove(`notes/${revisionItem.noteId}/revisions/${revisionItem.noteRevisionId}`);
+
+ this.loadNoteRevisions(revisionItem.noteId);
+
+ toastService.showMessage('Note revision has been deleted.');
+ }
+ });
+
+ if (!revisionItem.isProtected || protectedSessionHolder.isProtectedSessionAvailable()) {
+ this.$titleButtons
+ .append($restoreRevisionButton)
+ .append(' ');
+ }
+
+ this.$titleButtons
+ .append($eraseRevisionButton)
+ .append(' ');
+
+ const $downloadButton = $('');
+
+ $downloadButton.on('click', () => openService.downloadNoteRevision(revisionItem.noteId, revisionItem.noteRevisionId));
+
+ if (!revisionItem.isProtected || protectedSessionHolder.isProtectedSessionAvailable()) {
+ this.$titleButtons.append($downloadButton);
+ }
+
+ const fullNoteRevision = await server.get(`notes/${revisionItem.noteId}/revisions/${revisionItem.noteRevisionId}`);
+
+ if (revisionItem.type === 'text') {
+ this.$content.html(fullNoteRevision.content);
+
+ if (this.$content.find('span.math-tex').length > 0) {
+ await libraryLoader.requireLibrary(libraryLoader.KATEX);
+
+ renderMathInElement($content[0], {trust: true});
+ }
+ }
+ else if (revisionItem.type === 'code') {
+ this.$content.html($("
+
+
+ ").text(fullNoteRevision.content)); + } + else if (revisionItem.type === 'image') { + this.$content.html($("
|