joplin-plugin-minimap 1.4.0 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "joplin-plugin-minimap",
3
- "version": "1.4.0",
3
+ "version": "1.4.1",
4
4
  "description": "A table of contents minimap for the Joplin note viewer, on desktop and mobile",
5
5
  "author": "lim0513",
6
6
  "homepage": "https://github.com/lim0513/joplin-minimap",
@@ -7,7 +7,7 @@
7
7
  "desktop",
8
8
  "mobile"
9
9
  ],
10
- "version": "1.4.0",
10
+ "version": "1.4.1",
11
11
  "name": "Joplin Minimap",
12
12
  "description": "A table of contents minimap for the note viewer. Shows heading tick marks along one edge; hover (or tap on mobile) to expand into a full outline, click to jump.",
13
13
  "author": "lim0513",
@@ -116,7 +116,7 @@
116
116
  return Array.prototype.slice.call(root.querySelectorAll('h1, h2, h3, h4, h5, h6'));
117
117
  }
118
118
 
119
- function jumpTo(index, text) {
119
+ function findHeading(index, text) {
120
120
  var hs = liveHeadings();
121
121
  var h = hs[index];
122
122
  if (!h || (text && (h.textContent || '').trim() !== text)) {
@@ -124,7 +124,74 @@
124
124
  if ((hs[i].textContent || '').trim() === text) { h = hs[i]; break; }
125
125
  }
126
126
  }
127
- if (h && h.isConnected) h.scrollIntoView({ behavior: 'smooth', block: 'start' });
127
+ return h;
128
+ }
129
+
130
+ // A smooth scrollIntoView is fire-and-forget: the browser animates towards
131
+ // an offset worked out when it STARTS, and plenty can cut it short or make
132
+ // it land wrong - the reader nudging the wheel, Joplin re-rendering the note
133
+ // underneath, split view writing scrollTop of its own, or images above the
134
+ // target finishing layout and shifting it. The jump then stops somewhere in
135
+ // between, which is the "clicked H1 but only went up to 4.5" report.
136
+ // Some environments ignore behavior:'smooth' altogether (headless Chromium
137
+ // does, measured) and the jump never moves at all.
138
+ //
139
+ // So the animation is started for the feel, then the heading is watched
140
+ // until it stops moving and an INSTANT scroll closes whatever gap is left.
141
+ // The instant call uses the same alignment, so when the smooth scroll did
142
+ // land correctly it is a no-op.
143
+ var jumpWatch = null;
144
+ var jumpRelease = null;
145
+
146
+ function stopJumpWatch() {
147
+ if (jumpWatch) { clearInterval(jumpWatch); jumpWatch = null; }
148
+ if (jumpRelease) { jumpRelease(); jumpRelease = null; }
149
+ }
150
+
151
+ function watchJump(index, text) {
152
+ stopJumpWatch();
153
+
154
+ // The reader always wins: if they scroll themselves we are no longer
155
+ // correcting a broken jump, we are fighting them.
156
+ var takenOver = false;
157
+ function onUserScroll(e) {
158
+ // Wheeling the ToC list itself is not the reader taking over the note -
159
+ // the panel has its own wheel handler, and clicking a row then scrolling
160
+ // the list to pick another is a normal sequence.
161
+ var t = e && e.target;
162
+ if (t && t.closest && t.closest('#jp-minimap')) return;
163
+ takenOver = true;
164
+ }
165
+ document.addEventListener('wheel', onUserScroll, { passive: true, capture: true });
166
+ document.addEventListener('touchstart', onUserScroll, { passive: true, capture: true });
167
+ jumpRelease = function () {
168
+ document.removeEventListener('wheel', onUserScroll, { capture: true });
169
+ document.removeEventListener('touchstart', onUserScroll, { capture: true });
170
+ };
171
+
172
+ var ticks = 0;
173
+ var prevTop = null;
174
+ jumpWatch = setInterval(function () {
175
+ ticks++;
176
+ if (takenOver) { stopJumpWatch(); return; }
177
+ var h = findHeading(index, text);
178
+ // A rebuild can briefly detach it; keep waiting, within reason.
179
+ if (!h || !h.isConnected) { if (ticks > 20) stopJumpWatch(); return; }
180
+ var top = Math.round(h.getBoundingClientRect().top);
181
+ var settled = prevTop !== null && top === prevTop;
182
+ prevTop = top;
183
+ if (settled || ticks > 20) {
184
+ stopJumpWatch();
185
+ h.scrollIntoView({ block: 'start' });
186
+ }
187
+ }, 70);
188
+ }
189
+
190
+ function jumpTo(index, text) {
191
+ var h = findHeading(index, text);
192
+ if (!h || !h.isConnected) return;
193
+ h.scrollIntoView({ behavior: 'smooth', block: 'start' });
194
+ watchJump(index, text);
128
195
  }
129
196
 
130
197
  // Width of the note viewer's right-edge scrollbar zone. Overlay scrollbars
Binary file