import { getTokenConfig, setTokenConfig } from '../scripts/utils.js';
|
|
|
|
export default class TokenCustomConfig extends TokenConfig {
|
|
constructor(object, options, imgSrc, imgName, callback, config) {
|
|
let token;
|
|
if (object instanceof Actor) {
|
|
token = new TokenDocument(object.token, {
|
|
actor: object,
|
|
});
|
|
} else {
|
|
token = new TokenDocument(object.document, {
|
|
actor: game.actors.get(object.actorId),
|
|
});
|
|
}
|
|
super(token, options);
|
|
this.imgSrc = imgSrc;
|
|
this.imgName = imgName;
|
|
this.callback = callback;
|
|
this.config = config;
|
|
if (this.config) {
|
|
this.flags = this.config.flags;
|
|
this.tv_script = this.config.tv_script;
|
|
}
|
|
}
|
|
|
|
_getSubmitData(updateData = {}) {
|
|
if (!this.form) throw new Error('The FormApplication subclass has no registered form element');
|
|
const fd = new FormDataExtended(this.form, { editors: this.editors });
|
|
let data = fd.object;
|
|
if (updateData) data = foundry.utils.flattenObject(foundry.utils.mergeObject(data, updateData));
|
|
|
|
// Clear detection modes array
|
|
if (!('detectionModes.0.id' in data)) data.detectionModes = [];
|
|
|
|
// Treat "None" as null for bar attributes
|
|
data['bar1.attribute'] ||= null;
|
|
data['bar2.attribute'] ||= null;
|
|
return data;
|
|
}
|
|
|
|
async _updateObject(event, formData) {
|
|
const filtered = {};
|
|
|
|
const form = $(event.target).closest('form');
|
|
|
|
form.find('.form-group').each(function (_) {
|
|
const tva_checkbox = $(this).find('.tva-config-checkbox > input');
|
|
if (tva_checkbox.length && tva_checkbox.is(':checked')) {
|
|
$(this)
|
|
.find('[name]')
|
|
.each(function (_) {
|
|
const name = $(this).attr('name');
|
|
filtered[name] = formData[name];
|
|
});
|
|
}
|
|
});
|
|
|
|
if (this.tv_script) {
|
|
filtered.tv_script = this.tv_script;
|
|
}
|
|
|
|
if (this.config) {
|
|
let config = expandObject(filtered);
|
|
config.flags = config.flags ? mergeObject(this.flags || {}, config.flags) : this.flags;
|
|
if (this.callback) this.callback(config);
|
|
} else {
|
|
const saved = setTokenConfig(this.imgSrc, this.imgName, filtered);
|
|
if (this.callback) this.callback(saved);
|
|
}
|
|
}
|
|
|
|
applyCustomConfig() {
|
|
const tokenConfig = flattenObject(this.config || getTokenConfig(this.imgSrc, this.imgName));
|
|
const form = $(this.form);
|
|
for (const key of Object.keys(tokenConfig)) {
|
|
const el = form.find(`[name="${key}"]`);
|
|
if (el.is(':checkbox')) {
|
|
el.prop('checked', tokenConfig[key]);
|
|
} else {
|
|
el.val(tokenConfig[key]);
|
|
}
|
|
el.trigger('change');
|
|
}
|
|
}
|
|
|
|
// *************
|
|
// consider moving html injection to:
|
|
// _replaceHTML | _injectHTML
|
|
|
|
async activateListeners(html) {
|
|
await super.activateListeners(html);
|
|
|
|
// Disable image path controls
|
|
$(html).find('.token-variants-image-select-button').prop('disabled', true);
|
|
$(html).find('.file-picker').prop('disabled', true);
|
|
$(html).find('.image').prop('disabled', true);
|
|
|
|
// Remove 'Assign Token' button
|
|
$(html).find('.assign-token').remove();
|
|
|
|
// Add checkboxes to control inclusion of specific tabs in the custom config
|
|
const tokenConfig = this.config || getTokenConfig(this.imgSrc, this.imgName);
|
|
this.tv_script = tokenConfig.tv_script;
|
|
|
|
$(html).on('change', '.tva-config-checkbox', this._onCheckboxChange);
|
|
|
|
const processFormGroup = function (formGroup) {
|
|
// Checkbox is not added for the Image Path group
|
|
if (!$(formGroup).find('[name="img"]').length) {
|
|
let savedField = false;
|
|
if (tokenConfig) {
|
|
const flatConfig = flattenObject(tokenConfig);
|
|
$(formGroup)
|
|
.find('[name]')
|
|
.each(function (_) {
|
|
const name = $(this).attr('name');
|
|
if (name in flatConfig) {
|
|
savedField = true;
|
|
}
|
|
});
|
|
}
|
|
|
|
const checkbox = $(
|
|
`<div class="tva-config-checkbox"><input type="checkbox" data-dtype="Boolean" ${
|
|
savedField ? 'checked=""' : ''
|
|
}></div>`
|
|
);
|
|
if ($(formGroup).find('p.hint').length) {
|
|
$(formGroup).find('p.hint').before(checkbox);
|
|
} else {
|
|
$(formGroup).append(checkbox);
|
|
}
|
|
checkbox.find('input').trigger('change');
|
|
}
|
|
};
|
|
// Add checkboxes to each form-group to control highlighting and which fields will are to be saved
|
|
$(html)
|
|
.find('.form-group')
|
|
.each(function (index) {
|
|
processFormGroup(this);
|
|
});
|
|
|
|
// Add 'update' and 'remove' config buttons
|
|
$(html).find('.sheet-footer > button').remove();
|
|
$(html)
|
|
.find('.sheet-footer')
|
|
.append('<button type="submit" value="1"><i class="far fa-save"></i> Save Config</button>');
|
|
if (tokenConfig) {
|
|
$(html)
|
|
.find('.sheet-footer')
|
|
.append('<button type="button" class="remove-config"><i class="fas fa-trash"></i> Remove Config</button>');
|
|
html.find('.remove-config').click(this._onRemoveConfig.bind(this));
|
|
}
|
|
|
|
// Pre-select image or appearance tab
|
|
$(html).find('.tabs > .item[data-tab="image"] > i').trigger('click');
|
|
$(html).find('.tabs > .item[data-tab="appearance"] > i').trigger('click');
|
|
|
|
document.activeElement.blur(); // Hack fix for key UP/DOWN effects not registering after config has been opened
|
|
|
|
// TokenConfig might be changed by some modules after activateListeners is processed
|
|
// Look out for these updates and add checkboxes for any newly added form-groups
|
|
const mutate = (mutations) => {
|
|
mutations.forEach((mutation) => {
|
|
mutation.addedNodes.forEach((node) => {
|
|
if (node.nodeName === 'DIV' && node.className === 'form-group') {
|
|
processFormGroup(node);
|
|
this.applyCustomConfig();
|
|
}
|
|
});
|
|
});
|
|
};
|
|
|
|
const observer = new MutationObserver(mutate);
|
|
observer.observe(html[0], {
|
|
characterData: false,
|
|
attributes: false,
|
|
childList: true,
|
|
subtree: true,
|
|
});
|
|
|
|
// On any field being changed we want to automatically select the form-group to be included in the update
|
|
$(html).on('change', 'input, select', onInputChange);
|
|
$(html).on('click', 'button', onInputChange);
|
|
|
|
this.applyCustomConfig();
|
|
}
|
|
|
|
async _onCheckboxChange(event) {
|
|
const checkbox = $(event.target);
|
|
checkbox.closest('.form-group').css({
|
|
'outline-color': checkbox.is(':checked') ? 'green' : '#ffcc6e',
|
|
'outline-width': '2px',
|
|
'outline-style': 'dotted',
|
|
'margin-bottom': '5px',
|
|
});
|
|
checkbox.closest('.tva-config-checkbox').css({
|
|
'outline-color': checkbox.is(':checked') ? 'green' : '#ffcc6e',
|
|
'outline-width': '2px',
|
|
'outline-style': 'solid',
|
|
});
|
|
}
|
|
|
|
async _onRemoveConfig(event) {
|
|
if (this.config) {
|
|
if (this.callback) this.callback({});
|
|
} else {
|
|
const saved = setTokenConfig(this.imgSrc, this.imgName, null);
|
|
if (this.callback) this.callback(saved);
|
|
}
|
|
this.close();
|
|
}
|
|
|
|
get id() {
|
|
return `token-custom-config-${this.object.id}`;
|
|
}
|
|
|
|
_getHeaderButtons() {
|
|
const buttons = super._getHeaderButtons();
|
|
return buttons;
|
|
}
|
|
}
|
|
|
|
// Toggle checkbox if input has been detected inside it's form-group
|
|
async function onInputChange(event) {
|
|
if (event.target.parentNode.className === 'tva-config-checkbox') return;
|
|
$(event.target).closest('.form-group').find('.tva-config-checkbox input').prop('checked', true);
|
|
}
|