Add the ability to display / edit the description from the item sheet

This commit is contained in:
Oliver-Akins 2025-02-10 23:04:28 -07:00
parent 46a235b603
commit 69db3ca719
13 changed files with 168 additions and 17 deletions

View file

@ -1,5 +1,7 @@
import { deleteItemFromElement, editItemFromElement } from "./utils.mjs";
import { DicePool } from "./DicePool.mjs";
import { RichEditor } from "./RichEditor.mjs";
import { toBoolean } from "../consts.mjs";
/**
* A mixin that takes the class from HandlebarsApplicationMixin and
@ -16,6 +18,7 @@ export function GenericAppMixin(HandlebarsApp) {
roll: this._rollDice,
editItem: (_event, target) => editItemFromElement(target),
deleteItem: (_event, target) => deleteItemFromElement(target),
openRichEditor: this.#openRichEditor,
},
};
@ -57,14 +60,39 @@ export function GenericAppMixin(HandlebarsApp) {
// #region Actions
/** @this {GenericRipCryptApp} */
static async _rollDice(_$e, el) {
const data = el.dataset;
static async _rollDice(_event, target) {
const data = target.dataset;
const diceCount = parseInt(data.diceCount);
const flavor = data.flavor;
const dp = new DicePool({ diceCount, flavor });
dp.render({ force: true });
};
/** @this {GenericRipCryptApp} */
static async #openRichEditor(_event, target) {
const data = target.dataset;
const {
uuid,
path,
collaborative,
compact,
} = data;
if (!uuid || !path) {
console.error(`Rich Editor requires a document uuid and path to edit`);
return;
};
const document = await fromUuid(uuid);
const app = new RichEditor({
document,
path,
collaborative: toBoolean(collaborative),
compact: toBoolean(compact ),
});
app.render({ force: true });
};
// #endregion
};
return GenericRipCryptApp;

View file

@ -20,8 +20,6 @@ export class AllItemSheetV1 extends GenericAppMixin(HandlebarsApplicationMixin(I
window: {
resizable: false,
},
actions: {
},
form: {
submitOnChange: true,
closeOnSubmit: false,
@ -40,7 +38,7 @@ export class AllItemSheetV1 extends GenericAppMixin(HandlebarsApplicationMixin(I
ctx = await super._preparePartContext(partId, ctx, opts);
ctx.item = this.document;
ctx.formFields = this.document.system.getFormFields(ctx);
ctx.formFields = await this.document.system.getFormFields(ctx);
Logger.debug(`Context:`, ctx);
return ctx;

View file

@ -79,11 +79,6 @@ export class RichEditor extends HandlebarsApplicationMixin(DocumentSheetV2) {
path: this.path,
};
console.log({
doc: this.document,
path: this.path,
value: this.document.system.description,
});
const value = getProperty(this.document, this.path);
ctx.enriched = await TextEditor.enrichHTML(value);
ctx.raw = value;

View file

@ -1,3 +1,5 @@
const { getType } = foundry.utils;
// MARK: filePath
export function filePath(path) {
if (path.startsWith(`/`)) {
@ -6,6 +8,24 @@ export function filePath(path) {
return `systems/ripcrypt/${path}`;
};
// MARK: toBoolean
/**
* Converts a value into a boolean based on the type of the value provided
*
* @param {any} val The value to convert
*/
export function toBoolean(val) {
switch (getType(val)) {
case `string`: {
return val === `true`;
};
case `number`: {
return val === 1;
};
};
return Boolean(val);
};
// MARK: documentSorter
/**
* @typedef {Object} Sortable

View file

@ -35,7 +35,7 @@ export class CraftData extends SkillData {
// #endregion
// #region Sheet Data
getFormFields(_ctx) {
async getFormFields(_ctx) {
const fields = [
{
id: `fate-path`,
@ -48,6 +48,15 @@ export class CraftData extends SkillData {
value: aspect,
})),
},
{
id: `description`,
type: `prosemirror`,
label: `RipCrypt.common.description`,
path: `system.description`,
uuid: this.parent.uuid,
value: await TextEditor.enrichHTML(this.description),
collaborative: false,
},
{
type: `group`,
title: `RipCrypt.common.advances`,

View file

@ -48,7 +48,7 @@ export class SkillData extends foundry.abstract.TypeDataModel {
// #endregion
// #region Sheet Data
getFormFields(_ctx) {
async getFormFields(_ctx) {
const fields = [
{
id: `fate-path`,
@ -62,12 +62,13 @@ export class SkillData extends foundry.abstract.TypeDataModel {
})),
},
{
// TODO: Figure out how tf to make this work nicely on a generic level
id: `description`,
type: `prosemirror`,
label: `RipCrypt.common.description`,
path: `system.description`,
collaborative: true,
uuid: this.parent.uuid,
value: await TextEditor.enrichHTML(this.description),
collaborative: false,
},
{
type: `group`,

View file

@ -3,6 +3,7 @@ import { booleanInput } from "./booleanInput.mjs";
import { dropdownInput } from "./dropdownInput.mjs";
import { groupInput } from "./groupInput.mjs";
import { numberInput } from "./numberInput.mjs";
import { prosemirrorInput } from "./prosemirrorInput.mjs";
import { stringSet } from "./stringSet.mjs";
import { textInput } from "./textInput.mjs";
@ -10,6 +11,7 @@ const { getType } = foundry.utils;
const inputTypes = {
"string-set": stringSet,
prosemirror: prosemirrorInput,
integer: numberInput,
bar: barInput,
dropdown: dropdownInput,
@ -29,7 +31,10 @@ export function formFields(inputs, opts) {
input.limited ??= true;
};
if (typesToSanitize.has(getType(input.value))) {
if (
input.type !== `prosemirror`
&& typesToSanitize.has(getType(input.value))
) {
input.value = Handlebars.escapeExpression(input.value);
};
fields.push(inputTypes[input.type](input, opts.data.root));

View file

@ -0,0 +1,43 @@
import { localizer } from "../../utils/Localizer.mjs";
export function prosemirrorInput(input, data) {
const label = localizer(input.label);
if (!data.meta.editable) {
return `<div data-input-type="prose-mirror">
<div class="label-row">
<div class="label">
${label}
</div>
</div>
<div class="value">
${input.value}
</div>
</div>`;
};
return `<div data-input-type="prose-mirror">
<div class="label-row">
<div class="label">
${label}
</div>
<button
type="button"
data-action="openRichEditor"
data-uuid="${input.uuid}"
data-path="${input.path}"
data-compact="${input.compact}"
data-collaborative="${input.collaborative}"
>
${localizer(`RipCrypt.common.edit`)}
</button>
</div>
<!--
This cannot be spread across multiple lines because of the :empty selector
considering whitespace as "not being empty". Though browsers will eventually
treat :empty as "empty, or only whitespace".
-->
<div class="value">${input.value}</div>
</div>`;
};