intelligent-system-design-language 0.3.21 → 0.3.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agents/langium-language-designer.md +38 -38
- package/.claude/agents/typescript-vscode-expert.md +29 -29
- package/.claude/agents/ui-ux-designer.md +36 -36
- package/.claude/settings.local.json +33 -33
- package/.idea/inspectionProfiles/Project_Default.xml +6 -6
- package/.idea/isdl.iml +13 -13
- package/.idea/modules.xml +8 -8
- package/.idea/vcs.xml +6 -6
- package/.idea/watcherTasks.xml +3 -3
- package/.vscodeignore +18 -18
- package/LICENSE +673 -673
- package/README.md +86 -86
- package/bin/cli.js +4 -4
- package/bin/lsp.js +8 -8
- package/out/_backgrounds.scss +91 -91
- package/out/_handlebars.scss +497 -497
- package/out/_isdlStyles.scss +1444 -1381
- package/out/_vuetifyOverrides.scss +425 -425
- package/out/_vuetifyStyles.scss +31957 -31957
- package/out/cli/components/_backgrounds.scss +91 -91
- package/out/cli/components/_handlebars.scss +497 -497
- package/out/cli/components/_isdlStyles.scss +1444 -1381
- package/out/cli/components/_vuetifyOverrides.scss +425 -425
- package/out/cli/components/_vuetifyStyles.scss +31957 -31957
- package/out/cli/components/active-effect-sheet-generator.js +453 -453
- package/out/cli/components/chat-card-generator.js +654 -651
- package/out/cli/components/chat-card-generator.js.map +1 -1
- package/out/cli/components/css-generator.js +4 -4
- package/out/cli/components/damage-roll-generator.js +160 -160
- package/out/cli/components/datamodel-generator.js +264 -257
- package/out/cli/components/datamodel-generator.js.map +1 -1
- package/out/cli/components/derived-data-generator.js +923 -923
- package/out/cli/components/hotbar-drop-hook-generator.js +82 -82
- package/out/cli/components/init-hook-generator.js +495 -495
- package/out/cli/components/language-generator.js +1 -1
- package/out/cli/components/language-generator.js.map +1 -1
- package/out/cli/components/measured-template-preview.js +221 -221
- package/out/cli/components/method-generator.js +979 -887
- package/out/cli/components/method-generator.js.map +1 -1
- package/out/cli/components/ready-hook-generator.js +404 -404
- package/out/cli/components/token-generator.js +116 -116
- package/out/cli/components/vue/base-components/vue-attribute.js +138 -138
- package/out/cli/components/vue/base-components/vue-boolean.js +64 -64
- package/out/cli/components/vue/base-components/vue-calculator.js +93 -93
- package/out/cli/components/vue/base-components/vue-damage-application.js +356 -356
- package/out/cli/components/vue/base-components/vue-damage-bonuses.js +165 -165
- package/out/cli/components/vue/base-components/vue-damage-resistances.js +196 -196
- package/out/cli/components/vue/base-components/vue-damage-track.js +121 -121
- package/out/cli/components/vue/base-components/vue-date-time.js +42 -42
- package/out/cli/components/vue/base-components/vue-dice.js +98 -98
- package/out/cli/components/vue/base-components/vue-die.js +73 -73
- package/out/cli/components/vue/base-components/vue-document-choice.js +149 -149
- package/out/cli/components/vue/base-components/vue-document-choices.js +179 -179
- package/out/cli/components/vue/base-components/vue-document-link.js +60 -60
- package/out/cli/components/vue/base-components/vue-extended-choice.js +88 -88
- package/out/cli/components/vue/base-components/vue-inventory.js +519 -519
- package/out/cli/components/vue/base-components/vue-macro-choice.js +138 -138
- package/out/cli/components/vue/base-components/vue-measured-template.js +530 -530
- package/out/cli/components/vue/base-components/vue-money.js +483 -483
- package/out/cli/components/vue/base-components/vue-number.js +174 -174
- package/out/cli/components/vue/base-components/vue-paperdoll.js +43 -43
- package/out/cli/components/vue/base-components/vue-parent-property-reference.js +76 -76
- package/out/cli/components/vue/base-components/vue-prosemirror.js +18 -18
- package/out/cli/components/vue/base-components/vue-resource.js +136 -136
- package/out/cli/components/vue/base-components/vue-roll-visualizer.js +286 -109
- package/out/cli/components/vue/base-components/vue-roll-visualizer.js.map +1 -1
- package/out/cli/components/vue/base-components/vue-self-property-reference.js +62 -62
- package/out/cli/components/vue/base-components/vue-string-choice.js +98 -98
- package/out/cli/components/vue/base-components/vue-string-choices.js +203 -203
- package/out/cli/components/vue/base-components/vue-string.js +60 -60
- package/out/cli/components/vue/base-components/vue-text-field.js +53 -53
- package/out/cli/components/vue/base-components/vue-tracker.js +431 -431
- package/out/cli/components/vue/vue-action-component-generator.js +64 -64
- package/out/cli/components/vue/vue-active-effect-sheet-generator.js +856 -856
- package/out/cli/components/vue/vue-datatable-sheet-class-generator.js +292 -292
- package/out/cli/components/vue/vue-datatable2-component-generator.js +824 -824
- package/out/cli/components/vue/vue-document-creation-app.js +121 -121
- package/out/cli/components/vue/vue-document-creation-sheet.js +94 -94
- package/out/cli/components/vue/vue-generator.js +40 -40
- package/out/cli/components/vue/vue-mixin.js +296 -296
- package/out/cli/components/vue/vue-pinned-datatable-component-generator.js +260 -260
- package/out/cli/components/vue/vue-prompt-generator.js +91 -76
- package/out/cli/components/vue/vue-prompt-generator.js.map +1 -1
- package/out/cli/components/vue/vue-prompt-sheet-class-generator.js +317 -317
- package/out/cli/components/vue/vue-sheet-application-generator.js +1177 -1167
- package/out/cli/components/vue/vue-sheet-application-generator.js.map +1 -1
- package/out/cli/components/vue/vue-sheet-class-generator.js +510 -510
- package/out/cli/generator.js +438 -433
- package/out/cli/generator.js.map +1 -1
- package/out/extension/github/githubAuthProvider.js +71 -29
- package/out/extension/github/githubAuthProvider.js.map +1 -1
- package/out/extension/github/githubGistManager.js +4 -3
- package/out/extension/github/githubGistManager.js.map +1 -1
- package/out/extension/github/githubManager.js +40 -38
- package/out/extension/github/githubManager.js.map +1 -1
- package/out/extension/github/githubQuickActions.js +120 -120
- package/out/extension/github/system-workflow.yml +47 -47
- package/out/extension/main.cjs +909 -532
- package/out/extension/main.cjs.map +3 -3
- package/out/extension/package.json +419 -419
- package/out/language/generated/ast.js +51 -2
- package/out/language/generated/ast.js.map +1 -1
- package/out/language/generated/grammar.js +14240 -13991
- package/out/language/generated/grammar.js.map +1 -1
- package/out/language/intelligent-system-design-language-validator.js +32 -2
- package/out/language/intelligent-system-design-language-validator.js.map +1 -1
- package/out/language/isdl-scope-provider.js +14 -1
- package/out/language/isdl-scope-provider.js.map +1 -1
- package/out/language/main.cjs +913 -569
- package/out/language/main.cjs.map +3 -3
- package/out/package.json +419 -419
- package/out/progressbar.min.js +6 -6
- package/out/styles.scss +762 -747
- package/out/test/validating/diagnostics.test.js +40 -0
- package/out/test/validating/diagnostics.test.js.map +1 -1
- package/package.json +419 -419
|
@@ -33,469 +33,469 @@ export function generateDocumentVueSheet(entry, id, document, destination) {
|
|
|
33
33
|
const functionName = toMachineIdentifier(functionDef.name);
|
|
34
34
|
console.log(`Generating function ${functionName} for ${document.name} Vue sheet.`);
|
|
35
35
|
if (functionDef.params.length > 0) {
|
|
36
|
-
return expandToNode `
|
|
37
|
-
async function_${functionName}(context, update, embeddedUpdate, parentUpdate, parentEmbeddedUpdate, targetUpdate, targetEmbeddedUpdate, ${joinToNode(functionDef.params, param => expandToNode `${param.param.name}`, { separator: ', ' })}) {
|
|
38
|
-
let system = context.object.system;
|
|
39
|
-
${translateBodyExpressionToJavascript(entry, id, functionDef.method.body, false, functionDef)}
|
|
40
|
-
}
|
|
36
|
+
return expandToNode `
|
|
37
|
+
async function_${functionName}(context, update, embeddedUpdate, parentUpdate, parentEmbeddedUpdate, targetUpdate, targetEmbeddedUpdate, ${joinToNode(functionDef.params, param => expandToNode `${param.param.name}`, { separator: ', ' })}) {
|
|
38
|
+
let system = context.object.system;
|
|
39
|
+
${translateBodyExpressionToJavascript(entry, id, functionDef.method.body, false, functionDef)}
|
|
40
|
+
}
|
|
41
41
|
`.appendNewLine();
|
|
42
42
|
}
|
|
43
43
|
// No-arg functions take the caller's `context` as their first argument too (the call site
|
|
44
44
|
// passes context regardless of arity). Deriving `system` from it — mirroring the param
|
|
45
45
|
// branch — keeps `self.*` (which compiles to `system.*`) and `context.object` both valid.
|
|
46
|
-
return expandToNode `
|
|
47
|
-
async function_${functionName}(context, update, embeddedUpdate, parentUpdate, parentEmbeddedUpdate, targetUpdate, targetEmbeddedUpdate) {
|
|
48
|
-
let system = context.object.system;
|
|
49
|
-
${translateBodyExpressionToJavascript(entry, id, functionDef.method.body, false, functionDef)}
|
|
50
|
-
}
|
|
46
|
+
return expandToNode `
|
|
47
|
+
async function_${functionName}(context, update, embeddedUpdate, parentUpdate, parentEmbeddedUpdate, targetUpdate, targetEmbeddedUpdate) {
|
|
48
|
+
let system = context.object.system;
|
|
49
|
+
${translateBodyExpressionToJavascript(entry, id, functionDef.method.body, false, functionDef)}
|
|
50
|
+
}
|
|
51
51
|
`.appendNewLine();
|
|
52
52
|
}
|
|
53
|
-
const fileNode = expandToNode `
|
|
54
|
-
import VueRenderingMixin from '../VueRenderingMixin.mjs';
|
|
55
|
-
import { ${document.name}${titleize(type)}App } from "../components/components.vue.es.mjs";
|
|
56
|
-
import ${entry.config.name}Roll from "../../../rolls/roll.mjs";
|
|
57
|
-
import ${entry.config.name}DamageRoll from "../../../rolls/damage-roll.mjs";
|
|
58
|
-
const { DOCUMENT_OWNERSHIP_LEVELS } = CONST;
|
|
59
|
-
|
|
60
|
-
export default class ${document.name}VueSheet extends VueRenderingMixin(foundry.applications.sheets.${titleize(type)}SheetV2) {
|
|
61
|
-
|
|
62
|
-
constructor(options = {}) {
|
|
63
|
-
super(options);
|
|
64
|
-
this.#dragDrop = this.#createDragDropHandlers();
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
vueParts = {
|
|
68
|
-
"${vueComponentName}": {
|
|
69
|
-
component: ${document.name}${titleize(type)}App,
|
|
70
|
-
template: "<${vueComponentName} :context=\\"context\\">Vue rendering for sheet failed.</${vueComponentName}>"
|
|
71
|
-
}
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
_arrayEntryKey = 0;
|
|
75
|
-
_renderKey = 0;
|
|
76
|
-
|
|
77
|
-
/** @override */
|
|
78
|
-
static DEFAULT_OPTIONS = {
|
|
79
|
-
classes: ["${id}", "sheet", "vue-sheet", "${type}", "${document.name.toLowerCase()}-sheet"],
|
|
80
|
-
viewPermission: DOCUMENT_OWNERSHIP_LEVELS.LIMITED,
|
|
81
|
-
editPermission: DOCUMENT_OWNERSHIP_LEVELS.OWNER,
|
|
82
|
-
position: {
|
|
83
|
-
width: ${sheetWidth},
|
|
84
|
-
height: ${sheetHeight},
|
|
85
|
-
},
|
|
86
|
-
window: {
|
|
87
|
-
resizable: true,
|
|
88
|
-
title: "${humanize(document.name)}",
|
|
89
|
-
controls: ${type == "item" ? expandToNode `[]` : expandToNode `[
|
|
90
|
-
{
|
|
91
|
-
action: "configurePrototypeToken",
|
|
92
|
-
icon: "fa-solid fa-user-circle",
|
|
93
|
-
label: "TOKEN.TitlePrototype",
|
|
94
|
-
ownership: "OWNER"
|
|
95
|
-
},
|
|
96
|
-
{
|
|
97
|
-
action: "showPortraitArtwork",
|
|
98
|
-
icon: "fa-solid fa-image",
|
|
99
|
-
label: "SIDEBAR.CharArt",
|
|
100
|
-
ownership: "OWNER"
|
|
101
|
-
},
|
|
102
|
-
{
|
|
103
|
-
action: "showTokenArtwork",
|
|
104
|
-
icon: "fa-solid fa-image",
|
|
105
|
-
label: "SIDEBAR.TokenArt",
|
|
106
|
-
ownership: "OWNER"
|
|
107
|
-
}
|
|
108
|
-
]`}
|
|
109
|
-
},
|
|
110
|
-
tag: "form",
|
|
111
|
-
actions: {
|
|
112
|
-
onEditImage: this._onEditImage
|
|
113
|
-
},
|
|
114
|
-
changeActions: {
|
|
115
|
-
},
|
|
116
|
-
// Custom property that's merged into this.options
|
|
117
|
-
dragDrop: [
|
|
118
|
-
{dragSelector: "tr", dropSelector: ".tabs-container, .datatable-drop-zone"},
|
|
119
|
-
{dropSelector: ".single-document"},
|
|
120
|
-
{dragSelector: ".paper-doll-slot", dropSelector: ".paper-doll-slot"},
|
|
121
|
-
{dragSelector: ".inventory-slot.filled", dropSelector: ".inventory-grid-container"}
|
|
122
|
-
],
|
|
123
|
-
form: {
|
|
124
|
-
submitOnChange: true,
|
|
125
|
-
submitOnClose: true,
|
|
126
|
-
closeOnSubmit: false,
|
|
127
|
-
}
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
async _prepareContext(options) {
|
|
131
|
-
// Output initialization
|
|
132
|
-
const context = {
|
|
133
|
-
// Validates both permissions and compendium status
|
|
134
|
-
editable: this.isEditable,
|
|
135
|
-
owner: this.document.isOwner,
|
|
136
|
-
limited: this.document.limited,
|
|
137
|
-
|
|
138
|
-
// Add the document.
|
|
139
|
-
object: this.document.toObject(),
|
|
140
|
-
document: this.document,
|
|
141
|
-
|
|
142
|
-
// Add the data to context.data for easier access, as well as flags.
|
|
143
|
-
system: this.document.system,
|
|
144
|
-
flags: this.document.flags,
|
|
145
|
-
|
|
146
|
-
// Roll data.
|
|
147
|
-
rollData: this.document.getRollData() ?? {},
|
|
148
|
-
|
|
149
|
-
// Editors
|
|
150
|
-
editors: {},
|
|
151
|
-
|
|
152
|
-
// Force re-renders. Defined in the vue mixin.
|
|
153
|
-
_renderKey: this._renderKey ?? 0,
|
|
154
|
-
_arrayEntryKey: this._arrayEntryKey ?? 0,
|
|
155
|
-
// tabs: this._getTabs(options.parts),
|
|
156
|
-
|
|
157
|
-
// Necessary for formInput and formFields helpers
|
|
158
|
-
fields: this.document.schema.fields,
|
|
159
|
-
systemFields: this.document.system.schema.fields
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
// Enrich editors
|
|
163
|
-
await this._enrichEditor(context, "description");
|
|
164
|
-
${joinToNode(htmlElements, htmlElement => expandToNode `await this._enrichEditor(context, "${htmlElement.name.toLowerCase()}");`, { appendNewLineIfNotEmpty: true })}
|
|
165
|
-
|
|
166
|
-
// Make another pass through the editors to fix the element contents.
|
|
167
|
-
for (let [field, editor] of Object.entries(context.editors)) {
|
|
168
|
-
if (context.editors[field].element) {
|
|
169
|
-
context.editors[field].element.innerHTML = context.editors[field].enriched;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
return context;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
async _enrichEditor(context, field) {
|
|
177
|
-
const enrichmentOptions = {
|
|
178
|
-
// Whether to show secret blocks in the finished html
|
|
179
|
-
secrets: this.document.isOwner,
|
|
180
|
-
// Data to fill in for inline rolls
|
|
181
|
-
rollData: this.document.getRollData() ?? {},
|
|
182
|
-
// Relative UUID resolution
|
|
183
|
-
relativeTo: this.document
|
|
184
|
-
};
|
|
185
|
-
|
|
186
|
-
const editorOptions = {
|
|
187
|
-
toggled: true,
|
|
188
|
-
collaborate: true,
|
|
189
|
-
documentUUID: this.document.uuid,
|
|
190
|
-
height: 300
|
|
191
|
-
};
|
|
192
|
-
|
|
193
|
-
const editorValue = this.document.system?.[field] ?? foundry.utils.getProperty(this.document.system, field);
|
|
194
|
-
context.editors[\`system.\${field}\`] = {
|
|
195
|
-
enriched: await TextEditor.enrichHTML(editorValue, enrichmentOptions),
|
|
196
|
-
element: foundry.applications.elements.HTMLProseMirrorElement.create({
|
|
197
|
-
...editorOptions,
|
|
198
|
-
name: \`system.\${field}\`,
|
|
199
|
-
value: editorValue ?? ""
|
|
200
|
-
})
|
|
201
|
-
};
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* Actions performed after any render of the Application.
|
|
206
|
-
* Post-render steps are not awaited by the render process.
|
|
207
|
-
* @param {ApplicationRenderContext} context Prepared context data
|
|
208
|
-
* @param {RenderOptions} options Provided render options
|
|
209
|
-
* @protected
|
|
210
|
-
*/
|
|
211
|
-
_onRender(context, options) {
|
|
212
|
-
this.#dragDrop.forEach((d) => d.bind(this.element));
|
|
213
|
-
// You may want to add other special handling here
|
|
214
|
-
// Foundry comes with a large number of utility classes, e.g. SearchFilter
|
|
215
|
-
// That you may want to implement yourself.
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* Handle changing a Document's image.
|
|
220
|
-
*
|
|
221
|
-
* @this ArchmageBaseItemSheetV2
|
|
222
|
-
* @param {PointerEvent} event The originating click event
|
|
223
|
-
* @param {HTMLElement} target The capturing HTML element which defined a [data-action]
|
|
224
|
-
* @returns {Promise}
|
|
225
|
-
* @protected
|
|
226
|
-
*/
|
|
227
|
-
static async _onEditImage(event, target) {
|
|
228
|
-
if (!this.isEditable) return false;
|
|
229
|
-
const attr = target.dataset.edit;
|
|
230
|
-
const current = foundry.utils.getProperty(this.document, attr);
|
|
231
|
-
const { img } = this.document.constructor.getDefaultArtwork?.(this.document.toObject()) ?? {};
|
|
232
|
-
const fp = new FilePicker({
|
|
233
|
-
current,
|
|
234
|
-
type: "image",
|
|
235
|
-
redirectToRoot: img ? [img] : [],
|
|
236
|
-
callback: (path) => {
|
|
237
|
-
target.src = path;
|
|
238
|
-
this.document.update({ [attr]: path });
|
|
239
|
-
this._renderKey++;
|
|
240
|
-
},
|
|
241
|
-
top: this.position.top + 40,
|
|
242
|
-
left: this.position.left + 10
|
|
243
|
-
});
|
|
244
|
-
return fp.browse();
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
_prepareSubmitData(event, form, formData) {
|
|
248
|
-
// We don't modify the image via the sheet itself, so we can remove it from the submit data to avoid errors.
|
|
249
|
-
delete formData.object.img;
|
|
250
|
-
return super._prepareSubmitData(event, form, formData);
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
// Drag and Drop
|
|
254
|
-
|
|
255
|
-
/**
|
|
256
|
-
* Returns an array of DragDrop instances
|
|
257
|
-
* @type {DragDrop[]}
|
|
258
|
-
*/
|
|
259
|
-
get dragDrop() {
|
|
260
|
-
return this.#dragDrop;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
/**
|
|
264
|
-
* Define whether a user is able to begin a dragstart workflow for a given drag selector
|
|
265
|
-
* @param {string} selector The candidate HTML selector for dragging
|
|
266
|
-
* @returns {boolean} Can the current user drag this selector?
|
|
267
|
-
* @protected
|
|
268
|
-
*/
|
|
269
|
-
_canDragStart(selector) {
|
|
270
|
-
return this.isEditable;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
/**
|
|
274
|
-
* Define whether a user is able to conclude a drag-and-drop workflow for a given drop selector
|
|
275
|
-
* @param {string} selector The candidate HTML selector for the drop target
|
|
276
|
-
* @returns {boolean} Can the current user drop on this selector?
|
|
277
|
-
* @protected
|
|
278
|
-
*/
|
|
279
|
-
_canDragDrop(selector) {
|
|
280
|
-
return this.isEditable;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
/**
|
|
284
|
-
* Callback actions which occur at the beginning of a drag start workflow.
|
|
285
|
-
* @param {DragEvent} event The originating DragEvent
|
|
286
|
-
* @protected
|
|
287
|
-
*/
|
|
288
|
-
_onDragStart(event) {
|
|
289
|
-
if (event.currentTarget.classList.contains("paper-doll-slot")) {
|
|
290
|
-
// Remove the item from the slot
|
|
291
|
-
const name = event.currentTarget.dataset.name;
|
|
292
|
-
const update = {};
|
|
293
|
-
update[name] = null;
|
|
294
|
-
this.document.update(update);
|
|
295
|
-
}
|
|
296
|
-
else if (event.currentTarget.classList.contains("inventory-slot")) {
|
|
297
|
-
// Inventory slots - data is set by Vue component's @dragstart handler
|
|
298
|
-
// Nothing to do here, the Vue component handles it
|
|
299
|
-
return;
|
|
300
|
-
}
|
|
301
|
-
else {
|
|
302
|
-
// For table rows, currentTarget should already be the tr element
|
|
303
|
-
const tr = event.currentTarget.tagName === "TR" ? event.currentTarget : event.currentTarget.closest("tr");
|
|
304
|
-
if (tr) {
|
|
305
|
-
// Try to get UUID from data attributes
|
|
306
|
-
let uuid = tr.dataset.uuid;
|
|
307
|
-
let type = tr.dataset.type;
|
|
308
|
-
|
|
309
|
-
// If not found, try to get from item map (for Vuetify tables)
|
|
310
|
-
if (!uuid && tr.dataset.itemId && tr.dataset.documentId) {
|
|
311
|
-
const itemMap = window.isdlItemMaps?.get(tr.dataset.documentId);
|
|
312
|
-
if (itemMap) {
|
|
313
|
-
const item = itemMap.value.get(tr.dataset.itemId);
|
|
314
|
-
if (item) {
|
|
315
|
-
uuid = item.uuid;
|
|
316
|
-
type = item.type || 'Item';
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
if (!uuid) {
|
|
322
|
-
console.error("No UUID found on tr element", tr);
|
|
323
|
-
return;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
const data = {
|
|
327
|
-
type: type == "ActiveEffect" ? "ActiveEffect" : "Item",
|
|
328
|
-
uuid: uuid
|
|
329
|
-
};
|
|
330
|
-
|
|
331
|
-
event.dataTransfer.setData("text/plain", JSON.stringify(data));
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
/**
|
|
337
|
-
* Callback actions which occur when a dragged element is over a drop target.
|
|
338
|
-
* @param {DragEvent} event The originating DragEvent
|
|
339
|
-
* @protected
|
|
340
|
-
*/
|
|
341
|
-
_onDragOver(event) {}
|
|
342
|
-
|
|
343
|
-
/* -------------------------------------------- */
|
|
344
|
-
|
|
345
|
-
async _onDrop(event) {
|
|
346
|
-
const data = JSON.parse(event.dataTransfer.getData("text/plain"));
|
|
347
|
-
|
|
348
|
-
// If the drop target is a single document, handle it differently
|
|
349
|
-
const linkedClasses = [ "single-document", "paper-doll-slot" ];
|
|
350
|
-
const eventClasses = Array.from(event.currentTarget.classList);
|
|
351
|
-
if (eventClasses.find(c => linkedClasses.includes(c))) {
|
|
352
|
-
const doc = await fromUuid(data.uuid);
|
|
353
|
-
if ( !doc ) return;
|
|
354
|
-
if ( doc.type !== event.currentTarget.dataset.type ) {
|
|
355
|
-
ui.notifications.error(\`Expected a \${event.currentTarget.dataset.type} type Document, but got a \${doc.type} type one instead. \`);
|
|
356
|
-
return;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
const update = {};
|
|
360
|
-
update[event.currentTarget.dataset.name] = data.uuid;
|
|
361
|
-
await this.document.update(update);
|
|
362
|
-
return;
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
const dropTypes = ["Item", "ActiveEffect"];
|
|
366
|
-
if ( !dropTypes.includes(data.type) ) return;
|
|
367
|
-
const item = await fromUuid(data.uuid);
|
|
368
|
-
if ( !item ) return;
|
|
369
|
-
|
|
370
|
-
// Prevent duplicates when dropping an item that's already owned by this document
|
|
371
|
-
if ( item.parent?.uuid === this.document.uuid ) return;
|
|
372
|
-
|
|
373
|
-
if ( data.type === "ActiveEffect" ) {
|
|
374
|
-
ActiveEffect.createDocuments([item], {parent: this.document})
|
|
375
|
-
return;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
Item.createDocuments([item], {parent: this.document})
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
/* -------------------------------------------- */
|
|
382
|
-
|
|
383
|
-
/**
|
|
384
|
-
* Returns an array of DragDrop instances
|
|
385
|
-
* @type {DragDrop[]}
|
|
386
|
-
*/
|
|
387
|
-
get dragDrop() {
|
|
388
|
-
return this.#dragDrop;
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
// This is marked as private because there's no real need
|
|
392
|
-
// for subclasses or external hooks to mess with it directly
|
|
393
|
-
#dragDrop;
|
|
394
|
-
|
|
395
|
-
/**
|
|
396
|
-
* Create drag-and-drop workflow handlers for this Application
|
|
397
|
-
* @returns {DragDrop[]} An array of DragDrop handlers
|
|
398
|
-
* @private
|
|
399
|
-
*/
|
|
400
|
-
#createDragDropHandlers() {
|
|
401
|
-
return this.options.dragDrop.map((d) => {
|
|
402
|
-
d.permissions = {
|
|
403
|
-
dragstart: this._canDragStart.bind(this),
|
|
404
|
-
drop: this._canDragDrop.bind(this)
|
|
405
|
-
};
|
|
406
|
-
d.callbacks = {
|
|
407
|
-
dragstart: this._onDragStart.bind(this),
|
|
408
|
-
dragover: this._onDragOver.bind(this),
|
|
409
|
-
drop: this._onDrop.bind(this)
|
|
410
|
-
};
|
|
411
|
-
return new DragDrop(d);
|
|
412
|
-
});
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
/* -------------------------------------------- */
|
|
416
|
-
|
|
417
|
-
async _onAction(event) {
|
|
418
|
-
if (event.preventDefault) event.preventDefault();
|
|
419
|
-
const action = event.currentTarget.dataset.action;
|
|
420
|
-
switch ( action ) {
|
|
421
|
-
${joinToNode(actions, property => `case "${property.name.toLowerCase()}": this._on${property.name}Action(event, this.document.system); break;`, { appendNewLineIfNotEmpty: true })}
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
${joinToNode(actions, property => generateAction(property), { appendNewLineIfNotEmpty: true })}
|
|
426
|
-
|
|
427
|
-
/* -------------------------------------------- */
|
|
428
|
-
|
|
429
|
-
// Attribute click handlers (function: param)
|
|
430
|
-
${joinToNode(attributeFunctions, generateAttributeFunctionMethod, { appendNewLineIfNotEmpty: true })}
|
|
431
|
-
|
|
432
|
-
/* -------------------------------------------- */
|
|
433
|
-
|
|
434
|
-
// User defined methods
|
|
435
|
-
${joinToNode(functions, generateFunctionDefinition, { appendNewLineIfNotEmpty: true })}
|
|
436
|
-
}
|
|
53
|
+
const fileNode = expandToNode `
|
|
54
|
+
import VueRenderingMixin from '../VueRenderingMixin.mjs';
|
|
55
|
+
import { ${document.name}${titleize(type)}App } from "../components/components.vue.es.mjs";
|
|
56
|
+
import ${entry.config.name}Roll from "../../../rolls/roll.mjs";
|
|
57
|
+
import ${entry.config.name}DamageRoll from "../../../rolls/damage-roll.mjs";
|
|
58
|
+
const { DOCUMENT_OWNERSHIP_LEVELS } = CONST;
|
|
59
|
+
|
|
60
|
+
export default class ${document.name}VueSheet extends VueRenderingMixin(foundry.applications.sheets.${titleize(type)}SheetV2) {
|
|
61
|
+
|
|
62
|
+
constructor(options = {}) {
|
|
63
|
+
super(options);
|
|
64
|
+
this.#dragDrop = this.#createDragDropHandlers();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
vueParts = {
|
|
68
|
+
"${vueComponentName}": {
|
|
69
|
+
component: ${document.name}${titleize(type)}App,
|
|
70
|
+
template: "<${vueComponentName} :context=\\"context\\">Vue rendering for sheet failed.</${vueComponentName}>"
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
_arrayEntryKey = 0;
|
|
75
|
+
_renderKey = 0;
|
|
76
|
+
|
|
77
|
+
/** @override */
|
|
78
|
+
static DEFAULT_OPTIONS = {
|
|
79
|
+
classes: ["${id}", "sheet", "vue-sheet", "${type}", "${document.name.toLowerCase()}-sheet"],
|
|
80
|
+
viewPermission: DOCUMENT_OWNERSHIP_LEVELS.LIMITED,
|
|
81
|
+
editPermission: DOCUMENT_OWNERSHIP_LEVELS.OWNER,
|
|
82
|
+
position: {
|
|
83
|
+
width: ${sheetWidth},
|
|
84
|
+
height: ${sheetHeight},
|
|
85
|
+
},
|
|
86
|
+
window: {
|
|
87
|
+
resizable: true,
|
|
88
|
+
title: "${humanize(document.name)}",
|
|
89
|
+
controls: ${type == "item" ? expandToNode `[]` : expandToNode `[
|
|
90
|
+
{
|
|
91
|
+
action: "configurePrototypeToken",
|
|
92
|
+
icon: "fa-solid fa-user-circle",
|
|
93
|
+
label: "TOKEN.TitlePrototype",
|
|
94
|
+
ownership: "OWNER"
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
action: "showPortraitArtwork",
|
|
98
|
+
icon: "fa-solid fa-image",
|
|
99
|
+
label: "SIDEBAR.CharArt",
|
|
100
|
+
ownership: "OWNER"
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
action: "showTokenArtwork",
|
|
104
|
+
icon: "fa-solid fa-image",
|
|
105
|
+
label: "SIDEBAR.TokenArt",
|
|
106
|
+
ownership: "OWNER"
|
|
107
|
+
}
|
|
108
|
+
]`}
|
|
109
|
+
},
|
|
110
|
+
tag: "form",
|
|
111
|
+
actions: {
|
|
112
|
+
onEditImage: this._onEditImage
|
|
113
|
+
},
|
|
114
|
+
changeActions: {
|
|
115
|
+
},
|
|
116
|
+
// Custom property that's merged into this.options
|
|
117
|
+
dragDrop: [
|
|
118
|
+
{dragSelector: "tr", dropSelector: ".tabs-container, .datatable-drop-zone"},
|
|
119
|
+
{dropSelector: ".single-document"},
|
|
120
|
+
{dragSelector: ".paper-doll-slot", dropSelector: ".paper-doll-slot"},
|
|
121
|
+
{dragSelector: ".inventory-slot.filled", dropSelector: ".inventory-grid-container"}
|
|
122
|
+
],
|
|
123
|
+
form: {
|
|
124
|
+
submitOnChange: true,
|
|
125
|
+
submitOnClose: true,
|
|
126
|
+
closeOnSubmit: false,
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
async _prepareContext(options) {
|
|
131
|
+
// Output initialization
|
|
132
|
+
const context = {
|
|
133
|
+
// Validates both permissions and compendium status
|
|
134
|
+
editable: this.isEditable,
|
|
135
|
+
owner: this.document.isOwner,
|
|
136
|
+
limited: this.document.limited,
|
|
137
|
+
|
|
138
|
+
// Add the document.
|
|
139
|
+
object: this.document.toObject(),
|
|
140
|
+
document: this.document,
|
|
141
|
+
|
|
142
|
+
// Add the data to context.data for easier access, as well as flags.
|
|
143
|
+
system: this.document.system,
|
|
144
|
+
flags: this.document.flags,
|
|
145
|
+
|
|
146
|
+
// Roll data.
|
|
147
|
+
rollData: this.document.getRollData() ?? {},
|
|
148
|
+
|
|
149
|
+
// Editors
|
|
150
|
+
editors: {},
|
|
151
|
+
|
|
152
|
+
// Force re-renders. Defined in the vue mixin.
|
|
153
|
+
_renderKey: this._renderKey ?? 0,
|
|
154
|
+
_arrayEntryKey: this._arrayEntryKey ?? 0,
|
|
155
|
+
// tabs: this._getTabs(options.parts),
|
|
156
|
+
|
|
157
|
+
// Necessary for formInput and formFields helpers
|
|
158
|
+
fields: this.document.schema.fields,
|
|
159
|
+
systemFields: this.document.system.schema.fields
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
// Enrich editors
|
|
163
|
+
await this._enrichEditor(context, "description");
|
|
164
|
+
${joinToNode(htmlElements, htmlElement => expandToNode `await this._enrichEditor(context, "${htmlElement.name.toLowerCase()}");`, { appendNewLineIfNotEmpty: true })}
|
|
165
|
+
|
|
166
|
+
// Make another pass through the editors to fix the element contents.
|
|
167
|
+
for (let [field, editor] of Object.entries(context.editors)) {
|
|
168
|
+
if (context.editors[field].element) {
|
|
169
|
+
context.editors[field].element.innerHTML = context.editors[field].enriched;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return context;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
async _enrichEditor(context, field) {
|
|
177
|
+
const enrichmentOptions = {
|
|
178
|
+
// Whether to show secret blocks in the finished html
|
|
179
|
+
secrets: this.document.isOwner,
|
|
180
|
+
// Data to fill in for inline rolls
|
|
181
|
+
rollData: this.document.getRollData() ?? {},
|
|
182
|
+
// Relative UUID resolution
|
|
183
|
+
relativeTo: this.document
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
const editorOptions = {
|
|
187
|
+
toggled: true,
|
|
188
|
+
collaborate: true,
|
|
189
|
+
documentUUID: this.document.uuid,
|
|
190
|
+
height: 300
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
const editorValue = this.document.system?.[field] ?? foundry.utils.getProperty(this.document.system, field);
|
|
194
|
+
context.editors[\`system.\${field}\`] = {
|
|
195
|
+
enriched: await TextEditor.enrichHTML(editorValue, enrichmentOptions),
|
|
196
|
+
element: foundry.applications.elements.HTMLProseMirrorElement.create({
|
|
197
|
+
...editorOptions,
|
|
198
|
+
name: \`system.\${field}\`,
|
|
199
|
+
value: editorValue ?? ""
|
|
200
|
+
})
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Actions performed after any render of the Application.
|
|
206
|
+
* Post-render steps are not awaited by the render process.
|
|
207
|
+
* @param {ApplicationRenderContext} context Prepared context data
|
|
208
|
+
* @param {RenderOptions} options Provided render options
|
|
209
|
+
* @protected
|
|
210
|
+
*/
|
|
211
|
+
_onRender(context, options) {
|
|
212
|
+
this.#dragDrop.forEach((d) => d.bind(this.element));
|
|
213
|
+
// You may want to add other special handling here
|
|
214
|
+
// Foundry comes with a large number of utility classes, e.g. SearchFilter
|
|
215
|
+
// That you may want to implement yourself.
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Handle changing a Document's image.
|
|
220
|
+
*
|
|
221
|
+
* @this ArchmageBaseItemSheetV2
|
|
222
|
+
* @param {PointerEvent} event The originating click event
|
|
223
|
+
* @param {HTMLElement} target The capturing HTML element which defined a [data-action]
|
|
224
|
+
* @returns {Promise}
|
|
225
|
+
* @protected
|
|
226
|
+
*/
|
|
227
|
+
static async _onEditImage(event, target) {
|
|
228
|
+
if (!this.isEditable) return false;
|
|
229
|
+
const attr = target.dataset.edit;
|
|
230
|
+
const current = foundry.utils.getProperty(this.document, attr);
|
|
231
|
+
const { img } = this.document.constructor.getDefaultArtwork?.(this.document.toObject()) ?? {};
|
|
232
|
+
const fp = new FilePicker({
|
|
233
|
+
current,
|
|
234
|
+
type: "image",
|
|
235
|
+
redirectToRoot: img ? [img] : [],
|
|
236
|
+
callback: (path) => {
|
|
237
|
+
target.src = path;
|
|
238
|
+
this.document.update({ [attr]: path });
|
|
239
|
+
this._renderKey++;
|
|
240
|
+
},
|
|
241
|
+
top: this.position.top + 40,
|
|
242
|
+
left: this.position.left + 10
|
|
243
|
+
});
|
|
244
|
+
return fp.browse();
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
_prepareSubmitData(event, form, formData) {
|
|
248
|
+
// We don't modify the image via the sheet itself, so we can remove it from the submit data to avoid errors.
|
|
249
|
+
delete formData.object.img;
|
|
250
|
+
return super._prepareSubmitData(event, form, formData);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Drag and Drop
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Returns an array of DragDrop instances
|
|
257
|
+
* @type {DragDrop[]}
|
|
258
|
+
*/
|
|
259
|
+
get dragDrop() {
|
|
260
|
+
return this.#dragDrop;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Define whether a user is able to begin a dragstart workflow for a given drag selector
|
|
265
|
+
* @param {string} selector The candidate HTML selector for dragging
|
|
266
|
+
* @returns {boolean} Can the current user drag this selector?
|
|
267
|
+
* @protected
|
|
268
|
+
*/
|
|
269
|
+
_canDragStart(selector) {
|
|
270
|
+
return this.isEditable;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Define whether a user is able to conclude a drag-and-drop workflow for a given drop selector
|
|
275
|
+
* @param {string} selector The candidate HTML selector for the drop target
|
|
276
|
+
* @returns {boolean} Can the current user drop on this selector?
|
|
277
|
+
* @protected
|
|
278
|
+
*/
|
|
279
|
+
_canDragDrop(selector) {
|
|
280
|
+
return this.isEditable;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Callback actions which occur at the beginning of a drag start workflow.
|
|
285
|
+
* @param {DragEvent} event The originating DragEvent
|
|
286
|
+
* @protected
|
|
287
|
+
*/
|
|
288
|
+
_onDragStart(event) {
|
|
289
|
+
if (event.currentTarget.classList.contains("paper-doll-slot")) {
|
|
290
|
+
// Remove the item from the slot
|
|
291
|
+
const name = event.currentTarget.dataset.name;
|
|
292
|
+
const update = {};
|
|
293
|
+
update[name] = null;
|
|
294
|
+
this.document.update(update);
|
|
295
|
+
}
|
|
296
|
+
else if (event.currentTarget.classList.contains("inventory-slot")) {
|
|
297
|
+
// Inventory slots - data is set by Vue component's @dragstart handler
|
|
298
|
+
// Nothing to do here, the Vue component handles it
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
else {
|
|
302
|
+
// For table rows, currentTarget should already be the tr element
|
|
303
|
+
const tr = event.currentTarget.tagName === "TR" ? event.currentTarget : event.currentTarget.closest("tr");
|
|
304
|
+
if (tr) {
|
|
305
|
+
// Try to get UUID from data attributes
|
|
306
|
+
let uuid = tr.dataset.uuid;
|
|
307
|
+
let type = tr.dataset.type;
|
|
308
|
+
|
|
309
|
+
// If not found, try to get from item map (for Vuetify tables)
|
|
310
|
+
if (!uuid && tr.dataset.itemId && tr.dataset.documentId) {
|
|
311
|
+
const itemMap = window.isdlItemMaps?.get(tr.dataset.documentId);
|
|
312
|
+
if (itemMap) {
|
|
313
|
+
const item = itemMap.value.get(tr.dataset.itemId);
|
|
314
|
+
if (item) {
|
|
315
|
+
uuid = item.uuid;
|
|
316
|
+
type = item.type || 'Item';
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if (!uuid) {
|
|
322
|
+
console.error("No UUID found on tr element", tr);
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const data = {
|
|
327
|
+
type: type == "ActiveEffect" ? "ActiveEffect" : "Item",
|
|
328
|
+
uuid: uuid
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
event.dataTransfer.setData("text/plain", JSON.stringify(data));
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Callback actions which occur when a dragged element is over a drop target.
|
|
338
|
+
* @param {DragEvent} event The originating DragEvent
|
|
339
|
+
* @protected
|
|
340
|
+
*/
|
|
341
|
+
_onDragOver(event) {}
|
|
342
|
+
|
|
343
|
+
/* -------------------------------------------- */
|
|
344
|
+
|
|
345
|
+
async _onDrop(event) {
|
|
346
|
+
const data = JSON.parse(event.dataTransfer.getData("text/plain"));
|
|
347
|
+
|
|
348
|
+
// If the drop target is a single document, handle it differently
|
|
349
|
+
const linkedClasses = [ "single-document", "paper-doll-slot" ];
|
|
350
|
+
const eventClasses = Array.from(event.currentTarget.classList);
|
|
351
|
+
if (eventClasses.find(c => linkedClasses.includes(c))) {
|
|
352
|
+
const doc = await fromUuid(data.uuid);
|
|
353
|
+
if ( !doc ) return;
|
|
354
|
+
if ( doc.type !== event.currentTarget.dataset.type ) {
|
|
355
|
+
ui.notifications.error(\`Expected a \${event.currentTarget.dataset.type} type Document, but got a \${doc.type} type one instead. \`);
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
const update = {};
|
|
360
|
+
update[event.currentTarget.dataset.name] = data.uuid;
|
|
361
|
+
await this.document.update(update);
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
const dropTypes = ["Item", "ActiveEffect"];
|
|
366
|
+
if ( !dropTypes.includes(data.type) ) return;
|
|
367
|
+
const item = await fromUuid(data.uuid);
|
|
368
|
+
if ( !item ) return;
|
|
369
|
+
|
|
370
|
+
// Prevent duplicates when dropping an item that's already owned by this document
|
|
371
|
+
if ( item.parent?.uuid === this.document.uuid ) return;
|
|
372
|
+
|
|
373
|
+
if ( data.type === "ActiveEffect" ) {
|
|
374
|
+
ActiveEffect.createDocuments([item], {parent: this.document})
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
Item.createDocuments([item], {parent: this.document})
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/* -------------------------------------------- */
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Returns an array of DragDrop instances
|
|
385
|
+
* @type {DragDrop[]}
|
|
386
|
+
*/
|
|
387
|
+
get dragDrop() {
|
|
388
|
+
return this.#dragDrop;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// This is marked as private because there's no real need
|
|
392
|
+
// for subclasses or external hooks to mess with it directly
|
|
393
|
+
#dragDrop;
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Create drag-and-drop workflow handlers for this Application
|
|
397
|
+
* @returns {DragDrop[]} An array of DragDrop handlers
|
|
398
|
+
* @private
|
|
399
|
+
*/
|
|
400
|
+
#createDragDropHandlers() {
|
|
401
|
+
return this.options.dragDrop.map((d) => {
|
|
402
|
+
d.permissions = {
|
|
403
|
+
dragstart: this._canDragStart.bind(this),
|
|
404
|
+
drop: this._canDragDrop.bind(this)
|
|
405
|
+
};
|
|
406
|
+
d.callbacks = {
|
|
407
|
+
dragstart: this._onDragStart.bind(this),
|
|
408
|
+
dragover: this._onDragOver.bind(this),
|
|
409
|
+
drop: this._onDrop.bind(this)
|
|
410
|
+
};
|
|
411
|
+
return new DragDrop(d);
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/* -------------------------------------------- */
|
|
416
|
+
|
|
417
|
+
async _onAction(event) {
|
|
418
|
+
if (event.preventDefault) event.preventDefault();
|
|
419
|
+
const action = event.currentTarget.dataset.action;
|
|
420
|
+
switch ( action ) {
|
|
421
|
+
${joinToNode(actions, property => `case "${property.name.toLowerCase()}": this._on${property.name}Action(event, this.document.system); break;`, { appendNewLineIfNotEmpty: true })}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
${joinToNode(actions, property => generateAction(property), { appendNewLineIfNotEmpty: true })}
|
|
426
|
+
|
|
427
|
+
/* -------------------------------------------- */
|
|
428
|
+
|
|
429
|
+
// Attribute click handlers (function: param)
|
|
430
|
+
${joinToNode(attributeFunctions, generateAttributeFunctionMethod, { appendNewLineIfNotEmpty: true })}
|
|
431
|
+
|
|
432
|
+
/* -------------------------------------------- */
|
|
433
|
+
|
|
434
|
+
// User defined methods
|
|
435
|
+
${joinToNode(functions, generateFunctionDefinition, { appendNewLineIfNotEmpty: true })}
|
|
436
|
+
}
|
|
437
437
|
`.appendNewLineIfNotEmpty();
|
|
438
438
|
fs.writeFileSync(generatedFilePath, toString(fileNode));
|
|
439
439
|
function generateAction(action) {
|
|
440
440
|
console.log(`Generating action ${action.name} for ${document.name} Vue sheet.`);
|
|
441
|
-
return expandToNode `
|
|
442
|
-
|
|
443
|
-
/* -------------------------------------------- */
|
|
444
|
-
|
|
445
|
-
async _on${action.name}Action(event, system) {
|
|
446
|
-
if (event.preventDefault) event.preventDefault();
|
|
447
|
-
let update = {};
|
|
448
|
-
let embeddedUpdate = {};
|
|
449
|
-
let parentUpdate = {};
|
|
450
|
-
let parentEmbeddedUpdate = {};
|
|
451
|
-
let targetUpdate = {};
|
|
452
|
-
let targetEmbeddedUpdate = {};
|
|
453
|
-
let selfDeleted = false;
|
|
454
|
-
let rerender = false;
|
|
455
|
-
let document = this.document;
|
|
456
|
-
const context = {
|
|
457
|
-
object: this.document,
|
|
458
|
-
target: game.user.getTargetOrNothing()
|
|
459
|
-
};
|
|
460
|
-
// If this is an item, attach the parent
|
|
461
|
-
if (document.documentName === "Item" && document.parent) {
|
|
462
|
-
context.actor = document.parent;
|
|
463
|
-
}
|
|
464
|
-
else {
|
|
465
|
-
context.actor = document;
|
|
466
|
-
}
|
|
467
|
-
${translateExpression(entry, id, action.method, false, action)}
|
|
468
|
-
if (!selfDeleted && Object.keys(update).length > 0) {
|
|
469
|
-
await this.document.update(update);
|
|
470
|
-
rerender = true;
|
|
471
|
-
}
|
|
472
|
-
if (!selfDeleted && Object.keys(embeddedUpdate).length > 0) {
|
|
473
|
-
for (let key of Object.keys(embeddedUpdate)) {
|
|
474
|
-
await this.document.updateEmbeddedDocuments("Item", embeddedUpdate[key]);
|
|
475
|
-
}
|
|
476
|
-
rerender = true;
|
|
477
|
-
}
|
|
478
|
-
if (Object.keys(parentUpdate).length > 0) {
|
|
479
|
-
await this.document.parent.update(parentUpdate);
|
|
480
|
-
rerender = true;
|
|
481
|
-
}
|
|
482
|
-
if (Object.keys(parentEmbeddedUpdate).length > 0) {
|
|
483
|
-
for (let key of Object.keys(parentEmbeddedUpdate)) {
|
|
484
|
-
await document.parent.updateEmbeddedDocuments("Item", parentEmbeddedUpdate[key]);
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
if (Object.keys(targetUpdate).length > 0) {
|
|
488
|
-
await context.target.update(targetUpdate);
|
|
489
|
-
}
|
|
490
|
-
if (Object.keys(targetEmbeddedUpdate).length > 0) {
|
|
491
|
-
for (let key of Object.keys(targetEmbeddedUpdate)) {
|
|
492
|
-
await context.target.updateEmbeddedDocuments("Item", targetEmbeddedUpdate[key]);
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
if (rerender) {
|
|
496
|
-
this.render();
|
|
497
|
-
}
|
|
498
|
-
}
|
|
441
|
+
return expandToNode `
|
|
442
|
+
|
|
443
|
+
/* -------------------------------------------- */
|
|
444
|
+
|
|
445
|
+
async _on${action.name}Action(event, system) {
|
|
446
|
+
if (event.preventDefault) event.preventDefault();
|
|
447
|
+
let update = {};
|
|
448
|
+
let embeddedUpdate = {};
|
|
449
|
+
let parentUpdate = {};
|
|
450
|
+
let parentEmbeddedUpdate = {};
|
|
451
|
+
let targetUpdate = {};
|
|
452
|
+
let targetEmbeddedUpdate = {};
|
|
453
|
+
let selfDeleted = false;
|
|
454
|
+
let rerender = false;
|
|
455
|
+
let document = this.document;
|
|
456
|
+
const context = {
|
|
457
|
+
object: this.document,
|
|
458
|
+
target: game.user.getTargetOrNothing()
|
|
459
|
+
};
|
|
460
|
+
// If this is an item, attach the parent
|
|
461
|
+
if (document.documentName === "Item" && document.parent) {
|
|
462
|
+
context.actor = document.parent;
|
|
463
|
+
}
|
|
464
|
+
else {
|
|
465
|
+
context.actor = document;
|
|
466
|
+
}
|
|
467
|
+
${translateExpression(entry, id, action.method, false, action)}
|
|
468
|
+
if (!selfDeleted && Object.keys(update).length > 0) {
|
|
469
|
+
await this.document.update(update);
|
|
470
|
+
rerender = true;
|
|
471
|
+
}
|
|
472
|
+
if (!selfDeleted && Object.keys(embeddedUpdate).length > 0) {
|
|
473
|
+
for (let key of Object.keys(embeddedUpdate)) {
|
|
474
|
+
await this.document.updateEmbeddedDocuments("Item", embeddedUpdate[key]);
|
|
475
|
+
}
|
|
476
|
+
rerender = true;
|
|
477
|
+
}
|
|
478
|
+
if (Object.keys(parentUpdate).length > 0) {
|
|
479
|
+
await this.document.parent.update(parentUpdate);
|
|
480
|
+
rerender = true;
|
|
481
|
+
}
|
|
482
|
+
if (Object.keys(parentEmbeddedUpdate).length > 0) {
|
|
483
|
+
for (let key of Object.keys(parentEmbeddedUpdate)) {
|
|
484
|
+
await document.parent.updateEmbeddedDocuments("Item", parentEmbeddedUpdate[key]);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
if (Object.keys(targetUpdate).length > 0) {
|
|
488
|
+
await context.target.update(targetUpdate);
|
|
489
|
+
}
|
|
490
|
+
if (Object.keys(targetEmbeddedUpdate).length > 0) {
|
|
491
|
+
for (let key of Object.keys(targetEmbeddedUpdate)) {
|
|
492
|
+
await context.target.updateEmbeddedDocuments("Item", targetEmbeddedUpdate[key]);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
if (rerender) {
|
|
496
|
+
this.render();
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
499
|
`;
|
|
500
500
|
}
|
|
501
501
|
// Generates a sheet method that runs an attribute's `function:` body with the same update/flush
|
|
@@ -504,64 +504,64 @@ export function generateDocumentVueSheet(entry, id, document, destination) {
|
|
|
504
504
|
function generateAttributeFunctionMethod({ attr, param }) {
|
|
505
505
|
const functionDef = param.function.ref;
|
|
506
506
|
console.log(`Generating attribute function handler ${attr.name} -> ${functionDef.name} for ${document.name} Vue sheet.`);
|
|
507
|
-
return expandToNode `
|
|
508
|
-
|
|
509
|
-
/* -------------------------------------------- */
|
|
510
|
-
|
|
511
|
-
async _on${attr.name}AttributeFunction(event) {
|
|
512
|
-
if (event?.preventDefault) event.preventDefault();
|
|
513
|
-
let update = {};
|
|
514
|
-
let embeddedUpdate = {};
|
|
515
|
-
let parentUpdate = {};
|
|
516
|
-
let parentEmbeddedUpdate = {};
|
|
517
|
-
let targetUpdate = {};
|
|
518
|
-
let targetEmbeddedUpdate = {};
|
|
519
|
-
let selfDeleted = false;
|
|
520
|
-
let rerender = false;
|
|
521
|
-
let document = this.document;
|
|
522
|
-
const context = {
|
|
523
|
-
object: this.document,
|
|
524
|
-
target: game.user.getTargetOrNothing()
|
|
525
|
-
};
|
|
526
|
-
// If this is an item, attach the parent
|
|
527
|
-
if (document.documentName === "Item" && document.parent) {
|
|
528
|
-
context.actor = document.parent;
|
|
529
|
-
}
|
|
530
|
-
else {
|
|
531
|
-
context.actor = document;
|
|
532
|
-
}
|
|
533
|
-
${translateExpression(entry, id, functionDef.method, false, functionDef)}
|
|
534
|
-
if (!selfDeleted && Object.keys(update).length > 0) {
|
|
535
|
-
await this.document.update(update);
|
|
536
|
-
rerender = true;
|
|
537
|
-
}
|
|
538
|
-
if (!selfDeleted && Object.keys(embeddedUpdate).length > 0) {
|
|
539
|
-
for (let key of Object.keys(embeddedUpdate)) {
|
|
540
|
-
await this.document.updateEmbeddedDocuments("Item", embeddedUpdate[key]);
|
|
541
|
-
}
|
|
542
|
-
rerender = true;
|
|
543
|
-
}
|
|
544
|
-
if (Object.keys(parentUpdate).length > 0) {
|
|
545
|
-
await this.document.parent.update(parentUpdate);
|
|
546
|
-
rerender = true;
|
|
547
|
-
}
|
|
548
|
-
if (Object.keys(parentEmbeddedUpdate).length > 0) {
|
|
549
|
-
for (let key of Object.keys(parentEmbeddedUpdate)) {
|
|
550
|
-
await document.parent.updateEmbeddedDocuments("Item", parentEmbeddedUpdate[key]);
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
if (Object.keys(targetUpdate).length > 0) {
|
|
554
|
-
await context.target.update(targetUpdate);
|
|
555
|
-
}
|
|
556
|
-
if (Object.keys(targetEmbeddedUpdate).length > 0) {
|
|
557
|
-
for (let key of Object.keys(targetEmbeddedUpdate)) {
|
|
558
|
-
await context.target.updateEmbeddedDocuments("Item", targetEmbeddedUpdate[key]);
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
if (rerender) {
|
|
562
|
-
this.render();
|
|
563
|
-
}
|
|
564
|
-
}
|
|
507
|
+
return expandToNode `
|
|
508
|
+
|
|
509
|
+
/* -------------------------------------------- */
|
|
510
|
+
|
|
511
|
+
async _on${attr.name}AttributeFunction(event) {
|
|
512
|
+
if (event?.preventDefault) event.preventDefault();
|
|
513
|
+
let update = {};
|
|
514
|
+
let embeddedUpdate = {};
|
|
515
|
+
let parentUpdate = {};
|
|
516
|
+
let parentEmbeddedUpdate = {};
|
|
517
|
+
let targetUpdate = {};
|
|
518
|
+
let targetEmbeddedUpdate = {};
|
|
519
|
+
let selfDeleted = false;
|
|
520
|
+
let rerender = false;
|
|
521
|
+
let document = this.document;
|
|
522
|
+
const context = {
|
|
523
|
+
object: this.document,
|
|
524
|
+
target: game.user.getTargetOrNothing()
|
|
525
|
+
};
|
|
526
|
+
// If this is an item, attach the parent
|
|
527
|
+
if (document.documentName === "Item" && document.parent) {
|
|
528
|
+
context.actor = document.parent;
|
|
529
|
+
}
|
|
530
|
+
else {
|
|
531
|
+
context.actor = document;
|
|
532
|
+
}
|
|
533
|
+
${translateExpression(entry, id, functionDef.method, false, functionDef)}
|
|
534
|
+
if (!selfDeleted && Object.keys(update).length > 0) {
|
|
535
|
+
await this.document.update(update);
|
|
536
|
+
rerender = true;
|
|
537
|
+
}
|
|
538
|
+
if (!selfDeleted && Object.keys(embeddedUpdate).length > 0) {
|
|
539
|
+
for (let key of Object.keys(embeddedUpdate)) {
|
|
540
|
+
await this.document.updateEmbeddedDocuments("Item", embeddedUpdate[key]);
|
|
541
|
+
}
|
|
542
|
+
rerender = true;
|
|
543
|
+
}
|
|
544
|
+
if (Object.keys(parentUpdate).length > 0) {
|
|
545
|
+
await this.document.parent.update(parentUpdate);
|
|
546
|
+
rerender = true;
|
|
547
|
+
}
|
|
548
|
+
if (Object.keys(parentEmbeddedUpdate).length > 0) {
|
|
549
|
+
for (let key of Object.keys(parentEmbeddedUpdate)) {
|
|
550
|
+
await document.parent.updateEmbeddedDocuments("Item", parentEmbeddedUpdate[key]);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
if (Object.keys(targetUpdate).length > 0) {
|
|
554
|
+
await context.target.update(targetUpdate);
|
|
555
|
+
}
|
|
556
|
+
if (Object.keys(targetEmbeddedUpdate).length > 0) {
|
|
557
|
+
for (let key of Object.keys(targetEmbeddedUpdate)) {
|
|
558
|
+
await context.target.updateEmbeddedDocuments("Item", targetEmbeddedUpdate[key]);
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
if (rerender) {
|
|
562
|
+
this.render();
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
565
|
`;
|
|
566
566
|
}
|
|
567
567
|
}
|