mirror of
https://github.com/Kornstalx/5etools-mirror-2.github.io.git
synced 2025-10-28 20:45:35 -05:00
v1.209.2
This commit is contained in:
@@ -565,6 +565,9 @@ class BookUtil {
|
||||
if (await this._booksHashChange_pDoLoadPrerelease({bookId, $contents, hashParts, isNewBook})) return;
|
||||
if (await this._booksHashChange_pDoLoadBrew({bookId, $contents, hashParts, isNewBook})) return;
|
||||
|
||||
// if it's prerelease/homebrew but hasn't been loaded
|
||||
if (await this._booksHashChange_pDoFetchPrereleaseBrew({bookId, $contents, hashParts, isNewBook})) return;
|
||||
|
||||
return this._booksHashChange_handleNotFound({$contents, bookId});
|
||||
}
|
||||
|
||||
@@ -595,6 +598,27 @@ class BookUtil {
|
||||
return true;
|
||||
}
|
||||
|
||||
static async _booksHashChange_pDoFetchPrereleaseBrew ({bookId, $contents, hashParts, isNewBook}) {
|
||||
const {source} = await UrlUtil.pAutoDecodeHash(bookId);
|
||||
|
||||
const loaded = await DataLoader.pCacheAndGetHash(UrlUtil.getCurrentPage(), bookId, {isSilent: true});
|
||||
if (!loaded) return false;
|
||||
|
||||
return [
|
||||
PrereleaseUtil,
|
||||
BrewUtil2,
|
||||
]
|
||||
.some(brewUtil => {
|
||||
if (
|
||||
brewUtil.hasSourceJson(source)
|
||||
&& brewUtil.isReloadRequired()
|
||||
) {
|
||||
brewUtil.doLocationReload({isRetainHash: true});
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static _booksHashChange_getCleanName (fromIndex) {
|
||||
if (fromIndex.parentSource) {
|
||||
const fullParentSource = Parser.sourceJsonToFull(fromIndex.parentSource);
|
||||
|
||||
@@ -88,41 +88,42 @@ class UtilClassesPage {
|
||||
Renderer.get().setFirstSection(true);
|
||||
|
||||
if (hasEntries) {
|
||||
const renderer = Renderer.get();
|
||||
Renderer.get().withDepthTracker(
|
||||
depthArr || [],
|
||||
({renderer}) => {
|
||||
entFluff.entries.filter(f => f.source === ent.source).forEach(f => f._isStandardSource = true);
|
||||
|
||||
if (depthArr) renderer.setDepthTracker(depthArr, {additionalPropsInherited: ["_isStandardSource"]});
|
||||
else renderer.setDepthTracker([]);
|
||||
entFluff.entries.forEach((f, i) => {
|
||||
const cpy = MiscUtil.copyFast(f);
|
||||
|
||||
entFluff.entries.filter(f => f.source === ent.source).forEach(f => f._isStandardSource = true);
|
||||
// Remove the name from the first section if it is a copy of the class/subclass name
|
||||
if (
|
||||
isRemoveRootName
|
||||
&& i === 0
|
||||
&& cpy.name
|
||||
&& (
|
||||
cpy.name.toLowerCase() === ent.name.toLowerCase()
|
||||
|| cpy.name.toLowerCase() === `the ${ent.name.toLowerCase()}`
|
||||
)
|
||||
) {
|
||||
delete cpy.name;
|
||||
}
|
||||
|
||||
entFluff.entries.forEach((f, i) => {
|
||||
const cpy = MiscUtil.copyFast(f);
|
||||
if (
|
||||
isAddSourceNote
|
||||
&& typeof cpy !== "string"
|
||||
&& cpy.source
|
||||
&& cpy.source !== ent.source
|
||||
&& cpy.entries
|
||||
) {
|
||||
cpy.entries.unshift(`{@note The following information is from ${Parser.sourceJsonToFull(cpy.source)}${Renderer.utils.isDisplayPage(cpy.page) ? `, page ${cpy.page}` : ""}.}`);
|
||||
}
|
||||
|
||||
// Remove the name from the first section if it is a copy of the class/subclass name
|
||||
if (
|
||||
isRemoveRootName
|
||||
&& i === 0
|
||||
&& cpy.name
|
||||
&& (
|
||||
cpy.name.toLowerCase() === ent.name.toLowerCase()
|
||||
|| cpy.name.toLowerCase() === `the ${ent.name.toLowerCase()}`
|
||||
)
|
||||
) {
|
||||
delete cpy.name;
|
||||
}
|
||||
|
||||
if (
|
||||
isAddSourceNote
|
||||
&& typeof cpy !== "string"
|
||||
&& cpy.source
|
||||
&& cpy.source !== ent.source
|
||||
&& cpy.entries
|
||||
) {
|
||||
cpy.entries.unshift(`{@note The following information is from ${Parser.sourceJsonToFull(cpy.source)}${Renderer.utils.isDisplayPage(cpy.page) ? `, page ${cpy.page}` : ""}.}`);
|
||||
}
|
||||
|
||||
stack += renderer.render(cpy);
|
||||
});
|
||||
stack += renderer.render(cpy);
|
||||
});
|
||||
},
|
||||
{additionalPropsInherited: ["_isStandardSource"]},
|
||||
);
|
||||
}
|
||||
|
||||
if (hasImages) {
|
||||
@@ -2158,9 +2159,15 @@ class ClassesPage extends MixinComponentGlobalState(MixinBaseComponent(MixinProx
|
||||
if (source === cls.source) return {isSkip: true};
|
||||
},
|
||||
fn: () => {
|
||||
return $(`<tr data-scroll-id="${ixLvl}-${ixFeature}" data-feature-type="class" class="cls-main__linked-titles"><td colspan="6"></td></tr>`)
|
||||
.fastSetHtml(Renderer.get().setDepthTracker(depthArr, {additionalProps: ["isReprinted"], additionalPropsInherited: ["_isStandardSource", "isClassFeatureVariant"]}).render(feature))
|
||||
.appendTo($content);
|
||||
return Renderer.get().withDepthTracker(
|
||||
depthArr,
|
||||
({renderer}) => {
|
||||
return $(`<tr data-scroll-id="${ixLvl}-${ixFeature}" data-feature-type="class" class="cls-main__linked-titles"><td colspan="6"></td></tr>`)
|
||||
.fastSetHtml(renderer.render(feature))
|
||||
.appendTo($content);
|
||||
},
|
||||
{additionalProps: ["isReprinted"], additionalPropsInherited: ["_isStandardSource", "isClassFeatureVariant"]},
|
||||
);
|
||||
},
|
||||
});
|
||||
this._trackOutlineCfData(ixLvl, ixFeature, depthArr);
|
||||
@@ -2173,7 +2180,7 @@ class ClassesPage extends MixinComponentGlobalState(MixinBaseComponent(MixinProx
|
||||
|
||||
// Add a placeholder feature to display when no subclasses are active
|
||||
const $trSubclassFeature = $(`<tr class="cls-main__sc-feature" data-subclass-none-message="true"><td colspan="6"></td></tr>`)
|
||||
.fastSetHtml(Renderer.get().setDepthTracker([]).render({type: "entries", entries: [{name: `{@note No Subclass Selected}`, type: "entries", entries: [`{@note <span class="clickable roller" data-jump-select-a-subclass="true">Select a subclass</span> to view its feature(s) here.}`]}]}))
|
||||
.fastSetHtml(Renderer.get().withDepthTracker([], ({renderer}) => renderer.render({type: "entries", entries: [{name: `{@note No Subclass Selected}`, type: "entries", entries: [`{@note <span class="clickable roller" data-jump-select-a-subclass="true">Select a subclass</span> to view its feature(s) here.}`]}]})))
|
||||
.appendTo($content);
|
||||
|
||||
await cls.subclasses.pSerialAwaitMap(async sc => {
|
||||
@@ -2224,7 +2231,9 @@ class ClassesPage extends MixinComponentGlobalState(MixinBaseComponent(MixinProx
|
||||
},
|
||||
fn: () => {
|
||||
const $trSubclassFeature = $(`<tr class="cls-main__sc-feature" data-subclass-id="${UrlUtil.getStateKeySubclass(sc)}"><td colspan="6"></td></tr>`)
|
||||
.fastSetHtml(Renderer.get().setDepthTracker(depthArr, {additionalProps: ["isReprinted"], additionalPropsInherited: ["_isStandardSource", "isClassFeatureVariant"]}).render(toRender))
|
||||
.fastSetHtml(
|
||||
Renderer.get().withDepthTracker(depthArr, ({renderer}) => renderer.render(toRender), {additionalProps: ["isReprinted"], additionalPropsInherited: ["_isStandardSource", "isClassFeatureVariant"]}),
|
||||
)
|
||||
.appendTo($content);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -422,11 +422,11 @@ class SublistManager {
|
||||
await this.pDoSublistRemove({entity, doFinalize: true});
|
||||
}
|
||||
|
||||
getTitleBtnAdd () { return `Add (SHIFT for ${this._shiftCountAddSubtract})`; }
|
||||
getTitleBtnSubtract () { return `Subtract (SHIFT for ${this._shiftCountAddSubtract})`; }
|
||||
getTitleBtnAdd () { return `Add (SHIFT for ${this._shiftCountAddSubtract}) (Hotkey: p)`; }
|
||||
getTitleBtnSubtract () { return `Subtract (SHIFT for ${this._shiftCountAddSubtract}) (Hotkey: P)`; }
|
||||
|
||||
async pHandleClick_btnAdd ({evt, entity}) {
|
||||
const addCount = evt.shiftKey ? this._shiftCountAddSubtract : 1;
|
||||
async pHandleClick_btnAdd ({entity, isMultiple = false}) {
|
||||
const addCount = isMultiple ? this._shiftCountAddSubtract : 1;
|
||||
return this.pDoSublistAdd({
|
||||
index: Hist.lastLoadedId,
|
||||
entity,
|
||||
@@ -435,8 +435,8 @@ class SublistManager {
|
||||
});
|
||||
}
|
||||
|
||||
async pHandleClick_btnSubtract ({evt, entity}) {
|
||||
const subtractCount = evt.shiftKey ? this._shiftCountAddSubtract : 1;
|
||||
async pHandleClick_btnSubtract ({entity, isMultiple = false}) {
|
||||
const subtractCount = isMultiple ? this._shiftCountAddSubtract : 1;
|
||||
return this.pDoSublistSubtract({
|
||||
index: Hist.lastLoadedId,
|
||||
entity,
|
||||
@@ -1567,7 +1567,7 @@ class ListPage {
|
||||
|
||||
const key = EventUtil.getKeyIgnoreCapsLock(evt);
|
||||
switch (key) {
|
||||
// K up; J down
|
||||
// k up; j down
|
||||
case "k":
|
||||
case "j": {
|
||||
// don't switch if the user is typing somewhere else
|
||||
@@ -1576,6 +1576,24 @@ class ListPage {
|
||||
return;
|
||||
}
|
||||
|
||||
// p: toggle pinned/add 1 to sublist
|
||||
case "p": {
|
||||
if (EventUtil.isInInput(evt)) return;
|
||||
if (!this._sublistManager) return;
|
||||
if (this._sublistManager.isSublistItemsCountable) this._sublistManager.pHandleClick_btnAdd({entity: this._lastRender.entity}).then(null);
|
||||
else this._sublistManager.pHandleClick_btnPin({entity: this._lastRender.entity}).then(null);
|
||||
return;
|
||||
}
|
||||
// P: toggle pinned/remove 1 from sublist
|
||||
case "P": {
|
||||
if (EventUtil.isInInput(evt)) return;
|
||||
if (!this._sublistManager) return;
|
||||
if (this._sublistManager.isSublistItemsCountable) this._sublistManager.pHandleClick_btnSubtract({entity: this._lastRender.entity}).then(null);
|
||||
else this._sublistManager.pHandleClick_btnPin({entity: this._lastRender.entity}).then(null);
|
||||
return;
|
||||
}
|
||||
|
||||
// m: expand/collapse current selection
|
||||
case "m": {
|
||||
if (EventUtil.isInInput(evt)) return;
|
||||
const it = Hist.getSelectedListElementWithLocation();
|
||||
@@ -1735,21 +1753,21 @@ class ListPage {
|
||||
this._getOrTabRightButton(`pin`, `pushpin`)
|
||||
.off("click")
|
||||
.on("click", () => this._sublistManager.pHandleClick_btnPin({entity: this._lastRender.entity}))
|
||||
.title("Pin (Toggle)");
|
||||
.title("Pin (Toggle) (Hotkey: p/P)");
|
||||
}
|
||||
|
||||
_bindAddButton () {
|
||||
this._getOrTabRightButton(`sublist-add`, `plus`)
|
||||
.off("click")
|
||||
.title(this._sublistManager.getTitleBtnAdd())
|
||||
.on("click", evt => this._sublistManager.pHandleClick_btnAdd({evt, entity: this._lastRender.entity}));
|
||||
.on("click", evt => this._sublistManager.pHandleClick_btnAdd({entity: this._lastRender.entity, isMultiple: !!evt.shiftKey}));
|
||||
}
|
||||
|
||||
_bindSubtractButton () {
|
||||
this._getOrTabRightButton(`sublist-subtract`, `minus`)
|
||||
.off("click")
|
||||
.title(this._sublistManager.getTitleBtnSubtract())
|
||||
.on("click", evt => this._sublistManager.pHandleClick_btnSubtract({evt, entity: this._lastRender.entity}));
|
||||
.on("click", evt => this._sublistManager.pHandleClick_btnSubtract({entity: this._lastRender.entity, isMultiple: !!evt.shiftKey}));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -915,8 +915,7 @@ class IndexableFileQuickReference extends IndexableFile {
|
||||
|
||||
static getChapterNameMetas (it, {isRequireQuickrefFlag = true} = {}) {
|
||||
const trackedNames = [];
|
||||
const renderer = Renderer.get().setDepthTracker(trackedNames);
|
||||
renderer.render(it);
|
||||
Renderer.get().withDepthTracker(trackedNames, ({renderer}) => renderer.render(it));
|
||||
|
||||
const nameCounts = {};
|
||||
trackedNames.forEach(meta => {
|
||||
|
||||
82
js/render.js
82
js/render.js
@@ -243,6 +243,50 @@ globalThis.Renderer = function () {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Specify an array where the renderer will record rendered header depths.
|
||||
* Items added to the array are of the form: `{name: "Header Name", depth: 1, type: "entries", source: "PHB"}`
|
||||
* @param arr
|
||||
* @param additionalProps Additional data props which should be tracked per-entry.
|
||||
* @param additionalPropsInherited As per additionalProps, but if a parent entry has the prop, it should be passed
|
||||
* to its children.
|
||||
*/
|
||||
this.setDepthTracker = function (arr, {additionalProps, additionalPropsInherited} = {}) {
|
||||
this._depthTracker = arr;
|
||||
this._depthTrackerAdditionalProps = additionalProps || [];
|
||||
this._depthTrackerAdditionalPropsInherited = additionalPropsInherited || [];
|
||||
return this;
|
||||
};
|
||||
|
||||
this.withDepthTracker = function (arr, fn, {additionalProps, additionalPropsInherited} = {}) {
|
||||
const depthTrackerPrev = this._depthTracker;
|
||||
const depthTrackerAdditionalPropsPrev = this._depthTrackerAdditionalProps;
|
||||
const depthTrackerAdditionalPropsInheritedPrev = this._depthTrackerAdditionalPropsInherited;
|
||||
|
||||
let out;
|
||||
try {
|
||||
this.setDepthTracker(
|
||||
arr,
|
||||
{
|
||||
additionalProps,
|
||||
additionalPropsInherited,
|
||||
},
|
||||
);
|
||||
out = fn({renderer: this});
|
||||
} finally {
|
||||
this.setDepthTracker(
|
||||
depthTrackerPrev,
|
||||
{
|
||||
additionalProps: depthTrackerAdditionalPropsPrev,
|
||||
additionalPropsInherited: depthTrackerAdditionalPropsInheritedPrev,
|
||||
},
|
||||
);
|
||||
}
|
||||
return out;
|
||||
};
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
// region Plugins
|
||||
this.addPlugin = function (pluginType, fnPlugin) {
|
||||
MiscUtil.getOrSet(this._plugins, pluginType, []).push(fnPlugin);
|
||||
@@ -309,21 +353,6 @@ globalThis.Renderer = function () {
|
||||
};
|
||||
// endregion
|
||||
|
||||
/**
|
||||
* Specify an array where the renderer will record rendered header depths.
|
||||
* Items added to the array are of the form: `{name: "Header Name", depth: 1, type: "entries", source: "PHB"}`
|
||||
* @param arr
|
||||
* @param additionalProps Additional data props which should be tracked per-entry.
|
||||
* @param additionalPropsInherited As per additionalProps, but if a parent entry has the prop, it should be passed
|
||||
* to its children.
|
||||
*/
|
||||
this.setDepthTracker = function (arr, {additionalProps, additionalPropsInherited} = {}) {
|
||||
this._depthTracker = arr;
|
||||
this._depthTrackerAdditionalProps = additionalProps || [];
|
||||
this._depthTrackerAdditionalPropsInherited = additionalPropsInherited || [];
|
||||
return this;
|
||||
};
|
||||
|
||||
this.getLineBreak = function () { return "<br>"; };
|
||||
|
||||
/**
|
||||
@@ -1431,19 +1460,26 @@ globalThis.Renderer = function () {
|
||||
};
|
||||
|
||||
this._renderStatblock = function (entry, textStack, meta, options) {
|
||||
this._renderPrefix(entry, textStack, meta, options);
|
||||
|
||||
const page = entry.prop || Renderer.tag.getPage(entry.tag);
|
||||
const source = Parser.getTagSource(entry.tag, entry.source);
|
||||
const hash = entry.hash || (UrlUtil.URL_TO_HASH_BUILDER[page] ? UrlUtil.URL_TO_HASH_BUILDER[page]({...entry, name: entry.name, source}) : null);
|
||||
const tag = entry.tag || Parser.getPropTag(entry.prop);
|
||||
|
||||
const asTag = `{@${entry.tag} ${entry.name}|${source}${entry.displayName ? `|${entry.displayName}` : ""}}`;
|
||||
const asTag = `{@${tag} ${entry.name}|${source}${entry.displayName ? `|${entry.displayName}` : ""}}`;
|
||||
|
||||
const fromPlugins = this._applyPlugins_useFirst(
|
||||
"statblock_render",
|
||||
{textStack, meta, options},
|
||||
{input: {entry, page, source, hash, tag, asTag}},
|
||||
);
|
||||
if (fromPlugins) return void (textStack[0] += fromPlugins);
|
||||
|
||||
if (!page || !source || !hash) {
|
||||
this._renderPrefix(entry, textStack, meta, options);
|
||||
this._renderDataHeader(textStack, entry.name, entry.style);
|
||||
textStack[0] += `<tr>
|
||||
<td colspan="6">
|
||||
<i class="text-danger">Cannot load ${entry.tag ? `"${asTag}"` : entry.displayName || entry.name}! An unknown tag/prop, source, or hash was provided.</i>
|
||||
<i class="text-danger">Cannot load ${tag ? `"${asTag}"` : entry.displayName || entry.name}! An unknown tag/prop, source, or hash was provided.</i>
|
||||
</td>
|
||||
</tr>`;
|
||||
this._renderDataFooter(textStack);
|
||||
@@ -1452,10 +1488,11 @@ globalThis.Renderer = function () {
|
||||
return;
|
||||
}
|
||||
|
||||
this._renderPrefix(entry, textStack, meta, options);
|
||||
this._renderDataHeader(textStack, entry.displayName || entry.name, entry.style, {isCollapsed: entry.collapsed});
|
||||
textStack[0] += `<tr>
|
||||
<td colspan="6" data-rd-tag="${(entry.tag || "").qq()}" data-rd-page="${(page || "").qq()}" data-rd-source="${(source || "").qq()}" data-rd-hash="${(hash || "").qq()}" data-rd-name="${(entry.name || "").qq()}" data-rd-display-name="${(entry.displayName || "").qq()}" data-rd-style="${(entry.style || "").qq()}">
|
||||
<i>Loading ${entry.tag ? `${Renderer.get().render(asTag)}` : entry.displayName || entry.name}...</i>
|
||||
<td colspan="6" data-rd-tag="${(tag || "").qq()}" data-rd-page="${(page || "").qq()}" data-rd-source="${(source || "").qq()}" data-rd-hash="${(hash || "").qq()}" data-rd-name="${(entry.name || "").qq()}" data-rd-display-name="${(entry.displayName || "").qq()}" data-rd-style="${(entry.style || "").qq()}">
|
||||
<i>Loading ${tag ? `${Renderer.get().render(asTag)}` : entry.displayName || entry.name}...</i>
|
||||
<style onload="Renderer.events.handleLoad_inlineStatblock(this)"></style>
|
||||
</td>
|
||||
</tr>`;
|
||||
@@ -10494,7 +10531,7 @@ Renderer.recipe = class {
|
||||
? `{@b {@style Makes|small-caps}} ${ent._scaleFactor ? `${ent._scaleFactor}× ` : ""}${ent.makes}`
|
||||
: null,
|
||||
entryServes: ent.serves
|
||||
? `{@b {@style Serves|small-caps}} ${ent.serves.min ?? ent.serves.exact}${ent.serves.min != null ? " to " : ""}${ent.serves.max ?? ""}`
|
||||
? `{@b {@style Serves|small-caps}} ${ent.serves.min ?? ent.serves.exact}${ent.serves.min != null ? " to " : ""}${ent.serves.max ?? ""}${ent.serves.note ? ` ${ent.serves.note}` : ""}`
|
||||
: null,
|
||||
entryMetasTime: Renderer.recipe._getEntryMetasTime(ent),
|
||||
entryIngredients: {entries: ent._fullIngredients},
|
||||
@@ -10680,6 +10717,7 @@ Renderer.recipe = class {
|
||||
"tablespoon",
|
||||
"teaspoon",
|
||||
"wedge",
|
||||
"fist",
|
||||
];
|
||||
static _UNITS_SINGLE_TO_PLURAL_ES = [
|
||||
"dash",
|
||||
|
||||
@@ -113,9 +113,11 @@ export class BrewUtil2Base {
|
||||
|
||||
isReloadRequired () { return this._isDirty; }
|
||||
|
||||
doLocationReload () {
|
||||
if (typeof Hist !== "undefined") Hist.doPreLocationReload();
|
||||
else window.location.hash = "";
|
||||
doLocationReload ({isRetainHash = false} = {}) {
|
||||
if (!isRetainHash) {
|
||||
if (typeof Hist !== "undefined") Hist.doPreLocationReload();
|
||||
else window.location.hash = "";
|
||||
}
|
||||
|
||||
location.reload();
|
||||
}
|
||||
@@ -513,6 +515,8 @@ export class BrewUtil2Base {
|
||||
pLoadPropIndex (urlRoot) { throw new Error("Unimplemented!"); }
|
||||
/** @abstract */
|
||||
pLoadMetaIndex (urlRoot) { throw new Error("Unimplemented!"); }
|
||||
/** @abstract */
|
||||
pLoadAdventureBookIdsIndex (urlRoot) { throw new Error("Unimplemented!"); }
|
||||
|
||||
async pGetCombinedIndexes () {
|
||||
const urlRoot = await this.pGetCustomUrl();
|
||||
|
||||
@@ -89,6 +89,8 @@ export class BrewUtil2_ extends BrewUtil2Base {
|
||||
|
||||
pLoadMetaIndex (urlRoot) { return DataUtil.brew.pLoadMetaIndex(urlRoot); }
|
||||
|
||||
pLoadAdventureBookIdsIndex (urlRoot) { return DataUtil.brew.pLoadAdventureBookIdsIndex(urlRoot); }
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
// region Editable
|
||||
|
||||
@@ -41,6 +41,8 @@ export class PrereleaseUtil_ extends BrewUtil2Base {
|
||||
|
||||
pLoadMetaIndex (urlRoot) { return DataUtil.prerelease.pLoadMetaIndex(urlRoot); }
|
||||
|
||||
pLoadAdventureBookIdsIndex (urlRoot) { return DataUtil.prerelease.pLoadAdventureBookIdsIndex(urlRoot); }
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
// region Editable
|
||||
|
||||
@@ -1987,7 +1987,7 @@ class DataLoader {
|
||||
}
|
||||
|
||||
static async pCacheAndGetHash (page, hash, opts) {
|
||||
const {source} = UrlUtil.autoDecodeHash(hash, {page});
|
||||
const {source} = await UrlUtil.pAutoDecodeHash(hash, {page});
|
||||
if (!source) {
|
||||
if (opts.isRequired) throw new Error(`Could not find entity for page "${page}" with hash "${hash}"`);
|
||||
return null;
|
||||
|
||||
@@ -1907,6 +1907,8 @@ PropOrder._VARIANTRULE = [
|
||||
|
||||
"type",
|
||||
"entries",
|
||||
|
||||
"foundryImg",
|
||||
];
|
||||
PropOrder._RACE_SUBRACE = [
|
||||
"page",
|
||||
|
||||
@@ -965,7 +965,7 @@ class ListUiUtil {
|
||||
let elePreviewWrp;
|
||||
if (item.ele.children.length === 1) {
|
||||
elePreviewWrp = e_({
|
||||
ag: "div",
|
||||
tag: "div",
|
||||
clazz: "ve-hidden ve-flex",
|
||||
children: [
|
||||
e_({tag: "div", clazz: "ve-col-0-5"}),
|
||||
|
||||
71
js/utils.js
71
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.209.1"/* 5ETOOLS_VERSION__CLOSE */;
|
||||
globalThis.VERSION_NUMBER = /* 5ETOOLS_VERSION__OPEN */"1.209.2"/* 5ETOOLS_VERSION__CLOSE */;
|
||||
globalThis.DEPLOYED_IMG_ROOT = undefined;
|
||||
// for the roll20 script to set
|
||||
globalThis.IS_VTT = false;
|
||||
@@ -2812,7 +2812,24 @@ globalThis.UrlUtil = {
|
||||
return hash.split(HASH_LIST_SEP).map(it => decodeURIComponent(it));
|
||||
},
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @param hash
|
||||
* @param {?string} page
|
||||
*/
|
||||
async pAutoDecodeHash (hash, {page = null} = {}) {
|
||||
page ||= UrlUtil.getCurrentPage();
|
||||
|
||||
if ([UrlUtil.PG_ADVENTURE, UrlUtil.PG_BOOK].includes(page)) return UrlUtil._pAutoDecodeHashAdventureBookHash(hash, {page});
|
||||
return UrlUtil.autoDecodeHash(hash, {page});
|
||||
},
|
||||
|
||||
// TODO(Future) expand
|
||||
/**
|
||||
* @param hash
|
||||
* @param {?string} page
|
||||
*/
|
||||
autoDecodeHash (hash, {page = null} = {}) {
|
||||
page ||= UrlUtil.getCurrentPage();
|
||||
const parts = UrlUtil.decodeHash(hash.toLowerCase().trim());
|
||||
@@ -2822,10 +2839,57 @@ globalThis.UrlUtil = {
|
||||
return {name, pantheon, source};
|
||||
}
|
||||
|
||||
// TODO(Future) this is broken for docs where the id != the source
|
||||
// consider indexing
|
||||
// + homebrew
|
||||
if (page === UrlUtil.PG_ADVENTURE || page === UrlUtil.PG_BOOK) {
|
||||
const [source] = parts;
|
||||
return {source};
|
||||
}
|
||||
|
||||
const [name, source] = parts;
|
||||
return {name, source};
|
||||
},
|
||||
|
||||
/**
|
||||
* @param hash
|
||||
* @param {?string} page
|
||||
*/
|
||||
async _pAutoDecodeHashAdventureBookHash (hash, {page = null} = {}) {
|
||||
page ||= UrlUtil.getCurrentPage();
|
||||
const parts = UrlUtil.decodeHash(hash.toLowerCase().trim());
|
||||
|
||||
if (![UrlUtil.PG_ADVENTURE, UrlUtil.PG_BOOK].includes(page)) throw new Error(`Unhandled page "${page}"!`);
|
||||
|
||||
const [id] = parts;
|
||||
|
||||
for (const {prop, contentsUrl} of [
|
||||
{
|
||||
prop: "adventure",
|
||||
contentsUrl: `${Renderer.get().baseUrl}data/adventures.json`,
|
||||
},
|
||||
{
|
||||
prop: "book",
|
||||
contentsUrl: `${Renderer.get().baseUrl}data/books.json`,
|
||||
},
|
||||
]) {
|
||||
const contents = await DataUtil.loadJSON(contentsUrl);
|
||||
|
||||
const ent = contents[prop].find(it => it.id.toLowerCase() === id);
|
||||
if (ent) return {name: ent.name, source: ent.source, id: ent.id};
|
||||
}
|
||||
|
||||
for (const brewUtil of [PrereleaseUtil, BrewUtil2]) {
|
||||
const urlRoot = await brewUtil.pGetCustomUrl();
|
||||
const idsIndex = await brewUtil.pLoadAdventureBookIdsIndex(urlRoot);
|
||||
if (idsIndex[id]) return idsIndex[id];
|
||||
}
|
||||
|
||||
return {};
|
||||
},
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
getSluggedHash (hash) {
|
||||
return Parser.stringToSlug(decodeURIComponent(hash)).replace(/_/g, "-");
|
||||
},
|
||||
@@ -3758,6 +3822,11 @@ class _DataUtilBrewHelper {
|
||||
return DataUtil.loadJSON(`${urlRoot}_generated/index-sources.json`);
|
||||
}
|
||||
|
||||
async pLoadAdventureBookIdsIndex (urlRoot) {
|
||||
urlRoot = this._getCleanUrlRoot(urlRoot);
|
||||
return DataUtil.loadJSON(`${urlRoot}_generated/index-adventure-book-ids.json`);
|
||||
}
|
||||
|
||||
getFileUrl (path, urlRoot) {
|
||||
urlRoot = this._getCleanUrlRoot(urlRoot);
|
||||
return `${urlRoot}${path}`;
|
||||
|
||||
Reference in New Issue
Block a user