├── BackToHistory.js
├── README.md
└── images
└── button.png
/BackToHistory.js:
--------------------------------------------------------------------------------
1 | /*
2 | Back-to-historytory
3 | https://github.com/SiriusXT/trilium-back-to-history
4 | version: 0.5 for TriliumNext > 0.90.8
5 | */
6 |
7 |
8 | const supportType = ['text', 'code']
9 | const autoJump = true;
10 | const showJumpButton = true;
11 | const omitNoteIds=['root']
12 |
13 | // The following code does not need to be modified
14 |
15 | if (!autoJump && !showJumpButton) {
16 | console.log("BackUpHistory: do nothing");
17 | return;
18 | }
19 |
20 | function creatHistory() {
21 | return new Promise((resolve, reject) => {
22 | api.runOnBackend((noteId) => {
23 | try {
24 | const { note, branch } = api.createNewNote({
25 | parentNoteId: noteId,
26 | title: 'history',
27 | content: '{}',
28 | type: 'code',
29 | mime: 'application/json'
30 | });
31 | resolve(note);
32 | } catch (error) {
33 | // reject(error);
34 | }
35 | }, [api.startNote.noteId]);
36 | });
37 | }
38 |
39 | let historyNoteId;
40 | async function getHistory() {
41 | let history;
42 | if (historyNoteId !== undefined) {
43 | const childNote = await api.getNote(historyNoteId);
44 | // return JSON.parse((await (await api.getNote(historyNoteId)).getNoteComplement()).content);
45 | history = JSON.parse((await childNote.getNoteComplement()).content);
46 | return history;
47 | }
48 | const children = api.startNote.children;
49 | let haveHistory = false;
50 | for (let i = 0; i < children.length; i++) {
51 | const childNote = await api.getNote(children[i]);
52 | if (childNote.type == 'code' && childNote.mime == 'application/json' && childNote.title == 'history') {
53 | historyNoteId = childNote.noteId;
54 | try {
55 | history = JSON.parse((await childNote.getNoteComplement()).content);
56 | } catch (error) {
57 | history = {}
58 | }
59 | haveHistory = true;
60 | break;
61 | }
62 | }
63 | if (!haveHistory) {
64 | const note = await creatHistory();
65 | historyNoteId = note.noteId;
66 | history = JSON.parse((await note.getNoteComplement()).content);
67 | }
68 | return history;
69 | }
70 |
71 | const jumpButton = `
72 |
73 |
`
74 | var jumpHistory = class extends api.NoteContextAwareWidget {
75 | get position() {
76 | return 50;
77 | }
78 | static get parentWidget() {
79 | return 'note-detail-pane';
80 | }
81 | constructor() {
82 | super();
83 | }
84 | isEnabled() {
85 | return super.isEnabled() && supportType.includes(this.note.type) && !omitNoteIds.includes(this.noteId);
86 | }
87 | doRender() {
88 | this.$widget = $('');
89 | return this.$widget;
90 | }
91 | scrollHandler = () => {
92 | clearTimeout(this.updateTimer);
93 | this.updateTimer = setTimeout(async () => {
94 | try {
95 | const sc = this.$scrollingContainer[0];
96 | const nl = this.$scrollingContainer.find('.note-list-widget')[0];
97 | const radio = (sc.scrollTop / (sc.scrollHeight - nl.offsetHeight)).toFixed(5);
98 | if (!isNaN(radio)) {
99 | let history = await getHistory();
100 | history[this.note.noteId] = radio;
101 | saveHistory(history);
102 | }
103 | }
104 | catch (error) {
105 | const $noteSplit = $(`.note-split[data-ntx-id="${this.noteContext.ntxId}"]`);
106 | this.$scrollingContainer = $noteSplit.children('.scrolling-container');
107 | console.warn('jumpHistory: ', error);
108 | }
109 | }, 3000);
110 | }
111 | scrollTo = () => {
112 | const sc = this.$scrollingContainer[0];
113 | const nl = sc.querySelector('.note-list-widget');
114 | const scrollHeight = sc.scrollHeight - nl.offsetHeight;
115 | $(sc).animate({
116 | scrollTop: this.scrollToRadio * scrollHeight,
117 | }, 300);
118 | }
119 | addJumpButton() {
120 | const $ribbonTab = $(`.note-split[data-ntx-id="${this.noteContext.ntxId}"]`).find('.ribbon-tab-container');
121 | $ribbonTab.find('.jump-history').remove();
122 | const $button = $(jumpButton);
123 | $ribbonTab.append($button);
124 | $button.on('click', this.scrollTo);
125 | $button.attr('title', "Scorll To " + this.scrollToRadio * 100 + "%");
126 | }
127 |
128 | autoJumpFunc() {
129 | this.scrollTo();
130 | clearInterval(this.jumpInterval);
131 | let timesRun = 0;
132 | let preHeight = 0;
133 | this.jumpInterval = setInterval(() => {
134 | timesRun += 1;
135 | if (timesRun == 5) {
136 | clearInterval(this.jumpInterval);
137 | }
138 | if (this.$scrollingContainer[0].scrollHeight != preHeight) {
139 | preHeight = this.$scrollingContainer[0].scrollHeight;
140 | this.scrollTo();
141 | }
142 | }, 200);
143 | }
144 | async initEvent() {
145 | this.updateTimeout = 0;
146 | const $noteSplit = $(`.note-split[data-ntx-id="${this.noteContext.ntxId}"]`);
147 | this.$scrollingContainer = $noteSplit.children('.scrolling-container');
148 | this.$scrollingContainer.off('scroll', this.scrollHandler);
149 | if (showJumpButton && this.scrollToRadio != undefined) {
150 | this.addJumpButton();
151 | }
152 | setTimeout(() => {
153 | // Automatic jump without monitoring
154 | this.$scrollingContainer.off('scroll', this.scrollHandler);
155 | this.$scrollingContainer.on('scroll', this.scrollHandler);
156 | }, 1000);
157 | }
158 | async refreshWithNote() {
159 | const history = await getHistory();
160 | this.scrollToRadio = history[this.note.noteId];
161 | await this.initEvent();
162 | if (this.scrollToRadio != undefined && autoJump) {
163 | this.autoJumpFunc();
164 | }
165 | }
166 | async entitiesReloadedEvent({ loadResults }) {
167 | if (loadResults.isNoteContentReloaded(this.noteId)) {
168 | const $noteSplit = $(`.note-split[data-ntx-id="${this.noteContext.ntxId}"]`);
169 | this.$scrollingContainer = $noteSplit.children('.scrolling-container');
170 | this.scrollHandler();
171 | }
172 | if (loadResults.getAttributeRows().find(attr => attr.noteId === this.noteId)) {
173 | this.initEvent();
174 | }
175 | }
176 | }
177 |
178 | module.exports = jumpHistory;
179 |
180 | function saveHistory(history) {
181 | const keys = Object.keys(history);
182 | while (keys.length > 100) {
183 | const oldestKey = keys.shift(); // Get the oldest key
184 | delete history[oldestKey]; // Delete the element corresponding to the key
185 | }
186 | api.runAsyncOnBackendWithManualTransactionHandling(async (historyNoteId, history) => {
187 | const historyNote = await api.getNote(historyNoteId);
188 | historyNote.setContent(JSON.stringify(history));
189 | }, [historyNoteId, history]);
190 | }
191 |
192 |
193 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SiriusXT/trilium-back-to-history/48f9b414ee8e0f85abf27f3365efcfbc312615dd/README.md
--------------------------------------------------------------------------------
/images/button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SiriusXT/trilium-back-to-history/48f9b414ee8e0f85abf27f3365efcfbc312615dd/images/button.png
--------------------------------------------------------------------------------