overlay.js 4.1 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
  }

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

37
    this.node = pageOverlay;
38
    this.node.style.opacity = '0';
K
Kamran Ahmed 已提交
39 40
  }

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

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

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

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

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

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

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

K
Kamran Ahmed 已提交
78 79 80 81 82 83 84
    this.showOverlay();

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

  showOverlay() {
85 86 87 88 89 90 91 92 93 94
    this.makeNode();

    window.setTimeout(() => {
      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';
    });
K
Kamran Ahmed 已提交
95 96 97 98 99 100 101 102 103 104 105
  }

  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 = '';
106 107

      this.node.parentElement.removeChild(this.node);
K
Kamran Ahmed 已提交
108
    }, ANIMATION_DURATION_MS);
K
Kamran Ahmed 已提交
109 110
  }

111 112 113 114 115 116 117 118
  /**
   * Returns the currently selected element
   * @returns {null|*}
   */
  getHighlightedElement() {
    return this.highlightedElement;
  }

119 120 121 122 123 124 125 126
  /**
   * Gets the element that was highlighted before current element
   * @returns {null|*}
   */
  getLastHighlightedElement() {
    return this.lastHighlightedElement;
  }

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

136
    this.highlightedElement = null;
137
    this.lastHighlightedElement = null;
138

K
Kamran Ahmed 已提交
139
    this.hideOverlay();
K
Kamran Ahmed 已提交
140 141
  }

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

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