GO-33-4: wrap manager classes in IIFEs, drop window.* namespace bridges
- Wrap pagination-manager/selection-manager/virtual-scroller in a strict IIFE
(column-0 body per the components.js/state.js convention) so their top-level
class no longer leaks a global binding; consumers already used GoingsOn.X so
no call sites change
- address-highlight.js: export only GoingsOn.addressHighlight; the window.attach*
fallback branch was dead (escape.js bootstraps GoingsOn before this file loads
in both compose.html and index.html)
- compose-form.js: export only GoingsOn.composeForm; drop window.GoingsOnComposeForm
and the dead window.attachAddressHighlight fallback
- compose.html: read GoingsOn.composeForm instead of the window global
node --check clean on all 5 files, JS gate 56/56, no window.* bridges remain.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
6 files changed,
+30 insertions,
-23 deletions
| 163 |
163 |
|
|
| 164 |
164 |
|
// Stage 4 of compose unification — autocomplete, address highlight,
|
| 165 |
165 |
|
// CC/BCC toggle, signature swap, and attachment picker/render/remove
|
| 166 |
|
- |
// now live in composeForm.bindBehaviors. The window keeps a thin
|
| 167 |
|
- |
// contacts loader (contactEmails) since it doesn't bootstrap the
|
| 168 |
|
- |
// GoingsOn namespace; the controller's getContacts callback reads it.
|
|
166 |
+ |
// now live in composeForm.bindBehaviors. This inline script keeps a thin
|
|
167 |
+ |
// contacts loader (contactEmails); the controller's getContacts callback
|
|
168 |
+ |
// reads it. escape.js bootstraps GoingsOn here, so the compose API is on
|
|
169 |
+ |
// the namespace.
|
| 169 |
170 |
|
|
| 170 |
|
- |
const composeForm = window.GoingsOnComposeForm;
|
|
171 |
+ |
const composeForm = GoingsOn.composeForm;
|
| 171 |
172 |
|
let composeCtrl = null;
|
| 172 |
173 |
|
let contactEmails = []; // [{name, email, isImplicit}]
|
| 173 |
174 |
|
|
| 270 |
270 |
|
// (js/escape.js), loaded before this file in both compose.html and index.html.
|
| 271 |
271 |
|
const escapeHtml = GoingsOn.escape.escapeHtml;
|
| 272 |
272 |
|
|
| 273 |
|
- |
// Export to GoingsOn namespace or window (for standalone compose.html)
|
| 274 |
|
- |
if (typeof GoingsOn !== 'undefined') {
|
| 275 |
|
- |
GoingsOn.addressHighlight = { attach, detach, clearCache };
|
| 276 |
|
- |
} else {
|
| 277 |
|
- |
window.attachAddressHighlight = attach;
|
| 278 |
|
- |
window.detachAddressHighlight = detach;
|
| 279 |
|
- |
window.clearAddressHighlightCache = clearCache;
|
| 280 |
|
- |
}
|
|
273 |
+ |
// Export to the GoingsOn namespace. escape.js (loaded before this file in
|
|
274 |
+ |
// both compose.html and index.html) guarantees GoingsOn exists, so no
|
|
275 |
+ |
// window.* fallback is needed.
|
|
276 |
+ |
GoingsOn.addressHighlight = { attach, detach, clearCache };
|
| 281 |
277 |
|
|
| 282 |
278 |
|
})();
|
| 358 |
358 |
|
attachAutocomplete(ccEl);
|
| 359 |
359 |
|
attachAutocomplete(bccEl);
|
| 360 |
360 |
|
|
| 361 |
|
- |
// ---------- Address highlight (uses whichever helper the surface loaded) ----------
|
| 362 |
|
- |
const ahAttach = (window.GoingsOn && window.GoingsOn.addressHighlight && window.GoingsOn.addressHighlight.attach)
|
| 363 |
|
- |
|| (typeof window.attachAddressHighlight === 'function' ? window.attachAddressHighlight : null);
|
|
361 |
+ |
// ---------- Address highlight (GoingsOn.addressHighlight, if the surface loaded it) ----------
|
|
362 |
+ |
const ahAttach = window.GoingsOn && window.GoingsOn.addressHighlight && window.GoingsOn.addressHighlight.attach;
|
| 364 |
363 |
|
if (ahAttach) {
|
| 365 |
364 |
|
const ahOpts = { contacts: getContacts };
|
| 366 |
365 |
|
// Tauri's `invoke` is needed by the IMAP-backed lookup in
|
| 616 |
615 |
|
bindBehaviors,
|
| 617 |
616 |
|
};
|
| 618 |
617 |
|
|
| 619 |
|
- |
// Compose.html is a standalone webview that doesn't bootstrap the
|
| 620 |
|
- |
// GoingsOn namespace, so we attach to window as well for that path.
|
| 621 |
|
- |
if (typeof window !== 'undefined') {
|
| 622 |
|
- |
window.GoingsOnComposeForm = api;
|
| 623 |
|
- |
if (window.GoingsOn) {
|
| 624 |
|
- |
window.GoingsOn.composeForm = api;
|
| 625 |
|
- |
}
|
| 626 |
|
- |
}
|
|
618 |
+ |
// escape.js bootstraps the GoingsOn namespace even in the standalone
|
|
619 |
+ |
// compose.html webview (this file already depends on GoingsOn.escape), so
|
|
620 |
+ |
// the API lives on the namespace, not a bare window global.
|
|
621 |
+ |
GoingsOn.composeForm = api;
|
| 627 |
622 |
|
})();
|
| 4 |
4 |
|
* Replaces duplicate pagination code in tasks.js and emails.js.
|
| 5 |
5 |
|
*/
|
| 6 |
6 |
|
|
|
7 |
+ |
(function() {
|
|
8 |
+ |
'use strict';
|
|
9 |
+ |
|
| 7 |
10 |
|
class PaginationManager {
|
| 8 |
11 |
|
/**
|
| 9 |
12 |
|
* Create a pagination manager.
|
| 152 |
155 |
|
if (window.GoingsOn) {
|
| 153 |
156 |
|
GoingsOn.PaginationManager = PaginationManager;
|
| 154 |
157 |
|
}
|
|
158 |
+ |
|
|
159 |
+ |
})();
|
| 6 |
6 |
|
* Supports both DOM-based and data-based range selection for virtual scrolling.
|
| 7 |
7 |
|
*/
|
| 8 |
8 |
|
|
|
9 |
+ |
(function() {
|
|
10 |
+ |
'use strict';
|
|
11 |
+ |
|
| 9 |
12 |
|
class SelectionManager {
|
| 10 |
13 |
|
/**
|
| 11 |
14 |
|
* Create a selection manager.
|
| 213 |
216 |
|
if (window.GoingsOn) {
|
| 214 |
217 |
|
GoingsOn.SelectionManager = SelectionManager;
|
| 215 |
218 |
|
}
|
|
219 |
+ |
|
|
220 |
+ |
})();
|
| 4 |
4 |
|
* Only renders visible DOM nodes + overscan buffer.
|
| 5 |
5 |
|
*/
|
| 6 |
6 |
|
|
|
7 |
+ |
(function() {
|
|
8 |
+ |
'use strict';
|
|
9 |
+ |
|
| 7 |
10 |
|
class VirtualScroller {
|
| 8 |
11 |
|
/**
|
| 9 |
12 |
|
* Create a virtual scroller instance.
|
| 417 |
420 |
|
if (window.GoingsOn) {
|
| 418 |
421 |
|
GoingsOn.VirtualScroller = VirtualScroller;
|
| 419 |
422 |
|
}
|
|
423 |
+ |
|
|
424 |
+ |
})();
|