sidenav-menu-arrows
Version:
Material Multi-Level Menu for Angular Projects.
574 lines (563 loc) • 22.2 kB
JavaScript
import { CommonModule } from '@angular/common';
import { MatIconModule, MatListModule, MatRippleModule } from '@angular/material';
import { NgModule, Injectable, Component, Input, Output, EventEmitter, defineInjectable } from '@angular/core';
import { Router, NavigationEnd } from '@angular/router';
import { trigger, style, transition, animate, state, group } from '@angular/animations';
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class MaterialsModule {
}
MaterialsModule.decorators = [
{ type: NgModule, args: [{
imports: [
MatIconModule,
MatListModule,
MatRippleModule,
],
declarations: [],
exports: [
MatIconModule,
MatListModule,
MatRippleModule,
]
},] }
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class MultilevelMenuService {
/**
* @return {?}
*/
generateId() {
/** @type {?} */
let text = '';
/** @type {?} */
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (let i = 0; i < 20; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
}
/**
* @param {?} nodes
* @return {?}
*/
addRandomId(nodes) {
nodes.forEach((node) => {
node.id = this.generateId();
if (node.items !== undefined) {
this.addRandomId(node.items);
}
});
}
/**
* @param {?} node
* @param {?} nodeId
* @return {?}
*/
recursiveCheckId(node, nodeId) {
if (node.id === nodeId) {
return true;
}
else {
if (node.items !== undefined) {
return node.items.some((nestedNode) => {
return this.recursiveCheckId(nestedNode, nodeId);
});
}
}
}
/**
* @param {?} nodes
* @param {?} link
* @return {?}
*/
recursiveCheckLink(nodes, link) {
for (let nodeIndex = 0; nodeIndex < nodes.length; nodeIndex++) {
/** @type {?} */
const node = nodes[nodeIndex];
for (const key in node) {
if (node.hasOwnProperty(key)) {
if (encodeURI(node.link) === link) {
this.foundLinkObject = node;
}
else {
if (node.items !== undefined) {
this.recursiveCheckLink(node.items, link);
}
}
}
}
}
}
/**
* @param {?} node
* @param {?} link
* @return {?}
*/
getMatchedObjectByUrl(node, link) {
this.recursiveCheckLink(node, link);
return this.foundLinkObject;
}
}
MultilevelMenuService.decorators = [
{ type: Injectable, args: [{
providedIn: 'root'
},] }
];
/** @nocollapse */ MultilevelMenuService.ngInjectableDef = defineInjectable({ factory: function MultilevelMenuService_Factory() { return new MultilevelMenuService(); }, token: MultilevelMenuService, providedIn: "root" });
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/** @type {?} */
const CONSTANT = {
PADDING_AT_START: true,
DEFAULT_CLASS_NAME: `amml-container`,
DEFAULT_LIST_CLASS_NAME: `amml-item`,
SELECTED_LIST_CLASS_NAME: `selected-amml-item`,
ACTIVE_ITEM_CLASS_NAME: `active-amml-item`,
DEFAULT_SELECTED_FONT_COLOR: `#1976d2`,
DEFAULT_LIST_BACKGROUND_COLOR: `transparent`,
DEFAULT_LIST_FONT_COLOR: `rgba(0,0,0,.87)`,
ERROR_MESSAGE: `Invalid data for material Multilevel List Component`
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class NgMaterialMultilevelMenuComponent {
/**
* @param {?} router
* @param {?} multilevelMenuService
*/
constructor(router, multilevelMenuService) {
this.router = router;
this.multilevelMenuService = multilevelMenuService;
this.configuration = null;
this.selectedItem = new EventEmitter();
this.selectedLabel = new EventEmitter();
this.nodeConfig = {
paddingAtStart: true,
listBackgroundColor: null,
fontColor: null,
selectedListFontColor: null,
interfaceWithRoute: null,
collapseOnSelect: null,
highlightOnSelect: false,
rtlLayout: false,
};
this.isInvalidConfig = true;
}
/**
* @return {?}
*/
ngOnChanges() {
this.checkValidData();
this.detectInvalidConfig();
}
/**
* @return {?}
*/
ngOnInit() {
if (this.configuration !== null && this.configuration !== undefined && this.configuration !== '' &&
this.configuration.interfaceWithRoute !== null && this.configuration.interfaceWithRoute) {
this.router.events
.subscribe((event) => {
if (event instanceof NavigationEnd) {
this.updateNodeByURL(event.url);
}
});
this.updateNodeByURL(this.router.url);
}
}
/**
* @param {?} url
* @return {?}
*/
updateNodeByURL(url) {
/** @type {?} */
const foundNode = this.multilevelMenuService.getMatchedObjectByUrl(this.items, url);
if (foundNode !== undefined &&
foundNode.link !== undefined &&
foundNode.link !== null &&
foundNode.link !== '') {
this.currentNode = foundNode;
this.selectedListItem(foundNode);
}
}
/**
* @return {?}
*/
checkValidData() {
if (this.items.length === 0) {
console.warn(CONSTANT.ERROR_MESSAGE);
}
else {
this.items = this.items.filter(n => !n.hidden);
this.multilevelMenuService.addRandomId(this.items);
}
}
/**
* @return {?}
*/
detectInvalidConfig() {
if (this.configuration === null || this.configuration === undefined || this.configuration === '') {
this.isInvalidConfig = true;
}
else {
this.isInvalidConfig = false;
/** @type {?} */
const config = this.configuration;
if (config.paddingAtStart !== undefined && config.paddingAtStart !== null && typeof config.paddingAtStart === 'boolean') {
this.nodeConfig.paddingAtStart = config.paddingAtStart;
}
if (config.listBackgroundColor !== '' &&
config.listBackgroundColor !== null &&
config.listBackgroundColor !== undefined) {
this.nodeConfig.listBackgroundColor = config.listBackgroundColor;
}
if (config.fontColor !== '' &&
config.fontColor !== null &&
config.fontColor !== undefined) {
this.nodeConfig.fontColor = config.fontColor;
}
if (config.selectedListFontColor !== '' &&
config.selectedListFontColor !== null &&
config.selectedListFontColor !== undefined) {
this.nodeConfig.selectedListFontColor = config.selectedListFontColor;
}
if (config.interfaceWithRoute !== null &&
config.interfaceWithRoute !== undefined &&
typeof config.interfaceWithRoute === 'boolean') {
this.nodeConfig.interfaceWithRoute = config.interfaceWithRoute;
}
if (config.collapseOnSelect !== null &&
config.collapseOnSelect !== undefined &&
typeof config.collapseOnSelect === 'boolean') {
this.nodeConfig.collapseOnSelect = config.collapseOnSelect;
}
if (config.highlightOnSelect !== null &&
config.highlightOnSelect !== undefined &&
typeof config.highlightOnSelect === 'boolean') {
this.nodeConfig.highlightOnSelect = config.highlightOnSelect;
}
if (config.rtlLayout !== null &&
config.rtlLayout !== undefined &&
typeof config.rtlLayout === 'boolean') {
this.nodeConfig.rtlLayout = config.rtlLayout;
}
}
}
/**
* @return {?}
*/
getClassName() {
if (this.isInvalidConfig) {
return CONSTANT.DEFAULT_CLASS_NAME;
}
else {
if (this.configuration.classname !== '' && this.configuration.classname !== null && this.configuration.classname !== undefined) {
return `${CONSTANT.DEFAULT_CLASS_NAME} ${this.configuration.classname}`;
}
else {
return CONSTANT.DEFAULT_CLASS_NAME;
}
}
}
/**
* @return {?}
*/
getGlobalStyle() {
if (!this.isInvalidConfig) {
/** @type {?} */
const styles = {
background: null
};
if (this.configuration.backgroundColor !== '' &&
this.configuration.backgroundColor !== null &&
this.configuration.backgroundColor !== undefined) {
styles.background = this.configuration.backgroundColor;
}
return styles;
}
}
/**
* @return {?}
*/
isRtlLayout() {
return this.nodeConfig.rtlLayout;
}
/**
* @param {?} event
* @return {?}
*/
selectedListItem(event) {
this.currentNode = event;
if (event.items === undefined && (!event.onSelected || typeof event.onSelected !== 'function')) {
this.selectedItem.emit(event);
}
else {
this.selectedLabel.emit(event);
}
}
}
NgMaterialMultilevelMenuComponent.decorators = [
{ type: Component, args: [{
selector: 'ng-material-multilevel-menu',
template: "<div [ngClass]=\"getClassName()\" [ngStyle]=\"getGlobalStyle()\" *ngIf='items.length !== 0' [dir]=\"isRtlLayout() ? 'rtl' : 'ltr'\">\r\n <mat-list>\r\n <ng-list-item\r\n *ngFor=\"let node of items\"\r\n [nodeConfiguration]='nodeConfig'\r\n [node]='node'\r\n [selectedNode]='currentNode'\r\n (selectedItem)=\"selectedListItem($event)\r\n \">\r\n </ng-list-item>\r\n </mat-list>\r\n</div>",
styles: [".amml-item{line-height:48px;display:flex;justify-content:space-between;position:relative}.anml-data{width:100%;text-transform:capitalize;display:flex;justify-content:flex-start}.amml-icon-fa{font-size:20px}.amml-icon{line-height:48px}.active{color:#1976d2}div[dir=ltr] .amml-icon{margin-right:15px}div[dir=ltr] .amml-submenu{margin-left:16px}div[dir=rtl] .amml-icon{margin-left:15px}div[dir=rtl] .amml-submenu{margin-right:16px}"]
}] }
];
/** @nocollapse */
NgMaterialMultilevelMenuComponent.ctorParameters = () => [
{ type: Router },
{ type: MultilevelMenuService }
];
NgMaterialMultilevelMenuComponent.propDecorators = {
items: [{ type: Input }],
configuration: [{ type: Input }],
selectedItem: [{ type: Output }],
selectedLabel: [{ type: Output }]
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class ListItemComponent {
/**
* @param {?} router
* @param {?} multilevelMenuService
*/
constructor(router, multilevelMenuService) {
this.router = router;
this.multilevelMenuService = multilevelMenuService;
this.level = 1;
this.nodeConfiguration = null;
this.selectedItem = new EventEmitter();
this.isSelected = false;
this.expanded = false;
this.firstInitializer = false;
this.selectedListClasses = {
[CONSTANT.DEFAULT_LIST_CLASS_NAME]: true,
[CONSTANT.SELECTED_LIST_CLASS_NAME]: false,
[CONSTANT.ACTIVE_ITEM_CLASS_NAME]: false,
};
}
/**
* @return {?}
*/
ngOnChanges() {
this.nodeChildren = this.node && this.node.items ? this.node.items.filter(n => !n.hidden) : [];
if (this.selectedNode !== undefined && this.selectedNode !== null) {
this.setSelectedClass(this.multilevelMenuService.recursiveCheckId(this.node, this.selectedNode.id));
}
}
/**
* @param {?} isFound
* @return {?}
*/
setSelectedClass(isFound) {
if (isFound) {
if (!this.firstInitializer) {
this.expanded = true;
}
this.isSelected = this.nodeConfiguration.highlightOnSelect || this.selectedNode.items === undefined ? true : false;
}
else {
this.isSelected = false;
if (this.nodeConfiguration.collapseOnSelect) {
this.expanded = false;
}
}
this.selectedListClasses = {
[CONSTANT.DEFAULT_LIST_CLASS_NAME]: true,
[CONSTANT.SELECTED_LIST_CLASS_NAME]: this.isSelected,
[CONSTANT.ACTIVE_ITEM_CLASS_NAME]: this.selectedNode.id === this.node.id,
};
this.setClasses();
}
/**
* @return {?}
*/
getPaddingAtStart() {
return this.nodeConfiguration.paddingAtStart ? true : false;
}
/**
* @return {?}
*/
getListStyle() {
/** @type {?} */
const styles = {
background: CONSTANT.DEFAULT_LIST_BACKGROUND_COLOR,
color: CONSTANT.DEFAULT_LIST_FONT_COLOR
};
if (this.nodeConfiguration.listBackgroundColor !== null) {
styles.background = this.nodeConfiguration.listBackgroundColor;
}
if (this.isSelected) {
this.nodeConfiguration.selectedListFontColor !== null ?
styles.color = this.nodeConfiguration.selectedListFontColor : styles.color = CONSTANT.DEFAULT_SELECTED_FONT_COLOR;
}
else if (this.nodeConfiguration.fontColor !== null) {
styles.color = this.nodeConfiguration.fontColor;
}
return styles;
}
/**
* @param {?} node
* @return {?}
*/
getListIcon(node) {
if (node.icon !== null && node.icon !== undefined && node.icon !== '') {
return `icon`;
}
else if (node.faIcon !== null && node.faIcon !== undefined && node.faIcon !== '') {
return `faicon`;
}
else if (node.imageIcon !== null && node.imageIcon !== undefined && node.imageIcon !== '') {
return `imageicon`;
}
else if (node.svgIcon !== null && node.svgIcon !== undefined && node.svgIcon !== '') {
return `svgicon`;
}
else {
return ``;
}
}
/**
* @return {?}
*/
hasItems() {
return this.nodeChildren.length > 0 ? true : false;
}
/**
* @return {?}
*/
isRtlLayout() {
return this.nodeConfiguration.rtlLayout;
}
/**
* @return {?}
*/
setClasses() {
this.classes = {
['level-' + this.level]: true,
'amml-submenu': this.hasItems() && this.getPaddingAtStart()
};
}
/**
* @param {?} node
* @return {?}
*/
expand(node) {
this.expanded = !this.expanded;
this.firstInitializer = true;
this.setClasses();
if (this.nodeConfiguration.interfaceWithRoute !== null
&& this.nodeConfiguration.interfaceWithRoute
&& node.link !== undefined
&& node.link) {
if (node.externalRedirect !== undefined && node.externalRedirect) {
window.location.href = node.link;
}
else {
this.router.navigate([node.link]);
}
}
else if (node.onSelected && typeof node.onSelected === 'function') {
node.onSelected(node);
this.selectedListItem(node);
}
else if (node.items === undefined || this.nodeConfiguration.collapseOnSelect) {
this.selectedListItem(node);
}
}
/**
* @param {?} node
* @return {?}
*/
selectedListItem(node) {
this.selectedItem.emit(node);
}
}
ListItemComponent.decorators = [
{ type: Component, args: [{
selector: 'ng-list-item',
template: "<mat-list-item matRipple [ngClass]=\"selectedListClasses\" *ngIf=\"!node.hidden\" (click)=\"expand(node)\" title=\"{{node.label}}\"\r\n [ngStyle]=\"getListStyle()\">\r\n <div class=\"anml-data\" [dir]=\"isRtlLayout() ? 'rtl' : 'ltr'\">\r\n <div class=\"icon-container\" [ngSwitch]=\"getListIcon(node)\">\r\n <span *ngSwitchCase=\"'faicon'\" class=\"amml-icon amml-icon-fa\">\r\n <i [ngClass]=\"node.faIcon\"></i>\r\n </span>\r\n <mat-icon *ngSwitchCase=\"'icon'\" class=\"amml-icon\">\r\n {{node.icon}}\r\n </mat-icon>\r\n <mat-icon *ngSwitchCase=\"'svgicon'\" svgIcon=\"{{node.svgIcon}}\" class=\"amml-icon amml-svg-icon\">\r\n </mat-icon>\r\n <img matListAvatar *ngSwitchCase=\"'imageicon'\" class=\"amml-icon\" src=\"{{node.imageIcon}}\" alt=\"{{node.label}}\"/>\r\n </div>\r\n <span class=\"label\">{{node.label}}</span>\r\n </div>\r\n <div class=\"amml-icon-arrow-container\" *ngIf='hasItems()'>\r\n <mat-icon *ngIf='!isRtlLayout()' [@isExpandedLTR]=\"expanded ? 'yes' : 'no'\">\r\n keyboard_arrow_down\r\n </mat-icon>\r\n <mat-icon *ngIf='isRtlLayout()' [@isExpandedRTL]=\"expanded ? 'yes' : 'no'\">\r\n keyboard_arrow_down\r\n </mat-icon>\r\n </div>\r\n</mat-list-item>\r\n\r\n<mat-divider></mat-divider>\r\n\r\n<div *ngIf=\"hasItems() && expanded\" [@slideInOut] [dir]=\"isRtlLayout() ? 'rtl' : 'ltr'\" [ngClass]=\"classes\">\r\n <ng-list-item *ngFor=\"let singleNode of nodeChildren\"\r\n [nodeConfiguration]='nodeConfiguration'\r\n [node]='singleNode'\r\n [level]=\"level + 1\"\r\n [selectedNode]='selectedNode'\r\n (selectedItem)=\"selectedListItem($event)\">\r\n </ng-list-item>\r\n</div>\r\n",
animations: [
trigger('slideInOut', [
state('in', style({ height: '*', opacity: 0 })),
transition(':leave', [
style({ height: '*', opacity: 0.2 }),
group([
animate(200, style({ height: 0 })),
animate('200ms ease-out', style({ opacity: 0 }))
])
]),
transition(':enter', [
style({ height: '0', opacity: 0 }),
group([
animate(200, style({ height: '*' })),
animate('400ms ease-out', style({ opacity: 1 }))
])
])
]),
trigger('isExpandedLTR', [
state('no', style({ transform: 'rotate(0deg)' })),
state('yes', style({ transform: 'rotate(-180deg)', })),
transition('no => yes', animate(200)),
transition('yes => no', animate(200))
]),
trigger('isExpandedRTL', [
state('no', style({ transform: 'rotate(0deg)' })),
state('yes', style({ transform: 'rotate(180deg)', })),
transition('no => yes', animate(200)),
transition('yes => no', animate(200))
])
],
styles: [".amml-item{line-height:48px;position:relative;cursor:pointer}.anml-data{width:100%;text-transform:capitalize;display:flex;justify-content:flex-start;height:48px}.amml-icon-fa{font-size:20px}.amml-icon,.label{line-height:48px}.amml-svg-icon{line-height:57px;width:22px;height:22px}.amml-icon-arrow-container{direction:ltr;display:flex;align-items:center}div[dir=ltr] .amml-icon{margin-right:16px}div[dir=ltr].amml-submenu,div[dir=rtl] .amml-icon{margin-left:16px}div[dir=rtl].amml-submenu{margin-right:16px}"]
}] }
];
/** @nocollapse */
ListItemComponent.ctorParameters = () => [
{ type: Router },
{ type: MultilevelMenuService }
];
ListItemComponent.propDecorators = {
node: [{ type: Input }],
level: [{ type: Input }],
selectedNode: [{ type: Input }],
nodeConfiguration: [{ type: Input }],
selectedItem: [{ type: Output }]
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class NgMaterialMultilevelMenuModule {
}
NgMaterialMultilevelMenuModule.decorators = [
{ type: NgModule, args: [{
imports: [
CommonModule,
MaterialsModule
],
declarations: [NgMaterialMultilevelMenuComponent, ListItemComponent],
exports: [NgMaterialMultilevelMenuComponent]
},] }
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
export { NgMaterialMultilevelMenuModule, ListItemComponent as ɵd, MaterialsModule as ɵa, MultilevelMenuService as ɵc, NgMaterialMultilevelMenuComponent as ɵb };
//# sourceMappingURL=ng-material-multilevel-menu.js.map