v0.14.11 - Fix DOM selector: onmouseover is on inner div, not .eqb parent

- .eqb parent has onclick and structure, but the onmouseover with
  equips.set() and the item name text are on a CHILD div within .eqb
- Fixed scrapeCharacterEquip() and triggerAllTooltips() to query
  :scope > div[onmouseover] inside each .eqb slot
- Fixed debugScrapeGear() diagnostic to show inner div content
This commit is contained in:
GaboGG 2026-07-27 15:28:58 -04:00
parent 992c6acc38
commit c632c13818
5 changed files with 39 additions and 30 deletions

View file

@ -1,7 +1,7 @@
// ==UserScript== // ==UserScript==
// @name HV Unified // @name HV Unified
// @namespace hvunified // @namespace hvunified
// @version 0.14.10 // @version 0.14.11
// @description HV Unified — battle automation, guidance, and UI enhancements for HentaiVerse // @description HV Unified — battle automation, guidance, and UI enhancements for HentaiVerse
// @author GaboGG + Hermes // @author GaboGG + Hermes
// @match *://*.hentaiverse.org/* // @match *://*.hentaiverse.org/*
@ -17,7 +17,7 @@
// CONFIG — default settings // CONFIG — default settings
// ═══════════════════════════════════════════════════════════════════════ // ═══════════════════════════════════════════════════════════════════════
const VERSION = '0.14.10'; const VERSION = '0.14.11';
const CFG = { const CFG = {
// — Battle automation // — Battle automation
@ -3265,9 +3265,11 @@ function debugScrapeGear() {
console.log(`%c[HV] #eqsb found: ${slots.length} equipment slots`, 'color:#0f0'); console.log(`%c[HV] #eqsb found: ${slots.length} equipment slots`, 'color:#0f0');
slots.forEach((s, i) => { slots.forEach((s, i) => {
const omo = s.getAttribute('onmouseover') || ''; const omo = s.getAttribute('onmouseover') || '';
const nameEl = s.querySelector(':scope > div:not([class])') || s.querySelector('div'); // The onmouseover is on the inner name div, not the .eqb parent
const name = nameEl ? (nameEl.textContent || '').trim() : 'no name'; const nameDiv = s.querySelector(':scope > div[onmouseover]');
console.log(` [${i}] ${name} | onmouseover: ${omo.substring(0, 80)}`); const innerOmo = nameDiv ? (nameDiv.getAttribute('onmouseover') || '') : '';
const name = nameDiv ? (nameDiv.textContent || '').trim() : 'no name';
console.log(` [${i}] ${name} | onmouseover: ${(innerOmo || omo).substring(0, 80)}`);
}); });
} else { } else {
console.log(`%c[HV] ❌ #eqsb NOT FOUND`, 'color:#f44'); console.log(`%c[HV] ❌ #eqsb NOT FOUND`, 'color:#f44');
@ -3414,13 +3416,13 @@ function scrapeCharacterEquip() {
const slots = document.querySelectorAll('#eqsb > .eqb'); const slots = document.querySelectorAll('#eqsb > .eqb');
slots.forEach(slot => { slots.forEach(slot => {
// Get item ID from onmouseover // onmouseover is on the inner name div, not the .eqb parent
const omo = slot.getAttribute('onmouseover') || slot.querySelector('[onmouseover]')?.getAttribute('onmouseover') || ''; const nameDiv = slot.querySelector(':scope > div[onmouseover]');
const omo = nameDiv ? (nameDiv.getAttribute('onmouseover') || '') : slot.getAttribute('onmouseover') || '';
const idMatch = omo.match(/equips\.set\((\d+)/); const idMatch = omo.match(/equips\.set\((\d+)/);
const itemId = idMatch ? idMatch[1] : ''; const itemId = idMatch ? idMatch[1] : '';
// Get item name from the child div (text node) // Name is the text content of the name div
const nameDiv = slot.querySelector(':scope > div:not([class])') || slot.querySelector('div');
const name = nameDiv ? (nameDiv.textContent || '').trim() : ''; const name = nameDiv ? (nameDiv.textContent || '').trim() : '';
// Check if slot is disabled // Check if slot is disabled
@ -3557,7 +3559,8 @@ function triggerAllTooltips() {
const results = []; const results = [];
slots.forEach(slot => { slots.forEach(slot => {
const omo = slot.getAttribute('onmouseover') || ''; const nameDiv = slot.querySelector(':scope > div[onmouseover]');
const omo = nameDiv ? (nameDiv.getAttribute('onmouseover') || '') : slot.getAttribute('onmouseover') || '';
const idMatch = omo.match(/equips\.set\((\d+)/); const idMatch = omo.match(/equips\.set\((\d+)/);
if (idMatch && typeof equips !== 'undefined' && equips.set) { if (idMatch && typeof equips !== 'undefined' && equips.set) {
// Trigger the tooltip // Trigger the tooltip

View file

@ -1,7 +1,7 @@
// ==UserScript== // ==UserScript==
// @name HV Unified // @name HV Unified
// @namespace hvunified // @namespace hvunified
// @version 0.14.10 // @version 0.14.11
// @description HV Unified — battle automation, guidance, and UI enhancements for HentaiVerse // @description HV Unified — battle automation, guidance, and UI enhancements for HentaiVerse
// @author GaboGG + Hermes // @author GaboGG + Hermes
// @match *://*.hentaiverse.org/* // @match *://*.hentaiverse.org/*
@ -17,7 +17,7 @@
// CONFIG — default settings // CONFIG — default settings
// ═══════════════════════════════════════════════════════════════════════ // ═══════════════════════════════════════════════════════════════════════
const VERSION = '0.14.10'; const VERSION = '0.14.11';
const CFG = { const CFG = {
// — Battle automation // — Battle automation
@ -3265,9 +3265,11 @@ function debugScrapeGear() {
console.log(`%c[HV] #eqsb found: ${slots.length} equipment slots`, 'color:#0f0'); console.log(`%c[HV] #eqsb found: ${slots.length} equipment slots`, 'color:#0f0');
slots.forEach((s, i) => { slots.forEach((s, i) => {
const omo = s.getAttribute('onmouseover') || ''; const omo = s.getAttribute('onmouseover') || '';
const nameEl = s.querySelector(':scope > div:not([class])') || s.querySelector('div'); // The onmouseover is on the inner name div, not the .eqb parent
const name = nameEl ? (nameEl.textContent || '').trim() : 'no name'; const nameDiv = s.querySelector(':scope > div[onmouseover]');
console.log(` [${i}] ${name} | onmouseover: ${omo.substring(0, 80)}`); const innerOmo = nameDiv ? (nameDiv.getAttribute('onmouseover') || '') : '';
const name = nameDiv ? (nameDiv.textContent || '').trim() : 'no name';
console.log(` [${i}] ${name} | onmouseover: ${(innerOmo || omo).substring(0, 80)}`);
}); });
} else { } else {
console.log(`%c[HV] ❌ #eqsb NOT FOUND`, 'color:#f44'); console.log(`%c[HV] ❌ #eqsb NOT FOUND`, 'color:#f44');
@ -3414,13 +3416,13 @@ function scrapeCharacterEquip() {
const slots = document.querySelectorAll('#eqsb > .eqb'); const slots = document.querySelectorAll('#eqsb > .eqb');
slots.forEach(slot => { slots.forEach(slot => {
// Get item ID from onmouseover // onmouseover is on the inner name div, not the .eqb parent
const omo = slot.getAttribute('onmouseover') || slot.querySelector('[onmouseover]')?.getAttribute('onmouseover') || ''; const nameDiv = slot.querySelector(':scope > div[onmouseover]');
const omo = nameDiv ? (nameDiv.getAttribute('onmouseover') || '') : slot.getAttribute('onmouseover') || '';
const idMatch = omo.match(/equips\.set\((\d+)/); const idMatch = omo.match(/equips\.set\((\d+)/);
const itemId = idMatch ? idMatch[1] : ''; const itemId = idMatch ? idMatch[1] : '';
// Get item name from the child div (text node) // Name is the text content of the name div
const nameDiv = slot.querySelector(':scope > div:not([class])') || slot.querySelector('div');
const name = nameDiv ? (nameDiv.textContent || '').trim() : ''; const name = nameDiv ? (nameDiv.textContent || '').trim() : '';
// Check if slot is disabled // Check if slot is disabled
@ -3557,7 +3559,8 @@ function triggerAllTooltips() {
const results = []; const results = [];
slots.forEach(slot => { slots.forEach(slot => {
const omo = slot.getAttribute('onmouseover') || ''; const nameDiv = slot.querySelector(':scope > div[onmouseover]');
const omo = nameDiv ? (nameDiv.getAttribute('onmouseover') || '') : slot.getAttribute('onmouseover') || '';
const idMatch = omo.match(/equips\.set\((\d+)/); const idMatch = omo.match(/equips\.set\((\d+)/);
if (idMatch && typeof equips !== 'undefined' && equips.set) { if (idMatch && typeof equips !== 'undefined' && equips.set) {
// Trigger the tooltip // Trigger the tooltip

View file

@ -2,7 +2,7 @@
// CONFIG — default settings // CONFIG — default settings
// ═══════════════════════════════════════════════════════════════════════ // ═══════════════════════════════════════════════════════════════════════
const VERSION = '0.14.10'; const VERSION = '0.14.11';
const CFG = { const CFG = {
// — Battle automation // — Battle automation

View file

@ -22,9 +22,11 @@ function debugScrapeGear() {
console.log(`%c[HV] #eqsb found: ${slots.length} equipment slots`, 'color:#0f0'); console.log(`%c[HV] #eqsb found: ${slots.length} equipment slots`, 'color:#0f0');
slots.forEach((s, i) => { slots.forEach((s, i) => {
const omo = s.getAttribute('onmouseover') || ''; const omo = s.getAttribute('onmouseover') || '';
const nameEl = s.querySelector(':scope > div:not([class])') || s.querySelector('div'); // The onmouseover is on the inner name div, not the .eqb parent
const name = nameEl ? (nameEl.textContent || '').trim() : 'no name'; const nameDiv = s.querySelector(':scope > div[onmouseover]');
console.log(` [${i}] ${name} | onmouseover: ${omo.substring(0, 80)}`); const innerOmo = nameDiv ? (nameDiv.getAttribute('onmouseover') || '') : '';
const name = nameDiv ? (nameDiv.textContent || '').trim() : 'no name';
console.log(` [${i}] ${name} | onmouseover: ${(innerOmo || omo).substring(0, 80)}`);
}); });
} else { } else {
console.log(`%c[HV] ❌ #eqsb NOT FOUND`, 'color:#f44'); console.log(`%c[HV] ❌ #eqsb NOT FOUND`, 'color:#f44');
@ -171,13 +173,13 @@ function scrapeCharacterEquip() {
const slots = document.querySelectorAll('#eqsb > .eqb'); const slots = document.querySelectorAll('#eqsb > .eqb');
slots.forEach(slot => { slots.forEach(slot => {
// Get item ID from onmouseover // onmouseover is on the inner name div, not the .eqb parent
const omo = slot.getAttribute('onmouseover') || slot.querySelector('[onmouseover]')?.getAttribute('onmouseover') || ''; const nameDiv = slot.querySelector(':scope > div[onmouseover]');
const omo = nameDiv ? (nameDiv.getAttribute('onmouseover') || '') : slot.getAttribute('onmouseover') || '';
const idMatch = omo.match(/equips\.set\((\d+)/); const idMatch = omo.match(/equips\.set\((\d+)/);
const itemId = idMatch ? idMatch[1] : ''; const itemId = idMatch ? idMatch[1] : '';
// Get item name from the child div (text node) // Name is the text content of the name div
const nameDiv = slot.querySelector(':scope > div:not([class])') || slot.querySelector('div');
const name = nameDiv ? (nameDiv.textContent || '').trim() : ''; const name = nameDiv ? (nameDiv.textContent || '').trim() : '';
// Check if slot is disabled // Check if slot is disabled
@ -314,7 +316,8 @@ function triggerAllTooltips() {
const results = []; const results = [];
slots.forEach(slot => { slots.forEach(slot => {
const omo = slot.getAttribute('onmouseover') || ''; const nameDiv = slot.querySelector(':scope > div[onmouseover]');
const omo = nameDiv ? (nameDiv.getAttribute('onmouseover') || '') : slot.getAttribute('onmouseover') || '';
const idMatch = omo.match(/equips\.set\((\d+)/); const idMatch = omo.match(/equips\.set\((\d+)/);
if (idMatch && typeof equips !== 'undefined' && equips.set) { if (idMatch && typeof equips !== 'undefined' && equips.set) {
// Trigger the tooltip // Trigger the tooltip

View file

@ -1,7 +1,7 @@
// ==UserScript== // ==UserScript==
// @name HV Unified // @name HV Unified
// @namespace hvunified // @namespace hvunified
// @version 0.14.10 // @version 0.14.11
// @description HV Unified — battle automation, guidance, and UI enhancements for HentaiVerse // @description HV Unified — battle automation, guidance, and UI enhancements for HentaiVerse
// @author GaboGG + Hermes // @author GaboGG + Hermes
// @match *://*.hentaiverse.org/* // @match *://*.hentaiverse.org/*