From 10ad294690eca2584088d88b28e369489eb90506 Mon Sep 17 00:00:00 2001 From: James Tanner Date: Sun, 9 Jul 2023 12:42:24 -0700 Subject: [PATCH] Run make fmt --- sim/druid/survival_instincts.go | 2 +- ui/balance_druid/presets.ts | 240 +-- ui/core/components/base_modal.ts | 4 +- ui/core/components/character_stats.ts | 6 +- ui/core/components/close_button.ts | 2 +- ui/core/components/content_block.ts | 82 +- ui/core/components/detailed_results.ts | 6 +- .../detailed_results/dps_histogram.ts | 2 +- ui/core/components/dropdown_picker.ts | 310 +-- ui/core/components/encounter_picker.ts | 12 +- ui/core/components/exporters.ts | 134 +- ui/core/components/filters_menu.ts | 6 +- ui/core/components/fire_elemental_inputs.ts | 40 +- ui/core/components/gear_picker.ts | 26 +- ui/core/components/icon_enum_picker.ts | 4 +- ui/core/components/importers.ts | 16 +- .../individual_sim_ui/apl_actions.ts | 28 +- .../individual_sim_ui/apl_helpers.ts | 10 +- .../individual_sim_ui/apl_rotation_picker.ts | 109 +- .../individual_sim_ui/apl_values.ts | 24 +- .../components/individual_sim_ui/bulk_tab.ts | 1622 ++++++++-------- .../individual_sim_ui/consumes_picker.ts | 160 +- .../custom_rotation_picker.ts | 2 +- .../components/individual_sim_ui/gear_tab.ts | 96 +- .../individual_sim_ui/rotation_tab.ts | 132 +- .../individual_sim_ui/settings_tab.ts | 74 +- ui/core/components/input.ts | 4 +- ui/core/components/input_helpers.ts | 2 +- ui/core/components/item_swap_picker.ts | 8 +- ui/core/components/list_picker.ts | 2 +- ui/core/components/multi_icon_picker.ts | 2 +- ui/core/components/other_inputs.ts | 22 +- ui/core/components/raid_sim_action.ts | 78 +- ui/core/components/raid_target_picker.ts | 6 +- ui/core/components/results_viewer.ts | 2 +- ui/core/components/saved_data_manager.ts | 4 +- ui/core/components/settings_menu.ts | 2 +- ui/core/components/sim_header.ts | 48 +- ui/core/components/sim_tab.ts | 58 +- ui/core/components/sim_title_dropdown.ts | 398 ++-- ui/core/components/stat_weights_action.ts | 10 +- ui/core/components/totem_inputs.ts | 8 +- ui/core/individual_sim_ui.ts | 40 +- ui/core/player.ts | 26 +- ui/core/proto_utils/action_id.ts | 4 +- ui/core/proto_utils/database.ts | 8 +- ui/core/proto_utils/gear.ts | 18 +- ui/core/proto_utils/logs_parser.ts | 4 +- ui/core/proto_utils/stats.ts | 8 +- ui/core/proto_utils/utils.ts | 20 +- ui/core/sim.ts | 4 +- ui/core/sim_ui.ts | 8 +- ui/core/talents/glyphs_picker.ts | 2 +- ui/core/talents/talents_picker.ts | 2 +- ui/core/utils.ts | 8 +- ui/core/worker_pool.ts | 2 +- ui/deathknight/inputs.ts | 2 +- ui/deathknight/presets.ts | 10 +- ui/elemental_shaman/presets.ts | 4 +- ui/enhancement_shaman/inputs.ts | 74 +- ui/enhancement_shaman/presets.ts | 20 +- ui/feral_druid/inputs.ts | 4 +- ui/feral_tank_druid/sim.ts | 10 +- ui/index.ts | 28 +- ui/mage/presets.ts | 4 +- ui/protection_paladin/presets.ts | 4 +- ui/protection_paladin/sim.ts | 2 +- ui/protection_warrior/presets.ts | 2 +- ui/protection_warrior/sim.ts | 2 +- ui/raid/assignments_picker.ts | 4 +- ui/raid/import_export.ts | 113 +- ui/raid/presets.ts | 4 +- ui/raid/raid_picker.ts | 2 +- ui/raid/raid_stats.ts | 1658 +++++++++-------- ui/raid/raid_tab.ts | 88 +- ui/raid/settings_tab.ts | 212 +-- ui/restoration_druid/presets.ts | 4 +- ui/retribution_paladin/inputs.ts | 6 +- ui/rogue/presets.ts | 8 +- ui/rogue/sim.ts | 26 +- ui/shared/bootstrap_overrides.ts | 92 +- ui/shared/utils.ts | 22 +- ui/tank_deathknight/presets.ts | 16 +- ui/warlock/presets.ts | 16 +- ui/warrior/inputs.ts | 2 +- ui/warrior/presets.ts | 4 +- 86 files changed, 3204 insertions(+), 3196 deletions(-) diff --git a/sim/druid/survival_instincts.go b/sim/druid/survival_instincts.go index 9c75ce95e7..2cea0cd8ff 100644 --- a/sim/druid/survival_instincts.go +++ b/sim/druid/survival_instincts.go @@ -38,7 +38,7 @@ func (druid *Druid) registerSurvivalInstinctsCD() { druid.SurvivalInstincts = druid.RegisterSpell(core.SpellConfig{ ActionID: actionID, - Flags: SpellFlagOmenTrigger, + Flags: SpellFlagOmenTrigger, Cast: core.CastConfig{ CD: core.Cooldown{ Timer: cdTimer, diff --git a/ui/balance_druid/presets.ts b/ui/balance_druid/presets.ts index f346b54e2c..6112f48989 100644 --- a/ui/balance_druid/presets.ts +++ b/ui/balance_druid/presets.ts @@ -1,33 +1,33 @@ import { - Consumes, - Debuffs, - EquipmentSpec, Explosive, Faction, - Flask, - Food, - Glyphs, - IndividualBuffs, - PartyBuffs, - Potions, - RaidBuffs, - RaidTarget, Spec, - TristateEffect + Consumes, + Debuffs, + EquipmentSpec, Explosive, Faction, + Flask, + Food, + Glyphs, + IndividualBuffs, + PartyBuffs, + Potions, + RaidBuffs, + RaidTarget, Spec, + TristateEffect } from '../core/proto/common.js'; -import {SavedTalents} from '../core/proto/ui.js'; +import { SavedTalents } from '../core/proto/ui.js'; import { - BalanceDruid_Options as BalanceDruidOptions, - BalanceDruid_Rotation as BalanceDruidRotation, - BalanceDruid_Rotation_IsUsage, - BalanceDruid_Rotation_MfUsage, - BalanceDruid_Rotation_Type as RotationType, - BalanceDruid_Rotation_WrathUsage, - DruidMajorGlyph, - DruidMinorGlyph, + BalanceDruid_Options as BalanceDruidOptions, + BalanceDruid_Rotation as BalanceDruidRotation, + BalanceDruid_Rotation_IsUsage, + BalanceDruid_Rotation_MfUsage, + BalanceDruid_Rotation_Type as RotationType, + BalanceDruid_Rotation_WrathUsage, + DruidMajorGlyph, + DruidMinorGlyph, } from '../core/proto/druid.js'; import * as Tooltips from '../core/constants/tooltips.js'; -import {NO_TARGET} from "../core/proto_utils/utils"; -import {Player} from "../core/player"; +import { NO_TARGET } from "../core/proto_utils/utils"; +import { Player } from "../core/player"; // Preset options for this spec. // Eventually we will import these values for the raid sim too, so its good to @@ -36,122 +36,122 @@ import {Player} from "../core/player"; // Default talents. Uses the wowhead calculator format, make the talents on // https://wowhead.com/wotlk/talent-calc and copy the numbers in the url. export const Phase1Talents = { - name: 'Phase 1', - data: SavedTalents.create({ - talentsString: '5032003115331303213305311231--205003012', - glyphs: Glyphs.create({ - major1: DruidMajorGlyph.GlyphOfFocus, - major2: DruidMajorGlyph.GlyphOfInsectSwarm, - major3: DruidMajorGlyph.GlyphOfStarfall, - minor1: DruidMinorGlyph.GlyphOfTyphoon, - minor2: DruidMinorGlyph.GlyphOfUnburdenedRebirth, - minor3: DruidMinorGlyph.GlyphOfTheWild, - }), - }), + name: 'Phase 1', + data: SavedTalents.create({ + talentsString: '5032003115331303213305311231--205003012', + glyphs: Glyphs.create({ + major1: DruidMajorGlyph.GlyphOfFocus, + major2: DruidMajorGlyph.GlyphOfInsectSwarm, + major3: DruidMajorGlyph.GlyphOfStarfall, + minor1: DruidMinorGlyph.GlyphOfTyphoon, + minor2: DruidMinorGlyph.GlyphOfUnburdenedRebirth, + minor3: DruidMinorGlyph.GlyphOfTheWild, + }), + }), }; export const Phase2Talents = { - name: 'Phase 2', - data: SavedTalents.create({ - talentsString: '5012203115331303213305311231--205003012', - glyphs: Glyphs.create({ - major1: DruidMajorGlyph.GlyphOfStarfire, - major2: DruidMajorGlyph.GlyphOfInsectSwarm, - major3: DruidMajorGlyph.GlyphOfStarfall, - minor1: DruidMinorGlyph.GlyphOfTyphoon, - minor2: DruidMinorGlyph.GlyphOfUnburdenedRebirth, - minor3: DruidMinorGlyph.GlyphOfTheWild, - }), - }), + name: 'Phase 2', + data: SavedTalents.create({ + talentsString: '5012203115331303213305311231--205003012', + glyphs: Glyphs.create({ + major1: DruidMajorGlyph.GlyphOfStarfire, + major2: DruidMajorGlyph.GlyphOfInsectSwarm, + major3: DruidMajorGlyph.GlyphOfStarfall, + minor1: DruidMinorGlyph.GlyphOfTyphoon, + minor2: DruidMinorGlyph.GlyphOfUnburdenedRebirth, + minor3: DruidMinorGlyph.GlyphOfTheWild, + }), + }), }; export const Phase3Talents = { - name: 'Phase 3', - data: SavedTalents.create({ - talentsString: '5102233115331303213305311031--205003002', - glyphs: Glyphs.create({ - major1: DruidMajorGlyph.GlyphOfStarfire, - major2: DruidMajorGlyph.GlyphOfMoonfire, - major3: DruidMajorGlyph.GlyphOfStarfall, - minor1: DruidMinorGlyph.GlyphOfTyphoon, - minor2: DruidMinorGlyph.GlyphOfUnburdenedRebirth, - minor3: DruidMinorGlyph.GlyphOfTheWild, - }), - }), + name: 'Phase 3', + data: SavedTalents.create({ + talentsString: '5102233115331303213305311031--205003002', + glyphs: Glyphs.create({ + major1: DruidMajorGlyph.GlyphOfStarfire, + major2: DruidMajorGlyph.GlyphOfMoonfire, + major3: DruidMajorGlyph.GlyphOfStarfall, + minor1: DruidMinorGlyph.GlyphOfTyphoon, + minor2: DruidMinorGlyph.GlyphOfUnburdenedRebirth, + minor3: DruidMinorGlyph.GlyphOfTheWild, + }), + }), }; export const DefaultRotation = BalanceDruidRotation.create({ - type: RotationType.Default, - maintainFaerieFire: true, - useSmartCooldowns: true, - mfUsage: BalanceDruid_Rotation_MfUsage.BeforeLunar, - isUsage: BalanceDruid_Rotation_IsUsage.MaximizeIs, - wrathUsage: BalanceDruid_Rotation_WrathUsage.RegularWrath, - useStarfire: true, - useBattleRes: false, - playerLatency: 200, + type: RotationType.Default, + maintainFaerieFire: true, + useSmartCooldowns: true, + mfUsage: BalanceDruid_Rotation_MfUsage.BeforeLunar, + isUsage: BalanceDruid_Rotation_IsUsage.MaximizeIs, + wrathUsage: BalanceDruid_Rotation_WrathUsage.RegularWrath, + useStarfire: true, + useBattleRes: false, + playerLatency: 200, }); export const DefaultOptions = BalanceDruidOptions.create({ - innervateTarget: RaidTarget.create({ - targetIndex: NO_TARGET, - }), + innervateTarget: RaidTarget.create({ + targetIndex: NO_TARGET, + }), }); export const DefaultConsumes = Consumes.create({ - defaultPotion: Potions.PotionOfSpeed, - flask: Flask.FlaskOfTheFrostWyrm, - food: Food.FoodFishFeast, - prepopPotion: Potions.PotionOfWildMagic, - fillerExplosive: Explosive.ExplosiveSaroniteBomb, + defaultPotion: Potions.PotionOfSpeed, + flask: Flask.FlaskOfTheFrostWyrm, + food: Food.FoodFishFeast, + prepopPotion: Potions.PotionOfWildMagic, + fillerExplosive: Explosive.ExplosiveSaroniteBomb, }); export const DefaultRaidBuffs = RaidBuffs.create({ - arcaneBrilliance: true, - bloodlust: true, - divineSpirit: true, - giftOfTheWild: TristateEffect.TristateEffectImproved, - icyTalons: true, - moonkinAura: TristateEffect.TristateEffectImproved, - leaderOfThePack: TristateEffect.TristateEffectImproved, - powerWordFortitude: TristateEffect.TristateEffectImproved, - sanctifiedRetribution: true, - strengthOfEarthTotem: TristateEffect.TristateEffectImproved, - trueshotAura: true, - wrathOfAirTotem: true, - demonicPact: 500, + arcaneBrilliance: true, + bloodlust: true, + divineSpirit: true, + giftOfTheWild: TristateEffect.TristateEffectImproved, + icyTalons: true, + moonkinAura: TristateEffect.TristateEffectImproved, + leaderOfThePack: TristateEffect.TristateEffectImproved, + powerWordFortitude: TristateEffect.TristateEffectImproved, + sanctifiedRetribution: true, + strengthOfEarthTotem: TristateEffect.TristateEffectImproved, + trueshotAura: true, + wrathOfAirTotem: true, + demonicPact: 500, }); export const DefaultIndividualBuffs = IndividualBuffs.create({ - blessingOfKings: true, - blessingOfMight: TristateEffect.TristateEffectImproved, - blessingOfWisdom: TristateEffect.TristateEffectImproved, - vampiricTouch: true, + blessingOfKings: true, + blessingOfMight: TristateEffect.TristateEffectImproved, + blessingOfWisdom: TristateEffect.TristateEffectImproved, + vampiricTouch: true, }); export const DefaultPartyBuffs = PartyBuffs.create({ - heroicPresence: false, + heroicPresence: false, }); export const DefaultDebuffs = Debuffs.create({ - bloodFrenzy: true, - ebonPlaguebringer: true, - faerieFire: TristateEffect.TristateEffectImproved, - heartOfTheCrusader: true, - judgementOfWisdom: true, - shadowMastery: true, - sunderArmor: true, - totemOfWrath: true, + bloodFrenzy: true, + ebonPlaguebringer: true, + faerieFire: TristateEffect.TristateEffectImproved, + heartOfTheCrusader: true, + judgementOfWisdom: true, + shadowMastery: true, + sunderArmor: true, + totemOfWrath: true, }); export const OtherDefaults = { - distanceFromTarget: 18, + distanceFromTarget: 18, }; export const P2_PRESET = { - name: 'P2 Preset', - tooltip: Tooltips.BASIC_BIS_DISCLAIMER, - gear: EquipmentSpec.fromJsonString(` { + name: 'P2 Preset', + tooltip: Tooltips.BASIC_BIS_DISCLAIMER, + gear: EquipmentSpec.fromJsonString(` { "items": [ { "id": 45497, @@ -267,9 +267,9 @@ export const P2_PRESET = { }; export const P1_PRESET = { - name: 'P1 Preset', - tooltip: Tooltips.BASIC_BIS_DISCLAIMER, - gear: EquipmentSpec.fromJsonString(`{"items": [ + name: 'P1 Preset', + tooltip: Tooltips.BASIC_BIS_DISCLAIMER, + gear: EquipmentSpec.fromJsonString(`{"items": [ { "id": 40467, "enchant": 3820, @@ -363,9 +363,9 @@ export const P1_PRESET = { }; export const PRE_RAID_PRESET = { - name: 'Pre-raid Preset', - tooltip: Tooltips.BASIC_BIS_DISCLAIMER, - gear: EquipmentSpec.fromJsonString(`{ "items": [ + name: 'Pre-raid Preset', + tooltip: Tooltips.BASIC_BIS_DISCLAIMER, + gear: EquipmentSpec.fromJsonString(`{ "items": [ { "id": 42554, "enchant": 3820, @@ -459,10 +459,10 @@ export const PRE_RAID_PRESET = { }; export const P3_PRESET_HORDE = { - name: 'P3 Preset Horde', - enableWhen: (player: Player) => player.getFaction() == Faction.Horde, - tooltip: Tooltips.BASIC_BIS_DISCLAIMER, - gear: EquipmentSpec.fromJsonString(`{"items": [ + name: 'P3 Preset Horde', + enableWhen: (player: Player) => player.getFaction() == Faction.Horde, + tooltip: Tooltips.BASIC_BIS_DISCLAIMER, + gear: EquipmentSpec.fromJsonString(`{"items": [ { "id": 48174, "enchant": 3820, @@ -573,10 +573,10 @@ export const P3_PRESET_HORDE = { }; export const P3_PRESET_ALLI = { - name: 'P3 Preset Alliance', - enableWhen: (player: Player) => player.getFaction() == Faction.Alliance, - tooltip: Tooltips.BASIC_BIS_DISCLAIMER, - gear: EquipmentSpec.fromJsonString(`{"items": [ + name: 'P3 Preset Alliance', + enableWhen: (player: Player) => player.getFaction() == Faction.Alliance, + tooltip: Tooltips.BASIC_BIS_DISCLAIMER, + gear: EquipmentSpec.fromJsonString(`{"items": [ { "id": 48171, "enchant": 3820, diff --git a/ui/core/components/base_modal.ts b/ui/core/components/base_modal.ts index 13d5cc0b66..daa4711790 100644 --- a/ui/core/components/base_modal.ts +++ b/ui/core/components/base_modal.ts @@ -40,7 +40,7 @@ export class BaseModal extends Component { constructor(parent: HTMLElement, cssClass: string, config: BaseModalConfig = {}) { super(parent, 'modal'); - this.modalConfig = {...DEFAULT_CONFIG, ...config}; + this.modalConfig = { ...DEFAULT_CONFIG, ...config }; const modalSizeKlass = this.modalConfig.size && this.modalConfig.size != 'md' ? `modal-${this.modalConfig.size}` : ''; @@ -83,7 +83,7 @@ export class BaseModal extends Component { this.modal = new Modal(this.rootElem); this.open(); - + this.rootElem.addEventListener('hidden.bs.modal', (event) => { this.rootElem.remove(); }) diff --git a/ui/core/components/character_stats.ts b/ui/core/components/character_stats.ts index b4e06c3e30..b8f828d8f0 100644 --- a/ui/core/components/character_stats.ts +++ b/ui/core/components/character_stats.ts @@ -94,7 +94,7 @@ export class CharacterStats extends Component { this.valueElems[idx].prepend(valueElem); let bonusStatValue = bonusStats.getStat(stat); - + if (bonusStatValue == 0) { valueElem.classList.remove('text-success', 'text-danger'); valueElem.classList.add('text-white'); @@ -187,10 +187,10 @@ export class CharacterStats extends Component { displayStr += ` (${((rawValue / Mechanics.BLOCK_RATING_PER_BLOCK_CHANCE) + (Mechanics.MISS_DODGE_PARRY_BLOCK_CRIT_CHANCE_PER_DEFENSE * Math.floor(stats.getStat(Stat.StatDefense) / Mechanics.DEFENSE_RATING_PER_DEFENSE)) + 5.00).toFixed(2)}%)`; } else if (stat == Stat.StatDodge) { //displayStr += ` (${(rawValue / Mechanics.DODGE_RATING_PER_DODGE_CHANCE).toFixed(2)}%)`; - displayStr += ` (${(stats.getPseudoStat(PseudoStat.PseudoStatDodge)*100).toFixed(2)}%)`; + displayStr += ` (${(stats.getPseudoStat(PseudoStat.PseudoStatDodge) * 100).toFixed(2)}%)`; } else if (stat == Stat.StatParry) { //displayStr += ` (${(rawValue / Mechanics.PARRY_RATING_PER_PARRY_CHANCE).toFixed(2)}%)`; - displayStr += ` (${(stats.getPseudoStat(PseudoStat.PseudoStatParry)*100).toFixed(2)}%)`; + displayStr += ` (${(stats.getPseudoStat(PseudoStat.PseudoStatParry) * 100).toFixed(2)}%)`; } else if (stat == Stat.StatResilience) { displayStr += ` (${(rawValue / Mechanics.RESILIENCE_RATING_PER_CRIT_REDUCTION_CHANCE).toFixed(2)}%)`; } diff --git a/ui/core/components/close_button.ts b/ui/core/components/close_button.ts index 9e6d2cbbc4..37ae794ff1 100644 --- a/ui/core/components/close_button.ts +++ b/ui/core/components/close_button.ts @@ -13,7 +13,7 @@ export class CloseButton extends Component { constructor(parent: HTMLElement, onClick: () => void, config: CloseButtonConfig = {}) { super(parent, 'close-button', document.createElement('a')); - this.config = {...DEFAULT_CONFIG, ...config}; + this.config = { ...DEFAULT_CONFIG, ...config }; if (this.config.fixed) this.rootElem.classList.add('position-fixed'); diff --git a/ui/core/components/content_block.ts b/ui/core/components/content_block.ts index ca01d76037..48f3635075 100644 --- a/ui/core/components/content_block.ts +++ b/ui/core/components/content_block.ts @@ -3,46 +3,46 @@ import { title } from 'process'; import { Component } from './component.js'; export interface ContentBlockHeaderConfig { - title: string, - extraCssClasses?: Array, - titleTag?: string, - tooltip?: string, + title: string, + extraCssClasses?: Array, + titleTag?: string, + tooltip?: string, } export interface ContentBlockConfig { bodyClasses?: Array, - extraCssClasses?: Array, - rootElem?: HTMLElement, - header?: ContentBlockHeaderConfig, + extraCssClasses?: Array, + rootElem?: HTMLElement, + header?: ContentBlockHeaderConfig, } export class ContentBlock extends Component { - readonly headerElement: HTMLElement|null; - readonly bodyElement: HTMLElement; + readonly headerElement: HTMLElement | null; + readonly bodyElement: HTMLElement; - readonly config: ContentBlockConfig; + readonly config: ContentBlockConfig; constructor(parent: HTMLElement, cssClass: string, config: ContentBlockConfig) { super(parent, 'content-block', config.rootElem); - this.config = config; + this.config = config; this.rootElem.classList.add(cssClass); if (config.extraCssClasses) { this.rootElem.classList.add(...config.extraCssClasses); - } + } - this.headerElement = this.buildHeader(); - this.bodyElement = this.buildBody(); - config.bodyClasses?.forEach((cl) => { - this.bodyElement.classList.add(cl); - }) + this.headerElement = this.buildHeader(); + this.bodyElement = this.buildBody(); + config.bodyClasses?.forEach((cl) => { + this.bodyElement.classList.add(cl); + }) } - private buildHeader(): HTMLElement|null { - if (this.config.header && Object.keys(this.config.header).length) { - let titleTag = this.config.header.titleTag || 'h6'; - let headerFragment = document.createElement('fragment'); - headerFragment.innerHTML = ` + private buildHeader(): HTMLElement | null { + if (this.config.header && Object.keys(this.config.header).length) { + let titleTag = this.config.header.titleTag || 'h6'; + let headerFragment = document.createElement('fragment'); + headerFragment.innerHTML = `
<${titleTag} class="content-block-title" @@ -53,29 +53,29 @@ export class ContentBlock extends Component {
`; - let header = headerFragment.children[0] as HTMLElement; - - if (this.config.header.extraCssClasses) { - header.classList.add(...this.config.header.extraCssClasses); - } + let header = headerFragment.children[0] as HTMLElement; - if (this.config.header.tooltip) - Tooltip.getOrCreateInstance(header.querySelector('.content-block-title') as HTMLElement); + if (this.config.header.extraCssClasses) { + header.classList.add(...this.config.header.extraCssClasses); + } - this.rootElem.appendChild(header); + if (this.config.header.tooltip) + Tooltip.getOrCreateInstance(header.querySelector('.content-block-title') as HTMLElement); - return header; - } else { - return null; - } - } + this.rootElem.appendChild(header); - private buildBody(): HTMLElement { - let bodyElem = document.createElement('div'); - bodyElem.classList.add('content-block-body'); + return header; + } else { + return null; + } + } + + private buildBody(): HTMLElement { + let bodyElem = document.createElement('div'); + bodyElem.classList.add('content-block-body'); - this.rootElem.appendChild(bodyElem); + this.rootElem.appendChild(bodyElem); - return bodyElem; - } + return bodyElem; + } } diff --git a/ui/core/components/detailed_results.ts b/ui/core/components/detailed_results.ts index 5021897555..798184b04f 100644 --- a/ui/core/components/detailed_results.ts +++ b/ui/core/components/detailed_results.ts @@ -265,7 +265,7 @@ export abstract class DetailedResults extends Component { }); } - abstract postMessage(update: DetailedResultsUpdate) : Promise; + abstract postMessage(update: DetailedResultsUpdate): Promise; protected async setSimRunData(simRunData: SimRunData) { this.latestRun = simRunData; @@ -348,7 +348,7 @@ export class WindowedDetailedResults extends DetailedResults { constructor(parent: HTMLElement) { super(parent, null, new URLSearchParams(window.location.search).get("cssScheme") ?? "") - window.addEventListener('message', + window.addEventListener('message', async (event) => await this.handleMessage(DetailedResultsUpdate.fromJson(event.data)) ); } @@ -360,7 +360,7 @@ export class WindowedDetailedResults extends DetailedResults { export class EmbeddedDetailedResults extends DetailedResults { private tabWindow: Window | null = null; - + constructor(parent: HTMLElement, simUI: SimUI, simResultsManager: RaidSimResultsManager) { super(parent, simUI, simUI.cssScheme) diff --git a/ui/core/components/detailed_results/dps_histogram.ts b/ui/core/components/detailed_results/dps_histogram.ts index 09691fe5c2..b8cec307c7 100644 --- a/ui/core/components/detailed_results/dps_histogram.ts +++ b/ui/core/components/detailed_results/dps_histogram.ts @@ -36,7 +36,7 @@ export class DpsHistogram extends ResultComponent { const ctx = chartCanvas.getContext('2d'); this.rootElem.appendChild(chartCanvas); - + const chart = new Chart(ctx, { type: 'bar', data: { diff --git a/ui/core/components/dropdown_picker.ts b/ui/core/components/dropdown_picker.ts index 41edcd4e6e..51e891f76c 100644 --- a/ui/core/components/dropdown_picker.ts +++ b/ui/core/components/dropdown_picker.ts @@ -6,177 +6,177 @@ import { Input, InputConfig } from './input.js'; export interface DropdownValueConfig { value: T, - submenu?: Array, - headerText?: string, - tooltip?: string, - extraCssClasses?: Array, + submenu?: Array, + headerText?: string, + tooltip?: string, + extraCssClasses?: Array, } export interface DropdownPickerConfig extends InputConfig { values: Array>; - equals: (a: T|undefined, b: T|undefined) => boolean, - setOptionContent: (button: HTMLButtonElement, valueConfig: DropdownValueConfig) => void, - createMissingValue?: (val: T) => Promise>, - defaultLabel: string, + equals: (a: T | undefined, b: T | undefined) => boolean, + setOptionContent: (button: HTMLButtonElement, valueConfig: DropdownValueConfig) => void, + createMissingValue?: (val: T) => Promise>, + defaultLabel: string, } interface DropdownSubmenu { - path: Array, + path: Array, - listElem: HTMLUListElement, + listElem: HTMLUListElement, } /** UI Input that uses a dropdown menu. */ export class DropdownPicker extends Input { - private readonly config: DropdownPickerConfig; - private valueConfigs: Array>; + private readonly config: DropdownPickerConfig; + private valueConfigs: Array>; private readonly buttonElem: HTMLButtonElement; private readonly listElem: HTMLUListElement; - private currentSelection: DropdownValueConfig|null; - private submenus: Array; + private currentSelection: DropdownValueConfig | null; + private submenus: Array; constructor(parent: HTMLElement, modObject: ModObject, config: DropdownPickerConfig) { super(parent, 'dropdown-picker-root', modObject, config); - this.config = config; - this.valueConfigs = this.config.values.filter(vc => !vc.headerText); - this.currentSelection = null; - this.submenus = []; + this.config = config; + this.valueConfigs = this.config.values.filter(vc => !vc.headerText); + this.currentSelection = null; + this.submenus = []; - this.rootElem.classList.add('dropdown'); + this.rootElem.classList.add('dropdown'); this.buttonElem = document.createElement('button'); this.buttonElem.classList.add('dropdown-picker-button', 'btn', 'dropdown-toggle', 'open-on-click'); - this.buttonElem.setAttribute('data-bs-toggle', 'dropdown'); - this.buttonElem.setAttribute('aria-expanded', 'false'); - this.buttonElem.setAttribute('role', 'button'); - this.buttonElem.textContent = config.defaultLabel; + this.buttonElem.setAttribute('data-bs-toggle', 'dropdown'); + this.buttonElem.setAttribute('aria-expanded', 'false'); + this.buttonElem.setAttribute('role', 'button'); + this.buttonElem.textContent = config.defaultLabel; this.rootElem.appendChild(this.buttonElem); this.listElem = document.createElement('ul'); this.listElem.classList.add('dropdown-picker-list', 'dropdown-menu'); this.rootElem.appendChild(this.listElem); - this.buildDropdown(this.valueConfigs); + this.buildDropdown(this.valueConfigs); this.init(); } - setOptions(newValueConfigs: Array>) { - this.buildDropdown(newValueConfigs); - this.valueConfigs = newValueConfigs.filter(vc => !vc.headerText); - this.setInputValue(this.getSourceValue()); - } + setOptions(newValueConfigs: Array>) { + this.buildDropdown(newValueConfigs); + this.valueConfigs = newValueConfigs.filter(vc => !vc.headerText); + this.setInputValue(this.getSourceValue()); + } - private buildDropdown(valueConfigs: Array>) { - this.listElem.innerHTML = ''; - this.submenus = []; + private buildDropdown(valueConfigs: Array>) { + this.listElem.innerHTML = ''; + this.submenus = []; valueConfigs.forEach(valueConfig => { - const itemElem = document.createElement('li'); - if (valueConfig.extraCssClasses) { - itemElem.classList.add(...valueConfig.extraCssClasses); - } - if (valueConfig.headerText) { - itemElem.classList.add('dropdown-picker-header'); - - const headerElem = document.createElement('h6'); - headerElem.classList.add('dropdown-header'); - headerElem.textContent = valueConfig.headerText; - itemElem.appendChild(headerElem); - } else { - itemElem.classList.add('dropdown-picker-item'); - - const buttonElem = document.createElement('button'); - buttonElem.classList.add('dropdown-item'); - buttonElem.type = 'button'; - this.config.setOptionContent(buttonElem, valueConfig); - itemElem.appendChild(buttonElem); - - if (valueConfig.tooltip) { - buttonElem.setAttribute('data-bs-toggle', 'tooltip'); - buttonElem.setAttribute('data-bs-html', 'true'); - buttonElem.setAttribute('data-bs-title', valueConfig.tooltip); - const tooltip = Tooltip.getOrCreateInstance(buttonElem, { - animation: false, - placement: 'right', - fallbackPlacements: ['left', 'bottom'], - offset: [0, 10], - customClass: 'dropdown-tooltip', - }); - } - - buttonElem.addEventListener('click', event => { - this.updateValue(valueConfig); - this.inputChanged(TypedEvent.nextEventID()); - }); - } - - if (valueConfig.submenu && valueConfig.submenu.length > 0) { - this.createSubmenu(valueConfig.submenu); - } - const submenu = this.getSubmenu(valueConfig.submenu); - if (submenu) { - submenu.listElem.appendChild(itemElem); - } else { - this.listElem.appendChild(itemElem); - } + const itemElem = document.createElement('li'); + if (valueConfig.extraCssClasses) { + itemElem.classList.add(...valueConfig.extraCssClasses); + } + if (valueConfig.headerText) { + itemElem.classList.add('dropdown-picker-header'); + + const headerElem = document.createElement('h6'); + headerElem.classList.add('dropdown-header'); + headerElem.textContent = valueConfig.headerText; + itemElem.appendChild(headerElem); + } else { + itemElem.classList.add('dropdown-picker-item'); + + const buttonElem = document.createElement('button'); + buttonElem.classList.add('dropdown-item'); + buttonElem.type = 'button'; + this.config.setOptionContent(buttonElem, valueConfig); + itemElem.appendChild(buttonElem); + + if (valueConfig.tooltip) { + buttonElem.setAttribute('data-bs-toggle', 'tooltip'); + buttonElem.setAttribute('data-bs-html', 'true'); + buttonElem.setAttribute('data-bs-title', valueConfig.tooltip); + const tooltip = Tooltip.getOrCreateInstance(buttonElem, { + animation: false, + placement: 'right', + fallbackPlacements: ['left', 'bottom'], + offset: [0, 10], + customClass: 'dropdown-tooltip', + }); + } + + buttonElem.addEventListener('click', event => { + this.updateValue(valueConfig); + this.inputChanged(TypedEvent.nextEventID()); + }); + } + + if (valueConfig.submenu && valueConfig.submenu.length > 0) { + this.createSubmenu(valueConfig.submenu); + } + const submenu = this.getSubmenu(valueConfig.submenu); + if (submenu) { + submenu.listElem.appendChild(itemElem); + } else { + this.listElem.appendChild(itemElem); + } }); - } - - private getSubmenu(path: Array|undefined): DropdownSubmenu|null { - if (!path) { - return null; - } - return this.submenus.find(submenu => DropdownPicker.equalPaths(submenu.path, path)) || null; - } - - private createSubmenu(path: Array): DropdownSubmenu { - const submenu = this.getSubmenu(path); - if (submenu) { - return submenu; - } - - let parent: DropdownSubmenu|null = null; - if (path.length > 1) { - parent = this.createSubmenu(path.slice(0, path.length - 1)); - } - - const itemElem = document.createElement('li'); - itemElem.classList.add('dropdown-picker-item'); - - const containerElem = document.createElement('div'); - containerElem.classList.add('dropend'); - itemElem.appendChild(containerElem); - - const titleElem = document.createElement('button'); - titleElem.classList.add('dropdown-item'); - titleElem.setAttribute('data-bs-toggle', 'dropdown'); - titleElem.setAttribute('role', 'button'); - titleElem.setAttribute('aria-expanded', 'false'); - titleElem.textContent = path[path.length - 1] + ' \u00bb'; - containerElem.appendChild(titleElem); + } + + private getSubmenu(path: Array | undefined): DropdownSubmenu | null { + if (!path) { + return null; + } + return this.submenus.find(submenu => DropdownPicker.equalPaths(submenu.path, path)) || null; + } + + private createSubmenu(path: Array): DropdownSubmenu { + const submenu = this.getSubmenu(path); + if (submenu) { + return submenu; + } + + let parent: DropdownSubmenu | null = null; + if (path.length > 1) { + parent = this.createSubmenu(path.slice(0, path.length - 1)); + } + + const itemElem = document.createElement('li'); + itemElem.classList.add('dropdown-picker-item'); + + const containerElem = document.createElement('div'); + containerElem.classList.add('dropend'); + itemElem.appendChild(containerElem); + + const titleElem = document.createElement('button'); + titleElem.classList.add('dropdown-item'); + titleElem.setAttribute('data-bs-toggle', 'dropdown'); + titleElem.setAttribute('role', 'button'); + titleElem.setAttribute('aria-expanded', 'false'); + titleElem.textContent = path[path.length - 1] + ' \u00bb'; + containerElem.appendChild(titleElem); const listElem = document.createElement('ul'); listElem.classList.add('dropdown-submenu', 'dropdown-menu'); containerElem.appendChild(listElem); - if (parent) { - parent.listElem.appendChild(itemElem); - } else { - this.listElem.appendChild(itemElem); - } - - const newSubmenu = { - path: path, - listElem: listElem, - }; - this.submenus.push(newSubmenu); - return newSubmenu; - } + if (parent) { + parent.listElem.appendChild(itemElem); + } else { + this.listElem.appendChild(itemElem); + } + + const newSubmenu = { + path: path, + listElem: listElem, + }; + this.submenus.push(newSubmenu); + return newSubmenu; + } - private static equalPaths(a: Array|null|undefined, b: Array|null|undefined): boolean { - return (a?.length || 0) == (b?.length || 0) && (a || []).every((aVal, i) => aVal == b![i]); - } + private static equalPaths(a: Array | null | undefined, b: Array | null | undefined): boolean { + return (a?.length || 0) == (b?.length || 0) && (a || []).every((aVal, i) => aVal == b![i]); + } getInputElem(): HTMLElement { return this.listElem; @@ -187,33 +187,33 @@ export class DropdownPicker extends Input { } setInputValue(newValue: T) { - const newSelection = this.valueConfigs.find(v => this.config.equals(v.value, newValue))!; - if (newSelection) { - this.updateValue(newSelection); - } else if (newValue == null) { - this.updateValue(null); - } else if (this.config.createMissingValue) { - this.config.createMissingValue(newValue).then(newSelection => this.updateValue(newSelection)); - } else { - this.updateValue(null); - } + const newSelection = this.valueConfigs.find(v => this.config.equals(v.value, newValue))!; + if (newSelection) { + this.updateValue(newSelection); + } else if (newValue == null) { + this.updateValue(null); + } else if (this.config.createMissingValue) { + this.config.createMissingValue(newValue).then(newSelection => this.updateValue(newSelection)); + } else { + this.updateValue(null); + } } - private updateValue(newValue: DropdownValueConfig|null) { - this.currentSelection = newValue; - - // Update button - if (newValue) { - this.buttonElem.innerHTML = ''; - this.config.setOptionContent(this.buttonElem, newValue); - } else { - this.buttonElem.textContent = this.config.defaultLabel; - } - } + private updateValue(newValue: DropdownValueConfig | null) { + this.currentSelection = newValue; + + // Update button + if (newValue) { + this.buttonElem.innerHTML = ''; + this.config.setOptionContent(this.buttonElem, newValue); + } else { + this.buttonElem.textContent = this.config.defaultLabel; + } + } } export interface TextDropdownValueConfig extends DropdownValueConfig { - label: string, + label: string, } export interface TextDropdownPickerConfig extends Omit, 'values' | 'setOptionContent'> { @@ -224,9 +224,9 @@ export class TextDropdownPicker extends DropdownPicker) { super(parent, modObject, { ...config, - setOptionContent: (button: HTMLButtonElement, valueConfig: DropdownValueConfig) => { - button.textContent = (valueConfig as TextDropdownValueConfig).label; - } + setOptionContent: (button: HTMLButtonElement, valueConfig: DropdownValueConfig) => { + button.textContent = (valueConfig as TextDropdownValueConfig).label; + } }); } } \ No newline at end of file diff --git a/ui/core/components/encounter_picker.ts b/ui/core/components/encounter_picker.ts index f1db436079..7285fd9df6 100644 --- a/ui/core/components/encounter_picker.ts +++ b/ui/core/components/encounter_picker.ts @@ -6,7 +6,7 @@ import { Target as TargetProto, TargetInput, Target, - } from '../proto/common.js'; +} from '../proto/common.js'; import { Encounter } from '../encounter.js'; import { Raid } from '../raid.js'; import { EventID, TypedEvent } from '../typed_event.js'; @@ -469,7 +469,7 @@ class TargetPicker extends Input { this.init(); } - getInputElem(): HTMLElement|null { + getInputElem(): HTMLElement | null { return null; } getInputValue(): TargetProto { @@ -519,8 +519,8 @@ class TargetInputPicker extends Input { private readonly targetIndex: number; private readonly targetInputIndex: number; - private boolPicker: Input|null; - private numberPicker: Input|null; + private boolPicker: Input | null; + private numberPicker: Input | null; private getTargetInput(): TargetInput { return this.encounter.targets[this.targetIndex].targetInputs[this.targetInputIndex] || TargetInput.create(); @@ -537,7 +537,7 @@ class TargetInputPicker extends Input { this.init(); } - getInputElem(): HTMLElement|null { + getInputElem(): HTMLElement | null { return this.rootElem; } getInputValue(): TargetInput { @@ -663,7 +663,7 @@ function makeTargetInputsPicker(parent: HTMLElement, encounter: Encounter, targe }); } -function equalTargetsIgnoreInputs(target1: TargetProto|undefined, target2: TargetProto|undefined): boolean { +function equalTargetsIgnoreInputs(target1: TargetProto | undefined, target2: TargetProto | undefined): boolean { if ((target1 == null) != (target2 == null)) { return false; } diff --git a/ui/core/components/exporters.ts b/ui/core/components/exporters.ts index 31aae8aed5..ceac14e0e3 100644 --- a/ui/core/components/exporters.ts +++ b/ui/core/components/exporters.ts @@ -20,7 +20,7 @@ export abstract class Exporter extends BaseModal { private readonly textElem: HTMLElement; constructor(parent: HTMLElement, simUI: SimUI, title: string, allowDownload: boolean) { - super(parent, 'exporter', {title: title, footer: true}); + super(parent, 'exporter', { title: title, footer: true }); this.body.innerHTML = ` @@ -159,8 +159,8 @@ export class IndividualWowheadGearPlannerExporter extends glyphStr += d[glyphPosition]; glyphStr += d[(spellId >> 15) & 0b00011111]; glyphStr += d[(spellId >> 10) & 0b00011111]; - glyphStr += d[(spellId >> 5) & 0b00011111]; - glyphStr += d[(spellId >> 0) & 0b00011111]; + glyphStr += d[(spellId >> 5) & 0b00011111]; + glyphStr += d[(spellId >> 0) & 0b00011111]; }; addGlyph(glyphs.major1, 0); addGlyph(glyphs.major2, 1); @@ -187,33 +187,33 @@ export class IndividualWowheadGearPlannerExporter extends const gear = player.getGear(); const isBlacksmithing = player.isBlacksmithing(); gear.getItemSlots() - .sort((slot1, slot2) => IndividualWowheadGearPlannerImporter.slotIDs[slot1] - IndividualWowheadGearPlannerImporter.slotIDs[slot2]) - .forEach(itemSlot => { - const item = gear.getEquippedItem(itemSlot); - if (!item) { - return; - } - - let slotId = IndividualWowheadGearPlannerImporter.slotIDs[itemSlot]; - if (item.enchant) { - slotId = slotId | 0b10000000; - } - bytes.push(slotId); - bytes.push(item.curGems(isBlacksmithing).length << 5); - bytes = bytes.concat(to2Bytes(item.item.id)); + .sort((slot1, slot2) => IndividualWowheadGearPlannerImporter.slotIDs[slot1] - IndividualWowheadGearPlannerImporter.slotIDs[slot2]) + .forEach(itemSlot => { + const item = gear.getEquippedItem(itemSlot); + if (!item) { + return; + } - if (item.enchant) { - bytes.push(0); - bytes = bytes.concat(to2Bytes(item.enchant.spellId)); - } + let slotId = IndividualWowheadGearPlannerImporter.slotIDs[itemSlot]; + if (item.enchant) { + slotId = slotId | 0b10000000; + } + bytes.push(slotId); + bytes.push(item.curGems(isBlacksmithing).length << 5); + bytes = bytes.concat(to2Bytes(item.item.id)); - item.gems.slice(0, item.numSockets(isBlacksmithing)).forEach((gem, i) => { - if (gem) { - bytes.push(i << 5); - bytes = bytes.concat(to2Bytes(gem.id)); + if (item.enchant) { + bytes.push(0); + bytes = bytes.concat(to2Bytes(item.enchant.spellId)); } + + item.gems.slice(0, item.numSockets(isBlacksmithing)).forEach((gem, i) => { + if (gem) { + bytes.push(i << 5); + bytes = bytes.concat(to2Bytes(gem.id)); + } + }); }); - }); //console.log('Hex: ' + buf2hex(new Uint8Array(bytes))); const binaryString = String.fromCharCode(...bytes); @@ -240,20 +240,20 @@ export class Individual80UEPExporter extends Exporter { const namesToWeights: Record = {}; allUnitStats - .forEach(stat => { - const statName = Individual80UEPExporter.getName(stat); - const weight = epValues.getUnitStat(stat); - if (weight == 0 || statName == '') { - return; - } + .forEach(stat => { + const statName = Individual80UEPExporter.getName(stat); + const weight = epValues.getUnitStat(stat); + if (weight == 0 || statName == '') { + return; + } - // Need to add together stats with the same name (e.g. hit/crit/haste). - if (namesToWeights[statName]) { - namesToWeights[statName] += weight; - } else { - namesToWeights[statName] = weight; - } - }); + // Need to add together stats with the same name (e.g. hit/crit/haste). + if (namesToWeights[statName]) { + namesToWeights[statName] += weight; + } else { + namesToWeights[statName] = weight; + } + }); return `https://eightyupgrades.com/ep/import?name=${encodeURIComponent(`${specNames[player.spec]} WoWSims Weights`)}` + Object.keys(namesToWeights) @@ -332,20 +332,20 @@ export class IndividualPawnEPExporter extends Exporter { const namesToWeights: Record = {}; allUnitStats - .forEach(stat => { - const statName = IndividualPawnEPExporter.getName(stat); - const weight = epValues.getUnitStat(stat); - if (weight == 0 || statName == '') { - return; - } + .forEach(stat => { + const statName = IndividualPawnEPExporter.getName(stat); + const weight = epValues.getUnitStat(stat); + if (weight == 0 || statName == '') { + return; + } - // Need to add together stats with the same name (e.g. hit/crit/haste). - if (namesToWeights[statName]) { - namesToWeights[statName] += weight; - } else { - namesToWeights[statName] = weight; - } - }); + // Need to add together stats with the same name (e.g. hit/crit/haste). + if (namesToWeights[statName]) { + namesToWeights[statName] += weight; + } else { + namesToWeights[statName] = weight; + } + }); return `( Pawn: v1: "${specNames[player.spec]} WoWSims Weights": Class=${classNames[player.getClass()]},` + Object.keys(namesToWeights) @@ -410,19 +410,19 @@ export class IndividualPawnEPExporter extends Exporter { } export class IndividualCLIExporter extends Exporter { - private readonly simUI: IndividualSimUI; - - constructor(parent: HTMLElement, simUI: IndividualSimUI) { - super(parent, simUI, "CLI Export", true); - this.simUI = simUI; - this.init(); - } - - getData(): string { - const raidSimJson: any = RaidSimRequest.toJson( - this.simUI.sim.makeRaidSimRequest(false) - ); - delete raidSimJson.raid?.parties[0]?.players[0]?.database; - return JSON.stringify(raidSimJson, null, 2); - } + private readonly simUI: IndividualSimUI; + + constructor(parent: HTMLElement, simUI: IndividualSimUI) { + super(parent, simUI, "CLI Export", true); + this.simUI = simUI; + this.init(); + } + + getData(): string { + const raidSimJson: any = RaidSimRequest.toJson( + this.simUI.sim.makeRaidSimRequest(false) + ); + delete raidSimJson.raid?.parties[0]?.players[0]?.database; + return JSON.stringify(raidSimJson, null, 2); + } } diff --git a/ui/core/components/filters_menu.ts b/ui/core/components/filters_menu.ts index e75c05c275..6e673f351e 100644 --- a/ui/core/components/filters_menu.ts +++ b/ui/core/components/filters_menu.ts @@ -38,7 +38,7 @@ const factionRestrictionsToLabels: Record = { export class FiltersMenu extends BaseModal { constructor(rootElem: HTMLElement, player: Player, slot: ItemSlot) { - super(rootElem, 'filters-menu', {size: 'md', title: 'Filters'}); + super(rootElem, 'filters-menu', { size: 'md', title: 'Filters' }); let section = this.newSection('Factions'); @@ -111,8 +111,8 @@ export class FiltersMenu extends BaseModal { const section = this.newSection('Armor Type'); section.classList.add('filters-menu-section-bool-list'); const armorTypes = (getEnumValues(ArmorType) as Array) - .filter(at => at != ArmorType.ArmorTypeUnknown) - .filter(at => at <= maxArmorType); + .filter(at => at != ArmorType.ArmorTypeUnknown) + .filter(at => at <= maxArmorType); armorTypes.forEach(armorType => { new BooleanPicker(section, player.sim, { diff --git a/ui/core/components/fire_elemental_inputs.ts b/ui/core/components/fire_elemental_inputs.ts index f103f7af27..4bbb1093cf 100644 --- a/ui/core/components/fire_elemental_inputs.ts +++ b/ui/core/components/fire_elemental_inputs.ts @@ -13,7 +13,7 @@ import { BooleanPicker } from "./boolean_picker"; export function FireElementalSection(parentElem: HTMLElement, simUI: IndividualSimUI): ContentBlock { let contentBlock = new ContentBlock(parentElem, 'fire-elemental-settings', { - header: {title: 'Fire Elemental'} + header: { title: 'Fire Elemental' } }); let fireElementalIconContainer = Input.newGroupContainer(); @@ -31,47 +31,47 @@ export function FireElementalSection(parentElem: HTMLElement, simUI: IndividualS }, changeEmitter: (player: Player) => player.rotationChangeEmitter, }, ActionId.fromSpellId(2894), "useFireElemental"); - + new IconPicker(fireElementalIconContainer, simUI.player, fireElementalBooleanIconInput); - new NumberPicker(contentBlock.bodyElement, simUI.player, { - positive: true, - label: "Bonus spell power", + new NumberPicker(contentBlock.bodyElement, simUI.player, { + positive: true, + label: "Bonus spell power", labelTooltip: "Bonus spell power to snapshot Fire Elemental with. Will prioritize dropping Fire Elemental if greater then 0", inline: true, - getValue: (player: Player) => player.getRotation().totems?.bonusSpellpower || 0, + getValue: (player: Player) => player.getRotation().totems?.bonusSpellpower || 0, setValue: (eventID: EventID, player: Player, newVal: number) => { const newRotation = player.getRotation(); - - if (newRotation.totems){ - newRotation.totems.bonusSpellpower = newVal - } + + if (newRotation.totems) { + newRotation.totems.bonusSpellpower = newVal + } player.setRotation(eventID, newRotation); }, - changedEvent: (player: Player) => player.rotationChangeEmitter, - }) + changedEvent: (player: Player) => player.rotationChangeEmitter, + }) new BooleanPicker(contentBlock.bodyElement, simUI.player, { - label: "Use Tier 10 (4pc)", + label: "Use Tier 10 (4pc)", labelTooltip: "Will use Tier 10 (4pc) to snapshot Fire Elemental.", inline: true, - getValue: (player: Player) => player.getRotation().totems?.enhTierTenBonus || false, + getValue: (player: Player) => player.getRotation().totems?.enhTierTenBonus || false, setValue: (eventID: EventID, player: Player, newVal: boolean) => { const newRotation = player.getRotation(); - - if (newRotation.totems){ - newRotation.totems.enhTierTenBonus = newVal - } + + if (newRotation.totems) { + newRotation.totems.enhTierTenBonus = newVal + } player.setRotation(eventID, newRotation); }, - changedEvent: (player: Player) => player.currentStatsEmitter, + changedEvent: (player: Player) => player.currentStatsEmitter, showWhen: (player: Player) => { const hasBonus = player.getCurrentStats().sets.includes('Frost Witch\'s Battlegear (4pc)'); return hasBonus } - }) + }) return contentBlock; diff --git a/ui/core/components/gear_picker.ts b/ui/core/components/gear_picker.ts index df0adb402d..0954d1fd81 100644 --- a/ui/core/components/gear_picker.ts +++ b/ui/core/components/gear_picker.ts @@ -497,12 +497,12 @@ export class SelectorModal extends BaseModal { // Could be 'Items' 'Enchants' or 'Gem1'-'Gem3' openTabName(name: string) { Array.from(this.tabsElem.getElementsByClassName("selector-modal-item-tab")).forEach(elem => { - if (elem.getAttribute("data-content-id") == name+"-tab") { + if (elem.getAttribute("data-content-id") == name + "-tab") { (elem as HTMLElement).click(); - } + } }); } - + openTab(idx: number) { const elems = this.tabsElem.getElementsByClassName("selector-modal-item-tab"); (elems[idx] as HTMLElement).click(); @@ -743,8 +743,8 @@ export class SelectorModal extends BaseModal { }, ) - let invokeUpdate = () => {ilist.updateSelected()} - let applyFilter = () => {ilist.applyFilters()} + let invokeUpdate = () => { ilist.updateSelected() } + let applyFilter = () => { ilist.applyFilters() } // Add event handlers gearData.changeEvent.on(invokeUpdate); @@ -1076,13 +1076,13 @@ export class ItemList { this.listItemElems.forEach(elem => elem.classList.remove('active')); onRemove(TypedEvent.nextEventID()); }); - + if (label.startsWith("Enchants")) { removeButton.textContent = 'Remove Enchant'; } else if (label.startsWith("Gem")) { removeButton.textContent = 'Remove Gem'; } - + this.updateSelected(); this.searchInput = tabContent.getElementsByClassName('selector-modal-search')[0] as HTMLInputElement; @@ -1110,15 +1110,15 @@ export class ItemList { if (simUI instanceof IndividualSimUI) { let itemSpecs = Array(); const isRangedOrTrinket = this.slot == ItemSlot.ItemSlotRanged || - this.slot == ItemSlot.ItemSlotTrinket1 || - this.slot == ItemSlot.ItemSlotTrinket2 + this.slot == ItemSlot.ItemSlotTrinket1 || + this.slot == ItemSlot.ItemSlotTrinket2 const curItem = this.equippedToItemFn(this.player.getEquippedItem(this.slot)); let curEP = 0; if (curItem != null) { curEP = this.computeEP(curItem); } - + this.listItemElems.forEach((elem, index) => { // skip items already filtered out. if (elem.classList.contains('hidden')) { @@ -1126,15 +1126,15 @@ export class ItemList { } const idata = this.itemData[index]; - if (!isRangedOrTrinket && curEP > 0 && idata.baseEP < (curEP / 2) ) { + if (!isRangedOrTrinket && curEP > 0 && idata.baseEP < (curEP / 2)) { return; // If we have EPs on current item, dont sim items with less than half the EP. } // Add any item that is either >0 EP or a trinket/ranged item. - if ( idata.baseEP > 0 || isRangedOrTrinket ) { + if (idata.baseEP > 0 || isRangedOrTrinket) { itemSpecs.push(ItemSpec.create({ id: idata.id })); } - + }); simUI.bt.addItems(itemSpecs); diff --git a/ui/core/components/icon_enum_picker.ts b/ui/core/components/icon_enum_picker.ts index e4ee8216ad..2436947304 100644 --- a/ui/core/components/icon_enum_picker.ts +++ b/ui/core/components/icon_enum_picker.ts @@ -79,7 +79,7 @@ export class IconEnumPicker extends Input { `; this.buttonElem = this.rootElem.querySelector('.icon-picker-button') as HTMLAnchorElement; - this.buttonText = this.buttonElem.querySelector('.icon-picker-label') as HTMLElement; + this.buttonText = this.buttonElem.querySelector('.icon-picker-label') as HTMLElement; const dropdownMenu = this.rootElem.querySelector('.dropdown-menu') as HTMLElement; dropdownMenu.style.gridTemplateColumns = `repeat(${this.config.numColumns}, 1fr)`; @@ -94,7 +94,7 @@ export class IconEnumPicker extends Input { optionContainer.appendChild(option); this.setImage(option, valueConfig); - if (valueConfig.text != undefined){ + if (valueConfig.text != undefined) { const optionText = document.createElement('div'); optionText.classList.add("icon-picker-label"); optionText.textContent = valueConfig.text; diff --git a/ui/core/components/importers.ts b/ui/core/components/importers.ts index 89872d97d7..a593a959c9 100644 --- a/ui/core/components/importers.ts +++ b/ui/core/components/importers.ts @@ -27,7 +27,7 @@ export abstract class Importer extends BaseModal { private readonly includeFile: boolean; constructor(parent: HTMLElement, simUI: SimUI, title: string, includeFile: boolean) { - super(parent, 'importer', {title: title, footer: true}); + super(parent, 'importer', { title: title, footer: true }); this.includeFile = includeFile; const uploadInputId = 'upload-input-' + title.toLowerCase().replaceAll(' ', '-'); @@ -288,8 +288,8 @@ export class IndividualWowheadGearPlannerImporter extends const spellId = 0 + (d.indexOf(glyphStr[cur + 0]) << 15) + (d.indexOf(glyphStr[cur + 1]) << 10) + - (d.indexOf(glyphStr[cur + 2]) << 5) + - (d.indexOf(glyphStr[cur + 3]) << 0); + (d.indexOf(glyphStr[cur + 2]) << 5) + + (d.indexOf(glyphStr[cur + 3]) << 0); const itemId = this.simUI.sim.db.glyphSpellToItemId(spellId); //console.log(`Glyph position: ${glyphPosition}, spellID: ${spellId}`); @@ -343,7 +343,7 @@ export class IndividualWowheadGearPlannerImporter extends for (let gemIdx = 0; gemIdx < numGems; gemIdx++) { const gemPosition = (gearBytes[cur] & 0b11100000) >> 5; - const highgemid = (gearBytes[cur] & 0b00011111); + const highgemid = (gearBytes[cur] & 0b00011111); cur++; const gemId = (highgemid << 16) + (gearBytes[cur] << 8) + gearBytes[cur + 1]; @@ -424,7 +424,7 @@ export class IndividualAddonImporter extends Importer { throw new Error('Could not parse Race!'); } - const professions = (importJson['professions'] as Array<{name: string, level: number}>).map(profData => nameToProfession(profData.name)); + const professions = (importJson['professions'] as Array<{ name: string, level: number }>).map(profData => nameToProfession(profData.name)); professions.forEach((prof, i) => { if (prof == Profession.ProfessionUnknown) { throw new Error(`Could not parse profession '${importJson['professions'][i]}'`); @@ -435,8 +435,8 @@ export class IndividualAddonImporter extends Importer { const glyphsConfig = classGlyphsConfig[charClass]; const db = await Database.get(); - const majorGlyphIDs = (importJson['glyphs']['major'] as Array).map(g => glyphToID(g, db, glyphsConfig.majorGlyphs)); - const minorGlyphIDs = (importJson['glyphs']['minor'] as Array).map(g => glyphToID(g, db, glyphsConfig.minorGlyphs)); + const majorGlyphIDs = (importJson['glyphs']['major'] as Array).map(g => glyphToID(g, db, glyphsConfig.majorGlyphs)); + const minorGlyphIDs = (importJson['glyphs']['minor'] as Array).map(g => glyphToID(g, db, glyphsConfig.minorGlyphs)); const glyphs = Glyphs.create({ major1: majorGlyphIDs[0] || 0, @@ -473,7 +473,7 @@ function glyphNameToID(glyphName: string, glyphsConfig: Record): number { +function glyphToID(glyph: string | JsonObject, db: Database, glyphsConfig: Record): number { if (typeof glyph === 'string') { // Legacy version: AddOn exports Glyphs by name (string) only. Names must be in English. return glyphNameToID(glyph, glyphsConfig); diff --git a/ui/core/components/individual_sim_ui/apl_actions.ts b/ui/core/components/individual_sim_ui/apl_actions.ts index 05283c1644..0a6d31baf8 100644 --- a/ui/core/components/individual_sim_ui/apl_actions.ts +++ b/ui/core/components/individual_sim_ui/apl_actions.ts @@ -30,7 +30,7 @@ export class APLActionPicker extends Input, APLAction> { private readonly actionDiv: HTMLElement; private currentType: APLActionType; - private actionPicker: Input, any>|null; + private actionPicker: Input, any> | null; private readonly conditionPicker: AplValues.APLValuePicker; @@ -41,7 +41,7 @@ export class APLActionPicker extends Input, APLAction> { label: 'If:', changedEvent: (player: Player) => player.rotationChangeEmitter, getValue: (player: Player) => this.getSourceValue().condition, - setValue: (eventID: EventID, player: Player, newValue: APLValue|undefined) => { + setValue: (eventID: EventID, player: Player, newValue: APLValue | undefined) => { this.getSourceValue().condition = newValue; player.rotationChangeEmitter.emit(eventID); }, @@ -56,18 +56,18 @@ export class APLActionPicker extends Input, APLAction> { const allActionTypes = Object.keys(actionTypeFactories) as Array>; this.typePicker = new TextDropdownPicker(this.actionDiv, player, { - defaultLabel: 'Action', + defaultLabel: 'Action', values: allActionTypes .filter(actionType => actionTypeFactories[actionType].isPrepull == undefined || actionTypeFactories[actionType].isPrepull === isPrepull) .map(actionType => { - const factory = actionTypeFactories[actionType]; - return { - value: actionType, - label: factory.label, - submenu: factory.submenu, - tooltip: factory.fullDescription ? `

${factory.shortDescription}

${factory.fullDescription}` : factory.shortDescription, - }; - }), + const factory = actionTypeFactories[actionType]; + return { + value: actionType, + label: factory.label, + submenu: factory.submenu, + tooltip: factory.fullDescription ? `

${factory.shortDescription}

${factory.fullDescription}` : factory.shortDescription, + }; + }), equals: (a, b) => a == b, changedEvent: (player: Player) => player.rotationChangeEmitter, getValue: (player: Player) => this.getSourceValue().action.oneofKind, @@ -100,9 +100,9 @@ export class APLActionPicker extends Input, APLAction> { return this.rootElem; } - getInputValue(): APLAction { + getInputValue(): APLAction { const actionType = this.typePicker.getInputValue(); - return APLAction.create({ + return APLAction.create({ condition: this.conditionPicker.getInputValue(), action: { oneofKind: actionType, @@ -115,7 +115,7 @@ export class APLActionPicker extends Input, APLAction> { })()), }, }) - } + } setInputValue(newValue: APLAction) { if (!newValue) { diff --git a/ui/core/components/individual_sim_ui/apl_helpers.ts b/ui/core/components/individual_sim_ui/apl_helpers.ts index 199a48389d..aaf7e99798 100644 --- a/ui/core/components/individual_sim_ui/apl_helpers.ts +++ b/ui/core/components/individual_sim_ui/apl_helpers.ts @@ -41,7 +41,7 @@ const actionIdSets: Record spell.data.isCastable); // Split up non-cooldowns and cooldowns into separate sections for easier browsing. - const {'spells': spells, 'cooldowns': cooldowns } = bucket(castableSpells, spell => spell.data.isMajorCooldown ? 'cooldowns' : 'spells'); + const { 'spells': spells, 'cooldowns': cooldowns } = bucket(castableSpells, spell => spell.data.isMajorCooldown ? 'cooldowns' : 'spells'); const placeholders: Array = [ ActionId.fromOtherId(OtherAction.OtherActionPotion), @@ -108,7 +108,7 @@ export class APLActionIDPicker extends DropdownPicker, ActionId> { setValue: (eventID: EventID, player: Player, newValue: ActionId) => config.setValue(eventID, player, newValue.toProto()), defaultLabel: actionIdSet.defaultLabel, equals: (a, b) => ((a == null) == (b == null)) && (!a || a.equals(b!)), - setOptionContent: (button, valueConfig) => { + setOptionContent: (button, valueConfig) => { const actionId = valueConfig.value; const iconElem = document.createElement('a'); @@ -130,10 +130,10 @@ export class APLActionIDPicker extends DropdownPicker, ActionId> { const getActionIDs = actionIdSet.getActionIDs; const updateValues = async () => { const values = await getActionIDs(player); - this.setOptions(values); + this.setOptions(values); }; - updateValues(); - player.currentSpellsAndAurasEmitter.on(updateValues); + updateValues(); + player.currentSpellsAndAurasEmitter.on(updateValues); } } diff --git a/ui/core/components/individual_sim_ui/apl_rotation_picker.ts b/ui/core/components/individual_sim_ui/apl_rotation_picker.ts index d21e3e5338..eee5d9ad51 100644 --- a/ui/core/components/individual_sim_ui/apl_rotation_picker.ts +++ b/ui/core/components/individual_sim_ui/apl_rotation_picker.ts @@ -29,7 +29,7 @@ export class APLRotationPicker extends Component { changedEvent: (player: Player) => player.rotationChangeEmitter, getValue: (player: Player) => player.aplRotation.prepullActions, setValue: (eventID: EventID, player: Player, newValue: Array) => { - player.aplRotation.prepullActions = newValue; + player.aplRotation.prepullActions = newValue; player.rotationChangeEmitter.emit(eventID); }, newItem: () => APLPrepullAction.create({ @@ -49,7 +49,7 @@ export class APLRotationPicker extends Component { changedEvent: (player: Player) => player.rotationChangeEmitter, getValue: (player: Player) => player.aplRotation.priorityList, setValue: (eventID: EventID, player: Player, newValue: Array) => { - player.aplRotation.priorityList = newValue; + player.aplRotation.priorityList = newValue; player.rotationChangeEmitter.emit(eventID); }, newItem: () => APLListItem.create({ @@ -71,11 +71,11 @@ class APLPrepullActionPicker extends Input, APLPrepullAction> { private readonly doAtPicker: Input, string>; private readonly actionPicker: APLActionPicker; - private getItem(): APLPrepullAction { - return this.getSourceValue() || APLPrepullAction.create({ + private getItem(): APLPrepullAction { + return this.getSourceValue() || APLPrepullAction.create({ action: {}, }); - } + } constructor(parent: HTMLElement, player: Player, config: ListItemPickerConfig, APLPrepullAction>, index: number) { config.enableWhen = () => !this.getItem().hide; @@ -85,36 +85,36 @@ class APLPrepullActionPicker extends Input, APLPrepullAction> { const itemHeaderElem = ListPicker.getItemHeaderElem(this); makeListItemWarnings(itemHeaderElem, player, player => player.getCurrentStats().rotationStats?.prepullActions[index]?.warnings || []); - this.hidePicker = new HidePicker(itemHeaderElem, player, { - changedEvent: () => this.player.rotationChangeEmitter, - getValue: () => this.getItem().hide, - setValue: (eventID: EventID, player: Player, newValue: boolean) => { - this.getItem().hide = newValue; + this.hidePicker = new HidePicker(itemHeaderElem, player, { + changedEvent: () => this.player.rotationChangeEmitter, + getValue: () => this.getItem().hide, + setValue: (eventID: EventID, player: Player, newValue: boolean) => { + this.getItem().hide = newValue; this.player.rotationChangeEmitter.emit(eventID); - }, - }); + }, + }); - this.doAtPicker = new AdaptiveStringPicker(this.rootElem, this.player, { + this.doAtPicker = new AdaptiveStringPicker(this.rootElem, this.player, { label: 'Do At', labelTooltip: 'Time before pull to do the action. Should be negative, and formatted like, \'-1s\' or \'-2500ms\'.', extraCssClasses: ['apl-prepull-actions-doat'], - changedEvent: () => this.player.rotationChangeEmitter, - getValue: () => this.getItem().doAt, - setValue: (eventID: EventID, player: Player, newValue: string) => { - this.getItem().doAt = newValue; + changedEvent: () => this.player.rotationChangeEmitter, + getValue: () => this.getItem().doAt, + setValue: (eventID: EventID, player: Player, newValue: string) => { + this.getItem().doAt = newValue; this.player.rotationChangeEmitter.emit(eventID); - }, + }, inline: true, - }); + }); - this.actionPicker = new APLActionPicker(this.rootElem, this.player, { - changedEvent: () => this.player.rotationChangeEmitter, - getValue: () => this.getItem().action!, - setValue: (eventID: EventID, player: Player, newValue: APLAction) => { - this.getItem().action = newValue; + this.actionPicker = new APLActionPicker(this.rootElem, this.player, { + changedEvent: () => this.player.rotationChangeEmitter, + getValue: () => this.getItem().action!, + setValue: (eventID: EventID, player: Player, newValue: APLAction) => { + this.getItem().action = newValue; this.player.rotationChangeEmitter.emit(eventID); - }, - }); + }, + }); this.init(); } @@ -122,14 +122,14 @@ class APLPrepullActionPicker extends Input, APLPrepullAction> { return this.rootElem; } - getInputValue(): APLPrepullAction { - const item = APLPrepullAction.create({ + getInputValue(): APLPrepullAction { + const item = APLPrepullAction.create({ hide: this.hidePicker.getInputValue(), doAt: this.doAtPicker.getInputValue(), action: this.actionPicker.getInputValue(), }); return item; - } + } setInputValue(newValue: APLPrepullAction) { if (!newValue) { @@ -147,11 +147,11 @@ class APLListItemPicker extends Input, APLListItem> { private readonly hidePicker: Input, boolean>; private readonly actionPicker: APLActionPicker; - private getItem(): APLListItem { - return this.getSourceValue() || APLListItem.create({ + private getItem(): APLListItem { + return this.getSourceValue() || APLListItem.create({ action: {}, }); - } + } constructor(parent: HTMLElement, player: Player, config: ListItemPickerConfig, APLListItem>, index: number) { config.enableWhen = () => !this.getItem().hide; @@ -161,23 +161,23 @@ class APLListItemPicker extends Input, APLListItem> { const itemHeaderElem = ListPicker.getItemHeaderElem(this); makeListItemWarnings(itemHeaderElem, player, player => player.getCurrentStats().rotationStats?.priorityList[index]?.warnings || []); - this.hidePicker = new HidePicker(itemHeaderElem, player, { - changedEvent: () => this.player.rotationChangeEmitter, - getValue: () => this.getItem().hide, - setValue: (eventID: EventID, player: Player, newValue: boolean) => { - this.getItem().hide = newValue; + this.hidePicker = new HidePicker(itemHeaderElem, player, { + changedEvent: () => this.player.rotationChangeEmitter, + getValue: () => this.getItem().hide, + setValue: (eventID: EventID, player: Player, newValue: boolean) => { + this.getItem().hide = newValue; this.player.rotationChangeEmitter.emit(eventID); - }, - }); - - this.actionPicker = new APLActionPicker(this.rootElem, this.player, { - changedEvent: () => this.player.rotationChangeEmitter, - getValue: () => this.getItem().action!, - setValue: (eventID: EventID, player: Player, newValue: APLAction) => { - this.getItem().action = newValue; + }, + }); + + this.actionPicker = new APLActionPicker(this.rootElem, this.player, { + changedEvent: () => this.player.rotationChangeEmitter, + getValue: () => this.getItem().action!, + setValue: (eventID: EventID, player: Player, newValue: APLAction) => { + this.getItem().action = newValue; this.player.rotationChangeEmitter.emit(eventID); - }, - }); + }, + }); this.init(); } @@ -185,13 +185,13 @@ class APLListItemPicker extends Input, APLListItem> { return this.rootElem; } - getInputValue(): APLListItem { - const item = APLListItem.create({ + getInputValue(): APLListItem { + const item = APLListItem.create({ hide: this.hidePicker.getInputValue(), action: this.actionPicker.getInputValue(), }); return item; - } + } setInputValue(newValue: APLListItem) { if (!newValue) { @@ -212,14 +212,15 @@ function makeListItemWarnings(itemHeaderElem: HTMLElement, player: Player, itemHeaderElem.appendChild(warningsElem); const updateWarnings = async () => { - warningsTooltip.setContent({'.tooltip-inner': ''}); + warningsTooltip.setContent({ '.tooltip-inner': '' }); const warnings = getWarnings(player); if (warnings.length == 0) { warningsElem.style.visibility = 'hidden'; } else { warningsElem.style.visibility = 'visible'; const formattedWarnings = await Promise.all(warnings.map(w => ActionId.replaceAllInString(w))); - warningsTooltip.setContent({'.tooltip-inner': ` + warningsTooltip.setContent({ + '.tooltip-inner': `

This action has warnings, and might not behave as expected.

    ${formattedWarnings.map(w => `
  • ${w}
  • `).join('')} @@ -264,11 +265,11 @@ class HidePicker extends Input, boolean> { if (newValue) { this.iconElem.classList.add('fa-eye-slash'); this.iconElem.classList.remove('fa-eye'); - this.tooltip.setContent({'.tooltip-inner': 'Enable Action'}); + this.tooltip.setContent({ '.tooltip-inner': 'Enable Action' }); } else { this.iconElem.classList.add('fa-eye'); this.iconElem.classList.remove('fa-eye-slash'); - this.tooltip.setContent({'.tooltip-inner': 'Disable Action'}); + this.tooltip.setContent({ '.tooltip-inner': 'Disable Action' }); } } } \ No newline at end of file diff --git a/ui/core/components/individual_sim_ui/apl_values.ts b/ui/core/components/individual_sim_ui/apl_values.ts index ecb8d77d7e..6a8f345d7e 100644 --- a/ui/core/components/individual_sim_ui/apl_values.ts +++ b/ui/core/components/individual_sim_ui/apl_values.ts @@ -35,24 +35,24 @@ import { ListItemPickerConfig, ListPicker } from '../list_picker.js'; import * as AplHelpers from './apl_helpers.js'; -export interface APLValuePickerConfig extends InputConfig, APLValue|undefined> { +export interface APLValuePickerConfig extends InputConfig, APLValue | undefined> { } export type APLValueType = APLValue['value']['oneofKind']; -export class APLValuePicker extends Input, APLValue|undefined> { +export class APLValuePicker extends Input, APLValue | undefined> { private typePicker: TextDropdownPicker, APLValueType>; private currentType: APLValueType; - private valuePicker: Input, any>|null; + private valuePicker: Input, any> | null; constructor(parent: HTMLElement, player: Player, config: APLValuePickerConfig) { super(parent, 'apl-value-picker-root', player, config); const allValueTypes = Object.keys(valueTypeFactories) as Array>; this.typePicker = new TextDropdownPicker(this.rootElem, player, { - defaultLabel: 'No Condition', + defaultLabel: 'No Condition', values: [{ value: undefined, label: '', @@ -102,7 +102,7 @@ export class APLValuePicker extends Input, APLValue|undefined> { return this.rootElem; } - getInputValue(): APLValue|undefined { + getInputValue(): APLValue | undefined { const valueType = this.typePicker.getInputValue(); if (!valueType) { return undefined; @@ -120,9 +120,9 @@ export class APLValuePicker extends Input, APLValue|undefined> { }, }) } - } + } - setInputValue(newValue: APLValue|undefined) { + setInputValue(newValue: APLValue | undefined) { const newValueType = newValue?.value.oneofKind; this.updateValuePicker(newValueType); @@ -209,17 +209,17 @@ export function valueListFieldConfig(field: string): AplHelpers.APLPickerBuilder return { field: field, newValue: () => [], - factory: (parent, player, config) => new ListPicker, APLValue|undefined>(parent, player, { + factory: (parent, player, config) => new ListPicker, APLValue | undefined>(parent, player, { ...config, // Override setValue to replace undefined elements with default messages. - setValue: (eventID: EventID, player: Player, newValue: Array) => { + setValue: (eventID: EventID, player: Player, newValue: Array) => { config.setValue(eventID, player, newValue.map(val => val || APLValue.create())); }, itemLabel: 'Value', newItem: APLValue.create, - copyItem: (oldValue: APLValue|undefined) => oldValue ? APLValue.clone(oldValue) : oldValue, - newItemPicker: (parent: HTMLElement, listPicker: ListPicker, APLValue|undefined>, index: number, config: ListItemPickerConfig, APLValue|undefined>) => new APLValuePicker(parent, player, config), + copyItem: (oldValue: APLValue | undefined) => oldValue ? APLValue.clone(oldValue) : oldValue, + newItemPicker: (parent: HTMLElement, listPicker: ListPicker, APLValue | undefined>, index: number, config: ListItemPickerConfig, APLValue | undefined>) => new APLValuePicker(parent, player, config), horizontalLayout: true, allowedActions: ['create', 'delete'], }), @@ -244,7 +244,7 @@ function inputBuilder(config: { }; } -const valueTypeFactories: Record, ValueTypeConfig> = { +const valueTypeFactories: Record, ValueTypeConfig> = { // Operators ['const']: inputBuilder({ label: 'Const', diff --git a/ui/core/components/individual_sim_ui/bulk_tab.ts b/ui/core/components/individual_sim_ui/bulk_tab.ts index 51a9d953e9..61e25d2c80 100644 --- a/ui/core/components/individual_sim_ui/bulk_tab.ts +++ b/ui/core/components/individual_sim_ui/bulk_tab.ts @@ -26,754 +26,754 @@ import { BooleanPicker } from "../boolean_picker"; import { UIItem_FactionRestriction } from '../../proto/ui'; export class BulkGearJsonImporter extends Importer { - private readonly simUI: IndividualSimUI; - private readonly bulkUI: BulkTab - constructor(parent: HTMLElement, simUI: IndividualSimUI, bulkUI: BulkTab) { - super(parent, simUI, 'Bag Item Import', true); - this.simUI = simUI; - this.bulkUI = bulkUI; - this.descriptionElem.innerHTML = ` + private readonly simUI: IndividualSimUI; + private readonly bulkUI: BulkTab + constructor(parent: HTMLElement, simUI: IndividualSimUI, bulkUI: BulkTab) { + super(parent, simUI, 'Bag Item Import', true); + this.simUI = simUI; + this.bulkUI = bulkUI; + this.descriptionElem.innerHTML = `

    Import bag items from a JSON file, which can be created by the WowSimsExporter in-game AddOn.

    To import, upload the file or paste the text below, then click, 'Import'.

    `; - } - - async onImport(data: string) { - try { - const equipment = EquipmentSpec.fromJsonString(data, { ignoreUnknownFields: true }); - if (equipment?.items?.length > 0) { - const db = await Database.loadLeftoversIfNecessary(equipment); - const items = equipment.items.filter((spec) => spec.id > 0); - if (items.length > 0) { - for (const itemSpec of items) { - if (itemSpec.id == 0) { - continue; - } - if (!db.lookupItemSpec(itemSpec)) { - throw new Error("cannot find item with ID " + itemSpec.id); - } - } - this.bulkUI.addItems(items); - } - } - this.close(); - } catch (e: any) { - alert(e.toString()); - } - } + } + + async onImport(data: string) { + try { + const equipment = EquipmentSpec.fromJsonString(data, { ignoreUnknownFields: true }); + if (equipment?.items?.length > 0) { + const db = await Database.loadLeftoversIfNecessary(equipment); + const items = equipment.items.filter((spec) => spec.id > 0); + if (items.length > 0) { + for (const itemSpec of items) { + if (itemSpec.id == 0) { + continue; + } + if (!db.lookupItemSpec(itemSpec)) { + throw new Error("cannot find item with ID " + itemSpec.id); + } + } + this.bulkUI.addItems(items); + } + } + this.close(); + } catch (e: any) { + alert(e.toString()); + } + } } class BulkSimResultRenderer { - constructor(parent: ContentBlock, simUI: IndividualSimUI, result: BulkComboResult, baseResult: BulkComboResult) { - const dpsDivParent = document.createElement('div'); - dpsDivParent.classList.add('results-sim'); - - const dpsDiv = document.createElement('div'); - dpsDiv.classList.add('bulk-result-body-dps', 'bulk-items-text-line', 'results-sim-dps', 'damage-metrics'); - dpsDivParent.appendChild(dpsDiv); - - const dpsNumber = document.createElement('span'); - dpsNumber.textContent = this.formatDps(result.unitMetrics?.dps?.avg!); - dpsNumber.classList.add('topline-result-avg'); - dpsDiv.appendChild(dpsNumber); - - const dpsDelta = result.unitMetrics?.dps?.avg! - baseResult.unitMetrics?.dps?.avg!; - const dpsDeltaSpan = document.createElement('span'); - dpsDeltaSpan.textContent = `${this.formatDpsDelta(dpsDelta)}`; - dpsDeltaSpan.classList.add(dpsDelta >= 0 ? 'bulk-result-header-positive' : 'bulk-result-header-negative'); - dpsDiv.appendChild(dpsDeltaSpan); - - const itemsContainer = document.createElement('div'); - itemsContainer.classList.add('bulk-gear-combo'); - parent.bodyElement.appendChild(itemsContainer); - parent.bodyElement.appendChild(dpsDivParent); - - if (result.itemsAdded && result.itemsAdded.length > 0) { - const equipBtn = document.createElement('button'); - equipBtn.textContent = 'Equip'; - equipBtn.classList.add('btn', 'btn-primary', 'bulk-equipit'); - equipBtn.onclick = () => { - result.itemsAdded.forEach((itemAdded) => { - const item = simUI.sim.db.lookupItemSpec(itemAdded.item!); - simUI.player.equipItem(TypedEvent.nextEventID(), itemAdded.slot, item); - simUI.simHeader.activateTab('gear-tab'); - }); - }; - - parent.bodyElement.appendChild(equipBtn); - - for (const is of result.itemsAdded) { - const item = simUI.sim.db.lookupItemSpec(is.item!) - const renderer = new ItemRenderer(itemsContainer, simUI.player); - renderer.update(item!); - - const p = document.createElement('a'); - p.classList.add('bulk-result-item-slot'); - p.textContent = this.itemSlotName(is); - renderer.nameElem.appendChild(p); - } - } else { - const p = document.createElement('p'); - p.textContent = 'No changes - this is your currently equipped gear!'; - parent.bodyElement.appendChild(p); - dpsDeltaSpan.textContent = ''; - } - } - - private formatDps(dps: number): string { - return (Math.round(dps * 100) / 100).toFixed(2); - } - - private formatDpsDelta(delta: number): string { - return ((delta >= 0) ? "+" : "") + this.formatDps(delta); - } - - private itemSlotName(is: ItemSpecWithSlot): string { - return JSON.parse(ItemSpecWithSlot.toJsonString(is, { emitDefaultValues: true }))['slot'].replace('ItemSlot', '') - } + constructor(parent: ContentBlock, simUI: IndividualSimUI, result: BulkComboResult, baseResult: BulkComboResult) { + const dpsDivParent = document.createElement('div'); + dpsDivParent.classList.add('results-sim'); + + const dpsDiv = document.createElement('div'); + dpsDiv.classList.add('bulk-result-body-dps', 'bulk-items-text-line', 'results-sim-dps', 'damage-metrics'); + dpsDivParent.appendChild(dpsDiv); + + const dpsNumber = document.createElement('span'); + dpsNumber.textContent = this.formatDps(result.unitMetrics?.dps?.avg!); + dpsNumber.classList.add('topline-result-avg'); + dpsDiv.appendChild(dpsNumber); + + const dpsDelta = result.unitMetrics?.dps?.avg! - baseResult.unitMetrics?.dps?.avg!; + const dpsDeltaSpan = document.createElement('span'); + dpsDeltaSpan.textContent = `${this.formatDpsDelta(dpsDelta)}`; + dpsDeltaSpan.classList.add(dpsDelta >= 0 ? 'bulk-result-header-positive' : 'bulk-result-header-negative'); + dpsDiv.appendChild(dpsDeltaSpan); + + const itemsContainer = document.createElement('div'); + itemsContainer.classList.add('bulk-gear-combo'); + parent.bodyElement.appendChild(itemsContainer); + parent.bodyElement.appendChild(dpsDivParent); + + if (result.itemsAdded && result.itemsAdded.length > 0) { + const equipBtn = document.createElement('button'); + equipBtn.textContent = 'Equip'; + equipBtn.classList.add('btn', 'btn-primary', 'bulk-equipit'); + equipBtn.onclick = () => { + result.itemsAdded.forEach((itemAdded) => { + const item = simUI.sim.db.lookupItemSpec(itemAdded.item!); + simUI.player.equipItem(TypedEvent.nextEventID(), itemAdded.slot, item); + simUI.simHeader.activateTab('gear-tab'); + }); + }; + + parent.bodyElement.appendChild(equipBtn); + + for (const is of result.itemsAdded) { + const item = simUI.sim.db.lookupItemSpec(is.item!) + const renderer = new ItemRenderer(itemsContainer, simUI.player); + renderer.update(item!); + + const p = document.createElement('a'); + p.classList.add('bulk-result-item-slot'); + p.textContent = this.itemSlotName(is); + renderer.nameElem.appendChild(p); + } + } else { + const p = document.createElement('p'); + p.textContent = 'No changes - this is your currently equipped gear!'; + parent.bodyElement.appendChild(p); + dpsDeltaSpan.textContent = ''; + } + } + + private formatDps(dps: number): string { + return (Math.round(dps * 100) / 100).toFixed(2); + } + + private formatDpsDelta(delta: number): string { + return ((delta >= 0) ? "+" : "") + this.formatDps(delta); + } + + private itemSlotName(is: ItemSpecWithSlot): string { + return JSON.parse(ItemSpecWithSlot.toJsonString(is, { emitDefaultValues: true }))['slot'].replace('ItemSlot', '') + } } export class BulkItemPicker extends Component { - private readonly itemElem: ItemRenderer; - readonly simUI: IndividualSimUI; - readonly bulkUI: BulkTab; - readonly index: number; - - protected item: EquippedItem; - - constructor(parent: HTMLElement, simUI: IndividualSimUI, bulkUI: BulkTab, item: EquippedItem, index: number) { - super(parent, 'bulk-item-picker'); - this.simUI = simUI; - this.bulkUI = bulkUI; - this.index = index; - this.item = item; - this.itemElem = new ItemRenderer(this.rootElem, simUI.player); - - this.simUI.sim.waitForInit().then(() => { - this.setItem(item); - const slot = getEligibleItemSlots(this.item.item)[0]; - const eligibleEnchants = this.simUI.sim.db.getEnchants(slot); - const openEnchantGemSelector = (event: Event) => { - event.preventDefault(); - const changeEvent = new TypedEvent(); - const modal = new SelectorModal(this.bulkUI.rootElem, this.simUI, this.simUI.player, { - selectedTab: SelectorModalTabs.Enchants, - slot: slot, - equippedItem: this.item, - eligibleItems: new Array(), - eligibleEnchants: eligibleEnchants, - gearData: { - equipItem: (eventID: EventID, equippedItem: EquippedItem | null) => { - if (equippedItem) { - const allItems = this.bulkUI.getItems(); - allItems[this.index] = equippedItem.asSpec(); - this.item = equippedItem; - this.bulkUI.setItems(allItems); - changeEvent.emit(TypedEvent.nextEventID()); - } - }, - getEquippedItem: () => this.item, - changeEvent: changeEvent, - } - }); - - if (eligibleEnchants.length > 0) { - modal.openTabName("Enchants"); - } else if (this.item._gems.length > 0) { - modal.openTabName("Gem1"); - } - - const destroyItemButton = document.createElement('button'); - destroyItemButton.textContent = 'Remove from Batch'; - destroyItemButton.classList.add('btn', 'btn-danger'); - destroyItemButton.onclick = () => { - bulkUI.setItems(bulkUI.getItems().filter((item, idx) => { return idx != this.index })); - modal.close(); - }; - const closeX = modal.header?.querySelector('.close-button'); - if (closeX != undefined) { - modal.header?.insertBefore(destroyItemButton, closeX); - } - }; - - const onClickEnd = (event: Event) => { - event.preventDefault(); - }; - - // Make icon open gear selector - this.itemElem.iconElem.addEventListener('click', openEnchantGemSelector); - this.itemElem.iconElem.addEventListener('touchstart', openEnchantGemSelector); - this.itemElem.iconElem.addEventListener('touchend', onClickEnd); - - // Make item name open gear selector - this.itemElem.nameElem.addEventListener('click', openEnchantGemSelector); - this.itemElem.nameElem.addEventListener('touchstart', openEnchantGemSelector); - this.itemElem.nameElem.addEventListener('touchend', onClickEnd); - - this.itemElem.enchantElem.addEventListener('click', openEnchantGemSelector); - this.itemElem.enchantElem.addEventListener('touchstart', openEnchantGemSelector); - this.itemElem.enchantElem.addEventListener('touchend', onClickEnd); - }); - } - - setItem(newItem: EquippedItem | null) { - this.itemElem.clear(); - if (newItem != null) { - this.itemElem.update(newItem); - this.item = newItem; - } else { - this.itemElem.rootElem.style.opacity = '30%'; - this.itemElem.iconElem.style.backgroundImage = `url('/wotlk/assets/item_slots/empty.jpg')`; - this.itemElem.nameElem.textContent = 'Add new item (not implemented)'; - this.itemElem.rootElem.style.alignItems = 'center'; - } - } + private readonly itemElem: ItemRenderer; + readonly simUI: IndividualSimUI; + readonly bulkUI: BulkTab; + readonly index: number; + + protected item: EquippedItem; + + constructor(parent: HTMLElement, simUI: IndividualSimUI, bulkUI: BulkTab, item: EquippedItem, index: number) { + super(parent, 'bulk-item-picker'); + this.simUI = simUI; + this.bulkUI = bulkUI; + this.index = index; + this.item = item; + this.itemElem = new ItemRenderer(this.rootElem, simUI.player); + + this.simUI.sim.waitForInit().then(() => { + this.setItem(item); + const slot = getEligibleItemSlots(this.item.item)[0]; + const eligibleEnchants = this.simUI.sim.db.getEnchants(slot); + const openEnchantGemSelector = (event: Event) => { + event.preventDefault(); + const changeEvent = new TypedEvent(); + const modal = new SelectorModal(this.bulkUI.rootElem, this.simUI, this.simUI.player, { + selectedTab: SelectorModalTabs.Enchants, + slot: slot, + equippedItem: this.item, + eligibleItems: new Array(), + eligibleEnchants: eligibleEnchants, + gearData: { + equipItem: (eventID: EventID, equippedItem: EquippedItem | null) => { + if (equippedItem) { + const allItems = this.bulkUI.getItems(); + allItems[this.index] = equippedItem.asSpec(); + this.item = equippedItem; + this.bulkUI.setItems(allItems); + changeEvent.emit(TypedEvent.nextEventID()); + } + }, + getEquippedItem: () => this.item, + changeEvent: changeEvent, + } + }); + + if (eligibleEnchants.length > 0) { + modal.openTabName("Enchants"); + } else if (this.item._gems.length > 0) { + modal.openTabName("Gem1"); + } + + const destroyItemButton = document.createElement('button'); + destroyItemButton.textContent = 'Remove from Batch'; + destroyItemButton.classList.add('btn', 'btn-danger'); + destroyItemButton.onclick = () => { + bulkUI.setItems(bulkUI.getItems().filter((item, idx) => { return idx != this.index })); + modal.close(); + }; + const closeX = modal.header?.querySelector('.close-button'); + if (closeX != undefined) { + modal.header?.insertBefore(destroyItemButton, closeX); + } + }; + + const onClickEnd = (event: Event) => { + event.preventDefault(); + }; + + // Make icon open gear selector + this.itemElem.iconElem.addEventListener('click', openEnchantGemSelector); + this.itemElem.iconElem.addEventListener('touchstart', openEnchantGemSelector); + this.itemElem.iconElem.addEventListener('touchend', onClickEnd); + + // Make item name open gear selector + this.itemElem.nameElem.addEventListener('click', openEnchantGemSelector); + this.itemElem.nameElem.addEventListener('touchstart', openEnchantGemSelector); + this.itemElem.nameElem.addEventListener('touchend', onClickEnd); + + this.itemElem.enchantElem.addEventListener('click', openEnchantGemSelector); + this.itemElem.enchantElem.addEventListener('touchstart', openEnchantGemSelector); + this.itemElem.enchantElem.addEventListener('touchend', onClickEnd); + }); + } + + setItem(newItem: EquippedItem | null) { + this.itemElem.clear(); + if (newItem != null) { + this.itemElem.update(newItem); + this.item = newItem; + } else { + this.itemElem.rootElem.style.opacity = '30%'; + this.itemElem.iconElem.style.backgroundImage = `url('/wotlk/assets/item_slots/empty.jpg')`; + this.itemElem.nameElem.textContent = 'Add new item (not implemented)'; + this.itemElem.rootElem.style.alignItems = 'center'; + } + } } export class BulkTab extends SimTab { - readonly simUI: IndividualSimUI; - - readonly itemsChangedEmitter = new TypedEvent(); - - readonly leftPanel: HTMLElement; - readonly rightPanel: HTMLElement; - - readonly column1: HTMLElement = this.buildColumn(1, 'raid-settings-col'); - - protected items: Array = new Array(); - - private pendingResults: ResultsViewer; - private pendingDiv: HTMLDivElement; - - // TODO: Make a real options probably - private doCombos: boolean; - private fastMode: boolean; - private autoGem: boolean; - private autoEnchant: boolean; - private defaultGems: SimGem[]; - private gemIconElements: HTMLImageElement[]; - - constructor(parentElem: HTMLElement, simUI: IndividualSimUI) { - super(parentElem, simUI, { identifier: 'bulk-tab', title: 'Batch' }); - this.simUI = simUI; - - this.leftPanel = document.createElement('div'); - this.leftPanel.classList.add('bulk-tab-left', 'tab-panel-left'); - this.leftPanel.appendChild(this.column1); - - this.rightPanel = document.createElement('div'); - this.rightPanel.classList.add('bulk-tab-right', 'tab-panel-right'); - - this.pendingDiv = document.createElement('div'); - this.pendingDiv.classList.add("results-pending-overlay"); - this.pendingResults = new ResultsViewer(this.pendingDiv); - this.pendingResults.hideAll(); - - this.contentContainer.appendChild(this.leftPanel); - this.contentContainer.appendChild(this.rightPanel); - this.contentContainer.appendChild(this.pendingDiv); - - this.doCombos = true; - this.fastMode = true; - this.autoGem = true; - this.autoEnchant = true; - this.defaultGems = [UIGem.create(), UIGem.create(), UIGem.create(), UIGem.create()]; - this.gemIconElements = []; - this.buildTabContent(); - - this.simUI.sim.waitForInit().then(() => { - this.loadSettings(); - }); - } - - private getSettingsKey(): string { - return this.simUI.getStorageKey("bulk-settings.v1"); - } - - private loadSettings() { - const storedSettings = window.localStorage.getItem(this.getSettingsKey()); - if (storedSettings != null) { - let settings = BulkSettings.fromJsonString(storedSettings, { ignoreUnknownFields: true }) - - this.doCombos = settings.combinations; - this.fastMode = settings.fastMode; - this.autoEnchant = settings.autoEnchant; - this.autoGem = settings.autoGem; - this.defaultGems = new Array( - SimGem.create({ id: settings.defaultRedGem }), - SimGem.create({ id: settings.defaultYellowGem }), - SimGem.create({ id: settings.defaultBlueGem }), - SimGem.create({ id: settings.defaultMetaGem }), - ) - - this.defaultGems.forEach((gem, idx) => { - ActionId.fromItemId(gem.id).fill().then(filledId => { - this.gemIconElements[idx].src = filledId.iconUrl; - }); - }); - - } - } - - private storeSettings() { - const settings = this.createBulkSettings(); - const setStr = BulkSettings.toJsonString(settings, {enumAsInteger: true}) - window.localStorage.setItem(this.getSettingsKey(), setStr); - } - - - protected createBulkSettings(): BulkSettings { - - return BulkSettings.create({ - items: this.items, - // TODO(Riotdog-GehennasEU): Make all of these configurable. - // For now, it's always constant iteration combinations mode for "sim my bags". - combinations: this.doCombos, - fastMode: this.fastMode, - autoEnchant: this.autoEnchant, - autoGem: this.autoGem, - defaultRedGem: this.defaultGems[0].id, - defaultYellowGem: this.defaultGems[1].id, - defaultBlueGem: this.defaultGems[2].id, - defaultMetaGem: this.defaultGems[3].id, - iterationsPerCombo: this.simUI.sim.getIterations(), // TODO(Riotdog-GehennasEU): Define a new UI element for the iteration setting. - }); - } - - protected createBulkItemsDatabase(): SimDatabase { - const itemsDb = SimDatabase.create(); - for (const is of this.items) { - const item = this.simUI.sim.db.lookupItemSpec(is) - if (!item) { - throw new Error(`item with ID ${is.id} not found in database`); - } - itemsDb.items.push(SimItem.fromJson(UIItem.toJson(item.item), { ignoreUnknownFields: true })) - if (item.enchant) { - itemsDb.enchants.push(SimEnchant.fromJson(UIEnchant.toJson(item.enchant), { ignoreUnknownFields: true })); - } - for (const gem of item.gems) { - if (gem) { - itemsDb.gems.push(SimGem.fromJson(UIGem.toJson(gem), { ignoreUnknownFields: true })); - } - } - } - for (const gem of this.defaultGems) { - if (gem.id > 0) { - itemsDb.gems.push(gem); - } - } - return itemsDb; - } - - addItems(items: Array) { - if (this.items.length == 0) { - this.items = items; - } else { - this.items = this.items.concat(items); - } - this.itemsChangedEmitter.emit(TypedEvent.nextEventID()); - } - - setItems(items: Array) { - this.items = items; - this.itemsChangedEmitter.emit(TypedEvent.nextEventID()); - } - - clearItems() { - this.items = new Array(); - this.itemsChangedEmitter.emit(TypedEvent.nextEventID()); - } - - getItems(): Array { - const result = new Array(); - this.items.forEach((spec) => { result.push(ItemSpec.clone(spec)); }); - return result; - } - - setCombinations(doCombos: boolean) { - this.doCombos = doCombos; - this.itemsChangedEmitter.emit(TypedEvent.nextEventID()); - } - - setFastMode(fastMode: boolean) { - this.fastMode = fastMode; - this.itemsChangedEmitter.emit(TypedEvent.nextEventID()); - } - - protected async runBulkSim(onProgress: Function) { - this.pendingResults.setPending(); - - try { - await this.simUI.sim.runBulkSim(this.createBulkSettings(), this.createBulkItemsDatabase(), onProgress); - } catch (e) { - this.simUI.handleCrash(e); - } - } - - protected buildTabContent() { - const itemsBlock = new ContentBlock(this.column1, 'bulk-items', { - header: { title: 'Items' } - }); - - itemsBlock.bodyElement.classList.add('gear-picker-root'); - - const noticeWorkInProgress = document.createElement('div'); - noticeWorkInProgress.classList.add('bulk-items-text-line'); - itemsBlock.bodyElement.appendChild(noticeWorkInProgress); - noticeWorkInProgress.innerHTML = 'Notice: This is under very early but active development and experimental. You may also need to update your WoW AddOn if you want to import your bags.' - - const itemTextIntro = document.createElement('div'); - itemTextIntro.classList.add('bulk-items-text-line'); - itemsBlock.bodyElement.appendChild(itemTextIntro); - - const itemList = document.createElement('div'); - - itemList.classList.add('tab-panel-col', 'bulk-gear-combo'); - itemsBlock.bodyElement.appendChild(itemList); - - this.itemsChangedEmitter.on(() => { - itemList.innerHTML = ''; - if (this.items.length > 0) { - itemTextIntro.textContent = 'The following items will be simmed together with your equipped gear.'; - for (let i = 0; i < this.items.length; ++i) { - const spec = this.items[i]; - const item = this.simUI.sim.db.lookupItemSpec(spec); - const bulkItemPicker = new BulkItemPicker(itemList, this.simUI, this, item!, i); - } - } - }); - - this.clearItems(); - - let resultsBlock = new ContentBlock(this.column1, 'bulk-results', { - header: { - title: 'Results', - extraCssClasses: ['bulk-results-header'], - }, - }); - - resultsBlock.rootElem.hidden = true; - resultsBlock.bodyElement.classList.add('gear-picker-root', 'tab-panel-col'); - - this.simUI.sim.bulkSimStartEmitter.on(() => { - resultsBlock.rootElem.hidden = true; - }); - - this.simUI.sim.bulkSimResultEmitter.on((_, bulkSimResult) => { - resultsBlock.rootElem.hidden = bulkSimResult.results.length == 0; - resultsBlock.bodyElement.innerHTML = ''; - - for (const r of bulkSimResult.results) { - const resultBlock = new ContentBlock(resultsBlock.bodyElement, 'bulk-result', { header: { title: '' }, bodyClasses: ['bulk-results-body'] }); - new BulkSimResultRenderer(resultBlock, this.simUI, r, bulkSimResult.equippedGearResult!); - } - }); - - const settingsBlock = new ContentBlock(this.rightPanel, 'bulk-settings', { - header: { title: 'Setup' } - }); - - const bulkSimButton = document.createElement('button'); - bulkSimButton.classList.add('btn', 'btn-primary', 'w-100', 'bulk-settings-button'); - bulkSimButton.textContent = 'Simulate Batch'; - bulkSimButton.addEventListener('click', () => { - - this.pendingDiv.style.display = "flex"; - this.leftPanel.classList.add("blurred"); - this.rightPanel.classList.add("blurred"); - - const previousContents = bulkSimButton.innerHTML; - bulkSimButton.disabled = true; - bulkSimButton.classList.add(".disabled"); - bulkSimButton.innerHTML = ` Running`; - - - let simStart = new Date().getTime(); - let lastTotal = 0; - let rounds = 0; - let currentRound = 0; - let combinations = 0; - - this.runBulkSim((progressMetrics: ProgressMetrics) => { - console.log(progressMetrics); - - const msSinceStart = new Date().getTime() - simStart; - const iterPerSecond = progressMetrics.completedIterations / (msSinceStart / 1000); - - if (combinations == 0) { - combinations = progressMetrics.totalSims; - } - if (this.fastMode) { - if (rounds == 0 && progressMetrics.totalSims > 0) { - rounds = Math.ceil(Math.log(progressMetrics.totalSims / 20) / Math.log(2)) + 1; - currentRound = 1; - } - if (progressMetrics.totalSims < lastTotal) { - currentRound += 1; - simStart = new Date().getTime(); - } - } - - this.setSimProgress(progressMetrics, iterPerSecond, currentRound, rounds, combinations); - lastTotal = progressMetrics.totalSims; - - if (progressMetrics.finalBulkResult != null) { - // reset state - this.pendingDiv.style.display = "none"; - this.leftPanel.classList.remove("blurred"); - this.rightPanel.classList.remove("blurred"); - - this.pendingResults.hideAll(); - bulkSimButton.disabled = false; - bulkSimButton.classList.remove(".disabled"); - bulkSimButton.innerHTML = previousContents; - } - }); - }); - - settingsBlock.bodyElement.appendChild(bulkSimButton); - - const importButton = document.createElement('button'); - importButton.classList.add('btn', 'btn-secondary', 'w-100', 'bulk-settings-button'); - importButton.innerHTML = ' Import From Bags'; - importButton.addEventListener('click', () => new BulkGearJsonImporter(this.simUI.rootElem, this.simUI, this)); - settingsBlock.bodyElement.appendChild(importButton); - - const importFavsButton = document.createElement('button'); - importFavsButton.classList.add('btn', 'btn-secondary', 'w-100', 'bulk-settings-button'); - importFavsButton.innerHTML = ' Import Favorites'; - importFavsButton.addEventListener('click', () => { - const filters = this.simUI.player.sim.getFilters(); - const items = filters.favoriteItems.map((itemID) => { - return ItemSpec.create({ id: itemID }); - }); - this.addItems(items); - }); - settingsBlock.bodyElement.appendChild(importFavsButton); - - const searchButton = document.createElement('button'); - let searchText = document.createElement('input'); - searchText.type = "text"; - searchText.placeholder = "search..."; - searchText.style.display = "none"; - - const searchResults = document.createElement('ul'); - searchResults.classList.add("batch-search-results"); - - let allItems = Array(); - - searchText.addEventListener("keyup", ev => { - if (ev.key == "Enter") { - let toAdd = Array(); - searchResults.childNodes.forEach((node) => { - const strID = (node as HTMLElement).getAttribute('data-item-id'); - if (strID != null) { - toAdd.push(ItemSpec.create({ id: Number.parseInt(strID) })); - } - }); - this.addItems(toAdd); - } - }); - - searchText.addEventListener("input", (e) => { - const searchString = searchText.value; - searchResults.innerHTML = ""; - if (searchString.length == 0) { - return; - } - var pieces = searchString.split(' '); - - let displayCount = 0; - allItems.every((item) => { - let matched = true; - const lcName = item.name.toLowerCase(); - const lcSetName = item.setName.toLowerCase(); - - pieces.forEach((piece) => { - var lcPiece = piece.toLowerCase(); - if (!lcName.includes(lcPiece) && !lcSetName.includes(lcPiece)) { - matched = false; - return false; - } - return true; - }) - - if (matched) { - let itemElement = document.createElement('li'); - itemElement.innerHTML = `${item.name}`; - itemElement.setAttribute("data-item-id", item.id.toString()); - itemElement.addEventListener("click", (ev) => { - this.addItems(Array(ItemSpec.create({ id: item.id }))); - }) - if (item.heroic) { - let htxt = document.createElement("span"); - htxt.style.color = "green"; - htxt.innerText = "[H]"; - itemElement.appendChild(htxt); - } - if (item.factionRestriction == UIItem_FactionRestriction.HORDE_ONLY) { - let ftxt = document.createElement("span"); - ftxt.style.color = "red"; - ftxt.innerText = "(H)"; - itemElement.appendChild(ftxt); - } - if (item.factionRestriction == UIItem_FactionRestriction.ALLIANCE_ONLY) { - let ftxt = document.createElement("span"); - ftxt.style.color = "blue"; - ftxt.innerText = "(A)"; - itemElement.appendChild(ftxt); - } - searchResults.append(itemElement); - displayCount++; - } - - return displayCount < 10; - }); - }); - - searchButton.classList.add('btn', 'btn-secondary', 'w-100', 'bulk-settings-button'); - const baseSearchHTML = ' Add Item'; - searchButton.innerHTML = baseSearchHTML; - searchButton.addEventListener('click', () => { - if (searchText.style.display == "none") { - searchButton.innerHTML = 'Close Search Results'; - allItems = this.simUI.sim.db.getAllItems().filter((item) => { - return canEquipItem(item, this.simUI.player.spec, undefined); - }) - searchText.style.display = "block"; - searchText.focus(); - } else { - searchButton.innerHTML = baseSearchHTML; - searchText.style.display = "none"; - searchResults.innerHTML = ""; - } - }); - settingsBlock.bodyElement.appendChild(searchButton); - settingsBlock.bodyElement.appendChild(searchText); - settingsBlock.bodyElement.appendChild(searchResults); - - const clearButton = document.createElement('button'); - clearButton.classList.add('btn', 'btn-secondary', 'w-100', 'bulk-settings-button'); - clearButton.textContent = 'Clear All'; - clearButton.addEventListener('click', () => { - this.clearItems(); - resultsBlock.rootElem.hidden = true; - resultsBlock.bodyElement.innerHTML = ''; - }); - settingsBlock.bodyElement.appendChild(clearButton); - - // Default Gem Options - const defaultGemDiv = document.createElement("div"); - if (this.autoGem) { - defaultGemDiv.style.display = "flex"; - } else { - defaultGemDiv.style.display = "none"; - } - - defaultGemDiv.classList.add("default-gem-container"); - const gemLabel = document.createElement("label"); - gemLabel.innerText = "Defaults for Auto Gem"; - defaultGemDiv.appendChild(gemLabel); - - const gemSocketsDiv = document.createElement("div"); - gemSocketsDiv.classList.add("sockets-container"); - - Array(GemColor.GemColorRed, GemColor.GemColorYellow, GemColor.GemColorBlue, GemColor.GemColorMeta).forEach((socketColor, socketIndex) => { - let gemFragment = document.createElement('fragment'); - gemFragment.innerHTML = ` + readonly simUI: IndividualSimUI; + + readonly itemsChangedEmitter = new TypedEvent(); + + readonly leftPanel: HTMLElement; + readonly rightPanel: HTMLElement; + + readonly column1: HTMLElement = this.buildColumn(1, 'raid-settings-col'); + + protected items: Array = new Array(); + + private pendingResults: ResultsViewer; + private pendingDiv: HTMLDivElement; + + // TODO: Make a real options probably + private doCombos: boolean; + private fastMode: boolean; + private autoGem: boolean; + private autoEnchant: boolean; + private defaultGems: SimGem[]; + private gemIconElements: HTMLImageElement[]; + + constructor(parentElem: HTMLElement, simUI: IndividualSimUI) { + super(parentElem, simUI, { identifier: 'bulk-tab', title: 'Batch' }); + this.simUI = simUI; + + this.leftPanel = document.createElement('div'); + this.leftPanel.classList.add('bulk-tab-left', 'tab-panel-left'); + this.leftPanel.appendChild(this.column1); + + this.rightPanel = document.createElement('div'); + this.rightPanel.classList.add('bulk-tab-right', 'tab-panel-right'); + + this.pendingDiv = document.createElement('div'); + this.pendingDiv.classList.add("results-pending-overlay"); + this.pendingResults = new ResultsViewer(this.pendingDiv); + this.pendingResults.hideAll(); + + this.contentContainer.appendChild(this.leftPanel); + this.contentContainer.appendChild(this.rightPanel); + this.contentContainer.appendChild(this.pendingDiv); + + this.doCombos = true; + this.fastMode = true; + this.autoGem = true; + this.autoEnchant = true; + this.defaultGems = [UIGem.create(), UIGem.create(), UIGem.create(), UIGem.create()]; + this.gemIconElements = []; + this.buildTabContent(); + + this.simUI.sim.waitForInit().then(() => { + this.loadSettings(); + }); + } + + private getSettingsKey(): string { + return this.simUI.getStorageKey("bulk-settings.v1"); + } + + private loadSettings() { + const storedSettings = window.localStorage.getItem(this.getSettingsKey()); + if (storedSettings != null) { + let settings = BulkSettings.fromJsonString(storedSettings, { ignoreUnknownFields: true }) + + this.doCombos = settings.combinations; + this.fastMode = settings.fastMode; + this.autoEnchant = settings.autoEnchant; + this.autoGem = settings.autoGem; + this.defaultGems = new Array( + SimGem.create({ id: settings.defaultRedGem }), + SimGem.create({ id: settings.defaultYellowGem }), + SimGem.create({ id: settings.defaultBlueGem }), + SimGem.create({ id: settings.defaultMetaGem }), + ) + + this.defaultGems.forEach((gem, idx) => { + ActionId.fromItemId(gem.id).fill().then(filledId => { + this.gemIconElements[idx].src = filledId.iconUrl; + }); + }); + + } + } + + private storeSettings() { + const settings = this.createBulkSettings(); + const setStr = BulkSettings.toJsonString(settings, { enumAsInteger: true }) + window.localStorage.setItem(this.getSettingsKey(), setStr); + } + + + protected createBulkSettings(): BulkSettings { + + return BulkSettings.create({ + items: this.items, + // TODO(Riotdog-GehennasEU): Make all of these configurable. + // For now, it's always constant iteration combinations mode for "sim my bags". + combinations: this.doCombos, + fastMode: this.fastMode, + autoEnchant: this.autoEnchant, + autoGem: this.autoGem, + defaultRedGem: this.defaultGems[0].id, + defaultYellowGem: this.defaultGems[1].id, + defaultBlueGem: this.defaultGems[2].id, + defaultMetaGem: this.defaultGems[3].id, + iterationsPerCombo: this.simUI.sim.getIterations(), // TODO(Riotdog-GehennasEU): Define a new UI element for the iteration setting. + }); + } + + protected createBulkItemsDatabase(): SimDatabase { + const itemsDb = SimDatabase.create(); + for (const is of this.items) { + const item = this.simUI.sim.db.lookupItemSpec(is) + if (!item) { + throw new Error(`item with ID ${is.id} not found in database`); + } + itemsDb.items.push(SimItem.fromJson(UIItem.toJson(item.item), { ignoreUnknownFields: true })) + if (item.enchant) { + itemsDb.enchants.push(SimEnchant.fromJson(UIEnchant.toJson(item.enchant), { ignoreUnknownFields: true })); + } + for (const gem of item.gems) { + if (gem) { + itemsDb.gems.push(SimGem.fromJson(UIGem.toJson(gem), { ignoreUnknownFields: true })); + } + } + } + for (const gem of this.defaultGems) { + if (gem.id > 0) { + itemsDb.gems.push(gem); + } + } + return itemsDb; + } + + addItems(items: Array) { + if (this.items.length == 0) { + this.items = items; + } else { + this.items = this.items.concat(items); + } + this.itemsChangedEmitter.emit(TypedEvent.nextEventID()); + } + + setItems(items: Array) { + this.items = items; + this.itemsChangedEmitter.emit(TypedEvent.nextEventID()); + } + + clearItems() { + this.items = new Array(); + this.itemsChangedEmitter.emit(TypedEvent.nextEventID()); + } + + getItems(): Array { + const result = new Array(); + this.items.forEach((spec) => { result.push(ItemSpec.clone(spec)); }); + return result; + } + + setCombinations(doCombos: boolean) { + this.doCombos = doCombos; + this.itemsChangedEmitter.emit(TypedEvent.nextEventID()); + } + + setFastMode(fastMode: boolean) { + this.fastMode = fastMode; + this.itemsChangedEmitter.emit(TypedEvent.nextEventID()); + } + + protected async runBulkSim(onProgress: Function) { + this.pendingResults.setPending(); + + try { + await this.simUI.sim.runBulkSim(this.createBulkSettings(), this.createBulkItemsDatabase(), onProgress); + } catch (e) { + this.simUI.handleCrash(e); + } + } + + protected buildTabContent() { + const itemsBlock = new ContentBlock(this.column1, 'bulk-items', { + header: { title: 'Items' } + }); + + itemsBlock.bodyElement.classList.add('gear-picker-root'); + + const noticeWorkInProgress = document.createElement('div'); + noticeWorkInProgress.classList.add('bulk-items-text-line'); + itemsBlock.bodyElement.appendChild(noticeWorkInProgress); + noticeWorkInProgress.innerHTML = 'Notice: This is under very early but active development and experimental. You may also need to update your WoW AddOn if you want to import your bags.' + + const itemTextIntro = document.createElement('div'); + itemTextIntro.classList.add('bulk-items-text-line'); + itemsBlock.bodyElement.appendChild(itemTextIntro); + + const itemList = document.createElement('div'); + + itemList.classList.add('tab-panel-col', 'bulk-gear-combo'); + itemsBlock.bodyElement.appendChild(itemList); + + this.itemsChangedEmitter.on(() => { + itemList.innerHTML = ''; + if (this.items.length > 0) { + itemTextIntro.textContent = 'The following items will be simmed together with your equipped gear.'; + for (let i = 0; i < this.items.length; ++i) { + const spec = this.items[i]; + const item = this.simUI.sim.db.lookupItemSpec(spec); + const bulkItemPicker = new BulkItemPicker(itemList, this.simUI, this, item!, i); + } + } + }); + + this.clearItems(); + + let resultsBlock = new ContentBlock(this.column1, 'bulk-results', { + header: { + title: 'Results', + extraCssClasses: ['bulk-results-header'], + }, + }); + + resultsBlock.rootElem.hidden = true; + resultsBlock.bodyElement.classList.add('gear-picker-root', 'tab-panel-col'); + + this.simUI.sim.bulkSimStartEmitter.on(() => { + resultsBlock.rootElem.hidden = true; + }); + + this.simUI.sim.bulkSimResultEmitter.on((_, bulkSimResult) => { + resultsBlock.rootElem.hidden = bulkSimResult.results.length == 0; + resultsBlock.bodyElement.innerHTML = ''; + + for (const r of bulkSimResult.results) { + const resultBlock = new ContentBlock(resultsBlock.bodyElement, 'bulk-result', { header: { title: '' }, bodyClasses: ['bulk-results-body'] }); + new BulkSimResultRenderer(resultBlock, this.simUI, r, bulkSimResult.equippedGearResult!); + } + }); + + const settingsBlock = new ContentBlock(this.rightPanel, 'bulk-settings', { + header: { title: 'Setup' } + }); + + const bulkSimButton = document.createElement('button'); + bulkSimButton.classList.add('btn', 'btn-primary', 'w-100', 'bulk-settings-button'); + bulkSimButton.textContent = 'Simulate Batch'; + bulkSimButton.addEventListener('click', () => { + + this.pendingDiv.style.display = "flex"; + this.leftPanel.classList.add("blurred"); + this.rightPanel.classList.add("blurred"); + + const previousContents = bulkSimButton.innerHTML; + bulkSimButton.disabled = true; + bulkSimButton.classList.add(".disabled"); + bulkSimButton.innerHTML = ` Running`; + + + let simStart = new Date().getTime(); + let lastTotal = 0; + let rounds = 0; + let currentRound = 0; + let combinations = 0; + + this.runBulkSim((progressMetrics: ProgressMetrics) => { + console.log(progressMetrics); + + const msSinceStart = new Date().getTime() - simStart; + const iterPerSecond = progressMetrics.completedIterations / (msSinceStart / 1000); + + if (combinations == 0) { + combinations = progressMetrics.totalSims; + } + if (this.fastMode) { + if (rounds == 0 && progressMetrics.totalSims > 0) { + rounds = Math.ceil(Math.log(progressMetrics.totalSims / 20) / Math.log(2)) + 1; + currentRound = 1; + } + if (progressMetrics.totalSims < lastTotal) { + currentRound += 1; + simStart = new Date().getTime(); + } + } + + this.setSimProgress(progressMetrics, iterPerSecond, currentRound, rounds, combinations); + lastTotal = progressMetrics.totalSims; + + if (progressMetrics.finalBulkResult != null) { + // reset state + this.pendingDiv.style.display = "none"; + this.leftPanel.classList.remove("blurred"); + this.rightPanel.classList.remove("blurred"); + + this.pendingResults.hideAll(); + bulkSimButton.disabled = false; + bulkSimButton.classList.remove(".disabled"); + bulkSimButton.innerHTML = previousContents; + } + }); + }); + + settingsBlock.bodyElement.appendChild(bulkSimButton); + + const importButton = document.createElement('button'); + importButton.classList.add('btn', 'btn-secondary', 'w-100', 'bulk-settings-button'); + importButton.innerHTML = ' Import From Bags'; + importButton.addEventListener('click', () => new BulkGearJsonImporter(this.simUI.rootElem, this.simUI, this)); + settingsBlock.bodyElement.appendChild(importButton); + + const importFavsButton = document.createElement('button'); + importFavsButton.classList.add('btn', 'btn-secondary', 'w-100', 'bulk-settings-button'); + importFavsButton.innerHTML = ' Import Favorites'; + importFavsButton.addEventListener('click', () => { + const filters = this.simUI.player.sim.getFilters(); + const items = filters.favoriteItems.map((itemID) => { + return ItemSpec.create({ id: itemID }); + }); + this.addItems(items); + }); + settingsBlock.bodyElement.appendChild(importFavsButton); + + const searchButton = document.createElement('button'); + let searchText = document.createElement('input'); + searchText.type = "text"; + searchText.placeholder = "search..."; + searchText.style.display = "none"; + + const searchResults = document.createElement('ul'); + searchResults.classList.add("batch-search-results"); + + let allItems = Array(); + + searchText.addEventListener("keyup", ev => { + if (ev.key == "Enter") { + let toAdd = Array(); + searchResults.childNodes.forEach((node) => { + const strID = (node as HTMLElement).getAttribute('data-item-id'); + if (strID != null) { + toAdd.push(ItemSpec.create({ id: Number.parseInt(strID) })); + } + }); + this.addItems(toAdd); + } + }); + + searchText.addEventListener("input", (e) => { + const searchString = searchText.value; + searchResults.innerHTML = ""; + if (searchString.length == 0) { + return; + } + var pieces = searchString.split(' '); + + let displayCount = 0; + allItems.every((item) => { + let matched = true; + const lcName = item.name.toLowerCase(); + const lcSetName = item.setName.toLowerCase(); + + pieces.forEach((piece) => { + var lcPiece = piece.toLowerCase(); + if (!lcName.includes(lcPiece) && !lcSetName.includes(lcPiece)) { + matched = false; + return false; + } + return true; + }) + + if (matched) { + let itemElement = document.createElement('li'); + itemElement.innerHTML = `${item.name}`; + itemElement.setAttribute("data-item-id", item.id.toString()); + itemElement.addEventListener("click", (ev) => { + this.addItems(Array(ItemSpec.create({ id: item.id }))); + }) + if (item.heroic) { + let htxt = document.createElement("span"); + htxt.style.color = "green"; + htxt.innerText = "[H]"; + itemElement.appendChild(htxt); + } + if (item.factionRestriction == UIItem_FactionRestriction.HORDE_ONLY) { + let ftxt = document.createElement("span"); + ftxt.style.color = "red"; + ftxt.innerText = "(H)"; + itemElement.appendChild(ftxt); + } + if (item.factionRestriction == UIItem_FactionRestriction.ALLIANCE_ONLY) { + let ftxt = document.createElement("span"); + ftxt.style.color = "blue"; + ftxt.innerText = "(A)"; + itemElement.appendChild(ftxt); + } + searchResults.append(itemElement); + displayCount++; + } + + return displayCount < 10; + }); + }); + + searchButton.classList.add('btn', 'btn-secondary', 'w-100', 'bulk-settings-button'); + const baseSearchHTML = ' Add Item'; + searchButton.innerHTML = baseSearchHTML; + searchButton.addEventListener('click', () => { + if (searchText.style.display == "none") { + searchButton.innerHTML = 'Close Search Results'; + allItems = this.simUI.sim.db.getAllItems().filter((item) => { + return canEquipItem(item, this.simUI.player.spec, undefined); + }) + searchText.style.display = "block"; + searchText.focus(); + } else { + searchButton.innerHTML = baseSearchHTML; + searchText.style.display = "none"; + searchResults.innerHTML = ""; + } + }); + settingsBlock.bodyElement.appendChild(searchButton); + settingsBlock.bodyElement.appendChild(searchText); + settingsBlock.bodyElement.appendChild(searchResults); + + const clearButton = document.createElement('button'); + clearButton.classList.add('btn', 'btn-secondary', 'w-100', 'bulk-settings-button'); + clearButton.textContent = 'Clear All'; + clearButton.addEventListener('click', () => { + this.clearItems(); + resultsBlock.rootElem.hidden = true; + resultsBlock.bodyElement.innerHTML = ''; + }); + settingsBlock.bodyElement.appendChild(clearButton); + + // Default Gem Options + const defaultGemDiv = document.createElement("div"); + if (this.autoGem) { + defaultGemDiv.style.display = "flex"; + } else { + defaultGemDiv.style.display = "none"; + } + + defaultGemDiv.classList.add("default-gem-container"); + const gemLabel = document.createElement("label"); + gemLabel.innerText = "Defaults for Auto Gem"; + defaultGemDiv.appendChild(gemLabel); + + const gemSocketsDiv = document.createElement("div"); + gemSocketsDiv.classList.add("sockets-container"); + + Array(GemColor.GemColorRed, GemColor.GemColorYellow, GemColor.GemColorBlue, GemColor.GemColorMeta).forEach((socketColor, socketIndex) => { + let gemFragment = document.createElement('fragment'); + gemFragment.innerHTML = `
    `; - const gemContainer = gemFragment.children[0] as HTMLElement; - this.gemIconElements.push(gemContainer.querySelector('.gem-icon') as HTMLImageElement); - const socketIconElem = gemContainer.querySelector('.socket-icon') as HTMLImageElement; - socketIconElem.src = getEmptyGemSocketIconUrl(socketColor); - - let selector: GemSelectorModal; - - let handleChoose = (itemData: ItemData) => { - this.defaultGems[socketIndex] = itemData.item; - this.storeSettings(); - ActionId.fromItemId(itemData.id).fill().then(filledId => { - this.gemIconElements[socketIndex].src = filledId.iconUrl; - }); - selector.close(); - }; - - let openGemSelector = (color: GemColor, socketIndex: number) => { - return (event: Event) => { - if (selector == null) { - selector = new GemSelectorModal(this.simUI.rootElem, this.simUI, socketColor, handleChoose); - } - selector.show(); - } - } - - this.gemIconElements[socketIndex].addEventListener("click", openGemSelector(socketColor, socketIndex)); - gemContainer.addEventListener("click", openGemSelector(socketColor, socketIndex)); - gemSocketsDiv.appendChild(gemContainer); - }); - defaultGemDiv.appendChild(gemSocketsDiv); - - new BooleanPicker(settingsBlock.bodyElement, this, { - label: "Fast Mode", - labelTooltip: "Fast mode reduces accuracy but will run faster.", - changedEvent: (obj: BulkTab) => this.itemsChangedEmitter, - getValue: (obj) => this.fastMode, - setValue: (id: EventID, obj: BulkTab, value: boolean) => { obj.fastMode = value } - }); - new BooleanPicker(settingsBlock.bodyElement, this, { - label: "Combinations", - labelTooltip: "When checked bulk simulator will create all possible combinations of the items. When disabled trinkets and rings will still run all combinations becausee they have two slots to fill each.", - changedEvent: (obj: BulkTab) => this.itemsChangedEmitter, - getValue: (obj) => this.doCombos, - setValue: (id: EventID, obj: BulkTab, value: boolean) => { obj.doCombos = value } - }); - new BooleanPicker(settingsBlock.bodyElement, this, { - label: "Auto Enchant", - labelTooltip: "When checked bulk simulator apply the current enchant for a slot to each replacement item it can.", - changedEvent: (obj: BulkTab) => this.itemsChangedEmitter, - getValue: (obj) => this.autoEnchant, - setValue: (id: EventID, obj: BulkTab, value: boolean) => { - obj.autoEnchant = value - if (value) { - defaultGemDiv.style.display = "flex"; - } else { - defaultGemDiv.style.display = "none"; - } - } - }); - new BooleanPicker(settingsBlock.bodyElement, this, { - label: "Auto Gem", - labelTooltip: "When checked bulk simulator will fill any un-filled gem sockets with default gems.", - changedEvent: (obj: BulkTab) => this.itemsChangedEmitter, - getValue: (obj) => this.autoGem, - setValue: (id: EventID, obj: BulkTab, value: boolean) => { - obj.autoGem = value - if (value) { - defaultGemDiv.style.display = "flex"; - } else { - defaultGemDiv.style.display = "none"; - } - } - }); - - settingsBlock.bodyElement.appendChild(defaultGemDiv); - } - - private setSimProgress(progress: ProgressMetrics, iterPerSecond: number, currentRound: number, rounds: number, combinations: number) { - const secondsRemain = ((progress.totalIterations - progress.completedIterations) / iterPerSecond).toFixed(); - - let roundsText = ""; - if (rounds > 0) { - roundsText = `${currentRound} / ${rounds} refining rounds`; - } - - this.pendingResults.setContent(` + const gemContainer = gemFragment.children[0] as HTMLElement; + this.gemIconElements.push(gemContainer.querySelector('.gem-icon') as HTMLImageElement); + const socketIconElem = gemContainer.querySelector('.socket-icon') as HTMLImageElement; + socketIconElem.src = getEmptyGemSocketIconUrl(socketColor); + + let selector: GemSelectorModal; + + let handleChoose = (itemData: ItemData) => { + this.defaultGems[socketIndex] = itemData.item; + this.storeSettings(); + ActionId.fromItemId(itemData.id).fill().then(filledId => { + this.gemIconElements[socketIndex].src = filledId.iconUrl; + }); + selector.close(); + }; + + let openGemSelector = (color: GemColor, socketIndex: number) => { + return (event: Event) => { + if (selector == null) { + selector = new GemSelectorModal(this.simUI.rootElem, this.simUI, socketColor, handleChoose); + } + selector.show(); + } + } + + this.gemIconElements[socketIndex].addEventListener("click", openGemSelector(socketColor, socketIndex)); + gemContainer.addEventListener("click", openGemSelector(socketColor, socketIndex)); + gemSocketsDiv.appendChild(gemContainer); + }); + defaultGemDiv.appendChild(gemSocketsDiv); + + new BooleanPicker(settingsBlock.bodyElement, this, { + label: "Fast Mode", + labelTooltip: "Fast mode reduces accuracy but will run faster.", + changedEvent: (obj: BulkTab) => this.itemsChangedEmitter, + getValue: (obj) => this.fastMode, + setValue: (id: EventID, obj: BulkTab, value: boolean) => { obj.fastMode = value } + }); + new BooleanPicker(settingsBlock.bodyElement, this, { + label: "Combinations", + labelTooltip: "When checked bulk simulator will create all possible combinations of the items. When disabled trinkets and rings will still run all combinations becausee they have two slots to fill each.", + changedEvent: (obj: BulkTab) => this.itemsChangedEmitter, + getValue: (obj) => this.doCombos, + setValue: (id: EventID, obj: BulkTab, value: boolean) => { obj.doCombos = value } + }); + new BooleanPicker(settingsBlock.bodyElement, this, { + label: "Auto Enchant", + labelTooltip: "When checked bulk simulator apply the current enchant for a slot to each replacement item it can.", + changedEvent: (obj: BulkTab) => this.itemsChangedEmitter, + getValue: (obj) => this.autoEnchant, + setValue: (id: EventID, obj: BulkTab, value: boolean) => { + obj.autoEnchant = value + if (value) { + defaultGemDiv.style.display = "flex"; + } else { + defaultGemDiv.style.display = "none"; + } + } + }); + new BooleanPicker(settingsBlock.bodyElement, this, { + label: "Auto Gem", + labelTooltip: "When checked bulk simulator will fill any un-filled gem sockets with default gems.", + changedEvent: (obj: BulkTab) => this.itemsChangedEmitter, + getValue: (obj) => this.autoGem, + setValue: (id: EventID, obj: BulkTab, value: boolean) => { + obj.autoGem = value + if (value) { + defaultGemDiv.style.display = "flex"; + } else { + defaultGemDiv.style.display = "none"; + } + } + }); + + settingsBlock.bodyElement.appendChild(defaultGemDiv); + } + + private setSimProgress(progress: ProgressMetrics, iterPerSecond: number, currentRound: number, rounds: number, combinations: number) { + const secondsRemain = ((progress.totalIterations - progress.completedIterations) / iterPerSecond).toFixed(); + + let roundsText = ""; + if (rounds > 0) { + roundsText = `${currentRound} / ${rounds} refining rounds`; + } + + this.pendingResults.setContent(`
    ${combinations} total combinations.
    ${roundsText}
    @@ -786,90 +786,90 @@ export class BulkTab extends SimTab {
    `); - } + } } class GemSelectorModal extends BaseModal { - private readonly simUI: IndividualSimUI; - - private readonly contentElem: HTMLElement; - private ilist: ItemList | null; - private socketColor: GemColor; - private onSelect: (itemData: ItemData) => void; - - constructor(parent: HTMLElement, simUI: IndividualSimUI, socketColor: GemColor, onSelect: (itemData: ItemData) => void) { - super(parent, 'selector-modal'); - - this.simUI = simUI; - this.onSelect = onSelect; - this.socketColor = socketColor; - this.ilist = null; - - window.scrollTo({ top: 0 }); - - this.header!.insertAdjacentHTML('afterbegin', `Choose Default Gem`); - this.body.innerHTML = `
    ` - this.contentElem = this.rootElem.querySelector('.selector-modal-tab-content') as HTMLElement; - } - - show() { - // construct item list the first time its opened. - // This makes startup faster and also means we are sure to have item database loaded. - if (this.ilist == null) { - this.ilist = new ItemList( - this.body, - this.simUI, - { - selectedTab: SelectorModalTabs.Gem1, - slot: ItemSlot.ItemSlotHead, - equippedItem: null, - eligibleItems: new Array(), - eligibleEnchants: new Array(), - gearData: { - equipItem: (eventID: EventID, equippedItem: EquippedItem | null) => { }, - getEquippedItem: () => null, - changeEvent: new TypedEvent(), // FIXME - }, - }, - this.simUI.player, - "Gem1", - this.simUI.player.getGems(this.socketColor).map((gem: UIGem) => { - return { - item: gem, - id: gem.id, - actionId: ActionId.fromItemId(gem.id), - name: gem.name, - quality: gem.quality, - phase: gem.phase, - heroic: false, - baseEP: 0, - ignoreEPFilter: true, - onEquip: (eventID, gem: UIGem) => { - }, - }; - }), - gem => { - return this.simUI.player.computeGemEP(gem); - }, - () => { return null }, - this.socketColor, - () => { }, - this.onSelect - ) - - // let invokeUpdate = () => {this.ilist?.updateSelected()} - let applyFilter = () => { this.ilist?.applyFilters() } - // Add event handlers - // this.itemsChangedEmitter.on(invokeUpdate); - - // this.addOnDisposeCallback(() => gearData.changeEvent.off(invokeUpdate)); - - this.simUI.sim.phaseChangeEmitter.on(applyFilter); - this.simUI.sim.filtersChangeEmitter.on(applyFilter); - // gearData.changeEvent.on(applyFilter); - } - - this.open(); - } + private readonly simUI: IndividualSimUI; + + private readonly contentElem: HTMLElement; + private ilist: ItemList | null; + private socketColor: GemColor; + private onSelect: (itemData: ItemData) => void; + + constructor(parent: HTMLElement, simUI: IndividualSimUI, socketColor: GemColor, onSelect: (itemData: ItemData) => void) { + super(parent, 'selector-modal'); + + this.simUI = simUI; + this.onSelect = onSelect; + this.socketColor = socketColor; + this.ilist = null; + + window.scrollTo({ top: 0 }); + + this.header!.insertAdjacentHTML('afterbegin', `Choose Default Gem`); + this.body.innerHTML = `
    ` + this.contentElem = this.rootElem.querySelector('.selector-modal-tab-content') as HTMLElement; + } + + show() { + // construct item list the first time its opened. + // This makes startup faster and also means we are sure to have item database loaded. + if (this.ilist == null) { + this.ilist = new ItemList( + this.body, + this.simUI, + { + selectedTab: SelectorModalTabs.Gem1, + slot: ItemSlot.ItemSlotHead, + equippedItem: null, + eligibleItems: new Array(), + eligibleEnchants: new Array(), + gearData: { + equipItem: (eventID: EventID, equippedItem: EquippedItem | null) => { }, + getEquippedItem: () => null, + changeEvent: new TypedEvent(), // FIXME + }, + }, + this.simUI.player, + "Gem1", + this.simUI.player.getGems(this.socketColor).map((gem: UIGem) => { + return { + item: gem, + id: gem.id, + actionId: ActionId.fromItemId(gem.id), + name: gem.name, + quality: gem.quality, + phase: gem.phase, + heroic: false, + baseEP: 0, + ignoreEPFilter: true, + onEquip: (eventID, gem: UIGem) => { + }, + }; + }), + gem => { + return this.simUI.player.computeGemEP(gem); + }, + () => { return null }, + this.socketColor, + () => { }, + this.onSelect + ) + + // let invokeUpdate = () => {this.ilist?.updateSelected()} + let applyFilter = () => { this.ilist?.applyFilters() } + // Add event handlers + // this.itemsChangedEmitter.on(invokeUpdate); + + // this.addOnDisposeCallback(() => gearData.changeEvent.off(invokeUpdate)); + + this.simUI.sim.phaseChangeEmitter.on(applyFilter); + this.simUI.sim.filtersChangeEmitter.on(applyFilter); + // gearData.changeEvent.on(applyFilter); + } + + this.open(); + } } \ No newline at end of file diff --git a/ui/core/components/individual_sim_ui/consumes_picker.ts b/ui/core/components/individual_sim_ui/consumes_picker.ts index 571d85ce95..b8a71482f6 100644 --- a/ui/core/components/individual_sim_ui/consumes_picker.ts +++ b/ui/core/components/individual_sim_ui/consumes_picker.ts @@ -1,15 +1,15 @@ import { IndividualSimUI } from "../../individual_sim_ui"; import { - BattleElixir, - Class, - Conjured, - Flask, - Food, - GuardianElixir, - Potions, - Profession, - Spec, - Stat + BattleElixir, + Class, + Conjured, + Flask, + Food, + GuardianElixir, + Potions, + Profession, + Spec, + Stat } from "../../proto/common"; import { Component } from "../component"; import { IconEnumPicker } from "../icon_enum_picker"; @@ -19,24 +19,24 @@ import { buildIconInput } from "../icon_inputs.js"; import { SettingsTab } from "./settings_tab"; export class ConsumesPicker extends Component { - protected settingsTab: SettingsTab; - protected simUI: IndividualSimUI; + protected settingsTab: SettingsTab; + protected simUI: IndividualSimUI; - constructor(parentElem: HTMLElement, settingsTab: SettingsTab, simUI: IndividualSimUI) { - super(parentElem, 'consumes-picker-root'); - this.settingsTab = settingsTab; - this.simUI = simUI; + constructor(parentElem: HTMLElement, settingsTab: SettingsTab, simUI: IndividualSimUI) { + super(parentElem, 'consumes-picker-root'); + this.settingsTab = settingsTab; + this.simUI = simUI; - this.buildPotionsPicker(); - this.buildElixirsPicker(); - this.buildFoodPicker(); - this.buildEngPicker(); - this.buildPetPicker(); - } + this.buildPotionsPicker(); + this.buildElixirsPicker(); + this.buildFoodPicker(); + this.buildEngPicker(); + this.buildPetPicker(); + } - private buildPotionsPicker() { - let fragment = document.createElement('fragment'); - fragment.innerHTML = ` + private buildPotionsPicker() { + let fragment = document.createElement('fragment'); + fragment.innerHTML = `
    @@ -47,9 +47,9 @@ export class ConsumesPicker extends Component {
    `; - this.rootElem.appendChild(fragment.children[0] as HTMLElement); + this.rootElem.appendChild(fragment.children[0] as HTMLElement); - const prepopPotionOptions = this.simUI.splitRelevantOptions([ + const prepopPotionOptions = this.simUI.splitRelevantOptions([ // This list is smaller because some potions don't make sense to use as prepot. // E.g. healing/mana potions. { item: Potions.IndestructiblePotion, stats: [Stat.StatArmor] }, @@ -61,11 +61,11 @@ export class ConsumesPicker extends Component { if (prepopPotionOptions.length) { const elem = this.rootElem.querySelector('.consumes-prepot') as HTMLElement; new IconEnumPicker( - elem, - this.simUI.player, - IconInputs.makePrepopPotionsInput(prepopPotionOptions, 'Prepop Potion (1s before combat)') - ); - } + elem, + this.simUI.player, + IconInputs.makePrepopPotionsInput(prepopPotionOptions, 'Prepop Potion (1s before combat)') + ); + } const potionOptions = this.simUI.splitRelevantOptions([ { item: Potions.RunicHealingPotion, stats: [Stat.StatStamina] }, @@ -81,10 +81,10 @@ export class ConsumesPicker extends Component { if (potionOptions.length) { const elem = this.rootElem.querySelector('.consumes-potions') as HTMLElement; new IconEnumPicker( - elem, - this.simUI.player, - IconInputs.makePotionsInput(potionOptions, 'Combat Potion') - ); + elem, + this.simUI.player, + IconInputs.makePotionsInput(potionOptions, 'Combat Potion') + ); } const conjuredOptions = this.simUI.splitRelevantOptions([ @@ -97,11 +97,11 @@ export class ConsumesPicker extends Component { const elem = this.rootElem.querySelector('.consumes-conjured') as HTMLElement; new IconEnumPicker(elem, this.simUI.player, IconInputs.makeConjuredInput(conjuredOptions)); } - } + } - private buildElixirsPicker() { - let fragment = document.createElement('fragment'); - fragment.innerHTML = ` + private buildElixirsPicker() { + let fragment = document.createElement('fragment'); + fragment.innerHTML = `
    @@ -113,9 +113,9 @@ export class ConsumesPicker extends Component {
    `; - this.rootElem.appendChild(fragment.children[0] as HTMLElement); + this.rootElem.appendChild(fragment.children[0] as HTMLElement); - const flaskOptions = this.simUI.splitRelevantOptions([ + const flaskOptions = this.simUI.splitRelevantOptions([ { item: Flask.FlaskOfTheFrostWyrm, stats: [Stat.StatSpellPower] }, { item: Flask.FlaskOfEndlessRage, stats: [Stat.StatAttackPower, Stat.StatRangedAttackPower] }, { item: Flask.FlaskOfPureMojo, stats: [Stat.StatMP5] }, @@ -126,10 +126,10 @@ export class ConsumesPicker extends Component { if (flaskOptions.length) { const elem = this.rootElem.querySelector('.consumes-flasks') as HTMLElement; new IconEnumPicker( - elem, - this.simUI.player, - IconInputs.makeFlasksInput(flaskOptions, 'Flask') - ); + elem, + this.simUI.player, + IconInputs.makeFlasksInput(flaskOptions, 'Flask') + ); } const battleElixirOptions = this.simUI.splitRelevantOptions([ @@ -145,16 +145,16 @@ export class ConsumesPicker extends Component { { item: BattleElixir.WrathElixir, stats: [Stat.StatAttackPower, Stat.StatRangedAttackPower] }, ]); - const battleElixirsContainer = this.rootElem.querySelector('.consumes-battle-elixirs') as HTMLElement; + const battleElixirsContainer = this.rootElem.querySelector('.consumes-battle-elixirs') as HTMLElement; if (battleElixirOptions.length) { new IconEnumPicker( - battleElixirsContainer, - this.simUI.player, - IconInputs.makeBattleElixirsInput(battleElixirOptions, 'Battle Elixir') - ); + battleElixirsContainer, + this.simUI.player, + IconInputs.makeBattleElixirsInput(battleElixirOptions, 'Battle Elixir') + ); } else { - battleElixirsContainer.remove(); - } + battleElixirsContainer.remove(); + } const guardianElixirOptions = this.simUI.splitRelevantOptions([ { item: GuardianElixir.ElixirOfMightyDefense, stats: [Stat.StatDefense] }, @@ -166,22 +166,22 @@ export class ConsumesPicker extends Component { { item: GuardianElixir.GiftOfArthas, stats: [Stat.StatStamina] }, ]); - const guardianElixirsContainer = this.rootElem.querySelector('.consumes-guardian-elixirs') as HTMLElement; + const guardianElixirsContainer = this.rootElem.querySelector('.consumes-guardian-elixirs') as HTMLElement; if (guardianElixirOptions.length) { const guardianElixirsContainer = this.rootElem.querySelector('.consumes-guardian-elixirs') as HTMLElement; new IconEnumPicker( - guardianElixirsContainer, - this.simUI.player, - IconInputs.makeGuardianElixirsInput(guardianElixirOptions, 'Guardian Elixir') - ); + guardianElixirsContainer, + this.simUI.player, + IconInputs.makeGuardianElixirsInput(guardianElixirOptions, 'Guardian Elixir') + ); } else { - guardianElixirsContainer.remove(); - } - } + guardianElixirsContainer.remove(); + } + } - private buildFoodPicker() { - let fragment = document.createElement('fragment'); - fragment.innerHTML = ` + private buildFoodPicker() { + let fragment = document.createElement('fragment'); + fragment.innerHTML = `
    @@ -190,9 +190,9 @@ export class ConsumesPicker extends Component {
    `; - this.rootElem.appendChild(fragment.children[0] as HTMLElement); + this.rootElem.appendChild(fragment.children[0] as HTMLElement); - const foodOptions = this.simUI.splitRelevantOptions([ + const foodOptions = this.simUI.splitRelevantOptions([ { item: Food.FoodFishFeast, stats: [Stat.StatStamina, Stat.StatAttackPower, Stat.StatRangedAttackPower, Stat.StatSpellPower] }, { item: Food.FoodGreatFeast, stats: [Stat.StatStamina, Stat.StatAttackPower, Stat.StatRangedAttackPower, Stat.StatSpellPower] }, { item: Food.FoodBlackenedDragonfin, stats: [Stat.StatAgility] }, @@ -211,20 +211,20 @@ export class ConsumesPicker extends Component { const elem = this.rootElem.querySelector('.consumes-food') as HTMLElement; new IconEnumPicker(elem, this.simUI.player, IconInputs.makeFoodInput(foodOptions)); } - } + } - private buildEngPicker() { - let fragment = document.createElement('fragment'); - fragment.innerHTML = ` + private buildEngPicker() { + let fragment = document.createElement('fragment'); + fragment.innerHTML = `
    `; - this.rootElem.appendChild(fragment.children[0] as HTMLElement); + this.rootElem.appendChild(fragment.children[0] as HTMLElement); - const tradeConsumesElem = this.rootElem.querySelector('.consumes-trade') as HTMLElement; + const tradeConsumesElem = this.rootElem.querySelector('.consumes-trade') as HTMLElement; buildIconInput(tradeConsumesElem, this.simUI.player, IconInputs.ThermalSapper); buildIconInput(tradeConsumesElem, this.simUI.player, IconInputs.ExplosiveDecoy); @@ -238,22 +238,22 @@ export class ConsumesPicker extends Component { }; this.simUI.player.professionChangeEmitter.on(updateProfession); updateProfession(); - } + } - private buildPetPicker() { - if (this.simUI.individualConfig.petConsumeInputs?.length) { - let fragment = document.createElement('fragment'); - fragment.innerHTML = ` + private buildPetPicker() { + if (this.simUI.individualConfig.petConsumeInputs?.length) { + let fragment = document.createElement('fragment'); + fragment.innerHTML = `
    `; - this.rootElem.appendChild(fragment.children[0] as HTMLElement); + this.rootElem.appendChild(fragment.children[0] as HTMLElement); - const petConsumesElem = this.rootElem.querySelector('.consumes-pet') as HTMLElement; + const petConsumesElem = this.rootElem.querySelector('.consumes-pet') as HTMLElement; this.simUI.individualConfig.petConsumeInputs.map(iconInput => buildIconInput(petConsumesElem, this.simUI.player, iconInput)); } - } + } } diff --git a/ui/core/components/individual_sim_ui/custom_rotation_picker.ts b/ui/core/components/individual_sim_ui/custom_rotation_picker.ts index 4654b0b3b9..7014d6edfa 100644 --- a/ui/core/components/individual_sim_ui/custom_rotation_picker.ts +++ b/ui/core/components/individual_sim_ui/custom_rotation_picker.ts @@ -56,7 +56,7 @@ class CustomSpellPicker extends Input private readonly spellIndex: number; private readonly spellPicker: Input; - private readonly cpmPicker: Input|null; + private readonly cpmPicker: Input | null; getSpell(): CustomSpell { return this.listPicker.config.getValue(this.player)[this.spellIndex] || CustomSpell.create(); diff --git a/ui/core/components/individual_sim_ui/gear_tab.ts b/ui/core/components/individual_sim_ui/gear_tab.ts index 1739e3406d..bf6f9a832a 100644 --- a/ui/core/components/individual_sim_ui/gear_tab.ts +++ b/ui/core/components/individual_sim_ui/gear_tab.ts @@ -11,63 +11,63 @@ import { SavedDataManager } from "../saved_data_manager"; import { SimTab } from "../sim_tab"; export class GearTab extends SimTab { - protected simUI: IndividualSimUI; + protected simUI: IndividualSimUI; - readonly leftPanel: HTMLElement; - readonly rightPanel: HTMLElement; + readonly leftPanel: HTMLElement; + readonly rightPanel: HTMLElement; - constructor(parentElem: HTMLElement, simUI: IndividualSimUI) { - super(parentElem, simUI, {identifier: 'gear-tab', title: 'Gear'}); - this.simUI = simUI; + constructor(parentElem: HTMLElement, simUI: IndividualSimUI) { + super(parentElem, simUI, { identifier: 'gear-tab', title: 'Gear' }); + this.simUI = simUI; - this.leftPanel = document.createElement('div'); - this.leftPanel.classList.add('gear-tab-left', 'tab-panel-left'); + this.leftPanel = document.createElement('div'); + this.leftPanel.classList.add('gear-tab-left', 'tab-panel-left'); - this.rightPanel = document.createElement('div'); - this.rightPanel.classList.add('gear-tab-right', 'tab-panel-right'); + this.rightPanel = document.createElement('div'); + this.rightPanel.classList.add('gear-tab-right', 'tab-panel-right'); - this.contentContainer.appendChild(this.leftPanel); - this.contentContainer.appendChild(this.rightPanel); + this.contentContainer.appendChild(this.leftPanel); + this.contentContainer.appendChild(this.rightPanel); - this.buildTabContent(); - } + this.buildTabContent(); + } - protected buildTabContent() { - this.buildGearPickers(); + protected buildTabContent() { + this.buildGearPickers(); - this.buildSavedGearsetPicker(); - } + this.buildSavedGearsetPicker(); + } - private buildGearPickers() { - new GearPicker(this.leftPanel, this.simUI, this.simUI.player); - } + private buildGearPickers() { + new GearPicker(this.leftPanel, this.simUI, this.simUI.player); + } - private buildSavedGearsetPicker() { - const savedGearManager = new SavedDataManager, SavedGearSet>(this.rightPanel, this.simUI, this.simUI.player, { - header: {title: "Gear Sets"}, - label: 'Gear Set', - storageKey: this.simUI.getSavedGearStorageKey(), - getData: (player: Player) => { - return SavedGearSet.create({ - gear: player.getGear().asSpec(), - bonusStatsStats: player.getBonusStats().toProto(), - }); - }, - setData: (eventID: EventID, player: Player, newSavedGear: SavedGearSet) => { - TypedEvent.freezeAllAndDo(() => { - player.setGear(eventID, this.simUI.sim.db.lookupEquipmentSpec(newSavedGear.gear || EquipmentSpec.create())); - if (newSavedGear.bonusStats && newSavedGear.bonusStats.some(s => s != 0)) { - player.setBonusStats(eventID, new Stats(newSavedGear.bonusStats)); - } else { - player.setBonusStats(eventID, Stats.fromProto(newSavedGear.bonusStatsStats || UnitStats.create())); - } - }); - }, - changeEmitters: [this.simUI.player.changeEmitter], - equals: (a: SavedGearSet, b: SavedGearSet) => SavedGearSet.equals(a, b), - toJson: (a: SavedGearSet) => SavedGearSet.toJson(a), - fromJson: (obj: any) => SavedGearSet.fromJson(obj), - }); + private buildSavedGearsetPicker() { + const savedGearManager = new SavedDataManager, SavedGearSet>(this.rightPanel, this.simUI, this.simUI.player, { + header: { title: "Gear Sets" }, + label: 'Gear Set', + storageKey: this.simUI.getSavedGearStorageKey(), + getData: (player: Player) => { + return SavedGearSet.create({ + gear: player.getGear().asSpec(), + bonusStatsStats: player.getBonusStats().toProto(), + }); + }, + setData: (eventID: EventID, player: Player, newSavedGear: SavedGearSet) => { + TypedEvent.freezeAllAndDo(() => { + player.setGear(eventID, this.simUI.sim.db.lookupEquipmentSpec(newSavedGear.gear || EquipmentSpec.create())); + if (newSavedGear.bonusStats && newSavedGear.bonusStats.some(s => s != 0)) { + player.setBonusStats(eventID, new Stats(newSavedGear.bonusStats)); + } else { + player.setBonusStats(eventID, Stats.fromProto(newSavedGear.bonusStatsStats || UnitStats.create())); + } + }); + }, + changeEmitters: [this.simUI.player.changeEmitter], + equals: (a: SavedGearSet, b: SavedGearSet) => SavedGearSet.equals(a, b), + toJson: (a: SavedGearSet) => SavedGearSet.toJson(a), + fromJson: (obj: any) => SavedGearSet.fromJson(obj), + }); this.simUI.sim.waitForInit().then(() => { savedGearManager.loadUserData(); @@ -85,5 +85,5 @@ export class GearTab extends SimTab { }); }); }); - } + } } diff --git a/ui/core/components/individual_sim_ui/rotation_tab.ts b/ui/core/components/individual_sim_ui/rotation_tab.ts index 05fa4edbe8..38b380c944 100644 --- a/ui/core/components/individual_sim_ui/rotation_tab.ts +++ b/ui/core/components/individual_sim_ui/rotation_tab.ts @@ -29,81 +29,81 @@ import * as Tooltips from '../../constants/tooltips.js'; import { APLRotationPicker } from "./apl_rotation_picker"; export class RotationTab extends SimTab { - protected simUI: IndividualSimUI; + protected simUI: IndividualSimUI; - readonly leftPanel: HTMLElement; - readonly rightPanel: HTMLElement; + readonly leftPanel: HTMLElement; + readonly rightPanel: HTMLElement; - constructor(parentElem: HTMLElement, simUI: IndividualSimUI) { - super(parentElem, simUI, {identifier: 'rotation-tab', title: 'Rotation'}); - this.simUI = simUI; + constructor(parentElem: HTMLElement, simUI: IndividualSimUI) { + super(parentElem, simUI, { identifier: 'rotation-tab', title: 'Rotation' }); + this.simUI = simUI; - this.leftPanel = document.createElement('div'); - this.leftPanel.classList.add('rotation-tab-left', 'tab-panel-left'); + this.leftPanel = document.createElement('div'); + this.leftPanel.classList.add('rotation-tab-left', 'tab-panel-left'); - this.rightPanel = document.createElement('div'); - this.rightPanel.classList.add('rotation-tab-right', 'tab-panel-right'); + this.rightPanel = document.createElement('div'); + this.rightPanel.classList.add('rotation-tab-right', 'tab-panel-right'); - this.contentContainer.appendChild(this.leftPanel); - this.contentContainer.appendChild(this.rightPanel); + this.contentContainer.appendChild(this.leftPanel); + this.contentContainer.appendChild(this.rightPanel); - this.buildTabContent(); + this.buildTabContent(); - this.updateSections(); - this.simUI.player.rotationChangeEmitter.on(() => this.updateSections()); - } + this.updateSections(); + this.simUI.player.rotationChangeEmitter.on(() => this.updateSections()); + } + + protected buildTabContent() { + this.buildHeader(); + this.buildContent(); + this.buildRotationSettings(); + this.buildCooldownSettings(); + this.buildSavedDataPickers(); + } + + private updateSections() { + if (this.simUI.player.aplRotation.enabled) { + this.rootElem.classList.add('rotation-type-apl'); + this.rootElem.classList.remove('rotation-type-legacy'); + } else { + this.rootElem.classList.remove('rotation-type-apl'); + this.rootElem.classList.add('rotation-type-legacy'); + } + } + + private buildHeader() { + const header = document.createElement('div'); + header.classList.add('rotation-tab-header'); + this.leftPanel.appendChild(header); + + new EnumPicker(header, this.simUI.player, { + label: 'Rotation Type', + labelTooltip: 'Whether to use the legacy rotation options, or the new APL rotation options.', + inline: true, + values: [ + { value: 0, name: 'Legacy' }, + { value: 1, name: 'APL' }, + ], + changedEvent: (player: Player) => player.rotationChangeEmitter, + getValue: (player: Player) => Number(player.aplRotation.enabled), + setValue: (eventID: EventID, player: Player, newValue: number) => { + player.aplRotation.enabled = !!newValue; + player.rotationChangeEmitter.emit(eventID); + }, + }); + } - protected buildTabContent() { - this.buildHeader(); - this.buildContent(); - this.buildRotationSettings(); - this.buildCooldownSettings(); - this.buildSavedDataPickers(); - } + private buildContent() { + const content = document.createElement('div'); + content.classList.add('rotation-tab-main'); + this.leftPanel.appendChild(content); - private updateSections() { - if (this.simUI.player.aplRotation.enabled) { - this.rootElem.classList.add('rotation-type-apl'); - this.rootElem.classList.remove('rotation-type-legacy'); - } else { - this.rootElem.classList.remove('rotation-type-apl'); - this.rootElem.classList.add('rotation-type-legacy'); + new APLRotationPicker(content, this.simUI, this.simUI.player); } - } - - private buildHeader() { - const header = document.createElement('div'); - header.classList.add('rotation-tab-header'); - this.leftPanel.appendChild(header); - - new EnumPicker(header, this.simUI.player, { - label: 'Rotation Type', - labelTooltip: 'Whether to use the legacy rotation options, or the new APL rotation options.', - inline: true, - values: [ - {value: 0, name: 'Legacy'}, - {value: 1, name: 'APL'}, - ], - changedEvent: (player: Player) => player.rotationChangeEmitter, - getValue: (player: Player) => Number(player.aplRotation.enabled), - setValue: (eventID: EventID, player: Player, newValue: number) => { - player.aplRotation.enabled = !!newValue; - player.rotationChangeEmitter.emit(eventID); - }, - }); - } - - private buildContent() { - const content = document.createElement('div'); - content.classList.add('rotation-tab-main'); - this.leftPanel.appendChild(content); - - new APLRotationPicker(content, this.simUI, this.simUI.player); - } private buildRotationSettings() { const contentBlock = new ContentBlock(this.leftPanel, 'rotation-settings', { - header: {title: 'Rotation'} + header: { title: 'Rotation' } }); const rotationIconGroup = Input.newGroupContainer(); @@ -127,7 +127,7 @@ export class RotationTab extends SimTab { private buildCooldownSettings() { const contentBlock = new ContentBlock(this.leftPanel, 'cooldown-settings', { - header: {title: 'Cooldowns', tooltip: Tooltips.COOLDOWNS_SECTION} + header: { title: 'Cooldowns', tooltip: Tooltips.COOLDOWNS_SECTION } }); new CooldownsPicker(contentBlock.bodyElement, this.simUI.player); @@ -138,12 +138,12 @@ export class RotationTab extends SimTab { if (inputConfig.type == 'number') { new NumberPicker(sectionElem, this.simUI.player, inputConfig); } else if (inputConfig.type == 'boolean') { - new BooleanPicker(sectionElem, this.simUI.player, {...inputConfig, ...{cssScheme: this.simUI.cssScheme}}); + new BooleanPicker(sectionElem, this.simUI.player, { ...inputConfig, ...{ cssScheme: this.simUI.cssScheme } }); } else if (inputConfig.type == 'enum') { new EnumPicker(sectionElem, this.simUI.player, inputConfig); } else if (inputConfig.type == 'customRotation') { new CustomRotationPicker(sectionElem, this.simUI, this.simUI.player, inputConfig); - } else if (inputConfig.type == 'itemSwap'){ + } else if (inputConfig.type == 'itemSwap') { new ItemSwapPicker(sectionElem, this.simUI, this.simUI.player, inputConfig) } }); @@ -164,7 +164,7 @@ export class RotationTab extends SimTab { private buildSavedDataPickers() { const savedRotationsManager = new SavedDataManager, SavedRotation>(this.rightPanel, this.simUI, this.simUI.player, { label: 'Rotation', - header: {title: 'Saved Rotations'}, + header: { title: 'Saved Rotations' }, storageKey: this.simUI.getSavedRotationStorageKey(), getData: (player: Player) => SavedRotation.create({ rotation: APLRotation.clone(player.aplRotation), diff --git a/ui/core/components/individual_sim_ui/settings_tab.ts b/ui/core/components/individual_sim_ui/settings_tab.ts index 58f1da218f..35c97d23a8 100644 --- a/ui/core/components/individual_sim_ui/settings_tab.ts +++ b/ui/core/components/individual_sim_ui/settings_tab.ts @@ -41,22 +41,22 @@ import * as Tooltips from '../../constants/tooltips.js'; import { ItemSwapPicker } from "../item_swap_picker"; export class SettingsTab extends SimTab { - protected simUI: IndividualSimUI; + protected simUI: IndividualSimUI; - readonly leftPanel: HTMLElement; - readonly rightPanel: HTMLElement; + readonly leftPanel: HTMLElement; + readonly rightPanel: HTMLElement; readonly column1: HTMLElement = this.buildColumn(1, 'settings-left-col'); readonly column2: HTMLElement = this.buildColumn(2, 'settings-left-col'); readonly column3: HTMLElement = this.buildColumn(3, 'settings-left-col'); readonly column4?: HTMLElement; - constructor(parentElem: HTMLElement, simUI: IndividualSimUI) { - super(parentElem, simUI, {identifier: 'settings-tab', title: 'Settings'}); - this.simUI = simUI; + constructor(parentElem: HTMLElement, simUI: IndividualSimUI) { + super(parentElem, simUI, { identifier: 'settings-tab', title: 'Settings' }); + this.simUI = simUI; - this.leftPanel = document.createElement('div'); - this.leftPanel.classList.add('settings-tab-left', 'tab-panel-left'); + this.leftPanel = document.createElement('div'); + this.leftPanel.classList.add('settings-tab-left', 'tab-panel-left'); this.leftPanel.appendChild(this.column1); this.leftPanel.appendChild(this.column2); @@ -69,17 +69,17 @@ export class SettingsTab extends SimTab { } this.rightPanel = document.createElement('div'); - this.rightPanel.classList.add('settings-tab-right', 'tab-panel-right', 'within-raid-sim-hide'); + this.rightPanel.classList.add('settings-tab-right', 'tab-panel-right', 'within-raid-sim-hide'); - this.contentContainer.appendChild(this.leftPanel); - this.contentContainer.appendChild(this.rightPanel); + this.contentContainer.appendChild(this.leftPanel); + this.contentContainer.appendChild(this.rightPanel); - this.buildTabContent(); - } + this.buildTabContent(); + } - protected buildTabContent() { + protected buildTabContent() { if (!this.simUI.isWithinRaidSim) { - this.buildEncounterSettings(); + this.buildEncounterSettings(); } if (aplLaunchStatuses[this.simUI.player.spec] == LaunchStatus.Unlaunched) { @@ -100,22 +100,22 @@ export class SettingsTab extends SimTab { } if (!this.simUI.isWithinRaidSim) { - this.buildSavedDataPickers(); + this.buildSavedDataPickers(); } - } + } - private buildEncounterSettings() { - const contentBlock = new ContentBlock(this.column1, 'encounter-settings', { - header: {title: 'Encounter'} - }); + private buildEncounterSettings() { + const contentBlock = new ContentBlock(this.column1, 'encounter-settings', { + header: { title: 'Encounter' } + }); - new EncounterPicker(contentBlock.bodyElement, this.simUI.sim.encounter, this.simUI.individualConfig.encounterPicker, this.simUI); - } + new EncounterPicker(contentBlock.bodyElement, this.simUI.sim.encounter, this.simUI.individualConfig.encounterPicker, this.simUI); + } private buildRotationSettings() { const contentBlock = new ContentBlock(this.column1, 'rotation-settings', { - header: {title: 'Rotation'} - }); + header: { title: 'Rotation' } + }); const rotationIconGroup = Input.newGroupContainer(); rotationIconGroup.classList.add('rotation-icon-group', 'icon-group'); @@ -139,7 +139,7 @@ export class SettingsTab extends SimTab { private buildPlayerSettings() { const column = aplLaunchStatuses[this.simUI.player.spec] == LaunchStatus.Unlaunched ? this.column2 : this.column1; const contentBlock = new ContentBlock(column, 'player-settings', { - header: {title: 'Player'} + header: { title: 'Player' } }); const playerIconGroup = Input.newGroupContainer(); @@ -211,7 +211,7 @@ export class SettingsTab extends SimTab { private buildConsumesSection() { const column = this.simUI.isWithinRaidSim ? this.column3 : this.column2; const contentBlock = new ContentBlock(column, 'consumes-settings', { - header: {title: 'Consumables'} + header: { title: 'Consumables' } }); new ConsumesPicker(contentBlock.bodyElement, this, this.simUI); @@ -220,7 +220,7 @@ export class SettingsTab extends SimTab { private buildCooldownSettings() { const column = (this.simUI.isWithinRaidSim ? this.column4 : this.column2) as HTMLElement; const contentBlock = new ContentBlock(column, 'cooldown-settings', { - header: {title: 'Cooldowns', tooltip: Tooltips.COOLDOWNS_SECTION} + header: { title: 'Cooldowns', tooltip: Tooltips.COOLDOWNS_SECTION } }); new CooldownsPicker(contentBlock.bodyElement, this.simUI.player); @@ -234,7 +234,7 @@ export class SettingsTab extends SimTab { if (settings.length > 0) { const contentBlock = new ContentBlock(this.column2, 'other-settings', { - header: {title: 'Other'} + header: { title: 'Other' } }); this.configureInputSection(contentBlock.bodyElement, this.simUI.individualConfig.otherInputs); @@ -247,7 +247,7 @@ export class SettingsTab extends SimTab { private buildBuffsSettings() { const contentBlock = new ContentBlock(this.column3, 'buffs-settings', { - header: {title: 'Raid Buffs', tooltip: Tooltips.BUFFS_SECTION} + header: { title: 'Raid Buffs', tooltip: Tooltips.BUFFS_SECTION } }); const buffOptions = this.simUI.splitRelevantOptions([ @@ -323,7 +323,7 @@ export class SettingsTab extends SimTab { private buildDebuffsSettings() { const contentBlock = new ContentBlock(this.column3, 'debuffs-settings', { - header: {title: 'Debuffs', tooltip: Tooltips.DEBUFFS_SECTION} + header: { title: 'Debuffs', tooltip: Tooltips.DEBUFFS_SECTION } }); const debuffOptions = this.simUI.splitRelevantOptions([ @@ -367,9 +367,9 @@ export class SettingsTab extends SimTab { } private buildSavedDataPickers() { - const savedEncounterManager = new SavedDataManager(this.rightPanel, this.simUI, this.simUI.sim.encounter, { + const savedEncounterManager = new SavedDataManager(this.rightPanel, this.simUI, this.simUI.sim.encounter, { label: 'Encounter', - header: {title: 'Saved Encounters'}, + header: { title: 'Saved Encounters' }, storageKey: this.simUI.getSavedEncounterStorageKey(), getData: (encounter: Encounter) => SavedEncounter.create({ encounter: encounter.toProto() }), setData: (eventID: EventID, encounter: Encounter, newEncounter: SavedEncounter) => encounter.fromProto(eventID, newEncounter.encounter!), @@ -379,9 +379,9 @@ export class SettingsTab extends SimTab { fromJson: (obj: any) => SavedEncounter.fromJson(obj), }); - const savedSettingsManager = new SavedDataManager, SavedSettings>(this.rightPanel, this.simUI, this.simUI, { + const savedSettingsManager = new SavedDataManager, SavedSettings>(this.rightPanel, this.simUI, this.simUI, { label: 'Settings', - header: {title: 'Saved Settings'}, + header: { title: 'Saved Settings' }, storageKey: this.simUI.getSavedSettingsStorageKey(), getData: (simUI: IndividualSimUI) => { const player = simUI.player; @@ -442,12 +442,12 @@ export class SettingsTab extends SimTab { if (inputConfig.type == 'number') { new NumberPicker(sectionElem, this.simUI.player, inputConfig); } else if (inputConfig.type == 'boolean') { - new BooleanPicker(sectionElem, this.simUI.player, {...inputConfig, ...{cssScheme: this.simUI.cssScheme}}); + new BooleanPicker(sectionElem, this.simUI.player, { ...inputConfig, ...{ cssScheme: this.simUI.cssScheme } }); } else if (inputConfig.type == 'enum') { new EnumPicker(sectionElem, this.simUI.player, inputConfig); } else if (inputConfig.type == 'customRotation') { new CustomRotationPicker(sectionElem, this.simUI, this.simUI.player, inputConfig); - } else if (inputConfig.type == 'itemSwap'){ + } else if (inputConfig.type == 'itemSwap') { new ItemSwapPicker(sectionElem, this.simUI, this.simUI.player, inputConfig) } }); diff --git a/ui/core/components/input.ts b/ui/core/components/input.ts index 00c101d150..4b874abe87 100644 --- a/ui/core/components/input.ts +++ b/ui/core/components/input.ts @@ -73,7 +73,7 @@ export abstract class Input extends Component { if (config.labelTooltip) new Tooltip(label); - + return label; } @@ -107,7 +107,7 @@ export abstract class Input extends Component { this.update(); } - abstract getInputElem(): HTMLElement|null; + abstract getInputElem(): HTMLElement | null; abstract getInputValue(): T; diff --git a/ui/core/components/input_helpers.ts b/ui/core/components/input_helpers.ts index 491800f110..13e3cafa05 100644 --- a/ui/core/components/input_helpers.ts +++ b/ui/core/components/input_helpers.ts @@ -496,7 +496,7 @@ interface WrappedItemSwapInputConfig { export function MakeItemSwapInput(config: WrappedItemSwapInputConfig): TypedItemSwapPickerConfig { return { type: 'itemSwap', - getValue: config.getValue || ((player: Player) => (player.getRotation()[config.fieldName] as unknown as ItemSwap) || ItemSwap.create()), + getValue: config.getValue || ((player: Player) => (player.getRotation()[config.fieldName] as unknown as ItemSwap) || ItemSwap.create()), setValue: config.setValue || ((eventID: EventID, player: Player, newValue: ItemSwap) => { const options = player.getRotation(); (options[config.fieldName] as unknown as ItemSwap) = newValue; diff --git a/ui/core/components/item_swap_picker.ts b/ui/core/components/item_swap_picker.ts index fe8438093b..017ae53633 100644 --- a/ui/core/components/item_swap_picker.ts +++ b/ui/core/components/item_swap_picker.ts @@ -7,7 +7,7 @@ import { SimUI } from '../sim_ui.js'; import { TypedEvent } from '../typed_event.js'; import { mapToStyles } from '@popperjs/core/lib/modifiers/computeStyles.js'; -export interface ItemSwapPickerConfig extends InputConfig, T>{ +export interface ItemSwapPickerConfig extends InputConfig, T> { itemSlots: Array; } @@ -64,11 +64,11 @@ export class ItemSwapPicker extends Component { }); config.itemSlots.forEach(itemSlot => { - new IconItemSwapPicker(itemSwapContainer, simUI, player,itemSlot, config); + new IconItemSwapPicker(itemSwapContainer, simUI, player, itemSlot, config); }); } - swapWithGear(player : Player, config: ItemSwapPickerConfig ) { + swapWithGear(player: Player, config: ItemSwapPickerConfig) { let gear = player.getGear() const gearMap = new Map(); @@ -96,7 +96,7 @@ export class ItemSwapPicker extends Component { const itemSwap = player.getItemSwapGear().toProto() as unknown as T config.setValue(eventID, player, itemSwap) } - + } diff --git a/ui/core/components/list_picker.ts b/ui/core/components/list_picker.ts index b2e7d776c7..241522200b 100644 --- a/ui/core/components/list_picker.ts +++ b/ui/core/components/list_picker.ts @@ -66,7 +66,7 @@ export class ListPicker extends Input extends Component { this.buttonElem.addEventListener('hide.bs.dropdown', event => { if (event.hasOwnProperty('clickEvent')) - event.preventDefault(); + event.preventDefault(); }) this.buttonElem.addEventListener('contextmenu', event => { diff --git a/ui/core/components/other_inputs.ts b/ui/core/components/other_inputs.ts index 7426d99658..52e2eec85d 100644 --- a/ui/core/components/other_inputs.ts +++ b/ui/core/components/other_inputs.ts @@ -212,18 +212,18 @@ export const HpPercentForDefensives = { }; export const InspirationUptime = { - type: 'number' as const, - float: true, - label: 'Inspiration % Uptime', - labelTooltip: ` + type: 'number' as const, + float: true, + label: 'Inspiration % Uptime', + labelTooltip: `

    % average of Encounter Duration, during which you have the Inspiration buff.

    If set to 0, the buff isn't applied.

    `, - changedEvent: (player: Player) => player.healingModelChangeEmitter, - getValue: (player: Player) => player.getHealingModel().inspirationUptime * 100, - setValue: (eventID: EventID, player: Player, newValue: number) => { - const healingModel = player.getHealingModel(); - healingModel.inspirationUptime = newValue / 100; - player.setHealingModel(eventID, healingModel); - }, + changedEvent: (player: Player) => player.healingModelChangeEmitter, + getValue: (player: Player) => player.getHealingModel().inspirationUptime * 100, + setValue: (eventID: EventID, player: Player, newValue: number) => { + const healingModel = player.getHealingModel(); + healingModel.inspirationUptime = newValue / 100; + player.setHealingModel(eventID, healingModel); + }, }; diff --git a/ui/core/components/raid_sim_action.ts b/ui/core/components/raid_sim_action.ts index 40b806fc01..3aadd7f070 100644 --- a/ui/core/components/raid_sim_action.ts +++ b/ui/core/components/raid_sim_action.ts @@ -31,22 +31,22 @@ export type ReferenceData = { }; export interface ResultMetrics { - cod: string, - dps: string, + cod: string, + dps: string, dpasp: string, - dtps: string, - tmi: string, - dur: string, - hps: string, - tps: string, - tto: string, + dtps: string, + tmi: string, + dur: string, + hps: string, + tps: string, + tto: string, } export interface ResultMetricCategories { - damage: string, + damage: string, demo: string, healing: string, - threat: string, + threat: string, } export interface ResultsLineArgs { @@ -56,34 +56,34 @@ export interface ResultsLineArgs { } export class RaidSimResultsManager { - static resultMetricCategories: {[ResultMetrics: string]: keyof ResultMetricCategories} = { - dps: 'damage', + static resultMetricCategories: { [ResultMetrics: string]: keyof ResultMetricCategories } = { + dps: 'damage', dpasp: 'demo', - tps: 'threat', - dtps: 'threat', - tmi: 'threat', - cod: 'threat', - tto: 'healing', - hps: 'healing', + tps: 'threat', + dtps: 'threat', + tmi: 'threat', + cod: 'threat', + tto: 'healing', + hps: 'healing', } - static resultMetricClasses: {[ResultMetrics: string]: string} = { - cod: 'results-sim-cod', - dps: 'results-sim-dps', - dpasp: 'results-sim-dpasp', - dtps: 'results-sim-dtps', - tmi: 'results-sim-tmi', - dur: 'results-sim-dur', - hps: 'results-sim-hps', - tps: 'results-sim-tps', - tto: 'results-sim-tto', + static resultMetricClasses: { [ResultMetrics: string]: string } = { + cod: 'results-sim-cod', + dps: 'results-sim-dps', + dpasp: 'results-sim-dpasp', + dtps: 'results-sim-dtps', + tmi: 'results-sim-tmi', + dur: 'results-sim-dur', + hps: 'results-sim-hps', + tps: 'results-sim-tps', + tto: 'results-sim-tto', } - static metricsClasses: {[ResultMetricCategories: string]: string} = { - damage: 'damage-metrics', + static metricsClasses: { [ResultMetricCategories: string]: string } = { + damage: 'damage-metrics', demo: 'demo-metrics', healing: 'healing-metrics', - threat: 'threat-metrics', + threat: 'threat-metrics', } readonly currentChangeEmitter: TypedEvent = new TypedEvent(); @@ -269,7 +269,7 @@ export class RaidSimResultsManager { } } - private formatToplineResult(querySelector: string, getMetrics: (result: SimResult) => DistributionMetricsProto|number, precision: number, lowerIsBetter?: boolean) { + private formatToplineResult(querySelector: string, getMetrics: (result: SimResult) => DistributionMetricsProto | number, precision: number, lowerIsBetter?: boolean) { const elem = this.simUI.resultsViewer.contentElem.querySelector(querySelector) as HTMLSpanElement; if (!elem) { return; @@ -293,16 +293,16 @@ export class RaidSimResultsManager { private applyZTestTooltip(elem: HTMLElement, n1: number, avg1: number, stdev1: number, n2: number, avg2: number, stdev2: number): boolean { const delta = avg1 - avg2; - const err1 = stdev1/Math.sqrt(n1); - const err2 = stdev2/Math.sqrt(n2); + const err1 = stdev1 / Math.sqrt(n1); + const err2 = stdev2 / Math.sqrt(n2); const denom = Math.sqrt(Math.pow(err1, 2) + Math.pow(err2, 2)); - const z = Math.abs(delta/denom); + const z = Math.abs(delta / denom); const isDiff = z > 1.96; let significance_str = ''; - if (isDiff) { + if (isDiff) { significance_str = `Difference is significantly different (Z = ${z.toFixed(3)}).`; - } else { + } else { significance_str = `Difference is not significantly different (Z = ${z.toFixed(3)}).`; } tippy(elem, { @@ -439,7 +439,7 @@ export class RaidSimResultsManager { content += this.buildResultsLine({ average: dpsMetrics.avg, stdev: dpsMetrics.stdev, - classes: this.getResultsLineClasses('dps'), + classes: this.getResultsLineClasses('dps'), }).outerHTML; //const hpsMetrics = simResult.raidMetrics.hps; //content += this.buildResultsLine({ @@ -476,7 +476,7 @@ export class RaidSimResultsManager { (${args.stdev.toFixed()}) ` : '' - } + }
    vs reference
    diff --git a/ui/core/components/raid_target_picker.ts b/ui/core/components/raid_target_picker.ts index 0973bf00c6..af26a11d23 100644 --- a/ui/core/components/raid_target_picker.ts +++ b/ui/core/components/raid_target_picker.ts @@ -12,7 +12,7 @@ export interface RaidTargetPickerConfig extends InputConfig|null, + player: Player | null, } // Dropdown menu for selecting a player. @@ -59,7 +59,7 @@ export class RaidTargetPicker extends Input { } private makeTargetOptions(): Array { - const unassignedOption = {player: null, isDropdown: true} + const unassignedOption = { player: null, isDropdown: true } const playerOptions = this.raid.getPlayers().filter(player => player != null).map(player => { return { player: player, isDropdown: true } }); @@ -114,7 +114,7 @@ export class RaidTargetPicker extends Input { const optionData = this.currentOptions.find(optionData => optionData.player == this.curPlayer); if (optionData) - this.buttonElem.innerHTML = RaidTargetPicker.makeOptionElem({player: optionData.player}).outerHTML; + this.buttonElem.innerHTML = RaidTargetPicker.makeOptionElem({ player: optionData.player }).outerHTML; } // static makeOptionElem(data: RaidTargetElemOption): HTMLElement { diff --git a/ui/core/components/results_viewer.ts b/ui/core/components/results_viewer.ts index f6affedc44..a46226cf20 100644 --- a/ui/core/components/results_viewer.ts +++ b/ui/core/components/results_viewer.ts @@ -42,7 +42,7 @@ export class ResultsViewer extends Component { this.contentElem = this.rootElem.getElementsByClassName('results-content')[0] as HTMLElement; this.warningElem = this.rootElem.getElementsByClassName('warning-zone')[0] as HTMLElement; - + this.warningsLink = this.addWarningsLink(); this.updateWarnings(); diff --git a/ui/core/components/saved_data_manager.ts b/ui/core/components/saved_data_manager.ts index 153a744db3..b4e74e2f2f 100644 --- a/ui/core/components/saved_data_manager.ts +++ b/ui/core/components/saved_data_manager.ts @@ -58,7 +58,7 @@ export class SavedDataManager extends Component { this.presets = []; this.frozen = false; - let contentBlock = new ContentBlock(this.rootElem, 'saved-data', {header: config.header}); + let contentBlock = new ContentBlock(this.rootElem, 'saved-data', { header: config.header }); contentBlock.bodyElement.innerHTML = `
    `; this.savedDataDiv = contentBlock.bodyElement.querySelector('.saved-data-container') as HTMLElement; @@ -75,7 +75,7 @@ export class SavedDataManager extends Component { const newData = this.makeSavedData(config); const dataArr = config.isPreset ? this.presets : this.userData; const oldIdx = dataArr.findIndex(data => data.name == config.name); - + if (oldIdx == -1) { if (config.isPreset || this.presets.length == 0) { this.savedDataDiv.appendChild(newData.elem); diff --git a/ui/core/components/settings_menu.ts b/ui/core/components/settings_menu.ts index 219b86d883..fae725e6c0 100644 --- a/ui/core/components/settings_menu.ts +++ b/ui/core/components/settings_menu.ts @@ -12,7 +12,7 @@ export class SettingsMenu extends BaseModal { private readonly simUI: SimUI; constructor(parent: HTMLElement, simUI: SimUI) { - super(parent, 'settings-menu', {title: "Options", footer: true}); + super(parent, 'settings-menu', { title: "Options", footer: true }); this.simUI = simUI; this.body.innerHTML = ` diff --git a/ui/core/components/sim_header.ts b/ui/core/components/sim_header.ts index 24184d1603..76650d2b28 100644 --- a/ui/core/components/sim_header.ts +++ b/ui/core/components/sim_header.ts @@ -15,32 +15,32 @@ interface ToolbarLinkArgs { } export class SimHeader extends Component { - private simUI: SimUI; + private simUI: SimUI; - private simTabsContainer: HTMLElement; + private simTabsContainer: HTMLElement; private simToolbar: HTMLElement; private knownIssuesLink: HTMLElement; - constructor(parentElem: HTMLElement, simUI: SimUI) { - super(parentElem, 'sim-header'); + constructor(parentElem: HTMLElement, simUI: SimUI) { + super(parentElem, 'sim-header'); - this.simUI = simUI; + this.simUI = simUI; - this.simTabsContainer = this.rootElem.querySelector('.sim-tabs') as HTMLElement; - this.simToolbar = this.rootElem.querySelector('.sim-toolbar') as HTMLElement; + this.simTabsContainer = this.rootElem.querySelector('.sim-tabs') as HTMLElement; + this.simToolbar = this.rootElem.querySelector('.sim-toolbar') as HTMLElement; this.knownIssuesLink = this.addKnownIssuesLink(); - this.addBugReportLink(); - this.addDownloadBinaryLink(); - this.addSimOptionsLink(); + this.addBugReportLink(); + this.addDownloadBinaryLink(); + this.addSimOptionsLink(); this.addSocialLinks(); - } + } - activateTab(className: string) { - (this.simTabsContainer.getElementsByClassName(className)[0] as HTMLElement).click(); - } + activateTab(className: string) { + (this.simTabsContainer.getElementsByClassName(className)[0] as HTMLElement).click(); + } - addTab(title: string, contentId: string) { + addTab(title: string, contentId: string) { const isFirstTab = this.simTabsContainer.children.length == 0; const tabFragment = document.createElement('fragment'); @@ -67,16 +67,16 @@ export class SimHeader extends Component { tab.navLink.setAttribute('aria-selected', isFirstTab.toString()); if (isFirstTab) tab.navLink.classList.add('active', 'show'); - + this.simTabsContainer.appendChild(tab.navItem); } addImportLink(label: string, onClick: (parent: HTMLElement) => void, hideInRaidSim?: boolean) { this.addImportExportLink('import-dropdown', label, onClick, hideInRaidSim); - } + } addExportLink(label: string, onClick: (parent: HTMLElement) => void, hideInRaidSim?: boolean) { this.addImportExportLink('export-dropdown', label, onClick, hideInRaidSim); - } + } private addImportExportLink(cssClass: string, label: string, onClick: (parent: HTMLElement) => void, hideInRaidSim?: boolean) { const dropdownElem = this.rootElem.getElementsByClassName(cssClass)[0] as HTMLElement; const menuElem = dropdownElem.getElementsByClassName('dropdown-menu')[0] as HTMLElement; @@ -142,7 +142,7 @@ export class SimHeader extends Component { }).children[0] as HTMLElement; } - addKnownIssue(issue: string) { + addKnownIssue(issue: string) { let tooltipFragment = document.createElement('fragment'); tooltipFragment.innerHTML = this.knownIssuesLink.getAttribute('data-bs-title') as string; let list = tooltipFragment.children[0] as HTMLElement; @@ -150,10 +150,10 @@ export class SimHeader extends Component { listItem.innerHTML = issue; list.appendChild(listItem); this.knownIssuesLink.setAttribute('data-bs-title', list.outerHTML); - new Tooltip(this.knownIssuesLink); + new Tooltip(this.knownIssuesLink); } - private addBugReportLink() { + private addBugReportLink() { this.addToolbarLink({ href: "https://github.com/wowsims/wotlk/issues/new/choose", parent: this.simToolbar, @@ -162,7 +162,7 @@ export class SimHeader extends Component { }) } - private addDownloadBinaryLink() { + private addDownloadBinaryLink() { let href = "https://github.com/wowsims/wotlk/releases"; let icon = "fas fa-gauge-high fa-lg" let parent = this.simToolbar; @@ -194,9 +194,9 @@ export class SimHeader extends Component { classes: "downbin", }) } - } + } - private addSimOptionsLink() { + private addSimOptionsLink() { this.addToolbarLink({ parent: this.simToolbar, icon: "fas fa-cog fa-lg", diff --git a/ui/core/components/sim_tab.ts b/ui/core/components/sim_tab.ts index f901294805..d4c7f1f94d 100644 --- a/ui/core/components/sim_tab.ts +++ b/ui/core/components/sim_tab.ts @@ -2,43 +2,43 @@ import { SimUI } from "../sim_ui"; import { Component } from "./component"; export interface SimTabConfig { - identifier: string, - title: string, + identifier: string, + title: string, } export abstract class SimTab extends Component { - protected simUI: SimUI; - protected config: SimTabConfig; + protected simUI: SimUI; + protected config: SimTabConfig; - readonly navItem: HTMLElement; - readonly navLink: HTMLElement; - readonly contentContainer: HTMLElement; + readonly navItem: HTMLElement; + readonly navLink: HTMLElement; + readonly contentContainer: HTMLElement; - constructor(parentElem: HTMLElement, simUI: SimUI, config: SimTabConfig ) { - super(parentElem, 'sim-tab'); + constructor(parentElem: HTMLElement, simUI: SimUI, config: SimTabConfig) { + super(parentElem, 'sim-tab'); - this.rootElem.classList.add(config.identifier); + this.rootElem.classList.add(config.identifier); - this.simUI = simUI; - this.config = config; + this.simUI = simUI; + this.config = config; - this.rootElem.id = this.config.identifier; - this.rootElem.classList.add('tab-pane', 'fade'); + this.rootElem.id = this.config.identifier; + this.rootElem.classList.add('tab-pane', 'fade'); - if (parentElem.childNodes.length == 0) - this.rootElem.classList.add('active', 'show'); + if (parentElem.childNodes.length == 0) + this.rootElem.classList.add('active', 'show'); - this.navItem = this.buildNavItem(); - this.navLink = this.navItem.children[0] as HTMLElement; - this.contentContainer = document.createElement('div'); - this.contentContainer.classList.add('tab-pane-content-container'); - this.rootElem.appendChild(this.contentContainer); + this.navItem = this.buildNavItem(); + this.navLink = this.navItem.children[0] as HTMLElement; + this.contentContainer = document.createElement('div'); + this.contentContainer.classList.add('tab-pane-content-container'); + this.rootElem.appendChild(this.contentContainer); - this.simUI.simHeader.addSimTabLink(this); - } + this.simUI.simHeader.addSimTabLink(this); + } - private buildNavItem(): HTMLElement { - const tabFragment = document.createElement('fragment'); + private buildNavItem(): HTMLElement { + const tabFragment = document.createElement('fragment'); tabFragment.innerHTML = `