mirror of
https://github.com/Kornstalx/5etools-mirror-2.github.io.git
synced 2025-10-28 20:45:35 -05:00
467 lines
15 KiB
JavaScript
467 lines
15 KiB
JavaScript
"use strict";
|
||
|
||
class ItemsSublistManager extends SublistManager {
|
||
constructor () {
|
||
super({
|
||
sublistListOptions: {
|
||
fnSort: PageFilterItems.sortItems,
|
||
},
|
||
isSublistItemsCountable: true,
|
||
});
|
||
|
||
this._sublistCurrencyConversion = null;
|
||
this._sublistCurrencyDisplayMode = null;
|
||
|
||
this._$totalWeight = null;
|
||
this._$totalValue = null;
|
||
this._$totalItems = null;
|
||
}
|
||
|
||
async pCreateSublist () {
|
||
[this._sublistCurrencyConversion, this._sublistCurrencyDisplayMode] = await Promise.all([
|
||
StorageUtil.pGetForPage("sublistCurrencyConversion"),
|
||
StorageUtil.pGetForPage("sublistCurrencyDisplayMode"),
|
||
]);
|
||
|
||
return super.pCreateSublist();
|
||
}
|
||
|
||
static get _ROW_TEMPLATE () {
|
||
return [
|
||
new SublistCellTemplate({
|
||
name: "Name",
|
||
css: "bold col-6 pl-0",
|
||
colStyle: "",
|
||
}),
|
||
new SublistCellTemplate({
|
||
name: "Weight",
|
||
css: "ve-text-center col-2",
|
||
colStyle: "text-center",
|
||
}),
|
||
new SublistCellTemplate({
|
||
name: "Cost",
|
||
css: "ve-text-center col-2",
|
||
colStyle: "text-center",
|
||
}),
|
||
new SublistCellTemplate({
|
||
name: "Number",
|
||
css: "ve-text-center col-2 pr-0",
|
||
colStyle: "text-center",
|
||
}),
|
||
];
|
||
}
|
||
|
||
pGetSublistItem (item, hash, {count = 1} = {}) {
|
||
const cellsText = [
|
||
item.name,
|
||
Parser.itemWeightToFull(item, true) || "\u2014",
|
||
item.value || item.valueMult ? Parser.itemValueToFullMultiCurrency(item, {isShortForm: true}).replace(/ +/g, "\u00A0") : "\u2014",
|
||
];
|
||
|
||
const $dispCount = $(`<span class="ve-text-center col-2 pr-0">${count}</span>`);
|
||
const $ele = $$`<div class="lst__row lst__row--sublist ve-flex-col">
|
||
<a href="#${hash}" class="lst--border lst__row-inner">
|
||
${this.constructor._getRowCellsHtml({values: cellsText, templates: this.constructor._ROW_TEMPLATE.slice(0, 3)})}
|
||
${$dispCount}
|
||
</a>
|
||
</div>`
|
||
.contextmenu(evt => this._handleSublistItemContextMenu(evt, listItem))
|
||
.click(evt => this._listSub.doSelect(listItem, evt));
|
||
|
||
const listItem = new ListItem(
|
||
hash,
|
||
$ele,
|
||
item.name,
|
||
{
|
||
hash,
|
||
source: Parser.sourceJsonToAbv(item.source),
|
||
weight: Parser.weightValueToNumber(item.weight),
|
||
cost: item.value || 0,
|
||
},
|
||
{
|
||
count,
|
||
$elesCount: [$dispCount],
|
||
entity: item,
|
||
mdRow: [...cellsText, ({listItem}) => listItem.data.count],
|
||
},
|
||
);
|
||
return listItem;
|
||
}
|
||
|
||
_onSublistChange () {
|
||
this._$totalWeight = this._$totalWeight || $(`#totalweight`);
|
||
this._$totalValue = this._$totalValue || $(`#totalvalue`);
|
||
this._$totalItems = this._$totalItems || $(`#totalitems`);
|
||
|
||
let weight = 0;
|
||
let value = 0;
|
||
let cntItems = 0;
|
||
|
||
const availConversions = new Set();
|
||
this._listSub.items.forEach(it => {
|
||
const {data: {entity: item}} = it;
|
||
if (item.currencyConversion) availConversions.add(item.currencyConversion);
|
||
const count = it.data.count;
|
||
cntItems += it.data.count;
|
||
if (item.weight) weight += Number(item.weight) * count;
|
||
if (item.value) value += item.value * count;
|
||
});
|
||
|
||
this._$totalWeight.text(Parser.itemWeightToFull({weight}, true));
|
||
this._$totalItems.text(cntItems);
|
||
|
||
if (availConversions.size) {
|
||
this._$totalValue
|
||
.text(Parser.itemValueToFullMultiCurrency({value, currencyConversion: this._sublistCurrencyConversion}))
|
||
.off("click")
|
||
.click(async () => {
|
||
const values = ["(Default)", ...[...availConversions].sort(SortUtil.ascSortLower)];
|
||
const defaultSel = values.indexOf(this._sublistCurrencyConversion);
|
||
const userSel = await InputUiUtil.pGetUserEnum({
|
||
values,
|
||
isResolveItem: true,
|
||
default: ~defaultSel ? defaultSel : 0,
|
||
title: "Select Currency Conversion Table",
|
||
fnDisplay: it => it === null ? values[0] : it,
|
||
});
|
||
if (userSel == null) return;
|
||
this._sublistCurrencyConversion = userSel === values[0] ? null : userSel;
|
||
await StorageUtil.pSetForPage("sublistCurrencyConversion", this._sublistCurrencyConversion);
|
||
this._onSublistChange();
|
||
});
|
||
return;
|
||
}
|
||
|
||
this._$totalValue
|
||
.text(this._getTotalValueText({value}) || "\u2014")
|
||
.off("click")
|
||
.click(async () => {
|
||
const defaultSel = this.constructor._TOTAL_VALUE_MODES.indexOf(this._sublistCurrencyDisplayMode);
|
||
const userSel = await InputUiUtil.pGetUserEnum({
|
||
values: this.constructor._TOTAL_VALUE_MODES,
|
||
isResolveItem: true,
|
||
default: ~defaultSel ? defaultSel : 0,
|
||
title: "Select Display Mode",
|
||
fnDisplay: it => it === null ? this.constructor._TOTAL_VALUE_MODES[0] : it,
|
||
});
|
||
if (userSel == null) return;
|
||
this._sublistCurrencyDisplayMode = userSel === this.constructor._TOTAL_VALUE_MODES[0] ? null : userSel;
|
||
await StorageUtil.pSetForPage("sublistCurrencyDisplayMode", this._sublistCurrencyDisplayMode);
|
||
this._onSublistChange();
|
||
});
|
||
}
|
||
|
||
static _TOTAL_VALUE_MODE_EXACT_COINAGE = "Exact Coinage";
|
||
static _TOTAL_VALUE_MODE_LOWEST_COMMON = "Lowest Common Currency";
|
||
static _TOTAL_VALUE_MODE_GOLD = "Gold";
|
||
static _TOTAL_VALUE_MODES = [
|
||
this._TOTAL_VALUE_MODE_EXACT_COINAGE,
|
||
this._TOTAL_VALUE_MODE_LOWEST_COMMON,
|
||
this._TOTAL_VALUE_MODE_GOLD,
|
||
];
|
||
_getTotalValueText ({value}) {
|
||
switch (this._sublistCurrencyDisplayMode) {
|
||
case this.constructor._TOTAL_VALUE_MODE_LOWEST_COMMON: return Parser.itemValueToFull({value});
|
||
|
||
case this.constructor._TOTAL_VALUE_MODE_GOLD: {
|
||
return value ? `${Number((Parser.DEFAULT_CURRENCY_CONVERSION_TABLE.find(it => it.coin === "gp").mult * value).toFixed(2))} gp` : "";
|
||
}
|
||
|
||
default: {
|
||
const CURRENCIES = ["gp", "sp", "cp"];
|
||
const coins = {cp: value};
|
||
CurrencyUtil.doSimplifyCoins(coins);
|
||
return CURRENCIES.filter(it => coins[it]).map(it => `${coins[it].toLocaleString(undefined, {maximumFractionDigits: 5})} ${it}`).join(", ");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
class ItemsPage extends ListPage {
|
||
constructor () {
|
||
const pFnGetFluff = Renderer.item.pGetFluff.bind(Renderer.item);
|
||
|
||
super({
|
||
dataSource: DataUtil.item.loadJSON.bind(DataUtil.item),
|
||
prereleaseDataSource: DataUtil.item.loadPrerelease.bind(DataUtil.item),
|
||
brewDataSource: DataUtil.item.loadBrew.bind(DataUtil.item),
|
||
|
||
pFnGetFluff,
|
||
|
||
pageFilter: new PageFilterItems(),
|
||
|
||
dataProps: ["item"],
|
||
|
||
bookViewOptions: {
|
||
namePlural: "items",
|
||
pageTitle: "Items Book View",
|
||
propMarkdown: "item",
|
||
},
|
||
|
||
tableViewOptions: {
|
||
title: "Items",
|
||
colTransforms: {
|
||
name: UtilsTableview.COL_TRANSFORM_NAME,
|
||
source: UtilsTableview.COL_TRANSFORM_SOURCE,
|
||
rarity: {name: "Rarity"},
|
||
_type: {name: "Type", transform: it => [it._typeHtml || "", it._subTypeHtml || ""].filter(Boolean).join(", ")},
|
||
_attunement: {name: "Attunement", transform: it => it._attunement ? it._attunement.slice(1, it._attunement.length - 1) : ""},
|
||
_properties: {name: "Properties", transform: it => Renderer.item.getDamageAndPropertiesText(it).filter(Boolean).join(", ")},
|
||
_weight: {name: "Weight", transform: it => Parser.itemWeightToFull(it)},
|
||
_value: {name: "Value", transform: it => Parser.itemValueToFullMultiCurrency(it)},
|
||
_entries: {name: "Text", transform: (it) => Renderer.item.getRenderedEntries(it, {isCompact: true}), flex: 3},
|
||
},
|
||
},
|
||
|
||
isMarkdownPopout: true,
|
||
propEntryData: "item",
|
||
|
||
listSyntax: new ListSyntaxItems({fnGetDataList: () => this._dataList, pFnGetFluff}),
|
||
});
|
||
|
||
this._mundaneList = null;
|
||
this._magicList = null;
|
||
}
|
||
|
||
get _bindOtherButtonsOptions () {
|
||
return {
|
||
other: [
|
||
this._bindOtherButtonsOptions_openAsSinglePage({slugPage: "items", fnGetHash: () => Hist.getHashParts()[0]}),
|
||
].filter(Boolean),
|
||
};
|
||
}
|
||
|
||
get primaryLists () { return [this._mundaneList, this._magicList]; }
|
||
|
||
getListItem (item, itI, isExcluded) {
|
||
const hash = UrlUtil.autoEncodeHash(item);
|
||
|
||
if (Renderer.item.isExcluded(item, {hash})) return null;
|
||
if (item.noDisplay) return null;
|
||
Renderer.item.enhanceItem(item);
|
||
|
||
this._pageFilter.mutateAndAddToFilters(item, isExcluded);
|
||
|
||
const source = Parser.sourceJsonToAbv(item.source);
|
||
const type = item._typeListText.join(", ").toTitleCase();
|
||
|
||
if (item._fIsMundane) {
|
||
const eleLi = e_({
|
||
tag: "div",
|
||
clazz: `lst__row ve-flex-col ${isExcluded ? "lst__row--blocklisted" : ""}`,
|
||
click: (evt) => this._mundaneList.doSelect(listItem, evt),
|
||
contextmenu: (evt) => this._openContextMenu(evt, this._mundaneList, listItem),
|
||
children: [
|
||
e_({
|
||
tag: "a",
|
||
href: `#${hash}`,
|
||
clazz: "lst--border lst__row-inner",
|
||
children: [
|
||
e_({tag: "span", clazz: `col-3-5 pl-0 bold`, text: item.name}),
|
||
e_({tag: "span", clazz: `col-4-5`, text: type}),
|
||
e_({tag: "span", clazz: `col-1-5 ve-text-center`, text: `${item.value || item.valueMult ? Parser.itemValueToFullMultiCurrency(item, {isShortForm: true}).replace(/ +/g, "\u00A0") : "\u2014"}`}),
|
||
e_({tag: "span", clazz: `col-1-5 ve-text-center`, text: Parser.itemWeightToFull(item, true) || "\u2014"}),
|
||
e_({
|
||
tag: "span",
|
||
clazz: `col-1 ve-text-center ${Parser.sourceJsonToColor(item.source)} pr-0`,
|
||
style: Parser.sourceJsonToStylePart(item.source),
|
||
title: `${Parser.sourceJsonToFull(item.source)}${Renderer.utils.getSourceSubText(item)}`,
|
||
text: source,
|
||
}),
|
||
],
|
||
}),
|
||
],
|
||
});
|
||
|
||
const listItem = new ListItem(
|
||
itI,
|
||
eleLi,
|
||
item.name,
|
||
{
|
||
hash,
|
||
source,
|
||
type,
|
||
cost: item.value || 0,
|
||
weight: Parser.weightValueToNumber(item.weight),
|
||
},
|
||
{
|
||
isExcluded,
|
||
},
|
||
);
|
||
|
||
return {mundane: listItem};
|
||
} else {
|
||
const eleLi = e_({
|
||
tag: "div",
|
||
clazz: `lst__row ve-flex-col ${isExcluded ? "lst__row--blocklisted" : ""}`,
|
||
click: (evt) => this._magicList.doSelect(listItem, evt),
|
||
contextmenu: (evt) => this._openContextMenu(evt, this._magicList, listItem),
|
||
children: [
|
||
e_({
|
||
tag: "a",
|
||
href: `#${hash}`,
|
||
clazz: "lst--border lst__row-inner",
|
||
children: [
|
||
e_({tag: "span", clazz: `col-3-5 pl-0 bold`, text: item.name}),
|
||
e_({tag: "span", clazz: `col-4`, text: type}),
|
||
e_({tag: "span", clazz: `col-1-5 ve-text-center`, text: Parser.itemWeightToFull(item, true) || "\u2014"}),
|
||
e_({tag: "span", clazz: `col-0-6 ve-text-center`, text: item._attunementCategory !== VeCt.STR_NO_ATTUNEMENT ? "×" : ""}),
|
||
e_({tag: "span", clazz: `col-1-4 ve-text-center`, text: (item.rarity || "").toTitleCase()}),
|
||
e_({
|
||
tag: "span",
|
||
clazz: `col-1 ve-text-center ${Parser.sourceJsonToColor(item.source)} pr-0`,
|
||
style: Parser.sourceJsonToStylePart(item.source),
|
||
title: `${Parser.sourceJsonToFull(item.source)}${Renderer.utils.getSourceSubText(item)}`,
|
||
text: source,
|
||
}),
|
||
],
|
||
}),
|
||
],
|
||
});
|
||
|
||
const listItem = new ListItem(
|
||
itI,
|
||
eleLi,
|
||
item.name,
|
||
{
|
||
source,
|
||
hash,
|
||
type,
|
||
rarity: item.rarity,
|
||
attunement: item._attunementCategory !== VeCt.STR_NO_ATTUNEMENT,
|
||
weight: Parser.weightValueToNumber(item.weight),
|
||
},
|
||
);
|
||
|
||
return {magic: listItem};
|
||
}
|
||
}
|
||
|
||
handleFilterChange () {
|
||
const f = this._pageFilter.filterBox.getValues();
|
||
const listFilter = li => this._pageFilter.toDisplay(f, this._dataList[li.ix]);
|
||
this._mundaneList.filter(listFilter);
|
||
this._magicList.filter(listFilter);
|
||
FilterBox.selectFirstVisible(this._dataList);
|
||
}
|
||
|
||
_tabTitleStats = "Item";
|
||
|
||
_renderStats_doBuildStatsTab ({ent}) {
|
||
this._$pgContent.empty().append(RenderItems.$getRenderedItem(ent));
|
||
}
|
||
|
||
async _pOnLoad_pInitPrimaryLists () {
|
||
const $iptSearch = $("#lst__search");
|
||
const $btnReset = $("#reset");
|
||
const $btnClear = $(`#lst__search-glass`);
|
||
this._mundaneList = this._initList({
|
||
$iptSearch,
|
||
$btnReset,
|
||
$btnClear,
|
||
dispPageTagline: document.getElementById(`page__subtitle`),
|
||
$wrpList: $(`.list.mundane`),
|
||
syntax: this._listSyntax.build(),
|
||
isBindFindHotkey: true,
|
||
optsList: {
|
||
fnSort: PageFilterItems.sortItems,
|
||
},
|
||
});
|
||
this._magicList = this._initList({
|
||
$iptSearch,
|
||
$btnReset,
|
||
$btnClear,
|
||
$wrpList: $(`.list.magic`),
|
||
syntax: this._listSyntax.build(),
|
||
optsList: {
|
||
fnSort: PageFilterItems.sortItems,
|
||
},
|
||
});
|
||
|
||
SortUtil.initBtnSortHandlers($("#filtertools-mundane"), this._mundaneList);
|
||
SortUtil.initBtnSortHandlers($("#filtertools-magic"), this._magicList);
|
||
|
||
this._mundaneList.nextList = this._magicList;
|
||
this._magicList.prevList = this._mundaneList;
|
||
|
||
this._filterBox = await this._pageFilter.pInitFilterBox({
|
||
$iptSearch,
|
||
$wrpFormTop: $(`#filter-search-group`),
|
||
$btnReset,
|
||
});
|
||
}
|
||
|
||
_pOnLoad_initVisibleItemsDisplay () {
|
||
const $elesMundaneAndMagic = $(`.ele-mundane-and-magic`);
|
||
$(`.side-label--mundane`).click(() => {
|
||
const filterValues = this._pageFilter.filterBox.getValues();
|
||
const curValue = MiscUtil.get(filterValues, "Miscellaneous", "Mundane");
|
||
this._pageFilter.filterBox.setFromValues({
|
||
Miscellaneous: {
|
||
...(filterValues?.Miscellaneous || {}),
|
||
Mundane: curValue === 1 ? 0 : 1,
|
||
},
|
||
});
|
||
});
|
||
$(`.side-label--magic`).click(() => {
|
||
const filterValues = this._pageFilter.filterBox.getValues();
|
||
const curValue = MiscUtil.get(filterValues, "Miscellaneous", "Magic");
|
||
this._pageFilter.filterBox.setFromValues({
|
||
Miscellaneous: {
|
||
...(filterValues?.Miscellaneous || {}),
|
||
Magic: curValue === 1 ? 0 : 1,
|
||
},
|
||
});
|
||
});
|
||
const $outVisibleResults = $(`.lst__wrp-search-visible`);
|
||
const $wrpListMundane = $(`.itm__wrp-list--mundane`);
|
||
const $wrpListMagic = $(`.itm__wrp-list--magic`);
|
||
const $elesMundane = $(`.ele-mundane`);
|
||
const $elesMagic = $(`.ele-magic`);
|
||
this._mundaneList.on("updated", () => {
|
||
// Force-show the mundane list if there are no items on display
|
||
if (this._magicList.visibleItems.length) $elesMundane.toggleVe(!!this._mundaneList.visibleItems.length);
|
||
else $elesMundane.showVe();
|
||
$elesMundaneAndMagic.toggleVe(!!(this._mundaneList.visibleItems.length && this._magicList.visibleItems.length));
|
||
|
||
const current = this._mundaneList.visibleItems.length + this._magicList.visibleItems.length;
|
||
const total = this._mundaneList.items.length + this._magicList.items.length;
|
||
$outVisibleResults.html(`${current}/${total}`);
|
||
|
||
// Collapse the mundane section if there are no magic items displayed
|
||
$wrpListMundane.toggleClass(`itm__wrp-list--empty`, this._mundaneList.visibleItems.length === 0);
|
||
});
|
||
this._magicList.on("updated", () => {
|
||
$elesMagic.toggleVe(!!this._magicList.visibleItems.length);
|
||
// Force-show the mundane list if there are no items on display
|
||
if (!this._magicList.visibleItems.length) $elesMundane.showVe();
|
||
else $elesMundane.toggleVe(!!this._mundaneList.visibleItems.length);
|
||
$elesMundaneAndMagic.toggleVe(!!(this._mundaneList.visibleItems.length && this._magicList.visibleItems.length));
|
||
|
||
const current = this._mundaneList.visibleItems.length + this._magicList.visibleItems.length;
|
||
const total = this._mundaneList.items.length + this._magicList.items.length;
|
||
$outVisibleResults.html(`${current}/${total}`);
|
||
|
||
// Collapse the magic section if there are no magic items displayed
|
||
$wrpListMagic.toggleClass(`itm__wrp-list--empty`, this._magicList.visibleItems.length === 0);
|
||
});
|
||
}
|
||
|
||
_addData (data) {
|
||
super._addData(data);
|
||
|
||
// populate table labels
|
||
$(`h3.ele-mundane span.side-label`).text("Mundane");
|
||
$(`h3.ele-magic span.side-label`).text("Magic");
|
||
}
|
||
|
||
_addListItem (listItem) {
|
||
if (listItem.mundane) this._mundaneList.addItem(listItem.mundane);
|
||
if (listItem.magic) this._magicList.addItem(listItem.magic);
|
||
}
|
||
}
|
||
|
||
const itemsPage = new ItemsPage();
|
||
itemsPage.sublistManager = new ItemsSublistManager();
|
||
window.addEventListener("load", () => itemsPage.pOnLoad());
|