summaryrefslogtreecommitdiffstatshomepage
path: root/core/misc/displace.js
blob: ac1902b71302793cab79f3c1c685b3f6fa09e74b (plain) (blame)
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
122
123
124
125
126
127
128
129
/**
* DO NOT EDIT THIS FILE.
* See the following change record for more information,
* https://www.drupal.org/node/2815083
* @preserve
**/

(function ($, Drupal, debounce) {
  const cache = {
    right: 0,
    left: 0,
    bottom: 0,
    top: 0
  };
  const cssVarPrefix = '--drupal-displace-offset';
  const documentStyle = document.documentElement.style;
  const offsetKeys = Object.keys(cache);
  const offsetProps = {};
  offsetKeys.forEach(edge => {
    offsetProps[edge] = {
      enumerable: true,

      get() {
        return cache[edge];
      },

      set(value) {
        if (value !== cache[edge]) {
          documentStyle.setProperty(`${cssVarPrefix}-${edge}`, `${value}px`);
        }

        cache[edge] = value;
      }

    };
  });
  const offsets = Object.seal(Object.defineProperties({}, offsetProps));

  function getRawOffset(el, edge) {
    const $el = $(el);
    const documentElement = document.documentElement;
    let displacement = 0;
    const horizontal = edge === 'left' || edge === 'right';
    let placement = $el.offset()[horizontal ? 'left' : 'top'];
    placement -= window[`scroll${horizontal ? 'X' : 'Y'}`] || document.documentElement[`scroll${horizontal ? 'Left' : 'Top'}`] || 0;

    switch (edge) {
      case 'top':
        displacement = placement + $el.outerHeight();
        break;

      case 'left':
        displacement = placement + $el.outerWidth();
        break;

      case 'bottom':
        displacement = documentElement.clientHeight - placement;
        break;

      case 'right':
        displacement = documentElement.clientWidth - placement;
        break;

      default:
        displacement = 0;
    }

    return displacement;
  }

  function calculateOffset(edge) {
    let edgeOffset = 0;
    const displacingElements = document.querySelectorAll(`[data-offset-${edge}]`);
    const n = displacingElements.length;

    for (let i = 0; i < n; i++) {
      const el = displacingElements[i];

      if (el.style.display === 'none') {
        continue;
      }

      let displacement = parseInt(el.getAttribute(`data-offset-${edge}`), 10);

      if (isNaN(displacement)) {
        displacement = getRawOffset(el, edge);
      }

      edgeOffset = Math.max(edgeOffset, displacement);
    }

    return edgeOffset;
  }

  function displace() {
    let broadcast = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
    const newOffsets = {};
    offsetKeys.forEach(edge => {
      newOffsets[edge] = calculateOffset(edge);
    });
    offsetKeys.forEach(edge => {
      offsets[edge] = newOffsets[edge];
    });

    if (broadcast) {
      $(document).trigger('drupalViewportOffsetChange', offsets);
    }

    return offsets;
  }

  Drupal.behaviors.drupalDisplace = {
    attach() {
      if (this.displaceProcessed) {
        return;
      }

      this.displaceProcessed = true;
      $(window).on('resize.drupalDisplace', debounce(displace, 200));
    }

  };
  Drupal.displace = displace;
  Object.defineProperty(Drupal.displace, 'offsets', {
    value: offsets,
    writable: false
  });
  Drupal.displace.calculateOffset = calculateOffset;
})(jQuery, Drupal, Drupal.debounce);