mirror of
https://github.com/Kornstalx/5etools-mirror-2.github.io.git
synced 2026-01-14 05:47:50 -06:00
v1.202.0
This commit is contained in:
@@ -1553,7 +1553,7 @@ class CreatureParser extends BaseParser {
|
||||
// regular creatures
|
||||
|
||||
// region Size
|
||||
const reSize = new RegExp(`(${Object.values(Parser.SIZE_ABV_TO_FULL).join("|")})`, "i");
|
||||
const reSize = new RegExp(`\\b(${Object.values(Parser.SIZE_ABV_TO_FULL).join("|")})\\b`, "i");
|
||||
const reSizeGlobal = new RegExp(reSize, "gi");
|
||||
|
||||
const tks = meta.curLine.split(reSizeGlobal);
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
class AcConvert {
|
||||
static tryPostProcessAc (mon, cbMan, cbErr) {
|
||||
const traitNames = new Set(
|
||||
(mon.trait || [])
|
||||
.map(it => it.name ? it.name.toLowerCase() : null)
|
||||
.filter(Boolean),
|
||||
);
|
||||
|
||||
if (this._tryPostProcessAc_special(mon, cbMan, cbErr)) return;
|
||||
|
||||
const nuAc = [];
|
||||
@@ -114,14 +120,14 @@ class AcConvert {
|
||||
|
||||
// everything else
|
||||
default: {
|
||||
const simpleFrom = this._getSimpleFrom(fromLow);
|
||||
const simpleFrom = this._getSimpleFrom({fromLow, traitNames});
|
||||
if (simpleFrom) return froms.push(simpleFrom);
|
||||
|
||||
// Special parsing for barding, as the pre-barding armor type might not exactly match our known
|
||||
// barding names (e.g. "chainmail barding")
|
||||
const mWithBarding = /^(?<ac>\d+) with (?<name>(?<type>.*?) barding)$/.exec(fromLow);
|
||||
if (mWithBarding) {
|
||||
let simpleFromBarding = this._getSimpleFrom(mWithBarding.groups.type);
|
||||
let simpleFromBarding = this._getSimpleFrom({fromLow: mWithBarding.groups.type, traitNames});
|
||||
if (simpleFromBarding) {
|
||||
simpleFromBarding = simpleFromBarding
|
||||
.replace(/{@item ([^}]+)}/, (...m) => {
|
||||
@@ -203,7 +209,7 @@ class AcConvert {
|
||||
return false;
|
||||
}
|
||||
|
||||
static _getSimpleFrom (fromLow) {
|
||||
static _getSimpleFrom ({fromLow, traitNames}) {
|
||||
switch (fromLow) {
|
||||
// region unhandled/other
|
||||
case "unarmored defense":
|
||||
@@ -323,6 +329,10 @@ class AcConvert {
|
||||
if (/scraps of .*?armor/i.test(fromLow)) { // e.g. "scraps of hide armor"
|
||||
return fromLow;
|
||||
}
|
||||
|
||||
if (traitNames.has(fromLow)) {
|
||||
return fromLow;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -371,9 +381,19 @@ class _CreatureImmunityResistanceVulnerabilityConverterBase {
|
||||
static _getSplitInput ({ipt}) {
|
||||
return ipt
|
||||
.toLowerCase()
|
||||
.split(";")
|
||||
|
||||
// Split e.g.
|
||||
// "Bludgeoning and Piercing from nonmagical attacks, Acid, Fire, Lightning"
|
||||
.split(/(.*\b(?:from|by)\b[^,;.!?]+)(?:[,;] ?)?/g)
|
||||
.map(it => it.trim())
|
||||
.filter(Boolean);
|
||||
.filter(Boolean)
|
||||
|
||||
// Split e.g.
|
||||
// "poison; bludgeoning, piercing, and slashing from nonmagical attacks"
|
||||
.flatMap(pt => pt.split(";"))
|
||||
.map(it => it.trim())
|
||||
.filter(Boolean)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1343,9 +1363,14 @@ class MiscTag {
|
||||
globalThis.MiscTag = MiscTag;
|
||||
|
||||
class SpellcastingTraitConvert {
|
||||
static SPELL_SRC_MAP = {};
|
||||
static SPELL_SRD_MAP = {};
|
||||
|
||||
static init (spellData) {
|
||||
// reversed so official sources take precedence over 3pp
|
||||
spellData.forEach(s => SpellcastingTraitConvert.SPELL_SRC_MAP[s.name.toLowerCase()] = s.source);
|
||||
spellData.forEach(s => {
|
||||
this.SPELL_SRC_MAP[s.name.toLowerCase()] = s.source;
|
||||
if (typeof s.srd === "string") this.SPELL_SRD_MAP[s.srd.toLowerCase()] = s.name;
|
||||
});
|
||||
}
|
||||
|
||||
static tryParseSpellcasting (ent, {isMarkdown, cbErr, displayAs, actions, reactions}) {
|
||||
@@ -1490,6 +1515,8 @@ class SpellcastingTraitConvert {
|
||||
str = str.substring(0, ixParenOpen);
|
||||
}
|
||||
|
||||
str = this._parseSpell_getNonSrdSpellName(str);
|
||||
|
||||
return [
|
||||
`{@spell ${str}${this._parseSpell_getSourcePart(str)}}`,
|
||||
ptsSuffix.join(" "),
|
||||
@@ -1498,6 +1525,16 @@ class SpellcastingTraitConvert {
|
||||
.join(" ");
|
||||
}
|
||||
|
||||
static _parseSpell_getNonSrdSpellName (spellName) {
|
||||
const nonSrdName = SpellcastingTraitConvert.SPELL_SRD_MAP[spellName.toLowerCase().trim()];
|
||||
if (!nonSrdName) return spellName;
|
||||
|
||||
if (spellName.toSpellCase() === spellName) return nonSrdName.toSpellCase();
|
||||
if (spellName.toLowerCase() === spellName) return nonSrdName.toLowerCase();
|
||||
if (spellName.toTitleCase() === spellName) return nonSrdName.toTitleCase();
|
||||
return spellName;
|
||||
}
|
||||
|
||||
static _parseSpell_getSourcePart (spellName) {
|
||||
const source = SpellcastingTraitConvert._getSpellSource(spellName);
|
||||
return `${source && source !== Parser.SRC_PHB ? `|${source}` : ""}`;
|
||||
@@ -1583,7 +1620,6 @@ class SpellcastingTraitConvert {
|
||||
});
|
||||
}
|
||||
}
|
||||
SpellcastingTraitConvert.SPELL_SRC_MAP = {};
|
||||
|
||||
globalThis.SpellcastingTraitConvert = SpellcastingTraitConvert;
|
||||
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
"use strict";
|
||||
|
||||
class LanguagesSublistManager extends SublistManager {
|
||||
constructor () {
|
||||
super({
|
||||
sublistClass: "sublanguages",
|
||||
});
|
||||
}
|
||||
|
||||
static get _ROW_TEMPLATE () {
|
||||
return [
|
||||
new SublistCellTemplate({
|
||||
@@ -70,8 +64,6 @@ class LanguagesPage extends ListPage {
|
||||
|
||||
pageFilter,
|
||||
|
||||
listClass: "languages",
|
||||
|
||||
dataProps: ["language"],
|
||||
|
||||
isMarkdownPopout: true,
|
||||
|
||||
@@ -107,7 +107,6 @@ class SublistManager {
|
||||
|
||||
/**
|
||||
* @param [opts]
|
||||
* @param [opts.sublistClass] Sublist class.
|
||||
* @param [opts.sublistListOptions] Other sublist options.
|
||||
* @param [opts.isSublistItemsCountable] If the sublist items should be countable, i.e. have a quantity.
|
||||
* @param [opts.shiftCountAddSubtract] If the sublist items should be countable, i.e. have a quantity.
|
||||
@@ -115,7 +114,6 @@ class SublistManager {
|
||||
constructor (opts) {
|
||||
opts = opts || {};
|
||||
|
||||
this._sublistClass = opts.sublistClass; // TODO(PageGen) remove once all pages transitioned
|
||||
this._sublistListOptions = opts.sublistListOptions || {};
|
||||
this._isSublistItemsCountable = !!opts.isSublistItemsCountable;
|
||||
this._shiftCountAddSubtract = opts.shiftCountAddSubtract ?? 20;
|
||||
@@ -160,7 +158,7 @@ class SublistManager {
|
||||
|
||||
this._listSub = new List({
|
||||
...this._sublistListOptions,
|
||||
$wrpList: this._sublistClass ? $(`.${this._sublistClass}`) : $(`#sublist`),
|
||||
$wrpList: $(`#sublist`),
|
||||
isUseJquery: true,
|
||||
});
|
||||
|
||||
@@ -987,7 +985,6 @@ class ListPage {
|
||||
* `pageFilter` must be specified.)
|
||||
* @param [opts.pageFilter] PageFilter implementation for this page. (Either `filters` and `filterSource` or
|
||||
* `pageFilter` must be specified.)
|
||||
* @param [opts.listClass] List class.
|
||||
* @param opts.listOptions Other list options.
|
||||
* @param opts.dataProps JSON data propert(y/ies).
|
||||
*
|
||||
@@ -1017,7 +1014,6 @@ class ListPage {
|
||||
this._filters = opts.filters;
|
||||
this._filterSource = opts.filterSource;
|
||||
this._pageFilter = opts.pageFilter;
|
||||
this._listClass = opts.listClass; // TODO(PageGen) remove once all pages transitioned
|
||||
this._listOptions = opts.listOptions || {};
|
||||
this._dataProps = opts.dataProps;
|
||||
this._bookViewOptions = opts.bookViewOptions;
|
||||
@@ -1152,7 +1148,7 @@ class ListPage {
|
||||
const $btnReset = $("#reset");
|
||||
this._list = this._initList({
|
||||
$iptSearch,
|
||||
$wrpList: this._listClass ? $(`.list.${this._listClass}`) : $(`#list`),
|
||||
$wrpList: $(`#list`),
|
||||
$btnReset,
|
||||
$btnClear: $(`#lst__search-glass`),
|
||||
dispPageTagline: document.getElementById(`page__subtitle`),
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
"use strict";
|
||||
|
||||
class ObjectsSublistManager extends SublistManager {
|
||||
constructor () {
|
||||
super({
|
||||
sublistClass: "subobjects",
|
||||
});
|
||||
}
|
||||
|
||||
static get _ROW_TEMPLATE () {
|
||||
return [
|
||||
new SublistCellTemplate({
|
||||
@@ -64,8 +58,6 @@ class ObjectsPage extends ListPage {
|
||||
|
||||
pageFilter,
|
||||
|
||||
listClass: "objects",
|
||||
|
||||
dataProps: ["object"],
|
||||
|
||||
listSyntax: new ListSyntaxObjects({fnGetDataList: () => this._dataList, pFnGetFluff}),
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
class OptionalFeaturesSublistManager extends SublistManager {
|
||||
constructor () {
|
||||
super({
|
||||
sublistClass: "suboptfeatures",
|
||||
sublistListOptions: {
|
||||
fnSort: PageFilterOptionalFeatures.sortOptionalFeatures,
|
||||
},
|
||||
@@ -84,7 +83,6 @@ class OptionalFeaturesPage extends ListPage {
|
||||
|
||||
pageFilter,
|
||||
|
||||
listClass: "optfeatures",
|
||||
listOptions: {
|
||||
fnSort: PageFilterOptionalFeatures.sortOptionalFeatures,
|
||||
},
|
||||
|
||||
11
js/parser.js
11
js/parser.js
@@ -645,7 +645,7 @@ Parser.sourceJsonToDate = function (source) {
|
||||
};
|
||||
|
||||
Parser.sourceJsonToColor = function (source) {
|
||||
return `source${Parser.sourceJsonToAbv(source)}`;
|
||||
return `source__${source}`;
|
||||
};
|
||||
|
||||
Parser.sourceJsonToStyle = function (source) {
|
||||
@@ -2536,7 +2536,7 @@ Parser.vehicleTypeToFull = function (vehicleType) {
|
||||
|
||||
// SOURCES =============================================================================================================
|
||||
|
||||
Parser.SRC_5ETOOLS_TMP = "Parser.SRC_5ETOOLS_TMP"; // Temp source, used as a placeholder value
|
||||
Parser.SRC_5ETOOLS_TMP = "SRC_5ETOOLS_TMP"; // Temp source, used as a placeholder value
|
||||
|
||||
Parser.SRC_CoS = "CoS";
|
||||
Parser.SRC_DMG = "DMG";
|
||||
@@ -2645,6 +2645,7 @@ Parser.SRC_GHLoE = "GHLoE";
|
||||
Parser.SRC_DoDk = "DoDk";
|
||||
Parser.SRC_HWCS = "HWCS";
|
||||
Parser.SRC_HWAitW = "HWAitW";
|
||||
Parser.SRC_ToB1_2023 = "ToB1-2023";
|
||||
Parser.SRC_TD = "TD";
|
||||
Parser.SRC_SCREEN = "Screen";
|
||||
Parser.SRC_SCREEN_WILDERNESS_KIT = "ScreenWildernessKit";
|
||||
@@ -2821,6 +2822,7 @@ Parser.SOURCE_JSON_TO_FULL[Parser.SRC_GHLoE] = "Grim Hollow: Lairs of Etharis";
|
||||
Parser.SOURCE_JSON_TO_FULL[Parser.SRC_DoDk] = "Dungeons of Drakkenheim";
|
||||
Parser.SOURCE_JSON_TO_FULL[Parser.SRC_HWCS] = "Humblewood Campaign Setting";
|
||||
Parser.SOURCE_JSON_TO_FULL[Parser.SRC_HWAitW] = "Humblewood: Adventure in the Wood";
|
||||
Parser.SOURCE_JSON_TO_FULL[Parser.SRC_ToB1_2023] = "Tome of Beasts 1 (2023 Edition)";
|
||||
Parser.SOURCE_JSON_TO_FULL[Parser.SRC_TD] = "Tarot Deck";
|
||||
Parser.SOURCE_JSON_TO_FULL[Parser.SRC_SCREEN] = "Dungeon Master's Screen";
|
||||
Parser.SOURCE_JSON_TO_FULL[Parser.SRC_SCREEN_WILDERNESS_KIT] = "Dungeon Master's Screen: Wilderness Kit";
|
||||
@@ -2972,6 +2974,7 @@ Parser.SOURCE_JSON_TO_ABV[Parser.SRC_GHLoE] = "GHLoE";
|
||||
Parser.SOURCE_JSON_TO_ABV[Parser.SRC_DoDk] = "DoDk";
|
||||
Parser.SOURCE_JSON_TO_ABV[Parser.SRC_HWCS] = "HWCS";
|
||||
Parser.SOURCE_JSON_TO_ABV[Parser.SRC_HWAitW] = "HWAitW";
|
||||
Parser.SOURCE_JSON_TO_ABV[Parser.SRC_ToB1_2023] = "ToB1'23";
|
||||
Parser.SOURCE_JSON_TO_ABV[Parser.SRC_TD] = "TD";
|
||||
Parser.SOURCE_JSON_TO_ABV[Parser.SRC_SCREEN] = "Screen";
|
||||
Parser.SOURCE_JSON_TO_ABV[Parser.SRC_SCREEN_WILDERNESS_KIT] = "ScWild";
|
||||
@@ -3122,6 +3125,7 @@ Parser.SOURCE_JSON_TO_DATE[Parser.SRC_GHLoE] = "2023-11-30";
|
||||
Parser.SOURCE_JSON_TO_DATE[Parser.SRC_DoDk] = "2023-12-21";
|
||||
Parser.SOURCE_JSON_TO_DATE[Parser.SRC_HWCS] = "2019-06-17";
|
||||
Parser.SOURCE_JSON_TO_DATE[Parser.SRC_HWAitW] = "2019-06-17";
|
||||
Parser.SOURCE_JSON_TO_DATE[Parser.SRC_ToB1_2023] = "2023-05-31";
|
||||
Parser.SOURCE_JSON_TO_DATE[Parser.SRC_TD] = "2022-05-24";
|
||||
Parser.SOURCE_JSON_TO_DATE[Parser.SRC_SCREEN] = "2015-01-20";
|
||||
Parser.SOURCE_JSON_TO_DATE[Parser.SRC_SCREEN_WILDERNESS_KIT] = "2020-11-17";
|
||||
@@ -3311,6 +3315,7 @@ Parser.SOURCES_PARTNERED_WOTC = new Set([
|
||||
Parser.SRC_DoDk,
|
||||
Parser.SRC_HWCS,
|
||||
Parser.SRC_HWAitW,
|
||||
Parser.SRC_ToB1_2023,
|
||||
Parser.SRC_TD,
|
||||
]);
|
||||
// region Source categories
|
||||
@@ -3397,6 +3402,7 @@ Parser.SOURCES_NON_FR = new Set([
|
||||
Parser.SRC_DoDk,
|
||||
Parser.SRC_HWCS,
|
||||
Parser.SRC_HWAitW,
|
||||
Parser.SRC_ToB1_2023,
|
||||
]);
|
||||
|
||||
// endregion
|
||||
@@ -3439,6 +3445,7 @@ Parser.SOURCES_AVAILABLE_DOCS_BOOK = {};
|
||||
Parser.SRC_BMT,
|
||||
Parser.SRC_DMTCRG,
|
||||
Parser.SRC_HWCS,
|
||||
Parser.SRC_ToB1_2023,
|
||||
Parser.SRC_TD,
|
||||
].forEach(src => {
|
||||
Parser.SOURCES_AVAILABLE_DOCS_BOOK[src] = src;
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
"use strict";
|
||||
|
||||
class PsionicsSublistManager extends SublistManager {
|
||||
constructor () {
|
||||
super({
|
||||
sublistClass: "subpsionics",
|
||||
});
|
||||
}
|
||||
|
||||
static get _ROW_TEMPLATE () {
|
||||
return [
|
||||
new SublistCellTemplate({
|
||||
@@ -65,10 +59,6 @@ class PsionicsPage extends ListPage {
|
||||
|
||||
pageFilter,
|
||||
|
||||
listClass: "psionics",
|
||||
|
||||
sublistClass: "subpsionics",
|
||||
|
||||
dataProps: ["psionic"],
|
||||
|
||||
isMarkdownPopout: true,
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
"use strict";
|
||||
|
||||
class RacesSublistManager extends SublistManager {
|
||||
constructor () {
|
||||
super({
|
||||
sublistClass: "subraces",
|
||||
});
|
||||
}
|
||||
|
||||
static get _ROW_TEMPLATE () {
|
||||
return [
|
||||
new SublistCellTemplate({
|
||||
@@ -73,8 +67,6 @@ class RacesPage extends ListPage {
|
||||
|
||||
pageFilter,
|
||||
|
||||
listClass: "races",
|
||||
|
||||
dataProps: ["race"],
|
||||
|
||||
isMarkdownPopout: true,
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
"use strict";
|
||||
|
||||
class RecipesSublistManager extends SublistManager {
|
||||
constructor () {
|
||||
super({
|
||||
sublistClass: "subrecipes",
|
||||
});
|
||||
}
|
||||
|
||||
_getCustomHashId ({entity}) {
|
||||
return Renderer.recipe.getCustomHashId(entity);
|
||||
}
|
||||
@@ -71,8 +65,6 @@ class RecipesPage extends ListPage {
|
||||
|
||||
pageFilter,
|
||||
|
||||
listClass: "recipes",
|
||||
|
||||
dataProps: ["recipe"],
|
||||
|
||||
isMarkdownPopout: true,
|
||||
|
||||
@@ -1689,6 +1689,8 @@ RendererMarkdown.vehicle = class {
|
||||
renderer.render(entriesMetaShip.entrySizeDimensions),
|
||||
RendererMarkdown.vehicle.ship.getCrewCargoPaceSection_(ent, {entriesMetaShip}),
|
||||
RendererMarkdown.utils.compact.getRenderedAbilityScores(ent),
|
||||
entriesMeta.entryDamageVulnerabilities ? renderer.render(entriesMeta.entryDamageVulnerabilities) : null,
|
||||
entriesMeta.entryDamageResistances ? renderer.render(entriesMeta.entryDamageResistances) : null,
|
||||
entriesMeta.entryDamageImmunities ? renderer.render(entriesMeta.entryDamageImmunities) : null,
|
||||
entriesMeta.entryConditionImmunities ? renderer.render(entriesMeta.entryConditionImmunities) : null,
|
||||
ent.action ? "### Actions" : null,
|
||||
@@ -1770,6 +1772,8 @@ RendererMarkdown.vehicle = class {
|
||||
.map(prop => renderer.render(entriesMetaInfwar[prop])),
|
||||
renderer.render(entriesMetaInfwar.entrySpeedNote),
|
||||
RendererMarkdown.utils.compact.getRenderedAbilityScores(ent),
|
||||
entriesMeta.entryDamageVulnerabilities ? renderer.render(entriesMeta.entryDamageVulnerabilities) : null,
|
||||
entriesMeta.entryDamageResistances ? renderer.render(entriesMeta.entryDamageResistances) : null,
|
||||
entriesMeta.entryDamageImmunities ? renderer.render(entriesMeta.entryDamageImmunities) : null,
|
||||
entriesMeta.entryConditionImmunities ? renderer.render(entriesMeta.entryConditionImmunities) : null,
|
||||
...this._getLinesRendered_traits({ent, renderer}),
|
||||
|
||||
31
js/render.js
31
js/render.js
@@ -260,6 +260,25 @@ globalThis.Renderer = function () {
|
||||
|
||||
this._getPlugins = function (pluginType) { return this._plugins[pluginType] ||= []; };
|
||||
|
||||
// TODO(Future) refactor to use this
|
||||
this._applyPlugins_useFirst = function (pluginType, commonArgs, pluginArgs) {
|
||||
for (const plugin of this._getPlugins(pluginType)) {
|
||||
const out = plugin(commonArgs, pluginArgs);
|
||||
if (out) return out;
|
||||
}
|
||||
};
|
||||
|
||||
this._applyPlugins_useAll = function (pluginType, commonArgs, pluginArgs) {
|
||||
const plugins = this._getPlugins(pluginType);
|
||||
if (!plugins?.length) return null;
|
||||
|
||||
let input = pluginArgs.input;
|
||||
for (const plugin of plugins) {
|
||||
input = plugin(commonArgs, pluginArgs) ?? input;
|
||||
}
|
||||
return input;
|
||||
};
|
||||
|
||||
/** Run a function with the given plugin active. */
|
||||
this.withPlugin = function ({pluginTypes, fnPlugin, fn}) {
|
||||
for (const pt of pluginTypes) this.addPlugin(pt, fnPlugin);
|
||||
@@ -1547,7 +1566,9 @@ globalThis.Renderer = function () {
|
||||
};
|
||||
|
||||
this._renderString = function (entry, textStack, meta, options) {
|
||||
const tagSplit = Renderer.splitByTags(entry);
|
||||
const str = this._applyPlugins_useAll("string_preprocess", {textStack, meta, options}, {input: entry}) ?? entry;
|
||||
|
||||
const tagSplit = Renderer.splitByTags(str);
|
||||
const len = tagSplit.length;
|
||||
for (let i = 0; i < len; ++i) {
|
||||
const s = tagSplit[i];
|
||||
@@ -9605,6 +9626,12 @@ Renderer.vehicle = class {
|
||||
|
||||
static getVehicleRenderableEntriesMeta (ent) {
|
||||
return {
|
||||
entryDamageVulnerabilities: ent.vulnerable
|
||||
? `{@b Damage Vulnerabilities} ${Parser.getFullImmRes(ent.vulnerable)}`
|
||||
: null,
|
||||
entryDamageResistances: ent.resist
|
||||
? `{@b Damage Resistances} ${Parser.getFullImmRes(ent.resist)}`
|
||||
: null,
|
||||
entryDamageImmunities: ent.immune
|
||||
? `{@b Damage Immunities} ${Parser.getFullImmRes(ent.immune)}`
|
||||
: null,
|
||||
@@ -9940,6 +9967,8 @@ Renderer.vehicle = class {
|
||||
entriesMeta ||= Renderer.vehicle.getVehicleRenderableEntriesMeta(ent);
|
||||
|
||||
const props = [
|
||||
"entryDamageVulnerabilities",
|
||||
"entryDamageResistances",
|
||||
"entryDamageImmunities",
|
||||
"entryConditionImmunities",
|
||||
];
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
"use strict";
|
||||
|
||||
class RewardsSublistManager extends SublistManager {
|
||||
constructor () {
|
||||
super({
|
||||
sublistClass: "subrewards",
|
||||
});
|
||||
}
|
||||
|
||||
static get _ROW_TEMPLATE () {
|
||||
return [
|
||||
new SublistCellTemplate({
|
||||
@@ -61,8 +55,6 @@ class RewardsPage extends ListPage {
|
||||
|
||||
pageFilter,
|
||||
|
||||
listClass: "rewards",
|
||||
|
||||
dataProps: ["reward"],
|
||||
|
||||
isPreviewable: true,
|
||||
|
||||
@@ -104,10 +104,10 @@ class SearchPage {
|
||||
SearchPage._$wrpResults = $(`<div class="ve-flex-col w-100">${this._getWrpResult_message("Loading...")}</div>`);
|
||||
|
||||
$$(SearchPage._$wrp)`<div class="ve-flex-col w-100 pg-search__wrp">
|
||||
<div class="ve-flex-v-center mb-2 mobile-ish__ve-flex-col">
|
||||
<div class="ve-flex-v-center input-group btn-group mr-2 w-100 mobile-ish__mb-2">${$iptSearch}${$btnSearch}</div>
|
||||
<div class="ve-flex-v-center mb-2 mobile-lg__ve-flex-col">
|
||||
<div class="ve-flex-v-center input-group btn-group mr-2 w-100 mobile-lg__mb-2">${$iptSearch}${$btnSearch}</div>
|
||||
|
||||
<div class="ve-flex-v-center mobile__ve-flex-col mobile-ish__ve-flex-ai-start mobile-ish__w-100">
|
||||
<div class="ve-flex-v-center mobile__ve-flex-col mobile-lg__ve-flex-ai-start mobile-lg__w-100">
|
||||
${$btnHelp}
|
||||
<div class="ve-flex-v-center btn-group mr-2 mobile__mb-2 mobile__mr-0">
|
||||
${$btnToggleBrew}
|
||||
|
||||
10
js/spells.js
10
js/spells.js
@@ -1,15 +1,6 @@
|
||||
"use strict";
|
||||
|
||||
class SpellsSublistManager extends SublistManager {
|
||||
constructor () {
|
||||
super({
|
||||
sublistClass: "subspells",
|
||||
sublistListOptions: {
|
||||
fnSort: PageFilterSpells.sortSpells,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
static get _ROW_TEMPLATE () {
|
||||
return [
|
||||
new SublistCellTemplate({
|
||||
@@ -223,7 +214,6 @@ class SpellsPage extends ListPageMultiSource {
|
||||
super({
|
||||
pageFilter: new PageFilterSpells(),
|
||||
|
||||
listClass: "spells",
|
||||
listOptions: {
|
||||
fnSort: PageFilterSpells.sortSpells,
|
||||
},
|
||||
|
||||
@@ -661,8 +661,8 @@ class StatGenUi extends BaseComponent {
|
||||
// region Point Buy stages
|
||||
const $stgPbHeader = this._render_$getStgPbHeader();
|
||||
const $stgPbCustom = this._render_$getStgPbCustom();
|
||||
const $vrPbCustom = $(`<div class="vr-5 mobile-ish__hidden"></div>`);
|
||||
const $hrPbCustom = $(`<hr class="hr-5 mobile-ish__visible">`);
|
||||
const $vrPbCustom = $(`<div class="vr-5 mobile-lg__hidden"></div>`);
|
||||
const $hrPbCustom = $(`<hr class="hr-5 mobile-lg__visible">`);
|
||||
const hkStgPb = () => {
|
||||
$stgPbHeader.toggleVe(this.ixActiveTab === this._IX_TAB_PB);
|
||||
$stgPbCustom.toggleVe(this.ixActiveTab === this._IX_TAB_PB);
|
||||
@@ -859,7 +859,7 @@ class StatGenUi extends BaseComponent {
|
||||
${$stgArrayHeader}
|
||||
${$stgManualHeader}
|
||||
|
||||
<div class="ve-flex mobile-ish__ve-flex-col w-100 px-3">
|
||||
<div class="ve-flex mobile-lg__ve-flex-col w-100 px-3">
|
||||
<div class="ve-flex-col">
|
||||
${$stgPbHeader}
|
||||
|
||||
@@ -1363,7 +1363,7 @@ class StatGenUi extends BaseComponent {
|
||||
const $wrpAsi = this._render_$getWrpAsi();
|
||||
|
||||
$$($wrpTab)`
|
||||
<div class="ve-flex mobile-ish__ve-flex-col w-100 px-3">
|
||||
<div class="ve-flex mobile-lg__ve-flex-col w-100 px-3">
|
||||
<div class="ve-flex-col">
|
||||
<div class="ve-flex">
|
||||
<div class="ve-flex-col mr-3">
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
class TablesSublistManager extends SublistManager {
|
||||
constructor () {
|
||||
super({
|
||||
sublistClass: "subtablesdata",
|
||||
sublistListOptions: {
|
||||
sortByInitial: "sortName",
|
||||
},
|
||||
@@ -55,7 +54,6 @@ class TablesPage extends ListPage {
|
||||
|
||||
pageFilter,
|
||||
|
||||
listClass: "tablesdata",
|
||||
listOptions: {
|
||||
sortByInitial: "sortName",
|
||||
},
|
||||
|
||||
@@ -2119,7 +2119,7 @@ class ManageBrewUi {
|
||||
|
||||
const btnViewJson = e_({
|
||||
tag: "button",
|
||||
clazz: `btn btn-default btn-xs mobile-ish__hidden w-24p`,
|
||||
clazz: `btn btn-default btn-xs mobile-lg__hidden w-24p`,
|
||||
title: `${this._LBL_LIST_VIEW_JSON}: ${this.constructor._getBrewJsonTitle({brew, brewName})}`,
|
||||
children: [
|
||||
e_({
|
||||
|
||||
@@ -78,11 +78,16 @@ PropOrder._ObjectKey = class {
|
||||
this.order = opts.order;
|
||||
}
|
||||
|
||||
static getCopyKey ({fnGetModOrder}) {
|
||||
static getCopyKey ({identKeys = null, fnGetModOrder}) {
|
||||
return new this("_copy", {
|
||||
order: [
|
||||
"name",
|
||||
"source",
|
||||
...(
|
||||
identKeys
|
||||
|| [
|
||||
"name",
|
||||
"source",
|
||||
]
|
||||
),
|
||||
"_templates",
|
||||
new PropOrder._ObjectKey("_mod", {
|
||||
fnGetOrder: fnGetModOrder,
|
||||
@@ -112,6 +117,63 @@ PropOrder._ArrayKey = class {
|
||||
}
|
||||
};
|
||||
|
||||
PropOrder._META = [
|
||||
"sources",
|
||||
|
||||
"dependencies",
|
||||
"includes",
|
||||
"internalCopies",
|
||||
|
||||
"otherSources",
|
||||
|
||||
"spellSchools",
|
||||
"spellDistanceUnits",
|
||||
"optionalFeatureTypes",
|
||||
"psionicTypes",
|
||||
"currencyConversions",
|
||||
"fonts",
|
||||
|
||||
"status",
|
||||
"unlisted",
|
||||
|
||||
"dateAdded",
|
||||
"dateLastModified",
|
||||
"_dateLastModifiedHash",
|
||||
];
|
||||
PropOrder._FOUNDRY_GENERIC = [
|
||||
"name",
|
||||
"source",
|
||||
|
||||
"type",
|
||||
"system",
|
||||
"effects",
|
||||
"flags",
|
||||
"img",
|
||||
|
||||
"_merge",
|
||||
];
|
||||
PropOrder._FOUNDRY_GENERIC_FEATURE = [
|
||||
"name",
|
||||
"source",
|
||||
|
||||
"isIgnored",
|
||||
|
||||
"type",
|
||||
"system",
|
||||
"actorDataMod",
|
||||
"effects",
|
||||
"ignoreSrdEffects",
|
||||
"flags",
|
||||
"img",
|
||||
|
||||
"entries",
|
||||
|
||||
new PropOrder._ObjectKey("entryData", {
|
||||
fnGetOrder: () => PropOrder._ENTRY_DATA_OBJECT,
|
||||
}),
|
||||
|
||||
"_merge",
|
||||
];
|
||||
PropOrder._MONSTER = [
|
||||
"name",
|
||||
"shortName",
|
||||
@@ -335,6 +397,7 @@ PropOrder._FOUNDRY_MONSTER = [
|
||||
"source",
|
||||
|
||||
"system",
|
||||
"prototypeToken",
|
||||
"effects",
|
||||
"flags",
|
||||
"img",
|
||||
@@ -450,15 +513,6 @@ PropOrder._ROLL20_SPELL = [
|
||||
}),
|
||||
"shapedData",
|
||||
];
|
||||
PropOrder._FOUNDRY_SPELL = [
|
||||
"name",
|
||||
"source",
|
||||
|
||||
"system",
|
||||
"effects",
|
||||
"flags",
|
||||
"img",
|
||||
];
|
||||
PropOrder._SPELL__COPY_MOD = [
|
||||
"*",
|
||||
"_",
|
||||
@@ -739,6 +793,21 @@ PropOrder._SUBCLASS__COPY_MOD = [
|
||||
"_",
|
||||
...PropOrder._SUBCLASS,
|
||||
];
|
||||
PropOrder._FOUNDRY_SUBCLASS = [
|
||||
"name",
|
||||
"source",
|
||||
"className",
|
||||
"classSource",
|
||||
|
||||
"advancement",
|
||||
"chooseSystem",
|
||||
"isChooseSystemRenderEntries",
|
||||
"isChooseFlagsRenderEntries",
|
||||
"isIgnored",
|
||||
"ignoreSrdEffects",
|
||||
"actorDataMod",
|
||||
"actorTokenMod",
|
||||
];
|
||||
PropOrder._ENTRY_DATA_OBJECT = [
|
||||
"languageProficiencies",
|
||||
"skillProficiencies",
|
||||
@@ -1110,15 +1179,6 @@ PropOrder._FEAT__COPY_MOD = [
|
||||
"_",
|
||||
...PropOrder._FEAT,
|
||||
];
|
||||
PropOrder._FOUNDRY_FEAT = [
|
||||
"name",
|
||||
"source",
|
||||
|
||||
"system",
|
||||
"effects",
|
||||
"flags",
|
||||
"img",
|
||||
];
|
||||
PropOrder._VEHICLE = [
|
||||
"name",
|
||||
|
||||
@@ -1158,7 +1218,9 @@ PropOrder._VEHICLE = [
|
||||
|
||||
"hp",
|
||||
|
||||
"resist",
|
||||
"immune",
|
||||
"vulnerable",
|
||||
"conditionImmune",
|
||||
|
||||
"hull",
|
||||
@@ -1319,6 +1381,7 @@ PropOrder._ITEM = [
|
||||
"bonusSavingThrow",
|
||||
"bonusAbilityCheck",
|
||||
"bonusProficiencyBonus",
|
||||
"bonusSavingThrowConcentration",
|
||||
"modifySpeed",
|
||||
"reach",
|
||||
"critThreshold",
|
||||
@@ -1679,11 +1742,26 @@ PropOrder._FOUNDRY_RACE_FEATURE = [
|
||||
"raceName",
|
||||
"raceSource",
|
||||
|
||||
PropOrder._ObjectKey.getCopyKey({
|
||||
identKeys: [
|
||||
"name",
|
||||
"source",
|
||||
"raceName",
|
||||
"raceSource",
|
||||
],
|
||||
fnGetModOrder: () => PropOrder._FOUNDRY_RACE_FEATURE__COPY_MOD,
|
||||
}),
|
||||
|
||||
"system",
|
||||
"effects",
|
||||
"flags",
|
||||
"img",
|
||||
];
|
||||
PropOrder._FOUNDRY_RACE_FEATURE__COPY_MOD = [
|
||||
"*",
|
||||
"_",
|
||||
...PropOrder._FOUNDRY_RACE_FEATURE,
|
||||
];
|
||||
PropOrder._TABLE = [
|
||||
"name",
|
||||
|
||||
@@ -1915,6 +1993,7 @@ PropOrder._CITATION = [
|
||||
];
|
||||
|
||||
PropOrder._PROP_TO_LIST = {
|
||||
"_meta": PropOrder._META,
|
||||
"monster": PropOrder._MONSTER,
|
||||
"foundryMonster": PropOrder._FOUNDRY_MONSTER,
|
||||
"monsterFluff": PropOrder._GENERIC_FLUFF,
|
||||
@@ -1935,9 +2014,10 @@ PropOrder._PROP_TO_LIST = {
|
||||
"hazardFluff": PropOrder._GENERIC_FLUFF,
|
||||
"spell": PropOrder._SPELL,
|
||||
"roll20Spell": PropOrder._ROLL20_SPELL,
|
||||
"foundrySpell": PropOrder._FOUNDRY_SPELL,
|
||||
"foundrySpell": PropOrder._FOUNDRY_GENERIC,
|
||||
"spellList": PropOrder._SPELL_LIST,
|
||||
"action": PropOrder._ACTION,
|
||||
"foundryAction": PropOrder._FOUNDRY_GENERIC,
|
||||
"adventure": PropOrder._ADVENTURE,
|
||||
"adventureData": PropOrder._ADVENTURE_DATA,
|
||||
"book": PropOrder._BOOK,
|
||||
@@ -1947,6 +2027,7 @@ PropOrder._PROP_TO_LIST = {
|
||||
"class": PropOrder._CLASS,
|
||||
"foundryClass": PropOrder._FOUNDRY_CLASS,
|
||||
"subclass": PropOrder._SUBCLASS,
|
||||
"foundrySubclass": PropOrder._FOUNDRY_SUBCLASS,
|
||||
"classFeature": PropOrder._CLASS_FEATURE,
|
||||
"subclassFeature": PropOrder._SUBCLASS_FEATURE,
|
||||
"foundryClassFeature": PropOrder._FOUNDRY_CLASS_FEATURE,
|
||||
@@ -1961,21 +2042,28 @@ PropOrder._PROP_TO_LIST = {
|
||||
"boon": PropOrder._BOON,
|
||||
"deity": PropOrder._DEITY,
|
||||
"feat": PropOrder._FEAT,
|
||||
"foundryFeat": PropOrder._FOUNDRY_FEAT,
|
||||
"foundryFeat": PropOrder._FOUNDRY_GENERIC_FEATURE,
|
||||
"vehicle": PropOrder._VEHICLE,
|
||||
"vehicleUpgrade": PropOrder._VEHICLE_UPGRADE,
|
||||
"foundryVehicleUpgrade": PropOrder._FOUNDRY_GENERIC_FEATURE,
|
||||
"item": PropOrder._ITEM,
|
||||
"foundryItem": PropOrder._FOUNDRY_GENERIC,
|
||||
"baseitem": PropOrder._ITEM,
|
||||
"magicvariant": PropOrder._MAGICVARIANT,
|
||||
"foundryMagicvariant": PropOrder._FOUNDRY_GENERIC,
|
||||
"itemGroup": PropOrder._ITEM,
|
||||
"itemMastery": PropOrder._ITEM_MASTERY,
|
||||
"object": PropOrder._OBJECT,
|
||||
"optionalfeature": PropOrder._OPTIONALFEATURE,
|
||||
"foundryOptionalfeature": PropOrder._FOUNDRY_GENERIC_FEATURE,
|
||||
"psionic": PropOrder._PSIONIC,
|
||||
"foundryPsionic": PropOrder._FOUNDRY_GENERIC_FEATURE,
|
||||
"reward": PropOrder._REWARD,
|
||||
"foundryReward": PropOrder._FOUNDRY_GENERIC_FEATURE,
|
||||
"variantrule": PropOrder._VARIANTRULE,
|
||||
"spellFluff": PropOrder._GENERIC_FLUFF,
|
||||
"race": PropOrder._RACE,
|
||||
"foundryRace": PropOrder._FOUNDRY_GENERIC_FEATURE,
|
||||
"subrace": PropOrder._SUBRACE,
|
||||
"foundryRaceFeature": PropOrder._FOUNDRY_RACE_FEATURE,
|
||||
"table": PropOrder._TABLE,
|
||||
|
||||
@@ -1406,7 +1406,7 @@ class TabUiUtilSide extends TabUiUtilBase {
|
||||
super.decorate(obj, {isInitMeta});
|
||||
|
||||
obj.__$getBtnTab = function ({isSingleTab, tabMeta, _propProxy, propActive, ixTab}) {
|
||||
return isSingleTab ? null : $(`<button class="btn btn-default btn-sm ui-tab-side__btn-tab mb-2 br-0 btr-0 bbr-0 text-left ve-flex-v-center" title="${tabMeta.name.qq()}"><div class="${tabMeta.icon} ui-tab-side__icon-tab mr-2 mobile-ish__mr-0 ve-text-center"></div><div class="mobile-ish__hidden">${tabMeta.name.qq()}</div></button>`)
|
||||
return isSingleTab ? null : $(`<button class="btn btn-default btn-sm ui-tab-side__btn-tab mb-2 br-0 btr-0 bbr-0 text-left ve-flex-v-center" title="${tabMeta.name.qq()}"><div class="${tabMeta.icon} ui-tab-side__icon-tab mr-2 mobile-lg__mr-0 ve-text-center"></div><div class="mobile-lg__hidden">${tabMeta.name.qq()}</div></button>`)
|
||||
.click(() => this[_propProxy][propActive] = ixTab);
|
||||
};
|
||||
|
||||
@@ -3496,11 +3496,14 @@ class SourceUiUtil {
|
||||
$iptJson.removeClass("form-control--error");
|
||||
});
|
||||
if (options.source) $iptJson.val(options.source.json);
|
||||
const $iptVersion = $(`<input class="form-control ui-source__ipt-named">`)
|
||||
.keydown(evt => { if (evt.key === "Escape") $iptUrl.blur(); });
|
||||
if (options.source) $iptVersion.val(options.source.version);
|
||||
let hasColor = false;
|
||||
const $iptColor = $(`<input type="color" class="w-100 b-0">`)
|
||||
.keydown(evt => { if (evt.key === "Escape") $iptColor.blur(); })
|
||||
.change(() => hasColor = true);
|
||||
if (options.source?.color != null) { hasColor = true; $iptColor.val(options.source.color); }
|
||||
if (options.source?.color != null) { hasColor = true; $iptColor.val(`#${options.source.color}`); }
|
||||
const $iptUrl = $(`<input class="form-control ui-source__ipt-named">`)
|
||||
.keydown(evt => { if (evt.key === "Escape") $iptUrl.blur(); });
|
||||
if (options.source) $iptUrl.val(options.source.url);
|
||||
@@ -3531,11 +3534,19 @@ class SourceUiUtil {
|
||||
json: jsonVal,
|
||||
abbreviation: $iptAbv.val().trim(),
|
||||
full: $iptName.val().trim(),
|
||||
url: $iptUrl.val().trim(),
|
||||
authors: $iptAuthors.val().trim().split(",").map(it => it.trim()).filter(Boolean),
|
||||
convertedBy: $iptConverters.val().trim().split(",").map(it => it.trim()).filter(Boolean),
|
||||
version: $iptVersion.val().trim() || "1.0.0",
|
||||
};
|
||||
if (hasColor) source.color = $iptColor.val().trim();
|
||||
|
||||
const url = $iptUrl.val().trim();
|
||||
if (url) source.url = url;
|
||||
|
||||
const authors = $iptAuthors.val().trim().split(",").map(it => it.trim()).filter(Boolean);
|
||||
if (authors.length) source.authors = authors;
|
||||
|
||||
const convertedBy = $iptConverters.val().trim().split(",").map(it => it.trim()).filter(Boolean);
|
||||
if (convertedBy.length) source.convertedBy = convertedBy;
|
||||
|
||||
if (hasColor) source.color = $iptColor.val().trim().replace(/^#/, "");
|
||||
|
||||
await options.cbConfirm(source, options.mode !== "edit");
|
||||
});
|
||||
@@ -3567,6 +3578,10 @@ class SourceUiUtil {
|
||||
<span class="mr-2 ui-source__name help" title="This will be used to identify your homebrew universally, so should be unique to you and you alone">JSON Identifier</span>
|
||||
${$iptJson}
|
||||
</div></div>
|
||||
<div class="ui-source__row mb-2"><div class="ve-col-12 ve-flex-v-center">
|
||||
<span class="mr-2 ui-source__name help" title="A version identifier, e.g. "1.0.0" or "draft 1"">Version</span>
|
||||
${$iptVersion}
|
||||
</div></div>
|
||||
<div class="ui-source__row mb-2"><div class="ve-col-12 ve-flex-v-center">
|
||||
<span class="mr-2 ui-source__name help" title="A color which should be used when displaying the source abbreviation">Color</span>
|
||||
${$iptColor}
|
||||
|
||||
153
js/utils.js
153
js/utils.js
@@ -2,7 +2,7 @@
|
||||
|
||||
// in deployment, `IS_DEPLOYED = "<version number>";` should be set below.
|
||||
globalThis.IS_DEPLOYED = undefined;
|
||||
globalThis.VERSION_NUMBER = /* 5ETOOLS_VERSION__OPEN */"1.201.1"/* 5ETOOLS_VERSION__CLOSE */;
|
||||
globalThis.VERSION_NUMBER = /* 5ETOOLS_VERSION__OPEN */"1.202.0"/* 5ETOOLS_VERSION__CLOSE */;
|
||||
globalThis.DEPLOYED_IMG_ROOT = undefined;
|
||||
// for the roll20 script to set
|
||||
globalThis.IS_VTT = false;
|
||||
@@ -1293,12 +1293,12 @@ globalThis.ObjUtil = {
|
||||
},
|
||||
};
|
||||
|
||||
// TODO refactor other misc utils into this
|
||||
globalThis.MiscUtil = {
|
||||
COLOR_HEALTHY: "#00bb20",
|
||||
COLOR_HURT: "#c5ca00",
|
||||
COLOR_BLOODIED: "#f7a100",
|
||||
COLOR_DEFEATED: "#cc0000",
|
||||
// TODO refactor specific utils out of this
|
||||
globalThis.MiscUtil = class {
|
||||
static COLOR_HEALTHY = "#00bb20";
|
||||
static COLOR_HURT = "#c5ca00";
|
||||
static COLOR_BLOODIED = "#f7a100";
|
||||
static COLOR_DEFEATED = "#cc0000";
|
||||
|
||||
/**
|
||||
* @param obj
|
||||
@@ -1306,12 +1306,12 @@ globalThis.MiscUtil = {
|
||||
* @param isPreserveUndefinedValueKeys Otherwise, drops the keys of `undefined` values
|
||||
* (e.g. `{a: undefined}` -> `{}`).
|
||||
*/
|
||||
copy (obj, {isSafe = false, isPreserveUndefinedValueKeys = false} = {}) {
|
||||
static copy (obj, {isSafe = false, isPreserveUndefinedValueKeys = false} = {}) {
|
||||
if (isSafe && obj === undefined) return undefined; // Generally use "unsafe," as this helps identify bugs.
|
||||
return JSON.parse(JSON.stringify(obj));
|
||||
},
|
||||
}
|
||||
|
||||
copyFast (obj) {
|
||||
static copyFast (obj) {
|
||||
if ((typeof obj !== "object") || obj == null) return obj;
|
||||
|
||||
if (obj instanceof Array) return obj.map(MiscUtil.copyFast);
|
||||
@@ -1319,9 +1319,9 @@ globalThis.MiscUtil = {
|
||||
const cpy = {};
|
||||
for (const k of Object.keys(obj)) cpy[k] = MiscUtil.copyFast(obj[k]);
|
||||
return cpy;
|
||||
},
|
||||
}
|
||||
|
||||
async pCopyTextToClipboard (text) {
|
||||
static async pCopyTextToClipboard (text) {
|
||||
function doCompatibilityCopy () {
|
||||
const $iptTemp = $(`<textarea class="clp__wrp-temp"></textarea>`)
|
||||
.appendTo(document.body)
|
||||
@@ -1339,26 +1339,26 @@ globalThis.MiscUtil = {
|
||||
} else doCompatibilityCopy();
|
||||
} catch (e) { doCompatibilityCopy(); }
|
||||
} else doCompatibilityCopy();
|
||||
},
|
||||
}
|
||||
|
||||
checkProperty (object, ...path) {
|
||||
static checkProperty (object, ...path) {
|
||||
for (let i = 0; i < path.length; ++i) {
|
||||
object = object[path[i]];
|
||||
if (object == null) return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
}
|
||||
|
||||
get (object, ...path) {
|
||||
static get (object, ...path) {
|
||||
if (object == null) return null;
|
||||
for (let i = 0; i < path.length; ++i) {
|
||||
object = object[path[i]];
|
||||
if (object == null) return object;
|
||||
}
|
||||
return object;
|
||||
},
|
||||
}
|
||||
|
||||
set (object, ...pathAndVal) {
|
||||
static set (object, ...pathAndVal) {
|
||||
if (object == null) return null;
|
||||
|
||||
const val = pathAndVal.pop();
|
||||
@@ -1372,31 +1372,31 @@ globalThis.MiscUtil = {
|
||||
}
|
||||
|
||||
return val;
|
||||
},
|
||||
}
|
||||
|
||||
getOrSet (object, ...pathAndVal) {
|
||||
static getOrSet (object, ...pathAndVal) {
|
||||
if (pathAndVal.length < 2) return null;
|
||||
const existing = MiscUtil.get(object, ...pathAndVal.slice(0, -1));
|
||||
if (existing != null) return existing;
|
||||
return MiscUtil.set(object, ...pathAndVal);
|
||||
},
|
||||
}
|
||||
|
||||
getThenSetCopy (object1, object2, ...path) {
|
||||
static getThenSetCopy (object1, object2, ...path) {
|
||||
const val = MiscUtil.get(object1, ...path);
|
||||
return MiscUtil.set(object2, ...path, MiscUtil.copyFast(val, {isSafe: true}));
|
||||
},
|
||||
}
|
||||
|
||||
delete (object, ...path) {
|
||||
static delete (object, ...path) {
|
||||
if (object == null) return object;
|
||||
for (let i = 0; i < path.length - 1; ++i) {
|
||||
object = object[path[i]];
|
||||
if (object == null) return object;
|
||||
}
|
||||
return delete object[path.last()];
|
||||
},
|
||||
}
|
||||
|
||||
/** Delete a prop from a nested object, then all now-empty objects backwards from that point. */
|
||||
deleteObjectPath (object, ...path) {
|
||||
static deleteObjectPath (object, ...path) {
|
||||
const stack = [object];
|
||||
|
||||
if (object == null) return object;
|
||||
@@ -1412,9 +1412,9 @@ globalThis.MiscUtil = {
|
||||
}
|
||||
|
||||
return out;
|
||||
},
|
||||
}
|
||||
|
||||
merge (obj1, obj2) {
|
||||
static merge (obj1, obj2) {
|
||||
obj2 = MiscUtil.copyFast(obj2);
|
||||
|
||||
Object.entries(obj2)
|
||||
@@ -1438,21 +1438,21 @@ globalThis.MiscUtil = {
|
||||
});
|
||||
|
||||
return obj1;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
mix: (superclass) => new MiscUtil._MixinBuilder(superclass),
|
||||
_MixinBuilder: function (superclass) {
|
||||
static mix = (superclass) => new MiscUtil._MixinBuilder(superclass);
|
||||
static _MixinBuilder = function (superclass) {
|
||||
this.superclass = superclass;
|
||||
|
||||
this.with = function (...mixins) {
|
||||
return mixins.reduce((c, mixin) => mixin(c), this.superclass);
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
clearSelection () {
|
||||
static clearSelection () {
|
||||
if (document.getSelection) {
|
||||
document.getSelection().removeAllRanges();
|
||||
document.getSelection().addRange(document.createRange());
|
||||
@@ -1466,9 +1466,9 @@ globalThis.MiscUtil = {
|
||||
} else if (document.selection) {
|
||||
document.selection.empty();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
randomColor () {
|
||||
static randomColor () {
|
||||
let r; let g; let b;
|
||||
const h = RollerUtil.randomise(30, 0) / 30;
|
||||
const i = ~~(h * 6);
|
||||
@@ -1483,7 +1483,7 @@ globalThis.MiscUtil = {
|
||||
case 5: r = 1; g = 0; b = q; break;
|
||||
}
|
||||
return `#${`00${(~~(r * 255)).toString(16)}`.slice(-2)}${`00${(~~(g * 255)).toString(16)}`.slice(-2)}${`00${(~~(b * 255)).toString(16)}`.slice(-2)}`;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param hex Original hex color.
|
||||
@@ -1492,7 +1492,7 @@ globalThis.MiscUtil = {
|
||||
* @param [opts.dark] Color to return if a "dark" color would contrast best.
|
||||
* @param [opts.light] Color to return if a "light" color would contrast best.
|
||||
*/
|
||||
invertColor (hex, opts) {
|
||||
static invertColor (hex, opts) {
|
||||
opts = opts || {};
|
||||
|
||||
hex = hex.slice(1); // remove #
|
||||
@@ -1508,18 +1508,18 @@ globalThis.MiscUtil = {
|
||||
|
||||
r = (255 - r).toString(16); g = (255 - g).toString(16); b = (255 - b).toString(16);
|
||||
return `#${[r, g, b].map(it => it.padStart(2, "0")).join("")}`;
|
||||
},
|
||||
}
|
||||
|
||||
scrollPageTop () {
|
||||
static scrollPageTop () {
|
||||
document.body.scrollTop = document.documentElement.scrollTop = 0;
|
||||
},
|
||||
}
|
||||
|
||||
expEval (str) {
|
||||
static expEval (str) {
|
||||
// eslint-disable-next-line no-new-func
|
||||
return new Function(`return ${str.replace(/[^-()\d/*+.]/g, "")}`)();
|
||||
},
|
||||
}
|
||||
|
||||
parseNumberRange (input, min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER) {
|
||||
static parseNumberRange (input, min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER) {
|
||||
if (!input || !input.trim()) return null;
|
||||
|
||||
const errInvalid = input => { throw new Error(`Could not parse range input "${input}"`); };
|
||||
@@ -1563,9 +1563,9 @@ globalThis.MiscUtil = {
|
||||
}
|
||||
|
||||
return out;
|
||||
},
|
||||
}
|
||||
|
||||
findCommonPrefix (strArr, {isRespectWordBoundaries} = {}) {
|
||||
static findCommonPrefix (strArr, {isRespectWordBoundaries} = {}) {
|
||||
if (isRespectWordBoundaries) {
|
||||
return MiscUtil._findCommonPrefixSuffixWords({strArr});
|
||||
}
|
||||
@@ -1588,15 +1588,15 @@ globalThis.MiscUtil = {
|
||||
}
|
||||
});
|
||||
return prefix;
|
||||
},
|
||||
}
|
||||
|
||||
findCommonSuffix (strArr, {isRespectWordBoundaries} = {}) {
|
||||
static findCommonSuffix (strArr, {isRespectWordBoundaries} = {}) {
|
||||
if (!isRespectWordBoundaries) throw new Error(`Unimplemented!`);
|
||||
|
||||
return MiscUtil._findCommonPrefixSuffixWords({strArr, isSuffix: true});
|
||||
},
|
||||
}
|
||||
|
||||
_findCommonPrefixSuffixWords ({strArr, isSuffix}) {
|
||||
static _findCommonPrefixSuffixWords ({strArr, isSuffix}) {
|
||||
let prefixTks = null;
|
||||
let lenMax = -1;
|
||||
|
||||
@@ -1633,18 +1633,18 @@ globalThis.MiscUtil = {
|
||||
return isSuffix
|
||||
? ` ${prefixTks.join(" ")}`
|
||||
: `${prefixTks.join(" ")} `;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fgHexTarget Target/resultant color for the foreground item
|
||||
* @param fgOpacity Desired foreground transparency (0-1 inclusive)
|
||||
* @param bgHex Background color
|
||||
*/
|
||||
calculateBlendedColor (fgHexTarget, fgOpacity, bgHex) {
|
||||
static calculateBlendedColor (fgHexTarget, fgOpacity, bgHex) {
|
||||
const fgDcTarget = CryptUtil.hex2Dec(fgHexTarget);
|
||||
const bgDc = CryptUtil.hex2Dec(bgHex);
|
||||
return ((fgDcTarget - ((1 - fgOpacity) * bgDc)) / fgOpacity).toString(16);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Borrowed from lodash.
|
||||
@@ -1654,7 +1654,7 @@ globalThis.MiscUtil = {
|
||||
* @param options Options object.
|
||||
* @return {Function} The debounced function.
|
||||
*/
|
||||
debounce (func, wait, options) {
|
||||
static debounce (func, wait, options) {
|
||||
let lastArgs; let lastThis; let maxWait; let result; let timerId; let lastCallTime; let lastInvokeTime = 0; let leading = false; let maxing = false; let trailing = true;
|
||||
|
||||
wait = Number(wait) || 0;
|
||||
@@ -1739,10 +1739,10 @@ globalThis.MiscUtil = {
|
||||
debounced.cancel = cancel;
|
||||
debounced.flush = flush;
|
||||
return debounced;
|
||||
},
|
||||
}
|
||||
|
||||
// from lodash
|
||||
throttle (func, wait, options) {
|
||||
static throttle (func, wait, options) {
|
||||
let leading = true; let trailing = true;
|
||||
|
||||
if (typeof options === "object") {
|
||||
@@ -1751,13 +1751,13 @@ globalThis.MiscUtil = {
|
||||
}
|
||||
|
||||
return this.debounce(func, wait, {leading, maxWait: wait, trailing});
|
||||
},
|
||||
}
|
||||
|
||||
pDelay (msecs, resolveAs) {
|
||||
static pDelay (msecs, resolveAs) {
|
||||
return new Promise(resolve => setTimeout(() => resolve(resolveAs), msecs));
|
||||
},
|
||||
}
|
||||
|
||||
GENERIC_WALKER_ENTRIES_KEY_BLOCKLIST: new Set(["caption", "type", "colLabels", "colLabelGroups", "name", "colStyles", "style", "shortName", "subclassShortName", "id", "path"]),
|
||||
static GENERIC_WALKER_ENTRIES_KEY_BLOCKLIST = new Set(["caption", "type", "colLabels", "colLabelGroups", "name", "colStyles", "style", "shortName", "subclassShortName", "id", "path"]);
|
||||
|
||||
/**
|
||||
* @param [opts]
|
||||
@@ -1771,7 +1771,7 @@ globalThis.MiscUtil = {
|
||||
* @param [opts.isNoModification] If the walker should not attempt to modify the data.
|
||||
* @param [opts.isBreakOnReturn] If the walker should fast-exist on any handler returning a value.
|
||||
*/
|
||||
getWalker (opts) {
|
||||
static getWalker (opts) {
|
||||
opts = opts || {};
|
||||
|
||||
if (opts.isBreakOnReturn && !opts.isNoModification) throw new Error(`"isBreakOnReturn" may only be used in "isNoModification" mode!`);
|
||||
@@ -1893,9 +1893,9 @@ globalThis.MiscUtil = {
|
||||
};
|
||||
|
||||
return {walk: fn};
|
||||
},
|
||||
}
|
||||
|
||||
_getWalker_applyHandlers ({opts, handlers, obj, lastKey, stack}) {
|
||||
static _getWalker_applyHandlers ({opts, handlers, obj, lastKey, stack}) {
|
||||
handlers = handlers instanceof Array ? handlers : [handlers];
|
||||
const didBreak = handlers.some(h => {
|
||||
const out = h(obj, lastKey, stack);
|
||||
@@ -1904,12 +1904,12 @@ globalThis.MiscUtil = {
|
||||
});
|
||||
if (didBreak) return VeCt.SYM_WALKER_BREAK;
|
||||
return obj;
|
||||
},
|
||||
}
|
||||
|
||||
_getWalker_runHandlers ({handlers, obj, lastKey, stack}) {
|
||||
static _getWalker_runHandlers ({handlers, obj, lastKey, stack}) {
|
||||
handlers = handlers instanceof Array ? handlers : [handlers];
|
||||
handlers.forEach(h => h(obj, lastKey, stack));
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO refresh to match sync version
|
||||
@@ -1923,7 +1923,7 @@ globalThis.MiscUtil = {
|
||||
* @param [opts.isDepthFirst] If array/object recursion should occur before array/object primitive handling.
|
||||
* @param [opts.isNoModification] If the walker should not attempt to modify the data.
|
||||
*/
|
||||
getAsyncWalker (opts) {
|
||||
static getAsyncWalker (opts) {
|
||||
opts = opts || {};
|
||||
const keyBlocklist = opts.keyBlocklist || new Set();
|
||||
|
||||
@@ -2040,25 +2040,32 @@ globalThis.MiscUtil = {
|
||||
};
|
||||
|
||||
return {pWalk: pFn};
|
||||
},
|
||||
}
|
||||
|
||||
async _getAsyncWalker_pApplyHandlers ({opts, handlers, obj, lastKey, stack}) {
|
||||
static async _getAsyncWalker_pApplyHandlers ({opts, handlers, obj, lastKey, stack}) {
|
||||
handlers = handlers instanceof Array ? handlers : [handlers];
|
||||
await handlers.pSerialAwaitMap(async pH => {
|
||||
const out = await pH(obj, lastKey, stack);
|
||||
if (!opts.isNoModification) obj = out;
|
||||
});
|
||||
return obj;
|
||||
},
|
||||
}
|
||||
|
||||
async _getAsyncWalker_pRunHandlers ({handlers, obj, lastKey, stack}) {
|
||||
static async _getAsyncWalker_pRunHandlers ({handlers, obj, lastKey, stack}) {
|
||||
handlers = handlers instanceof Array ? handlers : [handlers];
|
||||
await handlers.pSerialAwaitMap(pH => pH(obj, lastKey, stack));
|
||||
},
|
||||
}
|
||||
|
||||
pDefer (fn) {
|
||||
static pDefer (fn) {
|
||||
return (async () => fn())();
|
||||
},
|
||||
}
|
||||
|
||||
static isNearStrictlyEqual (a, b) {
|
||||
if (a == null && b == null) return true;
|
||||
if (a == null && b != null) return false;
|
||||
if (a != null && b == null) return false;
|
||||
return a === b;
|
||||
}
|
||||
};
|
||||
|
||||
// EVENT HANDLERS ======================================================================================================
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
"use strict";
|
||||
|
||||
class VariantRulesSublistManager extends SublistManager {
|
||||
constructor () {
|
||||
super({
|
||||
sublistClass: "subvariantrules",
|
||||
});
|
||||
}
|
||||
|
||||
static get _ROW_TEMPLATE () {
|
||||
return [
|
||||
new SublistCellTemplate({
|
||||
@@ -58,8 +52,6 @@ class VariantRulesPage extends ListPage {
|
||||
|
||||
pageFilter,
|
||||
|
||||
listClass: "variantrules",
|
||||
|
||||
dataProps: ["variantrule"],
|
||||
|
||||
isMarkdownPopout: true,
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
"use strict";
|
||||
|
||||
class VehiclesSublistManager extends SublistManager {
|
||||
constructor () {
|
||||
super({
|
||||
sublistClass: "subvehicles",
|
||||
});
|
||||
}
|
||||
|
||||
static get _ROW_TEMPLATE () {
|
||||
return [
|
||||
new SublistCellTemplate({
|
||||
@@ -66,8 +60,6 @@ class VehiclesPage extends ListPage {
|
||||
|
||||
pageFilter,
|
||||
|
||||
listClass: "vehicles",
|
||||
|
||||
dataProps: ["vehicle", "vehicleUpgrade"],
|
||||
|
||||
isMarkdownPopout: true,
|
||||
|
||||
Reference in New Issue
Block a user