diff --git a/src/lang/en.json b/src/lang/en.json index ff64cf3..fcc6e39 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -26,19 +26,6 @@ "ItemsPacksMonsterHunter": "Monster Hunter's Pack", "ItemsPacksPriest": "Priest's Pack", "ItemsPacksScholar": "Scholar's Pack", - "artificer": "Artificer", - "barbarian": "Barbarian", - "bard": "Bard", - "cleric": "Cleric", - "druid": "Druid", - "fighter": "Fighter", - "monk": "Monk", - "paladin": "Paladin", - "ranger": "Ranger", - "rogue": "Rogue", - "sorcerer": "Sorcerer", - "warlock": "Warlock", - "wizard": "Wizard", "general": "General", "overall": "Overall Type", "subfeature": "Subfeature Type", @@ -49,7 +36,7 @@ "dmgDealt": "Damage Dealt", "Tab": { "SpellBrowser": "Spells", - "FeatBrowser": "Feats", + "FeatBrowser": "Features", "ItemBrowser": "Items", "NPCBrowser": "Actors", "Settings": "Settings" diff --git a/src/module/compendium-browser.js b/src/module/compendium-browser.js index 6a5c863..3dc83a5 100644 --- a/src/module/compendium-browser.js +++ b/src/module/compendium-browser.js @@ -7,6 +7,39 @@ const NOT_MIGRATED = "NotMigratedException"; const COMPENDIUM_BROWSER = "compendium-browser"; class CompendiumBrowser extends Application { + constructor(options={}) { + super(options); + + this.provider = new dnd5eProvider(); + + // Reset the filters used in the dialog + this.spellFilters = { + registeredFilterCategorys: {}, + activeFilters: {}, + }; + this.npcFilters = { + registeredFilterCategorys: {}, + activeFilters: {}, + }; + this.featFilters = { + registeredFilterCategorys: {}, + activeFilters: {}, + }; + this.itemFilters = { + registeredFilterCategorys: {}, + activeFilters: {}, + }; + this.changeTabs = null; + } + + async setup() { + await this.provider.getClasses(); + this.addSpellFilters(); + this.addFeatFilters(); + this.addItemFilters(); + this.addNpcFilters(); + } + static get defaultOptions() { return mergeObject(super.defaultOptions, { title: "CMPBrowser.compendiumBrowser", @@ -23,6 +56,10 @@ class CompendiumBrowser extends Application { return game.settings.get(COMPENDIUM_BROWSER, "maxload"); } + get settings() { + return game.settings.get(COMPENDIUM_BROWSER, "settings"); + } + static get extraButtonsGlobal() { return game.settings.get(COMPENDIUM_BROWSER, "extraButtonsGlobal"); } @@ -43,33 +80,6 @@ class CompendiumBrowser extends Application { return game.settings.get(COMPENDIUM_BROWSER, "bannersLocal"); } - async setup() { - // load settings - this.initSettings(); - - // Reset the filters used in the dialog - this.spellFilters = { - registeredFilterCategorys: {}, - activeFilters: {}, - }; - this.npcFilters = { - registeredFilterCategorys: {}, - activeFilters: {}, - }; - this.featFilters = { - registeredFilterCategorys: {}, - activeFilters: {}, - }; - this.itemFilters = { - registeredFilterCategorys: {}, - activeFilters: {}, - }; - this.addSpellFilters(); - this.addFeatFilters(); - this.addItemFilters(); - this.addNpcFilters(); - } - /** @override */ _onChangeTab(event, tabs, active) { super._onChangeTab(event, tabs, active); @@ -95,6 +105,15 @@ class CompendiumBrowser extends Application { }; } + _activateCoreListeners(html) { + super._activateCoreListeners(html); + if (this.changeTabs !== null) { + const tabName = this.changeTabs.toString(); + if (tabName !== this._tabs[0].active) this._tabs[0].activate(tabName); + this.changeTabs = null; + } + } + activateItemListListeners(html) { // show entity sheet html.find(".item-edit").click((ev) => { @@ -646,58 +665,59 @@ class CompendiumBrowser extends Application { return npcs; } - hookCompendiumList(html) { - if (game.user.isGM - || this.settings.allowSpellBrowser - || this.settings.allowNpcBrowser - || this.settings.allowFeatBrowser - || this.settings.allowItemBrowser) { - - const cbButton = $( - `` - ); - html.find(".compendium-browser-btn").remove(); - - // adding to directory-list since the footer doesn't exist if the user is not gm - html.find(".directory-footer").append(cbButton); - - // Handle button clicks - cbButton.click((ev) => { - ev.preventDefault(); - // 0.4.1: Reset filters when you click button - this.resetFilters(); - // 0.4.3: Reset everything (including data) when you press the button - calls afterRender() hook - - if (!this.refreshList) { - if (game.user.isGM || this.settings.allowSpellBrowser) { - this.refreshList = "spell"; - } else if (this.settings.allowFeatBrowser) { - this.refreshList = "feat"; - } else if (this.settings.allowItemBrowser) { - this.refreshList = "item"; - } else if (this.settings.allowNPCBrowser) { - this.refreshList = "npc"; - } - } - this.render(true); - }); + hookCompendiumList(html, sidebarName) { + if (!game.user.isGM) { + if (!this.settings.allowNpcBrowser && sidebarName === "actors") return; + if (!this.settings.allowItemBrowser && sidebarName === "items") return; + if (!(this.settings.allowSpellBrowser + || this.settings.allowNpcBrowser + || this.settings.allowFeatBrowser + || this.settings.allowItemBrowser)) return; } + const cbButton = $( + `` + ); + html.find(".compendium-browser-btn").remove(); + + // adding to directory-list since the footer doesn't exist if the user is not gm + html.find(".directory-footer").append(cbButton); + + if (sidebarName === "compendium") sidebarName = null; + + // Handle button clicks + cbButton.click((ev) => { + ev.preventDefault(); + this.resetFilters(); + + if (sidebarName === "actors") { + this.refreshList = "npc"; + this.changeTabs = "npc"; + } else if (sidebarName === "items") { + this.refreshList = "item"; + this.changeTabs = "item"; + } else if (!this.refreshList) { + if (game.user.isGM || this.settings.allowSpellBrowser) { + this.refreshList = "spell"; + } else if (this.settings.allowFeatBrowser) { + this.refreshList = "feat"; + } else if (this.settings.allowItemBrowser) { + this.refreshList = "item"; + } else if (this.settings.allowNPCBrowser) { + this.refreshList = "npc"; + } + } + this.render(true); + }); } /* Hook to load the first data */ static afterRender(cb, html) { - // 0.4.3: Because a render always resets ALL the displayed filters (on all tabs) to unselected , we have to blank all the lists as well - // (because the current HTML template doesn't set the selected filter values) - if (!cb?.refreshList) { - return; - } + if (!cb?.refreshList) return; cb.replaceList(html, cb.refreshList); - // cb.refreshList = null; - if (CompendiumBrowser.postRender) { CompendiumBrowser.postRender(); } @@ -922,17 +942,19 @@ class CompendiumBrowser extends Application { } } else if (item.type === "feat" || item.type === "class") { // getting class - let reqString = item.requirements?.replace(/[0-9]/g, "").trim(); - let matchedClass = []; - for (let c in this.subClasses) { - if (reqString && reqString.toLowerCase().indexOf(c) !== -1) { - matchedClass.push(c); - } else { - for (let subClass of this.subClasses[c]) { - if (reqString && reqString.indexOf(subClass) !== -1) { - matchedClass.push(c); - break; - } + const matchedClass = []; + const reqString = item.requirements?.replace(/\d/g, "").trim(); + if (reqString) { + const reqStringLower = reqString.toLowerCase(); + for (const [className, classInfo] of Object.entries(this.provider.classes)) { + const isClassMatch = reqStringLower && className.toLowerCase().includes(reqStringLower); + const isSubclassMatch = classInfo.subclasses.some( + // TODO compare with id and label + (subClass) => reqString.includes(subClass) + ); + + if (isClassMatch || isSubclassMatch) { + matchedClass.push(className); } } } @@ -942,7 +964,6 @@ class CompendiumBrowser extends Application { // getting uses/ressources status item.usesRessources = item5e.hasLimitedUses; } else if (item.type === "subclass") { - // subclasses dont exist lower then version 10 item.classRequirement = [item.system.classIdentifier]; item.classRequirementString = item.system.classIdentifier; } else { @@ -1145,113 +1166,6 @@ class CompendiumBrowser extends Application { return newObj; } - initSettings() { - let defaultSettings = { - loadedSpellCompendium: {}, - loadedNpcCompendium: {}, - }; - for (let compendium of game.packs) { - if (compendium.documentName === "Item") { - defaultSettings.loadedSpellCompendium[compendium.collection] = { - load: true, - name: `${compendium.metadata.label} (${compendium.collection})`, - }; - } - if (compendium.documentName === "Actor") { - defaultSettings.loadedNpcCompendium[compendium.collection] = { - load: true, - name: `${compendium.metadata.label} (${compendium.collection})`, - }; - } - } - // creating game setting container - game.settings.register(COMPENDIUM_BROWSER, "settings", { - name: "Compendium Browser Settings", - hint: "Settings to exclude packs from loading and visibility of the browser", - default: defaultSettings, - type: Object, - scope: "world", - onChange: (settings) => { - this.settings = settings; - }, - }); - game.settings.register(COMPENDIUM_BROWSER, "maxload", { - name: game.i18n.localize("CMPBrowser.SETTING.Maxload.NAME"), - hint: game.i18n.localize("CMPBrowser.SETTING.Maxload.HINT"), - scope: "world", - config: true, - default: 600, - type: Number, - range: { - // If range is specified, the resulting setting will be a range slider - min: 200, - max: 2000, - step: 100, - }, - }); - game.settings.register(COMPENDIUM_BROWSER, "extraButtonsGlobal", { - name: game.i18n.localize("CMPBrowser.SETTING.extraButtonsGlobal.NAME"), - hint: game.i18n.localize("CMPBrowser.SETTING.extraButtonsGlobal.HINT"), - scope: "world", - config: true, - default: true, - type: Boolean, - }); - game.settings.register(COMPENDIUM_BROWSER, "extraSheetButtons", { - name: game.i18n.localize("CMPBrowser.SETTING.extraSheetButtons.NAME"), - hint: game.i18n.localize("CMPBrowser.SETTING.extraSheetButtons.HINT"), - scope: "client", - config: true, - default: true, - type: Boolean, - }); - game.settings.register(COMPENDIUM_BROWSER, "extraAdvancementButtons", { - name: game.i18n.localize("CMPBrowser.SETTING.extraAdvancementButtons.NAME"), - hint: game.i18n.localize("CMPBrowser.SETTING.extraAdvancementButtons.HINT"), - scope: "client", - config: true, - default: true, - type: Boolean, - }); - game.settings.register(COMPENDIUM_BROWSER, "bannersGlobal", { - name: game.i18n.localize("CMPBrowser.SETTING.bannersGlobal.NAME"), - hint: game.i18n.localize("CMPBrowser.SETTING.bannersGlobal.HINT"), - scope: "world", - config: true, - default: true, - type: Boolean, - }); - game.settings.register(COMPENDIUM_BROWSER, "bannersLocal", { - name: game.i18n.localize("CMPBrowser.SETTING.bannersLocal.NAME"), - hint: game.i18n.localize("CMPBrowser.SETTING.bannersLocal.HINT"), - scope: "client", - config: true, - default: true, - type: Boolean, - }); - - // load settings from container and apply to default settings (available compendie might have changed) - let settings = game.settings.get(COMPENDIUM_BROWSER, "settings"); - for (let compKey in defaultSettings.loadedSpellCompendium) { - // v0.7.1 Check for settings.loadedSpellCompendium - if (settings.loadedSpellCompendium && settings.loadedSpellCompendium[compKey] !== undefined) { - defaultSettings.loadedSpellCompendium[compKey].load = settings.loadedSpellCompendium[compKey].load; - } - } - for (let compKey in defaultSettings.loadedNpcCompendium) { - // v0.7.1 Check for settings.loadedNpcCompendium - if (settings.loadedNpcCompendium && settings.loadedNpcCompendium[compKey] !== undefined) { - defaultSettings.loadedNpcCompendium[compKey].load = settings.loadedNpcCompendium[compKey].load; - } - } - defaultSettings.allowSpellBrowser = !!settings.allowSpellBrowser; - defaultSettings.allowFeatBrowser = !!settings.allowFeatBrowser; - defaultSettings.allowItemBrowser = !!settings.allowItemBrowser; - defaultSettings.allowNpcBrowser = !!settings.allowNpcBrowser; - - this.settings = defaultSettings; - } - // FILTERS - Added on the Ready hook // 0.4.0 Make this async so filters can be added all at once async addFilter(entityType, category, label, path, type, possibleValues = null, valIsArray = false) { @@ -1290,7 +1204,7 @@ class CompendiumBrowser extends Application { } async addSpellFilters() { - this.addSpellFilter("CMPBrowser.general", "DND5E.Source", "system.source", "text"); + this.addSpellFilter("CMPBrowser.general", "DND5E.Source", "system.source.book", "text"); this.addSpellFilter("CMPBrowser.general", "DND5E.Level", "system.level", "multiSelect", { 0: "DND5E.SpellCantrip", 1: "1", @@ -1332,23 +1246,17 @@ class CompendiumBrowser extends Application { "select", this._sortPackValues(CONFIG.DND5E.damageTypes) ); - // JV-082: Fix for missing "Class" search feature + const classes = Object.fromEntries( + Object.entries(this.provider.classes).map(([k, v]) => { + return [k, v.label]; + }) + ); this.addSpellFilter( "CMPBrowser.general", "ITEM.TypeClass", "classes", "select", - this._sortPackValues({ - artificer: "CMPBrowser.artificer", - bard: "CMPBrowser.bard", - cleric: "CMPBrowser.cleric", - druid: "CMPBrowser.druid", - paladin: "CMPBrowser.paladin", - ranger: "CMPBrowser.ranger", - sorcerer: "CMPBrowser.sorcerer", - warlock: "CMPBrowser.warlock", - wizard: "CMPBrowser.wizard", - }), + this._sortPackValues(classes), true ); this.addSpellFilter("DND5E.SpellComponents", "DND5E.Ritual", "system.properties.ritual", "bool"); @@ -1359,7 +1267,7 @@ class CompendiumBrowser extends Application { } async addItemFilters() { - this.addItemFilter("CMPBrowser.general", "DND5E.Source", "system.source", "text"); + this.addItemFilter("CMPBrowser.general", "DND5E.Source", "system.source.book", "text"); this.addItemFilter( "CMPBrowser.general", @@ -1444,27 +1352,18 @@ class CompendiumBrowser extends Application { async addFeatFilters() { // Feature Filters // Foundry v10+ Item#data is now Item#system - this.addFeatFilter("CMPBrowser.general", "DND5E.Source", "system.source", "text"); + this.addFeatFilter("CMPBrowser.general", "DND5E.Source", "system.source.book", "text"); + const classes = Object.fromEntries( + Object.entries(this.provider.classes).map(([k, v]) => { + return [k, v.label]; + }) + ); this.addFeatFilter( "CMPBrowser.general", "ITEM.TypeClass", "classRequirement", "select", - this._sortPackValues({ - artificer: "CMPBrowser.artificer", - barbarian: "CMPBrowser.barbarian", - bard: "CMPBrowser.bard", - cleric: "CMPBrowser.cleric", - druid: "CMPBrowser.druid", - fighter: "CMPBrowser.fighter", - monk: "CMPBrowser.monk", - paladin: "CMPBrowser.paladin", - ranger: "CMPBrowser.ranger", - rogue: "CMPBrowser.rogue", - sorcerer: "CMPBrowser.sorcerer", - warlock: "CMPBrowser.warlock", - wizard: "CMPBrowser.wizard", - }), + this._sortPackValues(classes), true ); @@ -1539,7 +1438,7 @@ class CompendiumBrowser extends Application { async addNpcFilters() { // NPC Filters - this.addNpcFilter("CMPBrowser.general", "DND5E.Source", "system.details.source", "text"); + this.addNpcFilter("CMPBrowser.general", "DND5E.Source", "system.details.source.book", "text"); this.addNpcFilter("CMPBrowser.general", "DND5E.Size", "system.traits.size", "select", CONFIG.DND5E.actorSizes); this.addNpcFilter("CMPBrowser.general", "CMPBrowser.hasLegAct", "system.resources.legact.max", "bool"); @@ -1796,260 +1695,27 @@ class CompendiumBrowser extends Application { console.warn(filterTarget); } - - static async addTidySheetButton(cb, html, actor) { - await CompendiumBrowser.createBanners(html); - await CompendiumBrowser.addButtons(html, actor); - } - - static async addButtons(html, actor) { - - // exit out because we dont want these - if (!CompendiumBrowser.extraButtonsGlobal || !CompendiumBrowser.extraSheetButtons) { - return; - } - - await CompendiumBrowser.addTidyFeatureButton(html, "race"); - await CompendiumBrowser.addTidyFeatureButton(html, "background"); - await CompendiumBrowser.addTidyFeatureButton(html, "class"); - - await html.find(".spell-browser-btn").remove(); - - let tabBar = html.find("div.tab.spellbook .spellcasting-ability"); - - const tooltip = game.i18n.localize("CMPBrowser.ToolTip.Spells"); - const cbButton = $( - `