vendor: 17,676 bytes, lines 1-581
1/*! 2 * Salvattore 1.0.5 by @rnmp and @ppold 3 * https://github.com/rnmp/salvattore 4 */ 5(function(root, factory) { 6 if (typeof define === 'function' && define.amd) { 7 define([], factory); 8 } else if (typeof exports === 'object') { 9 module.exports = factory(); 10 } else { 11 root.salvattore = factory(); 12 } 13}(this, function() { 14/*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas, David Knight. Dual MIT/BSD license */ 15 16if (!window.matchMedia) { 17 window.matchMedia = function() { 18 "use strict"; 19 20 // For browsers that support matchMedium api such as IE 9 and webkit 21 var styleMedia = (window.styleMedia || window.media); 22 23 // For those that don't support matchMedium 24 if (!styleMedia) { 25 var style = document.createElement('style'), 26 script = document.getElementsByTagName('script')[0], 27 info = null; 28 29 style.type = 'text/css'; 30 style.id = 'matchmediajs-test'; 31 32 script.parentNode.insertBefore(style, script); 33 34 // 'style.currentStyle' is used by IE <= 8 and 'window.getComputedStyle' for all other browsers 35 info = ('getComputedStyle' in window) && window.getComputedStyle(style, null) || style.currentStyle; 36 37 styleMedia = { 38 matchMedium: function(media) { 39 var text = '@media ' + media + '{ #matchmediajs-test { width: 1px; } }'; 40 41 // 'style.styleSheet' is used by IE <= 8 and 'style.textContent' for all other browsers 42 if (style.styleSheet) { 43 style.styleSheet.cssText = text; 44 } else { 45 style.textContent = text; 46 } 47 48 // Test if media query is true or false 49 return info.width === '1px'; 50 } 51 }; 52 } 53 54 return function(media) { 55 return { 56 matches: styleMedia.matchMedium(media || 'all'), 57 media: media || 'all' 58 }; 59 }; 60 }(); 61} 62 63/*! matchMedia() polyfill addListener/removeListener extension. Author & copyright (c) 2012: Scott Jehl. Dual MIT/BSD license */ 64(function(){ 65 "use strict"; 66 67 // Bail out for browsers that have addListener support 68 if (window.matchMedia && window.matchMedia('all').addListener) { 69 return false; 70 } 71 72 var localMatchMedia = window.matchMedia, 73 hasMediaQueries = localMatchMedia('only all').matches, 74 isListening = false, 75 timeoutID = 0, // setTimeout for debouncing 'handleChange' 76 queries = [], // Contains each 'mql' and associated 'listeners' if 'addListener' is used 77 handleChange = function(evt) { 78 // Debounce 79 clearTimeout(timeoutID); 80 81 timeoutID = setTimeout(function() { 82 for (var i = 0, il = queries.length; i < il; i++) { 83 var mql = queries[i].mql, 84 listeners = queries[i].listeners || [], 85 matches = localMatchMedia(mql.media).matches; 86 87 // Update mql.matches value and call listeners 88 // Fire listeners only if transitioning to or from matched state 89 if (matches !== mql.matches) { 90 mql.matches = matches; 91 92 for (var j = 0, jl = listeners.length; j < jl; j++) { 93 listeners[j].call(window, mql); 94 } 95 } 96 } 97 }, 30); 98 }; 99 100 window.matchMedia = function(media) { 101 var mql = localMatchMedia(media), 102 listeners = [], 103 index = 0; 104 105 mql.addListener = function(listener) { 106 // Changes would not occur to css media type so return now (Affects IE <= 8) 107 if (!hasMediaQueries) { 108 return; 109 } 110 111 // Set up 'resize' listener for browsers that support CSS3 media queries (Not for IE <= 8) 112 // There should only ever be 1 resize listener running for performance 113 if (!isListening) { 114 isListening = true; 115 window.addEventListener('resize', handleChange, true); 116 } 117 118 // Push object only if it has not been pushed already 119 if (index === 0) { 120 index = queries.push({ 121 mql : mql, 122 listeners : listeners 123 }); 124 } 125 126 listeners.push(listener); 127 }; 128 129 mql.removeListener = function(listener) { 130 for (var i = 0, il = listeners.length; i < il; i++){ 131 if (listeners[i] === listener){ 132 listeners.splice(i, 1); 133 } 134 } 135 }; 136 137 return mql; 138 }; 139}()); 140 141// http://paulirish.com/2011/requestanimationframe-for-smart-animating/ 142// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating 143 144// requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel 145 146// MIT license 147 148(function() { 149 "use strict"; 150 151 var lastTime = 0; 152 var vendors = ['ms', 'moz', 'webkit', 'o']; 153 for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { 154 window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame']; 155 window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] || 156 window[vendors[x]+'CancelRequestAnimationFrame']; 157 } 158 159 if (!window.requestAnimationFrame) 160 window.requestAnimationFrame = function(callback, element) { 161 var currTime = new Date().getTime(); 162 var timeToCall = Math.max(0, 16 - (currTime - lastTime)); 163 var id = window.setTimeout(function() { callback(currTime + timeToCall); }, 164 timeToCall); 165 lastTime = currTime + timeToCall; 166 return id; 167 }; 168 169 if (!window.cancelAnimationFrame) 170 window.cancelAnimationFrame = function(id) { 171 clearTimeout(id); 172 }; 173}()); 174 175// https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent 176 177if (typeof window.CustomEvent !== "function") { 178 (function() { 179 "use strict"; 180 function CustomEvent(event, params) { 181 params = params || { bubbles: false, cancelable: false, detail: undefined }; 182 var evt = document.createEvent('CustomEvent'); 183 evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail); 184 return evt; 185 } 186 187 CustomEvent.prototype = window.Event.prototype; 188 189 window.CustomEvent = CustomEvent; 190 })(); 191} 192 193/* jshint laxcomma: true */ 194var salvattore = (function (global, document, undefined) { 195"use strict"; 196 197var self = {}, 198 grids = [], 199 mediaRules = [], 200 mediaQueries = [], 201 add_to_dataset = function(element, key, value) { 202 // uses dataset function or a fallback for <ie10 203 if (element.dataset) { 204 element.dataset[key] = value; 205 } else { 206 element.setAttribute("data-" + key, value); 207 } 208 return; 209 }; 210 211self.obtainGridSettings = function obtainGridSettings(element) { 212 // returns the number of columns and the classes a column should have, 213 // from computing the style of the ::before pseudo-element of the grid. 214 215 var computedStyle = global.getComputedStyle(element, ":before") 216 , content = computedStyle.getPropertyValue("content").slice(1, -1) 217 , matchResult = content.match(/^\s*(\d+)(?:\s?\.(.+))?\s*$/) 218 , numberOfColumns = 1 219 , columnClasses = [] 220 ; 221 222 if (matchResult) { 223 numberOfColumns = matchResult[1]; 224 columnClasses = matchResult[2]; 225 columnClasses = columnClasses? columnClasses.split(".") : ["column"]; 226 } else { 227 matchResult = content.match(/^\s*\.(.+)\s+(\d+)\s*$/); 228 if (matchResult) { 229 columnClasses = matchResult[1]; 230 numberOfColumns = matchResult[2]; 231 if (numberOfColumns) { 232 numberOfColumns = numberOfColumns.split("."); 233 } 234 } 235 } 236 237 return { 238 numberOfColumns: numberOfColumns, 239 columnClasses: columnClasses 240 }; 241}; 242 243 244self.addColumns = function addColumns(grid, items) { 245 // from the settings obtained, it creates columns with 246 // the configured classes and adds to them a list of items. 247 248 var settings = self.obtainGridSettings(grid) 249 , numberOfColumns = settings.numberOfColumns 250 , columnClasses = settings.columnClasses 251 , columnsItems = new Array(+numberOfColumns) 252 , columnsFragment = document.createDocumentFragment() 253 , i = numberOfColumns 254 , selector 255 ; 256 257 while (i-- !== 0) { 258 selector = "[data-columns] > *:nth-child(" + numberOfColumns + "n-" + i + ")"; 259 columnsItems.push(items.querySelectorAll(selector)); 260 } 261 262 columnsItems.forEach(function append_to_grid_fragment(rows) { 263 var column = document.createElement("div") 264 , rowsFragment = document.createDocumentFragment() 265 ; 266 267 column.className = columnClasses.join(" "); 268 269 Array.prototype.forEach.call(rows, function append_to_column(row) { 270 rowsFragment.appendChild(row); 271 }); 272 column.appendChild(rowsFragment); 273 columnsFragment.appendChild(column); 274 }); 275 276 grid.appendChild(columnsFragment); 277 add_to_dataset(grid, 'columns', numberOfColumns); 278}; 279 280 281self.removeColumns = function removeColumns(grid) { 282 // removes all the columns from a grid, and returns a list 283 // of items sorted by the ordering of columns. 284 285 var range = document.createRange(); 286 range.selectNodeContents(grid); 287 288 var columns = Array.prototype.filter.call(range.extractContents().childNodes, function filter_elements(node) { 289 return node instanceof global.HTMLElement; 290 }); 291 292 var numberOfColumns = columns.length 293 , numberOfRowsInFirstColumn = columns[0].childNodes.length 294 , sortedRows = new Array(numberOfRowsInFirstColumn * numberOfColumns) 295 ; 296 297 Array.prototype.forEach.call(columns, function iterate_columns(column, columnIndex) { 298 Array.prototype.forEach.call(column.children, function iterate_rows(row, rowIndex) { 299 sortedRows[rowIndex * numberOfColumns + columnIndex] = row; 300 }); 301 }); 302 303 var container = document.createElement("div"); 304 add_to_dataset(container, 'columns', 0); 305 306 sortedRows.filter(function filter_non_null(child) { 307 return !!child; 308 }).forEach(function append_row(child) { 309 container.appendChild(child); 310 }); 311 312 return container; 313}; 314 315 316self.recreateColumns = function recreateColumns(grid) { 317 // removes all the columns from the grid, and adds them again, 318 // it is used when the number of columns change. 319 320 global.requestAnimationFrame(function render_after_css_mediaQueryChange() { 321 self.addColumns(grid, self.removeColumns(grid)); 322 var columnsChange = new CustomEvent("columnsChange"); 323 grid.dispatchEvent(columnsChange); 324 }); 325}; 326 327 328self.mediaQueryChange = function mediaQueryChange(mql) { 329 // recreates the columns when a media query matches the current state 330 // of the browser. 331 332 if (mql.matches) { 333 Array.prototype.forEach.call(grids, self.recreateColumns); 334 } 335}; 336 337 338self.getCSSRules = function getCSSRules(stylesheet) { 339 // returns a list of css rules from a stylesheet 340 341 var cssRules; 342 try { 343 cssRules = stylesheet.sheet.cssRules || stylesheet.sheet.rules; 344 } catch (e) { 345 return []; 346 } 347 348 return cssRules || []; 349}; 350 351 352self.getStylesheets = function getStylesheets() { 353 // returns a list of all the styles in the document (that are accessible). 354 355 return Array.prototype.concat.call( 356 Array.prototype.slice.call(document.querySelectorAll("style[type='text/css']")), 357 Array.prototype.slice.call(document.querySelectorAll("link[rel='stylesheet']")) 358 ); 359}; 360 361 362self.mediaRuleHasColumnsSelector = function mediaRuleHasColumnsSelector(rules) { 363 // checks if a media query css rule has in its contents a selector that 364 // styles the grid. 365 366 var i, rule; 367 368 try { 369 i = rules.length; 370 } 371 catch (e) { 372 i = 0; 373 } 374 375 while (i--) { 376 rule = rules[i]; 377 if (rule.selectorText && rule.selectorText.match(/\[data-columns\](.*)::?before$/)) { 378 return true; 379 } 380 } 381 382 return false; 383}; 384 385 386self.scanMediaQueries = function scanMediaQueries() { 387 // scans all the stylesheets for selectors that style grids, 388 // if the matchMedia API is supported. 389 390 var newMediaRules = []; 391 392 if (!global.matchMedia) { 393 return; 394 } 395 396 self.getStylesheets().forEach(function extract_rules(stylesheet) { 397 Array.prototype.forEach.call(self.getCSSRules(stylesheet), function filter_by_column_selector(rule) { 398 if (rule.media && rule.cssRules && self.mediaRuleHasColumnsSelector(rule.cssRules)) { 399 newMediaRules.push(rule); 400 } 401 }); 402 }); 403 404 // remove matchMedia listeners from the old rules 405 var oldRules = mediaRules.filter(function (el) { 406 return newMediaRules.indexOf(el) === -1; 407 }); 408 mediaQueries.filter(function (el) { 409 return oldRules.indexOf(el.rule) !== -1; 410 }).forEach(function (el) { 411 el.mql.removeListener(self.mediaQueryChange); 412 }); 413 mediaQueries = mediaQueries.filter(function (el) { 414 return oldRules.indexOf(el.rule) === -1; 415 }); 416 417 // add matchMedia listeners to the new rules 418 newMediaRules.filter(function (el) { 419 return mediaRules.indexOf(el) == -1; 420 }).forEach(function (rule) { 421 var mql = global.matchMedia(rule.media.mediaText); 422 mql.addListener(self.mediaQueryChange); 423 mediaQueries.push({rule: rule, mql:mql}); 424 }); 425 426 // swap mediaRules with the new set 427 mediaRules.length = 0; 428 mediaRules = newMediaRules; 429}; 430 431 432self.rescanMediaQueries = function rescanMediaQueries() { 433 self.scanMediaQueries(); 434 Array.prototype.forEach.call(grids, self.recreateColumns); 435}; 436 437 438self.nextElementColumnIndex = function nextElementColumnIndex(grid, fragments) { 439 // returns the index of the column where the given element must be added. 440 441 var children = grid.children 442 , m = children.length 443 , lowestRowCount = 0 444 , child 445 , currentRowCount 446 , i 447 , index = 0 448 ; 449 for (i = 0; i < m; i++) { 450 child = children[i]; 451 currentRowCount = child.children.length + (fragments[i].children || fragments[i].childNodes).length; 452 if(lowestRowCount === 0) { 453 lowestRowCount = currentRowCount; 454 } 455 if(currentRowCount < lowestRowCount) { 456 index = i; 457 lowestRowCount = currentRowCount; 458 } 459 } 460 461 return index; 462}; 463 464 465self.createFragmentsList = function createFragmentsList(quantity) { 466 // returns a list of fragments 467 468 var fragments = new Array(quantity) 469 , i = 0 470 ; 471 472 while (i !== quantity) { 473 fragments[i] = document.createDocumentFragment(); 474 i++; 475 } 476 477 return fragments; 478}; 479 480 481self.appendElements = function appendElements(grid, elements) { 482 // adds a list of elements to the end of a grid 483 484 var columns = grid.children 485 , numberOfColumns = columns.length 486 , fragments = self.createFragmentsList(numberOfColumns) 487 ; 488 489 Array.prototype.forEach.call(elements, function append_to_next_fragment(element) { 490 var columnIndex = self.nextElementColumnIndex(grid, fragments); 491 fragments[columnIndex].appendChild(element); 492 }); 493 494 Array.prototype.forEach.call(columns, function insert_column(column, index) { 495 column.appendChild(fragments[index]); 496 }); 497}; 498 499 500self.prependElements = function prependElements(grid, elements) { 501 // adds a list of elements to the start of a grid 502 503 var columns = grid.children 504 , numberOfColumns = columns.length 505 , fragments = self.createFragmentsList(numberOfColumns) 506 , columnIndex = numberOfColumns - 1 507 ; 508 509 elements.forEach(function append_to_next_fragment(element) { 510 var fragment = fragments[columnIndex]; 511 fragment.insertBefore(element, fragment.firstChild); 512 if (columnIndex === 0) { 513 columnIndex = numberOfColumns - 1; 514 } else { 515 columnIndex--; 516 } 517 }); 518 519 Array.prototype.forEach.call(columns, function insert_column(column, index) { 520 column.insertBefore(fragments[index], column.firstChild); 521 }); 522 523 // populates a fragment with n columns till the right 524 var fragment = document.createDocumentFragment() 525 , numberOfColumnsToExtract = elements.length % numberOfColumns 526 ; 527 528 while (numberOfColumnsToExtract-- !== 0) { 529 fragment.appendChild(grid.lastChild); 530 } 531 532 // adds the fragment to the left 533 grid.insertBefore(fragment, grid.firstChild); 534}; 535 536 537self.registerGrid = function registerGrid (grid) { 538 if (global.getComputedStyle(grid).display === "none") { 539 return; 540 } 541 542 // retrieve the list of items from the grid itself 543 var range = document.createRange(); 544 range.selectNodeContents(grid); 545 546 var items = document.createElement("div"); 547 items.appendChild(range.extractContents()); 548 549 550 add_to_dataset(items, 'columns', 0); 551 self.addColumns(grid, items); 552 grids.push(grid); 553}; 554 555 556self.init = function init() { 557 // adds required CSS rule to hide 'content' based 558 // configuration. 559 560 var css = document.createElement("style"); 561 css.innerHTML = "[data-columns]::before{visibility:hidden;position:absolute;font-size:1px;}"; 562 document.head.appendChild(css); 563 564 // scans all the grids in the document and generates 565 // columns from their configuration. 566 567 var gridElements = document.querySelectorAll("[data-columns]"); 568 Array.prototype.forEach.call(gridElements, self.registerGrid); 569 self.scanMediaQueries(); 570}; 571 572self.init(); 573 574return { 575 appendElements: self.appendElements, 576 prependElements: self.prependElements, 577 registerGrid: self.registerGrid, 578 recreateColumns: self.recreateColumns, 579 rescanMediaQueries: self.rescanMediaQueries, 580 581 // maintains backwards compatibility with underscore style method n
581ames 582 append_elements: self.appendElements, 583 prepend_elements: self.prependElements, 584 register_grid: self.registerGrid, 585 recreate_columns: self.recreateColumns, 586 rescan_media_queries: self.rescanMediaQueries 587}; 588 589})(window, window.document); 590 591return salvattore; 592}));
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.