From 8d89e40b913f81dafd0c7d9178ee1d86a1c16f45 Mon Sep 17 00:00:00 2001 From: dev Date: Fri, 5 Jun 2026 08:43:22 -0500 Subject: [PATCH] fix(bundle): mirror source fixes in embedded userscript --- torn-attribute-tracker.user.js | 159 ++++++++++++++++++++------------- 1 file changed, 95 insertions(+), 64 deletions(-) diff --git a/torn-attribute-tracker.user.js b/torn-attribute-tracker.user.js index 062b9f0..190787a 100644 --- a/torn-attribute-tracker.user.js +++ b/torn-attribute-tracker.user.js @@ -122,76 +122,80 @@ } // ===== dom.js (embedded) ===== + const TAT_KNOWN_ATTRS = ['strength', 'defense', 'speed', 'dexterity', 'endurance', 'intelligence']; + const TAT_KNOWN_GYMS = [ + 'Total Bastion', 'Frontline Fitness', 'Premier Fitness', 'Average Joes', + "Woody's Workout Club", "Baldr's Gym", 'Sportscience Laboratory', + 'Chrome Gym', "Mr. Miyagi's", 'Power House', 'Gym 300', 'Gym 400', 'Gym 500', 'Gym 600', + 'Elite Gym', "David's Gym", + ]; function currentAttribute() { - const KNOWN = ['strength', 'defense', 'speed', 'dexterity', 'endurance', 'intelligence']; - const ATTR_RE = new RegExp('\\b(' + KNOWN.join('|') + ')\\b'); - const headers = document.querySelectorAll('h1, h2, h3, h4, .title, .gym-title, [class*="gym"]'); - let attr = null, attrEl = null; - for (const el of headers) { - const t = (el.textContent || '').trim().toLowerCase(); - const m = t.match(ATTR_RE); - if (m) { attr = m[1]; attrEl = el; break; } - } + const li = tatFindActiveAttributeLi(); + if (!li) return null; + const attr = tatExtractAttrFromLi(li); if (!attr) return null; - let valEl = findValueNear(attrEl); - if (!valEl) valEl = findValueElement(); - if (!valEl) return null; - const current = parseNumber(valEl.textContent); + const current = tatExtractValueFromLi(li); if (current == null) return null; - const gym = findGymName() || 'Unknown gym'; - return { attr: attr, current: current, gym: gym }; + const gym = tatFindGymName() || 'Unknown gym'; + return { attr: attr, current: current, gym: tatEsc(gym) }; } - function findValueNear(el) { - const scope = []; - let cur = el; - for (let depth = 0; depth < 3 && cur; depth++) { - scope.push(cur); - cur = cur.parentElement; + function tatFindActiveAttributeLi() { + // Priority 1: the
  • with the "success" class (just trained). + const lis = document.querySelectorAll('ul[class*="properties"] > li[class*="success"]'); + for (const li of lis) { + if (tatExtractAttrFromLi(li)) return li; } - let best = null, bestN = -Infinity; - for (const root of scope) { - const candidates = root.querySelectorAll('*'); - for (const c of candidates) { - if (c.children.length > 0) continue; - const t = (c.textContent || '').trim(); - if (!/^[\d,]+(\.\d+)?$/.test(t)) continue; - const n = parseNumber(t); - if (n == null || n < 1) continue; - if (n > bestN) { best = c; bestN = n; } + // Priority 2: the
  • corresponding to the .gained message's attribute. + const gained = document.querySelector('[class*="gained"]'); + if (gained) { + const text = (gained.textContent || '').toLowerCase(); + for (const attr of TAT_KNOWN_ATTRS) { + if (text.indexOf(attr) !== -1) { + const li = document.querySelector('ul[class*="properties"] > li[class^="' + attr + '___"]'); + if (li) return li; + } } } - return best; - } - function findValueElement() { - const candidates = document.querySelectorAll('*'); - let best = null, bestN = -Infinity; - for (const el of candidates) { - if (el.children.length > 0) continue; - const t = (el.textContent || '').trim(); - if (!/^[\d,]+(\.\d+)?$/.test(t)) continue; - const n = parseNumber(t); - if (n == null || n < 1) continue; - if (n > bestN) { best = el; bestN = n; } + // Priority 3: the first
  • in the properties list. + const all = document.querySelectorAll('ul[class*="properties"] > li'); + for (const li of all) { + if (tatExtractAttrFromLi(li)) return li; } - return best; + return null; } - function findGymName() { - const panel = document.querySelector('.gym, #gym, [class*="gym-"], [class*="Gym"]'); - const roots = panel ? [panel, document.body] : [document.body]; - const known = ['Total Bastion', 'Frontline Fitness', 'Gym 300', 'Gym 500', "Baldr's Gym", 'Sportscience Laboratory', 'Premier Fitness', 'Chrome Gym', "Mr. Miyagi's", 'Power House']; - for (const root of roots) { - const all = root.querySelectorAll('h1, h2, h3, h4, p, span, div, li'); - for (const el of all) { - if (el.children.length > 0) continue; - const t = (el.textContent || '').trim(); - for (const name of known) { if (t.includes(name)) return name; } + function tatExtractAttrFromLi(li) { + const cls = li.className || ''; + const parts = cls.split(/\s+/); + for (const attr of TAT_KNOWN_ATTRS) { + const prefix = attr + '___'; + for (const c of parts) { + if (c.indexOf(prefix) === 0) return attr; } } return null; } - function parseNumber(text) { + function tatExtractValueFromLi(li) { + const valueSpan = li.querySelector('[class^="propertyValue"]'); + if (!valueSpan) return null; + return tatParseNumber(valueSpan.textContent); + } + function tatFindGymName() { + // Gym names live in aria-labels of