Code coverage report for src/link-handler.js

Statements: 9.68% (3 / 31)      Branches: 0% (0 / 27)      Functions: 18.18% (2 / 11)      Lines: 9.68% (3 / 31)      Ignored: none     

All files » src/ » link-handler.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 1221         1                                           1                                                                                                                                                                                            
import {DOM, PLATFORM} from 'aurelia-pal';
 
/**
 * Class responsible for handling interactions that should trigger browser history navigations.
 */
export class LinkHandler {
  /**
   * Activate the instance.
   *
   * @param history The BrowserHistory instance that navigations should be dispatched to.
   */
  activate(history: BrowserHistory): void {}
 
  /**
   * Deactivate the instance. Event handlers and other resources should be cleaned up here.
   */
  deactivate(): void {}
}
 
/**
 * The default LinkHandler implementation. Navigations are triggered by click events on
 * anchor elements with relative hrefs when the history instance is using pushstate.
 */
export class DefaultLinkHandler extends LinkHandler {
  /**
   * Creates an instance of DefaultLinkHandler.
   */
  constructor() {
    super();
 
    this.handler = (e) => {
      let {shouldHandleEvent, href} = DefaultLinkHandler.getEventInfo(e);
 
      if (shouldHandleEvent) {
        e.preventDefault();
        this.history.navigate(href);
      }
    };
  }
 
  /**
   * Activate the instance.
   *
   * @param history The BrowserHistory instance that navigations should be dispatched to.
   */
  activate(history: BrowserHistory): void {
    if (history._hasPushState) {
      this.history = history;
      DOM.addEventListener('click', this.handler, true);
    }
  }
 
  /**
   * Deactivate the instance. Event handlers and other resources should be cleaned up here.
   */
  deactivate(): void {
    DOM.removeEventListener('click', this.handler);
  }
 
  /**
   * Gets the href and a "should handle" recommendation, given an Event.
   *
   * @param event The Event to inspect for target anchor and href.
   */
  static getEventInfo(event: Event): Object {
    let info = {
      shouldHandleEvent: false,
      href: null,
      anchor: null
    };
 
    let target = DefaultLinkHandler.findClosestAnchor(event.target);
    if (!target || !DefaultLinkHandler.targetIsThisWindow(target)) {
      return info;
    }
 
    if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) {
      return info;
    }
 
    let href = target.getAttribute('href');
    info.anchor = target;
    info.href = href;
 
    let leftButtonClicked = event.which === 1;
    let isRelative = href && !(href.charAt(0) === '#' || (/^[a-z]+:/i).test(href));
 
    info.shouldHandleEvent = leftButtonClicked && isRelative;
    return info;
  }
 
  /**
   * Finds the closest ancestor that's an anchor element.
   *
   * @param el The element to search upward from.
   */
  static findClosestAnchor(el: Element): Element {
    while (el) {
      if (el.tagName === 'A') {
        return el;
      }
 
      el = el.parentNode;
    }
  }
 
  /**
   * Gets a value indicating whether or not an anchor targets the current window.
   *
   * @param target The anchor element whose target should be inspected.
   */
  static targetIsThisWindow(target: Element): boolean {
    let targetWindow = target.getAttribute('target');
    let win = PLATFORM.global;
 
    return !targetWindow ||
      targetWindow === win.name ||
      targetWindow === '_self' ||
      (targetWindow === 'top' && win === win.top);
  }
}