vendor: 38,691 bytes, lines 1-1575
1/*! 2 * Isotope PACKAGED v3.0.5 3 * 4 * Licensed GPLv3 for open source use 5 * or Isotope Commercial License for commercial use 6 * 7 * https://isotope.metafizzy.co 8 * Copyright 2017 Metafizzy 9 */ 10 11/** 12 * Bridget makes jQuery widgets 13 * v2.0.1 14 * MIT license 15 */ 16 17/* jshint browser: true, strict: true, undef: true, unused: true */ 18 19(function (window, factory) { 20 // universal module definition 21 /*jshint strict: false */ 22 /* globals define, module, require */ 23 if (typeof define == 'function' && define.amd) { 24 // AMD 25 define('jquery-bridget/jquery-bridget', ['jquery'], function (jQuery) { 26 return factory(window, jQuery); 27 }); 28 } else if (typeof module == 'object' && module.exports) { 29 // CommonJS 30 module.exports = factory( 31 window, 32 require('jquery') 33 ); 34 } else { 35 // browser global 36 window.jQueryBridget = factory( 37 window, 38 window.jQuery 39 ); 40 } 41 42}(window, function factory(window, jQuery) { 43 'use strict'; 44 45// ----- utils ----- // 46 47 var arraySlice = Array.prototype.slice; 48 49// helper function for logging errors 50// $.error breaks jQuery chaining 51 var console = window.console; 52 var logError = typeof console == 'undefined' ? function () { 53 } : 54 function (message) { 55 console.error(message); 56 }; 57 58// ----- jQueryBridget ----- // 59 60 function jQueryBridget(namespace, PluginClass, $) { 61 $ = $ || jQuery || window.jQuery; 62 if (!$) { 63 return; 64 } 65 66 // add option method -> $().plugin('option', {...}) 67 if (!PluginClass.prototype.option) { 68 // option setter 69 PluginClass.prototype.option = function (opts) { 70 // bail out if not an object 71 if (!$.isPlainObject(opts)) { 72 return; 73 } 74 this.options = $.extend(true, this.options, opts); 75 }; 76 } 77 78 // make jQuery plugin 79 $.fn[namespace] = function (arg0 /*, arg1 */) { 80 if (typeof arg0 == 'string') { 81 // method call $().plugin( 'methodName', { options } ) 82 // shift arguments by 1 83 var args = arraySlice.call(arguments, 1); 84 return methodCall(this, arg0, args); 85 } 86 // just $().plugin({ options }) 87 plainCall(this, arg0); 88 return this; 89 }; 90 91 // $().plugin('methodName') 92 function methodCall($elems, methodName, args) { 93 var returnValue; 94 var pluginMethodStr = '$().' + namespace + '("' + methodName + '")'; 95 96 $elems.each(function (i, elem) { 97 // get instance 98 var instance = $.data(elem, namespace); 99 if (!instance) { 100 logError(namespace + ' not initialized. Cannot call methods, i.e. ' + 101 pluginMethodStr); 102 return; 103 } 104 105 var method = instance[methodName]; 106 if (!method || methodName.charAt(0) == '_') { 107 logError(pluginMethodStr + ' is not a valid method'); 108 return; 109 } 110 111 // apply method, get return value 112 var value = method.apply(instance, args); 113 // set return value if value is returned, use only first value 114 returnValue = returnValue === undefined ? value : returnValue; 115 }); 116 117 return returnValue !== undefined ? returnValue : $elems; 118 } 119 120 function plainCall($elems, options) { 121 $elems.each(function (i, elem) { 122 var instance = $.data(elem, namespace); 123 if (instance) { 124 // set options & init 125 instance.option(options); 126 instance._init(); 127 } else { 128 // initialize new instance 129 instance = new PluginClass(elem, options); 130 $.data(elem, namespace, instance); 131 } 132 }); 133 } 134 135 updateJQuery($); 136 137 } 138 139// ----- updateJQuery ----- // 140 141// set $.bridget for v1 backwards compatibility 142 function updateJQuery($) { 143 if (!$ || ($ && $.bridget)) { 144 return; 145 } 146 $.bridget = jQueryBridget; 147 } 148 149 updateJQuery(jQuery || window.jQuery); 150 151// ----- ----- // 152 153 return jQueryBridget; 154 155})); 156 157/** 158 * EvEmitter v1.1.0 159 * Lil' event emitter 160 * MIT License 161 */ 162 163/* jshint unused: true, undef: true, strict: true */ 164 165(function (global, factory) { 166 // universal module definition 167 /* jshint strict: false */ 168 /* globals define, module, window */ 169 if (typeof define == 'function' && define.amd) { 170 // AMD - RequireJS 171 define('ev-emitter/ev-emitter', factory); 172 } else if (typeof module == 'object' && module.exports) { 173 // CommonJS - Browserify, Webpack 174 module.exports = factory(); 175 } else { 176 // Browser globals 177 global.EvEmitter = factory(); 178 } 179 180}(typeof window != 'undefined' ? window : this, function () { 181 182 183 function EvEmitter() { 184 } 185 186 var proto = EvEmitter.prototype; 187 188 proto.on = function (eventName, listener) { 189 if (!eventName || !listener) { 190 return; 191 } 192 // set events hash 193 var events = this._events = this._events || {}; 194 // set listeners array 195 var listeners = events[eventName] = events[eventName] || []; 196 // only add once 197 if (listeners.indexOf(listener) == -1) { 198 listeners.push(listener); 199 } 200 201 return this; 202 }; 203 204 proto.once = function (eventName, listener) { 205 if (!eventName || !listener) { 206 return; 207 } 208 // add event 209 this.on(eventName, listener); 210 // set once flag 211 // set onceEvents hash 212 var onceEvents = this._onceEvents = this._onceEvents || {}; 213 // set onceListeners object 214 var onceListeners = onceEvents[eventName] = onceEvents[eventName] || {}; 215 // set flag 216 onceListeners[listener] = true; 217 218 return this; 219 }; 220 221 proto.off = function (eventName, listener) { 222 var listeners = this._events && this._events[eventName]; 223 if (!listeners || !listeners.length) { 224 return; 225 } 226 var index = listeners.indexOf(listener); 227 if (index != -1) { 228 listeners.splice(index, 1); 229 } 230 231 return this; 232 }; 233 234 proto.emitEvent = function (eventName, args) { 235 var listeners = this._events && this._events[eventName]; 236 if (!listeners || !listeners.length) { 237 return; 238 } 239 // copy over to avoid interference if .off() in listener 240 listeners = listeners.slice(0); 241 args = args || []; 242 // once stuff 243 var onceListeners = this._onceEvents && this._onceEvents[eventName]; 244 245 for (var i = 0; i < listeners.length; i++) { 246 var listener = listeners[i] 247 var isOnce = onceListeners && onceListeners[listener]; 248 if (isOnce) { 249 // remove listener 250 // remove before trigger to prevent recursion 251 this.off(eventName, listener); 252 // unset once flag 253 delete onceListeners[listener]; 254 } 255 // trigger listener 256 listener.apply(this, args); 257 } 258 259 return this; 260 }; 261 262 proto.allOff = function () { 263 delete this._events; 264 delete this._onceEvents; 265 }; 266 267 return EvEmitter; 268 269})); 270 271/*! 272 * getSize v2.0.2 273 * measure size of elements 274 * MIT license 275 */ 276 277/*jshint browser: true, strict: true, undef: true, unused: true */ 278/*global define: false, module: false, console: false */ 279 280(function (window, factory) { 281 'use strict'; 282 283 if (typeof define == 'function' && define.amd) { 284 // AMD 285 define('get-size/get-size', [], function () { 286 return factory(); 287 }); 288 } else if (typeof module == 'object' && module.exports) { 289 // CommonJS 290 module.exports = factory(); 291 } else { 292 // browser global 293 window.getSize = factory(); 294 } 295 296})(window, function factory() { 297 'use strict'; 298 299// -------------------------- helpers -------------------------- // 300 301// get a number from a string, not a percentage 302 function getStyleSize(value) { 303 var num = parseFloat(value); 304 // not a percent like '100%', and a number 305 var isValid = value.indexOf('%') == -1 && !isNaN(num); 306 return isValid && num; 307 } 308 309 function noop() { 310 } 311 312 var logError = typeof console == 'undefined' ? noop : 313 function (message) { 314 console.error(message); 315 }; 316 317// -------------------------- measurements -------------------------- // 318 319 var measurements = [ 320 'paddingLeft', 321 'paddingRight', 322 'paddingTop', 323 'paddingBottom', 324 'marginLeft', 325 'marginRight', 326 'marginTop', 327 'marginBottom', 328 'borderLeftWidth', 329 'borderRightWidth', 330 'borderTopWidth', 331 'borderBottomWidth' 332 ]; 333 334 var measurementsLength = measurements.length; 335 336 function getZeroSize() { 337 var size = { 338 width : 0, 339 height : 0, 340 innerWidth : 0, 341 innerHeight: 0, 342 outerWidth : 0, 343 outerHeight: 0 344 }; 345 for (var i = 0; i < measurementsLength; i++) { 346 var measurement = measurements[i]; 347 size[measurement] = 0; 348 } 349 return size; 350 } 351 352// -------------------------- getStyle -------------------------- // 353 354 /** 355 * getStyle, get style of element, check for Firefox bug 356 * https://bugzilla.mozilla.org/show_bug.cgi?id=548397 357 */ 358 function getStyle(elem) { 359 var style = getComputedStyle(elem); 360 if (!style) { 361 logError('Style returned ' + style + 362 '. Are you running this code in a hidden iframe on Firefox? ' + 363 'See http://bit.ly/getsizebug1'); 364 } 365 return style; 366 } 367 368// -------------------------- setup -------------------------- // 369 370 var isSetup = false; 371 372 var isBoxSizeOuter; 373 374 /** 375 * setup 376 * check isBoxSizerOuter 377 * do on first getSize() rather than on page load for Firefox bug 378 */ 379 function setup() { 380 // setup once 381 if (isSetup) { 382 return; 383 } 384 isSetup = true; 385 386 // -------------------------- box sizing -------------------------- // 387 388 /** 389 * WebKit measures the outer-width on style.width on border-box elems 390 * IE & Firefox<29 measures the inner-width 391 */ 392 var div = document.createElement('div'); 393 div.style.width = '200px'; 394 div.style.padding = '1px 2px 3px 4px'; 395 div.style.borderStyle = 'solid'; 396 div.style.borderWidth = '1px 2px 3px 4px'; 397 div.style.boxSizing = 'border-box'; 398 399 var body = document.body || document.documentElement; 400 body.appendChild(div); 401 var style = getStyle(div); 402 403 getSize.isBoxSizeOuter = isBoxSizeOuter = getStyleSize(style.width) == 200; 404 body.removeChild(div); 405 406 } 407 408// -------------------------- getSize -------------------------- // 409 410 function getSize(elem) { 411 setup(); 412 413 // use querySeletor if elem is string 414 if (typeof elem == 'string') { 415 elem = document.querySelector(elem); 416 } 417 418 // do not proceed on non-objects 419 if (!elem || typeof elem != 'object' || !elem.nodeType) { 420 return; 421 } 422 423 var style = getStyle(elem); 424 425 // if hidden, everything is 0 426 if (style.display == 'none') { 427 return getZeroSize(); 428 } 429 430 var size = {}; 431 size.width = elem.offsetWidth; 432 size.height = elem.offsetHeight; 433 434 var isBorderBox = size.isBorderBox = style.boxSizing == 'border-box'; 435 436 // get all measurements 437 for (var i = 0; i < measurementsLength; i++) { 438 var measurement = measurements[i]; 439 var value = style[measurement]; 440 var num = parseFloat(value); 441 // any 'auto', 'medium' value will be 0 442 size[measurement] = !isNaN(num) ? num : 0; 443 } 444 445 var paddingWidth = size.paddingLeft + size.paddingRight; 446 var paddingHeight = size.paddingTop + size.paddingBottom; 447 var marginWidth = size.marginLeft + size.marginRight; 448 var marginHeight = size.marginTop + size.marginBottom; 449 var borderWidth = size.borderLeftWidth + size.borderRightWidth; 450 var borderHeight = size.borderTopWidth + size.borderBottomWidth; 451 452 var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter; 453 454 // overwrite width and height if we can get it from style 455 var styleWidth = getStyleSize(style.width); 456 if (styleWidth !== false) { 457 size.width = styleWidth + 458 // add padding and border unless it's already including it 459 (isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth); 460 } 461 462 var styleHeight = getStyleSize(style.height); 463 if (styleHeight !== false) { 464 size.height = styleHeight + 465 // add padding and border unless it's already including it 466 (isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight); 467 } 468 469 size.innerWidth = size.width - (paddingWidth + borderWidth); 470 size.innerHeight = size.height - (paddingHeight + borderHeight); 471 472 size.outerWidth = size.width + marginWidth; 473 size.outerHeight = size.height + marginHeight; 474 475 return size; 476 } 477 478 return getSize; 479 480}); 481 482/** 483 * matchesSelector v2.0.2 484 * matchesSelector( element, '.selector' ) 485 * MIT license 486 */ 487 488/*jshint browser: true, strict: true, undef: true, unused: true */ 489 490(function (window, factory) { 491 /*global define: false, module: false */ 492 'use strict'; 493 // universal module definition 494 if (typeof define == 'function' && define.amd) { 495 // AMD 496 define('desandro-matches-selector/matches-selector', factory); 497 } else if (typeof module == 'object' && module.exports) { 498 // CommonJS 499 module.exports = factory(); 500 } else { 501 // browser global 502 window.matchesSelector = factory(); 503 } 504 505}(window, function factory() { 506 'use strict'; 507 508 var matchesMethod = (function () { 509 var ElemProto = window.Element.prototype; 510 // check for the standard method name first 511 if (ElemProto.matches) { 512 return 'matches'; 513 } 514 // check un-prefixed 515 if (ElemProto.matchesSelector) { 516 return 'matchesSelector'; 517 } 518 // check vendor prefixes 519 var prefixes = ['webkit', 'moz', 'ms', 'o']; 520 521 for (var i = 0; i < prefixes.length; i++) { 522 var prefix = prefixes[i]; 523 var method = prefix + 'MatchesSelector'; 524 if (ElemProto[method]) { 525 return method; 526 } 527 } 528 })(); 529 530 return function matchesSelector(elem, selector) { 531 return elem[matchesMethod](selector); 532 }; 533 534})); 535 536/** 537 * Fizzy UI utils v2.0.5 538 * MIT license 539 */ 540 541/*jshint browser: true, undef: true, unused: true, strict: true */ 542 543(function (window, factory) { 544 // universal module definition 545 /*jshint strict: false */ 546 /*globals define, module, require */ 547 548 if (typeof define == 'function' && define.amd) { 549 // AMD 550 define('fizzy-ui-utils/utils', [ 551 'desandro-matches-selector/matches-selector' 552 ], function (matchesSelector) { 553 return factory(window, matchesSelector); 554 }); 555 } else if (typeof module == 'object' && module.exports) { 556 // CommonJS 557 module.exports = factory( 558 window, 559 require('desandro-matches-selector') 560 ); 561 } else { 562 // browser global 563 window.fizzyUIUtils = factory( 564 window, 565 window.matchesSelector 566 ); 567 } 568 569}(window, function factory(window, matchesSelector) { 570 571 572 var utils = {}; 573 574// ----- extend ----- // 575 576// extends objects 577 utils.extend = function (a, b) { 578 for (var prop in b) { 579 a[prop] = b[prop]; 580 } 581 return a; 582 }; 583 584// ----- modulo ----- // 585 586 utils.modulo = function (num, div) { 587 return ((num % div) + div) % div; 588 }; 589 590// ----- makeArray ----- // 591 592// turn element or nodeList into an array 593 utils.makeArray = function (obj) { 594 var ary = []; 595 if (Array.isArray(obj)) { 596 // use object if already an array 597 ary = obj; 598 } else if (obj && typeof obj == 'object' && 599 typeof obj.length == 'number') { 600 // convert nodeList to array 601 for (var i = 0; i < obj.length; i++) { 602 ary.push(obj[i]); 603 } 604 } else { 605 // array of single index 606 ary.push(obj); 607 } 608 return ary; 609 }; 610 611// ----- removeFrom ----- // 612 613 utils.removeFrom = function (ary, obj) { 614 var index = ary.indexOf(obj); 615 if (index != -1) { 616 ary.splice(index, 1); 617 } 618 }; 619 620// ----- getParent ----- // 621 622 utils.getParent = function (elem, selector) { 623 while (elem.parentNode && elem != document.body) { 624 elem = elem.parentNode; 625 if (matchesSelector(elem, selector)) { 626 return elem; 627 } 628 } 629 }; 630 631// ----- getQueryElement ----- // 632 633// use element as selector string 634 utils.getQueryElement = function (elem) { 635 if (typeof elem == 'string') { 636 return document.querySelector(elem); 637 } 638 return elem; 639 }; 640 641// ----- handleEvent ----- // 642 643// enable .ontype to trigger from .addEventListener( elem, 'type' ) 644 utils.handleEvent = function (event) { 645 var method = 'on' + event.type; 646 if (this[method]) { 647 this[method](event); 648 } 649 }; 650 651// ----- filterFindElements ----- // 652 653 utils.filterFindElements = function (elems, selector) { 654 // make array of elems 655 elems = utils.makeArray(elems); 656 var ffElems = []; 657 658 elems.forEach(function (elem) { 659 // check that elem is an actual element 660 if (!(elem instanceof HTMLElement)) { 661 return; 662 } 663 // add elem if no selector 664 if (!selector) { 665 ffElems.push(elem); 666 return; 667 } 668 // filter & find items if we have a selector 669 // filter 670 if (matchesSelector(elem, selector)) { 671 ffElems.push(elem); 672 } 673 // find children 674 var childElems = elem.querySelectorAll(selector); 675 // concat childElems to filterFound array 676 for (var i = 0; i < childElems.length; i++) { 677 ffElems.push(childElems[i]); 678 } 679 }); 680 681 return ffElems; 682 }; 683 684// ----- debounceMethod ----- // 685 686 utils.debounceMethod = function (_class, methodName, threshold) { 687 // original method 688 var method = _class.prototype[methodName]; 689 var timeoutName = methodName + 'Timeout'; 690 691 _class.prototype[methodName] = function () { 692 var timeout = this[timeoutName]; 693 if (timeout) { 694 clearTimeout(timeout); 695 } 696 var args = arguments; 697 698 var _this = this; 699 this[timeoutName] = setTimeout(function () { 700 method.apply(_this, args); 701 delete _this[timeoutName]; 702 }, threshold || 100); 703 }; 704 }; 705 706// ----- docReady ----- // 707 708 utils.docReady = function (callback) { 709 var readyState = document.readyState; 710 if (readyState == 'complete' || readyState == 'interactive') { 711 // do async to allow for other scripts to run. metafizzy/flickity#441 712 setTimeout(callback); 713 } else { 714 document.addEventListener('DOMContentLoaded', callback); 715 } 716 }; 717 718// ----- htmlInit ----- // 719 720// http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/ 721 utils.toDashed = function (str) { 722 return str.replace(/(.)([A-Z])/g, function (match, $1, $2) { 723 return $1 + '-' + $2; 724 }).toLowerCase(); 725 }; 726 727 var console = window.console; 728 /** 729 * allow user to initialize classes via [data-namespace] or .js-namespace class 730 * htmlInit( Widget, 'widgetName' ) 731 * options are parsed from data-namespace-options 732 */ 733 utils.htmlInit = function (WidgetClass, namespace) { 734 utils.docReady(function () { 735 var dashedNamespace = utils.toDashed(namespace); 736 var dataAttr = 'data-' + dashedNamespace; 737 var dataAttrElems = document.querySelectorAll('[' + dataAttr + ']'); 738 var jsDashElems = document.querySelectorAll('.js-' + dashedNamespace); 739 var elems = utils.makeArray(dataAttrElems) 740 .concat(utils.makeArray(jsDashElems)); 741 var dataOptionsAttr = dataAttr + '-options'; 742 var jQuery = window.jQuery; 743 744 elems.forEach(function (elem) { 745 var attr = elem.getAttribute(dataAttr) || 746 elem.getAttribute(dataOptionsAttr); 747 var options; 748 try { 749 options = attr && JSON.parse(attr); 750 } catch (error) { 751 // log error, do not initialize 752 if (console) { 753 console.error('Error parsing ' + dataAttr + ' on ' + elem.className + 754 ': ' + error); 755 } 756 return; 757 } 758 // initialize 759 var instance = new WidgetClass(elem, options); 760 // make available via $().data('namespace') 761 if (jQuery) { 762 jQuery.data(elem, namespace, instance); 763 } 764 }); 765 766 }); 767 }; 768 769// ----- ----- // 770 771 return utils; 772 773})); 774 775/** 776 * Outlayer Item 777 */ 778 779(function (window, factory) { 780 // universal module definition 781 /* jshint strict: false */ 782 /* globals define, module, require */ 783 if (typeof define == 'function' && define.amd) { 784 // AMD - RequireJS 785 define('outlayer/item', [ 786 'ev-emitter/ev-emitter', 787 'get-size/get-size' 788 ], 789 factory 790 ); 791 } else if (typeof module == 'object' && module.exports) { 792 // CommonJS - Browserify, Webpack 793 module.exports = factory( 794 require('ev-emitter'), 795 require('get-size') 796 ); 797 } else { 798 // browser global 799 window.Outlayer = {}; 800 window.Outlayer.Item = factory( 801 window.EvEmitter, 802 window.getSize 803 ); 804 } 805 806}(window, function factory(EvEmitter, getSize) { 807 'use strict'; 808 809// ----- helpers ----- // 810 811 function isEmptyObj(obj) { 812 for (var prop in obj) { 813 return false; 814 } 815 prop = null; 816 return true; 817 } 818 819// -------------------------- CSS3 support -------------------------- // 820 821 822 var docElemStyle = document.documentElement.style; 823 824 var transitionProperty = typeof docElemStyle.transition == 'string' ? 825 'transition' : 'WebkitTransition'; 826 var transformProperty = typeof docElemStyle.transform == 'string' ? 827 'transform' : 'WebkitTransform'; 828 829 var transitionEndEvent = { 830 WebkitTransition: 'webkitTransitionEnd', 831 transition : 'transitionend' 832 }[transitionProperty]; 833 834// cache all vendor properties that could have vendor prefix 835 var vendorProperties = { 836 transform : transformProperty, 837 transition : transitionProperty, 838 transitionDuration: transitionProperty + 'Duration', 839 transitionProperty: transitionProperty + 'Property', 840 transitionDelay : transitionProperty + 'Delay' 841 }; 842 843// -------------------------- Item -------------------------- // 844 845 function Item(element, layout) { 846 if (!element) { 847 return; 848 } 849 850 this.element = element; 851 // parent layout class, i.e. Masonry, Isotope, or Packery 852 this.layout = layout; 853 this.position = { 854 x: 0, 855 y: 0 856 }; 857 858 this._create(); 859 } 860 861// inherit EvEmitter 862 var proto = Item.prototype = Object.create(EvEmitter.prototype); 863 proto.constructor = Item; 864 865 proto._create = function () { 866 // transition objects 867 this._transn = { 868 ingProperties: {}, 869 clean : {}, 870 onEnd : {} 871 }; 872 873 this.css({ 874 position: 'absolute' 875 }); 876 }; 877 878// trigger specified handler for event type 879 proto.handleEvent = function (event) { 880 var method = 'on' + event.type; 881 if (this[method]) { 882 this[method](event); 883 } 884 }; 885 886 proto.getSize = function () { 887 this.size = getSize(this.element); 888 }; 889 890 /** 891 * apply CSS styles to element 892 * @param {Object} style 893 */ 894 proto.css = function (style) { 895 var elemStyle = this.element.style; 896 897 for (var prop in style) { 898 // use vendor property if available 899 var supportedProp = vendorProperties[prop] || prop; 900 elemStyle[supportedProp] = style[prop]; 901 } 902 }; 903 904 // measure position, and sets it 905 proto.getPosition = function () { 906 var style = getComputedStyle(this.element); 907 var isOriginLeft = this.layout._getOption('originLeft'); 908 var isOriginTop = this.layout._getOption('originTop'); 909 var xValue = style[isOriginLeft ? 'left' : 'right']; 910 var yValue = style[isOriginTop ? 'top' : 'bottom']; 911 // convert percent to pixels 912 var layoutSize = this.layout.size; 913 var x = xValue.indexOf('%') != -1 ? 914 (parseFloat(xValue) / 100) * layoutSize.width : parseInt(xValue, 10); 915 var y = yValue.indexOf('%') != -1 ? 916 (parseFloat(yValue) / 100) * layoutSize.height : parseInt(yValue, 10); 917 918 // clean up 'auto' or other non-integer values 919 x = isNaN(x) ? 0 : x; 920 y = isNaN(y) ? 0 : y; 921 // remove padding from measurement 922 x -= isOriginLeft ? layoutSize.paddingLeft : layoutSize.paddingRight; 923 y -= isOriginTop ? layoutSize.paddingTop : layoutSize.paddingBottom; 924 925 this.position.x = x; 926 this.position.y = y; 927 }; 928 929// set settled position, apply padding 930 proto.layoutPosition = function () { 931 var layoutSize = this.layout.size; 932 var style = {}; 933 var isOriginLeft = this.layout._getOption('originLeft'); 934 var isOriginTop = this.layout._getOption('originTop'); 935 936 // x 937 var xPadding = isOriginLeft ? 'paddingLeft' : 'paddingRight'; 938 var xProperty = isOriginLeft ? 'left' : 'right'; 939 var xResetProperty = isOriginLeft ? 'right' : 'left'; 940 941 var x = this.position.x + layoutSize[xPadding]; 942 // set in percentage or pixels 943 style[xProperty] = this.getXValue(x); 944 // reset other property 945 style[xResetProperty] = ''; 946 947 // y 948 var yPadding = isOriginTop ? 'paddingTop' : 'paddingBottom'; 949 var yProperty = isOriginTop ? 'top' : 'bottom'; 950 var yResetProperty = isOriginTop ? 'bottom' : 'top'; 951 952 var y = this.position.y + layoutSize[yPadding]; 953 // set in percentage or pixels 954 style[yProperty] = this.getYValue(y); 955 // reset other property 956 style[yResetProperty] = ''; 957 958 this.css(style); 959 this.emitEvent('layout', [this]); 960 }; 961 962 proto.getXValue = function (x) { 963 var isHorizontal = this.layout._getOption('horizontal'); 964 return this.layout.options.percentPosition && !isHorizontal ? 965 ((x / this.layout.size.width) * 100) + '%' : x + 'px'; 966 }; 967 968 proto.getYValue = function (y) { 969 var isHorizontal = this.layout._getOption('horizontal'); 970 return this.layout.options.percentPosition && isHorizontal ? 971 ((y / this.layout.size.height) * 100) + '%' : y + 'px'; 972 }; 973 974 proto._transitionTo = function (x, y) { 975 this.getPosition(); 976 // get current x & y from top/left 977 var curX = this.position.x; 978 var curY = this.position.y; 979 980 var compareX = parseInt(x, 10); 981 var compareY = parseInt(y, 10); 982 var didNotMove = compareX === this.position.x && compareY === this.position.y; 983 984 // save end position 985 this.setPosition(x, y); 986 987 // if did not move and not transitioning, just go to layout 988 if (didNotMove && !this.isTransitioning) { 989 this.layoutPosition(); 990 return; 991 } 992 993 var transX = x - curX; 994 var transY = y - curY; 995 var transitionStyle = {}; 996 transitionStyle.transform = this.getTranslate(transX, transY); 997 998 this.transition({ 999 to : transitionStyle, 1000 onTransitionEnd: { 1001 transform: this.layoutPosition 1002 }, 1003 isCleaning : true 1004 }); 1005 }; 1006 1007 proto.getTranslate = function (x, y) { 1008 // flip cooridinates if origin on right or bottom 1009 var isOriginLeft = this.layout._getOption('originLeft'); 1010 var isOriginTop = this.layout._getOption('originTop'); 1011 x = isOriginLeft ? x : -x; 1012 y = isOriginTop ? y : -y; 1013 return 'translate3d(' + x + 'px, ' + y + 'px, 0)'; 1014 }; 1015 1016// non transition + transform support 1017 proto.goTo = function (x, y) { 1018 this.setPosition(x, y); 1019 this.layoutPosition(); 1020 }; 1021 1022 proto.moveTo = proto._transitionTo; 1023 1024 proto.setPosition = function (x, y) { 1025 this.position.x = parseInt(x, 10); 1026 this.position.y = parseInt(y, 10); 1027 }; 1028 1029// ----- transition ----- // 1030 1031 /** 1032 * @param {Object} style - CSS 1033 * @param {Function} onTransitionEnd 1034 */ 1035 1036// non transition, just trigger callback 1037 proto._nonTransition = function (args) { 1038 this.css(args.to); 1039 if (args.isCleaning) { 1040 this._removeStyles(args.to); 1041 } 1042 for (var prop in args.onTransitionEnd) { 1043 args.onTransitionEnd[prop].call(this); 1044 } 1045 }; 1046 1047 /** 1048 * proper transition 1049 * @param {Object} args - arguments 1050 * @param {Object} to - style to transition to 1051 * @param {Object} from - style to start transition from 1052 * @param {Boolean} isCleaning - removes transition styles after transition 1053 * @param {Function} onTransitionEnd - callback 1054 */ 1055 proto.transition = function (args) { 1056 // redirect to nonTransition if no transition duration 1057 if (!parseFloat(this.layout.options.transitionDuration)) { 1058 this._nonTransition(args); 1059 return; 1060 } 1061 1062 var _transition = this._transn; 1063 // keep track of onTransitionEnd callback by css property 1064 for (var prop in args.onTransitionEnd) { 1065 _transition.onEnd[prop] = args.onTransitionEnd[prop]; 1066 } 1067 // keep track of properties that are transitioning 1068 for (prop in args.to) { 1069 _transition.ingProperties[prop] = true; 1070 // keep track of properties to clean up when transition is done 1071 if (args.isCleaning) { 1072 _transition.clean[prop] = true; 1073 } 1074 } 1075 1076 // set from styles 1077 if (args.from) { 1078 this.css(args.from); 1079 // force redraw. http://blog.alexmaccaw.com/css-transitions 1080 var h = this.element.offsetHeight; 1081 // hack for JSHint to hush about unused var 1082 h = null; 1083 } 1084 // enable transition 1085 this.enableTransition(args.to); 1086 // set styles that are transitioning 1087 this.css(args.to); 1088 1089 this.isTransitioning = true; 1090 1091 }; 1092 1093// dash before all cap letters, including first for 1094// WebkitTransform => -webkit-transform 1095 function toDashedAll(str) { 1096 return str.replace(/([A-Z])/g, function ($1) { 1097 return '-' + $1.toLowerCase(); 1098 }); 1099 } 1100 1101 var transitionProps = 'opacity,' + toDashedAll(transformProperty); 1102 1103 proto.enableTransition = function (/* style */) { 1104 // HACK changing transitionProperty during a transition 1105 // will cause transition to jump 1106 if (this.isTransitioning) { 1107 return; 1108 } 1109 1110 // make `transition: foo, bar, baz` from style object 1111 // HACK un-comment this when enableTransition can work 1112 // while a transition is happening 1113 // var transitionValues = []; 1114 // for ( var prop in style ) { 1115 // // dash-ify camelCased properties like WebkitTransition 1116 // prop = vendorProperties[ prop ] || prop; 1117 // transitionValues.push( toDashedAll( prop ) ); 1118 // } 1119 // munge number to millisecond, to match stagger 1120 var duration = this.layout.options.transitionDuration; 1121 duration = typeof duration == 'number' ? duration + 'ms' : duration; 1122 // enable transition styles 1123 this.css({ 1124 transitionProperty: transitionProps, 1125 transitionDuration: duration, 1126 transitionDelay : this.staggerDelay || 0 1127 }); 1128 // listen for transition end event 1129 this.element.addEventListener(transitionEndEvent, this, false); 1130 }; 1131 1132// ----- events ----- // 1133 1134 proto.onwebkitTransitionEnd = function (event) { 1135 this.ontransitionend(event); 1136 }; 1137 1138 proto.onotransitionend = function (event) { 1139 this.ontransitionend(event); 1140 }; 1141 1142// properties that I munge to make my life easier 1143 var dashedVendorProperties = { 1144 '-webkit-transform': 'transform' 1145 }; 1146 1147 proto.ontransitionend = function (event) { 1148 // disregard bubbled events from children 1149 if (event.target !== this.element) { 1150 return; 1151 } 1152 var _transition = this._transn; 1153 // get property name of transitioned property, convert to prefix-free 1154 var propertyName = dashedVendorProperties[event.propertyName] || event.propertyName; 1155 1156 // remove property that has completed transitioning 1157 delete _transition.ingProperties[propertyName]; 1158 // check if any properties are still transitioning 1159 if (isEmptyObj(_transition.ingProperties)) { 1160 // all properties have completed transitioning 1161 this.disableTransition(); 1162 } 1163 // clean style 1164 if (propertyName in _transition.clean) { 1165 // clean up style 1166 this.element.style[event.propertyName] = ''; 1167 delete _transition.clean[propertyName]; 1168 } 1169 // trigger onTransitionEnd callback 1170 if (propertyName in _transition.onEnd) { 1171 var onTransitionEnd = _transition.onEnd[propertyName]; 1172 onTransitionEnd.call(this); 1173 delete _transition.onEnd[propertyName]; 1174 } 1175 1176 this.emitEvent('transitionEnd', [this]); 1177 }; 1178 1179 proto.disableTransition = function () { 1180 this.removeTransitionStyles(); 1181 this.element.removeEventListener(transitionEndEvent, this, false); 1182 this.isTransitioning = false; 1183 }; 1184 1185 /** 1186 * removes style property from element 1187 * @param {Object} style 1188 **/ 1189 proto._removeStyles = function (style) { 1190 // clean up transition styles 1191 var cleanStyle = {}; 1192 for (var prop in style) { 1193 cleanStyle[prop] = ''; 1194 } 1195 this.css(cleanStyle); 1196 }; 1197 1198 var cleanTransitionStyle = { 1199 transitionProperty: '', 1200 transitionDuration: '', 1201 transitionDelay : '' 1202 }; 1203 1204 proto.removeTransitionStyles = function () { 1205 // remove transition 1206 this.css(cleanTransitionStyle); 1207 }; 1208 1209// ----- stagger ----- // 1210 1211 proto.stagger = function (delay) { 1212 delay = isNaN(delay) ? 0 : delay; 1213 this.staggerDelay = delay + 'ms'; 1214 }; 1215 1216// ----- show/hide/remove ----- // 1217 1218// remove element from DOM 1219 proto.removeElem = function () { 1220 this.element.parentNode.removeChild(this.element); 1221 // remove display: none 1222 this.css({display: ''}); 1223 this.emitEvent('remove', [this]); 1224 }; 1225 1226 proto.remove = function () { 1227 // just remove element if no transition support or no transition 1228 if (!transitionProperty || !parseFloat(this.layout.options.transitionDuration)) { 1229 this.removeElem(); 1230 return; 1231 } 1232 1233 // start transition 1234 this.once('transitionEnd', function () { 1235 this.removeElem(); 1236 }); 1237 this.hide(); 1238 }; 1239 1240 proto.reveal = function () { 1241 delete this.isHidden; 1242 // remove display: none 1243 this.css({display: ''}); 1244 1245 var options = this.layout.options; 1246 1247 var onTransitionEnd = {}; 1248 var transitionEndProperty = this.getHideRevealTransitionEndProperty('visibleStyle'); 1249 onTransitionEnd[transitionEndProperty] = this.onRevealTransitionEnd; 1250 1251 this.transition({ 1252 from : options.hiddenStyle, 1253 to : options.visibleStyle, 1254 isCleaning : true, 1255 onTransitionEnd: onTransitionEnd 1256 }); 1257 }; 1258 1259 proto.onRevealTransitionEnd = function () { 1260 // check if still visible 1261 // during transition, item may have been hidden 1262 if (!this.isHidden) { 1263 this.emitEvent('reveal'); 1264 } 1265 }; 1266 1267 /** 1268 * get style property use for hide/reveal transition end 1269 * @param {String} styleProperty - hiddenStyle/visibleStyle 1270 * @returns {String} 1271 */ 1272 proto.getHideRevealTransitionEndProperty = function (styleProperty) { 1273 var optionStyle = this.layout.options[styleProperty]; 1274 // use opacity 1275 if (optionStyle.opacity) { 1276 return 'opacity'; 1277 } 1278 // get first property 1279 for (var prop in optionStyle) { 1280 return prop; 1281 } 1282 }; 1283 1284 proto.hide = function () { 1285 // set flag 1286 this.isHidden = true; 1287 // remove display: none 1288 this.css({display: ''}); 1289 1290 var options = this.layout.options; 1291 1292 var onTransitionEnd = {}; 1293 var transitionEndProperty = this.getHideRevealTransitionEndProperty('hiddenStyle'); 1294 onTransitionEnd[transitionEndProperty] = this.onHideTransitionEnd; 1295 1296 this.transition({ 1297 from : options.visibleStyle, 1298 to : options.hiddenStyle, 1299 // keep hidden stuff hidden 1300 isCleaning : true, 1301 onTransitionEnd: onTransitionEnd 1302 }); 1303 }; 1304 1305 proto.onHideTransitionEnd = function () { 1306 // check if still hidden 1307 // during transition, item may have been un-hidden 1308 if (this.isHidden) { 1309 this.css({display: 'none'}); 1310 this.emitEvent('hide'); 1311 } 1312 }; 1313 1314 proto.destroy = function () { 1315 this.css({ 1316 position : '', 1317 left : '', 1318 right : '', 1319 top : '', 1320 bottom : '', 1321 transition: '', 1322 transform : '' 1323 }); 1324 }; 1325 1326 return Item; 1327 1328})); 1329 1330/*! 1331 * Outlayer v2.1.0 1332 * the brains and guts of a layout library 1333 * MIT license 1334 */ 1335 1336(function (window, factory) { 1337 'use strict'; 1338 // universal module definition 1339 /* jshint strict: false */ 1340 /* globals define, module, require */ 1341 if (typeof define == 'function' && define.amd) { 1342 // AMD - RequireJS 1343 define('outlayer/outlayer', [ 1344 'ev-emitter/ev-emitter', 1345 'get-size/get-size', 1346 'fizzy-ui-utils/utils', 1347 './item' 1348 ], 1349 function (EvEmitter, getSize, utils, Item) { 1350 return factory(window, EvEmitter, getSize, utils, Item); 1351 } 1352 ); 1353 } else if (typeof module == 'object' && module.exports) { 1354 // CommonJS - Browserify, Webpack 1355 module.exports = factory( 1356 window, 1357 require('ev-emitter'), 1358 require('get-size'), 1359 require('fizzy-ui-utils'), 1360 require('./item') 1361 ); 1362 } else { 1363 // browser global 1364 window.Outlayer = factory( 1365 window, 1366 window.EvEmitter, 1367 window.getSize, 1368 window.fizzyUIUtils, 1369 window.Outlayer.Item 1370 ); 1371 } 1372 1373}(window, function factory(window, EvEmitter, getSize, utils, Item) { 1374 'use strict'; 1375 1376// ----- vars ----- // 1377 1378 var console = window.console; 1379 var jQuery = window.jQuery; 1380 var noop = function () { 1381 }; 1382 1383// -------------------------- Outlayer -------------------------- // 1384 1385// globally unique identifiers 1386 var GUID = 0; 1387// internal store of all Outlayer intances 1388 var instances = {}; 1389 1390 1391 /** 1392 * @param {Element, String} element 1393 * @param {Object} options 1394 * @constructor 1395 */ 1396 function Outlayer(element, options) { 1397 var queryElement = utils.getQueryElement(element); 1398 if (!queryElement) { 1399 if (console) { 1400 console.error('Bad element for ' + this.constructor.namespace + 1401 ': ' + (queryElement || element)); 1402 } 1403 return; 1404 } 1405 this.element = queryElement; 1406 // add jQuery 1407 if (jQuery) { 1408 this.$element = jQuery(this.element); 1409 } 1410 1411 // options 1412 this.options = utils.extend({}, this.constructor.defaults); 1413 this.option(options); 1414 1415 // add id for Outlayer.getFromElement 1416 var id = ++GUID; 1417 this.element.outlayerGUID = id; // expando 1418 instances[id] = this; // associate via id 1419 1420 // kick it off 1421 this._create(); 1422 1423 var isInitLayout = this._getOption('initLayout'); 1424 if (isInitLayout) { 1425 this.layout(); 1426 } 1427 } 1428 1429// settings are for internal use only 1430 Outlayer.namespace = 'outlayer'; 1431 Outlayer.Item = Item; 1432 1433// default options 1434 Outlayer.defaults = { 1435 containerStyle : { 1436 position: 'relative' 1437 }, 1438 initLayout : true, 1439 originLeft : true, 1440 originTop : true, 1441 resize : true, 1442 resizeContainer : true, 1443 // item options 1444 transitionDuration: '0.4s', 1445 hiddenStyle : { 1446 opacity : 0, 1447 transform: 'scale(0.001)' 1448 }, 1449 visibleStyle : { 1450 opacity : 1, 1451 transform: 'scale(1)' 1452 } 1453 }; 1454 1455 var proto = Outlayer.prototype; 1456// inherit EvEmitter 1457 utils.extend(proto, EvEmitter.prototype); 1458 1459 /** 1460 * set options 1461 * @param {Object} opts 1462 */ 1463 proto.option = function (opts) { 1464 utils.extend(this.options, opts); 1465 }; 1466 1467 /** 1468 * get backwards compatible option value, check old name 1469 */ 1470 proto._getOption = function (option) { 1471 var oldOption = this.constructor.compatOptions[option]; 1472 return oldOption && this.options[oldOption] !== undefined ? 1473 this.options[oldOption] : this.options[option]; 1474 }; 1475 1476 Outlayer.compatOptions = { 1477 // currentName: oldName 1478 initLayout : 'isInitLayout', 1479 horizontal : 'isHorizontal', 1480 layoutInstant : 'isLayoutInstant', 1481 originLeft : 'isOriginLeft', 1482 originTop : 'isOriginTop', 1483 resize : 'isResizeBound', 1484 resizeContainer: 'isResizingContainer' 1485 }; 1486 1487 proto._create = function () { 1488 // get items from children 1489 this.reloadItems(); 1490 // elements that affect layout, but are not laid out 1491 this.stamps = []; 1492 this.stamp(this.options.stamp); 1493 // set container style 1494 utils.extend(this.element.style, this.options.containerStyle); 1495 1496 // bind resize method 1497 var canBindResize = this._getOption('resize'); 1498 if (canBindResize) { 1499 this.bindResize(); 1500 } 1501 }; 1502 1503// goes through all children again and gets bricks in proper order 1504 proto.reloadItems = function () { 1505 // collection of item elements 1506 this.items = this._itemize(this.element.children); 1507 }; 1508 1509 1510 /** 1511 * turn elements into Outlayer.Items to be used in layout 1512 * @param {Array or NodeList or HTMLElement} elems 1513 * @returns {Array} items - collection of new Outlayer Items 1514 */ 1515 proto._itemize = function (elems) { 1516 1517 var itemElems = this._filterFindItemElements(elems); 1518 var Item = this.constructor.Item; 1519 1520 // create new Outlayer Items for collection 1521 var items = []; 1522 for (var i = 0; i < itemElems.length; i++) { 1523 var elem = itemElems[i]; 1524 var item = new Item(elem, this); 1525 items.push(item); 1526 } 1527 1528 return items; 1529 }; 1530 1531 /** 1532 * get item elements to be used in layout 1533 * @param {Array or NodeList or HTMLElement} elems 1534 * @returns {Array} items - item elements 1535 */ 1536 proto._filterFindItemElements = function (elems) { 1537 return utils.filterFindElements(elems, this.options.itemSelector); 1538 }; 1539 1540 /** 1541 * getter method for getting item elements 1542 * @returns {Array} elems - collection of item elements 1543 */ 1544 proto.getItemElements = function () { 1545 return this.items.map(function (item) { 1546 return item.element; 1547 }); 1548 }; 1549 1550// ----- init & layout ----- // 1551 1552 /** 1553 * lays out all items 1554 */ 1555 proto.layout = function () { 1556 this._resetLayout(); 1557 this._manageStamps(); 1558 1559 // don't animate first layout 1560 var layoutInstant = this._getOption('layoutInstant'); 1561 var isInstant = layoutInstant !== undefined ? 1562 layoutInstant : !this._isLayoutInited; 1563 this.layoutItems(this.items, isInstant); 1564 1565 // flag for initalized 1566 this._isLayoutInited = true; 1567 }; 1568 1569// _init is alias for layout 1570 proto._init = proto.layout; 1571 1572 /** 1573 * logic before any new layout 1574 */ 1575 proto._resetLayout = function () {
vendor: 13,397 bytes, lines 1576-2146
1576 this.getSize(); 1577 }; 1578 1579 1580 proto.getSize = function () { 1581 this.size = getSize(this.element); 1582 }; 1583 1584 /** 1585 * get measurement from option, for columnWidth, rowHeight, gutter 1586 * if option is String -> get element from selector string, & get size of element 1587 * if option is Element -> get size of element 1588 * else use option as a number 1589 * 1590 * @param {String} measurement 1591 * @param {String} size - width or height 1592 * @private 1593 */ 1594 proto._getMeasurement = function (measurement, size) { 1595 var option = this.options[measurement]; 1596 var elem; 1597 if (!option) { 1598 // default to 0 1599 this[measurement] = 0; 1600 } else { 1601 // use option as an element 1602 if (typeof option == 'string') { 1603 elem = this.element.querySelector(option); 1604 } else if (option instanceof HTMLElement) { 1605 elem = option; 1606 } 1607 // use size of element, if element 1608 this[measurement] = elem ? getSize(elem)[size] : option; 1609 } 1610 }; 1611 1612 /** 1613 * layout a collection of item elements 1614 * @api public 1615 */ 1616 proto.layoutItems = function (items, isInstant) { 1617 items = this._getItemsForLayout(items); 1618 1619 this._layoutItems(items, isInstant); 1620 1621 this._postLayout(); 1622 }; 1623 1624 /** 1625 * get the items to be laid out 1626 * you may want to skip over some items 1627 * @param {Array} items 1628 * @returns {Array} items 1629 */ 1630 proto._getItemsForLayout = function (items) { 1631 return items.filter(function (item) { 1632 return !item.isIgnored; 1633 }); 1634 }; 1635 1636 /** 1637 * layout items 1638 * @param {Array} items 1639 * @param {Boolean} isInstant 1640 */ 1641 proto._layoutItems = function (items, isInstant) { 1642 this._emitCompleteOnItems('layout', items); 1643 1644 if (!items || !items.length) { 1645 // no items, emit event with empty array 1646 return; 1647 } 1648 1649 var queue = []; 1650 1651 items.forEach(function (item) { 1652 // get x/y object from method 1653 var position = this._getItemLayoutPosition(item); 1654 // enqueue 1655 position.item = item; 1656 position.isInstant = isInstant || item.isLayoutInstant; 1657 queue.push(position); 1658 }, this); 1659 1660 this._processLayoutQueue(queue); 1661 }; 1662 1663 /** 1664 * get item layout position 1665 * @param {Outlayer.Item} item 1666 * @returns {Object} x and y position 1667 */ 1668 proto._getItemLayoutPosition = function (/* item */) { 1669 return { 1670 x: 0, 1671 y: 0 1672 }; 1673 }; 1674 1675 /** 1676 * iterate over array and position each item 1677 * Reason being - separating this logic prevents 'layout invalidation' 1678 * thx @paul_irish 1679 * @param {Array} queue 1680 */ 1681 proto._processLayoutQueue = function (queue) { 1682 this.updateStagger(); 1683 queue.forEach(function (obj, i) { 1684 this._positionItem(obj.item, obj.x, obj.y, obj.isInstant, i); 1685 }, this); 1686 }; 1687 1688// set stagger from option in milliseconds number 1689 proto.updateStagger = function () { 1690 var stagger = this.options.stagger; 1691 if (stagger === null || stagger === undefined) { 1692 this.stagger = 0; 1693 return; 1694 } 1695 this.stagger = getMilliseconds(stagger); 1696 return this.stagger; 1697 }; 1698 1699 /** 1700 * Sets position of item in DOM 1701 * @param {Outlayer.Item} item 1702 * @param {Number} x - horizontal position 1703 * @param {Number} y - vertical position 1704 * @param {Boolean} isInstant - disables transitions 1705 */ 1706 proto._positionItem = function (item, x, y, isInstant, i) { 1707 if (isInstant) { 1708 // if not transition, just set CSS 1709 item.goTo(x, y); 1710 } else { 1711 item.stagger(i * this.stagger); 1712 item.moveTo(x, y); 1713 } 1714 }; 1715 1716 /** 1717 * Any logic you want to do after each layout, 1718 * i.e. size the container 1719 */ 1720 proto._postLayout = function () { 1721 this.resizeContainer(); 1722 }; 1723 1724 proto.resizeContainer = function () { 1725 var isResizingContainer = this._getOption('resizeContainer'); 1726 if (!isResizingContainer) { 1727 return; 1728 } 1729 var size = this._getContainerSize(); 1730 if (size) { 1731 this._setContainerMeasure(size.width, true); 1732 this._setContainerMeasure(size.height, false); 1733 } 1734 }; 1735 1736 /** 1737 * Sets width or height of container if returned 1738 * @returns {Object} size 1739 * @param {Number} width 1740 * @param {Number} height 1741 */ 1742 proto._getContainerSize = noop; 1743 1744 /** 1745 * @param {Number} measure - size of width or height 1746 * @param {Boolean} isWidth 1747 */ 1748 proto._setContainerMeasure = function (measure, isWidth) { 1749 if (measure === undefined) { 1750 return; 1751 } 1752 1753 var elemSize = this.size; 1754 // add padding and border width if border box 1755 if (elemSize.isBorderBox) { 1756 measure += isWidth ? elemSize.paddingLeft + elemSize.paddingRight + 1757 elemSize.borderLeftWidth + elemSize.borderRightWidth : 1758 elemSize.paddingBottom + elemSize.paddingTop + 1759 elemSize.borderTopWidth + elemSize.borderBottomWidth; 1760 } 1761 1762 measure = Math.max(measure, 0); 1763 this.element.style[isWidth ? 'width' : 'height'] = measure + 'px'; 1764 }; 1765 1766 /** 1767 * emit eventComplete on a collection of items events 1768 * @param {String} eventName 1769 * @param {Array} items - Outlayer.Items 1770 */ 1771 proto._emitCompleteOnItems = function (eventName, items) { 1772 var _this = this; 1773 1774 function onComplete() { 1775 _this.dispatchEvent(eventName + 'Complete', null, [items]); 1776 } 1777 1778 var count = items.length; 1779 if (!items || !count) { 1780 onComplete(); 1781 return; 1782 } 1783 1784 var doneCount = 0; 1785 1786 function tick() { 1787 doneCount++; 1788 if (doneCount == count) { 1789 onComplete(); 1790 } 1791 } 1792 1793 // bind callback 1794 items.forEach(function (item) { 1795 item.once(eventName, tick); 1796 }); 1797 }; 1798 1799 /** 1800 * emits events via EvEmitter and jQuery events 1801 * @param {String} type - name of event 1802 * @param {Event} event - original event 1803 * @param {Array} args - extra arguments 1804 */ 1805 proto.dispatchEvent = function (type, event, args) { 1806 // add original event to arguments 1807 var emitArgs = event ? [event].concat(args) : args; 1808 this.emitEvent(type, emitArgs); 1809 1810 if (jQuery) { 1811 // set this.$element 1812 this.$element = this.$element || jQuery(this.element); 1813 if (event) { 1814 // create jQuery event 1815 var $event = jQuery.Event(event); 1816 $event.type = type; 1817 this.$element.trigger($event, args); 1818 } else { 1819 // just trigger with type if no event available 1820 this.$element.trigger(type, args); 1821 } 1822 } 1823 }; 1824 1825// -------------------------- ignore & stamps -------------------------- // 1826 1827 1828 /** 1829 * keep item in collection, but do not lay it out 1830 * ignored items do not get skipped in layout 1831 * @param {Element} elem 1832 */ 1833 proto.ignore = function (elem) { 1834 var item = this.getItem(elem); 1835 if (item) { 1836 item.isIgnored = true; 1837 } 1838 }; 1839 1840 /** 1841 * return item to layout collection 1842 * @param {Element} elem 1843 */ 1844 proto.unignore = function (elem) { 1845 var item = this.getItem(elem); 1846 if (item) { 1847 delete item.isIgnored; 1848 } 1849 }; 1850 1851 /** 1852 * adds elements to stamps 1853 * @param {NodeList, Array, Element, or String} elems 1854 */ 1855 proto.stamp = function (elems) { 1856 elems = this._find(elems); 1857 if (!elems) { 1858 return; 1859 } 1860 1861 this.stamps = this.stamps.concat(elems); 1862 // ignore 1863 elems.forEach(this.ignore, this); 1864 }; 1865 1866 /** 1867 * removes elements to stamps 1868 * @param {NodeList, Array, or Element} elems 1869 */ 1870 proto.unstamp = function (elems) { 1871 elems = this._find(elems); 1872 if (!elems) { 1873 return; 1874 } 1875 1876 elems.forEach(function (elem) { 1877 // filter out removed stamp elements 1878 utils.removeFrom(this.stamps, elem); 1879 this.unignore(elem); 1880 }, this); 1881 }; 1882 1883 /** 1884 * finds child elements 1885 * @param {NodeList, Array, Element, or String} elems 1886 * @returns {Array} elems 1887 */ 1888 proto._find = function (elems) { 1889 if (!elems) { 1890 return; 1891 } 1892 // if string, use argument as selector string 1893 if (typeof elems == 'string') { 1894 elems = this.element.querySelectorAll(elems); 1895 } 1896 elems = utils.makeArray(elems); 1897 return elems; 1898 }; 1899 1900 proto._manageStamps = function () { 1901 if (!this.stamps || !this.stamps.length) { 1902 return; 1903 } 1904 1905 this._getBoundingRect(); 1906 1907 this.stamps.forEach(this._manageStamp, this); 1908 }; 1909 1910// update boundingLeft / Top 1911 proto._getBoundingRect = function () { 1912 // get bounding rect for container element 1913 var boundingRect = this.element.getBoundingClientRect(); 1914 var size = this.size; 1915 this._boundingRect = { 1916 left : boundingRect.left + size.paddingLeft + size.borderLeftWidth, 1917 top : boundingRect.top + size.paddingTop + size.borderTopWidth, 1918 right : boundingRect.right - (size.paddingRight + size.borderRightWidth), 1919 bottom: boundingRect.bottom - (size.paddingBottom + size.borderBottomWidth) 1920 }; 1921 }; 1922 1923 /** 1924 * @param {Element} stamp 1925 **/ 1926 proto._manageStamp = noop; 1927 1928 /** 1929 * get x/y position of element relative to container element 1930 * @param {Element} elem 1931 * @returns {Object} offset - has left, top, right, bottom 1932 */ 1933 proto._getElementOffset = function (elem) { 1934 var boundingRect = elem.getBoundingClientRect(); 1935 var thisRect = this._boundingRect; 1936 var size = getSize(elem); 1937 var offset = { 1938 left : boundingRect.left - thisRect.left - size.marginLeft, 1939 top : boundingRect.top - thisRect.top - size.marginTop, 1940 right : thisRect.right - boundingRect.right - size.marginRight, 1941 bottom: thisRect.bottom - boundingRect.bottom - size.marginBottom 1942 }; 1943 return offset; 1944 }; 1945 1946// -------------------------- resize -------------------------- // 1947 1948// enable event handlers for listeners 1949// i.e. resize -> onresize 1950 proto.handleEvent = utils.handleEvent; 1951 1952 /** 1953 * Bind layout to window resizing 1954 */ 1955 proto.bindResize = function () { 1956 window.addEventListener('resize', this); 1957 this.isResizeBound = true; 1958 }; 1959 1960 /** 1961 * Unbind layout to window resizing 1962 */ 1963 proto.unbindResize = function () { 1964 window.removeEventListener('resize', this); 1965 this.isResizeBound = false; 1966 }; 1967 1968 proto.onresize = function () { 1969 this.resize(); 1970 }; 1971 1972 utils.debounceMethod(Outlayer, 'onresize', 100); 1973 1974 proto.resize = function () { 1975 // don't trigger if size did not change 1976 // or if resize was unbound. See #9 1977 if (!this.isResizeBound || !this.needsResizeLayout()) { 1978 return; 1979 } 1980 1981 this.layout(); 1982 }; 1983 1984 /** 1985 * check if layout is needed post layout 1986 * @returns Boolean 1987 */ 1988 proto.needsResizeLayout = function () { 1989 var size = getSize(this.element); 1990 // check that this.size and size are there 1991 // IE8 triggers resize on body size change, so they might not be 1992 var hasSizes = this.size && size; 1993 return hasSizes && size.innerWidth !== this.size.innerWidth; 1994 }; 1995 1996// -------------------------- methods -------------------------- // 1997 1998 /** 1999 * add items to Outlayer instance 2000 * @param {Array or NodeList or Element} elems 2001 * @returns {Array} items - Outlayer.Items 2002 **/ 2003 proto.addItems = function (elems) { 2004 var items = this._itemize(elems); 2005 // add items to collection 2006 if (items.length) { 2007 this.items = this.items.concat(items); 2008 } 2009 return items; 2010 }; 2011 2012 /** 2013 * Layout newly-appended item elements 2014 * @param {Array or NodeList or Element} elems 2015 */ 2016 proto.appended = function (elems) { 2017 var items = this.addItems(elems); 2018 if (!items.length) { 2019 return; 2020 } 2021 // layout and reveal just the new items 2022 this.layoutItems(items, true); 2023 this.reveal(items); 2024 }; 2025 2026 /** 2027 * Layout prepended elements 2028 * @param {Array or NodeList or Element} elems 2029 */ 2030 proto.prepended = function (elems) { 2031 var items = this._itemize(elems); 2032 if (!items.length) { 2033 return; 2034 } 2035 // add items to beginning of collection 2036 var previousItems = this.items.slice(0); 2037 this.items = items.concat(previousItems); 2038 // start new layout 2039 this._resetLayout(); 2040 this._manageStamps(); 2041 // layout new stuff without transition 2042 this.layoutItems(items, true); 2043 this.reveal(items); 2044 // layout previous items 2045 this.layoutItems(previousItems); 2046 }; 2047 2048 /** 2049 * reveal a collection of items 2050 * @param {Array of Outlayer.Items} items 2051 */ 2052 proto.reveal = function (items) { 2053 this._emitCompleteOnItems('reveal', items); 2054 if (!items || !items.length) { 2055 return; 2056 } 2057 var stagger = this.updateStagger(); 2058 items.forEach(function (item, i) { 2059 item.stagger(i * stagger); 2060 item.reveal(); 2061 }); 2062 }; 2063 2064 /** 2065 * hide a collection of items 2066 * @param {Array of Outlayer.Items} items 2067 */ 2068 proto.hide = function (items) { 2069 this._emitCompleteOnItems('hide', items); 2070 if (!items || !items.length) { 2071 return; 2072 } 2073 var stagger = this.updateStagger(); 2074 items.forEach(function (item, i) { 2075 item.stagger(i * stagger); 2076 item.hide(); 2077 }); 2078 }; 2079 2080 /** 2081 * reveal item elements 2082 * @param {Array}, {Element}, {NodeList} items 2083 */ 2084 proto.revealItemElements = function (elems) { 2085 var items = this.getItems(elems); 2086 this.reveal(items); 2087 }; 2088 2089 /** 2090 * hide item elements 2091 * @param {Array}, {Element}, {NodeList} items 2092 */ 2093 proto.hideItemElements = function (elems) { 2094 var items = this.getItems(elems); 2095 this.hide(items); 2096 }; 2097 2098 /** 2099 * get Outlayer.Item, given an Element 2100 * @param {Element} elem 2101 * @param {Function} callback 2102 * @returns {Outlayer.Item} item 2103 */ 2104 proto.getItem = function (elem) { 2105 // loop through items to get the one that matches 2106 for (var i = 0; i < this.items.length; i++) { 2107 var item = this.items[i]; 2108 if (item.element == elem) { 2109 // return item 2110 return item; 2111 } 2112 } 2113 }; 2114 2115 /** 2116 * get collection of Outlayer.Items, given Elements 2117 * @param {Array} elems 2118 * @returns {Array} items - Outlayer.Items 2119 */ 2120 proto.getItems = function (elems) { 2121 elems = utils.makeArray(elems); 2122 var items = []; 2123 elems.forEach(function (elem) { 2124 var item = this.getItem(elem); 2125 if (item) { 2126 items.push(item); 2127 } 2128 }, this); 2129 2130 return items; 2131 }; 2132 2133 /** 2134 * remove element(s) from instance and DOM 2135 * @param {Array or NodeList or Element} elems 2136 */ 2137 proto.remove = function (elems) { 2138 var removeItems = this.getItems(elems); 2139 2140 this._emitCompleteOnItems('remove', removeItems); 2141 2142 // bail if no items to remove 2143 if (!removeItems || !removeItems.length) { 2144 return; 2145 } 2146
vendor: 24,063 bytes, lines 2147-3126
2147 removeItems.forEach(function (item) { 2148 item.remove(); 2149 // remove item from collection 2150 utils.removeFrom(this.items, item); 2151 }, this); 2152 }; 2153 2154// ----- destroy ----- // 2155 2156// remove and disable Outlayer instance 2157 proto.destroy = function () { 2158 // clean up dynamic styles 2159 var style = this.element.style; 2160 style.height = ''; 2161 style.position = ''; 2162 style.width = ''; 2163 // destroy items 2164 this.items.forEach(function (item) { 2165 item.destroy(); 2166 }); 2167 2168 this.unbindResize(); 2169 2170 var id = this.element.outlayerGUID; 2171 delete instances[id]; // remove reference to instance by id 2172 delete this.element.outlayerGUID; 2173 // remove data for jQuery 2174 if (jQuery) { 2175 jQuery.removeData(this.element, this.constructor.namespace); 2176 } 2177 2178 }; 2179 2180// -------------------------- data -------------------------- // 2181 2182 /** 2183 * get Outlayer instance from element 2184 * @param {Element} elem 2185 * @returns {Outlayer} 2186 */ 2187 Outlayer.data = function (elem) { 2188 elem = utils.getQueryElement(elem); 2189 var id = elem && elem.outlayerGUID; 2190 return id && instances[id]; 2191 }; 2192 2193 2194// -------------------------- create Outlayer class -------------------------- // 2195 2196 /** 2197 * create a layout class 2198 * @param {String} namespace 2199 */ 2200 Outlayer.create = function (namespace, options) { 2201 // sub-class Outlayer 2202 var Layout = subclass(Outlayer); 2203 // apply new options and compatOptions 2204 Layout.defaults = utils.extend({}, Outlayer.defaults); 2205 utils.extend(Layout.defaults, options); 2206 Layout.compatOptions = utils.extend({}, Outlayer.compatOptions); 2207 2208 Layout.namespace = namespace; 2209 2210 Layout.data = Outlayer.data; 2211 2212 // sub-class Item 2213 Layout.Item = subclass(Item); 2214 2215 // -------------------------- declarative -------------------------- // 2216 2217 utils.htmlInit(Layout, namespace); 2218 2219 // -------------------------- jQuery bridge -------------------------- // 2220 2221 // make into jQuery plugin 2222 if (jQuery && jQuery.bridget) { 2223 jQuery.bridget(namespace, Layout); 2224 } 2225 2226 return Layout; 2227 }; 2228 2229 function subclass(Parent) { 2230 function SubClass() { 2231 Parent.apply(this, arguments); 2232 } 2233 2234 SubClass.prototype = Object.create(Parent.prototype); 2235 SubClass.prototype.constructor = SubClass; 2236 2237 return SubClass; 2238 } 2239 2240// ----- helpers ----- // 2241 2242// how many milliseconds are in each unit 2243 var msUnits = { 2244 ms: 1, 2245 s : 1000 2246 }; 2247 2248// munge time-like parameter into millisecond number 2249// '0.4s' -> 40 2250 function getMilliseconds(time) { 2251 if (typeof time == 'number') { 2252 return time; 2253 } 2254 var matches = time.match(/(^\d*\.?\d*)(\w*)/); 2255 var num = matches && matches[1]; 2256 var unit = matches && matches[2]; 2257 if (!num.length) { 2258 return 0; 2259 } 2260 num = parseFloat(num); 2261 var mult = msUnits[unit] || 1; 2262 return num * mult; 2263 } 2264 2265// ----- fin ----- // 2266 2267// back in global 2268 Outlayer.Item = Item; 2269 2270 return Outlayer; 2271 2272})); 2273 2274/** 2275 * Isotope Item 2276 **/ 2277 2278(function (window, factory) { 2279 // universal module definition 2280 /* jshint strict: false */ 2281 /*globals define, module, require */ 2282 if (typeof define == 'function' && define.amd) { 2283 // AMD 2284 define('isotope-layout/js/item', [ 2285 'outlayer/outlayer' 2286 ], 2287 factory); 2288 } else if (typeof module == 'object' && module.exports) { 2289 // CommonJS 2290 module.exports = factory( 2291 require('outlayer') 2292 ); 2293 } else { 2294 // browser global 2295 window.Isotope = window.Isotope || {}; 2296 window.Isotope.Item = factory( 2297 window.Outlayer 2298 ); 2299 } 2300 2301}(window, function factory(Outlayer) { 2302 'use strict'; 2303 2304// -------------------------- Item -------------------------- // 2305 2306// sub-class Outlayer Item 2307 function Item() { 2308 Outlayer.Item.apply(this, arguments); 2309 } 2310 2311 var proto = Item.prototype = Object.create(Outlayer.Item.prototype); 2312 2313 var _create = proto._create; 2314 proto._create = function () { 2315 // assign id, used for original-order sorting 2316 this.id = this.layout.itemGUID++; 2317 _create.call(this); 2318 this.sortData = {}; 2319 }; 2320 2321 proto.updateSortData = function () { 2322 if (this.isIgnored) { 2323 return; 2324 } 2325 // default sorters 2326 this.sortData.id = this.id; 2327 // for backward compatibility 2328 this.sortData['original-order'] = this.id; 2329 this.sortData.random = Math.random(); 2330 // go thru getSortData obj and apply the sorters 2331 var getSortData = this.layout.options.getSortData; 2332 var sorters = this.layout._sorters; 2333 for (var key in getSortData) { 2334 var sorter = sorters[key]; 2335 this.sortData[key] = sorter(this.element, this); 2336 } 2337 }; 2338 2339 var _destroy = proto.destroy; 2340 proto.destroy = function () { 2341 // call super 2342 _destroy.apply(this, arguments); 2343 // reset display, #741 2344 this.css({ 2345 display: '' 2346 }); 2347 }; 2348 2349 return Item; 2350 2351})); 2352 2353/** 2354 * Isotope LayoutMode 2355 */ 2356 2357(function (window, factory) { 2358 // universal module definition 2359 /* jshint strict: false */ 2360 /*globals define, module, require */ 2361 if (typeof define == 'function' && define.amd) { 2362 // AMD 2363 define('isotope-layout/js/layout-mode', [ 2364 'get-size/get-size', 2365 'outlayer/outlayer' 2366 ], 2367 factory); 2368 } else if (typeof module == 'object' && module.exports) { 2369 // CommonJS 2370 module.exports = factory( 2371 require('get-size'), 2372 require('outlayer') 2373 ); 2374 } else { 2375 // browser global 2376 window.Isotope = window.Isotope || {}; 2377 window.Isotope.LayoutMode = factory( 2378 window.getSize, 2379 window.Outlayer 2380 ); 2381 } 2382 2383}(window, function factory(getSize, Outlayer) { 2384 'use strict'; 2385 2386 // layout mode class 2387 function LayoutMode(isotope) { 2388 this.isotope = isotope; 2389 // link properties 2390 if (isotope) { 2391 this.options = isotope.options[this.namespace]; 2392 this.element = isotope.element; 2393 this.items = isotope.filteredItems; 2394 this.size = isotope.size; 2395 } 2396 } 2397 2398 var proto = LayoutMode.prototype; 2399 2400 /** 2401 * some methods should just defer to default Outlayer method 2402 * and reference the Isotope instance as `this` 2403 **/ 2404 var facadeMethods = [ 2405 '_resetLayout', 2406 '_getItemLayoutPosition', 2407 '_manageStamp', 2408 '_getContainerSize', 2409 '_getElementOffset', 2410 'needsResizeLayout', 2411 '_getOption' 2412 ]; 2413 2414 facadeMethods.forEach(function (methodName) { 2415 proto[methodName] = function () { 2416 return Outlayer.prototype[methodName].apply(this.isotope, arguments); 2417 }; 2418 }); 2419 2420 // ----- ----- // 2421 2422 // for horizontal layout modes, check vertical size 2423 proto.needsVerticalResizeLayout = function () { 2424 // don't trigger if size did not change 2425 var size = getSize(this.isotope.element); 2426 // check that this.size and size are there 2427 // IE8 triggers resize on body size change, so they might not be 2428 var hasSizes = this.isotope.size && size; 2429 return hasSizes && size.innerHeight != this.isotope.size.innerHeight; 2430 }; 2431 2432 // ----- measurements ----- // 2433 2434 proto._getMeasurement = function () { 2435 this.isotope._getMeasurement.apply(this, arguments); 2436 }; 2437 2438 proto.getColumnWidth = function () { 2439 this.getSegmentSize('column', 'Width'); 2440 }; 2441 2442 proto.getRowHeight = function () { 2443 this.getSegmentSize('row', 'Height'); 2444 }; 2445 2446 /** 2447 * get columnWidth or rowHeight 2448 * segment: 'column' or 'row' 2449 * size 'Width' or 'Height' 2450 **/ 2451 proto.getSegmentSize = function (segment, size) { 2452 var segmentName = segment + size; 2453 var outerSize = 'outer' + size; 2454 // columnWidth / outerWidth // rowHeight / outerHeight 2455 this._getMeasurement(segmentName, outerSize); 2456 // got rowHeight or columnWidth, we can chill 2457 if (this[segmentName]) { 2458 return; 2459 } 2460 // fall back to item of first element 2461 var firstItemSize = this.getFirstItemSize(); 2462 this[segmentName] = firstItemSize && firstItemSize[outerSize] || 2463 // or size of container 2464 this.isotope.size['inner' + size]; 2465 }; 2466 2467 proto.getFirstItemSize = function () { 2468 var firstItem = this.isotope.filteredItems[0]; 2469 return firstItem && firstItem.element && getSize(firstItem.element); 2470 }; 2471 2472 // ----- methods that should reference isotope ----- // 2473 2474 proto.layout = function () { 2475 this.isotope.layout.apply(this.isotope, arguments); 2476 }; 2477 2478 proto.getSize = function () { 2479 this.isotope.getSize(); 2480 this.size = this.isotope.size; 2481 }; 2482 2483 // -------------------------- create -------------------------- // 2484 2485 LayoutMode.modes = {}; 2486 2487 LayoutMode.create = function (namespace, options) { 2488 2489 function Mode() { 2490 LayoutMode.apply(this, arguments); 2491 } 2492 2493 Mode.prototype = Object.create(proto); 2494 Mode.prototype.constructor = Mode; 2495 2496 // default options 2497 if (options) { 2498 Mode.options = options; 2499 } 2500 2501 Mode.prototype.namespace = namespace; 2502 // register in Isotope 2503 LayoutMode.modes[namespace] = Mode; 2504 2505 return Mode; 2506 }; 2507 2508 return LayoutMode; 2509 2510})); 2511 2512/*! 2513 * Masonry v4.2.1 2514 * Cascading grid layout library 2515 * https://masonry.desandro.com 2516 * MIT License 2517 * by David DeSandro 2518 */ 2519 2520(function (window, factory) { 2521 // universal module definition 2522 /* jshint strict: false */ 2523 /*globals define, module, require */ 2524 if (typeof define == 'function' && define.amd) { 2525 // AMD 2526 define('masonry-layout/masonry', [ 2527 'outlayer/outlayer', 2528 'get-size/get-size' 2529 ], 2530 factory); 2531 } else if (typeof module == 'object' && module.exports) { 2532 // CommonJS 2533 module.exports = factory( 2534 require('outlayer'), 2535 require('get-size') 2536 ); 2537 } else { 2538 // browser global 2539 window.Masonry = factory( 2540 window.Outlayer, 2541 window.getSize 2542 ); 2543 } 2544 2545}(window, function factory(Outlayer, getSize) { 2546 2547 2548 2549// -------------------------- masonryDefinition -------------------------- // 2550 2551 // create an Outlayer layout class 2552 var Masonry = Outlayer.create('masonry'); 2553 // isFitWidth -> fitWidth 2554 Masonry.compatOptions.fitWidth = 'isFitWidth'; 2555 2556 var proto = Masonry.prototype; 2557 2558 proto._resetLayout = function () { 2559 this.getSize(); 2560 this._getMeasurement('columnWidth', 'outerWidth'); 2561 this._getMeasurement('gutter', 'outerWidth'); 2562 this.measureColumns(); 2563 2564 // reset column Y 2565 this.colYs = []; 2566 for (var i = 0; i < this.cols; i++) { 2567 this.colYs.push(0); 2568 } 2569 2570 this.maxY = 0; 2571 this.horizontalColIndex = 0; 2572 }; 2573 2574 proto.measureColumns = function () { 2575 this.getContainerWidth(); 2576 // if columnWidth is 0, default to outerWidth of first item 2577 if (!this.columnWidth) { 2578 var firstItem = this.items[0]; 2579 var firstItemElem = firstItem && firstItem.element; 2580 // columnWidth fall back to item of first element 2581 this.columnWidth = firstItemElem && getSize(firstItemElem).outerWidth || 2582 // if first elem has no width, default to size of container 2583 this.containerWidth; 2584 } 2585 2586 var columnWidth = this.columnWidth += this.gutter; 2587 2588 // calculate columns 2589 var containerWidth = this.containerWidth + this.gutter; 2590 var cols = containerWidth / columnWidth; 2591 // fix rounding errors, typically with gutters 2592 var excess = columnWidth - containerWidth % columnWidth; 2593 // if overshoot is less than a pixel, round up, otherwise floor it 2594 var mathMethod = excess && excess < 1 ? 'round' : 'floor'; 2595 cols = Math[mathMethod](cols); 2596 this.cols = Math.max(cols, 1); 2597 }; 2598 2599 proto.getContainerWidth = function () { 2600 // container is parent if fit width 2601 var isFitWidth = this._getOption('fitWidth'); 2602 var container = isFitWidth ? this.element.parentNode : this.element; 2603 // check that this.size and size are there 2604 // IE8 triggers resize on body size change, so they might not be 2605 var size = getSize(container); 2606 this.containerWidth = size && size.innerWidth; 2607 }; 2608 2609 proto._getItemLayoutPosition = function (item) { 2610 item.getSize(); 2611 // how many columns does this brick span 2612 var remainder = item.size.outerWidth % this.columnWidth; 2613 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil'; 2614 // round if off by 1 pixel, otherwise use ceil 2615 var colSpan = Math[mathMethod](item.size.outerWidth / this.columnWidth); 2616 colSpan = Math.min(colSpan, this.cols); 2617 // use horizontal or top column position 2618 var colPosMethod = this.options.horizontalOrder ? 2619 '_getHorizontalColPosition' : '_getTopColPosition'; 2620 var colPosition = this[colPosMethod](colSpan, item); 2621 // position the brick 2622 var position = { 2623 x: this.columnWidth * colPosition.col, 2624 y: colPosition.y 2625 }; 2626 // apply setHeight to necessary columns 2627 var setHeight = colPosition.y + item.size.outerHeight; 2628 var setMax = colSpan + colPosition.col; 2629 for (var i = colPosition.col; i < setMax; i++) { 2630 this.colYs[i] = setHeight; 2631 } 2632 2633 return position; 2634 }; 2635 2636 proto._getTopColPosition = function (colSpan) { 2637 var colGroup = this._getTopColGroup(colSpan); 2638 // get the minimum Y value from the columns 2639 var minimumY = Math.min.apply(Math, colGroup); 2640 2641 return { 2642 col: colGroup.indexOf(minimumY), 2643 y : minimumY, 2644 }; 2645 }; 2646 2647 /** 2648 * @param {Number} colSpan - number of columns the element spans 2649 * @returns {Array} colGroup 2650 */ 2651 proto._getTopColGroup = function (colSpan) { 2652 if (colSpan < 2) { 2653 // if brick spans only one column, use all the column Ys 2654 return this.colYs; 2655 } 2656 2657 var colGroup = []; 2658 // how many different places could this brick fit horizontally 2659 var groupCount = this.cols + 1 - colSpan; 2660 // for each group potential horizontal position 2661 for (var i = 0; i < groupCount; i++) { 2662 colGroup[i] = this._getColGroupY(i, colSpan); 2663 } 2664 return colGroup; 2665 }; 2666 2667 proto._getColGroupY = function (col, colSpan) { 2668 if (colSpan < 2) { 2669 return this.colYs[col]; 2670 } 2671 // make an array of colY values for that one group 2672 var groupColYs = this.colYs.slice(col, col + colSpan); 2673 // and get the max value of the array 2674 return Math.max.apply(Math, groupColYs); 2675 }; 2676 2677 // get column position based on horizontal index. #873 2678 proto._getHorizontalColPosition = function (colSpan, item) { 2679 var col = this.horizontalColIndex % this.cols; 2680 var isOver = colSpan > 1 && col + colSpan > this.cols; 2681 // shift to next row if item can't fit on current row 2682 col = isOver ? 0 : col; 2683 // don't let zero-size items take up space 2684 var hasSize = item.size.outerWidth && item.size.outerHeight; 2685 this.horizontalColIndex = hasSize ? col + colSpan : this.horizontalColIndex; 2686 2687 return { 2688 col: col, 2689 y : this._getColGroupY(col, colSpan), 2690 }; 2691 }; 2692 2693 proto._manageStamp = function (stamp) { 2694 var stampSize = getSize(stamp); 2695 var offset = this._getElementOffset(stamp); 2696 // get the columns that this stamp affects 2697 var isOriginLeft = this._getOption('originLeft'); 2698 var firstX = isOriginLeft ? offset.left : offset.right; 2699 var lastX = firstX + stampSize.outerWidth; 2700 var firstCol = Math.floor(firstX / this.columnWidth); 2701 firstCol = Math.max(0, firstCol); 2702 var lastCol = Math.floor(lastX / this.columnWidth); 2703 // lastCol should not go over if multiple of columnWidth #425 2704 lastCol -= lastX % this.columnWidth ? 0 : 1; 2705 lastCol = Math.min(this.cols - 1, lastCol); 2706 // set colYs to bottom of the stamp 2707 2708 var isOriginTop = this._getOption('originTop'); 2709 var stampMaxY = (isOriginTop ? offset.top : offset.bottom) + 2710 stampSize.outerHeight; 2711 for (var i = firstCol; i <= lastCol; i++) { 2712 this.colYs[i] = Math.max(stampMaxY, this.colYs[i]); 2713 } 2714 }; 2715 2716 proto._getContainerSize = function () { 2717 this.maxY = Math.max.apply(Math, this.colYs); 2718 var size = { 2719 height: this.maxY 2720 }; 2721 2722 if (this._getOption('fitWidth')) { 2723 size.width = this._getContainerFitWidth(); 2724 } 2725 2726 return size; 2727 }; 2728 2729 proto._getContainerFitWidth = function () { 2730 var unusedCols = 0; 2731 // count unused columns 2732 var i = this.cols; 2733 while (--i) { 2734 if (this.colYs[i] !== 0) { 2735 break; 2736 } 2737 unusedCols++; 2738 } 2739 // fit container to columns that have been used 2740 return (this.cols - unusedCols) * this.columnWidth - this.gutter; 2741 }; 2742 2743 proto.needsResizeLayout = function () { 2744 var previousWidth = this.containerWidth; 2745 this.getContainerWidth(); 2746 return previousWidth != this.containerWidth; 2747 }; 2748 2749 return Masonry; 2750 2751})); 2752 2753/*! 2754 * Masonry layout mode 2755 * sub-classes Masonry 2756 * https://masonry.desandro.com 2757 */ 2758 2759(function (window, factory) { 2760 // universal module definition 2761 /* jshint strict: false */ 2762 /*globals define, module, require */ 2763 if (typeof define == 'function' && define.amd) { 2764 // AMD 2765 define('isotope-layout/js/layout-modes/masonry', [ 2766 '../layout-mode', 2767 'masonry-layout/masonry' 2768 ], 2769 factory); 2770 } else if (typeof module == 'object' && module.exports) { 2771 // CommonJS 2772 module.exports = factory( 2773 require('../layout-mode'), 2774 require('masonry-layout') 2775 ); 2776 } else { 2777 // browser global 2778 factory( 2779 window.Isotope.LayoutMode, 2780 window.Masonry 2781 ); 2782 } 2783 2784}(window, function factory(LayoutMode, Masonry) { 2785 'use strict'; 2786 2787// -------------------------- masonryDefinition -------------------------- // 2788 2789 // create an Outlayer layout class 2790 var MasonryMode = LayoutMode.create('masonry'); 2791 2792 var proto = MasonryMode.prototype; 2793 2794 var keepModeMethods = { 2795 _getElementOffset: true, 2796 layout : true, 2797 _getMeasurement : true 2798 }; 2799 2800 // inherit Masonry prototype 2801 for (var method in Masonry.prototype) { 2802 // do not inherit mode methods 2803 if (!keepModeMethods[method]) { 2804 proto[method] = Masonry.prototype[method]; 2805 } 2806 } 2807 2808 var measureColumns = proto.measureColumns; 2809 proto.measureColumns = function () { 2810 // set items, used if measuring first item 2811 this.items = this.isotope.filteredItems; 2812 measureColumns.call(this); 2813 }; 2814 2815 // point to mode options for fitWidth 2816 var _getOption = proto._getOption; 2817 proto._getOption = function (option) { 2818 if (option == 'fitWidth') { 2819 return this.options.isFitWidth !== undefined ? 2820 this.options.isFitWidth : this.options.fitWidth; 2821 } 2822 return _getOption.apply(this.isotope, arguments); 2823 }; 2824 2825 return MasonryMode; 2826 2827})); 2828 2829/** 2830 * fitRows layout mode 2831 */ 2832 2833(function (window, factory) { 2834 // universal module definition 2835 /* jshint strict: false */ 2836 /*globals define, module, require */ 2837 if (typeof define == 'function' && define.amd) { 2838 // AMD 2839 define('isotope-layout/js/layout-modes/fit-rows', [ 2840 '../layout-mode' 2841 ], 2842 factory); 2843 } else if (typeof exports == 'object') { 2844 // CommonJS 2845 module.exports = factory( 2846 require('../layout-mode') 2847 ); 2848 } else { 2849 // browser global 2850 factory( 2851 window.Isotope.LayoutMode 2852 ); 2853 } 2854 2855}(window, function factory(LayoutMode) { 2856 'use strict'; 2857 2858 var FitRows = LayoutMode.create('fitRows'); 2859 2860 var proto = FitRows.prototype; 2861 2862 proto._resetLayout = function () { 2863 this.x = 0; 2864 this.y = 0; 2865 this.maxY = 0; 2866 this._getMeasurement('gutter', 'outerWidth'); 2867 }; 2868 2869 proto._getItemLayoutPosition = function (item) { 2870 item.getSize(); 2871 2872 var itemWidth = item.size.outerWidth + this.gutter; 2873 // if this element cannot fit in the current row 2874 var containerWidth = this.isotope.size.innerWidth + this.gutter; 2875 if (this.x !== 0 && itemWidth + this.x > containerWidth) { 2876 this.x = 0; 2877 this.y = this.maxY; 2878 } 2879 2880 var position = { 2881 x: this.x, 2882 y: this.y 2883 }; 2884 2885 this.maxY = Math.max(this.maxY, this.y + item.size.outerHeight); 2886 this.x += itemWidth; 2887 2888 return position; 2889 }; 2890 2891 proto._getContainerSize = function () { 2892 return {height: this.maxY}; 2893 }; 2894 2895 return FitRows; 2896 2897})); 2898 2899/** 2900 * vertical layout mode 2901 */ 2902 2903(function (window, factory) { 2904 // universal module definition 2905 /* jshint strict: false */ 2906 /*globals define, module, require */ 2907 if (typeof define == 'function' && define.amd) { 2908 // AMD 2909 define('isotope-layout/js/layout-modes/vertical', [ 2910 '../layout-mode' 2911 ], 2912 factory); 2913 } else if (typeof module == 'object' && module.exports) { 2914 // CommonJS 2915 module.exports = factory( 2916 require('../layout-mode') 2917 ); 2918 } else { 2919 // browser global 2920 factory( 2921 window.Isotope.LayoutMode 2922 ); 2923 } 2924 2925}(window, function factory(LayoutMode) { 2926 'use strict'; 2927 2928 var Vertical = LayoutMode.create('vertical', { 2929 horizontalAlignment: 0 2930 }); 2931 2932 var proto = Vertical.prototype; 2933 2934 proto._resetLayout = function () { 2935 this.y = 0; 2936 }; 2937 2938 proto._getItemLayoutPosition = function (item) { 2939 item.getSize(); 2940 var x = (this.isotope.size.innerWidth - item.size.outerWidth) * 2941 this.options.horizontalAlignment; 2942 var y = this.y; 2943 this.y += item.size.outerHeight; 2944 return {x: x, y: y}; 2945 }; 2946 2947 proto._getContainerSize = function () { 2948 return {height: this.y}; 2949 }; 2950 2951 return Vertical; 2952 2953})); 2954 2955/*! 2956 * Isotope v3.0.5 2957 * 2958 * Licensed GPLv3 for open source use 2959 * or Isotope Commercial License for commercial use 2960 * 2961 * https://isotope.metafizzy.co 2962 * Copyright 2017 Metafizzy 2963 */ 2964 2965(function (window, factory) { 2966 // universal module definition 2967 /* jshint strict: false */ 2968 /*globals define, module, require */ 2969 if (typeof define == 'function' && define.amd) { 2970 // AMD 2971 define([ 2972 'outlayer/outlayer', 2973 'get-size/get-size', 2974 'desandro-matches-selector/matches-selector', 2975 'fizzy-ui-utils/utils', 2976 'isotope-layout/js/item', 2977 'isotope-layout/js/layout-mode', 2978 // include default layout modes 2979 'isotope-layout/js/layout-modes/masonry', 2980 'isotope-layout/js/layout-modes/fit-rows', 2981 'isotope-layout/js/layout-modes/vertical' 2982 ], 2983 function (Outlayer, getSize, matchesSelector, utils, Item, LayoutMode) { 2984 return factory(window, Outlayer, getSize, matchesSelector, utils, Item, LayoutMode); 2985 }); 2986 } else if (typeof module == 'object' && module.exports) { 2987 // CommonJS 2988 module.exports = factory( 2989 window, 2990 require('outlayer'), 2991 require('get-size'), 2992 require('desandro-matches-selector'), 2993 require('fizzy-ui-utils'), 2994 require('isotope-layout/js/item'), 2995 require('isotope-layout/js/layout-mode'), 2996 // include default layout modes 2997 require('isotope-layout/js/layout-modes/masonry'), 2998 require('isotope-layout/js/layout-modes/fit-rows'), 2999 require('isotope-layout/js/layout-modes/vertical') 3000 ); 3001 } else { 3002 // browser global 3003 window.Isotope = factory( 3004 window, 3005 window.Outlayer, 3006 window.getSize, 3007 window.matchesSelector, 3008 window.fizzyUIUtils, 3009 window.Isotope.Item, 3010 window.Isotope.LayoutMode 3011 ); 3012 } 3013 3014}(window, function factory(window, Outlayer, getSize, matchesSelector, utils, 3015 Item, LayoutMode) { 3016 3017 3018 3019// -------------------------- vars -------------------------- // 3020 3021 var jQuery = window.jQuery; 3022 3023// -------------------------- helpers -------------------------- // 3024 3025 var trim = String.prototype.trim ? 3026 function (str) { 3027 return str.trim(); 3028 } : 3029 function (str) { 3030 return str.replace(/^\s+|\s+$/g, ''); 3031 }; 3032 3033// -------------------------- isotopeDefinition -------------------------- // 3034 3035 // create an Outlayer layout class 3036 var Isotope = Outlayer.create('isotope', { 3037 layoutMode : 'masonry', 3038 isJQueryFiltering: true, 3039 sortAscending : true 3040 }); 3041 3042 Isotope.Item = Item; 3043 Isotope.LayoutMode = LayoutMode; 3044 3045 var proto = Isotope.prototype; 3046 3047 proto._create = function () { 3048 this.itemGUID = 0; 3049 // functions that sort items 3050 this._sorters = {}; 3051 this._getSorters(); 3052 // call super 3053 Outlayer.prototype._create.call(this); 3054 3055 // create layout modes 3056 this.modes = {}; 3057 // start filteredItems with all items 3058 this.filteredItems = this.items; 3059 // keep of track of sortBys 3060 this.sortHistory = ['original-order']; 3061 // create from registered layout modes 3062 for (var name in LayoutMode.modes) { 3063 this._initLayoutMode(name); 3064 } 3065 }; 3066 3067 proto.reloadItems = function () { 3068 // reset item ID counter 3069 this.itemGUID = 0; 3070 // call super 3071 Outlayer.prototype.reloadItems.call(this); 3072 }; 3073 3074 proto._itemize = function () { 3075 var items = Outlayer.prototype._itemize.apply(this, arguments); 3076 // assign ID for original-order 3077 for (var i = 0; i < items.length; i++) { 3078 var item = items[i]; 3079 item.id = this.itemGUID++; 3080 } 3081 this._updateItemsSortData(items); 3082 return items; 3083 }; 3084 3085 3086 // -------------------------- layout -------------------------- // 3087 3088 proto._initLayoutMode = function (name) { 3089 var Mode = LayoutMode.modes[name]; 3090 // set mode options 3091 // HACK extend initial options, back-fill in default options 3092 var initialOpts = this.options[name] || {}; 3093 this.options[name] = Mode.options ? 3094 utils.extend(Mode.options, initialOpts) : initialOpts; 3095 // init layout mode instance 3096 this.modes[name] = new Mode(this); 3097 }; 3098 3099 3100 proto.layout = function () { 3101 // if first time doing layout, do all magic 3102 if (!this._isLayoutInited && this._getOption('initLayout')) { 3103 this.arrange(); 3104 return; 3105 } 3106 this._layout(); 3107 }; 3108 3109 // private method to be used in layout() & magic() 3110 proto._layout = function () { 3111 // don't animate first layout 3112 var isInstant = this._getIsInstant(); 3113 // layout flow 3114 this._resetLayout(); 3115 this._manageStamps(); 3116 this.layoutItems(this.filteredItems, isInstant); 3117 3118 // flag for initalized 3119 this._isLayoutInited = true; 3120 }; 3121 3122 // filter + sort + layout 3123 proto.arrange = function (opts) { 3124 // set any options pass 3125 this.option(opts); 3126 this._getIsInstant();
vendor: 11,869 bytes, lines 3127-3578
3127 // filter, sort, and layout 3128 3129 // filter 3130 var filtered = this._filter(this.items); 3131 this.filteredItems = filtered.matches; 3132 3133 this._bindArrangeComplete(); 3134 3135 if (this._isInstant) { 3136 this._noTransition(this._hideReveal, [filtered]); 3137 } else { 3138 this._hideReveal(filtered); 3139 } 3140 3141 this._sort(); 3142 this._layout(); 3143 }; 3144 // alias to _init for main plugin method 3145 proto._init = proto.arrange; 3146 3147 proto._hideReveal = function (filtered) { 3148 this.reveal(filtered.needReveal); 3149 this.hide(filtered.needHide); 3150 }; 3151 3152 // HACK 3153 // Don't animate/transition first layout 3154 // Or don't animate/transition other layouts 3155 proto._getIsInstant = function () { 3156 var isLayoutInstant = this._getOption('layoutInstant'); 3157 var isInstant = isLayoutInstant !== undefined ? isLayoutInstant : 3158 !this._isLayoutInited; 3159 this._isInstant = isInstant; 3160 return isInstant; 3161 }; 3162 3163 // listen for layoutComplete, hideComplete and revealComplete 3164 // to trigger arrangeComplete 3165 proto._bindArrangeComplete = function () { 3166 // listen for 3 events to trigger arrangeComplete 3167 var isLayoutComplete, isHideComplete, isRevealComplete; 3168 var _this = this; 3169 3170 function arrangeParallelCallback() { 3171 if (isLayoutComplete && isHideComplete && isRevealComplete) { 3172 _this.dispatchEvent('arrangeComplete', null, [_this.filteredItems]); 3173 } 3174 } 3175 3176 this.once('layoutComplete', function () { 3177 isLayoutComplete = true; 3178 arrangeParallelCallback(); 3179 }); 3180 this.once('hideComplete', function () { 3181 isHideComplete = true; 3182 arrangeParallelCallback(); 3183 }); 3184 this.once('revealComplete', function () { 3185 isRevealComplete = true; 3186 arrangeParallelCallback(); 3187 }); 3188 }; 3189 3190 // -------------------------- filter -------------------------- // 3191 3192 proto._filter = function (items) { 3193 var filter = this.options.filter; 3194 filter = filter || '*'; 3195 var matches = []; 3196 var hiddenMatched = []; 3197 var visibleUnmatched = []; 3198 3199 var test = this._getFilterTest(filter); 3200 3201 // test each item 3202 for (var i = 0; i < items.length; i++) { 3203 var item = items[i]; 3204 if (item.isIgnored) { 3205 continue; 3206 } 3207 // add item to either matched or unmatched group 3208 var isMatched = test(item); 3209 // item.isFilterMatched = isMatched; 3210 // add to matches if its a match 3211 if (isMatched) { 3212 matches.push(item); 3213 } 3214 // add to additional group if item needs to be hidden or revealed 3215 if (isMatched && item.isHidden) { 3216 hiddenMatched.push(item); 3217 } else if (!isMatched && !item.isHidden) { 3218 visibleUnmatched.push(item); 3219 } 3220 } 3221 3222 // return collections of items to be manipulated 3223 return { 3224 matches : matches, 3225 needReveal: hiddenMatched, 3226 needHide : visibleUnmatched 3227 }; 3228 }; 3229 3230 // get a jQuery, function, or a matchesSelector test given the filter 3231 proto._getFilterTest = function (filter) { 3232 if (jQuery && this.options.isJQueryFiltering) { 3233 // use jQuery 3234 return function (item) { 3235 return jQuery(item.element).is(filter); 3236 }; 3237 } 3238 if (typeof filter == 'function') { 3239 // use filter as function 3240 return function (item) { 3241 return filter(item.element); 3242 }; 3243 } 3244 // default, use filter as selector string 3245 return function (item) { 3246 return matchesSelector(item.element, filter); 3247 }; 3248 }; 3249 3250 // -------------------------- sorting -------------------------- // 3251 3252 /** 3253 * @params {Array} elems 3254 * @public 3255 */ 3256 proto.updateSortData = function (elems) { 3257 // get items 3258 var items; 3259 if (elems) { 3260 elems = utils.makeArray(elems); 3261 items = this.getItems(elems); 3262 } else { 3263 // update all items if no elems provided 3264 items = this.items; 3265 } 3266 3267 this._getSorters(); 3268 this._updateItemsSortData(items); 3269 }; 3270 3271 proto._getSorters = function () { 3272 var getSortData = this.options.getSortData; 3273 for (var key in getSortData) { 3274 var sorter = getSortData[key]; 3275 this._sorters[key] = mungeSorter(sorter); 3276 } 3277 }; 3278 3279 /** 3280 * @params {Array} items - of Isotope.Items 3281 * @private 3282 */ 3283 proto._updateItemsSortData = function (items) { 3284 // do not update if no items 3285 var len = items && items.length; 3286 3287 for (var i = 0; len && i < len; i++) { 3288 var item = items[i]; 3289 item.updateSortData(); 3290 } 3291 }; 3292 3293 // ----- munge sorter ----- // 3294 3295 // encapsulate this, as we just need mungeSorter 3296 // other functions in here are just for munging 3297 var mungeSorter = (function () { 3298 // add a magic layer to sorters for convienent shorthands 3299 // `.foo-bar` will use the text of .foo-bar querySelector 3300 // `[foo-bar]` will use attribute 3301 // you can also add parser 3302 // `.foo-bar parseInt` will parse that as a number 3303 function mungeSorter(sorter) { 3304 // if not a string, return function or whatever it is 3305 if (typeof sorter != 'string') { 3306 return sorter; 3307 } 3308 // parse the sorter string 3309 var args = trim(sorter).split(' '); 3310 var query = args[0]; 3311 // check if query looks like [an-attribute] 3312 var attrMatch = query.match(/^\[(.+)\]$/); 3313 var attr = attrMatch && attrMatch[1]; 3314 var getValue = getValueGetter(attr, query); 3315 // use second argument as a parser 3316 var parser = Isotope.sortDataParsers[args[1]]; 3317 // parse the value, if there was a parser 3318 sorter = parser ? function (elem) { 3319 return elem && parser(getValue(elem)); 3320 } : 3321 // otherwise just return value 3322 function (elem) { 3323 return elem && getValue(elem); 3324 }; 3325 3326 return sorter; 3327 } 3328 3329 // get an attribute getter, or get text of the querySelector 3330 function getValueGetter(attr, query) { 3331 // if query looks like [foo-bar], get attribute 3332 if (attr) { 3333 return function getAttribute(elem) { 3334 return elem.getAttribute(attr); 3335 }; 3336 } 3337 3338 // otherwise, assume its a querySelector, and get its text 3339 return function getChildText(elem) { 3340 var child = elem.querySelector(query); 3341 return child && child.textContent; 3342 }; 3343 } 3344 3345 return mungeSorter; 3346 })(); 3347 3348 // parsers used in getSortData shortcut strings 3349 Isotope.sortDataParsers = { 3350 'parseInt' : function (val) { 3351 return parseInt(val, 10); 3352 }, 3353 'parseFloat': function (val) { 3354 return parseFloat(val); 3355 } 3356 }; 3357 3358 // ----- sort method ----- // 3359 3360 // sort filteredItem order 3361 proto._sort = function () { 3362 if (!this.options.sortBy) { 3363 return; 3364 } 3365 // keep track of sortBy History 3366 var sortBys = utils.makeArray(this.options.sortBy); 3367 if (!this._getIsSameSortBy(sortBys)) { 3368 // concat all sortBy and sortHistory, add to front, oldest goes in last 3369 this.sortHistory = sortBys.concat(this.sortHistory); 3370 } 3371 // sort magic 3372 var itemSorter = getItemSorter(this.sortHistory, this.options.sortAscending); 3373 this.filteredItems.sort(itemSorter); 3374 }; 3375 3376 // check if sortBys is same as start of sortHistory 3377 proto._getIsSameSortBy = function (sortBys) { 3378 for (var i = 0; i < sortBys.length; i++) { 3379 if (sortBys[i] != this.sortHistory[i]) { 3380 return false; 3381 } 3382 } 3383 return true; 3384 }; 3385 3386 // returns a function used for sorting 3387 function getItemSorter(sortBys, sortAsc) { 3388 return function sorter(itemA, itemB) { 3389 // cycle through all sortKeys 3390 for (var i = 0; i < sortBys.length; i++) { 3391 var sortBy = sortBys[i]; 3392 var a = itemA.sortData[sortBy]; 3393 var b = itemB.sortData[sortBy]; 3394 if (a > b || a < b) { 3395 // if sortAsc is an object, use the value given the sortBy key 3396 var isAscending = sortAsc[sortBy] !== undefined ? sortAsc[sortBy] : sortAsc; 3397 var direction = isAscending ? 1 : -1; 3398 return (a > b ? 1 : -1) * direction; 3399 } 3400 } 3401 return 0; 3402 }; 3403 } 3404 3405 // -------------------------- methods -------------------------- // 3406 3407 // get layout mode 3408 proto._mode = function () { 3409 var layoutMode = this.options.layoutMode; 3410 var mode = this.modes[layoutMode]; 3411 if (!mode) { 3412 // TODO console.error 3413 throw new Error('No layout mode: ' + layoutMode); 3414 } 3415 // HACK sync mode's options 3416 // any options set after init for layout mode need to be synced 3417 mode.options = this.options[layoutMode]; 3418 return mode; 3419 }; 3420 3421 proto._resetLayout = function () { 3422 // trigger original reset layout 3423 Outlayer.prototype._resetLayout.call(this); 3424 this._mode()._resetLayout(); 3425 }; 3426 3427 proto._getItemLayoutPosition = function (item) { 3428 return this._mode()._getItemLayoutPosition(item); 3429 }; 3430 3431 proto._manageStamp = function (stamp) { 3432 this._mode()._manageStamp(stamp); 3433 }; 3434 3435 proto._getContainerSize = function () { 3436 return this._mode()._getContainerSize(); 3437 }; 3438 3439 proto.needsResizeLayout = function () { 3440 return this._mode().needsResizeLayout(); 3441 }; 3442 3443 // -------------------------- adding & removing -------------------------- // 3444 3445 // HEADS UP overwrites default Outlayer appended 3446 proto.appended = function (elems) { 3447 var items = this.addItems(elems); 3448 if (!items.length) { 3449 return; 3450 } 3451 // filter, layout, reveal new items 3452 var filteredItems = this._filterRevealAdded(items); 3453 // add to filteredItems 3454 this.filteredItems = this.filteredItems.concat(filteredItems); 3455 }; 3456 3457 // HEADS UP overwrites default Outlayer prepended 3458 proto.prepended = function (elems) { 3459 var items = this._itemize(elems); 3460 if (!items.length) { 3461 return; 3462 } 3463 // start new layout 3464 this._resetLayout(); 3465 this._manageStamps(); 3466 // filter, layout, reveal new items 3467 var filteredItems = this._filterRevealAdded(items); 3468 // layout previous items 3469 this.layoutItems(this.filteredItems); 3470 // add to items and filteredItems 3471 this.filteredItems = filteredItems.concat(this.filteredItems); 3472 this.items = items.concat(this.items); 3473 }; 3474 3475 proto._filterRevealAdded = function (items) { 3476 var filtered = this._filter(items); 3477 this.hide(filtered.needHide); 3478 // reveal all new items 3479 this.reveal(filtered.matches); 3480 // layout new items, no transition 3481 this.layoutItems(filtered.matches, true); 3482 return filtered.matches; 3483 }; 3484 3485 /** 3486 * Filter, sort, and layout newly-appended item elements 3487 * @param {Array or NodeList or Element} elems 3488 */ 3489 proto.insert = function (elems) { 3490 var items = this.addItems(elems); 3491 if (!items.length) { 3492 return; 3493 } 3494 // append item elements 3495 var i, item; 3496 var len = items.length; 3497 for (i = 0; i < len; i++) { 3498 item = items[i]; 3499 this.element.appendChild(item.element); 3500 } 3501 // filter new stuff 3502 var filteredInsertItems = this._filter(items).matches; 3503 // set flag 3504 for (i = 0; i < len; i++) { 3505 items[i].isLayoutInstant = true; 3506 } 3507 this.arrange(); 3508 // reset flag 3509 for (i = 0; i < len; i++) { 3510 delete items[i].isLayoutInstant; 3511 } 3512 this.reveal(filteredInsertItems); 3513 }; 3514 3515 var _remove = proto.remove; 3516 proto.remove = function (elems) { 3517 elems = utils.makeArray(elems); 3518 var removeItems = this.getItems(elems); 3519 // do regular thing 3520 _remove.call(this, elems); 3521 // bail if no items to remove 3522 var len = removeItems && removeItems.length; 3523 // remove elems from filteredItems 3524 for (var i = 0; len && i < len; i++) { 3525 var item = removeItems[i]; 3526 // remove item from collection 3527 utils.removeFrom(this.filteredItems, item); 3528 } 3529 }; 3530 3531 proto.shuffle = function () { 3532 // update random sortData 3533 for (var i = 0; i < this.items.length; i++) { 3534 var item = this.items[i]; 3535 item.sortData.random = Math.random(); 3536 } 3537 this.options.sortBy = 'random'; 3538 this._sort(); 3539 this._layout(); 3540 }; 3541 3542 /** 3543 * trigger fn without transition 3544 * kind of hacky to have this in the first place 3545 * @param {Function} fn 3546 * @param {Array} args 3547 * @returns ret 3548 * @private 3549 */ 3550 proto._noTransition = function (fn, args) { 3551 // save transitionDuration before disabling 3552 var transitionDuration = this.options.transitionDuration; 3553 // disable transition 3554 this.options.transitionDuration = 0; 3555 // do it 3556 var returnValue = fn.apply(this, args); 3557 // re-enable transition for reveal 3558 this.options.transitionDuration = transitionDuration; 3559 return returnValue; 3560 }; 3561 3562 // ----- helper methods ----- // 3563 3564 /** 3565 * getter method for getting filtered item elements 3566 * @returns {Array} elems - collection of item elements 3567 */ 3568 proto.getFilteredItemElements = function () { 3569 return this.filteredItems.map(function (item) { 3570 return item.element; 3571 }); 3572 }; 3573 3574 // ----- ----- // 3575 3576 return Isotope; 3577 3578}));
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.