Skip to content

Commit

Permalink
add sections capability to dropdowns
Browse files Browse the repository at this point in the history
  • Loading branch information
cbartondock committed Aug 22, 2024
1 parent 0eee117 commit 2948b7b
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 7 deletions.
4 changes: 4 additions & 0 deletions src/models/helpers.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,7 @@ export interface SteamTree<T> {


export const StringLiteralArray = <L extends string>(arr: L[])=>arr;

export interface StringDict {
[key: string]: string
}
3 changes: 3 additions & 0 deletions src/models/nested-form.model.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { AbstractControl, FormGroup, FormControl } from '@angular/forms';
import { Observable } from "rxjs";
import { StringDict } from './helpers.model';

export interface IndexedFormGroup extends FormGroup {
__path?: string[]
Expand Down Expand Up @@ -46,6 +47,8 @@ export namespace NestedFormElement {
/** Optional */
allowEmpty?: boolean
/** Optional */
sectionsMap?: StringDict
/** Optional */
required?: boolean
/** Optional */
onValidate?: NestedInputValidator;
Expand Down
78 changes: 73 additions & 5 deletions src/renderer/components/ng-select.component.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Component, forwardRef, ElementRef, Optional, Host, HostListener, Input,Output, ContentChildren, QueryList, ChangeDetectorRef } from '@angular/core';
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';
import * as _ from 'lodash';
import {SelectItem} from "../../models";
import {SelectItem, StringDict} from "../../models";

@Component({
selector: 'ng-select',
Expand All @@ -15,13 +15,29 @@ import {SelectItem} from "../../models";
<ng-text-input *ngIf="searchable" class="display" [placeholder]="placeholder" (click)="open = !open" [class.open]="open" [(ngModel)]="searchText" (ngModelChange)="searchText=$event;filterOptions($event);" value="searchText;">
</ng-text-input>
<div class="options" [class.open]="open">
<ng-option text-scroll *ngFor="let option of optionsList; let i = index"
<ng-container *ngIf="_sections.length">
<ng-container *ngFor="let option of optionsList; let i=index;">
<ng-container *ngIf="_sectionsList[i.toString()] && !searchText.length">
<div class="sectionTitle">{{_sectionsList[i.toString()].name}}</div>
</ng-container>
<ng-option text-scroll
[displayValue]="option.displayValue"
[isSelected]="selected.indexOf(i)>=0"
[isHidden]="searchable&&searchText.length&&filtered.indexOf(i)>=0"
(click)="selectOption(i, true)">
{{option.displayValue}}
</ng-option>
</ng-container>
</ng-container>
<ng-container *ngIf="!_sections.length">
<ng-option text-scroll *ngFor="let option of optionsList; let i = index;"
[displayValue]="option.displayValue"
[isSelected]="selected.indexOf(i)>=0"
[isHidden]="searchable&&searchText.length&&filtered.indexOf(i)>=0"
(click)="selectOption(i, true)">
{{option.displayValue}}
</ng-option>
</ng-container>
</div>
`,
styleUrls: [
Expand All @@ -38,6 +54,14 @@ import {SelectItem} from "../../models";
export class NgSelectComponent implements ControlValueAccessor {
open: boolean = false;
optionsList: SelectItem[] = [];
_sectionsMap: StringDict = {};
_sections: string[] = [];
_sectionsList: {
[tally: string]: {
name: string,
options: SelectItem[]
}
}={};
currentDisplay: string = '';
private currentValue: any[] = [];

Expand All @@ -51,6 +75,16 @@ export class NgSelectComponent implements ControlValueAccessor {
@Input() private separator: string = ', ';
@Input() private sort: boolean = true;
@Input() private emitOnly: boolean = false;
@Input() get sectionsMap() {
return this._sectionsMap;
}
set sectionsMap(sectionsMap: StringDict) {
if(sectionsMap) {
this._sectionsMap = sectionsMap;
this._sections = _.uniq(Object.values(sectionsMap));
this.changeOptions(this.optionsList);
}
}
@Output() searchText: string='';
@Output() filtered: number[] = [];
@Output() selected: number[] = [];
Expand All @@ -59,15 +93,49 @@ export class NgSelectComponent implements ControlValueAccessor {

changeOptions(newOptions: SelectItem[]) {
let currentOptions = this.selected.map(i=>this.optionsList[i]);
let newSelected = _.intersectionWith(newOptions, currentOptions, _.isEqual);
this.optionsList = newOptions;
let newSelected: SelectItem[] = _.intersectionWith(newOptions, currentOptions, _.isEqual);
let sortedOptions: SelectItem[];
if(this._sections.length) {
this._sectionsList = this.getSectionList(newOptions);
sortedOptions = _.flatten(Object.values(this._sectionsList).map(sec=>sec.options))
} else {
sortedOptions = newOptions;
}
this.optionsList = sortedOptions;
this.selected = newSelected.map(value=>_.findIndex(this.optionsList,(e)=>_.isEqual(e,value)));
}

toggleOpen() {
this.open = !this.open;
this.changeRef.detectChanges();
}

getSectionList(optionsList: SelectItem[]) {
let running=0;
const sections: {[tally: string]: {
name: string,
options: SelectItem[],
}} = {};
for(let sec of this._sections) {
sections[running.toString()] = {
name: sec,
options: optionsList
.filter(item =>this._sectionsMap[item.value]==sec)
.sort((a,b) => a.displayValue.localeCompare(b.displayValue))
}
running += optionsList.filter(item => this._sectionsMap[item.value]==sec).length;
}
const unmatched = optionsList.filter(item=>!this._sectionsMap[item.value])
if(unmatched.length) {
sections[running.toString()] = {
name: "Uncategorized",
options: optionsList
.sort((a,b) => a.displayValue.localeCompare(b.displayValue))
}
}
return sections
}

selectOption(id: number, toggle: boolean, suppressChanges: boolean = false) {
let valueChanged = true;
let selectedIds = this.selected;
Expand Down Expand Up @@ -227,4 +295,4 @@ export class NgSelectComponent implements ControlValueAccessor {
private getOptionId(value: any) {
return _.findIndex(this.optionsList.map(option=>option.value), (e)=>_.isEqual(e,value))
}
}
}
11 changes: 10 additions & 1 deletion src/renderer/components/parsers.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import * as parserInfo from '../../lib/parsers/available-parsers';
import * as steam from '../../lib/helpers/steam';
import { controllerTypes, controllerNames } from '../../lib/controller-manager';
import { artworkTypes, artworkViewNames, artworkSingDict } from '../../lib/artwork-types';
import { UserConfiguration, NestedFormElement, AppSettings, ConfigPresets, ControllerTemplates, ParserType, OnlineProviderType } from '../../models';
import { UserConfiguration, NestedFormElement, AppSettings, ConfigPresets, ControllerTemplates, ParserType, OnlineProviderType, StringDict } from '../../models';
import { BehaviorSubject, Subscription, of, concat } from "rxjs";
import { map } from 'rxjs/operators'
import { APP } from '../../variables';
Expand All @@ -27,6 +27,7 @@ export class ParsersComponent implements AfterViewInit, OnDestroy {
configurationIndex: number = -1;
isUnsaved: boolean = false;
configPresets: ConfigPresets = {};
presetsSections: StringDict = {};
nestedGroup: NestedFormElement.Group;
userForm: FormGroup;
chooseUserAccountsVisible: boolean = false;
Expand Down Expand Up @@ -69,6 +70,7 @@ export class ParsersComponent implements AfterViewInit, OnDestroy {
parserType: new NestedFormElement.Select({
label: this.lang.label.parserType,
placeholder: this.lang.placeholder.parserType,
sectionsMap: parserInfo.superTypesMap,
required: true,
values: parserInfo.availableParsers,
onValidate: (self, path) => this.parsersService.validate(path[0] as keyof UserConfiguration, self.value),
Expand Down Expand Up @@ -549,6 +551,10 @@ export class ParsersComponent implements AfterViewInit, OnDestroy {
return APP.lang.parsers.component;
}

get parserInfo() {
return parserInfo;
}

ngAfterViewInit() {
this.subscriptions.add(this.parsersService.getUserConfigurations().subscribe((data) => {
this.userConfigurations = data;
Expand All @@ -566,6 +572,9 @@ export class ParsersComponent implements AfterViewInit, OnDestroy {
}));
this.subscriptions.add(this.cpService.dataObservable.subscribe((data) => {
this.configPresets = data;
this.presetsSections = Object.fromEntries(Object.keys(this.configPresets).map(presetName=>[presetName,
parserInfo.superTypesMap[this.configPresets[presetName].parserType]
]).sort((a,b)=>a[1].localeCompare(b[1])))
}));
this.subscriptions.add(this.parsersService.getSavedControllerTemplates().subscribe((data) => {
this.parsersService.controllerTemplates = data;
Expand Down
7 changes: 7 additions & 0 deletions src/renderer/styles/ng-select.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -81,5 +81,12 @@

@include webkitScrollbar(ng-select-scrollbar);
}
.sectionTitle {
border-bottom: solid 1px;
background-color: var(--ng-select-background);
padding-left: 1em;
padding-top: 0.5em;
}

}
}
10 changes: 9 additions & 1 deletion src/renderer/templates/ng-nested-form.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,15 @@
</label>
<ng-container [ngSwitch]="child.constructor.displayName">
<ng-container *ngSwitchCase="'Select'">
<ng-select [formControlName]="childrenKey" [placeholder]="child.placeholder" [multiple]="child.multiple" [allowEmpty]="child.allowEmpty" [values]="child.values" [class.required]="child.required">
<ng-select
[formControlName]="childrenKey"
[placeholder]="child.placeholder"
[multiple]="child.multiple"
[allowEmpty]="child.allowEmpty"
[values]="child.values"
[sectionsMap]="child.sectionsMap"
[class.required]="child.required"
>
</ng-select>
</ng-container>
<ng-container *ngSwitchCase="'Button'">
Expand Down
1 change: 1 addition & 0 deletions src/renderer/templates/parsers.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
ngModel
(ngModelChange)="setPreset($event)"
[searchable]="true"
[sectionsMap]="presetsSections"
[values]="configPresets | keys"
>
</ng-select>
Expand Down

0 comments on commit 2948b7b

Please sign in to comment.