Skip to content

Commit 4b73934

Browse files
committed
release: bump to v0.8.8
1 parent 352a70f commit 4b73934

9 files changed

Lines changed: 1739 additions & 9 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "weavero",
3-
"version": "0.8.7",
3+
"version": "0.8.8",
44
"private": true,
55
"description": "A Zotero plugin to make clickable links and filter your library.",
66
"homepage": "https://github.com/mjthoraval/Weavero",

src/index.ts

Lines changed: 141 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ class WeaveroPlugin {
7171
this._sidebarHandler = (event) => this._sidebarHandlerImpl(event);
7272
this._contextHandler = (event) => this._contextHandlerImpl(event);
7373
this._viewContextHandler = (event) => this._viewContextHandlerImpl(event);
74+
this._toolbarHandler = (event) => this._toolbarHandlerImpl(event);
7475
}
7576

7677
// ---- Utilities --------------------------------------------------------
@@ -672,6 +673,24 @@ class WeaveroPlugin {
672673
return this._getEnableMarkdown() || this._getEnableCommentMarkdown();
673674
}
674675

676+
/** Compact title bar — hide the menubar row in the main window and move
677+
* the window controls into the tab strip (Firefox-style "tabs in
678+
* titlebar"). Default OFF: existing users keep the standard menubar
679+
* unless they explicitly opt in. Mac-excluded by the apply method.
680+
*
681+
* Reads tolerate the pref being stored as either a bool (Prefs.set
682+
* with a boolean — the normal path) OR a string (some external tools
683+
* write `"true"` / `"false"`). Without the string check, `!!"false"`
684+
* evaluates to `true` and the feature silently stays on. */
685+
_getCompactTitleBar() {
686+
try {
687+
const v = Zotero.Prefs.get("weavero.compactTitleBar");
688+
if (v === undefined) return false;
689+
if (typeof v === "string") return v.toLowerCase() === "true";
690+
return !!v;
691+
} catch (e) { return false; }
692+
}
693+
675694
// ====================================================================
676695
// Per-feature toggles introduced in v0.8.1.
677696
// Pattern: each group has a master pref + per-feature children.
@@ -1730,13 +1749,23 @@ class WeaveroPlugin {
17301749
this._resetStaleMarkers(win && win.document);
17311750
} catch(e) {}
17321751

1733-
// 2. Reader event listeners
1752+
// 2. Reader event listeners.
1753+
// The pluginID MUST be the full addon ID ("weavero@mjthoraval"),
1754+
// not a short slug. Zotero's `Plugins.addObserver({shutdown})`
1755+
// hook calls `_unregisterEventListenerByPluginID(id)` with the
1756+
// addon ID, filtering listeners by `pluginID !== id`. A short
1757+
// slug never matches, so prior-version listeners survive plugin
1758+
// upgrades and a second registration in the new init() leaves
1759+
// TWO live listeners — visible to the user as duplicate toolbar
1760+
// buttons in standalone reader windows.
17341761
Zotero.Reader.registerEventListener(
1735-
"renderSidebarAnnotationHeader", this._sidebarHandler, "weavero");
1762+
"renderSidebarAnnotationHeader", this._sidebarHandler, "weavero@mjthoraval");
17361763
Zotero.Reader.registerEventListener(
1737-
"createAnnotationContextMenu", this._contextHandler, "weavero");
1764+
"createAnnotationContextMenu", this._contextHandler, "weavero@mjthoraval");
17381765
Zotero.Reader.registerEventListener(
1739-
"createViewContextMenu", this._viewContextHandler, "weavero");
1766+
"createViewContextMenu", this._viewContextHandler, "weavero@mjthoraval");
1767+
Zotero.Reader.registerEventListener(
1768+
"renderToolbar", this._toolbarHandler, "weavero@mjthoraval");
17401769

17411770
// 3. Notifier: new reader tabs
17421771
this._notifierIDs.push(Zotero.Notifier.registerObserver({
@@ -2201,6 +2230,50 @@ class WeaveroPlugin {
22012230
this._applyTreeIconPref(this._getShowTreeIcon());
22022231
this._applyInlineLinksPref(this._getInlineLinks());
22032232
this._applyCommentMarkdownPref();
2233+
// Defensive: prune dead entries from `Zotero.Reader._readers`.
2234+
// Earlier dev builds occasionally left a ReaderWindow in the list
2235+
// after its chrome window was destroyed; the dead entry then
2236+
// broke the next `Zotero.Reader.open` call ("can't access dead
2237+
// object" at reader.js:73). Even with the unload-cleanup we
2238+
// added in `_applyReaderCompactMenubar`, this self-heal at every
2239+
// init keeps the user unblocked if a leak slips through.
2240+
try {
2241+
const readers = (Zotero as any).Reader?._readers;
2242+
if (Array.isArray(readers)) {
2243+
let pruned = 0;
2244+
for (let i = readers.length - 1; i >= 0; i--) {
2245+
try {
2246+
const _ = readers[i].tabID; // throws if dead
2247+
} catch (e) {
2248+
readers.splice(i, 1);
2249+
pruned++;
2250+
}
2251+
}
2252+
if (pruned) Zotero.debug("[Weavero] init: pruned " + pruned + " dead reader(s) from Zotero.Reader._readers");
2253+
}
2254+
} catch (e) {}
2255+
2256+
// Compact title bar — apply to any already-open main windows.
2257+
// `onMainWindowLoad` only fires for NEW windows, so on Zotero
2258+
// restart the existing window won't trigger it; we apply here
2259+
// from init() too. Idempotent: `_applyCompactTitleBar` early-
2260+
// returns when a stash already exists, so onMainWindowLoad's
2261+
// call later (for fresh windows) doesn't double-apply.
2262+
try {
2263+
if (this._getCompactTitleBar()) {
2264+
const wins = Zotero.getMainWindows ? Zotero.getMainWindows() : [Zotero.getMainWindow()].filter(Boolean);
2265+
for (const w of wins) {
2266+
try { this._applyCompactTitleBar(w); } catch (e) {}
2267+
}
2268+
// Same for any already-open standalone reader windows.
2269+
// Newly opened readers are handled by the renderToolbar
2270+
// event path in `_toolbarHandlerImpl`.
2271+
const readers = (Zotero.Reader._readers || []).filter(r => !r.tabID && r._window);
2272+
for (const r of readers) {
2273+
try { this._applyReaderCompactMenubar(r); } catch (e) {}
2274+
}
2275+
}
2276+
} catch (e) { Zotero.debug("[Weavero] init compactTitleBar err: " + e); }
22042277
this._applyUIThemeClass();
22052278
// Sync per-scheme `network.protocol-handler.warn-external.<x>`
22062279
// prefs with the user's "Open without confirmation" choice.
@@ -2287,6 +2360,27 @@ class WeaveroPlugin {
22872360
if (data === "extensions.zotero.weavero.enableReaderViewIcons") {
22882361
this._applySurfacePref("readerView");
22892362
}
2363+
// Compact title bar — apply or revert across every main
2364+
// window AND every standalone reader window so the
2365+
// change is visible without a restart.
2366+
if (data === "extensions.zotero.weavero.compactTitleBar") {
2367+
try {
2368+
const on = this._getCompactTitleBar();
2369+
const wins = Zotero.getMainWindows ? Zotero.getMainWindows() : [Zotero.getMainWindow()].filter(Boolean);
2370+
for (const w of wins) {
2371+
if (on) this._applyCompactTitleBar(w);
2372+
else this._revertCompactTitleBar(w);
2373+
}
2374+
// Reader windows — iterate every window-mode
2375+
// ReaderInstance and apply/revert the menubar
2376+
// collapse.
2377+
const readers = (Zotero.Reader._readers || []).filter(r => !r.tabID && r._window);
2378+
for (const r of readers) {
2379+
if (on) this._applyReaderCompactMenubar(r);
2380+
else this._revertReaderCompactMenubar(r);
2381+
}
2382+
} catch (e) { Zotero.debug("[Weavero] compactTitleBar toggle err: " + e); }
2383+
}
22902384
// Tags column auto-count toggle — (1) resize the
22912385
// column to fit one or two numbers, (2) re-render
22922386
// the items view so already-painted Tags cells pick
@@ -2713,6 +2807,12 @@ class WeaveroPlugin {
27132807
this._applyInlineLinksPref(this._getInlineLinks());
27142808
this._applyCommentMarkdownPref();
27152809
this._applyUIThemeClass();
2810+
// Apply compact-title-bar mode if the pref is on (default off).
2811+
// Runs after the window is fully laid out so the buttonbox move
2812+
// doesn't race against Zotero's own titlebar init.
2813+
try {
2814+
if (this._getCompactTitleBar()) this._applyCompactTitleBar(_window);
2815+
} catch (e) { Zotero.debug("[Weavero] _applyCompactTitleBar onLoad err: " + e); }
27162816
// Refresh sidebar icons across any open readers. The
27172817
// renderSidebarAnnotationHeader event won't re-fire for rows
27182818
// that were already mounted before the plugin (re-)started,
@@ -2821,9 +2921,43 @@ class WeaveroPlugin {
28212921
this._uiThemeObserver = null;
28222922
}
28232923

2824-
try { (Zotero.Reader as any).unregisterEventListener("renderSidebarAnnotationHeader", "weavero"); } catch(e) {}
2825-
try { (Zotero.Reader as any).unregisterEventListener("createAnnotationContextMenu", "weavero"); } catch(e) {}
2826-
try { (Zotero.Reader as any).unregisterEventListener("createViewContextMenu", "weavero"); } catch(e) {}
2924+
// Reader event listeners are cleaned up by Zotero's plugin-
2925+
// shutdown observer (`_unregisterEventListenerByPluginID`,
2926+
// wired in xpcom/reader.js), which fires on plugin disable /
2927+
// upgrade and filters listeners by pluginID. We DON'T call
2928+
// `unregisterEventListener(type, handler)` manually because
2929+
// Zotero's implementation is inverted — it does
2930+
// `filter(x => x.type === type && x.handler === handler)`,
2931+
// which KEEPS the matching listener and discards all others,
2932+
// i.e. it would wipe other plugins' listeners on any actual
2933+
// match (and our prior code passed a string where a handler
2934+
// was expected, so the predicate never matched and it merely
2935+
// wiped everything). Registering with the correct full plugin
2936+
// ID is enough — the shutdown observer handles teardown.
2937+
// Revert compact-title-bar across every main window AND every
2938+
// standalone reader window so unloading the plugin doesn't leave
2939+
// the DOM mutilated (buttonbox moved, icon hidden, menubar
2940+
// collapsed). SKIPPED during app shutdown — the windows are
2941+
// about to be destroyed anyway, and reverting here was found
2942+
// to interfere with Zotero's session save (Session.save reads
2943+
// `Zotero.getZoteroPanes()` from `quit-application-granted`;
2944+
// if our long synchronous DOM revert delays things, the panes
2945+
// are gone by save time and the old tab state gets restored,
2946+
// making closed tabs reappear on next startup).
2947+
try {
2948+
if (!Services.startup.shuttingDown) {
2949+
const wins = Zotero.getMainWindows ? Zotero.getMainWindows() : [Zotero.getMainWindow()].filter(Boolean);
2950+
for (const w of wins) {
2951+
try { this._revertCompactTitleBar(w); } catch(e) {}
2952+
}
2953+
const readers = (Zotero.Reader._readers || []).filter(r => !r.tabID && r._window);
2954+
for (const r of readers) {
2955+
try { this._revertReaderCompactMenubar(r); } catch(e) {}
2956+
}
2957+
} else {
2958+
Zotero.debug("[Weavero] destroy: app shutting down, skipping compact-title-bar revert");
2959+
}
2960+
} catch (e) {}
28272961
this._unregisterItemTreeColumns();
28282962
try { this._unpatchAnnotationRow(); } catch (e) {}
28292963

src/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"manifest_version": 2,
33
"name": "Weavero",
4-
"version": "0.8.7",
4+
"version": "0.8.8",
55
"description": "A Zotero plugin to make clickable links and filter your library.",
66
"author": "mjthoraval",
77
"homepage_url": "https://github.com/mjthoraval/Weavero",

src/modules/constants.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,11 @@ export const PLUGIN_CSS = [
579579
".wv-tags-count-manual {",
580580
" color: var(--accent-blue, #2ea8e5); font-weight: 600;",
581581
"}",
582+
// On a selected row the accent-blue clashes with the selection
583+
// background (blue-on-blue) — fall back to the row's own (light)
584+
// text colour there, keeping the bold weight so the manual count
585+
// still reads as the emphasised one.
586+
".selected .wv-tags-count-manual { color: inherit; }",
582587
".wv-tags-count-auto {",
583588
" color: currentColor; opacity: 0.85;",
584589
"}",

src/modules/filter.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ import {
5757
// so these live as module-private consts and are exposed via
5858
// getters on the mixin prototype.
5959

60+
// The same 8 highlight-and-friends colours Zotero ships in
61+
// `ANNOTATION_COLORS` (reader/src/common/defines.js), plus
62+
// Black from `EXTRA_INK_AND_TEXT_COLORS` — upstream restricts
63+
// Black to ink/text annotations, but those exist in the wild,
64+
// so we need to be able to filter on it.
6065
const _ANNOTATION_COLORS_DATA = [
6166
{ value: "#ffd400", label: "Yellow" },
6267
{ value: "#ff6666", label: "Red" },
@@ -66,6 +71,7 @@ const _ANNOTATION_COLORS_DATA = [
6671
{ value: "#e56eee", label: "Magenta" },
6772
{ value: "#f19837", label: "Orange" },
6873
{ value: "#aaaaaa", label: "Gray" },
74+
{ value: "#000000", label: "Black" },
6975
];
7076

7177
const _ANNOTATION_TYPES_DATA = [

0 commit comments

Comments
 (0)