1/* ---------------------------------------------------------- 2 * Plugins 3 * ---------------------------------------------------------- */ 4 5(function(window, $) { 6 'use strict'; 7 var counter = 0, 8 $headCache = $('head'), 9 oldBigText = window.BigText, 10 oldjQueryMethod = $.fn.bigtext, 11 BigText = { 12 DEBUG_MODE: false, 13 DEFAULT_MIN_FONT_SIZE_PX: null, 14 DEFAULT_MAX_FONT_SIZE_PX: 528, 15 GLOBAL_STYLE_ID: 'bigtext-style', 16 STYLE_ID: 'bigtext-id', 17 LINE_CLASS_PREFIX: 'bigtext-line', 18 EXEMPT_CLASS: 'bigtext-exempt', 19 noConflict: function(restore) 20 { 21 if(restore) { 22 $.fn.bigtext = oldjQueryMethod; 23 window.BigText = oldBigText; 24 } 25 return BigText; 26 }, 27 supports: { 28 wholeNumberFontSizeOnly: (function() { 29 if( !( 'getComputedStyle' in window ) ) { 30 return true; 31 } 32 var test = $('<div/>').css({ 33 position: 'absolute', 34 'font-size': '14.1px' 35 }).insertBefore( $('script').eq(0) ), 36 computedStyle = window.getComputedStyle( test[0], null ); 37 38 var ret = computedStyle && computedStyle.getPropertyValue( 'font-size' ) === '14px'; 39 test.remove(); 40 return ret; 41 })() 42 }, 43 init: function() { 44 if(!$('#'+BigText.GLOBAL_STYLE_ID).length) { 45 $headCache.append(BigText.generateStyleTag(BigText.GLOBAL_STYLE_ID, ['.bigtext * { white-space: nowrap; } .bigtext > * { display: block; }', 46 '.bigtext .' + BigText.EXEMPT_CLASS + ', .bigtext .' + BigText.EXEMPT_CLASS + ' * { white-space: normal; }'])); 47 } 48 }, 49 bindResize: function(eventName, resizeFunction) { 50 var timeoutId; 51 $(window).unbind(eventName).bind(eventName, function() { 52 if( timeoutId ) { 53 clearTimeout( timeoutId ); 54 } 55 timeoutId = setTimeout( resizeFunction, 300 ); 56 }); 57 }, 58 getStyleId: function(id) 59 { 60 return BigText.STYLE_ID + '-' + id; 61 }, 62 generateStyleTag: function(id, css) 63 { 64 return $('<style>' + css.join('\n') + '</style>').attr('id', id); 65 }, 66 clearCss: function(id) 67 { 68 var styleId = BigText.getStyleId(id); 69 $('#' + styleId).remove(); 70 }, 71 generateCss: function(id, linesFontSizes, lineWordSpacings, minFontSizes) 72 { 73 var css = []; 74 75 BigText.clearCss(id); 76 77 for(var j=0, k=linesFontSizes.length; j<k; j++) { 78 css.push('#' + id + ' .' + BigText.LINE_CLASS_PREFIX + j + ' {' + 79 (minFontSizes[j] ? ' white-space: normal;' : '') + 80 (linesFontSizes[j] ? ' font-size: ' + linesFontSizes[j] + 'px;' : '') + 81 (lineWordSpacings[j] ? ' word-spacing: ' + lineWordSpacings[j] + 'px;' : '') + 82 '}'); 83 } 84 85 return BigText.generateStyleTag(BigText.getStyleId(id), css); 86 }, 87 jQueryMethod: function(options) 88 { 89 BigText.init(); 90 91 options = $.extend({ 92 minfontsize: BigText.DEFAULT_MIN_FONT_SIZE_PX, 93 maxfontsize: BigText.DEFAULT_MAX_FONT_SIZE_PX, 94 childSelector: '', 95 resize: true 96 }, options || {}); 97 98 this.each(function() 99 { 100 var $t = $(this).addClass('bigtext'), 101 maxWidth = $t.width(), 102 id = $t.attr('id'), 103 $children = options.childSelector ? $t.find( options.childSelector ) : $t.children(); 104 105 if(!id) { 106 id = 'bigtext-id' + (counter++); 107 $t.attr('id', id); 108 } 109 110 if(options.resize) { 111 BigText.bindResize('resize.bigtext-event-' + id, function() 112 { 113 // TODO only call this if the width has changed. 114 BigText.jQueryMethod.call($('#' + id), options); 115 }); 116 } 117 118 BigText.clearCss(id); 119 120 $children.addClass(function(lineNumber, className) 121 { 122 // remove existing line classes. 123 return [className.replace(new RegExp('\\b' + BigText.LINE_CLASS_PREFIX + '\\d+\\b'), ''), 124 BigText.LINE_CLASS_PREFIX + lineNumber].join(' '); 125 }); 126 127 var sizes = calculateSizes($t, $children, maxWidth, options.maxfontsize, options.minfontsize); 128 $headCache.append(BigText.generateCss(id, sizes.fontSizes, sizes.wordSpacings, sizes.minFontSizes)); 129 }); 130 131 return this.trigger('bigtext:complete'); 132 } 133 }; 134 135 function testLineDimensions($line, maxWidth, property, size, interval, units, previousWidth) 136 { 137 var width; 138 previousWidth = typeof previousWidth === 'number' ? previousWidth : 0; 139 $line.css(property, size + units); 140 141 width = $line.width(); 142 143 if(width >= maxWidth) { 144 145 $line.css(property, ''); 146 147 if(width === maxWidth) { 148 return { 149 match: 'exact', 150 size: parseFloat((parseFloat(size) - 0.1).toFixed(3)) 151 }; 152 } 153 154 // Since this is an estimate, we calculate how far over the width we went with the new value. 155 // If this is word-spacing (our last resort guess) and the over is less than the under, we keep the higher value. 156 // Otherwise, we revert to the underestimate. 157 var under = maxWidth - previousWidth, 158 over = width - maxWidth; 159 160 return { 161 match: 'estimate', 162 size: parseFloat((parseFloat(size) - (property === 'word-spacing' && previousWidth && ( over < under ) ? 0 : interval)).toFixed(3)) 163 }; 164 } 165 166 return width; 167 } 168 169 function calculateSizes($t, $children, maxWidth, maxFontSize, minFontSize) 170 { 171 var $c = $t.clone(true) 172 .addClass('bigtext-cloned') 173 .css({ 174 fontFamily: $t.css('font-family'), 175 textTransform: $t.css('text-transform'), 176 wordSpacing: $t.css('word-spacing'), 177 letterSpacing: $t.css('letter-spacing'), 178 position: 'absolute', 179 left: BigText.DEBUG_MODE ? 0 : -9999, 180 top: BigText.DEBUG_MODE ? 0 : -9999
181 }) 182 .appendTo(document.body); 183 184 // font-size isn't the only thing we can modify, we can also mess with: 185 // word-spacing and letter-spacing. WebKit does not respect subpixel 186 // letter-spacing, word-spacing, or font-size. 187 // TODO try -webkit-transform: scale() as a workaround. 188 var fontSizes = [], 189 wordSpacings = [], 190 minFontSizes = [], 191 ratios = []; 192 193 $children.css('float', 'left').each(function() { 194 var $line = $(this), 195 // TODO replace 8, 4 with a proportional size to the calculated font-size. 196 intervals = BigText.supports.wholeNumberFontSizeOnly ? [8, 4, 1] : [8, 4, 1, 0.1], 197 lineMax, 198 newFontSize; 199 200 if($line.hasClass(BigText.EXEMPT_CLASS)) { 201 fontSizes.push(null); 202 ratios.push(null); 203 minFontSizes.push(false); 204 return; 205 } 206 207 // TODO we can cache this ratio? 208 var autoGuessSubtraction = 32, // font size in px 209 currentFontSize = parseFloat($line.css('font-size')), 210 ratio = ( $line.width() / currentFontSize ).toFixed(6); 211 212 newFontSize = parseInt( maxWidth / ratio, 10 ) - autoGuessSubtraction; 213 214 outer: for(var m=0, n=intervals.length; m<n; m++) { 215 inner: for(var j=1, k=10; j<=k; j++) { 216 if(newFontSize + j*intervals[m] > maxFontSize) { 217 newFontSize = maxFontSize; 218 break outer; 219 } 220 221 lineMax = testLineDimensions($line, maxWidth, 'font-size', newFontSize + j*intervals[m], intervals[m], 'px', lineMax); 222 if(typeof lineMax !== 'number') { 223 newFontSize = lineMax.size; 224 225 if(lineMax.match === 'exact') { 226 break outer; 227 } 228 break inner; 229 } 230 } 231 } 232 233 ratios.push(maxWidth / newFontSize); 234 235 if(newFontSize > maxFontSize) { 236 fontSizes.push(maxFontSize); 237 minFontSizes.push(false); 238 } else if(!!minFontSize && newFontSize < minFontSize) { 239 fontSizes.push(minFontSize); 240 minFontSizes.push(true); 241 } else { 242 fontSizes.push(newFontSize); 243 minFontSizes.push(false); 244 } 245 }).each(function(lineNumber) { 246 var $line = $(this), 247 wordSpacing = 0, 248 interval = 1, 249 maxWordSpacing; 250 251 if($line.hasClass(BigText.EXEMPT_CLASS)) { 252 wordSpacings.push(null); 253 return; 254 } 255 256 // must re-use font-size, even though it was removed above. 257 $line.css('font-size', fontSizes[lineNumber] + 'px'); 258 259 for(var m=1, n=3; m<n; m+=interval) { 260 maxWordSpacing = testLineDimensions($line, maxWidth, 'word-spacing', m, interval, 'px', maxWordSpacing); 261 if(typeof maxWordSpacing !== 'number') { 262 wordSpacing = maxWordSpacing.size; 263 break; 264 } 265 } 266 267 $line.css('font-size', ''); 268 wordSpacings.push(wordSpacing); 269 }).removeAttr('style'); 270 271 if( !BigText.DEBUG_MODE ) { 272 $c.remove(); 273 } else { 274 $c.css({ 275 'background-color': 'rgba(255,255,255,.4)' 276 }); 277 } 278 279 return { 280 fontSizes: fontSizes, 281 wordSpacings: wordSpacings, 282 ratios: ratios, 283 minFontSizes: minFontSizes 284 }; 285 } 286 287 $.fn.bigtext = BigText.jQueryMethod; 288 window.BigText = BigText; 289 290})(this, jQuery);
vendor: 16,093 bytes, lines 291-948
291/*! 292 * Isotope PACKAGED v3.0.6 293 * 294 * Licensed GPLv3 for open source use 295 * or Isotope Commercial License for commercial use 296 * 297 * https://isotope.metafizzy.co 298 * Copyright 2010-2018 Metafizzy 299 */ 300 301/** 302 * Bridget makes jQuery widgets 303 * v2.0.1 304 * MIT license 305 */ 306 307/* jshint browser: true, strict: true, undef: true, unused: true */ 308 309( function( window, factory ) { 310 // universal module definition 311 /*jshint strict: false */ /* globals define, module, require */ 312 if ( typeof define == 'function' && define.amd ) { 313 // AMD 314 define( 'jquery-bridget/jquery-bridget',[ 'jquery' ], function( jQuery ) { 315 return factory( window, jQuery ); 316 }); 317 } else if ( typeof module == 'object' && module.exports ) { 318 // CommonJS 319 module.exports = factory( 320 window, 321 require('jquery') 322 ); 323 } else { 324 // browser global 325 window.jQueryBridget = factory( 326 window, 327 window.jQuery 328 ); 329 } 330 331}( window, function factory( window, jQuery ) { 332'use strict'; 333 334// ----- utils ----- // 335 336var arraySlice = Array.prototype.slice; 337 338// helper function for logging errors 339// $.error breaks jQuery chaining 340var console = window.console; 341var logError = typeof console == 'undefined' ? function() {} : 342 function( message ) { 343 console.error( message ); 344 }; 345 346// ----- jQueryBridget ----- // 347 348function jQueryBridget( namespace, PluginClass, $ ) { 349 $ = $ || jQuery || window.jQuery; 350 if ( !$ ) { 351 return; 352 } 353 354 // add option method -> $().plugin('option', {...}) 355 if ( !PluginClass.prototype.option ) { 356 // option setter 357 PluginClass.prototype.option = function( opts ) { 358 // bail out if not an object 359 if ( !$.isPlainObject( opts ) ){ 360 return; 361 } 362 this.options = $.extend( true, this.options, opts ); 363 }; 364 } 365 366 // make jQuery plugin 367 $.fn[ namespace ] = function( arg0 /*, arg1 */ ) { 368 if ( typeof arg0 == 'string' ) { 369 // method call $().plugin( 'methodName', { options } ) 370 // shift arguments by 1 371 var args = arraySlice.call( arguments, 1 ); 372 return methodCall( this, arg0, args ); 373 } 374 // just $().plugin({ options }) 375 plainCall( this, arg0 ); 376 return this; 377 }; 378 379 // $().plugin('methodName') 380 function methodCall( $elems, methodName, args ) { 381 var returnValue; 382 var pluginMethodStr = '$().' + namespace + '("' + methodName + '")'; 383 384 $elems.each( function( i, elem ) { 385 // get instance 386 var instance = $.data( elem, namespace ); 387 if ( !instance ) { 388 logError( namespace + ' not initialized. Cannot call methods, i.e. ' + 389 pluginMethodStr ); 390 return; 391 } 392 393 var method = instance[ methodName ]; 394 if ( !method || methodName.charAt(0) == '_' ) { 395 logError( pluginMethodStr + ' is not a valid method' ); 396 return; 397 } 398 399 // apply method, get return value 400 var value = method.apply( instance, args ); 401 // set return value if value is returned, use only first value 402 returnValue = returnValue === undefined ? value : returnValue; 403 }); 404 405 return returnValue !== undefined ? returnValue : $elems; 406 } 407 408 function plainCall( $elems, options ) { 409 $elems.each( function( i, elem ) { 410 var instance = $.data( elem, namespace ); 411 if ( instance ) { 412 // set options & init 413 instance.option( options ); 414 instance._init(); 415 } else { 416 // initialize new instance 417 instance = new PluginClass( elem, options ); 418 $.data( elem, namespace, instance ); 419 } 420 }); 421 } 422 423 updateJQuery( $ ); 424 425} 426 427// ----- updateJQuery ----- // 428 429// set $.bridget for v1 backwards compatibility 430function updateJQuery( $ ) { 431 if ( !$ || ( $ && $.bridget ) ) { 432 return; 433 } 434 $.bridget = jQueryBridget; 435} 436 437updateJQuery( jQuery || window.jQuery ); 438 439// ----- ----- // 440 441return jQueryBridget; 442 443})); 444 445/** 446 * EvEmitter v1.1.0 447 * Lil' event emitter 448 * MIT License 449 */ 450 451/* jshint unused: true, undef: true, strict: true */ 452 453( function( global, factory ) { 454 // universal module definition 455 /* jshint strict: false */ /* globals define, module, window */ 456 if ( typeof define == 'function' && define.amd ) { 457 // AMD - RequireJS 458 define( 'ev-emitter/ev-emitter',factory ); 459 } else if ( typeof module == 'object' && module.exports ) { 460 // CommonJS - Browserify, Webpack 461 module.exports = factory(); 462 } else { 463 // Browser globals 464 global.EvEmitter = factory(); 465 } 466 467}( typeof window != 'undefined' ? window : this, function() { 468 469 470 471function EvEmitter() {} 472 473var proto = EvEmitter.prototype; 474 475proto.on = function( eventName, listener ) { 476 if ( !eventName || !listener ) { 477 return; 478 } 479 // set events hash 480 var events = this._events = this._events || {}; 481 // set listeners array 482 var listeners = events[ eventName ] = events[ eventName ] || []; 483 // only add once 484 if ( listeners.indexOf( listener ) == -1 ) { 485 listeners.push( listener ); 486 } 487 488 return this; 489}; 490 491proto.once = function( eventName, listener ) { 492 if ( !eventName || !listener ) { 493 return; 494 } 495 // add event 496 this.on( eventName, listener ); 497 // set once flag 498 // set onceEvents hash 499 var onceEvents = this._onceEvents = this._onceEvents || {}; 500 // set onceListeners object 501 var onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || {}; 502 // set flag 503 onceListeners[ listener ] = true; 504 505 return this; 506}; 507 508proto.off = function( eventName, listener ) { 509 var listeners = this._events && this._events[ eventName ]; 510 if ( !listeners || !listeners.length ) { 511 return; 512 } 513 var index = listeners.indexOf( listener ); 514 if ( index != -1 ) { 515 listeners.splice( index, 1 ); 516 } 517 518 return this; 519}; 520 521proto.emitEvent = function( eventName, args ) { 522 var listeners = this._events && this._events[ eventName ]; 523 if ( !listeners || !listeners.length ) { 524 return; 525 } 526 // copy over to avoid interference if .off() in listener 527 listeners = listeners.slice(0); 528 args = args || []; 529 // once stuff 530 var onceListeners = this._onceEvents && this._onceEvents[ eventName ]; 531 532 for ( var i=0; i < listeners.length; i++ ) { 533 var listener = listeners[i] 534 var isOnce = onceListeners && onceListeners[ listener ]; 535 if ( isOnce ) { 536 // remove listener 537 // remove before trigger to prevent recursion 538 this.off( eventName, listener ); 539 // unset once flag 540 delete onceListeners[ listener ]; 541 } 542 // trigger listener 543 listener.apply( this, args ); 544 } 545 546 return this; 547}; 548 549proto.allOff = function() { 550 delete this._events; 551 delete this._onceEvents; 552}; 553 554return EvEmitter; 555 556})); 557 558/*! 559 * getSize v2.0.3 560 * measure size of elements 561 * MIT license 562 */ 563 564/* jshint browser: true, strict: true, undef: true, unused: true */ 565/* globals console: false */ 566 567( function( window, factory ) { 568 /* jshint strict: false */ /* globals define, module */ 569 if ( typeof define == 'function' && define.amd ) { 570 // AMD 571 define( 'get-size/get-size',factory ); 572 } else if ( typeof module == 'object' && module.exports ) { 573 // CommonJS 574 module.exports = factory(); 575 } else { 576 // browser global 577 window.getSize = factory(); 578 } 579 580})( window, function factory() { 581'use strict'; 582 583// -------------------------- helpers -------------------------- // 584 585// get a number from a string, not a percentage 586function getStyleSize( value ) { 587 var num = parseFloat( value ); 588 // not a percent like '100%', and a number 589 var isValid = value.indexOf('%') == -1 && !isNaN( num ); 590 return isValid && num; 591} 592 593function noop() {} 594 595var logError = typeof console == 'undefined' ? noop : 596 function( message ) { 597 console.error( message ); 598 }; 599 600// -------------------------- measurements -------------------------- // 601 602var measurements = [ 603 'paddingLeft', 604 'paddingRight', 605 'paddingTop', 606 'paddingBottom', 607 'marginLeft', 608 'marginRight', 609 'marginTop', 610 'marginBottom', 611 'borderLeftWidth', 612 'borderRightWidth', 613 'borderTopWidth', 614 'borderBottomWidth' 615]; 616 617var measurementsLength = measurements.length; 618 619function getZeroSize() { 620 var size = { 621 width: 0, 622 height: 0, 623 innerWidth: 0, 624 innerHeight: 0, 625 outerWidth: 0, 626 outerHeight: 0 627 }; 628 for ( var i=0; i < measurementsLength; i++ ) { 629 var measurement = measurements[i]; 630 size[ measurement ] = 0; 631 } 632 return size; 633} 634 635// -------------------------- getStyle -------------------------- // 636 637/** 638 * getStyle, get style of element, check for Firefox bug 639 * https://bugzilla.mozilla.org/show_bug.cgi?id=548397 640 */ 641function getStyle( elem ) { 642 var style = getComputedStyle( elem ); 643 if ( !style ) { 644 logError( 'Style returned ' + style + 645 '. Are you running this code in a hidden iframe on Firefox? ' + 646 'See https://bit.ly/getsizebug1' ); 647 } 648 return style; 649} 650 651// -------------------------- setup -------------------------- // 652 653var isSetup = false; 654 655var isBoxSizeOuter; 656 657/** 658 * setup 659 * check isBoxSizerOuter 660 * do on first getSize() rather than on page load for Firefox bug 661 */ 662function setup() { 663 // setup once 664 if ( isSetup ) { 665 return; 666 } 667 isSetup = true; 668 669 // -------------------------- box sizing -------------------------- // 670 671 /** 672 * Chrome & Safari measure the outer-width on style.width on border-box elems 673 * IE11 & Firefox<29 measures the inner-width 674 */ 675 var div = document.createElement('div'); 676 div.style.width = '200px'; 677 div.style.padding = '1px 2px 3px 4px'; 678 div.style.borderStyle = 'solid'; 679 div.style.borderWidth = '1px 2px 3px 4px'; 680 div.style.boxSizing = 'border-box'; 681 682 var body = document.body || document.documentElement; 683 body.appendChild( div ); 684 var style = getStyle( div ); 685 // round value for browser zoom. desandro/masonry#928 686 isBoxSizeOuter = Math.round( getStyleSize( style.width ) ) == 200; 687 getSize.isBoxSizeOuter = isBoxSizeOuter; 688 689 body.removeChild( div ); 690} 691 692// -------------------------- getSize -------------------------- // 693 694function getSize( elem ) { 695 setup(); 696 697 // use querySeletor if elem is string 698 if ( typeof elem == 'string' ) { 699 elem = document.querySelector( elem ); 700 } 701 702 // do not proceed on non-objects 703 if ( !elem || typeof elem != 'object' || !elem.nodeType ) { 704 return; 705 } 706 707 var style = getStyle( elem ); 708 709 // if hidden, everything is 0 710 if ( style.display == 'none' ) { 711 return getZeroSize(); 712 } 713 714 var size = {}; 715 size.width = elem.offsetWidth; 716 size.height = elem.offsetHeight; 717 718 var isBorderBox = size.isBorderBox = style.boxSizing == 'border-box'; 719 720 // get all measurements 721 for ( var i=0; i < measurementsLength; i++ ) { 722 var measurement = measurements[i]; 723 var value = style[ measurement ]; 724 var num = parseFloat( value ); 725 // any 'auto', 'medium' value will be 0 726 size[ measurement ] = !isNaN( num ) ? num : 0; 727 } 728 729 var paddingWidth = size.paddingLeft + size.paddingRight; 730 var paddingHeight = size.paddingTop + size.paddingBottom; 731 var marginWidth = size.marginLeft + size.marginRight; 732 var marginHeight = size.marginTop + size.marginBottom; 733 var borderWidth = size.borderLeftWidth + size.borderRightWidth; 734 var borderHeight = size.borderTopWidth + size.borderBottomWidth; 735 736 var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter; 737 738 // overwrite width and height if we can get it from style 739 var styleWidth = getStyleSize( style.width ); 740 if ( styleWidth !== false ) { 741 size.width = styleWidth + 742 // add padding and border unless it's already including it 743 ( isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth ); 744 } 745 746 var styleHeight = getStyleSize( style.height ); 747 if ( styleHeight !== false ) { 748 size.height = styleHeight + 749 // add padding and border unless it's already including it 750 ( isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight ); 751 } 752 753 size.innerWidth = size.width - ( paddingWidth + borderWidth ); 754 size.innerHeight = size.height - ( paddingHeight + borderHeight ); 755 756 size.outerWidth = size.width + marginWidth; 757 size.outerHeight = size.height + marginHeight; 758 759 return size; 760} 761 762return getSize; 763 764}); 765 766/** 767 * matchesSelector v2.0.2 768 * matchesSelector( element, '.selector' ) 769 * MIT license 770 */ 771 772/*jshint browser: true, strict: true, undef: true, unused: true */ 773 774( function( window, factory ) { 775 /*global define: false, module: false */ 776 'use strict'; 777 // universal module definition 778 if ( typeof define == 'function' && define.amd ) { 779 // AMD 780 define( 'desandro-matches-selector/matches-selector',factory ); 781 } else if ( typeof module == 'object' && module.exports ) { 782 // CommonJS 783 module.exports = factory(); 784 } else { 785 // browser global 786 window.matchesSelector = factory(); 787 } 788 789}( window, function factory() { 790 'use strict'; 791 792 var matchesMethod = ( function() { 793 var ElemProto = window.Element.prototype; 794 // check for the standard method name first 795 if ( ElemProto.matches ) { 796 return 'matches'; 797 } 798 // check un-prefixed 799 if ( ElemProto.matchesSelector ) { 800 return 'matchesSelector'; 801 } 802 // check vendor prefixes 803 var prefixes = [ 'webkit', 'moz', 'ms', 'o' ]; 804 805 for ( var i=0; i < prefixes.length; i++ ) { 806 var prefix = prefixes[i]; 807 var method = prefix + 'MatchesSelector'; 808 if ( ElemProto[ method ] ) { 809 return method; 810 } 811 } 812 })(); 813 814 return function matchesSelector( elem, selector ) { 815 return elem[ matchesMethod ]( selector ); 816 }; 817 818})); 819 820/** 821 * Fizzy UI utils v2.0.7 822 * MIT license 823 */ 824 825/*jshint browser: true, undef: true, unused: true, strict: true */ 826 827( function( window, factory ) { 828 // universal module definition 829 /*jshint strict: false */ /*globals define, module, require */ 830 831 if ( typeof define == 'function' && define.amd ) { 832 // AMD 833 define( 'fizzy-ui-utils/utils',[ 834 'desandro-matches-selector/matches-selector' 835 ], function( matchesSelector ) { 836 return factory( window, matchesSelector ); 837 }); 838 } else if ( typeof module == 'object' && module.exports ) { 839 // CommonJS 840 module.exports = factory( 841 window, 842 require('desandro-matches-selector') 843 ); 844 } else { 845 // browser global 846 window.fizzyUIUtils = factory( 847 window, 848 window.matchesSelector 849 ); 850 } 851 852}( window, function factory( window, matchesSelector ) { 853 854 855 856var utils = {}; 857 858// ----- extend ----- // 859 860// extends objects 861utils.extend = function( a, b ) { 862 for ( var prop in b ) { 863 a[ prop ] = b[ prop ]; 864 } 865 return a; 866}; 867 868// ----- modulo ----- // 869 870utils.modulo = function( num, div ) { 871 return ( ( num % div ) + div ) % div; 872}; 873 874// ----- makeArray ----- // 875 876var arraySlice = Array.prototype.slice; 877 878// turn element or nodeList into an array 879utils.makeArray = function( obj ) { 880 if ( Array.isArray( obj ) ) { 881 // use object if already an array 882 return obj; 883 } 884 // return empty array if undefined or null. #6 885 if ( obj === null || obj === undefined ) { 886 return []; 887 } 888 889 var isArrayLike = typeof obj == 'object' && typeof obj.length == 'number'; 890 if ( isArrayLike ) { 891 // convert nodeList to array 892 return arraySlice.call( obj ); 893 } 894 895 // array of single index 896 return [ obj ]; 897}; 898 899// ----- removeFrom ----- // 900 901utils.removeFrom = function( ary, obj ) { 902 var index = ary.indexOf( obj ); 903 if ( index != -1 ) { 904 ary.splice( index, 1 ); 905 } 906}; 907 908// ----- getParent ----- // 909 910utils.getParent = function( elem, selector ) { 911 while ( elem.parentNode && elem != document.body ) { 912 elem = elem.parentNode; 913 if ( matchesSelector( elem, selector ) ) { 914 return elem; 915 } 916 } 917}; 918 919// ----- getQueryElement ----- // 920 921// use element as selector string 922utils.getQueryElement = function( elem ) { 923 if ( typeof elem == 'string' ) { 924 return document.querySelector( elem ); 925 } 926 return elem; 927}; 928 929// ----- handleEvent ----- // 930 931// enable .ontype to trigger from .addEventListener( elem, 'type' ) 932utils.handleEvent = function( event ) { 933 var method = 'on' + event.type; 934 if ( this[ method ] ) { 935 this[ method ]( event ); 936 } 937}; 938 939// ----- filterFindElements ----- // 940 941utils.filterFindElements = function( elems, selector ) { 942 // make array of elems 943 elems = utils.makeArray( elems ); 944 var ffElems = []; 945 946 elems.forEach( function( elem ) { 947 // check that elem is an actual element 948
948// START UNCODE EDIT 949 // if ( !( elem instanceof HTMLElement ) ) { 950 if ( !( elem instanceof HTMLElement ) && !SiteParameters.is_frontend_editor ) { 951 // END UNCODE EDIT
vendor: 75,264 bytes, lines 951-3856
951 952 return; 953 } 954 // add elem if no selector 955 if ( !selector ) { 956 ffElems.push( elem ); 957 return; 958 } 959 // filter & find items if we have a selector 960 // filter 961 if ( matchesSelector( elem, selector ) ) { 962 ffElems.push( elem ); 963 } 964 // find children 965 var childElems = elem.querySelectorAll( selector ); 966 // concat childElems to filterFound array 967 for ( var i=0; i < childElems.length; i++ ) { 968 ffElems.push( childElems[i] ); 969 } 970 }); 971 972 return ffElems; 973}; 974 975// ----- debounceMethod ----- // 976 977utils.debounceMethod = function( _class, methodName, threshold ) { 978 threshold = threshold || 100; 979 // original method 980 var method = _class.prototype[ methodName ]; 981 var timeoutName = methodName + 'Timeout'; 982 983 _class.prototype[ methodName ] = function() { 984 var timeout = this[ timeoutName ]; 985 clearTimeout( timeout ); 986 987 var args = arguments; 988 var _this = this; 989 this[ timeoutName ] = setTimeout( function() { 990 method.apply( _this, args ); 991 delete _this[ timeoutName ]; 992 }, threshold ); 993 }; 994}; 995 996// ----- docReady ----- // 997 998utils.docReady = function( callback ) { 999 var readyState = document.readyState; 1000 if ( readyState == 'complete' || readyState == 'interactive' ) { 1001 // do async to allow for other scripts to run. metafizzy/flickity#441 1002 setTimeout( callback ); 1003 } else { 1004 document.addEventListener( 'DOMContentLoaded', callback ); 1005 } 1006}; 1007 1008// ----- htmlInit ----- // 1009 1010// http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/ 1011utils.toDashed = function( str ) { 1012 return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) { 1013 return $1 + '-' + $2; 1014 }).toLowerCase(); 1015}; 1016 1017var console = window.console; 1018/** 1019 * allow user to initialize classes via [data-namespace] or .js-namespace class 1020 * htmlInit( Widget, 'widgetName' ) 1021 * options are parsed from data-namespace-options 1022 */ 1023utils.htmlInit = function( WidgetClass, namespace ) { 1024 utils.docReady( function() { 1025 var dashedNamespace = utils.toDashed( namespace ); 1026 var dataAttr = 'data-' + dashedNamespace; 1027 var dataAttrElems = document.querySelectorAll( '[' + dataAttr + ']' ); 1028 var jsDashElems = document.querySelectorAll( '.js-' + dashedNamespace ); 1029 var elems = utils.makeArray( dataAttrElems ) 1030 .concat( utils.makeArray( jsDashElems ) ); 1031 var dataOptionsAttr = dataAttr + '-options'; 1032 var jQuery = window.jQuery; 1033 1034 elems.forEach( function( elem ) { 1035 var attr = elem.getAttribute( dataAttr ) || 1036 elem.getAttribute( dataOptionsAttr ); 1037 var options; 1038 try { 1039 options = attr && JSON.parse( attr ); 1040 } catch ( error ) { 1041 // log error, do not initialize 1042 if ( console ) { 1043 console.error( 'Error parsing ' + dataAttr + ' on ' + elem.className + 1044 ': ' + error ); 1045 } 1046 return; 1047 } 1048 // initialize 1049 var instance = new WidgetClass( elem, options ); 1050 // make available via $().data('namespace') 1051 if ( jQuery ) { 1052 jQuery.data( elem, namespace, instance ); 1053 } 1054 }); 1055 1056 }); 1057}; 1058 1059// ----- ----- // 1060 1061return utils; 1062 1063})); 1064 1065/** 1066 * Outlayer Item 1067 */ 1068 1069( function( window, factory ) { 1070 // universal module definition 1071 /* jshint strict: false */ /* globals define, module, require */ 1072 if ( typeof define == 'function' && define.amd ) { 1073 // AMD - RequireJS 1074 define( 'outlayer/item',[ 1075 'ev-emitter/ev-emitter', 1076 'get-size/get-size' 1077 ], 1078 factory 1079 ); 1080 } else if ( typeof module == 'object' && module.exports ) { 1081 // CommonJS - Browserify, Webpack 1082 module.exports = factory( 1083 require('ev-emitter'), 1084 require('get-size') 1085 ); 1086 } else { 1087 // browser global 1088 window.Outlayer = {}; 1089 window.Outlayer.Item = factory( 1090 window.EvEmitter, 1091 window.getSize 1092 ); 1093 } 1094 1095}( window, function factory( EvEmitter, getSize ) { 1096'use strict'; 1097 1098// ----- helpers ----- // 1099 1100function isEmptyObj( obj ) { 1101 for ( var prop in obj ) { 1102 return false; 1103 } 1104 prop = null; 1105 return true; 1106} 1107 1108// -------------------------- CSS3 support -------------------------- // 1109 1110 1111var docElemStyle = document.documentElement.style; 1112 1113var transitionProperty = typeof docElemStyle.transition == 'string' ? 1114 'transition' : 'WebkitTransition'; 1115var transformProperty = typeof docElemStyle.transform == 'string' ? 1116 'transform' : 'WebkitTransform'; 1117 1118var transitionEndEvent = { 1119 WebkitTransition: 'webkitTransitionEnd', 1120 transition: 'transitionend' 1121}[ transitionProperty ]; 1122 1123// cache all vendor properties that could have vendor prefix 1124var vendorProperties = { 1125 transform: transformProperty, 1126 transition: transitionProperty, 1127 transitionDuration: transitionProperty + 'Duration', 1128 transitionProperty: transitionProperty + 'Property', 1129 transitionDelay: transitionProperty + 'Delay' 1130}; 1131 1132// -------------------------- Item -------------------------- // 1133 1134function Item( element, layout ) { 1135 if ( !element ) { 1136 return; 1137 } 1138 1139 this.element = element; 1140 // parent layout class, i.e. Masonry, Isotope, or Packery 1141 this.layout = layout; 1142 this.position = { 1143 x: 0, 1144 y: 0 1145 }; 1146 1147 this._create(); 1148} 1149 1150// inherit EvEmitter 1151var proto = Item.prototype = Object.create( EvEmitter.prototype ); 1152proto.constructor = Item; 1153 1154proto._create = function() { 1155 // transition objects 1156 this._transn = { 1157 ingProperties: {}, 1158 clean: {}, 1159 onEnd: {} 1160 }; 1161 1162 this.css({ 1163 position: 'absolute' 1164 }); 1165}; 1166 1167// trigger specified handler for event type 1168proto.handleEvent = function( event ) { 1169 var method = 'on' + event.type; 1170 if ( this[ method ] ) { 1171 this[ method ]( event ); 1172 } 1173}; 1174 1175proto.getSize = function() { 1176 this.size = getSize( this.element ); 1177}; 1178 1179/** 1180 * apply CSS styles to element 1181 * @param {Object} style 1182 */ 1183proto.css = function( style ) { 1184 var elemStyle = this.element.style; 1185 1186 for ( var prop in style ) { 1187 // use vendor property if available 1188 var supportedProp = vendorProperties[ prop ] || prop; 1189 elemStyle[ supportedProp ] = style[ prop ]; 1190 } 1191}; 1192 1193 // measure position, and sets it 1194proto.getPosition = function() { 1195 var style = getComputedStyle( this.element ); 1196 var isOriginLeft = this.layout._getOption('originLeft'); 1197 var isOriginTop = this.layout._getOption('originTop'); 1198 var xValue = style[ isOriginLeft ? 'left' : 'right' ]; 1199 var yValue = style[ isOriginTop ? 'top' : 'bottom' ]; 1200 var x = parseFloat( xValue ); 1201 var y = parseFloat( yValue ); 1202 // convert percent to pixels 1203 var layoutSize = this.layout.size; 1204 if ( xValue.indexOf('%') != -1 ) { 1205 x = ( x / 100 ) * layoutSize.width; 1206 } 1207 if ( yValue.indexOf('%') != -1 ) { 1208 y = ( y / 100 ) * layoutSize.height; 1209 } 1210 // clean up 'auto' or other non-integer values 1211 x = isNaN( x ) ? 0 : x; 1212 y = isNaN( y ) ? 0 : y; 1213 // remove padding from measurement 1214 x -= isOriginLeft ? layoutSize.paddingLeft : layoutSize.paddingRight; 1215 y -= isOriginTop ? layoutSize.paddingTop : layoutSize.paddingBottom; 1216 1217 this.position.x = x; 1218 this.position.y = y; 1219}; 1220 1221// set settled position, apply padding 1222proto.layoutPosition = function() { 1223 var layoutSize = this.layout.size; 1224 var style = {}; 1225 var isOriginLeft = this.layout._getOption('originLeft'); 1226 var isOriginTop = this.layout._getOption('originTop'); 1227 1228 // x 1229 var xPadding = isOriginLeft ? 'paddingLeft' : 'paddingRight'; 1230 var xProperty = isOriginLeft ? 'left' : 'right'; 1231 var xResetProperty = isOriginLeft ? 'right' : 'left'; 1232 1233 var x = this.position.x + layoutSize[ xPadding ]; 1234 // set in percentage or pixels 1235 style[ xProperty ] = this.getXValue( x ); 1236 // reset other property 1237 style[ xResetProperty ] = ''; 1238 1239 // y 1240 var yPadding = isOriginTop ? 'paddingTop' : 'paddingBottom'; 1241 var yProperty = isOriginTop ? 'top' : 'bottom'; 1242 var yResetProperty = isOriginTop ? 'bottom' : 'top'; 1243 1244 var y = this.position.y + layoutSize[ yPadding ]; 1245 // set in percentage or pixels 1246 style[ yProperty ] = this.getYValue( y ); 1247 // reset other property 1248 style[ yResetProperty ] = ''; 1249 1250 this.css( style ); 1251 this.emitEvent( 'layout', [ this ] ); 1252}; 1253 1254proto.getXValue = function( x ) { 1255 var isHorizontal = this.layout._getOption('horizontal'); 1256 return this.layout.options.percentPosition && !isHorizontal ? 1257 ( ( x / this.layout.size.width ) * 100 ) + '%' : x + 'px'; 1258}; 1259 1260proto.getYValue = function( y ) { 1261 var isHorizontal = this.layout._getOption('horizontal'); 1262 return this.layout.options.percentPosition && isHorizontal ? 1263 ( ( y / this.layout.size.height ) * 100 ) + '%' : y + 'px'; 1264}; 1265 1266proto._transitionTo = function( x, y ) { 1267 this.getPosition(); 1268 // get current x & y from top/left 1269 var curX = this.position.x; 1270 var curY = this.position.y; 1271 1272 var didNotMove = x == this.position.x && y == this.position.y; 1273 1274 // save end position 1275 this.setPosition( x, y ); 1276 1277 // if did not move and not transitioning, just go to layout 1278 if ( didNotMove && !this.isTransitioning ) { 1279 this.layoutPosition(); 1280 return; 1281 } 1282 1283 var transX = x - curX; 1284 var transY = y - curY; 1285 var transitionStyle = {}; 1286 transitionStyle.transform = this.getTranslate( transX, transY ); 1287 1288 this.transition({ 1289 to: transitionStyle, 1290 onTransitionEnd: { 1291 transform: this.layoutPosition 1292 }, 1293 isCleaning: true 1294 }); 1295}; 1296 1297proto.getTranslate = function( x, y ) { 1298 // flip cooridinates if origin on right or bottom 1299 var isOriginLeft = this.layout._getOption('originLeft'); 1300 var isOriginTop = this.layout._getOption('originTop'); 1301 x = isOriginLeft ? x : -x; 1302 y = isOriginTop ? y : -y; 1303 return 'translate3d(' + x + 'px, ' + y + 'px, 0)'; 1304}; 1305 1306// non transition + transform support 1307proto.goTo = function( x, y ) { 1308 this.setPosition( x, y ); 1309 this.layoutPosition(); 1310}; 1311 1312proto.moveTo = proto._transitionTo; 1313 1314proto.setPosition = function( x, y ) { 1315 this.position.x = parseFloat( x ); 1316 this.position.y = parseFloat( y ); 1317}; 1318 1319// ----- transition ----- // 1320 1321/** 1322 * @param {Object} style - CSS 1323 * @param {Function} onTransitionEnd 1324 */ 1325 1326// non transition, just trigger callback 1327proto._nonTransition = function( args ) { 1328 this.css( args.to ); 1329 if ( args.isCleaning ) { 1330 this._removeStyles( args.to ); 1331 } 1332 for ( var prop in args.onTransitionEnd ) { 1333 args.onTransitionEnd[ prop ].call( this ); 1334 } 1335}; 1336 1337/** 1338 * proper transition 1339 * @param {Object} args - arguments 1340 * @param {Object} to - style to transition to 1341 * @param {Object} from - style to start transition from 1342 * @param {Boolean} isCleaning - removes transition styles after transition 1343 * @param {Function} onTransitionEnd - callback 1344 */ 1345proto.transition = function( args ) { 1346 // redirect to nonTransition if no transition duration 1347 if ( !parseFloat( this.layout.options.transitionDuration ) ) { 1348 this._nonTransition( args ); 1349 return; 1350 } 1351 1352 var _transition = this._transn; 1353 // keep track of onTransitionEnd callback by css property 1354 for ( var prop in args.onTransitionEnd ) { 1355 _transition.onEnd[ prop ] = args.onTransitionEnd[ prop ]; 1356 } 1357 // keep track of properties that are transitioning 1358 for ( prop in args.to ) { 1359 _transition.ingProperties[ prop ] = true; 1360 // keep track of properties to clean up when transition is done 1361 if ( args.isCleaning ) { 1362 _transition.clean[ prop ] = true; 1363 } 1364 } 1365 1366 // set from styles 1367 if ( args.from ) { 1368 this.css( args.from ); 1369 // force redraw. http://blog.alexmaccaw.com/css-transitions 1370 var h = this.element.offsetHeight; 1371 // hack for JSHint to hush about unused var 1372 h = null; 1373 } 1374 // enable transition 1375 this.enableTransition( args.to ); 1376 // set styles that are transitioning 1377 this.css( args.to ); 1378 1379 this.isTransitioning = true; 1380 1381}; 1382 1383// dash before all cap letters, including first for 1384// WebkitTransform => -webkit-transform 1385function toDashedAll( str ) { 1386 return str.replace( /([A-Z])/g, function( $1 ) { 1387 return '-' + $1.toLowerCase(); 1388 }); 1389} 1390 1391var transitionProps = 'opacity,' + toDashedAll( transformProperty ); 1392 1393proto.enableTransition = function(/* style */) { 1394 // HACK changing transitionProperty during a transition 1395 // will cause transition to jump 1396 if ( this.isTransitioning ) { 1397 return; 1398 } 1399 1400 // make `transition: foo, bar, baz` from style object 1401 // HACK un-comment this when enableTransition can work 1402 // while a transition is happening 1403 // var transitionValues = []; 1404 // for ( var prop in style ) { 1405 // // dash-ify camelCased properties like WebkitTransition 1406 // prop = vendorProperties[ prop ] || prop; 1407 // transitionValues.push( toDashedAll( prop ) ); 1408 // } 1409 // munge number to millisecond, to match stagger 1410 var duration = this.layout.options.transitionDuration; 1411 duration = typeof duration == 'number' ? duration + 'ms' : duration; 1412 // enable transition styles 1413 this.css({ 1414 transitionProperty: transitionProps, 1415 transitionDuration: duration, 1416 transitionDelay: this.staggerDelay || 0 1417 }); 1418 // listen for transition end event 1419 this.element.addEventListener( transitionEndEvent, this, false ); 1420}; 1421 1422// ----- events ----- // 1423 1424proto.onwebkitTransitionEnd = function( event ) { 1425 this.ontransitionend( event ); 1426}; 1427 1428proto.onotransitionend = function( event ) { 1429 this.ontransitionend( event ); 1430}; 1431 1432// properties that I munge to make my life easier 1433var dashedVendorProperties = { 1434 '-webkit-transform': 'transform' 1435}; 1436 1437proto.ontransitionend = function( event ) { 1438 // disregard bubbled events from children 1439 if ( event.target !== this.element ) { 1440 return; 1441 } 1442 var _transition = this._transn; 1443 // get property name of transitioned property, convert to prefix-free 1444 var propertyName = dashedVendorProperties[ event.propertyName ] || event.propertyName; 1445 1446 // remove property that has completed transitioning 1447 delete _transition.ingProperties[ propertyName ]; 1448 // check if any properties are still transitioning 1449 if ( isEmptyObj( _transition.ingProperties ) ) { 1450 // all properties have completed transitioning 1451 this.disableTransition(); 1452 } 1453 // clean style 1454 if ( propertyName in _transition.clean ) { 1455 // clean up style 1456 this.element.style[ event.propertyName ] = ''; 1457 delete _transition.clean[ propertyName ]; 1458 } 1459 // trigger onTransitionEnd callback 1460 if ( propertyName in _transition.onEnd ) { 1461 var onTransitionEnd = _transition.onEnd[ propertyName ]; 1462 onTransitionEnd.call( this ); 1463 delete _transition.onEnd[ propertyName ]; 1464 } 1465 1466 this.emitEvent( 'transitionEnd', [ this ] ); 1467}; 1468 1469proto.disableTransition = function() { 1470 this.removeTransitionStyles(); 1471 this.element.removeEventListener( transitionEndEvent, this, false ); 1472 this.isTransitioning = false; 1473}; 1474 1475/** 1476 * removes style property from element 1477 * @param {Object} style 1478**/ 1479proto._removeStyles = function( style ) { 1480 // clean up transition styles 1481 var cleanStyle = {}; 1482 for ( var prop in style ) { 1483 cleanStyle[ prop ] = ''; 1484 } 1485 this.css( cleanStyle ); 1486}; 1487 1488var cleanTransitionStyle = { 1489 transitionProperty: '', 1490 transitionDuration: '', 1491 transitionDelay: '' 1492}; 1493 1494proto.removeTransitionStyles = function() { 1495 // remove transition 1496 this.css( cleanTransitionStyle ); 1497}; 1498 1499// ----- stagger ----- // 1500 1501proto.stagger = function( delay ) { 1502 delay = isNaN( delay ) ? 0 : delay; 1503 this.staggerDelay = delay + 'ms'; 1504}; 1505 1506// ----- show/hide/remove ----- // 1507 1508// remove element from DOM 1509proto.removeElem = function() { 1510 this.element.parentNode.removeChild( this.element ); 1511 // remove display: none 1512 this.css({ display: '' }); 1513 this.emitEvent( 'remove', [ this ] ); 1514}; 1515 1516proto.remove = function() { 1517 // just remove element if no transition support or no transition 1518 if ( !transitionProperty || !parseFloat( this.layout.options.transitionDuration ) ) { 1519 this.removeElem(); 1520 return; 1521 } 1522 1523 // start transition 1524 this.once( 'transitionEnd', function() { 1525 this.removeElem(); 1526 }); 1527 this.hide(); 1528}; 1529 1530proto.reveal = function() { 1531 delete this.isHidden; 1532 // remove display: none 1533 this.css({ display: '' }); 1534 1535 var options = this.layout.options; 1536 1537 var onTransitionEnd = {}; 1538 var transitionEndProperty = this.getHideRevealTransitionEndProperty('visibleStyle'); 1539 onTransitionEnd[ transitionEndProperty ] = this.onRevealTransitionEnd; 1540 1541 this.transition({ 1542 from: options.hiddenStyle, 1543 to: options.visibleStyle, 1544 isCleaning: true, 1545 onTransitionEnd: onTransitionEnd 1546 }); 1547}; 1548 1549proto.onRevealTransitionEnd = function() { 1550 // check if still visible 1551 // during transition, item may have been hidden 1552 if ( !this.isHidden ) { 1553 this.emitEvent('reveal'); 1554 } 1555}; 1556 1557/** 1558 * get style property use for hide/reveal transition end 1559 * @param {String} styleProperty - hiddenStyle/visibleStyle 1560 * @returns {String} 1561 */ 1562proto.getHideRevealTransitionEndProperty = function( styleProperty ) { 1563 var optionStyle = this.layout.options[ styleProperty ]; 1564 // use opacity 1565 if ( optionStyle.opacity ) { 1566 return 'opacity'; 1567 } 1568 // get first property 1569 for ( var prop in optionStyle ) { 1570 return prop; 1571 } 1572}; 1573 1574proto.hide = function() { 1575 // set flag 1576 this.isHidden = true; 1577 // remove display: none 1578 this.css({ display: '' }); 1579 1580 var options = this.layout.options; 1581 1582 var onTransitionEnd = {}; 1583 var transitionEndProperty = this.getHideRevealTransitionEndProperty('hiddenStyle'); 1584 onTransitionEnd[ transitionEndProperty ] = this.onHideTransitionEnd; 1585 1586 this.transition({ 1587 from: options.visibleStyle, 1588 to: options.hiddenStyle, 1589 // keep hidden stuff hidden 1590 isCleaning: true, 1591 onTransitionEnd: onTransitionEnd 1592 }); 1593}; 1594 1595proto.onHideTransitionEnd = function() { 1596 // check if still hidden 1597 // during transition, item may have been un-hidden 1598 if ( this.isHidden ) { 1599 this.css({ display: 'none' }); 1600 this.emitEvent('hide'); 1601 } 1602}; 1603 1604proto.destroy = function() { 1605 this.css({ 1606 position: '', 1607 left: '', 1608 right: '', 1609 top: '', 1610 bottom: '', 1611 transition: '', 1612 transform: '' 1613 }); 1614}; 1615 1616return Item; 1617 1618})); 1619 1620/*! 1621 * Outlayer v2.1.1 1622 * the brains and guts of a layout library 1623 * MIT license 1624 */ 1625 1626( function( window, factory ) { 1627 'use strict'; 1628 // universal module definition 1629 /* jshint strict: false */ /* globals define, module, require */ 1630 if ( typeof define == 'function' && define.amd ) { 1631 // AMD - RequireJS 1632 define( 'outlayer/outlayer',[ 1633 'ev-emitter/ev-emitter', 1634 'get-size/get-size', 1635 'fizzy-ui-utils/utils', 1636 './item' 1637 ], 1638 function( EvEmitter, getSize, utils, Item ) { 1639 return factory( window, EvEmitter, getSize, utils, Item); 1640 } 1641 ); 1642 } else if ( typeof module == 'object' && module.exports ) { 1643 // CommonJS - Browserify, Webpack 1644 module.exports = factory( 1645 window, 1646 require('ev-emitter'), 1647 require('get-size'), 1648 require('fizzy-ui-utils'), 1649 require('./item') 1650 ); 1651 } else { 1652 // browser global 1653 window.Outlayer = factory( 1654 window, 1655 window.EvEmitter, 1656 window.getSize, 1657 window.fizzyUIUtils, 1658 window.Outlayer.Item 1659 ); 1660 } 1661 1662}( window, function factory( window, EvEmitter, getSize, utils, Item ) { 1663'use strict'; 1664 1665// ----- vars ----- // 1666 1667var console = window.console; 1668var jQuery = window.jQuery; 1669var noop = function() {}; 1670 1671// -------------------------- Outlayer -------------------------- // 1672 1673// globally unique identifiers 1674var GUID = 0; 1675// internal store of all Outlayer intances 1676var instances = {}; 1677 1678 1679/** 1680 * @param {Element, String} element 1681 * @param {Object} options 1682 * @constructor 1683 */ 1684function Outlayer( element, options ) { 1685 var queryElement = utils.getQueryElement( element ); 1686 if ( !queryElement ) { 1687 if ( console ) { 1688 console.error( 'Bad element for ' + this.constructor.namespace + 1689 ': ' + ( queryElement || element ) ); 1690 } 1691 return; 1692 } 1693 this.element = queryElement; 1694 // add jQuery 1695 if ( jQuery ) { 1696 this.$element = jQuery( this.element ); 1697 } 1698 1699 // options 1700 this.options = utils.extend( {}, this.constructor.defaults ); 1701 this.option( options ); 1702 1703 // add id for Outlayer.getFromElement 1704 var id = ++GUID; 1705 this.element.outlayerGUID = id; // expando 1706 instances[ id ] = this; // associate via id 1707 1708 // kick it off 1709 this._create(); 1710 1711 var isInitLayout = this._getOption('initLayout'); 1712 if ( isInitLayout ) { 1713 this.layout(); 1714 } 1715} 1716 1717// settings are for internal use only 1718Outlayer.namespace = 'outlayer'; 1719Outlayer.Item = Item; 1720 1721// default options 1722Outlayer.defaults = { 1723 containerStyle: { 1724 position: 'relative' 1725 }, 1726 initLayout: true, 1727 originLeft: true, 1728 originTop: true, 1729 resize: true, 1730 resizeContainer: true, 1731 // item options 1732 transitionDuration: '0.4s', 1733 hiddenStyle: { 1734 opacity: 0, 1735 transform: 'scale(0.001)' 1736 }, 1737 visibleStyle: { 1738 opacity: 1, 1739 transform: 'scale(1)' 1740 } 1741}; 1742 1743var proto = Outlayer.prototype; 1744// inherit EvEmitter 1745utils.extend( proto, EvEmitter.prototype ); 1746 1747/** 1748 * set options 1749 * @param {Object} opts 1750 */ 1751proto.option = function( opts ) { 1752 utils.extend( this.options, opts ); 1753}; 1754 1755/** 1756 * get backwards compatible option value, check old name 1757 */ 1758proto._getOption = function( option ) { 1759 var oldOption = this.constructor.compatOptions[ option ]; 1760 return oldOption && this.options[ oldOption ] !== undefined ? 1761 this.options[ oldOption ] : this.options[ option ]; 1762}; 1763 1764Outlayer.compatOptions = { 1765 // currentName: oldName 1766 initLayout: 'isInitLayout', 1767 horizontal: 'isHorizontal', 1768 layoutInstant: 'isLayoutInstant', 1769 originLeft: 'isOriginLeft', 1770 originTop: 'isOriginTop', 1771 resize: 'isResizeBound', 1772 resizeContainer: 'isResizingContainer' 1773}; 1774 1775proto._create = function() { 1776 // get items from children 1777 this.reloadItems(); 1778 // elements that affect layout, but are not laid out 1779 this.stamps = []; 1780 this.stamp( this.options.stamp ); 1781 // set container style 1782 utils.extend( this.element.style, this.options.containerStyle ); 1783 1784 // bind resize method 1785 var canBindResize = this._getOption('resize'); 1786 if ( canBindResize ) { 1787 this.bindResize(); 1788 } 1789}; 1790 1791// goes through all children again and gets bricks in proper order 1792proto.reloadItems = function() { 1793 // collection of item elements 1794 this.items = this._itemize( this.element.children ); 1795}; 1796 1797 1798/** 1799 * turn elements into Outlayer.Items to be used in layout 1800 * @param {Array or NodeList or HTMLElement} elems 1801 * @returns {Array} items - collection of new Outlayer Items 1802 */ 1803proto._itemize = function( elems ) { 1804 1805 var itemElems = this._filterFindItemElements( elems ); 1806 var Item = this.constructor.Item; 1807 1808 // create new Outlayer Items for collection 1809 var items = []; 1810 for ( var i=0; i < itemElems.length; i++ ) { 1811 var elem = itemElems[i]; 1812 var item = new Item( elem, this ); 1813 items.push( item ); 1814 } 1815 1816 return items; 1817}; 1818 1819/** 1820 * get item elements to be used in layout 1821 * @param {Array or NodeList or HTMLElement} elems 1822 * @returns {Array} items - item elements 1823 */ 1824proto._filterFindItemElements = function( elems ) { 1825 return utils.filterFindElements( elems, this.options.itemSelector ); 1826}; 1827 1828/** 1829 * getter method for getting item elements 1830 * @returns {Array} elems - collection of item elements 1831 */ 1832proto.getItemElements = function() { 1833 return this.items.map( function( item ) { 1834 return item.element; 1835 }); 1836}; 1837 1838// ----- init & layout ----- // 1839 1840/** 1841 * lays out all items 1842 */ 1843proto.layout = function() { 1844 this._resetLayout(); 1845 this._manageStamps(); 1846 1847 // don't animate first layout 1848 var layoutInstant = this._getOption('layoutInstant'); 1849 var isInstant = layoutInstant !== undefined ? 1850 layoutInstant : !this._isLayoutInited; 1851 this.layoutItems( this.items, isInstant ); 1852 1853 // flag for initalized 1854 this._isLayoutInited = true; 1855}; 1856 1857// _init is alias for layout 1858proto._init = proto.layout; 1859 1860/** 1861 * logic before any new layout 1862 */ 1863proto._resetLayout = function() { 1864 this.getSize(); 1865}; 1866 1867 1868proto.getSize = function() { 1869 this.size = getSize( this.element ); 1870}; 1871 1872/** 1873 * get measurement from option, for columnWidth, rowHeight, gutter 1874 * if option is String -> get element from selector string, & get size of element 1875 * if option is Element -> get size of element 1876 * else use option as a number 1877 * 1878 * @param {String} measurement 1879 * @param {String} size - width or height 1880 * @private 1881 */ 1882proto._getMeasurement = function( measurement, size ) { 1883 var option = this.options[ measurement ]; 1884 var elem; 1885 if ( !option ) { 1886 // default to 0 1887 this[ measurement ] = 0; 1888 } else { 1889 // use option as an element 1890 if ( typeof option == 'string' ) { 1891 elem = this.element.querySelector( option ); 1892 } else if ( option instanceof HTMLElement ) { 1893 elem = option; 1894 } 1895 // use size of element, if element 1896 this[ measurement ] = elem ? getSize( elem )[ size ] : option; 1897 } 1898}; 1899 1900/** 1901 * layout a collection of item elements 1902 * @api public 1903 */ 1904proto.layoutItems = function( items, isInstant ) { 1905 items = this._getItemsForLayout( items ); 1906 1907 this._layoutItems( items, isInstant ); 1908 1909 this._postLayout(); 1910}; 1911 1912/** 1913 * get the items to be laid out 1914 * you may want to skip over some items 1915 * @param {Array} items 1916 * @returns {Array} items 1917 */ 1918proto._getItemsForLayout = function( items ) { 1919 return items.filter( function( item ) { 1920 return !item.isIgnored; 1921 }); 1922}; 1923 1924/** 1925 * layout items 1926 * @param {Array} items 1927 * @param {Boolean} isInstant 1928 */ 1929proto._layoutItems = function( items, isInstant ) { 1930 this._emitCompleteOnItems( 'layout', items ); 1931 1932 if ( !items || !items.length ) { 1933 // no items, emit event with empty array 1934 return; 1935 } 1936 1937 var queue = []; 1938 1939 items.forEach( function( item ) { 1940 // get x/y object from method 1941 var position = this._getItemLayoutPosition( item ); 1942 // enqueue 1943 position.item = item; 1944 position.isInstant = isInstant || item.isLayoutInstant; 1945 queue.push( position ); 1946 }, this ); 1947 1948 this._processLayoutQueue( queue ); 1949}; 1950 1951/** 1952 * get item layout position 1953 * @param {Outlayer.Item} item 1954 * @returns {Object} x and y position 1955 */ 1956proto._getItemLayoutPosition = function( /* item */ ) { 1957 return { 1958 x: 0, 1959 y: 0 1960 }; 1961}; 1962 1963/** 1964 * iterate over array and position each item 1965 * Reason being - separating this logic prevents 'layout invalidation' 1966 * thx @paul_irish 1967 * @param {Array} queue 1968 */ 1969proto._processLayoutQueue = function( queue ) { 1970 this.updateStagger(); 1971 queue.forEach( function( obj, i ) { 1972 this._positionItem( obj.item, obj.x, obj.y, obj.isInstant, i ); 1973 }, this ); 1974}; 1975 1976// set stagger from option in milliseconds number 1977proto.updateStagger = function() { 1978 var stagger = this.options.stagger; 1979 if ( stagger === null || stagger === undefined ) { 1980 this.stagger = 0; 1981 return; 1982 } 1983 this.stagger = getMilliseconds( stagger ); 1984 return this.stagger; 1985}; 1986 1987/** 1988 * Sets position of item in DOM 1989 * @param {Outlayer.Item} item 1990 * @param {Number} x - horizontal position 1991 * @param {Number} y - vertical position 1992 * @param {Boolean} isInstant - disables transitions 1993 */ 1994proto._positionItem = function( item, x, y, isInstant, i ) { 1995 if ( isInstant ) { 1996 // if not transition, just set CSS 1997 item.goTo( x, y ); 1998 } else { 1999 item.stagger( i * this.stagger ); 2000 item.moveTo( x, y ); 2001 } 2002}; 2003 2004/** 2005 * Any logic you want to do after each layout, 2006 * i.e. size the container 2007 */ 2008proto._postLayout = function() { 2009 this.resizeContainer(); 2010}; 2011 2012proto.resizeContainer = function() { 2013 var isResizingContainer = this._getOption('resizeContainer'); 2014 if ( !isResizingContainer ) { 2015 return; 2016 } 2017 var size = this._getContainerSize(); 2018 if ( size ) { 2019 this._setContainerMeasure( size.width, true ); 2020 this._setContainerMeasure( size.height, false ); 2021 } 2022}; 2023 2024/** 2025 * Sets width or height of container if returned 2026 * @returns {Object} size 2027 * @param {Number} width 2028 * @param {Number} height 2029 */ 2030proto._getContainerSize = noop; 2031 2032/** 2033 * @param {Number} measure - size of width or height 2034 * @param {Boolean} isWidth 2035 */ 2036proto._setContainerMeasure = function( measure, isWidth ) { 2037 if ( measure === undefined ) { 2038 return; 2039 } 2040 2041 var elemSize = this.size; 2042 // add padding and border width if border box 2043 if ( elemSize.isBorderBox ) { 2044 measure += isWidth ? elemSize.paddingLeft + elemSize.paddingRight + 2045 elemSize.borderLeftWidth + elemSize.borderRightWidth : 2046 elemSize.paddingBottom + elemSize.paddingTop + 2047 elemSize.borderTopWidth + elemSize.borderBottomWidth; 2048 } 2049 2050 measure = Math.max( measure, 0 ); 2051 this.element.style[ isWidth ? 'width' : 'height' ] = measure + 'px'; 2052}; 2053 2054/** 2055 * emit eventComplete on a collection of items events 2056 * @param {String} eventName 2057 * @param {Array} items - Outlayer.Items 2058 */ 2059proto._emitCompleteOnItems = function( eventName, items ) { 2060 var _this = this; 2061 function onComplete() { 2062 _this.dispatchEvent( eventName + 'Complete', null, [ items ] ); 2063 } 2064 2065 var count = items.length; 2066 if ( !items || !count ) { 2067 onComplete(); 2068 return; 2069 } 2070 2071 var doneCount = 0; 2072 function tick() { 2073 doneCount++; 2074 if ( doneCount == count ) { 2075 onComplete(); 2076 } 2077 } 2078 2079 // bind callback 2080 items.forEach( function( item ) { 2081 item.once( eventName, tick ); 2082 }); 2083}; 2084 2085/** 2086 * emits events via EvEmitter and jQuery events 2087 * @param {String} type - name of event 2088 * @param {Event} event - original event 2089 * @param {Array} args - extra arguments 2090 */ 2091proto.dispatchEvent = function( type, event, args ) { 2092 // add original event to arguments 2093 var emitArgs = event ? [ event ].concat( args ) : args; 2094 this.emitEvent( type, emitArgs ); 2095 2096 if ( jQuery ) { 2097 // set this.$element 2098 this.$element = this.$element || jQuery( this.element ); 2099 if ( event ) { 2100 // create jQuery event 2101 var $event = jQuery.Event( event ); 2102 $event.type = type; 2103 this.$element.trigger( $event, args ); 2104 } else { 2105 // just trigger with type if no event available 2106 this.$element.trigger( type, args ); 2107 } 2108 } 2109}; 2110 2111// -------------------------- ignore & stamps -------------------------- // 2112 2113 2114/** 2115 * keep item in collection, but do not lay it out 2116 * ignored items do not get skipped in layout 2117 * @param {Element} elem 2118 */ 2119proto.ignore = function( elem ) { 2120 var item = this.getItem( elem ); 2121 if ( item ) { 2122 item.isIgnored = true; 2123 } 2124}; 2125 2126/** 2127 * return item to layout collection 2128 * @param {Element} elem 2129 */ 2130proto.unignore = function( elem ) { 2131 var item = this.getItem( elem ); 2132 if ( item ) { 2133 delete item.isIgnored; 2134 } 2135}; 2136 2137/** 2138 * adds elements to stamps 2139 * @param {NodeList, Array, Element, or String} elems 2140 */ 2141proto.stamp = function( elems ) { 2142 elems = this._find( elems ); 2143 if ( !elems ) { 2144 return; 2145 } 2146 2147 this.stamps = this.stamps.concat( elems ); 2148 // ignore 2149 elems.forEach( this.ignore, this ); 2150}; 2151 2152/** 2153 * removes elements to stamps 2154 * @param {NodeList, Array, or Element} elems 2155 */ 2156proto.unstamp = function( elems ) { 2157 elems = this._find( elems ); 2158 if ( !elems ){ 2159 return; 2160 } 2161 2162 elems.forEach( function( elem ) { 2163 // filter out removed stamp elements 2164 utils.removeFrom( this.stamps, elem ); 2165 this.unignore( elem ); 2166 }, this ); 2167}; 2168 2169/** 2170 * finds child elements 2171 * @param {NodeList, Array, Element, or String} elems 2172 * @returns {Array} elems 2173 */ 2174proto._find = function( elems ) { 2175 if ( !elems ) { 2176 return; 2177 } 2178 // if string, use argument as selector string 2179 if ( typeof elems == 'string' ) { 2180 elems = this.element.querySelectorAll( elems ); 2181 } 2182 elems = utils.makeArray( elems ); 2183 return elems; 2184}; 2185 2186proto._manageStamps = function() { 2187 if ( !this.stamps || !this.stamps.length ) { 2188 return; 2189 } 2190 2191 this._getBoundingRect(); 2192 2193 this.stamps.forEach( this._manageStamp, this ); 2194}; 2195 2196// update boundingLeft / Top 2197proto._getBoundingRect = function() { 2198 // get bounding rect for container element 2199 var boundingRect = this.element.getBoundingClientRect(); 2200 var size = this.size; 2201 this._boundingRect = { 2202 left: boundingRect.left + size.paddingLeft + size.borderLeftWidth, 2203 top: boundingRect.top + size.paddingTop + size.borderTopWidth, 2204 right: boundingRect.right - ( size.paddingRight + size.borderRightWidth ), 2205 bottom: boundingRect.bottom - ( size.paddingBottom + size.borderBottomWidth ) 2206 }; 2207}; 2208 2209/** 2210 * @param {Element} stamp 2211**/ 2212proto._manageStamp = noop; 2213 2214/** 2215 * get x/y position of element relative to container element 2216 * @param {Element} elem 2217 * @returns {Object} offset - has left, top, right, bottom 2218 */ 2219proto._getElementOffset = function( elem ) { 2220 var boundingRect = elem.getBoundingClientRect(); 2221 var thisRect = this._boundingRect; 2222 var size = getSize( elem ); 2223 var offset = { 2224 left: boundingRect.left - thisRect.left - size.marginLeft, 2225 top: boundingRect.top - thisRect.top - size.marginTop, 2226 right: thisRect.right - boundingRect.right - size.marginRight, 2227 bottom: thisRect.bottom - boundingRect.bottom - size.marginBottom 2228 }; 2229 return offset; 2230}; 2231 2232// -------------------------- resize -------------------------- // 2233 2234// enable event handlers for listeners 2235// i.e. resize -> onresize 2236proto.handleEvent = utils.handleEvent; 2237 2238/** 2239 * Bind layout to window resizing 2240 */ 2241proto.bindResize = function() { 2242 window.addEventListener( 'resize', this ); 2243 this.isResizeBound = true; 2244}; 2245 2246/** 2247 * Unbind layout to window resizing 2248 */ 2249proto.unbindResize = function() { 2250 window.removeEventListener( 'resize', this ); 2251 this.isResizeBound = false; 2252}; 2253 2254proto.onresize = function() { 2255 this.resize(); 2256}; 2257 2258utils.debounceMethod( Outlayer, 'onresize', 100 ); 2259 2260proto.resize = function() { 2261 // don't trigger if size did not change 2262 // or if resize was unbound. See #9 2263 if ( !this.isResizeBound || !this.needsResizeLayout() ) { 2264 return; 2265 } 2266 2267 this.layout(); 2268}; 2269 2270/** 2271 * check if layout is needed post layout 2272 * @returns Boolean 2273 */ 2274proto.needsResizeLayout = function() { 2275 var size = getSize( this.element ); 2276 // check that this.size and size are there 2277 // IE8 triggers resize on body size change, so they might not be 2278 var hasSizes = this.size && size; 2279 return hasSizes && size.innerWidth !== this.size.innerWidth; 2280}; 2281 2282// -------------------------- methods -------------------------- // 2283 2284/** 2285 * add items to Outlayer instance 2286 * @param {Array or NodeList or Element} elems 2287 * @returns {Array} items - Outlayer.Items 2288**/ 2289proto.addItems = function( elems ) { 2290 var items = this._itemize( elems ); 2291 // add items to collection 2292 if ( items.length ) { 2293 this.items = this.items.concat( items ); 2294 } 2295 return items; 2296}; 2297 2298/** 2299 * Layout newly-appended item elements 2300 * @param {Array or NodeList or Element} elems 2301 */ 2302proto.appended = function( elems ) { 2303 var items = this.addItems( elems ); 2304 if ( !items.length ) { 2305 return; 2306 } 2307 // layout and reveal just the new items 2308 this.layoutItems( items, true ); 2309 this.reveal( items ); 2310}; 2311 2312/** 2313 * Layout prepended elements 2314 * @param {Array or NodeList or Element} elems 2315 */ 2316proto.prepended = function( elems ) { 2317 var items = this._itemize( elems ); 2318 if ( !items.length ) { 2319 return; 2320 } 2321 // add items to beginning of collection 2322 var previousItems = this.items.slice(0); 2323 this.items = items.concat( previousItems ); 2324 // start new layout 2325 this._resetLayout(); 2326 this._manageStamps(); 2327 // layout new stuff without transition 2328 this.layoutItems( items, true ); 2329 this.reveal( items ); 2330 // layout previous items 2331 this.layoutItems( previousItems ); 2332}; 2333 2334/** 2335 * reveal a collection of items 2336 * @param {Array of Outlayer.Items} items 2337 */ 2338proto.reveal = function( items ) { 2339 this._emitCompleteOnItems( 'reveal', items ); 2340 if ( !items || !items.length ) { 2341 return; 2342 } 2343 var stagger = this.updateStagger(); 2344 items.forEach( function( item, i ) { 2345 item.stagger( i * stagger ); 2346 item.reveal(); 2347 }); 2348}; 2349 2350/** 2351 * hide a collection of items 2352 * @param {Array of Outlayer.Items} items 2353 */ 2354proto.hide = function( items ) { 2355 this._emitCompleteOnItems( 'hide', items ); 2356 if ( !items || !items.length ) { 2357 return; 2358 } 2359 var stagger = this.updateStagger(); 2360 items.forEach( function( item, i ) { 2361 item.stagger( i * stagger ); 2362 item.hide(); 2363 }); 2364}; 2365 2366/** 2367 * reveal item elements 2368 * @param {Array}, {Element}, {NodeList} items 2369 */ 2370proto.revealItemElements = function( elems ) { 2371 var items = this.getItems( elems ); 2372 this.reveal( items ); 2373}; 2374 2375/** 2376 * hide item elements 2377 * @param {Array}, {Element}, {NodeList} items 2378 */ 2379proto.hideItemElements = function( elems ) { 2380 var items = this.getItems( elems ); 2381 this.hide( items ); 2382}; 2383 2384/** 2385 * get Outlayer.Item, given an Element 2386 * @param {Element} elem 2387 * @param {Function} callback 2388 * @returns {Outlayer.Item} item 2389 */ 2390proto.getItem = function( elem ) { 2391 // loop through items to get the one that matches 2392 for ( var i=0; i < this.items.length; i++ ) { 2393 var item = this.items[i]; 2394 if ( item.element == elem ) { 2395 // return item 2396 return item; 2397 } 2398 } 2399}; 2400 2401/** 2402 * get collection of Outlayer.Items, given Elements 2403 * @param {Array} elems 2404 * @returns {Array} items - Outlayer.Items 2405 */ 2406proto.getItems = function( elems ) { 2407 elems = utils.makeArray( elems ); 2408 var items = []; 2409 elems.forEach( function( elem ) { 2410 var item = this.getItem( elem ); 2411 if ( item ) { 2412 items.push( item ); 2413 } 2414 }, this ); 2415 2416 return items; 2417}; 2418 2419/** 2420 * remove element(s) from instance and DOM 2421 * @param {Array or NodeList or Element} elems 2422 */ 2423proto.remove = function( elems ) { 2424 var removeItems = this.getItems( elems ); 2425 2426 this._emitCompleteOnItems( 'remove', removeItems ); 2427 2428 // bail if no items to remove 2429 if ( !removeItems || !removeItems.length ) { 2430 return; 2431 } 2432 2433 removeItems.forEach( function( item ) { 2434 item.remove(); 2435 // remove item from collection 2436 utils.removeFrom( this.items, item ); 2437 }, this ); 2438}; 2439 2440// ----- destroy ----- // 2441 2442// remove and disable Outlayer instance 2443proto.destroy = function() { 2444 // clean up dynamic styles 2445 var style = this.element.style; 2446 style.height = ''; 2447 style.position = ''; 2448 style.width = ''; 2449 // destroy items 2450 this.items.forEach( function( item ) { 2451 item.destroy(); 2452 }); 2453 2454 this.unbindResize(); 2455 2456 var id = this.element.outlayerGUID; 2457 delete instances[ id ]; // remove reference to instance by id 2458 delete this.element.outlayerGUID; 2459 // remove data for jQuery 2460 if ( jQuery ) { 2461 jQuery.removeData( this.element, this.constructor.namespace ); 2462 } 2463 2464}; 2465 2466// -------------------------- data -------------------------- // 2467 2468/** 2469 * get Outlayer instance from element 2470 * @param {Element} elem 2471 * @returns {Outlayer} 2472 */ 2473Outlayer.data = function( elem ) { 2474 elem = utils.getQueryElement( elem ); 2475 var id = elem && elem.outlayerGUID; 2476 return id && instances[ id ]; 2477}; 2478 2479 2480// -------------------------- create Outlayer class -------------------------- // 2481 2482/** 2483 * create a layout class 2484 * @param {String} namespace 2485 */ 2486Outlayer.create = function( namespace, options ) { 2487 // sub-class Outlayer 2488 var Layout = subclass( Outlayer ); 2489 // apply new options and compatOptions 2490 Layout.defaults = utils.extend( {}, Outlayer.defaults ); 2491 utils.extend( Layout.defaults, options ); 2492 Layout.compatOptions = utils.extend( {}, Outlayer.compatOptions ); 2493 2494 Layout.namespace = namespace; 2495 2496 Layout.data = Outlayer.data; 2497 2498 // sub-class Item 2499 Layout.Item = subclass( Item ); 2500 2501 // -------------------------- declarative -------------------------- // 2502 2503 utils.htmlInit( Layout, namespace ); 2504 2505 // -------------------------- jQuery bridge -------------------------- // 2506 2507 // make into jQuery plugin 2508 if ( jQuery && jQuery.bridget ) { 2509 jQuery.bridget( namespace, Layout ); 2510 } 2511 2512 return Layout; 2513}; 2514 2515function subclass( Parent ) { 2516 function SubClass() { 2517 Parent.apply( this, arguments ); 2518 } 2519 2520 SubClass.prototype = Object.create( Parent.prototype ); 2521 SubClass.prototype.constructor = SubClass; 2522 2523 return SubClass; 2524} 2525 2526// ----- helpers ----- // 2527 2528// how many milliseconds are in each unit 2529var msUnits = { 2530 ms: 1, 2531 s: 1000 2532}; 2533 2534// munge time-like parameter into millisecond number 2535// '0.4s' -> 40 2536function getMilliseconds( time ) { 2537 if ( typeof time == 'number' ) { 2538 return time; 2539 } 2540 var matches = time.match( /(^\d*\.?\d*)(\w*)/ ); 2541 var num = matches && matches[1]; 2542 var unit = matches && matches[2]; 2543 if ( !num.length ) { 2544 return 0; 2545 } 2546 num = parseFloat( num ); 2547 var mult = msUnits[ unit ] || 1; 2548 return num * mult; 2549} 2550 2551// ----- fin ----- // 2552 2553// back in global 2554Outlayer.Item = Item; 2555 2556return Outlayer; 2557 2558})); 2559 2560/** 2561 * Isotope Item 2562**/ 2563 2564( function( window, factory ) { 2565 // universal module definition 2566 /* jshint strict: false */ /*globals define, module, require */ 2567 if ( typeof define == 'function' && define.amd ) { 2568 // AMD 2569 define( 'isotope-layout/js/item',[ 2570 'outlayer/outlayer' 2571 ], 2572 factory ); 2573 } else if ( typeof module == 'object' && module.exports ) { 2574 // CommonJS 2575 module.exports = factory( 2576 require('outlayer') 2577 ); 2578 } else { 2579 // browser global 2580 window.Isotope = window.Isotope || {}; 2581 window.Isotope.Item = factory( 2582 window.Outlayer 2583 ); 2584 } 2585 2586}( window, function factory( Outlayer ) { 2587'use strict'; 2588 2589// -------------------------- Item -------------------------- // 2590 2591// sub-class Outlayer Item 2592function Item() { 2593 Outlayer.Item.apply( this, arguments ); 2594} 2595 2596var proto = Item.prototype = Object.create( Outlayer.Item.prototype ); 2597 2598var _create = proto._create; 2599proto._create = function() { 2600 // assign id, used for original-order sorting 2601 this.id = this.layout.itemGUID++; 2602 _create.call( this ); 2603 this.sortData = {}; 2604}; 2605 2606proto.updateSortData = function() { 2607 if ( this.isIgnored ) { 2608 return; 2609 } 2610 // default sorters 2611 this.sortData.id = this.id; 2612 // for backward compatibility 2613 this.sortData['original-order'] = this.id; 2614 this.sortData.random = Math.random(); 2615 // go thru getSortData obj and apply the sorters 2616 var getSortData = this.layout.options.getSortData; 2617 var sorters = this.layout._sorters; 2618 for ( var key in getSortData ) { 2619 var sorter = sorters[ key ]; 2620 this.sortData[ key ] = sorter( this.element, this ); 2621 } 2622}; 2623 2624var _destroy = proto.destroy; 2625proto.destroy = function() { 2626 // call super 2627 _destroy.apply( this, arguments ); 2628 // reset display, #741 2629 this.css({ 2630 display: '' 2631 }); 2632}; 2633 2634return Item; 2635 2636})); 2637 2638/** 2639 * Isotope LayoutMode 2640 */ 2641 2642( function( window, factory ) { 2643 // universal module definition 2644 /* jshint strict: false */ /*globals define, module, require */ 2645 if ( typeof define == 'function' && define.amd ) { 2646 // AMD 2647 define( 'isotope-layout/js/layout-mode',[ 2648 'get-size/get-size', 2649 'outlayer/outlayer' 2650 ], 2651 factory ); 2652 } else if ( typeof module == 'object' && module.exports ) { 2653 // CommonJS 2654 module.exports = factory( 2655 require('get-size'), 2656 require('outlayer') 2657 ); 2658 } else { 2659 // browser global 2660 window.Isotope = window.Isotope || {}; 2661 window.Isotope.LayoutMode = factory( 2662 window.getSize, 2663 window.Outlayer 2664 ); 2665 } 2666 2667}( window, function factory( getSize, Outlayer ) { 2668 'use strict'; 2669 2670 // layout mode class 2671 function LayoutMode( isotope ) { 2672 this.isotope = isotope; 2673 // link properties 2674 if ( isotope ) { 2675 this.options = isotope.options[ this.namespace ]; 2676 this.element = isotope.element; 2677 this.items = isotope.filteredItems; 2678 this.size = isotope.size; 2679 } 2680 } 2681 2682 var proto = LayoutMode.prototype; 2683 2684 /** 2685 * some methods should just defer to default Outlayer method 2686 * and reference the Isotope instance as `this` 2687 **/ 2688 var facadeMethods = [ 2689 '_resetLayout', 2690 '_getItemLayoutPosition', 2691 '_manageStamp', 2692 '_getContainerSize', 2693 '_getElementOffset', 2694 'needsResizeLayout', 2695 '_getOption' 2696 ]; 2697 2698 facadeMethods.forEach( function( methodName ) { 2699 proto[ methodName ] = function() { 2700 return Outlayer.prototype[ methodName ].apply( this.isotope, arguments ); 2701 }; 2702 }); 2703 2704 // ----- ----- // 2705 2706 // for horizontal layout modes, check vertical size 2707 proto.needsVerticalResizeLayout = function() { 2708 // don't trigger if size did not change 2709 var size = getSize( this.isotope.element ); 2710 // check that this.size and size are there 2711 // IE8 triggers resize on body size change, so they might not be 2712 var hasSizes = this.isotope.size && size; 2713 return hasSizes && size.innerHeight != this.isotope.size.innerHeight; 2714 }; 2715 2716 // ----- measurements ----- // 2717 2718 proto._getMeasurement = function() { 2719 this.isotope._getMeasurement.apply( this, arguments ); 2720 }; 2721 2722 proto.getColumnWidth = function() { 2723 this.getSegmentSize( 'column', 'Width' ); 2724 }; 2725 2726 proto.getRowHeight = function() { 2727 this.getSegmentSize( 'row', 'Height' ); 2728 }; 2729 2730 /** 2731 * get columnWidth or rowHeight 2732 * segment: 'column' or 'row' 2733 * size 'Width' or 'Height' 2734 **/ 2735 proto.getSegmentSize = function( segment, size ) { 2736 var segmentName = segment + size; 2737 var outerSize = 'outer' + size; 2738 // columnWidth / outerWidth // rowHeight / outerHeight 2739 this._getMeasurement( segmentName, outerSize ); 2740 // got rowHeight or columnWidth, we can chill 2741 if ( this[ segmentName ] ) { 2742 return; 2743 } 2744 // fall back to item of first element 2745 var firstItemSize = this.getFirstItemSize(); 2746 this[ segmentName ] = firstItemSize && firstItemSize[ outerSize ] || 2747 // or size of container 2748 this.isotope.size[ 'inner' + size ]; 2749 }; 2750 2751 proto.getFirstItemSize = function() { 2752 var firstItem = this.isotope.filteredItems[0]; 2753 return firstItem && firstItem.element && getSize( firstItem.element ); 2754 }; 2755 2756 // ----- methods that should reference isotope ----- // 2757 2758 proto.layout = function() { 2759 this.isotope.layout.apply( this.isotope, arguments ); 2760 }; 2761 2762 proto.getSize = function() { 2763 this.isotope.getSize(); 2764 this.size = this.isotope.size; 2765 }; 2766 2767 // -------------------------- create -------------------------- // 2768 2769 LayoutMode.modes = {}; 2770 2771 LayoutMode.create = function( namespace, options ) { 2772 2773 function Mode() { 2774 LayoutMode.apply( this, arguments ); 2775 } 2776 2777 Mode.prototype = Object.create( proto ); 2778 Mode.prototype.constructor = Mode; 2779 2780 // default options 2781 if ( options ) { 2782 Mode.options = options; 2783 } 2784 2785 Mode.prototype.namespace = namespace; 2786 // register in Isotope 2787 LayoutMode.modes[ namespace ] = Mode; 2788 2789 return Mode; 2790 }; 2791 2792 return LayoutMode; 2793 2794})); 2795 2796/*! 2797 * Masonry v4.2.1 2798 * Cascading grid layout library 2799 * https://masonry.desandro.com 2800 * MIT License 2801 * by David DeSandro 2802 */ 2803 2804( function( window, factory ) { 2805 // universal module definition 2806 /* jshint strict: false */ /*globals define, module, require */ 2807 if ( typeof define == 'function' && define.amd ) { 2808 // AMD 2809 define( 'masonry-layout/masonry',[ 2810 'outlayer/outlayer', 2811 'get-size/get-size' 2812 ], 2813 factory ); 2814 } else if ( typeof module == 'object' && module.exports ) { 2815 // CommonJS 2816 module.exports = factory( 2817 require('outlayer'), 2818 require('get-size') 2819 ); 2820 } else { 2821 // browser global 2822 window.Masonry = factory( 2823 window.Outlayer, 2824 window.getSize 2825 ); 2826 } 2827 2828}( window, function factory( Outlayer, getSize ) { 2829 2830 2831 2832// -------------------------- masonryDefinition -------------------------- // 2833 2834 // create an Outlayer layout class 2835 var Masonry = Outlayer.create('masonry'); 2836 // isFitWidth -> fitWidth 2837 Masonry.compatOptions.fitWidth = 'isFitWidth'; 2838 2839 var proto = Masonry.prototype; 2840 2841 proto._resetLayout = function() { 2842 this.getSize(); 2843 this._getMeasurement( 'columnWidth', 'outerWidth' ); 2844 this._getMeasurement( 'gutter', 'outerWidth' ); 2845 this.measureColumns(); 2846 2847 // reset column Y 2848 this.colYs = []; 2849 for ( var i=0; i < this.cols; i++ ) { 2850 this.colYs.push( 0 ); 2851 } 2852 2853 this.maxY = 0; 2854 this.horizontalColIndex = 0; 2855 }; 2856 2857 proto.measureColumns = function() { 2858 this.getContainerWidth(); 2859 // if columnWidth is 0, default to outerWidth of first item 2860 if ( !this.columnWidth ) { 2861 var firstItem = this.items[0]; 2862 var firstItemElem = firstItem && firstItem.element; 2863 // columnWidth fall back to item of first element 2864 this.columnWidth = firstItemElem && getSize( firstItemElem ).outerWidth || 2865 // if first elem has no width, default to size of container 2866 this.containerWidth; 2867 } 2868 2869 var columnWidth = this.columnWidth += this.gutter; 2870 2871 // calculate columns 2872 var containerWidth = this.containerWidth + this.gutter; 2873 var cols = containerWidth / columnWidth; 2874 // fix rounding errors, typically with gutters 2875 var excess = columnWidth - containerWidth % columnWidth; 2876 // if overshoot is less than a pixel, round up, otherwise floor it 2877 var mathMethod = excess && excess < 1 ? 'round' : 'floor'; 2878 cols = Math[ mathMethod ]( cols ); 2879 this.cols = Math.max( cols, 1 ); 2880 }; 2881 2882 proto.getContainerWidth = function() { 2883 // container is parent if fit width 2884 var isFitWidth = this._getOption('fitWidth'); 2885 var container = isFitWidth ? this.element.parentNode : this.element; 2886 // check that this.size and size are there 2887 // IE8 triggers resize on body size change, so they might not be 2888 var size = getSize( container ); 2889 this.containerWidth = size && size.innerWidth; 2890 }; 2891 2892 proto._getItemLayoutPosition = function( item ) { 2893 item.getSize(); 2894 // how many columns does this brick span 2895 var remainder = item.size.outerWidth % this.columnWidth; 2896 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil'; 2897 // round if off by 1 pixel, otherwise use ceil 2898 var colSpan = Math[ mathMethod ]( item.size.outerWidth / this.columnWidth ); 2899 colSpan = Math.min( colSpan, this.cols ); 2900 // use horizontal or top column position 2901 var colPosMethod = this.options.horizontalOrder ? 2902 '_getHorizontalColPosition' : '_getTopColPosition'; 2903 var colPosition = this[ colPosMethod ]( colSpan, item ); 2904 // position the brick 2905 var position = { 2906 x: this.columnWidth * colPosition.col, 2907 y: colPosition.y 2908 }; 2909 // apply setHeight to necessary columns 2910 var setHeight = colPosition.y + item.size.outerHeight; 2911 var setMax = colSpan + colPosition.col; 2912 for ( var i = colPosition.col; i < setMax; i++ ) { 2913 this.colYs[i] = setHeight; 2914 } 2915 2916 return position; 2917 }; 2918 2919 proto._getTopColPosition = function( colSpan ) { 2920 var colGroup = this._getTopColGroup( colSpan ); 2921 // get the minimum Y value from the columns 2922 var minimumY = Math.min.apply( Math, colGroup ); 2923 2924 return { 2925 col: colGroup.indexOf( minimumY ), 2926 y: minimumY, 2927 }; 2928 }; 2929 2930 /** 2931 * @param {Number} colSpan - number of columns the element spans 2932 * @returns {Array} colGroup 2933 */ 2934 proto._getTopColGroup = function( colSpan ) { 2935 if ( colSpan < 2 ) { 2936 // if brick spans only one column, use all the column Ys 2937 return this.colYs; 2938 } 2939 2940 var colGroup = []; 2941 // how many different places could this brick fit horizontally 2942 var groupCount = this.cols + 1 - colSpan; 2943 // for each group potential horizontal position 2944 for ( var i = 0; i < groupCount; i++ ) { 2945 colGroup[i] = this._getColGroupY( i, colSpan ); 2946 } 2947 return colGroup; 2948 }; 2949 2950 proto._getColGroupY = function( col, colSpan ) { 2951 if ( colSpan < 2 ) { 2952 return this.colYs[ col ]; 2953 } 2954 // make an array of colY values for that one group 2955 var groupColYs = this.colYs.slice( col, col + colSpan ); 2956 // and get the max value of the array 2957 return Math.max.apply( Math, groupColYs ); 2958 }; 2959 2960 // get column position based on horizontal index. #873 2961 proto._getHorizontalColPosition = function( colSpan, item ) { 2962 var col = this.horizontalColIndex % this.cols; 2963 var isOver = colSpan > 1 && col + colSpan > this.cols; 2964 // shift to next row if item can't fit on current row 2965 col = isOver ? 0 : col; 2966 // don't let zero-size items take up space 2967 var hasSize = item.size.outerWidth && item.size.outerHeight; 2968 this.horizontalColIndex = hasSize ? col + colSpan : this.horizontalColIndex; 2969 2970 return { 2971 col: col, 2972 y: this._getColGroupY( col, colSpan ), 2973 }; 2974 }; 2975 2976 proto._manageStamp = function( stamp ) { 2977 var stampSize = getSize( stamp ); 2978 var offset = this._getElementOffset( stamp ); 2979 // get the columns that this stamp affects 2980 var isOriginLeft = this._getOption('originLeft'); 2981 var firstX = isOriginLeft ? offset.left : offset.right; 2982 var lastX = firstX + stampSize.outerWidth; 2983 var firstCol = Math.floor( firstX / this.columnWidth ); 2984 firstCol = Math.max( 0, firstCol ); 2985 var lastCol = Math.floor( lastX / this.columnWidth ); 2986 // lastCol should not go over if multiple of columnWidth #425 2987 lastCol -= lastX % this.columnWidth ? 0 : 1; 2988 lastCol = Math.min( this.cols - 1, lastCol ); 2989 // set colYs to bottom of the stamp 2990 2991 var isOriginTop = this._getOption('originTop'); 2992 var stampMaxY = ( isOriginTop ? offset.top : offset.bottom ) + 2993 stampSize.outerHeight; 2994 for ( var i = firstCol; i <= lastCol; i++ ) { 2995 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] ); 2996 } 2997 }; 2998 2999 proto._getContainerSize = function() { 3000 this.maxY = Math.max.apply( Math, this.colYs ); 3001 var size = { 3002 height: this.maxY 3003 }; 3004 3005 if ( this._getOption('fitWidth') ) { 3006 size.width = this._getContainerFitWidth(); 3007 } 3008 3009 return size; 3010 }; 3011 3012 proto._getContainerFitWidth = function() { 3013 var unusedCols = 0; 3014 // count unused columns 3015 var i = this.cols; 3016 while ( --i ) { 3017 if ( this.colYs[i] !== 0 ) { 3018 break; 3019 } 3020 unusedCols++; 3021 } 3022 // fit container to columns that have been used 3023 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter; 3024 }; 3025 3026 proto.needsResizeLayout = function() { 3027 var previousWidth = this.containerWidth; 3028 this.getContainerWidth(); 3029 return previousWidth != this.containerWidth; 3030 }; 3031 3032 return Masonry; 3033 3034})); 3035 3036/*! 3037 * Masonry layout mode 3038 * sub-classes Masonry 3039 * https://masonry.desandro.com 3040 */ 3041 3042( function( window, factory ) { 3043 // universal module definition 3044 /* jshint strict: false */ /*globals define, module, require */ 3045 if ( typeof define == 'function' && define.amd ) { 3046 // AMD 3047 define( 'isotope-layout/js/layout-modes/masonry',[ 3048 '../layout-mode', 3049 'masonry-layout/masonry' 3050 ], 3051 factory ); 3052 } else if ( typeof module == 'object' && module.exports ) { 3053 // CommonJS 3054 module.exports = factory( 3055 require('../layout-mode'), 3056 require('masonry-layout') 3057 ); 3058 } else { 3059 // browser global 3060 factory( 3061 window.Isotope.LayoutMode, 3062 window.Masonry 3063 ); 3064 } 3065 3066}( window, function factory( LayoutMode, Masonry ) { 3067'use strict'; 3068 3069// -------------------------- masonryDefinition -------------------------- // 3070 3071 // create an Outlayer layout class 3072 var MasonryMode = LayoutMode.create('masonry'); 3073 3074 var proto = MasonryMode.prototype; 3075 3076 var keepModeMethods = { 3077 _getElementOffset: true, 3078 layout: true, 3079 _getMeasurement: true 3080 }; 3081 3082 // inherit Masonry prototype 3083 for ( var method in Masonry.prototype ) { 3084 // do not inherit mode methods 3085 if ( !keepModeMethods[ method ] ) { 3086 proto[ method ] = Masonry.prototype[ method ]; 3087 } 3088 } 3089 3090 var measureColumns = proto.measureColumns; 3091 proto.measureColumns = function() { 3092 // set items, used if measuring first item 3093 this.items = this.isotope.filteredItems; 3094 measureColumns.call( this ); 3095 }; 3096 3097 // point to mode options for fitWidth 3098 var _getOption = proto._getOption; 3099 proto._getOption = function( option ) { 3100 if ( option == 'fitWidth' ) { 3101 return this.options.isFitWidth !== undefined ? 3102 this.options.isFitWidth : this.options.fitWidth; 3103 } 3104 return _getOption.apply( this.isotope, arguments ); 3105 }; 3106 3107 return MasonryMode; 3108 3109})); 3110 3111/** 3112 * fitRows layout mode 3113 */ 3114 3115( function( window, factory ) { 3116 // universal module definition 3117 /* jshint strict: false */ /*globals define, module, require */ 3118 if ( typeof define == 'function' && define.amd ) { 3119 // AMD 3120 define( 'isotope-layout/js/layout-modes/fit-rows',[ 3121 '../layout-mode' 3122 ], 3123 factory ); 3124 } else if ( typeof exports == 'object' ) { 3125 // CommonJS 3126 module.exports = factory( 3127 require('../layout-mode') 3128 ); 3129 } else { 3130 // browser global 3131 factory( 3132 window.Isotope.LayoutMode 3133 ); 3134 } 3135 3136}( window, function factory( LayoutMode ) { 3137'use strict'; 3138 3139var FitRows = LayoutMode.create('fitRows'); 3140 3141var proto = FitRows.prototype; 3142 3143proto._resetLayout = function() { 3144 this.x = 0; 3145 this.y = 0; 3146 this.maxY = 0; 3147 this._getMeasurement( 'gutter', 'outerWidth' ); 3148}; 3149 3150proto._getItemLayoutPosition = function( item ) { 3151 item.getSize(); 3152 3153 var itemWidth = item.size.outerWidth + this.gutter; 3154 // if this element cannot fit in the current row 3155 var containerWidth = this.isotope.size.innerWidth + this.gutter; 3156 if ( this.x !== 0 && itemWidth + this.x > containerWidth ) { 3157 this.x = 0; 3158 this.y = this.maxY; 3159 } 3160 3161 var position = { 3162 x: this.x, 3163 y: this.y 3164 }; 3165 3166 this.maxY = Math.max( this.maxY, this.y + item.size.outerHeight ); 3167 this.x += itemWidth; 3168 3169 return position; 3170}; 3171 3172proto._getContainerSize = function() { 3173 return { height: this.maxY }; 3174}; 3175 3176return FitRows; 3177 3178})); 3179 3180/** 3181 * vertical layout mode 3182 */ 3183 3184( function( window, factory ) { 3185 // universal module definition 3186 /* jshint strict: false */ /*globals define, module, require */ 3187 if ( typeof define == 'function' && define.amd ) { 3188 // AMD 3189 define( 'isotope-layout/js/layout-modes/vertical',[ 3190 '../layout-mode' 3191 ], 3192 factory ); 3193 } else if ( typeof module == 'object' && module.exports ) { 3194 // CommonJS 3195 module.exports = factory( 3196 require('../layout-mode') 3197 ); 3198 } else { 3199 // browser global 3200 factory( 3201 window.Isotope.LayoutMode 3202 ); 3203 } 3204 3205}( window, function factory( LayoutMode ) { 3206'use strict'; 3207 3208var Vertical = LayoutMode.create( 'vertical', { 3209 horizontalAlignment: 0 3210}); 3211 3212var proto = Vertical.prototype; 3213 3214proto._resetLayout = function() { 3215 this.y = 0; 3216}; 3217 3218proto._getItemLayoutPosition = function( item ) { 3219 item.getSize(); 3220 var x = ( this.isotope.size.innerWidth - item.size.outerWidth ) * 3221 this.options.horizontalAlignment; 3222 var y = this.y; 3223 this.y += item.size.outerHeight; 3224 return { x: x, y: y }; 3225}; 3226 3227proto._getContainerSize = function() { 3228 return { height: this.y }; 3229}; 3230 3231return Vertical; 3232 3233})); 3234 3235/*! 3236 * Isotope v3.0.6 3237 * 3238 * Licensed GPLv3 for open source use 3239 * or Isotope Commercial License for commercial use 3240 * 3241 * https://isotope.metafizzy.co 3242 * Copyright 2010-2018 Metafizzy 3243 */ 3244 3245( function( window, factory ) { 3246 // universal module definition 3247 /* jshint strict: false */ /*globals define, module, require */ 3248 if ( typeof define == 'function' && define.amd ) { 3249 // AMD 3250 define( [ 3251 'outlayer/outlayer', 3252 'get-size/get-size', 3253 'desandro-matches-selector/matches-selector', 3254 'fizzy-ui-utils/utils', 3255 'isotope-layout/js/item', 3256 'isotope-layout/js/layout-mode', 3257 // include default layout modes 3258 'isotope-layout/js/layout-modes/masonry', 3259 'isotope-layout/js/layout-modes/fit-rows', 3260 'isotope-layout/js/layout-modes/vertical' 3261 ], 3262 function( Outlayer, getSize, matchesSelector, utils, Item, LayoutMode ) { 3263 return factory( window, Outlayer, getSize, matchesSelector, utils, Item, LayoutMode ); 3264 }); 3265 } else if ( typeof module == 'object' && module.exports ) { 3266 // CommonJS 3267 module.exports = factory( 3268 window, 3269 require('outlayer'), 3270 require('get-size'), 3271 require('desandro-matches-selector'), 3272 require('fizzy-ui-utils'), 3273 require('isotope-layout/js/item'), 3274 require('isotope-layout/js/layout-mode'), 3275 // include default layout modes 3276 require('isotope-layout/js/layout-modes/masonry'), 3277 require('isotope-layout/js/layout-modes/fit-rows'), 3278 require('isotope-layout/js/layout-modes/vertical') 3279 ); 3280 } else { 3281 // browser global 3282 window.Isotope = factory( 3283 window, 3284 window.Outlayer, 3285 window.getSize, 3286 window.matchesSelector, 3287 window.fizzyUIUtils, 3288 window.Isotope.Item, 3289 window.Isotope.LayoutMode 3290 ); 3291 } 3292 3293}( window, function factory( window, Outlayer, getSize, matchesSelector, utils, 3294 Item, LayoutMode ) { 3295 3296 3297 3298// -------------------------- vars -------------------------- // 3299 3300var jQuery = window.jQuery; 3301 3302// -------------------------- helpers -------------------------- // 3303 3304var trim = String.prototype.trim ? 3305 function( str ) { 3306 return str.trim(); 3307 } : 3308 function( str ) { 3309 return str.replace( /^\s+|\s+$/g, '' ); 3310 }; 3311 3312// -------------------------- isotopeDefinition -------------------------- // 3313 3314 // create an Outlayer layout class 3315 var Isotope = Outlayer.create( 'isotope', { 3316 layoutMode: 'masonry', 3317 isJQueryFiltering: true, 3318 sortAscending: true 3319 }); 3320 3321 Isotope.Item = Item; 3322 Isotope.LayoutMode = LayoutMode; 3323 3324 var proto = Isotope.prototype; 3325 3326 proto._create = function() { 3327 this.itemGUID = 0; 3328 // functions that sort items 3329 this._sorters = {}; 3330 this._getSorters(); 3331 // call super 3332 Outlayer.prototype._create.call( this ); 3333 3334 // create layout modes 3335 this.modes = {}; 3336 // start filteredItems with all items 3337 this.filteredItems = this.items; 3338 // keep of track of sortBys 3339 this.sortHistory = [ 'original-order' ]; 3340 // create from registered layout modes 3341 for ( var name in LayoutMode.modes ) { 3342 this._initLayoutMode( name ); 3343 } 3344 }; 3345 3346 proto.reloadItems = function() { 3347 // reset item ID counter 3348 this.itemGUID = 0; 3349 // call super 3350 Outlayer.prototype.reloadItems.call( this ); 3351 }; 3352 3353 proto._itemize = function() { 3354 var items = Outlayer.prototype._itemize.apply( this, arguments ); 3355 // assign ID for original-order 3356 for ( var i=0; i < items.length; i++ ) { 3357 var item = items[i]; 3358 item.id = this.itemGUID++; 3359 } 3360 this._updateItemsSortData( items ); 3361 return items; 3362 }; 3363 3364 3365 // -------------------------- layout -------------------------- // 3366 3367 proto._initLayoutMode = function( name ) { 3368 var Mode = LayoutMode.modes[ name ]; 3369 // set mode options 3370 // HACK extend initial options, back-fill in default options 3371 var initialOpts = this.options[ name ] || {}; 3372 this.options[ name ] = Mode.options ? 3373 utils.extend( Mode.options, initialOpts ) : initialOpts; 3374 // init layout mode instance 3375 this.modes[ name ] = new Mode( this ); 3376 }; 3377 3378 3379 proto.layout = function() { 3380 // if first time doing layout, do all magic 3381 if ( !this._isLayoutInited && this._getOption('initLayout') ) { 3382 this.arrange(); 3383 return; 3384 } 3385 this._layout(); 3386 }; 3387 3388 // private method to be used in layout() & magic() 3389 proto._layout = function() { 3390 // don't animate first layout 3391 var isInstant = this._getIsInstant(); 3392 // layout flow 3393 this._resetLayout(); 3394 this._manageStamps(); 3395 this.layoutItems( this.filteredItems, isInstant ); 3396 3397 // flag for initalized 3398 this._isLayoutInited = true; 3399 }; 3400 3401 // filter + sort + layout 3402 proto.arrange = function( opts ) { 3403 // set any options pass 3404 this.option( opts ); 3405 this._getIsInstant(); 3406 // filter, sort, and layout 3407 3408 // filter 3409 var filtered = this._filter( this.items ); 3410 this.filteredItems = filtered.matches; 3411 3412 this._bindArrangeComplete(); 3413 3414 if ( this._isInstant ) { 3415 this._noTransition( this._hideReveal, [ filtered ] ); 3416 } else { 3417 this._hideReveal( filtered ); 3418 } 3419 3420 this._sort(); 3421 this._layout(); 3422 }; 3423 // alias to _init for main plugin method 3424 proto._init = proto.arrange; 3425 3426 proto._hideReveal = function( filtered ) { 3427 this.reveal( filtered.needReveal ); 3428 this.hide( filtered.needHide ); 3429 }; 3430 3431 // HACK 3432 // Don't animate/transition first layout 3433 // Or don't animate/transition other layouts 3434 proto._getIsInstant = function() { 3435 var isLayoutInstant = this._getOption('layoutInstant'); 3436 var isInstant = isLayoutInstant !== undefined ? isLayoutInstant : 3437 !this._isLayoutInited; 3438 this._isInstant = isInstant; 3439 return isInstant; 3440 }; 3441 3442 // listen for layoutComplete, hideComplete and revealComplete 3443 // to trigger arrangeComplete 3444 proto._bindArrangeComplete = function() { 3445 // listen for 3 events to trigger arrangeComplete 3446 var isLayoutComplete, isHideComplete, isRevealComplete; 3447 var _this = this; 3448 function arrangeParallelCallback() { 3449 if ( isLayoutComplete && isHideComplete && isRevealComplete ) { 3450 _this.dispatchEvent( 'arrangeComplete', null, [ _this.filteredItems ] ); 3451 } 3452 } 3453 this.once( 'layoutComplete', function() { 3454 isLayoutComplete = true; 3455 arrangeParallelCallback(); 3456 }); 3457 this.once( 'hideComplete', function() { 3458 isHideComplete = true; 3459 arrangeParallelCallback(); 3460 }); 3461 this.once( 'revealComplete', function() { 3462 isRevealComplete = true; 3463 arrangeParallelCallback(); 3464 }); 3465 }; 3466 3467 // -------------------------- filter -------------------------- // 3468 3469 proto._filter = function( items ) { 3470 var filter = this.options.filter; 3471 filter = filter || '*'; 3472 var matches = []; 3473 var hiddenMatched = []; 3474 var visibleUnmatched = []; 3475 3476 var test = this._getFilterTest( filter ); 3477 3478 // test each item 3479 for ( var i=0; i < items.length; i++ ) { 3480 var item = items[i]; 3481 if ( item.isIgnored ) { 3482 continue; 3483 } 3484 // add item to either matched or unmatched group 3485 var isMatched = test( item ); 3486 // item.isFilterMatched = isMatched; 3487 // add to matches if its a match 3488 if ( isMatched ) { 3489 matches.push( item ); 3490 } 3491 // add to additional group if item needs to be hidden or revealed 3492 if ( isMatched && item.isHidden ) { 3493 hiddenMatched.push( item ); 3494 } else if ( !isMatched && !item.isHidden ) { 3495 visibleUnmatched.push( item ); 3496 } 3497 } 3498 3499 // return collections of items to be manipulated 3500 return { 3501 matches: matches, 3502 needReveal: hiddenMatched, 3503 needHide: visibleUnmatched 3504 }; 3505 }; 3506 3507 // get a jQuery, function, or a matchesSelector test given the filter 3508 proto._getFilterTest = function( filter ) { 3509 if ( jQuery && this.options.isJQueryFiltering ) { 3510 // use jQuery 3511 return function( item ) { 3512 return jQuery( item.element ).is( filter ); 3513 }; 3514 } 3515 if ( typeof filter == 'function' ) { 3516 // use filter as function 3517 return function( item ) { 3518 return filter( item.element ); 3519 }; 3520 } 3521 // default, use filter as selector string 3522 return function( item ) { 3523 return matchesSelector( item.element, filter ); 3524 }; 3525 }; 3526 3527 // -------------------------- sorting -------------------------- // 3528 3529 /** 3530 * @params {Array} elems 3531 * @public 3532 */ 3533 proto.updateSortData = function( elems ) { 3534 // get items 3535 var items; 3536 if ( elems ) { 3537 elems = utils.makeArray( elems ); 3538 items = this.getItems( elems ); 3539 } else { 3540 // update all items if no elems provided 3541 items = this.items; 3542 } 3543 3544 this._getSorters(); 3545 this._updateItemsSortData( items ); 3546 }; 3547 3548 proto._getSorters = function() { 3549 var getSortData = this.options.getSortData; 3550 for ( var key in getSortData ) { 3551 var sorter = getSortData[ key ]; 3552 this._sorters[ key ] = mungeSorter( sorter ); 3553 } 3554 }; 3555 3556 /** 3557 * @params {Array} items - of Isotope.Items 3558 * @private 3559 */ 3560 proto._updateItemsSortData = function( items ) { 3561 // do not update if no items 3562 var len = items && items.length; 3563 3564 for ( var i=0; len && i < len; i++ ) { 3565 var item = items[i]; 3566 item.updateSortData(); 3567 } 3568 }; 3569 3570 // ----- munge sorter ----- // 3571 3572 // encapsulate this, as we just need mungeSorter 3573 // other functions in here are just for munging 3574 var mungeSorter = ( function() { 3575 // add a magic layer to sorters for convienent shorthands 3576 // `.foo-bar` will use the text of .foo-bar querySelector 3577 // `[foo-bar]` will use attribute 3578 // you can also add parser 3579 // `.foo-bar parseInt` will parse that as a number 3580 function mungeSorter( sorter ) { 3581 // if not a string, return function or whatever it is 3582 if ( typeof sorter != 'string' ) { 3583 return sorter; 3584 } 3585 // parse the sorter string 3586 var args = trim( sorter ).split(' '); 3587 var query = args[0]; 3588 // check if query looks like [an-attribute] 3589 var attrMatch = query.match( /^\[(.+)\]$/ ); 3590 var attr = attrMatch && attrMatch[1]; 3591 var getValue = getValueGetter( attr, query ); 3592 // use second argument as a parser 3593 var parser = Isotope.sortDataParsers[ args[1] ]; 3594 // parse the value, if there was a parser 3595 sorter = parser ? function( elem ) { 3596 return elem && parser( getValue( elem ) ); 3597 } : 3598 // otherwise just return value 3599 function( elem ) { 3600 return elem && getValue( elem ); 3601 }; 3602 3603 return sorter; 3604 } 3605 3606 // get an attribute getter, or get text of the querySelector 3607 function getValueGetter( attr, query ) { 3608 // if query looks like [foo-bar], get attribute 3609 if ( attr ) { 3610 return function getAttribute( elem ) { 3611 return elem.getAttribute( attr ); 3612 }; 3613 } 3614 3615 // otherwise, assume its a querySelector, and get its text 3616 return function getChildText( elem ) { 3617 var child = elem.querySelector( query ); 3618 return child && child.textContent; 3619 }; 3620 } 3621 3622 return mungeSorter; 3623 })(); 3624 3625 // parsers used in getSortData shortcut strings 3626 Isotope.sortDataParsers = { 3627 'parseInt': function( val ) { 3628 return parseInt( val, 10 ); 3629 }, 3630 'parseFloat': function( val ) { 3631 return parseFloat( val ); 3632 } 3633 }; 3634 3635 // ----- sort method ----- // 3636 3637 // sort filteredItem order 3638 proto._sort = function() { 3639 if ( !this.options.sortBy ) { 3640 return; 3641 } 3642 // keep track of sortBy History 3643 var sortBys = utils.makeArray( this.options.sortBy ); 3644 if ( !this._getIsSameSortBy( sortBys ) ) { 3645 // concat all sortBy and sortHistory, add to front, oldest goes in last 3646 this.sortHistory = sortBys.concat( this.sortHistory ); 3647 } 3648 // sort magic 3649 var itemSorter = getItemSorter( this.sortHistory, this.options.sortAscending ); 3650 this.filteredItems.sort( itemSorter ); 3651 }; 3652 3653 // check if sortBys is same as start of sortHistory 3654 proto._getIsSameSortBy = function( sortBys ) { 3655 for ( var i=0; i < sortBys.length; i++ ) { 3656 if ( sortBys[i] != this.sortHistory[i] ) { 3657 return false; 3658 } 3659 } 3660 return true; 3661 }; 3662 3663 // returns a function used for sorting 3664 function getItemSorter( sortBys, sortAsc ) { 3665 return function sorter( itemA, itemB ) { 3666 // cycle through all sortKeys 3667 for ( var i = 0; i < sortBys.length; i++ ) { 3668 var sortBy = sortBys[i]; 3669 var a = itemA.sortData[ sortBy ]; 3670 var b = itemB.sortData[ sortBy ]; 3671 if ( a > b || a < b ) { 3672 // if sortAsc is an object, use the value given the sortBy key 3673 var isAscending = sortAsc[ sortBy ] !== undefined ? sortAsc[ sortBy ] : sortAsc; 3674 var direction = isAscending ? 1 : -1; 3675 return ( a > b ? 1 : -1 ) * direction; 3676 } 3677 } 3678 return 0; 3679 }; 3680 } 3681 3682 // -------------------------- methods -------------------------- // 3683 3684 // get layout mode 3685 proto._mode = function() { 3686 var layoutMode = this.options.layoutMode; 3687 var mode = this.modes[ layoutMode ]; 3688 if ( !mode ) { 3689 // TODO console.error 3690 throw new Error( 'No layout mode: ' + layoutMode ); 3691 } 3692 // HACK sync mode's options 3693 // any options set after init for layout mode need to be synced 3694 mode.options = this.options[ layoutMode ]; 3695 return mode; 3696 }; 3697 3698 proto._resetLayout = function() { 3699 // trigger original reset layout 3700 Outlayer.prototype._resetLayout.call( this ); 3701 this._mode()._resetLayout(); 3702 }; 3703 3704 proto._getItemLayoutPosition = function( item ) { 3705 return this._mode()._getItemLayoutPosition( item ); 3706 }; 3707 3708 proto._manageStamp = function( stamp ) { 3709 this._mode()._manageStamp( stamp ); 3710 }; 3711 3712 proto._getContainerSize = function() { 3713 return this._mode()._getContainerSize(); 3714 }; 3715 3716 proto.needsResizeLayout = function() { 3717 return this._mode().needsResizeLayout(); 3718 }; 3719 3720 // -------------------------- adding & removing -------------------------- // 3721 3722 // HEADS UP overwrites default Outlayer appended 3723 proto.appended = function( elems ) { 3724 var items = this.addItems( elems ); 3725 if ( !items.length ) { 3726 return; 3727 } 3728 // filter, layout, reveal new items 3729 var filteredItems = this._filterRevealAdded( items ); 3730 // add to filteredItems 3731 this.filteredItems = this.filteredItems.concat( filteredItems ); 3732 }; 3733 3734 // HEADS UP overwrites default Outlayer prepended 3735 proto.prepended = function( elems ) { 3736 var items = this._itemize( elems ); 3737 if ( !items.length ) { 3738 return; 3739 } 3740 // start new layout 3741 this._resetLayout(); 3742 this._manageStamps(); 3743 // filter, layout, reveal new items 3744 var filteredItems = this._filterRevealAdded( items ); 3745 // layout previous items 3746 this.layoutItems( this.filteredItems ); 3747 // add to items and filteredItems 3748 this.filteredItems = filteredItems.concat( this.filteredItems ); 3749 this.items = items.concat( this.items ); 3750 }; 3751 3752 proto._filterRevealAdded = function( items ) { 3753 var filtered = this._filter( items ); 3754 this.hide( filtered.needHide ); 3755 // reveal all new items 3756 this.reveal( filtered.matches ); 3757 // layout new items, no transition 3758 this.layoutItems( filtered.matches, true ); 3759 return filtered.matches; 3760 }; 3761 3762 /** 3763 * Filter, sort, and layout newly-appended item elements 3764 * @param {Array or NodeList or Element} elems 3765 */ 3766 proto.insert = function( elems ) { 3767 var items = this.addItems( elems ); 3768 if ( !items.length ) { 3769 return; 3770 } 3771 // append item elements 3772 var i, item; 3773 var len = items.length; 3774 for ( i=0; i < len; i++ ) { 3775 item = items[i]; 3776 this.element.appendChild( item.element ); 3777 } 3778 // filter new stuff 3779 var filteredInsertItems = this._filter( items ).matches; 3780 // set flag 3781 for ( i=0; i < len; i++ ) { 3782 items[i].isLayoutInstant = true; 3783 } 3784 this.arrange(); 3785 // reset flag 3786 for ( i=0; i < len; i++ ) { 3787 delete items[i].isLayoutInstant; 3788 } 3789 this.reveal( filteredInsertItems ); 3790 }; 3791 3792 var _remove = proto.remove; 3793 proto.remove = function( elems ) { 3794 elems = utils.makeArray( elems ); 3795 var removeItems = this.getItems( elems ); 3796 // do regular thing 3797 _remove.call( this, elems ); 3798 // bail if no items to remove 3799 var len = removeItems && removeItems.length; 3800 // remove elems from filteredItems 3801 for ( var i=0; len && i < len; i++ ) { 3802 var item = removeItems[i]; 3803 // remove item from collection 3804 utils.removeFrom( this.filteredItems, item ); 3805 } 3806 }; 3807 3808 proto.shuffle = function() { 3809 // update random sortData 3810 for ( var i=0; i < this.items.length; i++ ) { 3811 var item = this.items[i]; 3812 item.sortData.random = Math.random(); 3813 } 3814 this.options.sortBy = 'random'; 3815 this._sort(); 3816 this._layout(); 3817 }; 3818 3819 /** 3820 * trigger fn without transition 3821 * kind of hacky to have this in the first place 3822 * @param {Function} fn 3823 * @param {Array} args 3824 * @returns ret 3825 * @private 3826 */ 3827 proto._noTransition = function( fn, args ) { 3828 // save transitionDuration before disabling 3829 var transitionDuration = this.options.transitionDuration; 3830 // disable transition 3831 this.options.transitionDuration = 0; 3832 // do it 3833 var returnValue = fn.apply( this, args ); 3834 // re-enable transition for reveal 3835 this.options.transitionDuration = transitionDuration; 3836 return returnValue; 3837 }; 3838 3839 // ----- helper methods ----- // 3840 3841 /** 3842 * getter method for getting filtered item elements 3843 * @returns {Array} elems - collection of item elements 3844 */ 3845 proto.getFilteredItemElements = function() { 3846 return this.filteredItems.map( function( item ) { 3847 return item.element; 3848 }); 3849 }; 3850 3851 // ----- ----- // 3852 3853 return Isotope; 3854 3855})); 3856
3857/*! 3858 * Packery layout mode PACKAGED v2.0.1 3859 * sub-classes Packery 3860 */ 3861 3862/** 3863 * Rect 3864 * low-level utility class for basic geometry 3865 */ 3866 3867( function( window, factory ) { 3868 // universal module definition 3869 /* jshint strict: false */ /* globals define, module */ 3870 if ( typeof define == 'function' && define.amd ) { 3871 // AMD 3872 define( 'packery/js/rect',factory ); 3873 } else if ( typeof module == 'object' && module.exports ) { 3874 // CommonJS 3875 module.exports = factory(); 3876 } else { 3877 // browser global 3878 window.Packery = window.Packery || {}; 3879 window.Packery.Rect = factory(); 3880 } 3881 3882}( window, function factory() { 3883 3884 3885// -------------------------- Rect -------------------------- // 3886 3887function Rect( props ) { 3888 // extend properties from defaults 3889 for ( var prop in Rect.defaults ) { 3890 this[ prop ] = Rect.defaults[ prop ]; 3891 } 3892 3893 for ( prop in props ) { 3894 this[ prop ] = props[ prop ]; 3895 } 3896 3897} 3898 3899Rect.defaults = { 3900 x: 0, 3901 y: 0, 3902 width: 0, 3903 height: 0 3904}; 3905 3906var proto = Rect.prototype; 3907 3908/** 3909 * Determines whether or not this rectangle wholly encloses another rectangle or point. 3910 * @param {Rect} rect 3911 * @returns {Boolean} 3912**/ 3913proto.contains = function( rect ) { 3914 // points don't have width or height 3915 var otherWidth = rect.width || 0; 3916 var otherHeight = rect.height || 0; 3917 return this.x <= rect.x && 3918 this.y <= rect.y && 3919 this.x + this.width >= rect.x + otherWidth && 3920 this.y + this.height >= rect.y + otherHeight; 3921}; 3922 3923/** 3924 * Determines whether or not the rectangle intersects with another. 3925 * @param {Rect} rect 3926 * @returns {Boolean} 3927**/ 3928proto.overlaps = function( rect ) { 3929 var thisRight = this.x + this.width; 3930 var thisBottom = this.y + this.height; 3931 var rectRight = rect.x + rect.width; 3932 var rectBottom = rect.y + rect.height; 3933 3934 // http://stackoverflow.com/a/306332 3935 return this.x < rectRight && 3936 thisRight > rect.x && 3937 this.y < rectBottom && 3938 thisBottom > rect.y; 3939}; 3940 3941/** 3942 * @param {Rect} rect - the overlapping rect 3943 * @returns {Array} freeRects - rects representing the area around the rect 3944**/ 3945proto.getMaximalFreeRects = function( rect ) { 3946 3947 // if no intersection, return false 3948 if ( !this.overlaps( rect ) ) { 3949 return false; 3950 } 3951 3952 var freeRects = []; 3953 var freeRect; 3954 3955 var thisRight = this.x + this.width; 3956 var thisBottom = this.y + this.height; 3957 var rectRight = rect.x + rect.width; 3958 var rectBottom = rect.y + rect.height; 3959 3960 // top 3961 if ( this.y < rect.y ) { 3962 freeRect = new Rect({ 3963 x: this.x, 3964 y: this.y, 3965 width: this.width, 3966 height: rect.y - this.y 3967 }); 3968 freeRects.push( freeRect ); 3969 } 3970 3971 // right 3972 if ( thisRight > rectRight ) { 3973 freeRect = new Rect({ 3974 x: rectRight, 3975 y: this.y, 3976 width: thisRight - rectRight, 3977 height: this.height 3978 }); 3979 freeRects.push( freeRect ); 3980 } 3981 3982 // bottom 3983 if ( thisBottom > rectBottom ) { 3984 freeRect = new Rect({ 3985 x: this.x, 3986 y: rectBottom, 3987 width: this.width, 3988 height: thisBottom - rectBottom 3989 }); 3990 freeRects.push( freeRect ); 3991 } 3992 3993 // left 3994 if ( this.x < rect.x ) { 3995 freeRect = new Rect({ 3996 x: this.x, 3997 y: this.y, 3998 width: rect.x - this.x, 3999 height: this.height 4000 }); 4001 freeRects.push( freeRect ); 4002 } 4003 4004 return freeRects; 4005}; 4006 4007proto.canFit = function( rect ) { 4008 return this.width >= rect.width && this.height >= rect.height; 4009}; 4010 4011return Rect; 4012 4013})); 4014 4015/** 4016 * Packer 4017 * bin-packing algorithm 4018 */ 4019 4020( function( window, factory ) { 4021 // universal module definition 4022 /* jshint strict: false */ /* globals define, module, require */ 4023 if ( typeof define == 'function' && define.amd ) { 4024 // AMD 4025 define( 'packery/js/packer',[ './rect' ], factory ); 4026 } else if ( typeof module == 'object' && module.exports ) { 4027 // CommonJS 4028 module.exports = factory( 4029 require('./rect') 4030 ); 4031 } else { 4032 // browser global 4033 var Packery = window.Packery = window.Packery || {}; 4034 Packery.Packer = factory( Packery.Rect ); 4035 } 4036 4037}( window, function factory( Rect ) { 4038 4039 4040// -------------------------- Packer -------------------------- // 4041 4042/** 4043 * @param {Number} width 4044 * @param {Number} height 4045 * @param {String} sortDirection 4046 * topLeft for vertical, leftTop for horizontal 4047 */ 4048function Packer( width, height, sortDirection ) { 4049 this.width = width || 0; 4050 this.height = height || 0; 4051 this.sortDirection = sortDirection || 'downwardLeftToRight'; 4052 4053 this.reset(); 4054} 4055 4056var proto = Packer.prototype; 4057 4058proto.reset = function() { 4059 this.spaces = []; 4060 4061 var initialSpace = new Rect({ 4062 x: 0, 4063 y: 0, 4064 width: this.width, 4065 height: this.height 4066 }); 4067 4068 this.spaces.push( initialSpace ); 4069 // set sorter 4070 this.sorter = sorters[ this.sortDirection ] || sorters.downwardLeftToRight; 4071}; 4072 4073// change x and y of rect to fit with in Packer's available space
4073s 4074proto.pack = function( rect ) { 4075 for ( var i=0; i < this.spaces.length; i++ ) { 4076 var space = this.spaces[i]; 4077 if ( space.canFit( rect ) ) { 4078 this.placeInSpace( rect, space ); 4079 break; 4080 } 4081 } 4082}; 4083 4084proto.columnPack = function( rect ) { 4085 for ( var i=0; i < this.spaces.length; i++ ) { 4086 var space = this.spaces[i]; 4087 var canFitInSpaceColumn = space.x <= rect.x && 4088 space.x + space.width >= rect.x + rect.width && 4089 space.height >= rect.height - 0.01; // fudge number for rounding error 4090 if ( canFitInSpaceColumn ) { 4091 rect.y = space.y; 4092 this.placed( rect ); 4093 break; 4094 } 4095 } 4096}; 4097 4098proto.rowPack = function( rect ) { 4099 for ( var i=0; i < this.spaces.length; i++ ) { 4100 var space = this.spaces[i]; 4101 var canFitInSpaceRow = space.y <= rect.y && 4102 space.y + space.height >= rect.y + rect.height && 4103 space.width >= rect.width - 0.01; // fudge number for rounding error 4104 if ( canFitInSpaceRow ) { 4105 rect.x = space.x; 4106 this.placed( rect ); 4107 break; 4108 } 4109 } 4110}; 4111 4112proto.placeInSpace = function( rect, space ) { 4113 // place rect in space 4114 rect.x = space.x; 4115 rect.y = space.y; 4116 4117 this.placed( rect ); 4118}; 4119 4120// update spaces with placed rect 4121proto.placed = function( rect ) { 4122 // update spaces 4123 var revisedSpaces = []; 4124 for ( var i=0; i < this.spaces.length; i++ ) { 4125 var space = this.spaces[i]; 4126 var newSpaces = space.getMaximalFreeRects( rect ); 4127 // add either the original space or the new spaces to the revised spaces 4128 if ( newSpaces ) { 4129 revisedSpaces.push.apply( revisedSpaces, newSpaces ); 4130 } else { 4131 revisedSpaces.push( space ); 4132 } 4133 } 4134 4135 this.spaces = revisedSpaces; 4136 4137 this.mergeSortSpaces(); 4138}; 4139 4140proto.mergeSortSpaces = function() { 4141 // remove redundant spaces 4142 Packer.mergeRects( this.spaces ); 4143 this.spaces.sort( this.sorter ); 4144}; 4145 4146// add a space back 4147proto.addSpace = function( rect ) { 4148 this.spaces.push( rect ); 4149 this.mergeSortSpaces(); 4150}; 4151 4152// -------------------------- utility functions -------------------------- // 4153 4154/** 4155 * Remove redundant rectangle from array of rectangles 4156 * @param {Array} rects: an array of Rects 4157 * @returns {Array} rects: an array of Rects 4158**/ 4159Packer.mergeRects = function( rects ) { 4160 var i = 0; 4161 var rect = rects[i]; 4162 4163 rectLoop: 4164 while ( rect ) { 4165 var j = 0; 4166 var compareRect = rects[ i + j ]; 4167 4168 while ( compareRect ) { 4169 if ( compareRect == rect ) { 4170 j++; // next 4171 } else if ( compareRect.contains( rect ) ) { 4172 // remove rect 4173 rects.splice( i, 1 ); 4174 rect = rects[i]; // set next rect 4175 continue rectLoop; // bail on compareLoop 4176 } else if ( rect.contains( compareRect ) ) { 4177 // remove compareRect 4178 rects.splice( i + j, 1 ); 4179 } else { 4180 j++; 4181 } 4182 compareRect = rects[ i + j ]; // set next compareRect 4183 } 4184 i++; 4185 rect = rects[i]; 4186 } 4187 4188 return rects; 4189}; 4190 4191 4192// -------------------------- sorters -------------------------- // 4193 4194// functions for sorting rects in order 4195var sorters = { 4196 // top down, then left to right 4197 downwardLeftToRight: function( a, b ) { 4198 return a.y - b.y || a.x - b.x; 4199 }, 4200 // left to right, then top down 4201 rightwardTopToBottom: function( a, b ) { 4202 return a.x - b.x || a.y - b.y; 4203 } 4204}; 4205 4206 4207// -------------------------- -------------------------- // 4208 4209return Packer; 4210 4211})); 4212 4213/** 4214 * Packery Item Element 4215**/ 4216 4217( function( window, factory ) { 4218 // universal module definition 4219 /* jshint strict: false */ /* globals define, module, require */ 4220 if ( typeof define == 'function' && define.amd ) { 4221 // AMD 4222 define( 'packery/js/item',[ 4223 'outlayer/outlayer', 4224 './rect' 4225 ], 4226 factory ); 4227 } else if ( typeof module == 'object' && module.exports ) { 4228 // CommonJS 4229 module.exports = factory( 4230 require('outlayer'), 4231 require('./rect') 4232 ); 4233 } else { 4234 // browser global 4235 window.Packery.Item = factory( 4236 window.Outlayer, 4237 window.Packery.Rect 4238 ); 4239 } 4240 4241}( window, function factory( Outlayer, Rect ) { 4242 4243 4244// -------------------------- Item -------------------------- // 4245 4246var docElemStyle = document.documentElement.style; 4247 4248var transformProperty = typeof docElemStyle.transform == 'string' ? 4249 'transform' : 'WebkitTransform'; 4250 4251// sub-class Item 4252var Item = function PackeryItem() { 4253 Outlayer.Item.apply( this, arguments ); 4254}; 4255 4256var proto = Item.prototype = Object.create( Outlayer.Item.prototype ); 4257 4258var __create = proto._create; 4259proto._create = function() { 4260 // call default _create logic 4261 __create.call( this ); 4262 this.rect = new Rect(); 4263}; 4264 4265var _moveTo = proto.moveTo; 4266proto.moveTo = function( x, y ) {
4267 // don't shift 1px while dragging 4268 var dx = Math.abs( this.position.x - x ); 4269 var dy = Math.abs( this.position.y - y ); 4270 4271 var canHackGoTo = this.layout.dragItemCount && !this.isPlacing && 4272 !this.isTransitioning && dx < 1 && dy < 1; 4273 if ( canHackGoTo ) { 4274 this.goTo( x, y ); 4275 return; 4276 } 4277 _moveTo.apply( this, arguments ); 4278}; 4279 4280// -------------------------- placing -------------------------- // 4281 4282proto.enablePlacing = function() { 4283 this.removeTransitionStyles(); 4284 // remove transform property from transition 4285 if ( this.isTransitioning && transformProperty ) { 4286 this.element.style[ transformProperty ] = 'none'; 4287 } 4288 this.isTransitioning = false; 4289 this.getSize(); 4290 this.layout._setRectSize( this.element, this.rect ); 4291 this.isPlacing = true; 4292}; 4293 4294proto.disablePlacing = function() { 4295 this.isPlacing = false; 4296}; 4297 4298// ----- ----- // 4299 4300// remove element from DOM 4301proto.removeElem = function() { 4302 this.element.parentNode.removeChild( this.element ); 4303 // add space back to packer 4304 this.layout.packer.addSpace( this.rect ); 4305 this.emitEvent( 'remove', [ this ] ); 4306}; 4307 4308// ----- dropPlaceholder ----- // 4309 4310proto.showDropPlaceholder = function() { 4311 var dropPlaceholder = this.dropPlaceholder; 4312 if ( !dropPlaceholder ) { 4313 // create dropPlaceholder 4314 dropPlaceholder = this.dropPlaceholder = document.createElement('div'); 4315 dropPlaceholder.className = 'packery-drop-placeholder'; 4316 dropPlaceholder.style.position = 'absolute'; 4317 } 4318 4319 dropPlaceholder.style.width = this.size.width + 'px'; 4320 dropPlaceholder.style.height = this.size.height + 'px'; 4321 this.positionDropPlaceholder(); 4322 this.layout.element.appendChild( dropPlaceholder ); 4323}; 4324 4325proto.positionDropPlaceholder = function() { 4326 this.dropPlaceholder.style[ transformProperty ] = 'translate(' + 4327 this.rect.x + 'px, ' + this.rect.y + 'px)'; 4328}; 4329 4330proto.hideDropPlaceholder = function() { 4331 this.layout.element.removeChild( this.dropPlaceholder ); 4332}; 4333 4334// ----- ----- // 4335 4336return Item; 4337 4338})); 4339 4340/*! 4341 * Packery v2.0.0 4342 * Gapless, draggable grid layouts 4343 * 4344 * Licensed GPLv3 for open source use 4345 * or Packery Commercial License for commercial use 4346 * 4347 * http://packery.metafizzy.co 4348 * Copyright 2016 Metafizzy 4349 */ 4350 4351( function( window, factory ) { 4352 // universal module definition 4353 /* jshint strict: false */ /* globals define, module, require */ 4354 if ( typeof define == 'function' && define.amd ) { 4355 // AMD 4356 define( 'packery/js/packery',[ 4357 'get-size/get-size', 4358 'outlayer/outlayer', 4359 './rect', 4360 './packer', 4361 './item' 4362 ], 4363 factory ); 4364 } else if ( typeof module == 'object' && module.exports ) { 4365 // CommonJS 4366 module.exports = factory( 4367 require('get-size'), 4368 require('outlayer'), 4369 require('./rect'), 4370 require('./packer'), 4371 require('./item') 4372 ); 4373 } else { 4374 // browser global 4375 window.Packery = factory( 4376 window.getSize, 4377 window.Outlayer, 4378 window.Packery.Rect, 4379 window.Packery.Packer, 4380 window.Packery.Item 4381 ); 4382 } 4383 4384}( window, function factory( getSize, Outlayer, Rect, Packer, Item ) { 4385 4386 4387// ----- Rect ----- // 4388 4389// allow for pixel rounding errors IE8-IE11 & Firefox; #227 4390Rect.prototype.canFit = function( rect ) { 4391 return this.width >= rect.width - 1 && this.height >= rect.height - 1; 4392}; 4393 4394// -------------------------- Packery -------------------------- // 4395 4396// create an Outlayer layout class 4397var Packery = Outlayer.create('packery'); 4398Packery.Item = Item; 4399 4400var proto = Packery.prototype; 4401 4402proto._create = function() { 4403 // call super 4404 Outlayer.prototype._create.call( this ); 4405 4406 // initial properties 4407 this.packer = new Packer(); 4408 // packer for drop targets 4409 this.shiftPacker = new Packer(); 4410 this.isEnabled = true; 4411 4412 this.dragItemCount = 0; 4413 4414 // create drag handlers 4415 var _this = this; 4416 this.handleDraggabilly = { 4417 dragStart: function() { 4418 _this.itemDragStart( this.element ); 4419 }, 4420 dragMove: function() { 4421 _this.itemDragMove( this.element, this.position.x, this.position.y ); 4422 }, 4423 dragEnd: function() { 4424 _this.itemDragEnd( this.element ); 4425 } 4426 }; 4427 4428 this.handleUIDraggable = { 4429 start: function handleUIDraggableStart( event, ui ) { 4430 // HTML5 may trigger dragstart, dismiss HTML5 dragging 4431 if ( !ui ) { 4432 return; 4433 } 4434 _this.itemDragStart( event.currentTarget ); 4435 }, 4436 drag: function handleUIDraggableDrag( event, ui ) { 4437 if ( !ui ) { 4438 return; 4439 } 4440 _this.itemDragMove( event.currentTarget, ui.position.left, ui.position.top ); 4441 }, 4442 stop: function handleUIDraggableStop( event, ui ) { 4443 if ( !ui ) { 4444 return; 4445 } 4446 _this.itemDragEnd( event.currentTarget ); 4447 } 4448 }; 4449 4450}; 4451 4452 4453// ----- init & layout ----- // 4454 4455/** 4456 * logic before any new layout 4457 */ 4458proto._resetLayout = function() {
4459 this.getSize(); 4460 4461 this._getMeasurements(); 4462 4463 // reset packer 4464 var width, height, sortDirection; 4465 // packer settings, if horizontal or vertical 4466 if ( this._getOption('horizontal') ) { 4467 width = Infinity; 4468 height = this.size.innerHeight + this.gutter; 4469 sortDirection = 'rightwardTopToBottom'; 4470 } else { 4471 width = this.size.innerWidth + this.gutter; 4472 height = Infinity; 4473 sortDirection = 'downwardLeftToRight'; 4474 } 4475 4476 this.packer.width = this.shiftPacker.width = width; 4477 this.packer.height = this.shiftPacker.height = height; 4478 this.packer.sortDirection = this.shiftPacker.sortDirection = sortDirection; 4479 4480 this.packer.reset(); 4481 4482 // layout 4483 this.maxY = 0; 4484 this.maxX = 0; 4485}; 4486 4487/** 4488 * update columnWidth, rowHeight, & gutter 4489 * @private 4490 */ 4491proto._getMeasurements = function() { 4492 this._getMeasurement( 'columnWidth', 'width' ); 4493 this._getMeasurement( 'rowHeight', 'height' ); 4494 this._getMeasurement( 'gutter', 'width' ); 4495}; 4496 4497proto._getItemLayoutPosition = function( item ) { 4498 this._setRectSize( item.element, item.rect ); 4499 if ( this.isShifting || this.dragItemCount > 0 ) { 4500 var packMethod = this._getPackMethod(); 4501 this.packer[ packMethod ]( item.rect ); 4502 } else { 4503 this.packer.pack( item.rect ); 4504 } 4505 4506 this._setMaxXY( item.rect ); 4507 return item.rect; 4508}; 4509 4510proto.shiftLayout = function() { 4511 this.isShifting = true; 4512 this.layout(); 4513 delete this.isShifting; 4514}; 4515 4516proto._getPackMethod = function() { 4517 return this._getOption('horizontal') ? 'rowPack' : 'columnPack'; 4518}; 4519 4520 4521/** 4522 * set max X and Y value, for size of container 4523 * @param {Packery.Rect} rect 4524 * @private 4525 */ 4526proto._setMaxXY = function( rect ) { 4527 this.maxX = Math.max( rect.x + rect.width, this.maxX ); 4528 this.maxY = Math.max( rect.y + rect.height, this.maxY ); 4529}; 4530 4531/** 4532 * set the width and height of a rect, applying columnWidth and rowHeight 4533 * @param {Element} elem 4534 * @param {Packery.Rect} rect 4535 */ 4536proto._setRectSize = function( elem, rect ) { 4537 var size = getSize( elem ); 4538 var w = size.outerWidth; 4539 var h = size.outerHeight; 4540 // size for columnWidth and rowHeight, if available 4541 // only check if size is non-zero, #177 4542 if ( w || h ) { 4543 w = this._applyGridGutter( w, this.columnWidth ); 4544 h = this._applyGridGutter( h, this.rowHeight ); 4545 } 4546 // rect must fit in packer 4547 rect.width = Math.min( w, this.packer.width ); 4548 rect.height = Math.min( h, this.packer.height ); 4549}; 4550 4551/** 4552 * fits item to columnWidth/rowHeight and adds gutter 4553 * @param {Number} measurement - item width or height 4554 * @param {Number} gridSize - columnWidth or rowHeight 4555 * @returns measurement 4556 */ 4557proto._applyGridGutter = function( measurement, gridSize ) { 4558 // just add gutter if no gridSize 4559 if ( !gridSize ) { 4560 return measurement + this.gutter; 4561 } 4562 gridSize += this.gutter; 4563 // fit item to columnWidth/rowHeight 4564 var remainder = measurement % gridSize; 4565 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil'; 4566 measurement = Math[ mathMethod ]( measurement / gridSize ) * gridSize; 4567 return measurement; 4568}; 4569 4570proto._getContainerSize = function() { 4571 if ( this._getOption('horizontal') ) { 4572 return { 4573 width: this.maxX - this.gutter 4574 }; 4575 } else { 4576 return { 4577 height: this.maxY - this.gutter 4578 }; 4579 } 4580}; 4581 4582 4583// -------------------------- stamp -------------------------- // 4584 4585/** 4586 * makes space for element 4587 * @param {Element} elem 4588 */ 4589proto._manageStamp = function( elem ) { 4590 4591 var item = this.getItem( elem ); 4592 var rect; 4593 if ( item && item.isPlacing ) { 4594 rect = item.rect; 4595 } else { 4596 var offset = this._getElementOffset( elem ); 4597 rect = new Rect({ 4598 x: this._getOption('originLeft') ? offset.left : offset.right, 4599 y: this._getOption('originTop') ? offset.top : offset.bottom 4600 }); 4601 } 4602 4603 this._setRectSize( elem, rect ); 4604 // save its space in the packer 4605 this.packer.placed( rect ); 4606 this._setMaxXY( rect ); 4607}; 4608 4609// -------------------------- methods -------------------------- // 4610 4611function verticalSorter( a, b ) { 4612 return a.position.y - b.position.y || a.position.x - b.position.x; 4613} 4614 4615function horizontalSorter( a, b ) { 4616 return a.position.x - b.position.x || a.position.y - b.position.y; 4617} 4618
4619proto.sortItemsByPosition = function() { 4620 var sorter = this._getOption('horizontal') ? horizontalSorter : verticalSorter; 4621 this.items.sort( sorter ); 4622}; 4623 4624/** 4625 * Fit item element in its current position 4626 * Packery will position elements around it 4627 * useful for expanding elements 4628 * 4629 * @param {Element} elem 4630 * @param {Number} x - horizontal destination position, optional 4631 * @param {Number} y - vertical destination position, optional 4632 */ 4633proto.fit = function( elem, x, y ) { 4634 var item = this.getItem( elem ); 4635 if ( !item ) { 4636 return; 4637 } 4638 4639 // stamp item to get it out of layout 4640 this.stamp( item.element ); 4641 // set placing flag 4642 item.enablePlacing(); 4643 this.updateShiftTargets( item ); 4644 // fall back to current position for fitting 4645 x = x === undefined ? item.rect.x: x; 4646 y = y === undefined ? item.rect.y: y; 4647 // position it best at its destination 4648 this.shift( item, x, y ); 4649 this._bindFitEvents( item ); 4650 item.moveTo( item.rect.x, item.rect.y ); 4651 // layout everything else 4652 this.shiftLayout(); 4653 // return back to regularly scheduled programming 4654 this.unstamp( item.element ); 4655 this.sortItemsByPosition(); 4656 item.disablePlacing(); 4657}; 4658 4659/** 4660 * emit event when item is fit and other items are laid out 4661 * @param {Packery.Item} item 4662 * @private 4663 */ 4664proto._bindFitEvents = function( item ) { 4665 var _this = this; 4666 var ticks = 0; 4667 function onLayout() { 4668 ticks++; 4669 if ( ticks != 2 ) { 4670 return; 4671 } 4672 _this.dispatchEvent( 'fitComplete', null, [ item ] ); 4673 } 4674 // when item is laid out 4675 item.once( 'layout', onLayout ); 4676 // when all items are laid out 4677 this.once( 'layoutComplete', onLayout ); 4678}; 4679 4680// -------------------------- resize -------------------------- // 4681 4682// debounced, layout on resize 4683proto.resize = function() { 4684 // don't trigger if size did not change 4685 // or if resize was unbound. See #285, outlayer#9 4686 if ( !this.isResizeBound || !this.needsResizeLayout() ) { 4687 return; 4688 } 4689 4690 if ( this.options.shiftPercentResize ) { 4691 this.resizeShiftPercentLayout(); 4692 } else { 4693 this.layout(); 4694 } 4695}; 4696 4697/** 4698 * check if layout is needed post layout 4699 * @returns Boolean 4700 */ 4701proto.needsResizeLayout = function() { 4702 var size = getSize( this.element ); 4703 var innerSize = this._getOption('horizontal') ? 'innerHeight' : 'innerWidth'; 4704 return size[ innerSize ] != this.size[ innerSize ]; 4705}; 4706 4707proto.resizeShiftPercentLayout = function() { 4708 var items = this._getItemsForLayout( this.items ); 4709 4710 var isHorizontal = this._getOption('horizontal'); 4711 var coord = isHorizontal ? 'y' : 'x'; 4712 var measure = isHorizontal ? 'height' : 'width'; 4713 var segmentName = isHorizontal ? 'rowHeight' : 'columnWidth'; 4714 var innerSize = isHorizontal ? 'innerHeight' : 'innerWidth'; 4715 4716 // proportional re-align items 4717 var previousSegment = this[ segmentName ]; 4718 previousSegment = previousSegment && previousSegment + this.gutter; 4719 4720 if ( previousSegment ) { 4721 this._getMeasurements(); 4722 var currentSegment = this[ segmentName ] + this.gutter; 4723 items.forEach( function( item ) { 4724 var seg = Math.round( item.rect[ coord ] / previousSegment ); 4725 item.rect[ coord ] = seg * currentSegment; 4726 }); 4727 } else { 4728 var currentSize = getSize( this.element )[ innerSize ] + this.gutter; 4729 var previousSize = this.packer[ measure ]; 4730 items.forEach( function( item ) { 4731 item.rect[ coord ] = ( item.rect[ coord ] / previousSize ) * currentSize; 4732 }); 4733 } 4734 4735 this.shiftLayout(); 4736}; 4737 4738// -------------------------- drag -------------------------- // 4739 4740/** 4741 * handle an item drag start event 4742 * @param {Element} elem 4743 */ 4744proto.itemDragStart = function( elem ) { 4745 if ( !this.isEnabled ) { 4746 return; 4747 } 4748 this.stamp( elem ); 4749 // this.ignore( elem ); 4750 var item = this.getItem( elem ); 4751 if ( !item ) { 4752 return; 4753 } 4754 4755 item.enablePlacing(); 4756 item.showDropPlaceholder(); 4757 this.dragItemCount++; 4758 this.updateShiftTargets( item ); 4759}; 4760 4761proto.updateShiftTargets = function( dropItem ) { 4762 this.shiftPacker.reset(); 4763 4764 // pack stamps 4765 this._getBoundingRect(); 4766 var isOriginLeft = this._getOption('originLeft'); 4767 var isOriginTop = this._getOption('originTop'); 4768 this.stamps.forEach( function( stamp ) { 4769 // ignore dragged item 4770 var item = this.getItem( stamp ); 4771 if ( item && item.isPlacing ) { 4772 return; 4773 } 4774 var offset = this._getElementOffset( stamp ); 4775 var rect = new Rect({ 4776 x: isOriginLeft ? offset.left : offset.right, 4777 y: isOriginTop ? offset.top : offset.bottom 4778 }); 4779 this._setRectSize( stamp, rect ); 4780 // save its space in the packer 4781 this.shiftPacker.placed( rect ); 4782 }, this ); 4783 4784 // reset shiftTargets 4785 var isHorizontal = this._getOption('horizontal'); 4786 var segmentName = isHorizontal ? 'rowHeight' : 'columnWidth'; 4787 var measure = isHorizontal ? 'height' : 'width'; 4788 4789 this.shiftTargetKeys = []; 4790 this.shiftTargets = []; 4791 var boundsSize; 4792 var segment = this[ segmentName ]; 4793 segment = segment && segment + this.gutter; 4794 4795 if ( segment ) { 4796 var segmentSpan = Math.ceil( dropItem.rect[ measure ] / segment ); 4797 var segs = Math.floor( ( this.shiftPacker[ measure ] + this.gutter ) / segment ); 4798 boundsSize = ( segs - segmentSpan ) * segment; 4799 // add targets on top 4800 for ( var i=0; i < segs; i++ ) { 4801 this._addShiftTarget( i * segment, 0, boundsSize ); 4802 } 4803 } else { 4804 boundsSize = ( this.shiftPacker[ measure ] + this.gutter ) - dropItem.rect[ measure ]; 4805 this._addShiftTarget( 0, 0, boundsSize ); 4806 } 4807 4808 // pack each item to measure where shiftTargets are 4809 var items = this._getItemsForLayout( this.items ); 4810 var packMethod = this._getPackMethod();
4811 items.forEach( function( item ) { 4812 var rect = item.rect; 4813 this._setRectSize( item.element, rect ); 4814 this.shiftPacker[ packMethod ]( rect ); 4815 4816 // add top left corner 4817 this._addShiftTarget( rect.x, rect.y, boundsSize ); 4818 // add bottom left / top right corner 4819 var cornerX = isHorizontal ? rect.x + rect.width : rect.x; 4820 var cornerY = isHorizontal ? rect.y : rect.y + rect.height; 4821 this._addShiftTarget( cornerX, cornerY, boundsSize ); 4822 4823 if ( segment ) { 4824 // add targets for each column on bottom / row on right 4825 var segSpan = Math.round( rect[ measure ] / segment ); 4826 for ( var i=1; i < segSpan; i++ ) { 4827 var segX = isHorizontal ? cornerX : rect.x + segment * i; 4828 var segY = isHorizontal ? rect.y + segment * i : cornerY; 4829 this._addShiftTarget( segX, segY, boundsSize ); 4830 } 4831 } 4832 }, this ); 4833 4834}; 4835 4836proto._addShiftTarget = function( x, y, boundsSize ) { 4837 var checkCoord = this._getOption('horizontal') ? y : x; 4838 if ( checkCoord !== 0 && checkCoord > boundsSize ) { 4839 return; 4840 } 4841 // create string for a key, easier to keep track of what targets 4842 var key = x + ',' + y; 4843 var hasKey = this.shiftTargetKeys.indexOf( key ) != -1; 4844 if ( hasKey ) { 4845 return; 4846 } 4847 this.shiftTargetKeys.push( key ); 4848 this.shiftTargets.push({ x: x, y: y }); 4849}; 4850 4851// -------------------------- drop -------------------------- // 4852 4853proto.shift = function( item, x, y ) { 4854 var shiftPosition; 4855 var minDistance = Infinity; 4856 var position = { x: x, y: y }; 4857 this.shiftTargets.forEach( function( target ) { 4858 var distance = getDistance( target, position ); 4859 if ( distance < minDistance ) { 4860 shiftPosition = target; 4861 minDistance = distance; 4862 } 4863 }); 4864 item.rect.x = shiftPosition.x; 4865 item.rect.y = shiftPosition.y; 4866}; 4867 4868function getDistance( a, b ) { 4869 var dx = b.x - a.x; 4870 var dy = b.y - a.y; 4871 return Math.sqrt( dx * dx + dy * dy ); 4872} 4873 4874// -------------------------- drag move -------------------------- // 4875 4876var DRAG_THROTTLE_TIME = 120; 4877 4878/** 4879 * handle an item drag move event 4880 * @param {Element} elem 4881 * @param {Number} x - horizontal change in position 4882 * @param {Number} y - vertical change in position 4883 */ 4884proto.itemDragMove = function( elem, x, y ) { 4885 var item = this.isEnabled && this.getItem( elem ); 4886 if ( !item ) { 4887 return; 4888 } 4889 4890 x -= this.size.paddingLeft; 4891 y -= this.size.paddingTop; 4892 4893 var _this = this; 4894 function onDrag() { 4895 _this.shift( item, x, y ); 4896 item.positionDropPlaceholder(); 4897 _this.layout(); 4898 } 4899 4900 // throttle 4901 var now = new Date(); 4902 if ( this._itemDragTime && now - this._itemDragTime < DRAG_THROTTLE_TIME ) { 4903 clearTimeout( this.dragTimeout ); 4904 this.dragTimeout = setTimeout( onDrag, DRAG_THROTTLE_TIME ); 4905 } else { 4906 onDrag(); 4907 this._itemDragTime = now; 4908 } 4909}; 4910 4911// -------------------------- drag end -------------------------- // 4912 4913/** 4914 * handle an item drag end event 4915 * @param {Element} elem 4916 */ 4917proto.itemDragEnd = function( elem ) { 4918 var item = this.isEnabled && this.getItem( elem ); 4919 if ( !item ) { 4920 return; 4921 } 4922 4923 clearTimeout( this.dragTimeout ); 4924 item.element.classList.add('is-positioning-post-drag'); 4925 4926 var completeCount = 0; 4927 var _this = this; 4928 function onDragEndLayoutComplete() { 4929 completeCount++; 4930 if ( completeCount != 2 ) { 4931 return; 4932 } 4933 // reset drag item 4934 item.element.classList.remove('is-positioning-post-drag'); 4935 item.hideDropPlaceholder(); 4936 _this.dispatchEvent( 'dragItemPositioned', null, [ item ] ); 4937 } 4938 4939 item.once( 'layout', onDragEndLayoutComplete ); 4940 this.once( 'layoutComplete', onDragEndLayoutComplete ); 4941 item.moveTo( item.rect.x, item.rect.y ); 4942 this.layout(); 4943 this.dragItemCount = Math.max( 0, this.dragItemCount - 1 ); 4944 this.sortItemsByPosition(); 4945 item.disablePlacing(); 4946 this.unstamp( item.element ); 4947}; 4948 4949/** 4950 * binds Draggabilly events 4951 * @param {Draggabilly} draggie 4952 */ 4953proto.bindDraggabillyEvents = function( draggie ) { 4954 this._bindDraggabillyEvents( draggie, 'on' ); 4955}; 4956 4957proto.unbindDraggabillyEvents = function( draggie ) { 4958 this._bindDraggabillyEvents( draggie, 'off' ); 4959}; 4960 4961proto._bindDraggabillyEvents = function( draggie, method ) { 4962 var handlers = this.handleDraggabilly; 4963 draggie[ method ]( 'dragStart', handlers.dragStart ); 4964 draggie[ method ]( 'dragMove', handlers.dragMove ); 4965 draggie[ method ]( 'dragEnd', handlers.dragEnd ); 4966}; 4967 4968/** 4969 * binds jQuery UI Draggable events 4970 * @param {jQuery} $elems 4971 */ 4972proto.bindUIDraggableEvents = function( $elems ) { 4973 this._bindUIDraggableEvents( $elems, 'on' ); 4974}; 4975 4976proto.unbindUIDraggableEvents = function( $elems ) { 4977 this._bindUIDraggableEvents( $elems, 'off' ); 4978}; 4979 4980proto._bindUIDraggableEvents = function( $elems, method ) { 4981 var handlers = this.handleUIDraggable; 4982 $elems 4983 [ method ]( 'dragstart', handlers.start ) 4984 [ method ]( 'drag', handlers.drag ) 4985 [ method ]( 'dragstop', handlers.stop ); 4986}; 4987 4988// ----- destroy ----- // 4989 4990var _destroy = proto.destroy; 4991proto.destroy = function() { 4992 _destroy.apply( this, arguments ); 4993 // disable flag; prevent drag events from triggering. #72 4994 this.isEnabled = false;
4995}; 4996 4997// ----- ----- // 4998 4999Packery.Rect = Rect; 5000Packery.Packer = Packer; 5001 5002return Packery; 5003 5004})); 5005 5006/*! 5007 * Packery layout mode v2.0.1 5008 * sub-classes Packery 5009 */ 5010 5011/*jshint browser: true, strict: true, undef: true, unused: true */ 5012 5013( function( window, factory ) { 5014 5015 // universal module definition 5016 if ( typeof define == 'function' && define.amd ) { 5017 // AMD 5018 define( [ 5019 'isotope-layout/js/layout-mode', 5020 'packery/js/packery' 5021 ], 5022 factory ); 5023 } else if ( typeof module == 'object' && module.exports ) { 5024 // CommonJS 5025 module.exports = factory( 5026 require('isotope-layout/js/layout-mode'), 5027 require('packery') 5028 ); 5029 } else { 5030 // browser global 5031 factory( 5032 window.Isotope.LayoutMode, 5033 window.Packery 5034 ); 5035 } 5036 5037}( window, function factor( LayoutMode, Packery ) { 5038 5039 5040 // create an Outlayer layout class 5041 var PackeryMode = LayoutMode.create('packery'); 5042 var proto = PackeryMode.prototype; 5043 5044 var keepModeMethods = { 5045 _getElementOffset: true, 5046 _getMeasurement: true 5047 }; 5048 5049 // inherit Packery prototype 5050 for ( var method in Packery.prototype ) { 5051 // do not inherit mode methods 5052 if ( !keepModeMethods[ method ] ) { 5053 proto[ method ] = Packery.prototype[ method ]; 5054 } 5055 } 5056 5057 // set packer in _resetLayout 5058 var _resetLayout = proto._resetLayout; 5059 proto._resetLayout = function() { 5060 this.packer = this.packer || new Packery.Packer(); 5061 this.shiftPacker = this.shiftPacker || new Packery.Packer(); 5062 _resetLayout.apply( this, arguments ); 5063 }; 5064 5065 var _getItemLayoutPosition = proto._getItemLayoutPosition; 5066 proto._getItemLayoutPosition = function( item ) { 5067 // set packery rect 5068 item.rect = item.rect || new Packery.Rect(); 5069 return _getItemLayoutPosition.call( this, item ); 5070 }; 5071 5072 // needsResizeLayout for vertical or horizontal 5073 var _needsResizeLayout = proto.needsResizeLayout; 5074 proto.needsResizeLayout = function() { 5075 if ( this._getOption('horizontal') ) { 5076 return this.needsVerticalResizeLayout(); 5077 } else { 5078 return _needsResizeLayout.call( this ); 5079 } 5080 }; 5081 5082 // point to mode options for horizontal 5083 var _getOption = proto._getOption; 5084 proto._getOption = function( option ) { 5085 if ( option == 'horizontal' ) { 5086 return this.options.isHorizontal !== undefined ? 5087 this.options.isHorizontal : this.options.horizontal; 5088 } 5089 return _getOption.apply( this.isotope, arguments ); 5090 }; 5091 5092 return PackeryMode; 5093 5094})); 5095 5096/*! 5097 * cellsByRows layout mode for Isotope 5098 * v1.1.3 5099 * http://isotope.metafizzy.co/layout-modes/cellsbyrow.html 5100 */ 5101 5102/*jshint browser: true, devel: false, strict: true, undef: true, unused: true */ 5103 5104( function( window, factory ) { 5105 // universal module definition 5106 /* jshint strict: false */ /*globals define, module, require */ 5107 if ( typeof define === 'function' && define.amd ) { 5108 // AMD 5109 define( [ 5110 'isotope/js/layout-mode' 5111 ], 5112 factory ); 5113 } else if ( typeof exports === 'object' ) { 5114 // CommonJS 5115 module.exports = factory( 5116 require('isotope-layout/js/layout-mode') 5117 ); 5118 } else { 5119 // browser global 5120 factory( 5121 window.Isotope.LayoutMode 5122 ); 5123 } 5124 5125}( window, function factory( LayoutMode ) { 5126 'use strict'; 5127 5128 var CellsByRow = LayoutMode.create( 'cellsByRow' ); 5129 var proto = CellsByRow.prototype; 5130 5131 proto._resetLayout = function() { 5132 // reset properties 5133 this.itemIndex = 0; 5134 // measurements 5135 this.getColumnWidth(); 5136 this.getRowHeight(); 5137 // set cols 5138 this.cols = Math.floor( this.isotope.size.innerWidth / this.columnWidth ); 5139 this.cols = Math.max( this.cols, 1 ); 5140 }; 5141 5142 proto._getItemLayoutPosition = function( item ) { 5143 item.getSize(); 5144 var col = this.itemIndex % this.cols; 5145 var row = Math.floor( this.itemIndex / this.cols ); 5146 // center item within cell 5147 var x = ( col + 0.5 ) * this.columnWidth - item.size.outerWidth / 2; 5148 var y = ( row + 0.5 ) * this.rowHeight - item.size.outerHeight / 2; 5149 this.itemIndex++; 5150 return { x: x, y: y }; 5151 }; 5152 5153 proto._getContainerSize = function() { 5154 return { 5155 height: Math.ceil( this.itemIndex / this.cols ) * this.rowHeight 5156 }; 5157 }; 5158 5159 return CellsByRow; 5160 5161})); 5162/*global jQuery: true */ 5163 5164/*! 5165 -------------------------------- 5166 Infinite Scroll 5167 -------------------------------- 5168 + https://github.com/paulirish/infinite-scroll 5169 + version 2.1.0 5170 + Copyright 2011/12 Paul Irish & Luke Shumard 5171 + Licensed under the MIT license 5172 5173 + Documentation: http://infinite-scroll.com/ 5174*/ 5175 5176// Uses AMD or browser globals to create a jQuery plugin. 5177(function (factory) { 5178 if (typeof define === 'function' && define.amd) { 5179 // AMD. Register as an anonymous module. 5180 define(['jquery'], factory); 5181 } else { 5182 // Browser globals 5183 factory(jQuery); 5184 } 5185}(function ($, undefined) { 5186 'use strict'; 5187
5188 $.infinitescroll = function infscr(options, callback, element) { 5189 this.element = $(element); 5190 5191 // Flag the object in the event of a failed creation 5192 if (!this._create(options, callback)) { 5193 this.failed = true; 5194 } 5195 }; 5196 5197 $.infinitescroll.defaults = { 5198 loading: { 5199 finished: undefined, 5200 finishedMsg: "<em>Congratulations, you've reached the end of the internet.</em>", 5201 img: 'data:image/gif;base64,R0lGODlh3AATAPQeAPDy+MnQ6LW/4N3h8MzT6rjC4sTM5r/I5NHX7N7j8c7U6tvg8OLl8uXo9Ojr9b3G5MfP6Ovu9tPZ7PT1+vX2+tbb7vf4+8/W69jd7rC73vn5/O/x+K243ai02////wAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQECgD/ACwAAAAA3AATAAAF/6AnjmRpnmiqrmzrvnAsz3Rt33iu73zv/8CgcEj0BAScpHLJbDqf0Kh0Sq1ar9isdioItAKGw+MAKYMFhbF63CW438f0mg1R2O8EuXj/aOPtaHx7fn96goR4hmuId4qDdX95c4+RBIGCB4yAjpmQhZN0YGYGXitdZBIVGAsLoq4BBKQDswm1CQRkcG6ytrYKubq8vbfAcMK9v7q7EMO1ycrHvsW6zcTKsczNz8HZw9vG3cjTsMIYqQkCLBwHCgsMDQ4RDAYIqfYSFxDxEfz88/X38Onr16+Bp4ADCco7eC8hQYMAEe57yNCew4IVBU7EGNDiRn8Z831cGLHhSIgdFf9chIeBg7oA7gjaWUWTVQAGE3LqBDCTlc9WOHfm7PkTqNCh54rePDqB6M+lR536hCpUqs2gVZM+xbrTqtGoWqdy1emValeXKzggYBBB5y1acFNZmEvXAoN2cGfJrTv3bl69Ffj2xZt3L1+/fw3XRVw4sGDGcR0fJhxZsF3KtBTThZxZ8mLMgC3fRatCbYMNFCzwLEqLgE4NsDWs/tvqdezZf13Hvk2A9Szdu2X3pg18N+68xXn7rh1c+PLksI/Dhe6cuO3ow3NfV92bdArTqC2Ebd3A8vjf5QWfH6Bg7Nz17c2fj69+fnq+8N2Lty+fuP78/eV2X13neIcCeBRwxorbZrA1ANoCDGrgoG8RTshahQ9iSKEEzUmYIYfNWViUhheCGJyIP5E4oom7WWjgCeBFAJNv1DVV01MAdJhhjdkplWNzO/5oXI846njjVEIqR2OS2B1pE5PVscajkxhMycqLJghQSwT40PgfAl4GqNSXYdZXJn5gSkmmmmJu1aZYb14V51do+pTOCmA40AqVCIhG5IJ9PvYnhIFOxmdqhpaI6GeHCtpooisuutmg+Eg62KOMKuqoTaXgicQWoIYq6qiklmoqFV0UoeqqrLbq6quwxirrrLTWauutJ4QAACH5BAUKABwALAcABADOAAsAAAX/IPd0D2dyRCoUp/k8gpHOKtseR9yiSmGbuBykler9XLAhkbDavXTL5k2oqFqNOxzUZPU5YYZd1XsD72rZpBjbeh52mSNnMSC8lwblKZGwi+0QfIJ8CncnCoCDgoVnBHmKfByGJimPkIwtiAeBkH6ZHJaKmCeVnKKTHIihg5KNq4uoqmEtcRUtEREMBggtEr4QDrjCuRC8h7/BwxENeicSF8DKy82pyNLMOxzWygzFmdvD2L3P0dze4+Xh1Arkyepi7dfFvvTtLQkZBC0T/FX3CRgCMOBHsJ+EHYQY7OinAGECgQsB+Lu3AOK+CewcWjwxQeJBihtNGHSoQOE+iQ3//4XkwBBhRZMcUS6YSXOAwIL8PGqEaSJCiYt9SNoCmnJPAgUVLChdaoFBURN8MAzl2PQphwQLfDFd6lTowglHve6rKpbjhK7/pG5VinZP1qkiz1rl4+tr2LRwWU64cFEihwEtZgbgR1UiHaMVvxpOSwBA37kzGz9e8G+B5MIEKLutOGEsAH2ATQwYfTmuX8aETWdGPZmiZcccNSzeTCA1Sw0bdiitC7LBWgu8jQr8HRzqgpK6gX88QbrB14z/kF+ELpwB8eVQj/JkqdylAudji/+ts3039vEEfK8Vz2dlvxZKG0CmbkKDBvllRd6fCzDvBLKBDSCeffhRJEFebFk1k/Mv9jVIoIJZSeBggwUaNeB+Qk34IE0cXlihcfRxkOAJFFhwGmKlmWDiakZhUJtnLBpnWWcnKaAZcxI0piFGGLBm1mc90kajSCveeBVWKeYEoU2wqeaQi0PetoE+rr14EpVC7oAbAUHqhYExbn2XHHsVqbcVew9tx8+XJKk5AZsqqdlddGpqAKdbAYBn1pcczmSTdWvdmZ17c1b3FZ99vnTdCRFM8OEcAhLwm1NdXnWcBBSMRWmfkWZqVlsmLIiAp/o1gGV2vpS4lalGYsUOqXrddcKCmK61aZ8SjEpUpVFVoCpTj4r661Km7kBHjrDyc1RAIQAAIfkEBQoAGwAsBwAEAM4ACwAABf/gtmUCd4goQQgFKj6PYKi0yrrbc8i4ohQt12EHcal+MNSQiCP8gigdz7iCioaCIvUmZLp8QBzW0EN2vSlCuDtFKaq4RyHzQLEKZNdiQDhRDVooCwkbfm59EAmKi4SGIm+AjIsKjhsqB4mSjT2IOIOUnICeCaB/mZKFNTSRmqVpmJqklSqskq6PfYYCDwYHDC4REQwGCBLGxxIQDsHMwhAIX8bKzcENgSLGF9PU1j3Sy9zX2NrgzQziChLk1BHWxcjf7N046tvN82715czn9Pryz6Ilc4ACj4EBOCZM8KEnAYYADBRKnACAYUMFv1wotIhCEcaJCisqwJFgAUSQGyX/kCSVUUTIdKMwJlyo0oXHlhskwrTJciZHEXsgaqS4s6PJiCAr1uzYU8kBBSgnWFqpoMJMUjGtDmUwkmfVmVypakWhEKvXsS4nhLW5wNjVroJIoc05wSzTr0PtiigpYe4EC2vj4iWrFu5euWIMRBhacaVJhYQBEFjA9jHjyQ0xEABwGceGAZYjY0YBOrRLCxUp29QM+bRkx5s7ZyYgVbTqwwti2ybJ+vLtDYpycyZbYOlptxdx0kV+V7lC5iJAyyRrwYKxAdiz82ng0/jnAdMJFz0cPi104Ec1Vj9/M6F173vKL/feXv156dw11tlqeMMnv4V5Ap53GmjQQH97nFfg+IFiucfgRX5Z8KAgbUlQ4IULIlghhhdOSB6AgX0IVn8eReghen3NRIBsRgnH4l4LuEidZBjwRpt6NM5WGwoW0KSjCwX6yJSMab2GwwAPDXfaBCtWpluRTQqC5JM5oUZAjUNS+VeOLWpJEQ7VYQANW0INJSZVDFSnZphjSikfmzE5N4EEbQI1QJmnWXCmHulRp2edwDXF43txukenJwvI9xyg9Q26Z3MzGUcBYFEChZh6DVTq34AU8Iflh51Sd+CnKFYQ6mmZkhqfBKfSxZWqA9DZanWjxmhrWwi0qtCrt/43K6WqVjjpmhIqgEGvculaGKklKstAACEAACH5BAUKABwALAcABADOAAsAAAX/ICdyQmaMYyAUqPgIBiHPxNpy79kqRXH8wAPsRmDdXpAWgWdEIYm2llCHqjVHU+jjJkwqBTecwItShMXkEfNWSh8e1NGAcLgpDGlRgk7EJ/6Ae3VKfoF/fDuFhohVeDeCfXkcCQqDVQcQhn+VNDOYmpSWaoqBlUSfmowjEA+iEAEGDRGztAwGCDcXEA60tXEiCrq8vREMEBLIyRLCxMWSH
5201MzExnbRvQ2Sy7vN0zvVtNfU2tLY3rPgLdnDvca4VQS/Cpk3ABwSLQkYAQwT/P309vcI7OvXr94jBQMJ/nskkGA/BQBRLNDncAIAiDcG6LsxAWOLiQzmeURBKWSLCQbv/1F0eDGinJUKR47YY1IEgQASKk7Yc7ACRwZm7mHweRJoz59BJUogisKCUaFMR0x4SlJBVBFTk8pZivTR0K73rN5wqlXEAq5Fy3IYgHbEzQ0nLy4QSoCjXLoom96VOJEeCosK5n4kkFfqXjl94wa+l1gvAcGICbewAOAxY8l/Ky/QhAGz4cUkGxu2HNozhwMGBnCUqUdBg9UuW9eUynqSwLHIBujePef1ZGQZXcM+OFuEBeBhi3OYgLyqcuaxbT9vLkf4SeqyWxSQpKGB2gQpm1KdWbu72rPRzR9Ne2Nu9Kzr/1Jqj0yD/fvqP4aXOt5sW/5qsXXVcv1Nsp8IBUAmgswGF3llGgeU1YVXXKTN1FlhWFXW3gIE+DVChApysACHHo7Q4A35lLichh+ROBmLKAzgYmYEYDAhCgxKGOOMn4WR4kkDaoBBOxJtdNKQxFmg5JIWIBnQc07GaORfUY4AEkdV6jHlCEISSZ5yTXpp1pbGZbkWmcuZmQCaE6iJ0FhjMaDjTMsgZaNEHFRAQVp3bqXnZED1qYcECOz5V6BhSWCoVJQIKuKQi2KFKEkEFAqoAo7uYSmO3jk61wUUMKmknJ4SGimBmAa0qVQBhAAAIfkEBQoAGwAsBwAEAM4ACwAABf/gJm5FmRlEqhJC+bywgK5pO4rHI0D3pii22+Mg6/0Ej96weCMAk7cDkXf7lZTTnrMl7eaYoy10JN0ZFdco0XAuvKI6qkgVFJXYNwjkIBcNBgR8TQoGfRsJCRuCYYQQiI+ICosiCoGOkIiKfSl8mJkHZ4U9kZMbKaI3pKGXmJKrngmug4WwkhA0lrCBWgYFCCMQFwoQDRHGxwwGCBLMzRLEx8iGzMMO0cYNeCMKzBDW19lnF9DXDIY/48Xg093f0Q3s1dcR8OLe8+Y91OTv5wrj7o7B+7VNQqABIoRVCMBggsOHE36kSoCBIcSH3EbFangxogJYFi8CkJhqQciLJEf/LDDJEeJIBT0GsOwYUYJGBS0fjpQAMidGmyVP6sx4Y6VQhzs9VUwkwqaCCh0tmKoFtSMDmBOf9phg4SrVrROuasRQAaxXpVUhdsU6IsECZlvX3kwLUWzRt0BHOLTbNlbZG3vZinArge5Dvn7wbqtQkSYAAgtKmnSsYKVKo2AfW048uaPmG386i4Q8EQMBAIAnfB7xBxBqvapJ9zX9WgRS2YMpnvYMGdPK3aMjt/3dUcNI4blpj7iwkMFWDXDvSmgAlijrt9RTR78+PS6z1uAJZIe93Q8g5zcsWCi/4Y+C8bah5zUv3vv89uft30QP23punGCx5954oBBwnwYaNCDY/wYrsYeggnM9B2Fpf8GG2CEUVWhbWAtGouEGDy7Y4IEJVrbSiXghqGKIo7z1IVcXIkKWWR361QOLWWnIhwERpLaaCCee5iMBGJQmJGyPFTnbkfHVZGRtIGrg5HALEJAZbu39BuUEUmq1JJQIPtZilY5hGeSWsSk52G9XqsmgljdIcABytq13HyIM6RcUA+r1qZ4EBF3WHWB29tBgAzRhEGhig8KmqKFv8SeCeo+mgsF7YFXa1qWSbkDpom/mqR1PmHCqJ3fwNRVXjC7S6CZhFVCQ2lWvZiirhQq42SACt25IK2hv8TprriUV1usGgeka7LFcNmCldMLi6qZMgFLgpw16Cipb7bC1knXsBiEAACH5BAUKABsALAcABADOAAsAAAX/4FZsJPkUmUGsLCEUTywXglFuSg7fW1xAvNWLF6sFFcPb42C8EZCj24EJdCp2yoegWsolS0Uu6fmamg8n8YYcLU2bXSiRaXMGvqV6/KAeJAh8VgZqCX+BexCFioWAYgqNi4qAR4ORhRuHY408jAeUhAmYYiuVlpiflqGZa5CWkzc5fKmbbhIpsAoQDRG8vQwQCBLCwxK6vb5qwhfGxxENahvCEA7NzskSy7vNzzzK09W/PNHF1NvX2dXcN8K55cfh69Luveol3vO8zwi4Yhj+AQwmCBw4IYclDAAJDlQggVOChAoLKkgFkSCAHDwWLKhIEOONARsDKryogFPIiAUb/95gJNIiw4wnI778GFPhzBKFOAq8qLJEhQpiNArjMcHCmlTCUDIouTKBhApELSxFWiGiVKY4E2CAekPgUphDu0742nRrVLJZnyrFSqKQ2ohoSYAMW6IoDpNJ4bLdILTnAj8KUF7UeENjAKuDyxIgOuGiOI0EBBMgLNew5AUrDTMGsFixwBIaNCQuAXJB57qNJ2OWm2Aj4skwCQCIyNkhhtMkdsIuodE0AN4LJDRgfLPtn5YDLdBlraAByuUbBgxQwICxMOnYpVOPej074OFdlfc0TqC62OIbcppHjV4o+LrieWhfT8JC/I/T6W8oCl29vQ0XjLdBaA3s1RcPBO7lFvpX8BVoG4O5jTXRQRDuJ6FDTzEWF1/BCZhgbyAKE9qICYLloQYOFtahVRsWYlZ4KQJHlwHS/IYaZ6sZd9tmu5HQm2xi1UaTbzxYwJk/wBF5g5EEYOBZeEfGZmNdFyFZmZIR4jikbLThlh5kUUVJGmRT7sekkziRWUIACABk3T4qCsedgO4xhgGcY7q5pHJ4klBBTQRJ0CeHcoYHHUh6wgfdn9uJdSdMiebGJ0zUPTcoS286FCkrZxnYoYYKWLkBowhQoBeaOlZAgVhLidrXqg2G
5201iqpQpZ4apwSwRtjqrB3muoF9BboaXKmshlqWqsWiGt2wphJkQbAU5hoCACH5BAUKABsALAcABADOAAsAAAX/oGFw2WZuT5oZROsSQnGaKjRvilI893MItlNOJ5v5gDcFrHhKIWcEYu/xFEqNv6B1N62aclysF7fsZYe5aOx2yL5aAUGSaT1oTYMBwQ5VGCAJgYIJCnx1gIOBhXdwiIl7d0p2iYGQUAQBjoOFSQR/lIQHnZ+Ue6OagqYzSqSJi5eTpTxGcjcSChANEbu8DBAIEsHBChe5vL13G7fFuscRDcnKuM3H0La3EA7Oz8kKEsXazr7Cw9/Gztar5uHHvte47MjktznZ2w0G1+D3BgirAqJmJMAQgMGEgwgn5Ei0gKDBhBMALGRYEOJBb5QcWlQo4cbAihZz3GgIMqFEBSM1/4ZEOWPAgpIIJXYU+PIhRG8ja1qU6VHlzZknJNQ6UanCjQkWCIGSUGEjAwVLjc44+DTqUQtPPS5gejUrTa5TJ3g9sWCr1BNUWZI161StiQUDmLYdGfesibQ3XMq1OPYthrwuA2yU2LBs2cBHIypYQPPlYAKFD5cVvNPtW8eVGbdcQADATsiNO4cFAPkvHpedPzc8kUcPgNGgZ5RNDZG05reoE9s2vSEP79MEGiQGy1qP8LA4ZcdtsJE48ONoLTBtTV0B9LsTnPceoIDBDQvS7W7vfjVY3q3eZ4A339J4eaAmKqU/sV58HvJh2RcnIBsDUw0ABqhBA5aV5V9XUFGiHfVeAiWwoFgJJrIXRH1tEMiDFV4oHoAEGlaWhgIGSGBO2nFomYY3mKjVglidaNYJGJDkWW2xxTfbjCbVaOGNqoX2GloR8ZeTaECS9pthRGJH2g0b3Agbk6hNANtteHD2GJUucfajCQBy5OOTQ25ZgUPvaVVQmbKh9510/qQpwXx3SQdfk8tZJOd5b6JJFplT3ZnmmX3qd5l1eg5q00HrtUkUn0AKaiGjClSAgKLYZcgWXwocGRcCFGCKwSB6ceqphwmYRUFYT/1WKlOdUpipmxW0mlCqHjYkAaeoZlqrqZ4qd+upQKaapn/AmgAegZ8KUtYtFAQQAgAh+QQFCgAbACwHAAQAzgALAAAF/+C2PUcmiCiZGUTrEkKBis8jQEquKwU5HyXIbEPgyX7BYa5wTNmEMwWsSXsqFbEh8DYs9mrgGjdK6GkPY5GOeU6ryz7UFopSQEzygOGhJBjoIgMDBAcBM0V/CYqLCQqFOwobiYyKjn2TlI6GKC2YjJZknouaZAcQlJUHl6eooJwKooobqoewrJSEmyKdt59NhRKFMxLEEA4RyMkMEAjDEhfGycqAG8TQx9IRDRDE3d3R2ctD1RLg0ttKEnbY5wZD3+zJ6M7X2RHi9Oby7u/r9g38UFjTh2xZJBEBMDAboogAgwkQI07IMUORwocSJwCgWDFBAIwZOaJIsOBjRogKJP8wTODw5ESVHVtm3AhzpEeQElOuNDlTZ0ycEUWKWFASqEahGwYUPbnxoAgEdlYSqDBkgoUNClAlIHbSAoOsqCRQnQHxq1axVb06FWFxLIqyaze0Tft1JVqyE+pWXMD1pF6bYl3+HTqAWNW8cRUFzmih0ZAAB2oGKukSAAGGRHWJgLiR6AylBLpuHKKUMlMCngMpDSAa9QIUggZVVvDaJobLeC3XZpvgNgCmtPcuwP3WgmXSq4do0DC6o2/guzcseECtUoO0hmcsGKDgOt7ssBd07wqesAIGZC1YIBa7PQHvb1+SFo+++HrJSQfB33xfav3i5eX3Hnb4CTJgegEq8tH/YQEOcIJzbm2G2EoYRLgBXFpVmFYDcREV4HIcnmUhiGBRouEMJGJGzHIspqgdXxK0yCKHRNXoIX4uorCdTyjkyNtdPWrA4Up82EbAbzMRxxZRR54WXVLDIRmRcag5d2R6ugl3ZXzNhTecchpMhIGVAKAYpgJjjsSklBEd99maZoo535ZvdamjBEpusJyctg3h4X8XqodBMx0tiNeg/oGJaKGABpogS40KSqiaEgBqlQWLUtqoVQnytekEjzo0hHqhRorppOZt2p923M2AAV+oBtpAnnPNoB6HaU6mAAIU+IXmi3j2mtFXuUoHKwXpzVrsjcgGOauKEjQrwq157hitGq2NoWmjh7z6Wmxb0m5w66+2VRAuXN/yFUAIACH5BAUKABsALAcABADOAAsAAAX/4CZuRiaM45MZqBgIRbs9AqTcuFLE7VHLOh7KB5ERdjJaEaU4ClO/lgKWjKKcMiJQ8KgumcieVdQMD8cbBeuAkkC6LYLhOxoQ2PF5Ys9PKPBMen17f0CCg4VSh32JV4t8jSNqEIOEgJKPlkYBlJWRInKdiJdkmQlvKAsLBxdABA4RsbIMBggtEhcQsLKxDBC2TAS6vLENdJLDxMZAubu8vjIbzcQRtMzJz79S08oQEt/guNiyy7fcvMbh4OezdAvGrakLAQwyABsELQkY9BP+//ckyPDD4J9BfAMh1GsBoImMeQUN+lMgUJ9CiRMa5msxoB9Gh/o8GmxYMZXIgxtR/yQ46S/gQAURR0pDwYDfywoyLPip5AdnCwsMFPBU4BPFhKBDi444quCmDKZOfwZ9KEGpCKgcN1jdALSpPqIYsabS+nSqvqplvYqQYAeDPgwKwjaMtiDl0oaqUAyo+3TuWwUAMPpVCfee0cEjVBGQq2ABx7oTWmQk4FglZMGN9fGVDMCuiH2AOVOu/PmyxM630gwM0CCn6q8LjVJ8GXvpa5Uwn95OTC/nNxkda1/dLSK475IjCD6dHbK1ZOa4hXP9DXs5chJ00UpVm5xo2qRpoxptwF2E4/IbJpB/SDz9+q9b1aNfQH08+p4a8uvX8B53fLP+ycAfemjsRUBgp1H20K+BghHgVgt1GXZXZpZ5lt4ECjxYR4ScUWiShEtZqBiIInRGWnERNnjiBglw+JyGnxUmGowsyiiZg189lNtPGACjV2+S9UjbU0JWF6SPvEk3QZEqsZYTk3UAaRSUnznJI5LmESCdBVSyaOWUWLK4I5gDUYVeV1T9l+FZClCAUVA09uSmRHBCKAECFEhW51ht6rnmWBXkaR+NjuHpJ40D3DmnQXt2F+ihZxlqVKOfQRACACH5BAUKABwALAcABADOAAsAAAX/ICdyUCkUo/g8mUG8MCGkKgspeC6j6XEIEBpBUeCNfECaglBcOVfJFK7YQwZHQ6JRZBUqTrSuVEuD3nI45pYjFuWKvjjSkCoRaBUMWxkwBGgJCXspQ36Bh4EEB0oKhoiBgyNLjo8Ki4QElIiWfJqHnISNEI+Ql5J9o6SgkqKkgqYihamPkW6oNBgSfiMMDQkGCBLCwxIQDhHIyQwQCGMKxsnKVyPCF9DREQ3MxMPX0cu4wt7J2uHWx9jlKd3o39MiuefYEcvNkuLt5O8c1ePI2tyELXGQwoGDAQf+iEC2xByDCRAjTlAgIUWCBRgCPJQ4AQBFXAs0coT40WLIjRxL/47AcHLkxIomRXL0CHPERZkpa4q4iVKiyp0tR/7kwHMkTUBBJR5dOCEBAVcKKtCAyOHpowXCpk7goABqBZdcvWploACpBKkpIJI1q5OD2rIWE0R1uTZu1LFwbWL9OlKuWb4c6+o9i3dEgw0RCGDUG9KlRw56gDY2qmCByZBaASi+TACA0TucAaTteCcy0ZuOK3N2vJlx58+LRQyY3Xm0ZsgjZg+oPQLi7dUcNXi0LOJw1pgNtB7XG6CBy+U75SYfPTSQAgZTNUDnQHt67wnbZyvwLgKiMN3oCZB3C76tdewpLFgIP2C88rbi4Y+QT3+8S5USMICZXWj1pkEDeUU3lOYGB3alSoEiMIjgX4WlgNF2EibIwQIXauWXSRg2SAOHIU5IIIMoZkhhWiJaiFVbKo6AQEgQXrTAazO1JhkBrBG3Y2Y6EsUhaGn95hprSN0oWpFE7rhkeaQBchGOEWnwEmc0uKWZj0LeuNV3W4Y2lZHFlQCSRjTIl8uZ+kG5HU/3sRlnTG2ytyadytnD3HrmuRcSn+0h1dycexIK1KCjYaCnjCCVqOFFJTZ5GkUUjESWaUIKU2lgCmAKKQIUjHapXRKE+t2og1VgankNYnohqKJ2CmKplso6GKz7WYCgqxeuyoF8u9IQAgA7', 5202 msg: null, 5203 msgText: '<em>Loading the next set of posts...</em>', 5204 selector: null, 5205 speed: 'fast', 5206 start: undefined 5207 }, 5208 state: { 5209 isDuringAjax: false, 5210 isInvalidPage: false,
5211 isDestroyed: false, 5212 isDone: false, // For when it goes all the way through the archive. 5213 isPaused: false, 5214 isBeyondMaxPage: false, 5215 currPage: 1 5216 }, 5217 debug: false, 5218 behavior: undefined, 5219 binder: $(window), // used to cache the selector 5220 nextSelector: 'div.navigation a:first', 5221 navSelector: 'div.navigation', 5222 contentSelector: null, // rename to pageFragment 5223 extraScrollPx: 150, 5224 itemSelector: 'div.post', 5225 animate: false, 5226 pathParse: undefined, 5227 dataType: 'html', 5228 appendCallback: true, 5229 bufferPx: 40, 5230 errorCallback: function () { }, 5231 infid: 0, //Instance ID 5232 pixelsFromNavToBottom: undefined, 5233 path: undefined, // Either parts of a URL as an array (e.g. ["/page/", "/"] or a function that takes in the page number and returns a URL 5234 prefill: false, // When the document is smaller than the window, load data until the document is larger or links are exhausted 5235 maxPage: undefined // to manually control maximum page (when maxPage is undefined, maximum page limitation is not work) 5236 }; 5237 5238 $.infinitescroll.prototype = { 5239 5240 /* 5241 ---------------------------- 5242 Private methods 5243 ---------------------------- 5244 */ 5245 5246 // Bind or unbind from scroll 5247 _binding: function infscr_binding(binding) { 5248 5249 var instance = this, 5250 opts = instance.options; 5251 5252 opts.v = '2.0b2.120520'; 5253 5254 // if behavior is defined and this function is extended, call that instead of default 5255 if (!!opts.behavior && this['_binding_'+opts.behavior] !== undefined) { 5256 this['_binding_'+opts.behavior].call(this); 5257 return; 5258 } 5259 5260 if (binding !== 'bind' && binding !== 'unbind') { 5261 this._debug('Binding value ' + binding + ' not valid'); 5262 return false; 5263 } 5264 5265 if (binding === 'unbind') { 5266 (this.options.binder).unbind('smartscroll.infscr.' + instance.options.infid); 5267 } else { 5268 (this.options.binder)[binding]('smartscroll.infscr.' + instance.options.infid, function () { 5269 instance.scroll(); 5270 }); 5271 } 5272 5273 this._debug('Binding', binding); 5274 }, 5275 5276 // Fundamental aspects of the plugin are initialized 5277 _create: function infscr_create(options, callback) { 5278 5279 // Add custom options to defaults 5280 var opts = $.extend(true, {}, $.infinitescroll.defaults, options); 5281 this.options = opts; 5282 var $window = $(window); 5283 var instance = this; 5284 5285 // Validate selectors 5286 if (!instance._validate(options)) { 5287 return false; 5288 } 5289 5290 // Validate page fragment path 5291 var path = $(opts.nextSelector).attr('href'); 5292 if (!path) { 5293 this._debug('Navigation selector not found'); 5294 return false; 5295 } 5296 5297 // Set the path to be a relative URL from root. 5298 opts.path = opts.path || this._determinepath(path); 5299 5300 // contentSelector is 'page fragment' option for .load() / .ajax() calls 5301 opts.contentSelector = opts.contentSelector || this.element; 5302 5303 // loading.selector - if we want to place the load message in a specific selector, defaulted to the contentSelector 5304 opts.loading.selector = opts.loading.selector || opts.contentSelector; 5305 5306 // Define loading.msg 5307 opts.loading.msg = opts.loading.msg || $('<div id="infscr-loading"><img alt="Loading..." src="' + opts.loading.img + '" /><div>' + opts.loading.msgText + '</div></div>'); 5308 5309 // Preload loading.img 5310 (new Image()).src = opts.loading.img; 5311 5312 // distance from nav links to bottom 5313 // computed as: height of the document + top offset of container - top offset of nav link 5314 if(opts.pixelsFromNavToBottom === undefined) { 5315 opts.pixelsFromNavToBottom = $(document).height() - $(opts.navSelector).offset().top; 5316 this._debug('pixelsFromNavToBottom: ' + opts.pixelsFromNavToBottom); 5317 } 5318 5319 var self = this; 5320 5321 // determine loading.start actions 5322 opts.loading.start = opts.loading.start || function() { 5323 $(opts.navSelector).hide(); 5324 opts.loading.msg 5325 .appendTo(opts.loading.selector) 5326 .show(opts.loading.speed, $.proxy(function() { 5327 this.beginAjax(opts); 5328 }, self)); 5329 }; 5330 5331 // determine loading.finished actions 5332 opts.loading.finished = opts.loading.finished || function() { 5333 if (!opts.state.isBeyondMaxPage) 5334 opts.loading.msg.fadeOut(opts.loading.speed); 5335 }; 5336 5337 // callback loading 5338 opts.callback = function(instance, data, url) { 5339 if (!!opts.behavior && instance['_callback_'+opts.behavior] !== undefined) { 5340 instance['_callback_'+opts.behavior].call($(opts.contentSelector)[0], data, url); 5341 } 5342 5343 if (callback) { 5344 callback.call($(opts.contentSelector)[0], data, opts, url); 5345 } 5346 5347 if (opts.prefill) { 5348 $window.bind('resize.infinite-scroll', instance._prefill); 5349 } 5350 }; 5351 5352 if (options.debug) { 5353 // Tell IE9 to use its built-in console 5354 if (Function.prototype.bind && (typeof console === 'object' || typeof console === 'function') && typeof console.log === 'object') { 5355 ['log','info','warn','error','assert','dir','clear','profile','profileEnd'] 5356 .forEach(function (method) { 5357 console[method] = this.call(console[method], console); 5358 }, Function.prototype.bind); 5359 } 5360 } 5361 5362 this._setup(); 5363 5364 // Setups the prefill method for use 5365 if (opts.prefill) { 5366 this._prefill(); 5367 } 5368 5369 // Return true to indicate successful creation 5370 return true; 5371 }, 5372 5373 _prefill: function infscr_prefill() { 5374 var instance = this; 5375 var $window = $(window); 5376 5377 function needsPrefill() { 5378 return ( $(instance.options.contentSelector).height() <= $window.height() ); 5379 } 5380 5381 this._prefill = function() { 5382 if (needsPrefill()) { 5383 instance.scroll(); 5384 } 5385 5386 $window.bind('resize.infinite-scroll', function() { 5387 if (needsPrefill()) { 5388 $window.unbind('resize.infinite-scroll'); 5389 instance.scroll(); 5390 } 5391 }); 5392 }; 5393 5394 // Call self after setting up the new function 5395 this._prefill(); 5396 }, 5397 5398 // Console log wrapper 5399 _debug: function infscr_debug() { 5400 if (true !== this.options.debug) { 5401 return; 5402 } 5403 5404 if (typeof console !== 'undefined' && typeof console.log === 'function') { 5405 // Modern browsers 5406 // Single argument, which is a string 5407 if ((Array.prototype.slice.call(arguments)).length === 1 && typeof Array.prototype.slice.call(arguments)[0] === 'string') { 5408 console.log( (Array.prototype.slice.call(arguments)).toString() ); 5409 } else { 5410 console.log( Array.prototype.slice.call(arguments) ); 5411 } 5412 } else if (!Function.prototype.bind && typeof console !== 'undefined' && typeof console.log === 'object') { 5413 // IE8 5414 Function.prototype.call.call(console.log, console, Array.prototype.slice.call(arguments)); 5415 } 5416 }, 5417 5418 // find the number to increment in the path.
5419 _determinepath: function infscr_determinepath(path) { 5420 5421 var opts = this.options; 5422 5423 // if behavior is defined and this function is extended, call that instead of default 5424 if (!!opts.behavior && this['_determinepath_'+opts.behavior] !== undefined) { 5425 return this['_determinepath_'+opts.behavior].call(this,path); 5426 } 5427 5428 if (!!opts.pathParse) { 5429 5430 this._debug('pathParse manual'); 5431 return opts.pathParse(path, this.options.state.currPage+1); 5432 5433 } else if (path.match(/^(.*?)\b2\b(.*?$)/)) { 5434 path = path.match(/^(.*?)\b2\b(.*?$)/).slice(1); 5435 5436 // if there is any 2 in the url at all. 5437 } else if (path.match(/^(.*?)2(.*?$)/)) { 5438 5439 // page= is used in django: 5440 // http://www.infinite-scroll.com/changelog/comment-page-1/#comment-127 5441 if (path.match(/^(.*?page=)2(\/.*|$)/)) { 5442 path = path.match(/^(.*?page=)2(\/.*|$)/).slice(1); 5443 return path; 5444 } 5445 5446 path = path.match(/^(.*?)2(.*?$)/).slice(1); 5447 5448 } else { 5449 5450 // page= is used in drupal too but second page is page=1 not page=2: 5451 // thx Jerod Fritz, vladikoff 5452 if (path.match(/^(.*?page=)1(\/.*|$)/)) { 5453 path = path.match(/^(.*?page=)1(\/.*|$)/).slice(1); 5454 return path; 5455 } else { 5456 this._debug("Sorry, we couldn't parse your Next (Previous Posts) URL. Verify your the css selector points to the correct A tag. If you still get this error: yell, scream, and kindly ask for help at infinite-scroll.com."); 5457 // Get rid of isInvalidPage to allow permalink to state 5458 opts.state.isInvalidPage = true; //prevent it from running on this page. 5459 } 5460 } 5461 this._debug('determinePath', path); 5462 return path; 5463 5464 }, 5465 5466 // Custom error 5467 _error: function infscr_error(xhr) { 5468 5469 var opts = this.options; 5470 5471 // if behavior is defined and this function is extended, call that instead of default 5472 if (!!opts.behavior && this['_error_'+opts.behavior] !== undefined) { 5473 this['_error_'+opts.behavior].call(this,xhr); 5474 return; 5475 } 5476 5477 if (xhr !== 'destroy' && xhr !== 'end') { 5478 xhr = 'unknown'; 5479 } 5480 5481 this._debug('Error', xhr); 5482 5483 if (xhr === 'end' || opts.state.isBeyondMaxPage) { 5484 this._showdonemsg(); 5485 } 5486 5487 opts.state.isDone = true; 5488 opts.state.currPage = 1; // if you need to go back to this instance 5489 opts.state.isPaused = false; 5490 opts.state.isBeyondMaxPage = false; 5491 this._binding('unbind'); 5492 5493 }, 5494 5495 // Load Callback 5496 _loadcallback: function infscr_loadcallback(box, data, url) { 5497 var opts = this.options, 5498 callback = this.options.callback, // GLOBAL OBJECT FOR CALLBACK 5499 result = (opts.state.isDone) ? 'done' : (!opts.appendCallback) ? 'no-append' : 'append', 5500 frag; 5501 5502 // if behavior is defined and this function is extended, call that instead of default 5503 if (!!opts.behavior && this['_loadcallback_'+opts.behavior] !== undefined) { 5504 this['_loadcallback_'+opts.behavior].call(this,box,data); 5505 return; 5506 } 5507 5508 switch (result) { 5509 case 'done': 5510 this._showdonemsg(); 5511 return false; 5512 5513 case 'no-append': 5514 if (opts.dataType === 'html') { 5515 data = '<div>' + data + '</div>'; 5516 data = $(data).find(opts.itemSelector); 5517 } 5518 5519 // if it didn't return anything 5520 if (data.length === 0) { 5521 return this._error('end'); 5522 } 5523 5524 break; 5525 5526 case 'append': 5527 var children = box.children(); 5528 // if it didn't return anything 5529 if (children.length === 0) { 5530 return this._error('end'); 5531 } 5532 5533 // use a documentFragment because it works when content is going into a table or UL 5534 frag = document.createDocumentFragment(); 5535 while (box[0].firstChild) { 5536 frag.appendChild(box[0].firstChild); 5537 } 5538 5539 this._debug('contentSelector', $(opts.contentSelector)[0]); 5540 $(opts.contentSelector)[0].appendChild(frag); 5541 // previously, we would pass in the new DOM element as context for the callback 5542 // however we're now using a documentfragment, which doesn't have parents or children, 5543 // so the context is the contentContainer guy, and we pass in an array 5544 // of the elements collected as the first argument. 5545 5546 data = children.get(); 5547 break; 5548 } 5549 5550 // loadingEnd function 5551 opts.loading.finished.call($(opts.contentSelector)[0],opts); 5552 5553 // smooth scroll to ease in the new content 5554 if (opts.animate) { 5555 var scrollTo = $(window).scrollTop() + $(opts.loading.msg).height() + opts.extraScrollPx + 'px'; 5556 $('html,body').animate({ scrollTop: scrollTo }, 800, function () { opts.state.isDuringAjax = false; }); 5557 } 5558 5559 if (!opts.animate) { 5560 // once the call is done, we can allow it again. 5561 opts.state.isDuringAjax = false;
5562 } 5563 5564 callback(this, data, url); 5565 5566 if (opts.prefill) { 5567 this._prefill(); 5568 } 5569 }, 5570 5571 _nearbottom: function infscr_nearbottom() { 5572 5573 var opts = this.options, 5574 pixelsFromWindowBottomToBottom = 0 + $(document).height() - (opts.binder.scrollTop()) - $(window).height(); 5575 5576 // if behavior is defined and this function is extended, call that instead of default 5577 if (!!opts.behavior && this['_nearbottom_'+opts.behavior] !== undefined) { 5578 return this['_nearbottom_'+opts.behavior].call(this); 5579 } 5580 5581 this._debug('math:', pixelsFromWindowBottomToBottom, opts.pixelsFromNavToBottom); 5582 5583 // if distance remaining in the scroll (including buffer) is less than the orignal nav to bottom.... 5584 return (pixelsFromWindowBottomToBottom - opts.bufferPx < opts.pixelsFromNavToBottom); 5585 5586 }, 5587 5588 // Pause / temporarily disable plugin from firing 5589 _pausing: function infscr_pausing(pause) { 5590 5591 var opts = this.options; 5592 5593 // if behavior is defined and this function is extended, call that instead of default 5594 if (!!opts.behavior && this['_pausing_'+opts.behavior] !== undefined) { 5595 this['_pausing_'+opts.behavior].call(this,pause); 5596 return; 5597 } 5598 5599 // If pause is not 'pause' or 'resume', toggle it's value 5600 if (pause !== 'pause' && pause !== 'resume' && pause !== null) { 5601 this._debug('Invalid argument. Toggling pause value instead'); 5602 } 5603 5604 pause = (pause && (pause === 'pause' || pause === 'resume')) ? pause : 'toggle'; 5605 5606 switch (pause) { 5607 case 'pause': 5608 opts.state.isPaused = true; 5609 break; 5610 5611 case 'resume': 5612 opts.state.isPaused = false; 5613 break; 5614 5615 case 'toggle': 5616 opts.state.isPaused = !opts.state.isPaused; 5617 break; 5618 } 5619 5620 this._debug('Paused', opts.state.isPaused); 5621 return false; 5622 5623 }, 5624 5625 // Behavior is determined 5626 // If the behavior option is undefined, it will set to default and bind to scroll 5627 _setup: function infscr_setup() { 5628 5629 var opts = this.options; 5630 5631 // if behavior is defined and this function is extended, call that instead of default 5632 if (!!opts.behavior && this['_setup_'+opts.behavior] !== undefined) { 5633 this['_setup_'+opts.behavior].call(this); 5634 return; 5635 } 5636 5637 this._binding('bind'); 5638 5639 return false; 5640 5641 }, 5642 5643 // Show done message 5644 _showdonemsg: function infscr_showdonemsg() { 5645 5646 var opts = this.options; 5647 5648 // if behavior is defined and this function is extended, call that instead of default 5649 if (!!opts.behavior && this['_showdonemsg_'+opts.behavior] !== undefined) { 5650 this['_showdonemsg_'+opts.behavior].call(this); 5651 return; 5652 } 5653 5654 opts.loading.msg 5655 .find('img') 5656 .hide() 5657 .parent() 5658 .find('div').html(opts.loading.finishedMsg).animate({ opacity: 1 }, 2000, function () { 5659 $(this).parent().fadeOut(opts.loading.speed); 5660 }); 5661 5662 // user provided callback when done 5663 opts.errorCallback.call($(opts.contentSelector)[0],'done'); 5664 }, 5665 5666 // grab each selector option and see if any fail 5667 _validate: function infscr_validate(opts) { 5668 for (var key in opts) { 5669 if (key.indexOf && key.indexOf('Selector') > -1 && $(opts[key]).length === 0) { 5670 this._debug('Your ' + key + ' found no elements.'); 5671 return false; 5672 } 5673 } 5674 5675 return true; 5676 }, 5677 5678 /* 5679 ---------------------------- 5680 Public methods 5681 ---------------------------- 5682 */ 5683 5684 // Bind to scroll 5685 bind: function infscr_bind() { 5686 this._binding('bind'); 5687 }, 5688 5689 // Destroy current instance of plugin 5690 destroy: function infscr_destroy() { 5691 this.options.state.isDestroyed = true; 5692 this.options.loading.finished(); 5693 return this._error('destroy'); 5694 }, 5695 5696 // Set pause value to false 5697 pause: function infscr_pause() { 5698 this._pausing('pause'); 5699 }, 5700 5701 // Set pause value to false 5702 resume: function infscr_resume() { 5703 this._pausing('resume'); 5704 }, 5705 5706 beginAjax: function infscr_ajax(opts) { 5707 var instance = this, 5708 path = opts.path, 5709 box, desturl, method, condition; 5710 5711 // increment the URL bit. e.g. /page/3/ 5712 opts.state.currPage++; 5713 5714 // Manually control maximum page 5715 if ( opts.maxPage !== undefined && opts.state.currPage > opts.maxPage ){ 5716 opts.state.isBeyondMaxPage = true; 5717 this.destroy(); 5718 return; 5719 } 5720 5721 // if we're dealing with a table we can't use DIVs 5722 box = $(opts.contentSelector).is('table, tbody') ? $('<tbody/>') : $('<div/>'); 5723 5724 desturl = (typeof path === 'function') ? path(opts.state.currPage) : path.join(opts.state.currPage); 5725 instance._debug('heading into ajax', desturl); 5726 5727 method = (opts.dataType === 'html' || opts.dataType === 'json' ) ? opts.dataType : 'html+callback'; 5728 if (opts.appendCallback && opts.dataType === 'html') { 5729 method += '+callback'; 5730 } 5731 5732 switch (method) { 5733 case 'html+callback': 5734 instance._debug('Using HTML via .load() method'); 5735 box.load(desturl + ' ' + opts.itemSelector, undefined, function infscr_ajax_callback(responseText) { 5736 instance._loadcallback(box, responseText, desturl); 5737 }); 5738 5739 break; 5740 5741 case 'html': 5742 instance._debug('Using ' + (method.toUpperCase()) + ' via $.ajax() method'); 5743 $.ajax({ 5744 // params 5745 url: desturl, 5746 dataType: opts.dataType, 5747 complete: function infscr_ajax_callback(jqXHR, textStatus) { 5748 condition = (typeof (jqXHR.isResolved) !== 'undefined') ? (jqXHR.isResolved()) : (textStatus === 'success' || textStatus === 'notmodified'); 5749 if (condition) { 5750 instance._loadcallback(box, jqXHR.responseText, desturl); 5751 } else { 5752 instance._error('end'); 5753 } 5754 } 5755 }); 5756 5757 break; 5758 case 'json': 5759 instance._debug('Using ' + (method.toUpperCase()) + ' via $.ajax() method'); 5760 $.ajax({ 5761 dataType: 'json', 5762 type: 'GET', 5763 url: desturl, 5764 success: function (data, textStatus, jqXHR) { 5765 condition = (typeof (jqXHR.isResolved) !== 'undefined') ? (jqXHR.isResolved()) : (textStatus === 'success' || textStatus === 'notmodified'); 5766 if (opts.appendCallback) { 5767 // if appendCallback is true, you must defined template in options. 5768 // note that data passed into _loadcallback is already an html (after processed in opts.template(data)). 5769 if (opts.template !== undefined) { 5770 var theData = opts.template(data); 5771 box.append(theData); 5772 if (condition) { 5773 instance._loadcallback(box, theData); 5774 } else { 5775 instance._error('end'); 5776 } 5777 } else { 5778 instance._debug('template must be defined.'); 5779 instance._error('end'); 5780 } 5781 } else { 5782 // if appendCallback is false, we will pass in the JSON object. you should handle it yourself in your callback. 5783 if (condition) { 5784 instance._loadcallback(box, data, desturl); 5785 } else { 5786 instance._error('end'); 5787 } 5788 } 5789 }, 5790 error: function() { 5791 instance._debug('JSON ajax request failed.'); 5792 instance._error('end'); 5793 } 5794 }); 5795 5796 break; 5797 } 5798 }, 5799 5800 // Retrieve next set of content items 5801 retrieve: function infscr_retrieve(pageNum) { 5802 pageNum = pageNum || null; 5803 5804 var instance = this, 5805 opts = instance.options; 5806 5807 // if behavior is defined and this function is extended, call that instead of default 5808 if (!!opts.behavior && this['retrieve_'+opts.behavior] !== undefined) { 5809 this['retrieve_'+opts.behavior].call(this,pageNum); 5810 return; 5811 } 5812 5813 // for manual triggers, if destroyed, get out of here 5814 if (opts.state.isDestroyed) { 5815 this._debug('Instance is destroyed'); 5816 return false;
5817 } 5818 5819 // we dont want to fire the ajax multiple times 5820 opts.state.isDuringAjax = true; 5821 5822 opts.loading.start.call($(opts.contentSelector)[0],opts); 5823 }, 5824 5825 // Check to see next page is needed 5826 scroll: function infscr_scroll() { 5827 5828 var opts = this.options, 5829 state = opts.state; 5830 5831 // if behavior is defined and this function is extended, call that instead of default 5832 if (!!opts.behavior && this['scroll_'+opts.behavior] !== undefined) { 5833 this['scroll_'+opts.behavior].call(this); 5834 return; 5835 } 5836 5837 if (state.isDuringAjax || state.isInvalidPage || state.isDone || state.isDestroyed || state.isPaused) { 5838 return; 5839 } 5840 5841 if (!this._nearbottom()) { 5842 return; 5843 } 5844 5845 this.retrieve(); 5846 5847 }, 5848 5849 // Toggle pause value 5850 toggle: function infscr_toggle() { 5851 this._pausing(); 5852 }, 5853 5854 // Unbind from scroll 5855 unbind: function infscr_unbind() { 5856 this._binding('unbind'); 5857 }, 5858 5859 // update options 5860 update: function infscr_options(key) { 5861 if ($.isPlainObject(key)) { 5862 this.options = $.extend(true,this.options,key); 5863 } 5864 } 5865 }; 5866 5867 5868 /* 5869 ---------------------------- 5870 Infinite Scroll function 5871 ---------------------------- 5872 5873 Borrowed logic from the following... 5874 5875 jQuery UI 5876 - https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.widget.js 5877 5878 jCarousel 5879 - https://github.com/jsor/jcarousel/blob/master/lib/jquery.jcarousel.js 5880 5881 Masonry 5882 - https://github.com/desandro/masonry/blob/master/jquery.masonry.js 5883 5884*/ 5885 5886 $.fn.infinitescroll = function infscr_init(options, callback) { 5887 5888 5889 var thisCall = typeof options; 5890 5891 switch (thisCall) { 5892 5893 // method 5894 case 'string': 5895 var args = Array.prototype.slice.call(arguments, 1); 5896 5897 this.each(function () { 5898 var instance = $.data(this, 'infinitescroll'); 5899 5900 if (!instance) { 5901 // not setup yet 5902 // return $.error('Method ' + options + ' cannot be called until Infinite Scroll is setup'); 5903 return false; 5904 } 5905 5906 if (!$.isFunction(instance[options]) || options.charAt(0) === '_') { 5907 // return $.error('No such method ' + options + ' for Infinite Scroll'); 5908 return false; 5909 } 5910 5911 // no errors! 5912 instance[options].apply(instance, args); 5913 }); 5914 5915 break; 5916 5917 // creation 5918 case 'object': 5919 5920 this.each(function () { 5921 5922 var instance = $.data(this, 'infinitescroll'); 5923 5924 if (instance) { 5925 5926 // update options of current instance 5927 instance.update(options); 5928 5929 } else { 5930 5931 // initialize new instance 5932 instance = new $.infinitescroll(options, callback, this); 5933 5934 // don't attach if instantiation failed 5935 if (!instance.failed) { 5936 $.data(this, 'infinitescroll', instance); 5937 } 5938 5939 } 5940 5941 }); 5942 5943 break; 5944 5945 } 5946 5947 return this; 5948 }; 5949 5950 5951 5952 /* 5953 * smartscroll: debounced scroll event for jQuery * 5954 * https://github.com/lukeshumard/smartscroll 5955 * Based on smartresize by @louis_remi: https://github.com/lrbabe/jquery.smartresize.js * 5956 * Copyright 2011 Louis-Remi & Luke Shumard * Licensed under the MIT license. * 5957 */ 5958 5959 var event = $.event, 5960 scrollTimeout; 5961 5962 event.special.smartscroll = { 5963 setup: function () { 5964 $(this).bind('scroll', event.special.smartscroll.handler); 5965 }, 5966 teardown: function () { 5967 $(this).unbind('scroll', event.special.smartscroll.handler); 5968 }, 5969 handler: function (event, execAsap) { 5970 // Save the context 5971 var context = this, 5972 args = arguments; 5973 5974 // set correct event type 5975 event.type = 'smartscroll'; 5976 5977 if (scrollTimeout) { clearTimeout(scrollTimeout); } 5978 scrollTimeout = setTimeout(function () { 5979 $(context).trigger('smartscroll', args); 5980 }, execAsap === 'execAsap' ? 0 : 100); 5981 } 5982 }; 5983 5984 $.fn.smartscroll = function (fn) {
5985 return fn ? this.bind('smartscroll', fn) : this.trigger('smartscroll', ['execAsap']); 5986 }; 5987 5988})); 5989 5990/*! 5991Waypoints - 4.0.1 5992Copyright © 2011-2016 Caleb Troughton 5993Licensed under the MIT license. 5994https://github.com/imakewebthings/waypoints/blob/master/licenses.txt 5995*/ 5996(function() { 5997 'use strict' 5998 5999 var keyCounter = 0 6000 var allWaypoints = {} 6001 6002 /* http://imakewebthings.com/waypoints/api/waypoint */ 6003 function Waypoint(options) { 6004 if (!options) { 6005 throw new Error('No options passed to Waypoint constructor') 6006 } 6007 if (!options.element) { 6008 throw new Error('No element option passed to Waypoint constructor') 6009 } 6010 if (!options.handler) { 6011 throw new Error('No handler option passed to Waypoint constructor') 6012 } 6013 6014 this.key = 'waypoint-' + keyCounter 6015 this.options = Waypoint.Adapter.extend({}, Waypoint.defaults, options) 6016 this.element = this.options.element 6017 this.adapter = new Waypoint.Adapter(this.element) 6018 this.callback = options.handler 6019 this.axis = this.options.horizontal ? 'horizontal' : 'vertical' 6020 this.enabled = this.options.enabled 6021 this.triggerPoint = null 6022 this.group = Waypoint.Group.findOrCreate({ 6023 name: this.options.group, 6024 axis: this.axis 6025 }) 6026 this.context = Waypoint.Context.findOrCreateByElement(this.options.context) 6027 6028 if (Waypoint.offsetAliases[this.options.offset]) { 6029 this.options.offset = Waypoint.offsetAliases[this.options.offset] 6030 } 6031 this.group.add(this) 6032 this.context.add(this) 6033 allWaypoints[this.key] = this 6034 keyCounter += 1 6035 } 6036 6037 /* Private */ 6038 Waypoint.prototype.queueTrigger = function(direction) { 6039 this.group.queueTrigger(this, direction) 6040 } 6041 6042 /* Private */ 6043 Waypoint.prototype.trigger = function(args) { 6044 if (!this.enabled) { 6045 return 6046 } 6047 if (this.callback) { 6048 this.callback.apply(this, args) 6049 } 6050 } 6051 6052 /* Public */ 6053 /* http://imakewebthings.com/waypoints/api/destroy */ 6054 Waypoint.prototype.destroy = function() { 6055 this.context.remove(this) 6056 this.group.remove(this) 6057 delete allWaypoints[this.key] 6058 } 6059 6060 /* Public */ 6061 /* http://imakewebthings.com/waypoints/api/disable */ 6062 Waypoint.prototype.disable = function() { 6063 this.enabled = false 6064 return this 6065 } 6066 6067 /* Public */ 6068 /* http://imakewebthings.com/waypoints/api/enable */ 6069 Waypoint.prototype.enable = function() { 6070 this.context.refresh() 6071 this.enabled = true 6072 return this 6073 } 6074 6075 /* Public */ 6076 /* http://imakewebthings.com/waypoints/api/next */ 6077 Waypoint.prototype.next = function() { 6078 return this.group.next(this) 6079 } 6080 6081 /* Public */ 6082 /* http://imakewebthings.com/waypoints/api/previous */ 6083 Waypoint.prototype.previous = function() { 6084 return this.group.previous(this) 6085 } 6086 6087 /* Private */ 6088 Waypoint.invokeAll = function(method) { 6089 var allWaypointsArray = []
6090 for (var waypointKey in allWaypoints) { 6091 allWaypointsArray.push(allWaypoints[waypointKey]) 6092 } 6093 for (var i = 0, end = allWaypointsArray.length; i < end; i++) { 6094 allWaypointsArray[i][method]() 6095 } 6096 } 6097 6098 /* Public */ 6099 /* http://imakewebthings.com/waypoints/api/destroy-all */ 6100 Waypoint.destroyAll = function() { 6101 Waypoint.invokeAll('destroy') 6102 } 6103 6104 /* Public */ 6105 /* http://imakewebthings.com/waypoints/api/disable-all */ 6106 Waypoint.disableAll = function() { 6107 Waypoint.invokeAll('disable') 6108 } 6109 6110 /* Public */ 6111 /* http://imakewebthings.com/waypoints/api/enable-all */ 6112 Waypoint.enableAll = function() { 6113 Waypoint.Context.refreshAll() 6114 for (var waypointKey in allWaypoints) { 6115 allWaypoints[waypointKey].enabled = true 6116 } 6117 return this 6118 } 6119 6120 /* Public */ 6121 /* http://imakewebthings.com/waypoints/api/refresh-all */ 6122 Waypoint.refreshAll = function() { 6123 Waypoint.Context.refreshAll() 6124 } 6125 6126 /* Public */ 6127 /* http://imakewebthings.com/waypoints/api/viewport-height */ 6128 Waypoint.viewportHeight = function() { 6129 return window.innerHeight || document.documentElement.clientHeight 6130 } 6131 6132 /* Public */ 6133 /* http://imakewebthings.com/waypoints/api/viewport-width */ 6134 Waypoint.viewportWidth = function() { 6135 return document.documentElement.clientWidth 6136 } 6137 6138 Waypoint.adapters = [] 6139 6140 Waypoint.defaults = { 6141 context: window, 6142 continuous: true, 6143 enabled: true, 6144 group: 'default', 6145 horizontal: false, 6146 offset: 0 6147 } 6148 6149 Waypoint.offsetAliases = { 6150 'bottom-in-view': function() { 6151 return this.context.innerHeight() - this.adapter.outerHeight() 6152 }, 6153 'right-in-view': function() { 6154 return this.context.innerWidth() - this.adapter.outerWidth() 6155 } 6156 } 6157 6158 window.Waypoint = Waypoint 6159}()) 6160;(function() { 6161 'use strict' 6162 6163 function requestAnimationFrameShim(callback) { 6164 window.setTimeout(callback, 1000 / 60) 6165 } 6166 6167 var keyCounter = 0 6168 var contexts = {} 6169 var Waypoint = window.Waypoint 6170 var oldWindowLoad = window.onload 6171 6172 /* http://imakewebthings.com/waypoints/api/context */ 6173 function Context(element) { 6174 this.element = element 6175 this.Adapter = Waypoint.Adapter 6176 this.adapter = new this.Adapter(element) 6177 this.key = 'waypoint-context-' + keyCounter 6178 this.didScroll = false 6179 this.didResize = false 6180 this.oldScroll = { 6181 x: this.adapter.scrollLeft(), 6182 y: this.adapter.scrollTop() 6183 } 6184 this.waypoints = { 6185 vertical: {}, 6186 horizontal: {} 6187 } 6188 6189 element.waypointContextKey = this.key 6190 contexts[element.waypointContextKey] = this 6191 keyCounter += 1 6192 if (!Waypoint.windowContext) { 6193 Waypoint.windowContext = true 6194 Waypoint.windowContext = new Context(window) 6195 } 6196 6197 this.createThrottledScrollHandler() 6198 this.createThrottledResizeHandler() 6199 } 6200 6201 /* Private */ 6202 Context.prototype.add = function(waypoint) { 6203 var axis = waypoint.options.horizontal ? 'horizontal' : 'vertical' 6204 this.waypoints[axis][waypoint.key] = waypoint 6205 this.refresh() 6206 } 6207 6208 /* Private */ 6209 Context.prototype.checkEmpty = function() { 6210 var horizontalEmpty = this.Adapter.isEmptyObject(this.waypoints.horizontal) 6211 var verticalEmpty = this.Adapter.isEmptyObject(this.waypoints.vertical) 6212 var isWindow = this.element == this.element.window 6213 if (horizontalEmpty && verticalEmpty && !isWindow) { 6214 this.adapter.off('.waypoints') 6215 delete contexts[this.key] 6216 } 6217 } 6218 6219 /* Private */ 6220 Context.prototype.createThrottledResizeHandler = function() { 6221 var self = this 6222 6223 function resizeHandler() { 6224 self.handleResize() 6225 self.didResize = false 6226 } 6227 6228 this.adapter.on('resize.waypoints', function() { 6229 if (!self.didResize) { 6230 self.didResize = true 6231 Waypoint.requestAnimationFrame(resizeHandler) 6232 } 6233 }) 6234 } 6235 6236 /* Private */ 6237 Context.prototype.createThrottledScrollHandler = function() { 6238 var self = this 6239 function scrollHandler() { 6240 self.handleScroll() 6241 self.didScroll = false 6242 } 6243 6244 this.adapter.on('scroll.waypoints', function() { 6245 if (!self.didScroll || Waypoint.isTouch) { 6246 self.didScroll = true 6247 Waypoint.requestAnimationFrame(scrollHandler) 6248 } 6249 }) 6250 } 6251 6252 /* Private */ 6253 Context.prototype.handleResize = function() { 6254 Waypoint.Context.refreshAll() 6255 } 6256 6257 /* Private */ 6258 Context.prototype.handleScroll = function() { 6259 var triggeredGroups = {} 6260 var axes = { 6261 horizontal: { 6262 newScroll: this.adapter.scrollLeft(), 6263 oldScroll: this.oldScroll.x, 6264 forward: 'right', 6265 backward: 'left' 6266 }, 6267 vertical: { 6268 newScroll: this.adapter.scrollTop(), 6269 oldScroll: this.oldScroll.y, 6270 forward: 'down', 6271 backward: 'up' 6272 } 6273 } 6274 6275 for (var axisKey in axes) { 6276 var axis = axes[axisKey] 6277 var isForward = axis.newScroll > axis.oldScroll 6278 var direction = isForward ? axis.forward : axis.backward 6279
6280 for (var waypointKey in this.waypoints[axisKey]) { 6281 var waypoint = this.waypoints[axisKey][waypointKey] 6282 if (waypoint.triggerPoint === null) { 6283 continue 6284 } 6285 var wasBeforeTriggerPoint = axis.oldScroll < waypoint.triggerPoint 6286 var nowAfterTriggerPoint = axis.newScroll >= waypoint.triggerPoint 6287 var crossedForward = wasBeforeTriggerPoint && nowAfterTriggerPoint 6288 var crossedBackward = !wasBeforeTriggerPoint && !nowAfterTriggerPoint 6289 if (crossedForward || crossedBackward) { 6290 waypoint.queueTrigger(direction) 6291 triggeredGroups[waypoint.group.id] = waypoint.group 6292 } 6293 } 6294 } 6295 6296 for (var groupKey in triggeredGroups) { 6297 triggeredGroups[groupKey].flushTriggers() 6298 } 6299 6300 this.oldScroll = { 6301 x: axes.horizontal.newScroll, 6302 y: axes.vertical.newScroll 6303 } 6304 } 6305 6306 /* Private */ 6307 Context.prototype.innerHeight = function() { 6308 /*eslint-disable eqeqeq */ 6309 if (this.element == this.element.window) { 6310 return Waypoint.viewportHeight() 6311 } 6312 /*eslint-enable eqeqeq */ 6313 return this.adapter.innerHeight() 6314 } 6315 6316 /* Private */ 6317 Context.prototype.remove = function(waypoint) { 6318 delete this.waypoints[waypoint.axis][waypoint.key] 6319 this.checkEmpty() 6320 } 6321 6322 /* Private */ 6323 Context.prototype.innerWidth = function() { 6324 /*eslint-disable eqeqeq */ 6325 if (this.element == this.element.window) { 6326 return Waypoint.viewportWidth() 6327 } 6328 /*eslint-enable eqeqeq */ 6329 return this.adapter.innerWidth() 6330 } 6331 6332 /* Public */ 6333 /* http://imakewebthings.com/waypoints/api/context-destroy */ 6334 Context.prototype.destroy = function() { 6335 var allWaypoints = [] 6336 for (var axis in this.waypoints) {
6337 for (var waypointKey in this.waypoints[axis]) { 6338 allWaypoints.push(this.waypoints[axis][waypointKey]) 6339 } 6340 } 6341 for (var i = 0, end = allWaypoints.length; i < end; i++) { 6342 allWaypoints[i].destroy() 6343 } 6344 } 6345 6346 /* Public */ 6347 /* http://imakewebthings.com/waypoints/api/context-refresh */ 6348 Context.prototype.refresh = function() { 6349 /*eslint-disable eqeqeq */ 6350 var isWindow = this.element == this.element.window 6351 /*eslint-enable eqeqeq */ 6352 var contextOffset = isWindow ? undefined : this.adapter.offset() 6353 var triggeredGroups = {} 6354 var axes 6355 6356 this.handleScroll() 6357 axes = { 6358 horizontal: { 6359 contextOffset: isWindow ? 0 : contextOffset.left, 6360 contextScroll: isWindow ? 0 : this.oldScroll.x, 6361 contextDimension: this.innerWidth(), 6362 oldScroll: this.oldScroll.x, 6363 forward: 'right', 6364 backward: 'left', 6365 offsetProp: 'left' 6366 }, 6367 vertical: { 6368 contextOffset: isWindow ? 0 : contextOffset.top, 6369 contextScroll: isWindow ? 0 : this.oldScroll.y, 6370 contextDimension: this.innerHeight(), 6371 oldScroll: this.oldScroll.y, 6372 forward: 'down', 6373 backward: 'up', 6374 offsetProp: 'top' 6375 } 6376 } 6377 6378 for (var axisKey in axes) { 6379 var axis = axes[axisKey]
6380 for (var waypointKey in this.waypoints[axisKey]) { 6381 var waypoint = this.waypoints[axisKey][waypointKey] 6382 var adjustment = waypoint.options.offset 6383 var oldTriggerPoint = waypoint.triggerPoint 6384 var elementOffset = 0 6385 var freshWaypoint = oldTriggerPoint == null 6386 var contextModifier, wasBeforeScroll, nowAfterScroll 6387 var triggeredBackward, triggeredForward 6388 6389 if (waypoint.element !== waypoint.element.window) { 6390 elementOffset = waypoint.adapter.offset()[axis.offsetProp] 6391 } 6392 6393 if (typeof adjustment === 'function') { 6394 adjustment = adjustment.apply(waypoint) 6395 } 6396 else if (typeof adjustment === 'string') { 6397 adjustment = parseFloat(adjustment) 6398 if (waypoint.options.offset.indexOf('%') > - 1) { 6399 adjustment = Math.ceil(axis.contextDimension * adjustment / 100) 6400 } 6401 } 6402 6403 contextModifier = axis.contextScroll - axis.contextOffset 6404 waypoint.triggerPoint = Math.floor(elementOffset + contextModifier - adjustment) 6405 wasBeforeScroll = oldTriggerPoint < axis.oldScroll 6406 nowAfterScroll = waypoint.triggerPoint >= axis.oldScroll 6407 triggeredBackward = wasBeforeScroll && nowAfterScroll 6408 triggeredForward = !wasBeforeScroll && !nowAfterScroll 6409 6410 if (!freshWaypoint && triggeredBackward) { 6411 waypoint.queueTrigger(axis.backward) 6412 triggeredGroups[waypoint.group.id] = waypoint.group 6413 } 6414 else if (!freshWaypoint && triggeredForward) { 6415 waypoint.queueTrigger(axis.forward) 6416 triggeredGroups[waypoint.group.id] = waypoint.group 6417 } 6418 else if (freshWaypoint && axis.oldScroll >= waypoint.triggerPoint) { 6419 waypoint.queueTrigger(axis.forward) 6420 triggeredGroups[waypoint.group.id] = waypoint.group 6421 } 6422 } 6423 } 6424 6425 Waypoint.requestAnimationFrame(function() { 6426 for (var groupKey in triggeredGroups) { 6427 triggeredGroups[groupKey].flushTriggers() 6428 } 6429 }) 6430 6431 return this 6432 } 6433 6434 /* Private */ 6435 Context.findOrCreateByElement = function(element) { 6436 return Context.findByElement(element) || new Context(element) 6437 } 6438 6439 /* Private */ 6440 Context.refreshAll = function() { 6441 for (var contextId in contexts) { 6442 contexts[contextId].refresh() 6443 } 6444 } 6445 6446 /* Public */ 6447 /* http://imakewebthings.com/waypoints/api/context-find-by-element */ 6448 Context.findByElement = function(element) { 6449 return contexts[element.waypointContextKey] 6450 } 6451 6452 window.onload = function() { 6453 if (oldWindowLoad) { 6454 oldWindowLoad() 6455 } 6456 Context.refreshAll() 6457 } 6458 6459 6460 Waypoint.requestAnimationFrame = function(callback) { 6461 var requestFn = window.requestAnimationFrame || 6462 window.mozRequestAnimationFrame || 6463 window.webkitRequestAnimationFrame || 6464 requestAnimationFrameShim 6465 requestFn.call(window, callback) 6466 } 6467 Waypoint.Context = Context 6468}()) 6469;(function() { 6470 'use strict' 6471 6472 function byTriggerPoint(a, b) { 6473 return a.triggerPoint - b.triggerPoint 6474 } 6475 6476 function byReverseTriggerPoint(a, b) { 6477 return b.triggerPoint - a.triggerPoint 6478 } 6479 6480 var groups = { 6481 vertical: {}, 6482 horizontal: {} 6483 } 6484 var Waypoint = window.Waypoint 6485 6486 /* http://imakewebthings.com/waypoints/api/group */ 6487 function Group(options) { 6488 this.name = options.name 6489 this.axis = options.axis 6490 this.id = this.name + '-' + this.axis 6491 this.waypoints = [] 6492 this.clearTriggerQueues() 6493 groups[this.axis][this.name] = this 6494 } 6495 6496 /* Private */ 6497 Group.prototype.add = function(waypoint) { 6498 this.waypoints.push(waypoint) 6499 } 6500 6501 /* Private */ 6502 Group.prototype.clearTriggerQueues = function() { 6503 this.triggerQueues = { 6504 up: [], 6505 down: [], 6506 left: [], 6507 right: [] 6508 } 6509 } 6510 6511 /* Private */ 6512 Group.prototype.flushTriggers = function() { 6513 for (var direction in this.triggerQueues) { 6514 var waypoints = this.triggerQueues[direction] 6515 var reverse = direction === 'up' || direction === 'left' 6516 waypoints.sort(reverse ? byReverseTriggerPoint : byTriggerPoint) 6517 for (var i = 0, end = waypoints.length; i < end; i += 1) { 6518 var waypoint = waypoints[i] 6519 if (waypoint.options.continuous || i === waypoints.length - 1) { 6520 waypoint.trigger([direction]) 6521 } 6522 } 6523 } 6524 this.clearTriggerQueues() 6525 } 6526 6527 /* Private */ 6528 Group.prototype.next = function(waypoint) { 6529 this.waypoints.sort(byTriggerPoint) 6530 var index = Waypoint.Adapter.inArray(waypoint, this.waypoints) 6531 var isLast = index === this.waypoints.length - 1 6532 return isLast ? null : this.waypoints[index + 1] 6533 } 6534 6535 /* Private */ 6536 Group.prototype.previous = function(waypoint) { 6537 this.waypoints.sort(byTriggerPoint) 6538 var index = Waypoint.Adapter.inArray(waypoint, this.waypoints) 6539 return index ? this.waypoints[index - 1] : null 6540 } 6541 6542 /* Private */ 6543 Group.prototype.queueTrigger = function(waypoint, direction) { 6544 this.triggerQueues[direction].push(waypoint) 6545 } 6546 6547 /* Private */ 6548 Group.prototype.remove = function(waypoint) { 6549 var index = Waypoint.Adapter.inArray(waypoint, this.waypoints) 6550 if (index > -1) { 6551 this.waypoints.splice(index, 1) 6552 } 6553 } 6554 6555 /* Public */ 6556 /* http://imakewebthings.com/waypoints/api/first */ 6557 Group.prototype.first = function() { 6558 return this.waypoints[0] 6559 } 6560 6561 /* Public */ 6562 /* http://imakewebthings.com/waypoints/api/last */ 6563 Group.prototype.last = function() { 6564 return this.waypoints[this.waypoints.length - 1] 6565 } 6566 6567 /* Private */ 6568 Group.findOrCreate = function(options) { 6569 return groups[options.axis][options.name] || new Group(options) 6570 } 6571 6572 Waypoint.Group = Group 6573}()) 6574;(function() { 6575 'use strict' 6576 6577 var $ = window.jQuery 6578 var Waypoint = window.Waypoint 6579 6580 function JQueryAdapter(element) { 6581 this.$element = $(element) 6582 } 6583 6584 $.each([
6585 'innerHeight', 6586 'innerWidth', 6587 'off', 6588 'offset', 6589 'on', 6590 'outerHeight', 6591 'outerWidth', 6592 'scrollLeft', 6593 'scrollTop' 6594 ], function(i, method) { 6595 JQueryAdapter.prototype[method] = function() { 6596 var args = Array.prototype.slice.call(arguments) 6597 return this.$element[method].apply(this.$element, args) 6598 } 6599 }) 6600 6601 $.each([ 6602 'extend', 6603 'inArray', 6604 'isEmptyObject' 6605 ], function(i, method) { 6606 JQueryAdapter[method] = $[method] 6607 }) 6608 6609 Waypoint.adapters.push({ 6610 name: 'jquery', 6611 Adapter: JQueryAdapter 6612 }) 6613 Waypoint.Adapter = JQueryAdapter 6614}()) 6615;(function() { 6616 'use strict' 6617 6618 var Waypoint = window.Waypoint 6619 6620 function createExtension(framework) { 6621 return function() { 6622 var waypoints = [] 6623 var overrides = arguments[0] 6624 6625 if (framework.isFunction(arguments[0])) { 6626 overrides = framework.extend({}, arguments[1]) 6627 overrides.handler = arguments[0] 6628 } 6629 6630 this.each(function() { 6631 var options = framework.extend({}, overrides, { 6632 element: this 6633 }) 6634 if (typeof options.context === 'string') { 6635 options.context = framework(this).closest(options.context)[0] 6636 } 6637 waypoints.push(new Waypoint(options)) 6638 }) 6639 6640 return waypoints 6641 } 6642 } 6643 6644 if (window.jQuery) { 6645 window.jQuery.fn.waypoint = createExtension(window.jQuery) 6646 } 6647 if (window.Zepto) { 6648 window.Zepto.fn.waypoint = createExtension(window.Zepto) 6649 } 6650}()) 6651; 6652/*! 6653Waypoints Inview Shortcut - 4.0.1 6654Copyright © 2011-2016 Caleb Troughton 6655Licensed under the MIT license. 6656https://github.com/imakewebthings/waypoints/blob/master/licenses.txt 6657*/ 6658(function() { 6659 'use strict' 6660 6661 function noop() {} 6662 6663 var Waypoint = window.Waypoint 6664 6665 /* http://imakewebthings.com/waypoints/shortcuts/inview */ 6666 function Inview(options) { 6667 this.options = Waypoint.Adapter.extend({}, Inview.defaults, options) 6668 this.axis = this.options.horizontal ? 'horizontal' : 'vertical' 6669 this.waypoints = [] 6670 this.element = this.options.element 6671 this.createWaypoints() 6672 } 6673 6674 /* Private */ 6675 Inview.prototype.createWaypoints = function() { 6676 var configs = { 6677 vertical: [{ 6678 down: 'enter', 6679 up: 'exited', 6680 offset: '100%' 6681 }, { 6682 down: 'entered', 6683 up: 'exit', 6684 offset: 'bottom-in-view' 6685 }, { 6686 down: 'exit', 6687 up: 'entered', 6688 offset: 0 6689 }, { 6690 down: 'exited', 6691 up: 'enter', 6692 offset: function() { 6693 return -this.adapter.outerHeight() 6694 } 6695 }], 6696 horizontal: [{ 6697 right: 'enter', 6698 left: 'exited', 6699 offset: '100%' 6700 }, { 6701 right: 'entered', 6702 left: 'exit', 6703 offset: 'right-in-view' 6704 }, { 6705 right: 'exit', 6706 left: 'entered', 6707 offset: 0 6708 }, { 6709 right: 'exited', 6710 left: 'enter', 6711 offset: function() { 6712 return -this.adapter.outerWidth() 6713 } 6714 }] 6715 } 6716 6717 for (var i = 0, end = configs[this.axis].length; i < end; i++) { 6718 var config = configs[this.axis][i] 6719 this.createWaypoint(config) 6720 } 6721 } 6722 6723 /* Private */ 6724 Inview.prototype.createWaypoint = function(config) { 6725 var self = this 6726 this.waypoints.push(new Waypoint({ 6727 context: this.options.context, 6728 element: this.options.element, 6729 enabled: this.options.enabled, 6730 handler: (function(config) { 6731 return function(direction) { 6732 self.options[config[direction]].call(self, direction) 6733 } 6734 }(config)), 6735 offset: config.offset, 6736 horizontal: this.options.horizontal 6737 })) 6738 } 6739 6740 /* Public */ 6741 Inview.prototype.destroy = function() { 6742 for (var i = 0, end = this.waypoints.length; i < end; i++) { 6743 this.waypoints[i].destroy() 6744 } 6745 this.waypoints = [] 6746 } 6747 6748 Inview.prototype.disable = function() { 6749 for (var i = 0, end = this.waypoints.length; i < end; i++) { 6750 this.waypoints[i].disable() 6751 } 6752 } 6753 6754 Inview.prototype.enable = function() { 6755 for (var i = 0, end = this.waypoints.length; i < end; i++) { 6756 this.waypoints[i].enable() 6757 } 6758 } 6759 6760 Inview.defaults = { 6761 context: window, 6762 enabled: true, 6763 enter: noop, 6764 entered: noop,
6765 exit: noop, 6766 exited: noop 6767 } 6768 6769 Waypoint.Inview = Inview 6770}()) 6771; 6772 6773/* 6774 * SmartMenus jQuery v0.9.6 6775 * http://www.smartmenus.org/ 6776 * 6777 * Copyright 2014 Vasil Dinkov, Vadikom Web Ltd. 6778 * http://vadikom.com/ 6779 * 6780 * Released under the MIT license: 6781 * http://www.opensource.org/licenses/MIT 6782 */ 6783 6784(function($) { 6785 6786 var menuTrees = [], 6787 IE = !!window.createPopup, // we need to detect it, unfortunately 6788 IElt9 = IE && !document.defaultView, 6789 IElt8 = IE && !document.querySelector, 6790 IE6 = IE && typeof document.documentElement.currentStyle.minWidth == 'undefined', 6791 mouse = false, // optimize for touch by default - we will detect for mouse input 6792 mouseDetectionEnabled = false; 6793 6794 // Handle detection for mouse input (i.e. desktop browsers, tablets with a mouse, etc.) 6795 function initMouseDetection(disable) { 6796 if (!mouseDetectionEnabled && !disable) { 6797 // if we get two consecutive mousemoves within 2 pixels from each other and within 300ms, we assume a real mouse/cursor is present 6798 // in practice, this seems like impossible to trick unintentianally with a real mouse and a pretty safe detection on touch devices (even with older browsers that do not support touch events) 6799 var firstTime = true, 6800 lastMove = null; 6801 $(document).bind({ 6802 'mousemove.smartmenus_mouse': function(e) { 6803 var thisMove = { x: e.pageX, y: e.pageY, timeStamp: new Date().getTime() }; 6804 if (lastMove) { 6805 var deltaX = Math.abs(lastMove.x - thisMove.x), 6806 deltaY = Math.abs(lastMove.y - thisMove.y); 6807 if ((deltaX > 0 || deltaY > 0) && deltaX <= 2 && deltaY <= 2 && thisMove.timeStamp - lastMove.timeStamp <= 300) { 6808 mouse = true; 6809 // if this is the first check after page load, check if we are not over some item by chance and call the mouseenter handler if yes 6810 if (firstTime) { 6811 var $a = $(e.target).closest('a'); 6812 if ($a.is('a')) { 6813 $.each(menuTrees, function() { 6814 if ($.contains(this.$root[0], $a[0])) { 6815 this.itemEnter({ currentTarget: $a[0] }); 6816 return false; 6817 } 6818 }); 6819 } 6820 firstTime = false; 6821 } 6822 } 6823 } 6824 lastMove = thisMove; 6825 }, 6826 'touchstart.smartmenus_mouse pointerover.smartmenus_mouse MSPointerOver.smartmenus_mouse': function(e) { 6827 if (!/^(4|mouse)$/.test(e.originalEvent.pointerType)) { 6828 mouse = false; 6829 } 6830 } 6831 }); 6832 mouseDetectionEnabled = true; 6833 } else if (mouseDetectionEnabled && disable) { 6834 $(document).unbind('.smartmenus_mouse'); 6835 mouseDetectionEnabled = false; 6836 } 6837 }; 6838 6839 $.SmartMenus = function(elm, options) { 6840 this.$root = $(elm); 6841 this.opts = options; 6842 this.rootId = ''; // internal 6843 this.$subArrow = null; 6844 this.subMenus = []; // all sub menus in the tree (UL elms) in no particular order (only real - e.g. UL's in mega sub menus won't be counted) 6845 this.activatedItems = []; // stores last activated A's for each level 6846 this.visibleSubMenus = []; // stores visible sub menus UL's 6847 this.showTimeout = 0; 6848 this.hideTimeout = 0; 6849 this.scrollTimeout = 0; 6850 this.clickActivated = false; 6851 this.zIndexInc = 0; 6852 this.$firstLink = null; // we'll use these for some tests 6853 this.$firstSub = null; // at runtime so we'll cache them 6854 this.disabled = false; 6855 this.$disableOverlay = null; 6856 this.init(); 6857 }; 6858 6859 $.extend($.SmartMenus, { 6860 hideAll: function() { 6861 $.each(menuTrees, function() { 6862 this.menuHideAll(); 6863 }); 6864 }, 6865 destroy: function() { 6866 while (menuTrees.length) { 6867 menuTrees[0].destroy(); 6868 } 6869 initMouseDetection(true); 6870 }, 6871 prototype: { 6872 init: function(refresh) { 6873 var self = this; 6874 6875 if (!refresh) { 6876 menuTrees.push(this); 6877 6878 this.rootId = (new Date().getTime() + Math.random() + '').replace(/\D/g, ''); 6879 6880 if (this.$root.hasClass('sm-rtl')) { 6881 this.opts.rightToLeftSubMenus = true; 6882 } 6883 6884 // init root (main menu) 6885 this.$root 6886 .data('smartmenus', this) 6887 .attr('data-smartmenus-id', this.rootId) 6888 .dataSM('level', 1) 6889 .bind({ 6890 'mouseover.smartmenus focusin.smartmenus': $.proxy(this.rootOver, this),
6891 'mouseout.smartmenus focusout.smartmenus': $.proxy(this.rootOut, this) 6892 }) 6893 .delegate('a', { 6894 'mouseenter.smartmenus': $.proxy(this.itemEnter, this), 6895 'mouseleave.smartmenus': $.proxy(this.itemLeave, this), 6896 'mousedown.smartmenus': $.proxy(this.itemDown, this), 6897 'focus.smartmenus': $.proxy(this.itemFocus, this), 6898 'blur.smartmenus': $.proxy(this.itemBlur, this), 6899 'click.smartmenus': $.proxy(this.itemClick, this), 6900 'touchend.smartmenus': $.proxy(this.itemTouchEnd, this) 6901 }); 6902 6903 var eNamespace = '.smartmenus' + this.rootId; 6904 // hide menus on tap or click outside the root UL 6905 if (this.opts.hideOnClick) { 6906 $(document).bind('touchstart' + eNamespace, $.proxy(this.docTouchStart, this)) 6907 .bind('touchmove' + eNamespace, $.proxy(this.docTouchMove, this)) 6908 .bind('touchend' + eNamespace, $.proxy(this.docTouchEnd, this)) 6909 // for Opera Mobile < 11.5, webOS browser, etc. we'll check click too 6910 .bind('click' + eNamespace, $.proxy(this.docClick, this)); 6911 } 6912 // hide sub menus on resize 6913 $(window).bind('resize' + eNamespace + ' orientationchange' + eNamespace, $.proxy(this.winResize, this)); 6914 $(window).bind('scroll' + eNamespace + ' orientationchange' + eNamespace, $.proxy(this.winResize, this)); 6915 6916 if (this.opts.subIndicators) { 6917 this.$subArrow = $('<span/>').addClass('sub-arrow'); 6918 if (this.opts.subIndicatorsText) { 6919 this.$subArrow.html(this.opts.subIndicatorsText); 6920 } 6921 } 6922 6923 // make sure mouse detection is enabled 6924 initMouseDetection(); 6925 } 6926 6927 // init sub menus 6928 this.$firstSub = this.$root.find('ul').each(function() { self.menuInit($(this)); }).eq(0); 6929 6930 this.$firstLink = this.$root.find('a').eq(0); 6931 6932 // find current item 6933 if (this.opts.markCurrentItem) { 6934 var reDefaultDoc = /(index|default)\.[^#\?\/]*/i, 6935 reHash = /#.*/, 6936 locHref = window.location.href.replace(reDefaultDoc, ''), 6937 locHrefNoHash = locHref.replace(reHash, ''); 6938 this.$root.find('a').each(function() { 6939 var href = this.href.replace(reDefaultDoc, ''), 6940 $this = $(this); 6941 if (href == locHref || href == locHrefNoHash) { 6942 $this.addClass('current'); 6943 if (self.opts.markCurrentTree) { 6944 $this.parents('li').each(function() { 6945 var $this = $(this); 6946 if ($this.dataSM('sub')) { 6947 $this.children('a').addClass('current'); 6948 } 6949 }); 6950 } 6951 } 6952 }); 6953 } 6954 }, 6955 destroy: function() { 6956 this.menuHideAll(); 6957 this.$root 6958 .removeData('smartmenus') 6959 .removeAttr('data-smartmenus-id') 6960 .removeDataSM('level') 6961 .unbind('.smartmenus') 6962 .undelegate('.smartmenus'); 6963 var eNamespace = '.smartmenus' + this.rootId; 6964 $(document).unbind(eNamespace); 6965 $(window).unbind(eNamespace); 6966 if (this.opts.subIndicators) { 6967 this.$subArrow = null; 6968 } 6969 var self = this; 6970 $.each(this.subMenus, function() { 6971 if (this.hasClass('mega-menu')) { 6972 this.find('ul').removeDataSM('in-mega'); 6973 } 6974 if (this.dataSM('shown-before')) { 6975 if (IElt8) { 6976 this.children().css({ styleFloat: '', width: '' }); 6977 } 6978 if (self.opts.subMenusMinWidth || self.opts.subMenusMaxWidth) { 6979 if (!IE6) { 6980 this.css({ width: '', minWidth: '', maxWidth: '' }).removeClass('sm-nowrap'); 6981 } else { 6982 this.css({ width: '', overflowX: '', overflowY: '' }).children().children('a').css('white-space', ''); 6983 } 6984 } 6985 if (this.dataSM('scroll-arrows')) { 6986 this.dataSM('scroll-arrows').remove(); 6987 } 6988 this.css({ zIndex: '', top: '', left: '', marginLeft: '', marginTop: '', display: '' }); 6989 } 6990 if (self.opts.subIndicators) { 6991 this.dataSM('parent-a').removeClass('has-submenu').children('span.sub-arrow').remove(); 6992 } 6993 this.removeDataSM('shown-before') 6994 .removeDataSM('ie-shim') 6995 .removeDataSM('scroll-arrows') 6996 .removeDataSM('parent-a') 6997 .removeDataSM('level') 6998 .removeDataSM('beforefirstshowfired') 6999 .parent().removeDataSM('sub'); 7000 }); 7001 if (this.opts.markCurrentItem) { 7002 this.$root.find('a.current').removeClass('current'); 7003 } 7004 this.$root = null; 7005 this.$firstLink = null; 7006 this.$firstSub = null; 7007 if (this.$disableOverlay) { 7008 this.$disableOverlay.remove(); 7009 this.$disableOverlay = null; 7010 } 7011 menuTrees.splice($.inArray(this, menuTrees), 1); 7012 }, 7013 disable: function(noOverlay) { 7014 if (!this.disabled) { 7015 this.menuHideAll(); 7016 // display overlay over the menu to prevent interaction 7017 if (!noOverlay && !this.opts.isPopup && this.$root.is(':visible')) { 7018 var pos = this.$root.offset(); 7019 this.$disableOverlay = $('<div class="sm-jquery-disable-overlay"/>').css({ 7020 position: 'absolute', 7021 top: pos.top, 7022 left: pos.left, 7023 width: this.$root.outerWidth(), 7024 height: this.$root.outerHeight(),
7025 zIndex: this.getStartZIndex() + 1, 7026 opacity: 0 7027 }).appendTo(document.body); 7028 } 7029 this.disabled = true; 7030 } 7031 }, 7032 docClick: function(e) { 7033 // hide on any click outside the menu or on a menu link 7034 if (this.visibleSubMenus.length && !$.contains(this.$root[0], e.target) || $(e.target).is('a')) { 7035 this.menuHideAll($(e.target)); 7036 } 7037 }, 7038 docTouchEnd: function(e) { 7039 if (!this.lastTouch) { 7040 return; 7041 } 7042 if (this.visibleSubMenus.length && (this.lastTouch.x2 === undefined || this.lastTouch.x1 == this.lastTouch.x2) && (this.lastTouch.y2 === undefined || this.lastTouch.y1 == this.lastTouch.y2) && (!this.lastTouch.target || !$.contains(this.$root[0], this.lastTouch.target))) { 7043 if (this.hideTimeout) { 7044 clearTimeout(this.hideTimeout); 7045 this.hideTimeout = 0; 7046 } 7047 // hide with a delay to prevent triggering accidental unwanted click on some page element 7048 var self = this; 7049 this.hideTimeout = setTimeout(function() { self.menuHideAll($(e.target)); }, 350); 7050 } 7051 this.lastTouch = null; 7052 }, 7053 docTouchMove: function(e) { 7054 if (!this.lastTouch) { 7055 return; 7056 } 7057 var touchPoint = e.originalEvent.touches[0]; 7058 this.lastTouch.x2 = touchPoint.pageX; 7059 this.lastTouch.y2 = touchPoint.pageY; 7060 }, 7061 docTouchStart: function(e) { 7062 var touchPoint = e.originalEvent.touches[0]; 7063 this.lastTouch = { x1: touchPoint.pageX, y1: touchPoint.pageY, target: touchPoint.target }; 7064 }, 7065 enable: function() { 7066 if (this.disabled) { 7067 if (this.$disableOverlay) { 7068 this.$disableOverlay.remove(); 7069 this.$disableOverlay = null; 7070 } 7071 this.disabled = false; 7072 } 7073 }, 7074 getHeight: function($elm) { 7075 return this.getOffset($elm, true); 7076 }, 7077 // returns precise width/height float values in IE9+, FF4+, recent WebKit 7078 // http://vadikom.com/dailies/offsetwidth-offsetheight-useless-in-ie9-firefox4/ 7079 getOffset: function($elm, height) { 7080 var old; 7081 if ($elm.css('display') == 'none') { 7082 old = { position: $elm[0].style.position, visibility: $elm[0].style.visibility }; 7083 $elm.css({ position: 'absolute', visibility: 'hidden' }).show(); 7084 } 7085 var defaultView = $elm[0].ownerDocument.defaultView, 7086 compStyle = defaultView && defaultView.getComputedStyle && defaultView.getComputedStyle($elm[0], null), 7087 val = compStyle && parseFloat(compStyle[height ? 'height' : 'width']); 7088 if (val) { 7089 val += parseFloat(compStyle[height ? 'paddingTop' : 'paddingLeft']) 7090 + parseFloat(compStyle[height ? 'paddingBottom' : 'paddingRight']) 7091 + parseInt(compStyle[height ? 'borderTopWidth' : 'borderLeftWidth']) 7092 + parseInt(compStyle[height ? 'borderBottomWidth' : 'borderRightWidth']); 7093 } else { 7094 val = height ? $elm[0].offsetHeight : $elm[0].offsetWidth; 7095 } 7096 if (old) { 7097 $elm.hide().css(old); 7098 } 7099 return val; 7100 }, 7101 getWidth: function($elm) { 7102 return this.getOffset($elm); 7103 }, 7104 getStartZIndex: function() { 7105 var zIndex = parseInt(this.$root.css('z-index')); 7106 return !isNaN(zIndex) ? zIndex : 1; 7107 }, 7108 handleEvents: function() { 7109 return !this.disabled && this.isCSSOn(); 7110 }, 7111 handleItemEvents: function($a) { 7112 return this.handleEvents() && !this.isLinkInMegaMenu($a); 7113 }, 7114 isCollapsible: function() { 7115 return this.$firstSub.css('position') == 'static'; 7116 }, 7117 isCSSOn: function() { 7118 return this.$firstLink.css('display') == 'block' || this.$firstLink.css('display') == 'inline'; 7119 }, 7120 isFixed: function() { 7121 return this.$root.css('position') == 'fixed'; 7122 }, 7123 isLinkInMegaMenu: function($a) { 7124 return !$a.parent().parent().dataSM('level'); 7125 }, 7126 isTouchMode: function() { 7127 return !mouse || this.isCollapsible(); 7128 }, 7129 itemActivate: function($a) { 7130 var $li = $a.parent(), 7131 $ul = $li.parent(), 7132 level = $ul.dataSM('level'); 7133 // if for some reason the parent item is not activated (e.g. this is an API call to activate the item), activate all parent items first 7134 if (level > 1 && (!this.activatedItems[level - 2] || this.activatedItems[level - 2][0] != $ul.dataSM('parent-a')[0])) { 7135 var self = this; 7136 $($ul.parentsUntil('[data-smartmenus-id]', 'ul').get().reverse()).add($ul).each(function() { 7137 self.itemActivate($(this).dataSM('parent-a')); 7138 }); 7139 } 7140 // hide any visible deeper level sub menus 7141 if (this.visibleSubMenus.length > level) { 7142 for (var i = this.visibleSubMenus.length - 1, l = !this.activatedItems[level - 1] || this.activatedItems[level - 1][0] != $a[0] ? level - 1 : level; i > l; i--) { 7143 this.menuHide(this.visibleSubMenus[i]); 7144 } 7145 } 7146 // save new active item and sub menu for this level 7147 this.activatedItems[level - 1] = $a; 7148 this.visibleSubMenus[level - 1] = $ul; 7149 if (this.$root.triggerHandler('activate.smapi', $a[0]) === false) { 7150 return; 7151 } 7152 // show the sub menu if this item has one 7153 var $sub = $li.dataSM('sub'); 7154 if ($sub && (this.isTouchMode() || (!this.opts.showOnClick || this.clickActivated))) { 7155 this.menuShow($sub); 7156 } 7157 }, 7158 itemBlur: function(e) { 7159 var $a = $(e.currentTarget); 7160 if (!this.handleItemEvents($a)) { 7161 return; 7162 } 7163 this.$root.triggerHandler('blur.smapi', $a[0]); 7164 }, 7165 itemClick: function(e) { 7166 var $a = $(e.currentTarget); 7167 7168 if (!this.handleItemEvents($a)) { 7169 return; 7170 } 7171 $a.removeDataSM('mousedown'); 7172 if (this.$root.triggerHandler('click.smapi', $a[0]) === false) { 7173 return false;
7174 } 7175 var $sub = $a.parent().dataSM('sub'); 7176 if (this.isTouchMode()) { 7177 // undo fix: prevent the address bar on iPhone from sliding down when expanding a sub menu 7178 if ($a.dataSM('href')) { 7179 $a.attr('href', $a.dataSM('href')).removeDataSM('href'); 7180 } 7181 // if the sub is not visible 7182 if ($sub && (!$sub.dataSM('shown-before') || !$sub.is(':visible'))) { 7183 // try to activate the item and show the sub 7184 this.itemActivate($a); 7185 // if "itemActivate" showed the sub, prevent the click so that the link is not loaded 7186 // if it couldn't show it, then the sub menus are disabled with an !important declaration (e.g. via mobile styles) so let the link get loaded 7187 if ($sub.is(':visible')) { 7188 return false; 7189 } 7190 } 7191 } else if (this.opts.showOnClick && $a.parent().parent().dataSM('level') == 1 && $sub) { 7192 this.clickActivated = true; 7193 this.menuShow($sub); 7194 return false; 7195 } 7196 if ($a.hasClass('disabled')) { 7197 return false; 7198 } 7199 if (this.$root.triggerHandler('select.smapi', $a[0]) === false) { 7200 return false; 7201 } 7202 }, 7203 itemDown: function(e) { 7204 var $a = $(e.currentTarget); 7205 if (!this.handleItemEvents($a)) { 7206 return; 7207 } 7208 $a.dataSM('mousedown', true); 7209 }, 7210 itemEnter: function(e) { 7211 var $a = $(e.currentTarget); 7212 if (!this.handleItemEvents($a)) { 7213 return; 7214 } 7215 if (!this.isTouchMode()) { 7216 if (this.showTimeout) { 7217 clearTimeout(this.showTimeout); 7218 this.showTimeout = 0; 7219 } 7220 var self = this; 7221 this.showTimeout = setTimeout(function() { self.itemActivate($a); }, this.opts.showOnClick && $a.parent().parent().dataSM('level') == 1 ? 1 : this.opts.showTimeout); 7222 } 7223 this.$root.triggerHandler('mouseenter.smapi', $a[0]); 7224 }, 7225 itemFocus: function(e) { 7226 var $a = $(e.currentTarget); 7227 if (!this.handleItemEvents($a)) { 7228 return; 7229 } 7230 // fix (the mousedown check): in some browsers a tap/click produces consecutive focus + click events so we don't need to activate the item on focus 7231 if ((!this.isTouchMode() || !$a.dataSM('mousedown')) && (!this.activatedItems.length || this.activatedItems[this.activatedItems.length - 1][0] != $a[0])) { 7232 this.itemActivate($a); 7233 } 7234 this.$root.triggerHandler('focus.smapi', $a[0]); 7235 }, 7236 itemLeave: function(e) { 7237 var $a = $(e.currentTarget); 7238 if (!this.handleItemEvents($a)) { 7239 return; 7240 } 7241 if (!this.isTouchMode()) { 7242 if ($a[0].blur) { 7243 $a[0].blur(); 7244 } 7245 if (this.showTimeout) { 7246 clearTimeout(this.showTimeout); 7247 this.showTimeout = 0; 7248 } 7249 } 7250 $a.removeDataSM('mousedown'); 7251 this.$root.triggerHandler('mouseleave.smapi', $a[0]); 7252 }, 7253 itemTouchEnd: function(e) { 7254 var $a = $(e.currentTarget); 7255 if (!this.handleItemEvents($a)) { 7256 return; 7257 } 7258 // prevent the address bar on iPhone from sliding down when expanding a sub menu 7259 var $sub = $a.parent().dataSM('sub'); 7260 if ($a.attr('href').charAt(0) !== '#' && $sub && (!$sub.dataSM('shown-before') || !$sub.is(':visible'))) { 7261 $a.dataSM('href', $a.attr('href')); 7262 $a.attr('href', '#'); 7263 } 7264 }, 7265 menuFixLayout: function($ul) { 7266 // fixes a menu that is being shown for the first time 7267 if (!$ul.dataSM('shown-before')) { 7268 $ul.hide().dataSM('shown-before', true); 7269 // fix the layout of the items in IE<8 7270 if (IElt8) { 7271 $ul.children().css({ styleFloat: 'left', width: '100%' }); 7272 } 7273 } 7274 }, 7275 menuHide: function($sub) { 7276 if (this.$root.triggerHandler('beforehide.smapi', $sub[0]) === false) { 7277 return; 7278 } 7279 $sub.stop(true, true); 7280 if ($sub.is(':visible')) { 7281 var complete = function() { 7282 // unset z-index 7283 if (IElt9) { 7284 $sub.parent().css('z-index', ''); 7285 } else { 7286 $sub.css('z-index', ''); 7287 } 7288 }; 7289 // if sub is collapsible (mobile view) 7290 if (this.isCollapsible()) { 7291 if (this.opts.collapsibleHideFunction) { 7292 this.opts.collapsibleHideFunction.call(this, $sub, complete); 7293 } else { 7294 $sub.hide(this.opts.collapsibleHideDuration, complete); 7295 } 7296 } else { 7297 if (this.opts.hideFunction) { 7298 this.opts.hideFunction.call(this, $sub, complete); 7299 } else { 7300 $sub.hide(this.opts.hideDuration, complete); 7301 } 7302 } 7303 // remove IE iframe shim 7304 if ($sub.dataSM('ie-shim')) { 7305 $sub.dataSM('ie-shim').remove(); 7306 } 7307 // deactivate scrolling if it is activated for this sub 7308 if ($sub.dataSM('scroll')) { 7309 $sub.unbind('.smartmenus_scroll').removeDataSM('scroll').dataSM('scroll-arrows').hide(); 7310 } 7311 // unhighlight parent item 7312 $sub.dataSM('parent-a').removeClass('highlighted'); 7313 var level = $sub.dataSM('level'); 7314 this.activatedItems.splice(level - 1, 1); 7315 this.visibleSubMenus.splice(level - 1, 1); 7316 this.$root.triggerHandler('hide.smapi', $sub[0]); 7317 } 7318 }, 7319 menuHideAll: function($item) { 7320 if ($item != undefined && $item.parent().hasClass('menu-item') && !$item.parent().hasClass('menu-item-has-children')) return; 7321 if ( $('body').hasClass('vmenu') ) return; 7322 if (this.showTimeout) { 7323 clearTimeout(this.showTimeout); 7324 this.showTimeout = 0; 7325 } 7326 // hide all subs 7327 for (var i = this.visibleSubMenus.length - 1; i > 0; i--) { 7328 this.menuHide(this.visibleSubMenus[i]); 7329 } 7330 // hide root if it's popup 7331 if (this.opts.isPopup) { 7332 this.$root.stop(true, true); 7333 if (this.$root.is(':visible')) { 7334 if (this.opts.hideFunction) { 7335 this.opts.hideFunction.call(this, this.$root); 7336 } else { 7337 this.$root.hide(this.opts.hideDuration); 7338 } 7339 // remove IE iframe shim 7340 if (this.$root.dataSM('ie-shim')) { 7341 this.$root.dataSM('ie-shim').remove(); 7342 } 7343 } 7344 } 7345 this.activatedItems = []; 7346 this.visibleSubMenus = []; 7347 this.clickActivated = false;
7348 // reset z-index increment 7349 this.zIndexInc = 0; 7350 }, 7351 menuIframeShim: function($ul) { 7352 // create iframe shim for the menu 7353 if (IE && this.opts.overlapControlsInIE && !$ul.dataSM('ie-shim')) { 7354 $ul.dataSM('ie-shim', $('<iframe/>').attr({ src: 'javascript:0', tabindex: -9 }) 7355 .css({ position: 'absolute', top: 'auto', left: '0', opacity: 0, border: '0' }) 7356 ); 7357 } 7358 }, 7359 menuInit: function($ul) { 7360 if (!$ul.dataSM('in-mega')) { 7361 this.subMenus.push($ul); 7362 // mark UL's in mega drop downs (if any) so we can neglect them 7363 if ($ul.hasClass('mega-menu')) { 7364 $ul.find('ul').dataSM('in-mega', true); 7365 } 7366 // get level (much faster than, for example, using parentsUntil) 7367 var level = 2, 7368 par = $ul[0]; 7369 while ((par = par.parentNode.parentNode) != this.$root[0]) { 7370 level++; 7371 } 7372 // cache stuff 7373 $ul.dataSM('parent-a', $ul.prevAll('a').eq(-1)) 7374 .dataSM('level', level) 7375 .parent().dataSM('sub', $ul); 7376 // add sub indicator to parent item 7377 if (this.opts.subIndicators) { 7378 $ul.dataSM('parent-a').addClass('has-submenu')[this.opts.subIndicatorsPos](this.$subArrow.clone()); 7379 } 7380 } 7381 }, 7382 menuPosition: function($sub) { 7383 var fixIE = $('html.ie').length; 7384 // if (fixIE) { 7385 // var $rowParent = $($sub).closest('.main-menu-container'); 7386 // $rowParent.height($rowParent.height()); 7387 // } 7388 var $a = $sub.dataSM('parent-a'), 7389 $li = $sub.parent(), 7390 $ul = $sub.parent().parent(), 7391 $container = $ul.closest('.row-menu-inner').length ? $ul.closest('.row-menu-inner') : $ul.closest('.uncol'), 7392 level = $sub.dataSM('level'), 7393 subW = this.getWidth($sub), 7394 subH = this.getHeight($sub), 7395 itemOffset = $a.offset(), 7396 itemX = itemOffset.left, 7397 itemY = itemOffset.top, 7398 itemW = this.getWidth($a), 7399 itemH = this.getHeight($a), 7400 $win = $(window), 7401 winX = $win.scrollLeft(), 7402 winY = $win.scrollTop(), 7403 winW = $win.width(), 7404 winH = $win.height(), 7405 containerW = $container.width(), 7406 containerOffsetX = containerW + ((winW - containerW) / 2), 7407 horizontalParent = $ul.hasClass('sm') && !$ul.hasClass('sm-vertical'), 7408 subOffsetX = level == 2 ? this.opts.mainMenuSubOffsetX : this.opts.subMenusSubOffsetX, 7409 subOffsetY = level == 2 ? this.opts.mainMenuSubOffsetY : this.opts.subMenusSubOffsetY, 7410 x, y, leftPos; 7411 if (horizontalParent) { 7412 x = this.opts.rightToLeftSubMenus ? itemW - subW - subOffsetX : subOffsetX; 7413 y = this.opts.bottomToTopSubMenus ? -subH - subOffsetY : itemH + subOffsetY; 7414 } else { 7415 x = this.opts.rightToLeftSubMenus ? subOffsetX - subW : itemW - subOffsetX; 7416 y = this.opts.bottomToTopSubMenus ? itemH - subOffsetY - subH : subOffsetY; 7417 } 7418 if (this.opts.keepInViewport && !this.isCollapsible()) { 7419 if (this.isFixed()) { 7420 itemX -= winX; 7421 itemY -= winY; 7422 winX = winY = 0; 7423 } 7424 var absX = itemX + x, 7425 absY = itemY + y; 7426 if (this.opts.rightToLeftSubMenus && absX < winX) { 7427 x = horizontalParent ? winX - absX + x : itemW - subOffsetX; 7428 } else if (!this.opts.rightToLeftSubMenus && absX + subW > winX + containerOffsetX ) { 7429 x = horizontalParent ? winX + containerOffsetX - subW - absX + x : subOffsetX - subW; 7430 } 7431 if (!horizontalParent) { 7432 if (subH < winH && absY + subH > winY + winH) { 7433 y += winY + winH - subH - absY; 7434 } else if (subH >= winH || absY < winY) { 7435 y += winY - absY; 7436 } 7437 } 7438 // do we need scrolling? 7439 // 0.49 added for the sake of IE9/FF4+ where we might be dealing with float numbers for "subH" 7440 if (mouse && (horizontalParent && (absY + subH > winY + winH + 0.49 || absY < winY) || !horizontalParent && subH > winH + 0.49)) { 7441 var self = this; 7442 if (!$sub.dataSM('scroll-arrows')) { 7443 $sub.dataSM('scroll-arrows', $([$('<span class="scroll-up"><span class="scroll-up-arrow"></span></span>')[0], $('<span class="scroll-down"><span class="scroll-down-arrow"></span></span>')[0]]) 7444 .bind({ 7445 mouseenter: function() { self.menuScroll($sub, $(this).hasClass('scroll-up')); }, 7446 mouseleave: function(e) { 7447 self.menuScrollStop($sub); 7448 self.menuScrollOut($sub, e); 7449 }, 7450 'mousewheel DOMMouseScroll': function(e) { e.preventDefault(); } 7451 }) 7452 .insertAfter($sub) 7453 ); 7454 } 7455 // bind events to show/hide arrows on hover and save scrolling data for this sub 7456 var vportY = winY - (itemY + itemH); 7457 $sub.dataSM('scroll', { 7458 vportY: vportY, 7459 subH: subH, 7460 winH: winH, 7461 step: 1 7462 }) 7463 .bind({ 7464 'mouseover.smartmenus_scroll': function(e) { self.menuScrollOver($sub, e); }, 7465 'mouseout.smartmenus_scroll': function(e) { self.menuScrollOut($sub, e); }, 7466 'mousewheel.smartmenus_scroll DOMMouseScroll.smartmenus_scroll': function(e) { self.menuScrollMousewheel($sub, e); } 7467 }) 7468 .dataSM('scroll-arrows').css({ top: 'auto', left: '0', marginLeft: x + (parseInt($sub.css('border-left-width')) || 0), width: this.getWidth($sub) - (parseInt($sub.css('border-left-width')) || 0) - (parseInt($sub.css('border-right-width')) || 0), zIndex: this.get
7468StartZIndex() + this.zIndexInc }) 7469 .eq(0).css('margin-top', vportY).end() 7470 .eq(1).css('margin-top', vportY + winH - this.getHeight($sub.dataSM('scroll-arrows').eq(1))).end() 7471 .eq(horizontalParent && this.opts.bottomToTopSubMenus ? 0 : 1).show(); 7472 } 7473 } 7474 // if ($sub.hasClass('mega-menu-inner')) { 7475 // if ($('.menu-wrapper .megamenu-diff').length > 0) { 7476 // leftPos = parseFloat($('.menu-wrapper .megamenu-diff').outerWidth()); 7477 // leftPos = -leftPos; 7478 // } else leftPos = parseFloat($('.menu-wrapper .main-menu-container').css('paddingLeft')); 7479 7480 // if ($('body.header-full-width').length > 0) { 7481 // $sub.css({ width: $('.box-container').width()}); 7482 // leftPos = (leftPos - parseFloat($('.menu-wrapper .row-menu-inner').css('paddingLeft'))); 7483 // } else $sub.css({ width: containerW}); 7484 // leftPos = leftPos + 'px'; 7485 7486 // } else { 7487 // leftPos = $li.position().left + 'px'; 7488 // } 7489 var rightPos = 'auto'; 7490 if ( $sub.parents('.isotope-filters').length ) { 7491 if ( $sub.parents('.text-right').eq(0).length ) { 7492 leftPos = '0px'; 7493 rightPos = 'auto'; 7494 } else { 7495 leftPos = 'auto'; 7496 rightPos = '0px'; 7497 } 7498 x = 0; 7499 } else { 7500 if ($sub.hasClass('mega-menu-inner')) { 7501 $sub.css({ width: containerW}); 7502 if ( $('body.hmenu-center-double').length ) { 7503 leftPos = '0px'; 7504 } else { 7505 if ( $('body.hmenu-center-split').length > 0 && !$sub.closest('.navbar-cta').length && ! $('body.hormenu-position-right').length ) { 7506 leftPos = - ($sub.closest('.menu-primary-inner')[0].offsetLeft) + 'px'; 7507 } else { 7508 if ( $sub.closest('.navbar-cta').length && !$('body.hmenu').length && !$('body.hmenu-center').length ) { 7509 leftPos = - ( parseFloat($sub.closest('.navbar-cta').offset().left) - parseFloat($sub.closest('.row-menu-inner').find('.logo-container').offset().left) ) + 'px'; 7510 } else if ($sub.closest('.row-menu-inner').find('.logo-container').length > 0 && !$('body.hmenu-center-split').length) { 7511 leftPos = - (parseFloat($sub.closest('.row-menu-inner').find('.logo-container').css('paddingRight')) + ($sub.closest('.row-menu-inner').find('.logo-container').width())) + 'px'; 7512 } else { 7513 leftPos = '0px'; 7514 } 7515 } 7516 } 7517 } else { 7518 leftPos = (level > 2 ? $li.position().left - parseFloat($li.closest('ul').css('paddingLeft')) : $li.position().left ) + 'px'; 7519 x = (level > 2 && x >= 0) ? x + (parseFloat($li.closest('ul').css('paddingLeft')) * 2) + 1 : x - 1; 7520 } 7521 } 7522 7523 7524 $sub.css({ top: (level > 2) ? $a[0].offsetTop : (fixIE ? itemH : '100%'), left: leftPos, right: rightPos, marginLeft: x, marginTop: (level > 2) ? 0 : y - itemH + ($sub.closest('.menu-mini').length ? 0 : 1) }); 7525 // IE iframe shim 7526 this.menuIframeShim($sub); 7527 if ($sub.dataSM('ie-shim')) { 7528 $sub.dataSM('ie-shim').css({ zIndex: $sub.css('z-index'), width: subW, height: subH, marginLeft: x, marginTop: y - itemH + ($sub.closest('.menu-mini').length ? 0 : 1) }); 7529 } 7530 }, 7531 menuScroll: function($sub, up, wheel) { 7532 var y = parseFloat($sub.css('margin-top')), 7533 scroll = $sub.dataSM('scroll'), 7534 end = scroll.vportY + (up ? 0 : scroll.winH - scroll.subH), 7535 step = wheel || !this.opts.scrollAccelerate ? this.opts.scrollStep : Math.floor($sub.dataSM('scroll').step); 7536 $sub.add($sub.dataSM('ie-shim')).css('margin-top', Math.abs(end - y) > step ? y + (up ? step : -step) : end); 7537 y = parseFloat($sub.css('margin-top')); 7538 // show opposite arrow if appropriate 7539 if (up && y + scroll.subH > scroll.vportY + scroll.winH || !up && y < scroll.vportY) { 7540 $sub.dataSM('scroll-arrows').eq(up ? 1 : 0).show(); 7541 } 7542 // accelerate when not using mousewheel to scroll 7543 if (!wheel && this.opts.scrollAccelerate && $sub.dataSM('scroll').step < this.opts.scrollStep) { 7544 $sub.dataSM('scroll').step += 0.5; 7545 } 7546 // "y" and "end" might be float numbers in IE9/FF4+ so this weird way to check is used 7547 if (Math.abs(y - end) < 1) { 7548 $sub.dataSM('scroll-arrows').eq(up ? 0 : 1).hide(); 7549 $sub.dataSM('scroll').step = 1; 7550 } else if (!wheel) { 7551 var self = this; 7552 this.scrollTimeout = setTimeout(function() { self.menuScroll($sub, up); }, this.opts.scrollInterval); 7553 } 7554 }, 7555 menuScrollMousewheel: function($sub, e) { 7556 var $closestSub = $(e.target).closest('ul'); 7557 while ($closestSub.dataSM('in-mega')) { 7558 $closestSub = $closestSub.parent().closest('ul'); 7559 } 7560 if ($closestSub[0] == $sub[0]) { 7561 var up = (e.originalEvent.wheelDelta || -e.originalEvent.detail) > 0; 7562 if ($sub.dataSM('scroll-arrows').eq(up ? 0 : 1).is(':visible')) { 7563 this.menuScroll($sub, up, true); 7564 } 7565 } 7566 e.preventDefault(); 7567 }, 7568 menuScrollOut: function($sub, e) { 7569 var reClass = /^scroll-(up|down)/, 7570 $closestSub = $(e.relatedTarget).closest('ul'); 7571 while ($closestSub.dataSM('in-mega')) { 7572 $closestSub = $closestSub.parent().closest('ul'); 7573 } 7574 if (!reClass.test((e.relatedTarget || '').className) && ($sub[0] != e.relatedTarget && !$.contains($sub[0], e.relatedTarget) || $closestSub[0] != $sub[0])) { 7575 $sub.dataSM('scroll-arrows').css('visibility', 'hidden'); 7576 } 7577 }, 7578 menuScrollOver: function($sub, e) { 7579 var reClass = /^scroll-(up|down)/, 7580 $closestSub = $(e.target).closest('ul'); 7581 while ($closestSub.dataSM('in-mega')) { 7582 $closestSub = $closestSub.parent().closest('ul'); 7583 } 7584 if (!reClass.test(e.target.className) && $closestSub[0] == $sub[0]) { 7585 $sub.dataSM('scroll-arrows').css('visibility', 'visible'); 7586 } 7587 }, 7588 menuScrollStop: function($sub) { 7589 if (this.scrollTimeout) { 7590 clearTimeout(this.scrollTimeout); 7591 this.scrollTimeout = 0; 7592 $sub.dataSM('scroll').step = 1; 7593 } 7594 }, 7595 menuShow: function($sub) { 7596 if (!$sub.dataSM('beforefirstshowfired')) { 7597 $sub.dataSM('beforefirstshowfired', true); 7598 if (this.$root.triggerHandler('beforefirstshow.smapi', $sub[0]) === false) { 7599 return; 7600 } 7601 } 7602 if (this.$root.triggerHandler('beforeshow.smapi', $sub[0]) === false) { 7603 return; 7604 } 7605 this.menuFixLayout($sub); 7606 $sub.stop(true, true); 7607 if (!$sub.is(':visible')) { 7608 // set z-index - for IE < 9 set it to the parent LI
7609 var zIndex = this.getStartZIndex() + (++this.zIndexInc); 7610 if (IElt9) { 7611 $sub.parent().css('z-index', zIndex); 7612 } else { 7613 $sub.css('z-index', zIndex); 7614 } 7615 // highlight parent item 7616 if (this.opts.keepHighlighted || this.isCollapsible()) { 7617 if ($sub.dataSM('parent-a').attr('data-type') != 'title') 7618 $sub.dataSM('parent-a').addClass('highlighted'); 7619 } 7620 // min/max-width fix - no way to rely purely on CSS as all UL's are nested 7621 if (this.opts.subMenusMinWidth || this.opts.subMenusMaxWidth) { 7622 if (!IElt8) { 7623 $sub.css({ width: ($sub.hasClass('mega-menu-inner')) ? $('.box-container').outerWidth() + 'px' : 'auto', minWidth: '', maxWidth: '' }).addClass('sm-nowrap'); 7624 if (this.opts.subMenusMinWidth) { 7625 $sub.css('min-width', this.opts.subMenusMinWidth); 7626 } 7627 if (this.opts.subMenusMaxWidth) { 7628 var noMaxWidth = this.getWidth($sub); 7629 $sub.css('max-width', this.opts.subMenusMaxWidth); 7630 if (noMaxWidth > this.getWidth($sub)) { 7631 $sub.removeClass('sm-nowrap').css('width', this.opts.subMenusMaxWidth); 7632 } 7633 } 7634 // IE6,7 7635 } else { 7636 $sub.children().css('styleFloat', 'none'); 7637 if (IE6) { 7638 $sub.width(this.opts.subMenusMinWidth ? this.opts.subMenusMinWidth : 1) 7639 .children().children('a').css('white-space', 'nowrap'); 7640 } else { // IE7 7641 $sub.css({ width: ($sub.hasClass('mega-menu-inner')) ? $('.box-container').outerWidth() + 'px' : 'auto', minWidth: '', maxWidth: '' }).addClass('sm-nowrap'); 7642 if (this.opts.subMenusMinWidth) { 7643 $sub.css('min-width', this.opts.subMenusMinWidth); 7644 } 7645 } 7646 if (this.opts.subMenusMaxWidth) { 7647 var noMaxWidth = $sub.width(); 7648 if (IE6) { 7649 var maxWidth = $sub.css({ width: this.opts.subMenusMaxWidth, overflowX: 'hidden', overflowY: 'hidden' }).width(); 7650 if (noMaxWidth > maxWidth) { 7651 $sub.css({ width: maxWidth, overflowX: 'visible', overflowY: 'visible' }).children().children('a').css('white-space', ''); 7652 } else { 7653 $sub.css({ width: noMaxWidth, overflowX: 'visible', overflowY: 'visible' }); 7654 } 7655 } else { // IE7 7656 $sub.css('max-width', this.opts.subMenusMaxWidth); 7657 if (noMaxWidth > $sub.width()) { 7658 $sub.removeClass('sm-nowrap').css('width', this.opts.subMenusMaxWidth); 7659 } else { 7660 $sub.width(noMaxWidth); 7661 } 7662 } 7663 } else { 7664 $sub.width($sub.width()); 7665 } 7666 $sub.children().css('styleFloat', 'left'); 7667 } 7668 } 7669 this.menuPosition($sub); 7670 // insert IE iframe shim 7671 if ($sub.dataSM('ie-shim')) { 7672 $sub.dataSM('ie-shim').insertBefore($sub); 7673 } 7674 var complete = function() { 7675 // fix: "overflow: hidden;" is not reset on animation complete in jQuery < 1.9.0 in Chrome when global "box-sizing: border-box;" is used 7676 $sub.css('overflow', ''); 7677 }; 7678 // if sub is collapsible (mobile view) 7679 if (this.isCollapsible()) { 7680 if (this.opts.collapsibleShowFunction) { 7681 this.opts.collapsibleShowFunction.call(this, $sub, complete); 7682 } else { 7683 $sub.show(this.opts.collapsibleShowDuration, complete); 7684 } 7685 } else { 7686 if (this.opts.showFunction) { 7687 this.opts.showFunction.call(this, $sub, complete); 7688 } else { 7689 $sub.show(this.opts.showDuration, complete); 7690 } 7691 } 7692 // save new sub menu for this level 7693 this.visibleSubMenus[$sub.dataSM('level') - 1] = $sub; 7694 this.$root.triggerHandler('show.smapi', $sub[0]); 7695 } 7696 }, 7697 popupHide: function(noHideTimeout) { 7698 if (this.hideTimeout) { 7699 clearTimeout(this.hideTimeout); 7700 this.hideTimeout = 0; 7701 } 7702 var self = this; 7703 this.hideTimeout = setTimeout(function() { 7704 self.menuHideAll(); 7705 }, noHideTimeout ? 1 : this.opts.hideTimeout); 7706 }, 7707 popupShow: function(left, top) { 7708 if (!this.opts.isPopup) { 7709 alert('SmartMenus jQuery Error:\n\nIf you want to show this menu via the "popupShow" method, set the isPopup:true option.'); 7710 return; 7711 } 7712 if (this.hideTimeout) { 7713 clearTimeout(this.hideTimeout); 7714 this.hideTimeout = 0; 7715 } 7716 this.menuFixLayout(this.$root); 7717 this.$root.stop(true, true); 7718 if (!this.$root.is(':visible')) { 7719 this.$root.css({ left: left, top: top }); 7720 // IE iframe shim 7721 this.menuIframeShim(this.$root); 7722 if (this.$root.dataSM('ie-shim')) { 7723 this.$root.dataSM('ie-shim').css({ zIndex: this.$root.css('z-index'), width: this.getWidth(this.$root), height: this.getHeight(this.$root), left
7723: left, top: top }).insertBefore(this.$root); 7724 } 7725 // show menu 7726 if (this.opts.showFunction) { 7727 this.opts.showFunction.call(this, this.$root); 7728 } else { 7729 this.$root.show(this.opts.showDuration); 7730 } 7731 this.visibleSubMenus[0] = this.$root; 7732 } 7733 }, 7734 refresh: function() { 7735 this.menuHideAll(); 7736 this.$root.find('ul').each(function() { 7737 var $this = $(this); 7738 if ($this.dataSM('scroll-arrows')) { 7739 $this.dataSM('scroll-arrows').remove(); 7740 } 7741 }) 7742 .removeDataSM('in-mega') 7743 .removeDataSM('shown-before') 7744 .removeDataSM('ie-shim') 7745 .removeDataSM('scroll-arrows') 7746 .removeDataSM('parent-a') 7747 .removeDataSM('level') 7748 .removeDataSM('beforefirstshowfired'); 7749 this.$root.find('a.has-submenu').removeClass('has-submenu') 7750 .parent().removeDataSM('sub'); 7751 if (this.opts.subIndicators) { 7752 this.$root.find('span.sub-arrow').remove(); 7753 } 7754 if (this.opts.markCurrentItem) { 7755 this.$root.find('a.current').removeClass('current'); 7756 } 7757 this.subMenus = []; 7758 this.init(true); 7759 }, 7760 rootOut: function(e) { 7761 if (!this.handleEvents() || this.isTouchMode() || e.target == this.$root[0]) { 7762 return; 7763 } 7764 if (this.hideTimeout) { 7765 clearTimeout(this.hideTimeout); 7766 this.hideTimeout = 0; 7767 } 7768 if (!this.opts.showOnClick || !this.opts.hideOnClick) { 7769 var self = this; 7770 this.hideTimeout = setTimeout(function() { self.menuHideAll(); }, this.opts.hideTimeout); 7771 } 7772 }, 7773 rootOver: function(e) { 7774 if (!this.handleEvents() || this.isTouchMode() || e.target == this.$root[0]) { 7775 return; 7776 } 7777 if (this.hideTimeout) { 7778 clearTimeout(this.hideTimeout); 7779 this.hideTimeout = 0; 7780 } 7781 }, 7782 winResize: function(e) { 7783 if (!this.handleEvents()) { 7784 // we still need to resize the disable overlay if it's visible 7785 if (this.$disableOverlay) { 7786 var pos = this.$root.offset(); 7787 this.$disableOverlay.css({ 7788 top: pos.top, 7789 left: pos.left, 7790 width: this.$root.outerWidth(), 7791 height: this.$root.outerHeight() 7792 }); 7793 } 7794 return; 7795 } 7796 // hide sub menus on resize - on mobile do it only on orientation change 7797 if (!this.isCollapsible() && (!('onorientationchange' in window) || e.type == 'orientationchange')) { 7798 if (this.activatedItems.length) { 7799 this.activatedItems[this.activatedItems.length - 1][0].blur(); 7800 } 7801 this.menuHideAll(); 7802 } 7803 } 7804 } 7805 }); 7806 7807 $.fn.dataSM = function(key, val) { 7808 if (val) { 7809 return this.data(key + '_smartmenus', val); 7810 } 7811 return this.data(key + '_smartmenus'); 7812 } 7813 7814 $.fn.removeDataSM = function(key) { 7815 return this.removeData(key + '_smartmenus'); 7816 } 7817 7818 $.fn.smartmenus = function(options) { 7819 if (typeof options == 'string') { 7820 var args = arguments, 7821 method = options; 7822 Array.prototype.shift.call(args); 7823 return this.each(function() { 7824 var smartmenus = $(this).data('smartmenus'); 7825 if (smartmenus && smartmenus[method]) { 7826 smartmenus[method].apply(smartmenus, args); 7827 } 7828 }); 7829 } 7830 var opts = $.extend({}, $.fn.smartmenus.defaults, options); 7831 return this.each(function() { 7832 new $.SmartMenus(this, opts); 7833 }); 7834 } 7835 7836 // default settings 7837 $.fn.smartmenus.defaults = { 7838 isPopup: false, // is this a popup menu (can be shown via the popupShow/popupHide methods) or a permanent menu bar 7839 mainMenuSubOffsetX: 0, // pixels offset from default position
7840 mainMenuSubOffsetY: 0, // pixels offset from default position 7841 subMenusSubOffsetX: 0, // pixels offset from default position 7842 subMenusSubOffsetY: 0, // pixels offset from default position 7843 subMenusMinWidth: '10em', // min-width for the sub menus (any CSS unit) - if set, the fixed width set in CSS will be ignored 7844 subMenusMaxWidth: '20em', // max-width for the sub menus (any CSS unit) - if set, the fixed width set in CSS will be ignored 7845 subIndicators: true, // create sub menu indicators - creates a SPAN and inserts it in the A 7846 subIndicatorsPos: 'prepend', // position of the SPAN relative to the menu item content ('prepend', 'append') 7847 subIndicatorsText: '+', // [optionally] add text in the SPAN (e.g. '+') (you may want to check the CSS for the sub indicators too) 7848 scrollStep: 30, // pixels step when scrolling long sub menus that do not fit in the viewport height 7849 scrollInterval: 30, // interval between each scrolling step 7850 scrollAccelerate: true, // accelerate scrolling or use a fixed step 7851 showTimeout: 250, // timeout before showing the sub menus 7852 hideTimeout: 500, // timeout before hiding the sub menus 7853 showDuration: 0, // duration for show animation - set to 0 for no animation - matters only if showFunction:null 7854 showFunction: null, // custom function to use when showing a sub menu (the default is the jQuery 'show') 7855 // don't forget to call complete() at the end of whatever you do 7856 // e.g.: function($ul, complete) { $ul.fadeIn(250, complete); } 7857 hideDuration: 0, // duration for hide animation - set to 0 for no animation - matters only if hideFunction:null 7858 hideFunction: function($ul, complete) { $ul.fadeOut(200, complete); }, // custom function to use when hiding a sub menu (the default is the jQuery 'hide') 7859 // don't forget to call complete() at the end of whatever you do 7860 // e.g.: function($ul, complete) { $ul.fadeOut(250, complete); } 7861 collapsibleShowDuration:0, // duration for show animation for collapsible sub menus - matters only if collapsibleShowFunction:null 7862 collapsibleShowFunction:function($ul, complete) { $ul.slideDown(200, complete); }, // custom function to use when showing a collapsible sub menu 7863 // (i.e. when mobile styles are used to make the sub menus collapsible) 7864 collapsibleHideDuration:0, // duration for hide animation for collapsible sub menus - matters only if collapsibleHideFunction:null 7865 collapsibleHideFunction:function($ul, complete) { $ul.slideUp(200, complete); }, // custom function to use when hiding a collapsible sub menu 7866 // (i.e. when mobile styles are used to make the sub menus collapsible) 7867 showOnClick: false, // show the first-level sub menus onclick instead of onmouseover (matters only for mouse input) 7868 hideOnClick: true, // hide the sub menus on click/tap anywhere on the page 7869 keepInViewport: true, // reposition the sub menus if needed to make sure they always appear inside the viewport 7870 keepHighlighted: true, // keep all ancestor items of the current sub menu highlighted (adds the 'highlighted' class to the A's) 7871 markCurrentItem: false, // automatically add the 'current' class to the A element of the item linking to the current URL 7872 markCurrentTree: true, // add the 'current' class also to the A elements of all ancestor items of the current item 7873 rightToLeftSubMenus: false, // right to left display of the sub menus (check the CSS for the sub indicators' position) 7874 bottomToTopSubMenus: false, // bottom to top display of the sub menus 7875 overlapControlsInIE: true // make sure sub menus appear on top of special OS controls in IE (i.e. SELECT, OBJECT, EMBED, etc.) 7876 }; 7877 7878})(jQuery); 7879 7880/* 7881 * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/ 7882 * 7883 * Uses the built in easing capabilities added In jQuery 1.1 7884 * to offer multiple easing options 7885 * 7886 * TERMS OF USE - jQuery Easing 7887 * 7888 * Open source under the BSD License. 7889 * 7890 * Copyright © 2008 George McGinley Smith 7891 * All rights reserved. 7892 * 7893 * Redistribution and use in source and binary forms, with or without modification, 7894 * are permitted provided that the following conditions are met: 7895 * 7896 * Redistributions of source code must retain the above copyright notice, this list of 7897 * conditions and the following disclaimer. 7898 * Redistributions in binary form must reproduce the above copyright notice, this list 7899 * of conditions and the following disclaimer in the documentation and/or other materials 7900 * provided with the distribution. 7901 * 7902 * Neither the name of the author nor the names of contributors may be used to endorse 7903 * or promote products derived from this software without specific prior written permission. 7904 * 7905 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 7906 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 7907 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 7908 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
vendor: 5,091 bytes, lines 7909-8054
7909 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 7910 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 7911 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 7912 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 7913 * OF THE POSSIBILITY OF SUCH DAMAGE. 7914 * 7915*/ 7916 7917// t: current time, b: begInnIng value, c: change In value, d: duration 7918jQuery.easing['jswing'] = jQuery.easing['swing']; 7919 7920jQuery.extend( jQuery.easing, 7921{ 7922 def: 'easeOutQuad', 7923 swing: function (x, t, b, c, d) { 7924 //alert(jQuery.easing.default); 7925 return jQuery.easing[jQuery.easing.def](x, t, b, c, d); 7926 }, 7927 easeInQuad: function (x, t, b, c, d) { 7928 return c*(t/=d)*t + b; 7929 }, 7930 easeOutQuad: function (x, t, b, c, d) { 7931 return -c *(t/=d)*(t-2) + b; 7932 }, 7933 easeInOutQuad: function (x, t, b, c, d) { 7934 if ((t/=d/2) < 1) return c/2*t*t + b; 7935 return -c/2 * ((--t)*(t-2) - 1) + b; 7936 }, 7937 easeInCubic: function (x, t, b, c, d) { 7938 return c*(t/=d)*t*t + b; 7939 }, 7940 easeOutCubic: function (x, t, b, c, d) { 7941 return c*((t=t/d-1)*t*t + 1) + b; 7942 }, 7943 easeInOutCubic: function (x, t, b, c, d) { 7944 if ((t/=d/2) < 1) return c/2*t*t*t + b; 7945 return c/2*((t-=2)*t*t + 2) + b; 7946 }, 7947 easeInQuart: function (x, t, b, c, d) { 7948 return c*(t/=d)*t*t*t + b; 7949 }, 7950 easeOutQuart: function (x, t, b, c, d) { 7951 return -c * ((t=t/d-1)*t*t*t - 1) + b; 7952 }, 7953 easeInOutQuart: function (x, t, b, c, d) { 7954 if ((t/=d/2) < 1) return c/2*t*t*t*t + b; 7955 return -c/2 * ((t-=2)*t*t*t - 2) + b; 7956 }, 7957 easeInQuint: function (x, t, b, c, d) { 7958 return c*(t/=d)*t*t*t*t + b; 7959 }, 7960 easeOutQuint: function (x, t, b, c, d) { 7961 return c*((t=t/d-1)*t*t*t*t + 1) + b; 7962 }, 7963 easeInOutQuint: function (x, t, b, c, d) { 7964 if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b; 7965 return c/2*((t-=2)*t*t*t*t + 2) + b; 7966 }, 7967 easeInSine: function (x, t, b, c, d) { 7968 return -c * Math.cos(t/d * (Math.PI/2)) + c + b; 7969 }, 7970 easeOutSine: function (x, t, b, c, d) { 7971 return c * Math.sin(t/d * (Math.PI/2)) + b; 7972 }, 7973 easeInOutSine: function (x, t, b, c, d) { 7974 return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b; 7975 }, 7976 easeInExpo: function (x, t, b, c, d) { 7977 return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b; 7978 }, 7979 easeOutExpo: function (x, t, b, c, d) { 7980 return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b; 7981 }, 7982 easeInOutExpo: function (x, t, b, c, d) { 7983 if (t==0) return b; 7984 if (t==d) return b+c; 7985 if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b; 7986 return c/2 * (-Math.pow(2, -10 * --t) + 2) + b; 7987 }, 7988 easeInCirc: function (x, t, b, c, d) { 7989 return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b; 7990 }, 7991 easeOutCirc: function (x, t, b, c, d) { 7992 return c * Math.sqrt(1 - (t=t/d-1)*t) + b; 7993 }, 7994 easeInOutCirc: function (x, t, b, c, d) { 7995 if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b; 7996 return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b; 7997 }, 7998 easeInElastic: function (x, t, b, c, d) { 7999 var s=1.70158;var p=0;var a=c; 8000 if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; 8001 if (a < Math.abs(c)) { a=c; var s=p/4; } 8002 else var s = p/(2*Math.PI) * Math.asin (c/a); 8003 return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; 8004 }, 8005 easeOutElastic: function (x, t, b, c, d) { 8006 var s=1.70158;var p=0;var a=c; 8007 if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; 8008 if (a < Math.abs(c)) { a=c; var s=p/4; } 8009 else var s = p/(2*Math.PI) * Math.asin (c/a); 8010 return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b; 8011 }, 8012 easeInOutElastic: function (x, t, b, c, d) { 8013 var s=1.70158;var p=0;var a=c; 8014 if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5); 8015 if (a < Math.abs(c)) { a=c; var s=p/4; } 8016 else var s = p/(2*Math.PI) * Math.asin (c/a); 8017 if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; 8018 return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b; 8019 }, 8020 easeInBack: function (x, t, b, c, d, s) { 8021 if (s == undefined) s = 1.70158; 8022 return c*(t/=d)*t*((s+1)*t - s) + b; 8023 }, 8024 easeOutBack: function (x, t, b, c, d, s) { 8025 if (s == undefined) s = 1.70158; 8026 return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b; 8027 }, 8028 easeInOutBack: function (x, t, b, c, d, s) { 8029 if (s == undefined) s = 1.70158; 8030 if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b; 8031 return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b; 8032 }, 8033 easeInBounce: function (x, t, b, c, d) { 8034 return c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d) + b; 8035 }, 8036 easeOutBounce: function (x, t, b, c, d) { 8037 if ((t/=d) < (1/2.75)) { 8038 return c*(7.5625*t*t) + b; 8039 } else if (t < (2/2.75)) { 8040 return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b; 8041 } else if (t < (2.5/2.75)) { 8042 return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b; 8043 } else { 8044 return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b; 8045 } 8046 }, 8047 easeInOutBounce: function (x, t, b, c, d) { 8048 if (t < d/2) return jQuery.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b; 8049 return jQuery.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b; 8050 } 8051}); 8052 8053/* 8054 *
8055 * TERMS OF USE - EASING EQUATIONS 8056 * 8057 * Open source under the BSD License. 8058 * 8059 * Copyright © 2001 Robert Penner 8060 * All rights reserved. 8061 * 8062 * Redistribution and use in source and binary forms, with or without modification, 8063 * are permitted provided that the following conditions are met: 8064 * 8065 * Redistributions of source code must retain the above copyright notice, this list of 8066 * conditions and the following disclaimer. 8067 * Redistributions in binary form must reproduce the above copyright notice, this list 8068 * of conditions and the following disclaimer in the documentation and/or other materials 8069 * provided with the distribution. 8070 * 8071 * Neither the name of the author nor the names of contributors may be used to endorse 8072 * or promote products derived from this software without specific prior written permission. 8073 * 8074 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 8075 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 8076 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 8077 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 8078 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 8079 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 8080 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 8081 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 8082 * OF THE POSSIBILITY OF SUCH DAMAGE. 8083 * 8084 */ 8085(function($, window, undefined) { 8086 // http://paulirish.com/2011/requestanimationframe-for-smart-animating/ 8087 // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating 8088 8089 // requestAnimationFrame polyfill by Erik Möller 8090 // fixes from Paul Irish and Tino Zijdel 8091 8092 var lastTime = 0, 8093 running, 8094 animate = function (elem) { 8095 if (running) { 8096 window.requestAnimationFrame(animate, elem); 8097 jQuery.fx.tick(); 8098 } 8099 }, 8100 vendors = ['ms', 'moz', 'webkit', 'o']; 8101 8102 for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { 8103 window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame']; 8104 window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] 8105 || window[vendors[x]+'CancelRequestAnimationFrame']; 8106 } 8107 8108 if (!window.requestAnimationFrame) 8109 window.requestAnimationFrame = function(fn, element) { 8110 var currTime = new Date().getTime(), 8111 delta = currTime - lastTime, 8112 timeToCall = Math.max(0, 16 - delta); 8113 8114 var id = window.setTimeout(function() { 8115 fn(currTime + timeToCall); 8116 }, 8117 timeToCall 8118 ); 8119 8120 lastTime = currTime + timeToCall; 8121 8122 return id; 8123 }; 8124 8125 if (!window.cancelAnimationFrame) { 8126 window.cancelAnimationFrame = function(id) { 8127 clearTimeout(id); 8128 }; 8129 } 8130 8131 jQuery.fx.timer = function (timer) { 8132 if (timer() && jQuery.timers.push(timer) && !running) { 8133 running = true; 8134 animate(timer.elem); 8135 } 8136 }; 8137 8138 jQuery.fx.stop = function() { 8139 running = false; 8140 }; 8141 8142}(jQuery, this)); 8143/*! Copyright (c) 2011 Brandon Aaron (http://brandonaaron.net) 8144 * Licensed under the MIT License (LICENSE.txt). 8145 * 8146 * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers. 8147 * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix. 8148 * Thanks to: Seamus Leahy for adding deltaX and deltaY 8149 * 8150 * Version: 3.0.6 8151 * 8152 * Requires: 1.2.2+ 8153 */ 8154(function($) { 8155 var types = ['DOMMouseScroll', 'mousewheel']; 8156 if ($.event.fixHooks) { 8157 for (var i = types.length; i;) { 8158 $.event.fixHooks[types[--i]] = $.event.mouseHooks; 8159 } 8160 } 8161 $.event.special.mousewheel = { 8162 setup: function() { 8163 if (this.addEventListener) { 8164 for (var i = types.length; i;) { 8165 this.addEventListener(types[--i], handler, false); 8166 } 8167 } else { 8168 this.onmousewheel = handler; 8169 } 8170 }, 8171 teardown: function() { 8172 if (this.removeEventListener) { 8173 for (var i = types.length; i;) { 8174 this.removeEventListener(types[--i], handler, false); 8175 } 8176 } else { 8177 this.onmousewheel = null; 8178 } 8179 } 8180 }; 8181 $.fn.extend({ 8182 mousewheel: function(fn) { 8183 return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel"); 8184 }, 8185 unmousewheel: function(fn) { 8186 return this.unbind("mousewheel", fn); 8187 } 8188 }); 8189 8190 function handler(event) { 8191 var orgEvent = event || window.event, 8192 args = [].slice.call(arguments, 1), 8193 delta = 0, 8194 returnValue = true, 8195 deltaX = 0, 8196 deltaY = 0; 8197 event = $.event.fix(orgEvent); 8198 event.type = "mousewheel"; 8199 // Old school scrollwheel delta 8200 if (orgEvent.wheelDelta) { 8201 delta = orgEvent.wheelDelta / 120; 8202 } 8203 if (orgEvent.detail) { 8204 delta = -orgEvent.detail / 3; 8205 } 8206 // New school multidimensional scroll (touchpads) deltas 8207 deltaY = delta; 8208 // Gecko 8209 if (orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS) { 8210 deltaY = 0; 8211 deltaX = -1 * delta; 8212 } 8213 // Webkit 8214 if (orgEvent.wheelDeltaY !== undefined) { 8215 deltaY = orgEvent.wheelDeltaY / 120; 8216 } 8217 if (orgEvent.wheelDeltaX !== undefined) { 8218 deltaX = -1 * orgEvent.wheelDeltaX / 120; 8219 } 8220 // Add event and delta to the front of the arguments 8221 args.unshift(event, delta, deltaX, deltaY); 8222 return ($.event.dispatch || $.event.handle).apply(this, args); 8223 } 8224})(jQuery); 8225/** 8226 * jQuery iLightBox - Revolutionary Lightbox Plugin 8227 * http://www.ilightbox.net/ 8228 * 8229 * @version: 2.2.4 - October 14, 2017 8230 * 8231 * @author: iProDev (Hemn Chawroka) 8232 * http://www.iprodev.com/ 8233 * 8234 */ 8235(function($, window, undefined) { 8236 8237 var extensions = { 8238 flash: ['swf'], 8239 image: ['bmp', 'gif', 'jpeg', 'jpg', 'png', 'tiff', 'tif', 'jfif', 'jpe'], 8240 iframe: ['asp', 'aspx', 'cgi', 'cfm', 'htm', 'html', 'jsp', 'php', 'pl', 'php3', 'php4', 'php5', 'phtml', 'rb', 'rhtml', 'shtml', 'txt'], 8241 video: ['avi', 'mov', 'mpg', 'mpeg', 'movie', 'mp4', 'webm', 'ogv', 'ogg', '3gp', 'm4v'] 8242 }, 8243 8244 // Global DOM elements 8245 $win = $(window), 8246 $doc = $(document), 8247
8248 // Support indicators 8249 browser, 8250 transform, 8251 gpuAcceleration, 8252 fullScreenApi = '', 8253 userAgent = navigator.userAgent || navigator.vendor || window.opera, 8254 supportTouch = "ontouchstart" in window || navigator.msMaxTouchPoints || (navigator.maxTouchPoints && navigator.userAgent.indexOf('Windows') > -1), 8255 ishybrid = navigator.maxTouchPoints && navigator.userAgent.indexOf('Windows') > -1, 8256 isMobile = /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(userAgent) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(userAgent.substr(0, 4)), 8257 8258 // Events 8259 clickEvent = ishybrid ? "itap.iLightBox click.iLightBox" : supportTouch ? "itap.iLightBox" : "click.iLightBox", 8260 touchStartEvent = ishybrid ? "touchstart.iLightBox mousedown.iLightBox" : supportTouch ? "touchstart.iLightBox" : "mousedown.iLightBox", 8261 touchStopEvent = ishybrid ? "touchend.iLightBox mouseup.iLightBox" : supportTouch ? "touchend.iLightBox" : "mouseup.iLightBox", 8262 touchMoveEvent = ishybrid ? "touchmove.iLightBox mousemove.iLightBox" : supportTouch ? "touchmove.iLightBox" : "mousemove.iLightBox", 8263 8264 // Math shorthands 8265 abs = Math.abs, 8266 sqrt = Math.sqrt, 8267 round = Math.round, 8268 max = Math.max, 8269 min = Math.min, 8270 floor = Math.floor, 8271 random = Math.random, 8272 8273 pluginspages = { 8274 quicktime: 'http://www.apple.com/quicktime/download', 8275 flash: 'http://www.adobe.com/go/getflash' 8276 }, 8277 8278 iLightBox = function(el, options, items, instant) { 8279 var iL = this; 8280 8281 iL.options = options, 8282 iL.selector = el.selector || el, 8283 iL.context = el.context, 8284 iL.instant = instant; 8285 8286 if (items.length < 1) iL.attachItems(); 8287 else iL.items = items; 8288 8289 iL.vars = { 8290 total: iL.items.length, 8291 start: 0, 8292 current: null, 8293 next: null, 8294 prev: null, 8295 BODY: $('body'), 8296 loadRequests: 0, 8297 overlay: $('<div class="ilightbox-overlay"></div>'), 8298 loader: $('<div class="ilightbox-loader"><div></div></div>'), 8299 toolbar: $('<div class="ilightbox-toolbar"></div>'), 8300 innerToolbar: $('<div class="ilightbox-inner-toolbar"></div>'), 8301 title: $('<div class="ilightbox-title"></div>'), 8302 closeButton: $('<a class="ilightbox-close" title="' + iL.options.text.close + '"></a>'), 8303 fullScreenButton: $('<a class="ilightbox-fullscreen" title="' + iL.options.text.enterFullscreen + '"></a>'), 8304 innerPlayButton: $('<a class="ilightbox-play" title="' + iL.options.text.slideShow + '"></a>'), 8305 innerNextButton: $('<a class="ilightbox-next-button" title="' + iL.options.text.next + '"></a>'), 8306 innerPrevButton: $('<a class="ilightbox-prev-button" title="' + iL.options.text.previous + '"></a>'), 8307 holder: $('<div class="ilightbox-holder' + (supportTouch ? ' supportTouch' : '') + '" ondragstart="return false;"><div class="ilightbox-container"></div></div>'), 8308 nextPhoto: $('<div class="ilightbox-holder' + (supportTouch ? ' supportTouch' : '') + ' ilightbox-next" ondragstart="return false;"><div class="ilightbox-container"></div></div>'), 8309 prevPhoto: $('<div class="ilightbox-holder' + (supportTouch ? ' supportTouch' : '') + ' ilightbox-prev" ondragstart="return false;"><div class="ilightbox-container"></div></div>'), 8310 nextButton: $('<a class="ilightbox-button ilightbox-next-button" ondragstart="return false;" title="' + iL.options.text.next + '"><span></span></a>'), 8311 prevButton: $('<a class="ilightbox-button ilightbox-prev-button" ondragstart="return false;" title="' + iL.options.text.previous + '"><span></span></a>'),
8312 thumbnails: $('<div class="ilightbox-thumbnails" ondragstart="return false;"><div class="ilightbox-thumbnails-container"><a class="ilightbox-thumbnails-dragger"></a><div class="ilightbox-thumbnails-grid"></div></div></div>'), 8313 thumbs: false, 8314 nextLock: false, 8315 prevLock: false, 8316 hashLock: false, 8317 isMobile: false, 8318 mobileMaxWidth: 980, 8319 isInFullScreen: false, 8320 isSwipe: false, 8321 mouseID: 0, 8322 cycleID: 0, 8323 isPaused: 0, 8324 captionHeight: 39, 8325 }; 8326 8327 // Hideable elements with mousemove event 8328 iL.vars.hideableElements = iL.vars.nextButton.add(iL.vars.prevButton); 8329 8330 iL.normalizeItems(); 8331 8332 //Check necessary plugins 8333 iL.availPlugins(); 8334 8335 //Set startFrom 8336 iL.options.startFrom = (iL.options.startFrom > 0 && iL.options.startFrom >= iL.vars.total) ? iL.vars.total - 1 : iL.options.startFrom; 8337 8338 //If randomStart 8339 iL.options.startFrom = (iL.options.randomStart) ? floor(random() * iL.vars.total) : iL.options.startFrom; 8340 iL.vars.start = iL.options.startFrom; 8341 8342 if (instant) iL.instantCall(); 8343 else iL.patchItemsEvents(); 8344 8345 if (iL.options.linkId) { 8346 iL.hashChangeHandler(); 8347 $win.iLightBoxHashChange(function() { 8348 iL.hashChangeHandler(); 8349 }); 8350 } 8351 8352 if (supportTouch) { 8353 var RegExp = /(click|mouseenter|mouseleave|mouseover|mouseout)/ig, 8354 replace = "itap"; 8355 iL.options.caption.show = iL.options.caption.show.replace(RegExp, replace), 8356 iL.options.caption.hide = iL.options.caption.hide.replace(RegExp, replace), 8357 iL.options.social.show = iL.options.social.show.replace(RegExp, replace), 8358 iL.options.social.hide = iL.options.social.hide.replace(RegExp, replace); 8359 } 8360 8361 if (iL.options.controls.arrows || $(window).width() < UNCODE.mediaQuery) { 8362 $.extend(iL.options.styles, { 8363 nextOffsetX: ($(window).width() > UNCODE.mediaQuery) ? 36 : 4, 8364 prevOffsetX: ($(window).width() > UNCODE.mediaQuery) ? 36 : 4, 8365 nextOpacity: 0, 8366 prevOpacity: 0 8367 }); 8368 } 8369 }; 8370 8371 //iLightBox helpers 8372 iLightBox.prototype = { 8373 showLoader: function() { 8374 var iL = this; 8375 iL.vars.loadRequests += 1; 8376 if (iL.options.path.toLowerCase() == "horizontal") iL.vars.loader.addClass('ilightbox-show').stop().animate({ 8377 //top: '-30px' 8378 opacity: '1' 8379 }, iL.options.show.speed, 'easeOutCirc'); 8380 else iL.vars.loader.addClass('ilightbox-show').stop().animate({ 8381 //left: '-30px' 8382 opacity: '1' 8383 }, iL.options.show.speed, 'easeOutCirc'); 8384 }, 8385 8386 hideLoader: function() { 8387 var iL = this; 8388 iL.vars.loadRequests -= 1; 8389 iL.vars.loadRequests = (iL.vars.loadRequests < 0) ? 0 : iL.vars.loadRequests; 8390 if (iL.options.path.toLowerCase() == "horizontal") { 8391 if (iL.vars.loadRequests <= 0) iL.vars.loader.removeClass('ilightbox-show').stop().animate({ 8392 //top: '-192px' 8393 opacity: '0' 8394 }, iL.options.show.speed, 'easeInCirc'); 8395 } else { 8396 if (iL.vars.loadRequests <= 0) iL.vars.loader.removeClass('ilightbox-show').stop().animate({ 8397 //left: '-192px' 8398 opacity: '0' 8399 }, iL.options.show.speed, 'easeInCirc'); 8400 } 8401 }, 8402 8403 createUI: function() { 8404 var iL = this; 8405 8406 iL.ui = { 8407 currentElement: iL.vars.holder, 8408 nextElement: iL.vars.nextPhoto, 8409 prevElement: iL.vars.prevPhoto, 8410 currentItem: iL.vars.current, 8411 nextItem: iL.vars.next, 8412 prevItem: iL.vars.prev, 8413 hide: function() { 8414 iL.closeAction(); 8415 }, 8416 refresh: function() { 8417 (arguments.length > 0) ? iL.repositionPhoto(true): iL.repositionPhoto(); 8418 }, 8419 fullscreen: function() { 8420 iL.fullScreenAction(); 8421 } 8422 }; 8423 }, 8424 8425 attachItems: function() { 8426 var iL = this, 8427 itemsObject = new Array(), 8428 items = new Array(); 8429 8430 $(iL.selector, iL.context).each(function() { 8431 var t = $(this), 8432 URL = t.attr(iL.options.attr) || null, 8433 options = t.data("options") && eval("({" + t.data("options") + "})") || {}, 8434 caption = t.data('caption'), 8435 title = t.data('title'), 8436 type = t.data('type') || getTypeByExtension(URL), 8437 clone = t.data('lbox-clone') || false; 8438 8439 if (t.data('lbox-clone') != undefined) return; 8440 8441 //Uncode addition ##START## 8442 if ( typeof t.attr('data-album') != 'undefined' && t.attr('data-album') != '' ) { 8443 var ALBUM_URLS = JSON.parse(t.attr('data-album')), 8444 URL_i, 8445 URLS_LENGHT = ALBUM_URLS.length; 8446 for (URL_i = 0; URL_i < URLS_LENGHT; URL_i++) { 8447 if ( typeof ALBUM_URLS[URL_i].url !== 'undefined' && ALBUM_URLS[URL_i].url != '' ) { 8448 var item_opts = 'width:' + ALBUM_URLS[URL_i].width + ',height:' + ALBUM_URLS[URL_i].height + ',thumbnail: \'' + ALBUM_URLS[URL_i].thumbnail + '\''; 8449 item_opts = item_opts && eval("({" + item_opts + "})") || {}, 8450 items.push({ 8451 URL: ALBUM_URLS[URL_i].url, 8452 caption: ALBUM_URLS[URL_i].caption, 8453 title: ALBUM_URLS[URL_i].title, 8454 type: getTypeByExtension(ALBUM_URLS[URL_i].url), 8455 options: item_opts, 8456 clone: clone 8457 }); 8458 var newT = t; 8459 newT.attr('href',ALBUM_URLS[URL_i].url); 8460 if (!iL.instant) itemsObject.push(newT); 8461 } 8462 } 8463 } else { 8464 //Uncode addition ##END## 8465 items.push({ 8466 URL: URL, 8467 caption: caption, 8468 title: title, 8469 type: type, 8470 options: options, 8471 clone: clone 8472 }); 8473 } 8474 8475 8476 if (iL.vars != undefined) iL.vars.total = items.length; 8477 8478 if (!iL.instant) itemsObject.push(t); 8479 }); 8480 8481 iL.items = items, 8482 iL.itemsObject = itemsObject; 8483 8484 }, 8485 8486 normalizeItems: function() { 8487 var iL = this, 8488 newItems = new Array(); 8489 8490 $.each(iL.items, function(key, val) { 8491 8492 if (typeof val == "string") val = { 8493 url: val 8494 }; 8495 8496 var URL = val.url || val.URL || null, 8497 options = val.options || {}, 8498 caption = val.caption || null, 8499 title = val.title || null, 8500 type = (val.type) ? val.type.toLowerCase() : getTypeByExtension(URL), 8501 ext = (typeof URL != 'object') ? getExtension(URL) : ''; 8502 8503 options.thumbnail = options.thumbnail || ((type == "image") ? URL : null),
8504 options.videoType = options.videoType || null, 8505 options.skin = options.skin || iL.options.skin, 8506 options.width = options.width || null, 8507 options.height = options.height || null, 8508 options.mousewheel = (typeof options.mousewheel != 'undefined') ? options.mousewheel : true, 8509 options.swipe = (typeof options.swipe != 'undefined') ? options.swipe : true, 8510 options.social = (typeof options.social != 'undefined') ? options.social : iL.options.social.buttons && $.extend({}, {}, iL.options.social.buttons); 8511 8512 if (type == "video") { 8513 options.html5video = (typeof options.html5video != 'undefined') ? options.html5video : {}; 8514 8515 options.html5video.webm = options.html5video.webm || options.html5video.WEBM || null; 8516 options.html5video.controls = (typeof options.html5video.controls != 'undefined') ? options.html5video.controls : "controls"; 8517 options.html5video.preload = options.html5video.preload || "metadata"; 8518 options.html5video.autoplay = (typeof options.html5video.autoplay != 'undefined') ? options.html5video.autoplay : false; 8519 //UNCODE addition 8520 options.html5video.loop = (typeof options.html5video.loop != 'undefined') ? options.html5video.loop : false; 8521 } 8522 8523 if (!options.width || !options.height) { 8524 if (type == "video") options.width = 1280, options.height = 720; 8525 else if (type == "iframe") options.width = '100%', options.height = '90%'; 8526 else if (type == "flash") options.width = 1280, options.height = 720; 8527 } 8528 8529 delete val.url; 8530 val.index = key; 8531 val.URL = URL; 8532 val.caption = caption; 8533 val.title = title; 8534 val.type = type; 8535 val.options = options; 8536 val.ext = ext; 8537 8538 newItems.push(val); 8539 }); 8540 8541 iL.items = newItems; 8542 }, 8543 8544 instantCall: function() { 8545 var iL = this, 8546 key = iL.vars.start; 8547 8548 iL.vars.current = key; 8549 iL.vars.next = (iL.items[key + 1]) ? key + 1 : null; 8550 iL.vars.prev = (iL.items[key - 1]) ? key - 1 : null; 8551 8552 iL.addContents(); 8553 iL.patchEvents(); 8554 }, 8555 8556 addContents: function() { 8557 var iL = this, 8558 vars = iL.vars, 8559 opts = iL.options, 8560 viewport = getViewport(), 8561 path = opts.path.toLowerCase(), 8562 recognizingItems = vars.total > 0 && iL.items.filter(function(e, i, arr) { 8563 return ['image', 'flash', 'video'].indexOf(e.type) === -1 && typeof e.recognized === 'undefined' && (opts.smartRecognition || e.options.smartRecognition); 8564 }), 8565 needRecognition = recognizingItems.length > 0; 8566 8567 if (opts.mobileOptimizer && !opts.innerToolbar) 8568 vars.isMobile = viewport.width <= vars.mobileMaxWidth; 8569 8570 vars.overlay.addClass(opts.skin).hide().css('opacity', opts.overlay.opacity); 8571 8572 if (opts.linkId) 8573 vars.overlay[0].setAttribute('linkid', opts.linkId); 8574 8575 //Add Toolbar Buttons 8576 if (opts.controls.toolbar) { 8577 vars.toolbar.addClass(opts.skin).append(vars.closeButton); 8578 if (opts.controls.fullscreen) 8579 vars.toolbar.append(vars.fullScreenButton); 8580 if (opts.controls.slideshow) 8581 vars.toolbar.append(vars.innerPlayButton); 8582 if (vars.total > 1) 8583 vars.toolbar.append(vars.innerPrevButton).append(vars.innerNextButton); 8584 } 8585 8586 //Append elements to body 8587 vars.BODY.addClass('ilightbox-noscroll').append(vars.overlay).append(vars.loader).append(vars.holder).append(vars.nextPhoto).append(vars.prevPhoto); 8588 8589 if (!opts.innerToolbar) 8590 vars.BODY.append(vars.toolbar); 8591 if (opts.controls.arrows) 8592 vars.BODY.append(vars.nextButton).append(vars.prevButton); 8593 8594 if (opts.controls.thumbnail && vars.total > 1) { 8595 vars.BODY.append(vars.thumbnails); 8596 vars.thumbnails.addClass(opts.skin).addClass('ilightbox-' + path); 8597 $('div.ilightbox-thumbnails-grid', vars.thumbnails).empty(); 8598 vars.thumbs = true; 8599 } 8600 8601 //Configure loader and arrows 8602 var loaderCss = (opts.path.toLowerCase() == "horizontal") ? { 8603 left: parseInt((viewport.width / 2) - (vars.loader.outerWidth() / 2)) 8604 } : { 8605 top: parseInt((viewport.height / 2) - (vars.loader.outerHeight() / 2)) 8606 }; 8607 vars.loader.addClass(opts.skin).css(loaderCss); 8608 vars.nextButton.add(vars.prevButton).addClass(opts.skin); 8609 if (path == "horizontal") 8610 vars.loader.add(vars.nextButton).add(vars.prevButton).addClass('horizontal'); 8611 8612 // Configure arrow buttons 8613 vars.BODY[vars.isMobile ? 'addClass' : 'removeClass']('isMobile'); 8614 8615 if (!opts.infinite) { 8616 vars.prevButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled'); 8617 8618 if (vars.current == 0) 8619 vars.prevButton.add(vars.innerPrevButton).addClass('disabled'); 8620 if (vars.current >= vars.total - 1) 8621 vars.nextButton.add(vars.innerNextButton).addClass('disabled'); 8622 } 8623 8624 if (opts.show.effect) { 8625 vars.overlay.stop().fadeIn(opts.show.speed); 8626 vars.toolbar.stop().fadeIn(opts.show.speed); 8627 } else { 8628 vars.overlay.show(); 8629 vars.toolbar.show(); 8630 } 8631 8632 var length = recognizingItems.length; 8633 if (needRecognition) { 8634 iL.showLoader(); 8635 8636 $.each(recognizingItems, function(key, val) { 8637 var resultFnc = function(result) { 8638 var key = -1, 8639 filter = iL.items.filter(function(e, i, arr) { 8640 if (e.URL == result.url) 8641 key = i; 8642 8643 return e.URL == result.url; 8644 }), 8645 self = iL.items[key]; 8646 8647 if (result) 8648 $.extend(true, self, { 8649 URL: result.source, 8650 type: result.type, 8651 recognized: true, 8652 options: { 8653 html5video: result.html5video, 8654 width: (result.type == "image") ? 0 : (result.width || self.width), 8655 height: (result.type == "image") ? 0 : (result.height || self.height), 8656 thumbnail: self.options.thumbnail || result.thumbnail 8657 } 8658 }); 8659 8660 length--; 8661 8662 if (length == 0) { 8663 iL.hideLoader(); 8664 8665 vars.dontGenerateThumbs = false;
8666 iL.generateThumbnails(); 8667 8668 if (opts.show.effect) 8669 setTimeout(function() { 8670 iL.generateBoxes(); 8671 }, opts.show.speed); 8672 else 8673 iL.generateBoxes(); 8674 } 8675 }; 8676 8677 iL.ogpRecognition(this, resultFnc); 8678 }); 8679 } 8680 else { 8681 if (opts.show.effect) 8682 setTimeout(function() { 8683 iL.generateBoxes(); 8684 }, opts.show.speed); 8685 else 8686 iL.generateBoxes(); 8687 } 8688 8689 iL.createUI(); 8690 8691 window.iLightBox = { 8692 close: function() { 8693 iL.closeAction(); 8694 }, 8695 fullscreen: function() { 8696 iL.fullScreenAction(); 8697 }, 8698 moveNext: function() { 8699 iL.moveTo('next'); 8700 }, 8701 movePrev: function() { 8702 iL.moveTo('prev'); 8703 }, 8704 goTo: function(index) { 8705 iL.goTo(index); 8706 }, 8707 refresh: function() { 8708 iL.refresh(); 8709 }, 8710 reposition: function() { 8711 (arguments.length > 0) ? iL.repositionPhoto(true): iL.repositionPhoto(); 8712 }, 8713 setOption: function(options) { 8714 iL.setOption(options); 8715 }, 8716 destroy: function() { 8717 iL.closeAction(); 8718 iL.dispatchItemsEvents(); 8719 } 8720 }; 8721 8722 if (opts.linkId) { 8723 vars.hashLock = true; 8724 window.location.hash = opts.linkId + '/' + vars.current; 8725 setTimeout(function() { 8726 vars.hashLock = false; 8727 }, 55); 8728 } 8729 8730 if (!opts.slideshow.startPaused) { 8731 iL.resume(); 8732 vars.innerPlayButton.removeClass('ilightbox-play').addClass('ilightbox-pause'); 8733 } 8734 8735 //Trigger the onOpen callback 8736 if (typeof iL.options.callback.onOpen == 'function') iL.options.callback.onOpen.call(iL); 8737 }, 8738 8739 loadContent: function(obj, opt, speed) { 8740 var iL = this, 8741 holder, item; 8742 8743 iL.createUI(); 8744 8745 obj.speed = speed || iL.options.effects.loadedFadeSpeed; 8746 8747 if (opt == 'current') { 8748 if (!obj.options.mousewheel) iL.vars.lockWheel = true; 8749 else iL.vars.lockWheel = false; 8750 8751 if (!obj.options.swipe) iL.vars.lockSwipe = true; 8752 else iL.vars.lockSwipe = false; 8753 } 8754 8755 switch (opt) { 8756 case 'current': 8757 holder = iL.vars.holder, item = iL.vars.current; 8758 break; 8759 case 'next': 8760 holder = iL.vars.nextPhoto, item = iL.vars.next; 8761 break; 8762 case 'prev': 8763 holder = iL.vars.prevPhoto, item = iL.vars.prev; 8764 break; 8765 } 8766 8767 holder.removeAttr('style class').addClass('ilightbox-holder' + (supportTouch ? ' supportTouch' : '')).addClass(obj.options.skin); 8768 $('div.ilightbox-inner-toolbar', holder).remove(); 8769 8770 if (obj.title || iL.options.innerToolbar) { 8771 var innerToolbar = iL.vars.innerToolbar.clone(); 8772 if (obj.title && iL.options.show.title) { 8773 var title = iL.vars.title.clone(); 8774 title.empty().html(obj.title); 8775 innerToolbar.append(title); 8776 } 8777 if (iL.options.innerToolbar) { 8778 innerToolbar.append((iL.vars.total > 1) ? iL.vars.toolbar.clone() : iL.vars.toolbar); 8779 } 8780 holder.prepend(innerToolbar); 8781 } 8782 8783 //console.warn('loadContent', arguments); 8784 8785 iL.loadSwitcher(obj, holder, item, opt); 8786 }, 8787 8788 loadSwitcher: function(obj, holder, item, opt) { 8789 var iL = this, 8790 opts = iL.options, 8791 api = { 8792 element: holder, 8793 position: item 8794 }; 8795 8796 switch (obj.type) { 8797 case 'image': 8798 //Trigger the onBeforeLoad callback 8799 if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item); 8800 if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api); 8801 8802 iL.loadImage(obj.URL, function(img) { 8803 //Trigger the onAfterLoad callback 8804 if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item); 8805 if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api); 8806 8807 var width = (img) ? img.width : 400, 8808 height = (img) ? img.height : 200; 8809 8810 holder.data({ 8811 naturalWidth: width, 8812 naturalHeight: height 8813 }); 8814 $('div.ilightbox-container', holder).empty().append((img) ? '<img src="' + obj.URL + '" class="ilightbox-image" />' : '<span class="ilightbox-alert">' + opts.errors.loadImage + '</span>'); 8815 8816 //Trigger the onRender callback 8817 if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item); 8818 if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api); 8819 8820 iL.configureHolder(obj, opt, holder); 8821 }); 8822 8823 break; 8824
8825 case 'video': 8826 holder.data({ 8827 naturalWidth: obj.options.width, 8828 naturalHeight: obj.options.height 8829 }); 8830 8831 if (opt === 'current') { 8832 iL.addContent(holder, obj); 8833 8834 //Trigger the onRender callback 8835 if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item); 8836 if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api); 8837 } else { 8838 $('div.ilightbox-container', holder).empty(); 8839 } 8840 8841 iL.configureHolder(obj, opt, holder); 8842 8843 break; 8844 8845 case 'iframe': 8846 //iL.showLoader(); 8847 holder.data({ 8848 naturalWidth: obj.options.width, 8849 naturalHeight: obj.options.height 8850 }); 8851 8852 iL.configureHolder(obj, opt, holder); 8853 8854 if (opt === 'current') { 8855 var el = iL.addContent(holder, obj); 8856 8857 //Trigger the onRender callback 8858 if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item); 8859 if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api); 8860 8861 //Trigger the onBeforeLoad callback 8862 if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item); 8863 if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api); 8864 8865 el.bind('load', function() { 8866 //Trigger the onAfterLoad callback 8867 if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item); 8868 if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api); 8869 8870 //iL.hideLoader(); 8871 el.unbind('load'); 8872 }); 8873 } else { 8874 $('div.ilightbox-container', holder).empty(); 8875 } 8876 8877 break; 8878 8879 case 'inline': 8880 var el = $(obj.URL), 8881 content = iL.addContent(holder, obj), 8882 images = findImageInElement(holder); 8883 8884 holder.data({ 8885 naturalWidth: (iL.items[item].options.width || el.outerWidth()), 8886 naturalHeight: (iL.items[item].options.height || el.outerHeight()) 8887 }); 8888 content.children().eq(0).show(); 8889 8890 //Trigger the onRender callback 8891 if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item); 8892 if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api); 8893 8894 //Trigger the onBeforeLoad callback 8895 if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item); 8896 if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api); 8897 8898 iL.loadImage(images, function() { 8899 //Trigger the onAfterLoad callback 8900 if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item); 8901 if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api); 8902 8903 iL.configureHolder(obj, opt, holder); 8904 }); 8905 8906 break; 8907 8908 case 'flash': 8909 var el = iL.addContent(holder, obj); 8910 8911 holder.data({ 8912 naturalWidth: (iL.items[item].options.width || el.outerWidth()), 8913 naturalHeight: (iL.items[item].options.height || el.outerHeight()) 8914 }); 8915 8916 //Trigger the onRender callback 8917 if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item); 8918 if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api); 8919 8920 iL.configureHolder(obj, opt, holder); 8921 8922 break; 8923 8924 case 'ajax': 8925 var ajax = obj.options.ajax || {}; 8926 //Trigger the onBeforeLoad callback 8927 if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item); 8928 if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api); 8929 8930 iL.showLoader(); 8931 $.ajax({ 8932 url: obj.URL || opts.ajaxSetup.url, 8933 data: ajax.data || null, 8934 dataType: ajax.dataType || "html", 8935 type: ajax.type || opts.ajaxSetup.type, 8936 cache: ajax.cache || opts.ajaxSetup.cache, 8937 crossDomain: ajax.crossDomain || opts.ajaxSetup.crossDomain, 8938 global: ajax.global || opts.ajaxSetup.global, 8939 ifModified: ajax.ifModified || opts.ajaxSetup.ifModified, 8940 username: ajax.username || opts.ajaxSetup.username, 8941 password: ajax.password || opts.ajaxSetup.password, 8942 beforeSend: ajax.beforeSend || opts.ajaxSetup.beforeSend, 8943 complete: ajax.complete || opts.ajaxSetup.complete, 8944 success: function(data, textStatus, jqXHR) { 8945 iL.hideLoader(); 8946 8947 var el = $(data), 8948 container = $('div.ilightbox-container', holder), 8949 elWidth = iL.items[item].options.width || parseInt(el[0].getAttribute('width')), 8950 elHeight = iL.items[item].options.height || parseInt(el[0].getAttribute('height')), 8951 css = (el[0].getAttribute('width') && el[0].getAttribute('height')) ? { 8952 'overflow': 'hidden' 8953 } : {}; 8954 8955 container.empty().append($('<div class="ilightbox-wrapper"></div>').css(css).html(el)); 8956 holder.show().data({
8957 naturalWidth: (elWidth || container.outerWidth()), 8958 naturalHeight: (elHeight || container.outerHeight()) 8959 }).hide(); 8960 8961 //Trigger the onRender callback 8962 if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item); 8963 if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api); 8964 8965 var images = findImageInElement(holder); 8966 iL.loadImage(images, function() { 8967 //Trigger the onAfterLoad callback 8968 if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item); 8969 if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api); 8970 8971 iL.configureHolder(obj, opt, holder); 8972 }); 8973 8974 opts.ajaxSetup.success(data, textStatus, jqXHR); 8975 if (typeof ajax.success == 'function') ajax.success(data, textStatus, jqXHR); 8976 }, 8977 error: function(jqXHR, textStatus, errorThrown) { 8978 //Trigger the onAfterLoad callback 8979 if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item); 8980 if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api); 8981 8982 iL.hideLoader(); 8983 $('div.ilightbox-container', holder).empty().append('<span class="ilightbox-alert">' + opts.errors.loadContents + '</span>'); 8984 iL.configureHolder(obj, opt, holder); 8985 8986 opts.ajaxSetup.error(jqXHR, textStatus, errorThrown); 8987 if (typeof ajax.error == 'function') ajax.error(jqXHR, textStatus, errorThrown); 8988 } 8989 }); 8990 8991 break; 8992 8993 case 'html': 8994 var object = obj.URL, 8995 el 8996 container = $('div.ilightbox-container', holder); 8997 8998 if (object[0].nodeName) el = object.clone(); 8999 else { 9000 var dom = $(object); 9001 if (dom.selector) el = $('<div>' + dom + '</div>'); 9002 else el = dom; 9003 } 9004 9005 var elWidth = iL.items[item].options.width || parseInt(el.attr('width')), 9006 elHeight = iL.items[item].options.height || parseInt(el.attr('height')); 9007 9008 iL.addContent(holder, obj); 9009 9010 el.appendTo(document.documentElement).hide(); 9011 9012 //Trigger the onRender callback 9013 if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item); 9014 if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api); 9015 9016 var images = findImageInElement(holder); 9017 9018 //Trigger the onBeforeLoad callback 9019 if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item); 9020 if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api); 9021 9022 iL.loadImage(images, function() { 9023 //Trigger the onAfterLoad callback 9024 if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item); 9025 if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api); 9026 9027 holder.show().data({ 9028 naturalWidth: (elWidth || container.outerWidth()), 9029 naturalHeight: (elHeight || container.outerHeight()) 9030 }).hide(); 9031 el.remove(); 9032 9033 iL.configureHolder(obj, opt, holder); 9034 }); 9035 9036 break; 9037 } 9038 }, 9039 9040 configureHolder: function(obj, opt, holder) { 9041 var iL = this, 9042 vars = iL.vars, 9043 opts = iL.options; 9044 9045 if (opt != "current")(opt == "next") ? holder.addClass('ilightbox-next') : holder.addClass('ilightbox-prev'); 9046 9047 if (opt == "current") 9048 var item = vars.current; 9049 else if (opt == "next") 9050 var opacity = opts.styles.nextOpacity, 9051 item = vars.next; 9052 else 9053 var opacity = opts.styles.prevOpacity, 9054 item = vars.prev; 9055 9056 var api = { 9057 element: holder, 9058 position: item 9059 }; 9060 9061 iL.items[item].options.width = iL.items[item].options.width || 0, 9062 iL.items[item].options.height = iL.items[item].options.height || 0; 9063 9064 if (opt == "current") { 9065 if (opts.show.effect) holder.css(transform, gpuAcceleration).fadeIn(obj.speed, function() { 9066 holder.css(transform, ''); 9067 if (obj.caption) { 9068 iL.setCaption(obj, holder); 9069 var caption = $('div.ilightbox-caption', holder), 9070 percent = parseInt((caption.outerHeight() / holder.outerHeight()) * 100); 9071 if (opts.caption.start & percent <= 50) caption.fadeIn(opts.effects.fade
9071Speed); 9072 } 9073 9074 var social = obj.options.social; 9075 if (social) { 9076 iL.setSocial(social, obj.URL, holder); 9077 if (opts.social.start) $('div.ilightbox-social', holder).fadeIn(opts.effects.fadeSpeed); 9078 } 9079 9080 //Generate thumbnails 9081 iL.generateThumbnails(); 9082 9083 //Trigger the onShow callback 9084 if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item); 9085 if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api); 9086 }); 9087 else { 9088 holder.show(); 9089 9090 //Generate thumbnails 9091 iL.generateThumbnails(); 9092 9093 //Trigger the onShow callback 9094 if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item); 9095 if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api); 9096 } 9097 } else { 9098 if (opts.show.effect) holder.fadeTo(obj.speed, opacity, function() { 9099 if (opt == "next") vars.nextLock = false; 9100 else vars.prevLock = false; 9101 9102 //Generate thumbnails 9103 iL.generateThumbnails(); 9104 9105 //Trigger the onShow callback 9106 if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item); 9107 if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api); 9108 }); 9109 else { 9110 holder.css({ 9111 opacity: opacity 9112 }).show(); 9113 if (opt == "next") vars.nextLock = false; 9114 else vars.prevLock = false; 9115 9116 //Generate thumbnails 9117 iL.generateThumbnails(); 9118 9119 //Trigger the onShow callback 9120 if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item); 9121 if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api); 9122 } 9123 } 9124 9125 setTimeout(function() { 9126 iL.repositionPhoto(); 9127 }, 0); 9128 }, 9129 9130 generateBoxes: function() { 9131 var iL = this, 9132 vars = iL.vars, 9133 opts = iL.options; 9134 9135 if (opts.infinite && vars.total >= 3) { 9136 if (vars.current == vars.total - 1) vars.next = 0; 9137 if (vars.current == 0) vars.prev = vars.total - 1; 9138 } else opts.infinite = false; 9139 9140 //UNCODE addition 9141 if ( typeof iL.items[vars.current] == 'undefined' ) 9142 vars.current = 0; 9143 9144 iL.loadContent(iL.items[vars.current], 'current', opts.show.speed); 9145 9146 if (iL.items[vars.next]) iL.loadContent(iL.items[vars.next], 'next', opts.show.speed); 9147 if (iL.items[vars.prev]) iL.loadContent(iL.items[vars.prev], 'prev', opts.show.speed); 9148 }, 9149 9150 generateThumbnails: function() { 9151 var iL = this, 9152 vars = iL.vars, 9153 opts = iL.options, 9154 timeOut = null; 9155 9156 if (vars.thumbs && !iL.vars.dontGenerateThumbs) { 9157 var thumbnails = vars.thumbnails, 9158 container = $('div.ilightbox-thumbnails-container', thumbnails), 9159 grid = $('div.ilightbox-thumbnails-grid', container), 9160 i = 0; 9161 9162 grid.removeAttr('style').empty(); 9163 9164 $.each(iL.items, function(key, val) { 9165 var isActive = (vars.current == key) ? 'ilightbox-active' : '', 9166 opacity = (vars.current == key) ? opts.thumbnails.activeOpacity : opts.thumbnails.normalOpacity, 9167 thumb = val.options.thumbnail, 9168 thumbnail = $('<div class="ilightbox-thumbnail"></div>'), 9169 icon = $('<div class="ilightbox-thumbnail-icon"></div>'); 9170 9171 thumbnail.css({ 9172 opacity: 0 9173 }).addClass(isActive); 9174 9175 if ((val.type == "video" || val.type == "flash") && typeof val.options.icon == 'undefined') { 9176 icon.addClass('ilightbox-thumbnail-video'); 9177 thumbnail.append(icon); 9178 } else if (val.options.icon) { 9179 icon.addClass('ilightbox-thumbnail-' + val.options.icon); 9180 thumbnail.append(icon); 9181 } 9182 9183 if (thumb) iL.loadImage(thumb, function(img) { 9184 i++; 9185 if (img) thumbnail.data({ 9186 naturalWidth: img.width, 9187 naturalHeight: img.height 9188 }).append('<img src="' + thumb + '" border="0" />'); 9189 else thumbnail.data({ 9190 naturalWidth: opts.thumbnails.maxWidth, 9191 naturalHeight: opts.thumbnails.maxHeight 9192 }); 9193 9194 clearTimeout(timeOut); 9195 timeOut = setTimeout(function() { 9196 iL.positionThumbnails(thumbnails, container, grid); 9197 }, 20); 9198 setTimeout(function() { 9199 thumbnail.fadeTo(opts.effects.loadedFadeSpeed, opacity); 9200 }, i * 20); 9201 }); 9202 9203 grid.append(thumbnail); 9204 }); 9205 iL.vars.dontGenerateThumbs = true; 9206 } 9207 }, 9208
9209 positionThumbnails: function(thumbnails, container, grid) { 9210 var iL = this, 9211 vars = iL.vars, 9212 opts = iL.options, 9213 viewport = getViewport(), 9214 path = opts.path.toLowerCase(); 9215 9216 if (!thumbnails) thumbnails = vars.thumbnails; 9217 if (!container) container = $('div.ilightbox-thumbnails-container', thumbnails); 9218 if (!grid) grid = $('div.ilightbox-thumbnails-grid', container); 9219 9220 var thumbs = $('.ilightbox-thumbnail', grid), 9221 widthAvail = (path == 'horizontal') ? viewport.width - opts.styles.pageOffsetX : thumbs.eq(0).outerWidth() - opts.styles.pageOffsetX, 9222 heightAvail = (path == 'horizontal') ? thumbs.eq(0).outerHeight() - opts.styles.pageOffsetY : viewport.height - opts.styles.pageOffsetY, 9223 gridWidth = (path == 'horizontal') ? 0 : widthAvail, 9224 gridHeight = (path == 'horizontal') ? heightAvail : 0, 9225 active = $('.ilightbox-active', grid), 9226 gridCss = {}, 9227 css = {}; 9228 9229 if (arguments.length < 3) { 9230 thumbs.css({ 9231 opacity: opts.thumbnails.normalOpacity 9232 }); 9233 active.css({ 9234 opacity: opts.thumbnails.activeOpacity 9235 }); 9236 } 9237 9238 thumbs.each(function(i) { 9239 var t = $(this), 9240 data = t.data(), 9241 width = (path == 'horizontal') ? 0 : opts.thumbnails.maxWidth; 9242 height = (path == 'horizontal') ? opts.thumbnails.maxHeight : 0; 9243 dims = iL.getNewDimenstions(width, height, data.naturalWidth, data.naturalHeight, true); 9244 9245 t.css({ 9246 width: dims.width, 9247 height: dims.height 9248 }); 9249 if (path == 'horizontal') t.css({ 9250 'float': 'left' 9251 }); 9252 9253 (path == 'horizontal') ? ( 9254 gridWidth += t.outerWidth() 9255 ) : ( 9256 gridHeight += t.outerHeight() 9257 ); 9258 }); 9259 9260 gridCss = { 9261 width: gridWidth, 9262 height: gridHeight 9263 }; 9264 9265 grid.css(gridCss); 9266 9267 gridCss = {}; 9268 9269 var gridOffset = grid.offset(), 9270 activeOffset = (active.length) ? active.offset() : { 9271 top: parseInt(heightAvail / 2), 9272 left: parseInt(widthAvail / 2) 9273 }; 9274 9275 gridOffset.top = (gridOffset.top - $doc.scrollTop()), 9276 gridOffset.left = (gridOffset.left - $doc.scrollLeft()), 9277 activeOffset.top = (activeOffset.top - gridOffset.top - $doc.scrollTop()), 9278 activeOffset.left = (activeOffset.left - gridOffset.left - $doc.scrollLeft()); 9279 9280 (path == 'horizontal') ? ( 9281 gridCss.top = 0, 9282 gridCss.left = parseInt((widthAvail / 2) - activeOffset.left - (active.outerWidth() / 2)) 9283 ) : ( 9284 gridCss.top = parseInt(((heightAvail / 2) - activeOffset.top - (active.outerHeight() / 2))), 9285 gridCss.left = 0 9286 ); 9287 9288 if (arguments.length < 3) grid.stop().animate(gridCss, opts.effects.repositionSpeed, 'easeOutCirc'); 9289 else grid.css(gridCss); 9290 }, 9291 9292 loadImage: function(image, callback) { 9293 if (!$.isArray(image)) image = [image]; 9294 9295 var iL = this, 9296 length = image.length; 9297 9298 if (length > 0) { 9299 iL.showLoader(); 9300 $.each(image, function(index, value) { 9301 var img = new Image(); 9302 img.onload = function() { 9303 length -= 1; 9304 if (length == 0) { 9305 iL.hideLoader(); 9306 callback(img); 9307 } 9308 }; 9309 img.onerror = img.onabort = function() { 9310 length -= 1; 9311 if (length == 0) { 9312 iL.hideLoader(); 9313 callback(false); 9314 } 9315 }; 9316 img.src = image[index]; 9317 }); 9318 } else callback(false); 9319 }, 9320 9321 patchItemsEvents: function() { 9322 var iL = this, 9323 vars = iL.vars, 9324 clickEvent = ishybrid ? "itap.iL click.iL" : supportTouch ? "itap.iL" : "click.iL", 9325 vEvent = ishybrid ? "click.iL itap.iL" : supportTouch ? "click.iL" : "itap.iL"; 9326 9327 if (iL.context && iL.selector) { 9328 var $items = $(iL.selector, iL.context); 9329 9330 $(iL.context).on(clickEvent, iL.selector, function() { 9331 var $this = $(this), 9332 //UNCODE addition 9333 key = typeof $(this).data('lb-index') !== '' && $(this).closest('.owl-item').length ? $(this).data('lb-index') : $items.index($this); 9334 if (UNCODE.isMobile) { 9335 var isCarousel = $this.closest('.owl-carousel'); 9336 if (isCarousel.length) { 9337 if (isCarousel.hasClass('owl-translating')) return false; 9338 } 9339 } 9340 9341 vars.current = key; 9342 vars.next = iL.items[key + 1] ? key + 1 : null; 9343 vars.prev = iL.items[key - 1] ? key - 1 : null; 9344 9345 //UNCODE addition 9346 if ( vars.BODY.hasClass('fp-slide-scrolling') ) 9347 return false;
9348 9349 iL.addContents(); 9350 iL.patchEvents(); 9351 9352 return false; 9353 }).on(vEvent, iL.selector, function() { 9354 return false; 9355 }); 9356 } else 9357 $.each(iL.itemsObject, function(key, val) { 9358 val.on(clickEvent, function() { 9359 vars.current = key; 9360 vars.next = iL.items[key + 1] ? key + 1 : null; 9361 vars.prev = iL.items[key - 1] ? key - 1 : null; 9362 9363 iL.addContents(); 9364 iL.patchEvents(); 9365 9366 return false; 9367 }).on(vEvent, function() { 9368 return false; 9369 }); 9370 }); 9371 }, 9372 9373 dispatchItemsEvents: function() { 9374 var iL = this, 9375 vars = iL.vars, 9376 opts = iL.options; 9377 9378 if (iL.context && iL.selector) 9379 $(iL.context).off('.iL', iL.selector); 9380 else 9381 $.each(iL.itemsObject, function(key, val) { 9382 val.off('.iL'); 9383 }); 9384 }, 9385 9386 refresh: function() { 9387 var iL = this; 9388 9389 iL.dispatchItemsEvents(); 9390 iL.attachItems(); 9391 iL.normalizeItems(); 9392 iL.patchItemsEvents(); 9393 }, 9394 9395 patchEvents: function() { 9396 var iL = this, 9397 vars = iL.vars, 9398 opts = iL.options, 9399 path = opts.path.toLowerCase(), 9400 holders = $('.ilightbox-holder'), 9401 fullscreenEvent = fullScreenApi.fullScreenEventName + '.iLightBox', 9402 durationThreshold = 1000, 9403 horizontalDistanceThreshold = 9404 verticalDistanceThreshold = 100, 9405 buttonsArray = [vars.nextButton[0], vars.prevButton[0], vars.nextButton[0].firstChild, vars.prevButton[0].firstChild]; 9406 9407 $win.bind('resize.iLightBox', function() { 9408 var viewport = getViewport(); 9409 9410 if (opts.mobileOptimizer && !opts.innerToolbar) vars.isMobile = viewport.width <= vars.mobileMaxWidth; 9411 vars.BODY[vars.isMobile ? 'addClass' : 'removeClass']('isMobile'); 9412 9413 iL.repositionPhoto(null); 9414 if (supportTouch) { 9415 clearTimeout(vars.setTime); 9416 vars.setTime = setTimeout(function() { 9417 var scrollTop = getScrollXY().y; 9418 window.scrollTo(0, scrollTop - 30); 9419 window.scrollTo(0, scrollTop + 30); 9420 window.scrollTo(0, scrollTop); 9421 }, 2000); 9422 } 9423 if (vars.thumbs) iL.positionThumbnails(); 9424 }).bind('keydown.iLightBox', function(event) { 9425 if (opts.controls.keyboard) { 9426 switch (event.keyCode) { 9427 case 13: 9428 if (event.shiftKey && opts.keyboard.shift_enter) iL.fullScreenAction(); 9429 break; 9430 case 27: 9431 if (opts.keyboard.esc) iL.closeAction(); 9432 break; 9433 case 37: 9434 if (opts.keyboard.left && !vars.lockKey) iL.moveTo('prev'); 9435 break; 9436 case 38: 9437 if (opts.keyboard.up && !vars.lockKey) iL.moveTo('prev'); 9438 break; 9439 case 39: 9440 if (opts.keyboard.right && !vars.lockKey) iL.moveTo('next'); 9441 break; 9442 case 40: 9443 if (opts.keyboard.down && !vars.lockKey) iL.moveTo('next'); 9444 break; 9445 } 9446 } 9447 }); 9448 9449 if (fullScreenApi.supportsFullScreen) $win.bind(fullscreenEvent, function() { 9450 iL.doFullscreen(); 9451 }); 9452 9453 var holderEventsArr = [opts.caption.show + '.iLightBox', opts.caption.hide + '.iLightBox', opts.social.show + '.iLightBox', opts.social.hide + '.iLightBox'].filter(function(e, i, arr) { 9454 return arr.lastIndexOf(e) === i; 9455 }), 9456 holderEvents = ""; 9457 9458 $.each(holderEventsArr, function(key, val) { 9459 if (key != 0) holderEvents += ' '; 9460 holderEvents += val; 9461 }); 9462 9463 $doc.on(clickEvent, '.ilightbox-overlay', function() { 9464 if (opts.overlay.blur) iL.closeAction(); 9465 }).on(clickEvent, '.ilightbox-next, .ilightbox-next-button', function() { 9466 iL.moveTo('next'); 9467 }).on(clickEvent, '.ilightbox-prev, .ilightbox-prev-button', function() { 9468 iL.moveTo('prev'); 9469 }).on(clickEvent, '.ilightbox-thumbnail', function() { 9470 var t = $(this), 9471 thumbs = $('.ilightbox-thumbnail', vars.thumbnails), 9472 index = thumbs.index(t); 9473 9474 if (index != vars.current) iL.goTo(index); 9475 }).on(holderEvents, '.ilightbox-holder:not(.ilightbox-next, .ilightbox-prev)', function(e) { 9476 var caption = $('div.ilightbox-caption', vars.holder), 9477 social = $('div.ilightbox-social', vars.holder), 9478 fadeSpeed = opts.effects.fadeSpeed; 9479 9480 if (vars.nextLock || vars.prevLock) { 9481 if (e.type == opts.caption.show && !caption.is(':visible')) caption.fadeIn(fadeSpeed); 9482 else if (e.type == opts.caption.hide && caption.is(':visible')) caption.fadeOut(fadeSpeed); 9483 9484 if (e.type == opts.social.show && !social.is(':visible')) social.fadeIn(fadeSpeed); 9485 else if (e.type == opts.social.hide && social.is(':visible')) social.fadeOut(fadeSpeed); 9486 } else { 9487 if (e.type == opts.caption.show && !caption.is(':visible')) caption.stop().fadeIn(fadeSpeed); 9488 else if (e.type == opts.caption.hide && caption.is(':visible')) caption.stop().fadeOut(fadeSpeed); 9489 9490 if (e.type == opts.social.show && !social.is(':visible')) social.stop().fadeIn(fadeSpeed); 9491 else if (e.type == opts.social.hide && social.is(':visible')) social.stop().fadeOut(fadeSpeed); 9492 } 9493 }).on('mouseenter.iLightBox mouseleave.iLightBox', '.ilightbox-wrapper', function(e) { 9494 if (e.type == 'mouseenter') vars.lockWheel = true; 9495 else vars.lockWheel = false;
9496 }).on(clickEvent, '.ilightbox-toolbar a.ilightbox-close, .ilightbox-toolbar a.ilightbox-fullscreen, .ilightbox-toolbar a.ilightbox-play, .ilightbox-toolbar a.ilightbox-pause', function() { 9497 var t = $(this); 9498 9499 if (t.hasClass('ilightbox-fullscreen')) iL.fullScreenAction(); 9500 else if (t.hasClass('ilightbox-play')) { 9501 iL.resume(); 9502 t.addClass('ilightbox-pause').removeClass('ilightbox-play'); 9503 } else if (t.hasClass('ilightbox-pause')) { 9504 iL.pause(); 9505 t.addClass('ilightbox-play').removeClass('ilightbox-pause'); 9506 } else iL.closeAction(); 9507 }).on(touchMoveEvent, '.ilightbox-overlay, .ilightbox-thumbnails-container', function(e) { 9508 // prevent scrolling 9509 e.preventDefault(); 9510 }); 9511 9512 function mouseMoveHandler(e) { 9513 if (!vars.isMobile) { 9514 if (!vars.mouseID) { 9515 vars.hideableElements.show(); 9516 } 9517 9518 vars.mouseID = clearTimeout(vars.mouseID); 9519 9520 if (buttonsArray.indexOf(e.target) === -1) 9521 vars.mouseID = setTimeout(function() { 9522 vars.hideableElements.hide(); 9523 vars.mouseID = clearTimeout(vars.mouseID); 9524 }, 3000); 9525 } 9526 } 9527 9528 if (opts.controls.arrows && !supportTouch) $doc.on('mousemove.iLightBox', mouseMoveHandler); 9529 9530 if (opts.controls.slideshow && opts.slideshow.pauseOnHover) $doc.on('mouseenter.iLightBox mouseleave.iLightBox', '.ilightbox-holder:not(.ilightbox-next, .ilightbox-prev)', function(e) { 9531 if (e.type == 'mouseenter' && vars.cycleID) iL.pause(); 9532 else if (e.type == 'mouseleave' && vars.isPaused) iL.resume(); 9533 }); 9534 9535 var switchers = $('.ilightbox-overlay, .ilightbox-holder, .ilightbox-thumbnails'); 9536 9537 if (opts.controls.mousewheel) switchers.on('mousewheel.iLightBox', function(event, delta) { 9538 if (!vars.lockWheel) { 9539 event.preventDefault(); 9540 if (delta < 0) iL.moveTo('next'); 9541 else if (delta > 0) iL.moveTo('prev'); 9542 } 9543 }); 9544 9545 if (opts.controls.swipe) holders.on(touchStartEvent, function(event) { 9546 if (vars.nextLock || vars.prevLock || vars.total == 1 || vars.lockSwipe) return; 9547 9548 vars.BODY.addClass('ilightbox-closedhand'); 9549 9550 var data = event.originalEvent.touches ? event.originalEvent.touches[0] : event, 9551 scrollTop = $doc.scrollTop(), 9552 scrollLeft = $doc.scrollLeft(), 9553 offsets = [ 9554 holders.eq(0).offset(), 9555 holders.eq(1).offset(), 9556 holders.eq(2).offset() 9557 ], 9558 offSet = [{ 9559 top: offsets[0].top - scrollTop, 9560 left: offsets[0].left - scrollLeft 9561 }, { 9562 top: offsets[1].top - scrollTop, 9563 left: offsets[1].left - scrollLeft 9564 }, { 9565 top: offsets[2].top - scrollTop, 9566 left: offsets[2].left - scrollLeft 9567 }], 9568 start = { 9569 time: (new Date()).getTime(), 9570 coords: [data.pageX - scrollLeft, data.pageY - scrollTop] 9571 }, 9572 stop; 9573 9574 function moveEachHandler(i) { 9575 var t = $(this), 9576 offset = offSet[i], 9577 scroll = [(start.coords[0] - stop.coords[0]), (start.coords[1] - stop.coords[1])]; 9578 9579 t[0].style[path == "horizontal" ? 'left' : 'top'] = (path == "horizontal" ? offset.left - scroll[0] : offset.top - scroll[1]) + 'px'; 9580 } 9581 9582 function moveHandler(event) { 9583 9584 if (!start) return; 9585 9586 var data = event.originalEvent.touches ? event.originalEvent.touches[0] : event; 9587 9588 stop = { 9589 time: (new Date()).getTime(), 9590 coords: [data.pageX - scrollLeft, data.pageY - scrollTop] 9591 }; 9592 9593 holders.each(moveEachHandler); 9594 9595 // prevent scrolling 9596 event.preventDefault(); 9597 } 9598 9599 function repositionHolders() { 9600 holders.each(function() { 9601 var t = $(this), 9602 offset = t.data('offset') || { 9603 top: t.offset().top - scrollTop, 9604 left: t.offset().left - scrollLeft 9605 }, 9606 top = offset.top, 9607 left = offset.left; 9608 9609 t.css(transform, gpuAcceleration).stop().animate({ 9610 top: top, 9611 left: left 9612 }, 500, 'easeOutCirc', function() { 9613 t.css(transform, ''); 9614 }); 9615 }); 9616 } 9617 9618 holders.bind(touchMoveEvent, moveHandler); 9619 $doc.one(touchStopEvent, function(event) { 9620 holders.unbind(touchMoveEvent, moveHandler); 9621 9622 vars.BODY.removeClass('ilightbox-closedhand'); 9623 9624 if (start && stop) { 9625 if (path == "horizontal" && stop.time - start.time < durationThreshold && abs(start.coords[0] - stop.coords[0]) > horizontalDistanceThreshold && abs(start.coords[1] - stop.coords[1]) < verticalDistanceThreshold) { 9626 if (start.coords[0] > stop.coords[0]) { 9627 if (vars.current == vars.total - 1 && !opts.infinite) repositionHolders(); 9628 else { 9629 vars.isSwipe = true; 9630 iL.moveTo('next'); 9631 } 9632 } else { 9633 if (vars.current == 0 && !opts.infinite) repositionHolders(); 9634 else { 9635 vars.isSwipe = true; 9636 iL.moveTo('prev'); 9637 } 9638 } 9639 } else if (path == "vertical" && stop.time - start.time < durationThreshold && abs(start.coords[1] - stop.coords[1]) > horizontalDistanceThreshold && abs(start.coords[0] - stop.coords[0]) < verticalDistanceThreshold) { 9640 if (start.coords[1] > stop.coords[1]) { 9641 if (vars.current == vars.total - 1 && !opts.infinite) repositionHolders(); 9642 else { 9643 vars.isSwipe = true; 9644 iL.moveTo('next'); 9645 } 9646 } else { 9647 if (vars.current == 0 && !opts.infinite) repositionHolders(); 9648 else { 9649 vars.isSwipe = true; 9650 iL.moveTo('prev'); 9651 } 9652 } 9653 } else repositionHolders(); 9654 } 9655 start = stop = undefined; 9656 }); 9657 }); 9658 9659 }, 9660 9661 goTo: function(index) { 9662 var iL = this, 9663 vars = iL.vars, 9664 opts = iL.options, 9665 diff = (index - vars.current); 9666 9667 if (opts.infinite) { 9668 if (index == vars.total - 1 && vars.current == 0) diff = -1; 9669 if (vars.current == vars.total - 1 && index == 0) diff = 1; 9670 } 9671 9672 if (diff == 1) iL.moveTo('next'); 9673 else if (diff == -1) iL.moveTo('prev'); 9674 else { 9675 9676 if (vars.nextLock || vars.prevLock) return false;
9677 9678 //Trigger the onBeforeChange callback 9679 if (typeof opts.callback.onBeforeChange == 'function') opts.callback.onBeforeChange.call(iL, iL.ui); 9680 9681 if (opts.linkId) { 9682 vars.hashLock = true; 9683 window.location.hash = opts.linkId + '/' + index; 9684 } 9685 9686 if (iL.items[index]) { 9687 if (!iL.items[index].options.mousewheel) vars.lockWheel = true; 9688 else iL.vars.lockWheel = false; 9689 9690 if (!iL.items[index].options.swipe) vars.lockSwipe = true; 9691 else vars.lockSwipe = false; 9692 } 9693 9694 $.each([vars.holder, vars.nextPhoto, vars.prevPhoto], function(key, val) { 9695 val.css(transform, gpuAcceleration).fadeOut(opts.effects.loadedFadeSpeed); 9696 }); 9697 9698 vars.current = index; 9699 vars.next = index + 1; 9700 vars.prev = index - 1; 9701 9702 iL.createUI(); 9703 9704 setTimeout(function() { 9705 iL.generateBoxes(); 9706 }, opts.effects.loadedFadeSpeed + 50); 9707 9708 $('.ilightbox-thumbnail', vars.thumbnails).removeClass('ilightbox-active').eq(index).addClass('ilightbox-active'); 9709 iL.positionThumbnails(); 9710 9711 if (opts.linkId) setTimeout(function() { 9712 vars.hashLock = false; 9713 }, 55); 9714 9715 // Configure arrow buttons 9716 if (!opts.infinite) { 9717 vars.nextButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled'); 9718 9719 if (vars.current == 0) { 9720 vars.prevButton.add(vars.innerPrevButton).addClass('disabled'); 9721 } 9722 if (vars.current >= vars.total - 1) { 9723 vars.nextButton.add(vars.innerNextButton).addClass('disabled'); 9724 } 9725 } 9726 9727 // Reset next cycle timeout 9728 iL.resetCycle(); 9729 9730 //Trigger the onAfterChange callback 9731 if (typeof opts.callback.onAfterChange == 'function') opts.callback.onAfterChange.call(iL, iL.ui); 9732 } 9733 }, 9734 9735 moveTo: function(side) { 9736 var iL = this, 9737 vars = iL.vars, 9738 opts = iL.options, 9739 path = opts.path.toLowerCase(), 9740 viewport = getViewport(), 9741 switchSpeed = opts.effects.switchSpeed; 9742 9743 if (vars.nextLock || vars.prevLock) return false; 9744 else { 9745 9746 var item = (side == "next") ? vars.next : vars.prev; 9747 9748 if (opts.linkId) { 9749 vars.hashLock = true; 9750 window.location.hash = opts.linkId + '/' + item; 9751 } 9752 9753 if (side == "next") { 9754 if (!iL.items[item]) return false; 9755 var firstHolder = vars.nextPhoto, 9756 secondHolder = vars.holder, 9757 lastHolder = vars.prevPhoto, 9758 firstClass = 'ilightbox-prev', 9759 secondClass = 'ilightbox-next'; 9760 } else if (side == "prev") { 9761 if (!iL.items[item]) return false; 9762 var firstHolder = vars.prevPhoto, 9763 secondHolder = vars.holder, 9764 lastHolder = vars.nextPhoto, 9765 firstClass = 'ilightbox-next', 9766 secondClass = 'ilightbox-prev'; 9767 } 9768 9769 //Trigger the onBeforeChange callback 9770 if (typeof opts.callback.onBeforeChange == 'function') 9771 opts.callback.onBeforeChange.call(iL, iL.ui); 9772 9773 (side == "next") ? vars.nextLock = true: vars.prevLock = true; 9774 9775 var captionFirst = $('div.ilightbox-caption', secondHolder), 9776 socialFirst = $('div.ilightbox-social', secondHolder); 9777 9778 if (captionFirst.length) 9779 captionFirst.stop().fadeOut(switchSpeed, function() { 9780 $(this).remove(); 9781 }); 9782 if (socialFirst.length) 9783 socialFirst.stop().fadeOut(switchSpeed, function() { 9784 $(this).remove(); 9785 }); 9786 9787 if (iL.items[item].caption) { 9788 iL.setCaption(iL.items[item], firstHolder); 9789 var caption = $('div.ilightbox-caption', firstHolder), 9790 percent = parseInt((caption.outerHeight() / firstHolder.outerHeight()) * 100); 9791 if (opts.caption.start && percent <= 50) caption.fadeIn(switchSpeed); 9792 } 9793 9794 var social = iL.items[item].options.social; 9795 if (social) { 9796 iL.setSocial(social, iL.items[item].URL, firstHolder); 9797 if (opts.social.start) $('div.ilightbox-social', firstHolder).fadeIn(opts.effects.fadeSpeed); 9798 } 9799 9800 $.each([firstHolder, secondHolder, lastHolder], function(key, val) { 9801 val.removeClass('ilightbox-next ilightbox-prev'); 9802 }); 9803 9804 var firstOffset = firstHolder.data('offset'), 9805 winW = (viewport.width - (opts.styles.pageOffsetX)), 9806 winH = (viewport.height - (opts.styles.pageOffsetY)), 9807 width = firstOffset.newDims.width, 9808 height = firstOffset.newDims.height, 9809 thumbsOffset = firstOffset.thumbsOffset, 9810 diff = firstOffset.diff, 9811 top = parseInt((winH / 2) - (height / 2) - diff.H - (thumbsOffset.H / 2)), 9812 left = parseInt((winW / 2) - (width / 2) - diff.W - (thumbsOffset.W / 2)); 9813 9814 var secondOffset = secondHolder.data('offset'), 9815 object = secondOffset.object; 9816 9817 /*if (object.item.caption && !isNaN(width) && !isNaN(height) && UNCODE.wwidth > UNCODE.mediaQuery) { 9818 var objRatio = width / height; 9819 height = height - vars.captionHeight; 9820 width = height * objRatio; 9821 top = path == 'horizontal' ? parseInt((winH / 2) - (height / 2) - diff.H - (thumbsOffset.H / 2)) : top, 9822 left = parseInt((winW / 2) - (width / 2) - diff.W - (thumbsOffset.W / 2)); 9823 }*/ 9824 9825 firstHolder.show().css(transform, gpuAcceleration).animate({ 9826 top: top, 9827 left: left, 9828 opacity: 1 9829 }, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc', function() { 9830 firstHolder.css(transform, ''); 9831 }); 9832 9833 $('div.ilightbox-container', firstHolder).animate({ 9834 width: width, 9835 height: height 9836 }, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc'); 9837 9838 diff = secondOffset.diff; 9839 9840 width = secondOffset.newDims.width, 9841 height = secondOffset.newDims.height; 9842 9843 width = parseInt(width * opts.styles[side == 'next' ? 'prevScale' : 'nextScale']), 9844 height = parseInt(height * opts.styles[side == 'next' ? 'prevScale' : 'nextScale']), 9845 top = (path == 'horizontal') ? parseInt((winH / 2) - object.offsetY - (height / 2) - diff.H - (thumbsOffset.H / 2)) : parseInt(winH - object.offsetX - diff.H - (thumbsOffset.H / 2)); 9846 9847 if (side == 'prev') 9848 left = (path == 'horizontal') ? parseInt(winW - object.offsetX - diff.W - (thumbsOffset.W / 2)) : parseInt((winW / 2) - (width / 2) - diff.W - object.offsetY - (thumbsOffset.W / 2)); 9849 else { 9850 top = (path == 'horizontal') ? top : parseInt(object.offsetX - diff.H - height - (thumbsOffset.H / 2)), 9851 left = (path == 'horizontal') ? parseInt(object.offsetX - diff.W - width - (thumbsOffset.W / 2)) : parseInt((winW / 2) - object.offsetY - (width / 2) - diff.W - (thumbsOffset.W / 2)); 9852 } 9853 9854 /*if (object.item.caption && !isNaN(width) && !isNaN(height) && UNCODE.wwidth > UNCODE.mediaQuery) { 9855 var objRatio = width / height; 9856 height = height - vars.captionHeight; 9857 width = height * objRatio; 9858 top = path == 'horizontal' ? parseInt((winH / 2) - (height / 2) - diff.H - (thumbsOffset.H / 2)) : top; 9859 }*/ 9860 9861 $('div.ilightbox-container', secondHolder).animate({ 9862 width: width, 9863 height: height 9864 }, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc'); 9865 9866 secondHolder.addClass(firstClass).css(transform, gpuAcceleration).animate({ 9867 top: top, 9868 left: left, 9869 opacity: opts.styles.prevOpacity, 9870 }, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc', function() { 9871 secondHolder.css(transform, ''); 9872
9873 $('.ilightbox-thumbnail', vars.thumbnails).removeClass('ilightbox-active').eq(item).addClass('ilightbox-active'); 9874 iL.positionThumbnails(); 9875 9876 if (iL.items[item]) { 9877 if (!iL.items[item].options.mousewheel) vars.lockWheel = true; 9878 else vars.lockWheel = false; 9879 9880 if (!iL.items[item].options.swipe) vars.lockSwipe = true; 9881 else vars.lockSwipe = false; 9882 } 9883 9884 vars.isSwipe = false; 9885 9886 // Remove iframe & video from previous slide 9887 if (['iframe', 'video'].indexOf(iL.items[vars.current].type) !== -1) { 9888 $('div.ilightbox-container', secondHolder).empty(); 9889 } 9890 9891 if (side == "next") { 9892 vars.nextPhoto = lastHolder, 9893 vars.prevPhoto = secondHolder, 9894 vars.holder = firstHolder; 9895 9896 vars.nextPhoto.hide(); 9897 9898 vars.next = vars.next + 1, 9899 vars.prev = vars.current, 9900 vars.current = vars.current + 1; 9901 9902 if (opts.infinite) { 9903 if (vars.current > vars.total - 1) vars.current = 0; 9904 if (vars.current == vars.total - 1) vars.next = 0; 9905 if (vars.current == 0) vars.prev = vars.total - 1; 9906 } 9907 9908 iL.createUI(); 9909 9910 if (!iL.items[vars.next]) 9911 vars.nextLock = false; 9912 else 9913 iL.loadContent(iL.items[vars.next], 'next'); 9914 } else { 9915 vars.prevPhoto = lastHolder; 9916 vars.nextPhoto = secondHolder; 9917 vars.holder = firstHolder; 9918 9919 vars.prevPhoto.hide(); 9920 9921 vars.next = vars.current; 9922 vars.current = vars.prev; 9923 vars.prev = vars.current - 1; 9924 9925 if (opts.infinite) { 9926 if (vars.current == vars.total - 1) vars.next = 0; 9927 if (vars.current == 0) vars.prev = vars.total - 1; 9928 } 9929 9930 iL.createUI(); 9931 9932 if (!iL.items[vars.prev]) 9933 vars.prevLock = false; 9934 else 9935 iL.loadContent(iL.items[vars.prev], 'prev'); 9936 } 9937 9938 // Add iframe & video content for current slide 9939 if (['iframe', 'video'].indexOf(iL.items[vars.current].type) !== -1) { 9940 iL.loadContent(iL.items[vars.current], 'current'); 9941 } 9942 9943 if (opts.linkId) setTimeout(function() { 9944 vars.hashLock = false; 9945 }, 55); 9946 9947 // Configure arrow buttons 9948 if (!opts.infinite) { 9949 vars.nextButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled'); 9950 9951 if (vars.current == 0) 9952 vars.prevButton.add(vars.innerPrevButton).addClass('disabled'); 9953 if (vars.current >= vars.total - 1) 9954 vars.nextButton.add(vars.innerNextButton).addClass('disabled'); 9955 } 9956 9957 iL.repositionPhoto(); 9958 9959 // Reset next cycle timeout 9960 iL.resetCycle(); 9961 9962 //Trigger the onAfterChange callback 9963 if (typeof opts.callback.onAfterChange == 'function') 9964 opts.callback.onAfterChange.call(iL, iL.ui); 9965 }); 9966 9967 top = (path == 'horizontal') ? getPixel(lastHolder, 'top') : ((side == "next") ? parseInt(-(winH / 2) - lastHolder.outerHeight()) : parseInt(top * 2)), 9968 left = (path == 'horizontal') ? ((side == "next") ? parseInt(-(winW / 2) - lastHolder.outerWidth()) : parseInt(left * 2)) : getPixel(lastHolder, 'left'); 9969 9970 lastHolder.css(transform, gpuAcceleration).animate({ 9971 top: top, 9972 left: left, 9973 opacity: opts.styles.nextOpacity 9974 }, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc', function() { 9975 lastHolder.css(transform, ''); 9976 }).addClass(secondClass); 9977 } 9978 }, 9979 9980 setCaption: function(obj, target) { 9981 var iL = this, 9982 caption = $('<div class="ilightbox-caption"></div>'); 9983 9984 if (obj.caption) { 9985 caption.html(obj.caption); 9986 $('div.ilightbox-container', target).append(caption); 9987 } 9988 }, 9989 9990 normalizeSocial: function(obj, url) { 9991 var iL = this, 9992 vars = iL.vars, 9993 opts = iL.options, 9994 baseURL = window.location.href; 9995 9996 $.each(obj, function(key, value) { 9997 if (!value) 9998 return true; 9999 10000 var item = key.toLowerCase(), 10001 source, text; 10002 10003 switch (item) { 10004 case 'facebook': 10005 source = "http://www.facebook.com/share.php?v=4&src=bm&u={URL}", 10006 text = "Share on Facebook"; 10007 break; 10008 case 'twitter': 10009 source = "http://twitter.com/home?status={URL}", 10010 text = "Share on Twitter"; 10011 break; 10012 case 'googleplus': 10013 source = "https://plus.google.com/share?url={URL}", 10014 text = "Share on Google+"; 10015 break; 10016 case 'delicious': 10017 source = "http://delicious.com/post?url={URL}", 10018 text = "Share on Delicious"; 10019 break; 10020 case 'digg': 10021 source = "http://digg.com/submit?phase=2&url={URL}", 10022 text = "Share on Digg"; 10023 break; 10024 case 'reddit': 10025 source = "http://reddit.com/submit?url={URL}", 10026 text = "Share on reddit"; 10027 break; 10028 } 10029 10030 obj[key] = { 10031 URL: value.URL && absolutizeURI(baseURL, value.URL) || opts.linkId && window.location.href || typeof url !== 'string' && baseURL || url && absolutizeURI(baseURL, url) || baseURL, 10032 source: value.source || source || value.URL && absolutizeURI(baseURL, value.URL) || url && absolutizeURI(baseURL, url), 10033 text: value.text || text || "Share on " + key, 10034 width: (typeof(value.width) != 'undefined' && !isNaN(value.width)) ? parseInt(value.width) : 640, 10035 height: value.height || 360 10036 }; 10037 10038 }); 10039 10040 return obj; 10041 }, 10042 10043 setSocial: function(obj, url, target) { 10044 var iL = this, 10045 socialBar = $('<div class="ilightbox-social"></div>'), 10046 buttons = '<ul>'; 10047 10048 obj = iL.normalizeSocial(obj, url); 10049 10050 $.each(obj, function(key, value) { 10051 var item = key.toLowerCase(), 10052 source = value.source.replace(/\{URL\}/g, encodeURIComponent(value.URL).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28').replace(/\)/g, '%29').replace(/\*/g, '%2A').replace(/%20/g, '+')); 10053 buttons += '<li class="' + key + '"><a href="' + source + '" onclick="javascript:window.open(this.href' + ((value.width <= 0 || value.height <= 0) ? '' : ', \'\', \'menubar=no,toolbar=no,resizable=yes,scrollbars=yes,height=' + value.height + ',width=' + value.width + ',left=40,top=40\'') + ');return false;" title="' + value.text + '" target="_blank"></a></li>'; 10054 }); 10055 10056 buttons += '</ul>'; 10057 10058 socialBar.html(buttons); 10059 $('div.ilightbox-container', target).append(socialBar); 10060 }, 10061 10062 fullScreenAction: function() { 10063 var iL = this, 10064 vars = iL.vars; 10065 10066 if (fullScreenApi.supportsFullScreen) { 10067 if (fullScreenApi.isFullScreen()) fullScreenApi.cancelFullScreen(document.documentElement); 10068 else fullScreenApi.requestFullScreen(document.documentElement); 10069 } else { 10070 iL.doFullscreen(); 10071 } 10072 }, 10073 10074 doFullscreen: function() { 10075 var iL = this, 10076 vars = iL.vars, 10077 viewport = getViewport(), 10078 opts = iL.options; 10079 10080 if (opts.fullAlone) { 10081 var currentHolder = vars.holder, 10082 current = iL.items[vars.current], 10083 windowWidth = viewport.width, 10084 windowHeight = viewport.height, 10085 elements = [currentHolder, vars.nextPhoto, vars.prevPhoto, vars.nextButton, vars.prevButton, vars.overlay, vars.toolbar, vars.thumbnails, vars.loader], 10086 hideElements = [vars.nextPhoto, vars.prevPhoto, vars.nextButton, vars.prevButton, vars.loader, vars.thumbnails]; 10087 10088 if (!vars.isInFullScreen) { 10089 vars.isInFullScreen = vars.lockKey = vars.lockWheel = vars.lockSwipe = true; 10090 vars.overlay.css({ 10091 opacity: 1 10092 }); 10093 10094 $.each(hideElements, function(i, element) { 10095 element.hide(); 10096 }); 10097 10098 vars.fullScreenButton.attr('title', opts.text.exitFullscreen); 10099 10100 if (opts.fullStretchTypes.indexOf(current.type) != -1) currentHolder.data({
10101 naturalWidthOld: currentHolder.data('naturalWidth'), 10102 naturalHeightOld: currentHolder.data('naturalHeight'), 10103 naturalWidth: windowWidth, 10104 naturalHeight: windowHeight 10105 }); 10106 else { 10107 var viewport = current.options.fullViewPort || opts.fullViewPort || '', 10108 newWidth = windowWidth, 10109 newHeight = windowHeight, 10110 width = currentHolder.data('naturalWidth'), 10111 height = currentHolder.data('naturalHeight'); 10112 10113 if (viewport.toLowerCase() == 'fill') { 10114 newHeight = (newWidth / width) * height; 10115 10116 if (newHeight < windowHeight) { 10117 newWidth = (windowHeight / height) * width, 10118 newHeight = windowHeight; 10119 } 10120 } else if (viewport.toLowerCase() == 'fit') { 10121 var dims = iL.getNewDimenstions(newWidth, newHeight, width, height, true); 10122 10123 newWidth = dims.width, 10124 newHeight = dims.height; 10125 } else if (viewport.toLowerCase() == 'stretch') { 10126 newWidth = newWidth, 10127 newHeight = newHeight; 10128 } else { 10129 var scale = (width > newWidth || height > newHeight) ? true : false, 10130 dims = iL.getNewDimenstions(newWidth, newHeight, width, height, scale); 10131 newWidth = dims.width, 10132 newHeight = dims.height; 10133 } 10134 10135 currentHolder.data({ 10136 naturalWidthOld: currentHolder.data('naturalWidth'), 10137 naturalHeightOld: currentHolder.data('naturalHeight'), 10138 naturalWidth: newWidth, 10139 naturalHeight: newHeight 10140 }); 10141 } 10142 10143 $.each(elements, function(key, val) { 10144 val.addClass('ilightbox-fullscreen'); 10145 }); 10146 10147 //Trigger the onEnterFullScreen callback 10148 if (typeof opts.callback.onEnterFullScreen == 'function') opts.callback.onEnterFullScreen.call(iL, iL.ui); 10149 } else { 10150 vars.isInFullScreen = vars.lockKey = vars.lockWheel = vars.lockSwipe = false; 10151 vars.overlay.css({ 10152 opacity: iL.options.overlay.opacity 10153 }); 10154 10155 $.each(hideElements, function(i, element) { 10156 element.show(); 10157 }); 10158 10159 vars.fullScreenButton.attr('title', opts.text.enterFullscreen); 10160 10161 currentHolder.data({ 10162 naturalWidth: currentHolder.data('naturalWidthOld'), 10163 naturalHeight: currentHolder.data('naturalHeightOld'), 10164 naturalWidthOld: null, 10165 naturalHeightOld: null 10166 }); 10167 10168 $.each(elements, function(key, val) { 10169 val.removeClass('ilightbox-fullscreen'); 10170 }); 10171 10172 //Trigger the onExitFullScreen callback 10173 if (typeof opts.callback.onExitFullScreen == 'function') opts.callback.onExitFullScreen.call(iL, iL.ui); 10174 } 10175 } else { 10176 if (!vars.isInFullScreen) vars.isInFullScreen = true; 10177 else vars.isInFullScreen = false; 10178 } 10179 iL.repositionPhoto(true); 10180 }, 10181 10182 closeAction: function() { 10183 var iL = this, 10184 vars = iL.vars, 10185 opts = iL.options; 10186 10187 $win.unbind('.iLightBox'); 10188 $doc.off('.iLightBox'); 10189 10190 if (vars.isInFullScreen) fullScreenApi.cancelFullScreen(document.documentElement); 10191 10192 $('.ilightbox-overlay, .ilightbox-holder, .ilightbox-thumbnails').off('.iLightBox'); 10193 10194 if (opts.hide.effect) vars.overlay.stop().fadeOut(opts.hide.speed, function() { 10195 vars.overlay.remove(); 10196 vars.BODY.removeClass('ilightbox-noscroll').off('.iLightBox'); 10197 }); 10198 else { 10199 vars.overlay.remove(); 10200 vars.BODY.removeClass('ilightbox-noscroll').off('.iLightBox'); 10201 } 10202 10203 var fadeOuts = [vars.toolbar, vars.holder, vars.nextPhoto, vars.prevPhoto, vars.nextButton, vars.prevButton, vars.loader, vars.thumbnails]; 10204 10205 $.each(fadeOuts, function(i, element) { 10206 element.removeAttr('style').remove(); 10207 }); 10208 10209 vars.dontGenerateThumbs = vars.isInFullScreen = false; 10210 10211 window.iLightBox = null; 10212 10213 if (opts.linkId) { 10214 vars.hashLock = true; 10215 removeHash(); 10216 setTimeout(function() { 10217 vars.hashLock = false; 10218 }, 55); 10219 } 10220 10221 vars.nextButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled'); 10222 10223 //Trigger the onHide callback 10224 if (typeof opts.callback.onHide == 'function') opts.callback.onHide.call(iL, iL.ui); 10225 }, 10226 10227 repositionPhoto: function() { 10228 var iL = this, 10229 vars = iL.vars, 10230 opts = iL.options, 10231 path = opts.path.toLowerCase(), 10232 viewport = getViewport(), 10233 winWidth = viewport.width, 10234 winHeight = viewport.height; 10235 10236 if (viewport.width < UNCODE.mediaQuery) opts.styles.nextOffsetX = 0; 10237 10238 var thumbsOffsetW = (vars.isInFullScreen && opts.fullAlone || vars.isMobile) ? 0 : ((path == 'horizontal') ? 0 : vars.thumbnails.outerWidth()), 10239 thumbsOffsetH = vars.isMobile ? vars.toolbar.outerHeight() : ((vars.isInFullScreen && opts.fullAlone) ? 0 : ((path == 'horizontal') ? vars.thumbnails.outerHeight() : 0)), 10240 width = (vars.isInFullScreen && opts.fullAlone) ? winWidth : (winWidth - (opts.styles.pageOffsetX)), 10241 height = (vars.isInFullScreen && opts.fullAlone) ? winHeight : (winHeight - (opts.styles.pageOffsetY)), 10242 offsetW = (path == 'horizontal') ? parseInt((iL.items[vars.next] || iL.items[vars.prev]) ? ((opts.styles.nextOffsetX + opts.styles.prevOffsetX)) * 2 : (((width / 10) <= 30) ? 30 : (width / 10))) : parseInt(((width / 10) <= 30) ? 30 : (width / 10)) + thumbsOffsetW, 10243 offsetH = (path == 'horizontal') ? parseInt(((height / 10) <= 30) ? 30 : (height / 10)) + thumbsOffsetH : parseInt((iL.items[vars.next] || iL.items[vars.prev]) ? ((opts.styles.nextOffsetX + opts.styles.prevOffsetX)) * 2 : (((height / 10) <= 30) ? 30 : (height / 10))); 10244 10245 var elObject = { 10246 type: 'current', 10247 width: width, 10248 height: height, 10249 item: iL.items[vars.current], 10250 offsetW: offsetW, 10251 offsetH: offsetH,
10252 thumbsOffsetW: thumbsOffsetW, 10253 thumbsOffsetH: thumbsOffsetH, 10254 animate: arguments.length, 10255 holder: vars.holder 10256 }; 10257 10258 iL.repositionEl(elObject); 10259 10260 if (iL.items[vars.next]) { 10261 elObject = $.extend(elObject, { 10262 type: 'next', 10263 item: iL.items[vars.next], 10264 offsetX: opts.styles.nextOffsetX, 10265 offsetY: opts.styles.nextOffsetY, 10266 holder: vars.nextPhoto 10267 }); 10268 10269 iL.repositionEl(elObject); 10270 } 10271 10272 if (iL.items[vars.prev]) { 10273 elObject = $.extend(elObject, { 10274 type: 'prev', 10275 item: iL.items[vars.prev], 10276 offsetX: opts.styles.nextOffsetX, 10277 offsetY: opts.styles.prevOffsetY, 10278 holder: vars.prevPhoto 10279 }); 10280 10281 iL.repositionEl(elObject); 10282 } 10283 10284 var loaderCss = (path == "horizontal") ? { 10285 left: parseInt((width / 2) - (vars.loader.outerWidth() / 2)) 10286 } : { 10287 top: parseInt((height / 2) - (vars.loader.outerHeight() / 2)) 10288 }; 10289 vars.loader.css(loaderCss); 10290 }, 10291 10292 repositionEl: function(obj) { 10293 var iL = this, 10294 vars = iL.vars, 10295 opts = iL.options, 10296 path = opts.path.toLowerCase(), 10297 widthAvail = (obj.type == 'current') ? ((vars.isInFullScreen && opts.fullAlone) ? obj.width : (obj.width - obj.offsetW)) : (obj.width - obj.offsetW), 10298 heightAvail = (obj.type == 'current') ? ((vars.isInFullScreen && opts.fullAlone) ? obj.height : (obj.height - obj.offsetH)) : (obj.height - obj.offsetH), 10299 itemParent = obj.item, 10300 item = obj.item.options, 10301 holder = obj.holder, 10302 offsetX = obj.offsetX || 0, 10303 offsetY = obj.offsetY || 0, 10304 thumbsOffsetW = obj.thumbsOffsetW, 10305 thumbsOffsetH = obj.thumbsOffsetH; 10306 10307 if (obj.type == 'current') { 10308 if (typeof item.width == 'number' && item.width) widthAvail = ((vars.isInFullScreen && opts.fullAlone) && (opts.fullStretchTypes.indexOf(itemParent.type) != -1 || item.fullViewPort || opts.fullViewPort)) ? widthAvail : ((item.width > widthAvail) ? widthAvail : item.width); 10309 if (typeof item.height == 'number' && item.height) heightAvail = ((vars.isInFullScreen && opts.fullAlone) && (opts.fullStretchTypes.indexOf(itemParent.type) != -1 || item.fullViewPort || opts.fullViewPort)) ? heightAvail : ((item.height > heightAvail) ? heightAvail : item.height); 10310 } else { 10311 if (typeof item.width == 'number' && item.width) widthAvail = (item.width > widthAvail) ? widthAvail : item.width; 10312 if (typeof item.height == 'number' && item.height) heightAvail = (item.height > heightAvail) ? heightAvail : item.height; 10313 } 10314 10315 heightAvail = parseInt(heightAvail - $('.ilightbox-inner-toolbar', holder).outerHeight()); 10316 10317 var width = (typeof item.width == 'string' && item.width.indexOf('%') != -1) ? percentToValue(parseInt(item.width.replace('%', '')), obj.width) : holder.data('naturalWidth'), 10318 height = (typeof item.height == 'string' && item.height.indexOf('%') != -1) ? percentToValue(parseInt(item.height.replace('%', '')), obj.height) : holder.data('naturalHeight'); 10319 10320 var dims = ((typeof item.width == 'string' && item.width.indexOf('%') != -1 || typeof item.height == 'string' && item.height.indexOf('%') != -1) ? { 10321 width: width, 10322 height: height 10323 } : iL.getNewDimenstions(widthAvail, heightAvail, width, height)), 10324 newDims = $.extend({}, dims, {}); 10325 10326 if (obj.type == 'prev' || obj.type == 'next') 10327 width = parseInt(dims.width * ((obj.type == 'next') ? opts.styles.nextScale : opts.styles.prevScale)), 10328 height = parseInt(dims.height * ((obj.type == 'next') ? opts.styles.nextScale : opts.styles.prevScale)); 10329 else 10330 width = dims.width, 10331 height = dims.height; 10332 10333 var widthDiff = parseInt((getPixel(holder, 'padding-left') + getPixel(holder, 'padding-right') + getPixel(holder, 'border-left-width') + getPixel(holder, 'border-right-width')) / 2), 10334 heightDiff = parseInt((getPixel(holder, 'padding-top') + getPixel(holder, 'padding-bottom') + getPixel(holder, 'border-top-width') + getPixel(holder, 'border-bottom-width') + ($('.ilightbox-inner-toolbar', holder).outerHeight() || 0)) / 2); 10335 10336 switch (obj.type) { 10337 case 'current': 10338 var top = parseInt((obj.height / 2) - (height / 2) - heightDiff - (thumbsOffsetH / 2)), 10339 left = parseInt((obj.width / 2) - (width / 2) - widthDiff - (thumbsOffsetW / 2)); 10340 break; 10341
10342 case 'next': 10343 var top = (path == 'horizontal') ? parseInt((obj.height / 2) - offsetY - (height / 2) - heightDiff - (thumbsOffsetH / 2)) : parseInt(obj.height - offsetX - heightDiff - (thumbsOffsetH / 2)), 10344 left = (path == 'horizontal') ? parseInt(obj.width - offsetX - widthDiff - (thumbsOffsetW / 2)) : parseInt((obj.width / 2) - (width / 2) - widthDiff - offsetY - (thumbsOffsetW / 2)); 10345 break; 10346 10347 case 'prev': 10348 var top = (path == 'horizontal') ? parseInt((obj.height / 2) - offsetY - (height / 2) - heightDiff - (thumbsOffsetH / 2)) : parseInt(offsetX - heightDiff - height - (thumbsOffsetH / 2)), 10349 left = (path == 'horizontal') ? parseInt(offsetX - widthDiff - width - (thumbsOffsetW / 2)) : parseInt((obj.width / 2) - offsetY - (width / 2) - widthDiff - (thumbsOffsetW / 2)); 10350 break; 10351 } 10352 10353 holder.data('offset', { 10354 top: top, 10355 left: left, 10356 newDims: newDims, 10357 diff: { 10358 W: widthDiff, 10359 H: heightDiff 10360 }, 10361 thumbsOffset: { 10362 W: thumbsOffsetW, 10363 H: thumbsOffsetH 10364 }, 10365 object: obj 10366 }); 10367 10368 var opacityMobile; 10369 if ( isMobile ) { 10370 opacityMobile = { 10371 opacity: 1, 10372 top: top, 10373 left: left 10374 }; 10375 } else { 10376 opacityMobile = { 10377 top: top, 10378 left: left 10379 }; 10380 } 10381 10382 if (obj.animate > 0 && opts.effects.reposition) { 10383 holder.css(transform, gpuAcceleration).stop().animate( 10384 opacityMobile, 10385 opts.effects.repositionSpeed, 'easeOutCirc', function() { 10386 holder.css(transform, ''); 10387 }); 10388 $('div.ilightbox-container', holder).stop().animate({ 10389 width: width, 10390 height: height 10391 }, opts.effects.repositionSpeed, 'easeOutCirc'); 10392 $('div.ilightbox-inner-toolbar', holder).stop().animate({ 10393 width: width 10394 }, opts.effects.repositionSpeed, 'easeOutCirc', function() { 10395 $(this).css('overflow', 'visible'); 10396 }); 10397 } else { 10398 holder.css(opacityMobile); 10399 $('div.ilightbox-container', holder).css({ 10400 width: width, 10401 height: height 10402 }); 10403 $('div.ilightbox-inner-toolbar', holder).css({ 10404 width: width 10405 }); 10406 } 10407 }, 10408 10409 10410 resume: function(priority) { 10411 var iL = this, 10412 vars = iL.vars, 10413 opts = iL.options; 10414 10415 if (!opts.slideshow.pauseTime || opts.controls.slideshow && vars.total <= 1 || priority < vars.isPaused) { 10416 return; 10417 } 10418 10419 vars.isPaused = 0; 10420 10421 if (vars.cycleID) { 10422 vars.cycleID = clearTimeout(vars.cycleID); 10423 } 10424 10425 vars.cycleID = setTimeout(function() { 10426 if (vars.current == vars.total - 1) iL.goTo(0); 10427 else iL.moveTo('next'); 10428 }, opts.slideshow.pauseTime); 10429 }, 10430 10431 pause: function(priority) { 10432 var iL = this, 10433 vars = iL.vars, 10434 opts = iL.options; 10435 10436 if (priority < vars.isPaused) { 10437 return; 10438 } 10439 10440 vars.isPaused = priority || 100; 10441 10442 if (vars.cycleID) { 10443 vars.cycleID = clearTimeout(vars.cycleID); 10444 } 10445 }, 10446 10447 resetCycle: function() { 10448 var iL = this, 10449 vars = iL.vars, 10450 opts = iL.options; 10451 10452 if (opts.controls.slideshow && vars.cycleID && !vars.isPaused) { 10453 iL.resume(); 10454 } 10455 }, 10456 10457 getNewDimenstions: function(width, height, width_old, height_old, thumb) { 10458 var iL = this; 10459 10460 if (!width) factor = height / height_old; 10461 else if (!height) factor = width / width_old; 10462 else factor = min(width / width_old, height / height_old); 10463 10464 if (!thumb) { 10465 if (factor > iL.options.maxScale) factor = iL.options.maxScale; 10466 else if (factor < iL.options.minScale) factor = iL.options.minScale; 10467 } 10468 10469 var final_width = (iL.options.keepAspectRatio) ? round(width_old * factor) : width, 10470 final_height = (iL.options.keepAspectRatio) ? round(height_old * factor) : height; 10471 10472 return { 10473 width: final_width, 10474 height: final_height, 10475 ratio: factor 10476 }; 10477 }, 10478 10479 setOption: function(options) { 10480 var iL = this; 10481 10482 iL.options = $.extend(true, iL.options, options || {}); 10483 iL.refresh(); 10484 }, 10485 10486 availPlugins: function() { 10487 var iL = this, 10488 testEl = document.createElement("video"); 10489 10490 iL.plugins = { 10491 flash: !isMobile, 10492 quicktime: (parseInt(PluginDetect.getVersion("QuickTime")) >= 0) ? true : false, 10493 html5H264: !!(testEl.canPlayType && testEl.canPlayType('video/mp4').replace(/no/, '')), 10494 html5WebM: !!(testEl.canPlayType && testEl.canPlayType('video/webm').replace(/no/, '')), 10495 html5Vorbis: !!(testEl.canPlayType && testEl.canPlayType('video/ogg').replace(/no/, '')), 10496 html5QuickTime: !!(testEl.canPlayType && testEl.canPlayType('video/quicktime').replace(/no/, '')) 10497 }; 10498 }, 10499 10500 addContent: function(element, obj) { 10501 var iL = this, 10502 el; 10503 10504 switch (obj.type) { 10505 case 'video': 10506 var HTML5 = false, 10507 videoType = obj.videoType, 10508 html5video = obj.options.html5video; 10509 10510 if (((videoType == 'video/mp4' || obj.ext == 'mp4' || obj.ext == 'm4v') || html5video.h264) && iL.plugins.html5H264) 10511 obj.ext = 'mp4', 10512 obj.URL = html5video.h264 || obj.URL; 10513 else if (html5video.webm && iL.plugins.html5WebM) 10514 obj.ext = 'webm', 10515 obj.URL = html5video.webm || obj.URL; 10516 else if (html5video.ogg && iL.plugins.html5Vorbis) 10517 obj.ext = 'ogv', 10518 obj.URL = html5video.ogg || obj.URL; 10519 10520 if (iL.plugins.html5H264 && (videoType == 'video/mp4' || obj.ext == 'mp4' || obj.ext == 'm4v')) HTML5 = true, videoType = "video/mp4"; 10521 else if (iL.plugins.html5WebM && (videoType == 'video/webm' || obj.ext == 'webm')) HTML5 = true, videoType = "video/webm"; 10522 else if (iL.plugins.html5Vorbis && (videoType == 'video/ogg' || obj.ext == 'ogv')) HTML5 = true, videoType = "video/ogg"; 10523 else if (iL.plugins.html5QuickTime && (videoType == 'video/quicktime' || obj.ext == 'mov' || obj.ext == 'qt')) HTML5 = true, videoType = "video/quicktime"; 10524 10525 if (HTML5) { 10526 el = $('<video />
10526', { 10527 "width": "100%", 10528 "height": "100%", 10529 "preload": html5video.preload, 10530 "autoplay": html5video.autoplay, 10531 "loop": html5video.loop, 10532 "poster": html5video.poster, 10533 "controls": html5video.controls, 10534 "controlslist": "nodownload" 10535 }).append($('<source />', { 10536 "src": obj.URL, 10537 "type": videoType 10538 })); 10539 } else { 10540 if (!iL.plugins.quicktime) el = $('<span />', { 10541 "class": "ilightbox-alert", 10542 html: iL.options.errors.missingPlugin.replace('{pluginspage}', pluginspages.quicktime).replace('{type}', 'QuickTime') 10543 }); 10544 else { 10545 10546 el = $('<object />', { 10547 "type": "video/quicktime", 10548 "pluginspage": pluginspages.quicktime 10549 }).attr({ 10550 "data": obj.URL, 10551 "width": "100%", 10552 "height": "100%" 10553 }).append($('<param />', { 10554 "name": "src", 10555 "value": obj.URL 10556 })).append($('<param />', { 10557 "name": "autoplay", 10558 "value": "false" 10559 })).append($('<param />', { 10560 "name": "loop", 10561 "value": "false" 10562 })).append($('<param />', { 10563 "name": "scale", 10564 "value": "tofit" 10565 })); 10566 10567 if (browser.msie) el = QT_GenerateOBJECTText(obj.URL, '100%', '100%', '', 'SCALE', 'tofit', 'AUTOPLAY', 'false', 'LOOP', 'false'); 10568 } 10569 } 10570 10571 break; 10572 10573 case 'flash': 10574 if (!iL.plugins.flash) el = $('<span />', { 10575 "class": "ilightbox-alert", 10576 html: iL.options.errors.missingPlugin.replace('{pluginspage}', pluginspages.flash).replace('{type}', 'Adobe Flash player') 10577 }); 10578 else { 10579 var flashvars = "", 10580 i = 0; 10581 10582 if (obj.options.flashvars) $.each(obj.options.flashvars, function(k, v) { 10583 if (i != 0) flashvars += "&"; 10584 flashvars += k + "=" + encodeURIComponent(v); 10585 i++; 10586 }); 10587 else flashvars = null; 10588 10589 el = $('<embed />').attr({ 10590 "type": "application/x-shockwave-flash", 10591 "src": obj.URL, 10592 "width": (typeof obj.options.width == 'number' && obj.options.width && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.width : "100%", 10593 "height": (typeof obj.options.height == 'number' && obj.options.height && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.height : "100%", 10594 "quality": "high", 10595 "bgcolor": "#000000", 10596 "play": "true", 10597 "loop": "true", 10598 "menu": "true", 10599 "wmode": "transparent", 10600 "scale": "showall", 10601 "allowScriptAccess": "always", 10602 "allowFullScreen": "true", 10603 "flashvars": flashvars, 10604 "fullscreen": "yes" 10605 }); 10606 } 10607 10608 break; 10609 10610 case 'iframe': 10611 el = $('<iframe />').attr({ 10612 "width": (typeof obj.options.width == 'number' && obj.options.width && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.width : "100%", 10613 "height": (typeof obj.options.height == 'number' && obj.options.height && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.height : "100%", 10614 src: obj.URL, 10615 frameborder: 0, 10616 'hspace': 0, 10617 'vspace': 0, 10618 'scrolling': supportTouch ? 'auto' : 'scroll', 10619 'webkitAllowFullScreen': '', 10620 'mozallowfullscreen': '', 10621 'allowFullScreen': '' 10622 }); 10623 10624 break; 10625 10626 case 'inline': 10627 el = $('<div class="ilightbox-wrapper"></div>').html($(obj.URL).clone(true)); 10628 10629 break; 10630 10631 case 'html': 10632 var object = obj.URL, 10633 el; 10634 10635 if (object[0].nodeName) { 10636 el = $('<div class="ilightbox-wrapper"></div>').html(object); 10637 } else { 10638 var dom = $(obj.URL), 10639 html = (dom.selector) ? $('<div>' + dom + '</div>') : dom; 10640 el = $('<div class="ilightbox-wrapper"></div>').html(html); 10641 } 10642 10643 break; 10644 } 10645 10646 $('div.ilightbox-container', element).empty().html(el); 10647 10648 // For fixing Chrome about just playing the video for first time 10649 if (el[0].tagName.toLowerCase() === 'video' && browser.webkit) setTimeout(function() { 10650 var src = el[0].currentSrc + '?' + floor(random() * 30000); 10651 el[0].currentSrc = src; 10652 el[0].src = src; 10653 }); 10654 10655 return el; 10656 }, 10657 10658 ogpRecognition: function(obj, callback) { 10659 var iL = this, 10660 url = obj.URL; 10661 10662 iL.showLoader(); 10663 doAjax(url, function(data) { 10664 iL.hideLoader(); 10665 if (data) { 10666 var object = new Object(); 10667 10668 object.length = false, 10669 object.url = data.url; 10670 10671 if (data.status == 200) { 10672 var result = data.results, 10673 type = result.type, 10674 source = result.source; 10675 10676 object.source = source.src, 10677 object.width = source.width && parseInt(source.width) || 0, 10678 object.height = source.height && parseInt(source.height) || 0, 10679 object.type = type, 10680 object.thumbnail = source.thumbnail || result.images && result.images[0], 10681 object.html5video = result.html5video || {}, 10682 object.length = true; 10683 10684 if (source.type == 'application/x-shockwave-flash') object.type = "flash"; 10685 else if (source.type.indexOf("video/") != -1) object.type = "video"; 10686 else if (source.type.indexOf("/html") != -1) object.type = "iframe"; 10687 else if (source.type.indexOf("image/") != -1) object.type = "image"; 10688 10689 } else if (typeof data.response != 'undefined') 10690 throw data.response; 10691 10692 callback.call(this, object.length ? object : false); 10693 } 10694 }); 10695 }, 10696 10697 hashChangeHandler: function(url) { 10698 var iL = this, 10699 vars = iL.vars, 10700 opts = iL.options, 10701 URL = url || window.location.href, 10702 hash = parseURI(URL).hash, 10703 split = hash.split('/'), 10704 index = split[1]; 10705 10706 if (vars.hashLock || ('#' + opts.linkId != split[0] && hash.length > 1)) return; 10707 10708 if (index) { 10709 var target = split[1] || 0; 10710 if (iL.items[target]) {
10711 var overlay = $('.ilightbox-overlay'); 10712 if (overlay.length && overlay.attr('linkid') == opts.linkId) { 10713 iL.goTo(target); 10714 } else { 10715 iL.itemsObject[target].trigger(ishybrid ? "itap click" : supportTouch ? 'itap' : 'click'); 10716 //iL.goTo(target); 10717 } 10718 } else { 10719 var overlay = $('.ilightbox-overlay'); 10720 if (overlay.length) iL.closeAction(); 10721 } 10722 } else { 10723 var overlay = $('.ilightbox-overlay'); 10724 if (overlay.length) iL.closeAction(); 10725 } 10726 } 10727 }; 10728 10729 /** 10730 * Parse style to pixels. 10731 * 10732 * @param {Object} $element jQuery object with element. 10733 * @param {Property} property CSS property to get the pixels from. 10734 * 10735 * @return {Int} 10736 */ 10737 function getPixel($element, property) { 10738 return parseInt($element.css(property), 10) || 0; 10739 } 10740 10741 /** 10742 * Make sure that number is within the limits. 10743 * 10744 * @param {Number} number 10745 * @param {Number} min 10746 * @param {Number} max 10747 * 10748 * @return {Number} 10749 */ 10750 function within(number, min, max) { 10751 return number < min ? min : number > max ? max : number; 10752 } 10753 10754 /** 10755 * Get viewport/window size (width and height). 10756 * 10757 * @return {Object} 10758 */ 10759 function getViewport() { 10760 var e = window, 10761 a = 'inner'; 10762 if (!('innerWidth' in window)) { 10763 a = 'client'; 10764 e = document.documentElement || document.body; 10765 } 10766 return { 10767 width: e[a + 'Width'], 10768 height: e[a + 'Height'] 10769 } 10770 } 10771 10772 /** 10773 * Remove hash tag from the URL 10774 * 10775 * @return {Void} 10776 */ 10777 function removeHash() { 10778 var scroll = getScrollXY(); 10779 10780 //UNCODE change 10781 //window.location.hash = ""; 10782 history.pushState("", document.title, window.location.pathname + window.location.search); 10783 10784 // Restore the scroll offset, should be flicker free 10785 window.scrollTo(scroll.x, scroll.y); 10786 } 10787 10788 /** 10789 * Do the ajax requests with callback. 10790 * 10791 * @param {String} url 10792 * @param {Function} callback 10793 * 10794 * @return {Void} 10795 */ 10796 function doAjax(url, callback) { 10797 var url = "//ilightbox.net/getSource/jsonp.php?url=" + encodeURIComponent(url).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28').replace(/\)/g, '%29').replace(/\*/g, '%2A'); 10798 $.ajax({ 10799 url: url, 10800 dataType: 'jsonp' 10801 }); 10802 10803 iLCallback = function(data) { 10804 callback.call(this, data); 10805 }; 10806 } 10807 10808 /** 10809 * Find image from DOM elements 10810 * 10811 * @param {Element} element 10812 * 10813 * @return {Void} 10814 */ 10815 function findImageInElement(element) { 10816 var elements = $('*', element), 10817 imagesArr = new Array(); 10818 10819 elements.each(function() { 10820 var url = "", 10821 element = this; 10822 10823 if ($(element).css("background-image") != "none") { 10824 url = $(element).css("background-image"); 10825 } else if (typeof($(element).attr("src")) != "undefined" && element.nodeName.toLowerCase() == "img") { 10826 url = $(element).attr("src"); 10827 } 10828 10829 if (url.indexOf("gradient") == -1) { 10830 url = url.replace(/url\(\"/g, ""); 10831 url = url.replace(/url\(/g, ""); 10832 url = url.replace(/\"\)/g, ""); 10833 url = url.replace(/\)/g, ""); 10834 10835 var urls = url.split(","); 10836 10837 for (var i = 0; i < urls.length; i++) { 10838 if (urls[i].length > 0 && $.inArray(urls[i], imagesArr) == -1) { 10839 var extra = ""; 10840 if (browser.msie && browser.version < 9) { 10841 extra = "?" + floor(random() * 3000); 10842 } 10843 imagesArr.push(urls[i] + extra); 10844 } 10845 } 10846 } 10847 }); 10848 10849 return imagesArr; 10850 } 10851 10852 /** 10853 * Get file extension. 10854 * 10855 * @param {String} URL 10856 * 10857 * @return {String} 10858 */ 10859 function getExtension(URL) { 10860 if (URL !== null) { 10861 //UNCODE: fix issue to detect media type with query strings 10862 var ext = URL.indexOf('?') !== -1 ? URL.split('?')[0] : URL; 10863 ext = ext.split('.').pop().toLowerCase(); 10864 10865 return ext; 10866 } 10867 } 10868 10869 /** 10870 * Get type via extension. 10871 * 10872 * @param {String} URL 10873 * 10874 * @return {String} 10875 */ 10876 function getTypeByExtension(URL) { 10877 var type, 10878 ext = getExtension(URL); 10879 10880 if (extensions.image.indexOf(ext) !== -1) type = 'image'; 10881 else if (extensions.flash.indexOf(ext) !== -1) type = 'flash'; 10882 else if (extensions.video.indexOf(ext) !== -1) type = 'video'; 10883 else if (ext.substring(0, 1) == "#") type = 'inline'; //Uncode addition 10884 else type = 'iframe'; 10885 10886 return type; 10887 } 10888 10889 /** 10890 * Return value from percent of a number. 10891 * 10892 * @param {Number} percent 10893 * @param {Number} total 10894 * 10895 * @return {Number} 10896 */ 10897 function percentToValue(percent, total) { 10898 return parseInt((total / 100) * percent); 10899 } 10900 10901 /** 10902 * A JavaScript equivalent of PHP’s parse_url. 10903 * 10904 * @param {String} url The URL to parse. 10905 * 10906 * @return {Mixed} 10907 */ 10908 function parseURI(url) { 10909 var m = String(url).replace(/^\s+|\s+$/g, '').match(/^([^:\/?#]+:)?(\/\/(?:[^:@]*(?::[^:@]*)?@)?(([^:\/?#]*)(?::(\d*))?))?([^?#]*)(\?[^#]*)?(#[\s\S]*)?/); 10910 // authority = '//' + user + ':' + pass '@' + hostname + ':' port 10911 return (m ? { 10912 href: m[0] || '', 10913 protocol: m[1] || '', 10914 authority: m[2] || '', 10915 host: m[3] || '', 10916 hostname: m[4] || '', 10917 port: m[5] || '', 10918 pathname: m[6] || '', 10919 search: m[7] || '', 10920 hash: m[8] || '' 10921 } : null); 10922 } 10923 10924 /** 10925 * Gets the absolute URI. 10926 * 10927 * @param {String} href The relative URL. 10928 * @param {String} base The base URL. 10929 * 10930 * @return {String} The absolute URL. 10931 */ 10932 function absolutizeURI(base, href) { // RFC 3986 10933 var iL = this; 10934 10935 function removeDotSegments(input) { 10936 var output = []; 10937 input.replace(/^(\.\.?(\/|$))+/, '') 10938 .replace(/\/(\.(\/|$))+/g, '/') 10939 .replace(/\/\.\.$/, '/../') 10940 .replace(/\/?[^\/]*/g, function(p) { 10941 if (p === '/..') { 10942 output.pop(); 10943 } else { 10944 output.push(p); 10945 } 10946 }); 10947 return output.join('').replace(/^\//, input.charAt(0) === '/' ? '/' : ''); 10948 } 10949 10950 href = parseURI(href || ''); 10951 base = parseURI(base || ''); 10952 10953 return !href || !base ? null : (href.protocol || base.protocol) + 10954 (href.protocol || href.authority ? href.authority : base.authority) + 10955 removeDotSegments(href.protocol || href.authority || href.pathname.charAt(0) === '/' ? href.pathname : (href.pathname ? ((base.authority && !base.pathname ? '/' : '') + base.pathname.slice(0, base.pathname.lastIndexOf('/') + 1) + href.pathname) : base.pathname)) + 10956 (href.protocol || href.authority || href.pathname ? href.search : (href.search || base.search)) + 10957 href.hash; 10958 } 10959 10960 /** 10961 * A JavaScript equivalent of PHP’s version_compare. 10962 * 10963 * @param {String} v1 10964 * @param {String} v2 10965 * @param {String} operator
10966 * 10967 * @return {Boolean} 10968 */ 10969 function version_compare(v1, v2, operator) { 10970 this.php_js = this.php_js || {}; 10971 this.php_js.ENV = this.php_js.ENV || {}; 10972 var i = 0, 10973 x = 0, 10974 compare = 0, 10975 vm = { 10976 'dev': -6, 10977 'alpha': -5, 10978 'a': -5, 10979 'beta': -4, 10980 'b': -4, 10981 'RC': -3, 10982 'rc': -3, 10983 '#': -2, 10984 'p': 1, 10985 'pl': 1 10986 }, 10987 prepVersion = function(v) { 10988 v = ('' + v).replace(/[_\-+]/g, '.'); 10989 v = v.replace(/([^.\d]+)/g, '.$1.').replace(/\.{2,}/g, '.'); 10990 return (!v.length ? [-8] : v.split('.')); 10991 }, 10992 numVersion = function(v) { 10993 return !v ? 0 : (isNaN(v) ? vm[v] || -7 : parseInt(v, 10)); 10994 }; 10995 v1 = prepVersion(v1); 10996 v2 = prepVersion(v2); 10997 x = max(v1.length, v2.length); 10998 for (i = 0; i < x; i++) { 10999 if (v1[i] == v2[i]) { 11000 continue; 11001 } 11002 v1[i] = numVersion(v1[i]); 11003 v2[i] = numVersion(v2[i]); 11004 if (v1[i] < v2[i]) { 11005 compare = -1; 11006 break; 11007 } else if (v1[i] > v2[i]) { 11008 compare = 1; 11009 break; 11010 } 11011 } 11012 if (!operator) { 11013 return compare; 11014 } 11015 11016 switch (operator) { 11017 case '>': 11018 case 'gt': 11019 return (compare > 0); 11020 case '>=': 11021 case 'ge': 11022 return (compare >= 0); 11023 case '<=': 11024 case 'le': 11025 return (compare <= 0); 11026 case '==': 11027 case '=': 11028 case 'eq': 11029 return (compare === 0); 11030 case '<>': 11031 case '!=': 11032 case 'ne': 11033 return (compare !== 0); 11034 case '': 11035 case '<': 11036 case 'lt': 11037 return (compare < 0); 11038 default: 11039 return null; 11040 } 11041 } 11042 11043 11044 // Begin the iLightBox plugin 11045 $.fn.iLightBox = function() { 11046 11047 var args = arguments, 11048 opt = ($.isPlainObject(args[0])) ? args[0] : args[1], 11049 items = ($.isArray(args[0]) || typeof args[0] == 'string') ? args[0] : args[1]; 11050 11051 if (!opt) opt = {}; 11052 11053 // Default options. Play carefully. 11054 var options = $.extend(true, { 11055 attr: 'href', 11056 path: 'vertical', 11057 skin: 'dark', 11058 linkId: false, 11059 infinite: false, 11060 startFrom: 0, 11061 randomStart: false, 11062 keepAspectRatio: true, 11063 maxScale: 1, 11064 minScale: .2, 11065 innerToolbar: false, 11066 smartRecognition: false, 11067 mobileOptimizer: true, 11068 fullAlone: true, 11069 fullViewPort: null, 11070 fullStretchTypes: 'flash, video', 11071 overlay: { 11072 blur: true, 11073 opacity: .85 11074 }, 11075 controls: { 11076 arrows: false, 11077 slideshow: false, 11078 toolbar: true, 11079 fullscreen: true, 11080 thumbnail: true, 11081 keyboard: true, 11082 mousewheel: true, 11083 swipe: true 11084 }, 11085 keyboard: { 11086 left: true, // previous 11087 right: true, // next 11088 up: true, // previous 11089 down: true, // next 11090 esc: true, // close 11091 shift_enter: true // fullscreen 11092 }, 11093 show: { 11094 effect: true, 11095 speed: 300, 11096 title: true 11097 }, 11098 hide: { 11099 effect: true, 11100 speed: 300 11101 }, 11102 caption: { 11103 start: true, 11104 show: 'mouseenter', 11105 hide: 'mouseleave' 11106 }, 11107 social: { 11108 start: true, 11109 show: 'mouseenter', 11110 hide: 'mouseleave',
11111 buttons: false 11112 }, 11113 styles: { 11114 pageOffsetX: 0, 11115 pageOffsetY: 0, 11116 nextOffsetX: 45, 11117 nextOffsetY: 0, 11118 nextOpacity: 1, 11119 nextScale: 1, 11120 prevOffsetX: 45, 11121 prevOffsetY: 0, 11122 prevOpacity: 1, 11123 prevScale: 1 11124 }, 11125 thumbnails: { 11126 maxWidth: 120, 11127 maxHeight: 80, 11128 normalOpacity: 1, 11129 activeOpacity: .6 11130 }, 11131 effects: { 11132 reposition: true, 11133 repositionSpeed: 200, 11134 switchSpeed: 500, 11135 loadedFadeSpeed: 180, 11136 fadeSpeed: 200 11137 }, 11138 slideshow: { 11139 pauseTime: 5000, 11140 pauseOnHover: false, 11141 startPaused: true 11142 }, 11143 text: { 11144 close: "Press Esc to close", 11145 enterFullscreen: "Enter Fullscreen (Shift+Enter)", 11146 exitFullscreen: "Exit Fullscreen (Shift+Enter)", 11147 slideShow: "Slideshow", 11148 next: "Next", 11149 previous: "Previous" 11150 }, 11151 errors: { 11152 loadImage: "An error occurred when trying to load photo.", 11153 loadContents: "An error occurred when trying to load contents.", 11154 missingPlugin: "The content your are attempting to view requires the <a href='{pluginspage}' target='_blank'>{type} plugin<\/a>." 11155 }, 11156 ajaxSetup: { 11157 url: '', 11158 beforeSend: function(jqXHR, settings) {}, 11159 cache: false, 11160 complete: function(jqXHR, textStatus) {}, 11161 crossDomain: false, 11162 error: function(jqXHR, textStatus, errorThrown) {}, 11163 success: function(data, textStatus, jqXHR) {}, 11164 global: true, 11165 ifModified: false, 11166 username: null, 11167 password: null, 11168 type: 'GET' 11169 }, 11170 callback: {} 11171 }, opt); 11172 11173 var instant = ($.isArray(items) || typeof items == 'string') ? true : false; 11174 11175 items = $.isArray(items) ? items : new Array(); 11176 11177 if (typeof args[0] == 'string') items[0] = args[0]; 11178 11179 if (version_compare($.fn.jquery, '1.8', '>=')) { 11180 var iLB = new iLightBox($(this), options, items, instant); 11181 return { 11182 close: function() { 11183 iLB.closeAction(); 11184 }, 11185 fullscreen: function() { 11186 iLB.fullScreenAction(); 11187 }, 11188 moveNext: function() { 11189 iLB.moveTo('next'); 11190 }, 11191 movePrev: function() { 11192 iLB.moveTo('prev'); 11193 }, 11194 goTo: function(index) { 11195 iLB.goTo(index); 11196 }, 11197 refresh: function() { 11198 iLB.refresh(); 11199 }, 11200 reposition: function() { 11201 (arguments.length > 0) ? iLB.repositionPhoto(true): iLB.repositionPhoto(); 11202 }, 11203 setOption: function(options) { 11204 iLB.setOption(options); 11205 }, 11206 destroy: function() { 11207 iLB.closeAction(); 11208 iLB.dispatchItemsEvents(); 11209 } 11210 }; 11211 } else { 11212 throw "The jQuery version that was loaded is too old. iLightBox requires jQuery 1.8+"; 11213 } 11214 11215 }; 11216 11217 11218 $.iLightBox = function() { 11219 return $.fn.iLightBox(arguments[0], arguments[1]); 11220 }; 11221 11222 11223 $.extend($.easing, { 11224 easeInCirc: function(x, t, b, c, d) { 11225 return -c * (sqrt(1 - (t /= d) * t) - 1) + b; 11226 }, 11227 easeOutCirc: function(x, t, b, c, d) { 11228 return c * sqrt(1 - (t = t / d - 1) * t) + b; 11229 }, 11230 easeInOutCirc: function(x, t, b, c, d) { 11231 if ((t /= d / 2) < 1) return -c / 2 * (sqrt(1 - t * t) - 1) + b; 11232 return c / 2 * (sqrt(1 - (t -= 2) * t) + 1) + b; 11233 } 11234 }); 11235 11236 function getScrollXY() { 11237 var scrOfX = 0, 11238 scrOfY = 0; 11239 if (typeof(window.pageYOffset) == 'number') { 11240 //Netscape compliant 11241 scrOfY = window.pageYOffset; 11242 scrOfX = window.pageXOffset; 11243 } else if (document.body && (document.body.scrollLeft || document.body.scrollTop)) { 11244 //DOM compliant 11245 scrOfY = document.body.scrollTop; 11246 scrOfX = document.body.scrollLeft; 11247 } else if (document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)) { 11248 //IE6 standards compliant mode 11249 scrOfY = document.documentElement.scrollTop; 11250 scrOfX = document.documentElement.scrollLeft; 11251 } 11252 return { 11253 x: scrOfX, 11254 y: scrOfY 11255 }; 11256 } 11257 11258 (function() { 11259 // add new event shortcuts 11260 $.each(("touchstart touchmove touchend " + 11261 "tap taphold " + 11262 "swipe swipeleft swiperight " + 11263 "scrollstart scrollstop").split(" "), function(i, name) { 11264 11265 $.fn[name] = function(fn) { 11266 return fn ? this.bind(name, fn) : this.trigger(name); 11267 }; 11268 11269 // jQuery < 1.8 11270 // if ($.attrFn) { 11271 // $.attrFn[name] = true; 11272 // } 11273 }); 11274 11275 var tapSettings = { 11276 startEvent: 'touchstart.iTap', 11277 endEvent: 'touchend.iTap' 11278 }; 11279 11280 // tap Event: 11281 $.event.special.itap = { 11282 setup: function() { 11283 11284 var self = this, 11285 $self = $(this), 11286 start, stop; 11287 11288 $self.bind(tapSettings.startEvent, function(event) { 11289 start = getScrollXY(); 11290 11291 $self.one(tapSettings.endEvent, function(event) { 11292 stop = getScrollXY(); 11293 11294 var orgEvent = event || window.event; 11295 event = $.event.fix(orgEvent); 11296 event.type = "itap"; 11297 11298 if ((start && stop) && (start.x == stop.x && start.y == stop.y))($.event.dispatch || $.event.handle).call(self, event); 11299 11300 start = stop = undefined; 11301 }); 11302 }); 11303 }, 11304 11305 teardown: function() { 11306 $(this).unbind(tapSettings.startEvent); 11307 } 11308 }; 11309 }()); 11310 11311 11312 //Fullscreen API 11313 (function() { 11314 fullScreenApi = { 11315 supportsFullScreen: false, 11316 isFullScreen: function() { 11317 return false;
11318 }, 11319 requestFullScreen: function() {}, 11320 cancelFullScreen: function() {}, 11321 fullScreenEventName: '', 11322 prefix: '' 11323 }, 11324 browserPrefixes = 'webkit moz o ms khtml'.split(' '); 11325 11326 // check for native support 11327 if (typeof document.cancelFullScreen != 'undefined') { 11328 fullScreenApi.supportsFullScreen = true; 11329 } else { 11330 // check for fullscreen support by vendor prefix 11331 for (var i = 0, il = browserPrefixes.length; i < il; i++) { 11332 fullScreenApi.prefix = browserPrefixes[i]; 11333 11334 if (typeof document[fullScreenApi.prefix + 'CancelFullScreen'] != 'undefined') { 11335 fullScreenApi.supportsFullScreen = true; 11336 11337 break; 11338 } 11339 } 11340 } 11341 11342 // update methods to do something useful 11343 if (fullScreenApi.supportsFullScreen) { 11344 fullScreenApi.fullScreenEventName = fullScreenApi.prefix + 'fullscreenchange'; 11345 11346 fullScreenApi.isFullScreen = function() { 11347 switch (this.prefix) { 11348 case '': 11349 return document.fullScreen; 11350 case 'webkit': 11351 return document.webkitIsFullScreen; 11352 default: 11353 return document[this.prefix + 'FullScreen']; 11354 } 11355 } 11356 fullScreenApi.requestFullScreen = function(el) { 11357 return (this.prefix === '') ? el.requestFullScreen() : el[this.prefix + 'RequestFullScreen'](); 11358 } 11359 fullScreenApi.cancelFullScreen = function(el) { 11360 return (this.prefix === '') ? document.cancelFullScreen() : document[this.prefix + 'CancelFullScreen'](); 11361 } 11362 } 11363 }()); 11364 11365 // Browser detect 11366 (function() { 11367 function uaMatch(ua) { 11368 ua = ua.toLowerCase(); 11369 11370 var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || 11371 /(webkit)[ \/]([\w.]+)/.exec(ua) || 11372 /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || 11373 /(msie) ([\w.]+)/.exec(ua) || 11374 ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || []; 11375 11376 return { 11377 browser: match[1] || "", 11378 version: match[2] || "0" 11379 }; 11380 } 11381 11382 var matched = uaMatch(navigator.userAgent); 11383 browser = {}; 11384 11385 if (matched.browser) { 11386 browser[matched.browser] = true; 11387 browser.version = matched.version; 11388 } 11389 11390 // Chrome is Webkit, but Webkit is also Safari. 11391 if (browser.chrome) { 11392 browser.webkit = true; 11393 } else if (browser.webkit) { 11394 browser.safari = true; 11395 } 11396 }()); 11397 11398 // Feature detects 11399 (function() { 11400 var prefixes = ['', 'webkit', 'moz', 'ms', 'o']; 11401 var el = document.createElement('div'); 11402 11403 function testProp(prop) { 11404 for (var p = 0, pl = prefixes.length; p < pl; p++) { 11405 var prefixedProp = prefixes[p] ? prefixes[p] + prop.charAt(0).toUpperCase() + prop.slice(1) : prop; 11406 if (el.style[prefixedProp] !== undefined) { 11407 return prefixedProp; 11408 } 11409 } 11410 } 11411 11412 // Global support indicators 11413 transform = testProp('transform') || ''; 11414 gpuAcceleration = testProp('perspective') ? 'translateZ(0) ' : ''; 11415 }()); 11416 11417 11418 /* 11419 PluginDetect v0.7.9 11420 www.pinlady.net/PluginDetect/license/ 11421 [ getVersion onWindowLoaded BetterIE ] 11422 [ Flash QuickTime Shockwave ] 11423 */ 11424 var PluginDetect={version:"0.7.9",name:"PluginDetect",handler:function(c,b,a){return function(){c(b,a)}},openTag:"<",isDefined:function(b){return typeof b!="undefined"},isArray:function(b){return(/array/i).test(Object.prototype.toString.call(b))},isFunc:function(b){return typeof b=="function"},isString:function(b){return typeof b=="string"},isNum:function(b){return typeof b=="number"},isStrNum:function(b){return(typeof b=="string"&&(/\d/).test(b))},getNumRegx:/[\d][\d\.\_,-]*/,splitNumRegx:/[\.\_,-]/g,getNum:function(b,c){var d=this,a=d.isStrNum(b)?(d.isDefined(c)?new RegExp(c):d.getNumRegx).exec(b):null;return a?a[0]:null},compareNums:function(h,f,d){var e=this,c,b,a,g=parseInt;if(e.isStrNum(h)&&e.isStrNum(f)){if(e.isDefined(d)&&d.compareNums){return d.compareNums(h,f)}c=h.split(e.splitNumRegx);b=f.split(e.splitNumRegx);for(a=0;a<min(c.length,b.length);a++){if(g(c[a],10)>g(b[a],10)){return 1}if(g(c[a],10)<g(b[a],10)){return -1}}}return 0},formatNum:function(b,c){var d=this,a,e;if(!d.isStrNum(b)){return null}if(!d.isNum(c)){c=4}c--;e=b.replace(/\s/g,"").split(d.splitNumRegx).concat(["0","0","0","0"]);for(a=0;a<4;a++){if(/^(0+)(.+)$/.test(e[a])){e[a]=RegExp.$2}if(a>c||!(/\d/).test(e[a])){e[a]="0"}}return e.slice(0,4).join(",")},$$hasMimeType:function(a){return function(c){if(!a.isIE&&c){var f,e,b,d=a.isArray(c)?c:(a.isString(c)?[c]:[]);for(b=0;b<d.length;b++){if(a.isString(d[b])&&/[^\s]/.test(d[b])){f=navigator.mimeTypes[d[b]];e=f?f.enabledPlugin:0;if(e&&(e.name||e.description)){return f}}}}return null}},findNavPlugin:function(l,e,c){var j=this,h=new RegExp(l,"i"),d=(!j.isDefined(e)||e)?/\d/:0,k=c?new RegExp(c,"i"):0,a=navigator.plugins,g="",f,b,m;for(f=0;f<a.length;f++){m=a[f].description||g;b=a[f].name||g;if((h.test(m)&&(!d||d.test(RegExp.leftContext+RegExp.rightContext)))||(h.test(b)&&(!d||d.test(RegExp.leftContext+RegExp.rightContext)))){if(!k||!(k.test(m)||k.test(b))){return a[f]}}}return null},getMimeEnabledPlugin:function(k,m,c){var e=this,f,b=new RegExp(m,"i"),h="",g=c?new RegExp(c,"i"):0,a,l,d,j=e.isString(k)?[k]:k;for(d=0;d<j.length;
11424d++){if((f=e.hasMimeType(j[d]))&&(f=f.enabledPlugin)){l=f.description||h;a=f.name||h;if(b.test(l)||b.test(a)){if(!g||!(g.test(l)||g.test(a))){return f}}}}return 0},getPluginFileVersion:function(f,b){var h=this,e,d,g,a,c=-1;if(h.OS>2||!f||!f.version||!(e=h.getNum(f.version))){return b}if(!b){return e}e=h.formatNum(e);b=h.formatNum(b);d=b.split(h.splitNumRegx);g=e.split(h.splitNumRegx);for(a=0;a<d.length;a++){if(c>-1&&a>c&&d[a]!="0"){return b}if(g[a]!=d[a]){if(c==-1){c=a}if(d[a]!="0"){return b}}}return e},AXO:window.ActiveXObject,getAXO:function(a){var f=null,d,b=this,c={};try{f=new b.AXO(a)}catch(d){}return f},convertFuncs:function(f){var a,g,d,b=/^[\$][\$]/,c=this;for(a in f){if(b.test(a)){try{g=a.slice(2);if(g.length>0&&!f[g]){f[g]=f[a](f);delete f[a]}}catch(d){}}}},initObj:function(e,b,d){var a,c;if(e){if(e[b[0]]==1||d){for(a=0;a<b.length;a=a+2){e[b[a]]=b[a+1]}}for(a in e){c=e[a];if(c&&c[b[0]]==1){this.initObj(c,b)}}}},initScript:function(){var d=this,a=navigator,h,i=document,l=a.userAgent||"",j=a.vendor||"",b=a.platform||"",k=a.product||"";d.initObj(d,["$",d]);for(h in d.Plugins){if(d.Plugins[h]){d.initObj(d.Plugins[h],["$",d,"$$",d.Plugins[h]],1)}}d.convertFuncs(d);d.OS=100;if(b){var g=["Win",1,"Mac",2,"Linux",3,"FreeBSD",4,"iPhone",21.1,"iPod",21.2,"iPad",21.3,"Win.*CE",22.1,"Win.*Mobile",22.2,"Pocket\\s*PC",22.3,"",100];for(h=g.length-2;h>=0;h=h-2){if(g[h]&&new RegExp(g[h],"i").test(b)){d.OS=g[h+1];break}}};d.head=i.getElementsByTagName("head")[0]||i.getElementsByTagName("body")[0]||i.body||null;d.isIE=new Function("return/*@cc_on!@*/!1")();d.verIE=d.isIE&&(/MSIE\s*(\d+\.?\d*)/i).test(l)?parseFloat(RegExp.$1,10):null;d.verIEfull=null;d.docModeIE=null;if(d.isIE){var f,n,c=document.createElement("div");try{c.style.behavior="url(#default#clientcaps)";d.verIEfull=(c.getComponentVersion("{89820200-ECBD-11CF-8B85-00AA005B4383}","componentid")).replace(/,/g,".")}catch(f){}n=parseFloat(d.verIEfull||"0",10);d.docModeIE=i.documentMode||((/back/i).test(i.compatMode||"")?5:n)||d.verIE;d.verIE=n||d.docModeIE};d.ActiveXEnabled=false;if(d.isIE){var h,m=["Msxml2.XMLHTTP","Msxml2.DOMDocument","Microsoft.XMLDOM","ShockwaveFlash.ShockwaveFlash","TDCCtl.TDCCtl","Shell.UIHelper","Scripting.Dictionary","wmplayer.ocx"];for(h=0;h<m.length;h++){if(d.getAXO(m[h])){d.ActiveXEnabled=true;break}}};d.isGecko=(/Gecko/i).test(k)&&(/Gecko\s*\/\s*\d/i).test(l);
11424d.verGecko=d.isGecko?d.formatNum((/rv\s*\:\s*([\.\,\d]+)/i).test(l)?RegExp.$1:"0.9"):null;d.isChrome=(/Chrome\s*\/\s*(\d[\d\.]*)/i).test(l);d.verChrome=d.isChrome?d.formatNum(RegExp.$1):null;d.isSafari=((/Apple/i).test(j)||(!j&&!d.isChrome))&&(/Safari\s*\/\s*(\d[\d\.]*)/i).test(l);d.verSafari=d.isSafari&&(/Version\s*\/\s*(\d[\d\.]*)/i).test(l)?d.formatNum(RegExp.$1):null;d.isOpera=(/Opera\s*[\/]?\s*(\d+\.?\d*)/i).test(l);d.verOpera=d.isOpera&&((/Version\s*\/\s*(\d+\.?\d*)/i).test(l)||1)?parseFloat(RegExp.$1,10):null;d.addWinEvent("load",d.handler(d.runWLfuncs,d))},init:function(d){var c=this,b,d,a={status:-3,plugin:0};if(!c.isString(d)){return a}if(d.length==1){c.getVersionDelimiter=d;return a}d=d.toLowerCase().replace(/\s/g,"");b=c.Plugins[d];if(!b||!b.getVersion){return a}a.plugin=b;if(!c.isDefined(b.installed)){b.installed=null;b.version=null;b.version0=null;b.getVersionDone=null;b.pluginName=d}c.garbage=false;if(c.isIE&&!c.ActiveXEnabled&&d!=="java"){a.status=-2;return a}a.status=1;return a},fPush:function(b,a){var c=this;if(c.isArray(a)&&(c.isFunc(b)||(c.isArray(b)&&b.length>0&&c.isFunc(b[0])))){a.push(b)}},callArray:function(b){var c=this,a;if(c.isArray(b)){for(a=0;a<b.length;a++){if(b[a]===null){return}c.call(b[a]);b[a]=null}}},call:function(c){var b=this,a=b.isArray(c)?c.length:-1;if(a>0&&b.isFunc(c[0])){c[0](b,a>1?c[1]:0,a>2?c[2]:0,a>3?c[3]:0)}else{if(b.isFunc(c)){c(b)}}},getVersionDelimiter:",",$$getVersion:function(a){return function(g,d,c){var e=a.init(g),f,b,h={};if(e.status<0){return null};f=e.plugin;if(f.getVersionDone!=1){f.getVersion(null,d,c);if(f.getVersionDone===null){f.getVersionDone=1}}a.cleanup();b=(f.version||f.version0);b=b?b.replace(a.splitNumRegx,a.getVersionDelimiter):b;return b}},cleanup:function(){var a=this;if(a.garbage&&a.isDefined(window.CollectGarbage)){window.CollectGarbage()}},isActiveXObject:function(d,b){var f=this,a=false,g,c='<object width="1" height="1" style="display:none" '+d.getCodeBaseVersion(b)+">"+d.HTML+f.openTag+"/object>";if(!f.head){return a}f.head.insertBefore(document.createElement("object"),f.head.firstChild);f.head.firstChild.outerHTML=c;try{f.head.firstChild.classid=d.classID}catch(g){}try{if(f.head.firstChild.object){a=true}}catch(g){}try{if(a&&f.head.firstChild.readyState<4){f.garbage=true}}catch(g){}f.head.removeChild(f.head.firstChild);return a},codebaseSearch:function(f,b){var c=this;if(!c.ActiveXEnabled||!f){return null}if(f.BIfuncs&&f.BIfuncs.length&&f.BIfuncs[f.BIfuncs.length-1]!==null){c.callArray(f.BIfuncs)}var d,o=f.SEARCH,k={};if(c.isStrNum(b)){if(o.match&&o.min&&c.compareNums(b,o.min)<=0){return true}if(o.match&&o.max&&c.compareNums(b,o.max)>=0){return false}d=c.isActiveXObject(f,b);if(d&&(!o.min||c.compareNums(b,o.min)>0)){o.min=b}if(!d&&(!o.max||c.compareNums(b,o.max)<0)){o.max=b}return d};var e=[0,0,0,0],l=[].concat(o.digits),a=o.min?1:0,j,i,h,g,m,n=function(p,r){var q=[].concat(e);q[p]=r;return c.isActiveXObject(f,q.join(","))};if(o.max){g=o.max.split(c.splitNumRegx);for(j=0;j<g.length;j++){g[j]=parseInt(g[j],10)}if(g[0]<l[0]){l[0]=g[0]}}if(o.min){m=o.min.split(c.splitNumRegx);for(j=0;j<m.length;j++){m[j]=parseInt(m[j],10)}if(m[0]>e[0]){e[0]=m[0]}}if(m&&g){for(j=1;j<m.length;j++){if(m[j-1]!=g[j-1]){break}if(g[j]<l[j]){l[j]=g[j]}if(m[j]>e[j]){e[j]=m[j]}}}if(o.max){for(j=1;j<l.length;j++){if(g[j]>0&&l[j]==0&&l[j-1]<o.digits[j-1]){l[j-1]+=1;break}}};for(j=0;j<l.length;j++){h={};for(i=0;i<20;i++){if(l[j]-e[j]<1){break}d=round((l[j]+e[j])/2);if(h["a"+d]){break}h["a"+d]=1;if(n(j,d)){e[j]=d;a=1}else{l[j]=d}}l[j]=e[j];if(!a&&n(j,e[j])){a=1};if(!a){break}};return a?e.join(","):null},addWinEvent:function(d,c){var e=this,a=window,b;if(e.isFunc(c)){if(a.addEventListener){a.addEventListener(d,c,false)}else{if(a.attachEvent){a.attachEvent("on"+d,c)}else{b=a["on"+d];a["on"+d]=e.winHandler(c,b)}}}},winHandler:function(d,c){return function(){d();if(typeof c=="function"){c()}}},WLfuncs0:[],WLfuncs:[],runWLfuncs:function(a){var b={};a.winLoaded=true;a.callArray(a.WLfuncs0);a.callArray(a.WLfuncs);if(a.onDoneEmptyDiv){a.onDoneEmptyDiv()}},winLoaded:false,$$onWindowLoaded:function(a){return function(b){if(a.winLoaded){a.call(b)}else{a.fPush(b,a.WLfuncs)}}},div:null,divID:"plugindetect",divWidth:50,pluginSize:1,emptyDiv:function(){var d=this,b,h,c,a,f,g;if(d.div&&d.div.childNodes){for(b=d.div.childNodes.length-1;b>=0;b--){c=d.div.childNodes[b];if(c&&c.childNodes){for(h=c.childNodes.length-1;h>=0;h--){g=c.childNodes[h];try{c.removeChild(g)}catch(f){}}}if(c){try{d.div.removeChild(c)}catch(f){}}}}if(!d.div){a=document.getElementById(d.divID);if(a){d.div=a}}if(d.div&&d.div.parentNode){try{d.div.parentNode.removeChild(d.div)}catch(f){}d.div=null}},DONEfuncs:[],onDoneEmptyDiv:function(){var c=this,a,b;if(!c.winLoaded){return}if(c.WLfuncs&&c.WLfuncs.length&&c.WLfuncs[c.WLfuncs.length-1]!==null){return}for(a in c){b=c[a];if(b&&b.funcs){if(b.OTF==3){return}if(b.funcs.length&&b.funcs[b.funcs.length-1]!==null){return}}}for(a=0;a<c.DONEfuncs.length;a++){c.callArray(c.DONEfuncs)}
11424c.emptyDiv()},getWidth:function(c){if(c){var a=c.scrollWidth||c.offsetWidth,b=this;if(b.isNum(a)){return a}}return -1},getTagStatus:function(m,g,a,b){var c=this,f,k=m.span,l=c.getWidth(k),h=a.span,j=c.getWidth(h),d=g.span,i=c.getWidth(d);if(!k||!h||!d||!c.getDOMobj(m)){return -2}if(j<i||l<0||j<0||i<0||i<=c.pluginSize||c.pluginSize<1){return 0}if(l>=i){return -1}try{if(l==c.pluginSize&&(!c.isIE||c.getDOMobj(m).readyState==4)){if(!m.winLoaded&&c.winLoaded){return 1}if(m.winLoaded&&c.isNum(b)){if(!c.isNum(m.count)){m.count=b}if(b-m.count>=10){return 1}}}}catch(f){}return 0},getDOMobj:function(g,a){var f,d=this,c=g?g.span:0,b=c&&c.firstChild?1:0;try{if(b&&a){d.div.focus()}}catch(f){}return b?c.firstChild:null},setStyle:function(b,g){var f=b.style,a,d,c=this;if(f&&g){for(a=0;a<g.length;a=a+2){try{f[g[a]]=g[a+1]}catch(d){}}}},insertDivInBody:function(i,g){var f,c=this,h="pd33993399",b=null,d=g?window.top.document:window.document,a=d.getElementsByTagName("body")[0]||d.body;if(!a){try{d.write('<div id="'+h+'">.'+c.openTag+"/div>");b=d.getElementById(h)}catch(f){}}a=d.getElementsByTagName("body")[0]||d.body;if(a){a.insertBefore(i,a.firstChild);if(b){a.removeChild(b)}}},insertHTML:function(f,b,g,a,k){var l,m=document,j=this,p,o=m.createElement("span"),n,i;var c=["outlineStyle","none","borderStyle","none","padding","0px","margin","0px","visibility","visible"];var h="outline-style:none;border-style:none;padding:0px;margin:0px;visibility:visible;";if(!j.isDefined(a)){a=""}if(j.isString(f)&&(/[^\s]/).test(f)){f=f.toLowerCase().replace(/\s/g,"");p=j.openTag+f+' width="'+j.pluginSize+'" height="'+j.pluginSize+'" ';p+='style="'+h+'display:inline;" ';for(n=0;n<b.length;n=n+2){if(/[^\s]/.test(b[n+1])){p+=b[n]+'="'+b[n+1]+'" '}}p+=">";for(n=0;n<g.length;n=n+2){if(/[^\s]/.test(g[n+1])){p+=j.openTag+'param name="'+g[n]+'" value="'+g[n+1]+'" />'}}p+=a+j.openTag+"/"+f+">"}else{p=a}if(!j.div){i=m.getElementById(j.divID);if(i){j.div=i}else{j.div=m.createElement("div");j.div.id=j.divID}j.setStyle(j.div,c.concat(["width",j.divWidth+"px","height",(j.pluginSize+3)+"px","fontSize",(j.pluginSize+3)+"px","lineHeight",(j.pluginSize+3)+"px","verticalAlign","baseline","display","block"]));if(!i){j.setStyle(j.div,["position","absolute","right","0px","top","0px"]);j.insertDivInBody(j.div)}}if(j.div&&j.div.parentNode){j.setStyle(o,c.concat(["fontSize",(j.pluginSize+3)+"px","lineHeight",(j.pluginSize+3)+"px","verticalAlign","baseline","display","inline"]));try{o.innerHTML=p}catch(l){};try{j.div.appendChild(o)}catch(l){};return{span:o,winLoaded:j.winLoaded,tagName:f,outerHTML:p}}return{span:null,winLoaded:j.winLoaded,tagName:"",outerHTML:p}},Plugins:{quicktime:{mimeType:["video/quicktime","application/x-quicktimeplayer","image/x-macpaint","image/x-quicktime"],progID:"QuickTimeCheckObject.QuickTimeCheck.1",progID0:"QuickTime.QuickTime",classID:"clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B",minIEver:7,HTML:'<param name="src" value="" /><param name="controller" value="false" />',getCodeBaseVersion:function(a){return'codebase="#version='+a+'"'},SEARCH:{min:0,max:0,match:0,digits:[16,128,128,0]},getVersion:function(c){var f=this,d=f.$,a=null,e=null,b;if(!d.isIE){if(d.hasMimeType(f.mimeType)){e=d.OS!=3?d.findNavPlugin("QuickTime.*Plug-?in",0):null;if(e&&e.name){a=d.getNum(e.name)}}}else{if(d.isStrNum(c)){b=c.split(d.splitNumRegx);if(b.length>3&&parseInt(b[3],10)>0){b[3]="9999"}c=b.join(",")}if(d.isStrNum(c)&&d.verIE>=f.minIEver&&f.canUseIsMin()>0){f.installed=f.isMin(c);f.getVersionDone=0;return}f.getVersionDone=1;if(!a&&d.verIE>=f.minIEver){a=f.CDBASE2VER(d.codebaseSearch(f))}if(!a){e=d.getAXO(f.progID);if(e&&e.QuickTimeVersion){a=e.QuickTimeVersion.toString(16);a=parseInt(a.charAt(0),16)+"."+parseInt(a.charAt(1),16)+"."+parseInt(a.charAt(2),16)}}}f.installed=a?1:(e?0:-1);f.version=d.formatNum(a,3)},cdbaseUpper:["7,60,0,0","0,0,0,0"],cdbaseLower:["7,50,0,0",null],cdbase2ver:[function(c,b){var a=b.split(c.$.splitNumRegx);return[a[0],a[1].charAt(0),a[1].charAt(1),a[2]].join(",")},null],CDBASE2VER:function(f){var e=this,c=e.$,b,a=e.cdbaseUpper,d=e.cdbaseLower;
11424if(f){f=c.formatNum(f);for(b=0;b<a.length;b++){if(a[b]&&c.compareNums(f,a[b])<0&&d[b]&&c.compareNums(f,d[b])>=0&&e.cdbase2ver[b]){return e.cdbase2ver[b](e,f)}}}return f},canUseIsMin:function(){var f=this,d=f.$,b,c=f.canUseIsMin,a=f.cdbaseUpper,e=f.cdbaseLower;if(!c.value){c.value=-1;for(b=0;b<a.length;b++){if(a[b]&&d.codebaseSearch(f,a[b])){c.value=1;break}if(e[b]&&d.codebaseSearch(f,e[b])){c.value=-1;break}}}f.SEARCH.match=c.value==1?1:0;return c.value},isMin:function(c){var b=this,a=b.$;return a.codebaseSearch(b,c)?0.7:-1}},flash:{mimeType:"application/x-shockwave-flash",progID:"ShockwaveFlash.ShockwaveFlash",classID:"clsid:D27CDB6E-AE6D-11CF-96B8-444553540000",getVersion:function(){var b=function(i){if(!i){return null}var e=/[\d][\d\,\.\s]*[rRdD]{0,1}[\d\,]*/.exec(i);return e?e[0].replace(/[rRdD\.]/g,",").replace(/\s/g,""):null};var j=this,g=j.$,k,h,l=null,c=null,a=null,f,m,d;if(!g.isIE){m=g.hasMimeType(j.mimeType);if(m){f=g.getDOMobj(g.insertHTML("object",["type",j.mimeType],[],"",j));try{l=g.getNum(f.GetVariable("$version"))}catch(k){}}if(!l){d=m?m.enabledPlugin:null;if(d&&d.description){l=b(d.description)}if(l){l=g.getPluginFileVersion(d,l)}}}else{for(h=15;h>2;h--){c=g.getAXO(j.progID+"."+h);if(c){a=h.toString();break}}if(!c){c=g.getAXO(j.progID)}if(a=="6"){try{c.AllowScriptAccess="always"}catch(k){return"6,0,21,0"}}try{l=b(c.GetVariable("$version"))}catch(k){}if(!l&&a){l=a}}j.installed=l?1:-1;j.version=g.formatNum(l);return true}},shockwave:{mimeType:"application/x-director",progID:"SWCtl.SWCtl",classID:"clsid:166B1BCA-3F9C-11CF-8075-444553540000",getVersion:function(){var a=null,b=null,g,f,d=this,c=d.$;if(!c.isIE){f=c.findNavPlugin("Shockwave\\s*for\\s*Director");if(f&&f.description&&c.hasMimeType(d.mimeType)){a=c.getNum(f.description)}if(a){a=c.getPluginFileVersion(f,a)}}else{try{b=c.getAXO(d.progID).ShockwaveVersion("")}catch(g){}if(c.isString(b)&&b.length>0){a=c.getNum(b)}else{if(c.getAXO(d.progID+".8")){a="8"}else{if(c.getAXO(d.progID+".7")){a="7"}else{if(c.getAXO(d.progID+".1")){a="6"}}}}}d.installed=a?1:-1;d.version=c.formatNum(a)}},zz:0}};PluginDetect.initScript(); 11425 11426 var gArgCountErr='The "%%" function requires an even number of arguments.\nArguments should be in the form "atttributeName", "attributeValue", ...',gTagAttrs=null,gQTGeneratorVersion=1;function AC_QuickTimeVersion(){return gQTGeneratorVersion}function _QTComplain(a,b){b=b.replace("%%",a);alert(b)}function _QTAddAttribute(a,b,c){var d;d=gTagAttrs[a+b];null==d&&(d=gTagAttrs[b]);return null!=d?(0==b.indexOf(a)&&null==c&&(c=b.substring(a.length)),null==c&&(c=b),c+'="'+d+'" '):""}function _QTAddObjectAttr(a,b){if(0==a.indexOf("emb#"))return"";0==a.indexOf("obj#")&&null==b&&(b=a.substring(4));return _QTAddAttribute("obj#",a,b)}function _QTAddEmbedAttr(a,b){if(0==a.indexOf("obj#"))return"";0==a.indexOf("emb#")&&null==b&&(b=a.substring(4));return _QTAddAttribute("emb#",a,b)}function _QTAddObjectParam(a,b){var c,d="",e=b?" />":">";-1==a.indexOf("emb#")&&(c=gTagAttrs["obj#"+a],null==c&&(c=gTagAttrs[a]),0==a.indexOf("obj#")&&(a=a.substring(4)),null!=c&&(d=' <param name="'+a+'" value="'+c+'"'+e+"\n"));return d}function _QTDeleteTagAttrs(){for(var a=0;a<arguments.length;a++){var b=arguments[a];delete gTagAttrs[b];delete gTagAttrs["emb#"+b];delete gTagAttrs["obj#"+b]}}function _QTGenerate(a,b,c){if(4>c.length||0!=c.length%2)return _QTComplain(a,gArgCountErr),"";gTagAttrs=[];gTagAttrs.src=c[0];gTagAttrs.width=c[1];gTagAttrs.height=c[2];gTagAttrs.classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B";gTagAttrs.pluginspage="http://www.apple.com/quicktime/download/";a=c[3];if(null==a||""==a)a="6,0,2,0";gTagAttrs.codebase="http://www.apple.com/qtactivex/qtplugin.cab#version="+a;for(var d,e=4;e<c.length;e+=2)d=c[e].toLowerCase(),a=c[e+1],"name"==d||"id"==d?gTagAttrs.name=a:gTagAttrs[d]=a;c="<object "+_QTAddObjectAttr("classid")+_QTAddObjectAttr("width")+_QTAddObjectAttr("height")+_QTAddObjectAttr("codebase")+_QTAddObjectAttr("name","id")+_QTAddObjectAttr("tabindex")+_QTAddObjectAttr("hspace")+_QTAddObjectAttr("vspace")+_QTAddObjectAttr("border")+_QTAddObjectAttr("align")+_QTAddObjectAttr("class")+_QTAddObjectAttr("title")+_QTAddObjectAttr("accesskey")+_QTAddObjectAttr("noexternaldata")+">\n"+_QTAddObjectParam("src",b);e=" <embed "+_QTAddEmbedAttr("src")+_QTAddEmbedAttr("width")+_QTAddEmbedAttr("height")+_QTAddEmbedAttr("pluginspage")+_QTAddEmbedAttr("name")+_QTAddEmbedAttr("align")+_QTAddEmbedAttr("tabindex");_QTDeleteTagAttrs("src","width","height","pluginspage","classid","codebase","name","tabindex","hspace","vspace","border","align","noexternaldata","class","title","accesskey");for(d in gTagAttrs)a=gTagAttrs[d],null!=a&&(e+=_QTAddEmbedAttr(d),c+=_QTAddObjectParam(d,b));return c+e+"> </embed>\n</object>"}function QT_GenerateOBJECTText(){return _QTGenerate("QT_GenerateOBJECTText",!1,arguments)}; 11427 11428 11429 /* 11430 jQuery hashchange event v1.3 11431 https://github.com/cowboy/jquery-hashchange 11432 Copyright (c) 2010 "Cowboy" Ben Alman 11433 Dual licensed under the MIT and GPL licenses. 11434 */ 11435 (function(){function e(a){a=a||location.href;return"#"+a.replace(/^[^#]*#?(.*)$/,"$1")}var k=document,b,f=$.event.special,p=k.documentMode,m="oniLightBoxHashChange"in window&&(void 0===p||7<p);$.fn.iLightBoxHashChange=function(a){return a?this.bind("iLightBoxHashChange",a):this.trigger("iLightBoxHashChange")};$.fn.iLightBoxHashChange.delay=50;f.iLightBoxHashChange=$.extend(f.iLightBoxHashChange,{setup:function(){if(m)return!1;$(b.start)},teardown:function(){if(m)return!1;$(b.stop)}});b=function(){function a(){var c= 11436 e(),d=f(l);c!==l?(n(l=c,d),$(window).trigger("iLightBoxHashChange")):d!==l&&(location.href=location.href.replace(/#.*/,"")+d);g=setTimeout(a,$.fn.iLightBoxHashChange.delay)}var h={},g,l=e(),b=function(c){return c},n=b,f=b;h.start=function(){g||a()};h.stop=function(){g&&clearTimeout(g);g=void 0};browser.msie&&!m&&function(){var c,d;h.start=function(){c||(d=(d=$.fn.iLightBoxHashChange.src)&&d+e(),c=$('<iframe tabindex="-1" title="empty"/>').hide().one("load",function(){d||n(e());a()}).attr("src",d|| 11437 "javascript:0").insertAfter("body")[0].contentWindow,k.onpropertychange=function(){try{"title"===event.propertyName&&(c.document.title=k.title)}catch(a){}})};h.stop=b;f=function(){return e(c.location.href)};n=function(a,d){var b=c.document,e=$.fn.iLightBoxHashChange.domain;
11437a!==d&&(b.title=k.title,b.open(),e&&b.write('<script>document.domain="'+e+'"\x3c/script>'),b.close(),c.location.hash=a)}}();return h}()})(); 11438 11439 if (!Array.prototype.filter) { 11440 Array.prototype.filter = function(fun /*, thisp */ ) { 11441 "use strict"; 11442 11443 if (this == null) 11444 throw new TypeError(); 11445 11446 var t = Object(this); 11447 var len = t.length >>> 0; 11448 if (typeof fun != "function") 11449 throw new TypeError(); 11450 11451 var res = []; 11452 var thisp = arguments[1]; 11453 for (var i = 0; i < len; i++) { 11454 if (i in t) { 11455 var val = t[i]; // in case fun mutates this 11456 if (fun.call(thisp, val, i, t)) 11457 res.push(val); 11458 } 11459 } 11460 11461 return res; 11462 }; 11463 } 11464 11465 if (!Array.prototype.indexOf) { 11466 Array.prototype.indexOf = function(searchElement, fromIndex) { 11467 var k; 11468 11469 if (this == null) { 11470 throw new TypeError('"this" is null or not defined'); 11471 } 11472 11473 var O = Object(this); 11474 11475 var len = O.length >>> 0; 11476 11477 if (len === 0) { 11478 return -1; 11479 } 11480 11481 var n = +fromIndex || 0; 11482 11483 if (abs(n) === Infinity) { 11484 n = 0; 11485 } 11486 11487 if (n >= len) { 11488 return -1; 11489 } 11490 11491 k = max(n >= 0 ? n : len - abs(n), 0); 11492 11493 while (k < len) { 11494 var kValue; 11495 if (k in O && O[k] === searchElement) { 11496 return k; 11497 } 11498 k++; 11499 } 11500 return -1; 11501 }; 11502 } 11503 11504 if (!Array.prototype.lastIndexOf) { 11505 Array.prototype.lastIndexOf = function(searchElement /*, fromIndex*/ ) { 11506 "use strict"; 11507 11508 if (this == null) 11509 throw new TypeError(); 11510 11511 var t = Object(this); 11512 var len = t.length >>> 0; 11513 if (len === 0) 11514 return -1; 11515 11516 var n = len; 11517 if (arguments.length > 1) { 11518 n = Number(arguments[1]); 11519 if (n != n) 11520 n = 0; 11521 else if (n != 0 && n != (1 / 0) && n != -(1 / 0)) 11522 n = (n > 0 || -1) * floor(abs(n)); 11523 } 11524 11525 var k = n >= 0 ? min(n, len - 1) : len - abs(n); 11526 11527 for (; k >= 0; k--) { 11528 if (k in t && t[k] === searchElement) 11529 return k; 11530 } 11531 return -1; 11532 }; 11533 } 11534})(jQuery, this); 11535 11536/** 11537 * Owl carousel
vendor: 12,108 bytes, lines 11538-12044
11538 * @version 2.0.0-beta.3 11539 * @author Bartosz Wojciechowski 11540 * @license The MIT License (MIT) 11541 * @todo Lazy Load Icon 11542 * @todo prevent animationend bubling 11543 * @todo itemsScaleUp 11544 * @todo Test Zepto 11545 * @todo stagePadding calculate wrong active classes 11546 */ 11547;(function($, window, document, undefined) { 11548 11549 /** 11550 * Creates a carousel. 11551 * @class The Owl Carousel. 11552 * @public 11553 * @param {HTMLElement|jQuery} element - The element to create the carousel for. 11554 * @param {Object} [options] - The options 11555 */ 11556 function Owl(element, options) { 11557 11558 /** 11559 * Current settings for the carousel. 11560 * @public 11561 */ 11562 this.settings = null; 11563 11564 /** 11565 * Current options set by the caller including defaults. 11566 * @public 11567 */ 11568 this.options = $.extend({}, Owl.Defaults, options); 11569 11570 /** 11571 * Plugin element. 11572 * @public 11573 */ 11574 this.$element = $(element); 11575 11576 /** 11577 * Proxied event handlers. 11578 * @protected 11579 */ 11580 this._handlers = {}; 11581 11582 /** 11583 * References to the running plugins of this carousel. 11584 * @protected 11585 */ 11586 this._plugins = {}; 11587 11588 /** 11589 * Currently suppressed events to prevent them from beeing retriggered. 11590 * @protected 11591 */ 11592 this._supress = {}; 11593 11594 /** 11595 * Absolute current position. 11596 * @protected 11597 */ 11598 this._current = null; 11599 11600 /** 11601 * Animation speed in milliseconds. 11602 * @protected 11603 */ 11604 this._speed = null; 11605 11606 /** 11607 * Coordinates of all items in pixel. 11608 * @todo The name of this member is missleading. 11609 * @protected 11610 */ 11611 this._coordinates = []; 11612 11613 /** 11614 * Current breakpoint. 11615 * @todo Real media queries would be nice. 11616 * @protected 11617 */ 11618 this._breakpoint = null; 11619 11620 /** 11621 * Current width of the plugin element. 11622 */ 11623 this._width = null; 11624 11625 /** 11626 * All real items. 11627 * @protected 11628 */ 11629 this._items = []; 11630 11631 /** 11632 * All cloned items. 11633 * @protected 11634 */ 11635 this._clones = []; 11636 11637 /** 11638 * Merge values of all items. 11639 * @todo Maybe this could be part of a plugin. 11640 * @protected 11641 */ 11642 this._mergers = []; 11643 11644 /** 11645 * Widths of all items. 11646 */ 11647 this._widths = []; 11648 11649 /** 11650 * Invalidated parts within the update process. 11651 * @protected 11652 */ 11653 this._invalidated = {}; 11654 11655 /** 11656 * Ordered list of workers for the update process. 11657 * @protected 11658 */ 11659 this._pipe = []; 11660 11661 /** 11662 * Current state information for the drag operation. 11663 * @todo #261 11664 * @protected 11665 */ 11666 this._drag = { 11667 time: null, 11668 target: null, 11669 pointer: null, 11670 stage: { 11671 start: null, 11672 current: null 11673 }, 11674 direction: null 11675 }; 11676 11677 /** 11678 * Current state information and their tags. 11679 * @type {Object} 11680 * @protected 11681 */ 11682 this._states = { 11683 current: {}, 11684 tags: { 11685 'initializing': [ 'busy' ], 11686 'animating': [ 'busy' ], 11687 'dragging': [ 'interacting' ] 11688 } 11689 }; 11690 11691 $.each([ 'onResize', 'onThrottledResize' ], $.proxy(function(i, handler) { 11692 this._handlers[handler] = $.proxy(this[handler], this); 11693 }, this)); 11694 11695 $.each(Owl.Plugins, $.proxy(function(key, plugin) { 11696 this._plugins[key.charAt(0).toLowerCase() + key.slice(1)] 11697 = new plugin(this); 11698 }, this)); 11699 11700 $.each(Owl.Workers, $.proxy(function(priority, worker) { 11701 this._pipe.push({ 11702 'filter': worker.filter, 11703 'run': $.proxy(worker.run, this) 11704 }); 11705 }, this)); 11706 11707 this.setup(); 11708 this.initialize(); 11709 } 11710 11711 /** 11712 * Default options for the carousel. 11713 * @public 11714 */ 11715 Owl.Defaults = { 11716 items: 3, 11717 loop: false, 11718 center: false, 11719 rewind: false, 11720 11721 mouseDrag: true, 11722 touchDrag: true, 11723 pullDrag: true, 11724 freeDrag: false, 11725 11726 margin: 0, 11727 stagePadding: 0, 11728 11729 merge: false, 11730 mergeFit: true, 11731 autoWidth: false, 11732 11733 startPosition: 0, 11734 rtl: false, 11735 11736 smartSpeed: 250, 11737 fluidSpeed: false, 11738 dragEndSpeed: false, 11739 11740 responsive: {}, 11741 responsiveRefreshRate: 200, 11742 responsiveBaseElement: window, 11743 11744 fallbackEasing: 'swing', 11745 11746 info: false, 11747 11748 nestedItemSelector: false, 11749 itemElement: 'div', 11750 stageElement: 'div', 11751 11752 refreshClass: 'owl-refresh', 11753 loadedClass: 'owl-loaded', 11754 loadingClass: 'owl-loading', 11755 rtlClass: 'owl-rtl', 11756 responsiveClass: 'owl-responsive', 11757 dragClass: 'owl-drag', 11758 itemClass: 'owl-item', 11759 stageClass: 'owl-stage', 11760 stageOuterClass: 'owl-stage-outer', 11761 grabClass: 'owl-grab' 11762 }; 11763 11764 /** 11765 * Enumeration for width. 11766 * @public 11767 * @readonly 11768 * @enum {String} 11769 */ 11770 Owl.Width = { 11771 Default: 'default', 11772 Inner: 'inner', 11773 Outer: 'outer' 11774 }; 11775 11776 /** 11777 * Enumeration for types. 11778 * @public 11779 * @readonly 11780 * @enum {String} 11781 */ 11782 Owl.Type = { 11783 Event: 'event', 11784 State: 'state' 11785 }; 11786 11787 /** 11788 * Contains all registered plugins. 11789 * @public 11790 */ 11791 Owl.Plugins = {}; 11792 11793 /** 11794 * List of workers involved in the update process. 11795 */ 11796 Owl.Workers = [ { 11797 filter: [ 'width', 'settings' ], 11798 run: function() { 11799 this._width = (this.$element.closest('.px-gutter').length) ? 12 * Math.ceil(this.$element.width() / 12) : this.$element.width(); 11800 //this._width = (UNCODE.isMobile) ? this.$element.width() : 12 * Math.ceil(this.$element.width() / 12); 11801 } 11802 }, { 11803 filter: [ 'width', 'items', 'settings' ], 11804 run: function(cache) { 11805 cache.current = this._items && this._items[this.relative(this._current)]; 11806 } 11807 }, { 11808 filter: [ 'items', 'settings' ], 11809 run: function() { 11810 this.$stage.children('.cloned').remove(); 11811 } 11812 }, { 11813 filter: [ 'width', 'items', 'settings' ], 11814 run: function(cache) { 11815 var margin = this.settings.margin || '', 11816 grid = !this.settings.autoWidth, 11817 rtl = this.settings.rtl, 11818 css = { 11819 'width': 'auto', 11820 'margin-left': rtl ? margin : '', 11821 'margin-right': rtl ? '' : margin 11822 }; 11823 11824 !grid && this.$stage.children().css(css); 11825 11826 cache.css = css; 11827 } 11828 }, { 11829 filter: [ 'width', 'items', 'settings' ], 11830 run: function(cache) { 11831 //UNCODE edit to fix Chrome stage padding issue 11832 var width = Math.round((this.width() / this.settings.items).toFixed(3) - this.settings.margin), 11833 merge = null, 11834 iterator = this._items.length, 11835 grid = !this.settings.autoWidth, 11836 widths = []; 11837 11838 cache.items = { 11839 merge: false, 11840 width: width 11841 }; 11842 11843 while (iterator--) { 11844 merge = this._mergers[iterator]; 11845 merge = this.settings.mergeFit && Math.min(merge, this.settings.items) || merge; 11846 11847 cache.items.merge = merge > 1 || cache.items.merge; 11848 11849 widths[iterator] = !grid ? this._items[iterator].width() : width * merge; 11850 } 11851 11852 this._widths = widths; 11853 } 11854 }, { 11855 filter: [ 'items', 'settings' ], 11856 run: function() { 11857 var clones = [], 11858 items = this._items, 11859 settings = this.settings, 11860 view = Math.max(settings.items * 2, 4), 11861 size = Math.ceil(items.length / 2) * 2, 11862 repeat = settings.loop && items.length ? settings.rewind ? view : Math.max(view, size) : 0, 11863 append = '', 11864 prepend = ''; 11865 11866 repeat /= 2; 11867 11868 while (repeat--) { 11869 clones.push(this.normalize(clones.length / 2, true)); 11870 append = append + items[clones[clones.length - 1]][0].outerHTML; 11871 clones.push(this.normalize(items.length - 1 - (clones.length - 1) / 2, true)); 11872 prepend = items[clones[clones.length - 1]][0].outerHTML + prepend; 11873 } 11874 11875 this._clones = clones; 11876 11877 // var appendVideo = $(append).find('.uncode-video-container'); 11878 // if (appendVideo.length) { 11879 // appendVideo.attr('data-id', Math.round(Math.random() * 100000)); 11880 // } 11881 // var prependVideo = $(prepend).find('.uncode-video-container'); 11882 // if (prependVideo.length) { 11883 // prependVideo.attr('data-id', Math.round(Math.random() * 100000)); 11884 // } 11885 $(append).addClass('cloned').appendTo(this.$stage); 11886 $(prepend).addClass('cloned').prependTo(this.$stage); 11887 } 11888 }, { 11889 filter: [ 'width', 'items', 'settings' ], 11890 run: function() { 11891 var rtl = this.settings.rtl ? 1 : -1, 11892 size = this._clones.length + this._items.length, 11893 iterator = -1, 11894 previous = 0, 11895 current = 0, 11896 coordinates = []; 11897 11898 while (++iterator < size) { 11899 previous = coordinates[iterator - 1] || 0; 11900 current = this._widths[this.relative(iterator)] + this.settings.margin; 11901 coordinates.push(previous + current * rtl); 11902 } 11903 11904 this._coordinates = coordinates; 11905 } 11906 }, { 11907 filter: [ 'width', 'items', 'settings' ], 11908 run: function() { 11909 var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200, 11910 padding = stagePadding, 11911 coordinates = this._coordinates, 11912 css = { 11913 'width': Math.ceil(Math.abs(coordinates[coordinates.length - 1])) + padding * 2, 11914 'padding-left': padding || '', 11915 'padding-right': padding || '' 11916 }; 11917 11918 this.$stage.css(css); 11919 } 11920 }, { 11921 filter: [ 'width', 'items', 'settings' ], 11922 run: function(cache) { 11923 var iterator = this._coordinates.length, 11924 grid = !this.settings.autoWidth, 11925 items = this.$stage.children(); 11926 11927 if (grid && cache.items.merge) { 11928 while (iterator--) { 11929 cache.css.width = this._widths[this.relative(iterator)]; 11930 items.eq(iterator).css(cache.css); 11931 } 11932 } else if (grid) { 11933 cache.css.width = cache.items.width; 11934 items.css(cache.css); 11935 } 11936 } 11937 }, { 11938 filter: [ 'items' ], 11939 run: function() { 11940 this._coordinates.length < 1 && this.$stage.removeAttr('style'); 11941 } 11942 }, { 11943 filter: [ 'width', 'items', 'settings' ], 11944 run: function(cache) { 11945 cache.current = cache.current ? this.$stage.children().index(cache.current) : 0; 11946 cache.current = Math.max(this.minimum(), Math.min(this.maximum(), cache.current)); 11947 this.reset(cache.current); 11948 } 11949 }, { 11950 filter: [ 'position' ], 11951 run: function() { 11952 this.animate(this.coordinates(this._current)); 11953 } 11954 }, { 11955 filter: [ 'width', 'position', 'items', 'settings' ], 11956 run: function() { 11957 var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200, 11958 rtl = this.settings.rtl ? 1 : -1, 11959 padding = this.settings.stagePadding * 2, 11960 begin = this.coordinates(this.current()) + padding, 11961 end = begin + this.width() * rtl, 11962 inner, outer, matches = [], i, n; 11963 11964 for (i = 0, n = this._coordinates.length; i < n; i++) { 11965 inner = this._coordinates[i - 1] || 0; 11966 outer = Math.abs(this._coordinates[i]) + padding * rtl; 11967 11968 if ((this.op(inner, '<=', begin) && (this.op(inner, '>', end))) 11969 || (this.op(outer, '<', begin) && this.op(outer, '>', end))) { 11970 matches.push(i); 11971 } 11972 } 11973 11974 this.$stage.children('.active').removeClass('active'); 11975 this.$stage.children(':eq(' + matches.join('), :eq(') + ')').addClass('active'); 11976 11977 if (this.settings.center) { 11978 this.$stage.children('.center').removeClass('center'); 11979 this.$stage.children().eq(this.current()).addClass('center'); 11980 } 11981 } 11982 } ]; 11983 11984 /** 11985 * Initializes the carousel. 11986 * @protected 11987 */ 11988 Owl.prototype.initialize = function() { 11989 this.enter('initializing'); 11990 this.trigger('initialize'); 11991 11992 this.$element.toggleClass(this.settings.rtlClass, this.settings.rtl); 11993 11994 if (this.settings.autoWidth && !this.is('pre-loading')) { 11995 var imgs, nestedSelector, width; 11996 imgs = this.$element.find('img'); 11997 nestedSelector = this.settings.nestedItemSelector ? '.' + this.settings.nestedItemSelector : undefined; 11998 width = this.$element.children(nestedSelector).width(); 11999 12000 if (imgs.length && width <= 0) { 12001 this.preloadAutoWidthImages(imgs); 12002 } 12003 } 12004 12005 this.$element.addClass(this.options.loadingClass); 12006 12007 // create stage 12008 this.$stage = $('<' + this.settings.stageElement + ' class="' + this.settings.stageClass + '"/>') 12009 .wrap('<div class="' + this.settings.stageOuterClass + '"/>'); 12010 12011 // append stage 12012 this.$element.append(this.$stage.parent()); 12013 12014 // append content 12015 this.replace(this.$element.children().not(this.$stage.parent())); 12016 12017 // check visibility 12018 if (this.$element.is(':visible')) { 12019 // update view 12020 this.refresh(); 12021 } else { 12022 // invalidate width 12023 this.invalidate('width'); 12024 } 12025 12026 this.$element 12027 .removeClass(this.options.loadingClass) 12028 .addClass(this.options.loadedClass); 12029 12030 // register event handlers 12031 this.registerEventHandlers(); 12032 12033 this.leave('initializing'); 12034 this.trigger('initialized'); 12035 }; 12036 12037 /** 12038 * Setups the current settings. 12039 * @todo Remove responsive classes. Why should adaptive designs be brought into IE8? 12040 * @todo Support for media queries by using `matchMedia` would be nice. 12041 * @public 12042 */ 12043 Owl.prototype.setup = function() { 12044 var viewport = this.viewport(),
12045 overwrites = this.options.responsive, 12046 match = -1, 12047 settings = null; 12048 12049 if (!overwrites) { 12050 settings = $.extend({}, this.options); 12051 } else { 12052 $.each(overwrites, function(breakpoint) { 12053 if (breakpoint <= viewport && breakpoint > match) { 12054 match = Number(breakpoint); 12055 } 12056 }); 12057 12058 settings = $.extend({}, this.options, overwrites[match]); 12059 delete settings.responsive; 12060 12061 // responsive class 12062 if (settings.responsiveClass) { 12063 this.$element.attr('class', 12064 this.$element.attr('class').replace(new RegExp('(' + this.options.responsiveClass + '-)\\S+\\s', 'g'), '$1' + match) 12065 ); 12066 } 12067 } 12068 12069 if (this.settings === null || this._breakpoint !== match) { 12070 this.trigger('change', { property: { name: 'settings', value: settings } }); 12071 this._breakpoint = match; 12072 this.settings = settings; 12073 this.invalidate('settings'); 12074 this.trigger('changed', { property: { name: 'settings', value: this.settings } }); 12075 } 12076 }; 12077 12078 /** 12079 * Updates option logic if necessery. 12080 * @protected 12081 */ 12082 Owl.prototype.optionsLogic = function() { 12083 if (this.settings.autoWidth) { 12084 this.settings.stagePadding = false; 12085 this.settings.merge = false; 12086 } 12087 }; 12088 12089 /** 12090 * Prepares an item before add. 12091 * @todo Rename event parameter `content` to `item`. 12092 * @protected 12093 * @returns {jQuery|HTMLElement} - The item container. 12094 */ 12095 Owl.prototype.prepare = function(item, index) { 12096 var event = this.trigger('prepare', { content: item }); 12097 if (!event.data) { 12098 event.data = $('<' + this.settings.itemElement + '/>') 12099 .addClass(this.options.itemClass).attr('data-index', index + 1).append(item) 12100 } 12101 12102 this.trigger('prepared', { content: event.data }); 12103 12104 return event.data; 12105 }; 12106 12107 /** 12108 * Updates the view. 12109 * @public 12110 */ 12111 Owl.prototype.update = function() { 12112 var i = 0, 12113 n = this._pipe.length, 12114 filter = $.proxy(function(p) { return this[p] }, this._invalidated), 12115 cache = {}; 12116 12117 while (i < n) { 12118 if (this._invalidated.all || $.grep(this._pipe[i].filter, filter).length > 0) { 12119 this._pipe[i].run(cache); 12120 } 12121 i++; 12122 } 12123 12124 this._invalidated = {}; 12125 12126 !this.is('valid') && this.enter('valid'); 12127 }; 12128 12129 /** 12130 * Gets the width of the view. 12131 * @public 12132 * @param {Owl.Width} [dimension=Owl.Width.Default] - The dimension to return. 12133 * @returns {Number} - The width of the view in pixel. 12134 */ 12135 Owl.prototype.width = function(dimension) { 12136 dimension = dimension || Owl.Width.Default; 12137 var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200; 12138 switch (dimension) { 12139 case Owl.Width.Inner: 12140 case Owl.Width.Outer: 12141 return this._width; 12142 default: 12143 return this._width - stagePadding * 2 + this.settings.margin; 12144 } 12145 }; 12146 12147 /** 12148 * Refreshes the carousel primarily for adaptive purposes. 12149 * @public 12150 */ 12151 Owl.prototype.refresh = function() { 12152 this.enter('refreshing'); 12153 this.trigger('refresh'); 12154 12155 this.setup(); 12156 12157 this.optionsLogic(); 12158 12159 this.$element.addClass(this.options.refreshClass); 12160 12161 this.update(); 12162 12163 this.$element.removeClass(this.options.refreshClass); 12164 12165 this.leave('refreshing'); 12166 this.trigger('refreshed'); 12167 }; 12168 12169 /** 12170 * Checks window `resize` event. 12171 * @protected 12172 */ 12173 Owl.prototype.onThrottledResize = function() { 12174 window.clearTimeout(this.resizeTimer); 12175 this.resizeTimer = window.setTimeout(this._handlers.onResize, this.settings.responsiveRefreshRate); 12176 }; 12177 12178 /** 12179 * Checks window `resize` event. 12180 * @protected 12181 */ 12182 Owl.prototype.onResize = function() { 12183 if (!this._items.length) { 12184 return false; 12185 } 12186 12187 if (this._width === this.$element.width()) { 12188 return false; 12189 } 12190 12191 if (!this.$element.is(':visible')) { 12192 return false; 12193 } 12194 12195 this.enter('resizing'); 12196 12197 if (this.trigger('resize').isDefaultPrevented()) { 12198 this.leave('resizing'); 12199 return false; 12200 } 12201 12202 this.invalidate('width'); 12203 12204 this.refresh(); 12205 12206 this.leave('resizing'); 12207 this.trigger('resized'); 12208 }; 12209 12210 /** 12211 * Registers event handlers. 12212 * @todo Check `msPointerEnabled` 12213 * @todo #261 12214 * @protected 12215 */ 12216 Owl.prototype.registerEventHandlers = function() { 12217 if ($.support.transition) { 12218 this.$stage.on($.support.transition.end + '.owl.core', $.proxy(this.onTransitionEnd, this)); 12219 } 12220 12221 if (this.settings.responsive !== false) { 12222 this.on(window, 'resize', this._handlers.onThrottledResize); 12223 } 12224 12225 if (this.settings.mouseDrag) { 12226 this.$element.addClass(this.options.dragClass); 12227 this.$stage.on('mousedown.owl.core', $.proxy(this.onDragStart, this)); 12228 this.$stage.on('dragstart.owl.core selectstart.owl.core', function() { return false }); 12229 } 12230 12231 if (this.settings.touchDrag){ 12232 this.$stage.on('touchstart.owl.core', $.proxy(this.onDragStart, this)); 12233 this.$stage.on('touchcancel.owl.core', $.proxy(this.onDragEnd, this)); 12234 } 12235 }; 12236 12237 /** 12238 * Handles `touchstart` and `mousedown` events. 12239 * @todo Horizontal swipe threshold as option 12240 * @todo #261 12241 * @protected 12242 * @param {Event} event - The event arguments. 12243 */ 12244 Owl.prototype.onDragStart = function(event) { 12245 var stage = null; 12246 12247 if (event.which === 3) { 12248 return; 12249 } 12250
vendor: 9,106 bytes, lines 12251-12566
12251 if ($.support.transform) { 12252 stage = this.$stage.css('transform').replace(/.*\(|\)| /g, '').split(','); 12253 stage = { 12254 x: stage[stage.length === 16 ? 12 : 4], 12255 y: stage[stage.length === 16 ? 13 : 5] 12256 }; 12257 } else { 12258 stage = this.$stage.position(); 12259 stage = { 12260 x: this.settings.rtl ? 12261 stage.left + this.$stage.width() - this.width() + this.settings.margin : 12262 stage.left, 12263 y: stage.top 12264 }; 12265 } 12266 12267 if (this.is('animating')) { 12268 $.support.transform ? this.animate(stage.x) : this.$stage.stop() 12269 this.invalidate('position'); 12270 } 12271 12272 this.$element.toggleClass(this.options.grabClass, event.type === 'mousedown'); 12273 12274 this.speed(0); 12275 12276 this._drag.time = new Date().getTime(); 12277 this._drag.target = $(event.target); 12278 this._drag.stage.start = stage; 12279 this._drag.stage.current = stage; 12280 this._drag.pointer = this.pointer(event); 12281 12282 $(document).on('mouseup.owl.core touchend.owl.core', $.proxy(this.onDragEnd, this)); 12283 12284 $(document).one('mousemove.owl.core touchmove.owl.core', $.proxy(function(event) { 12285 var delta = this.difference(this._drag.pointer, this.pointer(event)); 12286 12287 $(document).on('mousemove.owl.core touchmove.owl.core', $.proxy(this.onDragMove, this)); 12288 12289 if (Math.abs(delta.x) < Math.abs(delta.y) && this.is('valid')) { 12290 return; 12291 } 12292 12293 event.preventDefault(); 12294 12295 this.enter('dragging'); 12296 this.trigger('drag'); 12297 }, this)); 12298 }; 12299 12300 /** 12301 * Handles the `touchmove` and `mousemove` events. 12302 * @todo #261 12303 * @protected 12304 * @param {Event} event - The event arguments. 12305 */ 12306 Owl.prototype.onDragMove = function(event) { 12307 var minimum = null, 12308 maximum = null, 12309 pull = null, 12310 delta = this.difference(this._drag.pointer, this.pointer(event)), 12311 stage = this.difference(this._drag.stage.start, delta); 12312 12313 if (!this.is('dragging')) { 12314 return; 12315 } 12316 12317 event.preventDefault(); 12318 12319 if (this.settings.loop) { 12320 minimum = this.coordinates(this.minimum()); 12321 maximum = this.coordinates(this.maximum() + 1) - minimum; 12322 stage.x = (((stage.x - minimum) % maximum + maximum) % maximum) + minimum; 12323 } else { 12324 minimum = this.settings.rtl ? this.coordinates(this.maximum()) : this.coordinates(this.minimum()); 12325 maximum = this.settings.rtl ? this.coordinates(this.minimum()) : this.coordinates(this.maximum()); 12326 pull = this.settings.pullDrag ? -1 * delta.x / 5 : 0; 12327 stage.x = Math.max(Math.min(stage.x, minimum + pull), maximum + pull); 12328 } 12329 12330 this._drag.stage.current = stage; 12331 12332 this.animate(stage.x); 12333 }; 12334 12335 /** 12336 * Handles the `touchend` and `mouseup` events. 12337 * @todo #261 12338 * @todo Threshold for click event 12339 * @protected 12340 * @param {Event} event - The event arguments. 12341 */ 12342 Owl.prototype.onDragEnd = function(event) { 12343 var delta = this.difference(this._drag.pointer, this.pointer(event)), 12344 stage = this._drag.stage.current, 12345 direction = delta.x > 0 ^ this.settings.rtl ? 'left' : 'right'; 12346 12347 $(document).off('.owl.core'); 12348 12349 this.$element.removeClass(this.options.grabClass); 12350 12351 if (delta.x !== 0 && this.is('dragging') || !this.is('valid')) { 12352 this.speed(this.settings.dragEndSpeed || this.settings.smartSpeed); 12353 this.current(this.closest(stage.x, delta.x !== 0 ? direction : this._drag.direction)); 12354 this.invalidate('position'); 12355 this.update(); 12356 12357 this._drag.direction = direction; 12358 12359 if (Math.abs(delta.x) > 3 || new Date().getTime() - this._drag.time > 300) { 12360 this._drag.target.one('click.owl.core', function() { return false; }); 12361 } 12362 } 12363 12364 if (!this.is('dragging')) { 12365 return; 12366 } 12367 12368 this.leave('dragging'); 12369 this.trigger('dragged'); 12370 }; 12371 12372 /** 12373 * Gets absolute position of the closest item for a coordinate. 12374 * @todo Setting `freeDrag` makes `closest` not reusable. See #165. 12375 * @protected 12376 * @param {Number} coordinate - The coordinate in pixel. 12377 * @param {String} direction - The direction to check for the closest item. Ether `left` or `right`. 12378 * @return {Number} - The absolute position of the closest item. 12379 */ 12380 Owl.prototype.closest = function(coordinate, direction) { 12381 var position = -1, 12382 pull = 30, 12383 width = this.width(), 12384 coordinates = this.coordinates(); 12385 12386 if (!this.settings.freeDrag) { 12387 // check closest item 12388 $.each(coordinates, $.proxy(function(index, value) { 12389 if (coordinate > value - pull && coordinate < value + pull) { 12390 position = index; 12391 } else if (this.op(coordinate, '<', value) 12392 && this.op(coordinate, '>', coordinates[index + 1] || value - width)) { 12393 position = direction === 'left' ? index + 1 : index; 12394 } 12395 return position === -1; 12396 }, this)); 12397 } 12398 12399 if (!this.settings.loop) { 12400 // non loop boundries 12401 if (this.op(coordinate, '>', coordinates[this.minimum()])) { 12402 position = coordinate = this.minimum(); 12403 } else if (this.op(coordinate, '<', coordinates[this.maximum()])) { 12404 position = coordinate = this.maximum(); 12405 } 12406 } 12407 12408 return position; 12409 }; 12410 12411 /** 12412 * Animates the stage. 12413 * @todo #270 12414 * @public 12415 * @param {Number} coordinate - The coordinate in pixels. 12416 */ 12417 Owl.prototype.animate = function(coordinate) { 12418 var animate = this.speed() > 0; 12419 12420 this.is('animating') && this.onTransitionEnd(); 12421 12422 if (animate) { 12423 this.enter('animating'); 12424 this.trigger('translate'); 12425 } 12426 12427 if ($.support.transform3d && $.support.transition) { 12428 this.$stage.css({ 12429 transform: 'translate3d(' + coordinate + 'px,0px,0px)', 12430 transition: (this.speed() / 1000) + 's' 12431 }); 12432 } else if (animate) { 12433 this.$stage.animate({ 12434 left: coordinate + 'px' 12435 }, this.speed(), this.settings.fallbackEasing, $.proxy(this.onTransitionEnd, this)); 12436 } else { 12437 this.$stage.css({ 12438 left: coordinate + 'px' 12439 }); 12440 } 12441 }; 12442 12443 /** 12444 * Checks whether the carousel is in a specific state or not. 12445 * @param {String} state - The state to check. 12446 * @returns {Boolean} - The flag which indicates if the carousel is busy. 12447 */ 12448 Owl.prototype.is = function(state) { 12449 return this._states.current[state] && this._states.current[state] > 0; 12450 }; 12451 12452 /** 12453 * Sets the absolute position of the current item. 12454 * @public 12455 * @param {Number} [position] - The new absolute position or nothing to leave it unchanged. 12456 * @returns {Number} - The absolute position of the current item. 12457 */ 12458 Owl.prototype.current = function(position) { 12459 if (position === undefined) { 12460 return this._current; 12461 } 12462 12463 if (this._items.length === 0) { 12464 return undefined; 12465 } 12466 12467 position = this.normalize(position); 12468 12469 if (this._current !== position) { 12470 var event = this.trigger('change', { property: { name: 'position', value: position } }); 12471 12472 if (event.data !== undefined) { 12473 position = this.normalize(event.data); 12474 } 12475 12476 this._current = position; 12477 12478 this.invalidate('position'); 12479 12480 this.trigger('changed', { property: { name: 'position', value: this._current } }); 12481 } 12482 12483 return this._current; 12484 }; 12485 12486 /** 12487 * Invalidates the given part of the update routine. 12488 * @param {String} [part] - The part to invalidate. 12489 * @returns {Array.<String>} - The invalidated parts. 12490 */ 12491 Owl.prototype.invalidate = function(part) { 12492 if ($.type(part) === 'string') { 12493 this._invalidated[part] = true; 12494 this.is('valid') && this.leave('valid'); 12495 } 12496 return $.map(this._invalidated, function(v, i) { return i }); 12497 }; 12498 12499 /** 12500 * Resets the absolute position of the current item. 12501 * @public 12502 * @param {Number} position - The absolute position of the new item. 12503 */ 12504 Owl.prototype.reset = function(position) { 12505 position = this.normalize(position); 12506 12507 if (position === undefined) { 12508 return; 12509 } 12510 12511 this._speed = 0; 12512 this._current = position; 12513 12514 this.suppress([ 'translate', 'translated' ]); 12515 12516 this.animate(this.coordinates(position)); 12517 12518 this.release([ 'translate', 'translated' ]); 12519 }; 12520 12521 /** 12522 * Normalizes an absolute or a relative position of an item. 12523 * @public 12524 * @param {Number} position - The absolute or relative position to normalize. 12525 * @param {Boolean} [relative=false] - Whether the given position is relative or not. 12526 * @returns {Number} - The normalized position. 12527 */ 12528 Owl.prototype.normalize = function(position, relative) { 12529 var n = this._items.length, 12530 m = relative ? 0 : this._clones.length; 12531 12532 if (!$.isNumeric(position) || n < 1) { 12533 position = undefined; 12534 } else if (position < 0 || position >= n + m) { 12535 position = ((position - m / 2) % n + n) % n + m / 2; 12536 } 12537 12538 return position; 12539 }; 12540 12541 /** 12542 * Converts an absolute position of an item into a relative one. 12543 * @public 12544 * @param {Number} position - The absolute position to convert. 12545 * @returns {Number} - The converted position. 12546 */ 12547 Owl.prototype.relative = function(position) { 12548 position -= this._clones.length / 2; 12549 return this.normalize(position, true); 12550 }; 12551 12552 /** 12553 * Gets the maximum position for the current item. 12554 * @public 12555 * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position. 12556 * @returns {Number} 12557 */ 12558 Owl.prototype.maximum = function(relative) { 12559 var settings = this.settings, 12560 maximum = this._coordinates.length, 12561 boundary = Math.abs(this._coordinates[maximum - 1]) - this._width, 12562 i = -1, j; 12563 12564 if (settings.loop) { 12565 maximum = this._clones.length / 2 + this._items.length - 1; 12566 } else if (settings.autoWidth || settings.merge) {
12567 // binary search 12568 while (maximum - i > 1) { 12569 Math.abs(this._coordinates[j = maximum + i >> 1]) < boundary 12570 ? i = j : maximum = j; 12571 } 12572 } else if (settings.center) { 12573 maximum = this._items.length - 1; 12574 } else { 12575 maximum = this._items.length - settings.items; 12576 } 12577 12578 if (relative) { 12579 maximum -= this._clones.length / 2; 12580 } 12581 12582 return Math.max(maximum, 0); 12583 }; 12584 12585 /** 12586 * Gets the minimum position for the current item. 12587 * @public 12588 * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position. 12589 * @returns {Number} 12590 */ 12591 Owl.prototype.minimum = function(relative) { 12592 return relative ? 0 : this._clones.length / 2; 12593 }; 12594 12595 /** 12596 * Gets an item at the specified relative position. 12597 * @public 12598 * @param {Number} [position] - The relative position of the item. 12599 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given. 12600 */ 12601 Owl.prototype.items = function(position) { 12602 if (position === undefined) { 12603 return this._items.slice(); 12604 } 12605 12606 position = this.normalize(position, true); 12607 return this._items[position]; 12608 }; 12609 12610 /** 12611 * Gets an item at the specified relative position. 12612 * @public 12613 * @param {Number} [position] - The relative position of the item. 12614 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given. 12615 */ 12616 Owl.prototype.mergers = function(position) { 12617 if (position === undefined) { 12618 return this._mergers.slice(); 12619 } 12620 12621 position = this.normalize(position, true); 12622 return this._mergers[position]; 12623 }; 12624 12625 /** 12626 * Gets the absolute positions of clones for an item. 12627 * @public 12628 * @param {Number} [position] - The relative position of the item. 12629 * @returns {Array.<Number>} - The absolute positions of clones for the item or all if no position was given. 12630 */ 12631 Owl.prototype.clones = function(position) { 12632 var odd = this._clones.length / 2, 12633 even = odd + this._items.length, 12634 map = function(index) { return index % 2 === 0 ? even + index / 2 : odd - (index + 1) / 2 }; 12635 12636 if (position === undefined) { 12637 return $.map(this._clones, function(v, i) { return map(i) }); 12638 } 12639 12640 return $.map(this._clones, function(v, i) { return v === position ? map(i) : null }); 12641 }; 12642 12643 /** 12644 * Sets the current animation speed. 12645 * @public 12646 * @param {Number} [speed] - The animation speed in milliseconds or nothing to leave it unchanged. 12647 * @returns {Number} - The current animation speed in milliseconds. 12648 */ 12649 Owl.prototype.speed = function(speed) { 12650 if (speed !== undefined) { 12651 this._speed = speed; 12652 } 12653 12654 return this._speed; 12655 }; 12656 12657 /** 12658 * Gets the coordinate of an item. 12659 * @todo The name of this method is missleanding. 12660 * @public 12661 * @param {Number} position - The absolute position of the item within `minimum()` and `maximum()`. 12662 * @returns {Number|Array.<Number>} - The coordinate of the item in pixel or all coordinates. 12663 */ 12664 Owl.prototype.coordinates = function(position) { 12665 var coordinate = null; 12666 12667 if (position === undefined) { 12668 return $.map(this._coordinates, $.proxy(function(coordinate, index) { 12669 return this.coordinates(index); 12670 }, this)); 12671 } 12672 12673 if (this.settings.center) { 12674 coordinate = this._coordinates[position]; 12675 coordinate += (this.width() - coordinate + (this._coordinates[position - 1] || 0)) / 2 * (this.settings.rtl ? -1 : 1); 12676 } else { 12677 coordinate = this._coordinates[position - 1] || 0; 12678 } 12679 12680 return coordinate; 12681 }; 12682 12683 /** 12684 * Calculates the speed for a translation. 12685 * @protected 12686 * @param {Number} from - The absolute position of the start item. 12687 * @param {Number} to - The absolute position of the target item. 12688 * @param {Number} [factor=undefined] - The time factor in milliseconds. 12689 * @returns {Number} - The time in milliseconds for the translation. 12690 */ 12691 Owl.prototype.duration = function(from, to, factor) { 12692 return Math.min(Math.max(Math.abs(to - from), 1), 6) * Math.abs((factor || this.settings.smartSpeed)); 12693 }; 12694 12695 /** 12696 * Slides to the specified item. 12697 * @public 12698 * @param {Number} position - The position of the item. 12699 * @param {Number} [speed] - The time in milliseconds for the transition. 12700 */ 12701 Owl.prototype.to = function(position, speed) { 12702 var current = this.current(), 12703 revert = null, 12704 distance = position - this.relative(current), 12705 direction = (distance > 0) - (distance < 0), 12706 items = this._items.length, 12707 minimum = this.minimum(), 12708 maximum = this.maximum(); 12709 12710 if (this.settings.loop) { 12711 if (!this.settings.rewind && Math.abs(distance) > items / 2) { 12712 distance += direction * -1 * items; 12713 } 12714 12715 position = current + distance; 12716 revert = ((position - minimum) % items + items) % items + minimum; 12717 12718 if (revert !== position && revert - distance <= maximum && revert - distance > 0) { 12719 current = revert - distance; 12720 position = revert; 12721 this.reset(current); 12722 } 12723 } else if (this.settings.rewind) { 12724 maximum += 1; 12725 position = (position % maximum + maximum) % maximum; 12726 } else { 12727 position = Math.max(minimum, Math.min(maximum, position)); 12728 } 12729 12730 this.speed(this.duration(current, position, speed)); 12731 this.current(position); 12732 12733 if (this.$element.is(':visible')) { 12734 this.update(); 12735 } 12736 }; 12737 12738 /** 12739 * Slides to the next item. 12740 * @public 12741 * @param {Number}
vendor: 30,399 bytes, lines 12741-13889
12741 [speed] - The time in milliseconds for the transition. 12742 */ 12743 Owl.prototype.next = function(speed) { 12744 speed = speed || false; 12745 this.to(this.relative(this.current()) + 1, speed); 12746 }; 12747 12748 /** 12749 * Slides to the previous item. 12750 * @public 12751 * @param {Number} [speed] - The time in milliseconds for the transition. 12752 */ 12753 Owl.prototype.prev = function(speed) { 12754 speed = speed || false; 12755 this.to(this.relative(this.current()) - 1, speed); 12756 }; 12757 12758 /** 12759 * Handles the end of an animation. 12760 * @protected 12761 * @param {Event} event - The event arguments. 12762 */ 12763 Owl.prototype.onTransitionEnd = function(event) { 12764 12765 // if css2 animation then event object is undefined 12766 if (event !== undefined) { 12767 event.stopPropagation(); 12768 12769 // Catch only owl-stage transitionEnd event 12770 if ((event.target || event.srcElement || event.originalTarget) !== this.$stage.get(0)) { 12771 return false; 12772 } 12773 } 12774 12775 this.leave('animating'); 12776 this.trigger('translated'); 12777 }; 12778 12779 /** 12780 * Gets viewport width. 12781 * @protected 12782 * @return {Number} - The width in pixel. 12783 */ 12784 Owl.prototype.viewport = function() { 12785 var width; 12786 if (this.options.responsiveBaseElement !== window) { 12787 width = $(this.options.responsiveBaseElement).width(); 12788 } else if (window.innerWidth) { 12789 width = window.innerWidth; 12790 } else if (document.documentElement && document.documentElement.clientWidth) { 12791 width = document.documentElement.clientWidth; 12792 } else { 12793 throw 'Can not detect viewport width.'; 12794 } 12795 12796 return width; 12797 }; 12798 12799 /** 12800 * Replaces the current content. 12801 * @public 12802 * @param {HTMLElement|jQuery|String} content - The new content. 12803 */ 12804 Owl.prototype.replace = function(content) { 12805 this.$stage.empty(); 12806 this._items = []; 12807 12808 if (content) { 12809 content = (content instanceof jQuery) ? content : $(content); 12810 } 12811 12812 if (this.settings.nestedItemSelector) { 12813 content = content.find('.' + this.settings.nestedItemSelector); 12814 } 12815 12816 content.filter(function() { 12817 return this.nodeType === 1; 12818 }).each($.proxy(function(index, item) { 12819 item = this.prepare(item, index); 12820 this.$stage.append(item); 12821 this._items.push(item); 12822 this._mergers.push(item.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1); 12823 }, this)); 12824 12825 this.reset($.isNumeric(this.settings.startPosition) ? this.settings.startPosition : 0); 12826 12827 this.invalidate('items'); 12828 }; 12829 12830 /** 12831 * Adds an item. 12832 * @todo Use `item` instead of `content` for the event arguments. 12833 * @public 12834 * @param {HTMLElement|jQuery|String} content - The item content to add. 12835 * @param {Number} [position] - The relative position at which to insert the item otherwise the item will be added to the end. 12836 */ 12837 Owl.prototype.add = function(content, position) { 12838 var current = this.relative(this._current); 12839 12840 position = position === undefined ? this._items.length : this.normalize(position, true); 12841 content = content instanceof jQuery ? content : $(content); 12842 12843 this.trigger('add', { content: content, position: position }); 12844 12845 content = this.prepare(content, this._items[current].index()); 12846 12847 if (this._items.length === 0 || position === this._items.length) { 12848 this._items.length === 0 && this.$stage.append(content); 12849 this._items.length !== 0 && this._items[position - 1].after(content); 12850 this._items.push(content); 12851 this._mergers.push(content.find('[data-merge]').andSelf('[data-merge]').attr('data-merge') * 1 || 1); 12852 } else { 12853 this._items[position].before(content); 12854 this._items.splice(position, 0, content); 12855 this._mergers.splice(position, 0, content.find('[data-merge]').andSelf('[data-merge]').attr('data-merge') * 1 || 1); 12856 } 12857 12858 this._items[current] && this.reset(this._items[current].index()); 12859 12860 this.invalidate('items'); 12861 12862 this.trigger('added', { content: content, position: position }); 12863 }; 12864 12865 /** 12866 * Removes an item by its position. 12867 * @todo Use `item` instead of `content` for the event arguments. 12868 * @public 12869 * @param {Number} position - The relative position of the item to remove. 12870 */ 12871 Owl.prototype.remove = function(position) { 12872 position = this.normalize(position, true); 12873 12874 if (position === undefined) { 12875 return; 12876 } 12877 12878 this.trigger('remove', { content: this._items[position], position: position }); 12879 12880 this._items[position].remove(); 12881 this._items.splice(position, 1); 12882 this._mergers.splice(position, 1); 12883 12884 this.invalidate('items'); 12885 12886 this.trigger('removed', { content: null, position: position }); 12887 }; 12888 12889 /** 12890 * Preloads images with auto width. 12891 * @todo Replace by a more generic approach 12892 * @protected 12893 */ 12894 Owl.prototype.preloadAutoWidthImages = function(images) { 12895 images.each($.proxy(function(i, element) { 12896 this.enter('pre-loading'); 12897 element = $(element); 12898 $(new Image()).one('load', $.proxy(function(e) { 12899 element.attr('src', e.target.src); 12900 element.css('opacity', 1); 12901 this.leave('pre-loading'); 12902 !this.is('pre-loading') && !this.is('initializing') && this.refresh(); 12903 }, this)).attr('src', element.attr('src') || element.attr('data-src') || element.attr('data-src-retina')); 12904 }, this)); 12905 }; 12906 12907 /** 12908 * Destroys the carousel. 12909 * @public 12910 */ 12911 Owl.prototype.destroy = function() { 12912 12913 this.$element.off('.owl.core'); 12914 this.$stage.off('.owl.core'); 12915 $(document).off('.owl.core'); 12916 12917 if (this.settings.responsive !== false) { 12918 window.clearTimeout(this.resizeTimer); 12919 this.off(window, 'resize', this._handlers.onThrottledResize); 12920 } 12921 12922 for (var i in this._plugins) { 12923 this._plugins[i].destroy(); 12924 } 12925 12926 this.$stage.children('.cloned').remove(); 12927 12928 this.$stage.unwrap(); 12929 this.$stage.children().contents().unwrap(); 12930 this.$stage.children().unwrap(); 12931 12932 this.$element 12933 .removeClass(this.options.refreshClass) 12934 .removeClass(this.options.loadingClass) 12935 .removeClass(this.options.loadedClass) 12936 .removeClass(this.options.rtlClass) 12937 .removeClass(this.options.dragClass) 12938 .removeClass(this.options.grabClass) 12939 .attr('class', this.$element.attr('class').replace(new RegExp(this.options.responsiveClass + '-\\S+\\s', 'g'), '')) 12940 .removeData('owl.carousel'); 12941 }; 12942 12943 /** 12944 * Operators to calculate right-to-left and left-to-right. 12945 * @protected 12946 * @param {Number} [a] - The left side operand. 12947 * @param {String} [o] - The operator. 12948 * @param {Number} [b] - The right side operand. 12949 */ 12950 Owl.prototype.op = function(a, o, b) { 12951 var rtl = this.settings.rtl; 12952 switch (o) { 12953 case '<': 12954 return rtl ? a > b : a < b; 12955 case '>': 12956 return rtl ? a < b : a > b; 12957 case '>=': 12958 return rtl ? a <= b : a >= b; 12959 case '<=': 12960 return rtl ? a >= b : a <= b; 12961 default: 12962 break; 12963 } 12964 }; 12965 12966 /** 12967 * Attaches to an internal event. 12968 * @protected 12969 * @param {HTMLElement} element - The event source. 12970 * @param {String} event - The event name. 12971 * @param {Function} listener - The event handler to attach. 12972 * @param {Boolean} capture - Wether the event should be handled at the capturing phase or not. 12973 */ 12974 Owl.prototype.on = function(element, event, listener, capture) { 12975 if (element.addEventListener) { 12976 element.addEventListener(event, listener, capture); 12977 } else if (element.attachEvent) { 12978 element.attachEvent('on' + event, listener); 12979 } 12980 }; 12981 12982 /** 12983 * Detaches from an internal event. 12984 * @protected 12985 * @param {HTMLElement} element - The event source. 12986 * @param {String} event - The event name. 12987 * @param {Function} listener - The attached event handler to detach. 12988 * @param {Boolean} capture - Wether the attached event handler was registered as a capturing listener or not. 12989 */ 12990 Owl.prototype.off = function(element, event, listener, capture) { 12991 if (element.removeEventListener) { 12992 element.removeEventListener(event, listener, capture); 12993 } else if (element.detachEvent) { 12994 element.detachEvent('on' + event, listener); 12995 } 12996 }; 12997 12998 /** 12999 * Triggers a public event. 13000 * @todo Remove `status`, `relatedTarget` should be used instead. 13001 * @protected 13002 * @param {String} name - The event name. 13003 * @param {*} [data=null] - The event data. 13004 * @param {String} [namespace=carousel] - The event namespace. 13005 * @param {String} [state] - The state which is associated with the event. 13006 * @param {Boolean} [enter=false] - Indicates if the call enters the specified state or not. 13007 * @returns {Event} - The event arguments. 13008 */ 13009 Owl.prototype.trigger = function(name, data, namespace, state, enter) { 13010 var status = { 13011 item: { count: this._items.length, index: this.current() } 13012 }, handler = $.camelCase( 13013 $.grep([ 'on', name, namespace ], function(v) { return v }) 13014 .join('-').toLowerCase() 13015 ), event = $.Event( 13016 [ name, 'owl', namespace || 'carousel' ].join('.').toLowerCase(), 13017 $.extend({ relatedTarget: this }, status, data) 13018 ); 13019 13020 if (!this._supress[name]) { 13021 $.each(this._plugins, function(name, plugin) { 13022 if (plugin.onTrigger) { 13023 plugin.onTrigger(event); 13024 } 13025 }); 13026 13027 this.register({ type: Owl.Type.Event, name: name }); 13028 this.$element.trigger(event); 13029 13030 if (this.settings && typeof this.settings[handler] === 'function') { 13031 this.settings[handler].call(this, event); 13032 } 13033 } 13034 13035 return event; 13036 }; 13037 13038 /** 13039 * Enters a state. 13040 * @param name - The state name. 13041 */ 13042 Owl.prototype.enter = function(name) { 13043 $.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) { 13044 if (this._states.current[name] === undefined) { 13045 this._states.current[name] = 0; 13046 } 13047 13048 this._states.current[name]++; 13049 }, this)); 13050 }; 13051 13052 /** 13053 * Leaves a state. 13054 * @param name - The state name. 13055 */ 13056 Owl.prototype.leave = function(name) { 13057 $.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) { 13058 this._states.current[name]--; 13059 }, this)); 13060 }; 13061 13062 /** 13063 * Registers an event or state. 13064 * @public 13065 * @param {Object} object - The event or state to register. 13066 */ 13067 Owl.prototype.register = function(object) { 13068 if (object.type === Owl.Type.Event) { 13069 if (!$.event.special[object.name]) { 13070 $.event.special[object.name] = {}; 13071 } 13072 13073 if (!$.event.special[object.name].owl) { 13074 var _default = $.event.special[object.name]._default; 13075 $.event.special[object.name]._default = function(e) { 13076 if (_default && _default.apply && (!e.namespace || e.namespace.indexOf('owl') === -1)) { 13077 return _default.apply(this, arguments); 13078 } 13079 return e.namespace && e.namespace.indexOf('owl') > -1; 13080 }; 13081 $.event.special[object.name].owl = true; 13082 } 13083 } else if (object.type === Owl.Type.State) { 13084 if (!this._states.tags[object.name]) { 13085 this._states.tags[object.name] = object.tags; 13086 } else { 13087 this._states.tags[object.name] = this._states.tags[object.name].concat(object.tags); 13088 } 13089 13090 this._states.tags[object.name] = $.grep(this._states.tags[object.name], $.proxy(function(tag, i) { 13091 return $.inArray(tag, this._states.tags[object.name]) === i; 13092 }, this)); 13093 } 13094 }; 13095 13096 /** 13097 * Suppresses events. 13098 * @protected 13099 * @param {Array.<String>} events - The events to suppress. 13100 */ 13101 Owl.prototype.suppress = function(events) { 13102 $.each(events, $.proxy(function(index, event) { 13103 this._supress[event] = true; 13104 }, this)); 13105 }; 13106 13107 /** 13108 * Releases suppressed events. 13109 * @protected 13110 * @param {Array.<String>} events - The events to release. 13111 */ 13112 Owl.prototype.release = function(events) { 13113 $.each(events, $.proxy(function(index, event) { 13114 delete this._supress[event]; 13115 }, this)); 13116 }; 13117 13118 /** 13119 * Gets unified pointer coordinates from event. 13120 * @todo #261 13121 * @protected 13122 * @param {Event} - The `mousedown` or `touchstart` event. 13123 * @returns {Object} - Contains `x` and `y` coordinates of current pointer position. 13124 */ 13125 Owl.prototype.pointer = function(event) { 13126 var result = { x: null, y: null }; 13127 13128 event = event.originalEvent || event || window.event; 13129 13130 event = event.touches && event.touches.length ? 13131 event.touches[0] : event.changedTouches && event.changedTouches.length ? 13132 event.changedTouches[0] : event; 13133 13134 if (event.pageX) { 13135 result.x = event.pageX; 13136 result.y = event.pageY; 13137 } else { 13138 result.x = event.clientX; 13139 result.y = event.clientY; 13140 } 13141 13142 return result; 13143 }; 13144 13145 /** 13146 * Gets the difference of two vectors. 13147 * @todo #261 13148 * @protected 13149 * @param {Object} - The first vector. 13150 * @param {Object} - The second vector. 13151 * @returns {Object} - The difference. 13152 */ 13153 Owl.prototype.difference = function(first, second) { 13154 return { 13155 x: first.x - second.x, 13156 y: first.y - second.y 13157 }; 13158 }; 13159 13160 /** 13161 * The jQuery Plugin for the Owl Carousel 13162 * @todo Navigation plugin `next` and `prev` 13163 * @public 13164 */ 13165 $.fn.owlCarousel = function(option) { 13166 var args = Array.prototype.slice.call(arguments, 1); 13167 13168 return this.each(function() { 13169 var $this = $(this), 13170 data = $this.data('owl.carousel'); 13171 13172 if (!data) { 13173 data = new Owl(this, typeof option == 'object' && option); 13174 $this.data('owl.carousel', data); 13175 13176 $.each([ 13177 'next', 'prev', 'to', 'destroy', 'refresh', 'replace', 'add', 'remove' 13178 ], function(i, event) { 13179 data.register({ type: Owl.Type.Event, name: event }); 13180 data.$element.on(event + '.owl.carousel.core', $.proxy(function(e) { 13181 if (e.namespace && e.relatedTarget !== this) { 13182 this.suppress([ event ]); 13183 data[event].apply(this, [].slice.call(arguments, 1)); 13184 this.release([ event ]); 13185 } 13186 }, data)); 13187 }); 13188 } 13189 13190 if (typeof option == 'string' && option.charAt(0) !== '_') { 13191 data[option].apply(data, args); 13192 } 13193 }); 13194 }; 13195 13196 /** 13197 * The constructor for the jQuery Plugin 13198 * @public 13199 */ 13200 $.fn.owlCarousel.Constructor = Owl; 13201 13202})(window.Zepto || window.jQuery, window, document); 13203 13204/** 13205 * AutoRefresh Plugin 13206 * @version 2.0.0-beta.3 13207 * @author Artus Kolanowski 13208 * @license The MIT License (MIT) 13209 */ 13210;(function($, window, document, undefined) { 13211 13212 /** 13213 * Creates the auto refresh plugin. 13214 * @class The Auto Refresh Plugin 13215 * @param {Owl} carousel - The Owl Carousel 13216 */ 13217 var AutoRefresh = function(carousel) { 13218 /** 13219 * Reference to the core. 13220 * @protected 13221 * @type {Owl} 13222 */ 13223 this._core = carousel; 13224 13225 /** 13226 * Refresh interval. 13227 * @protected 13228 * @type {number} 13229 */ 13230 this._interval = null; 13231 13232 /** 13233 * Whether the element is currently visible or not. 13234 * @protected 13235 * @type {Boolean} 13236 */ 13237 this._visible = null; 13238 13239 /** 13240 * All event handlers. 13241 * @protected 13242 * @type {Object} 13243 */ 13244 this._handlers = { 13245 'initialized.owl.carousel': $.proxy(function(e) { 13246 if (e.namespace && this._core.settings.autoRefresh) { 13247 this.watch(); 13248 } 13249 }, this) 13250 }; 13251 13252 // set default options 13253 this._core.options = $.extend({}, AutoRefresh.Defaults, this._core.options); 13254 13255 // register event handlers 13256 this._core.$element.on(this._handlers); 13257 }; 13258 13259 /** 13260 * Default options. 13261 * @public 13262 */ 13263 AutoRefresh.Defaults = { 13264 autoRefresh: true, 13265 autoRefreshInterval: 500 13266 }; 13267 13268 /** 13269 * Watches the element. 13270 */ 13271 AutoRefresh.prototype.watch = function() { 13272 if (this._interval) { 13273 return; 13274 } 13275 13276 this._visible = this._core.$element.is(':visible'); 13277 this._interval = window.setInterval($.proxy(this.refresh, this), this._core.settings.autoRefreshInterval); 13278 }; 13279 13280 /** 13281 * Refreshes the element. 13282 */ 13283 AutoRefresh.prototype.refresh = function() { 13284 if (this._core.$element.is(':visible') === this._visible) { 13285 return; 13286 } 13287 13288 this._visible = !this._visible; 13289 13290 this._core.$element.toggleClass('owl-hidden', !this._visible); 13291 13292 this._visible && (this._core.invalidate('width') && this._core.refresh()); 13293 }; 13294 13295 /** 13296 * Destroys the plugin. 13297 */ 13298 AutoRefresh.prototype.destroy = function() { 13299 var handler, property; 13300 13301 window.clearInterval(this._interval); 13302 13303 for (handler in this._handlers) { 13304 this._core.$element.off(handler, this._handlers[handler]); 13305 } 13306 for (property in Object.getOwnPropertyNames(this)) { 13307 typeof this[property] != 'function' && (this[property] = null); 13308 } 13309 }; 13310 13311 $.fn.owlCarousel.Constructor.Plugins.AutoRefresh = AutoRefresh; 13312 13313})(window.Zepto || window.jQuery, window, document); 13314 13315/** 13316 * Lazy Plugin 13317 * @version 2.0.0-beta.3 13318 * @author Bartosz Wojciechowski 13319 * @license The MIT License (MIT) 13320 */ 13321;(function($, window, document, undefined) { 13322 13323 /** 13324 * Creates the lazy plugin. 13325 * @class The Lazy Plugin 13326 * @param {Owl} carousel - The Owl Carousel 13327 */ 13328 var Lazy = function(carousel) { 13329 13330 /** 13331 * Reference to the core. 13332 * @protected 13333 * @type {Owl} 13334 */ 13335 this._core = carousel; 13336 13337 /** 13338 * Already loaded items. 13339 * @protected 13340 * @type {Array.<jQuery>} 13341 */ 13342 this._loaded = []; 13343 13344 /** 13345 * Event handlers. 13346 * @protected 13347 * @type {Object} 13348 */ 13349 this._handlers = { 13350 'initialized.owl.carousel change.owl.carousel': $.proxy(function(e) { 13351 if (!e.namespace) { 13352 return; 13353 } 13354 13355 if (!this._core.settings || !this._core.settings.lazyLoad) { 13356 return; 13357 } 13358 13359 if ((e.property && e.property.name == 'position') || e.type == 'initialized') { 13360 var settings = this._core.settings, 13361 n = (settings.center && Math.ceil(settings.items / 2) || settings.items), 13362 i = ((settings.center && n * -1) || 0), 13363 position = ((e.property && e.property.value) || this._core.current()) + i, 13364 clones = this._core.clones().length, 13365 load = $.proxy(function(i, v) { this.load(v) }, this); 13366 13367 while (i++ < n) { 13368 this.load(clones / 2 + this._core.relative(position)); 13369 clones && $.each(this._core.clones(this._core.relative(position)), load); 13370 position++; 13371 } 13372 } 13373 }, this) 13374 }; 13375 13376 // set the default options 13377 this._core.options = $.extend({}, Lazy.Defaults, this._core.options); 13378 13379 // register event handler 13380 this._core.$element.on(this._handlers); 13381 } 13382 13383 /** 13384 * Default options. 13385 * @public 13386 */ 13387 Lazy.Defaults = { 13388 lazyLoad: false 13389 } 13390 13391 /** 13392 * Loads all resources of an item at the specified position. 13393 * @param {Number} position - The absolute position of the item. 13394 * @protected 13395 */ 13396 Lazy.prototype.load = function(position) { 13397 var $item = this._core.$stage.children().eq(position), 13398 $elements = $item && $item.find('.owl-lazy'); 13399 13400 if (!$elements || $.inArray($item.get(0), this._loaded) > -1) { 13401 return; 13402 } 13403 13404 $elements.each($.proxy(function(index, element) { 13405 var $element = $(element), image, 13406 url = (window.devicePixelRatio > 1 && $element.attr('data-src-retina')) || $element.attr('data-src'); 13407 13408 this._core.trigger('load', { element: $element, url: url }, 'lazy'); 13409 13410 if ($element.is('img')) { 13411 $element.one('load.owl.lazy', $.proxy(function() { 13412 $element.css('opacity', 1); 13413 this._core.trigger('loaded', { element: $element, url: url }, 'lazy'); 13414 }, this)).attr('src', url); 13415 } else { 13416 image = new Image(); 13417 image.onload = $.proxy(function() { 13418 $element.css({ 13419 'background-image': 'url(' + url + ')', 13420 'opacity': '1' 13421 }); 13422 this._core.trigger('loaded', { element: $element, url: url }, 'lazy'); 13423 }, this); 13424 image.src = url; 13425 } 13426 }, this)); 13427 13428 this._loaded.push($item.get(0)); 13429 } 13430 13431 /** 13432 * Destroys the plugin. 13433 * @public 13434 */ 13435 Lazy.prototype.destroy = function() { 13436 var handler, property; 13437 13438 for (handler in this.handlers) { 13439 this._core.$element.off(handler, this.handlers[handler]); 13440 } 13441 for (property in Object.getOwnPropertyNames(this)) { 13442 typeof this[property] != 'function' && (this[property] = null); 13443 } 13444 }; 13445 13446 $.fn.owlCarousel.Constructor.Plugins.Lazy = Lazy; 13447 13448})(window.Zepto || window.jQuery, window, document); 13449 13450/** 13451 * AutoHeight Plugin 13452 * @version 2.0.0-beta.3 13453 * @author Bartosz Wojciechowski 13454 * @license The MIT License (MIT) 13455 */ 13456;(function($, window, document, undefined) { 13457 13458 /** 13459 * Creates the auto height plugin. 13460 * @class The Auto Height Plugin 13461 * @param {Owl} carousel - The Owl Carousel 13462 */ 13463 var AutoHeight = function(carousel) { 13464 /** 13465 * Reference to the core. 13466 * @protected 13467 * @type {Owl} 13468 */ 13469 this._core = carousel; 13470 13471 /** 13472 * All event handlers. 13473 * @protected 13474 * @type {Object} 13475 */ 13476 this._handlers = { 13477 'initialized.owl.carousel refreshed.owl.carousel': $.proxy(function(e) { 13478 if (e.namespace && this._core.settings.autoHeight) { 13479 this.update(); 13480 } 13481 }, this), 13482 'changed.owl.carousel': $.proxy(function(e) { 13483 if (e.namespace && this._core.settings.autoHeight && e.property.name == 'position'){ 13484 this.update(); 13485 } 13486 }, this), 13487 'loaded.owl.lazy': $.proxy(function(e) { 13488 if (e.namespace && this._core.settings.autoHeight 13489 && e.element.closest('.' + this._core.settings.itemClass).index() === this._core.current()) { 13490 this.update(); 13491 } 13492 }, this) 13493 }; 13494 13495 // set default options 13496 this._core.options = $.extend({}, AutoHeight.Defaults, this._core.options); 13497 13498 // register event handlers 13499 this._core.$element.on(this._handlers); 13500 }; 13501 13502 /** 13503 * Default options. 13504 * @public 13505 */ 13506 AutoHeight.Defaults = { 13507 autoHeight: false, 13508 autoHeightClass: 'owl-height' 13509 }; 13510 13511 /** 13512 * Updates the view. 13513 */ 13514 AutoHeight.prototype.update = function() { 13515 var start = this._core._current, 13516 end = start + this._core.settings.items, 13517 visible = this._core.$stage.children().toArray().slice(start, end); 13518 heights = [], 13519 maxheight = 0; 13520 13521 $.each(visible, function(index, item) { 13522 heights.push($(item).height()); 13523 }); 13524 13525 maxheight = Math.max.apply(null, heights); 13526 13527 this._core.$stage.parent() 13528 .height(maxheight) 13529 .addClass(this._core.settings.autoHeightClass); 13530 }; 13531 13532 AutoHeight.prototype.destroy = function() { 13533 var handler, property; 13534 13535 for (handler in this._handlers) { 13536 this._core.$element.off(handler, this._handlers[handler]); 13537 } 13538 for (property in Object.getOwnPropertyNames(this)) { 13539 typeof this[property] != 'function' && (this[property] = null); 13540 } 13541 }; 13542 13543 $.fn.owlCarousel.Constructor.Plugins.AutoHeight = AutoHeight; 13544 13545})(window.Zepto || window.jQuery, window, document); 13546 13547/** 13548 * Video Plugin 13549 * @version 2.0.0-beta.3 13550 * @author Bartosz Wojciechowski 13551 * @license The MIT License (MIT) 13552 */ 13553;(function($, window, document, undefined) { 13554 13555 /** 13556 * Creates the video plugin. 13557 * @class The Video Plugin 13558 * @param {Owl} carousel - The Owl Carousel 13559 */ 13560 var Video = function(carousel) { 13561 /** 13562 * Reference to the core. 13563 * @protected 13564 * @type {Owl} 13565 */ 13566 this._core = carousel; 13567 13568 /** 13569 * Cache all video URLs. 13570 * @protected 13571 * @type {Object} 13572 */ 13573 this._videos = {}; 13574 13575 /** 13576 * Current playing item. 13577 * @protected 13578 * @type {jQuery} 13579 */ 13580 this._playing = null; 13581 13582 /** 13583 * All event handlers. 13584 * @todo The cloned content removale is too late 13585 * @protected 13586 * @type {Object} 13587 */ 13588 this._handlers = { 13589 'initialized.owl.carousel': $.proxy(function(e) { 13590 if (e.namespace) { 13591 this._core.register({ type: 'state', name: 'playing', tags: [ 'interacting' ] }); 13592 } 13593 }, this), 13594 'resize.owl.carousel': $.proxy(function(e) { 13595 if (e.namespace && this._core.settings.video && this.isInFullScreen()) { 13596 e.preventDefault(); 13597 } 13598 }, this), 13599 'refreshed.owl.carousel': $.proxy(function(e) { 13600 if (e.namespace && this._core.is('resizing')) { 13601 this._core.$stage.find('.cloned .owl-video-frame').remove(); 13602 } 13603 }, this), 13604 'changed.owl.carousel': $.proxy(function(e) { 13605 if (e.namespace && e.property.name === 'position' && this._playing) { 13606 this.stop(); 13607 } 13608 }, this), 13609 'prepared.owl.carousel': $.proxy(function(e) { 13610 if (!e.namespace) { 13611 return; 13612 } 13613 13614 var $element = $(e.content).find('.owl-video'); 13615 13616 if ($element.length) { 13617 $element.css('display', 'none'); 13618 this.fetch($element, $(e.content)); 13619 } 13620 }, this) 13621 }; 13622 13623 // set default options 13624 this._core.options = $.extend({}, Video.Defaults, this._core.options); 13625 13626 // register event handlers 13627 this._core.$element.on(this._handlers); 13628 13629 this._core.$element.on('click.owl.video', '.owl-video-play-icon', $.proxy(function(e) { 13630 this.play(e); 13631 }, this)); 13632 }; 13633 13634 /** 13635 * Default options. 13636 * @public 13637 */ 13638 Video.Defaults = { 13639 video: false, 13640 videoHeight: false, 13641 videoWidth: false 13642 }; 13643 13644 /** 13645 * Gets the video ID and the type (YouTube/Vimeo only). 13646 * @protected 13647 * @param {jQuery} target - The target containing the video data. 13648 * @param {jQuery} item - The item containing the video. 13649 */ 13650 Video.prototype.fetch = function(target, item) { 13651 var type = target.attr('data-vimeo-id') ? 'vimeo' : 'youtube', 13652 id = target.attr('data-vimeo-id') || target.attr('data-youtube-id'), 13653 width = target.attr('data-width') || this._core.settings.videoWidth, 13654 height = target.attr('data-height') || this._core.settings.videoHeight, 13655 url = target.attr('href'); 13656 13657 if (url) { 13658 id = url.match(/(http:|https:|)\/\/(player.|www.)?(vimeo\.com|youtu(be\.com|\.be|be\.googleapis\.com))\/(video\/|embed\/|watch\?v=|v\/)?([A-Za-z0-9._%-]*)(\&\S+)?/); 13659 13660 if (id[3].indexOf('youtu') > -1) { 13661 type = 'youtube'; 13662 } else if (id[3].indexOf('vimeo') > -1) { 13663 type = 'vimeo'; 13664 } else { 13665 throw new Error('Video URL not supported.'); 13666 } 13667 id = id[6]; 13668 } else { 13669 throw new Error('Missing video URL.'); 13670 } 13671 13672 this._videos[url] = { 13673 type: type, 13674 id: id, 13675 width: width, 13676 height: height 13677 }; 13678 13679 item.attr('data-video', url); 13680 13681 this.thumbnail(target, this._videos[url]); 13682 }; 13683 13684 /** 13685 * Creates video thumbnail. 13686 * @protected 13687 * @param {jQuery} target - The target containing the video data. 13688 * @param {Object} info - The video info object. 13689 * @see `fetch` 13690 */ 13691 Video.prototype.thumbnail = function(target, video) { 13692 var tnLink, 13693 icon, 13694 path, 13695 dimensions = video.width && video.height ? 'style="width:' + video.width + 'px;height:' + video.height + 'px;"' : '', 13696 customTn = target.find('img'), 13697 srcType = 'src', 13698 lazyClass = '', 13699 settings = this._core.settings, 13700 create = function(path) { 13701 icon = '<div class="owl-video-play-icon"></div>'; 13702 13703 if (settings.lazyLoad) { 13704 tnLink = '<div class="owl-video-tn ' + lazyClass + '" ' + srcType + '="' + path + '"></div>'; 13705 } else { 13706 tnLink = '<div class="owl-video-tn" style="opacity:1;background-image:url(' + path + ')"></div>'; 13707 } 13708 target.after(tnLink); 13709 target.after(icon); 13710 }; 13711 13712 // wrap video content into owl-video-wrapper div 13713 target.wrap('<div class="owl-video-wrapper"' + dimensions + '></div>'); 13714 13715 if (this._core.settings.lazyLoad) { 13716 srcType = 'data-src'; 13717 lazyClass = 'owl-lazy'; 13718 } 13719 13720 // custom thumbnail 13721 if (customTn.length) { 13722 create(customTn.attr(srcType)); 13723 customTn.remove(); 13724 return false; 13725 } 13726 13727 if (video.type === 'youtube') { 13728 path = "//img.youtube.com/vi/" + video.id + "/hqdefault.jpg"; 13729 create(path); 13730 } else if (video.type === 'vimeo') { 13731 $.ajax({ 13732 type: 'GET', 13733 url: '//vimeo.com/api/v2/video/' + video.id + '.json', 13734 jsonp: 'callback', 13735 dataType: 'jsonp', 13736 success: function(data) { 13737 path = data[0].thumbnail_large; 13738 create(path); 13739 } 13740 }); 13741 } 13742 }; 13743 13744 /** 13745 * Stops the current video. 13746 * @public 13747 */ 13748 Video.prototype.stop = function() { 13749 this._core.trigger('stop', null, 'video'); 13750 this._playing.find('.owl-video-frame').remove(); 13751 this._playing.removeClass('owl-video-playing'); 13752 this._playing = null; 13753 this._core.leave('playing'); 13754 this._core.trigger('stopped', null, 'video'); 13755 }; 13756 13757 /** 13758 * Starts the current video. 13759 * @public 13760 * @param {Event} event - The event arguments. 13761 */ 13762 Video.prototype.play = function(event) { 13763 var target = $(event.target), 13764 item = target.closest('.' + this._core.settings.itemClass), 13765 video = this._videos[item.attr('data-video')], 13766 width = video.width || '100%', 13767 height = video.height || this._core.$stage.height(), 13768 html; 13769 13770 if (this._playing) { 13771 return; 13772 } 13773 13774 this._core.enter('playing'); 13775 this._core.trigger('play', null, 'video'); 13776 13777 item = this._core.items(this._core.relative(item.index())); 13778 13779 this._core.reset(item.index()); 13780 13781 if (video.type === 'youtube') { 13782 html = '<iframe width="' + width + '" height="' + height + '" src="//www.youtube.com/embed/' + 13783 video.id + '?autoplay=1&v=' + video.id + '" frameborder="0" allowfullscreen></iframe>'; 13784 } else if (video.type === 'vimeo') { 13785 html = '<iframe src="//player.vimeo.com/video/' + video.id + 13786 '?autoplay=1" width="' + width + '" height="' + height + 13787 '" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>'; 13788 } 13789 13790 $('<div class="owl-video-frame">' + html + '</div>').insertAfter(item.find('.owl-video')); 13791 13792 this._playing = item.addClass('owl-video-playing'); 13793 }; 13794 13795 /** 13796 * Checks whether an video is currently in full screen mode or not. 13797 * @todo Bad style because looks like a readonly method but changes members. 13798 * @protected 13799 * @returns {Boolean} 13800 */ 13801 Video.prototype.isInFullScreen = function() { 13802 var element = document.fullscreenElement || document.mozFullScreenElement || 13803 document.webkitFullscreenElement; 13804 13805 return element && $(element).parent().hasClass('owl-video-frame'); 13806 }; 13807 13808 /** 13809 * Destroys the plugin. 13810 */ 13811 Video.prototype.destroy = function() { 13812 var handler, property; 13813 13814 this._core.$element.off('click.owl.video'); 13815 13816 for (handler in this._handlers) { 13817 this._core.$element.off(handler, this._handlers[handler]); 13818 } 13819 for (property in Object.getOwnPropertyNames(this)) { 13820 typeof this[property] != 'function' && (this[property] = null); 13821 } 13822 }; 13823 13824 $.fn.owlCarousel.Constructor.Plugins.Video = Video; 13825 13826})(window.Zepto || window.jQuery, window, document); 13827 13828/** 13829 * Animate Plugin 13830 * @version 2.0.0-beta.3 13831 * @author Bartosz Wojciechowski 13832 * @license The MIT License (MIT) 13833 */ 13834;(function($, window, document, undefined) { 13835 13836 /** 13837 * Creates the animate plugin. 13838 * @class The Navigation Plugin 13839 * @param {Owl} scope - The Owl Carousel 13840 */ 13841 var Animate = function(scope) { 13842 this.core = scope; 13843 this.core.options = $.extend({}, Animate.Defaults, this.core.options); 13844 this.swapping = true; 13845 this.previous = undefined; 13846 this.next = undefined; 13847 13848 this.handlers = { 13849 'change.owl.carousel': $.proxy(function(e) { 13850 if (e.namespace && e.property.name == 'position') { 13851 this.previous = this.core.current(); 13852 this.next = e.property.value; 13853 } 13854 }, this), 13855 'drag.owl.carousel dragged.owl.carousel translated.owl.carousel': $.proxy(function(e) { 13856 if (e.namespace) { 13857 this.swapping = e.type == 'translated'; 13858 } 13859 }, this), 13860 'translate.owl.carousel': $.proxy(function(e) { 13861 if (e.namespace && this.swapping && (this.core.options.animateOut || this.core.options.animateIn)) { 13862 this.swap(); 13863 } 13864 }, this) 13865 }; 13866 13867 this.core.$element.on(this.handlers); 13868 }; 13869 13870 /** 13871 * Default options. 13872 * @public 13873 */ 13874 Animate.Defaults = { 13875 animateOut: false, 13876 animateIn: false 13877 }; 13878 13879 /** 13880 * Toggles the animation classes whenever an translations starts. 13881 * @protected 13882 * @returns {Boolean|undefined} 13883 */ 13884 Animate.prototype.swap = function() { 13885 13886 if (this.core.settings.items !== 1) { 13887 return; 13888 } 13889
13890 if (!$.support.animation || !$.support.transition) { 13891 return; 13892 } 13893 13894 this.core.speed(0); 13895 13896 var left, 13897 clear = $.proxy(this.clear, this), 13898 previous = this.core.$stage.children().eq(this.previous), 13899 next = this.core.$stage.children().eq(this.next), 13900 incoming = this.core.settings.animateIn, 13901 outgoing = this.core.settings.animateOut; 13902 13903 if (this.core.current() === this.previous) { 13904 return; 13905 } 13906 13907 if (outgoing) { 13908 left = this.core.coordinates(this.previous) - this.core.coordinates(this.next); 13909 previous.css( { 'left': left + 'px' } ) 13910 .addClass('animated owl-animated-out') 13911 .addClass(outgoing) 13912 .on($.support.animation.end, clear); 13913 } 13914 13915 if (incoming) { 13916 next.addClass('animated owl-animated-in') 13917 .addClass(incoming) 13918 .on($.support.animation.end, clear); 13919 } 13920 }; 13921 13922 Animate.prototype.clear = function(e) { 13923 if ($(e.target).hasClass('animated')) { 13924 $(e.target).css( { 'left': '' } ) 13925 .removeClass('animated owl-animated-out owl-animated-in') 13926 .removeClass(this.core.settings.animateIn) 13927 .removeClass(this.core.settings.animateOut); 13928 this.core.onTransitionEnd(); 13929 } 13930 }; 13931 13932 /** 13933 * Destroys the plugin. 13934 * @public 13935 */ 13936 Animate.prototype.destroy = function() { 13937 var handler, property; 13938 13939 for (handler in this.handlers) { 13940 this.core.$element.off(handler, this.handlers[handler]); 13941 } 13942 for (property in Object.getOwnPropertyNames(this)) { 13943 typeof this[property] != 'function' && (this[property] = null); 13944 } 13945 }; 13946 13947 $.fn.owlCarousel.Constructor.Plugins.Animate = Animate; 13948 13949})(window.Zepto || window.jQuery, window, document); 13950 13951/** 13952 * Autoplay Plugin 13953 * @version 2.0.0-beta.3 13954 * @author Bartosz Wojciechowski 13955 * @author Artus Kolanowski 13956 * @license The MIT License (MIT) 13957 */ 13958;(function($, window, document, undefined) { 13959 13960 /** 13961 * Creates the autoplay plugin. 13962 * @class The Autoplay Plugin 13963 * @param {Owl} scope - The Owl Carousel 13964 */ 13965 var Autoplay = function(carousel) { 13966 /** 13967 * Reference to the core. 13968 * @protected 13969 * @type {Owl} 13970 */ 13971 this._core = carousel; 13972 13973 /** 13974 * The autoplay interval. 13975 * @type {Number} 13976 */ 13977 this._interval = null; 13978 13979 /** 13980 * Indicates whenever the autoplay is paused. 13981 * @type {Boolean} 13982 */ 13983 this._paused = false; 13984 13985 /** 13986 * All event handlers. 13987 * @protected 13988 * @type {Object} 13989 */ 13990 this._handlers = { 13991 'changed.owl.carousel': $.proxy(function(e) { 13992 if (e.namespace && e.property.name === 'settings') { 13993 if (this._core.settings.autoplay) { 13994 this.play(); 13995 } else { 13996 this.stop(); 13997 } 13998 } 13999 }, this), 14000 'initialized.owl.carousel': $.proxy(function(e) { 14001 if (e.namespace && this._core.settings.autoplay) { 14002 this.play(); 14003 } 14004 }, this), 14005 'play.owl.autoplay': $.proxy(function(e, t, s) { 14006 if (e.namespace) { 14007 this.play(t, s); 14008 } 14009 }, this), 14010 'stop.owl.autoplay': $.proxy(function(e) { 14011 if (e.namespace) { 14012 this.stop(); 14013 } 14014 }, this), 14015 'mouseover.owl.autoplay': $.proxy(function() { 14016 if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) { 14017 this.pause(); 14018 } 14019 }, this), 14020 'mouseleave.owl.autoplay': $.proxy(function() { 14021 if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) { 14022 this.play(); 14023 } 14024 }, this) 14025 }; 14026 14027 // register event handlers 14028 this._core.$element.on(this._handlers); 14029 14030 // set default options 14031 this._core.options = $.extend({}, Autoplay.Defaults, this._core.options); 14032 }; 14033 14034 /** 14035 * Default options. 14036 * @public 14037 */ 14038 Autoplay.Defaults = { 14039 autoplay: false, 14040 autoplayTimeout: 5000, 14041 autoplayHoverPause: false, 14042 autoplaySpeed: false 14043 }; 14044 14045 /** 14046 * Starts the autoplay. 14047 * @public 14048 * @param {Number} [timeout] - The interval before the next animation starts. 14049 * @param {Number} [speed] - The animation speed for the animations. 14050 */ 14051 Autoplay.prototype.play = function(timeout, speed) { 14052 this._paused = false; 14053 14054 if (this._core.is('rotating')) { 14055 return; 14056 } 14057 14058 this._core.enter('rotating'); 14059 14060 this._interval = window.setInterval($.proxy(function() { 14061 if (this._paused || this._core.is('busy') || this._core.is('interacting') || document.hidden) { 14062 return; 14063 } 14064 this._core.next(speed || this._core.settings.autoplaySpeed); 14065 }, this), timeout || this._core.settings.autoplayTimeout); 14066 }; 14067 14068 /** 14069 * Stops the autoplay. 14070 * @public 14071 */ 14072 Autoplay.prototype.stop = function() { 14073 if (!this._core.is('rotating')) { 14074 return; 14075 } 14076 14077 window.clearInterval(this._interval); 14078 this._core.leave('rotating'); 14079 }; 14080 14081 /** 14082 * Stops the autoplay. 14083 * @public 14084 */ 14085 Autoplay.prototype.pause = function() { 14086 if (!this._core.is('rotating')) { 14087 return; 14088 } 14089 14090 this._paused = true; 14091 }; 14092 14093 /** 14094 * Destroys the plugin. 14095 */ 14096 Autoplay.prototype.destroy = function() { 14097 var handler, property; 14098 14099 this.stop(); 14100 14101 for (handler in this._handlers) { 14102 this._core.$element.off(handler, this._handlers[handler]); 14103 } 14104 for (property in Object.getOwnPropertyNames(this)) { 14105 typeof this[property] != 'function' && (this[property] = null); 14106 } 14107 }; 14108 14109 $.fn.owlCarousel.Constructor.Plugins.autoplay = Autoplay; 14110 14111})(window.Zepto || window.jQuery, window, document); 14112 14113/** 14114 * Navigation Plugin 14115 * @version 2.0.0-beta.3 14116 * @author Artus Kolanowski 14117 * @license The MIT License (MIT) 14118 */ 14119;(function($, window, document, undefined) { 14120 'use strict'; 14121 14122 /** 14123 * Creates the navigation plugin. 14124 * @class The Navigation Plugin 14125 * @param {Owl} carousel - The Owl Carousel. 14126 */ 14127 var Navigation = function(carousel) { 14128 /** 14129 * Reference to the core. 14130 * @protected 14131 * @type {Owl} 14132 */ 14133 this._core = carousel; 14134 14135 /** 14136 * Indicates whether the plugin is initialized or not. 14137 * @protected 14138 * @type {Boolean} 14139 */ 14140 this._initialized = false;
vendor: 14,104 bytes, lines 14141-14669
14141 14142 /** 14143 * The current paging indexes. 14144 * @protected 14145 * @type {Array} 14146 */ 14147 this._pages = []; 14148 14149 /** 14150 * All DOM elements of the user interface. 14151 * @protected 14152 * @type {Object} 14153 */ 14154 this._controls = {}; 14155 14156 /** 14157 * Markup for an indicator. 14158 * @protected 14159 * @type {Array.<String>} 14160 */ 14161 this._templates = []; 14162 14163 /** 14164 * The carousel element. 14165 * @type {jQuery} 14166 */ 14167 this.$element = this._core.$element; 14168 14169 /** 14170 * Overridden methods of the carousel. 14171 * @protected 14172 * @type {Object} 14173 */ 14174 this._overrides = { 14175 next: this._core.next, 14176 prev: this._core.prev, 14177 to: this._core.to 14178 }; 14179 14180 /** 14181 * All event handlers. 14182 * @protected 14183 * @type {Object} 14184 */ 14185 this._handlers = { 14186 'prepared.owl.carousel': $.proxy(function(e) { 14187 if (e.namespace && this._core.settings.dotsData) { 14188 this._templates.push('<div class="' + this._core.settings.dotClass + '">' + 14189 $(e.content).find('[data-dot]').andSelf('[data-dot]').attr('data-dot') + '</div>'); 14190 } 14191 }, this), 14192 'added.owl.carousel': $.proxy(function(e) { 14193 if (e.namespace && this._core.settings.dotsData) { 14194 this._templates.splice(e.position, 0, this._templates.pop()); 14195 } 14196 }, this), 14197 'remove.owl.carousel': $.proxy(function(e) { 14198 if (e.namespace && this._core.settings.dotsData) { 14199 this._templates.splice(e.position, 1); 14200 } 14201 }, this), 14202 'changed.owl.carousel': $.proxy(function(e) { 14203 if (e.namespace && e.property.name == 'position') { 14204 this.draw(); 14205 } 14206 }, this), 14207 'initialized.owl.carousel': $.proxy(function(e) { 14208 if (e.namespace && !this._initialized) { 14209 this._core.trigger('initialize', null, 'navigation'); 14210 this.initialize(); 14211 this.update(); 14212 this.draw(); 14213 this._initialized = true; 14214 this._core.trigger('initialized', null, 'navigation'); 14215 } 14216 }, this), 14217 'refreshed.owl.carousel': $.proxy(function(e) { 14218 if (e.namespace && this._initialized) { 14219 this._core.trigger('refresh', null, 'navigation'); 14220 this.update(); 14221 this.draw(); 14222 this._core.trigger('refreshed', null, 'navigation'); 14223 } 14224 }, this) 14225 }; 14226 14227 // set default options 14228 this._core.options = $.extend({}, Navigation.Defaults, this._core.options); 14229 14230 // register event handlers 14231 this.$element.on(this._handlers); 14232 }; 14233 14234 /** 14235 * Default options. 14236 * @public 14237 * @todo Rename `slideBy` to `navBy` 14238 */ 14239 Navigation.Defaults = { 14240 nav: false, 14241 navText: [ 'prev', 'next' ], 14242 navSpeed: false, 14243 navElement: 'div', 14244 navContainer: false, 14245 navContainerClass: 'owl-nav', 14246 navClass: [ 'owl-prev', 'owl-next' ], 14247 slideBy: 1, 14248 dotClass: 'owl-dot', 14249 dotsClass: 'owl-dots', 14250 dots: true, 14251 dotsEach: false, 14252 dotsData: false, 14253 dotsSpeed: false, 14254 dotsContainer: false 14255 }; 14256 14257 /** 14258 * Initializes the layout of the plugin and extends the carousel. 14259 * @protected 14260 */ 14261 Navigation.prototype.initialize = function() { 14262 var override, 14263 settings = this._core.settings; 14264 14265 // create DOM structure for relative navigation 14266 this._controls.$relative = (settings.navContainer ? $(settings.navContainer) 14267 : $('<div>').addClass(settings.navContainerClass).appendTo(this.$element)).addClass('disabled'); 14268 14269 this._controls.$previous = $('<' + settings.navElement + '>') 14270 .addClass(settings.navClass[0]) 14271 .html(settings.navText[0]) 14272 .prependTo(this._controls.$relative) 14273 .on('click', $.proxy(function(e) { 14274 this.prev(settings.navSpeed); 14275 }, this)); 14276 this._controls.$next = $('<' + settings.navElement + '>') 14277 .addClass(settings.navClass[1]) 14278 .html(settings.navText[1]) 14279 .appendTo(this._controls.$relative) 14280 .on('click', $.proxy(function(e) { 14281 this.next(settings.navSpeed); 14282 }, this)); 14283 14284 // create DOM structure for absolute navigation 14285 if (!settings.dotsData) { 14286 this._templates = [ $('<div>') 14287 .addClass(settings.dotClass) 14288 .append($('<span>')) 14289 .prop('outerHTML') ]; 14290 } 14291 14292 this._controls.$absolute = (settings.dotsContainer ? $(settings.dotsContainer) 14293 : $('<div>').addClass(settings.dotsClass).appendTo(this.$element)).addClass('disabled'); 14294 14295 this._controls.$absolute.on('click', 'div', $.proxy(function(e) { 14296 var index = $(e.target).parent().is(this._controls.$absolute) 14297 ? $(e.target).index() : $(e.target).parent().index(); 14298 14299 e.preventDefault(); 14300 14301 this.to(index, settings.dotsSpeed); 14302 }, this)); 14303 14304 // override public methods of the carousel 14305 for (override in this._overrides) { 14306 this._core[override] = $.proxy(this[override], this); 14307 } 14308 }; 14309 14310 /** 14311 * Destroys the plugin. 14312 * @protected 14313 */ 14314 Navigation.prototype.destroy = function() { 14315 var handler, control, property, override; 14316 14317 for (handler in this._handlers) { 14318 this.$element.off(handler, this._handlers[handler]); 14319 } 14320 for (control in this._controls) { 14321 this._controls[control].remove(); 14322 } 14323 for (override in this.overides) { 14324 this._core[override] = this._overrides[override]; 14325 } 14326 for (property in Object.getOwnPropertyNames(this)) { 14327 typeof this[property] != 'function' && (this[property] = null); 14328 } 14329 }; 14330 14331 /** 14332 * Updates the internal state. 14333 * @protected 14334 */ 14335 Navigation.prototype.update = function() { 14336 var i, j, k, 14337 lower = this._core.clones().length / 2, 14338 upper = lower + this._core.items().length, 14339 maximum = this._core.maximum(true), 14340 settings = this._core.settings, 14341 size = settings.center || settings.autoWidth || settings.dotsData 14342 ? 1 : settings.dotsEach || settings.items; 14343 14344 if (settings.slideBy !== 'page') { 14345 settings.slideBy = Math.min(settings.slideBy, settings.items); 14346 } 14347 14348 if (settings.dots || settings.slideBy == 'page') { 14349 this._pages = []; 14350 14351 for (i = lower, j = 0, k = 0; i < upper; i++) { 14352 if (j >= size || j === 0) { 14353 this._pages.push({ 14354 start: Math.min(maximum, i - lower), 14355 end: i - lower + size - 1 14356 }); 14357 if (Math.min(maximum, i - lower) === maximum) { 14358 break; 14359 } 14360 j = 0, ++k; 14361 } 14362 j += this._core.mergers(this._core.relative(i)); 14363 } 14364 } 14365 }; 14366 14367 /** 14368 * Draws the user interface. 14369 * @todo The option `dotsData` wont work. 14370 * @protected 14371 */ 14372 Navigation.prototype.draw = function() { 14373 var difference, 14374 settings = this._core.settings, 14375 disabled = this._core.items().length <= settings.items, 14376 index = this._core.relative(this._core.current()), 14377 loop = settings.loop || settings.rewind; 14378 14379 this._controls.$relative.toggleClass('disabled', !settings.nav || disabled); 14380 14381 if (settings.nav) { 14382 this._controls.$previous.toggleClass('disabled', !loop && index <= this._core.minimum(true)); 14383 this._controls.$next.toggleClass('disabled', !loop && index >= this._core.maximum(true)); 14384 } 14385 14386 this._controls.$absolute.toggleClass('disabled', !settings.dots || disabled); 14387 14388 if (settings.dots) { 14389 difference = this._pages.length - this._controls.$absolute.children().length; 14390 14391 if (settings.dotsData && difference !== 0) { 14392 this._controls.$absolute.html(this._templates.join('')); 14393 } else if (difference > 0) { 14394 this._controls.$absolute.append(new Array(difference + 1).join(this._templates[0])); 14395 } else if (difference < 0) { 14396 this._controls.$absolute.children().slice(difference).remove(); 14397 } 14398 14399 this._controls.$absolute.find('.active').removeClass('active'); 14400 this._controls.$absolute.children().eq($.inArray(this.current(), this._pages)).addClass('active'); 14401 } 14402 }; 14403 14404 /** 14405 * Extends event data. 14406 * @protected 14407 * @param {Event} event - The event object which gets thrown. 14408 */ 14409 Navigation.prototype.onTrigger = function(event) { 14410 var settings = this._core.settings; 14411 14412 event.page = { 14413 index: $.inArray(this.current(), this._pages), 14414 count: this._pages.length, 14415 size: settings && (settings.center || settings.autoWidth || settings.dotsData 14416 ? 1 : settings.dotsEach || settings.items) 14417 }; 14418 }; 14419 14420 /** 14421 * Gets the current page position of the carousel. 14422 * @protected 14423 * @returns {Number} 14424 */ 14425 Navigation.prototype.current = function() { 14426 var current = this._core.relative(this._core.current()); 14427 return $.grep(this._pages, $.proxy(function(page, index) { 14428 return page.start <= current && page.end >= current; 14429 }, this)).pop(); 14430 }; 14431 14432 /** 14433 * Gets the current succesor/predecessor position. 14434 * @protected 14435 * @returns {Number} 14436 */ 14437 Navigation.prototype.getPosition = function(successor) { 14438 var position, length, 14439 settings = this._core.settings; 14440 14441 if (settings.slideBy == 'page') { 14442 position = $.inArray(this.current(), this._pages); 14443 length = this._pages.length; 14444 successor ? ++position : --position; 14445 position = this._pages[((position % length) + length) % length].start; 14446 } else { 14447 position = this._core.relative(this._core.current()); 14448 length = this._core.items().length; 14449 successor ? position += settings.slideBy : position -= settings.slideBy; 14450 } 14451 14452 return position; 14453 }; 14454 14455 /** 14456 * Slides to the next item or page. 14457 * @public 14458 * @param {Number} [speed=false] - The time in milliseconds for the transition. 14459 */ 14460 Navigation.prototype.next = function(speed) { 14461 $.proxy(this._overrides.to, this._core)(this.getPosition(true), speed); 14462 }; 14463 14464 /** 14465 * Slides to the previous item or page. 14466 * @public 14467 * @param {Number} [speed=false] - The time in milliseconds for the transition. 14468 */ 14469 Navigation.prototype.prev = function(speed) { 14470 $.proxy(this._overrides.to, this._core)(this.getPosition(false), speed); 14471 }; 14472 14473 /** 14474 * Slides to the specified item or page. 14475 * @public 14476 * @param {Number} position - The position of the item or page. 14477 * @param {Number} [speed] - The time in milliseconds for the transition. 14478 * @param {Boolean} [standard=false] - Whether to use the standard behaviour or not. 14479 */ 14480 Navigation.prototype.to = function(position, speed, standard) { 14481 var length; 14482 14483 if (!standard) { 14484 length = this._pages.length; 14485 $.proxy(this._overrides.to, this._core)(this._pages[((position % length) + length) % length].start, speed); 14486 } else { 14487 $.proxy(this._overrides.to, this._core)(position, speed); 14488 } 14489 }; 14490 14491 $.fn.owlCarousel.Constructor.Plugins.Navigation = Navigation; 14492 14493})(window.Zepto || window.jQuery, window, document); 14494 14495/** 14496 * Hash Plugin 14497 * @version 2.0.0-beta.3 14498 * @author Artus Kolanowski 14499 * @license The MIT License (MIT) 14500 */ 14501;(function($, window, document, undefined) { 14502 'use strict'; 14503 14504 /** 14505 * Creates the hash plugin. 14506 * @class The Hash Plugin 14507 * @param {Owl} carousel - The Owl Carousel 14508 */ 14509 var Hash = function(carousel) { 14510 /** 14511 * Reference to the core. 14512 * @protected 14513 * @type {Owl} 14514 */ 14515 this._core = carousel; 14516 14517 /** 14518 * Hash index for the items. 14519 * @protected 14520 * @type {Object} 14521 */ 14522 this._hashes = {}; 14523 14524 /** 14525 * The carousel element. 14526 * @type {jQuery} 14527 */ 14528 this.$element = this._core.$element; 14529 14530 /** 14531 * All event handlers. 14532 * @protected 14533 * @type {Object} 14534 */ 14535 this._handlers = { 14536 /*'initialized.owl.carousel': $.proxy(function(e) { 14537 if (e.namespace && this._core.settings.startPosition === 'URLHash') { 14538 $(window).trigger('hashchange.owl.navigation'); 14539 } 14540 }, this),*/ 14541 'prepared.owl.carousel': $.proxy(function(e) { 14542 if (e.namespace) { 14543 var hash = $(e.content).find('[data-hash]').addBack('[data-hash]').attr('data-hash'); 14544 14545 if (!hash) { 14546 return; 14547 } 14548 14549 this._hashes[hash] = e.content; 14550 } 14551 }, this), 14552 'changed.owl.carousel': $.proxy(function(e) { 14553 if (e.namespace && e.property.name === 'position') { 14554 var current = this._core.items(this._core.relative(this._core.current())), 14555 hash = $.map(this._hashes, function(item, hash) { 14556 return item === current ? hash : null; 14557 }).join(); 14558 14559 if (!hash || window.location.hash.slice(1) === hash) { 14560 return; 14561 } 14562 14563 window.location.hash = hash; 14564 } 14565 }, this) 14566 }; 14567 14568 // set default options 14569 this._core.options = $.extend({}, Hash.Defaults, this._core.options); 14570 14571 // register the event handlers 14572 this.$element.on(this._handlers); 14573 14574 // register event listener for hash navigation 14575 /*$(window).on('hashchange.owl.navigation', $.proxy(function(e) { 14576 var hash = window.location.hash.substring(1), 14577 items = this._core.$stage.children(), 14578 position = this._hashes[hash] && items.index(this._hashes[hash]); 14579 14580 if (position === undefined || position === this._core.current()) { 14581 return; 14582 } 14583 14584 this._core.to(this._core.relative(position), false, true); 14585 }, this));*/ 14586 }; 14587 14588 /** 14589 * Default options. 14590 * @public 14591 */ 14592 Hash.Defaults = { 14593 URLhashListener: false 14594 }; 14595 14596 /** 14597 * Destroys the plugin. 14598 * @public 14599 */ 14600 Hash.prototype.destroy = function() { 14601 var handler, property; 14602 14603 $(window).off('hashchange.owl.navigation'); 14604 14605 for (handler in this._handlers) { 14606 this._core.$element.off(handler, this._handlers[handler]); 14607 } 14608 for (property in Object.getOwnPropertyNames(this)) { 14609 typeof this[property] != 'function' && (this[property] = null); 14610 } 14611 }; 14612 14613 $.fn.owlCarousel.Constructor.Plugins.Hash = Hash; 14614 14615})(window.Zepto || window.jQuery, window, document); 14616 14617/** 14618 * Support Plugin 14619 * 14620 * @version 2.0.0-beta.3 14621 * @author Vivid Planet Software GmbH 14622 * @author Artus Kolanowski 14623 * @license The MIT License (MIT) 14624 */ 14625;(function($, window, document, undefined) { 14626 14627 var style = $('<support>').get(0).style, 14628 prefixes = 'Webkit Moz O ms'.split(' '), 14629 events = { 14630 transition: { 14631 end: { 14632 WebkitTransition: 'webkitTransitionEnd', 14633 MozTransition: 'transitionend', 14634 OTransition: 'oTransitionEnd', 14635 transition: 'transitionend' 14636 } 14637 }, 14638 animation: { 14639 end: { 14640 WebkitAnimation: 'webkitAnimationEnd', 14641 MozAnimation: 'animationend', 14642 OAnimation: 'oAnimationEnd', 14643 animation: 'animationend' 14644 } 14645 } 14646 }, 14647 tests = { 14648 csstransforms: function() { 14649 return !!test('transform'); 14650 }, 14651 csstransforms3d: function() { 14652 return !!test('perspective'); 14653 }, 14654 csstransitions: function() { 14655 return !!test('transition'); 14656 }, 14657 cssanimations: function() { 14658 return !!test('animation'); 14659 } 14660 }; 14661 14662 function test(property, prefixed) { 14663 var result = false, 14664 upper = property.charAt(0).toUpperCase() + property.slice(1); 14665 14666 $.each((property + ' ' + prefixes.join(upper + ' ') + upper).split(' '), function(i, property) { 14667 if (style[property] !== undefined) { 14668 result = prefixed ? property : true; 14669 return false;
14670 } 14671 }); 14672 14673 return result; 14674 } 14675 14676 function prefixed(property) { 14677 return test(property, true); 14678 } 14679 14680 if (tests.csstransitions()) { 14681 /* jshint -W053 */ 14682 $.support.transition = new String(prefixed('transition')) 14683 $.support.transition.end = events.transition.end[ $.support.transition ]; 14684 } 14685 14686 if (tests.cssanimations()) { 14687 /* jshint -W053 */ 14688 $.support.animation = new String(prefixed('animation')) 14689 $.support.animation.end = events.animation.end[ $.support.animation ]; 14690 } 14691 14692 if (tests.csstransforms()) { 14693 /* jshint -W053 */ 14694 $.support.transform = new String(prefixed('transform')); 14695 $.support.transform3d = tests.csstransforms3d(); 14696 } 14697 14698})(window.Zepto || window.jQuery, window, document); 14699 14700(function(window, document, undefined) { 14701 14702 /** 14703 * Find the absolute position of an element 14704 */ 14705 var absPos = function(element) { 14706 var offsetLeft, offsetTop; 14707 offsetLeft = offsetTop = 0; 14708 if (element.offsetParent) { 14709 do { 14710 offsetLeft += element.offsetLeft; 14711 offsetTop += element.offsetTop; 14712 } while (element = element.offsetParent); 14713 } 14714 return [offsetLeft, offsetTop]; 14715 }; 14716 14717 /** 14718 * @constructor Progress Circle class 14719 * @param params.canvas Canvas on which the circles will be drawn. 14720 * @param params.minRadius Inner radius of the innermost circle, in px. 14721 * @param params.arcWidth Width of each circle(to be more accurate, ring). 14722 * @param params.gapWidth Space between each circle. 14723 * @param params.centerX X coordinate of the center of circles. 14724 * @param params.centerY Y coordinate of the center of circles. 14725 * @param params.infoLineBaseAngle Base angle of the info line. 14726 * @param params.infoLineAngleInterval Angles between the info lines. 14727 */ 14728 var ProgressCircle = function(params) { 14729 this.canvas = params.canvas; 14730 this.minRadius = params.minRadius || 15; 14731 this.arcWidth = params.arcWidth || 5; 14732 this.gapWidth = params.gapWidth || 3; 14733 this.centerX = params.centerX || this.canvas.width / 2; 14734 this.centerY = params.centerY || this.canvas.height / 2;
14735 this.infoLineLength = params.infoLineLength || 60; 14736 this.horizLineLength = params.horizLineLength || 10; 14737 this.infoLineAngleInterval = params.infoLineAngleInterval || Math.PI / 8; 14738 this.infoLineBaseAngle = params.infoLineBaseAngle || Math.PI / 6; 14739 14740 this.context = this.canvas.getContext('2d'); 14741 14742 this.width = this.canvas.width; 14743 this.height = this.canvas.height; 14744 14745 this.circles = []; 14746 this.runningCount = 0; 14747 }; 14748 14749 ProgressCircle.prototype = { 14750 constructor: ProgressCircle, 14751 14752 /** 14753 * @method Adds an progress monitor entry. 14754 * @param params.fillColor Color to fill in the circle. 14755 * @param params.outlineColor Color to outline the circle. 14756 * @param params.progressListener Callback function to fetch the progress. 14757 * @param params.infoListener Callback function to fetch the info. 14758 * @returns this 14759 */ 14760 addEntry: function(params) { 14761 this.circles.push(new Circle({ 14762 canvas: this.canvas, 14763 context: this.context, 14764 centerX: this.centerX, 14765 centerY: this.centerY, 14766 innerRadius: this.minRadius + this.circles.length * 14767 (this.gapWidth + this.arcWidth), 14768 arcWidth: this.arcWidth,
14769 infoLineLength: this.infoLineLength, 14770 horizLineLength: this.horizLineLength, 14771 14772 id: this.circles.length, 14773 fillColor: params.fillColor, 14774 outlineColor: params.outlineColor, 14775 progressListener: params.progressListener, 14776 infoListener: params.infoListener, 14777 infoLineAngle: this.infoLineBaseAngle + 14778 this.circles.length * this.infoLineAngleInterval, 14779 })); 14780 14781 return this; 14782 }, 14783 14784 /** 14785 * @method Starts the monitor and updates with the given interval. 14786 * @param interval Interval between updates, in millisecond. 14787 * @returns this 14788 */ 14789 start: function(interval) { 14790 var self = this; 14791 this.timer = setInterval(function() { 14792 self._update(); 14793 }, interval || 33); 14794 14795 return this; 14796 }, 14797 14798 /** 14799 * @method Stop the animation. 14800 */ 14801 stop: function() { 14802 clearTimeout(this.timer); 14803 }, 14804 14805 /** 14806 * @private 14807 * @method Call update on each circle and redraw them. 14808 * @returns this 14809 */ 14810 _update: function() { 14811 this._clear(); 14812 this.circles.forEach(function(circle, idx, array) { 14813 circle.update(); 14814 }); 14815 14816 return this; 14817 }, 14818 14819 /** 14820 * @private 14821 * @method Clear the canvas. 14822 * @returns this 14823 */ 14824 _clear: function() { 14825 this.context.clearRect(0, 0, this.canvas.width, this.canvas.height); 14826 14827 return this; 14828 }, 14829 14830 }; 14831 14832 /** 14833 * @private 14834 * @class Individual progress circle. 14835 * @param params.canvas Canvas on which the circle will be drawn. 14836 * @param params.context Context of the canvas. 14837 * @param params.innerRadius Inner radius of the circle, in px. 14838 * @param params.arcWidth Width of each arc(circle). 14839 * @param params.gapWidth Distance between each arc. 14840 * @param params.centerX X coordinate of the center of circles. 14841 * @param params.centerY Y coordinate of the center of circles. 14842 * @param params.fillColor Color to fill in the circle. 14843 * @param params.outlineColor Color to outline the circle. 14844 * @param params.progressListener Callback function to fetch the progress. 14845 * @param params.infoListener Callback function to fetch the info. 14846 * @param params.infoLineAngle Angle of info line. 14847 */ 14848 var Circle = function(params) { 14849 this.id = params.id; 14850 this.canvas = params.canvas; 14851 this.context = params.context; 14852 this.centerX = params.centerX; 14853 this.centerY = params.centerY; 14854 this.arcWidth = params.arcWidth; 14855 this.innerRadius = params.innerRadius || 0; 14856 this.fillColor = params.fillColor || '#fff'; 14857 this.outlineColor = params.outlineColor || this.fillColor; 14858 this.progressListener = params.progressListener;
14859 this.infoLineLength = params.infoLineLength || 250; 14860 this.horizLineLength = params.horizLineLength || 50; 14861 this.infoListener = params.infoListener; 14862 this.infoLineAngle = params.infoLineAngle; 14863 14864 this.outerRadius = this.innerRadius + this.arcWidth; 14865 14866 // If the info listener is not registered, then don't calculate 14867 // the related coordinates 14868 if (!this.infoListener) return; 14869 14870 // calculate the info-line turning points 14871 var angle = this.infoLineAngle, 14872 arcDistance = (this.innerRadius + this.outerRadius) / 2, 14873 14874 sinA = Math.sin(angle), 14875 cosA = Math.cos(angle); 14876 14877 this.infoLineStartX = this.centerX + sinA * arcDistance; 14878 this.infoLineStartY = this.centerY - cosA * arcDistance; 14879 14880 this.infoLineMidX = this.centerX + sinA * this.infoLineLength; 14881 this.infoLineMidY = this.centerY - cosA * this.infoLineLength; 14882 14883 this.infoLineEndX = this.infoLineMidX + 14884 (sinA < 0 ? -this.horizLineLength : this.horizLineLength); 14885 this.infoLineEndY = this.infoLineMidY; 14886 14887 var infoText = document.createElement('div'), 14888 style = infoText.style; 14889 14890 style.color = this.fillColor; 14891 style.position = 'absolute'; 14892 style.left = this.infoLineEndX + absPos(this.canvas)[0] + 'px'; 14893 // style.top will be calculated in the `drawInfo` method. Since 14894 // user may want to change the size of the font, so the top offset 14895 // must be updated in each loop. 14896 infoText.className = 'ProgressCircleInfo'; // For css styling 14897 infoText.id = 'progress_circle_info_' + this.id; 14898 document.body.appendChild(infoText); 14899 this.infoText = infoText; 14900 }; 14901 14902 Circle.prototype = { 14903 constructor: Circle, 14904 14905 update: function() { 14906 this.progress = this.progressListener(); 14907 this._draw(); 14908 14909 if (this.infoListener) { 14910 this.info = this.infoListener(); 14911 this._drawInfo(); 14912 } 14913 }, 14914 14915 /** 14916 * @private 14917 * @method Draw the circle on the canvas. 14918 * @returns this 14919 */ 14920 _draw: function() { 14921 var ctx = this.context, 14922 14923 ANGLE_OFFSET = -Math.PI / 2, 14924 14925 startAngle = 0 + ANGLE_OFFSET, 14926 endAngle= startAngle + this.progress * Math.PI * 2, 14927 14928 x = this.centerX, 14929 y = this.centerY, 14930 14931 innerRadius = this.innerRadius - this.arcWidth - 1, 14932 outerRadius = this.outerRadius - this.arcWidth - 1; 14933 14934 if ( innerRadius < 0 ) 14935 return; 14936 14937 ctx.fillStyle = this.fillColor; 14938 ctx.strokeStyle = this.outlineColor; 14939 14940 ctx.beginPath(); 14941 ctx.arc(x, y, innerRadius, startAngle, endAngle, false); 14942 ctx.arc(x, y, outerRadius, endAngle, startAngle, true); 14943 ctx.closePath(); 14944 ctx.stroke(); 14945 ctx.fill(); 14946 14947 return this; 14948 }, 14949 14950 /** 14951 * @private 14952 * @method Draw the info lines and info text. 14953 * @returns this 14954 */ 14955 _drawInfo: function() { 14956 14957 var pointList, lineHeight; 14958 14959 pointList = [ 14960 [this.infoLineStartX, this.infoLineStartY], 14961 [this.infoLineMidX, this.infoLineMidY], 14962 [this.infoLineEndX, this.infoLineEndY], 14963 ]; 14964 this._drawSegments(pointList, false); 14965 14966 this.infoText.innerHTML = this.info; 14967 14968 lineHeight = this.infoText.offsetHeight; 14969 this.infoText.style.top = this.infoLineEndY + 14970 absPos(this.canvas)[1] - lineHeight / 2 + 'px'; 14971 14972 return this; 14973 }, 14974 14975 /** 14976 * @private 14977 * @method Helper function to draw the segments 14978 * @param pointList An array of points in the form of [x, y]. 14979 * @param close Whether to connect the first and last point. 14980 */ 14981 _drawSegments: function(pointList, close) { 14982 var ctx = this.context; 14983 14984 ctx.beginPath(); 14985 ctx.moveTo(pointList[0][0], pointList[0][1]); 14986 for (var i = 1; i < pointList.length; ++i) { 14987 ctx.lineTo(pointList[i][0], pointList[i][1]); 14988 } 14989 14990 if (close) { 14991 ctx.closePath(); 14992 } 14993 ctx.stroke(); 14994 }, 14995 }; 14996 14997 window.ProgressCircle = ProgressCircle; 14998 14999})(window, document); 15000 15001 15002 15003 15004/* ========================================================= 15005 * jquery.vc_chart.js v1.0 15006 * ========================================================= 15007 * Copyright 2013 Wpbakery 15008 * 15009 * Jquery chart plugin for the Visual Composer. 15010 * ========================================================= */ 15011(function($){ 15012 /** 15013 * Pie chart animated. 15014 * @param element - DOM element 15015 * @param options - settings object. 15016 * @constructor 15017 */ 15018 var VcChart = function(element, options) { 15019 this.el = element; 15020 this.$el = $(this.el); 15021 var $this = this; 15022 $this.options = $.extend({ 15023 color: 'wpb_button', 15024 units: '', 15025 width: '', 15026 label_selector: '.vc_pie_chart_value', 15027 back_selector: '.vc_pie_chart_back', 15028 responsive: true 15029 }, options); 15030 $this.init(); 15031 }; 15032 VcChart.prototype = { 15033 constructor: VcChart, 15034 _progress_v: 0, 15035 animated: false, 15036 colors: { 15037 'wpb_button': 'rgba(247, 247, 247, 1)', 15038 'btn-primary': 'rgba(0, 136, 204, 1)', 15039 'btn-info': 'rgba(88, 185, 218, 1)', 15040 'btn-success': 'rgba(106, 177, 101, 1)', 15041 'btn-warning': 'rgba(255, 153, 0, 1)', 15042 'btn-danger': 'rgba(255, 103, 91, 1)', 15043 'btn-inverse': 'rgba(85, 85, 85, 1)' 15044 }, 15045 init: function() { 15046 this.setupColor(); 15047 this.value = this.$el.data('pie-value')/100; 15048 this.label_value = this.$el.data('pie-label-value') || this.$el.data('pie-value'); 15049 this.$wrapper = $('.vc_pie_wrapper', this.$el); 15050 this.$label = $(this.options.label_selector, this.$el); 15051 this.$back = $(this.options.back_selector, this.$el); 15052 this.$canvas = this.$el.find('canvas'); 15053 this.arcWidth = this.$el.data('pie-width') * 2; 15054 this.draw(); 15055 this.setWayPoint(); 15056 if(this.options.responsive === true) this.setResponsive(); 15057 if (UNCODE.isMobile) this._progress_v = this.value; 15058 }, 15059 setupColor: function() { 15060 // if(typeof this.colors[this.options.color] !== 'undefined') { 15061 // this.color = this.colors[this.options.color]; 15062 // } else if(typeof this.options.color === 'string' && this.options.color.match(/^rgba?\([^\)]+\)/)) { 15063 // this.color = this.options.color; 15064 // } else { 15065 // this.color = 'rgba(247, 247, 247, 0.2)'; 15066 // } 15067 if(typeof this.options.color !== 'undefined') { 15068 this.color = this.options.color; 15069 } else this.color = 'rgba(247, 247, 247, 0.2)'; 15070 15071 }, 15072 setResponsive: function() { 15073 var that = this; 15074 if (!UNCODE.isMobile) { 15075 $(window).resize(function(){ 15076 if(that.animated === true) that.circle.stop(); 15077 that.draw(true); 15078 }); 15079 } 15080 }, 15081 draw: function(redraw) { 15082 var w = this.$el.addClass('vc_ready').width() * 2, 15083 border_w = this.arcWidth, 15084 radius; 15085 if(!w) w = this.$el.parents(':visible').first().width()-2; 15086 //w = Math.round(w/100*80); 15087 //if (w < 250) w = 250; 15088 radius = w/2; 15089 this.$wrapper.css({"width" : (w / 2) + "px"}); 15090 this.$label.css({"width" : (w / 2), "height" : (w / 2), "line-height" : (w / 2)+"px"}); 15091 this.$back.css({"width" : (w / 2), "height" : (w / 2)}); 15092 this.$canvas.attr({"width" : w + "px", "height" : w + "px"}); 15093 this.$el.addClass('vc_ready'); 15094 this.circle = new ProgressCircle({ 15095 canvas: this.$canvas.get(0), 15096 minRadius: radius, 15097 arcWidth: border_w 15098 }); 15099 if(redraw === true && this.animated === true) { 15100 this._progress_v = this.value; 15101 this.circle.addEntry({ 15102 fillColor: this.color, 15103 progressListener: $.proxy(this.setProgress, this) 15104 }).start(); 15105 } 15106 }, 15107 setProgress: function() { 15108 if (this._progress_v >= this.value) { 15109 this.circle.stop(); 15110 this.animated = true; 15111 this.$label.html(this.label_value + this.options.units); 15112 return this._progress_v; 15113 } 15114 this._progress_v += 0.01; 15115 if (!isNaN(this.label_value)) { 15116 var label_value = this._progress_v/this.value*this.label_value; 15117 var val = Math.round(label_value) + this.options.units; 15118 this.$label.html(val); 15119 } else this.$label.html(this.label_value + this.options.units); 15120 return this._progress_v; 15121 }, 15122 animate: function() { 15123 if(this.animated !== true) { 15124 this.circle.addEntry({ 15125 fillColor: this.color, 15126 progressListener: $.proxy(this.setProgress, this) 15127 }).start(10); 15128 } 15129 }, 15130 setWayPoint: function() { 15131 if (typeof $.fn.waypoint !== 'undefined' && !UNCODE.isMobile) { 15132 this.$el.waypoint($.proxy(this.animate, this), { offset: '85%' }); 15133 } else { 15134 this.animate(); 15135 } 15136 } 15137 }; 15138 /** 15139 * jQuery plugin 15140 * @param option - object with settings 15141 * @return {*} 15142 */ 15143 $.fn.vcChat = function(option, value) { 15144 return this.each(function () { 15145 var $this = $(this), 15146 data = $this.data('vc_chart'), 15147 options = typeof option === 'object' ? option : { 15148 color: $this.data('pie-color'), 15149 units: $this.data('pie-units') 15150 }; 15151 if (typeof option == 'undefined') $this.data('vc_chart', (data = new VcChart(this, options))); 15152 if (typeof option == 'string') data[option](value); 15153 }); 15154 }; 15155 /** 15156 * Allows users to rewrite function inside theme. 15157 */ 15158 if ( typeof window['vc_pieChart'] !== 'function' ) { 15159 window.vc_pieChart = function() { 15160 $('.vc_pie_chart:visible:not(.vc_ready)').vcChat(); 15161 } 15162 } 15163 $(document).ready(function(){ 15164 !window.vc_iframe && vc_pieChart(); 15165 15166 /** 15167 * Tab and collapse integration. 15168 */ 15169 $('.nav-tabs a').on('shown.bs.tab', function(e){ 15170 var $cont = $(e.target).closest('.tab-container'), 15171 $active = $('.tab-pane.active', $cont); 15172 $('.vc_pie_chart:not(.vc_ready)', $active).vcChat(); 15173 }); 15174 15175 $('.panel-collapse').on('shown.bs.collapse', function (e) { 15176 $('.vc_pie_chart:not(.vc_ready)', e.target).vcChat(); 15177 }) 15178 }); 15179 15180})(window.jQuery); 15181 15182/* Progress bar 15183 ---------------------------------------------------------- */ 15184function uncode_progress_bar() {    15185 jQuery.each(jQuery('.vc_progress_bar'), function(index, val) { 15186 if (UNCODE.isUnmodalOpen && !val.closest('#unmodal-content')) { 15187 return; 15188 } 15189 if (!UNCODE.isMobile) { 15190 new Waypoint({ 15191 context: UNCODE.isUnmodalOpen ? document.getElementById('unmodal-content') : window, 15192 element: val, 15193 handler: function() { 15194 var element = jQuery(this.element); 15195 element.find('.vc_single_bar').each(function(index) {          15196 var $this = jQuery(this), 15197             bar = $this.find('.vc_bar'), 15198             val = bar.data('percentage-value');          15199 setTimeout(function() {            15200 bar.css({ 15201 "width": val + '%' 15202 });          15203 }, index * 200);        15204 }); 15205 }, 15206 offset: '80%' 15207 }); 15208 } else { 15209 var element = jQuery(val); 15210 element.find('.vc_single_bar').each(function(index) {          15211 var $this = jQuery(this), 15212             bar = $this.find('.vc_bar'), 15213             val = bar.data('percentage-value');          15214 setTimeout(function() {            15215 bar.css({ 15216 "width": val + '%' 15217 });          15218 }, index * 200);        15219 }); 15220 } 15221 }); 15222}; 15223uncode_progress_bar(); 15224 15225/*! 15226 * jquery.counterup.js 1.0 15227 * 15228 * Copyright 2013, Benjamin Intal http://gambit.ph @bfintal 15229 * Released under the GPL v2 License 15230 * 15231 * Date: Nov 26, 2013 15232 */ 15233(function($) { 15234 "use strict"; 15235 $.fn.counterUp = function(options) { 15236 // Defaults 15237 var settings = $.extend({ 15238 'time': 400, 15239 'delay': 10 15240 }, options); 15241 return this.each(function() { 15242 // Store the object 15243 var $this = $(this); 15244 var $settings = settings; 15245 var counterUpper = function() { 15246 var nums = []; 15247 var divisions = $settings.time / $settings.delay; 15248 var numReal = $this.attr('data-val'), 15249 num = numReal; 15250 var isComma = /[0-9]+,[0-9]+/.test(num); 15251 num = num.replace(/,/g, ''); 15252 var isInt = /^[0-9]+$/.test(num); 15253 var isFloat = /^[0-9]+\.[0-9]+$/.test(num); 15254 var decimalPlaces = isFloat ? (num.split('.')[1] || []).length : 0; 15255 // Generate list of incremental numbers to display 15256 for (var i = divisions; i >= 1; i--) { 15257 // Preserve as int if input was int 15258 var newNum = parseInt(num / divisions * i); 15259 // Preserve float if input was float 15260 if (isFloat) { 15261 newNum = parseFloat(num / divisions * i).toFixed(decimalPlaces); 15262 } 15263 // Preserve commas if input had commas 15264 if (isComma) { 15265 while (/(\d+)(\d{3})/.test(newNum.toString())) { 15266 newNum = newNum.toString().replace(/(\d+)(\d{3})/, '$1' + ',' + '$2'); 15267 } 15268 } 15269 nums.unshift(newNum); 15270 } 15271 nums.push(numReal); 15272 $this.data('counterup-nums', nums); 15273 $this.text('0'); 15274 // Updates the number until we're done 15275 var f = function() { 15276 if ($this.data('counterup-nums') != null) { 15277 $this.text($this.data('counterup-nums').shift()); 15278 if ($this.data('counterup-nums').length) { 15279 setTimeout($this.data('counterup-func'), $settings.delay); 15280 } else { 15281 delete $this.data('counterup-nums'); 15282 $this.data('counterup-nums', null); 15283 $this.data('counterup-func', null); 15284 } 15285 } 15286 }; 15287 $this.data('counterup-func', f); 15288 // Start the count up 15289 setTimeout($this.data('counterup-func'), $settings.delay); 15290 }; 15291 // Perform counts when the element gets into view 15292 new Waypoint({ 15293 context: UNCODE.isUnmodalOpen ? document.getElementById('unmodal-content') : window, 15294 element: this, 15295 handler: function() { 15296 counterUpper(); 15297 if (!UNCODE.isUnmodalOpen) { 15298 this.destroy(); 15299 } 15300 }, 15301 offset: '100%' 15302 }); 15303 }); 15304 }; 15305})(jQuery); 15306 15307/*! 15308 * The Final Countdown for jQuery v2.0.4 (http://hilios.github.io/jQuery.countdown/) 15309 * Copyright (c) 2014 Edson Hilios 15310 * 15311 * Permission is hereby granted, free of charge, to any person obtaining a copy of 15312 * this software and associated documentation files (the "Software"), to deal in 15313 * the Software without restriction, including without limitation the rights to 15314 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 15315 * the Software, and to permit persons to whom the Software is furnished to do so, 15316 * subject to the following conditions: 15317 * 15318 * The above copyright notice and this permission notice shall be included in all 15319 * copies or substantial portions of the Software. 15320 * 15321 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15322 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 15323 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15324 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 15325 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 15326 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15327 */ 15328(function(factory) { 15329 "use strict"; 15330 if (typeof define === "function" && define.amd) { 15331 define([ "jquery" ], factory); 15332 } else { 15333 factory(jQuery); 15334 } 15335})(function($) { 15336 "use strict"; 15337 var PRECISION = 100; 15338 var instances = [], matchers = []; 15339 matchers.push(/^[0-9]*$/.source); 15340 matchers.push(/([0-9]{1,2}\/){2}[0-9]{4}( [0-9]{1,2}(:[0-9]{2}){2})?/.source); 15341 matchers.push(/[0-9]{4}([\/\-][0-9]{1,2}){2}( [0-9]{1,2}(:[0-9]{2}){2})?/.source); 15342 matchers = new RegExp(matchers.join("|")); 15343 function parseDateString(dateString) { 15344 if (dateString instanceof Date) { 15345 return dateString; 15346 } 15347 if (String(dateString).match(matchers)) { 15348 if (String(dateString).match(/^[0-9]*$/)) { 15349 dateString = Number(dateString); 15350 } 15351 if (String(dateString).match(/\-/)) { 15352 dateString = String(dateString).replace(/\-/g, "/"); 15353 } 15354 return new Date(dateString); 15355 } else { 15356 throw new Error("Couldn't cast `" + dateString + "` to a date object."); 15357 } 15358 } 15359 var DIRECTIVE_KEY_MAP = { 15360 Y: "years", 15361 m: "months", 15362 w: "weeks", 15363 d: "days", 15364 D: "totalDays", 15365 H: "hours", 15366 M: "minutes", 15367 S: "seconds" 15368 }; 15369 function strftime(offsetObject) { 15370 return function(format) { 15371 var directives = format.match(/%(-|!)?[A-Z]{1}(:[^;]+;)?/gi); 15372 if (directives) { 15373 for (var i = 0, len = directives.length; i < len; ++i) { 15374 var directive = directives[i].match(/%(-|!)?([a-zA-Z]{1})(:[^;]+;)?/), regexp = new RegExp(directive[0]), modifier = directive[1] || "", plural = directive[3] || "", value = null; 15375 directive = directive[2]; 15376 if (DIRECTIVE_KEY_MAP.hasOwnProperty(directive)) { 15377 value = DIRECTIVE_KEY_MAP[directive]; 15378 value = Number(offsetObject[value]); 15379 } 15380 if (value !== null) { 15381 if (modifier === "!") { 15382
15382 value = pluralize(plural, value); 15383 } 15384 if (modifier === "") { 15385 if (value < 10) { 15386 value = "0" + value.toString(); 15387 } 15388 } 15389 format = format.replace(regexp, value.toString()); 15390 } 15391 } 15392 } 15393 format = format.replace(/%%/, "%"); 15394 return format; 15395 }; 15396 } 15397 function pluralize(format, count) { 15398 var plural = "s", singular = ""; 15399 if (format) { 15400 format = format.replace(/(:|;|\s)/gi, "").split(/\,/); 15401 if (format.length === 1) { 15402 plural = format[0]; 15403 } else { 15404 singular = format[0]; 15405 plural = format[1]; 15406 } 15407 } 15408 if (Math.abs(count) === 1) { 15409 return singular; 15410 } else { 15411 return plural; 15412 } 15413 } 15414 var Countdown = function(el, finalDate, callback) { 15415 this.el = el; 15416 this.$el = $(el); 15417 this.interval = null; 15418 this.offset = {}; 15419 this.instanceNumber = instances.length; 15420 instances.push(this); 15421 this.$el.data("countdown-instance", this.instanceNumber); 15422 if (callback) { 15423 this.$el.on("update.countdown", callback); 15424 this.$el.on("stoped.countdown", callback); 15425 this.$el.on("finish.countdown", callback); 15426 } 15427 this.setFinalDate(finalDate); 15428 this.start(); 15429 }; 15430 $.extend(Countdown.prototype, { 15431 start: function() { 15432 if (this.interval !== null) { 15433 clearInterval(this.interval); 15434 } 15435 var self = this; 15436 this.update(); 15437 this.interval = setInterval(function() { 15438 self.update.call(self); 15439 }, PRECISION); 15440 }, 15441 stop: function() { 15442 clearInterval(this.interval); 15443 this.interval = null; 15444 this.dispatchEvent("stoped"); 15445 }, 15446 pause: function() { 15447 this.stop.call(this); 15448 }, 15449 resume: function() { 15450 this.start.call(this); 15451 }, 15452 remove: function() { 15453 this.stop(); 15454 instances[this.instanceNumber] = null; 15455 delete this.$el.data().countdownInstance; 15456 }, 15457 setFinalDate: function(value) { 15458 this.finalDate = parseDateString(value); 15459 }, 15460 update: function() { 15461 if (this.$el.closest("html").length === 0) { 15462 this.remove(); 15463 return; 15464 } 15465 this.totalSecsLeft = this.finalDate.getTime() - new Date().getTime(); 15466 this.totalSecsLeft = Math.ceil(this.totalSecsLeft / 1e3); 15467 this.totalSecsLeft = this.totalSecsLeft < 0 ? 0 : this.totalSecsLeft; 15468 this.offset = { 15469 seconds: this.totalSecsLeft % 60, 15470 minutes: Math.floor(this.totalSecsLeft / 60) % 60, 15471 hours: Math.floor(this.totalSecsLeft / 60 / 60) % 24, 15472 days: Math.floor(this.totalSecsLeft / 60 / 60 / 24) % 7, 15473 totalDays: Math.floor(this.totalSecsLeft / 60 / 60 / 24), 15474 weeks: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 7), 15475 months: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 30), 15476 years: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 365) 15477 }; 15478 if (this.totalSecsLeft === 0) { 15479 this.stop(); 15480 this.dispatchEvent("finish"); 15481 } else { 15482 this.dispatchEvent("update"); 15483 } 15484 }, 15485 dispatchEvent: function(eventName) { 15486 var event = $.Event(eventName + ".countdown"); 15487 event.finalDate = this.finalDate; 15488 event.offset = $.extend({}, this.offset); 15489 event.strftime = strftime(this.offset); 15490 this.$el.trigger(event); 15491 } 15492 }); 15493 $.fn.countdown = function() { 15494 var argumentsArray = Array.prototype.slice.call(arguments, 0); 15495 return this.each(function() {
15496 var instanceNumber = $(this).data("countdown-instance"); 15497 if (instanceNumber !== undefined) { 15498 var instance = instances[instanceNumber], method = argumentsArray[0]; 15499 if (Countdown.prototype.hasOwnProperty(method)) { 15500 instance[method].apply(instance, argumentsArray.slice(1)); 15501 } else if (String(method).match(/^[$A-Z_][0-9A-Z_$]*$/i) === null) { 15502 instance.setFinalDate.call(instance, method); 15503 instance.start(); 15504 } else { 15505 $.error("Method %s does not exist on jQuery.countdown".replace(/\%s/gi, method)); 15506 } 15507 } else { 15508 new Countdown(this, argumentsArray[0], argumentsArray[1]); 15509 } 15510 }); 15511 }; 15512}); 15513 15514/*! waitForImages jQuery Plugin - v2.0.2 - 2015-05-05 15515* https://github.com/alexanderdickson/waitForImages 15516* Copyright (c) 2015 Alex Dickson; Licensed MIT */ 15517;(function (factory) { 15518 if (typeof define === 'function' && define.amd) { 15519 // AMD. Register as an anonymous module. 15520 define(['jquery'], factory); 15521 } else if (typeof exports === 'object') { 15522 // CommonJS / nodejs module 15523 module.exports = factory(require('jquery')); 15524 } else { 15525 // Browser globals 15526 factory(jQuery); 15527 } 15528}(function ($) { 15529 // Namespace all events. 15530 var eventNamespace = 'waitForImages'; 15531 15532 // CSS properties which contain references to images. 15533 $.waitForImages = { 15534 hasImageProperties: [ 15535 'backgroundImage', 15536 'listStyleImage', 15537 'borderImage', 15538 'borderCornerImage', 15539 'cursor' 15540 ], 15541 hasImageAttributes: ['srcset'] 15542 }; 15543 15544 // Custom selector to find `img` elements that have a valid `src` 15545 // attribute and have not already loaded. 15546 $.expr[':'].uncached = function (obj) { 15547 // Ensure we are dealing with an `img` element with a valid 15548 // `src` attribute. 15549 if (!$(obj).is('img[src][src!=""]')) { 15550 return false; 15551 } 15552 15553 return !obj.complete; 15554 }; 15555 15556 $.fn.waitForImages = function () { 15557 15558 var allImgsLength = 0; 15559 var allImgsLoaded = 0; 15560 var deferred = $.Deferred(); 15561 15562 var finishedCallback; 15563 var eachCallback; 15564 var waitForAll; 15565 15566 // Handle options object (if passed). 15567 if ($.isPlainObject(arguments[0])) { 15568 15569 waitForAll = arguments[0].waitForAll; 15570 eachCallback = arguments[0].each; 15571 finishedCallback = arguments[0].finished; 15572 15573 } else { 15574 15575 // Handle if using deferred object and only one param was passed in. 15576 if (arguments.length === 1 && $.type(arguments[0]) === 'boolean') { 15577 waitForAll = arguments[0]; 15578 } else { 15579 finishedCallback = arguments[0]; 15580 eachCallback = arguments[1]; 15581 waitForAll = arguments[2]; 15582 } 15583 15584 } 15585 15586 // Handle missing callbacks. 15587 finishedCallback = finishedCallback || $.noop; 15588 eachCallback = eachCallback || $.noop; 15589 15590 // Convert waitForAll to Boolean 15591 waitForAll = !! waitForAll; 15592 15593 // Ensure callbacks are functions. 15594 if (!$.isFunction(finishedCallback) || !$.isFunction(eachCallback)) { 15595 throw new TypeError('An invalid callback was supplied.'); 15596 } 15597 15598 this.each(function () { 15599 // Build a list of all imgs, dependent on what images will 15600 // be considered. 15601 var obj = $(this); 15602 var allImgs = []; 15603 // CSS properties which may contain an image. 15604 var hasImgProperties = $.waitForImages.hasImageProperties || []; 15605 // Element attributes which may contain an image. 15606 var hasImageAttributes = $.waitForImages.hasImageAttributes || []; 15607 // To match `url()` references. 15608 // Spec: http://www.w3.org/TR/CSS2/syndata.html#value-def-uri 15609 var matchUrl = /url\(\s*(['"]?)(.*?)\1\s*\)/g; 15610 15611 if (waitForAll) { 15612 15613 // Get all elements (including the original), as any one of 15614 // them could have a background image. 15615 obj.find('*').addBack().each(function () { 15616 var element = $(this); 15617 15618 // If an `img` element, add it. But keep iterating in 15619 // case it has a background image too. 15620 if (element.is('img:uncached')) { 15621 allImgs.push({ 15622 src: element.attr('src'), 15623 element: element[0] 15624 }); 15625 } 15626 15627 $.each(hasImgProperties, function (i, property) { 15628 var propertyValue = element.css(property); 15629 var match; 15630 15631 // If it doesn't contain this property, skip. 15632 if (!propertyValue) { 15633 return true; 15634 } 15635 15636 // Get all url() of this element. 15637 while (match = matchUrl.exec(propertyValue)) { 15638 allImgs.push({ 15639 src: match[2], 15640 element: element[0] 15641 }); 15642 } 15643 }); 15644 15645 $.each(hasImageAttributes, function (i, attribute) { 15646 var attributeValue = element.attr(attribute); 15647 var attributeValues; 15648 15649 // If it doesn't contain this property, skip. 15650 if (!attributeValue) { 15651 return true; 15652 } 15653 15654 // Check for multiple comma separated images 15655 attributeValues = attributeValue.split(','); 15656 15657 $.each(attributeValues, function(i, value) { 15658 // Trim value and get string before first 15659 // whitespace (for use with srcset). 15660 value = $.trim(value).split(' ')[0]; 15661 allImgs.push({ 15662 src: value, 15663 element: element[0] 15664 }); 15665 }); 15666 }); 15667 }); 15668 } else { 15669 // For images only, the task is simpler. 15670 obj.find('img:uncached') 15671 .each(function () { 15672 allImgs.push({ 15673 src: this.src, 15674 element: this 15675 }); 15676 }); 15677 } 15678 15679 allImgsLength = allImgs.length; 15680 allImgsLoaded = 0; 15681 15682 // If no images found, don't bother. 15683 if (allImgsLength === 0) { 15684 finishedCallback.call(obj[0]); 15685 deferred.resolveWith(obj[0]); 15686 } 15687 15688 $.each(allImgs, function (i, img) { 15689 15690 var image = new Image(); 15691 var events = 15692 'load.' + eventNamespace + ' error.' + eventNamespace; 15693 15694 // Handle the image loading and error with the same callback. 15695 $(image).one(events, function me (event) { 15696 // If an error occurred with loading the image, set the 15697 // third argument accordingly. 15698 var eachArguments = [ 15699 allImgsLoaded, 15700 allImgsLength,
15701 event.type == 'load' 15702 ]; 15703 allImgsLoaded++; 15704 15705 eachCallback.apply(img.element, eachArguments); 15706 deferred.notifyWith(img.element, eachArguments); 15707 15708 // Unbind the event listeners. I use this in addition to 15709 // `one` as one of those events won't be called (either 15710 // 'load' or 'error' will be called). 15711 $(this).off(events, me); 15712 15713 if (allImgsLoaded == allImgsLength) { 15714 finishedCallback.call(obj[0]); 15715 deferred.resolveWith(obj[0]); 15716 return false; 15717 } 15718 15719 }); 15720 15721 image.src = img.src; 15722 }); 15723 }); 15724 15725 return deferred.promise(); 15726 15727 }; 15728})); 15729 15730/** 15731 * @preserve textfill 15732 * @name jquery.textfill.js 15733 * @author Russ Painter 15734 * @author Yu-Jie Lin 15735 * @author Alexandre Dantas 15736 * @version 0.6.0 15737 * @date 2014-08-19 15738 * @copyright (c) 2014 Alexandre Dantas 15739 * @copyright (c) 2012-2013 Yu-Jie Lin 15740 * @copyright (c) 2009 Russ Painter 15741 * @license MIT License 15742 * @homepage https://github.com/jquery-textfill/jquery-textfill 15743 * @example http://jquery-textfill.github.io/jquery-textfill/index.html 15744 */ 15745; (function($) { 15746 15747 /** 15748 * Resizes an inner element's font so that the 15749 * inner element completely fills the outer element. 15750 * 15751 * @param {Object} options User options that take 15752 * higher precedence when 15753 * merging with the default ones. 15754 * 15755 * @return All outer elements processed 15756 */ 15757 $.fn.textfill = function(options) { 15758 15759 // ______ _______ _______ _______ _ _ _______ _______ 15760 // | \ |______ |______ |_____| | | | | |______ 15761 // |_____/ |______ | | | |_____| |_____ | ______| 15762 // 15763 // Merging user options with the default values 15764 15765 var defaults = { 15766 debug : false, 15767 maxFontPixels : 40, 15768 minFontPixels : 4, 15769 innerTag : 'span', 15770 widthOnly : false, 15771 success : null, // callback when a resizing is done 15772 callback : null, // callback when a resizing is done (deprecated, use success) 15773 fail : null, // callback when a resizing is failed 15774 complete : null, // callback when all is done 15775 explicitWidth : null, 15776 explicitHeight : null, 15777 changeLineHeight : false 15778 }; 15779 15780 var Opts = $.extend(defaults, options); 15781 15782 // _______ _ _ __ _ _______ _______ _____ _____ __ _ _______ 15783 // |______ | | | \ | | | | | | | \ | |______ 15784 // | |_____| | \_| |_____ | __|__ |_____| | \_| ______| 15785 // 15786 // Predefining the awesomeness 15787 15788 // Output arguments to the Debug console 15789 // if "Debug Mode" is enabled 15790 function _debug() { 15791 if (!Opts.debug 15792 || typeof console == 'undefined' 15793 || typeof console.debug == 'undefined') { 15794 return; 15795 } 15796 console.debug.apply(console, arguments); 15797 } 15798 15799 // Output arguments to the Warning console 15800 function _warn() { 15801 if (typeof console == 'undefined' || 15802 typeof console.warn == 'undefined') { 15803 return; 15804 } 15805 console.warn.apply(console, arguments); 15806 } 15807 15808 // Outputs all information on the current sizing 15809 // of the font. 15810 function _debug_sizing(prefix, ourText, maxHeight, maxWidth, minFontPixels, maxFontPixels) { 15811 15812 function _m(v1, v2) { 15813 15814 var marker = ' / '; 15815 15816 if (v1 > v2) 15817 marker = ' > '; 15818 15819 else if (v1 == v2) 15820 marker = ' = '; 15821 15822 return marker; 15823 } 15824 15825 _debug( 15826 '[TextFill] ' + prefix + ' { ' + 15827 'font-size: ' + ourText.css('font-size') + ',' +
15828 'Height: ' + ourText.height() + 'px ' + _m(ourText.height(), maxHeight) + maxHeight + 'px,' + 15829 'Width: ' + ourText.width() + _m(ourText.width() , maxWidth) + maxWidth + ',' + 15830 'minFontPixels: ' + minFontPixels + 'px, ' + 15831 'maxFontPixels: ' + maxFontPixels + 'px }' 15832 ); 15833 } 15834 15835 /** 15836 * Calculates which size the font can get resized, 15837 * according to constrains. 15838 * 15839 * @param {String} prefix Gets shown on the console before 15840 * all the arguments, if debug mode is on. 15841 * @param {Object} ourText The DOM element to resize, 15842 * that contains the text. 15843 * @param {function} func Function called on `ourText` that's 15844 * used to compare with `max`. 15845 * @param {number} max Maximum value, that gets compared with 15846 * `func` called on `ourText`. 15847 * @param {number} minFontPixels Minimum value the font can 15848 * get resized to (in pixels). 15849 * @param {number} maxFontPixels Maximum value the font can 15850 * get resized to (in pixels). 15851 * 15852 * @return Size (in pixels) that the font can be resized. 15853 */ 15854 function _sizing(prefix, ourText, func, max, maxHeight, maxWidth, minFontPixels, maxFontPixels) { 15855 15856 _debug_sizing( 15857 prefix, ourText, 15858 maxHeight, maxWidth, 15859 minFontPixels, maxFontPixels 15860 ); 15861 15862 // The kernel of the whole plugin, take most attention 15863 // on this part. 15864 // 15865 // This is a loop that keeps increasing the `font-size` 15866 // until it fits the parent element. 15867 // 15868 // - Start from the minimal allowed value (`minFontPixels`) 15869 // - Guesses an average font size (in pixels) for the font, 15870 // - Resizes the text and sees if its size is within the 15871 // boundaries (`minFontPixels` and `maxFontPixels`). 15872 // - If so, keep guessing until we break. 15873 // - If not, return the last calculated size. 15874 // 15875 // I understand this is not optimized and we should 15876 // consider implementing something akin to 15877 // Daniel Hoffmann's answer here: 15878 // 15879 // http://stackoverflow.com/a/17433451/1094964 15880 // 15881 15882 while (minFontPixels < (maxFontPixels - 1)) { 15883 15884 var fontSize = Math.floor((minFontPixels + maxFontPixels) / 2); 15885 ourText.css('font-size', fontSize); 15886 15887 if (func.call(ourText) <= max) { 15888 minFontPixels = fontSize; 15889 15890 if (func.call(ourText) == max) 15891 break; 15892 } 15893 else 15894 maxFontPixels = fontSize; 15895 15896 _debug_sizing( 15897 prefix, ourText, 15898 maxHeight, maxWidth, 15899 minFontPixels, maxFontPixels 15900 ); 15901 } 15902 15903 ourText.css('font-size', maxFontPixels); 15904 15905 if (func.call(ourText) <= max) { 15906 minFontPixels = maxFontPixels; 15907 15908 _debug_sizing( 15909 prefix + '* ', ourText, 15910 maxHeight, maxWidth, 15911 minFontPixels, maxFontPixels 15912 ); 15913 } 15914 return minFontPixels; 15915 } 15916 15917 // _______ _______ _______ ______ _______ 15918 // |______ | |_____| |_____/ | 15919 // ______| | | | | \_ | 15920 // 15921 // Let's get it started (yeah)! 15922 15923 _debug('[TextFill] Start Debug'); 15924 15925 this.each(function() { 15926 15927 // Contains the child element we will resize. 15928 // $(this) means the parent container 15929 var ourText = $(Opts.innerTag + ':visible:first', this); 15930 15931 // Will resize to this dimensions. 15932 // Use explicit dimensions when specified 15933 var maxHeight = Opts.explicitHeight || $(this).height(); 15934 var maxWidth = Opts.explicitWidth || $(this).width(); 15935 15936 var oldFontSize = ourText.css('font-size'); 15937 15938 var lineHeight = parseFloat(ourText.css('line-height')) / parseFloat(oldFontSize); 15939 15940 _debug('[TextFill] Inner text: ' + ourText.text()); 15941 _debug('[TextFill] All options: ', Opts); 15942 _debug('[TextFill] Maximum sizes: { ' + 15943 'Height: ' + maxHeight + 'px, ' + 15944 'Width: ' + maxWidth + 'px' + ' }' 15945 ); 15946 15947 var minFontPixels = Opts.minFontPixels; 15948 15949 // Remember, if this `maxFontPixels` is negative, 15950 // the text will resize to as long as the container 15951 // can accomodate 15952 var maxFontPixels = (Opts.maxFontPixels <= 0 ? 15953 maxHeight : 15954 Opts.maxFontPixels); 15955 15956 15957 // Let's start it all! 15958 15959 // 1. Calculate which `font-size` would 15960 // be best for the Height 15961 var fontSizeHeight = undefined; 15962 15963 if (! Opts.widthOnly) 15964 fontSizeHeight = _sizing( 15965 'Height', ourText, 15966 $.fn.height, maxHeight, 15967 maxHeight, maxWidth, 15968 minFontPixels, maxFontPixels 15969 ); 15970 15971 // 2. Calculate which `font-size` would 15972 // be best for the Width 15973 var fontSizeWidth = undefined; 15974 15975 fontSizeWidth = _sizing( 15976 'Width', ourText, 15977 $.fn.width, maxWidth, 15978 maxHeight, maxWidth, 15979 minFontPixels, maxFontPixels 15980 ); 15981 15982 // 3. Actually resize the text! 15983 15984 if (Opts.widthOnly) { 15985 ourText.css({ 15986 'font-size' : fontSizeWidth, 15987 'white-space': 'nowrap' 15988 }); 15989 15990 if (Opts.changeLineHeight) 15991 ourText.parent().css( 15992 'line-height', 15993 (lineHeight * fontSizeWidth + 'px') 15994 ); 15995 } 15996 else { 15997 var fontSizeFinal = Math.min(fontSizeHeight, fontSizeWidth); 15998 15999 ourText.css('font-size', fontSizeFinal); 16000 16001 if (Opts.changeLineHeight) 16002 ourText.parent().css( 16003 'line-height', 16004 (lineHeight * fontSizeFinal) + 'px' 16005 ); 16006 } 16007 16008 _debug( 16009 '[TextFill] Finished { ' + 16010 'Old font-size: ' + oldFontSize + ', ' + 16011 'New font-size: ' + ourText.css('font-size') + ' }' 16012 ); 16013 16014 // Oops, something wrong happened! 16015 // We weren't supposed to exceed the original size 16016 if ((ourText.width() > maxWidth) ||
16017 (ourText.height() > maxHeight && !Opts.widthOnly)) { 16018 16019 ourText.css('font-size', oldFontSize); 16020 16021 // Failure callback 16022 if (Opts.fail) 16023 Opts.fail(this); 16024 16025 _debug( 16026 '[TextFill] Failure { ' + 16027 'Current Width: ' + ourText.width() + ', ' + 16028 'Maximum Width: ' + maxWidth + ', ' + 16029 'Current Height: ' + ourText.height() + ', ' + 16030 'Maximum Height: ' + maxHeight + ' }' 16031 ); 16032 } 16033 else if (Opts.success) { 16034 Opts.success(this); 16035 } 16036 else if (Opts.callback) { 16037 _warn('callback is deprecated, use success, instead'); 16038 16039 // Success callback 16040 Opts.callback(this); 16041 } 16042 }); 16043 16044 // Complete callback 16045 if (Opts.complete) 16046 Opts.complete(this); 16047 16048 _debug('[TextFill] End Debug'); 16049 return this; 16050 }; 16051 16052})(window.jQuery); 16053 16054!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.Share=e()}}(function(){var define,module,exports; 16055function getStyles(config){ 16056 // return ""+config.selector+"{width:92px;height:20px;-webkit-touch-callout:none;-khtml-user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}"+config.selector+" [class*=social-]:before{font-family:'uncodeicon'}"+config.selector+" label{font-size:16px;cursor:pointer;margin:0;padding:5px 10px;border-radius:5px;background:#a29baa;-webkit-transition:all .3s ease-in-out;transition:all .3s ease-in-out}"+config.selector+" label:hover{opacity:.8}"+config.selector+" label span{text-transform:uppercase;font-size:.9em;font-family:Lato,sans-serif;font-weight:700;-webkit-font-smoothing:antialiased;padding-left:6px}"+config.selector+" .social{opacity:0;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out;margin-left:-15px;visibility:hidden}"+config.selector+" .social.top{-webkit-transform-origin:0 0;-ms-transform-origin:0 0;transform-origin:0 0;margin-top:-80px}"+config.selector+" .social.bottom{-webkit-transform-origin:0 0;-ms-transform-origin:0 0;transform-origin:0 0;margin-top:5px}"+config.selector+" .social.middle{margin-top:-34px}"+config.selector+" .social.middle.right{-webkit-transform-origin:5% 50%;-ms-transform-origin:5% 50%;transform-origin:5% 50%;margin-left:105px}"+config.selector+" .social.middle.left{-webkit-transform-origin:5% 50%;-ms-transform-origin:5% 50%;transform-origin:5% 50%}"+config.selector+" .social.right{margin-left:14px}"+config.selector+" .social.load{-webkit-transition:none!important;transition:none!important}"+config.selector+" .social.networks-1{width:60px}"+config.selector+" .social.networks-1.center,"+config.selector+" .social.networks-1.left{margin-left:14px}"+config.selector+" .social.networks-1.middle.left{margin-left:-70px}"+config.selector+" .social.networks-1 ul{width:60px}"+config.selector+" .social.networks-2{width:120px}"+config.selector+" .social.networks-2.center{margin-left:-13px}"+config.selector+" .social.networks-2.left{margin-left:-44px}"+config.selector+" .social.networks-2.middle.left{margin-left:-130px}"+config.selector+" .social.networks-2 ul{width:120px}"+config.selector+" .social.networks-3{width:180px}"+config.selector+" .social.networks-3.center{margin-left:-45px}"+config.selector+" .social.networks-3.left{margin-left:-102px}"+config.selector+" .social.networks-3.middle.left{margin-left:-190px}"+config.selector+" .social.networks-3 ul{width:180px}"+config.selector+" .social.networks-4{width:240px}"+config.selector+" .social.networks-4.center{margin-left:-75px}"+config.selector+" .social.networks-4.left{margin-left:162px}"+config.selector+" .social.networks-4.middle.left{margin-left:-250px}"+config.selector+" .social.networks-4 ul{width:240px}"+config.selector+" .social.networks-5{width:300px}"+config.selector+" .social.networks-5.center{margin-left:-105px}"+config.selector+" .social.networks-5.left{margin-left:-225px}"+config.selector+" .social.networks-5.middle.left{margin-left:-320px}"+config.selector+" .social.networks-5 ul{width:300px}"+config.selector+" .social.active{opacity:1;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out;visibility:visible}"+config.selector+" .social.active.top{-webkit-transform:scale(1) translateY(-20px);-ms-transform:scale(1) translateY(-20px);transform:scale(1) translateY(-20px)}"+config.selector+" .social.active.bottom{-webkit-transform:scale(1) translateY(15px);-ms-transform:scale(1) translateY(15px);transform:scale(1) translateY(15px)}"+config.selector+" .social.active.middle.right{-webkit-transform:scale(1) translateX(10px);-ms-transform:scale(1) translateX(10px);transform:scale(1) translateX(10px)}"+config.selector+" .social.active.middle.left{-webkit-transform:scale(1) translateX(-20px);-ms-transform:scale(1) translateX(-20px);transform:scale(1) translateX(-20px)}"+config.selector+" .social ul{position:relative;
16056left:0;right:0;height:46px;color:#fff;margin:auto;padding:0;list-style:none}"+config.selector+" .social ul li{font-size:20px;cursor:pointer;width:60px;margin:0;padding:12px 0;text-align:center;float:left;display:none;height:22px;position:relative;z-index:2;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-transition:all .3s ease-in-out;transition:all .3s ease-in-out}"+config.selector+" .social ul li:hover{}"+config.selector+" .social li[class*=facebook]{display:"+config.networks.facebook.display+"}"+config.selector+" .social li[class*=twitter]{display:"+config.networks.twitter.display+"}"+config.selector+" .social li[class*=gplus]{display:"+config.networks.google_plus.display+"}"+config.selector+" .social li[class*=pinterest]{display:"+config.networks.pinterest.display+"}"+config.selector+" .social li[class*=paper-plane]{display:"+config.networks.email.display+"}" 16057}; 16058 var ShareUtils; 16059 16060if ((!("classList" in document.documentElement)) && Object.defineProperty && typeof HTMLElement !== "undefined") { 16061 Object.defineProperty(HTMLElement.prototype, "classList", { 16062 get: function() { 16063 var ret, self, update; 16064 update = function(fn) { 16065 return function(value) { 16066 var classes, index; 16067 classes = self.className.split(/\s+/); 16068 index = classes.indexOf(value); 16069 fn(classes, index, value); 16070 self.className = classes.join(" "); 16071 }; 16072 }; 16073 self = this; 16074 ret = { 16075 add: update(function(classes, index, value) { 16076 ~index || classes.push(value); 16077 }), 16078 remove: update(function(classes, index) { 16079 ~index && classes.splice(index, 1); 16080 }), 16081 toggle: update(function(classes, index, value) { 16082 if (~index) { 16083 classes.splice(index, 1); 16084 } else { 16085 classes.push(value); 16086 } 16087 }), 16088 contains: function(value) { 16089 return !!~self.className.split(/\s+/).indexOf(value); 16090 }, 16091 item: function(i) { 16092 return self.className.split(/\s+/)[i] || null; 16093 } 16094 }; 16095 Object.defineProperty(ret, "length", { 16096 get: function() { 16097 return self.className.split(/\s+/).length; 16098 } 16099 }); 16100 return ret; 16101 } 16102 }); 16103} 16104 16105String.prototype.to_rfc3986 = function() { 16106 var tmp; 16107 tmp = encodeURIComponent(this); 16108 return tmp.replace(/[!'()*]/g, function(c) { 16109 return "%" + c.charCodeAt(0).toString(16); 16110 }); 16111}; 16112 16113ShareUtils = (function() { 16114 function ShareUtils() {} 16115 16116 ShareUtils.prototype.extend = function(to, from, overwrite) { 16117 var hasProp, prop; 16118 for (prop in from) { 16119 hasProp = to[prop] !== undefined; 16120 if (hasProp && typeof from[prop] === "object") { 16121 this.extend(to[prop], from[prop], overwrite); 16122 } else { 16123 if (overwrite || !hasProp) { 16124 to[prop] = from[prop]; 16125 } 16126 } 16127 } 16128 }; 16129 16130 ShareUtils.prototype.hide = function(el) { 16131 return el.style.display = "none"; 16132 }; 16133 16134 ShareUtils.prototype.show = function(el) { 16135 return el.style.display = "block"; 16136 }; 16137 16138 ShareUtils.prototype.has_class = function(el, class_name) { 16139 return el.classList.contains(class_name); 16140 }; 16141 16142 ShareUtils.prototype.add_class = function(el, class_name) { 16143 return el.classList.add(class_name); 16144 }; 16145 16146 ShareUtils.prototype.remove_class = function(el, class_name) { 16147 return el.classList.remove(class_name); 16148 }; 16149 16150 ShareUtils.prototype.is_encoded = function(str) { 16151 str = str.to_rfc3986(); 16152 return decodeURIComponent(str) !== str; 16153 }; 16154 16155 ShareUtils.prototype.encode = function(str) { 16156 if (typeof str === "undefined" || this.is_encoded(str)) { 16157 return str; 16158 } else { 16159 return str.to_rfc3986(); 16160 } 16161 }; 16162 16163 ShareUtils.prototype.popup = function(url, params) { 16164 var k, popup, qs, v; 16165 if (params == null) { 16166 params = {}; 16167 } 16168 popup = { 16169 width: 500, 16170 height: 350 16171 }; 16172 popup.top = (screen.height / 2) - (popup.height / 2); 16173 popup.left = (screen.width / 2) - (popup.width / 2); 16174 qs = ((function() { 16175 var _results; 16176 _results = []; 16177 for (k in params) { 16178 v = params[k]; 16179 _results.push("" + k + "=" + (this.encode(v))); 16180 } 16181 return _results; 16182 }).call(this)).join('&'); 16183 if (qs) { 16184 qs = "?" + qs; 16185 } 16186 return window.open(url + qs, 'targetWindow', "toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes,left=" + popup.left + ",top=" + popup.top + ",width="
16186+ popup.width + ",height=" + popup.height); 16187 }; 16188 16189 return ShareUtils; 16190 16191})(); 16192var Share, 16193 __hasProp = {}.hasOwnProperty, 16194 __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; 16195 16196Share = (function(_super) { 16197 __extends(Share, _super); 16198 16199 function Share(element, options) { 16200 this.element = element; 16201 this.el = { 16202 head: document.getElementsByTagName('head')[0], 16203 body: document.getElementsByTagName('body')[0] 16204 }; 16205 this.config = { 16206 enabled_networks: 0, 16207 protocol: ['http', 'https'].indexOf(window.location.href.split(':')[0]) === -1 ? 'https://' : '//', 16208 url: window.location.href.replace("&", "%26"), 16209 caption: null, 16210 title: this.default_title(), 16211 image: this.default_image(), 16212 description: this.default_description(), 16213 ui: { 16214 flyout: 'top center', 16215 button_text: 'Share', 16216 button_font: true, 16217 icon_font: true 16218 }, 16219 networks: { 16220 google_plus: { 16221 enabled: true, 16222 url: null 16223 }, 16224 twitter: { 16225 enabled: true, 16226 url: null, 16227 title: null, 16228 description: null 16229 }, 16230 facebook: { 16231 enabled: true, 16232 load_sdk: true, 16233 url: null, 16234 app_id: null, 16235 title: null, 16236 caption: null, 16237 description: null, 16238 image: null 16239 }, 16240 pinterest: { 16241 enabled: true, 16242 url: null, 16243 image: null, 16244 description: null 16245 }, 16246 reddit: { 16247 enabled: true, 16248 url: null, 16249 title: null 16250 }, 16251 linkedin: { 16252 enabled: true, 16253 url: null, 16254 title: null, 16255 description: null 16256 }, 16257 xing: { 16258 enabled: true, 16259 url: null, 16260 title: null, 16261 image: null, 16262 description: null 16263 }, 16264 whatsapp: { 16265 enabled: true, 16266 description: null, 16267 url: null 16268 }, 16269 email: { 16270 enabled: true, 16271 title: null, 16272 description: null, 16273 url: null 16274 } 16275 } 16276 }; 16277 this.setup(element, options); 16278 return this; 16279 } 16280 16281 Share.prototype.setup = function(element, opts) { 16282 var index, instance, instances, _i, _len; 16283 instances = document.querySelectorAll(element); 16284 this.extend(this.config, opts, true); 16285 this.set_global_configuration(); 16286 this.normalize_network_configuration(); 16287 if (this.config.ui.icon_font) { 16288 this.inject_icons(); 16289 } 16290 if (this.config.ui.button_font) { 16291 this.inject_fonts(); 16292 } 16293 if (this.config.networks.facebook.enabled && this.config.networks.facebook.load_sdk) { 16294 this.inject_facebook_sdk(); 16295 } 16296 for (index = _i = 0, _len = instances.length; _i < _len; index = ++_i) { 16297 instance = instances[index]; 16298 this.setup_instance(element, index); 16299 } 16300 }; 16301 16302 Share.prototype.setup_instance = function(element, index) { 16303 var button, instance, label, network, networks, _i, _len, _results, 16304 _this = this; 16305 instance = document.querySelectorAll(element)[index]; 16306 this.hide(instance); 16307 this.add_class(instance, "sharer-" + index); 16308 instance = document.querySelectorAll(element)[index]; 16309 this.inject_css(instance); 16310 this.inject_html(instance); 16311 this.show(instance); 16312 label = instance.getElementsByTagName("label")[0]; 16313 button = instance.getElementsByClassName("social")[0]; 16314 networks = instance.getElementsByTagName('li'); 16315 this.add_class(button, "networks-" + this.config.enabled_networks); 16316 label.addEventListener("click", function() { 16317 return _this.event_toggle(button); 16318 }); 16319 _this = this; 16320 _results = []; 16321 for (index = _i = 0, _len = networks.length; _i < _len; index = ++_i) { 16322 network = networks[index]; 16323 _results.push(network.addEventListener("click", function() { 16324 _this.event_network(instance, this); 16325 return _this.event_close(button); 16326 })); 16327 } 16328 return _results; 16329 }; 16330 16331 Share.prototype.event_toggle = function(button) { 16332 if (this.has_class(button, "active")) { 16333 return this.event_close(button); 16334 } else { 16335 return this.event_open(button); 16336 } 16337 }; 16338 16339 Share.prototype.event_open = function(button) { 16340 if (this.has_class(button, "load")) { 16341 this.remove_class(button, "load"); 16342 } 16343 return this.add_class(button, "active"); 16344 }; 16345 16346 Share.prototype.event_close = function(button) { 16347 return this.remove_class(button, "active"); 16348 }; 16349 16350 Share.prototype.event_network = function(instance, network) { 16351 var name; 16352 name = network.getAttribute("data-network"); 16353 this.hook("before", name, instance);
16354 this["network_" + name](); 16355 return this.hook("after", name, instance); 16356 }; 16357 16358 Share.prototype.open = function() { 16359 return this["public"]("open"); 16360 }; 16361 16362 Share.prototype.close = function() { 16363 return this["public"]("close"); 16364 }; 16365 16366 Share.prototype.toggle = function() { 16367 return this["public"]("toggle"); 16368 }; 16369 16370 Share.prototype["public"] = function(action) { 16371 var button, index, instance, _i, _len, _ref, _results; 16372 _ref = document.querySelectorAll(this.element); 16373 _results = []; 16374 for (index = _i = 0, _len = _ref.length; _i < _len; index = ++_i) { 16375 instance = _ref[index]; 16376 button = instance.getElementsByClassName("social")[0]; 16377 _results.push(this["event_" + action](button)); 16378 } 16379 return _results; 16380 }; 16381 16382 Share.prototype.network_facebook = function() { 16383 if (this.config.networks.facebook.load_sdk) { 16384 if (!window.FB) { 16385 return console.error("The Facebook JS SDK hasn't loaded yet."); 16386 } 16387 return FB.ui({ 16388 method: 'feed', 16389 name: this.config.networks.facebook.title, 16390 link: this.config.networks.facebook.url, 16391 picture: this.config.networks.facebook.image, 16392 caption: this.config.networks.facebook.caption, 16393 description: this.config.networks.facebook.description 16394 }); 16395 } else { 16396 return this.popup('https://www.facebook.com/sharer/sharer.php', { 16397 u: this.config.networks.facebook.url 16398 }); 16399 } 16400 }; 16401 16402 Share.prototype.network_twitter = function() { 16403 return this.popup('https://twitter.com/intent/tweet', { 16404 text: this.config.networks.twitter.title, 16405 url: this.config.networks.twitter.url 16406 }); 16407 }; 16408 16409 Share.prototype.network_google_plus = function() { 16410 return this.popup('https://plus.google.com/share', { 16411 url: this.config.networks.google_plus.url 16412 }); 16413 }; 16414 16415 Share.prototype.network_pinterest = function() { 16416 return this.popup('https://www.pinterest.com/pin/create/button', { 16417 url: this.config.networks.pinterest.url, 16418 media: this.config.networks.pinterest.image, 16419 description: this.config.networks.pinterest.description 16420 }); 16421 }; 16422 16423 Share.prototype.network_linkedin = function() { 16424 return this.popup('https://www.linkedin.com/shareArticle', { 16425 url: this.config.networks.linkedin.url, 16426 title: this.config.networks.linkedin.title, 16427 summary: this.config.networks.linkedin.description 16428 }); 16429 } 16430 16431 Share.prototype.network_xing = function() { 16432 return this.popup('https://www.xing.com/spi/shares/new', { 16433 url: this.config.networks.xing.url, 16434 image: this.config.networks.xing.image, 16435 title: this.config.networks.xing.title, 16436 summary: this.config.networks.xing.description 16437 }); 16438 } 16439 16440 Share.prototype.network_email = function() { 16441 return this.popup('mailto:', { 16442 subject: this.config.networks.email.title, 16443 body: this.config.networks.email.url + '%0A%0A' + this.config.networks.email.description, 16444 }); 16445 }; 16446 16447 Share.prototype.inject_icons = function() { 16448 // return this.inject_stylesheet("https://www.sharebutton.co/fonts/v2/entypo.min.css"); 16449 }; 16450 16451 Share.prototype.inject_fonts = function() { 16452 // return this.inject_stylesheet("http://fonts.googleapis.com/css?family=Lato:900&text=" + this.config.ui.button_text); 16453 }; 16454 16455 Share.prototype.inject_stylesheet = function(url) { 16456 var link; 16457 if (!this.el.head.querySelector("link[href=\"" + url + "\"]")) { 16458 link = document.createElement("link"); 16459 link.setAttribute("rel", "stylesheet"); 16460 link.setAttribute("href", url); 16461 return this.el.head.appendChild(link); 16462 } 16463 }; 16464 16465 Share.prototype.inject_css = function(instance) { 16466 var css, meta, selector, style; 16467 selector = "." + (instance.getAttribute('class').split(" ").join(".")); 16468 if (!this.el.head.querySelector("meta[name='sharer" + selector + "']")) { 16469 this.config.selector = selector; 16470 css = getStyles(this.config); 16471 style = document.createElement("style"); 16472 style.type = "text/css"; 16473 if (style.styleSheet) { 16474 style.styleSheet.cssText = css; 16475 } else { 16476 style.appendChild(document.createTextNode(css)); 16477 } 16478 this.el.head.appendChild(style); 16479 delete this.config.selector; 16480 meta = document.createElement("meta"); 16481 meta.setAttribute("name", "sharer" + selector); 16482 return this.el.head.appendChild(meta); 16483 } 16484 }; 16485 16486 Share.prototype.inject_html = function(instance) { 16487 //return instance.innerHTML = "<label class='social-export'><span>" + this.config.ui.button_text + "</span></label><div class='social load " + this.config.ui.flyout + "'><ul><li class='social-facebook' data-network='facebook' tabindex='0'></li><li class='social-twitter' data-network='twitter' tabindex='0'></li><li class='social-gplus' data-network='google_plus' tabindex='0'></li><li class='social-pinterest' data-network='pinterest' tabindex='0'></li><li class='social-linkedin' data-network='linkedin' tabindex='0'></li><li class='social-xing' data-network='xing' tabindex='0'></li><li class='social-paper-plane' data-network='email' tabindex='0'></li></ul></div>"; 16488 return instance.innerHTML = "<label class='social-export'><span>" + this.config.ui.button_text + "</span></label><div class='social load " + this.config.ui.flyout + "'><ul><li class='social-facebook' data-network='facebook' tabindex='0'></li><li class='social-twitter' data-network='twitter' tabindex='0'></li><li class='social-pinterest' data-network='pinterest' tabindex='0'></li><li class='social-linkedin' data-network='linkedin' tabindex='0'></li><li class='social-xing' data-network='xing' tabindex='0'></li><li class='social-paper-plane' data-network='email' tabindex='0'></li></ul></div>"; 16489 }; 16490 16491 Share.prototype.inject_facebook_sdk = function() { 16492 var fb_root, script; 16493 if (!window.FB && this.config.networks.facebook.app_id && !this.el.body.querySelector('#fb-root')) { 16494 script = document.createElement("script"); 16495 script.text = "window.fbAsyncInit=function(){FB.init({appId:'" + this.config.networks.facebook.app_id + "',status:true,xfbml:true})};(function(e,t,n){var r,i=e.getElementsByTagName(t)[0];if(e.getElementById(n)){return}r=e.createElement(t);r.id=n;r.src='" + this.config.protocol + "connect.facebook.net/en_US/all.js';i.parentNode.insertBefore(r,i)})(document,'script','facebook-jssdk')"; 16496 fb_root = document.createElement("div"); 16497 fb_root.id = "fb-root"; 16498 this.el.body.appendChild(fb_root); 16499 return this.el.body.appendChild(script); 16500 } 16501 }; 16502 16503 Share.prototype.hook = function(type, network, instance) { 16504 var fn, opts; 16505 fn = this.config.networks[network][type]; 16506 if (typeof fn === "function") { 16507 opts = fn.call(this.config.networks[network], instance); 16508 if (opts !== void 0) { 16509 opts = this.normalize_filter_config_updates(opts); 16510 this.extend(this.config.networks[network], opts, true); 16511 this.normalize_network_configuration(); 16512 } 16513 } 16514 }; 16515 16516 Share.prototype.default_title = function() { 16517 var content; 16518 if (content = document.querySelector('meta[property="og:title"]') || document.querySelector('meta[name="twitter:title"]')) { 16519 return encodeURIComponent(content.getAttribute('content')); 16520 } else if (content = document.querySelector('title')) { 16521 return encodeURIComponent(content.innerText); 16522 } 16523 }; 16524 16525 Share.prototype.default_image = function() { 16526 var content; 16527 if (content = document.querySelector('meta[property="og:image"]') || document.querySelector('meta[name="twitter:image"]')) { 16528 return content.getAttribute('content'); 16529 } 16530 }; 16531 16532 Share.prototype.default_description = function() { 16533 var content; 16534 if (content = document.querySelector('meta[property="og:description"]') || document.querySelector('meta[name="twitter:description"]') || document.querySelector('meta[name="description"]')) { 16535 return encodeURIComponent(content.getAttribute('content')); 16536 } else { 16537 return ''; 16538 } 16539 }; 16540 16541 Share.prototype.set_global_configuration = function() { 16542 var display, network, option, options, _ref, _results; 16543 _ref = this.config.networks; 16544 _results = []; 16545 for (network in _ref) { 16546 options = _ref[network]; 16547 for (option in options) { 16548 if (this.config.networks[network][option] == null) { 16549 this.config.networks[network][option] = this.config[option]; 16550 } 16551 } 16552 if (this.config.networks[network].enabled) { 16553 display = 'block'; 16554 this.config.enabled_networks += 1; 16555 } else { 16556 display = 'none'; 16557 } 16558 _results.push(this.config.networks[network].display = display); 16559 } 16560 return _results; 16561 }; 16562 16563 Share.prototype.normalize_network_configuration = function() { 16564 if (!this.config.networks.facebook.app_id) { 16565 this.config.networks.facebook.load_sdk = false;
16566 } 16567 if (!this.is_encoded(this.config.networks.twitter.description)) { 16568 this.config.networks.twitter.description = encodeURIComponent(this.config.networks.twitter.description); 16569 } 16570 if (typeof this.config.networks.facebook.app_id === 'number') { 16571 return this.config.networks.facebook.app_id = this.config.networks.facebook.app_id.toString(); 16572 } 16573 }; 16574 16575 Share.prototype.normalize_filter_config_updates = function(opts) { 16576 if (this.config.networks.facebook.app_id !== opts.app_id) { 16577 console.warn("You are unable to change the Facebook app_id after the button has been initialized. Please-in-out update your Facebook filters accordingly."); 16578 delete opts.app_id; 16579 } 16580 if (this.config.networks.facebook.load_sdk !== opts.load_sdk) { 16581 console.warn("You are unable to change the Facebook load_sdk option after the button has been initialized. Please-in-out update your Facebook filters accordingly."); 16582 delete opts.app_id; 16583 } 16584 return opts; 16585 }; 16586 16587 return Share; 16588 16589})(ShareUtils); 16590 return Share; 16591}); 16592 16593// Generated by CoffeeScript 1.9.2 16594 16595// @license Sticky-kit v1.1.2 | WTFPL | Leaf Corcoran 2015 | http://leafo.net 16596 16597(function() { 16598 var $, win; 16599 16600 $ = this.jQuery || window.jQuery; 16601 16602 win = $(window); 16603 16604 $.fn.stick_in_parent = function(opts) { 16605 var doc, elm, enable_bottoming, fn, i, inner_scrolling, len, manual_spacer, offset_top, outer_width, parent_selector, recalc_every, sticky_class; 16606 if (opts == null) { 16607 opts = {}; 16608 } 16609 sticky_class = opts.sticky_class, inner_scrolling = opts.inner_scrolling, recalc_every = opts.recalc_every, parent_selector = opts.parent, offset_top = opts.offset_top, manual_spacer = opts.spacer, enable_bottoming = opts.bottoming; 16610 if (offset_top == null) { 16611 offset_top = 0; 16612 } 16613 if (parent_selector == null) { 16614 parent_selector = void 0; 16615 } 16616 if (inner_scrolling == null) { 16617 inner_scrolling = true; 16618 } 16619 if (sticky_class == null) { 16620 sticky_class = "is_stuck"; 16621 } 16622 doc = $(document); 16623 if (enable_bottoming == null) { 16624 enable_bottoming = true; 16625 } 16626 outer_width = function(el) { 16627 var _el, computed, w; 16628 if (window.getComputedStyle) { 16629 _el = el[0]; 16630 computed = window.getComputedStyle(el[0]); 16631 w = parseFloat(computed.getPropertyValue("width")) + parseFloat(computed.getPropertyValue("margin-left")) + parseFloat(computed.getPropertyValue("margin-right")); 16632 if (computed.getPropertyValue("box-sizing") !== "border-box") { 16633 w += parseFloat(computed.getPropertyValue("border-left-width")) + parseFloat(computed.getPropertyValue("border-right-width")) + parseFloat(computed.getPropertyValue("padding-left")) + parseFloat(computed.getPropertyValue("padding-right")); 16634 } 16635 return w; 16636 } else { 16637 return el.outerWidth(true); 16638 } 16639 }; 16640 fn = function(elm, padding_bottom, parent_top, parent_height, top, height, el_float, detached) { 16641 var bottomed, detach, fixed, last_pos, last_scroll_height, offset, parent, recalc, recalc_and_tick, recalc_counter, spacer, tick; 16642 if (elm.data("sticky_kit")) { 16643 return; 16644 } 16645 elm.data("sticky_kit", true); 16646 last_scroll_height = doc.height(); 16647 parent = elm.parent(); 16648 if (parent_selector != null) { 16649 parent = parent.closest(parent_selector); 16650 } 16651 if (!parent.length) { 16652 throw "failed to find stick parent"; 16653 } 16654 fixed = false; 16655 bottomed = false; 16656 spacer = manual_spacer != null ? manual_spacer && elm.closest(manual_spacer) : $("<div />"); 16657 if (spacer) { 16658 spacer.css('position', elm.css('position')); 16659 } 16660 recalc = function() { 16661 var border_top, padding_top, restore; 16662 if (detached) { 16663 return; 16664 } 16665 last_scroll_height = doc.height(); 16666 border_top = parseInt(parent.css("border-top-width"), 10); 16667 padding_top = parseInt(parent.css("padding-top"), 10); 16668 padding_bottom = parseInt(parent.css("padding-bottom"), 10); 16669 parent_top = parent.offset().top + border_top + padding_top; 16670 parent_height = parent.height(); 16671 if (fixed) { 16672 fixed = false;
vendor: 6,068 bytes, lines 16673-16867
16673 bottomed = false; 16674 if (manual_spacer == null) { 16675 elm.insertAfter(spacer); 16676 spacer.detach(); 16677 } 16678 elm.css({ 16679 position: "", 16680 top: "", 16681 width: "", 16682 bottom: "" 16683 }).removeClass(sticky_class); 16684 restore = true; 16685 } 16686 top = elm.offset().top - (parseInt(elm.css("margin-top"), 10) || 0) - offset_top; 16687 height = elm.outerHeight(true); 16688 el_float = elm.css("float"); 16689 if (spacer) { 16690 spacer.css({ 16691 width: outer_width(elm), 16692 height: height, 16693 display: elm.css("display"), 16694 "vertical-align": elm.css("vertical-align"), 16695 "float": el_float 16696 }); 16697 } 16698 if (restore) { 16699 return tick(); 16700 } 16701 }; 16702 recalc(); 16703 if (height === parent_height) { 16704 return; 16705 } 16706 last_pos = void 0; 16707 offset = offset_top; 16708 recalc_counter = recalc_every; 16709 tick = function() { 16710 var css, delta, recalced, scroll, will_bottom, win_height; 16711 if (detached) { 16712 return; 16713 } 16714 recalced = false; 16715 if (recalc_counter != null) { 16716 recalc_counter -= 1; 16717 if (recalc_counter <= 0) { 16718 recalc_counter = recalc_every; 16719 recalc(); 16720 recalced = true; 16721 } 16722 } 16723 if (!recalced && doc.height() !== last_scroll_height) { 16724 recalc(); 16725 recalced = true; 16726 } 16727 scroll = win.scrollTop(); 16728 if (last_pos != null) { 16729 delta = scroll - last_pos; 16730 } 16731 last_pos = scroll; 16732 if (fixed) { 16733 if (enable_bottoming) { 16734 will_bottom = scroll + height + offset > parent_height + parent_top; 16735 if (bottomed && !will_bottom) { 16736 bottomed = false; 16737 elm.css({ 16738 position: "fixed", 16739 bottom: "", 16740 top: offset 16741 }).trigger("sticky_kit:unbottom"); 16742 } 16743 } 16744 if (scroll < top) { 16745 fixed = false; 16746 offset = offset_top; 16747 if (manual_spacer == null) { 16748 if (el_float === "left" || el_float === "right") { 16749 elm.insertAfter(spacer); 16750 } 16751 spacer.detach(); 16752 } 16753 css = { 16754 position: "", 16755 width: "", 16756 top: "" 16757 }; 16758 elm.css(css).removeClass(sticky_class).trigger("sticky_kit:unstick"); 16759 } 16760 if (inner_scrolling) { 16761 win_height = win.height(); 16762 if (height + offset_top > win_height) { 16763 if (!bottomed) { 16764 offset -= delta; 16765 offset = Math.max(win_height - height, offset); 16766 offset = Math.min(offset_top, offset); 16767 if (fixed) { 16768 elm.css({ 16769 top: offset + "px" 16770 }); 16771 } 16772 } 16773 } 16774 } 16775 } else { 16776 if (scroll > top) { 16777 fixed = true; 16778 css = { 16779 position: "fixed", 16780 top: offset 16781 }; 16782 css.width = elm.css("box-sizing") === "border-box" ? elm.outerWidth() + "px" : elm.width() + "px"; 16783 elm.css(css).addClass(sticky_class); 16784 if (manual_spacer == null) { 16785 elm.after(spacer); 16786 if (el_float === "left" || el_float === "right") { 16787 spacer.append(elm); 16788 } 16789 } 16790 elm.trigger("sticky_kit:stick"); 16791 } 16792 } 16793 if (fixed && enable_bottoming) { 16794 if (will_bottom == null) { 16795 will_bottom = scroll + height + offset > parent_height + parent_top; 16796 } 16797 if (!bottomed && will_bottom) { 16798 bottomed = true; 16799 if (parent.css("position") === "static") { 16800 parent.css({ 16801 position: "relative" 16802 }); 16803 } 16804 return elm.css({ 16805 position: "absolute", 16806 bottom: padding_bottom, 16807 top: "auto" 16808 }).trigger("sticky_kit:bottom"); 16809 } 16810 } 16811 }; 16812 recalc_and_tick = function() { 16813 recalc(); 16814 return tick(); 16815 }; 16816 detach = function() { 16817 detached = true; 16818 win.off("touchmove", tick); 16819 win.off("scroll", tick); 16820 win.off("resize", recalc_and_tick); 16821 $(document.body).off("sticky_kit:recalc", recalc_and_tick); 16822 elm.off("sticky_kit:detach", detach); 16823 elm.removeData("sticky_kit"); 16824 elm.css({ 16825 position: "", 16826 bottom: "", 16827 top: "", 16828 width: "" 16829 }); 16830 parent.position("position", ""); 16831 if (fixed) { 16832 if (manual_spacer == null) { 16833 if (el_float === "left" || el_float === "right") { 16834 elm.insertAfter(spacer); 16835 } 16836 spacer.remove(); 16837 } 16838 return elm.removeClass(sticky_class); 16839 } 16840 }; 16841 win.on("touchmove", tick); 16842 win.on("scroll", tick); 16843 win.on("resize", recalc_and_tick); 16844 $(document.body).on("sticky_kit:recalc", recalc_and_tick); 16845 elm.on("sticky_kit:detach", detach); 16846 return setTimeout(tick, 0); 16847 }; 16848 for (i = 0, len = this.length; i < len; i++) { 16849 elm = this[i]; 16850 fn($(elm)); 16851 } 16852 return this; 16853 }; 16854 16855}).call(this); 16856/* ========================================================================== 16857 * bootstrap-tab-history.js 16858 * Author: Michael Narayan <[email protected]> 16859 * Repository: https://github.com/mnarayan01/bootstrap-tab-history/ 16860 * ========================================================================== 16861 * Licensed under the Apache License, Version 2.0 (the "License"); you may 16862 * not use this file except in compliance with the License. You may obtain a 16863 * copy of the License at 16864 * 16865 * http://www.apache.org/licenses/LICENSE-2.0 16866 * 16867 * Unless required by applicable law or agreed to in writing, softw
16867are 16868 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 16869 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 16870 * License for the specific language governing permissions and limitations 16871 * under the License. 16872 * ========================================================================== */ 16873 16874/* ========================================================================== */ 16875/* JSHint directives */ 16876/* */ 16877/* global BootstrapTabHistory: true */ 16878/* */ 16879/* global document */ 16880/* global jQuery */ 16881/* global history */ 16882/* global window */ 16883/* ========================================================================== */ 16884 16885/** 16886 * Integrate [HTML5 history state tracking](https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Manipulating_the_browser_history) 16887 * with [`bootstrap/tab.js`](http://getbootstrap.com/javascript/#tabs). To enable tracking on a tab element, simply set 16888 * the `data-tab-history` attribute to true (or a string denoting a tab grouping). 16889 * 16890 * See the README for additional information. 16891 * 16892 * Functionality based upon bootstrap/tab.js v3.1.0; reference it when making any changes. 16893 */ 16894 16895BootstrapTabHistory = { 16896 options: { 16897 /** 16898 * When the anchor portion of the URI is used to activate a tab, scroll down to the given offset, rather than the 16899 * element with the given `id` attribute. Set to null to disable. Only relevant if showTabsBasedOnAnchor is true. 16900 * 16901 * May be overriden on a per-element basis by the attribute `data-tab-history-anchor-y-offset`. 16902 * 16903 * @public 16904 * @type {?number} 16905 */ 16906 defaultAnchorYOffset: 0, 16907 /** 16908 * Either 'push' or 'replace', for whether to use `history.pushState` or `history.replaceState`, resp. 16909 * 16910 * May be overriden on a per-element basis by the attribute `data-tab-history-changer`. 16911 * 16912 * @public 16913 * @type {string} 16914 */ 16915 defaultChanger: 'replace', 16916 /** 16917 * If true, update the URL in onShownTab in the calls to `history.pushState` and `history.replaceState`. Otherwise, 16918 * `null` is passed as the third parameter to these calls. 16919 * 16920 * May be overriden on a per-element basis by the attribute `data-tab-history-update-url`. 16921 * 16922 * @public 16923 * @type {boolean} 16924 */ 16925 defaultUpdateURL: false, 16926 /** 16927 * Should the anchor portion of the loaded URI be used to activate a single tab if no history was present on page 16928 * load. 16929 * 16930 * @public 16931 * @type {boolean} 16932 */ 16933 showTabsBasedOnAnchor: true 16934 } 16935}; 16936 16937(function () { 16938 'use strict'; 16939 16940 jQuery(function () { 16941 if(history && history.pushState && history.replaceState) { 16942 var bootstrapTabHistory = history.state && history.state.bootstrapTabHistory; 16943 16944 if(bootstrapTabHistory) { 16945 showTabsBasedOnState(bootstrapTabHistory); 16946 } else { 16947 showTabsBasedOnAnchor(); 16948 } 16949 16950 backfillHistoryState(); 16951 16952 jQuery(document).on('shown.bs.tab show.bs.collapse', onShownTab); 16953 jQuery(window).on('popstate', onPopState); 16954 } else { 16955 showTabsBasedOnAnchor(); 16956 } 16957 }); 16958 16959 /** 16960 * Used to prevent onShownTab from registering shown events that we triggered via showTabsBasedOnState. 16961 * 16962 * @type {boolean} 16963 */ 16964 var showingTabsBasedOnState = false; 16965 16966 /** 16967 * Used to update `history.state` to reflect the default active tabs on initial page load. This supports proper 16968 * `history.back` handling when `data-tab-history-update-url` is true. 16969 */ 16970 function backfillHistoryState() { 16971 var newState = null; 16972 16973 jQuery('li.active > [data-tab-history], .panel-title.active [data-tab-history]').each(function () {//edited by Uncode 16974 var $activeTabElement = jQuery(this); 16975 var selector = getTabSelector($activeTabElement); 16976 16977 if(selector) { 16978 var tabGroup = getTabGroup($activeTabElement); 16979 16980 if(tabGroup) { 16981 newState = createNewHistoryState(newState || history.state, tabGroup, selector); 16982 } 16983 } 16984 }); 16985 16986 if(newState) { 16987 history.replaceState(newState, '', null); 16988 } 16989 } 16990 16991 /** 16992 * Clone the existing state, ensure its bootstrapTabHistory attribute is an Object, and add the provided tabGroup to 16993 * said bootstrapTabHistory attribute. 16994 * 16995 * @param {?object} existingState 16996 * @param {!string} tabGroup 16997 * @param {!string} selector 16998 * @returns {!object} 16999 */ 17000 function createNewHistoryState(existingState, tabGroup, selector) { 17001 // Clone history.state and ensure it has a bootstrapTabHistory entry. 17002 var newState = jQuery.extend(true, {}, existingState, { 17003 bootstrapTabHistory: {} 17004 }); 17005 17006 newState.bootstrapTabHistory[tabGroup] = selector; 17007 17008 return newState; 17009 } 17010 17011 /** 17012 * @param {jQuery} $tab
17013 * @returns {?string} 17014 */ 17015 function getTabGroup($tab) { 17016 return parseTruthyAttributeValue($tab.data('tab-history')); 17017 } 17018 17019 /** 17020 * @param {jQuery} $tab 17021 * @returns {?string} 17022 */ 17023 function getTabSelector($tab) { 17024 return $tab.data('target') || $tab.attr('href'); 17025 } 17026 17027 /** 17028 * Receives the `shown.bs.tab` event. Updates `history.state` as appropriate. 17029 * 17030 * @param {jQuery.Event} shownEvt 17031 */ 17032 function onShownTab(shownEvt) { 17033 if(!showingTabsBasedOnState) { 17034 var $activatedTab = jQuery(shownEvt.target); 17035 if ( $activatedTab.hasClass('panel-collapse') ) 17036 $activatedTab = $activatedTab.closest('.panel').find('a'); 17037 var selector = getTabSelector($activatedTab); 17038 17039 if(selector) { 17040 var tabGroup = getTabGroup($activatedTab); 17041 17042 if(tabGroup) { 17043 var historyChanger = $activatedTab.data('tab-history-changer') || BootstrapTabHistory.options.defaultChanger; 17044 var newState = createNewHistoryState(history.state, tabGroup, selector); 17045 var updateURL = (function ($activatedTab) { 17046 if(selector[0] === '#') { 17047 var elementUpdateURLOption = parseTruthyAttributeValue($activatedTab.data('tab-history-update-url')); 17048 17049 if(elementUpdateURLOption === undefined) { 17050 return BootstrapTabHistory.options.defaultUpdateURL; 17051 } else { 17052 return elementUpdateURLOption; 17053 } 17054 } else { 17055 return false; 17056 } 17057 })($activatedTab); 17058 17059 switch(historyChanger) { 17060 case 'push': 17061 history.pushState(newState, '', updateURL ? selector : null); 17062 break; 17063 case 'replace': 17064 history.replaceState(newState, '', updateURL ? selector : null); 17065 break; 17066 default: 17067 throw new Error('Unknown tab-history-changer: ' + historyChanger); 17068 } 17069 } 17070 } 17071 } 17072 } 17073 17074 /** 17075 * Receives the `popstate` event. Shows tabs based on the value of `history.state` as appropriate. 17076 */ 17077 function onPopState() { 17078 var bootstrapTabHistory = history.state && history.state.bootstrapTabHistory; 17079 17080 if(bootstrapTabHistory) { 17081 showTabsBasedOnState(bootstrapTabHistory); 17082 } 17083 } 17084 17085 /** 17086 * Returns the given value, _unless_ that value is an empty string, in which case `true` is returned. 17087 * 17088 * Rationale: HAML data attributes which are set to `true` are rendered as a blank string. 17089 * 17090 * @param {*} value 17091 * @returns {*} 17092 */ 17093 function parseTruthyAttributeValue(value) { 17094 if(value) { 17095 return value; 17096 } else if(value === '') { 17097 return true; 17098 } else { 17099 return value; 17100 } 17101 } 17102 17103 /** 17104 * Show tabs based upon the anchor component of `window.location`. 17105 */ 17106 function showTabsBasedOnAnchor() { 17107 if(BootstrapTabHistory.options.showTabsBasedOnAnchor) { 17108 var anchor = window.location && window.location.hash; 17109 17110 if(anchor) { 17111 var $tabElement = showTabForSelector(anchor); 17112 17113 if($tabElement && window.addEventListener && window.removeEventListener) { 17114 var anchorYOffset = (function ($tabElement) { 17115 var elementSetting = $tabElement.data('tab-history-anchor-y-offset'); 17116 17117 if(elementSetting === undefined) { 17118 return BootstrapTabHistory.options.defaultAnchorYOffset; 17119 } else { 17120 return elementSetting; 17121 } 17122 })($tabElement); 17123 17124 // HACK: This prevents scrolling to the tab on page load. This relies on the fact that we should never get 17125 // here on `history.forward`, `history.back`, or `location.reload`, since in all those situations the 17126 // `history.state` object should have been used (unless the browser did not support the modern History API). 17127 if(anchorYOffset || anchorYOffset === 0) { 17128 var scrollListener = function resetAnchorScroll () { 17129 window.removeEventListener('scroll', scrollListener); 17130 window.scrollTo(0, anchorYOffset); 17131 }; 17132 17133 window.addEventListener('scroll', scrollListener); 17134 } 17135 } 17136 } 17137 } 17138 } 17139 17140 /** 17141 * Show a tab which corresponds to the provided selector. 17142 * 17143 * @param {string} selector - A CSS selector. 17144 * @returns {?jQuery} - The tab which was found to show (even if said tab was already active). 17145 */ 17146 function showTabForSelector(selector) { 17147 var $tabElement = (function (selector) { 17148 var $ret = null; 17149 17150 jQuery('[data-toggle="tab"], [data-toggle="pill"], [data-toggle="collapse"]').each(function () { 17151 var $potentialTab = jQuery(this); 17152 17153 if(($potentialTab.attr('href') === selector || $potentialTab.data('target') === selector ) && getTabGroup($potentialTab)) { 17154 $ret = $potentialTab; 17155 return false;
vendor: 4,522 bytes, lines 17156-17305
17156 } else { 17157 return null; 17158 } 17159 }); 17160 17161 return $ret; 17162 })(selector); 17163 17164 if($tabElement) { 17165 $tabElement.trigger('click'); 17166 //$tabElement.tab('show'); 17167 } 17168 17169 return $tabElement; 17170 } 17171 17172 /** 17173 * Iterate through the provided set of tab tab groups, showing the tabs based on the stored selectors. 17174 * 17175 * @param {object} bootstrapTabHistory - Each of the values is passed to showTabForSelector; the keys are actually irrelevant. 17176 */ 17177 function showTabsBasedOnState(bootstrapTabHistory) { 17178 showingTabsBasedOnState = true; 17179 17180 try { 17181 for(var k in bootstrapTabHistory) { 17182 if(bootstrapTabHistory.hasOwnProperty(k)) { 17183 showTabForSelector(bootstrapTabHistory[k]); 17184 } 17185 } 17186 } finally { 17187 showingTabsBasedOnState = false; 17188 } 17189 } 17190})(); 17191 17192/*! 17193 * Justified Gallery - v3.6.3 17194 * http://miromannino.github.io/Justified-Gallery/ 17195 * Copyright (c) 2016 Miro Mannino 17196 * Licensed under the MIT license. 17197 */ 17198(function($) { 17199 17200 function hasScrollBar() { 17201 return $("body").height() > $(window).height(); 17202 } 17203 /** 17204 * Justified Gallery controller constructor 17205 * 17206 * @param $gallery the gallery to build 17207 * @param settings the settings (the defaults are in $.fn.justifiedGallery.defaults) 17208 * @constructor 17209 */ 17210 var JustifiedGallery = function ($gallery, settings) { 17211 17212 this.settings = settings; 17213 this.checkSettings(); 17214 17215 this.imgAnalyzerTimeout = null; 17216 this.entries = null; 17217 this.buildingRow = { 17218 entriesBuff : [], 17219 width : 0, 17220 height : 0, 17221 aspectRatio : 0 17222 }; 17223 this.lastFetchedEntry = null; 17224 this.lastAnalyzedIndex = -1; 17225 this.yield = { 17226 every : 2, // do a flush every n flushes (must be greater than 1) 17227 flushed : 0 // flushed rows without a yield 17228 }; 17229 this.border = settings.border >= 0 ? settings.border : settings.margins; 17230 this.maxRowHeight = this.retrieveMaxRowHeight(); 17231 this.suffixRanges = this.retrieveSuffixRanges(); 17232 this.offY = this.border; 17233 this.rows = 0; 17234 this.spinner = { 17235 phase : 0, 17236 timeSlot : 150, 17237 $el : $('<div class="spinner"><span></span><span></span><span></span></div>'), 17238 intervalId : null 17239 }; 17240 this.checkWidthIntervalId = null; 17241 this.galleryWidth = $gallery.width(); 17242 this.$gallery = $gallery; 17243 17244 }; 17245 17246 /** @returns {String} the best suffix given the width and the height */ 17247 JustifiedGallery.prototype.getSuffix = function (width, height) { 17248 var longestSide, i; 17249 longestSide = (width > height) ? width : height; 17250 for (i = 0; i < this.suffixRanges.length; i++) { 17251 if (longestSide <= this.suffixRanges[i]) { 17252 return this.settings.sizeRangeSuffixes[this.suffixRanges[i]]; 17253 } 17254 } 17255 return this.settings.sizeRangeSuffixes[this.suffixRanges[i - 1]]; 17256 }; 17257 17258 /** 17259 * Remove the suffix from the string 17260 * 17261 * @returns {string} a new string without the suffix 17262 */ 17263 JustifiedGallery.prototype.removeSuffix = function (str, suffix) { 17264 return str.substring(0, str.length - suffix.length); 17265 }; 17266 17267 /** 17268 * @returns {boolean} a boolean to say if the suffix is contained in the str or not 17269 */ 17270 JustifiedGallery.prototype.endsWith = function (str, suffix) { 17271 return str.indexOf(suffix, str.length - suffix.length) !== -1; 17272 }; 17273 17274 /** 17275 * Get the used suffix of a particular url 17276 * 17277 * @param str 17278 * @returns {String} return the used suffix 17279 */ 17280 JustifiedGallery.prototype.getUsedSuffix = function (str) { 17281 for (var si in this.settings.sizeRangeSuffixes) { 17282 if (this.settings.sizeRangeSuffixes.hasOwnProperty(si)) { 17283 if (this.settings.sizeRangeSuffixes[si].length === 0) continue; 17284 if (this.endsWith(str, this.settings.sizeRangeSuffixes[si])) return this.settings.sizeRangeSuffixes[si]; 17285 } 17286 } 17287 return ''; 17288 }; 17289 17290 /** 17291 * Given an image src, with the width and the height, returns the new image src with the 17292 * best suffix to show the best quality thumbnail. 17293 * 17294 * @returns {String} the suffix to use 17295 */ 17296 JustifiedGallery.prototype.newSrc = function (imageSrc, imgWidth, imgHeight, image) { 17297 var newImageSrc; 17298 17299 if (this.settings.thumbnailPath) { 17300 newImageSrc = this.settings.thumbnailPath(imageSrc, imgWidth, imgHeight, image); 17301 } else { 17302 var matchRes = imageSrc.match(this.settings.extension); 17303 var ext = (matchRes !== null) ? matchRes[0] : ''; 17304 newImageSrc = imageSrc.replace(this.settings.extension, ''); 17305 newImageSrc = this.removeSuffix(newImageSrc, this.getUsedSuffix(newImageSrc));
17306 newImageSrc += this.getSuffix(imgWidth, imgHeight) + ext; 17307 } 17308 17309 return newImageSrc; 17310 }; 17311 17312 /** 17313 * Shows the images that is in the given entry 17314 * 17315 * @param $entry the entry 17316 * @param callback the callback that is called when the show animation is finished 17317 */ 17318 JustifiedGallery.prototype.showImg = function ($entry, callback) { 17319 if (this.settings.cssAnimation) { 17320 $entry.addClass('entry-visible'); 17321 if (callback) callback(); 17322 } else { 17323 $entry.stop().fadeTo(this.settings.imagesAnimationDuration, 1.0, callback); 17324 $entry.find('> img, > a > img').stop().fadeTo(this.settings.imagesAnimationDuration, 1.0, callback); 17325 } 17326 }; 17327 17328 /** 17329 * Extract the image src form the image, looking from the 'safe-src', and if it can't be found, from the 17330 * 'src' attribute. It saves in the image data the 'jg.originalSrc' field, with the extracted src. 17331 * 17332 * @param $image the image to analyze 17333 * @returns {String} the extracted src 17334 */ 17335 JustifiedGallery.prototype.extractImgSrcFromImage = function ($image) { 17336 var imageSrc = (typeof $image.data('safe-src') !== 'undefined') ? $image.data('safe-src') : $image.attr('src'); 17337 $image.data('jg.originalSrc', imageSrc); 17338 return imageSrc; 17339 }; 17340 17341 /** @returns {jQuery} the image in the given entry */ 17342 JustifiedGallery.prototype.imgFromEntry = function ($entry) { 17343 var $img = $entry.find('> img'); 17344 if ($img.length === 0) $img = $entry.find('> a > img'); 17345 if ($img.length === 0) $img = $entry.find('.t-entry-visual-cont img');//hacked by Uncode 17346 return $img.length === 0 ? null : $img; 17347 }; 17348 17349 /** @returns {jQuery} the caption in the given entry */ 17350 JustifiedGallery.prototype.captionFromEntry = function ($entry) { 17351 var $caption = $entry.find('> .caption'); 17352 return $caption.length === 0 ? null : $caption; 17353 }; 17354 17355 /** 17356 * Display the entry 17357 * 17358 * @param {jQuery} $entry the entry to display 17359 * @param {int} x the x position where the entry must be positioned 17360 * @param y the y position where the entry must be positioned 17361 * @param imgWidth the image width 17362 * @param imgHeight the image height 17363 * @param rowHeight the row height of the row that owns the entry 17364 */ 17365 JustifiedGallery.prototype.displayEntry = function ($entry, x, y, imgWidth, imgHeight, rowHeight) { 17366 $entry.width(imgWidth); 17367 $entry.height(Math.floor(rowHeight));//hacked by Uncode 17368 $entry.css('top', Math.floor(y));//hacked by Uncode 17369 $entry.css('left', x); 17370 17371 var $image = this.imgFromEntry($entry); 17372 if ($image !== null) { 17373 $image.css('width', imgWidth); 17374 $image.css('height', imgHeight); 17375 $image.css('margin-left', - imgWidth / 2); 17376 $image.css('margin-top', - imgHeight / 2); 17377 17378 // Image reloading for an high quality of thumbnails 17379 var imageSrc = $image.attr('src'); 17380 var newImageSrc = this.newSrc(imageSrc, imgWidth, imgHeight, $image[0]); 17381 17382 $image.one('error', function () { 17383 $image.attr('src', $image.data('jg.originalSrc')); //revert to the original thumbnail, we got it. 17384 }); 17385 17386 var loadNewImage = function () { 17387 if (imageSrc !== newImageSrc) { //load the new image after the fadeIn 17388 $image.attr('src', newImageSrc); 17389 } 17390 }; 17391 17392 if ($entry.data('jg.loaded') === 'skipped') { 17393 this.onImageEvent(imageSrc, $.proxy(function() { 17394 this.showImg($entry, loadNewImage); 17395 $entry.data('jg.loaded', true); 17396 }, this)); 17397 } else { 17398 this.showImg($entry, loadNewImage); 17399 } 17400 17401 } else { 17402 this.showImg($entry); 17403 } 17404 17405 this.displayEntryCaption($entry); 17406 }; 17407 17408 /** 17409 * Display the entry caption. If the caption element doesn't exists, it creates the caption using the 'alt' 17410 * or the 'title' attributes. 17411 * 17412 * @param {jQuery} $entry the entry to process 17413 */ 17414 JustifiedGallery.prototype.displayEntryCaption = function ($entry) { 17415 var $image = this.imgFromEntry($entry); 17416 if ($image !== null && this.settings.captions) { 17417 var $imgCaption = this.captionFromEntry($entry); 17418 17419 // Create it if it doesn't exists 17420 if ($imgCaption === null) { 17421 var caption = $image.attr('alt'); 17422 if (!this.isValidCaption(caption)) caption = $entry.attr('title'); 17423 if (this.isValidCaption(caption)) { // Create only we found something 17424 $imgCaption = $('<div class="caption">' + caption + '</div>'); 17425 $entry.append($imgCaption); 17426 $entry.data('jg.createdCaption', true); 17427 } 17428 } 17429 17430 // Create events (we check again the $imgCaption because it can be still inexistent) 17431 if ($imgCaption !== null) { 17432 if (!this.settings.cssAnimation) $imgCaption.stop().fadeTo(0, this.settings.captionSettings.nonVisibleOpacity); 17433 this.addCaptionEventsHandlers($entry); 17434 } 17435 } else { 17436 this.removeCaptionEventsHandlers($entry); 17437 } 17438 }; 17439 17440 /** 17441 * Validates the caption 17442 * 17443 * @param caption The caption that should be validated 17444 * @return {boolean} Validation result 17445 */ 17446 JustifiedGallery.prototype.isValidCaption = function (caption) { 17447 return (typeof caption !== 'undefined' && caption.length > 0); 17448 }; 17449 17450 /** 17451 * The callback for the event 'mouseenter'. It assumes that the event currentTarget is an entry. 17452 * It shows the caption using jQuery (or using CSS if it is configured so) 17453 * 17454 * @param {Event} eventObject the event object 17455 */ 17456 JustifiedGallery.prototype.onEntryMouseEnterForCaption = function (eventObject) { 17457 var $caption = this.captionFromEntry($(eventObject.currentTarget)); 17458 if (this.settings.cssAnimation) { 17459 $caption.addClass('caption-visible').removeClass('caption-hidden'); 17460 } else { 17461 $caption.stop().fadeTo(this.settings.captionSettings.animationDuration, 17462 this.settings.captionSettings.visibleOpacity); 17463 } 17464 }; 17465 17466 /** 17467 * The callback for the event 'mouseleave'. It assumes that the event currentTarget is an entry. 17468 * It hides the caption using jQuery (or using CSS if it is configured so) 17469 * 17470 * @param {Event} eventObject the event object 17471 */ 17472 JustifiedGallery.prototype.onEntryMouseLeaveForCaption = function (eventObject) { 17473 var $caption = this.captionFromEntry($(eventObject.currentTarget)); 17474 if (this.settings.cssAnimation) { 17475 $caption.removeClass('caption-visible').removeClass('caption-hidden'); 17476 } else { 17477 $caption.stop().fadeTo(this.settings.captionSettings.animationDuration, 17478 this.settings.captionSettings.nonVisibleOpacity); 17479 } 17480 }; 17481 17482 /** 17483 * Add the handlers of the entry for the caption 17484 * 17485 * @param $entry the entry to modify 17486 */ 17487 JustifiedGallery.prototype.addCaptionEventsHandlers = function ($entry) { 17488 var captionMouseEvents = $entry.data('jg.captionMouseEvents'); 17489 if (typeof captionMouseEvents === 'undefined') { 17490 captionMouseEvents = { 17491 mouseenter: $.proxy(this.onEntryMouseEnterForCaption, this), 17492 mouseleave: $.proxy(this.onEntryMouseLeaveForCaption, this) 17493 }; 17494 $entry.on('mouseenter', undefined, undefined, captionMouseEvents.mouseenter); 17495 $entry.on('mouseleave', undefined, undefined, captionMouseEvents.mouseleave); 17496 $entry.data('jg.captionMouseEvents', captionMouseEvents); 17497 } 17498 }; 17499 17500 /** 17501 * Remove the handlers of the entry for the caption 17502 * 17503 * @param $entry the entry to modify 17504 */ 17505 JustifiedGallery.prototype.removeCaptionEventsHandlers = function ($entry) { 17506 var captionMouseEvents = $entry.data('jg.captionMouseEvents'); 17507 if (typeof captionMouseEvents !== 'undefined') { 17508 $entry.off('mouseenter', undefined, captionMouseEvents.mouseenter); 17509 $entry.off('mouseleave', undefined, captionMouseEvents.mouseleave); 17510 $entry.removeData('jg.captionMouseEvents'); 17511 } 17512 }; 17513 17514 /** 17515 * Justify the building row, preparing it to 17516 * 17517 * @param isLastRow 17518 * @returns a boolean to know if the row has been justified or not 17519 */ 17520 JustifiedGallery.prototype.prepareBuildingRow = function (isLastRow) { 17521 var i, $entry, imgAspectRatio, newImgW, newImgH, justify = true; 17522 var minHeight = 0; 17523 var availableWidth = this.galleryWidth - 2 * this.border - ( 17524 (this.buildingRow.entriesBuff.length - 1) * this.settings.margins); 17525 var rowHeight = Math.floor( availableWidth / this.buildingRow.aspectRatio );//hacked by Uncode 17526 var defaultRowHeight = this.settings.rowHeight; 17527 var justifiable = this.buildingRow.width / availableWidth > this.settings.justifyThreshold; 17528 17529 //Skip the last row if we can't justify it and the lastRow == 'hide' 17530 if (isLastRow && this.settings.lastRow === 'hide' && !justifiable) { 17531 for (i = 0; i < this.buildingRow.entriesBuff.length; i++) { 17532 $entry = this.buildingRow.entriesBuff[i]; 17533 if (this.settings.cssAnimation) 17534 $entry.removeClass('entry-visible'); 17535 else { 17536 $entry.stop().fadeTo(0, 0.1); 17537 $entry.find('> img, > a > img').fadeTo(0, 0); 17538 } 17539 } 17540 return -1; 17541 } 17542 17543 // With lastRow = nojustify, justify if is justificable (the images will not become too big) 17544 if (isLastRow && !justifiable && this.settings.lastRow !== 'justify' && this.settings.lastRow !== 'hide') { 17545 justify = false;
17546 17547 if (this.rows > 0) { 17548 defaultRowHeight = (this.offY - this.border - this.settings.margins * this.rows) / this.rows; 17549 justify = defaultRowHeight * this.buildingRow.aspectRatio / availableWidth > this.settings.justifyThreshold; 17550 } 17551 } 17552 17553 for (i = 0; i < this.buildingRow.entriesBuff.length; i++) { 17554 $entry = this.buildingRow.entriesBuff[i]; 17555 imgAspectRatio = $entry.data('jg.width') / $entry.data('jg.height'); 17556 17557 if (justify) { 17558 newImgW = (i === this.buildingRow.entriesBuff.length - 1) ? availableWidth : rowHeight * imgAspectRatio; 17559 newImgH = rowHeight; 17560 } else { 17561 newImgW = defaultRowHeight * imgAspectRatio; 17562 newImgH = defaultRowHeight; 17563 } 17564 17565 availableWidth -= Math.round(newImgW); 17566 $entry.data('jg.jwidth', Math.round(newImgW)); 17567 $entry.data('jg.jheight', Math.ceil(newImgH)); 17568 if (i === 0 || minHeight > newImgH) minHeight = newImgH; 17569 } 17570 17571 this.buildingRow.height = minHeight; 17572 return justify; 17573 }; 17574 17575 /** 17576 * Clear the building row data to be used for a new row 17577 */ 17578 JustifiedGallery.prototype.clearBuildingRow = function () { 17579 this.buildingRow.entriesBuff = []; 17580 this.buildingRow.aspectRatio = 0; 17581 this.buildingRow.width = 0; 17582 }; 17583 17584 /** 17585 * Flush a row: justify it, modify the gallery height accordingly to the row height 17586 * 17587 * @param isLastRow 17588 */ 17589 JustifiedGallery.prototype.flushRow = function (isLastRow) { 17590 var settings = this.settings; 17591 var $entry, buildingRowRes, offX = this.border, i; 17592 17593 buildingRowRes = this.prepareBuildingRow(isLastRow); 17594 if (isLastRow && settings.lastRow === 'hide' && buildingRowRes === -1) { 17595 this.clearBuildingRow(); 17596 return; 17597 } 17598 17599 if (this.maxRowHeight) { 17600 if (this.maxRowHeight.isPercentage && this.maxRowHeight.value * settings.rowHeight < this.buildingRow.height) { 17601 this.buildingRow.height = this.maxRowHeight.value * settings.rowHeight; 17602 } else if (this.maxRowHeight.value >= settings.rowHeight && this.maxRowHeight.value < this.buildingRow.height) { 17603 this.buildingRow.height = this.maxRowHeight.value; 17604 } 17605 } 17606 17607 //Align last (unjustified) row 17608 if (settings.lastRow === 'center' || settings.lastRow === 'right') { 17609 var availableWidth = this.galleryWidth - 2 * this.border - (this.buildingRow.entriesBuff.length - 1) * settings.margins; 17610 17611 for (i = 0; i < this.buildingRow.entriesBuff.length; i++) { 17612 $entry = this.buildingRow.entriesBuff[i]; 17613 availableWidth -= $entry.data('jg.jwidth'); 17614 } 17615 17616 if (settings.lastRow === 'center') 17617 offX += availableWidth / 2; 17618 else if (settings.lastRow === 'right') 17619 offX += availableWidth; 17620 } 17621 17622 for (i = 0; i < this.buildingRow.entriesBuff.length; i++) { 17623 $entry = this.buildingRow.entriesBuff[i]; 17624 this.displayEntry($entry, offX, this.offY, $entry.data('jg.jwidth'), $entry.data('jg.jheight'), this.buildingRow.height); 17625 offX += $entry.data('jg.jwidth') + settings.margins; 17626 } 17627 17628 //Gallery Height 17629 this.galleryHeightToSet = this.offY + this.buildingRow.height + this.border; 17630 this.$gallery.height(this.galleryHeightToSet + this.getSpinnerHeight()); 17631 17632 if (!isLastRow || (this.buildingRow.height <= settings.rowHeight && buildingRowRes)) { 17633 //Ready for a new row 17634 this.offY += this.buildingRow.height + settings.margins; 17635 this.rows += 1; 17636 this.clearBuildingRow(); 17637 this.$gallery.trigger('jg.rowflush'); 17638 } 17639 }; 17640 17641 /** 17642 * Checks the width of the gallery container, to know if a new justification is needed 17643 */ 17644 var scrollBarOn = false; 17645 JustifiedGallery.prototype.checkWidth = function () { 17646 this.checkWidthIntervalId = setInterval($.proxy(function () { 17647 var galleryWidth = parseFloat(this.$gallery.width()); 17648 if (hasScrollBar() === scrollBarOn) { 17649 if (Math.abs(galleryWidth - this.galleryWidth) > this.settings.refreshSensitivity) { 17650 this.galleryWidth = galleryWidth; 17651 this.rewind(); 17652 17653 // Restart to analyze 17654 this.startImgAnalyzer(true); 17655 } 17656 } else { 17657 scrollBarOn = hasScrollBar(); 17658 this.galleryWidth = galleryWidth; 17659 } 17660 }, this), this.settings.refreshTime); 17661 }; 17662 17663 /** 17664 * @returns {boolean} a boolean saying if the spinner is active or not 17665 */ 17666 JustifiedGallery.prototype.isSpinnerActive = function () { 17667 return this.spinner.intervalId !== null; 17668 }; 17669 17670 /** 17671 * @returns {int} the spinner height 17672 */ 17673 JustifiedGallery.prototype.getSpinnerHeight = function () {
17674 return this.spinner.$el.innerHeight(); 17675 }; 17676 17677 /** 17678 * Stops the spinner animation and modify the gallery height to exclude the spinner 17679 */ 17680 JustifiedGallery.prototype.stopLoadingSpinnerAnimation = function () { 17681 clearInterval(this.spinner.intervalId); 17682 this.spinner.intervalId = null; 17683 this.$gallery.height(this.$gallery.height() - this.getSpinnerHeight()); 17684 this.spinner.$el.detach(); 17685 }; 17686 17687 /** 17688 * Starts the spinner animation 17689 */ 17690 JustifiedGallery.prototype.startLoadingSpinnerAnimation = function () { 17691 var spinnerContext = this.spinner; 17692 var $spinnerPoints = spinnerContext.$el.find('span'); 17693 clearInterval(spinnerContext.intervalId); 17694 this.$gallery.append(spinnerContext.$el); 17695 this.$gallery.height(this.offY + this.buildingRow.height + this.getSpinnerHeight()); 17696 spinnerContext.intervalId = setInterval(function () { 17697 if (spinnerContext.phase < $spinnerPoints.length) { 17698 $spinnerPoints.eq(spinnerContext.phase).fadeTo(spinnerContext.timeSlot, 1); 17699 } else {
vendor: 4,333 bytes, lines 17700-17844
17700 $spinnerPoints.eq(spinnerContext.phase - $spinnerPoints.length).fadeTo(spinnerContext.timeSlot, 0); 17701 } 17702 spinnerContext.phase = (spinnerContext.phase + 1) % ($spinnerPoints.length * 2); 17703 }, spinnerContext.timeSlot); 17704 }; 17705 17706 /** 17707 * Rewind the image analysis to start from the first entry. 17708 */ 17709 JustifiedGallery.prototype.rewind = function () { 17710 this.lastFetchedEntry = null; 17711 this.lastAnalyzedIndex = -1; 17712 this.offY = this.border; 17713 this.rows = 0; 17714 this.clearBuildingRow(); 17715 }; 17716 17717 /** 17718 * Update the entries searching it from the justified gallery HTML element 17719 * 17720 * @param norewind if norewind only the new entries will be changed (i.e. randomized, sorted or filtered) 17721 * @returns {boolean} true if some entries has been founded 17722 */ 17723 JustifiedGallery.prototype.updateEntries = function (norewind) { 17724 var newEntries; 17725 17726 if (norewind && this.lastFetchedEntry != null) { 17727 newEntries = $(this.lastFetchedEntry).nextAll(this.settings.selector).toArray(); 17728 } else { 17729 this.entries = []; 17730 newEntries = this.$gallery.children(this.settings.selector).toArray(); 17731 } 17732 17733 if (newEntries.length > 0) { 17734 17735 // Sort or randomize 17736 if ($.isFunction(this.settings.sort)) { 17737 newEntries = this.sortArray(newEntries); 17738 } else if (this.settings.randomize) { 17739 newEntries = this.shuffleArray(newEntries); 17740 } 17741 this.lastFetchedEntry = newEntries[newEntries.length - 1]; 17742 17743 // Filter 17744 if (this.settings.filter) { 17745 newEntries = this.filterArray(newEntries); 17746 } else { 17747 this.resetFilters(newEntries); 17748 } 17749 17750 } 17751 17752 this.entries = this.entries.concat(newEntries); 17753 return true; 17754 }; 17755 17756 /** 17757 * Apply the entries order to the DOM, iterating the entries and appending the images 17758 * 17759 * @param entries the entries that has been modified and that must be re-ordered in the DOM 17760 */ 17761 JustifiedGallery.prototype.insertToGallery = function (entries) { 17762 var that = this; 17763 $.each(entries, function () { 17764 $(this).appendTo(that.$gallery); 17765 }); 17766 }; 17767 17768 /** 17769 * Shuffle the array using the Fisher-Yates shuffle algorithm 17770 * 17771 * @param a the array to shuffle 17772 * @return the shuffled array 17773 */ 17774 JustifiedGallery.prototype.shuffleArray = function (a) { 17775 var i, j, temp; 17776 for (i = a.length - 1; i > 0; i--) { 17777 j = Math.floor(Math.random() * (i + 1)); 17778 temp = a[i]; 17779 a[i] = a[j]; 17780 a[j] = temp; 17781 } 17782 this.insertToGallery(a); 17783 return a; 17784 }; 17785 17786 /** 17787 * Sort the array using settings.comparator as comparator 17788 * 17789 * @param a the array to sort (it is sorted) 17790 * @return the sorted array 17791 */ 17792 JustifiedGallery.prototype.sortArray = function (a) { 17793 a.sort(this.settings.sort); 17794 this.insertToGallery(a); 17795 return a; 17796 }; 17797 17798 /** 17799 * Reset the filters removing the 'jg-filtered' class from all the entries 17800 * 17801 * @param a the array to reset 17802 */ 17803 JustifiedGallery.prototype.resetFilters = function (a) { 17804 for (var i = 0; i < a.length; i++) $(a[i]).removeClass('jg-filtered'); 17805 }; 17806 17807 /** 17808 * Filter the entries considering theirs classes (if a string has been passed) or using a function for filtering. 17809 * 17810 * @param a the array to filter 17811 * @return the filtered array 17812 */ 17813 JustifiedGallery.prototype.filterArray = function (a) { 17814 var settings = this.settings; 17815 if ($.type(settings.filter) === 'string') { 17816 // Filter only keeping the entries passed in the string 17817 return a.filter(function (el) { 17818 var $el = $(el); 17819 if ($el.is(settings.filter)) { 17820 $el.removeClass('jg-filtered'); 17821 return true; 17822 } else { 17823 $el.addClass('jg-filtered').removeClass('jg-visible'); 17824 return false; 17825 } 17826 }); 17827 } else if ($.isFunction(settings.filter)) { 17828 // Filter using the passed function 17829 var filteredArr = a.filter(settings.filter); 17830 for (var i = 0; i < a.length; i++) { 17831 if (filteredArr.indexOf(a[i]) == -1) { 17832 $(a[i]).addClass('jg-filtered').removeClass('jg-visible'); 17833 } else { 17834 $(a[i]).removeClass('jg-filtered'); 17835 } 17836 } 17837 return filteredArr; 17838 } 17839 }; 17840 17841 /** 17842 * Destroy the Justified Gallery instance. 17843 * 17844 * It clears all the css properties added in the style attributes. We doesn't backup the original
17845 * values for those css attributes, because it costs (performance) and because in general one 17846 * shouldn't use the style attribute for an uniform set of images (where we suppose the use of 17847 * classes). Creating a backup is also difficult because JG could be called multiple times and 17848 * with different style attributes. 17849 */ 17850 JustifiedGallery.prototype.destroy = function () { 17851 clearInterval(this.checkWidthIntervalId); 17852 17853 $.each(this.entries, $.proxy(function(_, entry) { 17854 var $entry = $(entry); 17855 17856 // Reset entry style 17857 $entry.css('width', ''); 17858 $entry.css('height', ''); 17859 $entry.css('top', ''); 17860 $entry.css('left', ''); 17861 $entry.data('jg.loaded', undefined); 17862 $entry.removeClass('jg-entry'); 17863 17864 // Reset image style 17865 var $img = this.imgFromEntry($entry); 17866 $img.css('width', ''); 17867 $img.css('height', ''); 17868 $img.css('margin-left', ''); 17869 $img.css('margin-top', ''); 17870 $img.attr('src', $img.data('jg.originalSrc')); 17871 $img.data('jg.originalSrc', undefined); 17872 17873 // Remove caption 17874 this.removeCaptionEventsHandlers($entry); 17875 var $caption = this.captionFromEntry($entry); 17876 if ($entry.data('jg.createdCaption')) { 17877 // remove also the caption element (if created by jg) 17878 $entry.data('jg.createdCaption', undefined); 17879 if ($caption !== null) $caption.remove(); 17880 } else { 17881 if ($caption !== null) $caption.fadeTo(0, 1); 17882 } 17883 17884 }, this)); 17885 17886 this.$gallery.css('height', ''); 17887 this.$gallery.removeClass('justified-gallery'); 17888 this.$gallery.data('jg.controller', undefined); 17889 }; 17890 17891 /** 17892 * Analyze the images and builds the rows. It returns if it found an image that is not loaded. 17893 * 17894 * @param isForResize if the image analyzer is called for resizing or not, to call a different callback at the end 17895 */ 17896 JustifiedGallery.prototype.analyzeImages = function (isForResize) { 17897 for (var i = this.lastAnalyzedIndex + 1; i < this.entries.length; i++) { 17898 var $entry = $(this.entries[i]); 17899 if ($entry.data('jg.loaded') === true || $entry.data('jg.loaded') === 'skipped') { 17900 var availableWidth = this.galleryWidth - 2 * this.border - ( 17901 (this.buildingRow.entriesBuff.length - 1) * this.settings.margins); 17902 var imgAspectRatio = $entry.data('jg.width') / $entry.data('jg.height'); 17903 if (availableWidth / (this.buildingRow.aspectRatio + imgAspectRatio) < this.settings.rowHeight) { 17904 this.flushRow(false); 17905 if(++this.yield.flushed >= this.yield.every) { 17906 this.startImgAnalyzer(isForResize); 17907 return; 17908 } 17909 } 17910 17911 this.buildingRow.entriesBuff.push($entry); 17912 this.buildingRow.aspectRatio += imgAspectRatio; 17913 this.buildingRow.width += imgAspectRatio * this.settings.rowHeight; 17914 this.lastAnalyzedIndex = i; 17915 17916 } else if ($entry.data('jg.loaded') !== 'error') { 17917 return; 17918 } 17919 } 17920 17921 // Last row flush (the row is not full) 17922 if (this.buildingRow.entriesBuff.length > 0) this.flushRow(true); 17923 17924 if (this.isSpinnerActive()) { 17925 this.stopLoadingSpinnerAnimation(); 17926 } 17927 17928 /* Stop, if there is, the timeout to start the analyzeImages. 17929 This is because an image can be set loaded, and the timeout can be set, 17930 but this image can be analyzed yet. 17931 */ 17932 this.stopImgAnalyzerStarter(); 17933 17934 //On complete callback 17935 this.$gallery.trigger(isForResize ? 'jg.resize' : 'jg.complete'); 17936 this.$gallery.height(this.galleryHeightToSet); 17937 }; 17938 17939 /** 17940 * Stops any ImgAnalyzer starter (that has an assigned timeout) 17941 */ 17942 JustifiedGallery.prototype.stopImgAnalyzerStarter = function () { 17943 this.yield.flushed = 0; 17944 if (this.imgAnalyzerTimeout !== null) clearTimeout(this.imgAnalyzerTimeout); 17945 }; 17946 17947 /** 17948 * Starts the image analyzer. It is not immediately called to let the browser to update the view 17949 * 17950 * @param isForResize specifies if the image analyzer must be called for resizing or not 17951 */ 17952 JustifiedGallery.prototype.startImgAnalyzer = function (isForResize) { 17953 var that = this; 17954 this.stopImgAnalyzerStarter(); 17955 this.imgAnalyzerTimeout = setTimeout(function () { 17956 that.analyzeImages(isForResize); 17957 }, 0.001); // we can't start it immediately due to a IE different behaviour 17958 }; 17959 17960 /** 17961 * Checks if the image is loaded or not using another image object. We cannot use the 'complete' image property, 17962 * because some browsers, with a 404 set complete = true. 17963 * 17964 * @param imageSrc the image src to load 17965 * @param onLoad callback that is called when the image has been loaded
vendor: 13,320 bytes, lines 17966-18316
17966 * @param onError callback that is called in case of an error 17967 */ 17968 JustifiedGallery.prototype.onImageEvent = function (imageSrc, onLoad, onError) { 17969 if (!onLoad && !onError) return; 17970 17971 var memImage = new Image(); 17972 var $memImage = $(memImage); 17973 if (onLoad) { 17974 $memImage.one('load', function () { 17975 $memImage.off('load error'); 17976 onLoad(memImage); 17977 }); 17978 } 17979 if (onError) { 17980 $memImage.one('error', function() { 17981 $memImage.off('load error'); 17982 onError(memImage); 17983 }); 17984 } 17985 memImage.src = imageSrc; 17986 }; 17987 17988 /** 17989 * Init of Justified Gallery controlled 17990 * It analyzes all the entries starting theirs loading and calling the image analyzer (that works with loaded images) 17991 */ 17992 JustifiedGallery.prototype.init = function () { 17993 var imagesToLoad = false, skippedImages = false, that = this; 17994 $.each(this.entries, function (index, entry) { 17995 var $entry = $(entry); 17996 var $image = that.imgFromEntry($entry); 17997 17998 $entry.addClass('jg-entry'); 17999 18000 if ($entry.data('jg.loaded') !== true && $entry.data('jg.loaded') !== 'skipped') { 18001 18002 // Link Rel global overwrite 18003 if (that.settings.rel !== null) $entry.attr('rel', that.settings.rel); 18004 18005 // Link Target global overwrite 18006 if (that.settings.target !== null) $entry.attr('target', that.settings.target); 18007 18008 if ($image !== null) { 18009 18010 // Image src 18011 var imageSrc = that.extractImgSrcFromImage($image); 18012 $image.attr('src', imageSrc); 18013 18014 /* If we have the height and the width, we don't wait that the image is loaded, but we start directly 18015 * with the justification */ 18016 if (that.settings.waitThumbnailsLoad === false) { 18017 var width = parseFloat($image.attr('width')); 18018 var height = parseFloat($image.attr('height')); 18019 if (!isNaN(width) && !isNaN(height)) { 18020 $entry.data('jg.width', width); 18021 $entry.data('jg.height', height); 18022 $entry.data('jg.loaded', 'skipped'); 18023 skippedImages = true; 18024 that.startImgAnalyzer(false); 18025 return true; // continue 18026 } 18027 } 18028 18029 $entry.data('jg.loaded', false); 18030 imagesToLoad = true; 18031 18032 // Spinner start 18033 if (!that.isSpinnerActive()) that.startLoadingSpinnerAnimation(); 18034 18035 that.onImageEvent(imageSrc, function (loadImg) { // image loaded 18036 $entry.data('jg.width', loadImg.width); 18037 $entry.data('jg.height', loadImg.height); 18038 $entry.data('jg.loaded', true); 18039 that.startImgAnalyzer(false); 18040 }, function () { // image load error 18041 $entry.data('jg.loaded', 'error'); 18042 that.startImgAnalyzer(false); 18043 }); 18044 18045 } else { 18046 $entry.data('jg.loaded', true); 18047 $entry.data('jg.width', $entry.width() | parseFloat($entry.css('width')) | 1); 18048 $entry.data('jg.height', $entry.height() | parseFloat($entry.css('height')) | 1); 18049 } 18050 18051 } 18052 18053 }); 18054 18055 if (!imagesToLoad && !skippedImages) this.startImgAnalyzer(false); 18056 this.checkWidth(); 18057 }; 18058 18059 /** 18060 * Checks that it is a valid number. If a string is passed it is converted to a number 18061 * 18062 * @param settingContainer the object that contains the setting (to allow the conversion) 18063 * @param settingName the setting name 18064 */ 18065 JustifiedGallery.prototype.checkOrConvertNumber = function (settingContainer, settingName) { 18066 if ($.type(settingContainer[settingName]) === 'string') { 18067 settingContainer[settingName] = parseFloat(settingContainer[settingName]); 18068 } 18069 18070 if ($.type(settingContainer[settingName]) === 'number') { 18071 if (isNaN(settingContainer[settingName])) throw 'invalid number for ' + settingName; 18072 } else { 18073 throw settingName + ' must be a number'; 18074 } 18075 }; 18076 18077 /** 18078 * Checks the sizeRangeSuffixes and, if necessary, converts 18079 * its keys from string (e.g. old settings with 'lt100') to int. 18080 */ 18081 JustifiedGallery.prototype.checkSizeRangesSuffixes = function () { 18082 if ($.type(this.settings.sizeRangeSuffixes) !== 'object') { 18083 throw 'sizeRangeSuffixes must be defined and must be an object'; 18084 } 18085 18086 var suffixRanges = []; 18087 for (var rangeIdx in this.settings.sizeRangeSuffixes) { 18088 if (this.settings.sizeRangeSuffixes.hasOwnProperty(rangeIdx)) suffixRanges.push(rangeIdx); 18089 } 18090 18091 var newSizeRngSuffixes = {0: ''}; 18092 for (var i = 0; i < suffixRanges.length; i++) { 18093 if ($.type(suffixRanges[i]) === 'string') { 18094 try { 18095 var numIdx = parseInt(suffixRanges[i].replace(/^[a-z]+/, ''), 10); 18096 newSizeRngSuffixes[numIdx] = this.settings.sizeRangeSuffixes[suffixRanges[i]]; 18097 } catch (e) { 18098 throw 'sizeRangeSuffixes keys must contains correct numbers (' + e + ')'; 18099 } 18100 } else { 18101 newSizeRngSuffixes[suffixRanges[i]] = this.settings.sizeRangeSuffixes[suffixRanges[i]]; 18102 } 18103 } 18104 18105 this.settings.sizeRangeSuffixes = newSizeRngSuffixes; 18106 }; 18107 18108 /** 18109 * check and convert the maxRowHeight setting 18110 */ 18111 JustifiedGallery.prototype.retrieveMaxRowHeight = function () { 18112 var newMaxRowHeight = { }; 18113 18114 if ($.type(this.settings.maxRowHeight) === 'string') { 18115 if (this.settings.maxRowHeight.match(/^[0-9]+%$/)) { 18116 newMaxRowHeight.value = parseFloat(this.settings.maxRowHeight.match(/^([0-9]+)%$/)[1]) / 100; 18117 newMaxRowHeight.isPercentage = false; 18118 } else { 18119 newMaxRowHeight.value = parseFloat(this.settings.maxRowHeight); 18120 newMaxRowHeight.isPercentage = true; 18121 } 18122 } else if ($.type(this.settings.maxRowHeight) === 'number') { 18123 newMaxRowHeight.value = this.settings.maxRowHeight; 18124 newMaxRowHeight.isPercentage = false; 18125 } else if (this.settings.maxRowHeight === false || 18126 this.settings.maxRowHeight === null || 18127 typeof this.settings.maxRowHeight == 'undefined') { 18128 return null; 18129 } else { 18130 throw 'maxRowHeight must be a number or a percentage'; 18131 } 18132 18133 // check if the converted value is not a number 18134 if (isNaN(newMaxRowHeight.value)) throw 'invalid number for maxRowHeight'; 18135 18136 // check values 18137 if (newMaxRowHeight.isPercentage) { 18138 if (newMaxRowHeight.value < 100) newMaxRowHeight.value = 100; 18139 } 18140 18141 return newMaxRowHeight; 18142 }; 18143 18144 /** 18145 * Checks the settings 18146 */ 18147 JustifiedGallery.prototype.checkSettings = function () { 18148 this.checkSizeRangesSuffixes(); 18149 18150 this.checkOrConvertNumber(this.settings, 'rowHeight'); 18151 this.checkOrConvertNumber(this.settings, 'margins'); 18152 this.checkOrConvertNumber(this.settings, 'border'); 18153 18154 var lastRowModes = [ 18155 'justify', 18156 'nojustify', 18157 'left', 18158 'center', 18159 'right', 18160 'hide' 18161 ]; 18162 if (lastRowModes.indexOf(this.settings.lastRow) === -1) { 18163 throw 'lastRow must be one of: ' + lastRowModes.join(', '); 18164 } 18165 18166 this.checkOrConvertNumber(this.settings, 'justifyThreshold'); 18167 if (this.settings.justifyThreshold < 0 || this.settings.justifyThreshold > 1) { 18168 throw 'justifyThreshold must be in the interval [0,1]'; 18169 } 18170 if ($.type(this.settings.cssAnimation) !== 'boolean') { 18171 throw 'cssAnimation must be a boolean'; 18172 } 18173 18174 if ($.type(this.settings.captions) !== 'boolean') throw 'captions must be a boolean'; 18175 this.checkOrConvertNumber(this.settings.captionSettings, 'animationDuration'); 18176 18177 this.checkOrConvertNumber(this.settings.captionSettings, 'visibleOpacity'); 18178 if (this.settings.captionSettings.visibleOpacity < 0 || 18179 this.settings.captionSettings.visibleOpacity > 1) { 18180 throw 'captionSettings.visibleOpacity must be in the interval [0, 1]'; 18181 } 18182 18183 this.checkOrConvertNumber(this.settings.captionSettings, 'nonVisibleOpacity'); 18184 if (this.settings.captionSettings.nonVisibleOpacity < 0 || 18185 this.settings.captionSettings.nonVisibleOpacity > 1) { 18186 throw 'captionSettings.nonVisibleOpacity must be in the interval [0, 1]'; 18187 } 18188 18189 this.checkOrConvertNumber(this.settings, 'imagesAnimationDuration'); 18190 this.checkOrConvertNumber(this.settings, 'refreshTime'); 18191 this.checkOrConvertNumber(this.settings, 'refreshSensitivity'); 18192 if ($.type(this.settings.randomize) !== 'boolean') throw 'randomize must be a boolean'; 18193 if ($.type(this.settings.selector) !== 'string') throw 'selector must be a string'; 18194 18195 if (this.settings.sort !== false && !$.isFunction(this.settings.sort)) { 18196 throw 'sort must be false or a comparison function'; 18197 } 18198 18199 if (this.settings.filter !== false && !$.isFunction(this.settings.filter) && 18200 $.type(this.settings.filter) !== 'string') { 18201 throw 'filter must be false, a string or a filter function'; 18202 } 18203 }; 18204 18205 /** 18206 * It brings all the indexes from the sizeRangeSuffixes and it orders them. They are then sorted and returned. 18207 * @returns {Array} sorted suffix ranges 18208 */ 18209 JustifiedGallery.prototype.retrieveSuffixRanges = function () { 18210 var suffixRanges = []; 18211 for (var rangeIdx in this.settings.sizeRangeSuffixes) { 18212 if (this.settings.sizeRangeSuffixes.hasOwnProperty(rangeIdx)) suffixRanges.push(parseInt(rangeIdx, 10)); 18213 } 18214 suffixRanges.sort(function (a, b) { return a > b ? 1 : a < b ? -1 : 0; }); 18215 return suffixRanges; 18216 }; 18217 18218 /** 18219 * Update the existing settings only changing some of them 18220 * 18221 * @param newSettings the new settings (or a subgroup of them) 18222 */ 18223 JustifiedGallery.prototype.updateSettings = function (newSettings) { 18224 // In this case Justified Gallery has been called again changing only some options 18225 this.settings = $.extend({}, this.settings, newSettings); 18226 this.checkSettings(); 18227 18228 // As reported in the settings: negative value = same as margins, 0 = disabled 18229 this.border = this.settings.border >= 0 ? this.settings.border : this.settings.margins; 18230 18231 this.maxRowHeight = this.retrieveMaxRowHeight(); 18232 this.suffixRanges = this.retrieveSuffixRanges(); 18233 }; 18234 18235 /** 18236 * Justified Gallery plugin for jQuery 18237 * 18238 * Events 18239 * - jg.complete : called when all the gallery has been created 18240 * - jg.resize : called when the gallery has been resized 18241 * - jg.rowflush : when a new row appears 18242 * 18243 * @param arg the action (or the settings) passed when the plugin is called 18244 * @returns {*} the object itself 18245 */ 18246 $.fn.justifiedGallery = function (arg) { 18247 return this.each(function (index, gallery) { 18248 18249 var $gallery = $(gallery); 18250 $gallery.addClass('justified-gallery'); 18251 18252 var controller = $gallery.data('jg.controller'); 18253 if (typeof controller === 'undefined') { 18254 // Create controller and assign it to the object data 18255 if (typeof arg !== 'undefined' && arg !== null && $.type(arg) !== 'object') { 18256 if (arg === 'destroy') return; // Just a call to an unexisting object 18257 throw 'The argument must be an object'; 18258 } 18259 controller = new JustifiedGallery($gallery, $.extend({}, $.fn.justifiedGallery.defaults, arg)); 18260 $gallery.data('jg.controller', controller); 18261 } else if (arg === 'norewind') { 18262 // In this case we don't rewind: we analyze only the latest images (e.g. to complete the last unfinished row 18263 // ... left to be more readable 18264 } else if (arg === 'destroy') { 18265 controller.destroy(); 18266 return; 18267 } else { 18268 // In this case Justified Gallery has been called again changing only some options 18269 controller.updateSettings(arg); 18270 controller.rewind(); 18271 } 18272 18273 // Update the entries list 18274 if (!controller.updateEntries(arg === 'norewind')) return; 18275 18276 // Init justified gallery 18277 controller.init(); 18278 18279 }); 18280 }; 18281 18282 // Default options 18283 $.fn.justifiedGallery.defaults = { 18284 sizeRangeSuffixes: { }, /* e.g. Flickr configuration 18285 { 18286 100: '_t', // used when longest is less than 100px 18287 240: '_m', // used when longest is between 101px and 240px 18288 320: '_n', // ... 18289 500: '', 18290 640: '_z', 18291 1024: '_b' // used as else case because it is the last 18292 } 18293 */ 18294 thumbnailPath: undefined, /* If defined, sizeRangeSuffixes is not used, and this function is used to determine the 18295 path relative to a specific thumbnail size. The function should accept respectively three arguments: 18296 current path, width and height */ 18297 rowHeight: 120, 18298 maxRowHeight: false, // false or negative value to deactivate. Positive number to express the value in pixels, 18299 // A string '[0-9]+%' to express in percentage (e.g. 300% means that the row height 18300 // can't exceed 3 * rowHeight) 18301 margins: 1, 18302 border: -1, // negative value = same as margins, 0 = disabled, any other value to set the border 18303 18304 lastRow: 'nojustify', // … which is the same as 'left', or can be 'justify', 'center', 'right' or 'hide' 18305 18306 justifyThreshold: 0.90, /* if row width / available space > 0.90 it will be always justified 18307 * (i.e. lastRow setting is not considered) */ 18308 waitThumbnailsLoad: true, 18309 captions: true, 18310 cssAnimation: true, 18311 imagesAnimationDuration: 500, // ignored with css animations 18312 captionSettings: { // ignored with css animations 18313 animationDuration: 500, 18314 visibleOpacity: 0.7, 18315 nonVisibleOpacity: 0.0 18316 },
18317 rel: null, // rewrite the rel of each analyzed links 18318 target: null, // rewrite the target of all links 18319 extension: /\.[^.\\/]+$/, // regexp to capture the extension of an image 18320 refreshTime: 200, // time interval (in ms) to check if the page changes its width 18321 refreshSensitivity: 0, // change in width allowed (in px) without re-building the gallery 18322 randomize: false, 18323 sort: false, /* 18324 - false: to do not sort 18325 - function: to sort them using the function as comparator (see Array.prototype.sort()) 18326 */ 18327 filter: false, /* 18328 - false, null or undefined: for a disabled filter 18329 - a string: an entry is kept if entry.is(filter string) returns true 18330 see jQuery's .is() function for further information 18331 - a function: invoked with arguments (entry, index, array). Return true to keep the entry, false otherwise. 18332 It follows the specifications of the Array.prototype.filter() function of JavaScript. 18333 */ 18334 selector: 'a, div:not(.spinner)' // The selector that is used to know what are the entries of the gallery 18335 }; 18336 18337}(jQuery)); 18338/*! 18339* Customized version of iScroll.js 0.0.1 18340* It fixes bugs affecting its integration with fullpage.js 18341*/ 18342/*! iScroll v5.2.0 ~ (c) 2008-2016 Matteo Spinelli ~ http://cubiq.org/license */ 18343(function (window, document, Math) { 18344var rAF = window.requestAnimationFrame || 18345 window.webkitRequestAnimationFrame || 18346 window.mozRequestAnimationFrame || 18347 window.oRequestAnimationFrame || 18348 window.msRequestAnimationFrame || 18349 function (callback) { window.setTimeout(callback, 1000 / 60); }; 18350 18351var utils = (function () { 18352 var me = {}; 18353 18354 var _elementStyle = document.createElement('div').style; 18355 var _vendor = (function () { 18356 var vendors = ['t', 'webkitT', 'MozT', 'msT', 'OT'], 18357 transform, 18358 i = 0, 18359 l = vendors.length; 18360 18361 for ( ; i < l; i++ ) { 18362 transform = vendors[i] + 'ransform'; 18363 if ( transform in _elementStyle ) return vendors[i].substr(0, vendors[i].length-1); 18364 } 18365 18366 return false; 18367 })(); 18368 18369 function _prefixStyle (style) { 18370 if ( _vendor === false ) return false; 18371 if ( _vendor === '' ) return style; 18372 return _vendor + style.charAt(0).toUpperCase() + style.substr(1); 18373 } 18374 18375 me.getTime = Date.now || function getTime () { return new Date().getTime(); }; 18376 18377 me.extend = function (target, obj) { 18378 for ( var i in obj ) { 18379 target[i] = obj[i]; 18380 } 18381 }; 18382 18383 me.addEvent = function (el, type, fn, capture) { 18384 el.addEventListener(type, fn, !!capture); 18385 }; 18386 18387 me.removeEvent = function (el, type, fn, capture) { 18388 el.removeEventListener(type, fn, !!capture); 18389 }; 18390 18391 me.prefixPointerEvent = function (pointerEvent) { 18392 return window.MSPointerEvent ? 18393 'MSPointer' + pointerEvent.charAt(7).toUpperCase() + pointerEvent.substr(8): 18394 pointerEvent; 18395 }; 18396 18397 me.momentum = function (current, start, time, lowerMargin, wrapperSize, deceleration) { 18398 var distance = current - start, 18399 speed = Math.abs(distance) / time, 18400 destination, 18401 duration; 18402 18403 deceleration = deceleration === undefined ? 0.0006 : deceleration; 18404 18405 destination = current + ( speed * speed ) / ( 2 * deceleration ) * ( distance < 0 ? -1 : 1 ); 18406 duration = speed / deceleration; 18407 18408 if ( destination < lowerMargin ) { 18409 destination = wrapperSize ? lowerMargin - ( wrapperSize / 2.5 * ( speed / 8 ) ) : lowerMargin; 18410 distance = Math.abs(destination - current); 18411 duration = distance / speed; 18412 } else if ( destination > 0 ) { 18413 destination = wrapperSize ? wrapperSize / 2.5 * ( speed / 8 ) : 0; 18414 distance = Math.abs(current) + destination; 18415 duration = distance / speed; 18416 } 18417 18418 return { 18419 destination: Math.round(destination), 18420 duration: duration 18421 }; 18422 }; 18423 18424 var _transform = _prefixStyle('transform'); 18425 18426 me.extend(me, { 18427 hasTransform: _transform !== false, 18428 hasPerspective: _prefixStyle('perspective') in _elementStyle, 18429 hasTouch: 'ontouchstart' in window, 18430 hasPointer: !!(window.PointerEvent || window.MSPointerEvent), // IE10 is prefixed 18431 hasTransition: _prefixStyle('transition') in _elementStyle 18432 }); 18433 18434 /* 18435 This should find all Android browsers lower than build 535.19 (both stock browser and webview) 18436 - galaxy S2 is ok 18437 - 2.3.6 : `AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1` 18438 - 4.0.4 : `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30` 18439 - galaxy S3 is badAndroid (stock brower, webview) 18440 `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30` 18441 - galaxy S4 is badAndroid (stock brower, webview) 18442 `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30` 18443 - galaxy S5 is OK 18444 `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)` 18445 - galaxy S6 is OK 18446 `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)` 18447 */ 18448 me.isBadAndroid = (function() { 18449 var appVersion = window.navigator.appVersion; 18450 // Android browser is not a chrome browser. 18451 if (/Android/.test(appVersion) && !(/Chrome\/\d/.test(appVersion))) { 18452 var safariVersion = appVersion.match(/Safari\/(\d+.\d)/); 18453 if(safariVersion && typeof safariVersion === "object" && safariVersion.length >= 2) { 18454 return parseFloat(safariVersion[1]) < 535.19; 18455 } else { 18456 return true; 18457 } 18458 } else { 18459 return false;
18460 } 18461 })(); 18462 18463 me.extend(me.style = {}, { 18464 transform: _transform, 18465 transitionTimingFunction: _prefixStyle('transitionTimingFunction'), 18466 transitionDuration: _prefixStyle('transitionDuration'), 18467 transitionDelay: _prefixStyle('transitionDelay'), 18468 transformOrigin: _prefixStyle('transformOrigin') 18469 }); 18470 18471 me.hasClass = function (e, c) { 18472 var re = new RegExp("(^|\\s)" + c + "(\\s|$)"); 18473 return re.test(e.className); 18474 }; 18475 18476 me.addClass = function (e, c) { 18477 if ( me.hasClass(e, c) ) { 18478 return; 18479 } 18480 18481 var newclass = e.className.split(' '); 18482 newclass.push(c); 18483 e.className = newclass.join(' '); 18484 }; 18485 18486 me.removeClass = function (e, c) { 18487 if ( !me.hasClass(e, c) ) { 18488 return; 18489 } 18490 18491 var re = new RegExp("(^|\\s)" + c + "(\\s|$)", 'g'); 18492 e.className = e.className.replace(re, ' '); 18493 }; 18494 18495 me.offset = function (el) { 18496 var left = -el.offsetLeft, 18497 top = -el.offsetTop; 18498 18499 // jshint -W084 18500 while (el = el.offsetParent) { 18501 left -= el.offsetLeft; 18502 top -= el.offsetTop; 18503 } 18504 // jshint +W084 18505 18506 return { 18507 left: left, 18508 top: top 18509 }; 18510 }; 18511 18512 me.preventDefaultException = function (el, exceptions) { 18513 for ( var i in exceptions ) { 18514 if ( exceptions[i].test(el[i]) ) { 18515 return true; 18516 } 18517 } 18518 18519 return false; 18520 }; 18521 18522 me.extend(me.eventType = {}, { 18523 touchstart: 1, 18524 touchmove: 1, 18525 touchend: 1, 18526 18527 mousedown: 2, 18528 mousemove: 2, 18529 mouseup: 2, 18530 18531 pointerdown: 3, 18532 pointermove: 3, 18533 pointerup: 3, 18534 18535 MSPointerDown: 3, 18536 MSPointerMove: 3, 18537 MSPointerUp: 3 18538 }); 18539 18540 me.extend(me.ease = {}, { 18541 quadratic: { 18542 style: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)', 18543 fn: function (k) { 18544 return k * ( 2 - k ); 18545 } 18546 }, 18547 circular: { 18548 style: 'cubic-bezier(0.1, 0.57, 0.1, 1)', // Not properly "circular" but this looks better, it should be (0.075, 0.82, 0.165, 1) 18549 fn: function (k) { 18550 return Math.sqrt( 1 - ( --k * k ) ); 18551 } 18552 }, 18553 back: { 18554 style: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)', 18555 fn: function (k) { 18556 var b = 4; 18557 return ( k = k - 1 ) * k * ( ( b + 1 ) * k + b ) + 1; 18558 } 18559 }, 18560 bounce: { 18561 style: '', 18562 fn: function (k) { 18563 if ( ( k /= 1 ) < ( 1 / 2.75 ) ) { 18564 return 7.5625 * k * k; 18565 } else if ( k < ( 2 / 2.75 ) ) { 18566 return 7.5625 * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75; 18567 } else if ( k < ( 2.5 / 2.75 ) ) { 18568 return 7.5625 * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375; 18569 } else { 18570 return 7.5625 * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375; 18571 } 18572 } 18573 }, 18574 elastic: { 18575 style: '', 18576 fn: function (k) { 18577 var f = 0.22, 18578 e = 0.4; 18579 18580 if ( k === 0 ) { return 0; } 18581 if ( k == 1 ) { return 1; } 18582 18583 return ( e * Math.pow( 2, - 10 * k ) * Math.sin( ( k - f / 4 ) * ( 2 * Math.PI ) / f ) + 1 ); 18584 } 18585 } 18586 }); 18587 18588 me.tap = function (e, eventName) { 18589 var ev = document.createEvent('Event'); 18590 ev.initEvent(eventName, true, true); 18591 ev.pageX = e.pageX; 18592 ev.pageY = e.pageY; 18593 e.target.dispatchEvent(ev); 18594 }; 18595 18596 me.click = function (e) { 18597 var target = e.target, 18598 ev; 18599 18600 if ( !(/(SELECT|INPUT|TEXTAREA)/i).test(target.tagName) ) { 18601 // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/initMouseEvent 18602 // initMouseEvent is deprecated. 18603 ev = document.createEvent(window.MouseEvent ? 'MouseEvents' : 'Event'); 18604 ev.initEvent('click', true, true); 18605 ev.view = e.view || window; 18606 ev.detail = 1; 18607 ev.screenX = target.screenX || 0; 18608 ev.screenY = target.screenY || 0; 18609 ev.clientX = target.clientX || 0; 18610 ev.clientY = target.clientY || 0; 18611 ev.ctrlKey = !!e.ctrlKey; 18612 ev.altKey = !!e.altKey; 18613 ev.shiftKey = !!e.shiftKey; 18614 ev.metaKey = !!e.metaKey; 18615 ev.button = 0; 18616 ev.relatedTarget = null; 18617 ev._constructed = true; 18618 target.dispatchEvent(ev); 18619 } 18620 }; 18621 18622 return me; 18623})(); 18624function IScroll (el, options) { 18625 this.wrapper = typeof el == 'string' ? document.querySelector(el) : el; 18626 this.scroller = this.wrapper.children[0]; 18627 this.scrollerStyle = this.scroller.style; // cache style for better performance 18628 18629 this.options = { 18630 18631 resizeScrollbars: true, 18632 18633 mouseWheelSpeed: 20, 18634 18635 snapThreshold: 0.334, 18636 18637// INSERT POINT: OPTIONS 18638 disablePointer : !utils.hasPointer, 18639 disableTouch : utils.hasPointer || !utils.hasTouch, 18640 disableMouse : utils.hasPointer || utils.hasTouch, 18641 startX: 0, 18642 startY: 0, 18643 scrollY: true, 18644 directionLockThreshold: 5, 18645 momentum: true, 18646 18647 bounce: true, 18648 bounceTime: 600, 18649 bounceEasing: '', 18650 18651 preventDefault: true, 18652 preventDefaultException: { tagName: /^(INPUT|TEXTAREA|BUTTON|
18652SELECT|LABEL)$/ }, 18653 18654 HWCompositing: true, 18655 useTransition: true, 18656 useTransform: true, 18657 bindToWrapper: typeof window.onmousedown === "undefined" 18658 }; 18659 18660 for ( var i in options ) { 18661 this.options[i] = options[i]; 18662 } 18663 18664 // Normalize options 18665 this.translateZ = this.options.HWCompositing && utils.hasPerspective ? ' translateZ(0)' : ''; 18666 18667 this.options.useTransition = utils.hasTransition && this.options.useTransition; 18668 this.options.useTransform = utils.hasTransform && this.options.useTransform; 18669 18670 this.options.eventPassthrough = this.options.eventPassthrough === true ? 'vertical' : this.options.eventPassthrough; 18671 this.options.preventDefault = !this.options.eventPassthrough && this.options.preventDefault; 18672 18673 // If you want eventPassthrough I have to lock one of the axes 18674 this.options.scrollY = this.options.eventPassthrough == 'vertical' ? false : this.options.scrollY; 18675 this.options.scrollX = this.options.eventPassthrough == 'horizontal' ? false : this.options.scrollX; 18676 18677 // With eventPassthrough we also need lockDirection mechanism 18678 this.options.freeScroll = this.options.freeScroll && !this.options.eventPassthrough; 18679 this.options.directionLockThreshold = this.options.eventPassthrough ? 0 : this.options.directionLockThreshold; 18680 18681 this.options.bounceEasing = typeof this.options.bounceEasing == 'string' ? utils.ease[this.options.bounceEasing] || utils.ease.circular : this.options.bounceEasing; 18682 18683 this.options.resizePolling = this.options.resizePolling === undefined ? 60 : this.options.resizePolling; 18684 18685 if ( this.options.tap === true ) { 18686 this.options.tap = 'tap'; 18687 } 18688 18689 // https://github.com/cubiq/iscroll/issues/1029 18690 if (!this.options.useTransition && !this.options.useTransform) { 18691 if(!(/relative|absolute/i).test(this.scrollerStyle.position)) { 18692 this.scrollerStyle.position = "relative"; 18693 } 18694 } 18695 18696 if ( this.options.shrinkScrollbars == 'scale' ) { 18697 this.options.useTransition = false; 18698 } 18699 18700 this.options.invertWheelDirection = this.options.invertWheelDirection ? -1 : 1; 18701 18702// INSERT POINT: NORMALIZATION 18703 18704 // Some defaults 18705 this.x = 0; 18706 this.y = 0; 18707 this.directionX = 0; 18708 this.directionY = 0; 18709 this._events = {}; 18710 18711// INSERT POINT: DEFAULTS 18712 18713 this._init(); 18714 this.refresh(); 18715 18716 this.scrollTo(this.options.startX, this.options.startY); 18717 this.enable(); 18718} 18719 18720IScroll.prototype = { 18721 version: '5.2.0', 18722 18723 _init: function () { 18724 this._initEvents(); 18725 18726 if ( this.options.scrollbars || this.options.indicators ) { 18727 this._initIndicators(); 18728 } 18729 18730 if ( this.options.mouseWheel ) { 18731 this._initWheel(); 18732 } 18733 18734 if ( this.options.snap ) { 18735 this._initSnap(); 18736 } 18737 18738 if ( this.options.keyBindings ) { 18739 this._initKeys(); 18740 } 18741 18742// INSERT POINT: _init 18743 18744 }, 18745 18746 destroy: function () { 18747 this._initEvents(true); 18748 clearTimeout(this.resizeTimeout); 18749 this.resizeTimeout = null; 18750 this._execEvent('destroy'); 18751 }, 18752 18753 _transitionEnd: function (e) { 18754 if ( e.target != this.scroller || !this.isInTransition ) { 18755 return; 18756 } 18757 18758 this._transitionTime(); 18759 if ( !this.resetPosition(this.options.bounceTime) ) { 18760 this.isInTransition = false; 18761 this._execEvent('scrollEnd'); 18762 } 18763 }, 18764 18765 _start: function (e) { 18766 // React to left mouse button only 18767 if ( utils.eventType[e.type] != 1 ) { 18768 // for button property 18769 // http://unixpapa.com/js/mouse.html 18770 var button; 18771 if (!e.which) { 18772 /* IE case */ 18773 button = (e.button < 2) ? 0 : 18774 ((e.button == 4) ? 1 : 2); 18775 } else { 18776 /* All others */ 18777 button = e.button; 18778 } 18779 if ( button !== 0 ) { 18780 return; 18781 } 18782 } 18783 18784 if ( !this.enabled || (this.initiated && utils.eventType[e.type] !== this.initiated) ) { 18785 return; 18786 } 18787 18788 if ( this.options.preventDefault && !utils.isBadAndroid && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) { 18789 e.preventDefault(); 18790 } 18791 18792 var point = e.touches ? e.touches[0] : e, 18793 pos; 18794 18795 this.initiated = utils.eventType[e.type]; 18796 this.moved = false;
18797 this.distX = 0; 18798 this.distY = 0; 18799 this.directionX = 0; 18800 this.directionY = 0; 18801 this.directionLocked = 0; 18802 18803 this.startTime = utils.getTime(); 18804 18805 if ( this.options.useTransition && this.isInTransition ) { 18806 this._transitionTime(); 18807 this.isInTransition = false; 18808 pos = this.getComputedPosition(); 18809 this._translate(Math.round(pos.x), Math.round(pos.y)); 18810 this._execEvent('scrollEnd'); 18811 } else if ( !this.options.useTransition && this.isAnimating ) { 18812 this.isAnimating = false; 18813 this._execEvent('scrollEnd'); 18814 } 18815 18816 this.startX = this.x; 18817 this.startY = this.y; 18818 this.absStartX = this.x; 18819 this.absStartY = this.y; 18820 this.pointX = point.pageX; 18821 this.pointY = point.pageY; 18822 18823 this._execEvent('beforeScrollStart'); 18824 }, 18825 18826 _move: function (e) { 18827 if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) { 18828 return; 18829 } 18830 18831 if ( this.options.preventDefault ) { // increases performance on Android? TODO: check! 18832 e.preventDefault(); 18833 } 18834 18835 var point = e.touches ? e.touches[0] : e, 18836 deltaX = point.pageX - this.pointX, 18837 deltaY = point.pageY - this.pointY, 18838 timestamp = utils.getTime(), 18839 newX, newY, 18840 absDistX, absDistY; 18841 18842 this.pointX = point.pageX; 18843 this.pointY = point.pageY; 18844 18845 this.distX += deltaX; 18846 this.distY += deltaY; 18847 absDistX = Math.abs(this.distX); 18848 absDistY = Math.abs(this.distY); 18849 18850 // We need to move at least 10 pixels for the scrolling to initiate 18851 if ( timestamp - this.endTime > 300 && (absDistX < 10 && absDistY < 10) ) { 18852 return; 18853 } 18854 18855 // If you are scrolling in one direction lock the other 18856 if ( !this.directionLocked && !this.options.freeScroll ) { 18857 if ( absDistX > absDistY + this.options.directionLockThreshold ) { 18858 this.directionLocked = 'h'; // lock horizontally 18859 } else if ( absDistY >= absDistX + this.options.directionLockThreshold ) { 18860 this.directionLocked = 'v'; // lock vertically 18861 } else { 18862 this.directionLocked = 'n'; // no lock 18863 } 18864 } 18865 18866 if ( this.directionLocked == 'h' ) { 18867 if ( this.options.eventPassthrough == 'vertical' ) { 18868 e.preventDefault(); 18869 } else if ( this.options.eventPassthrough == 'horizontal' ) { 18870 this.initiated = false; 18871 return; 18872 } 18873 18874 deltaY = 0; 18875 } else if ( this.directionLocked == 'v' ) { 18876 if ( this.options.eventPassthrough == 'horizontal' ) { 18877 e.preventDefault(); 18878 } else if ( this.options.eventPassthrough == 'vertical' ) { 18879 this.initiated = false; 18880 return; 18881 } 18882 18883 deltaX = 0; 18884 } 18885 18886 deltaX = this.hasHorizontalScroll ? deltaX : 0; 18887 deltaY = this.hasVerticalScroll ? deltaY : 0; 18888 18889 newX = this.x + deltaX; 18890 newY = this.y + deltaY; 18891 18892 // Slow down if outside of the boundaries 18893 if ( newX > 0 || newX < this.maxScrollX ) { 18894 newX = this.options.bounce ? this.x + deltaX / 3 : newX > 0 ? 0 : this.maxScrollX; 18895 } 18896 if ( newY > 0 || newY < this.maxScrollY ) { 18897 newY = this.options.bounce ? this.y + deltaY / 3 : newY > 0 ? 0 : this.maxScrollY; 18898 } 18899 18900 this.directionX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0; 18901 this.directionY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0; 18902 18903 if ( !this.moved ) { 18904 this._execEvent('scrollStart'); 18905 } 18906 18907 this.moved = true; 18908 18909 this._translate(newX, newY); 18910 18911/* REPLACE START: _move */ 18912 18913 if ( timestamp - this.startTime > 300 ) { 18914 this.startTime = timestamp; 18915 this.startX = this.x; 18916 this.startY = this.y; 18917 } 18918 18919/* REPLACE END: _move */ 18920 18921 }, 18922 18923 _end: function (e) { 18924 if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) { 18925 return; 18926 } 18927 18928 if ( this.options.preventDefault && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) { 18929 e.preventDefault(); 18930 } 18931 18932 var point = e.changedTouches ? e.changedTouches[0] : e, 18933 momentumX, 18934 momentumY, 18935 duration = utils.getTime() - this.startTime, 18936 newX = Math.round(this.x), 18937 newY = Math.round(this.y), 18938 distanceX = Math.abs(newX - this.startX), 18939 distanceY = Math.abs(newY - this.startY), 18940 time = 0, 18941 easing = ''; 18942 18943 this.isInTransition = 0; 18944 this.initiated = 0; 18945 this.endTime = utils.getTime(); 18946 18947 // reset if we are outside of the boundaries 18948 if ( this.resetPosition(this.options.bounceTime) ) { 18949 return; 18950 } 18951 18952 this.scrollTo(newX, newY); // ensures that the last position is rounded 18953 18954 // we scrolled less than 10 pixels 18955 if ( !this.moved ) { 18956 if ( this.options.tap ) { 18957 utils.tap(e, this.options.tap); 18958 } 18959 18960 if ( this.options.click ) { 18961 utils.click(e); 18962 } 18963 18964 this._execEvent('scrollCancel'); 18965 return; 18966 } 18967 18968 if ( this._events.flick && duration < 200 && distanceX < 100 && distanceY < 100 ) { 18969 this._execEvent('flick'); 18970 return; 18971 } 18972 18973 // start momentum animation if needed 18974 if ( this.options.momentum && duration < 300 ) { 18975 momentumX = this.hasHorizontalScroll ? utils.momentum(this.x, this.startX, duration, this.maxScrollX, this.options.bounce ? this.wrapperW
18975idth : 0, this.options.deceleration) : { destination: newX, duration: 0 }; 18976 momentumY = this.hasVerticalScroll ? utils.momentum(this.y, this.startY, duration, this.maxScrollY, this.options.bounce ? this.wrapperHeight : 0, this.options.deceleration) : { destination: newY, duration: 0 }; 18977 newX = momentumX.destination; 18978 newY = momentumY.destination; 18979 time = Math.max(momentumX.duration, momentumY.duration); 18980 this.isInTransition = 1; 18981 } 18982 18983 18984 if ( this.options.snap ) { 18985 var snap = this._nearestSnap(newX, newY); 18986 this.currentPage = snap; 18987 time = this.options.snapSpeed || Math.max( 18988 Math.max( 18989 Math.min(Math.abs(newX - snap.x), 1000), 18990 Math.min(Math.abs(newY - snap.y), 1000) 18991 ), 300); 18992 newX = snap.x; 18993 newY = snap.y; 18994 18995 this.directionX = 0; 18996 this.directionY = 0; 18997 easing = this.options.bounceEasing; 18998 } 18999 19000// INSERT POINT: _end 19001 19002 if ( newX != this.x || newY != this.y ) { 19003 // change easing function when scroller goes out of the boundaries 19004 if ( newX > 0 || newX < this.maxScrollX || newY > 0 || newY < this.maxScrollY ) { 19005 easing = utils.ease.quadratic; 19006 } 19007 19008 this.scrollTo(newX, newY, time, easing); 19009 return; 19010 } 19011 19012 this._execEvent('scrollEnd'); 19013 }, 19014 19015 _resize: function () { 19016 var that = this; 19017 19018 clearTimeout(this.resizeTimeout); 19019 19020 this.resizeTimeout = setTimeout(function () { 19021 that.refresh(); 19022 }, this.options.resizePolling); 19023 }, 19024 19025 resetPosition: function (time) { 19026 var x = this.x, 19027 y = this.y; 19028 19029 time = time || 0; 19030 19031 if ( !this.hasHorizontalScroll || this.x > 0 ) { 19032 x = 0; 19033 } else if ( this.x < this.maxScrollX ) { 19034 x = this.maxScrollX; 19035 } 19036 19037 if ( !this.hasVerticalScroll || this.y > 0 ) { 19038 y = 0; 19039 } else if ( this.y < this.maxScrollY ) { 19040 y = this.maxScrollY; 19041 } 19042 19043 if ( x == this.x && y == this.y ) { 19044 return false; 19045 } 19046 19047 this.scrollTo(x, y, time, this.options.bounceEasing); 19048 19049 return true; 19050 }, 19051 19052 disable: function () { 19053 this.enabled = false; 19054 }, 19055 19056 enable: function () { 19057 this.enabled = true; 19058 }, 19059 19060 refresh: function () { 19061 var rf = this.wrapper.offsetHeight; // Force reflow 19062 19063 this.wrapperWidth = this.wrapper.clientWidth; 19064 this.wrapperHeight = this.wrapper.clientHeight; 19065 19066/* REPLACE START: refresh */ 19067 19068 this.scrollerWidth = this.scroller.offsetWidth; 19069 this.scrollerHeight = this.scroller.offsetHeight; 19070 19071 this.maxScrollX = this.wrapperWidth - this.scrollerWidth; 19072 this.maxScrollY = this.wrapperHeight - this.scrollerHeight; 19073 19074/* REPLACE END: refresh */ 19075 19076 this.hasHorizontalScroll = this.options.scrollX && this.maxScrollX < 0; 19077 this.hasVerticalScroll = this.options.scrollY && this.maxScrollY < 0; 19078 19079 if ( !this.hasHorizontalScroll ) { 19080 this.maxScrollX = 0; 19081 this.scrollerWidth = this.wrapperWidth; 19082 } 19083 19084 if ( !this.hasVerticalScroll ) { 19085 this.maxScrollY = 0; 19086 this.scrollerHeight = this.wrapperHeight; 19087 } 19088 19089 this.endTime = 0; 19090 this.directionX = 0; 19091 this.directionY = 0; 19092 19093 this.wrapperOffset = utils.offset(this.wrapper); 19094 19095 this._execEvent('refresh'); 19096 19097 this.resetPosition(); 19098 19099// INSERT POINT: _refresh 19100 19101 }, 19102 19103 on: function (type, fn) { 19104 if ( !this._events[type] ) { 19105 this._events[type] = []; 19106 } 19107 19108 this._events[type].push(fn); 19109 }, 19110 19111 off: function (type, fn) { 19112 if ( !this._events[type] ) { 19113 return; 19114 } 19115 19116 var index = this._events[type].indexOf(fn); 19117 19118 if ( index > -1 ) { 19119 this._events[type].splice(index, 1); 19120 } 19121 }, 19122 19123 _execEvent: function (type) { 19124 if ( !this._events[type] ) { 19125 return; 19126 } 19127 19128 var i = 0, 19129 l = this._events[type].length; 19130 19131 if ( !l ) { 19132 return; 19133 } 19134 19135 for ( ; i < l; i++ ) { 19136 this._events[type][i].apply(this, [].slice.call(arguments, 1)); 19137 } 19138 }, 19139 19140 scrollBy: function (x, y, time, easing) { 19141 x = this.x + x; 19142 y = this.y + y; 19143 time = time || 0; 19144 19145 this.scrollTo(x, y, time, easing); 19146 }, 19147 19148 scrollTo: function (x, y, time, easing) { 19149 easing = easing || utils.ease.circular; 19150 19151 this.isInTransition = this.options.useTransition && time > 0; 19152 var transitionType = this.options.useTransition && easing.style; 19153 if ( !time || transitionType ) { 19154 if(transitionType) { 19155 this._transitionTimingFunction(easing.style); 19156 this._transitionTime(time); 19157 } 19158 this._translate(x, y); 19159 } else { 19160 this._animate(x, y, time, easing.fn); 19161 } 19162 }, 19163 19164 scrollToElement: function (el, time, offsetX, offsetY, easing) { 19165 el = el.nodeType ? el : this.scroller.querySelector(el); 19166 19167 if ( !el ) { 19168 return; 19169 } 19170 19171 var pos = utils.offset(el); 19172 19173 pos.left -= this.wrapperOffset.left; 19174 pos.top -= this.wrapperOffset.top; 19175 19176 // if offsetX/Y are true we center the element to the screen 19177 if ( offsetX === true ) { 19178 offsetX = Math.round(el.offsetWidth / 2 - this.wrapper.offsetWidth / 2); 19179 } 19180 if ( offsetY === true ) { 19181 offsetY = Math.round(el.offsetHeight / 2 - this.wrapper.offsetHeight / 2); 19182 } 19183 19184 pos.left -= offsetX || 0; 19185 pos.top -= offsetY || 0; 19186 19187 pos.left = pos.left > 0 ? 0 : pos.left < this.maxScrollX ? this.maxScrollX : pos.left; 19188 pos.top = pos.top > 0 ? 0 : pos.top < this.maxScrollY ? this.maxScrollY : pos.top; 19189 19190 time = time === undefined || time === null || time === 'auto' ? Math.max(Math.abs(this.x-pos.left), Math.abs(this.y-pos.top)) : time; 19191 19192 this.scrollTo(pos.left, pos.top, time, easing); 19193 }, 19194 19195 _transitionTime: function (time) { 19196 if (!this.options.useTransition) { 19197 return; 19198 } 19199 time = time || 0; 19200 var durationProp = utils.style.transitionDuration; 19201 if(!durationProp) { 19202 return; 19203 } 19204 19205 this.scrollerStyle[durationProp] = time + 'ms'; 19206 19207 if ( !time && utils.isBadAndroid ) { 19208 this.scrollerStyle[durationProp] = '0.0001ms'; 19209 // remove 0.0001ms 19210 var self = this; 19211 rAF(function() { 19212 if(self.scrollerStyle[durationProp] === '0.0001ms') { 19213 self.scrollerStyle[durationProp] = '0s'; 19214 } 19215 }); 19216 } 19217 19218 19219 if ( this.indicators ) { 19220 for ( var i = this.indicators.length; i--; ) { 19221 this.indicators[i].transitionTime(time); 19222 } 19223 } 19224 19225 19226// INSERT POINT: _transitionTime 19227 19228 }, 19229 19230 _transitionTimingFunction: function (easing) { 19231 this.scrollerStyle[utils.style.transitionTimingFunction] = easing; 19232 19233 19234 if ( this.indicators ) { 19235 for ( var i = this.indicators.length; i--; ) { 19236 this.indicators[i].transitionTimingFunction(easing); 19237 } 19238 } 19239 19240 19241// INSERT POINT: _transitionTimingFunction 19242 19243 }, 19244 19245 _translate: function (x, y) { 19246 //Uncode addition 19247 if ( (" " + this.wrapper.className + " ").replace(/[\n\t]/g, " ").indexOf(" no-scrolloverflow ") > -1 ) 19248 return false;
19249 19250 if ( this.options.useTransform ) { 19251 19252/* REPLACE START: _translate */ 19253 19254 this.scrollerStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.translateZ; 19255 19256/* REPLACE END: _translate */ 19257 19258 } else { 19259 x = Math.round(x); 19260 y = Math.round(y); 19261 this.scrollerStyle.left = x + 'px'; 19262 this.scrollerStyle.top = y + 'px'; 19263 } 19264 19265 this.x = x; 19266 this.y = y; 19267 19268 19269 if ( this.indicators ) { 19270 for ( var i = this.indicators.length; i--; ) { 19271 this.indicators[i].updatePosition(); 19272 } 19273 } 19274 19275 //Uncode addition 19276 var uncodevent = new CustomEvent('fp-slide-scroll'); 19277 window.dispatchEvent(uncodevent); 19278 19279// INSERT POINT: _translate 19280 19281 }, 19282 19283 _initEvents: function (remove) { 19284 var eventType = remove ? utils.removeEvent : utils.addEvent, 19285 target = this.options.bindToWrapper ? this.wrapper : window; 19286 19287 eventType(window, 'orientationchange', this); 19288 eventType(window, 'resize', this); 19289 19290 if ( this.options.click ) { 19291 eventType(this.wrapper, 'click', this, true); 19292 } 19293 19294 if ( !this.options.disableMouse ) { 19295 eventType(this.wrapper, 'mousedown', this); 19296 eventType(target, 'mousemove', this); 19297 eventType(target, 'mousecancel', this); 19298 eventType(target, 'mouseup', this); 19299 } 19300 19301 if ( utils.hasPointer && !this.options.disablePointer ) { 19302 eventType(this.wrapper, utils.prefixPointerEvent('pointerdown'), this); 19303 eventType(target, utils.prefixPointerEvent('pointermove'), this); 19304 eventType(target, utils.prefixPointerEvent('pointercancel'), this); 19305 eventType(target, utils.prefixPointerEvent('pointerup'), this); 19306 } 19307 19308 if ( utils.hasTouch && !this.options.disableTouch ) { 19309 eventType(this.wrapper, 'touchstart', this); 19310 eventType(target, 'touchmove', this); 19311 eventType(target, 'touchcancel', this); 19312 eventType(target, 'touchend', this); 19313 } 19314 19315 eventType(this.scroller, 'transitionend', this); 19316 eventType(this.scroller, 'webkitTransitionEnd', this); 19317 eventType(this.scroller, 'oTransitionEnd', this); 19318 eventType(this.scroller, 'MSTransitionEnd', this); 19319 }, 19320 19321 getComputedPosition: function () { 19322 var matrix = window.getComputedStyle(this.scroller, null), 19323 x, y; 19324 19325 if ( this.options.useTransform ) { 19326 matrix = matrix[utils.style.transform].split(')')[0].split(', '); 19327 x = +(matrix[12] || matrix[4]); 19328 y = +(matrix[13] || matrix[5]); 19329 } else { 19330 x = +matrix.left.replace(/[^-\d.]/g, ''); 19331 y = +matrix.top.replace(/[^-\d.]/g, ''); 19332 } 19333 19334 return { x: x, y: y }; 19335 }, 19336 _initIndicators: function () { 19337 var interactive = this.options.interactiveScrollbars, 19338 customStyle = typeof this.options.scrollbars != 'string', 19339 indicators = [], 19340 indicator; 19341 19342 var that = this; 19343 19344 this.indicators = []; 19345 19346 if ( this.options.scrollbars ) { 19347 // Vertical scrollbar 19348 if ( this.options.scrollY ) { 19349 indicator = { 19350 el: createDefaultScrollbar('v', interactive, this.options.scrollbars), 19351 interactive: interactive, 19352 defaultScrollbars: true, 19353 customStyle: customStyle, 19354 resize: this.options.resizeScrollbars, 19355 shrink: this.options.shrinkScrollbars, 19356 fade: this.options.fadeScrollbars, 19357 listenX: false 19358 }; 19359 19360 this.wrapper.appendChild(indicator.el); 19361 indicators.push(indicator); 19362 } 19363 19364 // Horizontal scrollbar 19365 if ( this.options.scrollX ) { 19366 indicator = { 19367 el: createDefaultScrollbar('h', interactive, this.options.scrollbars), 19368 interactive: interactive, 19369 defaultScrollbars: true, 19370 customStyle: customStyle, 19371 resize: this.options.resizeScrollbars, 19372 shrink: this.options.shrinkScrollbars, 19373 fade: this.options.fadeScrollbars, 19374 listenY: false 19375 }; 19376 19377 this.wrapper.appendChild(indicator.el); 19378 indicators.push(indicator); 19379 } 19380 } 19381 19382 if ( this.options.indicators ) { 19383 // TODO: check concat compatibility 19384 indicators = indicators.concat(this.options.indicators); 19385 } 19386 19387 for ( var i = indicators.length; i--; ) { 19388 this.indicators.push( new Indicator(this, indicators[i]) ); 19389 } 19390 19391 // TODO: check if we can use array.map (wide compatibility and performance issues) 19392 function _indicatorsMap (fn) { 19393 if (that.indicators) { 19394 for ( var i = that.indicators.length; i--; ) { 19395 fn.call(that.indicators[i]); 19396 } 19397 } 19398 } 19399 19400 if ( this.options.fadeScrollbars ) { 19401 this.on('scrollEnd', function () { 19402 _indicatorsMap(function () { 19403 this.fade(); 19404 }); 19405 }); 19406 19407 this.on('scrollCancel', function () { 19408 _indicatorsMap(function () { 19409 this.fade(); 19410 }); 19411 }); 19412 19413 this.on('scrollStart', function () { 19414 _indicatorsMap(function () { 19415 this.fade(1); 19416 }); 19417 }); 19418 19419 this.on('beforeScrollStart', function () { 19420 _indicatorsMap(function () { 19421 this.fade(1, true); 19422 }); 19423 }); 19424 } 19425 19426 19427 this.on('refresh', function () { 19428 _indicatorsMap(function () { 19429 this.refresh(); 19430 }); 19431 }); 19432 19433 this.on('destroy', function () { 19434 _indicatorsMap(function () { 19435 this.destroy(); 19436 }); 19437 19438 delete this.indicators; 19439 }); 19440 }, 19441 19442 _initWheel: function () { 19443 utils.addEvent(this.wrapper, 'wheel', this); 19444 utils.addEvent(this.wrapper, 'mousewheel', this); 19445 utils.addEvent(this.wrapper, 'DOMMouseScroll', this); 19446 19447 this.on('destroy', function () { 19448 clearTimeout(this.wheelTimeout); 19449 this.wheelTimeout = null; 19450 utils.removeEvent(this.wrapper, 'wheel', this); 19451 utils.removeEvent(this.wrapper, 'mousewheel', this); 19452 utils.removeEvent(this.wrapper, 'DOMMouseScroll', this); 19453 }); 19454 }, 19455 19456 _wheel: function (e) { 19457 if ( !this.enabled ) { 19458 return; 19459 } 19460 19461 var wheelDeltaX, wheelDeltaY, 19462 newX, newY, 19463 that = this; 19464 19465 if ( this.wheelTimeout === undefined ) { 19466 that._execEvent('scrollStart'); 19467 } 19468 19469 // Execute the scrollEnd event after 400ms the wheel stopped scrolling 19470 clearTimeout(this.wheelTimeout); 19471 this.wheelTimeout = setTimeout(function () { 19472 if(!that.options.snap) { 19473 that._execEvent('scrollEnd'); 19474 } 19475 that.wheelTimeout = undefined; 19476 }, 400); 19477 19478 if ( 'deltaX' in e ) { 19479 if (e.deltaMode === 1) { 19480 wheelDeltaX = -e.deltaX * this.options.mouseWheelSpeed; 19481 wheelDeltaY = -e.deltaY * this.options.mouseWheelSpeed; 19482 } else { 19483 wheelDeltaX = -e.deltaX; 19484 wheelDeltaY = -e.deltaY; 19485 } 19486 } else if ( 'wheelDeltaX' in e ) { 19487 wheelDeltaX = e.wheelDeltaX / 120 * this.options.mouseWheelSpeed; 19488 wheelDeltaY = e.wheelDeltaY / 120 * this.options.mouseWheelSpeed; 19489 } else if ( 'wheelDelta' in e ) { 19490 wheelDeltaX = wheelDeltaY = e.wheelDelta / 120 * this.options.mouseWheelSpeed; 19491 } else if ( 'detail' in e ) { 19492 wheelDeltaX = wheelDeltaY = -e.detail / 3 * this.options.mouseWheelSpeed; 19493 } else { 19494 return; 19495 } 19496 19497 wheelDeltaX *= this.options.invertWheelDirection; 19498 wheelDeltaY *= this.options.invertWheelDirection; 19499 19500 if ( !this.hasVerticalScroll ) { 19501 wheelDeltaX = wheelDeltaY; 19502 wheelDeltaY = 0; 19503 } 19504 19505 if ( this.options.snap ) { 19506 newX = this.currentPage.pageX; 19507 newY = this.currentPage.pageY; 19508 19509 if ( wheelDeltaX > 0 ) { 19510 newX--; 19511 } else if ( wheelDeltaX < 0 ) { 19512 newX++; 19513 } 19514 19515 if ( wheelDeltaY > 0 ) { 19516 newY--; 19517 } else if ( wheelDeltaY < 0 ) { 19518 newY++; 19519 } 19520 19521 this.goToPage(newX, newY); 19522 19523 return; 19524 } 19525 19526 newX = this.x + Math.round(this.hasHorizontalScroll ? wheelDeltaX : 0); 19527 newY = this.y + Math.round(this.hasVerticalScroll ? wheelDeltaY : 0); 19528 19529 this.directionX = wheelDeltaX > 0 ? -1 : wheelDeltaX < 0 ? 1 : 0; 19530 this.directionY = wheelDeltaY > 0 ? -1 : wheelDeltaY < 0 ? 1 : 0; 19531 19532 if ( newX > 0 ) { 19533 newX = 0; 19534 } else if ( newX < this.maxScrollX ) { 19535 newX = this.maxScrollX; 19536 } 19537 19538 if ( newY > 0 ) { 19539 newY = 0; 19540 } else if ( newY < this.maxScrollY ) { 19541 newY = this.maxScrollY; 19542 } 19543 19544 this.scrollTo(newX, newY, 0); 19545 19546// INSERT POINT: _wheel 19547 }, 19548 19549 _initSnap: function () { 19550 this.currentPage = {}; 19551 19552 if ( typeof this.options.snap == 'string' ) { 19553 this.options.snap = this.scroller.querySelectorAll(this.options.snap); 19554 } 19555 19556 this.on('refresh', function () { 19557 var i = 0, l, 19558 m = 0, n, 19559 cx, cy, 19560 x = 0, y,
19561 stepX = this.options.snapStepX || this.wrapperWidth, 19562 stepY = this.options.snapStepY || this.wrapperHeight, 19563 el; 19564 19565 this.pages = []; 19566 19567 if ( !this.wrapperWidth || !this.wrapperHeight || !this.scrollerWidth || !this.scrollerHeight ) { 19568 return; 19569 } 19570 19571 if ( this.options.snap === true ) { 19572 cx = Math.round( stepX / 2 ); 19573 cy = Math.round( stepY / 2 ); 19574 19575 while ( x > -this.scrollerWidth ) { 19576 this.pages[i] = []; 19577 l = 0; 19578 y = 0; 19579 19580 while ( y > -this.scrollerHeight ) { 19581 this.pages[i][l] = { 19582 x: Math.max(x, this.maxScrollX), 19583 y: Math.max(y, this.maxScrollY), 19584 width: stepX, 19585 height: stepY, 19586 cx: x - cx, 19587 cy: y - cy 19588 }; 19589 19590 y -= stepY; 19591 l++; 19592 } 19593 19594 x -= stepX; 19595 i++; 19596 } 19597 } else { 19598 el = this.options.snap; 19599 l = el.length; 19600 n = -1; 19601 19602 for ( ; i < l; i++ ) { 19603 if ( i === 0 || el[i].offsetLeft <= el[i-1].offsetLeft ) { 19604 m = 0; 19605 n++; 19606 } 19607 19608 if ( !this.pages[m] ) { 19609 this.pages[m] = []; 19610 } 19611 19612 x = Math.max(-el[i].offsetLeft, this.maxScrollX); 19613 y = Math.max(-el[i].offsetTop, this.maxScrollY); 19614 cx = x - Math.round(el[i].offsetWidth / 2); 19615 cy = y - Math.round(el[i].offsetHeight / 2); 19616 19617 this.pages[m][n] = { 19618 x: x, 19619 y: y, 19620 width: el[i].offsetWidth, 19621 height: el[i].offsetHeight, 19622 cx: cx, 19623 cy: cy 19624 }; 19625 19626 if ( x > this.maxScrollX ) { 19627 m++; 19628 } 19629 } 19630 } 19631 19632 this.goToPage(this.currentPage.pageX || 0, this.currentPage.pageY || 0, 0); 19633 19634 // Update snap threshold if needed 19635 if ( this.options.snapThreshold % 1 === 0 ) { 19636 this.snapThresholdX = this.options.snapThreshold; 19637 this.snapThresholdY = this.options.snapThreshold; 19638 } else { 19639 this.snapThresholdX = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].width * this.options.snapThreshold); 19640 this.snapThresholdY = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].height * this.options.snapThreshold); 19641 } 19642 }); 19643 19644 this.on('flick', function () { 19645 var time = this.options.snapSpeed || Math.max( 19646 Math.max( 19647 Math.min(Math.abs(this.x - this.startX), 1000), 19648 Math.min(Math.abs(this.y - this.startY), 1000) 19649 ), 300); 19650 19651 this.goToPage( 19652 this.currentPage.pageX + this.directionX, 19653 this.currentPage.pageY + this.directionY, 19654 time 19655 ); 19656 }); 19657 }, 19658 19659 _nearestSnap: function (x, y) { 19660 if ( !this.pages.length ) { 19661 return { x: 0, y: 0, pageX: 0, pageY: 0 }; 19662 } 19663 19664 var i = 0, 19665 l = this.pages.length, 19666 m = 0; 19667 19668 // Check if we exceeded the snap threshold 19669 if ( Math.abs(x - this.absStartX) < this.snapThresholdX && 19670 Math.abs(y - this.absStartY) < this.snapThresholdY ) { 19671 return this.currentPage; 19672 } 19673 19674 if ( x > 0 ) { 19675 x = 0; 19676 } else if ( x < this.maxScrollX ) { 19677 x = this.maxScrollX; 19678 } 19679 19680 if ( y > 0 ) { 19681 y = 0; 19682 } else if ( y < this.maxScrollY ) { 19683 y = this.maxScrollY; 19684 } 19685 19686 for ( ; i < l; i++ ) { 19687 if ( x >= this.pages[i][0].cx ) { 19688 x = this.pages[i][0].x; 19689 break; 19690 } 19691 } 19692 19693 l = this.pages[i].length; 19694 19695 for ( ; m < l; m++ ) { 19696 if ( y >= this.pages[0][m].cy ) { 19697 y = this.pages[0][m].y; 19698 break; 19699 } 19700 } 19701 19702 if ( i == this.currentPage.pageX ) { 19703 i += this.directionX; 19704 19705 if ( i < 0 ) { 19706 i = 0; 19707 } else if ( i >= this.pages.length ) { 19708 i = this.pages.length - 1; 19709 } 19710 19711 x = this.pages[i][0].x; 19712 } 19713 19714 if ( m == this.currentPage.pageY ) { 19715 m += this.directionY; 19716 19717 if ( m < 0 ) { 19718 m = 0; 19719 } else if ( m >= this.pages[0].length ) { 19720 m = this.pages[0].length - 1; 19721 } 19722 19723 y = this.pages[0][m].y; 19724 } 19725 19726 return { 19727 x: x, 19728 y: y, 19729 pageX: i, 19730 pageY: m 19731 }; 19732 }, 19733 19734 goToPage: function (x, y, time, easing) { 19735 easing = easing || this.options.bounceEasing; 19736 19737 if ( x >= this.pages.length ) { 19738 x = this.pages.length - 1; 19739 } else if ( x < 0 ) { 19740 x = 0; 19741 } 19742 19743 if ( y >= this.pages[x].length ) { 19744 y = this.pages[x].length - 1; 19745 } else if ( y < 0 ) { 19746 y = 0; 19747 } 19748 19749 var posX = this.pages[x][y].x, 19750 posY = this.pages[x][y].y; 19751 19752 time = time === undefined ? this.options.snapSpeed || Math.max( 19753 Math.max( 19754 Math.min(Math.abs(posX - this.x), 1000), 19755 Math.min(Math.abs(posY - this.y), 1000) 19756 ), 300) : time; 19757 19758 this.currentPage = { 19759 x: posX, 19760 y: posY, 19761 pageX: x, 19762 pageY: y 19763 }; 19764 19765 this.scrollTo(posX, posY, time, easing); 19766 }, 19767 19768 next: function (time, easing) { 19769 var x = this.currentPage.pageX, 19770 y = this.currentPage.pageY; 19771 19772 x++; 19773 19774 if ( x >= this.pages.length && this.hasVerticalScroll ) { 19775 x = 0; 19776 y++; 19777 } 19778 19779 this.goToPage(x, y, time, easing); 19780 }, 19781 19782 prev: function (time, easing) { 19783 var x = this.currentPage.pageX, 19784 y = this.currentPage.pageY; 19785 19786 x--; 19787 19788 if ( x < 0 && this.hasVerticalScroll ) { 19789 x = 0; 19790 y--; 19791 } 19792 19793 this.goToPage(x, y, time, easing); 19794 }, 19795 19796 _initKeys: function (e) { 19797 // default key bindings 19798 var keys = { 19799 pageUp: 33, 19800 pageDown: 34, 19801 end: 35, 19802 home: 36, 19803 left: 37, 19804 up: 38, 19805 right: 39, 19806 down: 40 19807 }; 19808 var i; 19809 19810 // if you give me characters I give you keycode 19811 if ( typeof this.options.keyBindings == 'object' ) { 19812 for ( i in this.options.keyBindings ) { 19813 if ( typeof this.options.keyBindings[i] == 'string' ) { 19814 this.options.keyBindings[i] = this.options.keyBindings[i].toUpperCase().charCo
19814deAt(0); 19815 } 19816 } 19817 } else { 19818 this.options.keyBindings = {}; 19819 } 19820 19821 for ( i in keys ) { 19822 this.options.keyBindings[i] = this.options.keyBindings[i] || keys[i]; 19823 } 19824 19825 utils.addEvent(window, 'keydown', this); 19826 19827 this.on('destroy', function () { 19828 utils.removeEvent(window, 'keydown', this); 19829 }); 19830 }, 19831 19832 _key: function (e) { 19833 if ( !this.enabled ) { 19834 return; 19835 } 19836 19837 var snap = this.options.snap, // we are using this alot, better to cache it 19838 newX = snap ? this.currentPage.pageX : this.x, 19839 newY = snap ? this.currentPage.pageY : this.y, 19840 now = utils.getTime(), 19841 prevTime = this.keyTime || 0, 19842 acceleration = 0.250, 19843 pos; 19844 19845 if ( this.options.useTransition && this.isInTransition ) { 19846 pos = this.getComputedPosition(); 19847 19848 this._translate(Math.round(pos.x), Math.round(pos.y)); 19849 this.isInTransition = false; 19850 } 19851 19852 this.keyAcceleration = now - prevTime < 200 ? Math.min(this.keyAcceleration + acceleration, 50) : 0; 19853 19854 switch ( e.keyCode ) { 19855 case this.options.keyBindings.pageUp: 19856 if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) { 19857 newX += snap ? 1 : this.wrapperWidth; 19858 } else { 19859 newY += snap ? 1 : this.wrapperHeight; 19860 } 19861 break; 19862 case this.options.keyBindings.pageDown: 19863 if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) { 19864 newX -= snap ? 1 : this.wrapperWidth; 19865 } else { 19866 newY -= snap ? 1 : this.wrapperHeight; 19867 } 19868 break; 19869 case this.options.keyBindings.end: 19870 newX = snap ? this.pages.length-1 : this.maxScrollX; 19871 newY = snap ? this.pages[0].length-1 : this.maxScrollY; 19872 break; 19873 case this.options.keyBindings.home: 19874 newX = 0; 19875 newY = 0; 19876 break; 19877 case this.options.keyBindings.left: 19878 newX += snap ? -1 : 5 + this.keyAcceleration>>0; 19879 break; 19880 case this.options.keyBindings.up: 19881 newY += snap ? 1 : 5 + this.keyAcceleration>>0; 19882 break; 19883 case this.options.keyBindings.right: 19884 newX -= snap ? -1 : 5 + this.keyAcceleration>>0; 19885 break; 19886 case this.options.keyBindings.down: 19887 newY -= snap ? 1 : 5 + this.keyAcceleration>>0; 19888 break; 19889 default: 19890 return; 19891 } 19892 19893 if ( snap ) { 19894 this.goToPage(newX, newY); 19895 return; 19896 } 19897 19898 if ( newX > 0 ) { 19899 newX = 0; 19900 this.keyAcceleration = 0; 19901 } else if ( newX < this.maxScrollX ) { 19902 newX = this.maxScrollX; 19903 this.keyAcceleration = 0; 19904 } 19905 19906 if ( newY > 0 ) { 19907 newY = 0; 19908 this.keyAcceleration = 0; 19909 } else if ( newY < this.maxScrollY ) { 19910 newY = this.maxScrollY; 19911 this.keyAcceleration = 0; 19912 } 19913 19914 this.scrollTo(newX, newY, 0); 19915 19916 this.keyTime = now; 19917 }, 19918 19919 _animate: function (destX, destY, duration, easingFn) { 19920 var that = this, 19921 startX = this.x, 19922 startY = this.y, 19923 startTime = utils.getTime(), 19924 destTime = startTime + duration; 19925 19926 function step () { 19927 var now = utils.getTime(), 19928 newX, newY, 19929 easing; 19930 19931 if ( now >= destTime ) { 19932 that.isAnimating = false; 19933 that._translate(destX, destY); 19934 19935 if ( !that.resetPosition(that.options.bounceTime) ) { 19936 that._execEvent('scrollEnd'); 19937 } 19938 19939 return; 19940 } 19941 19942 now = ( now - startTime ) / duration; 19943 easing = easingFn(now); 19944 newX = ( destX - startX ) * easing + startX; 19945 newY = ( destY - startY ) * easing + startY; 19946 that._translate(newX, newY); 19947 19948 if ( that.isAnimating ) { 19949 rAF(step); 19950 } 19951 } 19952 19953 this.isAnimating = true; 19954 step(); 19955 }, 19956 handleEvent: function (e) { 19957 switch ( e.type ) { 19958 case 'touchstart': 19959 case 'pointerdown': 19960 case 'MSPointerDown': 19961 case 'mousedown': 19962 this._start(e); 19963 break; 19964 case 'touchmove': 19965 case 'pointermove': 19966 case 'MSPointerMove': 19967 case 'mousemove': 19968 this._move(e); 19969 break; 19970 case 'touchend': 19971 case 'pointerup': 19972 case 'MSPointerUp': 19973 case 'mouseup': 19974 case 'touchcancel': 19975 case 'pointercancel': 19976 case 'MSPointerCancel': 19977 case 'mousecancel': 19978 this._end(e); 19979 break; 19980 case 'orientationchange': 19981 case 'resize': 19982 this._resize(); 19983 break; 19984 case 'transitionend': 19985 case 'webkitTransitionEnd': 19986 case 'oTransitionEnd': 19987 case 'MSTransitionEnd': 19988 this._transitionEnd(e); 19989 break; 19990 case 'wheel': 19991 case 'DOMMouseScroll': 19992 case 'mousewheel': 19993 this._wheel(e); 19994 break; 19995 case 'keydown': 19996 this._key(e); 19997 break; 19998 case 'click': 19999 if ( this.enabled && !e._constructed ) { 20000 e.preventDefault(); 20001 e.stopPropagation(); 20002 } 20003 break; 20004 } 20005 } 20006}; 20007function createDefaultScrollbar (direction, interactive, type) { 20008 var scrollbar = document.createElement('div'), 20009 indicator = document.createElement('div'); 20010 20011 if ( type === true ) { 20012 scrollbar.style.cssText = 'position:absolute;z-index:9999'; 20013 indicator.style.cssText = '-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;position:absolute;background:rgba(0,0,0,0.5);border:1px solid rgba(255,255,255,0.9);border-radius:3px'; 20014 } 20015 20016 indicator.className = 'iScrollIndicator'; 20017 20018 if ( direction == 'h' ) { 20019 if ( type === true ) { 20020 scrollbar.style.cssText += ';height:7px;left:2px;right:2px;bottom:0'; 20021 indicator.style.height = '100%'; 20022 } 20023 scrollbar.className = 'iScrollHorizontalScrollbar'; 20024 } else { 20025 if ( type === true ) { 20026 scrollbar.style.cssText += ';width:7px;bottom:2px;top:2px;right:1px'; 20027 indicator.style.width = '100%'; 20028 } 20029 scrollbar.className = 'iScrollVerticalScrollbar'; 20030 } 20031 20032 scrollbar.style.cssText += ';overflow:hidden'; 20033 20034 if ( !interactive ) { 20035 scrollbar.style.pointerEvents = 'none'; 20036 } 20037 20038 scrollbar.appendChild(indicator); 20039 20040 return scrollbar; 20041} 20042 20043function Indicator (scroller, options) { 20044 this.wrapper = typeof options.el == 'string' ? document.querySelector(options.el) : options.el; 20045 this.wrapperStyle = this.wrapper.style; 20046 this.indicator = this.wrapper.children[0]; 20047 this.indicatorStyle = this.indicator.style; 20048 this.scroller = scroller; 20049 20050 this.options = { 20051 listenX: true, 20052 listenY: true, 20053 interactive: false, 20054 resize: true, 20055 defaultScrollbars: false, 20056 shrink: false, 20057 fade: false, 20058 speedRatioX: 0, 20059 speedRatioY: 0 20060 }; 20061 20062 for ( var i in options ) { 20063 this.options[i] = options[i]; 20064 } 20065 20066 this.sizeRatioX = 1; 20067 this.sizeRatioY = 1; 20068 this.maxPosX = 0; 20069 this.maxPosY = 0; 20070 20071 if ( this.options.interactive ) { 20072 if ( !this.options.disableTouch ) { 20073 utils.addEvent(this.indicator, 'touchstart', this); 20074 utils.addEvent(window, 'touchend', this); 20075 } 20076 if ( !this.options.disablePointer ) { 20077 utils.addEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this); 20078 utils.addEvent(window, utils.prefixPointerEvent('pointerup'), this); 20079 } 20080 if ( !this.options.disableMouse ) { 20081 utils.addEvent(this.indicator, 'mousedown', this); 20082 utils.addEvent(window, 'mouseup', this); 20083 } 20084 } 20085 20086 if ( this.options.fade ) { 20087 this.wrapperStyle[utils.style.transform] = this.scroller.translateZ; 20088 var durationProp = utils.style.transitionDuration; 20089 if(!durationProp) { 20090 return; 20091 } 20092 this.wrapperStyle[durationProp] = utils.isBadAndroid ? '0.0001ms' : '0ms'; 20093 // remove 0.0001ms 20094 var self = this; 20095 if(utils.isBadAndroid) { 20096 rAF(function() { 20097 if(self.wrapperStyle[durationProp] === '0.0001ms') { 20098 self.wrapperStyle[durationProp] = '0s'; 20099 } 20100 }); 20101 } 20102 this.wrapperStyle.opacity = '0'; 20103 } 20104} 20105 20106Indicator.prototype = { 20107 handleEvent: function (e) { 20108 switch ( e.type ) { 20109 case 'touchstart': 20110 case 'pointerdown': 20111 case 'MSPointerDown': 20112 case 'mousedown': 20113 this._start(e); 20114 break; 20115 case 'touchmove': 20116 case 'pointermove': 20117 case 'MSPointerMove': 20118 case 'mousemove': 20119 this._move(e); 20120 break; 20121 case 'touchend': 20122 case 'pointerup': 20123 case 'MSPointerUp': 20124 case 'mouseup': 20125 case 'touchcancel': 20126 case 'pointercancel': 20127 case 'MSPointerCancel': 20128 case 'mousecancel': 20129 this._end(e); 20130 break; 20131 } 20132 }, 20133 20134 destroy: function () { 20135 if ( this.options.fadeScrollbars ) { 20136 clearTimeout(this.fadeTimeout); 20137 this.fadeTimeout = null; 20138 } 20139 if ( this.options.interactive ) { 20140 utils.removeEvent(this.indicator, 'touchstart', this); 20141 utils.removeEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this); 20142 utils.removeEvent(this.indicator, 'mousedown', this); 20143 20144 utils.removeEvent(window, 'touchmove', this); 20145 utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this); 20146 utils.removeEvent(window, 'mousemove', this); 20147 20148 utils.removeEvent(window, 'touchend', this); 20149 utils.removeEvent(window, utils.prefixPointerEvent('pointerup'), this); 20150 utils.removeEvent(window, 'mouseup', this); 20151 } 20152 20153 if ( this.options.defaultScrollbars ) { 20154 this.wrapper.parentNode.removeChild(this.wrapper); 20155 } 20156 }, 20157 20158 _start: function (e) { 20159 var point = e.touches ? e.touches[0] : e; 20160 20161 e.preventDefault(); 20162 e.stopPropagation(); 20163 20164 this.transitionTime(); 20165 20166 this.initiated = true; 20167 this.moved = false;
20168 this.lastPointX = point.pageX; 20169 this.lastPointY = point.pageY; 20170 20171 this.startTime = utils.getTime(); 20172 20173 if ( !this.options.disableTouch ) { 20174 utils.addEvent(window, 'touchmove', this); 20175 } 20176 if ( !this.options.disablePointer ) { 20177 utils.addEvent(window, utils.prefixPointerEvent('pointermove'), this); 20178 } 20179 if ( !this.options.disableMouse ) { 20180 utils.addEvent(window, 'mousemove', this); 20181 } 20182 20183 this.scroller._execEvent('beforeScrollStart'); 20184 }, 20185 20186 _move: function (e) { 20187 var point = e.touches ? e.touches[0] : e, 20188 deltaX, deltaY, 20189 newX, newY, 20190 timestamp = utils.getTime(); 20191 20192 if ( !this.moved ) { 20193 this.scroller._execEvent('scrollStart'); 20194 } 20195 20196 this.moved = true; 20197 20198 deltaX = point.pageX - this.lastPointX; 20199 this.lastPointX = point.pageX; 20200 20201 deltaY = point.pageY - this.lastPointY; 20202 this.lastPointY = point.pageY; 20203 20204 newX = this.x + deltaX; 20205 newY = this.y + deltaY; 20206 20207 this._pos(newX, newY); 20208 20209// INSERT POINT: indicator._move 20210 20211 e.preventDefault(); 20212 e.stopPropagation(); 20213 }, 20214 20215 _end: function (e) { 20216 if ( !this.initiated ) { 20217 return; 20218 } 20219 20220 this.initiated = false; 20221 20222 e.preventDefault(); 20223 e.stopPropagation(); 20224 20225 utils.removeEvent(window, 'touchmove', this); 20226 utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this); 20227 utils.removeEvent(window, 'mousemove', this); 20228 20229 if ( this.scroller.options.snap ) { 20230 var snap = this.scroller._nearestSnap(this.scroller.x, this.scroller.y); 20231 20232 var time = this.options.snapSpeed || Math.max( 20233 Math.max( 20234 Math.min(Math.abs(this.scroller.x - snap.x), 1000), 20235 Math.min(Math.abs(this.scroller.y - snap.y), 1000) 20236 ), 300); 20237 20238 if ( this.scroller.x != snap.x || this.scroller.y != snap.y ) { 20239 this.scroller.directionX = 0; 20240 this.scroller.directionY = 0; 20241 this.scroller.currentPage = snap; 20242 this.scroller.scrollTo(snap.x, snap.y, time, this.scroller.options.bounceEasing); 20243 } 20244 } 20245 20246 if ( this.moved ) { 20247 this.scroller._execEvent('scrollEnd'); 20248 } 20249 }, 20250 20251 transitionTime: function (time) { 20252 time = time || 0; 20253 var durationProp = utils.style.transitionDuration; 20254 if(!durationProp) { 20255 return; 20256 } 20257 20258 this.indicatorStyle[durationProp] = time + 'ms'; 20259 20260 if ( !time && utils.isBadAndroid ) { 20261 this.indicatorStyle[durationProp] = '0.0001ms'; 20262 // remove 0.0001ms 20263 var self = this; 20264 rAF(function() { 20265 if(self.indicatorStyle[durationProp] === '0.0001ms') { 20266 self.indicatorStyle[durationProp] = '0s'; 20267 } 20268 }); 20269 } 20270 }, 20271 20272 transitionTimingFunction: function (easing) { 20273 this.indicatorStyle[utils.style.transitionTimingFunction] = easing; 20274 }, 20275 20276 refresh: function () { 20277 this.transitionTime(); 20278 20279 if ( this.options.listenX && !this.options.listenY ) { 20280 this.indicatorStyle.display = this.scroller.hasHorizontalScroll ? 'block' : 'none'; 20281 } else if ( this.options.listenY && !this.options.listenX ) { 20282 this.indicatorStyle.display = this.scroller.hasVerticalScroll ? 'block' : 'none'; 20283 } else { 20284 this.indicatorStyle.display = this.scroller.hasHorizontalScroll || this.scroller.hasVerticalScroll ? 'block' : 'none'; 20285 } 20286 20287 if ( this.scroller.hasHorizontalScroll && this.scroller.hasVerticalScroll ) { 20288 utils.addClass(this.wrapper, 'iScrollBothScrollbars'); 20289 utils.removeClass(this.wrapper, 'iScrollLoneScrollbar'); 20290 20291 if ( this.options.defaultScrollbars && this.options.customStyle ) { 20292 if ( this.options.listenX ) { 20293 this.wrapper.style.right = '8px'; 20294 } else { 20295 this.wrapper.style.bottom = '8px'; 20296 } 20297 } 20298 } else { 20299 utils.removeClass(this.wrapper, 'iScrollBothScrollbars'); 20300 utils.addClass(this.wrapper, 'iScrollLoneScrollbar'); 20301 20302 if ( this.options.defaultScrollbars && this.options.customStyle ) { 20303 if ( this.options.listenX ) { 20304 this.wrapper.style.right = '2px'; 20305 } else { 20306 this.wrapper.style.bottom = '2px'; 20307 } 20308 } 20309 } 20310 20311 var r = this.wrapper.offsetHeight; // force refresh 20312 20313 if ( this.options.listenX ) {
20314 this.wrapperWidth = this.wrapper.clientWidth; 20315 if ( this.options.resize ) { 20316 this.indicatorWidth = Math.max(Math.round(this.wrapperWidth * this.wrapperWidth / (this.scroller.scrollerWidth || this.wrapperWidth || 1)), 8); 20317 this.indicatorStyle.width = this.indicatorWidth + 'px'; 20318 } else { 20319 this.indicatorWidth = this.indicator.clientWidth; 20320 } 20321 20322 this.maxPosX = this.wrapperWidth - this.indicatorWidth; 20323 20324 if ( this.options.shrink == 'clip' ) { 20325 this.minBoundaryX = -this.indicatorWidth + 8; 20326 this.maxBoundaryX = this.wrapperWidth - 8; 20327 } else { 20328 this.minBoundaryX = 0; 20329 this.maxBoundaryX = this.maxPosX; 20330 } 20331 20332 this.sizeRatioX = this.options.speedRatioX || (this.scroller.maxScrollX && (this.maxPosX / this.scroller.maxScrollX)); 20333 } 20334 20335 if ( this.options.listenY ) { 20336 this.wrapperHeight = this.wrapper.clientHeight; 20337 if ( this.options.resize ) { 20338 this.indicatorHeight = Math.max(Math.round(this.wrapperHeight * this.wrapperHeight / (this.scroller.scrollerHeight || this.wrapperHeight || 1)), 8); 20339 this.indicatorStyle.height = this.indicatorHeight + 'px'; 20340 } else { 20341 this.indicatorHeight = this.indicator.clientHeight; 20342 } 20343 20344 this.maxPosY = this.wrapperHeight - this.indicatorHeight; 20345 20346 if ( this.options.shrink == 'clip' ) { 20347 this.minBoundaryY = -this.indicatorHeight + 8; 20348 this.maxBoundaryY = this.wrapperHeight - 8; 20349 } else { 20350 this.minBoundaryY = 0; 20351 this.maxBoundaryY = this.maxPosY; 20352 } 20353 20354 this.maxPosY = this.wrapperHeight - this.indicatorHeight; 20355 this.sizeRatioY = this.options.speedRatioY || (this.scroller.maxScrollY && (this.maxPosY / this.scroller.maxScrollY)); 20356 } 20357 20358 this.updatePosition(); 20359 }, 20360 20361 updatePosition: function () { 20362 var x = this.options.listenX && Math.round(this.sizeRatioX * this.scroller.x) || 0, 20363 y = this.options.listenY && Math.round(this.sizeRatioY * this.scroller.y) || 0; 20364 20365 if ( !this.options.ignoreBoundaries ) { 20366 if ( x < this.minBoundaryX ) { 20367 if ( this.options.shrink == 'scale' ) { 20368 this.width = Math.max(this.indicatorWidth + x, 8); 20369 this.indicatorStyle.width = this.width + 'px'; 20370 } 20371 x = this.minBoundaryX; 20372 } else if ( x > this.maxBoundaryX ) { 20373 if ( this.options.shrink == 'scale' ) { 20374 this.width = Math.max(this.indicatorWidth - (x - this.maxPosX), 8); 20375 this.indicatorStyle.width = this.width + 'px'; 20376 x = this.maxPosX + this.indicatorWidth - this.width; 20377 } else { 20378 x = this.maxBoundaryX; 20379 } 20380 } else if ( this.options.shrink == 'scale' && this.width != this.indicatorWidth ) { 20381 this.width = this.indicatorWidth; 20382 this.indicatorStyle.width = this.width + 'px'; 20383 } 20384 20385 if ( y < this.minBoundaryY ) { 20386 if ( this.options.shrink == 'scale' ) { 20387 this.height = Math.max(this.indicatorHeight + y * 3, 8); 20388 this.indicatorStyle.height = this.height + 'px'; 20389 } 20390 y = this.minBoundaryY; 20391 } else if ( y > this.maxBoundaryY ) { 20392 if ( this.options.shrink == 'scale' ) { 20393 this.height = Math.max(this.indicatorHeight - (y - this.maxPosY) * 3, 8); 20394 this.indicatorStyle.height = this.height + 'px'; 20395 y = this.maxPosY + this.indicatorHeight - this.height; 20396 } else { 20397 y = this.maxBoundaryY; 20398 } 20399 } else if ( this.options.shrink == 'scale' && this.height != this.indicatorHeight ) { 20400 this.height = this.indicatorHeight; 20401 this.indicatorStyle.height = this.height + 'px'; 20402 } 20403 } 20404 20405 this.x = x; 20406 this.y = y; 20407 20408 if ( this.scroller.options.useTransform ) { 20409 this.indicatorStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.scroller.translateZ; 20410 } else { 20411 this.indicatorStyle.left = x + 'px'; 20412 this.indicatorStyle.top = y + 'px'; 20413 } 20414 }, 20415 20416 _pos: function (x, y) { 20417 if ( x < 0 ) { 20418 x = 0; 20419 } else if ( x > this.maxPosX ) { 20420 x = this.maxPosX; 20421 } 20422 20423 if ( y < 0 ) { 20424 y = 0; 20425 } else if ( y > this.maxPosY ) { 20426 y = this.maxPosY;
20427 } 20428 20429 x = this.options.listenX ? Math.round(x / this.sizeRatioX) : this.scroller.x; 20430 y = this.options.listenY ? Math.round(y / this.sizeRatioY) : this.scroller.y; 20431 20432 this.scroller.scrollTo(x, y); 20433 }, 20434 20435 fade: function (val, hold) { 20436 if ( hold && !this.visible ) { 20437 return; 20438 } 20439 20440 clearTimeout(this.fadeTimeout); 20441 this.fadeTimeout = null; 20442 20443 var time = val ? 250 : 500, 20444 delay = val ? 0 : 300; 20445 20446 val = val ? '1' : '0'; 20447 20448 this.wrapperStyle[utils.style.transitionDuration] = time + 'ms'; 20449 20450 this.fadeTimeout = setTimeout((function (val) { 20451 this.wrapperStyle.opacity = val; 20452 this.visible = +val; 20453 }).bind(this, val), delay); 20454 } 20455}; 20456 20457IScroll.utils = utils; 20458 20459if ( typeof module != 'undefined' && module.exports ) { 20460 module.exports = IScroll; 20461} else if ( typeof define == 'function' && define.amd ) { 20462 define( function () { return IScroll; } ); 20463} else { 20464 window.IScroll = IScroll; 20465} 20466 20467})(window, document, Math); 20468/*! 20469 * fullPage 2.9.4 20470 * https://github.com/alvarotrigo/fullPage.js 20471 * @license MIT licensed 20472 * 20473 * Copyright (C) 2015 alvarotrigo.com - A project by Alvaro Trigo 20474 */ 20475(function(global, factory) { 20476 'use strict'; 20477 if (typeof define === 'function' && define.amd) { 20478 define(['jquery'], function($) { 20479 return factory($, global, global.document, global.Math); 20480 }); 20481 } else if (typeof exports === "object" && exports) { 20482 module.exports = factory(require('jquery'), global, global.document, global.Math); 20483 } else { 20484 factory(jQuery, global, global.document, global.Math); 20485 } 20486})(typeof window !== 'undefined' ? window : this, function($, window, document, Math, undefined) { 20487 'use strict'; 20488 20489 // keeping central set of classnames and selectors 20490 var WRAPPER = 'fullpage-wrapper'; 20491 var WRAPPER_SEL = '.' + WRAPPER; 20492 20493 // slimscroll 20494 var SCROLLABLE = 'fp-scrollable'; 20495 var SCROLLABLE_SEL = '.' + SCROLLABLE; 20496 20497 // util 20498 var RESPONSIVE = 'fp-responsive'; 20499 var NO_TRANSITION = 'fp-notransition'; 20500 var DESTROYED = 'fp-destroyed'; 20501 var ENABLED = 'fp-enabled'; 20502 var VIEWING_PREFIX = 'fp-viewing'; 20503 var ACTIVE = 'active'; 20504 var ACTIVE_SEL = '.' + ACTIVE; 20505 var COMPLETELY = 'fp-completely'; 20506 var COMPLETELY_SEL = '.' + COMPLETELY; 20507 20508 // section 20509 var SECTION_DEFAULT_SEL = '.section'; 20510 var SECTION = 'fp-section'; 20511 var SECTION_SEL = '.' + SECTION; 20512 var SECTION_ACTIVE_SEL = SECTION_SEL + ACTIVE_SEL; 20513 var SECTION_FIRST_SEL = SECTION_SEL + ':first'; 20514 var SECTION_LAST_SEL = SECTION_SEL + ':last'; 20515 var TABLE_CELL = 'fp-tableCell'; 20516 var TABLE_CELL_SEL = '.' + TABLE_CELL; 20517 var AUTO_HEIGHT = 'fp-auto-height'; 20518 var AUTO_HEIGHT_SEL = '.fp-auto-height'; 20519 var NORMAL_SCROLL = 'fp-normal-scroll'; 20520 var NORMAL_SCROLL_SEL = '.fp-normal-scroll'; 20521 20522 // section nav 20523 var SECTION_NAV = 'fp-nav'; 20524 var SECTION_NAV_SEL = '#' + SECTION_NAV; 20525 var SECTION_NAV_TOOLTIP = 'fp-tooltip'; 20526 var SECTION_NAV_TOOLTIP_SEL='.'+SECTION_NAV_TOOLTIP; 20527 var SHOW_ACTIVE_TOOLTIP = 'fp-show-active'; 20528 20529 // slide 20530 var SLIDE_DEFAULT_SEL = '.slide'; 20531 var SLIDE = 'fp-slide'; 20532 var SLIDE_SEL = '.' + SLIDE; 20533 var SLIDE_ACTIVE_SEL = SLIDE_SEL + ACTIVE_SEL; 20534 var SLIDES_WRAPPER = 'fp-slides'; 20535 var SLIDES_WRAPPER_SEL = '.' + SLIDES_WRAPPER; 20536 var SLIDES_CONTAINER = 'fp-slidesContainer'; 20537 var SLIDES_CONTAINER_SEL = '.' + SLIDES_CONTAINER; 20538 var TABLE = 'fp-table'; 20539 20540 // slide nav 20541 var SLIDES_NAV = 'fp-slidesNav'; 20542 var SLIDES_NAV_SEL = '.' + SLIDES_NAV; 20543 var SLIDES_NAV_LINK_SEL = SLIDES_NAV_SEL + ' a'; 20544 var SLIDES_ARROW = 'fp-controlArrow'; 20545 var SLIDES_ARROW_SEL = '.' + SLIDES_ARROW; 20546 var SLIDES_PREV = 'fp-prev'; 20547 var SLIDES_PREV_SEL = '.' + SLIDES_PREV; 20548 var SLIDES_ARROW_PREV = SLIDES_ARROW + ' ' + SLIDES_PREV; 20549 var SLIDES_ARROW_PREV_SEL = SLIDES_ARROW_SEL + SLIDES_PREV_SEL; 20550 var SLIDES_NEXT = 'fp-next';
20551 var SLIDES_NEXT_SEL = '.' + SLIDES_NEXT; 20552 var SLIDES_ARROW_NEXT = SLIDES_ARROW + ' ' + SLIDES_NEXT; 20553 var SLIDES_ARROW_NEXT_SEL = SLIDES_ARROW_SEL + SLIDES_NEXT_SEL; 20554 20555 var $window = $(window); 20556 var $document = $(document); 20557 20558 // Default options for iScroll.js used when using scrollOverflow 20559 var iscrollOptions = { 20560 scrollbars: true, 20561 mouseWheel: true, 20562 hideScrollbars: false, 20563 fadeScrollbars: false, 20564 disableMouse: true, 20565 interactiveScrollbars: true, 20566 bounce: false, 20567 }; 20568 20569 $.fn.fullpage = function(options) { 20570 //only once my friend! 20571 if($('html').hasClass(ENABLED)){ displayWarnings(); return; } 20572 20573 // common jQuery objects 20574 var $htmlBody = $('html, body'); 20575 var $body = $('body'); 20576 20577 var FP = $.fn.fullpage; 20578 20579 // Creating some defaults, extending them with any options that were provided 20580 options = $.extend({ 20581 //navigation 20582 menu: false, 20583 anchors:[], 20584 lockAnchors: false, 20585 navigation: false, 20586 navigationPosition: 'right', 20587 navigationTooltips: [], 20588 showActiveTooltip: false, 20589 slidesNavigation: false, 20590 slidesNavPosition: 'bottom', 20591 scrollBar: false, 20592 hybrid: false, 20593 20594 //scrolling 20595 css3: true, 20596 scrollingSpeed: 700, 20597 autoScrolling: true, 20598 fitToSection: true, 20599 fitToSectionDelay: 1000, 20600 easing: 'easeInOutCubic', 20601 easingcss3: 'ease', 20602 loopBottom: false, 20603 loopTop: false, 20604 loopHorizontal: true, 20605 continuousVertical: false, 20606 continuousHorizontal: false, 20607 scrollHorizontally: false, 20608 interlockedSlides: false, 20609 dragAndMove: false, 20610 offsetSections: false, 20611 resetSliders: false, 20612 fadingEffect: false, 20613 normalScrollElements: null, 20614 scrollOverflow: false, 20615 scrollOverflowReset: false, 20616 scrollOverflowHandler: iscrollHandler, 20617 scrollOverflowOptions: null, 20618 touchSensitivity: 5, 20619 normalScrollElementTouchThreshold: 5, 20620 bigSectionsDestination: null, 20621 20622 //Accessibility 20623 keyboardScrolling: true, 20624 animateAnchor: true, 20625 recordHistory: true, 20626 20627 //design 20628 controlArrows: true, 20629 controlArrowColor: '#fff', 20630 verticalCentered: true, 20631 sectionsColor : [], 20632 paddingTop: 0, 20633 paddingBottom: 0, 20634 fixedElements: null, 20635 responsive: 0, //backwards compabitility with responsiveWiddth 20636 responsiveWidth: 0, 20637 responsiveHeight: 0, 20638 responsiveSlides: false, 20639 parallax: false, 20640 parallaxOptions: { 20641 type: 'reveal', 20642 percentage: 62, 20643 property: 'translate' 20644 }, 20645 20646 //Custom selectors 20647 sectionSelector: SECTION_DEFAULT_SEL, 20648 slideSelector: SLIDE_DEFAULT_SEL, 20649 20650 //events 20651 afterLoad: null, 20652 onLeave: null, 20653 afterRender: null, 20654 afterResize: null, 20655 afterReBuild: null, 20656 afterSlideLoad: null, 20657 onSlideLeave: null, 20658 afterResponsive: null, 20659 20660 lazyLoading: true 20661 }, options); 20662 20663 //flag to avoid very fast sliding for landscape sliders 20664 var slideMoving = false; 20665 20666 var isTouchDevice = navigator.userAgent.match(/(iPhone|iPod|iPad|Android|playbook|silk|BlackBerry|BB10|Windows Phone|Tizen|Bada|webOS|IEMobile|Opera Mini)/); 20667 var isTouch = (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0) || (navigator.maxTouchPoints)); 20668 var container = $(this); 20669 var windowsHeight = $window.height(); 20670 var isResizing = false; 20671 var isWindowFocused = true; 20672 var lastScrolledDestiny; 20673 var lastScrolledSlide; 20674 var canScroll = true; 20675 var scrollings = []; 20676 var controlPressed; 20677 var startingSection; 20678 var isScrollAllowed = {}; 20679 isScrollAllowed.m = { 'up':true, 'down':true, 'left':true, 'right':true }; 20680 isScrollAllowed.k = $.extend(true,{}, isScrollAllowed.m); 20681 var MSPointer = getMSPointer(); 20682 var events = { 20683 touchmove: 'ontouchmove' in window ? 'touchmove' : MSPointer.move, 20684 touchstart: 'ontouchstart' in window ? 'touchstart' : MSPointer.down 20685 }; 20686 20687 //cheks for passive event support 20688 //added by Uncode from new fullPage updates 20689 var g_supportsPassive = false;
20690 try { 20691 var opts = Object.defineProperty({}, 'passive', { 20692 get: function() { 20693 g_supportsPassive = true; 20694 } 20695 }); 20696 window.addEventListener("testPassive", null, opts); 20697 window.removeEventListener("testPassive", null, opts); 20698 } catch (e) {} 20699 20700 //timeouts 20701 var resizeId; 20702 var afterSectionLoadsId; 20703 var afterSlideLoadsId; 20704 var scrollId; 20705 var scrollId2; 20706 var keydownId; 20707 var originals = $.extend(true, {}, options); //deep copy 20708 20709 //Uncode addition 20710 var $masthead = $('#masthead'); 20711 var hideMenu = !$('body').hasClass('vmenu') && $('body').hasClass('uncode-fp-menu-hide') ? true : false; 20712 var menuHeight = $masthead.hasClass('menu-transparent') || hideMenu ? 0 : UNCODE.menuHeight; 20713 var bodyBorder = UNCODE.bodyBorder; 20714 var adminBarHeight = UNCODE.adminBarHeight; 20715 20716 displayWarnings(); 20717 20718 //fixing bug in iScroll with links: https://github.com/cubiq/iscroll/issues/783 20719 iscrollOptions.click = isTouch; // see #2035 20720 20721 //extending iScroll options with the user custom ones 20722 iscrollOptions = $.extend(iscrollOptions, options.scrollOverflowOptions); 20723 20724 //easeInOutCubic animation included in the plugin 20725 $.extend($.easing,{ easeInOutCubic: function (x, t, b, c, d) {if ((t/=d/2) < 1) return c/2*t*t*t + b;return c/2*((t-=2)*t*t + 2) + b;}}); 20726 20727 /** 20728 * Sets the autoScroll option. 20729 * It changes the scroll bar visibility and the history of the site as a result. 20730 */ 20731 function setAutoScrolling(value, type){ 20732 //removing the transformation 20733 if(!value){ 20734 silentScroll(0); 20735 } 20736 20737 setVariableState('autoScrolling', value, type); 20738 20739 var element = $(SECTION_ACTIVE_SEL); 20740 20741 if(options.autoScrolling && !options.scrollBar){ 20742 $htmlBody.css({ 20743 'overflow' : 'hidden !important', 20744 'height' : '100%' 20745 }); 20746 20747 //Uncode addition 20748 //setRecordHistory(originals.recordHistory, 'internal'); 20749 20750 //for IE touch devices 20751 container.css({ 20752 '-ms-touch-action': 'none', 20753 'touch-action': 'none' 20754 }); 20755 20756 if(element.length){ 20757 //moving the container up 20758 silentScroll(element.position().top); 20759 } 20760 20761 }else{ 20762 $htmlBody.css({ 20763 'overflow' : 'visible !important', 20764 'height' : 'initial' 20765 }); 20766 20767 //Uncode addition 20768 //setRecordHistory(false, 'internal'); 20769 20770 //for IE touch devices 20771 container.css({ 20772 '-ms-touch-action': '', 20773 'touch-action': '' 20774 }); 20775 20776 //scrolling the page to the section with no animation 20777 if (element.length) { 20778 $htmlBody.scrollTop(element.position().top); 20779 } 20780 } 20781 } 20782 20783 /** 20784 * Defines wheter to record the history for each hash change in the URL. 20785 */ 20786 function setRecordHistory(value, type){ 20787 setVariableState('recordHistory', value, type); 20788 } 20789 20790 /** 20791 * Defines the scrolling speed 20792 */ 20793 function setScrollingSpeed(value, type){ 20794 setVariableState('scrollingSpeed', value, type); 20795 } 20796 20797 /** 20798 * Sets fitToSection 20799 */ 20800 function setFitToSection(value, type){ 20801 setVariableState('fitToSection', value, type); 20802 } 20803 20804 /** 20805 * Sets lockAnchors 20806 */ 20807 function setLockAnchors(value){ 20808 options.lockAnchors = value; 20809 } 20810 20811 /** 20812 * Adds or remove the possiblity of scrolling through sections by using the mouse wheel or the trackpad. 20813 */ 20814 function setMouseWheelScrolling(value){ 20815 if(value){ 20816 addMouseWheelHandler(); 20817 addMiddleWheelHandler(); 20818 }else{ 20819 removeMouseWheelHandler(); 20820 removeMiddleWheelHandler(); 20821 } 20822 } 20823 20824 /** 20825 * Adds or remove the possibility of scrolling through sections by using the mouse wheel/trackpad or touch gestures. 20826 * Optionally a second parameter can be used to specify the direction for which the action will be applied. 20827 * 20828 * @param directions string containing the direction or directions separated by comma. 20829 */ 20830 function setAllowScrolling(value, directions){ 20831 if(typeof directions !== 'undefined'){ 20832 directions = directions.replace(/ /g,'').split(','); 20833 20834 $.each(directions, function (index, direction){ 20835 setIsScrollAllowed(value, direction, 'm'); 20836 }); 20837 } 20838 else if(value){ 20839 setMouseWheelScrolling(true); 20840 addTouchHandler(); 20841 }else{ 20842 setMouseWheelScrolling(false); 20843 removeTouchHandler(); 20844 } 20845 } 20846 20847 /** 20848 * Adds or remove the possibility of scrolling through sections by using the keyboard arrow keys 20849 */ 20850 function setKeyboardScrolling(value, directions){ 20851 if(typeof directions !== 'undefined'){ 20852 directions = directions.replace(/ /g,'').split(','); 20853 20854 $.each(directions, function (index, direction){ 20855 setIsScrollAllowed(value, direction, 'k'); 20856 }); 20857 }else{ 20858 options.keyboardScrolling = value; 20859 } 20860 } 20861 20862 /** 20863 * Moves the page up one section. 20864 */ 20865 function moveSectionUp(){ 20866 var prev = $(SECTION_ACTIVE_SEL).prev(SECTION_SEL); 20867 20868 //looping to the bottom if there's no more sections above 20869 if (!prev.length && (options.loopTop || options.continuousVertical)) {
20870 prev = $(SECTION_SEL).last(); 20871 } 20872 20873 if (prev.length) { 20874 scrollPage(prev, null, true); 20875 } 20876 } 20877 20878 /** 20879 * Moves the page down one section. 20880 */ 20881 function moveSectionDown(){ 20882 var next = $(SECTION_ACTIVE_SEL).next(SECTION_SEL); 20883 20884 //looping to the top if there's no more sections below 20885 if(!next.length && 20886 (options.loopBottom || options.continuousVertical)){ 20887 next = $(SECTION_SEL).first(); 20888 } 20889 20890 if(next.length){ 20891 scrollPage(next, null, false); 20892 } 20893 } 20894 20895 /** 20896 * Moves the page to the given section and slide with no animation. 20897 * Anchors or index positions can be used as params. 20898 */ 20899 function silentMoveTo(sectionAnchor, slideAnchor){ 20900 setScrollingSpeed (0, 'internal'); 20901 moveTo(sectionAnchor, slideAnchor); 20902 setScrollingSpeed (originals.scrollingSpeed, 'internal'); 20903 } 20904 20905 /** 20906 * Moves the page to the given section and slide. 20907 * Anchors or index positions can be used as params. 20908 */ 20909 function moveTo(sectionAnchor, slideAnchor){ 20910 var destiny = getSectionByAnchor(sectionAnchor); 20911 20912 if (typeof slideAnchor !== 'undefined'){ 20913 scrollPageAndSlide(sectionAnchor, slideAnchor); 20914 }else if(destiny.length > 0){ 20915 scrollPage(destiny); 20916 } 20917 } 20918 20919 /** 20920 * Slides right the slider of the active section. 20921 * Optional `section` param. 20922 */ 20923 function moveSlideRight(section){ 20924 moveSlide('right', section); 20925 } 20926 20927 /** 20928 * Slides left the slider of the active section. 20929 * Optional `section` param. 20930 */ 20931 function moveSlideLeft(section){ 20932 moveSlide('left', section); 20933 } 20934 20935 /** 20936 * When resizing is finished, we adjust the slides sizes and positions 20937 */ 20938 function reBuild(resizing){ 20939 if(container.hasClass(DESTROYED)){ return; } //nothing to do if the plugin was destroyed 20940 20941 isResizing = true; 20942 20943 windowsHeight = $window.height(); //updating global var 20944 20945 $(SECTION_SEL).each(function(){ 20946 var slidesWrap = $(this).find(SLIDES_WRAPPER_SEL); 20947 var slides = $(this).find(SLIDE_SEL); 20948 20949 //adjusting the height of the table-cell for IE and Firefox 20950 if(options.verticalCentered){ 20951 $(this).find(TABLE_CELL_SEL).css('height', getTableHeight($(this)) + 'px'); 20952 } 20953 20954 $(this).css('height', windowsHeight + 'px'); 20955 20956 //resizing the scrolling divs 20957 if(options.scrollOverflow){ 20958 if(slides.length){ 20959 slides.each(function(){ 20960 createScrollBar($(this)); 20961 }); 20962 }else{ 20963 createScrollBar($(this)); 20964 } 20965 } 20966 20967 //adjusting the position fo the FULL WIDTH slides... 20968 if (slides.length > 1) { 20969 landscapeScroll(slidesWrap, slidesWrap.find(SLIDE_ACTIVE_SEL)); 20970 } 20971 }); 20972 20973 var activeSection = $(SECTION_ACTIVE_SEL); 20974 var sectionIndex = activeSection.index(SECTION_SEL); 20975 20976 //isn't it the first section? 20977 if(sectionIndex){ 20978 //adjusting the position for the current section 20979 silentMoveTo(sectionIndex + 1); 20980 } 20981 20982 isResizing = false; 20983 $.isFunction( options.afterResize ) && resizing && options.afterResize.call(container); 20984 $.isFunction( options.afterReBuild ) && !resizing && options.afterReBuild.call(container); 20985 } 20986 20987 /** 20988 * Turns fullPage.js to normal scrolling mode when the viewport `width` or `height` 20989 * are smaller than the set limit values. 20990 */ 20991 function setResponsive(active){ 20992 var isResponsive = $body.hasClass(RESPONSIVE); 20993 20994 if(active){ 20995 if(!isResponsive){ 20996 setAutoScrolling(false, 'internal'); 20997 setFitToSection(false, 'internal'); 20998 $(SECTION_NAV_SEL).hide(); 20999 $body.addClass(RESPONSIVE); 21000 $.isFunction( options.afterResponsive ) && options.afterResponsive.call( container, active); 21001 } 21002 } 21003 else if(isResponsive){ 21004 setAutoScrolling(originals.autoScrolling, 'internal'); 21005 setFitToSection(originals.autoScrolling, 'internal'); 21006 $(SECTION_NAV_SEL).show(); 21007 $body.removeClass(RESPONSIVE); 21008 $.isFunction( options.afterResponsive ) && options.afterResponsive.call( container, active); 21009 } 21010 } 21011 21012 if($(this).length){ 21013 //public functions 21014 FP.setAutoScrolling = setAutoScrolling; 21015 FP.setRecordHistory = setRecordHistory; 21016 FP.setScrollingSpeed = setScrollingSpeed; 21017 FP.setFitToSection = setFitToSection; 21018 FP.setLockAnchors = setLockAnchors; 21019 FP.setMouseWheelScrolling = setMouseWheelScrolling; 21020 FP.setAllowScrolling = setAllowScrolling; 21021 FP.setKeyboardScrolling = setKeyboardScrolling; 21022 FP.moveSectionUp = moveSectionUp; 21023 FP.moveSectionDown = moveSectionDown; 21024 FP.silentMoveTo = silentMoveTo; 21025 FP.moveTo = moveTo; 21026 FP.moveSlideRight = moveSlideRight; 21027 FP.moveSlideLeft = moveSlideLeft; 21028 FP.fitToSection = fitToSection; 21029 FP.reBuild = reBuild; 21030 FP.setResponsive = setResponsive; 21031 FP.destroy = destroy; 21032 21033 init(); 21034 21035 bindEvents(); 21036 } 21037
21038 function init(){ 21039 //if css3 is not supported, it will use jQuery animations 21040 if(options.css3){ 21041 options.css3 = support3d(); 21042 } 21043 21044 options.scrollBar = options.scrollBar || options.hybrid; 21045 21046 setOptionsFromDOM(); 21047 prepareDom(); 21048 setAllowScrolling(true); 21049 setAutoScrolling(options.autoScrolling, 'internal'); 21050 responsive(); 21051 21052 //setting the class for the body element 21053 setBodyClass(); 21054 21055 //Uncode addition 21056 // if(document.readyState === 'complete'){ 21057 // scrollToAnchor(); 21058 // } 21059 // $window.on('load', scrollToAnchor); 21060 } 21061 21062 function bindEvents(){ 21063 $window 21064 //when scrolling... 21065 //.on('scroll', scrollHandler) 21066 21067 //detecting any change on the URL to scroll to the given anchor link 21068 //(a way to detect back history button as we play with the hashes on the URL) 21069 .on('hashchange', hashChangeHandler) 21070 21071 //when opening a new tab (ctrl + t), `control` won't be pressed when coming back. 21072 .blur(blurHandler) 21073 21074 //when resizing the site, we adjust the heights of the sections, slimScroll... 21075 .resize(resizeHandler); 21076 21077 $document 21078 //Sliding with arrow keys, both, vertical and horizontal 21079 .keydown(keydownHandler) 21080 21081 //to prevent scrolling while zooming 21082 .keyup(keyUpHandler) 21083 21084 //Scrolls to the section when clicking the navigation bullet 21085 .on('click touchstart', SECTION_NAV_SEL + ' a', sectionBulletHandler) 21086 21087 //Scrolls the slider to the given slide destination for the given section 21088 .on('click touchstart', SLIDES_NAV_LINK_SEL, slideBulletHandler) 21089 21090 .on('click', SECTION_NAV_TOOLTIP_SEL, tooltipTextHandler); 21091 21092 //Scrolling horizontally when clicking on the slider controls. 21093 $(SECTION_SEL).on('click touchstart', SLIDES_ARROW_SEL, slideArrowHandler); 21094 21095 /** 21096 * Applying normalScroll elements. 21097 * Ignoring the scrolls over the specified selectors. 21098 */ 21099 if(options.normalScrollElements){ 21100 $document.on('mouseenter', options.normalScrollElements, function () { 21101 setMouseWheelScrolling(false); 21102 }); 21103 21104 $document.on('mouseleave', options.normalScrollElements, function(){ 21105 setMouseWheelScrolling(true); 21106 }); 21107 } 21108 } 21109 21110 /** 21111 * Setting options from DOM elements if they are not provided. 21112 */ 21113 function setOptionsFromDOM(){ 21114 var sections = container.find(options.sectionSelector); 21115 21116 //no anchors option? Checking for them in the DOM attributes 21117 if(!options.anchors.length){ 21118 options.anchors = sections.filter('[data-anchor]').map(function(){ 21119 return $(this).data('anchor').toString(); 21120 }).get(); 21121 } 21122 21123 //no tooltips option? Checking for them in the DOM attributes 21124 if(!options.navigationTooltips.length){ 21125 options.navigationTooltips = sections.filter('[data-tooltip]').map(function(){ 21126 return $(this).data('tooltip').toString(); 21127 }).get(); 21128 } 21129 } 21130 21131 /** 21132 * Works over the DOM structure to set it up for the current fullpage options. 21133 */ 21134 function prepareDom(){ 21135 container.css({ 21136 'height': '100%', 21137 'position': 'relative' 21138 }); 21139 21140 //adding a class to recognize the container internally in the code 21141 container.addClass(WRAPPER); 21142 $('html').addClass(ENABLED); 21143 21144 windowsHeight = $window.height(); 21145 21146 container.removeClass(DESTROYED); //in case it was destroyed before initializing it again 21147 21148 addInternalSelectors(); 21149 21150 //styling the sections / slides / menu 21151 $(SECTION_SEL).each(function(index){ 21152 var section = $(this); 21153 var slides = section.find(SLIDE_SEL); 21154 var numSlides = slides.length; 21155 21156 styleSection(section, index); 21157 styleMenu(section, index); 21158 21159 // if there's any slide 21160 if (numSlides > 0) { 21161 styleSlides(section, slides, numSlides); 21162 }else{ 21163 if(options.verticalCentered){ 21164 addTableClass(section); 21165 } 21166 } 21167 }); 21168 21169 //fixed elements need to be moved out of the plugin container due to problems with CSS3. 21170 if(options.fixedElements && options.css3){ 21171 $(options.fixedElements).appendTo($body); 21172 } 21173 21174 //vertical centered of the navigation + active bullet 21175 if(options.navigation){ 21176 addVerticalNavigation(); 21177 } 21178 21179 enableYoutubeAPI(); 21180 21181 if(options.scrollOverflow){ 21182 if(document.readyState === 'complete'){ 21183 createScrollBarHandler(); 21184 } 21185 //after DOM and images are loaded 21186 $window.on('load', createScrollBarHandler); 21187 }else{ 21188 afterRenderActions(); 21189 } 21190 } 21191 21192 /** 21193 * Styles the horizontal slides for a section. 21194 */ 21195 function styleSlides(section, slides, numSlides){ 21196 var sliderWidth = numSlides * 100; 21197 var slideWidth = 100 / numSlides; 21198 21199 slides.wrapAll('<div class="' + SLIDES_CONTAINER + '" />'); 21200 slides.parent().wrap('<div class="' + SLIDES_WRAPPER + '" />'); 21201 21202 section.find(SLIDES_CONTAINER_SEL).css('width', sliderWidth + '%'); 21203 21204 if(numSlides > 1){ 21205 if(options.controlArrows){ 21206 createSlideArrows(section); 21207 } 21208 21209 if(options.slidesNavigation){ 21210 addSlidesNavigation(section, numSlides); 21211 } 21212 } 21213 21214 slides.each(function(index) { 21215 $(this).css('width', slideWidth + '%'); 21216 21217 if(options.verticalCentered){ 21218 addTableClass($(this)); 21219 } 21220 }); 21221 21222 var startingSlide = section.find(SLIDE_ACTIVE_SEL); 21223 21224 //if the slide won't be an starting point, the default will be the first one 21225 //the active section isn't the first one? Is not the first slide of the first section? Then we load that section/sl
21225ide by default. 21226 if( startingSlide.length && ($(SECTION_ACTIVE_SEL).index(SECTION_SEL) !== 0 || ($(SECTION_ACTIVE_SEL).index(SECTION_SEL) === 0 && startingSlide.index() !== 0))){ 21227 silentLandscapeScroll(startingSlide, 'internal'); 21228 }else{ 21229 slides.eq(0).addClass(ACTIVE); 21230 } 21231 } 21232 21233 /** 21234 * Styling vertical sections 21235 */ 21236 function styleSection(section, index){ 21237 //if no active section is defined, the 1st one will be the default one 21238 if(!index && $(SECTION_ACTIVE_SEL).length === 0) { 21239 section.addClass(ACTIVE); 21240 } 21241 startingSection = $(SECTION_ACTIVE_SEL); 21242 21243 section.css('height', windowsHeight + 'px'); 21244 21245 if(options.paddingTop){ 21246 section.css('padding-top', options.paddingTop); 21247 } 21248 21249 if(options.paddingBottom){ 21250 section.css('padding-bottom', options.paddingBottom); 21251 } 21252 21253 if (typeof options.sectionsColor[index] !== 'undefined') { 21254 section.css('background-color', options.sectionsColor[index]); 21255 } 21256 21257 if (typeof options.anchors[index] !== 'undefined') { 21258 section.attr('data-anchor', options.anchors[index]); 21259 } 21260 } 21261 21262 /** 21263 * Sets the data-anchor attributes to the menu elements and activates the current one. 21264 */ 21265 function styleMenu(section, index){ 21266 if (typeof options.anchors[index] !== 'undefined') { 21267 //activating the menu / nav element on load 21268 if(section.hasClass(ACTIVE)){ 21269 activateMenuAndNav(options.anchors[index], index); 21270 } 21271 } 21272 21273 //moving the menu outside the main container if it is inside (avoid problems with fixed positions when using CSS3 tranforms) 21274 if(options.menu && options.css3 && $(options.menu).closest(WRAPPER_SEL).length){ 21275 $(options.menu).appendTo($body); 21276 } 21277 } 21278 21279 /** 21280 * Adds internal classes to be able to provide customizable selectors 21281 * keeping the link with the style sheet. 21282 */ 21283 function addInternalSelectors(){ 21284 container.find(options.sectionSelector).addClass(SECTION); 21285 container.find(options.slideSelector).addClass(SLIDE); 21286 } 21287 21288 /** 21289 * Creates the control arrows for the given section 21290 */ 21291 function createSlideArrows(section){ 21292 section.find(SLIDES_WRAPPER_SEL).after('<div class="' + SLIDES_ARROW_PREV + '"></div><div class="' + SLIDES_ARROW_NEXT + '"></div>'); 21293 21294 if(options.controlArrowColor!='#fff'){ 21295 section.find(SLIDES_ARROW_NEXT_SEL).css('border-color', 'transparent transparent transparent '+options.controlArrowColor); 21296 section.find(SLIDES_ARROW_PREV_SEL).css('border-color', 'transparent '+ options.controlArrowColor + ' transparent transparent'); 21297 } 21298 21299 if(!options.loopHorizontal){ 21300 section.find(SLIDES_ARROW_PREV_SEL).hide(); 21301 } 21302 } 21303 21304 /** 21305 * Creates a vertical navigation bar. 21306 */ 21307 function addVerticalNavigation(){ 21308 $body.append('<div id="' + SECTION_NAV + '"><ul></ul></div>'); 21309 var nav = $(SECTION_NAV_SEL); 21310 21311 nav.addClass(function() { 21312 return options.showActiveTooltip ? SHOW_ACTIVE_TOOLTIP + ' ' + options.navigationPosition : options.navigationPosition; 21313 }); 21314 21315 for (var i = 0; i < $(SECTION_SEL).length; i++) { 21316 var link = ''; 21317 if (options.anchors.length) { 21318 link = options.anchors[i]; 21319 } 21320 21321 var li = '<li><a href="#' + link + '"><span></span></a>'; 21322 21323 // Only add tooltip if needed (defined by user) 21324 var tooltip = options.navigationTooltips[i]; 21325 21326 if (typeof tooltip !== 'undefined' && tooltip !== '') { 21327 li += '<div class="' + SECTION_NAV_TOOLTIP + ' ' + options.navigationPosition + '">' + tooltip + '</div>'; 21328 } 21329 21330 li += '</li>'; 21331 21332 nav.find('ul').append(li); 21333 } 21334 21335 //centering it vertically 21336 $(SECTION_NAV_SEL).css('margin-top', '-' + ($(SECTION_NAV_SEL).height()/2) + 'px'); 21337 21338 //activating the current active section 21339 $(SECTION_NAV_SEL).find('li').eq($(SECTION_ACTIVE_SEL).index(SECTION_SEL)).find('a').addClass(ACTIVE); 21340 } 21341 21342 /** 21343 * Creates the slim scroll scrollbar for the sections and slides inside them. 21344 */ 21345 function createScrollBarHandler(){ 21346 $(SECTION_SEL).each(function(){ 21347 var slides = $(this).find(SLIDE_SEL); 21348 21349 if(slides.length){ 21350 slides.each(function(){ 21351 createScrollBar($(this)); 21352 }); 21353 }else{ 21354 createScrollBar($(this)); 21355 } 21356 21357 }); 21358 afterRenderActions(); 21359 } 21360 21361 /*
21362 * Enables the Youtube videos API so we can control their flow if necessary. 21363 */ 21364 function enableYoutubeAPI(){ 21365 container.find('iframe[src*="youtube.com/embed/"]').each(function(){ 21366 addURLParam($(this), 'enablejsapi=1'); 21367 }); 21368 } 21369 21370 /** 21371 * Adds a new parameter and its value to the `src` of a given element 21372 */ 21373 function addURLParam(element, newParam){ 21374 var originalSrc = element.attr('src'); 21375 element.attr('src', originalSrc + getUrlParamSign(originalSrc) + newParam); 21376 } 21377 21378 /* 21379 * Returns the prefix sign to use for a new parameter in an existen URL. 21380 * 21381 * @return {String} ? | & 21382 */ 21383 function getUrlParamSign(url){ 21384 return ( !/\?/.test( url ) ) ? '?' : '&'; 21385 } 21386 21387 /** 21388 * Actions and callbacks to fire afterRender 21389 */ 21390 function afterRenderActions(){ 21391 var section = $(SECTION_ACTIVE_SEL); 21392 21393 section.addClass(COMPLETELY); 21394 21395 if(options.scrollOverflowHandler.afterRender){ 21396 options.scrollOverflowHandler.afterRender(section); 21397 } 21398 lazyLoad(section); 21399 playMedia(section); 21400 options.scrollOverflowHandler.afterLoad(); 21401 21402 if(isDestinyTheStartingSection()){ 21403 $.isFunction( options.afterLoad ) && options.afterLoad.call(section, section.data('anchor'), (section.index(SECTION_SEL) + 1)); 21404 } 21405 21406 $.isFunction( options.afterRender ) && options.afterRender.call(container); 21407 } 21408 21409 /** 21410 * Determines if the URL anchor destiny is the starting section (the one using 'active' class before initialization) 21411 */ 21412 function isDestinyTheStartingSection(){ 21413 var anchors = window.location.hash.replace('#', '').split('/'); 21414 var destinationSection = getSectionByAnchor(decodeURIComponent(anchors[0])); 21415 21416 return !destinationSection.length || destinationSection.length && destinationSection.index() === startingSection.index(); 21417 } 21418 21419 21420 var isScrolling = false; 21421 var lastScroll = 0; 21422 21423 //when scrolling... 21424 function scrollHandler(){ 21425 var currentSection; 21426 21427 if(!options.autoScrolling || options.scrollBar){ 21428 var currentScroll = $window.scrollTop(); 21429 var scrollDirection = getScrollDirection(currentScroll); 21430 var visibleSectionIndex = 0; 21431 var screen_mid = currentScroll + ($window.height() / 2.0); 21432 var isAtBottom = $body.height() - $window.height() === currentScroll; 21433 var sections = document.querySelectorAll(SECTION_SEL); 21434 21435 //when using `auto-height` for a small last section it won't be centered in the viewport 21436 if(isAtBottom){ 21437 visibleSectionIndex = sections.length - 1; 21438 } 21439 //is at top? when using `auto-height` for a small first section it won't be centered in the viewport 21440 else if(!currentScroll){ 21441 visibleSectionIndex = 0; 21442 } 21443 21444 //taking the section which is showing more content in the viewport 21445 else{ 21446 for (var i = 0; i < sections.length; ++i) { 21447 var section = sections[i]; 21448 21449 // Pick the the last section which passes the middle line of the screen. 21450 if (section.offsetTop <= screen_mid) 21451 { 21452 visibleSectionIndex = i; 21453 } 21454 } 21455 } 21456 21457 if(isCompletelyInViewPort(scrollDirection)){ 21458 if(!$(SECTION_ACTIVE_SEL).hasClass(COMPLETELY)){ 21459 $(SECTION_ACTIVE_SEL).addClass(COMPLETELY).siblings().removeClass(COMPLETELY); 21460 } 21461 } 21462 21463 //geting the last one, the current one on the screen 21464 currentSection = $(sections).eq(visibleSectionIndex); 21465 21466 //setting the visible section as active when manually scrolling 21467 //executing only once the first time we reach the section 21468 if(!currentSection.hasClass(ACTIVE)){ 21469 isScrolling = true; 21470 var leavingSection = $(SECTION_ACTIVE_SEL); 21471 var leavingSectionIndex = leavingSection.index(SECTION_SEL) + 1; 21472 var yMovement = getYmovement(currentSection); 21473 var anchorLink = currentSection.data('anchor'); 21474 var sectionIndex = currentSection.index(SECTION_SEL) + 1; 21475 var activeSlide = currentSection.find(SLIDE_ACTIVE_SEL); 21476 var slideIndex; 21477 var slideAnchorLink; 21478 21479 if(activeSlide.length){ 21480 slideAnchorLink = activeSlide.data('anchor'); 21481 slideIndex = activeSlide.index(); 21482 } 21483 21484 if(canScroll){ 21485 currentSection.addClass(ACTIVE).siblings().removeClass(ACTIVE); 21486 21487 $.isFunction( options.onLeave ) && options.onLeave.call( leavingSection, leavingSectionIndex, sectionIndex, yMovement); 21488 $.isFunction( options.afterLoad ) && options.afterLoad.call( currentSection, anchorLink, sectionIndex); 21489 21490 stopMedia(leavingSection); 21491 lazyLoad(currentSection); 21492 playMedia(currentSection); 21493 21494 activateMenuAndNav(anchorLink, sectionIndex - 1); 21495 21496 if(options.anchors.length){ 21497 //needed to enter in hashChange event when using the menu with anchor links 21498 lastScrolledDestiny = anchorLink; 21499 } 21500 setState(slideIndex, slideAnchorLink, anchorLink, sectionIndex); 21501 } 21502 21503 //small timeout in order to avoid entering in hashChange event when scrolling is not finished yet 21504 clearTimeout(scrollId); 21505 scrollId = setTimeout(function(){ 21506 isScrolling = false;
21507 }, 100); 21508 } 21509 21510 if(options.fitToSection){ 21511 //for the auto adjust of the viewport to fit a whole section 21512 clearTimeout(scrollId2); 21513 21514 scrollId2 = setTimeout(function(){ 21515 //checking it again in case it changed during the delay 21516 if(options.fitToSection){ 21517 fitToSection(); 21518 } 21519 }, options.fitToSectionDelay); 21520 } 21521 } 21522 } 21523 21524 /** 21525 * Fits the site to the nearest active section 21526 */ 21527 function fitToSection(){ 21528 //checking fitToSection again in case it was set to false before the timeout delay 21529 if(canScroll){ 21530 //allows to scroll to an active section and 21531 //if the section is already active, we prevent firing callbacks 21532 isResizing = true; 21533 21534 scrollPage($(SECTION_ACTIVE_SEL)); 21535 isResizing = false; 21536 } 21537 } 21538 21539 /** 21540 * Determines whether the active section has seen in its whole or not. 21541 */ 21542 function isCompletelyInViewPort(movement){ 21543 var top = $(SECTION_ACTIVE_SEL).position().top; 21544 var bottom = top + $window.height(); 21545 21546 if(movement == 'up'){ 21547 return bottom >= ($window.scrollTop() + $window.height()); 21548 } 21549 return top <= $window.scrollTop(); 21550 } 21551 21552 /** 21553 * Gets the directon of the the scrolling fired by the scroll event. 21554 */ 21555 function getScrollDirection(currentScroll){ 21556 var direction = currentScroll > lastScroll ? 'down' : 'up'; 21557 21558 lastScroll = currentScroll; 21559 21560 //needed for auto-height sections to determine if we want to scroll to the top or bottom of the destination 21561 previousDestTop = currentScroll; 21562 21563 return direction; 21564 } 21565 21566 /** 21567 * Determines the way of scrolling up or down: 21568 * by 'automatically' scrolling a section or by using the default and normal scrolling. 21569 */ 21570 function scrolling(type, scrollable){ 21571 if (!isScrollAllowed.m[type]){ 21572 return; 21573 } 21574 var check = (type === 'down') ? 'bottom' : 'top'; 21575 var scrollSection = (type === 'down') ? moveSectionDown : moveSectionUp; 21576 21577 if(scrollable.length > 0 ){ 21578 //is the scrollbar at the start/end of the scroll? 21579 if(options.scrollOverflowHandler.isScrolled(check, scrollable)){ 21580 scrollSection(); 21581 }else{ 21582 return true; 21583 } 21584 }else{ 21585 // moved up/down 21586 scrollSection(); 21587 } 21588 } 21589 21590 /* 21591 * Preventing bouncing in iOS #2285 21592 */ 21593 function preventBouncing(event){ 21594 var e = event.originalEvent; 21595 if(!checkParentForNormalScrollElement(event.target) && options.autoScrolling && isReallyTouch(e) && isScrollAllowed.m.up){ 21596 //preventing the easing on iOS devices 21597 event.preventDefault(); 21598 } 21599 } 21600 21601 var touchStartY = 0; 21602 var touchStartX = 0; 21603 var touchEndY = 0; 21604 var touchEndX = 0; 21605 21606 /* Detecting touch events 21607 21608 * As we are changing the top property of the page on scrolling, we can not use the traditional way to detect it. 21609 * This way, the touchstart and the touch moves shows an small difference between them which is the 21610 * used one to determine the direction. 21611 */ 21612 function touchMoveHandler(event){ 21613 var e = event.originalEvent; 21614 var activeSection = $(e.target).closest(SECTION_SEL); 21615 21616 // additional: if one of the normalScrollElements isn't within options.normalScrollElementTouchThreshold hops up the DOM chain 21617 if (!checkParentForNormalScrollElement(event.target) && isReallyTouch(e) ) { 21618 21619 if(options.autoScrolling){ 21620 //preventing the easing on iOS devices 21621 event.preventDefault(); 21622 } 21623 21624 var scrollable = options.scrollOverflowHandler.scrollable(activeSection); 21625 var touchEvents = getEventsPage(e); 21626 21627 touchEndY = touchEvents.y; 21628 touchEndX = touchEvents.x; 21629 21630 //if movement in the X axys is greater than in the Y and the currect section has slides... 21631 if (activeSection.find(SLIDES_WRAPPER_SEL).length && Math.abs(touchStartX - touchEndX) > (Math.abs(touchStartY - touchEndY))) { 21632 21633 //is the movement greater than the minimum resistance to scroll? 21634 if (!slideMoving && Math.abs(touchStartX - touchEndX) > ($window.outerWidth() / 100 * options.touchSensitivity)) { 21635 if (touchStartX > touchEndX) { 21636 if(isScrollAllowed.m.right){ 21637 moveSlideRight(activeSection); //next 21638 } 21639 } else { 21640 if(isScrollAllowed.m.left){ 21641 moveSlideLeft(activeSection); //prev 21642 } 21643 } 21644 } 21645 } 21646 21647 //vertical scrolling (only when autoScrolling is enabled) 21648 else if(options.autoScrolling && canScroll){ 21649 21650 //is the movement greater than the minimum resistance to scroll? 21651 if (Math.abs(touchStartY - touchEndY) > ($window.height() / 100 * options.touchSensitivity)) { 21652 if (touchStartY > touchEndY) { 21653 scrolling('down', scrollable); 21654 } else if (touchEndY > touchStartY) { 21655 scrolling('up', scrollable); 21656 } 21657 } 21658 } 21659 } 21660 } 21661 21662 /** 21663 * recursive function to loop up the parent nodes to check if one of them exists in options.normalScrollElements 21664 * Currently works well for iOS - Android might need some testing 21665 * @param {Element} el target element / jquery selector (in subsequent nodes) 21666 * @param {int} hop current hop compared to options.normalScrollElementTouchThreshold 21667 * @return {boolean} true if there is a match to options.normalScrollElements 21668 */ 21669 function checkParentForNormalScrollElement (el, hop) { 21670 hop = hop || 0; 21671 var parent = $(el).parent(); 21672 21673 if (hop < options.normalScrollElementTouchThreshold && 21674 parent.is(options.normalScrollElements) ) { 21675 return true; 21676 } else if (hop == options.normalScrollElementTouchThreshold) { 21677 return false;
21678 } else { 21679 return checkParentForNormalScrollElement(parent, ++hop); 21680 } 21681 } 21682 21683 /** 21684 * As IE >= 10 fires both touch and mouse events when using a mouse in a touchscreen 21685 * this way we make sure that is really a touch event what IE is detecting. 21686 */ 21687 function isReallyTouch(e){ 21688 //if is not IE || IE is detecting `touch` or `pen` 21689 return typeof e.pointerType === 'undefined' || e.pointerType != 'mouse'; 21690 } 21691 21692 /** 21693 * Handler for the touch start event. 21694 */ 21695 function touchStartHandler(event){ 21696 var e = event.originalEvent; 21697 21698 //stopping the auto scroll to adjust to a section 21699 if(options.fitToSection){ 21700 $htmlBody.stop(); 21701 } 21702 21703 if(isReallyTouch(e)){ 21704 var touchEvents = getEventsPage(e); 21705 touchStartY = touchEvents.y; 21706 touchStartX = touchEvents.x; 21707 } 21708 } 21709 21710 /** 21711 * Gets the average of the last `number` elements of the given array. 21712 */ 21713 function getAverage(elements, number){ 21714 var sum = 0; 21715 21716 //taking `number` elements from the end to make the average, if there are not enought, 1 21717 var lastElements = elements.slice(Math.max(elements.length - number, 1)); 21718 21719 for(var i = 0; i < lastElements.length; i++){ 21720 sum = sum + lastElements[i]; 21721 } 21722 21723 return Math.ceil(sum/number); 21724 } 21725 21726 /** 21727 * Detecting mousewheel scrolling 21728 * 21729 * http://blogs.sitepointstatic.com/examples/tech/mouse-wheel/index.html 21730 * http://www.sitepoint.com/html5-javascript-mouse-wheel/ 21731 */ 21732 var prevTime = new Date().getTime(); 21733 21734 function MouseWheelHandler(e) { 21735 var curTime = new Date().getTime(); 21736 var isNormalScroll = $(COMPLETELY_SEL).hasClass(NORMAL_SCROLL); 21737 21738 //autoscrolling and not zooming? 21739 if(options.autoScrolling && !controlPressed && !isNormalScroll){ 21740 // cross-browser wheel delta 21741 e = e || window.event; 21742 var value = e.wheelDelta || -e.deltaY || -e.detail; 21743 var delta = Math.max(-1, Math.min(1, value)); 21744 21745 var horizontalDetection = typeof e.wheelDeltaX !== 'undefined' || typeof e.deltaX !== 'undefined'; 21746 var isScrollingVertically = (Math.abs(e.wheelDeltaX) < Math.abs(e.wheelDelta)) || (Math.abs(e.deltaX ) < Math.abs(e.deltaY) || !horizontalDetection); 21747 21748 //Limiting the array to 150 (lets not waste memory!) 21749 if(scrollings.length > 149){ 21750 scrollings.shift(); 21751 } 21752 21753 //keeping record of the previous scrollings 21754 scrollings.push(Math.abs(value)); 21755 21756 //preventing to scroll the site on mouse wheel when scrollbar is present 21757 if(options.scrollBar){ 21758 e.preventDefault ? e.preventDefault() : e.returnValue = false; 21759 } 21760 21761 var activeSection = $(SECTION_ACTIVE_SEL); 21762 var scrollable = options.scrollOverflowHandler.scrollable(activeSection); 21763 21764 //time difference between the last scroll and the current one 21765 var timeDiff = curTime-prevTime; 21766 prevTime = curTime; 21767 21768 //haven't they scrolled in a while? 21769 //(enough to be consider a different scrolling action to scroll another section) 21770 if(timeDiff > 200){ 21771 //emptying the array, we dont care about old scrollings for our averages 21772 scrollings = []; 21773 } 21774 21775 if(canScroll){ 21776 var averageEnd = getAverage(scrollings, 10); 21777 var averageMiddle = getAverage(scrollings, 70); 21778 var isAccelerating = averageEnd >= averageMiddle; 21779 21780 //to avoid double swipes... 21781 if(isAccelerating && isScrollingVertically){ 21782 //scrolling down? 21783 if (delta < 0) { 21784 scrolling('down', scrollable); 21785 21786 //scrolling up? 21787 }else { 21788 scrolling('up', scrollable); 21789 } 21790 } 21791 } 21792 21793 return false;
21794 } 21795 21796 if(options.fitToSection){ 21797 //stopping the auto scroll to adjust to a section 21798 $htmlBody.stop(); 21799 } 21800 } 21801 21802 /** 21803 * Slides a slider to the given direction. 21804 * Optional `section` param. 21805 */ 21806 function moveSlide(direction, section){ 21807 var activeSection = typeof section === 'undefined' ? $(SECTION_ACTIVE_SEL) : section; 21808 var slides = activeSection.find(SLIDES_WRAPPER_SEL); 21809 var numSlides = slides.find(SLIDE_SEL).length; 21810 21811 // more than one slide needed and nothing should be sliding 21812 if (!slides.length || slideMoving || numSlides < 2) { 21813 return; 21814 } 21815 21816 var currentSlide = slides.find(SLIDE_ACTIVE_SEL); 21817 var destiny = null; 21818 21819 if(direction === 'left'){ 21820 destiny = currentSlide.prev(SLIDE_SEL); 21821 }else{ 21822 destiny = currentSlide.next(SLIDE_SEL); 21823 } 21824 21825 //isn't there a next slide in the secuence? 21826 if(!destiny.length){ 21827 //respect loopHorizontal settin 21828 if (!options.loopHorizontal) return; 21829 21830 if(direction === 'left'){ 21831 destiny = currentSlide.siblings(':last'); 21832 }else{ 21833 destiny = currentSlide.siblings(':first'); 21834 } 21835 } 21836 21837 slideMoving = true; 21838 21839 landscapeScroll(slides, destiny, direction); 21840 } 21841 21842 /** 21843 * Maintains the active slides in the viewport 21844 * (Because the `scroll` animation might get lost with some actions, such as when using continuousVertical) 21845 */ 21846 function keepSlidesPosition(){ 21847 $(SLIDE_ACTIVE_SEL).each(function(){ 21848 silentLandscapeScroll($(this), 'internal'); 21849 }); 21850 } 21851 21852 var previousDestTop = 0; 21853 /** 21854 * Returns the destination Y position based on the scrolling direction and 21855 * the height of the section. 21856 */ 21857 function getDestinationPosition(element){ 21858 var elemPosition = element.position(); 21859 21860 //top of the desination will be at the top of the viewport 21861 var position = elemPosition.top; 21862 var isScrollingDown = elemPosition.top > previousDestTop; 21863 var sectionBottom = position - windowsHeight + element.outerHeight(); 21864 var bigSectionsDestination = options.bigSectionsDestination; 21865 21866 //Uncode addition 21867 var containerH = container.outerHeight(); 21868 var containerPosition = container.offset(); 21869 21870 //########### Commented by Uncode - START ########### 21871 //is the destination element bigger than the viewport? 21872 // if(element.outerHeight() > windowsHeight){ 21873 // //scrolling up? 21874 // if(!isScrollingDown && !bigSectionsDestination || bigSectionsDestination === 'bottom' ){ 21875 // position = sectionBottom; 21876 // } 21877 // } 21878 21879 // //sections equal or smaller than the viewport height && scrolling down? || is resizing and its in the last section 21880 // else if(isScrollingDown || (isResizing && element.is(':last-child')) ){ 21881 // //The bottom of the destination will be at the bottom of the viewport 21882 // position = sectionBottom; 21883 // } 21884 //########### Commented by Uncode - END ########### 21885 21886 //Uncode addition 21887 if ( !$masthead.hasClass('menu-transparent') && $('body').hasClass('uncode-fp-menu-shrink') && !element.is(':first-child') ) 21888 position += 18; 21889 if ( ( containerH + menuHeight + bodyBorder + adminBarHeight - windowsHeight ) < position || ( isResizing && element.is(':last-child') ) ) { 21890 position = sectionBottom + menuHeight + bodyBorder*2 + adminBarHeight; 21891 } 21892 21893 /* 21894 Keeping record of the last scrolled position to determine the scrolling direction. 21895 No conventional methods can be used as the scroll bar might not be present 21896 AND the section might not be active if it is auto-height and didnt reach the middle 21897 of the viewport. 21898 */ 21899 previousDestTop = position; 21900 return position; 21901 } 21902 21903 /** 21904 * Scrolls the site to the given element and scrolls to the slide if a callback is given. 21905 */ 21906 function scrollPage(element, callback, isMovementUp){ 21907 if(typeof element === 'undefined'){ return; } //there's no element to scroll, leaving the function 21908 21909 var dtop = getDestinationPosition(element); 21910 var slideAnchorLink; 21911 var slideIndex; 21912 21913 //local variables 21914 var v = { 21915 element: element, 21916 callback: callback, 21917 isMovementUp: isMovementUp, 21918 dtop: dtop, 21919 yMovement: getYmovement(element), 21920 anchorLink: element.data('anchor'), 21921 sectionIndex: element.index(SECTION_SEL), 21922 activeSlide: element.find(SLIDE_ACTIVE_SEL), 21923 activeSection: $(SECTION_ACTIVE_SEL), 21924 leavingSection: $(SECTION_ACTIVE_SEL).index(SECTION_SEL) + 1, 21925 21926 //caching the value of isResizing at the momment the function is called 21927 //because it will be checked later inside a setTimeout and the value might change 21928 localIsResizing: isResizing 21929 }; 21930 21931 //quiting when destination scroll is the same as the current one 21932 if((v.activeSection.is(element) && !isResizing) || (options.scrollBar && $window.scrollTop() === v.dtop && !element.hasClass(AUTO_HEIGHT) )){ return; } 21933 21934 if(v.activeSlide.length){ 21935 slideAnchorLink = v.activeSlide.data('anchor'); 21936 slideIndex = v.activeSlide.index(); 21937 } 21938 21939 // If continuousVertical && we need to wrap around 21940 if (options.autoScrolling && options.continuousVertical && typeof (v.isMovementUp) !== "undefined" && 21941 ((!v.isMovementUp && v.yMovement == 'up') || // Intending to scroll down but about to go up or 21942 (v.isMovementUp && v.yMovement == 'down'))) { // intending to scroll up but about to go down 21943 21944 v = createInfiniteSections(v); 21945 } 21946 21947 //callback (onLeave) if the site is not just resizing and readjusting the slides 21948 if($.isFunction(options.onLeave) && !v.localIsResizing){ 21949 if(options.onLeave.call(v.activeSection, v.leavingSection, (v.sectionIndex + 1), v.yMovement) === false){ 21950 return; 21951 } 21952 } 21953 21954 //pausing media of the leaving section (if we are not just resizing, as destinatino will be the same one) 21955 if(!v.localIsResizing){ 21956 stopMedia(v.activeSection); 21957 } 21958 21959 options.scrollOverflowHandler.beforeLeave(); 21960 element.addClass(ACTIVE).siblings().removeClass(ACTIVE); 21961 lazyLoad(element); 21962 options.scrollOverflowHandler.onLeave(); 21963 21964 21965 //preventing from activating the MouseWheelHandler event 21966 //more than once if the page is scrolling 21967 canScroll = false;
21968 21969 setState(slideIndex, slideAnchorLink, v.anchorLink, v.sectionIndex); 21970 21971 performMovement(v); 21972 21973 //flag to avoid callingn `scrollPage()` twice in case of using anchor links 21974 lastScrolledDestiny = v.anchorLink; 21975 21976 //avoid firing it twice (as it does also on scroll) 21977 activateMenuAndNav(v.anchorLink, v.sectionIndex); 21978 } 21979 21980 /** 21981 * Performs the vertical movement (by CSS3 or by jQuery) 21982 */ 21983 function performMovement(v){ 21984 // using CSS3 translate functionality 21985 if (options.css3 && options.autoScrolling && !options.scrollBar) { 21986 21987 // The first section can have a negative value in iOS 10. Not quite sure why: -0.0142822265625 21988 // that's why we round it to 0. 21989 var translate3d = 'translate3d(0px, -' + Math.round(v.dtop) + 'px, 0px)'; 21990 transformContainer(translate3d, true); 21991 21992 //even when the scrollingSpeed is 0 there's a little delay, which might cause the 21993 //scrollingSpeed to change in case of using silentMoveTo(); 21994 if(options.scrollingSpeed){ 21995 clearTimeout(afterSectionLoadsId); 21996 afterSectionLoadsId = setTimeout(function () { 21997 afterSectionLoads(v); 21998 }, options.scrollingSpeed); 21999 }else{ 22000 afterSectionLoads(v); 22001 } 22002 } 22003 22004 // using jQuery animate 22005 else{ 22006 var scrollSettings = getScrollSettings(v); 22007 22008 $(scrollSettings.element).animate( 22009 scrollSettings.options, 22010 options.scrollingSpeed, options.easing).promise().done(function () { //only one single callback in case of animating `html, body` 22011 if(options.scrollBar){ 22012 22013 /* Hack! 22014 The timeout prevents setting the most dominant section in the viewport as "active" when the user 22015 scrolled to a smaller section by using the mousewheel (auto scrolling) rather than draging the scroll bar. 22016 22017 When using scrollBar:true It seems like the scroll events still getting propagated even after the scrolling animation has finished. 22018 */ 22019 setTimeout(function(){ 22020 afterSectionLoads(v); 22021 },30); 22022 }else{ 22023 afterSectionLoads(v); 22024 } 22025 }); 22026 } 22027 } 22028 22029 /** 22030 * Gets the scrolling settings depending on the plugin autoScrolling option 22031 */ 22032 function getScrollSettings(v){ 22033 var scroll = {}; 22034 22035 if(options.autoScrolling && !options.scrollBar){ 22036 scroll.options = { 'top': -v.dtop}; 22037 scroll.element = WRAPPER_SEL; 22038 }else{ 22039 scroll.options = { 'scrollTop': v.dtop}; 22040 scroll.element = 'html, body'; 22041 } 22042 22043 return scroll; 22044 } 22045 22046 /** 22047 * Adds sections before or after the current one to create the infinite effect. 22048 */ 22049 function createInfiniteSections(v){ 22050 // Scrolling down 22051 if (!v.isMovementUp) { 22052 // Move all previous sections to after the active section 22053 $(SECTION_ACTIVE_SEL).after(v.activeSection.prevAll(SECTION_SEL).get().reverse()); 22054 } 22055 else { // Scrolling up 22056 // Move all next sections to before the active section 22057 $(SECTION_ACTIVE_SEL).before(v.activeSection.nextAll(SECTION_SEL)); 22058 } 22059 22060 // Maintain the displayed position (now that we changed the element order) 22061 silentScroll($(SECTION_ACTIVE_SEL).position().top); 22062 22063 // Maintain the active slides visible in the viewport 22064 keepSlidesPosition(); 22065 22066 // save for later the elements that still need to be reordered 22067 v.wrapAroundElements = v.activeSection; 22068 22069 // Recalculate animation variables 22070 v.dtop = v.element.position().top; 22071 v.yMovement = getYmovement(v.element); 22072 22073 return v; 22074 } 22075 22076 /** 22077 * Fix section order after continuousVertical changes have been animated 22078 */ 22079 function continuousVerticalFixSectionOrder (v) {
22080 // If continuousVertical is in effect (and autoScrolling would also be in effect then), 22081 // finish moving the elements around so the direct navigation will function more simply 22082 if (!v.wrapAroundElements || !v.wrapAroundElements.length) { 22083 return; 22084 } 22085 22086 if (v.isMovementUp) { 22087 $(SECTION_FIRST_SEL).before(v.wrapAroundElements); 22088 } 22089 else { 22090 $(SECTION_LAST_SEL).after(v.wrapAroundElements); 22091 } 22092 22093 silentScroll($(SECTION_ACTIVE_SEL).position().top); 22094 22095 // Maintain the active slides visible in the viewport 22096 keepSlidesPosition(); 22097 } 22098 22099 22100 /** 22101 * Actions to do once the section is loaded. 22102 */ 22103 function afterSectionLoads (v){ 22104 continuousVerticalFixSectionOrder(v); 22105 22106 //callback (afterLoad) if the site is not just resizing and readjusting the slides 22107 $.isFunction(options.afterLoad) && !v.localIsResizing && options.afterLoad.call(v.element, v.anchorLink, (v.sectionIndex + 1)); 22108 options.scrollOverflowHandler.afterLoad(); 22109 22110 if(!v.localIsResizing){ 22111 playMedia(v.element); 22112 } 22113 22114 v.element.addClass(COMPLETELY).siblings().removeClass(COMPLETELY); 22115 22116 canScroll = true; 22117 22118 $.isFunction(v.callback) && v.callback.call(this); 22119 } 22120 22121 /** 22122 * Sets the value for the given attribute from the `data-` attribute with the same suffix 22123 * ie: data-srcset ==> srcset | data-src ==> src 22124 */ 22125 function setSrc(element, attribute){ 22126 element 22127 .attr(attribute, element.data(attribute)) 22128 .removeAttr('data-' + attribute); 22129 } 22130 22131 /** 22132 * Lazy loads image, video and audio elements. 22133 */ 22134 function lazyLoad(destiny){ 22135 if (!options.lazyLoading){ 22136 return; 22137 } 22138 22139 var panel = getSlideOrSection(destiny); 22140 var element; 22141 22142 panel.find('img[data-src], img[data-srcset], source[data-src], audio[data-src], iframe[data-src]').each(function(){ 22143 element = $(this); 22144 22145 $.each(['src', 'srcset'], function(index, type){ 22146 var attribute = element.attr('data-' + type); 22147 if(typeof attribute !== 'undefined' && attribute){ 22148 setSrc(element, type); 22149 } 22150 }); 22151 22152 if(element.is('source')){ 22153 element.closest('video').get(0).load(); 22154 } 22155 }); 22156 } 22157 22158 /** 22159 * Plays video and audio elements. 22160 */ 22161 function playMedia(destiny){ 22162 var panel = getSlideOrSection(destiny); 22163 22164 //playing HTML5 media elements 22165 panel.find('video, audio').each(function(){ 22166 var element = $(this).get(0); 22167 22168 if( element.hasAttribute('data-autoplay') && typeof element.play === 'function' ) { 22169 element.play(); 22170 } 22171 }); 22172 22173 //youtube videos 22174 panel.find('iframe[src*="youtube.com/embed/"]').each(function(){ 22175 var element = $(this).get(0); 22176 22177 if ( element.hasAttribute('data-autoplay') ){ 22178 playYoutube(element); 22179 } 22180 22181 //in case the URL was not loaded yet. On page load we need time for the new URL (with the API string) to load. 22182 element.onload = function() { 22183 if ( element.hasAttribute('data-autoplay') ){ 22184 playYoutube(element); 22185 } 22186 }; 22187 }); 22188 } 22189 22190 /** 22191 * Plays a youtube video 22192 */ 22193 function playYoutube(element){ 22194 element.contentWindow.postMessage('{"event":"command","func":"playVideo","args":""}', '*'); 22195 } 22196 22197 /** 22198 * Stops video and audio elements. 22199 */ 22200 function stopMedia(destiny){ 22201 var panel = getSlideOrSection(destiny); 22202 22203 //stopping HTML5 media elements 22204 panel.find('video, audio').each(function(){ 22205 var element = $(this).get(0); 22206 22207 if( !element.hasAttribute('data-keepplaying') && typeof element.pause === 'function' ) { 22208 element.pause(); 22209 } 22210 }); 22211 22212 //youtube videos 22213 panel.find('iframe[src*="youtube.com/embed/"]').each(function(){ 22214 var element = $(this).get(0); 22215 22216 if( /youtube\.com\/embed\//.test($(this).attr('src')) && !element.hasAttribute('data-keepplaying')){ 22217 $(this).get(0).contentWindow.postMessage('{"event":"command","func":"pauseVideo","args":""}','*'); 22218 } 22219 }); 22220 } 22221 22222 /** 22223 * Gets the active slide (or section) for the given section 22224 */ 22225 function getSlideOrSection(destiny){ 22226 var slide = destiny.find(SLIDE_ACTIVE_SEL); 22227 if( slide.length ) { 22228 destiny = $(slide); 22229 } 22230 22231 return destiny; 22232 } 22233 22234 /**
22235 * Scrolls to the anchor in the URL when loading the site 22236 */ 22237 function scrollToAnchor(){ 22238 //getting the anchor link in the URL and deleting the `#` 22239 var value = window.location.hash.replace('#', '').split('/'); 22240 var sectionAnchor = decodeURIComponent(value[0]); 22241 var slideAnchor = decodeURIComponent(value[1]); 22242 22243 if(sectionAnchor){ //if theres any # 22244 if(options.animateAnchor){ 22245 scrollPageAndSlide(sectionAnchor, slideAnchor); 22246 }else{ 22247 silentMoveTo(sectionAnchor, slideAnchor); 22248 } 22249 } 22250 } 22251 22252 /** 22253 * Detecting any change on the URL to scroll to the given anchor link 22254 * (a way to detect back history button as we play with the hashes on the URL) 22255 */ 22256 function hashChangeHandler(){ 22257 if(!isScrolling && !options.lockAnchors){ 22258 var value = window.location.hash.replace('#', '').split('/'); 22259 var sectionAnchor = decodeURIComponent(value[0]); 22260 var slideAnchor = decodeURIComponent(value[1]); 22261 22262 //when moving to a slide in the first section for the first time (first time to add an anchor to the URL) 22263 var isFirstSlideMove = (typeof lastScrolledDestiny === 'undefined'); 22264 var isFirstScrollMove = (typeof lastScrolledDestiny === 'undefined' && typeof slideAnchor === 'undefined' && !slideMoving); 22265 22266 22267 if(sectionAnchor.length){ 22268 /*in order to call scrollpage() only once for each destination at a time 22269 It is called twice for each scroll otherwise, as in case of using anchorlinks `hashChange` 22270 event is fired on every scroll too.*/ 22271 if ((sectionAnchor && sectionAnchor !== lastScrolledDestiny) && !isFirstSlideMove || isFirstScrollMove || (!slideMoving && lastScrolledSlide != slideAnchor )) { 22272 scrollPageAndSlide(sectionAnchor, slideAnchor); 22273 } 22274 } 22275 } 22276 } 22277 22278 //Sliding with arrow keys, both, vertical and horizontal 22279 function keydownHandler(e) { 22280 22281 clearTimeout(keydownId); 22282 22283 var activeElement = $(':focus'); 22284 22285 if(!activeElement.is('textarea') && !activeElement.is('input') && !activeElement.is('select') && 22286 activeElement.attr('contentEditable') !== "true" && activeElement.attr('contentEditable') !== '' && 22287 options.keyboardScrolling && options.autoScrolling){ 22288 var keyCode = e.which; 22289 22290 //preventing the scroll with arrow keys & spacebar & Page Up & Down keys 22291 var keyControls = [40, 38, 32, 33, 34]; 22292 if($.inArray(keyCode, keyControls) > -1){ 22293 e.preventDefault(); 22294 } 22295 22296 controlPressed = e.ctrlKey; 22297 22298 keydownId = setTimeout(function(){ 22299 onkeydown(e); 22300 },150); 22301 } 22302 } 22303 22304 function tooltipTextHandler(){ 22305 $(this).prev().trigger('click'); 22306 } 22307 22308 //to prevent scrolling while zooming 22309 function keyUpHandler(e){ 22310 if(isWindowFocused){ //the keyup gets fired on new tab ctrl + t in Firefox 22311 controlPressed = e.ctrlKey; 22312 } 22313 } 22314 22315 //binding the mousemove when the mouse's middle button is released 22316 function mouseDownHandler(e){ 22317 //middle button 22318 if (e.which == 2){ 22319 oldPageY = e.pageY; 22320 container.on('mousemove', mouseMoveHandler); 22321 } 22322 } 22323 22324 //unbinding the mousemove when the mouse's middle button is released 22325 function mouseUpHandler(e){ 22326 //middle button 22327 if (e.which == 2){ 22328 container.off('mousemove'); 22329 } 22330 } 22331 22332 //Scrolling horizontally when clicking on the slider controls. 22333 function slideArrowHandler(){ 22334 var section = $(this).closest(SECTION_SEL); 22335 22336 if ($(this).hasClass(SLIDES_PREV)) { 22337 if(isScrollAllowed.m.left){ 22338 moveSlideLeft(section); 22339 } 22340 } else { 22341 if(isScrollAllowed.m.right){ 22342 moveSlideRight(section); 22343 } 22344 } 22345 } 22346 22347 //when opening a new tab (ctrl + t), `control` won't be pressed when coming back. 22348 function blurHandler(){ 22349 isWindowFocused = false;
22350 controlPressed = false; 22351 } 22352 22353 //Scrolls to the section when clicking the navigation bullet 22354 function sectionBulletHandler(e){ 22355 e.preventDefault(); 22356 var index = $(this).parent().index(); 22357 scrollPage($(SECTION_SEL).eq(index)); 22358 } 22359 22360 //Scrolls the slider to the given slide destination for the given section 22361 function slideBulletHandler(e){ 22362 e.preventDefault(); 22363 var slides = $(this).closest(SECTION_SEL).find(SLIDES_WRAPPER_SEL); 22364 var destiny = slides.find(SLIDE_SEL).eq($(this).closest('li').index()); 22365 22366 landscapeScroll(slides, destiny); 22367 } 22368 22369 /** 22370 * Keydown event 22371 */ 22372 function onkeydown(e){ 22373 var shiftPressed = e.shiftKey; 22374 22375 //do nothing if we can not scroll or we are not using horizotnal key arrows. 22376 if(!canScroll && [37,39].indexOf(e.which) < 0){ 22377 return; 22378 } 22379 22380 switch (e.which) { 22381 //up 22382 case 38: 22383 case 33: 22384 if(isScrollAllowed.k.up){ 22385 moveSectionUp(); 22386 } 22387 break; 22388 22389 //down 22390 case 32: //spacebar 22391 if(shiftPressed && isScrollAllowed.k.up){ 22392 moveSectionUp(); 22393 break; 22394 } 22395 /* falls through */ 22396 case 40: 22397 case 34: 22398 if(isScrollAllowed.k.down){ 22399 moveSectionDown(); 22400 } 22401 break; 22402 22403 //Home 22404 case 36: 22405 if(isScrollAllowed.k.up){ 22406 moveTo(1); 22407 } 22408 break; 22409 22410 //End 22411 case 35: 22412 if(isScrollAllowed.k.down){ 22413 moveTo( $(SECTION_SEL).length ); 22414 } 22415 break; 22416 22417 //left 22418 case 37: 22419 if(isScrollAllowed.k.left){ 22420 moveSlideLeft(); 22421 } 22422 break; 22423 22424 //right 22425 case 39: 22426 if(isScrollAllowed.k.right){ 22427 moveSlideRight(); 22428 } 22429 break; 22430 22431 default: 22432 return; // exit this handler for other keys 22433 } 22434 } 22435 22436 /** 22437 * Detecting the direction of the mouse movement. 22438 * Used only for the middle button of the mouse. 22439 */ 22440 var oldPageY = 0; 22441 function mouseMoveHandler(e){ 22442 if(canScroll){ 22443 // moving up 22444 if (e.pageY < oldPageY && isScrollAllowed.m.up){ 22445 moveSectionUp(); 22446 } 22447 22448 // moving down 22449 else if(e.pageY > oldPageY && isScrollAllowed.m.down){ 22450 moveSectionDown(); 22451 } 22452 } 22453 oldPageY = e.pageY; 22454 } 22455 22456 /** 22457 * Scrolls horizontal sliders. 22458 */ 22459 function landscapeScroll(slides, destiny, direction){ 22460 var section = slides.closest(SECTION_SEL); 22461 var v = { 22462 slides: slides, 22463 destiny: destiny, 22464 direction: direction, 22465 destinyPos: destiny.position(), 22466 slideIndex: destiny.index(), 22467 section: section, 22468 sectionIndex: section.index(SECTION_SEL), 22469 anchorLink: section.data('anchor'), 22470 slidesNav: section.find(SLIDES_NAV_SEL), 22471 slideAnchor: getAnchor(destiny), 22472 prevSlide: section.find(SLIDE_ACTIVE_SEL), 22473 prevSlideIndex: section.find(SLIDE_ACTIVE_SEL).index(), 22474 22475 //caching the value of isResizing at the momment the function is called 22476 //because it will be checked later inside a setTimeout and the value might change 22477 localIsResizing: isResizing 22478 }; 22479 v.xMovement = getXmovement(v.prevSlideIndex, v.slideIndex); 22480 v.direction = v.direction ? v.direction : v.xMovement; 22481 22482 //important!! Only do it when not resizing 22483 if(!v.localIsResizing){ 22484 //preventing from scrolling to the next/prev section when using scrollHorizontally 22485 canScroll = false;
22486 } 22487 22488 if(options.onSlideLeave){ 22489 22490 //if the site is not just resizing and readjusting the slides 22491 if(!v.localIsResizing && v.xMovement!=='none'){ 22492 if($.isFunction( options.onSlideLeave )){ 22493 if(options.onSlideLeave.call( v.prevSlide, v.anchorLink, (v.sectionIndex + 1), v.prevSlideIndex, v.xMovement, v.slideIndex ) === false){ 22494 slideMoving = false; 22495 return; 22496 } 22497 } 22498 } 22499 } 22500 22501 destiny.addClass(ACTIVE).siblings().removeClass(ACTIVE); 22502 22503 if(!v.localIsResizing){ 22504 stopMedia(v.prevSlide); 22505 lazyLoad(destiny); 22506 } 22507 22508 if(!options.loopHorizontal && options.controlArrows){ 22509 //hidding it for the fist slide, showing for the rest 22510 section.find(SLIDES_ARROW_PREV_SEL).toggle(v.slideIndex!==0); 22511 22512 //hidding it for the last slide, showing for the rest 22513 section.find(SLIDES_ARROW_NEXT_SEL).toggle(!destiny.is(':last-child')); 22514 } 22515 22516 //only changing the URL if the slides are in the current section (not for resize re-adjusting) 22517 if(section.hasClass(ACTIVE) && !v.localIsResizing){ 22518 setState(v.slideIndex, v.slideAnchor, v.anchorLink, v.sectionIndex); 22519 } 22520 22521 performHorizontalMove(slides, v, true); 22522 } 22523 22524 22525 function afterSlideLoads(v){ 22526 activeSlidesNavigation(v.slidesNav, v.slideIndex); 22527 22528 //if the site is not just resizing and readjusting the slides 22529 if(!v.localIsResizing){ 22530 $.isFunction( options.afterSlideLoad ) && options.afterSlideLoad.call( v.destiny, v.anchorLink, (v.sectionIndex + 1), v.slideAnchor, v.slideIndex); 22531 22532 //needs to be inside the condition to prevent problems with continuousVertical and scrollHorizontally 22533 //and to prevent double scroll right after a windows resize 22534 canScroll = true; 22535 22536 playMedia(v.destiny); 22537 } 22538 22539 //letting them slide again 22540 slideMoving = false; 22541 } 22542 22543 /** 22544 * Performs the horizontal movement. (CSS3 or jQuery) 22545 * 22546 * @param fireCallback {Bool} - determines whether or not to fire the callback 22547 */ 22548 function performHorizontalMove(slides, v, fireCallback){ 22549 var destinyPos = v.destinyPos; 22550 22551 if(options.css3){ 22552 var translate3d = 'translate3d(-' + Math.round(destinyPos.left) + 'px, 0px, 0px)'; 22553 22554 addAnimation(slides.find(SLIDES_CONTAINER_SEL)).css(getTransforms(translate3d), v); 22555 22556 afterSlideLoadsId = setTimeout(function(){ 22557 fireCallback && afterSlideLoads(v); 22558 }, options.scrollingSpeed, options.easing); 22559 }else{ 22560 slides.animate({ 22561 scrollLeft : Math.round(destinyPos.left) 22562 }, options.scrollingSpeed, options.easing, function() { 22563 22564 fireCallback && afterSlideLoads(v); 22565 }); 22566 } 22567 } 22568 22569 /** 22570 * Sets the state for the horizontal bullet navigations. 22571 */ 22572 function activeSlidesNavigation(slidesNav, slideIndex){ 22573 slidesNav.find(ACTIVE_SEL).removeClass(ACTIVE); 22574 slidesNav.find('li').eq(slideIndex).find('a').addClass(ACTIVE); 22575 } 22576 22577 var previousHeight = windowsHeight; 22578 22579 //when resizing the site, we adjust the heights of the sections, slimScroll... 22580 function resizeHandler(){ 22581 //checking if it needs to get responsive 22582 responsive(); 22583 22584 // rebuild immediately on touch devices 22585 if (isTouchDevice) { 22586 var activeElement = $(document.activeElement); 22587 22588 //if the keyboard is NOT visible 22589 if (!activeElement.is('textarea') && !activeElement.is('input') && !activeElement.is('select')) { 22590 var currentHeight = $window.height(); 22591 22592 //making sure the change in the viewport size is enough to force a rebuild. (20 % of the window to avoid problems when hidding scroll bars) 22593 if( Math.abs(currentHeight - previousHeight) > (20 * Math.max(previousHeight, currentHeight) / 100) ){ 22594 reBuild(true); 22595 previousHeight = currentHeight; 22596 } 22597 } 22598 }else{ 22599 //in order to call the functions only when the resize is finished 22600 //http://stackoverflow.com/questions/4298612/jquery-how-to-call-resize-event-only-once-its-finished-resizing 22601 clearTimeout(resizeId); 22602 22603 resizeId = setTimeout(function(){ 22604 reBuild(true); 22605 }, 350); 22606 } 22607 } 22608 22609 /** 22610 * Checks if the site needs to get responsive and disables autoScrolling if so. 22611 * A class `fp-responsive` is added to the plugin's container in case the user wants to use it for his own responsive CSS. 22612 */ 22613 function responsive(){ 22614 var widthLimit = options.responsive || options.responsiveWidth; //backwards compatiblity 22615 var heightLimit = options.responsiveHeight; 22616 22617 //only calculating what we need. Remember its called on the resize event. 22618 var isBreakingPointWidth = widthLimit && $window.outerWidth() < widthLimit; 22619 var isBreakingPointHeight = heightLimit && $window.height() < heightLimit; 22620 22621 if(widthLimit && heightLimit){ 22622 setResponsive(isBreakingPointWidth || isBreakingPointHeight); 22623 } 22624 else if(widthLimit){ 22625 setResponsive(isBreakingPointWidth); 22626 } 22627 else if(heightLimit){ 22628 setResponsive(isBreakingPointHeight); 22629 } 22630 } 22631 22632 /** 22633 * Adds transition animations for the given element 22634 */ 22635 function addAnimation(container, element){ 22636 var transition = 'all ' + options.scrollingSpeed + 'ms ' + options.easingcss3; 22637 22638 container.removeClass(NO_TRANSITION); 22639 return container.css({
22640 '-webkit-transition': transition, 22641 'transition': transition 22642 }); 22643 } 22644 22645 /** 22646 * Remove transition animations for the given element 22647 */ 22648 function removeAnimation(element){ 22649 return element.addClass(NO_TRANSITION); 22650 } 22651 22652 /** 22653 * Activating the vertical navigation bullets according to the given slide name. 22654 */ 22655 function activateNavDots(name, sectionIndex){ 22656 if(options.navigation){ 22657 $(SECTION_NAV_SEL).find(ACTIVE_SEL).removeClass(ACTIVE); 22658 if(name){ 22659 $(SECTION_NAV_SEL).find('a[href="#' + name + '"]').addClass(ACTIVE); 22660 }else{ 22661 $(SECTION_NAV_SEL).find('li').eq(sectionIndex).find('a').addClass(ACTIVE); 22662 } 22663 } 22664 } 22665 22666 /** 22667 * Activating the website main menu elements according to the given slide name. 22668 */ 22669 function activateMenuElement(name){ 22670 if(options.menu){ 22671 $(options.menu).find(ACTIVE_SEL).removeClass(ACTIVE); 22672 $(options.menu).find('[data-menuanchor="'+name+'"]').addClass(ACTIVE); 22673 } 22674 } 22675 22676 /** 22677 * Sets to active the current menu and vertical nav items. 22678 */ 22679 function activateMenuAndNav(anchor, index){ 22680 activateMenuElement(anchor); 22681 activateNavDots(anchor, index); 22682 } 22683 22684 /** 22685 * Retuns `up` or `down` depending on the scrolling movement to reach its destination 22686 * from the current section. 22687 */ 22688 function getYmovement(destiny){ 22689 var fromIndex = $(SECTION_ACTIVE_SEL).index(SECTION_SEL); 22690 var toIndex = destiny.index(SECTION_SEL); 22691 if( fromIndex == toIndex){ 22692 return 'none'; 22693 } 22694 if(fromIndex > toIndex){ 22695 return 'up'; 22696 } 22697 return 'down'; 22698 } 22699 22700 /** 22701 * Retuns `right` or `left` depending on the scrolling movement to reach its destination 22702 * from the current slide. 22703 */ 22704 function getXmovement(fromIndex, toIndex){ 22705 if( fromIndex == toIndex){ 22706 return 'none'; 22707 } 22708 if(fromIndex > toIndex){ 22709 return 'left'; 22710 } 22711 return 'right'; 22712 } 22713 22714 /** 22715 * Checks if the element needs scrollbar and if the user wants to apply it. 22716 * If so it creates it. 22717 * 22718 * @param {Object} element jQuery object of the section or slide 22719 */ 22720 function createScrollBar(element){ 22721 //User doesn't want scrollbar here? Sayonara baby! 22722 if(element.hasClass('fp-noscroll')) return; 22723 22724 //needed to make `scrollHeight` work under Opera 12 22725 element.css('overflow', 'hidden'); 22726 22727 var scrollOverflowHandler = options.scrollOverflowHandler; 22728 var wrap = scrollOverflowHandler.wrapContent(); 22729 //in case element is a slide 22730 var section = element.closest(SECTION_SEL); 22731 var scrollable = scrollOverflowHandler.scrollable(element); 22732 var contentHeight; 22733 22734 //if there was scroll, the contentHeight will be the one in the scrollable section 22735 if(scrollable.length){ 22736 contentHeight = scrollOverflowHandler.scrollHeight(element); 22737 }else{ 22738 contentHeight = element.get(0).scrollHeight; 22739 if(options.verticalCentered){ 22740 contentHeight = element.find(TABLE_CELL_SEL).get(0).scrollHeight; 22741 } 22742 } 22743 22744 var scrollHeight = windowsHeight - parseInt(section.css('padding-bottom')) - parseInt(section.css('padding-top')); 22745 22746 //needs scroll? 22747 if ( contentHeight > scrollHeight) { 22748 //did we already have an scrollbar ? Updating it 22749 if(scrollable.length){ 22750 scrollOverflowHandler.update(element, scrollHeight); 22751 } 22752 //creating the scrolling 22753 else{ 22754 if(options.verticalCentered){ 22755 element.find(TABLE_CELL_SEL).wrapInner(wrap); 22756 }else{ 22757 element.wrapInner(wrap); 22758 } 22759 scrollOverflowHandler.create(element, scrollHeight); 22760 } 22761 } 22762 //removing the scrolling when it is not necessary anymore 22763 else{ 22764 scrollOverflowHandler.remove(element); 22765 } 22766 22767 //undo 22768 element.css('overflow', ''); 22769 } 22770 22771 function addTableClass(element){ 22772 //In case we are styling for the 2nd time as in with reponsiveSlides 22773 if(!element.hasClass(TABLE)){ 22774 element.addClass(TABLE).wrapInner('<div class="' + TABLE_CELL + '" style="height:' + getTableHeight(element) + 'px;" />'); 22775 } 22776 } 22777 22778 function getTableHeight(element){ 22779 var sectionHeight = windowsHeight; 22780 22781 if(options.paddingTop || options.paddingBottom){ 22782 var section = element; 22783 if(!section.hasClass(SECTION)){ 22784 section = element.closest(SECTION_SEL); 22785 } 22786 22787 var paddings = parseInt(section.css('padding-top')) + parseInt(section.css('padding-bottom')); 22788 sectionHeight = (windowsHeight - paddings); 22789 } 22790 22791 return sectionHeight; 22792 } 22793 22794 /** 22795 * Adds a css3 transform property to the container class with or without animation depending on the animated param. 22796 */ 22797 function transformContainer(translate3d, animated){ 22798 if(animated){ 22799 addAnimation(container); 22800 }else{ 22801 removeAnimation(container); 22802 } 22803 22804 container.css(getTransforms(translate3d)); 22805 22806 //syncronously removing the class after the animation has been applied. 22807 setTimeout(function(){ 22808 container.removeClass(NO_TRANSITION); 22809 },10); 22810 } 22811 22812 /** 22813 * Gets a section by its anchor / index 22814 */ 22815 function getSectionByAnchor(sectionAnchor){ 22816 if(!sectionAnchor) return []; 22817 22818 var section = container.find(SECTION_SEL + '[data-anchor="'+sectionAnchor+'"]'); 22819 if(!section.length){ 22820 section = $(SECTION_SEL).eq( sectionAnchor -1); 22821 } 22822 22823 return section; 22824 } 22825 22826 /** 22827 * Gets a slide inside a given section by its anchor / index 22828 */ 22829 function getSlideByAnchor(slideAnchor, section){ 22830 var slides = section.find(SLIDES_WRAPPER_SEL); 22831 var slide = slides.find(SLIDE_SEL + '[data-anchor="'+slideAnchor+'"]'); 22832
22833 if(!slide.length){ 22834 slide = slides.find(SLIDE_SEL).eq(slideAnchor); 22835 } 22836 22837 return slide; 22838 } 22839 22840 /** 22841 * Scrolls to the given section and slide anchors 22842 */ 22843 function scrollPageAndSlide(destiny, slide){ 22844 var section = getSectionByAnchor(destiny); 22845 22846 //do nothing if there's no section with the given anchor name 22847 if(!section.length) return; 22848 22849 //default slide 22850 if (typeof slide === 'undefined') { 22851 slide = 0; 22852 } 22853 22854 //we need to scroll to the section and then to the slide 22855 if (destiny !== lastScrolledDestiny && !section.hasClass(ACTIVE)){ 22856 scrollPage(section, function(){ 22857 scrollSlider(section, slide); 22858 }); 22859 } 22860 //if we were already in the section 22861 else{ 22862 scrollSlider(section, slide); 22863 } 22864 } 22865 22866 /** 22867 * Scrolls the slider to the given slide destination for the given section 22868 */ 22869 function scrollSlider(section, slideAnchor){ 22870 if(typeof slideAnchor !== 'undefined'){ 22871 var slides = section.find(SLIDES_WRAPPER_SEL); 22872 var destiny = getSlideByAnchor(slideAnchor, section); 22873 22874 if(destiny.length){ 22875 landscapeScroll(slides, destiny); 22876 } 22877 } 22878 } 22879 22880 /** 22881 * Creates a landscape navigation bar with dots for horizontal sliders. 22882 */ 22883 function addSlidesNavigation(section, numSlides){ 22884 section.append('<div class="' + SLIDES_NAV + '"><ul></ul></div>'); 22885 var nav = section.find(SLIDES_NAV_SEL); 22886 22887 //top or bottom 22888 nav.addClass(options.slidesNavPosition); 22889 22890 for(var i=0; i< numSlides; i++){ 22891 nav.find('ul').append('<li><a href="#"><span></span></a></li>'); 22892 } 22893 22894 //centering it 22895 nav.css('margin-left', '-' + (nav.width()/2) + 'px'); 22896 22897 nav.find('li').first().find('a').addClass(ACTIVE); 22898 } 22899 22900 22901 /** 22902 * Sets the state of the website depending on the active section/slide. 22903 * It changes the URL hash when needed and updates the body class. 22904 */ 22905 function setState(slideIndex, slideAnchor, anchorLink, sectionIndex){ 22906 var sectionHash = ''; 22907 22908 if(options.anchors.length && !options.lockAnchors){ 22909 22910 //isn't it the first slide? 22911 if(slideIndex){ 22912 if(typeof anchorLink !== 'undefined'){ 22913 sectionHash = anchorLink; 22914 } 22915 22916 //slide without anchor link? We take the index instead. 22917 if(typeof slideAnchor === 'undefined'){ 22918 slideAnchor = slideIndex; 22919 } 22920 22921 lastScrolledSlide = slideAnchor; 22922 setUrlHash(sectionHash + '/' + slideAnchor); 22923 22924 //first slide won't have slide anchor, just the section one 22925 }else if(typeof slideIndex !== 'undefined'){ 22926 lastScrolledSlide = slideAnchor; 22927 setUrlHash(anchorLink); 22928 } 22929 22930 //section without slides 22931 else{ 22932 setUrlHash(anchorLink); 22933 } 22934 } 22935 22936 setBodyClass(); 22937 } 22938 22939 /** 22940 * Sets the URL hash. 22941 */ 22942 function setUrlHash(url){ 22943 //Uncode addition 22944 if ( typeof SiteParameters.slide_footer != 'undefined' && url == SiteParameters.slide_footer ) 22945 return false; 22946 22947 if(options.recordHistory){ 22948 location.hash = url; 22949 }else{ 22950 //Uncode addition 22951 //Mobile Chrome doesn't work the normal way, so... lets use HTML5 for phones :) 22952 // if(isTouchDevice || isTouch){ 22953 // window.history.replaceState(undefined, undefined, '#' + url); 22954 // }else{ 22955 // var baseUrl = window.location.href.split('#')[0]; 22956 // window.location.replace( baseUrl + '#' + url ); 22957 // } 22958 return false;
22959 } 22960 } 22961 22962 /** 22963 * Gets the anchor for the given slide / section. Its index will be used if there's none. 22964 */ 22965 function getAnchor(element){ 22966 var anchor = element.data('anchor'); 22967 var index = element.index(); 22968 22969 //Slide without anchor link? We take the index instead. 22970 if(typeof anchor === 'undefined'){ 22971 anchor = index; 22972 } 22973 22974 return anchor; 22975 } 22976 22977 /** 22978 * Sets a class for the body of the page depending on the active section / slide 22979 */ 22980 function setBodyClass(){ 22981 var section = $(SECTION_ACTIVE_SEL); 22982 var slide = section.find(SLIDE_ACTIVE_SEL); 22983 22984 var sectionAnchor = getAnchor(section); 22985 var slideAnchor = getAnchor(slide); 22986 22987 var text = String(sectionAnchor); 22988 22989 if(slide.length){ 22990 text = text + '-' + slideAnchor; 22991 } 22992 22993 //changing slash for dash to make it a valid CSS style 22994 text = text.replace('/', '-').replace('#',''); 22995 22996 //removing previous anchor classes 22997 var classRe = new RegExp('\\b\\s?' + VIEWING_PREFIX + '-[^\\s]+\\b', "g"); 22998 $body[0].className = $body[0].className.replace(classRe, ''); 22999 23000 //adding the current anchor 23001 $body.addClass(VIEWING_PREFIX + '-' + text); 23002 } 23003 23004 /** 23005 * Checks for translate3d support 23006 * @return boolean 23007 * http://stackoverflow.com/questions/5661671/detecting-transform-translate3d-support 23008 */ 23009 function support3d() { 23010 var el = document.createElement('p'), 23011 has3d, 23012 transforms = { 23013 'webkitTransform':'-webkit-transform', 23014 'OTransform':'-o-transform', 23015 'msTransform':'-ms-transform', 23016 'MozTransform':'-moz-transform', 23017 'transform':'transform' 23018 }; 23019 23020 // Add it to the body to get the computed style. 23021 document.body.insertBefore(el, null); 23022 23023 for (var t in transforms) { 23024 if (el.style[t] !== undefined) { 23025 el.style[t] = 'translate3d(1px,1px,1px)'; 23026 has3d = window.getComputedStyle(el).getPropertyValue(transforms[t]); 23027 } 23028 } 23029 23030 document.body.removeChild(el); 23031 23032 return (has3d !== undefined && has3d.length > 0 && has3d !== 'none'); 23033 } 23034 23035 /** 23036 * Removes the auto scrolling action fired by the mouse wheel and trackpad. 23037 * After this function is called, the mousewheel and trackpad movements won't scroll through sections. 23038 */ 23039 function removeMouseWheelHandler(){ 23040 if (document.addEventListener) { 23041 document.removeEventListener('mousewheel', MouseWheelHandler, false); //IE9, Chrome, Safari, Oper 23042 document.removeEventListener('wheel', MouseWheelHandler, false); //Firefox 23043 document.removeEventListener('MozMousePixelScroll', MouseWheelHandler, false); //old Firefox 23044 } else { 23045 document.detachEvent('onmousewheel', MouseWheelHandler); //IE 6/7/8 23046 } 23047 } 23048 23049 /** 23050 * Adds the auto scrolling action for the mouse wheel and trackpad. 23051 * After this function is called, the mousewheel and trackpad movements will scroll through sections 23052 * https://developer.mozilla.org/en-US/docs/Web/Events/wheel 23053 */ 23054 function addMouseWheelHandler(){ 23055 var prefix = ''; 23056 var _addEventListener; 23057 23058 if (window.addEventListener){ 23059 _addEventListener = "addEventListener"; 23060 }else{ 23061 _addEventListener = "attachEvent"; 23062 prefix = 'on'; 23063 } 23064 23065 // detect available wheel event 23066 var support = 'onwheel' in document.createElement('div') ? 'wheel' : // Modern browsers support "wheel" 23067 document.onmousewheel !== undefined ? 'mousewheel' : // Webkit and IE support at least "mousewheel" 23068 'DOMMouseScroll'; // let's assume that remaining browsers are older Firefox 23069 var passiveEvent = g_supportsPassive ? {passive: false }
23069: false; 23070 23071 23072 if(support == 'DOMMouseScroll'){ 23073 document[ _addEventListener ](prefix + 'MozMousePixelScroll', MouseWheelHandler, passiveEvent); 23074 } 23075 23076 //handle MozMousePixelScroll in older Firefox 23077 else{ 23078 document[ _addEventListener ](prefix + support, MouseWheelHandler, passiveEvent); 23079 } 23080 } 23081 23082 /** 23083 * Binding the mousemove when the mouse's middle button is pressed 23084 */ 23085 function addMiddleWheelHandler(){ 23086 container 23087 .on('mousedown', mouseDownHandler) 23088 .on('mouseup', mouseUpHandler); 23089 } 23090 23091 /** 23092 * Unbinding the mousemove when the mouse's middle button is released 23093 */ 23094 function removeMiddleWheelHandler(){ 23095 container 23096 .off('mousedown', mouseDownHandler) 23097 .off('mouseup', mouseUpHandler); 23098 } 23099 23100 /** 23101 * Adds the possibility to auto scroll through sections on touch devices. 23102 */ 23103 function addTouchHandler(){ 23104 if(isTouchDevice || isTouch){ 23105 if(options.autoScrolling){ 23106 $body.off(events.touchmove).on(events.touchmove, preventBouncing); 23107 } 23108 23109 $(WRAPPER_SEL) 23110 .off(events.touchstart).on(events.touchstart, touchStartHandler) 23111 .off(events.touchmove).on(events.touchmove, touchMoveHandler); 23112 } 23113 } 23114 23115 /** 23116 * Removes the auto scrolling for touch devices. 23117 */ 23118 function removeTouchHandler(){ 23119 if(isTouchDevice || isTouch){ 23120 $(WRAPPER_SEL) 23121 .off(events.touchstart) 23122 .off(events.touchmove); 23123 } 23124 } 23125 23126 /* 23127 * Returns and object with Microsoft pointers (for IE<11 and for IE >= 11) 23128 * http://msdn.microsoft.com/en-us/library/ie/dn304886(v=vs.85).aspx 23129 */ 23130 function getMSPointer(){ 23131 var pointer; 23132 23133 //IE >= 11 & rest of browsers 23134 if(window.PointerEvent){ 23135 pointer = { down: 'pointerdown', move: 'pointermove'}; 23136 } 23137 23138 //IE < 11 23139 else{ 23140 pointer = { down: 'MSPointerDown', move: 'MSPointerMove'}; 23141 } 23142 23143 return pointer; 23144 } 23145 23146 /** 23147 * Gets the pageX and pageY properties depending on the browser. 23148 * https://github.com/alvarotrigo/fullPage.js/issues/194#issuecomment-34069854 23149 */ 23150 function getEventsPage(e){ 23151 var events = []; 23152 23153 events.y = (typeof e.pageY !== 'undefined' && (e.pageY || e.pageX) ? e.pageY : e.touches[0].pageY); 23154 events.x = (typeof e.pageX !== 'undefined' && (e.pageY || e.pageX) ? e.pageX : e.touches[0].pageX); 23155 23156 //in touch devices with scrollBar:true, e.pageY is detected, but we have to deal with touch events. #1008 23157 if(isTouch && isReallyTouch(e) && options.scrollBar){ 23158 events.y = e.touches[0].pageY; 23159 events.x = e.touches[0].pageX; 23160 } 23161 23162 return events; 23163 } 23164 23165 /** 23166 * Slides silently (with no animation) the active slider to the given slide. 23167 * @param noCallback {bool} true or defined -> no callbacks 23168 */ 23169 function silentLandscapeScroll(activeSlide, noCallbacks){ 23170 setScrollingSpeed (0, 'internal'); 23171 23172 if(typeof noCallbacks !== 'undefined'){ 23173 //preventing firing callbacks afterSlideLoad etc. 23174 isResizing = true; 23175 } 23176 23177 landscapeScroll(activeSlide.closest(SLIDES_WRAPPER_SEL), activeSlide); 23178 23179 if(typeof noCallbacks !== 'undefined'){ 23180 isResizing = false; 23181 } 23182 23183 setScrollingSpeed(originals.scrollingSpeed, 'internal'); 23184 } 23185 23186 /** 23187 * Scrolls silently (with no animation) the page to the given Y position. 23188 */ 23189 function silentScroll(top){ 23190 // The first section can have a negative value in iOS 10. Not quite sure why: -0.0142822265625 23191 // that's why we round it to 0. 23192 var roundedTop = Math.round(top); 23193 23194 if (options.css3 && options.autoScrolling && !options.scrollBar){ 23195 var translate3d = 'translate3d(0px, -' + roundedTop + 'px, 0px)'; 23196 transformContainer(translate3d, false); 23197 } 23198 else if(options.autoScrolling && !options.scrollBar){ 23199 container.css('top', -roundedTop); 23200 } 23201 else{ 23202 $htmlBody.scrollTop(roundedTop); 23203 } 23204 } 23205 23206 /** 23207 * Returns the cross-browser transform string. 23208 */ 23209 function getTransforms(translate3d){ 23210 return {
23211 '-webkit-transform': translate3d, 23212 '-moz-transform': translate3d, 23213 '-ms-transform':translate3d, 23214 'transform': translate3d 23215 }; 23216 } 23217 23218 /** 23219 * Allowing or disallowing the mouse/swipe scroll in a given direction. (not for keyboard) 23220 * @type m (mouse) or k (keyboard) 23221 */ 23222 function setIsScrollAllowed(value, direction, type){ 23223 switch (direction){ 23224 case 'up': isScrollAllowed[type].up = value; break; 23225 case 'down': isScrollAllowed[type].down = value; break; 23226 case 'left': isScrollAllowed[type].left = value; break; 23227 case 'right': isScrollAllowed[type].right = value; break; 23228 case 'all': 23229 if(type == 'm'){ 23230 setAllowScrolling(value); 23231 }else{ 23232 setKeyboardScrolling(value); 23233 } 23234 } 23235 } 23236 23237 /* 23238 * Destroys fullpage.js plugin events and optinally its html markup and styles 23239 */ 23240 function destroy(all){ 23241 setAutoScrolling(false, 'internal'); 23242 setAllowScrolling(false); 23243 setKeyboardScrolling(false); 23244 container.addClass(DESTROYED); 23245 23246 clearTimeout(afterSlideLoadsId); 23247 clearTimeout(afterSectionLoadsId); 23248 clearTimeout(resizeId); 23249 clearTimeout(scrollId); 23250 clearTimeout(scrollId2); 23251 23252 $window 23253 .off('scroll', scrollHandler) 23254 .off('hashchange', hashChangeHandler) 23255 .off('resize', resizeHandler); 23256 23257 $document 23258 .off('click touchstart', SECTION_NAV_SEL + ' a') 23259 .off('mouseenter', SECTION_NAV_SEL + ' li') 23260 .off('mouseleave', SECTION_NAV_SEL + ' li') 23261 .off('click touchstart', SLIDES_NAV_LINK_SEL) 23262 .off('mouseover', options.normalScrollElements) 23263 .off('mouseout', options.normalScrollElements); 23264 23265 $(SECTION_SEL) 23266 .off('click touchstart', SLIDES_ARROW_SEL); 23267 23268 clearTimeout(afterSlideLoadsId); 23269 clearTimeout(afterSectionLoadsId); 23270 23271 //lets make a mess! 23272 if(all){ 23273 destroyStructure(); 23274 } 23275 } 23276 23277 /* 23278 * Removes inline styles added by fullpage.js 23279 */ 23280 function destroyStructure(){ 23281 //reseting the `top` or `translate` properties to 0 23282 silentScroll(0); 23283 23284 //loading all the lazy load content 23285 container.find('img[data-src], source[data-src], audio[data-src], iframe[data-src]').each(function(){ 23286 setSrc($(this), 'src'); 23287 }); 23288 23289 container.find('img[data-srcset]').each(function(){ 23290 setSrc($(this), 'srcset'); 23291 }); 23292 23293 $(SECTION_NAV_SEL + ', ' + SLIDES_NAV_SEL + ', ' + SLIDES_ARROW_SEL).remove(); 23294 23295 //removing inline styles 23296 $(SECTION_SEL).css( { 23297 'height': '', 23298 'background-color' : '', 23299 'padding': '' 23300 }); 23301 23302 $(SLIDE_SEL).css( { 23303 'width': '' 23304 }); 23305 23306 container.css({ 23307 'height': '', 23308 'position': '', 23309 '-ms-touch-action': '', 23310 'touch-action': '' 23311 }); 23312 23313 $htmlBody.css({ 23314 'overflow': '', 23315 'height': '' 23316 }); 23317 23318 // remove .fp-enabled class 23319 $('html').removeClass(ENABLED); 23320 23321 // remove .fp-responsive class 23322 $body.removeClass(RESPONSIVE); 23323 23324 // remove all of the .fp-viewing- classes 23325 $.each($body.get(0).className.split(/\s+/), function (index, className) { 23326 if (className.indexOf(VIEWING_PREFIX) === 0) { 23327 $body.removeClass(className); 23328 } 23329 }); 23330 23331 //removing added classes 23332 $(SECTION_SEL + ', ' + SLIDE_SEL).each(function(){ 23333 options.scrollOverflowHandler.remove($(this)); 23334 $(this).removeClass(TABLE + ' ' + ACTIVE); 23335 }); 23336 23337 removeAnimation(container); 23338 23339 //Unwrapping content 23340 container.find(TABLE_CELL_SEL + ', ' + SLIDES_CONTAINER_SEL + ', ' + SLIDES_WRAPPER_SEL).each(function(){ 23341 //unwrap not being use in case there's no child element inside and its just text 23342 $(this).replaceWith(this.childNodes); 23343 }); 23344 23345 //removing the applied transition from the fullpage wrapper 23346 container.css({
23347 '-webkit-transition': 'none', 23348 'transition': 'none' 23349 }); 23350 23351 //scrolling the page to the top with no animation 23352 $htmlBody.scrollTop(0); 23353 23354 //removing selectors 23355 var usedSelectors = [SECTION, SLIDE, SLIDES_CONTAINER]; 23356 $.each(usedSelectors, function(index, value){ 23357 $('.' + value).removeClass(value); 23358 }); 23359 } 23360 23361 /* 23362 * Sets the state for a variable with multiple states (original, and temporal) 23363 * Some variables such as `autoScrolling` or `recordHistory` might change automatically its state when using `responsive` or `autoScrolling:false`. 23364 * This function is used to keep track of both states, the original and the temporal one. 23365 * If type is not 'internal', then we assume the user is globally changing the variable. 23366 */ 23367 function setVariableState(variable, value, type){ 23368 options[variable] = value; 23369 if(type !== 'internal'){ 23370 originals[variable] = value; 23371 } 23372 } 23373 23374 /** 23375 * Displays warnings 23376 */ 23377 function displayWarnings(){ 23378 var extensions = ['fadingEffect', 'continuousHorizontal', 'scrollHorizontally', 'interlockedSlides', 'resetSliders', 'responsiveSlides', 'offsetSections', 'dragAndMove', 'scrollOverflowReset', 'parallax']; 23379 //UNCODE.addition 23380 // if($('html').hasClass(ENABLED)){ 23381 // showError('error', 'Fullpage.js can only be initialized once and you are doing it multiple times!'); 23382 // return; 23383 // } 23384 23385 // Disable mutually exclusive settings 23386 //UNCODE.addition 23387 // if (options.continuousVertical && 23388 // (options.loopTop || options.loopBottom)) { 23389 // options.continuousVertical = false;
23390 // showError('warn', 'Option `loopTop/loopBottom` is mutually exclusive with `continuousVertical`; `continuousVertical` disabled'); 23391 // } 23392 23393 // if(options.scrollBar && options.scrollOverflow){ 23394 // showError('warn', 'Option `scrollBar` is mutually exclusive with `scrollOverflow`. Sections with scrollOverflow might not work well in Firefox'); 23395 // } 23396 23397 // if(options.continuousVertical && (options.scrollBar || !options.autoScrolling)){ 23398 // options.continuousVertical = false; 23399 // showError('warn', 'Scroll bars (`scrollBar:true` or `autoScrolling:false`) are mutually exclusive with `continuousVertical`; `continuousVertical` disabled'); 23400 // } 23401 23402 //using extensions? Wrong file! 23403 $.each(extensions, function(index, extension){ 23404 //is the option set to true? 23405 if(options[extension]){ 23406 showError('warn', 'fullpage.js extensions require jquery.fullpage.extensions.min.js file instead of the usual jquery.fullpage.js. Requested: '+ extension); 23407 } 23408 }); 23409 23410 //anchors can not have the same value as any element ID or NAME 23411 $.each(options.anchors, function(index, name){ 23412 23413 //case insensitive selectors (http://stackoverflow.com/a/19465187/1081396) 23414 var nameAttr = $document.find('[name]').filter(function() { 23415 return $(this).attr('name') && $(this).attr('name').toLowerCase() == name.toLowerCase(); 23416 }); 23417 23418 var idAttr = $document.find('[id]').filter(function() { 23419 return $(this).attr('id') && $(this).attr('id').toLowerCase() == name.toLowerCase(); 23420 }); 23421 23422 if(idAttr.length || nameAttr.length ){ 23423 showError('error', 'data-anchor tags can not have the same value as any `id` element on the site (or `name` element for IE).'); 23424 idAttr.length && showError('error', '"' + name + '" is is being used by another element `id` property'); 23425 nameAttr.length && showError('error', '"' + name + '" is is being used by another element `name` property'); 23426 } 23427 }); 23428 } 23429 23430 /** 23431 * Shows a message in the console of the given type. 23432 */ 23433 function showError(type, text){ 23434 console && console[type] && console[type]('fullPage: ' + text); 23435 } 23436 23437 }; //end of $.fn.fullpage 23438 23439 if(typeof IScroll !== 'undefined'){ 23440 /* 23441 * Turns iScroll `mousewheel` option off dynamically 23442 * https://github.com/cubiq/iscroll/issues/1036 23443 */ 23444 IScroll.prototype.wheelOn = function () { 23445 this.wrapper.addEventListener('wheel', this); 23446 this.wrapper.addEventListener('mousewheel', this); 23447 this.wrapper.addEventListener('DOMMouseScroll', this); 23448 }; 23449 23450 /* 23451 * Turns iScroll `mousewheel` option on dynamically 23452 * https://github.com/cubiq/iscroll/issues/1036 23453 */ 23454 IScroll.prototype.wheelOff = function () { 23455 this.wrapper.removeEventListener('wheel', this); 23456 this.wrapper.removeEventListener('mousewheel', this); 23457 this.wrapper.removeEventListener('DOMMouseScroll', this); 23458 }; 23459 } 23460 23461 /** 23462 * An object to handle overflow scrolling. 23463 * This uses jquery.slimScroll to accomplish overflow scrolling. 23464 * It is possible to pass in an alternate scrollOverflowHandler 23465 * to the fullpage.js option that implements the same functions 23466 * as this handler. 23467 * 23468 * @type {Object} 23469 */ 23470 var iscrollHandler = { 23471 refreshId: null, 23472 iScrollInstances: [], 23473 23474 // Enables or disables the mouse wheel for the active section or all slides in it 23475 toggleWheel: function(value){ 23476 var scrollable = $(SECTION_ACTIVE_SEL).find(SCROLLABLE_SEL); 23477 scrollable.each(function(){ 23478 var iScrollInstance = $(this).data('iscrollInstance'); 23479 if(typeof iScrollInstance !== 'undefined' && iScrollInstance){ 23480 if(value){ 23481 iScrollInstance.wheelOn(); 23482 } 23483 else{ 23484 iScrollInstance.wheelOff(); 23485 } 23486 } 23487 }); 23488 }, 23489 23490 /** 23491 * Turns off iScroll for the destination section. 23492 * When scrolling very fast on some trackpads (and Apple laptops) the inertial scrolling would
23493 * scroll the destination section/slide before the sections animations ends. 23494 */ 23495 onLeave: function(){ 23496 iscrollHandler.toggleWheel(false); 23497 }, 23498 23499 // Turns off iScroll for the leaving section 23500 beforeLeave: function(){ 23501 iscrollHandler.onLeave() 23502 }, 23503 23504 // Turns on iScroll on section load 23505 afterLoad: function(){ 23506 iscrollHandler.toggleWheel(true); 23507 }, 23508 23509 /** 23510 * Called when overflow scrolling is needed for a section. 23511 * 23512 * @param {Object} element jQuery object containing current section 23513 * @param {Number} scrollHeight Current window height in pixels 23514 */ 23515 create: function(element, scrollHeight) { 23516 var scrollable = element.find(SCROLLABLE_SEL); 23517 23518 scrollable.height(scrollHeight); 23519 scrollable.each(function() { 23520 var $this = $(this); 23521 var iScrollInstance = $this.data('iscrollInstance'); 23522 if (iScrollInstance) { 23523 $.each(iscrollHandler.iScrollInstances, function(){ 23524 $(this).destroy(); 23525 }); 23526 } 23527 23528 iScrollInstance = new IScroll($this.get(0), iscrollOptions); 23529 iscrollHandler.iScrollInstances.push(iScrollInstance); 23530 23531 //off by default until the section gets active 23532 iScrollInstance.wheelOff(); 23533 23534 $this.data('iscrollInstance', iScrollInstance); 23535 }); 23536 }, 23537 23538 /** 23539 * Return a boolean depending on whether the scrollable element is a 23540 * the end or at the start of the scrolling depending on the given type. 23541 * 23542 * @param {String} type Either 'top' or 'bottom' 23543 * @param {Object} scrollable jQuery object for the scrollable element 23544 * @return {Boolean} 23545 */ 23546 isScrolled: function(type, scrollable) { 23547 var scroller = scrollable.data('iscrollInstance'); 23548 23549 //no scroller? 23550 if (!scroller) { 23551 return true; 23552 } 23553 23554 if (type === 'top') { 23555 return scroller.y >= 0 && !scrollable.scrollTop(); 23556 } else if (type === 'bottom') { 23557 return (0 - scroller.y) + scrollable.scrollTop() + 1 + scrollable.innerHeight() >= scrollable[0].scrollHeight; 23558 } 23559 }, 23560 23561 /** 23562 * Returns the scrollable element for the given section. 23563 * If there are landscape slides, will only return a scrollable element 23564 * if it is in the active slide. 23565 * 23566 * @param {Object} activeSection jQuery object containing current section 23567 * @return {Boolean} 23568 */ 23569 scrollable: function(activeSection){ 23570 // if there are landscape slides, we check if the scrolling bar is in the current one or not 23571 if (activeSection.find(SLIDES_WRAPPER_SEL).length) { 23572 return activeSection.find(SLIDE_ACTIVE_SEL).find(SCROLLABLE_SEL); 23573 } 23574 return activeSection.find(SCROLLABLE_SEL); 23575 }, 23576 23577 /** 23578 * Returns the scroll height of the wrapped content. 23579 * If this is larger than the window height minus section padding, 23580 * overflow scrolling is needed. 23581 * 23582 * @param {Object} element jQuery object containing current section 23583 * @return {Number} 23584 */ 23585 scrollHeight: function(element) { 23586 return element.find(SCROLLABLE_SEL).children().first().get(0).scrollHeight; 23587 }, 23588 23589 /** 23590 * Called when overflow scrolling is no longer needed for a section. 23591 * 23592 * @param {Object} element jQuery object containing current section 23593 */ 23594 remove: function(element) { 23595 var scrollable = element.find(SCROLLABLE_SEL); 23596 if (scrollable.length) { 23597 var iScrollInstance = scrollable.data('iscrollInstance'); 23598 iScrollInstance.destroy(); 23599 23600 scrollable.data('iscrollInstance', null); 23601 } 23602 element.find(SCROLLABLE_SEL).children().first().children().first().unwrap().unwrap(); 23603 }, 23604 23605 /** 23606 * Called when overflow scrolling has already been setup but the 23607 * window height has potentially changed. 23608 * 23609 * @param {Object}
23609 element jQuery object containing current section 23610 * @param {Number} scrollHeight Current window height in pixels 23611 */ 23612 update: function(element, scrollHeight) { 23613 //using a timeout in order to execute the refresh function only once when `update` is called multiple times in a 23614 //short period of time. 23615 //it also comes on handy because iScroll requires the use of timeout when using `refresh`. 23616 clearTimeout(iscrollHandler.refreshId); 23617 iscrollHandler.refreshId = setTimeout(function(){ 23618 $.each(iscrollHandler.iScrollInstances, function(){ 23619 $(this).get(0).refresh(); 23620 }); 23621 }, 150); 23622 23623 //updating the wrappers height 23624 element.find(SCROLLABLE_SEL).css('height', scrollHeight + 'px').parent().css('height', scrollHeight + 'px'); 23625 }, 23626 23627 /** 23628 * Called to get any additional elements needed to wrap the section 23629 * content in order to facilitate overflow scrolling. 23630 * 23631 * @return {String|Object} Can be a string containing HTML, 23632 * a DOM element, or jQuery object. 23633 */ 23634 wrapContent: function() { 23635 return '<div class="' + SCROLLABLE + '"><div class="fp-scroller"></div></div>'; 23636 } 23637 }; 23638}); 23639 23640/* ======================================================================== 23641 * Bootstrap: collapse.js v3.1.1 23642 * http://getbootstrap.com/javascript/#collapse 23643 * ======================================================================== 23644 * Copyright 2011-2014 Twitter, Inc. 23645 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 23646 * ======================================================================== */ 23647 23648 23649+function ($) { 23650 'use strict'; 23651 23652 // COLLAPSE PUBLIC CLASS DEFINITION 23653 // ================================ 23654 23655 var Collapse = function (element, options) { 23656 this.$element = $(element) 23657 this.options = $.extend({}, Collapse.DEFAULTS, options) 23658 this.transitioning = null 23659 23660 if (this.options.parent) this.$parent = $(this.options.parent) 23661 if (this.options.toggle) this.toggle() 23662 } 23663 23664 Collapse.DEFAULTS = { 23665 toggle: true 23666 } 23667 23668 Collapse.prototype.dimension = function () { 23669 var hasWidth = this.$element.hasClass('width') 23670 return hasWidth ? 'width' : 'height' 23671 } 23672 23673 Collapse.prototype.show = function () { 23674 if (this.transitioning || this.$element.hasClass('in')) return 23675 23676 var startEvent = $.Event('show.bs.collapse') 23677 this.$element.trigger(startEvent) 23678 if (startEvent.isDefaultPrevented()) return 23679 23680 var actives = this.$parent && this.$parent.find('> .panel > .in') 23681 23682 if (actives && actives.length) { 23683 var hasData = actives.data('bs.collapse') 23684 if (hasData && hasData.transitioning) return 23685 actives.collapse('hide') 23686 hasData || actives.data('bs.collapse', null) 23687 } 23688 23689 var dimension = this.dimension() 23690 23691 this.$element 23692 .removeClass('collapse') 23693 .addClass('collapsing')[dimension](0) 23694 23695 this.transitioning = 1 23696 23697 var complete = function (e) { 23698 if (e && e.target != this.$element[0]) return 23699 this.$element 23700 .removeClass('collapsing') 23701 .addClass('collapse in')[dimension]('auto') 23702 this.transitioning = 0 23703 this.$element.trigger('shown.bs.collapse') 23704 } 23705 23706 if (!$.support.transition) return complete.call(this) 23707 23708 var scrollSize = $.camelCase(['scroll', dimension].join('-')) 23709 23710 this.$element 23711 .one($.support.transition.end, $.proxy(complete, this)) 23712 .emulateTransitionEnd(350)[dimension](this.$element[0][scrollSize]) 23713 } 23714 23715 Collapse.prototype.hide = function () { 23716 if (this.transitioning || !this.$element.hasClass('in')) return 23717 23718 var startEvent = $.Event('hide.bs.collapse') 23719 this.$element.trigger(startEvent) 23720 if (startEvent.isDefaultPrevented()) return 23721 23722 var dimension = this.dimension() 23723 23724 this.$element[dimension](this.$element[dimension]())[0].offsetHeight 23725 23726 this.$element 23727 .addClass('collapsing') 23728 .removeClass('collapse') 23729 .removeClass('in') 23730 23731 this.transitioning = 1 23732 23733 var complete = function (e) { 23734 if (e && e.target != this.$element[0]) return 23735 this.transitioning = 0 23736 this.$element 23737 .trigger('hidden.bs.collapse') 23738 .removeClass('collapsing') 23739 .addClass('collapse') 23740 } 23741 23742 if (!$.support.transition) return complete.call(this) 23743 23744 this.$element 23745 [dimension](0) 23746 .one($.support.transition.end, $.proxy(complete, this)) 23747 .emulateTransitionEnd(350) 23748 } 23749 23750 Collapse.prototype.toggle = function () { 23751 this[this.$element.hasClass('in') ? 'hide' : 'show']() 23752 } 23753 23754 23755 // COLLAPSE PLUGIN DEFINITION 23756 // ========================== 23757 23758 var old = $.fn.collapse 23759 23760 $.fn.collapse = function (option) { 23761 return this.each(function () { 23762 var $this = $(this) 23763 var data = $this.data('bs.collapse') 23764 var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) 23765 23766 if (!data && options.toggle && option == 'show') option = !option 23767 if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) 23768 if (typeof option == 'string') data[option]() 23769 }) 23770 } 23771 23772 $.fn.collapse.Constructor = Collapse 23773 23774 23775 // COLLAPSE NO CONFLICT 23776 // ==================== 23777 23778 $.fn.collapse.noConflict = function () { 23779 $.fn.collapse = old 23780 return this 23781 } 23782 23783 23784 // COLLAPSE DATA-API 23785 // ================= 23786 23787 $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) { 23788 var $this = $(this), href 23789 var target = $this.attr('data-target') 23790 || e.preventDefault() 23791 || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 23792 //Edited by Uncode to replace ID in panel [START] 23793 var _target = href.replace(/^#/, ""); 23794 if ( $('[data-id="' + _target + '"]').length ) { 23795 var $target = $('[data-id="' + _target + '"]') 23796 } else { 23797 var $target = $(target) 23798 } 23799 //Edited by Uncode to replace ID in panel [END] 23800 var data = $target.data('bs.collapse') 23801 var option = data ? 'toggle' : $this.data() 23802 var parent = $this.attr('data-parent') 23803 var $parent = parent && $(parent) 23804 23805 if (!data || !data.transitioning) { 23806 if ($parent) $parent.find('[data-toggle="collapse"][data-parent="' + parent + '"]').not($this).addClass('collapsed') 23807 $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed') 23808 } 23809 23810 $target.collapse(option) 23811 }) 23812 23813}(jQuery); 23814 23815/* ======================================================================== 23816 * Bootstrap: tab.js v3.1.1 23817 * http://getbootstrap.com/javascript/#tabs 23818 * ======================================================================== 23819 * Copyright 2011-2014 Twitter, Inc. 23820 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 23821 * ======================================================================== */ 23822 23823 23824+function ($) { 23825 'use strict'; 23826 23827 // TAB CLASS DEFINITION 23828 // ==================== 23829 23830 var Tab = function (element) { 23831 this.element = $(element) 23832 } 23833 23834 Tab.prototype.show = function () { 23835 var $this = this.element 23836 var $ul = $this.closest('ul:not(.dropdown-menu)') 23837 var selector = $this.data('target') 23838 23839 if (!selector) { 23840 selector = $this.attr('href') 23841 selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 23842 } 23843 23844 if ($this.parent('li').hasClass('active')) return 23845 23846 var previous = $ul.find('.active:last a')[0] 23847 var e = $.Event('show.bs.tab', { 23848 relatedTarget: previous 23849 }) 23850 23851 $this.trigger(e) 23852 23853 if (e.isDefaultPrevented()) return 23854 23855 //Edited by Uncode to replace ID in panel [START] 23856 var _target = selector.replace(/^#/, ""); 23857 if ( $('[data-id="' + _target + '"]').length ) 23858 var $target = $('[data-id="' + _target + '"]') 23859 else 23860 var $target = $(selector) 23861 //Edited by Uncode to replace ID in panel [END] 23862 23863 this.activate($this.parent('li'), $ul) 23864 this.activate($target, $target.parent(), function () { 23865 $this.trigger({ 23866 type: 'shown.bs.tab', 23867 relatedTarget: previous 23868 }) 23869 }) 23870 } 23871 23872 Tab.prototype.activate = function (element, container, callback) { 23873 var $active = container.find('> .active') 23874 var transition = callback 23875 && $.support.transition 23876 && $active.hasClass('fade') 23877 23878 function next() { 23879 $active 23880 .removeClass('active') 23881 .find('> .dropdown-menu > .active') 23882 .removeClass('active') 23883 23884 element.addClass('active') 23885 23886 if (transition) { 23887 element[0].offsetWidth // reflow for transition 23888 element.addClass('in') 23889 } else { 23890 element.removeClass('fade') 23891 } 23892 23893 if (element.parent('.dropdown-menu')) { 23894 element.closest('li.dropdown').addClass('active') 23895 } 23896 23897 callback && callback() 23898 } 23899 23900 transition ? 23901 $active 23902 .one($.support.transition.end, next) 23903 .emulateTransitionEnd(150) : 23904 next() 23905 23906 $active.removeClass('in') 23907 } 23908 23909 23910 // TAB PLUGIN DEFINITION 23911 // ===================== 23912 23913 var old = $.fn.tab 23914 23915 $.fn.tab = function ( option ) { 23916 return this.each(function () { 23917 var $this = $(this) 23918 var data = $this.data('bs.tab') 23919 23920 if (!data) $this.data('bs.tab', (data = new Tab(this))) 23921 if (typeof option == 'string') data[option]() 23922 }) 23923 } 23924 23925 $.fn.tab.Constructor = Tab 23926 23927 23928 // TAB NO CONFLICT 23929 // =============== 23930 23931 $.fn.tab.noConflict = function () { 23932 $.fn.tab = old 23933 return this 23934 } 23935 23936 23937 // TAB DATA-API 23938 // ============ 23939 23940 $(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) { 23941 e.preventDefault() 23942 $(this).tab('show') 23943 }) 23944 23945}(jQuery); 23946 23947/* ======================================================================== 23948 * Bootstrap: tooltip.js v3.1.1 23949 * http://getbootstrap.com/javascript/#tooltip 23950 * Inspired by the original jQuery.tipsy by Jason Frame 23951 * ======================================================================== 23952 * Copyright 2011-2014 Twitter, Inc. 23953 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 23954 * ======================================================================== */ 23955 23956 23957+function ($) { 23958 'use strict'; 23959 23960 // TOOLTIP PUBLIC CLASS DEFINITION 23961 // =============================== 23962 23963 var Tooltip = function (element, options) { 23964 this.type = 23965 this.options = 23966 this.enabled = 23967 this.timeout = 23968 this.hoverState = 23969 this.$element = null 23970 23971 this.init('tooltip', element, options) 23972 } 23973 23974 Tooltip.DEFAULTS = { 23975 animation: true, 23976 placement: 'top', 23977 selector: false, 23978 template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>', 23979 trigger: 'hover focus', 23980 title: '', 23981 delay: 0, 23982 html: false, 23983 container: false, 23984 viewport: { 23985 selector: 'body', 23986 padding: 0 23987 } 23988 } 23989 23990 Tooltip.prototype.init = function (type, element, options) { 23991 this.enabled = true 23992 this.type = type 23993 this.$element = $(element) 23994 this.options = this.getOptions(options) 23995 this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport) 23996 23997 var triggers = this.options.trigger.split(' ') 23998 23999 for (var i = triggers.length; i--;) { 24000 var trigger = triggers[i] 24001 24002 if (trigger == 'click') { 24003 this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this)) 24004 } else if (trigger != 'manual') { 24005 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin' 24006 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout' 24007 24008 this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this)) 24009 this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this)) 24010 } 24011 } 24012 24013 this.options.selector ? 24014 (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) : 24015 this.fixTitle() 24016 } 24017 24018 Tooltip.prototype.getDefaults = function () { 24019 return Tooltip.DEFAULTS 24020 } 24021 24022 Tooltip.prototype.getOptions = function (options) { 24023 options = $.extend({}, this.getDefaults(), this.$element.data(), options) 24024 24025 if (options.delay && typeof options.delay == 'number') { 24026 options.delay = { 24027 show: options.delay, 24028 hide: options.delay 24029 } 24030 } 24031 24032 return options 24033 } 24034 24035 Tooltip.prototype.getDelegateOptions = function () { 24036 var options = {} 24037 var defaults = this.getDefaults() 24038 24039 this._options && $.each(this._options, function (key, value) { 24040 if (defaults[key] != value) options[key] = value 24041 }) 24042 24043 return options 24044 } 24045 24046 Tooltip.prototype.enter = function (obj) { 24047 var self = obj instanceof this.constructor ? 24048 obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) 24049 24050 clearTimeout(self.timeout) 24051 24052 self.hoverState = 'in' 24053 24054 if (!self.options.delay || !self.options.delay.show) return self.show() 24055 24056 self.timeout = setTimeout(function () { 24057 if (self.hoverState == 'in') self.show() 24058 }, self.options.delay.show) 24059 } 24060 24061 Tooltip.prototype.leave = function (obj) { 24062 var self = obj instanceof this.constructor ? 24063 obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) 24064 24065 clearTimeout(self.timeout) 24066 24067 self.hoverState = 'out' 24068 24069 if (!self.options.delay || !self.options.delay.hide) return self.hide() 24070 24071 self.timeout = setTimeout(function () { 24072 if (self.hoverState == 'out') self.hide() 24073 }, self.options.delay.hide) 24074 } 24075 24076 Tooltip.prototype.show = function () { 24077 var e = $.Event('show.bs.' + this.type) 24078 24079 if (this.hasContent() && this.enabled) { 24080 this.$element.trigger(e) 24081 24082 if (e.isDefaultPrevented()) return 24083 var that = this; 24084 24085 var $tip = this.tip() 24086 24087 this.setContent() 24088 24089 if (this.options.animation) $tip.addClass('fade') 24090 24091 var placement = typeof this.options.placement == 'function' ? 24092 this.options.placement.call(this, $tip[0], this.$element[0]) : 24093 this.options.placement 24094 24095 var autoToken = /\s?auto?\s?/i 24096 var autoPlace = autoToken.test(placement) 24097 if (autoPlace) placement = placement.replace(autoToken, '') || 'top' 24098 24099 $tip 24100 .detach() 24101 .css({ top: 0, left: 0, display: 'block' }) 24102 .addClass(placement) 24103 24104 this.options.container ? $tip.appendTo($(document).find(this.options.container)) : $tip.insertAfter(this.$element) 24105 24106 var pos = this.getPosition() 24107 var actualWidth = $tip[0].offsetWidth 24108 var actualHeight = $tip[0].offsetHeight 24109 24110 if (autoPlace) { 24111 var orgPlacement = placement 24112 var $parent = this.$element.parent() 24113 var parentDim = this.getPosition($parent) 24114 24115 placement = placement == 'bottom' && pos.top + pos.height + actualHeight - parentDim.scroll > parentDim.height ? 'top' : 24116 placement == 'top' && pos.top - parentDim.scroll - actualHeight < 0 ? 'bottom' : 24117 placement == 'right' && pos.right + actualWidth > parentDim.width ? 'left' : 24118 placement == 'left' && pos.left - actualWidth < parentDim.left ? 'right' : 24119 placement 24120 24121 $tip 24122 .removeClass(orgPlacement) 24123 .addClass(placement) 24124 } 24125 24126 var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight) 24127 24128 this.applyPlacement(calculatedOffset, placement) 24129 this.hoverState = null 24130 24131 var complete = function() { 24132 that.$element.trigger('shown.bs.' + that.type) 24133 } 24134 24135 $.support.transition && this.$tip.hasClass('fade') ? 24136 $tip 24137 .one($.support.transition.end, complete) 24138 .emulateTransitionEnd(150) : 24139 complete() 24140 } 24141 } 24142 24143 Tooltip.prototype.applyPlacement = function (offset, placement) { 24144 var $tip = this.tip() 24145 var width = $tip[0].offsetWidth 24146 var height = $tip[0].offsetHeight 24147 24148 // manually read margins because getBoundingClientRect includes difference 24149 var marginTop = parseInt($tip.css('margin-top'), 10) 24150 var marginLeft = parseInt($tip.css('margin-left'), 10) 24151 24152 // we must check
24152 for NaN for ie 8/9 24153 if (isNaN(marginTop)) marginTop = 0 24154 if (isNaN(marginLeft)) marginLeft = 0 24155 24156 offset.top = offset.top + marginTop 24157 offset.left = offset.left + marginLeft 24158 24159 // $.fn.offset doesn't round pixel values 24160 // so we use setOffset directly with our own function B-0 24161 $.offset.setOffset($tip[0], $.extend({ 24162 using: function (props) { 24163 $tip.css({ 24164 top: Math.round(props.top), 24165 left: Math.round(props.left) 24166 }) 24167 } 24168 }, offset), 0) 24169 24170 $tip.addClass('in') 24171 24172 // check to see if placing tip in new offset caused the tip to resize itself 24173 var actualWidth = $tip[0].offsetWidth 24174 var actualHeight = $tip[0].offsetHeight 24175 24176 if (placement == 'top' && actualHeight != height) { 24177 offset.top = offset.top + height - actualHeight 24178 } 24179 24180 var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight) 24181 24182 if (delta.left) offset.left += delta.left 24183 else offset.top += delta.top 24184 24185 var arrowDelta = delta.left ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight 24186 var arrowPosition = delta.left ? 'left' : 'top' 24187 var arrowOffsetPosition = delta.left ? 'offsetWidth' : 'offsetHeight' 24188 24189 $tip.offset(offset) 24190 this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], arrowPosition) 24191 } 24192 24193 Tooltip.prototype.replaceArrow = function (delta, dimension, position) { 24194 this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + '%') : '') 24195 } 24196 24197 Tooltip.prototype.setContent = function () { 24198 var $tip = this.tip() 24199 var title = this.getTitle() 24200 24201 $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title) 24202 $tip.removeClass('fade in top bottom left right') 24203 } 24204 24205 Tooltip.prototype.hide = function () { 24206 var that = this 24207 var $tip = this.tip() 24208 var e = $.Event('hide.bs.' + this.type) 24209 24210 function complete() { 24211 if (that.hoverState != 'in') $tip.detach() 24212 that.$element.trigger('hidden.bs.' + that.type) 24213 } 24214 24215 this.$element.trigger(e) 24216 24217 if (e.isDefaultPrevented()) return 24218 24219 $tip.removeClass('in') 24220 24221 $.support.transition && this.$tip.hasClass('fade') ? 24222 $tip 24223 .one($.support.transition.end, complete) 24224 .emulateTransitionEnd(150) : 24225 complete() 24226 24227 this.hoverState = null 24228 24229 return this 24230 } 24231 24232 Tooltip.prototype.fixTitle = function () { 24233 var $e = this.$element 24234 if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') { 24235 $e.attr('data-original-title', $e.attr('title') || '').attr('title', '') 24236 } 24237 } 24238 24239 Tooltip.prototype.hasContent = function () { 24240 return this.getTitle() 24241 } 24242 24243 Tooltip.prototype.getPosition = function ($element) { 24244 $element = $element || this.$element 24245 var el = $element[0] 24246 var isBody = el.tagName == 'BODY' 24247 return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : null, { 24248 scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop(), 24249 width: isBody ? $(window).width() : $element.outerWidth(), 24250 height: isBody ? $(window).height() : $element.outerHeight() 24251 }, isBody ? {top: 0, left: 0} : $element.offset()) 24252 } 24253 24254 Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) { 24255 return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } : 24256 placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } : 24257 placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } : 24258 /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width } 24259 24260 } 24261 24262 Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) { 24263 var delta = { top: 0, left: 0 } 24264 if (!this.$viewport) return delta 24265 24266 var viewportPadding = this.options.viewport && this.options.viewport.padding || 0 24267 var viewportDimensions = this.getPosition(this.$viewport) 24268 24269 if (/right|left/.test(placement)) { 24270 var topEdgeOffset = pos.top - viewportPadding - viewportDimensions.scroll 24271 var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight 24272 if (topEdgeOffset < viewportDimensions.top) { // top overflow 24273 delta.top = viewportDimensions.top - topEdgeOffset 24274 } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow 24275 delta.top = viewportDimensions.top + viewportDimensions.height - bottom
24275EdgeOffset 24276 } 24277 } else { 24278 var leftEdgeOffset = pos.left - viewportPadding 24279 var rightEdgeOffset = pos.left + viewportPadding + actualWidth 24280 if (leftEdgeOffset < viewportDimensions.left) { // left overflow 24281 delta.left = viewportDimensions.left - leftEdgeOffset 24282 } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow 24283 delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset 24284 } 24285 } 24286 24287 return delta 24288 } 24289 24290 Tooltip.prototype.getTitle = function () { 24291 var title 24292 var $e = this.$element 24293 var o = this.options 24294 24295 title = $e.attr('data-original-title') 24296 || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title) 24297 24298 return title 24299 } 24300 24301 Tooltip.prototype.tip = function () { 24302 return this.$tip = this.$tip || $(this.options.template) 24303 } 24304 24305 Tooltip.prototype.arrow = function () { 24306 return this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow') 24307 } 24308 24309 Tooltip.prototype.validate = function () { 24310 if (!this.$element[0].parentNode) { 24311 this.hide() 24312 this.$element = null 24313 this.options = null 24314 } 24315 } 24316 24317 Tooltip.prototype.enable = function () { 24318 this.enabled = true 24319 } 24320 24321 Tooltip.prototype.disable = function () { 24322 this.enabled = false 24323 } 24324 24325 Tooltip.prototype.toggleEnabled = function () { 24326 this.enabled = !this.enabled 24327 } 24328 24329 Tooltip.prototype.toggle = function (e) { 24330 var self = e ? $(e.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) : this 24331 self.tip().hasClass('in') ? self.leave(self) : self.enter(self) 24332 } 24333 24334 Tooltip.prototype.destroy = function () { 24335 clearTimeout(this.timeout) 24336 this.hide().$element.off('.' + this.type).removeData('bs.' + this.type) 24337 } 24338 24339 24340 // TOOLTIP PLUGIN DEFINITION 24341 // ========================= 24342 24343 var old = $.fn.tooltip 24344 24345 $.fn.tooltip = function (option) { 24346 return this.each(function () { 24347 var $this = $(this) 24348 var data = $this.data('bs.tooltip') 24349 var options = typeof option == 'object' && option 24350 24351 if (!data && option == 'destroy') return 24352 if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options))) 24353 if (typeof option == 'string') data[option]() 24354 }) 24355 } 24356 24357 $.fn.tooltip.Constructor = Tooltip 24358 24359 24360 // TOOLTIP NO CONFLICT 24361 // =================== 24362 24363 $.fn.tooltip.noConflict = function () { 24364 $.fn.tooltip = old 24365 return this 24366 } 24367 24368}(jQuery); 24369 24370/* ======================================================================== 24371 * Bootstrap: transition.js v3.1.1 24372 * http://getbootstrap.com/javascript/#transitions 24373 * ======================================================================== 24374 * Copyright 2011-2014 Twitter, Inc. 24375 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 24376 * ======================================================================== */ 24377 24378 24379+function ($) { 24380 'use strict'; 24381 24382 // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) 24383 // ============================================================ 24384 24385 function transitionEnd() { 24386 var el = document.createElement('bootstrap') 24387 24388 var transEndEventNames = { 24389 WebkitTransition : 'webkitTransitionEnd', 24390 MozTransition : 'transitionend', 24391 OTransition : 'oTransitionEnd otransitionend', 24392 transition : 'transitionend' 24393 } 24394 24395 for (var name in transEndEventNames) { 24396 if (el.style[name] !== undefined) { 24397 return { end: transEndEventNames[name] } 24398 } 24399 } 24400 24401 return false // explicit for ie8 ( ._.) 24402 } 24403 24404 // http://blog.alexmaccaw.com/css-transitions 24405 $.fn.emulateTransitionEnd = function (duration) { 24406 var called = false, $el = this 24407 $(this).one($.support.transition.end, function () { called = true }) 24408 var callback = function () { if (!called) $($el).trigger($.support.transition.end) } 24409 setTimeout(callback, duration) 24410 return this 24411 } 24412 24413 $(function () { 24414 $.support.transition = transitionEnd() 24415 }) 24416 24417}(jQuery);
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.