Remove references to the AttributeManager now that it is no longer required
This commit is contained in:
parent
0347a00632
commit
14193cbad0
8 changed files with 0 additions and 516 deletions
|
|
@ -85,16 +85,7 @@
|
||||||
"title": "Questions",
|
"title": "Questions",
|
||||||
"invalid-input-type": "Invalid input type provided: {type}"
|
"invalid-input-type": "Invalid input type provided: {type}"
|
||||||
},
|
},
|
||||||
"AttributeManager": {
|
|
||||||
"title": "Attributes: {name}",
|
|
||||||
"has-max": "Has Maximum?",
|
|
||||||
"name-placeholder": "Attribute Name...",
|
|
||||||
"no-attributes": "No attributes yet",
|
|
||||||
"add-new-attribute": "Add New Attribute",
|
|
||||||
"default-attribute-values": "Default Attribute Values"
|
|
||||||
},
|
|
||||||
"PlayerSheet": {
|
"PlayerSheet": {
|
||||||
"manage-attributes": "Manage Attributes",
|
|
||||||
"create-item": "Create Embedded Item",
|
"create-item": "Create Embedded Item",
|
||||||
"current-value": "Current value",
|
"current-value": "Current value",
|
||||||
"max-value": "Maximum value",
|
"max-value": "Maximum value",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
// Apps
|
// Apps
|
||||||
import { Ask } from "./apps/Ask.mjs";
|
import { Ask } from "./apps/Ask.mjs";
|
||||||
import { AttributeManager } from "./apps/AttributeManager.mjs";
|
|
||||||
import { PlayerSheet } from "./apps/PlayerSheet.mjs";
|
import { PlayerSheet } from "./apps/PlayerSheet.mjs";
|
||||||
import { QueryStatus } from "./apps/QueryStatus.mjs";
|
import { QueryStatus } from "./apps/QueryStatus.mjs";
|
||||||
|
|
||||||
|
|
@ -18,7 +17,6 @@ export const api = deepFreeze({
|
||||||
QueryManager,
|
QueryManager,
|
||||||
Apps: {
|
Apps: {
|
||||||
Ask,
|
Ask,
|
||||||
AttributeManager,
|
|
||||||
PlayerSheet,
|
PlayerSheet,
|
||||||
QueryStatus,
|
QueryStatus,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,357 +0,0 @@
|
||||||
import { __ID__, filePath } from "../consts.mjs";
|
|
||||||
import { ask } from "../utils/DialogManager.mjs";
|
|
||||||
import { attributeSorter } from "../utils/attributeSort.mjs";
|
|
||||||
import { localizer } from "../utils/localizer.mjs";
|
|
||||||
import { toID } from "../utils/toID.mjs";
|
|
||||||
|
|
||||||
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
|
|
||||||
const { deepClone, diffObject, mergeObject, performIntegerSort, randomID, setProperty } = foundry.utils;
|
|
||||||
const { DragDrop } = foundry.applications.ux;
|
|
||||||
|
|
||||||
export class AttributeManager extends HandlebarsApplicationMixin(ApplicationV2) {
|
|
||||||
|
|
||||||
// #region Options
|
|
||||||
static DEFAULT_OPTIONS = {
|
|
||||||
tag: `form`,
|
|
||||||
classes: [
|
|
||||||
__ID__,
|
|
||||||
`AttributeManager`,
|
|
||||||
],
|
|
||||||
position: {
|
|
||||||
width: 400,
|
|
||||||
height: `auto`,
|
|
||||||
},
|
|
||||||
window: {
|
|
||||||
resizable: true,
|
|
||||||
controls: [
|
|
||||||
{
|
|
||||||
icon: `fa-solid fa-globe`,
|
|
||||||
label: `Save As Defaults`,
|
|
||||||
visible: () => game.user.isGM,
|
|
||||||
action: `saveAsDefault`,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
form: {
|
|
||||||
submitOnChange: false,
|
|
||||||
closeOnSubmit: true,
|
|
||||||
handler: this.#onSubmit,
|
|
||||||
},
|
|
||||||
actions: {
|
|
||||||
addNew: this.#addNew,
|
|
||||||
removeAttribute: this.#remove,
|
|
||||||
saveAsDefault: this.#saveAsDefaults,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
static PARTS = {
|
|
||||||
attributes: { template: filePath(`templates/AttributeManager/attribute-list.hbs`) },
|
|
||||||
controls: { template: filePath(`templates/AttributeManager/controls.hbs`) },
|
|
||||||
};
|
|
||||||
// #endregion Options
|
|
||||||
|
|
||||||
// #region Instance Data
|
|
||||||
/** @type {string | null} */
|
|
||||||
#doc = null;
|
|
||||||
|
|
||||||
#attributes;
|
|
||||||
|
|
||||||
constructor({ document , ...options } = {}) {
|
|
||||||
super(options);
|
|
||||||
this.#doc = document;
|
|
||||||
this.#attributes = deepClone(document.system.attr);
|
|
||||||
};
|
|
||||||
|
|
||||||
get title() {
|
|
||||||
return localizer(
|
|
||||||
`taf.Apps.AttributeManager.title`,
|
|
||||||
this.#doc,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
// #endregion Instance Data
|
|
||||||
|
|
||||||
// #region Lifecycle
|
|
||||||
async _onRender(context, options) {
|
|
||||||
await super._onRender(context, options);
|
|
||||||
|
|
||||||
const elements = this.element
|
|
||||||
.querySelectorAll(`[data-bind]`);
|
|
||||||
for (const input of elements) {
|
|
||||||
input.addEventListener(`change`, this.#bindListener.bind(this));
|
|
||||||
};
|
|
||||||
|
|
||||||
new DragDrop.implementation({
|
|
||||||
dragSelector: `.attribute-drag-handle`,
|
|
||||||
dropSelector: `.attributes`,
|
|
||||||
callbacks: {
|
|
||||||
dragstart: this._onDragStart.bind(this),
|
|
||||||
drop: this._onDrop.bind(this),
|
|
||||||
},
|
|
||||||
}).bind(this.element);
|
|
||||||
};
|
|
||||||
|
|
||||||
/** @this {AttributeManager} */
|
|
||||||
static async #onSubmit() {
|
|
||||||
const entries = Object.entries(this.#attributes)
|
|
||||||
.map(([id, attr]) => {
|
|
||||||
if (attr == null) {
|
|
||||||
return [ id, attr ];
|
|
||||||
};
|
|
||||||
|
|
||||||
if (attr.isNew) {
|
|
||||||
delete attr.isNew;
|
|
||||||
return [ toID(attr.name), attr ];
|
|
||||||
};
|
|
||||||
|
|
||||||
return [ id, attr ];
|
|
||||||
});
|
|
||||||
const data = Object.fromEntries(entries);
|
|
||||||
this.#attributes = data;
|
|
||||||
|
|
||||||
const diff = diffObject(
|
|
||||||
this.#doc.system.attr,
|
|
||||||
data,
|
|
||||||
{ inner: false, deletionKeys: true },
|
|
||||||
);
|
|
||||||
|
|
||||||
await this.#doc.update({ "system.attr": diff });
|
|
||||||
};
|
|
||||||
// #endregion Lifecycle
|
|
||||||
|
|
||||||
// #region Data Prep
|
|
||||||
async _preparePartContext(partId) {
|
|
||||||
const ctx = {};
|
|
||||||
|
|
||||||
ctx.actor = this.#doc;
|
|
||||||
|
|
||||||
switch (partId) {
|
|
||||||
case `attributes`: {
|
|
||||||
await this._prepareAttributeContext(ctx);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
return ctx;
|
|
||||||
};
|
|
||||||
|
|
||||||
async _prepareAttributeContext(ctx) {
|
|
||||||
const attrs = [];
|
|
||||||
for (const [id, data] of Object.entries(this.#attributes)) {
|
|
||||||
if (data == null) { continue };
|
|
||||||
// Remove with issue: Foundry/taf#54
|
|
||||||
if (game.release.generation >= 14 && data == _del) {continue}
|
|
||||||
attrs.push({
|
|
||||||
id,
|
|
||||||
name: data.name,
|
|
||||||
sort: data.sort,
|
|
||||||
isRange: data.isRange,
|
|
||||||
isNew: data.isNew ?? false,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
ctx.attrs = attrs.sort(attributeSorter);
|
|
||||||
};
|
|
||||||
// #endregion Data Prep
|
|
||||||
|
|
||||||
// #region Actions
|
|
||||||
/**
|
|
||||||
* @param {Event} event
|
|
||||||
*/
|
|
||||||
async #bindListener(event) {
|
|
||||||
const target = event.target;
|
|
||||||
const data = target.dataset;
|
|
||||||
const binding = data.bind;
|
|
||||||
|
|
||||||
let value = target.value;
|
|
||||||
switch (target.type) {
|
|
||||||
case `checkbox`: {
|
|
||||||
value = target.checked;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
setProperty(this.#attributes, binding, value);
|
|
||||||
await this.render({ parts: [ `attributes` ]});
|
|
||||||
};
|
|
||||||
|
|
||||||
/** @this {AttributeManager} */
|
|
||||||
static async #addNew() {
|
|
||||||
const id = randomID();
|
|
||||||
this.#attributes[id] = {
|
|
||||||
name: ``,
|
|
||||||
sort: Number.MAX_SAFE_INTEGER,
|
|
||||||
isRange: false,
|
|
||||||
isNew: true,
|
|
||||||
};
|
|
||||||
await this.render({ parts: [ `attributes` ]});
|
|
||||||
};
|
|
||||||
|
|
||||||
/** @this {AttributeManager} */
|
|
||||||
static async #remove($e, element) {
|
|
||||||
const attribute = element.closest(`[data-attribute]`)?.dataset.attribute;
|
|
||||||
if (!attribute) { return };
|
|
||||||
// Remove with issue: Foundry/taf#54
|
|
||||||
if (game.release.generation < 14) {
|
|
||||||
delete this.#attributes[attribute];
|
|
||||||
this.#attributes[`-=${attribute}`] = null;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.#attributes[attribute] = _del;
|
|
||||||
}
|
|
||||||
await this.render({ parts: [ `attributes` ] });
|
|
||||||
};
|
|
||||||
|
|
||||||
/** @this {AttributeManager} */
|
|
||||||
static async #saveAsDefaults() {
|
|
||||||
const attrs = deepClone(this.#attributes);
|
|
||||||
|
|
||||||
// Prompt the user for what values they want to save the attributes with
|
|
||||||
const inputs = [];
|
|
||||||
for (const attr of Object.values(attrs)) {
|
|
||||||
const id = toID(attr.name);
|
|
||||||
|
|
||||||
if (attr.isRange) {
|
|
||||||
inputs.push(
|
|
||||||
{
|
|
||||||
type: `collapse`,
|
|
||||||
summary: attr.name,
|
|
||||||
inputs: [
|
|
||||||
{
|
|
||||||
key: `${id}.value`,
|
|
||||||
type: `input`,
|
|
||||||
inputType: `number`,
|
|
||||||
label: `Value`,
|
|
||||||
defaultValue: attr.value,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: `${id}.max`,
|
|
||||||
type: `input`,
|
|
||||||
inputType: `number`,
|
|
||||||
label: `Maximum`,
|
|
||||||
defaultValue: attr.max,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{ type: `divider` },
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
inputs.push({
|
|
||||||
key: `${id}.value`,
|
|
||||||
type: `input`,
|
|
||||||
inputType: `number`,
|
|
||||||
label: `${attr.name}`,
|
|
||||||
defaultValue: attr.value,
|
|
||||||
});
|
|
||||||
|
|
||||||
inputs.push({ type: `divider` });
|
|
||||||
};
|
|
||||||
|
|
||||||
const prompt = {
|
|
||||||
id: `${this.#doc.id}-global-attr-saving`,
|
|
||||||
inputs: inputs.slice(0, -1),
|
|
||||||
alwaysUseAnswerObject: true,
|
|
||||||
window: { title: `taf.Apps.AttributeManager.default-attribute-values` },
|
|
||||||
};
|
|
||||||
|
|
||||||
const response = await ask(prompt);
|
|
||||||
switch (response.state) {
|
|
||||||
case `errored`:
|
|
||||||
ui.notifications.error(response.error);
|
|
||||||
// eslint-disable-next-line no-fallthrough
|
|
||||||
case `fronted`:
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!response.answers) { return };
|
|
||||||
|
|
||||||
const fullAttrs = mergeObject(attrs, response.answers);
|
|
||||||
game.settings.set(__ID__, `actorDefaultAttributes`, fullAttrs);
|
|
||||||
ui.notifications.success(`taf.notifs.success.saved-default-attributes`, { localize: true });
|
|
||||||
};
|
|
||||||
// #endregion Actions
|
|
||||||
|
|
||||||
// #region Drag & Drop
|
|
||||||
_onDragStart(event) {
|
|
||||||
const target = event.currentTarget.closest(`[data-attribute]`);
|
|
||||||
if (`link` in event.target.dataset) { return };
|
|
||||||
if (!target.dataset.attribute) { return };
|
|
||||||
|
|
||||||
const attributeID = target.dataset.attribute;
|
|
||||||
const attribute = this.#attributes[attributeID];
|
|
||||||
const dragData = {
|
|
||||||
_id: attributeID,
|
|
||||||
sort: attribute.sort,
|
|
||||||
};
|
|
||||||
|
|
||||||
event.dataTransfer.setDragImage(target, 16, 23);
|
|
||||||
event.dataTransfer.setData(`taf/json`, JSON.stringify(dragData));
|
|
||||||
|
|
||||||
// Provide an attribute reference in a way that prose-mirror can use
|
|
||||||
if (!attribute.isNew) {
|
|
||||||
event.dataTransfer.setData(
|
|
||||||
`text/plain`,
|
|
||||||
`[[@${attributeID}]]{${attribute.name}}`,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
_onDrop(event) {
|
|
||||||
let dropped;
|
|
||||||
try {
|
|
||||||
dropped = JSON.parse(event.dataTransfer.getData(`taf/json`));
|
|
||||||
} catch {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const dropTarget = event.target.closest(`[data-attribute]`);
|
|
||||||
if (!dropTarget) { return };
|
|
||||||
const targetID = dropTarget.dataset.attribute;
|
|
||||||
let target;
|
|
||||||
|
|
||||||
// Not moving location, ignore drop event
|
|
||||||
if (targetID === dropped._id) { return };
|
|
||||||
|
|
||||||
// Determine all of the siblings and create sort data
|
|
||||||
const siblings = [];
|
|
||||||
for (const element of dropTarget.parentElement.children) {
|
|
||||||
const siblingID = element.dataset.attribute;
|
|
||||||
const attr = this.#attributes[siblingID];
|
|
||||||
const sibling = {
|
|
||||||
_id: siblingID,
|
|
||||||
sort: attr.sort,
|
|
||||||
};
|
|
||||||
if (siblingID && siblingID !== dropped._id) {
|
|
||||||
siblings.push(sibling);
|
|
||||||
};
|
|
||||||
if (siblingID === targetID) {
|
|
||||||
target = sibling;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const sortUpdates = performIntegerSort(
|
|
||||||
dropped,
|
|
||||||
{
|
|
||||||
target,
|
|
||||||
siblings,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const updateEntries = sortUpdates.map(({ target, update }) => {
|
|
||||||
return [ `${target._id}.sort`, update.sort ];
|
|
||||||
});
|
|
||||||
const update = Object.fromEntries(updateEntries);
|
|
||||||
|
|
||||||
mergeObject(
|
|
||||||
this.#attributes,
|
|
||||||
update,
|
|
||||||
{
|
|
||||||
insertKeys: false,
|
|
||||||
insertValues: false,
|
|
||||||
inplace: true,
|
|
||||||
performDeletions: false,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
this.render({ parts: [ `attributes` ] });
|
|
||||||
};
|
|
||||||
// #endregion Drag & Drop
|
|
||||||
};
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import { __ID__, filePath } from "../consts.mjs";
|
import { __ID__, filePath } from "../consts.mjs";
|
||||||
import { deleteItemFromElement, editItemFromElement } from "./utils.mjs";
|
import { deleteItemFromElement, editItemFromElement } from "./utils.mjs";
|
||||||
import { AttributeManager } from "./AttributeManager.mjs";
|
|
||||||
import { config } from "../config.mjs";
|
import { config } from "../config.mjs";
|
||||||
import { Logger } from "../utils/Logger.mjs";
|
import { Logger } from "../utils/Logger.mjs";
|
||||||
import { TAFDocumentSheetConfig } from "./TAFDocumentSheetConfig.mjs";
|
import { TAFDocumentSheetConfig } from "./TAFDocumentSheetConfig.mjs";
|
||||||
|
|
@ -36,7 +35,6 @@ export class PlayerSheet extends
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
createEmbeddedItem: this.#createEmbeddedItem,
|
createEmbeddedItem: this.#createEmbeddedItem,
|
||||||
manageAttributes: this.#manageAttributes,
|
|
||||||
configureSheet: this.#configureSheet,
|
configureSheet: this.#configureSheet,
|
||||||
toggleExpand: this.#toggleExpand,
|
toggleExpand: this.#toggleExpand,
|
||||||
},
|
},
|
||||||
|
|
@ -194,17 +192,6 @@ export class PlayerSheet extends
|
||||||
const controls = super._getHeaderControls();
|
const controls = super._getHeaderControls();
|
||||||
|
|
||||||
controls.push(
|
controls.push(
|
||||||
{
|
|
||||||
icon: `fa-solid fa-at`,
|
|
||||||
label: `taf.Apps.PlayerSheet.manage-attributes`,
|
|
||||||
action: `manageAttributes`,
|
|
||||||
visible: () => {
|
|
||||||
const isGM = game.user.isGM;
|
|
||||||
const allowPlayerEdits = game.settings.get(__ID__, `canPlayersManageAttributes`);
|
|
||||||
const editable = this.isEditable;
|
|
||||||
return isGM || (allowPlayerEdits && editable);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
icon: `fa-solid fa-suitcase`,
|
icon: `fa-solid fa-suitcase`,
|
||||||
label: `taf.Apps.PlayerSheet.create-item`,
|
label: `taf.Apps.PlayerSheet.create-item`,
|
||||||
|
|
@ -252,12 +239,6 @@ export class PlayerSheet extends
|
||||||
{ jQuery: false, fixed: true },
|
{ jQuery: false, fixed: true },
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
async close() {
|
|
||||||
this.#attributeManager?.close();
|
|
||||||
this.#attributeManager = null;
|
|
||||||
return super.close();
|
|
||||||
};
|
|
||||||
// #endregion Lifecycle
|
// #endregion Lifecycle
|
||||||
|
|
||||||
// #region Data Prep
|
// #region Data Prep
|
||||||
|
|
@ -412,28 +393,6 @@ export class PlayerSheet extends
|
||||||
// #endregion Data Prep
|
// #endregion Data Prep
|
||||||
|
|
||||||
// #region Actions
|
// #region Actions
|
||||||
#attributeManager = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This action opens an instance of the AttributeManager application
|
|
||||||
* so that the user can edit and update all of the attributes for the
|
|
||||||
* actor. This persists the application instance for the duration of
|
|
||||||
* the ActorSheet's lifespan.
|
|
||||||
*
|
|
||||||
* @this {PlayerSheet}
|
|
||||||
*/
|
|
||||||
static async #manageAttributes() {
|
|
||||||
this.#attributeManager ??= new AttributeManager({ document: this.actor });
|
|
||||||
if (this.#attributeManager.rendered) {
|
|
||||||
await this.#attributeManager.bringToFront();
|
|
||||||
} else {
|
|
||||||
await this.#attributeManager.render({
|
|
||||||
force: true,
|
|
||||||
window: { windowId: this.window.windowId },
|
|
||||||
});
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This action overrides the default Foundry action in order to tell
|
* This action overrides the default Foundry action in order to tell
|
||||||
* it to open my custom DocumentSheetConfig application instead of
|
* it to open my custom DocumentSheetConfig application instead of
|
||||||
|
|
|
||||||
|
|
@ -1,50 +0,0 @@
|
||||||
.taf.AttributeManager {
|
|
||||||
.attributes {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.attribute {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: min-content 1fr repeat(3, auto);
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
padding: 8px;
|
|
||||||
border: 1px solid rebeccapurple;
|
|
||||||
border-radius: 4px;
|
|
||||||
|
|
||||||
label {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
&.vertical {
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Used to style the actual element as dragging */
|
|
||||||
&:has(taf-icon:active) {
|
|
||||||
background: var(--background);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
taf-icon {
|
|
||||||
cursor: grab;
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
cursor: grabbing;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.controls {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
gap: 8px;
|
|
||||||
|
|
||||||
button {
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -27,7 +27,6 @@
|
||||||
@import url("./Apps/common.css") layer(apps);
|
@import url("./Apps/common.css") layer(apps);
|
||||||
@import url("./Apps/Ask.css") layer(apps);
|
@import url("./Apps/Ask.css") layer(apps);
|
||||||
@import url("./Apps/AttributeItemSheet.css") layer(apps);
|
@import url("./Apps/AttributeItemSheet.css") layer(apps);
|
||||||
@import url("./Apps/AttributeManager.css") layer(apps);
|
|
||||||
@import url("./Apps/GenericItemSheet.css") layer(apps);
|
@import url("./Apps/GenericItemSheet.css") layer(apps);
|
||||||
@import url("./Apps/PlayerSheet.css") layer(apps);
|
@import url("./Apps/PlayerSheet.css") layer(apps);
|
||||||
@import url("./Apps/QueryStatus.css") layer(apps);
|
@import url("./Apps/QueryStatus.css") layer(apps);
|
||||||
|
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
<div class="attributes">
|
|
||||||
{{#each attrs as |attr|}}
|
|
||||||
<div
|
|
||||||
class="attribute"
|
|
||||||
data-attribute="{{ attr.id }}"
|
|
||||||
>
|
|
||||||
<taf-icon
|
|
||||||
name="icons/drag-handle"
|
|
||||||
var:stroke="currentColor"
|
|
||||||
var:fill="currentColor"
|
|
||||||
class="attribute-drag-handle"
|
|
||||||
></taf-icon>
|
|
||||||
{{#if attr.isNew}}
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
data-bind="{{ attr.id }}.name"
|
|
||||||
value="{{ attr.name }}"
|
|
||||||
placeholder="{{localize "taf.Apps.AttributeManager.name-placeholder"}}"
|
|
||||||
>
|
|
||||||
{{else}}
|
|
||||||
<span>{{ attr.name }}</span>
|
|
||||||
{{/if}}
|
|
||||||
<label>
|
|
||||||
{{localize "taf.Apps.AttributeManager.has-max"}}
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
data-bind="{{ attr.id }}.isRange"
|
|
||||||
{{ checked attr.isRange }}
|
|
||||||
>
|
|
||||||
</label>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
data-action="removeAttribute"
|
|
||||||
>
|
|
||||||
{{localize "taf.misc.delete"}}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
{{else}}
|
|
||||||
<p>
|
|
||||||
{{localize "taf.Apps.AttributeManager.no-attributes"}}
|
|
||||||
</p>
|
|
||||||
{{/each}}
|
|
||||||
</div>
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
<div class="controls">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
data-action="addNew"
|
|
||||||
>
|
|
||||||
{{localize "taf.Apps.AttributeManager.add-new-attribute"}}
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
>
|
|
||||||
{{localize "taf.misc.save-and-close"}}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue