feat!: port DS4 actor sheets to ApplicationV2

Convert DS4ActorSheet, DS4CharacterActorSheet, and DS4CreatureActorSheet
from ApplicationV1 to ApplicationV2 architecture. Update all templates
to use data-action attributes. Implement manual tab system and preserve
all existing functionality including item management, effects, and
rolling system.

BREAKING CHANGE: Requires FoundryVTT ApplicationV2 system
This commit is contained in:
Alexander Minges 2025-07-12 20:44:03 +02:00
parent 2a797ed8ed
commit cd44db079f
Signed by: Athemis
GPG key ID: 31FBDEF92DDB162B
15 changed files with 626 additions and 508 deletions

File diff suppressed because it is too large Load diff

View file

@ -2,27 +2,32 @@
//
// SPDX-License-Identifier: MIT
import { DS4ActorSheet } from "./base-sheet";
import { DS4ActorSheet } from "./base-sheet.js";
/**
* The Sheet class for DS4 Character Actors
*/
export class DS4CharacterActorSheet extends DS4ActorSheet {
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
classes: ["sheet", "ds4-actor-sheet", "ds4-character-sheet"],
});
}
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
classes: ["sheet", "ds4-actor-sheet", "ds4-character-sheet"],
};
/** @override */
async getData(options = {}) {
const context = await super.getData(options);
context.data.system.profile.biography = await foundry.applications.ux.TextEditor.implementation.enrichHTML(
context.data.system.profile.biography,
{
async: true,
},
);
async _prepareContext(options) {
const context = await super._prepareContext(options);
// Enrich biography HTML content
if (context.data.system.profile.biography) {
context.data.system.profile.biography = await TextEditor.enrichHTML(
context.data.system.profile.biography,
{
async: true,
relativeTo: this.document,
}
);
}
return context;
}
}

View file

@ -2,27 +2,32 @@
//
// SPDX-License-Identifier: MIT
import { DS4ActorSheet } from "./base-sheet";
import { DS4ActorSheet } from "./base-sheet.js";
/**
* The Sheet class for DS4 Creature Actors
*/
export class DS4CreatureActorSheet extends DS4ActorSheet {
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
classes: ["sheet", "ds4-actor-sheet", "ds4-creature-sheet"],
});
}
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
classes: ["sheet", "ds4-actor-sheet", "ds4-creature-sheet"],
};
/** @override */
async getData(options = {}) {
const context = await super.getData(options);
context.data.system.baseInfo.description = await foundry.applications.ux.TextEditor.implementation.enrichHTML(
context.data.system.baseInfo.description,
{
async: true,
},
);
async _prepareContext(options) {
const context = await super._prepareContext(options);
// Enrich description HTML content
if (context.data.system.baseInfo.description) {
context.data.system.baseInfo.description = await TextEditor.enrichHTML(
context.data.system.baseInfo.description,
{
async: true,
relativeTo: this.document,
}
);
}
return context;
}
}

View file

@ -14,12 +14,12 @@ SPDX-License-Identifier: MIT
{{!-- Sheet Tab Navigation --}}
<nav class="ds4-sheet-tab-nav tabs" data-group="primary">
<a class="ds4-sheet-tab-nav__item" data-tab="values">{{localize 'DS4.HeadingValues'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="inventory">{{localize 'DS4.HeadingInventory'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="spells">{{localize 'DS4.HeadingSpells'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="abilities">{{localize 'DS4.HeadingAbilities'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="effects">{{localize 'DS4.HeadingEffects'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="biography">{{localize 'DS4.HeadingBiography'}}</a>
<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="inventory">{{localize 'DS4.HeadingInventory'}}</a>
<a class="ds4-sheet-tab-nav__item" data-action="changeTab" data-tab="spells">{{localize 'DS4.HeadingSpells'}}</a>
<a class="ds4-sheet-tab-nav__item" data-action="changeTab" data-tab="abilities">{{localize 'DS4.HeadingAbilities'}}</a>
<a class="ds4-sheet-tab-nav__item" data-action="changeTab" data-tab="effects">{{localize 'DS4.HeadingEffects'}}</a>
<a class="ds4-sheet-tab-nav__item" data-action="changeTab" data-tab="biography">{{localize 'DS4.HeadingBiography'}}</a>
</nav>
<!-- beautify ignore:start -->

View file

@ -12,7 +12,7 @@ SPDX-License-Identifier: MIT
!-- @param check-label: The label for the check
--}}
<button class="ds4-check rollable-check" data-check="{{check-key}}"
<button class="ds4-check" data-action="rollCheck" data-check="{{check-key}}"
title="{{localize 'DS4.CheckTooltip' check=check-label}}">
<span>{{check-label}}</span>
<span>{{check-target-number}}</span>

View file

@ -11,9 +11,9 @@ SPDX-License-Identifier: MIT
--}}
<li class="ds4-embedded-document-list__row effect" data-effect-uuid="{{effectData.uuid}}" data-effect-id="{{effectData.id}}">
{{!-- enabled --}}
<input class="ds4-embedded-document-list__editable ds4-embedded-document-list__editable--checkbox change-effect"
<input class="ds4-embedded-document-list__editable ds4-embedded-document-list__editable--checkbox"
type="checkbox" {{checked (ne effectData.disabled true)}} data-dtype="Boolean" data-property="disabled"
data-inverted="true" title="{{localize 'DS4.EffectEnabled'}}">
data-inverted="true" data-action="changeEffect" title="{{localize 'DS4.EffectEnabled'}}">
{{!-- active --}}
{{#if effectData.active}}<i class="fas fa-check"></i>{{else}}<i class="fas fa-ban"></i>{{/if}}

View file

@ -18,27 +18,27 @@ SPDX-License-Identifier: MIT
<li class="ds4-embedded-document-list__row item" data-item-uuid="{{item.uuid}}" data-item-id="{{item.id}}">
{{!-- equipped --}}
{{#if isEquipable}}
<input class="ds4-embedded-document-list__editable ds4-embedded-document-list__editable--checkbox change-item"
<input class="ds4-embedded-document-list__editable ds4-embedded-document-list__editable--checkbox"
type="checkbox" {{checked item.system.equipped}} data-dtype="Boolean" data-property="system.equipped"
title="{{localize 'DS4.ItemEquipped'}}">
data-action="changeItem" title="{{localize 'DS4.ItemEquipped'}}">
{{/if}}
{{!-- image --}}
{{> systems/ds4/templates/sheets/shared/components/rollable-image.hbs rollable=(and item.system.rollable
@root/editable)
src=item.img alt=(localize "DS4.DocumentImageAltText" name=item.name) title=item.name
rollableTitle=(localize "DS4.RollableImageRollableTitle" name=item.name) rollableClass="rollable-item"}}
rollableTitle=(localize "DS4.RollableImageRollableTitle" name=item.name) rollableAction="rollItem"}}
{{!-- amount --}}
{{#if hasQuantity}}
<input class="ds4-embedded-document-list__editable change-item" type="number" min="0" step="1"
<input class="ds4-embedded-document-list__editable" type="number" min="0" step="1"
value="{{item.system.quantity}}" data-dtype="Number" data-property="system.quantity"
title="{{localize 'DS4.Quantity'}}" />
data-action="changeItem" title="{{localize 'DS4.Quantity'}}" />
{{/if}}
{{!-- name --}}
<input class="ds4-embedded-document-list__editable change-item" type="text" value="{{item.name}}"
data-dtype="String" data-property="name" title="{{htmlToPlainText item.system.description}}" />
<input class="ds4-embedded-document-list__editable" type="text" value="{{item.name}}"
data-dtype="String" data-property="name" data-action="changeItem" title="{{htmlToPlainText item.system.description}}" />
{{!-- item type specifics --}}
{{#if @partial-block }}

View file

@ -18,7 +18,7 @@ SPDX-License-Identifier: MIT
<li class="ds4-embedded-document-list__row ds4-embedded-document-list__row--header" data-type={{type}}>
{{!-- equipped --}}
{{#if isEquipable}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.equipped"
<div class="ds4-embedded-document-list__clickable" data-action="sortItems" data-data-path="system.equipped"
title="{{localize 'DS4.SortByItemEquipped'}}">
{{localize 'DS4.ItemEquippedAbbr'}}</div>
{{/if}}
@ -28,12 +28,12 @@ SPDX-License-Identifier: MIT
{{!-- amount --}}
{{#if hasQuantity}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.quantity"
<div class="ds4-embedded-document-list__clickable" data-action="sortItems" data-data-path="system.quantity"
title="{{localize 'DS4.SortByQuantity'}}">#</div>
{{/if}}
{{!-- name --}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="name"
<div class="ds4-embedded-document-list__clickable" data-action="sortItems" data-data-path="name"
title="{{localize 'DS4.SortByItemName'}}">{{localize 'DS4.ItemName'}}
</div>
@ -44,7 +44,7 @@ SPDX-License-Identifier: MIT
{{!-- description --}}
{{#unless hideDescription}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.description"
<div class="ds4-embedded-document-list__clickable" data-action="sortItems" data-data-path="system.description"
title="{{localize 'DS4.SortByDescription'}}">{{localize
'DS4.Description'}}</div>
{{/unless}}

View file

@ -13,19 +13,19 @@ SPDX-License-Identifier: MIT
{{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs isEquipable=true hasQuantity=true
type='weapon'}}
{{!-- attack type --}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.attackType"
<div class="ds4-embedded-document-list__clickable" data-action="sortItems" data-data-path="system.attackType"
title="{{localize 'DS4.SortByAttackType'}}">
{{localize
'DS4.AttackTypeAbbr'}}</div>
{{!-- weapon bonus --}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.weaponBonus"
<div class="ds4-embedded-document-list__clickable" data-action="sortItems" data-data-path="system.weaponBonus"
title="{{localize 'DS4.SortByWeaponBonus'}}">
{{localize 'DS4.WeaponBonusAbbr'}}
</div>
{{!-- opponent defense --}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.opponentDefense"
<div class="ds4-embedded-document-list__clickable" data-action="sortItems" data-data-path="system.opponentDefense"
title="{{localize 'DS4.SortByOpponentDefense'}}">
{{localize 'DS4.OpponentDefenseAbbr'}}
</div>
@ -70,15 +70,15 @@ documentType='item' type='weapon'}}
{{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs isEquipable=true hasQuantity=true
type="armor"}}
{{!-- armor material type --}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.armorMaterialType"
<div class="ds4-embedded-document-list__clickable" data-action="sortItems" data-data-path="system.armorMaterialType"
title="{{localize 'DS4.SortByArmorMaterialType'}}">{{localize 'DS4.ArmorMaterialTypeAbbr'}}</div>
{{!-- armor type --}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.armorType"
<div class="ds4-embedded-document-list__clickable" data-action="sortItems" data-data-path="system.armorType"
title="{{localize 'DS4.SortByArmorType'}}">{{localize 'DS4.ArmorTypeAbbr'}}</div>
{{!-- armor value --}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.armorValue"
<div class="ds4-embedded-document-list__clickable" data-action="sortItems" data-data-path="system.armorValue"
title="{{localize 'DS4.SortByArmorValue'}}">
{{localize 'DS4.ArmorValueAbbr'}}
</div>
@ -113,7 +113,7 @@ documentType='item' type='armor'}}
{{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs isEquipable=true hasQuantity=true
type='shield'}}
{{!-- armor value --}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.armorValue"
<div class="ds4-embedded-document-list__clickable" data-action="sortItems" data-data-path="system.armorValue"
title="{{localize 'DS4.SortByArmorValue'}}">
{{localize 'DS4.ArmorValueAbbr'}}
</div>
@ -137,15 +137,15 @@ documentType='item' type='shield'}}
{{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs isEquipable=true hasQuantity=true
type='equipment'}}
{{!-- storage location --}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.storageLocation"
<div class="ds4-embedded-document-list__clickable" data-action="sortItems" data-data-path="system.storageLocation"
title="{{localize 'DS4.SortByStorageLocation'}}">{{localize 'DS4.StorageLocation'}}</div>
{{/systems/ds4/templates/sheets/actor/components/item-list-header.hbs}}
{{#each itemsByType.equipment as |item id|}}
{{#> systems/ds4/templates/sheets/actor/components/item-list-entry.hbs item=item isEquipable=true
hasQuantity=true}}
{{!-- storage location --}}
<input class="ds4-embedded-document-list__editable change-item" type="text" value="{{item.system.storageLocation}}"
data-dtype="String" data-property="system.storageLocation" title="{{localize 'DS4.StorageLocation'}}">
<input class="ds4-embedded-document-list__editable" type="text" value="{{item.system.storageLocation}}"
data-dtype="String" data-property="system.storageLocation" data-action="changeItem" title="{{localize 'DS4.StorageLocation'}}">
{{/systems/ds4/templates/sheets/actor/components/item-list-entry.hbs}}
{{/each}}
</ol>
@ -159,14 +159,14 @@ documentType='item' type='equipment'}}
<ol class="ds4-embedded-document-list ds4-embedded-document-list--loot item-list">
{{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs hasQuantity=true type='loot'}}
{{!-- storage location --}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.storageLocation"
<div class="ds4-embedded-document-list__clickable" data-action="sortItems" data-data-path="system.storageLocation"
title="{{localize 'DS4.SortByStorageLocation'}}">{{localize 'DS4.StorageLocation'}}</div>
{{/systems/ds4/templates/sheets/actor/components/item-list-header.hbs}}
{{#each itemsByType.loot as |item id|}}
{{#> systems/ds4/templates/sheets/actor/components/item-list-entry.hbs item=item hasQuantity=true}}
{{!-- storage location --}}
<input class="ds4-embedded-document-list__editable change-item" type="text" value="{{item.system.storageLocation}}"
data-dtype="String" data-property="system.storageLocation" title="{{localize 'DS4.StorageLocation'}}">
<input class="ds4-embedded-document-list__editable" type="text" value="{{item.system.storageLocation}}"
data-dtype="String" data-property="system.storageLocation" data-action="changeItem" title="{{localize 'DS4.StorageLocation'}}">
{{/systems/ds4/templates/sheets/actor/components/item-list-entry.hbs}}
{{/each}}
</ol>

View file

@ -15,12 +15,12 @@ SPDX-License-Identifier: MIT
{{!-- Sheet Tab Navigation --}}
<nav class="ds4-sheet-tab-nav" data-group="primary">
<a class="ds4-sheet-tab-nav__item" data-tab="values">{{localize 'DS4.HeadingValues'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="inventory">{{localize 'DS4.HeadingInventory'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="spells">{{localize 'DS4.HeadingSpells'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="abilities">{{localize 'DS4.HeadingAbilities'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="effects">{{localize 'DS4.HeadingEffects'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="description">{{localize 'DS4.HeadingDescription'}}</a>
<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="inventory">{{localize 'DS4.HeadingInventory'}}</a>
<a class="ds4-sheet-tab-nav__item" data-action="changeTab" data-tab="spells">{{localize 'DS4.HeadingSpells'}}</a>
<a class="ds4-sheet-tab-nav__item" data-action="changeTab" data-tab="abilities">{{localize 'DS4.HeadingAbilities'}}</a>
<a class="ds4-sheet-tab-nav__item" data-action="changeTab" data-tab="effects">{{localize 'DS4.HeadingEffects'}}</a>
<a class="ds4-sheet-tab-nav__item" data-action="changeTab" data-tab="description">{{localize 'DS4.HeadingDescription'}}</a>
</nav>
{{!-- Sheet Body --}}

View file

@ -12,7 +12,7 @@ SPDX-License-Identifier: MIT
<ol class="ds4-embedded-document-list ds4-embedded-document-list--talent item-list">
{{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs type='talent'}}
{{!-- rank --}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.rank.total"
<div class="ds4-embedded-document-list__clickable" data-action="sortItems" data-data-path="system.rank.total"
title="{{localize 'DS4.SortByTalentRank'}}">{{localize 'DS4.TalentRank'}}</div>
{{/systems/ds4/templates/sheets/actor/components/item-list-header.hbs}}
{{#each itemsByType.talent as |item id|}}

View file

@ -50,11 +50,11 @@ titleKey=titleKey}}
{{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs isEquipable=true hideDescription=true
type='spell'}}
{{!-- spell type --}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.spellType"
<div class="ds4-embedded-document-list__clickable" data-action="sortItems" data-data-path="system.spellType"
title="{{localize 'DS4.SortBySpellType'}}">{{localize 'DS4.SpellTypeAbbr'}}</div>
{{!-- spell modifier --}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.spellModifier.complex"
<div class="ds4-embedded-document-list__clickable" data-action="sortItems" data-data-path="system.spellModifier.complex"
data-data-path2="system.spellModifier.numerical" title="{{localize 'DS4.SortBySpellModifier'}}">{{localize
'DS4.SpellModifierAbbr'}}</div>

View file

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

View file

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

View file

@ -7,13 +7,14 @@ SPDX-License-Identifier: MIT
{{!--
!-- Render an image that has a dice overlay image.
!-- @param rollable: A flag indicating whether or not the image is actually rollable.
!-- @param rollableClass: The CSS class(es) to add if the image is rollable.
!-- @param rollableAction: The action to trigger when the image is clicked (e.g. "rollItem").
!-- @param title: The title for the rollable image if it is not actually rollable.
!-- @param rollableTitle: The title for the rollable image if it is rollable.
!-- @param src: The path to the image.
!-- @param alt: An alternate text for the image.
--}}
<div class="ds4-rollable-image{{#if rollable}} ds4-rollable-image--rollable {{rollableClass}}{{/if}}"
<div class="ds4-rollable-image{{#if rollable}} ds4-rollable-image--rollable{{/if}}"
{{#if rollable}}data-action="{{rollableAction}}"{{/if}}
title="{{#if rollable}}{{rollableTitle}}{{else}}{{title}}{{/if}}">
{{#if src}}
<img class="ds4-rollable-image__image" alt="{{alt}}" src="{{src}}" />