Add a RichEditor to make HTMLFields livable
This commit is contained in:
parent
f6ff3247e3
commit
ced2b5151b
7 changed files with 137 additions and 0 deletions
93
module/Apps/RichEditor.mjs
Normal file
93
module/Apps/RichEditor.mjs
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
/*
|
||||||
|
This Application is used by parts of the system to enable a better experience
|
||||||
|
while editing enriched text, because a lot of the spaces for text are really
|
||||||
|
small and are better served by a bigger text editor so that the controls are
|
||||||
|
more visible and doesn't cause as much overflow chaos.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { filePath } from "../consts.mjs";
|
||||||
|
|
||||||
|
const { HandlebarsApplicationMixin, DocumentSheetV2 } = foundry.applications.api;
|
||||||
|
const { hasProperty, getProperty } = foundry.utils;
|
||||||
|
|
||||||
|
export class RichEditor extends HandlebarsApplicationMixin(DocumentSheetV2) {
|
||||||
|
// #region Options
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
classes: [
|
||||||
|
`ripcrypt`,
|
||||||
|
`ripcrypt--RichEditor`,
|
||||||
|
],
|
||||||
|
window: {
|
||||||
|
title: `Text Editor`,
|
||||||
|
frame: true,
|
||||||
|
positioned: true,
|
||||||
|
resizable: false,
|
||||||
|
minimizable: true,
|
||||||
|
},
|
||||||
|
position: {
|
||||||
|
width: `auto`,
|
||||||
|
height: `auto`,
|
||||||
|
},
|
||||||
|
actions: {},
|
||||||
|
form: {
|
||||||
|
submitOnChange: true,
|
||||||
|
closeOnSubmit: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static PARTS = {
|
||||||
|
editor: {
|
||||||
|
template: filePath(`templates/Apps/RichEditor/content.hbs`),
|
||||||
|
root: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region Instance Data
|
||||||
|
document;
|
||||||
|
path;
|
||||||
|
|
||||||
|
constructor(opts) {
|
||||||
|
const {
|
||||||
|
document,
|
||||||
|
path,
|
||||||
|
compact = false,
|
||||||
|
collaborative = true,
|
||||||
|
} = opts;
|
||||||
|
|
||||||
|
if (!hasProperty(document, path)) {
|
||||||
|
throw new Error(`Document provided to text editor must have the property specified by the path.`);
|
||||||
|
};
|
||||||
|
|
||||||
|
opts.sheetConfig = false;
|
||||||
|
super(opts);
|
||||||
|
|
||||||
|
this.compact = compact;
|
||||||
|
this.collaborative = collaborative;
|
||||||
|
this.document = document;
|
||||||
|
this.path = path;
|
||||||
|
};
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region Lifecycle
|
||||||
|
async _preparePartContext(partId, ctx, _opts) {
|
||||||
|
ctx = {
|
||||||
|
uuid: this.document.uuid,
|
||||||
|
editable: true, // this.isEditable
|
||||||
|
collaborative: this.collaborative,
|
||||||
|
compact: this.compact,
|
||||||
|
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;
|
||||||
|
return ctx;
|
||||||
|
};
|
||||||
|
// #endregion
|
||||||
|
};
|
||||||
|
|
@ -3,6 +3,7 @@ import { CombinedHeroSheet } from "./Apps/ActorSheets/CombinedHeroSheet.mjs";
|
||||||
import { DicePool } from "./Apps/DicePool.mjs";
|
import { DicePool } from "./Apps/DicePool.mjs";
|
||||||
import { HeroSkillsCardV1 } from "./Apps/ActorSheets/HeroSkillsCardV1.mjs";
|
import { HeroSkillsCardV1 } from "./Apps/ActorSheets/HeroSkillsCardV1.mjs";
|
||||||
import { HeroSummaryCardV1 } from "./Apps/ActorSheets/HeroSummaryCardV1.mjs";
|
import { HeroSummaryCardV1 } from "./Apps/ActorSheets/HeroSummaryCardV1.mjs";
|
||||||
|
import { RichEditor } from "./Apps/RichEditor.mjs";
|
||||||
|
|
||||||
// Util imports
|
// Util imports
|
||||||
import { documentSorter } from "./consts.mjs";
|
import { documentSorter } from "./consts.mjs";
|
||||||
|
|
@ -19,6 +20,7 @@ Object.defineProperty(
|
||||||
CombinedHeroSheet,
|
CombinedHeroSheet,
|
||||||
HeroSummaryCardV1,
|
HeroSummaryCardV1,
|
||||||
HeroSkillsCardV1,
|
HeroSkillsCardV1,
|
||||||
|
RichEditor,
|
||||||
},
|
},
|
||||||
utils: {
|
utils: {
|
||||||
documentSorter,
|
documentSorter,
|
||||||
|
|
|
||||||
16
templates/Apps/RichEditor/content.hbs
Normal file
16
templates/Apps/RichEditor/content.hbs
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
<div>
|
||||||
|
{{#if editable}}
|
||||||
|
<prose-mirror
|
||||||
|
name="{{ path }}"
|
||||||
|
value="{{ raw }}"
|
||||||
|
{{ifThen compact "compact" ""}}
|
||||||
|
{{#if collaborative}}
|
||||||
|
data-document-uuid="{{ uuid }}"
|
||||||
|
{{/if}}
|
||||||
|
>
|
||||||
|
{{{ enriched }}}
|
||||||
|
</prose-mirror>
|
||||||
|
{{else}}
|
||||||
|
{{{ enriched }}}
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
19
templates/Apps/RichEditor/style.css
Normal file
19
templates/Apps/RichEditor/style.css
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
.ripcrypt--RichEditor {
|
||||||
|
width: 500px;
|
||||||
|
height: 600px;
|
||||||
|
|
||||||
|
> .window-content {
|
||||||
|
padding: 4px;
|
||||||
|
background: var(--base-background);
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
prose-mirror {
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.editor-content {
|
||||||
|
color: var(--input-text);
|
||||||
|
background: var(--input-background);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,3 +4,4 @@
|
||||||
@import url("./DicePool/style.css");
|
@import url("./DicePool/style.css");
|
||||||
@import url("./HeroSummaryCardV1/style.css");
|
@import url("./HeroSummaryCardV1/style.css");
|
||||||
@import url("./HeroSkillsCardV1/style.css");
|
@import url("./HeroSkillsCardV1/style.css");
|
||||||
|
@import url("./RichEditor/style.css");
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,12 @@
|
||||||
|
@layer exceptions;
|
||||||
|
|
||||||
@import url("./vars.css");
|
@import url("./vars.css");
|
||||||
|
|
||||||
@import url("./elements/button.css");
|
@import url("./elements/button.css");
|
||||||
@import url("./elements/input.css");
|
@import url("./elements/input.css");
|
||||||
@import url("./elements/lists.css");
|
@import url("./elements/lists.css");
|
||||||
@import url("./elements/pill-bar.css");
|
@import url("./elements/pill-bar.css");
|
||||||
|
@import url("./elements/prose-mirror.css") layer(exceptions);
|
||||||
@import url("./elements/select.css");
|
@import url("./elements/select.css");
|
||||||
@import url("./elements/span.css");
|
@import url("./elements/span.css");
|
||||||
@import url("./elements/string-tags.css");
|
@import url("./elements/string-tags.css");
|
||||||
|
|
|
||||||
3
templates/css/elements/prose-mirror.css
Normal file
3
templates/css/elements/prose-mirror.css
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
.ripcrypt prose-mirror * {
|
||||||
|
all: revert-layer !important;
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue