File

projects/components/src/lib/navbar/navbar.component.ts

Description

MenuItem interface to follow

Index

Properties

Properties

icon
icon: string
Type : string

icon name defined by NexOpt CDN

id
id: number
Type : number

ID of item

isUrl
isUrl: boolean
Type : boolean

If url link is active and should be processed

link
link: string
Type : string

URL address of navbar

name
name: string
Type : string

Name of the app

type
type: string
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();
    });
  }
}

results matching ""

    No results matching ""