annotate core/misc/displace.es6.js @ 0:c75dbcec494b

Initial commit from drush-created site
author Chris Cannam
date Thu, 05 Jul 2018 14:24:15 +0000
parents
children a9cd425dd02b
rev   line source
Chris@0 1 /**
Chris@0 2 * @file
Chris@0 3 * Manages elements that can offset the size of the viewport.
Chris@0 4 *
Chris@0 5 * Measures and reports viewport offset dimensions from elements like the
Chris@0 6 * toolbar that can potentially displace the positioning of other elements.
Chris@0 7 */
Chris@0 8
Chris@0 9 /**
Chris@0 10 * @typedef {object} Drupal~displaceOffset
Chris@0 11 *
Chris@0 12 * @prop {number} top
Chris@0 13 * @prop {number} left
Chris@0 14 * @prop {number} right
Chris@0 15 * @prop {number} bottom
Chris@0 16 */
Chris@0 17
Chris@0 18 /**
Chris@0 19 * Triggers when layout of the page changes.
Chris@0 20 *
Chris@0 21 * This is used to position fixed element on the page during page resize and
Chris@0 22 * Toolbar toggling.
Chris@0 23 *
Chris@0 24 * @event drupalViewportOffsetChange
Chris@0 25 */
Chris@0 26
Chris@0 27 (function ($, Drupal, debounce) {
Chris@0 28 /**
Chris@0 29 * @name Drupal.displace.offsets
Chris@0 30 *
Chris@0 31 * @type {Drupal~displaceOffset}
Chris@0 32 */
Chris@0 33 let offsets = {
Chris@0 34 top: 0,
Chris@0 35 right: 0,
Chris@0 36 bottom: 0,
Chris@0 37 left: 0,
Chris@0 38 };
Chris@0 39
Chris@0 40 /**
Chris@0 41 * Registers a resize handler on the window.
Chris@0 42 *
Chris@0 43 * @type {Drupal~behavior}
Chris@0 44 */
Chris@0 45 Drupal.behaviors.drupalDisplace = {
Chris@0 46 attach() {
Chris@0 47 // Mark this behavior as processed on the first pass.
Chris@0 48 if (this.displaceProcessed) {
Chris@0 49 return;
Chris@0 50 }
Chris@0 51 this.displaceProcessed = true;
Chris@0 52
Chris@0 53 $(window).on('resize.drupalDisplace', debounce(displace, 200));
Chris@0 54 },
Chris@0 55 };
Chris@0 56
Chris@0 57 /**
Chris@0 58 * Informs listeners of the current offset dimensions.
Chris@0 59 *
Chris@0 60 * @function Drupal.displace
Chris@0 61 *
Chris@0 62 * @prop {Drupal~displaceOffset} offsets
Chris@0 63 *
Chris@0 64 * @param {bool} [broadcast]
Chris@0 65 * When true or undefined, causes the recalculated offsets values to be
Chris@0 66 * broadcast to listeners.
Chris@0 67 *
Chris@0 68 * @return {Drupal~displaceOffset}
Chris@0 69 * An object whose keys are the for sides an element -- top, right, bottom
Chris@0 70 * and left. The value of each key is the viewport displacement distance for
Chris@0 71 * that edge.
Chris@0 72 *
Chris@0 73 * @fires event:drupalViewportOffsetChange
Chris@0 74 */
Chris@0 75 function displace(broadcast) {
Chris@0 76 offsets = calculateOffsets();
Chris@0 77 Drupal.displace.offsets = offsets;
Chris@0 78 if (typeof broadcast === 'undefined' || broadcast) {
Chris@0 79 $(document).trigger('drupalViewportOffsetChange', offsets);
Chris@0 80 }
Chris@0 81 return offsets;
Chris@0 82 }
Chris@0 83
Chris@0 84 /**
Chris@0 85 * Determines the viewport offsets.
Chris@0 86 *
Chris@0 87 * @return {Drupal~displaceOffset}
Chris@0 88 * An object whose keys are the for sides an element -- top, right, bottom
Chris@0 89 * and left. The value of each key is the viewport displacement distance for
Chris@0 90 * that edge.
Chris@0 91 */
Chris@0 92 function calculateOffsets() {
Chris@0 93 return {
Chris@0 94 top: calculateOffset('top'),
Chris@0 95 right: calculateOffset('right'),
Chris@0 96 bottom: calculateOffset('bottom'),
Chris@0 97 left: calculateOffset('left'),
Chris@0 98 };
Chris@0 99 }
Chris@0 100
Chris@0 101 /**
Chris@0 102 * Gets a specific edge's offset.
Chris@0 103 *
Chris@0 104 * Any element with the attribute data-offset-{edge} e.g. data-offset-top will
Chris@0 105 * be considered in the viewport offset calculations. If the attribute has a
Chris@0 106 * numeric value, that value will be used. If no value is provided, one will
Chris@0 107 * be calculated using the element's dimensions and placement.
Chris@0 108 *
Chris@0 109 * @function Drupal.displace.calculateOffset
Chris@0 110 *
Chris@0 111 * @param {string} edge
Chris@0 112 * The name of the edge to calculate. Can be 'top', 'right',
Chris@0 113 * 'bottom' or 'left'.
Chris@0 114 *
Chris@0 115 * @return {number}
Chris@0 116 * The viewport displacement distance for the requested edge.
Chris@0 117 */
Chris@0 118 function calculateOffset(edge) {
Chris@0 119 let edgeOffset = 0;
Chris@0 120 const displacingElements = document.querySelectorAll(`[data-offset-${edge}]`);
Chris@0 121 const n = displacingElements.length;
Chris@0 122 for (let i = 0; i < n; i++) {
Chris@0 123 const el = displacingElements[i];
Chris@0 124 // If the element is not visible, do consider its dimensions.
Chris@0 125 if (el.style.display === 'none') {
Chris@0 126 continue;
Chris@0 127 }
Chris@0 128 // If the offset data attribute contains a displacing value, use it.
Chris@0 129 let displacement = parseInt(el.getAttribute(`data-offset-${edge}`), 10);
Chris@0 130 // If the element's offset data attribute exits
Chris@0 131 // but is not a valid number then get the displacement
Chris@0 132 // dimensions directly from the element.
Chris@0 133 if (isNaN(displacement)) {
Chris@0 134 displacement = getRawOffset(el, edge);
Chris@0 135 }
Chris@0 136 // If the displacement value is larger than the current value for this
Chris@0 137 // edge, use the displacement value.
Chris@0 138 edgeOffset = Math.max(edgeOffset, displacement);
Chris@0 139 }
Chris@0 140
Chris@0 141 return edgeOffset;
Chris@0 142 }
Chris@0 143
Chris@0 144 /**
Chris@0 145 * Calculates displacement for element based on its dimensions and placement.
Chris@0 146 *
Chris@0 147 * @param {HTMLElement} el
Chris@0 148 * The jQuery element whose dimensions and placement will be measured.
Chris@0 149 *
Chris@0 150 * @param {string} edge
Chris@0 151 * The name of the edge of the viewport that the element is associated
Chris@0 152 * with.
Chris@0 153 *
Chris@0 154 * @return {number}
Chris@0 155 * The viewport displacement distance for the requested edge.
Chris@0 156 */
Chris@0 157 function getRawOffset(el, edge) {
Chris@0 158 const $el = $(el);
Chris@0 159 const documentElement = document.documentElement;
Chris@0 160 let displacement = 0;
Chris@0 161 const horizontal = (edge === 'left' || edge === 'right');
Chris@0 162 // Get the offset of the element itself.
Chris@0 163 let placement = $el.offset()[horizontal ? 'left' : 'top'];
Chris@0 164 // Subtract scroll distance from placement to get the distance
Chris@0 165 // to the edge of the viewport.
Chris@0 166 placement -= window[`scroll${horizontal ? 'X' : 'Y'}`] || document.documentElement[`scroll${horizontal ? 'Left' : 'Top'}`] || 0;
Chris@0 167 // Find the displacement value according to the edge.
Chris@0 168 switch (edge) {
Chris@0 169 // Left and top elements displace as a sum of their own offset value
Chris@0 170 // plus their size.
Chris@0 171 case 'top':
Chris@0 172 // Total displacement is the sum of the elements placement and size.
Chris@0 173 displacement = placement + $el.outerHeight();
Chris@0 174 break;
Chris@0 175
Chris@0 176 case 'left':
Chris@0 177 // Total displacement is the sum of the elements placement and size.
Chris@0 178 displacement = placement + $el.outerWidth();
Chris@0 179 break;
Chris@0 180
Chris@0 181 // Right and bottom elements displace according to their left and
Chris@0 182 // top offset. Their size isn't important.
Chris@0 183 case 'bottom':
Chris@0 184 displacement = documentElement.clientHeight - placement;
Chris@0 185 break;
Chris@0 186
Chris@0 187 case 'right':
Chris@0 188 displacement = documentElement.clientWidth - placement;
Chris@0 189 break;
Chris@0 190
Chris@0 191 default:
Chris@0 192 displacement = 0;
Chris@0 193 }
Chris@0 194 return displacement;
Chris@0 195 }
Chris@0 196
Chris@0 197 /**
Chris@0 198 * Assign the displace function to a property of the Drupal global object.
Chris@0 199 *
Chris@0 200 * @ignore
Chris@0 201 */
Chris@0 202 Drupal.displace = displace;
Chris@0 203 $.extend(Drupal.displace, {
Chris@0 204
Chris@0 205 /**
Chris@0 206 * Expose offsets to other scripts to avoid having to recalculate offsets.
Chris@0 207 *
Chris@0 208 * @ignore
Chris@0 209 */
Chris@0 210 offsets,
Chris@0 211
Chris@0 212 /**
Chris@0 213 * Expose method to compute a single edge offsets.
Chris@0 214 *
Chris@0 215 * @ignore
Chris@0 216 */
Chris@0 217 calculateOffset,
Chris@0 218 });
Chris@0 219 }(jQuery, Drupal, Drupal.debounce));