diff --git a/package-lock.json b/package-lock.json
index 6424b4f78..30a0dbed2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "trilium",
- "version": "0.51.2",
+ "version": "0.52.0-beta",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "trilium",
- "version": "0.51.2",
+ "version": "0.52.0-beta",
"hasInstallScript": true,
"license": "AGPL-3.0-only",
"dependencies": {
diff --git a/src/public/app/widgets/basic_widget.js b/src/public/app/widgets/basic_widget.js
index be1f09e93..5c8cccdeb 100644
--- a/src/public/app/widgets/basic_widget.js
+++ b/src/public/app/widgets/basic_widget.js
@@ -103,10 +103,22 @@ class BasicWidget extends Component {
this.$widget.toggleClass('hidden-int', !show);
}
+ isHiddenInt() {
+ return this.$widget.hasClass('hidden-int');
+ }
+
toggleExt(show) {
this.$widget.toggleClass('hidden-ext', !show);
}
+ isHiddenExt() {
+ return this.$widget.hasClass('hidden-ext');
+ }
+
+ canBeShown() {
+ return !this.isHiddenInt() && !this.isHiddenExt();
+ }
+
isVisible() {
return this.$widget.is(":visible");
}
diff --git a/src/public/app/widgets/collapsible_widget.js b/src/public/app/widgets/collapsible_widget.js
index bbe60345b..0d108f27e 100644
--- a/src/public/app/widgets/collapsible_widget.js
+++ b/src/public/app/widgets/collapsible_widget.js
@@ -35,8 +35,4 @@ export default class CollapsibleWidget extends NoteContextAwareWidget {
/** for overriding */
async doRenderBody() {}
-
- isExpanded() {
- return this.$bodyWrapper.hasClass("show");
- }
}
diff --git a/src/public/app/widgets/containers/right_pane_container.js b/src/public/app/widgets/containers/right_pane_container.js
index a927045f3..204c48cb4 100644
--- a/src/public/app/widgets/containers/right_pane_container.js
+++ b/src/public/app/widgets/containers/right_pane_container.js
@@ -11,7 +11,9 @@ export default class RightPaneContainer extends FlexContainer {
}
isEnabled() {
- return super.isEnabled() && this.children.length > 0 && !!this.children.find(ch => ch.isEnabled());
+ return super.isEnabled()
+ && this.children.length > 0
+ && !!this.children.find(ch => ch.isEnabled() && ch.canBeShown());
}
handleEventInChildren(name, data) {
@@ -21,13 +23,20 @@ export default class RightPaneContainer extends FlexContainer {
// right pane is displayed only if some child widget is active
// we'll reevaluate the visibility based on events which are probable to cause visibility change
// but these events needs to be finished and only then we check
- promise.then(() => {
- this.toggleInt(this.isEnabled());
-
- splitService.setupRightPaneResizer();
- });
+ promise.then(() => this.reevaluateIsEnabledCommand());
}
return promise;
}
+
+ reevaluateIsEnabledCommand() {
+ const oldToggle = !this.isHiddenInt();
+ const newToggle = this.isEnabled();
+
+ if (oldToggle !== newToggle) {
+ this.toggleInt(newToggle);
+
+ splitService.setupRightPaneResizer();
+ }
+ }
}
diff --git a/src/public/app/widgets/toc.js b/src/public/app/widgets/toc.js
index 5a181686f..adde8805b 100644
--- a/src/public/app/widgets/toc.js
+++ b/src/public/app/widgets/toc.js
@@ -26,11 +26,11 @@ const TPL = `
}
.toc ol {
- padding-left: 20px;
+ padding-left: 25px;
}
.toc > ol {
- padding-left: 0;
+ padding-left: 10px;
}
@@ -75,7 +75,10 @@ function findHeadingElementByIndex(parent, headingIndex) {
// "H" plus the level, eg "H2", "H3", "H2", etc and not nested wrt the
// heading level. If a heading node is found, decrement the headingIndex
// until zero is reached
- if (child.tagName.match(/H\d+/) !== null) {
+
+ console.log(child.tagName, headingIndex);
+
+ if (child.tagName.match(/H\d+/i) !== null) {
if (headingIndex === 0) {
headingElement = child;
break;
@@ -86,6 +89,8 @@ function findHeadingElementByIndex(parent, headingIndex) {
return headingElement;
}
+const MIN_HEADING_COUNT = 3;
+
export default class TocWidget extends CollapsibleWidget {
get widgetTitle() {
return "Table of Contents";
@@ -94,7 +99,7 @@ export default class TocWidget extends CollapsibleWidget {
isEnabled() {
return super.isEnabled()
&& this.note.type === 'text'
- && !this.note.hasLabel('noTocWidget');
+ && !this.note.hasLabel('noToc');
}
async doRenderBody() {
@@ -103,21 +108,23 @@ export default class TocWidget extends CollapsibleWidget {
}
async refreshWithNote(note) {
- let toc = "";
+ let $toc = "", headingCount = 0;
// Check for type text unconditionally in case alwaysShowWidget is set
if (this.note.type === 'text') {
const { content } = await note.getNoteComplement();
- toc = await this.getToc(content);
+ ({$toc, headingCount} = await this.getToc(content));
}
- this.$toc.html(toc);
+ this.$toc.html($toc);
+ this.toggleInt(headingCount >= MIN_HEADING_COUNT);
+ this.triggerCommand("reevaluateIsEnabled");
}
/**
* Builds a jquery table of contents.
*
* @param {String} html Note's html content
- * @returns {jQuery} ordered list table of headings, nested by heading level
+ * @returns {$toc: jQuery, headingCount: integer} ordered list table of headings, nested by heading level
* with an onclick event that will cause the document to scroll to
* the desired position.
*/
@@ -133,7 +140,8 @@ export default class TocWidget extends CollapsibleWidget {
// Note heading 2 is the first level Trilium makes available to the note
let curLevel = 2;
const $ols = [$toc];
- for (let m = null, headingIndex = 0; ((m = headingTagsRegex.exec(html)) !== null); ++headingIndex) {
+ let headingCount;
+ for (let m = null, headingIndex = 0; ((m = headingTagsRegex.exec(html)) !== null); headingIndex++) {
//
// Nest/unnest whatever necessary number of ordered lists
//
@@ -164,93 +172,101 @@ export default class TocWidget extends CollapsibleWidget {
}).mouseout(function () {
$(this).css("font-weight", "normal");
});
- $li.on("click", async () => {
- // A readonly note can change state to "readonly disabled
- // temporarily" (ie "edit this note" button) without any
- // intervening events, do the readonly calculation at navigation
- // time and not at outline creation time
- // See https://github.com/zadam/trilium/issues/2828
- const isReadOnly = await this.noteContext.isReadOnly();
-
- if (isReadOnly) {
- const readonlyTextElement = await this.noteContext.getContentElement();
- const headingElement = findHeadingElementByIndex(readonlyTextElement, headingIndex);
-
- if (headingElement != null) {
- headingElement.scrollIntoView();
- }
- } else {
- const textEditor = await this.noteContext.getTextEditor();
-
- const model = textEditor.model;
- const doc = model.document;
- const root = doc.getRoot();
-
- const headingNode = findHeadingNodeByIndex(root, headingIndex);
-
- // headingNode could be null if the html was malformed or
- // with headings inside elements, just ignore and don't
- // navigate (note that the TOC rendering and other TOC
- // entries' navigation could be wrong too)
- if (headingNode != null) {
- // Setting the selection alone doesn't scroll to the
- // caret, needs to be done explicitly and outside of
- // the writer change callback so the scroll is
- // guaranteed to happen after the selection is
- // updated.
-
- // In addition, scrolling to a caret later in the
- // document (ie "forward scrolls"), only scrolls
- // barely enough to place the caret at the bottom of
- // the screen, which is a usability issue, you would
- // like the caret to be placed at the top or center
- // of the screen.
-
- // To work around that issue, first scroll to the
- // end of the document, then scroll to the desired
- // point. This causes all the scrolls to be
- // "backward scrolls" no matter the current caret
- // position, which places the caret at the top of
- // the screen.
-
- // XXX This could be fixed in another way by using
- // the underlying CKEditor5
- // scrollViewportToShowTarget, which allows to
- // provide a larger "viewportOffset", but that
- // has coding complications (requires calling an
- // internal CKEditor utils funcion and passing
- // an HTML element, not a CKEditor node, and
- // CKEditor5 doesn't seem to have a
- // straightforward way to convert a node to an
- // HTML element? (in CKEditor4 this was done
- // with $(node.$) )
-
- // Scroll to the end of the note to guarantee the
- // next scroll is a backwards scroll that places the
- // caret at the top of the screen
- model.change(writer => {
- writer.setSelection(root.getChild(root.childCount - 1), 0);
- });
- textEditor.editing.view.scrollToTheSelection();
- // Backwards scroll to the heading
- model.change(writer => {
- writer.setSelection(headingNode, 0);
- });
- textEditor.editing.view.scrollToTheSelection();
- }
- }
- });
+ $li.on("click", () => this.jumpToHeading(headingIndex));
$ols[$ols.length - 1].append($li);
+ headingCount = headingIndex;
}
- return $toc;
+ return {
+ $toc,
+ headingCount
+ };
+ }
+
+ async jumpToHeading(headingIndex) {
+ // A readonly note can change state to "readonly disabled
+ // temporarily" (ie "edit this note" button) without any
+ // intervening events, do the readonly calculation at navigation
+ // time and not at outline creation time
+ // See https://github.com/zadam/trilium/issues/2828
+ const isReadOnly = await this.noteContext.isReadOnly();
+
+ if (isReadOnly) {
+ const $readonlyTextContent = await this.noteContext.getContentElement();
+
+ const headingElement = findHeadingElementByIndex($readonlyTextContent[0], headingIndex);
+
+ if (headingElement != null) {
+ headingElement.scrollIntoView();
+ }
+ } else {
+ const textEditor = await this.noteContext.getTextEditor();
+
+ const model = textEditor.model;
+ const doc = model.document;
+ const root = doc.getRoot();
+
+ const headingNode = findHeadingNodeByIndex(root, headingIndex);
+
+ // headingNode could be null if the html was malformed or
+ // with headings inside elements, just ignore and don't
+ // navigate (note that the TOC rendering and other TOC
+ // entries' navigation could be wrong too)
+ if (headingNode != null) {
+ // Setting the selection alone doesn't scroll to the
+ // caret, needs to be done explicitly and outside of
+ // the writer change callback so the scroll is
+ // guaranteed to happen after the selection is
+ // updated.
+
+ // In addition, scrolling to a caret later in the
+ // document (ie "forward scrolls"), only scrolls
+ // barely enough to place the caret at the bottom of
+ // the screen, which is a usability issue, you would
+ // like the caret to be placed at the top or center
+ // of the screen.
+
+ // To work around that issue, first scroll to the
+ // end of the document, then scroll to the desired
+ // point. This causes all the scrolls to be
+ // "backward scrolls" no matter the current caret
+ // position, which places the caret at the top of
+ // the screen.
+
+ // XXX This could be fixed in another way by using
+ // the underlying CKEditor5
+ // scrollViewportToShowTarget, which allows to
+ // provide a larger "viewportOffset", but that
+ // has coding complications (requires calling an
+ // internal CKEditor utils funcion and passing
+ // an HTML element, not a CKEditor node, and
+ // CKEditor5 doesn't seem to have a
+ // straightforward way to convert a node to an
+ // HTML element? (in CKEditor4 this was done
+ // with $(node.$) )
+
+ // Scroll to the end of the note to guarantee the
+ // next scroll is a backwards scroll that places the
+ // caret at the top of the screen
+ model.change(writer => {
+ writer.setSelection(root.getChild(root.childCount - 1), 0);
+ });
+ textEditor.editing.view.scrollToTheSelection();
+ // Backwards scroll to the heading
+ model.change(writer => {
+ writer.setSelection(headingNode, 0);
+ });
+ textEditor.editing.view.scrollToTheSelection();
+ }
+ }
}
async entitiesReloadedEvent({loadResults}) {
- if (loadResults.isNoteContentReloaded(this.noteId)
- || loadResults.getAttributes().find(attr => attr.type === 'label'
- && attr.name.toLowerCase().includes('readonly')
- && attributeService.isAffecting(attr, this.note))) {
+ if (loadResults.isNoteContentReloaded(this.noteId)) {
+ await this.refresh();
+ } else if (loadResults.getAttributes().find(attr => attr.type === 'label'
+ && (attr.name.toLowerCase().includes('readonly') || attr.name === 'noToc')
+ && attributeService.isAffecting(attr, this.note))) {
await this.refresh();
}
diff --git a/src/public/stylesheets/style.css b/src/public/stylesheets/style.css
index 647373b6d..7797f4c3a 100644
--- a/src/public/stylesheets/style.css
+++ b/src/public/stylesheets/style.css
@@ -241,8 +241,8 @@ body .CodeMirror {
background-color: #eeeeee
}
-.CodeMirror pre.CodeMirror-placeholder {
- color: #999 !important;
+.CodeMirror pre.CodeMirror-placeholder {
+ color: #999 !important;
}
#sql-console-query {
@@ -943,7 +943,6 @@ input {
border: 0;
height: 100%;
overflow: auto;
- max-height: 300px;
}
#right-pane .card-body ul {