diff --git a/ui/core/components/detailed_results.tsx b/ui/core/components/detailed_results.tsx index 9be046d0b7..287681e298 100644 --- a/ui/core/components/detailed_results.tsx +++ b/ui/core/components/detailed_results.tsx @@ -194,7 +194,7 @@ export abstract class DetailedResults extends Component { this.simUI?.sim.settingsChangeEmitter.on(async () => await this.updateSettings()); // Allow styling the sticky toolbar - const toolbar = document.querySelector('.dr-toolbar') as HTMLElement; + const toolbar = document.querySelector('.dr-toolbar')!; new IntersectionObserver( ([e]) => { e.target.classList.toggle('stuck', e.intersectionRatio < 1); diff --git a/ui/core/components/detailed_results/metrics_table/metrics_table.tsx b/ui/core/components/detailed_results/metrics_table/metrics_table.tsx index 0a3c18da2f..905b7faca0 100644 --- a/ui/core/components/detailed_results/metrics_table/metrics_table.tsx +++ b/ui/core/components/detailed_results/metrics_table/metrics_table.tsx @@ -6,8 +6,7 @@ import { ActionId } from '../../../proto_utils/action_id'; import { ActionMetrics, AuraMetrics, ResourceMetrics, UnitMetrics } from '../../../proto_utils/sim_result'; import { TypedEvent } from '../../../typed_event'; import { ResultComponent, ResultComponentConfig, SimResultData } from '../result_component'; - -declare let $: any; +import { TableSorter } from './table_sorter'; export enum ColumnSortType { None, @@ -33,7 +32,8 @@ export abstract class MetricsTable>; protected readonly tableElem: HTMLElement; - protected readonly bodyElem: HTMLElement; + protected readonly bodyElem: HTMLTableSectionElement; + private readonly sorter: TableSorter; readonly onUpdate = new TypedEvent('MetricsTableUpdate'); @@ -50,10 +50,10 @@ export abstract class MetricsTable, ); - this.tableElem = this.rootElem.getElementsByClassName('metrics-table')[0] as HTMLTableSectionElement; - this.bodyElem = this.rootElem.getElementsByClassName('metrics-table-body')[0] as HTMLElement; + this.tableElem = this.rootElem.querySelector('.metrics-table')!; + this.bodyElem = this.rootElem.querySelector('.metrics-table-body')!; - const headerRowElem = this.rootElem.getElementsByClassName('metrics-table-header-row')[0] as HTMLElement; + const headerRowElem = this.rootElem.querySelector('.metrics-table-header-row')!; this.columnConfigs.forEach(columnConfig => { const headerCell = document.createElement('th'); const tooltip = columnConfig.tooltip || TOOLTIP_METRIC_LABELS[columnConfig.name as keyof typeof TOOLTIP_METRIC_LABELS]; @@ -74,13 +74,15 @@ export abstract class MetricsTable [i, config.sort == ColumnSortType.Ascending ? 0 : 1]) - .filter(sortData => this.columnConfigs[sortData[0]].sort); + const sortCol = this.columnConfigs.findIndex(v => !!v.sort); - $(this.tableElem).tablesorter({ - sortList: sortList, - cssChildRow: 'child-metric', + this.sorter = new TableSorter({ + tableHead: headerRowElem, + tableBody: this.bodyElem, + dataSetKey: 'text', + childRowClass: 'child-metric', + defaultSortCol: sortCol !== -1 ? sortCol : 0, + defaultSortDesc: sortCol !== -1 && this.columnConfigs[sortCol].sort == ColumnSortType.Descending, }); } @@ -168,7 +170,7 @@ export abstract class MetricsTable this.addGroup(group)); - $(this.tableElem).trigger('update'); + this.sorter.update(); this.onUpdate.emit(resultData.eventID); } diff --git a/ui/core/components/detailed_results/metrics_table/table_sorter.ts b/ui/core/components/detailed_results/metrics_table/table_sorter.ts new file mode 100644 index 0000000000..916c152a61 --- /dev/null +++ b/ui/core/components/detailed_results/metrics_table/table_sorter.ts @@ -0,0 +1,104 @@ +type TableSorterRowData = { + readonly values: ReadonlyArray; + readonly rowElement: HTMLTableRowElement; +}; + +type TableSorterConfig = { + tableHead: HTMLTableRowElement; + tableBody: HTMLTableSectionElement; + dataSetKey: string; + childRowClass: string; + defaultSortCol: number; + defaultSortDesc: boolean; +}; + +export class TableSorter { + private readonly cfg: Readonly; + private readonly rowData: Array }> = []; + private sortCol = -1; + private sortDesc: Array; + + constructor(config: TableSorterConfig) { + if (config.tableHead.cells[config.defaultSortCol] === undefined) throw new Error('Default sort column must be a valid header cell index!'); + + this.cfg = config; + + this.sortCol = this.cfg.defaultSortCol; + this.sortDesc = Array(config.tableHead.cells.length).fill(true); + this.sortDesc[config.defaultSortCol] = config.defaultSortDesc; + + Array.from(config.tableHead.cells).forEach((cell, i) => { + cell.addEventListener('click', () => this.setSort(i)); + }); + } + + private sortFunc = (a: TableSorterRowData, b: TableSorterRowData) => { + const aValue = a.values[this.sortCol]; + const bValue = b.values[this.sortCol]; + const asc = !this.sortDesc[this.sortCol]; + if (typeof aValue === 'number' && typeof bValue === 'number') { + return asc ? aValue - bValue : bValue - aValue; + } else { + return asc ? aValue.toString().localeCompare(bValue.toString()) : bValue.toString().localeCompare(aValue.toString()); + } + }; + + private sort() { + if (!this.rowData.length || !(this.sortCol in this.rowData[0].values)) return; + + const sortedRowElems: Array = []; + + this.rowData.sort(this.sortFunc); + for (const row of this.rowData) { + sortedRowElems.push(row.rowElement); + if (row.children) { + row.children.sort(this.sortFunc); + sortedRowElems.push(...row.children.map(v => v.rowElement)); + } + } + + this.cfg.tableBody.replaceChildren(...sortedRowElems); + } + + /** + * Set column to sort by. If set to the current sort column the order will be reversed. + * @param column If omitted use default column. + */ + setSort(column = -1) { + if (this.sortDesc[column] === undefined) column = this.cfg.defaultSortCol; + this.sortDesc[column] = !this.sortDesc[column]; + this.sortCol = column; + this.sort(); + } + + private parseRowValues(rowElement: HTMLTableRowElement): Array { + const values: Array = []; + for (const cell of rowElement.cells) { + const val = cell.dataset[this.cfg.dataSetKey] ?? cell.innerText; + const numVal = parseFloat(val); + values.push(!isNaN(numVal) ? numVal : val); + } + return values; + } + + /** + * Update internal data structure for changed table data. + */ + update() { + this.rowData.length = 0; + + for (const rowElement of this.cfg.tableBody.rows) { + const values = this.parseRowValues(rowElement); + if (!rowElement.classList.contains(this.cfg.childRowClass)) { + this.rowData.push({ values, rowElement }); + } else { + const parentData = this.rowData[this.rowData.length - 1]; + if (!parentData) throw new Error('Child row has no parent!'); + if (!parentData.children) parentData.children = []; + parentData.children.push({ values, rowElement }); + } + } + + this.sort(); + } +} diff --git a/ui/core/components/icon_enum_picker.tsx b/ui/core/components/icon_enum_picker.tsx index b2811b5b0a..f414c091b5 100644 --- a/ui/core/components/icon_enum_picker.tsx +++ b/ui/core/components/icon_enum_picker.tsx @@ -82,9 +82,9 @@ export class IconEnumPicker extends Input { , ); - this.buttonElem = this.rootElem.querySelector('.icon-picker-button') as HTMLAnchorElement; - this.buttonText = this.rootElem.querySelector('label') as HTMLElement; - this.dropdownMenu = this.rootElem.querySelector('.dropdown-menu') as HTMLElement; + this.buttonElem = this.rootElem.querySelector('.icon-picker-button')!; + this.buttonText = this.rootElem.querySelector('label')!; + this.dropdownMenu = this.rootElem.querySelector('.dropdown-menu')!; if (this.config.numColumns) { this.dropdownMenu.style.gridTemplateColumns = `repeat(${this.config.numColumns}, 1fr)`; diff --git a/ui/core/components/individual_sim_ui/consumes_picker.ts b/ui/core/components/individual_sim_ui/consumes_picker.ts index ce72dcad3b..3c435db0b7 100644 --- a/ui/core/components/individual_sim_ui/consumes_picker.ts +++ b/ui/core/components/individual_sim_ui/consumes_picker.ts @@ -42,7 +42,7 @@ export class ConsumesPicker extends Component { `; const row = this.rootElem.appendChild(fragment.children[0] as HTMLElement); - const potionsElem = this.rootElem.querySelector('.consumes-potions') as HTMLElement; + const potionsElem = this.rootElem.querySelector('.consumes-potions')!; const potionsOptions = ConsumablesInputs.makePotionsInput(relevantStatOptions(ConsumablesInputs.POTIONS_CONFIG, this.simUI), 'Potions'); const conjuredOptions = ConsumablesInputs.makeConjuredInput(relevantStatOptions(ConsumablesInputs.CONJURED_CONFIG, this.simUI)); @@ -67,7 +67,7 @@ export class ConsumesPicker extends Component { `; const row = this.rootElem.appendChild(fragment.children[0] as HTMLElement); - const flasksElem = this.rootElem.querySelector('.consumes-flasks') as HTMLElement; + const flasksElem = this.rootElem.querySelector('.consumes-flasks')!; const flasksOptions = ConsumablesInputs.makeFlasksInput(relevantStatOptions(ConsumablesInputs.FLASKS_CONFIG, this.simUI)); @@ -87,7 +87,7 @@ export class ConsumesPicker extends Component { `; const row = this.rootElem.appendChild(fragment.children[0] as HTMLElement); - const imbuesElem = this.rootElem.querySelector('.consumes-weapon-imbues') as HTMLElement; + const imbuesElem = this.rootElem.querySelector('.consumes-weapon-imbues')!; const mhImbueOptions = ConsumablesInputs.makeMainHandImbuesInput( relevantStatOptions(ConsumablesInputs.WEAPON_IMBUES_MH_CONFIG, this.simUI), @@ -111,7 +111,7 @@ export class ConsumesPicker extends Component { `; const row = this.rootElem.appendChild(fragment.children[0] as HTMLElement); - const foodsElem = this.rootElem.querySelector('.consumes-food') as HTMLElement; + const foodsElem = this.rootElem.querySelector('.consumes-food')!; const foodOptions = ConsumablesInputs.makeFoodInput(relevantStatOptions(ConsumablesInputs.FOOD_CONFIG, this.simUI)); const alcoholOptions = ConsumablesInputs.makeAlcoholInput(relevantStatOptions(ConsumablesInputs.ALCOHOL_CONFIG, this.simUI)); @@ -136,7 +136,7 @@ export class ConsumesPicker extends Component { `; const row = this.rootElem.appendChild(fragment.children[0] as HTMLElement); - const physicalConsumesElem = this.rootElem.querySelector('.consumes-physical') as HTMLElement; + const physicalConsumesElem = this.rootElem.querySelector('.consumes-physical')!; const apBuffOptions = ConsumablesInputs.makeAttackPowerConsumeInput( relevantStatOptions(ConsumablesInputs.ATTACK_POWER_CONSUMES_CONFIG, this.simUI), @@ -168,7 +168,7 @@ export class ConsumesPicker extends Component { `; const row = this.rootElem.appendChild(fragment.children[0] as HTMLElement); - const defensiveConsumesElem = this.rootElem.querySelector('.consumes-defensive') as HTMLElement; + const defensiveConsumesElem = this.rootElem.querySelector('.consumes-defensive')!; const healthBuffOptions = ConsumablesInputs.makeHealthConsumeInput(relevantStatOptions(ConsumablesInputs.HEALTH_CONSUMES_CONFIG, this.simUI), 'Health'); @@ -193,7 +193,7 @@ export class ConsumesPicker extends Component { `; const row = this.rootElem.appendChild(fragment.children[0] as HTMLElement); - const spellsCnsumesElem = this.rootElem.querySelector('.consumes-spells') as HTMLElement; + const spellsCnsumesElem = this.rootElem.querySelector('.consumes-spells')!; const spBuffOptions = ConsumablesInputs.makeSpellPowerConsumeInput( relevantStatOptions(ConsumablesInputs.SPELL_POWER_CONFIG, this.simUI), @@ -235,7 +235,7 @@ export class ConsumesPicker extends Component { `; const row = this.rootElem.appendChild(fragment.children[0] as HTMLElement); - const miscConsumesElem = this.rootElem.querySelector('.consumes-misc') as HTMLElement; + const miscConsumesElem = this.rootElem.querySelector('.consumes-misc')!; const sealOfTheDawnOptions = ConsumablesInputs.makeSealOfTheDawnConsumesInput( relevantStatOptions(ConsumablesInputs.SEAL_OF_THE_DAWN_CONSUMES_CONFIG, this.simUI), @@ -272,7 +272,7 @@ export class ConsumesPicker extends Component { `; const row = this.rootElem.appendChild(fragment.children[0] as HTMLElement); - const engiConsumesElem = this.rootElem.querySelector('.consumes-engi') as HTMLElement; + const engiConsumesElem = this.rootElem.querySelector('.consumes-engi')!; const explosiveOptions = ConsumablesInputs.makeExplosivesInput(relevantStatOptions(ConsumablesInputs.EXPLOSIVES_CONFIG, this.simUI), 'Explosives'); const sapperOptions = ConsumablesInputs.makeSappersInput(relevantStatOptions(ConsumablesInputs.SAPPER_CONFIG, this.simUI), 'Sappers'); @@ -297,7 +297,7 @@ export class ConsumesPicker extends Component { `; const row = this.rootElem.appendChild(fragment.children[0] as HTMLElement); - const enchConsumesElem = this.rootElem.querySelector('.consumes-ench') as HTMLElement; + const enchConsumesElem = this.rootElem.querySelector('.consumes-ench')!; const enchantedSigilOptions = ConsumablesInputs.makeEncanthedSigilInput( relevantStatOptions(ConsumablesInputs.ENCHANTED_SIGIL_CONFIG, this.simUI), @@ -322,7 +322,7 @@ export class ConsumesPicker extends Component { `; const row = this.rootElem.appendChild(fragment.children[0] as HTMLElement); - const petConsumesElem = this.rootElem.querySelector('.consumes-pet') as HTMLElement; + const petConsumesElem = this.rootElem.querySelector('.consumes-pet')!; // const miscPetConsumesOptions = relevantStatOptions(ConsumablesInputs.MISC_PET_CONSUMES, this.simUI); diff --git a/ui/core/components/list_picker.tsx b/ui/core/components/list_picker.tsx index 7a8eeaf857..1326251802 100644 --- a/ui/core/components/list_picker.tsx +++ b/ui/core/components/list_picker.tsx @@ -90,7 +90,7 @@ export class ListPicker extends Input('.list-picker-title')!, { content: this.config.titleTooltip, }); this.addOnDisposeCallback(() => titleTooltip?.destroy()); diff --git a/ui/core/components/multi_icon_picker.ts b/ui/core/components/multi_icon_picker.ts index bbcc47102c..013e0b7d3d 100644 --- a/ui/core/components/multi_icon_picker.ts +++ b/ui/core/components/multi_icon_picker.ts @@ -61,15 +61,15 @@ export class MultiIconPicker extends Component { this.addOnDisposeCallback(() => tooltip.destroy()); } - const labelElem = this.rootElem.querySelector('.multi-icon-picker-label') as HTMLElement; + const labelElem = this.rootElem.querySelector('.multi-icon-picker-label')!; if (config.label) { labelElem.textContent = config.label; } else { labelElem.remove(); } - this.buttonElem = this.rootElem.querySelector('.icon-picker-button') as HTMLAnchorElement; - this.dropdownMenu = this.rootElem.querySelector('.dropdown-menu') as HTMLElement; + this.buttonElem = this.rootElem.querySelector('.icon-picker-button')!; + this.dropdownMenu = this.rootElem.querySelector('.dropdown-menu')!; if (this.config.direction == IconPickerDirection.Horizontal) { this.dropdownMenu.style.gridAutoFlow = 'column'; diff --git a/ui/core/components/raid_sim_action.tsx b/ui/core/components/raid_sim_action.tsx index 1d87fd25f5..217009cae9 100644 --- a/ui/core/components/raid_sim_action.tsx +++ b/ui/core/components/raid_sim_action.tsx @@ -332,7 +332,7 @@ export class RaidSimResultsManager { lowerIsBetter?: boolean, preNormalizedErrors?: boolean, ) { - const elem = this.simUI.resultsViewer.contentElem.querySelector(querySelector) as HTMLSpanElement; + const elem = this.simUI.resultsViewer.contentElem.querySelector(querySelector)!; if (!elem) { return; } diff --git a/ui/core/components/raid_target_picker.ts b/ui/core/components/raid_target_picker.ts index 493c37ac86..82f32387b0 100644 --- a/ui/core/components/raid_target_picker.ts +++ b/ui/core/components/raid_target_picker.ts @@ -46,8 +46,8 @@ export class UnitReferencePicker extends Input `; - this.buttonElem = this.rootElem.querySelector('.raid-target-picker-button') as HTMLElement; - this.dropdownElem = this.rootElem.querySelector('.dropdown-menu') as HTMLElement; + this.buttonElem = this.rootElem.querySelector('.raid-target-picker-button')!; + this.dropdownElem = this.rootElem.querySelector('.dropdown-menu')!; this.buttonElem.addEventListener('click', event => event.preventDefault()); diff --git a/ui/core/components/sim_header.tsx b/ui/core/components/sim_header.tsx index 6ba832f3ea..ba1fbbe23d 100644 --- a/ui/core/components/sim_header.tsx +++ b/ui/core/components/sim_header.tsx @@ -31,8 +31,8 @@ export class SimHeader extends Component { constructor(parentElem: HTMLElement, simUI: SimUI) { super(parentElem, 'sim-header'); 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')!; + this.simToolbar = this.rootElem.querySelector('.sim-toolbar')!; this.knownIssuesContent = (
    ) as HTMLUListElement; this.knownIssuesLink = this.addKnownIssuesLink(); diff --git a/ui/core/components/stat_weights_action.ts b/ui/core/components/stat_weights_action.ts index eadb2f6b0d..f620efe001 100644 --- a/ui/core/components/stat_weights_action.ts +++ b/ui/core/components/stat_weights_action.ts @@ -330,11 +330,11 @@ class EpWeightsMenu extends BaseModal { `; - this.container = this.rootElem.querySelector('.results-ep-table-container') as HTMLElement; - this.table = this.rootElem.querySelector('.results-ep-table') as HTMLElement; - this.tableBody = this.rootElem.querySelector('.results-ep-table tbody') as HTMLElement; + this.container = this.rootElem.querySelector('.results-ep-table-container')!; + this.table = this.rootElem.querySelector('.results-ep-table')!; + this.tableBody = this.rootElem.querySelector('.results-ep-table tbody')!; - const resultsElem = this.rootElem.querySelector('.results-pending-overlay') as HTMLElement; + const resultsElem = this.rootElem.querySelector('.results-pending-overlay')!; this.resultsViewer = new ResultsViewer(resultsElem); const updateType = () => { @@ -726,7 +726,7 @@ class EpWeightsMenu extends BaseModal { `; if (this.isEpStat(stat)) { - const includeToggleCell = row.querySelector('.swcalc-include-toggle') as HTMLElement; + const includeToggleCell = row.querySelector('.swcalc-include-toggle')!; new BooleanPicker(includeToggleCell, this, { id: 'sw-stat-toggle-' + stat.getName(this.simUI.player.getClass()), getValue: epWeightsModal => !epWeightsModal.settings.isUnitStatExcludedFromCalc(stat), @@ -736,7 +736,7 @@ class EpWeightsMenu extends BaseModal { }); } - const currentEpCell = row.querySelector('.current-ep') as HTMLElement; + const currentEpCell = row.querySelector('.current-ep')!; new NumberPicker(currentEpCell, this.simUI.player, { id: `ep-weight-stat-${stat}`, float: true, @@ -787,7 +787,7 @@ class EpWeightsMenu extends BaseModal { const epCurrent = this.simUI.player.getEpWeights().getUnitStat(stat); const epDelta = epTotal - epCurrent; - const epAvgElem = template.content.querySelector('.type-ep .results-avg') as HTMLElement; + const epAvgElem = template.content.querySelector('.type-ep .results-avg')!; if (epDelta.toFixed(2) == '0.00') epAvgElem; // no-op else if (epDelta > 0) epAvgElem.classList.add('positive'); else if (epDelta < 0) epAvgElem.classList.add('negative'); diff --git a/ui/core/sim_ui.tsx b/ui/core/sim_ui.tsx index 21479c8f48..70d171130c 100644 --- a/ui/core/sim_ui.tsx +++ b/ui/core/sim_ui.tsx @@ -89,7 +89,7 @@ export abstract class SimUI extends Component { this.rootElem.appendChild(container); - this.simContentContainer = this.rootElem.querySelector('.sim-content') as HTMLElement; + this.simContentContainer = this.rootElem.querySelector('.sim-content')!; this.simHeader = new SimHeader(this.simContentContainer, this); this.simMain = document.createElement('main'); this.simMain.classList.add('sim-main', 'tab-content'); @@ -156,10 +156,10 @@ export abstract class SimUI extends Component { // Sidebar Contents - const titleElem = this.rootElem.querySelector('.sim-title') as HTMLElement; + const titleElem = this.rootElem.querySelector('.sim-title')!; new SimTitleDropdown(titleElem, config.spec, { noDropdown: this.isWithinRaidSim }); - this.simActionsContainer = this.rootElem.querySelector('.sim-sidebar-actions') as HTMLElement; + this.simActionsContainer = this.rootElem.querySelector('.sim-sidebar-actions')!; this.iterationsPicker = new NumberPicker(this.simActionsContainer, this.sim, { id: 'simui-iterations', label: 'Iterations', @@ -171,15 +171,15 @@ export abstract class SimUI extends Component { }, }).rootElem; - const resultsViewerElem = this.rootElem.querySelector('.sim-sidebar-results') as HTMLElement; + const resultsViewerElem = this.rootElem.querySelector('.sim-sidebar-results')!; this.resultsViewer = new ResultsViewer(resultsViewerElem); - const socialsContainer = this.rootElem.querySelector('.sim-sidebar-socials') as HTMLElement; + const socialsContainer = this.rootElem.querySelector('.sim-sidebar-socials')!; socialsContainer.appendChild(SocialLinks.buildDiscordLink()); socialsContainer.appendChild(SocialLinks.buildGitHubLink()); socialsContainer.appendChild(SocialLinks.buildPatreonLink()); - this.simTabContentsContainer = this.rootElem.querySelector('.sim-main.tab-content') as HTMLElement; + this.simTabContentsContainer = this.rootElem.querySelector('.sim-main.tab-content')!; if (!this.isWithinRaidSim) { window.addEventListener('message', async event => { diff --git a/ui/core/talents/talents_picker.tsx b/ui/core/talents/talents_picker.tsx index 1fc4353cf7..ddd584f65a 100644 --- a/ui/core/talents/talents_picker.tsx +++ b/ui/core/talents/talents_picker.tsx @@ -196,12 +196,12 @@ class TalentTreePicker extends Component { ); this.title = this.rootElem.getElementsByClassName('talent-tree-title')[0] as HTMLElement; - this.pointsElem = this.rootElem.querySelector('.talent-tree-points') as HTMLElement; + this.pointsElem = this.rootElem.querySelector('.talent-tree-points')!; - const background = this.rootElem.querySelector('.talent-tree-background') as HTMLElement; + const background = this.rootElem.querySelector('.talent-tree-background')!; background.style.backgroundImage = `url('${config.backgroundUrl}')`; - const main = this.rootElem.querySelector('.talent-tree-main') as HTMLElement; + const main = this.rootElem.querySelector('.talent-tree-main')!; main.style.gridTemplateRows = `repeat(${this.picker.numRows}, 1fr)`; // Add 2 for spacing on the sides main.style.gridTemplateColumns = `repeat(${this.picker.numCols}, 1fr)`; @@ -235,7 +235,7 @@ class TalentTreePicker extends Component { if (t.config.prereqLocation !== undefined) continue; recurseCalcIdx(t, 20); } - const resetBtn = this.rootElem.querySelector('.talent-tree-reset') as HTMLElement; + const resetBtn = this.rootElem.querySelector('.talent-tree-reset')!; tippy(resetBtn, { content: 'Reset talent points' }); resetBtn.addEventListener('click', _ => { this.talents.forEach(talent => talent.setPoints(0, false)); diff --git a/ui/index_template.html b/ui/index_template.html index e3f72dcea3..36838c535d 100644 --- a/ui/index_template.html +++ b/ui/index_template.html @@ -19,13 +19,6 @@ crossorigin="anonymous" referrerpolicy="no-referrer" /> - - - diff --git a/ui/raid/components/blessings_picker.ts b/ui/raid/components/blessings_picker.ts index 3d92a31b90..9fddfb654e 100644 --- a/ui/raid/components/blessings_picker.ts +++ b/ui/raid/components/blessings_picker.ts @@ -97,7 +97,7 @@ export class BlessingsPicker extends Component { `; - const icon = fragment.querySelector('.blessings-spec-icon') as HTMLElement; + const icon = fragment.querySelector('.blessings-spec-icon')!; tippy(icon, { content: specNames[spec] }); return fragment.children[0] as HTMLElement; diff --git a/ui/raid/raid_picker.tsx b/ui/raid/raid_picker.tsx index e8fa461180..66b13af44e 100644 --- a/ui/raid/raid_picker.tsx +++ b/ui/raid/raid_picker.tsx @@ -521,12 +521,12 @@ export class PlayerPicker extends Component { `; - this.labelElem = this.rootElem.querySelector('.player-label') as HTMLElement; - this.iconElem = this.rootElem.querySelector('.player-icon') as HTMLImageElement; - this.nameElem = this.rootElem.querySelector('.player-name') as HTMLInputElement; - this.resultsElem = this.rootElem.querySelector('.player-results') as HTMLElement; - this.dpsResultElem = this.rootElem.querySelector('.player-results-dps') as HTMLElement; - this.referenceDeltaElem = this.rootElem.querySelector('.player-results-reference-delta') as HTMLElement; + this.labelElem = this.rootElem.querySelector('.player-label')!; + this.iconElem = this.rootElem.querySelector('.player-icon')!; + this.nameElem = this.rootElem.querySelector('.player-name')!; + this.resultsElem = this.rootElem.querySelector('.player-results')!; + this.dpsResultElem = this.rootElem.querySelector('.player-results-dps')!; + this.referenceDeltaElem = this.rootElem.querySelector('.player-results-reference-delta')!; this.bindPlayerEvents(); } diff --git a/ui/raid/raid_stats.tsx b/ui/raid/raid_stats.tsx index 2869101275..33ab43d946 100644 --- a/ui/raid/raid_stats.tsx +++ b/ui/raid/raid_stats.tsx @@ -124,7 +124,7 @@ class RaidStatsCategory extends Component { const total = sum(this.effects.map(effect => effect.count)); this.counterElem.textContent = String(total); - const statsLink = this.rootElem.querySelector('.raid-stats-category') as HTMLElement; + const statsLink = this.rootElem.querySelector('.raid-stats-category')!; if (total == 0) { statsLink?.classList.remove('active'); @@ -166,12 +166,12 @@ class RaidStatsEffect extends Component { this.counterElem = counterElemRef.value!; if (this.options.playerData?.class) { - const labelElem = this.rootElem.querySelector('.raid-stats-effect-label') as HTMLElement; + const labelElem = this.rootElem.querySelector('.raid-stats-effect-label')!; const playerCssClass = textCssClassForClass(this.options.playerData.class); labelElem.classList.add(playerCssClass); } - const iconElem = this.rootElem.querySelector('.raid-stats-effect-icon') as HTMLImageElement; + const iconElem = this.rootElem.querySelector('.raid-stats-effect-icon')!; if (options.actionId) { options.actionId.fill().then(actionId => (iconElem.src = actionId.iconUrl)); } else { diff --git a/ui/shared/bootstrap_overrides.ts b/ui/shared/bootstrap_overrides.ts index eb3acc87ea..d4453b449f 100644 --- a/ui/shared/bootstrap_overrides.ts +++ b/ui/shared/bootstrap_overrides.ts @@ -6,7 +6,7 @@ import { isDescendant } from './utils'; Dropdown.Default.offset = [0, -1]; //Dropdown.Default.display = "static"; -const body = document.querySelector('body') as HTMLElement; +const body = document.querySelector('body')!; export const hasTouch = () => 'ontouchstart' in window || navigator.maxTouchPoints > 0;