Commit Graph

35 Commits

Author SHA1 Message Date
Claude 501c6746eb fix(main): hoist let bindings to top of start() to fix TDZ on anchorError
The applyMode() function reads/writes anchorError, lastSnapshot, and other
let-bound state. Function declarations are hoisted, so applyMode() can fire
from inside the dialog.mount() / applyMode() call sequence at the top of
start() — but the let bindings themselves are not initialized until
execution reaches their declaration line, which came later.

When prefs.mode === 'anchored' and findAnchorElement() returns null, the
new 'anchor missed' branch writes to anchorError and calls render(). Both
access anchorError before its let binding is initialized, throwing
ReferenceError: Cannot access 'anchorError' before initialization.

Move all four let declarations (lastSnapshot, lastAttr, lastDelta,
anchorError) to the top of start(), before dialog.mount() and applyMode().
Function declarations are unaffected — they are hoisted regardless.
2026-06-01 22:22:29 -05:00
dev 578736a492 fix(test): adjust comment formatting for clarity in computeEstimate tests 2026-06-01 21:42:39 -05:00
Claude a061410f16 fix(bundle): mirror source fixes in embedded userscript
Mirror the three source-level fixes in the embedded copies inside
torn-attribute-tracker.user.js:

1. _wireHeaderDrag: add the .tat-header closest() guard so the bundle
   no longer steals focus from inputs/selects.
2. findAnchorElement: replace the narrow 'button[name="train"]' query
   with the priority-ordered candidate list and the gym-panel last-
   ditch fallback.
3. Inline anchor-error UX: add the anchorError state, include it in
   the snapshot, surface it via applyMode, render the note with the
   .tat-anchor-err class, and add the corresponding CSS rule.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 18:47:39 -05:00
Claude bb33bcbb61 fix(main): broaden anchor selector and show inline "can't anchor" note
findAnchorElement used a narrow selector ('button[name="train"],
a[href*="train"]') that often missed Torn's actual gym page DOM.
When it missed, applyMode fell through to dialog.setMode('free'),
snapping the dialog to the default bottom-right position — which the
user perceived as a 'bounce' when clicking 'Above training UI'.

Widen the selector to a priority-ordered candidate list and prefer the
form ancestor of any matched element. As a last-ditch, look for a form
inside the gym panel. This covers more of Torn's gym-page variations.

When the anchor selector still misses, do NOT snap to the default free
position. Instead, keep the dialog where it is, set anchorError on the
state, and let the dialog render an inline note so the user gets
visible feedback explaining what happened.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 18:45:40 -05:00
Claude e200faf8c4 fix(ui): scope mousedown handler to .tat-header to restore input/select focus
The dialog's mousedown listener was attached to the whole root and
unconditionally called preventDefault(), which blocked the target
element from receiving focus. As a result, the custom target <input>
and the milestone <select> could never be focused.

Only initiate drag (and only preventDefault) when the mousedown is on
the .tat-header bar. This lets the user click into inputs, selects, and
buttons inside the dialog body, while still allowing the dialog to be
dragged from the title bar.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 18:42:16 -05:00
dev ef90a6b779 Add design document for Torn Attribute Training Tracker
- Introduced a new userscript for torn.com to assist players in planning attribute training.
- Document outlines the purpose, scope, architecture, dialog content, placement modes, error handling, testing, and file layout.
- Details on data handling, UI interactions, and user preferences included.
2026-06-01 18:16:02 -05:00
dev ecea14b051 test(build): extend behavioral drift checks to all four pure functions 2026-06-01 17:59:36 -05:00
dev e21582b7c4 fix(bundle): strict 30-day boundary in pruneHistory to match src/pure.js 2026-06-01 17:59:06 -05:00
dev adc8a5dec9 docs: README with install, usage, and self-test instructions 2026-06-01 17:40:18 -05:00
dev a5f402132e test(build): catch behavioral drift in bundle summary via eval-extracted comparison 2026-06-01 17:37:46 -05:00
dev 62fe86a71f test(build): verify userscript bundle embeds pure functions and self-test 2026-06-01 17:31:24 -05:00
dev 75f10126d2 fix(bundle): floor perDay in summary and hoist self alias in render 2026-06-01 17:28:41 -05:00
dev 7c2533d188 feat: bundle torn-attribute-tracker.user.js (Tat-style Tampermonkey script) 2026-06-01 17:16:54 -05:00
dev 36a6b4c52d fix(main): keep prefs.mode in sync and rAF-coalesce mutation observer 2026-06-01 17:09:38 -05:00
dev 12fc79022f feat(main): wire Store + Dialog + DataLayer on /gym.php 2026-06-01 17:03:03 -05:00
dev 8502c53663 fix(ui): escape user strings, lazy drag listeners, drop dead warn field 2026-06-01 16:58:12 -05:00
dev 3053a6d713 feat(ui): Dialog with render, drag, mode toggle, milestone dropdown 2026-06-01 16:52:25 -05:00
dev cd6fb7cf91 fix(interceptor): guard XHR double-wrap and thread currentAttr into regex fallback 2026-06-01 16:47:39 -05:00
dev 491d3201f8 feat(interceptor): XHR/fetch wrap to detect Train responses 2026-06-01 16:41:01 -05:00
dev aec9c40835 fix(dom): scope value search near attribute, whole-word matching, panel-scoped gym name 2026-06-01 16:38:22 -05:00
dev e647fbf545 feat(dom): currentAttribute scraper for gym page (manual verify) 2026-06-01 16:32:44 -05:00
dev 3d000c70ff test(store): cover recordTrain validation and getSummary on unknown attr 2026-06-01 16:29:25 -05:00
dev 07215e5617 feat(store): recordTrain with pruning and getSummary 2026-06-01 16:22:18 -05:00
dev e39758c1af feat(store): _saveDisabled latch and stronger corruption-wipe coverage 2026-06-01 16:16:21 -05:00
dev 231890a9e0 feat(store): load/save and target accessors with validation 2026-06-01 16:08:42 -05:00
dev 48e51054ca docs(pure): note that summary.perDay is integer-rounded 2026-06-01 16:03:27 -05:00
dev 5fd0f5e548 feat(pure): summary with today/week counts and per-day rate 2026-06-01 15:54:43 -05:00
dev a2e23341ac refactor(pure): share MS_PER_DAY with tests and document pruneHistory 2026-06-01 15:48:52 -05:00
dev ca753bf196 feat(pure): pruneHistory with strict 30-day window 2026-06-01 15:42:37 -05:00
dev 757139624f refactor(pure): extract MS_PER_DAY constant and document computeEstimate precondition 2026-06-01 15:36:56 -05:00
dev faae7702aa feat(pure): computeEstimate with safe division and target-reached handling 2026-06-01 15:30:07 -05:00
dev 545cf65beb refactor(pure): remove duplicate regex and dead empty-string guard 2026-06-01 15:24:55 -05:00
dev e0540468c3 feat(pure): parseTarget with comma and magnitude suffix support 2026-06-01 15:16:12 -05:00
dev 07ef131d65 chore: broaden .gitignore for logs and OS junk 2026-06-01 15:07:26 -05:00
dev b1ab57596d chore: initialize project 2026-06-01 15:01:31 -05:00