Skip to content

Commit

Permalink
add EquipmentSheet class
Browse files Browse the repository at this point in the history
  • Loading branch information
pyanderson committed Nov 12, 2023
1 parent 5f1f692 commit b900c25
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 78 deletions.
4 changes: 4 additions & 0 deletions src/common/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -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] || ''), ''),
Expand Down
18 changes: 11 additions & 7 deletions src/features/character-sheet.js
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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();
}
});
Expand Down Expand Up @@ -300,10 +308,6 @@ export class CharacterSheet {
this.characterData = newCharacterData;
}

loadEquipment() {
loadEquipmentEnhancement({ iframe: this.iframe, data: this.db });
}

loadRaces() {
loadRacesEnhancement({
iframe: this.iframe,
Expand Down
155 changes: 84 additions & 71 deletions src/features/equipments.js
Original file line number Diff line number Diff line change
@@ -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],
[],
),
});
}

0 comments on commit b900c25

Please sign in to comment.