projects/components/src/lib/navbar/navbar.component.ts
MenuItem interface to follow
Properties |
| icon |
icon:
|
Type : string
|
|
icon name defined by NexOpt CDN |
| id |
id:
|
Type : number
|
|
ID of item |
| isUrl |
isUrl:
|
Type : boolean
|
|
If url link is active and should be processed |
| link |
link:
|
Type : string
|
|
URL address of navbar |
| name |
name:
|
Type : string
|
|
Name of the app |
| type |
type:
|
Type : string
|
| Optional |
|
valid for activities |
import {
Component,
ElementRef,
EventEmitter,
HostListener,
Input,
OnInit,
Output,
SimpleChange,
} from '@angular/core';
import { FormControl } from '@angular/forms';
import { Subscription } from 'rxjs';
import { distinctUntilChanged, debounceTime } from 'rxjs/operators';
/**
* NavbarMenu interface to follow
*/
export interface NavbarMenu {
/**
* if we should show dots icon to open drawer with all app menu items
*/
hasAppMenu: boolean;
/**
* endpoint for builder api
*/
apiEndpoint: string;
/**
* Helper text to know how to trigger builder api
*/
apiHelp: string;
/**
* Translations for whole component
*/
translations: any;
/**
* URL address of logo
*/
logo: string;
/**
* If search icon should be shown
*/
showSearch: boolean;
/**
* Where should be search positioned
*/
searchPosition: 'left' | 'right';
/**
* Placeholder for search
*/
searchPlaceholder: '';
/**
* If microphone toggle should be present
*/
showMicIcon: boolean;
/**
* container for profile menu
*/
appsMenu: any[];
/**
* container for activity menu
*/
activityMenu: any;
/**
* container for chat menu
*/
chatMenu: any;
/**
* container for profile menu
*/
profileMenu: MenuDropdown[];
/**
* container for left menu
*/
leftMenu: MenuDropdown[];
/**
* container for right menu
*/
rightMenu: MenuDropdown[];
}
/**
* Dropdown interface to follow
*/
export interface MenuDropdown {
/**
* name of the dropdown
*/
name: string;
/**
* Imag of the profile
*/
image?: string;
/**
* icon name defined by [NexOpt CDN]{@link https://cdn.nexopt.com/icons}
*/
icon: string;
/**
* Specifies badge to be shown if there is any count (i.e. activities)
*/
count: number;
/**
* items inside dropdown
*/
links: MenuItem[];
}
/**
* MenuItem interface to follow
*/
export interface MenuItem {
/**
* ID of item
*/
id: number;
/**
* URL address of navbar
*/
link: string;
/**
* If url link is active and should be processed
*/
isUrl: boolean;
/**
* icon name defined by [NexOpt CDN]{@link https://cdn.nexopt.com/icons}
*/
icon: string;
/**
* Name of the app
*/
name: string;
/**
* valid for activities
*/
type?: string;
}
/**
* @ignore
*/
declare var webkitSpeechRecognition: any;
/**
* @ignore
*/
declare var webkitSpeechGrammarList: any;
/**
* @ignore
*/
declare var webkitSpeechRecognitionEvent: any;
/**
* Navbar component
*
* Visualizes links in menu component
*
* tag: no-navbar
*/
@Component({
selector: 'no-navbar',
templateUrl: './navbar.component.html',
styleUrls: ['./navbar.component.scss'],
})
export class NavbarComponent implements OnInit {
/**
* Toggle if search is activated
*/
searchActivated: boolean = false;
/**
* Toggle if apps drawer is activated
*/
appsDrawerActivated: boolean = false;
/**
* Search control to listen for data
*/
searchControl = new FormControl();
/**
* Data to present in apps menu
*
* @example
* Simply pass in array of objects
* ```
* menuData = [
* {
* link: 'link',
* text: 'text',
* icon: 'mdi mdi-help',
* },
* {
* link: 'link',
* text: 'text',
* icon: 'mdi mdi-help',
* },
* ]
* ```
*
* if you have array you can create navbar in js
* ```
* const navbar = document.querySelector('no-navbar');
* navbar.menu = [items]
* ```
* @param {NavbarMenu} menu
*/
@Input() menu!: NavbarMenu;
/**
* Listener for selected menu item
*
* @example
* in js
* ```
* const navbar = document.querySelector('no-navbar');
* navbar.addEventListener('onMenuClick', (menuItem) => {
//could be menuItem.detail, since its event
* console.log(menuItem);
* })
* ```
*
* @return {MenuItem} menu
*/
@Output() onMenuClick: EventEmitter<MenuItem> = new EventEmitter<MenuItem>();
/**
* Listener for selected menu item
*
* @example
* in js
* ```
* const navbar = document.querySelector('no-navbar');
* navbar.addEventListener('onDrawerClicked', (menuItem) => {
//could be menuItem.detail, since its event
* console.log(menuItem);
* })
* ```
*
* @return {MenuItem} menu
*/
@Output() onDrawerClicked: EventEmitter<MenuItem> =
new EventEmitter<MenuItem>();
/**
* Listener for selected logo
*
* @example
* in js
* ```
* const navbar = document.querySelector('no-navbar');
* navbar.addEventListener('onLogoClick', (clicked) => {
//could be clicked.detail, since its event
* console.log(clicked);
* })
* ```
*
* @return {MenuItem} menu
*/
@Output() onLogoClick: EventEmitter<boolean> = new EventEmitter<boolean>();
/**
* Listener for query api data
*
* @example
* in js
* ```
* const navbar = document.querySelector('no-navbar');
* navbar.addEventListener('searchQuery', (data) => {
//could be data.detail, since its event
* console.log(data);
* })
* ```
*
* @return SearchQuery
*/
@Output() searchQuery: EventEmitter<boolean> = new EventEmitter<boolean>();
/**
* Listener for output of search if there is any error to show notification
*
* @example
* in js
* ```
* const navbar = document.querySelector('no-navbar');
* navbar.addEventListener('errorHandling', (data) => {
//could be data.detail, since its event
* console.log(data);
* })
* ```
*
* @return SearchQuery
*/
@Output() errorHandling: EventEmitter<any> = new EventEmitter<any>();
/**
* Subscription holder of search input
*/
searchInputSub!: Subscription;
/**
* @ignore
*/
SpeechRecognition: any;
/**
* @ignore
*/
SpeechGrammarList: any;
/**
* @ignore
*/
SpeechRecognitionEvent: any;
/**
* Holds recognition api
*/
recognition: any;
/**
* @ignore
*/
constructor() {}
/**
* Detection for drawer to close when clicked outside
* @param targetElement
*/
@HostListener('document:click', ['$event.target'])
public onPageClick(targetElement: any) {
if (this.appsDrawerActivated) {
if (
targetElement.classList.contains('drawer-toggle') ||
targetElement.classList.contains('drawer-item') ||
targetElement.classList.contains('drawer-link') ||
targetElement.classList.contains('drawer')
) {
} else {
this.appsDrawerActivated = false;
}
}
}
/**
* Handler for search input to process
*/
ngOnInit() {
this.searchInputSub = this.searchControl.valueChanges
.pipe(debounceTime(400), distinctUntilChanged())
.subscribe((term) => {
if (term) {
fetch(
this.menu.apiEndpoint +
'?' +
new URLSearchParams({
query: term,
})
)
.then((response) => response.json())
.then((data) => {
if (!data.syntax.hasOwnProperty('table')) {
this.errorHandling.emit(
this.menu.translations.errors.NO_RESULTS_TRY_AGAIN
);
}
this.searchQuery.emit(data);
});
}
});
}
/**
* Handling clicked logo
* @param {boolean} item
*/
logoClicked() {
this.onLogoClick.emit(true);
}
/**
* Handling clicked search
*/
searchClicked() {
this.searchActivated = !this.searchActivated;
if (!this.searchActivated) {
this.searchControl.setValue('');
if (this.recognition) {
this.recognition.stop();
}
}
}
/**
* Handling clicked apps menu
*/
openAppsMenu() {
this.appsDrawerActivated = !this.appsDrawerActivated;
}
/**
* Handling text in search
* @param e
*/
searchQueryEmit(e: any) {
this.searchQuery.emit(e);
}
/**
* Handling clicked menu item
* @param {MenuItem} item
*/
menuItemClicked(item: MenuItem, type: string = '') {
if (type) {
item.type = type;
}
this.onMenuClick.emit(item);
}
/**
* Handling clicked app menu item
* @param {MenuItem} item
*/
drawerItemClicked(item: MenuItem) {
this.onDrawerClicked.emit(item);
this.appsDrawerActivated = false;
}
/**
* Handler for clicking microphone and receiving spoken text
*/
microphoneClicked() {
this.searchControl.setValue('');
this.SpeechRecognition =
(window as any).SpeechRecognition || webkitSpeechRecognition;
this.SpeechGrammarList =
(window as any).SpeechGrammarList || webkitSpeechGrammarList;
this.SpeechRecognitionEvent =
(window as any).SpeechRecognitionEvent || webkitSpeechRecognitionEvent;
this.recognition = new this.SpeechRecognition();
this.recognition.continuous = false;
//recognition.lang = 'en-US';
this.recognition.interimResults = false;
//recognition.maxAlternatives = 1;
this.recognition.start();
this.recognition.addEventListener('end', (e: any) => {
this.recognition.stop();
console.log('End speech recognition');
});
this.recognition.addEventListener('result', (event: any) => {
let text = event.results[0][0].transcript;
console.log('Result received: ' + text + '.');
let first = text.split(' ')[0];
this.searchControl.setValue(text);
this.recognition.stop();
});
}
}