Files
5etools-mirror-2.github.io/js/multisource.js
TheGiddyLimit e3bf75f42a v1.198.3
2024-01-06 14:47:30 +00:00

178 lines
5.9 KiB
JavaScript

"use strict";
/** @abstract */
class ListPageMultiSource extends ListPage {
constructor ({propLoader, ...rest}) {
super({
...rest,
isLoadDataAfterFilterInit: true,
isBindHashHandlerUnknown: true,
});
this._propLoader = propLoader;
this._loadedSources = {};
this._lastFilterValues = null;
}
_onFilterChangeMulti (multiList, filterValues) {
FilterBox.selectFirstVisible(multiList);
if (!this._lastFilterValues) {
this._lastFilterValues = filterValues;
return;
}
if (!filterValues.Source._isActive && this._lastFilterValues.Source._isActive) {
this._lastFilterValues = filterValues;
this._pForceLoadDefaultSources();
}
}
handleFilterChange () {
const f = this._pageFilter.filterBox.getValues();
this._list.filter(li => this._pageFilter.toDisplay(f, this._dataList[li.ix]));
this._onFilterChangeMulti(this._dataList, f);
}
async _pForceLoadDefaultSources () {
const defaultSources = Object.keys(this._loadedSources)
.filter(s => PageFilter.defaultSourceSelFn(s));
await Promise.all(defaultSources.map(src => this._pLoadSource(src, "yes")));
}
async pDoLoadExportedSublistSources (exportedSublist) {
if (!exportedSublist?.sources?.length) return;
const sourcesJson = exportedSublist.sources
.map(src => Parser.sourceJsonToJson(src));
await sourcesJson
.filter(src => this._isLoadableSiteSource({src}))
.pMap(src => this._pLoadSource(src, "yes"));
// region Note that we can't e.g. load the sources in the background, because the list won't update, and therefore
// the sublist can't find the matching list elements.
// TODO(Future) have the notification include a button which, when clicked, will attempt to:
// - load the brew from the repo
// - cache the to-be-loaded sublist in local storage
// - reload the page
// - load the cached sublist
const sourcesUnknown = sourcesJson
.filter(src => !SourceUtil.isSiteSource(src) && !PrereleaseUtil.hasSourceJson(src) && !BrewUtil2.hasSourceJson(src));
if (!sourcesUnknown.length) return;
JqueryUtil.doToast({
content: `Could not load content from the following source${sourcesUnknown.length === 1 ? "" : "s"}: ${sourcesUnknown.map(it => `"${it}"`).join(", ")}. You may need to load ${sourcesUnknown.length === 1 ? "it" : "them"} as homebrew first.`,
type: "danger",
isAutoHide: false,
});
// endregion
}
_isLoadableSiteSource ({src}) {
if (!SourceUtil.isSiteSource(src)) return false;
return !!(this._loadedSources[src] || this._loadedSources[Object.keys(this._loadedSources).find(k => k.toLowerCase() === src)]);
}
async _pLoadSource (src, nextFilterVal) {
// We only act when the user changes the filter to "yes", i.e. "load/view the source"
if (nextFilterVal !== "yes") return;
const toLoad = this._loadedSources[src] || this._loadedSources[Object.keys(this._loadedSources).find(k => k.toLowerCase() === src)];
if (toLoad.loaded) return;
const data = await DataUtil[this._propLoader].pLoadSingleSource(src);
this._addData(data);
toLoad.loaded = true;
}
async _pOnLoad_pGetData () {
const siteSourcesAvail = new Set(
Object.keys(await DataUtil[this._propLoader].pLoadIndex())
.filter(source => !ExcludeUtil.isExcluded("*", "*", source, {isNoCount: true})),
);
// track loaded sources
siteSourcesAvail
.forEach(src => this._loadedSources[src] = {source: src, loaded: false});
// collect a list of sources to load
const defaultSel = [...siteSourcesAvail].filter(s => PageFilter.defaultSourceSelFn(s));
const userSel = [
// Selected in filter
...await this._filterBox.pGetStoredActiveSources() || defaultSel,
// From entities in sublist
...await this._sublistManager.pGetSelectedSources() || [],
// From current link
this._pOnLoad_getLinkHashSource({siteSourcesAvail}),
]
.filter(Boolean)
.unique();
const allSources = [];
// add any sources from the user's saved filters, provided they have URLs and haven't already been added
if (userSel) {
userSel
.filter(src => siteSourcesAvail.has(src) && !allSources.includes(src))
.forEach(src => allSources.push(src));
}
// if there's no saved filters, load the defaults
if (allSources.length === 0) {
// remove any sources that don't have URLs
defaultSel
.filter(src => siteSourcesAvail.has(src))
.forEach(src => allSources.push(src));
}
// add source from the current hash, if there is one
if (window.location.hash.length) {
const [link] = Hist.getHashParts();
const src = link.split(HASH_LIST_SEP)[1];
const hashSrcs = {};
siteSourcesAvail.forEach(src => hashSrcs[UrlUtil.encodeForHash(src)] = src);
const mapped = hashSrcs[src];
if (mapped && !allSources.includes(mapped)) {
allSources.push(mapped);
}
}
// make a list of src : url objects
// load the sources
let toAdd = {};
if (allSources.length > 0) {
const dataStack = (await Promise.all(allSources.map(async src => {
const data = await DataUtil[this._propLoader].pLoadSingleSource(src);
this._loadedSources[src].loaded = true;
return data;
}))).flat();
dataStack.forEach(d => {
Object.entries(d)
.forEach(([prop, arr]) => {
if (!(arr instanceof Array)) return;
toAdd[prop] = (toAdd[prop] || []).concat(arr);
});
});
}
Object.keys(this._loadedSources)
.map(src => new SourceFilterItem({item: src, pFnChange: this._pLoadSource.bind(this)}))
.forEach(fi => this._pageFilter.sourceFilter.addItem(fi));
const prerelease = await (this._prereleaseDataSource ? this._prereleaseDataSource() : PrereleaseUtil.pGetBrewProcessed());
const homebrew = await (this._brewDataSource ? this._brewDataSource() : BrewUtil2.pGetBrewProcessed());
return BrewUtil2.getMergedData(PrereleaseUtil.getMergedData(toAdd, prerelease), homebrew);
}
_pOnLoad_getLinkHashSource ({siteSourcesAvail}) {
const hashSourceRaw = Hist.getHashSource();
return hashSourceRaw
? [...siteSourcesAvail].find(it => it.toLowerCase() === hashSourceRaw.toLowerCase())
: null;
}
}