RC-65 | Gear | Display Data
This commit is contained in:
parent
9a3b82ef6a
commit
1e416ff9bf
10 changed files with 172 additions and 39 deletions
|
|
@ -17,6 +17,8 @@
|
|||
"HeroSkillsCardV1": "Hero Skill Card"
|
||||
},
|
||||
"common": {
|
||||
"edit": "Edit",
|
||||
"delete": "Delete",
|
||||
"empty": "---",
|
||||
"move": "Move",
|
||||
"run": "Run",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { filePath } from "../../consts.mjs";
|
||||
import { GenericAppMixin } from "../GenericApp.mjs";
|
||||
import { HeroSkillsCardV1 } from "./HeroSkillsCardV1.mjs";
|
||||
import { HeroSummaryCardV1 } from "./HeroSummaryCardV1.mjs";
|
||||
import { Logger } from "../../utils/Logger.mjs";
|
||||
|
||||
|
|
@ -43,7 +44,26 @@ export class CombinedHeroSheet extends GenericAppMixin(HandlebarsApplicationMixi
|
|||
// #region Lifecycle
|
||||
async _onRender(context, options) {
|
||||
await super._onRender(context, options);
|
||||
HeroSummaryCardV1._onRender.bind(this)(context, options);
|
||||
|
||||
const summaryElement = this.element.querySelector(`.HeroSummaryCardV1`);
|
||||
HeroSummaryCardV1._onRender(
|
||||
context,
|
||||
{
|
||||
...options,
|
||||
element: summaryElement,
|
||||
isEditable: this.isEditable,
|
||||
},
|
||||
);
|
||||
|
||||
const skillsElement = this.element.querySelector(`.HeroSkillsCardV1`);
|
||||
HeroSkillsCardV1._onRender.bind(this)(
|
||||
context,
|
||||
{
|
||||
...options,
|
||||
element: skillsElement,
|
||||
isEditable: this.isEditable,
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
async _preparePartContext(partId, ctx, opts) {
|
||||
|
|
@ -58,6 +78,8 @@ export class CombinedHeroSheet extends GenericAppMixin(HandlebarsApplicationMixi
|
|||
ctx = await HeroSummaryCardV1.prepareSpeed(ctx);
|
||||
ctx = await HeroSummaryCardV1.prepareLevelData(ctx);
|
||||
|
||||
ctx = await HeroSkillsCardV1.prepareGear(ctx);
|
||||
|
||||
Logger.debug(`Context:`, ctx);
|
||||
return ctx;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { deleteItemFromElement, editItemFromElement } from "../utils.mjs";
|
||||
import { filePath } from "../../consts.mjs";
|
||||
import { gameTerms } from "../../gameTerms.mjs";
|
||||
import { GenericAppMixin } from "../GenericApp.mjs";
|
||||
|
|
@ -6,6 +7,7 @@ import { Logger } from "../../utils/Logger.mjs";
|
|||
|
||||
const { HandlebarsApplicationMixin } = foundry.applications.api;
|
||||
const { ActorSheetV2 } = foundry.applications.sheets;
|
||||
const { ContextMenu } = foundry.applications.ui;
|
||||
|
||||
export class HeroSkillsCardV1 extends GenericAppMixin(HandlebarsApplicationMixin(ActorSheetV2)) {
|
||||
|
||||
|
|
@ -38,13 +40,79 @@ export class HeroSkillsCardV1 extends GenericAppMixin(HandlebarsApplicationMixin
|
|||
// #endregion
|
||||
|
||||
// #region Lifecycle
|
||||
async _onRender(context, options) {
|
||||
await super._onRender(context, options);
|
||||
HeroSkillsCardV1._onRender.bind(this)(context, options);
|
||||
};
|
||||
|
||||
static async _onRender(_context, options) {
|
||||
const {
|
||||
element = this.element,
|
||||
isEditable = this.isEditable,
|
||||
} = options;
|
||||
new ContextMenu(
|
||||
element,
|
||||
`[data-ctx-menu="gear"]`,
|
||||
[
|
||||
{
|
||||
name: localizer(`RipCrypt.common.edit`),
|
||||
condition: (el) => {
|
||||
const itemId = el.dataset.itemId;
|
||||
return isEditable && itemId !== ``;
|
||||
},
|
||||
callback: editItemFromElement,
|
||||
},
|
||||
{
|
||||
name: localizer(`RipCrypt.common.delete`),
|
||||
condition: (el) => {
|
||||
const itemId = el.dataset.itemId;
|
||||
return isEditable && itemId !== ``;
|
||||
},
|
||||
callback: deleteItemFromElement,
|
||||
},
|
||||
],
|
||||
{ jQuery: false, fixed: true },
|
||||
);
|
||||
};
|
||||
|
||||
async _preparePartContext(partId, ctx, opts) {
|
||||
ctx = await super._preparePartContext(partId, ctx, opts);
|
||||
ctx.actor = this.document;
|
||||
|
||||
ctx = await HeroSkillsCardV1.prepareGear(ctx);
|
||||
|
||||
Logger.debug(`Context:`, ctx);
|
||||
return ctx;
|
||||
};
|
||||
|
||||
static async prepareGear(ctx) {
|
||||
const limit = ctx.actor.system.limit.equipment;
|
||||
ctx.gear = [];
|
||||
const items = [...ctx.actor.items];
|
||||
for (const item of items) {
|
||||
if (!gameTerms.gearItemTypes.has(item.type)) { continue };
|
||||
|
||||
if ( `equipped` in item.system && !item.system.equipped) { continue };
|
||||
ctx.gear.push({
|
||||
index: ctx.gear.length,
|
||||
uuid: item.uuid,
|
||||
name: item.name,
|
||||
empty: false,
|
||||
});
|
||||
|
||||
if (ctx.gear.length >= limit) { break };
|
||||
};
|
||||
|
||||
if (ctx.gear.length < limit) {
|
||||
for (let i = ctx.gear.length - 1; i <= limit; i++) {
|
||||
ctx.gear.push({
|
||||
index: ctx.gear.length,
|
||||
uuid: ``, name: ``, empty: true });
|
||||
};
|
||||
};
|
||||
|
||||
return ctx;
|
||||
};
|
||||
// #endregion
|
||||
|
||||
// #region Actions
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { deleteItemFromElement, editItemFromElement } from "../utils.mjs";
|
||||
import { filePath } from "../../consts.mjs";
|
||||
import { gameTerms } from "../../gameTerms.mjs";
|
||||
import { GenericAppMixin } from "../GenericApp.mjs";
|
||||
|
|
@ -24,7 +25,6 @@ export class HeroSummaryCardV1 extends GenericAppMixin(HandlebarsApplicationMixi
|
|||
resizable: false,
|
||||
},
|
||||
actions: {
|
||||
editItem: (_event, target) => this._editItem(target),
|
||||
},
|
||||
form: {
|
||||
submitOnChange: true,
|
||||
|
|
@ -45,32 +45,30 @@ export class HeroSummaryCardV1 extends GenericAppMixin(HandlebarsApplicationMixi
|
|||
HeroSummaryCardV1._onRender.bind(this)(context, options);
|
||||
};
|
||||
|
||||
static async _onRender() {
|
||||
static async _onRender(context, options) {
|
||||
const {
|
||||
element = this.element,
|
||||
isEditable = this.isEditable,
|
||||
} = options;
|
||||
new ContextMenu(
|
||||
this.element,
|
||||
element,
|
||||
`[data-ctx-menu="weapon"],[data-ctx-menu="armour"]`,
|
||||
[
|
||||
{
|
||||
name: `Edit`,
|
||||
name: localizer(`RipCrypt.common.edit`),
|
||||
condition: (el) => {
|
||||
const itemId = el.dataset.itemId;
|
||||
return this.isEditable && itemId !== ``;
|
||||
return isEditable && itemId !== ``;
|
||||
},
|
||||
callback: HeroSummaryCardV1._editItem,
|
||||
callback: editItemFromElement,
|
||||
},
|
||||
{
|
||||
name: `Delete`,
|
||||
name: localizer(`RipCrypt.common.delete`),
|
||||
condition: (el) => {
|
||||
const itemId = el.dataset.itemId;
|
||||
return this.isEditable && itemId !== ``;
|
||||
},
|
||||
callback: async (el) => {
|
||||
const itemEl = el.closest(`[data-item-id]`);
|
||||
if (!itemEl) { return };
|
||||
const itemId = itemEl.dataset.itemId;
|
||||
const item = await fromUuid(itemId);
|
||||
await item.delete();
|
||||
return isEditable && itemId !== ``;
|
||||
},
|
||||
callback: deleteItemFromElement,
|
||||
},
|
||||
],
|
||||
{ jQuery: false, fixed: true },
|
||||
|
|
@ -200,13 +198,5 @@ export class HeroSummaryCardV1 extends GenericAppMixin(HandlebarsApplicationMixi
|
|||
// #endregion
|
||||
|
||||
// #region Actions
|
||||
static async _editItem(target) {
|
||||
const itemEl = target.closest(`[data-item-id]`);
|
||||
if (!itemEl) { return };
|
||||
const itemId = itemEl.dataset.itemId;
|
||||
if (!itemId) { return };
|
||||
const item = await fromUuid(itemId);
|
||||
item.sheet.render({ force: true });
|
||||
};
|
||||
// #endregion
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { deleteItemFromElement, editItemFromElement } from "./utils.mjs";
|
||||
import { DicePool } from "./DicePool.mjs";
|
||||
|
||||
/**
|
||||
|
|
@ -12,7 +13,9 @@ export function GenericAppMixin(HandlebarsApp) {
|
|||
`ripcrypt`,
|
||||
],
|
||||
actions: {
|
||||
roll: this.rollDice,
|
||||
roll: this._rollDice,
|
||||
editItem: (_event, target) => editItemFromElement(target),
|
||||
deleteItem: (_event, target) => deleteItemFromElement(target),
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -22,6 +25,19 @@ export function GenericAppMixin(HandlebarsApp) {
|
|||
// #endregion
|
||||
|
||||
// #region Lifecycle
|
||||
/**
|
||||
* @override
|
||||
* Making it so that if the app is already open, it's brought to
|
||||
* top after being re-rendered as normal
|
||||
*/
|
||||
async render(options = {}, _options = {}) {
|
||||
super.render(options, _options);
|
||||
const instance = foundry.applications.instances.get(this.id);
|
||||
if (instance !== undefined && !options.noBringToFront) {
|
||||
instance.bringToFront();
|
||||
};
|
||||
};
|
||||
|
||||
async _preparePartContext(partId, ctx, opts) {
|
||||
ctx = await super._preparePartContext(partId, ctx, opts);
|
||||
delete ctx.document;
|
||||
|
|
@ -41,7 +57,7 @@ export function GenericAppMixin(HandlebarsApp) {
|
|||
|
||||
// #region Actions
|
||||
/** @this {GenericRipCryptApp} */
|
||||
static async rollDice(_$e, el) {
|
||||
static async _rollDice(_$e, el) {
|
||||
const data = el.dataset;
|
||||
const diceCount = parseInt(data.diceCount);
|
||||
const flavor = data.flavor;
|
||||
|
|
|
|||
27
module/Apps/utils.mjs
Normal file
27
module/Apps/utils.mjs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
This file contains utilities used by Applications in order to be DRYer
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {HTMLElement} target The element that gets
|
||||
*/
|
||||
export async function editItemFromElement(target) {
|
||||
const itemEl = target.closest(`[data-item-id]`);
|
||||
if (!itemEl) { return };
|
||||
const itemId = itemEl.dataset.itemId;
|
||||
if (!itemId) { return };
|
||||
const item = await fromUuid(itemId);
|
||||
item.sheet.render({ force: true });
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {HTMLElement} target The element that gets
|
||||
*/
|
||||
export async function deleteItemFromElement(target) {
|
||||
const itemEl = target.closest(`[data-item-id]`);
|
||||
if (!itemEl) { return };
|
||||
const itemId = itemEl.dataset.itemId;
|
||||
if (!itemId) { return };
|
||||
const item = await fromUuid(itemId);
|
||||
item.delete();
|
||||
};
|
||||
|
|
@ -46,7 +46,7 @@ export class ProtectorData extends foundry.abstract.TypeDataModel {
|
|||
// #endregion
|
||||
|
||||
// #region Sheet Data
|
||||
getFormFields(ctx) {
|
||||
getFormFields(_ctx) {
|
||||
const fields = [
|
||||
{
|
||||
id: `location`,
|
||||
|
|
|
|||
|
|
@ -23,4 +23,10 @@ export const gameTerms = Object.preventExtensions({
|
|||
ARMS: `arms`,
|
||||
LEGS: `legs`,
|
||||
}),
|
||||
/** The types of items that contribute to the gear limit */
|
||||
gearItemTypes: new Set([
|
||||
`armour`,
|
||||
`weapon`,
|
||||
`shield`,
|
||||
]),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -48,18 +48,16 @@
|
|||
<span class="small">{{ rc-i18n "RipCrypt.common.slot" }}</span>
|
||||
</div>
|
||||
<ol class="num-after gear-list">
|
||||
<li></li>
|
||||
<li></li>
|
||||
<li></li>
|
||||
<li></li>
|
||||
<li></li>
|
||||
<li></li>
|
||||
<li></li>
|
||||
<li></li>
|
||||
<li></li>
|
||||
<li></li>
|
||||
<li></li>
|
||||
<li></li>
|
||||
{{#each gear as | itemInSlot |}}
|
||||
<li
|
||||
data-slot="{{itemInSlot.index}}"
|
||||
data-ctx-menu="gear"
|
||||
data-slot-empty="{{ itemInSlot.empty }}"
|
||||
data-item-id="{{ itemInSlot.uuid }}"
|
||||
>
|
||||
{{itemInSlot.name}}
|
||||
</li>
|
||||
{{/each}}
|
||||
</ol>
|
||||
|
||||
<div class="currencies">
|
||||
|
|
|
|||
|
|
@ -85,6 +85,10 @@
|
|||
grid-template-rows: subgrid;
|
||||
list-style-type: none;
|
||||
|
||||
> li {
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
> :nth-child(even) {
|
||||
background: var(--alt-row-background);
|
||||
color: var(--alt-row-text);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue