vendor: 5,872 bytes, lines 1-246
1/*! 2 * imagesLoaded PACKAGED v4.1.4 3 * JavaScript is all like "You images are done yet or what?" 4 * MIT License 5 */ 6 7/** 8 * EvEmitter v1.1.0 9 * Lil' event emitter 10 * MIT License 11 */ 12 13/* jshint unused: true, undef: true, strict: true */ 14 15( function( global, factory ) { 16 // universal module definition 17 /* jshint strict: false */ /* globals define, module, window */ 18 if ( typeof define == 'function' && define.amd ) { 19 // AMD - RequireJS 20 define( 'ev-emitter/ev-emitter',factory ); 21 } else if ( typeof module == 'object' && module.exports ) { 22 // CommonJS - Browserify, Webpack 23 module.exports = factory(); 24 } else { 25 // Browser globals 26 global.EvEmitter = factory(); 27 } 28 29}( typeof window != 'undefined' ? window : this, function() { 30 31 32 33function EvEmitter() {} 34 35var proto = EvEmitter.prototype; 36 37proto.on = function( eventName, listener ) { 38 if ( !eventName || !listener ) { 39 return; 40 } 41 // set events hash 42 var events = this._events = this._events || {}; 43 // set listeners array 44 var listeners = events[ eventName ] = events[ eventName ] || []; 45 // only add once 46 if ( listeners.indexOf( listener ) == -1 ) { 47 listeners.push( listener ); 48 } 49 50 return this; 51}; 52 53proto.once = function( eventName, listener ) { 54 if ( !eventName || !listener ) { 55 return; 56 } 57 // add event 58 this.on( eventName, listener ); 59 // set once flag 60 // set onceEvents hash 61 var onceEvents = this._onceEvents = this._onceEvents || {}; 62 // set onceListeners object 63 var onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || {}; 64 // set flag 65 onceListeners[ listener ] = true; 66 67 return this; 68}; 69 70proto.off = function( eventName, listener ) { 71 var listeners = this._events && this._events[ eventName ]; 72 if ( !listeners || !listeners.length ) { 73 return; 74 } 75 var index = listeners.indexOf( listener ); 76 if ( index != -1 ) { 77 listeners.splice( index, 1 ); 78 } 79 80 return this; 81}; 82 83proto.emitEvent = function( eventName, args ) { 84 var listeners = this._events && this._events[ eventName ]; 85 if ( !listeners || !listeners.length ) { 86 return; 87 } 88 // copy over to avoid interference if .off() in listener 89 listeners = listeners.slice(0); 90 args = args || []; 91 // once stuff 92 var onceListeners = this._onceEvents && this._onceEvents[ eventName ]; 93 94 for ( var i=0; i < listeners.length; i++ ) { 95 var listener = listeners[i] 96 var isOnce = onceListeners && onceListeners[ listener ]; 97 if ( isOnce ) { 98 // remove listener 99 // remove before trigger to prevent recursion 100 this.off( eventName, listener ); 101 // unset once flag 102 delete onceListeners[ listener ]; 103 } 104 // trigger listener 105 listener.apply( this, args ); 106 } 107 108 return this; 109}; 110 111proto.allOff = function() { 112 delete this._events; 113 delete this._onceEvents; 114}; 115 116return EvEmitter; 117 118})); 119 120/*! 121 * imagesLoaded v4.1.4 122 * JavaScript is all like "You images are done yet or what?" 123 * MIT License 124 */ 125 126( function( window, factory ) { 'use strict'; 127 // universal module definition 128 129 /*global define: false, module: false, require: false */ 130 131 if ( typeof define == 'function' && define.amd ) { 132 // AMD 133 define( [ 134 'ev-emitter/ev-emitter' 135 ], function( EvEmitter ) { 136 return factory( window, EvEmitter ); 137 }); 138 } else if ( typeof module == 'object' && module.exports ) { 139 // CommonJS 140 module.exports = factory( 141 window, 142 require('ev-emitter') 143 ); 144 } else { 145 // browser global 146 window.imagesLoaded = factory( 147 window, 148 window.EvEmitter 149 ); 150 } 151 152})( typeof window !== 'undefined' ? window : this, 153 154// -------------------------- factory -------------------------- // 155 156function factory( window, EvEmitter ) { 157 158 159 160var $ = window.jQuery; 161var console = window.console; 162 163// -------------------------- helpers -------------------------- // 164 165// extend objects 166function extend( a, b ) { 167 for ( var prop in b ) { 168 a[ prop ] = b[ prop ]; 169 } 170 return a; 171} 172 173var arraySlice = Array.prototype.slice; 174 175// turn element or nodeList into an array 176function makeArray( obj ) { 177 if ( Array.isArray( obj ) ) { 178 // use object if already an array 179 return obj; 180 } 181 182 var isArrayLike = typeof obj == 'object' && typeof obj.length == 'number'; 183 if ( isArrayLike ) { 184 // convert nodeList to array 185 return arraySlice.call( obj ); 186 } 187 188 // array of single index 189 return [ obj ]; 190} 191 192// -------------------------- imagesLoaded -------------------------- // 193 194/** 195 * @param {Array, Element, NodeList, String} elem 196 * @param {Object or Function} options - if function, use as callback 197 * @param {Function} onAlways - callback function 198 */ 199function ImagesLoaded( elem, options, onAlways ) { 200 // coerce ImagesLoaded() without new, to be new ImagesLoaded() 201 if ( !( this instanceof ImagesLoaded ) ) { 202 return new ImagesLoaded( elem, options, onAlways ); 203 } 204 // use elem as selector string 205 var queryElem = elem; 206 if ( typeof elem == 'string' ) { 207 queryElem = document.querySelectorAll( elem ); 208 } 209 // bail if bad element 210 if ( !queryElem ) { 211 console.error( 'Bad element for imagesLoaded ' + ( queryElem || elem ) ); 212 return; 213 } 214 215 this.elements = makeArray( queryElem ); 216 this.options = extend( {}, this.options ); 217 // shift arguments if no options set 218 if ( typeof options == 'function' ) { 219 onAlways = options; 220 } else { 221 extend( this.options, options ); 222 } 223 224 if ( onAlways ) { 225 this.on( 'always', onAlways ); 226 } 227 228 this.getImages(); 229 230 if ( $ ) { 231 // add jQuery Deferred object 232 this.jqDeferred = new $.Deferred(); 233 } 234 235 // HACK check async to allow time to bind listeners 236 setTimeout( this.check.bind( this ) ); 237} 238 239ImagesLoaded.prototype = Object.create( EvEmitter.prototype ); 240 241ImagesLoaded.prototype.options = {}; 242 243ImagesLoaded.prototype.getImages = function() { 244 this.images = []; 245 246 // filter & find items if we have an item selector
vendor: 4,347 bytes, lines 247-403
247 this.elements.forEach( this.addElementImages, this ); 248}; 249 250/** 251 * @param {Node} element 252 */ 253ImagesLoaded.prototype.addElementImages = function( elem ) { 254 // filter siblings 255 if ( elem.nodeName == 'IMG' ) { 256 this.addImage( elem ); 257 } 258 // get background image on element 259 if ( this.options.background === true ) { 260 this.addElementBackgroundImages( elem ); 261 } 262 263 // find children 264 // no non-element nodes, #143 265 var nodeType = elem.nodeType; 266 if ( !nodeType || !elementNodeTypes[ nodeType ] ) { 267 return; 268 } 269 var childImgs = elem.querySelectorAll('img'); 270 // concat childElems to filterFound array 271 for ( var i=0; i < childImgs.length; i++ ) { 272 var img = childImgs[i]; 273 this.addImage( img ); 274 } 275 276 // get child background images 277 if ( typeof this.options.background == 'string' ) { 278 var children = elem.querySelectorAll( this.options.background ); 279 for ( i=0; i < children.length; i++ ) { 280 var child = children[i]; 281 this.addElementBackgroundImages( child ); 282 } 283 } 284}; 285 286var elementNodeTypes = { 287 1: true, 288 9: true, 289 11: true 290}; 291 292ImagesLoaded.prototype.addElementBackgroundImages = function( elem ) { 293 var style = getComputedStyle( elem ); 294 if ( !style ) { 295 // Firefox returns null if in a hidden iframe https://bugzil.la/548397 296 return; 297 } 298 // get url inside url("...") 299 var reURL = /url\((['"])?(.*?)\1\)/gi; 300 var matches = reURL.exec( style.backgroundImage ); 301 while ( matches !== null ) { 302 var url = matches && matches[2]; 303 if ( url ) { 304 this.addBackground( url, elem ); 305 } 306 matches = reURL.exec( style.backgroundImage ); 307 } 308}; 309 310/** 311 * @param {Image} img 312 */ 313ImagesLoaded.prototype.addImage = function( img ) { 314 var loadingImage = new LoadingImage( img ); 315 this.images.push( loadingImage ); 316}; 317 318ImagesLoaded.prototype.addBackground = function( url, elem ) { 319 var background = new Background( url, elem ); 320 this.images.push( background ); 321}; 322 323ImagesLoaded.prototype.check = function() { 324 var _this = this; 325 this.progressedCount = 0; 326 this.hasAnyBroken = false; 327 // complete if no images 328 if ( !this.images.length ) { 329 this.complete(); 330 return; 331 } 332 333 function onProgress( image, elem, message ) { 334 // HACK - Chrome triggers event before object properties have changed. #83 335 setTimeout( function() { 336 _this.progress( image, elem, message ); 337 }); 338 } 339 340 this.images.forEach( function( loadingImage ) { 341 loadingImage.once( 'progress', onProgress ); 342 loadingImage.check(); 343 }); 344}; 345 346ImagesLoaded.prototype.progress = function( image, elem, message ) { 347 this.progressedCount++; 348 this.hasAnyBroken = this.hasAnyBroken || !image.isLoaded; 349 // progress event 350 this.emitEvent( 'progress', [ this, image, elem ] ); 351 if ( this.jqDeferred && this.jqDeferred.notify ) { 352 this.jqDeferred.notify( this, image ); 353 } 354 // check if completed 355 if ( this.progressedCount == this.images.length ) { 356 this.complete(); 357 } 358 359 if ( this.options.debug && console ) { 360 console.log( 'progress: ' + message, image, elem ); 361 } 362}; 363 364ImagesLoaded.prototype.complete = function() { 365 var eventName = this.hasAnyBroken ? 'fail' : 'done'; 366 this.isComplete = true; 367 this.emitEvent( eventName, [ this ] ); 368 this.emitEvent( 'always', [ this ] ); 369 if ( this.jqDeferred ) { 370 var jqMethod = this.hasAnyBroken ? 'reject' : 'resolve'; 371 this.jqDeferred[ jqMethod ]( this ); 372 } 373}; 374 375// -------------------------- -------------------------- // 376 377function LoadingImage( img ) { 378 this.img = img; 379} 380 381LoadingImage.prototype = Object.create( EvEmitter.prototype ); 382 383LoadingImage.prototype.check = function() { 384 // If complete is true and browser supports natural sizes, 385 // try to check for image status manually. 386 var isComplete = this.getIsImageComplete(); 387 if ( isComplete ) { 388 // report based on naturalWidth 389 this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' ); 390 return; 391 } 392 393 // If none of the checks above matched, simulate loading on detached element. 394 this.proxyImage = new Image(); 395 this.proxyImage.addEventListener( 'load', this ); 396 this.proxyImage.addEventListener( 'error', this ); 397 // bind to image as well for Firefox. #191 398 this.img.addEventListener( 'load', this ); 399 this.img.addEventListener( 'error', this ); 400 this.proxyImage.src = this.img.src; 401}; 402 403LoadingImage.prototype.getIsImageComplete = function() {
vendor: 2,759 bytes, lines 404-506
404 // check for non-zero, non-undefined naturalWidth 405 // fixes Safari+InfiniteScroll+Masonry bug infinite-scroll#671 406 return this.img.complete && this.img.naturalWidth; 407}; 408 409LoadingImage.prototype.confirm = function( isLoaded, message ) { 410 this.isLoaded = isLoaded; 411 this.emitEvent( 'progress', [ this, this.img, message ] ); 412}; 413 414// ----- events ----- // 415 416// trigger specified handler for event type 417LoadingImage.prototype.handleEvent = function( event ) { 418 var method = 'on' + event.type; 419 if ( this[ method ] ) { 420 this[ method ]( event ); 421 } 422}; 423 424LoadingImage.prototype.onload = function() { 425 this.confirm( true, 'onload' ); 426 this.unbindEvents(); 427}; 428 429LoadingImage.prototype.onerror = function() { 430 this.confirm( false, 'onerror' ); 431 this.unbindEvents(); 432}; 433 434LoadingImage.prototype.unbindEvents = function() { 435 this.proxyImage.removeEventListener( 'load', this ); 436 this.proxyImage.removeEventListener( 'error', this ); 437 this.img.removeEventListener( 'load', this ); 438 this.img.removeEventListener( 'error', this ); 439}; 440 441// -------------------------- Background -------------------------- // 442 443function Background( url, element ) { 444 this.url = url; 445 this.element = element; 446 this.img = new Image(); 447} 448 449// inherit LoadingImage prototype 450Background.prototype = Object.create( LoadingImage.prototype ); 451 452Background.prototype.check = function() { 453 this.img.addEventListener( 'load', this ); 454 this.img.addEventListener( 'error', this ); 455 this.img.src = this.url; 456 // check if image is already complete 457 var isComplete = this.getIsImageComplete(); 458 if ( isComplete ) { 459 this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' ); 460 this.unbindEvents(); 461 } 462}; 463 464Background.prototype.unbindEvents = function() { 465 this.img.removeEventListener( 'load', this ); 466 this.img.removeEventListener( 'error', this ); 467}; 468 469Background.prototype.confirm = function( isLoaded, message ) { 470 this.isLoaded = isLoaded; 471 this.emitEvent( 'progress', [ this, this.element, message ] ); 472}; 473 474// -------------------------- jQuery -------------------------- // 475 476ImagesLoaded.makeJQueryPlugin = function( jQuery ) { 477 jQuery = jQuery || window.jQuery; 478 if ( !jQuery ) { 479 return; 480 } 481 // set local variable 482 $ = jQuery; 483 // $().imagesLoaded() 484 $.fn.imagesLoaded = function( options, callback ) { 485 var instance = new ImagesLoaded( this, options, callback ); 486 return instance.jqDeferred.promise( $(this) ); 487 }; 488}; 489// try making plugin 490ImagesLoaded.makeJQueryPlugin(); 491 492// -------------------------- -------------------------- // 493 494return ImagesLoaded; 495 496}); 497 498 499/*! 500 * Isotope PACKAGED v3.0.6 501 * 502 * Licensed GPLv3 for open source use 503 * or Isotope Commercial License for commercial use 504 * 505 * https://isotope.metafizzy.co 506 * Copyright 2010-2018 Metafizzy
vendor: 39,423 bytes, lines 506-2068
506 507 */ 508 509/** 510 * Bridget makes jQuery widgets 511 * v2.0.1 512 * MIT license 513 */ 514 515/* jshint browser: true, strict: true, undef: true, unused: true */ 516 517( function( window, factory ) { 518 // universal module definition 519 /*jshint strict: false */ /* globals define, module, require */ 520 if ( typeof define == 'function' && define.amd ) { 521 // AMD 522 define( 'jquery-bridget/jquery-bridget',[ 'jquery' ], function( jQuery ) { 523 return factory( window, jQuery ); 524 }); 525 } else if ( typeof module == 'object' && module.exports ) { 526 // CommonJS 527 module.exports = factory( 528 window, 529 require('jquery') 530 ); 531 } else { 532 // browser global 533 window.jQueryBridget = factory( 534 window, 535 window.jQuery 536 ); 537 } 538 539}( window, function factory( window, jQuery ) { 540'use strict'; 541 542// ----- utils ----- // 543 544var arraySlice = Array.prototype.slice; 545 546// helper function for logging errors 547// $.error breaks jQuery chaining 548var console = window.console; 549var logError = typeof console == 'undefined' ? function() {} : 550 function( message ) { 551 console.error( message ); 552 }; 553 554// ----- jQueryBridget ----- // 555 556function jQueryBridget( namespace, PluginClass, $ ) { 557 $ = $ || jQuery || window.jQuery; 558 if ( !$ ) { 559 return; 560 } 561 562 // add option method -> $().plugin('option', {...}) 563 if ( !PluginClass.prototype.option ) { 564 // option setter 565 PluginClass.prototype.option = function( opts ) { 566 // bail out if not an object 567 if ( !$.isPlainObject( opts ) ){ 568 return; 569 } 570 this.options = $.extend( true, this.options, opts ); 571 }; 572 } 573 574 // make jQuery plugin 575 $.fn[ namespace ] = function( arg0 /*, arg1 */ ) { 576 if ( typeof arg0 == 'string' ) { 577 // method call $().plugin( 'methodName', { options } ) 578 // shift arguments by 1 579 var args = arraySlice.call( arguments, 1 ); 580 return methodCall( this, arg0, args ); 581 } 582 // just $().plugin({ options }) 583 plainCall( this, arg0 ); 584 return this; 585 }; 586 587 // $().plugin('methodName') 588 function methodCall( $elems, methodName, args ) { 589 var returnValue; 590 var pluginMethodStr = '$().' + namespace + '("' + methodName + '")'; 591 592 $elems.each( function( i, elem ) { 593 // get instance 594 var instance = $.data( elem, namespace ); 595 if ( !instance ) { 596 logError( namespace + ' not initialized. Cannot call methods, i.e. ' + 597 pluginMethodStr ); 598 return; 599 } 600 601 var method = instance[ methodName ]; 602 if ( !method || methodName.charAt(0) == '_' ) { 603 logError( pluginMethodStr + ' is not a valid method' ); 604 return; 605 } 606 607 // apply method, get return value 608 var value = method.apply( instance, args ); 609 // set return value if value is returned, use only first value 610 returnValue = returnValue === undefined ? value : returnValue; 611 }); 612 613 return returnValue !== undefined ? returnValue : $elems; 614 } 615 616 function plainCall( $elems, options ) { 617 $elems.each( function( i, elem ) { 618 var instance = $.data( elem, namespace ); 619 if ( instance ) { 620 // set options & init 621 instance.option( options ); 622 instance._init(); 623 } else { 624 // initialize new instance 625 instance = new PluginClass( elem, options ); 626 $.data( elem, namespace, instance ); 627 } 628 }); 629 } 630 631 updateJQuery( $ ); 632 633} 634 635// ----- updateJQuery ----- // 636 637// set $.bridget for v1 backwards compatibility 638function updateJQuery( $ ) { 639 if ( !$ || ( $ && $.bridget ) ) { 640 return; 641 } 642 $.bridget = jQueryBridget; 643} 644 645updateJQuery( jQuery || window.jQuery ); 646 647// ----- ----- // 648 649return jQueryBridget; 650 651})); 652 653/** 654 * EvEmitter v1.1.0 655 * Lil' event emitter 656 * MIT License 657 */ 658 659/* jshint unused: true, undef: true, strict: true */ 660 661( function( global, factory ) { 662 // universal module definition 663 /* jshint strict: false */ /* globals define, module, window */ 664 if ( typeof define == 'function' && define.amd ) { 665 // AMD - RequireJS 666 define( 'ev-emitter/ev-emitter',factory ); 667 } else if ( typeof module == 'object' && module.exports ) { 668 // CommonJS - Browserify, Webpack 669 module.exports = factory(); 670 } else { 671 // Browser globals 672 global.EvEmitter = factory(); 673 } 674 675}( typeof window != 'undefined' ? window : this, function() { 676 677 678 679function EvEmitter() {} 680 681var proto = EvEmitter.prototype; 682 683proto.on = function( eventName, listener ) { 684 if ( !eventName || !listener ) { 685 return; 686 } 687 // set events hash 688 var events = this._events = this._events || {}; 689 // set listeners array 690 var listeners = events[ eventName ] = events[ eventName ] || []; 691 // only add once 692 if ( listeners.indexOf( listener ) == -1 ) { 693 listeners.push( listener ); 694 } 695 696 return this; 697}; 698 699proto.once = function( eventName, listener ) { 700 if ( !eventName || !listener ) { 701 return; 702 } 703 // add event 704 this.on( eventName, listener ); 705 // set once flag 706 // set onceEvents hash 707 var onceEvents = this._onceEvents = this._onceEvents || {}; 708 // set onceListeners object 709 var onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || {}; 710 // set flag 711 onceListeners[ listener ] = true; 712 713 return this; 714}; 715 716proto.off = function( eventName, listener ) { 717 var listeners = this._events && this._events[ eventName ]; 718 if ( !listeners || !listeners.length ) { 719 return; 720 } 721 var index = listeners.indexOf( listener ); 722 if ( index != -1 ) { 723 listeners.splice( index, 1 ); 724 } 725 726 return this; 727}; 728 729proto.emitEvent = function( eventName, args ) { 730 var listeners = this._events && this._events[ eventName ]; 731 if ( !listeners || !listeners.length ) { 732 return; 733 } 734 // copy over to avoid interference if .off() in listener 735 listeners = listeners.slice(0); 736 args = args || []; 737 // once stuff 738 var onceListeners = this._onceEvents && this._onceEvents[ eventName ]; 739 740 for ( var i=0; i < listeners.length; i++ ) { 741 var listener = listeners[i] 742 var isOnce = onceListeners && onceListeners[ listener ]; 743 if ( isOnce ) { 744 // remove listener 745 // remove before trigger to prevent recursion 746 this.off( eventName, listener ); 747 // unset once flag 748 delete onceListeners[ listener ]; 749 } 750 // trigger listener 751 listener.apply( this, args ); 752 } 753 754 return this; 755}; 756 757proto.allOff = function() { 758 delete this._events; 759 delete this._onceEvents; 760}; 761 762return EvEmitter; 763 764})); 765 766/*! 767 * getSize v2.0.3 768 * measure size of elements 769 * MIT license 770 */ 771 772/* jshint browser: true, strict: true, undef: true, unused: true */ 773/* globals console: false */ 774 775( function( window, factory ) { 776 /* jshint strict: false */ /* globals define, module */ 777 if ( typeof define == 'function' && define.amd ) { 778 // AMD 779 define( 'get-size/get-size',factory ); 780 } else if ( typeof module == 'object' && module.exports ) { 781 // CommonJS 782 module.exports = factory(); 783 } else { 784 // browser global 785 window.getSize = factory(); 786 } 787 788})( window, function factory() { 789'use strict'; 790 791// -------------------------- helpers -------------------------- // 792 793// get a number from a string, not a percentage 794function getStyleSize( value ) { 795 var num = parseFloat( value ); 796 // not a percent like '100%', and a number 797 var isValid = value.indexOf('%') == -1 && !isNaN( num ); 798 return isValid && num; 799} 800 801function noop() {} 802 803var logError = typeof console == 'undefined' ? noop : 804 function( message ) { 805 console.error( message ); 806 }; 807 808// -------------------------- measurements -------------------------- // 809 810var measurements = [ 811 'paddingLeft', 812 'paddingRight', 813 'paddingTop', 814 'paddingBottom', 815 'marginLeft', 816 'marginRight', 817 'marginTop', 818 'marginBottom', 819 'borderLeftWidth', 820 'borderRightWidth', 821 'borderTopWidth', 822 'borderBottomWidth' 823]; 824 825var measurementsLength = measurements.length; 826 827function getZeroSize() { 828 var size = { 829 width: 0, 830 height: 0, 831 innerWidth: 0, 832 innerHeight: 0, 833 outerWidth: 0, 834 outerHeight: 0 835 }; 836 for ( var i=0; i < measurementsLength; i++ ) { 837 var measurement = measurements[i]; 838 size[ measurement ] = 0; 839 } 840 return size; 841} 842 843// -------------------------- getStyle -------------------------- // 844 845/** 846 * getStyle, get style of element, check for Firefox bug 847 * https://bugzilla.mozilla.org/show_bug.cgi?id=548397 848 */ 849function getStyle( elem ) { 850 var style = getComputedStyle( elem ); 851 if ( !style ) { 852 logError( 'Style returned ' + style + 853 '. Are you running this code in a hidden iframe on Firefox? ' + 854 'See https://bit.ly/getsizebug1' ); 855 } 856 return style; 857} 858 859// -------------------------- setup -------------------------- // 860 861var isSetup = false; 862 863var isBoxSizeOuter; 864 865/** 866 * setup 867 * check isBoxSizerOuter 868 * do on first getSize() rather than on page load for Firefox bug 869 */ 870function setup() { 871 // setup once 872 if ( isSetup ) { 873 return; 874 } 875 isSetup = true; 876 877 // -------------------------- box sizing -------------------------- // 878 879 /** 880 * Chrome & Safari measure the outer-width on style.width on border-box elems 881 * IE11 & Firefox<29 measures the inner-width 882 */ 883 var div = document.createElement('div'); 884 div.style.width = '200px'; 885 div.style.padding = '1px 2px 3px 4px'; 886 div.style.borderStyle = 'solid'; 887 div.style.borderWidth = '1px 2px 3px 4px'; 888 div.style.boxSizing = 'border-box'; 889 890 var body = document.body || document.documentElement; 891 body.appendChild( div ); 892 var style = getStyle( div ); 893 // round value for browser zoom. desandro/masonry#928 894 isBoxSizeOuter = Math.round( getStyleSize( style.width ) ) == 200; 895 getSize.isBoxSizeOuter = isBoxSizeOuter; 896 897 body.removeChild( div ); 898} 899 900// -------------------------- getSize -------------------------- // 901 902function getSize( elem ) { 903 setup(); 904 905 // use querySeletor if elem is string 906 if ( typeof elem == 'string' ) { 907 elem = document.querySelector( elem ); 908 } 909 910 // do not proceed on non-objects 911 if ( !elem || typeof elem != 'object' || !elem.nodeType ) { 912 return; 913 } 914 915 var style = getStyle( elem ); 916 917 // if hidden, everything is 0 918 if ( style.display == 'none' ) { 919 return getZeroSize(); 920 } 921 922 var size = {}; 923 size.width = elem.offsetWidth; 924 size.height = elem.offsetHeight; 925 926 var isBorderBox = size.isBorderBox = style.boxSizing == 'border-box'; 927 928 // get all measurements 929 for ( var i=0; i < measurementsLength; i++ ) { 930 var measurement = measurements[i]; 931 var value = style[ measurement ]; 932 var num = parseFloat( value ); 933 // any 'auto', 'medium' value will be 0 934 size[ measurement ] = !isNaN( num ) ? num : 0; 935 } 936 937 var paddingWidth = size.paddingLeft + size.paddingRight; 938 var paddingHeight = size.paddingTop + size.paddingBottom; 939 var marginWidth = size.marginLeft + size.marginRight; 940 var marginHeight = size.marginTop + size.marginBottom; 941 var borderWidth = size.borderLeftWidth + size.borderRightWidth; 942 var borderHeight = size.borderTopWidth + size.borderBottomWidth; 943 944 var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter; 945 946 // overwrite width and height if we can get it from style 947 var styleWidth = getStyleSize( style.width ); 948 if ( styleWidth !== false ) { 949 size.width = styleWidth + 950 // add padding and border unless it's already including it 951 ( isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth ); 952 } 953 954 var styleHeight = getStyleSize( style.height ); 955 if ( styleHeight !== false ) { 956 size.height = styleHeight + 957 // add padding and border unless it's already including it 958 ( isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight ); 959 } 960 961 size.innerWidth = size.width - ( paddingWidth + borderWidth ); 962 size.innerHeight = size.height - ( paddingHeight + borderHeight ); 963 964 size.outerWidth = size.width + marginWidth; 965 size.outerHeight = size.height + marginHeight; 966 967 return size; 968} 969 970return getSize; 971 972}); 973 974/** 975 * matchesSelector v2.0.2 976 * matchesSelector( element, '.selector' ) 977 * MIT license 978 */ 979 980/*jshint browser: true, strict: true, undef: true, unused: true */ 981 982( function( window, factory ) { 983 /*global define: false, module: false */ 984 'use strict'; 985 // universal module definition 986 if ( typeof define == 'function' && define.amd ) { 987 // AMD 988 define( 'desandro-matches-selector/matches-selector',factory ); 989 } else if ( typeof module == 'object' && module.exports ) { 990 // CommonJS 991 module.exports = factory(); 992 } else { 993 // browser global 994 window.matchesSelector = factory(); 995 } 996 997}( window, function factory() { 998 'use strict'; 999 1000 var matchesMethod = ( function() { 1001 var ElemProto = window.Element.prototype; 1002 // check for the standard method name first 1003 if ( ElemProto.matches ) { 1004 return 'matches'; 1005 } 1006 // check un-prefixed 1007 if ( ElemProto.matchesSelector ) { 1008 return 'matchesSelector'; 1009 } 1010 // check vendor prefixes 1011 var prefixes = [ 'webkit', 'moz', 'ms', 'o' ]; 1012 1013 for ( var i=0; i < prefixes.length; i++ ) { 1014 var prefix = prefixes[i]; 1015 var method = prefix + 'MatchesSelector'; 1016 if ( ElemProto[ method ] ) { 1017 return method; 1018 } 1019 } 1020 })(); 1021 1022 return function matchesSelector( elem, selector ) { 1023 return elem[ matchesMethod ]( selector ); 1024 }; 1025 1026})); 1027 1028/** 1029 * Fizzy UI utils v2.0.7 1030 * MIT license 1031 */ 1032 1033/*jshint browser: true, undef: true, unused: true, strict: true */ 1034 1035( function( window, factory ) { 1036 // universal module definition 1037 /*jshint strict: false */ /*globals define, module, require */ 1038 1039 if ( typeof define == 'function' && define.amd ) { 1040 // AMD 1041 define( 'fizzy-ui-utils/utils',[ 1042 'desandro-matches-selector/matches-selector' 1043 ], function( matchesSelector ) { 1044 return factory( window, matchesSelector ); 1045 }); 1046 } else if ( typeof module == 'object' && module.exports ) { 1047 // CommonJS 1048 module.exports = factory( 1049 window, 1050 require('desandro-matches-selector') 1051 ); 1052 } else { 1053 // browser global 1054 window.fizzyUIUtils = factory( 1055 window, 1056 window.matchesSelector 1057 ); 1058 } 1059 1060}( window, function factory( window, matchesSelector ) { 1061 1062 1063 1064var utils = {}; 1065 1066// ----- extend ----- // 1067 1068// extends objects 1069utils.extend = function( a, b ) { 1070 for ( var prop in b ) { 1071 a[ prop ] = b[ prop ]; 1072 } 1073 return a; 1074}; 1075 1076// ----- modulo ----- // 1077 1078utils.modulo = function( num, div ) { 1079 return ( ( num % div ) + div ) % div; 1080}; 1081 1082// ----- makeArray ----- // 1083 1084var arraySlice = Array.prototype.slice; 1085 1086// turn element or nodeList into an array 1087utils.makeArray = function( obj ) { 1088 if ( Array.isArray( obj ) ) { 1089 // use object if already an array 1090 return obj; 1091 } 1092 // return empty array if undefined or null. #6 1093 if ( obj === null || obj === undefined ) { 1094 return []; 1095 } 1096 1097 var isArrayLike = typeof obj == 'object' && typeof obj.length == 'number'; 1098 if ( isArrayLike ) { 1099 // convert nodeList to array 1100 return arraySlice.call( obj ); 1101 } 1102 1103 // array of single index 1104 return [ obj ]; 1105}; 1106 1107// ----- removeFrom ----- // 1108 1109utils.removeFrom = function( ary, obj ) { 1110 var index = ary.indexOf( obj ); 1111 if ( index != -1 ) { 1112 ary.splice( index, 1 ); 1113 } 1114}; 1115 1116// ----- getParent ----- // 1117 1118utils.getParent = function( elem, selector ) { 1119 while ( elem.parentNode && elem != document.body ) { 1120 elem = elem.parentNode; 1121 if ( matchesSelector( elem, selector ) ) { 1122 return elem; 1123 } 1124 } 1125}; 1126 1127// ----- getQueryElement ----- // 1128 1129// use element as selector string 1130utils.getQueryElement = function( elem ) { 1131 if ( typeof elem == 'string' ) { 1132 return document.querySelector( elem ); 1133 } 1134 return elem; 1135}; 1136 1137// ----- handleEvent ----- // 1138 1139// enable .ontype to trigger from .addEventListener( elem, 'type' ) 1140utils.handleEvent = function( event ) { 1141 var method = 'on' + event.type; 1142 if ( this[ method ] ) { 1143 this[ method ]( event ); 1144 } 1145}; 1146 1147// ----- filterFindElements ----- // 1148 1149utils.filterFindElements = function( elems, selector ) { 1150 // make array of elems 1151 elems = utils.makeArray( elems ); 1152 var ffElems = []; 1153 1154 elems.forEach( function( elem ) { 1155 // check that elem is an actual element 1156 if ( !( elem instanceof HTMLElement ) ) { 1157 return; 1158 } 1159 // add elem if no selector 1160 if ( !selector ) { 1161 ffElems.push( elem ); 1162 return; 1163 } 1164 // filter & find items if we have a selector 1165 // filter 1166 if ( matchesSelector( elem, selector ) ) { 1167 ffElems.push( elem ); 1168 } 1169 // find children 1170 var childElems = elem.querySelectorAll( selector ); 1171 // concat childElems to filterFound array 1172 for ( var i=0; i < childElems.length; i++ ) { 1173 ffElems.push( childElems[i] ); 1174 } 1175 }); 1176 1177 return ffElems; 1178}; 1179 1180// ----- debounceMethod ----- // 1181 1182utils.debounceMethod = function( _class, methodName, threshold ) { 1183 threshold = threshold || 100; 1184 // original method 1185 var method = _class.prototype[ methodName ]; 1186 var timeoutName = methodName + 'Timeout'; 1187 1188 _class.prototype[ methodName ] = function() { 1189 var timeout = this[ timeoutName ]; 1190 clearTimeout( timeout ); 1191 1192 var args = arguments; 1193 var _this = this; 1194 this[ timeoutName ] = setTimeout( function() { 1195 method.apply( _this, args ); 1196 delete _this[ timeoutName ]; 1197 }, threshold ); 1198 }; 1199}; 1200 1201// ----- docReady ----- // 1202 1203utils.docReady = function( callback ) { 1204 var readyState = document.readyState; 1205 if ( readyState == 'complete' || readyState == 'interactive' ) { 1206 // do async to allow for other scripts to run. metafizzy/flickity#441 1207 setTimeout( callback ); 1208 } else { 1209 document.addEventListener( 'DOMContentLoaded', callback ); 1210 } 1211}; 1212 1213// ----- htmlInit ----- // 1214 1215// http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/ 1216utils.toDashed = function( str ) { 1217 return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) { 1218 return $1 + '-' + $2; 1219 }).toLowerCase(); 1220}; 1221 1222var console = window.console; 1223/** 1224 * allow user to initialize classes via [data-namespace] or .js-namespace class 1225 * htmlInit( Widget, 'widgetName' ) 1226 * options are parsed from data-namespace-options 1227 */ 1228utils.htmlInit = function( WidgetClass, namespace ) { 1229 utils.docReady( function() { 1230 var dashedNamespace = utils.toDashed( namespace ); 1231 var dataAttr = 'data-' + dashedNamespace; 1232 var dataAttrElems = document.querySelectorAll( '[' + dataAttr + ']' ); 1233 var jsDashElems = document.querySelectorAll( '.js-' + dashedNamespace ); 1234 var elems = utils.makeArray( dataAttrElems ) 1235 .concat( utils.makeArray( jsDashElems ) ); 1236 var dataOptionsAttr = dataAttr + '-options'; 1237 var jQuery = window.jQuery; 1238 1239 elems.forEach( function( elem ) { 1240 var attr = elem.getAttribute( dataAttr ) || 1241 elem.getAttribute( dataOptionsAttr ); 1242 var options; 1243 try { 1244 options = attr && JSON.parse( attr ); 1245 } catch ( error ) { 1246 // log error, do not initialize 1247 if ( console ) { 1248 console.error( 'Error parsing ' + dataAttr + ' on ' + elem.className + 1249 ': ' + error ); 1250 } 1251 return; 1252 } 1253 // initialize 1254 var instance = new WidgetClass( elem, options ); 1255 // make available via $().data('namespace') 1256 if ( jQuery ) { 1257 jQuery.data( elem, namespace, instance ); 1258 } 1259 }); 1260 1261 }); 1262}; 1263 1264// ----- ----- // 1265 1266return utils; 1267 1268})); 1269 1270/** 1271 * Outlayer Item 1272 */ 1273 1274( function( window, factory ) { 1275 // universal module definition 1276 /* jshint strict: false */ /* globals define, module, require */ 1277 if ( typeof define == 'function' && define.amd ) { 1278 // AMD - RequireJS 1279 define( 'outlayer/item',[ 1280 'ev-emitter/ev-emitter', 1281 'get-size/get-size' 1282 ], 1283 factory 1284 ); 1285 } else if ( typeof module == 'object' && module.exports ) { 1286 // CommonJS - Browserify, Webpack 1287 module.exports = factory( 1288 require('ev-emitter'), 1289 require('get-size') 1290 ); 1291 } else { 1292 // browser global 1293 window.Outlayer = {}; 1294 window.Outlayer.Item = factory( 1295 window.EvEmitter, 1296 window.getSize 1297 ); 1298 } 1299 1300}( window, function factory( EvEmitter, getSize ) { 1301'use strict'; 1302 1303// ----- helpers ----- // 1304 1305function isEmptyObj( obj ) { 1306 for ( var prop in obj ) { 1307 return false; 1308 } 1309 prop = null; 1310 return true; 1311} 1312 1313// -------------------------- CSS3 support -------------------------- // 1314 1315 1316var docElemStyle = document.documentElement.style; 1317 1318var transitionProperty = typeof docElemStyle.transition == 'string' ? 1319 'transition' : 'WebkitTransition'; 1320var transformProperty = typeof docElemStyle.transform == 'string' ? 1321 'transform' : 'WebkitTransform'; 1322 1323var transitionEndEvent = { 1324 WebkitTransition: 'webkitTransitionEnd', 1325 transition: 'transitionend' 1326}[ transitionProperty ]; 1327 1328// cache all vendor properties that could have vendor prefix 1329var vendorProperties = { 1330 transform: transformProperty, 1331 transition: transitionProperty, 1332 transitionDuration: transitionProperty + 'Duration', 1333 transitionProperty: transitionProperty + 'Property', 1334 transitionDelay: transitionProperty + 'Delay' 1335}; 1336 1337// -------------------------- Item -------------------------- // 1338 1339function Item( element, layout ) { 1340 if ( !element ) { 1341 return; 1342 } 1343 1344 this.element = element; 1345 // parent layout class, i.e. Masonry, Isotope, or Packery 1346 this.layout = layout; 1347 this.position = { 1348 x: 0, 1349 y: 0 1350 }; 1351 1352 this._create(); 1353} 1354 1355// inherit EvEmitter 1356var proto = Item.prototype = Object.create( EvEmitter.prototype ); 1357proto.constructor = Item; 1358 1359proto._create = function() { 1360 // transition objects 1361 this._transn = { 1362 ingProperties: {}, 1363 clean: {}, 1364 onEnd: {} 1365 }; 1366 1367 this.css({ 1368 position: 'absolute' 1369 }); 1370}; 1371 1372// trigger specified handler for event type 1373proto.handleEvent = function( event ) { 1374 var method = 'on' + event.type; 1375 if ( this[ method ] ) { 1376 this[ method ]( event ); 1377 } 1378}; 1379 1380proto.getSize = function() { 1381 this.size = getSize( this.element ); 1382}; 1383 1384/** 1385 * apply CSS styles to element 1386 * @param {Object} style 1387 */ 1388proto.css = function( style ) { 1389 var elemStyle = this.element.style; 1390 1391 for ( var prop in style ) { 1392 // use vendor property if available 1393 var supportedProp = vendorProperties[ prop ] || prop; 1394 elemStyle[ supportedProp ] = style[ prop ]; 1395 } 1396}; 1397 1398 // measure position, and sets it 1399proto.getPosition = function() { 1400 var style = getComputedStyle( this.element ); 1401 var isOriginLeft = this.layout._getOption('originLeft'); 1402 var isOriginTop = this.layout._getOption('originTop'); 1403 var xValue = style[ isOriginLeft ? 'left' : 'right' ]; 1404 var yValue = style[ isOriginTop ? 'top' : 'bottom' ]; 1405 var x = parseFloat( xValue ); 1406 var y = parseFloat( yValue ); 1407 // convert percent to pixels 1408 var layoutSize = this.layout.size; 1409 if ( xValue.indexOf('%') != -1 ) { 1410 x = ( x / 100 ) * layoutSize.width; 1411 } 1412 if ( yValue.indexOf('%') != -1 ) { 1413 y = ( y / 100 ) * layoutSize.height; 1414 } 1415 // clean up 'auto' or other non-integer values 1416 x = isNaN( x ) ? 0 : x; 1417 y = isNaN( y ) ? 0 : y; 1418 // remove padding from measurement 1419 x -= isOriginLeft ? layoutSize.paddingLeft : layoutSize.paddingRight; 1420 y -= isOriginTop ? layoutSize.paddingTop : layoutSize.paddingBottom; 1421 1422 this.position.x = x; 1423 this.position.y = y; 1424}; 1425 1426// set settled position, apply padding 1427proto.layoutPosition = function() { 1428 var layoutSize = this.layout.size; 1429 var style = {}; 1430 var isOriginLeft = this.layout._getOption('originLeft'); 1431 var isOriginTop = this.layout._getOption('originTop'); 1432 1433 // x 1434 var xPadding = isOriginLeft ? 'paddingLeft' : 'paddingRight'; 1435 var xProperty = isOriginLeft ? 'left' : 'right'; 1436 var xResetProperty = isOriginLeft ? 'right' : 'left'; 1437 1438 var x = this.position.x + layoutSize[ xPadding ]; 1439 // set in percentage or pixels 1440 style[ xProperty ] = this.getXValue( x ); 1441 // reset other property 1442 style[ xResetProperty ] = ''; 1443 1444 // y 1445 var yPadding = isOriginTop ? 'paddingTop' : 'paddingBottom'; 1446 var yProperty = isOriginTop ? 'top' : 'bottom'; 1447 var yResetProperty = isOriginTop ? 'bottom' : 'top'; 1448 1449 var y = this.position.y + layoutSize[ yPadding ]; 1450 // set in percentage or pixels 1451 style[ yProperty ] = this.getYValue( y ); 1452 // reset other property 1453 style[ yResetProperty ] = ''; 1454 1455 this.css( style ); 1456 this.emitEvent( 'layout', [ this ] ); 1457}; 1458 1459proto.getXValue = function( x ) { 1460 var isHorizontal = this.layout._getOption('horizontal'); 1461 return this.layout.options.percentPosition && !isHorizontal ? 1462 ( ( x / this.layout.size.width ) * 100 ) + '%' : x + 'px'; 1463}; 1464 1465proto.getYValue = function( y ) { 1466 var isHorizontal = this.layout._getOption('horizontal'); 1467 return this.layout.options.percentPosition && isHorizontal ? 1468 ( ( y / this.layout.size.height ) * 100 ) + '%' : y + 'px'; 1469}; 1470 1471proto._transitionTo = function( x, y ) { 1472 this.getPosition(); 1473 // get current x & y from top/left 1474 var curX = this.position.x; 1475 var curY = this.position.y; 1476 1477 var didNotMove = x == this.position.x && y == this.position.y; 1478 1479 // save end position 1480 this.setPosition( x, y ); 1481 1482 // if did not move and not transitioning, just go to layout 1483 if ( didNotMove && !this.isTransitioning ) { 1484 this.layoutPosition(); 1485 return; 1486 } 1487 1488 var transX = x - curX; 1489 var transY = y - curY; 1490 var transitionStyle = {}; 1491 transitionStyle.transform = this.getTranslate( transX, transY ); 1492 1493 this.transition({ 1494 to: transitionStyle, 1495 onTransitionEnd: { 1496 transform: this.layoutPosition 1497 }, 1498 isCleaning: true 1499 }); 1500}; 1501 1502proto.getTranslate = function( x, y ) { 1503 // flip cooridinates if origin on right or bottom 1504 var isOriginLeft = this.layout._getOption('originLeft'); 1505 var isOriginTop = this.layout._getOption('originTop'); 1506 x = isOriginLeft ? x : -x; 1507 y = isOriginTop ? y : -y; 1508 return 'translate3d(' + x + 'px, ' + y + 'px, 0)'; 1509}; 1510 1511// non transition + transform support 1512proto.goTo = function( x, y ) { 1513 this.setPosition( x, y ); 1514 this.layoutPosition(); 1515}; 1516 1517proto.moveTo = proto._transitionTo; 1518 1519proto.setPosition = function( x, y ) { 1520 this.position.x = parseFloat( x ); 1521 this.position.y = parseFloat( y ); 1522}; 1523 1524// ----- transition ----- // 1525 1526/** 1527 * @param {Object} style - CSS 1528 * @param {Function} onTransitionEnd 1529 */ 1530 1531// non transition, just trigger callback 1532proto._nonTransition = function( args ) { 1533 this.css( args.to ); 1534 if ( args.isCleaning ) { 1535 this._removeStyles( args.to ); 1536 } 1537 for ( var prop in args.onTransitionEnd ) { 1538 args.onTransitionEnd[ prop ].call( this ); 1539 } 1540}; 1541 1542/** 1543 * proper transition 1544 * @param {Object} args - arguments 1545 * @param {Object} to - style to transition to 1546 * @param {Object} from - style to start transition from 1547 * @param {Boolean} isCleaning - removes transition styles after transition 1548 * @param {Function} onTransitionEnd - callback 1549 */ 1550proto.transition = function( args ) { 1551 // redirect to nonTransition if no transition duration 1552 if ( !parseFloat( this.layout.options.transitionDuration ) ) { 1553 this._nonTransition( args ); 1554 return; 1555 } 1556 1557 var _transition = this._transn; 1558 // keep track of onTransitionEnd callback by css property 1559 for ( var prop in args.onTransitionEnd ) { 1560 _transition.onEnd[ prop ] = args.onTransitionEnd[ prop ]; 1561 } 1562 // keep track of properties that are transitioning 1563 for ( prop in args.to ) { 1564 _transition.ingProperties[ prop ] = true; 1565 // keep track of properties to clean up when transition is done 1566 if ( args.isCleaning ) { 1567 _transition.clean[ prop ] = true; 1568 } 1569 } 1570 1571 // set from styles 1572 if ( args.from ) { 1573 this.css( args.from ); 1574 // force redraw. http://blog.alexmaccaw.com/css-transitions 1575 var h = this.element.offsetHeight; 1576 // hack for JSHint to hush about unused var 1577 h = null; 1578 } 1579 // enable transition 1580 this.enableTransition( args.to ); 1581 // set styles that are transitioning 1582 this.css( args.to ); 1583 1584 this.isTransitioning = true; 1585 1586}; 1587 1588// dash before all cap letters, including first for 1589// WebkitTransform => -webkit-transform 1590function toDashedAll( str ) { 1591 return str.replace( /([A-Z])/g, function( $1 ) { 1592 return '-' + $1.toLowerCase(); 1593 }); 1594} 1595 1596var transitionProps = 'opacity,' + toDashedAll( transformProperty ); 1597 1598proto.enableTransition = function(/* style */) { 1599 // HACK changing transitionProperty during a transition 1600 // will cause transition to jump 1601 if ( this.isTransitioning ) { 1602 return; 1603 } 1604 1605 // make `transition: foo, bar, baz` from style object 1606 // HACK un-comment this when enableTransition can work 1607 // while a transition is happening 1608 // var transitionValues = []; 1609 // for ( var prop in style ) { 1610 // // dash-ify camelCased properties like WebkitTransition 1611 // prop = vendorProperties[ prop ] || prop; 1612 // transitionValues.push( toDashedAll( prop ) ); 1613 // } 1614 // munge number to millisecond, to match stagger 1615 var duration = this.layout.options.transitionDuration; 1616 duration = typeof duration == 'number' ? duration + 'ms' : duration; 1617 // enable transition styles 1618 this.css({ 1619 transitionProperty: transitionProps, 1620 transitionDuration: duration, 1621 transitionDelay: this.staggerDelay || 0 1622 }); 1623 // listen for transition end event 1624 this.element.addEventListener( transitionEndEvent, this, false ); 1625}; 1626 1627// ----- events ----- // 1628 1629proto.onwebkitTransitionEnd = function( event ) { 1630 this.ontransitionend( event ); 1631}; 1632 1633proto.onotransitionend = function( event ) { 1634 this.ontransitionend( event ); 1635}; 1636 1637// properties that I munge to make my life easier 1638var dashedVendorProperties = { 1639 '-webkit-transform': 'transform' 1640}; 1641 1642proto.ontransitionend = function( event ) { 1643 // disregard bubbled events from children 1644 if ( event.target !== this.element ) { 1645 return; 1646 } 1647 var _transition = this._transn; 1648 // get property name of transitioned property, convert to prefix-free 1649 var propertyName = dashedVendorProperties[ event.propertyName ] || event.propertyName; 1650 1651 // remove property that has completed transitioning 1652 delete _transition.ingProperties[ propertyName ]; 1653 // check if any properties are still transitioning 1654 if ( isEmptyObj( _transition.ingProperties ) ) { 1655 // all properties have completed transitioning 1656 this.disableTransition(); 1657 } 1658 // clean style 1659 if ( propertyName in _transition.clean ) { 1660 // clean up style 1661 this.element.style[ event.propertyName ] = ''; 1662 delete _transition.clean[ propertyName ]; 1663 } 1664 // trigger onTransitionEnd callback 1665 if ( propertyName in _transition.onEnd ) { 1666 var onTransitionEnd = _transition.onEnd[ propertyName ]; 1667 onTransitionEnd.call( this ); 1668 delete _transition.onEnd[ propertyName ]; 1669 } 1670 1671 this.emitEvent( 'transitionEnd', [ this ] ); 1672}; 1673 1674proto.disableTransition = function() { 1675 this.removeTransitionStyles(); 1676 this.element.removeEventListener( transitionEndEvent, this, false ); 1677 this.isTransitioning = false; 1678}; 1679 1680/** 1681 * removes style property from element 1682 * @param {Object} style 1683**/ 1684proto._removeStyles = function( style ) { 1685 // clean up transition styles 1686 var cleanStyle = {}; 1687 for ( var prop in style ) { 1688 cleanStyle[ prop ] = ''; 1689 } 1690 this.css( cleanStyle ); 1691}; 1692 1693var cleanTransitionStyle = { 1694 transitionProperty: '', 1695 transitionDuration: '', 1696 transitionDelay: '' 1697}; 1698 1699proto.removeTransitionStyles = function() { 1700 // remove transition 1701 this.css( cleanTransitionStyle ); 1702}; 1703 1704// ----- stagger ----- // 1705 1706proto.stagger = function( delay ) { 1707 delay = isNaN( delay ) ? 0 : delay; 1708 this.staggerDelay = delay + 'ms'; 1709}; 1710 1711// ----- show/hide/remove ----- // 1712 1713// remove element from DOM 1714proto.removeElem = function() { 1715 this.element.parentNode.removeChild( this.element ); 1716 // remove display: none 1717 this.css({ display: '' }); 1718 this.emitEvent( 'remove', [ this ] ); 1719}; 1720 1721proto.remove = function() { 1722 // just remove element if no transition support or no transition 1723 if ( !transitionProperty || !parseFloat( this.layout.options.transitionDuration ) ) { 1724 this.removeElem(); 1725 return; 1726 } 1727 1728 // start transition 1729 this.once( 'transitionEnd', function() { 1730 this.removeElem(); 1731 }); 1732 this.hide(); 1733}; 1734 1735proto.reveal = function() { 1736 delete this.isHidden; 1737 // remove display: none 1738 this.css({ display: '' }); 1739 1740 var options = this.layout.options; 1741 1742 var onTransitionEnd = {}; 1743 var transitionEndProperty = this.getHideRevealTransitionEndProperty('visibleStyle'); 1744 onTransitionEnd[ transitionEndProperty ] = this.onRevealTransitionEnd; 1745 1746 this.transition({ 1747 from: options.hiddenStyle, 1748 to: options.visibleStyle, 1749 isCleaning: true, 1750 onTransitionEnd: onTransitionEnd 1751 }); 1752}; 1753 1754proto.onRevealTransitionEnd = function() { 1755 // check if still visible 1756 // during transition, item may have been hidden 1757 if ( !this.isHidden ) { 1758 this.emitEvent('reveal'); 1759 } 1760}; 1761 1762/** 1763 * get style property use for hide/reveal transition end 1764 * @param {String} styleProperty - hiddenStyle/visibleStyle 1765 * @returns {String} 1766 */ 1767proto.getHideRevealTransitionEndProperty = function( styleProperty ) { 1768 var optionStyle = this.layout.options[ styleProperty ]; 1769 // use opacity 1770 if ( optionStyle.opacity ) { 1771 return 'opacity'; 1772 } 1773 // get first property 1774 for ( var prop in optionStyle ) { 1775 return prop; 1776 } 1777}; 1778 1779proto.hide = function() { 1780 // set flag 1781 this.isHidden = true; 1782 // remove display: none 1783 this.css({ display: '' }); 1784 1785 var options = this.layout.options; 1786 1787 var onTransitionEnd = {}; 1788 var transitionEndProperty = this.getHideRevealTransitionEndProperty('hiddenStyle'); 1789 onTransitionEnd[ transitionEndProperty ] = this.onHideTransitionEnd; 1790 1791 this.transition({ 1792 from: options.visibleStyle, 1793 to: options.hiddenStyle, 1794 // keep hidden stuff hidden 1795 isCleaning: true, 1796 onTransitionEnd: onTransitionEnd 1797 }); 1798}; 1799 1800proto.onHideTransitionEnd = function() { 1801 // check if still hidden 1802 // during transition, item may have been un-hidden 1803 if ( this.isHidden ) { 1804 this.css({ display: 'none' }); 1805 this.emitEvent('hide'); 1806 } 1807}; 1808 1809proto.destroy = function() { 1810 this.css({ 1811 position: '', 1812 left: '', 1813 right: '', 1814 top: '', 1815 bottom: '', 1816 transition: '', 1817 transform: '' 1818 }); 1819}; 1820 1821return Item; 1822 1823})); 1824 1825/*! 1826 * Outlayer v2.1.1 1827 * the brains and guts of a layout library 1828 * MIT license 1829 */ 1830 1831( function( window, factory ) { 1832 'use strict'; 1833 // universal module definition 1834 /* jshint strict: false */ /* globals define, module, require */ 1835 if ( typeof define == 'function' && define.amd ) { 1836 // AMD - RequireJS 1837 define( 'outlayer/outlayer',[ 1838 'ev-emitter/ev-emitter', 1839 'get-size/get-size', 1840 'fizzy-ui-utils/utils', 1841 './item' 1842 ], 1843 function( EvEmitter, getSize, utils, Item ) { 1844 return factory( window, EvEmitter, getSize, utils, Item); 1845 } 1846 ); 1847 } else if ( typeof module == 'object' && module.exports ) { 1848 // CommonJS - Browserify, Webpack 1849 module.exports = factory( 1850 window, 1851 require('ev-emitter'), 1852 require('get-size'), 1853 require('fizzy-ui-utils'), 1854 require('./item') 1855 ); 1856 } else { 1857 // browser global 1858 window.Outlayer = factory( 1859 window, 1860 window.EvEmitter, 1861 window.getSize, 1862 window.fizzyUIUtils, 1863 window.Outlayer.Item 1864 ); 1865 } 1866 1867}( window, function factory( window, EvEmitter, getSize, utils, Item ) { 1868'use strict'; 1869 1870// ----- vars ----- // 1871 1872var console = window.console; 1873var jQuery = window.jQuery; 1874var noop = function() {}; 1875 1876// -------------------------- Outlayer -------------------------- // 1877 1878// globally unique identifiers 1879var GUID = 0; 1880// internal store of all Outlayer intances 1881var instances = {}; 1882 1883 1884/** 1885 * @param {Element, String} element 1886 * @param {Object} options 1887 * @constructor 1888 */ 1889function Outlayer( element, options ) { 1890 var queryElement = utils.getQueryElement( element ); 1891 if ( !queryElement ) { 1892 if ( console ) { 1893 console.error( 'Bad element for ' + this.constructor.namespace + 1894 ': ' + ( queryElement || element ) ); 1895 } 1896 return; 1897 } 1898 this.element = queryElement; 1899 // add jQuery 1900 if ( jQuery ) { 1901 this.$element = jQuery( this.element ); 1902 } 1903 1904 // options 1905 this.options = utils.extend( {}, this.constructor.defaults ); 1906 this.option( options ); 1907 1908 // add id for Outlayer.getFromElement 1909 var id = ++GUID; 1910 this.element.outlayerGUID = id; // expando 1911 instances[ id ] = this; // associate via id 1912 1913 // kick it off 1914 this._create(); 1915 1916 var isInitLayout = this._getOption('initLayout'); 1917 if ( isInitLayout ) { 1918 this.layout(); 1919 } 1920} 1921 1922// settings are for internal use only 1923Outlayer.namespace = 'outlayer'; 1924Outlayer.Item = Item; 1925 1926// default options 1927Outlayer.defaults = { 1928 containerStyle: { 1929 position: 'relative' 1930 }, 1931 initLayout: true, 1932 originLeft: true, 1933 originTop: true, 1934 resize: true, 1935 resizeContainer: true, 1936 // item options 1937 transitionDuration: '0.4s', 1938 hiddenStyle: { 1939 opacity: 0, 1940 transform: 'scale(0.001)' 1941 }, 1942 visibleStyle: { 1943 opacity: 1, 1944 transform: 'scale(1)' 1945 } 1946}; 1947 1948var proto = Outlayer.prototype; 1949// inherit EvEmitter 1950utils.extend( proto, EvEmitter.prototype ); 1951 1952/** 1953 * set options 1954 * @param {Object} opts 1955 */ 1956proto.option = function( opts ) { 1957 utils.extend( this.options, opts ); 1958}; 1959 1960/** 1961 * get backwards compatible option value, check old name 1962 */ 1963proto._getOption = function( option ) { 1964 var oldOption = this.constructor.compatOptions[ option ]; 1965 return oldOption && this.options[ oldOption ] !== undefined ? 1966 this.options[ oldOption ] : this.options[ option ]; 1967}; 1968 1969Outlayer.compatOptions = { 1970 // currentName: oldName 1971 initLayout: 'isInitLayout', 1972 horizontal: 'isHorizontal', 1973 layoutInstant: 'isLayoutInstant', 1974 originLeft: 'isOriginLeft', 1975 originTop: 'isOriginTop', 1976 resize: 'isResizeBound', 1977 resizeContainer: 'isResizingContainer' 1978}; 1979 1980proto._create = function() { 1981 // get items from children 1982 this.reloadItems(); 1983 // elements that affect layout, but are not laid out 1984 this.stamps = []; 1985 this.stamp( this.options.stamp ); 1986 // set container style 1987 utils.extend( this.element.style, this.options.containerStyle ); 1988 1989 // bind resize method 1990 var canBindResize = this._getOption('resize'); 1991 if ( canBindResize ) { 1992 this.bindResize(); 1993 } 1994}; 1995 1996// goes through all children again and gets bricks in proper order 1997proto.reloadItems = function() { 1998 // collection of item elements 1999 this.items = this._itemize( this.element.children ); 2000}; 2001 2002 2003/** 2004 * turn elements into Outlayer.Items to be used in layout 2005 * @param {Array or NodeList or HTMLElement} elems 2006 * @returns {Array} items - collection of new Outlayer Items 2007 */ 2008proto._itemize = function( elems ) { 2009 2010 var itemElems = this._filterFindItemElements( elems ); 2011 var Item = this.constructor.Item; 2012 2013 // create new Outlayer Items for collection 2014 var items = []; 2015 for ( var i=0; i < itemElems.length; i++ ) { 2016 var elem = itemElems[i]; 2017 var item = new Item( elem, this ); 2018 items.push( item ); 2019 } 2020 2021 return items; 2022}; 2023 2024/** 2025 * get item elements to be used in layout 2026 * @param {Array or NodeList or HTMLElement} elems 2027 * @returns {Array} items - item elements 2028 */ 2029proto._filterFindItemElements = function( elems ) { 2030 return utils.filterFindElements( elems, this.options.itemSelector ); 2031}; 2032 2033/** 2034 * getter method for getting item elements 2035 * @returns {Array} elems - collection of item elements 2036 */ 2037proto.getItemElements = function() { 2038 return this.items.map( function( item ) { 2039 return item.element; 2040 }); 2041}; 2042 2043// ----- init & layout ----- // 2044 2045/** 2046 * lays out all items 2047 */ 2048proto.layout = function() { 2049 this._resetLayout(); 2050 this._manageStamps(); 2051 2052 // don't animate first layout 2053 var layoutInstant = this._getOption('layoutInstant'); 2054 var isInstant = layoutInstant !== undefined ? 2055 layoutInstant : !this._isLayoutInited; 2056 this.layoutItems( this.items, isInstant ); 2057 2058 // flag for initalized 2059 this._isLayoutInited = true; 2060}; 2061 2062// _init is alias for layout 2063proto._init = proto.layout; 2064 2065/** 2066 * logic before any new layout 2067 */ 2068proto._resetLayout = function() {
vendor: 13,499 bytes, lines 2069-2637
2069 this.getSize(); 2070}; 2071 2072 2073proto.getSize = function() { 2074 this.size = getSize( this.element ); 2075}; 2076 2077/** 2078 * get measurement from option, for columnWidth, rowHeight, gutter 2079 * if option is String -> get element from selector string, & get size of element 2080 * if option is Element -> get size of element 2081 * else use option as a number 2082 * 2083 * @param {String} measurement 2084 * @param {String} size - width or height 2085 * @private 2086 */ 2087proto._getMeasurement = function( measurement, size ) { 2088 var option = this.options[ measurement ]; 2089 var elem; 2090 if ( !option ) { 2091 // default to 0 2092 this[ measurement ] = 0; 2093 } else { 2094 // use option as an element 2095 if ( typeof option == 'string' ) { 2096 elem = this.element.querySelector( option ); 2097 } else if ( option instanceof HTMLElement ) { 2098 elem = option; 2099 } 2100 // use size of element, if element 2101 this[ measurement ] = elem ? getSize( elem )[ size ] : option; 2102 } 2103}; 2104 2105/** 2106 * layout a collection of item elements 2107 * @api public 2108 */ 2109proto.layoutItems = function( items, isInstant ) { 2110 items = this._getItemsForLayout( items ); 2111 2112 this._layoutItems( items, isInstant ); 2113 2114 this._postLayout(); 2115}; 2116 2117/** 2118 * get the items to be laid out 2119 * you may want to skip over some items 2120 * @param {Array} items 2121 * @returns {Array} items 2122 */ 2123proto._getItemsForLayout = function( items ) { 2124 return items.filter( function( item ) { 2125 return !item.isIgnored; 2126 }); 2127}; 2128 2129/** 2130 * layout items 2131 * @param {Array} items 2132 * @param {Boolean} isInstant 2133 */ 2134proto._layoutItems = function( items, isInstant ) { 2135 this._emitCompleteOnItems( 'layout', items ); 2136 2137 if ( !items || !items.length ) { 2138 // no items, emit event with empty array 2139 return; 2140 } 2141 2142 var queue = []; 2143 2144 items.forEach( function( item ) { 2145 // get x/y object from method 2146 var position = this._getItemLayoutPosition( item ); 2147 // enqueue 2148 position.item = item; 2149 position.isInstant = isInstant || item.isLayoutInstant; 2150 queue.push( position ); 2151 }, this ); 2152 2153 this._processLayoutQueue( queue ); 2154}; 2155 2156/** 2157 * get item layout position 2158 * @param {Outlayer.Item} item 2159 * @returns {Object} x and y position 2160 */ 2161proto._getItemLayoutPosition = function( /* item */ ) { 2162 return { 2163 x: 0, 2164 y: 0 2165 }; 2166}; 2167 2168/** 2169 * iterate over array and position each item 2170 * Reason being - separating this logic prevents 'layout invalidation' 2171 * thx @paul_irish 2172 * @param {Array} queue 2173 */ 2174proto._processLayoutQueue = function( queue ) { 2175 this.updateStagger(); 2176 queue.forEach( function( obj, i ) { 2177 this._positionItem( obj.item, obj.x, obj.y, obj.isInstant, i ); 2178 }, this ); 2179}; 2180 2181// set stagger from option in milliseconds number 2182proto.updateStagger = function() { 2183 var stagger = this.options.stagger; 2184 if ( stagger === null || stagger === undefined ) { 2185 this.stagger = 0; 2186 return; 2187 } 2188 this.stagger = getMilliseconds( stagger ); 2189 return this.stagger; 2190}; 2191 2192/** 2193 * Sets position of item in DOM 2194 * @param {Outlayer.Item} item 2195 * @param {Number} x - horizontal position 2196 * @param {Number} y - vertical position 2197 * @param {Boolean} isInstant - disables transitions 2198 */ 2199proto._positionItem = function( item, x, y, isInstant, i ) { 2200 if ( isInstant ) { 2201 // if not transition, just set CSS 2202 item.goTo( x, y ); 2203 } else { 2204 item.stagger( i * this.stagger ); 2205 item.moveTo( x, y ); 2206 } 2207}; 2208 2209/** 2210 * Any logic you want to do after each layout, 2211 * i.e. size the container 2212 */ 2213proto._postLayout = function() { 2214 this.resizeContainer(); 2215}; 2216 2217proto.resizeContainer = function() { 2218 var isResizingContainer = this._getOption('resizeContainer'); 2219 if ( !isResizingContainer ) { 2220 return; 2221 } 2222 var size = this._getContainerSize(); 2223 if ( size ) { 2224 this._setContainerMeasure( size.width, true ); 2225 this._setContainerMeasure( size.height, false ); 2226 } 2227}; 2228 2229/** 2230 * Sets width or height of container if returned 2231 * @returns {Object} size 2232 * @param {Number} width 2233 * @param {Number} height 2234 */ 2235proto._getContainerSize = noop; 2236 2237/** 2238 * @param {Number} measure - size of width or height 2239 * @param {Boolean} isWidth 2240 */ 2241proto._setContainerMeasure = function( measure, isWidth ) { 2242 if ( measure === undefined ) { 2243 return; 2244 } 2245 2246 var elemSize = this.size; 2247 // add padding and border width if border box 2248 if ( elemSize.isBorderBox ) { 2249 measure += isWidth ? elemSize.paddingLeft + elemSize.paddingRight + 2250 elemSize.borderLeftWidth + elemSize.borderRightWidth : 2251 elemSize.paddingBottom + elemSize.paddingTop + 2252 elemSize.borderTopWidth + elemSize.borderBottomWidth; 2253 } 2254 2255 measure = Math.max( measure, 0 ); 2256 this.element.style[ isWidth ? 'width' : 'height' ] = measure + 'px'; 2257}; 2258 2259/** 2260 * emit eventComplete on a collection of items events 2261 * @param {String} eventName 2262 * @param {Array} items - Outlayer.Items 2263 */ 2264proto._emitCompleteOnItems = function( eventName, items ) { 2265 var _this = this; 2266 function onComplete() { 2267 _this.dispatchEvent( eventName + 'Complete', null, [ items ] ); 2268 } 2269 2270 var count = items.length; 2271 if ( !items || !count ) { 2272 onComplete(); 2273 return; 2274 } 2275 2276 var doneCount = 0; 2277 function tick() { 2278 doneCount++; 2279 if ( doneCount == count ) { 2280 onComplete(); 2281 } 2282 } 2283 2284 // bind callback 2285 items.forEach( function( item ) { 2286 item.once( eventName, tick ); 2287 }); 2288}; 2289 2290/** 2291 * emits events via EvEmitter and jQuery events 2292 * @param {String} type - name of event 2293 * @param {Event} event - original event 2294 * @param {Array} args - extra arguments 2295 */ 2296proto.dispatchEvent = function( type, event, args ) { 2297 // add original event to arguments 2298 var emitArgs = event ? [ event ].concat( args ) : args; 2299 this.emitEvent( type, emitArgs ); 2300 2301 if ( jQuery ) { 2302 // set this.$element 2303 this.$element = this.$element || jQuery( this.element ); 2304 if ( event ) { 2305 // create jQuery event 2306 var $event = jQuery.Event( event ); 2307 $event.type = type; 2308 this.$element.trigger( $event, args ); 2309 } else { 2310 // just trigger with type if no event available 2311 this.$element.trigger( type, args ); 2312 } 2313 } 2314}; 2315 2316// -------------------------- ignore & stamps -------------------------- // 2317 2318 2319/** 2320 * keep item in collection, but do not lay it out 2321 * ignored items do not get skipped in layout 2322 * @param {Element} elem 2323 */ 2324proto.ignore = function( elem ) { 2325 var item = this.getItem( elem ); 2326 if ( item ) { 2327 item.isIgnored = true; 2328 } 2329}; 2330 2331/** 2332 * return item to layout collection 2333 * @param {Element} elem 2334 */ 2335proto.unignore = function( elem ) { 2336 var item = this.getItem( elem ); 2337 if ( item ) { 2338 delete item.isIgnored; 2339 } 2340}; 2341 2342/** 2343 * adds elements to stamps 2344 * @param {NodeList, Array, Element, or String} elems 2345 */ 2346proto.stamp = function( elems ) { 2347 elems = this._find( elems ); 2348 if ( !elems ) { 2349 return; 2350 } 2351 2352 this.stamps = this.stamps.concat( elems ); 2353 // ignore 2354 elems.forEach( this.ignore, this ); 2355}; 2356 2357/** 2358 * removes elements to stamps 2359 * @param {NodeList, Array, or Element} elems 2360 */ 2361proto.unstamp = function( elems ) { 2362 elems = this._find( elems ); 2363 if ( !elems ){ 2364 return; 2365 } 2366 2367 elems.forEach( function( elem ) { 2368 // filter out removed stamp elements 2369 utils.removeFrom( this.stamps, elem ); 2370 this.unignore( elem ); 2371 }, this ); 2372}; 2373 2374/** 2375 * finds child elements 2376 * @param {NodeList, Array, Element, or String} elems 2377 * @returns {Array} elems 2378 */ 2379proto._find = function( elems ) { 2380 if ( !elems ) { 2381 return; 2382 } 2383 // if string, use argument as selector string 2384 if ( typeof elems == 'string' ) { 2385 elems = this.element.querySelectorAll( elems ); 2386 } 2387 elems = utils.makeArray( elems ); 2388 return elems; 2389}; 2390 2391proto._manageStamps = function() { 2392 if ( !this.stamps || !this.stamps.length ) { 2393 return; 2394 } 2395 2396 this._getBoundingRect(); 2397 2398 this.stamps.forEach( this._manageStamp, this ); 2399}; 2400 2401// update boundingLeft / Top 2402proto._getBoundingRect = function() { 2403 // get bounding rect for container element 2404 var boundingRect = this.element.getBoundingClientRect(); 2405 var size = this.size; 2406 this._boundingRect = { 2407 left: boundingRect.left + size.paddingLeft + size.borderLeftWidth, 2408 top: boundingRect.top + size.paddingTop + size.borderTopWidth, 2409 right: boundingRect.right - ( size.paddingRight + size.borderRightWidth ), 2410 bottom: boundingRect.bottom - ( size.paddingBottom + size.borderBottomWidth ) 2411 }; 2412}; 2413 2414/** 2415 * @param {Element} stamp 2416**/ 2417proto._manageStamp = noop; 2418 2419/** 2420 * get x/y position of element relative to container element 2421 * @param {Element} elem 2422 * @returns {Object} offset - has left, top, right, bottom 2423 */ 2424proto._getElementOffset = function( elem ) { 2425 var boundingRect = elem.getBoundingClientRect(); 2426 var thisRect = this._boundingRect; 2427 var size = getSize( elem ); 2428 var offset = { 2429 left: boundingRect.left - thisRect.left - size.marginLeft, 2430 top: boundingRect.top - thisRect.top - size.marginTop, 2431 right: thisRect.right - boundingRect.right - size.marginRight, 2432 bottom: thisRect.bottom - boundingRect.bottom - size.marginBottom 2433 }; 2434 return offset; 2435}; 2436 2437// -------------------------- resize -------------------------- // 2438 2439// enable event handlers for listeners 2440// i.e. resize -> onresize 2441proto.handleEvent = utils.handleEvent; 2442 2443/** 2444 * Bind layout to window resizing 2445 */ 2446proto.bindResize = function() { 2447 window.addEventListener( 'resize', this ); 2448 this.isResizeBound = true; 2449}; 2450 2451/** 2452 * Unbind layout to window resizing 2453 */ 2454proto.unbindResize = function() { 2455 window.removeEventListener( 'resize', this ); 2456 this.isResizeBound = false; 2457}; 2458 2459proto.onresize = function() { 2460 this.resize(); 2461}; 2462 2463utils.debounceMethod( Outlayer, 'onresize', 100 ); 2464 2465proto.resize = function() { 2466 // don't trigger if size did not change 2467 // or if resize was unbound. See #9 2468 if ( !this.isResizeBound || !this.needsResizeLayout() ) { 2469 return; 2470 } 2471 2472 this.layout(); 2473}; 2474 2475/** 2476 * check if layout is needed post layout 2477 * @returns Boolean 2478 */ 2479proto.needsResizeLayout = function() { 2480 var size = getSize( this.element ); 2481 // check that this.size and size are there 2482 // IE8 triggers resize on body size change, so they might not be 2483 var hasSizes = this.size && size; 2484 return hasSizes && size.innerWidth !== this.size.innerWidth; 2485}; 2486 2487// -------------------------- methods -------------------------- // 2488 2489/** 2490 * add items to Outlayer instance 2491 * @param {Array or NodeList or Element} elems 2492 * @returns {Array} items - Outlayer.Items 2493**/ 2494proto.addItems = function( elems ) { 2495 var items = this._itemize( elems ); 2496 // add items to collection 2497 if ( items.length ) { 2498 this.items = this.items.concat( items ); 2499 } 2500 return items; 2501}; 2502 2503/** 2504 * Layout newly-appended item elements 2505 * @param {Array or NodeList or Element} elems 2506 */ 2507proto.appended = function( elems ) { 2508 var items = this.addItems( elems ); 2509 if ( !items.length ) { 2510 return; 2511 } 2512 // layout and reveal just the new items 2513 this.layoutItems( items, true ); 2514 this.reveal( items ); 2515}; 2516 2517/** 2518 * Layout prepended elements 2519 * @param {Array or NodeList or Element} elems 2520 */ 2521proto.prepended = function( elems ) { 2522 var items = this._itemize( elems ); 2523 if ( !items.length ) { 2524 return; 2525 } 2526 // add items to beginning of collection 2527 var previousItems = this.items.slice(0); 2528 this.items = items.concat( previousItems ); 2529 // start new layout 2530 this._resetLayout(); 2531 this._manageStamps(); 2532 // layout new stuff without transition 2533 this.layoutItems( items, true ); 2534 this.reveal( items ); 2535 // layout previous items 2536 this.layoutItems( previousItems ); 2537}; 2538 2539/** 2540 * reveal a collection of items 2541 * @param {Array of Outlayer.Items} items 2542 */ 2543proto.reveal = function( items ) { 2544 this._emitCompleteOnItems( 'reveal', items ); 2545 if ( !items || !items.length ) { 2546 return; 2547 } 2548 var stagger = this.updateStagger(); 2549 items.forEach( function( item, i ) { 2550 item.stagger( i * stagger ); 2551 item.reveal(); 2552 }); 2553}; 2554 2555/** 2556 * hide a collection of items 2557 * @param {Array of Outlayer.Items} items 2558 */ 2559proto.hide = function( items ) { 2560 this._emitCompleteOnItems( 'hide', items ); 2561 if ( !items || !items.length ) { 2562 return; 2563 } 2564 var stagger = this.updateStagger(); 2565 items.forEach( function( item, i ) { 2566 item.stagger( i * stagger ); 2567 item.hide(); 2568 }); 2569}; 2570 2571/** 2572 * reveal item elements 2573 * @param {Array}, {Element}, {NodeList} items 2574 */ 2575proto.revealItemElements = function( elems ) { 2576 var items = this.getItems( elems ); 2577 this.reveal( items ); 2578}; 2579 2580/** 2581 * hide item elements 2582 * @param {Array}, {Element}, {NodeList} items 2583 */ 2584proto.hideItemElements = function( elems ) { 2585 var items = this.getItems( elems ); 2586 this.hide( items ); 2587}; 2588 2589/** 2590 * get Outlayer.Item, given an Element 2591 * @param {Element} elem 2592 * @param {Function} callback 2593 * @returns {Outlayer.Item} item 2594 */ 2595proto.getItem = function( elem ) { 2596 // loop through items to get the one that matches 2597 for ( var i=0; i < this.items.length; i++ ) { 2598 var item = this.items[i]; 2599 if ( item.element == elem ) { 2600 // return item 2601 return item; 2602 } 2603 } 2604}; 2605 2606/** 2607 * get collection of Outlayer.Items, given Elements 2608 * @param {Array} elems 2609 * @returns {Array} items - Outlayer.Items 2610 */ 2611proto.getItems = function( elems ) { 2612 elems = utils.makeArray( elems ); 2613 var items = []; 2614 elems.forEach( function( elem ) { 2615 var item = this.getItem( elem ); 2616 if ( item ) { 2617 items.push( item ); 2618 } 2619 }, this ); 2620 2621 return items; 2622}; 2623 2624/** 2625 * remove element(s) from instance and DOM 2626 * @param {Array or NodeList or Element} elems 2627 */ 2628proto.remove = function( elems ) { 2629 var removeItems = this.getItems( elems ); 2630 2631 this._emitCompleteOnItems( 'remove', removeItems ); 2632 2633 // bail if no items to remove 2634 if ( !removeItems || !removeItems.length ) { 2635 return; 2636 } 2637
vendor: 38,285 bytes, lines 2638-4061
2638 removeItems.forEach( function( item ) { 2639 item.remove(); 2640 // remove item from collection 2641 utils.removeFrom( this.items, item ); 2642 }, this ); 2643}; 2644 2645// ----- destroy ----- // 2646 2647// remove and disable Outlayer instance 2648proto.destroy = function() { 2649 // clean up dynamic styles 2650 var style = this.element.style; 2651 style.height = ''; 2652 style.position = ''; 2653 style.width = ''; 2654 // destroy items 2655 this.items.forEach( function( item ) { 2656 item.destroy(); 2657 }); 2658 2659 this.unbindResize(); 2660 2661 var id = this.element.outlayerGUID; 2662 delete instances[ id ]; // remove reference to instance by id 2663 delete this.element.outlayerGUID; 2664 // remove data for jQuery 2665 if ( jQuery ) { 2666 jQuery.removeData( this.element, this.constructor.namespace ); 2667 } 2668 2669}; 2670 2671// -------------------------- data -------------------------- // 2672 2673/** 2674 * get Outlayer instance from element 2675 * @param {Element} elem 2676 * @returns {Outlayer} 2677 */ 2678Outlayer.data = function( elem ) { 2679 elem = utils.getQueryElement( elem ); 2680 var id = elem && elem.outlayerGUID; 2681 return id && instances[ id ]; 2682}; 2683 2684 2685// -------------------------- create Outlayer class -------------------------- // 2686 2687/** 2688 * create a layout class 2689 * @param {String} namespace 2690 */ 2691Outlayer.create = function( namespace, options ) { 2692 // sub-class Outlayer 2693 var Layout = subclass( Outlayer ); 2694 // apply new options and compatOptions 2695 Layout.defaults = utils.extend( {}, Outlayer.defaults ); 2696 utils.extend( Layout.defaults, options ); 2697 Layout.compatOptions = utils.extend( {}, Outlayer.compatOptions ); 2698 2699 Layout.namespace = namespace; 2700 2701 Layout.data = Outlayer.data; 2702 2703 // sub-class Item 2704 Layout.Item = subclass( Item ); 2705 2706 // -------------------------- declarative -------------------------- // 2707 2708 utils.htmlInit( Layout, namespace ); 2709 2710 // -------------------------- jQuery bridge -------------------------- // 2711 2712 // make into jQuery plugin 2713 if ( jQuery && jQuery.bridget ) { 2714 jQuery.bridget( namespace, Layout ); 2715 } 2716 2717 return Layout; 2718}; 2719 2720function subclass( Parent ) { 2721 function SubClass() { 2722 Parent.apply( this, arguments ); 2723 } 2724 2725 SubClass.prototype = Object.create( Parent.prototype ); 2726 SubClass.prototype.constructor = SubClass; 2727 2728 return SubClass; 2729} 2730 2731// ----- helpers ----- // 2732 2733// how many milliseconds are in each unit 2734var msUnits = { 2735 ms: 1, 2736 s: 1000 2737}; 2738 2739// munge time-like parameter into millisecond number 2740// '0.4s' -> 40 2741function getMilliseconds( time ) { 2742 if ( typeof time == 'number' ) { 2743 return time; 2744 } 2745 var matches = time.match( /(^\d*\.?\d*)(\w*)/ ); 2746 var num = matches && matches[1]; 2747 var unit = matches && matches[2]; 2748 if ( !num.length ) { 2749 return 0; 2750 } 2751 num = parseFloat( num ); 2752 var mult = msUnits[ unit ] || 1; 2753 return num * mult; 2754} 2755 2756// ----- fin ----- // 2757 2758// back in global 2759Outlayer.Item = Item; 2760 2761return Outlayer; 2762 2763})); 2764 2765/** 2766 * Isotope Item 2767**/ 2768 2769( function( window, factory ) { 2770 // universal module definition 2771 /* jshint strict: false */ /*globals define, module, require */ 2772 if ( typeof define == 'function' && define.amd ) { 2773 // AMD 2774 define( 'isotope-layout/js/item',[ 2775 'outlayer/outlayer' 2776 ], 2777 factory ); 2778 } else if ( typeof module == 'object' && module.exports ) { 2779 // CommonJS 2780 module.exports = factory( 2781 require('outlayer') 2782 ); 2783 } else { 2784 // browser global 2785 window.Isotope = window.Isotope || {}; 2786 window.Isotope.Item = factory( 2787 window.Outlayer 2788 ); 2789 } 2790 2791}( window, function factory( Outlayer ) { 2792'use strict'; 2793 2794// -------------------------- Item -------------------------- // 2795 2796// sub-class Outlayer Item 2797function Item() { 2798 Outlayer.Item.apply( this, arguments ); 2799} 2800 2801var proto = Item.prototype = Object.create( Outlayer.Item.prototype ); 2802 2803var _create = proto._create; 2804proto._create = function() { 2805 // assign id, used for original-order sorting 2806 this.id = this.layout.itemGUID++; 2807 _create.call( this ); 2808 this.sortData = {}; 2809}; 2810 2811proto.updateSortData = function() { 2812 if ( this.isIgnored ) { 2813 return; 2814 } 2815 // default sorters 2816 this.sortData.id = this.id; 2817 // for backward compatibility 2818 this.sortData['original-order'] = this.id; 2819 this.sortData.random = Math.random(); 2820 // go thru getSortData obj and apply the sorters 2821 var getSortData = this.layout.options.getSortData; 2822 var sorters = this.layout._sorters; 2823 for ( var key in getSortData ) { 2824 var sorter = sorters[ key ]; 2825 this.sortData[ key ] = sorter( this.element, this ); 2826 } 2827}; 2828 2829var _destroy = proto.destroy; 2830proto.destroy = function() { 2831 // call super 2832 _destroy.apply( this, arguments ); 2833 // reset display, #741 2834 this.css({ 2835 display: '' 2836 }); 2837}; 2838 2839return Item; 2840 2841})); 2842 2843/** 2844 * Isotope LayoutMode 2845 */ 2846 2847( function( window, factory ) { 2848 // universal module definition 2849 /* jshint strict: false */ /*globals define, module, require */ 2850 if ( typeof define == 'function' && define.amd ) { 2851 // AMD 2852 define( 'isotope-layout/js/layout-mode',[ 2853 'get-size/get-size', 2854 'outlayer/outlayer' 2855 ], 2856 factory ); 2857 } else if ( typeof module == 'object' && module.exports ) { 2858 // CommonJS 2859 module.exports = factory( 2860 require('get-size'), 2861 require('outlayer') 2862 ); 2863 } else { 2864 // browser global 2865 window.Isotope = window.Isotope || {}; 2866 window.Isotope.LayoutMode = factory( 2867 window.getSize, 2868 window.Outlayer 2869 ); 2870 } 2871 2872}( window, function factory( getSize, Outlayer ) { 2873 'use strict'; 2874 2875 // layout mode class 2876 function LayoutMode( isotope ) { 2877 this.isotope = isotope; 2878 // link properties 2879 if ( isotope ) { 2880 this.options = isotope.options[ this.namespace ]; 2881 this.element = isotope.element; 2882 this.items = isotope.filteredItems; 2883 this.size = isotope.size; 2884 } 2885 } 2886 2887 var proto = LayoutMode.prototype; 2888 2889 /** 2890 * some methods should just defer to default Outlayer method 2891 * and reference the Isotope instance as `this` 2892 **/ 2893 var facadeMethods = [ 2894 '_resetLayout', 2895 '_getItemLayoutPosition', 2896 '_manageStamp', 2897 '_getContainerSize', 2898 '_getElementOffset', 2899 'needsResizeLayout', 2900 '_getOption' 2901 ]; 2902 2903 facadeMethods.forEach( function( methodName ) { 2904 proto[ methodName ] = function() { 2905 return Outlayer.prototype[ methodName ].apply( this.isotope, arguments ); 2906 }; 2907 }); 2908 2909 // ----- ----- // 2910 2911 // for horizontal layout modes, check vertical size 2912 proto.needsVerticalResizeLayout = function() { 2913 // don't trigger if size did not change 2914 var size = getSize( this.isotope.element ); 2915 // check that this.size and size are there 2916 // IE8 triggers resize on body size change, so they might not be 2917 var hasSizes = this.isotope.size && size; 2918 return hasSizes && size.innerHeight != this.isotope.size.innerHeight; 2919 }; 2920 2921 // ----- measurements ----- // 2922 2923 proto._getMeasurement = function() { 2924 this.isotope._getMeasurement.apply( this, arguments ); 2925 }; 2926 2927 proto.getColumnWidth = function() { 2928 this.getSegmentSize( 'column', 'Width' ); 2929 }; 2930 2931 proto.getRowHeight = function() { 2932 this.getSegmentSize( 'row', 'Height' ); 2933 }; 2934 2935 /** 2936 * get columnWidth or rowHeight 2937 * segment: 'column' or 'row' 2938 * size 'Width' or 'Height' 2939 **/ 2940 proto.getSegmentSize = function( segment, size ) { 2941 var segmentName = segment + size; 2942 var outerSize = 'outer' + size; 2943 // columnWidth / outerWidth // rowHeight / outerHeight 2944 this._getMeasurement( segmentName, outerSize ); 2945 // got rowHeight or columnWidth, we can chill 2946 if ( this[ segmentName ] ) { 2947 return; 2948 } 2949 // fall back to item of first element 2950 var firstItemSize = this.getFirstItemSize(); 2951 this[ segmentName ] = firstItemSize && firstItemSize[ outerSize ] || 2952 // or size of container 2953 this.isotope.size[ 'inner' + size ]; 2954 }; 2955 2956 proto.getFirstItemSize = function() { 2957 var firstItem = this.isotope.filteredItems[0]; 2958 return firstItem && firstItem.element && getSize( firstItem.element ); 2959 }; 2960 2961 // ----- methods that should reference isotope ----- // 2962 2963 proto.layout = function() { 2964 this.isotope.layout.apply( this.isotope, arguments ); 2965 }; 2966 2967 proto.getSize = function() { 2968 this.isotope.getSize(); 2969 this.size = this.isotope.size; 2970 }; 2971 2972 // -------------------------- create -------------------------- // 2973 2974 LayoutMode.modes = {}; 2975 2976 LayoutMode.create = function( namespace, options ) { 2977 2978 function Mode() { 2979 LayoutMode.apply( this, arguments ); 2980 } 2981 2982 Mode.prototype = Object.create( proto ); 2983 Mode.prototype.constructor = Mode; 2984 2985 // default options 2986 if ( options ) { 2987 Mode.options = options; 2988 } 2989 2990 Mode.prototype.namespace = namespace; 2991 // register in Isotope 2992 LayoutMode.modes[ namespace ] = Mode; 2993 2994 return Mode; 2995 }; 2996 2997 return LayoutMode; 2998 2999})); 3000 3001/*! 3002 * Masonry v4.2.1 3003 * Cascading grid layout library 3004 * https://masonry.desandro.com 3005 * MIT License 3006 * by David DeSandro 3007 */ 3008 3009( function( window, factory ) { 3010 // universal module definition 3011 /* jshint strict: false */ /*globals define, module, require */ 3012 if ( typeof define == 'function' && define.amd ) { 3013 // AMD 3014 define( 'masonry-layout/masonry',[ 3015 'outlayer/outlayer', 3016 'get-size/get-size' 3017 ], 3018 factory ); 3019 } else if ( typeof module == 'object' && module.exports ) { 3020 // CommonJS 3021 module.exports = factory( 3022 require('outlayer'), 3023 require('get-size') 3024 ); 3025 } else { 3026 // browser global 3027 window.Masonry = factory( 3028 window.Outlayer, 3029 window.getSize 3030 ); 3031 } 3032 3033}( window, function factory( Outlayer, getSize ) { 3034 3035 3036 3037// -------------------------- masonryDefinition -------------------------- // 3038 3039 // create an Outlayer layout class 3040 var Masonry = Outlayer.create('masonry'); 3041 // isFitWidth -> fitWidth 3042 Masonry.compatOptions.fitWidth = 'isFitWidth'; 3043 3044 var proto = Masonry.prototype; 3045 3046 proto._resetLayout = function() { 3047 this.getSize(); 3048 this._getMeasurement( 'columnWidth', 'outerWidth' ); 3049 this._getMeasurement( 'gutter', 'outerWidth' ); 3050 this.measureColumns(); 3051 3052 // reset column Y 3053 this.colYs = []; 3054 for ( var i=0; i < this.cols; i++ ) { 3055 this.colYs.push( 0 ); 3056 } 3057 3058 this.maxY = 0; 3059 this.horizontalColIndex = 0; 3060 }; 3061 3062 proto.measureColumns = function() { 3063 this.getContainerWidth(); 3064 // if columnWidth is 0, default to outerWidth of first item 3065 if ( !this.columnWidth ) { 3066 var firstItem = this.items[0]; 3067 var firstItemElem = firstItem && firstItem.element; 3068 // columnWidth fall back to item of first element 3069 this.columnWidth = firstItemElem && getSize( firstItemElem ).outerWidth || 3070 // if first elem has no width, default to size of container 3071 this.containerWidth; 3072 } 3073 3074 var columnWidth = this.columnWidth += this.gutter; 3075 3076 // calculate columns 3077 var containerWidth = this.containerWidth + this.gutter; 3078 var cols = containerWidth / columnWidth; 3079 // fix rounding errors, typically with gutters 3080 var excess = columnWidth - containerWidth % columnWidth; 3081 // if overshoot is less than a pixel, round up, otherwise floor it 3082 var mathMethod = excess && excess < 1 ? 'round' : 'floor'; 3083 cols = Math[ mathMethod ]( cols ); 3084 this.cols = Math.max( cols, 1 ); 3085 }; 3086 3087 proto.getContainerWidth = function() { 3088 // container is parent if fit width 3089 var isFitWidth = this._getOption('fitWidth'); 3090 var container = isFitWidth ? this.element.parentNode : this.element; 3091 // check that this.size and size are there 3092 // IE8 triggers resize on body size change, so they might not be 3093 var size = getSize( container ); 3094 this.containerWidth = size && size.innerWidth; 3095 }; 3096 3097 proto._getItemLayoutPosition = function( item ) { 3098 item.getSize(); 3099 // how many columns does this brick span 3100 var remainder = item.size.outerWidth % this.columnWidth; 3101 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil'; 3102 // round if off by 1 pixel, otherwise use ceil 3103 var colSpan = Math[ mathMethod ]( item.size.outerWidth / this.columnWidth ); 3104 colSpan = Math.min( colSpan, this.cols ); 3105 // use horizontal or top column position 3106 var colPosMethod = this.options.horizontalOrder ? 3107 '_getHorizontalColPosition' : '_getTopColPosition'; 3108 var colPosition = this[ colPosMethod ]( colSpan, item ); 3109 // position the brick 3110 var position = { 3111 x: this.columnWidth * colPosition.col, 3112 y: colPosition.y 3113 }; 3114 // apply setHeight to necessary columns 3115 var setHeight = colPosition.y + item.size.outerHeight; 3116 var setMax = colSpan + colPosition.col; 3117 for ( var i = colPosition.col; i < setMax; i++ ) { 3118 this.colYs[i] = setHeight; 3119 } 3120 3121 return position; 3122 }; 3123 3124 proto._getTopColPosition = function( colSpan ) { 3125 var colGroup = this._getTopColGroup( colSpan ); 3126 // get the minimum Y value from the columns 3127 var minimumY = Math.min.apply( Math, colGroup ); 3128 3129 return { 3130 col: colGroup.indexOf( minimumY ), 3131 y: minimumY, 3132 }; 3133 }; 3134 3135 /** 3136 * @param {Number} colSpan - number of columns the element spans 3137 * @returns {Array} colGroup 3138 */ 3139 proto._getTopColGroup = function( colSpan ) { 3140 if ( colSpan < 2 ) { 3141 // if brick spans only one column, use all the column Ys 3142 return this.colYs; 3143 } 3144 3145 var colGroup = []; 3146 // how many different places could this brick fit horizontally 3147 var groupCount = this.cols + 1 - colSpan; 3148 // for each group potential horizontal position 3149 for ( var i = 0; i < groupCount; i++ ) { 3150 colGroup[i] = this._getColGroupY( i, colSpan ); 3151 } 3152 return colGroup; 3153 }; 3154 3155 proto._getColGroupY = function( col, colSpan ) { 3156 if ( colSpan < 2 ) { 3157 return this.colYs[ col ]; 3158 } 3159 // make an array of colY values for that one group 3160 var groupColYs = this.colYs.slice( col, col + colSpan ); 3161 // and get the max value of the array 3162 return Math.max.apply( Math, groupColYs ); 3163 }; 3164 3165 // get column position based on horizontal index. #873 3166 proto._getHorizontalColPosition = function( colSpan, item ) { 3167 var col = this.horizontalColIndex % this.cols; 3168 var isOver = colSpan > 1 && col + colSpan > this.cols; 3169 // shift to next row if item can't fit on current row 3170 col = isOver ? 0 : col; 3171 // don't let zero-size items take up space 3172 var hasSize = item.size.outerWidth && item.size.outerHeight; 3173 this.horizontalColIndex = hasSize ? col + colSpan : this.horizontalColIndex; 3174 3175 return { 3176 col: col, 3177 y: this._getColGroupY( col, colSpan ), 3178 }; 3179 }; 3180 3181 proto._manageStamp = function( stamp ) { 3182 var stampSize = getSize( stamp ); 3183 var offset = this._getElementOffset( stamp ); 3184 // get the columns that this stamp affects 3185 var isOriginLeft = this._getOption('originLeft'); 3186 var firstX = isOriginLeft ? offset.left : offset.right; 3187 var lastX = firstX + stampSize.outerWidth; 3188 var firstCol = Math.floor( firstX / this.columnWidth ); 3189 firstCol = Math.max( 0, firstCol ); 3190 var lastCol = Math.floor( lastX / this.columnWidth ); 3191 // lastCol should not go over if multiple of columnWidth #425 3192 lastCol -= lastX % this.columnWidth ? 0 : 1; 3193 lastCol = Math.min( this.cols - 1, lastCol ); 3194 // set colYs to bottom of the stamp 3195 3196 var isOriginTop = this._getOption('originTop'); 3197 var stampMaxY = ( isOriginTop ? offset.top : offset.bottom ) + 3198 stampSize.outerHeight; 3199 for ( var i = firstCol; i <= lastCol; i++ ) { 3200 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] ); 3201 } 3202 }; 3203 3204 proto._getContainerSize = function() { 3205 this.maxY = Math.max.apply( Math, this.colYs ); 3206 var size = { 3207 height: this.maxY 3208 }; 3209 3210 if ( this._getOption('fitWidth') ) { 3211 size.width = this._getContainerFitWidth(); 3212 } 3213 3214 return size; 3215 }; 3216 3217 proto._getContainerFitWidth = function() { 3218 var unusedCols = 0; 3219 // count unused columns 3220 var i = this.cols; 3221 while ( --i ) { 3222 if ( this.colYs[i] !== 0 ) { 3223 break; 3224 } 3225 unusedCols++; 3226 } 3227 // fit container to columns that have been used 3228 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter; 3229 }; 3230 3231 proto.needsResizeLayout = function() { 3232 var previousWidth = this.containerWidth; 3233 this.getContainerWidth(); 3234 return previousWidth != this.containerWidth; 3235 }; 3236 3237 return Masonry; 3238 3239})); 3240 3241/*! 3242 * Masonry layout mode 3243 * sub-classes Masonry 3244 * https://masonry.desandro.com 3245 */ 3246 3247( function( window, factory ) { 3248 // universal module definition 3249 /* jshint strict: false */ /*globals define, module, require */ 3250 if ( typeof define == 'function' && define.amd ) { 3251 // AMD 3252 define( 'isotope-layout/js/layout-modes/masonry',[ 3253 '../layout-mode', 3254 'masonry-layout/masonry' 3255 ], 3256 factory ); 3257 } else if ( typeof module == 'object' && module.exports ) { 3258 // CommonJS 3259 module.exports = factory( 3260 require('../layout-mode'), 3261 require('masonry-layout') 3262 ); 3263 } else { 3264 // browser global 3265 factory( 3266 window.Isotope.LayoutMode, 3267 window.Masonry 3268 ); 3269 } 3270 3271}( window, function factory( LayoutMode, Masonry ) { 3272'use strict'; 3273 3274// -------------------------- masonryDefinition -------------------------- // 3275 3276 // create an Outlayer layout class 3277 var MasonryMode = LayoutMode.create('masonry'); 3278 3279 var proto = MasonryMode.prototype; 3280 3281 var keepModeMethods = { 3282 _getElementOffset: true, 3283 layout: true, 3284 _getMeasurement: true 3285 }; 3286 3287 // inherit Masonry prototype 3288 for ( var method in Masonry.prototype ) { 3289 // do not inherit mode methods 3290 if ( !keepModeMethods[ method ] ) { 3291 proto[ method ] = Masonry.prototype[ method ]; 3292 } 3293 } 3294 3295 var measureColumns = proto.measureColumns; 3296 proto.measureColumns = function() { 3297 // set items, used if measuring first item 3298 this.items = this.isotope.filteredItems; 3299 measureColumns.call( this ); 3300 }; 3301 3302 // point to mode options for fitWidth 3303 var _getOption = proto._getOption; 3304 proto._getOption = function( option ) { 3305 if ( option == 'fitWidth' ) { 3306 return this.options.isFitWidth !== undefined ? 3307 this.options.isFitWidth : this.options.fitWidth; 3308 } 3309 return _getOption.apply( this.isotope, arguments ); 3310 }; 3311 3312 return MasonryMode; 3313 3314})); 3315 3316/** 3317 * fitRows layout mode 3318 */ 3319 3320( function( window, factory ) { 3321 // universal module definition 3322 /* jshint strict: false */ /*globals define, module, require */ 3323 if ( typeof define == 'function' && define.amd ) { 3324 // AMD 3325 define( 'isotope-layout/js/layout-modes/fit-rows',[ 3326 '../layout-mode' 3327 ], 3328 factory ); 3329 } else if ( typeof exports == 'object' ) { 3330 // CommonJS 3331 module.exports = factory( 3332 require('../layout-mode') 3333 ); 3334 } else { 3335 // browser global 3336 factory( 3337 window.Isotope.LayoutMode 3338 ); 3339 } 3340 3341}( window, function factory( LayoutMode ) { 3342'use strict'; 3343 3344var FitRows = LayoutMode.create('fitRows'); 3345 3346var proto = FitRows.prototype; 3347 3348proto._resetLayout = function() { 3349 this.x = 0; 3350 this.y = 0; 3351 this.maxY = 0; 3352 this._getMeasurement( 'gutter', 'outerWidth' ); 3353}; 3354 3355proto._getItemLayoutPosition = function( item ) { 3356 item.getSize(); 3357 3358 var itemWidth = item.size.outerWidth + this.gutter; 3359 // if this element cannot fit in the current row 3360 var containerWidth = this.isotope.size.innerWidth + this.gutter; 3361 if ( this.x !== 0 && itemWidth + this.x > containerWidth ) { 3362 this.x = 0; 3363 this.y = this.maxY; 3364 } 3365 3366 var position = { 3367 x: this.x, 3368 y: this.y 3369 }; 3370 3371 this.maxY = Math.max( this.maxY, this.y + item.size.outerHeight ); 3372 this.x += itemWidth; 3373 3374 return position; 3375}; 3376 3377proto._getContainerSize = function() { 3378 return { height: this.maxY }; 3379}; 3380 3381return FitRows; 3382 3383})); 3384 3385/** 3386 * vertical layout mode 3387 */ 3388 3389( function( window, factory ) { 3390 // universal module definition 3391 /* jshint strict: false */ /*globals define, module, require */ 3392 if ( typeof define == 'function' && define.amd ) { 3393 // AMD 3394 define( 'isotope-layout/js/layout-modes/vertical',[ 3395 '../layout-mode' 3396 ], 3397 factory ); 3398 } else if ( typeof module == 'object' && module.exports ) { 3399 // CommonJS 3400 module.exports = factory( 3401 require('../layout-mode') 3402 ); 3403 } else { 3404 // browser global 3405 factory( 3406 window.Isotope.LayoutMode 3407 ); 3408 } 3409 3410}( window, function factory( LayoutMode ) { 3411'use strict'; 3412 3413var Vertical = LayoutMode.create( 'vertical', { 3414 horizontalAlignment: 0 3415}); 3416 3417var proto = Vertical.prototype; 3418 3419proto._resetLayout = function() { 3420 this.y = 0; 3421}; 3422 3423proto._getItemLayoutPosition = function( item ) { 3424 item.getSize(); 3425 var x = ( this.isotope.size.innerWidth - item.size.outerWidth ) * 3426 this.options.horizontalAlignment; 3427 var y = this.y; 3428 this.y += item.size.outerHeight; 3429 return { x: x, y: y }; 3430}; 3431 3432proto._getContainerSize = function() { 3433 return { height: this.y }; 3434}; 3435 3436return Vertical; 3437 3438})); 3439 3440/*! 3441 * Isotope v3.0.6 3442 * 3443 * Licensed GPLv3 for open source use 3444 * or Isotope Commercial License for commercial use 3445 * 3446 * https://isotope.metafizzy.co 3447 * Copyright 2010-2018 Metafizzy 3448 */ 3449 3450( function( window, factory ) { 3451 // universal module definition 3452 /* jshint strict: false */ /*globals define, module, require */ 3453 if ( typeof define == 'function' && define.amd ) { 3454 // AMD 3455 define( [ 3456 'outlayer/outlayer', 3457 'get-size/get-size', 3458 'desandro-matches-selector/matches-selector', 3459 'fizzy-ui-utils/utils', 3460 'isotope-layout/js/item', 3461 'isotope-layout/js/layout-mode', 3462 // include default layout modes 3463 'isotope-layout/js/layout-modes/masonry', 3464 'isotope-layout/js/layout-modes/fit-rows', 3465 'isotope-layout/js/layout-modes/vertical' 3466 ], 3467 function( Outlayer, getSize, matchesSelector, utils, Item, LayoutMode ) { 3468 return factory( window, Outlayer, getSize, matchesSelector, utils, Item, LayoutMode ); 3469 }); 3470 } else if ( typeof module == 'object' && module.exports ) { 3471 // CommonJS 3472 module.exports = factory( 3473 window, 3474 require('outlayer'), 3475 require('get-size'), 3476 require('desandro-matches-selector'), 3477 require('fizzy-ui-utils'), 3478 require('isotope-layout/js/item'), 3479 require('isotope-layout/js/layout-mode'), 3480 // include default layout modes 3481 require('isotope-layout/js/layout-modes/masonry'), 3482 require('isotope-layout/js/layout-modes/fit-rows'), 3483 require('isotope-layout/js/layout-modes/vertical') 3484 ); 3485 } else { 3486 // browser global 3487 window.Isotope = factory( 3488 window, 3489 window.Outlayer, 3490 window.getSize, 3491 window.matchesSelector, 3492 window.fizzyUIUtils, 3493 window.Isotope.Item, 3494 window.Isotope.LayoutMode 3495 ); 3496 } 3497 3498}( window, function factory( window, Outlayer, getSize, matchesSelector, utils, 3499 Item, LayoutMode ) { 3500 3501 3502 3503// -------------------------- vars -------------------------- // 3504 3505var jQuery = window.jQuery; 3506 3507// -------------------------- helpers -------------------------- // 3508 3509var trim = String.prototype.trim ? 3510 function( str ) { 3511 return str.trim(); 3512 } : 3513 function( str ) { 3514 return str.replace( /^\s+|\s+$/g, '' ); 3515 }; 3516 3517// -------------------------- isotopeDefinition -------------------------- // 3518 3519 // create an Outlayer layout class 3520 var Isotope = Outlayer.create( 'isotope', { 3521 layoutMode: 'masonry', 3522 isJQueryFiltering: true, 3523 sortAscending: true 3524 }); 3525 3526 Isotope.Item = Item; 3527 Isotope.LayoutMode = LayoutMode; 3528 3529 var proto = Isotope.prototype; 3530 3531 proto._create = function() { 3532 this.itemGUID = 0; 3533 // functions that sort items 3534 this._sorters = {}; 3535 this._getSorters(); 3536 // call super 3537 Outlayer.prototype._create.call( this ); 3538 3539 // create layout modes 3540 this.modes = {}; 3541 // start filteredItems with all items 3542 this.filteredItems = this.items; 3543 // keep of track of sortBys 3544 this.sortHistory = [ 'original-order' ]; 3545 // create from registered layout modes 3546 for ( var name in LayoutMode.modes ) { 3547 this._initLayoutMode( name ); 3548 } 3549 }; 3550 3551 proto.reloadItems = function() { 3552 // reset item ID counter 3553 this.itemGUID = 0; 3554 // call super 3555 Outlayer.prototype.reloadItems.call( this ); 3556 }; 3557 3558 proto._itemize = function() { 3559 var items = Outlayer.prototype._itemize.apply( this, arguments ); 3560 // assign ID for original-order 3561 for ( var i=0; i < items.length; i++ ) { 3562 var item = items[i]; 3563 item.id = this.itemGUID++; 3564 } 3565 this._updateItemsSortData( items ); 3566 return items; 3567 }; 3568 3569 3570 // -------------------------- layout -------------------------- // 3571 3572 proto._initLayoutMode = function( name ) { 3573 var Mode = LayoutMode.modes[ name ]; 3574 // set mode options 3575 // HACK extend initial options, back-fill in default options 3576 var initialOpts = this.options[ name ] || {}; 3577 this.options[ name ] = Mode.options ? 3578 utils.extend( Mode.options, initialOpts ) : initialOpts; 3579 // init layout mode instance 3580 this.modes[ name ] = new Mode( this ); 3581 }; 3582 3583 3584 proto.layout = function() { 3585 // if first time doing layout, do all magic 3586 if ( !this._isLayoutInited && this._getOption('initLayout') ) { 3587 this.arrange(); 3588 return; 3589 } 3590 this._layout(); 3591 }; 3592 3593 // private method to be used in layout() & magic() 3594 proto._layout = function() { 3595 // don't animate first layout 3596 var isInstant = this._getIsInstant(); 3597 // layout flow 3598 this._resetLayout(); 3599 this._manageStamps(); 3600 this.layoutItems( this.filteredItems, isInstant ); 3601 3602 // flag for initalized 3603 this._isLayoutInited = true; 3604 }; 3605 3606 // filter + sort + layout 3607 proto.arrange = function( opts ) { 3608 // set any options pass 3609 this.option( opts ); 3610 this._getIsInstant(); 3611 // filter, sort, and layout 3612 3613 // filter 3614 var filtered = this._filter( this.items ); 3615 this.filteredItems = filtered.matches; 3616 3617 this._bindArrangeComplete(); 3618 3619 if ( this._isInstant ) { 3620 this._noTransition( this._hideReveal, [ filtered ] ); 3621 } else { 3622 this._hideReveal( filtered ); 3623 } 3624 3625 this._sort(); 3626 this._layout(); 3627 }; 3628 // alias to _init for main plugin method 3629 proto._init = proto.arrange; 3630 3631 proto._hideReveal = function( filtered ) { 3632 this.reveal( filtered.needReveal ); 3633 this.hide( filtered.needHide ); 3634 }; 3635 3636 // HACK 3637 // Don't animate/transition first layout 3638 // Or don't animate/transition other layouts 3639 proto._getIsInstant = function() { 3640 var isLayoutInstant = this._getOption('layoutInstant'); 3641 var isInstant = isLayoutInstant !== undefined ? isLayoutInstant : 3642 !this._isLayoutInited; 3643 this._isInstant = isInstant; 3644 return isInstant; 3645 }; 3646 3647 // listen for layoutComplete, hideComplete and revealComplete 3648 // to trigger arrangeComplete 3649 proto._bindArrangeComplete = function() { 3650 // listen for 3 events to trigger arrangeComplete 3651 var isLayoutComplete, isHideComplete, isRevealComplete; 3652 var _this = this; 3653 function arrangeParallelCallback() { 3654 if ( isLayoutComplete && isHideComplete && isRevealComplete ) { 3655 _this.dispatchEvent( 'arrangeComplete', null, [ _this.filteredItems ] ); 3656 } 3657 } 3658 this.once( 'layoutComplete', function() { 3659 isLayoutComplete = true; 3660 arrangeParallelCallback(); 3661 }); 3662 this.once( 'hideComplete', function() { 3663 isHideComplete = true; 3664 arrangeParallelCallback(); 3665 }); 3666 this.once( 'revealComplete', function() { 3667 isRevealComplete = true; 3668 arrangeParallelCallback(); 3669 }); 3670 }; 3671 3672 // -------------------------- filter -------------------------- // 3673 3674 proto._filter = function( items ) { 3675 var filter = this.options.filter; 3676 filter = filter || '*'; 3677 var matches = []; 3678 var hiddenMatched = []; 3679 var visibleUnmatched = []; 3680 3681 var test = this._getFilterTest( filter ); 3682 3683 // test each item 3684 for ( var i=0; i < items.length; i++ ) { 3685 var item = items[i]; 3686 if ( item.isIgnored ) { 3687 continue; 3688 } 3689 // add item to either matched or unmatched group 3690 var isMatched = test( item ); 3691 // item.isFilterMatched = isMatched; 3692 // add to matches if its a match 3693 if ( isMatched ) { 3694 matches.push( item ); 3695 } 3696 // add to additional group if item needs to be hidden or revealed 3697 if ( isMatched && item.isHidden ) { 3698 hiddenMatched.push( item ); 3699 } else if ( !isMatched && !item.isHidden ) { 3700 visibleUnmatched.push( item ); 3701 } 3702 } 3703 3704 // return collections of items to be manipulated 3705 return { 3706 matches: matches, 3707 needReveal: hiddenMatched, 3708 needHide: visibleUnmatched 3709 }; 3710 }; 3711 3712 // get a jQuery, function, or a matchesSelector test given the filter 3713 proto._getFilterTest = function( filter ) { 3714 if ( jQuery && this.options.isJQueryFiltering ) { 3715 // use jQuery 3716 return function( item ) { 3717 return jQuery( item.element ).is( filter ); 3718 }; 3719 } 3720 if ( typeof filter == 'function' ) { 3721 // use filter as function 3722 return function( item ) { 3723 return filter( item.element ); 3724 }; 3725 } 3726 // default, use filter as selector string 3727 return function( item ) { 3728 return matchesSelector( item.element, filter ); 3729 }; 3730 }; 3731 3732 // -------------------------- sorting -------------------------- // 3733 3734 /** 3735 * @params {Array} elems 3736 * @public 3737 */ 3738 proto.updateSortData = function( elems ) { 3739 // get items 3740 var items; 3741 if ( elems ) { 3742 elems = utils.makeArray( elems ); 3743 items = this.getItems( elems ); 3744 } else { 3745 // update all items if no elems provided 3746 items = this.items; 3747 } 3748 3749 this._getSorters(); 3750 this._updateItemsSortData( items ); 3751 }; 3752 3753 proto._getSorters = function() { 3754 var getSortData = this.options.getSortData; 3755 for ( var key in getSortData ) { 3756 var sorter = getSortData[ key ]; 3757 this._sorters[ key ] = mungeSorter( sorter ); 3758 } 3759 }; 3760 3761 /** 3762 * @params {Array} items - of Isotope.Items 3763 * @private 3764 */ 3765 proto._updateItemsSortData = function( items ) { 3766 // do not update if no items 3767 var len = items && items.length; 3768 3769 for ( var i=0; len && i < len; i++ ) { 3770 var item = items[i]; 3771 item.updateSortData(); 3772 } 3773 }; 3774 3775 // ----- munge sorter ----- // 3776 3777 // encapsulate this, as we just need mungeSorter 3778 // other functions in here are just for munging 3779 var mungeSorter = ( function() { 3780 // add a magic layer to sorters for convienent shorthands 3781 // `.foo-bar` will use the text of .foo-bar querySelector 3782 // `[foo-bar]` will use attribute 3783 // you can also add parser 3784 // `.foo-bar parseInt` will parse that as a number 3785 function mungeSorter( sorter ) { 3786 // if not a string, return function or whatever it is 3787 if ( typeof sorter != 'string' ) { 3788 return sorter; 3789 } 3790 // parse the sorter string 3791 var args = trim( sorter ).split(' '); 3792 var query = args[0]; 3793 // check if query looks like [an-attribute] 3794 var attrMatch = query.match( /^\[(.+)\]$/ ); 3795 var attr = attrMatch && attrMatch[1]; 3796 var getValue = getValueGetter( attr, query ); 3797 // use second argument as a parser 3798 var parser = Isotope.sortDataParsers[ args[1] ]; 3799 // parse the value, if there was a parser 3800 sorter = parser ? function( elem ) { 3801 return elem && parser( getValue( elem ) ); 3802 } : 3803 // otherwise just return value 3804 function( elem ) { 3805 return elem && getValue( elem ); 3806 }; 3807 3808 return sorter; 3809 } 3810 3811 // get an attribute getter, or get text of the querySelector 3812 function getValueGetter( attr, query ) { 3813 // if query looks like [foo-bar], get attribute 3814 if ( attr ) { 3815 return function getAttribute( elem ) { 3816 return elem.getAttribute( attr ); 3817 }; 3818 } 3819 3820 // otherwise, assume its a querySelector, and get its text 3821 return function getChildText( elem ) { 3822 var child = elem.querySelector( query ); 3823 return child && child.textContent; 3824 }; 3825 } 3826 3827 return mungeSorter; 3828 })(); 3829 3830 // parsers used in getSortData shortcut strings 3831 Isotope.sortDataParsers = { 3832 'parseInt': function( val ) { 3833 return parseInt( val, 10 ); 3834 }, 3835 'parseFloat': function( val ) { 3836 return parseFloat( val ); 3837 } 3838 }; 3839 3840 // ----- sort method ----- // 3841 3842 // sort filteredItem order 3843 proto._sort = function() { 3844 if ( !this.options.sortBy ) { 3845 return; 3846 } 3847 // keep track of sortBy History 3848 var sortBys = utils.makeArray( this.options.sortBy ); 3849 if ( !this._getIsSameSortBy( sortBys ) ) { 3850 // concat all sortBy and sortHistory, add to front, oldest goes in last 3851 this.sortHistory = sortBys.concat( this.sortHistory ); 3852 } 3853 // sort magic 3854 var itemSorter = getItemSorter( this.sortHistory, this.options.sortAscending ); 3855 this.filteredItems.sort( itemSorter ); 3856 }; 3857 3858 // check if sortBys is same as start of sortHistory 3859 proto._getIsSameSortBy = function( sortBys ) { 3860 for ( var i=0; i < sortBys.length; i++ ) { 3861 if ( sortBys[i] != this.sortHistory[i] ) { 3862 return false; 3863 } 3864 } 3865 return true; 3866 }; 3867 3868 // returns a function used for sorting 3869 function getItemSorter( sortBys, sortAsc ) { 3870 return function sorter( itemA, itemB ) { 3871 // cycle through all sortKeys 3872 for ( var i = 0; i < sortBys.length; i++ ) { 3873 var sortBy = sortBys[i]; 3874 var a = itemA.sortData[ sortBy ]; 3875 var b = itemB.sortData[ sortBy ]; 3876 if ( a > b || a < b ) { 3877 // if sortAsc is an object, use the value given the sortBy key 3878 var isAscending = sortAsc[ sortBy ] !== undefined ? sortAsc[ sortBy ] : sortAsc; 3879 var direction = isAscending ? 1 : -1; 3880 return ( a > b ? 1 : -1 ) * direction; 3881 } 3882 } 3883 return 0; 3884 }; 3885 } 3886 3887 // -------------------------- methods -------------------------- // 3888 3889 // get layout mode 3890 proto._mode = function() { 3891 var layoutMode = this.options.layoutMode; 3892 var mode = this.modes[ layoutMode ]; 3893 if ( !mode ) { 3894 // TODO console.error 3895 throw new Error( 'No layout mode: ' + layoutMode ); 3896 } 3897 // HACK sync mode's options 3898 // any options set after init for layout mode need to be synced 3899 mode.options = this.options[ layoutMode ]; 3900 return mode; 3901 }; 3902 3903 proto._resetLayout = function() { 3904 // trigger original reset layout 3905 Outlayer.prototype._resetLayout.call( this ); 3906 this._mode()._resetLayout(); 3907 }; 3908 3909 proto._getItemLayoutPosition = function( item ) { 3910 return this._mode()._getItemLayoutPosition( item ); 3911 }; 3912 3913 proto._manageStamp = function( stamp ) { 3914 this._mode()._manageStamp( stamp ); 3915 }; 3916 3917 proto._getContainerSize = function() { 3918 return this._mode()._getContainerSize(); 3919 }; 3920 3921 proto.needsResizeLayout = function() { 3922 return this._mode().needsResizeLayout(); 3923 }; 3924 3925 // -------------------------- adding & removing -------------------------- // 3926 3927 // HEADS UP overwrites default Outlayer appended 3928 proto.appended = function( elems ) { 3929 var items = this.addItems( elems ); 3930 if ( !items.length ) { 3931 return; 3932 } 3933 // filter, layout, reveal new items 3934 var filteredItems = this._filterRevealAdded( items ); 3935 // add to filteredItems 3936 this.filteredItems = this.filteredItems.concat( filteredItems ); 3937 }; 3938 3939 // HEADS UP overwrites default Outlayer prepended 3940 proto.prepended = function( elems ) { 3941 var items = this._itemize( elems ); 3942 if ( !items.length ) { 3943 return; 3944 } 3945 // start new layout 3946 this._resetLayout(); 3947 this._manageStamps(); 3948 // filter, layout, reveal new items 3949 var filteredItems = this._filterRevealAdded( items ); 3950 // layout previous items 3951 this.layoutItems( this.filteredItems ); 3952 // add to items and filteredItems 3953 this.filteredItems = filteredItems.concat( this.filteredItems ); 3954 this.items = items.concat( this.items ); 3955 }; 3956 3957 proto._filterRevealAdded = function( items ) { 3958 var filtered = this._filter( items ); 3959 this.hide( filtered.needHide ); 3960 // reveal all new items 3961 this.reveal( filtered.matches ); 3962 // layout new items, no transition 3963 this.layoutItems( filtered.matches, true ); 3964 return filtered.matches; 3965 }; 3966 3967 /** 3968 * Filter, sort, and layout newly-appended item elements 3969 * @param {Array or NodeList or Element} elems 3970 */ 3971 proto.insert = function( elems ) { 3972 var items = this.addItems( elems ); 3973 if ( !items.length ) { 3974 return; 3975 } 3976 // append item elements 3977 var i, item; 3978 var len = items.length; 3979 for ( i=0; i < len; i++ ) { 3980 item = items[i]; 3981 this.element.appendChild( item.element ); 3982 } 3983 // filter new stuff 3984 var filteredInsertItems = this._filter( items ).matches; 3985 // set flag 3986 for ( i=0; i < len; i++ ) { 3987 items[i].isLayoutInstant = true; 3988 } 3989 this.arrange(); 3990 // reset flag 3991 for ( i=0; i < len; i++ ) { 3992 delete items[i].isLayoutInstant; 3993 } 3994 this.reveal( filteredInsertItems ); 3995 }; 3996 3997 var _remove = proto.remove; 3998 proto.remove = function( elems ) { 3999 elems = utils.makeArray( elems ); 4000 var removeItems = this.getItems( elems ); 4001 // do regular thing 4002 _remove.call( this, elems ); 4003 // bail if no items to remove 4004 var len = removeItems && removeItems.length; 4005 // remove elems from filteredItems 4006 for ( var i=0; len && i < len; i++ ) { 4007 var item = removeItems[i]; 4008 // remove item from collection 4009 utils.removeFrom( this.filteredItems, item ); 4010 } 4011 }; 4012 4013 proto.shuffle = function() { 4014 // update random sortData 4015 for ( var i=0; i < this.items.length; i++ ) { 4016 var item = this.items[i]; 4017 item.sortData.random = Math.random(); 4018 } 4019 this.options.sortBy = 'random'; 4020 this._sort(); 4021 this._layout(); 4022 }; 4023 4024 /** 4025 * trigger fn without transition 4026 * kind of hacky to have this in the first place 4027 * @param {Function} fn 4028 * @param {Array} args 4029 * @returns ret 4030 * @private 4031 */ 4032 proto._noTransition = function( fn, args ) { 4033 // save transitionDuration before disabling 4034 var transitionDuration = this.options.transitionDuration; 4035 // disable transition 4036 this.options.transitionDuration = 0; 4037 // do it 4038 var returnValue = fn.apply( this, args ); 4039 // re-enable transition for reveal 4040 this.options.transitionDuration = transitionDuration; 4041 return returnValue; 4042 }; 4043 4044 // ----- helper methods ----- // 4045 4046 /** 4047 * getter method for getting filtered item elements 4048 * @returns {Array} elems - collection of item elements 4049 */ 4050 proto.getFilteredItemElements = function() { 4051 return this.filteredItems.map( function( item ) { 4052 return item.element; 4053 }); 4054 }; 4055 4056 // ----- ----- // 4057 4058 return Isotope; 4059 4060})); 4061
4062
vendor: 31,440 bytes, lines 4063-5301
4063/*! 4064 * Packery layout mode PACKAGED v2.0.1 4065 * sub-classes Packery 4066 */ 4067 4068/** 4069 * Rect 4070 * low-level utility class for basic geometry 4071 */ 4072 4073( function( window, factory ) { 4074 // universal module definition 4075 /* jshint strict: false */ /* globals define, module */ 4076 if ( typeof define == 'function' && define.amd ) { 4077 // AMD 4078 define( 'packery/js/rect',factory ); 4079 } else if ( typeof module == 'object' && module.exports ) { 4080 // CommonJS 4081 module.exports = factory(); 4082 } else { 4083 // browser global 4084 window.Packery = window.Packery || {}; 4085 window.Packery.Rect = factory(); 4086 } 4087 4088}( window, function factory() { 4089 4090 4091// -------------------------- Rect -------------------------- // 4092 4093function Rect( props ) { 4094 // extend properties from defaults 4095 for ( var prop in Rect.defaults ) { 4096 this[ prop ] = Rect.defaults[ prop ]; 4097 } 4098 4099 for ( prop in props ) { 4100 this[ prop ] = props[ prop ]; 4101 } 4102 4103} 4104 4105Rect.defaults = { 4106 x: 0, 4107 y: 0, 4108 width: 0, 4109 height: 0 4110}; 4111 4112var proto = Rect.prototype; 4113 4114/** 4115 * Determines whether or not this rectangle wholly encloses another rectangle or point. 4116 * @param {Rect} rect 4117 * @returns {Boolean} 4118**/ 4119proto.contains = function( rect ) { 4120 // points don't have width or height 4121 var otherWidth = rect.width || 0; 4122 var otherHeight = rect.height || 0; 4123 return this.x <= rect.x && 4124 this.y <= rect.y && 4125 this.x + this.width >= rect.x + otherWidth && 4126 this.y + this.height >= rect.y + otherHeight; 4127}; 4128 4129/** 4130 * Determines whether or not the rectangle intersects with another. 4131 * @param {Rect} rect 4132 * @returns {Boolean} 4133**/ 4134proto.overlaps = function( rect ) { 4135 var thisRight = this.x + this.width; 4136 var thisBottom = this.y + this.height; 4137 var rectRight = rect.x + rect.width; 4138 var rectBottom = rect.y + rect.height; 4139 4140 // http://stackoverflow.com/a/306332 4141 return this.x < rectRight && 4142 thisRight > rect.x && 4143 this.y < rectBottom && 4144 thisBottom > rect.y; 4145}; 4146 4147/** 4148 * @param {Rect} rect - the overlapping rect 4149 * @returns {Array} freeRects - rects representing the area around the rect 4150**/ 4151proto.getMaximalFreeRects = function( rect ) { 4152 4153 // if no intersection, return false 4154 if ( !this.overlaps( rect ) ) { 4155 return false; 4156 } 4157 4158 var freeRects = []; 4159 var freeRect; 4160 4161 var thisRight = this.x + this.width; 4162 var thisBottom = this.y + this.height; 4163 var rectRight = rect.x + rect.width; 4164 var rectBottom = rect.y + rect.height; 4165 4166 // top 4167 if ( this.y < rect.y ) { 4168 freeRect = new Rect({ 4169 x: this.x, 4170 y: this.y, 4171 width: this.width, 4172 height: rect.y - this.y 4173 }); 4174 freeRects.push( freeRect ); 4175 } 4176 4177 // right 4178 if ( thisRight > rectRight ) { 4179 freeRect = new Rect({ 4180 x: rectRight, 4181 y: this.y, 4182 width: thisRight - rectRight, 4183 height: this.height 4184 }); 4185 freeRects.push( freeRect ); 4186 } 4187 4188 // bottom 4189 if ( thisBottom > rectBottom ) { 4190 freeRect = new Rect({ 4191 x: this.x, 4192 y: rectBottom, 4193 width: this.width, 4194 height: thisBottom - rectBottom 4195 }); 4196 freeRects.push( freeRect ); 4197 } 4198 4199 // left 4200 if ( this.x < rect.x ) { 4201 freeRect = new Rect({ 4202 x: this.x, 4203 y: this.y, 4204 width: rect.x - this.x, 4205 height: this.height 4206 }); 4207 freeRects.push( freeRect ); 4208 } 4209 4210 return freeRects; 4211}; 4212 4213proto.canFit = function( rect ) { 4214 return this.width >= rect.width && this.height >= rect.height; 4215}; 4216 4217return Rect; 4218 4219})); 4220 4221/** 4222 * Packer 4223 * bin-packing algorithm 4224 */ 4225 4226( function( window, factory ) { 4227 // universal module definition 4228 /* jshint strict: false */ /* globals define, module, require */ 4229 if ( typeof define == 'function' && define.amd ) { 4230 // AMD 4231 define( 'packery/js/packer',[ './rect' ], factory ); 4232 } else if ( typeof module == 'object' && module.exports ) { 4233 // CommonJS 4234 module.exports = factory( 4235 require('./rect') 4236 ); 4237 } else { 4238 // browser global 4239 var Packery = window.Packery = window.Packery || {}; 4240 Packery.Packer = factory( Packery.Rect ); 4241 } 4242 4243}( window, function factory( Rect ) { 4244 4245 4246// -------------------------- Packer -------------------------- // 4247 4248/** 4249 * @param {Number} width 4250 * @param {Number} height 4251 * @param {String} sortDirection 4252 * topLeft for vertical, leftTop for horizontal 4253 */ 4254function Packer( width, height, sortDirection ) { 4255 this.width = width || 0; 4256 this.height = height || 0; 4257 this.sortDirection = sortDirection || 'downwardLeftToRight'; 4258 4259 this.reset(); 4260} 4261 4262var proto = Packer.prototype; 4263 4264proto.reset = function() { 4265 this.spaces = []; 4266 4267 var initialSpace = new Rect({ 4268 x: 0, 4269 y: 0, 4270 width: this.width, 4271 height: this.height 4272 }); 4273 4274 this.spaces.push( initialSpace ); 4275 // set sorter 4276 this.sorter = sorters[ this.sortDirection ] || sorters.downwardLeftToRight; 4277}; 4278 4279// change x and y of rect to fit with in Packer's available spaces 4280proto.pack = function( rect ) { 4281 for ( var i=0; i < this.spaces.length; i++ ) { 4282 var space = this.spaces[i]; 4283 if ( space.canFit( rect ) ) { 4284 this.placeInSpace( rect, space ); 4285 break; 4286 } 4287 } 4288}; 4289 4290proto.columnPack = function( rect ) { 4291 for ( var i=0; i < this.spaces.length; i++ ) { 4292 var space = this.spaces[i]; 4293 var canFitInSpaceColumn = space.x <= rect.x && 4294 space.x + space.width >= rect.x + rect.width && 4295 space.height >= rect.height - 0.01; // fudge number for rounding error 4296 if ( canFitInSpaceColumn ) { 4297 rect.y = space.y; 4298 this.placed( rect ); 4299 break; 4300 } 4301 } 4302}; 4303 4304proto.rowPack = function( rect ) { 4305 for ( var i=0; i < this.spaces.length; i++ ) { 4306 var space = this.spaces[i]; 4307 var canFitInSpaceRow = space.y <= rect.y && 4308 space.y + space.height >= rect.y + rect.height && 4309 space.width >= rect.width - 0.01; // fudge number for rounding error 4310 if ( canFitInSpaceRow ) { 4311 rect.x = space.x; 4312 this.placed( rect ); 4313 break; 4314 } 4315 } 4316}; 4317 4318proto.placeInSpace = function( rect, space ) { 4319 // place rect in space 4320 rect.x = space.x; 4321 rect.y = space.y; 4322 4323 this.placed( rect ); 4324}; 4325 4326// update spaces with placed rect 4327proto.placed = function( rect ) { 4328 // update spaces 4329 var revisedSpaces = []; 4330 for ( var i=0; i < this.spaces.length; i++ ) { 4331 var space = this.spaces[i]; 4332 var newSpaces = space.getMaximalFreeRects( rect ); 4333 // add either the original space or the new spaces to the revised spaces 4334 if ( newSpaces ) { 4335 revisedSpaces.push.apply( revisedSpaces, newSpaces ); 4336 } else { 4337 revisedSpaces.push( space ); 4338 } 4339 } 4340 4341 this.spaces = revisedSpaces; 4342 4343 this.mergeSortSpaces(); 4344}; 4345 4346proto.mergeSortSpaces = function() { 4347 // remove redundant spaces 4348 Packer.mergeRects( this.spaces ); 4349 this.spaces.sort( this.sorter ); 4350}; 4351 4352// add a space back 4353proto.addSpace = function( rect ) { 4354 this.spaces.push( rect ); 4355 this.mergeSortSpaces(); 4356}; 4357 4358// -------------------------- utility functions -------------------------- // 4359 4360/** 4361 * Remove redundant rectangle from array of rectangles 4362 * @param {Array} rects: an array of Rects 4363 * @returns {Array} rects: an array of Rects 4364**/ 4365Packer.mergeRects = function( rects ) { 4366 var i = 0; 4367 var rect = rects[i]; 4368 4369 rectLoop: 4370 while ( rect ) { 4371 var j = 0; 4372 var compareRect = rects[ i + j ]; 4373 4374 while ( compareRect ) { 4375 if ( compareRect == rect ) { 4376 j++; // next 4377 } else if ( compareRect.contains( rect ) ) { 4378 // remove rect 4379 rects.splice( i, 1 ); 4380 rect = rects[i]; // set next rect 4381 continue rectLoop; // bail on compareLoop 4382 } else if ( rect.contains( compareRect ) ) { 4383 // remove compareRect 4384 rects.splice( i + j, 1 ); 4385 } else { 4386 j++; 4387 } 4388 compareRect = rects[ i + j ]; // set next compareRect 4389 } 4390 i++; 4391 rect = rects[i]; 4392 } 4393 4394 return rects; 4395}; 4396 4397 4398// -------------------------- sorters -------------------------- // 4399 4400// functions for sorting rects in order 4401var sorters = { 4402 // top down, then left to right 4403 downwardLeftToRight: function( a, b ) { 4404 return a.y - b.y || a.x - b.x; 4405 }, 4406 // left to right, then top down 4407 rightwardTopToBottom: function( a, b ) { 4408 return a.x - b.x || a.y - b.y; 4409 } 4410}; 4411 4412 4413// -------------------------- -------------------------- // 4414 4415return Packer; 4416 4417})); 4418 4419/** 4420 * Packery Item Element 4421**/ 4422 4423( function( window, factory ) { 4424 // universal module definition 4425 /* jshint strict: false */ /* globals define, module, require */ 4426 if ( typeof define == 'function' && define.amd ) { 4427 // AMD 4428 define( 'packery/js/item',[ 4429 'outlayer/outlayer', 4430 './rect' 4431 ], 4432 factory ); 4433 } else if ( typeof module == 'object' && module.exports ) { 4434 // CommonJS 4435 module.exports = factory( 4436 require('outlayer'), 4437 require('./rect') 4438 ); 4439 } else { 4440 // browser global 4441 window.Packery.Item = factory( 4442 window.Outlayer, 4443 window.Packery.Rect 4444 ); 4445 } 4446 4447}( window, function factory( Outlayer, Rect ) { 4448 4449 4450// -------------------------- Item -------------------------- // 4451 4452var docElemStyle = document.documentElement.style; 4453 4454var transformProperty = typeof docElemStyle.transform == 'string' ? 4455 'transform' : 'WebkitTransform'; 4456 4457// sub-class Item 4458var Item = function PackeryItem() { 4459 Outlayer.Item.apply( this, arguments ); 4460}; 4461 4462var proto = Item.prototype = Object.create( Outlayer.Item.prototype ); 4463 4464var __create = proto._create; 4465proto._create = function() { 4466 // call default _create logic 4467 __create.call( this ); 4468 this.rect = new Rect(); 4469}; 4470 4471var _moveTo = proto.moveTo; 4472proto.moveTo = function( x, y ) { 4473 // don't shift 1px while dragging 4474 var dx = Math.abs( this.position.x - x ); 4475 var dy = Math.abs( this.position.y - y ); 4476 4477 var canHackGoTo = this.layout.dragItemCount && !this.isPlacing && 4478 !this.isTransitioning && dx < 1 && dy < 1; 4479 if ( canHackGoTo ) { 4480 this.goTo( x, y ); 4481 return; 4482 } 4483 _moveTo.apply( this, arguments ); 4484}; 4485 4486// -------------------------- placing -------------------------- // 4487 4488proto.enablePlacing = function() { 4489 this.removeTransitionStyles(); 4490 // remove transform property from transition 4491 if ( this.isTransitioning && transformProperty ) { 4492 this.element.style[ transformProperty ] = 'none'; 4493 } 4494 this.isTransitioning = false; 4495 this.getSize(); 4496 this.layout._setRectSize( this.element, this.rect ); 4497 this.isPlacing = true; 4498}; 4499 4500proto.disablePlacing = function() { 4501 this.isPlacing = false; 4502}; 4503 4504// ----- ----- // 4505 4506// remove element from DOM 4507proto.removeElem = function() { 4508 this.element.parentNode.removeChild( this.element ); 4509 // add space back to packer 4510 this.layout.packer.addSpace( this.rect ); 4511 this.emitEvent( 'remove', [ this ] ); 4512}; 4513 4514// ----- dropPlaceholder ----- // 4515 4516proto.showDropPlaceholder = function() { 4517 var dropPlaceholder = this.dropPlaceholder; 4518 if ( !dropPlaceholder ) { 4519 // create dropPlaceholder 4520 dropPlaceholder = this.dropPlaceholder = document.createElement('div'); 4521 dropPlaceholder.className = 'packery-drop-placeholder'; 4522 dropPlaceholder.style.position = 'absolute'; 4523 } 4524 4525 dropPlaceholder.style.width = this.size.width + 'px'; 4526 dropPlaceholder.style.height = this.size.height + 'px'; 4527 this.positionDropPlaceholder(); 4528 this.layout.element.appendChild( dropPlaceholder ); 4529}; 4530 4531proto.positionDropPlaceholder = function() { 4532 this.dropPlaceholder.style[ transformProperty ] = 'translate(' + 4533 this.rect.x + 'px, ' + this.rect.y + 'px)'; 4534}; 4535 4536proto.hideDropPlaceholder = function() { 4537 this.layout.element.removeChild( this.dropPlaceholder ); 4538}; 4539 4540// ----- ----- // 4541 4542return Item; 4543 4544})); 4545 4546/*! 4547 * Packery v2.0.0 4548 * Gapless, draggable grid layouts 4549 * 4550 * Licensed GPLv3 for open source use 4551 * or Packery Commercial License for commercial use 4552 * 4553 * http://packery.metafizzy.co 4554 * Copyright 2016 Metafizzy 4555 */ 4556 4557( function( window, factory ) { 4558 // universal module definition 4559 /* jshint strict: false */ /* globals define, module, require */ 4560 if ( typeof define == 'function' && define.amd ) { 4561 // AMD 4562 define( 'packery/js/packery',[ 4563 'get-size/get-size', 4564 'outlayer/outlayer', 4565 './rect', 4566 './packer', 4567 './item' 4568 ], 4569 factory ); 4570 } else if ( typeof module == 'object' && module.exports ) { 4571 // CommonJS 4572 module.exports = factory( 4573 require('get-size'), 4574 require('outlayer'), 4575 require('./rect'), 4576 require('./packer'), 4577 require('./item') 4578 ); 4579 } else { 4580 // browser global 4581 window.Packery = factory( 4582 window.getSize, 4583 window.Outlayer, 4584 window.Packery.Rect, 4585 window.Packery.Packer, 4586 window.Packery.Item 4587 ); 4588 } 4589 4590}( window, function factory( getSize, Outlayer, Rect, Packer, Item ) { 4591 4592 4593// ----- Rect ----- // 4594 4595// allow for pixel rounding errors IE8-IE11 & Firefox; #227 4596Rect.prototype.canFit = function( rect ) { 4597 return this.width >= rect.width - 1 && this.height >= rect.height - 1; 4598}; 4599 4600// -------------------------- Packery -------------------------- // 4601 4602// create an Outlayer layout class 4603var Packery = Outlayer.create('packery'); 4604Packery.Item = Item; 4605 4606var proto = Packery.prototype; 4607 4608proto._create = function() { 4609 // call super 4610 Outlayer.prototype._create.call( this ); 4611 4612 // initial properties 4613 this.packer = new Packer(); 4614 // packer for drop targets 4615 this.shiftPacker = new Packer(); 4616 this.isEnabled = true; 4617 4618 this.dragItemCount = 0; 4619 4620 // create drag handlers 4621 var _this = this; 4622 this.handleDraggabilly = { 4623 dragStart: function() { 4624 _this.itemDragStart( this.element ); 4625 }, 4626 dragMove: function() { 4627 _this.itemDragMove( this.element, this.position.x, this.position.y ); 4628 }, 4629 dragEnd: function() { 4630 _this.itemDragEnd( this.element ); 4631 } 4632 }; 4633 4634 this.handleUIDraggable = { 4635 start: function handleUIDraggableStart( event, ui ) { 4636 // HTML5 may trigger dragstart, dismiss HTML5 dragging 4637 if ( !ui ) { 4638 return; 4639 } 4640 _this.itemDragStart( event.currentTarget ); 4641 }, 4642 drag: function handleUIDraggableDrag( event, ui ) { 4643 if ( !ui ) { 4644 return; 4645 } 4646 _this.itemDragMove( event.currentTarget, ui.position.left, ui.position.top ); 4647 }, 4648 stop: function handleUIDraggableStop( event, ui ) { 4649 if ( !ui ) { 4650 return; 4651 } 4652 _this.itemDragEnd( event.currentTarget ); 4653 } 4654 }; 4655 4656}; 4657 4658 4659// ----- init & layout ----- // 4660 4661/** 4662 * logic before any new layout 4663 */ 4664proto._resetLayout = function() { 4665 this.getSize(); 4666 4667 this._getMeasurements(); 4668 4669 // reset packer 4670 var width, height, sortDirection; 4671 // packer settings, if horizontal or vertical 4672 if ( this._getOption('horizontal') ) { 4673 width = Infinity; 4674 height = this.size.innerHeight + this.gutter; 4675 sortDirection = 'rightwardTopToBottom'; 4676 } else { 4677 width = this.size.innerWidth + this.gutter; 4678 height = Infinity; 4679 sortDirection = 'downwardLeftToRight'; 4680 } 4681 4682 this.packer.width = this.shiftPacker.width = width; 4683 this.packer.height = this.shiftPacker.height = height; 4684 this.packer.sortDirection = this.shiftPacker.sortDirection = sortDirection; 4685 4686 this.packer.reset(); 4687 4688 // layout 4689 this.maxY = 0; 4690 this.maxX = 0; 4691}; 4692 4693/** 4694 * update columnWidth, rowHeight, & gutter 4695 * @private 4696 */ 4697proto._getMeasurements = function() { 4698 this._getMeasurement( 'columnWidth', 'width' ); 4699 this._getMeasurement( 'rowHeight', 'height' ); 4700 this._getMeasurement( 'gutter', 'width' ); 4701}; 4702 4703proto._getItemLayoutPosition = function( item ) { 4704 this._setRectSize( item.element, item.rect ); 4705 if ( this.isShifting || this.dragItemCount > 0 ) { 4706 var packMethod = this._getPackMethod(); 4707 this.packer[ packMethod ]( item.rect ); 4708 } else { 4709 this.packer.pack( item.rect ); 4710 } 4711 4712 this._setMaxXY( item.rect ); 4713 return item.rect; 4714}; 4715 4716proto.shiftLayout = function() { 4717 this.isShifting = true; 4718 this.layout(); 4719 delete this.isShifting; 4720}; 4721 4722proto._getPackMethod = function() { 4723 return this._getOption('horizontal') ? 'rowPack' : 'columnPack'; 4724}; 4725 4726 4727/** 4728 * set max X and Y value, for size of container 4729 * @param {Packery.Rect} rect 4730 * @private 4731 */ 4732proto._setMaxXY = function( rect ) { 4733 this.maxX = Math.max( rect.x + rect.width, this.maxX ); 4734 this.maxY = Math.max( rect.y + rect.height, this.maxY ); 4735}; 4736 4737/** 4738 * set the width and height of a rect, applying columnWidth and rowHeight 4739 * @param {Element} elem 4740 * @param {Packery.Rect} rect 4741 */ 4742proto._setRectSize = function( elem, rect ) { 4743 var size = getSize( elem ); 4744 var w = size.outerWidth; 4745 var h = size.outerHeight; 4746 // size for columnWidth and rowHeight, if available 4747 // only check if size is non-zero, #177 4748 if ( w || h ) { 4749 w = this._applyGridGutter( w, this.columnWidth ); 4750 h = this._applyGridGutter( h, this.rowHeight ); 4751 } 4752 // rect must fit in packer 4753 rect.width = Math.min( w, this.packer.width ); 4754 rect.height = Math.min( h, this.packer.height ); 4755}; 4756 4757/** 4758 * fits item to columnWidth/rowHeight and adds gutter 4759 * @param {Number} measurement - item width or height 4760 * @param {Number} gridSize - columnWidth or rowHeight 4761 * @returns measurement 4762 */ 4763proto._applyGridGutter = function( measurement, gridSize ) { 4764 // just add gutter if no gridSize 4765 if ( !gridSize ) { 4766 return measurement + this.gutter; 4767 } 4768 gridSize += this.gutter; 4769 // fit item to columnWidth/rowHeight 4770 var remainder = measurement % gridSize; 4771 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil'; 4772 measurement = Math[ mathMethod ]( measurement / gridSize ) * gridSize; 4773 return measurement; 4774}; 4775 4776proto._getContainerSize = function() { 4777 if ( this._getOption('horizontal') ) { 4778 return { 4779 width: this.maxX - this.gutter 4780 }; 4781 } else { 4782 return { 4783 height: this.maxY - this.gutter 4784 }; 4785 } 4786}; 4787 4788 4789// -------------------------- stamp -------------------------- // 4790 4791/** 4792 * makes space for element 4793 * @param {Element} elem 4794 */ 4795proto._manageStamp = function( elem ) { 4796 4797 var item = this.getItem( elem ); 4798 var rect; 4799 if ( item && item.isPlacing ) { 4800 rect = item.rect; 4801 } else { 4802 var offset = this._getElementOffset( elem ); 4803 rect = new Rect({ 4804 x: this._getOption('originLeft') ? offset.left : offset.right, 4805 y: this._getOption('originTop') ? offset.top : offset.bottom 4806 }); 4807 } 4808 4809 this._setRectSize( elem, rect ); 4810 // save its space in the packer 4811 this.packer.placed( rect ); 4812 this._setMaxXY( rect ); 4813}; 4814 4815// -------------------------- methods -------------------------- // 4816 4817function verticalSorter( a, b ) { 4818 return a.position.y - b.position.y || a.position.x - b.position.x; 4819} 4820 4821function horizontalSorter( a, b ) { 4822 return a.position.x - b.position.x || a.position.y - b.position.y; 4823} 4824 4825proto.sortItemsByPosition = function() { 4826 var sorter = this._getOption('horizontal') ? horizontalSorter : verticalSorter; 4827 this.items.sort( sorter ); 4828}; 4829 4830/** 4831 * Fit item element in its current position 4832 * Packery will position elements around it 4833 * useful for expanding elements 4834 * 4835 * @param {Element} elem 4836 * @param {Number} x - horizontal destination position, optional 4837 * @param {Number} y - vertical destination position, optional 4838 */ 4839proto.fit = function( elem, x, y ) { 4840 var item = this.getItem( elem ); 4841 if ( !item ) { 4842 return; 4843 } 4844 4845 // stamp item to get it out of layout 4846 this.stamp( item.element ); 4847 // set placing flag 4848 item.enablePlacing(); 4849 this.updateShiftTargets( item ); 4850 // fall back to current position for fitting 4851 x = x === undefined ? item.rect.x: x; 4852 y = y === undefined ? item.rect.y: y; 4853 // position it best at its destination 4854 this.shift( item, x, y ); 4855 this._bindFitEvents( item ); 4856 item.moveTo( item.rect.x, item.rect.y ); 4857 // layout everything else 4858 this.shiftLayout(); 4859 // return back to regularly scheduled programming 4860 this.unstamp( item.element ); 4861 this.sortItemsByPosition(); 4862 item.disablePlacing(); 4863}; 4864 4865/** 4866 * emit event when item is fit and other items are laid out 4867 * @param {Packery.Item} item 4868 * @private 4869 */ 4870proto._bindFitEvents = function( item ) { 4871 var _this = this; 4872 var ticks = 0; 4873 function onLayout() { 4874 ticks++; 4875 if ( ticks != 2 ) { 4876 return; 4877 } 4878 _this.dispatchEvent( 'fitComplete', null, [ item ] ); 4879 } 4880 // when item is laid out 4881 item.once( 'layout', onLayout ); 4882 // when all items are laid out 4883 this.once( 'layoutComplete', onLayout ); 4884}; 4885 4886// -------------------------- resize -------------------------- // 4887 4888// debounced, layout on resize 4889proto.resize = function() { 4890 // don't trigger if size did not change 4891 // or if resize was unbound. See #285, outlayer#9 4892 if ( !this.isResizeBound || !this.needsResizeLayout() ) { 4893 return; 4894 } 4895 4896 if ( this.options.shiftPercentResize ) { 4897 this.resizeShiftPercentLayout(); 4898 } else { 4899 this.layout(); 4900 } 4901}; 4902 4903/** 4904 * check if layout is needed post layout 4905 * @returns Boolean 4906 */ 4907proto.needsResizeLayout = function() { 4908 var size = getSize( this.element ); 4909 var innerSize = this._getOption('horizontal') ? 'innerHeight' : 'innerWidth'; 4910 return size[ innerSize ] != this.size[ innerSize ]; 4911}; 4912 4913proto.resizeShiftPercentLayout = function() { 4914 var items = this._getItemsForLayout( this.items ); 4915 4916 var isHorizontal = this._getOption('horizontal'); 4917 var coord = isHorizontal ? 'y' : 'x'; 4918 var measure = isHorizontal ? 'height' : 'width'; 4919 var segmentName = isHorizontal ? 'rowHeight' : 'columnWidth'; 4920 var innerSize = isHorizontal ? 'innerHeight' : 'innerWidth'; 4921 4922 // proportional re-align items 4923 var previousSegment = this[ segmentName ]; 4924 previousSegment = previousSegment && previousSegment + this.gutter; 4925 4926 if ( previousSegment ) { 4927 this._getMeasurements(); 4928 var currentSegment = this[ segmentName ] + this.gutter; 4929 items.forEach( function( item ) { 4930 var seg = Math.round( item.rect[ coord ] / previousSegment ); 4931 item.rect[ coord ] = seg * currentSegment; 4932 }); 4933 } else { 4934 var currentSize = getSize( this.element )[ innerSize ] + this.gutter; 4935 var previousSize = this.packer[ measure ]; 4936 items.forEach( function( item ) { 4937 item.rect[ coord ] = ( item.rect[ coord ] / previousSize ) * currentSize; 4938 }); 4939 } 4940 4941 this.shiftLayout(); 4942}; 4943 4944// -------------------------- drag -------------------------- // 4945 4946/** 4947 * handle an item drag start event 4948 * @param {Element} elem 4949 */ 4950proto.itemDragStart = function( elem ) { 4951 if ( !this.isEnabled ) { 4952 return; 4953 } 4954 this.stamp( elem ); 4955 // this.ignore( elem ); 4956 var item = this.getItem( elem ); 4957 if ( !item ) { 4958 return; 4959 } 4960 4961 item.enablePlacing(); 4962 item.showDropPlaceholder(); 4963 this.dragItemCount++; 4964 this.updateShiftTargets( item ); 4965}; 4966 4967proto.updateShiftTargets = function( dropItem ) { 4968 this.shiftPacker.reset(); 4969 4970 // pack stamps 4971 this._getBoundingRect(); 4972 var isOriginLeft = this._getOption('originLeft'); 4973 var isOriginTop = this._getOption('originTop'); 4974 this.stamps.forEach( function( stamp ) { 4975 // ignore dragged item 4976 var item = this.getItem( stamp ); 4977 if ( item && item.isPlacing ) { 4978 return; 4979 } 4980 var offset = this._getElementOffset( stamp ); 4981 var rect = new Rect({ 4982 x: isOriginLeft ? offset.left : offset.right, 4983 y: isOriginTop ? offset.top : offset.bottom 4984 }); 4985 this._setRectSize( stamp, rect ); 4986 // save its space in the packer 4987 this.shiftPacker.placed( rect ); 4988 }, this ); 4989 4990 // reset shiftTargets 4991 var isHorizontal = this._getOption('horizontal'); 4992 var segmentName = isHorizontal ? 'rowHeight' : 'columnWidth'; 4993 var measure = isHorizontal ? 'height' : 'width'; 4994 4995 this.shiftTargetKeys = []; 4996 this.shiftTargets = []; 4997 var boundsSize; 4998 var segment = this[ segmentName ]; 4999 segment = segment && segment + this.gutter; 5000 5001 if ( segment ) { 5002 var segmentSpan = Math.ceil( dropItem.rect[ measure ] / segment ); 5003 var segs = Math.floor( ( this.shiftPacker[ measure ] + this.gutter ) / segment ); 5004 boundsSize = ( segs - segmentSpan ) * segment; 5005 // add targets on top 5006 for ( var i=0; i < segs; i++ ) { 5007 this._addShiftTarget( i * segment, 0, boundsSize ); 5008 } 5009 } else { 5010 boundsSize = ( this.shiftPacker[ measure ] + this.gutter ) - dropItem.rect[ measure ]; 5011 this._addShiftTarget( 0, 0, boundsSize ); 5012 } 5013 5014 // pack each item to measure where shiftTargets are 5015 var items = this._getItemsForLayout( this.items ); 5016 var packMethod = this._getPackMethod(); 5017 items.forEach( function( item ) { 5018 var rect = item.rect; 5019 this._setRectSize( item.element, rect ); 5020 this.shiftPacker[ packMethod ]( rect ); 5021 5022 // add top left corner 5023 this._addShiftTarget( rect.x, rect.y, boundsSize ); 5024 // add bottom left / top right corner 5025 var cornerX = isHorizontal ? rect.x + rect.width : rect.x; 5026 var cornerY = isHorizontal ? rect.y : rect.y + rect.height; 5027 this._addShiftTarget( cornerX, cornerY, boundsSize ); 5028 5029 if ( segment ) { 5030 // add targets for each column on bottom / row on right 5031 var segSpan = Math.round( rect[ measure ] / segment ); 5032 for ( var i=1; i < segSpan; i++ ) { 5033 var segX = isHorizontal ? cornerX : rect.x + segment * i; 5034 var segY = isHorizontal ? rect.y + segment * i : cornerY; 5035 this._addShiftTarget( segX, segY, boundsSize ); 5036 } 5037 } 5038 }, this ); 5039 5040}; 5041 5042proto._addShiftTarget = function( x, y, boundsSize ) { 5043 var checkCoord = this._getOption('horizontal') ? y : x; 5044 if ( checkCoord !== 0 && checkCoord > boundsSize ) { 5045 return; 5046 } 5047 // create string for a key, easier to keep track of what targets 5048 var key = x + ',' + y; 5049 var hasKey = this.shiftTargetKeys.indexOf( key ) != -1; 5050 if ( hasKey ) { 5051 return; 5052 } 5053 this.shiftTargetKeys.push( key ); 5054 this.shiftTargets.push({ x: x, y: y }); 5055}; 5056 5057// -------------------------- drop -------------------------- // 5058 5059proto.shift = function( item, x, y ) { 5060 var shiftPosition; 5061 var minDistance = Infinity; 5062 var position = { x: x, y: y }; 5063 this.shiftTargets.forEach( function( target ) { 5064 var distance = getDistance( target, position ); 5065 if ( distance < minDistance ) { 5066 shiftPosition = target; 5067 minDistance = distance; 5068 } 5069 }); 5070 item.rect.x = shiftPosition.x; 5071 item.rect.y = shiftPosition.y; 5072}; 5073 5074function getDistance( a, b ) { 5075 var dx = b.x - a.x; 5076 var dy = b.y - a.y; 5077 return Math.sqrt( dx * dx + dy * dy ); 5078} 5079 5080// -------------------------- drag move -------------------------- // 5081 5082var DRAG_THROTTLE_TIME = 120; 5083 5084/** 5085 * handle an item drag move event 5086 * @param {Element} elem 5087 * @param {Number} x - horizontal change in position 5088 * @param {Number} y - vertical change in position 5089 */ 5090proto.itemDragMove = function( elem, x, y ) { 5091 var item = this.isEnabled && this.getItem( elem ); 5092 if ( !item ) { 5093 return; 5094 } 5095 5096 x -= this.size.paddingLeft; 5097 y -= this.size.paddingTop; 5098 5099 var _this = this; 5100 function onDrag() { 5101 _this.shift( item, x, y ); 5102 item.positionDropPlaceholder(); 5103 _this.layout(); 5104 } 5105 5106 // throttle 5107 var now = new Date(); 5108 if ( this._itemDragTime && now - this._itemDragTime < DRAG_THROTTLE_TIME ) { 5109 clearTimeout( this.dragTimeout ); 5110 this.dragTimeout = setTimeout( onDrag, DRAG_THROTTLE_TIME ); 5111 } else { 5112 onDrag(); 5113 this._itemDragTime = now; 5114 } 5115}; 5116 5117// -------------------------- drag end -------------------------- // 5118 5119/** 5120 * handle an item drag end event 5121 * @param {Element} elem 5122 */ 5123proto.itemDragEnd = function( elem ) { 5124 var item = this.isEnabled && this.getItem( elem ); 5125 if ( !item ) { 5126 return; 5127 } 5128 5129 clearTimeout( this.dragTimeout ); 5130 item.element.classList.add('is-positioning-post-drag'); 5131 5132 var completeCount = 0; 5133 var _this = this; 5134 function onDragEndLayoutComplete() { 5135 completeCount++; 5136 if ( completeCount != 2 ) { 5137 return; 5138 } 5139 // reset drag item 5140 item.element.classList.remove('is-positioning-post-drag'); 5141 item.hideDropPlaceholder(); 5142 _this.dispatchEvent( 'dragItemPositioned', null, [ item ] ); 5143 } 5144 5145 item.once( 'layout', onDragEndLayoutComplete ); 5146 this.once( 'layoutComplete', onDragEndLayoutComplete ); 5147 item.moveTo( item.rect.x, item.rect.y ); 5148 this.layout(); 5149 this.dragItemCount = Math.max( 0, this.dragItemCount - 1 ); 5150 this.sortItemsByPosition(); 5151 item.disablePlacing(); 5152 this.unstamp( item.element ); 5153}; 5154 5155/** 5156 * binds Draggabilly events 5157 * @param {Draggabilly} draggie 5158 */ 5159proto.bindDraggabillyEvents = function( draggie ) { 5160 this._bindDraggabillyEvents( draggie, 'on' ); 5161}; 5162 5163proto.unbindDraggabillyEvents = function( draggie ) { 5164 this._bindDraggabillyEvents( draggie, 'off' ); 5165}; 5166 5167proto._bindDraggabillyEvents = function( draggie, method ) { 5168 var handlers = this.handleDraggabilly; 5169 draggie[ method ]( 'dragStart', handlers.dragStart ); 5170 draggie[ method ]( 'dragMove', handlers.dragMove ); 5171 draggie[ method ]( 'dragEnd', handlers.dragEnd ); 5172}; 5173 5174/** 5175 * binds jQuery UI Draggable events 5176 * @param {jQuery} $elems 5177 */ 5178proto.bindUIDraggableEvents = function( $elems ) { 5179 this._bindUIDraggableEvents( $elems, 'on' ); 5180}; 5181 5182proto.unbindUIDraggableEvents = function( $elems ) { 5183 this._bindUIDraggableEvents( $elems, 'off' ); 5184}; 5185 5186proto._bindUIDraggableEvents = function( $elems, method ) { 5187 var handlers = this.handleUIDraggable; 5188 $elems 5189 [ method ]( 'dragstart', handlers.start ) 5190 [ method ]( 'drag', handlers.drag ) 5191 [ method ]( 'dragstop', handlers.stop ); 5192}; 5193 5194// ----- destroy ----- // 5195 5196var _destroy = proto.destroy; 5197proto.destroy = function() { 5198 _destroy.apply( this, arguments ); 5199 // disable flag; prevent drag events from triggering. #72 5200 this.isEnabled = false; 5201}; 5202 5203// ----- ----- // 5204 5205Packery.Rect = Rect; 5206Packery.Packer = Packer; 5207 5208return Packery; 5209 5210})); 5211 5212/*! 5213 * Packery layout mode v2.0.1 5214 * sub-classes Packery 5215 */ 5216 5217/*jshint browser: true, strict: true, undef: true, unused: true */ 5218 5219( function( window, factory ) { 5220 5221 // universal module definition 5222 if ( typeof define == 'function' && define.amd ) { 5223 // AMD 5224 define( [ 5225 'isotope-layout/js/layout-mode', 5226 'packery/js/packery' 5227 ], 5228 factory ); 5229 } else if ( typeof module == 'object' && module.exports ) { 5230 // CommonJS 5231 module.exports = factory( 5232 require('isotope-layout/js/layout-mode'), 5233 require('packery') 5234 ); 5235 } else { 5236 // browser global 5237 factory( 5238 window.Isotope.LayoutMode, 5239 window.Packery 5240 ); 5241 } 5242 5243}( window, function factor( LayoutMode, Packery ) { 5244 5245 5246 // create an Outlayer layout class 5247 var PackeryMode = LayoutMode.create('packery'); 5248 var proto = PackeryMode.prototype; 5249 5250 var keepModeMethods = { 5251 _getElementOffset: true, 5252 _getMeasurement: true 5253 }; 5254 5255 // inherit Packery prototype 5256 for ( var method in Packery.prototype ) { 5257 // do not inherit mode methods 5258 if ( !keepModeMethods[ method ] ) { 5259 proto[ method ] = Packery.prototype[ method ]; 5260 } 5261 } 5262 5263 // set packer in _resetLayout 5264 var _resetLayout = proto._resetLayout; 5265 proto._resetLayout = function() { 5266 this.packer = this.packer || new Packery.Packer(); 5267 this.shiftPacker = this.shiftPacker || new Packery.Packer(); 5268 _resetLayout.apply( this, arguments ); 5269 }; 5270 5271 var _getItemLayoutPosition = proto._getItemLayoutPosition; 5272 proto._getItemLayoutPosition = function( item ) { 5273 // set packery rect 5274 item.rect = item.rect || new Packery.Rect(); 5275 return _getItemLayoutPosition.call( this, item ); 5276 }; 5277 5278 // needsResizeLayout for vertical or horizontal 5279 var _needsResizeLayout = proto.needsResizeLayout; 5280 proto.needsResizeLayout = function() { 5281 if ( this._getOption('horizontal') ) { 5282 return this.needsVerticalResizeLayout(); 5283 } else { 5284 return _needsResizeLayout.call( this ); 5285 } 5286 }; 5287 5288 // point to mode options for horizontal 5289 var _getOption = proto._getOption; 5290 proto._getOption = function( option ) { 5291 if ( option == 'horizontal' ) { 5292 return this.options.isHorizontal !== undefined ? 5293 this.options.isHorizontal : this.options.horizontal; 5294 } 5295 return _getOption.apply( this.isotope, arguments ); 5296 }; 5297 5298 return PackeryMode; 5299 5300})); 5301
vendor: 9,043 bytes, lines 5302-5653
5302 5303/*! 5304 * Packery PACKAGED v2.1.2 5305 * Gapless, draggable grid layouts 5306 * 5307 * Licensed GPLv3 for open source use 5308 * or Packery Commercial License for commercial use 5309 * 5310 * http://packery.metafizzy.co 5311 * Copyright 2013-2018 Metafizzy 5312 */ 5313 5314/** 5315 * Bridget makes jQuery widgets 5316 * v2.0.1 5317 * MIT license 5318 */ 5319 5320/* jshint browser: true, strict: true, undef: true, unused: true */ 5321 5322( function( window, factory ) { 5323 // universal module definition 5324 /*jshint strict: false */ /* globals define, module, require */ 5325 if ( typeof define == 'function' && define.amd ) { 5326 // AMD 5327 define( 'jquery-bridget/jquery-bridget',[ 'jquery' ], function( jQuery ) { 5328 return factory( window, jQuery ); 5329 }); 5330 } else if ( typeof module == 'object' && module.exports ) { 5331 // CommonJS 5332 module.exports = factory( 5333 window, 5334 require('jquery') 5335 ); 5336 } else { 5337 // browser global 5338 window.jQueryBridget = factory( 5339 window, 5340 window.jQuery 5341 ); 5342 } 5343 5344}( window, function factory( window, jQuery ) { 5345'use strict'; 5346 5347// ----- utils ----- // 5348 5349var arraySlice = Array.prototype.slice; 5350 5351// helper function for logging errors 5352// $.error breaks jQuery chaining 5353var console = window.console; 5354var logError = typeof console == 'undefined' ? function() {} : 5355 function( message ) { 5356 console.error( message ); 5357 }; 5358 5359// ----- jQueryBridget ----- // 5360 5361function jQueryBridget( namespace, PluginClass, $ ) { 5362 $ = $ || jQuery || window.jQuery; 5363 if ( !$ ) { 5364 return; 5365 } 5366 5367 // add option method -> $().plugin('option', {...}) 5368 if ( !PluginClass.prototype.option ) { 5369 // option setter 5370 PluginClass.prototype.option = function( opts ) { 5371 // bail out if not an object 5372 if ( !$.isPlainObject( opts ) ){ 5373 return; 5374 } 5375 this.options = $.extend( true, this.options, opts ); 5376 }; 5377 } 5378 5379 // make jQuery plugin 5380 $.fn[ namespace ] = function( arg0 /*, arg1 */ ) { 5381 if ( typeof arg0 == 'string' ) { 5382 // method call $().plugin( 'methodName', { options } ) 5383 // shift arguments by 1 5384 var args = arraySlice.call( arguments, 1 ); 5385 return methodCall( this, arg0, args ); 5386 } 5387 // just $().plugin({ options }) 5388 plainCall( this, arg0 ); 5389 return this; 5390 }; 5391 5392 // $().plugin('methodName') 5393 function methodCall( $elems, methodName, args ) { 5394 var returnValue; 5395 var pluginMethodStr = '$().' + namespace + '("' + methodName + '")'; 5396 5397 $elems.each( function( i, elem ) { 5398 // get instance 5399 var instance = $.data( elem, namespace ); 5400 if ( !instance ) { 5401 logError( namespace + ' not initialized. Cannot call methods, i.e. ' + 5402 pluginMethodStr ); 5403 return; 5404 } 5405 5406 var method = instance[ methodName ]; 5407 if ( !method || methodName.charAt(0) == '_' ) { 5408 logError( pluginMethodStr + ' is not a valid method' ); 5409 return; 5410 } 5411 5412 // apply method, get return value 5413 var value = method.apply( instance, args ); 5414 // set return value if value is returned, use only first value 5415 returnValue = returnValue === undefined ? value : returnValue; 5416 }); 5417 5418 return returnValue !== undefined ? returnValue : $elems; 5419 } 5420 5421 function plainCall( $elems, options ) { 5422 $elems.each( function( i, elem ) { 5423 var instance = $.data( elem, namespace ); 5424 if ( instance ) { 5425 // set options & init 5426 instance.option( options ); 5427 instance._init(); 5428 } else { 5429 // initialize new instance 5430 instance = new PluginClass( elem, options ); 5431 $.data( elem, namespace, instance ); 5432 } 5433 }); 5434 } 5435 5436 updateJQuery( $ ); 5437 5438} 5439 5440// ----- updateJQuery ----- // 5441 5442// set $.bridget for v1 backwards compatibility 5443function updateJQuery( $ ) { 5444 if ( !$ || ( $ && $.bridget ) ) { 5445 return; 5446 } 5447 $.bridget = jQueryBridget; 5448} 5449 5450updateJQuery( jQuery || window.jQuery ); 5451 5452// ----- ----- // 5453 5454return jQueryBridget; 5455 5456})); 5457 5458/*! 5459 * getSize v2.0.3 5460 * measure size of elements 5461 * MIT license 5462 */ 5463 5464/* jshint browser: true, strict: true, undef: true, unused: true */ 5465/* globals console: false */ 5466 5467( function( window, factory ) { 5468 /* jshint strict: false */ /* globals define, module */ 5469 if ( typeof define == 'function' && define.amd ) { 5470 // AMD 5471 define( 'get-size/get-size',factory ); 5472 } else if ( typeof module == 'object' && module.exports ) { 5473 // CommonJS 5474 module.exports = factory(); 5475 } else { 5476 // browser global 5477 window.getSize = factory(); 5478 } 5479 5480})( window, function factory() { 5481'use strict'; 5482 5483// -------------------------- helpers -------------------------- // 5484 5485// get a number from a string, not a percentage 5486function getStyleSize( value ) { 5487 var num = parseFloat( value ); 5488 // not a percent like '100%', and a number 5489 var isValid = value.indexOf('%') == -1 && !isNaN( num ); 5490 return isValid && num; 5491} 5492 5493function noop() {} 5494 5495var logError = typeof console == 'undefined' ? noop : 5496 function( message ) { 5497 console.error( message ); 5498 }; 5499 5500// -------------------------- measurements -------------------------- // 5501 5502var measurements = [ 5503 'paddingLeft', 5504 'paddingRight', 5505 'paddingTop', 5506 'paddingBottom', 5507 'marginLeft', 5508 'marginRight', 5509 'marginTop', 5510 'marginBottom', 5511 'borderLeftWidth', 5512 'borderRightWidth', 5513 'borderTopWidth', 5514 'borderBottomWidth' 5515]; 5516 5517var measurementsLength = measurements.length; 5518 5519function getZeroSize() { 5520 var size = { 5521 width: 0, 5522 height: 0, 5523 innerWidth: 0, 5524 innerHeight: 0, 5525 outerWidth: 0, 5526 outerHeight: 0 5527 }; 5528 for ( var i=0; i < measurementsLength; i++ ) { 5529 var measurement = measurements[i]; 5530 size[ measurement ] = 0; 5531 } 5532 return size; 5533} 5534 5535// -------------------------- getStyle -------------------------- // 5536 5537/** 5538 * getStyle, get style of element, check for Firefox bug 5539 * https://bugzilla.mozilla.org/show_bug.cgi?id=548397 5540 */ 5541function getStyle( elem ) { 5542 var style = getComputedStyle( elem ); 5543 if ( !style ) { 5544 logError( 'Style returned ' + style + 5545 '. Are you running this code in a hidden iframe on Firefox? ' + 5546 'See https://bit.ly/getsizebug1' ); 5547 } 5548 return style; 5549} 5550 5551// -------------------------- setup -------------------------- // 5552 5553var isSetup = false; 5554 5555var isBoxSizeOuter; 5556 5557/** 5558 * setup 5559 * check isBoxSizerOuter 5560 * do on first getSize() rather than on page load for Firefox bug 5561 */ 5562function setup() { 5563 // setup once 5564 if ( isSetup ) { 5565 return; 5566 } 5567 isSetup = true; 5568 5569 // -------------------------- box sizing -------------------------- // 5570 5571 /** 5572 * Chrome & Safari measure the outer-width on style.width on border-box elems 5573 * IE11 & Firefox<29 measures the inner-width 5574 */ 5575 var div = document.createElement('div'); 5576 div.style.width = '200px'; 5577 div.style.padding = '1px 2px 3px 4px'; 5578 div.style.borderStyle = 'solid'; 5579 div.style.borderWidth = '1px 2px 3px 4px'; 5580 div.style.boxSizing = 'border-box'; 5581 5582 var body = document.body || document.documentElement; 5583 body.appendChild( div ); 5584 var style = getStyle( div ); 5585 // round value for browser zoom. desandro/masonry#928 5586 isBoxSizeOuter = Math.round( getStyleSize( style.width ) ) == 200; 5587 getSize.isBoxSizeOuter = isBoxSizeOuter; 5588 5589 body.removeChild( div ); 5590} 5591 5592// -------------------------- getSize -------------------------- // 5593 5594function getSize( elem ) { 5595 setup(); 5596 5597 // use querySeletor if elem is string 5598 if ( typeof elem == 'string' ) { 5599 elem = document.querySelector( elem ); 5600 } 5601 5602 // do not proceed on non-objects 5603 if ( !elem || typeof elem != 'object' || !elem.nodeType ) { 5604 return; 5605 } 5606 5607 var style = getStyle( elem ); 5608 5609 // if hidden, everything is 0 5610 if ( style.display == 'none' ) { 5611 return getZeroSize(); 5612 } 5613 5614 var size = {}; 5615 size.width = elem.offsetWidth; 5616 size.height = elem.offsetHeight; 5617 5618 var isBorderBox = size.isBorderBox = style.boxSizing == 'border-box'; 5619 5620 // get all measurements 5621 for ( var i=0; i < measurementsLength; i++ ) { 5622 var measurement = measurements[i]; 5623 var value = style[ measurement ]; 5624 var num = parseFloat( value ); 5625 // any 'auto', 'medium' value will be 0 5626 size[ measurement ] = !isNaN( num ) ? num : 0; 5627 } 5628 5629 var paddingWidth = size.paddingLeft + size.paddingRight; 5630 var paddingHeight = size.paddingTop + size.paddingBottom; 5631 var marginWidth = size.marginLeft + size.marginRight; 5632 var marginHeight = size.marginTop + size.marginBottom; 5633 var borderWidth = size.borderLeftWidth + size.borderRightWidth; 5634 var borderHeight = size.borderTopWidth + size.borderBottomWidth; 5635 5636 var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter; 5637 5638 // overwrite width and height if we can get it from style 5639 var styleWidth = getStyleSize( style.width ); 5640 if ( styleWidth !== false ) { 5641 size.width = styleWidth + 5642 // add padding and border unless it's already including it 5643 ( isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth ); 5644 } 5645 5646 var styleHeight = getStyleSize( style.height ); 5647 if ( styleHeight !== false ) { 5648 size.height = styleHeight + 5649 // add padding and border unless it's already including it 5650 ( isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight ); 5651 } 5652 5653 size.innerWidth = size.width - ( paddingWidth + borderWidth );
vendor: 2,918 bytes, lines 5654-5777
5654 size.innerHeight = size.height - ( paddingHeight + borderHeight ); 5655 5656 size.outerWidth = size.width + marginWidth; 5657 size.outerHeight = size.height + marginHeight; 5658 5659 return size; 5660} 5661 5662return getSize; 5663 5664}); 5665 5666/** 5667 * EvEmitter v1.1.0 5668 * Lil' event emitter 5669 * MIT License 5670 */ 5671 5672/* jshint unused: true, undef: true, strict: true */ 5673 5674( function( global, factory ) { 5675 // universal module definition 5676 /* jshint strict: false */ /* globals define, module, window */ 5677 if ( typeof define == 'function' && define.amd ) { 5678 // AMD - RequireJS 5679 define( 'ev-emitter/ev-emitter',factory ); 5680 } else if ( typeof module == 'object' && module.exports ) { 5681 // CommonJS - Browserify, Webpack 5682 module.exports = factory(); 5683 } else { 5684 // Browser globals 5685 global.EvEmitter = factory(); 5686 } 5687 5688}( typeof window != 'undefined' ? window : this, function() { 5689 5690 5691 5692function EvEmitter() {} 5693 5694var proto = EvEmitter.prototype; 5695 5696proto.on = function( eventName, listener ) { 5697 if ( !eventName || !listener ) { 5698 return; 5699 } 5700 // set events hash 5701 var events = this._events = this._events || {}; 5702 // set listeners array 5703 var listeners = events[ eventName ] = events[ eventName ] || []; 5704 // only add once 5705 if ( listeners.indexOf( listener ) == -1 ) { 5706 listeners.push( listener ); 5707 } 5708 5709 return this; 5710}; 5711 5712proto.once = function( eventName, listener ) { 5713 if ( !eventName || !listener ) { 5714 return; 5715 } 5716 // add event 5717 this.on( eventName, listener ); 5718 // set once flag 5719 // set onceEvents hash 5720 var onceEvents = this._onceEvents = this._onceEvents || {}; 5721 // set onceListeners object 5722 var onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || {}; 5723 // set flag 5724 onceListeners[ listener ] = true; 5725 5726 return this; 5727}; 5728 5729proto.off = function( eventName, listener ) { 5730 var listeners = this._events && this._events[ eventName ]; 5731 if ( !listeners || !listeners.length ) { 5732 return; 5733 } 5734 var index = listeners.indexOf( listener ); 5735 if ( index != -1 ) { 5736 listeners.splice( index, 1 ); 5737 } 5738 5739 return this; 5740}; 5741 5742proto.emitEvent = function( eventName, args ) { 5743 var listeners = this._events && this._events[ eventName ]; 5744 if ( !listeners || !listeners.length ) { 5745 return; 5746 } 5747 // copy over to avoid interference if .off() in listener 5748 listeners = listeners.slice(0); 5749 args = args || []; 5750 // once stuff 5751 var onceListeners = this._onceEvents && this._onceEvents[ eventName ]; 5752 5753 for ( var i=0; i < listeners.length; i++ ) { 5754 var listener = listeners[i] 5755 var isOnce = onceListeners && onceListeners[ listener ]; 5756 if ( isOnce ) { 5757 // remove listener 5758 // remove before trigger to prevent recursion 5759 this.off( eventName, listener ); 5760 // unset once flag 5761 delete onceListeners[ listener ]; 5762 } 5763 // trigger listener 5764 listener.apply( this, args ); 5765 } 5766 5767 return this; 5768}; 5769 5770proto.allOff = function() { 5771 delete this._events; 5772 delete this._onceEvents; 5773}; 5774 5775return EvEmitter; 5776 5777})
vendor: 27,688 bytes, lines 5777-6873
5777); 5778 5779/** 5780 * matchesSelector v2.0.2 5781 * matchesSelector( element, '.selector' ) 5782 * MIT license 5783 */ 5784 5785/*jshint browser: true, strict: true, undef: true, unused: true */ 5786 5787( function( window, factory ) { 5788 /*global define: false, module: false */ 5789 'use strict'; 5790 // universal module definition 5791 if ( typeof define == 'function' && define.amd ) { 5792 // AMD 5793 define( 'desandro-matches-selector/matches-selector',factory ); 5794 } else if ( typeof module == 'object' && module.exports ) { 5795 // CommonJS 5796 module.exports = factory(); 5797 } else { 5798 // browser global 5799 window.matchesSelector = factory(); 5800 } 5801 5802}( window, function factory() { 5803 'use strict'; 5804 5805 var matchesMethod = ( function() { 5806 var ElemProto = window.Element.prototype; 5807 // check for the standard method name first 5808 if ( ElemProto.matches ) { 5809 return 'matches'; 5810 } 5811 // check un-prefixed 5812 if ( ElemProto.matchesSelector ) { 5813 return 'matchesSelector'; 5814 } 5815 // check vendor prefixes 5816 var prefixes = [ 'webkit', 'moz', 'ms', 'o' ]; 5817 5818 for ( var i=0; i < prefixes.length; i++ ) { 5819 var prefix = prefixes[i]; 5820 var method = prefix + 'MatchesSelector'; 5821 if ( ElemProto[ method ] ) { 5822 return method; 5823 } 5824 } 5825 })(); 5826 5827 return function matchesSelector( elem, selector ) { 5828 return elem[ matchesMethod ]( selector ); 5829 }; 5830 5831})); 5832 5833/** 5834 * Fizzy UI utils v2.0.7 5835 * MIT license 5836 */ 5837 5838/*jshint browser: true, undef: true, unused: true, strict: true */ 5839 5840( function( window, factory ) { 5841 // universal module definition 5842 /*jshint strict: false */ /*globals define, module, require */ 5843 5844 if ( typeof define == 'function' && define.amd ) { 5845 // AMD 5846 define( 'fizzy-ui-utils/utils',[ 5847 'desandro-matches-selector/matches-selector' 5848 ], function( matchesSelector ) { 5849 return factory( window, matchesSelector ); 5850 }); 5851 } else if ( typeof module == 'object' && module.exports ) { 5852 // CommonJS 5853 module.exports = factory( 5854 window, 5855 require('desandro-matches-selector') 5856 ); 5857 } else { 5858 // browser global 5859 window.fizzyUIUtils = factory( 5860 window, 5861 window.matchesSelector 5862 ); 5863 } 5864 5865}( window, function factory( window, matchesSelector ) { 5866 5867 5868 5869var utils = {}; 5870 5871// ----- extend ----- // 5872 5873// extends objects 5874utils.extend = function( a, b ) { 5875 for ( var prop in b ) { 5876 a[ prop ] = b[ prop ]; 5877 } 5878 return a; 5879}; 5880 5881// ----- modulo ----- // 5882 5883utils.modulo = function( num, div ) { 5884 return ( ( num % div ) + div ) % div; 5885}; 5886 5887// ----- makeArray ----- // 5888 5889var arraySlice = Array.prototype.slice; 5890 5891// turn element or nodeList into an array 5892utils.makeArray = function( obj ) { 5893 if ( Array.isArray( obj ) ) { 5894 // use object if already an array 5895 return obj; 5896 } 5897 // return empty array if undefined or null. #6 5898 if ( obj === null || obj === undefined ) { 5899 return []; 5900 } 5901 5902 var isArrayLike = typeof obj == 'object' && typeof obj.length == 'number'; 5903 if ( isArrayLike ) { 5904 // convert nodeList to array 5905 return arraySlice.call( obj ); 5906 } 5907 5908 // array of single index 5909 return [ obj ]; 5910}; 5911 5912// ----- removeFrom ----- // 5913 5914utils.removeFrom = function( ary, obj ) { 5915 var index = ary.indexOf( obj ); 5916 if ( index != -1 ) { 5917 ary.splice( index, 1 ); 5918 } 5919}; 5920 5921// ----- getParent ----- // 5922 5923utils.getParent = function( elem, selector ) { 5924 while ( elem.parentNode && elem != document.body ) { 5925 elem = elem.parentNode; 5926 if ( matchesSelector( elem, selector ) ) { 5927 return elem; 5928 } 5929 } 5930}; 5931 5932// ----- getQueryElement ----- // 5933 5934// use element as selector string 5935utils.getQueryElement = function( elem ) { 5936 if ( typeof elem == 'string' ) { 5937 return document.querySelector( elem ); 5938 } 5939 return elem; 5940}; 5941 5942// ----- handleEvent ----- // 5943 5944// enable .ontype to trigger from .addEventListener( elem, 'type' ) 5945utils.handleEvent = function( event ) { 5946 var method = 'on' + event.type; 5947 if ( this[ method ] ) { 5948 this[ method ]( event ); 5949 } 5950}; 5951 5952// ----- filterFindElements ----- // 5953 5954utils.filterFindElements = function( elems, selector ) { 5955 // make array of elems 5956 elems = utils.makeArray( elems ); 5957 var ffElems = []; 5958 5959 elems.forEach( function( elem ) { 5960 // check that elem is an actual element 5961 if ( !( elem instanceof HTMLElement ) ) { 5962 return; 5963 } 5964 // add elem if no selector 5965 if ( !selector ) { 5966 ffElems.push( elem ); 5967 return; 5968 } 5969 // filter & find items if we have a selector 5970 // filter 5971 if ( matchesSelector( elem, selector ) ) { 5972 ffElems.push( elem ); 5973 } 5974 // find children 5975 var childElems = elem.querySelectorAll( selector ); 5976 // concat childElems to filterFound array 5977 for ( var i=0; i < childElems.length; i++ ) { 5978 ffElems.push( childElems[i] ); 5979 } 5980 }); 5981 5982 return ffElems; 5983}; 5984 5985// ----- debounceMethod ----- // 5986 5987utils.debounceMethod = function( _class, methodName, threshold ) { 5988 threshold = threshold || 100; 5989 // original method 5990 var method = _class.prototype[ methodName ]; 5991 var timeoutName = methodName + 'Timeout'; 5992 5993 _class.prototype[ methodName ] = function() { 5994 var timeout = this[ timeoutName ]; 5995 clearTimeout( timeout ); 5996 5997 var args = arguments; 5998 var _this = this; 5999 this[ timeoutName ] = setTimeout( function() { 6000 method.apply( _this, args ); 6001 delete _this[ timeoutName ]; 6002 }, threshold ); 6003 }; 6004}; 6005 6006// ----- docReady ----- // 6007 6008utils.docReady = function( callback ) { 6009 var readyState = document.readyState; 6010 if ( readyState == 'complete' || readyState == 'interactive' ) { 6011 // do async to allow for other scripts to run. metafizzy/flickity#441 6012 setTimeout( callback ); 6013 } else { 6014 document.addEventListener( 'DOMContentLoaded', callback ); 6015 } 6016}; 6017 6018// ----- htmlInit ----- // 6019 6020// http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/ 6021utils.toDashed = function( str ) { 6022 return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) { 6023 return $1 + '-' + $2; 6024 }).toLowerCase(); 6025}; 6026 6027var console = window.console; 6028/** 6029 * allow user to initialize classes via [data-namespace] or .js-namespace class 6030 * htmlInit( Widget, 'widgetName' ) 6031 * options are parsed from data-namespace-options 6032 */ 6033utils.htmlInit = function( WidgetClass, namespace ) { 6034 utils.docReady( function() { 6035 var dashedNamespace = utils.toDashed( namespace ); 6036 var dataAttr = 'data-' + dashedNamespace; 6037 var dataAttrElems = document.querySelectorAll( '[' + dataAttr + ']' ); 6038 var jsDashElems = document.querySelectorAll( '.js-' + dashedNamespace ); 6039 var elems = utils.makeArray( dataAttrElems ) 6040 .concat( utils.makeArray( jsDashElems ) ); 6041 var dataOptionsAttr = dataAttr + '-options'; 6042 var jQuery = window.jQuery; 6043 6044 elems.forEach( function( elem ) { 6045 var attr = elem.getAttribute( dataAttr ) || 6046 elem.getAttribute( dataOptionsAttr ); 6047 var options; 6048 try { 6049 options = attr && JSON.parse( attr ); 6050 } catch ( error ) { 6051 // log error, do not initialize 6052 if ( console ) { 6053 console.error( 'Error parsing ' + dataAttr + ' on ' + elem.className + 6054 ': ' + error ); 6055 } 6056 return; 6057 } 6058 // initialize 6059 var instance = new WidgetClass( elem, options ); 6060 // make available via $().data('namespace') 6061 if ( jQuery ) { 6062 jQuery.data( elem, namespace, instance ); 6063 } 6064 }); 6065 6066 }); 6067}; 6068 6069// ----- ----- // 6070 6071return utils; 6072 6073})); 6074 6075/** 6076 * Outlayer Item 6077 */ 6078 6079( function( window, factory ) { 6080 // universal module definition 6081 /* jshint strict: false */ /* globals define, module, require */ 6082 if ( typeof define == 'function' && define.amd ) { 6083 // AMD - RequireJS 6084 define( 'outlayer/item',[ 6085 'ev-emitter/ev-emitter', 6086 'get-size/get-size' 6087 ], 6088 factory 6089 ); 6090 } else if ( typeof module == 'object' && module.exports ) { 6091 // CommonJS - Browserify, Webpack 6092 module.exports = factory( 6093 require('ev-emitter'), 6094 require('get-size') 6095 ); 6096 } else { 6097 // browser global 6098 window.Outlayer = {}; 6099 window.Outlayer.Item = factory( 6100 window.EvEmitter, 6101 window.getSize 6102 ); 6103 } 6104 6105}( window, function factory( EvEmitter, getSize ) { 6106'use strict'; 6107 6108// ----- helpers ----- // 6109 6110function isEmptyObj( obj ) { 6111 for ( var prop in obj ) { 6112 return false; 6113 } 6114 prop = null; 6115 return true; 6116} 6117 6118// -------------------------- CSS3 support -------------------------- // 6119 6120 6121var docElemStyle = document.documentElement.style; 6122 6123var transitionProperty = typeof docElemStyle.transition == 'string' ? 6124 'transition' : 'WebkitTransition'; 6125var transformProperty = typeof docElemStyle.transform == 'string' ? 6126 'transform' : 'WebkitTransform'; 6127 6128var transitionEndEvent = { 6129 WebkitTransition: 'webkitTransitionEnd', 6130 transition: 'transitionend' 6131}[ transitionProperty ]; 6132 6133// cache all vendor properties that could have vendor prefix 6134var vendorProperties = { 6135 transform: transformProperty, 6136 transition: transitionProperty, 6137 transitionDuration: transitionProperty + 'Duration', 6138 transitionProperty: transitionProperty + 'Property', 6139 transitionDelay: transitionProperty + 'Delay' 6140}; 6141 6142// -------------------------- Item -------------------------- // 6143 6144function Item( element, layout ) { 6145 if ( !element ) { 6146 return; 6147 } 6148 6149 this.element = element; 6150 // parent layout class, i.e. Masonry, Isotope, or Packery 6151 this.layout = layout; 6152 this.position = { 6153 x: 0, 6154 y: 0 6155 }; 6156 6157 this._create(); 6158} 6159 6160// inherit EvEmitter 6161var proto = Item.prototype = Object.create( EvEmitter.prototype ); 6162proto.constructor = Item; 6163 6164proto._create = function() { 6165 // transition objects 6166 this._transn = { 6167 ingProperties: {}, 6168 clean: {}, 6169 onEnd: {} 6170 }; 6171 6172 this.css({ 6173 position: 'absolute' 6174 }); 6175}; 6176 6177// trigger specified handler for event type 6178proto.handleEvent = function( event ) { 6179 var method = 'on' + event.type; 6180 if ( this[ method ] ) { 6181 this[ method ]( event ); 6182 } 6183}; 6184 6185proto.getSize = function() { 6186 this.size = getSize( this.element ); 6187}; 6188 6189/** 6190 * apply CSS styles to element 6191 * @param {Object} style 6192 */ 6193proto.css = function( style ) { 6194 var elemStyle = this.element.style; 6195 6196 for ( var prop in style ) { 6197 // use vendor property if available 6198 var supportedProp = vendorProperties[ prop ] || prop; 6199 elemStyle[ supportedProp ] = style[ prop ]; 6200 } 6201}; 6202 6203 // measure position, and sets it 6204proto.getPosition = function() { 6205 var style = getComputedStyle( this.element ); 6206 var isOriginLeft = this.layout._getOption('originLeft'); 6207 var isOriginTop = this.layout._getOption('originTop'); 6208 var xValue = style[ isOriginLeft ? 'left' : 'right' ]; 6209 var yValue = style[ isOriginTop ? 'top' : 'bottom' ]; 6210 var x = parseFloat( xValue ); 6211 var y = parseFloat( yValue ); 6212 // convert percent to pixels 6213 var layoutSize = this.layout.size; 6214 if ( xValue.indexOf('%') != -1 ) { 6215 x = ( x / 100 ) * layoutSize.width; 6216 } 6217 if ( yValue.indexOf('%') != -1 ) { 6218 y = ( y / 100 ) * layoutSize.height; 6219 } 6220 // clean up 'auto' or other non-integer values 6221 x = isNaN( x ) ? 0 : x; 6222 y = isNaN( y ) ? 0 : y; 6223 // remove padding from measurement 6224 x -= isOriginLeft ? layoutSize.paddingLeft : layoutSize.paddingRight; 6225 y -= isOriginTop ? layoutSize.paddingTop : layoutSize.paddingBottom; 6226 6227 this.position.x = x; 6228 this.position.y = y; 6229}; 6230 6231// set settled position, apply padding 6232proto.layoutPosition = function() { 6233 var layoutSize = this.layout.size; 6234 var style = {}; 6235 var isOriginLeft = this.layout._getOption('originLeft'); 6236 var isOriginTop = this.layout._getOption('originTop'); 6237 6238 // x 6239 var xPadding = isOriginLeft ? 'paddingLeft' : 'paddingRight'; 6240 var xProperty = isOriginLeft ? 'left' : 'right'; 6241 var xResetProperty = isOriginLeft ? 'right' : 'left'; 6242 6243 var x = this.position.x + layoutSize[ xPadding ]; 6244 // set in percentage or pixels 6245 style[ xProperty ] = this.getXValue( x ); 6246 // reset other property 6247 style[ xResetProperty ] = ''; 6248 6249 // y 6250 var yPadding = isOriginTop ? 'paddingTop' : 'paddingBottom'; 6251 var yProperty = isOriginTop ? 'top' : 'bottom'; 6252 var yResetProperty = isOriginTop ? 'bottom' : 'top'; 6253 6254 var y = this.position.y + layoutSize[ yPadding ]; 6255 // set in percentage or pixels 6256 style[ yProperty ] = this.getYValue( y ); 6257 // reset other property 6258 style[ yResetProperty ] = ''; 6259 6260 this.css( style ); 6261 this.emitEvent( 'layout', [ this ] ); 6262}; 6263 6264proto.getXValue = function( x ) { 6265 var isHorizontal = this.layout._getOption('horizontal'); 6266 return this.layout.options.percentPosition && !isHorizontal ? 6267 ( ( x / this.layout.size.width ) * 100 ) + '%' : x + 'px'; 6268}; 6269 6270proto.getYValue = function( y ) { 6271 var isHorizontal = this.layout._getOption('horizontal'); 6272 return this.layout.options.percentPosition && isHorizontal ? 6273 ( ( y / this.layout.size.height ) * 100 ) + '%' : y + 'px'; 6274}; 6275 6276proto._transitionTo = function( x, y ) { 6277 this.getPosition(); 6278 // get current x & y from top/left 6279 var curX = this.position.x; 6280 var curY = this.position.y; 6281 6282 var didNotMove = x == this.position.x && y == this.position.y; 6283 6284 // save end position 6285 this.setPosition( x, y ); 6286 6287 // if did not move and not transitioning, just go to layout 6288 if ( didNotMove && !this.isTransitioning ) { 6289 this.layoutPosition(); 6290 return; 6291 } 6292 6293 var transX = x - curX; 6294 var transY = y - curY; 6295 var transitionStyle = {}; 6296 transitionStyle.transform = this.getTranslate( transX, transY ); 6297 6298 this.transition({ 6299 to: transitionStyle, 6300 onTransitionEnd: { 6301 transform: this.layoutPosition 6302 }, 6303 isCleaning: true 6304 }); 6305}; 6306 6307proto.getTranslate = function( x, y ) { 6308 // flip cooridinates if origin on right or bottom 6309 var isOriginLeft = this.layout._getOption('originLeft'); 6310 var isOriginTop = this.layout._getOption('originTop'); 6311 x = isOriginLeft ? x : -x; 6312 y = isOriginTop ? y : -y; 6313 return 'translate3d(' + x + 'px, ' + y + 'px, 0)'; 6314}; 6315 6316// non transition + transform support 6317proto.goTo = function( x, y ) { 6318 this.setPosition( x, y ); 6319 this.layoutPosition(); 6320}; 6321 6322proto.moveTo = proto._transitionTo; 6323 6324proto.setPosition = function( x, y ) { 6325 this.position.x = parseFloat( x ); 6326 this.position.y = parseFloat( y ); 6327}; 6328 6329// ----- transition ----- // 6330 6331/** 6332 * @param {Object} style - CSS 6333 * @param {Function} onTransitionEnd 6334 */ 6335 6336// non transition, just trigger callback 6337proto._nonTransition = function( args ) { 6338 this.css( args.to ); 6339 if ( args.isCleaning ) { 6340 this._removeStyles( args.to ); 6341 } 6342 for ( var prop in args.onTransitionEnd ) { 6343 args.onTransitionEnd[ prop ].call( this ); 6344 } 6345}; 6346 6347/** 6348 * proper transition 6349 * @param {Object} args - arguments 6350 * @param {Object} to - style to transition to 6351 * @param {Object} from - style to start transition from 6352 * @param {Boolean} isCleaning - removes transition styles after transition 6353 * @param {Function} onTransitionEnd - callback 6354 */ 6355proto.transition = function( args ) { 6356 // redirect to nonTransition if no transition duration 6357 if ( !parseFloat( this.layout.options.transitionDuration ) ) { 6358 this._nonTransition( args ); 6359 return; 6360 } 6361 6362 var _transition = this._transn; 6363 // keep track of onTransitionEnd callback by css property 6364 for ( var prop in args.onTransitionEnd ) { 6365 _transition.onEnd[ prop ] = args.onTransitionEnd[ prop ]; 6366 } 6367 // keep track of properties that are transitioning 6368 for ( prop in args.to ) { 6369 _transition.ingProperties[ prop ] = true; 6370 // keep track of properties to clean up when transition is done 6371 if ( args.isCleaning ) { 6372 _transition.clean[ prop ] = true; 6373 } 6374 } 6375 6376 // set from styles 6377 if ( args.from ) { 6378 this.css( args.from ); 6379 // force redraw. http://blog.alexmaccaw.com/css-transitions 6380 var h = this.element.offsetHeight; 6381 // hack for JSHint to hush about unused var 6382 h = null; 6383 } 6384 // enable transition 6385 this.enableTransition( args.to ); 6386 // set styles that are transitioning 6387 this.css( args.to ); 6388 6389 this.isTransitioning = true; 6390 6391}; 6392 6393// dash before all cap letters, including first for 6394// WebkitTransform => -webkit-transform 6395function toDashedAll( str ) { 6396 return str.replace( /([A-Z])/g, function( $1 ) { 6397 return '-' + $1.toLowerCase(); 6398 }); 6399} 6400 6401var transitionProps = 'opacity,' + toDashedAll( transformProperty ); 6402 6403proto.enableTransition = function(/* style */) { 6404 // HACK changing transitionProperty during a transition 6405 // will cause transition to jump 6406 if ( this.isTransitioning ) { 6407 return; 6408 } 6409 6410 // make `transition: foo, bar, baz` from style object 6411 // HACK un-comment this when enableTransition can work 6412 // while a transition is happening 6413 // var transitionValues = []; 6414 // for ( var prop in style ) { 6415 // // dash-ify camelCased properties like WebkitTransition 6416 // prop = vendorProperties[ prop ] || prop; 6417 // transitionValues.push( toDashedAll( prop ) ); 6418 // } 6419 // munge number to millisecond, to match stagger 6420 var duration = this.layout.options.transitionDuration; 6421 duration = typeof duration == 'number' ? duration + 'ms' : duration; 6422 // enable transition styles 6423 this.css({ 6424 transitionProperty: transitionProps, 6425 transitionDuration: duration, 6426 transitionDelay: this.staggerDelay || 0 6427 }); 6428 // listen for transition end event 6429 this.element.addEventListener( transitionEndEvent, this, false ); 6430}; 6431 6432// ----- events ----- // 6433 6434proto.onwebkitTransitionEnd = function( event ) { 6435 this.ontransitionend( event ); 6436}; 6437 6438proto.onotransitionend = function( event ) { 6439 this.ontransitionend( event ); 6440}; 6441 6442// properties that I munge to make my life easier 6443var dashedVendorProperties = { 6444 '-webkit-transform': 'transform' 6445}; 6446 6447proto.ontransitionend = function( event ) { 6448 // disregard bubbled events from children 6449 if ( event.target !== this.element ) { 6450 return; 6451 } 6452 var _transition = this._transn; 6453 // get property name of transitioned property, convert to prefix-free 6454 var propertyName = dashedVendorProperties[ event.propertyName ] || event.propertyName; 6455 6456 // remove property that has completed transitioning 6457 delete _transition.ingProperties[ propertyName ]; 6458 // check if any properties are still transitioning 6459 if ( isEmptyObj( _transition.ingProperties ) ) { 6460 // all properties have completed transitioning 6461 this.disableTransition(); 6462 } 6463 // clean style 6464 if ( propertyName in _transition.clean ) { 6465 // clean up style 6466 this.element.style[ event.propertyName ] = ''; 6467 delete _transition.clean[ propertyName ]; 6468 } 6469 // trigger onTransitionEnd callback 6470 if ( propertyName in _transition.onEnd ) { 6471 var onTransitionEnd = _transition.onEnd[ propertyName ]; 6472 onTransitionEnd.call( this ); 6473 delete _transition.onEnd[ propertyName ]; 6474 } 6475 6476 this.emitEvent( 'transitionEnd', [ this ] ); 6477}; 6478 6479proto.disableTransition = function() { 6480 this.removeTransitionStyles(); 6481 this.element.removeEventListener( transitionEndEvent, this, false ); 6482 this.isTransitioning = false; 6483}; 6484 6485/** 6486 * removes style property from element 6487 * @param {Object} style 6488**/ 6489proto._removeStyles = function( style ) { 6490 // clean up transition styles 6491 var cleanStyle = {}; 6492 for ( var prop in style ) { 6493 cleanStyle[ prop ] = ''; 6494 } 6495 this.css( cleanStyle ); 6496}; 6497 6498var cleanTransitionStyle = { 6499 transitionProperty: '', 6500 transitionDuration: '', 6501 transitionDelay: '' 6502}; 6503 6504proto.removeTransitionStyles = function() { 6505 // remove transition 6506 this.css( cleanTransitionStyle ); 6507}; 6508 6509// ----- stagger ----- // 6510 6511proto.stagger = function( delay ) { 6512 delay = isNaN( delay ) ? 0 : delay; 6513 this.staggerDelay = delay + 'ms'; 6514}; 6515 6516// ----- show/hide/remove ----- // 6517 6518// remove element from DOM 6519proto.removeElem = function() { 6520 this.element.parentNode.removeChild( this.element ); 6521 // remove display: none 6522 this.css({ display: '' }); 6523 this.emitEvent( 'remove', [ this ] ); 6524}; 6525 6526proto.remove = function() { 6527 // just remove element if no transition support or no transition 6528 if ( !transitionProperty || !parseFloat( this.layout.options.transitionDuration ) ) { 6529 this.removeElem(); 6530 return; 6531 } 6532 6533 // start transition 6534 this.once( 'transitionEnd', function() { 6535 this.removeElem(); 6536 }); 6537 this.hide(); 6538}; 6539 6540proto.reveal = function() { 6541 delete this.isHidden; 6542 // remove display: none 6543 this.css({ display: '' }); 6544 6545 var options = this.layout.options; 6546 6547 var onTransitionEnd = {}; 6548 var transitionEndProperty = this.getHideRevealTransitionEndProperty('visibleStyle'); 6549 onTransitionEnd[ transitionEndProperty ] = this.onRevealTransitionEnd; 6550 6551 this.transition({ 6552 from: options.hiddenStyle, 6553 to: options.visibleStyle, 6554 isCleaning: true, 6555 onTransitionEnd: onTransitionEnd 6556 }); 6557}; 6558 6559proto.onRevealTransitionEnd = function() { 6560 // check if still visible 6561 // during transition, item may have been hidden 6562 if ( !this.isHidden ) { 6563 this.emitEvent('reveal'); 6564 } 6565}; 6566 6567/** 6568 * get style property use for hide/reveal transition end 6569 * @param {String} styleProperty - hiddenStyle/visibleStyle 6570 * @returns {String} 6571 */ 6572proto.getHideRevealTransitionEndProperty = function( styleProperty ) { 6573 var optionStyle = this.layout.options[ styleProperty ]; 6574 // use opacity 6575 if ( optionStyle.opacity ) { 6576 return 'opacity'; 6577 } 6578 // get first property 6579 for ( var prop in optionStyle ) { 6580 return prop; 6581 } 6582}; 6583 6584proto.hide = function() { 6585 // set flag 6586 this.isHidden = true; 6587 // remove display: none 6588 this.css({ display: '' }); 6589 6590 var options = this.layout.options; 6591 6592 var onTransitionEnd = {}; 6593 var transitionEndProperty = this.getHideRevealTransitionEndProperty('hiddenStyle'); 6594 onTransitionEnd[ transitionEndProperty ] = this.onHideTransitionEnd; 6595 6596 this.transition({ 6597 from: options.visibleStyle, 6598 to: options.hiddenStyle, 6599 // keep hidden stuff hidden 6600 isCleaning: true, 6601 onTransitionEnd: onTransitionEnd 6602 }); 6603}; 6604 6605proto.onHideTransitionEnd = function() { 6606 // check if still hidden 6607 // during transition, item may have been un-hidden 6608 if ( this.isHidden ) { 6609 this.css({ display: 'none' }); 6610 this.emitEvent('hide'); 6611 } 6612}; 6613 6614proto.destroy = function() { 6615 this.css({ 6616 position: '', 6617 left: '', 6618 right: '', 6619 top: '', 6620 bottom: '', 6621 transition: '', 6622 transform: '' 6623 }); 6624}; 6625 6626return Item; 6627 6628})); 6629 6630/*! 6631 * Outlayer v2.1.1 6632 * the brains and guts of a layout library 6633 * MIT license 6634 */ 6635 6636( function( window, factory ) { 6637 'use strict'; 6638 // universal module definition 6639 /* jshint strict: false */ /* globals define, module, require */ 6640 if ( typeof define == 'function' && define.amd ) { 6641 // AMD - RequireJS 6642 define( 'outlayer/outlayer',[ 6643 'ev-emitter/ev-emitter', 6644 'get-size/get-size', 6645 'fizzy-ui-utils/utils', 6646 './item' 6647 ], 6648 function( EvEmitter, getSize, utils, Item ) { 6649 return factory( window, EvEmitter, getSize, utils, Item); 6650 } 6651 ); 6652 } else if ( typeof module == 'object' && module.exports ) { 6653 // CommonJS - Browserify, Webpack 6654 module.exports = factory( 6655 window, 6656 require('ev-emitter'), 6657 require('get-size'), 6658 require('fizzy-ui-utils'), 6659 require('./item') 6660 ); 6661 } else { 6662 // browser global 6663 window.Outlayer = factory( 6664 window, 6665 window.EvEmitter, 6666 window.getSize, 6667 window.fizzyUIUtils, 6668 window.Outlayer.Item 6669 ); 6670 } 6671 6672}( window, function factory( window, EvEmitter, getSize, utils, Item ) { 6673'use strict'; 6674 6675// ----- vars ----- // 6676 6677var console = window.console; 6678var jQuery = window.jQuery; 6679var noop = function() {}; 6680 6681// -------------------------- Outlayer -------------------------- // 6682 6683// globally unique identifiers 6684var GUID = 0; 6685// internal store of all Outlayer intances 6686var instances = {}; 6687 6688 6689/** 6690 * @param {Element, String} element 6691 * @param {Object} options 6692 * @constructor 6693 */ 6694function Outlayer( element, options ) { 6695 var queryElement = utils.getQueryElement( element ); 6696 if ( !queryElement ) { 6697 if ( console ) { 6698 console.error( 'Bad element for ' + this.constructor.namespace + 6699 ': ' + ( queryElement || element ) ); 6700 } 6701 return; 6702 } 6703 this.element = queryElement; 6704 // add jQuery 6705 if ( jQuery ) { 6706 this.$element = jQuery( this.element ); 6707 } 6708 6709 // options 6710 this.options = utils.extend( {}, this.constructor.defaults ); 6711 this.option( options ); 6712 6713 // add id for Outlayer.getFromElement 6714 var id = ++GUID; 6715 this.element.outlayerGUID = id; // expando 6716 instances[ id ] = this; // associate via id 6717 6718 // kick it off 6719 this._create(); 6720 6721 var isInitLayout = this._getOption('initLayout'); 6722 if ( isInitLayout ) { 6723 this.layout(); 6724 } 6725} 6726 6727// settings are for internal use only 6728Outlayer.namespace = 'outlayer'; 6729Outlayer.Item = Item; 6730 6731// default options 6732Outlayer.defaults = { 6733 containerStyle: { 6734 position: 'relative' 6735 }, 6736 initLayout: true, 6737 originLeft: true, 6738 originTop: true, 6739 resize: true, 6740 resizeContainer: true, 6741 // item options 6742 transitionDuration: '0.4s', 6743 hiddenStyle: { 6744 opacity: 0, 6745 transform: 'scale(0.001)' 6746 }, 6747 visibleStyle: { 6748 opacity: 1, 6749 transform: 'scale(1)' 6750 } 6751}; 6752 6753var proto = Outlayer.prototype; 6754// inherit EvEmitter 6755utils.extend( proto, EvEmitter.prototype ); 6756 6757/** 6758 * set options 6759 * @param {Object} opts 6760 */ 6761proto.option = function( opts ) { 6762 utils.extend( this.options, opts ); 6763}; 6764 6765/** 6766 * get backwards compatible option value, check old name 6767 */ 6768proto._getOption = function( option ) { 6769 var oldOption = this.constructor.compatOptions[ option ]; 6770 return oldOption && this.options[ oldOption ] !== undefined ? 6771 this.options[ oldOption ] : this.options[ option ]; 6772}; 6773 6774Outlayer.compatOptions = { 6775 // currentName: oldName 6776 initLayout: 'isInitLayout', 6777 horizontal: 'isHorizontal', 6778 layoutInstant: 'isLayoutInstant', 6779 originLeft: 'isOriginLeft', 6780 originTop: 'isOriginTop', 6781 resize: 'isResizeBound', 6782 resizeContainer: 'isResizingContainer' 6783}; 6784 6785proto._create = function() { 6786 // get items from children 6787 this.reloadItems(); 6788 // elements that affect layout, but are not laid out 6789 this.stamps = []; 6790 this.stamp( this.options.stamp ); 6791 // set container style 6792 utils.extend( this.element.style, this.options.containerStyle ); 6793 6794 // bind resize method 6795 var canBindResize = this._getOption('resize'); 6796 if ( canBindResize ) { 6797 this.bindResize(); 6798 } 6799}; 6800 6801// goes through all children again and gets bricks in proper order 6802proto.reloadItems = function() { 6803 // collection of item elements 6804 this.items = this._itemize( this.element.children ); 6805}; 6806 6807 6808/** 6809 * turn elements into Outlayer.Items to be used in layout 6810 * @param {Array or NodeList or HTMLElement} elems 6811 * @returns {Array} items - collection of new Outlayer Items 6812 */ 6813proto._itemize = function( elems ) { 6814 6815 var itemElems = this._filterFindItemElements( elems ); 6816 var Item = this.constructor.Item; 6817 6818 // create new Outlayer Items for collection 6819 var items = []; 6820 for ( var i=0; i < itemElems.length; i++ ) { 6821 var elem = itemElems[i]; 6822 var item = new Item( elem, this ); 6823 items.push( item ); 6824 } 6825 6826 return items; 6827}; 6828 6829/** 6830 * get item elements to be used in layout 6831 * @param {Array or NodeList or HTMLElement} elems 6832 * @returns {Array} items - item elements 6833 */ 6834proto._filterFindItemElements = function( elems ) { 6835 return utils.filterFindElements( elems, this.options.itemSelector ); 6836}; 6837 6838/** 6839 * getter method for getting item elements 6840 * @returns {Array} elems - collection of item elements 6841 */ 6842proto.getItemElements = function() { 6843 return this.items.map( function( item ) { 6844 return item.element; 6845 }); 6846}; 6847 6848// ----- init & layout ----- // 6849 6850/** 6851 * lays out all items 6852 */ 6853proto.layout = function() { 6854 this._resetLayout(); 6855 this._manageStamps(); 6856 6857 // don't animate first layout 6858 var layoutInstant = this._getOption('layoutInstant'); 6859 var isInstant = layoutInstant !== undefined ? 6860 layoutInstant : !this._isLayoutInited; 6861 this.layoutItems( this.items, isInstant ); 6862 6863 // flag for initalized 6864 this._isLayoutInited = true; 6865}; 6866 6867// _init is alias for layout 6868proto._init = proto.layout; 6869 6870/** 6871 * logic before any new layout 6872 */ 6873proto._resetLayout = function() {
vendor: 45,660 bytes, lines 6874-8723
6874 this.getSize(); 6875}; 6876 6877 6878proto.getSize = function() { 6879 this.size = getSize( this.element ); 6880}; 6881 6882/** 6883 * get measurement from option, for columnWidth, rowHeight, gutter 6884 * if option is String -> get element from selector string, & get size of element 6885 * if option is Element -> get size of element 6886 * else use option as a number 6887 * 6888 * @param {String} measurement 6889 * @param {String} size - width or height 6890 * @private 6891 */ 6892proto._getMeasurement = function( measurement, size ) { 6893 var option = this.options[ measurement ]; 6894 var elem; 6895 if ( !option ) { 6896 // default to 0 6897 this[ measurement ] = 0; 6898 } else { 6899 // use option as an element 6900 if ( typeof option == 'string' ) { 6901 elem = this.element.querySelector( option ); 6902 } else if ( option instanceof HTMLElement ) { 6903 elem = option; 6904 } 6905 // use size of element, if element 6906 this[ measurement ] = elem ? getSize( elem )[ size ] : option; 6907 } 6908}; 6909 6910/** 6911 * layout a collection of item elements 6912 * @api public 6913 */ 6914proto.layoutItems = function( items, isInstant ) { 6915 items = this._getItemsForLayout( items ); 6916 6917 this._layoutItems( items, isInstant ); 6918 6919 this._postLayout(); 6920}; 6921 6922/** 6923 * get the items to be laid out 6924 * you may want to skip over some items 6925 * @param {Array} items 6926 * @returns {Array} items 6927 */ 6928proto._getItemsForLayout = function( items ) { 6929 return items.filter( function( item ) { 6930 return !item.isIgnored; 6931 }); 6932}; 6933 6934/** 6935 * layout items 6936 * @param {Array} items 6937 * @param {Boolean} isInstant 6938 */ 6939proto._layoutItems = function( items, isInstant ) { 6940 this._emitCompleteOnItems( 'layout', items ); 6941 6942 if ( !items || !items.length ) { 6943 // no items, emit event with empty array 6944 return; 6945 } 6946 6947 var queue = []; 6948 6949 items.forEach( function( item ) { 6950 // get x/y object from method 6951 var position = this._getItemLayoutPosition( item ); 6952 // enqueue 6953 position.item = item; 6954 position.isInstant = isInstant || item.isLayoutInstant; 6955 queue.push( position ); 6956 }, this ); 6957 6958 this._processLayoutQueue( queue ); 6959}; 6960 6961/** 6962 * get item layout position 6963 * @param {Outlayer.Item} item 6964 * @returns {Object} x and y position 6965 */ 6966proto._getItemLayoutPosition = function( /* item */ ) { 6967 return { 6968 x: 0, 6969 y: 0 6970 }; 6971}; 6972 6973/** 6974 * iterate over array and position each item 6975 * Reason being - separating this logic prevents 'layout invalidation' 6976 * thx @paul_irish 6977 * @param {Array} queue 6978 */ 6979proto._processLayoutQueue = function( queue ) { 6980 this.updateStagger(); 6981 queue.forEach( function( obj, i ) { 6982 this._positionItem( obj.item, obj.x, obj.y, obj.isInstant, i ); 6983 }, this ); 6984}; 6985 6986// set stagger from option in milliseconds number 6987proto.updateStagger = function() { 6988 var stagger = this.options.stagger; 6989 if ( stagger === null || stagger === undefined ) { 6990 this.stagger = 0; 6991 return; 6992 } 6993 this.stagger = getMilliseconds( stagger ); 6994 return this.stagger; 6995}; 6996 6997/** 6998 * Sets position of item in DOM 6999 * @param {Outlayer.Item} item 7000 * @param {Number} x - horizontal position 7001 * @param {Number} y - vertical position 7002 * @param {Boolean} isInstant - disables transitions 7003 */ 7004proto._positionItem = function( item, x, y, isInstant, i ) { 7005 if ( isInstant ) { 7006 // if not transition, just set CSS 7007 item.goTo( x, y ); 7008 } else { 7009 item.stagger( i * this.stagger ); 7010 item.moveTo( x, y ); 7011 } 7012}; 7013 7014/** 7015 * Any logic you want to do after each layout, 7016 * i.e. size the container 7017 */ 7018proto._postLayout = function() { 7019 this.resizeContainer(); 7020}; 7021 7022proto.resizeContainer = function() { 7023 var isResizingContainer = this._getOption('resizeContainer'); 7024 if ( !isResizingContainer ) { 7025 return; 7026 } 7027 var size = this._getContainerSize(); 7028 if ( size ) { 7029 this._setContainerMeasure( size.width, true ); 7030 this._setContainerMeasure( size.height, false ); 7031 } 7032}; 7033 7034/** 7035 * Sets width or height of container if returned 7036 * @returns {Object} size 7037 * @param {Number} width 7038 * @param {Number} height 7039 */ 7040proto._getContainerSize = noop; 7041 7042/** 7043 * @param {Number} measure - size of width or height 7044 * @param {Boolean} isWidth 7045 */ 7046proto._setContainerMeasure = function( measure, isWidth ) { 7047 if ( measure === undefined ) { 7048 return; 7049 } 7050 7051 var elemSize = this.size; 7052 // add padding and border width if border box 7053 if ( elemSize.isBorderBox ) { 7054 measure += isWidth ? elemSize.paddingLeft + elemSize.paddingRight + 7055 elemSize.borderLeftWidth + elemSize.borderRightWidth : 7056 elemSize.paddingBottom + elemSize.paddingTop + 7057 elemSize.borderTopWidth + elemSize.borderBottomWidth; 7058 } 7059 7060 measure = Math.max( measure, 0 ); 7061 this.element.style[ isWidth ? 'width' : 'height' ] = measure + 'px'; 7062}; 7063 7064/** 7065 * emit eventComplete on a collection of items events 7066 * @param {String} eventName 7067 * @param {Array} items - Outlayer.Items 7068 */ 7069proto._emitCompleteOnItems = function( eventName, items ) { 7070 var _this = this; 7071 function onComplete() { 7072 _this.dispatchEvent( eventName + 'Complete', null, [ items ] ); 7073 } 7074 7075 var count = items.length; 7076 if ( !items || !count ) { 7077 onComplete(); 7078 return; 7079 } 7080 7081 var doneCount = 0; 7082 function tick() { 7083 doneCount++; 7084 if ( doneCount == count ) { 7085 onComplete(); 7086 } 7087 } 7088 7089 // bind callback 7090 items.forEach( function( item ) { 7091 item.once( eventName, tick ); 7092 }); 7093}; 7094 7095/** 7096 * emits events via EvEmitter and jQuery events 7097 * @param {String} type - name of event 7098 * @param {Event} event - original event 7099 * @param {Array} args - extra arguments 7100 */ 7101proto.dispatchEvent = function( type, event, args ) { 7102 // add original event to arguments 7103 var emitArgs = event ? [ event ].concat( args ) : args; 7104 this.emitEvent( type, emitArgs ); 7105 7106 if ( jQuery ) { 7107 // set this.$element 7108 this.$element = this.$element || jQuery( this.element ); 7109 if ( event ) { 7110 // create jQuery event 7111 var $event = jQuery.Event( event ); 7112 $event.type = type; 7113 this.$element.trigger( $event, args ); 7114 } else { 7115 // just trigger with type if no event available 7116 this.$element.trigger( type, args ); 7117 } 7118 } 7119}; 7120 7121// -------------------------- ignore & stamps -------------------------- // 7122 7123 7124/** 7125 * keep item in collection, but do not lay it out 7126 * ignored items do not get skipped in layout 7127 * @param {Element} elem 7128 */ 7129proto.ignore = function( elem ) { 7130 var item = this.getItem( elem ); 7131 if ( item ) { 7132 item.isIgnored = true; 7133 } 7134}; 7135 7136/** 7137 * return item to layout collection 7138 * @param {Element} elem 7139 */ 7140proto.unignore = function( elem ) { 7141 var item = this.getItem( elem ); 7142 if ( item ) { 7143 delete item.isIgnored; 7144 } 7145}; 7146 7147/** 7148 * adds elements to stamps 7149 * @param {NodeList, Array, Element, or String} elems 7150 */ 7151proto.stamp = function( elems ) { 7152 elems = this._find( elems ); 7153 if ( !elems ) { 7154 return; 7155 } 7156 7157 this.stamps = this.stamps.concat( elems ); 7158 // ignore 7159 elems.forEach( this.ignore, this ); 7160}; 7161 7162/** 7163 * removes elements to stamps 7164 * @param {NodeList, Array, or Element} elems 7165 */ 7166proto.unstamp = function( elems ) { 7167 elems = this._find( elems ); 7168 if ( !elems ){ 7169 return; 7170 } 7171 7172 elems.forEach( function( elem ) { 7173 // filter out removed stamp elements 7174 utils.removeFrom( this.stamps, elem ); 7175 this.unignore( elem ); 7176 }, this ); 7177}; 7178 7179/** 7180 * finds child elements 7181 * @param {NodeList, Array, Element, or String} elems 7182 * @returns {Array} elems 7183 */ 7184proto._find = function( elems ) { 7185 if ( !elems ) { 7186 return; 7187 } 7188 // if string, use argument as selector string 7189 if ( typeof elems == 'string' ) { 7190 elems = this.element.querySelectorAll( elems ); 7191 } 7192 elems = utils.makeArray( elems ); 7193 return elems; 7194}; 7195 7196proto._manageStamps = function() { 7197 if ( !this.stamps || !this.stamps.length ) { 7198 return; 7199 } 7200 7201 this._getBoundingRect(); 7202 7203 this.stamps.forEach( this._manageStamp, this ); 7204}; 7205 7206// update boundingLeft / Top 7207proto._getBoundingRect = function() { 7208 // get bounding rect for container element 7209 var boundingRect = this.element.getBoundingClientRect(); 7210 var size = this.size; 7211 this._boundingRect = { 7212 left: boundingRect.left + size.paddingLeft + size.borderLeftWidth, 7213 top: boundingRect.top + size.paddingTop + size.borderTopWidth, 7214 right: boundingRect.right - ( size.paddingRight + size.borderRightWidth ), 7215 bottom: boundingRect.bottom - ( size.paddingBottom + size.borderBottomWidth ) 7216 }; 7217}; 7218 7219/** 7220 * @param {Element} stamp 7221**/ 7222proto._manageStamp = noop; 7223 7224/** 7225 * get x/y position of element relative to container element 7226 * @param {Element} elem 7227 * @returns {Object} offset - has left, top, right, bottom 7228 */ 7229proto._getElementOffset = function( elem ) { 7230 var boundingRect = elem.getBoundingClientRect(); 7231 var thisRect = this._boundingRect; 7232 var size = getSize( elem ); 7233 var offset = { 7234 left: boundingRect.left - thisRect.left - size.marginLeft, 7235 top: boundingRect.top - thisRect.top - size.marginTop, 7236 right: thisRect.right - boundingRect.right - size.marginRight, 7237 bottom: thisRect.bottom - boundingRect.bottom - size.marginBottom 7238 }; 7239 return offset; 7240}; 7241 7242// -------------------------- resize -------------------------- // 7243 7244// enable event handlers for listeners 7245// i.e. resize -> onresize 7246proto.handleEvent = utils.handleEvent; 7247 7248/** 7249 * Bind layout to window resizing 7250 */ 7251proto.bindResize = function() { 7252 window.addEventListener( 'resize', this ); 7253 this.isResizeBound = true; 7254}; 7255 7256/** 7257 * Unbind layout to window resizing 7258 */ 7259proto.unbindResize = function() { 7260 window.removeEventListener( 'resize', this ); 7261 this.isResizeBound = false; 7262}; 7263 7264proto.onresize = function() { 7265 this.resize(); 7266}; 7267 7268utils.debounceMethod( Outlayer, 'onresize', 100 ); 7269 7270proto.resize = function() { 7271 // don't trigger if size did not change 7272 // or if resize was unbound. See #9 7273 if ( !this.isResizeBound || !this.needsResizeLayout() ) { 7274 return; 7275 } 7276 7277 this.layout(); 7278}; 7279 7280/** 7281 * check if layout is needed post layout 7282 * @returns Boolean 7283 */ 7284proto.needsResizeLayout = function() { 7285 var size = getSize( this.element ); 7286 // check that this.size and size are there 7287 // IE8 triggers resize on body size change, so they might not be 7288 var hasSizes = this.size && size; 7289 return hasSizes && size.innerWidth !== this.size.innerWidth; 7290}; 7291 7292// -------------------------- methods -------------------------- // 7293 7294/** 7295 * add items to Outlayer instance 7296 * @param {Array or NodeList or Element} elems 7297 * @returns {Array} items - Outlayer.Items 7298**/ 7299proto.addItems = function( elems ) { 7300 var items = this._itemize( elems ); 7301 // add items to collection 7302 if ( items.length ) { 7303 this.items = this.items.concat( items ); 7304 } 7305 return items; 7306}; 7307 7308/** 7309 * Layout newly-appended item elements 7310 * @param {Array or NodeList or Element} elems 7311 */ 7312proto.appended = function( elems ) { 7313 var items = this.addItems( elems ); 7314 if ( !items.length ) { 7315 return; 7316 } 7317 // layout and reveal just the new items 7318 this.layoutItems( items, true ); 7319 this.reveal( items ); 7320}; 7321 7322/** 7323 * Layout prepended elements 7324 * @param {Array or NodeList or Element} elems 7325 */ 7326proto.prepended = function( elems ) { 7327 var items = this._itemize( elems ); 7328 if ( !items.length ) { 7329 return; 7330 } 7331 // add items to beginning of collection 7332 var previousItems = this.items.slice(0); 7333 this.items = items.concat( previousItems ); 7334 // start new layout 7335 this._resetLayout(); 7336 this._manageStamps(); 7337 // layout new stuff without transition 7338 this.layoutItems( items, true ); 7339 this.reveal( items ); 7340 // layout previous items 7341 this.layoutItems( previousItems ); 7342}; 7343 7344/** 7345 * reveal a collection of items 7346 * @param {Array of Outlayer.Items} items 7347 */ 7348proto.reveal = function( items ) { 7349 this._emitCompleteOnItems( 'reveal', items ); 7350 if ( !items || !items.length ) { 7351 return; 7352 } 7353 var stagger = this.updateStagger(); 7354 items.forEach( function( item, i ) { 7355 item.stagger( i * stagger ); 7356 item.reveal(); 7357 }); 7358}; 7359 7360/** 7361 * hide a collection of items 7362 * @param {Array of Outlayer.Items} items 7363 */ 7364proto.hide = function( items ) { 7365 this._emitCompleteOnItems( 'hide', items ); 7366 if ( !items || !items.length ) { 7367 return; 7368 } 7369 var stagger = this.updateStagger(); 7370 items.forEach( function( item, i ) { 7371 item.stagger( i * stagger ); 7372 item.hide(); 7373 }); 7374}; 7375 7376/** 7377 * reveal item elements 7378 * @param {Array}, {Element}, {NodeList} items 7379 */ 7380proto.revealItemElements = function( elems ) { 7381 var items = this.getItems( elems ); 7382 this.reveal( items ); 7383}; 7384 7385/** 7386 * hide item elements 7387 * @param {Array}, {Element}, {NodeList} items 7388 */ 7389proto.hideItemElements = function( elems ) { 7390 var items = this.getItems( elems ); 7391 this.hide( items ); 7392}; 7393 7394/** 7395 * get Outlayer.Item, given an Element 7396 * @param {Element} elem 7397 * @param {Function} callback 7398 * @returns {Outlayer.Item} item 7399 */ 7400proto.getItem = function( elem ) { 7401 // loop through items to get the one that matches 7402 for ( var i=0; i < this.items.length; i++ ) { 7403 var item = this.items[i]; 7404 if ( item.element == elem ) { 7405 // return item 7406 return item; 7407 } 7408 } 7409}; 7410 7411/** 7412 * get collection of Outlayer.Items, given Elements 7413 * @param {Array} elems 7414 * @returns {Array} items - Outlayer.Items 7415 */ 7416proto.getItems = function( elems ) { 7417 elems = utils.makeArray( elems ); 7418 var items = []; 7419 elems.forEach( function( elem ) { 7420 var item = this.getItem( elem ); 7421 if ( item ) { 7422 items.push( item ); 7423 } 7424 }, this ); 7425 7426 return items; 7427}; 7428 7429/** 7430 * remove element(s) from instance and DOM 7431 * @param {Array or NodeList or Element} elems 7432 */ 7433proto.remove = function( elems ) { 7434 var removeItems = this.getItems( elems ); 7435 7436 this._emitCompleteOnItems( 'remove', removeItems ); 7437 7438 // bail if no items to remove 7439 if ( !removeItems || !removeItems.length ) { 7440 return; 7441 } 7442 7443 removeItems.forEach( function( item ) { 7444 item.remove(); 7445 // remove item from collection 7446 utils.removeFrom( this.items, item ); 7447 }, this ); 7448}; 7449 7450// ----- destroy ----- // 7451 7452// remove and disable Outlayer instance 7453proto.destroy = function() { 7454 // clean up dynamic styles 7455 var style = this.element.style; 7456 style.height = ''; 7457 style.position = ''; 7458 style.width = ''; 7459 // destroy items 7460 this.items.forEach( function( item ) { 7461 item.destroy(); 7462 }); 7463 7464 this.unbindResize(); 7465 7466 var id = this.element.outlayerGUID; 7467 delete instances[ id ]; // remove reference to instance by id 7468 delete this.element.outlayerGUID; 7469 // remove data for jQuery 7470 if ( jQuery ) { 7471 jQuery.removeData( this.element, this.constructor.namespace ); 7472 } 7473 7474}; 7475 7476// -------------------------- data -------------------------- // 7477 7478/** 7479 * get Outlayer instance from element 7480 * @param {Element} elem 7481 * @returns {Outlayer} 7482 */ 7483Outlayer.data = function( elem ) { 7484 elem = utils.getQueryElement( elem ); 7485 var id = elem && elem.outlayerGUID; 7486 return id && instances[ id ]; 7487}; 7488 7489 7490// -------------------------- create Outlayer class -------------------------- // 7491 7492/** 7493 * create a layout class 7494 * @param {String} namespace 7495 */ 7496Outlayer.create = function( namespace, options ) { 7497 // sub-class Outlayer 7498 var Layout = subclass( Outlayer ); 7499 // apply new options and compatOptions 7500 Layout.defaults = utils.extend( {}, Outlayer.defaults ); 7501 utils.extend( Layout.defaults, options ); 7502 Layout.compatOptions = utils.extend( {}, Outlayer.compatOptions ); 7503 7504 Layout.namespace = namespace; 7505 7506 Layout.data = Outlayer.data; 7507 7508 // sub-class Item 7509 Layout.Item = subclass( Item ); 7510 7511 // -------------------------- declarative -------------------------- // 7512 7513 utils.htmlInit( Layout, namespace ); 7514 7515 // -------------------------- jQuery bridge -------------------------- // 7516 7517 // make into jQuery plugin 7518 if ( jQuery && jQuery.bridget ) { 7519 jQuery.bridget( namespace, Layout ); 7520 } 7521 7522 return Layout; 7523}; 7524 7525function subclass( Parent ) { 7526 function SubClass() { 7527 Parent.apply( this, arguments ); 7528 } 7529 7530 SubClass.prototype = Object.create( Parent.prototype ); 7531 SubClass.prototype.constructor = SubClass; 7532 7533 return SubClass; 7534} 7535 7536// ----- helpers ----- // 7537 7538// how many milliseconds are in each unit 7539var msUnits = { 7540 ms: 1, 7541 s: 1000 7542}; 7543 7544// munge time-like parameter into millisecond number 7545// '0.4s' -> 40 7546function getMilliseconds( time ) { 7547 if ( typeof time == 'number' ) { 7548 return time; 7549 } 7550 var matches = time.match( /(^\d*\.?\d*)(\w*)/ ); 7551 var num = matches && matches[1]; 7552 var unit = matches && matches[2]; 7553 if ( !num.length ) { 7554 return 0; 7555 } 7556 num = parseFloat( num ); 7557 var mult = msUnits[ unit ] || 1; 7558 return num * mult; 7559} 7560 7561// ----- fin ----- // 7562 7563// back in global 7564Outlayer.Item = Item; 7565 7566return Outlayer; 7567 7568})); 7569 7570/** 7571 * Rect 7572 * low-level utility class for basic geometry 7573 */ 7574 7575( function( window, factory ) { 7576 // universal module definition 7577 /* jshint strict: false */ /* globals define, module */ 7578 if ( typeof define == 'function' && define.amd ) { 7579 // AMD 7580 define( 'packery/js/rect',factory ); 7581 } else if ( typeof module == 'object' && module.exports ) { 7582 // CommonJS 7583 module.exports = factory(); 7584 } else { 7585 // browser global 7586 window.Packery = window.Packery || {}; 7587 window.Packery.Rect = factory(); 7588 } 7589 7590}( window, function factory() { 7591'use strict'; 7592 7593// -------------------------- Rect -------------------------- // 7594 7595function Rect( props ) { 7596 // extend properties from defaults 7597 for ( var prop in Rect.defaults ) { 7598 this[ prop ] = Rect.defaults[ prop ]; 7599 } 7600 7601 for ( prop in props ) { 7602 this[ prop ] = props[ prop ]; 7603 } 7604 7605} 7606 7607Rect.defaults = { 7608 x: 0, 7609 y: 0, 7610 width: 0, 7611 height: 0 7612}; 7613 7614var proto = Rect.prototype; 7615 7616/** 7617 * Determines whether or not this rectangle wholly encloses another rectangle or point. 7618 * @param {Rect} rect 7619 * @returns {Boolean} 7620**/ 7621proto.contains = function( rect ) { 7622 // points don't have width or height 7623 var otherWidth = rect.width || 0; 7624 var otherHeight = rect.height || 0; 7625 return this.x <= rect.x && 7626 this.y <= rect.y && 7627 this.x + this.width >= rect.x + otherWidth && 7628 this.y + this.height >= rect.y + otherHeight; 7629}; 7630 7631/** 7632 * Determines whether or not the rectangle intersects with another. 7633 * @param {Rect} rect 7634 * @returns {Boolean} 7635**/ 7636proto.overlaps = function( rect ) { 7637 var thisRight = this.x + this.width; 7638 var thisBottom = this.y + this.height; 7639 var rectRight = rect.x + rect.width; 7640 var rectBottom = rect.y + rect.height; 7641 7642 // http://stackoverflow.com/a/306332 7643 return this.x < rectRight && 7644 thisRight > rect.x && 7645 this.y < rectBottom && 7646 thisBottom > rect.y; 7647}; 7648 7649/** 7650 * @param {Rect} rect - the overlapping rect 7651 * @returns {Array} freeRects - rects representing the area around the rect 7652**/ 7653proto.getMaximalFreeRects = function( rect ) { 7654 7655 // if no intersection, return false 7656 if ( !this.overlaps( rect ) ) { 7657 return false; 7658 } 7659 7660 var freeRects = []; 7661 var freeRect; 7662 7663 var thisRight = this.x + this.width; 7664 var thisBottom = this.y + this.height; 7665 var rectRight = rect.x + rect.width; 7666 var rectBottom = rect.y + rect.height; 7667 7668 // top 7669 if ( this.y < rect.y ) { 7670 freeRect = new Rect({ 7671 x: this.x, 7672 y: this.y, 7673 width: this.width, 7674 height: rect.y - this.y 7675 }); 7676 freeRects.push( freeRect ); 7677 } 7678 7679 // right 7680 if ( thisRight > rectRight ) { 7681 freeRect = new Rect({ 7682 x: rectRight, 7683 y: this.y, 7684 width: thisRight - rectRight, 7685 height: this.height 7686 }); 7687 freeRects.push( freeRect ); 7688 } 7689 7690 // bottom 7691 if ( thisBottom > rectBottom ) { 7692 freeRect = new Rect({ 7693 x: this.x, 7694 y: rectBottom, 7695 width: this.width, 7696 height: thisBottom - rectBottom 7697 }); 7698 freeRects.push( freeRect ); 7699 } 7700 7701 // left 7702 if ( this.x < rect.x ) { 7703 freeRect = new Rect({ 7704 x: this.x, 7705 y: this.y, 7706 width: rect.x - this.x, 7707 height: this.height 7708 }); 7709 freeRects.push( freeRect ); 7710 } 7711 7712 return freeRects; 7713}; 7714 7715proto.canFit = function( rect ) { 7716 return this.width >= rect.width && this.height >= rect.height; 7717}; 7718 7719return Rect; 7720 7721})); 7722 7723/** 7724 * Packer 7725 * bin-packing algorithm 7726 */ 7727 7728( function( window, factory ) { 7729 // universal module definition 7730 /* jshint strict: false */ /* globals define, module, require */ 7731 if ( typeof define == 'function' && define.amd ) { 7732 // AMD 7733 define( 'packery/js/packer',[ './rect' ], factory ); 7734 } else if ( typeof module == 'object' && module.exports ) { 7735 // CommonJS 7736 module.exports = factory( 7737 require('./rect') 7738 ); 7739 } else { 7740 // browser global 7741 var Packery = window.Packery = window.Packery || {}; 7742 Packery.Packer = factory( Packery.Rect ); 7743 } 7744 7745}( window, function factory( Rect ) { 7746'use strict'; 7747 7748// -------------------------- Packer -------------------------- // 7749 7750/** 7751 * @param {Number} width 7752 * @param {Number} height 7753 * @param {String} sortDirection 7754 * topLeft for vertical, leftTop for horizontal 7755 */ 7756function Packer( width, height, sortDirection ) { 7757 this.width = width || 0; 7758 this.height = height || 0; 7759 this.sortDirection = sortDirection || 'downwardLeftToRight'; 7760 7761 this.reset(); 7762} 7763 7764var proto = Packer.prototype; 7765 7766proto.reset = function() { 7767 this.spaces = []; 7768 7769 var initialSpace = new Rect({ 7770 x: 0, 7771 y: 0, 7772 width: this.width, 7773 height: this.height 7774 }); 7775 7776 this.spaces.push( initialSpace ); 7777 // set sorter 7778 this.sorter = sorters[ this.sortDirection ] || sorters.downwardLeftToRight; 7779}; 7780 7781// change x and y of rect to fit with in Packer's available spaces 7782proto.pack = function( rect ) { 7783 for ( var i=0; i < this.spaces.length; i++ ) { 7784 var space = this.spaces[i]; 7785 if ( space.canFit( rect ) ) { 7786 this.placeInSpace( rect, space ); 7787 break; 7788 } 7789 } 7790}; 7791 7792proto.columnPack = function( rect ) { 7793 for ( var i=0; i < this.spaces.length; i++ ) { 7794 var space = this.spaces[i]; 7795 var canFitInSpaceColumn = space.x <= rect.x && 7796 space.x + space.width >= rect.x + rect.width && 7797 space.height >= rect.height - 0.01; // fudge number for rounding error 7798 if ( canFitInSpaceColumn ) { 7799 rect.y = space.y; 7800 this.placed( rect ); 7801 break; 7802 } 7803 } 7804}; 7805 7806proto.rowPack = function( rect ) { 7807 for ( var i=0; i < this.spaces.length; i++ ) { 7808 var space = this.spaces[i]; 7809 var canFitInSpaceRow = space.y <= rect.y && 7810 space.y + space.height >= rect.y + rect.height && 7811 space.width >= rect.width - 0.01; // fudge number for rounding error 7812 if ( canFitInSpaceRow ) { 7813 rect.x = space.x; 7814 this.placed( rect ); 7815 break; 7816 } 7817 } 7818}; 7819 7820proto.placeInSpace = function( rect, space ) { 7821 // place rect in space 7822 rect.x = space.x; 7823 rect.y = space.y; 7824 7825 this.placed( rect ); 7826}; 7827 7828// update spaces with placed rect 7829proto.placed = function( rect ) { 7830 // update spaces 7831 var revisedSpaces = []; 7832 for ( var i=0; i < this.spaces.length; i++ ) { 7833 var space = this.spaces[i]; 7834 var newSpaces = space.getMaximalFreeRects( rect ); 7835 // add either the original space or the new spaces to the revised spaces 7836 if ( newSpaces ) { 7837 revisedSpaces.push.apply( revisedSpaces, newSpaces ); 7838 } else { 7839 revisedSpaces.push( space ); 7840 } 7841 } 7842 7843 this.spaces = revisedSpaces; 7844 7845 this.mergeSortSpaces(); 7846}; 7847 7848proto.mergeSortSpaces = function() { 7849 // remove redundant spaces 7850 Packer.mergeRects( this.spaces ); 7851 this.spaces.sort( this.sorter ); 7852}; 7853 7854// add a space back 7855proto.addSpace = function( rect ) { 7856 this.spaces.push( rect ); 7857 this.mergeSortSpaces(); 7858}; 7859 7860// -------------------------- utility functions -------------------------- // 7861 7862/** 7863 * Remove redundant rectangle from array of rectangles 7864 * @param {Array} rects: an array of Rects 7865 * @returns {Array} rects: an array of Rects 7866**/ 7867Packer.mergeRects = function( rects ) { 7868 var i = 0; 7869 var rect = rects[i]; 7870 7871 rectLoop: 7872 while ( rect ) { 7873 var j = 0; 7874 var compareRect = rects[ i + j ]; 7875 7876 while ( compareRect ) { 7877 if ( compareRect == rect ) { 7878 j++; // next 7879 } else if ( compareRect.contains( rect ) ) { 7880 // remove rect 7881 rects.splice( i, 1 ); 7882 rect = rects[i]; // set next rect 7883 continue rectLoop; // bail on compareLoop 7884 } else if ( rect.contains( compareRect ) ) { 7885 // remove compareRect 7886 rects.splice( i + j, 1 ); 7887 } else { 7888 j++; 7889 } 7890 compareRect = rects[ i + j ]; // set next compareRect 7891 } 7892 i++; 7893 rect = rects[i]; 7894 } 7895 7896 return rects; 7897}; 7898 7899 7900// -------------------------- sorters -------------------------- // 7901 7902// functions for sorting rects in order 7903var sorters = { 7904 // top down, then left to right 7905 downwardLeftToRight: function( a, b ) { 7906 return a.y - b.y || a.x - b.x; 7907 }, 7908 // left to right, then top down 7909 rightwardTopToBottom: function( a, b ) { 7910 return a.x - b.x || a.y - b.y; 7911 } 7912}; 7913 7914 7915// -------------------------- -------------------------- // 7916 7917return Packer; 7918 7919})); 7920 7921/** 7922 * Packery Item Element 7923**/ 7924 7925( function( window, factory ) { 7926 // universal module definition 7927 /* jshint strict: false */ /* globals define, module, require */ 7928 if ( typeof define == 'function' && define.amd ) { 7929 // AMD 7930 define( 'packery/js/item',[ 7931 'outlayer/outlayer', 7932 './rect' 7933 ], 7934 factory ); 7935 } else if ( typeof module == 'object' && module.exports ) { 7936 // CommonJS 7937 module.exports = factory( 7938 require('outlayer'), 7939 require('./rect') 7940 ); 7941 } else { 7942 // browser global 7943 window.Packery.Item = factory( 7944 window.Outlayer, 7945 window.Packery.Rect 7946 ); 7947 } 7948 7949}( window, function factory( Outlayer, Rect ) { 7950'use strict'; 7951 7952// -------------------------- Item -------------------------- // 7953 7954var docElemStyle = document.documentElement.style; 7955 7956var transformProperty = typeof docElemStyle.transform == 'string' ? 7957 'transform' : 'WebkitTransform'; 7958 7959// sub-class Item 7960var Item = function PackeryItem() { 7961 Outlayer.Item.apply( this, arguments ); 7962}; 7963 7964var proto = Item.prototype = Object.create( Outlayer.Item.prototype ); 7965 7966var __create = proto._create; 7967proto._create = function() { 7968 // call default _create logic 7969 __create.call( this ); 7970 this.rect = new Rect(); 7971}; 7972 7973var _moveTo = proto.moveTo; 7974proto.moveTo = function( x, y ) { 7975 // don't shift 1px while dragging 7976 var dx = Math.abs( this.position.x - x ); 7977 var dy = Math.abs( this.position.y - y ); 7978 7979 var canHackGoTo = this.layout.dragItemCount && !this.isPlacing && 7980 !this.isTransitioning && dx < 1 && dy < 1; 7981 if ( canHackGoTo ) { 7982 this.goTo( x, y ); 7983 return; 7984 } 7985 _moveTo.apply( this, arguments ); 7986}; 7987 7988// -------------------------- placing -------------------------- // 7989 7990proto.enablePlacing = function() { 7991 this.removeTransitionStyles(); 7992 // remove transform property from transition 7993 if ( this.isTransitioning && transformProperty ) { 7994 this.element.style[ transformProperty ] = 'none'; 7995 } 7996 this.isTransitioning = false; 7997 this.getSize(); 7998 this.layout._setRectSize( this.element, this.rect ); 7999 this.isPlacing = true; 8000}; 8001 8002proto.disablePlacing = function() { 8003 this.isPlacing = false; 8004}; 8005 8006// ----- ----- // 8007 8008// remove element from DOM 8009proto.removeElem = function() { 8010 var parent = this.element.parentNode; 8011 if ( parent ) { 8012 parent.removeChild( this.element ); 8013 } 8014 // add space back to packer 8015 this.layout.packer.addSpace( this.rect ); 8016 this.emitEvent( 'remove', [ this ] ); 8017}; 8018 8019// ----- dropPlaceholder ----- // 8020 8021proto.showDropPlaceholder = function() { 8022 var dropPlaceholder = this.dropPlaceholder; 8023 if ( !dropPlaceholder ) { 8024 // create dropPlaceholder 8025 dropPlaceholder = this.dropPlaceholder = document.createElement('div'); 8026 dropPlaceholder.className = 'packery-drop-placeholder'; 8027 dropPlaceholder.style.position = 'absolute'; 8028 } 8029 8030 dropPlaceholder.style.width = this.size.width + 'px'; 8031 dropPlaceholder.style.height = this.size.height + 'px'; 8032 this.positionDropPlaceholder(); 8033 this.layout.element.appendChild( dropPlaceholder ); 8034}; 8035 8036proto.positionDropPlaceholder = function() { 8037 this.dropPlaceholder.style[ transformProperty ] = 'translate(' + 8038 this.rect.x + 'px, ' + this.rect.y + 'px)'; 8039}; 8040 8041proto.hideDropPlaceholder = function() { 8042 // only remove once, #333 8043 var parent = this.dropPlaceholder.parentNode; 8044 if ( parent ) { 8045 parent.removeChild( this.dropPlaceholder ); 8046 } 8047}; 8048 8049// ----- ----- // 8050 8051return Item; 8052 8053})); 8054 8055/*! 8056 * Packery v2.1.2 8057 * Gapless, draggable grid layouts 8058 * 8059 * Licensed GPLv3 for open source use 8060 * or Packery Commercial License for commercial use 8061 * 8062 * http://packery.metafizzy.co 8063 * Copyright 2013-2018 Metafizzy 8064 */ 8065 8066( function( window, factory ) { 8067 // universal module definition 8068 /* jshint strict: false */ /* globals define, module, require */ 8069 if ( typeof define == 'function' && define.amd ) { 8070 // AMD 8071 define( [ 8072 'get-size/get-size', 8073 'outlayer/outlayer', 8074 'packery/js/rect', 8075 'packery/js/packer', 8076 'packery/js/item' 8077 ], 8078 factory ); 8079 } else if ( typeof module == 'object' && module.exports ) { 8080 // CommonJS 8081 module.exports = factory( 8082 require('get-size'), 8083 require('outlayer'), 8084 require('./rect'), 8085 require('./packer'), 8086 require('./item') 8087 ); 8088 } else { 8089 // browser global 8090 window.Packery = factory( 8091 window.getSize, 8092 window.Outlayer, 8093 window.Packery.Rect, 8094 window.Packery.Packer, 8095 window.Packery.Item 8096 ); 8097 } 8098 8099}( window, function factory( getSize, Outlayer, Rect, Packer, Item ) { 8100'use strict'; 8101 8102// ----- Rect ----- // 8103 8104// allow for pixel rounding errors IE8-IE11 & Firefox; #227 8105Rect.prototype.canFit = function( rect ) { 8106 return this.width >= rect.width - 1 && this.height >= rect.height - 1; 8107}; 8108 8109// -------------------------- Packery -------------------------- // 8110 8111// create an Outlayer layout class 8112var Packery = Outlayer.create('packery'); 8113Packery.Item = Item; 8114 8115var proto = Packery.prototype; 8116 8117proto._create = function() { 8118 // call super 8119 Outlayer.prototype._create.call( this ); 8120 8121 // initial properties 8122 this.packer = new Packer(); 8123 // packer for drop targets 8124 this.shiftPacker = new Packer(); 8125 this.isEnabled = true; 8126 8127 this.dragItemCount = 0; 8128 8129 // create drag handlers 8130 var _this = this; 8131 this.handleDraggabilly = { 8132 dragStart: function() { 8133 _this.itemDragStart( this.element ); 8134 }, 8135 dragMove: function() { 8136 _this.itemDragMove( this.element, this.position.x, this.position.y ); 8137 }, 8138 dragEnd: function() { 8139 _this.itemDragEnd( this.element ); 8140 } 8141 }; 8142 8143 this.handleUIDraggable = { 8144 start: function handleUIDraggableStart( event, ui ) { 8145 // HTML5 may trigger dragstart, dismiss HTML5 dragging 8146 if ( !ui ) { 8147 return; 8148 } 8149 _this.itemDragStart( event.currentTarget ); 8150 }, 8151 drag: function handleUIDraggableDrag( event, ui ) { 8152 if ( !ui ) { 8153 return; 8154 } 8155 _this.itemDragMove( event.currentTarget, ui.position.left, ui.position.top ); 8156 }, 8157 stop: function handleUIDraggableStop( event, ui ) { 8158 if ( !ui ) { 8159 return; 8160 } 8161 _this.itemDragEnd( event.currentTarget ); 8162 } 8163 }; 8164 8165}; 8166 8167 8168// ----- init & layout ----- // 8169 8170/** 8171 * logic before any new layout 8172 */ 8173proto._resetLayout = function() { 8174 this.getSize(); 8175 8176 this._getMeasurements(); 8177 8178 // reset packer 8179 var width, height, sortDirection; 8180 // packer settings, if horizontal or vertical 8181 if ( this._getOption('horizontal') ) { 8182 width = Infinity; 8183 height = this.size.innerHeight + this.gutter; 8184 sortDirection = 'rightwardTopToBottom'; 8185 } else { 8186 width = this.size.innerWidth + this.gutter; 8187 height = Infinity; 8188 sortDirection = 'downwardLeftToRight'; 8189 } 8190 8191 this.packer.width = this.shiftPacker.width = width; 8192 this.packer.height = this.shiftPacker.height = height; 8193 this.packer.sortDirection = this.shiftPacker.sortDirection = sortDirection; 8194 8195 this.packer.reset(); 8196 8197 // layout 8198 this.maxY = 0; 8199 this.maxX = 0; 8200}; 8201 8202/** 8203 * update columnWidth, rowHeight, & gutter 8204 * @private 8205 */ 8206proto._getMeasurements = function() { 8207 this._getMeasurement( 'columnWidth', 'width' ); 8208 this._getMeasurement( 'rowHeight', 'height' ); 8209 this._getMeasurement( 'gutter', 'width' ); 8210}; 8211 8212proto._getItemLayoutPosition = function( item ) { 8213 this._setRectSize( item.element, item.rect ); 8214 if ( this.isShifting || this.dragItemCount > 0 ) { 8215 var packMethod = this._getPackMethod(); 8216 this.packer[ packMethod ]( item.rect ); 8217 } else { 8218 this.packer.pack( item.rect ); 8219 } 8220 8221 this._setMaxXY( item.rect ); 8222 return item.rect; 8223}; 8224 8225proto.shiftLayout = function() { 8226 this.isShifting = true; 8227 this.layout(); 8228 delete this.isShifting; 8229}; 8230 8231proto._getPackMethod = function() { 8232 return this._getOption('horizontal') ? 'rowPack' : 'columnPack'; 8233}; 8234 8235 8236/** 8237 * set max X and Y value, for size of container 8238 * @param {Packery.Rect} rect 8239 * @private 8240 */ 8241proto._setMaxXY = function( rect ) { 8242 this.maxX = Math.max( rect.x + rect.width, this.maxX ); 8243 this.maxY = Math.max( rect.y + rect.height, this.maxY ); 8244}; 8245 8246/** 8247 * set the width and height of a rect, applying columnWidth and rowHeight 8248 * @param {Element} elem 8249 * @param {Packery.Rect} rect 8250 */ 8251proto._setRectSize = function( elem, rect ) { 8252 var size = getSize( elem ); 8253 var w = size.outerWidth; 8254 var h = size.outerHeight; 8255 // size for columnWidth and rowHeight, if available 8256 // only check if size is non-zero, #177 8257 if ( w || h ) { 8258 w = this._applyGridGutter( w, this.columnWidth ); 8259 h = this._applyGridGutter( h, this.rowHeight ); 8260 } 8261 // rect must fit in packer 8262 rect.width = Math.min( w, this.packer.width ); 8263 rect.height = Math.min( h, this.packer.height ); 8264}; 8265 8266/** 8267 * fits item to columnWidth/rowHeight and adds gutter 8268 * @param {Number} measurement - item width or height 8269 * @param {Number} gridSize - columnWidth or rowHeight 8270 * @returns measurement 8271 */ 8272proto._applyGridGutter = function( measurement, gridSize ) { 8273 // just add gutter if no gridSize 8274 if ( !gridSize ) { 8275 return measurement + this.gutter; 8276 } 8277 gridSize += this.gutter; 8278 // fit item to columnWidth/rowHeight 8279 var remainder = measurement % gridSize; 8280 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil'; 8281 measurement = Math[ mathMethod ]( measurement / gridSize ) * gridSize; 8282 return measurement; 8283}; 8284 8285proto._getContainerSize = function() { 8286 if ( this._getOption('horizontal') ) { 8287 return { 8288 width: this.maxX - this.gutter 8289 }; 8290 } else { 8291 return { 8292 height: this.maxY - this.gutter 8293 }; 8294 } 8295}; 8296 8297 8298// -------------------------- stamp -------------------------- // 8299 8300/** 8301 * makes space for element 8302 * @param {Element} elem 8303 */ 8304proto._manageStamp = function( elem ) { 8305 8306 var item = this.getItem( elem ); 8307 var rect; 8308 if ( item && item.isPlacing ) { 8309 rect = item.rect; 8310 } else { 8311 var offset = this._getElementOffset( elem ); 8312 rect = new Rect({ 8313 x: this._getOption('originLeft') ? offset.left : offset.right, 8314 y: this._getOption('originTop') ? offset.top : offset.bottom 8315 }); 8316 } 8317 8318 this._setRectSize( elem, rect ); 8319 // save its space in the packer 8320 this.packer.placed( rect ); 8321 this._setMaxXY( rect ); 8322}; 8323 8324// -------------------------- methods -------------------------- // 8325 8326function verticalSorter( a, b ) { 8327 return a.position.y - b.position.y || a.position.x - b.position.x; 8328} 8329 8330function horizontalSorter( a, b ) { 8331 return a.position.x - b.position.x || a.position.y - b.position.y; 8332} 8333 8334proto.sortItemsByPosition = function() { 8335 var sorter = this._getOption('horizontal') ? horizontalSorter : verticalSorter; 8336 this.items.sort( sorter ); 8337}; 8338 8339/** 8340 * Fit item element in its current position 8341 * Packery will position elements around it 8342 * useful for expanding elements 8343 * 8344 * @param {Element} elem 8345 * @param {Number} x - horizontal destination position, optional 8346 * @param {Number} y - vertical destination position, optional 8347 */ 8348proto.fit = function( elem, x, y ) { 8349 var item = this.getItem( elem ); 8350 if ( !item ) { 8351 return; 8352 } 8353 8354 // stamp item to get it out of layout 8355 this.stamp( item.element ); 8356 // set placing flag 8357 item.enablePlacing(); 8358 this.updateShiftTargets( item ); 8359 // fall back to current position for fitting 8360 x = x === undefined ? item.rect.x: x; 8361 y = y === undefined ? item.rect.y: y; 8362 // position it best at its destination 8363 this.shift( item, x, y ); 8364 this._bindFitEvents( item ); 8365 item.moveTo( item.rect.x, item.rect.y ); 8366 // layout everything else 8367 this.shiftLayout(); 8368 // return back to regularly scheduled programming 8369 this.unstamp( item.element ); 8370 this.sortItemsByPosition(); 8371 item.disablePlacing(); 8372}; 8373 8374/** 8375 * emit event when item is fit and other items are laid out 8376 * @param {Packery.Item} item 8377 * @private 8378 */ 8379proto._bindFitEvents = function( item ) { 8380 var _this = this; 8381 var ticks = 0; 8382 function onLayout() { 8383 ticks++; 8384 if ( ticks != 2 ) { 8385 return; 8386 } 8387 _this.dispatchEvent( 'fitComplete', null, [ item ] ); 8388 } 8389 // when item is laid out 8390 item.once( 'layout', onLayout ); 8391 // when all items are laid out 8392 this.once( 'layoutComplete', onLayout ); 8393}; 8394 8395// -------------------------- resize -------------------------- // 8396 8397// debounced, layout on resize 8398proto.resize = function() { 8399 // don't trigger if size did not change 8400 // or if resize was unbound. See #285, outlayer#9 8401 if ( !this.isResizeBound || !this.needsResizeLayout() ) { 8402 return; 8403 } 8404 8405 if ( this.options.shiftPercentResize ) { 8406 this.resizeShiftPercentLayout(); 8407 } else { 8408 this.layout(); 8409 } 8410}; 8411 8412/** 8413 * check if layout is needed post layout 8414 * @returns Boolean 8415 */ 8416proto.needsResizeLayout = function() { 8417 var size = getSize( this.element ); 8418 var innerSize = this._getOption('horizontal') ? 'innerHeight' : 'innerWidth'; 8419 return size[ innerSize ] != this.size[ innerSize ]; 8420}; 8421 8422proto.resizeShiftPercentLayout = function() { 8423 var items = this._getItemsForLayout( this.items ); 8424 8425 var isHorizontal = this._getOption('horizontal'); 8426 var coord = isHorizontal ? 'y' : 'x'; 8427 var measure = isHorizontal ? 'height' : 'width'; 8428 var segmentName = isHorizontal ? 'rowHeight' : 'columnWidth'; 8429 var innerSize = isHorizontal ? 'innerHeight' : 'innerWidth'; 8430 8431 // proportional re-align items 8432 var previousSegment = this[ segmentName ]; 8433 previousSegment = previousSegment && previousSegment + this.gutter; 8434 8435 if ( previousSegment ) { 8436 this._getMeasurements(); 8437 var currentSegment = this[ segmentName ] + this.gutter; 8438 items.forEach( function( item ) { 8439 var seg = Math.round( item.rect[ coord ] / previousSegment ); 8440 item.rect[ coord ] = seg * currentSegment; 8441 }); 8442 } else { 8443 var currentSize = getSize( this.element )[ innerSize ] + this.gutter; 8444 var previousSize = this.packer[ measure ]; 8445 items.forEach( function( item ) { 8446 item.rect[ coord ] = ( item.rect[ coord ] / previousSize ) * currentSize; 8447 }); 8448 } 8449 8450 this.shiftLayout(); 8451}; 8452 8453// -------------------------- drag -------------------------- // 8454 8455/** 8456 * handle an item drag start event 8457 * @param {Element} elem 8458 */ 8459proto.itemDragStart = function( elem ) { 8460 if ( !this.isEnabled ) { 8461 return; 8462 } 8463 this.stamp( elem ); 8464 // this.ignore( elem ); 8465 var item = this.getItem( elem ); 8466 if ( !item ) { 8467 return; 8468 } 8469 8470 item.enablePlacing(); 8471 item.showDropPlaceholder(); 8472 this.dragItemCount++; 8473 this.updateShiftTargets( item ); 8474}; 8475 8476proto.updateShiftTargets = function( dropItem ) { 8477 this.shiftPacker.reset(); 8478 8479 // pack stamps 8480 this._getBoundingRect(); 8481 var isOriginLeft = this._getOption('originLeft'); 8482 var isOriginTop = this._getOption('originTop'); 8483 this.stamps.forEach( function( stamp ) { 8484 // ignore dragged item 8485 var item = this.getItem( stamp ); 8486 if ( item && item.isPlacing ) { 8487 return; 8488 } 8489 var offset = this._getElementOffset( stamp ); 8490 var rect = new Rect({ 8491 x: isOriginLeft ? offset.left : offset.right, 8492 y: isOriginTop ? offset.top : offset.bottom 8493 }); 8494 this._setRectSize( stamp, rect ); 8495 // save its space in the packer 8496 this.shiftPacker.placed( rect ); 8497 }, this ); 8498 8499 // reset shiftTargets 8500 var isHorizontal = this._getOption('horizontal'); 8501 var segmentName = isHorizontal ? 'rowHeight' : 'columnWidth'; 8502 var measure = isHorizontal ? 'height' : 'width'; 8503 8504 this.shiftTargetKeys = []; 8505 this.shiftTargets = []; 8506 var boundsSize; 8507 var segment = this[ segmentName ]; 8508 segment = segment && segment + this.gutter; 8509 8510 if ( segment ) { 8511 var segmentSpan = Math.ceil( dropItem.rect[ measure ] / segment ); 8512 var segs = Math.floor( ( this.shiftPacker[ measure ] + this.gutter ) / segment ); 8513 boundsSize = ( segs - segmentSpan ) * segment; 8514 // add targets on top 8515 for ( var i=0; i < segs; i++ ) { 8516 var initialX = isHorizontal ? 0 : i * segment; 8517 var initialY = isHorizontal ? i * segment : 0; 8518 this._addShiftTarget( initialX, initialY, boundsSize ); 8519 } 8520 } else { 8521 boundsSize = ( this.shiftPacker[ measure ] + this.gutter ) - dropItem.rect[ measure ]; 8522 this._addShiftTarget( 0, 0, boundsSize ); 8523 } 8524 8525 // pack each item to measure where shiftTargets are 8526 var items = this._getItemsForLayout( this.items ); 8527 var packMethod = this._getPackMethod(); 8528 items.forEach( function( item ) { 8529 var rect = item.rect; 8530 this._setRectSize( item.element, rect ); 8531 this.shiftPacker[ packMethod ]( rect ); 8532 8533 // add top left corner 8534 this._addShiftTarget( rect.x, rect.y, boundsSize ); 8535 // add bottom left / top right corner 8536 var cornerX = isHorizontal ? rect.x + rect.width : rect.x; 8537 var cornerY = isHorizontal ? rect.y : rect.y + rect.height; 8538 this._addShiftTarget( cornerX, cornerY, boundsSize ); 8539 8540 if ( segment ) { 8541 // add targets for each column on bottom / row on right 8542 var segSpan = Math.round( rect[ measure ] / segment ); 8543 for ( var i=1; i < segSpan; i++ ) { 8544 var segX = isHorizontal ? cornerX : rect.x + segment * i; 8545 var segY = isHorizontal ? rect.y + segment * i : cornerY; 8546 this._addShiftTarget( segX, segY, boundsSize ); 8547 } 8548 } 8549 }, this ); 8550 8551}; 8552 8553proto._addShiftTarget = function( x, y, boundsSize ) { 8554 var checkCoord = this._getOption('horizontal') ? y : x; 8555 if ( checkCoord !== 0 && checkCoord > boundsSize ) { 8556 return; 8557 } 8558 // create string for a key, easier to keep track of what targets 8559 var key = x + ',' + y; 8560 var hasKey = this.shiftTargetKeys.indexOf( key ) != -1; 8561 if ( hasKey ) { 8562 return; 8563 } 8564 this.shiftTargetKeys.push( key ); 8565 this.shiftTargets.push({ x: x, y: y }); 8566}; 8567 8568// -------------------------- drop -------------------------- // 8569 8570proto.shift = function( item, x, y ) { 8571 var shiftPosition; 8572 var minDistance = Infinity; 8573 var position = { x: x, y: y }; 8574 this.shiftTargets.forEach( function( target ) { 8575 var distance = getDistance( target, position ); 8576 if ( distance < minDistance ) { 8577 shiftPosition = target; 8578 minDistance = distance; 8579 } 8580 }); 8581 item.rect.x = shiftPosition.x; 8582 item.rect.y = shiftPosition.y; 8583}; 8584 8585function getDistance( a, b ) { 8586 var dx = b.x - a.x; 8587 var dy = b.y - a.y; 8588 return Math.sqrt( dx * dx + dy * dy ); 8589} 8590 8591// -------------------------- drag move -------------------------- // 8592 8593var DRAG_THROTTLE_TIME = 120; 8594 8595/** 8596 * handle an item drag move event 8597 * @param {Element} elem 8598 * @param {Number} x - horizontal change in position 8599 * @param {Number} y - vertical change in position 8600 */ 8601proto.itemDragMove = function( elem, x, y ) { 8602 var item = this.isEnabled && this.getItem( elem ); 8603 if ( !item ) { 8604 return; 8605 } 8606 8607 x -= this.size.paddingLeft; 8608 y -= this.size.paddingTop; 8609 8610 var _this = this; 8611 function onDrag() { 8612 _this.shift( item, x, y ); 8613 item.positionDropPlaceholder(); 8614 _this.layout(); 8615 } 8616 8617 // throttle 8618 var now = new Date(); 8619 var isThrottled = this._itemDragTime && now - this._itemDragTime < DRAG_THROTTLE_TIME; 8620 if ( isThrottled ) { 8621 clearTimeout( this.dragTimeout ); 8622 this.dragTimeout = setTimeout( onDrag, DRAG_THROTTLE_TIME ); 8623 } else { 8624 onDrag(); 8625 this._itemDragTime = now; 8626 } 8627}; 8628 8629// -------------------------- drag end -------------------------- // 8630 8631/** 8632 * handle an item drag end event 8633 * @param {Element} elem 8634 */ 8635proto.itemDragEnd = function( elem ) { 8636 var item = this.isEnabled && this.getItem( elem ); 8637 if ( !item ) { 8638 return; 8639 } 8640 8641 clearTimeout( this.dragTimeout ); 8642 item.element.classList.add('is-positioning-post-drag'); 8643 8644 var completeCount = 0; 8645 var _this = this; 8646 function onDragEndLayoutComplete() { 8647 completeCount++; 8648 if ( completeCount != 2 ) { 8649 return; 8650 } 8651 // reset drag item 8652 item.element.classList.remove('is-positioning-post-drag'); 8653 item.hideDropPlaceholder(); 8654 _this.dispatchEvent( 'dragItemPositioned', null, [ item ] ); 8655 } 8656 8657 item.once( 'layout', onDragEndLayoutComplete ); 8658 this.once( 'layoutComplete', onDragEndLayoutComplete ); 8659 item.moveTo( item.rect.x, item.rect.y ); 8660 this.layout(); 8661 this.dragItemCount = Math.max( 0, this.dragItemCount - 1 ); 8662 this.sortItemsByPosition(); 8663 item.disablePlacing(); 8664 this.unstamp( item.element ); 8665}; 8666 8667/** 8668 * binds Draggabilly events 8669 * @param {Draggabilly} draggie 8670 */ 8671proto.bindDraggabillyEvents = function( draggie ) { 8672 this._bindDraggabillyEvents( draggie, 'on' ); 8673}; 8674 8675proto.unbindDraggabillyEvents = function( draggie ) { 8676 this._bindDraggabillyEvents( draggie, 'off' ); 8677}; 8678 8679proto._bindDraggabillyEvents = function( draggie, method ) { 8680 var handlers = this.handleDraggabilly; 8681 draggie[ method ]( 'dragStart', handlers.dragStart ); 8682 draggie[ method ]( 'dragMove', handlers.dragMove ); 8683 draggie[ method ]( 'dragEnd', handlers.dragEnd ); 8684}; 8685 8686/** 8687 * binds jQuery UI Draggable events 8688 * @param {jQuery} $elems 8689 */ 8690proto.bindUIDraggableEvents = function( $elems ) { 8691 this._bindUIDraggableEvents( $elems, 'on' ); 8692}; 8693 8694proto.unbindUIDraggableEvents = function( $elems ) { 8695 this._bindUIDraggableEvents( $elems, 'off' ); 8696}; 8697 8698proto._bindUIDraggableEvents = function( $elems, method ) { 8699 var handlers = this.handleUIDraggable; 8700 $elems 8701 [ method ]( 'dragstart', handlers.start ) 8702 [ method ]( 'drag', handlers.drag ) 8703 [ method ]( 'dragstop', handlers.stop ); 8704}; 8705 8706// ----- destroy ----- // 8707 8708var _destroy = proto.destroy; 8709proto.destroy = function() { 8710 _destroy.apply( this, arguments ); 8711 // disable flag; prevent drag events from triggering. #72 8712 this.isEnabled = false; 8713}; 8714 8715// ----- ----- // 8716 8717Packery.Rect = Rect; 8718Packery.Packer = Packer; 8719 8720return Packery; 8721 8722})); 8723
8724 8725/*! 8726Waypoints - 4.0.0 8727Copyright © 2011-2015 Caleb Troughton 8728Licensed under the MIT license. 8729https://github.com/imakewebthings/waypoints/blob/master/licenses.txt 8730*/ 8731(function() { 8732 'use strict' 8733 8734 var keyCounter = 0 8735 var allWaypoints = {} 8736 8737 /* http://imakewebthings.com/waypoints/api/waypoint */ 8738 function Waypoint(options) { 8739 if (!options) { 8740 throw new Error('No options passed to Waypoint constructor') 8741 } 8742 if (!options.element) { 8743 throw new Error('No element option passed to Waypoint constructor') 8744 } 8745 if (!options.handler) { 8746 throw new Error('No handler option passed to Waypoint constructor') 8747 } 8748 8749 this.key = 'waypoint-' + keyCounter 8750 this.options = Waypoint.Adapter.extend({}, Waypoint.defaults, options) 8751 this.element = this.options.element 8752 this.adapter = new Waypoint.Adapter(this.element) 8753 this.callback = options.handler 8754 this.axis = this.options.horizontal ? 'horizontal' : 'vertical' 8755 this.enabled = this.options.enabled 8756 this.triggerPoint = null 8757 this.group = Waypoint.Group.findOrCreate({ 8758 name: this.options.group, 8759 axis: this.axis 8760 }) 8761 this.context = Waypoint.Context.findOrCreateByElement(this.options.context) 8762 8763 if (Waypoint.offsetAliases[this.options.offset]) { 8764 this.options.offset = Waypoint.offsetAliases[this.options.offset] 8765 } 8766 this.group.add(this) 8767 this.context.add(this) 8768 allWaypoints[this.key] = this 8769 keyCounter += 1 8770 } 8771 8772 /* Private */ 8773 Waypoint.prototype.queueTrigger = function(direction) { 8774 this.group.queueTrigger(this, direction) 8775 } 8776 8777 /* Private */ 8778 Waypoint.prototype.trigger = function(args) { 8779 if (!this.enabled) { 8780 return 8781 } 8782 if (this.callback) { 8783 this.callback.apply(this, args) 8784 } 8785 } 8786 8787 /* Public */ 8788 /* http://imakewebthings.com/waypoints/api/destroy */ 8789 Waypoint.prototype.destroy = function() { 8790 this.context.remove(this) 8791 this.group.remove(this) 8792 delete allWaypoints[this.key] 8793 } 8794 8795 /* Public */ 8796 /* http://imakewebthings.com/waypoints/api/disable */ 8797 Waypoint.prototype.disable = function() { 8798 this.enabled = false 8799 return this 8800 } 8801 8802 /* Public */ 8803 /* http://imakewebthings.com/waypoints/api/enable */ 8804 Waypoint.prototype.enable = function() { 8805 this.context.refresh() 8806 this.enabled = true 8807 return this 8808 } 8809 8810 /* Public */ 8811 /* http://imakewebthings.com/waypoints/api/next */ 8812 Waypoint.prototype.next = function() { 8813 return this.group.next(this) 8814 } 8815 8816 /* Public */ 8817 /* http://imakewebthings.com/waypoints/api/previous */ 8818 Waypoint.prototype.previous = function() { 8819 return this.group.previous(this) 8820 } 8821 8822 /* Private */ 8823 Waypoint.invokeAll = function(method) { 8824 var allWaypointsArray = []
8825 for (var waypointKey in allWaypoints) { 8826 allWaypointsArray.push(allWaypoints[waypointKey]) 8827 } 8828 for (var i = 0, end = allWaypointsArray.length; i < end; i++) { 8829 allWaypointsArray[i][method]() 8830 } 8831 } 8832 8833 /* Public */ 8834 /* http://imakewebthings.com/waypoints/api/destroy-all */ 8835 Waypoint.destroyAll = function() { 8836 Waypoint.invokeAll('destroy') 8837 } 8838 8839 /* Public */ 8840 /* http://imakewebthings.com/waypoints/api/disable-all */ 8841 Waypoint.disableAll = function() { 8842 Waypoint.invokeAll('disable') 8843 } 8844 8845 /* Public */ 8846 /* http://imakewebthings.com/waypoints/api/enable-all */ 8847 Waypoint.enableAll = function() { 8848 Waypoint.invokeAll('enable') 8849 } 8850 8851 /* Public */ 8852 /* http://imakewebthings.com/waypoints/api/refresh-all */ 8853 Waypoint.refreshAll = function() { 8854 Waypoint.Context.refreshAll() 8855 } 8856 8857 /* Public */ 8858 /* http://imakewebthings.com/waypoints/api/viewport-height */ 8859 Waypoint.viewportHeight = function() { 8860 return window.innerHeight || document.documentElement.clientHeight 8861 } 8862 8863 /* Public */ 8864 /* http://imakewebthings.com/waypoints/api/viewport-width */ 8865 Waypoint.viewportWidth = function() { 8866 return document.documentElement.clientWidth 8867 } 8868 8869 Waypoint.adapters = [] 8870 8871 Waypoint.defaults = { 8872 context: window, 8873 continuous: true, 8874 enabled: true, 8875 group: 'default', 8876 horizontal: false, 8877 offset: 0 8878 } 8879 8880 Waypoint.offsetAliases = { 8881 'bottom-in-view': function() { 8882 return this.context.innerHeight() - this.adapter.outerHeight() 8883 }, 8884 'right-in-view': function() { 8885 return this.context.innerWidth() - this.adapter.outerWidth() 8886 } 8887 } 8888 8889 window.Waypoint = Waypoint 8890}()) 8891;(function() { 8892 'use strict' 8893 8894 function requestAnimationFrameShim(callback) { 8895 window.setTimeout(callback, 1000 / 60) 8896 } 8897 8898 var keyCounter = 0 8899 var contexts = {} 8900 var Waypoint = window.Waypoint 8901 var oldWindowLoad = window.onload 8902 8903 /* http://imakewebthings.com/waypoints/api/context */ 8904 function Context(element) { 8905 this.element = element 8906 this.Adapter = Waypoint.Adapter 8907 this.adapter = new this.Adapter(element) 8908 this.key = 'waypoint-context-' + keyCounter 8909 this.didScroll = false 8910 this.didResize = false 8911 this.oldScroll = { 8912 x: this.adapter.scrollLeft(), 8913 y: this.adapter.scrollTop() 8914 } 8915 this.waypoints = { 8916 vertical: {}, 8917 horizontal: {} 8918 } 8919 8920 element.waypointContextKey = this.key 8921 contexts[element.waypointContextKey] = this 8922 keyCounter += 1 8923 8924 this.createThrottledScrollHandler() 8925 this.createThrottledResizeHandler() 8926 } 8927 8928 /* Private */ 8929 Context.prototype.add = function(waypoint) { 8930 var axis = waypoint.options.horizontal ? 'horizontal' : 'vertical' 8931 this.waypoints[axis][waypoint.key] = waypoint 8932 this.refresh() 8933 } 8934 8935 /* Private */ 8936 Context.prototype.checkEmpty = function() { 8937 var horizontalEmpty = this.Adapter.isEmptyObject(this.waypoints.horizontal) 8938 var verticalEmpty = this.Adapter.isEmptyObject(this.waypoints.vertical) 8939 if (horizontalEmpty && verticalEmpty) { 8940 this.adapter.off('.waypoints') 8941 delete contexts[this.key] 8942 } 8943 } 8944 8945 /* Private */ 8946 Context.prototype.createThrottledResizeHandler = function() { 8947 var self = this 8948 8949 function resizeHandler() { 8950 self.handleResize() 8951 self.didResize = false 8952 } 8953 8954 this.adapter.on('resize.waypoints', function() { 8955 if (!self.didResize) { 8956 self.didResize = true 8957 Waypoint.requestAnimationFrame(resizeHandler) 8958 } 8959 }) 8960 } 8961 8962 /* Private */ 8963 Context.prototype.createThrottledScrollHandler = function() { 8964 var self = this 8965 function scrollHandler() { 8966 self.handleScroll() 8967 self.didScroll = false 8968 } 8969 8970 this.adapter.on('scroll.waypoints', function() { 8971 if (!self.didScroll || Waypoint.isTouch) { 8972 self.didScroll = true 8973 Waypoint.requestAnimationFrame(scrollHandler) 8974 } 8975 }) 8976 } 8977 8978 /* Private */ 8979 Context.prototype.handleResize = function() { 8980 Waypoint.Context.refreshAll() 8981 } 8982 8983 /* Private */ 8984 Context.prototype.handleScroll = function() { 8985 var triggeredGroups = {} 8986 var axes = { 8987 horizontal: { 8988 newScroll: this.adapter.scrollLeft(), 8989 oldScroll: this.oldScroll.x, 8990 forward: 'right', 8991 backward: 'left' 8992 }, 8993 vertical: { 8994 newScroll: this.adapter.scrollTop(), 8995 oldScroll: this.oldScroll.y, 8996 forward: 'down', 8997 backward: 'up' 8998 } 8999 } 9000 9001 for (var axisKey in axes) { 9002 var axis = axes[axisKey] 9003 var isForward = axis.newScroll > axis.oldScroll 9004 var direction = isForward ? axis.forward : axis.backward 9005
9006 for (var waypointKey in this.waypoints[axisKey]) { 9007 var waypoint = this.waypoints[axisKey][waypointKey] 9008 var wasBeforeTriggerPoint = axis.oldScroll < waypoint.triggerPoint 9009 var nowAfterTriggerPoint = axis.newScroll >= waypoint.triggerPoint 9010 var crossedForward = wasBeforeTriggerPoint && nowAfterTriggerPoint 9011 var crossedBackward = !wasBeforeTriggerPoint && !nowAfterTriggerPoint 9012 if (crossedForward || crossedBackward) { 9013 waypoint.queueTrigger(direction) 9014 triggeredGroups[waypoint.group.id] = waypoint.group 9015 } 9016 } 9017 } 9018 9019 for (var groupKey in triggeredGroups) { 9020 triggeredGroups[groupKey].flushTriggers() 9021 } 9022 9023 this.oldScroll = { 9024 x: axes.horizontal.newScroll, 9025 y: axes.vertical.newScroll 9026 } 9027 } 9028 9029 /* Private */ 9030 Context.prototype.innerHeight = function() { 9031 /*eslint-disable eqeqeq */ 9032 if (this.element == this.element.window) { 9033 return Waypoint.viewportHeight() 9034 } 9035 /*eslint-enable eqeqeq */ 9036 return this.adapter.innerHeight() 9037 } 9038 9039 /* Private */ 9040 Context.prototype.remove = function(waypoint) { 9041 delete this.waypoints[waypoint.axis][waypoint.key] 9042 this.checkEmpty() 9043 } 9044 9045 /* Private */ 9046 Context.prototype.innerWidth = function() { 9047 /*eslint-disable eqeqeq */ 9048 if (this.element == this.element.window) { 9049 return Waypoint.viewportWidth() 9050 } 9051 /*eslint-enable eqeqeq */ 9052 return this.adapter.innerWidth() 9053 } 9054 9055 /* Public */ 9056 /* http://imakewebthings.com/waypoints/api/context-destroy */ 9057 Context.prototype.destroy = function() { 9058 var allWaypoints = [] 9059 for (var axis in this.waypoints) {
9060 for (var waypointKey in this.waypoints[axis]) { 9061 allWaypoints.push(this.waypoints[axis][waypointKey]) 9062 } 9063 } 9064 for (var i = 0, end = allWaypoints.length; i < end; i++) { 9065 allWaypoints[i].destroy() 9066 } 9067 } 9068 9069 /* Public */ 9070 /* http://imakewebthings.com/waypoints/api/context-refresh */ 9071 Context.prototype.refresh = function() { 9072 /*eslint-disable eqeqeq */ 9073 var isWindow = this.element == this.element.window 9074 /*eslint-enable eqeqeq */ 9075 var contextOffset = isWindow ? undefined : this.adapter.offset() 9076 var triggeredGroups = {} 9077 var axes 9078 9079 this.handleScroll() 9080 axes = { 9081 horizontal: { 9082 contextOffset: isWindow ? 0 : contextOffset.left, 9083 contextScroll: isWindow ? 0 : this.oldScroll.x, 9084 contextDimension: this.innerWidth(), 9085 oldScroll: this.oldScroll.x, 9086 forward: 'right', 9087 backward: 'left', 9088 offsetProp: 'left' 9089 }, 9090 vertical: { 9091 contextOffset: isWindow ? 0 : contextOffset.top, 9092 contextScroll: isWindow ? 0 : this.oldScroll.y, 9093 contextDimension: this.innerHeight(), 9094 oldScroll: this.oldScroll.y, 9095 forward: 'down', 9096 backward: 'up', 9097 offsetProp: 'top' 9098 } 9099 } 9100 9101 for (var axisKey in axes) { 9102 var axis = axes[axisKey]
9103 for (var waypointKey in this.waypoints[axisKey]) { 9104 var waypoint = this.waypoints[axisKey][waypointKey] 9105 var adjustment = waypoint.options.offset 9106 var oldTriggerPoint = waypoint.triggerPoint 9107 var elementOffset = 0 9108 var freshWaypoint = oldTriggerPoint == null 9109 var contextModifier, wasBeforeScroll, nowAfterScroll 9110 var triggeredBackward, triggeredForward 9111 9112 if (waypoint.element !== waypoint.element.window) { 9113 elementOffset = waypoint.adapter.offset()[axis.offsetProp] 9114 } 9115 9116 if (typeof adjustment === 'function') { 9117 adjustment = adjustment.apply(waypoint) 9118 } 9119 else if (typeof adjustment === 'string') { 9120 adjustment = parseFloat(adjustment) 9121 if (waypoint.options.offset.indexOf('%') > - 1) { 9122 adjustment = Math.ceil(axis.contextDimension * adjustment / 100) 9123 } 9124 } 9125 9126 contextModifier = axis.contextScroll - axis.contextOffset 9127 waypoint.triggerPoint = elementOffset + contextModifier - adjustment 9128 wasBeforeScroll = oldTriggerPoint < axis.oldScroll 9129 nowAfterScroll = waypoint.triggerPoint >= axis.oldScroll 9130 triggeredBackward = wasBeforeScroll && nowAfterScroll 9131 triggeredForward = !wasBeforeScroll && !nowAfterScroll 9132 9133 if (!freshWaypoint && triggeredBackward) { 9134 waypoint.queueTrigger(axis.backward) 9135 triggeredGroups[waypoint.group.id] = waypoint.group 9136 } 9137 else if (!freshWaypoint && triggeredForward) { 9138 waypoint.queueTrigger(axis.forward) 9139 triggeredGroups[waypoint.group.id] = waypoint.group 9140 } 9141 else if (freshWaypoint && axis.oldScroll >= waypoint.triggerPoint) { 9142 waypoint.queueTrigger(axis.forward) 9143 triggeredGroups[waypoint.group.id] = waypoint.group 9144 } 9145 } 9146 } 9147 9148 Waypoint.requestAnimationFrame(function() { 9149 for (var groupKey in triggeredGroups) { 9150 triggeredGroups[groupKey].flushTriggers() 9151 } 9152 }) 9153 9154 return this 9155 } 9156 9157 /* Private */ 9158 Context.findOrCreateByElement = function(element) { 9159 return Context.findByElement(element) || new Context(element) 9160 } 9161 9162 /* Private */ 9163 Context.refreshAll = function() { 9164 for (var contextId in contexts) { 9165 contexts[contextId].refresh() 9166 } 9167 } 9168 9169 /* Public */ 9170 /* http://imakewebthings.com/waypoints/api/context-find-by-element */ 9171 Context.findByElement = function(element) { 9172 return contexts[element.waypointContextKey] 9173 } 9174 9175 window.onload = function() { 9176 if (oldWindowLoad) { 9177 oldWindowLoad() 9178 } 9179 Context.refreshAll() 9180 } 9181 9182 Waypoint.requestAnimationFrame = function(callback) { 9183 var requestFn = window.requestAnimationFrame || 9184 window.mozRequestAnimationFrame || 9185 window.webkitRequestAnimationFrame || 9186 requestAnimationFrameShim 9187 requestFn.call(window, callback) 9188 } 9189 Waypoint.Context = Context 9190}()) 9191;(function() { 9192 'use strict' 9193 9194 function byTriggerPoint(a, b) { 9195 return a.triggerPoint - b.triggerPoint 9196 } 9197 9198 function byReverseTriggerPoint(a, b) { 9199 return b.triggerPoint - a.triggerPoint 9200 } 9201 9202 var groups = { 9203 vertical: {}, 9204 horizontal: {} 9205 } 9206 var Waypoint = window.Waypoint 9207 9208 /* http://imakewebthings.com/waypoints/api/group */ 9209 function Group(options) { 9210 this.name = options.name 9211 this.axis = options.axis 9212 this.id = this.name + '-' + this.axis 9213 this.waypoints = [] 9214 this.clearTriggerQueues() 9215 groups[this.axis][this.name] = this 9216 } 9217 9218 /* Private */ 9219 Group.prototype.add = function(waypoint) { 9220 this.waypoints.push(waypoint) 9221 } 9222 9223 /* Private */ 9224 Group.prototype.clearTriggerQueues = function() { 9225 this.triggerQueues = { 9226 up: [], 9227 down: [], 9228 left: [], 9229 right: [] 9230 } 9231 } 9232 9233 /* Private */ 9234 Group.prototype.flushTriggers = function() { 9235 for (var direction in this.triggerQueues) { 9236 var waypoints = this.triggerQueues[direction] 9237 var reverse = direction === 'up' || direction === 'left' 9238 waypoints.sort(reverse ? byReverseTriggerPoint : byTriggerPoint) 9239 for (var i = 0, end = waypoints.length; i < end; i += 1) { 9240 var waypoint = waypoints[i] 9241 if (waypoint.options.continuous || i === waypoints.length - 1) { 9242 waypoint.trigger([direction]) 9243 } 9244 } 9245 } 9246 this.clearTriggerQueues() 9247 } 9248 9249 /* Private */ 9250 Group.prototype.next = function(waypoint) { 9251 this.waypoints.sort(byTriggerPoint) 9252 var index = Waypoint.Adapter.inArray(waypoint, this.waypoints) 9253 var isLast = index === this.waypoints.length - 1 9254 return isLast ? null : this.waypoints[index + 1] 9255 } 9256 9257 /* Private */ 9258 Group.prototype.previous = function(waypoint) { 9259 this.waypoints.sort(byTriggerPoint) 9260 var index = Waypoint.Adapter.inArray(waypoint, this.waypoints) 9261 return index ? this.waypoints[index - 1] : null 9262 } 9263 9264 /* Private */ 9265 Group.prototype.queueTrigger = function(waypoint, direction) { 9266 this.triggerQueues[direction].push(waypoint) 9267 } 9268 9269 /* Private */ 9270 Group.prototype.remove = function(waypoint) { 9271 var index = Waypoint.Adapter.inArray(waypoint, this.waypoints) 9272 if (index > -1) { 9273 this.waypoints.splice(index, 1) 9274 } 9275 } 9276 9277 /* Public */ 9278 /* http://imakewebthings.com/waypoints/api/first */ 9279 Group.prototype.first = function() { 9280 return this.waypoints[0] 9281 } 9282 9283 /* Public */ 9284 /* http://imakewebthings.com/waypoints/api/last */ 9285 Group.prototype.last = function() { 9286 return this.waypoints[this.waypoints.length - 1] 9287 } 9288 9289 /* Private */ 9290 Group.findOrCreate = function(options) { 9291 return groups[options.axis][options.name] || new Group(options) 9292 } 9293 9294 Waypoint.Group = Group 9295}()) 9296;(function() { 9297 'use strict' 9298 9299 var $ = window.jQuery 9300 var Waypoint = window.Waypoint 9301 9302 function JQueryAdapter(element) { 9303 this.$element = $(element) 9304 } 9305 9306 $.each([
9307 'innerHeight', 9308 'innerWidth', 9309 'off', 9310 'offset', 9311 'on', 9312 'outerHeight', 9313 'outerWidth', 9314 'scrollLeft', 9315 'scrollTop' 9316 ], function(i, method) { 9317 JQueryAdapter.prototype[method] = function() { 9318 var args = Array.prototype.slice.call(arguments) 9319 return this.$element[method].apply(this.$element, args) 9320 } 9321 }) 9322 9323 $.each([ 9324 'extend', 9325 'inArray', 9326 'isEmptyObject' 9327 ], function(i, method) { 9328 JQueryAdapter[method] = $[method] 9329 }) 9330 9331 Waypoint.adapters.push({ 9332 name: 'jquery', 9333 Adapter: JQueryAdapter 9334 }) 9335 Waypoint.Adapter = JQueryAdapter 9336}()) 9337;(function() { 9338 'use strict' 9339 9340 var Waypoint = window.Waypoint 9341 9342 function createExtension(framework) { 9343 return function() { 9344 var waypoints = [] 9345 var overrides = arguments[0] 9346 9347 if (framework.isFunction(arguments[0])) { 9348 overrides = framework.extend({}, arguments[1]) 9349 overrides.handler = arguments[0] 9350 } 9351 9352 this.each(function() { 9353 var options = framework.extend({}, overrides, { 9354 element: this 9355 }) 9356 if (typeof options.context === 'string') { 9357 options.context = framework(this).closest(options.context)[0] 9358 } 9359 waypoints.push(new Waypoint(options)) 9360 }) 9361 9362 return waypoints 9363 } 9364 } 9365 9366 if (window.jQuery) { 9367 window.jQuery.fn.waypoint = createExtension(window.jQuery) 9368 } 9369 if (window.Zepto) { 9370 window.Zepto.fn.waypoint = createExtension(window.Zepto) 9371 } 9372}()) 9373; 9374/*! 9375Waypoints Inview Shortcut - 4.0.0 9376Copyright © 2011-2015 Caleb Troughton 9377Licensed under the MIT license. 9378https://github.com/imakewebthings/waypoints/blob/master/licenses.txt 9379*/ 9380(function() { 9381 'use strict' 9382 9383 function noop() {} 9384 9385 var Waypoint = window.Waypoint 9386 9387 /* http://imakewebthings.com/waypoints/shortcuts/inview */ 9388 function Inview(options) { 9389 this.options = Waypoint.Adapter.extend({}, Inview.defaults, options) 9390 this.axis = this.options.horizontal ? 'horizontal' : 'vertical' 9391 this.waypoints = [] 9392 this.element = this.options.element 9393 this.createWaypoints() 9394 } 9395 9396 /* Private */ 9397 Inview.prototype.createWaypoints = function() { 9398 var configs = { 9399 vertical: [{ 9400 down: 'enter', 9401 up: 'exited', 9402 offset: '100%' 9403 }, { 9404 down: 'entered', 9405 up: 'exit', 9406 offset: 'bottom-in-view' 9407 }, { 9408 down: 'exit', 9409 up: 'entered', 9410 offset: 0 9411 }, { 9412 down: 'exited', 9413 up: 'enter', 9414 offset: function() { 9415 return -this.adapter.outerHeight() 9416 } 9417 }], 9418 horizontal: [{ 9419 right: 'enter', 9420 left: 'exited', 9421 offset: '100%' 9422 }, { 9423 right: 'entered', 9424 left: 'exit', 9425 offset: 'right-in-view' 9426 }, { 9427 right: 'exit', 9428 left: 'entered', 9429 offset: 0 9430 }, { 9431 right: 'exited', 9432 left: 'enter', 9433 offset: function() { 9434 return -this.adapter.outerWidth() 9435 } 9436 }] 9437 } 9438 9439 for (var i = 0, end = configs[this.axis].length; i < end; i++) { 9440 var config = configs[this.axis][i] 9441 this.createWaypoint(config) 9442 } 9443 } 9444 9445 /* Private */ 9446 Inview.prototype.createWaypoint = function(config) { 9447 var self = this 9448 this.waypoints.push(new Waypoint({ 9449 context: this.options.context, 9450 element: this.options.element, 9451 enabled: this.options.enabled, 9452 handler: (function(config) { 9453 return function(direction) { 9454 self.options[config[direction]].call(self, direction) 9455 } 9456 }(config)), 9457 offset: config.offset, 9458 horizontal: this.options.horizontal 9459 })) 9460 } 9461 9462 /* Public */ 9463 Inview.prototype.destroy = function() { 9464 for (var i = 0, end = this.waypoints.length; i < end; i++) { 9465 this.waypoints[i].destroy() 9466 } 9467 this.waypoints = [] 9468 } 9469 9470 Inview.prototype.disable = function() { 9471 for (var i = 0, end = this.waypoints.length; i < end; i++) { 9472 this.waypoints[i].disable() 9473 } 9474 } 9475 9476 Inview.prototype.enable = function() { 9477 for (var i = 0, end = this.waypoints.length; i < end; i++) { 9478 this.waypoints[i].enable() 9479 } 9480 } 9481 9482 Inview.defaults = { 9483 context: window, 9484 enabled: true, 9485 enter: noop, 9486 entered: noop,
9487 exit: noop, 9488 exited: noop 9489 } 9490 9491 Waypoint.Inview = Inview 9492}()) 9493; 9494/** 9495 * Swiper 3.4.2 9496 * Most modern mobile touch slider and framework with hardware accelerated transitions 9497 * 9498 * http://www.idangero.us/swiper/ 9499 * 9500 * Copyright 2017, Vladimir Kharlampidi 9501 * The iDangero.us 9502 * http://www.idangero.us/ 9503 * 9504 * Licensed under MIT 9505 * 9506 * Released on: March 10, 2017 9507 */ 9508(function () { 9509 'use strict'; 9510 var $; 9511 9512 /*=========================== 9513 Swiper 9514 ===========================*/ 9515 var Swiper = function (container, params) { 9516 if (!(this instanceof Swiper)) return new Swiper(container, params); 9517 9518 9519 var defaults = { 9520 direction: 'horizontal', 9521 touchEventsTarget: 'container', 9522 initialSlide: 0, 9523 speed: 300, 9524 // autoplay 9525 autoplay: false, 9526 autoplayDisableOnInteraction: true, 9527 autoplayStopOnLast: false, 9528 // To support iOS's swipe-to-go-back gesture (when being used in-app, with UIWebView). 9529 iOSEdgeSwipeDetection: false, 9530 iOSEdgeSwipeThreshold: 20, 9531 // Free mode 9532 freeMode: false, 9533 freeModeMomentum: true, 9534 freeModeMomentumRatio: 1, 9535 freeModeMomentumBounce: true, 9536 freeModeMomentumBounceRatio: 1, 9537 freeModeMomentumVelocityRatio: 1, 9538 freeModeSticky: false, 9539 freeModeMinimumVelocity: 0.02, 9540 // Autoheight 9541 autoHeight: false, 9542 // Set wrapper width 9543 setWrapperSize: false, 9544 // Virtual Translate 9545 virtualTranslate: false, 9546 // Effects 9547 effect: 'slide', // 'slide' or 'fade' or 'cube' or 'coverflow' or 'flip' 9548 coverflow: { 9549 rotate: 50, 9550 stretch: 0, 9551 depth: 100, 9552 modifier: 1, 9553 slideShadows : true 9554 }, 9555 flip: { 9556 slideShadows : true, 9557 limitRotation: true 9558 }, 9559 cube: { 9560 slideShadows: true, 9561 shadow: true, 9562 shadowOffset: 20, 9563 shadowScale: 0.94 9564 }, 9565 fade: { 9566 crossFade: false 9567 }, 9568 // Parallax 9569 parallax: false, 9570 // Zoom 9571 zoom: false, 9572 zoomMax: 3, 9573 zoomMin: 1, 9574 zoomToggle: true, 9575 // Scrollbar 9576 scrollbar: null, 9577 scrollbarHide: true, 9578 scrollbarDraggable: false, 9579 scrollbarSnapOnRelease: false, 9580 // Keyboard Mousewheel 9581 keyboardControl: false, 9582 mousewheelControl: false, 9583 mousewheelReleaseOnEdges: false, 9584 mousewheelInvert: false,
9585 mousewheelForceToAxis: false, 9586 mousewheelSensitivity: 1, 9587 mousewheelEventsTarged: 'container', 9588 // Hash Navigation 9589 hashnav: false, 9590 hashnavWatchState: false, 9591 // History 9592 history: false, 9593 // Commong Nav State 9594 replaceState: false, 9595 // Breakpoints 9596 breakpoints: undefined, 9597 // Slides grid 9598 spaceBetween: 0, 9599 slidesPerView: 1, 9600 slidesPerColumn: 1, 9601 slidesPerColumnFill: 'column', 9602 slidesPerGroup: 1, 9603 centeredSlides: false, 9604 slidesOffsetBefore: 0, // in px 9605 slidesOffsetAfter: 0, // in px 9606 // Round length 9607 roundLengths: false, 9608 // Touches 9609 touchRatio: 1, 9610 touchAngle: 45, 9611 simulateTouch: true, 9612 shortSwipes: true, 9613 longSwipes: true, 9614 longSwipesRatio: 0.5, 9615 longSwipesMs: 300, 9616 followFinger: true, 9617 onlyExternal: false, 9618 threshold: 0, 9619 touchMoveStopPropagation: true, 9620 touchReleaseOnEdges: false, 9621 // Unique Navigation Elements 9622 uniqueNavElements: true, 9623 // Pagination 9624 pagination: null, 9625 paginationElement: 'span', 9626 paginationClickable: false, 9627 paginationHide: false, 9628 paginationBulletRender: null, 9629 paginationProgressRender: null, 9630 paginationFractionRender: null, 9631 paginationCustomRender: null, 9632 paginationType: 'bullets', // 'bullets' or 'progress' or 'fraction' or 'custom' 9633 // Resistance 9634 resistance: true, 9635 resistanceRatio: 0.85, 9636 // Next/prev buttons 9637 nextButton: null, 9638 prevButton: null, 9639 // Progress 9640 watchSlidesProgress: false, 9641 watchSlidesVisibility: false, 9642 // Cursor 9643 grabCursor: false, 9644 // Clicks 9645 preventClicks: true, 9646 preventClicksPropagation: true, 9647 slideToClickedSlide: false, 9648 // Lazy Loading 9649 lazyLoading: false, 9650 lazyLoadingInPrevNext: false, 9651 lazyLoadingInPrevNextAmount: 1, 9652 lazyLoadingOnTransitionStart: false, 9653 // Images 9654 preloadImages: true, 9655 updateOnImagesReady: true, 9656 // loop 9657 loop: false, 9658 loopAdditionalSlides: 0, 9659 loopedSlides: null, 9660 // Control 9661 control: undefined, 9662 controlInverse: false, 9663 controlBy: 'slide', //or 'container' 9664 normalizeSlideIndex: true, 9665 // Swiping/no swiping 9666 allowSwipeToPrev: true, 9667 allowSwipeToNext: true, 9668 swipeHandler: null, //'.swipe-handler', 9669 noSwiping: true, 9670 noSwipingClass: 'swiper-no-swiping', 9671 // Passive Listeners 9672 passiveListeners: true, 9673 // NS 9674 containerModifierClass: 'swiper-container-', // NEW 9675 slideClass: 'swiper-slide', 9676 slideActiveClass: 'swiper-slide-active', 9677 slideDuplicateActiveClass: 'swiper-slide-duplicate-active', 9678 slideVisibleClass: 'swiper-slide-visible', 9679 slideDuplicateClass: 'swiper-slide-duplicate', 9680 slideNextClass: 'swiper-slide-next', 9681 slideDuplicateNextClass: 'swiper-slide-duplicate-next', 9682 slidePrevClass: 'swiper-slide-prev', 9683 slideDuplicatePrevClass: 'swiper-slide-duplicate-prev', 9684 wrapperClass: 'swiper-wrapper', 9685 bulletClass: 'swiper-pagination-bullet', 9686 bulletActiveClass: 'swiper-pagination-bullet-active', 9687 buttonDisabledClass: 'swiper-button-disabled', 9688 paginationCurrentClass: 'swiper-pagination-current', 9689 paginationTotalClass: 'swiper-pagination-total', 9690 paginationHiddenClass: 'swiper-pagination-hidden', 9691 paginationProgressbarClass: 'swiper-pagination-progressbar', 9692 paginationClickableClass: 'swiper-pagination-clickable', // NEW 9693 paginationModifierClass: 'swiper-pagination-', // NEW 9694 lazyLoadingClass: 'swiper-lazy', 9695 lazyStatusLoadingClass: 'swiper-lazy-loading', 9696 lazyStatusLoadedClass: 'swiper-lazy-loaded', 9697 lazyPreloaderClass: 'swiper-lazy-preloader', 9698 notificationClass: 'swiper-notification', 9699 preloaderClass: 'preloader', 9700 zoomContainerClass: 'swiper-zoom-container', 9701 9702 // Observer 9703 observer: false, 9704 observeParents: false, 9705 // Accessibility
9706 a11y: false, 9707 prevSlideMessage: 'Previous slide', 9708 nextSlideMessage: 'Next slide', 9709 firstSlideMessage: 'This is the first slide', 9710 lastSlideMessage: 'This is the last slide', 9711 paginationBulletMessage: 'Go to slide {{index}}', 9712 // Callbacks 9713 runCallbacksOnInit: true 9714 /* 9715 Callbacks: 9716 onInit: function (swiper) 9717 onDestroy: function (swiper) 9718 onBeforeResize: function (swiper) 9719 onAfterResize: function (swiper) 9720 onClick: function (swiper, e) 9721 onTap: function (swiper, e) 9722 onDoubleTap: function (swiper, e) 9723 onSliderMove: function (swiper, e) 9724 onSlideChangeStart: function (swiper) 9725 onSlideChangeEnd: function (swiper) 9726 onTransitionStart: function (swiper) 9727 onTransitionEnd: function (swiper) 9728 onImagesReady: function (swiper) 9729 onProgress: function (swiper, progress) 9730 onTouchStart: function (swiper, e) 9731 onTouchMove: function (swiper, e) 9732 onTouchMoveOpposite: function (swiper, e) 9733 onTouchEnd: function (swiper, e) 9734 onReachBeginning: function (swiper) 9735 onReachEnd: function (swiper) 9736 onSetTransition: function (swiper, duration) 9737 onSetTranslate: function (swiper, translate) 9738 onAutoplayStart: function (swiper) 9739 onAutoplayStop: function (swiper), 9740 onLazyImageLoad: function (swiper, slide, image) 9741 onLazyImageReady: function (swiper, slide, image) 9742 onKeyPress: function (swiper, keyCode) 9743 */ 9744 9745 }; 9746 var initialVirtualTranslate = params && params.virtualTranslate; 9747 9748 params = params || {}; 9749 var originalParams = {}; 9750 for (var param in params) { 9751 if (typeof params[param] === 'object' && params[param] !== null && !(params[param].nodeType || params[param] === window || params[param] === document || (typeof Dom7 !== 'undefined' && params[param] instanceof Dom7) || (typeof jQuery !== 'undefined' && params[param] instanceof jQuery))) { 9752 originalParams[param] = {}; 9753 for (var deepParam in params[param]) { 9754 originalParams[param][deepParam] = params[param][deepParam]; 9755 } 9756 } 9757 else { 9758 originalParams[param] = params[param]; 9759 } 9760 } 9761 for (var def in defaults) { 9762 if (typeof params[def] === 'undefined') { 9763 params[def] = defaults[def]; 9764 } 9765 else if (typeof params[def] === 'object') { 9766 for (var deepDef in defaults[def]) { 9767 if (typeof params[def][deepDef] === 'undefined') { 9768 params[def][deepDef] = defaults[def][deepDef]; 9769 } 9770 } 9771 } 9772 } 9773 9774 // Swiper 9775 var s = this; 9776 9777 // Params 9778 s.params = params; 9779 s.originalParams = originalParams; 9780 9781 // Classname 9782 s.classNames = []; 9783 /*========================= 9784 Dom Library and plugins 9785 ===========================*/ 9786 if (typeof $ !== 'undefined' && typeof Dom7 !== 'undefined'){ 9787 $ = Dom7; 9788 } 9789 if (typeof $ === 'undefined') { 9790 if (typeof Dom7 === 'undefined') { 9791 $ = window.Dom7 || window.Zepto || window.jQuery; 9792 } 9793 else { 9794 $ = Dom7; 9795 } 9796 if (!$) return; 9797 } 9798 // Export it to Swiper instance 9799 s.$ = $; 9800 9801 /*========================= 9802 Breakpoints 9803 ===========================*/ 9804 s.currentBreakpoint = undefined; 9805 s.getActiveBreakpoint = function () { 9806 //Get breakpoint for window width 9807 if (!s.params.breakpoints) return false; 9808 var breakpoint = false; 9809 var points = [], point; 9810 for ( point in s.params.breakpoints ) { 9811 if (s.params.breakpoints.hasOwnProperty(point)) { 9812 points.push(point); 9813 } 9814 } 9815 points.sort(function (a, b) { 9816 return parseInt(a, 10) > parseInt(b, 10); 9817 }); 9818 for (var i = 0; i < points.length; i++) { 9819 point = points[i]; 9820 if (point >= window.innerWidth && !breakpoint) { 9821 breakpoint = point; 9822 } 9823 } 9824 return breakpoint || 'max'; 9825 }; 9826 s.setBreakpoint = function () { 9827 //Set breakpoint for window width and update parameters 9828 var breakpoint = s.getActiveBreakpoint(); 9829 if (breakpoint && s.currentBreakpoint !== breakpoint) { 9830 var breakPointsParams = breakpoint in s.params.breakpoints ? s.params.breakpoints[breakpoint] : s.originalParams; 9831 var needsReLoop = s.params.loop && (breakPointsParams.slidesPerView !== s.params.slidesPerView); 9832 for ( var param in breakPointsParams ) { 9833 s.params[param] = breakPointsParams[param]; 9834 } 9835 s.currentBreakpoint = breakpoint; 9836 if(needsReLoop && s.destroyLoop) { 9837 s.reLoop(true); 9838 } 9839 } 9840 }; 9841 // Set breakpoint on load 9842 if (s.params.breakpoints) { 9843 s.setBreakpoint(); 9844 } 9845 9846 /*=========================
9847 Preparation - Define Container, Wrapper and Pagination 9848 ===========================*/ 9849 s.container = $(container); 9850 if (s.container.length === 0) return; 9851 if (s.container.length > 1) { 9852 var swipers = []; 9853 s.container.each(function () { 9854 var container = this; 9855 swipers.push(new Swiper(this, params)); 9856 }); 9857 return swipers; 9858 } 9859 9860 // Save instance in container HTML Element and in data 9861 s.container[0].swiper = s; 9862 s.container.data('swiper', s); 9863 9864 s.classNames.push(s.params.containerModifierClass + s.params.direction); 9865 9866 if (s.params.freeMode) { 9867 s.classNames.push(s.params.containerModifierClass + 'free-mode'); 9868 } 9869 if (!s.support.flexbox) { 9870 s.classNames.push(s.params.containerModifierClass + 'no-flexbox'); 9871 s.params.slidesPerColumn = 1; 9872 } 9873 if (s.params.autoHeight) { 9874 s.classNames.push(s.params.containerModifierClass + 'autoheight'); 9875 } 9876 // Enable slides progress when required 9877 if (s.params.parallax || s.params.watchSlidesVisibility) { 9878 s.params.watchSlidesProgress = true; 9879 } 9880 // Max resistance when touchReleaseOnEdges 9881 if (s.params.touchReleaseOnEdges) { 9882 s.params.resistanceRatio = 0; 9883 } 9884 // Coverflow / 3D 9885 if (['cube', 'coverflow', 'flip'].indexOf(s.params.effect) >= 0) { 9886 if (s.support.transforms3d) { 9887 s.params.watchSlidesProgress = true; 9888 s.classNames.push(s.params.containerModifierClass + '3d'); 9889 } 9890 else { 9891 s.params.effect = 'slide'; 9892 } 9893 } 9894 if (s.params.effect !== 'slide') { 9895 s.classNames.push(s.params.containerModifierClass + s.params.effect); 9896 } 9897 if (s.params.effect === 'cube') { 9898 s.params.resistanceRatio = 0; 9899 s.params.slidesPerView = 1; 9900 s.params.slidesPerColumn = 1; 9901 s.params.slidesPerGroup = 1; 9902 s.params.centeredSlides = false; 9903 s.params.spaceBetween = 0; 9904 s.params.virtualTranslate = true; 9905 } 9906 if (s.params.effect === 'fade' || s.params.effect === 'flip') { 9907 s.params.slidesPerView = 1; 9908 s.params.slidesPerColumn = 1; 9909 s.params.slidesPerGroup = 1; 9910 s.params.watchSlidesProgress = true; 9911 s.params.spaceBetween = 0; 9912 if (typeof initialVirtualTranslate === 'undefined') { 9913 s.params.virtualTranslate = true; 9914 } 9915 } 9916 9917 // Grab Cursor 9918 if (s.params.grabCursor && s.support.touch) { 9919 s.params.grabCursor = false; 9920 } 9921 9922 // Wrapper 9923 s.wrapper = s.container.children('.' + s.params.wrapperClass); 9924 9925 // Pagination 9926 if (s.params.pagination) { 9927 s.paginationContainer = $(s.params.pagination); 9928 if (s.params.uniqueNavElements && typeof s.params.pagination === 'string' && s.paginationContainer.length > 1 && s.container.find(s.params.pagination).length === 1) { 9929 s.paginationContainer = s.container.find(s.params.pagination); 9930 } 9931 9932 if (s.params.paginationType === 'bullets' && s.params.paginationClickable) { 9933 s.paginationContainer.addClass(s.params.paginationModifierClass + 'clickable'); 9934 } 9935 else { 9936 s.params.paginationClickable = false; 9937 } 9938 s.paginationContainer.addClass(s.params.paginationModifierClass + s.params.paginationType); 9939 } 9940 // Next/Prev Buttons 9941 if (s.params.nextButton || s.params.prevButton) { 9942 if (s.params.nextButton) { 9943 s.nextButton = $(s.params.nextButton); 9944 if (s.params.uniqueNavElements && typeof s.params.nextButton === 'string' && s.nextButton.length > 1 && s.container.find(s.params.nextButton).length === 1) { 9945 s.nextButton = s.container.find(s.params.nextButton); 9946 } 9947 } 9948 if (s.params.prevButton) { 9949 s.prevButton = $(s.params.prevButton); 9950 if (s.params.uniqueNavElements && typeof s.params.prevButton === 'string' && s.prevButton.length > 1 && s.container.find(s.params.prevButton).length === 1) { 9951 s.prevButton = s.container.find(s.params.prevButton); 9952 } 9953 } 9954 } 9955 9956 // Is Horizontal 9957 s.isHorizontal = function () { 9958 return s.params.direction === 'horizontal'; 9959 }; 9960 // s.isH = isH; 9961 9962 // RTL 9963 s.rtl = s.isHorizontal() && (s.container[0].dir.toLowerCase() === 'rtl' || s.container.css('direction') === 'rtl'); 9964 if (s.rtl) { 9965 s.classNames.push(s.params.containerModifierClass + 'rtl'); 9966 } 9967 9968 // Wrong RTL support 9969 if (s.rtl) { 9970 s.wrongRTL = s.wrapper.css('display') === '-webkit-box'; 9971 } 9972 9973 // Columns 9974 if (s.params.slidesPerColumn > 1) { 9975 s.classNames.push(s.params.containerModifierClass + 'multirow'); 9976 } 9977 9978 // Check for Android 9979 if (s.device.android) { 9980 s.classNames.push(s.params.containerModifierClass + 'android'); 9981 } 9982 9983 // Add classes 9984 s.container.addClass(s.classNames.join(' ')); 9985 9986 // Translate 9987 s.translate = 0; 9988 9989 // Progress 9990 s.progress = 0; 9991 9992 // Velocity 9993 s.velocity = 0; 9994 9995 /*========================= 9996 Locks, unlocks 9997 ===========================*/ 9998 s.lockSwipeToNext = function () { 9999 s.params.allowSwipeToNext = false;
10000 if (s.params.allowSwipeToPrev === false && s.params.grabCursor) { 10001 s.unsetGrabCursor(); 10002 } 10003 }; 10004 s.lockSwipeToPrev = function () { 10005 s.params.allowSwipeToPrev = false; 10006 if (s.params.allowSwipeToNext === false && s.params.grabCursor) { 10007 s.unsetGrabCursor(); 10008 } 10009 }; 10010 s.lockSwipes = function () { 10011 s.params.allowSwipeToNext = s.params.allowSwipeToPrev = false; 10012 if (s.params.grabCursor) s.unsetGrabCursor(); 10013 }; 10014 s.unlockSwipeToNext = function () { 10015 s.params.allowSwipeToNext = true; 10016 if (s.params.allowSwipeToPrev === true && s.params.grabCursor) { 10017 s.setGrabCursor(); 10018 } 10019 }; 10020 s.unlockSwipeToPrev = function () { 10021 s.params.allowSwipeToPrev = true; 10022 if (s.params.allowSwipeToNext === true && s.params.grabCursor) { 10023 s.setGrabCursor(); 10024 } 10025 }; 10026 s.unlockSwipes = function () { 10027 s.params.allowSwipeToNext = s.params.allowSwipeToPrev = true; 10028 if (s.params.grabCursor) s.setGrabCursor(); 10029 }; 10030 10031 /*========================= 10032 Round helper 10033 ===========================*/ 10034 function round(a) { 10035 return Math.floor(a); 10036 } 10037 /*========================= 10038 Set grab cursor 10039 ===========================*/ 10040 s.setGrabCursor = function(moving) { 10041 s.container[0].style.cursor = 'move'; 10042 s.container[0].style.cursor = moving ? '-webkit-grabbing' : '-webkit-grab'; 10043 s.container[0].style.cursor = moving ? '-moz-grabbin' : '-moz-grab'; 10044 s.container[0].style.cursor = moving ? 'grabbing': 'grab'; 10045 }; 10046 s.unsetGrabCursor = function () { 10047 s.container[0].style.cursor = ''; 10048 }; 10049 if (s.params.grabCursor) { 10050 s.setGrabCursor(); 10051 } 10052 /*========================= 10053 Update on Images Ready 10054 ===========================*/ 10055 s.imagesToLoad = []; 10056 s.imagesLoaded = 0; 10057 10058 s.loadImage = function (imgElement, src, srcset, sizes, checkForComplete, callback) { 10059 var image; 10060 function onReady () { 10061 if (callback) callback(); 10062 } 10063 if (!imgElement.complete || !checkForComplete) { 10064 if (src) { 10065 image = new window.Image(); 10066 image.onload = onReady; 10067 image.onerror = onReady; 10068 if (sizes) { 10069 image.sizes = sizes; 10070 } 10071 if (srcset) { 10072 image.srcset = srcset; 10073 } 10074 if (src) { 10075 image.src = src; 10076 } 10077 } else { 10078 onReady(); 10079 } 10080 10081 } else {//image already loaded... 10082 onReady(); 10083 } 10084 }; 10085 s.preloadImages = function () { 10086 s.imagesToLoad = s.container.find('img'); 10087 function _onReady() { 10088 if (typeof s === 'undefined' || s === null || !s) return; 10089 if (s.imagesLoaded !== undefined) s.imagesLoaded++; 10090 if (s.imagesLoaded === s.imagesToLoad.length) { 10091 if (s.params.updateOnImagesReady) s.update(); 10092 s.emit('onImagesReady', s); 10093 } 10094 } 10095 for (var i = 0; i < s.imagesToLoad.length; i++) { 10096 s.loadImage(s.imagesToLoad[i], (s.imagesToLoad[i].currentSrc || s.imagesToLoad[i].getAttribute('src')), (s.imagesToLoad[i].srcset || s.imagesToLoad[i].getAttribute('srcset')), s.imagesToLoad[i].sizes || s.imagesToLoad[i].getAttribute('sizes'), true, _onReady); 10097 } 10098 }; 10099 10100 /*========================= 10101 Autoplay 10102 ===========================*/ 10103 s.autoplayTimeoutId = undefined; 10104 s.autoplaying = false; 10105 s.autoplayPaused = false;
10106 function autoplay() { 10107 var autoplayDelay = s.params.autoplay; 10108 var activeSlide = s.slides.eq(s.activeIndex); 10109 if (activeSlide.attr('data-swiper-autoplay')) { 10110 autoplayDelay = activeSlide.attr('data-swiper-autoplay') || s.params.autoplay; 10111 } 10112 s.autoplayTimeoutId = setTimeout(function () { 10113 if (s.params.loop) { 10114 s.fixLoop(); 10115 s._slideNext(); 10116 s.emit('onAutoplay', s); 10117 } 10118 else { 10119 if (!s.isEnd) { 10120 s._slideNext(); 10121 s.emit('onAutoplay', s); 10122 } 10123 else { 10124 if (!params.autoplayStopOnLast) { 10125 s._slideTo(0); 10126 s.emit('onAutoplay', s); 10127 } 10128 else { 10129 s.stopAutoplay(); 10130 } 10131 } 10132 } 10133 }, autoplayDelay); 10134 } 10135 s.startAutoplay = function () { 10136 if (typeof s.autoplayTimeoutId !== 'undefined') return false; 10137 if (!s.params.autoplay) return false; 10138 if (s.autoplaying) return false; 10139 s.autoplaying = true; 10140 s.emit('onAutoplayStart', s); 10141 autoplay(); 10142 }; 10143 s.stopAutoplay = function (internal) { 10144 if (!s.autoplayTimeoutId) return; 10145 if (s.autoplayTimeoutId) clearTimeout(s.autoplayTimeoutId); 10146 s.autoplaying = false; 10147 s.autoplayTimeoutId = undefined; 10148 s.emit('onAutoplayStop', s); 10149 }; 10150 s.pauseAutoplay = function (speed) { 10151 if (s.autoplayPaused) return; 10152 if (s.autoplayTimeoutId) clearTimeout(s.autoplayTimeoutId); 10153 s.autoplayPaused = true; 10154 if (speed === 0) { 10155 s.autoplayPaused = false; 10156 autoplay(); 10157 } 10158 else { 10159 s.wrapper.transitionEnd(function () { 10160 if (!s) return; 10161 s.autoplayPaused = false; 10162 if (!s.autoplaying) { 10163 s.stopAutoplay(); 10164 } 10165 else { 10166 autoplay(); 10167 } 10168 }); 10169 } 10170 }; 10171 /*========================= 10172 Min/Max Translate 10173 ===========================*/ 10174 s.minTranslate = function () { 10175 return (-s.snapGrid[0]); 10176 }; 10177 s.maxTranslate = function () { 10178 return (-s.snapGrid[s.snapGrid.length - 1]); 10179 }; 10180 /*========================= 10181 Slider/slides sizes 10182 ===========================*/ 10183 s.updateAutoHeight = function () { 10184 var activeSlides = []; 10185 var newHeight = 0; 10186 var i; 10187 10188 // Find slides currently in view 10189 if(s.params.slidesPerView !== 'auto' && s.params.slidesPerView > 1) { 10190 for (i = 0; i < Math.ceil(s.params.slidesPerView); i++) { 10191 var index = s.activeIndex + i; 10192 if(index > s.slides.length) break; 10193 activeSlides.push(s.slides.eq(index)[0]); 10194 } 10195 } else { 10196 activeSlides.push(s.slides.eq(s.activeIndex)[0]); 10197 } 10198 10199 // Find new height from heighest slide in view 10200 for (i = 0; i < activeSlides.length; i++) { 10201 if (typeof activeSlides[i] !== 'undefined') { 10202 var height = activeSlides[i].offsetHeight; 10203 newHeight = height > newHeight ? height : newHeight; 10204 } 10205 } 10206 10207 // Update Height 10208 if (newHeight) s.wrapper.css('height', newHeight + 'px'); 10209 }; 10210 s.updateContainerSize = function () { 10211 var width, height; 10212 if (typeof s.params.width !== 'undefined') { 10213 width = s.params.width; 10214 } 10215 else { 10216 width = s.container[0].clientWidth; 10217 } 10218 if (typeof s.params.height !== 'undefined') { 10219 height = s.params.height; 10220 } 10221 else { 10222 height = s.container[0].clientHeight; 10223 } 10224 if (width === 0 && s.isHorizontal() || height === 0 && !s.isHorizontal()) { 10225 return; 10226 } 10227 10228 //Subtract paddings 10229 width = width - parseInt(s.container.css('padding-left'), 10) - parseInt(s.container.css('padding-right'), 10); 10230 height = height - parseInt(s.container.css('padding-top'), 10) - parseInt(s.container.css('padding-bottom'), 10); 10231 10232 // Store values 10233 s.width = width; 10234 s.height = height; 10235 s.size = s.isHorizontal() ? s.width : s.height; 10236 }; 10237 10238 s.updateSlidesSize = function () { 10239 s.slides = s.wrapper.children('.' + s.params.slideClass); 10240 s.snapGrid = []; 10241 s.slidesGrid = []; 10242 s.slidesSizesGrid = []; 10243 10244 var spaceBetween = s.params.spaceBetween, 10245 slidePosition = -s.params.slidesOffsetBefore, 10246 i, 10247 prevSlideSize = 0, 10248 index = 0; 10249 if (typeof s.size === 'undefined') return; 10250 if (typeof spaceBetween === 'string' && spaceBetween.indexOf('%') >= 0) { 10251 spaceBetween = parseFloat(spaceBetween.replace('%', '')) / 100 * s.size; 10252 } 10253 10254 s.virtualSize = -spaceBetween; 10255 // reset margins 10256 if (s.rtl) s.slides.css({marginLeft: '', marginTop: ''}); 10257 else s.slides.css({marginRight: '', marginBottom: ''}); 10258
10259 var slidesNumberEvenToRows; 10260 if (s.params.slidesPerColumn > 1) { 10261 if (Math.floor(s.slides.length / s.params.slidesPerColumn) === s.slides.length / s.params.slidesPerColumn) { 10262 slidesNumberEvenToRows = s.slides.length; 10263 } 10264 else { 10265 slidesNumberEvenToRows = Math.ceil(s.slides.length / s.params.slidesPerColumn) * s.params.slidesPerColumn; 10266 } 10267 if (s.params.slidesPerView !== 'auto' && s.params.slidesPerColumnFill === 'row') { 10268 slidesNumberEvenToRows = Math.max(slidesNumberEvenToRows, s.params.slidesPerView * s.params.slidesPerColumn); 10269 } 10270 } 10271 10272 // Calc slides 10273 var slideSize; 10274 var slidesPerColumn = s.params.slidesPerColumn; 10275 var slidesPerRow = slidesNumberEvenToRows / slidesPerColumn; 10276 var numFullColumns = slidesPerRow - (s.params.slidesPerColumn * slidesPerRow - s.slides.length); 10277 for (i = 0; i < s.slides.length; i++) { 10278 slideSize = 0; 10279 var slide = s.slides.eq(i); 10280 if (s.params.slidesPerColumn > 1) { 10281 // Set slides order 10282 var newSlideOrderIndex; 10283 var column, row; 10284 if (s.params.slidesPerColumnFill === 'column') { 10285 column = Math.floor(i / slidesPerColumn); 10286 row = i - column * slidesPerColumn; 10287 if (column > numFullColumns || (column === numFullColumns && row === slidesPerColumn-1)) { 10288 if (++row >= slidesPerColumn) { 10289 row = 0; 10290 column++; 10291 } 10292 } 10293 newSlideOrderIndex = column + row * slidesNumberEvenToRows / slidesPerColumn; 10294 slide 10295 .css({ 10296 '-webkit-box-ordinal-group': newSlideOrderIndex, 10297 '-moz-box-ordinal-group': newSlideOrderIndex, 10298 '-ms-flex-order': newSlideOrderIndex, 10299 '-webkit-order': newSlideOrderIndex, 10300 'order': newSlideOrderIndex 10301 }); 10302 } 10303 else { 10304 row = Math.floor(i / slidesPerRow); 10305 column = i - row * slidesPerRow; 10306 } 10307 slide 10308 .css( 10309 'margin-' + (s.isHorizontal() ? 'top' : 'left'), 10310 (row !== 0 && s.params.spaceBetween) && (s.params.spaceBetween + 'px') 10311 ) 10312 .attr('data-swiper-column', column) 10313 .attr('data-swiper-row', row); 10314 10315 } 10316 if (slide.css('display') === 'none') continue; 10317 if (s.params.slidesPerView === 'auto') { 10318 slideSize = s.isHorizontal() ? slide.outerWidth(true) : slide.outerHeight(true); 10319 if (s.params.roundLengths) slideSize = round(slideSize); 10320 } 10321 else { 10322 slideSize = (s.size - (s.params.slidesPerView - 1) * spaceBetween) / s.params.slidesPerView; 10323 if (s.params.roundLengths) slideSize = round(slideSize); 10324 10325 if (s.isHorizontal()) { 10326 s.slides[i].style.width = slideSize + 'px'; 10327 } 10328 else { 10329 s.slides[i].style.height = slideSize + 'px'; 10330 } 10331 } 10332 s.slides[i].swiperSlideSize = slideSize; 10333 s.slidesSizesGrid.push(slideSize); 10334 10335 10336 if (s.params.centeredSlides) { 10337 slidePosition = slidePosition + slideSize / 2 + prevSlideSize / 2 + spaceBetween; 10338 if(prevSlideSize === 0 && i !== 0) slidePosition = slidePosition - s.size / 2 - spaceBetween; 10339 if (i === 0) slidePosition = slidePosition - s.size / 2 - spaceBetween; 10340 if (Math.abs(slidePosition) < 1 / 1000) slidePosition = 0; 10341 if ((index) % s.params.slidesPerGroup === 0) s.snapGrid.push(slidePosition); 10342 s.slidesGrid.push(slidePosition); 10343 } 10344 else { 10345 if ((index) % s.params.slidesPerGroup === 0) s.snapGrid.push(slidePosition); 10346 s.slidesGrid.push(slidePosition); 10347 slidePosition = slidePosition + slideSize + spaceBetween; 10348 } 10349 10350 s.virtualSize += slideSize + spaceBetween; 10351 10352 prevSlideSize = slideSize; 10353 10354 index ++; 10355 } 10356 s.virtualSize = Math.max(s.virtualSize, s.size) + s.params.slidesOffsetAfter; 10357 var newSlidesGrid; 10358 10359 if ( 10360 s.rtl && s.wrongRTL && (s.params.effect === 'slide' || s.params.effect === 'coverflow')) { 10361 s.wrapper.css({width: s.virtualSize + s.params.spaceBetween + 'px'}); 10362 } 10363 if (!s.support.flexbox || s.params.setWrapperSize) { 10364 if (s.isHorizontal()) s.wrapper.css({width: s.virtualSize + s.params.spaceBetween + 'px'}); 10365 else s.wrapper.css({height: s.virtualSize + s.params.spaceBetween + 'px'}); 10366 } 10367 10368 if (s.params.slidesPerColumn > 1) { 10369 s.virtualSize = (slideSize + s.params.spaceBetween) * slidesNumber
10369EvenToRows; 10370 s.virtualSize = Math.ceil(s.virtualSize / s.params.slidesPerColumn) - s.params.spaceBetween; 10371 if (s.isHorizontal()) s.wrapper.css({width: s.virtualSize + s.params.spaceBetween + 'px'}); 10372 else s.wrapper.css({height: s.virtualSize + s.params.spaceBetween + 'px'}); 10373 if (s.params.centeredSlides) { 10374 newSlidesGrid = []; 10375 for (i = 0; i < s.snapGrid.length; i++) { 10376 if (s.snapGrid[i] < s.virtualSize + s.snapGrid[0]) newSlidesGrid.push(s.snapGrid[i]); 10377 } 10378 s.snapGrid = newSlidesGrid; 10379 } 10380 } 10381 10382 // Remove last grid elements depending on width 10383 if (!s.params.centeredSlides) { 10384 newSlidesGrid = []; 10385 for (i = 0; i < s.snapGrid.length; i++) { 10386 if (s.snapGrid[i] <= s.virtualSize - s.size) { 10387 newSlidesGrid.push(s.snapGrid[i]); 10388 } 10389 } 10390 s.snapGrid = newSlidesGrid; 10391 if (Math.floor(s.virtualSize - s.size) - Math.floor(s.snapGrid[s.snapGrid.length - 1]) > 1) { 10392 s.snapGrid.push(s.virtualSize - s.size); 10393 } 10394 } 10395 if (s.snapGrid.length === 0) s.snapGrid = [0]; 10396 10397 if (s.params.spaceBetween !== 0) { 10398 if (s.isHorizontal()) { 10399 if (s.rtl) s.slides.css({marginLeft: spaceBetween + 'px'}); 10400 else s.slides.css({marginRight: spaceBetween + 'px'}); 10401 } 10402 else s.slides.css({marginBottom: spaceBetween + 'px'}); 10403 } 10404 if (s.params.watchSlidesProgress) { 10405 s.updateSlidesOffset(); 10406 } 10407 }; 10408 s.updateSlidesOffset = function () { 10409 for (var i = 0; i < s.slides.length; i++) { 10410 s.slides[i].swiperSlideOffset = s.isHorizontal() ? s.slides[i].offsetLeft : s.slides[i].offsetTop; 10411 } 10412 }; 10413 10414 /*========================= 10415 Dynamic Slides Per View 10416 ===========================*/ 10417 s.currentSlidesPerView = function () { 10418 var spv = 1, i, j; 10419 if (s.params.centeredSlides) { 10420 var size = s.slides[s.activeIndex].swiperSlideSize; 10421 var breakLoop; 10422 for (i = s.activeIndex + 1; i < s.slides.length; i++) { 10423 if (s.slides[i] && !breakLoop) { 10424 size += s.slides[i].swiperSlideSize; 10425 spv ++; 10426 if (size > s.size) breakLoop = true; 10427 } 10428 } 10429 for (j = s.activeIndex - 1; j >= 0; j--) { 10430 if (s.slides[j] && !breakLoop) { 10431 size += s.slides[j].swiperSlideSize; 10432 spv ++; 10433 if (size > s.size) breakLoop = true; 10434 } 10435 } 10436 } 10437 else { 10438 for (i = s.activeIndex + 1; i < s.slides.length; i++) { 10439 if (s.slidesGrid[i] - s.slidesGrid[s.activeIndex] < s.size) { 10440 spv++; 10441 } 10442 } 10443 } 10444 return spv; 10445 }; 10446 /*========================= 10447 Slider/slides progress 10448 ===========================*/ 10449 s.updateSlidesProgress = function (translate) { 10450 if (typeof translate === 'undefined') { 10451 translate = s.translate || 0; 10452 } 10453 if (s.slides.length === 0) return; 10454 if (typeof s.slides[0].swiperSlideOffset === 'undefined') s.updateSlidesOffset(); 10455 10456 var offsetCenter = -translate; 10457 if (s.rtl) offsetCenter = translate; 10458 10459 // Visible Slides 10460 s.slides.removeClass(s.params.slideVisibleClass); 10461 for (var i = 0; i < s.slides.length; i++) { 10462 var slide = s.slides[i]; 10463 var slideProgress = (offsetCenter + (s.params.centeredSlides ? s.minTranslate() : 0) - slide.swiperSlideOffset) / (slide.swiperSlideSize + s.params.spaceBetween); 10464 if (s.params.watchSlidesVisibility) { 10465 var slideBefore = -(offsetCenter - slide.swiperSlideOffset); 10466 var slideAfter = slideBefore + s.slidesSizesGrid[i]; 10467 var isVisible = 10468 (slideBefore >= 0 && slideBefore < s.size) || 10469 (slideAfter > 0 && slideAfter <= s.size) || 10470 (slideBefore <= 0 && slideAfter >= s.size); 10471 if (isVisible) { 10472 s.slides.eq(i).addClass(s.params.slideVisibleClass); 10473 } 10474 } 10475 slide.progress = s.rtl ? -slideProgress : slideProgress; 10476 } 10477 }; 10478 s.updateProgress = function (translate) { 10479 if (typeof translate === 'undefined') { 10480 translate = s.translate || 0; 10481 } 10482 var translatesDiff = s.maxTranslate() - s.minTranslate(); 10483 var wasBeginning = s.isBeginning; 10484 var wasEnd = s.isEnd; 10485 if (translatesDiff === 0) { 10486 s.progress = 0; 10487 s.isBeginning = s.isEnd = true; 10488 } 10489 else { 10490 s.progress = (translate - s.minTranslate()) / (translatesDiff); 10491 s.isBeginning = s.progress <= 0; 10492 s.isEnd = s.progress >= 1; 10493 } 10494 if (s.isBeginning && !wasBeginning) s.emit('onReachBeginning', s); 10495 if (s.isEnd && !wasEnd) s.emit('onReachEnd', s); 10496 10497 if (s.params.watchSlidesProgress) s.updateSlidesProgress(translate); 10498 s.emit('onProgress', s, s.progress); 10499 }; 10500 s.updateActiveIndex = function () { 10501 var translate = s.rtl ? s.translate : -s.translate; 10502 var newActiveIndex, i, snapIndex; 10503 for (i = 0; i < s.slidesGrid.length; i ++) { 10504 if (typeof s.slidesGrid[i + 1] !== 'undefined') { 10505 if (translate >= s.slidesGrid[i] && translate < s.slidesGrid[i + 1] - (s.slidesGrid[i + 1] - s.slidesGrid[i]) / 2) { 10506 newActiveIndex = i; 10507 } 10508 else if (translate >= s.slidesGrid[i] && translate < s.slidesGrid[i + 1]) { 10509 newActiveIndex = i + 1; 10510 } 10511 } 10512 else { 10513 if (translate >= s.slidesGrid[i]) { 10514 newActiveIndex = i; 10515 } 10516 } 10517 } 10518 // Normalize slideIndex 10519 if(s.params.normalizeSlideIndex){ 10520 if (newActiveIndex < 0 || typeof newActiveIndex === 'undefined') newActiveIndex = 0; 10521 } 10522 // for (i = 0; i < s.slidesGrid.length; i++) { 10523 // if (- translate >= s.slidesGrid[i]) { 10524 // newActiveIndex = i; 10525 // } 10526 // } 10527 snapIndex = Math.floor(newActiveIndex / s.params.slidesPerGroup); 10528 if (snapIndex >= s.snapGrid.length) snapIndex = s.snapGrid.length - 1; 10529 10530 if (newActiveIndex === s.activeIndex) { 10531 return; 10532 } 10533 s.snapIndex = snapIndex; 10534 s.previousIndex = s.activeIndex; 10535 s.activeIndex = newActiveIndex; 10536 s.updateClasses(); 10537 s.updateRealIndex(); 10538 }; 10539 s.updateRealIndex = function(){ 10540 s.realIndex = parseInt(s.slides.eq(s.activeIndex).attr('data-swiper-slide-index') || s.activeIndex, 10); 10541 }; 10542 10543 /*========================= 10544 Classes 10545 ===========================*/ 10546 s.updateClasses = function () { 10547 s.slides.removeClass(s.params.slideActiveClass + ' ' + s.params.slideNextClass + ' ' + s.params.slidePrevClass + ' ' + s.params.slideDuplicateActiveClass + ' ' + s.params.slideDuplicateNextClass + ' ' + s.params.slideDuplicatePrevClass); 10548 var activeSlide = s.slides.eq(s.activeIndex); 10549 // Active classes 10550 activeSlide.addClass(s.params.slideActiveClass); 10551 if (params.loop) { 10552 // Duplicate to all looped slides 10553 if (activeSlide.hasClass(s.params.slideDuplicateClass)) { 10554 s.wrapper.children('.' + s.params.slideClass + ':not(.' + s.params.slideDuplicateClass + ')[data-swiper-slide-index="' + s.realIndex + '"]').addClass(s.params.slideDuplicateActiveClass); 10555 } 10556 else { 10557 s.wrapper.children('.' + s.params.slideClass + '.' + s.params.slideDuplicateClass + '[data-swiper-slide-index="' + s.realIndex + '"]').addClass(s.params.slideDuplicateActiveClass); 10558 } 10559 } 10560 // Next Slide 10561 var nextSlide = activeSlide.next('.' + s.params.slideClass).addClass(s.params.slideNextClass); 10562 if (s.params.loop && nextSlide.length === 0) { 10563 nextSlide = s.slides.eq(0); 10564 nextSlide.addClass(s.params.slideNextClass); 10565 } 10566 // Prev Slide 10567 var prevSlide = activeSlide.prev('.' + s.params.slideClass).addClass(s.params.slidePrevClass); 10568 if (s.params.loop && prevSlide.length === 0) { 10569 prevSlide = s.slides.eq(-1); 10570 prevSlide.addClass(s.params.slidePrevClass); 10571 } 10572 if (params.loop) { 10573 // Duplicate to all looped slides 10574 if (nextSlide.hasClass(s.params.slideDuplicateClass)) { 10575 s.wrapper.children('.' + s.params.slideClass + ':not(.' + s.params.slideDuplicateClass + ')[data-swiper-slide-index="' + nextSlide.attr('data-swiper-slide-index') + '"]').addClass(s.params.slideDuplicateNextClass); 10576 } 10577 else { 10578 s.wrapper.children('.' + s.params.slideClass + '.' + s.params.slideDuplicateClass + '[data-swiper-slide-index="' + nextSlide.attr('data-swiper-slide-index') + '"]').addClass(s.params.slideDuplicateNextClass); 10579 } 10580 if (prevSlide.hasClass(s.params.slideDuplicateClass)) { 10581 s.wrapper.children('.' + s.params.slideClass + ':not(.' + s.params.slideDuplicateClass + ')[data-swiper-slide-index="' + prevSlide.attr('data-swiper-slide-index') + '"]').addClass(s.params.slideDuplicatePrevClass); 10582 } 10583 else { 10584 s.wrapper.children('.' + s.params.slideClass + '.' + s.params.slideDuplicateClass + '[data-swiper-slide-index="' + prevSlide.attr('data-swiper-slide-index') + '"]').addClass(s.params.slideDuplicatePrevClass); 10585 } 10586 } 10587 10588 // Pagination 10589 if (s.paginationContainer && s.paginationContainer.length > 0) { 10590 // Current/Total 10591 var current, 10592 total = s.params.loop ? Math.ceil((s.slides.length - s.loopedSlides * 2) / s.params.slidesPerGroup) : s.snapGrid.length; 10593 if (s.params.loop) {
10594 current = Math.ceil((s.activeIndex - s.loopedSlides)/s.params.slidesPerGroup); 10595 if (current > s.slides.length - 1 - s.loopedSlides * 2) { 10596 current = current - (s.slides.length - s.loopedSlides * 2); 10597 } 10598 if (current > total - 1) current = current - total; 10599 if (current < 0 && s.params.paginationType !== 'bullets') current = total + current; 10600 } 10601 else { 10602 if (typeof s.snapIndex !== 'undefined') { 10603 current = s.snapIndex; 10604 } 10605 else { 10606 current = s.activeIndex || 0; 10607 } 10608 } 10609 // Types 10610 if (s.params.paginationType === 'bullets' && s.bullets && s.bullets.length > 0) { 10611 s.bullets.removeClass(s.params.bulletActiveClass); 10612 if (s.paginationContainer.length > 1) { 10613 s.bullets.each(function () { 10614 if ($(this).index() === current) $(this).addClass(s.params.bulletActiveClass); 10615 }); 10616 } 10617 else { 10618 s.bullets.eq(current).addClass(s.params.bulletActiveClass); 10619 } 10620 } 10621 if (s.params.paginationType === 'fraction') { 10622 s.paginationContainer.find('.' + s.params.paginationCurrentClass).text(current + 1); 10623 s.paginationContainer.find('.' + s.params.paginationTotalClass).text(total); 10624 } 10625 if (s.params.paginationType === 'progress') { 10626 var scale = (current + 1) / total, 10627 scaleX = scale, 10628 scaleY = 1; 10629 if (!s.isHorizontal()) { 10630 scaleY = scale; 10631 scaleX = 1; 10632 } 10633 s.paginationContainer.find('.' + s.params.paginationProgressbarClass).transform('translate3d(0,0,0) scaleX(' + scaleX + ') scaleY(' + scaleY + ')').transition(s.params.speed); 10634 } 10635 if (s.params.paginationType === 'custom' && s.params.paginationCustomRender) { 10636 s.paginationContainer.html(s.params.paginationCustomRender(s, current + 1, total)); 10637 s.emit('onPaginationRendered', s, s.paginationContainer[0]); 10638 } 10639 } 10640 10641 // Next/active buttons 10642 if (!s.params.loop) { 10643 if (s.params.prevButton && s.prevButton && s.prevButton.length > 0) { 10644 if (s.isBeginning) { 10645 s.prevButton.addClass(s.params.buttonDisabledClass); 10646 if (s.params.a11y && s.a11y) s.a11y.disable(s.prevButton); 10647 } 10648 else { 10649 s.prevButton.removeClass(s.params.buttonDisabledClass); 10650 if (s.params.a11y && s.a11y) s.a11y.enable(s.prevButton); 10651 } 10652 } 10653 if (s.params.nextButton && s.nextButton && s.nextButton.length > 0) { 10654 if (s.isEnd) { 10655 s.nextButton.addClass(s.params.buttonDisabledClass); 10656 if (s.params.a11y && s.a11y) s.a11y.disable(s.nextButton); 10657 } 10658 else { 10659 s.nextButton.removeClass(s.params.buttonDisabledClass); 10660 if (s.params.a11y && s.a11y) s.a11y.enable(s.nextButton); 10661 } 10662 } 10663 } 10664 }; 10665 10666 /*========================= 10667 Pagination 10668 ===========================*/ 10669 s.updatePagination = function () { 10670 if (!s.params.pagination) return; 10671 if (s.paginationContainer && s.paginationContainer.length > 0) { 10672 var paginationHTML = ''; 10673 if (s.params.paginationType === 'bullets') { 10674 var numberOfBullets = s.params.loop ? Math.ceil((s.slides.length - s.loopedSlides * 2) / s.params.slidesPerGroup) : s.snapGrid.length; 10675 for (var i = 0; i < numberOfBullets; i++) { 10676 if (s.params.paginationBulletRender) { 10677 paginationHTML += s.params.paginationBulletRender(s, i, s.params.bulletClass); 10678 } 10679 else { 10680 paginationHTML += '<' + s.params.paginationElement+' class="' + s.params.bulletClass + '"></' + s.params.paginationElement + '>'; 10681 } 10682 } 10683 s.paginationContainer.html(paginationHTML); 10684 s.bullets = s.paginationContainer.find('.' + s.params.bulletClass); 10685 if (s.params.paginationClickable && s.params.a11y && s.a11y) { 10686 s.a11y.initPagination(); 10687 } 10688 } 10689 if (s.params.paginationType === 'fraction') { 10690 if (s.params.paginationFractionRender) { 10691 paginationHTML = s.params.paginationFractionRender(s, s.params.paginationCurrentClass, s.params.paginationTotalClass); 10692 } 10693 else { 10694 paginationHTML = 10695 '<span class="' + s.params.paginationCurrentClass + '"></span>' + 10696 ' / ' + 10697 '<span class="' + s.params.paginationTotalClass+'"></span>'; 10698 } 10699 s.paginationContainer.html(paginationHTML); 10700 } 10701 if (s.params.paginationType === 'progress') { 10702 if (s.params.paginationProgressRender) { 10703 paginationHTML = s.params.paginationProgressRender(s, s.params.paginationProgressbarClass); 10704 } 10705 else { 10706 paginationHTML = '<span class="' + s.params.paginationProgressbarClass + '"></span>'; 10707 } 10708 s.paginationContainer.html(paginationHTML); 10709 } 10710 if (s.params.paginationType !== 'custom') { 10711 s.emit('onPaginationRendered', s, s.paginationContainer[0]); 10712 } 10713 } 10714 }; 10715 /*========================= 10716 Common update method 10717 ===========================*/ 10718 s.update = function (updateTranslate) { 10719 if (!s) return; 10720 s.updateContainerSize(); 10721 s.updateSlidesSize(); 10722 s.updateProgress(); 10723 s.updatePagination(); 10724 s.updateClasses(); 10725 if (s.params.scrollbar && s.scrollbar) { 10726 s.scrollbar.set(); 10727 } 10728 var newTranslate; 10729 function forceSetTranslate() { 10730 var translate = s.rtl ? -s.translate : s.translate; 10731 newTranslate = Math.min(Math.max(s.translate, s.maxTranslate()), s.minTranslate()); 10732 s.setWrapperTranslate(newTranslate); 10733 s.updateActiveIndex(); 10734 s.updateClasses(); 10735 } 10736 if (updateTranslate) { 10737 var translated; 10738 if (s.controller && s.controller.spline) { 10739 s.controller.spline = undefined; 10740 } 10741 if (s.params.freeMode) { 10742 forceSetTranslate(); 10743 if (s.params.autoHeight) { 10744 s.updateAutoHeight(); 10745 } 10746 } 10747 else { 10748 if ((s.params.slidesPerView === 'auto' || s.params.slidesPerView > 1) && s.isEnd && !s.params.centeredSlides) { 10749 translated = s.slideTo(s.slides.length - 1, 0, false, true); 10750 } 10751 else { 10752 translated = s.slideTo(s.activeIndex, 0, false, true); 10753 } 10754 if (!translated) { 10755 forceSetTranslate(); 10756 } 10757 } 10758 } 10759 else if (s.params.autoHeight) { 10760 s.updateAutoHeight(); 10761 } 10762 }; 10763 10764 /*========================= 10765 Resize Handler 10766 ===========================*/ 10767 s.onResize = function (forceUpdatePagination) { 10768 if (s.params.onBeforeResize) s.params.onBeforeResize(s); 10769 //Breakpoints 10770 if (s.params.breakpoints) { 10771 s.setBreakpoint(); 10772 } 10773 10774 // Disable locks on resize 10775 var allowSwipeToPrev = s.params.allowSwipeToPrev; 10776 var allowSwipeToNext = s.params.allowSwipeToNext; 10777 s.params.allowSwipeToPrev = s.params.allowSwipeToNext = true; 10778 10779 s.updateContainerSize(); 10780 s.updateSlidesSize(); 10781 if (s.params.slidesPerView === 'auto' || s.params.freeMode || force
10781UpdatePagination) s.updatePagination(); 10782 if (s.params.scrollbar && s.scrollbar) { 10783 s.scrollbar.set(); 10784 } 10785 if (s.controller && s.controller.spline) { 10786 s.controller.spline = undefined; 10787 } 10788 var slideChangedBySlideTo = false; 10789 if (s.params.freeMode) { 10790 var newTranslate = Math.min(Math.max(s.translate, s.maxTranslate()), s.minTranslate()); 10791 s.setWrapperTranslate(newTranslate); 10792 s.updateActiveIndex(); 10793 s.updateClasses(); 10794 10795 if (s.params.autoHeight) { 10796 s.updateAutoHeight(); 10797 } 10798 } 10799 else { 10800 s.updateClasses(); 10801 if ((s.params.slidesPerView === 'auto' || s.params.slidesPerView > 1) && s.isEnd && !s.params.centeredSlides) { 10802 slideChangedBySlideTo = s.slideTo(s.slides.length - 1, 0, false, true); 10803 } 10804 else { 10805 slideChangedBySlideTo = s.slideTo(s.activeIndex, 0, false, true); 10806 } 10807 } 10808 if (s.params.lazyLoading && !slideChangedBySlideTo && s.lazy) { 10809 s.lazy.load(); 10810 } 10811 // Return locks after resize 10812 s.params.allowSwipeToPrev = allowSwipeToPrev; 10813 s.params.allowSwipeToNext = allowSwipeToNext; 10814 if (s.params.onAfterResize) s.params.onAfterResize(s); 10815 }; 10816 10817 /*========================= 10818 Events 10819 ===========================*/ 10820 10821 //Define Touch Events 10822 s.touchEventsDesktop = {start: 'mousedown', move: 'mousemove', end: 'mouseup'}; 10823 if (window.navigator.pointerEnabled) s.touchEventsDesktop = {start: 'pointerdown', move: 'pointermove', end: 'pointerup'}; 10824 else if (window.navigator.msPointerEnabled) s.touchEventsDesktop = {start: 'MSPointerDown', move: 'MSPointerMove', end: 'MSPointerUp'}; 10825 s.touchEvents = { 10826 start : s.support.touch || !s.params.simulateTouch ? 'touchstart' : s.touchEventsDesktop.start, 10827 move : s.support.touch || !s.params.simulateTouch ? 'touchmove' : s.touchEventsDesktop.move, 10828 end : s.support.touch || !s.params.simulateTouch ? 'touchend' : s.touchEventsDesktop.end 10829 }; 10830 10831 10832 // WP8 Touch Events Fix 10833 if (window.navigator.pointerEnabled || window.navigator.msPointerEnabled) { 10834 (s.params.touchEventsTarget === 'container' ? s.container : s.wrapper).addClass('swiper-wp8-' + s.params.direction); 10835 } 10836 10837 // Attach/detach events 10838 s.initEvents = function (detach) { 10839 var actionDom = detach ? 'off' : 'on'; 10840 var action = detach ? 'removeEventListener' : 'addEventListener'; 10841 var touchEventsTarget = s.params.touchEventsTarget === 'container' ? s.container[0] : s.wrapper[0]; 10842 var target = s.support.touch ? touchEventsTarget : document; 10843 10844 var moveCapture = s.params.nested ? true : false; 10845 10846 //Touch Events 10847 if (s.browser.ie) { 10848 touchEventsTarget[action](s.touchEvents.start, s.onTouchStart, false); 10849 target[action](s.touchEvents.move, s.onTouchMove, moveCapture); 10850 target[action](s.touchEvents.end, s.onTouchEnd, false); 10851 } 10852 else { 10853 if (s.support.touch) { 10854 var passiveListener = s.touchEvents.start === 'touchstart' && s.support.passiveListener && s.params.passiveListeners ? {passive: true, capture: false} : false; 10855 touchEventsTarget[action](s.touchEvents.start, s.onTouchStart, passiveListener); 10856 touchEventsTarget[action](s.touchEvents.move, s.onTouchMove, moveCapture); 10857 touchEventsTarget[action](s.touchEvents.end, s.onTouchEnd, passiveListener); 10858 } 10859 if ((params.simulateTouch && !s.device.ios && !s.device.android) || (params.simulateTouch && !s.support.touch && s.device.ios)) { 10860 touchEventsTarget[action]('mousedown', s.onTouchStart, false); 10861 document[action]('mousemove', s.onTouchMove, moveCapture); 10862 document[action]('mouseup', s.onTouchEnd, false); 10863 } 10864 } 10865 window[action]('resize', s.onResize); 10866 10867 // Next, Prev, Index 10868 if (s.params.nextButton && s.nextButton && s.nextButton.length > 0) { 10869 s.nextButton[actionDom]('click', s.onClickNext); 10870 if (s.params.a11y && s.a11y) s.nextButton[actionDom]('keydown', s.a11y.onEnterKey); 10871 } 10872 if (s.params.prevButton && s.prevButton && s.prevButton.length > 0) { 10873 s.prevButton[actionDom]('click', s.onClickPrev); 10874 if (s.params.a11y && s.a11y) s.prevButton[actionDom]('keydown', s.a11y.onEnterKey); 10875 } 10876 if (s.params.pagination && s.params.paginationClickable) { 10877 s.paginationContainer[actionDom]('click', '.' + s.params.bulletClass, s.onClickIndex); 10878 if (s.params.a11y && s.a11y) s.paginationContainer[actionDom]('keydown', '.' + s.params.bulletClass, s.a11y.onEnterKey); 10879 } 10880 10881 // Prevent Links Clicks 10882 if (s.params.preventClicks || s.params.preventClicksPropagation) touchEventsTarget[action]('click', s.preventClicks, true); 10883 }; 10884 s.attachEvents = function () { 10885 s.initEvents(); 10886 }; 10887 s.detachEvents = function () { 10888 s.initEvents(true); 10889 }; 10890 10891 /*========================= 10892 Handle Clicks 10893 ===========================*/ 10894 // Prevent Clicks 10895 s.allowClick = true; 10896 s.preventClicks = function (e) { 10897 if (!s.allowClick) { 10898 if (s.params.preventClicks) e.preventDefault(); 10899 if (s.params.preventClicksPropagation && s.animating) { 10900 e.stopPropagation(); 10901 e.stopImmediatePropagation(); 10902 } 10903 } 10904 }; 10905 // Clicks 10906 s.onClickNext = function (e) { 10907 e.preventDefault(); 10908 if (s.isEnd && !s.params.loop) return; 10909 s.slideNext(); 10910 }; 10911 s.onClickPrev = function (e) { 10912 e.preventDefault(); 10913 if (s.isBeginning && !s.params.loop) return; 10914 s.slidePrev(); 10915 }; 10916 s.onClickIndex = function (e) { 10917 e.preventDefault(); 10918 var index = $(this).index() * s.params.slidesPerGroup; 10919 if (s.params.loop) index = index + s.loopedSlides; 10920 s.slideTo(index); 10921 }; 10922 10923 /*========================= 10924 Handle Touches 10925 ===========================*/ 10926 function findElementInEvent(e, selector) { 10927 var el = $(e.target); 10928 if (!el.is(selector)) { 10929 if (typeof selector === 'string') { 10930 el = el.parents(selector); 10931 } 10932 else if (selector.nodeType) { 10933 var found; 10934 el.parents().each(function (index, _el) { 10935 if (_el === selector) found = selector; 10936 }); 10937 if (!found) return undefined; 10938 else return selector; 10939 } 10940 } 10941 if (el.length === 0) { 10942 return undefined; 10943 } 10944 return el[0]; 10945 } 10946 s.updateClickedSlide = function (e) { 10947 var slide = findElementInEvent(e, '.' + s.params.slideClass); 10948 var slideFound = false;
10949 if (slide) { 10950 for (var i = 0; i < s.slides.length; i++) { 10951 if (s.slides[i] === slide) slideFound = true; 10952 } 10953 } 10954 10955 if (slide && slideFound) { 10956 s.clickedSlide = slide; 10957 s.clickedIndex = $(slide).index(); 10958 } 10959 else { 10960 s.clickedSlide = undefined; 10961 s.clickedIndex = undefined; 10962 return; 10963 } 10964 if (s.params.slideToClickedSlide && s.clickedIndex !== undefined && s.clickedIndex !== s.activeIndex) { 10965 var slideToIndex = s.clickedIndex, 10966 realIndex, 10967 duplicatedSlides, 10968 slidesPerView = s.params.slidesPerView === 'auto' ? s.currentSlidesPerView() : s.params.slidesPerView; 10969 if (s.params.loop) { 10970 if (s.animating) return; 10971 realIndex = parseInt($(s.clickedSlide).attr('data-swiper-slide-index'), 10); 10972 if (s.params.centeredSlides) { 10973 if ((slideToIndex < s.loopedSlides - slidesPerView/2) || (slideToIndex > s.slides.length - s.loopedSlides + slidesPerView/2)) { 10974 s.fixLoop(); 10975 slideToIndex = s.wrapper.children('.' + s.params.slideClass + '[data-swiper-slide-index="' + realIndex + '"]:not(.' + s.params.slideDuplicateClass + ')').eq(0).index(); 10976 setTimeout(function () { 10977 s.slideTo(slideToIndex); 10978 }, 0); 10979 } 10980 else { 10981 s.slideTo(slideToIndex); 10982 } 10983 } 10984 else { 10985 if (slideToIndex > s.slides.length - slidesPerView) { 10986 s.fixLoop(); 10987 slideToIndex = s.wrapper.children('.' + s.params.slideClass + '[data-swiper-slide-index="' + realIndex + '"]:not(.' + s.params.slideDuplicateClass + ')').eq(0).index(); 10988 setTimeout(function () { 10989 s.slideTo(slideToIndex); 10990 }, 0); 10991 } 10992 else { 10993 s.slideTo(slideToIndex); 10994 } 10995 } 10996 } 10997 else { 10998 s.slideTo(slideToIndex); 10999 } 11000 } 11001 }; 11002 11003 var isTouched, 11004 isMoved, 11005 allowTouchCallbacks, 11006 touchStartTime, 11007 isScrolling, 11008 currentTranslate, 11009 startTranslate, 11010 allowThresholdMove, 11011 // Form elements to match 11012 formElements = 'input, select, textarea, button, video', 11013 // Last click time 11014 lastClickTime = Date.now(), clickTimeout, 11015 //Velocities 11016 velocities = [], 11017 allowMomentumBounce; 11018 11019 // Animating Flag 11020 s.animating = false; 11021 11022 // Touches information 11023 s.touches = { 11024 startX: 0, 11025 startY: 0, 11026 currentX: 0, 11027 currentY: 0, 11028 diff: 0 11029 }; 11030 11031 // Touch handlers 11032 var isTouchEvent, startMoving; 11033 s.onTouchStart = function (e) { 11034 if (e.originalEvent) e = e.originalEvent; 11035 isTouchEvent = e.type === 'touchstart'; 11036 if (!isTouchEvent && 'which' in e && e.which === 3) return; 11037 if (s.params.noSwiping && findElementInEvent(e, '.' + s.params.noSwipingClass)) { 11038 s.allowClick = true; 11039 return; 11040 } 11041 if (s.params.swipeHandler) { 11042 if (!findElementInEvent(e, s.params.swipeHandler)) return; 11043 } 11044 11045 var startX = s.touches.currentX = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.pageX; 11046 var startY = s.touches.currentY = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.pageY; 11047 11048 // Do NOT start if iOS edge swipe is detected. Otherwise iOS app (UIWebView) cannot swipe-to-go-back anymore 11049 if(s.device.ios && s.params.iOSEdgeSwipeDetection && startX <= s.params.iOSEdgeSwipeThreshold) { 11050 return; 11051 } 11052 11053 isTouched = true; 11054 isMoved = false;
11055 allowTouchCallbacks = true; 11056 isScrolling = undefined; 11057 startMoving = undefined; 11058 s.touches.startX = startX; 11059 s.touches.startY = startY; 11060 touchStartTime = Date.now(); 11061 s.allowClick = true; 11062 s.updateContainerSize(); 11063 s.swipeDirection = undefined; 11064 if (s.params.threshold > 0) allowThresholdMove = false; 11065 if (e.type !== 'touchstart') { 11066 var preventDefault = true; 11067 if ($(e.target).is(formElements)) preventDefault = false; 11068 if (document.activeElement && $(document.activeElement).is(formElements)) { 11069 document.activeElement.blur(); 11070 } 11071 if (preventDefault) { 11072 e.preventDefault(); 11073 } 11074 } 11075 s.emit('onTouchStart', s, e); 11076 }; 11077 11078 s.onTouchMove = function (e) { 11079 if (e.originalEvent) e = e.originalEvent; 11080 if (isTouchEvent && e.type === 'mousemove') return; 11081 if (e.preventedByNestedSwiper) { 11082 s.touches.startX = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.pageX; 11083 s.touches.startY = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY; 11084 return; 11085 } 11086 if (s.params.onlyExternal) { 11087 // isMoved = true; 11088 s.allowClick = false; 11089 if (isTouched) { 11090 s.touches.startX = s.touches.currentX = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.pageX; 11091 s.touches.startY = s.touches.currentY = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY; 11092 touchStartTime = Date.now(); 11093 } 11094 return; 11095 } 11096 if (isTouchEvent && s.params.touchReleaseOnEdges && !s.params.loop) { 11097 if (!s.isHorizontal()) { 11098 // Vertical 11099 if ( 11100 (s.touches.currentY < s.touches.startY && s.translate <= s.maxTranslate()) || 11101 (s.touches.currentY > s.touches.startY && s.translate >= s.minTranslate()) 11102 ) { 11103 return; 11104 } 11105 } 11106 else { 11107 if ( 11108 (s.touches.currentX < s.touches.startX && s.translate <= s.maxTranslate()) || 11109 (s.touches.currentX > s.touches.startX && s.translate >= s.minTranslate()) 11110 ) { 11111 return; 11112 } 11113 } 11114 } 11115 if (isTouchEvent && document.activeElement) { 11116 if (e.target === document.activeElement && $(e.target).is(formElements)) { 11117 isMoved = true; 11118 s.allowClick = false; 11119 return; 11120 } 11121 } 11122 if (allowTouchCallbacks) { 11123 s.emit('onTouchMove', s, e); 11124 } 11125 if (e.targetTouches && e.targetTouches.length > 1) return; 11126 11127 s.touches.currentX = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.pageX; 11128 s.touches.currentY = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY; 11129 11130 if (typeof isScrolling === 'undefined') { 11131 var touchAngle; 11132 if (s.isHorizontal() && s.touches.currentY === s.touches.startY || !s.isHorizontal() && s.touches.currentX === s.touches.startX) { 11133 isScrolling = false; 11134 } 11135 else { 11136 touchAngle = Math.atan2(Math.abs(s.touches.currentY - s.touches.startY), Math.abs(s.touches.currentX - s.touches.startX)) * 180 / Math.PI; 11137 isScrolling = s.isHorizontal() ? touchAngle > s.params.touchAngle : (90 - touchAngle > s.params.touchAngle); 11138 } 11139 } 11140 if (isScrolling) { 11141 s.emit('onTouchMoveOpposite', s, e); 11142 } 11143 if (typeof startMoving === 'undefined') { 11144 if (s.touches.currentX !== s.touches.startX || s.touches.currentY !== s.touches.startY) { 11145 startMoving = true; 11146 } 11147 } 11148 if (!isTouched) return; 11149 if (isScrolling) { 11150 isTouched = false;
11151 return; 11152 } 11153 if (!startMoving) { 11154 return; 11155 } 11156 s.allowClick = false; 11157 s.emit('onSliderMove', s, e); 11158 e.preventDefault(); 11159 if (s.params.touchMoveStopPropagation && !s.params.nested) { 11160 e.stopPropagation(); 11161 } 11162 11163 if (!isMoved) { 11164 if (params.loop) { 11165 s.fixLoop(); 11166 } 11167 startTranslate = s.getWrapperTranslate(); 11168 s.setWrapperTransition(0); 11169 if (s.animating) { 11170 s.wrapper.trigger('webkitTransitionEnd transitionend oTransitionEnd MSTransitionEnd msTransitionEnd'); 11171 } 11172 if (s.params.autoplay && s.autoplaying) { 11173 if (s.params.autoplayDisableOnInteraction) { 11174 s.stopAutoplay(); 11175 } 11176 else { 11177 s.pauseAutoplay(); 11178 } 11179 } 11180 allowMomentumBounce = false; 11181 //Grab Cursor 11182 if (s.params.grabCursor && (s.params.allowSwipeToNext === true || s.params.allowSwipeToPrev === true)) { 11183 s.setGrabCursor(true); 11184 } 11185 } 11186 isMoved = true; 11187 11188 var diff = s.touches.diff = s.isHorizontal() ? s.touches.currentX - s.touches.startX : s.touches.currentY - s.touches.startY; 11189 11190 diff = diff * s.params.touchRatio; 11191 if (s.rtl) diff = -diff; 11192 11193 s.swipeDirection = diff > 0 ? 'prev' : 'next'; 11194 currentTranslate = diff + startTranslate; 11195 11196 var disableParentSwiper = true; 11197 if ((diff > 0 && currentTranslate > s.minTranslate())) { 11198 disableParentSwiper = false;
11199 if (s.params.resistance) currentTranslate = s.minTranslate() - 1 + Math.pow(-s.minTranslate() + startTranslate + diff, s.params.resistanceRatio); 11200 } 11201 else if (diff < 0 && currentTranslate < s.maxTranslate()) { 11202 disableParentSwiper = false; 11203 if (s.params.resistance) currentTranslate = s.maxTranslate() + 1 - Math.pow(s.maxTranslate() - startTranslate - diff, s.params.resistanceRatio); 11204 } 11205 11206 if (disableParentSwiper) { 11207 e.preventedByNestedSwiper = true; 11208 } 11209 11210 // Directions locks 11211 if (!s.params.allowSwipeToNext && s.swipeDirection === 'next' && currentTranslate < startTranslate) { 11212 currentTranslate = startTranslate; 11213 } 11214 if (!s.params.allowSwipeToPrev && s.swipeDirection === 'prev' && currentTranslate > startTranslate) { 11215 currentTranslate = startTranslate; 11216 } 11217 11218 11219 // Threshold 11220 if (s.params.threshold > 0) { 11221 if (Math.abs(diff) > s.params.threshold || allowThresholdMove) { 11222 if (!allowThresholdMove) { 11223 allowThresholdMove = true; 11224 s.touches.startX = s.touches.currentX; 11225 s.touches.startY = s.touches.currentY; 11226 currentTranslate = startTranslate; 11227 s.touches.diff = s.isHorizontal() ? s.touches.currentX - s.touches.startX : s.touches.currentY - s.touches.startY; 11228 return; 11229 } 11230 } 11231 else { 11232 currentTranslate = startTranslate; 11233 return; 11234 } 11235 } 11236 11237 if (!s.params.followFinger) return; 11238 11239 // Update active index in free mode 11240 if (s.params.freeMode || s.params.watchSlidesProgress) { 11241 s.updateActiveIndex(); 11242 } 11243 if (s.params.freeMode) { 11244 //Velocity 11245 if (velocities.length === 0) { 11246 velocities.push({ 11247 position: s.touches[s.isHorizontal() ? 'startX' : 'startY'], 11248 time: touchStartTime 11249 }); 11250 } 11251 velocities.push({ 11252 position: s.touches[s.isHorizontal() ? 'currentX' : 'currentY'], 11253 time: (new window.Date()).getTime() 11254 }); 11255 } 11256 // Update progress 11257 s.updateProgress(currentTranslate); 11258 // Update translate 11259 s.setWrapperTranslate(currentTranslate); 11260 }; 11261 s.onTouchEnd = function (e) { 11262 if (e.originalEvent) e = e.originalEvent; 11263 if (allowTouchCallbacks) { 11264 s.emit('onTouchEnd', s, e); 11265 } 11266 allowTouchCallbacks = false; 11267 if (!isTouched) return; 11268 //Return Grab Cursor 11269 if (s.params.grabCursor && isMoved && isTouched && (s.params.allowSwipeToNext === true || s.params.allowSwipeToPrev === true)) { 11270 s.setGrabCursor(false); 11271 } 11272 11273 // Time diff 11274 var touchEndTime = Date.now(); 11275 var timeDiff = touchEndTime - touchStartTime; 11276 11277 // Tap, doubleTap, Click 11278 if (s.allowClick) { 11279 s.updateClickedSlide(e); 11280 s.emit('onTap', s, e); 11281 if (timeDiff < 300 && (touchEndTime - lastClickTime) > 300) { 11282 if (clickTimeout) clearTimeout(clickTimeout); 11283 clickTimeout = setTimeout(function () { 11284 if (!s) return; 11285 if (s.params.paginationHide && s.paginationContainer.length > 0 && !$(e.target).hasClass(s.params.bulletClass)) { 11286 s.paginationContainer.toggleClass(s.params.paginationHiddenClass); 11287 } 11288 s.emit('onClick', s, e); 11289 }, 300); 11290 11291 } 11292 if (timeDiff < 300 && (touchEndTime - lastClickTime) < 300) { 11293 if (clickTimeout) clearTimeout(clickTimeout); 11294 s.emit('onDoubleTap', s, e); 11295 } 11296 } 11297 11298 lastClickTime = Date.now(); 11299 setTimeout(function () { 11300 if (s) s.allowClick = true; 11301 }, 0); 11302 11303 if (!isTouched || !isMoved || !s.swipeDirection || s.touches.diff === 0 || currentTranslate === startTranslate) { 11304 isTouched = isMoved = false;
11305 return; 11306 } 11307 isTouched = isMoved = false; 11308 11309 var currentPos; 11310 if (s.params.followFinger) { 11311 currentPos = s.rtl ? s.translate : -s.translate; 11312 } 11313 else { 11314 currentPos = -currentTranslate; 11315 } 11316 if (s.params.freeMode) { 11317 if (currentPos < -s.minTranslate()) { 11318 s.slideTo(s.activeIndex); 11319 return; 11320 } 11321 else if (currentPos > -s.maxTranslate()) { 11322 if (s.slides.length < s.snapGrid.length) { 11323 s.slideTo(s.snapGrid.length - 1); 11324 } 11325 else { 11326 s.slideTo(s.slides.length - 1); 11327 } 11328 return; 11329 } 11330 11331 if (s.params.freeModeMomentum) { 11332 if (velocities.length > 1) { 11333 var lastMoveEvent = velocities.pop(), velocityEvent = velocities.pop(); 11334 11335 var distance = lastMoveEvent.position - velocityEvent.position; 11336 var time = lastMoveEvent.time - velocityEvent.time; 11337 s.velocity = distance / time; 11338 s.velocity = s.velocity / 2; 11339 if (Math.abs(s.velocity) < s.params.freeModeMinimumVelocity) { 11340 s.velocity = 0; 11341 } 11342 // this implies that the user stopped moving a finger then released. 11343 // There would be no events with distance zero, so the last event is stale. 11344 if (time > 150 || (new window.Date().getTime() - lastMoveEvent.time) > 300) { 11345 s.velocity = 0; 11346 } 11347 } else { 11348 s.velocity = 0; 11349 } 11350 s.velocity = s.velocity * s.params.freeModeMomentumVelocityRatio; 11351 11352 velocities.length = 0; 11353 var momentumDuration = 1000 * s.params.freeModeMomentumRatio; 11354 var momentumDistance = s.velocity * momentumDuration; 11355 11356 var newPosition = s.translate + momentumDistance; 11357 if (s.rtl) newPosition = - newPosition; 11358 var doBounce = false; 11359 var afterBouncePosition; 11360 var bounceAmount = Math.abs(s.velocity) * 20 * s.params.freeModeMomentumBounceRatio; 11361 if (newPosition < s.maxTranslate()) { 11362 if (s.params.freeModeMomentumBounce) { 11363 if (newPosition + s.maxTranslate() < -bounceAmount) { 11364 newPosition = s.maxTranslate() - bounceAmount; 11365 } 11366 afterBouncePosition = s.maxTranslate(); 11367 doBounce = true; 11368 allowMomentumBounce = true; 11369 } 11370 else { 11371 newPosition = s.maxTranslate(); 11372 } 11373 } 11374 else if (newPosition > s.minTranslate()) { 11375 if (s.params.freeModeMomentumBounce) { 11376 if (newPosition - s.minTranslate() > bounceAmount) { 11377 newPosition = s.minTranslate() + bounceAmount; 11378 } 11379 afterBouncePosition = s.minTranslate(); 11380 doBounce = true; 11381 allowMomentumBounce = true; 11382 } 11383 else { 11384 newPosition = s.minTranslate(); 11385 } 11386 } 11387 else if (s.params.freeModeSticky) { 11388 var j = 0, 11389 nextSlide; 11390 for (j = 0; j < s.snapGrid.length; j += 1) { 11391 if (s.snapGrid[j] > -newPosition) { 11392 nextSlide = j; 11393 break; 11394 } 11395 11396 } 11397 if (Math.abs(s.snapGrid[nextSlide] - newPosition) < Math.abs(s.snapGrid[nextSlide - 1] - newPosition) || s.swipeDirection === 'next') { 11398 newPosition = s.snapGrid[nextSlide]; 11399 } else { 11400 newPosition = s.snapGrid[nextSlide - 1]; 11401 } 11402 if (!s.rtl) newPosition = - newPosition; 11403 } 11404 //Fix duration 11405 if (s.velocity !== 0) { 11406 if (s.rtl) { 11407 momentumDuration = Math.abs((-newPosition - s.translate) / s.velocity); 11408 } 11409 else { 11410 momentumDuration = Math.abs((newPosition - s.translate) / s.velocity); 11411 } 11412 } 11413 else if (s.params.freeModeSticky) { 11414 s.slideReset(); 11415 return; 11416 } 11417 11418 if (s.params.freeModeMomentumBounce && doBounce) { 11419 s.updateProgress(afterBouncePosition); 11420 s.setWrapperTransition(momentumDuration); 11421 s.setWrapperTranslate(newPosition); 11422 s.onTransitionStart(); 11423 s.animating = true; 11424 s.wrapper.transitionEnd(function () { 11425 if (!s || !allowMomentumBounce) return; 11426 s.emit('onMomentumBounce', s); 11427 11428 s.setWrapperTransition(s.params.speed); 11429 s.setWrapperTranslate(afterBouncePosition); 11430 s.wrapper.transitionEnd(function () { 11431 if (!s) return; 11432 s.onTransitionEnd(); 11433 }); 11434 }); 11435 } else if (s.velocity) { 11436 s.updateProgress(newPosition); 11437 s.setWrapperTransition(momentumDuration); 11438 s.setWrapperTranslate(newPosition); 11439 s.onTransitionStart(); 11440 if (!s.animating) { 11441 s.animating = true; 11442 s.wrapper.transitionEnd(function () { 11443 if (!s) return; 11444 s.onTransitionEnd(); 11445 }); 11446 } 11447 11448 } else { 11449 s.updateProgress(newPosition); 11450 } 11451 11452 s.updateActiveIndex(); 11453 } 11454 if (!s.params.freeModeMomentum || timeDiff >= s.params.longSwipesMs) { 11455 s.updateProgress(); 11456 s.updateActiveIndex(); 11457 } 11458 return; 11459 } 11460 11461 // Find current slide 11462 var i, stopIndex = 0, groupSize = s.slidesSizesGrid[0]; 11463 for (i = 0; i < s.slidesGrid.length; i += s.params.slidesPerGroup) { 11464 if (typeof s.slidesGrid[i + s.params.slidesPerGroup] !== 'undefined') { 11465 if (currentPos >= s.slidesGrid[i] && currentPos < s.slidesGrid[i + s.params.slidesPerGroup]) { 11466 stopIndex = i; 11467 groupSize = s.slidesGrid[i + s.params.slidesPerGroup] - s.slidesGrid[i]; 11468 } 11469 } 11470 else { 11471 if (currentPos >= s.slidesGrid[i]) { 11472 stopIndex = i; 11473 groupSize = s.slidesGrid[s.slidesGrid.length - 1] - s.slidesGrid[s.slidesGrid.length - 2]; 11474 } 11475 } 11476 } 11477 11478 // Find current slide size 11479 var ratio = (currentPos - s.slidesGrid[stopIndex]) / groupSize; 11480 11481 if (timeDiff > s.params.longSwipesMs) { 11482 // Long touches 11483 if (!s.params.longSwipes) { 11484 s.slideTo(s.activeIndex); 11485 return; 11486 } 11487 if (s.swipeDirection === 'next') { 11488 if (ratio >= s.params.longSwipesRatio) s.slideTo(stopIndex + s.params.slidesPerGroup); 11489 else s.slideTo(stopIndex); 11490 11491 } 11492 if (s.swipeDirection === 'prev') { 11493 if (ratio > (1 - s.params.longSwipesRatio)) s.slideTo(stopIndex + s.params.slidesPerGroup); 11494 else s.slideTo(stopIndex); 11495 } 11496 } 11497 else { 11498 // Short swipes 11499 if (!s.params.shortSwipes) { 11500 s.slideTo(s.activeIndex); 11501 return; 11502 } 11503 if (s.swipeDirection === 'next') { 11504 s.slideTo(stopIndex + s.params.slidesPerGroup); 11505 11506 } 11507 if (s.swipeDirection === 'prev') { 11508 s.slideTo(stopIndex); 11509 } 11510 } 11511 }; 11512 /*========================= 11513 Transitions 11514 ===========================*/ 11515 s._slideTo = function (slideIndex, speed) { 11516 return s.slideTo(slideIndex, speed, true, true); 11517 }; 11518 s.slideTo = function (slideIndex, speed, runCallbacks, internal) { 11519 if (typeof runCallbacks === 'undefined') runCallbacks = true; 11520 if (typeof slideIndex === 'undefined') slideIndex = 0; 11521 if (slideIndex < 0) slideIndex = 0; 11522 s.snapIndex = Math.floor(slideIndex / s.params.slidesPerGroup); 11523 if (s.snapIndex >= s.snapGrid.length) s.snapIndex = s.snapGrid.length - 1; 11524 11525 var translate = - s.snapGrid[s.snapIndex]; 11526 // Stop autoplay 11527 if (s.params.autoplay && s.autoplaying) { 11528 if (internal || !s.params.autoplayDisableOnInteraction) { 11529 s.pauseAutoplay(speed); 11530 } 11531 else { 11532 s.stopAutoplay(); 11533 } 11534 } 11535 // Update progress 11536 s.updateProgress(translate); 11537 11538 // Normalize slideIndex 11539 if(s.params.normalizeSlideIndex){ 11540 for (var i = 0; i < s.slidesGrid.length; i++) { 11541 if (- Math.floor(translate * 100) >= Math.floor(s.slidesGrid[i] * 100)) { 11542 slideIndex = i; 11543 } 11544 } 11545 } 11546 11547 // Directions locks 11548 if (!s.params.allowSwipeToNext && translate < s.translate && translate < s.minTranslate()) { 11549 return false;
11550 } 11551 if (!s.params.allowSwipeToPrev && translate > s.translate && translate > s.maxTranslate()) { 11552 if ((s.activeIndex || 0) !== slideIndex ) return false; 11553 } 11554 11555 // Update Index 11556 if (typeof speed === 'undefined') speed = s.params.speed; 11557 s.previousIndex = s.activeIndex || 0; 11558 s.activeIndex = slideIndex; 11559 s.updateRealIndex(); 11560 if ((s.rtl && -translate === s.translate) || (!s.rtl && translate === s.translate)) { 11561 // Update Height 11562 if (s.params.autoHeight) { 11563 s.updateAutoHeight(); 11564 } 11565 s.updateClasses(); 11566 if (s.params.effect !== 'slide') { 11567 s.setWrapperTranslate(translate); 11568 } 11569 return false; 11570 } 11571 s.updateClasses(); 11572 s.onTransitionStart(runCallbacks); 11573 11574 if (speed === 0 || s.browser.lteIE9) { 11575 s.setWrapperTranslate(translate); 11576 s.setWrapperTransition(0); 11577 s.onTransitionEnd(runCallbacks); 11578 } 11579 else { 11580 s.setWrapperTranslate(translate); 11581 s.setWrapperTransition(speed); 11582 if (!s.animating) { 11583 s.animating = true; 11584 s.wrapper.transitionEnd(function () { 11585 if (!s) return; 11586 s.onTransitionEnd(runCallbacks); 11587 }); 11588 } 11589 11590 } 11591 11592 return true; 11593 }; 11594 11595 s.onTransitionStart = function (runCallbacks) { 11596 if (typeof runCallbacks === 'undefined') runCallbacks = true; 11597 if (s.params.autoHeight) { 11598 s.updateAutoHeight(); 11599 } 11600 if (s.lazy) s.lazy.onTransitionStart(); 11601 if (runCallbacks) { 11602 s.emit('onTransitionStart', s); 11603 if (s.activeIndex !== s.previousIndex) { 11604 s.emit('onSlideChangeStart', s); 11605 if (s.activeIndex > s.previousIndex) { 11606 s.emit('onSlideNextStart', s); 11607 } 11608 else { 11609 s.emit('onSlidePrevStart', s); 11610 } 11611 } 11612 11613 } 11614 }; 11615 s.onTransitionEnd = function (runCallbacks) { 11616 s.animating = false; 11617 s.setWrapperTransition(0); 11618 if (typeof runCallbacks === 'undefined') runCallbacks = true; 11619 if (s.lazy) s.lazy.onTransitionEnd(); 11620 if (runCallbacks) { 11621 s.emit('onTransitionEnd', s); 11622 if (s.activeIndex !== s.previousIndex) { 11623 s.emit('onSlideChangeEnd', s); 11624 if (s.activeIndex > s.previousIndex) { 11625 s.emit('onSlideNextEnd', s); 11626 } 11627 else { 11628 s.emit('onSlidePrevEnd', s); 11629 } 11630 } 11631 } 11632 if (s.params.history && s.history) { 11633 s.history.setHistory(s.params.history, s.activeIndex); 11634 } 11635 if (s.params.hashnav && s.hashnav) { 11636 s.hashnav.setHash(); 11637 } 11638 11639 }; 11640 s.slideNext = function (runCallbacks, speed, internal) { 11641 if (s.params.loop) { 11642 if (s.animating) return false; 11643 s.fixLoop(); 11644 var clientLeft = s.container[0].clientLeft; 11645 return s.slideTo(s.activeIndex + s.params.slidesPerGroup, speed, runCallbacks, internal); 11646 } 11647 else return s.slideTo(s.activeIndex + s.params.slidesPerGroup, speed, runCallbacks, internal); 11648 }; 11649 s._slideNext = function (speed) { 11650 return s.slideNext(true, speed, true); 11651 }; 11652 s.slidePrev = function (runCallbacks, speed, internal) { 11653 if (s.params.loop) { 11654 if (s.animating) return false; 11655 s.fixLoop(); 11656 var clientLeft = s.container[0].clientLeft; 11657 return s.slideTo(s.activeIndex - 1, speed, runCallbacks, internal); 11658 } 11659 else return s.slideTo(s.activeIndex - 1, speed, runCallbacks, internal); 11660 }; 11661 s._slidePrev = function (speed) { 11662 return s.slidePrev(true, speed, true); 11663 }; 11664 s.slideReset = function (runCallbacks, speed, internal) { 11665 return s.slideTo(s.activeIndex, speed, runCallbacks); 11666 }; 11667 11668 s.disableTouchControl = function () { 11669 s.params.onlyExternal = true; 11670 return true; 11671 }; 11672 s.enableTouchControl = function () { 11673 s.params.onlyExternal = false;
11674 return true; 11675 }; 11676 11677 /*========================= 11678 Translate/transition helpers 11679 ===========================*/ 11680 s.setWrapperTransition = function (duration, byController) { 11681 s.wrapper.transition(duration); 11682 if (s.params.effect !== 'slide' && s.effects[s.params.effect]) { 11683 s.effects[s.params.effect].setTransition(duration); 11684 } 11685 if (s.params.parallax && s.parallax) { 11686 s.parallax.setTransition(duration); 11687 } 11688 if (s.params.scrollbar && s.scrollbar) { 11689 s.scrollbar.setTransition(duration); 11690 } 11691 if (s.params.control && s.controller) { 11692 s.controller.setTransition(duration, byController); 11693 } 11694 s.emit('onSetTransition', s, duration); 11695 }; 11696 s.setWrapperTranslate = function (translate, updateActiveIndex, byController) { 11697 var x = 0, y = 0, z = 0; 11698 if (s.isHorizontal()) { 11699 x = s.rtl ? -translate : translate; 11700 } 11701 else { 11702 y = translate; 11703 } 11704 11705 if (s.params.roundLengths) { 11706 x = round(x); 11707 y = round(y); 11708 } 11709 11710 if (!s.params.virtualTranslate) { 11711 if (s.support.transforms3d) s.wrapper.transform('translate3d(' + x + 'px, ' + y + 'px, ' + z + 'px)'); 11712 else s.wrapper.transform('translate(' + x + 'px, ' + y + 'px)'); 11713 } 11714 11715 s.translate = s.isHorizontal() ? x : y; 11716 11717 // Check if we need to update progress 11718 var progress; 11719 var translatesDiff = s.maxTranslate() - s.minTranslate(); 11720 if (translatesDiff === 0) { 11721 progress = 0; 11722 } 11723 else { 11724 progress = (translate - s.minTranslate()) / (translatesDiff); 11725 } 11726 if (progress !== s.progress) { 11727 s.updateProgress(translate); 11728 } 11729 11730 if (updateActiveIndex) s.updateActiveIndex(); 11731 if (s.params.effect !== 'slide' && s.effects[s.params.effect]) { 11732 s.effects[s.params.effect].setTranslate(s.translate); 11733 } 11734 if (s.params.parallax && s.parallax) { 11735 s.parallax.setTranslate(s.translate); 11736 } 11737 if (s.params.scrollbar && s.scrollbar) { 11738 s.scrollbar.setTranslate(s.translate); 11739 } 11740 if (s.params.control && s.controller) { 11741 s.controller.setTranslate(s.translate, byController); 11742 } 11743 s.emit('onSetTranslate', s, s.translate); 11744 }; 11745 11746 s.getTranslate = function (el, axis) { 11747 var matrix, curTransform, curStyle, transformMatrix; 11748 11749 // automatic axis detection 11750 if (typeof axis === 'undefined') { 11751 axis = 'x'; 11752 } 11753 11754 if (s.params.virtualTranslate) { 11755 return s.rtl ? -s.translate : s.translate; 11756 } 11757 11758 curStyle = window.getComputedStyle(el, null); 11759 if (window.WebKitCSSMatrix) { 11760 curTransform = curStyle.transform || curStyle.webkitTransform; 11761 if (curTransform.split(',').length > 6) { 11762 curTransform = curTransform.split(', ').map(function(a){ 11763 return a.replace(',','.'); 11764 }).join(', '); 11765 } 11766 // Some old versions of Webkit choke when 'none' is passed; pass 11767 // empty string instead in this case 11768 transformMatrix = new window.WebKitCSSMatrix(curTransform === 'none' ? '' : curTransform); 11769 } 11770 else { 11771 transformMatrix = curStyle.MozTransform || curStyle.OTransform || curStyle.MsTransform || curStyle.msTransform || curStyle.transform || curStyle.getPropertyValue('transform').replace('translate(', 'matrix(1, 0, 0, 1,'); 11772 matrix = transformMatrix.toString().split(','); 11773 } 11774 11775 if (axis === 'x') { 11776 //Latest Chrome and webkits Fix 11777 if (window.WebKitCSSMatrix) 11778 curTransform = transformMatrix.m41; 11779 //Crazy IE10 Matrix 11780 else if (matrix.length === 16) 11781 curTransform = parseFloat(matrix[12]); 11782 //Normal Browsers 11783 else 11784 curTransform = parseFloat(matrix[4]); 11785 } 11786 if (axis === 'y') { 11787 //Latest Chrome and webkits Fix 11788 if (window.WebKitCSSMatrix) 11789 curTransform = transformMatrix.m42; 11790 //Crazy IE10 Matrix 11791 else if (matrix.length === 16) 11792 curTransform = parseFloat(matrix[13]); 11793 //Normal Browsers 11794 else 11795 curTransform = parseFloat(matrix[5]); 11796 } 11797 if (s.rtl && curTransform) curTransform = -curTransform; 11798 return curTransform || 0; 11799 }; 11800 s.getWrapperTranslate = function (axis) { 11801 if (typeof axis === 'undefined') { 11802 axis = s.isHorizontal() ? 'x' : 'y'; 11803 } 11804 return s.getTranslate(s.wrapper[0], axis); 11805 }; 11806 11807 /*========================= 11808 Observer 11809 ===========================*/ 11810 s.observers = []; 11811 function initObserver(target, options) { 11812 options = options || {}; 11813 // create an observer instance 11814 var ObserverFunc = window.MutationObserver || window.WebkitMutationObserver; 11815 var observer = new ObserverFunc(function (mutations) { 11816 mutations.forEach(function (mutation) { 11817 s.onResize(true); 11818 s.emit('onObserverUpdate', s, mutation); 11819 }); 11820 }); 11821 11822 observer.observe(target, { 11823 attributes: typeof options.attributes === 'undefined' ? true : options.attributes, 11824 childList: typeof options.childList === 'undefined' ? true : options.childList, 11825 characterData: typeof options.characterData === 'undefined' ? true : options.characterData 11826 }); 11827 11828 s.observers.push(observer); 11829 }
11830 s.initObservers = function () { 11831 if (s.params.observeParents) { 11832 var containerParents = s.container.parents(); 11833 for (var i = 0; i < containerParents.length; i++) { 11834 initObserver(containerParents[i]); 11835 } 11836 } 11837 11838 // Observe container 11839 initObserver(s.container[0], {childList: false}); 11840 11841 // Observe wrapper 11842 initObserver(s.wrapper[0], {attributes: false}); 11843 }; 11844 s.disconnectObservers = function () { 11845 for (var i = 0; i < s.observers.length; i++) { 11846 s.observers[i].disconnect(); 11847 } 11848 s.observers = []; 11849 }; 11850 /*========================= 11851 Loop 11852 ===========================*/ 11853 // Create looped slides 11854 s.createLoop = function () { 11855 // Remove duplicated slides 11856 s.wrapper.children('.' + s.params.slideClass + '.' + s.params.slideDuplicateClass).remove(); 11857 11858 var slides = s.wrapper.children('.' + s.params.slideClass); 11859 11860 if(s.params.slidesPerView === 'auto' && !s.params.loopedSlides) s.params.loopedSlides = slides.length; 11861 11862 s.loopedSlides = parseInt(s.params.loopedSlides || s.params.slidesPerView, 10); 11863 s.loopedSlides = s.loopedSlides + s.params.loopAdditionalSlides; 11864 if (s.loopedSlides > slides.length) { 11865 s.loopedSlides = slides.length; 11866 } 11867 11868 var prependSlides = [], appendSlides = [], i; 11869 slides.each(function (index, el) { 11870 var slide = $(this); 11871 if (index < s.loopedSlides) appendSlides.push(el); 11872 if (index < slides.length && index >= slides.length - s.loopedSlides) prependSlides.push(el); 11873 slide.attr('data-swiper-slide-index', index); 11874 }); 11875 for (i = 0; i < appendSlides.length; i++) { 11876 s.wrapper.append($(appendSlides[i].cloneNode(true)).addClass(s.params.slideDuplicateClass)); 11877 } 11878 for (i = prependSlides.length - 1; i >= 0; i--) { 11879 s.wrapper.prepend($(prependSlides[i].cloneNode(true)).addClass(s.params.slideDuplicateClass)); 11880 } 11881 }; 11882 s.destroyLoop = function () { 11883 s.wrapper.children('.' + s.params.slideClass + '.' + s.params.slideDuplicateClass).remove(); 11884 s.slides.removeAttr('data-swiper-slide-index'); 11885 }; 11886 s.reLoop = function (updatePosition) { 11887 var oldIndex = s.activeIndex - s.loopedSlides; 11888 s.destroyLoop(); 11889 s.createLoop(); 11890 s.updateSlidesSize(); 11891 if (updatePosition) { 11892 s.slideTo(oldIndex + s.loopedSlides, 0, false); 11893 } 11894 11895 }; 11896 s.fixLoop = function () { 11897 var newIndex; 11898 //Fix For Negative Oversliding 11899 if (s.activeIndex < s.loopedSlides) { 11900 newIndex = s.slides.length - s.loopedSlides * 3 + s.activeIndex; 11901 newIndex = newIndex + s.loopedSlides; 11902 s.slideTo(newIndex, 0, false, true); 11903 } 11904 //Fix For Positive Oversliding 11905 else if ((s.params.slidesPerView === 'auto' && s.activeIndex >= s.loopedSlides * 2) || (s.activeIndex > s.slides.length - s.params.slidesPerView * 2)) { 11906 newIndex = -s.slides.length + s.activeIndex + s.loopedSlides; 11907 newIndex = newIndex + s.loopedSlides; 11908 s.slideTo(newIndex, 0, false, true); 11909 } 11910 }; 11911 /*========================= 11912 Append/Prepend/Remove Slides 11913 ===========================*/ 11914 s.appendSlide = function (slides) { 11915 if (s.params.loop) { 11916 s.destroyLoop(); 11917 } 11918 if (typeof slides === 'object' && slides.length) { 11919 for (var i = 0; i < slides.length; i++) { 11920 if (slides[i]) s.wrapper.append(slides[i]); 11921 } 11922 } 11923 else { 11924 s.wrapper.append(slides); 11925 } 11926 if (s.params.loop) { 11927 s.createLoop(); 11928 } 11929 if (!(s.params.observer && s.support.observer)) { 11930 s.update(true); 11931 } 11932 }; 11933 s.prependSlide = function (slides) { 11934 if (s.params.loop) { 11935 s.destroyLoop(); 11936 } 11937 var newActiveIndex = s.activeIndex + 1; 11938 if (typeof slides === 'object' && slides.length) { 11939 for (var i = 0; i < slides.length; i++) {
11940 if (slides[i]) s.wrapper.prepend(slides[i]); 11941 } 11942 newActiveIndex = s.activeIndex + slides.length; 11943 } 11944 else { 11945 s.wrapper.prepend(slides); 11946 } 11947 if (s.params.loop) { 11948 s.createLoop(); 11949 } 11950 if (!(s.params.observer && s.support.observer)) { 11951 s.update(true); 11952 } 11953 s.slideTo(newActiveIndex, 0, false); 11954 }; 11955 s.removeSlide = function (slidesIndexes) { 11956 if (s.params.loop) { 11957 s.destroyLoop(); 11958 s.slides = s.wrapper.children('.' + s.params.slideClass); 11959 } 11960 var newActiveIndex = s.activeIndex, 11961 indexToRemove; 11962 if (typeof slidesIndexes === 'object' && slidesIndexes.length) { 11963 for (var i = 0; i < slidesIndexes.length; i++) { 11964 indexToRemove = slidesIndexes[i]; 11965 if (s.slides[indexToRemove]) s.slides.eq(indexToRemove).remove(); 11966 if (indexToRemove < newActiveIndex) newActiveIndex--; 11967 } 11968 newActiveIndex = Math.max(newActiveIndex, 0); 11969 } 11970 else { 11971 indexToRemove = slidesIndexes; 11972 if (s.slides[indexToRemove]) s.slides.eq(indexToRemove).remove(); 11973 if (indexToRemove < newActiveIndex) newActiveIndex--; 11974 newActiveIndex = Math.max(newActiveIndex, 0); 11975 } 11976 11977 if (s.params.loop) { 11978 s.createLoop(); 11979 } 11980 11981 if (!(s.params.observer && s.support.observer)) { 11982 s.update(true); 11983 } 11984 if (s.params.loop) { 11985 s.slideTo(newActiveIndex + s.loopedSlides, 0, false); 11986 } 11987 else { 11988 s.slideTo(newActiveIndex, 0, false); 11989 } 11990 11991 }; 11992 s.removeAllSlides = function () { 11993 var slidesIndexes = []; 11994 for (var i = 0; i < s.slides.length; i++) { 11995 slidesIndexes.push(i); 11996 } 11997 s.removeSlide(slidesIndexes); 11998 }; 11999 12000 12001 /*=========================
12002 Effects 12003 ===========================*/ 12004 s.effects = { 12005 fade: { 12006 setTranslate: function () { 12007 for (var i = 0; i < s.slides.length; i++) { 12008 var slide = s.slides.eq(i); 12009 var offset = slide[0].swiperSlideOffset; 12010 var tx = -offset; 12011 if (!s.params.virtualTranslate) tx = tx - s.translate; 12012 var ty = 0; 12013 if (!s.isHorizontal()) { 12014 ty = tx; 12015 tx = 0; 12016 } 12017 var slideOpacity = s.params.fade.crossFade ? 12018 Math.max(1 - Math.abs(slide[0].progress), 0) : 12019 1 + Math.min(Math.max(slide[0].progress, -1), 0); 12020 slide 12021 .css({ 12022 opacity: slideOpacity 12023 }) 12024 .transform('translate3d(' + tx + 'px, ' + ty + 'px, 0px)'); 12025 12026 } 12027 12028 }, 12029 setTransition: function (duration) { 12030 s.slides.transition(duration); 12031 if (s.params.virtualTranslate && duration !== 0) { 12032 var eventTriggered = false; 12033 s.slides.transitionEnd(function () { 12034 if (eventTriggered) return; 12035 if (!s) return; 12036 eventTriggered = true; 12037 s.animating = false; 12038 var triggerEvents = ['webkitTransitionEnd', 'transitionend', 'oTransitionEnd', 'MSTransitionEnd', 'msTransitionEnd']; 12039 for (var i = 0; i < triggerEvents.length; i++) { 12040 s.wrapper.trigger(triggerEvents[i]); 12041 } 12042 }); 12043 } 12044 } 12045 }, 12046 flip: { 12047 setTranslate: function () { 12048 for (var i = 0; i < s.slides.length; i++) { 12049 var slide = s.slides.eq(i); 12050 var progress = slide[0].progress; 12051 if (s.params.flip.limitRotation) { 12052 progress = Math.max(Math.min(slide[0].progress, 1), -1); 12053 } 12054 var offset = slide[0].swiperSlideOffset; 12055 var rotate = -180 * progress, 12056 rotateY = rotate, 12057 rotateX = 0, 12058 tx = -offset, 12059 ty = 0; 12060 if (!s.isHorizontal()) { 12061 ty = tx; 12062 tx = 0; 12063 rotateX = -rotateY; 12064 rotateY = 0; 12065 } 12066 else if (s.rtl) { 12067 rotateY = -rotateY; 12068 } 12069 12070 slide[0].style.zIndex = -Math.abs(Math.round(progress)) + s.slides.length; 12071 12072 if (s.params.flip.slideShadows) { 12073 //Set shadows 12074 var shadowBefore = s.isHorizontal() ? slide.find('.swiper-slide-shadow-left') : slide.find('.swiper-slide-shadow-top'); 12075 var shadowAfter = s.isHorizontal() ? slide.find('.swiper-slide-shadow-right') : slide.find('.swiper-slide-shadow-bottom'); 12076 if (shadowBefore.length === 0) { 12077 shadowBefore = $('<div class="swiper-slide-shadow-' + (s.isHorizontal() ? 'left' : 'top') + '"></div>'); 12078 slide.append(shadowBefore); 12079 } 12080 if (shadowAfter.length === 0) { 12081 shadowAfter = $('<div class="swiper-slide-shadow-' + (s.isHorizontal() ? 'right' : 'bottom') + '"></div>'); 12082 slide.append(shadowAfter); 12083 } 12084 if (shadowBefore.length) shadowBefore[0].style.opacity = Math.max(-progress, 0); 12085 if (shadowAfter.length) shadowAfter[0].style.opacity = Math.max(progress, 0); 12086 } 12087 12088 slide 12089 .transform('translate3d(' + tx + 'px, ' + ty + 'px, 0px) rotateX(' + rotateX + 'deg) rotateY(' + rotateY + 'deg)'); 12090 } 12091 }, 12092 setTransition: function (duration) { 12093 s.slides.transition(duration).find('.swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left').transition(duration); 12094 if (s.params.virtualTranslate && duration !== 0) { 12095 var eventTriggered = false;
12096 s.slides.eq(s.activeIndex).transitionEnd(function () { 12097 if (eventTriggered) return; 12098 if (!s) return; 12099 if (!$(this).hasClass(s.params.slideActiveClass)) return; 12100 eventTriggered = true; 12101 s.animating = false; 12102 var triggerEvents = ['webkitTransitionEnd', 'transitionend', 'oTransitionEnd', 'MSTransitionEnd', 'msTransitionEnd']; 12103 for (var i = 0; i < triggerEvents.length; i++) { 12104 s.wrapper.trigger(triggerEvents[i]); 12105 } 12106 }); 12107 } 12108 } 12109 }, 12110 cube: { 12111 setTranslate: function () { 12112 var wrapperRotate = 0, cubeShadow; 12113 if (s.params.cube.shadow) { 12114 if (s.isHorizontal()) { 12115 cubeShadow = s.wrapper.find('.swiper-cube-shadow'); 12116 if (cubeShadow.length === 0) { 12117 cubeShadow = $('<div class="swiper-cube-shadow"></div>'); 12118 s.wrapper.append(cubeShadow); 12119 } 12120 cubeShadow.css({height: s.width + 'px'}); 12121 } 12122 else { 12123 cubeShadow = s.container.find('.swiper-cube-shadow'); 12124 if (cubeShadow.length === 0) { 12125 cubeShadow = $('<div class="swiper-cube-shadow"></div>'); 12126 s.container.append(cubeShadow); 12127 } 12128 } 12129 } 12130 for (var i = 0; i < s.slides.length; i++) { 12131 var slide = s.slides.eq(i); 12132 var slideAngle = i * 90; 12133 var round = Math.floor(slideAngle / 360); 12134 if (s.rtl) { 12135 slideAngle = -slideAngle; 12136 round = Math.floor(-slideAngle / 360); 12137 } 12138 var progress = Math.max(Math.min(slide[0].progress, 1), -1); 12139 var tx = 0, ty = 0, tz = 0; 12140 if (i % 4 === 0) { 12141 tx = - round * 4 * s.size; 12142 tz = 0; 12143 } 12144 else if ((i - 1) % 4 === 0) { 12145 tx = 0; 12146 tz = - round * 4 * s.size; 12147 } 12148 else if ((i - 2) % 4 === 0) { 12149 tx = s.size + round * 4 * s.size; 12150 tz = s.size; 12151 } 12152 else if ((i - 3) % 4 === 0) { 12153 tx = - s.size; 12154 tz = 3 * s.size + s.size * 4 * round; 12155 } 12156 if (s.rtl) { 12157 tx = -tx; 12158 } 12159 12160 if (!s.isHorizontal()) { 12161 ty = tx; 12162 tx = 0; 12163 } 12164 12165 var transform = 'rotateX(' + (s.isHorizontal() ? 0 : -slideAngle) + 'deg) rotateY(' + (s.isHorizontal() ? slideAngle : 0) + 'deg) translate3d(' + tx + 'px, ' + ty + 'px, ' + tz + 'px)'; 12166 if (progress <= 1 && progress > -1) { 12167 wrapperRotate = i * 90 + progress * 90; 12168 if (s.rtl) wrapperRotate = -i * 90 - progress * 90; 12169 } 12170 slide.transform(transform); 12171 if (s.params.cube.slideShadows) { 12172 //Set shadows 12173 var shadowBefore = s.isHorizontal() ? slide.find('.swiper-slide-shadow-left') : slide.find('.swiper-slide-shadow-top'); 12174 var shadowAfter = s.isHorizontal() ? slide.find('.swiper-slide-shadow-right') : slide.find('.swiper-slide-shadow-bottom'); 12175 if (shadowBefore.length === 0) { 12176 shadowBefore = $('<div class="swiper-slide-shadow-' + (s.isHorizontal() ? 'left' : 'top') + '"></div>'); 12177 slide.append(shadowBefore); 12178 } 12179 if (shadowAfter.length === 0) {
12180 shadowAfter = $('<div class="swiper-slide-shadow-' + (s.isHorizontal() ? 'right' : 'bottom') + '"></div>'); 12181 slide.append(shadowAfter); 12182 } 12183 if (shadowBefore.length) shadowBefore[0].style.opacity = Math.max(-progress, 0); 12184 if (shadowAfter.length) shadowAfter[0].style.opacity = Math.max(progress, 0); 12185 } 12186 } 12187 s.wrapper.css({ 12188 '-webkit-transform-origin': '50% 50% -' + (s.size / 2) + 'px', 12189 '-moz-transform-origin': '50% 50% -' + (s.size / 2) + 'px', 12190 '-ms-transform-origin': '50% 50% -' + (s.size / 2) + 'px', 12191 'transform-origin': '50% 50% -' + (s.size / 2) + 'px' 12192 }); 12193 12194 if (s.params.cube.shadow) { 12195 if (s.isHorizontal()) { 12196 cubeShadow.transform('translate3d(0px, ' + (s.width / 2 + s.params.cube.shadowOffset) + 'px, ' + (-s.width / 2) + 'px) rotateX(90deg) rotateZ(0deg) scale(' + (s.params.cube.shadowScale) + ')'); 12197 } 12198 else { 12199 var shadowAngle = Math.abs(wrapperRotate) - Math.floor(Math.abs(wrapperRotate) / 90) * 90; 12200 var multiplier = 1.5 - (Math.sin(shadowAngle * 2 * Math.PI / 360) / 2 + Math.cos(shadowAngle * 2 * Math.PI / 360) / 2); 12201 var scale1 = s.params.cube.shadowScale, 12202 scale2 = s.params.cube.shadowScale / multiplier, 12203 offset = s.params.cube.shadowOffset; 12204 cubeShadow.transform('scale3d(' + scale1 + ', 1, ' + scale2 + ') translate3d(0px, ' + (s.height / 2 + offset) + 'px, ' + (-s.height / 2 / scale2) + 'px) rotateX(-90deg)'); 12205 } 12206 } 12207 var zFactor = (s.isSafari || s.isUiWebView) ? (-s.size / 2) : 0; 12208 s.wrapper.transform('translate3d(0px,0,' + zFactor + 'px) rotateX(' + (s.isHorizontal() ? 0 : wrapperRotate) + 'deg) rotateY(' + (s.isHorizontal() ? -wrapperRotate : 0) + 'deg)'); 12209 }, 12210 setTransition: function (duration) { 12211 s.slides.transition(duration).find('.swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left').transition(duration); 12212 if (s.params.cube.shadow && !s.isHorizontal()) { 12213 s.container.find('.swiper-cube-shadow').transition(duration); 12214 } 12215 } 12216 }, 12217 coverflow: { 12218 setTranslate: function () { 12219 var transform = s.translate; 12220 var center = s.isHorizontal() ? -transform + s.width / 2 : -transform + s.height / 2; 12221 var rotate = s.isHorizontal() ? s.params.coverflow.rotate: -s.params.coverflow.rotate; 12222 var translate = s.params.coverflow.depth; 12223 //Each slide offset from center 12224 for (var i = 0, length = s.slides.length; i < length; i++) { 12225 var slide = s.slides.eq(i); 12226 var slideSize = s.slidesSizesGrid[i]; 12227 var slideOffset = slide[0].swiperSlideOffset; 12228 var offsetMultiplier = (center - slideOffset - slideSize / 2) / slideSize * s.params.coverflow.modifier; 12229 12230 var rotateY = s.isHorizontal() ? rotate * offsetMultiplier : 0; 12231 var rotateX = s.isHorizontal() ? 0 : rotate * offsetMultiplier; 12232 // var rotateZ = 0 12233 var translateZ = -translate * Math.abs(offsetMultiplier); 12234 12235 var translateY = s.isHorizontal() ? 0 : s.params.coverflow.stretch * (offsetMultiplier); 12236 var translateX = s.isHorizontal() ? s.params.coverflow.stretch * (offsetMultiplier) : 0; 12237 12238 //Fix for ultra small values 12239 if (Math.abs(translateX) < 0.001) translateX = 0; 12240 if (Math.abs(translateY) < 0.001) translateY = 0; 12241 if (Math.abs(translateZ) < 0.001) translateZ = 0; 12242 if (Math.abs(rotateY) < 0.001) rotateY = 0; 12243 if (Math.abs(rotateX) < 0.001) rotateX = 0; 12244 12245 var slideTransform = 'translate3d(' + translateX + 'px,' + translateY + 'px,' + translateZ + 'px) rotateX(' + rotateX + 'deg) rotateY(' + rotateY + 'deg)'; 12246 12247 slide.transform(slideTransform); 12248 slide[0].style.zIndex = -Math.abs(Math.round(offsetMultiplier)) + 1; 12249 if (s.params.coverflow.slideShadows) { 12250 //Set shadows 12251 var shadowBefore = s.isHorizontal() ? slide.find('.swiper-slide-shadow-left') : slide.find('.swiper-slide-shadow-top'); 12252 var shadowAfter = s.isHorizontal() ? slide.find('.swiper-slide-shadow-right') : slide.find('.swiper-slide-shadow-bottom'); 12253 if (shadowBefore.length === 0) { 12254 shadowBefore = $('<div class="swiper-slide-shadow-' + (s.isHorizontal() ? 'left' : 'top') + '"></div>'); 12255 slide.append(shadowBefore); 12256 } 12257 if (shadowAfter.length === 0) {
12258 shadowAfter = $('<div class="swiper-slide-shadow-' + (s.isHorizontal() ? 'right' : 'bottom') + '"></div>'); 12259 slide.append(shadowAfter); 12260 } 12261 if (shadowBefore.length) shadowBefore[0].style.opacity = offsetMultiplier > 0 ? offsetMultiplier : 0; 12262 if (shadowAfter.length) shadowAfter[0].style.opacity = (-offsetMultiplier) > 0 ? -offsetMultiplier : 0; 12263 } 12264 } 12265 12266 //Set correct perspective for IE10 12267 if (s.browser.ie) { 12268 var ws = s.wrapper[0].style; 12269 ws.perspectiveOrigin = center + 'px 50%'; 12270 } 12271 }, 12272 setTransition: function (duration) { 12273 s.slides.transition(duration).find('.swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left').transition(duration); 12274 } 12275 } 12276 }; 12277 12278 12279 /*========================= 12280 Images Lazy Loading 12281 ===========================*/ 12282 s.lazy = { 12283 initialImageLoaded: false, 12284 loadImageInSlide: function (index, loadInDuplicate) { 12285 if (typeof index === 'undefined') return; 12286 if (typeof loadInDuplicate === 'undefined') loadInDuplicate = true; 12287 if (s.slides.length === 0) return; 12288 12289 var slide = s.slides.eq(index); 12290 var img = slide.find('.' + s.params.lazyLoadingClass + ':not(.' + s.params.lazyStatusLoadedClass + '):not(.' + s.params.lazyStatusLoadingClass + ')'); 12291 if (slide.hasClass(s.params.lazyLoadingClass) && !slide.hasClass(s.params.lazyStatusLoadedClass) && !slide.hasClass(s.params.lazyStatusLoadingClass)) { 12292 img = img.add(slide[0]); 12293 } 12294 if (img.length === 0) return; 12295 12296 img.each(function () { 12297 var _img = $(this); 12298 _img.addClass(s.params.lazyStatusLoadingClass); 12299 var background = _img.attr('data-background'); 12300 var src = _img.attr('data-src'), 12301 srcset = _img.attr('data-srcset'), 12302 sizes = _img.attr('data-sizes'); 12303 s.loadImage(_img[0], (src || background), srcset, sizes, false, function () { 12304 if (typeof s === 'undefined' || s === null || !s) return; 12305 if (background) { 12306 _img.css('background-image', 'url("' + background + '")'); 12307 _img.removeAttr('data-background'); 12308 } 12309 else { 12310 if (srcset) { 12311 _img.attr('srcset', srcset); 12312 _img.removeAttr('data-srcset'); 12313 } 12314 if (sizes) { 12315 _img.attr('sizes', sizes); 12316 _img.removeAttr('data-sizes'); 12317 } 12318 if (src) { 12319 _img.attr('src', src); 12320 _img.removeAttr('data-src'); 12321 } 12322 12323 } 12324 12325 _img.addClass(s.params.lazyStatusLoadedClass).removeClass(s.params.lazyStatusLoadingClass); 12326 slide.find('.' + s.params.lazyPreloaderClass + ', .' + s.params.preloaderClass).remove(); 12327 if (s.params.loop && loadInDuplicate) { 12328 var slideOriginalIndex = slide.attr('data-swiper-slide-index'); 12329 if (slide.hasClass(s.params.slideDuplicateClass)) { 12330 var originalSlide = s.wrapper.children('[data-swiper-slide-index="' + slideOriginalIndex + '"]:not(.' + s.params.slideDuplicateClass + ')'); 12331 s.lazy.loadImageInSlide(originalSlide.index(), false); 12332 } 12333 else { 12334 var duplicatedSlide = s.wrapper.children('.' + s.params.slideDuplicateClass + '[data-swiper-slide-index="' + slideOriginalIndex + '"]'); 12335 s.lazy.loadImageInSlide(duplicatedSlide.index(), false); 12336 } 12337 } 12338 s.emit('onLazyImageReady', s, slide[0], _img[0]); 12339 }); 12340 12341 s.emit('onLazyImageLoad', s, slide[0], _img[0]); 12342 }); 12343 12344 }, 12345 load: function () { 12346 var i; 12347 var slidesPerView = s.params.slidesPerView; 12348 if (slidesPerView === 'auto') { 12349 slidesPerView = 0; 12350 } 12351 if (!s.lazy.initialImageLoaded) s.lazy.initialImageLoaded = true; 12352 if (s.params.watchSlidesVisibility) { 12353 s.wrapper.children('.' + s.params.slideVisibleClass).each(function () { 12354 s.lazy.loadImageInSlide($(this).index()); 12355 }); 12356 } 12357 else { 12358 if (slidesPerView > 1) { 12359 for (i = s.activeIndex; i < s.activeIndex + slidesPerView ; i++) { 12360 if (s.slides[i]) s.lazy.loadImageInSlide(i); 12361 } 12362 } 12363 else { 12364 s.lazy.loadImageInSlide(s.activeIndex); 12365 } 12366 } 12367 if (s.params.lazyLoadingInPrevNext) { 12368 if (slidesPerView > 1 || (s.params.lazyLoadingInPrevNextAmount && s.params.lazyLoadingInPrevNextAmount > 1)) { 12369 var amount = s.params.lazyLoadingInPrevNextAmount; 12370 var spv = slidesPerView; 12371 var maxIndex = Math.min(s.activeIndex + spv + Math.max(amount, spv), s.slides.length); 12372 var minIndex = Math.max(s.activeIndex - Math.max(spv, amount), 0); 12373 // Next Slides 12374 for (i = s.activeIndex + slidesPerView; i < maxIndex; i++) { 12375 if (s.slides[i]) s.lazy.loadImageInSlide(i); 12376 } 12377 // Prev Slides 12378 for (i = minIndex; i < s.activeIndex ; i++) { 12379 if (s.slides[i]) s.lazy.loadImageInSlide(i); 12380 } 12381 } 12382 else { 12383 var nextSlide = s.wrapper.children('.' + s.params.slideNextClass); 12384 if (nextSlide.length > 0) s.lazy.loadImageInSlide(nextSlide.index()); 12385 12386 var prevSlide = s.wrapper.children('.' + s.params.slidePrevClass); 12387 if (prevSlide.length > 0) s.lazy.loadImageInSlide(prevSlide.index()); 12388 } 12389 } 12390 }, 12391 onTransitionStart: function () { 12392 if (s.params.lazyLoading) { 12393 if (s.params.lazyLoadingOnTransitionStart || (!s.params.lazyLoadingOnTransitionStart && !s.lazy.initialImageLoaded)) { 12394 s.lazy.load(); 12395 } 12396 } 12397 }, 12398 onTransitionEnd: function () { 12399 if (s.params.lazyLoading && !s.params.lazyLoadingOnTransitionStart) { 12400 s.lazy.load(); 12401 } 12402 } 12403 }; 12404 12405 12406 /*========================= 12407 Scrollbar 12408 ===========================*/ 12409 s.scrollbar = { 12410 isTouched: false, 12411 setDragPosition: function (e) { 12412 var sb = s.scrollbar; 12413 var x = 0, y = 0; 12414 var translate; 12415 var pointerPosition = s.isHorizontal() ? 12416 ((e.type === 'touchstart' || e.type === 'touchmove') ? e.targetTouches[0].pageX : e.pageX || e.clientX) : 12417 ((e.type === 'touchstart' || e.type === 'touchmove') ? e.targetTouches[0].pageY : e.pageY || e.clientY) ; 12418 var position = (pointerPosition) - sb.track.offset()[s.isHorizontal() ? 'left' : 'top'] - sb.dragSize / 2; 12419 var positionMin = -s.minTranslate() * sb.moveDivider; 12420 var positionMax = -s.maxTranslate() * sb.moveDivider; 12421 if (position < positionMin) { 12422 position = positionMin; 12423 } 12424 else if (position > positionMax) { 12425 position = positionMax; 12426 } 12427 position = -position / sb.moveDivider; 12428 s.updateProgress(position); 12429 s.setWrapperTranslate(position, true); 12430 }, 12431 dragStart: function (e) { 12432 var sb = s.scrollbar; 12433 sb.isTouched = true; 12434 e.preventDefault(); 12435 e.stopPropagation(); 12436 12437 sb.setDragPosition(e); 12438 clearTimeout(sb.dragTimeout); 12439 12440 sb.track.transition(0); 12441 if (s.params.scrollbarHide) { 12442 sb.track.css('opacity', 1); 12443 } 12444 s.wrapper.transition(100); 12445 sb.drag.transition(100); 12446 s.emit('onScrollbarDragStart', s); 12447 }, 12448 dragMove: function (e) { 12449 var sb = s.scrollbar; 12450 if (!sb.isTouched) return; 12451 if (e.preventDefault) e.preventDefault(); 12452 else e.returnValue = false;
12453 sb.setDragPosition(e); 12454 s.wrapper.transition(0); 12455 sb.track.transition(0); 12456 sb.drag.transition(0); 12457 s.emit('onScrollbarDragMove', s); 12458 }, 12459 dragEnd: function (e) { 12460 var sb = s.scrollbar; 12461 if (!sb.isTouched) return; 12462 sb.isTouched = false; 12463 if (s.params.scrollbarHide) { 12464 clearTimeout(sb.dragTimeout); 12465 sb.dragTimeout = setTimeout(function () { 12466 sb.track.css('opacity', 0); 12467 sb.track.transition(400); 12468 }, 1000); 12469 12470 } 12471 s.emit('onScrollbarDragEnd', s); 12472 if (s.params.scrollbarSnapOnRelease) { 12473 s.slideReset(); 12474 } 12475 }, 12476 draggableEvents: (function () { 12477 if ((s.params.simulateTouch === false && !s.support.touch)) return s.touchEventsDesktop; 12478 else return s.touchEvents; 12479 })(), 12480 enableDraggable: function () { 12481 var sb = s.scrollbar; 12482 var target = s.support.touch ? sb.track : document; 12483 $(sb.track).on(sb.draggableEvents.start, sb.dragStart); 12484 $(target).on(sb.draggableEvents.move, sb.dragMove); 12485 $(target).on(sb.draggableEvents.end, sb.dragEnd); 12486 }, 12487 disableDraggable: function () { 12488 var sb = s.scrollbar; 12489 var target = s.support.touch ? sb.track : document; 12490 $(sb.track).off(sb.draggableEvents.start, sb.dragStart); 12491 $(target).off(sb.draggableEvents.move, sb.dragMove); 12492 $(target).off(sb.draggableEvents.end, sb.dragEnd); 12493 }, 12494 set: function () { 12495 if (!s.params.scrollbar) return; 12496 var sb = s.scrollbar; 12497 sb.track = $(s.params.scrollbar); 12498 if (s.params.uniqueNavElements && typeof s.params.scrollbar === 'string' && sb.track.length > 1 && s.container.find(s.params.scrollbar).length === 1) { 12499 sb.track = s.container.find(s.params.scrollbar); 12500 } 12501 sb.drag = sb.track.find('.swiper-scrollbar-drag'); 12502 if (sb.drag.length === 0) { 12503 sb.drag = $('<div class="swiper-scrollbar-drag"></div>'); 12504 sb.track.append(sb.drag); 12505 } 12506 sb.drag[0].style.width = ''; 12507 sb.drag[0].style.height = ''; 12508 sb.trackSize = s.isHorizontal() ? sb.track[0].offsetWidth : sb.track[0].offsetHeight; 12509 12510 sb.divider = s.size / s.virtualSize; 12511 sb.moveDivider = sb.divider * (sb.trackSize / s.size); 12512 sb.dragSize = sb.trackSize * sb.divider; 12513 12514 if (s.isHorizontal()) { 12515 sb.drag[0].style.width = sb.dragSize + 'px'; 12516 } 12517 else { 12518 sb.drag[0].style.height = sb.dragSize + 'px'; 12519 } 12520 12521 if (sb.divider >= 1) { 12522 sb.track[0].style.display = 'none'; 12523 } 12524 else { 12525 sb.track[0].style.display = ''; 12526 } 12527 if (s.params.scrollbarHide) { 12528 sb.track[0].style.opacity = 0; 12529 } 12530 }, 12531 setTranslate: function () { 12532 if (!s.params.scrollbar) return; 12533 var diff; 12534 var sb = s.scrollbar; 12535 var translate = s.translate || 0; 12536 var newPos; 12537 12538 var newSize = sb.dragSize; 12539 newPos = (sb.trackSize - sb.dragSize) * s.progress; 12540 if (s.rtl && s.isHorizontal()) { 12541 newPos = -newPos; 12542 if (newPos > 0) { 12543 newSize = sb.dragSize - newPos; 12544 newPos = 0; 12545 } 12546 else if (-newPos + sb.dragSize > sb.trackSize) { 12547 newSize = sb.trackSize + newPos; 12548 } 12549 } 12550 else { 12551 if (newPos < 0) { 12552 newSize = sb.dragSize + newPos; 12553 newPos = 0; 12554 } 12555 else if (newPos + sb.dragSize > sb.trackSize) { 12556 newSize = sb.trackSize - newPos; 12557 } 12558 } 12559 if (s.isHorizontal()) { 12560 if (s.support.transforms3d) { 12561 sb.drag.transform('translate3d(' + (newPos) + 'px, 0, 0)'); 12562 } 12563 else { 12564 sb.drag.transform('translateX(' + (newPos) + 'px)'); 12565 } 12566 sb.drag[0].style.width = newSize + 'px'; 12567 } 12568 else { 12569 if (s.support.transforms3d) { 12570 sb.drag.transform('translate3d(0px, ' + (newPos) + 'px, 0)'); 12571 } 12572 else { 12573 sb.drag.transform('translateY(' + (newPos) + 'px)'); 12574 } 12575 sb.drag[0].style.height = newSize + 'px'; 12576 } 12577 if (s.params.scrollbarHide) { 12578 clearTimeout(sb.timeout); 12579 sb.track[0].style.opacity = 1; 12580 sb.timeout = setTimeout(function () { 12581 sb.track[0].style.opacity = 0; 12582 sb.track.transition(400); 12583 }, 1000); 12584 } 12585 }, 12586 setTransition: function (duration) { 12587 if (!s.params.scrollbar) return; 12588 s.scrollbar.drag.transition(duration); 12589 } 12590 }; 12591 12592 12593 /*========================= 12594 Controller 12595 ===========================*/ 12596 s.controller = { 12597 LinearSpline: function (x, y) { 12598 var binarySearch = (function() { 12599 var maxIndex, minIndex, guess; 12600 return function(array, val) { 12601 minIndex = -1; 12602 maxIndex = array.length; 12603 while (maxIndex - minIndex > 1)
12604 if (array[guess = maxIndex + minIndex >> 1] <= val) { 12605 minIndex = guess; 12606 } else { 12607 maxIndex = guess; 12608 } 12609 return maxIndex; 12610 }; 12611 })(); 12612 this.x = x; 12613 this.y = y; 12614 this.lastIndex = x.length - 1; 12615 // Given an x value (x2), return the expected y2 value: 12616 // (x1,y1) is the known point before given value, 12617 // (x3,y3) is the known point after given value. 12618 var i1, i3; 12619 var l = this.x.length; 12620 12621 this.interpolate = function (x2) { 12622 if (!x2) return 0; 12623 12624 // Get the indexes of x1 and x3 (the array indexes before and after given x2): 12625 i3 = binarySearch(this.x, x2); 12626 i1 = i3 - 1; 12627 12628 // We have our indexes i1 & i3, so we can calculate already: 12629 // y2 := ((x2−x1) × (y3−y1)) ÷ (x3−x1) + y1 12630 return ((x2 - this.x[i1]) * (this.y[i3] - this.y[i1])) / (this.x[i3] - this.x[i1]) + this.y[i1]; 12631 }; 12632 }, 12633 //xxx: for now i will just save one spline function to to 12634 getInterpolateFunction: function(c){ 12635 if(!s.controller.spline) s.controller.spline = s.params.loop ? 12636 new s.controller.LinearSpline(s.slidesGrid, c.slidesGrid) : 12637 new s.controller.LinearSpline(s.snapGrid, c.snapGrid); 12638 }, 12639 setTranslate: function (translate, byController) { 12640 var controlled = s.params.control; 12641 var multiplier, controlledTranslate; 12642 function setControlledTranslate(c) { 12643 // this will create an Interpolate function based on the snapGrids 12644 // x is the Grid of the scrolled scroller and y will be the controlled scroller 12645 // it makes sense to create this only once and recall it for the interpolation 12646 // the function does a lot of value caching for performance 12647 translate = c.rtl && c.params.direction === 'horizontal' ? -s.translate : s.translate; 12648 if (s.params.controlBy === 'slide') { 12649 s.controller.getInterpolateFunction(c); 12650 // i am not sure why the values have to be multiplicated this way, tried to invert the snapGrid 12651 // but it did not work out 12652 controlledTranslate = -s.controller.spline.interpolate(-translate); 12653 } 12654 12655 if(!controlledTranslate || s.params.controlBy === 'container'){ 12656 multiplier = (c.maxTranslate() - c.minTranslate()) / (s.maxTranslate() - s.minTranslate()); 12657 controlledTranslate = (translate - s.minTranslate()) * multiplier + c.minTranslate(); 12658 } 12659 12660 if (s.params.controlInverse) { 12661 controlledTranslate = c.maxTranslate() - controlledTranslate; 12662 } 12663 c.updateProgress(controlledTranslate); 12664 c.setWrapperTranslate(controlledTranslate, false, s); 12665 c.updateActiveIndex(); 12666 } 12667 if (Array.isArray(controlled)) { 12668 for (var i = 0; i < controlled.length; i++) { 12669 if (controlled[i] !== byController && controlled[i] instanceof Swiper) { 12670 setControlledTranslate(controlled[i]); 12671 } 12672 } 12673 } 12674 else if (controlled instanceof Swiper && byController !== controlled) { 12675 12676 setControlledTranslate(controlled); 12677 } 12678 }, 12679 setTransition: function (duration, byController) { 12680 var controlled = s.params.control; 12681 var i; 12682 function setControlledTransition(c) { 12683 c.setWrapperTransition(duration, s); 12684 if (duration !== 0) { 12685 c.onTransitionStart(); 12686 c.wrapper.transitionEnd(function(){ 12687 if (!controlled) return; 12688 if (c.params.loop && s.params.controlBy === 'slide') { 12689 c.fixLoop(); 12690 } 12691 c.onTransitionEnd(); 12692 12693 }); 12694 } 12695 } 12696 if (Array.isArray(controlled)) { 12697 for (i = 0; i < controlled.length; i++) { 12698 if (controlled[i] !== byController && controlled[i] instanceof Swiper) { 12699 setControlledTransition(controlled[i]); 12700 } 12701 } 12702 } 12703 else if (controlled instanceof Swiper && byController !== controlled) { 12704 setControlledTransition(controlled); 12705 } 12706 } 12707 }; 12708 12709 12710 /*========================= 12711 Hash Navigation 12712 ===========================*/ 12713 s.hashnav = { 12714 onHashCange: function (e, a) { 12715 var newHash = document.location.hash.replace('#', ''); 12716 var activeSlideHash = s.slides.eq(s.activeIndex).attr('data-hash'); 12717 if (newHash !== activeSlideHash) { 12718 s.slideTo(s.wrapper.children('.' + s.params.slideClass + '[data-hash="' + (newHash) + '"]').index()); 12719 } 12720 }, 12721 attachEvents: function (detach) { 12722 var action = detach ? 'off' : 'on'; 12723 $(window)[action]('hashchange', s.hashnav.onHashCange); 12724 }, 12725 setHash: function () { 12726 if (!s.hashnav.initialized || !s.params.hashnav) return; 12727 if (s.params.replaceState && window.history && window.history.replaceState) { 12728 window.history.replaceState(null, null, ('#' + s.slides.eq(s.activeIndex).attr('data-hash') || '')); 12729 } else { 12730 var slide = s.slides.eq(s.activeIndex); 12731 var hash = slide.attr('data-hash') || slide.attr('data-history'); 12732 document.location.hash = hash || ''; 12733 } 12734 }, 12735 init: function () { 12736 if (!s.params.hashnav || s.params.history) return; 12737 s.hashnav.initialized = true; 12738 var hash = document.location.hash.replace('#', ''); 12739 if (hash) { 12740 var speed = 0; 12741 for (var i = 0, length = s.slides.length; i < length; i++) { 12742 var slide = s.slides.eq(i); 12743 var slideHash = slide.attr('data-hash') || slide.attr('data-history'); 12744 if (slideHash === hash && !slide.hasClass(s.params.slideDuplicateClass)) { 12745 var index = slide.index(); 12746 s.slideTo(index, speed, s.params.runCallbacksOnInit, true); 12747 } 12748 } 12749 } 12750 if (s.params.hashnavWatchState) s.hashnav.attachEvents(); 12751 }, 12752 destroy: function () { 12753 if (s.params.hashnavWatchState) s.hashnav.attachEvents(true); 12754 } 12755 }; 12756 12757 12758 /*========================= 12759 History Api with fallback to Hashnav 12760 ===========================*/ 12761 s.history = { 12762 init: function () { 12763 if (!s.params.history) return; 12764 if (!window.history || !window.history.pushState) { 12765 s.params.history = false;
12766 s.params.hashnav = true; 12767 return; 12768 } 12769 s.history.initialized = true; 12770 this.paths = this.getPathValues(); 12771 if (!this.paths.key && !this.paths.value) return; 12772 this.scrollToSlide(0, this.paths.value, s.params.runCallbacksOnInit); 12773 if (!s.params.replaceState) { 12774 window.addEventListener('popstate', this.setHistoryPopState); 12775 } 12776 }, 12777 setHistoryPopState: function() { 12778 s.history.paths = s.history.getPathValues(); 12779 s.history.scrollToSlide(s.params.speed, s.history.paths.value, false); 12780 }, 12781 getPathValues: function() { 12782 var pathArray = window.location.pathname.slice(1).split('/'); 12783 var total = pathArray.length; 12784 var key = pathArray[total - 2]; 12785 var value = pathArray[total - 1]; 12786 return { key: key, value: value }; 12787 }, 12788 setHistory: function (key, index) { 12789 if (!s.history.initialized || !s.params.history) return; 12790 var slide = s.slides.eq(index); 12791 var value = this.slugify(slide.attr('data-history')); 12792 if (!window.location.pathname.includes(key)) { 12793 value = key + '/' + value; 12794 } 12795 if (s.params.replaceState) { 12796 window.history.replaceState(null, null, value); 12797 } else { 12798 window.history.pushState(null, null, value); 12799 } 12800 }, 12801 slugify: function(text) { 12802 return text.toString().toLowerCase() 12803 .replace(/\s+/g, '-') 12804 .replace(/[^\w\-]+/g, '') 12805 .replace(/\-\-+/g, '-') 12806 .replace(/^-+/, '') 12807 .replace(/-+$/, ''); 12808 }, 12809 scrollToSlide: function(speed, value, runCallbacks) { 12810 if (value) { 12811 for (var i = 0, length = s.slides.length; i < length; i++) { 12812 var slide = s.slides.eq(i); 12813 var slideHistory = this.slugify(slide.attr('data-history')); 12814 if (slideHistory === value && !slide.hasClass(s.params.slideDuplicateClass)) { 12815 var index = slide.index(); 12816 s.slideTo(index, speed, runCallbacks); 12817 } 12818 } 12819 } else { 12820 s.slideTo(0, speed, runCallbacks); 12821 } 12822 } 12823 }; 12824 12825 12826 /*========================= 12827 Keyboard Control 12828 ===========================*/ 12829 function handleKeyboard(e) { 12830 if (e.originalEvent) e = e.originalEvent; //jquery fix 12831 var kc = e.keyCode || e.charCode; 12832 // Directions locks 12833 if (!s.params.allowSwipeToNext && (s.isHorizontal() && kc === 39 || !s.isHorizontal() && kc === 40)) { 12834 return false; 12835 } 12836 if (!s.params.allowSwipeToPrev && (s.isHorizontal() && kc === 37 || !s.isHorizontal() && kc === 38)) { 12837 return false; 12838 } 12839 if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey) { 12840 return; 12841 } 12842 if (document.activeElement && document.activeElement.nodeName && (document.activeElement.nodeName.toLowerCase() === 'input' || document.activeElement.nodeName.toLowerCase() === 'textarea')) { 12843 return; 12844 } 12845 if (kc === 37 || kc === 39 || kc === 38 || kc === 40) { 12846 var inView = false; 12847 //Check that swiper should be inside of visible area of window 12848 if (s.container.parents('.' + s.params.slideClass).length > 0 && s.container.parents('.' + s.params.slideActiveClass).length === 0) { 12849 return; 12850 } 12851 var windowScroll = { 12852 left: window.pageXOffset, 12853 top: window.pageYOffset 12854 }; 12855 var windowWidth = window.innerWidth; 12856 var windowHeight = window.innerHeight; 12857 var swiperOffset = s.container.offset(); 12858 if (s.rtl) swiperOffset.left = swiperOffset.left - s.container[0].scrollLeft; 12859 var swiperCoord = [ 12860 [swiperOffset.left, swiperOffset.top], 12861 [swiperOffset.left + s.width, swiperOffset.top], 12862 [swiperOffset.left, swiperOffset.top + s.height], 12863 [swiperOffset.left + s.width, swiperOffset.top + s.height] 12864 ]; 12865 for (var i = 0; i < swiperCoord.length; i++) { 12866 var point = swiperCoord[i]; 12867 if ( 12868 point[0] >= windowScroll.left && point[0] <= windowScroll.left + windowWidth && 12869 point[1] >= windowScroll.top && point[1] <= windowScroll.top + windowHeight 12870 ) { 12871 inView = true; 12872 } 12873 12874 } 12875 if (!inView) return; 12876 } 12877 if (s.isHorizontal()) { 12878 if (kc === 37 || kc === 39) { 12879 if (e.preventDefault) e.preventDefault(); 12880 else e.returnValue = false;
12881 } 12882 if ((kc === 39 && !s.rtl) || (kc === 37 && s.rtl)) s.slideNext(); 12883 if ((kc === 37 && !s.rtl) || (kc === 39 && s.rtl)) s.slidePrev(); 12884 } 12885 else { 12886 if (kc === 38 || kc === 40) { 12887 if (e.preventDefault) e.preventDefault(); 12888 else e.returnValue = false; 12889 } 12890 if (kc === 40) s.slideNext(); 12891 if (kc === 38) s.slidePrev(); 12892 } 12893 s.emit('onKeyPress', s, kc); 12894 } 12895 s.disableKeyboardControl = function () { 12896 s.params.keyboardControl = false; 12897 $(document).off('keydown', handleKeyboard); 12898 }; 12899 s.enableKeyboardControl = function () { 12900 s.params.keyboardControl = true; 12901 $(document).on('keydown', handleKeyboard); 12902 }; 12903 12904 12905 /*========================= 12906 Mousewheel Control 12907 ===========================*/ 12908 s.mousewheel = { 12909 event: false, 12910 lastScrollTime: (new window.Date()).getTime() 12911 }; 12912 function isEventSupported() { 12913 var eventName = 'onwheel'; 12914 var isSupported = eventName in document; 12915 12916 if (!isSupported) { 12917 var element = document.createElement('div'); 12918 element.setAttribute(eventName, 'return;'); 12919 isSupported = typeof element[eventName] === 'function'; 12920 } 12921 12922 if (!isSupported && 12923 document.implementation && 12924 document.implementation.hasFeature && 12925 // always returns true in newer browsers as per the standard. 12926 // @see http://dom.spec.whatwg.org/#dom-domimplementation-hasfeature 12927 document.implementation.hasFeature('', '') !== true ) { 12928 // This is the only way to test support for the `wheel` event in IE9+. 12929 isSupported = document.implementation.hasFeature('Events.wheel', '3.0'); 12930 } 12931 12932 return isSupported; 12933 } 12934 /** 12935 * Mouse wheel (and 2-finger trackpad) support on the web sucks. It is 12936 * complicated, thus this doc is long and (hopefully) detailed enough to answer 12937 * your questions. 12938 * 12939 * If you need to react to the mouse wheel in a predictable way, this code is 12940 * like your bestest friend. * hugs * 12941 * 12942 * As of today, there are 4 DOM event types you can listen to: 12943 * 12944 * 'wheel' -- Chrome(31+), FF(17+), IE(9+) 12945 * 'mousewheel' -- Chrome, IE(6+), Opera, Safari 12946 * 'MozMousePixelScroll' -- FF(3.5 only!) (2010-2013) -- don't bother! 12947 * 'DOMMouseScroll' -- FF(0.9.7+) since 2003 12948 * 12949 * So what to do? The is the best: 12950 * 12951 * normalizeWheel.getEventType(); 12952 * 12953 * In your event callback, use this code to get sane interpretation of the 12954 * deltas. This code will return an object with properties: 12955 * 12956 * spinX -- normalized spin speed (use for zoom) - x plane 12957 * spinY -- " - y plane 12958 * pixelX -- normalized distance (to pixels) - x plane 12959 * pixelY -- " - y plane 12960 * 12961 * Wheel values are provided by the browser assuming you are using the wheel to
12962 * scroll a web page by a number of lines or pixels (or pages). Values can vary 12963 * significantly on different platforms and browsers, forgetting that you can 12964 * scroll at different speeds. Some devices (like trackpads) emit more events 12965 * at smaller increments with fine granularity, and some emit massive jumps with 12966 * linear speed or acceleration. 12967 * 12968 * This code does its best to normalize the deltas for you: 12969 * 12970 * - spin is trying to normalize how far the wheel was spun (or trackpad 12971 * dragged). This is super useful for zoom support where you want to 12972 * throw away the chunky scroll steps on the PC and make those equal to 12973 * the slow and smooth tiny steps on the Mac. Key data: This code tries to 12974 * resolve a single slow step on a wheel to 1. 12975 * 12976 * - pixel is normalizing the desired scroll delta in pixel units. You'll 12977 * get the crazy differences between browsers, but at least it'll be in 12978 * pixels! 12979 * 12980 * - positive value indicates scrolling DOWN/RIGHT, negative UP/LEFT. This 12981 * should translate to positive value zooming IN, negative zooming OUT. 12982 * This matches the newer 'wheel' event. 12983 * 12984 * Why are there spinX, spinY (or pixels)? 12985 * 12986 * - spinX is a 2-finger side drag on the trackpad, and a shift + wheel turn 12987 * with a mouse. It results in side-scrolling in the browser by default. 12988 * 12989 * - spinY is what you expect -- it's the classic axis of a mouse wheel. 12990 * 12991 * - I dropped spinZ/pixelZ. It is supported by the DOM 3 'wheel' event and 12992 * probably is by browsers in conjunction with fancy 3D controllers .. but 12993 * you know. 12994 * 12995 * Implementation info: 12996 * 12997 * Examples of 'wheel' event if you scroll slowly (down) by one step with an 12998 * average mouse: 12999 * 13000 * OS X + Chrome (mouse) - 4 pixel delta (wheelDelta -120) 13001 * OS X + Safari (mouse) - N/A pixel delta (wheelDelta -12) 13002 * OS X + Firefox (mouse) - 0.1 line delta (wheelDelta N/A) 13003 * Win8 + Chrome (mouse) - 100 pixel delta (wheelDelta -120) 13004 * Win8 + Firefox (mouse) - 3 line delta (wheelDelta -120) 13005 * 13006 * On the trackpad: 13007 * 13008 * OS X + Chrome (trackpad) - 2 pixel delta (wheelDelta -6) 13009 * OS X + Firefox (trackpad) - 1 pixel delta (wheelDelta N/A) 13010 * 13011 * On other/older browsers.. it's more complicated as there can be multiple and 13012 * also missing delta values. 13013 * 13014 * The 'wheel' event is more standard: 13015 * 13016 * http://www.w3.org/TR/DOM-Level-3-Events/#events-wheelevents 13017 * 13018 * The basics is that it includes a unit, deltaMode (pixels, lines, pages), and 13019 * deltaX, deltaY and deltaZ. Some browsers provide other values to maintain 13020 * backward compatibility with older events. Those other values help us 13021 * better normalize spin speed. Example of what the browsers provide: 13022 * 13023 * | event.wheelDelta | event.detail 13024 * ------------------+------------------+-------------- 13025 * Safari v5/OS X | -120 | 0 13026 * Safari v5/Win7 | -120 | 0 13027 * Chrome v17/OS X | -120 | 0 13028 * Chrome v17/Win7 | -120 | 0 13029 * IE9/Win7 | -120 | undefined 13030 * Firefox v4/OS X | undefined | 1 13031 * Firefox v4/Win7 | undefined | 3 13032 * 13033 */ 13034 function normalizeWheel( /*object*/ event ) /*object*/ { 13035 // Reasonable defaults 13036 var PIXEL_STEP = 10; 13037 var LINE_HEIGHT = 40; 13038 var PAGE_HEIGHT = 800; 13039 13040 var sX = 0, sY = 0, // spinX, spinY 13041 pX = 0, pY = 0; // pixelX, pixelY 13042 13043 // Legacy 13044 if( 'detail' in event ) { 13045 sY = event.detail; 13046 } 13047 if( 'wheelDelta' in event ) { 13048 sY = -event.wheelDelta / 120; 13049 } 13050 if( 'wheelDeltaY' in event ) { 13051 sY = -event.wheelDeltaY / 120; 13052 } 13053 if( 'wheelDeltaX' in event ) { 13054 sX = -event.wheelDeltaX / 120; 13055 } 13056 13057 // side scrolling on FF with DOMMouseScroll 13058 if( 'axis' in event && event.axis === event.HORIZONTAL_AXIS ) { 13059 sX = sY; 13060 sY = 0; 13061 } 13062 13063 pX = sX * PIXEL_STEP; 13064 pY = sY * PIXEL_STEP; 13065 13066 if( 'deltaY' in event ) { 13067 pY = event.deltaY; 13068 } 13069 if( 'deltaX' in event ) { 13070 pX = event.deltaX; 13071 } 13072 13073 if( (pX || pY) && event.deltaMode ) { 13074 if( event.deltaMode === 1 ) { // delta in LINE units 13075 pX *= LINE_HEIGHT; 13076 pY *= LINE_HEIGHT; 13077 } else { // delta in PAGE units 13078 pX *= PAGE_HEIGHT; 13079 pY *= PAGE_HEIGHT; 13080 } 13081 } 13082 13083 // Fall-back if spin cannot be determined 13084 if( pX && !sX ) { 13085 sX = (pX < 1) ? -1 : 1; 13086 } 13087 if( pY && !sY ) { 13088 sY = (pY < 1) ? -1 : 1; 13089 } 13090 13091 return { 13092 spinX: sX, 13093 spinY: sY, 13094 pixelX: pX, 13095 pixelY: pY 13096 }; 13097 } 13098 if (s.params.mousewheelControl) { 13099 /** 13100 * The best combination if you prefer spinX + spinY normalization. It favors 13101 * the older DOMMouseScroll for Firefox, as FF does not include wheelDelta with 13102 * 'wheel' event, making spin speed determination impossible. 13103 */ 13104 s.mousewheel.event = (navigator.userAgent.indexOf('firefox') > -1) ? 13105 'DOMMouseScroll' : 13106 isEventSupported() ? 13107 'wheel' : 'mousewheel'; 13108 } 13109 function handleMousewheel(e) { 13110 if (e.originalEvent) e = e.originalEvent; //jquery fix 13111 var delta = 0; 13112 var rtlFactor = s.rtl ? -1 : 1; 13113 13114 var data = normalizeWheel( e ); 13115 13116 if (s.params.mousewheelForceToAxis) { 13117 if (s.isHorizontal()) { 13118 if (Math.abs(data.pixelX) > Math.abs(data.pixelY)) delta = data.pixelX * rtlFactor; 13119 else return; 13120 } 13121 else { 13122 if (Math.abs(data.pixelY) > Math.abs(data.pixelX)) delta = data.pixelY; 13123 else return; 13124 } 13125 } 13126 else { 13127 delta = Math.abs(data.pixelX) > Math.abs(data.pixelY) ? - data.pixelX * rtlFactor : - data.pixelY; 13128 } 13129 13130 if (delta === 0) return; 13131 13132 if (s.params.mousewheelInvert) delta = -delta; 13133 13134 if (!s.params.freeMode) { 13135 if ((new window.Date()).getTime() - s.mousewheel.lastScrollTime > 60) { 13136 if (delta < 0) { 13137 if ((!s.isEnd || s.params.loop) && !s.animating) { 13138 s.slideNext(); 13139 s.emit('onScroll', s, e); 13140 } 13141 else if (s.params.mousewheelReleaseOnEdges) return true; 13142 } 13143 else {
13144 if ((!s.isBeginning || s.params.loop) && !s.animating) { 13145 s.slidePrev(); 13146 s.emit('onScroll', s, e); 13147 } 13148 else if (s.params.mousewheelReleaseOnEdges) return true; 13149 } 13150 } 13151 s.mousewheel.lastScrollTime = (new window.Date()).getTime(); 13152 13153 } 13154 else { 13155 //Freemode or scrollContainer: 13156 var position = s.getWrapperTranslate() + delta * s.params.mousewheelSensitivity; 13157 var wasBeginning = s.isBeginning, 13158 wasEnd = s.isEnd; 13159 13160 if (position >= s.minTranslate()) position = s.minTranslate(); 13161 if (position <= s.maxTranslate()) position = s.maxTranslate(); 13162 13163 s.setWrapperTransition(0); 13164 s.setWrapperTranslate(position); 13165 s.updateProgress(); 13166 s.updateActiveIndex(); 13167 13168 if (!wasBeginning && s.isBeginning || !wasEnd && s.isEnd) { 13169 s.updateClasses(); 13170 } 13171 13172 if (s.params.freeModeSticky) { 13173 clearTimeout(s.mousewheel.timeout); 13174 s.mousewheel.timeout = setTimeout(function () { 13175 s.slideReset(); 13176 }, 300); 13177 } 13178 else { 13179 if (s.params.lazyLoading && s.lazy) { 13180 s.lazy.load(); 13181 } 13182 } 13183 // Emit event 13184 s.emit('onScroll', s, e); 13185 13186 // Stop autoplay 13187 if (s.params.autoplay && s.params.autoplayDisableOnInteraction) s.stopAutoplay(); 13188 13189 // Return page scroll on edge positions 13190 if (position === 0 || position === s.maxTranslate()) return; 13191 } 13192 13193 if (e.preventDefault) e.preventDefault(); 13194 else e.returnValue = false; 13195 return false; 13196 } 13197 s.disableMousewheelControl = function () { 13198 if (!s.mousewheel.event) return false; 13199 var target = s.container; 13200 if (s.params.mousewheelEventsTarged !== 'container') { 13201 target = $(s.params.mousewheelEventsTarged); 13202 } 13203 target.off(s.mousewheel.event, handleMousewheel); 13204 s.params.mousewheelControl = false; 13205 return true; 13206 }; 13207 13208 s.enableMousewheelControl = function () { 13209 if (!s.mousewheel.event) return false; 13210 var target = s.container; 13211 if (s.params.mousewheelEventsTarged !== 'container') { 13212 target = $(s.params.mousewheelEventsTarged); 13213 } 13214 target.on(s.mousewheel.event, handleMousewheel); 13215 s.params.mousewheelControl = true; 13216 return true; 13217 }; 13218 13219 13220 /*========================= 13221 Parallax 13222 ===========================*/ 13223 function setParallaxTransform(el, progress) { 13224 el = $(el); 13225 var p, pX, pY; 13226 var rtlFactor = s.rtl ? -1 : 1; 13227 13228 p = el.attr('data-swiper-parallax') || '0'; 13229 pX = el.attr('data-swiper-parallax-x'); 13230 pY = el.attr('data-swiper-parallax-y'); 13231 if (pX || pY) { 13232 pX = pX || '0'; 13233 pY = pY || '0'; 13234 } 13235 else { 13236 if (s.isHorizontal()) { 13237 pX = p; 13238 pY = '0'; 13239 } 13240 else { 13241 pY = p; 13242 pX = '0'; 13243 } 13244 } 13245 13246 if ((pX).indexOf('%') >= 0) { 13247 pX = parseInt(pX, 10) * progress * rtlFactor + '%'; 13248 } 13249 else { 13250 pX = pX * progress * rtlFactor + 'px' ; 13251 } 13252 if ((pY).indexOf('%') >= 0) { 13253 pY = parseInt(pY, 10) * progress + '%'; 13254 } 13255 else { 13256 pY = pY * progress + 'px' ; 13257 } 13258 13259 el.transform('translate3d(' + pX + ', ' + pY + ',0px)'); 13260 } 13261 s.parallax = { 13262 setTranslate: function () { 13263 s.container.children('[data-swiper-parallax], [data-swiper-parallax-x], [data-swiper-parallax-y]').each(function(){ 13264 setParallaxTransform(this, s.progress); 13265 13266 }); 13267 s.slides.each(function () { 13268 var slide = $(this); 13269 slide.find('[data-swiper-parallax], [data-swiper-parallax-x], [data-swiper-parallax-y]').each(function () { 13270 var progress = Math.min(Math.max(slide[0].progress, -1), 1); 13271 setParallaxTransform(this, progress); 13272 }); 13273 }); 13274 }, 13275 setTransition: function (duration) { 13276 if (typeof duration === 'undefined') duration = s.params.speed; 13277 s.container.find('[data-swiper-parallax], [data-swiper-parallax-x], [data-swiper-parallax-y]').each(function(){ 13278 var el = $(this); 13279 var parallaxDuration = parseInt(el.attr('data-swiper-parallax-duration'), 10) || duration; 13280 if (duration === 0) parallaxDuration = 0; 13281 el.transition(parallaxDuration); 13282 }); 13283 } 13284 }; 13285 13286 13287 /*========================= 13288 Zoom 13289 ===========================*/ 13290 s.zoom = { 13291 // "Global" Props 13292 scale: 1, 13293 currentScale: 1, 13294 isScaling: false, 13295 gesture: { 13296 slide: undefined, 13297 slideWidth: undefined, 13298 slideHeight: undefined, 13299 image: undefined, 13300 imageWrap: undefined, 13301 zoomMax: s.params.zoomMax 13302 }, 13303 image: { 13304 isTouched: undefined, 13305 isMoved: undefined, 13306 currentX: undefined, 13307 currentY: undefined, 13308 minX: undefined, 13309 minY: undefined, 13310 maxX: undefined, 13311 maxY: undefined, 13312 width: undefined, 13313 height: undefined, 13314 startX: undefined, 13315 startY: undefined, 13316 touchesStart: {}, 13317 touchesCurrent: {} 13318 }, 13319 velocity: { 13320 x: undefined, 13321 y: undefined, 13322 prevPositionX: undefined, 13323 prevPositionY: undefined, 13324 prevTime: undefined 13325 }, 13326 // Calc Scale From Multi-touches 13327 getDistanceBetweenTouches: function (e) { 13328 if (e.targetTouches.length < 2) return 1; 13329 var x1 = e.targetTouches[0].pageX, 13330 y1 = e.targetTouches[0].pageY, 13331 x2 = e.targetTouches[1].pageX, 13332 y2 = e.targetTouches[1].pageY; 13333 var distance = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)); 13334 return distance; 13335 }, 13336 // Events 13337 onGestureStart: function (e) { 13338 var z = s.zoom; 13339 if (!s.support.gestures) { 13340 if (e.type !== 'touchstart' || e.type === 'touchstart' && e.targetTouches.length < 2) { 13341 return; 13342 } 13343 z.gesture.scaleStart = z.getDistanceBetweenTouches(e); 13344 } 13345 if (!z.gesture.slide || !z.gesture.slide.length) { 13346 z.gesture.slide = $(this); 13347 if (z.gesture.slide.length === 0) z.gesture.slide = s.slides.eq(s.activeIndex); 13348 z.gesture.image = z.gesture.slide.find('img, svg, canvas'); 13349 z.gesture.imageWrap = z.gesture.image.parent('.' + s.params.zoomContainerClass); 13350 z.gesture.zoomMax = z.gesture.imageWrap.attr('data-swiper-zoom') || s.params.zoomMax ; 13351 if (z.gesture.imageWrap.length === 0) { 13352 z.gesture.image = undefined; 13353 return; 13354 } 13355 } 13356 z.gesture.image.transition(0); 13357 z.isScaling = true; 13358 }, 13359 onGestureChange: function (e) { 13360 var z = s.zoom; 13361 if (!s.support.gestures) { 13362 if (e.type !== 'touchmove' || e.type === 'touchmove' && e.targetTouches.length < 2) { 13363 return; 13364 } 13365 z.gesture.scaleMove = z.getDistanceBetweenTouches(e); 13366 } 13367 if (!z.gesture.image || z.gesture.image.length === 0) return; 13368 if (s.support.gestures) { 13369 z.scale = e.scale * z.currentScale; 13370 } 13371 else { 13372 z.scale = (z.gesture.scaleMove / z.gesture.scaleStart) * z.currentScale; 13373 } 13374 if (z.scale > z.gesture.zoomMax) { 13375 z.scale = z.gesture.zoomMax - 1 + Math.pow((z.scale - z.gesture.zoomMax + 1), 0.5); 13376 } 13377 if (z.scale < s.params.zoomMin) { 13378 z.scale = s.params.zoomMin + 1 - Math.pow((s.params.zoomMin - z.scale + 1), 0.5); 13379 }
13380 z.gesture.image.transform('translate3d(0,0,0) scale(' + z.scale + ')'); 13381 }, 13382 onGestureEnd: function (e) { 13383 var z = s.zoom; 13384 if (!s.support.gestures) { 13385 if (e.type !== 'touchend' || e.type === 'touchend' && e.changedTouches.length < 2) { 13386 return; 13387 } 13388 } 13389 if (!z.gesture.image || z.gesture.image.length === 0) return; 13390 z.scale = Math.max(Math.min(z.scale, z.gesture.zoomMax), s.params.zoomMin); 13391 z.gesture.image.transition(s.params.speed).transform('translate3d(0,0,0) scale(' + z.scale + ')'); 13392 z.currentScale = z.scale; 13393 z.isScaling = false; 13394 if (z.scale === 1) z.gesture.slide = undefined; 13395 }, 13396 onTouchStart: function (s, e) { 13397 var z = s.zoom; 13398 if (!z.gesture.image || z.gesture.image.length === 0) return; 13399 if (z.image.isTouched) return; 13400 if (s.device.os === 'android') e.preventDefault(); 13401 z.image.isTouched = true; 13402 z.image.touchesStart.x = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.pageX; 13403 z.image.touchesStart.y = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.pageY; 13404 }, 13405 onTouchMove: function (e) { 13406 var z = s.zoom; 13407 if (!z.gesture.image || z.gesture.image.length === 0) return; 13408 s.allowClick = false; 13409 if (!z.image.isTouched || !z.gesture.slide) return; 13410 13411 if (!z.image.isMoved) { 13412 z.image.width = z.gesture.image[0].offsetWidth; 13413 z.image.height = z.gesture.image[0].offsetHeight; 13414 z.image.startX = s.getTranslate(z.gesture.imageWrap[0], 'x') || 0; 13415 z.image.startY = s.getTranslate(z.gesture.imageWrap[0], 'y') || 0; 13416 z.gesture.slideWidth = z.gesture.slide[0].offsetWidth; 13417 z.gesture.slideHeight = z.gesture.slide[0].offsetHeight; 13418 z.gesture.imageWrap.transition(0); 13419 if (s.rtl) z.image.startX = -z.image.startX; 13420 if (s.rtl) z.image.startY = -z.image.startY; 13421 } 13422 // Define if we need image drag 13423 var scaledWidth = z.image.width * z.scale; 13424 var scaledHeight = z.image.height * z.scale; 13425 13426 if (scaledWidth < z.gesture.slideWidth && scaledHeight < z.gesture.slideHeight) return; 13427 13428 z.image.minX = Math.min((z.gesture.slideWidth / 2 - scaledWidth / 2), 0); 13429 z.image.maxX = -z.image.minX; 13430 z.image.minY = Math.min((z.gesture.slideHeight / 2 - scaledHeight / 2), 0); 13431 z.image.maxY = -z.image.minY; 13432 13433 z.image.touchesCurrent.x = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.pageX; 13434 z.image.touchesCurrent.y = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY; 13435 13436 if (!z.image.isMoved && !z.isScaling) { 13437 if (s.isHorizontal() && 13438 (Math.floor(z.image.minX) === Math.floor(z.image.startX) && z.image.touchesCurrent.x < z.image.touchesStart.x) || 13439 (Math.floor(z.image.maxX) === Math.floor(z.image.startX) && z.image.touchesCurrent.x > z.image.touchesStart.x) 13440 ) { 13441 z.image.isTouched = false; 13442 return; 13443 } 13444 else if (!s.isHorizontal() && 13445 (Math.floor(z.image.minY) === Math.floor(z.image.startY) && z.image.touchesCurrent.y < z.image.touchesStart.y) || 13446 (Math.floor(z.image.maxY) === Math.floor(z.image.startY) && z.image.touchesCurrent.y > z.image.touchesStart.y) 13447 ) { 13448 z.image.isTouched = false; 13449 return; 13450 } 13451 } 13452 e.preventDefault(); 13453 e.stopPropagation(); 13454 13455 z.image.isMoved = true; 13456 z.image.currentX = z.image.touchesCurrent.x - z.image.touchesStart.x + z.image.startX; 13457 z.image.currentY = z.image.touchesCurrent.y - z.image.touchesStart.y + z.image.startY; 13458 13459 if (z.image.currentX < z.image.minX) { 13460 z.image.currentX = z.image.minX + 1 - Math.pow((z.image.minX - z.image.currentX + 1), 0.8); 13461 } 13462 if (z.image.currentX > z.image.maxX) { 13463 z.image.currentX = z.image.maxX - 1 + Math.pow((z.image.currentX - z.image.maxX + 1), 0.8); 13464 } 13465 13466 if (z.image.currentY < z.image.minY) { 13467 z.image.currentY = z.image.minY + 1 - Math.pow((z.image.minY - z.image.currentY + 1), 0.8); 13468 } 13469 if (z.image.currentY > z.image.maxY) { 13470 z.image.currentY = z.image.maxY - 1 + Math.pow((z.image.currentY - z.image.maxY + 1), 0.8); 13471 } 13472 13473 //Velocity 13474 if (!z.velocity.prevPositionX) z.velocity.prevPositionX = z.image.touchesCurrent.x; 13475 if (!z.velocity.prevPositionY) z.velocity.prevPositionY = z.image.touchesCurrent.y; 13476 if (!z.velocity.prevTime) z.velocity.prevTime = Date.now(); 13477 z.velocity.x = (z.image.touchesCurrent.x - z.velocity.prevPositionX) / (Date.now() - z.velocity.prevTime) / 2; 13478 z.velocity.y = (z.image.touchesCurrent.y - z.velocity.prevPositionY) / (Date.now() - z.velocity.prevTime) / 2; 13479 if (Math.abs(z.image.touchesCurrent.x - z.velocity.prevPositionX) < 2) z.velocity.x = 0; 13480 if (Math.abs(z.image.touchesCurrent.y - z.velocity.prevPositionY) < 2) z.velocity.y = 0; 13481 z.velocity.prevPositionX = z.image.touchesCurrent.x; 13482 z.velocity.prevPositionY = z.image.touchesCurrent.y; 13483 z.velocity.prevTime = Date.now(); 13484 13485 z.gesture.imageWrap.transform('translate3d(' + z.image.currentX + 'px, ' + z.image.currentY + 'px,0)'); 13486 }, 13487 onTouchEnd: function (s, e) { 13488 var z = s.zoom; 13489 if (!z.gesture.image || z.gesture.image.length === 0) return; 13490 if (!z.image.isTouched || !z.image.isMoved) { 13491 z.image.isTouched = false;
13492 z.image.isMoved = false; 13493 return; 13494 } 13495 z.image.isTouched = false; 13496 z.image.isMoved = false; 13497 var momentumDurationX = 300; 13498 var momentumDurationY = 300; 13499 var momentumDistanceX = z.velocity.x * momentumDurationX; 13500 var newPositionX = z.image.currentX + momentumDistanceX; 13501 var momentumDistanceY = z.velocity.y * momentumDurationY; 13502 var newPositionY = z.image.currentY + momentumDistanceY; 13503 13504 //Fix duration 13505 if (z.velocity.x !== 0) momentumDurationX = Math.abs((newPositionX - z.image.currentX) / z.velocity.x); 13506 if (z.velocity.y !== 0) momentumDurationY = Math.abs((newPositionY - z.image.currentY) / z.velocity.y); 13507 var momentumDuration = Math.max(momentumDurationX, momentumDurationY); 13508 13509 z.image.currentX = newPositionX; 13510 z.image.currentY = newPositionY; 13511 13512 // Define if we need image drag 13513 var scaledWidth = z.image.width * z.scale; 13514 var scaledHeight = z.image.height * z.scale; 13515 z.image.minX = Math.min((z.gesture.slideWidth / 2 - scaledWidth / 2), 0); 13516 z.image.maxX = -z.image.minX; 13517 z.image.minY = Math.min((z.gesture.slideHeight / 2 - scaledHeight / 2), 0); 13518 z.image.maxY = -z.image.minY; 13519 z.image.currentX = Math.max(Math.min(z.image.currentX, z.image.maxX), z.image.minX); 13520 z.image.currentY = Math.max(Math.min(z.image.currentY, z.image.maxY), z.image.minY); 13521 13522 z.gesture.imageWrap.transition(momentumDuration).transform('translate3d(' + z.image.currentX + 'px, ' + z.image.currentY + 'px,0)'); 13523 }, 13524 onTransitionEnd: function (s) { 13525 var z = s.zoom; 13526 if (z.gesture.slide && s.previousIndex !== s.activeIndex) { 13527 z.gesture.image.transform('translate3d(0,0,0) scale(1)'); 13528 z.gesture.imageWrap.transform('translate3d(0,0,0)'); 13529 z.gesture.slide = z.gesture.image = z.gesture.imageWrap = undefined; 13530 z.scale = z.currentScale = 1; 13531 } 13532 }, 13533 // Toggle Zoom 13534 toggleZoom: function (s, e) { 13535 var z = s.zoom; 13536 if (!z.gesture.slide) { 13537 z.gesture.slide = s.clickedSlide ? $(s.clickedSlide) : s.slides.eq(s.activeIndex); 13538 z.gesture.image = z.gesture.slide.find('img, svg, canvas'); 13539 z.gesture.imageWrap = z.gesture.image.parent('.' + s.params.zoomContainerClass); 13540 } 13541 if (!z.gesture.image || z.gesture.image.length === 0) return; 13542 13543 var touchX, touchY, offsetX, offsetY, diffX, diffY, translateX, translateY, imageWidth, imageHeight, scaledWidth, scaledHeight, translateMinX, translateMinY, translateMaxX, translateMaxY, slideWidth, slideHeight; 13544 13545 if (typeof z.image.touchesStart.x === 'undefined' && e) { 13546 touchX = e.type === 'touchend' ? e.changedTouches[0].pageX : e.pageX; 13547 touchY = e.type === 'touchend' ? e.changedTouches[0].pageY : e.pageY; 13548 } 13549 else { 13550 touchX = z.image.touchesStart.x; 13551 touchY = z.image.touchesStart.y; 13552 } 13553 13554 if (z.scale && z.scale !== 1) { 13555 // Zoom Out 13556 z.scale = z.currentScale = 1; 13557 z.gesture.imageWrap.transition(300).transform('translate3d(0,0,0)'); 13558 z.gesture.image.transition(300).transform('translate3d(0,0,0) scale(1)'); 13559 z.gesture.slide = undefined; 13560 } 13561 else { 13562 // Zoom In 13563 z.scale = z.currentScale = z.gesture.imageWrap.attr('data-swiper-zoom') || s.params.zoomMax; 13564 if (e) { 13565 slideWidth = z.gesture.slide[0].offsetWidth; 13566 slideHeight = z.gesture.slide[0].offsetHeight; 13567 offsetX = z.gesture.slide.offset().left; 13568 offsetY = z.gesture.slide.offset().top; 13569 diffX = offsetX + slideWidth/2 - touchX; 13570 diffY = offsetY + slideHeight/2 - touchY; 13571 13572 imageWidth = z.gesture.image[0].offsetWidth; 13573 imageHeight = z.gesture.image[0].offsetHeight; 13574 scaledWidth = imageWidth * z.scale; 13575 scaledHeight = imageHeight * z.scale; 13576 13577 translateMinX = Math.min((slideWidth / 2 - scaledWidth / 2), 0); 13578 translateMinY = Math.min((slideHeight / 2 - scaledHeight / 2), 0); 13579 translateMaxX = -translateMinX; 13580 translateMaxY = -translateMinY; 13581 13582 translateX = diffX * z.scale; 13583 translateY = diffY * z.scale; 13584 13585 if (translateX < translateMinX) { 13586 translateX = translateMinX; 13587 } 13588 if (translateX > translateMaxX) { 13589 translateX = translateMaxX; 13590 } 13591 13592 if (translateY < translateMinY) { 13593 translateY = translateMinY; 13594 } 13595 if (translateY > translateMaxY) { 13596 translateY = translateMaxY; 13597 } 13598 } 13599 else { 13600 translateX = 0; 13601 translateY = 0; 13602 } 13603 z.gesture.imageWrap.transition(300).transform('translate3d(' + translateX + 'px, ' + translateY + 'px,0)'); 13604 z.gesture.image.transition(300).transform('translate3d(0,
136040,0) scale(' + z.scale + ')'); 13605 } 13606 }, 13607 // Attach/Detach Events 13608 attachEvents: function (detach) { 13609 var action = detach ? 'off' : 'on'; 13610 13611 if (s.params.zoom) { 13612 var target = s.slides; 13613 var passiveListener = s.touchEvents.start === 'touchstart' && s.support.passiveListener && s.params.passiveListeners ? {passive: true, capture: false} : false; 13614 // Scale image 13615 if (s.support.gestures) { 13616 s.slides[action]('gesturestart', s.zoom.onGestureStart, passiveListener); 13617 s.slides[action]('gesturechange', s.zoom.onGestureChange, passiveListener); 13618 s.slides[action]('gestureend', s.zoom.onGestureEnd, passiveListener); 13619 } 13620 else if (s.touchEvents.start === 'touchstart') { 13621 s.slides[action](s.touchEvents.start, s.zoom.onGestureStart, passiveListener); 13622 s.slides[action](s.touchEvents.move, s.zoom.onGestureChange, passiveListener); 13623 s.slides[action](s.touchEvents.end, s.zoom.onGestureEnd, passiveListener); 13624 } 13625 13626 // Move image 13627 s[action]('touchStart', s.zoom.onTouchStart); 13628 s.slides.each(function (index, slide){ 13629 if ($(slide).find('.' + s.params.zoomContainerClass).length > 0) { 13630 $(slide)[action](s.touchEvents.move, s.zoom.onTouchMove); 13631 } 13632 }); 13633 s[action]('touchEnd', s.zoom.onTouchEnd); 13634 13635 // Scale Out 13636 s[action]('transitionEnd', s.zoom.onTransitionEnd); 13637 if (s.params.zoomToggle) { 13638 s.on('doubleTap', s.zoom.toggleZoom); 13639 } 13640 } 13641 }, 13642 init: function () { 13643 s.zoom.attachEvents(); 13644 }, 13645 destroy: function () { 13646 s.zoom.attachEvents(true); 13647 } 13648 }; 13649 13650 13651 /*========================= 13652 Plugins API. Collect all and init all plugins 13653 ===========================*/ 13654 s._plugins = []; 13655 for (var plugin in s.plugins) { 13656 var p = s.plugins[plugin](s, s.params[plugin]); 13657 if (p) s._plugins.push(p); 13658 } 13659 // Method to call all plugins event/method 13660 s.callPlugins = function (eventName) { 13661 for (var i = 0; i < s._plugins.length; i++) { 13662 if (eventName in s._plugins[i]) { 13663 s._plugins[i][eventName](arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]); 13664 } 13665 } 13666 }; 13667 13668 13669 /*========================= 13670 Events/Callbacks/Plugins Emitter 13671 ===========================*/ 13672 function normalizeEventName (eventName) { 13673 if (eventName.indexOf('on') !== 0) { 13674 if (eventName[0] !== eventName[0].toUpperCase()) { 13675 eventName = 'on' + eventName[0].toUpperCase() + eventName.substring(1); 13676 } 13677 else { 13678 eventName = 'on' + eventName; 13679 } 13680 } 13681 return eventName; 13682 } 13683 s.emitterEventListeners = { 13684 13685 }; 13686 s.emit = function (eventName) { 13687 // Trigger callbacks 13688 if (s.params[eventName]) { 13689 s.params[eventName](arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]); 13690 } 13691 var i; 13692 // Trigger events 13693 if (s.emitterEventListeners[eventName]) { 13694 for (i = 0; i < s.emitterEventListeners[eventName].length; i++) { 13695 s.emitterEventListeners[eventName][i](arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]); 13696 } 13697 } 13698 // Trigger plugins 13699 if (s.callPlugins) s.callPlugins(eventName, arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]); 13700 }; 13701 s.on = function (eventName, handler) { 13702 eventName = normalizeEventName(eventName); 13703 if (!s.emitterEventListeners[eventName]) s.emitterEventListeners[eventName] = []; 13704 s.emitterEventListeners[eventName].push(handler); 13705 return s; 13706 }; 13707 s.off = function (eventName, handler) { 13708 var i; 13709 eventName = normalizeEventName(eventName); 13710 if (typeof handler === 'undefined') { 13711 // Remove all handlers for such event 13712 s.emitterEventListeners[eventName] = []; 13713 return s; 13714 } 13715 if (!s.emitterEventListeners[eventName] || s.emitterEventListeners[eventName].length === 0) return; 13716 for (i = 0; i < s.emitterEventListeners[eventName].length; i++) { 13717 if(s.emitterEventListeners[eventName][i] === handler) s.emitterEventListeners[eventName].splice(i, 1); 13718 } 13719 return s; 13720 }; 13721 s.once = function (eventName, handler) { 13722 eventName = normalizeEventName(eventName); 13723 var _handler = function () { 13724 handler(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4]); 13725 s.off(eventName, _handler); 13726 }; 13727 s.on(eventName, _handler); 13728 return s; 13729 }; 13730 13731 13732 // Accessibility tools 13733 s.a11y = { 13734 makeFocusable: function ($el) { 13735 $el.attr('tabIndex', '0'); 13736 return $el; 13737 }, 13738 addRole: function ($el, role) { 13739 $el.attr('role', role); 13740 return $el; 13741 }, 13742 13743 addLabel: function ($el, label) { 13744 $el.attr('aria-label', label); 13745 return $el; 13746 }, 13747 13748 disable: function ($el) { 13749 $el.attr('aria-disabled', true); 13750 return $el; 13751 }, 13752 13753 enable: function ($el) { 13754 $el.attr('aria-disabled', false); 13755 return $el; 13756 }, 13757 13758 onEnterKey: function (event) { 13759 if (event.keyCode !== 13) return; 13760 if ($(event.target).is(s.params.nextButton)) { 13761 s.onClickNext(event); 13762 if (s.isEnd) { 13763 s.a11y.notify(s.params.lastSlideMessage); 13764 } 13765 else { 13766 s.a11y.notify(s.params.nextSlideMessage); 13767 } 13768 } 13769 else if ($(event.target).is(s.params.prevButton)) { 13770 s.onClickPrev(event); 13771 if (s.isBeginning) { 13772 s.a11y.notify(s.params.firstSlideMessage); 13773 } 13774 else { 13775 s.a11y.notify(s.params.prevSlideMessage); 13776 } 13777 } 13778 if ($(event.target).is('.' + s.params.bulletClass)) { 13779 $(event.target)[0].click(); 13780 } 13781 }, 13782 13783 liveRegion: $('<span class="' + s.params.notificationClass + '" aria-live="assertive" aria-atomic="true"></span>'), 13784 13785 notify: function (message) { 13786 var notification = s.a11y.liveRegion; 13787 if (notification.length === 0) return; 13788 notification.html(''); 13789 notification.html(message); 13790 }, 13791 init: function () { 13792 // Setup accessibility 13793 if (s.params.nextButton && s.nextButton && s.nextButton.length > 0) { 13794 s.a11y.makeFocusable(s.nextButton); 13795 s.a11y.addRole(s.nextButton, 'button'); 13796 s.a11y.addLabel(s.nextButton, s.params.nextSlideMessage); 13797 } 13798 if (s.params.prevButton && s.prevButton && s.prevButton.length > 0) { 13799 s.a11y.makeFocusable(s.prevButton); 13800 s.a11y.addRole(s.prevButton, 'button'); 13801 s.a11y.addLabel(s.prevButton, s.params.prevSlideMessage); 13802 } 13803 13804 $(s.container).append(s.a11y.liveRegion); 13805 }, 13806 initPagination: function () { 13807 if (s.params.pagination && s.params.paginationClickable && s.bullets && s.bullets.length) { 13808 s.bullets.each(function () { 13809 var bullet = $(this); 13810 s.a11y.makeFocusable(bullet); 13811 s.a11y.addRole(bullet, 'button'); 13812 s.a11y.addLabel(bullet, s.params.paginationBulletMessage.replace(/{{index}}/, bullet.index() + 1)); 13813 }); 13814 } 13815 }, 13816 destroy: function () { 13817 if (s.a11y.liveRegion && s.a11y.liveRegion.length > 0) s.a11y.liveRegion.remove(); 13818 } 13819 }; 13820 13821 13822 /*========================= 13823 Init/Destroy 13824 ===========================*/ 13825 s.init = function () { 13826 if (s.params.loop) s.createLoop(); 13827 s.updateContainerSize(); 13828 s.updateSlidesSize(); 13829 s.updatePagination(); 13830 if (s.params.scrollbar && s.scrollbar) { 13831 s.scrollbar.set(); 13832 if (s.params.scrollbarDraggable) { 13833 s.scrollbar.enableDraggable(); 13834 } 13835 } 13836 if (s.params.effect !== 'slide' && s.effects[s.params.effect]) { 13837 if (!s.params.loop) s.updateProgress(); 13838 s.effects[s.params.effect].setTranslate(); 13839 } 13840 if (s.params.loop) { 13841 s.slideTo(s.params.initialSlide + s.loopedSlides, 0, s.params.runCallbacksOnInit); 13842 } 13843 else { 13844 s.slideTo(s.params.initialSlide, 0, s.params.runCallbacksOnInit); 13845 if (s.params.initialSlide === 0) { 13846 if (s.parallax && s.params.parallax) s.parallax.setTranslate(); 13847 if (s.lazy && s.params.lazyLoading) { 13848 s.lazy.load(); 13849 s.lazy.initialImageLoaded = true; 13850 } 13851 } 13852 } 13853 s.attachEvents(); 13854 if (s.params.observer && s.support.observer) {
13855 s.initObservers(); 13856 } 13857 if (s.params.preloadImages && !s.params.lazyLoading) { 13858 s.preloadImages(); 13859 } 13860 if (s.params.zoom && s.zoom) { 13861 s.zoom.init(); 13862 } 13863 if (s.params.autoplay) { 13864 s.startAutoplay(); 13865 } 13866 if (s.params.keyboardControl) { 13867 if (s.enableKeyboardControl) s.enableKeyboardControl(); 13868 } 13869 if (s.params.mousewheelControl) { 13870 if (s.enableMousewheelControl) s.enableMousewheelControl(); 13871 } 13872 // Deprecated hashnavReplaceState changed to replaceState for use in hashnav and history 13873 if (s.params.hashnavReplaceState) { 13874 s.params.replaceState = s.params.hashnavReplaceState; 13875 } 13876 if (s.params.history) { 13877 if (s.history) s.history.init(); 13878 } 13879 if (s.params.hashnav) { 13880 if (s.hashnav) s.hashnav.init(); 13881 } 13882 if (s.params.a11y && s.a11y) s.a11y.init(); 13883 s.emit('onInit', s); 13884 }; 13885 13886 // Cleanup dynamic styles 13887 s.cleanupStyles = function () { 13888 // Container 13889 s.container.removeClass(s.classNames.join(' ')).removeAttr('style'); 13890 13891 // Wrapper 13892 s.wrapper.removeAttr('style'); 13893 13894 // Slides 13895 if (s.slides && s.slides.length) { 13896 s.slides 13897 .removeClass([ 13898 s.params.slideVisibleClass, 13899 s.params.slideActiveClass, 13900 s.params.slideNextClass, 13901 s.params.slidePrevClass 13902 ].join(' ')) 13903 .removeAttr('style') 13904 .removeAttr('data-swiper-column') 13905 .removeAttr('data-swiper-row'); 13906 } 13907 13908 // Pagination/Bullets 13909 if (s.paginationContainer && s.paginationContainer.length) { 13910 s.paginationContainer.removeClass(s.params.paginationHiddenClass); 13911 } 13912 if (s.bullets && s.bullets.length) { 13913 s.bullets.removeClass(s.params.bulletActiveClass); 13914 } 13915 13916 // Buttons 13917 if (s.params.prevButton) $(s.params.prevButton).removeClass(s.params.buttonDisabledClass); 13918 if (s.params.nextButton) $(s.params.nextButton).removeClass(s.params.buttonDisabledClass); 13919 13920 // Scrollbar 13921 if (s.params.scrollbar && s.scrollbar) { 13922 if (s.scrollbar.track && s.scrollbar.track.length) s.scrollbar.track.removeAttr('style'); 13923 if (s.scrollbar.drag && s.scrollbar.drag.length) s.scrollbar.drag.removeAttr('style'); 13924 } 13925 }; 13926 13927 // Destroy 13928 s.destroy = function (deleteInstance, cleanupStyles) { 13929 // Detach evebts 13930 s.detachEvents(); 13931 // Stop autoplay 13932 s.stopAutoplay(); 13933 // Disable draggable 13934 if (s.params.scrollbar && s.scrollbar) { 13935 if (s.params.scrollbarDraggable) { 13936 s.scrollbar.disableDraggable(); 13937 } 13938 } 13939 // Destroy loop 13940 if (s.params.loop) { 13941 s.destroyLoop(); 13942 } 13943 // Cleanup styles 13944 if (cleanupStyles) { 13945 s.cleanupStyles(); 13946 } 13947 // Disconnect observer 13948 s.disconnectObservers(); 13949 13950 // Destroy zoom 13951 if (s.params.zoom && s.zoom) { 13952 s.zoom.destroy(); 13953 } 13954 // Disable keyboard/mousewheel 13955 if (s.params.keyboardControl) { 13956 if (s.disableKeyboardControl) s.disableKeyboardControl(); 13957 } 13958 if (s.params.mousewheelControl) { 13959 if (s.disableMousewheelControl) s.disableMousewheelControl(); 13960 } 13961 // Disable a11y 13962 if (s.params.a11y && s.a11y) s.a11y.destroy(); 13963 // Delete history popstate 13964 if (s.params.history && !s.params.replaceState) { 13965 window.removeEventListener('popstate', s.history.setHistoryPopState); 13966 } 13967 if (s.params.hashnav && s.hashnav) { 13968 s.hashnav.destroy(); 13969 } 13970 // Destroy callback 13971 s.emit('onDestroy'); 13972 // Delete instance 13973 if (deleteInstance !== false) s = null; 13974 }; 13975 13976 s.init(); 13977 13978 13979 13980 // Return swiper instance 13981 return s; 13982 }; 13983 13984 13985 /*================================================== 13986 Prototype 13987 ====================================================*/ 13988 Swiper.prototype = { 13989 isSafari: (function () { 13990 var ua = window.navigator.userAgent.toLowerCase(); 13991 return (ua.indexOf('safari') >= 0 && ua.indexOf('chrome') < 0 && ua.indexOf('android') < 0); 13992 })(),
13993 isUiWebView: /(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/i.test(window.navigator.userAgent), 13994 isArray: function (arr) { 13995 return Object.prototype.toString.apply(arr) === '[object Array]'; 13996 }, 13997 /*================================================== 13998 Browser 13999 ====================================================*/ 14000 browser: { 14001 ie: window.navigator.pointerEnabled || window.navigator.msPointerEnabled, 14002 ieTouch: (window.navigator.msPointerEnabled && window.navigator.msMaxTouchPoints > 1) || (window.navigator.pointerEnabled && window.navigator.maxTouchPoints > 1), 14003 lteIE9: (function() { 14004 // create temporary DIV 14005 var div = document.createElement('div'); 14006 // add content to tmp DIV which is wrapped into the IE HTML conditional statement 14007 div.innerHTML = '<!--[if lte IE 9]><i></i><![endif]-->'; 14008 // return true / false value based on what will browser render 14009 return div.getElementsByTagName('i').length === 1; 14010 })() 14011 }, 14012 /*================================================== 14013 Devices 14014 ====================================================*/ 14015 device: (function () { 14016 var ua = window.navigator.userAgent; 14017 var android = ua.match(/(Android);?[\s\/]+([\d.]+)?/); 14018 var ipad = ua.match(/(iPad).*OS\s([\d_]+)/); 14019 var ipod = ua.match(/(iPod)(.*OS\s([\d_]+))?/); 14020 var iphone = !ipad && ua.match(/(iPhone\sOS|iOS)\s([\d_]+)/); 14021 return { 14022 ios: ipad || iphone || ipod, 14023 android: android 14024 }; 14025 })(), 14026 /*================================================== 14027 Feature Detection 14028 ====================================================*/ 14029 support: { 14030 touch : (window.Modernizr && Modernizr.touch === true) || (function () { 14031 return !!(('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch); 14032 })(), 14033 14034 transforms3d : (window.Modernizr && Modernizr.csstransforms3d === true) || (function () { 14035 var div = document.createElement('div').style; 14036 return ('webkitPerspective' in div || 'MozPerspective' in div || 'OPerspective' in div || 'MsPerspective' in div || 'perspective' in div); 14037 })(), 14038 14039 flexbox: (function () { 14040 var div = document.createElement('div').style; 14041 var styles = ('alignItems webkitAlignItems webkitBoxAlign msFlexAlign mozBoxAlign webkitFlexDirection msFlexDirection mozBoxDirection mozBoxOrient webkitBoxDirection webkitBoxOrient').split(' '); 14042 for (var i = 0; i < styles.length; i++) { 14043 if (styles[i] in div) return true; 14044 } 14045 })(), 14046 14047 observer: (function () { 14048 return ('MutationObserver' in window || 'WebkitMutationObserver' in window); 14049 })(), 14050 14051 passiveListener: (function () { 14052 var supportsPassive = false; 14053 try { 14054 var opts = Object.defineProperty({}, 'passive', { 14055 get: function() { 14056 supportsPassive = true; 14057 } 14058 }); 14059 window.addEventListener('testPassiveListener', null, opts); 14060 } catch (e) {} 14061 return supportsPassive; 14062 })(), 14063 14064 gestures: (function () { 14065 return 'ongesturestart' in window; 14066 })() 14067 }, 14068 /*================================================== 14069 Plugins 14070 ====================================================*/ 14071 plugins: {} 14072 }; 14073 14074 14075 /*=========================== 14076 Get Dom libraries 14077 ===========================*/ 14078 var swiperDomPlugins = ['jQuery', 'Zepto', 'Dom7']; 14079 for (var i = 0; i < swiperDomPlugins.length; i++) { 14080 if (window[swiperDomPlugins[i]]) { 14081 addLibraryPlugin(window[swiperDomPlugins[i]]); 14082 } 14083 } 14084 // Required DOM Plugins 14085 var domLib; 14086 if (typeof Dom7 === 'undefined') { 14087 domLib = window.Dom7 || window.Zepto || window.jQuery; 14088 } 14089 else { 14090 domLib = Dom7; 14091 } 14092 14093 14094 /*=========================== 14095 Add .swiper plugin from Dom libraries 14096 ===========================*/ 14097 function addLibraryPlugin(lib) { 14098 lib.fn.swiper = function (params) { 14099 var firstInstance; 14100 lib(this).each(function () { 14101 var s = new Swiper(this, params); 14102 if (!firstInstance) firstInstance = s; 14103 }); 14104 return firstInstance; 14105 }; 14106 } 14107 14108 if (domLib) { 14109 if (!('transitionEnd' in domLib.fn)) { 14110 domLib.fn.transitionEnd = function (callback) {
14111 var events = ['webkitTransitionEnd', 'transitionend', 'oTransitionEnd', 'MSTransitionEnd', 'msTransitionEnd'], 14112 i, j, dom = this; 14113 function fireCallBack(e) { 14114 /*jshint validthis:true */ 14115 if (e.target !== this) return; 14116 callback.call(this, e); 14117 for (i = 0; i < events.length; i++) { 14118 dom.off(events[i], fireCallBack); 14119 } 14120 } 14121 if (callback) { 14122 for (i = 0; i < events.length; i++) { 14123 dom.on(events[i], fireCallBack); 14124 } 14125 } 14126 return this; 14127 }; 14128 } 14129 if (!('transform' in domLib.fn)) { 14130 domLib.fn.transform = function (transform) { 14131 for (var i = 0; i < this.length; i++) { 14132 var elStyle = this[i].style; 14133 elStyle.webkitTransform = elStyle.MsTransform = elStyle.msTransform = elStyle.MozTransform = elStyle.OTransform = elStyle.transform = transform; 14134 } 14135 return this; 14136 }; 14137 } 14138 if (!('transition' in domLib.fn)) { 14139 domLib.fn.transition = function (duration) { 14140 if (typeof duration !== 'string') { 14141 duration = duration + 'ms'; 14142 } 14143 for (var i = 0; i < this.length; i++) { 14144 var elStyle = this[i].style; 14145 elStyle.webkitTransitionDuration = elStyle.MsTransitionDuration = elStyle.msTransitionDuration = elStyle.MozTransitionDuration = elStyle.OTransitionDuration = elStyle.transitionDuration = duration; 14146 } 14147 return this; 14148 }; 14149 } 14150 if (!('outerWidth' in domLib.fn)) { 14151 domLib.fn.outerWidth = function (includeMargins) { 14152 if (this.length > 0) { 14153 if (includeMargins) 14154 return this[0].offsetWidth + parseFloat(this.css('margin-right')) + parseFloat(this.css('margin-left')); 14155 else 14156 return this[0].offsetWidth; 14157 } 14158 else return null; 14159 }; 14160 } 14161 } 14162 14163 14164 window.Swiper = Swiper; 14165})(); 14166 14167/*=========================== 14168Swiper AMD Export 14169===========================*/ 14170if (typeof(module) !== 'undefined') 14171{ 14172 module.exports = window.Swiper; 14173} 14174else if (typeof define === 'function' && define.amd) { 14175 define([], function () { 14176 'use strict'; 14177 return window.Swiper; 14178 }); 14179} 14180 14181//# sourceMappingURL=maps/swiper.jquery.js.map 14182 14183/* ------------------------------------------------------------------------ 14184 Class: prettyPhoto 14185 Use: Lightbox clone for jQuery 14186 Author: Stephane Caron (http://www.no-margin-for-errors.com) 14187 Version: 3.1.6 14188------------------------------------------------------------------------- */ 14189(function($) { 14190 $.prettyPhoto = {version: '3.1.6'}; 14191 14192 $.fn.prettyPhoto = function(pp_settings) { 14193 pp_settings = jQuery.extend({ 14194 hook: 'rel', /* the attribute tag to use for prettyPhoto hooks. default: 'rel'. For HTML5, use "data-rel" or similar. */ 14195 animation_speed: 'fast', /* fast/slow/normal */ 14196 ajaxcallback: function() {}, 14197 slideshow: 5000, /* false OR interval time in ms */ 14198 autoplay_slideshow: false, /* true/false */ 14199 opacity: 0.80, /* Value between 0 and 1 */ 14200 show_title: true, /* true/false */ 14201 allow_resize: true, /* Resize the photos bigger than viewport. true/false */ 14202 allow_expand: true, /* Allow the user to expand a resized image. true/false */ 14203 default_width: 500, 14204 default_height: 344, 14205 counter_separator_label: '/', /* The separator for the gallery counter 1 "of" 2 */ 14206 theme: 'pp_default', /* light_rounded / dark_rounded / light_square / dark_square / facebook */ 14207 horizontal_padding: 20, /* The padding on each side of the picture */ 14208 hideflash: false, /* Hides all the flash object on a page, set to TRUE if flash appears over prettyPhoto */ 14209 wmode: 'opaque', /* Set the flash wmode attribute */ 14210 autoplay: true, /* Automatically start videos: True/False */ 14211 modal: false, /* If set to true, only the close button will close the window */ 14212 deeplinking: true, /* Allow prettyPhoto to update the url to enable deeplinking. */ 14213 overlay_gallery: true, /* If set to true, a gallery will overlay the fullscreen image on mouse over */ 14214 overlay_gallery_max: 30, /* Maximum number of pictures in the overlay gallery */ 14215 keyboard_shortcuts: true, /* Set to false if you open forms inside prettyPhoto */ 14216 changepicturecallback: function(){}, /* Called everytime an item is shown/changed */ 14217 callback: function(){}, /* Called when prettyPhoto is closed */ 14218 ie6_fallback: true, 14219 markup: '<div class="pp_pic_holder"> \ 14220 <div class="ppt"> </div> \ 14221 <div class="pp_top"> \ 14222 <div class="pp_left"></div> \ 14223 <div class="pp_middle"></div> \ 14224 <div class="pp_right"></div> \ 14225 </div> \ 14226 <div class="pp_content_container"> \ 14227 <div class="pp_left"> \ 14228 <div class="pp_right"> \ 14229 <div class="pp_content"> \ 14230 <div class="pp_loaderIcon"></div> \ 14231 <div class="pp_fade"> \ 14232 <a href="#" class="pp_expand" title="Expand the image">Expand</a> \ 14233 <div class="pp_hoverContainer"> \ 14234 <a class="pp_next" href="#">next</a> \ 14235 <a class="pp_previous" href="#">previous</a> \ 14236 </div> \ 14237 <div id="pp_full_res"></div> \ 14238 <div class="pp_details"> \ 14239 <div class="pp_nav"> \ 14240 <a href="#" class="pp_arrow_previous">Previous</a> \ 14241 <p class="currentTextHolder">0/0</p> \ 14242 <a href="#" class="pp_arrow_next">Next</a> \ 14243 </div> \ 14244 <p class="pp_description"></p> \ 14245 <div class="pp_social">{pp_social}</div> \ 14246 <a class="pp_close" href="#">Close</a> \ 14247 </div> \ 14248 </div> \ 14249 </div> \ 14250 </div> \ 14251 </div> \ 14252 </div> \ 14253 <div class="pp_bottom"> \ 14254 <div class="pp_left"></div> \ 14255 <div class="pp_middle"></div> \ 14256 <div class="pp_right"></div> \ 14257 </div> \ 14258 </div> \ 14259 <div class="pp_overlay"></div>', 14260 gallery_markup: '<div class="pp_gallery"> \ 14261 <a href="#" class="pp_arrow_previous">Previous</a> \ 14262 <div> \ 14263 <ul> \ 14264 {gallery} \ 14265 </ul> \ 14266 </div> \ 14267 <a href="#" class="pp_arrow_next">Next</a> \ 14268 </div>', 14269 image_markup: '<img id="fullResImage" src="{path}" />', 14270 flash_markup: '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="{width}" height="{height}"><param name="wmode" value="{wmode}" /><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="movie" value="{path}" /><embed src="{path}" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="{width}" height="{height}" wmode="{wmode}"></embed></object>', 14271 quicktime_markup: '<object classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B" codebase="http://www.apple.com/qtactivex/qtplugin.cab" height="{height}" width="{width}"><param name="src" value="{path}"><param name="autoplay" value="{autoplay}"><param name="type" value="video/quicktime"><embed src="{path}" height="{height}" width="{width}" autoplay="{autoplay}" type="video/quicktime" pluginspage="http://www.apple.com/quicktime/download/"></embed></object>', 14272 iframe_markup: '<iframe src ="{path}" width="{width}" height="{height}" frameborder="no"></iframe>', 14273 inline_markup: '<div class="pp_inline">{content}</div>', 14274 custom_markup: '', 14275 social_tools: '<div class="twitter"><a href="http://twitter.com/share" class="twitter-share-button" data-count="none">Tweet</a><script type="text/javascript" src="http://platform.twitter.com/widgets.js"></script></div><div class="facebook"><iframe src="//www.facebook.com/plugins/like.php?locale=en_US&href={location_href}&layout=button_count&show_faces=true&width=500&action=like&font&colorscheme=light&height=23" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:500px; height:23px;" allowTransparency="true"></iframe></div>' /* html or false to disable */ 14276 }, pp_settings); 14277 14278 // Global variables accessible only by prettyPhoto 14279 var matchedObjects = this, percentBased = false, pp_dimensions, pp_open, 14280 14281 // prettyPhoto container specific 14282 pp_contentHeight, pp_contentWidth, pp_containerHeight, pp_containerWidth, 14283 14284 // Window size 14285 windowHeight = $(window).height(), windowWidth = $(window).width(), 14286 14287 // Global elements 14288 pp_slideshow; 14289 14290 doresize = true, scroll_pos = _get_scroll(); 14291 14292 // Window/Keyboard events 14293 $(window).unbind('resize.prettyphoto').bind('resize.prettyphoto',function(){ _center_overlay(); _resize_overlay(); }); 14294 14295 if(pp_settings.keyboard_shortcuts) { 14296 $(document).unbind('keydown.prettyphoto').bind('keydown.prettyphoto',function(e){ 14297 if(typeof $pp_pic_holder != 'undefined'){ 14298 if($pp_pic_holder.is(':visible')){ 14299 switch(e.keyCode){ 14300 case 37: 14301 $.prettyPhoto.changePage('previous'); 14302 e.preventDefault(); 14303 break; 14304 case 39: 14305 $.prettyPhoto.changePage('next'); 14306 e.preventDefault(); 14307 break; 14308 case 27: 14309 if(!settings.modal) 14310 $.prettyPhoto.close(); 14311 e.preventDefault(); 14312 break; 14313 }; 14314 // return false;
14315 }; 14316 }; 14317 }); 14318 }; 14319 14320 /** 14321 * Initialize prettyPhoto. 14322 */ 14323 $.prettyPhoto.initialize = function() { 14324 14325 settings = pp_settings; 14326 14327 if(settings.theme == 'pp_default') settings.horizontal_padding = 16; 14328 14329 // Find out if the picture is part of a set 14330 theRel = $(this).attr(settings.hook); 14331 galleryRegExp = /\[(?:.*)\]/; 14332 isSet = (galleryRegExp.exec(theRel)) ? true : false; 14333 14334 // Put the SRCs, TITLEs, ALTs into an array. 14335 pp_images = (isSet) ? jQuery.map(matchedObjects, function(n, i){ if($(n).attr(settings.hook).indexOf(theRel) != -1) return $(n).attr('href'); }) : $.makeArray($(this).attr('href')); 14336 pp_titles = (isSet) ? jQuery.map(matchedObjects, function(n, i){ if($(n).attr(settings.hook).indexOf(theRel) != -1) return ($(n).find('img').attr('alt')) ? $(n).find('img').attr('alt') : ""; }) : $.makeArray($(this).find('img').attr('alt')); 14337 pp_descriptions = (isSet) ? jQuery.map(matchedObjects, function(n, i){ if($(n).attr(settings.hook).indexOf(theRel) != -1) return ($(n).attr('title')) ? $(n).attr('title') : ""; }) : $.makeArray($(this).attr('title')); 14338 14339 if(pp_images.length > settings.overlay_gallery_max) settings.overlay_gallery = false; 14340 14341 set_position = jQuery.inArray($(this).attr('href'), pp_images); // Define where in the array the clicked item is positionned 14342 rel_index = (isSet) ? set_position : $("a["+settings.hook+"^='"+theRel+"']").index($(this)); 14343 14344 _build_overlay(this); // Build the overlay {this} being the caller 14345 14346 if(settings.allow_resize) 14347 $(window).bind('scroll.prettyphoto',function(){ _center_overlay(); }); 14348 14349 14350 $.prettyPhoto.open(); 14351 14352 return false; 14353 } 14354 14355 14356 /** 14357 * Opens the prettyPhoto modal box. 14358 * @param image {String,Array} Full path to the image to be open, can also be an array containing full images paths. 14359 * @param title {String,Array} The title to be displayed with the picture, can also be an array containing all the titles. 14360 * @param description {String,Array} The description to be displayed with the picture, can also be an array containing all the descriptions. 14361 */ 14362 $.prettyPhoto.open = function(event) { 14363 if(typeof settings == "undefined"){ // Means it's an API call, need to manually get the settings and set the variables 14364 settings = pp_settings; 14365 pp_images = $.makeArray(arguments[0]); 14366 pp_titles = (arguments[1]) ? $.makeArray(arguments[1]) : $.makeArray(""); 14367 pp_descriptions = (arguments[2]) ? $.makeArray(arguments[2]) : $.makeArray(""); 14368 isSet = (pp_images.length > 1) ? true : false; 14369 set_position = (arguments[3])? arguments[3]: 0; 14370 _build_overlay(event.target); // Build the overlay {this} being the caller 14371 } 14372 14373 if(settings.hideflash) $('object,embed,iframe[src*=youtube],iframe[src*=vimeo]').css('visibility','hidden'); // Hide the flash 14374 14375 _checkPosition($(pp_images).size()); // Hide the next/previous links if on first or last images. 14376 14377 $('.pp_loaderIcon').show(); 14378 14379 if(settings.deeplinking) 14380 setHashtag(); 14381 14382 // Rebuild Facebook Like Button with updated href 14383 if(settings.social_tools){ 14384 facebook_like_link = settings.social_tools.replace('{location_href}', encodeURIComponent(location.href)); 14385 $pp_pic_holder.find('.pp_social').html(facebook_like_link); 14386 } 14387 14388 // Fade the content in 14389 if($ppt.is(':hidden')) $ppt.css('opacity',0).show(); 14390 $pp_overlay.show().fadeTo(settings.animation_speed,settings.opacity); 14391 14392 // Display the current position 14393 $pp_pic_holder.find('.currentTextHolder').text((set_position+1) + settings.counter_separator_label + $(pp_images).size()); 14394 14395 // Set the description 14396 if(typeof pp_descriptions[set_position] != 'undefined' && pp_descriptions[set_position] != ""){ 14397 $pp_pic_holder.find('.pp_description').show().html(unescape(pp_descriptions[set_position])); 14398 }else{ 14399 $pp_pic_holder.find('.pp_description').hide(); 14400 } 14401 14402 // Get the dimensions 14403 movie_width = ( parseFloat(getParam('width',pp_images[set_position])) ) ? getParam('width',pp_images[set_position]) : settings.default_width.toString(); 14404 movie_height = ( parseFloat(getParam('height',pp_images[set_position])) ) ? getParam('height',pp_images[set_position]) : settings.default_height.toString(); 14405 14406 // If the size is % based, calculate according to window dimensions 14407 percentBased=false; 14408 if(movie_height.indexOf('%') != -1) { movie_height = parseFloat(($(window).height() * parseFloat(movie_height) / 100) - 150); percentBased = true; } 14409 if(movie_width.indexOf('%') != -1) { movie_width = parseFloat(($(window).width() * parseFloat(movie_width) / 100) - 150); percentBased = true; } 14410 14411 // Fade the holder 14412 $pp_pic_holder.fadeIn(function(){ 14413 // Set the title
14414 (settings.show_title && pp_titles[set_position] != "" && typeof pp_titles[set_position] != "undefined") ? $ppt.html(unescape(pp_titles[set_position])) : $ppt.html(' '); 14415 14416 imgPreloader = ""; 14417 skipInjection = false; 14418 14419 // Inject the proper content 14420 switch(_getFileType(pp_images[set_position])){ 14421 case 'image': 14422 imgPreloader = new Image(); 14423 14424 // Preload the neighbour images 14425 nextImage = new Image(); 14426 if(isSet && set_position < $(pp_images).size() -1) nextImage.src = pp_images[set_position + 1]; 14427 prevImage = new Image(); 14428 if(isSet && pp_images[set_position - 1]) prevImage.src = pp_images[set_position - 1]; 14429 14430 $pp_pic_holder.find('#pp_full_res')[0].innerHTML = settings.image_markup.replace(/{path}/g,pp_images[set_position]); 14431 14432 imgPreloader.onload = function(){ 14433 // Fit item to viewport 14434 pp_dimensions = _fitToViewport(imgPreloader.width,imgPreloader.height); 14435 14436 _showContent(); 14437 }; 14438 14439 imgPreloader.onerror = function(){ 14440 alert('Image cannot be loaded. Make sure the path is correct and image exist.'); 14441 $.prettyPhoto.close(); 14442 }; 14443 14444 imgPreloader.src = pp_images[set_position]; 14445 break; 14446 14447 case 'youtube': 14448 pp_dimensions = _fitToViewport(movie_width,movie_height); // Fit item to viewport 14449 14450 // Regular youtube link 14451 movie_id = getParam('v',pp_images[set_position]); 14452 14453 // youtu.be link 14454 if(movie_id == ""){ 14455 movie_id = pp_images[set_position].split('youtu.be/'); 14456 movie_id = movie_id[1]; 14457 if(movie_id.indexOf('?') > 0) 14458 movie_id = movie_id.substr(0,movie_id.indexOf('?')); // Strip anything after the ? 14459 14460 if(movie_id.indexOf('&') > 0) 14461 movie_id = movie_id.substr(0,movie_id.indexOf('&')); // Strip anything after the & 14462 } 14463 14464 movie = '//www.youtube.com/embed/'+movie_id; 14465 (getParam('rel',pp_images[set_position])) ? movie+="?rel="+getParam('rel',pp_images[set_position]) : movie+="?rel=1"; 14466 14467 if(settings.autoplay) movie += "&autoplay=1"; 14468 14469 toInject = settings.iframe_markup.replace(/{width}/g,pp_dimensions['width']).replace(/{height}/g,pp_dimensions['height']).replace(/{wmode}/g,settings.wmode).replace(/{path}/g,movie); 14470 break; 14471 14472 case 'vimeo': 14473 pp_dimensions = _fitToViewport(movie_width,movie_height); // Fit item to viewport 14474 14475 movie_id = pp_images[set_position]; 14476 var regExp = /http(s?):\/\/(www\.)?vimeo.com\/(\d+)/; 14477 var match = movie_id.match(regExp); 14478 14479 movie = '//player.vimeo.com/video/'+ match[3] +'?title=0&byline=0&portrait=0'; 14480 if(settings.autoplay) movie += "&autoplay=1;"; 14481 14482 vimeo_width = pp_dimensions['width'] + '/embed/?moog_width='+ pp_dimensions['width']; 14483 14484 toInject = settings.iframe_markup.replace(/{width}/g,vimeo_width).replace(/{height}/g,pp_dimensions['height']).replace(/{path}/g,movie); 14485 break; 14486 14487 case 'quicktime': 14488 pp_dimensions = _fitToViewport(movie_width,movie_height); // Fit item to viewport 14489 pp_dimensions['height']+=15; pp_dimensions['contentHeight']+=15; pp_dimensions['containerHeight']+=15; // Add space for the control bar 14490 14491 toInject = settings.quicktime_markup.replace(/{width}/g,pp_dimensions['width']).replace(/{height}/g,pp_dimensions['height']).replace(/{wmode}/g,settings.wmode).replace(/{path}/g,pp_images[set_position]).replace(/{autoplay}/g,settings.autoplay); 14492 break; 14493 14494 case 'flash': 14495 pp_dimensions = _fitToViewport(movie_width,movie_height); // Fit item to viewport 14496 14497 flash_vars = pp_images[set_position]; 14498 flash_vars = flash_vars.substring(pp_images[set_position].indexOf('flashvars') + 10,pp_images[set_position].length); 14499 14500 filename = pp_images[set_position]; 14501 filename = filename.substring(0,filename.indexOf('?')); 14502 14503 toInject = settings.flash_markup.replace(/{width}/g,pp_dimensions['width']).replace(/{height}/g,pp_dimensions['height']).replace(/{wmode}/g,settings.wmode).replace(/{path}/g,filename+'?'+flash_vars); 14504 break; 14505 14506 case 'iframe': 14507 pp_dimensions = _fitToViewport(movie_width,movie_height); // Fit item to viewport 14508 14509 frame_url = pp_images[set_position]; 14510 frame_url = frame_url.substr(0,frame_url.indexOf('iframe')-1); 14511 14512 toInject = settings.iframe_markup.replace(/{width}/g,pp_dimensions['width']).replace(/{height}/g,pp_dimensions['height']).replace(/{path}/g,frame_url); 14513 break; 14514 14515 case 'ajax': 14516 doresize = false; // Make sure the dimensions are not resized. 14517 pp_dimensions = _fitToViewport(movie_width,movie_height); 14518 doresize = true; // Reset the dimensions 14519 14520 skipInjection = true; 14521 $.get(pp_images[set_position],function(responseHTML){ 14522 toInject = settings.inline_markup.replace(/{content}/g,responseHTML); 14523 $pp_pic_holder.find('#pp_full_res')[0].innerHTML = toInject; 14524 _showContent(); 14525 }); 14526 14527 break; 14528 14529 case 'custom': 14530 pp_dimensions = _fitToViewport(movie_width,movie_height); // Fit item to viewport 14531 14532 toInject = settings.custom_markup; 14533 break; 14534 14535 case 'inline': 14536 // to get the item height clone it, apply default width, wrap it in the prettyPhoto containers , then delete 14537 myClone = $(pp_images[set_position]).clone().append('<br clear="all" />').css({'width':settings.default_width}).wrapInner('<div id="pp_full_res"><div class="pp_inline"></div></div>').appendTo($('body')).show(); 14538 doresize = false; // Make sure the dimensions are not resized. 14539 pp_dimensions = _fitToViewport($(myClone).width(),$(myClone).height()); 14540 doresize = true; // Reset the dimensions 14541 $(myClone).remove(); 14542 toInject = settings.inline_markup.replace(/{content}/g,$(pp_images[set_position]).html()); 14543 break; 14544 }; 14545 14546 if(!imgPreloader && !skipInjection){ 14547 $pp_pic_holder.find('#pp_full_res')[0].innerHTML = toInject; 14548 14549 // Show content 14550 _showContent(); 14551 }; 14552 }); 14553 14554 return false;
14555 }; 14556 14557 14558 /** 14559 * Change page in the prettyPhoto modal box 14560 * @param direction {String} Direction of the paging, previous or next. 14561 */ 14562 $.prettyPhoto.changePage = function(direction){ 14563 currentGalleryPage = 0; 14564 14565 if(direction == 'previous') { 14566 set_position--; 14567 if (set_position < 0) set_position = $(pp_images).size()-1; 14568 }else if(direction == 'next'){ 14569 set_position++; 14570 if(set_position > $(pp_images).size()-1) set_position = 0; 14571 }else{ 14572 set_position=direction; 14573 }; 14574 14575 rel_index = set_position; 14576 14577 if(!doresize) doresize = true; // Allow the resizing of the images 14578 if(settings.allow_expand) { 14579 $('.pp_contract').removeClass('pp_contract').addClass('pp_expand'); 14580 } 14581 14582 _hideContent(function(){ $.prettyPhoto.open(); }); 14583 }; 14584 14585 14586 /** 14587 * Change gallery page in the prettyPhoto modal box 14588 * @param direction {String} Direction of the paging, previous or next. 14589 */ 14590 $.prettyPhoto.changeGalleryPage = function(direction){ 14591 if(direction=='next'){ 14592 currentGalleryPage ++; 14593 14594 if(currentGalleryPage > totalPage) currentGalleryPage = 0; 14595 }else if(direction=='previous'){ 14596 currentGalleryPage --; 14597 14598 if(currentGalleryPage < 0) currentGalleryPage = totalPage; 14599 }else{ 14600 currentGalleryPage = direction; 14601 }; 14602 14603 slide_speed = (direction == 'next' || direction == 'previous') ? settings.animation_speed : 0; 14604 14605 slide_to = currentGalleryPage * (itemsPerPage * itemWidth); 14606 14607 $pp_gallery.find('ul').animate({left:-slide_to},slide_speed); 14608 }; 14609 14610 14611 /** 14612 * Start the slideshow... 14613 */ 14614 $.prettyPhoto.startSlideshow = function(){ 14615 if(typeof pp_slideshow == 'undefined'){ 14616 $pp_pic_holder.find('.pp_play').unbind('click').removeClass('pp_play').addClass('pp_pause').click(function(){ 14617 $.prettyPhoto.stopSlideshow(); 14618 return false; 14619 }); 14620 pp_slideshow = setInterval($.prettyPhoto.startSlideshow,settings.slideshow); 14621 }else{ 14622 $.prettyPhoto.changePage('next'); 14623 }; 14624 } 14625 14626 14627 /** 14628 * Stop the slideshow... 14629 */ 14630 $.prettyPhoto.stopSlideshow = function(){ 14631 $pp_pic_holder.find('.pp_pause').unbind('click').removeClass('pp_pause').addClass('pp_play').click(function(){ 14632 $.prettyPhoto.startSlideshow(); 14633 return false; 14634 }); 14635 clearInterval(pp_slideshow); 14636 pp_slideshow=undefined; 14637 } 14638 14639 14640 /** 14641 * Closes prettyPhoto. 14642 */ 14643 $.prettyPhoto.close = function(){ 14644 if($pp_overlay.is(":animated")) return; 14645 14646 $.prettyPhoto.stopSlideshow(); 14647 14648 $pp_pic_holder.stop().find('object,embed').css('visibility','hidden'); 14649 14650 $('div.pp_pic_holder,div.ppt,.pp_fade').fadeOut(settings.animation_speed,function(){ $(this).remove(); }); 14651 14652 $pp_overlay.fadeOut(settings.animation_speed, function(){ 14653 14654 if(settings.hideflash) $('object,embed,iframe[src*=youtube],iframe[src*=vimeo]').css('visibility','visible'); // Show the flash 14655 14656 $(this).remove(); // No more need for the prettyPhoto markup 14657 14658 $(window).unbind('scroll.prettyphoto'); 14659 14660 clearHashtag(); 14661 14662 settings.callback(); 14663 14664 doresize = true; 14665 14666 pp_open = false; 14667 14668 delete settings; 14669 }); 14670 }; 14671 14672 /** 14673 * Set the proper sizes on the containers and animate the content in. 14674 */ 14675 function _showContent(){ 14676 $('.pp_loaderIcon').hide(); 14677 14678 // Calculate the opened top position of the pic holder 14679 projectedTop = scroll_pos['scrollTop'] + ((windowHeight/2) - (pp_dimensions['containerHeight']/2)); 14680 if(projectedTop < 0) projectedTop = 0; 14681 14682 $ppt.fadeTo(settings.animation_speed,1); 14683 14684 // Resize the content holder 14685 $pp_pic_holder.find('.pp_content') 14686 .animate({ 14687 height:pp_dimensions['contentHeight'], 14688 width:pp_dimensions['contentWidth'] 14689 },settings.animation_speed); 14690 14691 // Resize picture the holder 14692 $pp_pic_holder.animate({ 14693 'top': projectedTop, 14694 'left': ((windowWidth/2) - (pp_dimensions['containerWidth']/2) < 0) ? 0 : (windowWidth/2) - (pp_dimensions['containerWidth']/2), 14695 width:pp_dimensions['containerWidth'] 14696 },settings.animation_speed,function(){ 14697 $pp_pic_holder.find('.pp_hoverContainer,#fullResImage').height(pp_dimensions['height']).width(pp_dimensions['width']); 14698 14699 $pp_pic_holder.find('.pp_fade').fadeIn(settings.animation_speed); // Fade the new content 14700 14701 // Show the nav 14702 if(isSet && _getFileType(pp_images[set_position])=="image") { $pp_pic_holder.find('.pp_hoverContainer').show(); }else{ $pp_pic_holder.find('.pp_hoverContainer').hide(); } 14703 14704 if(settings.allow_expand) { 14705 if(pp_dimensions['resized']){ // Fade the resizing link if the image is resized 14706 $('a.pp_expand,a.pp_contract').show(); 14707 }else{ 14708 $('a.pp_expand').hide(); 14709 } 14710 } 14711 14712 if(settings.autoplay_slideshow && !pp_slideshow && !pp_open) $.prettyPhoto.startSlideshow(); 14713 14714 settings.changepicturecallback(); // Callback! 14715 14716 pp_open = true; 14717 }); 14718 14719 _insert_gallery(); 14720 pp_settings.ajaxcallback(); 14721 }; 14722
14723 /** 14724 * Hide the content...DUH! 14725 */ 14726 function _hideContent(callback){ 14727 // Fade out the current picture 14728 $pp_pic_holder.find('#pp_full_res object,#pp_full_res embed').css('visibility','hidden'); 14729 $pp_pic_holder.find('.pp_fade').fadeOut(settings.animation_speed,function(){ 14730 $('.pp_loaderIcon').show(); 14731 14732 callback(); 14733 }); 14734 }; 14735 14736 /** 14737 * Check the item position in the gallery array, hide or show the navigation links 14738 * @param setCount {integer} The total number of items in the set 14739 */ 14740 function _checkPosition(setCount){ 14741 (setCount > 1) ? $('.pp_nav').show() : $('.pp_nav').hide(); // Hide the bottom nav if it's not a set. 14742 }; 14743 14744 /** 14745 * Resize the item dimensions if it's bigger than the viewport 14746 * @param width {integer} Width of the item to be opened 14747 * @param height {integer} Height of the item to be opened 14748 * @return An array containin the "fitted" dimensions 14749 */ 14750 function _fitToViewport(width,height){ 14751 resized = false; 14752 14753 _getDimensions(width,height); 14754 14755 // Define them in case there's no resize needed 14756 imageWidth = width, imageHeight = height; 14757 14758 if( ((pp_containerWidth > windowWidth) || (pp_containerHeight > windowHeight)) && doresize && settings.allow_resize && !percentBased) { 14759 resized = true, fitting = false; 14760 14761 while (!fitting){ 14762 if((pp_containerWidth > windowWidth)){ 14763 imageWidth = (windowWidth - 200); 14764 imageHeight = (height/width) * imageWidth; 14765 }else if((pp_containerHeight > windowHeight)){ 14766 imageHeight = (windowHeight - 200); 14767 imageWidth = (width/height) * imageHeight; 14768 }else{ 14769 fitting = true; 14770 }; 14771 14772 pp_containerHeight = imageHeight, pp_containerWidth = imageWidth; 14773 }; 14774 14775 14776 14777 if((pp_containerWidth > windowWidth) || (pp_containerHeight > windowHeight)){ 14778 _fitToViewport(pp_containerWidth,pp_containerHeight) 14779 }; 14780 14781 _getDimensions(imageWidth,imageHeight); 14782 }; 14783 14784 return { 14785 width:Math.floor(imageWidth), 14786 height:Math.floor(imageHeight), 14787 containerHeight:Math.floor(pp_containerHeight), 14788 containerWidth:Math.floor(pp_containerWidth) + (settings.horizontal_padding * 2), 14789 contentHeight:Math.floor(pp_contentHeight), 14790 contentWidth:Math.floor(pp_contentWidth), 14791 resized:resized 14792 }; 14793 }; 14794 14795 /** 14796 * Get the containers dimensions according to the item size 14797 * @param width {integer} Width of the item to be opened 14798 * @param height {integer} Height of the item to be opened 14799 */ 14800 function _getDimensions(width,height){ 14801 width = parseFloat(width); 14802 height = parseFloat(height); 14803 14804 // Get the details height, to do so, I need to clone it since it's invisible 14805 $pp_details = $pp_pic_holder.find('.pp_details'); 14806 $pp_details.width(width); 14807 detailsHeight = parseFloat($pp_details.css('marginTop')) + parseFloat($pp_details.css('marginBottom')); 14808 14809 $pp_details = $pp_details.clone().addClass(settings.theme).width(width).appendTo($('body')).css({ 14810 'position':'absolute', 14811 'top':-10000 14812 }); 14813 detailsHeight += $pp_details.height(); 14814 detailsHeight = (detailsHeight <= 34) ? 36 : detailsHeight; // Min-height for the details 14815 $pp_details.remove(); 14816 14817 // Get the titles height, to do so, I need to clone it since it's invisible 14818 $pp_title = $pp_pic_holder.find('.ppt'); 14819 $pp_title.width(width); 14820 titleHeight = parseFloat($pp_title.css('marginTop')) + parseFloat($pp_title.css('marginBottom')); 14821 $pp_title = $pp_title.clone().appendTo($('body')).css({ 14822 'position':'absolute', 14823 'top':-10000 14824 }); 14825 titleHeight += $pp_title.height(); 14826 $pp_title.remove(); 14827 14828 // Get the container size, to resize the holder to the right dimensions 14829 pp_contentHeight = height + detailsHeight; 14830 pp_contentWidth = width; 14831 pp_containerHeight = pp_contentHeight + titleHeight + $pp_pic_holder.find('.pp_top').height() + $pp_pic_holder.find('.pp_bottom').height(); 14832 pp_containerWidth = width; 14833 } 14834 14835 function _getFileType(itemSrc){ 14836 if (itemSrc.match(/youtube\.com\/watch/i) || itemSrc.match(/youtu\.be/i)) { 14837 return 'youtube'; 14838 }else if (itemSrc.match(/vimeo\.com/i)) { 14839 return 'vimeo'; 14840 }else if(itemSrc.match(/\b.mov\b/i)){ 14841 return 'quicktime'; 14842 }else if(itemSrc.match(/\b.swf\b/i)){ 14843 return 'flash'; 14844 }else if(itemSrc.match(/\biframe=true\b/i)){ 14845 return 'iframe'; 14846 }else if(itemSrc.match(/\bajax=true\b/i)){ 14847 return 'ajax'; 14848 }else if(itemSrc.match(/\bcustom=true\b/i)){ 14849 return 'custom'; 14850 }else if(itemSrc.substr(0,1) == '#'){ 14851 return 'inline'; 14852 }else{ 14853 return 'image'; 14854 }; 14855 }; 14856 14857 function _center_overlay(){ 14858 if(doresize && typeof $pp_pic_holder != 'undefined') { 14859 scroll_pos = _get_scroll(); 14860 contentHeight = $pp_pic_holder.height(), contentwidth = $pp_pic_holder.width(); 14861 14862 projectedTop = (windowHeight/2) + scroll_pos['scrollTop'] - (contentHeight/2); 14863 if(projectedTop < 0) projectedTop = 0; 14864 14865 if(contentHeight > windowHeight) 14866 return; 14867 14868 $pp_pic_holder.css({ 14869 'top': projectedTop, 14870 'left': (windowWidth/2) + scroll_pos['scrollLeft'] - (contentwidth/2) 14871 }); 14872 }; 14873 }; 14874 14875 function _get_scroll(){ 14876 if (self.pageYOffset) { 14877 return {scrollTop:self.pageYOffset,scrollLeft:self.pageXOffset}; 14878 } else if (document.documentElement && document.documentElement.scrollTop) { // Explorer 6 Strict 14879 return {scrollTop:document.documentElement.scrollTop,scrollLeft:document.documentElement.scrollLeft}; 14880 } else if (document.body) {// all other Explorers 14881 return {scrollTop:document.body.scrollTop,scrollLeft:document.body.scrollLeft}; 14882 }; 14883 }; 14884 14885 function _resize_overlay() { 14886 windowHeight = $(window).height(), windowWidth = $(window).width(); 14887 14888 if(typeof $pp_overlay != "undefined") $pp_overlay.height($(document).height()).width(windowWidth); 14889 }; 14890 14891 function _insert_gallery(){ 14892 if(isSet && settings.overlay_gallery && _getFileType(pp_images[set_position])=="image") { 14893 itemWidth = 52+5; // 52 beign the thumb width, 5 being the right margin. 14894 navWidth = (settings.theme == "facebook" || settings.theme == "pp_default") ? 50 : 30; // Define the arrow width depending on the theme 14895 14896 itemsPerPage = Math.floor((pp_dimensions['containerWidth'] - 100 - navWidth) / itemWidth); 14897 itemsPerPage = (itemsPerPage < pp_images.length) ? itemsPerPage : pp_images.length;
14898 totalPage = Math.ceil(pp_images.length / itemsPerPage) - 1; 14899 14900 // Hide the nav in the case there's no need for links 14901 if(totalPage == 0){ 14902 navWidth = 0; // No nav means no width! 14903 $pp_gallery.find('.pp_arrow_next,.pp_arrow_previous').hide(); 14904 }else{ 14905 $pp_gallery.find('.pp_arrow_next,.pp_arrow_previous').show(); 14906 }; 14907 14908 galleryWidth = itemsPerPage * itemWidth; 14909 fullGalleryWidth = pp_images.length * itemWidth; 14910 14911 // Set the proper width to the gallery items 14912 $pp_gallery 14913 .css('margin-left',-((galleryWidth/2) + (navWidth/2))) 14914 .find('div:first').width(galleryWidth+5) 14915 .find('ul').width(fullGalleryWidth) 14916 .find('li.selected').removeClass('selected'); 14917 14918 goToPage = (Math.floor(set_position/itemsPerPage) < totalPage) ? Math.floor(set_position/itemsPerPage) : totalPage; 14919 14920 $.prettyPhoto.changeGalleryPage(goToPage); 14921 14922 $pp_gallery_li.filter(':eq('+set_position+')').addClass('selected'); 14923 }else{ 14924 $pp_pic_holder.find('.pp_content').unbind('mouseenter mouseleave'); 14925 // $pp_gallery.hide(); 14926 } 14927 } 14928 14929 function _build_overlay(caller){ 14930 // Inject Social Tool markup into General markup 14931 if(settings.social_tools) 14932 facebook_like_link = settings.social_tools.replace('{location_href}', encodeURIComponent(location.href)); 14933 14934 settings.markup = settings.markup.replace('{pp_social}',''); 14935 14936 $('body').append(settings.markup); // Inject the markup 14937 14938 $pp_pic_holder = $('.pp_pic_holder') , $ppt = $('.ppt'), $pp_overlay
14938= $('div.pp_overlay'); // Set my global selectors 14939 14940 // Inject the inline gallery! 14941 if(isSet && settings.overlay_gallery) { 14942 currentGalleryPage = 0; 14943 toInject = ""; 14944 for (var i=0; i < pp_images.length; i++) { 14945 if(!pp_images[i].match(/\b(jpg|jpeg|png|gif)\b/gi)){ 14946 classname = 'default'; 14947 img_src = ''; 14948 }else{ 14949 classname = ''; 14950 img_src = pp_images[i]; 14951 } 14952 toInject += "<li class='"+classname+"'><a href='#'><img src='" + img_src + "' width='50' alt='' /></a></li>"; 14953 }; 14954 14955 toInject = settings.gallery_markup.replace(/{gallery}/g,toInject); 14956 14957 $pp_pic_holder.find('#pp_full_res').after(toInject); 14958 14959 $pp_gallery = $('.pp_pic_holder .pp_gallery'), $pp_gallery_li = $pp_gallery.find('li'); // Set the gallery selectors 14960 14961 $pp_gallery.find('.pp_arrow_next').click(function(){ 14962 $.prettyPhoto.changeGalleryPage('next'); 14963 $.prettyPhoto.stopSlideshow(); 14964 return false; 14965 }); 14966 14967 $pp_gallery.find('.pp_arrow_previous').click(function(){ 14968 $.prettyPhoto.changeGalleryPage('previous'); 14969 $.prettyPhoto.stopSlideshow(); 14970 return false; 14971 }); 14972 14973 $pp_pic_holder.find('.pp_content').hover( 14974 function(){ 14975 $pp_pic_holder.find('.pp_gallery:not(.disabled)').fadeIn(); 14976 }, 14977 function(){ 14978 $pp_pic_holder.find('.pp_gallery:not(.disabled)').fadeOut(); 14979 }); 14980 14981 itemWidth = 52+5; // 52 beign the thumb width, 5 being the right margin. 14982 $pp_gallery_li.each(function(i){ 14983 $(this) 14984 .find('a') 14985 .click(function(){ 14986 $.prettyPhoto.changePage(i); 14987 $.prettyPhoto.stopSlideshow(); 14988 return false; 14989 }); 14990 }); 14991 }; 14992 14993 14994 // Inject the play/pause if it's a slideshow 14995 if(settings.slideshow){ 14996 $pp_pic_holder.find('.pp_nav').prepend('<a href="#" class="pp_play">Play</a>') 14997 $pp_pic_holder.find('.pp_nav .pp_play').click(function(){ 14998 $.prettyPhoto.startSlideshow(); 14999 return false; 15000 }); 15001 } 15002 15003 $pp_pic_holder.attr('class','pp_pic_holder ' + settings.theme); // Set the proper theme 15004 15005 $pp_overlay 15006 .css({ 15007 'opacity':0, 15008 'height':$(document).height(), 15009 'width':$(window).width() 15010 }) 15011 .bind('click',function(){ 15012 if(!settings.modal) $.prettyPhoto.close(); 15013 }); 15014 15015 $('a.pp_close').bind('click',function(){ $.prettyPhoto.close(); return false; }); 15016 15017 15018 if(settings.allow_expand) { 15019 $('a.pp_expand').bind('click',function(e){ 15020 // Expand the image 15021 if($(this).hasClass('pp_expand')){ 15022 $(this).removeClass('pp_expand').addClass('pp_contract'); 15023 doresize = false; 15024 }else{ 15025 $(this).removeClass('pp_contract').addClass('pp_expand'); 15026 doresize = true; 15027 }; 15028 15029 _hideContent(function(){ $.prettyPhoto.open(); }); 15030 15031 return false; 15032 }); 15033 } 15034 15035 $pp_pic_holder.find('.pp_previous, .pp_nav .pp_arrow_previous').bind('click',function(){ 15036 $.prettyPhoto.changePage('previous'); 15037 $.prettyPhoto.stopSlideshow(); 15038 return false; 15039 }); 15040 15041 $pp_pic_holder.find('.pp_next, .pp_nav .pp_arrow_next').bind('click',function(){ 15042 $.prettyPhoto.changePage('next'); 15043 $.prettyPhoto.stopSlideshow(); 15044 return false; 15045 }); 15046 15047 _center_overlay(); // Center it 15048 }; 15049 15050 if(!pp_alreadyInitialized && getHashtag()){ 15051 pp_alreadyInitialized = true; 15052 15053 // Grab the rel index to trigger the click on the correct element 15054 hashIndex = getHashtag(); 15055 hashRel = hashIndex; 15056 hashIndex = hashIndex.substring(hashIndex.indexOf('/')+1,hashIndex.length-1); 15057 hashRel = hashRel.substring(0,hashRel.indexOf('/')); 15058 15059 // Little timeout to make sure all the prettyPhoto initialize scripts has been run. 15060 // Useful in the event the page contain several init scripts. 15061 setTimeout(function(){ $("a["+pp_settings.hook+"^='"+hashRel+"']:eq("+hashIndex+")").trigger('click'); },50); 15062 } 15063 15064 return this.unbind('click.prettyphoto').bind('click.prettyphoto',$.prettyPhoto.initialize); // Return the jQuery object for chaining. The unbind method is used to avoid click conflict when the plugin is called more than once 15065 }; 15066 15067 function getHashtag(){ 15068 var url = location.href; 15069 hashtag = (url.indexOf('#prettyPhoto') !== -1) ? decodeURI(url.substring(url.indexOf('#prettyPhoto')+1,url.length)) : false;
15070 if(hashtag){ hashtag = hashtag.replace(/<|>/g,''); } 15071 return hashtag; 15072 }; 15073 15074 function setHashtag(){ 15075 if(typeof theRel == 'undefined') return; // theRel is set on normal calls, it's impossible to deeplink using the API 15076 location.hash = theRel + '/'+rel_index+'/'; 15077 }; 15078 15079 function clearHashtag(){ 15080 if ( location.href.indexOf('#prettyPhoto') !== -1 ) location.hash = "prettyPhoto"; 15081 } 15082 15083 function getParam(name,url){ 15084 name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]"); 15085 var regexS = "[\\?&]"+name+"=([^&#]*)"; 15086 var regex = new RegExp( regexS ); 15087 var results = regex.exec( url ); 15088 return ( results == null ) ? "" : results[1]; 15089 } 15090 15091})(jQuery); 15092 15093var pp_alreadyInitialized = false; // Used for the deep linking to make sure not to call the same function several times. 15094 15095(function (factory) { 15096 if (typeof define === 'function' && define.amd) { 15097 // AMD 15098 define(['jquery'], factory); 15099 } else if (typeof exports === 'object') { 15100 // CommonJS 15101 factory(require('jquery')); 15102 } else { 15103 // Browser globals 15104 factory(jQuery); 15105 } 15106}(function ($) { 15107 var CountTo = function (element, options) { 15108 this.$element = $(element); 15109 this.options = $.extend({}, CountTo.DEFAULTS, this.dataOptions(), options); 15110 this.init(); 15111 }; 15112 15113 CountTo.DEFAULTS = { 15114 from: 0, // the number the element should start at 15115 to: 0, // the number the element should end at 15116 speed: 1000, // how long it should take to count between the target numbers 15117 refreshInterval: 100, // how often the element should be updated 15118 decimals: 0, // the number of decimal places to show 15119 formatter: formatter, // handler for formatting the value before rendering 15120 onUpdate: null, // callback method for every time the element is updated 15121 onComplete: null // callback method for when the element finishes updating 15122 }; 15123 15124 CountTo.prototype.init = function () { 15125 this.value = this.options.from; 15126 this.loops = Math.ceil(this.options.speed / this.options.refreshInterval); 15127 this.loopCount = 0; 15128 this.increment = (this.options.to - this.options.from) / this.loops; 15129 }; 15130 15131 CountTo.prototype.dataOptions = function () { 15132 var options = { 15133 from: this.$element.data('from'), 15134 to: this.$element.data('to'), 15135 speed: this.$element.data('speed'), 15136 refreshInterval: this.$element.data('refresh-interval'), 15137 decimals: this.$element.data('decimals') 15138 }; 15139 15140 var keys = Object.keys(options); 15141 15142 for (var i in keys) { 15143 var key = keys[i]; 15144 15145 if (typeof(options[key]) === 'undefined') { 15146 delete options[key]; 15147 } 15148 } 15149 15150 return options; 15151 }; 15152 15153 CountTo.prototype.update = function () { 15154 this.value += this.increment; 15155 this.loopCount++; 15156 15157 this.render(); 15158 15159 if (typeof(this.options.onUpdate) == 'function') { 15160 this.options.onUpdate.call(this.$element, this.value); 15161 } 15162 15163 if (this.loopCount >= this.loops) { 15164 clearInterval(this.interval); 15165 this.value = this.options.to; 15166 15167 if (typeof(this.options.onComplete) == 'function') { 15168 this.options.onComplete.call(this.$element, this.value); 15169 } 15170 } 15171 }; 15172 15173 CountTo.prototype.render = function () { 15174 var formattedValue = this.options.formatter.call(this.$element, this.value, this.options); 15175 this.$element.text(formattedValue); 15176 }; 15177 15178 CountTo.prototype.restart = function () { 15179 this.stop(); 15180 this.init(); 15181 this.start(); 15182 }; 15183 15184 CountTo.prototype.start = function () { 15185 this.stop(); 15186 this.render(); 15187 this.interval = setInterval(this.update.bind(this), this.options.refreshInterval); 15188 }; 15189 15190 CountTo.prototype.stop = function () { 15191 if (this.interval) { 15192 clearInterval(this.interval); 15193 } 15194 }; 15195 15196 CountTo.prototype.toggle = function () { 15197 if (this.interval) { 15198 this.stop(); 15199 } else { 15200 this.start(); 15201 } 15202 }; 15203 15204 function formatter(value, options) { 15205 return value.toFixed(options.decimals); 15206 } 15207 15208 $.fn.countTo = function (option) { 15209 return this.each(function () { 15210 var $this = $(this); 15211 var data = $this.data('countTo'); 15212 var init = !data || typeof(option) === 'object'; 15213 var options = typeof(option) === 'object' ? option : {}; 15214 var method = typeof(option) === 'string' ? option : 'start'; 15215 15216 if (init) { 15217 if (data) data.stop(); 15218 $this.data('countTo', data = new CountTo(this, options)); 15219 } 15220 15221 data[method].call(data); 15222 }); 15223 }; 15224}));
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.