Use material menu for column visibility

This commit is contained in:
jliddev
2020-09-25 16:19:07 -05:00
parent a959e419ea
commit ad3f515b14
8 changed files with 40 additions and 203 deletions

View File

@@ -1,19 +0,0 @@
<div class="container">
<div class="header">
<div class="icon" [style.backgroundImage]="'url(' + addon.thumbnailUrl + ')'"></div>
<div>
<p>{{addon.name}}</p>
</div>
</div>
<mat-divider></mat-divider>
<div style="visibility: hidden; position: fixed" [style.left]="xPos"
[style.top]="yPos" [matMenuTriggerFor]="contextMenu">
</div>
<mat-menu #contextMenu="matMenu">
<ng-template matMenuContent let-addon="addon">
<div>{{addon.name}}</div>
<button mat-menu-item (click)="onContextMenuAction1(item)">Action 1</button>
<button mat-menu-item (click)="onContextMenuAction2(item)">Action 2</button>
</ng-template>
</mat-menu>
</div>

View File

@@ -1,26 +0,0 @@
@import "../../../variables.scss";
.container {
padding: 0.5em;
background-color: $dark-4;
color: $white-1;
.header {
display: flex;
flex-direction: row;
margin-bottom: 0.5em;
.icon {
background-color: $dark-2;
width: 40px;
height: 40px;
margin-right: 0.5em;
background-size: contain;
background-repeat: none;
}
}
p {
margin: 0;
}
}

View File

@@ -1,25 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AddonContextMenuComponent } from './addon-context-menu.component';
describe('AddonContextMenuComponent', () => {
let component: AddonContextMenuComponent;
let fixture: ComponentFixture<AddonContextMenuComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ AddonContextMenuComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(AddonContextMenuComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -1,28 +0,0 @@
import { AfterViewInit, Component, Input, OnInit, ViewChild } from '@angular/core';
import { MatMenuTrigger } from '@angular/material/menu';
import { MyAddonsListItem } from 'app/business-objects/my-addons-list-item';
import { Addon } from 'app/entities/addon';
@Component({
selector: 'app-addon-context-menu',
templateUrl: './addon-context-menu.component.html',
styleUrls: ['./addon-context-menu.component.scss']
})
export class AddonContextMenuComponent implements OnInit, AfterViewInit {
@Input('addon') addon: MyAddonsListItem;
@Input('xPos') xPos: number;
@Input('yPos') yPos: number;
@ViewChild(MatMenuTrigger) contextMenu: MatMenuTrigger;
constructor() { }
ngOnInit(): void {
}
ngAfterViewInit(): void {
console.log(this.contextMenu);
this.contextMenu.openMenu();
}
}

View File

@@ -2,4 +2,5 @@ export interface ColumnState {
name: string;
display: string;
visible: boolean;
allowToggle?: boolean;
}

View File

@@ -18,7 +18,6 @@ import { PotentialAddonTableColumnComponent } from 'app/components/potential-add
import { PotentialAddonStatusColumnComponent } from 'app/components/potential-addon-status-column/potential-addon-status-column.component';
import { MyAddonsAddonCellComponent } from 'app/components/my-addons-addon-cell/my-addons-addon-cell.component';
import { MyAddonsStatusCellComponent } from 'app/components/my-addons-status-cell/my-addons-status-cell.component';
import { AddonContextMenuComponent } from 'app/components/addon-context-menu/addon-context-menu.component';
import { ProgressSpinnerComponent } from 'app/components/progress-spinner/progress-spinner.component';
import { DownloadCountPipe } from 'app/pipes/download-count.pipe';
import { TelemetryDialogComponent } from 'app/components/telemetry-dialog/telemetry-dialog.component';
@@ -33,7 +32,6 @@ import { TelemetryDialogComponent } from 'app/components/telemetry-dialog/teleme
ExternalLinkDirective,
MyAddonsAddonCellComponent,
MyAddonsStatusCellComponent,
AddonContextMenuComponent,
PotentialAddonStatusColumnComponent,
ProgressSpinnerComponent,
PotentialAddonTableColumnComponent,

View File

@@ -38,12 +38,14 @@
<th mat-header-cell *matHeaderCellDef> Status </th>
<td mat-cell *matCellDef="let element">
<div class="status-column">
<mat-icon *ngIf="element.addon.autoUpdateEnabled" class="auto-update-icon" matTooltip="Auto update enabled">update</mat-icon>
<mat-icon *ngIf="element.addon.autoUpdateEnabled" class="auto-update-icon" matTooltip="Auto update enabled">
update</mat-icon>
<button *ngIf="element.needsInstall === true" mat-flat-button color="primary"
(click)="onInstall()">Install</button>
<button *ngIf="element.needsUpdate === true" mat-flat-button color="primary"
(click)="onUpdateAddon(element)">Update</button>
<div *ngIf="element.isUpToDate === true || element.isIgnored === true" class="status-text">{{element.statusText}}</div>
<div *ngIf="element.isUpToDate === true || element.isIgnored === true" class="status-text">
{{element.statusText}}</div>
<div *ngIf="element.isInstalling === true" class="progress-container">
<p class="progress-text">{{element.statusText}}</p>
<mat-progress-bar class="addon-progress" mode="determinate" [value]="element.installProgress">
@@ -89,19 +91,8 @@
</div>
</div>
<ng-template #columnMenu let-user>
<section class="column-menu bg-dark-4">
<p>Visible Columns</p>
<mat-divider></mat-divider>
<div class="d-flex" *ngFor="let column of columns">
<mat-checkbox class="example-margin" [checked]="column.visible" (change)="onColumnVisibleChange($event, column)">
{{column.display}}</mat-checkbox>
</div>
</section>
</ng-template>
<div style="visibility: hidden; position: fixed" [style.left]="contextMenuPosition.x"
[style.top]="contextMenuPosition.y" [matMenuTriggerFor]="contextMenu">
<div style="visibility: hidden; position: fixed" #addonContextMenuTrigger="matMenuTrigger"
[style.left]="contextMenuPosition.x" [style.top]="contextMenuPosition.y" [matMenuTriggerFor]="contextMenu">
</div>
<mat-menu #contextMenu="matMenu" class="addon-context-menu">
<ng-template matMenuContent let-listItem="listItem">
@@ -113,9 +104,11 @@
</div>
</div>
<mat-divider></mat-divider>
<mat-checkbox class="mat-menu-item" [checked]="listItem.addon.isIgnored" (change)="onClickIgnoreAddon($event, listItem)">Ignore
<mat-checkbox class="mat-menu-item" [checked]="listItem.addon.isIgnored"
(change)="onClickIgnoreAddon($event, listItem)">Ignore
</mat-checkbox>
<mat-checkbox *ngIf="listItem.addon.isIgnored === false" class="mat-menu-item" [checked]="listItem.addon.autoUpdateEnabled" (change)="onClickAutoUpdateAddon($event, listItem.addon)">Auto
<mat-checkbox *ngIf="listItem.addon.isIgnored === false" class="mat-menu-item"
[checked]="listItem.addon.autoUpdateEnabled" (change)="onClickAutoUpdateAddon($event, listItem.addon)">Auto
Update
</mat-checkbox>
<button mat-menu-item [matMenuTriggerFor]="addonChannels">Channel</button>
@@ -133,8 +126,18 @@
</ng-template>
</mat-menu>
<!--
<ng-template #addonMenu let-addon>
<app-addon-context-menu [addon]="addon"></app-addon-context-menu>
</ng-template> -->
<div style="visibility: hidden; position: fixed" #columnContextMenuTrigger="matMenuTrigger"
[style.left]="contextMenuPosition.x" [style.top]="contextMenuPosition.y" [matMenuTriggerFor]="columnContextMenu">
</div>
<mat-menu #columnContextMenu="matMenu" class="addon-context-menu">
<ng-template matMenuContent let-columns="columns">
<div class="addon-context-menu-header">
<div class="addon-name">Show Columns</div>
</div>
<mat-divider></mat-divider>
<mat-checkbox *ngFor="let column of columns" class="mat-menu-item" [checked]="column.visible"
(change)="onColumnVisibleChange($event, column)">
{{column.display}}
</mat-checkbox>
</ng-template>
</mat-menu>

View File

@@ -8,7 +8,6 @@ import { AddonService } from 'app/services/addons/addon.service';
import { SessionService } from 'app/services/session/session.service';
import { GridApi, GridOptions } from 'ag-grid-community';
import { Overlay, OverlayRef } from '@angular/cdk/overlay';
import { TemplatePortal } from '@angular/cdk/portal';
import { ColumnState } from 'app/models/wowup/column-state';
import { MatCheckboxChange } from '@angular/material/checkbox';
import { MyAddonsListItem } from 'app/business-objects/my-addons-list-item';
@@ -26,10 +25,8 @@ import { MatRadioChange } from '@angular/material/radio';
})
export class MyAddonsComponent implements OnInit, OnDestroy {
@ViewChild('columnMenu') columnMenu: TemplateRef<any>;
@ViewChild('addonMenu') addonMenu: TemplateRef<any>;
@ViewChild(MatMenuTrigger)
contextMenu: MatMenuTrigger;
@ViewChild('addonContextMenuTrigger') contextMenu: MatMenuTrigger;
@ViewChild('columnContextMenuTrigger') columnContextMenu: MatMenuTrigger;
private readonly _displayAddonsSrc = new BehaviorSubject<MyAddonsListItem[]>([]);
@@ -39,24 +36,13 @@ export class MyAddonsComponent implements OnInit, OnDestroy {
contextMenuPosition = { x: '0px', y: '0px' };
gridOptions: GridOptions = {
suppressMovableColumns: true,
suppressDragLeaveHidesColumns: true,
}
defaultColDef = {
wrapText: true,
sortable: true,
autoHeight: true,
};
columns: ColumnState[] = [
{ name: 'addon', display: 'Addon', visible: true },
{ name: 'status', display: 'Status', visible: true },
{ name: 'latestVersion', display: 'Latest Version', visible: true },
{ name: 'gameVersion', display: 'Game Version', visible: true },
{ name: 'provider', display: 'Provider', visible: true },
{ name: 'author', display: 'Author', visible: true },
{ name: 'latestVersion', display: 'Latest Version', visible: true, allowToggle: true },
{ name: 'gameVersion', display: 'Game Version', visible: true, allowToggle: true },
{ name: 'provider', display: 'Provider', visible: true, allowToggle: true },
{ name: 'author', display: 'Author', visible: true, allowToggle: true },
]
public get displayedColumns(): string[] {
@@ -142,20 +128,22 @@ export class MyAddonsComponent implements OnInit, OnDestroy {
this.enableControls = true;
}
onHeaderContext({ x, y }: MouseEvent) {
this.showContextMenu(x, y, this.columnMenu, this.displayedColumns);
onHeaderContext(event: MouseEvent) {
event.preventDefault();
this.contextMenuPosition.x = event.clientX + 'px';
this.contextMenuPosition.y = event.clientY + 'px';
this.columnContextMenu.menuData = { 'columns': this.columns.filter(col => col.allowToggle) };
this.columnContextMenu.menu.focusFirstItem('mouse');
this.columnContextMenu.openMenu();
}
onCellContext(event: MouseEvent, listItem: MyAddonsListItem) {
console.log(listItem)
event.preventDefault();
this.contextMenuPosition.x = event.clientX + 'px';
this.contextMenuPosition.y = event.clientY + 'px';
this.contextMenu.menuData = { 'listItem': listItem };
this.contextMenu.menu.focusFirstItem('mouse');
this.contextMenu.openMenu();
// this.showContextMenu(event.x, event.y, this.addonMenu, addon);
}
onUpdateAddon(listItem: MyAddonsListItem) {
@@ -185,7 +173,7 @@ export class MyAddonsComponent implements OnInit, OnDestroy {
this.addonService.saveAddon(listItem.addon);
}
onClickAutoUpdateAddon(evt: MatCheckboxChange, addon: Addon){
onClickAutoUpdateAddon(evt: MatCheckboxChange, addon: Addon) {
addon.autoUpdateEnabled = evt.checked;
this.addonService.saveAddon(addon);
}
@@ -195,61 +183,6 @@ export class MyAddonsComponent implements OnInit, OnDestroy {
this.addonService.saveAddon(addon);
}
onGridReady(params) {
this.gridApi = params.api;
this.gridApi.sizeColumnsToFit();
// simple resize debouncer
let resizeTime = 0;
this.gridApi.addEventListener('columnResized', () => {
clearTimeout(resizeTime);
resizeTime = window.setTimeout(() => {
this.gridApi?.resetRowHeights();
}, 100);
});
}
private showContextMenu(x: number, y: number, template: TemplateRef<any>, data: any) {
this.closeContext();
const positionStrategy = this.overlay.position()
.flexibleConnectedTo({ x, y })
.withPositions([
{
originX: 'end',
originY: 'bottom',
overlayX: 'end',
overlayY: 'top',
}
]);
this.overlayRef = this.overlay.create({
positionStrategy,
scrollStrategy: this.overlay.scrollStrategies.close()
});
this.overlayRef.attach(new TemplatePortal(template, this.viewContainerRef, {
$implicit: data
}));
this.sub = fromEvent<MouseEvent>(document, 'click')
.pipe(
filter(event => {
const clickTarget = event.target as HTMLElement;
return !!this.overlayRef && !this.overlayRef.overlayElement.contains(clickTarget);
}),
take(1)
).subscribe(() => this.closeContext())
}
private closeContext() {
this.sub && this.sub.unsubscribe();
if (this.overlayRef) {
this.overlayRef.dispose();
this.overlayRef = null;
}
}
private loadAddons(clientType: WowClientType, rescan = false) {
this.isBusy = true;
this.enableControls = false;