-
@@ -211,6 +206,8 @@
this.cleanUpPreviouslyDraggedTabs()
this.layoutTabs()
this.setupDraggabilly()
+
+ return tabEl
}
setTabCloseEventListener(tabEl) {
@@ -251,15 +248,6 @@
updateTab(tabEl, tabProperties) {
tabEl.querySelector('.chrome-tab-title').textContent = tabProperties.title
- const faviconEl = tabEl.querySelector('.chrome-tab-favicon')
- if (tabProperties.favicon) {
- faviconEl.style.backgroundImage = `url('${ tabProperties.favicon }')`
- faviconEl.removeAttribute('hidden', '')
- } else {
- faviconEl.setAttribute('hidden', '')
- faviconEl.removeAttribute('style')
- }
-
if (tabProperties.id) {
tabEl.setAttribute('data-tab-id', tabProperties.id)
}
diff --git a/src/public/javascripts/desktop.js b/src/public/javascripts/desktop.js
index b333e9385..a08e51c7e 100644
--- a/src/public/javascripts/desktop.js
+++ b/src/public/javascripts/desktop.js
@@ -157,13 +157,3 @@ noteTypeService.init();
linkService.init();
noteAutocompleteService.init();
-
-$(document).ready(() => {
- const el = $('.chrome-tabs')[0];
- const chromeTabs = new ChromeTabs();
- chromeTabs.init(el);
-
- el.addEventListener('activeTabChange', ({detail}) => console.log('Active tab changed', detail.tabEl));
- el.addEventListener('tabAdd', ({detail}) => console.log('Tab added', detail.tabEl));
- el.addEventListener('tabRemove', ({detail}) => console.log('Tab removed', detail.tabEl));
-});
\ No newline at end of file
diff --git a/src/public/javascripts/services/attributes.js b/src/public/javascripts/services/attributes.js
index 200025602..cb7f7a50d 100644
--- a/src/public/javascripts/services/attributes.js
+++ b/src/public/javascripts/services/attributes.js
@@ -36,6 +36,9 @@ async function getAttributes() {
}
async function showAttributes() {
+ // FIXME tabs
+ return;
+
$promotedAttributesContainer.empty();
$attributeList.hide();
$attributeListInner.empty();
diff --git a/src/public/javascripts/services/link.js b/src/public/javascripts/services/link.js
index 24aef28d3..8b2a5e524 100644
--- a/src/public/javascripts/services/link.js
+++ b/src/public/javascripts/services/link.js
@@ -106,9 +106,9 @@ function init() {
// of opening the link in new window/tab
$(document).on('click', "a[data-action='note']", goToLink);
$(document).on('click', 'div.popover-content a, div.ui-tooltip-content a', goToLink);
-$(document).on('dblclick', '#note-detail-text a', goToLink);
-$(document).on('click', '#note-detail-render a', goToLink);
-$(document).on('click', '#note-detail-text.ck-read-only a', goToLink);
+$(document).on('dblclick', '.note-detail-text a', goToLink);
+$(document).on('click', '.note-detail-render a', goToLink);
+$(document).on('click', '.note-detail-text.ck-read-only a', goToLink);
$(document).on('click', 'span.ck-button__label', e => {
// this is a link preview dialog from CKEditor link editing
// for some reason clicked element is span
diff --git a/src/public/javascripts/services/note_context.js b/src/public/javascripts/services/note_context.js
index 76ecb3dfc..eba3294ad 100644
--- a/src/public/javascripts/services/note_context.js
+++ b/src/public/javascripts/services/note_context.js
@@ -13,7 +13,15 @@ import noteDetailSearch from "./note_detail_search.js";
import noteDetailRender from "./note_detail_render.js";
import noteDetailRelationMap from "./note_detail_relation_map.js";
-const $noteTabsContainer = $("#note-tab-container");
+const $noteTabContentsContainer = $("#note-tab-container");
+
+const el = $('.chrome-tabs')[0];
+const chromeTabs = new ChromeTabs();
+chromeTabs.init(el);
+
+el.addEventListener('activeTabChange', ({detail}) => console.log('Active tab changed', detail.tabEl));
+el.addEventListener('tabAdd', ({detail}) => console.log('Tab added', detail.tabEl));
+el.addEventListener('tabRemove', ({detail}) => console.log('Tab removed', detail.tabEl));
const componentClasses = {
'code': noteDetailCode,
@@ -26,17 +34,17 @@ const componentClasses = {
};
class NoteContext {
- constructor(noteId) {
+ constructor(note) {
/** @type {NoteFull} */
- this.note = null;
- this.noteId = noteId;
- this.$noteTab = $noteTabsContainer.find(`[data-note-id="${noteId}"]`);
- this.$noteTitle = this.$noteTab.find(".note-title");
- this.$noteDetailComponents = this.$noteTab.find(".note-detail-component");
- this.$protectButton = this.$noteTab.find(".protect-button");
- this.$unprotectButton = this.$noteTab.find(".unprotect-button");
- this.$childrenOverview = this.$noteTab.find(".children-overview");
- this.$scriptArea = this.$noteTab.find(".note-detail-script-area");
+ this.note = note;
+ this.noteId = note.noteId;
+ this.$noteTabContent = $noteTabContentsContainer.find(`[data-note-id="${this.noteId}"]`);
+ this.$noteTitle = this.$noteTabContent.find(".note-title");
+ this.$noteDetailComponents = this.$noteTabContent.find(".note-detail-component");
+ this.$protectButton = this.$noteTabContent.find(".protect-button");
+ this.$unprotectButton = this.$noteTabContent.find(".unprotect-button");
+ this.$childrenOverview = this.$noteTabContent.find(".children-overview");
+ this.$scriptArea = this.$noteTabContent.find(".note-detail-script-area");
this.isNoteChanged = false;
this.components = {};
@@ -47,6 +55,19 @@ class NoteContext {
treeService.setNoteTitle(this.noteId, title);
});
+
+ this.tab = chromeTabs.addTab({
+ title: note.title,
+ favicon: false
+ });
+ }
+
+ setNote(note) {
+ this.noteId = note.noteId;
+ this.note = note;
+ this.$noteTabContent.attr('data-note-id', note.noteId);
+
+ chromeTabs.updateTab(this.tab, {title: note.title});
}
getComponent(type) {
@@ -135,20 +156,20 @@ class NoteContext {
}
updateNoteView() {
- this.$noteTab.toggleClass("protected", this.note.isProtected);
+ this.$noteTabContent.toggleClass("protected", this.note.isProtected);
this.$protectButton.toggleClass("active", this.note.isProtected);
this.$protectButton.prop("disabled", this.note.isProtected);
this.$unprotectButton.toggleClass("active", !this.note.isProtected);
this.$unprotectButton.prop("disabled", !this.note.isProtected || !protectedSessionHolder.isProtectedSessionAvailable());
- for (const clazz of Array.from(this.$noteTab[0].classList)) { // create copy to safely iterate over while removing classes
+ for (const clazz of Array.from(this.$noteTabContent[0].classList)) { // create copy to safely iterate over while removing classes
if (clazz.startsWith("type-") || clazz.startsWith("mime-")) {
- this.$noteTab.removeClass(clazz);
+ this.$noteTabContent.removeClass(clazz);
}
}
- this.$noteTab.addClass(utils.getNoteTypeClass(this.note.type));
- this.$noteTab.addClass(utils.getMimeTypeClass(this.note.mime));
+ this.$noteTabContent.addClass(utils.getNoteTypeClass(this.note.type));
+ this.$noteTabContent.addClass(utils.getMimeTypeClass(this.note.mime));
}
}
diff --git a/src/public/javascripts/services/note_detail.js b/src/public/javascripts/services/note_detail.js
index 1d737690f..aba0b62bc 100644
--- a/src/public/javascripts/services/note_detail.js
+++ b/src/public/javascripts/services/note_detail.js
@@ -13,7 +13,7 @@ import attributeService from "./attributes.js";
import utils from "./utils.js";
import importDialog from "../dialogs/import.js";
-const $noteTabsContainer = $("#note-tab-container");
+const $noteTabContentsContainer = $("#note-tab-container");
const $savedIndicator = $("#saved-indicator");
let noteChangeDisabled = false;
@@ -43,18 +43,11 @@ async function reload() {
await loadNoteDetail(getActiveNoteId());
}
+async function openInTab(noteId) {
+ await loadNoteDetail(noteId, true);
+}
+
async function switchToNote(noteId) {
- if (Object.keys(noteContexts).length === 0) {
- const tabContent = $("#note-tab-content-template").clone();
-
- tabContent.removeAttr('id');
- tabContent.attr('data-note-id', noteId);
-
- $noteTabsContainer.append(tabContent);
-
- noteContexts[noteId] = new NoteContext(noteId);
- }
-
//if (getActiveNoteId() !== noteId) {
await saveNotesIfChanged();
@@ -71,7 +64,7 @@ function onNoteChange(func) {
}
async function saveNotesIfChanged() {
- for (const ctx of Object.values(noteContexts)) {
+ for (const ctx of noteContexts) {
await ctx.saveNoteIfChanged();
}
@@ -93,13 +86,15 @@ async function handleProtectedSession() {
return newSessionCreated;
}
-/** @type {Object.
} */
-const noteContexts = {};
+/** @type {NoteContext[]} */
+const noteContexts = [];
/** @returns {NoteContext} */
function getContext(noteId) {
- if (noteId in noteContexts) {
- return noteContexts[noteId];
+ const noteContext = noteContexts.find(nc => nc.noteId === noteId);
+
+ if (noteContext) {
+ return noteContext;
}
else {
throw new Error(`Can't find note context for ${noteId}`);
@@ -108,21 +103,36 @@ function getContext(noteId) {
/** @returns {NoteContext} */
function getActiveContext() {
- const currentTreeNode = treeService.getActiveNode();
-
- return getContext(currentTreeNode.data.noteId);
-}
-
-function showTab(noteId) {
- for (const ctx of Object.values(noteContexts)) {
- ctx.$noteTab.toggle(ctx.noteId === noteId);
+ for (const ctx of noteContexts) {
+ if (ctx.$noteTabContent.is(":visible")) {
+ return ctx;
+ }
}
}
-async function loadNoteDetail(noteId) {
- const ctx = getContext(noteId);
+function showTab(noteId) {
+ for (const ctx of noteContexts) {
+ ctx.$noteTabContent.toggle(ctx.noteId === noteId);
+ }
+}
+
+async function loadNoteDetail(noteId, newTab = false) {
const loadedNote = await loadNote(noteId);
+ if (noteContexts.length === 0 || newTab) {
+ const tabContent = $("#note-tab-content-template").clone();
+
+ tabContent.removeAttr('id');
+ tabContent.attr('data-note-id', noteId);
+
+ $noteTabContentsContainer.append(tabContent);
+
+ noteContexts.push(new NoteContext(loadedNote));
+ }
+
+ const ctx = getActiveContext();
+ ctx.setNote(loadedNote);
+
// we will try to render the new note only if it's still the active one in the tree
// this is useful when user quickly switches notes (by e.g. holding down arrow) so that we don't
// try to render all those loaded notes one after each other. This only guarantees that correct note
@@ -247,11 +257,11 @@ messagingService.subscribeToSyncMessages(syncData => {
}
});
-$noteTabsContainer.on("dragover", e => e.preventDefault());
+$noteTabContentsContainer.on("dragover", e => e.preventDefault());
-$noteTabsContainer.on("dragleave", e => e.preventDefault());
+$noteTabContentsContainer.on("dragleave", e => e.preventDefault());
-$noteTabsContainer.on("drop", e => {
+$noteTabContentsContainer.on("drop", e => {
importDialog.uploadFiles(getActiveNoteId(), e.originalEvent.dataTransfer.files, {
safeImport: true,
shrinkImages: true,
@@ -269,6 +279,7 @@ setInterval(saveNotesIfChanged, 3000);
export default {
reload,
+ openInTab,
switchToNote,
loadNote,
getActiveNote,
diff --git a/src/public/javascripts/services/note_detail_file.js b/src/public/javascripts/services/note_detail_file.js
index c32c63e03..98319f522 100644
--- a/src/public/javascripts/services/note_detail_file.js
+++ b/src/public/javascripts/services/note_detail_file.js
@@ -3,65 +3,74 @@ import server from "./server.js";
import protectedSessionHolder from "./protected_session_holder.js";
import noteDetailService from "./note_detail.js";
-const $component = $('#note-detail-file');
+class NoteDetailFile {
+ /**
+ * @param {NoteContext} ctx
+ */
+ constructor(ctx) {
+ this.$component = ctx.$noteTabContent.find('.note-detail-file');
+ this.$fileNoteId = ctx.$noteTabContent.find(".file-note-id");
+ this.$fileName = ctx.$noteTabContent.find(".file-filename");
+ this.$fileType = ctx.$noteTabContent.find(".file-filetype");
+ this.$fileSize = ctx.$noteTabContent.find(".file-filesize");
+ this.$previewRow = ctx.$noteTabContent.find(".file-preview-row");
+ this.$previewContent = ctx.$noteTabContent.find(".file-preview-content");
+ this.$downloadButton = ctx.$noteTabContent.find(".file-download");
+ this.$openButton = ctx.$noteTabContent.find(".file-open");
-const $fileNoteId = $("#file-note-id");
-const $fileName = $("#file-filename");
-const $fileType = $("#file-filetype");
-const $fileSize = $("#file-filesize");
-const $previewRow = $("#file-preview-row");
-const $previewContent = $("#file-preview-content");
-const $downloadButton = $("#file-download");
-const $openButton = $("#file-open");
+ this.$downloadButton.click(() => utils.download(this.getFileUrl()));
-async function show() {
- const activeNote = noteDetailService.getActiveNote();
+ this.$openButton.click(() => {
+ if (utils.isElectron()) {
+ const open = require("open");
- const attributes = await server.get('notes/' + activeNote.noteId + '/attributes');
- const attributeMap = utils.toObject(attributes, l => [l.name, l.value]);
-
- $component.show();
-
- $fileNoteId.text(activeNote.noteId);
- $fileName.text(attributeMap.originalFileName || "?");
- $fileSize.text((attributeMap.fileSize || "?") + " bytes");
- $fileType.text(activeNote.mime);
-
- if (activeNote.content) {
- $previewRow.show();
- $previewContent.text(activeNote.content);
- }
- else {
- $previewRow.hide();
+ open(this.getFileUrl());
+ }
+ else {
+ window.location.href = this.getFileUrl();
+ }
+ });
}
- // open doesn't work for protected notes since it works through browser which isn't in protected session
- $openButton.toggle(!activeNote.isProtected);
+ async show() {
+ const activeNote = noteDetailService.getActiveNote();
+
+ const attributes = await server.get('notes/' + activeNote.noteId + '/attributes');
+ const attributeMap = utils.toObject(attributes, l => [l.name, l.value]);
+
+ this.$component.show();
+
+ this.$fileNoteId.text(activeNote.noteId);
+ this.$fileName.text(attributeMap.originalFileName || "?");
+ this.$fileSize.text((attributeMap.fileSize || "?") + " bytes");
+ this.$fileType.text(activeNote.mime);
+
+ if (activeNote.content) {
+ this.$previewRow.show();
+ this.$previewContent.text(activeNote.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(!activeNote.isProtected);
+ }
+
+ getFileUrl() {
+ // electron needs absolute URL so we extract current host, port, protocol
+ return utils.getHost() + "/api/notes/" + noteDetailService.getActiveNoteId() + "/download";
+ }
+
+ getContent() {}
+
+ focus() {}
+
+ onNoteChange() {}
+
+ cleanup() {}
+
+ scrollToTop() {}
}
-$downloadButton.click(() => utils.download(getFileUrl()));
-
-$openButton.click(() => {
- if (utils.isElectron()) {
- const open = require("open");
-
- open(getFileUrl());
- }
- else {
- window.location.href = getFileUrl();
- }
-});
-
-function getFileUrl() {
- // electron needs absolute URL so we extract current host, port, protocol
- return utils.getHost() + "/api/notes/" + noteDetailService.getActiveNoteId() + "/download";
-}
-
-export default {
- show,
- getContent: () => null,
- focus: () => null,
- onNoteChange: () => null,
- cleanup: () => null,
- scrollToTop: () => null
-}
\ No newline at end of file
+export default NoteDetailFile;
\ No newline at end of file
diff --git a/src/public/javascripts/services/note_detail_image.js b/src/public/javascripts/services/note_detail_image.js
index 0202080d0..027410afa 100644
--- a/src/public/javascripts/services/note_detail_image.js
+++ b/src/public/javascripts/services/note_detail_image.js
@@ -1,75 +1,85 @@
import utils from "./utils.js";
-import protectedSessionHolder from "./protected_session_holder.js";
import noteDetailService from "./note_detail.js";
import infoService from "./info.js";
import server from "./server.js";
-const $component = $('#note-detail-image');
-const $imageWrapper = $('#note-detail-image-wrapper');
-const $imageView = $('#note-detail-image-view');
+class NoteDetailImage {
+ /**
+ * @param {NoteContext} ctx
+ */
+ constructor(ctx) {
+ this.$component = ctx.$noteTabContent.find('.note-detail-image');
+ this.$imageWrapper = ctx.$noteTabContent.find('.note-detail-image-wrapper');
+ this.$imageView = ctx.$noteTabContent.find('.note-detail-image-view');
+ this.$copyToClipboardButton = ctx.$noteTabContent.find(".image-copy-to-clipboard");
+ this.$fileName = ctx.$noteTabContent.find(".image-filename");
+ this.$fileType = ctx.$noteTabContent.find(".image-filetype");
+ this.$fileSize = ctx.$noteTabContent.find(".image-filesize");
-const $imageDownloadButton = $("#image-download");
-const $copyToClipboardButton = $("#image-copy-to-clipboard");
-const $fileName = $("#image-filename");
-const $fileType = $("#image-filetype");
-const $fileSize = $("#image-filesize");
+ this.$imageDownloadButton = ctx.$noteTabContent.find(".image-download");
+ this.$imageDownloadButton.click(() => utils.download(this.getFileUrl()));
-async function show() {
- const activeNote = noteDetailService.getActiveNote();
+ this.$copyToClipboardButton.click(() => {
+ this.$imageWrapper.attr('contenteditable','true');
- const attributes = await server.get('notes/' + activeNote.noteId + '/attributes');
- const attributeMap = utils.toObject(attributes, l => [l.name, l.value]);
+ try {
+ this.selectImage(this.$imageWrapper.get(0));
- $component.show();
+ const success = document.execCommand('copy');
- $fileName.text(attributeMap.originalFileName || "?");
- $fileSize.text((attributeMap.fileSize || "?") + " bytes");
- $fileType.text(activeNote.mime);
-
- $imageView.prop("src", `api/images/${activeNote.noteId}/${activeNote.title}`);
-}
-
-$imageDownloadButton.click(() => utils.download(getFileUrl()));
-
-function selectImage(element) {
- const selection = window.getSelection();
- const range = document.createRange();
- range.selectNodeContents(element);
- selection.removeAllRanges();
- selection.addRange(range);
-}
-
-$copyToClipboardButton.click(() => {
- $imageWrapper.attr('contenteditable','true');
-
- try {
- selectImage($imageWrapper.get(0));
-
- const success = document.execCommand('copy');
-
- if (success) {
- infoService.showMessage("Image copied to the clipboard");
- }
- else {
- infoService.showAndLogError("Could not copy the image to clipboard.");
- }
+ if (success) {
+ infoService.showMessage("Image copied to the clipboard");
+ }
+ else {
+ infoService.showAndLogError("Could not copy the image to clipboard.");
+ }
+ }
+ finally {
+ window.getSelection().removeAllRanges();
+ this.$imageWrapper.removeAttr('contenteditable');
+ }
+ });
}
- finally {
- window.getSelection().removeAllRanges();
- $imageWrapper.removeAttr('contenteditable');
- }
-});
-function getFileUrl() {
- // electron needs absolute URL so we extract current host, port, protocol
- return utils.getHost() + "/api/notes/" + noteDetailService.getActiveNoteId() + "/download";
+ async show() {
+ const activeNote = noteDetailService.getActiveNote();
+
+ const attributes = await server.get('notes/' + activeNote.noteId + '/attributes');
+ const attributeMap = utils.toObject(attributes, l => [l.name, l.value]);
+
+ this.$component.show();
+
+ this.$fileName.text(attributeMap.originalFileName || "?");
+ this.$fileSize.text((attributeMap.fileSize || "?") + " bytes");
+ this.$fileType.text(activeNote.mime);
+
+ this.$imageView.prop("src", `api/images/${activeNote.noteId}/${activeNote.title}`);
+ }
+
+ selectImage(element) {
+ const selection = window.getSelection();
+ const range = document.createRange();
+ range.selectNodeContents(element);
+ selection.removeAllRanges();
+ selection.addRange(range);
+ }
+
+ getFileUrl() {
+ // electron needs absolute URL so we extract current host, port, protocol
+ return utils.getHost() + "/api/notes/" + noteDetailService.getActiveNoteId() + "/download";
+ }
+
+ getContent() {}
+
+ focus() {}
+
+ onNoteChange() {}
+
+ cleanup() {}
+
+ scrollToTop() {
+ this.$component.scrollTop(0);
+ }
}
-export default {
- show,
- getContent: () => null,
- focus: () => null,
- onNoteChange: () => null,
- cleanup: () => null,
- scrollToTop: () => $component.scrollTop(0)
-}
\ No newline at end of file
+export default NoteDetailImage
\ No newline at end of file
diff --git a/src/public/javascripts/services/note_detail_text.js b/src/public/javascripts/services/note_detail_text.js
index 7a351038a..16c21632d 100644
--- a/src/public/javascripts/services/note_detail_text.js
+++ b/src/public/javascripts/services/note_detail_text.js
@@ -9,7 +9,7 @@ class NoteDetailText {
*/
constructor(ctx) {
this.ctx = ctx;
- this.$component = ctx.$noteTab.find('.note-detail-text');
+ this.$component = ctx.$noteTabContent.find('.note-detail-text');
this.textEditor = null;
this.$component.on("dblclick", "img", e => {
@@ -53,7 +53,7 @@ class NoteDetailText {
this.$component.show();
- this.textEditor.setData(this.ctx.note.content);
+// this.textEditor.setData(this.ctx.note.content);
}
getContent() {
diff --git a/src/public/javascripts/services/tree.js b/src/public/javascripts/services/tree.js
index a314e56e4..e9775470e 100644
--- a/src/public/javascripts/services/tree.js
+++ b/src/public/javascripts/services/tree.js
@@ -485,7 +485,7 @@ function initFancyTree(tree) {
});
$tree.on('contextmenu', '.fancytree-node', function(e) {
- treeContextMenuService.getContextMenuItems(e).then(contextMenuItems => {
+ treeContextMenuService.getContextMenuItems(e).then(([node, contextMenuItems]) => {
contextMenuWidget.initContextMenu(e, contextMenuItems, treeContextMenuService.selectContextMenuItem);
});
diff --git a/src/public/javascripts/services/tree_context_menu.js b/src/public/javascripts/services/tree_context_menu.js
index aca05ac4d..06a0dad4b 100644
--- a/src/public/javascripts/services/tree_context_menu.js
+++ b/src/public/javascripts/services/tree_context_menu.js
@@ -11,6 +11,7 @@ import infoService from "./info.js";
import treeCache from "./tree_cache.js";
import syncService from "./sync.js";
import hoistedNoteService from './hoisted_note.js';
+import noteDetailService from './note_detail.js';
let clipboardIds = [];
let clipboardMode = null;
@@ -103,6 +104,7 @@ async function getTopLevelItems(event) {
const insertChildNoteEnabled = note.type !== 'search';
return [
+ { title: "Open in new tab", cmd: "openInTab", uiIcon: "empty" },
{ title: "Insert note after Ctrl+O", cmd: "insertNoteAfter", uiIcon: "plus",
items: insertNoteAfterEnabled ? getNoteTypeItems("insertNoteAfter") : null,
enabled: insertNoteAfterEnabled },
@@ -143,9 +145,7 @@ async function getTopLevelItems(event) {
async function getContextMenuItems(event) {
const items = await getTopLevelItems(event);
- // Activate node on right-click
const node = $.ui.fancytree.getNode(event);
- node.setActive();
// right click resets selection to just this node
// this is important when e.g. you right click on a note while having different note active
@@ -153,14 +153,17 @@ async function getContextMenuItems(event) {
node.setSelected(true);
treeService.clearSelectedNodes();
- return items;
+ return [node, items];
}
async function selectContextMenuItem(event, cmd) {
// context menu is always triggered on current node
const node = treeService.getActiveNode();
- if (cmd.startsWith("insertNoteAfter")) {
+ if (cmd === 'openInTab') {
+ noteDetailService.openInTab(node.data.noteId);
+ }
+ else if (cmd.startsWith("insertNoteAfter")) {
const parentNoteId = node.data.parentNoteId;
const isProtected = await treeUtils.getParentProtectedStatus(node);
const type = cmd.split("_")[1];
diff --git a/src/public/stylesheets/desktop.css b/src/public/stylesheets/desktop.css
index 58072cf7b..c09f21d4c 100644
--- a/src/public/stylesheets/desktop.css
+++ b/src/public/stylesheets/desktop.css
@@ -31,7 +31,6 @@ body {
#note-tab-container {
grid-area: tab-container;
min-height: 0;
- min-height: 0;
}
#search-box {
@@ -148,7 +147,7 @@ li.dropdown-submenu:hover > ul.dropdown-menu {
border: 1px solid var(--main-border-color);
}
-#note-info-table td, #note-info-table th {
+.note-info-table td, .note-info-table th {
padding: 15px;
}
diff --git a/src/public/stylesheets/mobile.css b/src/public/stylesheets/mobile.css
index 523258c6c..8f4dd9ab3 100644
--- a/src/public/stylesheets/mobile.css
+++ b/src/public/stylesheets/mobile.css
@@ -50,7 +50,7 @@ html, body {
padding-left: 35px;
}
-#note-title-row {
+.note-title-row {
display: flex;
padding-left: 15px;
flex-shrink: 0;
diff --git a/src/public/stylesheets/style.css b/src/public/stylesheets/style.css
index fc06904a5..082128dfd 100644
--- a/src/public/stylesheets/style.css
+++ b/src/public/stylesheets/style.css
@@ -48,7 +48,7 @@ button.close {
color: var(--main-text-color) !important;
}
-#note-title {
+.note-title {
margin-left: 15px;
margin-right: 10px;
font-size: 150%;
@@ -95,7 +95,7 @@ ul.fancytree-container {
content: "\e9ba";
}
-#note-title[readonly] {
+.note-title[readonly] {
background: inherit;
}
@@ -103,13 +103,17 @@ ul.fancytree-container {
display: none;
}
+#note-tab-content-template {
+ display: none;
+}
+
.note-tab-content {
display: flex;
flex-direction: column;
height: 100%;
}
-#note-detail-component-wrapper {
+.note-detail-component-wrapper {
flex-grow: 100;
position: relative;
overflow: auto;
@@ -125,14 +129,14 @@ ul.fancytree-container {
display: none;
}
-#note-detail-text h1 { font-size: 2.0em; }
-#note-detail-text h2 { font-size: 1.8em; }
-#note-detail-text h3 { font-size: 1.6em; }
-#note-detail-text h4 { font-size: 1.4em; }
-#note-detail-text h5 { font-size: 1.2em; }
-#note-detail-text h6 { font-size: 1.1em; }
+.note-detail-text h1 { font-size: 2.0em; }
+.note-detail-text h2 { font-size: 1.8em; }
+.note-detail-text h3 { font-size: 1.6em; }
+.note-detail-text h4 { font-size: 1.4em; }
+.note-detail-text h5 { font-size: 1.2em; }
+.note-detail-text h6 { font-size: 1.1em; }
-#note-detail-text {
+.note-detail-text {
border: 0 !important;
box-shadow: none !important;
/* This is because with empty content height of editor is 0 and it's impossible to click into it */
@@ -142,7 +146,7 @@ ul.fancytree-container {
font-family: var(--detail-text-font-family);
}
-#note-detail-text p:first-child, #note-detail-text::before {
+.note-detail-text p:first-child, .note-detail-text::before {
margin-top: 0;
}
@@ -352,12 +356,12 @@ div.ui-tooltip {
color: #aaa !important;
}
-#note-detail-code {
+.note-detail-code {
min-height: 200px;
overflow: auto;
}
-#note-detail-render {
+.note-detail-render {
min-height: 200px;
}
@@ -376,7 +380,7 @@ div.ui-tooltip {
border-right: none;
}
-#note-type-dropdown {
+.note-type-dropdown {
max-height: 500px;
overflow-y: auto;
overflow-x: hidden;
@@ -403,7 +407,7 @@ div.ui-tooltip {
margin-right: 5px;
}
-#file-table th, #file-table td {
+.file-table th, .file-table td {
padding: 10px;
font-size: larger;
}
@@ -464,7 +468,7 @@ div.ui-tooltip {
background-color: var(--button-disabled-background-color) !important;
}
-#note-path-list a.current {
+.note-path-list a.current {
font-weight: bold;
}
@@ -473,12 +477,12 @@ button.icon-button {
padding: 2px;
}
-#note-actions {
+.note-actions {
margin-left: 10px;
margin-right: 10px;
}
-#note-actions .dropdown-menu {
+.note-actions .dropdown-menu {
width: 15em;
}
@@ -495,7 +499,7 @@ button.icon-button {
padding: 0;
}
-#note-detail-promoted-attributes {
+.note-detail-promoted-attributes {
margin: auto;
/* setting the display to block since "table" doesn't support scrolling */
display: block;
@@ -505,15 +509,15 @@ button.icon-button {
overflow: auto;
}
-#note-detail-promoted-attributes td, #note-detail-promoted-attributes th {
+.note-detail-promoted-attributes td, .note-detail-promoted-attributes th {
padding: 5px;
}
-#note-detail-image {
+.note-detail-image {
text-align: center;
}
-#note-detail-image-view {
+.note-detail-image-view {
max-width: 100%;
}
@@ -521,7 +525,7 @@ pre:not(.CodeMirror-line) {
color: var(--main-text-color) !important;
}
-#file-preview-content {
+.file-preview-content {
background-color: var(--accented-background-color);
padding: 15px;
max-width: 600px;
@@ -580,7 +584,7 @@ table.promoted-attributes-in-tooltip td, table.promoted-attributes-in-tooltip th
padding: 10px;
}
-#note-detail-render-help {
+.note-detail-render-help {
margin: 50px;
padding: 20px;
}
diff --git a/src/views/details/file.ejs b/src/views/details/file.ejs
index bfb801cd6..1ea689150 100644
--- a/src/views/details/file.ejs
+++ b/src/views/details/file.ejs
@@ -16,7 +16,7 @@
File size: |
|
-
+
Preview: |
diff --git a/src/views/tabs.ejs b/src/views/tabs.ejs
index 38e0f728f..5a80d24b4 100644
--- a/src/views/tabs.ejs
+++ b/src/views/tabs.ejs
@@ -1,20 +1,5 @@
|