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