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