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