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

/**
 * 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 已提交
9
  /**
K
Kamran Ahmed 已提交
10 11 12
   * @param {Object} options
   * @param {Window} window
   * @param {Document} document
K
Kamran Ahmed 已提交
13
   */
K
Kamran Ahmed 已提交
14
  constructor(options, window, document) {
K
Kamran Ahmed 已提交
15
    this.options = options;
16 17

    this.highlightedElement = null;              // currently highlighted dom element (instance of Element)
18
    this.lastHighlightedElement = null;          // element that was highlighted before current one
K
Kamran Ahmed 已提交
19
    this.hideTimer = null;
K
Kamran Ahmed 已提交
20

K
Kamran Ahmed 已提交
21
    this.window = window;
K
Kamran Ahmed 已提交
22
    this.document = document;
K
Kamran Ahmed 已提交
23 24
  }

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

35
    this.node = pageOverlay;
36
    this.node.style.opacity = '0';
37 38 39 40 41 42

    if (!this.options.animate) {
      this.node.classList.add(CLASS_NO_ANIMATION);
    } else {
      this.node.classList.remove(CLASS_NO_ANIMATION);
    }
K
Kamran Ahmed 已提交
43 44
  }

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

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

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

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

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

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

78
    this.lastHighlightedElement = this.highlightedElement;
79
    this.highlightedElement = element;
K
Kamran Ahmed 已提交
80

81
    this.show();
K
Kamran Ahmed 已提交
82 83 84 85 86

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

87 88 89 90 91
  show() {
    if (this.node && this.node.parentElement) {
      return;
    }

92 93 94 95 96 97 98 99 100 101
    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 已提交
102 103
  }

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

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

K
Kamran Ahmed 已提交
120 121 122
  /**
   * Removes the overlay and cancel any listeners
   */
K
Kamran Ahmed 已提交
123
  clear() {
K
Kamran Ahmed 已提交
124
    // Deselect the highlighted element if any
K
Kamran Ahmed 已提交
125
    if (this.highlightedElement) {
K
Kamran Ahmed 已提交
126
      this.highlightedElement.onDeselected(true);
K
Kamran Ahmed 已提交
127 128
    }

129
    this.highlightedElement = null;
130
    this.lastHighlightedElement = null;
131

K
Kamran Ahmed 已提交
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
    if (!this.node) {
      return;
    }

    // Clear any existing timers and remove node
    this.window.clearTimeout(this.hideTimer);

    if (this.options.animate) {
      this.node.style.opacity = '0';
      this.hideTimer = window.setTimeout(this.removeNode, ANIMATION_DURATION_MS);
    } else {
      this.removeNode();
    }
  }

  /**
   * Removes the overlay node if it exists
   */
  removeNode() {
    if (this.node && this.node.parentElement) {
      this.node.parentElement.removeChild(this.node);
    }
K
Kamran Ahmed 已提交
154 155
  }

K
Kamran Ahmed 已提交
156 157 158 159
  /**
   * Refreshes the overlay i.e. sets the size according to current window size
   * And moves the highlight around if necessary
   */
K
Kamran Ahmed 已提交
160
  refresh() {
K
Kamran Ahmed 已提交
161 162 163
    // If no highlighted element, cancel the refresh
    if (!this.highlightedElement) {
      return;
164
    }
K
Kamran Ahmed 已提交
165 166 167 168

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