mirror of
https://github.com/zadam/trilium.git
synced 2025-03-01 14:22:32 +01:00
similar notes section widget
This commit is contained in:
parent
9532a5662f
commit
57b6271c0b
@ -16,7 +16,7 @@ let clonedNoteIds;
|
|||||||
|
|
||||||
export async function showDialog(noteIds) {
|
export async function showDialog(noteIds) {
|
||||||
if (!noteIds || noteIds.length === 0) {
|
if (!noteIds || noteIds.length === 0) {
|
||||||
noteIds = [ appContext.tabManager.getActiveContextNoteId() ]
|
noteIds = [ appContext.tabManager.getActiveContextNoteId() ];
|
||||||
}
|
}
|
||||||
|
|
||||||
clonedNoteIds = [];
|
clonedNoteIds = [];
|
||||||
|
@ -38,6 +38,7 @@ import BookPropertiesWidget from "../widgets/type_property_widgets/book_properti
|
|||||||
import ShowNoteSourceButton from "../widgets/buttons/show_note_source.js";
|
import ShowNoteSourceButton from "../widgets/buttons/show_note_source.js";
|
||||||
import LinkMapWidget from "../widgets/type_property_widgets/link_map.js";
|
import LinkMapWidget from "../widgets/type_property_widgets/link_map.js";
|
||||||
import NotePathsWidget from "../widgets/type_property_widgets/note_paths.js";
|
import NotePathsWidget from "../widgets/type_property_widgets/note_paths.js";
|
||||||
|
import SimilarNotesWidget from "../widgets/type_property_widgets/similar_notes.js";
|
||||||
|
|
||||||
export default class DesktopLayout {
|
export default class DesktopLayout {
|
||||||
constructor(customWidgets) {
|
constructor(customWidgets) {
|
||||||
@ -115,6 +116,7 @@ export default class DesktopLayout {
|
|||||||
.section(new InheritedAttributesWidget())
|
.section(new InheritedAttributesWidget())
|
||||||
.section(new NotePathsWidget())
|
.section(new NotePathsWidget())
|
||||||
.section(new LinkMapWidget())
|
.section(new LinkMapWidget())
|
||||||
|
.section(new SimilarNotesWidget())
|
||||||
.section(new NoteInfoWidget())
|
.section(new NoteInfoWidget())
|
||||||
.button(new ButtonWidget()
|
.button(new ButtonWidget()
|
||||||
.icon('bx bx-history')
|
.icon('bx bx-history')
|
||||||
|
@ -1,151 +0,0 @@
|
|||||||
import linkService from "../services/link.js";
|
|
||||||
import server from "../services/server.js";
|
|
||||||
import froca from "../services/froca.js";
|
|
||||||
import NoteContextAwareWidget from "./note_context_aware_widget.js";
|
|
||||||
import options from "../services/options.js";
|
|
||||||
|
|
||||||
const TPL = `
|
|
||||||
<div class="similar-notes-widget hide-in-zen-mode">
|
|
||||||
<style>
|
|
||||||
.similar-notes-wrapper {
|
|
||||||
max-height: 75px;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.similar-notes-wrapper a {
|
|
||||||
display: inline-block;
|
|
||||||
border: 1px dotted var(--main-border-color);
|
|
||||||
border-radius: 20px;
|
|
||||||
background-color: var(--accented-background-color);
|
|
||||||
padding: 0 10px 0 10px;
|
|
||||||
margin: 0 3px 0 3px;
|
|
||||||
max-width: 10em;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<div class="area-expander">
|
|
||||||
<hr class="w-100">
|
|
||||||
|
|
||||||
<div class="area-expander-text"
|
|
||||||
title="This list contains notes which might be similar to the current note based on textual similarity of note title, its labels and relations."></div>
|
|
||||||
|
|
||||||
<hr class="w-100">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="similar-notes-wrapper"></div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
export default class SimilarNotesWidget extends NoteContextAwareWidget {
|
|
||||||
isEnabled() {
|
|
||||||
return super.isEnabled()
|
|
||||||
&& this.note.type !== 'search'
|
|
||||||
&& !this.note.hasLabel('similarNotesWidgetDisabled');
|
|
||||||
}
|
|
||||||
|
|
||||||
doRender() {
|
|
||||||
this.$widget = $(TPL);
|
|
||||||
this.overflowing();
|
|
||||||
|
|
||||||
this.$similarNotesWrapper = this.$widget.find(".similar-notes-wrapper");
|
|
||||||
this.$expanderText = this.$widget.find(".area-expander-text");
|
|
||||||
|
|
||||||
this.$expander = this.$widget.find('.area-expander');
|
|
||||||
this.$expander.on('click', async () => {
|
|
||||||
const collapse = this.$similarNotesWrapper.is(":visible");
|
|
||||||
|
|
||||||
await options.save('similarNotesExpanded', !collapse);
|
|
||||||
|
|
||||||
this.triggerEvent(`similarNotesCollapsedStateChanged`, {collapse});
|
|
||||||
});
|
|
||||||
|
|
||||||
return this.$widget;
|
|
||||||
}
|
|
||||||
|
|
||||||
noteSwitched() {
|
|
||||||
const noteId = this.noteId;
|
|
||||||
|
|
||||||
this.toggleInt(false);
|
|
||||||
this.$similarNotesWrapper.hide(); // we'll open it in refresh() if needed
|
|
||||||
|
|
||||||
// avoid executing this expensive operation multiple times when just going through notes (with keyboard especially)
|
|
||||||
// until the users settles on a note
|
|
||||||
setTimeout(() => {
|
|
||||||
if (this.noteId === noteId) {
|
|
||||||
this.refresh();
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
async refresh() {
|
|
||||||
if (!this.isEnabled()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// remember which title was when we found the similar notes
|
|
||||||
this.title = this.note.title;
|
|
||||||
|
|
||||||
const similarNotes = await server.get('similar-notes/' + this.noteId);
|
|
||||||
|
|
||||||
if (!similarNotes) {
|
|
||||||
this.toggleInt(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.toggleInt(similarNotes.length > 0);
|
|
||||||
|
|
||||||
if (similarNotes.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.is('similarNotesExpanded')) {
|
|
||||||
this.$similarNotesWrapper.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$expanderText.text(`${similarNotes.length} similar note${similarNotes.length === 1 ? '': "s"}`);
|
|
||||||
|
|
||||||
const noteIds = similarNotes.flatMap(note => note.notePath);
|
|
||||||
|
|
||||||
await froca.getNotes(noteIds, true); // preload all at once
|
|
||||||
|
|
||||||
const $list = $('<div>');
|
|
||||||
|
|
||||||
for (const similarNote of similarNotes) {
|
|
||||||
const note = await froca.getNote(similarNote.noteId, true);
|
|
||||||
|
|
||||||
if (!note) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const $item = (await linkService.createNoteLink(similarNote.notePath.join("/")))
|
|
||||||
.css("font-size", 24 * (1 - 1 / (1 + similarNote.score)));
|
|
||||||
|
|
||||||
$list.append($item);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$similarNotesWrapper.empty().append($list);
|
|
||||||
}
|
|
||||||
|
|
||||||
entitiesReloadedEvent({loadResults}) {
|
|
||||||
if (this.note && this.title !== this.note.title) {
|
|
||||||
this.rendered = false;
|
|
||||||
|
|
||||||
this.refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This event is used to synchronize collapsed state of all the tab-cached widgets since they are all rendered
|
|
||||||
* separately but should behave uniformly for the user.
|
|
||||||
*/
|
|
||||||
similarNotesCollapsedStateChangedEvent({collapse}) {
|
|
||||||
if (collapse) {
|
|
||||||
this.$similarNotesWrapper.slideUp(200);
|
|
||||||
} else {
|
|
||||||
this.$similarNotesWrapper.slideDown(200);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -44,7 +44,7 @@ export default class NotePathsWidget extends NoteContextAwareWidget {
|
|||||||
|
|
||||||
getTitle() {
|
getTitle() {
|
||||||
return {
|
return {
|
||||||
show: this.isEnabled(),
|
show: true,
|
||||||
title: 'Note Paths',
|
title: 'Note Paths',
|
||||||
icon: 'bx bx-collection'
|
icon: 'bx bx-collection'
|
||||||
};
|
};
|
||||||
|
@ -0,0 +1,98 @@
|
|||||||
|
import linkService from "../../services/link.js";
|
||||||
|
import server from "../../services/server.js";
|
||||||
|
import froca from "../../services/froca.js";
|
||||||
|
import NoteContextAwareWidget from "../note_context_aware_widget.js";
|
||||||
|
|
||||||
|
const TPL = `
|
||||||
|
<div class="similar-notes-widget">
|
||||||
|
<style>
|
||||||
|
.similar-notes-wrapper {
|
||||||
|
max-height: 200px;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.similar-notes-wrapper a {
|
||||||
|
display: inline-block;
|
||||||
|
border: 1px dotted var(--main-border-color);
|
||||||
|
border-radius: 20px;
|
||||||
|
background-color: var(--accented-background-color);
|
||||||
|
padding: 0 10px 0 10px;
|
||||||
|
margin: 0 3px 0 3px;
|
||||||
|
max-width: 10em;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="similar-notes-wrapper"></div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default class SimilarNotesWidget extends NoteContextAwareWidget {
|
||||||
|
static getType() { return "similar-notes"; }
|
||||||
|
|
||||||
|
isEnabled() {
|
||||||
|
return super.isEnabled()
|
||||||
|
&& this.note.type !== 'search'
|
||||||
|
&& !this.note.hasLabel('similarNotesWidgetDisabled');
|
||||||
|
}
|
||||||
|
|
||||||
|
getTitle() {
|
||||||
|
return {
|
||||||
|
show: this.isEnabled(),
|
||||||
|
title: 'Similar Notes',
|
||||||
|
icon: 'bx bx-bar-chart'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
doRender() {
|
||||||
|
this.$widget = $(TPL);
|
||||||
|
this.overflowing();
|
||||||
|
|
||||||
|
this.$similarNotesWrapper = this.$widget.find(".similar-notes-wrapper");
|
||||||
|
}
|
||||||
|
|
||||||
|
async refreshWithNote() {
|
||||||
|
// remember which title was when we found the similar notes
|
||||||
|
this.title = this.note.title;
|
||||||
|
|
||||||
|
const similarNotes = await server.get('similar-notes/' + this.noteId);
|
||||||
|
|
||||||
|
if (similarNotes.length === 0) {
|
||||||
|
this.$similarNotesWrapper.empty().append("No similar notes found.");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const noteIds = similarNotes.flatMap(note => note.notePath);
|
||||||
|
|
||||||
|
await froca.getNotes(noteIds, true); // preload all at once
|
||||||
|
|
||||||
|
const $list = $('<div>');
|
||||||
|
|
||||||
|
for (const similarNote of similarNotes) {
|
||||||
|
const note = await froca.getNote(similarNote.noteId, true);
|
||||||
|
|
||||||
|
if (!note) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const $item = (await linkService.createNoteLink(similarNote.notePath.join("/")))
|
||||||
|
.css("font-size", 24 * (1 - 1 / (1 + similarNote.score)));
|
||||||
|
|
||||||
|
$list.append($item);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$similarNotesWrapper.empty().append($list);
|
||||||
|
}
|
||||||
|
|
||||||
|
entitiesReloadedEvent({loadResults}) {
|
||||||
|
if (this.note && this.title !== this.note.title) {
|
||||||
|
this.rendered = false;
|
||||||
|
|
||||||
|
this.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user