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