forked from public/foundryvtt-reve-de-dragon
		
	
		
			
				
	
	
		
			336 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			336 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
import { RdDItem } from '../item.js';
 | 
						|
import { HtmlUtility } from '../html-utility.js';
 | 
						|
import { Misc } from "../misc.js";
 | 
						|
import { CompendiumTableHelpers } from '../settings/system-compendiums.js';
 | 
						|
import { RdDRaretes } from '../item/raretes.js';
 | 
						|
import { Grammar } from '../grammar.js';
 | 
						|
 | 
						|
const FILTER_GROUPS = [
 | 
						|
  { group: 'type', label: "Type d'objet" },
 | 
						|
  { group: 'comestible', label: 'Alimentaire' },
 | 
						|
  { group: 'utilisation', label: 'Utilisation' },
 | 
						|
  { group: 'rarete', label: 'Rarete' },
 | 
						|
  { group: 'qualite', label: 'Qualité' },
 | 
						|
  { group: 'enc', label: 'Encombrement' },
 | 
						|
  { group: 'prix', label: 'Prix' },
 | 
						|
]
 | 
						|
 | 
						|
const FILTERS = [
 | 
						|
  { group: 'comestible', code: 'comestible', label: 'Comestible', check: (item, milieux) => item.getUtilisation() == 'cuisine' },
 | 
						|
  { group: 'comestible', code: 'pret', label: 'Préparé', check: (item, milieux) => item.getUtilisationCuisine() == 'pret' },
 | 
						|
  { group: 'comestible', code: 'brut', label: 'A préparer', check: (item, milieux) => item.getUtilisationCuisine() == 'brut' },
 | 
						|
  { group: 'comestible', code: 'boisson', label: 'Boisson', check: (item, milieux) => item.isBoisson() },
 | 
						|
  { group: 'comestible', code: 'alcool', label: 'Alcool', check: (item, milieux) => item.isAlcool() },
 | 
						|
  { group: 'comestible', code: 'immangeable', label: 'Immangeable', check: (item, milieux) => item.isInventaire() && item.getUtilisation() != 'cuisine' },
 | 
						|
 | 
						|
  { group: 'utilisation', code: 'alchimie', label: 'Alchimique', check: (item, milieux) => item.isInventaire() && item.getUtilisation() == 'alchimie' },
 | 
						|
  { group: 'utilisation', code: 'soins', label: 'Médical', check: (item, milieux) => item.isInventaire() && item.getUtilisation() == 'soins' },
 | 
						|
  { group: 'utilisation', code: 'poison', label: 'Toxique', check: (item, milieux) => item.isInventaire() && item.getUtilisation() == 'poison' },
 | 
						|
  { group: 'utilisation', code: 'cuisine', label: 'Cuisine', check: (item, milieux) => item.isInventaire() && item.getUtilisation() == 'cuisine' },
 | 
						|
  { group: 'utilisation', code: 'autres', label: 'Autres/inconnu', check: (item, milieux) => !item.isInventaire() || item.getUtilisation() == '' },
 | 
						|
 | 
						|
  { group: "qualite", code: "mauvaise", label: "Mauvaise (négative)", check: (item, milieux) => item.isInventaire() && item.system.qualite < 0 },
 | 
						|
  { group: "qualite", code: "quelconque", label: "Quelconque (0)", check: (item, milieux) => item.isInventaire() && item.system.qualite == 0 },
 | 
						|
  { group: "qualite", code: "correcte", label: "Correcte (1-3)", check: (item, milieux) => item.isInventaire() && 1 <= item.system.qualite && item.system.qualite <= 3 },
 | 
						|
  { group: "qualite", code: "bonne", label: "Bonne (4-6)", check: (item, milieux) => item.isInventaire() && 4 <= item.system.qualite && item.system.qualite <= 6 },
 | 
						|
  { group: "qualite", code: "excellente", label: "Excellente (7-9)", check: (item, milieux) => item.isInventaire() && 7 <= item.system.qualite && item.system.qualite <= 9 },
 | 
						|
  { group: "qualite", code: "mythique", label: "Mythique (10+)", check: (item, milieux) => item.isInventaire() && 10 <= item.system.qualite },
 | 
						|
 | 
						|
  { group: "enc", code: "negligeable", label: "Négligeable (jusqu'à 0.1)", check: (item, milieux) => item.isInventaire() && item.system.encombrement <= 0.1 },
 | 
						|
  { group: "enc", code: "leger", label: "Léger (0.1 à 0.5)", check: (item, milieux) => item.isInventaire() && 0.1 < item.system.encombrement && item.system.encombrement <= 0.5 },
 | 
						|
  { group: "enc", code: "moyen", label: "Moyen (0.5 à 1.5)", check: (item, milieux) => item.isInventaire() && 0.5 < item.system.encombrement && item.system.encombrement <= 1.5 },
 | 
						|
  { group: "enc", code: "lourd", label: "Lourd (1.5 à 3)", check: (item, milieux) => item.isInventaire() && 1.5 < item.system.encombrement && item.system.encombrement <= 3 },
 | 
						|
  { group: "enc", code: "massif", label: "Massif (3 à 10)", check: (item, milieux) => item.isInventaire() && 3 < item.system.encombrement && item.system.encombrement <= 10 },
 | 
						|
  { group: "enc", code: "anemort", label: "Un âne mort (plus de 10)", check: (item, milieux) => item.isInventaire() && 10 < item.system.encombrement },
 | 
						|
 | 
						|
  { group: "prix", code: "gratuit", label: "Gratuit", check: (item, milieux) => item.isInventaire() && item.system.cout == 0 },
 | 
						|
  { group: "prix", code: "deniers", label: "Deniers (étain)", check: (item, milieux) => item.isInventaire() && 0 < item.system.cout && item.system.cout < 0.1 },
 | 
						|
  { group: "prix", code: "bronze", label: "Sous (bronze)", check: (item, milieux) => item.isInventaire() && 0.1 <= item.system.cout && item.system.cout < 1 },
 | 
						|
  { group: "prix", code: "sols", label: "Sols (argent)", check: (item, milieux) => item.isInventaire() && 1 <= item.system.cout && item.system.cout < 10 },
 | 
						|
  { group: "prix", code: "dragons", label: "Dragons (or)", check: (item, milieux) => item.isInventaire() && 10 <= item.system.cout },
 | 
						|
]
 | 
						|
 | 
						|
 | 
						|
function $filterMilieux(milieux) {
 | 
						|
  return milieux.map(m => {
 | 
						|
    return {
 | 
						|
      code: m,
 | 
						|
      label: m,
 | 
						|
      check: (item, milieux) => item.isPresentDansMilieux(m)
 | 
						|
    }
 | 
						|
  })
 | 
						|
}
 | 
						|
 | 
						|
function $filterRarete() {
 | 
						|
  return RdDRaretes.raretes()
 | 
						|
    .filter(it => it.frequence > 0)
 | 
						|
    .map(r => {
 | 
						|
      return {
 | 
						|
        group: 'rarete',
 | 
						|
        code: r.code,
 | 
						|
        label: r.label,
 | 
						|
        check: (item, milieux) => item.getRaretes(milieux).map(it => it.code).includes(r.code)
 | 
						|
      }
 | 
						|
    });
 | 
						|
}
 | 
						|
 | 
						|
function $filterTypes() {
 | 
						|
  return RdDItem.getItemTypesInventaire().map(type => {
 | 
						|
    return {
 | 
						|
      group: 'type',
 | 
						|
      code: type,
 | 
						|
      label: Misc.typeName('Item', type),
 | 
						|
      check: (item, milieux) => item.type == type
 | 
						|
    };
 | 
						|
  });
 | 
						|
}
 | 
						|
 | 
						|
function $getAllFilters() {
 | 
						|
  return FILTERS
 | 
						|
    .concat($filterTypes())
 | 
						|
    .concat($filterRarete());
 | 
						|
}
 | 
						|
 | 
						|
function $addFilterToGroup(groups, filter) {
 | 
						|
  if (filter.group && filter.code && filter.label) {
 | 
						|
    let fg = groups.find(g => g.group == filter.group);
 | 
						|
    if (fg == undefined) {
 | 
						|
      groups.push({ group: filter.group, label: filter.group, filters: [filter] })
 | 
						|
    }
 | 
						|
    else if (fg.filters == undefined) {
 | 
						|
      fg.filters = [filter];
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      fg.filters.push(filter);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    console.warn("Filtre incorrect, pas de groupe/code/label", filter);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
function $loadFilters(parameters) {
 | 
						|
  $getAllFilters(parameters.milieux).forEach(f => $addFilterToGroup(parameters.filterGroups, f));
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
export class FenetreRechercheTirage extends Application {
 | 
						|
  static get defaultOptions() {
 | 
						|
    return mergeObject(super.defaultOptions, {
 | 
						|
      template: "systems/foundryvtt-reve-de-dragon/templates/tirage/fenetre-recherche-tirage.hbs",
 | 
						|
      title: `Recherches et tirages`,
 | 
						|
      width: 600,
 | 
						|
      height: 600,
 | 
						|
      popOut: true,
 | 
						|
      dragDrop: [{ dragSelector: "a.content-link" }],
 | 
						|
      resizable: true
 | 
						|
    });
 | 
						|
  }
 | 
						|
 | 
						|
  static async create() {
 | 
						|
    const milieux = await game.system.rdd.environnement.milieux();
 | 
						|
    const parameters = {
 | 
						|
      milieux: milieux,
 | 
						|
      filterMilieux: $filterMilieux(milieux),
 | 
						|
      filterGroups: duplicate(FILTER_GROUPS).filter(it => it.group),
 | 
						|
    }
 | 
						|
    const options = {}
 | 
						|
    $loadFilters(parameters);
 | 
						|
 | 
						|
    new FenetreRechercheTirage(parameters, options).render(true);
 | 
						|
  }
 | 
						|
 | 
						|
  constructor(parameters, options) {
 | 
						|
    super(options);
 | 
						|
    this.parameters = parameters;
 | 
						|
  }
 | 
						|
 | 
						|
  async getData() {
 | 
						|
    return mergeObject(await super.getData(), this.parameters)
 | 
						|
  }
 | 
						|
 | 
						|
  _canDragStart() { return true; }
 | 
						|
  _onDragStart(event) { }
 | 
						|
 | 
						|
  _getHeaderButtons() {
 | 
						|
    let buttons = super._getHeaderButtons();
 | 
						|
    if (game.user.isGM) {
 | 
						|
      buttons.unshift({
 | 
						|
        class: "configurer",
 | 
						|
        label: "Configurer",
 | 
						|
        icon: "fas fa-cogs",
 | 
						|
        onclick: ev => this.configurer()
 | 
						|
      });
 | 
						|
    }
 | 
						|
    return buttons
 | 
						|
  }
 | 
						|
 | 
						|
  activateListeners(html) {
 | 
						|
    super.activateListeners(html);
 | 
						|
    this.html = html;
 | 
						|
 | 
						|
    this.showFilterGroup(this.html, false);
 | 
						|
 | 
						|
    this.html.find("a.section-filters-toggle").click(event => {
 | 
						|
      const groupDiv = this.html.find(event.currentTarget)?.parents('div.section-filters-root').first();
 | 
						|
      const visible = groupDiv.find('div.section-filters-content').first().is(":visible");
 | 
						|
      this.showFilterGroup(groupDiv, !visible)
 | 
						|
    });
 | 
						|
 | 
						|
    this.html.find("input:is(.activate-filter-group,.activate-filter-milieu)").change(event => this.changeListeFiltresActifs())
 | 
						|
 | 
						|
    this.html.find("a.supprimer-filtres").click(async event => this.supprimerFiltres())
 | 
						|
 | 
						|
    this.html.find("a.recherche-filtres").click(async event => await this.recherche())
 | 
						|
 | 
						|
    this.html.find("a.tirage-filtres").click(async event => {
 | 
						|
      const table = await this.buildTable();
 | 
						|
      const row = await CompendiumTableHelpers.getRandom(table, 'Item')
 | 
						|
      await CompendiumTableHelpers.tableRowToChatMessage(row, 'Item');
 | 
						|
    })
 | 
						|
  }
 | 
						|
 | 
						|
  showFilterGroup(groupDiv, show) {
 | 
						|
    if (groupDiv) {
 | 
						|
      HtmlUtility.showControlWhen(groupDiv.find('div.section-filters-content'), show);
 | 
						|
      HtmlUtility.showControlWhen(groupDiv.find('i.section-filters-hide'), show);
 | 
						|
      HtmlUtility.showControlWhen(groupDiv.find('i.section-filters-show'), !show);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  supprimerFiltres() {
 | 
						|
    this.html.find('input:is(.activate-filter-group,.activate-filter-milieu)').prop("checked", false);
 | 
						|
    this.html.find('div.liste-resultats-recherche').html('');
 | 
						|
    this.html.find('.section-filters-text input.recherche').val('');
 | 
						|
  }
 | 
						|
 | 
						|
  async recherche() {
 | 
						|
    const table = await this.buildTable();
 | 
						|
    const htmlResultats = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/tirage/liste-resultats-recherche.hbs`, { resultats: table });
 | 
						|
    this.html.find('div.liste-resultats-recherche').html(htmlResultats);
 | 
						|
    this._dragDrop.forEach(dragDropHandler => dragDropHandler.bind(this.element[0]))
 | 
						|
  }
 | 
						|
 | 
						|
  async buildTable() {
 | 
						|
    const milieux = this.getSelectedMilieux();
 | 
						|
    const filterItemMilieux = this.buildCheckedGroupFilter(milieux);
 | 
						|
    const filter = it => filterItemMilieux(it, milieux);
 | 
						|
    const itemFrequence = it => it.getFrequence(milieux);
 | 
						|
    return await game.system.rdd.environnement.buildTable(itemFrequence, filter)
 | 
						|
  }
 | 
						|
 | 
						|
  buildMilieuxFilter(milieux) {
 | 
						|
    if (milieux) {
 | 
						|
      return this.buildOrFilter(this.parameters.filterMilieux.filter(it => milieux.includes(it.code)).map(f => f.check));
 | 
						|
    }
 | 
						|
    return (it, mi) => true;
 | 
						|
  }
 | 
						|
  buildFilterRechercheName() {
 | 
						|
    const recherche = this.html.find('.section-filters-text input.recherche').val();
 | 
						|
    if (recherche) {
 | 
						|
      return  (it, mi) => Grammar.includesLowerCaseNoAccent(it.name, recherche);
 | 
						|
    }
 | 
						|
    return (it, mi) => true;
 | 
						|
  }
 | 
						|
 | 
						|
  buildCheckedGroupFilter(milieux) {
 | 
						|
    const filtersList = this.getGroupCheckedFilters()
 | 
						|
      .map(gf => this.buildOrFilter(gf.filters.map(f => f.check)));
 | 
						|
    filtersList.push(this.buildMilieuxFilter(milieux));
 | 
						|
    filtersList.push(this.buildFilterRechercheName());
 | 
						|
    return this.buildAndFilter(filtersList)
 | 
						|
  }
 | 
						|
 | 
						|
  buildAndFilter(filters) { return filters.reduce((f1, f2) => { return (it, mi) => f1(it, mi) && f2(it, mi); }); }
 | 
						|
  buildOrFilter(filters) { return filters.reduce((f1, f2) => { return (it, mi) => f1(it, mi) || f2(it, mi); }); }
 | 
						|
 | 
						|
  changeListeFiltresActifs() {
 | 
						|
    const milieux = this.getSelectedMilieux();
 | 
						|
    const summariesList = this.getGroupCheckedFilters()
 | 
						|
      .map(gf => {
 | 
						|
        return gf.group.label + ': ' + gf.filters
 | 
						|
          .map(f => f.label)
 | 
						|
          .reduce(Misc.joining(', '))
 | 
						|
      });
 | 
						|
    if (milieux) {
 | 
						|
      summariesList.push('Milieux: ' + this.parameters.filterMilieux.filter(f => milieux.includes(f.code)).map(f => f.label).reduce(Misc.joining(', ')))
 | 
						|
    }
 | 
						|
    const fullText = summariesList.length == 0 ? "" : summariesList.reduce(Misc.joining(' - '));
 | 
						|
    this.html.find('span.liste-filtres-actifs').text(fullText);
 | 
						|
  }
 | 
						|
 | 
						|
  getGroupCheckedFilters() {
 | 
						|
    const checkedGroupFilters = jQuery.map(this.html.find('input.activate-filter-group:checked'), it => this.html.find(it))
 | 
						|
      .map(element => {
 | 
						|
        return {
 | 
						|
          group: element.data('group'),
 | 
						|
          code: element.data('code')
 | 
						|
        };
 | 
						|
      }).filter(it => it.group);
 | 
						|
 | 
						|
    const entries = Object.entries(Misc.classify(checkedGroupFilters, it => it.group));
 | 
						|
    return entries.map(([key, list]) => {
 | 
						|
      const group = this.parameters.filterGroups.find(g => g.group == key);
 | 
						|
      const filters = list.map(it => group.filters.find(f => it.code == f.code));
 | 
						|
      return { group, filters };
 | 
						|
    });
 | 
						|
  }
 | 
						|
 | 
						|
  getSelectedMilieux() {
 | 
						|
    const milieux = jQuery.map(this.html.find('input.activate-filter-milieu:checked'), it => {
 | 
						|
      return this.html.find(it).data('code');
 | 
						|
    });
 | 
						|
    return milieux.length == 0 ? undefined : milieux
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  async configurer() {
 | 
						|
    FenetreRechercheConfiguration.create();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
class FenetreRechercheConfiguration extends Dialog {
 | 
						|
  static async create() {
 | 
						|
    const configuration = {
 | 
						|
      compendiums: game.packs.filter(it => it.metadata.type == 'Item').map(it => it.metadata)
 | 
						|
        .map(it => mergeObject({ selected: game.system.rdd.environnement.compendiums.includes(it.id) }, it))
 | 
						|
    }
 | 
						|
    const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/tirage/fenetre-recherche-configuration.hbs", configuration);
 | 
						|
    new FenetreRechercheConfiguration(html).render(true);
 | 
						|
  }
 | 
						|
 | 
						|
  constructor(html) {
 | 
						|
    const options = {
 | 
						|
      classes: ["fenetre-recherche-configuration"],
 | 
						|
      width: 600,
 | 
						|
      height: 'fit-content',
 | 
						|
      'max-height': 600,
 | 
						|
      height: 'fit-content',
 | 
						|
      'z-index': 99999
 | 
						|
    };
 | 
						|
    const conf = {
 | 
						|
      title: 'Configuration de la recherche',
 | 
						|
      content: html,
 | 
						|
      buttons: {
 | 
						|
        "Sauvegarder": { label: "Sauvegarder", callback: async it => { await this.sauvegarder(); } }
 | 
						|
      }
 | 
						|
    };
 | 
						|
    super(conf, options)
 | 
						|
  }
 | 
						|
 | 
						|
  activateListeners(html) {
 | 
						|
    this.html = html;
 | 
						|
    super.activateListeners(html);
 | 
						|
    this.html.find("button.configuration-save").click(event => this.sauvegarder())
 | 
						|
  }
 | 
						|
 | 
						|
  async sauvegarder() {
 | 
						|
    const compendiumIds = jQuery.map(this.html.find("input.select-compendium:checked"), it => {
 | 
						|
      return this.html.find(it).data('id');
 | 
						|
    });
 | 
						|
    await game.system.rdd.environnement.saveCompendiums(compendiumIds);
 | 
						|
    this.close();
 | 
						|
  }
 | 
						|
}
 |