Update Simple Worldbuilding for Foundry 0.8.x Compatibility

This commit is contained in:
Andrew 2021-05-18 17:36:07 -04:00
parent ee8814b76a
commit fb0add4cbc
11 changed files with 295 additions and 301 deletions

View file

@ -4,8 +4,13 @@
"SETTINGS.SimpleInitFormulaN": "Initiative Formula", "SETTINGS.SimpleInitFormulaN": "Initiative Formula",
"SETTINGS.SimpleInitFormulaL": "Enter an initiative formula, such as d20+@dex", "SETTINGS.SimpleInitFormulaL": "Enter an initiative formula, such as d20+@dex",
"SIMPLE.NotifyInitFormulaUpdated": "Initiative formula was updated to:", "SIMPLE.ItemCreate": "Create Item",
"SIMPLE.NotifyInitFormulaInvalid": "Initiative formula was invalid:", "SIMPLE.ItemEdit": "Edit Item",
"SIMPLE.ItemDelete": "Delete Item",
"SIMPLE.ItemNew": "New Item",
"SIMPLE.NotifyInitFormulaUpdated": "Initiative formula was updated to",
"SIMPLE.NotifyInitFormulaInvalid": "Initiative formula was invalid",
"SIMPLE.NotifyGroupDuplicate": "Attribute group already exists.", "SIMPLE.NotifyGroupDuplicate": "Attribute group already exists.",
"SIMPLE.NotifyGroupAttrDuplicate": "Attribute group already exists as an attribute.", "SIMPLE.NotifyGroupAttrDuplicate": "Attribute group already exists as an attribute.",
"SIMPLE.NotifyGroupAlphanumeric": "Attribute group names may not contain spaces or periods.", "SIMPLE.NotifyGroupAlphanumeric": "Attribute group names may not contain spaces or periods.",

View file

@ -1,4 +1,5 @@
import { EntitySheetHelper } from "./helper.js"; import { EntitySheetHelper } from "./helper.js";
import {ATTRIBUTE_TYPES} from "./constants.js";
/** /**
* Extend the basic ActorSheet with some very simple modifications * Extend the basic ActorSheet with some very simple modifications
@ -6,9 +7,9 @@ import { EntitySheetHelper } from "./helper.js";
*/ */
export class SimpleActorSheet extends ActorSheet { export class SimpleActorSheet extends ActorSheet {
/** @override */ /** @inheritdoc */
static get defaultOptions() { static get defaultOptions() {
return mergeObject(super.defaultOptions, { return foundry.utils.mergeObject(super.defaultOptions, {
classes: ["worldbuilding", "sheet", "actor"], classes: ["worldbuilding", "sheet", "actor"],
template: "systems/worldbuilding/templates/actor-sheet.html", template: "systems/worldbuilding/templates/actor-sheet.html",
width: 600, width: 600,
@ -21,42 +22,35 @@ export class SimpleActorSheet extends ActorSheet {
/* -------------------------------------------- */ /* -------------------------------------------- */
/** @override */ /** @inheritdoc */
getData() { getData() {
const data = super.getData(); const context = super.getData();
EntitySheetHelper.getAttributeData(data); EntitySheetHelper.getAttributeData(context.data);
data.shorthand = !!game.settings.get("worldbuilding", "macroShorthand"); context.shorthand = !!game.settings.get("worldbuilding", "macroShorthand");
return data; context.systemData = context.data.data;
context.dtypes = ATTRIBUTE_TYPES;
return context;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
/** @override */ /** @inheritdoc */
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
// Everything below here is only needed if the sheet is editable // Everything below here is only needed if the sheet is editable
if ( !this.options.editable ) return; if ( !this.isEditable ) return;
// Handle rollable items and attributes // Attribute Management
html.find(".items .rollable").on("click", this._onItemRoll.bind(this)); html.find(".attributes").on("click", ".attribute-control", EntitySheetHelper.onClickAttributeControl.bind(this));
html.find(".groups").on("click", ".group-control", EntitySheetHelper.onClickAttributeGroupControl.bind(this));
html.find(".attributes").on("click", "a.attribute-roll", EntitySheetHelper.onAttributeRoll.bind(this)); html.find(".attributes").on("click", "a.attribute-roll", EntitySheetHelper.onAttributeRoll.bind(this));
// Update Inventory Item // Item Controls
html.find('.item-edit').click(ev => { html.find(".item-control").click(this._onItemControl.bind(this));
const li = $(ev.currentTarget).parents(".item"); html.find(".items .rollable").on("click", this._onItemRoll.bind(this));
const item = this.actor.getOwnedItem(li.data("itemId"));
item.sheet.render(true);
});
// Delete Inventory Item // Add draggable for Macro creation
html.find('.item-delete').click(ev => {
const li = $(ev.currentTarget).parents(".item");
this.actor.deleteOwnedItem(li.data("itemId"));
li.slideUp(200, () => this.render(false));
});
// Add draggable for macros.
html.find(".attributes a.attribute-roll").each((i, a) => { html.find(".attributes a.attribute-roll").each((i, a) => {
a.setAttribute("draggable", true); a.setAttribute("draggable", true);
a.addEventListener("dragstart", ev => { a.addEventListener("dragstart", ev => {
@ -64,12 +58,33 @@ export class SimpleActorSheet extends ActorSheet {
ev.dataTransfer.setData('text/plain', JSON.stringify(dragData)); ev.dataTransfer.setData('text/plain', JSON.stringify(dragData));
}, false); }, false);
}); });
}
// Add or Remove Attribute /* -------------------------------------------- */
html.find(".attributes").on("click", ".attribute-control", EntitySheetHelper.onClickAttributeControl.bind(this));
// Add attribute groups. /**
html.find(".groups").on("click", ".group-control", EntitySheetHelper.onClickAttributeGroupControl.bind(this)); * Handle click events for Item control buttons within the Actor Sheet
* @param event
* @private
*/
_onItemControl(event) {
event.preventDefault();
// Obtain event data
const button = event.currentTarget;
const li = button.closest(".item");
const item = this.actor.items.get(li?.dataset.itemId);
// Handle different actions
switch ( button.dataset.action ) {
case "create":
const cls = getDocumentClass("Item");
return cls.create({name: game.i18n.localize("SIMPLE.ItemNew"), type: "item"}, {parent: this.actor});
case "edit":
return item.sheet.render(true);
case "delete":
return item.delete();
}
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -80,11 +95,11 @@ export class SimpleActorSheet extends ActorSheet {
*/ */
_onItemRoll(event) { _onItemRoll(event) {
let button = $(event.currentTarget); let button = $(event.currentTarget);
let r = new Roll(button.data('roll'), this.actor.getRollData());
const li = button.parents(".item"); const li = button.parents(".item");
const item = this.actor.getOwnedItem(li.data("itemId")); const item = this.actor.items.get(li.data("itemId"));
r.roll().toMessage({ let r = new Roll(button.data('roll'), this.actor.getRollData());
user: game.user._id, return r.toMessage({
user: game.user.id,
speaker: ChatMessage.getSpeaker({ actor: this.actor }), speaker: ChatMessage.getSpeaker({ actor: this.actor }),
flavor: `<h2>${item.name}</h2><h3>${button.text()}</h3>` flavor: `<h2>${item.name}</h2><h3>${button.text()}</h3>`
}); });
@ -92,11 +107,11 @@ export class SimpleActorSheet extends ActorSheet {
/* -------------------------------------------- */ /* -------------------------------------------- */
/** @override */ /** @inheritdoc */
_updateObject(event, formData) { _getSubmitData(updateData) {
formData = EntitySheetHelper.updateAttributes(formData, this); let formData = super._getSubmitData(updateData);
formData = EntitySheetHelper.updateGroups(formData, this); formData = EntitySheetHelper.updateAttributes(formData, this.object);
return this.object.update(formData); formData = EntitySheetHelper.updateGroups(formData, this.object);
return formData;
} }
} }

View file

@ -1,14 +1,14 @@
import { EntitySheetHelper } from "./helper.js"; import { EntitySheetHelper } from "./helper.js";
/** /**
* Extend the base Actor entity by defining a custom roll data structure which is ideal for the Simple system. * Extend the base Actor document to support attributes and groups with a custom template creation dialog.
* @extends {Actor} * @extends {Actor}
*/ */
export class SimpleActor extends Actor { export class SimpleActor extends Actor {
/** @override */ /** @inheritdoc */
prepareData() { prepareDerivedData() {
super.prepareData(); super.prepareDerivedData();
this.data.data.groups = this.data.data.groups || {}; this.data.data.groups = this.data.data.groups || {};
this.data.data.attributes = this.data.data.attributes || {}; this.data.data.attributes = this.data.data.attributes || {};
} }
@ -16,8 +16,19 @@ export class SimpleActor extends Actor {
/* -------------------------------------------- */ /* -------------------------------------------- */
/** @override */ /** @override */
static async createDialog(data={}, options={}) {
return EntitySheetHelper.createDialog.call(this, data, options);
}
/* -------------------------------------------- */
/* Roll Data Preparation */
/* -------------------------------------------- */
/** @inheritdoc */
getRollData() { getRollData() {
const data = super.getRollData();
// Copy the actor's system data
const data = this.toObject(false).data;
const shorthand = game.settings.get("worldbuilding", "macroShorthand"); const shorthand = game.settings.get("worldbuilding", "macroShorthand");
const formulaAttributes = []; const formulaAttributes = [];
const itemAttributes = []; const itemAttributes = [];
@ -41,10 +52,11 @@ export class SimpleActor extends Actor {
delete data.abil; delete data.abil;
delete data.groups; delete data.groups;
} }
return data; return data;
} }
/* -------------------------------------------- */
/** /**
* Apply shorthand syntax to actor roll data. * Apply shorthand syntax to actor roll data.
* @param {Object} data The actor's data object. * @param {Object} data The actor's data object.
@ -53,9 +65,9 @@ export class SimpleActor extends Actor {
*/ */
_applyShorthand(data, formulaAttributes, shorthand) { _applyShorthand(data, formulaAttributes, shorthand) {
// Handle formula attributes when the short syntax is disabled. // Handle formula attributes when the short syntax is disabled.
for ( let [k, v] of Object.entries(data.attributes) ) { for ( let [k, v] of Object.entries(data.attributes || {}) ) {
// Make an array of formula attributes for later reference. // Make an array of formula attributes for later reference.
if ( v.dtype == "Formula" ) formulaAttributes.push(k); if ( v.dtype === "Formula" ) formulaAttributes.push(k);
// Add shortened version of the attributes. // Add shortened version of the attributes.
if ( !!shorthand ) { if ( !!shorthand ) {
if ( !(k in data) ) { if ( !(k in data) ) {
@ -68,7 +80,7 @@ export class SimpleActor extends Actor {
data[k] = {}; data[k] = {};
for ( let [gk, gv] of Object.entries(v) ) { for ( let [gk, gv] of Object.entries(v) ) {
data[k][gk] = gv.value; data[k][gk] = gv.value;
if ( gv.dtype == "Formula" ) formulaAttributes.push(`${k}.${gk}`); if ( gv.dtype === "Formula" ) formulaAttributes.push(`${k}.${gk}`);
} }
} }
} }
@ -76,22 +88,25 @@ export class SimpleActor extends Actor {
} }
} }
/* -------------------------------------------- */
/** /**
* Add items to the actor roll data object. Handles regular and shorthand * Add items to the actor roll data object. Handles regular and shorthand
* syntax, and calculates derived formula attributes on the items. * syntax, and calculates derived formula attributes on the items.
* @param {Object} data The actor's data object. * @param {Object} data The actor's data object.
* @param {string[]} itemAttributes
* @param {Boolean} shorthand Whether or not the shorthand syntax is used. * @param {Boolean} shorthand Whether or not the shorthand syntax is used.
*/ */
_applyItems(data, itemAttributes, shorthand) { _applyItems(data, itemAttributes, shorthand) {
// Map all items data using their slugified names // Map all items data using their slugified names
data.items = this.data.items.reduce((obj, i) => { data.items = this.items.reduce((obj, item) => {
let key = i.name.slugify({strict: true}); const key = item.name.slugify({strict: true});
let itemData = duplicate(i.data); const itemData = item.toObject(false).data;
// Add items to shorthand and note which ones are formula attributes. // Add items to shorthand and note which ones are formula attributes.
for ( let [k, v] of Object.entries(itemData.attributes) ) { for ( let [k, v] of Object.entries(itemData.attributes) ) {
// When building the attribute list, prepend the item name for later use. // When building the attribute list, prepend the item name for later use.
if ( v.dtype == "Formula" ) itemAttributes.push(`${key}..${k}`); if ( v.dtype === "Formula" ) itemAttributes.push(`${key}..${k}`);
// Add shortened version of the attributes. // Add shortened version of the attributes.
if ( !!shorthand ) { if ( !!shorthand ) {
if ( !(k in itemData) ) { if ( !(k in itemData) ) {
@ -104,7 +119,7 @@ export class SimpleActor extends Actor {
if ( !itemData[k] ) itemData[k] = {}; if ( !itemData[k] ) itemData[k] = {};
for ( let [gk, gv] of Object.entries(v) ) { for ( let [gk, gv] of Object.entries(v) ) {
itemData[k][gk] = gv.value; itemData[k][gk] = gv.value;
if ( gv.dtype == "Formula" ) itemAttributes.push(`${key}..${k}.${gk}`); if ( gv.dtype === "Formula" ) itemAttributes.push(`${key}..${k}.${gk}`);
} }
} }
} }
@ -115,7 +130,7 @@ export class SimpleActor extends Actor {
if ( !itemData[k] ) itemData[k] = {}; if ( !itemData[k] ) itemData[k] = {};
for ( let [gk, gv] of Object.entries(v) ) { for ( let [gk, gv] of Object.entries(v) ) {
itemData[k][gk] = gv.value; itemData[k][gk] = gv.value;
if ( gv.dtype == "Formula" ) itemAttributes.push(`${key}..${k}.${gk}`); if ( gv.dtype === "Formula" ) itemAttributes.push(`${key}..${k}.${gk}`);
} }
} }
} }
@ -125,12 +140,13 @@ export class SimpleActor extends Actor {
if ( !!shorthand ) { if ( !!shorthand ) {
delete itemData.attributes; delete itemData.attributes;
} }
obj[key] = itemData; obj[key] = itemData;
return obj; return obj;
}, {}); }, {});
} }
/* -------------------------------------------- */
_applyItemsFormulaReplacements(data, itemAttributes, shorthand) { _applyItemsFormulaReplacements(data, itemAttributes, shorthand) {
for ( let k of itemAttributes ) { for ( let k of itemAttributes ) {
// Get the item name and separate the key. // Get the item name and separate the key.
@ -151,30 +167,32 @@ export class SimpleActor extends Actor {
if ( !!shorthand ) { if ( !!shorthand ) {
// Handle grouped attributes first. // Handle grouped attributes first.
if ( data.items[item][k][gk] ) { if ( data.items[item][k][gk] ) {
formula = data.items[item][k][gk]; formula = data.items[item][k][gk].replace('@item.', `@items.${item}.`);
data.items[item][k][gk] = EntitySheetHelper.replaceData(formula.replace('@item.', `@items.${item}.`), data, {missing: "0"}); data.items[item][k][gk] = Roll.replaceFormulaData(formula, data);
} }
// Handle non-grouped attributes. // Handle non-grouped attributes.
else if ( data.items[item][k] ) { else if ( data.items[item][k] ) {
formula = data.items[item][k]; formula = data.items[item][k].replace('@item.', `@items.${item}.`);
data.items[item][k] = EntitySheetHelper.replaceData(formula.replace('@item.', `@items.${item}.`), data, {missing: "0"}); data.items[item][k] = Roll.replaceFormulaData(formula, data);
} }
} }
else { else {
// Handle grouped attributes first. // Handle grouped attributes first.
if ( data.items[item]['attributes'][k][gk] ) { if ( data.items[item]['attributes'][k][gk] ) {
formula = data.items[item]['attributes'][k][gk]['value']; formula = data.items[item]['attributes'][k][gk]['value'].replace('@item.', `@items.${item}.attributes.`);
data.items[item]['attributes'][k][gk]['value'] = EntitySheetHelper.replaceData(formula.replace('@item.', `@items.${item}.attributes.`), data, {missing: "0"}); data.items[item]['attributes'][k][gk]['value'] = Roll.replaceFormulaData(formula, data);
} }
// Handle non-grouped attributes. // Handle non-grouped attributes.
else if ( data.items[item]['attributes'][k]['value'] ) { else if ( data.items[item]['attributes'][k]['value'] ) {
formula = data.items[item]['attributes'][k]['value']; formula = data.items[item]['attributes'][k]['value'].replace('@item.', `@items.${item}.attributes.`);
data.items[item]['attributes'][k]['value'] = EntitySheetHelper.replaceData(formula.replace('@item.', `@items.${item}.attributes.`), data, {missing: "0"}); data.items[item]['attributes'][k]['value'] = Roll.replaceFormulaData(formula, data);
} }
} }
} }
} }
/* -------------------------------------------- */
/** /**
* Apply replacements for derived formula attributes. * Apply replacements for derived formula attributes.
* @param {Object} data The actor's data object. * @param {Object} data The actor's data object.
@ -182,11 +200,9 @@ export class SimpleActor extends Actor {
* @param {Boolean} shorthand Whether or not the shorthand syntax is used. * @param {Boolean} shorthand Whether or not the shorthand syntax is used.
*/ */
_applyFormulaReplacements(data, formulaAttributes, shorthand) { _applyFormulaReplacements(data, formulaAttributes, shorthand) {
// Evaluate formula attributes after all other attributes have been handled, // Evaluate formula attributes after all other attributes have been handled, including items.
// including items.
for ( let k of formulaAttributes ) { for ( let k of formulaAttributes ) {
// Grouped attributes are included as `group.attr`, so we need to split // Grouped attributes are included as `group.attr`, so we need to split them into new keys.
// them into new keys.
let attr = null; let attr = null;
if ( k.includes('.') ) { if ( k.includes('.') ) {
let attrKey = k.split('.'); let attrKey = k.split('.');
@ -195,15 +211,11 @@ export class SimpleActor extends Actor {
} }
// Non-grouped attributes. // Non-grouped attributes.
if ( data.attributes[k]?.value ) { if ( data.attributes[k]?.value ) {
data.attributes[k].value = EntitySheetHelper.replaceData(data.attributes[k].value, data, {missing: "0"}); data.attributes[k].value = Roll.replaceFormulaData(data.attributes[k].value, data);
// TODO: Replace with:
// data.attributes[k].value = Roll.replaceFormulaData(data.attributes[k].value, data, {missing: "0"});
} }
// Grouped attributes. // Grouped attributes.
else { else if ( attr ) {
if ( attr ) { data.attributes[k][attr].value = Roll.replaceFormulaData(data.attributes[k][attr].value, data);
data.attributes[k][attr].value = EntitySheetHelper.replaceData(data.attributes[k][attr].value, data, {missing: "0"});
}
} }
// Duplicate values to shorthand. // Duplicate values to shorthand.

View file

@ -3,7 +3,6 @@ import { ATTRIBUTE_TYPES } from "./constants.js";
export class EntitySheetHelper { export class EntitySheetHelper {
static getAttributeData(data) { static getAttributeData(data) {
data.dtypes = ATTRIBUTE_TYPES;
// Determine attribute type. // Determine attribute type.
for ( let attr of Object.values(data.data.attributes) ) { for ( let attr of Object.values(data.data.attributes) ) {
@ -61,7 +60,7 @@ export class EntitySheetHelper {
// Add label fallback. // Add label fallback.
if ( !gv.label ) gv.label = gk; if ( !gv.label ) gv.label = gk;
// Add formula bool. // Add formula bool.
if ( gv.dtype == "Formula" ) { if ( gv.dtype === "Formula" ) {
gv.isFormula = true; gv.isFormula = true;
} }
else { else {
@ -75,7 +74,7 @@ export class EntitySheetHelper {
// Add label fallback. // Add label fallback.
if ( !v.label ) v.label = k; if ( !v.label ) v.label = k;
// Add formula bool. // Add formula bool.
if ( v.dtype == "Formula" ) { if ( v.dtype === "Formula" ) {
v.isFormula = true; v.isFormula = true;
} }
else { else {
@ -94,7 +93,7 @@ export class EntitySheetHelper {
// Closing the form/sheet will also trigger a submit, so only evaluate if this is an event. // Closing the form/sheet will also trigger a submit, so only evaluate if this is an event.
if ( event.currentTarget ) { if ( event.currentTarget ) {
// Exit early if this isn't a named attribute. // Exit early if this isn't a named attribute.
if ( event.currentTarget.tagName.toLowerCase() == 'input' && !event.currentTarget.hasAttribute('name')) { if ( (event.currentTarget.tagName.toLowerCase() === 'input') && !event.currentTarget.hasAttribute('name')) {
return false; return false;
} }
@ -108,7 +107,7 @@ export class EntitySheetHelper {
// Prevent attributes that already exist as groups. // Prevent attributes that already exist as groups.
let groups = document.querySelectorAll('.group-key'); let groups = document.querySelectorAll('.group-key');
for ( let i = 0; i < groups.length; i++ ) { for ( let i = 0; i < groups.length; i++ ) {
if (groups[i].value == val) { if (groups[i].value === val) {
ui.notifications.error(game.i18n.localize("SIMPLE.NotifyAttrDuplicate") + ` (${val})`); ui.notifications.error(game.i18n.localize("SIMPLE.NotifyAttrDuplicate") + ` (${val})`);
el.value = oldVal; el.value = oldVal;
attrError = true; attrError = true;
@ -132,24 +131,21 @@ export class EntitySheetHelper {
/** /**
* Listen for click events on an attribute control to modify the composition of attributes in the sheet * Listen for click events on an attribute control to modify the composition of attributes in the sheet
* @param {MouseEvent} event The originating left click event * @param {MouseEvent} event The originating left click event
* @private
*/ */
static async onClickAttributeControl(event) { static async onClickAttributeControl(event) {
event.preventDefault(); event.preventDefault();
const a = event.currentTarget; const a = event.currentTarget;
const action = a.dataset.action; const action = a.dataset.action;
// Perform create and delete actions.
switch ( action ) { switch ( action ) {
case "create": case "create":
EntitySheetHelper.createAttribute(event, this); return EntitySheetHelper.createAttribute(event, this);
break;
case "delete": case "delete":
EntitySheetHelper.deleteAttribute(event, this); return EntitySheetHelper.deleteAttribute(event, this);
break;
} }
} }
/* -------------------------------------------- */
/** /**
* Listen for click events and modify attribute groups. * Listen for click events and modify attribute groups.
* @param {MouseEvent} event The originating left click event * @param {MouseEvent} event The originating left click event
@ -158,14 +154,11 @@ export class EntitySheetHelper {
event.preventDefault(); event.preventDefault();
const a = event.currentTarget; const a = event.currentTarget;
const action = a.dataset.action; const action = a.dataset.action;
switch ( action ) { switch ( action ) {
case "create-group": case "create-group":
EntitySheetHelper.createAttributeGroup(event, this); return EntitySheetHelper.createAttributeGroup(event, this);
break;
case "delete-group": case "delete-group":
EntitySheetHelper.deleteAttributeGroup(event, this); return EntitySheetHelper.deleteAttributeGroup(event, this);
break;
} }
} }
@ -181,24 +174,24 @@ export class EntitySheetHelper {
const label = button.closest(".attribute").querySelector(".attribute-label")?.value; const label = button.closest(".attribute").querySelector(".attribute-label")?.value;
const chatLabel = label ?? button.parentElement.querySelector(".attribute-key").value; const chatLabel = label ?? button.parentElement.querySelector(".attribute-key").value;
const shorthand = game.settings.get("worldbuilding", "macroShorthand"); const shorthand = game.settings.get("worldbuilding", "macroShorthand");
// Use the actor for rollData so that formulas are always in reference to the parent actor. // Use the actor for rollData so that formulas are always in reference to the parent actor.
const rollData = this.actor.getRollData(); const rollData = this.actor.getRollData();
let formula = button.closest(".attribute").querySelector(".attribute-value")?.value; let formula = button.closest(".attribute").querySelector(".attribute-value")?.value;
// If there's a formula, attempt to roll it. // If there's a formula, attempt to roll it.
if ( formula ) { if ( formula ) {
// Get the machine safe version of the item name.
let replacement = null; let replacement = null;
if ( formula.includes('@item.') && this.item ) { if ( formula.includes('@item.') && this.item ) {
let itemName = this.item.name.slugify({strict: true}); let itemName = this.item.name.slugify({strict: true}); // Get the machine safe version of the item name.
replacement = !!shorthand ? `@items.${itemName}.` : `@items.${itemName}.attributes.`; replacement = !!shorthand ? `@items.${itemName}.` : `@items.${itemName}.attributes.`;
formula = formula.replace('@item.', replacement); formula = formula.replace('@item.', replacement);
} }
formula = EntitySheetHelper.replaceData(formula, rollData, {missing: null});
// Replace `@item` shorthand with the item name and make the roll. // Create the roll and the corresponding message
let r = new Roll(formula, rollData); let r = new Roll(formula, rollData);
r.roll().toMessage({ return r.toMessage({
user: game.user._id, user: game.user.id,
speaker: ChatMessage.getSpeaker({ actor: this.actor }), speaker: ChatMessage.getSpeaker({ actor: this.actor }),
flavor: `${chatLabel}` flavor: `${chatLabel}`
}); });
@ -218,7 +211,7 @@ export class EntitySheetHelper {
*/ */
static getAttributeHtml(items, index, group = false) { static getAttributeHtml(items, index, group = false) {
// Initialize the HTML. // Initialize the HTML.
let result = '<div>'; let result = '<div style="display: none;">';
// Iterate over the supplied keys and build their inputs (including whether or not they need a group key). // Iterate over the supplied keys and build their inputs (including whether or not they need a group key).
for (let [key, item] of Object.entries(items)) { for (let [key, item] of Object.entries(items)) {
result = result + `<input type="${item.type}" name="data.attributes${group ? '.' + group : '' }.attr${index}.${key}" value="${item.value}"/>`; result = result + `<input type="${item.type}" name="data.attributes${group ? '.' + group : '' }.attr${index}.${key}" value="${item.value}"/>`;
@ -231,12 +224,13 @@ export class EntitySheetHelper {
/** /**
* Validate whether or not a group name can be used. * Validate whether or not a group name can be used.
* @param {string} groupName Groupname to validate * @param {string} groupName The candidate group name to validate
* @param {Document} document The Actor or Item instance within which the group is being defined
* @returns {boolean} * @returns {boolean}
*/ */
static validateGroup(groupName, entity) { static validateGroup(groupName, document) {
let groups = Object.keys(entity.object.data.data.groups); let groups = Object.keys(document.data.data.groups || {});
let attributes = Object.keys(entity.object.data.data.attributes).filter(a => !groups.includes(a)); let attributes = Object.keys(document.data.data.attributes).filter(a => !groups.includes(a));
// Check for duplicate group keys. // Check for duplicate group keys.
if ( groups.includes(groupName) ) { if ( groups.includes(groupName) ) {
@ -255,7 +249,6 @@ export class EntitySheetHelper {
ui.notifications.error(game.i18n.localize("SIMPLE.NotifyGroupAlphanumeric")); ui.notifications.error(game.i18n.localize("SIMPLE.NotifyGroupAlphanumeric"));
return false; return false;
} }
return true; return true;
} }
@ -283,7 +276,7 @@ export class EntitySheetHelper {
while ( objKeys.includes(newValue) ) { while ( objKeys.includes(newValue) ) {
++nk; ++nk;
newValue = `attr${nk}`; newValue = `attr${nk}`;
}; }
// Build options for construction HTML inputs. // Build options for construction HTML inputs.
let htmlItems = { let htmlItems = {
@ -364,7 +357,7 @@ export class EntitySheetHelper {
const form = app.form; const form = app.form;
let newValue = $(a).siblings('.group-prefix').val(); let newValue = $(a).siblings('.group-prefix').val();
// Verify the new group key is valid, and use it to create the group. // Verify the new group key is valid, and use it to create the group.
if ( newValue.length > 0 && EntitySheetHelper.validateGroup(newValue, app) ) { if ( newValue.length > 0 && EntitySheetHelper.validateGroup(newValue, app.object) ) {
let newKey = document.createElement("div"); let newKey = document.createElement("div");
newKey.innerHTML = `<input type="text" name="data.groups.${newValue}.key" value="${newValue}"/>`; newKey.innerHTML = `<input type="text" name="data.groups.${newValue}.key" value="${newValue}"/>`;
// Append the form element and submit the form. // Append the form element and submit the form.
@ -374,6 +367,8 @@ export class EntitySheetHelper {
} }
} }
/* -------------------------------------------- */
/** /**
* Delete an attribute group. * Delete an attribute group.
* @param {MouseEvent} event The originating left click event * @param {MouseEvent} event The originating left click event
@ -410,15 +405,15 @@ export class EntitySheetHelper {
/** /**
* Update attributes when updating an actor object. * Update attributes when updating an actor object.
* * @param {object} formData The form data object to modify keys and values for.
* @param {Object} formData Form data object to modify keys and values for. * @param {Document} document The Actor or Item document within which attributes are being updated
* @returns {Object} updated formData object. * @returns {object} The updated formData object.
*/ */
static updateAttributes(formData, entity) { static updateAttributes(formData, document) {
let groupKeys = []; let groupKeys = [];
// Handle the free-form attributes list // Handle the free-form attributes list
const formAttrs = expandObject(formData).data.attributes || {}; const formAttrs = foundry.utils.expandObject(formData)?.data?.attributes || {};
const attributes = Object.values(formAttrs).reduce((obj, v) => { const attributes = Object.values(formAttrs).reduce((obj, v) => {
let attrs = []; let attrs = [];
let group = null; let group = null;
@ -453,14 +448,14 @@ export class EntitySheetHelper {
}, {}); }, {});
// Remove attributes which are no longer used // Remove attributes which are no longer used
for ( let k of Object.keys(entity.object.data.data.attributes) ) { for ( let k of Object.keys(document.data.data.attributes) ) {
if ( !attributes.hasOwnProperty(k) ) attributes[`-=${k}`] = null; if ( !attributes.hasOwnProperty(k) ) attributes[`-=${k}`] = null;
} }
// Remove grouped attributes which are no longer used. // Remove grouped attributes which are no longer used.
for ( let group of groupKeys) { for ( let group of groupKeys) {
if ( entity.object.data.data.attributes[group] ) { if ( document.data.data.attributes[group] ) {
for ( let k of Object.keys(entity.object.data.data.attributes[group]) ) { for ( let k of Object.keys(document.data.data.attributes[group]) ) {
if ( !attributes[group].hasOwnProperty(k) ) attributes[group][`-=${k}`] = null; if ( !attributes[group].hasOwnProperty(k) ) attributes[group][`-=${k}`] = null;
} }
} }
@ -470,18 +465,20 @@ export class EntitySheetHelper {
formData = Object.entries(formData).filter(e => !e[0].startsWith("data.attributes")).reduce((obj, e) => { formData = Object.entries(formData).filter(e => !e[0].startsWith("data.attributes")).reduce((obj, e) => {
obj[e[0]] = e[1]; obj[e[0]] = e[1];
return obj; return obj;
}, {_id: entity.object._id, "data.attributes": attributes}); }, {_id: document.id, "data.attributes": attributes});
return formData; return formData;
} }
/* -------------------------------------------- */
/** /**
* Update attribute groups when updating an actor object. * Update attribute groups when updating an actor object.
* * @param {object} formData The form data object to modify keys and values for.
* @param {Object} formData Form data object to modify keys and values for. * @param {Document} document The Actor or Item document within which attributes are being updated
* @returns {Object} updated formData object. * @returns {object} The updated formData object.
*/ */
static updateGroups(formData, entity) { static updateGroups(formData, document) {
// Handle the free-form groups list // Handle the free-form groups list
const formGroups = expandObject(formData).data.groups || {}; const formGroups = expandObject(formData).data.groups || {};
const groups = Object.values(formGroups).reduce((obj, v) => { const groups = Object.values(formGroups).reduce((obj, v) => {
@ -498,7 +495,7 @@ export class EntitySheetHelper {
}, {}); }, {});
// Remove groups which are no longer used // Remove groups which are no longer used
for ( let k of Object.keys(entity.object.data.data.groups) ) { for ( let k of Object.keys(document.data.data.groups) ) {
if ( !groups.hasOwnProperty(k) ) groups[`-=${k}`] = null; if ( !groups.hasOwnProperty(k) ) groups[`-=${k}`] = null;
} }
@ -506,42 +503,71 @@ export class EntitySheetHelper {
formData = Object.entries(formData).filter(e => !e[0].startsWith("data.groups")).reduce((obj, e) => { formData = Object.entries(formData).filter(e => !e[0].startsWith("data.groups")).reduce((obj, e) => {
obj[e[0]] = e[1]; obj[e[0]] = e[1];
return obj; return obj;
}, {_id: entity.object._id, "data.groups": groups}); }, {_id: document.id, "data.groups": groups});
return formData; return formData;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
/** /**
* Replace referenced data attributes in the roll formula with the syntax `@attr` with the corresponding key from * @see ClientDocumentMixin.createDialog
* the provided `data` object. This is a temporary helper function that will be replaced with Roll.replaceFormulaData()
* in Foundry 0.7.1.
*
* @param {String} formula The original formula within which to replace.
* @param {Object} data Data object to use for value replacements.
* @param {Object} missing Value to use as missing replacements, such as {missing: "0"}.
* @return {String} The formula with attributes replaced with values.
*/ */
static replaceData(formula, data, {missing=null,depth=1}={}) { static async createDialog(data={}, options={}) {
// Exit early if the formula is invalid.
if ( typeof formula != "string" || depth < 1) {
return 0;
}
// Replace attributes with their numeric equivalents.
let dataRgx = new RegExp(/@([a-z.0-9_\-]+)/gi);
let rollFormula = formula.replace(dataRgx, (match, term) => {
let value = getProperty(data, term);
// If there was a value returned, trim and return it.
if ( value ) {
return String(value).trim();
}
// Otherwise, return either the missing replacement value, or the original @attr string for later replacement.
else {
return missing != null ? missing : `@${term}`;
}
});
return rollFormula;
}
// Collect data
const documentName = this.metadata.name;
const folders = game.folders.filter(f => (f.data.type === documentName) && f.displayed);
const label = game.i18n.localize(this.metadata.label);
const title = game.i18n.format("ENTITY.Create", {entity: label});
// Identify the template Actor types
const collection = game.collections.get(this.documentName);
const templates = collection.filter(a => a.getFlag("worldbuilding", "isTemplate"));
const defaultType = this.metadata.types[0];
const types = {
[defaultType]: game.i18n.localize("SIMPLE.NoTemplate")
}
for ( let a of templates ) {
types[a.id] = a.name;
}
// Render the entity creation form
const html = await renderTemplate(`templates/sidebar/entity-create.html`, {
name: data.name || game.i18n.format("ENTITY.New", {entity: label}),
folder: data.folder,
folders: folders,
hasFolders: folders.length > 1,
type: data.type || templates[0]?.id || "",
types: types,
hasTypes: true
});
// Render the confirmation dialog window
return Dialog.prompt({
title: title,
content: html,
label: title,
callback: html => {
// Get the form data
const form = html[0].querySelector("form");
const fd = new FormDataExtended(form);
let createData = fd.toObject();
// Merge with template data
const template = collection.get(form.type.value);
if ( template ) {
createData = foundry.utils.mergeObject(template.toObject(), createData);
createData.type = template.data.type;
delete createData.flags.worldbuilding.isTemplate;
}
// Merge provided override data
createData = foundry.utils.mergeObject(createData, data);
return this.create(createData, {renderSheet: true});
},
rejectClose: false,
options: options
});
}
} }

View file

@ -1,4 +1,5 @@
import { EntitySheetHelper } from "./helper.js"; import { EntitySheetHelper } from "./helper.js";
import {ATTRIBUTE_TYPES} from "./constants.js";
/** /**
* Extend the basic ItemSheet with some very simple modifications * Extend the basic ItemSheet with some very simple modifications
@ -6,9 +7,9 @@ import { EntitySheetHelper } from "./helper.js";
*/ */
export class SimpleItemSheet extends ItemSheet { export class SimpleItemSheet extends ItemSheet {
/** @override */ /** @inheritdoc */
static get defaultOptions() { static get defaultOptions() {
return mergeObject(super.defaultOptions, { return foundry.utils.mergeObject(super.defaultOptions, {
classes: ["worldbuilding", "sheet", "item"], classes: ["worldbuilding", "sheet", "item"],
template: "systems/worldbuilding/templates/item-sheet.html", template: "systems/worldbuilding/templates/item-sheet.html",
width: 520, width: 520,
@ -20,26 +21,30 @@ export class SimpleItemSheet extends ItemSheet {
/* -------------------------------------------- */ /* -------------------------------------------- */
/** @override */ /** @inheritdoc */
getData() { getData() {
const data = super.getData(); const context = super.getData();
EntitySheetHelper.getAttributeData(data); EntitySheetHelper.getAttributeData(context.data);
return data; context.systemData = context.data.data;
context.dtypes = ATTRIBUTE_TYPES;
return context;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
/** @override */ /** @inheritdoc */
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
// Everything below here is only needed if the sheet is editable // Everything below here is only needed if the sheet is editable
if (!this.options.editable) return; if ( !this.isEditable ) return;
// Rollable attributes // Attribute Management
html.find(".attributes").on("click", ".attribute-control", EntitySheetHelper.onClickAttributeControl.bind(this));
html.find(".groups").on("click", ".group-control", EntitySheetHelper.onClickAttributeGroupControl.bind(this));
html.find(".attributes").on("click", "a.attribute-roll", EntitySheetHelper.onAttributeRoll.bind(this)); html.find(".attributes").on("click", "a.attribute-roll", EntitySheetHelper.onAttributeRoll.bind(this));
// Add draggable for macros. // Add draggable for Macro creation
html.find(".attributes a.attribute-roll").each((i, a) => { html.find(".attributes a.attribute-roll").each((i, a) => {
a.setAttribute("draggable", true); a.setAttribute("draggable", true);
a.addEventListener("dragstart", ev => { a.addEventListener("dragstart", ev => {
@ -47,24 +52,15 @@ export class SimpleItemSheet extends ItemSheet {
ev.dataTransfer.setData('text/plain', JSON.stringify(dragData)); ev.dataTransfer.setData('text/plain', JSON.stringify(dragData));
}, false); }, false);
}); });
// Add or Remove Attribute
html.find(".attributes").on("click", ".attribute-control", EntitySheetHelper.onClickAttributeControl.bind(this));
// Add attribute groups.
html.find(".groups").on("click", ".group-control", EntitySheetHelper.onClickAttributeGroupControl.bind(this));
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
/** @override */ /** @override */
_updateObject(event, formData) { _getSubmitData(updateData) {
let formData = super._getSubmitData(updateData);
// Handle attribute and group updates. formData = EntitySheetHelper.updateAttributes(formData, this.object);
formData = EntitySheetHelper.updateAttributes(formData, this); formData = EntitySheetHelper.updateGroups(formData, this.object);
formData = EntitySheetHelper.updateGroups(formData, this); return formData;
// Update the Actor with the new form values.
return this.object.update(formData);
} }
} }

22
module/item.js Normal file
View file

@ -0,0 +1,22 @@
import {EntitySheetHelper} from "./helper.js";
/**
* Extend the base Item document to support attributes and groups with a custom template creation dialog.
* @extends {Item}
*/
export class SimpleItem extends Item {
/** @inheritdoc */
prepareDerivedData() {
super.prepareDerivedData();
this.data.data.groups = this.data.data.groups || {};
this.data.data.attributes = this.data.data.attributes || {};
}
/* -------------------------------------------- */
/** @override */
static async createDialog(data={}, options={}) {
return EntitySheetHelper.createDialog.call(this, data, options);
}
}

View file

@ -5,6 +5,7 @@
// Import Modules // Import Modules
import { SimpleActor } from "./actor.js"; import { SimpleActor } from "./actor.js";
import { SimpleItem } from "./item.js";
import { SimpleItemSheet } from "./item-sheet.js"; import { SimpleItemSheet } from "./item-sheet.js";
import { SimpleActorSheet } from "./actor-sheet.js"; import { SimpleActorSheet } from "./actor-sheet.js";
import { preloadHandlebarsTemplates } from "./templates.js"; import { preloadHandlebarsTemplates } from "./templates.js";
@ -35,7 +36,8 @@ Hooks.once("init", async function() {
}; };
// Define custom Entity classes // Define custom Entity classes
CONFIG.Actor.entityClass = SimpleActor; CONFIG.Actor.documentClass = SimpleActor;
CONFIG.Item.documentClass = SimpleItem;
// Register sheet application classes // Register sheet application classes
Actors.unregisterSheet("core", ActorSheet); Actors.unregisterSheet("core", ActorSheet);
@ -74,21 +76,12 @@ Hooks.once("init", async function() {
* @param {boolean} notify - Whether or not to post nofications. * @param {boolean} notify - Whether or not to post nofications.
*/ */
function _simpleUpdateInit(formula, notify = false) { function _simpleUpdateInit(formula, notify = false) {
// If the formula is valid, use it. const isValid = Roll.validate(formula);
try { if ( !isValid ) {
new Roll(formula).roll(); if ( notify ) ui.notifications.error(`${game.i18n.localize("SIMPLE.NotifyInitFormulaInvalid")}: ${formula}`);
CONFIG.Combat.initiative.formula = formula; return;
if (notify) {
ui.notifications.notify(game.i18n.localize("SIMPLE.NotifyInitFormulaUpdated") + ` ${formula}`);
}
}
// Otherwise, fall back to a d20.
catch (error) {
CONFIG.Combat.initiative.formula = "1d20";
if (notify) {
ui.notifications.error(game.i18n.localize("SIMPLE.NotifyInitFormulaInvalid") + ` ${formula}`);
}
} }
CONFIG.Combat.initiative.formula = formula;
} }
/** /**
@ -98,8 +91,8 @@ Hooks.once("init", async function() {
return value.slugify({strict: true}); return value.slugify({strict: true});
}); });
// Preload template partials. // Preload template partials
preloadHandlebarsTemplates(); await preloadHandlebarsTemplates();
}); });
/** /**
@ -172,68 +165,3 @@ Hooks.on("getItemDirectoryEntryContext", (html, options) => {
} }
}); });
}); });
async function _onCreateEntity(event) {
event.preventDefault();
event.stopPropagation();
return _simpleDirectoryTemplates(this, event);
}
ActorDirectory.prototype._onCreateEntity = _onCreateEntity; // For 0.7.x+
ItemDirectory.prototype._onCreateEntity = _onCreateEntity;
ActorDirectory.prototype._onCreate = _onCreateEntity; // TODO: for 0.6.6
ItemDirectory.prototype._onCreate = _onCreateEntity;
/**
* Display the entity template dialog.
*
* Helper function to display a dialog if there are multiple template types defined for the entity type.
* TODO: Refactor in 0.7.x to play more nicely with the Entity.createDialog method
*1
* @param {EntityCollection} entityType - The sidebar tab
* @param {MouseEvent} event - Triggering event
*/
async function _simpleDirectoryTemplates(collection, event) {
// Retrieve the collection and find any available templates
const entityCollection = collection.tabName === "actors" ? game.actors : game.items;
const cls = collection.tabName === "actors" ? Actor : Item;
let templates = entityCollection.filter(a => a.getFlag("worldbuilding", "isTemplate"));
let ent = game.i18n.localize(cls.config.label);
// Setup default creation data
let type = collection.tabName === "actors" ? 'character' : 'item';
let createData = {
name: `${game.i18n.localize("SIMPLE.New")} ${ent}`,
type: type,
folder: event.currentTarget.dataset.folder
};
if ( !templates.length ) return cls.create(createData, {renderSheet: true});
// Build an array of types for the form, including an empty default.
let types = [{
value: null,
label: game.i18n.localize("SIMPLE.NoTemplate")
}].concat(templates.map(a => { return { value: a.id, label: a.name } }));
// Render the confirmation dialog window
const templateData = {upper: ent, lower: ent.toLowerCase(), types: types};
const dlg = await renderTemplate(`systems/worldbuilding/templates/sidebar/entity-create.html`, templateData);
return Dialog.confirm({
title: `${game.i18n.localize("SIMPLE.Create")} ${createData.name}`,
content: dlg,
yes: html => {
const form = html[0].querySelector("form");
const template = entityCollection.get(form.type.value);
if ( template ) {
createData = mergeObject(template.data, createData, {inplace: false});
createData.type = template.data.type;
delete createData.flags.worldbuilding.isTemplate;
}
createData.name = form.name.value;
return cls.create(createData, {renderSheet: true});
},
no: () => {},
defaultYes: false
});
}

View file

@ -2,10 +2,9 @@
"name": "worldbuilding", "name": "worldbuilding",
"title": "Simple World-Building", "title": "Simple World-Building",
"description": "A minimalist game system which provides configurable Actor and Item templates to support free-form system agnostic game-play.", "description": "A minimalist game system which provides configurable Actor and Item templates to support free-form system agnostic game-play.",
"version": 0.40, "version": "0.5.0",
"minimumCoreVersion": "0.6.6", "minimumCoreVersion": "0.8.4",
"compatibleCoreVersion": "0.7.3", "compatibleCoreVersion": "0.8.6",
"templateVersion": 2,
"author": "Atropos", "author": "Atropos",
"esmodules": ["module/simple.js"], "esmodules": ["module/simple.js"],
"styles": ["styles/simple.css"], "styles": ["styles/simple.css"],
@ -22,7 +21,7 @@
"primaryTokenAttribute": "health", "primaryTokenAttribute": "health",
"secondaryTokenAttribute": "power", "secondaryTokenAttribute": "power",
"url": "https://gitlab.com/foundrynet/worldbuilding/", "url": "https://gitlab.com/foundrynet/worldbuilding/",
"manifest": "https://gitlab.com/foundrynet/worldbuilding/raw/master/system.json", "manifest": "https://gitlab.com/foundrynet/worldbuilding/raw/0.5.x/system.json",
"download": "https://gitlab.com/foundrynet/worldbuilding/-/archive/release-040/worldbuilding-release-040.zip", "download": "https://gitlab.com/foundrynet/worldbuilding/-/archive/release-050/worldbuilding-release-050.zip",
"license": "LICENSE.txt" "license": "LICENSE.txt"
} }

View file

@ -2,18 +2,20 @@
{{!-- Sheet Header --}} {{!-- Sheet Header --}}
<header class="sheet-header"> <header class="sheet-header">
<img class="profile-img" src="{{actor.img}}" data-edit="img" title="{{actor.name}}" height="100" width="100" /> <img class="profile-img" src="{{data.img}}" data-edit="img" title="{{data.name}}" height="100" width="100" />
<div class="header-fields"> <div class="header-fields">
<h1 class="charname"><input name="name" type="text" value="{{actor.name}}" placeholder="Name" /></h1> <h1 class="charname">
<input name="name" type="text" value="{{data.name}}" placeholder="Name" />
</h1>
<div class="resource"> <div class="resource">
<input type="text" name="data.health.value" value="{{data.health.value}}" data-dtype="Number" /> <input type="number" name="data.health.value" value="{{systemData.health.value}}"/>
<span> / </span> <span> / </span>
<input type="text" name="data.health.max" value="{{data.health.max}}" data-dtype="Number" /> <input type="number" name="data.health.max" value="{{systemData.health.max}}"/>
</div> </div>
<div class="resource"> <div class="resource">
<input type="text" name="data.power.value" value="{{data.power.value}}" data-dtype="Number" /> <input type="number" name="data.power.value" value="{{systemData.power.value}}"/>
<span> / </span> <span> / </span>
<input type="text" name="data.power.max" value="{{data.power.max}}" data-dtype="Number" /> <input type="number" name="data.power.max" value="{{systemData.power.max}}"/>
</div> </div>
</div> </div>
</header> </header>
@ -29,14 +31,14 @@
<section class="sheet-body"> <section class="sheet-body">
{{!-- Biography Tab --}} {{!-- Biography Tab --}}
<div class="tab biography" data-group="primary" data-tab="description"> <div class="tab description" data-group="primary" data-tab="description">
{{editor content=data.biography target="data.biography" button=true owner=owner editable=editable}} {{editor content=systemData.biography target="data.biography" button=true owner=owner editable=editable rollData=rollData}}
</div> </div>
{{!-- Owned Items Tab --}} {{!-- Owned Items Tab --}}
<div class="tab items" data-group="primary" data-tab="items"> <div class="tab items" data-group="primary" data-tab="items">
<ol class="item-list"> <ol class="item-list">
{{#each actor.items as |item id|}} {{#each data.items as |item id|}}
<li class="item flexrow" data-item-id="{{item._id}}"> <li class="item flexrow" data-item-id="{{item._id}}">
<img src="{{item.img}}" title="{{item.name}}" width="24" height="24" /> <img src="{{item.img}}" title="{{item.name}}" width="24" height="24" />
<h4 class="item-name">{{item.name}}</h4> <h4 class="item-name">{{item.name}}</h4>
@ -75,12 +77,15 @@
{{/each}} {{/each}}
</div> </div>
<div class="item-controls"> <div class="item-controls">
<a class="item-control item-edit" title="Edit Item"><i class="fas fa-edit"></i></a> <a class="item-control" title="{{ localize "SIMPLE.ItemEdit" }}" data-action="edit"><i class="fas fa-edit"></i></a>
<a class="item-control item-delete" title="Delete Item"><i class="fas fa-trash"></i></a> <a class="item-control" title="{{ localize "SIMPLE.ItemDelete" }}" data-action="delete"><i class="fas fa-trash"></i></a>
</div> </div>
</li> </li>
{{/each}} {{/each}}
</ol> </ol>
<p>
<a class="item-control" title="{{ localize "SIMPLE.ItemCreate" }}" data-action="create"><i class="fas fa-plus"></i> {{ localize "SIMPLE.ItemCreate" }}</a>
</p>
</div> </div>
{{!-- Attributes Tab --}} {{!-- Attributes Tab --}}
@ -94,14 +99,14 @@
</header> </header>
{{!-- Render the attribute list partial. --}} {{!-- Render the attribute list partial. --}}
{{> "systems/worldbuilding/templates/parts/sheet-attributes.html" attributes=data.ungroupedAttributes dtypes=dtypes}} {{> "systems/worldbuilding/templates/parts/sheet-attributes.html" attributes=systemData.ungroupedAttributes dtypes=dtypes}}
{{!-- Render the grouped attributes partial and control. --}} {{!-- Render the grouped attributes partial and control. --}}
<div class="groups"> <div class="groups">
{{> "systems/worldbuilding/templates/parts/sheet-groups.html" attributes=data.groupedAttributes groups=data.groups dtypes=dtypes}} {{> "systems/worldbuilding/templates/parts/sheet-groups.html" attributes=systemData.groupedAttributes groups=systemData.groups dtypes=dtypes}}
<div class="group-controls flexrow"> <div class="group-controls flexrow">
<input class="group-prefix" type="text" val=""/> <input class="group-prefix" type="text" value=""/>
<a class="button group-control" data-action="create-group"><i class="fas fa-plus"></i>Add Attribute Group</a> <a class="button group-control" data-action="create-group"><i class="fas fa-plus"></i>Add Attribute Group</a>
</div> </div>
</div> </div>

View file

@ -1,15 +1,17 @@
<form class="flexcol {{cssClass}}" autocomplete="off"> <form class="flexcol {{cssClass}}" autocomplete="off">
<header class="sheet-header"> <header class="sheet-header">
<img class="profile-img" src="{{item.img}}" data-edit="img" title="{{item.name}}" /> <img class="profile-img" src="{{data.img}}" data-edit="img" title="{{data.name}}" />
<div class="header-fields"> <div class="header-fields">
<h1 class="charname"><input name="name" type="text" value="{{item.name}}" placeholder="Name" /></h1> <h1 class="charname">
<input name="name" type="text" value="{{data.name}}" placeholder="Name" />
</h1>
<div class="resource"> <div class="resource">
<label>Quantity</label> <label>Quantity</label>
<input type="text" name="data.quantity" value="{{data.quantity}}" data-dtype="Number" /> <input type="number" name="data.quantity" value="{{systemData.quantity}}"/>
</div> </div>
<div class="resource"> <div class="resource">
<label>Weight</label> <label>Weight</label>
<input type="text" name="data.weight" value="{{data.weight}}" data-dtype="Number" /> <input type="number" name="data.weight" value="{{systemData.weight}}"/>
</div> </div>
</div> </div>
</header> </header>
@ -25,7 +27,7 @@
{{!-- Description Tab --}} {{!-- Description Tab --}}
<div class="tab" data-group="primary" data-tab="description"> <div class="tab" data-group="primary" data-tab="description">
{{editor content=data.description target="data.description" button=true owner=owner editable=editable}} {{editor content=systemData.description target="data.description" button=true owner=owner editable=editable rollData=rollData}}
</div> </div>
{{!-- Attributes Tab --}} {{!-- Attributes Tab --}}
@ -39,14 +41,13 @@
</header> </header>
{{!-- Render the attribute list partial. --}} {{!-- Render the attribute list partial. --}}
{{> "systems/worldbuilding/templates/parts/sheet-attributes.html" attributes=data.ungroupedAttributes dtypes=dtypes}} {{> "systems/worldbuilding/templates/parts/sheet-attributes.html" attributes=systemData.ungroupedAttributes dtypes=dtypes}}
{{!-- Render the grouped attributes partial and control. --}} {{!-- Render the grouped attributes partial and control. --}}
<div class="groups"> <div class="groups">
{{> "systems/worldbuilding/templates/parts/sheet-groups.html" attributes=data.groupedAttributes groups=data.groups dtypes=dtypes}} {{> "systems/worldbuilding/templates/parts/sheet-groups.html" attributes=systemData.groupedAttributes groups=systemData.groups dtypes=dtypes}}
<div class="group-controls flexrow"> <div class="group-controls flexrow">
<input class="group-prefix" type="text" val=""/> <input class="group-prefix" type="text" value=""/>
<a class="button group-control" data-action="create-group"><i class="fas fa-plus"></i>Add Attribute Group</a> <a class="button group-control" data-action="create-group"><i class="fas fa-plus"></i>Add Attribute Group</a>
</div> </div>
</div> </div>

View file

@ -1,15 +0,0 @@
<form id="entity-create" autocomplete="off" onsubmit="event.preventDefault();">
<div class="form-group">
<label>{{localize "Name"}}</label>
<input type="text" name="name" placeholder="{{localize 'ENTITY.CreateNew'}} {{upper}}"/>
</div>
<div class="form-group">
<label>{{localize "Type"}}</label>
<select name="type">
{{#each types}}
<option value="{{this.value}}">{{this.label}}</option>
{{/each}}
</select>
</div>
</form>