From b900c25901074e34d5302ee0a142494f84440b30 Mon Sep 17 00:00:00 2001 From: Anderson Lima Date: Sat, 11 Nov 2023 22:35:14 -0300 Subject: [PATCH] add EquipmentSheet class --- src/common/helpers.js | 4 + src/features/character-sheet.js | 18 ++-- src/features/equipments.js | 155 +++++++++++++++++--------------- 3 files changed, 99 insertions(+), 78 deletions(-) diff --git a/src/common/helpers.js b/src/common/helpers.js index 6c7bc76..547811e 100644 --- a/src/common/helpers.js +++ b/src/common/helpers.js @@ -227,6 +227,10 @@ export function enhanceElement(el) { const toArray = (param) => (param instanceof Array ? param : [param]); el.getElement = (selectors) => selectors ? pathQuerySelector({ root: el, path: toArray(selectors) }) : el; + el.getAllElements = (selectors) => + Array.from(el.querySelectorAll(selectors)).map((node) => + enhanceElement(node), + ); el.select = (strings, ...values) => el.getElement( strings.reduce((acc, s, index) => acc + s + (values[index] || ''), ''), diff --git a/src/features/character-sheet.js b/src/features/character-sheet.js index f46269c..747ef51 100644 --- a/src/features/character-sheet.js +++ b/src/features/character-sheet.js @@ -1,7 +1,7 @@ 'use strict'; import { createElement, enhanceElement, hasCSS } from '../common/helpers'; -import { loadEquipmentEnhancement } from './equipments'; +import { EquipmentSheet } from './equipments'; import { PowerSheet } from './powers'; import { loadRacesEnhancement } from './races'; import { SpellSheet } from './spells'; @@ -98,6 +98,12 @@ export class CharacterSheet { abilitiesAndPowers: this.db.abilities_and_powers, character: this.character, }); + /** @type {EquipmentSheet} */ + this.equipmentSheet = new EquipmentSheet({ + iframe: this.iframe, + equipments: this.db.equipments, + character: this.character, + }); /** * @type {EnhancedHTMLElement|null} * @private @@ -197,12 +203,14 @@ export class CharacterSheet { } this.spellSheet.load(); this.powerSheet.load(); - this.loadEquipment(); + this.equipmentSheet.load(); this.loadRaces(); // Observers this.observe(this.spellsContainer, () => this.spellSheet.load()); this.observe(this.powersContainer, () => this.powerSheet.load()); - this.observe(this.equipmentsContainer, () => this.loadEquipment()); + this.observe(this.equipmentsContainer, () => + this.equipmentSheet.load(), + ); observer.disconnect(); } }); @@ -300,10 +308,6 @@ export class CharacterSheet { this.characterData = newCharacterData; } - loadEquipment() { - loadEquipmentEnhancement({ iframe: this.iframe, data: this.db }); - } - loadRaces() { loadRacesEnhancement({ iframe: this.iframe, diff --git a/src/features/equipments.js b/src/features/equipments.js index c8ebc2b..f28c952 100644 --- a/src/features/equipments.js +++ b/src/features/equipments.js @@ -1,83 +1,96 @@ 'use strict'; -import { - addEventObserver, - createElement, - pathQuerySelector, -} from '../common/helpers'; +import { createElement } from '../common/helpers'; /** - * Add the equipment autocomplete. + * Create a new Equipment Sheet object. * - * @param {object} props - * @param {HTMLElement} props.equipmentsContainer - The equipments container in the right side. - * @param {Equipment[]} props.equipments - All available equipments. + * @class */ -function loadEquipmentAutoComplete({ equipmentsContainer, equipments }) { - if (!equipmentsContainer.querySelector('#equipment-list')) { - equipmentsContainer.append( - createElement('datalist', { - id: 'equipment-list', - append: equipments.map((equipment) => - createElement('option', { value: equipment.name }), - ), - }), +export class EquipmentSheet { + /** + * @constructs + * @param {Object} props + * @param {EnhancedHTMLElement} props.iframe + * @param {EquipmentData[]} props.equipments + * @param {Object} props.character + */ + constructor({ iframe, equipments, character }) { + /** @type {EnhancedHTMLElement} */ + this.iframe = iframe; + /** @type {EquipmentData[]} */ + this.equipments = equipments; + /** @type {Equipment[]} */ + this.equipmentsList = equipments.reduce( + (acc, folder) => [...acc, ...folder.items], + [], ); + /** @type {Object} */ + this.character = character; + /** + * @type {EnhancedHTMLElement|null} + * @private + */ + this._equipmentsContainer = null; + } + + /** @type {EnhancedHTMLElement|null} */ + get equipmentsContainer() { + if (this._equipmentsContainer === null) { + const path = [ + 'div.sheet-right-container', + 'div.sheet-equipment-container', + 'div[data-groupname="repeating_equipment"]', + ]; + this._equipmentsContainer = this.iframe.getElement(path); + } + return this._equipmentsContainer; } - for (const input of equipmentsContainer.querySelectorAll( - 'input[name="attr_equipname"]:not([list="equipment-list"])', - )) { - input.setAttribute('list', 'equipment-list'); - input.autocomplete = 'off'; - const updateSpacesValue = () => { - const equipment = equipments.find( - (equipment) => equipment.name === input.value, + + /** Load the sheet equipment improvements. */ + load() { + this.loadAutoComplete(); + } + + /** Load the sheet equipment auto complete. */ + loadAutoComplete() { + if (!this.equipmentsContainer.querySelector('#equipment-list')) { + this.equipmentsContainer.append( + createElement('datalist', { + id: 'equipment-list', + append: this.equipmentsList.map((equipment) => + createElement('option', { value: equipment.name }), + ), + }), ); - if (equipment) { - const value = - parseFloat(equipment.spaces.replace(',', '.').trim()) || 0; - const spacesInput = input.parentNode.querySelector( - 'input[name="attr_equipweight"],input[name="attr_equipslot"]', + } + const selector = + 'input[name="attr_equipname"]:not([list="equipment-list"])'; + for (const input of this.equipmentsContainer.getAllElements(selector)) { + input.setAttribute('list', 'equipment-list'); + input.autocomplete = 'off'; + const repRow = input.parentNode.parentNode; + const id = repRow.getAttribute('data-reprowid'); + const updateSpacesValue = () => { + const equipment = this.equipmentsList.find( + (equipment) => equipment.name === input.value, ); - spacesInput.focus(); - spacesInput.value = value; - input.focus(); - } - }; - addEventObserver({ - el: input, - eventName: 'input', - eventHandler: updateSpacesValue, - }); - addEventObserver({ - el: input, - eventName: 'change', - eventHandler: updateSpacesValue, - }); + if (equipment) { + const prefix = `repeating_equipment_${id}`; + const rawValue = equipment.spaces.replace(',', '.').trim(); + const value = parseFloat(rawValue) || 0; + const spacesInput = input.parentNode.querySelector( + 'input[name="attr_equipweight"],input[name="attr_equipslot"]', + ); + const attrName = spacesInput.getAttribute('name').split('_')[1]; + this.character.updateAttributes(prefix, { + equipname: equipment.name, + [attrName]: value, + }); + } + }; + input.addEventObserver('input', updateSpacesValue); + input.addEventObserver('change', updateSpacesValue); + } } } - -/** - * Load the equipment related enhancements. - * - * @param {object} props - * @param {HTMLDocument} props.iframe - The character sheet iframe document. - * @param {T20Data} props.data - The Tormenta20 data. - */ -export function loadEquipmentEnhancement({ iframe, data }) { - const equipmentsContainer = pathQuerySelector({ - root: iframe, - path: [ - 'div.sheet-right-container', - 'div.sheet-equipment-container', - 'div[data-groupname="repeating_equipment"]', - ], - }); - loadEquipmentAutoComplete({ - equipmentsContainer, - equipments: data.equipments.reduce( - (acc, folder) => [...acc, ...folder.items], - [], - ), - }); -}