From e23893b6cad8b35e8e71aa90699e97b00ae58cfd Mon Sep 17 00:00:00 2001 From: Andrew Date: Tue, 23 Aug 2022 21:23:59 -0400 Subject: [PATCH] V10 compatibility with 0.7.0-alpha1 release --- module/actor-sheet.js | 10 ++- module/actor.js | 18 +++--- module/helper.js | 92 +++++++++++---------------- module/item-sheet.js | 12 ++-- module/item.js | 6 +- module/simple.js | 23 ++++--- module/token.js | 10 +-- system.json | 24 ++++--- templates/actor-sheet.html | 14 ++-- templates/item-sheet.html | 8 +-- templates/parts/sheet-attributes.html | 26 ++++---- templates/parts/sheet-groups.html | 8 +-- 12 files changed, 125 insertions(+), 126 deletions(-) diff --git a/module/actor-sheet.js b/module/actor-sheet.js index 5149792..392257a 100644 --- a/module/actor-sheet.js +++ b/module/actor-sheet.js @@ -23,12 +23,16 @@ export class SimpleActorSheet extends ActorSheet { /* -------------------------------------------- */ /** @inheritdoc */ - getData() { - const context = super.getData(); + async getData(options) { + const context = await super.getData(options); EntitySheetHelper.getAttributeData(context.data); context.shorthand = !!game.settings.get("worldbuilding", "macroShorthand"); - context.systemData = context.data.data; + context.systemData = context.data.system; context.dtypes = ATTRIBUTE_TYPES; + context.biographyHTML = await TextEditor.enrichHTML(context.systemData.biography, { + secrets: this.document.isOwner, + async: true + }); return context; } diff --git a/module/actor.js b/module/actor.js index 034b26a..ffc968f 100644 --- a/module/actor.js +++ b/module/actor.js @@ -9,9 +9,9 @@ export class SimpleActor extends Actor { /** @inheritdoc */ prepareDerivedData() { super.prepareDerivedData(); - this.data.data.groups = this.data.data.groups || {}; - this.data.data.attributes = this.data.data.attributes || {}; - EntitySheetHelper.clampResourceValues(this.data.data.attributes); + this.system.groups = this.system.groups || {}; + this.system.attributes = this.system.attributes || {}; + EntitySheetHelper.clampResourceValues(this.system.attributes); } /* -------------------------------------------- */ @@ -39,7 +39,7 @@ export class SimpleActor extends Actor { getRollData() { // Copy the actor's system data - const data = this.toObject(false).data; + const data = this.toObject(false); const shorthand = game.settings.get("worldbuilding", "macroShorthand"); const formulaAttributes = []; const itemAttributes = []; @@ -47,7 +47,7 @@ export class SimpleActor extends Actor { // Handle formula attributes when the short syntax is disabled. this._applyShorthand(data, formulaAttributes, shorthand); - // Map all items data using their slugified names + // Map all item data using their slugified names this._applyItems(data, itemAttributes, shorthand); // Evaluate formula replacements on items. @@ -111,10 +111,10 @@ export class SimpleActor extends Actor { // Map all items data using their slugified names data.items = this.items.reduce((obj, item) => { const key = item.name.slugify({strict: true}); - const itemData = item.toObject(false).data; + const itemData = item.toObject(false); // 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.system.attributes) ) { // When building the attribute list, prepend the item name for later use. if ( v.dtype === "Formula" ) itemAttributes.push(`${key}..${k}`); // Add shortened version of the attributes. @@ -252,11 +252,11 @@ export class SimpleActor extends Actor { /** @inheritdoc */ async modifyTokenAttribute(attribute, value, isDelta = false, isBar = true) { - const current = foundry.utils.getProperty(this.data.data, attribute); + const current = foundry.utils.getProperty(this.system, attribute); if ( !isBar || !isDelta || (current?.dtype !== "Resource") ) { return super.modifyTokenAttribute(attribute, value, isDelta, isBar); } - const updates = {[`data.${attribute}.value`]: Math.clamped(current.value + value, current.min, current.max)}; + const updates = {[`system.${attribute}.value`]: Math.clamped(current.value + value, current.min, current.max)}; const allowed = Hooks.call("modifyTokenAttribute", {attribute, value, isDelta, isBar}, updates); return allowed !== false ? this.update(updates) : this; } diff --git a/module/helper.js b/module/helper.js index dd04769..d18e126 100644 --- a/module/helper.js +++ b/module/helper.js @@ -1,11 +1,10 @@ -import { ATTRIBUTE_TYPES } from "./constants.js"; export class EntitySheetHelper { static getAttributeData(data) { // Determine attribute type. - for ( let attr of Object.values(data.data.attributes) ) { + for ( let attr of Object.values(data.system.attributes) ) { if ( attr.dtype ) { attr.isCheckbox = attr.dtype === "Boolean"; attr.isResource = attr.dtype === "Resource"; @@ -14,10 +13,10 @@ export class EntitySheetHelper { } // Initialize ungrouped attributes for later. - data.data.ungroupedAttributes = {}; + data.system.ungroupedAttributes = {}; // Build an array of sorted group keys. - const groups = data.data.groups || {}; + const groups = data.system.groups || {}; let groupKeys = Object.keys(groups).sort((a, b) => { let aSort = groups[a].label ?? a; let bSort = groups[b].label ?? b; @@ -26,10 +25,10 @@ export class EntitySheetHelper { // Iterate over the sorted groups to add their attributes. for ( let key of groupKeys ) { - let group = data.data.attributes[key] || {}; + let group = data.system.attributes[key] || {}; // Initialize the attributes container for this group. - if ( !data.data.groups[key]['attributes'] ) data.data.groups[key]['attributes'] = {}; + if ( !data.system.groups[key]['attributes'] ) data.system.groups[key]['attributes'] = {}; // Sort the attributes within the group, and then iterate over them. Object.keys(group).sort((a, b) => a.localeCompare(b)).forEach(attr => { @@ -39,20 +38,20 @@ export class EntitySheetHelper { group[attr]['isCheckbox'] = group[attr]['dtype'] === 'Boolean'; group[attr]['isResource'] = group[attr]['dtype'] === 'Resource'; group[attr]['isFormula'] = group[attr]['dtype'] === 'Formula'; - data.data.groups[key]['attributes'][attr] = group[attr]; + data.system.groups[key]['attributes'][attr] = group[attr]; }); } - // Sort the remaining attributes attributes. - Object.keys(data.data.attributes).filter(a => !groupKeys.includes(a)).sort((a, b) => a.localeCompare(b)).forEach(key => { - data.data.ungroupedAttributes[key] = data.data.attributes[key]; - }); + // Sort the remaining attributes. + const keys = Object.keys(data.system.attributes).filter(a => !groupKeys.includes(a)); + keys.sort((a, b) => a.localeCompare(b)); + for ( const key of keys ) data.system.ungroupedAttributes[key] = data.system.attributes[key]; // Modify attributes on items. if ( data.items ) { data.items.forEach(item => { // Iterate over attributes. - for ( let [k, v] of Object.entries(item.data.attributes) ) { + for ( let [k, v] of Object.entries(item.system.attributes) ) { // Grouped attributes. if ( !v.dtype ) { for ( let [gk, gv] of Object.entries(v) ) { @@ -212,9 +211,9 @@ export class EntitySheetHelper { static getAttributeHtml(items, index, group = false) { // Initialize the HTML. let result = '
'; - // 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 they need a group key). for (let [key, item] of Object.entries(items)) { - result = result + ``; + result = result + ``; } // Close the HTML and return. return result + '
'; @@ -229,8 +228,8 @@ export class EntitySheetHelper { * @returns {boolean} */ static validateGroup(groupName, document) { - let groups = Object.keys(document.data.data.groups || {}); - let attributes = Object.keys(document.data.data.attributes).filter(a => !groups.includes(a)); + let groups = Object.keys(document.system.groups || {}); + let attributes = Object.keys(document.system.attributes).filter(a => !groups.includes(a)); // Check for duplicate group keys. if ( groups.includes(groupName) ) { @@ -270,8 +269,8 @@ export class EntitySheetHelper { const a = event.currentTarget; const group = a.dataset.group; let dtype = a.dataset.dtype; - const attrs = app.object.data.data.attributes; - const groups = app.object.data.data.groups; + const attrs = app.object.system.attributes; + const groups = app.object.system.groups; const form = app.form; // Determine the new attribute key for ungrouped attributes. @@ -365,7 +364,7 @@ export class EntitySheetHelper { // Verify the new group key is valid, and use it to create the group. if ( newValue.length > 0 && EntitySheetHelper.validateGroup(newValue, app.object) ) { let newKey = document.createElement("div"); - newKey.innerHTML = ``; + newKey.innerHTML = ``; // Append the form element and submit the form. newKey = newKey.children[0]; form.appendChild(newKey); @@ -419,7 +418,7 @@ export class EntitySheetHelper { let groupKeys = []; // Handle the free-form attributes list - const formAttrs = foundry.utils.expandObject(formData)?.data?.attributes || {}; + const formAttrs = foundry.utils.expandObject(formData)?.system?.attributes || {}; const attributes = Object.values(formAttrs).reduce((obj, v) => { let attrs = []; let group = null; @@ -454,24 +453,24 @@ export class EntitySheetHelper { }, {}); // Remove attributes which are no longer used - for ( let k of Object.keys(document.data.data.attributes) ) { + for ( let k of Object.keys(document.system.attributes) ) { if ( !attributes.hasOwnProperty(k) ) attributes[`-=${k}`] = null; } // Remove grouped attributes which are no longer used. for ( let group of groupKeys) { - if ( document.data.data.attributes[group] ) { - for ( let k of Object.keys(document.data.data.attributes[group]) ) { + if ( document.system.attributes[group] ) { + for ( let k of Object.keys(document.system.attributes[group]) ) { if ( !attributes[group].hasOwnProperty(k) ) attributes[group][`-=${k}`] = null; } } } // Re-combine formData - formData = Object.entries(formData).filter(e => !e[0].startsWith("data.attributes")).reduce((obj, e) => { + formData = Object.entries(formData).filter(e => !e[0].startsWith("system.attributes")).reduce((obj, e) => { obj[e[0]] = e[1]; return obj; - }, {_id: document.id, "data.attributes": attributes}); + }, {_id: document.id, "system.attributes": attributes}); return formData; } @@ -485,40 +484,26 @@ export class EntitySheetHelper { * @returns {object} The updated formData object. */ static updateGroups(formData, document) { - // Handle the free-form groups list - const formGroups = expandObject(formData).data.groups || {}; - const documentGroups = Object.keys(document.data.data.groups || {}); - const groups = Object.values(formGroups).reduce((obj, v) => { - // If there are duplicate groups, collapse them. - if ( Array.isArray(v["key"]) ) { - v["key"] = v["key"][0]; - } - // Trim and clean up. - let k = v["key"].trim(); - // Validate groups. - let isValidGroup = true; - // Skip validation for existing/duplicate groups since they're collapsed above. - if ( !documentGroups.includes(k) ) { - isValidGroup = this.validateGroup(k, document); - } - // Delete the key and add the group to the reducer if valid. - delete v["key"]; - if (isValidGroup) obj[k] = v; + const formGroups = foundry.utils.expandObject(formData).system.groups || {}; + const documentGroups = Object.keys(document.system.groups || {}); + + // Identify valid groups submitted on the form + const groups = Object.entries(formGroups).reduce((obj, [k, v]) => { + const validGroup = documentGroups.includes(k) || this.validateGroup(k, document); + if ( validGroup ) obj[k] = v; return obj; }, {}); // Remove groups which are no longer used - if (groups) { - for ( let k of Object.keys(document.data.data.groups)) { - if ( !groups.hasOwnProperty(k) ) groups[`-=${k}`] = null; - } + for ( let k of Object.keys(document.system.groups)) { + if ( !groups.hasOwnProperty(k) ) groups[`-=${k}`] = null; } // Re-combine formData - formData = Object.entries(formData).filter(e => !e[0].startsWith("data.groups")).reduce((obj, e) => { + formData = Object.entries(formData).filter(e => !e[0].startsWith("system.groups")).reduce((obj, e) => { obj[e[0]] = e[1]; return obj; - }, {_id: document.id, "data.groups": groups}); + }, {_id: document.id, "system.groups": groups}); return formData; } @@ -531,7 +516,7 @@ export class EntitySheetHelper { // Collect data const documentName = this.metadata.name; - const folders = game.folders.filter(f => (f.data.type === documentName) && f.displayed); + const folders = game.folders.filter(f => (f.type === documentName) && f.displayed); const label = game.i18n.localize(this.metadata.label); const title = game.i18n.format("DOCUMENT.Create", {type: label}); @@ -547,8 +532,7 @@ export class EntitySheetHelper { } // Render the document creation form - const useEntity = game.worldbuilding.useEntity; - const template = `templates/sidebar/${useEntity ? "entity" : "document" }-create.html`; + const template = "templates/sidebar/document-create.html"; const html = await renderTemplate(template, { name: data.name || game.i18n.format("DOCUMENT.New", {type: label}), folder: data.folder, @@ -575,7 +559,7 @@ export class EntitySheetHelper { const template = collection.get(form.type.value); if ( template ) { createData = foundry.utils.mergeObject(template.toObject(), createData); - createData.type = template.data.type; + createData.type = template.type; delete createData.flags.worldbuilding.isTemplate; } diff --git a/module/item-sheet.js b/module/item-sheet.js index fbe20ad..82c7f31 100644 --- a/module/item-sheet.js +++ b/module/item-sheet.js @@ -22,18 +22,22 @@ export class SimpleItemSheet extends ItemSheet { /* -------------------------------------------- */ /** @inheritdoc */ - getData() { - const context = super.getData(); + async getData(options) { + const context = await super.getData(options); EntitySheetHelper.getAttributeData(context.data); - context.systemData = context.data.data; + context.systemData = context.data.system; context.dtypes = ATTRIBUTE_TYPES; + context.descriptionHTML = await TextEditor.enrichHTML(context.systemData.description, { + secrets: this.document.isOwner, + async: true + }); return context; } /* -------------------------------------------- */ /** @inheritdoc */ - activateListeners(html) { + activateListeners(html) { super.activateListeners(html); // Everything below here is only needed if the sheet is editable diff --git a/module/item.js b/module/item.js index 99fb5a0..dfe23e1 100644 --- a/module/item.js +++ b/module/item.js @@ -9,9 +9,9 @@ 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 || {}; - EntitySheetHelper.clampResourceValues(this.data.data.attributes); + this.system.groups = this.system.groups || {}; + this.system.attributes = this.system.attributes || {}; + EntitySheetHelper.clampResourceValues(this.system.attributes); } /* -------------------------------------------- */ diff --git a/module/simple.js b/module/simple.js index 6ffff4d..e839cba 100644 --- a/module/simple.js +++ b/module/simple.js @@ -33,8 +33,7 @@ Hooks.once("init", async function() { game.worldbuilding = { SimpleActor, - createWorldbuildingMacro, - useEntity: foundry.utils.isNewerVersion("9", game.version ?? game.data.version) + createWorldbuildingMacro }; // Define custom Document classes @@ -108,17 +107,17 @@ Hooks.on("hotbarDrop", (bar, data, slot) => createWorldbuildingMacro(data, slot) * Adds the actor template context menu. */ Hooks.on("getActorDirectoryEntryContext", (html, options) => { - const idAttr = game.worldbuilding.useEntity ? "entityId" : "documentId"; + // Define an actor as a template. options.push({ name: game.i18n.localize("SIMPLE.DefineTemplate"), icon: '', condition: li => { - const actor = game.actors.get(li.data(idAttr)); + const actor = game.actors.get(li.data("documentId")); return !actor.isTemplate; }, callback: li => { - const actor = game.actors.get(li.data(idAttr)); + const actor = game.actors.get(li.data("documentId")); actor.setFlag("worldbuilding", "isTemplate", true); } }); @@ -128,11 +127,11 @@ Hooks.on("getActorDirectoryEntryContext", (html, options) => { name: game.i18n.localize("SIMPLE.UnsetTemplate"), icon: '', condition: li => { - const actor = game.actors.get(li.data(idAttr)); + const actor = game.actors.get(li.data("documentId")); return actor.isTemplate; }, callback: li => { - const actor = game.actors.get(li.data(idAttr)); + const actor = game.actors.get(li.data("documentId")); actor.setFlag("worldbuilding", "isTemplate", false); } }); @@ -142,17 +141,17 @@ Hooks.on("getActorDirectoryEntryContext", (html, options) => { * Adds the item template context menu. */ Hooks.on("getItemDirectoryEntryContext", (html, options) => { - const idAttr = game.worldbuilding.useEntity ? "entityId" : "documentId"; + // Define an item as a template. options.push({ name: game.i18n.localize("SIMPLE.DefineTemplate"), icon: '', condition: li => { - const item = game.items.get(li.data(idAttr)); + const item = game.items.get(li.data("documentId")); return !item.isTemplate; }, callback: li => { - const item = game.items.get(li.data(idAttr)); + const item = game.items.get(li.data("documentId")); item.setFlag("worldbuilding", "isTemplate", true); } }); @@ -162,11 +161,11 @@ Hooks.on("getItemDirectoryEntryContext", (html, options) => { name: game.i18n.localize("SIMPLE.UnsetTemplate"), icon: '', condition: li => { - const item = game.items.get(li.data(idAttr)); + const item = game.items.get(li.data("documentId")); return item.isTemplate; }, callback: li => { - const item = game.items.get(li.data(idAttr)); + const item = game.items.get(li.data("documentId")); item.setFlag("worldbuilding", "isTemplate", false); } }); diff --git a/module/token.js b/module/token.js index ec38638..fc5e743 100644 --- a/module/token.js +++ b/module/token.js @@ -3,12 +3,13 @@ * @extends {TokenDocument} */ export class SimpleTokenDocument extends TokenDocument { + /** @inheritdoc */ getBarAttribute(barName, {alternative}={}) { const data = super.getBarAttribute(barName, {alternative}); - const attr = alternative || this.data[barName]?.attribute; + const attr = alternative || this[barName]?.attribute; if ( !data || !attr || !this.actor ) return data; - const current = foundry.utils.getProperty(this.actor.data.data, attr); + const current = foundry.utils.getProperty(this.actor.system, attr); if ( current?.dtype === "Resource" ) data.min = parseInt(current.min || 0); data.editable = true; return data; @@ -23,7 +24,7 @@ export class SimpleTokenDocument extends TokenDocument { foundry.utils.mergeObject(data, model); } for ( const actor of game.actors ) { - if ( actor.isTemplate ) foundry.utils.mergeObject(data, actor.toObject().data); + if ( actor.isTemplate ) foundry.utils.mergeObject(data, actor.toObject()); } return super.getTrackedAttributes(data); } @@ -42,8 +43,7 @@ export class SimpleToken extends Token { if ( "min" in data ) { // Copy the data to avoid mutating what the caller gave us. data = {...data}; - // Shift the value and max by the min to ensure that the bar's percentage is drawn accurately if this resource has - // a non-zero min. + // Shift the value and max by the min to draw the bar percentage accurately for a non-zero min data.value -= data.min; data.max -= data.min; } diff --git a/system.json b/system.json index 5f32b72..8f4c731 100644 --- a/system.json +++ b/system.json @@ -1,11 +1,16 @@ { - "name": "worldbuilding", + "id": "worldbuilding", + "version": "0.7.0-alpha1", "title": "Simple World-Building", + "url": "https://gitlab.com/foundrynet/worldbuilding/", "description": "A minimalist game system which provides configurable Actor and Item templates to support free-form system agnostic game-play.", - "version": "0.6.5", - "minimumCoreVersion": "0.8.9", - "compatibleCoreVersion": "9", - "author": "Atropos", + "license": "LICENSE.txt", + "authors": [ + { + "name": "Atropos", + "url": "https://foundryvtt.com" + } + ], "esmodules": ["module/simple.js"], "styles": ["styles/simple.css"], "packs": [], @@ -16,12 +21,15 @@ "path": "lang/en.json" } ], + "compatibility": { + "minimum": "10", + "verified": "10.278", + "maximum": "10" + }, "gridDistance": 5, "gridUnits": "ft", "primaryTokenAttribute": "health", "secondaryTokenAttribute": "power", - "url": "https://gitlab.com/foundrynet/worldbuilding/", "manifest": "https://raw.githubusercontent.com/foundryvtt/worldbuilding/master/system.json", - "download": "https://github.com/foundryvtt/worldbuilding/archive/refs/tags/release-065.zip", - "license": "LICENSE.txt" + "download": "https://github.com/foundryvtt/worldbuilding/archive/refs/tags/release-065.zip" } diff --git a/templates/actor-sheet.html b/templates/actor-sheet.html index 7979f17..3b31169 100644 --- a/templates/actor-sheet.html +++ b/templates/actor-sheet.html @@ -8,14 +8,14 @@
- + / - +
- + / - +
@@ -32,7 +32,7 @@ {{!-- Biography Tab --}}
- {{editor content=systemData.biography target="data.biography" button=true owner=owner editable=editable rollData=rollData}} + {{editor biographyHTML target="system.biography" button=true editable=editable engine="prosemirror"}}
{{!-- Owned Items Tab --}} @@ -44,7 +44,7 @@

{{item.name}}

{{!-- Iterate through all attributes on the item and output buttons for any that are formula. --}}
- {{#each item.data.attributes as |itemAttr key|}} + {{#each item.system.attributes as |itemAttr key|}} {{#if itemAttr.dtype}} {{#if itemAttr.isFormula}} {{!-- Use the items.name.key format for shorthand. --}} @@ -112,4 +112,4 @@
- \ No newline at end of file + diff --git a/templates/item-sheet.html b/templates/item-sheet.html index 0909121..c3fa48d 100644 --- a/templates/item-sheet.html +++ b/templates/item-sheet.html @@ -7,11 +7,11 @@
- +
- +
@@ -27,7 +27,7 @@ {{!-- Description Tab --}}
- {{editor content=systemData.description target="data.description" button=true owner=owner editable=editable rollData=rollData}} + {{editor descriptionHTML target="system.description" button=true editable=editable engine="prosemirror"}}
{{!-- Attributes Tab --}} @@ -53,4 +53,4 @@ - \ No newline at end of file + diff --git a/templates/parts/sheet-attributes.html b/templates/parts/sheet-attributes.html index 983e4e3..eb7ba89 100644 --- a/templates/parts/sheet-attributes.html +++ b/templates/parts/sheet-attributes.html @@ -6,50 +6,50 @@ {{#if attr.isFormula}} {{/if}} - + {{!-- Handle booleans. --}} {{#if attr.isCheckbox}} - {{else}} {{!-- Handle resources. --}} {{#if attr.isResource}}
- - {{localize "SIMPLE.ResourceMin"}} + - - {{localize "SIMPLE.ResourceValue"}} + - - {{localize "SIMPLE.ResourceMax"}} +
{{!-- Handle other input types. --}} {{else}} - {{/if}} {{/if}} - - {{#select attr.dtype}} {{#each ../dtypes as |t|}} {{/each}} {{/select}} - + {{/each}} - \ No newline at end of file + diff --git a/templates/parts/sheet-groups.html b/templates/parts/sheet-groups.html index 1075a1a..0309ecc 100644 --- a/templates/parts/sheet-groups.html +++ b/templates/parts/sheet-groups.html @@ -2,9 +2,9 @@ {{#each groups as |group groupKey|}}
  • - - - + +