@marcj/angular-desktop-ui
Version:
library offering you desktop UI widgets in Angular 7+
188 lines (152 loc) • 5.09 kB
text/typescript
import {
AfterViewInit,
ContentChildren,
Directive,
EventEmitter,
forwardRef,
Input,
OnDestroy,
Output,
QueryList
} from "@angular/core";
import {WindowMenuState} from "../window/window-menu";
import {arrayHasItem} from "@marcj/estdlib";
import {Subscription} from "rxjs";
import {Electron} from "../../core/utils";
export class MenuBase implements AfterViewInit {
label?: string;
sublabel?: string;
icon?: string;
enabled: boolean = true;
accelerator?: string;
role?: string;
visible: boolean = true;
onlyMacOs: boolean | '' = false;
noMacOs: boolean | '' = false;
id?: string;
before?: string;
after?: string;
beforeGroupContaining?: string;
afterGroupContaining?: string;
click = new EventEmitter();
change = new EventEmitter;
public type = '';
protected registered = new Set<MenuBase>();
protected subscriptions = new Map<MenuBase, Subscription>();
public child?: QueryList<MenuBase>;
constructor() {
}
buildTemplate() {
const submenu = [];
if (this.child) {
for (const item of this.child.toArray()) {
if (item === this) continue;
if (!item.validOs()) {
continue
}
submenu.push(item.buildTemplate());
}
}
const result: { [name: string]: any } = {
click: () => {
this.click.emit()
},
};
if (this.label) result['label'] = this.label;
if (this.sublabel) result['sublabel'] = this.sublabel;
if (!this.enabled) result['enabled'] = false;
if (this.type) result['type'] = this.type;
if (this.accelerator) result['accelerator'] = this.accelerator;
if (this.role) result['role'] = this.role;
if (this.type) result['type'] = this.type;
if (this.accelerator) result['accelerator'] = this.accelerator;
if (submenu.length) result['submenu'] = submenu;
return result;
}
public validOs(): boolean {
if (Electron.isAvailable()) {
if (this.onlyMacOs !== false && Electron.getProcess().platform !== 'darwin') {
return false;
}
if (this.noMacOs !== false && Electron.getProcess().platform === 'darwin') {
return false;
}
}
return true;
}
ngAfterViewInit() {
if (this.child) {
this.child!.changes.subscribe((items: MenuBase[]) => {
for (const item of items) {
if (!this.registered.has(item)) {
this.registered.add(item);
this.subscriptions.set(item, item.change.subscribe(() => {
this.change.emit();
}));
}
}
for (const item of this.registered) {
if (!arrayHasItem(items, item)) {
//got removed
this.registered.delete(item);
this.subscriptions.get(item)!.unsubscribe();
this.subscriptions.delete(item);
}
}
this.change.emit();
});
}
}
}
export class MenuItemDirective extends MenuBase {
}
export class MenuCheckboxDirective extends MenuBase {
checked: boolean = false;
type = 'checkbox';
buildTemplate() {
return {...super.buildTemplate(), checked: this.checked};
}
}
export class MenuRadioDirective extends MenuBase {
checked: boolean = false;
type = 'radio';
buildTemplate() {
return {...super.buildTemplate(), checked: this.checked};
}
}
export class MenuSeparatorDirective extends MenuBase {
type = 'separator';
}
export class MenuDirective extends MenuBase implements OnDestroy, AfterViewInit {
position: number = 0;
constructor(protected windowMenuState: WindowMenuState) {
super();
}
ngAfterViewInit() {
super.ngAfterViewInit();
this.windowMenuState.addMenu(this);
}
ngOnDestroy() {
this.windowMenuState.removeMenu(this);
}
}