PageSourceSearch

https://www.ecpi.edu/core/misc/displace.js?v=10.6.17

js ecpi.edu collected 2026-09-24 17:35:30 UTC 8,053 bytes, 267 lines download raw bytes

1/**
2 * @file
3 * Manages elements that can offset the size of the viewport.
4 *
5 * Measures and reports viewport offset dimensions from elements like the
6 * toolbar that can potentially displace the positioning of other elements.
7 */
8
9/**
10 * @typedef {object} Drupal~displaceOffset
11 *
12 * @prop {number} top
13 * @prop {number} left
14 * @prop {number} right
15 * @prop {number} bottom
16 */
17
18/**
19 * Triggers when layout of the page changes.
20 *
21 * This is used to position fixed element on the page during page resize and
22 * Toolbar toggling.
23 *
24 * @event drupalViewportOffsetChange
25 */
26(function ($, Drupal, debounce) {
27  /**
28   *
29   * @type {Drupal~displaceOffset}
30   */
31  const cache = {
32    right: 0,
33    left: 0,
34    bottom: 0,
35    top: 0,
36  };
37  /**
38   * The prefix used for the css custom variable name.
39   *
40   * @type {string}
41   */
42  const cssVarPrefix = '--drupal-displace-offset';
43  const documentStyle = document.documentElement.style;
44  const offsetKeys = Object.keys(cache);
45  /**
46   * The object with accessors that update the CSS variable on value update.
47   *
48   * @type {Drupal~displaceOffset}
49   */
50  const offsetProps = {};
51  offsetKeys.forEach((edge) => {
52    offsetProps[edge] = {
53      // Show this property when using Object.keys().
54      enumerable: true,
55      get() {
56        return cache[edge];
57      },
58      set(value) {
59        // Only update the CSS custom variable when the value changed.
60        if (value !== cache[edge]) {
61          documentStyle.setProperty(`${cssVarPrefix}-${edge}`, `${value}px`);
62        }
63        cache[edge] = value;
64      },
65    };
66  });
67
68  /**
69   * Current value of the size of margins on the page.
70   *
71   * This property is read-only and the object is sealed to prevent key name
72   * modifications since key names are used to dynamically construct CSS custom
73   * variable names.
74   *
75   * @name Drupal.displace.offsets
76   *
77   * @type {Drupal~displaceOffset}
78   */
79  const offsets = Object.seal(Object.defineProperties({}, offsetProps));
80
81  /**
82   * Calculates displacement for element based on its dimensions and placement.
83   *
84   * @param {HTMLElement} el
85   *   The element whose dimensions and placement will be measured.
86   *
87   * @param {string} edge
88   *   The name of the edge of the viewport that the element is associated
89   *   with.
90   *
91   * @return {number}
92   *   The viewport displacement distance for the requested edge.
93   */
94  function getRawOffset(el, edge) {
95    const $el = $(el);
96    const documentElement = document.documentElement;
97    let displacement = 0;
98    const horizontal = edge === 'left' || edge === 'right';
99    // Get the offset of the element itself.
100    let placement = $el.offset()[horizontal ? 'left' : 'top'];
101    // Subtract scroll distance from placement to get the distance
102    // to the edge of the viewport.
103    placement -=
104      window[`scroll${horizontal ? 'X' : 'Y'}`] ||
105      document.documentElement[`scroll${horizontal ? 'Left' : 'Top'}`] ||
106      0;
107    // Find the displacement value according to the edge.
108    switch (edge) {
109      // Left and top elements displace as a sum of their own offset value
110      // plus their size.
111      case 'top':
112        // Total displacement is the sum of the elements placement and size.
113        displacement = placement + $el.outerHeight();
114        break;
115
116      case 'left':
117        // Total displacement is the sum of the elements placement and size.
118        displacement = placement + $el.outerWidth();
119        break;
120
121      // Right and bottom elements displace according to their left and
122      // top offset. Their size isn't important.
123      case 'bottom':
124        displacement = documentElement.clientHeight - placement;
125        break;
126
127      case 'right':
128        displacement = documentElement.clientWidth - placement;
129        break;
130
131      default:
132        displacement = 0;
133    }
134    return displacement;
135  }
136
137  /**
138   * Gets a specific edge's offset.
139   *
140   * Any element with the attribute data-offset-{edge} e.g. data-offset-top will
141   * be considered in the viewport offset calculations. If the attribute has a
142   * numeric value, that value will be used. If no value is provided, one will
143   * be calculated using the element's dimensions and placement.
144   *
145   * @function Drupal.displace.calculateOffset
146   *
147   * @param {string} edge
148   *   The name of the edge to calculate. Can be 'top', 'right',
149   *   'bottom' or 'left'.
150   *
151   * @return {number}
152   *   The viewport displacement distance for the requested edge.
153   */
154  function calculateOffset(edge) {
155    let edgeOffset = 0;
156    const displacingElements = document.querySelectorAll(
157      `[data-offset-${edge}]`,
158    );
159    const n = displacingElements.length;
160    for (let i = 0; i < n; i++) {
161      const el = displacingElements[i];
162      // If the element is not visible, do consider its dimensions.
163      if (el.style.display === 'none') {
164        continue;
165      }
166      // If the offset data attribute contains a displacing value, use it.
167      let displacement = parseInt(el.getAttribute(`data-offset-${edge}`), 10);
168      // If the element's offset data attribute exits
169      // but is not a valid number then get the displacement
170      // dimensions directly from the element.
171      // eslint-disable-next-line no-restricted-globals
172      if (isNaN(displacement)) {
173        displacement = getRawOffset(el, edge);
174      }
175      // If the displacement value is larger than the current value for this
176      // edge, use the displacement value.
177      edgeOffset = Math.max(edgeOffset, displacement);
178    }
179
180    return edgeOffset;
181  }
182
183  /**
184   * Informs listeners of the current offset dimensions.
185   *
186   * Corresponding CSS custom variables are also updated.
187   * Corresponding CSS custom variables names are:
188   *  - `--drupal-displace-offset-top`
189   *  - `--drupal-displace-offset-right`
190   *  - `--drupal-displace-offset-bottom`
191   *  - `--drupal-displace-offset-left`
192   *
193   * @function Drupal.displace
194   *
195   * @prop {Drupal~displaceOffset} offsets
196   *
197   * @param {boolean} [broadcast=true]
198   *   When true, causes the recalculated offsets values to be
199   *   broadcast to listeners. If none is given, defaults to true.
200   *
201   * @return {Drupal~displaceOffset}
202   *   An object whose keys are the for sides an element -- top, right, bottom
203   *   and left. The value of each key is the viewport displacement distance for
204   *   that edge.
205   *
206   * @fires event:drupalViewportOffsetChange
207   */
208  function displace(broadcast = true) {
209    const newOffsets = {};
210    // Getting the offset and setting the offset needs to be separated because
211    // of performance concerns. Only do DOM/style reading happening here.
212    offsetKeys.forEach((edge) => {
213      newOffsets[edge] = calculateOffset(edge);
214    });
215    // Once we have all the values, write to the DOM/style.
216    offsetKeys.forEach((edge) => {
217      // Updating the value in place also update Drupal.displace.offsets.
218      offsets[edge] = newOffsets[edge];
219    });
220
221    if (broadcast) {
222      $(document).trigger('drupalViewportOffsetChange', offsets);
223    }
224    return offsets;
225  }
226
227  /**
228   * Registers a resize handler on the window.
229   *
230   * @type {Drupal~behavior}
231   */
232  Drupal.behaviors.drupalDisplace = {
233    attach() {
234      // Mark this behavior as processed on the first pass.
235      if (this.displaceProcessed) {
236        return;
237      }
238      this.displaceProcessed = true;
239      $(window).on('resize.drupalDisplace', debounce(displace, 200));
240    },
241  };
242
243  /**
244   * Assign the displace function to a property of the Drupal global object.
245   *
246   * @ignore
247   */
248  Drupal.displace = displace;
249
250  /**
251   * Expose offsets to other scripts to avoid having to recalculate offsets.
252   *
253   * @ignore
254   */
255  Object.defineProperty(Drupal.displace, 'offsets', {
256    value: offsets,
257    // Make sure other scripts don't replace this object.
258    writable: false,
259  });
260
261  /**
262   * Expose method to compute a single edge offsets.
263   *
264   * @ignore
265   */
266  Drupal.displace.calculateOffset = calculateOffset;
267})(jQuery, Drupal, Drupal.debounce);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.