PageSourceSearch

https://www.teaconnect.org/sites/default/files/js/optimized/js_KKc…VV8uRlIdEBGRNAxHwiTKoC8JTJnRZx8.js?v=10.5.4

js teaconnect.org collected 2026-09-24 18:52:23 UTC 8,307 bytes, 270 lines download raw bytes

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

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.