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 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)), 8256 8257 // Events 8258 clickEvent = supportTouch ? "itap.iLightBox" : "click.iLightBox", 8259 touchStartEvent = supportTouch ? "touchstart.iLightBox" : "mousedown.iLightBox", 8260 touchStopEvent = supportTouch ? "touchend.iLightBox" : "mouseup.iLightBox", 8261 touchMoveEvent = supportTouch ? "touchmove.iLightBox" : "mousemove.iLightBox", 8262 8263 // Math shorthands 8264 abs = Math.abs, 8265 sqrt = Math.sqrt, 8266 round = Math.round, 8267 max = Math.max, 8268 min = Math.min, 8269 floor = Math.floor, 8270 random = Math.random, 8271 8272 pluginspages = { 8273 quicktime: 'http://www.apple.com/quicktime/download', 8274 flash: 'http://www.adobe.com/go/getflash' 8275 }, 8276 8277 iLightBox = function(el, options, items, instant) { 8278 var iL = this; 8279 8280 iL.options = options, 8281 iL.selector = el.selector || el, 8282 iL.context = el.context, 8283 iL.instant = instant; 8284 8285 if (items.length < 1) iL.attachItems(); 8286 else iL.items = items; 8287 8288 iL.vars = { 8289 total: iL.items.length, 8290 start: 0, 8291 current: null, 8292 next: null, 8293 prev: null, 8294 BODY: $('body'), 8295 loadRequests: 0, 8296 overlay: $('<div class="ilightbox-overlay"></div>'), 8297 loader: $('<div class="ilightbox-loader"><div></div></div>'), 8298 toolbar: $('<div class="ilightbox-toolbar"></div>'), 8299 innerToolbar: $('<div class="ilightbox-inner-toolbar"></div>'), 8300 title: $('<div class="ilightbox-title"></div>'), 8301 closeButton: $('<a class="ilightbox-close" title="' + iL.options.text.close + '"></a>'), 8302 fullScreenButton: $('<a class="ilightbox-fullscreen" title="' + iL.options.text.enterFullscreen + '"></a>'), 8303 innerPlayButton: $('<a class="ilightbox-play" title="' + iL.options.text.slideShow + '"></a>'), 8304 innerNextButton: $('<a class="ilightbox-next-button" title="' + iL.options.text.next + '"></a>'), 8305 innerPrevButton: $('<a class="ilightbox-prev-button" title="' + iL.options.text.previous + '"></a>'), 8306 holder: $('<div class="ilightbox-holder' + (supportTouch ? ' supportTouch' : '') + '" ondragstart="return false;"><div class="ilightbox-container"></div></div>'), 8307 nextPhoto: $('<div class="ilightbox-holder' + (supportTouch ? ' supportTouch' : '') + ' ilightbox-next" ondragstart="return false;"><div class="ilightbox-container"></div></div>'), 8308 prevPhoto: $('<div class="ilightbox-holder' + (supportTouch ? ' supportTouch' : '') + ' ilightbox-prev" ondragstart="return false;"><div class="ilightbox-container"></div></div>'), 8309 nextButton: $('<a class="ilightbox-button ilightbox-next-button" ondragstart="return false;" title="' + iL.options.text.next + '"><span></span></a>'), 8310 prevButton: $('<a class="ilightbox-button ilightbox-prev-button" ondragstart="return false;" title="' + iL.options.text.previous + '"><span></span></a>'),
8311 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>'), 8312 thumbs: false, 8313 nextLock: false, 8314 prevLock: false, 8315 hashLock: false, 8316 isMobile: false, 8317 mobileMaxWidth: 980, 8318 isInFullScreen: false, 8319 isSwipe: false, 8320 mouseID: 0, 8321 cycleID: 0, 8322 isPaused: 0, 8323 captionHeight: 39, 8324 }; 8325 8326 // Hideable elements with mousemove event 8327 iL.vars.hideableElements = iL.vars.nextButton.add(iL.vars.prevButton); 8328 8329 iL.normalizeItems(); 8330 8331 //Check necessary plugins 8332 iL.availPlugins(); 8333 8334 //Set startFrom 8335 iL.options.startFrom = (iL.options.startFrom > 0 && iL.options.startFrom >= iL.vars.total) ? iL.vars.total - 1 : iL.options.startFrom; 8336 8337 //If randomStart 8338 iL.options.startFrom = (iL.options.randomStart) ? floor(random() * iL.vars.total) : iL.options.startFrom; 8339 iL.vars.start = iL.options.startFrom; 8340 8341 if (instant) iL.instantCall(); 8342 else iL.patchItemsEvents(); 8343 8344 if (iL.options.linkId) { 8345 iL.hashChangeHandler(); 8346 $win.iLightBoxHashChange(function() { 8347 iL.hashChangeHandler(); 8348 }); 8349 } 8350 8351 if (supportTouch) { 8352 var RegExp = /(click|mouseenter|mouseleave|mouseover|mouseout)/ig, 8353 replace = "itap"; 8354 iL.options.caption.show = iL.options.caption.show.replace(RegExp, replace), 8355 iL.options.caption.hide = iL.options.caption.hide.replace(RegExp, replace), 8356 iL.options.social.show = iL.options.social.show.replace(RegExp, replace), 8357 iL.options.social.hide = iL.options.social.hide.replace(RegExp, replace); 8358 } 8359 8360 if (iL.options.controls.arrows || $(window).width() < UNCODE.mediaQuery) { 8361 $.extend(iL.options.styles, { 8362 nextOffsetX: ($(window).width() > UNCODE.mediaQuery) ? 36 : 4, 8363 prevOffsetX: ($(window).width() > UNCODE.mediaQuery) ? 36 : 4, 8364 nextOpacity: 0, 8365 prevOpacity: 0 8366 }); 8367 } 8368 }; 8369 8370 //iLightBox helpers 8371 iLightBox.prototype = { 8372 showLoader: function() { 8373 var iL = this; 8374 iL.vars.loadRequests += 1; 8375 if (iL.options.path.toLowerCase() == "horizontal") iL.vars.loader.addClass('ilightbox-show').stop().animate({ 8376 //top: '-30px' 8377 opacity: '1' 8378 }, iL.options.show.speed, 'easeOutCirc'); 8379 else iL.vars.loader.addClass('ilightbox-show').stop().animate({ 8380 //left: '-30px' 8381 opacity: '1' 8382 }, iL.options.show.speed, 'easeOutCirc'); 8383 }, 8384 8385 hideLoader: function() { 8386 var iL = this; 8387 iL.vars.loadRequests -= 1; 8388 iL.vars.loadRequests = (iL.vars.loadRequests < 0) ? 0 : iL.vars.loadRequests; 8389 if (iL.options.path.toLowerCase() == "horizontal") { 8390 if (iL.vars.loadRequests <= 0) iL.vars.loader.removeClass('ilightbox-show').stop().animate({ 8391 //top: '-192px' 8392 opacity: '0' 8393 }, iL.options.show.speed, 'easeInCirc'); 8394 } else { 8395 if (iL.vars.loadRequests <= 0) iL.vars.loader.removeClass('ilightbox-show').stop().animate({ 8396 //left: '-192px' 8397 opacity: '0' 8398 }, iL.options.show.speed, 'easeInCirc'); 8399 } 8400 }, 8401 8402 createUI: function() { 8403 var iL = this; 8404 8405 iL.ui = { 8406 currentElement: iL.vars.holder, 8407 nextElement: iL.vars.nextPhoto, 8408 prevElement: iL.vars.prevPhoto, 8409 currentItem: iL.vars.current, 8410 nextItem: iL.vars.next, 8411 prevItem: iL.vars.prev, 8412 hide: function() { 8413 iL.closeAction(); 8414 }, 8415 refresh: function() { 8416 (arguments.length > 0) ? iL.repositionPhoto(true): iL.repositionPhoto(); 8417 }, 8418 fullscreen: function() { 8419 iL.fullScreenAction(); 8420 } 8421 }; 8422 }, 8423 8424 attachItems: function() { 8425 var iL = this, 8426 itemsObject = new Array(), 8427 items = new Array(); 8428 8429 $(iL.selector, iL.context).each(function() { 8430 var t = $(this), 8431 URL = t.attr(iL.options.attr) || null, 8432 options = t.data("options") && eval("({" + t.data("options") + "})") || {}, 8433 caption = t.data('caption'), 8434 title = t.data('title'), 8435 type = t.data('type') || getTypeByExtension(URL), 8436 clone = t.data('lbox-clone') || false; 8437 8438 if (t.data('lbox-clone') != undefined) return; 8439 8440 //Uncode addition ##START## 8441 if ( typeof t.attr('data-album') != 'undefined' && t.attr('data-album') != '' ) { 8442 var ALBUM_URLS = JSON.parse(t.attr('data-album')), 8443 URL_i, 8444 URLS_LENGHT = ALBUM_URLS.length; 8445 for (URL_i = 0; URL_i < URLS_LENGHT; URL_i++) { 8446 if ( typeof ALBUM_URLS[URL_i].url !== 'undefined' && ALBUM_URLS[URL_i].url != '' ) { 8447 var item_opts = 'width:' + ALBUM_URLS[URL_i].width + ',height:' + ALBUM_URLS[URL_i].height + ',thumbnail: \'' + ALBUM_URLS[URL_i].thumbnail + '\''; 8448 item_opts = item_opts && eval("({" + item_opts + "})") || {}, 8449 items.push({ 8450 URL: ALBUM_URLS[URL_i].url, 8451 caption: ALBUM_URLS[URL_i].caption, 8452 title: ALBUM_URLS[URL_i].title, 8453 type: getTypeByExtension(ALBUM_URLS[URL_i].url), 8454 options: item_opts, 8455 clone: clone 8456 }); 8457 var newT = t; 8458 newT.attr('href',ALBUM_URLS[URL_i].url); 8459 if (!iL.instant) itemsObject.push(newT); 8460 } 8461 } 8462 } else { 8463 //Uncode addition ##END## 8464 items.push({ 8465 URL: URL, 8466 caption: caption, 8467 title: title, 8468 type: type, 8469 options: options, 8470 clone: clone 8471 }); 8472 } 8473 8474 8475 if (iL.vars != undefined) iL.vars.total = items.length; 8476 8477 if (!iL.instant) itemsObject.push(t); 8478 }); 8479 8480 iL.items = items, 8481 iL.itemsObject = itemsObject; 8482 8483 }, 8484 8485 normalizeItems: function() { 8486 var iL = this, 8487 newItems = new Array(); 8488 8489 $.each(iL.items, function(key, val) { 8490 8491 if (typeof val == "string") val = { 8492 url: val 8493 }; 8494 8495 var URL = val.url || val.URL || null, 8496 options = val.options || {}, 8497 caption = val.caption || null, 8498 title = val.title || null, 8499 type = (val.type) ? val.type.toLowerCase() : getTypeByExtension(URL), 8500 ext = (typeof URL != 'object') ? getExtension(URL) : ''; 8501 8502 options.thumbnail = options.thumbnail || ((type == "image") ? URL : null),
8503 options.videoType = options.videoType || null, 8504 options.skin = options.skin || iL.options.skin, 8505 options.width = options.width || null, 8506 options.height = options.height || null, 8507 options.mousewheel = (typeof options.mousewheel != 'undefined') ? options.mousewheel : true, 8508 options.swipe = (typeof options.swipe != 'undefined') ? options.swipe : true, 8509 options.social = (typeof options.social != 'undefined') ? options.social : iL.options.social.buttons && $.extend({}, {}, iL.options.social.buttons); 8510 8511 if (type == "video") { 8512 options.html5video = (typeof options.html5video != 'undefined') ? options.html5video : {}; 8513 8514 options.html5video.webm = options.html5video.webm || options.html5video.WEBM || null; 8515 options.html5video.controls = (typeof options.html5video.controls != 'undefined') ? options.html5video.controls : "controls"; 8516 options.html5video.preload = options.html5video.preload || "metadata"; 8517 options.html5video.autoplay = (typeof options.html5video.autoplay != 'undefined') ? options.html5video.autoplay : false; 8518 //UNCODE addition 8519 options.html5video.loop = (typeof options.html5video.loop != 'undefined') ? options.html5video.loop : false; 8520 } 8521 8522 if (!options.width || !options.height) { 8523 if (type == "video") options.width = 1280, options.height = 720; 8524 else if (type == "iframe") options.width = '100%', options.height = '90%'; 8525 else if (type == "flash") options.width = 1280, options.height = 720; 8526 } 8527 8528 delete val.url; 8529 val.index = key; 8530 val.URL = URL; 8531 val.caption = caption; 8532 val.title = title; 8533 val.type = type; 8534 val.options = options; 8535 val.ext = ext; 8536 8537 newItems.push(val); 8538 }); 8539 8540 iL.items = newItems; 8541 }, 8542 8543 instantCall: function() { 8544 var iL = this, 8545 key = iL.vars.start; 8546 8547 iL.vars.current = key; 8548 iL.vars.next = (iL.items[key + 1]) ? key + 1 : null; 8549 iL.vars.prev = (iL.items[key - 1]) ? key - 1 : null; 8550 8551 iL.addContents(); 8552 iL.patchEvents(); 8553 }, 8554 8555 addContents: function() { 8556 var iL = this, 8557 vars = iL.vars, 8558 opts = iL.options, 8559 viewport = getViewport(), 8560 path = opts.path.toLowerCase(), 8561 recognizingItems = vars.total > 0 && iL.items.filter(function(e, i, arr) { 8562 return ['image', 'flash', 'video'].indexOf(e.type) === -1 && typeof e.recognized === 'undefined' && (opts.smartRecognition || e.options.smartRecognition); 8563 }), 8564 needRecognition = recognizingItems.length > 0; 8565 8566 if (opts.mobileOptimizer && !opts.innerToolbar) 8567 vars.isMobile = viewport.width <= vars.mobileMaxWidth; 8568 8569 vars.overlay.addClass(opts.skin).hide().css('opacity', opts.overlay.opacity); 8570 8571 if (opts.linkId) 8572 vars.overlay[0].setAttribute('linkid', opts.linkId); 8573 8574 //Add Toolbar Buttons 8575 if (opts.controls.toolbar) { 8576 vars.toolbar.addClass(opts.skin).append(vars.closeButton); 8577 if (opts.controls.fullscreen) 8578 vars.toolbar.append(vars.fullScreenButton); 8579 if (opts.controls.slideshow) 8580 vars.toolbar.append(vars.innerPlayButton); 8581 if (vars.total > 1) 8582 vars.toolbar.append(vars.innerPrevButton).append(vars.innerNextButton); 8583 } 8584 8585 //Append elements to body 8586 vars.BODY.addClass('ilightbox-noscroll').append(vars.overlay).append(vars.loader).append(vars.holder).append(vars.nextPhoto).append(vars.prevPhoto); 8587 8588 if (!opts.innerToolbar) 8589 vars.BODY.append(vars.toolbar); 8590 if (opts.controls.arrows) 8591 vars.BODY.append(vars.nextButton).append(vars.prevButton); 8592 8593 if (opts.controls.thumbnail && vars.total > 1) { 8594 vars.BODY.append(vars.thumbnails); 8595 vars.thumbnails.addClass(opts.skin).addClass('ilightbox-' + path); 8596 $('div.ilightbox-thumbnails-grid', vars.thumbnails).empty(); 8597 vars.thumbs = true; 8598 } 8599 8600 //Configure loader and arrows 8601 var loaderCss = (opts.path.toLowerCase() == "horizontal") ? { 8602 left: parseInt((viewport.width / 2) - (vars.loader.outerWidth() / 2)) 8603 } : { 8604 top: parseInt((viewport.height / 2) - (vars.loader.outerHeight() / 2)) 8605 }; 8606 vars.loader.addClass(opts.skin).css(loaderCss); 8607 vars.nextButton.add(vars.prevButton).addClass(opts.skin); 8608 if (path == "horizontal") 8609 vars.loader.add(vars.nextButton).add(vars.prevButton).addClass('horizontal'); 8610 8611 // Configure arrow buttons 8612 vars.BODY[vars.isMobile ? 'addClass' : 'removeClass']('isMobile'); 8613 8614 if (!opts.infinite) { 8615 vars.prevButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled'); 8616 8617 if (vars.current == 0) 8618 vars.prevButton.add(vars.innerPrevButton).addClass('disabled'); 8619 if (vars.current >= vars.total - 1) 8620 vars.nextButton.add(vars.innerNextButton).addClass('disabled'); 8621 } 8622 8623 if (opts.show.effect) { 8624 vars.overlay.stop().fadeIn(opts.show.speed); 8625 vars.toolbar.stop().fadeIn(opts.show.speed); 8626 } else { 8627 vars.overlay.show(); 8628 vars.toolbar.show(); 8629 } 8630 8631 var length = recognizingItems.length; 8632 if (needRecognition) { 8633 iL.showLoader(); 8634 8635 $.each(recognizingItems, function(key, val) { 8636 var resultFnc = function(result) { 8637 var key = -1, 8638 filter = iL.items.filter(function(e, i, arr) { 8639 if (e.URL == result.url) 8640 key = i; 8641 8642 return e.URL == result.url; 8643 }), 8644 self = iL.items[key]; 8645 8646 if (result) 8647 $.extend(true, self, { 8648 URL: result.source, 8649 type: result.type, 8650 recognized: true, 8651 options: { 8652 html5video: result.html5video, 8653 width: (result.type == "image") ? 0 : (result.width || self.width), 8654 height: (result.type == "image") ? 0 : (result.height || self.height), 8655 thumbnail: self.options.thumbnail || result.thumbnail 8656 } 8657 }); 8658 8659 length--; 8660 8661 if (length == 0) { 8662 iL.hideLoader(); 8663 8664 vars.dontGenerateThumbs = false;
8665 iL.generateThumbnails(); 8666 8667 if (opts.show.effect) 8668 setTimeout(function() { 8669 iL.generateBoxes(); 8670 }, opts.show.speed); 8671 else 8672 iL.generateBoxes(); 8673 } 8674 }; 8675 8676 iL.ogpRecognition(this, resultFnc); 8677 }); 8678 } 8679 else { 8680 if (opts.show.effect) 8681 setTimeout(function() { 8682 iL.generateBoxes(); 8683 }, opts.show.speed); 8684 else 8685 iL.generateBoxes(); 8686 } 8687 8688 iL.createUI(); 8689 8690 window.iLightBox = { 8691 close: function() { 8692 iL.closeAction(); 8693 }, 8694 fullscreen: function() { 8695 iL.fullScreenAction(); 8696 }, 8697 moveNext: function() { 8698 iL.moveTo('next'); 8699 }, 8700 movePrev: function() { 8701 iL.moveTo('prev'); 8702 }, 8703 goTo: function(index) { 8704 iL.goTo(index); 8705 }, 8706 refresh: function() { 8707 iL.refresh(); 8708 }, 8709 reposition: function() { 8710 (arguments.length > 0) ? iL.repositionPhoto(true): iL.repositionPhoto(); 8711 }, 8712 setOption: function(options) { 8713 iL.setOption(options); 8714 }, 8715 destroy: function() { 8716 iL.closeAction(); 8717 iL.dispatchItemsEvents(); 8718 } 8719 }; 8720 8721 if (opts.linkId) { 8722 vars.hashLock = true; 8723 window.location.hash = opts.linkId + '/' + vars.current; 8724 setTimeout(function() { 8725 vars.hashLock = false; 8726 }, 55); 8727 } 8728 8729 if (!opts.slideshow.startPaused) { 8730 iL.resume(); 8731 vars.innerPlayButton.removeClass('ilightbox-play').addClass('ilightbox-pause'); 8732 } 8733 8734 //Trigger the onOpen callback 8735 if (typeof iL.options.callback.onOpen == 'function') iL.options.callback.onOpen.call(iL); 8736 }, 8737 8738 loadContent: function(obj, opt, speed) { 8739 var iL = this, 8740 holder, item; 8741 8742 iL.createUI(); 8743 8744 obj.speed = speed || iL.options.effects.loadedFadeSpeed; 8745 8746 if (opt == 'current') { 8747 if (!obj.options.mousewheel) iL.vars.lockWheel = true; 8748 else iL.vars.lockWheel = false; 8749 8750 if (!obj.options.swipe) iL.vars.lockSwipe = true; 8751 else iL.vars.lockSwipe = false; 8752 } 8753 8754 switch (opt) { 8755 case 'current': 8756 holder = iL.vars.holder, item = iL.vars.current; 8757 break; 8758 case 'next': 8759 holder = iL.vars.nextPhoto, item = iL.vars.next; 8760 break; 8761 case 'prev': 8762 holder = iL.vars.prevPhoto, item = iL.vars.prev; 8763 break; 8764 } 8765 8766 holder.removeAttr('style class').addClass('ilightbox-holder' + (supportTouch ? ' supportTouch' : '')).addClass(obj.options.skin); 8767 $('div.ilightbox-inner-toolbar', holder).remove(); 8768 8769 if (obj.title || iL.options.innerToolbar) { 8770 var innerToolbar = iL.vars.innerToolbar.clone(); 8771 if (obj.title && iL.options.show.title) { 8772 var title = iL.vars.title.clone(); 8773 title.empty().html(obj.title); 8774 innerToolbar.append(title); 8775 } 8776 if (iL.options.innerToolbar) { 8777 innerToolbar.append((iL.vars.total > 1) ? iL.vars.toolbar.clone() : iL.vars.toolbar); 8778 } 8779 holder.prepend(innerToolbar); 8780 } 8781 8782 //console.warn('loadContent', arguments); 8783 8784 iL.loadSwitcher(obj, holder, item, opt); 8785 }, 8786 8787 loadSwitcher: function(obj, holder, item, opt) { 8788 var iL = this, 8789 opts = iL.options, 8790 api = { 8791 element: holder, 8792 position: item 8793 }; 8794 8795 switch (obj.type) { 8796 case 'image': 8797 //Trigger the onBeforeLoad callback 8798 if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item); 8799 if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api); 8800 8801 iL.loadImage(obj.URL, function(img) { 8802 //Trigger the onAfterLoad callback 8803 if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item); 8804 if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api); 8805 8806 var width = (img) ? img.width : 400, 8807 height = (img) ? img.height : 200; 8808 8809 holder.data({ 8810 naturalWidth: width, 8811 naturalHeight: height 8812 }); 8813 $('div.ilightbox-container', holder).empty().append((img) ? '<img src="' + obj.URL + '" class="ilightbox-image" />' : '<span class="ilightbox-alert">' + opts.errors.loadImage + '</span>'); 8814 8815 //Trigger the onRender callback 8816 if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item); 8817 if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api); 8818 8819 iL.configureHolder(obj, opt, holder); 8820 }); 8821 8822 break; 8823
8824 case 'video': 8825 holder.data({ 8826 naturalWidth: obj.options.width, 8827 naturalHeight: obj.options.height 8828 }); 8829 8830 if (opt === 'current') { 8831 iL.addContent(holder, obj); 8832 8833 //Trigger the onRender callback 8834 if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item); 8835 if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api); 8836 } else { 8837 $('div.ilightbox-container', holder).empty(); 8838 } 8839 8840 iL.configureHolder(obj, opt, holder); 8841 8842 break; 8843 8844 case 'iframe': 8845 //iL.showLoader(); 8846 holder.data({ 8847 naturalWidth: obj.options.width, 8848 naturalHeight: obj.options.height 8849 }); 8850 8851 iL.configureHolder(obj, opt, holder); 8852 8853 if (opt === 'current') { 8854 var el = iL.addContent(holder, obj); 8855 8856 //Trigger the onRender callback 8857 if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item); 8858 if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api); 8859 8860 //Trigger the onBeforeLoad callback 8861 if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item); 8862 if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api); 8863 8864 el.bind('load', function() { 8865 //Trigger the onAfterLoad callback 8866 if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item); 8867 if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api); 8868 8869 //iL.hideLoader(); 8870 el.unbind('load'); 8871 }); 8872 } else { 8873 $('div.ilightbox-container', holder).empty(); 8874 } 8875 8876 break; 8877 8878 case 'inline': 8879 var el = $(obj.URL), 8880 content = iL.addContent(holder, obj), 8881 images = findImageInElement(holder); 8882 8883 holder.data({ 8884 naturalWidth: (iL.items[item].options.width || el.outerWidth()), 8885 naturalHeight: (iL.items[item].options.height || el.outerHeight()) 8886 }); 8887 content.children().eq(0).show(); 8888 8889 //Trigger the onRender callback 8890 if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item); 8891 if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api); 8892 8893 //Trigger the onBeforeLoad callback 8894 if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item); 8895 if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api); 8896 8897 iL.loadImage(images, function() { 8898 //Trigger the onAfterLoad callback 8899 if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item); 8900 if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api); 8901 8902 iL.configureHolder(obj, opt, holder); 8903 }); 8904 8905 break; 8906 8907 case 'flash': 8908 var el = iL.addContent(holder, obj); 8909 8910 holder.data({ 8911 naturalWidth: (iL.items[item].options.width || el.outerWidth()), 8912 naturalHeight: (iL.items[item].options.height || el.outerHeight()) 8913 }); 8914 8915 //Trigger the onRender callback 8916 if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item); 8917 if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api); 8918 8919 iL.configureHolder(obj, opt, holder); 8920 8921 break; 8922 8923 case 'ajax': 8924 var ajax = obj.options.ajax || {}; 8925 //Trigger the onBeforeLoad callback 8926 if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item); 8927 if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api); 8928 8929 iL.showLoader(); 8930 $.ajax({ 8931 url: obj.URL || opts.ajaxSetup.url, 8932 data: ajax.data || null, 8933 dataType: ajax.dataType || "html", 8934 type: ajax.type || opts.ajaxSetup.type, 8935 cache: ajax.cache || opts.ajaxSetup.cache, 8936 crossDomain: ajax.crossDomain || opts.ajaxSetup.crossDomain, 8937 global: ajax.global || opts.ajaxSetup.global, 8938 ifModified: ajax.ifModified || opts.ajaxSetup.ifModified, 8939 username: ajax.username || opts.ajaxSetup.username, 8940 password: ajax.password || opts.ajaxSetup.password, 8941 beforeSend: ajax.beforeSend || opts.ajaxSetup.beforeSend, 8942 complete: ajax.complete || opts.ajaxSetup.complete, 8943 success: function(data, textStatus, jqXHR) { 8944 iL.hideLoader(); 8945 8946 var el = $(data), 8947 container = $('div.ilightbox-container', holder), 8948 elWidth = iL.items[item].options.width || parseInt(el[0].getAttribute('width')), 8949 elHeight = iL.items[item].options.height || parseInt(el[0].getAttribute('height')), 8950 css = (el[0].getAttribute('width') && el[0].getAttribute('height')) ? { 8951 'overflow': 'hidden' 8952 } : {}; 8953 8954 container.empty().append($('<div class="ilightbox-wrapper"></div>').css(css).html(el)); 8955 holder.show().data({
8956 naturalWidth: (elWidth || container.outerWidth()), 8957 naturalHeight: (elHeight || container.outerHeight()) 8958 }).hide(); 8959 8960 //Trigger the onRender callback 8961 if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item); 8962 if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api); 8963 8964 var images = findImageInElement(holder); 8965 iL.loadImage(images, function() { 8966 //Trigger the onAfterLoad callback 8967 if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item); 8968 if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api); 8969 8970 iL.configureHolder(obj, opt, holder); 8971 }); 8972 8973 opts.ajaxSetup.success(data, textStatus, jqXHR); 8974 if (typeof ajax.success == 'function') ajax.success(data, textStatus, jqXHR); 8975 }, 8976 error: function(jqXHR, textStatus, errorThrown) { 8977 //Trigger the onAfterLoad callback 8978 if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item); 8979 if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api); 8980 8981 iL.hideLoader(); 8982 $('div.ilightbox-container', holder).empty().append('<span class="ilightbox-alert">' + opts.errors.loadContents + '</span>'); 8983 iL.configureHolder(obj, opt, holder); 8984 8985 opts.ajaxSetup.error(jqXHR, textStatus, errorThrown); 8986 if (typeof ajax.error == 'function') ajax.error(jqXHR, textStatus, errorThrown); 8987 } 8988 }); 8989 8990 break; 8991 8992 case 'html': 8993 var object = obj.URL, 8994 el 8995 container = $('div.ilightbox-container', holder); 8996 8997 if (object[0].nodeName) el = object.clone(); 8998 else { 8999 var dom = $(object); 9000 if (dom.selector) el = $('<div>' + dom + '</div>'); 9001 else el = dom; 9002 } 9003 9004 var elWidth = iL.items[item].options.width || parseInt(el.attr('width')), 9005 elHeight = iL.items[item].options.height || parseInt(el.attr('height')); 9006 9007 iL.addContent(holder, obj); 9008 9009 el.appendTo(document.documentElement).hide(); 9010 9011 //Trigger the onRender callback 9012 if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item); 9013 if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api); 9014 9015 var images = findImageInElement(holder); 9016 9017 //Trigger the onBeforeLoad callback 9018 if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item); 9019 if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api); 9020 9021 iL.loadImage(images, function() { 9022 //Trigger the onAfterLoad callback 9023 if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item); 9024 if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api); 9025 9026 holder.show().data({ 9027 naturalWidth: (elWidth || container.outerWidth()), 9028 naturalHeight: (elHeight || container.outerHeight()) 9029 }).hide(); 9030 el.remove(); 9031 9032 iL.configureHolder(obj, opt, holder); 9033 }); 9034 9035 break; 9036 } 9037 }, 9038 9039 configureHolder: function(obj, opt, holder) { 9040 var iL = this, 9041 vars = iL.vars, 9042 opts = iL.options; 9043 9044 if (opt != "current")(opt == "next") ? holder.addClass('ilightbox-next') : holder.addClass('ilightbox-prev'); 9045 9046 if (opt == "current") 9047 var item = vars.current; 9048 else if (opt == "next") 9049 var opacity = opts.styles.nextOpacity, 9050 item = vars.next; 9051 else 9052 var opacity = opts.styles.prevOpacity, 9053 item = vars.prev; 9054 9055 var api = { 9056 element: holder, 9057 position: item 9058 }; 9059 9060 iL.items[item].options.width = iL.items[item].options.width || 0, 9061 iL.items[item].options.height = iL.items[item].options.height || 0; 9062 9063 if (opt == "current") { 9064 if (opts.show.effect) holder.css(transform, gpuAcceleration).fadeIn(obj.speed, function() { 9065 holder.css(transform, ''); 9066 if (obj.caption) { 9067 iL.setCaption(obj, holder); 9068 var caption = $('div.ilightbox-caption', holder), 9069 percent = parseInt((caption.outerHeight() / holder.outerHeight()) * 100); 9070 if (opts.caption.start & percent <= 50) caption.fadeIn(opts.effects.fade
9070Speed); 9071 } 9072 9073 var social = obj.options.social; 9074 if (social) { 9075 iL.setSocial(social, obj.URL, holder); 9076 if (opts.social.start) $('div.ilightbox-social', holder).fadeIn(opts.effects.fadeSpeed); 9077 } 9078 9079 //Generate thumbnails 9080 iL.generateThumbnails(); 9081 9082 //Trigger the onShow callback 9083 if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item); 9084 if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api); 9085 }); 9086 else { 9087 holder.show(); 9088 9089 //Generate thumbnails 9090 iL.generateThumbnails(); 9091 9092 //Trigger the onShow callback 9093 if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item); 9094 if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api); 9095 } 9096 } else { 9097 if (opts.show.effect) holder.fadeTo(obj.speed, opacity, function() { 9098 if (opt == "next") vars.nextLock = false; 9099 else vars.prevLock = false; 9100 9101 //Generate thumbnails 9102 iL.generateThumbnails(); 9103 9104 //Trigger the onShow callback 9105 if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item); 9106 if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api); 9107 }); 9108 else { 9109 holder.css({ 9110 opacity: opacity 9111 }).show(); 9112 if (opt == "next") vars.nextLock = false; 9113 else vars.prevLock = false; 9114 9115 //Generate thumbnails 9116 iL.generateThumbnails(); 9117 9118 //Trigger the onShow callback 9119 if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item); 9120 if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api); 9121 } 9122 } 9123 9124 setTimeout(function() { 9125 iL.repositionPhoto(); 9126 }, 0); 9127 }, 9128 9129 generateBoxes: function() { 9130 var iL = this, 9131 vars = iL.vars, 9132 opts = iL.options; 9133 9134 if (opts.infinite && vars.total >= 3) { 9135 if (vars.current == vars.total - 1) vars.next = 0; 9136 if (vars.current == 0) vars.prev = vars.total - 1; 9137 } else opts.infinite = false; 9138 9139 //UNCODE addition 9140 if ( typeof iL.items[vars.current] == 'undefined' ) 9141 vars.current = 0; 9142 9143 iL.loadContent(iL.items[vars.current], 'current', opts.show.speed); 9144 9145 if (iL.items[vars.next]) iL.loadContent(iL.items[vars.next], 'next', opts.show.speed); 9146 if (iL.items[vars.prev]) iL.loadContent(iL.items[vars.prev], 'prev', opts.show.speed); 9147 }, 9148 9149 generateThumbnails: function() { 9150 var iL = this, 9151 vars = iL.vars, 9152 opts = iL.options, 9153 timeOut = null; 9154 9155 if (vars.thumbs && !iL.vars.dontGenerateThumbs) { 9156 var thumbnails = vars.thumbnails, 9157 container = $('div.ilightbox-thumbnails-container', thumbnails), 9158 grid = $('div.ilightbox-thumbnails-grid', container), 9159 i = 0; 9160 9161 grid.removeAttr('style').empty(); 9162 9163 $.each(iL.items, function(key, val) { 9164 var isActive = (vars.current == key) ? 'ilightbox-active' : '', 9165 opacity = (vars.current == key) ? opts.thumbnails.activeOpacity : opts.thumbnails.normalOpacity, 9166 thumb = val.options.thumbnail, 9167 thumbnail = $('<div class="ilightbox-thumbnail"></div>'), 9168 icon = $('<div class="ilightbox-thumbnail-icon"></div>'); 9169 9170 thumbnail.css({ 9171 opacity: 0 9172 }).addClass(isActive); 9173 9174 if ((val.type == "video" || val.type == "flash") && typeof val.options.icon == 'undefined') { 9175 icon.addClass('ilightbox-thumbnail-video'); 9176 thumbnail.append(icon); 9177 } else if (val.options.icon) { 9178 icon.addClass('ilightbox-thumbnail-' + val.options.icon); 9179 thumbnail.append(icon); 9180 } 9181 9182 if (thumb) iL.loadImage(thumb, function(img) { 9183 i++; 9184 if (img) thumbnail.data({ 9185 naturalWidth: img.width, 9186 naturalHeight: img.height 9187 }).append('<img src="' + thumb + '" border="0" />'); 9188 else thumbnail.data({ 9189 naturalWidth: opts.thumbnails.maxWidth, 9190 naturalHeight: opts.thumbnails.maxHeight 9191 }); 9192 9193 clearTimeout(timeOut); 9194 timeOut = setTimeout(function() { 9195 iL.positionThumbnails(thumbnails, container, grid); 9196 }, 20); 9197 setTimeout(function() { 9198 thumbnail.fadeTo(opts.effects.loadedFadeSpeed, opacity); 9199 }, i * 20); 9200 }); 9201 9202 grid.append(thumbnail); 9203 }); 9204 iL.vars.dontGenerateThumbs = true; 9205 } 9206 }, 9207
9208 positionThumbnails: function(thumbnails, container, grid) { 9209 var iL = this, 9210 vars = iL.vars, 9211 opts = iL.options, 9212 viewport = getViewport(), 9213 path = opts.path.toLowerCase(); 9214 9215 if (!thumbnails) thumbnails = vars.thumbnails; 9216 if (!container) container = $('div.ilightbox-thumbnails-container', thumbnails); 9217 if (!grid) grid = $('div.ilightbox-thumbnails-grid', container); 9218 9219 var thumbs = $('.ilightbox-thumbnail', grid), 9220 widthAvail = (path == 'horizontal') ? viewport.width - opts.styles.pageOffsetX : thumbs.eq(0).outerWidth() - opts.styles.pageOffsetX, 9221 heightAvail = (path == 'horizontal') ? thumbs.eq(0).outerHeight() - opts.styles.pageOffsetY : viewport.height - opts.styles.pageOffsetY, 9222 gridWidth = (path == 'horizontal') ? 0 : widthAvail, 9223 gridHeight = (path == 'horizontal') ? heightAvail : 0, 9224 active = $('.ilightbox-active', grid), 9225 gridCss = {}, 9226 css = {}; 9227 9228 if (arguments.length < 3) { 9229 thumbs.css({ 9230 opacity: opts.thumbnails.normalOpacity 9231 }); 9232 active.css({ 9233 opacity: opts.thumbnails.activeOpacity 9234 }); 9235 } 9236 9237 thumbs.each(function(i) { 9238 var t = $(this), 9239 data = t.data(), 9240 width = (path == 'horizontal') ? 0 : opts.thumbnails.maxWidth; 9241 height = (path == 'horizontal') ? opts.thumbnails.maxHeight : 0; 9242 dims = iL.getNewDimenstions(width, height, data.naturalWidth, data.naturalHeight, true); 9243 9244 t.css({ 9245 width: dims.width, 9246 height: dims.height 9247 }); 9248 if (path == 'horizontal') t.css({ 9249 'float': 'left' 9250 }); 9251 9252 (path == 'horizontal') ? ( 9253 gridWidth += t.outerWidth() 9254 ) : ( 9255 gridHeight += t.outerHeight() 9256 ); 9257 }); 9258 9259 gridCss = { 9260 width: gridWidth, 9261 height: gridHeight 9262 }; 9263 9264 grid.css(gridCss); 9265 9266 gridCss = {}; 9267 9268 var gridOffset = grid.offset(), 9269 activeOffset = (active.length) ? active.offset() : { 9270 top: parseInt(heightAvail / 2), 9271 left: parseInt(widthAvail / 2) 9272 }; 9273 9274 gridOffset.top = (gridOffset.top - $doc.scrollTop()), 9275 gridOffset.left = (gridOffset.left - $doc.scrollLeft()), 9276 activeOffset.top = (activeOffset.top - gridOffset.top - $doc.scrollTop()), 9277 activeOffset.left = (activeOffset.left - gridOffset.left - $doc.scrollLeft()); 9278 9279 (path == 'horizontal') ? ( 9280 gridCss.top = 0, 9281 gridCss.left = parseInt((widthAvail / 2) - activeOffset.left - (active.outerWidth() / 2)) 9282 ) : ( 9283 gridCss.top = parseInt(((heightAvail / 2) - activeOffset.top - (active.outerHeight() / 2))), 9284 gridCss.left = 0 9285 ); 9286 9287 if (arguments.length < 3) grid.stop().animate(gridCss, opts.effects.repositionSpeed, 'easeOutCirc'); 9288 else grid.css(gridCss); 9289 }, 9290 9291 loadImage: function(image, callback) { 9292 if (!$.isArray(image)) image = [image]; 9293 9294 var iL = this, 9295 length = image.length; 9296 9297 if (length > 0) { 9298 iL.showLoader(); 9299 $.each(image, function(index, value) { 9300 var img = new Image(); 9301 img.onload = function() { 9302 length -= 1; 9303 if (length == 0) { 9304 iL.hideLoader(); 9305 callback(img); 9306 } 9307 }; 9308 img.onerror = img.onabort = function() { 9309 length -= 1; 9310 if (length == 0) { 9311 iL.hideLoader(); 9312 callback(false); 9313 } 9314 }; 9315 img.src = image[index]; 9316 }); 9317 } else callback(false); 9318 }, 9319 9320 patchItemsEvents: function() { 9321 var iL = this, 9322 vars = iL.vars, 9323 clickEvent = supportTouch ? "itap.iL" : "click.iL", 9324 vEvent = supportTouch ? "click.iL" : "itap.iL"; 9325 9326 if (iL.context && iL.selector) { 9327 var $items = $(iL.selector, iL.context); 9328 9329 $(iL.context).on(clickEvent, iL.selector, function() { 9330 var $this = $(this), 9331 //UNCODE addition 9332 key = typeof $(this).data('lb-index') !== '' && $(this).closest('.owl-item').length ? $(this).data('lb-index') : $items.index($this); 9333 if (UNCODE.isMobile) { 9334 var isCarousel = $this.closest('.owl-carousel'); 9335 if (isCarousel.length) { 9336 if (isCarousel.hasClass('owl-translating')) return false; 9337 } 9338 } 9339 9340 vars.current = key; 9341 vars.next = iL.items[key + 1] ? key + 1 : null; 9342 vars.prev = iL.items[key - 1] ? key - 1 : null; 9343 9344 //UNCODE addition 9345 if ( vars.BODY.hasClass('fp-slide-scrolling') ) 9346 return false;
9347 9348 iL.addContents(); 9349 iL.patchEvents(); 9350 9351 return false; 9352 }).on(vEvent, iL.selector, function() { 9353 return false; 9354 }); 9355 } else 9356 $.each(iL.itemsObject, function(key, val) { 9357 val.on(clickEvent, function() { 9358 vars.current = key; 9359 vars.next = iL.items[key + 1] ? key + 1 : null; 9360 vars.prev = iL.items[key - 1] ? key - 1 : null; 9361 9362 iL.addContents(); 9363 iL.patchEvents(); 9364 9365 return false; 9366 }).on(vEvent, function() { 9367 return false; 9368 }); 9369 }); 9370 }, 9371 9372 dispatchItemsEvents: function() { 9373 var iL = this, 9374 vars = iL.vars, 9375 opts = iL.options; 9376 9377 if (iL.context && iL.selector) 9378 $(iL.context).off('.iL', iL.selector); 9379 else 9380 $.each(iL.itemsObject, function(key, val) { 9381 val.off('.iL'); 9382 }); 9383 }, 9384 9385 refresh: function() { 9386 var iL = this; 9387 9388 iL.dispatchItemsEvents(); 9389 iL.attachItems(); 9390 iL.normalizeItems(); 9391 iL.patchItemsEvents(); 9392 }, 9393 9394 patchEvents: function() { 9395 var iL = this, 9396 vars = iL.vars, 9397 opts = iL.options, 9398 path = opts.path.toLowerCase(), 9399 holders = $('.ilightbox-holder'), 9400 fullscreenEvent = fullScreenApi.fullScreenEventName + '.iLightBox', 9401 durationThreshold = 1000, 9402 horizontalDistanceThreshold = 9403 verticalDistanceThreshold = 100, 9404 buttonsArray = [vars.nextButton[0], vars.prevButton[0], vars.nextButton[0].firstChild, vars.prevButton[0].firstChild]; 9405 9406 $win.bind('resize.iLightBox', function() { 9407 var viewport = getViewport(); 9408 9409 if (opts.mobileOptimizer && !opts.innerToolbar) vars.isMobile = viewport.width <= vars.mobileMaxWidth; 9410 vars.BODY[vars.isMobile ? 'addClass' : 'removeClass']('isMobile'); 9411 9412 iL.repositionPhoto(null); 9413 if (supportTouch) { 9414 clearTimeout(vars.setTime); 9415 vars.setTime = setTimeout(function() { 9416 var scrollTop = getScrollXY().y; 9417 window.scrollTo(0, scrollTop - 30); 9418 window.scrollTo(0, scrollTop + 30); 9419 window.scrollTo(0, scrollTop); 9420 }, 2000); 9421 } 9422 if (vars.thumbs) iL.positionThumbnails(); 9423 }).bind('keydown.iLightBox', function(event) { 9424 if (opts.controls.keyboard) { 9425 switch (event.keyCode) { 9426 case 13: 9427 if (event.shiftKey && opts.keyboard.shift_enter) iL.fullScreenAction(); 9428 break; 9429 case 27: 9430 if (opts.keyboard.esc) iL.closeAction(); 9431 break; 9432 case 37: 9433 if (opts.keyboard.left && !vars.lockKey) iL.moveTo('prev'); 9434 break; 9435 case 38: 9436 if (opts.keyboard.up && !vars.lockKey) iL.moveTo('prev'); 9437 break; 9438 case 39: 9439 if (opts.keyboard.right && !vars.lockKey) iL.moveTo('next'); 9440 break; 9441 case 40: 9442 if (opts.keyboard.down && !vars.lockKey) iL.moveTo('next'); 9443 break; 9444 } 9445 } 9446 }); 9447 9448 if (fullScreenApi.supportsFullScreen) $win.bind(fullscreenEvent, function() { 9449 iL.doFullscreen(); 9450 }); 9451 9452 var holderEventsArr = [opts.caption.show + '.iLightBox', opts.caption.hide + '.iLightBox', opts.social.show + '.iLightBox', opts.social.hide + '.iLightBox'].filter(function(e, i, arr) { 9453 return arr.lastIndexOf(e) === i; 9454 }), 9455 holderEvents = ""; 9456 9457 $.each(holderEventsArr, function(key, val) { 9458 if (key != 0) holderEvents += ' '; 9459 holderEvents += val; 9460 }); 9461 9462 $doc.on(clickEvent, '.ilightbox-overlay', function() { 9463 if (opts.overlay.blur) iL.closeAction(); 9464 }).on(clickEvent, '.ilightbox-next, .ilightbox-next-button', function() { 9465 iL.moveTo('next'); 9466 }).on(clickEvent, '.ilightbox-prev, .ilightbox-prev-button', function() { 9467 iL.moveTo('prev'); 9468 }).on(clickEvent, '.ilightbox-thumbnail', function() { 9469 var t = $(this), 9470 thumbs = $('.ilightbox-thumbnail', vars.thumbnails), 9471 index = thumbs.index(t); 9472 9473 if (index != vars.current) iL.goTo(index); 9474 }).on(holderEvents, '.ilightbox-holder:not(.ilightbox-next, .ilightbox-prev)', function(e) { 9475 var caption = $('div.ilightbox-caption', vars.holder), 9476 social = $('div.ilightbox-social', vars.holder), 9477 fadeSpeed = opts.effects.fadeSpeed; 9478 9479 if (vars.nextLock || vars.prevLock) { 9480 if (e.type == opts.caption.show && !caption.is(':visible')) caption.fadeIn(fadeSpeed); 9481 else if (e.type == opts.caption.hide && caption.is(':visible')) caption.fadeOut(fadeSpeed); 9482 9483 if (e.type == opts.social.show && !social.is(':visible')) social.fadeIn(fadeSpeed); 9484 else if (e.type == opts.social.hide && social.is(':visible')) social.fadeOut(fadeSpeed); 9485 } else { 9486 if (e.type == opts.caption.show && !caption.is(':visible')) caption.stop().fadeIn(fadeSpeed); 9487 else if (e.type == opts.caption.hide && caption.is(':visible')) caption.stop().fadeOut(fadeSpeed); 9488 9489 if (e.type == opts.social.show && !social.is(':visible')) social.stop().fadeIn(fadeSpeed); 9490 else if (e.type == opts.social.hide && social.is(':visible')) social.stop().fadeOut(fadeSpeed); 9491 } 9492 }).on('mouseenter.iLightBox mouseleave.iLightBox', '.ilightbox-wrapper', function(e) { 9493 if (e.type == 'mouseenter') vars.lockWheel = true; 9494 else vars.lockWheel = false;
9495 }).on(clickEvent, '.ilightbox-toolbar a.ilightbox-close, .ilightbox-toolbar a.ilightbox-fullscreen, .ilightbox-toolbar a.ilightbox-play, .ilightbox-toolbar a.ilightbox-pause', function() { 9496 var t = $(this); 9497 9498 if (t.hasClass('ilightbox-fullscreen')) iL.fullScreenAction(); 9499 else if (t.hasClass('ilightbox-play')) { 9500 iL.resume(); 9501 t.addClass('ilightbox-pause').removeClass('ilightbox-play'); 9502 } else if (t.hasClass('ilightbox-pause')) { 9503 iL.pause(); 9504 t.addClass('ilightbox-play').removeClass('ilightbox-pause'); 9505 } else iL.closeAction(); 9506 }).on(touchMoveEvent, '.ilightbox-overlay, .ilightbox-thumbnails-container', function(e) { 9507 // prevent scrolling 9508 e.preventDefault(); 9509 }); 9510 9511 function mouseMoveHandler(e) { 9512 if (!vars.isMobile) { 9513 if (!vars.mouseID) { 9514 vars.hideableElements.show(); 9515 } 9516 9517 vars.mouseID = clearTimeout(vars.mouseID); 9518 9519 if (buttonsArray.indexOf(e.target) === -1) 9520 vars.mouseID = setTimeout(function() { 9521 vars.hideableElements.hide(); 9522 vars.mouseID = clearTimeout(vars.mouseID); 9523 }, 3000); 9524 } 9525 } 9526 9527 if (opts.controls.arrows && !supportTouch) $doc.on('mousemove.iLightBox', mouseMoveHandler); 9528 9529 if (opts.controls.slideshow && opts.slideshow.pauseOnHover) $doc.on('mouseenter.iLightBox mouseleave.iLightBox', '.ilightbox-holder:not(.ilightbox-next, .ilightbox-prev)', function(e) { 9530 if (e.type == 'mouseenter' && vars.cycleID) iL.pause(); 9531 else if (e.type == 'mouseleave' && vars.isPaused) iL.resume(); 9532 }); 9533 9534 var switchers = $('.ilightbox-overlay, .ilightbox-holder, .ilightbox-thumbnails'); 9535 9536 if (opts.controls.mousewheel) switchers.on('mousewheel.iLightBox', function(event, delta) { 9537 if (!vars.lockWheel) { 9538 event.preventDefault(); 9539 if (delta < 0) iL.moveTo('next'); 9540 else if (delta > 0) iL.moveTo('prev'); 9541 } 9542 }); 9543 9544 if (opts.controls.swipe) holders.on(touchStartEvent, function(event) { 9545 if (vars.nextLock || vars.prevLock || vars.total == 1 || vars.lockSwipe) return; 9546 9547 vars.BODY.addClass('ilightbox-closedhand'); 9548 9549 var data = event.originalEvent.touches ? event.originalEvent.touches[0] : event, 9550 scrollTop = $doc.scrollTop(), 9551 scrollLeft = $doc.scrollLeft(), 9552 offsets = [ 9553 holders.eq(0).offset(), 9554 holders.eq(1).offset(), 9555 holders.eq(2).offset() 9556 ], 9557 offSet = [{ 9558 top: offsets[0].top - scrollTop, 9559 left: offsets[0].left - scrollLeft 9560 }, { 9561 top: offsets[1].top - scrollTop, 9562 left: offsets[1].left - scrollLeft 9563 }, { 9564 top: offsets[2].top - scrollTop, 9565 left: offsets[2].left - scrollLeft 9566 }], 9567 start = { 9568 time: (new Date()).getTime(), 9569 coords: [data.pageX - scrollLeft, data.pageY - scrollTop] 9570 }, 9571 stop; 9572 9573 function moveEachHandler(i) { 9574 var t = $(this), 9575 offset = offSet[i], 9576 scroll = [(start.coords[0] - stop.coords[0]), (start.coords[1] - stop.coords[1])]; 9577 9578 t[0].style[path == "horizontal" ? 'left' : 'top'] = (path == "horizontal" ? offset.left - scroll[0] : offset.top - scroll[1]) + 'px'; 9579 } 9580 9581 function moveHandler(event) { 9582 9583 if (!start) return; 9584 9585 var data = event.originalEvent.touches ? event.originalEvent.touches[0] : event; 9586 9587 stop = { 9588 time: (new Date()).getTime(), 9589 coords: [data.pageX - scrollLeft, data.pageY - scrollTop] 9590 }; 9591 9592 holders.each(moveEachHandler); 9593 9594 // prevent scrolling 9595 event.preventDefault(); 9596 } 9597 9598 function repositionHolders() { 9599 holders.each(function() { 9600 var t = $(this), 9601 offset = t.data('offset') || { 9602 top: t.offset().top - scrollTop, 9603 left: t.offset().left - scrollLeft 9604 }, 9605 top = offset.top, 9606 left = offset.left; 9607 9608 t.css(transform, gpuAcceleration).stop().animate({ 9609 top: top, 9610 left: left 9611 }, 500, 'easeOutCirc', function() { 9612 t.css(transform, ''); 9613 }); 9614 }); 9615 } 9616 9617 holders.bind(touchMoveEvent, moveHandler); 9618 $doc.one(touchStopEvent, function(event) { 9619 holders.unbind(touchMoveEvent, moveHandler); 9620 9621 vars.BODY.removeClass('ilightbox-closedhand'); 9622 9623 if (start && stop) { 9624 if (path == "horizontal" && stop.time - start.time < durationThreshold && abs(start.coords[0] - stop.coords[0]) > horizontalDistanceThreshold && abs(start.coords[1] - stop.coords[1]) < verticalDistanceThreshold) { 9625 if (start.coords[0] > stop.coords[0]) { 9626 if (vars.current == vars.total - 1 && !opts.infinite) repositionHolders(); 9627 else { 9628 vars.isSwipe = true; 9629 iL.moveTo('next'); 9630 } 9631 } else { 9632 if (vars.current == 0 && !opts.infinite) repositionHolders(); 9633 else { 9634 vars.isSwipe = true; 9635 iL.moveTo('prev'); 9636 } 9637 } 9638 } 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) { 9639 if (start.coords[1] > stop.coords[1]) { 9640 if (vars.current == vars.total - 1 && !opts.infinite) repositionHolders(); 9641 else { 9642 vars.isSwipe = true; 9643 iL.moveTo('next'); 9644 } 9645 } else { 9646 if (vars.current == 0 && !opts.infinite) repositionHolders(); 9647 else { 9648 vars.isSwipe = true; 9649 iL.moveTo('prev'); 9650 } 9651 } 9652 } else repositionHolders(); 9653 } 9654 start = stop = undefined; 9655 }); 9656 }); 9657 9658 }, 9659 9660 goTo: function(index) { 9661 var iL = this, 9662 vars = iL.vars, 9663 opts = iL.options, 9664 diff = (index - vars.current); 9665 9666 if (opts.infinite) { 9667 if (index == vars.total - 1 && vars.current == 0) diff = -1; 9668 if (vars.current == vars.total - 1 && index == 0) diff = 1; 9669 } 9670 9671 if (diff == 1) iL.moveTo('next'); 9672 else if (diff == -1) iL.moveTo('prev'); 9673 else { 9674 9675 if (vars.nextLock || vars.prevLock) return false;
9676 9677 //Trigger the onBeforeChange callback 9678 if (typeof opts.callback.onBeforeChange == 'function') opts.callback.onBeforeChange.call(iL, iL.ui); 9679 9680 if (opts.linkId) { 9681 vars.hashLock = true; 9682 window.location.hash = opts.linkId + '/' + index; 9683 } 9684 9685 if (iL.items[index]) { 9686 if (!iL.items[index].options.mousewheel) vars.lockWheel = true; 9687 else iL.vars.lockWheel = false; 9688 9689 if (!iL.items[index].options.swipe) vars.lockSwipe = true; 9690 else vars.lockSwipe = false; 9691 } 9692 9693 $.each([vars.holder, vars.nextPhoto, vars.prevPhoto], function(key, val) { 9694 val.css(transform, gpuAcceleration).fadeOut(opts.effects.loadedFadeSpeed); 9695 }); 9696 9697 vars.current = index; 9698 vars.next = index + 1; 9699 vars.prev = index - 1; 9700 9701 iL.createUI(); 9702 9703 setTimeout(function() { 9704 iL.generateBoxes(); 9705 }, opts.effects.loadedFadeSpeed + 50); 9706 9707 $('.ilightbox-thumbnail', vars.thumbnails).removeClass('ilightbox-active').eq(index).addClass('ilightbox-active'); 9708 iL.positionThumbnails(); 9709 9710 if (opts.linkId) setTimeout(function() { 9711 vars.hashLock = false; 9712 }, 55); 9713 9714 // Configure arrow buttons 9715 if (!opts.infinite) { 9716 vars.nextButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled'); 9717 9718 if (vars.current == 0) { 9719 vars.prevButton.add(vars.innerPrevButton).addClass('disabled'); 9720 } 9721 if (vars.current >= vars.total - 1) { 9722 vars.nextButton.add(vars.innerNextButton).addClass('disabled'); 9723 } 9724 } 9725 9726 // Reset next cycle timeout 9727 iL.resetCycle(); 9728 9729 //Trigger the onAfterChange callback 9730 if (typeof opts.callback.onAfterChange == 'function') opts.callback.onAfterChange.call(iL, iL.ui); 9731 } 9732 }, 9733 9734 moveTo: function(side) { 9735 var iL = this, 9736 vars = iL.vars, 9737 opts = iL.options, 9738 path = opts.path.toLowerCase(), 9739 viewport = getViewport(), 9740 switchSpeed = opts.effects.switchSpeed; 9741 9742 if (vars.nextLock || vars.prevLock) return false; 9743 else { 9744 9745 var item = (side == "next") ? vars.next : vars.prev; 9746 9747 if (opts.linkId) { 9748 vars.hashLock = true; 9749 window.location.hash = opts.linkId + '/' + item; 9750 } 9751 9752 if (side == "next") { 9753 if (!iL.items[item]) return false; 9754 var firstHolder = vars.nextPhoto, 9755 secondHolder = vars.holder, 9756 lastHolder = vars.prevPhoto, 9757 firstClass = 'ilightbox-prev', 9758 secondClass = 'ilightbox-next'; 9759 } else if (side == "prev") { 9760 if (!iL.items[item]) return false; 9761 var firstHolder = vars.prevPhoto, 9762 secondHolder = vars.holder, 9763 lastHolder = vars.nextPhoto, 9764 firstClass = 'ilightbox-next', 9765 secondClass = 'ilightbox-prev'; 9766 } 9767 9768 //Trigger the onBeforeChange callback 9769 if (typeof opts.callback.onBeforeChange == 'function') 9770 opts.callback.onBeforeChange.call(iL, iL.ui); 9771 9772 (side == "next") ? vars.nextLock = true: vars.prevLock = true; 9773 9774 var captionFirst = $('div.ilightbox-caption', secondHolder), 9775 socialFirst = $('div.ilightbox-social', secondHolder); 9776 9777 if (captionFirst.length) 9778 captionFirst.stop().fadeOut(switchSpeed, function() { 9779 $(this).remove(); 9780 }); 9781 if (socialFirst.length) 9782 socialFirst.stop().fadeOut(switchSpeed, function() { 9783 $(this).remove(); 9784 }); 9785 9786 if (iL.items[item].caption) { 9787 iL.setCaption(iL.items[item], firstHolder); 9788 var caption = $('div.ilightbox-caption', firstHolder), 9789 percent = parseInt((caption.outerHeight() / firstHolder.outerHeight()) * 100); 9790 if (opts.caption.start && percent <= 50) caption.fadeIn(switchSpeed); 9791 } 9792 9793 var social = iL.items[item].options.social; 9794 if (social) { 9795 iL.setSocial(social, iL.items[item].URL, firstHolder); 9796 if (opts.social.start) $('div.ilightbox-social', firstHolder).fadeIn(opts.effects.fadeSpeed); 9797 } 9798 9799 $.each([firstHolder, secondHolder, lastHolder], function(key, val) { 9800 val.removeClass('ilightbox-next ilightbox-prev'); 9801 }); 9802 9803 var firstOffset = firstHolder.data('offset'), 9804 winW = (viewport.width - (opts.styles.pageOffsetX)), 9805 winH = (viewport.height - (opts.styles.pageOffsetY)), 9806 width = firstOffset.newDims.width, 9807 height = firstOffset.newDims.height, 9808 thumbsOffset = firstOffset.thumbsOffset, 9809 diff = firstOffset.diff, 9810 top = parseInt((winH / 2) - (height / 2) - diff.H - (thumbsOffset.H / 2)), 9811 left = parseInt((winW / 2) - (width / 2) - diff.W - (thumbsOffset.W / 2)); 9812 9813 var secondOffset = secondHolder.data('offset'), 9814 object = secondOffset.object; 9815 9816 /*if (object.item.caption && !isNaN(width) && !isNaN(height) && UNCODE.wwidth > UNCODE.mediaQuery) { 9817 var objRatio = width / height; 9818 height = height - vars.captionHeight; 9819 width = height * objRatio; 9820 top = path == 'horizontal' ? parseInt((winH / 2) - (height / 2) - diff.H - (thumbsOffset.H / 2)) : top, 9821 left = parseInt((winW / 2) - (width / 2) - diff.W - (thumbsOffset.W / 2)); 9822 }*/ 9823 9824 firstHolder.show().css(transform, gpuAcceleration).animate({ 9825 top: top, 9826 left: left, 9827 opacity: 1 9828 }, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc', function() { 9829 firstHolder.css(transform, ''); 9830 }); 9831 9832 $('div.ilightbox-container', firstHolder).animate({ 9833 width: width, 9834 height: height 9835 }, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc'); 9836 9837 diff = secondOffset.diff; 9838 9839 width = secondOffset.newDims.width, 9840 height = secondOffset.newDims.height; 9841 9842 width = parseInt(width * opts.styles[side == 'next' ? 'prevScale' : 'nextScale']), 9843 height = parseInt(height * opts.styles[side == 'next' ? 'prevScale' : 'nextScale']), 9844 top = (path == 'horizontal') ? parseInt((winH / 2) - object.offsetY - (height / 2) - diff.H - (thumbsOffset.H / 2)) : parseInt(winH - object.offsetX - diff.H - (thumbsOffset.H / 2)); 9845 9846 if (side == 'prev') 9847 left = (path == 'horizontal') ? parseInt(winW - object.offsetX - diff.W - (thumbsOffset.W / 2)) : parseInt((winW / 2) - (width / 2) - diff.W - object.offsetY - (thumbsOffset.W / 2)); 9848 else { 9849 top = (path == 'horizontal') ? top : parseInt(object.offsetX - diff.H - height - (thumbsOffset.H / 2)), 9850 left = (path == 'horizontal') ? parseInt(object.offsetX - diff.W - width - (thumbsOffset.W / 2)) : parseInt((winW / 2) - object.offsetY - (width / 2) - diff.W - (thumbsOffset.W / 2)); 9851 } 9852 9853 /*if (object.item.caption && !isNaN(width) && !isNaN(height) && UNCODE.wwidth > UNCODE.mediaQuery) { 9854 var objRatio = width / height; 9855 height = height - vars.captionHeight; 9856 width = height * objRatio; 9857 top = path == 'horizontal' ? parseInt((winH / 2) - (height / 2) - diff.H - (thumbsOffset.H / 2)) : top; 9858 }*/ 9859 9860 $('div.ilightbox-container', secondHolder).animate({ 9861 width: width, 9862 height: height 9863 }, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc'); 9864 9865 secondHolder.addClass(firstClass).css(transform, gpuAcceleration).animate({ 9866 top: top, 9867 left: left, 9868 opacity: opts.styles.prevOpacity, 9869 }, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc', function() { 9870 secondHolder.css(transform, ''); 9871
9872 $('.ilightbox-thumbnail', vars.thumbnails).removeClass('ilightbox-active').eq(item).addClass('ilightbox-active'); 9873 iL.positionThumbnails(); 9874 9875 if (iL.items[item]) { 9876 if (!iL.items[item].options.mousewheel) vars.lockWheel = true; 9877 else vars.lockWheel = false; 9878 9879 if (!iL.items[item].options.swipe) vars.lockSwipe = true; 9880 else vars.lockSwipe = false; 9881 } 9882 9883 vars.isSwipe = false; 9884 9885 // Remove iframe & video from previous slide 9886 if (['iframe', 'video'].indexOf(iL.items[vars.current].type) !== -1) { 9887 $('div.ilightbox-container', secondHolder).empty(); 9888 } 9889 9890 if (side == "next") { 9891 vars.nextPhoto = lastHolder, 9892 vars.prevPhoto = secondHolder, 9893 vars.holder = firstHolder; 9894 9895 vars.nextPhoto.hide(); 9896 9897 vars.next = vars.next + 1, 9898 vars.prev = vars.current, 9899 vars.current = vars.current + 1; 9900 9901 if (opts.infinite) { 9902 if (vars.current > vars.total - 1) vars.current = 0; 9903 if (vars.current == vars.total - 1) vars.next = 0; 9904 if (vars.current == 0) vars.prev = vars.total - 1; 9905 } 9906 9907 iL.createUI(); 9908 9909 if (!iL.items[vars.next]) 9910 vars.nextLock = false; 9911 else 9912 iL.loadContent(iL.items[vars.next], 'next'); 9913 } else { 9914 vars.prevPhoto = lastHolder; 9915 vars.nextPhoto = secondHolder; 9916 vars.holder = firstHolder; 9917 9918 vars.prevPhoto.hide(); 9919 9920 vars.next = vars.current; 9921 vars.current = vars.prev; 9922 vars.prev = vars.current - 1; 9923 9924 if (opts.infinite) { 9925 if (vars.current == vars.total - 1) vars.next = 0; 9926 if (vars.current == 0) vars.prev = vars.total - 1; 9927 } 9928 9929 iL.createUI(); 9930 9931 if (!iL.items[vars.prev]) 9932 vars.prevLock = false; 9933 else 9934 iL.loadContent(iL.items[vars.prev], 'prev'); 9935 } 9936 9937 // Add iframe & video content for current slide 9938 if (['iframe', 'video'].indexOf(iL.items[vars.current].type) !== -1) { 9939 iL.loadContent(iL.items[vars.current], 'current'); 9940 } 9941 9942 if (opts.linkId) setTimeout(function() { 9943 vars.hashLock = false; 9944 }, 55); 9945 9946 // Configure arrow buttons 9947 if (!opts.infinite) { 9948 vars.nextButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled'); 9949 9950 if (vars.current == 0) 9951 vars.prevButton.add(vars.innerPrevButton).addClass('disabled'); 9952 if (vars.current >= vars.total - 1) 9953 vars.nextButton.add(vars.innerNextButton).addClass('disabled'); 9954 } 9955 9956 iL.repositionPhoto(); 9957 9958 // Reset next cycle timeout 9959 iL.resetCycle(); 9960 9961 //Trigger the onAfterChange callback 9962 if (typeof opts.callback.onAfterChange == 'function') 9963 opts.callback.onAfterChange.call(iL, iL.ui); 9964 }); 9965 9966 top = (path == 'horizontal') ? getPixel(lastHolder, 'top') : ((side == "next") ? parseInt(-(winH / 2) - lastHolder.outerHeight()) : parseInt(top * 2)), 9967 left = (path == 'horizontal') ? ((side == "next") ? parseInt(-(winW / 2) - lastHolder.outerWidth()) : parseInt(left * 2)) : getPixel(lastHolder, 'left'); 9968 9969 lastHolder.css(transform, gpuAcceleration).animate({ 9970 top: top, 9971 left: left, 9972 opacity: opts.styles.nextOpacity 9973 }, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc', function() { 9974 lastHolder.css(transform, ''); 9975 }).addClass(secondClass); 9976 } 9977 }, 9978 9979 setCaption: function(obj, target) { 9980 var iL = this, 9981 caption = $('<div class="ilightbox-caption"></div>'); 9982 9983 if (obj.caption) { 9984 caption.html(obj.caption); 9985 $('div.ilightbox-container', target).append(caption); 9986 } 9987 }, 9988 9989 normalizeSocial: function(obj, url) { 9990 var iL = this, 9991 vars = iL.vars, 9992 opts = iL.options, 9993 baseURL = window.location.href; 9994 9995 $.each(obj, function(key, value) { 9996 if (!value) 9997 return true; 9998 9999 var item = key.toLowerCase(), 10000 source, text; 10001 10002 switch (item) { 10003 case 'facebook': 10004 source = "http://www.facebook.com/share.php?v=4&src=bm&u={URL}", 10005 text = "Share on Facebook"; 10006 break; 10007 case 'twitter': 10008 source = "http://twitter.com/home?status={URL}", 10009 text = "Share on Twitter"; 10010 break; 10011 case 'googleplus': 10012 source = "https://plus.google.com/share?url={URL}", 10013 text = "Share on Google+"; 10014 break; 10015 case 'delicious': 10016 source = "http://delicious.com/post?url={URL}", 10017 text = "Share on Delicious"; 10018 break; 10019 case 'digg': 10020 source = "http://digg.com/submit?phase=2&url={URL}", 10021 text = "Share on Digg"; 10022 break; 10023 case 'reddit': 10024 source = "http://reddit.com/submit?url={URL}", 10025 text = "Share on reddit"; 10026 break; 10027 } 10028 10029 obj[key] = { 10030 URL: value.URL && absolutizeURI(baseURL, value.URL) || opts.linkId && window.location.href || typeof url !== 'string' && baseURL || url && absolutizeURI(baseURL, url) || baseURL, 10031 source: value.source || source || value.URL && absolutizeURI(baseURL, value.URL) || url && absolutizeURI(baseURL, url), 10032 text: value.text || text || "Share on " + key, 10033 width: (typeof(value.width) != 'undefined' && !isNaN(value.width)) ? parseInt(value.width) : 640, 10034 height: value.height || 360 10035 }; 10036 10037 }); 10038 10039 return obj; 10040 }, 10041 10042 setSocial: function(obj, url, target) { 10043 var iL = this, 10044 socialBar = $('<div class="ilightbox-social"></div>'), 10045 buttons = '<ul>'; 10046 10047 obj = iL.normalizeSocial(obj, url); 10048 10049 $.each(obj, function(key, value) { 10050 var item = key.toLowerCase(), 10051 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, '+')); 10052 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>'; 10053 }); 10054 10055 buttons += '</ul>'; 10056 10057 socialBar.html(buttons); 10058 $('div.ilightbox-container', target).append(socialBar); 10059 }, 10060 10061 fullScreenAction: function() { 10062 var iL = this, 10063 vars = iL.vars; 10064 10065 if (fullScreenApi.supportsFullScreen) { 10066 if (fullScreenApi.isFullScreen()) fullScreenApi.cancelFullScreen(document.documentElement); 10067 else fullScreenApi.requestFullScreen(document.documentElement); 10068 } else { 10069 iL.doFullscreen(); 10070 } 10071 }, 10072 10073 doFullscreen: function() { 10074 var iL = this, 10075 vars = iL.vars, 10076 viewport = getViewport(), 10077 opts = iL.options; 10078 10079 if (opts.fullAlone) { 10080 var currentHolder = vars.holder, 10081 current = iL.items[vars.current], 10082 windowWidth = viewport.width, 10083 windowHeight = viewport.height, 10084 elements = [currentHolder, vars.nextPhoto, vars.prevPhoto, vars.nextButton, vars.prevButton, vars.overlay, vars.toolbar, vars.thumbnails, vars.loader], 10085 hideElements = [vars.nextPhoto, vars.prevPhoto, vars.nextButton, vars.prevButton, vars.loader, vars.thumbnails]; 10086 10087 if (!vars.isInFullScreen) { 10088 vars.isInFullScreen = vars.lockKey = vars.lockWheel = vars.lockSwipe = true; 10089 vars.overlay.css({ 10090 opacity: 1 10091 }); 10092 10093 $.each(hideElements, function(i, element) { 10094 element.hide(); 10095 }); 10096 10097 vars.fullScreenButton.attr('title', opts.text.exitFullscreen); 10098 10099 if (opts.fullStretchTypes.indexOf(current.type) != -1) currentHolder.data({
10100 naturalWidthOld: currentHolder.data('naturalWidth'), 10101 naturalHeightOld: currentHolder.data('naturalHeight'), 10102 naturalWidth: windowWidth, 10103 naturalHeight: windowHeight 10104 }); 10105 else { 10106 var viewport = current.options.fullViewPort || opts.fullViewPort || '', 10107 newWidth = windowWidth, 10108 newHeight = windowHeight, 10109 width = currentHolder.data('naturalWidth'), 10110 height = currentHolder.data('naturalHeight'); 10111 10112 if (viewport.toLowerCase() == 'fill') { 10113 newHeight = (newWidth / width) * height; 10114 10115 if (newHeight < windowHeight) { 10116 newWidth = (windowHeight / height) * width, 10117 newHeight = windowHeight; 10118 } 10119 } else if (viewport.toLowerCase() == 'fit') { 10120 var dims = iL.getNewDimenstions(newWidth, newHeight, width, height, true); 10121 10122 newWidth = dims.width, 10123 newHeight = dims.height; 10124 } else if (viewport.toLowerCase() == 'stretch') { 10125 newWidth = newWidth, 10126 newHeight = newHeight; 10127 } else { 10128 var scale = (width > newWidth || height > newHeight) ? true : false, 10129 dims = iL.getNewDimenstions(newWidth, newHeight, width, height, scale); 10130 newWidth = dims.width, 10131 newHeight = dims.height; 10132 } 10133 10134 currentHolder.data({ 10135 naturalWidthOld: currentHolder.data('naturalWidth'), 10136 naturalHeightOld: currentHolder.data('naturalHeight'), 10137 naturalWidth: newWidth, 10138 naturalHeight: newHeight 10139 }); 10140 } 10141 10142 $.each(elements, function(key, val) { 10143 val.addClass('ilightbox-fullscreen'); 10144 }); 10145 10146 //Trigger the onEnterFullScreen callback 10147 if (typeof opts.callback.onEnterFullScreen == 'function') opts.callback.onEnterFullScreen.call(iL, iL.ui); 10148 } else { 10149 vars.isInFullScreen = vars.lockKey = vars.lockWheel = vars.lockSwipe = false; 10150 vars.overlay.css({ 10151 opacity: iL.options.overlay.opacity 10152 }); 10153 10154 $.each(hideElements, function(i, element) { 10155 element.show(); 10156 }); 10157 10158 vars.fullScreenButton.attr('title', opts.text.enterFullscreen); 10159 10160 currentHolder.data({ 10161 naturalWidth: currentHolder.data('naturalWidthOld'), 10162 naturalHeight: currentHolder.data('naturalHeightOld'), 10163 naturalWidthOld: null, 10164 naturalHeightOld: null 10165 }); 10166 10167 $.each(elements, function(key, val) { 10168 val.removeClass('ilightbox-fullscreen'); 10169 }); 10170 10171 //Trigger the onExitFullScreen callback 10172 if (typeof opts.callback.onExitFullScreen == 'function') opts.callback.onExitFullScreen.call(iL, iL.ui); 10173 } 10174 } else { 10175 if (!vars.isInFullScreen) vars.isInFullScreen = true; 10176 else vars.isInFullScreen = false; 10177 } 10178 iL.repositionPhoto(true); 10179 }, 10180 10181 closeAction: function() { 10182 var iL = this, 10183 vars = iL.vars, 10184 opts = iL.options; 10185 10186 $win.unbind('.iLightBox'); 10187 $doc.off('.iLightBox'); 10188 10189 if (vars.isInFullScreen) fullScreenApi.cancelFullScreen(document.documentElement); 10190 10191 $('.ilightbox-overlay, .ilightbox-holder, .ilightbox-thumbnails').off('.iLightBox'); 10192 10193 if (opts.hide.effect) vars.overlay.stop().fadeOut(opts.hide.speed, function() { 10194 vars.overlay.remove(); 10195 vars.BODY.removeClass('ilightbox-noscroll').off('.iLightBox'); 10196 }); 10197 else { 10198 vars.overlay.remove(); 10199 vars.BODY.removeClass('ilightbox-noscroll').off('.iLightBox'); 10200 } 10201 10202 var fadeOuts = [vars.toolbar, vars.holder, vars.nextPhoto, vars.prevPhoto, vars.nextButton, vars.prevButton, vars.loader, vars.thumbnails]; 10203 10204 $.each(fadeOuts, function(i, element) { 10205 element.removeAttr('style').remove(); 10206 }); 10207 10208 vars.dontGenerateThumbs = vars.isInFullScreen = false; 10209 10210 window.iLightBox = null; 10211 10212 if (opts.linkId) { 10213 vars.hashLock = true; 10214 removeHash(); 10215 setTimeout(function() { 10216 vars.hashLock = false; 10217 }, 55); 10218 } 10219 10220 vars.nextButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled'); 10221 10222 //Trigger the onHide callback 10223 if (typeof opts.callback.onHide == 'function') opts.callback.onHide.call(iL, iL.ui); 10224 }, 10225 10226 repositionPhoto: function() { 10227 var iL = this, 10228 vars = iL.vars, 10229 opts = iL.options, 10230 path = opts.path.toLowerCase(), 10231 viewport = getViewport(), 10232 winWidth = viewport.width, 10233 winHeight = viewport.height; 10234 10235 if (viewport.width < UNCODE.mediaQuery) opts.styles.nextOffsetX = 0; 10236 10237 var thumbsOffsetW = (vars.isInFullScreen && opts.fullAlone || vars.isMobile) ? 0 : ((path == 'horizontal') ? 0 : vars.thumbnails.outerWidth()), 10238 thumbsOffsetH = vars.isMobile ? vars.toolbar.outerHeight() : ((vars.isInFullScreen && opts.fullAlone) ? 0 : ((path == 'horizontal') ? vars.thumbnails.outerHeight() : 0)), 10239 width = (vars.isInFullScreen && opts.fullAlone) ? winWidth : (winWidth - (opts.styles.pageOffsetX)), 10240 height = (vars.isInFullScreen && opts.fullAlone) ? winHeight : (winHeight - (opts.styles.pageOffsetY)), 10241 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, 10242 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))); 10243 10244 var elObject = { 10245 type: 'current', 10246 width: width, 10247 height: height, 10248 item: iL.items[vars.current], 10249 offsetW: offsetW, 10250 offsetH: offsetH,
10251 thumbsOffsetW: thumbsOffsetW, 10252 thumbsOffsetH: thumbsOffsetH, 10253 animate: arguments.length, 10254 holder: vars.holder 10255 }; 10256 10257 iL.repositionEl(elObject); 10258 10259 if (iL.items[vars.next]) { 10260 elObject = $.extend(elObject, { 10261 type: 'next', 10262 item: iL.items[vars.next], 10263 offsetX: opts.styles.nextOffsetX, 10264 offsetY: opts.styles.nextOffsetY, 10265 holder: vars.nextPhoto 10266 }); 10267 10268 iL.repositionEl(elObject); 10269 } 10270 10271 if (iL.items[vars.prev]) { 10272 elObject = $.extend(elObject, { 10273 type: 'prev', 10274 item: iL.items[vars.prev], 10275 offsetX: opts.styles.nextOffsetX, 10276 offsetY: opts.styles.prevOffsetY, 10277 holder: vars.prevPhoto 10278 }); 10279 10280 iL.repositionEl(elObject); 10281 } 10282 10283 var loaderCss = (path == "horizontal") ? { 10284 left: parseInt((width / 2) - (vars.loader.outerWidth() / 2)) 10285 } : { 10286 top: parseInt((height / 2) - (vars.loader.outerHeight() / 2)) 10287 }; 10288 vars.loader.css(loaderCss); 10289 }, 10290 10291 repositionEl: function(obj) { 10292 var iL = this, 10293 vars = iL.vars, 10294 opts = iL.options, 10295 path = opts.path.toLowerCase(), 10296 widthAvail = (obj.type == 'current') ? ((vars.isInFullScreen && opts.fullAlone) ? obj.width : (obj.width - obj.offsetW)) : (obj.width - obj.offsetW), 10297 heightAvail = (obj.type == 'current') ? ((vars.isInFullScreen && opts.fullAlone) ? obj.height : (obj.height - obj.offsetH)) : (obj.height - obj.offsetH), 10298 itemParent = obj.item, 10299 item = obj.item.options, 10300 holder = obj.holder, 10301 offsetX = obj.offsetX || 0, 10302 offsetY = obj.offsetY || 0, 10303 thumbsOffsetW = obj.thumbsOffsetW, 10304 thumbsOffsetH = obj.thumbsOffsetH; 10305 10306 if (obj.type == 'current') { 10307 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); 10308 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); 10309 } else { 10310 if (typeof item.width == 'number' && item.width) widthAvail = (item.width > widthAvail) ? widthAvail : item.width; 10311 if (typeof item.height == 'number' && item.height) heightAvail = (item.height > heightAvail) ? heightAvail : item.height; 10312 } 10313 10314 heightAvail = parseInt(heightAvail - $('.ilightbox-inner-toolbar', holder).outerHeight()); 10315 10316 var width = (typeof item.width == 'string' && item.width.indexOf('%') != -1) ? percentToValue(parseInt(item.width.replace('%', '')), obj.width) : holder.data('naturalWidth'), 10317 height = (typeof item.height == 'string' && item.height.indexOf('%') != -1) ? percentToValue(parseInt(item.height.replace('%', '')), obj.height) : holder.data('naturalHeight'); 10318 10319 var dims = ((typeof item.width == 'string' && item.width.indexOf('%') != -1 || typeof item.height == 'string' && item.height.indexOf('%') != -1) ? { 10320 width: width, 10321 height: height 10322 } : iL.getNewDimenstions(widthAvail, heightAvail, width, height)), 10323 newDims = $.extend({}, dims, {}); 10324 10325 if (obj.type == 'prev' || obj.type == 'next') 10326 width = parseInt(dims.width * ((obj.type == 'next') ? opts.styles.nextScale : opts.styles.prevScale)), 10327 height = parseInt(dims.height * ((obj.type == 'next') ? opts.styles.nextScale : opts.styles.prevScale)); 10328 else 10329 width = dims.width, 10330 height = dims.height; 10331 10332 var widthDiff = parseInt((getPixel(holder, 'padding-left') + getPixel(holder, 'padding-right') + getPixel(holder, 'border-left-width') + getPixel(holder, 'border-right-width')) / 2), 10333 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); 10334 10335 switch (obj.type) { 10336 case 'current': 10337 var top = parseInt((obj.height / 2) - (height / 2) - heightDiff - (thumbsOffsetH / 2)), 10338 left = parseInt((obj.width / 2) - (width / 2) - widthDiff - (thumbsOffsetW / 2)); 10339 break; 10340
10341 case 'next': 10342 var top = (path == 'horizontal') ? parseInt((obj.height / 2) - offsetY - (height / 2) - heightDiff - (thumbsOffsetH / 2)) : parseInt(obj.height - offsetX - heightDiff - (thumbsOffsetH / 2)), 10343 left = (path == 'horizontal') ? parseInt(obj.width - offsetX - widthDiff - (thumbsOffsetW / 2)) : parseInt((obj.width / 2) - (width / 2) - widthDiff - offsetY - (thumbsOffsetW / 2)); 10344 break; 10345 10346 case 'prev': 10347 var top = (path == 'horizontal') ? parseInt((obj.height / 2) - offsetY - (height / 2) - heightDiff - (thumbsOffsetH / 2)) : parseInt(offsetX - heightDiff - height - (thumbsOffsetH / 2)), 10348 left = (path == 'horizontal') ? parseInt(offsetX - widthDiff - width - (thumbsOffsetW / 2)) : parseInt((obj.width / 2) - offsetY - (width / 2) - widthDiff - (thumbsOffsetW / 2)); 10349 break; 10350 } 10351 10352 holder.data('offset', { 10353 top: top, 10354 left: left, 10355 newDims: newDims, 10356 diff: { 10357 W: widthDiff, 10358 H: heightDiff 10359 }, 10360 thumbsOffset: { 10361 W: thumbsOffsetW, 10362 H: thumbsOffsetH 10363 }, 10364 object: obj 10365 }); 10366 10367 var opacityMobile; 10368 if ( isMobile ) { 10369 opacityMobile = { 10370 opacity: 1, 10371 top: top, 10372 left: left 10373 }; 10374 } else { 10375 opacityMobile = { 10376 top: top, 10377 left: left 10378 }; 10379 } 10380 10381 if (obj.animate > 0 && opts.effects.reposition) { 10382 holder.css(transform, gpuAcceleration).stop().animate( 10383 opacityMobile, 10384 opts.effects.repositionSpeed, 'easeOutCirc', function() { 10385 holder.css(transform, ''); 10386 }); 10387 $('div.ilightbox-container', holder).stop().animate({ 10388 width: width, 10389 height: height 10390 }, opts.effects.repositionSpeed, 'easeOutCirc'); 10391 $('div.ilightbox-inner-toolbar', holder).stop().animate({ 10392 width: width 10393 }, opts.effects.repositionSpeed, 'easeOutCirc', function() { 10394 $(this).css('overflow', 'visible'); 10395 }); 10396 } else { 10397 holder.css(opacityMobile); 10398 $('div.ilightbox-container', holder).css({ 10399 width: width, 10400 height: height 10401 }); 10402 $('div.ilightbox-inner-toolbar', holder).css({ 10403 width: width 10404 }); 10405 } 10406 }, 10407 10408 10409 resume: function(priority) { 10410 var iL = this, 10411 vars = iL.vars, 10412 opts = iL.options; 10413 10414 if (!opts.slideshow.pauseTime || opts.controls.slideshow && vars.total <= 1 || priority < vars.isPaused) { 10415 return; 10416 } 10417 10418 vars.isPaused = 0; 10419 10420 if (vars.cycleID) { 10421 vars.cycleID = clearTimeout(vars.cycleID); 10422 } 10423 10424 vars.cycleID = setTimeout(function() { 10425 if (vars.current == vars.total - 1) iL.goTo(0); 10426 else iL.moveTo('next'); 10427 }, opts.slideshow.pauseTime); 10428 }, 10429 10430 pause: function(priority) { 10431 var iL = this, 10432 vars = iL.vars, 10433 opts = iL.options; 10434 10435 if (priority < vars.isPaused) { 10436 return; 10437 } 10438 10439 vars.isPaused = priority || 100; 10440 10441 if (vars.cycleID) { 10442 vars.cycleID = clearTimeout(vars.cycleID); 10443 } 10444 }, 10445 10446 resetCycle: function() { 10447 var iL = this, 10448 vars = iL.vars, 10449 opts = iL.options; 10450 10451 if (opts.controls.slideshow && vars.cycleID && !vars.isPaused) { 10452 iL.resume(); 10453 } 10454 }, 10455 10456 getNewDimenstions: function(width, height, width_old, height_old, thumb) { 10457 var iL = this; 10458 10459 if (!width) factor = height / height_old; 10460 else if (!height) factor = width / width_old; 10461 else factor = min(width / width_old, height / height_old); 10462 10463 if (!thumb) { 10464 if (factor > iL.options.maxScale) factor = iL.options.maxScale; 10465 else if (factor < iL.options.minScale) factor = iL.options.minScale; 10466 } 10467 10468 var final_width = (iL.options.keepAspectRatio) ? round(width_old * factor) : width, 10469 final_height = (iL.options.keepAspectRatio) ? round(height_old * factor) : height; 10470 10471 return { 10472 width: final_width, 10473 height: final_height, 10474 ratio: factor 10475 }; 10476 }, 10477 10478 setOption: function(options) { 10479 var iL = this; 10480 10481 iL.options = $.extend(true, iL.options, options || {}); 10482 iL.refresh(); 10483 }, 10484 10485 availPlugins: function() { 10486 var iL = this, 10487 testEl = document.createElement("video"); 10488 10489 iL.plugins = { 10490 flash: !isMobile, 10491 quicktime: (parseInt(PluginDetect.getVersion("QuickTime")) >= 0) ? true : false, 10492 html5H264: !!(testEl.canPlayType && testEl.canPlayType('video/mp4').replace(/no/, '')), 10493 html5WebM: !!(testEl.canPlayType && testEl.canPlayType('video/webm').replace(/no/, '')), 10494 html5Vorbis: !!(testEl.canPlayType && testEl.canPlayType('video/ogg').replace(/no/, '')), 10495 html5QuickTime: !!(testEl.canPlayType && testEl.canPlayType('video/quicktime').replace(/no/, '')) 10496 }; 10497 }, 10498 10499 addContent: function(element, obj) { 10500 var iL = this, 10501 el; 10502 10503 switch (obj.type) { 10504 case 'video': 10505 var HTML5 = false, 10506 videoType = obj.videoType, 10507 html5video = obj.options.html5video; 10508 10509 if (((videoType == 'video/mp4' || obj.ext == 'mp4' || obj.ext == 'm4v') || html5video.h264) && iL.plugins.html5H264) 10510 obj.ext = 'mp4', 10511 obj.URL = html5video.h264 || obj.URL; 10512 else if (html5video.webm && iL.plugins.html5WebM) 10513 obj.ext = 'webm', 10514 obj.URL = html5video.webm || obj.URL; 10515 else if (html5video.ogg && iL.plugins.html5Vorbis) 10516 obj.ext = 'ogv', 10517 obj.URL = html5video.ogg || obj.URL; 10518 10519 if (iL.plugins.html5H264 && (videoType == 'video/mp4' || obj.ext == 'mp4' || obj.ext == 'm4v')) HTML5 = true, videoType = "video/mp4"; 10520 else if (iL.plugins.html5WebM && (videoType == 'video/webm' || obj.ext == 'webm')) HTML5 = true, videoType = "video/webm"; 10521 else if (iL.plugins.html5Vorbis && (videoType == 'video/ogg' || obj.ext == 'ogv')) HTML5 = true, videoType = "video/ogg"; 10522 else if (iL.plugins.html5QuickTime && (videoType == 'video/quicktime' || obj.ext == 'mov' || obj.ext == 'qt')) HTML5 = true, videoType = "video/quicktime"; 10523 10524 if (HTML5) { 10525 el = $('<video />
10525', { 10526 "width": "100%", 10527 "height": "100%", 10528 "preload": html5video.preload, 10529 "autoplay": html5video.autoplay, 10530 "loop": html5video.loop, 10531 "poster": html5video.poster, 10532 "controls": html5video.controls, 10533 "controlslist": "nodownload" 10534 }).append($('<source />', { 10535 "src": obj.URL, 10536 "type": videoType 10537 })); 10538 } else { 10539 if (!iL.plugins.quicktime) el = $('<span />', { 10540 "class": "ilightbox-alert", 10541 html: iL.options.errors.missingPlugin.replace('{pluginspage}', pluginspages.quicktime).replace('{type}', 'QuickTime') 10542 }); 10543 else { 10544 10545 el = $('<object />', { 10546 "type": "video/quicktime", 10547 "pluginspage": pluginspages.quicktime 10548 }).attr({ 10549 "data": obj.URL, 10550 "width": "100%", 10551 "height": "100%" 10552 }).append($('<param />', { 10553 "name": "src", 10554 "value": obj.URL 10555 })).append($('<param />', { 10556 "name": "autoplay", 10557 "value": "false" 10558 })).append($('<param />', { 10559 "name": "loop", 10560 "value": "false" 10561 })).append($('<param />', { 10562 "name": "scale", 10563 "value": "tofit" 10564 })); 10565 10566 if (browser.msie) el = QT_GenerateOBJECTText(obj.URL, '100%', '100%', '', 'SCALE', 'tofit', 'AUTOPLAY', 'false', 'LOOP', 'false'); 10567 } 10568 } 10569 10570 break; 10571 10572 case 'flash': 10573 if (!iL.plugins.flash) el = $('<span />', { 10574 "class": "ilightbox-alert", 10575 html: iL.options.errors.missingPlugin.replace('{pluginspage}', pluginspages.flash).replace('{type}', 'Adobe Flash player') 10576 }); 10577 else { 10578 var flashvars = "", 10579 i = 0; 10580 10581 if (obj.options.flashvars) $.each(obj.options.flashvars, function(k, v) { 10582 if (i != 0) flashvars += "&"; 10583 flashvars += k + "=" + encodeURIComponent(v); 10584 i++; 10585 }); 10586 else flashvars = null; 10587 10588 el = $('<embed />').attr({ 10589 "type": "application/x-shockwave-flash", 10590 "src": obj.URL, 10591 "width": (typeof obj.options.width == 'number' && obj.options.width && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.width : "100%", 10592 "height": (typeof obj.options.height == 'number' && obj.options.height && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.height : "100%", 10593 "quality": "high", 10594 "bgcolor": "#000000", 10595 "play": "true", 10596 "loop": "true", 10597 "menu": "true", 10598 "wmode": "transparent", 10599 "scale": "showall", 10600 "allowScriptAccess": "always", 10601 "allowFullScreen": "true", 10602 "flashvars": flashvars, 10603 "fullscreen": "yes" 10604 }); 10605 } 10606 10607 break; 10608 10609 case 'iframe': 10610 el = $('<iframe />').attr({ 10611 "width": (typeof obj.options.width == 'number' && obj.options.width && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.width : "100%", 10612 "height": (typeof obj.options.height == 'number' && obj.options.height && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.height : "100%", 10613 src: obj.URL, 10614 frameborder: 0, 10615 'hspace': 0, 10616 'vspace': 0, 10617 'scrolling': supportTouch ? 'auto' : 'scroll', 10618 'webkitAllowFullScreen': '', 10619 'mozallowfullscreen': '', 10620 'allowFullScreen': '' 10621 }); 10622 10623 break; 10624 10625 case 'inline': 10626 el = $('<div class="ilightbox-wrapper"></div>').html($(obj.URL).clone(true)); 10627 10628 break; 10629 10630 case 'html': 10631 var object = obj.URL, 10632 el; 10633 10634 if (object[0].nodeName) { 10635 el = $('<div class="ilightbox-wrapper"></div>').html(object); 10636 } else { 10637 var dom = $(obj.URL), 10638 html = (dom.selector) ? $('<div>' + dom + '</div>') : dom; 10639 el = $('<div class="ilightbox-wrapper"></div>').html(html); 10640 } 10641 10642 break; 10643 } 10644 10645 $('div.ilightbox-container', element).empty().html(el); 10646 10647 // For fixing Chrome about just playing the video for first time 10648 if (el[0].tagName.toLowerCase() === 'video' && browser.webkit) setTimeout(function() { 10649 var src = el[0].currentSrc + '?' + floor(random() * 30000); 10650 el[0].currentSrc = src; 10651 el[0].src = src; 10652 }); 10653 10654 return el; 10655 }, 10656 10657 ogpRecognition: function(obj, callback) { 10658 var iL = this, 10659 url = obj.URL; 10660 10661 iL.showLoader(); 10662 doAjax(url, function(data) { 10663 iL.hideLoader(); 10664 if (data) { 10665 var object = new Object(); 10666 10667 object.length = false, 10668 object.url = data.url; 10669 10670 if (data.status == 200) { 10671 var result = data.results, 10672 type = result.type, 10673 source = result.source; 10674 10675 object.source = source.src, 10676 object.width = source.width && parseInt(source.width) || 0, 10677 object.height = source.height && parseInt(source.height) || 0, 10678 object.type = type, 10679 object.thumbnail = source.thumbnail || result.images && result.images[0], 10680 object.html5video = result.html5video || {}, 10681 object.length = true; 10682 10683 if (source.type == 'application/x-shockwave-flash') object.type = "flash"; 10684 else if (source.type.indexOf("video/") != -1) object.type = "video"; 10685 else if (source.type.indexOf("/html") != -1) object.type = "iframe"; 10686 else if (source.type.indexOf("image/") != -1) object.type = "image"; 10687 10688 } else if (typeof data.response != 'undefined') 10689 throw data.response; 10690 10691 callback.call(this, object.length ? object : false); 10692 } 10693 }); 10694 }, 10695 10696 hashChangeHandler: function(url) { 10697 var iL = this, 10698 vars = iL.vars, 10699 opts = iL.options, 10700 URL = url || window.location.href, 10701 hash = parseURI(URL).hash, 10702 split = hash.split('/'), 10703 index = split[1]; 10704 10705 if (vars.hashLock || ('#' + opts.linkId != split[0] && hash.length > 1)) return; 10706 10707 if (index) { 10708 var target = split[1] || 0; 10709 if (iL.items[target]) {
10710 var overlay = $('.ilightbox-overlay'); 10711 if (overlay.length && overlay.attr('linkid') == opts.linkId) { 10712 iL.goTo(target); 10713 } else { 10714 iL.itemsObject[target].trigger(supportTouch ? 'itap' : 'click'); 10715 //iL.goTo(target); 10716 } 10717 } else { 10718 var overlay = $('.ilightbox-overlay'); 10719 if (overlay.length) iL.closeAction(); 10720 } 10721 } else { 10722 var overlay = $('.ilightbox-overlay'); 10723 if (overlay.length) iL.closeAction(); 10724 } 10725 } 10726 }; 10727 10728 /** 10729 * Parse style to pixels. 10730 * 10731 * @param {Object} $element jQuery object with element. 10732 * @param {Property} property CSS property to get the pixels from. 10733 * 10734 * @return {Int} 10735 */ 10736 function getPixel($element, property) { 10737 return parseInt($element.css(property), 10) || 0; 10738 } 10739 10740 /** 10741 * Make sure that number is within the limits. 10742 * 10743 * @param {Number} number 10744 * @param {Number} min 10745 * @param {Number} max 10746 * 10747 * @return {Number} 10748 */ 10749 function within(number, min, max) { 10750 return number < min ? min : number > max ? max : number; 10751 } 10752 10753 /** 10754 * Get viewport/window size (width and height). 10755 * 10756 * @return {Object} 10757 */ 10758 function getViewport() { 10759 var e = window, 10760 a = 'inner'; 10761 if (!('innerWidth' in window)) { 10762 a = 'client'; 10763 e = document.documentElement || document.body; 10764 } 10765 return { 10766 width: e[a + 'Width'], 10767 height: e[a + 'Height'] 10768 } 10769 } 10770 10771 /** 10772 * Remove hash tag from the URL 10773 * 10774 * @return {Void} 10775 */ 10776 function removeHash() { 10777 var scroll = getScrollXY(); 10778 10779 //UNCODE change 10780 //window.location.hash = ""; 10781 history.pushState("", document.title, window.location.pathname + window.location.search); 10782 10783 // Restore the scroll offset, should be flicker free 10784 window.scrollTo(scroll.x, scroll.y); 10785 } 10786 10787 /** 10788 * Do the ajax requests with callback. 10789 * 10790 * @param {String} url 10791 * @param {Function} callback 10792 * 10793 * @return {Void} 10794 */ 10795 function doAjax(url, callback) { 10796 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'); 10797 $.ajax({ 10798 url: url, 10799 dataType: 'jsonp' 10800 }); 10801 10802 iLCallback = function(data) { 10803 callback.call(this, data); 10804 }; 10805 } 10806 10807 /** 10808 * Find image from DOM elements 10809 * 10810 * @param {Element} element 10811 * 10812 * @return {Void} 10813 */ 10814 function findImageInElement(element) { 10815 var elements = $('*', element), 10816 imagesArr = new Array(); 10817 10818 elements.each(function() { 10819 var url = "", 10820 element = this; 10821 10822 if ($(element).css("background-image") != "none") { 10823 url = $(element).css("background-image"); 10824 } else if (typeof($(element).attr("src")) != "undefined" && element.nodeName.toLowerCase() == "img") { 10825 url = $(element).attr("src"); 10826 } 10827 10828 if (url.indexOf("gradient") == -1) { 10829 url = url.replace(/url\(\"/g, ""); 10830 url = url.replace(/url\(/g, ""); 10831 url = url.replace(/\"\)/g, ""); 10832 url = url.replace(/\)/g, ""); 10833 10834 var urls = url.split(","); 10835 10836 for (var i = 0; i < urls.length; i++) { 10837 if (urls[i].length > 0 && $.inArray(urls[i], imagesArr) == -1) { 10838 var extra = ""; 10839 if (browser.msie && browser.version < 9) { 10840 extra = "?" + floor(random() * 3000); 10841 } 10842 imagesArr.push(urls[i] + extra); 10843 } 10844 } 10845 } 10846 }); 10847 10848 return imagesArr; 10849 } 10850 10851 /** 10852 * Get file extension. 10853 * 10854 * @param {String} URL 10855 * 10856 * @return {String} 10857 */ 10858 function getExtension(URL) { 10859 if (URL !== null) { 10860 //UNCODE: fix issue to detect media type with query strings 10861 var ext = URL.indexOf('?') !== -1 ? URL.split('?')[0] : URL; 10862 ext = ext.split('.').pop().toLowerCase(); 10863 10864 return ext; 10865 } 10866 } 10867 10868 /** 10869 * Get type via extension. 10870 * 10871 * @param {String} URL 10872 * 10873 * @return {String} 10874 */ 10875 function getTypeByExtension(URL) { 10876 var type, 10877 ext = getExtension(URL); 10878 10879 if (extensions.image.indexOf(ext) !== -1) type = 'image'; 10880 else if (extensions.flash.indexOf(ext) !== -1) type = 'flash'; 10881 else if (extensions.video.indexOf(ext) !== -1) type = 'video'; 10882 else if (ext.substring(0, 1) == "#") type = 'inline'; //Uncode addition 10883 else type = 'iframe'; 10884 10885 return type; 10886 } 10887 10888 /** 10889 * Return value from percent of a number. 10890 * 10891 * @param {Number} percent 10892 * @param {Number} total 10893 * 10894 * @return {Number} 10895 */ 10896 function percentToValue(percent, total) { 10897 return parseInt((total / 100) * percent); 10898 } 10899 10900 /** 10901 * A JavaScript equivalent of PHP’s parse_url. 10902 * 10903 * @param {String} url The URL to parse. 10904 * 10905 * @return {Mixed} 10906 */ 10907 function parseURI(url) { 10908 var m = String(url).replace(/^\s+|\s+$/g, '').match(/^([^:\/?#]+:)?(\/\/(?:[^:@]*(?::[^:@]*)?@)?(([^:\/?#]*)(?::(\d*))?))?([^?#]*)(\?[^#]*)?(#[\s\S]*)?/); 10909 // authority = '//' + user + ':' + pass '@' + hostname + ':' port 10910 return (m ? { 10911 href: m[0] || '', 10912 protocol: m[1] || '', 10913 authority: m[2] || '', 10914 host: m[3] || '', 10915 hostname: m[4] || '', 10916 port: m[5] || '', 10917 pathname: m[6] || '', 10918 search: m[7] || '', 10919 hash: m[8] || '' 10920 } : null); 10921 } 10922 10923 /** 10924 * Gets the absolute URI. 10925 * 10926 * @param {String} href The relative URL. 10927 * @param {String} base The base URL. 10928 * 10929 * @return {String} The absolute URL. 10930 */ 10931 function absolutizeURI(base, href) { // RFC 3986 10932 var iL = this; 10933 10934 function removeDotSegments(input) { 10935 var output = []; 10936 input.replace(/^(\.\.?(\/|$))+/, '') 10937 .replace(/\/(\.(\/|$))+/g, '/') 10938 .replace(/\/\.\.$/, '/../') 10939 .replace(/\/?[^\/]*/g, function(p) { 10940 if (p === '/..') { 10941 output.pop(); 10942 } else { 10943 output.push(p); 10944 } 10945 }); 10946 return output.join('').replace(/^\//, input.charAt(0) === '/' ? '/' : ''); 10947 } 10948 10949 href = parseURI(href || ''); 10950 base = parseURI(base || ''); 10951 10952 return !href || !base ? null : (href.protocol || base.protocol) + 10953 (href.protocol || href.authority ? href.authority : base.authority) + 10954 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)) + 10955 (href.protocol || href.authority || href.pathname ? href.search : (href.search || base.search)) + 10956 href.hash; 10957 } 10958 10959 /** 10960 * A JavaScript equivalent of PHP’s version_compare. 10961 * 10962 * @param {String} v1 10963 * @param {String} v2 10964 * @param {String} operator
10965 * 10966 * @return {Boolean} 10967 */ 10968 function version_compare(v1, v2, operator) { 10969 this.php_js = this.php_js || {}; 10970 this.php_js.ENV = this.php_js.ENV || {}; 10971 var i = 0, 10972 x = 0, 10973 compare = 0, 10974 vm = { 10975 'dev': -6, 10976 'alpha': -5, 10977 'a': -5, 10978 'beta': -4, 10979 'b': -4, 10980 'RC': -3, 10981 'rc': -3, 10982 '#': -2, 10983 'p': 1, 10984 'pl': 1 10985 }, 10986 prepVersion = function(v) { 10987 v = ('' + v).replace(/[_\-+]/g, '.'); 10988 v = v.replace(/([^.\d]+)/g, '.$1.').replace(/\.{2,}/g, '.'); 10989 return (!v.length ? [-8] : v.split('.')); 10990 }, 10991 numVersion = function(v) { 10992 return !v ? 0 : (isNaN(v) ? vm[v] || -7 : parseInt(v, 10)); 10993 }; 10994 v1 = prepVersion(v1); 10995 v2 = prepVersion(v2); 10996 x = max(v1.length, v2.length); 10997 for (i = 0; i < x; i++) { 10998 if (v1[i] == v2[i]) { 10999 continue; 11000 } 11001 v1[i] = numVersion(v1[i]); 11002 v2[i] = numVersion(v2[i]); 11003 if (v1[i] < v2[i]) { 11004 compare = -1; 11005 break; 11006 } else if (v1[i] > v2[i]) { 11007 compare = 1; 11008 break; 11009 } 11010 } 11011 if (!operator) { 11012 return compare; 11013 } 11014 11015 switch (operator) { 11016 case '>': 11017 case 'gt': 11018 return (compare > 0); 11019 case '>=': 11020 case 'ge': 11021 return (compare >= 0); 11022 case '<=': 11023 case 'le': 11024 return (compare <= 0); 11025 case '==': 11026 case '=': 11027 case 'eq': 11028 return (compare === 0); 11029 case '<>': 11030 case '!=': 11031 case 'ne': 11032 return (compare !== 0); 11033 case '': 11034 case '<': 11035 case 'lt': 11036 return (compare < 0); 11037 default: 11038 return null; 11039 } 11040 } 11041 11042 11043 // Begin the iLightBox plugin 11044 $.fn.iLightBox = function() { 11045 11046 var args = arguments, 11047 opt = ($.isPlainObject(args[0])) ? args[0] : args[1], 11048 items = ($.isArray(args[0]) || typeof args[0] == 'string') ? args[0] : args[1]; 11049 11050 if (!opt) opt = {}; 11051 11052 // Default options. Play carefully. 11053 var options = $.extend(true, { 11054 attr: 'href', 11055 path: 'vertical', 11056 skin: 'dark', 11057 linkId: false, 11058 infinite: false, 11059 startFrom: 0, 11060 randomStart: false, 11061 keepAspectRatio: true, 11062 maxScale: 1, 11063 minScale: .2, 11064 innerToolbar: false, 11065 smartRecognition: false, 11066 mobileOptimizer: true, 11067 fullAlone: true, 11068 fullViewPort: null, 11069 fullStretchTypes: 'flash, video', 11070 overlay: { 11071 blur: true, 11072 opacity: .85 11073 }, 11074 controls: { 11075 arrows: false, 11076 slideshow: false, 11077 toolbar: true, 11078 fullscreen: true, 11079 thumbnail: true, 11080 keyboard: true, 11081 mousewheel: true, 11082 swipe: true 11083 }, 11084 keyboard: { 11085 left: true, // previous 11086 right: true, // next 11087 up: true, // previous 11088 down: true, // next 11089 esc: true, // close 11090 shift_enter: true // fullscreen 11091 }, 11092 show: { 11093 effect: true, 11094 speed: 300, 11095 title: true 11096 }, 11097 hide: { 11098 effect: true, 11099 speed: 300 11100 }, 11101 caption: { 11102 start: true, 11103 show: 'mouseenter', 11104 hide: 'mouseleave' 11105 }, 11106 social: { 11107 start: true, 11108 show: 'mouseenter', 11109 hide: 'mouseleave',
11110 buttons: false 11111 }, 11112 styles: { 11113 pageOffsetX: 0, 11114 pageOffsetY: 0, 11115 nextOffsetX: 45, 11116 nextOffsetY: 0, 11117 nextOpacity: 1, 11118 nextScale: 1, 11119 prevOffsetX: 45, 11120 prevOffsetY: 0, 11121 prevOpacity: 1, 11122 prevScale: 1 11123 }, 11124 thumbnails: { 11125 maxWidth: 120, 11126 maxHeight: 80, 11127 normalOpacity: 1, 11128 activeOpacity: .6 11129 }, 11130 effects: { 11131 reposition: true, 11132 repositionSpeed: 200, 11133 switchSpeed: 500, 11134 loadedFadeSpeed: 180, 11135 fadeSpeed: 200 11136 }, 11137 slideshow: { 11138 pauseTime: 5000, 11139 pauseOnHover: false, 11140 startPaused: true 11141 }, 11142 text: { 11143 close: "Press Esc to close", 11144 enterFullscreen: "Enter Fullscreen (Shift+Enter)", 11145 exitFullscreen: "Exit Fullscreen (Shift+Enter)", 11146 slideShow: "Slideshow", 11147 next: "Next", 11148 previous: "Previous" 11149 }, 11150 errors: { 11151 loadImage: "An error occurred when trying to load photo.", 11152 loadContents: "An error occurred when trying to load contents.", 11153 missingPlugin: "The content your are attempting to view requires the <a href='{pluginspage}' target='_blank'>{type} plugin<\/a>." 11154 }, 11155 ajaxSetup: { 11156 url: '', 11157 beforeSend: function(jqXHR, settings) {}, 11158 cache: false, 11159 complete: function(jqXHR, textStatus) {}, 11160 crossDomain: false, 11161 error: function(jqXHR, textStatus, errorThrown) {}, 11162 success: function(data, textStatus, jqXHR) {}, 11163 global: true, 11164 ifModified: false, 11165 username: null, 11166 password: null, 11167 type: 'GET' 11168 }, 11169 callback: {} 11170 }, opt); 11171 11172 var instant = ($.isArray(items) || typeof items == 'string') ? true : false; 11173 11174 items = $.isArray(items) ? items : new Array(); 11175 11176 if (typeof args[0] == 'string') items[0] = args[0]; 11177 11178 if (version_compare($.fn.jquery, '1.8', '>=')) { 11179 var iLB = new iLightBox($(this), options, items, instant); 11180 return { 11181 close: function() { 11182 iLB.closeAction(); 11183 }, 11184 fullscreen: function() { 11185 iLB.fullScreenAction(); 11186 }, 11187 moveNext: function() { 11188 iLB.moveTo('next'); 11189 }, 11190 movePrev: function() { 11191 iLB.moveTo('prev'); 11192 }, 11193 goTo: function(index) { 11194 iLB.goTo(index); 11195 }, 11196 refresh: function() { 11197 iLB.refresh(); 11198 }, 11199 reposition: function() { 11200 (arguments.length > 0) ? iLB.repositionPhoto(true): iLB.repositionPhoto(); 11201 }, 11202 setOption: function(options) { 11203 iLB.setOption(options); 11204 }, 11205 destroy: function() { 11206 iLB.closeAction(); 11207 iLB.dispatchItemsEvents(); 11208 } 11209 }; 11210 } else { 11211 throw "The jQuery version that was loaded is too old. iLightBox requires jQuery 1.8+"; 11212 } 11213 11214 }; 11215 11216 11217 $.iLightBox = function() { 11218 return $.fn.iLightBox(arguments[0], arguments[1]); 11219 }; 11220 11221 11222 $.extend($.easing, { 11223 easeInCirc: function(x, t, b, c, d) { 11224 return -c * (sqrt(1 - (t /= d) * t) - 1) + b; 11225 }, 11226 easeOutCirc: function(x, t, b, c, d) { 11227 return c * sqrt(1 - (t = t / d - 1) * t) + b; 11228 }, 11229 easeInOutCirc: function(x, t, b, c, d) { 11230 if ((t /= d / 2) < 1) return -c / 2 * (sqrt(1 - t * t) - 1) + b; 11231 return c / 2 * (sqrt(1 - (t -= 2) * t) + 1) + b; 11232 } 11233 }); 11234 11235 function getScrollXY() { 11236 var scrOfX = 0, 11237 scrOfY = 0; 11238 if (typeof(window.pageYOffset) == 'number') { 11239 //Netscape compliant 11240 scrOfY = window.pageYOffset; 11241 scrOfX = window.pageXOffset; 11242 } else if (document.body && (document.body.scrollLeft || document.body.scrollTop)) { 11243 //DOM compliant 11244 scrOfY = document.body.scrollTop; 11245 scrOfX = document.body.scrollLeft; 11246 } else if (document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)) { 11247 //IE6 standards compliant mode 11248 scrOfY = document.documentElement.scrollTop; 11249 scrOfX = document.documentElement.scrollLeft; 11250 } 11251 return { 11252 x: scrOfX, 11253 y: scrOfY 11254 }; 11255 } 11256 11257 (function() { 11258 // add new event shortcuts 11259 $.each(("touchstart touchmove touchend " + 11260 "tap taphold " + 11261 "swipe swipeleft swiperight " + 11262 "scrollstart scrollstop").split(" "), function(i, name) { 11263 11264 $.fn[name] = function(fn) { 11265 return fn ? this.bind(name, fn) : this.trigger(name); 11266 }; 11267 11268 // jQuery < 1.8 11269 // if ($.attrFn) { 11270 // $.attrFn[name] = true; 11271 // } 11272 }); 11273 11274 var tapSettings = { 11275 startEvent: 'touchstart.iTap', 11276 endEvent: 'touchend.iTap' 11277 }; 11278 11279 // tap Event: 11280 $.event.special.itap = { 11281 setup: function() { 11282 11283 var self = this, 11284 $self = $(this), 11285 start, stop; 11286 11287 $self.bind(tapSettings.startEvent, function(event) { 11288 start = getScrollXY(); 11289 11290 $self.one(tapSettings.endEvent, function(event) { 11291 stop = getScrollXY(); 11292 11293 var orgEvent = event || window.event; 11294 event = $.event.fix(orgEvent); 11295 event.type = "itap"; 11296 11297 if ((start && stop) && (start.x == stop.x && start.y == stop.y))($.event.dispatch || $.event.handle).call(self, event); 11298 11299 start = stop = undefined; 11300 }); 11301 }); 11302 }, 11303 11304 teardown: function() { 11305 $(this).unbind(tapSettings.startEvent); 11306 } 11307 }; 11308 }()); 11309 11310 11311 //Fullscreen API 11312 (function() { 11313 fullScreenApi = { 11314 supportsFullScreen: false, 11315 isFullScreen: function() { 11316 return false;
11317 }, 11318 requestFullScreen: function() {}, 11319 cancelFullScreen: function() {}, 11320 fullScreenEventName: '', 11321 prefix: '' 11322 }, 11323 browserPrefixes = 'webkit moz o ms khtml'.split(' '); 11324 11325 // check for native support 11326 if (typeof document.cancelFullScreen != 'undefined') { 11327 fullScreenApi.supportsFullScreen = true; 11328 } else { 11329 // check for fullscreen support by vendor prefix 11330 for (var i = 0, il = browserPrefixes.length; i < il; i++) { 11331 fullScreenApi.prefix = browserPrefixes[i]; 11332 11333 if (typeof document[fullScreenApi.prefix + 'CancelFullScreen'] != 'undefined') { 11334 fullScreenApi.supportsFullScreen = true; 11335 11336 break; 11337 } 11338 } 11339 } 11340 11341 // update methods to do something useful 11342 if (fullScreenApi.supportsFullScreen) { 11343 fullScreenApi.fullScreenEventName = fullScreenApi.prefix + 'fullscreenchange'; 11344 11345 fullScreenApi.isFullScreen = function() { 11346 switch (this.prefix) { 11347 case '': 11348 return document.fullScreen; 11349 case 'webkit': 11350 return document.webkitIsFullScreen; 11351 default: 11352 return document[this.prefix + 'FullScreen']; 11353 } 11354 } 11355 fullScreenApi.requestFullScreen = function(el) { 11356 return (this.prefix === '') ? el.requestFullScreen() : el[this.prefix + 'RequestFullScreen'](); 11357 } 11358 fullScreenApi.cancelFullScreen = function(el) { 11359 return (this.prefix === '') ? document.cancelFullScreen() : document[this.prefix + 'CancelFullScreen'](); 11360 } 11361 } 11362 }()); 11363 11364 // Browser detect 11365 (function() { 11366 function uaMatch(ua) { 11367 ua = ua.toLowerCase(); 11368 11369 var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || 11370 /(webkit)[ \/]([\w.]+)/.exec(ua) || 11371 /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || 11372 /(msie) ([\w.]+)/.exec(ua) || 11373 ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || []; 11374 11375 return { 11376 browser: match[1] || "", 11377 version: match[2] || "0" 11378 }; 11379 } 11380 11381 var matched = uaMatch(navigator.userAgent); 11382 browser = {}; 11383 11384 if (matched.browser) { 11385 browser[matched.browser] = true; 11386 browser.version = matched.version; 11387 } 11388 11389 // Chrome is Webkit, but Webkit is also Safari. 11390 if (browser.chrome) { 11391 browser.webkit = true; 11392 } else if (browser.webkit) { 11393 browser.safari = true; 11394 } 11395 }()); 11396 11397 // Feature detects 11398 (function() { 11399 var prefixes = ['', 'webkit', 'moz', 'ms', 'o']; 11400 var el = document.createElement('div'); 11401 11402 function testProp(prop) { 11403 for (var p = 0, pl = prefixes.length; p < pl; p++) { 11404 var prefixedProp = prefixes[p] ? prefixes[p] + prop.charAt(0).toUpperCase() + prop.slice(1) : prop; 11405 if (el.style[prefixedProp] !== undefined) { 11406 return prefixedProp; 11407 } 11408 } 11409 } 11410 11411 // Global support indicators 11412 transform = testProp('transform') || ''; 11413 gpuAcceleration = testProp('perspective') ? 'translateZ(0) ' : ''; 11414 }()); 11415 11416 11417 /* 11418 PluginDetect v0.7.9 11419 www.pinlady.net/PluginDetect/license/ 11420 [ getVersion onWindowLoaded BetterIE ] 11421 [ Flash QuickTime Shockwave ] 11422 */ 11423 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;
11423d++){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);
11423d.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)}
11423c.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;
11423if(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(); 11424 11425 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)}; 11426 11427 11428 /* 11429 jQuery hashchange event v1.3 11430 https://github.com/cowboy/jquery-hashchange 11431 Copyright (c) 2010 "Cowboy" Ben Alman 11432 Dual licensed under the MIT and GPL licenses. 11433 */ 11434 (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= 11435 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|| 11436 "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;
11436a!==d&&(b.title=k.title,b.open(),e&&b.write('<script>document.domain="'+e+'"\x3c/script>'),b.close(),c.location.hash=a)}}();return h}()})(); 11437 11438 if (!Array.prototype.filter) { 11439 Array.prototype.filter = function(fun /*, thisp */ ) { 11440 "use strict"; 11441 11442 if (this == null) 11443 throw new TypeError(); 11444 11445 var t = Object(this); 11446 var len = t.length >>> 0; 11447 if (typeof fun != "function") 11448 throw new TypeError(); 11449 11450 var res = []; 11451 var thisp = arguments[1]; 11452 for (var i = 0; i < len; i++) { 11453 if (i in t) { 11454 var val = t[i]; // in case fun mutates this 11455 if (fun.call(thisp, val, i, t)) 11456 res.push(val); 11457 } 11458 } 11459 11460 return res; 11461 }; 11462 } 11463 11464 if (!Array.prototype.indexOf) { 11465 Array.prototype.indexOf = function(searchElement, fromIndex) { 11466 var k; 11467 11468 if (this == null) { 11469 throw new TypeError('"this" is null or not defined'); 11470 } 11471 11472 var O = Object(this); 11473 11474 var len = O.length >>> 0; 11475 11476 if (len === 0) { 11477 return -1; 11478 } 11479 11480 var n = +fromIndex || 0; 11481 11482 if (abs(n) === Infinity) { 11483 n = 0; 11484 } 11485 11486 if (n >= len) { 11487 return -1; 11488 } 11489 11490 k = max(n >= 0 ? n : len - abs(n), 0); 11491 11492 while (k < len) { 11493 var kValue; 11494 if (k in O && O[k] === searchElement) { 11495 return k; 11496 } 11497 k++; 11498 } 11499 return -1; 11500 }; 11501 } 11502 11503 if (!Array.prototype.lastIndexOf) { 11504 Array.prototype.lastIndexOf = function(searchElement /*, fromIndex*/ ) { 11505 "use strict"; 11506 11507 if (this == null) 11508 throw new TypeError(); 11509 11510 var t = Object(this); 11511 var len = t.length >>> 0; 11512 if (len === 0) 11513 return -1; 11514 11515 var n = len; 11516 if (arguments.length > 1) { 11517 n = Number(arguments[1]); 11518 if (n != n) 11519 n = 0; 11520 else if (n != 0 && n != (1 / 0) && n != -(1 / 0)) 11521 n = (n > 0 || -1) * floor(abs(n)); 11522 } 11523 11524 var k = n >= 0 ? min(n, len - 1) : len - abs(n); 11525 11526 for (; k >= 0; k--) { 11527 if (k in t && t[k] === searchElement) 11528 return k; 11529 } 11530 return -1; 11531 }; 11532 } 11533})(jQuery, this); 11534 11535/** 11536 * Owl carousel
vendor: 12,108 bytes, lines 11537-12043
11537 * @version 2.0.0-beta.3 11538 * @author Bartosz Wojciechowski 11539 * @license The MIT License (MIT) 11540 * @todo Lazy Load Icon 11541 * @todo prevent animationend bubling 11542 * @todo itemsScaleUp 11543 * @todo Test Zepto 11544 * @todo stagePadding calculate wrong active classes 11545 */ 11546;(function($, window, document, undefined) { 11547 11548 /** 11549 * Creates a carousel. 11550 * @class The Owl Carousel. 11551 * @public 11552 * @param {HTMLElement|jQuery} element - The element to create the carousel for. 11553 * @param {Object} [options] - The options 11554 */ 11555 function Owl(element, options) { 11556 11557 /** 11558 * Current settings for the carousel. 11559 * @public 11560 */ 11561 this.settings = null; 11562 11563 /** 11564 * Current options set by the caller including defaults. 11565 * @public 11566 */ 11567 this.options = $.extend({}, Owl.Defaults, options); 11568 11569 /** 11570 * Plugin element. 11571 * @public 11572 */ 11573 this.$element = $(element); 11574 11575 /** 11576 * Proxied event handlers. 11577 * @protected 11578 */ 11579 this._handlers = {}; 11580 11581 /** 11582 * References to the running plugins of this carousel. 11583 * @protected 11584 */ 11585 this._plugins = {}; 11586 11587 /** 11588 * Currently suppressed events to prevent them from beeing retriggered. 11589 * @protected 11590 */ 11591 this._supress = {}; 11592 11593 /** 11594 * Absolute current position. 11595 * @protected 11596 */ 11597 this._current = null; 11598 11599 /** 11600 * Animation speed in milliseconds. 11601 * @protected 11602 */ 11603 this._speed = null; 11604 11605 /** 11606 * Coordinates of all items in pixel. 11607 * @todo The name of this member is missleading. 11608 * @protected 11609 */ 11610 this._coordinates = []; 11611 11612 /** 11613 * Current breakpoint. 11614 * @todo Real media queries would be nice. 11615 * @protected 11616 */ 11617 this._breakpoint = null; 11618 11619 /** 11620 * Current width of the plugin element. 11621 */ 11622 this._width = null; 11623 11624 /** 11625 * All real items. 11626 * @protected 11627 */ 11628 this._items = []; 11629 11630 /** 11631 * All cloned items. 11632 * @protected 11633 */ 11634 this._clones = []; 11635 11636 /** 11637 * Merge values of all items. 11638 * @todo Maybe this could be part of a plugin. 11639 * @protected 11640 */ 11641 this._mergers = []; 11642 11643 /** 11644 * Widths of all items. 11645 */ 11646 this._widths = []; 11647 11648 /** 11649 * Invalidated parts within the update process. 11650 * @protected 11651 */ 11652 this._invalidated = {}; 11653 11654 /** 11655 * Ordered list of workers for the update process. 11656 * @protected 11657 */ 11658 this._pipe = []; 11659 11660 /** 11661 * Current state information for the drag operation. 11662 * @todo #261 11663 * @protected 11664 */ 11665 this._drag = { 11666 time: null, 11667 target: null, 11668 pointer: null, 11669 stage: { 11670 start: null, 11671 current: null 11672 }, 11673 direction: null 11674 }; 11675 11676 /** 11677 * Current state information and their tags. 11678 * @type {Object} 11679 * @protected 11680 */ 11681 this._states = { 11682 current: {}, 11683 tags: { 11684 'initializing': [ 'busy' ], 11685 'animating': [ 'busy' ], 11686 'dragging': [ 'interacting' ] 11687 } 11688 }; 11689 11690 $.each([ 'onResize', 'onThrottledResize' ], $.proxy(function(i, handler) { 11691 this._handlers[handler] = $.proxy(this[handler], this); 11692 }, this)); 11693 11694 $.each(Owl.Plugins, $.proxy(function(key, plugin) { 11695 this._plugins[key.charAt(0).toLowerCase() + key.slice(1)] 11696 = new plugin(this); 11697 }, this)); 11698 11699 $.each(Owl.Workers, $.proxy(function(priority, worker) { 11700 this._pipe.push({ 11701 'filter': worker.filter, 11702 'run': $.proxy(worker.run, this) 11703 }); 11704 }, this)); 11705 11706 this.setup(); 11707 this.initialize(); 11708 } 11709 11710 /** 11711 * Default options for the carousel. 11712 * @public 11713 */ 11714 Owl.Defaults = { 11715 items: 3, 11716 loop: false, 11717 center: false, 11718 rewind: false, 11719 11720 mouseDrag: true, 11721 touchDrag: true, 11722 pullDrag: true, 11723 freeDrag: false, 11724 11725 margin: 0, 11726 stagePadding: 0, 11727 11728 merge: false, 11729 mergeFit: true, 11730 autoWidth: false, 11731 11732 startPosition: 0, 11733 rtl: false, 11734 11735 smartSpeed: 250, 11736 fluidSpeed: false, 11737 dragEndSpeed: false, 11738 11739 responsive: {}, 11740 responsiveRefreshRate: 200, 11741 responsiveBaseElement: window, 11742 11743 fallbackEasing: 'swing', 11744 11745 info: false, 11746 11747 nestedItemSelector: false, 11748 itemElement: 'div', 11749 stageElement: 'div', 11750 11751 refreshClass: 'owl-refresh', 11752 loadedClass: 'owl-loaded', 11753 loadingClass: 'owl-loading', 11754 rtlClass: 'owl-rtl', 11755 responsiveClass: 'owl-responsive', 11756 dragClass: 'owl-drag', 11757 itemClass: 'owl-item', 11758 stageClass: 'owl-stage', 11759 stageOuterClass: 'owl-stage-outer', 11760 grabClass: 'owl-grab' 11761 }; 11762 11763 /** 11764 * Enumeration for width. 11765 * @public 11766 * @readonly 11767 * @enum {String} 11768 */ 11769 Owl.Width = { 11770 Default: 'default', 11771 Inner: 'inner', 11772 Outer: 'outer' 11773 }; 11774 11775 /** 11776 * Enumeration for types. 11777 * @public 11778 * @readonly 11779 * @enum {String} 11780 */ 11781 Owl.Type = { 11782 Event: 'event', 11783 State: 'state' 11784 }; 11785 11786 /** 11787 * Contains all registered plugins. 11788 * @public 11789 */ 11790 Owl.Plugins = {}; 11791 11792 /** 11793 * List of workers involved in the update process. 11794 */ 11795 Owl.Workers = [ { 11796 filter: [ 'width', 'settings' ], 11797 run: function() { 11798 this._width = (this.$element.closest('.px-gutter').length) ? 12 * Math.ceil(this.$element.width() / 12) : this.$element.width(); 11799 //this._width = (UNCODE.isMobile) ? this.$element.width() : 12 * Math.ceil(this.$element.width() / 12); 11800 } 11801 }, { 11802 filter: [ 'width', 'items', 'settings' ], 11803 run: function(cache) { 11804 cache.current = this._items && this._items[this.relative(this._current)]; 11805 } 11806 }, { 11807 filter: [ 'items', 'settings' ], 11808 run: function() { 11809 this.$stage.children('.cloned').remove(); 11810 } 11811 }, { 11812 filter: [ 'width', 'items', 'settings' ], 11813 run: function(cache) { 11814 var margin = this.settings.margin || '', 11815 grid = !this.settings.autoWidth, 11816 rtl = this.settings.rtl, 11817 css = { 11818 'width': 'auto', 11819 'margin-left': rtl ? margin : '', 11820 'margin-right': rtl ? '' : margin 11821 }; 11822 11823 !grid && this.$stage.children().css(css); 11824 11825 cache.css = css; 11826 } 11827 }, { 11828 filter: [ 'width', 'items', 'settings' ], 11829 run: function(cache) { 11830 //UNCODE edit to fix Chrome stage padding issue 11831 var width = Math.round((this.width() / this.settings.items).toFixed(3) - this.settings.margin), 11832 merge = null, 11833 iterator = this._items.length, 11834 grid = !this.settings.autoWidth, 11835 widths = []; 11836 11837 cache.items = { 11838 merge: false, 11839 width: width 11840 }; 11841 11842 while (iterator--) { 11843 merge = this._mergers[iterator]; 11844 merge = this.settings.mergeFit && Math.min(merge, this.settings.items) || merge; 11845 11846 cache.items.merge = merge > 1 || cache.items.merge; 11847 11848 widths[iterator] = !grid ? this._items[iterator].width() : width * merge; 11849 } 11850 11851 this._widths = widths; 11852 } 11853 }, { 11854 filter: [ 'items', 'settings' ], 11855 run: function() { 11856 var clones = [], 11857 items = this._items, 11858 settings = this.settings, 11859 view = Math.max(settings.items * 2, 4), 11860 size = Math.ceil(items.length / 2) * 2, 11861 repeat = settings.loop && items.length ? settings.rewind ? view : Math.max(view, size) : 0, 11862 append = '', 11863 prepend = ''; 11864 11865 repeat /= 2; 11866 11867 while (repeat--) { 11868 clones.push(this.normalize(clones.length / 2, true)); 11869 append = append + items[clones[clones.length - 1]][0].outerHTML; 11870 clones.push(this.normalize(items.length - 1 - (clones.length - 1) / 2, true)); 11871 prepend = items[clones[clones.length - 1]][0].outerHTML + prepend; 11872 } 11873 11874 this._clones = clones; 11875 11876 // var appendVideo = $(append).find('.uncode-video-container'); 11877 // if (appendVideo.length) { 11878 // appendVideo.attr('data-id', Math.round(Math.random() * 100000)); 11879 // } 11880 // var prependVideo = $(prepend).find('.uncode-video-container'); 11881 // if (prependVideo.length) { 11882 // prependVideo.attr('data-id', Math.round(Math.random() * 100000)); 11883 // } 11884 $(append).addClass('cloned').appendTo(this.$stage); 11885 $(prepend).addClass('cloned').prependTo(this.$stage); 11886 } 11887 }, { 11888 filter: [ 'width', 'items', 'settings' ], 11889 run: function() { 11890 var rtl = this.settings.rtl ? 1 : -1, 11891 size = this._clones.length + this._items.length, 11892 iterator = -1, 11893 previous = 0, 11894 current = 0, 11895 coordinates = []; 11896 11897 while (++iterator < size) { 11898 previous = coordinates[iterator - 1] || 0; 11899 current = this._widths[this.relative(iterator)] + this.settings.margin; 11900 coordinates.push(previous + current * rtl); 11901 } 11902 11903 this._coordinates = coordinates; 11904 } 11905 }, { 11906 filter: [ 'width', 'items', 'settings' ], 11907 run: function() { 11908 var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200, 11909 padding = stagePadding, 11910 coordinates = this._coordinates, 11911 css = { 11912 'width': Math.ceil(Math.abs(coordinates[coordinates.length - 1])) + padding * 2, 11913 'padding-left': padding || '', 11914 'padding-right': padding || '' 11915 }; 11916 11917 this.$stage.css(css); 11918 } 11919 }, { 11920 filter: [ 'width', 'items', 'settings' ], 11921 run: function(cache) { 11922 var iterator = this._coordinates.length, 11923 grid = !this.settings.autoWidth, 11924 items = this.$stage.children(); 11925 11926 if (grid && cache.items.merge) { 11927 while (iterator--) { 11928 cache.css.width = this._widths[this.relative(iterator)]; 11929 items.eq(iterator).css(cache.css); 11930 } 11931 } else if (grid) { 11932 cache.css.width = cache.items.width; 11933 items.css(cache.css); 11934 } 11935 } 11936 }, { 11937 filter: [ 'items' ], 11938 run: function() { 11939 this._coordinates.length < 1 && this.$stage.removeAttr('style'); 11940 } 11941 }, { 11942 filter: [ 'width', 'items', 'settings' ], 11943 run: function(cache) { 11944 cache.current = cache.current ? this.$stage.children().index(cache.current) : 0; 11945 cache.current = Math.max(this.minimum(), Math.min(this.maximum(), cache.current)); 11946 this.reset(cache.current); 11947 } 11948 }, { 11949 filter: [ 'position' ], 11950 run: function() { 11951 this.animate(this.coordinates(this._current)); 11952 } 11953 }, { 11954 filter: [ 'width', 'position', 'items', 'settings' ], 11955 run: function() { 11956 var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200, 11957 rtl = this.settings.rtl ? 1 : -1, 11958 padding = this.settings.stagePadding * 2, 11959 begin = this.coordinates(this.current()) + padding, 11960 end = begin + this.width() * rtl, 11961 inner, outer, matches = [], i, n; 11962 11963 for (i = 0, n = this._coordinates.length; i < n; i++) { 11964 inner = this._coordinates[i - 1] || 0; 11965 outer = Math.abs(this._coordinates[i]) + padding * rtl; 11966 11967 if ((this.op(inner, '<=', begin) && (this.op(inner, '>', end))) 11968 || (this.op(outer, '<', begin) && this.op(outer, '>', end))) { 11969 matches.push(i); 11970 } 11971 } 11972 11973 this.$stage.children('.active').removeClass('active'); 11974 this.$stage.children(':eq(' + matches.join('), :eq(') + ')').addClass('active'); 11975 11976 if (this.settings.center) { 11977 this.$stage.children('.center').removeClass('center'); 11978 this.$stage.children().eq(this.current()).addClass('center'); 11979 } 11980 } 11981 } ]; 11982 11983 /** 11984 * Initializes the carousel. 11985 * @protected 11986 */ 11987 Owl.prototype.initialize = function() { 11988 this.enter('initializing'); 11989 this.trigger('initialize'); 11990 11991 this.$element.toggleClass(this.settings.rtlClass, this.settings.rtl); 11992 11993 if (this.settings.autoWidth && !this.is('pre-loading')) { 11994 var imgs, nestedSelector, width; 11995 imgs = this.$element.find('img'); 11996 nestedSelector = this.settings.nestedItemSelector ? '.' + this.settings.nestedItemSelector : undefined; 11997 width = this.$element.children(nestedSelector).width(); 11998 11999 if (imgs.length && width <= 0) { 12000 this.preloadAutoWidthImages(imgs); 12001 } 12002 } 12003 12004 this.$element.addClass(this.options.loadingClass); 12005 12006 // create stage 12007 this.$stage = $('<' + this.settings.stageElement + ' class="' + this.settings.stageClass + '"/>') 12008 .wrap('<div class="' + this.settings.stageOuterClass + '"/>'); 12009 12010 // append stage 12011 this.$element.append(this.$stage.parent()); 12012 12013 // append content 12014 this.replace(this.$element.children().not(this.$stage.parent())); 12015 12016 // check visibility 12017 if (this.$element.is(':visible')) { 12018 // update view 12019 this.refresh(); 12020 } else { 12021 // invalidate width 12022 this.invalidate('width'); 12023 } 12024 12025 this.$element 12026 .removeClass(this.options.loadingClass) 12027 .addClass(this.options.loadedClass); 12028 12029 // register event handlers 12030 this.registerEventHandlers(); 12031 12032 this.leave('initializing'); 12033 this.trigger('initialized'); 12034 }; 12035 12036 /** 12037 * Setups the current settings. 12038 * @todo Remove responsive classes. Why should adaptive designs be brought into IE8? 12039 * @todo Support for media queries by using `matchMedia` would be nice. 12040 * @public 12041 */ 12042 Owl.prototype.setup = function() { 12043 var viewport = this.viewport(),
12044 overwrites = this.options.responsive, 12045 match = -1, 12046 settings = null; 12047 12048 if (!overwrites) { 12049 settings = $.extend({}, this.options); 12050 } else { 12051 $.each(overwrites, function(breakpoint) { 12052 if (breakpoint <= viewport && breakpoint > match) { 12053 match = Number(breakpoint); 12054 } 12055 }); 12056 12057 settings = $.extend({}, this.options, overwrites[match]); 12058 delete settings.responsive; 12059 12060 // responsive class 12061 if (settings.responsiveClass) { 12062 this.$element.attr('class', 12063 this.$element.attr('class').replace(new RegExp('(' + this.options.responsiveClass + '-)\\S+\\s', 'g'), '$1' + match) 12064 ); 12065 } 12066 } 12067 12068 if (this.settings === null || this._breakpoint !== match) { 12069 this.trigger('change', { property: { name: 'settings', value: settings } }); 12070 this._breakpoint = match; 12071 this.settings = settings; 12072 this.invalidate('settings'); 12073 this.trigger('changed', { property: { name: 'settings', value: this.settings } }); 12074 } 12075 }; 12076 12077 /** 12078 * Updates option logic if necessery. 12079 * @protected 12080 */ 12081 Owl.prototype.optionsLogic = function() { 12082 if (this.settings.autoWidth) { 12083 this.settings.stagePadding = false; 12084 this.settings.merge = false; 12085 } 12086 }; 12087 12088 /** 12089 * Prepares an item before add. 12090 * @todo Rename event parameter `content` to `item`. 12091 * @protected 12092 * @returns {jQuery|HTMLElement} - The item container. 12093 */ 12094 Owl.prototype.prepare = function(item, index) { 12095 var event = this.trigger('prepare', { content: item }); 12096 if (!event.data) { 12097 event.data = $('<' + this.settings.itemElement + '/>') 12098 .addClass(this.options.itemClass).attr('data-index', index + 1).append(item) 12099 } 12100 12101 this.trigger('prepared', { content: event.data }); 12102 12103 return event.data; 12104 }; 12105 12106 /** 12107 * Updates the view. 12108 * @public 12109 */ 12110 Owl.prototype.update = function() { 12111 var i = 0, 12112 n = this._pipe.length, 12113 filter = $.proxy(function(p) { return this[p] }, this._invalidated), 12114 cache = {}; 12115 12116 while (i < n) { 12117 if (this._invalidated.all || $.grep(this._pipe[i].filter, filter).length > 0) { 12118 this._pipe[i].run(cache); 12119 } 12120 i++; 12121 } 12122 12123 this._invalidated = {}; 12124 12125 !this.is('valid') && this.enter('valid'); 12126 }; 12127 12128 /** 12129 * Gets the width of the view. 12130 * @public 12131 * @param {Owl.Width} [dimension=Owl.Width.Default] - The dimension to return. 12132 * @returns {Number} - The width of the view in pixel. 12133 */ 12134 Owl.prototype.width = function(dimension) { 12135 dimension = dimension || Owl.Width.Default; 12136 var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200; 12137 switch (dimension) { 12138 case Owl.Width.Inner: 12139 case Owl.Width.Outer: 12140 return this._width; 12141 default: 12142 return this._width - stagePadding * 2 + this.settings.margin; 12143 } 12144 }; 12145 12146 /** 12147 * Refreshes the carousel primarily for adaptive purposes. 12148 * @public 12149 */ 12150 Owl.prototype.refresh = function() { 12151 this.enter('refreshing'); 12152 this.trigger('refresh'); 12153 12154 this.setup(); 12155 12156 this.optionsLogic(); 12157 12158 this.$element.addClass(this.options.refreshClass); 12159 12160 this.update(); 12161 12162 this.$element.removeClass(this.options.refreshClass); 12163 12164 this.leave('refreshing'); 12165 this.trigger('refreshed'); 12166 }; 12167 12168 /** 12169 * Checks window `resize` event. 12170 * @protected 12171 */ 12172 Owl.prototype.onThrottledResize = function() { 12173 window.clearTimeout(this.resizeTimer); 12174 this.resizeTimer = window.setTimeout(this._handlers.onResize, this.settings.responsiveRefreshRate); 12175 }; 12176 12177 /** 12178 * Checks window `resize` event. 12179 * @protected 12180 */ 12181 Owl.prototype.onResize = function() { 12182 if (!this._items.length) { 12183 return false; 12184 } 12185 12186 if (this._width === this.$element.width()) { 12187 return false; 12188 } 12189 12190 if (!this.$element.is(':visible')) { 12191 return false; 12192 } 12193 12194 this.enter('resizing'); 12195 12196 if (this.trigger('resize').isDefaultPrevented()) { 12197 this.leave('resizing'); 12198 return false; 12199 } 12200 12201 this.invalidate('width'); 12202 12203 this.refresh(); 12204 12205 this.leave('resizing'); 12206 this.trigger('resized'); 12207 }; 12208 12209 /** 12210 * Registers event handlers. 12211 * @todo Check `msPointerEnabled` 12212 * @todo #261 12213 * @protected 12214 */ 12215 Owl.prototype.registerEventHandlers = function() { 12216 if ($.support.transition) { 12217 this.$stage.on($.support.transition.end + '.owl.core', $.proxy(this.onTransitionEnd, this)); 12218 } 12219 12220 if (this.settings.responsive !== false) { 12221 this.on(window, 'resize', this._handlers.onThrottledResize); 12222 } 12223 12224 if (this.settings.mouseDrag) { 12225 this.$element.addClass(this.options.dragClass); 12226 this.$stage.on('mousedown.owl.core', $.proxy(this.onDragStart, this)); 12227 this.$stage.on('dragstart.owl.core selectstart.owl.core', function() { return false }); 12228 } 12229 12230 if (this.settings.touchDrag){ 12231 this.$stage.on('touchstart.owl.core', $.proxy(this.onDragStart, this)); 12232 this.$stage.on('touchcancel.owl.core', $.proxy(this.onDragEnd, this)); 12233 } 12234 }; 12235 12236 /** 12237 * Handles `touchstart` and `mousedown` events. 12238 * @todo Horizontal swipe threshold as option 12239 * @todo #261 12240 * @protected 12241 * @param {Event} event - The event arguments. 12242 */ 12243 Owl.prototype.onDragStart = function(event) { 12244 var stage = null; 12245 12246 if (event.which === 3) { 12247 return; 12248 } 12249
vendor: 9,106 bytes, lines 12250-12565
12250 if ($.support.transform) { 12251 stage = this.$stage.css('transform').replace(/.*\(|\)| /g, '').split(','); 12252 stage = { 12253 x: stage[stage.length === 16 ? 12 : 4], 12254 y: stage[stage.length === 16 ? 13 : 5] 12255 }; 12256 } else { 12257 stage = this.$stage.position(); 12258 stage = { 12259 x: this.settings.rtl ? 12260 stage.left + this.$stage.width() - this.width() + this.settings.margin : 12261 stage.left, 12262 y: stage.top 12263 }; 12264 } 12265 12266 if (this.is('animating')) { 12267 $.support.transform ? this.animate(stage.x) : this.$stage.stop() 12268 this.invalidate('position'); 12269 } 12270 12271 this.$element.toggleClass(this.options.grabClass, event.type === 'mousedown'); 12272 12273 this.speed(0); 12274 12275 this._drag.time = new Date().getTime(); 12276 this._drag.target = $(event.target); 12277 this._drag.stage.start = stage; 12278 this._drag.stage.current = stage; 12279 this._drag.pointer = this.pointer(event); 12280 12281 $(document).on('mouseup.owl.core touchend.owl.core', $.proxy(this.onDragEnd, this)); 12282 12283 $(document).one('mousemove.owl.core touchmove.owl.core', $.proxy(function(event) { 12284 var delta = this.difference(this._drag.pointer, this.pointer(event)); 12285 12286 $(document).on('mousemove.owl.core touchmove.owl.core', $.proxy(this.onDragMove, this)); 12287 12288 if (Math.abs(delta.x) < Math.abs(delta.y) && this.is('valid')) { 12289 return; 12290 } 12291 12292 event.preventDefault(); 12293 12294 this.enter('dragging'); 12295 this.trigger('drag'); 12296 }, this)); 12297 }; 12298 12299 /** 12300 * Handles the `touchmove` and `mousemove` events. 12301 * @todo #261 12302 * @protected 12303 * @param {Event} event - The event arguments. 12304 */ 12305 Owl.prototype.onDragMove = function(event) { 12306 var minimum = null, 12307 maximum = null, 12308 pull = null, 12309 delta = this.difference(this._drag.pointer, this.pointer(event)), 12310 stage = this.difference(this._drag.stage.start, delta); 12311 12312 if (!this.is('dragging')) { 12313 return; 12314 } 12315 12316 event.preventDefault(); 12317 12318 if (this.settings.loop) { 12319 minimum = this.coordinates(this.minimum()); 12320 maximum = this.coordinates(this.maximum() + 1) - minimum; 12321 stage.x = (((stage.x - minimum) % maximum + maximum) % maximum) + minimum; 12322 } else { 12323 minimum = this.settings.rtl ? this.coordinates(this.maximum()) : this.coordinates(this.minimum()); 12324 maximum = this.settings.rtl ? this.coordinates(this.minimum()) : this.coordinates(this.maximum()); 12325 pull = this.settings.pullDrag ? -1 * delta.x / 5 : 0; 12326 stage.x = Math.max(Math.min(stage.x, minimum + pull), maximum + pull); 12327 } 12328 12329 this._drag.stage.current = stage; 12330 12331 this.animate(stage.x); 12332 }; 12333 12334 /** 12335 * Handles the `touchend` and `mouseup` events. 12336 * @todo #261 12337 * @todo Threshold for click event 12338 * @protected 12339 * @param {Event} event - The event arguments. 12340 */ 12341 Owl.prototype.onDragEnd = function(event) { 12342 var delta = this.difference(this._drag.pointer, this.pointer(event)), 12343 stage = this._drag.stage.current, 12344 direction = delta.x > 0 ^ this.settings.rtl ? 'left' : 'right'; 12345 12346 $(document).off('.owl.core'); 12347 12348 this.$element.removeClass(this.options.grabClass); 12349 12350 if (delta.x !== 0 && this.is('dragging') || !this.is('valid')) { 12351 this.speed(this.settings.dragEndSpeed || this.settings.smartSpeed); 12352 this.current(this.closest(stage.x, delta.x !== 0 ? direction : this._drag.direction)); 12353 this.invalidate('position'); 12354 this.update(); 12355 12356 this._drag.direction = direction; 12357 12358 if (Math.abs(delta.x) > 3 || new Date().getTime() - this._drag.time > 300) { 12359 this._drag.target.one('click.owl.core', function() { return false; }); 12360 } 12361 } 12362 12363 if (!this.is('dragging')) { 12364 return; 12365 } 12366 12367 this.leave('dragging'); 12368 this.trigger('dragged'); 12369 }; 12370 12371 /** 12372 * Gets absolute position of the closest item for a coordinate. 12373 * @todo Setting `freeDrag` makes `closest` not reusable. See #165. 12374 * @protected 12375 * @param {Number} coordinate - The coordinate in pixel. 12376 * @param {String} direction - The direction to check for the closest item. Ether `left` or `right`. 12377 * @return {Number} - The absolute position of the closest item. 12378 */ 12379 Owl.prototype.closest = function(coordinate, direction) { 12380 var position = -1, 12381 pull = 30, 12382 width = this.width(), 12383 coordinates = this.coordinates(); 12384 12385 if (!this.settings.freeDrag) { 12386 // check closest item 12387 $.each(coordinates, $.proxy(function(index, value) { 12388 if (coordinate > value - pull && coordinate < value + pull) { 12389 position = index; 12390 } else if (this.op(coordinate, '<', value) 12391 && this.op(coordinate, '>', coordinates[index + 1] || value - width)) { 12392 position = direction === 'left' ? index + 1 : index; 12393 } 12394 return position === -1; 12395 }, this)); 12396 } 12397 12398 if (!this.settings.loop) { 12399 // non loop boundries 12400 if (this.op(coordinate, '>', coordinates[this.minimum()])) { 12401 position = coordinate = this.minimum(); 12402 } else if (this.op(coordinate, '<', coordinates[this.maximum()])) { 12403 position = coordinate = this.maximum(); 12404 } 12405 } 12406 12407 return position; 12408 }; 12409 12410 /** 12411 * Animates the stage. 12412 * @todo #270 12413 * @public 12414 * @param {Number} coordinate - The coordinate in pixels. 12415 */ 12416 Owl.prototype.animate = function(coordinate) { 12417 var animate = this.speed() > 0; 12418 12419 this.is('animating') && this.onTransitionEnd(); 12420 12421 if (animate) { 12422 this.enter('animating'); 12423 this.trigger('translate'); 12424 } 12425 12426 if ($.support.transform3d && $.support.transition) { 12427 this.$stage.css({ 12428 transform: 'translate3d(' + coordinate + 'px,0px,0px)', 12429 transition: (this.speed() / 1000) + 's' 12430 }); 12431 } else if (animate) { 12432 this.$stage.animate({ 12433 left: coordinate + 'px' 12434 }, this.speed(), this.settings.fallbackEasing, $.proxy(this.onTransitionEnd, this)); 12435 } else { 12436 this.$stage.css({ 12437 left: coordinate + 'px' 12438 }); 12439 } 12440 }; 12441 12442 /** 12443 * Checks whether the carousel is in a specific state or not. 12444 * @param {String} state - The state to check. 12445 * @returns {Boolean} - The flag which indicates if the carousel is busy. 12446 */ 12447 Owl.prototype.is = function(state) { 12448 return this._states.current[state] && this._states.current[state] > 0; 12449 }; 12450 12451 /** 12452 * Sets the absolute position of the current item. 12453 * @public 12454 * @param {Number} [position] - The new absolute position or nothing to leave it unchanged. 12455 * @returns {Number} - The absolute position of the current item. 12456 */ 12457 Owl.prototype.current = function(position) { 12458 if (position === undefined) { 12459 return this._current; 12460 } 12461 12462 if (this._items.length === 0) { 12463 return undefined; 12464 } 12465 12466 position = this.normalize(position); 12467 12468 if (this._current !== position) { 12469 var event = this.trigger('change', { property: { name: 'position', value: position } }); 12470 12471 if (event.data !== undefined) { 12472 position = this.normalize(event.data); 12473 } 12474 12475 this._current = position; 12476 12477 this.invalidate('position'); 12478 12479 this.trigger('changed', { property: { name: 'position', value: this._current } }); 12480 } 12481 12482 return this._current; 12483 }; 12484 12485 /** 12486 * Invalidates the given part of the update routine. 12487 * @param {String} [part] - The part to invalidate. 12488 * @returns {Array.<String>} - The invalidated parts. 12489 */ 12490 Owl.prototype.invalidate = function(part) { 12491 if ($.type(part) === 'string') { 12492 this._invalidated[part] = true; 12493 this.is('valid') && this.leave('valid'); 12494 } 12495 return $.map(this._invalidated, function(v, i) { return i }); 12496 }; 12497 12498 /** 12499 * Resets the absolute position of the current item. 12500 * @public 12501 * @param {Number} position - The absolute position of the new item. 12502 */ 12503 Owl.prototype.reset = function(position) { 12504 position = this.normalize(position); 12505 12506 if (position === undefined) { 12507 return; 12508 } 12509 12510 this._speed = 0; 12511 this._current = position; 12512 12513 this.suppress([ 'translate', 'translated' ]); 12514 12515 this.animate(this.coordinates(position)); 12516 12517 this.release([ 'translate', 'translated' ]); 12518 }; 12519 12520 /** 12521 * Normalizes an absolute or a relative position of an item. 12522 * @public 12523 * @param {Number} position - The absolute or relative position to normalize. 12524 * @param {Boolean} [relative=false] - Whether the given position is relative or not. 12525 * @returns {Number} - The normalized position. 12526 */ 12527 Owl.prototype.normalize = function(position, relative) { 12528 var n = this._items.length, 12529 m = relative ? 0 : this._clones.length; 12530 12531 if (!$.isNumeric(position) || n < 1) { 12532 position = undefined; 12533 } else if (position < 0 || position >= n + m) { 12534 position = ((position - m / 2) % n + n) % n + m / 2; 12535 } 12536 12537 return position; 12538 }; 12539 12540 /** 12541 * Converts an absolute position of an item into a relative one. 12542 * @public 12543 * @param {Number} position - The absolute position to convert. 12544 * @returns {Number} - The converted position. 12545 */ 12546 Owl.prototype.relative = function(position) { 12547 position -= this._clones.length / 2; 12548 return this.normalize(position, true); 12549 }; 12550 12551 /** 12552 * Gets the maximum position for the current item. 12553 * @public 12554 * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position. 12555 * @returns {Number} 12556 */ 12557 Owl.prototype.maximum = function(relative) { 12558 var settings = this.settings, 12559 maximum = this._coordinates.length, 12560 boundary = Math.abs(this._coordinates[maximum - 1]) - this._width, 12561 i = -1, j; 12562 12563 if (settings.loop) { 12564 maximum = this._clones.length / 2 + this._items.length - 1; 12565 } else if (settings.autoWidth || settings.merge) {
12566 // binary search 12567 while (maximum - i > 1) { 12568 Math.abs(this._coordinates[j = maximum + i >> 1]) < boundary 12569 ? i = j : maximum = j; 12570 } 12571 } else if (settings.center) { 12572 maximum = this._items.length - 1; 12573 } else { 12574 maximum = this._items.length - settings.items; 12575 } 12576 12577 if (relative) { 12578 maximum -= this._clones.length / 2; 12579 } 12580 12581 return Math.max(maximum, 0); 12582 }; 12583 12584 /** 12585 * Gets the minimum position for the current item. 12586 * @public 12587 * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position. 12588 * @returns {Number} 12589 */ 12590 Owl.prototype.minimum = function(relative) { 12591 return relative ? 0 : this._clones.length / 2; 12592 }; 12593 12594 /** 12595 * Gets an item at the specified relative position. 12596 * @public 12597 * @param {Number} [position] - The relative position of the item. 12598 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given. 12599 */ 12600 Owl.prototype.items = function(position) { 12601 if (position === undefined) { 12602 return this._items.slice(); 12603 } 12604 12605 position = this.normalize(position, true); 12606 return this._items[position]; 12607 }; 12608 12609 /** 12610 * Gets an item at the specified relative position. 12611 * @public 12612 * @param {Number} [position] - The relative position of the item. 12613 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given. 12614 */ 12615 Owl.prototype.mergers = function(position) { 12616 if (position === undefined) { 12617 return this._mergers.slice(); 12618 } 12619 12620 position = this.normalize(position, true); 12621 return this._mergers[position]; 12622 }; 12623 12624 /** 12625 * Gets the absolute positions of clones for an item. 12626 * @public 12627 * @param {Number} [position] - The relative position of the item. 12628 * @returns {Array.<Number>} - The absolute positions of clones for the item or all if no position was given. 12629 */ 12630 Owl.prototype.clones = function(position) { 12631 var odd = this._clones.length / 2, 12632 even = odd + this._items.length, 12633 map = function(index) { return index % 2 === 0 ? even + index / 2 : odd - (index + 1) / 2 }; 12634 12635 if (position === undefined) { 12636 return $.map(this._clones, function(v, i) { return map(i) }); 12637 } 12638 12639 return $.map(this._clones, function(v, i) { return v === position ? map(i) : null }); 12640 }; 12641 12642 /** 12643 * Sets the current animation speed. 12644 * @public 12645 * @param {Number} [speed] - The animation speed in milliseconds or nothing to leave it unchanged. 12646 * @returns {Number} - The current animation speed in milliseconds. 12647 */ 12648 Owl.prototype.speed = function(speed) { 12649 if (speed !== undefined) { 12650 this._speed = speed; 12651 } 12652 12653 return this._speed; 12654 }; 12655 12656 /** 12657 * Gets the coordinate of an item. 12658 * @todo The name of this method is missleanding. 12659 * @public 12660 * @param {Number} position - The absolute position of the item within `minimum()` and `maximum()`. 12661 * @returns {Number|Array.<Number>} - The coordinate of the item in pixel or all coordinates. 12662 */ 12663 Owl.prototype.coordinates = function(position) { 12664 var coordinate = null; 12665 12666 if (position === undefined) { 12667 return $.map(this._coordinates, $.proxy(function(coordinate, index) { 12668 return this.coordinates(index); 12669 }, this)); 12670 } 12671 12672 if (this.settings.center) { 12673 coordinate = this._coordinates[position]; 12674 coordinate += (this.width() - coordinate + (this._coordinates[position - 1] || 0)) / 2 * (this.settings.rtl ? -1 : 1); 12675 } else { 12676 coordinate = this._coordinates[position - 1] || 0; 12677 } 12678 12679 return coordinate; 12680 }; 12681 12682 /** 12683 * Calculates the speed for a translation. 12684 * @protected 12685 * @param {Number} from - The absolute position of the start item. 12686 * @param {Number} to - The absolute position of the target item. 12687 * @param {Number} [factor=undefined] - The time factor in milliseconds. 12688 * @returns {Number} - The time in milliseconds for the translation. 12689 */ 12690 Owl.prototype.duration = function(from, to, factor) { 12691 return Math.min(Math.max(Math.abs(to - from), 1), 6) * Math.abs((factor || this.settings.smartSpeed)); 12692 }; 12693 12694 /** 12695 * Slides to the specified item. 12696 * @public 12697 * @param {Number} position - The position of the item. 12698 * @param {Number} [speed] - The time in milliseconds for the transition. 12699 */ 12700 Owl.prototype.to = function(position, speed) { 12701 var current = this.current(), 12702 revert = null, 12703 distance = position - this.relative(current), 12704 direction = (distance > 0) - (distance < 0), 12705 items = this._items.length, 12706 minimum = this.minimum(), 12707 maximum = this.maximum(); 12708 12709 if (this.settings.loop) { 12710 if (!this.settings.rewind && Math.abs(distance) > items / 2) { 12711 distance += direction * -1 * items; 12712 } 12713 12714 position = current + distance; 12715 revert = ((position - minimum) % items + items) % items + minimum; 12716 12717 if (revert !== position && revert - distance <= maximum && revert - distance > 0) { 12718 current = revert - distance; 12719 position = revert; 12720 this.reset(current); 12721 } 12722 } else if (this.settings.rewind) { 12723 maximum += 1; 12724 position = (position % maximum + maximum) % maximum; 12725 } else { 12726 position = Math.max(minimum, Math.min(maximum, position)); 12727 } 12728 12729 this.speed(this.duration(current, position, speed)); 12730 this.current(position); 12731 12732 if (this.$element.is(':visible')) { 12733 this.update(); 12734 } 12735 }; 12736 12737 /** 12738 * Slides to the next item. 12739 * @public 12740 * @param {Number}
vendor: 30,399 bytes, lines 12740-13888
12740 [speed] - The time in milliseconds for the transition. 12741 */ 12742 Owl.prototype.next = function(speed) { 12743 speed = speed || false; 12744 this.to(this.relative(this.current()) + 1, speed); 12745 }; 12746 12747 /** 12748 * Slides to the previous item. 12749 * @public 12750 * @param {Number} [speed] - The time in milliseconds for the transition. 12751 */ 12752 Owl.prototype.prev = function(speed) { 12753 speed = speed || false; 12754 this.to(this.relative(this.current()) - 1, speed); 12755 }; 12756 12757 /** 12758 * Handles the end of an animation. 12759 * @protected 12760 * @param {Event} event - The event arguments. 12761 */ 12762 Owl.prototype.onTransitionEnd = function(event) { 12763 12764 // if css2 animation then event object is undefined 12765 if (event !== undefined) { 12766 event.stopPropagation(); 12767 12768 // Catch only owl-stage transitionEnd event 12769 if ((event.target || event.srcElement || event.originalTarget) !== this.$stage.get(0)) { 12770 return false; 12771 } 12772 } 12773 12774 this.leave('animating'); 12775 this.trigger('translated'); 12776 }; 12777 12778 /** 12779 * Gets viewport width. 12780 * @protected 12781 * @return {Number} - The width in pixel. 12782 */ 12783 Owl.prototype.viewport = function() { 12784 var width; 12785 if (this.options.responsiveBaseElement !== window) { 12786 width = $(this.options.responsiveBaseElement).width(); 12787 } else if (window.innerWidth) { 12788 width = window.innerWidth; 12789 } else if (document.documentElement && document.documentElement.clientWidth) { 12790 width = document.documentElement.clientWidth; 12791 } else { 12792 throw 'Can not detect viewport width.'; 12793 } 12794 12795 return width; 12796 }; 12797 12798 /** 12799 * Replaces the current content. 12800 * @public 12801 * @param {HTMLElement|jQuery|String} content - The new content. 12802 */ 12803 Owl.prototype.replace = function(content) { 12804 this.$stage.empty(); 12805 this._items = []; 12806 12807 if (content) { 12808 content = (content instanceof jQuery) ? content : $(content); 12809 } 12810 12811 if (this.settings.nestedItemSelector) { 12812 content = content.find('.' + this.settings.nestedItemSelector); 12813 } 12814 12815 content.filter(function() { 12816 return this.nodeType === 1; 12817 }).each($.proxy(function(index, item) { 12818 item = this.prepare(item, index); 12819 this.$stage.append(item); 12820 this._items.push(item); 12821 this._mergers.push(item.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1); 12822 }, this)); 12823 12824 this.reset($.isNumeric(this.settings.startPosition) ? this.settings.startPosition : 0); 12825 12826 this.invalidate('items'); 12827 }; 12828 12829 /** 12830 * Adds an item. 12831 * @todo Use `item` instead of `content` for the event arguments. 12832 * @public 12833 * @param {HTMLElement|jQuery|String} content - The item content to add. 12834 * @param {Number} [position] - The relative position at which to insert the item otherwise the item will be added to the end. 12835 */ 12836 Owl.prototype.add = function(content, position) { 12837 var current = this.relative(this._current); 12838 12839 position = position === undefined ? this._items.length : this.normalize(position, true); 12840 content = content instanceof jQuery ? content : $(content); 12841 12842 this.trigger('add', { content: content, position: position }); 12843 12844 content = this.prepare(content, this._items[current].index()); 12845 12846 if (this._items.length === 0 || position === this._items.length) { 12847 this._items.length === 0 && this.$stage.append(content); 12848 this._items.length !== 0 && this._items[position - 1].after(content); 12849 this._items.push(content); 12850 this._mergers.push(content.find('[data-merge]').andSelf('[data-merge]').attr('data-merge') * 1 || 1); 12851 } else { 12852 this._items[position].before(content); 12853 this._items.splice(position, 0, content); 12854 this._mergers.splice(position, 0, content.find('[data-merge]').andSelf('[data-merge]').attr('data-merge') * 1 || 1); 12855 } 12856 12857 this._items[current] && this.reset(this._items[current].index()); 12858 12859 this.invalidate('items'); 12860 12861 this.trigger('added', { content: content, position: position }); 12862 }; 12863 12864 /** 12865 * Removes an item by its position. 12866 * @todo Use `item` instead of `content` for the event arguments. 12867 * @public 12868 * @param {Number} position - The relative position of the item to remove. 12869 */ 12870 Owl.prototype.remove = function(position) { 12871 position = this.normalize(position, true); 12872 12873 if (position === undefined) { 12874 return; 12875 } 12876 12877 this.trigger('remove', { content: this._items[position], position: position }); 12878 12879 this._items[position].remove(); 12880 this._items.splice(position, 1); 12881 this._mergers.splice(position, 1); 12882 12883 this.invalidate('items'); 12884 12885 this.trigger('removed', { content: null, position: position }); 12886 }; 12887 12888 /** 12889 * Preloads images with auto width. 12890 * @todo Replace by a more generic approach 12891 * @protected 12892 */ 12893 Owl.prototype.preloadAutoWidthImages = function(images) { 12894 images.each($.proxy(function(i, element) { 12895 this.enter('pre-loading'); 12896 element = $(element); 12897 $(new Image()).one('load', $.proxy(function(e) { 12898 element.attr('src', e.target.src); 12899 element.css('opacity', 1); 12900 this.leave('pre-loading'); 12901 !this.is('pre-loading') && !this.is('initializing') && this.refresh(); 12902 }, this)).attr('src', element.attr('src') || element.attr('data-src') || element.attr('data-src-retina')); 12903 }, this)); 12904 }; 12905 12906 /** 12907 * Destroys the carousel. 12908 * @public 12909 */ 12910 Owl.prototype.destroy = function() { 12911 12912 this.$element.off('.owl.core'); 12913 this.$stage.off('.owl.core'); 12914 $(document).off('.owl.core'); 12915 12916 if (this.settings.responsive !== false) { 12917 window.clearTimeout(this.resizeTimer); 12918 this.off(window, 'resize', this._handlers.onThrottledResize); 12919 } 12920 12921 for (var i in this._plugins) { 12922 this._plugins[i].destroy(); 12923 } 12924 12925 this.$stage.children('.cloned').remove(); 12926 12927 this.$stage.unwrap(); 12928 this.$stage.children().contents().unwrap(); 12929 this.$stage.children().unwrap(); 12930 12931 this.$element 12932 .removeClass(this.options.refreshClass) 12933 .removeClass(this.options.loadingClass) 12934 .removeClass(this.options.loadedClass) 12935 .removeClass(this.options.rtlClass) 12936 .removeClass(this.options.dragClass) 12937 .removeClass(this.options.grabClass) 12938 .attr('class', this.$element.attr('class').replace(new RegExp(this.options.responsiveClass + '-\\S+\\s', 'g'), '')) 12939 .removeData('owl.carousel'); 12940 }; 12941 12942 /** 12943 * Operators to calculate right-to-left and left-to-right. 12944 * @protected 12945 * @param {Number} [a] - The left side operand. 12946 * @param {String} [o] - The operator. 12947 * @param {Number} [b] - The right side operand. 12948 */ 12949 Owl.prototype.op = function(a, o, b) { 12950 var rtl = this.settings.rtl; 12951 switch (o) { 12952 case '<': 12953 return rtl ? a > b : a < b; 12954 case '>': 12955 return rtl ? a < b : a > b; 12956 case '>=': 12957 return rtl ? a <= b : a >= b; 12958 case '<=': 12959 return rtl ? a >= b : a <= b; 12960 default: 12961 break; 12962 } 12963 }; 12964 12965 /** 12966 * Attaches to an internal event. 12967 * @protected 12968 * @param {HTMLElement} element - The event source. 12969 * @param {String} event - The event name. 12970 * @param {Function} listener - The event handler to attach. 12971 * @param {Boolean} capture - Wether the event should be handled at the capturing phase or not. 12972 */ 12973 Owl.prototype.on = function(element, event, listener, capture) { 12974 if (element.addEventListener) { 12975 element.addEventListener(event, listener, capture); 12976 } else if (element.attachEvent) { 12977 element.attachEvent('on' + event, listener); 12978 } 12979 }; 12980 12981 /** 12982 * Detaches from an internal event. 12983 * @protected 12984 * @param {HTMLElement} element - The event source. 12985 * @param {String} event - The event name. 12986 * @param {Function} listener - The attached event handler to detach. 12987 * @param {Boolean} capture - Wether the attached event handler was registered as a capturing listener or not. 12988 */ 12989 Owl.prototype.off = function(element, event, listener, capture) { 12990 if (element.removeEventListener) { 12991 element.removeEventListener(event, listener, capture); 12992 } else if (element.detachEvent) { 12993 element.detachEvent('on' + event, listener); 12994 } 12995 }; 12996 12997 /** 12998 * Triggers a public event. 12999 * @todo Remove `status`, `relatedTarget` should be used instead. 13000 * @protected 13001 * @param {String} name - The event name. 13002 * @param {*} [data=null] - The event data. 13003 * @param {String} [namespace=carousel] - The event namespace. 13004 * @param {String} [state] - The state which is associated with the event. 13005 * @param {Boolean} [enter=false] - Indicates if the call enters the specified state or not. 13006 * @returns {Event} - The event arguments. 13007 */ 13008 Owl.prototype.trigger = function(name, data, namespace, state, enter) { 13009 var status = { 13010 item: { count: this._items.length, index: this.current() } 13011 }, handler = $.camelCase( 13012 $.grep([ 'on', name, namespace ], function(v) { return v }) 13013 .join('-').toLowerCase() 13014 ), event = $.Event( 13015 [ name, 'owl', namespace || 'carousel' ].join('.').toLowerCase(), 13016 $.extend({ relatedTarget: this }, status, data) 13017 ); 13018 13019 if (!this._supress[name]) { 13020 $.each(this._plugins, function(name, plugin) { 13021 if (plugin.onTrigger) { 13022 plugin.onTrigger(event); 13023 } 13024 }); 13025 13026 this.register({ type: Owl.Type.Event, name: name }); 13027 this.$element.trigger(event); 13028 13029 if (this.settings && typeof this.settings[handler] === 'function') { 13030 this.settings[handler].call(this, event); 13031 } 13032 } 13033 13034 return event; 13035 }; 13036 13037 /** 13038 * Enters a state. 13039 * @param name - The state name. 13040 */ 13041 Owl.prototype.enter = function(name) { 13042 $.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) { 13043 if (this._states.current[name] === undefined) { 13044 this._states.current[name] = 0; 13045 } 13046 13047 this._states.current[name]++; 13048 }, this)); 13049 }; 13050 13051 /** 13052 * Leaves a state. 13053 * @param name - The state name. 13054 */ 13055 Owl.prototype.leave = function(name) { 13056 $.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) { 13057 this._states.current[name]--; 13058 }, this)); 13059 }; 13060 13061 /** 13062 * Registers an event or state. 13063 * @public 13064 * @param {Object} object - The event or state to register. 13065 */ 13066 Owl.prototype.register = function(object) { 13067 if (object.type === Owl.Type.Event) { 13068 if (!$.event.special[object.name]) { 13069 $.event.special[object.name] = {}; 13070 } 13071 13072 if (!$.event.special[object.name].owl) { 13073 var _default = $.event.special[object.name]._default; 13074 $.event.special[object.name]._default = function(e) { 13075 if (_default && _default.apply && (!e.namespace || e.namespace.indexOf('owl') === -1)) { 13076 return _default.apply(this, arguments); 13077 } 13078 return e.namespace && e.namespace.indexOf('owl') > -1; 13079 }; 13080 $.event.special[object.name].owl = true; 13081 } 13082 } else if (object.type === Owl.Type.State) { 13083 if (!this._states.tags[object.name]) { 13084 this._states.tags[object.name] = object.tags; 13085 } else { 13086 this._states.tags[object.name] = this._states.tags[object.name].concat(object.tags); 13087 } 13088 13089 this._states.tags[object.name] = $.grep(this._states.tags[object.name], $.proxy(function(tag, i) { 13090 return $.inArray(tag, this._states.tags[object.name]) === i; 13091 }, this)); 13092 } 13093 }; 13094 13095 /** 13096 * Suppresses events. 13097 * @protected 13098 * @param {Array.<String>} events - The events to suppress. 13099 */ 13100 Owl.prototype.suppress = function(events) { 13101 $.each(events, $.proxy(function(index, event) { 13102 this._supress[event] = true; 13103 }, this)); 13104 }; 13105 13106 /** 13107 * Releases suppressed events. 13108 * @protected 13109 * @param {Array.<String>} events - The events to release. 13110 */ 13111 Owl.prototype.release = function(events) { 13112 $.each(events, $.proxy(function(index, event) { 13113 delete this._supress[event]; 13114 }, this)); 13115 }; 13116 13117 /** 13118 * Gets unified pointer coordinates from event. 13119 * @todo #261 13120 * @protected 13121 * @param {Event} - The `mousedown` or `touchstart` event. 13122 * @returns {Object} - Contains `x` and `y` coordinates of current pointer position. 13123 */ 13124 Owl.prototype.pointer = function(event) { 13125 var result = { x: null, y: null }; 13126 13127 event = event.originalEvent || event || window.event; 13128 13129 event = event.touches && event.touches.length ? 13130 event.touches[0] : event.changedTouches && event.changedTouches.length ? 13131 event.changedTouches[0] : event; 13132 13133 if (event.pageX) { 13134 result.x = event.pageX; 13135 result.y = event.pageY; 13136 } else { 13137 result.x = event.clientX; 13138 result.y = event.clientY; 13139 } 13140 13141 return result; 13142 }; 13143 13144 /** 13145 * Gets the difference of two vectors. 13146 * @todo #261 13147 * @protected 13148 * @param {Object} - The first vector. 13149 * @param {Object} - The second vector. 13150 * @returns {Object} - The difference. 13151 */ 13152 Owl.prototype.difference = function(first, second) { 13153 return { 13154 x: first.x - second.x, 13155 y: first.y - second.y 13156 }; 13157 }; 13158 13159 /** 13160 * The jQuery Plugin for the Owl Carousel 13161 * @todo Navigation plugin `next` and `prev` 13162 * @public 13163 */ 13164 $.fn.owlCarousel = function(option) { 13165 var args = Array.prototype.slice.call(arguments, 1); 13166 13167 return this.each(function() { 13168 var $this = $(this), 13169 data = $this.data('owl.carousel'); 13170 13171 if (!data) { 13172 data = new Owl(this, typeof option == 'object' && option); 13173 $this.data('owl.carousel', data); 13174 13175 $.each([ 13176 'next', 'prev', 'to', 'destroy', 'refresh', 'replace', 'add', 'remove' 13177 ], function(i, event) { 13178 data.register({ type: Owl.Type.Event, name: event }); 13179 data.$element.on(event + '.owl.carousel.core', $.proxy(function(e) { 13180 if (e.namespace && e.relatedTarget !== this) { 13181 this.suppress([ event ]); 13182 data[event].apply(this, [].slice.call(arguments, 1)); 13183 this.release([ event ]); 13184 } 13185 }, data)); 13186 }); 13187 } 13188 13189 if (typeof option == 'string' && option.charAt(0) !== '_') { 13190 data[option].apply(data, args); 13191 } 13192 }); 13193 }; 13194 13195 /** 13196 * The constructor for the jQuery Plugin 13197 * @public 13198 */ 13199 $.fn.owlCarousel.Constructor = Owl; 13200 13201})(window.Zepto || window.jQuery, window, document); 13202 13203/** 13204 * AutoRefresh Plugin 13205 * @version 2.0.0-beta.3 13206 * @author Artus Kolanowski 13207 * @license The MIT License (MIT) 13208 */ 13209;(function($, window, document, undefined) { 13210 13211 /** 13212 * Creates the auto refresh plugin. 13213 * @class The Auto Refresh Plugin 13214 * @param {Owl} carousel - The Owl Carousel 13215 */ 13216 var AutoRefresh = function(carousel) { 13217 /** 13218 * Reference to the core. 13219 * @protected 13220 * @type {Owl} 13221 */ 13222 this._core = carousel; 13223 13224 /** 13225 * Refresh interval. 13226 * @protected 13227 * @type {number} 13228 */ 13229 this._interval = null; 13230 13231 /** 13232 * Whether the element is currently visible or not. 13233 * @protected 13234 * @type {Boolean} 13235 */ 13236 this._visible = null; 13237 13238 /** 13239 * All event handlers. 13240 * @protected 13241 * @type {Object} 13242 */ 13243 this._handlers = { 13244 'initialized.owl.carousel': $.proxy(function(e) { 13245 if (e.namespace && this._core.settings.autoRefresh) { 13246 this.watch(); 13247 } 13248 }, this) 13249 }; 13250 13251 // set default options 13252 this._core.options = $.extend({}, AutoRefresh.Defaults, this._core.options); 13253 13254 // register event handlers 13255 this._core.$element.on(this._handlers); 13256 }; 13257 13258 /** 13259 * Default options. 13260 * @public 13261 */ 13262 AutoRefresh.Defaults = { 13263 autoRefresh: true, 13264 autoRefreshInterval: 500 13265 }; 13266 13267 /** 13268 * Watches the element. 13269 */ 13270 AutoRefresh.prototype.watch = function() { 13271 if (this._interval) { 13272 return; 13273 } 13274 13275 this._visible = this._core.$element.is(':visible'); 13276 this._interval = window.setInterval($.proxy(this.refresh, this), this._core.settings.autoRefreshInterval); 13277 }; 13278 13279 /** 13280 * Refreshes the element. 13281 */ 13282 AutoRefresh.prototype.refresh = function() { 13283 if (this._core.$element.is(':visible') === this._visible) { 13284 return; 13285 } 13286 13287 this._visible = !this._visible; 13288 13289 this._core.$element.toggleClass('owl-hidden', !this._visible); 13290 13291 this._visible && (this._core.invalidate('width') && this._core.refresh()); 13292 }; 13293 13294 /** 13295 * Destroys the plugin. 13296 */ 13297 AutoRefresh.prototype.destroy = function() { 13298 var handler, property; 13299 13300 window.clearInterval(this._interval); 13301 13302 for (handler in this._handlers) { 13303 this._core.$element.off(handler, this._handlers[handler]); 13304 } 13305 for (property in Object.getOwnPropertyNames(this)) { 13306 typeof this[property] != 'function' && (this[property] = null); 13307 } 13308 }; 13309 13310 $.fn.owlCarousel.Constructor.Plugins.AutoRefresh = AutoRefresh; 13311 13312})(window.Zepto || window.jQuery, window, document); 13313 13314/** 13315 * Lazy Plugin 13316 * @version 2.0.0-beta.3 13317 * @author Bartosz Wojciechowski 13318 * @license The MIT License (MIT) 13319 */ 13320;(function($, window, document, undefined) { 13321 13322 /** 13323 * Creates the lazy plugin. 13324 * @class The Lazy Plugin 13325 * @param {Owl} carousel - The Owl Carousel 13326 */ 13327 var Lazy = function(carousel) { 13328 13329 /** 13330 * Reference to the core. 13331 * @protected 13332 * @type {Owl} 13333 */ 13334 this._core = carousel; 13335 13336 /** 13337 * Already loaded items. 13338 * @protected 13339 * @type {Array.<jQuery>} 13340 */ 13341 this._loaded = []; 13342 13343 /** 13344 * Event handlers. 13345 * @protected 13346 * @type {Object} 13347 */ 13348 this._handlers = { 13349 'initialized.owl.carousel change.owl.carousel': $.proxy(function(e) { 13350 if (!e.namespace) { 13351 return; 13352 } 13353 13354 if (!this._core.settings || !this._core.settings.lazyLoad) { 13355 return; 13356 } 13357 13358 if ((e.property && e.property.name == 'position') || e.type == 'initialized') { 13359 var settings = this._core.settings, 13360 n = (settings.center && Math.ceil(settings.items / 2) || settings.items), 13361 i = ((settings.center && n * -1) || 0), 13362 position = ((e.property && e.property.value) || this._core.current()) + i, 13363 clones = this._core.clones().length, 13364 load = $.proxy(function(i, v) { this.load(v) }, this); 13365 13366 while (i++ < n) { 13367 this.load(clones / 2 + this._core.relative(position)); 13368 clones && $.each(this._core.clones(this._core.relative(position)), load); 13369 position++; 13370 } 13371 } 13372 }, this) 13373 }; 13374 13375 // set the default options 13376 this._core.options = $.extend({}, Lazy.Defaults, this._core.options); 13377 13378 // register event handler 13379 this._core.$element.on(this._handlers); 13380 } 13381 13382 /** 13383 * Default options. 13384 * @public 13385 */ 13386 Lazy.Defaults = { 13387 lazyLoad: false 13388 } 13389 13390 /** 13391 * Loads all resources of an item at the specified position. 13392 * @param {Number} position - The absolute position of the item. 13393 * @protected 13394 */ 13395 Lazy.prototype.load = function(position) { 13396 var $item = this._core.$stage.children().eq(position), 13397 $elements = $item && $item.find('.owl-lazy'); 13398 13399 if (!$elements || $.inArray($item.get(0), this._loaded) > -1) { 13400 return; 13401 } 13402 13403 $elements.each($.proxy(function(index, element) { 13404 var $element = $(element), image, 13405 url = (window.devicePixelRatio > 1 && $element.attr('data-src-retina')) || $element.attr('data-src'); 13406 13407 this._core.trigger('load', { element: $element, url: url }, 'lazy'); 13408 13409 if ($element.is('img')) { 13410 $element.one('load.owl.lazy', $.proxy(function() { 13411 $element.css('opacity', 1); 13412 this._core.trigger('loaded', { element: $element, url: url }, 'lazy'); 13413 }, this)).attr('src', url); 13414 } else { 13415 image = new Image(); 13416 image.onload = $.proxy(function() { 13417 $element.css({ 13418 'background-image': 'url(' + url + ')', 13419 'opacity': '1' 13420 }); 13421 this._core.trigger('loaded', { element: $element, url: url }, 'lazy'); 13422 }, this); 13423 image.src = url; 13424 } 13425 }, this)); 13426 13427 this._loaded.push($item.get(0)); 13428 } 13429 13430 /** 13431 * Destroys the plugin. 13432 * @public 13433 */ 13434 Lazy.prototype.destroy = function() { 13435 var handler, property; 13436 13437 for (handler in this.handlers) { 13438 this._core.$element.off(handler, this.handlers[handler]); 13439 } 13440 for (property in Object.getOwnPropertyNames(this)) { 13441 typeof this[property] != 'function' && (this[property] = null); 13442 } 13443 }; 13444 13445 $.fn.owlCarousel.Constructor.Plugins.Lazy = Lazy; 13446 13447})(window.Zepto || window.jQuery, window, document); 13448 13449/** 13450 * AutoHeight Plugin 13451 * @version 2.0.0-beta.3 13452 * @author Bartosz Wojciechowski 13453 * @license The MIT License (MIT) 13454 */ 13455;(function($, window, document, undefined) { 13456 13457 /** 13458 * Creates the auto height plugin. 13459 * @class The Auto Height Plugin 13460 * @param {Owl} carousel - The Owl Carousel 13461 */ 13462 var AutoHeight = function(carousel) { 13463 /** 13464 * Reference to the core. 13465 * @protected 13466 * @type {Owl} 13467 */ 13468 this._core = carousel; 13469 13470 /** 13471 * All event handlers. 13472 * @protected 13473 * @type {Object} 13474 */ 13475 this._handlers = { 13476 'initialized.owl.carousel refreshed.owl.carousel': $.proxy(function(e) { 13477 if (e.namespace && this._core.settings.autoHeight) { 13478 this.update(); 13479 } 13480 }, this), 13481 'changed.owl.carousel': $.proxy(function(e) { 13482 if (e.namespace && this._core.settings.autoHeight && e.property.name == 'position'){ 13483 this.update(); 13484 } 13485 }, this), 13486 'loaded.owl.lazy': $.proxy(function(e) { 13487 if (e.namespace && this._core.settings.autoHeight 13488 && e.element.closest('.' + this._core.settings.itemClass).index() === this._core.current()) { 13489 this.update(); 13490 } 13491 }, this) 13492 }; 13493 13494 // set default options 13495 this._core.options = $.extend({}, AutoHeight.Defaults, this._core.options); 13496 13497 // register event handlers 13498 this._core.$element.on(this._handlers); 13499 }; 13500 13501 /** 13502 * Default options. 13503 * @public 13504 */ 13505 AutoHeight.Defaults = { 13506 autoHeight: false, 13507 autoHeightClass: 'owl-height' 13508 }; 13509 13510 /** 13511 * Updates the view. 13512 */ 13513 AutoHeight.prototype.update = function() { 13514 var start = this._core._current, 13515 end = start + this._core.settings.items, 13516 visible = this._core.$stage.children().toArray().slice(start, end); 13517 heights = [], 13518 maxheight = 0; 13519 13520 $.each(visible, function(index, item) { 13521 heights.push($(item).height()); 13522 }); 13523 13524 maxheight = Math.max.apply(null, heights); 13525 13526 this._core.$stage.parent() 13527 .height(maxheight) 13528 .addClass(this._core.settings.autoHeightClass); 13529 }; 13530 13531 AutoHeight.prototype.destroy = function() { 13532 var handler, property; 13533 13534 for (handler in this._handlers) { 13535 this._core.$element.off(handler, this._handlers[handler]); 13536 } 13537 for (property in Object.getOwnPropertyNames(this)) { 13538 typeof this[property] != 'function' && (this[property] = null); 13539 } 13540 }; 13541 13542 $.fn.owlCarousel.Constructor.Plugins.AutoHeight = AutoHeight; 13543 13544})(window.Zepto || window.jQuery, window, document); 13545 13546/** 13547 * Video Plugin 13548 * @version 2.0.0-beta.3 13549 * @author Bartosz Wojciechowski 13550 * @license The MIT License (MIT) 13551 */ 13552;(function($, window, document, undefined) { 13553 13554 /** 13555 * Creates the video plugin. 13556 * @class The Video Plugin 13557 * @param {Owl} carousel - The Owl Carousel 13558 */ 13559 var Video = function(carousel) { 13560 /** 13561 * Reference to the core. 13562 * @protected 13563 * @type {Owl} 13564 */ 13565 this._core = carousel; 13566 13567 /** 13568 * Cache all video URLs. 13569 * @protected 13570 * @type {Object} 13571 */ 13572 this._videos = {}; 13573 13574 /** 13575 * Current playing item. 13576 * @protected 13577 * @type {jQuery} 13578 */ 13579 this._playing = null; 13580 13581 /** 13582 * All event handlers. 13583 * @todo The cloned content removale is too late 13584 * @protected 13585 * @type {Object} 13586 */ 13587 this._handlers = { 13588 'initialized.owl.carousel': $.proxy(function(e) { 13589 if (e.namespace) { 13590 this._core.register({ type: 'state', name: 'playing', tags: [ 'interacting' ] }); 13591 } 13592 }, this), 13593 'resize.owl.carousel': $.proxy(function(e) { 13594 if (e.namespace && this._core.settings.video && this.isInFullScreen()) { 13595 e.preventDefault(); 13596 } 13597 }, this), 13598 'refreshed.owl.carousel': $.proxy(function(e) { 13599 if (e.namespace && this._core.is('resizing')) { 13600 this._core.$stage.find('.cloned .owl-video-frame').remove(); 13601 } 13602 }, this), 13603 'changed.owl.carousel': $.proxy(function(e) { 13604 if (e.namespace && e.property.name === 'position' && this._playing) { 13605 this.stop(); 13606 } 13607 }, this), 13608 'prepared.owl.carousel': $.proxy(function(e) { 13609 if (!e.namespace) { 13610 return; 13611 } 13612 13613 var $element = $(e.content).find('.owl-video'); 13614 13615 if ($element.length) { 13616 $element.css('display', 'none'); 13617 this.fetch($element, $(e.content)); 13618 } 13619 }, this) 13620 }; 13621 13622 // set default options 13623 this._core.options = $.extend({}, Video.Defaults, this._core.options); 13624 13625 // register event handlers 13626 this._core.$element.on(this._handlers); 13627 13628 this._core.$element.on('click.owl.video', '.owl-video-play-icon', $.proxy(function(e) { 13629 this.play(e); 13630 }, this)); 13631 }; 13632 13633 /** 13634 * Default options. 13635 * @public 13636 */ 13637 Video.Defaults = { 13638 video: false, 13639 videoHeight: false, 13640 videoWidth: false 13641 }; 13642 13643 /** 13644 * Gets the video ID and the type (YouTube/Vimeo only). 13645 * @protected 13646 * @param {jQuery} target - The target containing the video data. 13647 * @param {jQuery} item - The item containing the video. 13648 */ 13649 Video.prototype.fetch = function(target, item) { 13650 var type = target.attr('data-vimeo-id') ? 'vimeo' : 'youtube', 13651 id = target.attr('data-vimeo-id') || target.attr('data-youtube-id'), 13652 width = target.attr('data-width') || this._core.settings.videoWidth, 13653 height = target.attr('data-height') || this._core.settings.videoHeight, 13654 url = target.attr('href'); 13655 13656 if (url) { 13657 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+)?/); 13658 13659 if (id[3].indexOf('youtu') > -1) { 13660 type = 'youtube'; 13661 } else if (id[3].indexOf('vimeo') > -1) { 13662 type = 'vimeo'; 13663 } else { 13664 throw new Error('Video URL not supported.'); 13665 } 13666 id = id[6]; 13667 } else { 13668 throw new Error('Missing video URL.'); 13669 } 13670 13671 this._videos[url] = { 13672 type: type, 13673 id: id, 13674 width: width, 13675 height: height 13676 }; 13677 13678 item.attr('data-video', url); 13679 13680 this.thumbnail(target, this._videos[url]); 13681 }; 13682 13683 /** 13684 * Creates video thumbnail. 13685 * @protected 13686 * @param {jQuery} target - The target containing the video data. 13687 * @param {Object} info - The video info object. 13688 * @see `fetch` 13689 */ 13690 Video.prototype.thumbnail = function(target, video) { 13691 var tnLink, 13692 icon, 13693 path, 13694 dimensions = video.width && video.height ? 'style="width:' + video.width + 'px;height:' + video.height + 'px;"' : '', 13695 customTn = target.find('img'), 13696 srcType = 'src', 13697 lazyClass = '', 13698 settings = this._core.settings, 13699 create = function(path) { 13700 icon = '<div class="owl-video-play-icon"></div>'; 13701 13702 if (settings.lazyLoad) { 13703 tnLink = '<div class="owl-video-tn ' + lazyClass + '" ' + srcType + '="' + path + '"></div>'; 13704 } else { 13705 tnLink = '<div class="owl-video-tn" style="opacity:1;background-image:url(' + path + ')"></div>'; 13706 } 13707 target.after(tnLink); 13708 target.after(icon); 13709 }; 13710 13711 // wrap video content into owl-video-wrapper div 13712 target.wrap('<div class="owl-video-wrapper"' + dimensions + '></div>'); 13713 13714 if (this._core.settings.lazyLoad) { 13715 srcType = 'data-src'; 13716 lazyClass = 'owl-lazy'; 13717 } 13718 13719 // custom thumbnail 13720 if (customTn.length) { 13721 create(customTn.attr(srcType)); 13722 customTn.remove(); 13723 return false; 13724 } 13725 13726 if (video.type === 'youtube') { 13727 path = "//img.youtube.com/vi/" + video.id + "/hqdefault.jpg"; 13728 create(path); 13729 } else if (video.type === 'vimeo') { 13730 $.ajax({ 13731 type: 'GET', 13732 url: '//vimeo.com/api/v2/video/' + video.id + '.json', 13733 jsonp: 'callback', 13734 dataType: 'jsonp', 13735 success: function(data) { 13736 path = data[0].thumbnail_large; 13737 create(path); 13738 } 13739 }); 13740 } 13741 }; 13742 13743 /** 13744 * Stops the current video. 13745 * @public 13746 */ 13747 Video.prototype.stop = function() { 13748 this._core.trigger('stop', null, 'video'); 13749 this._playing.find('.owl-video-frame').remove(); 13750 this._playing.removeClass('owl-video-playing'); 13751 this._playing = null; 13752 this._core.leave('playing'); 13753 this._core.trigger('stopped', null, 'video'); 13754 }; 13755 13756 /** 13757 * Starts the current video. 13758 * @public 13759 * @param {Event} event - The event arguments. 13760 */ 13761 Video.prototype.play = function(event) { 13762 var target = $(event.target), 13763 item = target.closest('.' + this._core.settings.itemClass), 13764 video = this._videos[item.attr('data-video')], 13765 width = video.width || '100%', 13766 height = video.height || this._core.$stage.height(), 13767 html; 13768 13769 if (this._playing) { 13770 return; 13771 } 13772 13773 this._core.enter('playing'); 13774 this._core.trigger('play', null, 'video'); 13775 13776 item = this._core.items(this._core.relative(item.index())); 13777 13778 this._core.reset(item.index()); 13779 13780 if (video.type === 'youtube') { 13781 html = '<iframe width="' + width + '" height="' + height + '" src="//www.youtube.com/embed/' + 13782 video.id + '?autoplay=1&v=' + video.id + '" frameborder="0" allowfullscreen></iframe>'; 13783 } else if (video.type === 'vimeo') { 13784 html = '<iframe src="//player.vimeo.com/video/' + video.id + 13785 '?autoplay=1" width="' + width + '" height="' + height + 13786 '" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>'; 13787 } 13788 13789 $('<div class="owl-video-frame">' + html + '</div>').insertAfter(item.find('.owl-video')); 13790 13791 this._playing = item.addClass('owl-video-playing'); 13792 }; 13793 13794 /** 13795 * Checks whether an video is currently in full screen mode or not. 13796 * @todo Bad style because looks like a readonly method but changes members. 13797 * @protected 13798 * @returns {Boolean} 13799 */ 13800 Video.prototype.isInFullScreen = function() { 13801 var element = document.fullscreenElement || document.mozFullScreenElement || 13802 document.webkitFullscreenElement; 13803 13804 return element && $(element).parent().hasClass('owl-video-frame'); 13805 }; 13806 13807 /** 13808 * Destroys the plugin. 13809 */ 13810 Video.prototype.destroy = function() { 13811 var handler, property; 13812 13813 this._core.$element.off('click.owl.video'); 13814 13815 for (handler in this._handlers) { 13816 this._core.$element.off(handler, this._handlers[handler]); 13817 } 13818 for (property in Object.getOwnPropertyNames(this)) { 13819 typeof this[property] != 'function' && (this[property] = null); 13820 } 13821 }; 13822 13823 $.fn.owlCarousel.Constructor.Plugins.Video = Video; 13824 13825})(window.Zepto || window.jQuery, window, document); 13826 13827/** 13828 * Animate Plugin 13829 * @version 2.0.0-beta.3 13830 * @author Bartosz Wojciechowski 13831 * @license The MIT License (MIT) 13832 */ 13833;(function($, window, document, undefined) { 13834 13835 /** 13836 * Creates the animate plugin. 13837 * @class The Navigation Plugin 13838 * @param {Owl} scope - The Owl Carousel 13839 */ 13840 var Animate = function(scope) { 13841 this.core = scope; 13842 this.core.options = $.extend({}, Animate.Defaults, this.core.options); 13843 this.swapping = true; 13844 this.previous = undefined; 13845 this.next = undefined; 13846 13847 this.handlers = { 13848 'change.owl.carousel': $.proxy(function(e) { 13849 if (e.namespace && e.property.name == 'position') { 13850 this.previous = this.core.current(); 13851 this.next = e.property.value; 13852 } 13853 }, this), 13854 'drag.owl.carousel dragged.owl.carousel translated.owl.carousel': $.proxy(function(e) { 13855 if (e.namespace) { 13856 this.swapping = e.type == 'translated'; 13857 } 13858 }, this), 13859 'translate.owl.carousel': $.proxy(function(e) { 13860 if (e.namespace && this.swapping && (this.core.options.animateOut || this.core.options.animateIn)) { 13861 this.swap(); 13862 } 13863 }, this) 13864 }; 13865 13866 this.core.$element.on(this.handlers); 13867 }; 13868 13869 /** 13870 * Default options. 13871 * @public 13872 */ 13873 Animate.Defaults = { 13874 animateOut: false, 13875 animateIn: false 13876 }; 13877 13878 /** 13879 * Toggles the animation classes whenever an translations starts. 13880 * @protected 13881 * @returns {Boolean|undefined} 13882 */ 13883 Animate.prototype.swap = function() { 13884 13885 if (this.core.settings.items !== 1) { 13886 return; 13887 } 13888
13889 if (!$.support.animation || !$.support.transition) { 13890 return; 13891 } 13892 13893 this.core.speed(0); 13894 13895 var left, 13896 clear = $.proxy(this.clear, this), 13897 previous = this.core.$stage.children().eq(this.previous), 13898 next = this.core.$stage.children().eq(this.next), 13899 incoming = this.core.settings.animateIn, 13900 outgoing = this.core.settings.animateOut; 13901 13902 if (this.core.current() === this.previous) { 13903 return; 13904 } 13905 13906 if (outgoing) { 13907 left = this.core.coordinates(this.previous) - this.core.coordinates(this.next); 13908 previous.css( { 'left': left + 'px' } ) 13909 .addClass('animated owl-animated-out') 13910 .addClass(outgoing) 13911 .on($.support.animation.end, clear); 13912 } 13913 13914 if (incoming) { 13915 next.addClass('animated owl-animated-in') 13916 .addClass(incoming) 13917 .on($.support.animation.end, clear); 13918 } 13919 }; 13920 13921 Animate.prototype.clear = function(e) { 13922 if ($(e.target).hasClass('animated')) { 13923 $(e.target).css( { 'left': '' } ) 13924 .removeClass('animated owl-animated-out owl-animated-in') 13925 .removeClass(this.core.settings.animateIn) 13926 .removeClass(this.core.settings.animateOut); 13927 this.core.onTransitionEnd(); 13928 } 13929 }; 13930 13931 /** 13932 * Destroys the plugin. 13933 * @public 13934 */ 13935 Animate.prototype.destroy = function() { 13936 var handler, property; 13937 13938 for (handler in this.handlers) { 13939 this.core.$element.off(handler, this.handlers[handler]); 13940 } 13941 for (property in Object.getOwnPropertyNames(this)) { 13942 typeof this[property] != 'function' && (this[property] = null); 13943 } 13944 }; 13945 13946 $.fn.owlCarousel.Constructor.Plugins.Animate = Animate; 13947 13948})(window.Zepto || window.jQuery, window, document); 13949 13950/** 13951 * Autoplay Plugin 13952 * @version 2.0.0-beta.3 13953 * @author Bartosz Wojciechowski 13954 * @author Artus Kolanowski 13955 * @license The MIT License (MIT) 13956 */ 13957;(function($, window, document, undefined) { 13958 13959 /** 13960 * Creates the autoplay plugin. 13961 * @class The Autoplay Plugin 13962 * @param {Owl} scope - The Owl Carousel 13963 */ 13964 var Autoplay = function(carousel) { 13965 /** 13966 * Reference to the core. 13967 * @protected 13968 * @type {Owl} 13969 */ 13970 this._core = carousel; 13971 13972 /** 13973 * The autoplay interval. 13974 * @type {Number} 13975 */ 13976 this._interval = null; 13977 13978 /** 13979 * Indicates whenever the autoplay is paused. 13980 * @type {Boolean} 13981 */ 13982 this._paused = false; 13983 13984 /** 13985 * All event handlers. 13986 * @protected 13987 * @type {Object} 13988 */ 13989 this._handlers = { 13990 'changed.owl.carousel': $.proxy(function(e) { 13991 if (e.namespace && e.property.name === 'settings') { 13992 if (this._core.settings.autoplay) { 13993 this.play(); 13994 } else { 13995 this.stop(); 13996 } 13997 } 13998 }, this), 13999 'initialized.owl.carousel': $.proxy(function(e) { 14000 if (e.namespace && this._core.settings.autoplay) { 14001 this.play(); 14002 } 14003 }, this), 14004 'play.owl.autoplay': $.proxy(function(e, t, s) { 14005 if (e.namespace) { 14006 this.play(t, s); 14007 } 14008 }, this), 14009 'stop.owl.autoplay': $.proxy(function(e) { 14010 if (e.namespace) { 14011 this.stop(); 14012 } 14013 }, this), 14014 'mouseover.owl.autoplay': $.proxy(function() { 14015 if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) { 14016 this.pause(); 14017 } 14018 }, this), 14019 'mouseleave.owl.autoplay': $.proxy(function() { 14020 if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) { 14021 this.play(); 14022 } 14023 }, this) 14024 }; 14025 14026 // register event handlers 14027 this._core.$element.on(this._handlers); 14028 14029 // set default options 14030 this._core.options = $.extend({}, Autoplay.Defaults, this._core.options); 14031 }; 14032 14033 /** 14034 * Default options. 14035 * @public 14036 */ 14037 Autoplay.Defaults = { 14038 autoplay: false, 14039 autoplayTimeout: 5000, 14040 autoplayHoverPause: false, 14041 autoplaySpeed: false 14042 }; 14043 14044 /** 14045 * Starts the autoplay. 14046 * @public 14047 * @param {Number} [timeout] - The interval before the next animation starts. 14048 * @param {Number} [speed] - The animation speed for the animations. 14049 */ 14050 Autoplay.prototype.play = function(timeout, speed) { 14051 this._paused = false; 14052 14053 if (this._core.is('rotating')) { 14054 return; 14055 } 14056 14057 this._core.enter('rotating'); 14058 14059 this._interval = window.setInterval($.proxy(function() { 14060 if (this._paused || this._core.is('busy') || this._core.is('interacting') || document.hidden) { 14061 return; 14062 } 14063 this._core.next(speed || this._core.settings.autoplaySpeed); 14064 }, this), timeout || this._core.settings.autoplayTimeout); 14065 }; 14066 14067 /** 14068 * Stops the autoplay. 14069 * @public 14070 */ 14071 Autoplay.prototype.stop = function() { 14072 if (!this._core.is('rotating')) { 14073 return; 14074 } 14075 14076 window.clearInterval(this._interval); 14077 this._core.leave('rotating'); 14078 }; 14079 14080 /** 14081 * Stops the autoplay. 14082 * @public 14083 */ 14084 Autoplay.prototype.pause = function() { 14085 if (!this._core.is('rotating')) { 14086 return; 14087 } 14088 14089 this._paused = true; 14090 }; 14091 14092 /** 14093 * Destroys the plugin. 14094 */ 14095 Autoplay.prototype.destroy = function() { 14096 var handler, property; 14097 14098 this.stop(); 14099 14100 for (handler in this._handlers) { 14101 this._core.$element.off(handler, this._handlers[handler]); 14102 } 14103 for (property in Object.getOwnPropertyNames(this)) { 14104 typeof this[property] != 'function' && (this[property] = null); 14105 } 14106 }; 14107 14108 $.fn.owlCarousel.Constructor.Plugins.autoplay = Autoplay; 14109 14110})(window.Zepto || window.jQuery, window, document); 14111 14112/** 14113 * Navigation Plugin 14114 * @version 2.0.0-beta.3 14115 * @author Artus Kolanowski 14116 * @license The MIT License (MIT) 14117 */ 14118;(function($, window, document, undefined) { 14119 'use strict'; 14120 14121 /** 14122 * Creates the navigation plugin. 14123 * @class The Navigation Plugin 14124 * @param {Owl} carousel - The Owl Carousel. 14125 */ 14126 var Navigation = function(carousel) { 14127 /** 14128 * Reference to the core. 14129 * @protected 14130 * @type {Owl} 14131 */ 14132 this._core = carousel; 14133 14134 /** 14135 * Indicates whether the plugin is initialized or not. 14136 * @protected 14137 * @type {Boolean} 14138 */ 14139 this._initialized = false;
vendor: 14,104 bytes, lines 14140-14668
14140 14141 /** 14142 * The current paging indexes. 14143 * @protected 14144 * @type {Array} 14145 */ 14146 this._pages = []; 14147 14148 /** 14149 * All DOM elements of the user interface. 14150 * @protected 14151 * @type {Object} 14152 */ 14153 this._controls = {}; 14154 14155 /** 14156 * Markup for an indicator. 14157 * @protected 14158 * @type {Array.<String>} 14159 */ 14160 this._templates = []; 14161 14162 /** 14163 * The carousel element. 14164 * @type {jQuery} 14165 */ 14166 this.$element = this._core.$element; 14167 14168 /** 14169 * Overridden methods of the carousel. 14170 * @protected 14171 * @type {Object} 14172 */ 14173 this._overrides = { 14174 next: this._core.next, 14175 prev: this._core.prev, 14176 to: this._core.to 14177 }; 14178 14179 /** 14180 * All event handlers. 14181 * @protected 14182 * @type {Object} 14183 */ 14184 this._handlers = { 14185 'prepared.owl.carousel': $.proxy(function(e) { 14186 if (e.namespace && this._core.settings.dotsData) { 14187 this._templates.push('<div class="' + this._core.settings.dotClass + '">' + 14188 $(e.content).find('[data-dot]').andSelf('[data-dot]').attr('data-dot') + '</div>'); 14189 } 14190 }, this), 14191 'added.owl.carousel': $.proxy(function(e) { 14192 if (e.namespace && this._core.settings.dotsData) { 14193 this._templates.splice(e.position, 0, this._templates.pop()); 14194 } 14195 }, this), 14196 'remove.owl.carousel': $.proxy(function(e) { 14197 if (e.namespace && this._core.settings.dotsData) { 14198 this._templates.splice(e.position, 1); 14199 } 14200 }, this), 14201 'changed.owl.carousel': $.proxy(function(e) { 14202 if (e.namespace && e.property.name == 'position') { 14203 this.draw(); 14204 } 14205 }, this), 14206 'initialized.owl.carousel': $.proxy(function(e) { 14207 if (e.namespace && !this._initialized) { 14208 this._core.trigger('initialize', null, 'navigation'); 14209 this.initialize(); 14210 this.update(); 14211 this.draw(); 14212 this._initialized = true; 14213 this._core.trigger('initialized', null, 'navigation'); 14214 } 14215 }, this), 14216 'refreshed.owl.carousel': $.proxy(function(e) { 14217 if (e.namespace && this._initialized) { 14218 this._core.trigger('refresh', null, 'navigation'); 14219 this.update(); 14220 this.draw(); 14221 this._core.trigger('refreshed', null, 'navigation'); 14222 } 14223 }, this) 14224 }; 14225 14226 // set default options 14227 this._core.options = $.extend({}, Navigation.Defaults, this._core.options); 14228 14229 // register event handlers 14230 this.$element.on(this._handlers); 14231 }; 14232 14233 /** 14234 * Default options. 14235 * @public 14236 * @todo Rename `slideBy` to `navBy` 14237 */ 14238 Navigation.Defaults = { 14239 nav: false, 14240 navText: [ 'prev', 'next' ], 14241 navSpeed: false, 14242 navElement: 'div', 14243 navContainer: false, 14244 navContainerClass: 'owl-nav', 14245 navClass: [ 'owl-prev', 'owl-next' ], 14246 slideBy: 1, 14247 dotClass: 'owl-dot', 14248 dotsClass: 'owl-dots', 14249 dots: true, 14250 dotsEach: false, 14251 dotsData: false, 14252 dotsSpeed: false, 14253 dotsContainer: false 14254 }; 14255 14256 /** 14257 * Initializes the layout of the plugin and extends the carousel. 14258 * @protected 14259 */ 14260 Navigation.prototype.initialize = function() { 14261 var override, 14262 settings = this._core.settings; 14263 14264 // create DOM structure for relative navigation 14265 this._controls.$relative = (settings.navContainer ? $(settings.navContainer) 14266 : $('<div>').addClass(settings.navContainerClass).appendTo(this.$element)).addClass('disabled'); 14267 14268 this._controls.$previous = $('<' + settings.navElement + '>') 14269 .addClass(settings.navClass[0]) 14270 .html(settings.navText[0]) 14271 .prependTo(this._controls.$relative) 14272 .on('click', $.proxy(function(e) { 14273 this.prev(settings.navSpeed); 14274 }, this)); 14275 this._controls.$next = $('<' + settings.navElement + '>') 14276 .addClass(settings.navClass[1]) 14277 .html(settings.navText[1]) 14278 .appendTo(this._controls.$relative) 14279 .on('click', $.proxy(function(e) { 14280 this.next(settings.navSpeed); 14281 }, this)); 14282 14283 // create DOM structure for absolute navigation 14284 if (!settings.dotsData) { 14285 this._templates = [ $('<div>') 14286 .addClass(settings.dotClass) 14287 .append($('<span>')) 14288 .prop('outerHTML') ]; 14289 } 14290 14291 this._controls.$absolute = (settings.dotsContainer ? $(settings.dotsContainer) 14292 : $('<div>').addClass(settings.dotsClass).appendTo(this.$element)).addClass('disabled'); 14293 14294 this._controls.$absolute.on('click', 'div', $.proxy(function(e) { 14295 var index = $(e.target).parent().is(this._controls.$absolute) 14296 ? $(e.target).index() : $(e.target).parent().index(); 14297 14298 e.preventDefault(); 14299 14300 this.to(index, settings.dotsSpeed); 14301 }, this)); 14302 14303 // override public methods of the carousel 14304 for (override in this._overrides) { 14305 this._core[override] = $.proxy(this[override], this); 14306 } 14307 }; 14308 14309 /** 14310 * Destroys the plugin. 14311 * @protected 14312 */ 14313 Navigation.prototype.destroy = function() { 14314 var handler, control, property, override; 14315 14316 for (handler in this._handlers) { 14317 this.$element.off(handler, this._handlers[handler]); 14318 } 14319 for (control in this._controls) { 14320 this._controls[control].remove(); 14321 } 14322 for (override in this.overides) { 14323 this._core[override] = this._overrides[override]; 14324 } 14325 for (property in Object.getOwnPropertyNames(this)) { 14326 typeof this[property] != 'function' && (this[property] = null); 14327 } 14328 }; 14329 14330 /** 14331 * Updates the internal state. 14332 * @protected 14333 */ 14334 Navigation.prototype.update = function() { 14335 var i, j, k, 14336 lower = this._core.clones().length / 2, 14337 upper = lower + this._core.items().length, 14338 maximum = this._core.maximum(true), 14339 settings = this._core.settings, 14340 size = settings.center || settings.autoWidth || settings.dotsData 14341 ? 1 : settings.dotsEach || settings.items; 14342 14343 if (settings.slideBy !== 'page') { 14344 settings.slideBy = Math.min(settings.slideBy, settings.items); 14345 } 14346 14347 if (settings.dots || settings.slideBy == 'page') { 14348 this._pages = []; 14349 14350 for (i = lower, j = 0, k = 0; i < upper; i++) { 14351 if (j >= size || j === 0) { 14352 this._pages.push({ 14353 start: Math.min(maximum, i - lower), 14354 end: i - lower + size - 1 14355 }); 14356 if (Math.min(maximum, i - lower) === maximum) { 14357 break; 14358 } 14359 j = 0, ++k; 14360 } 14361 j += this._core.mergers(this._core.relative(i)); 14362 } 14363 } 14364 }; 14365 14366 /** 14367 * Draws the user interface. 14368 * @todo The option `dotsData` wont work. 14369 * @protected 14370 */ 14371 Navigation.prototype.draw = function() { 14372 var difference, 14373 settings = this._core.settings, 14374 disabled = this._core.items().length <= settings.items, 14375 index = this._core.relative(this._core.current()), 14376 loop = settings.loop || settings.rewind; 14377 14378 this._controls.$relative.toggleClass('disabled', !settings.nav || disabled); 14379 14380 if (settings.nav) { 14381 this._controls.$previous.toggleClass('disabled', !loop && index <= this._core.minimum(true)); 14382 this._controls.$next.toggleClass('disabled', !loop && index >= this._core.maximum(true)); 14383 } 14384 14385 this._controls.$absolute.toggleClass('disabled', !settings.dots || disabled); 14386 14387 if (settings.dots) { 14388 difference = this._pages.length - this._controls.$absolute.children().length; 14389 14390 if (settings.dotsData && difference !== 0) { 14391 this._controls.$absolute.html(this._templates.join('')); 14392 } else if (difference > 0) { 14393 this._controls.$absolute.append(new Array(difference + 1).join(this._templates[0])); 14394 } else if (difference < 0) { 14395 this._controls.$absolute.children().slice(difference).remove(); 14396 } 14397 14398 this._controls.$absolute.find('.active').removeClass('active'); 14399 this._controls.$absolute.children().eq($.inArray(this.current(), this._pages)).addClass('active'); 14400 } 14401 }; 14402 14403 /** 14404 * Extends event data. 14405 * @protected 14406 * @param {Event} event - The event object which gets thrown. 14407 */ 14408 Navigation.prototype.onTrigger = function(event) { 14409 var settings = this._core.settings; 14410 14411 event.page = { 14412 index: $.inArray(this.current(), this._pages), 14413 count: this._pages.length, 14414 size: settings && (settings.center || settings.autoWidth || settings.dotsData 14415 ? 1 : settings.dotsEach || settings.items) 14416 }; 14417 }; 14418 14419 /** 14420 * Gets the current page position of the carousel. 14421 * @protected 14422 * @returns {Number} 14423 */ 14424 Navigation.prototype.current = function() { 14425 var current = this._core.relative(this._core.current()); 14426 return $.grep(this._pages, $.proxy(function(page, index) { 14427 return page.start <= current && page.end >= current; 14428 }, this)).pop(); 14429 }; 14430 14431 /** 14432 * Gets the current succesor/predecessor position. 14433 * @protected 14434 * @returns {Number} 14435 */ 14436 Navigation.prototype.getPosition = function(successor) { 14437 var position, length, 14438 settings = this._core.settings; 14439 14440 if (settings.slideBy == 'page') { 14441 position = $.inArray(this.current(), this._pages); 14442 length = this._pages.length; 14443 successor ? ++position : --position; 14444 position = this._pages[((position % length) + length) % length].start; 14445 } else { 14446 position = this._core.relative(this._core.current()); 14447 length = this._core.items().length; 14448 successor ? position += settings.slideBy : position -= settings.slideBy; 14449 } 14450 14451 return position; 14452 }; 14453 14454 /** 14455 * Slides to the next item or page. 14456 * @public 14457 * @param {Number} [speed=false] - The time in milliseconds for the transition. 14458 */ 14459 Navigation.prototype.next = function(speed) { 14460 $.proxy(this._overrides.to, this._core)(this.getPosition(true), speed); 14461 }; 14462 14463 /** 14464 * Slides to the previous item or page. 14465 * @public 14466 * @param {Number} [speed=false] - The time in milliseconds for the transition. 14467 */ 14468 Navigation.prototype.prev = function(speed) { 14469 $.proxy(this._overrides.to, this._core)(this.getPosition(false), speed); 14470 }; 14471 14472 /** 14473 * Slides to the specified item or page. 14474 * @public 14475 * @param {Number} position - The position of the item or page. 14476 * @param {Number} [speed] - The time in milliseconds for the transition. 14477 * @param {Boolean} [standard=false] - Whether to use the standard behaviour or not. 14478 */ 14479 Navigation.prototype.to = function(position, speed, standard) { 14480 var length; 14481 14482 if (!standard) { 14483 length = this._pages.length; 14484 $.proxy(this._overrides.to, this._core)(this._pages[((position % length) + length) % length].start, speed); 14485 } else { 14486 $.proxy(this._overrides.to, this._core)(position, speed); 14487 } 14488 }; 14489 14490 $.fn.owlCarousel.Constructor.Plugins.Navigation = Navigation; 14491 14492})(window.Zepto || window.jQuery, window, document); 14493 14494/** 14495 * Hash Plugin 14496 * @version 2.0.0-beta.3 14497 * @author Artus Kolanowski 14498 * @license The MIT License (MIT) 14499 */ 14500;(function($, window, document, undefined) { 14501 'use strict'; 14502 14503 /** 14504 * Creates the hash plugin. 14505 * @class The Hash Plugin 14506 * @param {Owl} carousel - The Owl Carousel 14507 */ 14508 var Hash = function(carousel) { 14509 /** 14510 * Reference to the core. 14511 * @protected 14512 * @type {Owl} 14513 */ 14514 this._core = carousel; 14515 14516 /** 14517 * Hash index for the items. 14518 * @protected 14519 * @type {Object} 14520 */ 14521 this._hashes = {}; 14522 14523 /** 14524 * The carousel element. 14525 * @type {jQuery} 14526 */ 14527 this.$element = this._core.$element; 14528 14529 /** 14530 * All event handlers. 14531 * @protected 14532 * @type {Object} 14533 */ 14534 this._handlers = { 14535 /*'initialized.owl.carousel': $.proxy(function(e) { 14536 if (e.namespace && this._core.settings.startPosition === 'URLHash') { 14537 $(window).trigger('hashchange.owl.navigation'); 14538 } 14539 }, this),*/ 14540 'prepared.owl.carousel': $.proxy(function(e) { 14541 if (e.namespace) { 14542 var hash = $(e.content).find('[data-hash]').addBack('[data-hash]').attr('data-hash'); 14543 14544 if (!hash) { 14545 return; 14546 } 14547 14548 this._hashes[hash] = e.content; 14549 } 14550 }, this), 14551 'changed.owl.carousel': $.proxy(function(e) { 14552 if (e.namespace && e.property.name === 'position') { 14553 var current = this._core.items(this._core.relative(this._core.current())), 14554 hash = $.map(this._hashes, function(item, hash) { 14555 return item === current ? hash : null; 14556 }).join(); 14557 14558 if (!hash || window.location.hash.slice(1) === hash) { 14559 return; 14560 } 14561 14562 window.location.hash = hash; 14563 } 14564 }, this) 14565 }; 14566 14567 // set default options 14568 this._core.options = $.extend({}, Hash.Defaults, this._core.options); 14569 14570 // register the event handlers 14571 this.$element.on(this._handlers); 14572 14573 // register event listener for hash navigation 14574 /*$(window).on('hashchange.owl.navigation', $.proxy(function(e) { 14575 var hash = window.location.hash.substring(1), 14576 items = this._core.$stage.children(), 14577 position = this._hashes[hash] && items.index(this._hashes[hash]); 14578 14579 if (position === undefined || position === this._core.current()) { 14580 return; 14581 } 14582 14583 this._core.to(this._core.relative(position), false, true); 14584 }, this));*/ 14585 }; 14586 14587 /** 14588 * Default options. 14589 * @public 14590 */ 14591 Hash.Defaults = { 14592 URLhashListener: false 14593 }; 14594 14595 /** 14596 * Destroys the plugin. 14597 * @public 14598 */ 14599 Hash.prototype.destroy = function() { 14600 var handler, property; 14601 14602 $(window).off('hashchange.owl.navigation'); 14603 14604 for (handler in this._handlers) { 14605 this._core.$element.off(handler, this._handlers[handler]); 14606 } 14607 for (property in Object.getOwnPropertyNames(this)) { 14608 typeof this[property] != 'function' && (this[property] = null); 14609 } 14610 }; 14611 14612 $.fn.owlCarousel.Constructor.Plugins.Hash = Hash; 14613 14614})(window.Zepto || window.jQuery, window, document); 14615 14616/** 14617 * Support Plugin 14618 * 14619 * @version 2.0.0-beta.3 14620 * @author Vivid Planet Software GmbH 14621 * @author Artus Kolanowski 14622 * @license The MIT License (MIT) 14623 */ 14624;(function($, window, document, undefined) { 14625 14626 var style = $('<support>').get(0).style, 14627 prefixes = 'Webkit Moz O ms'.split(' '), 14628 events = { 14629 transition: { 14630 end: { 14631 WebkitTransition: 'webkitTransitionEnd', 14632 MozTransition: 'transitionend', 14633 OTransition: 'oTransitionEnd', 14634 transition: 'transitionend' 14635 } 14636 }, 14637 animation: { 14638 end: { 14639 WebkitAnimation: 'webkitAnimationEnd', 14640 MozAnimation: 'animationend', 14641 OAnimation: 'oAnimationEnd', 14642 animation: 'animationend' 14643 } 14644 } 14645 }, 14646 tests = { 14647 csstransforms: function() { 14648 return !!test('transform'); 14649 }, 14650 csstransforms3d: function() { 14651 return !!test('perspective'); 14652 }, 14653 csstransitions: function() { 14654 return !!test('transition'); 14655 }, 14656 cssanimations: function() { 14657 return !!test('animation'); 14658 } 14659 }; 14660 14661 function test(property, prefixed) { 14662 var result = false, 14663 upper = property.charAt(0).toUpperCase() + property.slice(1); 14664 14665 $.each((property + ' ' + prefixes.join(upper + ' ') + upper).split(' '), function(i, property) { 14666 if (style[property] !== undefined) { 14667 result = prefixed ? property : true; 14668 return false;
14669 } 14670 }); 14671 14672 return result; 14673 } 14674 14675 function prefixed(property) { 14676 return test(property, true); 14677 } 14678 14679 if (tests.csstransitions()) { 14680 /* jshint -W053 */ 14681 $.support.transition = new String(prefixed('transition')) 14682 $.support.transition.end = events.transition.end[ $.support.transition ]; 14683 } 14684 14685 if (tests.cssanimations()) { 14686 /* jshint -W053 */ 14687 $.support.animation = new String(prefixed('animation')) 14688 $.support.animation.end = events.animation.end[ $.support.animation ]; 14689 } 14690 14691 if (tests.csstransforms()) { 14692 /* jshint -W053 */ 14693 $.support.transform = new String(prefixed('transform')); 14694 $.support.transform3d = tests.csstransforms3d(); 14695 } 14696 14697})(window.Zepto || window.jQuery, window, document); 14698 14699(function(window, document, undefined) { 14700 14701 /** 14702 * Find the absolute position of an element 14703 */ 14704 var absPos = function(element) { 14705 var offsetLeft, offsetTop; 14706 offsetLeft = offsetTop = 0; 14707 if (element.offsetParent) { 14708 do { 14709 offsetLeft += element.offsetLeft; 14710 offsetTop += element.offsetTop; 14711 } while (element = element.offsetParent); 14712 } 14713 return [offsetLeft, offsetTop]; 14714 }; 14715 14716 /** 14717 * @constructor Progress Circle class 14718 * @param params.canvas Canvas on which the circles will be drawn. 14719 * @param params.minRadius Inner radius of the innermost circle, in px. 14720 * @param params.arcWidth Width of each circle(to be more accurate, ring). 14721 * @param params.gapWidth Space between each circle. 14722 * @param params.centerX X coordinate of the center of circles. 14723 * @param params.centerY Y coordinate of the center of circles. 14724 * @param params.infoLineBaseAngle Base angle of the info line. 14725 * @param params.infoLineAngleInterval Angles between the info lines. 14726 */ 14727 var ProgressCircle = function(params) { 14728 this.canvas = params.canvas; 14729 this.minRadius = params.minRadius || 15; 14730 this.arcWidth = params.arcWidth || 5; 14731 this.gapWidth = params.gapWidth || 3; 14732 this.centerX = params.centerX || this.canvas.width / 2; 14733 this.centerY = params.centerY || this.canvas.height / 2;
14734 this.infoLineLength = params.infoLineLength || 60; 14735 this.horizLineLength = params.horizLineLength || 10; 14736 this.infoLineAngleInterval = params.infoLineAngleInterval || Math.PI / 8; 14737 this.infoLineBaseAngle = params.infoLineBaseAngle || Math.PI / 6; 14738 14739 this.context = this.canvas.getContext('2d'); 14740 14741 this.width = this.canvas.width; 14742 this.height = this.canvas.height; 14743 14744 this.circles = []; 14745 this.runningCount = 0; 14746 }; 14747 14748 ProgressCircle.prototype = { 14749 constructor: ProgressCircle, 14750 14751 /** 14752 * @method Adds an progress monitor entry. 14753 * @param params.fillColor Color to fill in the circle. 14754 * @param params.outlineColor Color to outline the circle. 14755 * @param params.progressListener Callback function to fetch the progress. 14756 * @param params.infoListener Callback function to fetch the info. 14757 * @returns this 14758 */ 14759 addEntry: function(params) { 14760 this.circles.push(new Circle({ 14761 canvas: this.canvas, 14762 context: this.context, 14763 centerX: this.centerX, 14764 centerY: this.centerY, 14765 innerRadius: this.minRadius + this.circles.length * 14766 (this.gapWidth + this.arcWidth), 14767 arcWidth: this.arcWidth,
14768 infoLineLength: this.infoLineLength, 14769 horizLineLength: this.horizLineLength, 14770 14771 id: this.circles.length, 14772 fillColor: params.fillColor, 14773 outlineColor: params.outlineColor, 14774 progressListener: params.progressListener, 14775 infoListener: params.infoListener, 14776 infoLineAngle: this.infoLineBaseAngle + 14777 this.circles.length * this.infoLineAngleInterval, 14778 })); 14779 14780 return this; 14781 }, 14782 14783 /** 14784 * @method Starts the monitor and updates with the given interval. 14785 * @param interval Interval between updates, in millisecond. 14786 * @returns this 14787 */ 14788 start: function(interval) { 14789 var self = this; 14790 this.timer = setInterval(function() { 14791 self._update(); 14792 }, interval || 33); 14793 14794 return this; 14795 }, 14796 14797 /** 14798 * @method Stop the animation. 14799 */ 14800 stop: function() { 14801 clearTimeout(this.timer); 14802 }, 14803 14804 /** 14805 * @private 14806 * @method Call update on each circle and redraw them. 14807 * @returns this 14808 */ 14809 _update: function() { 14810 this._clear(); 14811 this.circles.forEach(function(circle, idx, array) { 14812 circle.update(); 14813 }); 14814 14815 return this; 14816 }, 14817 14818 /** 14819 * @private 14820 * @method Clear the canvas. 14821 * @returns this 14822 */ 14823 _clear: function() { 14824 this.context.clearRect(0, 0, this.canvas.width, this.canvas.height); 14825 14826 return this; 14827 }, 14828 14829 }; 14830 14831 /** 14832 * @private 14833 * @class Individual progress circle. 14834 * @param params.canvas Canvas on which the circle will be drawn. 14835 * @param params.context Context of the canvas. 14836 * @param params.innerRadius Inner radius of the circle, in px. 14837 * @param params.arcWidth Width of each arc(circle). 14838 * @param params.gapWidth Distance between each arc. 14839 * @param params.centerX X coordinate of the center of circles. 14840 * @param params.centerY Y coordinate of the center of circles. 14841 * @param params.fillColor Color to fill in the circle. 14842 * @param params.outlineColor Color to outline the circle. 14843 * @param params.progressListener Callback function to fetch the progress. 14844 * @param params.infoListener Callback function to fetch the info. 14845 * @param params.infoLineAngle Angle of info line. 14846 */ 14847 var Circle = function(params) { 14848 this.id = params.id; 14849 this.canvas = params.canvas; 14850 this.context = params.context; 14851 this.centerX = params.centerX; 14852 this.centerY = params.centerY; 14853 this.arcWidth = params.arcWidth; 14854 this.innerRadius = params.innerRadius || 0; 14855 this.fillColor = params.fillColor || '#fff'; 14856 this.outlineColor = params.outlineColor || this.fillColor; 14857 this.progressListener = params.progressListener;
14858 this.infoLineLength = params.infoLineLength || 250; 14859 this.horizLineLength = params.horizLineLength || 50; 14860 this.infoListener = params.infoListener; 14861 this.infoLineAngle = params.infoLineAngle; 14862 14863 this.outerRadius = this.innerRadius + this.arcWidth; 14864 14865 // If the info listener is not registered, then don't calculate 14866 // the related coordinates 14867 if (!this.infoListener) return; 14868 14869 // calculate the info-line turning points 14870 var angle = this.infoLineAngle, 14871 arcDistance = (this.innerRadius + this.outerRadius) / 2, 14872 14873 sinA = Math.sin(angle), 14874 cosA = Math.cos(angle); 14875 14876 this.infoLineStartX = this.centerX + sinA * arcDistance; 14877 this.infoLineStartY = this.centerY - cosA * arcDistance; 14878 14879 this.infoLineMidX = this.centerX + sinA * this.infoLineLength; 14880 this.infoLineMidY = this.centerY - cosA * this.infoLineLength; 14881 14882 this.infoLineEndX = this.infoLineMidX + 14883 (sinA < 0 ? -this.horizLineLength : this.horizLineLength); 14884 this.infoLineEndY = this.infoLineMidY; 14885 14886 var infoText = document.createElement('div'), 14887 style = infoText.style; 14888 14889 style.color = this.fillColor; 14890 style.position = 'absolute'; 14891 style.left = this.infoLineEndX + absPos(this.canvas)[0] + 'px'; 14892 // style.top will be calculated in the `drawInfo` method. Since 14893 // user may want to change the size of the font, so the top offset 14894 // must be updated in each loop. 14895 infoText.className = 'ProgressCircleInfo'; // For css styling 14896 infoText.id = 'progress_circle_info_' + this.id; 14897 document.body.appendChild(infoText); 14898 this.infoText = infoText; 14899 }; 14900 14901 Circle.prototype = { 14902 constructor: Circle, 14903 14904 update: function() { 14905 this.progress = this.progressListener(); 14906 this._draw(); 14907 14908 if (this.infoListener) { 14909 this.info = this.infoListener(); 14910 this._drawInfo(); 14911 } 14912 }, 14913 14914 /** 14915 * @private 14916 * @method Draw the circle on the canvas. 14917 * @returns this 14918 */ 14919 _draw: function() { 14920 var ctx = this.context, 14921 14922 ANGLE_OFFSET = -Math.PI / 2, 14923 14924 startAngle = 0 + ANGLE_OFFSET, 14925 endAngle= startAngle + this.progress * Math.PI * 2, 14926 14927 x = this.centerX, 14928 y = this.centerY, 14929 14930 innerRadius = this.innerRadius - this.arcWidth - 1, 14931 outerRadius = this.outerRadius - this.arcWidth - 1; 14932 14933 if ( innerRadius < 0 ) 14934 return; 14935 14936 ctx.fillStyle = this.fillColor; 14937 ctx.strokeStyle = this.outlineColor; 14938 14939 ctx.beginPath(); 14940 ctx.arc(x, y, innerRadius, startAngle, endAngle, false); 14941 ctx.arc(x, y, outerRadius, endAngle, startAngle, true); 14942 ctx.closePath(); 14943 ctx.stroke(); 14944 ctx.fill(); 14945 14946 return this; 14947 }, 14948 14949 /** 14950 * @private 14951 * @method Draw the info lines and info text. 14952 * @returns this 14953 */ 14954 _drawInfo: function() { 14955 14956 var pointList, lineHeight; 14957 14958 pointList = [ 14959 [this.infoLineStartX, this.infoLineStartY], 14960 [this.infoLineMidX, this.infoLineMidY], 14961 [this.infoLineEndX, this.infoLineEndY], 14962 ]; 14963 this._drawSegments(pointList, false); 14964 14965 this.infoText.innerHTML = this.info; 14966 14967 lineHeight = this.infoText.offsetHeight; 14968 this.infoText.style.top = this.infoLineEndY + 14969 absPos(this.canvas)[1] - lineHeight / 2 + 'px'; 14970 14971 return this; 14972 }, 14973 14974 /** 14975 * @private 14976 * @method Helper function to draw the segments 14977 * @param pointList An array of points in the form of [x, y]. 14978 * @param close Whether to connect the first and last point. 14979 */ 14980 _drawSegments: function(pointList, close) { 14981 var ctx = this.context; 14982 14983 ctx.beginPath(); 14984 ctx.moveTo(pointList[0][0], pointList[0][1]); 14985 for (var i = 1; i < pointList.length; ++i) { 14986 ctx.lineTo(pointList[i][0], pointList[i][1]); 14987 } 14988 14989 if (close) { 14990 ctx.closePath(); 14991 } 14992 ctx.stroke(); 14993 }, 14994 }; 14995 14996 window.ProgressCircle = ProgressCircle; 14997 14998})(window, document); 14999 15000 15001 15002 15003/* ========================================================= 15004 * jquery.vc_chart.js v1.0 15005 * ========================================================= 15006 * Copyright 2013 Wpbakery 15007 * 15008 * Jquery chart plugin for the Visual Composer. 15009 * ========================================================= */ 15010(function($){ 15011 /** 15012 * Pie chart animated. 15013 * @param element - DOM element 15014 * @param options - settings object. 15015 * @constructor 15016 */ 15017 var VcChart = function(element, options) { 15018 this.el = element; 15019 this.$el = $(this.el); 15020 var $this = this; 15021 $this.options = $.extend({ 15022 color: 'wpb_button', 15023 units: '', 15024 width: '', 15025 label_selector: '.vc_pie_chart_value', 15026 back_selector: '.vc_pie_chart_back', 15027 responsive: true 15028 }, options); 15029 $this.init(); 15030 }; 15031 VcChart.prototype = { 15032 constructor: VcChart, 15033 _progress_v: 0, 15034 animated: false, 15035 colors: { 15036 'wpb_button': 'rgba(247, 247, 247, 1)', 15037 'btn-primary': 'rgba(0, 136, 204, 1)', 15038 'btn-info': 'rgba(88, 185, 218, 1)', 15039 'btn-success': 'rgba(106, 177, 101, 1)', 15040 'btn-warning': 'rgba(255, 153, 0, 1)', 15041 'btn-danger': 'rgba(255, 103, 91, 1)', 15042 'btn-inverse': 'rgba(85, 85, 85, 1)' 15043 }, 15044 init: function() { 15045 this.setupColor(); 15046 this.value = this.$el.data('pie-value')/100; 15047 this.label_value = this.$el.data('pie-label-value') || this.$el.data('pie-value'); 15048 this.$wrapper = $('.vc_pie_wrapper', this.$el); 15049 this.$label = $(this.options.label_selector, this.$el); 15050 this.$back = $(this.options.back_selector, this.$el); 15051 this.$canvas = this.$el.find('canvas'); 15052 this.arcWidth = this.$el.data('pie-width') * 2; 15053 this.draw(); 15054 this.setWayPoint(); 15055 if(this.options.responsive === true) this.setResponsive(); 15056 if (UNCODE.isMobile) this._progress_v = this.value; 15057 }, 15058 setupColor: function() { 15059 // if(typeof this.colors[this.options.color] !== 'undefined') { 15060 // this.color = this.colors[this.options.color]; 15061 // } else if(typeof this.options.color === 'string' && this.options.color.match(/^rgba?\([^\)]+\)/)) { 15062 // this.color = this.options.color; 15063 // } else { 15064 // this.color = 'rgba(247, 247, 247, 0.2)'; 15065 // } 15066 if(typeof this.options.color !== 'undefined') { 15067 this.color = this.options.color; 15068 } else this.color = 'rgba(247, 247, 247, 0.2)'; 15069 15070 }, 15071 setResponsive: function() { 15072 var that = this; 15073 if (!UNCODE.isMobile) { 15074 $(window).resize(function(){ 15075 if(that.animated === true) that.circle.stop(); 15076 that.draw(true); 15077 }); 15078 } 15079 }, 15080 draw: function(redraw) { 15081 var w = this.$el.addClass('vc_ready').width() * 2, 15082 border_w = this.arcWidth, 15083 radius; 15084 if(!w) w = this.$el.parents(':visible').first().width()-2; 15085 //w = Math.round(w/100*80); 15086 //if (w < 250) w = 250; 15087 radius = w/2; 15088 this.$wrapper.css({"width" : (w / 2) + "px"}); 15089 this.$label.css({"width" : (w / 2), "height" : (w / 2), "line-height" : (w / 2)+"px"}); 15090 this.$back.css({"width" : (w / 2), "height" : (w / 2)}); 15091 this.$canvas.attr({"width" : w + "px", "height" : w + "px"}); 15092 this.$el.addClass('vc_ready'); 15093 this.circle = new ProgressCircle({ 15094 canvas: this.$canvas.get(0), 15095 minRadius: radius, 15096 arcWidth: border_w 15097 }); 15098 if(redraw === true && this.animated === true) { 15099 this._progress_v = this.value; 15100 this.circle.addEntry({ 15101 fillColor: this.color, 15102 progressListener: $.proxy(this.setProgress, this) 15103 }).start(); 15104 } 15105 }, 15106 setProgress: function() { 15107 if (this._progress_v >= this.value) { 15108 this.circle.stop(); 15109 this.animated = true; 15110 this.$label.html(this.label_value + this.options.units); 15111 return this._progress_v; 15112 } 15113 this._progress_v += 0.01; 15114 if (!isNaN(this.label_value)) { 15115 var label_value = this._progress_v/this.value*this.label_value; 15116 var val = Math.round(label_value) + this.options.units; 15117 this.$label.html(val); 15118 } else this.$label.html(this.label_value + this.options.units); 15119 return this._progress_v; 15120 }, 15121 animate: function() { 15122 if(this.animated !== true) { 15123 this.circle.addEntry({ 15124 fillColor: this.color, 15125 progressListener: $.proxy(this.setProgress, this) 15126 }).start(10); 15127 } 15128 }, 15129 setWayPoint: function() { 15130 if (typeof $.fn.waypoint !== 'undefined' && !UNCODE.isMobile) { 15131 this.$el.waypoint($.proxy(this.animate, this), { offset: '85%' }); 15132 } else { 15133 this.animate(); 15134 } 15135 } 15136 }; 15137 /** 15138 * jQuery plugin 15139 * @param option - object with settings 15140 * @return {*} 15141 */ 15142 $.fn.vcChat = function(option, value) { 15143 return this.each(function () { 15144 var $this = $(this), 15145 data = $this.data('vc_chart'), 15146 options = typeof option === 'object' ? option : { 15147 color: $this.data('pie-color'), 15148 units: $this.data('pie-units') 15149 }; 15150 if (typeof option == 'undefined') $this.data('vc_chart', (data = new VcChart(this, options))); 15151 if (typeof option == 'string') data[option](value); 15152 }); 15153 }; 15154 /** 15155 * Allows users to rewrite function inside theme. 15156 */ 15157 if ( typeof window['vc_pieChart'] !== 'function' ) { 15158 window.vc_pieChart = function() { 15159 $('.vc_pie_chart:visible:not(.vc_ready)').vcChat(); 15160 } 15161 } 15162 $(document).ready(function(){ 15163 !window.vc_iframe && vc_pieChart(); 15164 15165 /** 15166 * Tab and collapse integration. 15167 */ 15168 $('.nav-tabs a').on('shown.bs.tab', function(e){ 15169 var $cont = $(e.target).closest('.tab-container'), 15170 $active = $('.tab-pane.active', $cont); 15171 $('.vc_pie_chart:not(.vc_ready)', $active).vcChat(); 15172 }); 15173 15174 $('.panel-collapse').on('shown.bs.collapse', function (e) { 15175 $('.vc_pie_chart:not(.vc_ready)', e.target).vcChat(); 15176 }) 15177 }); 15178 15179})(window.jQuery); 15180 15181/* Progress bar 15182 ---------------------------------------------------------- */ 15183function uncode_progress_bar() {    15184 jQuery.each(jQuery('.vc_progress_bar'), function(index, val) { 15185 if (UNCODE.isUnmodalOpen && !val.closest('#unmodal-content')) { 15186 return; 15187 } 15188 if (!UNCODE.isMobile) { 15189 new Waypoint({ 15190 context: UNCODE.isUnmodalOpen ? document.getElementById('unmodal-content') : window, 15191 element: val, 15192 handler: function() { 15193 var element = jQuery(this.element); 15194 element.find('.vc_single_bar').each(function(index) {          15195 var $this = jQuery(this), 15196             bar = $this.find('.vc_bar'), 15197             val = bar.data('percentage-value');          15198 setTimeout(function() {            15199 bar.css({ 15200 "width": val + '%' 15201 });          15202 }, index * 200);        15203 }); 15204 }, 15205 offset: '80%' 15206 }); 15207 } else { 15208 var element = jQuery(val); 15209 element.find('.vc_single_bar').each(function(index) {          15210 var $this = jQuery(this), 15211             bar = $this.find('.vc_bar'), 15212             val = bar.data('percentage-value');          15213 setTimeout(function() {            15214 bar.css({ 15215 "width": val + '%' 15216 });          15217 }, index * 200);        15218 }); 15219 } 15220 }); 15221}; 15222uncode_progress_bar(); 15223 15224/*! 15225 * jquery.counterup.js 1.0 15226 * 15227 * Copyright 2013, Benjamin Intal http://gambit.ph @bfintal 15228 * Released under the GPL v2 License 15229 * 15230 * Date: Nov 26, 2013 15231 */ 15232(function($) { 15233 "use strict"; 15234 $.fn.counterUp = function(options) { 15235 // Defaults 15236 var settings = $.extend({ 15237 'time': 400, 15238 'delay': 10 15239 }, options); 15240 return this.each(function() { 15241 // Store the object 15242 var $this = $(this); 15243 var $settings = settings; 15244 var counterUpper = function() { 15245 var nums = []; 15246 var divisions = $settings.time / $settings.delay; 15247 var numReal = $this.attr('data-val'), 15248 num = numReal; 15249 var isComma = /[0-9]+,[0-9]+/.test(num); 15250 num = num.replace(/,/g, ''); 15251 var isInt = /^[0-9]+$/.test(num); 15252 var isFloat = /^[0-9]+\.[0-9]+$/.test(num); 15253 var decimalPlaces = isFloat ? (num.split('.')[1] || []).length : 0; 15254 // Generate list of incremental numbers to display 15255 for (var i = divisions; i >= 1; i--) { 15256 // Preserve as int if input was int 15257 var newNum = parseInt(num / divisions * i); 15258 // Preserve float if input was float 15259 if (isFloat) { 15260 newNum = parseFloat(num / divisions * i).toFixed(decimalPlaces); 15261 } 15262 // Preserve commas if input had commas 15263 if (isComma) { 15264 while (/(\d+)(\d{3})/.test(newNum.toString())) { 15265 newNum = newNum.toString().replace(/(\d+)(\d{3})/, '$1' + ',' + '$2'); 15266 } 15267 } 15268 nums.unshift(newNum); 15269 } 15270 nums.push(numReal); 15271 $this.data('counterup-nums', nums); 15272 $this.text('0'); 15273 // Updates the number until we're done 15274 var f = function() { 15275 if ($this.data('counterup-nums') != null) { 15276 $this.text($this.data('counterup-nums').shift()); 15277 if ($this.data('counterup-nums').length) { 15278 setTimeout($this.data('counterup-func'), $settings.delay); 15279 } else { 15280 delete $this.data('counterup-nums'); 15281 $this.data('counterup-nums', null); 15282 $this.data('counterup-func', null); 15283 } 15284 } 15285 }; 15286 $this.data('counterup-func', f); 15287 // Start the count up 15288 setTimeout($this.data('counterup-func'), $settings.delay); 15289 }; 15290 // Perform counts when the element gets into view 15291 new Waypoint({ 15292 context: UNCODE.isUnmodalOpen ? document.getElementById('unmodal-content') : window, 15293 element: this, 15294 handler: function() { 15295 counterUpper(); 15296 if (!UNCODE.isUnmodalOpen) { 15297 this.destroy(); 15298 } 15299 }, 15300 offset: '100%' 15301 }); 15302 }); 15303 }; 15304})(jQuery); 15305 15306/*! 15307 * The Final Countdown for jQuery v2.0.4 (http://hilios.github.io/jQuery.countdown/) 15308 * Copyright (c) 2014 Edson Hilios 15309 * 15310 * Permission is hereby granted, free of charge, to any person obtaining a copy of 15311 * this software and associated documentation files (the "Software"), to deal in 15312 * the Software without restriction, including without limitation the rights to 15313 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 15314 * the Software, and to permit persons to whom the Software is furnished to do so, 15315 * subject to the following conditions: 15316 * 15317 * The above copyright notice and this permission notice shall be included in all 15318 * copies or substantial portions of the Software. 15319 * 15320 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15321 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 15322 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15323 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 15324 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 15325 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15326 */ 15327(function(factory) { 15328 "use strict"; 15329 if (typeof define === "function" && define.amd) { 15330 define([ "jquery" ], factory); 15331 } else { 15332 factory(jQuery); 15333 } 15334})(function($) { 15335 "use strict"; 15336 var PRECISION = 100; 15337 var instances = [], matchers = []; 15338 matchers.push(/^[0-9]*$/.source); 15339 matchers.push(/([0-9]{1,2}\/){2}[0-9]{4}( [0-9]{1,2}(:[0-9]{2}){2})?/.source); 15340 matchers.push(/[0-9]{4}([\/\-][0-9]{1,2}){2}( [0-9]{1,2}(:[0-9]{2}){2})?/.source); 15341 matchers = new RegExp(matchers.join("|")); 15342 function parseDateString(dateString) { 15343 if (dateString instanceof Date) { 15344 return dateString; 15345 } 15346 if (String(dateString).match(matchers)) { 15347 if (String(dateString).match(/^[0-9]*$/)) { 15348 dateString = Number(dateString); 15349 } 15350 if (String(dateString).match(/\-/)) { 15351 dateString = String(dateString).replace(/\-/g, "/"); 15352 } 15353 return new Date(dateString); 15354 } else { 15355 throw new Error("Couldn't cast `" + dateString + "` to a date object."); 15356 } 15357 } 15358 var DIRECTIVE_KEY_MAP = { 15359 Y: "years", 15360 m: "months", 15361 w: "weeks", 15362 d: "days", 15363 D: "totalDays", 15364 H: "hours", 15365 M: "minutes", 15366 S: "seconds" 15367 }; 15368 function strftime(offsetObject) { 15369 return function(format) { 15370 var directives = format.match(/%(-|!)?[A-Z]{1}(:[^;]+;)?/gi); 15371 if (directives) { 15372 for (var i = 0, len = directives.length; i < len; ++i) { 15373 var directive = directives[i].match(/%(-|!)?([a-zA-Z]{1})(:[^;]+;)?/), regexp = new RegExp(directive[0]), modifier = directive[1] || "", plural = directive[3] || "", value = null; 15374 directive = directive[2]; 15375 if (DIRECTIVE_KEY_MAP.hasOwnProperty(directive)) { 15376 value = DIRECTIVE_KEY_MAP[directive]; 15377 value = Number(offsetObject[value]); 15378 } 15379 if (value !== null) { 15380 if (modifier === "!") { 15381
15381 value = pluralize(plural, value); 15382 } 15383 if (modifier === "") { 15384 if (value < 10) { 15385 value = "0" + value.toString(); 15386 } 15387 } 15388 format = format.replace(regexp, value.toString()); 15389 } 15390 } 15391 } 15392 format = format.replace(/%%/, "%"); 15393 return format; 15394 }; 15395 } 15396 function pluralize(format, count) { 15397 var plural = "s", singular = ""; 15398 if (format) { 15399 format = format.replace(/(:|;|\s)/gi, "").split(/\,/); 15400 if (format.length === 1) { 15401 plural = format[0]; 15402 } else { 15403 singular = format[0]; 15404 plural = format[1]; 15405 } 15406 } 15407 if (Math.abs(count) === 1) { 15408 return singular; 15409 } else { 15410 return plural; 15411 } 15412 } 15413 var Countdown = function(el, finalDate, callback) { 15414 this.el = el; 15415 this.$el = $(el); 15416 this.interval = null; 15417 this.offset = {}; 15418 this.instanceNumber = instances.length; 15419 instances.push(this); 15420 this.$el.data("countdown-instance", this.instanceNumber); 15421 if (callback) { 15422 this.$el.on("update.countdown", callback); 15423 this.$el.on("stoped.countdown", callback); 15424 this.$el.on("finish.countdown", callback); 15425 } 15426 this.setFinalDate(finalDate); 15427 this.start(); 15428 }; 15429 $.extend(Countdown.prototype, { 15430 start: function() { 15431 if (this.interval !== null) { 15432 clearInterval(this.interval); 15433 } 15434 var self = this; 15435 this.update(); 15436 this.interval = setInterval(function() { 15437 self.update.call(self); 15438 }, PRECISION); 15439 }, 15440 stop: function() { 15441 clearInterval(this.interval); 15442 this.interval = null; 15443 this.dispatchEvent("stoped"); 15444 }, 15445 pause: function() { 15446 this.stop.call(this); 15447 }, 15448 resume: function() { 15449 this.start.call(this); 15450 }, 15451 remove: function() { 15452 this.stop(); 15453 instances[this.instanceNumber] = null; 15454 delete this.$el.data().countdownInstance; 15455 }, 15456 setFinalDate: function(value) { 15457 this.finalDate = parseDateString(value); 15458 }, 15459 update: function() { 15460 if (this.$el.closest("html").length === 0) { 15461 this.remove(); 15462 return; 15463 } 15464 this.totalSecsLeft = this.finalDate.getTime() - new Date().getTime(); 15465 this.totalSecsLeft = Math.ceil(this.totalSecsLeft / 1e3); 15466 this.totalSecsLeft = this.totalSecsLeft < 0 ? 0 : this.totalSecsLeft; 15467 this.offset = { 15468 seconds: this.totalSecsLeft % 60, 15469 minutes: Math.floor(this.totalSecsLeft / 60) % 60, 15470 hours: Math.floor(this.totalSecsLeft / 60 / 60) % 24, 15471 days: Math.floor(this.totalSecsLeft / 60 / 60 / 24) % 7, 15472 totalDays: Math.floor(this.totalSecsLeft / 60 / 60 / 24), 15473 weeks: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 7), 15474 months: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 30), 15475 years: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 365) 15476 }; 15477 if (this.totalSecsLeft === 0) { 15478 this.stop(); 15479 this.dispatchEvent("finish"); 15480 } else { 15481 this.dispatchEvent("update"); 15482 } 15483 }, 15484 dispatchEvent: function(eventName) { 15485 var event = $.Event(eventName + ".countdown"); 15486 event.finalDate = this.finalDate; 15487 event.offset = $.extend({}, this.offset); 15488 event.strftime = strftime(this.offset); 15489 this.$el.trigger(event); 15490 } 15491 }); 15492 $.fn.countdown = function() { 15493 var argumentsArray = Array.prototype.slice.call(arguments, 0); 15494 return this.each(function() {
15495 var instanceNumber = $(this).data("countdown-instance"); 15496 if (instanceNumber !== undefined) { 15497 var instance = instances[instanceNumber], method = argumentsArray[0]; 15498 if (Countdown.prototype.hasOwnProperty(method)) { 15499 instance[method].apply(instance, argumentsArray.slice(1)); 15500 } else if (String(method).match(/^[$A-Z_][0-9A-Z_$]*$/i) === null) { 15501 instance.setFinalDate.call(instance, method); 15502 instance.start(); 15503 } else { 15504 $.error("Method %s does not exist on jQuery.countdown".replace(/\%s/gi, method)); 15505 } 15506 } else { 15507 new Countdown(this, argumentsArray[0], argumentsArray[1]); 15508 } 15509 }); 15510 }; 15511}); 15512 15513/*! waitForImages jQuery Plugin - v2.0.2 - 2015-05-05 15514* https://github.com/alexanderdickson/waitForImages 15515* Copyright (c) 2015 Alex Dickson; Licensed MIT */ 15516;(function (factory) { 15517 if (typeof define === 'function' && define.amd) { 15518 // AMD. Register as an anonymous module. 15519 define(['jquery'], factory); 15520 } else if (typeof exports === 'object') { 15521 // CommonJS / nodejs module 15522 module.exports = factory(require('jquery')); 15523 } else { 15524 // Browser globals 15525 factory(jQuery); 15526 } 15527}(function ($) { 15528 // Namespace all events. 15529 var eventNamespace = 'waitForImages'; 15530 15531 // CSS properties which contain references to images. 15532 $.waitForImages = { 15533 hasImageProperties: [ 15534 'backgroundImage', 15535 'listStyleImage', 15536 'borderImage', 15537 'borderCornerImage', 15538 'cursor' 15539 ], 15540 hasImageAttributes: ['srcset'] 15541 }; 15542 15543 // Custom selector to find `img` elements that have a valid `src` 15544 // attribute and have not already loaded. 15545 $.expr[':'].uncached = function (obj) { 15546 // Ensure we are dealing with an `img` element with a valid 15547 // `src` attribute. 15548 if (!$(obj).is('img[src][src!=""]')) { 15549 return false; 15550 } 15551 15552 return !obj.complete; 15553 }; 15554 15555 $.fn.waitForImages = function () { 15556 15557 var allImgsLength = 0; 15558 var allImgsLoaded = 0; 15559 var deferred = $.Deferred(); 15560 15561 var finishedCallback; 15562 var eachCallback; 15563 var waitForAll; 15564 15565 // Handle options object (if passed). 15566 if ($.isPlainObject(arguments[0])) { 15567 15568 waitForAll = arguments[0].waitForAll; 15569 eachCallback = arguments[0].each; 15570 finishedCallback = arguments[0].finished; 15571 15572 } else { 15573 15574 // Handle if using deferred object and only one param was passed in. 15575 if (arguments.length === 1 && $.type(arguments[0]) === 'boolean') { 15576 waitForAll = arguments[0]; 15577 } else { 15578 finishedCallback = arguments[0]; 15579 eachCallback = arguments[1]; 15580 waitForAll = arguments[2]; 15581 } 15582 15583 } 15584 15585 // Handle missing callbacks. 15586 finishedCallback = finishedCallback || $.noop; 15587 eachCallback = eachCallback || $.noop; 15588 15589 // Convert waitForAll to Boolean 15590 waitForAll = !! waitForAll; 15591 15592 // Ensure callbacks are functions. 15593 if (!$.isFunction(finishedCallback) || !$.isFunction(eachCallback)) { 15594 throw new TypeError('An invalid callback was supplied.'); 15595 } 15596 15597 this.each(function () { 15598 // Build a list of all imgs, dependent on what images will 15599 // be considered. 15600 var obj = $(this); 15601 var allImgs = []; 15602 // CSS properties which may contain an image. 15603 var hasImgProperties = $.waitForImages.hasImageProperties || []; 15604 // Element attributes which may contain an image. 15605 var hasImageAttributes = $.waitForImages.hasImageAttributes || []; 15606 // To match `url()` references. 15607 // Spec: http://www.w3.org/TR/CSS2/syndata.html#value-def-uri 15608 var matchUrl = /url\(\s*(['"]?)(.*?)\1\s*\)/g; 15609 15610 if (waitForAll) { 15611 15612 // Get all elements (including the original), as any one of 15613 // them could have a background image. 15614 obj.find('*').addBack().each(function () { 15615 var element = $(this); 15616 15617 // If an `img` element, add it. But keep iterating in 15618 // case it has a background image too. 15619 if (element.is('img:uncached')) { 15620 allImgs.push({ 15621 src: element.attr('src'), 15622 element: element[0] 15623 }); 15624 } 15625 15626 $.each(hasImgProperties, function (i, property) { 15627 var propertyValue = element.css(property); 15628 var match; 15629 15630 // If it doesn't contain this property, skip. 15631 if (!propertyValue) { 15632 return true; 15633 } 15634 15635 // Get all url() of this element. 15636 while (match = matchUrl.exec(propertyValue)) { 15637 allImgs.push({ 15638 src: match[2], 15639 element: element[0] 15640 }); 15641 } 15642 }); 15643 15644 $.each(hasImageAttributes, function (i, attribute) { 15645 var attributeValue = element.attr(attribute); 15646 var attributeValues; 15647 15648 // If it doesn't contain this property, skip. 15649 if (!attributeValue) { 15650 return true; 15651 } 15652 15653 // Check for multiple comma separated images 15654 attributeValues = attributeValue.split(','); 15655 15656 $.each(attributeValues, function(i, value) { 15657 // Trim value and get string before first 15658 // whitespace (for use with srcset). 15659 value = $.trim(value).split(' ')[0]; 15660 allImgs.push({ 15661 src: value, 15662 element: element[0] 15663 }); 15664 }); 15665 }); 15666 }); 15667 } else { 15668 // For images only, the task is simpler. 15669 obj.find('img:uncached') 15670 .each(function () { 15671 allImgs.push({ 15672 src: this.src, 15673 element: this 15674 }); 15675 }); 15676 } 15677 15678 allImgsLength = allImgs.length; 15679 allImgsLoaded = 0; 15680 15681 // If no images found, don't bother. 15682 if (allImgsLength === 0) { 15683 finishedCallback.call(obj[0]); 15684 deferred.resolveWith(obj[0]); 15685 } 15686 15687 $.each(allImgs, function (i, img) { 15688 15689 var image = new Image(); 15690 var events = 15691 'load.' + eventNamespace + ' error.' + eventNamespace; 15692 15693 // Handle the image loading and error with the same callback. 15694 $(image).one(events, function me (event) { 15695 // If an error occurred with loading the image, set the 15696 // third argument accordingly. 15697 var eachArguments = [ 15698 allImgsLoaded, 15699 allImgsLength,
15700 event.type == 'load' 15701 ]; 15702 allImgsLoaded++; 15703 15704 eachCallback.apply(img.element, eachArguments); 15705 deferred.notifyWith(img.element, eachArguments); 15706 15707 // Unbind the event listeners. I use this in addition to 15708 // `one` as one of those events won't be called (either 15709 // 'load' or 'error' will be called). 15710 $(this).off(events, me); 15711 15712 if (allImgsLoaded == allImgsLength) { 15713 finishedCallback.call(obj[0]); 15714 deferred.resolveWith(obj[0]); 15715 return false; 15716 } 15717 15718 }); 15719 15720 image.src = img.src; 15721 }); 15722 }); 15723 15724 return deferred.promise(); 15725 15726 }; 15727})); 15728 15729/** 15730 * @preserve textfill 15731 * @name jquery.textfill.js 15732 * @author Russ Painter 15733 * @author Yu-Jie Lin 15734 * @author Alexandre Dantas 15735 * @version 0.6.0 15736 * @date 2014-08-19 15737 * @copyright (c) 2014 Alexandre Dantas 15738 * @copyright (c) 2012-2013 Yu-Jie Lin 15739 * @copyright (c) 2009 Russ Painter 15740 * @license MIT License 15741 * @homepage https://github.com/jquery-textfill/jquery-textfill 15742 * @example http://jquery-textfill.github.io/jquery-textfill/index.html 15743 */ 15744; (function($) { 15745 15746 /** 15747 * Resizes an inner element's font so that the 15748 * inner element completely fills the outer element. 15749 * 15750 * @param {Object} options User options that take 15751 * higher precedence when 15752 * merging with the default ones. 15753 * 15754 * @return All outer elements processed 15755 */ 15756 $.fn.textfill = function(options) { 15757 15758 // ______ _______ _______ _______ _ _ _______ _______ 15759 // | \ |______ |______ |_____| | | | | |______ 15760 // |_____/ |______ | | | |_____| |_____ | ______| 15761 // 15762 // Merging user options with the default values 15763 15764 var defaults = { 15765 debug : false, 15766 maxFontPixels : 40, 15767 minFontPixels : 4, 15768 innerTag : 'span', 15769 widthOnly : false, 15770 success : null, // callback when a resizing is done 15771 callback : null, // callback when a resizing is done (deprecated, use success) 15772 fail : null, // callback when a resizing is failed 15773 complete : null, // callback when all is done 15774 explicitWidth : null, 15775 explicitHeight : null, 15776 changeLineHeight : false 15777 }; 15778 15779 var Opts = $.extend(defaults, options); 15780 15781 // _______ _ _ __ _ _______ _______ _____ _____ __ _ _______ 15782 // |______ | | | \ | | | | | | | \ | |______ 15783 // | |_____| | \_| |_____ | __|__ |_____| | \_| ______| 15784 // 15785 // Predefining the awesomeness 15786 15787 // Output arguments to the Debug console 15788 // if "Debug Mode" is enabled 15789 function _debug() { 15790 if (!Opts.debug 15791 || typeof console == 'undefined' 15792 || typeof console.debug == 'undefined') { 15793 return; 15794 } 15795 console.debug.apply(console, arguments); 15796 } 15797 15798 // Output arguments to the Warning console 15799 function _warn() { 15800 if (typeof console == 'undefined' || 15801 typeof console.warn == 'undefined') { 15802 return; 15803 } 15804 console.warn.apply(console, arguments); 15805 } 15806 15807 // Outputs all information on the current sizing 15808 // of the font. 15809 function _debug_sizing(prefix, ourText, maxHeight, maxWidth, minFontPixels, maxFontPixels) { 15810 15811 function _m(v1, v2) { 15812 15813 var marker = ' / '; 15814 15815 if (v1 > v2) 15816 marker = ' > '; 15817 15818 else if (v1 == v2) 15819 marker = ' = '; 15820 15821 return marker; 15822 } 15823 15824 _debug( 15825 '[TextFill] ' + prefix + ' { ' + 15826 'font-size: ' + ourText.css('font-size') + ',' +
15827 'Height: ' + ourText.height() + 'px ' + _m(ourText.height(), maxHeight) + maxHeight + 'px,' + 15828 'Width: ' + ourText.width() + _m(ourText.width() , maxWidth) + maxWidth + ',' + 15829 'minFontPixels: ' + minFontPixels + 'px, ' + 15830 'maxFontPixels: ' + maxFontPixels + 'px }' 15831 ); 15832 } 15833 15834 /** 15835 * Calculates which size the font can get resized, 15836 * according to constrains. 15837 * 15838 * @param {String} prefix Gets shown on the console before 15839 * all the arguments, if debug mode is on. 15840 * @param {Object} ourText The DOM element to resize, 15841 * that contains the text. 15842 * @param {function} func Function called on `ourText` that's 15843 * used to compare with `max`. 15844 * @param {number} max Maximum value, that gets compared with 15845 * `func` called on `ourText`. 15846 * @param {number} minFontPixels Minimum value the font can 15847 * get resized to (in pixels). 15848 * @param {number} maxFontPixels Maximum value the font can 15849 * get resized to (in pixels). 15850 * 15851 * @return Size (in pixels) that the font can be resized. 15852 */ 15853 function _sizing(prefix, ourText, func, max, maxHeight, maxWidth, minFontPixels, maxFontPixels) { 15854 15855 _debug_sizing( 15856 prefix, ourText, 15857 maxHeight, maxWidth, 15858 minFontPixels, maxFontPixels 15859 ); 15860 15861 // The kernel of the whole plugin, take most attention 15862 // on this part. 15863 // 15864 // This is a loop that keeps increasing the `font-size` 15865 // until it fits the parent element. 15866 // 15867 // - Start from the minimal allowed value (`minFontPixels`) 15868 // - Guesses an average font size (in pixels) for the font, 15869 // - Resizes the text and sees if its size is within the 15870 // boundaries (`minFontPixels` and `maxFontPixels`). 15871 // - If so, keep guessing until we break. 15872 // - If not, return the last calculated size. 15873 // 15874 // I understand this is not optimized and we should 15875 // consider implementing something akin to 15876 // Daniel Hoffmann's answer here: 15877 // 15878 // http://stackoverflow.com/a/17433451/1094964 15879 // 15880 15881 while (minFontPixels < (maxFontPixels - 1)) { 15882 15883 var fontSize = Math.floor((minFontPixels + maxFontPixels) / 2); 15884 ourText.css('font-size', fontSize); 15885 15886 if (func.call(ourText) <= max) { 15887 minFontPixels = fontSize; 15888 15889 if (func.call(ourText) == max) 15890 break; 15891 } 15892 else 15893 maxFontPixels = fontSize; 15894 15895 _debug_sizing( 15896 prefix, ourText, 15897 maxHeight, maxWidth, 15898 minFontPixels, maxFontPixels 15899 ); 15900 } 15901 15902 ourText.css('font-size', maxFontPixels); 15903 15904 if (func.call(ourText) <= max) { 15905 minFontPixels = maxFontPixels; 15906 15907 _debug_sizing( 15908 prefix + '* ', ourText, 15909 maxHeight, maxWidth, 15910 minFontPixels, maxFontPixels 15911 ); 15912 } 15913 return minFontPixels; 15914 } 15915 15916 // _______ _______ _______ ______ _______ 15917 // |______ | |_____| |_____/ | 15918 // ______| | | | | \_ | 15919 // 15920 // Let's get it started (yeah)! 15921 15922 _debug('[TextFill] Start Debug'); 15923 15924 this.each(function() { 15925 15926 // Contains the child element we will resize. 15927 // $(this) means the parent container 15928 var ourText = $(Opts.innerTag + ':visible:first', this); 15929 15930 // Will resize to this dimensions. 15931 // Use explicit dimensions when specified 15932 var maxHeight = Opts.explicitHeight || $(this).height(); 15933 var maxWidth = Opts.explicitWidth || $(this).width(); 15934 15935 var oldFontSize = ourText.css('font-size'); 15936 15937 var lineHeight = parseFloat(ourText.css('line-height')) / parseFloat(oldFontSize); 15938 15939 _debug('[TextFill] Inner text: ' + ourText.text()); 15940 _debug('[TextFill] All options: ', Opts); 15941 _debug('[TextFill] Maximum sizes: { ' + 15942 'Height: ' + maxHeight + 'px, ' + 15943 'Width: ' + maxWidth + 'px' + ' }' 15944 ); 15945 15946 var minFontPixels = Opts.minFontPixels; 15947 15948 // Remember, if this `maxFontPixels` is negative, 15949 // the text will resize to as long as the container 15950 // can accomodate 15951 var maxFontPixels = (Opts.maxFontPixels <= 0 ? 15952 maxHeight : 15953 Opts.maxFontPixels); 15954 15955 15956 // Let's start it all! 15957 15958 // 1. Calculate which `font-size` would 15959 // be best for the Height 15960 var fontSizeHeight = undefined; 15961 15962 if (! Opts.widthOnly) 15963 fontSizeHeight = _sizing( 15964 'Height', ourText, 15965 $.fn.height, maxHeight, 15966 maxHeight, maxWidth, 15967 minFontPixels, maxFontPixels 15968 ); 15969 15970 // 2. Calculate which `font-size` would 15971 // be best for the Width 15972 var fontSizeWidth = undefined; 15973 15974 fontSizeWidth = _sizing( 15975 'Width', ourText, 15976 $.fn.width, maxWidth, 15977 maxHeight, maxWidth, 15978 minFontPixels, maxFontPixels 15979 ); 15980 15981 // 3. Actually resize the text! 15982 15983 if (Opts.widthOnly) { 15984 ourText.css({ 15985 'font-size' : fontSizeWidth, 15986 'white-space': 'nowrap' 15987 }); 15988 15989 if (Opts.changeLineHeight) 15990 ourText.parent().css( 15991 'line-height', 15992 (lineHeight * fontSizeWidth + 'px') 15993 ); 15994 } 15995 else { 15996 var fontSizeFinal = Math.min(fontSizeHeight, fontSizeWidth); 15997 15998 ourText.css('font-size', fontSizeFinal); 15999 16000 if (Opts.changeLineHeight) 16001 ourText.parent().css( 16002 'line-height', 16003 (lineHeight * fontSizeFinal) + 'px' 16004 ); 16005 } 16006 16007 _debug( 16008 '[TextFill] Finished { ' + 16009 'Old font-size: ' + oldFontSize + ', ' + 16010 'New font-size: ' + ourText.css('font-size') + ' }' 16011 ); 16012 16013 // Oops, something wrong happened! 16014 // We weren't supposed to exceed the original size 16015 if ((ourText.width() > maxWidth) ||
16016 (ourText.height() > maxHeight && !Opts.widthOnly)) { 16017 16018 ourText.css('font-size', oldFontSize); 16019 16020 // Failure callback 16021 if (Opts.fail) 16022 Opts.fail(this); 16023 16024 _debug( 16025 '[TextFill] Failure { ' + 16026 'Current Width: ' + ourText.width() + ', ' + 16027 'Maximum Width: ' + maxWidth + ', ' + 16028 'Current Height: ' + ourText.height() + ', ' + 16029 'Maximum Height: ' + maxHeight + ' }' 16030 ); 16031 } 16032 else if (Opts.success) { 16033 Opts.success(this); 16034 } 16035 else if (Opts.callback) { 16036 _warn('callback is deprecated, use success, instead'); 16037 16038 // Success callback 16039 Opts.callback(this); 16040 } 16041 }); 16042 16043 // Complete callback 16044 if (Opts.complete) 16045 Opts.complete(this); 16046 16047 _debug('[TextFill] End Debug'); 16048 return this; 16049 }; 16050 16051})(window.jQuery); 16052 16053!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; 16054function getStyles(config){ 16055 // 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;
16055left: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+"}" 16056}; 16057 var ShareUtils; 16058 16059if ((!("classList" in document.documentElement)) && Object.defineProperty && typeof HTMLElement !== "undefined") { 16060 Object.defineProperty(HTMLElement.prototype, "classList", { 16061 get: function() { 16062 var ret, self, update; 16063 update = function(fn) { 16064 return function(value) { 16065 var classes, index; 16066 classes = self.className.split(/\s+/); 16067 index = classes.indexOf(value); 16068 fn(classes, index, value); 16069 self.className = classes.join(" "); 16070 }; 16071 }; 16072 self = this; 16073 ret = { 16074 add: update(function(classes, index, value) { 16075 ~index || classes.push(value); 16076 }), 16077 remove: update(function(classes, index) { 16078 ~index && classes.splice(index, 1); 16079 }), 16080 toggle: update(function(classes, index, value) { 16081 if (~index) { 16082 classes.splice(index, 1); 16083 } else { 16084 classes.push(value); 16085 } 16086 }), 16087 contains: function(value) { 16088 return !!~self.className.split(/\s+/).indexOf(value); 16089 }, 16090 item: function(i) { 16091 return self.className.split(/\s+/)[i] || null; 16092 } 16093 }; 16094 Object.defineProperty(ret, "length", { 16095 get: function() { 16096 return self.className.split(/\s+/).length; 16097 } 16098 }); 16099 return ret; 16100 } 16101 }); 16102} 16103 16104String.prototype.to_rfc3986 = function() { 16105 var tmp; 16106 tmp = encodeURIComponent(this); 16107 return tmp.replace(/[!'()*]/g, function(c) { 16108 return "%" + c.charCodeAt(0).toString(16); 16109 }); 16110}; 16111 16112ShareUtils = (function() { 16113 function ShareUtils() {} 16114 16115 ShareUtils.prototype.extend = function(to, from, overwrite) { 16116 var hasProp, prop; 16117 for (prop in from) { 16118 hasProp = to[prop] !== undefined; 16119 if (hasProp && typeof from[prop] === "object") { 16120 this.extend(to[prop], from[prop], overwrite); 16121 } else { 16122 if (overwrite || !hasProp) { 16123 to[prop] = from[prop]; 16124 } 16125 } 16126 } 16127 }; 16128 16129 ShareUtils.prototype.hide = function(el) { 16130 return el.style.display = "none"; 16131 }; 16132 16133 ShareUtils.prototype.show = function(el) { 16134 return el.style.display = "block"; 16135 }; 16136 16137 ShareUtils.prototype.has_class = function(el, class_name) { 16138 return el.classList.contains(class_name); 16139 }; 16140 16141 ShareUtils.prototype.add_class = function(el, class_name) { 16142 return el.classList.add(class_name); 16143 }; 16144 16145 ShareUtils.prototype.remove_class = function(el, class_name) { 16146 return el.classList.remove(class_name); 16147 }; 16148 16149 ShareUtils.prototype.is_encoded = function(str) { 16150 str = str.to_rfc3986(); 16151 return decodeURIComponent(str) !== str; 16152 }; 16153 16154 ShareUtils.prototype.encode = function(str) { 16155 if (typeof str === "undefined" || this.is_encoded(str)) { 16156 return str; 16157 } else { 16158 return str.to_rfc3986(); 16159 } 16160 }; 16161 16162 ShareUtils.prototype.popup = function(url, params) { 16163 var k, popup, qs, v; 16164 if (params == null) { 16165 params = {}; 16166 } 16167 popup = { 16168 width: 500, 16169 height: 350 16170 }; 16171 popup.top = (screen.height / 2) - (popup.height / 2); 16172 popup.left = (screen.width / 2) - (popup.width / 2); 16173 qs = ((function() { 16174 var _results; 16175 _results = []; 16176 for (k in params) { 16177 v = params[k]; 16178 _results.push("" + k + "=" + (this.encode(v))); 16179 } 16180 return _results; 16181 }).call(this)).join('&'); 16182 if (qs) { 16183 qs = "?" + qs; 16184 } 16185 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="
16185+ popup.width + ",height=" + popup.height); 16186 }; 16187 16188 return ShareUtils; 16189 16190})(); 16191var Share, 16192 __hasProp = {}.hasOwnProperty, 16193 __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; }; 16194 16195Share = (function(_super) { 16196 __extends(Share, _super); 16197 16198 function Share(element, options) { 16199 this.element = element; 16200 this.el = { 16201 head: document.getElementsByTagName('head')[0], 16202 body: document.getElementsByTagName('body')[0] 16203 }; 16204 this.config = { 16205 enabled_networks: 0, 16206 protocol: ['http', 'https'].indexOf(window.location.href.split(':')[0]) === -1 ? 'https://' : '//', 16207 url: window.location.href.replace("&", "%26"), 16208 caption: null, 16209 title: this.default_title(), 16210 image: this.default_image(), 16211 description: this.default_description(), 16212 ui: { 16213 flyout: 'top center', 16214 button_text: 'Share', 16215 button_font: true, 16216 icon_font: true 16217 }, 16218 networks: { 16219 google_plus: { 16220 enabled: true, 16221 url: null 16222 }, 16223 twitter: { 16224 enabled: true, 16225 url: null, 16226 title: null, 16227 description: null 16228 }, 16229 facebook: { 16230 enabled: true, 16231 load_sdk: true, 16232 url: null, 16233 app_id: null, 16234 title: null, 16235 caption: null, 16236 description: null, 16237 image: null 16238 }, 16239 pinterest: { 16240 enabled: true, 16241 url: null, 16242 image: null, 16243 description: null 16244 }, 16245 reddit: { 16246 enabled: true, 16247 url: null, 16248 title: null 16249 }, 16250 linkedin: { 16251 enabled: true, 16252 url: null, 16253 title: null, 16254 description: null 16255 }, 16256 xing: { 16257 enabled: true, 16258 url: null, 16259 title: null, 16260 image: null, 16261 description: null 16262 }, 16263 whatsapp: { 16264 enabled: true, 16265 description: null, 16266 url: null 16267 }, 16268 email: { 16269 enabled: true, 16270 title: null, 16271 description: null, 16272 url: null 16273 } 16274 } 16275 }; 16276 this.setup(element, options); 16277 return this; 16278 } 16279 16280 Share.prototype.setup = function(element, opts) { 16281 var index, instance, instances, _i, _len; 16282 instances = document.querySelectorAll(element); 16283 this.extend(this.config, opts, true); 16284 this.set_global_configuration(); 16285 this.normalize_network_configuration(); 16286 if (this.config.ui.icon_font) { 16287 this.inject_icons(); 16288 } 16289 if (this.config.ui.button_font) { 16290 this.inject_fonts(); 16291 } 16292 if (this.config.networks.facebook.enabled && this.config.networks.facebook.load_sdk) { 16293 this.inject_facebook_sdk(); 16294 } 16295 for (index = _i = 0, _len = instances.length; _i < _len; index = ++_i) { 16296 instance = instances[index]; 16297 this.setup_instance(element, index); 16298 } 16299 }; 16300 16301 Share.prototype.setup_instance = function(element, index) { 16302 var button, instance, label, network, networks, _i, _len, _results, 16303 _this = this; 16304 instance = document.querySelectorAll(element)[index]; 16305 this.hide(instance); 16306 this.add_class(instance, "sharer-" + index); 16307 instance = document.querySelectorAll(element)[index]; 16308 this.inject_css(instance); 16309 this.inject_html(instance); 16310 this.show(instance); 16311 label = instance.getElementsByTagName("label")[0]; 16312 button = instance.getElementsByClassName("social")[0]; 16313 networks = instance.getElementsByTagName('li'); 16314 this.add_class(button, "networks-" + this.config.enabled_networks); 16315 label.addEventListener("click", function() { 16316 return _this.event_toggle(button); 16317 }); 16318 _this = this; 16319 _results = []; 16320 for (index = _i = 0, _len = networks.length; _i < _len; index = ++_i) { 16321 network = networks[index]; 16322 _results.push(network.addEventListener("click", function() { 16323 _this.event_network(instance, this); 16324 return _this.event_close(button); 16325 })); 16326 } 16327 return _results; 16328 }; 16329 16330 Share.prototype.event_toggle = function(button) { 16331 if (this.has_class(button, "active")) { 16332 return this.event_close(button); 16333 } else { 16334 return this.event_open(button); 16335 } 16336 }; 16337 16338 Share.prototype.event_open = function(button) { 16339 if (this.has_class(button, "load")) { 16340 this.remove_class(button, "load"); 16341 } 16342 return this.add_class(button, "active"); 16343 }; 16344 16345 Share.prototype.event_close = function(button) { 16346 return this.remove_class(button, "active"); 16347 }; 16348 16349 Share.prototype.event_network = function(instance, network) { 16350 var name; 16351 name = network.getAttribute("data-network"); 16352 this.hook("before", name, instance);
16353 this["network_" + name](); 16354 return this.hook("after", name, instance); 16355 }; 16356 16357 Share.prototype.open = function() { 16358 return this["public"]("open"); 16359 }; 16360 16361 Share.prototype.close = function() { 16362 return this["public"]("close"); 16363 }; 16364 16365 Share.prototype.toggle = function() { 16366 return this["public"]("toggle"); 16367 }; 16368 16369 Share.prototype["public"] = function(action) { 16370 var button, index, instance, _i, _len, _ref, _results; 16371 _ref = document.querySelectorAll(this.element); 16372 _results = []; 16373 for (index = _i = 0, _len = _ref.length; _i < _len; index = ++_i) { 16374 instance = _ref[index]; 16375 button = instance.getElementsByClassName("social")[0]; 16376 _results.push(this["event_" + action](button)); 16377 } 16378 return _results; 16379 }; 16380 16381 Share.prototype.network_facebook = function() { 16382 if (this.config.networks.facebook.load_sdk) { 16383 if (!window.FB) { 16384 return console.error("The Facebook JS SDK hasn't loaded yet."); 16385 } 16386 return FB.ui({ 16387 method: 'feed', 16388 name: this.config.networks.facebook.title, 16389 link: this.config.networks.facebook.url, 16390 picture: this.config.networks.facebook.image, 16391 caption: this.config.networks.facebook.caption, 16392 description: this.config.networks.facebook.description 16393 }); 16394 } else { 16395 return this.popup('https://www.facebook.com/sharer/sharer.php', { 16396 u: this.config.networks.facebook.url 16397 }); 16398 } 16399 }; 16400 16401 Share.prototype.network_twitter = function() { 16402 return this.popup('https://twitter.com/intent/tweet', { 16403 text: this.config.networks.twitter.title, 16404 url: this.config.networks.twitter.url 16405 }); 16406 }; 16407 16408 Share.prototype.network_google_plus = function() { 16409 return this.popup('https://plus.google.com/share', { 16410 url: this.config.networks.google_plus.url 16411 }); 16412 }; 16413 16414 Share.prototype.network_pinterest = function() { 16415 return this.popup('https://www.pinterest.com/pin/create/button', { 16416 url: this.config.networks.pinterest.url, 16417 media: this.config.networks.pinterest.image, 16418 description: this.config.networks.pinterest.description 16419 }); 16420 }; 16421 16422 Share.prototype.network_linkedin = function() { 16423 return this.popup('https://www.linkedin.com/shareArticle', { 16424 url: this.config.networks.linkedin.url, 16425 title: this.config.networks.linkedin.title, 16426 summary: this.config.networks.linkedin.description 16427 }); 16428 } 16429 16430 Share.prototype.network_xing = function() { 16431 return this.popup('https://www.xing.com/spi/shares/new', { 16432 url: this.config.networks.xing.url, 16433 image: this.config.networks.xing.image, 16434 title: this.config.networks.xing.title, 16435 summary: this.config.networks.xing.description 16436 }); 16437 } 16438 16439 Share.prototype.network_email = function() { 16440 return this.popup('mailto:', { 16441 subject: this.config.networks.email.title, 16442 body: this.config.networks.email.url + '%0A%0A' + this.config.networks.email.description, 16443 }); 16444 }; 16445 16446 Share.prototype.inject_icons = function() { 16447 // return this.inject_stylesheet("https://www.sharebutton.co/fonts/v2/entypo.min.css"); 16448 }; 16449 16450 Share.prototype.inject_fonts = function() { 16451 // return this.inject_stylesheet("http://fonts.googleapis.com/css?family=Lato:900&text=" + this.config.ui.button_text); 16452 }; 16453 16454 Share.prototype.inject_stylesheet = function(url) { 16455 var link; 16456 if (!this.el.head.querySelector("link[href=\"" + url + "\"]")) { 16457 link = document.createElement("link"); 16458 link.setAttribute("rel", "stylesheet"); 16459 link.setAttribute("href", url); 16460 return this.el.head.appendChild(link); 16461 } 16462 }; 16463 16464 Share.prototype.inject_css = function(instance) { 16465 var css, meta, selector, style; 16466 selector = "." + (instance.getAttribute('class').split(" ").join(".")); 16467 if (!this.el.head.querySelector("meta[name='sharer" + selector + "']")) { 16468 this.config.selector = selector; 16469 css = getStyles(this.config); 16470 style = document.createElement("style"); 16471 style.type = "text/css"; 16472 if (style.styleSheet) { 16473 style.styleSheet.cssText = css; 16474 } else { 16475 style.appendChild(document.createTextNode(css)); 16476 } 16477 this.el.head.appendChild(style); 16478 delete this.config.selector; 16479 meta = document.createElement("meta"); 16480 meta.setAttribute("name", "sharer" + selector); 16481 return this.el.head.appendChild(meta); 16482 } 16483 }; 16484 16485 Share.prototype.inject_html = function(instance) { 16486 //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>"; 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-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 }; 16489 16490 Share.prototype.inject_facebook_sdk = function() { 16491 var fb_root, script; 16492 if (!window.FB && this.config.networks.facebook.app_id && !this.el.body.querySelector('#fb-root')) { 16493 script = document.createElement("script"); 16494 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')"; 16495 fb_root = document.createElement("div"); 16496 fb_root.id = "fb-root"; 16497 this.el.body.appendChild(fb_root); 16498 return this.el.body.appendChild(script); 16499 } 16500 }; 16501 16502 Share.prototype.hook = function(type, network, instance) { 16503 var fn, opts; 16504 fn = this.config.networks[network][type]; 16505 if (typeof fn === "function") { 16506 opts = fn.call(this.config.networks[network], instance); 16507 if (opts !== void 0) { 16508 opts = this.normalize_filter_config_updates(opts); 16509 this.extend(this.config.networks[network], opts, true); 16510 this.normalize_network_configuration(); 16511 } 16512 } 16513 }; 16514 16515 Share.prototype.default_title = function() { 16516 var content; 16517 if (content = document.querySelector('meta[property="og:title"]') || document.querySelector('meta[name="twitter:title"]')) { 16518 return encodeURIComponent(content.getAttribute('content')); 16519 } else if (content = document.querySelector('title')) { 16520 return encodeURIComponent(content.innerText); 16521 } 16522 }; 16523 16524 Share.prototype.default_image = function() { 16525 var content; 16526 if (content = document.querySelector('meta[property="og:image"]') || document.querySelector('meta[name="twitter:image"]')) { 16527 return content.getAttribute('content'); 16528 } 16529 }; 16530 16531 Share.prototype.default_description = function() { 16532 var content; 16533 if (content = document.querySelector('meta[property="og:description"]') || document.querySelector('meta[name="twitter:description"]') || document.querySelector('meta[name="description"]')) { 16534 return encodeURIComponent(content.getAttribute('content')); 16535 } else { 16536 return ''; 16537 } 16538 }; 16539 16540 Share.prototype.set_global_configuration = function() { 16541 var display, network, option, options, _ref, _results; 16542 _ref = this.config.networks; 16543 _results = []; 16544 for (network in _ref) { 16545 options = _ref[network]; 16546 for (option in options) { 16547 if (this.config.networks[network][option] == null) { 16548 this.config.networks[network][option] = this.config[option]; 16549 } 16550 } 16551 if (this.config.networks[network].enabled) { 16552 display = 'block'; 16553 this.config.enabled_networks += 1; 16554 } else { 16555 display = 'none'; 16556 } 16557 _results.push(this.config.networks[network].display = display); 16558 } 16559 return _results; 16560 }; 16561 16562 Share.prototype.normalize_network_configuration = function() { 16563 if (!this.config.networks.facebook.app_id) { 16564 this.config.networks.facebook.load_sdk = false;
16565 } 16566 if (!this.is_encoded(this.config.networks.twitter.description)) { 16567 this.config.networks.twitter.description = encodeURIComponent(this.config.networks.twitter.description); 16568 } 16569 if (typeof this.config.networks.facebook.app_id === 'number') { 16570 return this.config.networks.facebook.app_id = this.config.networks.facebook.app_id.toString(); 16571 } 16572 }; 16573 16574 Share.prototype.normalize_filter_config_updates = function(opts) { 16575 if (this.config.networks.facebook.app_id !== opts.app_id) { 16576 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."); 16577 delete opts.app_id; 16578 } 16579 if (this.config.networks.facebook.load_sdk !== opts.load_sdk) { 16580 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."); 16581 delete opts.app_id; 16582 } 16583 return opts; 16584 }; 16585 16586 return Share; 16587 16588})(ShareUtils); 16589 return Share; 16590}); 16591 16592// Generated by CoffeeScript 1.9.2 16593 16594// @license Sticky-kit v1.1.2 | WTFPL | Leaf Corcoran 2015 | http://leafo.net 16595 16596(function() { 16597 var $, win; 16598 16599 $ = this.jQuery || window.jQuery; 16600 16601 win = $(window); 16602 16603 $.fn.stick_in_parent = function(opts) { 16604 var doc, elm, enable_bottoming, fn, i, inner_scrolling, len, manual_spacer, offset_top, outer_width, parent_selector, recalc_every, sticky_class; 16605 if (opts == null) { 16606 opts = {}; 16607 } 16608 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; 16609 if (offset_top == null) { 16610 offset_top = 0; 16611 } 16612 if (parent_selector == null) { 16613 parent_selector = void 0; 16614 } 16615 if (inner_scrolling == null) { 16616 inner_scrolling = true; 16617 } 16618 if (sticky_class == null) { 16619 sticky_class = "is_stuck"; 16620 } 16621 doc = $(document); 16622 if (enable_bottoming == null) { 16623 enable_bottoming = true; 16624 } 16625 outer_width = function(el) { 16626 var _el, computed, w; 16627 if (window.getComputedStyle) { 16628 _el = el[0]; 16629 computed = window.getComputedStyle(el[0]); 16630 w = parseFloat(computed.getPropertyValue("width")) + parseFloat(computed.getPropertyValue("margin-left")) + parseFloat(computed.getPropertyValue("margin-right")); 16631 if (computed.getPropertyValue("box-sizing") !== "border-box") { 16632 w += parseFloat(computed.getPropertyValue("border-left-width")) + parseFloat(computed.getPropertyValue("border-right-width")) + parseFloat(computed.getPropertyValue("padding-left")) + parseFloat(computed.getPropertyValue("padding-right")); 16633 } 16634 return w; 16635 } else { 16636 return el.outerWidth(true); 16637 } 16638 }; 16639 fn = function(elm, padding_bottom, parent_top, parent_height, top, height, el_float, detached) { 16640 var bottomed, detach, fixed, last_pos, last_scroll_height, offset, parent, recalc, recalc_and_tick, recalc_counter, spacer, tick; 16641 if (elm.data("sticky_kit")) { 16642 return; 16643 } 16644 elm.data("sticky_kit", true); 16645 last_scroll_height = doc.height(); 16646 parent = elm.parent(); 16647 if (parent_selector != null) { 16648 parent = parent.closest(parent_selector); 16649 } 16650 if (!parent.length) { 16651 throw "failed to find stick parent"; 16652 } 16653 fixed = false; 16654 bottomed = false; 16655 spacer = manual_spacer != null ? manual_spacer && elm.closest(manual_spacer) : $("<div />"); 16656 if (spacer) { 16657 spacer.css('position', elm.css('position')); 16658 } 16659 recalc = function() { 16660 var border_top, padding_top, restore; 16661 if (detached) { 16662 return; 16663 } 16664 last_scroll_height = doc.height(); 16665 border_top = parseInt(parent.css("border-top-width"), 10); 16666 padding_top = parseInt(parent.css("padding-top"), 10); 16667 padding_bottom = parseInt(parent.css("padding-bottom"), 10); 16668 parent_top = parent.offset().top + border_top + padding_top; 16669 parent_height = parent.height(); 16670 if (fixed) { 16671 fixed = false;
vendor: 6,068 bytes, lines 16672-16866
16672 bottomed = false; 16673 if (manual_spacer == null) { 16674 elm.insertAfter(spacer); 16675 spacer.detach(); 16676 } 16677 elm.css({ 16678 position: "", 16679 top: "", 16680 width: "", 16681 bottom: "" 16682 }).removeClass(sticky_class); 16683 restore = true; 16684 } 16685 top = elm.offset().top - (parseInt(elm.css("margin-top"), 10) || 0) - offset_top; 16686 height = elm.outerHeight(true); 16687 el_float = elm.css("float"); 16688 if (spacer) { 16689 spacer.css({ 16690 width: outer_width(elm), 16691 height: height, 16692 display: elm.css("display"), 16693 "vertical-align": elm.css("vertical-align"), 16694 "float": el_float 16695 }); 16696 } 16697 if (restore) { 16698 return tick(); 16699 } 16700 }; 16701 recalc(); 16702 if (height === parent_height) { 16703 return; 16704 } 16705 last_pos = void 0; 16706 offset = offset_top; 16707 recalc_counter = recalc_every; 16708 tick = function() { 16709 var css, delta, recalced, scroll, will_bottom, win_height; 16710 if (detached) { 16711 return; 16712 } 16713 recalced = false; 16714 if (recalc_counter != null) { 16715 recalc_counter -= 1; 16716 if (recalc_counter <= 0) { 16717 recalc_counter = recalc_every; 16718 recalc(); 16719 recalced = true; 16720 } 16721 } 16722 if (!recalced && doc.height() !== last_scroll_height) { 16723 recalc(); 16724 recalced = true; 16725 } 16726 scroll = win.scrollTop(); 16727 if (last_pos != null) { 16728 delta = scroll - last_pos; 16729 } 16730 last_pos = scroll; 16731 if (fixed) { 16732 if (enable_bottoming) { 16733 will_bottom = scroll + height + offset > parent_height + parent_top; 16734 if (bottomed && !will_bottom) { 16735 bottomed = false; 16736 elm.css({ 16737 position: "fixed", 16738 bottom: "", 16739 top: offset 16740 }).trigger("sticky_kit:unbottom"); 16741 } 16742 } 16743 if (scroll < top) { 16744 fixed = false; 16745 offset = offset_top; 16746 if (manual_spacer == null) { 16747 if (el_float === "left" || el_float === "right") { 16748 elm.insertAfter(spacer); 16749 } 16750 spacer.detach(); 16751 } 16752 css = { 16753 position: "", 16754 width: "", 16755 top: "" 16756 }; 16757 elm.css(css).removeClass(sticky_class).trigger("sticky_kit:unstick"); 16758 } 16759 if (inner_scrolling) { 16760 win_height = win.height(); 16761 if (height + offset_top > win_height) { 16762 if (!bottomed) { 16763 offset -= delta; 16764 offset = Math.max(win_height - height, offset); 16765 offset = Math.min(offset_top, offset); 16766 if (fixed) { 16767 elm.css({ 16768 top: offset + "px" 16769 }); 16770 } 16771 } 16772 } 16773 } 16774 } else { 16775 if (scroll > top) { 16776 fixed = true; 16777 css = { 16778 position: "fixed", 16779 top: offset 16780 }; 16781 css.width = elm.css("box-sizing") === "border-box" ? elm.outerWidth() + "px" : elm.width() + "px"; 16782 elm.css(css).addClass(sticky_class); 16783 if (manual_spacer == null) { 16784 elm.after(spacer); 16785 if (el_float === "left" || el_float === "right") { 16786 spacer.append(elm); 16787 } 16788 } 16789 elm.trigger("sticky_kit:stick"); 16790 } 16791 } 16792 if (fixed && enable_bottoming) { 16793 if (will_bottom == null) { 16794 will_bottom = scroll + height + offset > parent_height + parent_top; 16795 } 16796 if (!bottomed && will_bottom) { 16797 bottomed = true; 16798 if (parent.css("position") === "static") { 16799 parent.css({ 16800 position: "relative" 16801 }); 16802 } 16803 return elm.css({ 16804 position: "absolute", 16805 bottom: padding_bottom, 16806 top: "auto" 16807 }).trigger("sticky_kit:bottom"); 16808 } 16809 } 16810 }; 16811 recalc_and_tick = function() { 16812 recalc(); 16813 return tick(); 16814 }; 16815 detach = function() { 16816 detached = true; 16817 win.off("touchmove", tick); 16818 win.off("scroll", tick); 16819 win.off("resize", recalc_and_tick); 16820 $(document.body).off("sticky_kit:recalc", recalc_and_tick); 16821 elm.off("sticky_kit:detach", detach); 16822 elm.removeData("sticky_kit"); 16823 elm.css({ 16824 position: "", 16825 bottom: "", 16826 top: "", 16827 width: "" 16828 }); 16829 parent.position("position", ""); 16830 if (fixed) { 16831 if (manual_spacer == null) { 16832 if (el_float === "left" || el_float === "right") { 16833 elm.insertAfter(spacer); 16834 } 16835 spacer.remove(); 16836 } 16837 return elm.removeClass(sticky_class); 16838 } 16839 }; 16840 win.on("touchmove", tick); 16841 win.on("scroll", tick); 16842 win.on("resize", recalc_and_tick); 16843 $(document.body).on("sticky_kit:recalc", recalc_and_tick); 16844 elm.on("sticky_kit:detach", detach); 16845 return setTimeout(tick, 0); 16846 }; 16847 for (i = 0, len = this.length; i < len; i++) { 16848 elm = this[i]; 16849 fn($(elm)); 16850 } 16851 return this; 16852 }; 16853 16854}).call(this); 16855/* ========================================================================== 16856 * bootstrap-tab-history.js 16857 * Author: Michael Narayan <[email protected]> 16858 * Repository: https://github.com/mnarayan01/bootstrap-tab-history/ 16859 * ========================================================================== 16860 * Licensed under the Apache License, Version 2.0 (the "License"); you may 16861 * not use this file except in compliance with the License. You may obtain a 16862 * copy of the License at 16863 * 16864 * http://www.apache.org/licenses/LICENSE-2.0 16865 * 16866 * Unless required by applicable law or agreed to in writing, softw
16866are 16867 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 16868 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 16869 * License for the specific language governing permissions and limitations 16870 * under the License. 16871 * ========================================================================== */ 16872 16873/* ========================================================================== */ 16874/* JSHint directives */ 16875/* */ 16876/* global BootstrapTabHistory: true */ 16877/* */ 16878/* global document */ 16879/* global jQuery */ 16880/* global history */ 16881/* global window */ 16882/* ========================================================================== */ 16883 16884/** 16885 * Integrate [HTML5 history state tracking](https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Manipulating_the_browser_history) 16886 * with [`bootstrap/tab.js`](http://getbootstrap.com/javascript/#tabs). To enable tracking on a tab element, simply set 16887 * the `data-tab-history` attribute to true (or a string denoting a tab grouping). 16888 * 16889 * See the README for additional information. 16890 * 16891 * Functionality based upon bootstrap/tab.js v3.1.0; reference it when making any changes. 16892 */ 16893 16894BootstrapTabHistory = { 16895 options: { 16896 /** 16897 * When the anchor portion of the URI is used to activate a tab, scroll down to the given offset, rather than the 16898 * element with the given `id` attribute. Set to null to disable. Only relevant if showTabsBasedOnAnchor is true. 16899 * 16900 * May be overriden on a per-element basis by the attribute `data-tab-history-anchor-y-offset`. 16901 * 16902 * @public 16903 * @type {?number} 16904 */ 16905 defaultAnchorYOffset: 0, 16906 /** 16907 * Either 'push' or 'replace', for whether to use `history.pushState` or `history.replaceState`, resp. 16908 * 16909 * May be overriden on a per-element basis by the attribute `data-tab-history-changer`. 16910 * 16911 * @public 16912 * @type {string} 16913 */ 16914 defaultChanger: 'replace', 16915 /** 16916 * If true, update the URL in onShownTab in the calls to `history.pushState` and `history.replaceState`. Otherwise, 16917 * `null` is passed as the third parameter to these calls. 16918 * 16919 * May be overriden on a per-element basis by the attribute `data-tab-history-update-url`. 16920 * 16921 * @public 16922 * @type {boolean} 16923 */ 16924 defaultUpdateURL: false, 16925 /** 16926 * Should the anchor portion of the loaded URI be used to activate a single tab if no history was present on page 16927 * load. 16928 * 16929 * @public 16930 * @type {boolean} 16931 */ 16932 showTabsBasedOnAnchor: true 16933 } 16934}; 16935 16936(function () { 16937 'use strict'; 16938 16939 jQuery(function () { 16940 if(history && history.pushState && history.replaceState) { 16941 var bootstrapTabHistory = history.state && history.state.bootstrapTabHistory; 16942 16943 if(bootstrapTabHistory) { 16944 showTabsBasedOnState(bootstrapTabHistory); 16945 } else { 16946 showTabsBasedOnAnchor(); 16947 } 16948 16949 backfillHistoryState(); 16950 16951 jQuery(document).on('shown.bs.tab show.bs.collapse', onShownTab); 16952 jQuery(window).on('popstate', onPopState); 16953 } else { 16954 showTabsBasedOnAnchor(); 16955 } 16956 }); 16957 16958 /** 16959 * Used to prevent onShownTab from registering shown events that we triggered via showTabsBasedOnState. 16960 * 16961 * @type {boolean} 16962 */ 16963 var showingTabsBasedOnState = false; 16964 16965 /** 16966 * Used to update `history.state` to reflect the default active tabs on initial page load. This supports proper 16967 * `history.back` handling when `data-tab-history-update-url` is true. 16968 */ 16969 function backfillHistoryState() { 16970 var newState = null; 16971 16972 jQuery('li.active > [data-tab-history], .panel-title.active [data-tab-history]').each(function () {//edited by Uncode 16973 var $activeTabElement = jQuery(this); 16974 var selector = getTabSelector($activeTabElement); 16975 16976 if(selector) { 16977 var tabGroup = getTabGroup($activeTabElement); 16978 16979 if(tabGroup) { 16980 newState = createNewHistoryState(newState || history.state, tabGroup, selector); 16981 } 16982 } 16983 }); 16984 16985 if(newState) { 16986 history.replaceState(newState, '', null); 16987 } 16988 } 16989 16990 /** 16991 * Clone the existing state, ensure its bootstrapTabHistory attribute is an Object, and add the provided tabGroup to 16992 * said bootstrapTabHistory attribute. 16993 * 16994 * @param {?object} existingState 16995 * @param {!string} tabGroup 16996 * @param {!string} selector 16997 * @returns {!object} 16998 */ 16999 function createNewHistoryState(existingState, tabGroup, selector) { 17000 // Clone history.state and ensure it has a bootstrapTabHistory entry. 17001 var newState = jQuery.extend(true, {}, existingState, { 17002 bootstrapTabHistory: {} 17003 }); 17004 17005 newState.bootstrapTabHistory[tabGroup] = selector; 17006 17007 return newState; 17008 } 17009 17010 /** 17011 * @param {jQuery} $tab
17012 * @returns {?string} 17013 */ 17014 function getTabGroup($tab) { 17015 return parseTruthyAttributeValue($tab.data('tab-history')); 17016 } 17017 17018 /** 17019 * @param {jQuery} $tab 17020 * @returns {?string} 17021 */ 17022 function getTabSelector($tab) { 17023 return $tab.data('target') || $tab.attr('href'); 17024 } 17025 17026 /** 17027 * Receives the `shown.bs.tab` event. Updates `history.state` as appropriate. 17028 * 17029 * @param {jQuery.Event} shownEvt 17030 */ 17031 function onShownTab(shownEvt) { 17032 if(!showingTabsBasedOnState) { 17033 var $activatedTab = jQuery(shownEvt.target); 17034 if ( $activatedTab.hasClass('panel-collapse') ) 17035 $activatedTab = $activatedTab.closest('.panel').find('a'); 17036 var selector = getTabSelector($activatedTab); 17037 17038 if(selector) { 17039 var tabGroup = getTabGroup($activatedTab); 17040 17041 if(tabGroup) { 17042 var historyChanger = $activatedTab.data('tab-history-changer') || BootstrapTabHistory.options.defaultChanger; 17043 var newState = createNewHistoryState(history.state, tabGroup, selector); 17044 var updateURL = (function ($activatedTab) { 17045 if(selector[0] === '#') { 17046 var elementUpdateURLOption = parseTruthyAttributeValue($activatedTab.data('tab-history-update-url')); 17047 17048 if(elementUpdateURLOption === undefined) { 17049 return BootstrapTabHistory.options.defaultUpdateURL; 17050 } else { 17051 return elementUpdateURLOption; 17052 } 17053 } else { 17054 return false; 17055 } 17056 })($activatedTab); 17057 17058 switch(historyChanger) { 17059 case 'push': 17060 history.pushState(newState, '', updateURL ? selector : null); 17061 break; 17062 case 'replace': 17063 history.replaceState(newState, '', updateURL ? selector : null); 17064 break; 17065 default: 17066 throw new Error('Unknown tab-history-changer: ' + historyChanger); 17067 } 17068 } 17069 } 17070 } 17071 } 17072 17073 /** 17074 * Receives the `popstate` event. Shows tabs based on the value of `history.state` as appropriate. 17075 */ 17076 function onPopState() { 17077 var bootstrapTabHistory = history.state && history.state.bootstrapTabHistory; 17078 17079 if(bootstrapTabHistory) { 17080 showTabsBasedOnState(bootstrapTabHistory); 17081 } 17082 } 17083 17084 /** 17085 * Returns the given value, _unless_ that value is an empty string, in which case `true` is returned. 17086 * 17087 * Rationale: HAML data attributes which are set to `true` are rendered as a blank string. 17088 * 17089 * @param {*} value 17090 * @returns {*} 17091 */ 17092 function parseTruthyAttributeValue(value) { 17093 if(value) { 17094 return value; 17095 } else if(value === '') { 17096 return true; 17097 } else { 17098 return value; 17099 } 17100 } 17101 17102 /** 17103 * Show tabs based upon the anchor component of `window.location`. 17104 */ 17105 function showTabsBasedOnAnchor() { 17106 if(BootstrapTabHistory.options.showTabsBasedOnAnchor) { 17107 var anchor = window.location && window.location.hash; 17108 17109 if(anchor) { 17110 var $tabElement = showTabForSelector(anchor); 17111 17112 if($tabElement && window.addEventListener && window.removeEventListener) { 17113 var anchorYOffset = (function ($tabElement) { 17114 var elementSetting = $tabElement.data('tab-history-anchor-y-offset'); 17115 17116 if(elementSetting === undefined) { 17117 return BootstrapTabHistory.options.defaultAnchorYOffset; 17118 } else { 17119 return elementSetting; 17120 } 17121 })($tabElement); 17122 17123 // HACK: This prevents scrolling to the tab on page load. This relies on the fact that we should never get 17124 // here on `history.forward`, `history.back`, or `location.reload`, since in all those situations the 17125 // `history.state` object should have been used (unless the browser did not support the modern History API). 17126 if(anchorYOffset || anchorYOffset === 0) { 17127 var scrollListener = function resetAnchorScroll () { 17128 window.removeEventListener('scroll', scrollListener); 17129 window.scrollTo(0, anchorYOffset); 17130 }; 17131 17132 window.addEventListener('scroll', scrollListener); 17133 } 17134 } 17135 } 17136 } 17137 } 17138 17139 /** 17140 * Show a tab which corresponds to the provided selector. 17141 * 17142 * @param {string} selector - A CSS selector. 17143 * @returns {?jQuery} - The tab which was found to show (even if said tab was already active). 17144 */ 17145 function showTabForSelector(selector) { 17146 var $tabElement = (function (selector) { 17147 var $ret = null; 17148 17149 jQuery('[data-toggle="tab"], [data-toggle="pill"], [data-toggle="collapse"]').each(function () { 17150 var $potentialTab = jQuery(this); 17151 17152 if(($potentialTab.attr('href') === selector || $potentialTab.data('target') === selector ) && getTabGroup($potentialTab)) { 17153 $ret = $potentialTab; 17154 return false;
vendor: 4,522 bytes, lines 17155-17304
17155 } else { 17156 return null; 17157 } 17158 }); 17159 17160 return $ret; 17161 })(selector); 17162 17163 if($tabElement) { 17164 $tabElement.trigger('click'); 17165 //$tabElement.tab('show'); 17166 } 17167 17168 return $tabElement; 17169 } 17170 17171 /** 17172 * Iterate through the provided set of tab tab groups, showing the tabs based on the stored selectors. 17173 * 17174 * @param {object} bootstrapTabHistory - Each of the values is passed to showTabForSelector; the keys are actually irrelevant. 17175 */ 17176 function showTabsBasedOnState(bootstrapTabHistory) { 17177 showingTabsBasedOnState = true; 17178 17179 try { 17180 for(var k in bootstrapTabHistory) { 17181 if(bootstrapTabHistory.hasOwnProperty(k)) { 17182 showTabForSelector(bootstrapTabHistory[k]); 17183 } 17184 } 17185 } finally { 17186 showingTabsBasedOnState = false; 17187 } 17188 } 17189})(); 17190 17191/*! 17192 * Justified Gallery - v3.6.3 17193 * http://miromannino.github.io/Justified-Gallery/ 17194 * Copyright (c) 2016 Miro Mannino 17195 * Licensed under the MIT license. 17196 */ 17197(function($) { 17198 17199 function hasScrollBar() { 17200 return $("body").height() > $(window).height(); 17201 } 17202 /** 17203 * Justified Gallery controller constructor 17204 * 17205 * @param $gallery the gallery to build 17206 * @param settings the settings (the defaults are in $.fn.justifiedGallery.defaults) 17207 * @constructor 17208 */ 17209 var JustifiedGallery = function ($gallery, settings) { 17210 17211 this.settings = settings; 17212 this.checkSettings(); 17213 17214 this.imgAnalyzerTimeout = null; 17215 this.entries = null; 17216 this.buildingRow = { 17217 entriesBuff : [], 17218 width : 0, 17219 height : 0, 17220 aspectRatio : 0 17221 }; 17222 this.lastFetchedEntry = null; 17223 this.lastAnalyzedIndex = -1; 17224 this.yield = { 17225 every : 2, // do a flush every n flushes (must be greater than 1) 17226 flushed : 0 // flushed rows without a yield 17227 }; 17228 this.border = settings.border >= 0 ? settings.border : settings.margins; 17229 this.maxRowHeight = this.retrieveMaxRowHeight(); 17230 this.suffixRanges = this.retrieveSuffixRanges(); 17231 this.offY = this.border; 17232 this.rows = 0; 17233 this.spinner = { 17234 phase : 0, 17235 timeSlot : 150, 17236 $el : $('<div class="spinner"><span></span><span></span><span></span></div>'), 17237 intervalId : null 17238 }; 17239 this.checkWidthIntervalId = null; 17240 this.galleryWidth = $gallery.width(); 17241 this.$gallery = $gallery; 17242 17243 }; 17244 17245 /** @returns {String} the best suffix given the width and the height */ 17246 JustifiedGallery.prototype.getSuffix = function (width, height) { 17247 var longestSide, i; 17248 longestSide = (width > height) ? width : height; 17249 for (i = 0; i < this.suffixRanges.length; i++) { 17250 if (longestSide <= this.suffixRanges[i]) { 17251 return this.settings.sizeRangeSuffixes[this.suffixRanges[i]]; 17252 } 17253 } 17254 return this.settings.sizeRangeSuffixes[this.suffixRanges[i - 1]]; 17255 }; 17256 17257 /** 17258 * Remove the suffix from the string 17259 * 17260 * @returns {string} a new string without the suffix 17261 */ 17262 JustifiedGallery.prototype.removeSuffix = function (str, suffix) { 17263 return str.substring(0, str.length - suffix.length); 17264 }; 17265 17266 /** 17267 * @returns {boolean} a boolean to say if the suffix is contained in the str or not 17268 */ 17269 JustifiedGallery.prototype.endsWith = function (str, suffix) { 17270 return str.indexOf(suffix, str.length - suffix.length) !== -1; 17271 }; 17272 17273 /** 17274 * Get the used suffix of a particular url 17275 * 17276 * @param str 17277 * @returns {String} return the used suffix 17278 */ 17279 JustifiedGallery.prototype.getUsedSuffix = function (str) { 17280 for (var si in this.settings.sizeRangeSuffixes) { 17281 if (this.settings.sizeRangeSuffixes.hasOwnProperty(si)) { 17282 if (this.settings.sizeRangeSuffixes[si].length === 0) continue; 17283 if (this.endsWith(str, this.settings.sizeRangeSuffixes[si])) return this.settings.sizeRangeSuffixes[si]; 17284 } 17285 } 17286 return ''; 17287 }; 17288 17289 /** 17290 * Given an image src, with the width and the height, returns the new image src with the 17291 * best suffix to show the best quality thumbnail. 17292 * 17293 * @returns {String} the suffix to use 17294 */ 17295 JustifiedGallery.prototype.newSrc = function (imageSrc, imgWidth, imgHeight, image) { 17296 var newImageSrc; 17297 17298 if (this.settings.thumbnailPath) { 17299 newImageSrc = this.settings.thumbnailPath(imageSrc, imgWidth, imgHeight, image); 17300 } else { 17301 var matchRes = imageSrc.match(this.settings.extension); 17302 var ext = (matchRes !== null) ? matchRes[0] : ''; 17303 newImageSrc = imageSrc.replace(this.settings.extension, ''); 17304 newImageSrc = this.removeSuffix(newImageSrc, this.getUsedSuffix(newImageSrc));
17305 newImageSrc += this.getSuffix(imgWidth, imgHeight) + ext; 17306 } 17307 17308 return newImageSrc; 17309 }; 17310 17311 /** 17312 * Shows the images that is in the given entry 17313 * 17314 * @param $entry the entry 17315 * @param callback the callback that is called when the show animation is finished 17316 */ 17317 JustifiedGallery.prototype.showImg = function ($entry, callback) { 17318 if (this.settings.cssAnimation) { 17319 $entry.addClass('entry-visible'); 17320 if (callback) callback(); 17321 } else { 17322 $entry.stop().fadeTo(this.settings.imagesAnimationDuration, 1.0, callback); 17323 $entry.find('> img, > a > img').stop().fadeTo(this.settings.imagesAnimationDuration, 1.0, callback); 17324 } 17325 }; 17326 17327 /** 17328 * Extract the image src form the image, looking from the 'safe-src', and if it can't be found, from the 17329 * 'src' attribute. It saves in the image data the 'jg.originalSrc' field, with the extracted src. 17330 * 17331 * @param $image the image to analyze 17332 * @returns {String} the extracted src 17333 */ 17334 JustifiedGallery.prototype.extractImgSrcFromImage = function ($image) { 17335 var imageSrc = (typeof $image.data('safe-src') !== 'undefined') ? $image.data('safe-src') : $image.attr('src'); 17336 $image.data('jg.originalSrc', imageSrc); 17337 return imageSrc; 17338 }; 17339 17340 /** @returns {jQuery} the image in the given entry */ 17341 JustifiedGallery.prototype.imgFromEntry = function ($entry) { 17342 var $img = $entry.find('> img'); 17343 if ($img.length === 0) $img = $entry.find('> a > img'); 17344 if ($img.length === 0) $img = $entry.find('.t-entry-visual-cont img');//hacked by Uncode 17345 return $img.length === 0 ? null : $img; 17346 }; 17347 17348 /** @returns {jQuery} the caption in the given entry */ 17349 JustifiedGallery.prototype.captionFromEntry = function ($entry) { 17350 var $caption = $entry.find('> .caption'); 17351 return $caption.length === 0 ? null : $caption; 17352 }; 17353 17354 /** 17355 * Display the entry 17356 * 17357 * @param {jQuery} $entry the entry to display 17358 * @param {int} x the x position where the entry must be positioned 17359 * @param y the y position where the entry must be positioned 17360 * @param imgWidth the image width 17361 * @param imgHeight the image height 17362 * @param rowHeight the row height of the row that owns the entry 17363 */ 17364 JustifiedGallery.prototype.displayEntry = function ($entry, x, y, imgWidth, imgHeight, rowHeight) { 17365 $entry.width(imgWidth); 17366 $entry.height(Math.floor(rowHeight));//hacked by Uncode 17367 $entry.css('top', Math.floor(y));//hacked by Uncode 17368 $entry.css('left', x); 17369 17370 var $image = this.imgFromEntry($entry); 17371 if ($image !== null) { 17372 $image.css('width', imgWidth); 17373 $image.css('height', imgHeight); 17374 $image.css('margin-left', - imgWidth / 2); 17375 $image.css('margin-top', - imgHeight / 2); 17376 17377 // Image reloading for an high quality of thumbnails 17378 var imageSrc = $image.attr('src'); 17379 var newImageSrc = this.newSrc(imageSrc, imgWidth, imgHeight, $image[0]); 17380 17381 $image.one('error', function () { 17382 $image.attr('src', $image.data('jg.originalSrc')); //revert to the original thumbnail, we got it. 17383 }); 17384 17385 var loadNewImage = function () { 17386 if (imageSrc !== newImageSrc) { //load the new image after the fadeIn 17387 $image.attr('src', newImageSrc); 17388 } 17389 }; 17390 17391 if ($entry.data('jg.loaded') === 'skipped') { 17392 this.onImageEvent(imageSrc, $.proxy(function() { 17393 this.showImg($entry, loadNewImage); 17394 $entry.data('jg.loaded', true); 17395 }, this)); 17396 } else { 17397 this.showImg($entry, loadNewImage); 17398 } 17399 17400 } else { 17401 this.showImg($entry); 17402 } 17403 17404 this.displayEntryCaption($entry); 17405 }; 17406 17407 /** 17408 * Display the entry caption. If the caption element doesn't exists, it creates the caption using the 'alt' 17409 * or the 'title' attributes. 17410 * 17411 * @param {jQuery} $entry the entry to process 17412 */ 17413 JustifiedGallery.prototype.displayEntryCaption = function ($entry) { 17414 var $image = this.imgFromEntry($entry); 17415 if ($image !== null && this.settings.captions) { 17416 var $imgCaption = this.captionFromEntry($entry); 17417 17418 // Create it if it doesn't exists 17419 if ($imgCaption === null) { 17420 var caption = $image.attr('alt'); 17421 if (!this.isValidCaption(caption)) caption = $entry.attr('title'); 17422 if (this.isValidCaption(caption)) { // Create only we found something 17423 $imgCaption = $('<div class="caption">' + caption + '</div>'); 17424 $entry.append($imgCaption); 17425 $entry.data('jg.createdCaption', true); 17426 } 17427 } 17428 17429 // Create events (we check again the $imgCaption because it can be still inexistent) 17430 if ($imgCaption !== null) { 17431 if (!this.settings.cssAnimation) $imgCaption.stop().fadeTo(0, this.settings.captionSettings.nonVisibleOpacity); 17432 this.addCaptionEventsHandlers($entry); 17433 } 17434 } else { 17435 this.removeCaptionEventsHandlers($entry); 17436 } 17437 }; 17438 17439 /** 17440 * Validates the caption 17441 * 17442 * @param caption The caption that should be validated 17443 * @return {boolean} Validation result 17444 */ 17445 JustifiedGallery.prototype.isValidCaption = function (caption) { 17446 return (typeof caption !== 'undefined' && caption.length > 0); 17447 }; 17448 17449 /** 17450 * The callback for the event 'mouseenter'. It assumes that the event currentTarget is an entry. 17451 * It shows the caption using jQuery (or using CSS if it is configured so) 17452 * 17453 * @param {Event} eventObject the event object 17454 */ 17455 JustifiedGallery.prototype.onEntryMouseEnterForCaption = function (eventObject) { 17456 var $caption = this.captionFromEntry($(eventObject.currentTarget)); 17457 if (this.settings.cssAnimation) { 17458 $caption.addClass('caption-visible').removeClass('caption-hidden'); 17459 } else { 17460 $caption.stop().fadeTo(this.settings.captionSettings.animationDuration, 17461 this.settings.captionSettings.visibleOpacity); 17462 } 17463 }; 17464 17465 /** 17466 * The callback for the event 'mouseleave'. It assumes that the event currentTarget is an entry. 17467 * It hides the caption using jQuery (or using CSS if it is configured so) 17468 * 17469 * @param {Event} eventObject the event object 17470 */ 17471 JustifiedGallery.prototype.onEntryMouseLeaveForCaption = function (eventObject) { 17472 var $caption = this.captionFromEntry($(eventObject.currentTarget)); 17473 if (this.settings.cssAnimation) { 17474 $caption.removeClass('caption-visible').removeClass('caption-hidden'); 17475 } else { 17476 $caption.stop().fadeTo(this.settings.captionSettings.animationDuration, 17477 this.settings.captionSettings.nonVisibleOpacity); 17478 } 17479 }; 17480 17481 /** 17482 * Add the handlers of the entry for the caption 17483 * 17484 * @param $entry the entry to modify 17485 */ 17486 JustifiedGallery.prototype.addCaptionEventsHandlers = function ($entry) { 17487 var captionMouseEvents = $entry.data('jg.captionMouseEvents'); 17488 if (typeof captionMouseEvents === 'undefined') { 17489 captionMouseEvents = { 17490 mouseenter: $.proxy(this.onEntryMouseEnterForCaption, this), 17491 mouseleave: $.proxy(this.onEntryMouseLeaveForCaption, this) 17492 }; 17493 $entry.on('mouseenter', undefined, undefined, captionMouseEvents.mouseenter); 17494 $entry.on('mouseleave', undefined, undefined, captionMouseEvents.mouseleave); 17495 $entry.data('jg.captionMouseEvents', captionMouseEvents); 17496 } 17497 }; 17498 17499 /** 17500 * Remove the handlers of the entry for the caption 17501 * 17502 * @param $entry the entry to modify 17503 */ 17504 JustifiedGallery.prototype.removeCaptionEventsHandlers = function ($entry) { 17505 var captionMouseEvents = $entry.data('jg.captionMouseEvents'); 17506 if (typeof captionMouseEvents !== 'undefined') { 17507 $entry.off('mouseenter', undefined, captionMouseEvents.mouseenter); 17508 $entry.off('mouseleave', undefined, captionMouseEvents.mouseleave); 17509 $entry.removeData('jg.captionMouseEvents'); 17510 } 17511 }; 17512 17513 /** 17514 * Justify the building row, preparing it to 17515 * 17516 * @param isLastRow 17517 * @returns a boolean to know if the row has been justified or not 17518 */ 17519 JustifiedGallery.prototype.prepareBuildingRow = function (isLastRow) { 17520 var i, $entry, imgAspectRatio, newImgW, newImgH, justify = true; 17521 var minHeight = 0; 17522 var availableWidth = this.galleryWidth - 2 * this.border - ( 17523 (this.buildingRow.entriesBuff.length - 1) * this.settings.margins); 17524 var rowHeight = Math.floor( availableWidth / this.buildingRow.aspectRatio );//hacked by Uncode 17525 var defaultRowHeight = this.settings.rowHeight; 17526 var justifiable = this.buildingRow.width / availableWidth > this.settings.justifyThreshold; 17527 17528 //Skip the last row if we can't justify it and the lastRow == 'hide' 17529 if (isLastRow && this.settings.lastRow === 'hide' && !justifiable) { 17530 for (i = 0; i < this.buildingRow.entriesBuff.length; i++) { 17531 $entry = this.buildingRow.entriesBuff[i]; 17532 if (this.settings.cssAnimation) 17533 $entry.removeClass('entry-visible'); 17534 else { 17535 $entry.stop().fadeTo(0, 0.1); 17536 $entry.find('> img, > a > img').fadeTo(0, 0); 17537 } 17538 } 17539 return -1; 17540 } 17541 17542 // With lastRow = nojustify, justify if is justificable (the images will not become too big) 17543 if (isLastRow && !justifiable && this.settings.lastRow !== 'justify' && this.settings.lastRow !== 'hide') { 17544 justify = false;
17545 17546 if (this.rows > 0) { 17547 defaultRowHeight = (this.offY - this.border - this.settings.margins * this.rows) / this.rows; 17548 justify = defaultRowHeight * this.buildingRow.aspectRatio / availableWidth > this.settings.justifyThreshold; 17549 } 17550 } 17551 17552 for (i = 0; i < this.buildingRow.entriesBuff.length; i++) { 17553 $entry = this.buildingRow.entriesBuff[i]; 17554 imgAspectRatio = $entry.data('jg.width') / $entry.data('jg.height'); 17555 17556 if (justify) { 17557 newImgW = (i === this.buildingRow.entriesBuff.length - 1) ? availableWidth : rowHeight * imgAspectRatio; 17558 newImgH = rowHeight; 17559 } else { 17560 newImgW = defaultRowHeight * imgAspectRatio; 17561 newImgH = defaultRowHeight; 17562 } 17563 17564 availableWidth -= Math.round(newImgW); 17565 $entry.data('jg.jwidth', Math.round(newImgW)); 17566 $entry.data('jg.jheight', Math.ceil(newImgH)); 17567 if (i === 0 || minHeight > newImgH) minHeight = newImgH; 17568 } 17569 17570 this.buildingRow.height = minHeight; 17571 return justify; 17572 }; 17573 17574 /** 17575 * Clear the building row data to be used for a new row 17576 */ 17577 JustifiedGallery.prototype.clearBuildingRow = function () { 17578 this.buildingRow.entriesBuff = []; 17579 this.buildingRow.aspectRatio = 0; 17580 this.buildingRow.width = 0; 17581 }; 17582 17583 /** 17584 * Flush a row: justify it, modify the gallery height accordingly to the row height 17585 * 17586 * @param isLastRow 17587 */ 17588 JustifiedGallery.prototype.flushRow = function (isLastRow) { 17589 var settings = this.settings; 17590 var $entry, buildingRowRes, offX = this.border, i; 17591 17592 buildingRowRes = this.prepareBuildingRow(isLastRow); 17593 if (isLastRow && settings.lastRow === 'hide' && buildingRowRes === -1) { 17594 this.clearBuildingRow(); 17595 return; 17596 } 17597 17598 if (this.maxRowHeight) { 17599 if (this.maxRowHeight.isPercentage && this.maxRowHeight.value * settings.rowHeight < this.buildingRow.height) { 17600 this.buildingRow.height = this.maxRowHeight.value * settings.rowHeight; 17601 } else if (this.maxRowHeight.value >= settings.rowHeight && this.maxRowHeight.value < this.buildingRow.height) { 17602 this.buildingRow.height = this.maxRowHeight.value; 17603 } 17604 } 17605 17606 //Align last (unjustified) row 17607 if (settings.lastRow === 'center' || settings.lastRow === 'right') { 17608 var availableWidth = this.galleryWidth - 2 * this.border - (this.buildingRow.entriesBuff.length - 1) * settings.margins; 17609 17610 for (i = 0; i < this.buildingRow.entriesBuff.length; i++) { 17611 $entry = this.buildingRow.entriesBuff[i]; 17612 availableWidth -= $entry.data('jg.jwidth'); 17613 } 17614 17615 if (settings.lastRow === 'center') 17616 offX += availableWidth / 2; 17617 else if (settings.lastRow === 'right') 17618 offX += availableWidth; 17619 } 17620 17621 for (i = 0; i < this.buildingRow.entriesBuff.length; i++) { 17622 $entry = this.buildingRow.entriesBuff[i]; 17623 this.displayEntry($entry, offX, this.offY, $entry.data('jg.jwidth'), $entry.data('jg.jheight'), this.buildingRow.height); 17624 offX += $entry.data('jg.jwidth') + settings.margins; 17625 } 17626 17627 //Gallery Height 17628 this.galleryHeightToSet = this.offY + this.buildingRow.height + this.border; 17629 this.$gallery.height(this.galleryHeightToSet + this.getSpinnerHeight()); 17630 17631 if (!isLastRow || (this.buildingRow.height <= settings.rowHeight && buildingRowRes)) { 17632 //Ready for a new row 17633 this.offY += this.buildingRow.height + settings.margins; 17634 this.rows += 1; 17635 this.clearBuildingRow(); 17636 this.$gallery.trigger('jg.rowflush'); 17637 } 17638 }; 17639 17640 /** 17641 * Checks the width of the gallery container, to know if a new justification is needed 17642 */ 17643 var scrollBarOn = false; 17644 JustifiedGallery.prototype.checkWidth = function () { 17645 this.checkWidthIntervalId = setInterval($.proxy(function () { 17646 var galleryWidth = parseFloat(this.$gallery.width()); 17647 if (hasScrollBar() === scrollBarOn) { 17648 if (Math.abs(galleryWidth - this.galleryWidth) > this.settings.refreshSensitivity) { 17649 this.galleryWidth = galleryWidth; 17650 this.rewind(); 17651 17652 // Restart to analyze 17653 this.startImgAnalyzer(true); 17654 } 17655 } else { 17656 scrollBarOn = hasScrollBar(); 17657 this.galleryWidth = galleryWidth; 17658 } 17659 }, this), this.settings.refreshTime); 17660 }; 17661 17662 /** 17663 * @returns {boolean} a boolean saying if the spinner is active or not 17664 */ 17665 JustifiedGallery.prototype.isSpinnerActive = function () { 17666 return this.spinner.intervalId !== null; 17667 }; 17668 17669 /** 17670 * @returns {int} the spinner height 17671 */ 17672 JustifiedGallery.prototype.getSpinnerHeight = function () {
17673 return this.spinner.$el.innerHeight(); 17674 }; 17675 17676 /** 17677 * Stops the spinner animation and modify the gallery height to exclude the spinner 17678 */ 17679 JustifiedGallery.prototype.stopLoadingSpinnerAnimation = function () { 17680 clearInterval(this.spinner.intervalId); 17681 this.spinner.intervalId = null; 17682 this.$gallery.height(this.$gallery.height() - this.getSpinnerHeight()); 17683 this.spinner.$el.detach(); 17684 }; 17685 17686 /** 17687 * Starts the spinner animation 17688 */ 17689 JustifiedGallery.prototype.startLoadingSpinnerAnimation = function () { 17690 var spinnerContext = this.spinner; 17691 var $spinnerPoints = spinnerContext.$el.find('span'); 17692 clearInterval(spinnerContext.intervalId); 17693 this.$gallery.append(spinnerContext.$el); 17694 this.$gallery.height(this.offY + this.buildingRow.height + this.getSpinnerHeight()); 17695 spinnerContext.intervalId = setInterval(function () { 17696 if (spinnerContext.phase < $spinnerPoints.length) { 17697 $spinnerPoints.eq(spinnerContext.phase).fadeTo(spinnerContext.timeSlot, 1); 17698 } else {
vendor: 4,333 bytes, lines 17699-17843
17699 $spinnerPoints.eq(spinnerContext.phase - $spinnerPoints.length).fadeTo(spinnerContext.timeSlot, 0); 17700 } 17701 spinnerContext.phase = (spinnerContext.phase + 1) % ($spinnerPoints.length * 2); 17702 }, spinnerContext.timeSlot); 17703 }; 17704 17705 /** 17706 * Rewind the image analysis to start from the first entry. 17707 */ 17708 JustifiedGallery.prototype.rewind = function () { 17709 this.lastFetchedEntry = null; 17710 this.lastAnalyzedIndex = -1; 17711 this.offY = this.border; 17712 this.rows = 0; 17713 this.clearBuildingRow(); 17714 }; 17715 17716 /** 17717 * Update the entries searching it from the justified gallery HTML element 17718 * 17719 * @param norewind if norewind only the new entries will be changed (i.e. randomized, sorted or filtered) 17720 * @returns {boolean} true if some entries has been founded 17721 */ 17722 JustifiedGallery.prototype.updateEntries = function (norewind) { 17723 var newEntries; 17724 17725 if (norewind && this.lastFetchedEntry != null) { 17726 newEntries = $(this.lastFetchedEntry).nextAll(this.settings.selector).toArray(); 17727 } else { 17728 this.entries = []; 17729 newEntries = this.$gallery.children(this.settings.selector).toArray(); 17730 } 17731 17732 if (newEntries.length > 0) { 17733 17734 // Sort or randomize 17735 if ($.isFunction(this.settings.sort)) { 17736 newEntries = this.sortArray(newEntries); 17737 } else if (this.settings.randomize) { 17738 newEntries = this.shuffleArray(newEntries); 17739 } 17740 this.lastFetchedEntry = newEntries[newEntries.length - 1]; 17741 17742 // Filter 17743 if (this.settings.filter) { 17744 newEntries = this.filterArray(newEntries); 17745 } else { 17746 this.resetFilters(newEntries); 17747 } 17748 17749 } 17750 17751 this.entries = this.entries.concat(newEntries); 17752 return true; 17753 }; 17754 17755 /** 17756 * Apply the entries order to the DOM, iterating the entries and appending the images 17757 * 17758 * @param entries the entries that has been modified and that must be re-ordered in the DOM 17759 */ 17760 JustifiedGallery.prototype.insertToGallery = function (entries) { 17761 var that = this; 17762 $.each(entries, function () { 17763 $(this).appendTo(that.$gallery); 17764 }); 17765 }; 17766 17767 /** 17768 * Shuffle the array using the Fisher-Yates shuffle algorithm 17769 * 17770 * @param a the array to shuffle 17771 * @return the shuffled array 17772 */ 17773 JustifiedGallery.prototype.shuffleArray = function (a) { 17774 var i, j, temp; 17775 for (i = a.length - 1; i > 0; i--) { 17776 j = Math.floor(Math.random() * (i + 1)); 17777 temp = a[i]; 17778 a[i] = a[j]; 17779 a[j] = temp; 17780 } 17781 this.insertToGallery(a); 17782 return a; 17783 }; 17784 17785 /** 17786 * Sort the array using settings.comparator as comparator 17787 * 17788 * @param a the array to sort (it is sorted) 17789 * @return the sorted array 17790 */ 17791 JustifiedGallery.prototype.sortArray = function (a) { 17792 a.sort(this.settings.sort); 17793 this.insertToGallery(a); 17794 return a; 17795 }; 17796 17797 /** 17798 * Reset the filters removing the 'jg-filtered' class from all the entries 17799 * 17800 * @param a the array to reset 17801 */ 17802 JustifiedGallery.prototype.resetFilters = function (a) { 17803 for (var i = 0; i < a.length; i++) $(a[i]).removeClass('jg-filtered'); 17804 }; 17805 17806 /** 17807 * Filter the entries considering theirs classes (if a string has been passed) or using a function for filtering. 17808 * 17809 * @param a the array to filter 17810 * @return the filtered array 17811 */ 17812 JustifiedGallery.prototype.filterArray = function (a) { 17813 var settings = this.settings; 17814 if ($.type(settings.filter) === 'string') { 17815 // Filter only keeping the entries passed in the string 17816 return a.filter(function (el) { 17817 var $el = $(el); 17818 if ($el.is(settings.filter)) { 17819 $el.removeClass('jg-filtered'); 17820 return true; 17821 } else { 17822 $el.addClass('jg-filtered').removeClass('jg-visible'); 17823 return false; 17824 } 17825 }); 17826 } else if ($.isFunction(settings.filter)) { 17827 // Filter using the passed function 17828 var filteredArr = a.filter(settings.filter); 17829 for (var i = 0; i < a.length; i++) { 17830 if (filteredArr.indexOf(a[i]) == -1) { 17831 $(a[i]).addClass('jg-filtered').removeClass('jg-visible'); 17832 } else { 17833 $(a[i]).removeClass('jg-filtered'); 17834 } 17835 } 17836 return filteredArr; 17837 } 17838 }; 17839 17840 /** 17841 * Destroy the Justified Gallery instance. 17842 * 17843 * It clears all the css properties added in the style attributes. We doesn't backup the original
17844 * values for those css attributes, because it costs (performance) and because in general one 17845 * shouldn't use the style attribute for an uniform set of images (where we suppose the use of 17846 * classes). Creating a backup is also difficult because JG could be called multiple times and 17847 * with different style attributes. 17848 */ 17849 JustifiedGallery.prototype.destroy = function () { 17850 clearInterval(this.checkWidthIntervalId); 17851 17852 $.each(this.entries, $.proxy(function(_, entry) { 17853 var $entry = $(entry); 17854 17855 // Reset entry style 17856 $entry.css('width', ''); 17857 $entry.css('height', ''); 17858 $entry.css('top', ''); 17859 $entry.css('left', ''); 17860 $entry.data('jg.loaded', undefined); 17861 $entry.removeClass('jg-entry'); 17862 17863 // Reset image style 17864 var $img = this.imgFromEntry($entry); 17865 $img.css('width', ''); 17866 $img.css('height', ''); 17867 $img.css('margin-left', ''); 17868 $img.css('margin-top', ''); 17869 $img.attr('src', $img.data('jg.originalSrc')); 17870 $img.data('jg.originalSrc', undefined); 17871 17872 // Remove caption 17873 this.removeCaptionEventsHandlers($entry); 17874 var $caption = this.captionFromEntry($entry); 17875 if ($entry.data('jg.createdCaption')) { 17876 // remove also the caption element (if created by jg) 17877 $entry.data('jg.createdCaption', undefined); 17878 if ($caption !== null) $caption.remove(); 17879 } else { 17880 if ($caption !== null) $caption.fadeTo(0, 1); 17881 } 17882 17883 }, this)); 17884 17885 this.$gallery.css('height', ''); 17886 this.$gallery.removeClass('justified-gallery'); 17887 this.$gallery.data('jg.controller', undefined); 17888 }; 17889 17890 /** 17891 * Analyze the images and builds the rows. It returns if it found an image that is not loaded. 17892 * 17893 * @param isForResize if the image analyzer is called for resizing or not, to call a different callback at the end 17894 */ 17895 JustifiedGallery.prototype.analyzeImages = function (isForResize) { 17896 for (var i = this.lastAnalyzedIndex + 1; i < this.entries.length; i++) { 17897 var $entry = $(this.entries[i]); 17898 if ($entry.data('jg.loaded') === true || $entry.data('jg.loaded') === 'skipped') { 17899 var availableWidth = this.galleryWidth - 2 * this.border - ( 17900 (this.buildingRow.entriesBuff.length - 1) * this.settings.margins); 17901 var imgAspectRatio = $entry.data('jg.width') / $entry.data('jg.height'); 17902 if (availableWidth / (this.buildingRow.aspectRatio + imgAspectRatio) < this.settings.rowHeight) { 17903 this.flushRow(false); 17904 if(++this.yield.flushed >= this.yield.every) { 17905 this.startImgAnalyzer(isForResize); 17906 return; 17907 } 17908 } 17909 17910 this.buildingRow.entriesBuff.push($entry); 17911 this.buildingRow.aspectRatio += imgAspectRatio; 17912 this.buildingRow.width += imgAspectRatio * this.settings.rowHeight; 17913 this.lastAnalyzedIndex = i; 17914 17915 } else if ($entry.data('jg.loaded') !== 'error') { 17916 return; 17917 } 17918 } 17919 17920 // Last row flush (the row is not full) 17921 if (this.buildingRow.entriesBuff.length > 0) this.flushRow(true); 17922 17923 if (this.isSpinnerActive()) { 17924 this.stopLoadingSpinnerAnimation(); 17925 } 17926 17927 /* Stop, if there is, the timeout to start the analyzeImages. 17928 This is because an image can be set loaded, and the timeout can be set, 17929 but this image can be analyzed yet. 17930 */ 17931 this.stopImgAnalyzerStarter(); 17932 17933 //On complete callback 17934 this.$gallery.trigger(isForResize ? 'jg.resize' : 'jg.complete'); 17935 this.$gallery.height(this.galleryHeightToSet); 17936 }; 17937 17938 /** 17939 * Stops any ImgAnalyzer starter (that has an assigned timeout) 17940 */ 17941 JustifiedGallery.prototype.stopImgAnalyzerStarter = function () { 17942 this.yield.flushed = 0; 17943 if (this.imgAnalyzerTimeout !== null) clearTimeout(this.imgAnalyzerTimeout); 17944 }; 17945 17946 /** 17947 * Starts the image analyzer. It is not immediately called to let the browser to update the view 17948 * 17949 * @param isForResize specifies if the image analyzer must be called for resizing or not 17950 */ 17951 JustifiedGallery.prototype.startImgAnalyzer = function (isForResize) { 17952 var that = this; 17953 this.stopImgAnalyzerStarter(); 17954 this.imgAnalyzerTimeout = setTimeout(function () { 17955 that.analyzeImages(isForResize); 17956 }, 0.001); // we can't start it immediately due to a IE different behaviour 17957 }; 17958 17959 /** 17960 * Checks if the image is loaded or not using another image object. We cannot use the 'complete' image property, 17961 * because some browsers, with a 404 set complete = true. 17962 * 17963 * @param imageSrc the image src to load 17964 * @param onLoad callback that is called when the image has been loaded
vendor: 13,320 bytes, lines 17965-18315
17965 * @param onError callback that is called in case of an error 17966 */ 17967 JustifiedGallery.prototype.onImageEvent = function (imageSrc, onLoad, onError) { 17968 if (!onLoad && !onError) return; 17969 17970 var memImage = new Image(); 17971 var $memImage = $(memImage); 17972 if (onLoad) { 17973 $memImage.one('load', function () { 17974 $memImage.off('load error'); 17975 onLoad(memImage); 17976 }); 17977 } 17978 if (onError) { 17979 $memImage.one('error', function() { 17980 $memImage.off('load error'); 17981 onError(memImage); 17982 }); 17983 } 17984 memImage.src = imageSrc; 17985 }; 17986 17987 /** 17988 * Init of Justified Gallery controlled 17989 * It analyzes all the entries starting theirs loading and calling the image analyzer (that works with loaded images) 17990 */ 17991 JustifiedGallery.prototype.init = function () { 17992 var imagesToLoad = false, skippedImages = false, that = this; 17993 $.each(this.entries, function (index, entry) { 17994 var $entry = $(entry); 17995 var $image = that.imgFromEntry($entry); 17996 17997 $entry.addClass('jg-entry'); 17998 17999 if ($entry.data('jg.loaded') !== true && $entry.data('jg.loaded') !== 'skipped') { 18000 18001 // Link Rel global overwrite 18002 if (that.settings.rel !== null) $entry.attr('rel', that.settings.rel); 18003 18004 // Link Target global overwrite 18005 if (that.settings.target !== null) $entry.attr('target', that.settings.target); 18006 18007 if ($image !== null) { 18008 18009 // Image src 18010 var imageSrc = that.extractImgSrcFromImage($image); 18011 $image.attr('src', imageSrc); 18012 18013 /* If we have the height and the width, we don't wait that the image is loaded, but we start directly 18014 * with the justification */ 18015 if (that.settings.waitThumbnailsLoad === false) { 18016 var width = parseFloat($image.attr('width')); 18017 var height = parseFloat($image.attr('height')); 18018 if (!isNaN(width) && !isNaN(height)) { 18019 $entry.data('jg.width', width); 18020 $entry.data('jg.height', height); 18021 $entry.data('jg.loaded', 'skipped'); 18022 skippedImages = true; 18023 that.startImgAnalyzer(false); 18024 return true; // continue 18025 } 18026 } 18027 18028 $entry.data('jg.loaded', false); 18029 imagesToLoad = true; 18030 18031 // Spinner start 18032 if (!that.isSpinnerActive()) that.startLoadingSpinnerAnimation(); 18033 18034 that.onImageEvent(imageSrc, function (loadImg) { // image loaded 18035 $entry.data('jg.width', loadImg.width); 18036 $entry.data('jg.height', loadImg.height); 18037 $entry.data('jg.loaded', true); 18038 that.startImgAnalyzer(false); 18039 }, function () { // image load error 18040 $entry.data('jg.loaded', 'error'); 18041 that.startImgAnalyzer(false); 18042 }); 18043 18044 } else { 18045 $entry.data('jg.loaded', true); 18046 $entry.data('jg.width', $entry.width() | parseFloat($entry.css('width')) | 1); 18047 $entry.data('jg.height', $entry.height() | parseFloat($entry.css('height')) | 1); 18048 } 18049 18050 } 18051 18052 }); 18053 18054 if (!imagesToLoad && !skippedImages) this.startImgAnalyzer(false); 18055 this.checkWidth(); 18056 }; 18057 18058 /** 18059 * Checks that it is a valid number. If a string is passed it is converted to a number 18060 * 18061 * @param settingContainer the object that contains the setting (to allow the conversion) 18062 * @param settingName the setting name 18063 */ 18064 JustifiedGallery.prototype.checkOrConvertNumber = function (settingContainer, settingName) { 18065 if ($.type(settingContainer[settingName]) === 'string') { 18066 settingContainer[settingName] = parseFloat(settingContainer[settingName]); 18067 } 18068 18069 if ($.type(settingContainer[settingName]) === 'number') { 18070 if (isNaN(settingContainer[settingName])) throw 'invalid number for ' + settingName; 18071 } else { 18072 throw settingName + ' must be a number'; 18073 } 18074 }; 18075 18076 /** 18077 * Checks the sizeRangeSuffixes and, if necessary, converts 18078 * its keys from string (e.g. old settings with 'lt100') to int. 18079 */ 18080 JustifiedGallery.prototype.checkSizeRangesSuffixes = function () { 18081 if ($.type(this.settings.sizeRangeSuffixes) !== 'object') { 18082 throw 'sizeRangeSuffixes must be defined and must be an object'; 18083 } 18084 18085 var suffixRanges = []; 18086 for (var rangeIdx in this.settings.sizeRangeSuffixes) { 18087 if (this.settings.sizeRangeSuffixes.hasOwnProperty(rangeIdx)) suffixRanges.push(rangeIdx); 18088 } 18089 18090 var newSizeRngSuffixes = {0: ''}; 18091 for (var i = 0; i < suffixRanges.length; i++) { 18092 if ($.type(suffixRanges[i]) === 'string') { 18093 try { 18094 var numIdx = parseInt(suffixRanges[i].replace(/^[a-z]+/, ''), 10); 18095 newSizeRngSuffixes[numIdx] = this.settings.sizeRangeSuffixes[suffixRanges[i]]; 18096 } catch (e) { 18097 throw 'sizeRangeSuffixes keys must contains correct numbers (' + e + ')'; 18098 } 18099 } else { 18100 newSizeRngSuffixes[suffixRanges[i]] = this.settings.sizeRangeSuffixes[suffixRanges[i]]; 18101 } 18102 } 18103 18104 this.settings.sizeRangeSuffixes = newSizeRngSuffixes; 18105 }; 18106 18107 /** 18108 * check and convert the maxRowHeight setting 18109 */ 18110 JustifiedGallery.prototype.retrieveMaxRowHeight = function () { 18111 var newMaxRowHeight = { }; 18112 18113 if ($.type(this.settings.maxRowHeight) === 'string') { 18114 if (this.settings.maxRowHeight.match(/^[0-9]+%$/)) { 18115 newMaxRowHeight.value = parseFloat(this.settings.maxRowHeight.match(/^([0-9]+)%$/)[1]) / 100; 18116 newMaxRowHeight.isPercentage = false; 18117 } else { 18118 newMaxRowHeight.value = parseFloat(this.settings.maxRowHeight); 18119 newMaxRowHeight.isPercentage = true; 18120 } 18121 } else if ($.type(this.settings.maxRowHeight) === 'number') { 18122 newMaxRowHeight.value = this.settings.maxRowHeight; 18123 newMaxRowHeight.isPercentage = false; 18124 } else if (this.settings.maxRowHeight === false || 18125 this.settings.maxRowHeight === null || 18126 typeof this.settings.maxRowHeight == 'undefined') { 18127 return null; 18128 } else { 18129 throw 'maxRowHeight must be a number or a percentage'; 18130 } 18131 18132 // check if the converted value is not a number 18133 if (isNaN(newMaxRowHeight.value)) throw 'invalid number for maxRowHeight'; 18134 18135 // check values 18136 if (newMaxRowHeight.isPercentage) { 18137 if (newMaxRowHeight.value < 100) newMaxRowHeight.value = 100; 18138 } 18139 18140 return newMaxRowHeight; 18141 }; 18142 18143 /** 18144 * Checks the settings 18145 */ 18146 JustifiedGallery.prototype.checkSettings = function () { 18147 this.checkSizeRangesSuffixes(); 18148 18149 this.checkOrConvertNumber(this.settings, 'rowHeight'); 18150 this.checkOrConvertNumber(this.settings, 'margins'); 18151 this.checkOrConvertNumber(this.settings, 'border'); 18152 18153 var lastRowModes = [ 18154 'justify', 18155 'nojustify', 18156 'left', 18157 'center', 18158 'right', 18159 'hide' 18160 ]; 18161 if (lastRowModes.indexOf(this.settings.lastRow) === -1) { 18162 throw 'lastRow must be one of: ' + lastRowModes.join(', '); 18163 } 18164 18165 this.checkOrConvertNumber(this.settings, 'justifyThreshold'); 18166 if (this.settings.justifyThreshold < 0 || this.settings.justifyThreshold > 1) { 18167 throw 'justifyThreshold must be in the interval [0,1]'; 18168 } 18169 if ($.type(this.settings.cssAnimation) !== 'boolean') { 18170 throw 'cssAnimation must be a boolean'; 18171 } 18172 18173 if ($.type(this.settings.captions) !== 'boolean') throw 'captions must be a boolean'; 18174 this.checkOrConvertNumber(this.settings.captionSettings, 'animationDuration'); 18175 18176 this.checkOrConvertNumber(this.settings.captionSettings, 'visibleOpacity'); 18177 if (this.settings.captionSettings.visibleOpacity < 0 || 18178 this.settings.captionSettings.visibleOpacity > 1) { 18179 throw 'captionSettings.visibleOpacity must be in the interval [0, 1]'; 18180 } 18181 18182 this.checkOrConvertNumber(this.settings.captionSettings, 'nonVisibleOpacity'); 18183 if (this.settings.captionSettings.nonVisibleOpacity < 0 || 18184 this.settings.captionSettings.nonVisibleOpacity > 1) { 18185 throw 'captionSettings.nonVisibleOpacity must be in the interval [0, 1]'; 18186 } 18187 18188 this.checkOrConvertNumber(this.settings, 'imagesAnimationDuration'); 18189 this.checkOrConvertNumber(this.settings, 'refreshTime'); 18190 this.checkOrConvertNumber(this.settings, 'refreshSensitivity'); 18191 if ($.type(this.settings.randomize) !== 'boolean') throw 'randomize must be a boolean'; 18192 if ($.type(this.settings.selector) !== 'string') throw 'selector must be a string'; 18193 18194 if (this.settings.sort !== false && !$.isFunction(this.settings.sort)) { 18195 throw 'sort must be false or a comparison function'; 18196 } 18197 18198 if (this.settings.filter !== false && !$.isFunction(this.settings.filter) && 18199 $.type(this.settings.filter) !== 'string') { 18200 throw 'filter must be false, a string or a filter function'; 18201 } 18202 }; 18203 18204 /** 18205 * It brings all the indexes from the sizeRangeSuffixes and it orders them. They are then sorted and returned. 18206 * @returns {Array} sorted suffix ranges 18207 */ 18208 JustifiedGallery.prototype.retrieveSuffixRanges = function () { 18209 var suffixRanges = []; 18210 for (var rangeIdx in this.settings.sizeRangeSuffixes) { 18211 if (this.settings.sizeRangeSuffixes.hasOwnProperty(rangeIdx)) suffixRanges.push(parseInt(rangeIdx, 10)); 18212 } 18213 suffixRanges.sort(function (a, b) { return a > b ? 1 : a < b ? -1 : 0; }); 18214 return suffixRanges; 18215 }; 18216 18217 /** 18218 * Update the existing settings only changing some of them 18219 * 18220 * @param newSettings the new settings (or a subgroup of them) 18221 */ 18222 JustifiedGallery.prototype.updateSettings = function (newSettings) { 18223 // In this case Justified Gallery has been called again changing only some options 18224 this.settings = $.extend({}, this.settings, newSettings); 18225 this.checkSettings(); 18226 18227 // As reported in the settings: negative value = same as margins, 0 = disabled 18228 this.border = this.settings.border >= 0 ? this.settings.border : this.settings.margins; 18229 18230 this.maxRowHeight = this.retrieveMaxRowHeight(); 18231 this.suffixRanges = this.retrieveSuffixRanges(); 18232 }; 18233 18234 /** 18235 * Justified Gallery plugin for jQuery 18236 * 18237 * Events 18238 * - jg.complete : called when all the gallery has been created 18239 * - jg.resize : called when the gallery has been resized 18240 * - jg.rowflush : when a new row appears 18241 * 18242 * @param arg the action (or the settings) passed when the plugin is called 18243 * @returns {*} the object itself 18244 */ 18245 $.fn.justifiedGallery = function (arg) { 18246 return this.each(function (index, gallery) { 18247 18248 var $gallery = $(gallery); 18249 $gallery.addClass('justified-gallery'); 18250 18251 var controller = $gallery.data('jg.controller'); 18252 if (typeof controller === 'undefined') { 18253 // Create controller and assign it to the object data 18254 if (typeof arg !== 'undefined' && arg !== null && $.type(arg) !== 'object') { 18255 if (arg === 'destroy') return; // Just a call to an unexisting object 18256 throw 'The argument must be an object'; 18257 } 18258 controller = new JustifiedGallery($gallery, $.extend({}, $.fn.justifiedGallery.defaults, arg)); 18259 $gallery.data('jg.controller', controller); 18260 } else if (arg === 'norewind') { 18261 // In this case we don't rewind: we analyze only the latest images (e.g. to complete the last unfinished row 18262 // ... left to be more readable 18263 } else if (arg === 'destroy') { 18264 controller.destroy(); 18265 return; 18266 } else { 18267 // In this case Justified Gallery has been called again changing only some options 18268 controller.updateSettings(arg); 18269 controller.rewind(); 18270 } 18271 18272 // Update the entries list 18273 if (!controller.updateEntries(arg === 'norewind')) return; 18274 18275 // Init justified gallery 18276 controller.init(); 18277 18278 }); 18279 }; 18280 18281 // Default options 18282 $.fn.justifiedGallery.defaults = { 18283 sizeRangeSuffixes: { }, /* e.g. Flickr configuration 18284 { 18285 100: '_t', // used when longest is less than 100px 18286 240: '_m', // used when longest is between 101px and 240px 18287 320: '_n', // ... 18288 500: '', 18289 640: '_z', 18290 1024: '_b' // used as else case because it is the last 18291 } 18292 */ 18293 thumbnailPath: undefined, /* If defined, sizeRangeSuffixes is not used, and this function is used to determine the 18294 path relative to a specific thumbnail size. The function should accept respectively three arguments: 18295 current path, width and height */ 18296 rowHeight: 120, 18297 maxRowHeight: false, // false or negative value to deactivate. Positive number to express the value in pixels, 18298 // A string '[0-9]+%' to express in percentage (e.g. 300% means that the row height 18299 // can't exceed 3 * rowHeight) 18300 margins: 1, 18301 border: -1, // negative value = same as margins, 0 = disabled, any other value to set the border 18302 18303 lastRow: 'nojustify', // … which is the same as 'left', or can be 'justify', 'center', 'right' or 'hide' 18304 18305 justifyThreshold: 0.90, /* if row width / available space > 0.90 it will be always justified 18306 * (i.e. lastRow setting is not considered) */ 18307 waitThumbnailsLoad: true, 18308 captions: true, 18309 cssAnimation: true, 18310 imagesAnimationDuration: 500, // ignored with css animations 18311 captionSettings: { // ignored with css animations 18312 animationDuration: 500, 18313 visibleOpacity: 0.7, 18314 nonVisibleOpacity: 0.0 18315 },
18316 rel: null, // rewrite the rel of each analyzed links 18317 target: null, // rewrite the target of all links 18318 extension: /\.[^.\\/]+$/, // regexp to capture the extension of an image 18319 refreshTime: 200, // time interval (in ms) to check if the page changes its width 18320 refreshSensitivity: 0, // change in width allowed (in px) without re-building the gallery 18321 randomize: false, 18322 sort: false, /* 18323 - false: to do not sort 18324 - function: to sort them using the function as comparator (see Array.prototype.sort()) 18325 */ 18326 filter: false, /* 18327 - false, null or undefined: for a disabled filter 18328 - a string: an entry is kept if entry.is(filter string) returns true 18329 see jQuery's .is() function for further information 18330 - a function: invoked with arguments (entry, index, array). Return true to keep the entry, false otherwise. 18331 It follows the specifications of the Array.prototype.filter() function of JavaScript. 18332 */ 18333 selector: 'a, div:not(.spinner)' // The selector that is used to know what are the entries of the gallery 18334 }; 18335 18336}(jQuery)); 18337/*! 18338* Customized version of iScroll.js 0.0.1 18339* It fixes bugs affecting its integration with fullpage.js 18340*/ 18341/*! iScroll v5.2.0 ~ (c) 2008-2016 Matteo Spinelli ~ http://cubiq.org/license */ 18342(function (window, document, Math) { 18343var rAF = window.requestAnimationFrame || 18344 window.webkitRequestAnimationFrame || 18345 window.mozRequestAnimationFrame || 18346 window.oRequestAnimationFrame || 18347 window.msRequestAnimationFrame || 18348 function (callback) { window.setTimeout(callback, 1000 / 60); }; 18349 18350var utils = (function () { 18351 var me = {}; 18352 18353 var _elementStyle = document.createElement('div').style; 18354 var _vendor = (function () { 18355 var vendors = ['t', 'webkitT', 'MozT', 'msT', 'OT'], 18356 transform, 18357 i = 0, 18358 l = vendors.length; 18359 18360 for ( ; i < l; i++ ) { 18361 transform = vendors[i] + 'ransform'; 18362 if ( transform in _elementStyle ) return vendors[i].substr(0, vendors[i].length-1); 18363 } 18364 18365 return false; 18366 })(); 18367 18368 function _prefixStyle (style) { 18369 if ( _vendor === false ) return false; 18370 if ( _vendor === '' ) return style; 18371 return _vendor + style.charAt(0).toUpperCase() + style.substr(1); 18372 } 18373 18374 me.getTime = Date.now || function getTime () { return new Date().getTime(); }; 18375 18376 me.extend = function (target, obj) { 18377 for ( var i in obj ) { 18378 target[i] = obj[i]; 18379 } 18380 }; 18381 18382 me.addEvent = function (el, type, fn, capture) { 18383 el.addEventListener(type, fn, !!capture); 18384 }; 18385 18386 me.removeEvent = function (el, type, fn, capture) { 18387 el.removeEventListener(type, fn, !!capture); 18388 }; 18389 18390 me.prefixPointerEvent = function (pointerEvent) { 18391 return window.MSPointerEvent ? 18392 'MSPointer' + pointerEvent.charAt(7).toUpperCase() + pointerEvent.substr(8): 18393 pointerEvent; 18394 }; 18395 18396 me.momentum = function (current, start, time, lowerMargin, wrapperSize, deceleration) { 18397 var distance = current - start, 18398 speed = Math.abs(distance) / time, 18399 destination, 18400 duration; 18401 18402 deceleration = deceleration === undefined ? 0.0006 : deceleration; 18403 18404 destination = current + ( speed * speed ) / ( 2 * deceleration ) * ( distance < 0 ? -1 : 1 ); 18405 duration = speed / deceleration; 18406 18407 if ( destination < lowerMargin ) { 18408 destination = wrapperSize ? lowerMargin - ( wrapperSize / 2.5 * ( speed / 8 ) ) : lowerMargin; 18409 distance = Math.abs(destination - current); 18410 duration = distance / speed; 18411 } else if ( destination > 0 ) { 18412 destination = wrapperSize ? wrapperSize / 2.5 * ( speed / 8 ) : 0; 18413 distance = Math.abs(current) + destination; 18414 duration = distance / speed; 18415 } 18416 18417 return { 18418 destination: Math.round(destination), 18419 duration: duration 18420 }; 18421 }; 18422 18423 var _transform = _prefixStyle('transform'); 18424 18425 me.extend(me, { 18426 hasTransform: _transform !== false, 18427 hasPerspective: _prefixStyle('perspective') in _elementStyle, 18428 hasTouch: 'ontouchstart' in window, 18429 hasPointer: !!(window.PointerEvent || window.MSPointerEvent), // IE10 is prefixed 18430 hasTransition: _prefixStyle('transition') in _elementStyle 18431 }); 18432 18433 /* 18434 This should find all Android browsers lower than build 535.19 (both stock browser and webview) 18435 - galaxy S2 is ok 18436 - 2.3.6 : `AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1` 18437 - 4.0.4 : `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30` 18438 - galaxy S3 is badAndroid (stock brower, webview) 18439 `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30` 18440 - galaxy S4 is badAndroid (stock brower, webview) 18441 `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30` 18442 - galaxy S5 is OK 18443 `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)` 18444 - galaxy S6 is OK 18445 `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)` 18446 */ 18447 me.isBadAndroid = (function() { 18448 var appVersion = window.navigator.appVersion; 18449 // Android browser is not a chrome browser. 18450 if (/Android/.test(appVersion) && !(/Chrome\/\d/.test(appVersion))) { 18451 var safariVersion = appVersion.match(/Safari\/(\d+.\d)/); 18452 if(safariVersion && typeof safariVersion === "object" && safariVersion.length >= 2) { 18453 return parseFloat(safariVersion[1]) < 535.19; 18454 } else { 18455 return true; 18456 } 18457 } else { 18458 return false;
18459 } 18460 })(); 18461 18462 me.extend(me.style = {}, { 18463 transform: _transform, 18464 transitionTimingFunction: _prefixStyle('transitionTimingFunction'), 18465 transitionDuration: _prefixStyle('transitionDuration'), 18466 transitionDelay: _prefixStyle('transitionDelay'), 18467 transformOrigin: _prefixStyle('transformOrigin') 18468 }); 18469 18470 me.hasClass = function (e, c) { 18471 var re = new RegExp("(^|\\s)" + c + "(\\s|$)"); 18472 return re.test(e.className); 18473 }; 18474 18475 me.addClass = function (e, c) { 18476 if ( me.hasClass(e, c) ) { 18477 return; 18478 } 18479 18480 var newclass = e.className.split(' '); 18481 newclass.push(c); 18482 e.className = newclass.join(' '); 18483 }; 18484 18485 me.removeClass = function (e, c) { 18486 if ( !me.hasClass(e, c) ) { 18487 return; 18488 } 18489 18490 var re = new RegExp("(^|\\s)" + c + "(\\s|$)", 'g'); 18491 e.className = e.className.replace(re, ' '); 18492 }; 18493 18494 me.offset = function (el) { 18495 var left = -el.offsetLeft, 18496 top = -el.offsetTop; 18497 18498 // jshint -W084 18499 while (el = el.offsetParent) { 18500 left -= el.offsetLeft; 18501 top -= el.offsetTop; 18502 } 18503 // jshint +W084 18504 18505 return { 18506 left: left, 18507 top: top 18508 }; 18509 }; 18510 18511 me.preventDefaultException = function (el, exceptions) { 18512 for ( var i in exceptions ) { 18513 if ( exceptions[i].test(el[i]) ) { 18514 return true; 18515 } 18516 } 18517 18518 return false; 18519 }; 18520 18521 me.extend(me.eventType = {}, { 18522 touchstart: 1, 18523 touchmove: 1, 18524 touchend: 1, 18525 18526 mousedown: 2, 18527 mousemove: 2, 18528 mouseup: 2, 18529 18530 pointerdown: 3, 18531 pointermove: 3, 18532 pointerup: 3, 18533 18534 MSPointerDown: 3, 18535 MSPointerMove: 3, 18536 MSPointerUp: 3 18537 }); 18538 18539 me.extend(me.ease = {}, { 18540 quadratic: { 18541 style: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)', 18542 fn: function (k) { 18543 return k * ( 2 - k ); 18544 } 18545 }, 18546 circular: { 18547 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) 18548 fn: function (k) { 18549 return Math.sqrt( 1 - ( --k * k ) ); 18550 } 18551 }, 18552 back: { 18553 style: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)', 18554 fn: function (k) { 18555 var b = 4; 18556 return ( k = k - 1 ) * k * ( ( b + 1 ) * k + b ) + 1; 18557 } 18558 }, 18559 bounce: { 18560 style: '', 18561 fn: function (k) { 18562 if ( ( k /= 1 ) < ( 1 / 2.75 ) ) { 18563 return 7.5625 * k * k; 18564 } else if ( k < ( 2 / 2.75 ) ) { 18565 return 7.5625 * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75; 18566 } else if ( k < ( 2.5 / 2.75 ) ) { 18567 return 7.5625 * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375; 18568 } else { 18569 return 7.5625 * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375; 18570 } 18571 } 18572 }, 18573 elastic: { 18574 style: '', 18575 fn: function (k) { 18576 var f = 0.22, 18577 e = 0.4; 18578 18579 if ( k === 0 ) { return 0; } 18580 if ( k == 1 ) { return 1; } 18581 18582 return ( e * Math.pow( 2, - 10 * k ) * Math.sin( ( k - f / 4 ) * ( 2 * Math.PI ) / f ) + 1 ); 18583 } 18584 } 18585 }); 18586 18587 me.tap = function (e, eventName) { 18588 var ev = document.createEvent('Event'); 18589 ev.initEvent(eventName, true, true); 18590 ev.pageX = e.pageX; 18591 ev.pageY = e.pageY; 18592 e.target.dispatchEvent(ev); 18593 }; 18594 18595 me.click = function (e) { 18596 var target = e.target, 18597 ev; 18598 18599 if ( !(/(SELECT|INPUT|TEXTAREA)/i).test(target.tagName) ) { 18600 // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/initMouseEvent 18601 // initMouseEvent is deprecated. 18602 ev = document.createEvent(window.MouseEvent ? 'MouseEvents' : 'Event'); 18603 ev.initEvent('click', true, true); 18604 ev.view = e.view || window; 18605 ev.detail = 1; 18606 ev.screenX = target.screenX || 0; 18607 ev.screenY = target.screenY || 0; 18608 ev.clientX = target.clientX || 0; 18609 ev.clientY = target.clientY || 0; 18610 ev.ctrlKey = !!e.ctrlKey; 18611 ev.altKey = !!e.altKey; 18612 ev.shiftKey = !!e.shiftKey; 18613 ev.metaKey = !!e.metaKey; 18614 ev.button = 0; 18615 ev.relatedTarget = null; 18616 ev._constructed = true; 18617 target.dispatchEvent(ev); 18618 } 18619 }; 18620 18621 return me; 18622})(); 18623function IScroll (el, options) { 18624 this.wrapper = typeof el == 'string' ? document.querySelector(el) : el; 18625 this.scroller = this.wrapper.children[0]; 18626 this.scrollerStyle = this.scroller.style; // cache style for better performance 18627 18628 this.options = { 18629 18630 resizeScrollbars: true, 18631 18632 mouseWheelSpeed: 20, 18633 18634 snapThreshold: 0.334, 18635 18636// INSERT POINT: OPTIONS 18637 disablePointer : !utils.hasPointer, 18638 disableTouch : utils.hasPointer || !utils.hasTouch, 18639 disableMouse : utils.hasPointer || utils.hasTouch, 18640 startX: 0, 18641 startY: 0, 18642 scrollY: true, 18643 directionLockThreshold: 5, 18644 momentum: true, 18645 18646 bounce: true, 18647 bounceTime: 600, 18648 bounceEasing: '', 18649 18650 preventDefault: true, 18651 preventDefaultException: { tagName: /^(INPUT|TEXTAREA|BUTTON|
18651SELECT|LABEL)$/ }, 18652 18653 HWCompositing: true, 18654 useTransition: true, 18655 useTransform: true, 18656 bindToWrapper: typeof window.onmousedown === "undefined" 18657 }; 18658 18659 for ( var i in options ) { 18660 this.options[i] = options[i]; 18661 } 18662 18663 // Normalize options 18664 this.translateZ = this.options.HWCompositing && utils.hasPerspective ? ' translateZ(0)' : ''; 18665 18666 this.options.useTransition = utils.hasTransition && this.options.useTransition; 18667 this.options.useTransform = utils.hasTransform && this.options.useTransform; 18668 18669 this.options.eventPassthrough = this.options.eventPassthrough === true ? 'vertical' : this.options.eventPassthrough; 18670 this.options.preventDefault = !this.options.eventPassthrough && this.options.preventDefault; 18671 18672 // If you want eventPassthrough I have to lock one of the axes 18673 this.options.scrollY = this.options.eventPassthrough == 'vertical' ? false : this.options.scrollY; 18674 this.options.scrollX = this.options.eventPassthrough == 'horizontal' ? false : this.options.scrollX; 18675 18676 // With eventPassthrough we also need lockDirection mechanism 18677 this.options.freeScroll = this.options.freeScroll && !this.options.eventPassthrough; 18678 this.options.directionLockThreshold = this.options.eventPassthrough ? 0 : this.options.directionLockThreshold; 18679 18680 this.options.bounceEasing = typeof this.options.bounceEasing == 'string' ? utils.ease[this.options.bounceEasing] || utils.ease.circular : this.options.bounceEasing; 18681 18682 this.options.resizePolling = this.options.resizePolling === undefined ? 60 : this.options.resizePolling; 18683 18684 if ( this.options.tap === true ) { 18685 this.options.tap = 'tap'; 18686 } 18687 18688 // https://github.com/cubiq/iscroll/issues/1029 18689 if (!this.options.useTransition && !this.options.useTransform) { 18690 if(!(/relative|absolute/i).test(this.scrollerStyle.position)) { 18691 this.scrollerStyle.position = "relative"; 18692 } 18693 } 18694 18695 if ( this.options.shrinkScrollbars == 'scale' ) { 18696 this.options.useTransition = false; 18697 } 18698 18699 this.options.invertWheelDirection = this.options.invertWheelDirection ? -1 : 1; 18700 18701// INSERT POINT: NORMALIZATION 18702 18703 // Some defaults 18704 this.x = 0; 18705 this.y = 0; 18706 this.directionX = 0; 18707 this.directionY = 0; 18708 this._events = {}; 18709 18710// INSERT POINT: DEFAULTS 18711 18712 this._init(); 18713 this.refresh(); 18714 18715 this.scrollTo(this.options.startX, this.options.startY); 18716 this.enable(); 18717} 18718 18719IScroll.prototype = { 18720 version: '5.2.0', 18721 18722 _init: function () { 18723 this._initEvents(); 18724 18725 if ( this.options.scrollbars || this.options.indicators ) { 18726 this._initIndicators(); 18727 } 18728 18729 if ( this.options.mouseWheel ) { 18730 this._initWheel(); 18731 } 18732 18733 if ( this.options.snap ) { 18734 this._initSnap(); 18735 } 18736 18737 if ( this.options.keyBindings ) { 18738 this._initKeys(); 18739 } 18740 18741// INSERT POINT: _init 18742 18743 }, 18744 18745 destroy: function () { 18746 this._initEvents(true); 18747 clearTimeout(this.resizeTimeout); 18748 this.resizeTimeout = null; 18749 this._execEvent('destroy'); 18750 }, 18751 18752 _transitionEnd: function (e) { 18753 if ( e.target != this.scroller || !this.isInTransition ) { 18754 return; 18755 } 18756 18757 this._transitionTime(); 18758 if ( !this.resetPosition(this.options.bounceTime) ) { 18759 this.isInTransition = false; 18760 this._execEvent('scrollEnd'); 18761 } 18762 }, 18763 18764 _start: function (e) { 18765 // React to left mouse button only 18766 if ( utils.eventType[e.type] != 1 ) { 18767 // for button property 18768 // http://unixpapa.com/js/mouse.html 18769 var button; 18770 if (!e.which) { 18771 /* IE case */ 18772 button = (e.button < 2) ? 0 : 18773 ((e.button == 4) ? 1 : 2); 18774 } else { 18775 /* All others */ 18776 button = e.button; 18777 } 18778 if ( button !== 0 ) { 18779 return; 18780 } 18781 } 18782 18783 if ( !this.enabled || (this.initiated && utils.eventType[e.type] !== this.initiated) ) { 18784 return; 18785 } 18786 18787 if ( this.options.preventDefault && !utils.isBadAndroid && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) { 18788 e.preventDefault(); 18789 } 18790 18791 var point = e.touches ? e.touches[0] : e, 18792 pos; 18793 18794 this.initiated = utils.eventType[e.type]; 18795 this.moved = false;
18796 this.distX = 0; 18797 this.distY = 0; 18798 this.directionX = 0; 18799 this.directionY = 0; 18800 this.directionLocked = 0; 18801 18802 this.startTime = utils.getTime(); 18803 18804 if ( this.options.useTransition && this.isInTransition ) { 18805 this._transitionTime(); 18806 this.isInTransition = false; 18807 pos = this.getComputedPosition(); 18808 this._translate(Math.round(pos.x), Math.round(pos.y)); 18809 this._execEvent('scrollEnd'); 18810 } else if ( !this.options.useTransition && this.isAnimating ) { 18811 this.isAnimating = false; 18812 this._execEvent('scrollEnd'); 18813 } 18814 18815 this.startX = this.x; 18816 this.startY = this.y; 18817 this.absStartX = this.x; 18818 this.absStartY = this.y; 18819 this.pointX = point.pageX; 18820 this.pointY = point.pageY; 18821 18822 this._execEvent('beforeScrollStart'); 18823 }, 18824 18825 _move: function (e) { 18826 if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) { 18827 return; 18828 } 18829 18830 if ( this.options.preventDefault ) { // increases performance on Android? TODO: check! 18831 e.preventDefault(); 18832 } 18833 18834 var point = e.touches ? e.touches[0] : e, 18835 deltaX = point.pageX - this.pointX, 18836 deltaY = point.pageY - this.pointY, 18837 timestamp = utils.getTime(), 18838 newX, newY, 18839 absDistX, absDistY; 18840 18841 this.pointX = point.pageX; 18842 this.pointY = point.pageY; 18843 18844 this.distX += deltaX; 18845 this.distY += deltaY; 18846 absDistX = Math.abs(this.distX); 18847 absDistY = Math.abs(this.distY); 18848 18849 // We need to move at least 10 pixels for the scrolling to initiate 18850 if ( timestamp - this.endTime > 300 && (absDistX < 10 && absDistY < 10) ) { 18851 return; 18852 } 18853 18854 // If you are scrolling in one direction lock the other 18855 if ( !this.directionLocked && !this.options.freeScroll ) { 18856 if ( absDistX > absDistY + this.options.directionLockThreshold ) { 18857 this.directionLocked = 'h'; // lock horizontally 18858 } else if ( absDistY >= absDistX + this.options.directionLockThreshold ) { 18859 this.directionLocked = 'v'; // lock vertically 18860 } else { 18861 this.directionLocked = 'n'; // no lock 18862 } 18863 } 18864 18865 if ( this.directionLocked == 'h' ) { 18866 if ( this.options.eventPassthrough == 'vertical' ) { 18867 e.preventDefault(); 18868 } else if ( this.options.eventPassthrough == 'horizontal' ) { 18869 this.initiated = false; 18870 return; 18871 } 18872 18873 deltaY = 0; 18874 } else if ( this.directionLocked == 'v' ) { 18875 if ( this.options.eventPassthrough == 'horizontal' ) { 18876 e.preventDefault(); 18877 } else if ( this.options.eventPassthrough == 'vertical' ) { 18878 this.initiated = false; 18879 return; 18880 } 18881 18882 deltaX = 0; 18883 } 18884 18885 deltaX = this.hasHorizontalScroll ? deltaX : 0; 18886 deltaY = this.hasVerticalScroll ? deltaY : 0; 18887 18888 newX = this.x + deltaX; 18889 newY = this.y + deltaY; 18890 18891 // Slow down if outside of the boundaries 18892 if ( newX > 0 || newX < this.maxScrollX ) { 18893 newX = this.options.bounce ? this.x + deltaX / 3 : newX > 0 ? 0 : this.maxScrollX; 18894 } 18895 if ( newY > 0 || newY < this.maxScrollY ) { 18896 newY = this.options.bounce ? this.y + deltaY / 3 : newY > 0 ? 0 : this.maxScrollY; 18897 } 18898 18899 this.directionX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0; 18900 this.directionY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0; 18901 18902 if ( !this.moved ) { 18903 this._execEvent('scrollStart'); 18904 } 18905 18906 this.moved = true; 18907 18908 this._translate(newX, newY); 18909 18910/* REPLACE START: _move */ 18911 18912 if ( timestamp - this.startTime > 300 ) { 18913 this.startTime = timestamp; 18914 this.startX = this.x; 18915 this.startY = this.y; 18916 } 18917 18918/* REPLACE END: _move */ 18919 18920 }, 18921 18922 _end: function (e) { 18923 if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) { 18924 return; 18925 } 18926 18927 if ( this.options.preventDefault && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) { 18928 e.preventDefault(); 18929 } 18930 18931 var point = e.changedTouches ? e.changedTouches[0] : e, 18932 momentumX, 18933 momentumY, 18934 duration = utils.getTime() - this.startTime, 18935 newX = Math.round(this.x), 18936 newY = Math.round(this.y), 18937 distanceX = Math.abs(newX - this.startX), 18938 distanceY = Math.abs(newY - this.startY), 18939 time = 0, 18940 easing = ''; 18941 18942 this.isInTransition = 0; 18943 this.initiated = 0; 18944 this.endTime = utils.getTime(); 18945 18946 // reset if we are outside of the boundaries 18947 if ( this.resetPosition(this.options.bounceTime) ) { 18948 return; 18949 } 18950 18951 this.scrollTo(newX, newY); // ensures that the last position is rounded 18952 18953 // we scrolled less than 10 pixels 18954 if ( !this.moved ) { 18955 if ( this.options.tap ) { 18956 utils.tap(e, this.options.tap); 18957 } 18958 18959 if ( this.options.click ) { 18960 utils.click(e); 18961 } 18962 18963 this._execEvent('scrollCancel'); 18964 return; 18965 } 18966 18967 if ( this._events.flick && duration < 200 && distanceX < 100 && distanceY < 100 ) { 18968 this._execEvent('flick'); 18969 return; 18970 } 18971 18972 // start momentum animation if needed 18973 if ( this.options.momentum && duration < 300 ) { 18974 momentumX = this.hasHorizontalScroll ? utils.momentum(this.x, this.startX, duration, this.maxScrollX, this.options.bounce ? this.wrapperW
18974idth : 0, this.options.deceleration) : { destination: newX, duration: 0 }; 18975 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 }; 18976 newX = momentumX.destination; 18977 newY = momentumY.destination; 18978 time = Math.max(momentumX.duration, momentumY.duration); 18979 this.isInTransition = 1; 18980 } 18981 18982 18983 if ( this.options.snap ) { 18984 var snap = this._nearestSnap(newX, newY); 18985 this.currentPage = snap; 18986 time = this.options.snapSpeed || Math.max( 18987 Math.max( 18988 Math.min(Math.abs(newX - snap.x), 1000), 18989 Math.min(Math.abs(newY - snap.y), 1000) 18990 ), 300); 18991 newX = snap.x; 18992 newY = snap.y; 18993 18994 this.directionX = 0; 18995 this.directionY = 0; 18996 easing = this.options.bounceEasing; 18997 } 18998 18999// INSERT POINT: _end 19000 19001 if ( newX != this.x || newY != this.y ) { 19002 // change easing function when scroller goes out of the boundaries 19003 if ( newX > 0 || newX < this.maxScrollX || newY > 0 || newY < this.maxScrollY ) { 19004 easing = utils.ease.quadratic; 19005 } 19006 19007 this.scrollTo(newX, newY, time, easing); 19008 return; 19009 } 19010 19011 this._execEvent('scrollEnd'); 19012 }, 19013 19014 _resize: function () { 19015 var that = this; 19016 19017 clearTimeout(this.resizeTimeout); 19018 19019 this.resizeTimeout = setTimeout(function () { 19020 that.refresh(); 19021 }, this.options.resizePolling); 19022 }, 19023 19024 resetPosition: function (time) { 19025 var x = this.x, 19026 y = this.y; 19027 19028 time = time || 0; 19029 19030 if ( !this.hasHorizontalScroll || this.x > 0 ) { 19031 x = 0; 19032 } else if ( this.x < this.maxScrollX ) { 19033 x = this.maxScrollX; 19034 } 19035 19036 if ( !this.hasVerticalScroll || this.y > 0 ) { 19037 y = 0; 19038 } else if ( this.y < this.maxScrollY ) { 19039 y = this.maxScrollY; 19040 } 19041 19042 if ( x == this.x && y == this.y ) { 19043 return false; 19044 } 19045 19046 this.scrollTo(x, y, time, this.options.bounceEasing); 19047 19048 return true; 19049 }, 19050 19051 disable: function () { 19052 this.enabled = false; 19053 }, 19054 19055 enable: function () { 19056 this.enabled = true; 19057 }, 19058 19059 refresh: function () { 19060 var rf = this.wrapper.offsetHeight; // Force reflow 19061 19062 this.wrapperWidth = this.wrapper.clientWidth; 19063 this.wrapperHeight = this.wrapper.clientHeight; 19064 19065/* REPLACE START: refresh */ 19066 19067 this.scrollerWidth = this.scroller.offsetWidth; 19068 this.scrollerHeight = this.scroller.offsetHeight; 19069 19070 this.maxScrollX = this.wrapperWidth - this.scrollerWidth; 19071 this.maxScrollY = this.wrapperHeight - this.scrollerHeight; 19072 19073/* REPLACE END: refresh */ 19074 19075 this.hasHorizontalScroll = this.options.scrollX && this.maxScrollX < 0; 19076 this.hasVerticalScroll = this.options.scrollY && this.maxScrollY < 0; 19077 19078 if ( !this.hasHorizontalScroll ) { 19079 this.maxScrollX = 0; 19080 this.scrollerWidth = this.wrapperWidth; 19081 } 19082 19083 if ( !this.hasVerticalScroll ) { 19084 this.maxScrollY = 0; 19085 this.scrollerHeight = this.wrapperHeight; 19086 } 19087 19088 this.endTime = 0; 19089 this.directionX = 0; 19090 this.directionY = 0; 19091 19092 this.wrapperOffset = utils.offset(this.wrapper); 19093 19094 this._execEvent('refresh'); 19095 19096 this.resetPosition(); 19097 19098// INSERT POINT: _refresh 19099 19100 }, 19101 19102 on: function (type, fn) { 19103 if ( !this._events[type] ) { 19104 this._events[type] = []; 19105 } 19106 19107 this._events[type].push(fn); 19108 }, 19109 19110 off: function (type, fn) { 19111 if ( !this._events[type] ) { 19112 return; 19113 } 19114 19115 var index = this._events[type].indexOf(fn); 19116 19117 if ( index > -1 ) { 19118 this._events[type].splice(index, 1); 19119 } 19120 }, 19121 19122 _execEvent: function (type) { 19123 if ( !this._events[type] ) { 19124 return; 19125 } 19126 19127 var i = 0, 19128 l = this._events[type].length; 19129 19130 if ( !l ) { 19131 return; 19132 } 19133 19134 for ( ; i < l; i++ ) { 19135 this._events[type][i].apply(this, [].slice.call(arguments, 1)); 19136 } 19137 }, 19138 19139 scrollBy: function (x, y, time, easing) { 19140 x = this.x + x; 19141 y = this.y + y; 19142 time = time || 0; 19143 19144 this.scrollTo(x, y, time, easing); 19145 }, 19146 19147 scrollTo: function (x, y, time, easing) { 19148 easing = easing || utils.ease.circular; 19149 19150 this.isInTransition = this.options.useTransition && time > 0; 19151 var transitionType = this.options.useTransition && easing.style; 19152 if ( !time || transitionType ) { 19153 if(transitionType) { 19154 this._transitionTimingFunction(easing.style); 19155 this._transitionTime(time); 19156 } 19157 this._translate(x, y); 19158 } else { 19159 this._animate(x, y, time, easing.fn); 19160 } 19161 }, 19162 19163 scrollToElement: function (el, time, offsetX, offsetY, easing) { 19164 el = el.nodeType ? el : this.scroller.querySelector(el); 19165 19166 if ( !el ) { 19167 return; 19168 } 19169 19170 var pos = utils.offset(el); 19171 19172 pos.left -= this.wrapperOffset.left; 19173 pos.top -= this.wrapperOffset.top; 19174 19175 // if offsetX/Y are true we center the element to the screen 19176 if ( offsetX === true ) { 19177 offsetX = Math.round(el.offsetWidth / 2 - this.wrapper.offsetWidth / 2); 19178 } 19179 if ( offsetY === true ) { 19180 offsetY = Math.round(el.offsetHeight / 2 - this.wrapper.offsetHeight / 2); 19181 } 19182 19183 pos.left -= offsetX || 0; 19184 pos.top -= offsetY || 0; 19185 19186 pos.left = pos.left > 0 ? 0 : pos.left < this.maxScrollX ? this.maxScrollX : pos.left; 19187 pos.top = pos.top > 0 ? 0 : pos.top < this.maxScrollY ? this.maxScrollY : pos.top; 19188 19189 time = time === undefined || time === null || time === 'auto' ? Math.max(Math.abs(this.x-pos.left), Math.abs(this.y-pos.top)) : time; 19190 19191 this.scrollTo(pos.left, pos.top, time, easing); 19192 }, 19193 19194 _transitionTime: function (time) { 19195 if (!this.options.useTransition) { 19196 return; 19197 } 19198 time = time || 0; 19199 var durationProp = utils.style.transitionDuration; 19200 if(!durationProp) { 19201 return; 19202 } 19203 19204 this.scrollerStyle[durationProp] = time + 'ms'; 19205 19206 if ( !time && utils.isBadAndroid ) { 19207 this.scrollerStyle[durationProp] = '0.0001ms'; 19208 // remove 0.0001ms 19209 var self = this; 19210 rAF(function() { 19211 if(self.scrollerStyle[durationProp] === '0.0001ms') { 19212 self.scrollerStyle[durationProp] = '0s'; 19213 } 19214 }); 19215 } 19216 19217 19218 if ( this.indicators ) { 19219 for ( var i = this.indicators.length; i--; ) { 19220 this.indicators[i].transitionTime(time); 19221 } 19222 } 19223 19224 19225// INSERT POINT: _transitionTime 19226 19227 }, 19228 19229 _transitionTimingFunction: function (easing) { 19230 this.scrollerStyle[utils.style.transitionTimingFunction] = easing; 19231 19232 19233 if ( this.indicators ) { 19234 for ( var i = this.indicators.length; i--; ) { 19235 this.indicators[i].transitionTimingFunction(easing); 19236 } 19237 } 19238 19239 19240// INSERT POINT: _transitionTimingFunction 19241 19242 }, 19243 19244 _translate: function (x, y) { 19245 //Uncode addition 19246 if ( (" " + this.wrapper.className + " ").replace(/[\n\t]/g, " ").indexOf(" no-scrolloverflow ") > -1 ) 19247 return false;
19248 19249 if ( this.options.useTransform ) { 19250 19251/* REPLACE START: _translate */ 19252 19253 this.scrollerStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.translateZ; 19254 19255/* REPLACE END: _translate */ 19256 19257 } else { 19258 x = Math.round(x); 19259 y = Math.round(y); 19260 this.scrollerStyle.left = x + 'px'; 19261 this.scrollerStyle.top = y + 'px'; 19262 } 19263 19264 this.x = x; 19265 this.y = y; 19266 19267 19268 if ( this.indicators ) { 19269 for ( var i = this.indicators.length; i--; ) { 19270 this.indicators[i].updatePosition(); 19271 } 19272 } 19273 19274 //Uncode addition 19275 var uncodevent = new CustomEvent('fp-slide-scroll'); 19276 window.dispatchEvent(uncodevent); 19277 19278// INSERT POINT: _translate 19279 19280 }, 19281 19282 _initEvents: function (remove) { 19283 var eventType = remove ? utils.removeEvent : utils.addEvent, 19284 target = this.options.bindToWrapper ? this.wrapper : window; 19285 19286 eventType(window, 'orientationchange', this); 19287 eventType(window, 'resize', this); 19288 19289 if ( this.options.click ) { 19290 eventType(this.wrapper, 'click', this, true); 19291 } 19292 19293 if ( !this.options.disableMouse ) { 19294 eventType(this.wrapper, 'mousedown', this); 19295 eventType(target, 'mousemove', this); 19296 eventType(target, 'mousecancel', this); 19297 eventType(target, 'mouseup', this); 19298 } 19299 19300 if ( utils.hasPointer && !this.options.disablePointer ) { 19301 eventType(this.wrapper, utils.prefixPointerEvent('pointerdown'), this); 19302 eventType(target, utils.prefixPointerEvent('pointermove'), this); 19303 eventType(target, utils.prefixPointerEvent('pointercancel'), this); 19304 eventType(target, utils.prefixPointerEvent('pointerup'), this); 19305 } 19306 19307 if ( utils.hasTouch && !this.options.disableTouch ) { 19308 eventType(this.wrapper, 'touchstart', this); 19309 eventType(target, 'touchmove', this); 19310 eventType(target, 'touchcancel', this); 19311 eventType(target, 'touchend', this); 19312 } 19313 19314 eventType(this.scroller, 'transitionend', this); 19315 eventType(this.scroller, 'webkitTransitionEnd', this); 19316 eventType(this.scroller, 'oTransitionEnd', this); 19317 eventType(this.scroller, 'MSTransitionEnd', this); 19318 }, 19319 19320 getComputedPosition: function () { 19321 var matrix = window.getComputedStyle(this.scroller, null), 19322 x, y; 19323 19324 if ( this.options.useTransform ) { 19325 matrix = matrix[utils.style.transform].split(')')[0].split(', '); 19326 x = +(matrix[12] || matrix[4]); 19327 y = +(matrix[13] || matrix[5]); 19328 } else { 19329 x = +matrix.left.replace(/[^-\d.]/g, ''); 19330 y = +matrix.top.replace(/[^-\d.]/g, ''); 19331 } 19332 19333 return { x: x, y: y }; 19334 }, 19335 _initIndicators: function () { 19336 var interactive = this.options.interactiveScrollbars, 19337 customStyle = typeof this.options.scrollbars != 'string', 19338 indicators = [], 19339 indicator; 19340 19341 var that = this; 19342 19343 this.indicators = []; 19344 19345 if ( this.options.scrollbars ) { 19346 // Vertical scrollbar 19347 if ( this.options.scrollY ) { 19348 indicator = { 19349 el: createDefaultScrollbar('v', interactive, this.options.scrollbars), 19350 interactive: interactive, 19351 defaultScrollbars: true, 19352 customStyle: customStyle, 19353 resize: this.options.resizeScrollbars, 19354 shrink: this.options.shrinkScrollbars, 19355 fade: this.options.fadeScrollbars, 19356 listenX: false 19357 }; 19358 19359 this.wrapper.appendChild(indicator.el); 19360 indicators.push(indicator); 19361 } 19362 19363 // Horizontal scrollbar 19364 if ( this.options.scrollX ) { 19365 indicator = { 19366 el: createDefaultScrollbar('h', interactive, this.options.scrollbars), 19367 interactive: interactive, 19368 defaultScrollbars: true, 19369 customStyle: customStyle, 19370 resize: this.options.resizeScrollbars, 19371 shrink: this.options.shrinkScrollbars, 19372 fade: this.options.fadeScrollbars, 19373 listenY: false 19374 }; 19375 19376 this.wrapper.appendChild(indicator.el); 19377 indicators.push(indicator); 19378 } 19379 } 19380 19381 if ( this.options.indicators ) { 19382 // TODO: check concat compatibility 19383 indicators = indicators.concat(this.options.indicators); 19384 } 19385 19386 for ( var i = indicators.length; i--; ) { 19387 this.indicators.push( new Indicator(this, indicators[i]) ); 19388 } 19389 19390 // TODO: check if we can use array.map (wide compatibility and performance issues) 19391 function _indicatorsMap (fn) { 19392 if (that.indicators) { 19393 for ( var i = that.indicators.length; i--; ) { 19394 fn.call(that.indicators[i]); 19395 } 19396 } 19397 } 19398 19399 if ( this.options.fadeScrollbars ) { 19400 this.on('scrollEnd', function () { 19401 _indicatorsMap(function () { 19402 this.fade(); 19403 }); 19404 }); 19405 19406 this.on('scrollCancel', function () { 19407 _indicatorsMap(function () { 19408 this.fade(); 19409 }); 19410 }); 19411 19412 this.on('scrollStart', function () { 19413 _indicatorsMap(function () { 19414 this.fade(1); 19415 }); 19416 }); 19417 19418 this.on('beforeScrollStart', function () { 19419 _indicatorsMap(function () { 19420 this.fade(1, true); 19421 }); 19422 }); 19423 } 19424 19425 19426 this.on('refresh', function () { 19427 _indicatorsMap(function () { 19428 this.refresh(); 19429 }); 19430 }); 19431 19432 this.on('destroy', function () { 19433 _indicatorsMap(function () { 19434 this.destroy(); 19435 }); 19436 19437 delete this.indicators; 19438 }); 19439 }, 19440 19441 _initWheel: function () { 19442 utils.addEvent(this.wrapper, 'wheel', this); 19443 utils.addEvent(this.wrapper, 'mousewheel', this); 19444 utils.addEvent(this.wrapper, 'DOMMouseScroll', this); 19445 19446 this.on('destroy', function () { 19447 clearTimeout(this.wheelTimeout); 19448 this.wheelTimeout = null; 19449 utils.removeEvent(this.wrapper, 'wheel', this); 19450 utils.removeEvent(this.wrapper, 'mousewheel', this); 19451 utils.removeEvent(this.wrapper, 'DOMMouseScroll', this); 19452 }); 19453 }, 19454 19455 _wheel: function (e) { 19456 if ( !this.enabled ) { 19457 return; 19458 } 19459 19460 var wheelDeltaX, wheelDeltaY, 19461 newX, newY, 19462 that = this; 19463 19464 if ( this.wheelTimeout === undefined ) { 19465 that._execEvent('scrollStart'); 19466 } 19467 19468 // Execute the scrollEnd event after 400ms the wheel stopped scrolling 19469 clearTimeout(this.wheelTimeout); 19470 this.wheelTimeout = setTimeout(function () { 19471 if(!that.options.snap) { 19472 that._execEvent('scrollEnd'); 19473 } 19474 that.wheelTimeout = undefined; 19475 }, 400); 19476 19477 if ( 'deltaX' in e ) { 19478 if (e.deltaMode === 1) { 19479 wheelDeltaX = -e.deltaX * this.options.mouseWheelSpeed; 19480 wheelDeltaY = -e.deltaY * this.options.mouseWheelSpeed; 19481 } else { 19482 wheelDeltaX = -e.deltaX; 19483 wheelDeltaY = -e.deltaY; 19484 } 19485 } else if ( 'wheelDeltaX' in e ) { 19486 wheelDeltaX = e.wheelDeltaX / 120 * this.options.mouseWheelSpeed; 19487 wheelDeltaY = e.wheelDeltaY / 120 * this.options.mouseWheelSpeed; 19488 } else if ( 'wheelDelta' in e ) { 19489 wheelDeltaX = wheelDeltaY = e.wheelDelta / 120 * this.options.mouseWheelSpeed; 19490 } else if ( 'detail' in e ) { 19491 wheelDeltaX = wheelDeltaY = -e.detail / 3 * this.options.mouseWheelSpeed; 19492 } else { 19493 return; 19494 } 19495 19496 wheelDeltaX *= this.options.invertWheelDirection; 19497 wheelDeltaY *= this.options.invertWheelDirection; 19498 19499 if ( !this.hasVerticalScroll ) { 19500 wheelDeltaX = wheelDeltaY; 19501 wheelDeltaY = 0; 19502 } 19503 19504 if ( this.options.snap ) { 19505 newX = this.currentPage.pageX; 19506 newY = this.currentPage.pageY; 19507 19508 if ( wheelDeltaX > 0 ) { 19509 newX--; 19510 } else if ( wheelDeltaX < 0 ) { 19511 newX++; 19512 } 19513 19514 if ( wheelDeltaY > 0 ) { 19515 newY--; 19516 } else if ( wheelDeltaY < 0 ) { 19517 newY++; 19518 } 19519 19520 this.goToPage(newX, newY); 19521 19522 return; 19523 } 19524 19525 newX = this.x + Math.round(this.hasHorizontalScroll ? wheelDeltaX : 0); 19526 newY = this.y + Math.round(this.hasVerticalScroll ? wheelDeltaY : 0); 19527 19528 this.directionX = wheelDeltaX > 0 ? -1 : wheelDeltaX < 0 ? 1 : 0; 19529 this.directionY = wheelDeltaY > 0 ? -1 : wheelDeltaY < 0 ? 1 : 0; 19530 19531 if ( newX > 0 ) { 19532 newX = 0; 19533 } else if ( newX < this.maxScrollX ) { 19534 newX = this.maxScrollX; 19535 } 19536 19537 if ( newY > 0 ) { 19538 newY = 0; 19539 } else if ( newY < this.maxScrollY ) { 19540 newY = this.maxScrollY; 19541 } 19542 19543 this.scrollTo(newX, newY, 0); 19544 19545// INSERT POINT: _wheel 19546 }, 19547 19548 _initSnap: function () { 19549 this.currentPage = {}; 19550 19551 if ( typeof this.options.snap == 'string' ) { 19552 this.options.snap = this.scroller.querySelectorAll(this.options.snap); 19553 } 19554 19555 this.on('refresh', function () { 19556 var i = 0, l, 19557 m = 0, n, 19558 cx, cy, 19559 x = 0, y,
19560 stepX = this.options.snapStepX || this.wrapperWidth, 19561 stepY = this.options.snapStepY || this.wrapperHeight, 19562 el; 19563 19564 this.pages = []; 19565 19566 if ( !this.wrapperWidth || !this.wrapperHeight || !this.scrollerWidth || !this.scrollerHeight ) { 19567 return; 19568 } 19569 19570 if ( this.options.snap === true ) { 19571 cx = Math.round( stepX / 2 ); 19572 cy = Math.round( stepY / 2 ); 19573 19574 while ( x > -this.scrollerWidth ) { 19575 this.pages[i] = []; 19576 l = 0; 19577 y = 0; 19578 19579 while ( y > -this.scrollerHeight ) { 19580 this.pages[i][l] = { 19581 x: Math.max(x, this.maxScrollX), 19582 y: Math.max(y, this.maxScrollY), 19583 width: stepX, 19584 height: stepY, 19585 cx: x - cx, 19586 cy: y - cy 19587 }; 19588 19589 y -= stepY; 19590 l++; 19591 } 19592 19593 x -= stepX; 19594 i++; 19595 } 19596 } else { 19597 el = this.options.snap; 19598 l = el.length; 19599 n = -1; 19600 19601 for ( ; i < l; i++ ) { 19602 if ( i === 0 || el[i].offsetLeft <= el[i-1].offsetLeft ) { 19603 m = 0; 19604 n++; 19605 } 19606 19607 if ( !this.pages[m] ) { 19608 this.pages[m] = []; 19609 } 19610 19611 x = Math.max(-el[i].offsetLeft, this.maxScrollX); 19612 y = Math.max(-el[i].offsetTop, this.maxScrollY); 19613 cx = x - Math.round(el[i].offsetWidth / 2); 19614 cy = y - Math.round(el[i].offsetHeight / 2); 19615 19616 this.pages[m][n] = { 19617 x: x, 19618 y: y, 19619 width: el[i].offsetWidth, 19620 height: el[i].offsetHeight, 19621 cx: cx, 19622 cy: cy 19623 }; 19624 19625 if ( x > this.maxScrollX ) { 19626 m++; 19627 } 19628 } 19629 } 19630 19631 this.goToPage(this.currentPage.pageX || 0, this.currentPage.pageY || 0, 0); 19632 19633 // Update snap threshold if needed 19634 if ( this.options.snapThreshold % 1 === 0 ) { 19635 this.snapThresholdX = this.options.snapThreshold; 19636 this.snapThresholdY = this.options.snapThreshold; 19637 } else { 19638 this.snapThresholdX = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].width * this.options.snapThreshold); 19639 this.snapThresholdY = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].height * this.options.snapThreshold); 19640 } 19641 }); 19642 19643 this.on('flick', function () { 19644 var time = this.options.snapSpeed || Math.max( 19645 Math.max( 19646 Math.min(Math.abs(this.x - this.startX), 1000), 19647 Math.min(Math.abs(this.y - this.startY), 1000) 19648 ), 300); 19649 19650 this.goToPage( 19651 this.currentPage.pageX + this.directionX, 19652 this.currentPage.pageY + this.directionY, 19653 time 19654 ); 19655 }); 19656 }, 19657 19658 _nearestSnap: function (x, y) { 19659 if ( !this.pages.length ) { 19660 return { x: 0, y: 0, pageX: 0, pageY: 0 }; 19661 } 19662 19663 var i = 0, 19664 l = this.pages.length, 19665 m = 0; 19666 19667 // Check if we exceeded the snap threshold 19668 if ( Math.abs(x - this.absStartX) < this.snapThresholdX && 19669 Math.abs(y - this.absStartY) < this.snapThresholdY ) { 19670 return this.currentPage; 19671 } 19672 19673 if ( x > 0 ) { 19674 x = 0; 19675 } else if ( x < this.maxScrollX ) { 19676 x = this.maxScrollX; 19677 } 19678 19679 if ( y > 0 ) { 19680 y = 0; 19681 } else if ( y < this.maxScrollY ) { 19682 y = this.maxScrollY; 19683 } 19684 19685 for ( ; i < l; i++ ) { 19686 if ( x >= this.pages[i][0].cx ) { 19687 x = this.pages[i][0].x; 19688 break; 19689 } 19690 } 19691 19692 l = this.pages[i].length; 19693 19694 for ( ; m < l; m++ ) { 19695 if ( y >= this.pages[0][m].cy ) { 19696 y = this.pages[0][m].y; 19697 break; 19698 } 19699 } 19700 19701 if ( i == this.currentPage.pageX ) { 19702 i += this.directionX; 19703 19704 if ( i < 0 ) { 19705 i = 0; 19706 } else if ( i >= this.pages.length ) { 19707 i = this.pages.length - 1; 19708 } 19709 19710 x = this.pages[i][0].x; 19711 } 19712 19713 if ( m == this.currentPage.pageY ) { 19714 m += this.directionY; 19715 19716 if ( m < 0 ) { 19717 m = 0; 19718 } else if ( m >= this.pages[0].length ) { 19719 m = this.pages[0].length - 1; 19720 } 19721 19722 y = this.pages[0][m].y; 19723 } 19724 19725 return { 19726 x: x, 19727 y: y, 19728 pageX: i, 19729 pageY: m 19730 }; 19731 }, 19732 19733 goToPage: function (x, y, time, easing) { 19734 easing = easing || this.options.bounceEasing; 19735 19736 if ( x >= this.pages.length ) { 19737 x = this.pages.length - 1; 19738 } else if ( x < 0 ) { 19739 x = 0; 19740 } 19741 19742 if ( y >= this.pages[x].length ) { 19743 y = this.pages[x].length - 1; 19744 } else if ( y < 0 ) { 19745 y = 0; 19746 } 19747 19748 var posX = this.pages[x][y].x, 19749 posY = this.pages[x][y].y; 19750 19751 time = time === undefined ? this.options.snapSpeed || Math.max( 19752 Math.max( 19753 Math.min(Math.abs(posX - this.x), 1000), 19754 Math.min(Math.abs(posY - this.y), 1000) 19755 ), 300) : time; 19756 19757 this.currentPage = { 19758 x: posX, 19759 y: posY, 19760 pageX: x, 19761 pageY: y 19762 }; 19763 19764 this.scrollTo(posX, posY, time, easing); 19765 }, 19766 19767 next: function (time, easing) { 19768 var x = this.currentPage.pageX, 19769 y = this.currentPage.pageY; 19770 19771 x++; 19772 19773 if ( x >= this.pages.length && this.hasVerticalScroll ) { 19774 x = 0; 19775 y++; 19776 } 19777 19778 this.goToPage(x, y, time, easing); 19779 }, 19780 19781 prev: function (time, easing) { 19782 var x = this.currentPage.pageX, 19783 y = this.currentPage.pageY; 19784 19785 x--; 19786 19787 if ( x < 0 && this.hasVerticalScroll ) { 19788 x = 0; 19789 y--; 19790 } 19791 19792 this.goToPage(x, y, time, easing); 19793 }, 19794 19795 _initKeys: function (e) { 19796 // default key bindings 19797 var keys = { 19798 pageUp: 33, 19799 pageDown: 34, 19800 end: 35, 19801 home: 36, 19802 left: 37, 19803 up: 38, 19804 right: 39, 19805 down: 40 19806 }; 19807 var i; 19808 19809 // if you give me characters I give you keycode 19810 if ( typeof this.options.keyBindings == 'object' ) { 19811 for ( i in this.options.keyBindings ) { 19812 if ( typeof this.options.keyBindings[i] == 'string' ) { 19813 this.options.keyBindings[i] = this.options.keyBindings[i].toUpperCase().charCo
19813deAt(0); 19814 } 19815 } 19816 } else { 19817 this.options.keyBindings = {}; 19818 } 19819 19820 for ( i in keys ) { 19821 this.options.keyBindings[i] = this.options.keyBindings[i] || keys[i]; 19822 } 19823 19824 utils.addEvent(window, 'keydown', this); 19825 19826 this.on('destroy', function () { 19827 utils.removeEvent(window, 'keydown', this); 19828 }); 19829 }, 19830 19831 _key: function (e) { 19832 if ( !this.enabled ) { 19833 return; 19834 } 19835 19836 var snap = this.options.snap, // we are using this alot, better to cache it 19837 newX = snap ? this.currentPage.pageX : this.x, 19838 newY = snap ? this.currentPage.pageY : this.y, 19839 now = utils.getTime(), 19840 prevTime = this.keyTime || 0, 19841 acceleration = 0.250, 19842 pos; 19843 19844 if ( this.options.useTransition && this.isInTransition ) { 19845 pos = this.getComputedPosition(); 19846 19847 this._translate(Math.round(pos.x), Math.round(pos.y)); 19848 this.isInTransition = false; 19849 } 19850 19851 this.keyAcceleration = now - prevTime < 200 ? Math.min(this.keyAcceleration + acceleration, 50) : 0; 19852 19853 switch ( e.keyCode ) { 19854 case this.options.keyBindings.pageUp: 19855 if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) { 19856 newX += snap ? 1 : this.wrapperWidth; 19857 } else { 19858 newY += snap ? 1 : this.wrapperHeight; 19859 } 19860 break; 19861 case this.options.keyBindings.pageDown: 19862 if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) { 19863 newX -= snap ? 1 : this.wrapperWidth; 19864 } else { 19865 newY -= snap ? 1 : this.wrapperHeight; 19866 } 19867 break; 19868 case this.options.keyBindings.end: 19869 newX = snap ? this.pages.length-1 : this.maxScrollX; 19870 newY = snap ? this.pages[0].length-1 : this.maxScrollY; 19871 break; 19872 case this.options.keyBindings.home: 19873 newX = 0; 19874 newY = 0; 19875 break; 19876 case this.options.keyBindings.left: 19877 newX += snap ? -1 : 5 + this.keyAcceleration>>0; 19878 break; 19879 case this.options.keyBindings.up: 19880 newY += snap ? 1 : 5 + this.keyAcceleration>>0; 19881 break; 19882 case this.options.keyBindings.right: 19883 newX -= snap ? -1 : 5 + this.keyAcceleration>>0; 19884 break; 19885 case this.options.keyBindings.down: 19886 newY -= snap ? 1 : 5 + this.keyAcceleration>>0; 19887 break; 19888 default: 19889 return; 19890 } 19891 19892 if ( snap ) { 19893 this.goToPage(newX, newY); 19894 return; 19895 } 19896 19897 if ( newX > 0 ) { 19898 newX = 0; 19899 this.keyAcceleration = 0; 19900 } else if ( newX < this.maxScrollX ) { 19901 newX = this.maxScrollX; 19902 this.keyAcceleration = 0; 19903 } 19904 19905 if ( newY > 0 ) { 19906 newY = 0; 19907 this.keyAcceleration = 0; 19908 } else if ( newY < this.maxScrollY ) { 19909 newY = this.maxScrollY; 19910 this.keyAcceleration = 0; 19911 } 19912 19913 this.scrollTo(newX, newY, 0); 19914 19915 this.keyTime = now; 19916 }, 19917 19918 _animate: function (destX, destY, duration, easingFn) { 19919 var that = this, 19920 startX = this.x, 19921 startY = this.y, 19922 startTime = utils.getTime(), 19923 destTime = startTime + duration; 19924 19925 function step () { 19926 var now = utils.getTime(), 19927 newX, newY, 19928 easing; 19929 19930 if ( now >= destTime ) { 19931 that.isAnimating = false; 19932 that._translate(destX, destY); 19933 19934 if ( !that.resetPosition(that.options.bounceTime) ) { 19935 that._execEvent('scrollEnd'); 19936 } 19937 19938 return; 19939 } 19940 19941 now = ( now - startTime ) / duration; 19942 easing = easingFn(now); 19943 newX = ( destX - startX ) * easing + startX; 19944 newY = ( destY - startY ) * easing + startY; 19945 that._translate(newX, newY); 19946 19947 if ( that.isAnimating ) { 19948 rAF(step); 19949 } 19950 } 19951 19952 this.isAnimating = true; 19953 step(); 19954 }, 19955 handleEvent: function (e) { 19956 switch ( e.type ) { 19957 case 'touchstart': 19958 case 'pointerdown': 19959 case 'MSPointerDown': 19960 case 'mousedown': 19961 this._start(e); 19962 break; 19963 case 'touchmove': 19964 case 'pointermove': 19965 case 'MSPointerMove': 19966 case 'mousemove': 19967 this._move(e); 19968 break; 19969 case 'touchend': 19970 case 'pointerup': 19971 case 'MSPointerUp': 19972 case 'mouseup': 19973 case 'touchcancel': 19974 case 'pointercancel': 19975 case 'MSPointerCancel': 19976 case 'mousecancel': 19977 this._end(e); 19978 break; 19979 case 'orientationchange': 19980 case 'resize': 19981 this._resize(); 19982 break; 19983 case 'transitionend': 19984 case 'webkitTransitionEnd': 19985 case 'oTransitionEnd': 19986 case 'MSTransitionEnd': 19987 this._transitionEnd(e); 19988 break; 19989 case 'wheel': 19990 case 'DOMMouseScroll': 19991 case 'mousewheel': 19992 this._wheel(e); 19993 break; 19994 case 'keydown': 19995 this._key(e); 19996 break; 19997 case 'click': 19998 if ( this.enabled && !e._constructed ) { 19999 e.preventDefault(); 20000 e.stopPropagation(); 20001 } 20002 break; 20003 } 20004 } 20005}; 20006function createDefaultScrollbar (direction, interactive, type) { 20007 var scrollbar = document.createElement('div'), 20008 indicator = document.createElement('div'); 20009 20010 if ( type === true ) { 20011 scrollbar.style.cssText = 'position:absolute;z-index:9999'; 20012 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'; 20013 } 20014 20015 indicator.className = 'iScrollIndicator'; 20016 20017 if ( direction == 'h' ) { 20018 if ( type === true ) { 20019 scrollbar.style.cssText += ';height:7px;left:2px;right:2px;bottom:0'; 20020 indicator.style.height = '100%'; 20021 } 20022 scrollbar.className = 'iScrollHorizontalScrollbar'; 20023 } else { 20024 if ( type === true ) { 20025 scrollbar.style.cssText += ';width:7px;bottom:2px;top:2px;right:1px'; 20026 indicator.style.width = '100%'; 20027 } 20028 scrollbar.className = 'iScrollVerticalScrollbar'; 20029 } 20030 20031 scrollbar.style.cssText += ';overflow:hidden'; 20032 20033 if ( !interactive ) { 20034 scrollbar.style.pointerEvents = 'none'; 20035 } 20036 20037 scrollbar.appendChild(indicator); 20038 20039 return scrollbar; 20040} 20041 20042function Indicator (scroller, options) { 20043 this.wrapper = typeof options.el == 'string' ? document.querySelector(options.el) : options.el; 20044 this.wrapperStyle = this.wrapper.style; 20045 this.indicator = this.wrapper.children[0]; 20046 this.indicatorStyle = this.indicator.style; 20047 this.scroller = scroller; 20048 20049 this.options = { 20050 listenX: true, 20051 listenY: true, 20052 interactive: false, 20053 resize: true, 20054 defaultScrollbars: false, 20055 shrink: false, 20056 fade: false, 20057 speedRatioX: 0, 20058 speedRatioY: 0 20059 }; 20060 20061 for ( var i in options ) { 20062 this.options[i] = options[i]; 20063 } 20064 20065 this.sizeRatioX = 1; 20066 this.sizeRatioY = 1; 20067 this.maxPosX = 0; 20068 this.maxPosY = 0; 20069 20070 if ( this.options.interactive ) { 20071 if ( !this.options.disableTouch ) { 20072 utils.addEvent(this.indicator, 'touchstart', this); 20073 utils.addEvent(window, 'touchend', this); 20074 } 20075 if ( !this.options.disablePointer ) { 20076 utils.addEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this); 20077 utils.addEvent(window, utils.prefixPointerEvent('pointerup'), this); 20078 } 20079 if ( !this.options.disableMouse ) { 20080 utils.addEvent(this.indicator, 'mousedown', this); 20081 utils.addEvent(window, 'mouseup', this); 20082 } 20083 } 20084 20085 if ( this.options.fade ) { 20086 this.wrapperStyle[utils.style.transform] = this.scroller.translateZ; 20087 var durationProp = utils.style.transitionDuration; 20088 if(!durationProp) { 20089 return; 20090 } 20091 this.wrapperStyle[durationProp] = utils.isBadAndroid ? '0.0001ms' : '0ms'; 20092 // remove 0.0001ms 20093 var self = this; 20094 if(utils.isBadAndroid) { 20095 rAF(function() { 20096 if(self.wrapperStyle[durationProp] === '0.0001ms') { 20097 self.wrapperStyle[durationProp] = '0s'; 20098 } 20099 }); 20100 } 20101 this.wrapperStyle.opacity = '0'; 20102 } 20103} 20104 20105Indicator.prototype = { 20106 handleEvent: function (e) { 20107 switch ( e.type ) { 20108 case 'touchstart': 20109 case 'pointerdown': 20110 case 'MSPointerDown': 20111 case 'mousedown': 20112 this._start(e); 20113 break; 20114 case 'touchmove': 20115 case 'pointermove': 20116 case 'MSPointerMove': 20117 case 'mousemove': 20118 this._move(e); 20119 break; 20120 case 'touchend': 20121 case 'pointerup': 20122 case 'MSPointerUp': 20123 case 'mouseup': 20124 case 'touchcancel': 20125 case 'pointercancel': 20126 case 'MSPointerCancel': 20127 case 'mousecancel': 20128 this._end(e); 20129 break; 20130 } 20131 }, 20132 20133 destroy: function () { 20134 if ( this.options.fadeScrollbars ) { 20135 clearTimeout(this.fadeTimeout); 20136 this.fadeTimeout = null; 20137 } 20138 if ( this.options.interactive ) { 20139 utils.removeEvent(this.indicator, 'touchstart', this); 20140 utils.removeEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this); 20141 utils.removeEvent(this.indicator, 'mousedown', this); 20142 20143 utils.removeEvent(window, 'touchmove', this); 20144 utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this); 20145 utils.removeEvent(window, 'mousemove', this); 20146 20147 utils.removeEvent(window, 'touchend', this); 20148 utils.removeEvent(window, utils.prefixPointerEvent('pointerup'), this); 20149 utils.removeEvent(window, 'mouseup', this); 20150 } 20151 20152 if ( this.options.defaultScrollbars ) { 20153 this.wrapper.parentNode.removeChild(this.wrapper); 20154 } 20155 }, 20156 20157 _start: function (e) { 20158 var point = e.touches ? e.touches[0] : e; 20159 20160 e.preventDefault(); 20161 e.stopPropagation(); 20162 20163 this.transitionTime(); 20164 20165 this.initiated = true; 20166 this.moved = false;
20167 this.lastPointX = point.pageX; 20168 this.lastPointY = point.pageY; 20169 20170 this.startTime = utils.getTime(); 20171 20172 if ( !this.options.disableTouch ) { 20173 utils.addEvent(window, 'touchmove', this); 20174 } 20175 if ( !this.options.disablePointer ) { 20176 utils.addEvent(window, utils.prefixPointerEvent('pointermove'), this); 20177 } 20178 if ( !this.options.disableMouse ) { 20179 utils.addEvent(window, 'mousemove', this); 20180 } 20181 20182 this.scroller._execEvent('beforeScrollStart'); 20183 }, 20184 20185 _move: function (e) { 20186 var point = e.touches ? e.touches[0] : e, 20187 deltaX, deltaY, 20188 newX, newY, 20189 timestamp = utils.getTime(); 20190 20191 if ( !this.moved ) { 20192 this.scroller._execEvent('scrollStart'); 20193 } 20194 20195 this.moved = true; 20196 20197 deltaX = point.pageX - this.lastPointX; 20198 this.lastPointX = point.pageX; 20199 20200 deltaY = point.pageY - this.lastPointY; 20201 this.lastPointY = point.pageY; 20202 20203 newX = this.x + deltaX; 20204 newY = this.y + deltaY; 20205 20206 this._pos(newX, newY); 20207 20208// INSERT POINT: indicator._move 20209 20210 e.preventDefault(); 20211 e.stopPropagation(); 20212 }, 20213 20214 _end: function (e) { 20215 if ( !this.initiated ) { 20216 return; 20217 } 20218 20219 this.initiated = false; 20220 20221 e.preventDefault(); 20222 e.stopPropagation(); 20223 20224 utils.removeEvent(window, 'touchmove', this); 20225 utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this); 20226 utils.removeEvent(window, 'mousemove', this); 20227 20228 if ( this.scroller.options.snap ) { 20229 var snap = this.scroller._nearestSnap(this.scroller.x, this.scroller.y); 20230 20231 var time = this.options.snapSpeed || Math.max( 20232 Math.max( 20233 Math.min(Math.abs(this.scroller.x - snap.x), 1000), 20234 Math.min(Math.abs(this.scroller.y - snap.y), 1000) 20235 ), 300); 20236 20237 if ( this.scroller.x != snap.x || this.scroller.y != snap.y ) { 20238 this.scroller.directionX = 0; 20239 this.scroller.directionY = 0; 20240 this.scroller.currentPage = snap; 20241 this.scroller.scrollTo(snap.x, snap.y, time, this.scroller.options.bounceEasing); 20242 } 20243 } 20244 20245 if ( this.moved ) { 20246 this.scroller._execEvent('scrollEnd'); 20247 } 20248 }, 20249 20250 transitionTime: function (time) { 20251 time = time || 0; 20252 var durationProp = utils.style.transitionDuration; 20253 if(!durationProp) { 20254 return; 20255 } 20256 20257 this.indicatorStyle[durationProp] = time + 'ms'; 20258 20259 if ( !time && utils.isBadAndroid ) { 20260 this.indicatorStyle[durationProp] = '0.0001ms'; 20261 // remove 0.0001ms 20262 var self = this; 20263 rAF(function() { 20264 if(self.indicatorStyle[durationProp] === '0.0001ms') { 20265 self.indicatorStyle[durationProp] = '0s'; 20266 } 20267 }); 20268 } 20269 }, 20270 20271 transitionTimingFunction: function (easing) { 20272 this.indicatorStyle[utils.style.transitionTimingFunction] = easing; 20273 }, 20274 20275 refresh: function () { 20276 this.transitionTime(); 20277 20278 if ( this.options.listenX && !this.options.listenY ) { 20279 this.indicatorStyle.display = this.scroller.hasHorizontalScroll ? 'block' : 'none'; 20280 } else if ( this.options.listenY && !this.options.listenX ) { 20281 this.indicatorStyle.display = this.scroller.hasVerticalScroll ? 'block' : 'none'; 20282 } else { 20283 this.indicatorStyle.display = this.scroller.hasHorizontalScroll || this.scroller.hasVerticalScroll ? 'block' : 'none'; 20284 } 20285 20286 if ( this.scroller.hasHorizontalScroll && this.scroller.hasVerticalScroll ) { 20287 utils.addClass(this.wrapper, 'iScrollBothScrollbars'); 20288 utils.removeClass(this.wrapper, 'iScrollLoneScrollbar'); 20289 20290 if ( this.options.defaultScrollbars && this.options.customStyle ) { 20291 if ( this.options.listenX ) { 20292 this.wrapper.style.right = '8px'; 20293 } else { 20294 this.wrapper.style.bottom = '8px'; 20295 } 20296 } 20297 } else { 20298 utils.removeClass(this.wrapper, 'iScrollBothScrollbars'); 20299 utils.addClass(this.wrapper, 'iScrollLoneScrollbar'); 20300 20301 if ( this.options.defaultScrollbars && this.options.customStyle ) { 20302 if ( this.options.listenX ) { 20303 this.wrapper.style.right = '2px'; 20304 } else { 20305 this.wrapper.style.bottom = '2px'; 20306 } 20307 } 20308 } 20309 20310 var r = this.wrapper.offsetHeight; // force refresh 20311 20312 if ( this.options.listenX ) {
20313 this.wrapperWidth = this.wrapper.clientWidth; 20314 if ( this.options.resize ) { 20315 this.indicatorWidth = Math.max(Math.round(this.wrapperWidth * this.wrapperWidth / (this.scroller.scrollerWidth || this.wrapperWidth || 1)), 8); 20316 this.indicatorStyle.width = this.indicatorWidth + 'px'; 20317 } else { 20318 this.indicatorWidth = this.indicator.clientWidth; 20319 } 20320 20321 this.maxPosX = this.wrapperWidth - this.indicatorWidth; 20322 20323 if ( this.options.shrink == 'clip' ) { 20324 this.minBoundaryX = -this.indicatorWidth + 8; 20325 this.maxBoundaryX = this.wrapperWidth - 8; 20326 } else { 20327 this.minBoundaryX = 0; 20328 this.maxBoundaryX = this.maxPosX; 20329 } 20330 20331 this.sizeRatioX = this.options.speedRatioX || (this.scroller.maxScrollX && (this.maxPosX / this.scroller.maxScrollX)); 20332 } 20333 20334 if ( this.options.listenY ) { 20335 this.wrapperHeight = this.wrapper.clientHeight; 20336 if ( this.options.resize ) { 20337 this.indicatorHeight = Math.max(Math.round(this.wrapperHeight * this.wrapperHeight / (this.scroller.scrollerHeight || this.wrapperHeight || 1)), 8); 20338 this.indicatorStyle.height = this.indicatorHeight + 'px'; 20339 } else { 20340 this.indicatorHeight = this.indicator.clientHeight; 20341 } 20342 20343 this.maxPosY = this.wrapperHeight - this.indicatorHeight; 20344 20345 if ( this.options.shrink == 'clip' ) { 20346 this.minBoundaryY = -this.indicatorHeight + 8; 20347 this.maxBoundaryY = this.wrapperHeight - 8; 20348 } else { 20349 this.minBoundaryY = 0; 20350 this.maxBoundaryY = this.maxPosY; 20351 } 20352 20353 this.maxPosY = this.wrapperHeight - this.indicatorHeight; 20354 this.sizeRatioY = this.options.speedRatioY || (this.scroller.maxScrollY && (this.maxPosY / this.scroller.maxScrollY)); 20355 } 20356 20357 this.updatePosition(); 20358 }, 20359 20360 updatePosition: function () { 20361 var x = this.options.listenX && Math.round(this.sizeRatioX * this.scroller.x) || 0, 20362 y = this.options.listenY && Math.round(this.sizeRatioY * this.scroller.y) || 0; 20363 20364 if ( !this.options.ignoreBoundaries ) { 20365 if ( x < this.minBoundaryX ) { 20366 if ( this.options.shrink == 'scale' ) { 20367 this.width = Math.max(this.indicatorWidth + x, 8); 20368 this.indicatorStyle.width = this.width + 'px'; 20369 } 20370 x = this.minBoundaryX; 20371 } else if ( x > this.maxBoundaryX ) { 20372 if ( this.options.shrink == 'scale' ) { 20373 this.width = Math.max(this.indicatorWidth - (x - this.maxPosX), 8); 20374 this.indicatorStyle.width = this.width + 'px'; 20375 x = this.maxPosX + this.indicatorWidth - this.width; 20376 } else { 20377 x = this.maxBoundaryX; 20378 } 20379 } else if ( this.options.shrink == 'scale' && this.width != this.indicatorWidth ) { 20380 this.width = this.indicatorWidth; 20381 this.indicatorStyle.width = this.width + 'px'; 20382 } 20383 20384 if ( y < this.minBoundaryY ) { 20385 if ( this.options.shrink == 'scale' ) { 20386 this.height = Math.max(this.indicatorHeight + y * 3, 8); 20387 this.indicatorStyle.height = this.height + 'px'; 20388 } 20389 y = this.minBoundaryY; 20390 } else if ( y > this.maxBoundaryY ) { 20391 if ( this.options.shrink == 'scale' ) { 20392 this.height = Math.max(this.indicatorHeight - (y - this.maxPosY) * 3, 8); 20393 this.indicatorStyle.height = this.height + 'px'; 20394 y = this.maxPosY + this.indicatorHeight - this.height; 20395 } else { 20396 y = this.maxBoundaryY; 20397 } 20398 } else if ( this.options.shrink == 'scale' && this.height != this.indicatorHeight ) { 20399 this.height = this.indicatorHeight; 20400 this.indicatorStyle.height = this.height + 'px'; 20401 } 20402 } 20403 20404 this.x = x; 20405 this.y = y; 20406 20407 if ( this.scroller.options.useTransform ) { 20408 this.indicatorStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.scroller.translateZ; 20409 } else { 20410 this.indicatorStyle.left = x + 'px'; 20411 this.indicatorStyle.top = y + 'px'; 20412 } 20413 }, 20414 20415 _pos: function (x, y) { 20416 if ( x < 0 ) { 20417 x = 0; 20418 } else if ( x > this.maxPosX ) { 20419 x = this.maxPosX; 20420 } 20421 20422 if ( y < 0 ) { 20423 y = 0; 20424 } else if ( y > this.maxPosY ) { 20425 y = this.maxPosY;
20426 } 20427 20428 x = this.options.listenX ? Math.round(x / this.sizeRatioX) : this.scroller.x; 20429 y = this.options.listenY ? Math.round(y / this.sizeRatioY) : this.scroller.y; 20430 20431 this.scroller.scrollTo(x, y); 20432 }, 20433 20434 fade: function (val, hold) { 20435 if ( hold && !this.visible ) { 20436 return; 20437 } 20438 20439 clearTimeout(this.fadeTimeout); 20440 this.fadeTimeout = null; 20441 20442 var time = val ? 250 : 500, 20443 delay = val ? 0 : 300; 20444 20445 val = val ? '1' : '0'; 20446 20447 this.wrapperStyle[utils.style.transitionDuration] = time + 'ms'; 20448 20449 this.fadeTimeout = setTimeout((function (val) { 20450 this.wrapperStyle.opacity = val; 20451 this.visible = +val; 20452 }).bind(this, val), delay); 20453 } 20454}; 20455 20456IScroll.utils = utils; 20457 20458if ( typeof module != 'undefined' && module.exports ) { 20459 module.exports = IScroll; 20460} else if ( typeof define == 'function' && define.amd ) { 20461 define( function () { return IScroll; } ); 20462} else { 20463 window.IScroll = IScroll; 20464} 20465 20466})(window, document, Math); 20467/*! 20468 * fullPage 2.9.4 20469 * https://github.com/alvarotrigo/fullPage.js 20470 * @license MIT licensed 20471 * 20472 * Copyright (C) 2015 alvarotrigo.com - A project by Alvaro Trigo 20473 */ 20474(function(global, factory) { 20475 'use strict'; 20476 if (typeof define === 'function' && define.amd) { 20477 define(['jquery'], function($) { 20478 return factory($, global, global.document, global.Math); 20479 }); 20480 } else if (typeof exports === "object" && exports) { 20481 module.exports = factory(require('jquery'), global, global.document, global.Math); 20482 } else { 20483 factory(jQuery, global, global.document, global.Math); 20484 } 20485})(typeof window !== 'undefined' ? window : this, function($, window, document, Math, undefined) { 20486 'use strict'; 20487 20488 // keeping central set of classnames and selectors 20489 var WRAPPER = 'fullpage-wrapper'; 20490 var WRAPPER_SEL = '.' + WRAPPER; 20491 20492 // slimscroll 20493 var SCROLLABLE = 'fp-scrollable'; 20494 var SCROLLABLE_SEL = '.' + SCROLLABLE; 20495 20496 // util 20497 var RESPONSIVE = 'fp-responsive'; 20498 var NO_TRANSITION = 'fp-notransition'; 20499 var DESTROYED = 'fp-destroyed'; 20500 var ENABLED = 'fp-enabled'; 20501 var VIEWING_PREFIX = 'fp-viewing'; 20502 var ACTIVE = 'active'; 20503 var ACTIVE_SEL = '.' + ACTIVE; 20504 var COMPLETELY = 'fp-completely'; 20505 var COMPLETELY_SEL = '.' + COMPLETELY; 20506 20507 // section 20508 var SECTION_DEFAULT_SEL = '.section'; 20509 var SECTION = 'fp-section'; 20510 var SECTION_SEL = '.' + SECTION; 20511 var SECTION_ACTIVE_SEL = SECTION_SEL + ACTIVE_SEL; 20512 var SECTION_FIRST_SEL = SECTION_SEL + ':first'; 20513 var SECTION_LAST_SEL = SECTION_SEL + ':last'; 20514 var TABLE_CELL = 'fp-tableCell'; 20515 var TABLE_CELL_SEL = '.' + TABLE_CELL; 20516 var AUTO_HEIGHT = 'fp-auto-height'; 20517 var AUTO_HEIGHT_SEL = '.fp-auto-height'; 20518 var NORMAL_SCROLL = 'fp-normal-scroll'; 20519 var NORMAL_SCROLL_SEL = '.fp-normal-scroll'; 20520 20521 // section nav 20522 var SECTION_NAV = 'fp-nav'; 20523 var SECTION_NAV_SEL = '#' + SECTION_NAV; 20524 var SECTION_NAV_TOOLTIP = 'fp-tooltip'; 20525 var SECTION_NAV_TOOLTIP_SEL='.'+SECTION_NAV_TOOLTIP; 20526 var SHOW_ACTIVE_TOOLTIP = 'fp-show-active'; 20527 20528 // slide 20529 var SLIDE_DEFAULT_SEL = '.slide'; 20530 var SLIDE = 'fp-slide'; 20531 var SLIDE_SEL = '.' + SLIDE; 20532 var SLIDE_ACTIVE_SEL = SLIDE_SEL + ACTIVE_SEL; 20533 var SLIDES_WRAPPER = 'fp-slides'; 20534 var SLIDES_WRAPPER_SEL = '.' + SLIDES_WRAPPER; 20535 var SLIDES_CONTAINER = 'fp-slidesContainer'; 20536 var SLIDES_CONTAINER_SEL = '.' + SLIDES_CONTAINER; 20537 var TABLE = 'fp-table'; 20538 20539 // slide nav 20540 var SLIDES_NAV = 'fp-slidesNav'; 20541 var SLIDES_NAV_SEL = '.' + SLIDES_NAV; 20542 var SLIDES_NAV_LINK_SEL = SLIDES_NAV_SEL + ' a'; 20543 var SLIDES_ARROW = 'fp-controlArrow'; 20544 var SLIDES_ARROW_SEL = '.' + SLIDES_ARROW; 20545 var SLIDES_PREV = 'fp-prev'; 20546 var SLIDES_PREV_SEL = '.' + SLIDES_PREV; 20547 var SLIDES_ARROW_PREV = SLIDES_ARROW + ' ' + SLIDES_PREV; 20548 var SLIDES_ARROW_PREV_SEL = SLIDES_ARROW_SEL + SLIDES_PREV_SEL; 20549 var SLIDES_NEXT = 'fp-next';
20550 var SLIDES_NEXT_SEL = '.' + SLIDES_NEXT; 20551 var SLIDES_ARROW_NEXT = SLIDES_ARROW + ' ' + SLIDES_NEXT; 20552 var SLIDES_ARROW_NEXT_SEL = SLIDES_ARROW_SEL + SLIDES_NEXT_SEL; 20553 20554 var $window = $(window); 20555 var $document = $(document); 20556 20557 // Default options for iScroll.js used when using scrollOverflow 20558 var iscrollOptions = { 20559 scrollbars: true, 20560 mouseWheel: true, 20561 hideScrollbars: false, 20562 fadeScrollbars: false, 20563 disableMouse: true, 20564 interactiveScrollbars: true, 20565 bounce: false, 20566 }; 20567 20568 $.fn.fullpage = function(options) { 20569 //only once my friend! 20570 if($('html').hasClass(ENABLED)){ displayWarnings(); return; } 20571 20572 // common jQuery objects 20573 var $htmlBody = $('html, body'); 20574 var $body = $('body'); 20575 20576 var FP = $.fn.fullpage; 20577 20578 // Creating some defaults, extending them with any options that were provided 20579 options = $.extend({ 20580 //navigation 20581 menu: false, 20582 anchors:[], 20583 lockAnchors: false, 20584 navigation: false, 20585 navigationPosition: 'right', 20586 navigationTooltips: [], 20587 showActiveTooltip: false, 20588 slidesNavigation: false, 20589 slidesNavPosition: 'bottom', 20590 scrollBar: false, 20591 hybrid: false, 20592 20593 //scrolling 20594 css3: true, 20595 scrollingSpeed: 700, 20596 autoScrolling: true, 20597 fitToSection: true, 20598 fitToSectionDelay: 1000, 20599 easing: 'easeInOutCubic', 20600 easingcss3: 'ease', 20601 loopBottom: false, 20602 loopTop: false, 20603 loopHorizontal: true, 20604 continuousVertical: false, 20605 continuousHorizontal: false, 20606 scrollHorizontally: false, 20607 interlockedSlides: false, 20608 dragAndMove: false, 20609 offsetSections: false, 20610 resetSliders: false, 20611 fadingEffect: false, 20612 normalScrollElements: null, 20613 scrollOverflow: false, 20614 scrollOverflowReset: false, 20615 scrollOverflowHandler: iscrollHandler, 20616 scrollOverflowOptions: null, 20617 touchSensitivity: 5, 20618 normalScrollElementTouchThreshold: 5, 20619 bigSectionsDestination: null, 20620 20621 //Accessibility 20622 keyboardScrolling: true, 20623 animateAnchor: true, 20624 recordHistory: true, 20625 20626 //design 20627 controlArrows: true, 20628 controlArrowColor: '#fff', 20629 verticalCentered: true, 20630 sectionsColor : [], 20631 paddingTop: 0, 20632 paddingBottom: 0, 20633 fixedElements: null, 20634 responsive: 0, //backwards compabitility with responsiveWiddth 20635 responsiveWidth: 0, 20636 responsiveHeight: 0, 20637 responsiveSlides: false, 20638 parallax: false, 20639 parallaxOptions: { 20640 type: 'reveal', 20641 percentage: 62, 20642 property: 'translate' 20643 }, 20644 20645 //Custom selectors 20646 sectionSelector: SECTION_DEFAULT_SEL, 20647 slideSelector: SLIDE_DEFAULT_SEL, 20648 20649 //events 20650 afterLoad: null, 20651 onLeave: null, 20652 afterRender: null, 20653 afterResize: null, 20654 afterReBuild: null, 20655 afterSlideLoad: null, 20656 onSlideLeave: null, 20657 afterResponsive: null, 20658 20659 lazyLoading: true 20660 }, options); 20661 20662 //flag to avoid very fast sliding for landscape sliders 20663 var slideMoving = false; 20664 20665 var isTouchDevice = navigator.userAgent.match(/(iPhone|iPod|iPad|Android|playbook|silk|BlackBerry|BB10|Windows Phone|Tizen|Bada|webOS|IEMobile|Opera Mini)/); 20666 var isTouch = (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0) || (navigator.maxTouchPoints)); 20667 var container = $(this); 20668 var windowsHeight = $window.height(); 20669 var isResizing = false; 20670 var isWindowFocused = true; 20671 var lastScrolledDestiny; 20672 var lastScrolledSlide; 20673 var canScroll = true; 20674 var scrollings = []; 20675 var controlPressed; 20676 var startingSection; 20677 var isScrollAllowed = {}; 20678 isScrollAllowed.m = { 'up':true, 'down':true, 'left':true, 'right':true }; 20679 isScrollAllowed.k = $.extend(true,{}, isScrollAllowed.m); 20680 var MSPointer = getMSPointer(); 20681 var events = { 20682 touchmove: 'ontouchmove' in window ? 'touchmove' : MSPointer.move, 20683 touchstart: 'ontouchstart' in window ? 'touchstart' : MSPointer.down 20684 }; 20685 20686 //cheks for passive event support 20687 //added by Uncode from new fullPage updates 20688 var g_supportsPassive = false;
20689 try { 20690 var opts = Object.defineProperty({}, 'passive', { 20691 get: function() { 20692 g_supportsPassive = true; 20693 } 20694 }); 20695 window.addEventListener("testPassive", null, opts); 20696 window.removeEventListener("testPassive", null, opts); 20697 } catch (e) {} 20698 20699 //timeouts 20700 var resizeId; 20701 var afterSectionLoadsId; 20702 var afterSlideLoadsId; 20703 var scrollId; 20704 var scrollId2; 20705 var keydownId; 20706 var originals = $.extend(true, {}, options); //deep copy 20707 20708 //Uncode addition 20709 var $masthead = $('#masthead'); 20710 var hideMenu = !$('body').hasClass('vmenu') && $('body').hasClass('uncode-fp-menu-hide') ? true : false; 20711 var menuHeight = $masthead.hasClass('menu-transparent') || hideMenu ? 0 : UNCODE.menuHeight; 20712 var bodyBorder = UNCODE.bodyBorder; 20713 var adminBarHeight = UNCODE.adminBarHeight; 20714 20715 displayWarnings(); 20716 20717 //fixing bug in iScroll with links: https://github.com/cubiq/iscroll/issues/783 20718 iscrollOptions.click = isTouch; // see #2035 20719 20720 //extending iScroll options with the user custom ones 20721 iscrollOptions = $.extend(iscrollOptions, options.scrollOverflowOptions); 20722 20723 //easeInOutCubic animation included in the plugin 20724 $.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;}}); 20725 20726 /** 20727 * Sets the autoScroll option. 20728 * It changes the scroll bar visibility and the history of the site as a result. 20729 */ 20730 function setAutoScrolling(value, type){ 20731 //removing the transformation 20732 if(!value){ 20733 silentScroll(0); 20734 } 20735 20736 setVariableState('autoScrolling', value, type); 20737 20738 var element = $(SECTION_ACTIVE_SEL); 20739 20740 if(options.autoScrolling && !options.scrollBar){ 20741 $htmlBody.css({ 20742 'overflow' : 'hidden !important', 20743 'height' : '100%' 20744 }); 20745 20746 //Uncode addition 20747 //setRecordHistory(originals.recordHistory, 'internal'); 20748 20749 //for IE touch devices 20750 container.css({ 20751 '-ms-touch-action': 'none', 20752 'touch-action': 'none' 20753 }); 20754 20755 if(element.length){ 20756 //moving the container up 20757 silentScroll(element.position().top); 20758 } 20759 20760 }else{ 20761 $htmlBody.css({ 20762 'overflow' : 'visible !important', 20763 'height' : 'initial' 20764 }); 20765 20766 //Uncode addition 20767 //setRecordHistory(false, 'internal'); 20768 20769 //for IE touch devices 20770 container.css({ 20771 '-ms-touch-action': '', 20772 'touch-action': '' 20773 }); 20774 20775 //scrolling the page to the section with no animation 20776 if (element.length) { 20777 $htmlBody.scrollTop(element.position().top); 20778 } 20779 } 20780 } 20781 20782 /** 20783 * Defines wheter to record the history for each hash change in the URL. 20784 */ 20785 function setRecordHistory(value, type){ 20786 setVariableState('recordHistory', value, type); 20787 } 20788 20789 /** 20790 * Defines the scrolling speed 20791 */ 20792 function setScrollingSpeed(value, type){ 20793 setVariableState('scrollingSpeed', value, type); 20794 } 20795 20796 /** 20797 * Sets fitToSection 20798 */ 20799 function setFitToSection(value, type){ 20800 setVariableState('fitToSection', value, type); 20801 } 20802 20803 /** 20804 * Sets lockAnchors 20805 */ 20806 function setLockAnchors(value){ 20807 options.lockAnchors = value; 20808 } 20809 20810 /** 20811 * Adds or remove the possiblity of scrolling through sections by using the mouse wheel or the trackpad. 20812 */ 20813 function setMouseWheelScrolling(value){ 20814 if(value){ 20815 addMouseWheelHandler(); 20816 addMiddleWheelHandler(); 20817 }else{ 20818 removeMouseWheelHandler(); 20819 removeMiddleWheelHandler(); 20820 } 20821 } 20822 20823 /** 20824 * Adds or remove the possibility of scrolling through sections by using the mouse wheel/trackpad or touch gestures. 20825 * Optionally a second parameter can be used to specify the direction for which the action will be applied. 20826 * 20827 * @param directions string containing the direction or directions separated by comma. 20828 */ 20829 function setAllowScrolling(value, directions){ 20830 if(typeof directions !== 'undefined'){ 20831 directions = directions.replace(/ /g,'').split(','); 20832 20833 $.each(directions, function (index, direction){ 20834 setIsScrollAllowed(value, direction, 'm'); 20835 }); 20836 } 20837 else if(value){ 20838 setMouseWheelScrolling(true); 20839 addTouchHandler(); 20840 }else{ 20841 setMouseWheelScrolling(false); 20842 removeTouchHandler(); 20843 } 20844 } 20845 20846 /** 20847 * Adds or remove the possibility of scrolling through sections by using the keyboard arrow keys 20848 */ 20849 function setKeyboardScrolling(value, directions){ 20850 if(typeof directions !== 'undefined'){ 20851 directions = directions.replace(/ /g,'').split(','); 20852 20853 $.each(directions, function (index, direction){ 20854 setIsScrollAllowed(value, direction, 'k'); 20855 }); 20856 }else{ 20857 options.keyboardScrolling = value; 20858 } 20859 } 20860 20861 /** 20862 * Moves the page up one section. 20863 */ 20864 function moveSectionUp(){ 20865 var prev = $(SECTION_ACTIVE_SEL).prev(SECTION_SEL); 20866 20867 //looping to the bottom if there's no more sections above 20868 if (!prev.length && (options.loopTop || options.continuousVertical)) {
20869 prev = $(SECTION_SEL).last(); 20870 } 20871 20872 if (prev.length) { 20873 scrollPage(prev, null, true); 20874 } 20875 } 20876 20877 /** 20878 * Moves the page down one section. 20879 */ 20880 function moveSectionDown(){ 20881 var next = $(SECTION_ACTIVE_SEL).next(SECTION_SEL); 20882 20883 //looping to the top if there's no more sections below 20884 if(!next.length && 20885 (options.loopBottom || options.continuousVertical)){ 20886 next = $(SECTION_SEL).first(); 20887 } 20888 20889 if(next.length){ 20890 scrollPage(next, null, false); 20891 } 20892 } 20893 20894 /** 20895 * Moves the page to the given section and slide with no animation. 20896 * Anchors or index positions can be used as params. 20897 */ 20898 function silentMoveTo(sectionAnchor, slideAnchor){ 20899 setScrollingSpeed (0, 'internal'); 20900 moveTo(sectionAnchor, slideAnchor); 20901 setScrollingSpeed (originals.scrollingSpeed, 'internal'); 20902 } 20903 20904 /** 20905 * Moves the page to the given section and slide. 20906 * Anchors or index positions can be used as params. 20907 */ 20908 function moveTo(sectionAnchor, slideAnchor){ 20909 var destiny = getSectionByAnchor(sectionAnchor); 20910 20911 if (typeof slideAnchor !== 'undefined'){ 20912 scrollPageAndSlide(sectionAnchor, slideAnchor); 20913 }else if(destiny.length > 0){ 20914 scrollPage(destiny); 20915 } 20916 } 20917 20918 /** 20919 * Slides right the slider of the active section. 20920 * Optional `section` param. 20921 */ 20922 function moveSlideRight(section){ 20923 moveSlide('right', section); 20924 } 20925 20926 /** 20927 * Slides left the slider of the active section. 20928 * Optional `section` param. 20929 */ 20930 function moveSlideLeft(section){ 20931 moveSlide('left', section); 20932 } 20933 20934 /** 20935 * When resizing is finished, we adjust the slides sizes and positions 20936 */ 20937 function reBuild(resizing){ 20938 if(container.hasClass(DESTROYED)){ return; } //nothing to do if the plugin was destroyed 20939 20940 isResizing = true; 20941 20942 windowsHeight = $window.height(); //updating global var 20943 20944 $(SECTION_SEL).each(function(){ 20945 var slidesWrap = $(this).find(SLIDES_WRAPPER_SEL); 20946 var slides = $(this).find(SLIDE_SEL); 20947 20948 //adjusting the height of the table-cell for IE and Firefox 20949 if(options.verticalCentered){ 20950 $(this).find(TABLE_CELL_SEL).css('height', getTableHeight($(this)) + 'px'); 20951 } 20952 20953 $(this).css('height', windowsHeight + 'px'); 20954 20955 //resizing the scrolling divs 20956 if(options.scrollOverflow){ 20957 if(slides.length){ 20958 slides.each(function(){ 20959 createScrollBar($(this)); 20960 }); 20961 }else{ 20962 createScrollBar($(this)); 20963 } 20964 } 20965 20966 //adjusting the position fo the FULL WIDTH slides... 20967 if (slides.length > 1) { 20968 landscapeScroll(slidesWrap, slidesWrap.find(SLIDE_ACTIVE_SEL)); 20969 } 20970 }); 20971 20972 var activeSection = $(SECTION_ACTIVE_SEL); 20973 var sectionIndex = activeSection.index(SECTION_SEL); 20974 20975 //isn't it the first section? 20976 if(sectionIndex){ 20977 //adjusting the position for the current section 20978 silentMoveTo(sectionIndex + 1); 20979 } 20980 20981 isResizing = false; 20982 $.isFunction( options.afterResize ) && resizing && options.afterResize.call(container); 20983 $.isFunction( options.afterReBuild ) && !resizing && options.afterReBuild.call(container); 20984 } 20985 20986 /** 20987 * Turns fullPage.js to normal scrolling mode when the viewport `width` or `height` 20988 * are smaller than the set limit values. 20989 */ 20990 function setResponsive(active){ 20991 var isResponsive = $body.hasClass(RESPONSIVE); 20992 20993 if(active){ 20994 if(!isResponsive){ 20995 setAutoScrolling(false, 'internal'); 20996 setFitToSection(false, 'internal'); 20997 $(SECTION_NAV_SEL).hide(); 20998 $body.addClass(RESPONSIVE); 20999 $.isFunction( options.afterResponsive ) && options.afterResponsive.call( container, active); 21000 } 21001 } 21002 else if(isResponsive){ 21003 setAutoScrolling(originals.autoScrolling, 'internal'); 21004 setFitToSection(originals.autoScrolling, 'internal'); 21005 $(SECTION_NAV_SEL).show(); 21006 $body.removeClass(RESPONSIVE); 21007 $.isFunction( options.afterResponsive ) && options.afterResponsive.call( container, active); 21008 } 21009 } 21010 21011 if($(this).length){ 21012 //public functions 21013 FP.setAutoScrolling = setAutoScrolling; 21014 FP.setRecordHistory = setRecordHistory; 21015 FP.setScrollingSpeed = setScrollingSpeed; 21016 FP.setFitToSection = setFitToSection; 21017 FP.setLockAnchors = setLockAnchors; 21018 FP.setMouseWheelScrolling = setMouseWheelScrolling; 21019 FP.setAllowScrolling = setAllowScrolling; 21020 FP.setKeyboardScrolling = setKeyboardScrolling; 21021 FP.moveSectionUp = moveSectionUp; 21022 FP.moveSectionDown = moveSectionDown; 21023 FP.silentMoveTo = silentMoveTo; 21024 FP.moveTo = moveTo; 21025 FP.moveSlideRight = moveSlideRight; 21026 FP.moveSlideLeft = moveSlideLeft; 21027 FP.fitToSection = fitToSection; 21028 FP.reBuild = reBuild; 21029 FP.setResponsive = setResponsive; 21030 FP.destroy = destroy; 21031 21032 init(); 21033 21034 bindEvents(); 21035 } 21036
21037 function init(){ 21038 //if css3 is not supported, it will use jQuery animations 21039 if(options.css3){ 21040 options.css3 = support3d(); 21041 } 21042 21043 options.scrollBar = options.scrollBar || options.hybrid; 21044 21045 setOptionsFromDOM(); 21046 prepareDom(); 21047 setAllowScrolling(true); 21048 setAutoScrolling(options.autoScrolling, 'internal'); 21049 responsive(); 21050 21051 //setting the class for the body element 21052 setBodyClass(); 21053 21054 //Uncode addition 21055 // if(document.readyState === 'complete'){ 21056 // scrollToAnchor(); 21057 // } 21058 // $window.on('load', scrollToAnchor); 21059 } 21060 21061 function bindEvents(){ 21062 $window 21063 //when scrolling... 21064 //.on('scroll', scrollHandler) 21065 21066 //detecting any change on the URL to scroll to the given anchor link 21067 //(a way to detect back history button as we play with the hashes on the URL) 21068 .on('hashchange', hashChangeHandler) 21069 21070 //when opening a new tab (ctrl + t), `control` won't be pressed when coming back. 21071 .blur(blurHandler) 21072 21073 //when resizing the site, we adjust the heights of the sections, slimScroll... 21074 .resize(resizeHandler); 21075 21076 $document 21077 //Sliding with arrow keys, both, vertical and horizontal 21078 .keydown(keydownHandler) 21079 21080 //to prevent scrolling while zooming 21081 .keyup(keyUpHandler) 21082 21083 //Scrolls to the section when clicking the navigation bullet 21084 .on('click touchstart', SECTION_NAV_SEL + ' a', sectionBulletHandler) 21085 21086 //Scrolls the slider to the given slide destination for the given section 21087 .on('click touchstart', SLIDES_NAV_LINK_SEL, slideBulletHandler) 21088 21089 .on('click', SECTION_NAV_TOOLTIP_SEL, tooltipTextHandler); 21090 21091 //Scrolling horizontally when clicking on the slider controls. 21092 $(SECTION_SEL).on('click touchstart', SLIDES_ARROW_SEL, slideArrowHandler); 21093 21094 /** 21095 * Applying normalScroll elements. 21096 * Ignoring the scrolls over the specified selectors. 21097 */ 21098 if(options.normalScrollElements){ 21099 $document.on('mouseenter', options.normalScrollElements, function () { 21100 setMouseWheelScrolling(false); 21101 }); 21102 21103 $document.on('mouseleave', options.normalScrollElements, function(){ 21104 setMouseWheelScrolling(true); 21105 }); 21106 } 21107 } 21108 21109 /** 21110 * Setting options from DOM elements if they are not provided. 21111 */ 21112 function setOptionsFromDOM(){ 21113 var sections = container.find(options.sectionSelector); 21114 21115 //no anchors option? Checking for them in the DOM attributes 21116 if(!options.anchors.length){ 21117 options.anchors = sections.filter('[data-anchor]').map(function(){ 21118 return $(this).data('anchor').toString(); 21119 }).get(); 21120 } 21121 21122 //no tooltips option? Checking for them in the DOM attributes 21123 if(!options.navigationTooltips.length){ 21124 options.navigationTooltips = sections.filter('[data-tooltip]').map(function(){ 21125 return $(this).data('tooltip').toString(); 21126 }).get(); 21127 } 21128 } 21129 21130 /** 21131 * Works over the DOM structure to set it up for the current fullpage options. 21132 */ 21133 function prepareDom(){ 21134 container.css({ 21135 'height': '100%', 21136 'position': 'relative' 21137 }); 21138 21139 //adding a class to recognize the container internally in the code 21140 container.addClass(WRAPPER); 21141 $('html').addClass(ENABLED); 21142 21143 windowsHeight = $window.height(); 21144 21145 container.removeClass(DESTROYED); //in case it was destroyed before initializing it again 21146 21147 addInternalSelectors(); 21148 21149 //styling the sections / slides / menu 21150 $(SECTION_SEL).each(function(index){ 21151 var section = $(this); 21152 var slides = section.find(SLIDE_SEL); 21153 var numSlides = slides.length; 21154 21155 styleSection(section, index); 21156 styleMenu(section, index); 21157 21158 // if there's any slide 21159 if (numSlides > 0) { 21160 styleSlides(section, slides, numSlides); 21161 }else{ 21162 if(options.verticalCentered){ 21163 addTableClass(section); 21164 } 21165 } 21166 }); 21167 21168 //fixed elements need to be moved out of the plugin container due to problems with CSS3. 21169 if(options.fixedElements && options.css3){ 21170 $(options.fixedElements).appendTo($body); 21171 } 21172 21173 //vertical centered of the navigation + active bullet 21174 if(options.navigation){ 21175 addVerticalNavigation(); 21176 } 21177 21178 enableYoutubeAPI(); 21179 21180 if(options.scrollOverflow){ 21181 if(document.readyState === 'complete'){ 21182 createScrollBarHandler(); 21183 } 21184 //after DOM and images are loaded 21185 $window.on('load', createScrollBarHandler); 21186 }else{ 21187 afterRenderActions(); 21188 } 21189 } 21190 21191 /** 21192 * Styles the horizontal slides for a section. 21193 */ 21194 function styleSlides(section, slides, numSlides){ 21195 var sliderWidth = numSlides * 100; 21196 var slideWidth = 100 / numSlides; 21197 21198 slides.wrapAll('<div class="' + SLIDES_CONTAINER + '" />'); 21199 slides.parent().wrap('<div class="' + SLIDES_WRAPPER + '" />'); 21200 21201 section.find(SLIDES_CONTAINER_SEL).css('width', sliderWidth + '%'); 21202 21203 if(numSlides > 1){ 21204 if(options.controlArrows){ 21205 createSlideArrows(section); 21206 } 21207 21208 if(options.slidesNavigation){ 21209 addSlidesNavigation(section, numSlides); 21210 } 21211 } 21212 21213 slides.each(function(index) { 21214 $(this).css('width', slideWidth + '%'); 21215 21216 if(options.verticalCentered){ 21217 addTableClass($(this)); 21218 } 21219 }); 21220 21221 var startingSlide = section.find(SLIDE_ACTIVE_SEL); 21222 21223 //if the slide won't be an starting point, the default will be the first one 21224 //the active section isn't the first one? Is not the first slide of the first section? Then we load that section/sl
21224ide by default. 21225 if( startingSlide.length && ($(SECTION_ACTIVE_SEL).index(SECTION_SEL) !== 0 || ($(SECTION_ACTIVE_SEL).index(SECTION_SEL) === 0 && startingSlide.index() !== 0))){ 21226 silentLandscapeScroll(startingSlide, 'internal'); 21227 }else{ 21228 slides.eq(0).addClass(ACTIVE); 21229 } 21230 } 21231 21232 /** 21233 * Styling vertical sections 21234 */ 21235 function styleSection(section, index){ 21236 //if no active section is defined, the 1st one will be the default one 21237 if(!index && $(SECTION_ACTIVE_SEL).length === 0) { 21238 section.addClass(ACTIVE); 21239 } 21240 startingSection = $(SECTION_ACTIVE_SEL); 21241 21242 section.css('height', windowsHeight + 'px'); 21243 21244 if(options.paddingTop){ 21245 section.css('padding-top', options.paddingTop); 21246 } 21247 21248 if(options.paddingBottom){ 21249 section.css('padding-bottom', options.paddingBottom); 21250 } 21251 21252 if (typeof options.sectionsColor[index] !== 'undefined') { 21253 section.css('background-color', options.sectionsColor[index]); 21254 } 21255 21256 if (typeof options.anchors[index] !== 'undefined') { 21257 section.attr('data-anchor', options.anchors[index]); 21258 } 21259 } 21260 21261 /** 21262 * Sets the data-anchor attributes to the menu elements and activates the current one. 21263 */ 21264 function styleMenu(section, index){ 21265 if (typeof options.anchors[index] !== 'undefined') { 21266 //activating the menu / nav element on load 21267 if(section.hasClass(ACTIVE)){ 21268 activateMenuAndNav(options.anchors[index], index); 21269 } 21270 } 21271 21272 //moving the menu outside the main container if it is inside (avoid problems with fixed positions when using CSS3 tranforms) 21273 if(options.menu && options.css3 && $(options.menu).closest(WRAPPER_SEL).length){ 21274 $(options.menu).appendTo($body); 21275 } 21276 } 21277 21278 /** 21279 * Adds internal classes to be able to provide customizable selectors 21280 * keeping the link with the style sheet. 21281 */ 21282 function addInternalSelectors(){ 21283 container.find(options.sectionSelector).addClass(SECTION); 21284 container.find(options.slideSelector).addClass(SLIDE); 21285 } 21286 21287 /** 21288 * Creates the control arrows for the given section 21289 */ 21290 function createSlideArrows(section){ 21291 section.find(SLIDES_WRAPPER_SEL).after('<div class="' + SLIDES_ARROW_PREV + '"></div><div class="' + SLIDES_ARROW_NEXT + '"></div>'); 21292 21293 if(options.controlArrowColor!='#fff'){ 21294 section.find(SLIDES_ARROW_NEXT_SEL).css('border-color', 'transparent transparent transparent '+options.controlArrowColor); 21295 section.find(SLIDES_ARROW_PREV_SEL).css('border-color', 'transparent '+ options.controlArrowColor + ' transparent transparent'); 21296 } 21297 21298 if(!options.loopHorizontal){ 21299 section.find(SLIDES_ARROW_PREV_SEL).hide(); 21300 } 21301 } 21302 21303 /** 21304 * Creates a vertical navigation bar. 21305 */ 21306 function addVerticalNavigation(){ 21307 $body.append('<div id="' + SECTION_NAV + '"><ul></ul></div>'); 21308 var nav = $(SECTION_NAV_SEL); 21309 21310 nav.addClass(function() { 21311 return options.showActiveTooltip ? SHOW_ACTIVE_TOOLTIP + ' ' + options.navigationPosition : options.navigationPosition; 21312 }); 21313 21314 for (var i = 0; i < $(SECTION_SEL).length; i++) { 21315 var link = ''; 21316 if (options.anchors.length) { 21317 link = options.anchors[i]; 21318 } 21319 21320 var li = '<li><a href="#' + link + '"><span></span></a>'; 21321 21322 // Only add tooltip if needed (defined by user) 21323 var tooltip = options.navigationTooltips[i]; 21324 21325 if (typeof tooltip !== 'undefined' && tooltip !== '') { 21326 li += '<div class="' + SECTION_NAV_TOOLTIP + ' ' + options.navigationPosition + '">' + tooltip + '</div>'; 21327 } 21328 21329 li += '</li>'; 21330 21331 nav.find('ul').append(li); 21332 } 21333 21334 //centering it vertically 21335 $(SECTION_NAV_SEL).css('margin-top', '-' + ($(SECTION_NAV_SEL).height()/2) + 'px'); 21336 21337 //activating the current active section 21338 $(SECTION_NAV_SEL).find('li').eq($(SECTION_ACTIVE_SEL).index(SECTION_SEL)).find('a').addClass(ACTIVE); 21339 } 21340 21341 /** 21342 * Creates the slim scroll scrollbar for the sections and slides inside them. 21343 */ 21344 function createScrollBarHandler(){ 21345 $(SECTION_SEL).each(function(){ 21346 var slides = $(this).find(SLIDE_SEL); 21347 21348 if(slides.length){ 21349 slides.each(function(){ 21350 createScrollBar($(this)); 21351 }); 21352 }else{ 21353 createScrollBar($(this)); 21354 } 21355 21356 }); 21357 afterRenderActions(); 21358 } 21359 21360 /*
21361 * Enables the Youtube videos API so we can control their flow if necessary. 21362 */ 21363 function enableYoutubeAPI(){ 21364 container.find('iframe[src*="youtube.com/embed/"]').each(function(){ 21365 addURLParam($(this), 'enablejsapi=1'); 21366 }); 21367 } 21368 21369 /** 21370 * Adds a new parameter and its value to the `src` of a given element 21371 */ 21372 function addURLParam(element, newParam){ 21373 var originalSrc = element.attr('src'); 21374 element.attr('src', originalSrc + getUrlParamSign(originalSrc) + newParam); 21375 } 21376 21377 /* 21378 * Returns the prefix sign to use for a new parameter in an existen URL. 21379 * 21380 * @return {String} ? | & 21381 */ 21382 function getUrlParamSign(url){ 21383 return ( !/\?/.test( url ) ) ? '?' : '&'; 21384 } 21385 21386 /** 21387 * Actions and callbacks to fire afterRender 21388 */ 21389 function afterRenderActions(){ 21390 var section = $(SECTION_ACTIVE_SEL); 21391 21392 section.addClass(COMPLETELY); 21393 21394 if(options.scrollOverflowHandler.afterRender){ 21395 options.scrollOverflowHandler.afterRender(section); 21396 } 21397 lazyLoad(section); 21398 playMedia(section); 21399 options.scrollOverflowHandler.afterLoad(); 21400 21401 if(isDestinyTheStartingSection()){ 21402 $.isFunction( options.afterLoad ) && options.afterLoad.call(section, section.data('anchor'), (section.index(SECTION_SEL) + 1)); 21403 } 21404 21405 $.isFunction( options.afterRender ) && options.afterRender.call(container); 21406 } 21407 21408 /** 21409 * Determines if the URL anchor destiny is the starting section (the one using 'active' class before initialization) 21410 */ 21411 function isDestinyTheStartingSection(){ 21412 var anchors = window.location.hash.replace('#', '').split('/'); 21413 var destinationSection = getSectionByAnchor(decodeURIComponent(anchors[0])); 21414 21415 return !destinationSection.length || destinationSection.length && destinationSection.index() === startingSection.index(); 21416 } 21417 21418 21419 var isScrolling = false; 21420 var lastScroll = 0; 21421 21422 //when scrolling... 21423 function scrollHandler(){ 21424 var currentSection; 21425 21426 if(!options.autoScrolling || options.scrollBar){ 21427 var currentScroll = $window.scrollTop(); 21428 var scrollDirection = getScrollDirection(currentScroll); 21429 var visibleSectionIndex = 0; 21430 var screen_mid = currentScroll + ($window.height() / 2.0); 21431 var isAtBottom = $body.height() - $window.height() === currentScroll; 21432 var sections = document.querySelectorAll(SECTION_SEL); 21433 21434 //when using `auto-height` for a small last section it won't be centered in the viewport 21435 if(isAtBottom){ 21436 visibleSectionIndex = sections.length - 1; 21437 } 21438 //is at top? when using `auto-height` for a small first section it won't be centered in the viewport 21439 else if(!currentScroll){ 21440 visibleSectionIndex = 0; 21441 } 21442 21443 //taking the section which is showing more content in the viewport 21444 else{ 21445 for (var i = 0; i < sections.length; ++i) { 21446 var section = sections[i]; 21447 21448 // Pick the the last section which passes the middle line of the screen. 21449 if (section.offsetTop <= screen_mid) 21450 { 21451 visibleSectionIndex = i; 21452 } 21453 } 21454 } 21455 21456 if(isCompletelyInViewPort(scrollDirection)){ 21457 if(!$(SECTION_ACTIVE_SEL).hasClass(COMPLETELY)){ 21458 $(SECTION_ACTIVE_SEL).addClass(COMPLETELY).siblings().removeClass(COMPLETELY); 21459 } 21460 } 21461 21462 //geting the last one, the current one on the screen 21463 currentSection = $(sections).eq(visibleSectionIndex); 21464 21465 //setting the visible section as active when manually scrolling 21466 //executing only once the first time we reach the section 21467 if(!currentSection.hasClass(ACTIVE)){ 21468 isScrolling = true; 21469 var leavingSection = $(SECTION_ACTIVE_SEL); 21470 var leavingSectionIndex = leavingSection.index(SECTION_SEL) + 1; 21471 var yMovement = getYmovement(currentSection); 21472 var anchorLink = currentSection.data('anchor'); 21473 var sectionIndex = currentSection.index(SECTION_SEL) + 1; 21474 var activeSlide = currentSection.find(SLIDE_ACTIVE_SEL); 21475 var slideIndex; 21476 var slideAnchorLink; 21477 21478 if(activeSlide.length){ 21479 slideAnchorLink = activeSlide.data('anchor'); 21480 slideIndex = activeSlide.index(); 21481 } 21482 21483 if(canScroll){ 21484 currentSection.addClass(ACTIVE).siblings().removeClass(ACTIVE); 21485 21486 $.isFunction( options.onLeave ) && options.onLeave.call( leavingSection, leavingSectionIndex, sectionIndex, yMovement); 21487 $.isFunction( options.afterLoad ) && options.afterLoad.call( currentSection, anchorLink, sectionIndex); 21488 21489 stopMedia(leavingSection); 21490 lazyLoad(currentSection); 21491 playMedia(currentSection); 21492 21493 activateMenuAndNav(anchorLink, sectionIndex - 1); 21494 21495 if(options.anchors.length){ 21496 //needed to enter in hashChange event when using the menu with anchor links 21497 lastScrolledDestiny = anchorLink; 21498 } 21499 setState(slideIndex, slideAnchorLink, anchorLink, sectionIndex); 21500 } 21501 21502 //small timeout in order to avoid entering in hashChange event when scrolling is not finished yet 21503 clearTimeout(scrollId); 21504 scrollId = setTimeout(function(){ 21505 isScrolling = false;
21506 }, 100); 21507 } 21508 21509 if(options.fitToSection){ 21510 //for the auto adjust of the viewport to fit a whole section 21511 clearTimeout(scrollId2); 21512 21513 scrollId2 = setTimeout(function(){ 21514 //checking it again in case it changed during the delay 21515 if(options.fitToSection){ 21516 fitToSection(); 21517 } 21518 }, options.fitToSectionDelay); 21519 } 21520 } 21521 } 21522 21523 /** 21524 * Fits the site to the nearest active section 21525 */ 21526 function fitToSection(){ 21527 //checking fitToSection again in case it was set to false before the timeout delay 21528 if(canScroll){ 21529 //allows to scroll to an active section and 21530 //if the section is already active, we prevent firing callbacks 21531 isResizing = true; 21532 21533 scrollPage($(SECTION_ACTIVE_SEL)); 21534 isResizing = false; 21535 } 21536 } 21537 21538 /** 21539 * Determines whether the active section has seen in its whole or not. 21540 */ 21541 function isCompletelyInViewPort(movement){ 21542 var top = $(SECTION_ACTIVE_SEL).position().top; 21543 var bottom = top + $window.height(); 21544 21545 if(movement == 'up'){ 21546 return bottom >= ($window.scrollTop() + $window.height()); 21547 } 21548 return top <= $window.scrollTop(); 21549 } 21550 21551 /** 21552 * Gets the directon of the the scrolling fired by the scroll event. 21553 */ 21554 function getScrollDirection(currentScroll){ 21555 var direction = currentScroll > lastScroll ? 'down' : 'up'; 21556 21557 lastScroll = currentScroll; 21558 21559 //needed for auto-height sections to determine if we want to scroll to the top or bottom of the destination 21560 previousDestTop = currentScroll; 21561 21562 return direction; 21563 } 21564 21565 /** 21566 * Determines the way of scrolling up or down: 21567 * by 'automatically' scrolling a section or by using the default and normal scrolling. 21568 */ 21569 function scrolling(type, scrollable){ 21570 if (!isScrollAllowed.m[type]){ 21571 return; 21572 } 21573 var check = (type === 'down') ? 'bottom' : 'top'; 21574 var scrollSection = (type === 'down') ? moveSectionDown : moveSectionUp; 21575 21576 if(scrollable.length > 0 ){ 21577 //is the scrollbar at the start/end of the scroll? 21578 if(options.scrollOverflowHandler.isScrolled(check, scrollable)){ 21579 scrollSection(); 21580 }else{ 21581 return true; 21582 } 21583 }else{ 21584 // moved up/down 21585 scrollSection(); 21586 } 21587 } 21588 21589 /* 21590 * Preventing bouncing in iOS #2285 21591 */ 21592 function preventBouncing(event){ 21593 var e = event.originalEvent; 21594 if(!checkParentForNormalScrollElement(event.target) && options.autoScrolling && isReallyTouch(e) && isScrollAllowed.m.up){ 21595 //preventing the easing on iOS devices 21596 event.preventDefault(); 21597 } 21598 } 21599 21600 var touchStartY = 0; 21601 var touchStartX = 0; 21602 var touchEndY = 0; 21603 var touchEndX = 0; 21604 21605 /* Detecting touch events 21606 21607 * As we are changing the top property of the page on scrolling, we can not use the traditional way to detect it. 21608 * This way, the touchstart and the touch moves shows an small difference between them which is the 21609 * used one to determine the direction. 21610 */ 21611 function touchMoveHandler(event){ 21612 var e = event.originalEvent; 21613 var activeSection = $(e.target).closest(SECTION_SEL); 21614 21615 // additional: if one of the normalScrollElements isn't within options.normalScrollElementTouchThreshold hops up the DOM chain 21616 if (!checkParentForNormalScrollElement(event.target) && isReallyTouch(e) ) { 21617 21618 if(options.autoScrolling){ 21619 //preventing the easing on iOS devices 21620 event.preventDefault(); 21621 } 21622 21623 var scrollable = options.scrollOverflowHandler.scrollable(activeSection); 21624 var touchEvents = getEventsPage(e); 21625 21626 touchEndY = touchEvents.y; 21627 touchEndX = touchEvents.x; 21628 21629 //if movement in the X axys is greater than in the Y and the currect section has slides... 21630 if (activeSection.find(SLIDES_WRAPPER_SEL).length && Math.abs(touchStartX - touchEndX) > (Math.abs(touchStartY - touchEndY))) { 21631 21632 //is the movement greater than the minimum resistance to scroll? 21633 if (!slideMoving && Math.abs(touchStartX - touchEndX) > ($window.outerWidth() / 100 * options.touchSensitivity)) { 21634 if (touchStartX > touchEndX) { 21635 if(isScrollAllowed.m.right){ 21636 moveSlideRight(activeSection); //next 21637 } 21638 } else { 21639 if(isScrollAllowed.m.left){ 21640 moveSlideLeft(activeSection); //prev 21641 } 21642 } 21643 } 21644 } 21645 21646 //vertical scrolling (only when autoScrolling is enabled) 21647 else if(options.autoScrolling && canScroll){ 21648 21649 //is the movement greater than the minimum resistance to scroll? 21650 if (Math.abs(touchStartY - touchEndY) > ($window.height() / 100 * options.touchSensitivity)) { 21651 if (touchStartY > touchEndY) { 21652 scrolling('down', scrollable); 21653 } else if (touchEndY > touchStartY) { 21654 scrolling('up', scrollable); 21655 } 21656 } 21657 } 21658 } 21659 } 21660 21661 /** 21662 * recursive function to loop up the parent nodes to check if one of them exists in options.normalScrollElements 21663 * Currently works well for iOS - Android might need some testing 21664 * @param {Element} el target element / jquery selector (in subsequent nodes) 21665 * @param {int} hop current hop compared to options.normalScrollElementTouchThreshold 21666 * @return {boolean} true if there is a match to options.normalScrollElements 21667 */ 21668 function checkParentForNormalScrollElement (el, hop) { 21669 hop = hop || 0; 21670 var parent = $(el).parent(); 21671 21672 if (hop < options.normalScrollElementTouchThreshold && 21673 parent.is(options.normalScrollElements) ) { 21674 return true; 21675 } else if (hop == options.normalScrollElementTouchThreshold) { 21676 return false;
21677 } else { 21678 return checkParentForNormalScrollElement(parent, ++hop); 21679 } 21680 } 21681 21682 /** 21683 * As IE >= 10 fires both touch and mouse events when using a mouse in a touchscreen 21684 * this way we make sure that is really a touch event what IE is detecting. 21685 */ 21686 function isReallyTouch(e){ 21687 //if is not IE || IE is detecting `touch` or `pen` 21688 return typeof e.pointerType === 'undefined' || e.pointerType != 'mouse'; 21689 } 21690 21691 /** 21692 * Handler for the touch start event. 21693 */ 21694 function touchStartHandler(event){ 21695 var e = event.originalEvent; 21696 21697 //stopping the auto scroll to adjust to a section 21698 if(options.fitToSection){ 21699 $htmlBody.stop(); 21700 } 21701 21702 if(isReallyTouch(e)){ 21703 var touchEvents = getEventsPage(e); 21704 touchStartY = touchEvents.y; 21705 touchStartX = touchEvents.x; 21706 } 21707 } 21708 21709 /** 21710 * Gets the average of the last `number` elements of the given array. 21711 */ 21712 function getAverage(elements, number){ 21713 var sum = 0; 21714 21715 //taking `number` elements from the end to make the average, if there are not enought, 1 21716 var lastElements = elements.slice(Math.max(elements.length - number, 1)); 21717 21718 for(var i = 0; i < lastElements.length; i++){ 21719 sum = sum + lastElements[i]; 21720 } 21721 21722 return Math.ceil(sum/number); 21723 } 21724 21725 /** 21726 * Detecting mousewheel scrolling 21727 * 21728 * http://blogs.sitepointstatic.com/examples/tech/mouse-wheel/index.html 21729 * http://www.sitepoint.com/html5-javascript-mouse-wheel/ 21730 */ 21731 var prevTime = new Date().getTime(); 21732 21733 function MouseWheelHandler(e) { 21734 var curTime = new Date().getTime(); 21735 var isNormalScroll = $(COMPLETELY_SEL).hasClass(NORMAL_SCROLL); 21736 21737 //autoscrolling and not zooming? 21738 if(options.autoScrolling && !controlPressed && !isNormalScroll){ 21739 // cross-browser wheel delta 21740 e = e || window.event; 21741 var value = e.wheelDelta || -e.deltaY || -e.detail; 21742 var delta = Math.max(-1, Math.min(1, value)); 21743 21744 var horizontalDetection = typeof e.wheelDeltaX !== 'undefined' || typeof e.deltaX !== 'undefined'; 21745 var isScrollingVertically = (Math.abs(e.wheelDeltaX) < Math.abs(e.wheelDelta)) || (Math.abs(e.deltaX ) < Math.abs(e.deltaY) || !horizontalDetection); 21746 21747 //Limiting the array to 150 (lets not waste memory!) 21748 if(scrollings.length > 149){ 21749 scrollings.shift(); 21750 } 21751 21752 //keeping record of the previous scrollings 21753 scrollings.push(Math.abs(value)); 21754 21755 //preventing to scroll the site on mouse wheel when scrollbar is present 21756 if(options.scrollBar){ 21757 e.preventDefault ? e.preventDefault() : e.returnValue = false; 21758 } 21759 21760 var activeSection = $(SECTION_ACTIVE_SEL); 21761 var scrollable = options.scrollOverflowHandler.scrollable(activeSection); 21762 21763 //time difference between the last scroll and the current one 21764 var timeDiff = curTime-prevTime; 21765 prevTime = curTime; 21766 21767 //haven't they scrolled in a while? 21768 //(enough to be consider a different scrolling action to scroll another section) 21769 if(timeDiff > 200){ 21770 //emptying the array, we dont care about old scrollings for our averages 21771 scrollings = []; 21772 } 21773 21774 if(canScroll){ 21775 var averageEnd = getAverage(scrollings, 10); 21776 var averageMiddle = getAverage(scrollings, 70); 21777 var isAccelerating = averageEnd >= averageMiddle; 21778 21779 //to avoid double swipes... 21780 if(isAccelerating && isScrollingVertically){ 21781 //scrolling down? 21782 if (delta < 0) { 21783 scrolling('down', scrollable); 21784 21785 //scrolling up? 21786 }else { 21787 scrolling('up', scrollable); 21788 } 21789 } 21790 } 21791 21792 return false;
21793 } 21794 21795 if(options.fitToSection){ 21796 //stopping the auto scroll to adjust to a section 21797 $htmlBody.stop(); 21798 } 21799 } 21800 21801 /** 21802 * Slides a slider to the given direction. 21803 * Optional `section` param. 21804 */ 21805 function moveSlide(direction, section){ 21806 var activeSection = typeof section === 'undefined' ? $(SECTION_ACTIVE_SEL) : section; 21807 var slides = activeSection.find(SLIDES_WRAPPER_SEL); 21808 var numSlides = slides.find(SLIDE_SEL).length; 21809 21810 // more than one slide needed and nothing should be sliding 21811 if (!slides.length || slideMoving || numSlides < 2) { 21812 return; 21813 } 21814 21815 var currentSlide = slides.find(SLIDE_ACTIVE_SEL); 21816 var destiny = null; 21817 21818 if(direction === 'left'){ 21819 destiny = currentSlide.prev(SLIDE_SEL); 21820 }else{ 21821 destiny = currentSlide.next(SLIDE_SEL); 21822 } 21823 21824 //isn't there a next slide in the secuence? 21825 if(!destiny.length){ 21826 //respect loopHorizontal settin 21827 if (!options.loopHorizontal) return; 21828 21829 if(direction === 'left'){ 21830 destiny = currentSlide.siblings(':last'); 21831 }else{ 21832 destiny = currentSlide.siblings(':first'); 21833 } 21834 } 21835 21836 slideMoving = true; 21837 21838 landscapeScroll(slides, destiny, direction); 21839 } 21840 21841 /** 21842 * Maintains the active slides in the viewport 21843 * (Because the `scroll` animation might get lost with some actions, such as when using continuousVertical) 21844 */ 21845 function keepSlidesPosition(){ 21846 $(SLIDE_ACTIVE_SEL).each(function(){ 21847 silentLandscapeScroll($(this), 'internal'); 21848 }); 21849 } 21850 21851 var previousDestTop = 0; 21852 /** 21853 * Returns the destination Y position based on the scrolling direction and 21854 * the height of the section. 21855 */ 21856 function getDestinationPosition(element){ 21857 var elemPosition = element.position(); 21858 21859 //top of the desination will be at the top of the viewport 21860 var position = elemPosition.top; 21861 var isScrollingDown = elemPosition.top > previousDestTop; 21862 var sectionBottom = position - windowsHeight + element.outerHeight(); 21863 var bigSectionsDestination = options.bigSectionsDestination; 21864 21865 //Uncode addition 21866 var containerH = container.outerHeight(); 21867 var containerPosition = container.offset(); 21868 21869 //########### Commented by Uncode - START ########### 21870 //is the destination element bigger than the viewport? 21871 // if(element.outerHeight() > windowsHeight){ 21872 // //scrolling up? 21873 // if(!isScrollingDown && !bigSectionsDestination || bigSectionsDestination === 'bottom' ){ 21874 // position = sectionBottom; 21875 // } 21876 // } 21877 21878 // //sections equal or smaller than the viewport height && scrolling down? || is resizing and its in the last section 21879 // else if(isScrollingDown || (isResizing && element.is(':last-child')) ){ 21880 // //The bottom of the destination will be at the bottom of the viewport 21881 // position = sectionBottom; 21882 // } 21883 //########### Commented by Uncode - END ########### 21884 21885 //Uncode addition 21886 if ( !$masthead.hasClass('menu-transparent') && $('body').hasClass('uncode-fp-menu-shrink') && !element.is(':first-child') ) 21887 position += 18; 21888 if ( ( containerH + menuHeight + bodyBorder + adminBarHeight - windowsHeight ) < position || ( isResizing && element.is(':last-child') ) ) { 21889 position = sectionBottom + menuHeight + bodyBorder*2 + adminBarHeight; 21890 } 21891 21892 /* 21893 Keeping record of the last scrolled position to determine the scrolling direction. 21894 No conventional methods can be used as the scroll bar might not be present 21895 AND the section might not be active if it is auto-height and didnt reach the middle 21896 of the viewport. 21897 */ 21898 previousDestTop = position; 21899 return position; 21900 } 21901 21902 /** 21903 * Scrolls the site to the given element and scrolls to the slide if a callback is given. 21904 */ 21905 function scrollPage(element, callback, isMovementUp){ 21906 if(typeof element === 'undefined'){ return; } //there's no element to scroll, leaving the function 21907 21908 var dtop = getDestinationPosition(element); 21909 var slideAnchorLink; 21910 var slideIndex; 21911 21912 //local variables 21913 var v = { 21914 element: element, 21915 callback: callback, 21916 isMovementUp: isMovementUp, 21917 dtop: dtop, 21918 yMovement: getYmovement(element), 21919 anchorLink: element.data('anchor'), 21920 sectionIndex: element.index(SECTION_SEL), 21921 activeSlide: element.find(SLIDE_ACTIVE_SEL), 21922 activeSection: $(SECTION_ACTIVE_SEL), 21923 leavingSection: $(SECTION_ACTIVE_SEL).index(SECTION_SEL) + 1, 21924 21925 //caching the value of isResizing at the momment the function is called 21926 //because it will be checked later inside a setTimeout and the value might change 21927 localIsResizing: isResizing 21928 }; 21929 21930 //quiting when destination scroll is the same as the current one 21931 if((v.activeSection.is(element) && !isResizing) || (options.scrollBar && $window.scrollTop() === v.dtop && !element.hasClass(AUTO_HEIGHT) )){ return; } 21932 21933 if(v.activeSlide.length){ 21934 slideAnchorLink = v.activeSlide.data('anchor'); 21935 slideIndex = v.activeSlide.index(); 21936 } 21937 21938 // If continuousVertical && we need to wrap around 21939 if (options.autoScrolling && options.continuousVertical && typeof (v.isMovementUp) !== "undefined" && 21940 ((!v.isMovementUp && v.yMovement == 'up') || // Intending to scroll down but about to go up or 21941 (v.isMovementUp && v.yMovement == 'down'))) { // intending to scroll up but about to go down 21942 21943 v = createInfiniteSections(v); 21944 } 21945 21946 //callback (onLeave) if the site is not just resizing and readjusting the slides 21947 if($.isFunction(options.onLeave) && !v.localIsResizing){ 21948 if(options.onLeave.call(v.activeSection, v.leavingSection, (v.sectionIndex + 1), v.yMovement) === false){ 21949 return; 21950 } 21951 } 21952 21953 //pausing media of the leaving section (if we are not just resizing, as destinatino will be the same one) 21954 if(!v.localIsResizing){ 21955 stopMedia(v.activeSection); 21956 } 21957 21958 options.scrollOverflowHandler.beforeLeave(); 21959 element.addClass(ACTIVE).siblings().removeClass(ACTIVE); 21960 lazyLoad(element); 21961 options.scrollOverflowHandler.onLeave(); 21962 21963 21964 //preventing from activating the MouseWheelHandler event 21965 //more than once if the page is scrolling 21966 canScroll = false;
21967 21968 setState(slideIndex, slideAnchorLink, v.anchorLink, v.sectionIndex); 21969 21970 performMovement(v); 21971 21972 //flag to avoid callingn `scrollPage()` twice in case of using anchor links 21973 lastScrolledDestiny = v.anchorLink; 21974 21975 //avoid firing it twice (as it does also on scroll) 21976 activateMenuAndNav(v.anchorLink, v.sectionIndex); 21977 } 21978 21979 /** 21980 * Performs the vertical movement (by CSS3 or by jQuery) 21981 */ 21982 function performMovement(v){ 21983 // using CSS3 translate functionality 21984 if (options.css3 && options.autoScrolling && !options.scrollBar) { 21985 21986 // The first section can have a negative value in iOS 10. Not quite sure why: -0.0142822265625 21987 // that's why we round it to 0. 21988 var translate3d = 'translate3d(0px, -' + Math.round(v.dtop) + 'px, 0px)'; 21989 transformContainer(translate3d, true); 21990 21991 //even when the scrollingSpeed is 0 there's a little delay, which might cause the 21992 //scrollingSpeed to change in case of using silentMoveTo(); 21993 if(options.scrollingSpeed){ 21994 clearTimeout(afterSectionLoadsId); 21995 afterSectionLoadsId = setTimeout(function () { 21996 afterSectionLoads(v); 21997 }, options.scrollingSpeed); 21998 }else{ 21999 afterSectionLoads(v); 22000 } 22001 } 22002 22003 // using jQuery animate 22004 else{ 22005 var scrollSettings = getScrollSettings(v); 22006 22007 $(scrollSettings.element).animate( 22008 scrollSettings.options, 22009 options.scrollingSpeed, options.easing).promise().done(function () { //only one single callback in case of animating `html, body` 22010 if(options.scrollBar){ 22011 22012 /* Hack! 22013 The timeout prevents setting the most dominant section in the viewport as "active" when the user 22014 scrolled to a smaller section by using the mousewheel (auto scrolling) rather than draging the scroll bar. 22015 22016 When using scrollBar:true It seems like the scroll events still getting propagated even after the scrolling animation has finished. 22017 */ 22018 setTimeout(function(){ 22019 afterSectionLoads(v); 22020 },30); 22021 }else{ 22022 afterSectionLoads(v); 22023 } 22024 }); 22025 } 22026 } 22027 22028 /** 22029 * Gets the scrolling settings depending on the plugin autoScrolling option 22030 */ 22031 function getScrollSettings(v){ 22032 var scroll = {}; 22033 22034 if(options.autoScrolling && !options.scrollBar){ 22035 scroll.options = { 'top': -v.dtop}; 22036 scroll.element = WRAPPER_SEL; 22037 }else{ 22038 scroll.options = { 'scrollTop': v.dtop}; 22039 scroll.element = 'html, body'; 22040 } 22041 22042 return scroll; 22043 } 22044 22045 /** 22046 * Adds sections before or after the current one to create the infinite effect. 22047 */ 22048 function createInfiniteSections(v){ 22049 // Scrolling down 22050 if (!v.isMovementUp) { 22051 // Move all previous sections to after the active section 22052 $(SECTION_ACTIVE_SEL).after(v.activeSection.prevAll(SECTION_SEL).get().reverse()); 22053 } 22054 else { // Scrolling up 22055 // Move all next sections to before the active section 22056 $(SECTION_ACTIVE_SEL).before(v.activeSection.nextAll(SECTION_SEL)); 22057 } 22058 22059 // Maintain the displayed position (now that we changed the element order) 22060 silentScroll($(SECTION_ACTIVE_SEL).position().top); 22061 22062 // Maintain the active slides visible in the viewport 22063 keepSlidesPosition(); 22064 22065 // save for later the elements that still need to be reordered 22066 v.wrapAroundElements = v.activeSection; 22067 22068 // Recalculate animation variables 22069 v.dtop = v.element.position().top; 22070 v.yMovement = getYmovement(v.element); 22071 22072 return v; 22073 } 22074 22075 /** 22076 * Fix section order after continuousVertical changes have been animated 22077 */ 22078 function continuousVerticalFixSectionOrder (v) {
22079 // If continuousVertical is in effect (and autoScrolling would also be in effect then), 22080 // finish moving the elements around so the direct navigation will function more simply 22081 if (!v.wrapAroundElements || !v.wrapAroundElements.length) { 22082 return; 22083 } 22084 22085 if (v.isMovementUp) { 22086 $(SECTION_FIRST_SEL).before(v.wrapAroundElements); 22087 } 22088 else { 22089 $(SECTION_LAST_SEL).after(v.wrapAroundElements); 22090 } 22091 22092 silentScroll($(SECTION_ACTIVE_SEL).position().top); 22093 22094 // Maintain the active slides visible in the viewport 22095 keepSlidesPosition(); 22096 } 22097 22098 22099 /** 22100 * Actions to do once the section is loaded. 22101 */ 22102 function afterSectionLoads (v){ 22103 continuousVerticalFixSectionOrder(v); 22104 22105 //callback (afterLoad) if the site is not just resizing and readjusting the slides 22106 $.isFunction(options.afterLoad) && !v.localIsResizing && options.afterLoad.call(v.element, v.anchorLink, (v.sectionIndex + 1)); 22107 options.scrollOverflowHandler.afterLoad(); 22108 22109 if(!v.localIsResizing){ 22110 playMedia(v.element); 22111 } 22112 22113 v.element.addClass(COMPLETELY).siblings().removeClass(COMPLETELY); 22114 22115 canScroll = true; 22116 22117 $.isFunction(v.callback) && v.callback.call(this); 22118 } 22119 22120 /** 22121 * Sets the value for the given attribute from the `data-` attribute with the same suffix 22122 * ie: data-srcset ==> srcset | data-src ==> src 22123 */ 22124 function setSrc(element, attribute){ 22125 element 22126 .attr(attribute, element.data(attribute)) 22127 .removeAttr('data-' + attribute); 22128 } 22129 22130 /** 22131 * Lazy loads image, video and audio elements. 22132 */ 22133 function lazyLoad(destiny){ 22134 if (!options.lazyLoading){ 22135 return; 22136 } 22137 22138 var panel = getSlideOrSection(destiny); 22139 var element; 22140 22141 panel.find('img[data-src], img[data-srcset], source[data-src], audio[data-src], iframe[data-src]').each(function(){ 22142 element = $(this); 22143 22144 $.each(['src', 'srcset'], function(index, type){ 22145 var attribute = element.attr('data-' + type); 22146 if(typeof attribute !== 'undefined' && attribute){ 22147 setSrc(element, type); 22148 } 22149 }); 22150 22151 if(element.is('source')){ 22152 element.closest('video').get(0).load(); 22153 } 22154 }); 22155 } 22156 22157 /** 22158 * Plays video and audio elements. 22159 */ 22160 function playMedia(destiny){ 22161 var panel = getSlideOrSection(destiny); 22162 22163 //playing HTML5 media elements 22164 panel.find('video, audio').each(function(){ 22165 var element = $(this).get(0); 22166 22167 if( element.hasAttribute('data-autoplay') && typeof element.play === 'function' ) { 22168 element.play(); 22169 } 22170 }); 22171 22172 //youtube videos 22173 panel.find('iframe[src*="youtube.com/embed/"]').each(function(){ 22174 var element = $(this).get(0); 22175 22176 if ( element.hasAttribute('data-autoplay') ){ 22177 playYoutube(element); 22178 } 22179 22180 //in case the URL was not loaded yet. On page load we need time for the new URL (with the API string) to load. 22181 element.onload = function() { 22182 if ( element.hasAttribute('data-autoplay') ){ 22183 playYoutube(element); 22184 } 22185 }; 22186 }); 22187 } 22188 22189 /** 22190 * Plays a youtube video 22191 */ 22192 function playYoutube(element){ 22193 element.contentWindow.postMessage('{"event":"command","func":"playVideo","args":""}', '*'); 22194 } 22195 22196 /** 22197 * Stops video and audio elements. 22198 */ 22199 function stopMedia(destiny){ 22200 var panel = getSlideOrSection(destiny); 22201 22202 //stopping HTML5 media elements 22203 panel.find('video, audio').each(function(){ 22204 var element = $(this).get(0); 22205 22206 if( !element.hasAttribute('data-keepplaying') && typeof element.pause === 'function' ) { 22207 element.pause(); 22208 } 22209 }); 22210 22211 //youtube videos 22212 panel.find('iframe[src*="youtube.com/embed/"]').each(function(){ 22213 var element = $(this).get(0); 22214 22215 if( /youtube\.com\/embed\//.test($(this).attr('src')) && !element.hasAttribute('data-keepplaying')){ 22216 $(this).get(0).contentWindow.postMessage('{"event":"command","func":"pauseVideo","args":""}','*'); 22217 } 22218 }); 22219 } 22220 22221 /** 22222 * Gets the active slide (or section) for the given section 22223 */ 22224 function getSlideOrSection(destiny){ 22225 var slide = destiny.find(SLIDE_ACTIVE_SEL); 22226 if( slide.length ) { 22227 destiny = $(slide); 22228 } 22229 22230 return destiny; 22231 } 22232 22233 /**
22234 * Scrolls to the anchor in the URL when loading the site 22235 */ 22236 function scrollToAnchor(){ 22237 //getting the anchor link in the URL and deleting the `#` 22238 var value = window.location.hash.replace('#', '').split('/'); 22239 var sectionAnchor = decodeURIComponent(value[0]); 22240 var slideAnchor = decodeURIComponent(value[1]); 22241 22242 if(sectionAnchor){ //if theres any # 22243 if(options.animateAnchor){ 22244 scrollPageAndSlide(sectionAnchor, slideAnchor); 22245 }else{ 22246 silentMoveTo(sectionAnchor, slideAnchor); 22247 } 22248 } 22249 } 22250 22251 /** 22252 * Detecting any change on the URL to scroll to the given anchor link 22253 * (a way to detect back history button as we play with the hashes on the URL) 22254 */ 22255 function hashChangeHandler(){ 22256 if(!isScrolling && !options.lockAnchors){ 22257 var value = window.location.hash.replace('#', '').split('/'); 22258 var sectionAnchor = decodeURIComponent(value[0]); 22259 var slideAnchor = decodeURIComponent(value[1]); 22260 22261 //when moving to a slide in the first section for the first time (first time to add an anchor to the URL) 22262 var isFirstSlideMove = (typeof lastScrolledDestiny === 'undefined'); 22263 var isFirstScrollMove = (typeof lastScrolledDestiny === 'undefined' && typeof slideAnchor === 'undefined' && !slideMoving); 22264 22265 22266 if(sectionAnchor.length){ 22267 /*in order to call scrollpage() only once for each destination at a time 22268 It is called twice for each scroll otherwise, as in case of using anchorlinks `hashChange` 22269 event is fired on every scroll too.*/ 22270 if ((sectionAnchor && sectionAnchor !== lastScrolledDestiny) && !isFirstSlideMove || isFirstScrollMove || (!slideMoving && lastScrolledSlide != slideAnchor )) { 22271 scrollPageAndSlide(sectionAnchor, slideAnchor); 22272 } 22273 } 22274 } 22275 } 22276 22277 //Sliding with arrow keys, both, vertical and horizontal 22278 function keydownHandler(e) { 22279 22280 clearTimeout(keydownId); 22281 22282 var activeElement = $(':focus'); 22283 22284 if(!activeElement.is('textarea') && !activeElement.is('input') && !activeElement.is('select') && 22285 activeElement.attr('contentEditable') !== "true" && activeElement.attr('contentEditable') !== '' && 22286 options.keyboardScrolling && options.autoScrolling){ 22287 var keyCode = e.which; 22288 22289 //preventing the scroll with arrow keys & spacebar & Page Up & Down keys 22290 var keyControls = [40, 38, 32, 33, 34]; 22291 if($.inArray(keyCode, keyControls) > -1){ 22292 e.preventDefault(); 22293 } 22294 22295 controlPressed = e.ctrlKey; 22296 22297 keydownId = setTimeout(function(){ 22298 onkeydown(e); 22299 },150); 22300 } 22301 } 22302 22303 function tooltipTextHandler(){ 22304 $(this).prev().trigger('click'); 22305 } 22306 22307 //to prevent scrolling while zooming 22308 function keyUpHandler(e){ 22309 if(isWindowFocused){ //the keyup gets fired on new tab ctrl + t in Firefox 22310 controlPressed = e.ctrlKey; 22311 } 22312 } 22313 22314 //binding the mousemove when the mouse's middle button is released 22315 function mouseDownHandler(e){ 22316 //middle button 22317 if (e.which == 2){ 22318 oldPageY = e.pageY; 22319 container.on('mousemove', mouseMoveHandler); 22320 } 22321 } 22322 22323 //unbinding the mousemove when the mouse's middle button is released 22324 function mouseUpHandler(e){ 22325 //middle button 22326 if (e.which == 2){ 22327 container.off('mousemove'); 22328 } 22329 } 22330 22331 //Scrolling horizontally when clicking on the slider controls. 22332 function slideArrowHandler(){ 22333 var section = $(this).closest(SECTION_SEL); 22334 22335 if ($(this).hasClass(SLIDES_PREV)) { 22336 if(isScrollAllowed.m.left){ 22337 moveSlideLeft(section); 22338 } 22339 } else { 22340 if(isScrollAllowed.m.right){ 22341 moveSlideRight(section); 22342 } 22343 } 22344 } 22345 22346 //when opening a new tab (ctrl + t), `control` won't be pressed when coming back. 22347 function blurHandler(){ 22348 isWindowFocused = false;
22349 controlPressed = false; 22350 } 22351 22352 //Scrolls to the section when clicking the navigation bullet 22353 function sectionBulletHandler(e){ 22354 e.preventDefault(); 22355 var index = $(this).parent().index(); 22356 scrollPage($(SECTION_SEL).eq(index)); 22357 } 22358 22359 //Scrolls the slider to the given slide destination for the given section 22360 function slideBulletHandler(e){ 22361 e.preventDefault(); 22362 var slides = $(this).closest(SECTION_SEL).find(SLIDES_WRAPPER_SEL); 22363 var destiny = slides.find(SLIDE_SEL).eq($(this).closest('li').index()); 22364 22365 landscapeScroll(slides, destiny); 22366 } 22367 22368 /** 22369 * Keydown event 22370 */ 22371 function onkeydown(e){ 22372 var shiftPressed = e.shiftKey; 22373 22374 //do nothing if we can not scroll or we are not using horizotnal key arrows. 22375 if(!canScroll && [37,39].indexOf(e.which) < 0){ 22376 return; 22377 } 22378 22379 switch (e.which) { 22380 //up 22381 case 38: 22382 case 33: 22383 if(isScrollAllowed.k.up){ 22384 moveSectionUp(); 22385 } 22386 break; 22387 22388 //down 22389 case 32: //spacebar 22390 if(shiftPressed && isScrollAllowed.k.up){ 22391 moveSectionUp(); 22392 break; 22393 } 22394 /* falls through */ 22395 case 40: 22396 case 34: 22397 if(isScrollAllowed.k.down){ 22398 moveSectionDown(); 22399 } 22400 break; 22401 22402 //Home 22403 case 36: 22404 if(isScrollAllowed.k.up){ 22405 moveTo(1); 22406 } 22407 break; 22408 22409 //End 22410 case 35: 22411 if(isScrollAllowed.k.down){ 22412 moveTo( $(SECTION_SEL).length ); 22413 } 22414 break; 22415 22416 //left 22417 case 37: 22418 if(isScrollAllowed.k.left){ 22419 moveSlideLeft(); 22420 } 22421 break; 22422 22423 //right 22424 case 39: 22425 if(isScrollAllowed.k.right){ 22426 moveSlideRight(); 22427 } 22428 break; 22429 22430 default: 22431 return; // exit this handler for other keys 22432 } 22433 } 22434 22435 /** 22436 * Detecting the direction of the mouse movement. 22437 * Used only for the middle button of the mouse. 22438 */ 22439 var oldPageY = 0; 22440 function mouseMoveHandler(e){ 22441 if(canScroll){ 22442 // moving up 22443 if (e.pageY < oldPageY && isScrollAllowed.m.up){ 22444 moveSectionUp(); 22445 } 22446 22447 // moving down 22448 else if(e.pageY > oldPageY && isScrollAllowed.m.down){ 22449 moveSectionDown(); 22450 } 22451 } 22452 oldPageY = e.pageY; 22453 } 22454 22455 /** 22456 * Scrolls horizontal sliders. 22457 */ 22458 function landscapeScroll(slides, destiny, direction){ 22459 var section = slides.closest(SECTION_SEL); 22460 var v = { 22461 slides: slides, 22462 destiny: destiny, 22463 direction: direction, 22464 destinyPos: destiny.position(), 22465 slideIndex: destiny.index(), 22466 section: section, 22467 sectionIndex: section.index(SECTION_SEL), 22468 anchorLink: section.data('anchor'), 22469 slidesNav: section.find(SLIDES_NAV_SEL), 22470 slideAnchor: getAnchor(destiny), 22471 prevSlide: section.find(SLIDE_ACTIVE_SEL), 22472 prevSlideIndex: section.find(SLIDE_ACTIVE_SEL).index(), 22473 22474 //caching the value of isResizing at the momment the function is called 22475 //because it will be checked later inside a setTimeout and the value might change 22476 localIsResizing: isResizing 22477 }; 22478 v.xMovement = getXmovement(v.prevSlideIndex, v.slideIndex); 22479 v.direction = v.direction ? v.direction : v.xMovement; 22480 22481 //important!! Only do it when not resizing 22482 if(!v.localIsResizing){ 22483 //preventing from scrolling to the next/prev section when using scrollHorizontally 22484 canScroll = false;
22485 } 22486 22487 if(options.onSlideLeave){ 22488 22489 //if the site is not just resizing and readjusting the slides 22490 if(!v.localIsResizing && v.xMovement!=='none'){ 22491 if($.isFunction( options.onSlideLeave )){ 22492 if(options.onSlideLeave.call( v.prevSlide, v.anchorLink, (v.sectionIndex + 1), v.prevSlideIndex, v.xMovement, v.slideIndex ) === false){ 22493 slideMoving = false; 22494 return; 22495 } 22496 } 22497 } 22498 } 22499 22500 destiny.addClass(ACTIVE).siblings().removeClass(ACTIVE); 22501 22502 if(!v.localIsResizing){ 22503 stopMedia(v.prevSlide); 22504 lazyLoad(destiny); 22505 } 22506 22507 if(!options.loopHorizontal && options.controlArrows){ 22508 //hidding it for the fist slide, showing for the rest 22509 section.find(SLIDES_ARROW_PREV_SEL).toggle(v.slideIndex!==0); 22510 22511 //hidding it for the last slide, showing for the rest 22512 section.find(SLIDES_ARROW_NEXT_SEL).toggle(!destiny.is(':last-child')); 22513 } 22514 22515 //only changing the URL if the slides are in the current section (not for resize re-adjusting) 22516 if(section.hasClass(ACTIVE) && !v.localIsResizing){ 22517 setState(v.slideIndex, v.slideAnchor, v.anchorLink, v.sectionIndex); 22518 } 22519 22520 performHorizontalMove(slides, v, true); 22521 } 22522 22523 22524 function afterSlideLoads(v){ 22525 activeSlidesNavigation(v.slidesNav, v.slideIndex); 22526 22527 //if the site is not just resizing and readjusting the slides 22528 if(!v.localIsResizing){ 22529 $.isFunction( options.afterSlideLoad ) && options.afterSlideLoad.call( v.destiny, v.anchorLink, (v.sectionIndex + 1), v.slideAnchor, v.slideIndex); 22530 22531 //needs to be inside the condition to prevent problems with continuousVertical and scrollHorizontally 22532 //and to prevent double scroll right after a windows resize 22533 canScroll = true; 22534 22535 playMedia(v.destiny); 22536 } 22537 22538 //letting them slide again 22539 slideMoving = false; 22540 } 22541 22542 /** 22543 * Performs the horizontal movement. (CSS3 or jQuery) 22544 * 22545 * @param fireCallback {Bool} - determines whether or not to fire the callback 22546 */ 22547 function performHorizontalMove(slides, v, fireCallback){ 22548 var destinyPos = v.destinyPos; 22549 22550 if(options.css3){ 22551 var translate3d = 'translate3d(-' + Math.round(destinyPos.left) + 'px, 0px, 0px)'; 22552 22553 addAnimation(slides.find(SLIDES_CONTAINER_SEL)).css(getTransforms(translate3d), v); 22554 22555 afterSlideLoadsId = setTimeout(function(){ 22556 fireCallback && afterSlideLoads(v); 22557 }, options.scrollingSpeed, options.easing); 22558 }else{ 22559 slides.animate({ 22560 scrollLeft : Math.round(destinyPos.left) 22561 }, options.scrollingSpeed, options.easing, function() { 22562 22563 fireCallback && afterSlideLoads(v); 22564 }); 22565 } 22566 } 22567 22568 /** 22569 * Sets the state for the horizontal bullet navigations. 22570 */ 22571 function activeSlidesNavigation(slidesNav, slideIndex){ 22572 slidesNav.find(ACTIVE_SEL).removeClass(ACTIVE); 22573 slidesNav.find('li').eq(slideIndex).find('a').addClass(ACTIVE); 22574 } 22575 22576 var previousHeight = windowsHeight; 22577 22578 //when resizing the site, we adjust the heights of the sections, slimScroll... 22579 function resizeHandler(){ 22580 //checking if it needs to get responsive 22581 responsive(); 22582 22583 // rebuild immediately on touch devices 22584 if (isTouchDevice) { 22585 var activeElement = $(document.activeElement); 22586 22587 //if the keyboard is NOT visible 22588 if (!activeElement.is('textarea') && !activeElement.is('input') && !activeElement.is('select')) { 22589 var currentHeight = $window.height(); 22590 22591 //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) 22592 if( Math.abs(currentHeight - previousHeight) > (20 * Math.max(previousHeight, currentHeight) / 100) ){ 22593 reBuild(true); 22594 previousHeight = currentHeight; 22595 } 22596 } 22597 }else{ 22598 //in order to call the functions only when the resize is finished 22599 //http://stackoverflow.com/questions/4298612/jquery-how-to-call-resize-event-only-once-its-finished-resizing 22600 clearTimeout(resizeId); 22601 22602 resizeId = setTimeout(function(){ 22603 reBuild(true); 22604 }, 350); 22605 } 22606 } 22607 22608 /** 22609 * Checks if the site needs to get responsive and disables autoScrolling if so. 22610 * A class `fp-responsive` is added to the plugin's container in case the user wants to use it for his own responsive CSS. 22611 */ 22612 function responsive(){ 22613 var widthLimit = options.responsive || options.responsiveWidth; //backwards compatiblity 22614 var heightLimit = options.responsiveHeight; 22615 22616 //only calculating what we need. Remember its called on the resize event. 22617 var isBreakingPointWidth = widthLimit && $window.outerWidth() < widthLimit; 22618 var isBreakingPointHeight = heightLimit && $window.height() < heightLimit; 22619 22620 if(widthLimit && heightLimit){ 22621 setResponsive(isBreakingPointWidth || isBreakingPointHeight); 22622 } 22623 else if(widthLimit){ 22624 setResponsive(isBreakingPointWidth); 22625 } 22626 else if(heightLimit){ 22627 setResponsive(isBreakingPointHeight); 22628 } 22629 } 22630 22631 /** 22632 * Adds transition animations for the given element 22633 */ 22634 function addAnimation(container, element){ 22635 var transition = 'all ' + options.scrollingSpeed + 'ms ' + options.easingcss3; 22636 22637 container.removeClass(NO_TRANSITION); 22638 return container.css({
22639 '-webkit-transition': transition, 22640 'transition': transition 22641 }); 22642 } 22643 22644 /** 22645 * Remove transition animations for the given element 22646 */ 22647 function removeAnimation(element){ 22648 return element.addClass(NO_TRANSITION); 22649 } 22650 22651 /** 22652 * Activating the vertical navigation bullets according to the given slide name. 22653 */ 22654 function activateNavDots(name, sectionIndex){ 22655 if(options.navigation){ 22656 $(SECTION_NAV_SEL).find(ACTIVE_SEL).removeClass(ACTIVE); 22657 if(name){ 22658 $(SECTION_NAV_SEL).find('a[href="#' + name + '"]').addClass(ACTIVE); 22659 }else{ 22660 $(SECTION_NAV_SEL).find('li').eq(sectionIndex).find('a').addClass(ACTIVE); 22661 } 22662 } 22663 } 22664 22665 /** 22666 * Activating the website main menu elements according to the given slide name. 22667 */ 22668 function activateMenuElement(name){ 22669 if(options.menu){ 22670 $(options.menu).find(ACTIVE_SEL).removeClass(ACTIVE); 22671 $(options.menu).find('[data-menuanchor="'+name+'"]').addClass(ACTIVE); 22672 } 22673 } 22674 22675 /** 22676 * Sets to active the current menu and vertical nav items. 22677 */ 22678 function activateMenuAndNav(anchor, index){ 22679 activateMenuElement(anchor); 22680 activateNavDots(anchor, index); 22681 } 22682 22683 /** 22684 * Retuns `up` or `down` depending on the scrolling movement to reach its destination 22685 * from the current section. 22686 */ 22687 function getYmovement(destiny){ 22688 var fromIndex = $(SECTION_ACTIVE_SEL).index(SECTION_SEL); 22689 var toIndex = destiny.index(SECTION_SEL); 22690 if( fromIndex == toIndex){ 22691 return 'none'; 22692 } 22693 if(fromIndex > toIndex){ 22694 return 'up'; 22695 } 22696 return 'down'; 22697 } 22698 22699 /** 22700 * Retuns `right` or `left` depending on the scrolling movement to reach its destination 22701 * from the current slide. 22702 */ 22703 function getXmovement(fromIndex, toIndex){ 22704 if( fromIndex == toIndex){ 22705 return 'none'; 22706 } 22707 if(fromIndex > toIndex){ 22708 return 'left'; 22709 } 22710 return 'right'; 22711 } 22712 22713 /** 22714 * Checks if the element needs scrollbar and if the user wants to apply it. 22715 * If so it creates it. 22716 * 22717 * @param {Object} element jQuery object of the section or slide 22718 */ 22719 function createScrollBar(element){ 22720 //User doesn't want scrollbar here? Sayonara baby! 22721 if(element.hasClass('fp-noscroll')) return; 22722 22723 //needed to make `scrollHeight` work under Opera 12 22724 element.css('overflow', 'hidden'); 22725 22726 var scrollOverflowHandler = options.scrollOverflowHandler; 22727 var wrap = scrollOverflowHandler.wrapContent(); 22728 //in case element is a slide 22729 var section = element.closest(SECTION_SEL); 22730 var scrollable = scrollOverflowHandler.scrollable(element); 22731 var contentHeight; 22732 22733 //if there was scroll, the contentHeight will be the one in the scrollable section 22734 if(scrollable.length){ 22735 contentHeight = scrollOverflowHandler.scrollHeight(element); 22736 }else{ 22737 contentHeight = element.get(0).scrollHeight; 22738 if(options.verticalCentered){ 22739 contentHeight = element.find(TABLE_CELL_SEL).get(0).scrollHeight; 22740 } 22741 } 22742 22743 var scrollHeight = windowsHeight - parseInt(section.css('padding-bottom')) - parseInt(section.css('padding-top')); 22744 22745 //needs scroll? 22746 if ( contentHeight > scrollHeight) { 22747 //did we already have an scrollbar ? Updating it 22748 if(scrollable.length){ 22749 scrollOverflowHandler.update(element, scrollHeight); 22750 } 22751 //creating the scrolling 22752 else{ 22753 if(options.verticalCentered){ 22754 element.find(TABLE_CELL_SEL).wrapInner(wrap); 22755 }else{ 22756 element.wrapInner(wrap); 22757 } 22758 scrollOverflowHandler.create(element, scrollHeight); 22759 } 22760 } 22761 //removing the scrolling when it is not necessary anymore 22762 else{ 22763 scrollOverflowHandler.remove(element); 22764 } 22765 22766 //undo 22767 element.css('overflow', ''); 22768 } 22769 22770 function addTableClass(element){ 22771 //In case we are styling for the 2nd time as in with reponsiveSlides 22772 if(!element.hasClass(TABLE)){ 22773 element.addClass(TABLE).wrapInner('<div class="' + TABLE_CELL + '" style="height:' + getTableHeight(element) + 'px;" />'); 22774 } 22775 } 22776 22777 function getTableHeight(element){ 22778 var sectionHeight = windowsHeight; 22779 22780 if(options.paddingTop || options.paddingBottom){ 22781 var section = element; 22782 if(!section.hasClass(SECTION)){ 22783 section = element.closest(SECTION_SEL); 22784 } 22785 22786 var paddings = parseInt(section.css('padding-top')) + parseInt(section.css('padding-bottom')); 22787 sectionHeight = (windowsHeight - paddings); 22788 } 22789 22790 return sectionHeight; 22791 } 22792 22793 /** 22794 * Adds a css3 transform property to the container class with or without animation depending on the animated param. 22795 */ 22796 function transformContainer(translate3d, animated){ 22797 if(animated){ 22798 addAnimation(container); 22799 }else{ 22800 removeAnimation(container); 22801 } 22802 22803 container.css(getTransforms(translate3d)); 22804 22805 //syncronously removing the class after the animation has been applied. 22806 setTimeout(function(){ 22807 container.removeClass(NO_TRANSITION); 22808 },10); 22809 } 22810 22811 /** 22812 * Gets a section by its anchor / index 22813 */ 22814 function getSectionByAnchor(sectionAnchor){ 22815 if(!sectionAnchor) return []; 22816 22817 var section = container.find(SECTION_SEL + '[data-anchor="'+sectionAnchor+'"]'); 22818 if(!section.length){ 22819 section = $(SECTION_SEL).eq( sectionAnchor -1); 22820 } 22821 22822 return section; 22823 } 22824 22825 /** 22826 * Gets a slide inside a given section by its anchor / index 22827 */ 22828 function getSlideByAnchor(slideAnchor, section){ 22829 var slides = section.find(SLIDES_WRAPPER_SEL); 22830 var slide = slides.find(SLIDE_SEL + '[data-anchor="'+slideAnchor+'"]'); 22831
22832 if(!slide.length){ 22833 slide = slides.find(SLIDE_SEL).eq(slideAnchor); 22834 } 22835 22836 return slide; 22837 } 22838 22839 /** 22840 * Scrolls to the given section and slide anchors 22841 */ 22842 function scrollPageAndSlide(destiny, slide){ 22843 var section = getSectionByAnchor(destiny); 22844 22845 //do nothing if there's no section with the given anchor name 22846 if(!section.length) return; 22847 22848 //default slide 22849 if (typeof slide === 'undefined') { 22850 slide = 0; 22851 } 22852 22853 //we need to scroll to the section and then to the slide 22854 if (destiny !== lastScrolledDestiny && !section.hasClass(ACTIVE)){ 22855 scrollPage(section, function(){ 22856 scrollSlider(section, slide); 22857 }); 22858 } 22859 //if we were already in the section 22860 else{ 22861 scrollSlider(section, slide); 22862 } 22863 } 22864 22865 /** 22866 * Scrolls the slider to the given slide destination for the given section 22867 */ 22868 function scrollSlider(section, slideAnchor){ 22869 if(typeof slideAnchor !== 'undefined'){ 22870 var slides = section.find(SLIDES_WRAPPER_SEL); 22871 var destiny = getSlideByAnchor(slideAnchor, section); 22872 22873 if(destiny.length){ 22874 landscapeScroll(slides, destiny); 22875 } 22876 } 22877 } 22878 22879 /** 22880 * Creates a landscape navigation bar with dots for horizontal sliders. 22881 */ 22882 function addSlidesNavigation(section, numSlides){ 22883 section.append('<div class="' + SLIDES_NAV + '"><ul></ul></div>'); 22884 var nav = section.find(SLIDES_NAV_SEL); 22885 22886 //top or bottom 22887 nav.addClass(options.slidesNavPosition); 22888 22889 for(var i=0; i< numSlides; i++){ 22890 nav.find('ul').append('<li><a href="#"><span></span></a></li>'); 22891 } 22892 22893 //centering it 22894 nav.css('margin-left', '-' + (nav.width()/2) + 'px'); 22895 22896 nav.find('li').first().find('a').addClass(ACTIVE); 22897 } 22898 22899 22900 /** 22901 * Sets the state of the website depending on the active section/slide. 22902 * It changes the URL hash when needed and updates the body class. 22903 */ 22904 function setState(slideIndex, slideAnchor, anchorLink, sectionIndex){ 22905 var sectionHash = ''; 22906 22907 if(options.anchors.length && !options.lockAnchors){ 22908 22909 //isn't it the first slide? 22910 if(slideIndex){ 22911 if(typeof anchorLink !== 'undefined'){ 22912 sectionHash = anchorLink; 22913 } 22914 22915 //slide without anchor link? We take the index instead. 22916 if(typeof slideAnchor === 'undefined'){ 22917 slideAnchor = slideIndex; 22918 } 22919 22920 lastScrolledSlide = slideAnchor; 22921 setUrlHash(sectionHash + '/' + slideAnchor); 22922 22923 //first slide won't have slide anchor, just the section one 22924 }else if(typeof slideIndex !== 'undefined'){ 22925 lastScrolledSlide = slideAnchor; 22926 setUrlHash(anchorLink); 22927 } 22928 22929 //section without slides 22930 else{ 22931 setUrlHash(anchorLink); 22932 } 22933 } 22934 22935 setBodyClass(); 22936 } 22937 22938 /** 22939 * Sets the URL hash. 22940 */ 22941 function setUrlHash(url){ 22942 //Uncode addition 22943 if ( typeof SiteParameters.slide_footer != 'undefined' && url == SiteParameters.slide_footer ) 22944 return false; 22945 22946 if(options.recordHistory){ 22947 location.hash = url; 22948 }else{ 22949 //Uncode addition 22950 //Mobile Chrome doesn't work the normal way, so... lets use HTML5 for phones :) 22951 // if(isTouchDevice || isTouch){ 22952 // window.history.replaceState(undefined, undefined, '#' + url); 22953 // }else{ 22954 // var baseUrl = window.location.href.split('#')[0]; 22955 // window.location.replace( baseUrl + '#' + url ); 22956 // } 22957 return false;
22958 } 22959 } 22960 22961 /** 22962 * Gets the anchor for the given slide / section. Its index will be used if there's none. 22963 */ 22964 function getAnchor(element){ 22965 var anchor = element.data('anchor'); 22966 var index = element.index(); 22967 22968 //Slide without anchor link? We take the index instead. 22969 if(typeof anchor === 'undefined'){ 22970 anchor = index; 22971 } 22972 22973 return anchor; 22974 } 22975 22976 /** 22977 * Sets a class for the body of the page depending on the active section / slide 22978 */ 22979 function setBodyClass(){ 22980 var section = $(SECTION_ACTIVE_SEL); 22981 var slide = section.find(SLIDE_ACTIVE_SEL); 22982 22983 var sectionAnchor = getAnchor(section); 22984 var slideAnchor = getAnchor(slide); 22985 22986 var text = String(sectionAnchor); 22987 22988 if(slide.length){ 22989 text = text + '-' + slideAnchor; 22990 } 22991 22992 //changing slash for dash to make it a valid CSS style 22993 text = text.replace('/', '-').replace('#',''); 22994 22995 //removing previous anchor classes 22996 var classRe = new RegExp('\\b\\s?' + VIEWING_PREFIX + '-[^\\s]+\\b', "g"); 22997 $body[0].className = $body[0].className.replace(classRe, ''); 22998 22999 //adding the current anchor 23000 $body.addClass(VIEWING_PREFIX + '-' + text); 23001 } 23002 23003 /** 23004 * Checks for translate3d support 23005 * @return boolean 23006 * http://stackoverflow.com/questions/5661671/detecting-transform-translate3d-support 23007 */ 23008 function support3d() { 23009 var el = document.createElement('p'), 23010 has3d, 23011 transforms = { 23012 'webkitTransform':'-webkit-transform', 23013 'OTransform':'-o-transform', 23014 'msTransform':'-ms-transform', 23015 'MozTransform':'-moz-transform', 23016 'transform':'transform' 23017 }; 23018 23019 // Add it to the body to get the computed style. 23020 document.body.insertBefore(el, null); 23021 23022 for (var t in transforms) { 23023 if (el.style[t] !== undefined) { 23024 el.style[t] = 'translate3d(1px,1px,1px)'; 23025 has3d = window.getComputedStyle(el).getPropertyValue(transforms[t]); 23026 } 23027 } 23028 23029 document.body.removeChild(el); 23030 23031 return (has3d !== undefined && has3d.length > 0 && has3d !== 'none'); 23032 } 23033 23034 /** 23035 * Removes the auto scrolling action fired by the mouse wheel and trackpad. 23036 * After this function is called, the mousewheel and trackpad movements won't scroll through sections. 23037 */ 23038 function removeMouseWheelHandler(){ 23039 if (document.addEventListener) { 23040 document.removeEventListener('mousewheel', MouseWheelHandler, false); //IE9, Chrome, Safari, Oper 23041 document.removeEventListener('wheel', MouseWheelHandler, false); //Firefox 23042 document.removeEventListener('MozMousePixelScroll', MouseWheelHandler, false); //old Firefox 23043 } else { 23044 document.detachEvent('onmousewheel', MouseWheelHandler); //IE 6/7/8 23045 } 23046 } 23047 23048 /** 23049 * Adds the auto scrolling action for the mouse wheel and trackpad. 23050 * After this function is called, the mousewheel and trackpad movements will scroll through sections 23051 * https://developer.mozilla.org/en-US/docs/Web/Events/wheel 23052 */ 23053 function addMouseWheelHandler(){ 23054 var prefix = ''; 23055 var _addEventListener; 23056 23057 if (window.addEventListener){ 23058 _addEventListener = "addEventListener"; 23059 }else{ 23060 _addEventListener = "attachEvent"; 23061 prefix = 'on'; 23062 } 23063 23064 // detect available wheel event 23065 var support = 'onwheel' in document.createElement('div') ? 'wheel' : // Modern browsers support "wheel" 23066 document.onmousewheel !== undefined ? 'mousewheel' : // Webkit and IE support at least "mousewheel" 23067 'DOMMouseScroll'; // let's assume that remaining browsers are older Firefox 23068 var passiveEvent = g_supportsPassive ? {passive: false }
23068: false; 23069 23070 23071 if(support == 'DOMMouseScroll'){ 23072 document[ _addEventListener ](prefix + 'MozMousePixelScroll', MouseWheelHandler, passiveEvent); 23073 } 23074 23075 //handle MozMousePixelScroll in older Firefox 23076 else{ 23077 document[ _addEventListener ](prefix + support, MouseWheelHandler, passiveEvent); 23078 } 23079 } 23080 23081 /** 23082 * Binding the mousemove when the mouse's middle button is pressed 23083 */ 23084 function addMiddleWheelHandler(){ 23085 container 23086 .on('mousedown', mouseDownHandler) 23087 .on('mouseup', mouseUpHandler); 23088 } 23089 23090 /** 23091 * Unbinding the mousemove when the mouse's middle button is released 23092 */ 23093 function removeMiddleWheelHandler(){ 23094 container 23095 .off('mousedown', mouseDownHandler) 23096 .off('mouseup', mouseUpHandler); 23097 } 23098 23099 /** 23100 * Adds the possibility to auto scroll through sections on touch devices. 23101 */ 23102 function addTouchHandler(){ 23103 if(isTouchDevice || isTouch){ 23104 if(options.autoScrolling){ 23105 $body.off(events.touchmove).on(events.touchmove, preventBouncing); 23106 } 23107 23108 $(WRAPPER_SEL) 23109 .off(events.touchstart).on(events.touchstart, touchStartHandler) 23110 .off(events.touchmove).on(events.touchmove, touchMoveHandler); 23111 } 23112 } 23113 23114 /** 23115 * Removes the auto scrolling for touch devices. 23116 */ 23117 function removeTouchHandler(){ 23118 if(isTouchDevice || isTouch){ 23119 $(WRAPPER_SEL) 23120 .off(events.touchstart) 23121 .off(events.touchmove); 23122 } 23123 } 23124 23125 /* 23126 * Returns and object with Microsoft pointers (for IE<11 and for IE >= 11) 23127 * http://msdn.microsoft.com/en-us/library/ie/dn304886(v=vs.85).aspx 23128 */ 23129 function getMSPointer(){ 23130 var pointer; 23131 23132 //IE >= 11 & rest of browsers 23133 if(window.PointerEvent){ 23134 pointer = { down: 'pointerdown', move: 'pointermove'}; 23135 } 23136 23137 //IE < 11 23138 else{ 23139 pointer = { down: 'MSPointerDown', move: 'MSPointerMove'}; 23140 } 23141 23142 return pointer; 23143 } 23144 23145 /** 23146 * Gets the pageX and pageY properties depending on the browser. 23147 * https://github.com/alvarotrigo/fullPage.js/issues/194#issuecomment-34069854 23148 */ 23149 function getEventsPage(e){ 23150 var events = []; 23151 23152 events.y = (typeof e.pageY !== 'undefined' && (e.pageY || e.pageX) ? e.pageY : e.touches[0].pageY); 23153 events.x = (typeof e.pageX !== 'undefined' && (e.pageY || e.pageX) ? e.pageX : e.touches[0].pageX); 23154 23155 //in touch devices with scrollBar:true, e.pageY is detected, but we have to deal with touch events. #1008 23156 if(isTouch && isReallyTouch(e) && options.scrollBar){ 23157 events.y = e.touches[0].pageY; 23158 events.x = e.touches[0].pageX; 23159 } 23160 23161 return events; 23162 } 23163 23164 /** 23165 * Slides silently (with no animation) the active slider to the given slide. 23166 * @param noCallback {bool} true or defined -> no callbacks 23167 */ 23168 function silentLandscapeScroll(activeSlide, noCallbacks){ 23169 setScrollingSpeed (0, 'internal'); 23170 23171 if(typeof noCallbacks !== 'undefined'){ 23172 //preventing firing callbacks afterSlideLoad etc. 23173 isResizing = true; 23174 } 23175 23176 landscapeScroll(activeSlide.closest(SLIDES_WRAPPER_SEL), activeSlide); 23177 23178 if(typeof noCallbacks !== 'undefined'){ 23179 isResizing = false; 23180 } 23181 23182 setScrollingSpeed(originals.scrollingSpeed, 'internal'); 23183 } 23184 23185 /** 23186 * Scrolls silently (with no animation) the page to the given Y position. 23187 */ 23188 function silentScroll(top){ 23189 // The first section can have a negative value in iOS 10. Not quite sure why: -0.0142822265625 23190 // that's why we round it to 0. 23191 var roundedTop = Math.round(top); 23192 23193 if (options.css3 && options.autoScrolling && !options.scrollBar){ 23194 var translate3d = 'translate3d(0px, -' + roundedTop + 'px, 0px)'; 23195 transformContainer(translate3d, false); 23196 } 23197 else if(options.autoScrolling && !options.scrollBar){ 23198 container.css('top', -roundedTop); 23199 } 23200 else{ 23201 $htmlBody.scrollTop(roundedTop); 23202 } 23203 } 23204 23205 /** 23206 * Returns the cross-browser transform string. 23207 */ 23208 function getTransforms(translate3d){ 23209 return {
23210 '-webkit-transform': translate3d, 23211 '-moz-transform': translate3d, 23212 '-ms-transform':translate3d, 23213 'transform': translate3d 23214 }; 23215 } 23216 23217 /** 23218 * Allowing or disallowing the mouse/swipe scroll in a given direction. (not for keyboard) 23219 * @type m (mouse) or k (keyboard) 23220 */ 23221 function setIsScrollAllowed(value, direction, type){ 23222 switch (direction){ 23223 case 'up': isScrollAllowed[type].up = value; break; 23224 case 'down': isScrollAllowed[type].down = value; break; 23225 case 'left': isScrollAllowed[type].left = value; break; 23226 case 'right': isScrollAllowed[type].right = value; break; 23227 case 'all': 23228 if(type == 'm'){ 23229 setAllowScrolling(value); 23230 }else{ 23231 setKeyboardScrolling(value); 23232 } 23233 } 23234 } 23235 23236 /* 23237 * Destroys fullpage.js plugin events and optinally its html markup and styles 23238 */ 23239 function destroy(all){ 23240 setAutoScrolling(false, 'internal'); 23241 setAllowScrolling(false); 23242 setKeyboardScrolling(false); 23243 container.addClass(DESTROYED); 23244 23245 clearTimeout(afterSlideLoadsId); 23246 clearTimeout(afterSectionLoadsId); 23247 clearTimeout(resizeId); 23248 clearTimeout(scrollId); 23249 clearTimeout(scrollId2); 23250 23251 $window 23252 .off('scroll', scrollHandler) 23253 .off('hashchange', hashChangeHandler) 23254 .off('resize', resizeHandler); 23255 23256 $document 23257 .off('click touchstart', SECTION_NAV_SEL + ' a') 23258 .off('mouseenter', SECTION_NAV_SEL + ' li') 23259 .off('mouseleave', SECTION_NAV_SEL + ' li') 23260 .off('click touchstart', SLIDES_NAV_LINK_SEL) 23261 .off('mouseover', options.normalScrollElements) 23262 .off('mouseout', options.normalScrollElements); 23263 23264 $(SECTION_SEL) 23265 .off('click touchstart', SLIDES_ARROW_SEL); 23266 23267 clearTimeout(afterSlideLoadsId); 23268 clearTimeout(afterSectionLoadsId); 23269 23270 //lets make a mess! 23271 if(all){ 23272 destroyStructure(); 23273 } 23274 } 23275 23276 /* 23277 * Removes inline styles added by fullpage.js 23278 */ 23279 function destroyStructure(){ 23280 //reseting the `top` or `translate` properties to 0 23281 silentScroll(0); 23282 23283 //loading all the lazy load content 23284 container.find('img[data-src], source[data-src], audio[data-src], iframe[data-src]').each(function(){ 23285 setSrc($(this), 'src'); 23286 }); 23287 23288 container.find('img[data-srcset]').each(function(){ 23289 setSrc($(this), 'srcset'); 23290 }); 23291 23292 $(SECTION_NAV_SEL + ', ' + SLIDES_NAV_SEL + ', ' + SLIDES_ARROW_SEL).remove(); 23293 23294 //removing inline styles 23295 $(SECTION_SEL).css( { 23296 'height': '', 23297 'background-color' : '', 23298 'padding': '' 23299 }); 23300 23301 $(SLIDE_SEL).css( { 23302 'width': '' 23303 }); 23304 23305 container.css({ 23306 'height': '', 23307 'position': '', 23308 '-ms-touch-action': '', 23309 'touch-action': '' 23310 }); 23311 23312 $htmlBody.css({ 23313 'overflow': '', 23314 'height': '' 23315 }); 23316 23317 // remove .fp-enabled class 23318 $('html').removeClass(ENABLED); 23319 23320 // remove .fp-responsive class 23321 $body.removeClass(RESPONSIVE); 23322 23323 // remove all of the .fp-viewing- classes 23324 $.each($body.get(0).className.split(/\s+/), function (index, className) { 23325 if (className.indexOf(VIEWING_PREFIX) === 0) { 23326 $body.removeClass(className); 23327 } 23328 }); 23329 23330 //removing added classes 23331 $(SECTION_SEL + ', ' + SLIDE_SEL).each(function(){ 23332 options.scrollOverflowHandler.remove($(this)); 23333 $(this).removeClass(TABLE + ' ' + ACTIVE); 23334 }); 23335 23336 removeAnimation(container); 23337 23338 //Unwrapping content 23339 container.find(TABLE_CELL_SEL + ', ' + SLIDES_CONTAINER_SEL + ', ' + SLIDES_WRAPPER_SEL).each(function(){ 23340 //unwrap not being use in case there's no child element inside and its just text 23341 $(this).replaceWith(this.childNodes); 23342 }); 23343 23344 //removing the applied transition from the fullpage wrapper 23345 container.css({
23346 '-webkit-transition': 'none', 23347 'transition': 'none' 23348 }); 23349 23350 //scrolling the page to the top with no animation 23351 $htmlBody.scrollTop(0); 23352 23353 //removing selectors 23354 var usedSelectors = [SECTION, SLIDE, SLIDES_CONTAINER]; 23355 $.each(usedSelectors, function(index, value){ 23356 $('.' + value).removeClass(value); 23357 }); 23358 } 23359 23360 /* 23361 * Sets the state for a variable with multiple states (original, and temporal) 23362 * Some variables such as `autoScrolling` or `recordHistory` might change automatically its state when using `responsive` or `autoScrolling:false`. 23363 * This function is used to keep track of both states, the original and the temporal one. 23364 * If type is not 'internal', then we assume the user is globally changing the variable. 23365 */ 23366 function setVariableState(variable, value, type){ 23367 options[variable] = value; 23368 if(type !== 'internal'){ 23369 originals[variable] = value; 23370 } 23371 } 23372 23373 /** 23374 * Displays warnings 23375 */ 23376 function displayWarnings(){ 23377 var extensions = ['fadingEffect', 'continuousHorizontal', 'scrollHorizontally', 'interlockedSlides', 'resetSliders', 'responsiveSlides', 'offsetSections', 'dragAndMove', 'scrollOverflowReset', 'parallax']; 23378 //UNCODE.addition 23379 // if($('html').hasClass(ENABLED)){ 23380 // showError('error', 'Fullpage.js can only be initialized once and you are doing it multiple times!'); 23381 // return; 23382 // } 23383 23384 // Disable mutually exclusive settings 23385 //UNCODE.addition 23386 // if (options.continuousVertical && 23387 // (options.loopTop || options.loopBottom)) { 23388 // options.continuousVertical = false;
23389 // showError('warn', 'Option `loopTop/loopBottom` is mutually exclusive with `continuousVertical`; `continuousVertical` disabled'); 23390 // } 23391 23392 // if(options.scrollBar && options.scrollOverflow){ 23393 // showError('warn', 'Option `scrollBar` is mutually exclusive with `scrollOverflow`. Sections with scrollOverflow might not work well in Firefox'); 23394 // } 23395 23396 // if(options.continuousVertical && (options.scrollBar || !options.autoScrolling)){ 23397 // options.continuousVertical = false; 23398 // showError('warn', 'Scroll bars (`scrollBar:true` or `autoScrolling:false`) are mutually exclusive with `continuousVertical`; `continuousVertical` disabled'); 23399 // } 23400 23401 //using extensions? Wrong file! 23402 $.each(extensions, function(index, extension){ 23403 //is the option set to true? 23404 if(options[extension]){ 23405 showError('warn', 'fullpage.js extensions require jquery.fullpage.extensions.min.js file instead of the usual jquery.fullpage.js. Requested: '+ extension); 23406 } 23407 }); 23408 23409 //anchors can not have the same value as any element ID or NAME 23410 $.each(options.anchors, function(index, name){ 23411 23412 //case insensitive selectors (http://stackoverflow.com/a/19465187/1081396) 23413 var nameAttr = $document.find('[name]').filter(function() { 23414 return $(this).attr('name') && $(this).attr('name').toLowerCase() == name.toLowerCase(); 23415 }); 23416 23417 var idAttr = $document.find('[id]').filter(function() { 23418 return $(this).attr('id') && $(this).attr('id').toLowerCase() == name.toLowerCase(); 23419 }); 23420 23421 if(idAttr.length || nameAttr.length ){ 23422 showError('error', 'data-anchor tags can not have the same value as any `id` element on the site (or `name` element for IE).'); 23423 idAttr.length && showError('error', '"' + name + '" is is being used by another element `id` property'); 23424 nameAttr.length && showError('error', '"' + name + '" is is being used by another element `name` property'); 23425 } 23426 }); 23427 } 23428 23429 /** 23430 * Shows a message in the console of the given type. 23431 */ 23432 function showError(type, text){ 23433 console && console[type] && console[type]('fullPage: ' + text); 23434 } 23435 23436 }; //end of $.fn.fullpage 23437 23438 if(typeof IScroll !== 'undefined'){ 23439 /* 23440 * Turns iScroll `mousewheel` option off dynamically 23441 * https://github.com/cubiq/iscroll/issues/1036 23442 */ 23443 IScroll.prototype.wheelOn = function () { 23444 this.wrapper.addEventListener('wheel', this); 23445 this.wrapper.addEventListener('mousewheel', this); 23446 this.wrapper.addEventListener('DOMMouseScroll', this); 23447 }; 23448 23449 /* 23450 * Turns iScroll `mousewheel` option on dynamically 23451 * https://github.com/cubiq/iscroll/issues/1036 23452 */ 23453 IScroll.prototype.wheelOff = function () { 23454 this.wrapper.removeEventListener('wheel', this); 23455 this.wrapper.removeEventListener('mousewheel', this); 23456 this.wrapper.removeEventListener('DOMMouseScroll', this); 23457 }; 23458 } 23459 23460 /** 23461 * An object to handle overflow scrolling. 23462 * This uses jquery.slimScroll to accomplish overflow scrolling. 23463 * It is possible to pass in an alternate scrollOverflowHandler 23464 * to the fullpage.js option that implements the same functions 23465 * as this handler. 23466 * 23467 * @type {Object} 23468 */ 23469 var iscrollHandler = { 23470 refreshId: null, 23471 iScrollInstances: [], 23472 23473 // Enables or disables the mouse wheel for the active section or all slides in it 23474 toggleWheel: function(value){ 23475 var scrollable = $(SECTION_ACTIVE_SEL).find(SCROLLABLE_SEL); 23476 scrollable.each(function(){ 23477 var iScrollInstance = $(this).data('iscrollInstance'); 23478 if(typeof iScrollInstance !== 'undefined' && iScrollInstance){ 23479 if(value){ 23480 iScrollInstance.wheelOn(); 23481 } 23482 else{ 23483 iScrollInstance.wheelOff(); 23484 } 23485 } 23486 }); 23487 }, 23488 23489 /** 23490 * Turns off iScroll for the destination section. 23491 * When scrolling very fast on some trackpads (and Apple laptops) the inertial scrolling would
23492 * scroll the destination section/slide before the sections animations ends. 23493 */ 23494 onLeave: function(){ 23495 iscrollHandler.toggleWheel(false); 23496 }, 23497 23498 // Turns off iScroll for the leaving section 23499 beforeLeave: function(){ 23500 iscrollHandler.onLeave() 23501 }, 23502 23503 // Turns on iScroll on section load 23504 afterLoad: function(){ 23505 iscrollHandler.toggleWheel(true); 23506 }, 23507 23508 /** 23509 * Called when overflow scrolling is needed for a section. 23510 * 23511 * @param {Object} element jQuery object containing current section 23512 * @param {Number} scrollHeight Current window height in pixels 23513 */ 23514 create: function(element, scrollHeight) { 23515 var scrollable = element.find(SCROLLABLE_SEL); 23516 23517 scrollable.height(scrollHeight); 23518 scrollable.each(function() { 23519 var $this = $(this); 23520 var iScrollInstance = $this.data('iscrollInstance'); 23521 if (iScrollInstance) { 23522 $.each(iscrollHandler.iScrollInstances, function(){ 23523 $(this).destroy(); 23524 }); 23525 } 23526 23527 iScrollInstance = new IScroll($this.get(0), iscrollOptions); 23528 iscrollHandler.iScrollInstances.push(iScrollInstance); 23529 23530 //off by default until the section gets active 23531 iScrollInstance.wheelOff(); 23532 23533 $this.data('iscrollInstance', iScrollInstance); 23534 }); 23535 }, 23536 23537 /** 23538 * Return a boolean depending on whether the scrollable element is a 23539 * the end or at the start of the scrolling depending on the given type. 23540 * 23541 * @param {String} type Either 'top' or 'bottom' 23542 * @param {Object} scrollable jQuery object for the scrollable element 23543 * @return {Boolean} 23544 */ 23545 isScrolled: function(type, scrollable) { 23546 var scroller = scrollable.data('iscrollInstance'); 23547 23548 //no scroller? 23549 if (!scroller) { 23550 return true; 23551 } 23552 23553 if (type === 'top') { 23554 return scroller.y >= 0 && !scrollable.scrollTop(); 23555 } else if (type === 'bottom') { 23556 return (0 - scroller.y) + scrollable.scrollTop() + 1 + scrollable.innerHeight() >= scrollable[0].scrollHeight; 23557 } 23558 }, 23559 23560 /** 23561 * Returns the scrollable element for the given section. 23562 * If there are landscape slides, will only return a scrollable element 23563 * if it is in the active slide. 23564 * 23565 * @param {Object} activeSection jQuery object containing current section 23566 * @return {Boolean} 23567 */ 23568 scrollable: function(activeSection){ 23569 // if there are landscape slides, we check if the scrolling bar is in the current one or not 23570 if (activeSection.find(SLIDES_WRAPPER_SEL).length) { 23571 return activeSection.find(SLIDE_ACTIVE_SEL).find(SCROLLABLE_SEL); 23572 } 23573 return activeSection.find(SCROLLABLE_SEL); 23574 }, 23575 23576 /** 23577 * Returns the scroll height of the wrapped content. 23578 * If this is larger than the window height minus section padding, 23579 * overflow scrolling is needed. 23580 * 23581 * @param {Object} element jQuery object containing current section 23582 * @return {Number} 23583 */ 23584 scrollHeight: function(element) { 23585 return element.find(SCROLLABLE_SEL).children().first().get(0).scrollHeight; 23586 }, 23587 23588 /** 23589 * Called when overflow scrolling is no longer needed for a section. 23590 * 23591 * @param {Object} element jQuery object containing current section 23592 */ 23593 remove: function(element) { 23594 var scrollable = element.find(SCROLLABLE_SEL); 23595 if (scrollable.length) { 23596 var iScrollInstance = scrollable.data('iscrollInstance'); 23597 iScrollInstance.destroy(); 23598 23599 scrollable.data('iscrollInstance', null); 23600 } 23601 element.find(SCROLLABLE_SEL).children().first().children().first().unwrap().unwrap(); 23602 }, 23603 23604 /** 23605 * Called when overflow scrolling has already been setup but the 23606 * window height has potentially changed. 23607 * 23608 * @param {Object}
23608 element jQuery object containing current section 23609 * @param {Number} scrollHeight Current window height in pixels 23610 */ 23611 update: function(element, scrollHeight) { 23612 //using a timeout in order to execute the refresh function only once when `update` is called multiple times in a 23613 //short period of time. 23614 //it also comes on handy because iScroll requires the use of timeout when using `refresh`. 23615 clearTimeout(iscrollHandler.refreshId); 23616 iscrollHandler.refreshId = setTimeout(function(){ 23617 $.each(iscrollHandler.iScrollInstances, function(){ 23618 $(this).get(0).refresh(); 23619 }); 23620 }, 150); 23621 23622 //updating the wrappers height 23623 element.find(SCROLLABLE_SEL).css('height', scrollHeight + 'px').parent().css('height', scrollHeight + 'px'); 23624 }, 23625 23626 /** 23627 * Called to get any additional elements needed to wrap the section 23628 * content in order to facilitate overflow scrolling. 23629 * 23630 * @return {String|Object} Can be a string containing HTML, 23631 * a DOM element, or jQuery object. 23632 */ 23633 wrapContent: function() { 23634 return '<div class="' + SCROLLABLE + '"><div class="fp-scroller"></div></div>'; 23635 } 23636 }; 23637}); 23638 23639/* ======================================================================== 23640 * Bootstrap: collapse.js v3.1.1 23641 * http://getbootstrap.com/javascript/#collapse 23642 * ======================================================================== 23643 * Copyright 2011-2014 Twitter, Inc. 23644 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 23645 * ======================================================================== */ 23646 23647 23648+function ($) { 23649 'use strict'; 23650 23651 // COLLAPSE PUBLIC CLASS DEFINITION 23652 // ================================ 23653 23654 var Collapse = function (element, options) { 23655 this.$element = $(element) 23656 this.options = $.extend({}, Collapse.DEFAULTS, options) 23657 this.transitioning = null 23658 23659 if (this.options.parent) this.$parent = $(this.options.parent) 23660 if (this.options.toggle) this.toggle() 23661 } 23662 23663 Collapse.DEFAULTS = { 23664 toggle: true 23665 } 23666 23667 Collapse.prototype.dimension = function () { 23668 var hasWidth = this.$element.hasClass('width') 23669 return hasWidth ? 'width' : 'height' 23670 } 23671 23672 Collapse.prototype.show = function () { 23673 if (this.transitioning || this.$element.hasClass('in')) return 23674 23675 var startEvent = $.Event('show.bs.collapse') 23676 this.$element.trigger(startEvent) 23677 if (startEvent.isDefaultPrevented()) return 23678 23679 var actives = this.$parent && this.$parent.find('> .panel > .in') 23680 23681 if (actives && actives.length) { 23682 var hasData = actives.data('bs.collapse') 23683 if (hasData && hasData.transitioning) return 23684 actives.collapse('hide') 23685 hasData || actives.data('bs.collapse', null) 23686 } 23687 23688 var dimension = this.dimension() 23689 23690 this.$element 23691 .removeClass('collapse') 23692 .addClass('collapsing')[dimension](0) 23693 23694 this.transitioning = 1 23695 23696 var complete = function (e) { 23697 if (e && e.target != this.$element[0]) return 23698 this.$element 23699 .removeClass('collapsing') 23700 .addClass('collapse in')[dimension]('auto') 23701 this.transitioning = 0 23702 this.$element.trigger('shown.bs.collapse') 23703 } 23704 23705 if (!$.support.transition) return complete.call(this) 23706 23707 var scrollSize = $.camelCase(['scroll', dimension].join('-')) 23708 23709 this.$element 23710 .one($.support.transition.end, $.proxy(complete, this)) 23711 .emulateTransitionEnd(350)[dimension](this.$element[0][scrollSize]) 23712 } 23713 23714 Collapse.prototype.hide = function () { 23715 if (this.transitioning || !this.$element.hasClass('in')) return 23716 23717 var startEvent = $.Event('hide.bs.collapse') 23718 this.$element.trigger(startEvent) 23719 if (startEvent.isDefaultPrevented()) return 23720 23721 var dimension = this.dimension() 23722 23723 this.$element[dimension](this.$element[dimension]())[0].offsetHeight 23724 23725 this.$element 23726 .addClass('collapsing') 23727 .removeClass('collapse') 23728 .removeClass('in') 23729 23730 this.transitioning = 1 23731 23732 var complete = function (e) { 23733 if (e && e.target != this.$element[0]) return 23734 this.transitioning = 0 23735 this.$element 23736 .trigger('hidden.bs.collapse') 23737 .removeClass('collapsing') 23738 .addClass('collapse') 23739 } 23740 23741 if (!$.support.transition) return complete.call(this) 23742 23743 this.$element 23744 [dimension](0) 23745 .one($.support.transition.end, $.proxy(complete, this)) 23746 .emulateTransitionEnd(350) 23747 } 23748 23749 Collapse.prototype.toggle = function () { 23750 this[this.$element.hasClass('in') ? 'hide' : 'show']() 23751 } 23752 23753 23754 // COLLAPSE PLUGIN DEFINITION 23755 // ========================== 23756 23757 var old = $.fn.collapse 23758 23759 $.fn.collapse = function (option) { 23760 return this.each(function () { 23761 var $this = $(this) 23762 var data = $this.data('bs.collapse') 23763 var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) 23764 23765 if (!data && options.toggle && option == 'show') option = !option 23766 if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) 23767 if (typeof option == 'string') data[option]() 23768 }) 23769 } 23770 23771 $.fn.collapse.Constructor = Collapse 23772 23773 23774 // COLLAPSE NO CONFLICT 23775 // ==================== 23776 23777 $.fn.collapse.noConflict = function () { 23778 $.fn.collapse = old 23779 return this 23780 } 23781 23782 23783 // COLLAPSE DATA-API 23784 // ================= 23785 23786 $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) { 23787 var $this = $(this), href 23788 var target = $this.attr('data-target') 23789 || e.preventDefault() 23790 || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 23791 //Edited by Uncode to replace ID in panel [START] 23792 var _target = href.replace(/^#/, ""); 23793 if ( $('[data-id="' + _target + '"]').length ) { 23794 var $target = $('[data-id="' + _target + '"]') 23795 } else { 23796 var $target = $(target) 23797 } 23798 //Edited by Uncode to replace ID in panel [END] 23799 var data = $target.data('bs.collapse') 23800 var option = data ? 'toggle' : $this.data() 23801 var parent = $this.attr('data-parent') 23802 var $parent = parent && $(parent) 23803 23804 if (!data || !data.transitioning) { 23805 if ($parent) $parent.find('[data-toggle="collapse"][data-parent="' + parent + '"]').not($this).addClass('collapsed') 23806 $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed') 23807 } 23808 23809 $target.collapse(option) 23810 }) 23811 23812}(jQuery); 23813 23814/* ======================================================================== 23815 * Bootstrap: tab.js v3.1.1 23816 * http://getbootstrap.com/javascript/#tabs 23817 * ======================================================================== 23818 * Copyright 2011-2014 Twitter, Inc. 23819 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 23820 * ======================================================================== */ 23821 23822 23823+function ($) { 23824 'use strict'; 23825 23826 // TAB CLASS DEFINITION 23827 // ==================== 23828 23829 var Tab = function (element) { 23830 this.element = $(element) 23831 } 23832 23833 Tab.prototype.show = function () { 23834 var $this = this.element 23835 var $ul = $this.closest('ul:not(.dropdown-menu)') 23836 var selector = $this.data('target') 23837 23838 if (!selector) { 23839 selector = $this.attr('href') 23840 selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 23841 } 23842 23843 if ($this.parent('li').hasClass('active')) return 23844 23845 var previous = $ul.find('.active:last a')[0] 23846 var e = $.Event('show.bs.tab', { 23847 relatedTarget: previous 23848 }) 23849 23850 $this.trigger(e) 23851 23852 if (e.isDefaultPrevented()) return 23853 23854 //Edited by Uncode to replace ID in panel [START] 23855 var _target = selector.replace(/^#/, ""); 23856 if ( $('[data-id="' + _target + '"]').length ) 23857 var $target = $('[data-id="' + _target + '"]') 23858 else 23859 var $target = $(selector) 23860 //Edited by Uncode to replace ID in panel [END] 23861 23862 this.activate($this.parent('li'), $ul) 23863 this.activate($target, $target.parent(), function () { 23864 $this.trigger({ 23865 type: 'shown.bs.tab', 23866 relatedTarget: previous 23867 }) 23868 }) 23869 } 23870 23871 Tab.prototype.activate = function (element, container, callback) { 23872 var $active = container.find('> .active') 23873 var transition = callback 23874 && $.support.transition 23875 && $active.hasClass('fade') 23876 23877 function next() { 23878 $active 23879 .removeClass('active') 23880 .find('> .dropdown-menu > .active') 23881 .removeClass('active') 23882 23883 element.addClass('active') 23884 23885 if (transition) { 23886 element[0].offsetWidth // reflow for transition 23887 element.addClass('in') 23888 } else { 23889 element.removeClass('fade') 23890 } 23891 23892 if (element.parent('.dropdown-menu')) { 23893 element.closest('li.dropdown').addClass('active') 23894 } 23895 23896 callback && callback() 23897 } 23898 23899 transition ? 23900 $active 23901 .one($.support.transition.end, next) 23902 .emulateTransitionEnd(150) : 23903 next() 23904 23905 $active.removeClass('in') 23906 } 23907 23908 23909 // TAB PLUGIN DEFINITION 23910 // ===================== 23911 23912 var old = $.fn.tab 23913 23914 $.fn.tab = function ( option ) { 23915 return this.each(function () { 23916 var $this = $(this) 23917 var data = $this.data('bs.tab') 23918 23919 if (!data) $this.data('bs.tab', (data = new Tab(this))) 23920 if (typeof option == 'string') data[option]() 23921 }) 23922 } 23923 23924 $.fn.tab.Constructor = Tab 23925 23926 23927 // TAB NO CONFLICT 23928 // =============== 23929 23930 $.fn.tab.noConflict = function () { 23931 $.fn.tab = old 23932 return this 23933 } 23934 23935 23936 // TAB DATA-API 23937 // ============ 23938 23939 $(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) { 23940 e.preventDefault() 23941 $(this).tab('show') 23942 }) 23943 23944}(jQuery); 23945 23946/* ======================================================================== 23947 * Bootstrap: tooltip.js v3.1.1 23948 * http://getbootstrap.com/javascript/#tooltip 23949 * Inspired by the original jQuery.tipsy by Jason Frame 23950 * ======================================================================== 23951 * Copyright 2011-2014 Twitter, Inc. 23952 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 23953 * ======================================================================== */ 23954 23955 23956+function ($) { 23957 'use strict'; 23958 23959 // TOOLTIP PUBLIC CLASS DEFINITION 23960 // =============================== 23961 23962 var Tooltip = function (element, options) { 23963 this.type = 23964 this.options = 23965 this.enabled = 23966 this.timeout = 23967 this.hoverState = 23968 this.$element = null 23969 23970 this.init('tooltip', element, options) 23971 } 23972 23973 Tooltip.DEFAULTS = { 23974 animation: true, 23975 placement: 'top', 23976 selector: false, 23977 template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>', 23978 trigger: 'hover focus', 23979 title: '', 23980 delay: 0, 23981 html: false, 23982 container: false, 23983 viewport: { 23984 selector: 'body', 23985 padding: 0 23986 } 23987 } 23988 23989 Tooltip.prototype.init = function (type, element, options) { 23990 this.enabled = true 23991 this.type = type 23992 this.$element = $(element) 23993 this.options = this.getOptions(options) 23994 this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport) 23995 23996 var triggers = this.options.trigger.split(' ') 23997 23998 for (var i = triggers.length; i--;) { 23999 var trigger = triggers[i] 24000 24001 if (trigger == 'click') { 24002 this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this)) 24003 } else if (trigger != 'manual') { 24004 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin' 24005 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout' 24006 24007 this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this)) 24008 this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this)) 24009 } 24010 } 24011 24012 this.options.selector ? 24013 (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) : 24014 this.fixTitle() 24015 } 24016 24017 Tooltip.prototype.getDefaults = function () { 24018 return Tooltip.DEFAULTS 24019 } 24020 24021 Tooltip.prototype.getOptions = function (options) { 24022 options = $.extend({}, this.getDefaults(), this.$element.data(), options) 24023 24024 if (options.delay && typeof options.delay == 'number') { 24025 options.delay = { 24026 show: options.delay, 24027 hide: options.delay 24028 } 24029 } 24030 24031 return options 24032 } 24033 24034 Tooltip.prototype.getDelegateOptions = function () { 24035 var options = {} 24036 var defaults = this.getDefaults() 24037 24038 this._options && $.each(this._options, function (key, value) { 24039 if (defaults[key] != value) options[key] = value 24040 }) 24041 24042 return options 24043 } 24044 24045 Tooltip.prototype.enter = function (obj) { 24046 var self = obj instanceof this.constructor ? 24047 obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) 24048 24049 clearTimeout(self.timeout) 24050 24051 self.hoverState = 'in' 24052 24053 if (!self.options.delay || !self.options.delay.show) return self.show() 24054 24055 self.timeout = setTimeout(function () { 24056 if (self.hoverState == 'in') self.show() 24057 }, self.options.delay.show) 24058 } 24059 24060 Tooltip.prototype.leave = function (obj) { 24061 var self = obj instanceof this.constructor ? 24062 obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) 24063 24064 clearTimeout(self.timeout) 24065 24066 self.hoverState = 'out' 24067 24068 if (!self.options.delay || !self.options.delay.hide) return self.hide() 24069 24070 self.timeout = setTimeout(function () { 24071 if (self.hoverState == 'out') self.hide() 24072 }, self.options.delay.hide) 24073 } 24074 24075 Tooltip.prototype.show = function () { 24076 var e = $.Event('show.bs.' + this.type) 24077 24078 if (this.hasContent() && this.enabled) { 24079 this.$element.trigger(e) 24080 24081 if (e.isDefaultPrevented()) return 24082 var that = this; 24083 24084 var $tip = this.tip() 24085 24086 this.setContent() 24087 24088 if (this.options.animation) $tip.addClass('fade') 24089 24090 var placement = typeof this.options.placement == 'function' ? 24091 this.options.placement.call(this, $tip[0], this.$element[0]) : 24092 this.options.placement 24093 24094 var autoToken = /\s?auto?\s?/i 24095 var autoPlace = autoToken.test(placement) 24096 if (autoPlace) placement = placement.replace(autoToken, '') || 'top' 24097 24098 $tip 24099 .detach() 24100 .css({ top: 0, left: 0, display: 'block' }) 24101 .addClass(placement) 24102 24103 this.options.container ? $tip.appendTo($(document).find(this.options.container)) : $tip.insertAfter(this.$element) 24104 24105 var pos = this.getPosition() 24106 var actualWidth = $tip[0].offsetWidth 24107 var actualHeight = $tip[0].offsetHeight 24108 24109 if (autoPlace) { 24110 var orgPlacement = placement 24111 var $parent = this.$element.parent() 24112 var parentDim = this.getPosition($parent) 24113 24114 placement = placement == 'bottom' && pos.top + pos.height + actualHeight - parentDim.scroll > parentDim.height ? 'top' : 24115 placement == 'top' && pos.top - parentDim.scroll - actualHeight < 0 ? 'bottom' : 24116 placement == 'right' && pos.right + actualWidth > parentDim.width ? 'left' : 24117 placement == 'left' && pos.left - actualWidth < parentDim.left ? 'right' : 24118 placement 24119 24120 $tip 24121 .removeClass(orgPlacement) 24122 .addClass(placement) 24123 } 24124 24125 var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight) 24126 24127 this.applyPlacement(calculatedOffset, placement) 24128 this.hoverState = null 24129 24130 var complete = function() { 24131 that.$element.trigger('shown.bs.' + that.type) 24132 } 24133 24134 $.support.transition && this.$tip.hasClass('fade') ? 24135 $tip 24136 .one($.support.transition.end, complete) 24137 .emulateTransitionEnd(150) : 24138 complete() 24139 } 24140 } 24141 24142 Tooltip.prototype.applyPlacement = function (offset, placement) { 24143 var $tip = this.tip() 24144 var width = $tip[0].offsetWidth 24145 var height = $tip[0].offsetHeight 24146 24147 // manually read margins because getBoundingClientRect includes difference 24148 var marginTop = parseInt($tip.css('margin-top'), 10) 24149 var marginLeft = parseInt($tip.css('margin-left'), 10) 24150 24151 // we must check
24151 for NaN for ie 8/9 24152 if (isNaN(marginTop)) marginTop = 0 24153 if (isNaN(marginLeft)) marginLeft = 0 24154 24155 offset.top = offset.top + marginTop 24156 offset.left = offset.left + marginLeft 24157 24158 // $.fn.offset doesn't round pixel values 24159 // so we use setOffset directly with our own function B-0 24160 $.offset.setOffset($tip[0], $.extend({ 24161 using: function (props) { 24162 $tip.css({ 24163 top: Math.round(props.top), 24164 left: Math.round(props.left) 24165 }) 24166 } 24167 }, offset), 0) 24168 24169 $tip.addClass('in') 24170 24171 // check to see if placing tip in new offset caused the tip to resize itself 24172 var actualWidth = $tip[0].offsetWidth 24173 var actualHeight = $tip[0].offsetHeight 24174 24175 if (placement == 'top' && actualHeight != height) { 24176 offset.top = offset.top + height - actualHeight 24177 } 24178 24179 var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight) 24180 24181 if (delta.left) offset.left += delta.left 24182 else offset.top += delta.top 24183 24184 var arrowDelta = delta.left ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight 24185 var arrowPosition = delta.left ? 'left' : 'top' 24186 var arrowOffsetPosition = delta.left ? 'offsetWidth' : 'offsetHeight' 24187 24188 $tip.offset(offset) 24189 this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], arrowPosition) 24190 } 24191 24192 Tooltip.prototype.replaceArrow = function (delta, dimension, position) { 24193 this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + '%') : '') 24194 } 24195 24196 Tooltip.prototype.setContent = function () { 24197 var $tip = this.tip() 24198 var title = this.getTitle() 24199 24200 $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title) 24201 $tip.removeClass('fade in top bottom left right') 24202 } 24203 24204 Tooltip.prototype.hide = function () { 24205 var that = this 24206 var $tip = this.tip() 24207 var e = $.Event('hide.bs.' + this.type) 24208 24209 function complete() { 24210 if (that.hoverState != 'in') $tip.detach() 24211 that.$element.trigger('hidden.bs.' + that.type) 24212 } 24213 24214 this.$element.trigger(e) 24215 24216 if (e.isDefaultPrevented()) return 24217 24218 $tip.removeClass('in') 24219 24220 $.support.transition && this.$tip.hasClass('fade') ? 24221 $tip 24222 .one($.support.transition.end, complete) 24223 .emulateTransitionEnd(150) : 24224 complete() 24225 24226 this.hoverState = null 24227 24228 return this 24229 } 24230 24231 Tooltip.prototype.fixTitle = function () { 24232 var $e = this.$element 24233 if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') { 24234 $e.attr('data-original-title', $e.attr('title') || '').attr('title', '') 24235 } 24236 } 24237 24238 Tooltip.prototype.hasContent = function () { 24239 return this.getTitle() 24240 } 24241 24242 Tooltip.prototype.getPosition = function ($element) { 24243 $element = $element || this.$element 24244 var el = $element[0] 24245 var isBody = el.tagName == 'BODY' 24246 return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : null, { 24247 scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop(), 24248 width: isBody ? $(window).width() : $element.outerWidth(), 24249 height: isBody ? $(window).height() : $element.outerHeight() 24250 }, isBody ? {top: 0, left: 0} : $element.offset()) 24251 } 24252 24253 Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) { 24254 return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } : 24255 placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } : 24256 placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } : 24257 /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width } 24258 24259 } 24260 24261 Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) { 24262 var delta = { top: 0, left: 0 } 24263 if (!this.$viewport) return delta 24264 24265 var viewportPadding = this.options.viewport && this.options.viewport.padding || 0 24266 var viewportDimensions = this.getPosition(this.$viewport) 24267 24268 if (/right|left/.test(placement)) { 24269 var topEdgeOffset = pos.top - viewportPadding - viewportDimensions.scroll 24270 var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight 24271 if (topEdgeOffset < viewportDimensions.top) { // top overflow 24272 delta.top = viewportDimensions.top - topEdgeOffset 24273 } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow 24274 delta.top = viewportDimensions.top + viewportDimensions.height - bottom
24274EdgeOffset 24275 } 24276 } else { 24277 var leftEdgeOffset = pos.left - viewportPadding 24278 var rightEdgeOffset = pos.left + viewportPadding + actualWidth 24279 if (leftEdgeOffset < viewportDimensions.left) { // left overflow 24280 delta.left = viewportDimensions.left - leftEdgeOffset 24281 } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow 24282 delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset 24283 } 24284 } 24285 24286 return delta 24287 } 24288 24289 Tooltip.prototype.getTitle = function () { 24290 var title 24291 var $e = this.$element 24292 var o = this.options 24293 24294 title = $e.attr('data-original-title') 24295 || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title) 24296 24297 return title 24298 } 24299 24300 Tooltip.prototype.tip = function () { 24301 return this.$tip = this.$tip || $(this.options.template) 24302 } 24303 24304 Tooltip.prototype.arrow = function () { 24305 return this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow') 24306 } 24307 24308 Tooltip.prototype.validate = function () { 24309 if (!this.$element[0].parentNode) { 24310 this.hide() 24311 this.$element = null 24312 this.options = null 24313 } 24314 } 24315 24316 Tooltip.prototype.enable = function () { 24317 this.enabled = true 24318 } 24319 24320 Tooltip.prototype.disable = function () { 24321 this.enabled = false 24322 } 24323 24324 Tooltip.prototype.toggleEnabled = function () { 24325 this.enabled = !this.enabled 24326 } 24327 24328 Tooltip.prototype.toggle = function (e) { 24329 var self = e ? $(e.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) : this 24330 self.tip().hasClass('in') ? self.leave(self) : self.enter(self) 24331 } 24332 24333 Tooltip.prototype.destroy = function () { 24334 clearTimeout(this.timeout) 24335 this.hide().$element.off('.' + this.type).removeData('bs.' + this.type) 24336 } 24337 24338 24339 // TOOLTIP PLUGIN DEFINITION 24340 // ========================= 24341 24342 var old = $.fn.tooltip 24343 24344 $.fn.tooltip = function (option) { 24345 return this.each(function () { 24346 var $this = $(this) 24347 var data = $this.data('bs.tooltip') 24348 var options = typeof option == 'object' && option 24349 24350 if (!data && option == 'destroy') return 24351 if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options))) 24352 if (typeof option == 'string') data[option]() 24353 }) 24354 } 24355 24356 $.fn.tooltip.Constructor = Tooltip 24357 24358 24359 // TOOLTIP NO CONFLICT 24360 // =================== 24361 24362 $.fn.tooltip.noConflict = function () { 24363 $.fn.tooltip = old 24364 return this 24365 } 24366 24367}(jQuery); 24368 24369/* ======================================================================== 24370 * Bootstrap: transition.js v3.1.1 24371 * http://getbootstrap.com/javascript/#transitions 24372 * ======================================================================== 24373 * Copyright 2011-2014 Twitter, Inc. 24374 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 24375 * ======================================================================== */ 24376 24377 24378+function ($) { 24379 'use strict'; 24380 24381 // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) 24382 // ============================================================ 24383 24384 function transitionEnd() { 24385 var el = document.createElement('bootstrap') 24386 24387 var transEndEventNames = { 24388 WebkitTransition : 'webkitTransitionEnd', 24389 MozTransition : 'transitionend', 24390 OTransition : 'oTransitionEnd otransitionend', 24391 transition : 'transitionend' 24392 } 24393 24394 for (var name in transEndEventNames) { 24395 if (el.style[name] !== undefined) { 24396 return { end: transEndEventNames[name] } 24397 } 24398 } 24399 24400 return false // explicit for ie8 ( ._.) 24401 } 24402 24403 // http://blog.alexmaccaw.com/css-transitions 24404 $.fn.emulateTransitionEnd = function (duration) { 24405 var called = false, $el = this 24406 $(this).one($.support.transition.end, function () { called = true }) 24407 var callback = function () { if (!called) $($el).trigger($.support.transition.end) } 24408 setTimeout(callback, duration) 24409 return this 24410 } 24411 24412 $(function () { 24413 $.support.transition = transitionEnd() 24414 }) 24415 24416}(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.