mirror of
https://github.com/RoY7x/worldbuilding.git
synced 2025-04-30 02:31:41 -04:00
Update Simple Worldbuilding for Foundry 0.8.x Compatibility
This commit is contained in:
parent
ee8814b76a
commit
fb0add4cbc
11 changed files with 295 additions and 301 deletions
|
@ -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.",
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
|
172
module/helper.js
172
module/helper.js
|
@ -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) {
|
// Collect data
|
||||||
return 0;
|
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")
|
||||||
}
|
}
|
||||||
// Replace attributes with their numeric equivalents.
|
for ( let a of templates ) {
|
||||||
let dataRgx = new RegExp(/@([a-z.0-9_\-]+)/gi);
|
types[a.id] = a.name;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -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
22
module/item.js
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
CONFIG.Combat.initiative.formula = formula;
|
CONFIG.Combat.initiative.formula = formula;
|
||||||
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}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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
|
|
||||||
});
|
|
||||||
}
|
|
11
system.json
11
system.json
|
@ -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"
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
|
Loading…
Add table
Reference in a new issue