"use strict"; class PageFilterOptionalFeatures extends PageFilterBase { // region static static _filterFeatureTypeSort (a, b) { return SortUtil.ascSort(Parser.optFeatureTypeToFull(a.item), Parser.optFeatureTypeToFull(b.item)); } static sortOptionalFeatures (itemA, itemB, options) { if (options.sortBy === "level") { const aValue = Number(itemA.values.level) || 0; const bValue = Number(itemB.values.level) || 0; return SortUtil.ascSort(aValue, bValue) || SortUtil.listSort(itemA, itemB, options); } return SortUtil.listSort(itemA, itemB, options); } static getLevelFilterItem (prereq) { const lvlMeta = prereq.level; if (typeof lvlMeta === "number") { return new FilterItem({ item: `Level ${lvlMeta}`, nest: `(No Class)`, }); } const className = lvlMeta.class ? lvlMeta.class.name : `(No Class)`; return new FilterItem({ item: `${lvlMeta.class ? className : ""}${lvlMeta.subclass ? ` (${lvlMeta.subclass.name})` : ""} Level ${lvlMeta.level}`, nest: className, }); } // endregion constructor () { super(); this._typeFilter = new Filter({ header: "Feature Type", items: [], displayFn: Parser.optFeatureTypeToFull, itemSortFn: PageFilterOptionalFeatures._filterFeatureTypeSort, }); this._pactFilter = new Filter({ header: "Pact Boon", items: [], displayFn: Parser.prereqPactToFull, }); this._patronFilter = new Filter({ header: "Otherworldly Patron", items: [], displayFn: Parser.prereqPatronToShort, }); this._spellFilter = new Filter({ header: "Spell", items: [], displayFn: StrUtil.toTitleCase, }); this._featureFilter = new Filter({ header: "Feature", displayFn: StrUtil.toTitleCase, }); this._levelFilter = new Filter({ header: "Level", itemSortFn: SortUtil.ascSortNumericalSuffix, nests: [], }); this._prerequisiteFilter = new MultiFilter({ header: "Prerequisite", filters: [ this._pactFilter, this._patronFilter, this._spellFilter, this._levelFilter, this._featureFilter, ], }); this._miscFilter = new Filter({header: "Miscellaneous", items: ["Has Info", "Has Images", "SRD", "Legacy", "Grants Additional Spells"], isMiscFilter: true}); } static mutateForFilters (ent) { ent._fSources = SourceFilter.getCompleteFilterSources(ent); // (Convert legacy string format to array) ent.featureType = ent.featureType && ent.featureType instanceof Array ? ent.featureType : ent.featureType ? [ent.featureType] : ["OTH"]; if (ent.prerequisite) { ent._sPrereq = true; ent._fPrereqPact = ent.prerequisite.filter(it => it.pact).map(it => it.pact); ent._fPrereqPatron = ent.prerequisite.filter(it => it.patron).map(it => it.patron); ent._fprereqSpell = ent.prerequisite .filter(it => it.spell) .map(prereq => { return (prereq.spell || []) .map(strOrObj => { if (typeof strOrObj === "string") return strOrObj.split("#")[0].split("|")[0]; // TODO(Future) improve if required -- refactor this + `PageFilterSpells` display fns to e.g. render const ptChoose = strOrObj.choose .split("|") .sort(SortUtil.ascSortLower) .map(pt => { const [filter, values] = pt.split("="); switch (filter.toLowerCase()) { case "level": return values.split(";").map(v => Parser.spLevelToFullLevelText(Number(v), {isPluralCantrips: false})).join("/"); case "class": return values.split(";").map(v => v.toTitleCase()).join("/"); default: return pt; } }) .join(" "); return `Any ${ptChoose}`; }); }); ent._fprereqFeature = ent.prerequisite.filter(it => it.feature).map(it => it.feature); ent._fPrereqLevel = ent.prerequisite.filter(it => it.level).map(PageFilterOptionalFeatures.getLevelFilterItem.bind(PageFilterOptionalFeatures)); } ent._dFeatureType = ent.featureType.map(ft => Parser.optFeatureTypeToFull(ft)); ent._lFeatureType = ent.featureType.join(", "); ent.featureType.sort((a, b) => SortUtil.ascSortLower(Parser.optFeatureTypeToFull(a), Parser.optFeatureTypeToFull(b))); ent._fMisc = ent.srd ? ["SRD"] : []; if (SourceUtil.isLegacySourceWotc(ent.source)) ent._fMisc.push("Legacy"); if (ent.additionalSpells) ent._fMisc.push("Grants Additional Spells"); if (this._hasFluff(ent)) ent._fMisc.push("Has Info"); if (this._hasFluffImages(ent)) ent._fMisc.push("Has Images"); } addToFilters (it, isExcluded) { if (isExcluded) return; this._sourceFilter.addItem(it._fSources); this._typeFilter.addItem(it.featureType); this._pactFilter.addItem(it._fPrereqPact); this._patronFilter.addItem(it._fPrereqPatron); this._spellFilter.addItem(it._fprereqSpell); this._featureFilter.addItem(it._fprereqFeature); (it._fPrereqLevel || []).forEach(it => { this._levelFilter.addNest(it.nest, {isHidden: true}); this._levelFilter.addItem(it); }); } async _pPopulateBoxOptions (opts) { opts.filters = [ this._sourceFilter, this._typeFilter, this._prerequisiteFilter, this._miscFilter, ]; } toDisplay (values, it) { return this._filterBox.toDisplay( values, it._fSources, it.featureType, [ it._fPrereqPact, it._fPrereqPatron, it._fprereqSpell, it._fPrereqLevel, it._fprereqFeature, ], it._fMisc, ); } } globalThis.PageFilterOptionalFeatures = PageFilterOptionalFeatures; class ModalFilterOptionalFeatures extends ModalFilterBase { /** * @param opts * @param opts.namespace * @param [opts.isRadio] * @param [opts.allData] */ constructor (opts) { opts = opts || {}; super({ ...opts, modalTitle: `Optional Feature${opts.isRadio ? "" : "s"}`, pageFilter: new PageFilterOptionalFeatures(), }); } _$getColumnHeaders () { const btnMeta = [ {sort: "name", text: "Name", width: "3"}, {sort: "type", text: "Type", width: "2"}, {sort: "prerequisite", text: "Prerequisite", width: "4"}, {sort: "level", text: "Level", width: "1"}, {sort: "source", text: "Source", width: "1"}, ]; return ModalFilterBase._$getFilterColumnHeaders(btnMeta); } async _pLoadAllData () { return [ ...(await DataUtil.loadJSON(`${Renderer.get().baseUrl}data/optionalfeatures.json`)).optionalfeature, ...((await PrereleaseUtil.pGetBrewProcessed()).optionalfeature || []), ...((await BrewUtil2.pGetBrewProcessed()).optionalfeature || []), ]; } _getListItem (pageFilter, optfeat, ftI) { const eleRow = document.createElement("div"); eleRow.className = "px-0 w-100 ve-flex-col no-shrink"; const hash = UrlUtil.URL_TO_HASH_BUILDER[UrlUtil.PG_OPT_FEATURES](optfeat); const source = Parser.sourceJsonToAbv(optfeat.source); const prerequisite = Renderer.utils.prerequisite.getHtml(optfeat.prerequisite, {isListMode: true, blocklistKeys: new Set(["level"])}); const level = Renderer.optionalfeature.getListPrerequisiteLevelText(optfeat.prerequisite); eleRow.innerHTML = `