overlay.js 4.0 KB
Newer Older
K
Kamran Ahmed 已提交
1
import Position from './position';
K
Kamran Ahmed 已提交
2
import { ANIMATION_DURATION_MS, ID_OVERLAY, OVERLAY_HTML } from '../common/constants';
K
Kamran Ahmed 已提交
3
import { createNodeFromString } from '../common/utils';
K
Kamran Ahmed 已提交
4 5 6 7 8 9

/**
 * Responsible for overlay creation and manipulation i.e.
 * cutting out the visible part, animating between the sections etc
 */
export default class Overlay {
K
Kamran Ahmed 已提交
10
  /**
K
Kamran Ahmed 已提交
11 12 13
   * @param {Object} options
   * @param {Window} window
   * @param {Document} document
K
Kamran Ahmed 已提交
14
   */
K
Kamran Ahmed 已提交
15
  constructor(options, window, document) {
K
Kamran Ahmed 已提交
16
    this.options = options;
17 18 19

    this.positionToHighlight = new Position({}); // position at which layover is to be patched at
    this.highlightedElement = null;              // currently highlighted dom element (instance of Element)
20
    this.lastHighlightedElement = null;          // element that was highlighted before current one
K
Kamran Ahmed 已提交
21
    this.hideTimer = null;
K
Kamran Ahmed 已提交
22

K
Kamran Ahmed 已提交
23
    this.window = window;
K
Kamran Ahmed 已提交
24
    this.document = document;
K
Kamran Ahmed 已提交
25

26
    this.makeNode();
K
Kamran Ahmed 已提交
27 28
  }

K
Kamran Ahmed 已提交
29 30 31
  /**
   * Prepares the overlay
   */
32 33 34 35 36 37
  makeNode() {
    let pageOverlay = this.document.getElementById(ID_OVERLAY);
    if (!pageOverlay) {
      pageOverlay = createNodeFromString(OVERLAY_HTML);
      document.body.appendChild(pageOverlay);
    }
K
Kamran Ahmed 已提交
38

39
    this.node = pageOverlay;
K
Kamran Ahmed 已提交
40 41
  }

K
Kamran Ahmed 已提交
42 43
  /**
   * Highlights the dom element on the screen
K
Kamran Ahmed 已提交
44 45
   * @param {Element} element
   * @param {boolean} animate
K
Kamran Ahmed 已提交
46
   */
K
Kamran Ahmed 已提交
47
  highlight(element) {
K
Kamran Ahmed 已提交
48
    if (!element || !element.node) {
49
      console.warn('Invalid element to highlight. Must be an instance of `Element`');
K
Kamran Ahmed 已提交
50 51 52
      return;
    }

K
Kamran Ahmed 已提交
53 54 55 56 57
    // If highlighted element is not changed from last time
    if (this.highlightedElement && this.highlightedElement.isSame(this.lastHighlightedElement)) {
      return;
    }

K
Kamran Ahmed 已提交
58 59 60 61
    // There might be hide timer from last time
    // which might be getting triggered
    this.window.clearTimeout(this.hideTimer);

K
Kamran Ahmed 已提交
62 63 64 65
    // Trigger the hook for highlight started
    element.onHighlightStarted();

    // Old element has been deselected
K
Kamran Ahmed 已提交
66
    if (this.highlightedElement && !this.highlightedElement.isSame(this.lastHighlightedElement)) {
K
Kamran Ahmed 已提交
67 68 69
      this.highlightedElement.onDeselected();
    }

K
Kamran Ahmed 已提交
70
    // get the position of element around which we need to draw
K
Kamran Ahmed 已提交
71
    const position = element.getCalculatedPosition();
72
    if (!position.canHighlight()) {
K
Kamran Ahmed 已提交
73 74 75
      return;
    }

76
    this.lastHighlightedElement = this.highlightedElement;
77 78
    this.highlightedElement = element;
    this.positionToHighlight = position;
K
Kamran Ahmed 已提交
79

K
Kamran Ahmed 已提交
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
    this.showOverlay();

    // Element has been highlighted
    this.highlightedElement.onHighlighted();
  }

  showOverlay() {
    this.node.style.opacity = `${this.options.opacity}`;
    this.node.style.position = 'fixed';
    this.node.style.left = '0';
    this.node.style.top = '0';
    this.node.style.bottom = '0';
    this.node.style.right = '0';
  }

  hideOverlay() {
    this.node.style.opacity = '0';

    this.hideTimer = window.setTimeout(() => {
      this.node.style.position = 'absolute';
      this.node.style.left = '';
      this.node.style.top = '';
      this.node.style.bottom = '';
      this.node.style.right = '';
    }, ANIMATION_DURATION_MS);
K
Kamran Ahmed 已提交
105 106
  }

107 108 109 110 111 112 113 114
  /**
   * Returns the currently selected element
   * @returns {null|*}
   */
  getHighlightedElement() {
    return this.highlightedElement;
  }

115 116 117 118 119 120 121 122
  /**
   * Gets the element that was highlighted before current element
   * @returns {null|*}
   */
  getLastHighlightedElement() {
    return this.lastHighlightedElement;
  }

K
Kamran Ahmed 已提交
123 124 125
  /**
   * Removes the overlay and cancel any listeners
   */
K
Kamran Ahmed 已提交
126
  clear() {
127
    this.positionToHighlight = new Position();
K
Kamran Ahmed 已提交
128
    if (this.highlightedElement) {
K
Kamran Ahmed 已提交
129
      this.highlightedElement.onDeselected(true);
K
Kamran Ahmed 已提交
130 131
    }

132
    this.highlightedElement = null;
133
    this.lastHighlightedElement = null;
134

K
Kamran Ahmed 已提交
135
    this.hideOverlay();
K
Kamran Ahmed 已提交
136 137
  }

K
Kamran Ahmed 已提交
138 139 140 141
  /**
   * Refreshes the overlay i.e. sets the size according to current window size
   * And moves the highlight around if necessary
   */
K
Kamran Ahmed 已提交
142
  refresh() {
K
Kamran Ahmed 已提交
143 144 145
    // If no highlighted element, cancel the refresh
    if (!this.highlightedElement) {
      return;
146
    }
K
Kamran Ahmed 已提交
147 148 149 150

    // Reposition the stage and show popover
    this.highlightedElement.showPopover();
    this.highlightedElement.showStage();
K
Kamran Ahmed 已提交
151 152
  }
}