1if (!W.EDIT_MODE) W.Modules.add('Animator.Spacers', () => { 2 3 // "containers" is a map of divs that have might have columns 4 // containing spacers. It will include all .wSplits that have 5 // more than one child, plus any additional containers added by 6 // external code. 7 8 let containers = new Map(), // the containers 9 used = [], // containers that have spacers 10 sorted = false, // true if the containers have been sorted 11 spacers = [], // the spacers 12 found = false, // true of the spacers have been found 13 animationFrame = null // set if a resizeSpacers() call is pending 14 15 // Add another container to the containers map. The value used will be 16 // a map of all of the columns in that container. 17 function addContainer(container){ 18 19 // Add the new container 20 containers.set(container, new Map()) 21 22 // Set that this containers may not be sorted and that there 23 // may be spacers that have not bee found 24 sorted = false 25 found = false 26 27 // Schedule spacer resizing on the next animation frame 28 scheduleResize() 29 30 } 31 32 // Find all .wSplit divs that have multiple children 33 // and add them to the list of containers. 34 function findSplits(){ 35 36 document.querySelectorAll('.wSplit').forEach((split) => { 37 if (split.children.length > 1){ 38 addContainer(split) 39 } 40 }) 41 42 } 43 44 // Sort the containers so that they are ordered based in their 45 // relationship to each other in the dom tree with child containers 46 // coming first and parent containers coming last. 47 function sortContainers(){ 48 49 // convert the map into an array of key,value pairs 50 // containers = [...containers]; // spread not supported by IE 51 containers = Array.from(containers.entries()) 52 53 // sort containers into order so that all nested 54 // containers come before all parent containers 55 containers = containers.sort((a,b) => { 56 57 const position = a[0].compareDocumentPosition(b[0]) 58 59 if (position & Node.DOCUMENT_POSITION_CONTAINS) 60 return -1 61 else if (position & Node.DOCUMENT_POSITION_CONTAINED_BY) 62 return 1 63 else 64 return 0 65 66 }) 67 68 // convert the array of key,values pairs back into a map 69 containers = new Map(containers) 70 71 sorted = true 72 73 } 74 75 // Find all of the spacers and add them to the appropriate 76 // container and column within that container. 77 function findSpacers(){ 78 79 // Reset all of the containers to empty 80 for (let [container, columns] of containers){ 81 columns = new Map() 82 } 83 84 // Get the spacers 85 spacers = document.querySelectorAll('.newSpacer') 86 87 // Loop over the spacers 88 spacers.forEach(function(spacer){ 89 90 let column = spacer, 91 container = column.parentNode 92 93 // Search up the dom tree looking for a container 94 while (container && !containers.has(container)){ 95 column = container 96 container = container.parentNode 97 } 98 99 // Check that a container was found 100 if (container){ 101 102 // Get the columns for the container 103 const columns = containers.get(container) 104 105 // Add the new column to the container if needed 106 if (!columns.has(column)){ 107 columns.set(column, new Array()) 108 } 109 110 // Add the spacer to the column 111 columns.get(column).push(spacer) 112 113 } 114 115 }) 116 117 // Identify the containers that have at least two columns with spacers 118 used = Array.from(containers.values()).filter((columns) => { 119 return columns.size > 1 120 }) 121 122 //used = [...containers.values()].filter((columns) => { 123 // return columns.size > 1 124 //}) 125 126 found = true 127 128 } 129 130 // Resizes the spacers. 131 function resizeSpacers(){ 132 133 // Ensure the containers are sorted before proceeding 134 if (!sorted){ 135 sortContainers() 136 } 137 138 // Ensure we have found the spacers before proceeding 139 if (!found){ 140 findSpacers() 141 } 142 143 // Reset the current heights of the spacers
144 spacers.forEach((spacer) => { 145 spacer.style.height = 0 146 }) 147 148 // Set explicit heights from aspect ratios 149 document.querySelectorAll('[data-aspect-ratio]').forEach((node) => { 150 if (node.offsetWidth > 0){ 151 node.style.height = 152 Math.round( 153 node.offsetWidth 154 * parseFloat(node.getAttribute('data-aspect-ratio'))) 155 + 'px' 156 } 157 }) 158 159 // Loop over the containers that have spacers 160 used.forEach((columns) => { 161 162 // Create a map of columns with the same top 163 const groups = new Map() 164 165 // Look over columns in the container 166 columns.forEach((spacers, column) => { 167 168 // What is the top of the current column? 169 let top = column.getBoundingClientRect().top 170 171 // Create an entry for the new top if needed 172 if (!groups.has(top)){ 173 groups.set(top, new Array()) 174 } 175 176 // Get the entry for the current top 177 top = groups.get(top) 178 179 // Loop over each spacer in the current column 180 spacers.forEach((spacer, row) => { 181 182 // Create an entry for the row if needed 183 if (!top[row]){ 184 top[row] = new Array() 185 } 186 187 // Add the spacer to the row for the current top 188 top[row].push(spacer) 189 190 }) 191 192 }) 193 194 // For each group of columns with the same top 195 groups.forEach((rows) => { 196 197 // Loop over the spacers in the current group 198 rows.forEach((spacers) => { 199 200 const rowTops = spacers.map((spacer) => { 201 return spacer.getBoundingClientRect().top 202 }) 203 204 // Determine the lowest top 205 const rowTop = Math.max.apply(Math, rowTops) 206 207 // Loop over the spacers, updating their heights 208 spacers.forEach((spacer, index) => { 209 spacer.style.height = Math.round(rowTop - rowTops[index]) + 'px' 210 }) 211 212 }) 213 214 }) 215 216 }) 217 218 } 219 220 // Schedule spacer resizing on the next animation frame 221 function scheduleResize(){ 222 223 if (!animationFrame){ 224 animationFrame = requestAnimationFrame(() => { 225 resizeSpacers() 226 animationFrame = null 227 }) 228 } 229 230 } 231 232 W.Modules.use([], () => { 233 234 // Find all of the .wSpacer divs and convert them into 235 // .newSpacer divs so that spacers.js cannot see them 236 document.querySelectorAll('.wSpacer').forEach((spacer) => { 237 spacer.classList.remove('wSpacer') 238 spacer.classList.add('newSpacer') 239 spacer.style.setProperty('margin-top', '0px', 'important') 240 }) 241 242 }) 243 244 W.Modules.useOnLoad([], () => { 245 246 // Find all of the .wSplit divs and add them as containers 247 findSplits() 248 249 // Resize all of the spacers now 250 resizeSpacers() 251 252 // Ensure spacers will be resized if the Layout changes. 253 W.Layout.onUpdate(resizeSpacers) 254 255 }) 256 257 // Return an API to enable other code to add containers 258 // that might contain columns with spacers that also 259 // need to line up. 260 return { 261 addContainer 262 } 263 264})
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.