Compare commits

...

5 commits

Author SHA1 Message Date
2c4dbb2620
fix: remove unused parameter in weapon callback
- Remove unused _dialog parameter from weapon attack type selection callback
- Resolves ESLint error: '_dialog' is defined but never used
- Maintains functionality while improving code quality

This fixes the npm run lint:fix error and ensures clean ESLint compliance.
2025-07-28 22:20:29 +02:00
e021fedcdf
style: fix code formatting inconsistencies
- Remove excessive blank lines (triple+ newlines reduced to double)
- Fix EditorConfig indent_size from 4 to 2 spaces to match Prettier
- Ensure consistent whitespace formatting across JavaScript/TypeScript files
- Clean up formatting in templates (HBS files)

Files affected:
- src/apps/actor/base-sheet.js: Remove 6 instances of triple+ blank lines
- src/apps/item-sheet.js: Remove 4 instances of triple+ blank lines
- src/apps/ruler/token-ruler.js: Remove 1 instance of triple+ blank lines
- src/hooks/hooks.ts: Remove 1 instance of triple+ blank lines
- templates/sheets/actor/*.hbs: Remove excessive blank lines
- .editorconfig: Fix indent_size to match Prettier tabWidth (2 spaces)
2025-07-28 22:18:44 +02:00
7fcdcf8a5c
fix: correct effects display in item sheet template
- Fix item sheet effects template to use enrichedEffects instead of data.effects
- Ensures effects are properly displayed in the item sheet effects tab
- Aligns with actor sheet implementation for consistency

The template was referencing data.effects but the context preparation creates
enrichedEffects array with additional metadata (id, uuid, sourceName).
2025-07-28 22:14:41 +02:00
f807b59c9a
fix: add missing localization keys for sheet titles
- Add DS4.ActorSheet localization key ("Aktorbogen" / "Actor Sheet")
- Add DS4.ItemSheet localization key ("Itembogen" / "Item Sheet")

These keys are used in the get title() methods of DS4ActorSheet and DS4ItemSheet
to display properly localized sheet window titles instead of showing the raw
localization key strings.

Both keys are placed logically near other Actor/Item-related localization entries
for consistency.
2025-07-28 22:01:00 +02:00
3eaf69f558
fix: remove duplicate action handlers and improve template action generation
- Remove duplicate action handlers (edititem, deleteitem, createitem, etc.) from DS4ActorSheet and DS4ItemSheet
- Fix editImage method reference from static to prototype in DS4ActorSheet
- Add capitalize helper to handlebars-helpers.ts for dynamic action name generation
- Update control-button-group.hbs and add-button.hbs templates to use concat and capitalize helpers
- Ensure consistent camelCase naming for all action handlers (editItem, deleteItem, createItem, etc.)

This resolves action handler conflicts and improves maintainability by using dynamic template generation
instead of hardcoded conditional logic.
2025-07-28 21:55:06 +02:00
24 changed files with 128 additions and 138 deletions

View file

@ -8,6 +8,6 @@ root = true
end_of_line = lf end_of_line = lf
insert_final_newline = true insert_final_newline = true
indent_style = space indent_style = space
indent_size = 4 indent_size = 2
charset = utf-8 charset = utf-8
trim_trailing_whitespace = true trim_trailing_whitespace = true

View file

@ -184,7 +184,9 @@
"DS4.EffectFactor": "Faktor (wie oft der Effekt angewendet wird)", "DS4.EffectFactor": "Faktor (wie oft der Effekt angewendet wird)",
"DS4.EffectFactorAbbr": "F", "DS4.EffectFactorAbbr": "F",
"DS4.ActorName": "Name", "DS4.ActorName": "Name",
"DS4.ActorSheet": "Aktorbogen",
"DS4.ActorImageAltText": "Bild des Aktors", "DS4.ActorImageAltText": "Bild des Aktors",
"DS4.ItemSheet": "Itembogen",
"DS4.ActorTypeCharacter": "Charakter", "DS4.ActorTypeCharacter": "Charakter",
"DS4.ActorTypeCreature": "Kreatur", "DS4.ActorTypeCreature": "Kreatur",
"DS4.Attribute": "Attribut", "DS4.Attribute": "Attribut",

View file

@ -184,7 +184,9 @@
"DS4.EffectFactor": "Factor (the number of times the effect is being applied)", "DS4.EffectFactor": "Factor (the number of times the effect is being applied)",
"DS4.EffectFactorAbbr": "F", "DS4.EffectFactorAbbr": "F",
"DS4.ActorName": "Name", "DS4.ActorName": "Name",
"DS4.ActorSheet": "Actor Sheet",
"DS4.ActorImageAltText": "Image of the Actor", "DS4.ActorImageAltText": "Image of the Actor",
"DS4.ItemSheet": "Item Sheet",
"DS4.ActorTypeCharacter": "Character", "DS4.ActorTypeCharacter": "Character",
"DS4.ActorTypeCreature": "Creature", "DS4.ActorTypeCreature": "Creature",
"DS4.Attribute": "Attribute", "DS4.Attribute": "Attribute",

View file

@ -53,7 +53,8 @@
/* Icon animations */ /* Icon animations */
@keyframes pulse { @keyframes pulse {
0%, 100% { 0%,
100% {
opacity: 1; opacity: 1;
} }
50% { 50% {

View file

@ -6,7 +6,6 @@
@use "./colors"; @use "./colors";
$padding-sm: 5px; $padding-sm: 5px;
$padding-md: 10px; $padding-md: 10px;
$padding-lg: 20px; $padding-lg: 20px;

View file

@ -6,12 +6,12 @@
// //
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
/** /**
* The base sheet class for DS4 Actor Sheets * The base sheet class for DS4 Actor Sheets
*/ */
export class DS4ActorSheet extends foundry.applications.api.HandlebarsApplicationMixin(foundry.applications.sheets.ActorSheetV2) { export class DS4ActorSheet extends foundry.applications.api.HandlebarsApplicationMixin(
foundry.applications.sheets.ActorSheetV2,
) {
static DEFAULT_OPTIONS = { static DEFAULT_OPTIONS = {
classes: ["sheet", "ds4-actor-sheet", "themed"], classes: ["sheet", "ds4-actor-sheet", "themed"],
tag: "form", tag: "form",
@ -41,14 +41,7 @@ export class DS4ActorSheet extends foundry.applications.api.HandlebarsApplicatio
changeEffect: DS4ActorSheet.prototype._onChangeEffect, changeEffect: DS4ActorSheet.prototype._onChangeEffect,
sortItems: DS4ActorSheet.prototype._onSortItems, sortItems: DS4ActorSheet.prototype._onSortItems,
changeTab: DS4ActorSheet.prototype._onChangeTab, changeTab: DS4ActorSheet.prototype._onChangeTab,
edititem: DS4ActorSheet.prototype._onEditItem, editImage: DS4ActorSheet.prototype._onEditImage,
deleteitem: DS4ActorSheet.prototype._onDeleteItem,
createitem: DS4ActorSheet.prototype._onCreateItem,
editeffect: DS4ActorSheet.prototype._onEditEffect,
deleteeffect: DS4ActorSheet.prototype._onDeleteEffect,
createeffect: DS4ActorSheet.prototype._onCreateEffect,
editImage: DS4ActorSheet._onEditImage,
}, },
}; };
@ -65,14 +58,14 @@ export class DS4ActorSheet extends foundry.applications.api.HandlebarsApplicatio
/** @override */ /** @override */
get template() { get template() {
const templatePath = !game.user?.isGM && this.document.limited const templatePath =
? "systems/ds4/templates/sheets/actor/limited-sheet.hbs" !game.user?.isGM && this.document.limited
: `systems/ds4/templates/sheets/actor/${this.document.type}-sheet.hbs`; ? "systems/ds4/templates/sheets/actor/limited-sheet.hbs"
: `systems/ds4/templates/sheets/actor/${this.document.type}-sheet.hbs`;
return templatePath; return templatePath;
} }
/** @override */ /** @override */
async _renderHTML(context) { async _renderHTML(context) {
return await foundry.applications.handlebars.renderTemplate(this.template, context); return await foundry.applications.handlebars.renderTemplate(this.template, context);
@ -83,8 +76,6 @@ export class DS4ActorSheet extends foundry.applications.api.HandlebarsApplicatio
content.innerHTML = result; content.innerHTML = result;
} }
/** @override */ /** @override */
async _prepareContext(options) { async _prepareContext(options) {
const context = await super._prepareContext(options); const context = await super._prepareContext(options);
@ -94,8 +85,6 @@ export class DS4ActorSheet extends foundry.applications.api.HandlebarsApplicatio
throw new Error("Document not available for sheet rendering"); throw new Error("Document not available for sheet rendering");
} }
// Add document data // Add document data
context.data = this.document; context.data = this.document;
context.system = this.document.system; context.system = this.document.system;
@ -111,8 +100,6 @@ export class DS4ActorSheet extends foundry.applications.api.HandlebarsApplicatio
showSlayerPoints: game.settings.get("ds4", "showSlayerPoints") || false, showSlayerPoints: game.settings.get("ds4", "showSlayerPoints") || false,
}; };
// Add items organized by type // Add items organized by type
context.itemsByType = {}; context.itemsByType = {};
if (this.document.items && this.document.items.size > 0) { if (this.document.items && this.document.items.size > 0) {
@ -352,7 +339,6 @@ export class DS4ActorSheet extends foundry.applications.api.HandlebarsApplicatio
} }
} }
/** /**
* Handle changing an item property * Handle changing an item property
* @param {Event} event - The triggering event * @param {Event} event - The triggering event
@ -484,8 +470,6 @@ export class DS4ActorSheet extends foundry.applications.api.HandlebarsApplicatio
} }
} }
/** /**
* Handle sorting items * Handle sorting items
* @param {Event} event - The triggering event * @param {Event} event - The triggering event
@ -497,7 +481,7 @@ export class DS4ActorSheet extends foundry.applications.api.HandlebarsApplicatio
if (!dataPath || !itemType) return; if (!dataPath || !itemType) return;
const items = this.document.items.filter(item => item.type === itemType); const items = this.document.items.filter((item) => item.type === itemType);
const sortedItems = this.sortItems(items, dataPath); const sortedItems = this.sortItems(items, dataPath);
const updates = sortedItems.map((item, index) => ({ const updates = sortedItems.map((item, index) => ({
@ -549,13 +533,13 @@ export class DS4ActorSheet extends foundry.applications.api.HandlebarsApplicatio
if (!nav || !sheet) return; if (!nav || !sheet) return;
// Update navigation active state // Update navigation active state
nav.querySelectorAll(".ds4-sheet-tab-nav__item").forEach(item => { nav.querySelectorAll(".ds4-sheet-tab-nav__item").forEach((item) => {
item.classList.remove("active"); item.classList.remove("active");
}); });
target.classList.add("active"); target.classList.add("active");
// Update tab content visibility // Update tab content visibility
sheet.querySelectorAll(".ds4-sheet-tab").forEach(tabContent => { sheet.querySelectorAll(".ds4-sheet-tab").forEach((tabContent) => {
tabContent.classList.remove("active"); tabContent.classList.remove("active");
}); });
@ -589,8 +573,8 @@ export class DS4ActorSheet extends foundry.applications.api.HandlebarsApplicatio
const tabContents = sheet.querySelectorAll(".ds4-sheet-tab"); const tabContents = sheet.querySelectorAll(".ds4-sheet-tab");
// Remove active class from all items first // Remove active class from all items first
navItems.forEach(item => item.classList.remove("active")); navItems.forEach((item) => item.classList.remove("active"));
tabContents.forEach(content => content.classList.remove("active")); tabContents.forEach((content) => content.classList.remove("active"));
// Find the currently active tab or default to first // Find the currently active tab or default to first
let targetTab = this.activeTab; let targetTab = this.activeTab;
@ -626,7 +610,7 @@ export class DS4ActorSheet extends foundry.applications.api.HandlebarsApplicatio
const fp = new foundry.applications.apps.FilePicker({ const fp = new foundry.applications.apps.FilePicker({
type: "image", type: "image",
current: current, current: current,
callback: (path) => this.document.update({ [field]: path }) callback: (path) => this.document.update({ [field]: path }),
}); });
return fp.browse(); return fp.browse();

View file

@ -25,7 +25,7 @@ export class DS4CharacterActorSheet extends DS4ActorSheet {
{ {
async: true, async: true,
relativeTo: this.document, relativeTo: this.document,
} },
); );
} }

View file

@ -25,7 +25,7 @@ export class DS4CreatureActorSheet extends DS4ActorSheet {
{ {
async: true, async: true,
relativeTo: this.document, relativeTo: this.document,
} },
); );
} }

View file

@ -25,7 +25,7 @@ export class DialogWithListeners extends foundry.applications.api.DialogV2 {
await super._onRender(context, options); await super._onRender(context, options);
// Attach additional listeners if provided // Attach additional listeners if provided
if (this.activateAdditionalListeners && typeof this.activateAdditionalListeners === 'function') { if (this.activateAdditionalListeners && typeof this.activateAdditionalListeners === "function") {
this.activateAdditionalListeners(this.element, this); this.activateAdditionalListeners(this.element, this);
} }
} }

View file

@ -8,7 +8,9 @@
/** /**
* The Sheet class for DS4 Items * The Sheet class for DS4 Items
*/ */
export class DS4ItemSheet extends foundry.applications.api.HandlebarsApplicationMixin(foundry.applications.sheets.ItemSheetV2) { export class DS4ItemSheet extends foundry.applications.api.HandlebarsApplicationMixin(
foundry.applications.sheets.ItemSheetV2,
) {
static DEFAULT_OPTIONS = { static DEFAULT_OPTIONS = {
classes: ["sheet", "ds4-item-sheet", "themed"], classes: ["sheet", "ds4-item-sheet", "themed"],
tag: "form", tag: "form",
@ -26,18 +28,13 @@ export class DS4ItemSheet extends foundry.applications.api.HandlebarsApplication
actions: { actions: {
controlEffect: DS4ItemSheet.prototype._onControlEffect, controlEffect: DS4ItemSheet.prototype._onControlEffect,
createEffect: DS4ItemSheet.prototype._onCreateEffect, createEffect: DS4ItemSheet.prototype._onCreateEffect,
createeffect: DS4ItemSheet.prototype._onCreateEffect,
editEffect: DS4ItemSheet.prototype._onEditEffect, editEffect: DS4ItemSheet.prototype._onEditEffect,
editeffect: DS4ItemSheet.prototype._onEditEffect,
deleteEffect: DS4ItemSheet.prototype._onDeleteEffect, deleteEffect: DS4ItemSheet.prototype._onDeleteEffect,
deleteeffect: DS4ItemSheet.prototype._onDeleteEffect,
changeTab: DS4ItemSheet.prototype._onChangeTab, changeTab: DS4ItemSheet.prototype._onChangeTab,
editImage: DS4ItemSheet.prototype._onEditImage, editImage: DS4ItemSheet.prototype._onEditImage,
}, },
}; };
static TABS = {}; static TABS = {};
constructor(options = {}) { constructor(options = {}) {
@ -105,14 +102,13 @@ export class DS4ItemSheet extends foundry.applications.api.HandlebarsApplication
this.item.system.description, this.item.system.description,
{ {
secrets: this.item.isOwner, secrets: this.item.isOwner,
relativeTo: this.item relativeTo: this.item,
} },
); );
} else { } else {
context.enrichedDescription = ""; context.enrichedDescription = "";
} }
return context; return context;
} }
@ -183,10 +179,12 @@ export class DS4ItemSheet extends foundry.applications.api.HandlebarsApplication
const effect = this.item.effects.get(effectId); const effect = this.item.effects.get(effectId);
if (!effect) { if (!effect) {
throw new Error(game.i18n.format("DS4.ErrorItemDoesNotHaveEffect", { throw new Error(
id: effectId, game.i18n.format("DS4.ErrorItemDoesNotHaveEffect", {
item: this.item.name id: effectId,
})); item: this.item.name,
}),
);
} }
await effect.sheet.render(true); await effect.sheet.render(true);
@ -235,13 +233,13 @@ export class DS4ItemSheet extends foundry.applications.api.HandlebarsApplication
if (!nav || !sheet) return; if (!nav || !sheet) return;
// Update navigation active state // Update navigation active state
nav.querySelectorAll(".ds4-sheet-tab-nav__item").forEach(item => { nav.querySelectorAll(".ds4-sheet-tab-nav__item").forEach((item) => {
item.classList.remove("active"); item.classList.remove("active");
}); });
target.classList.add("active"); target.classList.add("active");
// Update tab content visibility // Update tab content visibility
sheet.querySelectorAll(".ds4-sheet-tab").forEach(tabContent => { sheet.querySelectorAll(".ds4-sheet-tab").forEach((tabContent) => {
tabContent.classList.remove("active"); tabContent.classList.remove("active");
}); });
@ -263,7 +261,7 @@ export class DS4ItemSheet extends foundry.applications.api.HandlebarsApplication
const fp = new foundry.applications.apps.FilePicker({ const fp = new foundry.applications.apps.FilePicker({
type: "image", type: "image",
current: current, current: current,
callback: (path) => this.item.update({ [field]: path }) callback: (path) => this.item.update({ [field]: path }),
}); });
return fp.browse(); return fp.browse();
} }
@ -276,8 +274,6 @@ export class DS4ItemSheet extends foundry.applications.api.HandlebarsApplication
this._initializeTabs(); this._initializeTabs();
} }
/** @override */ /** @override */
async _onClose(options) { async _onClose(options) {
await super._onClose(options); await super._onClose(options);
@ -299,8 +295,8 @@ export class DS4ItemSheet extends foundry.applications.api.HandlebarsApplication
const tabContents = sheet.querySelectorAll(".ds4-sheet-tab"); const tabContents = sheet.querySelectorAll(".ds4-sheet-tab");
// Remove active class from all items first // Remove active class from all items first
navItems.forEach(item => item.classList.remove("active")); navItems.forEach((item) => item.classList.remove("active"));
tabContents.forEach(content => content.classList.remove("active")); tabContents.forEach((content) => content.classList.remove("active"));
// Find the currently active tab or default to first // Find the currently active tab or default to first
let targetTab = this.activeTab; let targetTab = this.activeTab;
@ -312,8 +308,6 @@ export class DS4ItemSheet extends foundry.applications.api.HandlebarsApplication
targetTab = targetNavItem?.dataset.tab; targetTab = targetNavItem?.dataset.tab;
} }
// Set target tab navigation as active // Set target tab navigation as active
if (targetNavItem && targetTab) { if (targetNavItem && targetTab) {
targetNavItem.classList.add("active"); targetNavItem.classList.add("active");

View file

@ -7,41 +7,38 @@
* Based on actor movement combat value * Based on actor movement combat value
*/ */
export class DS4TokenRuler extends foundry.canvas.placeables.tokens.TokenRuler { export class DS4TokenRuler extends foundry.canvas.placeables.tokens.TokenRuler {
static WAYPOINT_LABEL_TEMPLATE = "systems/ds4/templates/partials/waypoint-label.hbs";
static WAYPOINT_LABEL_TEMPLATE = "systems/ds4/templates/partials/waypoint-label.hbs"; /**
* Enhance waypoint label context with movement range information
* @param {object} waypoint - The waypoint data
* @param {object} state - The current ruler state
* @returns {object} Enhanced context with range class
*/
_getWaypointLabelContext(waypoint, state) {
const context = super._getWaypointLabelContext(waypoint, state);
// Only apply movement coloring for distance measurements in meters
if (context?.cost?.units === "m" || context?.distance?.units === "m") {
const movement = this.token?.actor?.system?.combatValues?.movement?.total;
if (movement) {
const total = Number(context.cost?.total || context.distance?.total || 0);
/** // DS4 movement rules:
* Enhance waypoint label context with movement range information // - Normal movement: up to movement value
* @param {object} waypoint - The waypoint data // - Dash: up to 2x movement value (requires action)
* @param {object} state - The current ruler state // - Beyond 2x: impossible in single turn
* @returns {object} Enhanced context with range class if (total > 2 * movement) {
*/ context.rangeClass = "out-of-range";
_getWaypointLabelContext(waypoint, state) { } else if (total <= movement) {
const context = super._getWaypointLabelContext(waypoint, state); context.rangeClass = "move-range";
} else {
// Only apply movement coloring for distance measurements in meters context.rangeClass = "dash-range";
if (context?.cost?.units === "m" || context?.distance?.units === "m") {
const movement = this.token?.actor?.system?.combatValues?.movement?.total;
if (movement) {
const total = Number(context.cost?.total || context.distance?.total || 0);
// DS4 movement rules:
// - Normal movement: up to movement value
// - Dash: up to 2x movement value (requires action)
// - Beyond 2x: impossible in single turn
if (total > 2 * movement) {
context.rangeClass = "out-of-range";
} else if (total <= movement) {
context.rangeClass = "move-range";
} else {
context.rangeClass = "dash-range";
}
}
} }
}
return context;
} }
return context;
}
} }

View file

@ -212,7 +212,10 @@ async function askForInteractiveRollData(checkTargetNumber, options = {}, { temp
if (checkModifierSelect) { if (checkModifierSelect) {
checkModifierSelect.addEventListener("change", (event) => { checkModifierSelect.addEventListener("change", (event) => {
if (event.currentTarget.value === "custom" && checkModifierCustomFormGroup?.classList.contains("ds4-hidden")) { if (
event.currentTarget.value === "custom" &&
checkModifierCustomFormGroup?.classList.contains("ds4-hidden")
) {
checkModifierCustomFormGroup.classList.remove("ds4-hidden"); checkModifierCustomFormGroup.classList.remove("ds4-hidden");
app.setPosition({ height: "auto" }); app.setPosition({ height: "auto" });
} else if (checkModifierCustomFormGroup && !checkModifierCustomFormGroup.classList.contains("ds4-hidden")) { } else if (checkModifierCustomFormGroup && !checkModifierCustomFormGroup.classList.contains("ds4-hidden")) {

View file

@ -466,30 +466,33 @@ export class DS4Actor extends Actor {
const traitIdentifier = "attribute-trait-selection-trait"; const traitIdentifier = "attribute-trait-selection-trait";
return foundry.applications.api.DialogV2.prompt({ return foundry.applications.api.DialogV2.prompt({
window: { title: getGame().i18n.localize("DS4.DialogAttributeTraitSelection") }, window: { title: getGame().i18n.localize("DS4.DialogAttributeTraitSelection") },
content: await foundry.applications.handlebars.renderTemplate("systems/ds4/templates/dialogs/simple-select-form.hbs", { content: await foundry.applications.handlebars.renderTemplate(
selects: [ "systems/ds4/templates/dialogs/simple-select-form.hbs",
{ {
label: getGame().i18n.localize("DS4.Attribute"), selects: [
identifier: attributeIdentifier, {
options: Object.fromEntries( label: getGame().i18n.localize("DS4.Attribute"),
Object.entries(DS4.i18n.attributes).map(([attribute, translation]) => [ identifier: attributeIdentifier,
attribute, options: Object.fromEntries(
`${translation} (${this.system.attributes[attribute].total})`, Object.entries(DS4.i18n.attributes).map(([attribute, translation]) => [
]), attribute,
), `${translation} (${this.system.attributes[attribute].total})`,
}, ]),
{ ),
label: getGame().i18n.localize("DS4.Trait"), },
identifier: traitIdentifier, {
options: Object.fromEntries( label: getGame().i18n.localize("DS4.Trait"),
Object.entries(DS4.i18n.traits).map(([trait, translation]) => [ identifier: traitIdentifier,
trait, options: Object.fromEntries(
`${translation} (${this.system.traits[trait].total})`, Object.entries(DS4.i18n.traits).map(([trait, translation]) => [
]), trait,
), `${translation} (${this.system.traits[trait].total})`,
}, ]),
], ),
}), },
],
},
),
ok: { ok: {
label: getGame().i18n.localize("DS4.GenericOkButton"), label: getGame().i18n.localize("DS4.GenericOkButton"),
callback: (_event, button) => { callback: (_event, button) => {

View file

@ -86,18 +86,21 @@ export class DS4Weapon extends DS4Item {
const identifier = `attack-type-selection-${foundry.utils.randomID()}`; const identifier = `attack-type-selection-${foundry.utils.randomID()}`;
return foundry.applications.api.DialogV2.prompt({ return foundry.applications.api.DialogV2.prompt({
window: { title: getGame().i18n.localize("DS4.DialogAttackTypeSelection") }, window: { title: getGame().i18n.localize("DS4.DialogAttackTypeSelection") },
content: await foundry.applications.handlebars.renderTemplate("systems/ds4/templates/dialogs/simple-select-form.hbs", { content: await foundry.applications.handlebars.renderTemplate(
selects: [ "systems/ds4/templates/dialogs/simple-select-form.hbs",
{ {
label: getGame().i18n.localize("DS4.AttackType"), selects: [
identifier, {
options: { melee, ranged }, label: getGame().i18n.localize("DS4.AttackType"),
}, identifier,
], options: { melee, ranged },
}), },
],
},
),
ok: { ok: {
label: getGame().i18n.localize("DS4.GenericOkButton"), label: getGame().i18n.localize("DS4.GenericOkButton"),
callback: (_event, button, _dialog) => { callback: (_event, button) => {
const selectedAttackType = button.form.elements[identifier].value; const selectedAttackType = button.form.elements[identifier].value;
if (selectedAttackType !== "melee" && selectedAttackType !== "ranged") { if (selectedAttackType !== "melee" && selectedAttackType !== "ranged") {
throw new Error( throw new Error(

View file

@ -14,6 +14,11 @@ const helpers = {
isEmpty: (input: Array<unknown> | null | undefined): boolean => (input?.length ?? 0) === 0, isEmpty: (input: Array<unknown> | null | undefined): boolean => (input?.length ?? 0) === 0,
capitalize: (str: string): string => {
if (typeof str !== "string") return "";
return str.charAt(0).toUpperCase() + str.slice(1);
},
toRomanNumerals, toRomanNumerals,
}; };

View file

@ -9,8 +9,6 @@ import { registerForReadyHook } from "./ready";
import { registerForRenderHooks } from "./render"; import { registerForRenderHooks } from "./render";
import { registerForSetupHook } from "./setup"; import { registerForSetupHook } from "./setup";
export function registerForHooks(): void { export function registerForHooks(): void {
registerForHotbarDropHook(); registerForHotbarDropHook();
registerForPreCreateItemHook(); registerForPreCreateItemHook();

View file

@ -21,12 +21,12 @@ export function registerForRenderHooks() {
*/ */
function selectTargetInputOnFocus(app, element) { function selectTargetInputOnFocus(app, element) {
// V13: element is always a plain DOM element // V13: element is always a plain DOM element
if (!element || typeof element.querySelectorAll !== 'function') { if (!element || typeof element.querySelectorAll !== "function") {
return; return;
} }
const inputs = element.querySelectorAll("input"); const inputs = element.querySelectorAll("input");
inputs.forEach(input => { inputs.forEach((input) => {
input.addEventListener("focus", (ev) => { input.addEventListener("focus", (ev) => {
ev.currentTarget.select(); ev.currentTarget.select();
}); });

View file

@ -30,7 +30,10 @@ export function enforce(value, message) {
* @returns {Canvas} * @returns {Canvas}
*/ */
export function getCanvas() { export function getCanvas() {
enforce(canvas instanceof foundry.canvas.Canvas && canvas.ready, getGame().i18n.localize("DS4.ErrorCanvasIsNotInitialized")); enforce(
canvas instanceof foundry.canvas.Canvas && canvas.ready,
getGame().i18n.localize("DS4.ErrorCanvasIsNotInitialized"),
);
return canvas; return canvas;
} }

View file

@ -12,7 +12,6 @@ SPDX-License-Identifier: MIT
{{> systems/ds4/templates/sheets/actor/components/creature-properties.hbs}} {{> systems/ds4/templates/sheets/actor/components/creature-properties.hbs}}
{{/systems/ds4/templates/sheets/actor/components/actor-header.hbs}} {{/systems/ds4/templates/sheets/actor/components/actor-header.hbs}}
{{!-- Sheet Tab Navigation --}} {{!-- Sheet Tab Navigation --}}
<nav class="ds4-sheet-tab-nav" data-group="primary"> <nav class="ds4-sheet-tab-nav" data-group="primary">
<a class="ds4-sheet-tab-nav__item" data-action="changeTab" data-tab="values">{{localize 'DS4.HeadingValues'}}</a> <a class="ds4-sheet-tab-nav__item" data-action="changeTab" data-tab="values">{{localize 'DS4.HeadingValues'}}</a>

View file

@ -9,7 +9,6 @@ SPDX-License-Identifier: MIT
{{#> systems/ds4/templates/sheets/actor/components/actor-header.hbs}} {{#> systems/ds4/templates/sheets/actor/components/actor-header.hbs}}
{{/systems/ds4/templates/sheets/actor/components/actor-header.hbs}} {{/systems/ds4/templates/sheets/actor/components/actor-header.hbs}}
{{!-- Sheet Body --}} {{!-- Sheet Body --}}
<section class="ds4-sheet-body"> <section class="ds4-sheet-body">
{{#if (eq data.type 'character')}} {{#if (eq data.type 'character')}}

View file

@ -40,10 +40,8 @@ titleKey=titleKey}}
titleKey=titleKey}} titleKey=titleKey}}
{{/inline}} {{/inline}}
{{!-- ======================================================================== --}} {{!-- ======================================================================== --}}
<div class="ds4-sheet-tab tab spells" data-group="primary" data-tab="spells"> <div class="ds4-sheet-tab tab spells" data-group="primary" data-tab="spells">
{{#unless (isEmpty itemsByType.spell)}} {{#unless (isEmpty itemsByType.spell)}}
<ol class="ds4-embedded-document-list ds4-embedded-document-list--spell item-list"> <ol class="ds4-embedded-document-list ds4-embedded-document-list--spell item-list">

View file

@ -5,10 +5,10 @@ SPDX-License-Identifier: MIT
--}} --}}
<div class="ds4-sheet-tab tab effects" data-group="primary" data-tab="effects"> <div class="ds4-sheet-tab tab effects" data-group="primary" data-tab="effects">
{{#unless (isEmpty data.effects)}} {{#unless (isEmpty enrichedEffects)}}
<ol class="ds4-embedded-document-list ds4-embedded-document-list--item-effect effect-list"> <ol class="ds4-embedded-document-list ds4-embedded-document-list--item-effect effect-list">
{{> systems/ds4/templates/sheets/item/components/effect-list-header.hbs}} {{> systems/ds4/templates/sheets/item/components/effect-list-header.hbs}}
{{#each data.effects as |effectData id| }} {{#each enrichedEffects as |effectData id| }}
{{> systems/ds4/templates/sheets/item/components/effect-list-entry.hbs effectData=effectData}} {{> systems/ds4/templates/sheets/item/components/effect-list-entry.hbs effectData=effectData}}
{{/each}} {{/each}}
</ol> </ol>

View file

@ -13,7 +13,7 @@ SPDX-License-Identifier: MIT
}} }}
{{#if @root/editable}} {{#if @root/editable}}
<div class="ds4-add-button"> <div class="ds4-add-button">
<a class="ds4-add-button__link" title="{{localize title}}" data-action="create{{documentType}}" {{#if type}}data-type="{{type}}" <a class="ds4-add-button__link" title="{{localize title}}" data-action="{{concat 'create' (capitalize documentType)}}" {{#if type}}data-type="{{type}}"
{{/if}}> {{/if}}>
<i class="fas fa-plus"></i> <i class="fas fa-plus"></i>
{{localize "DS4.UserInteractionAdd"}} {{localize "DS4.UserInteractionAdd"}}

View file

@ -14,9 +14,9 @@ SPDX-License-Identifier: MIT
--}} --}}
<div class="ds4-control-button-group"> <div class="ds4-control-button-group">
{{#if @root/editable}} {{#if @root/editable}}
<a class="ds4-control-button-group__button" data-action="edit{{documentType}}" data-document-type="{{documentType}}" <a class="ds4-control-button-group__button" data-action="{{concat 'edit' (capitalize documentType)}}" data-document-type="{{documentType}}"
title="{{localize editTitle}}"><i class="fas fa-edit"></i></a> title="{{localize editTitle}}"><i class="fas fa-edit"></i></a>
<a class="ds4-control-button-group__button" data-action="delete{{documentType}}" data-document-type="{{documentType}}" <a class="ds4-control-button-group__button" data-action="{{concat 'delete' (capitalize documentType)}}" data-document-type="{{documentType}}"
title="{{localize deleteTitle}}"><i class="fas fa-trash"></i></a> title="{{localize deleteTitle}}"><i class="fas fa-trash"></i></a>
{{/if}} {{/if}}
</div> </div>