Skip to content

Commit

Permalink
Merge pull request #609 from wowsims/feature/apl-reset
Browse files Browse the repository at this point in the history
[UI] Add APL reset button
  • Loading branch information
rosenrusinov authored Jun 5, 2024
2 parents cc152be + 0900582 commit d73aa3c
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 90 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import * as Tooltips from '../../constants/tooltips.js';
import { ref } from 'tsx-vanilla';

import * as Tooltips from '../../constants/tooltips';
import { IndividualSimUI, InputSection } from '../../individual_sim_ui';
import { Player } from '../../player';
import { APLRotation, APLRotation_Type as APLRotationType } from '../../proto/apl';
Expand All @@ -7,7 +9,7 @@ import { EventID, TypedEvent } from '../../typed_event';
import { BooleanPicker } from '../boolean_picker';
import { ContentBlock } from '../content_block';
import { EnumPicker } from '../enum_picker';
import * as IconInputs from '../icon_inputs.js';
import * as IconInputs from '../icon_inputs';
import { Input } from '../input';
import { NumberPicker } from '../number_picker';
import { SavedDataManager } from '../saved_data_manager';
Expand All @@ -25,11 +27,9 @@ export class RotationTab extends SimTab {
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 = (<div className="rotation-tab-left tab-panel-left" />) as HTMLElement;

this.rightPanel = document.createElement('div');
this.rightPanel.classList.add('rotation-tab-right', 'tab-panel-right');
this.rightPanel = (<div className="rotation-tab-right tab-panel-right" />) as HTMLElement;

this.contentContainer.appendChild(this.leftPanel);
this.contentContainer.appendChild(this.rightPanel);
Expand All @@ -51,27 +51,50 @@ export class RotationTab extends SimTab {
}

private updateSections() {
this.rootElem.classList.remove('rotation-type-auto');
this.rootElem.classList.remove('rotation-type-simple');
this.rootElem.classList.remove('rotation-type-apl');
this.rootElem.classList.remove('rotation-type-legacy');

const rotType = this.simUI.player.getRotationType();
if (rotType == APLRotationType.TypeAuto) {
this.rootElem.classList.add('rotation-type-auto');
} else if (rotType == APLRotationType.TypeSimple) {
this.rootElem.classList.add('rotation-type-simple');
} else if (rotType == APLRotationType.TypeAPL) {
this.rootElem.classList.add('rotation-type-apl');
this.rootElem.classList.remove('rotation-type-auto', 'rotation-type-simple', 'rotation-type-apl', 'rotation-type-legacy');

const rotationType = this.simUI.player.getRotationType();
let rotationClass = '';
switch (rotationType) {
case APLRotationType.TypeAuto:
rotationClass = 'rotation-type-auto';
break;
case APLRotationType.TypeSimple:
rotationClass = 'rotation-type-simple';
break;
case APLRotationType.TypeAPL:
rotationClass = 'rotation-type-apl';
break;
}

this.rootElem.classList.add(rotationClass);
}

private buildHeader() {
const header = document.createElement('div');
header.classList.add('rotation-tab-header');
this.leftPanel.appendChild(header);
const headerRef = ref<HTMLDivElement>();
const resetButtonRef = ref<HTMLButtonElement>();
const rotationTypeSelectRef = ref<HTMLDivElement>();
this.leftPanel.appendChild(
<div ref={headerRef} className="rotation-tab-header d-flex justify-content-between align-items-baseline">
<div ref={rotationTypeSelectRef} />
<button ref={resetButtonRef} className="btn btn-sm btn-reset summary-table-reset-button">
Reset APL
<i className="fas fa-close ms-1"></i>
</button>
</div>,
);

resetButtonRef.value!.addEventListener('click', () => {
this.simUI.applyEmptyAplRotation(TypedEvent.nextEventID());
});

this.simUI.player.rotationChangeEmitter.on(() => {
const type = this.simUI.player.getRotationType();
resetButtonRef.value?.classList[type === APLRotationType.TypeAPL ? 'remove' : 'add']('hide');
});

new EnumPicker(header, this.simUI.player, {
new EnumPicker(rotationTypeSelectRef.value!, this.simUI.player, {
extraCssClasses: ['w-auto'],
id: 'rotation-tab-rotation-type',
label: 'Rotation Type',
labelTooltip: 'Which set of options to use for specifying the rotation.',
Expand All @@ -96,17 +119,14 @@ export class RotationTab extends SimTab {
}

private buildAutoContent() {
const content = document.createElement('div');
content.classList.add('rotation-tab-auto');
this.leftPanel.appendChild(content);
this.leftPanel.appendChild(<div className="rotation-tab-auto" />);
}

private buildAplContent() {
const content = document.createElement('div');
content.classList.add('rotation-tab-apl');
this.leftPanel.appendChild(content);
const contentRef = ref<HTMLDivElement>();
this.leftPanel.appendChild(<div ref={contentRef} className="rotation-tab-apl" />);

new APLRotationPicker(content, this.simUI, this.simUI.player);
new APLRotationPicker(contentRef.value!, this.simUI, this.simUI.player);
}

private buildSimpleContent() {
Expand All @@ -133,11 +153,6 @@ export class RotationTab extends SimTab {
}

this.configureInputSection(contentBlock.bodyElement, this.simUI.individualConfig.rotationInputs);

contentBlock.bodyElement.querySelectorAll('.input-root').forEach(elem => {
elem.classList.add('input-inline');
});

const cooldownsContentBlock = new ContentBlock(this.leftPanel, 'cooldown-settings', {
header: { title: 'Cooldowns', tooltip: Tooltips.COOLDOWNS_SECTION },
});
Expand All @@ -148,18 +163,19 @@ export class RotationTab extends SimTab {

private configureInputSection(sectionElem: HTMLElement, sectionConfig: InputSection) {
sectionConfig.inputs.forEach(inputConfig => {
inputConfig.extraCssClasses = [...(inputConfig.extraCssClasses || []), 'input-inline'];
if (inputConfig.type == 'number') {
new NumberPicker(sectionElem, this.simUI.player, inputConfig);
new NumberPicker(sectionElem, this.simUI.player, { ...inputConfig, inline: true });
} else if (inputConfig.type == 'boolean') {
new BooleanPicker(sectionElem, this.simUI.player, { ...inputConfig });
new BooleanPicker(sectionElem, this.simUI.player, { ...inputConfig, inline: true });
} else if (inputConfig.type == 'enum') {
new EnumPicker(sectionElem, this.simUI.player, inputConfig);
new EnumPicker(sectionElem, this.simUI.player, { ...inputConfig, inline: true });
}
});
}

private configureIconSection(sectionElem: HTMLElement, iconPickers: Array<any>, adjustColumns?: boolean) {
if (iconPickers.length == 0) {
if (!iconPickers.length) {
sectionElem.classList.add('hide');
} else if (adjustColumns) {
if (iconPickers.length <= 4) {
Expand Down
4 changes: 1 addition & 3 deletions ui/core/components/input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,6 @@ export abstract class Input<ModObject, T, V = T> extends Component {
}

static newGroupContainer(): HTMLElement {
const group = document.createElement('div');
group.classList.add('picker-group');
return group;
return (<div className="picker-group" />) as HTMLElement;
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import tippy from 'tippy.js';
import { ref } from 'tsx-vanilla';

import { Component } from '../components/component.js';
import { EventID, TypedEvent } from '../typed_event.js';
import { EventID, TypedEvent } from '../typed_event';
import { Component } from './component';
import { ContentBlock, ContentBlockHeaderConfig } from './content_block';

export type SavedDataManagerConfig<ModObject, T> = {
Expand Down Expand Up @@ -44,7 +45,7 @@ export class SavedDataManager<ModObject, T> extends Component {
private readonly savedDataDiv: HTMLElement;
private readonly presetDataDiv: HTMLElement;
private readonly customDataDiv: HTMLElement;
private readonly saveInput?: HTMLInputElement;
private saveInput?: HTMLInputElement;

private frozen: boolean;

Expand All @@ -59,19 +60,22 @@ export class SavedDataManager<ModObject, T> extends Component {

const contentBlock = new ContentBlock(this.rootElem, 'saved-data', { header: config.header });

contentBlock.bodyElement.innerHTML = `
<div class="saved-data-container hide">
<div class="saved-data-presets"></div>
<div class="saved-data-custom"></div>
</div>
`;
this.savedDataDiv = contentBlock.bodyElement.querySelector('.saved-data-container') as HTMLElement;
this.presetDataDiv = contentBlock.bodyElement.querySelector('.saved-data-presets') as HTMLElement;
this.customDataDiv = contentBlock.bodyElement.querySelector('.saved-data-custom') as HTMLElement;
const savedDataRef = ref<HTMLDivElement>();
const presetDataRef = ref<HTMLDivElement>();
const customDataRef = ref<HTMLDivElement>();
contentBlock.bodyElement.replaceChildren(
<div ref={savedDataRef} className="saved-data-container hide">
<div ref={presetDataRef} className="saved-data-presets" />
<div ref={customDataRef} className="saved-data-custom" />
</div>,
);

this.savedDataDiv = savedDataRef.value!;
this.presetDataDiv = presetDataRef.value!;
this.customDataDiv = customDataRef.value!;

if (!config.presetsOnly) {
contentBlock.bodyElement.appendChild(this.buildCreateContainer());
this.saveInput = contentBlock.bodyElement.querySelector('.saved-data-save-input') as HTMLInputElement;
}
}

Expand All @@ -96,38 +100,29 @@ export class SavedDataManager<ModObject, T> extends Component {
}

private makeSavedData(config: SavedDataConfig<ModObject, T>): SavedData<ModObject, T> {
const dataElemFragment = document.createElement('fragment');
dataElemFragment.innerHTML = `
<div class="saved-data-set-chip badge rounded-pill">
<a href="javascript:void(0)" class="saved-data-set-name" role="button">${config.name}</a>
const deleteButtonRef = ref<HTMLAnchorElement>();
const dataElem = (
<div className="saved-data-set-chip badge rounded-pill">
<a href="javascript:void(0)" className="saved-data-set-name" attributes={{ role: 'button' }}>
{config.name}
</a>
{!config.isPreset && (
<a ref={deleteButtonRef} href="javascript:void(0)" className="saved-data-set-delete" attributes={{ role: 'button' }}>
<i className="fa fa-times fa-lg"></i>
</a>
)}
</div>
`;
) as HTMLElement;

const dataElem = dataElemFragment.children[0] as HTMLElement;
dataElem.addEventListener('click', () => {
this.config.setData(TypedEvent.nextEventID(), this.modObject, config.data);

if (this.saveInput) this.saveInput.value = config.name;
});

if (!config.isPreset) {
const deleteFragment = document.createElement('fragment');
deleteFragment.innerHTML = `
<a
href="javascript:void(0)"
class="saved-data-set-delete"
role="button"
>
<i class="fa fa-times fa-lg"></i>
</a>
`;

const deleteButton = deleteFragment.children[0] as HTMLElement;
dataElem.appendChild(deleteButton);

const tooltip = tippy(deleteButton, { content: `Delete saved ${this.config.label}` });

deleteButton.addEventListener('click', event => {
if (!config.isPreset && deleteButtonRef.value) {
const tooltip = tippy(deleteButtonRef.value, { content: `Delete saved ${this.config.label}` });
deleteButtonRef.value.addEventListener('click', event => {
event.stopPropagation();
const shouldDelete = confirm(`Delete saved ${this.config.label} '${config.name}'?`);
if (!shouldDelete) return;
Expand Down Expand Up @@ -216,18 +211,20 @@ export class SavedDataManager<ModObject, T> extends Component {
}

private buildCreateContainer(): HTMLElement {
const savedDataCreateFragment = document.createElement('fragment');
savedDataCreateFragment.innerHTML = `
<div class="saved-data-create-container">
<label class="form-label">${this.config.label} Name</label>
<input class="saved-data-save-input form-control" type="text" placeholder="Name">
<button class="saved-data-save-button btn btn-primary">Save ${this.config.label}</button>
const saveButtonRef = ref<HTMLButtonElement>();
const saveInputRef = ref<HTMLInputElement>();
const savedDataCreateFragment = (
<div className="saved-data-create-container">
<label className="form-label">{this.config.label} Name</label>
<input ref={saveInputRef} className="saved-data-save-input form-control" type="text" placeholder="Name" />
<button ref={saveButtonRef} className="saved-data-save-button btn btn-primary">
Save {this.config.label}
</button>
</div>
`;
) as HTMLElement;

const saveButton = savedDataCreateFragment.querySelector('.saved-data-save-button') as HTMLButtonElement;

saveButton.addEventListener('click', () => {
this.saveInput = saveInputRef.value!;
saveButtonRef.value?.addEventListener('click', () => {
if (this.frozen) return;

const newName = this.saveInput?.value;
Expand All @@ -240,14 +237,13 @@ export class SavedDataManager<ModObject, T> extends Component {
alert(`${this.config.label} with name ${newName} already exists.`);
return;
}

this.addSavedData({
name: newName,
data: this.config.getData(this.modObject),
});
this.saveUserData();
});

return savedDataCreateFragment.children[0] as HTMLElement;
return savedDataCreateFragment;
}
}
11 changes: 11 additions & 0 deletions ui/core/individual_sim_ui.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,17 @@ export abstract class IndividualSimUI<SpecType extends Spec> extends SimUI {
});
}

applyEmptyAplRotation(eventID: EventID) {
TypedEvent.freezeAllAndDo(() => {
this.player.setAplRotation(
eventID,
APLRotation.create({
type: APLRotationType.TypeAPL,
}),
);
});
}

applyDefaults(eventID: EventID) {
TypedEvent.freezeAllAndDo(() => {
const tankSpec = this.player.getPlayerSpec().isTankSpec;
Expand Down

0 comments on commit d73aa3c

Please sign in to comment.