vendor: 12,020 bytes, lines 1-415
1/* jshint laxcomma: true */ 2var salvattore = (function (global, document, undefined) { 3"use strict"; 4 5var self = {}, 6 grids = [], 7 mediaRules = [], 8 mediaQueries = [], 9 add_to_dataset = function(element, key, value) { 10 // uses dataset function or a fallback for <ie10 11 if (element.dataset) { 12 element.dataset[key] = value; 13 } else { 14 element.setAttribute("data-" + key, value); 15 } 16 return; 17 }; 18 19self.obtainGridSettings = function obtainGridSettings(element) { 20 // returns the number of columns and the classes a column should have, 21 // from computing the style of the ::before pseudo-element of the grid. 22 23 var computedStyle = global.getComputedStyle(element, ":before") 24 , content = computedStyle.getPropertyValue("content").slice(1, -1) 25 , matchResult = content.match(/^\s*(\d+)(?:\s?\.(.+))?\s*$/) 26 , numberOfColumns = 1 27 , columnClasses = [] 28 ; 29 30 if (matchResult) { 31 numberOfColumns = matchResult[1]; 32 columnClasses = matchResult[2]; 33 columnClasses = columnClasses? columnClasses.split(".") : ["column"]; 34 } else { 35 matchResult = content.match(/^\s*\.(.+)\s+(\d+)\s*$/); 36 if (matchResult) { 37 columnClasses = matchResult[1]; 38 numberOfColumns = matchResult[2]; 39 if (numberOfColumns) { 40 numberOfColumns = numberOfColumns.split("."); 41 } 42 } 43 } 44 45 return { 46 numberOfColumns: numberOfColumns, 47 columnClasses: columnClasses 48 }; 49}; 50 51 52self.addColumns = function addColumns(grid, items) { 53 // from the settings obtained, it creates columns with 54 // the configured classes and adds to them a list of items. 55 56 var settings = self.obtainGridSettings(grid) 57 , numberOfColumns = settings.numberOfColumns 58 , columnClasses = settings.columnClasses 59 , columnsItems = new Array(+numberOfColumns) 60 , columnsFragment = document.createDocumentFragment() 61 , i = numberOfColumns 62 , selector 63 ; 64 65 while (i-- !== 0) { 66 selector = "[data-columns] > *:nth-child(" + numberOfColumns + "n-" + i + ")"; 67 columnsItems.push(items.querySelectorAll(selector)); 68 } 69 70 columnsItems.forEach(function append_to_grid_fragment(rows) { 71 var column = document.createElement("div") 72 , rowsFragment = document.createDocumentFragment() 73 ; 74 75 column.className = columnClasses.join(" "); 76 77 Array.prototype.forEach.call(rows, function append_to_column(row) { 78 rowsFragment.appendChild(row); 79 }); 80 column.appendChild(rowsFragment); 81 columnsFragment.appendChild(column); 82 }); 83 84 grid.appendChild(columnsFragment); 85 add_to_dataset(grid, 'columns', numberOfColumns); 86}; 87 88 89self.removeColumns = function removeColumns(grid) { 90 // removes all the columns from a grid, and returns a list 91 // of items sorted by the ordering of columns. 92 93 var range = document.createRange(); 94 range.selectNodeContents(grid); 95 96 var columns = Array.prototype.filter.call(range.extractContents().childNodes, function filter_elements(node) { 97 return node instanceof global.HTMLElement; 98 }); 99 100 var numberOfColumns = columns.length 101 , numberOfRowsInFirstColumn = columns[0].childNodes.length 102 , sortedRows = new Array(numberOfRowsInFirstColumn * numberOfColumns) 103 ; 104 105 Array.prototype.forEach.call(columns, function iterate_columns(column, columnIndex) { 106 Array.prototype.forEach.call(column.children, function iterate_rows(row, rowIndex) { 107 sortedRows[rowIndex * numberOfColumns + columnIndex] = row; 108 }); 109 }); 110 111 var container = document.createElement("div"); 112 add_to_dataset(container, 'columns', 0); 113 114 sortedRows.filter(function filter_non_null(child) { 115 return !!child; 116 }).forEach(function append_row(child) { 117 container.appendChild(child); 118 }); 119 120 return container; 121}; 122 123 124self.recreateColumns = function recreateColumns(grid) { 125 // removes all the columns from the grid, and adds them again, 126 // it is used when the number of columns change. 127 128 global.requestAnimationFrame(function render_after_css_mediaQueryChange() { 129 self.addColumns(grid, self.removeColumns(grid)); 130 var columnsChange = new CustomEvent("columnsChange"); 131 grid.dispatchEvent(columnsChange); 132 }); 133}; 134 135 136self.mediaQueryChange = function mediaQueryChange(mql) { 137 // recreates the columns when a media query matches the current state 138 // of the browser. 139 140 if (mql.matches) { 141 Array.prototype.forEach.call(grids, self.recreateColumns); 142 } 143}; 144 145 146self.getCSSRules = function getCSSRules(stylesheet) { 147 // returns a list of css rules from a stylesheet 148 149 var cssRules; 150 try { 151 cssRules = stylesheet.sheet.cssRules || stylesheet.sheet.rules; 152 } catch (e) { 153 return []; 154 } 155 156 return cssRules || []; 157}; 158 159 160self.getStylesheets = function getStylesheets() { 161 // returns a list of all the styles in the document (that are accessible). 162 163 var inlineStyleBlocks = Array.prototype.slice.call(document.querySelectorAll("style")); 164 inlineStyleBlocks.forEach(function(stylesheet, idx) { 165 if (stylesheet.type !== 'text/css' && stylesheet.type !== '') { 166 inlineStyleBlocks.splice(idx, 1); 167 } 168 }); 169 170 return Array.prototype.concat.call( 171 inlineStyleBlocks, 172 Array.prototype.slice.call(document.querySelectorAll("link[rel='stylesheet']")) 173 ); 174}; 175 176 177self.mediaRuleHasColumnsSelector = function mediaRuleHasColumnsSelector(rules) { 178 // checks if a media query css rule has in its contents a selector that 179 // styles the grid. 180 181 var i, rule; 182 183 try { 184 i = rules.length; 185 } 186 catch (e) { 187 i = 0; 188 } 189 190 while (i--) { 191 rule = rules[i]; 192 if (rule.selectorText && rule.selectorText.match(/\[data-columns\](.*)::?before$/)) { 193 return true; 194 } 195 } 196 197 return false; 198}; 199 200 201self.scanMediaQueries = function scanMediaQueries() { 202 // scans all the stylesheets for selectors that style grids, 203 // if the matchMedia API is supported. 204 205 var newMediaRules = []; 206 207 if (!global.matchMedia) { 208 return; 209 } 210 211 self.getStylesheets().forEach(function extract_rules(stylesheet) { 212 Array.prototype.forEach.call(self.getCSSRules(stylesheet), function filter_by_column_selector(rule) { 213 // rule.media throws an 'not implemented error' in ie9 for import rules occasionally 214 try { 215 if (rule.media && rule.cssRules && self.mediaRuleHasColumnsSelector(rule.cssRules)) { 216 newMediaRules.push(rule); 217 } 218 } catch (e) {} 219 }); 220 }); 221 222 // remove matchMedia listeners from the old rules 223 var oldRules = mediaRules.filter(function (el) { 224 return newMediaRules.indexOf(el) === -1; 225 }); 226 mediaQueries.filter(function (el) { 227 return oldRules.indexOf(el.rule) !== -1; 228 }).forEach(function (el) { 229 el.mql.removeListener(self.mediaQueryChange); 230 }); 231 mediaQueries = mediaQueries.filter(function (el) { 232 return oldRules.indexOf(el.rule) === -1; 233 }); 234 235 // add matchMedia listeners to the new rules 236 newMediaRules.filter(function (el) { 237 return mediaRules.indexOf(el) == -1; 238 }).forEach(function (rule) { 239 var mql = global.matchMedia(rule.media.mediaText); 240 mql.addListener(self.mediaQueryChange); 241 mediaQueries.push({rule: rule, mql:mql}); 242 }); 243 244 // swap mediaRules with the new set 245 mediaRules.length = 0; 246 mediaRules = newMediaRules; 247}; 248 249 250self.rescanMediaQueries = function rescanMediaQueries() { 251 self.scanMediaQueries(); 252 Array.prototype.forEach.call(grids, self.recreateColumns); 253}; 254 255 256self.nextElementColumnIndex = function nextElementColumnIndex(grid, fragments) { 257 // returns the index of the column where the given element must be added. 258 259 var children = grid.children 260 , m = children.length 261 , lowestRowCount = 0 262 , child 263 , currentRowCount 264 , i 265 , index = 0 266 ; 267 for (i = 0; i < m; i++) { 268 child = children[i]; 269 currentRowCount = child.children.length + (fragments[i].children || fragments[i].childNodes).length; 270 if(lowestRowCount === 0) { 271 lowestRowCount = currentRowCount; 272 } 273 if(currentRowCount < lowestRowCount) { 274 index = i; 275 lowestRowCount = currentRowCount; 276 } 277 } 278 279 return index; 280}; 281 282 283self.createFragmentsList = function createFragmentsList(quantity) { 284 // returns a list of fragments 285 286 var fragments = new Array(quantity) 287 , i = 0 288 ; 289 290 while (i !== quantity) { 291 fragments[i] = document.createDocumentFragment(); 292 i++; 293 } 294 295 return fragments; 296}; 297 298 299self.appendElements = function appendElements(grid, elements) { 300 // adds a list of elements to the end of a grid 301 302 var columns = grid.children 303 , numberOfColumns = columns.length 304 , fragments = self.createFragmentsList(numberOfColumns) 305 ; 306 307 Array.prototype.forEach.call(elements, function append_to_next_fragment(element) { 308 var columnIndex = self.nextElementColumnIndex(grid, fragments); 309 fragments[columnIndex].appendChild(element); 310 }); 311 312 Array.prototype.forEach.call(columns, function insert_column(column, index) { 313 column.appendChild(fragments[index]); 314 }); 315}; 316 317 318self.prependElements = function prependElements(grid, elements) { 319 // adds a list of elements to the start of a grid 320 321 var columns = grid.children 322 , numberOfColumns = columns.length 323 , fragments = self.createFragmentsList(numberOfColumns) 324 , columnIndex = numberOfColumns - 1 325 ; 326 327 elements.forEach(function append_to_next_fragment(element) { 328 var fragment = fragments[columnIndex]; 329 fragment.insertBefore(element, fragment.firstChild); 330 if (columnIndex === 0) { 331 columnIndex = numberOfColumns - 1; 332 } else { 333 columnIndex--; 334 } 335 }); 336 337 Array.prototype.forEach.call(columns, function insert_column(column, index) { 338 column.insertBefore(fragments[index], column.firstChild); 339 }); 340 341 // populates a fragment with n columns till the right 342 var fragment = document.createDocumentFragment() 343 , numberOfColumnsToExtract = elements.length % numberOfColumns 344 ; 345 346 while (numberOfColumnsToExtract-- !== 0) { 347 fragment.appendChild(grid.lastChild); 348 } 349 350 // adds the fragment to the left 351 grid.insertBefore(fragment, grid.firstChild); 352}; 353 354 355self.registerGrid = function registerGrid (grid) { 356 if (global.getComputedStyle(grid).display === "none") { 357 return; 358 } 359 360 if ( 'true' === grid.getAttribute('data-inited') ) { 361 return; 362 } 363 364 grid.setAttribute( 'data-inited', 'true' ); 365 366 // retrieve the list of items from the grid itself 367 var range = document.createRange(); 368 range.selectNodeContents(grid); 369 370 var items = document.createElement("div"); 371 items.appendChild(range.extractContents()); 372 373 374 add_to_dataset(items, 'columns', 0); 375 self.addColumns(grid, items); 376 grids.push(grid); 377}; 378 379 380self.init = function init() { 381 // adds required CSS rule to hide 'content' based 382 // configuration. 383 384 var css = document.createElement("style"); 385 css.innerHTML = "[data-columns]::before{display:block;visibility:hidden;position:absolute;font-size:1px;}"; 386 document.head.appendChild(css); 387 388 // scans all the grids in the document and generates 389 // columns from their configuration. 390 391 var gridElements = document.querySelectorAll("[data-columns]"); 392 393 Array.prototype.forEach.call(gridElements, self.registerGrid); 394 self.scanMediaQueries(); 395}; 396 397self.init(); 398 399return { 400 appendElements: self.appendElements, 401 prependElements: self.prependElements, 402 registerGrid: self.registerGrid, 403 recreateColumns: self.recreateColumns, 404 rescanMediaQueries: self.rescanMediaQueries, 405 init: self.init, 406 407 // maintains backwards compatibility with underscore style method names 408 append_elements: self.appendElements, 409 prepend_elements: self.prependElements, 410 register_grid: self.registerGrid, 411 recreate_columns: self.recreateColumns, 412 rescan_media_queries: self.rescanMediaQueries 413}; 414 415})(window, window.document);
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.