diff --git a/daggerheart.mjs b/daggerheart.mjs index 7bbdd947..1c4c2a85 100644 --- a/daggerheart.mjs +++ b/daggerheart.mjs @@ -162,6 +162,9 @@ Hooks.on('ready', async () => { if (game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.appearance).displayFear !== 'hide') ui.resources.render({ force: true }); + if(!(ui.compendiumBrowser instanceof applications.ui.ItemBrowser)) + ui.compendiumBrowser = new applications.ui.ItemBrowser(); + registerCountdownHooks(); socketRegistration.registerSocketHooks(); registerRollDiceHooks(); diff --git a/module/applications/characterCreation/characterCreation.mjs b/module/applications/characterCreation/characterCreation.mjs index cf20934e..490294cd 100644 --- a/module/applications/characterCreation/characterCreation.mjs +++ b/module/applications/characterCreation/characterCreation.mjs @@ -1,6 +1,5 @@ import { abilities } from '../../config/actorConfig.mjs'; import { burden } from '../../config/generalConfig.mjs'; -import { ItemBrowser } from '../ui/itemBrowser.mjs'; import { createEmbeddedItemsWithEffects, createEmbeddedItemWithEffects } from '../../helpers/utils.mjs'; const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; @@ -46,8 +45,6 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl }; this._dragDrop = this._createDragDropHandlers(); - - this.itemBrowser = null; } get title() { @@ -448,7 +445,7 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl 'type': { key: 'type', value: type } }; - return (this.itemBrowser = await new ItemBrowser({ presets }).render({ force: true })); + ui.compendiumBrowser.open(presets); } static async viewItem(_, target) { @@ -566,7 +563,7 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl { overwrite: true } ); - if (this.itemBrowser) this.itemBrowser.close(); + if (ui.compendiumBrowser) ui.compendiumBrowser.close(); this.close(); } diff --git a/module/applications/levelup/levelup.mjs b/module/applications/levelup/levelup.mjs index 389e32f2..99cc53f6 100644 --- a/module/applications/levelup/levelup.mjs +++ b/module/applications/levelup/levelup.mjs @@ -1,6 +1,5 @@ import { abilities, subclassFeatureLabels } from '../../config/actorConfig.mjs'; import { getDeleteKeys, tagifyElement } from '../../helpers/utils.mjs'; -import { ItemBrowser } from '../ui/itemBrowser.mjs'; const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; @@ -12,8 +11,6 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2) this._dragDrop = this._createDragDropHandlers(); this.tabGroups.primary = 'advancements'; - - this.itemBrowser = null; } get title() { @@ -558,7 +555,7 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2) }; } - return (this.itemBrowser = await new ItemBrowser({ presets }).render({ force: true })); + ui.compendiumBrowser.open(presets); } static async selectPreview(_, button) { @@ -661,7 +658,8 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2) }, {}); await this.actor.levelUp(levelupData); - if (this.itemBrowser) this.itemBrowser.close(); + + if (ui.compendiumBrowser) ui.compendiumBrowser.close(); this.close(); } } diff --git a/module/applications/sheets/actors/character.mjs b/module/applications/sheets/actors/character.mjs index 308faee7..500141c1 100644 --- a/module/applications/sheets/actors/character.mjs +++ b/module/applications/sheets/actors/character.mjs @@ -5,7 +5,6 @@ import { CharacterLevelup, LevelupViewMode } from '../../levelup/_module.mjs'; import DhCharacterCreation from '../../characterCreation/characterCreation.mjs'; import FilterMenu from '../../ux/filter-menu.mjs'; import { getDocFromElement, getDocFromElementSync } from '../../../helpers/utils.mjs'; -import { ItemBrowser } from '../../ui/itemBrowser.mjs'; /**@typedef {import('@client/applications/_types.mjs').ApplicationClickAction} ApplicationClickAction */ @@ -29,8 +28,7 @@ export default class CharacterSheet extends DHBaseActorSheet { toggleEquipItem: CharacterSheet.#toggleEquipItem, toggleResourceDice: CharacterSheet.#toggleResourceDice, handleResourceDice: CharacterSheet.#handleResourceDice, - useDowntime: this.useDowntime, - tempBrowser: CharacterSheet.#tempBrowser + useDowntime: this.useDowntime }, window: { resizable: true, @@ -635,7 +633,6 @@ export default class CharacterSheet extends DHBaseActorSheet { const { key } = button.dataset; const presets = { - compendium: 'daggerheart', folder: key, filter: key === 'subclasses' @@ -651,7 +648,7 @@ export default class CharacterSheet extends DHBaseActorSheet { } }; - return new ItemBrowser({ presets }).render({ force: true }); + ui.compendiumBrowser.open(presets); } /** @@ -768,13 +765,6 @@ export default class CharacterSheet extends DHBaseActorSheet { }); } - /** - * Temp - */ - static async #tempBrowser(_, target) { - new ItemBrowser().render({ force: true }); - } - /** * Handle the roll values of resource dice. * @type {ApplicationClickAction} diff --git a/module/applications/sheets/api/application-mixin.mjs b/module/applications/sheets/api/application-mixin.mjs index b1dcfe50..2158e48b 100644 --- a/module/applications/sheets/api/application-mixin.mjs +++ b/module/applications/sheets/api/application-mixin.mjs @@ -1,6 +1,5 @@ const { HandlebarsApplicationMixin } = foundry.applications.api; import { getDocFromElement, getDocFromElementSync, tagifyElement } from '../../../helpers/utils.mjs'; -import { ItemBrowser } from '../../ui/itemBrowser.mjs'; const typeSettingsMap = { character: 'extendCharacterDescriptions', @@ -619,7 +618,7 @@ export default function DHApplicationMixin(Base) { return; } - return new ItemBrowser({ presets }).render({ force: true }); + ui.compendiumBrowser.open(presets); } /** diff --git a/module/applications/ui/itemBrowser.mjs b/module/applications/ui/itemBrowser.mjs index dc8c61ab..40884817 100644 --- a/module/applications/ui/itemBrowser.mjs +++ b/module/applications/ui/itemBrowser.mjs @@ -15,16 +15,13 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { this.fieldFilter = []; this.selectedMenu = { path: [], data: null }; this.config = CONFIG.DH.ITEMBROWSER.compendiumConfig; - this.presets = options.presets; - - if (this.presets?.folder) - ItemBrowser.selectFolder.call(this, null, null, this.presets.folder); + this.presets = {}; } /** @inheritDoc */ static DEFAULT_OPTIONS = { id: 'itemBrowser', - classes: ['daggerheart', 'dh-style', 'dialog', 'compendium-browser'], + classes: ['daggerheart', 'dh-style', 'dialog', 'compendium-browser', 'loader'], tag: 'div', window: { frame: true, @@ -84,17 +81,15 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { } }; - /** @inheritDoc */ - async _preFirstRender(context, options) { - if (context.presets?.render?.noFolder || context.presets?.render?.lite) options.position.width = 600; - - await super._preFirstRender(context, options); - } - /** @inheritDoc */ async _preRender(context, options) { - if (context.presets?.render?.noFolder || context.presets?.render?.lite) - options.parts.splice(options.parts.indexOf('sidebar'), 1); + this.presets = options.presets ?? {}; + + const width = this.presets?.render?.noFolder === true || this.presets?.render?.lite === true ? 600 : 850; + if(this.rendered) + this.setPosition({ width }); + else + options.position.width = width; await super._preRender(context, options); } @@ -103,25 +98,18 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { async _onRender(context, options) { await super._onRender(context, options); + this.element + .querySelectorAll('[data-action="selectFolder"]') + .forEach(element => element.classList.toggle('is-selected', element.dataset.folderId === this.selectedMenu.path.join('.'))); + this._createSearchFilter(); - this._createFilterInputs(); - this._createDragProcess(); - - if (context.presets?.render?.lite) this.element.classList.add('lite'); - - if (context.presets?.render?.noFolder) this.element.classList.add('no-folder'); - - if (context.presets?.render?.noFilter) this.element.classList.add('no-filter'); - - if (this.presets?.filter) { - Object.entries(this.presets.filter).forEach( - ([k, v]) => { - const filter = this.fieldFilter.find(c => c.name === k) - if(filter) filter.value = v.value; - } - ); - await this._onInputFilterBrowser(); - } + + this.element.classList.toggle('lite', this.presets?.render?.lite === true); + this.element.classList.toggle('no-folder', this.presets?.render?.noFolder === true); + this.element.classList.toggle('no-filter', this.presets?.render?.noFilter === true); + this.element.querySelectorAll('.folder-list > [data-action="selectFolder"]').forEach(element => { + element.hidden = this.presets.render?.folders?.length && !this.presets.render.folders.includes(element.dataset.folderId); + }); } _attachPartListeners(partId, htmlElement, options) { @@ -142,20 +130,23 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { async _prepareContext(options) { const context = await super._prepareContext(options); context.compendiums = this.getCompendiumFolders(foundry.utils.deepClone(this.config)); - // context.pathTitle = this.pathTile; context.menu = this.selectedMenu; context.formatLabel = this.formatLabel; context.formatChoices = this.formatChoices; - context.fieldFilter = this.fieldFilter = this._createFieldFilter(); context.items = this.items; context.presets = this.presets; return context; } + open(presets = {}) { + this.presets = presets; + ItemBrowser.selectFolder.call(this); + } + getCompendiumFolders(config, parent = null, depth = 0) { let folders = []; Object.values(config).forEach(c => { - if(this.presets.render?.folders?.length && !this.presets.render.folders.includes(c.id)) return; + // if(this.presets.render?.folders?.length && !this.presets.render.folders.includes(c.id)) return; const folder = { id: c.id, label: game.i18n.localize(c.label), @@ -171,29 +162,9 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { return folders; } - static async selectFolder(_, target, folder) { - - let loadTimeout = ItemBrowser.toggleLoader(target, true); - - const folderId = folder ?? target.dataset.folderId, - folderData = foundry.utils.getProperty(this.config, folderId) ?? {}, - promises = []; - - game.packs.forEach(pack => { - promises.push( - new Promise(async resolve => { - const items = await pack.getDocuments({ type__in: folderData?.type }); - resolve(items); - }) - ) - }); - - Promise.all(promises).then(result => { - this.items = ItemBrowser.sortBy(result.flatMap(r => r), 'name'); - clearTimeout(loadTimeout); - ItemBrowser.toggleLoader(target, false); - this.render({ force: true }); - }); + static async selectFolder(_, target) { + const folderId = target?.dataset?.folderId ?? this.presets.folder, + folderData = foundry.utils.getProperty(this.config, folderId) ?? {}; const columns = ItemBrowser.getFolderConfig(folderData).map(col => ({ ...col, @@ -201,20 +172,17 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { })); this.selectedMenu = { - path: folderId.split('.'), + path: folderId?.split('.') ?? [], data: { ...folderData, columns: columns } }; - if (target) { - target - .closest('.compendium-sidebar') - .querySelectorAll('[data-action="selectFolder"]') - .forEach(element => element.classList.remove('is-selected')); - target.classList.add('is-selected'); - } + await this.render({ force: true, presets: this.presets }); + + if(this.selectedMenu?.data?.type?.length) + this.loadItems(); } _replaceHTML(result, content, options) { @@ -222,9 +190,70 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { super._replaceHTML(result, content, options); } - static toggleLoader(target, state) { - if(!target) return; - const container = target.closest(".window-content"); + loadItems() { + let loadTimeout = this.toggleLoader(true); + + const promises = []; + + game.packs.forEach(pack => { + promises.push( + new Promise(async resolve => { + const items = await pack.getDocuments({ type__in: this.selectedMenu?.data?.type }); + resolve(items); + }) + ) + }); + + Promise.all(promises).then(async result => { + this.items = ItemBrowser.sortBy(result.flatMap(r => r), 'name'); + this.fieldFilter = this._createFieldFilter(); + + if (this.presets?.filter) { + Object.entries(this.presets.filter).forEach( + ([k, v]) => { + const filter = this.fieldFilter.find(c => c.name === k) + if(filter) filter.value = v.value; + } + ); + // await this._onInputFilterBrowser(); + } + + const filterList = await foundry.applications.handlebars.renderTemplate('systems/daggerheart/templates/ui/itemBrowser/filterContainer.hbs', + { + fieldFilter: this.fieldFilter, + presets: this.presets, + formatChoices: this.formatChoices + } + ); + + this.element.querySelector('.filter-content .wrapper').innerHTML = filterList; + const filterContainer = this.element.querySelector('.filter-header > [data-action="expandContent"]'); + if(this.fieldFilter.length === 0) + filterContainer.setAttribute('disabled', ''); + else + filterContainer.removeAttribute('disabled'); + + const itemList = await foundry.applications.handlebars.renderTemplate('systems/daggerheart/templates/ui/itemBrowser/itemContainer.hbs', + { + items: this.items, + menu: this.selectedMenu, + formatLabel: this.formatLabel + } + ); + + this.element.querySelector('.item-list').innerHTML = itemList; + + this._createFilterInputs(); + await this._onInputFilterBrowser(); + this._createDragProcess(); + + clearTimeout(loadTimeout); + this.toggleLoader(false); + }); + } + + toggleLoader(state) { + const container = this.element.querySelector('.item-list'); return setTimeout(() => { container.classList.toggle("loader", state); }, 100); @@ -347,6 +376,7 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { for (const li of html.querySelectorAll('.item-container')) { const itemUUID = li.dataset.itemUuid, item = this.items.find(i => i.uuid === itemUUID); + if(!item) continue; const matchesSearch = !query || foundry.applications.ux.SearchFilter.testQuery(rgx, item.name); if (matchesSearch) this.#filteredItems.browser.search.add(item.id); const { input } = this.#filteredItems.browser; @@ -369,7 +399,7 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { item = this.items.find(i => i.uuid === itemUUID); if (!item) continue; - + const matchesMenu = this.fieldFilter.length === 0 || this.fieldFilter.every( @@ -503,8 +533,9 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { ${game.i18n.localize("DAGGERHEART.UI.Tooltip.compendiumBrowser")} `; - button.addEventListener("click", event => (new ItemBrowser({ presets: menus[sectionId] })).render({ force: true })); - // button.addEventListener("click", event => ui.compendiumBrowser?.render({ force: true, presets: menus[sectionId] })); + button.addEventListener("click", event => { + ui.compendiumBrowser.open(menus[sectionId]); + }); headerActions.append(button); } diff --git a/module/config/itemBrowserConfig.mjs b/module/config/itemBrowserConfig.mjs index cad06046..046efd8b 100644 --- a/module/config/itemBrowserConfig.mjs +++ b/module/config/itemBrowserConfig.mjs @@ -355,7 +355,7 @@ export const typeConfig = { { key: 'system.domains', label: 'DAGGERHEART.GENERAL.Domain.plural', - choices: () => Object.values(CONFIG.DH.DOMAIN.domains).map(d => ({ value: d.id, label: d.label })), + choices: () => Object.values(CONFIG.DH.DOMAIN.allDomains()).map(d => ({ value: d.id, label: d.label })), operator: 'contains2' } ] diff --git a/module/systemRegistration/handlebars.mjs b/module/systemRegistration/handlebars.mjs index cb7be42a..fd569499 100644 --- a/module/systemRegistration/handlebars.mjs +++ b/module/systemRegistration/handlebars.mjs @@ -30,12 +30,13 @@ export const preloadHandlebarsTemplates = async function () { 'systems/daggerheart/templates/dialogs/downtime/activities.hbs', 'systems/daggerheart/templates/dialogs/dice-roll/costSelection.hbs', - 'systems/daggerheart/templates/ui/chat/parts/roll-part.hbs', 'systems/daggerheart/templates/ui/chat/parts/damage-part.hbs', 'systems/daggerheart/templates/ui/chat/parts/target-part.hbs', 'systems/daggerheart/templates/ui/chat/parts/button-part.hbs', + 'systems/daggerheart/templates/ui/itemBrowser/itemContainer.hbs', + 'systems/daggerheart/templates/scene/dh-config.hbs', ]); diff --git a/styles/less/global/global.less b/styles/less/global/global.less index 383cdc6f..4c06d42b 100644 --- a/styles/less/global/global.less +++ b/styles/less/global/global.less @@ -25,9 +25,11 @@ } .loader { + position: relative; + overflow: hidden !important; + div { opacity: .5; - // transition: opacity .3s ease-in-out; } &:before { diff --git a/styles/less/ui/item-browser/item-browser.less b/styles/less/ui/item-browser/item-browser.less index 7c18e08e..70a64d89 100644 --- a/styles/less/ui/item-browser/item-browser.less +++ b/styles/less/ui/item-browser/item-browser.less @@ -292,6 +292,7 @@ display: flex; flex-direction: column; gap: 5px; + flex: 1; .item-container { &:hover { @@ -392,6 +393,7 @@ .title { text-align: center; + font-weight: bold; } .hint { @@ -407,7 +409,7 @@ &.lite, &.no-folder { - .menu-path { + .compendium-sidebar, .menu-path { display: none; } } diff --git a/templates/sheets/actors/character/inventory.hbs b/templates/sheets/actors/character/inventory.hbs index ee5b6034..017d37d9 100644 --- a/templates/sheets/actors/character/inventory.hbs +++ b/templates/sheets/actors/character/inventory.hbs @@ -10,9 +10,6 @@ - - -