Merge branch 'equip-items-in-character-sheet' into 'master'

make equip icon for items clickable in item list in character sheet

See merge request dungeonslayers/ds4!14
This commit is contained in:
Johannes Loher 2021-01-04 08:53:53 +01:00
commit 7f6896236c
5 changed files with 137 additions and 29 deletions

View file

@ -62,6 +62,8 @@ export class DS4ActorSheet extends ActorSheet<DS4ActorDataType, DS4Actor, DS4Ite
li.slideUp(200, () => this.render(false)); li.slideUp(200, () => this.render(false));
}); });
html.find(".item-change").on("change", this._onItemChange.bind(this));
// Rollable abilities. // Rollable abilities.
html.find(".rollable").click(this._onRoll.bind(this)); html.find(".rollable").click(this._onRoll.bind(this));
} }
@ -70,7 +72,7 @@ export class DS4ActorSheet extends ActorSheet<DS4ActorDataType, DS4Actor, DS4Ite
/** /**
* Handle creating a new Owned Item for the actor using initial data defined in the HTML dataset * Handle creating a new Owned Item for the actor using initial data defined in the HTML dataset
* @param {Event} event The originating click event * @param {JQuery.ClickEvent} event The originating click event
* @private * @private
*/ */
private _onItemCreate(event: JQuery.ClickEvent): Promise<Item> { private _onItemCreate(event: JQuery.ClickEvent): Promise<Item> {
@ -95,9 +97,93 @@ export class DS4ActorSheet extends ActorSheet<DS4ActorDataType, DS4Actor, DS4Ite
return this.actor.createOwnedItem(itemData); return this.actor.createOwnedItem(itemData);
} }
/**
* Handle changes to properties of an Owned Item from within character sheet.
* Can currently properly bind: see getValue().
* Assumes the item property is given as the value of the HTML element property 'data-property'.
* @param {JQuery.ChangeEvent<HTMLFormElement>} ev The originating change event
* @private
*/
private _onItemChange(ev: JQuery.ChangeEvent<HTMLFormElement>): void {
ev.preventDefault();
console.log("Current target:", $(ev.currentTarget).get(0)["name"]);
const el: HTMLFormElement = $(ev.currentTarget).get(0);
const id = $(ev.currentTarget).parents(".item").data("itemId");
const item = duplicate(this.actor.getOwnedItem(id)); // getOwnedItem is typed incorrectly, it actually returns a ItemData<DS4ItemDataType>, not an Item
const property: string | undefined = $(ev.currentTarget).data("property");
// Early return:
// Disabled => do nothing
if (el.disabled || el.getAttribute("disabled")) return;
// name not given => raise
if (property === undefined) {
throw TypeError("HTML element does not provide 'data-property' attribute");
}
// Set new value
const newValue = this.getValue(el);
setProperty(item, property, newValue);
this.actor.updateOwnedItem(item);
}
/**
* Collect the value of a form element depending on the element's type
* The value is parsed to:
* - Checkbox: boolean
* - Text input: string
* - Number: number
* @param el the input element to collect the value of
*/
private getValue(el: HTMLFormElement): boolean | string | number {
// One needs to differentiate between e.g. checkboxes (value="on") and select boxes etc.
// Checkbox:
if (el.type === "checkbox") {
const value: boolean = el.checked;
return value;
}
// Text input:
else if (el.type === "text") {
const value: string = el.value;
return value;
}
// Numbers:
else if (el.type === "number") {
const value = Number(el.value.trim());
return value;
}
// // Ranges:
// else if (el.type === "range") {
// const value: string = el.value.trim();
// return value;
// }
// // Radio Checkboxes (untested, cf. FormDataExtended.process)
// else if (el.type === "radio") {
// const chosen: HTMLFormElement = el.find((r: HTMLFormElement) => r["checked"]);
// const value: string = chosen ? chosen.value : null;
// return value;
// }
// // Multi-Select (untested, cf. FormDataExtended.process)
// else if (el.type === "select-multiple") {
// const value: Array<string> = [];
// el.options.array.forEach((opt: HTMLOptionElement) => {
// if (opt.selected) value.push(opt.value);
// });
// return value;
// unsupported:
else {
throw TypeError("Binding of item property to this type of HTML element not supported; given: " + el);
}
}
/** /**
* Handle clickable rolls. * Handle clickable rolls.
* @param {Event} event The originating click event * @param {JQuery.ClickEvent} event The originating click event
* @private * @private
*/ */
private _onRoll(event: JQuery.ClickEvent): void { private _onRoll(event: JQuery.ClickEvent): void {

View file

@ -1,3 +1,5 @@
@use "sass:color";
.items-list { .items-list {
list-style: none; list-style: none;
margin: 7px 0; margin: 7px 0;
@ -16,13 +18,26 @@
.item-image { .item-image {
flex: 0 0 24px; flex: 0 0 24px;
margin-right: 5px; height: 100%;
//margin-right: 5px;
@include centered-content;
} }
img { img {
display: block; display: block;
border: none; border: none;
} }
input {
border: 0;
padding: 0;
}
input[type="checkbox"] {
width: auto;
height: 100%;
margin: 0px;
}
} }
.item-name { .item-name {
@ -36,6 +51,11 @@
.item-num-val { .item-num-val {
text-align: center; text-align: center;
width: 2.5em;
padding: 0;
}
.item-num-val:invalid {
background-color: color.mix(lightcoral, $c-light-grey, 25%);
} }
.item-description { .item-description {
@ -43,6 +63,7 @@
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
height: 100%;
p { p {
text-overflow: ellipsis; text-overflow: ellipsis;
overflow: hidden; overflow: hidden;

View file

@ -12,7 +12,7 @@
--}} --}}
{{#*inline "addItemButton"}} {{#*inline "addItemButton"}}
<div class="item-controls"> <div class="item-controls">
<a class="item-control item-create" title="Create item" data-type="{{dataType}}" {{!-- SPECIFIC --}}> <a class="item-control item-create" title="Create item" data-type="{{dataType}}">
<i class="fas fa-plus"></i> <i class="fas fa-plus"></i>
{{localize 'DS4.UserInteractionAddItem'}}</a> {{localize 'DS4.UserInteractionAddItem'}}</a>
</div> </div>
@ -44,14 +44,14 @@
<li class="item flexrow item-header"> <li class="item flexrow item-header">
{{!-- equipped --}} {{!-- equipped --}}
{{#if (ne dataType 'equipment')}} {{#if (ne dataType 'equipment')}}
<div title="{{localize 'DS4.ItemEquipped'}}" class="flex05">E</div> <div class="flex05" title="{{localize 'DS4.ItemEquipped'}}">E</div>
{{/if}} {{/if}}
{{!-- image --}} {{!-- image --}}
<div class="item-image" class="flex05"></div> <div class="flex05 item-image"></div>
{{!-- amount --}} {{!-- amount --}}
<div class="item-num-val" title="{{localize 'DS4.Quantity'}}" class="flex05">#</div> <div class="flex05 item-num-val" title="{{localize 'DS4.Quantity'}}">#</div>
{{!-- name --}} {{!-- name --}}
<div class="item-name flex3">{{localize 'DS4.ItemName'}}</div> <div class="flex3 item-name">{{localize 'DS4.ItemName'}}</div>
{{!-- item type specifics --}} {{!-- item type specifics --}}
{{> @partial-block }} {{> @partial-block }}
{{!-- description --}} {{!-- description --}}
@ -76,20 +76,19 @@
<li class="item flexrow" data-item-id="{{item._id}}"> <li class="item flexrow" data-item-id="{{item._id}}">
{{!-- equipped --}} {{!-- equipped --}}
{{#if (ne item.data.data.equipped undefined)}} {{#if (ne item.data.data.equipped undefined)}}
{{#if item.data.data.equipped}}<i class="fas fa-check-square flex05"></i> <input class="flex05 item-change" type="checkbox" {{checked item.data.data.equipped}} data-dtype="Boolean"
{{else}}<i class="far fa-square flex05"></i> data-property="data.equipped" title="{{localize 'DS4.ItemEquipped'}}">
{{/if}}
{{/if}} {{/if}}
<div class="flexrow flexnowrap flex15"> {{!-- image --}}
{{!-- image --}} <div class="flex05 item-image">
<div class="item-image"> <img src="{{item.img}}" title="{{item.name}}" width="24" height="24" />
<img src="{{item.img}}" title="{{item.name}}" width="24" height="24" />
</div>
{{!-- amount --}}
<div class="item-num-val">{{item.data.data.quantity}}</div>
</div> </div>
{{!-- amount --}}
<input class="flex05 item-num-val item-change" type="number" min="0" step="1" value="{{item.data.data.quantity}}" data-dtype="Number"
data-property="data.quantity" title="{{localize 'DS4.Quantity'}}">
{{!-- name --}} {{!-- name --}}
<h4 class="item-name flex3">{{item.name}}</h4> <input class="flex3 item-name item-change" type="text" value="{{item.name}}" data-dtype="String"
data-property="name" title="{{localize 'DS4.ItemName'}}">
{{!-- item type specifics --}} {{!-- item type specifics --}}
{{> @partial-block}} {{> @partial-block}}
{{!-- description --}} {{!-- description --}}
@ -109,22 +108,22 @@
<h4 class="items-list-title">{{localize 'DS4.ItemTypeWeapon'}}</h4> <h4 class="items-list-title">{{localize 'DS4.ItemTypeWeapon'}}</h4>
<ol class="items-list"> <ol class="items-list">
{{#> itemListHeader dataType='weapon'}} {{#> itemListHeader dataType='weapon'}}
<div title="{{localize 'DS4.AttackType'}}" class="flex05">{{localize 'DS4.AttackTypeAbbr'}}</div> <div class="flex05 item-image" title="{{localize 'DS4.AttackType'}}">{{localize 'DS4.AttackTypeAbbr'}}</div>
<div class="item-num-val flex05" title="{{localize 'DS4.WeaponBonus'}}"> <div class="flex05 item-num-val" title="{{localize 'DS4.WeaponBonus'}}">
{{localize 'DS4.WeaponBonusAbbr'}} {{localize 'DS4.WeaponBonusAbbr'}}
</div> </div>
<div class="item-num-val flex05" title="{{localize 'DS4.OpponentDefense'}}"> <div class="flex05 item-num-val" title="{{localize 'DS4.OpponentDefense'}}">
{{localize 'DS4.OpponentDefenseAbbr'}} {{localize 'DS4.OpponentDefenseAbbr'}}
</div> </div>
{{/itemListHeader}} {{/itemListHeader}}
{{#each itemsByType.weapon as |item id|}} {{#each itemsByType.weapon as |item id|}}
{{#> itemListEntry item=item}} {{#> itemListEntry item=item}}
<div class="flex05"> <div class="flex05 item-image">
<img src="{{lookup ../../config.attackTypesIcons item.data.data.attackType}}" <img src="{{lookup ../../config.attackTypesIcons item.data.data.attackType}}"
title="{{lookup ../../config.attackTypes item.data.data.attackType}}" width="24" height="24" /> title="{{lookup ../../config.attackTypes item.data.data.attackType}}" width="24" height="24" />
</div> </div>
<div class="item-num-val flex05">{{ item.data.data.weaponBonus}}</div> <div class="flex05 item-num-val">{{ item.data.data.weaponBonus}}</div>
<div class="item-num-val flex05">{{ item.data.data.opponentDefense}}</div> <div class="flex05 item-num-val">{{ item.data.data.opponentDefense}}</div>
{{/itemListEntry}} {{/itemListEntry}}
{{/each}} {{/each}}
</ol> </ol>
@ -176,7 +175,8 @@
{{/itemListHeader}} {{/itemListHeader}}
{{#each itemsByType.trinket as |item id|}} {{#each itemsByType.trinket as |item id|}}
{{#> itemListEntry item=item }} {{#> itemListEntry item=item }}
<div class="flex2">{{{item.data.data.storageLocation}}}</div> <input class="flex2 item-change" type="text" value="{{item.data.data.storageLocation}}" data-dtype="String"
data-property="data.storageLocation" title="{{localize 'DS4.StorageLocation'}}">
{{/itemListEntry}} {{/itemListEntry}}
{{/each}} {{/each}}
</ol> </ol>
@ -189,7 +189,8 @@
{{/itemListHeader}} {{/itemListHeader}}
{{#each itemsByType.equipment as |item id|}} {{#each itemsByType.equipment as |item id|}}
{{#> itemListEntry item=item }} {{#> itemListEntry item=item }}
<div class="flex2">{{{item.data.data.storageLocation}}}</div> <input class="flex2 item-change" type="text" value="{{item.data.data.storageLocation}}" data-dtype="String"
data-property="data.storageLocation" title="{{localize 'DS4.StorageLocation'}}">
{{/itemListEntry}} {{/itemListEntry}}
{{/each}} {{/each}}
</ol> </ol>

View file

@ -13,7 +13,7 @@
</div> </div>
<div class="side-property"> <div class="side-property">
<label for="data.quantity">{{localize 'DS4.Quantity'}}</label> <label for="data.quantity">{{localize 'DS4.Quantity'}}</label>
<input type="number" data-dtype="Number" name="data.quantity" value="{{data.quantity}}" /> <input type="number" min="0" step="1" data-dtype="Number" name="data.quantity" value="{{data.quantity}}" />
</div> </div>
<div class="side-property"> <div class="side-property">
<label for="data.storageLocation">{{localize 'DS4.StorageLocation'}}</label> <label for="data.storageLocation">{{localize 'DS4.StorageLocation'}}</label>

View file

@ -4,7 +4,7 @@
<div class="side-properties"> <div class="side-properties">
<div class="side-property"> <div class="side-property">
<label for="data.price">{{localize "DS4.PriceGold"}}</label> <label for="data.price">{{localize "DS4.PriceGold"}}</label>
<input type="number" data-dtype="Number" name="data.price" value="{{data.price}}" /> <input type="number" min="0" data-dtype="Number" name="data.price" value="{{data.price}}" />
</div> </div>
<div class="side-property"> <div class="side-property">
<label for="data.availability">{{localize "DS4.ItemAvailability"}}</label> <label for="data.availability">{{localize "DS4.ItemAvailability"}}</label>