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