jekyll-hover-popup 0.2.0 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '093a8fdc8081648557c5767ccda5e569f65755d513df938c8c96b02bf8653348'
4
- data.tar.gz: 293393bc00ed5a9e096fb670b6c1468cf83450403db44f1cdd74258e1e1684c5
3
+ metadata.gz: d904538318970368b8ae375e4e1296000b2e9a88a25ccbfd7273846cbc42d21b
4
+ data.tar.gz: e212207697ebb5f6f5a2474078276d242a3b3c6902461473ec9e68f6dac4d818
5
5
  SHA512:
6
- metadata.gz: 258b38b8e03cdb86f0f1c1ac7c62dc3b56e6046463a28128dd3c7049c0681bd1f0bc609e4a8f357cf3d66c4ca1c8312a6cbc4b72f019fe8392f56ac8c27ff2e6
7
- data.tar.gz: '09ab116eea32d0d8f310ea74b75466a19dc6c279ea4b551d22f4cedb8c8574f30c139305433c54283cd131b5291dafa10aea3458abe4165fd8a36ca21ac5dedf'
6
+ metadata.gz: a1006d757734f03fe07bc223c1feb50ce98e4e557a5f5e4a39cfaba9403865bf1218fb99e332bc7e7cb98bad98e1b084d6dd6ceb5b121ecdcc39c1335ae74e6b
7
+ data.tar.gz: 8bf2a9bb8af64ababe2c3af6eed644c5ef16a3f2365da453966d0068270cac9c366109c518caad6aedd1b2cddb32671e05c4862e37e81d4ccdf8fe3759fbd83c
data/README.md CHANGED
@@ -6,14 +6,15 @@ Inspired by the hover window behavior in [5etools](https://github.com/5etools/5e
6
6
 
7
7
  ## Features
8
8
 
9
- - Hover an internal link to preview its target content in a floating window
10
- - Hold **Shift** while hovering (or when leaving the link) to pin the preview
11
- - Pinned windows show **Follow link** and **Close** (Ctrl/Cmd+click Close to close all)
12
- - Pinned links do not open additional previews on further hovers
13
- - Section links (`#heading-id`) show only that section; page links show the full page content
14
- - External links and non-page links are ignored
15
- - Popup windows are resizable (8 drag handles) and styled from the host page's computed theme
16
- - Exposes `window.JekyllHoverPopup` for other plugins (for example, image map region clicks)
9
+ - Hover over an internal link to see a reference preview
10
+ - Persist windows by holding the SHIFT key
11
+ - Close all windows by holding CTRL while closing one
12
+ - Minimize windows by double clicking the title bar
13
+ - Navigate to an entry later by clicking the link in the title bar
14
+ - Eight point window resize
15
+ - Exposes `window.JekyllHoverPopup` for other plugins
16
+
17
+ <img width="640" height="360" alt="window-preview-demo-2" src="https://github.com/user-attachments/assets/1f8f60ad-ad2a-4418-ad0f-0494f4e43faf" />
17
18
 
18
19
  ## Install
19
20
 
@@ -41,10 +42,12 @@ hover_popup:
41
42
  enabled: true
42
43
  assets_path: /assets/jekyll-hover-popup
43
44
  hover_delay_ms: 0
44
- nav_hover_preview: true
45
+ nav_hover_preview: false
45
46
  ```
46
47
 
47
- Set `nav_hover_preview: false` to disable hover previews for links inside navigation elements (`.site-nav`, `nav`, `[role="navigation"]`, etc.).
48
+ Add a `hover_delay_ms` to delay the preview window creation
49
+
50
+ Set `nav_hover_preview: true` to enable hover previews for links inside navigation elements (`.site-nav`, `nav`, `[role="navigation"]`, etc.).
48
51
 
49
52
  ## JavaScript API
50
53
 
@@ -72,4 +75,4 @@ window.JekyllHoverPopup.openContent({
72
75
 
73
76
  ## License
74
77
 
75
- MIT
78
+ [MIT](LICENSE)
@@ -3,7 +3,7 @@
3
3
 
4
4
  const config = window.__JHP_CONFIG__ || {};
5
5
  const HOVER_DELAY_MS = Number(config.hoverDelayMs) || 0;
6
- const NAV_HOVER_PREVIEW = config.navHoverPreview !== false;
6
+ const NAV_HOVER_PREVIEW = config.navHoverPreview === true;
7
7
  const TRANSIENT_TITLE_HINT = "SHIFT to persist";
8
8
  const MAX_VIEWPORT_WIDTH = 0.92;
9
9
  const MAX_VIEWPORT_HEIGHT = 0.92;
@@ -128,10 +128,16 @@
128
128
  });
129
129
  }
130
130
 
131
+ function stripHtmlExtension(pathname) {
132
+ return pathname.replace(/\.html?$/i, "");
133
+ }
134
+
131
135
  function normalizePath(pathname) {
132
136
  if (!pathname) return "/";
133
- const normalized = pathname.endsWith("/") ? pathname : `${pathname}/`;
134
- return normalized;
137
+ // Treat /page.html and /page/ as the same document for cache/same-page checks.
138
+ let path = stripHtmlExtension(pathname);
139
+ if (!path.endsWith("/")) path = `${path}/`;
140
+ return path || "/";
135
141
  }
136
142
 
137
143
  function normalizeLinkKey(url) {
@@ -145,6 +151,30 @@
145
151
  );
146
152
  }
147
153
 
154
+ // Prefer paths that static hosts (esp. Cloudflare Pages) resolve correctly.
155
+ // Never request `page.html/` — that often SPA-fallbacks to the site index.
156
+ function fetchPathCandidates(pathname) {
157
+ const paths = [];
158
+ const push = (p) => {
159
+ if (p && !paths.includes(p)) paths.push(p);
160
+ };
161
+
162
+ if (/\.html?$/i.test(pathname)) {
163
+ push(pathname);
164
+ const withoutExt = stripHtmlExtension(pathname) || "/";
165
+ push(withoutExt);
166
+ if (!withoutExt.endsWith("/")) push(`${withoutExt}/`);
167
+ return paths;
168
+ }
169
+
170
+ const withSlash = pathname.endsWith("/") ? pathname : `${pathname}/`;
171
+ const withoutSlash = pathname.endsWith("/") ? pathname.replace(/\/+$/, "") || "/" : pathname;
172
+ push(withSlash);
173
+ push(withoutSlash);
174
+ if (withoutSlash !== "/") push(`${withoutSlash}.html`);
175
+ return paths;
176
+ }
177
+
148
178
  function isImagePath(pathname) {
149
179
  return /\.(avif|bmp|gif|ico|jpe?g|png|svg|webp)$/i.test(pathname);
150
180
  }
@@ -281,30 +311,25 @@
281
311
  }
282
312
 
283
313
  async function fetchPageDocument(pathname) {
284
- const cacheKey = pathname.endsWith("/") ? pathname : `${pathname}/`;
314
+ const cacheKey = normalizePath(pathname);
285
315
  if (pageCache.has(cacheKey)) return pageCache.get(cacheKey);
286
316
 
287
- const fetchPath = cacheKey;
288
- const response = await fetch(fetchPath, { credentials: "same-origin" });
289
- if (!response.ok) {
290
- const fallback = pathname.endsWith("/") ? pathname.slice(0, -1) : `${pathname}/`;
291
- if (fallback !== fetchPath) {
292
- const retry = await fetch(fallback, { credentials: "same-origin" });
293
- if (retry.ok) {
294
- const html = await retry.text();
295
- const doc = new DOMParser().parseFromString(html, "text/html");
296
- pageCache.set(cacheKey, doc);
297
- pageCache.set(fallback, doc);
298
- return doc;
299
- }
317
+ let lastError;
318
+ for (const fetchPath of fetchPathCandidates(pathname)) {
319
+ try {
320
+ const response = await fetch(fetchPath, { credentials: "same-origin" });
321
+ if (!response.ok) continue;
322
+
323
+ const html = await response.text();
324
+ const doc = new DOMParser().parseFromString(html, "text/html");
325
+ pageCache.set(cacheKey, doc);
326
+ return doc;
327
+ } catch (err) {
328
+ lastError = err;
300
329
  }
301
- throw new Error(`Failed to load ${fetchPath}`);
302
330
  }
303
331
 
304
- const html = await response.text();
305
- const doc = new DOMParser().parseFromString(html, "text/html");
306
- pageCache.set(cacheKey, doc);
307
- return doc;
332
+ throw lastError || new Error(`Failed to load ${pathname}`);
308
333
  }
309
334
 
310
335
  async function loadLinkContent(anchor) {
@@ -312,7 +337,7 @@
312
337
  const hash = url.hash;
313
338
 
314
339
  let doc;
315
- if (url.pathname === window.location.pathname && url.search === window.location.search) {
340
+ if (isSamePage(url)) {
316
341
  doc = document;
317
342
  } else {
318
343
  doc = await fetchPageDocument(url.pathname);
@@ -11,7 +11,7 @@ module Jekyll
11
11
  assets_path = cfg["assets_path"] || "/assets/jekyll-hover-popup"
12
12
  assets_path = "/#{assets_path}" unless assets_path.start_with?("/")
13
13
  hover_delay_ms = cfg["hover_delay_ms"] || 0
14
- nav_hover_preview = cfg.fetch("nav_hover_preview", true)
14
+ nav_hover_preview = cfg.fetch("nav_hover_preview", false)
15
15
 
16
16
  begin
17
17
  doc.output = inject_assets(doc.output.to_s, assets_path: assets_path, hover_delay_ms: hover_delay_ms, nav_hover_preview: nav_hover_preview)
@@ -21,7 +21,7 @@ module Jekyll
21
21
  end
22
22
  end
23
23
 
24
- def self.inject_assets(html, assets_path:, hover_delay_ms:, nav_hover_preview: true)
24
+ def self.inject_assets(html, assets_path:, hover_delay_ms:, nav_hover_preview: false)
25
25
  return html if html.include?('data-hover-popup-root="true"')
26
26
 
27
27
  tags = <<~HTML
@@ -1,5 +1,5 @@
1
1
  module Jekyll
2
2
  module HoverPopup
3
- VERSION = "0.2.0"
3
+ VERSION = "0.3.1"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jekyll-hover-popup
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - directsun