Skip to content

Commit

Permalink
new UIS, start using SASS
Browse files Browse the repository at this point in the history
  • Loading branch information
esheyw committed Jan 23, 2024
1 parent a42ea88 commit 104b672
Show file tree
Hide file tree
Showing 17 changed files with 340 additions and 55 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
pf2e-macro-helper-library.lock
foundry/client
jsconfig.json
foundry/common
foundry/common
styles/*.css
styles/*.map
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ isEmpty({0:1}) == false
Passes `loggable` to `console[type]()`, with `prefix` as a separate argument first for ease of console filtering.
#### `mhlog(loggable, type = null, prefix="MHL |") `
Simple wrapper on the above with a set prefix.

---
### PF2e-specific Helpers
#### `levelBasedDC(level)`
Expand Down Expand Up @@ -118,7 +119,7 @@ This is mostly personal preference, but it means that any callbacks you use with
#### Doesn't clobber the classes array
In base Dialog, the way Application handles merging the options object, if you specify `classes:["my-class"]` as part of your dialog options, it will overwrite the array entirely, removing the `"dialog"` class. MHLDialog includes a workaround for this, and adds its own class (`"mhldialog"`) to the list in addition to whatever you give it.
#### Handlebars as `content`
Supports passing either a path to a handlebars file (must have extension `.html` or `.hbs`), or an inline handlebars template string, as `content` in dialog data. The temlpate is compiled and then passed the contents of the `contentData` property, in addition to the `buttons` and `content` variables that the base class provides, as well as the `idPrefix` variable, which is set to `mhldialog-${this.appId}-`. This last allows [valid-by-html-rules](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id) `id` properties on your form inputs, and associated labels, eg:
Supports passing either a path to a handlebars file (must have extension `.html` or `.hbs`), or an inline handlebars template string, as `content` in dialog data. The template is compiled and then passed the contents of the `contentData` property, in addition to the `buttons` and `content` variables that the base class provides, as well as the `idPrefix` variable, which is set to `mhldialog-${this.appId}-`. This last allows [valid-by-html-rules](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id) `id` properties on your form inputs, and associated labels, eg:
```hbs
<form>
<div class="form-group">
Expand Down
2 changes: 2 additions & 0 deletions TODO
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
- fix token settings on dropHeldTorch
- brushup the group initiative skills dialog macro
- implement current column
- account for lores known by all selected
- finish localization
- foundry package release api
- npm package setup, run link dev
- or just a standalone script
25 changes: 20 additions & 5 deletions lang/en.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
{
"MHL": {
"Header": {
"Current": "Current",
"SetTo": "Set To"
},
"Grammar": {
"Articles": {
"An": "an",
Expand All @@ -16,15 +20,19 @@
},
"Dialog": {
"Warning": {
"RequiredFields":"This dialog requires one or more fields to be non-empty: {fields}"
"RequiredFields": "This dialog requires one or more fields to be non-empty: {fields}"
},
"Error": {
"TemplateFailure": "The template filepath or literal passed to MHLDialog failed to compile properly.",
"FormRequiresName": "One or more of the forms provided lacks a `name` property.",
"ReservedKeys":"The contentData object must not contain any of the following reserved keys: {keys}",
"BadValidator":"The supplied validator must either be a function or an array of value names required to be non-empty."
"ReservedKeys": "The contentData object must not contain any of the following reserved keys: {keys}",
"BadValidator": "The supplied validator must either be a function or an array of value names required to be non-empty."
}
},
"Prompt": {
"SetAllSelected": "Set All Selected",
"SetIndividually": "Set Individually"
},
"Macro": {
"DropHeldTorch": {
"Error": {
Expand All @@ -51,6 +59,13 @@
"NoneSelected": "No weapon selected.",
"NoExistingFound": "No old-style Lashing Currents weapon found on the actor of selected token \"{name}\"."
}
},
"UpdateInitiativeStatistics": {
"Error": {
"NoValidTokens": "None of the selected tokens are PCs or NPCs that are neither minions nor eidolons."
},
"AllSharedSkills": "Skills shared by all selected actors: ",
"DisabledTooltip": "Being overridden by the all selector above."
}
},
"GetAllFromAllowedPacks": {
Expand Down Expand Up @@ -84,13 +99,13 @@
"NotAUser": "Provided user was not a foundry User."
}
},
"Error": {
"Error": {
"Generic": "You broke something.",
"BannerType": "Banner type must be one of \"info\", \"warn\", or \"error\".",
"LogType": "Log type must be one of \"debug\", \"info\", \"warn\", or \"error\".",
"InvalidType": "Invalid type \"{type}\" provided.",
"Type": {
"Array": "\"{var}\" must be an Array{typestr}.",
"Array": "\"{var}\" must be an Array{typestr}.",
"User": "\"{var}\" must be a User or the ID of one.",
"Folder": "\"{var}\" must be a Folder document or the ID of one.",
"Function": "\"{var}\" must be a Function.",
Expand Down
2 changes: 1 addition & 1 deletion module.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"verified": "11.315"
},
"esmodules": ["scripts/init.mjs"],
"styles": ["styles/pickAThing.css"],
"styles": ["styles/main.css"],
"authors": [
{
"name": "Emmanuel Wineberg",
Expand Down
14 changes: 7 additions & 7 deletions scripts/classes/MHLDialog.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { COLOURS, LABELABLE_TAGS, fu } from "../constants.mjs";
import { MHLError, isEmpty, localizedBanner, mhlog } from "../helpers/errorHelpers.mjs";
import { MHLError, isEmpty, localizedBanner } from "../helpers/errorHelpers.mjs";
import { localize } from "../helpers/stringHelpers.mjs";
const PREFIX = "MHL.Dialog";
export class MHLDialog extends Dialog {
Expand Down Expand Up @@ -124,19 +124,19 @@ export class MHLDialog extends Dialog {
const named = html.querySelectorAll("[name][id]");
if (!named.length) return {};
const namedIDs = Array.from(named).map((e) => e.getAttribute("id"));
const allLabels = Array.from(html.querySelectorAll('label'));
const allLabels = Array.from(html.querySelectorAll("label"));
if (!allLabels.length) return {};
return allLabels.reduce((acc, curr) => {
const forAttr = curr.getAttribute("for");
const forAttr = curr.getAttribute("for");
if (forAttr) {
if (!namedIDs.includes(forAttr)) return acc;
acc[curr.getAttribute('name')] = curr.innerText;
acc[curr.getAttribute("name")] = curr.innerText;
} else {
const labelableChild = curr.querySelector(LABELABLE_TAGS.map(t=>`${t}[name]`).join(', '));
const labelableChild = curr.querySelector(LABELABLE_TAGS.map((t) => `${t}[name]`).join(", "));
if (!labelableChild) return acc;
acc[labelableChild.getAttribute('name')] = curr.innerText;
acc[labelableChild.getAttribute("name")] = curr.innerText;
}
return acc;
return acc;
}, {});
}
}
2 changes: 1 addition & 1 deletion scripts/helpers/errorHelpers.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export function localizedBanner(
}

export function MHLError(str, data = {}, { notify = null, prefix = "MHL | ", log = {}, func = null } = {}) {
if (func && typeof func === "string") prefix += func;
if (func && typeof func === "string") prefix += `${func} |`;
return localizedError(str, data, { notify, prefix, log });
}

Expand Down
3 changes: 1 addition & 2 deletions scripts/helpers/tokenHelpers.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,4 @@ export function anyTokens(fallback = true) {
throw MHLError(`${PREFIX}.Error.NotAnySelected`, { fallback: fallbackStr });
}
return canvas.tokens.controlled;
}

}
6 changes: 6 additions & 0 deletions scripts/init.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,10 @@ Hooks.on("init", () => {
globalThis.mh = game.pf2emhl;
}
registerSettings();

Handlebars.registerHelper("mhlocalize", (value, options) => {
if ( value instanceof Handlebars.SafeString ) value = value.toString();
const data = options.hash;
return helpers.localize(value,data)
});
});
11 changes: 6 additions & 5 deletions scripts/macros/index.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from './fascinatingPerformance.mjs';
export * from './dropHeldTorch.mjs';
export * from './lashingCurrents.mjs';
export * from './recoverOldLashingCurrents.mjs';
export * from './updateInitiativeSkills.mjs'
export * from "./fascinatingPerformance.mjs";
export * from "./dropHeldTorch.mjs";
export * from "./lashingCurrents.mjs";
export * from "./recoverOldLashingCurrents.mjs";
export * from "./updateInitiativeSkills.mjs";
export * from "./updateInitiativeStatistics.mjs";
2 changes: 1 addition & 1 deletion scripts/macros/lashingCurrents.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,6 @@ export async function lashingCurrents() {
)
);
await existingLC.update({ "system.rules": oldRules });
localizedBanner(`${PREFIX}.Info.Removing`, {name: existingLC.name});
localizedBanner(`${PREFIX}.Info.Removing`, {name: existingLC.name}, {console:false});
}
}
113 changes: 113 additions & 0 deletions scripts/macros/updateInitiativeStatistics.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { anyTokens } from "../helpers/tokenHelpers.mjs";
import { MHLDialog } from "../classes/MHLDialog.mjs";
import { MODULE, fu } from "../constants.mjs";
import { MHLError, mhlog } from "../helpers/errorHelpers.mjs";
import { localize } from "../helpers/stringHelpers.mjs";

export async function updateInitiativeStatistics() {
const PREFIX = "MHL.Macro.UpdateInitiativeStatistics";
const func = "updateInitiativeStatistics";
const tokens = anyTokens().filter(
(t) => ["character", "npc"].includes(t.actor.type) && !t.actor.traits.intersects(new Set(["minion", "eidolon"]))
);
if (!tokens.length) throw MHLError(`${PREFIX}.Error.NoValidTokens`, null, { func });

const renderCallback = (html) => {
const allSelect = html.querySelector("select[name=all]");
const actorSelects = Array.from(html.querySelectorAll("select:not([name=all])"));
allSelect.addEventListener("change", (ev) => {
let disabled = false;
if (ev.target.value) disabled = true;
for (const select of actorSelects) {
select.disabled = disabled;
select.dataset.tooltip = disabled ? localize(`${PREFIX}.DisabledTooltip`) : "";
}
});
};

const universalSkills = fu.deepClone(CONFIG.PF2E.skillList);
delete universalSkills.lore; //remove the generic Lore entry
const lores = {};

const actorsData = tokens.reduce((actoracc, t) => {
// handle the rare case of more than one linked token of the same actor
if (actoracc.find((a) => a.uiid === t.actor.uuid)) return actoracc;
actoracc.push({
name: t.name,
uuid: t.actor.uuid,
skills: [["perception", { label: "PF2E.PerceptionLabel" }]]
.concat(Object.entries(t.actor.skills).sort(([aslug, _], [bslug, __]) => aslug.localeCompare(bslug))) //do the sorting here so perception stays on top
.map(([slug, statistic]) => [slug, statistic.label])
.reduce((acc, [slug, label]) => {
if (!(slug in universalSkills)) {
lores[slug] ??= {
label,
count: 0,
};
lores[slug].count++;
}
acc[slug] = label;
return acc;
}, {}),
current: t.actor.initiative.statistic.label,
});
return actoracc;
}, []);

const sharedLores = Object.entries(lores).reduce((acc, [slug, data]) => {
if (data.count === tokens.length) {
acc.push([slug, data.label]);
}
return acc;
}, []);

const allSharedSkills = Object.fromEntries(
[["perception", "PF2E.PerceptionLabel"]].concat(
Object.entries(universalSkills)
.concat(sharedLores)
.sort(([aslug, _], [bslug, __]) => aslug.localeCompare(bslug))
)
);

const contentData = {
allSharedSkills,
actorsData,
};
const dialogData = {
contentData,
title: `Set Initiative Statistics`,
content: `modules/${MODULE}/templates/updateInitiativeStatistics.hbs`,
buttons: {
yes: {
icon: "<i class='fas fa-check'></i>",
label: `Apply Changes`,
callback: MHLDialog.getFormData,
},
no: {
icon: "<i class='fas fa-times'></i>",
label: `Cancel Changes`,
},
},
default: "yes",
render: renderCallback,
};
const dialogOptions = {
classes: ["update-initiative-statistics"],
width: "auto",
};
const { all, ...data } = await MHLDialog.wait(dialogData, dialogOptions);
const actorUpdates = [];
const synthUpdates = [];
for (const actorData of actorsData) {
const actor = fromUuidSync(actorData.uuid);
const newStat = all || data[actorData.uuid];
if (!newStat) continue;
if (actorData.uuid.startsWith("Scene")) {
synthUpdates.push(actor.update({ "system.initiative.statistic": newStat }));
} else {
actorUpdates.push({ _id: actor._id, "system.initiative.statistic": newStat });
}
}
await Actor.updateDocuments(actorUpdates);
await Promise.all(synthUpdates);
}
37 changes: 37 additions & 0 deletions styles/_pickAThing.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
.mhldialog.pick-a-thing {
img {
max-width: 40px;
max-height: 40px;
width: 40px;
height: 40px;
margin: auto 2px auto 2px;
}

.dialog-buttons {
display: flex;
flex-direction: column;
gap: 5px;
}

button {
display: flex;
flex-direction: row;
justify-content: left;
padding: 0px;
margin: 0px;

span.item-name {
text-align: left;
margin: auto auto auto 2%;
}

span.dupe-id {
font-size: 0.7em;
text-align: right;
margin: auto;
margin-right: 2%;
color: var(--color-cool-3, #573fc0);
}
}
}

Loading

0 comments on commit 104b672

Please sign in to comment.