element.js 3.9 KB
Newer Older
K
Kamran Ahmed 已提交
1 2 3
import Position from './position';

export default class Element {
K
Kamran Ahmed 已提交
4 5 6
  /**
   * DOM element object
   * @param node
K
Kamran Ahmed 已提交
7
   * @param options
K
Kamran Ahmed 已提交
8
   */
K
Kamran Ahmed 已提交
9 10
  constructor(node, options) {
    this.node = node;
K
Kamran Ahmed 已提交
11
    this.document = document;
K
Kamran Ahmed 已提交
12 13
    this.window = window;
    this.options = options;
K
Kamran Ahmed 已提交
14
    this.popover = this.getPopover();
K
Kamran Ahmed 已提交
15 16
  }

K
Kamran Ahmed 已提交
17 18 19 20
  /**
   * Gets the screen co-ordinates (x,y) for the current dom element
   * @returns {{x: number, y: number}}
   */
K
Kamran Ahmed 已提交
21
  getScreenCoordinates() {
K
Kamran Ahmed 已提交
22
    let tempNode = this.node;
K
Kamran Ahmed 已提交
23 24 25 26 27 28 29 30 31 32 33 34 35 36

    let x = this.document.documentElement.offsetLeft;
    let y = this.document.documentElement.offsetTop;

    if (tempNode.offsetParent) {
      do {
        x += tempNode.offsetLeft;
        y += tempNode.offsetTop;
      } while (tempNode = tempNode.offsetParent);
    }

    return { x, y };
  }

K
Kamran Ahmed 已提交
37 38 39 40 41
  /**
   * Gets the calculated position on screen, around which
   * we need to draw
   */
  getCalculatedPosition() {
K
Kamran Ahmed 已提交
42 43 44 45 46 47 48 49 50 51
    const coordinates = this.getScreenCoordinates();
    const position = new Position({
      left: Number.MAX_VALUE,
      top: Number.MAX_VALUE,
      right: 0,
      bottom: 0,
    });

    // If we have the position for this element
    // and the element is visible on screen (has some height)
K
Kamran Ahmed 已提交
52
    if (typeof coordinates.x === 'number' && typeof coordinates.y === 'number' && (this.node.offsetWidth > 0 || this.node.offsetHeight > 0)) {
K
Kamran Ahmed 已提交
53 54
      position.left = Math.min(position.left, coordinates.x);
      position.top = Math.min(position.top, coordinates.y);
K
Kamran Ahmed 已提交
55 56
      position.right = Math.max(position.right, coordinates.x + this.node.offsetWidth);
      position.bottom = Math.max(position.bottom, coordinates.y + this.node.offsetHeight);
K
Kamran Ahmed 已提交
57 58 59 60
    }

    return position;
  }
61

K
Kamran Ahmed 已提交
62 63 64 65 66 67 68 69 70 71 72
  onDeselected() {
    // Will be called when element is about to be deselected
    this.hidePopover();
  }

  onHighlightStarted() {
    // Will be triggered when the element is about to be highlighted
    // i.e. overlay has started transitioning towards this element
    this.showPopover();
  }

73
  onHighlighted() {
K
Kamran Ahmed 已提交
74 75 76 77
    this.showPopover();
  }

  showPopover() {
K
Kamran Ahmed 已提交
78 79 80
    this.resetPopover();

    // Position at which the element is
K
Kamran Ahmed 已提交
81 82
    const position = this.getCalculatedPosition();

K
Kamran Ahmed 已提交
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
    const popoverTip = this.popover.querySelector('.sholo-popover-tip');

    const documentHeight = this.getDocumentHeight();
    const popoverHeight = this.getPopoverHeight();
    const popoverMargin = this.options.padding + 10;

    this.popover.style.left = `${position.left - this.options.padding}px`;

    // Calculate different dimensions after attaching popover
    const documentHeightAfterPopOver = position.bottom + popoverHeight + popoverMargin;

    // If adding popover would go out of the window height, then show it to the top
    if (documentHeightAfterPopOver >= documentHeight) {
      this.popover.style.top = `${position.top - popoverHeight - popoverMargin}px`;
      popoverTip.classList.add('bottom');
    } else {
      this.popover.style.top = `${position.bottom + popoverMargin}px`;
      popoverTip.classList.add('top');
    }
K
Kamran Ahmed 已提交
102 103 104 105 106 107 108 109 110 111 112 113
  }

  getPopover() {
    // @todo: Create if not there
    const popover = this.document.getElementById('sholo-popover-item');
    popover.style.position = 'absolute';

    return popover;
  }

  hidePopover() {
    this.popover.style.display = 'none';
114
  }
K
Kamran Ahmed 已提交
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139

  getDocumentHeight() {
    // eslint-disable-next-line prefer-destructuring
    const body = this.document.body;
    const html = this.document.documentElement;

    return Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight);
  }

  getPopoverHeight() {
    return Math.max(this.popover.scrollHeight, this.popover.offsetHeight);
  }

  resetPopover() {
    this.popover.style.display = 'block';
    this.popover.style.left = '';
    this.popover.style.top = '';
    this.popover.style.bottom = '';
    this.popover.style.right = '';

    // Remove the positional classes from tip
    this.popover
      .querySelector('.sholo-popover-tip')
      .className = 'sholo-popover-tip';
  }
K
Kamran Ahmed 已提交
140
}