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); 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
vendor: 15,902 bytes, lines 298-948
298 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: 23,480 bytes, lines 951-1863
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() {
vendor: 13,499 bytes, lines 1864-2432
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
vendor: 38,285 bytes, lines 2433-3856
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
vendor: 29,252 bytes, lines 3857-5013
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 spaces 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.4.1 - http://gsgd.co.uk/sandbox/jquery/easing/ 7882 * Open source under the BSD License. 7883 * Copyright © 2008 George McGinley Smith 7884 * All rights reserved. 7885 * https://raw.github.com/gdsmith/jquery.easing/master/LICENSE 7886*/ 7887 7888/* globals jQuery, define, module, require */ 7889(function (factory) { 7890 if (typeof define === "function" && define.amd) { 7891 define(['jquery'], function ($) { 7892 return factory($); 7893 }); 7894 } else if (typeof module === "object" && typeof module.exports === "object") { 7895 module.exports = factory(require('jquery')); 7896 } else { 7897 factory(jQuery); 7898 } 7899})(function($){ 7900 7901 // Preserve the original jQuery "swing" easing as "jswing" 7902 if (typeof $.easing !== 'undefined') { 7903 $.easing['jswing'] = $.easing['swing']; 7904 } 7905 7906 var pow = Math.pow, 7907 sqrt = Math.sqrt, 7908 sin = Math.sin, 7909 cos = Math.cos, 7910 PI = Math.PI,
7911 c1 = 1.70158, 7912 c2 = c1 * 1.525, 7913 c3 = c1 + 1, 7914 c4 = ( 2 * PI ) / 3, 7915 c5 = ( 2 * PI ) / 4.5; 7916 7917 // x is the fraction of animation progress, in the range 0..1 7918 function bounceOut(x) { 7919 var n1 = 7.5625, 7920 d1 = 2.75; 7921 if ( x < 1/d1 ) { 7922 return n1*x*x; 7923 } else if ( x < 2/d1 ) { 7924 return n1*(x-=(1.5/d1))*x + .75; 7925 } else if ( x < 2.5/d1 ) { 7926 return n1*(x-=(2.25/d1))*x + .9375; 7927 } else { 7928 return n1*(x-=(2.625/d1))*x + .984375; 7929 } 7930 } 7931 7932 $.extend( $.easing, { 7933 def: 'easeOutQuad', 7934 swing: function (x) { 7935 return $.easing[$.easing.def](x); 7936 }, 7937 easeInQuad: function (x) { 7938 return x * x; 7939 }, 7940 easeOutQuad: function (x) { 7941 return 1 - ( 1 - x ) * ( 1 - x ); 7942 }, 7943 easeInOutQuad: function (x) { 7944 return x < 0.5 ? 7945 2 * x * x : 7946 1 - pow( -2 * x + 2, 2 ) / 2; 7947 }, 7948 easeInCubic: function (x) { 7949 return x * x * x; 7950 }, 7951 easeOutCubic: function (x) { 7952 return 1 - pow( 1 - x, 3 ); 7953 }, 7954 easeInOutCubic: function (x) { 7955 return x < 0.5 ? 7956 4 * x * x * x : 7957 1 - pow( -2 * x + 2, 3 ) / 2; 7958 }, 7959 easeInQuart: function (x) { 7960 return x * x * x * x; 7961 }, 7962 easeOutQuart: function (x) { 7963 return 1 - pow( 1 - x, 4 ); 7964 }, 7965 easeInOutQuart: function (x) { 7966 return x < 0.5 ? 7967 8 * x * x * x * x : 7968 1 - pow( -2 * x + 2, 4 ) / 2; 7969 }, 7970 easeInQuint: function (x) { 7971 return x * x * x * x * x; 7972 }, 7973 easeOutQuint: function (x) { 7974 return 1 - pow( 1 - x, 5 ); 7975 }, 7976 easeInOutQuint: function (x) { 7977 return x < 0.5 ? 7978 16 * x * x * x * x * x : 7979 1 - pow( -2 * x + 2, 5 ) / 2; 7980 }, 7981 easeInSine: function (x) { 7982 return 1 - cos( x * PI/2 ); 7983 }, 7984 easeOutSine: function (x) { 7985 return sin( x * PI/2 ); 7986 }, 7987 easeInOutSine: function (x) { 7988 return -( cos( PI * x ) - 1 ) / 2; 7989 }, 7990 easeInExpo: function (x) { 7991 return x === 0 ? 0 : pow( 2, 10 * x - 10 ); 7992 }, 7993 easeOutExpo: function (x) { 7994 return x === 1 ? 1 : 1 - pow( 2, -10 * x ); 7995 }, 7996 easeInOutExpo: function (x) { 7997 return x === 0 ? 0 : x === 1 ? 1 : x < 0.5 ? 7998 pow( 2, 20 * x - 10 ) / 2 : 7999 ( 2 - pow( 2, -20 * x + 10 ) ) / 2; 8000 }, 8001 easeInCirc: function (x) { 8002 return 1 - sqrt( 1 - pow( x, 2 ) ); 8003 }, 8004 easeOutCirc: function (x) { 8005 return sqrt( 1 - pow( x - 1, 2 ) ); 8006 }, 8007 easeInOutCirc: function (x) { 8008 return x < 0.5 ? 8009 ( 1 - sqrt( 1 - pow( 2 * x, 2 ) ) ) / 2 : 8010 ( sqrt( 1 - pow( -2 * x + 2, 2 ) ) + 1 ) / 2; 8011 }, 8012 easeInElastic: function (x) { 8013 return x === 0 ? 0 : x === 1 ? 1 : 8014 -pow( 2, 10 * x - 10 ) * sin( ( x * 10 - 10.75 ) * c4 ); 8015 }, 8016 easeOutElastic: function (x) { 8017 return x === 0 ? 0 : x === 1 ? 1 : 8018 pow( 2, -10 * x ) * sin( ( x * 10 - 0.75 ) * c4 ) + 1; 8019 }, 8020 easeInOutElastic: function (x) { 8021 return x === 0 ? 0 : x === 1 ? 1 : x < 0.5 ? 8022 -( pow( 2, 20 * x - 10 ) * sin( ( 20 * x - 11.125 ) * c5 )) / 2 : 8023 pow( 2, -20 * x + 10 ) * sin( ( 20 * x - 11.125 ) * c5 ) / 2 + 1; 8024 }, 8025 easeInBack: function (x) { 8026 return c3 * x * x * x - c1 * x * x; 8027 }, 8028 easeOutBack: function (x) { 8029 return 1 + c3 * pow( x - 1, 3 ) + c1 * pow( x - 1, 2 ); 8030 }, 8031 easeInOutBack: function (x) { 8032 return x < 0.5 ? 8033 ( pow( 2 * x, 2 ) * ( ( c2 + 1 ) * 2 * x - c2 ) ) / 2 : 8034 ( pow( 2 * x - 2, 2 ) *( ( c2 + 1 ) * ( x * 2 - 2 ) + c2 ) + 2 ) / 2; 8035 }, 8036 easeInBounce: function (x) { 8037 return 1 - bounceOut( 1 - x ); 8038 }, 8039 easeOutBounce: bounceOut, 8040 easeInOutBounce: function (x) { 8041 return x < 0.5 ? 8042 ( 1 - bounceOut( 1 - 2 * x ) ) / 2 : 8043 ( 1 + bounceOut( 2 * x - 1 ) ) / 2; 8044 } 8045 }); 8046 return $; 8047}); 8048 8049(function($, window, undefined) { 8050 // http://paulirish.com/2011/requestanimationframe-for-smart-animating/ 8051 // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating 8052 8053 // requestAnimationFrame polyfill by Erik Möller 8054 // fixes from Paul Irish and Tino Zijdel 8055 8056 var lastTime = 0, 8057 running, 8058 animate = function (elem) { 8059 if (running) { 8060 window.requestAnimationFrame(animate, elem); 8061 jQuery.fx.tick(); 8062 } 8063 }, 8064 vendors = ['ms', 'moz', 'webkit', 'o']; 8065 8066 for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { 8067 window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame']; 8068 window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] 8069 || window[vendors[x]+'CancelRequestAnimationFrame']; 8070 } 8071 8072 if (!window.requestAnimationFrame) 8073 window.requestAnimationFrame = function(fn, element) { 8074 var currTime = new Date().getTime(), 8075 delta = currTime - lastTime, 8076 timeToCall = Math.max(0, 16 - delta); 8077 8078 var id = window.setTimeout(function() { 8079 fn(currTime + timeToCall); 8080 }, 8081 timeToCall 8082 ); 8083 8084 lastTime = currTime + timeToCall; 8085 8086 return id; 8087 }; 8088 8089 if (!window.cancelAnimationFrame) { 8090 window.cancelAnimationFrame = function(id) { 8091 clearTimeout(id); 8092 }; 8093 } 8094 8095 jQuery.fx.timer = function (timer) { 8096 if (timer() && jQuery.timers.push(timer) && !running) { 8097 running = true; 8098 animate(timer.elem); 8099 } 8100 }; 8101 8102 jQuery.fx.stop = function() { 8103 running = false;
8104 }; 8105 8106}(jQuery, this)); 8107/*! Copyright (c) 2011 Brandon Aaron (http://brandonaaron.net) 8108 * Licensed under the MIT License (LICENSE.txt). 8109 * 8110 * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers. 8111 * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix. 8112 * Thanks to: Seamus Leahy for adding deltaX and deltaY 8113 * 8114 * Version: 3.0.6 8115 * 8116 * Requires: 1.2.2+ 8117 */ 8118(function($) { 8119 var types = ['DOMMouseScroll', 'mousewheel']; 8120 if ($.event.fixHooks) { 8121 for (var i = types.length; i;) { 8122 $.event.fixHooks[types[--i]] = $.event.mouseHooks; 8123 } 8124 } 8125 $.event.special.mousewheel = { 8126 setup: function() { 8127 if (this.addEventListener) { 8128 for (var i = types.length; i;) { 8129 this.addEventListener(types[--i], handler, false); 8130 } 8131 } else { 8132 this.onmousewheel = handler; 8133 } 8134 }, 8135 teardown: function() { 8136 if (this.removeEventListener) { 8137 for (var i = types.length; i;) { 8138 this.removeEventListener(types[--i], handler, false); 8139 } 8140 } else { 8141 this.onmousewheel = null; 8142 } 8143 } 8144 }; 8145 $.fn.extend({ 8146 mousewheel: function(fn) { 8147 return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel"); 8148 }, 8149 unmousewheel: function(fn) { 8150 return this.unbind("mousewheel", fn); 8151 } 8152 }); 8153 8154 function handler(event) { 8155 var orgEvent = event || window.event, 8156 args = [].slice.call(arguments, 1), 8157 delta = 0, 8158 returnValue = true, 8159 deltaX = 0, 8160 deltaY = 0; 8161 event = $.event.fix(orgEvent); 8162 event.type = "mousewheel"; 8163 // Old school scrollwheel delta 8164 if (orgEvent.wheelDelta) { 8165 delta = orgEvent.wheelDelta / 120; 8166 } 8167 if (orgEvent.detail) { 8168 delta = -orgEvent.detail / 3; 8169 } 8170 // New school multidimensional scroll (touchpads) deltas 8171 deltaY = delta; 8172 // Gecko 8173 if (orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS) { 8174 deltaY = 0; 8175 deltaX = -1 * delta; 8176 } 8177 // Webkit 8178 if (orgEvent.wheelDeltaY !== undefined) { 8179 deltaY = orgEvent.wheelDeltaY / 120; 8180 } 8181 if (orgEvent.wheelDeltaX !== undefined) { 8182 deltaX = -1 * orgEvent.wheelDeltaX / 120; 8183 } 8184 // Add event and delta to the front of the arguments 8185 args.unshift(event, delta, deltaX, deltaY); 8186 return ($.event.dispatch || $.event.handle).apply(this, args); 8187 } 8188})(jQuery); 8189/** 8190 * jQuery iLightBox - Revolutionary Lightbox Plugin 8191 * http://www.ilightbox.net/ 8192 * 8193 * @version: 2.2.4 - October 14, 2017 8194 * 8195 * @author: iProDev (Hemn Chawroka) 8196 * http://www.iprodev.com/ 8197 * 8198 */ 8199(function($, window, undefined) { 8200 8201 var extensions = { 8202 flash: ['swf'], 8203 image: ['bmp', 'gif', 'jpeg', 'jpg', 'png', 'tiff', 'tif', 'jfif', 'jpe'], 8204 iframe: ['asp', 'aspx', 'cgi', 'cfm', 'htm', 'html', 'jsp', 'php', 'pl', 'php3', 'php4', 'php5', 'phtml', 'rb', 'rhtml', 'shtml', 'txt'], 8205 video: ['avi', 'mov', 'mpg', 'mpeg', 'movie', 'mp4', 'webm', 'ogv', 'ogg', '3gp', 'm4v'] 8206 }, 8207 8208 // Global DOM elements 8209 $win = $(window), 8210 $doc = $(document), 8211 8212 // Support indicators 8213 browser, 8214 transform, 8215 gpuAcceleration, 8216 fullScreenApi = '', 8217 userAgent = navigator.userAgent || navigator.vendor || window.opera, 8218 supportTouch = "ontouchstart" in window || navigator.msMaxTouchPoints || (navigator.maxTouchPoints && navigator.userAgent.indexOf('Windows') > -1), 8219 ishybrid = navigator.maxTouchPoints && navigator.userAgent.indexOf('Windows') > -1, 8220 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 )|
8220sy(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)), 8221 8222 // Events 8223 clickEvent = ishybrid ? "itap.iLightBox click.iLightBox" : supportTouch ? "itap.iLightBox" : "click.iLightBox", 8224 touchStartEvent = ishybrid ? "touchstart.iLightBox mousedown.iLightBox" : supportTouch ? "touchstart.iLightBox" : "mousedown.iLightBox", 8225 touchStopEvent = ishybrid ? "touchend.iLightBox mouseup.iLightBox" : supportTouch ? "touchend.iLightBox" : "mouseup.iLightBox", 8226 touchMoveEvent = ishybrid ? "touchmove.iLightBox mousemove.iLightBox" : supportTouch ? "touchmove.iLightBox" : "mousemove.iLightBox", 8227 8228 // Math shorthands 8229 abs = Math.abs, 8230 sqrt = Math.sqrt, 8231 round = Math.round, 8232 max = Math.max, 8233 min = Math.min, 8234 floor = Math.floor, 8235 random = Math.random, 8236 8237 pluginspages = { 8238 quicktime: 'http://www.apple.com/quicktime/download', 8239 flash: 'http://www.adobe.com/go/getflash' 8240 }, 8241 8242 iLightBox = function(el, options, items, instant) { 8243 var iL = this; 8244 8245 iL.options = options, 8246 iL.selector = options.selector || el, 8247 iL.context = document, 8248 iL.instant = instant; 8249 8250 if (items.length < 1) iL.attachItems(); 8251 else iL.items = items; 8252 8253 iL.vars = { 8254 total: iL.items.length, 8255 start: 0, 8256 current: null, 8257 next: null, 8258 prev: null, 8259 BODY: $('body'), 8260 loadRequests: 0, 8261 overlay: $('<div class="ilightbox-overlay"></div>'), 8262 loader: $('<div class="ilightbox-loader"><div></div></div>'), 8263 toolbar: $('<div class="ilightbox-toolbar"></div>'), 8264 innerToolbar: $('<div class="ilightbox-inner-toolbar"></div>'), 8265 title: $('<div class="ilightbox-title"></div>'), 8266 closeButton: $('<a class="ilightbox-close" title="' + iL.options.text.close + '"></a>'), 8267 fullScreenButton: $('<a class="ilightbox-fullscreen" title="' + iL.options.text.enterFullscreen + '"></a>'), 8268 innerPlayButton: $('<a class="ilightbox-play" title="' + iL.options.text.slideShow + '"></a>'), 8269 innerNextButton: $('<a class="ilightbox-next-button" title="' + iL.options.text.next + '"></a>'), 8270 innerPrevButton: $('<a class="ilightbox-prev-button" title="' + iL.options.text.previous + '"></a>'), 8271 holder: $('<div class="ilightbox-holder' + (supportTouch ? ' supportTouch' : '') + '" ondragstart="return false;"><div class="ilightbox-container"></div></div>'), 8272 nextPhoto: $('<div class="ilightbox-holder' + (supportTouch ? ' supportTouch' : '') + ' ilightbox-next" ondragstart="return false;"><div class="ilightbox-container"></div></div>'), 8273 prevPhoto: $('<div class="ilightbox-holder' + (supportTouch ? ' supportTouch' : '') + ' ilightbox-prev" ondragstart="return false;"><div class="ilightbox-container"></div></div>'), 8274 nextButton: $('<a class="ilightbox-button ilightbox-next-button" ondragstart="return false;" title="' + iL.options.text.next + '"><span></span></a>'), 8275 prevButton: $('<a class="ilightbox-button ilightbox-prev-button" ondragstart="return false;" title="' + iL.options.text.previous + '"><span></span></a>'), 8276 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>'), 8277 thumbs: false, 8278 nextLock: false, 8279 prevLock: false, 8280 hashLock: false, 8281 isMobile: false, 8282 mobileMaxWidth: 980, 8283 isInFullScreen: false, 8284 isSwipe: false, 8285 mouseID: 0, 8286 cycleID: 0, 8287 isPaused: 0, 8288 captionHeight: 39, 8289 }; 8290 8291 // Hideable elements with mousemove event 8292 iL.vars.hideableElements = iL.vars.nextButton.add(iL.vars.prevButton); 8293 8294 iL.normalizeItems(); 8295 8296 //Check necessary plugins 8297 iL.availPlugins(); 8298 8299 //Set startFrom 8300 iL.options.startFrom = (iL.options.startFrom > 0 && iL.options.startFrom >= iL.vars.total) ? iL.vars.total - 1 : iL.options.startFrom; 8301 8302 //If randomStart 8303 iL.options.startFrom = (iL.options.randomStart) ? floor(random() * iL.vars.total) : iL.options.startFrom; 8304 iL.vars.start = iL.options.startFrom; 8305 8306 if (instant) iL.instantCall(); 8307 else iL.patchItemsEvents(); 8308 8309 if (iL.options.linkId) { 8310 iL.hashChangeHandler(); 8311 $win.iLightBoxHashChange(function() { 8312 iL.hashChangeHandler(); 8313 }); 8314 } 8315 8316 if (supportTouch) {
8317 var RegExp = /(click|mouseenter|mouseleave|mouseover|mouseout)/ig, 8318 replace = "itap"; 8319 iL.options.caption.show = iL.options.caption.show.replace(RegExp, replace), 8320 iL.options.caption.hide = iL.options.caption.hide.replace(RegExp, replace), 8321 iL.options.social.show = iL.options.social.show.replace(RegExp, replace), 8322 iL.options.social.hide = iL.options.social.hide.replace(RegExp, replace); 8323 } 8324 8325 if (iL.options.controls.arrows || $(window).width() < UNCODE.mediaQuery) { 8326 $.extend(iL.options.styles, { 8327 nextOffsetX: ($(window).width() > UNCODE.mediaQuery) ? 36 : 4, 8328 prevOffsetX: ($(window).width() > UNCODE.mediaQuery) ? 36 : 4, 8329 nextOpacity: 0, 8330 prevOpacity: 0 8331 }); 8332 } 8333 }; 8334 8335 //iLightBox helpers 8336 iLightBox.prototype = { 8337 showLoader: function() { 8338 var iL = this; 8339 iL.vars.loadRequests += 1; 8340 if (iL.options.path.toLowerCase() == "horizontal") iL.vars.loader.addClass('ilightbox-show').stop().animate({ 8341 //top: '-30px' 8342 opacity: '1' 8343 }, iL.options.show.speed, 'easeOutCirc'); 8344 else iL.vars.loader.addClass('ilightbox-show').stop().animate({ 8345 //left: '-30px' 8346 opacity: '1' 8347 }, iL.options.show.speed, 'easeOutCirc'); 8348 }, 8349 8350 hideLoader: function() { 8351 var iL = this; 8352 iL.vars.loadRequests -= 1; 8353 iL.vars.loadRequests = (iL.vars.loadRequests < 0) ? 0 : iL.vars.loadRequests; 8354 if (iL.options.path.toLowerCase() == "horizontal") { 8355 if (iL.vars.loadRequests <= 0) iL.vars.loader.removeClass('ilightbox-show').stop().animate({ 8356 //top: '-192px' 8357 opacity: '0' 8358 }, iL.options.show.speed, 'easeInCirc'); 8359 } else { 8360 if (iL.vars.loadRequests <= 0) iL.vars.loader.removeClass('ilightbox-show').stop().animate({ 8361 //left: '-192px' 8362 opacity: '0' 8363 }, iL.options.show.speed, 'easeInCirc'); 8364 } 8365 }, 8366 8367 createUI: function() { 8368 var iL = this; 8369 8370 iL.ui = { 8371 currentElement: iL.vars.holder, 8372 nextElement: iL.vars.nextPhoto, 8373 prevElement: iL.vars.prevPhoto, 8374 currentItem: iL.vars.current, 8375 nextItem: iL.vars.next, 8376 prevItem: iL.vars.prev, 8377 hide: function() { 8378 iL.closeAction(); 8379 }, 8380 refresh: function() { 8381 (arguments.length > 0) ? iL.repositionPhoto(true): iL.repositionPhoto(); 8382 }, 8383 fullscreen: function() { 8384 iL.fullScreenAction(); 8385 } 8386 }; 8387 }, 8388 8389 attachItems: function() { 8390 var iL = this, 8391 itemsObject = new Array(), 8392 items = new Array(); 8393 8394 $(iL.selector, iL.context).each(function() { 8395 var t = $(this), 8396 URL = t.attr(iL.options.attr) || null, 8397 options = t.data("options") && eval("({" + t.data("options") + "})") || {}, 8398 caption = t.data('caption'), 8399 title = t.data('title'), 8400 type = t.data('type') || getTypeByExtension(URL), 8401 clone = t.data('lbox-clone') || false; 8402 8403 //Uncode addition ##START## 8404 if (type === false) { 8405 return; 8406 } 8407 //Uncode addition ##END## 8408 8409 if (t.data('lbox-clone') != undefined) return; 8410 8411 //Uncode addition ##START## 8412 if ( typeof t.attr('data-album') != 'undefined' && t.attr('data-album') != '' ) { 8413 var ALBUM_URLS = JSON.parse(t.attr('data-album')), 8414 URL_i, 8415 URLS_LENGHT = ALBUM_URLS.length; 8416 8417 for (URL_i = 0; URL_i < URLS_LENGHT; URL_i++) { 8418 if ( typeof ALBUM_URLS[URL_i].url !== 'undefined' && ALBUM_URLS[URL_i].url != '' ) { 8419 var item_opts = 'width:' + ALBUM_URLS[URL_i].width + ',height:' + ALBUM_URLS[URL_i].height + ',thumbnail: \'' + ALBUM_URLS[URL_i].thumbnail + '\''; 8420 item_opts = item_opts && eval("({" + item_opts + "})") || {}, 8421 items.push({ 8422 URL: ALBUM_URLS[URL_i].url, 8423 caption: ALBUM_URLS[URL_i].caption, 8424 title: ALBUM_URLS[URL_i].title, 8425 type: getTypeByExtension(ALBUM_URLS[URL_i].url), 8426 options: item_opts, 8427 clone: clone 8428 }); 8429 var newT = t; 8430 newT.attr('href',ALBUM_URLS[URL_i].url); 8431 if (!iL.instant) itemsObject.push(newT); 8432 } 8433 } 8434 } else { 8435 //Uncode addition ##END## 8436 items.push({ 8437 URL: URL, 8438 caption: caption, 8439 title: title, 8440 type: type, 8441 options: options, 8442 clone: clone 8443 }); 8444 } 8445 8446 8447 if (iL.vars != undefined) iL.vars.total = items.length; 8448 8449 if (!iL.instant) itemsObject.push(t); 8450 }); 8451 8452 iL.items = items, 8453 iL.itemsObject = itemsObject; 8454 8455 }, 8456 8457 normalizeItems: function() { 8458 var iL = this, 8459 newItems = new Array(); 8460 8461 $.each(iL.items, function(key, val) { 8462 8463 if (typeof val == "string") val = { 8464 url: val 8465 }; 8466 8467 var URL = val.url || val.URL || null, 8468 options = val.options || {}, 8469 caption = val.caption || null, 8470 title = val.title || null, 8471 type = (val.type) ? val.type.toLowerCase() : getTypeByExtension(URL), 8472 ext = (typeof URL != 'object') ? getExtension(URL) : ''; 8473 8474 options.thumbnail = options.thumbnail || ((type == "image") ? URL : null),
8475 options.videoType = options.videoType || null, 8476 options.skin = options.skin || iL.options.skin, 8477 options.width = options.width || null, 8478 options.height = options.height || null, 8479 options.mousewheel = (typeof options.mousewheel != 'undefined') ? options.mousewheel : true, 8480 options.swipe = (typeof options.swipe != 'undefined') ? options.swipe : true, 8481 options.social = (typeof options.social != 'undefined') ? options.social : iL.options.social.buttons && $.extend({}, {}, iL.options.social.buttons); 8482 8483 if (type == "video") { 8484 options.html5video = (typeof options.html5video != 'undefined') ? options.html5video : {}; 8485 8486 options.html5video.webm = options.html5video.webm || options.html5video.WEBM || null; 8487 options.html5video.controls = (typeof options.html5video.controls != 'undefined') ? options.html5video.controls : "controls"; 8488 options.html5video.preload = options.html5video.preload || "metadata"; 8489 options.html5video.autoplay = (typeof options.html5video.autoplay != 'undefined') ? options.html5video.autoplay : false; 8490 //UNCODE addition 8491 options.html5video.loop = (typeof options.html5video.loop != 'undefined') ? options.html5video.loop : false; 8492 } 8493 8494 if (!options.width || !options.height) { 8495 if (type == "video") options.width = 1280, options.height = 720; 8496 else if (type == "iframe") options.width = '100%', options.height = '90%'; 8497 else if (type == "flash") options.width = 1280, options.height = 720; 8498 } 8499 8500 delete val.url; 8501 val.index = key; 8502 val.URL = URL; 8503 val.caption = caption; 8504 val.title = title; 8505 val.type = type; 8506 val.options = options; 8507 val.ext = ext; 8508 8509 newItems.push(val); 8510 }); 8511 8512 iL.items = newItems; 8513 }, 8514 8515 instantCall: function() { 8516 var iL = this, 8517 key = iL.vars.start; 8518 8519 iL.vars.current = key; 8520 iL.vars.next = (iL.items[key + 1]) ? key + 1 : null; 8521 iL.vars.prev = (iL.items[key - 1]) ? key - 1 : null; 8522 8523 iL.addContents(); 8524 iL.patchEvents(); 8525 }, 8526 8527 addContents: function() { 8528 var iL = this, 8529 vars = iL.vars, 8530 opts = iL.options, 8531 viewport = getViewport(), 8532 path = opts.path.toLowerCase(), 8533 recognizingItems = vars.total > 0 && iL.items.filter(function(e, i, arr) { 8534 return ['image', 'flash', 'video'].indexOf(e.type) === -1 && typeof e.recognized === 'undefined' && (opts.smartRecognition || e.options.smartRecognition); 8535 }), 8536 needRecognition = recognizingItems.length > 0; 8537 8538 if (opts.mobileOptimizer && !opts.innerToolbar) 8539 vars.isMobile = viewport.width <= vars.mobileMaxWidth; 8540 8541 vars.overlay.addClass(opts.skin).hide().css('opacity', opts.overlay.opacity); 8542 8543 if (opts.linkId) 8544 vars.overlay[0].setAttribute('linkid', opts.linkId); 8545 8546 //Add Toolbar Buttons 8547 if (opts.controls.toolbar) { 8548 vars.toolbar.addClass(opts.skin).append(vars.closeButton); 8549 if (opts.controls.fullscreen) 8550 vars.toolbar.append(vars.fullScreenButton); 8551 if (opts.controls.slideshow) 8552 vars.toolbar.append(vars.innerPlayButton); 8553 if (vars.total > 1) 8554 vars.toolbar.append(vars.innerPrevButton).append(vars.innerNextButton); 8555 } 8556 8557 //Append elements to body 8558 vars.BODY.addClass('ilightbox-noscroll').append(vars.overlay).append(vars.loader).append(vars.holder).append(vars.nextPhoto).append(vars.prevPhoto); 8559 8560 if (!opts.innerToolbar) 8561 vars.BODY.append(vars.toolbar); 8562 if (opts.controls.arrows) 8563 vars.BODY.append(vars.nextButton).append(vars.prevButton); 8564 8565 if (opts.controls.thumbnail && vars.total > 1) { 8566 vars.BODY.append(vars.thumbnails); 8567 vars.thumbnails.addClass(opts.skin).addClass('ilightbox-' + path); 8568 $('div.ilightbox-thumbnails-grid', vars.thumbnails).empty(); 8569 vars.thumbs = true; 8570 } 8571 8572 //Configure loader and arrows 8573 var loaderCss = (opts.path.toLowerCase() == "horizontal") ? { 8574 left: parseInt((viewport.width / 2) - (vars.loader.outerWidth() / 2)) 8575 } : { 8576 top: parseInt((viewport.height / 2) - (vars.loader.outerHeight() / 2)) 8577 }; 8578 vars.loader.addClass(opts.skin).css(loaderCss); 8579 vars.nextButton.add(vars.prevButton).addClass(opts.skin); 8580 if (path == "horizontal") 8581 vars.loader.add(vars.nextButton).add(vars.prevButton).addClass('horizontal'); 8582 8583 // Configure arrow buttons 8584 vars.BODY[vars.isMobile ? 'addClass' : 'removeClass']('isMobile'); 8585 8586 if (!opts.infinite) { 8587 vars.prevButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled'); 8588 8589 if (vars.current == 0) 8590 vars.prevButton.add(vars.innerPrevButton).addClass('disabled'); 8591 if (vars.current >= vars.total - 1) 8592 vars.nextButton.add(vars.innerNextButton).addClass('disabled'); 8593 } 8594 8595 if (opts.show.effect) { 8596 vars.overlay.stop().fadeIn(opts.show.speed); 8597 vars.toolbar.stop().fadeIn(opts.show.speed); 8598 } else { 8599 vars.overlay.show(); 8600 vars.toolbar.show(); 8601 } 8602 8603 var length = recognizingItems.length; 8604 if (needRecognition) { 8605 iL.showLoader(); 8606 8607 $.each(recognizingItems, function(key, val) { 8608 var resultFnc = function(result) { 8609 var key = -1, 8610 filter = iL.items.filter(function(e, i, arr) { 8611 if (e.URL == result.url) 8612 key = i; 8613 8614 return e.URL == result.url; 8615 }), 8616 self = iL.items[key]; 8617 8618 if (result) 8619 $.extend(true, self, { 8620 URL: result.source, 8621 type: result.type, 8622 recognized: true, 8623 options: { 8624 html5video: result.html5video, 8625 width: (result.type == "image") ? 0 : (result.width || self.width), 8626 height: (result.type == "image") ? 0 : (result.height || self.height), 8627 thumbnail: self.options.thumbnail || result.thumbnail 8628 } 8629 }); 8630 8631 length--; 8632 8633 if (length == 0) { 8634 iL.hideLoader(); 8635 8636 vars.dontGenerateThumbs = false;
8637 iL.generateThumbnails(); 8638 8639 if (opts.show.effect) 8640 setTimeout(function() { 8641 iL.generateBoxes(); 8642 }, opts.show.speed); 8643 else 8644 iL.generateBoxes(); 8645 } 8646 }; 8647 8648 iL.ogpRecognition(this, resultFnc); 8649 }); 8650 } 8651 else { 8652 if (opts.show.effect) 8653 setTimeout(function() { 8654 iL.generateBoxes(); 8655 }, opts.show.speed); 8656 else 8657 iL.generateBoxes(); 8658 } 8659 8660 iL.createUI(); 8661 8662 window.iLightBox = { 8663 close: function() { 8664 iL.closeAction(); 8665 }, 8666 fullscreen: function() { 8667 iL.fullScreenAction(); 8668 }, 8669 moveNext: function() { 8670 iL.moveTo('next'); 8671 }, 8672 movePrev: function() { 8673 iL.moveTo('prev'); 8674 }, 8675 goTo: function(index) { 8676 iL.goTo(index); 8677 }, 8678 refresh: function() { 8679 iL.refresh(); 8680 }, 8681 reposition: function() { 8682 (arguments.length > 0) ? iL.repositionPhoto(true): iL.repositionPhoto(); 8683 }, 8684 setOption: function(options) { 8685 iL.setOption(options); 8686 }, 8687 destroy: function() { 8688 iL.closeAction(); 8689 iL.dispatchItemsEvents(); 8690 } 8691 }; 8692 8693 if (opts.linkId) { 8694 vars.hashLock = true; 8695 window.location.hash = opts.linkId + '/' + vars.current; 8696 setTimeout(function() { 8697 vars.hashLock = false; 8698 }, 55); 8699 } 8700 8701 if (!opts.slideshow.startPaused) { 8702 iL.resume(); 8703 vars.innerPlayButton.removeClass('ilightbox-play').addClass('ilightbox-pause'); 8704 } 8705 8706 //Trigger the onOpen callback 8707 if (typeof iL.options.callback.onOpen == 'function') iL.options.callback.onOpen.call(iL); 8708 }, 8709 8710 loadContent: function(obj, opt, speed) { 8711 var iL = this, 8712 holder, item; 8713 8714 iL.createUI(); 8715 8716 obj.speed = speed || iL.options.effects.loadedFadeSpeed; 8717 8718 if (opt == 'current') { 8719 if (!obj.options.mousewheel) iL.vars.lockWheel = true; 8720 else iL.vars.lockWheel = false; 8721 8722 if (!obj.options.swipe) iL.vars.lockSwipe = true; 8723 else iL.vars.lockSwipe = false; 8724 } 8725 8726 switch (opt) { 8727 case 'current': 8728 holder = iL.vars.holder, item = iL.vars.current; 8729 break; 8730 case 'next': 8731 holder = iL.vars.nextPhoto, item = iL.vars.next; 8732 break; 8733 case 'prev': 8734 holder = iL.vars.prevPhoto, item = iL.vars.prev; 8735 break; 8736 } 8737 8738 holder.removeAttr('style class').addClass('ilightbox-holder' + (supportTouch ? ' supportTouch' : '')).addClass(obj.options.skin); 8739 $('div.ilightbox-inner-toolbar', holder).remove(); 8740 8741 if (obj.title || iL.options.innerToolbar) { 8742 var innerToolbar = iL.vars.innerToolbar.clone(); 8743 if (obj.title && iL.options.show.title) { 8744 var title = iL.vars.title.clone(); 8745 title.empty().html(obj.title); 8746 innerToolbar.append(title); 8747 } 8748 if (iL.options.innerToolbar) { 8749 innerToolbar.append((iL.vars.total > 1) ? iL.vars.toolbar.clone() : iL.vars.toolbar); 8750 } 8751 holder.prepend(innerToolbar); 8752 } 8753 8754 //console.warn('loadContent', arguments); 8755 8756 iL.loadSwitcher(obj, holder, item, opt); 8757 }, 8758 8759 loadSwitcher: function(obj, holder, item, opt) { 8760 var iL = this, 8761 opts = iL.options, 8762 api = { 8763 element: holder, 8764 position: item 8765 }; 8766 8767 switch (obj.type) { 8768 case 'image': 8769 //Trigger the onBeforeLoad callback 8770 if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item); 8771 if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api); 8772 8773 iL.loadImage(obj.URL, function(img) { 8774 //Trigger the onAfterLoad callback 8775 if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item); 8776 if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api); 8777 8778 var width = (img) ? img.width : 400, 8779 height = (img) ? img.height : 200; 8780 8781 holder.data({ 8782 naturalWidth: width, 8783 naturalHeight: height 8784 }); 8785 8786 $('div.ilightbox-container', holder).empty().append((img) ? '<img src="' + obj.URL + '" class="ilightbox-image" />' : '<span class="ilightbox-alert">' + opts.errors.loadImage + '</span>'); 8787 8788 //Trigger the onRender callback 8789 if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item); 8790 if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api); 8791 8792 iL.configureHolder(obj, opt, holder); 8793 }); 8794 8795 break; 8796
8797 case 'video': 8798 holder.data({ 8799 naturalWidth: obj.options.width, 8800 naturalHeight: obj.options.height 8801 }); 8802 8803 if (opt === 'current') { 8804 iL.addContent(holder, obj); 8805 8806 //Trigger the onRender callback 8807 if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item); 8808 if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api); 8809 } else { 8810 $('div.ilightbox-container', holder).empty(); 8811 } 8812 8813 iL.configureHolder(obj, opt, holder); 8814 8815 break; 8816 8817 case 'iframe': 8818 //iL.showLoader(); 8819 holder.data({ 8820 naturalWidth: obj.options.width, 8821 naturalHeight: obj.options.height 8822 }); 8823 8824 iL.configureHolder(obj, opt, holder); 8825 8826 if (opt === 'current') { 8827 var el = iL.addContent(holder, obj); 8828 8829 //Trigger the onRender callback 8830 if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item); 8831 if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api); 8832 8833 //Trigger the onBeforeLoad callback 8834 if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item); 8835 if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api); 8836 8837 el.bind('load', function() { 8838 //Trigger the onAfterLoad callback 8839 if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item); 8840 if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api); 8841 8842 //iL.hideLoader(); 8843 el.unbind('load'); 8844 }); 8845 } else { 8846 $('div.ilightbox-container', holder).empty(); 8847 } 8848 8849 break; 8850 8851 case 'inline': 8852 var el = $(obj.URL), 8853 content = iL.addContent(holder, obj), 8854 images = findImageInElement(holder); 8855 8856 holder.data({ 8857 naturalWidth: (iL.items[item].options.width || el.outerWidth()), 8858 naturalHeight: (iL.items[item].options.height || el.outerHeight()) 8859 }); 8860 content.children().eq(0).show(); 8861 8862 //Trigger the onRender callback 8863 if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item); 8864 if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api); 8865 8866 //Trigger the onBeforeLoad callback 8867 if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item); 8868 if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api); 8869 8870 iL.loadImage(images, function() { 8871 //Trigger the onAfterLoad callback 8872 if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item); 8873 if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api); 8874 8875 iL.configureHolder(obj, opt, holder); 8876 }); 8877 8878 break; 8879 8880 case 'flash': 8881 var el = iL.addContent(holder, obj); 8882 8883 holder.data({ 8884 naturalWidth: (iL.items[item].options.width || el.outerWidth()), 8885 naturalHeight: (iL.items[item].options.height || el.outerHeight()) 8886 }); 8887 8888 //Trigger the onRender callback 8889 if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item); 8890 if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api); 8891 8892 iL.configureHolder(obj, opt, holder); 8893 8894 break; 8895 8896 case 'ajax': 8897 var ajax = obj.options.ajax || {}; 8898 //Trigger the onBeforeLoad callback 8899 if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item); 8900 if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api); 8901 8902 iL.showLoader(); 8903 $.ajax({ 8904 url: obj.URL || opts.ajaxSetup.url, 8905 data: ajax.data || null, 8906 dataType: ajax.dataType || "html", 8907 type: ajax.type || opts.ajaxSetup.type, 8908 cache: ajax.cache || opts.ajaxSetup.cache, 8909 crossDomain: ajax.crossDomain || opts.ajaxSetup.crossDomain, 8910 global: ajax.global || opts.ajaxSetup.global, 8911 ifModified: ajax.ifModified || opts.ajaxSetup.ifModified, 8912 username: ajax.username || opts.ajaxSetup.username, 8913 password: ajax.password || opts.ajaxSetup.password, 8914 beforeSend: ajax.beforeSend || opts.ajaxSetup.beforeSend, 8915 complete: ajax.complete || opts.ajaxSetup.complete, 8916 success: function(data, textStatus, jqXHR) { 8917 iL.hideLoader(); 8918 8919 var el = $(data), 8920 container = $('div.ilightbox-container', holder), 8921 elWidth = iL.items[item].options.width || parseInt(el[0].getAttribute('width')), 8922 elHeight = iL.items[item].options.height || parseInt(el[0].getAttribute('height')), 8923 css = (el[0].getAttribute('width') && el[0].getAttribute('height')) ? { 8924 'overflow': 'hidden' 8925 } : {}; 8926 8927 container.empty().append($('<div class="ilightbox-wrapper"></div>').css(css).html(el)); 8928 holder.show().data({
8929 naturalWidth: (elWidth || container.outerWidth()), 8930 naturalHeight: (elHeight || container.outerHeight()) 8931 }).hide(); 8932 8933 //Trigger the onRender callback 8934 if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item); 8935 if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api); 8936 8937 var images = findImageInElement(holder); 8938 iL.loadImage(images, function() { 8939 //Trigger the onAfterLoad callback 8940 if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item); 8941 if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api); 8942 8943 iL.configureHolder(obj, opt, holder); 8944 }); 8945 8946 opts.ajaxSetup.success(data, textStatus, jqXHR); 8947 if (typeof ajax.success == 'function') ajax.success(data, textStatus, jqXHR); 8948 }, 8949 error: function(jqXHR, textStatus, errorThrown) { 8950 //Trigger the onAfterLoad callback 8951 if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item); 8952 if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api); 8953 8954 iL.hideLoader(); 8955 $('div.ilightbox-container', holder).empty().append('<span class="ilightbox-alert">' + opts.errors.loadContents + '</span>'); 8956 iL.configureHolder(obj, opt, holder); 8957 8958 opts.ajaxSetup.error(jqXHR, textStatus, errorThrown); 8959 if (typeof ajax.error == 'function') ajax.error(jqXHR, textStatus, errorThrown); 8960 } 8961 }); 8962 8963 break; 8964 8965 case 'html': 8966 var object = obj.URL, 8967 el 8968 container = $('div.ilightbox-container', holder); 8969 8970 if (object[0].nodeName) el = object.clone(); 8971 else { 8972 var dom = $(object); 8973 if (dom.selector) el = $('<div>' + dom + '</div>'); 8974 else el = dom; 8975 } 8976 8977 var elWidth = iL.items[item].options.width || parseInt(el.attr('width')), 8978 elHeight = iL.items[item].options.height || parseInt(el.attr('height')); 8979 8980 iL.addContent(holder, obj); 8981 8982 el.appendTo(document.documentElement).hide(); 8983 8984 //Trigger the onRender callback 8985 if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item); 8986 if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api); 8987 8988 var images = findImageInElement(holder); 8989 8990 //Trigger the onBeforeLoad callback 8991 if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item); 8992 if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api); 8993 8994 iL.loadImage(images, function() { 8995 //Trigger the onAfterLoad callback 8996 if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item); 8997 if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api); 8998 8999 holder.show().data({ 9000 naturalWidth: (elWidth || container.outerWidth()), 9001 naturalHeight: (elHeight || container.outerHeight()) 9002 }).hide(); 9003 el.remove(); 9004 9005 iL.configureHolder(obj, opt, holder); 9006 }); 9007 9008 break; 9009 } 9010 }, 9011 9012 configureHolder: function(obj, opt, holder) { 9013 var iL = this, 9014 vars = iL.vars, 9015 opts = iL.options; 9016 9017 if (opt != "current")(opt == "next") ? holder.addClass('ilightbox-next') : holder.addClass('ilightbox-prev'); 9018 9019 if (opt == "current") 9020 var item = vars.current; 9021 else if (opt == "next") 9022 var opacity = opts.styles.nextOpacity, 9023 item = vars.next; 9024 else 9025 var opacity = opts.styles.prevOpacity, 9026 item = vars.prev; 9027 9028 var api = { 9029 element: holder, 9030 position: item 9031 }; 9032 9033 iL.items[item].options.width = iL.items[item].options.width || 0, 9034 iL.items[item].options.height = iL.items[item].options.height || 0; 9035 9036 if (opt == "current") { 9037 if (opts.show.effect) holder.css(transform, gpuAcceleration).fadeIn(obj.speed, function() { 9038 holder.css(transform, ''); 9039 if (obj.caption) { 9040 iL.setCaption(obj, holder); 9041 var caption = $('div.ilightbox-caption', holder), 9042 percent = parseInt((caption.outerHeight() / holder.outerHeight()) * 100); 9043 if (opts.caption.start & percent <= 50) caption.fadeIn(opts.effects.fade
9043Speed); 9044 } 9045 9046 var social = obj.options.social; 9047 if (social) { 9048 iL.setSocial(social, obj.URL, holder); 9049 if (opts.social.start) $('div.ilightbox-social', holder).fadeIn(opts.effects.fadeSpeed); 9050 } 9051 9052 //Generate thumbnails 9053 iL.generateThumbnails(); 9054 9055 //Trigger the onShow callback 9056 if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item); 9057 if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api); 9058 }); 9059 else { 9060 holder.show(); 9061 9062 //Generate thumbnails 9063 iL.generateThumbnails(); 9064 9065 //Trigger the onShow callback 9066 if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item); 9067 if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api); 9068 } 9069 } else { 9070 if (opts.show.effect) holder.fadeTo(obj.speed, opacity, function() { 9071 if (opt == "next") vars.nextLock = false; 9072 else vars.prevLock = false; 9073 9074 //Generate thumbnails 9075 iL.generateThumbnails(); 9076 9077 //Trigger the onShow callback 9078 if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item); 9079 if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api); 9080 }); 9081 else { 9082 holder.css({ 9083 opacity: opacity 9084 }).show(); 9085 if (opt == "next") vars.nextLock = false; 9086 else vars.prevLock = false; 9087 9088 //Generate thumbnails 9089 iL.generateThumbnails(); 9090 9091 //Trigger the onShow callback 9092 if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item); 9093 if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api); 9094 } 9095 } 9096 9097 setTimeout(function() { 9098 iL.repositionPhoto(); 9099 }, 0); 9100 }, 9101 9102 generateBoxes: function() { 9103 var iL = this, 9104 vars = iL.vars, 9105 opts = iL.options; 9106 9107 if (opts.infinite && vars.total >= 3) { 9108 if (vars.current == vars.total - 1) vars.next = 0; 9109 if (vars.current == 0) vars.prev = vars.total - 1; 9110 } else opts.infinite = false; 9111 9112 //UNCODE addition 9113 if ( typeof iL.items[vars.current] == 'undefined' ) 9114 vars.current = 0; 9115 9116 iL.loadContent(iL.items[vars.current], 'current', opts.show.speed); 9117 9118 if (iL.items[vars.next]) iL.loadContent(iL.items[vars.next], 'next', opts.show.speed); 9119 if (iL.items[vars.prev]) iL.loadContent(iL.items[vars.prev], 'prev', opts.show.speed); 9120 }, 9121 9122 generateThumbnails: function() { 9123 var iL = this, 9124 vars = iL.vars, 9125 opts = iL.options, 9126 timeOut = null; 9127 9128 if (vars.thumbs && !iL.vars.dontGenerateThumbs) { 9129 var thumbnails = vars.thumbnails, 9130 container = $('div.ilightbox-thumbnails-container', thumbnails), 9131 grid = $('div.ilightbox-thumbnails-grid', container), 9132 i = 0; 9133 9134 grid.removeAttr('style').empty(); 9135 9136 $.each(iL.items, function(key, val) { 9137 var isActive = (vars.current == key) ? 'ilightbox-active' : '', 9138 opacity = (vars.current == key) ? opts.thumbnails.activeOpacity : opts.thumbnails.normalOpacity, 9139 thumb = val.options.thumbnail, 9140 thumbnail = $('<div class="ilightbox-thumbnail"></div>'), 9141 icon = $('<div class="ilightbox-thumbnail-icon"></div>'); 9142 9143 thumbnail.css({ 9144 opacity: 0 9145 }).addClass(isActive); 9146 9147 if ((val.type == "video" || val.type == "flash") && typeof val.options.icon == 'undefined') { 9148 icon.addClass('ilightbox-thumbnail-video'); 9149 thumbnail.append(icon); 9150 } else if (val.options.icon) { 9151 icon.addClass('ilightbox-thumbnail-' + val.options.icon); 9152 thumbnail.append(icon); 9153 } 9154 9155 if (thumb) iL.loadImage(thumb, function(img) { 9156 i++; 9157 if (img) thumbnail.data({ 9158 naturalWidth: img.width, 9159 naturalHeight: img.height 9160 }).append('<img src="' + thumb + '" border="0" />'); 9161 else thumbnail.data({ 9162 naturalWidth: opts.thumbnails.maxWidth, 9163 naturalHeight: opts.thumbnails.maxHeight 9164 }); 9165 9166 clearTimeout(timeOut); 9167 timeOut = setTimeout(function() { 9168 iL.positionThumbnails(thumbnails, container, grid); 9169 }, 20); 9170 setTimeout(function() { 9171 thumbnail.fadeTo(opts.effects.loadedFadeSpeed, opacity); 9172 }, i * 20); 9173 }); 9174 9175 grid.append(thumbnail); 9176 }); 9177 iL.vars.dontGenerateThumbs = true; 9178 } 9179 }, 9180
9181 positionThumbnails: function(thumbnails, container, grid) { 9182 var iL = this, 9183 vars = iL.vars, 9184 opts = iL.options, 9185 viewport = getViewport(), 9186 path = opts.path.toLowerCase(); 9187 9188 if (!thumbnails) thumbnails = vars.thumbnails; 9189 if (!container) container = $('div.ilightbox-thumbnails-container', thumbnails); 9190 if (!grid) grid = $('div.ilightbox-thumbnails-grid', container); 9191 9192 var thumbs = $('.ilightbox-thumbnail', grid), 9193 widthAvail = (path == 'horizontal') ? viewport.width - opts.styles.pageOffsetX : thumbs.eq(0).outerWidth() - opts.styles.pageOffsetX, 9194 heightAvail = (path == 'horizontal') ? thumbs.eq(0).outerHeight() - opts.styles.pageOffsetY : viewport.height - opts.styles.pageOffsetY, 9195 gridWidth = (path == 'horizontal') ? 0 : widthAvail, 9196 gridHeight = (path == 'horizontal') ? heightAvail : 0, 9197 active = $('.ilightbox-active', grid), 9198 gridCss = {}, 9199 css = {}; 9200 9201 if (arguments.length < 3) { 9202 thumbs.css({ 9203 opacity: opts.thumbnails.normalOpacity 9204 }); 9205 active.css({ 9206 opacity: opts.thumbnails.activeOpacity 9207 }); 9208 } 9209 9210 thumbs.each(function(i) { 9211 var t = $(this), 9212 data = t.data(), 9213 width = (path == 'horizontal') ? 0 : opts.thumbnails.maxWidth; 9214 height = (path == 'horizontal') ? opts.thumbnails.maxHeight : 0; 9215 dims = iL.getNewDimenstions(width, height, data.naturalWidth, data.naturalHeight, true); 9216 9217 t.css({ 9218 width: dims.width, 9219 height: dims.height 9220 }); 9221 if (path == 'horizontal') t.css({ 9222 'float': 'left' 9223 }); 9224 9225 (path == 'horizontal') ? ( 9226 gridWidth += t.outerWidth() 9227 ) : ( 9228 gridHeight += t.outerHeight() 9229 ); 9230 }); 9231 9232 gridCss = { 9233 width: gridWidth, 9234 height: gridHeight 9235 }; 9236 9237 grid.css(gridCss); 9238 9239 gridCss = {}; 9240 9241 var gridOffset = grid.offset(), 9242 activeOffset = (active.length) ? active.offset() : { 9243 top: parseInt(heightAvail / 2), 9244 left: parseInt(widthAvail / 2) 9245 }; 9246 9247 gridOffset.top = (gridOffset.top - $doc.scrollTop()), 9248 gridOffset.left = (gridOffset.left - $doc.scrollLeft()), 9249 activeOffset.top = (activeOffset.top - gridOffset.top - $doc.scrollTop()), 9250 activeOffset.left = (activeOffset.left - gridOffset.left - $doc.scrollLeft()); 9251 9252 (path == 'horizontal') ? ( 9253 gridCss.top = 0, 9254 gridCss.left = parseInt((widthAvail / 2) - activeOffset.left - (active.outerWidth() / 2)) 9255 ) : ( 9256 gridCss.top = parseInt(((heightAvail / 2) - activeOffset.top - (active.outerHeight() / 2))), 9257 gridCss.left = 0 9258 ); 9259 9260 if (arguments.length < 3) grid.stop().animate(gridCss, opts.effects.repositionSpeed, 'easeOutCirc'); 9261 else grid.css(gridCss); 9262 }, 9263 9264 loadImage: function(image, callback) { 9265 if (!$.isArray(image)) image = [image]; 9266 9267 var iL = this, 9268 length = image.length; 9269 9270 if (length > 0) { 9271 iL.showLoader(); 9272 $.each(image, function(index, value) { 9273 var img = new Image(); 9274 img.onload = function() { 9275 length -= 1; 9276 if (length == 0) { 9277 iL.hideLoader(); 9278 callback(img); 9279 } 9280 }; 9281 img.onerror = img.onabort = function() { 9282 length -= 1; 9283 if (length == 0) { 9284 iL.hideLoader(); 9285 callback(false); 9286 } 9287 }; 9288 img.src = image[index]; 9289 }); 9290 } else callback(false); 9291 }, 9292 9293 patchItemsEvents: function() { 9294 var iL = this, 9295 vars = iL.vars, 9296 clickEvent = ishybrid ? "itap.iL click.iL" : supportTouch ? "itap.iL" : "click.iL", 9297 vEvent = ishybrid ? "click.iL itap.iL" : supportTouch ? "click.iL" : "itap.iL"; 9298 9299 if (iL.context && iL.selector) { 9300 var $items = $(iL.selector, iL.context); 9301 9302 $(iL.context).on(clickEvent, iL.selector, function() { 9303 var $this = $(this), 9304 //UNCODE addition 9305 key = typeof $(this).data('lb-index') !== '' && $(this).closest('.owl-item').length ? $(this).data('lb-index') : $items.index($this); 9306 if (UNCODE.isMobile) { 9307 var isCarousel = $this.closest('.owl-carousel'); 9308 if (isCarousel.length) { 9309 if (isCarousel.hasClass('owl-translating')) return false; 9310 } 9311 } 9312 9313 vars.current = key; 9314 vars.next = iL.items[key + 1] ? key + 1 : null; 9315 vars.prev = iL.items[key - 1] ? key - 1 : null; 9316 9317 //UNCODE addition 9318 if ( vars.BODY.hasClass('fp-slide-scrolling') ) 9319 return false;
9320 9321 iL.addContents(); 9322 iL.patchEvents(); 9323 9324 return false; 9325 }).on(vEvent, iL.selector, function() { 9326 return false; 9327 }); 9328 } else 9329 $.each(iL.itemsObject, function(key, val) { 9330 val.on(clickEvent, function() { 9331 vars.current = key; 9332 vars.next = iL.items[key + 1] ? key + 1 : null; 9333 vars.prev = iL.items[key - 1] ? key - 1 : null; 9334 9335 iL.addContents(); 9336 iL.patchEvents(); 9337 9338 return false; 9339 }).on(vEvent, function() { 9340 return false; 9341 }); 9342 }); 9343 }, 9344 9345 dispatchItemsEvents: function() { 9346 var iL = this, 9347 vars = iL.vars, 9348 opts = iL.options; 9349 9350 if (iL.context && iL.selector) 9351 $(iL.context).off('.iL', iL.selector); 9352 else 9353 $.each(iL.itemsObject, function(key, val) { 9354 val.off('.iL'); 9355 }); 9356 }, 9357 9358 refresh: function() { 9359 var iL = this; 9360 9361 iL.dispatchItemsEvents(); 9362 iL.attachItems(); 9363 iL.normalizeItems(); 9364 iL.patchItemsEvents(); 9365 }, 9366 9367 patchEvents: function() { 9368 var iL = this, 9369 vars = iL.vars, 9370 opts = iL.options, 9371 path = opts.path.toLowerCase(), 9372 holders = $('.ilightbox-holder'), 9373 fullscreenEvent = fullScreenApi.fullScreenEventName + '.iLightBox', 9374 durationThreshold = 1000, 9375 horizontalDistanceThreshold = 9376 verticalDistanceThreshold = 100, 9377 buttonsArray = [vars.nextButton[0], vars.prevButton[0], vars.nextButton[0].firstChild, vars.prevButton[0].firstChild]; 9378 9379 $win.bind('resize.iLightBox', function() { 9380 var viewport = getViewport(); 9381 9382 if (opts.mobileOptimizer && !opts.innerToolbar) vars.isMobile = viewport.width <= vars.mobileMaxWidth; 9383 vars.BODY[vars.isMobile ? 'addClass' : 'removeClass']('isMobile'); 9384 9385 iL.repositionPhoto(null); 9386 if (supportTouch) { 9387 clearTimeout(vars.setTime); 9388 vars.setTime = setTimeout(function() { 9389 var scrollTop = getScrollXY().y; 9390 window.scrollTo(0, scrollTop - 30); 9391 window.scrollTo(0, scrollTop + 30); 9392 window.scrollTo(0, scrollTop); 9393 }, 2000); 9394 } 9395 if (vars.thumbs) iL.positionThumbnails(); 9396 }).bind('keydown.iLightBox', function(event) { 9397 if (opts.controls.keyboard) { 9398 switch (event.keyCode) { 9399 case 13: 9400 if (event.shiftKey && opts.keyboard.shift_enter) iL.fullScreenAction(); 9401 break; 9402 case 27: 9403 if (opts.keyboard.esc) iL.closeAction(); 9404 break; 9405 case 37: 9406 if (opts.keyboard.left && !vars.lockKey) iL.moveTo('prev'); 9407 break; 9408 case 38: 9409 if (opts.keyboard.up && !vars.lockKey) iL.moveTo('prev'); 9410 break; 9411 case 39: 9412 if (opts.keyboard.right && !vars.lockKey) iL.moveTo('next'); 9413 break; 9414 case 40: 9415 if (opts.keyboard.down && !vars.lockKey) iL.moveTo('next'); 9416 break; 9417 } 9418 } 9419 }); 9420 9421 if (fullScreenApi.supportsFullScreen) $win.bind(fullscreenEvent, function() { 9422 iL.doFullscreen(); 9423 }); 9424 9425 var holderEventsArr = [opts.caption.show + '.iLightBox', opts.caption.hide + '.iLightBox', opts.social.show + '.iLightBox', opts.social.hide + '.iLightBox'].filter(function(e, i, arr) { 9426 return arr.lastIndexOf(e) === i; 9427 }), 9428 holderEvents = ""; 9429 9430 $.each(holderEventsArr, function(key, val) { 9431 if (key != 0) holderEvents += ' '; 9432 holderEvents += val; 9433 }); 9434 9435 $doc.on(clickEvent, '.ilightbox-overlay', function() { 9436 if (opts.overlay.blur) iL.closeAction(); 9437 }).on(clickEvent, '.ilightbox-next, .ilightbox-next-button', function() { 9438 iL.moveTo('next'); 9439 }).on(clickEvent, '.ilightbox-prev, .ilightbox-prev-button', function() { 9440 iL.moveTo('prev'); 9441 }).on(clickEvent, '.ilightbox-thumbnail', function() { 9442 var t = $(this), 9443 thumbs = $('.ilightbox-thumbnail', vars.thumbnails), 9444 index = thumbs.index(t); 9445 9446 if (index != vars.current) iL.goTo(index); 9447 }).on(holderEvents, '.ilightbox-holder:not(.ilightbox-next, .ilightbox-prev)', function(e) { 9448 var caption = $('div.ilightbox-caption', vars.holder), 9449 social = $('div.ilightbox-social', vars.holder), 9450 fadeSpeed = opts.effects.fadeSpeed; 9451 9452 if (vars.nextLock || vars.prevLock) { 9453 if (e.type == opts.caption.show && !caption.is(':visible')) caption.fadeIn(fadeSpeed); 9454 else if (e.type == opts.caption.hide && caption.is(':visible')) caption.fadeOut(fadeSpeed); 9455 9456 if (e.type == opts.social.show && !social.is(':visible')) social.fadeIn(fadeSpeed); 9457 else if (e.type == opts.social.hide && social.is(':visible')) social.fadeOut(fadeSpeed); 9458 } else { 9459 if (e.type == opts.caption.show && !caption.is(':visible')) caption.stop().fadeIn(fadeSpeed); 9460 else if (e.type == opts.caption.hide && caption.is(':visible')) caption.stop().fadeOut(fadeSpeed); 9461 9462 if (e.type == opts.social.show && !social.is(':visible')) social.stop().fadeIn(fadeSpeed); 9463 else if (e.type == opts.social.hide && social.is(':visible')) social.stop().fadeOut(fadeSpeed); 9464 } 9465 }).on('mouseenter.iLightBox mouseleave.iLightBox', '.ilightbox-wrapper', function(e) { 9466 if (e.type == 'mouseenter') vars.lockWheel = true; 9467 else vars.lockWheel = false;
9468 }).on(clickEvent, '.ilightbox-toolbar a.ilightbox-close, .ilightbox-toolbar a.ilightbox-fullscreen, .ilightbox-toolbar a.ilightbox-play, .ilightbox-toolbar a.ilightbox-pause', function() { 9469 var t = $(this); 9470 9471 if (t.hasClass('ilightbox-fullscreen')) iL.fullScreenAction(); 9472 else if (t.hasClass('ilightbox-play')) { 9473 iL.resume(); 9474 t.addClass('ilightbox-pause').removeClass('ilightbox-play'); 9475 } else if (t.hasClass('ilightbox-pause')) { 9476 iL.pause(); 9477 t.addClass('ilightbox-play').removeClass('ilightbox-pause'); 9478 } else iL.closeAction(); 9479 }).on(touchMoveEvent, '.ilightbox-overlay, .ilightbox-thumbnails-container', function(e) { 9480 // prevent scrolling 9481 e.preventDefault(); 9482 }); 9483 9484 function mouseMoveHandler(e) { 9485 if (!vars.isMobile) { 9486 if (!vars.mouseID) { 9487 vars.hideableElements.show(); 9488 } 9489 9490 vars.mouseID = clearTimeout(vars.mouseID); 9491 9492 if (buttonsArray.indexOf(e.target) === -1) 9493 vars.mouseID = setTimeout(function() { 9494 vars.hideableElements.hide(); 9495 vars.mouseID = clearTimeout(vars.mouseID); 9496 }, 3000); 9497 } 9498 } 9499 9500 if (opts.controls.arrows && !supportTouch) $doc.on('mousemove.iLightBox', mouseMoveHandler); 9501 9502 if (opts.controls.slideshow && opts.slideshow.pauseOnHover) $doc.on('mouseenter.iLightBox mouseleave.iLightBox', '.ilightbox-holder:not(.ilightbox-next, .ilightbox-prev)', function(e) { 9503 if (e.type == 'mouseenter' && vars.cycleID) iL.pause(); 9504 else if (e.type == 'mouseleave' && vars.isPaused) iL.resume(); 9505 }); 9506 9507 var switchers = $('.ilightbox-overlay, .ilightbox-holder, .ilightbox-thumbnails'), 9508 delay = false; 9509 9510 if (opts.controls.mousewheel) switchers.on('mousewheel.iLightBox', function(event, delta) { 9511 event.preventDefault(); 9512 if (delay) return; 9513 delay = true; 9514 if (!vars.lockWheel) { 9515 event.preventDefault(); 9516 if (delta < 0) { 9517 iL.moveTo('next'); 9518 } else if (delta > 0) { 9519 iL.moveTo('prev'); 9520 } 9521 } 9522 setTimeout(function(){
9523 delay = false; 9524 }, 2000); 9525 }); 9526 9527 if (opts.controls.swipe) holders.on(touchStartEvent, function(event) { 9528 if (vars.nextLock || vars.prevLock || vars.total == 1 || vars.lockSwipe) return; 9529 9530 vars.BODY.addClass('ilightbox-closedhand'); 9531 9532 var data = event.originalEvent.touches ? event.originalEvent.touches[0] : event, 9533 scrollTop = $doc.scrollTop(), 9534 scrollLeft = $doc.scrollLeft(), 9535 offsets = [ 9536 holders.eq(0).offset(), 9537 holders.eq(1).offset(), 9538 holders.eq(2).offset() 9539 ], 9540 offSet = [{ 9541 top: offsets[0].top - scrollTop, 9542 left: offsets[0].left - scrollLeft 9543 }, { 9544 top: offsets[1].top - scrollTop, 9545 left: offsets[1].left - scrollLeft 9546 }, { 9547 top: offsets[2].top - scrollTop, 9548 left: offsets[2].left - scrollLeft 9549 }], 9550 start = { 9551 time: (new Date()).getTime(), 9552 coords: [data.pageX - scrollLeft, data.pageY - scrollTop] 9553 }, 9554 stop; 9555 9556 function moveEachHandler(i) { 9557 var t = $(this), 9558 offset = offSet[i], 9559 scroll = [(start.coords[0] - stop.coords[0]), (start.coords[1] - stop.coords[1])]; 9560 9561 t[0].style[path == "horizontal" ? 'left' : 'top'] = (path == "horizontal" ? offset.left - scroll[0] : offset.top - scroll[1]) + 'px'; 9562 } 9563 9564 function moveHandler(event) { 9565 9566 if (!start) return; 9567 9568 var data = event.originalEvent.touches ? event.originalEvent.touches[0] : event; 9569 9570 stop = { 9571 time: (new Date()).getTime(), 9572 coords: [data.pageX - scrollLeft, data.pageY - scrollTop] 9573 }; 9574 9575 holders.each(moveEachHandler); 9576 9577 // prevent scrolling 9578 event.preventDefault(); 9579 } 9580 9581 function repositionHolders() { 9582 holders.each(function() { 9583 var t = $(this), 9584 offset = t.data('offset') || { 9585 top: t.offset().top - scrollTop, 9586 left: t.offset().left - scrollLeft 9587 }, 9588 top = offset.top, 9589 left = offset.left; 9590 9591 t.css(transform, gpuAcceleration).stop().animate({ 9592 top: top, 9593 left: left 9594 }, 500, 'easeOutCirc', function() { 9595 t.css(transform, ''); 9596 }); 9597 }); 9598 } 9599 9600 holders.bind(touchMoveEvent, moveHandler); 9601 $doc.one(touchStopEvent, function(event) { 9602 holders.unbind(touchMoveEvent, moveHandler); 9603 9604 vars.BODY.removeClass('ilightbox-closedhand'); 9605 9606 if (start && stop) { 9607 if (path == "horizontal" && stop.time - start.time < durationThreshold && abs(start.coords[0] - stop.coords[0]) > horizontalDistanceThreshold && abs(start.coords[1] - stop.coords[1]) < verticalDistanceThreshold) { 9608 if (start.coords[0] > stop.coords[0]) { 9609 if (vars.current == vars.total - 1 && !opts.infinite) repositionHolders(); 9610 else { 9611 vars.isSwipe = true; 9612 iL.moveTo('next'); 9613 } 9614 } else { 9615 if (vars.current == 0 && !opts.infinite) repositionHolders(); 9616 else { 9617 vars.isSwipe = true; 9618 iL.moveTo('prev'); 9619 } 9620 } 9621 } 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) { 9622 if (start.coords[1] > stop.coords[1]) { 9623 if (vars.current == vars.total - 1 && !opts.infinite) repositionHolders(); 9624 else { 9625 vars.isSwipe = true; 9626 iL.moveTo('next'); 9627 } 9628 } else { 9629 if (vars.current == 0 && !opts.infinite) repositionHolders(); 9630 else { 9631 vars.isSwipe = true; 9632 iL.moveTo('prev'); 9633 } 9634 } 9635 } else repositionHolders(); 9636 } 9637 start = stop = undefined; 9638 }); 9639 }); 9640 9641 }, 9642 9643 goTo: function(index) { 9644 var iL = this, 9645 vars = iL.vars, 9646 opts = iL.options, 9647 diff = (index - vars.current); 9648 9649 if (opts.infinite) { 9650 if (index == vars.total - 1 && vars.current == 0) diff = -1; 9651 if (vars.current == vars.total - 1 && index == 0) diff = 1; 9652 } 9653 9654 if (diff == 1) iL.moveTo('next'); 9655 else if (diff == -1) iL.moveTo('prev'); 9656 else { 9657 9658 if (vars.nextLock || vars.prevLock) return false; 9659 9660 //Trigger the onBeforeChange callback 9661 if (typeof opts.callback.onBeforeChange == 'function') opts.callback.onBeforeChange.call(iL, iL.ui); 9662 9663 if (opts.linkId) { 9664 vars.hashLock = true; 9665 window.location.hash = opts.linkId + '/' + index; 9666 } 9667 9668 if (iL.items[index]) { 9669 if (!iL.items[index].options.mousewheel) vars.lockWheel = true; 9670 else iL.vars.lockWheel = false;
9671 9672 if (!iL.items[index].options.swipe) vars.lockSwipe = true; 9673 else vars.lockSwipe = false; 9674 } 9675 9676 $.each([vars.holder, vars.nextPhoto, vars.prevPhoto], function(key, val) { 9677 val.css(transform, gpuAcceleration).fadeOut(opts.effects.loadedFadeSpeed); 9678 }); 9679 9680 vars.current = index; 9681 vars.next = index + 1; 9682 vars.prev = index - 1; 9683 9684 iL.createUI(); 9685 9686 setTimeout(function() { 9687 iL.generateBoxes(); 9688 }, opts.effects.loadedFadeSpeed + 50); 9689 9690 $('.ilightbox-thumbnail', vars.thumbnails).removeClass('ilightbox-active').eq(index).addClass('ilightbox-active'); 9691 iL.positionThumbnails(); 9692 9693 if (opts.linkId) setTimeout(function() { 9694 vars.hashLock = false; 9695 }, 55); 9696 9697 // Configure arrow buttons 9698 if (!opts.infinite) { 9699 vars.nextButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled'); 9700 9701 if (vars.current == 0) { 9702 vars.prevButton.add(vars.innerPrevButton).addClass('disabled'); 9703 } 9704 if (vars.current >= vars.total - 1) { 9705 vars.nextButton.add(vars.innerNextButton).addClass('disabled'); 9706 } 9707 } 9708 9709 // Reset next cycle timeout 9710 iL.resetCycle(); 9711 9712 //Trigger the onAfterChange callback 9713 if (typeof opts.callback.onAfterChange == 'function') opts.callback.onAfterChange.call(iL, iL.ui); 9714 } 9715 }, 9716 9717 moveTo: function(side) { 9718 var iL = this, 9719 vars = iL.vars, 9720 opts = iL.options, 9721 path = opts.path.toLowerCase(), 9722 viewport = getViewport(), 9723 switchSpeed = opts.effects.switchSpeed; 9724 9725 if (vars.nextLock || vars.prevLock) return false; 9726 else { 9727 9728 var item = (side == "next") ? vars.next : vars.prev; 9729 9730 if (opts.linkId) { 9731 vars.hashLock = true; 9732 window.location.hash = opts.linkId + '/' + item; 9733 } 9734 9735 if (side == "next") { 9736 if (!iL.items[item]) return false; 9737 var firstHolder = vars.nextPhoto, 9738 secondHolder = vars.holder, 9739 lastHolder = vars.prevPhoto, 9740 firstClass = 'ilightbox-prev', 9741 secondClass = 'ilightbox-next'; 9742 } else if (side == "prev") { 9743 if (!iL.items[item]) return false; 9744 var firstHolder = vars.prevPhoto, 9745 secondHolder = vars.holder, 9746 lastHolder = vars.nextPhoto, 9747 firstClass = 'ilightbox-next', 9748 secondClass = 'ilightbox-prev'; 9749 } 9750 9751 //Trigger the onBeforeChange callback 9752 if (typeof opts.callback.onBeforeChange == 'function') 9753 opts.callback.onBeforeChange.call(iL, iL.ui); 9754 9755 (side == "next") ? vars.nextLock = true: vars.prevLock = true; 9756 9757 var captionFirst = $('div.ilightbox-caption', secondHolder), 9758 socialFirst = $('div.ilightbox-social', secondHolder); 9759 9760 if (captionFirst.length) 9761 captionFirst.stop().fadeOut(switchSpeed, function() { 9762 $(this).remove(); 9763 }); 9764 if (socialFirst.length) 9765 socialFirst.stop().fadeOut(switchSpeed, function() { 9766 $(this).remove(); 9767 }); 9768 9769 if (iL.items[item].caption) { 9770 iL.setCaption(iL.items[item], firstHolder); 9771 var caption = $('div.ilightbox-caption', firstHolder), 9772 percent = parseInt((caption.outerHeight() / firstHolder.outerHeight()) * 100); 9773 if (opts.caption.start && percent <= 50) caption.fadeIn(switchSpeed); 9774 } 9775 9776 var social = iL.items[item].options.social; 9777 if (social) { 9778 iL.setSocial(social, iL.items[item].URL, firstHolder); 9779 if (opts.social.start) $('div.ilightbox-social', firstHolder).fadeIn(opts.effects.fadeSpeed); 9780 } 9781 9782 $.each([firstHolder, secondHolder, lastHolder], function(key, val) { 9783 val.removeClass('ilightbox-next ilightbox-prev'); 9784 }); 9785 9786 var firstOffset = firstHolder.data('offset'), 9787 winW = (viewport.width - (opts.styles.pageOffsetX)), 9788 winH = (viewport.height - (opts.styles.pageOffsetY)), 9789 width = firstOffset.newDims.width, 9790 height = firstOffset.newDims.height, 9791 thumbsOffset = firstOffset.thumbsOffset, 9792 diff = firstOffset.diff, 9793 top = parseInt((winH / 2) - (height / 2) - diff.H - (thumbsOffset.H / 2)), 9794 left = parseInt((winW / 2) - (width / 2) - diff.W - (thumbsOffset.W / 2)); 9795 9796 var secondOffset = secondHolder.data('offset'), 9797 object = secondOffset.object; 9798 9799 /*if (object.item.caption && !isNaN(width) && !isNaN(height) && UNCODE.wwidth > UNCODE.mediaQuery) { 9800 var objRatio = width / height; 9801 height = height - vars.captionHeight; 9802 width = height * objRatio; 9803 top = path == 'horizontal' ? parseInt((winH / 2) - (height / 2) - diff.H - (thumbsOffset.H / 2)) : top, 9804 left = parseInt((winW / 2) - (width / 2) - diff.W - (thumbsOffset.W / 2)); 9805 }*/ 9806 9807 firstHolder.show().css(transform, gpuAcceleration).animate({ 9808 top: top, 9809 left: left, 9810 opacity: 1 9811 }, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc', function() { 9812 firstHolder.css(transform, ''); 9813 }); 9814 9815 $('div.ilightbox-container', firstHolder).animate({ 9816 width: width, 9817 height: height 9818 }, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc'); 9819 9820 diff = secondOffset.diff; 9821 9822 width = secondOffset.newDims.width, 9823 height = secondOffset.newDims.height; 9824 9825 width = parseInt(width * opts.styles[side == 'next' ? 'prevScale' : 'nextScale']), 9826 height = parseInt(height * opts.styles[side == 'next' ? 'prevScale' : 'nextScale']), 9827 top = (path == 'horizontal') ? parseInt((winH / 2) - object.offsetY - (height / 2) - diff.H - (thumbsOffset.H / 2)) : parseInt(winH - object.offsetX - diff.H - (thumbsOffset.H / 2)); 9828 9829 if (side == 'prev') 9830 left = (path == 'horizontal') ? parseInt(winW - object.offsetX - diff.W - (thumbsOffset.W / 2)) : parseInt((winW / 2) - (width / 2) - diff.W - object.offsetY - (thumbsOffset.W / 2)); 9831 else { 9832 top = (path == 'horizontal') ? top : parseInt(object.offsetX - diff.H - height - (thumbsOffset.H / 2)), 9833 left = (path == 'horizontal') ? parseInt(object.offsetX - diff.W - width - (thumbsOffset.W / 2)) : parseInt((winW / 2) - object.offsetY - (width / 2) - diff.W - (thumbsOffset.W / 2)); 9834 } 9835 9836 /*if (object.item.caption && !isNaN(width) && !isNaN(height) && UNCODE.wwidth > UNCODE.mediaQuery) { 9837 var objRatio = width / height; 9838 height = height - vars.captionHeight; 9839 width = height * objRatio; 9840 top = path == 'horizontal' ? parseInt((winH / 2) - (height / 2) - diff.H - (thumbsOffset.H / 2)) : top; 9841 }*/ 9842 9843 $('div.ilightbox-container', secondHolder).animate({ 9844 width: width, 9845 height: height 9846 }, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc'); 9847 9848 secondHolder.addClass(firstClass).css(transform, gpuAcceleration).animate({ 9849 top: top, 9850 left: left, 9851 opacity: opts.styles.prevOpacity, 9852 }, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc', function() { 9853 secondHolder.css(transform, ''); 9854
9855 $('.ilightbox-thumbnail', vars.thumbnails).removeClass('ilightbox-active').eq(item).addClass('ilightbox-active'); 9856 iL.positionThumbnails(); 9857 9858 if (iL.items[item]) { 9859 if (!iL.items[item].options.mousewheel) vars.lockWheel = true; 9860 else vars.lockWheel = false; 9861 9862 if (!iL.items[item].options.swipe) vars.lockSwipe = true; 9863 else vars.lockSwipe = false; 9864 } 9865 9866 vars.isSwipe = false; 9867 9868 // Remove iframe & video from previous slide 9869 if (['iframe', 'video'].indexOf(iL.items[vars.current].type) !== -1) { 9870 $('div.ilightbox-container', secondHolder).empty(); 9871 } 9872 9873 if (side == "next") { 9874 vars.nextPhoto = lastHolder, 9875 vars.prevPhoto = secondHolder, 9876 vars.holder = firstHolder; 9877 9878 vars.nextPhoto.hide(); 9879 9880 vars.next = vars.next + 1, 9881 vars.prev = vars.current, 9882 vars.current = vars.current + 1; 9883 9884 if (opts.infinite) { 9885 if (vars.current > vars.total - 1) vars.current = 0; 9886 if (vars.current == vars.total - 1) vars.next = 0; 9887 if (vars.current == 0) vars.prev = vars.total - 1; 9888 } 9889 9890 iL.createUI(); 9891 9892 if (!iL.items[vars.next]) 9893 vars.nextLock = false; 9894 else 9895 iL.loadContent(iL.items[vars.next], 'next'); 9896 } else { 9897 vars.prevPhoto = lastHolder; 9898 vars.nextPhoto = secondHolder; 9899 vars.holder = firstHolder; 9900 9901 vars.prevPhoto.hide(); 9902 9903 vars.next = vars.current; 9904 vars.current = vars.prev; 9905 vars.prev = vars.current - 1; 9906 9907 if (opts.infinite) { 9908 if (vars.current == vars.total - 1) vars.next = 0; 9909 if (vars.current == 0) vars.prev = vars.total - 1; 9910 } 9911 9912 iL.createUI(); 9913 9914 if (!iL.items[vars.prev]) 9915 vars.prevLock = false; 9916 else 9917 iL.loadContent(iL.items[vars.prev], 'prev'); 9918 } 9919 9920 // Add iframe & video content for current slide 9921 if (['iframe', 'video'].indexOf(iL.items[vars.current].type) !== -1) { 9922 iL.loadContent(iL.items[vars.current], 'current'); 9923 } 9924 9925 if (opts.linkId) setTimeout(function() { 9926 vars.hashLock = false; 9927 }, 55); 9928 9929 // Configure arrow buttons 9930 if (!opts.infinite) { 9931 vars.nextButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled'); 9932 9933 if (vars.current == 0) 9934 vars.prevButton.add(vars.innerPrevButton).addClass('disabled'); 9935 if (vars.current >= vars.total - 1) 9936 vars.nextButton.add(vars.innerNextButton).addClass('disabled'); 9937 } 9938 9939 iL.repositionPhoto(); 9940 9941 // Reset next cycle timeout 9942 iL.resetCycle(); 9943 9944 //Trigger the onAfterChange callback 9945 if (typeof opts.callback.onAfterChange == 'function') 9946 opts.callback.onAfterChange.call(iL, iL.ui); 9947 }); 9948 9949 top = (path == 'horizontal') ? getPixel(lastHolder, 'top') : ((side == "next") ? parseInt(-(winH / 2) - lastHolder.outerHeight()) : parseInt(top * 2)), 9950 left = (path == 'horizontal') ? ((side == "next") ? parseInt(-(winW / 2) - lastHolder.outerWidth()) : parseInt(left * 2)) : getPixel(lastHolder, 'left'); 9951 9952 lastHolder.css(transform, gpuAcceleration).animate({ 9953 top: top, 9954 left: left, 9955 opacity: opts.styles.nextOpacity 9956 }, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc', function() { 9957 lastHolder.css(transform, ''); 9958 }).addClass(secondClass); 9959 } 9960 }, 9961 9962 setCaption: function(obj, target) { 9963 var iL = this, 9964 caption = $('<div class="ilightbox-caption"></div>'); 9965 9966 if (obj.caption) { 9967 caption.html(obj.caption); 9968 $('div.ilightbox-container', target).append(caption); 9969 } 9970 }, 9971 9972 normalizeSocial: function(obj, url) { 9973 var iL = this, 9974 vars = iL.vars, 9975 opts = iL.options, 9976 baseURL = window.location.href; 9977 9978 $.each(obj, function(key, value) { 9979 if (!value) 9980 return true; 9981 9982 var item = key.toLowerCase(), 9983 source, text; 9984 9985 switch (item) { 9986 case 'facebook': 9987 source = "http://www.facebook.com/share.php?v=4&src=bm&u={URL}", 9988 text = "Share on Facebook"; 9989 break; 9990 case 'twitter': 9991 source = "http://twitter.com/home?status={URL}", 9992 text = "Share on Twitter"; 9993 break; 9994 case 'googleplus': 9995 source = "https://plus.google.com/share?url={URL}", 9996 text = "Share on Google+"; 9997 break; 9998 case 'delicious': 9999 source = "http://delicious.com/post?url={URL}", 10000 text = "Share on Delicious"; 10001 break; 10002 case 'digg': 10003 source = "http://digg.com/submit?phase=2&url={URL}", 10004 text = "Share on Digg"; 10005 break; 10006 case 'reddit': 10007 source = "http://reddit.com/submit?url={URL}", 10008 text = "Share on reddit"; 10009 break; 10010 } 10011 10012 obj[key] = { 10013 URL: value.URL && absolutizeURI(baseURL, value.URL) || opts.linkId && window.location.href || typeof url !== 'string' && baseURL || url && absolutizeURI(baseURL, url) || baseURL, 10014 source: value.source || source || value.URL && absolutizeURI(baseURL, value.URL) || url && absolutizeURI(baseURL, url), 10015 text: value.text || text || "Share on " + key, 10016 width: (typeof(value.width) != 'undefined' && !isNaN(value.width)) ? parseInt(value.width) : 640, 10017 height: value.height || 360 10018 }; 10019 10020 }); 10021 10022 return obj; 10023 }, 10024 10025 setSocial: function(obj, url, target) { 10026 var iL = this, 10027 socialBar = $('<div class="ilightbox-social"></div>'), 10028 buttons = '<ul>'; 10029 10030 obj = iL.normalizeSocial(obj, url); 10031 10032 $.each(obj, function(key, value) { 10033 var item = key.toLowerCase(), 10034 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, '+')); 10035 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>'; 10036 }); 10037 10038 buttons += '</ul>'; 10039 10040 socialBar.html(buttons); 10041 $('div.ilightbox-container', target).append(socialBar); 10042 }, 10043 10044 fullScreenAction: function() { 10045 var iL = this, 10046 vars = iL.vars; 10047 10048 if (fullScreenApi.supportsFullScreen) { 10049 if (fullScreenApi.isFullScreen()) fullScreenApi.cancelFullScreen(document.documentElement); 10050 else fullScreenApi.requestFullScreen(document.documentElement); 10051 } else { 10052 iL.doFullscreen(); 10053 } 10054 }, 10055 10056 doFullscreen: function() { 10057 var iL = this, 10058 vars = iL.vars, 10059 viewport = getViewport(), 10060 opts = iL.options; 10061 10062 if (opts.fullAlone) { 10063 var currentHolder = vars.holder, 10064 current = iL.items[vars.current], 10065 windowWidth = viewport.width, 10066 windowHeight = viewport.height, 10067 elements = [currentHolder, vars.nextPhoto, vars.prevPhoto, vars.nextButton, vars.prevButton, vars.overlay, vars.toolbar, vars.thumbnails, vars.loader], 10068 hideElements = [vars.nextPhoto, vars.prevPhoto, vars.nextButton, vars.prevButton, vars.loader, vars.thumbnails]; 10069 10070 if (!vars.isInFullScreen) { 10071 vars.isInFullScreen = vars.lockKey = vars.lockWheel = vars.lockSwipe = true; 10072 vars.overlay.css({ 10073 opacity: 1 10074 }); 10075 10076 $.each(hideElements, function(i, element) { 10077 element.hide(); 10078 }); 10079 10080 vars.fullScreenButton.attr('title', opts.text.exitFullscreen); 10081 10082 if (opts.fullStretchTypes.indexOf(current.type) != -1) currentHolder.data({
10083 naturalWidthOld: currentHolder.data('naturalWidth'), 10084 naturalHeightOld: currentHolder.data('naturalHeight'), 10085 naturalWidth: windowWidth, 10086 naturalHeight: windowHeight 10087 }); 10088 else { 10089 var viewport = current.options.fullViewPort || opts.fullViewPort || '', 10090 newWidth = windowWidth, 10091 newHeight = windowHeight, 10092 width = currentHolder.data('naturalWidth'), 10093 height = currentHolder.data('naturalHeight'); 10094 10095 if (viewport.toLowerCase() == 'fill') { 10096 newHeight = (newWidth / width) * height; 10097 10098 if (newHeight < windowHeight) { 10099 newWidth = (windowHeight / height) * width, 10100 newHeight = windowHeight; 10101 } 10102 } else if (viewport.toLowerCase() == 'fit') { 10103 var dims = iL.getNewDimenstions(newWidth, newHeight, width, height, true); 10104 10105 newWidth = dims.width, 10106 newHeight = dims.height; 10107 } else if (viewport.toLowerCase() == 'stretch') { 10108 newWidth = newWidth, 10109 newHeight = newHeight; 10110 } else { 10111 var scale = (width > newWidth || height > newHeight) ? true : false, 10112 dims = iL.getNewDimenstions(newWidth, newHeight, width, height, scale); 10113 newWidth = dims.width, 10114 newHeight = dims.height; 10115 } 10116 10117 currentHolder.data({ 10118 naturalWidthOld: currentHolder.data('naturalWidth'), 10119 naturalHeightOld: currentHolder.data('naturalHeight'), 10120 naturalWidth: newWidth, 10121 naturalHeight: newHeight 10122 }); 10123 } 10124 10125 $.each(elements, function(key, val) { 10126 val.addClass('ilightbox-fullscreen'); 10127 }); 10128 10129 //Trigger the onEnterFullScreen callback 10130 if (typeof opts.callback.onEnterFullScreen == 'function') opts.callback.onEnterFullScreen.call(iL, iL.ui); 10131 } else { 10132 vars.isInFullScreen = vars.lockKey = vars.lockWheel = vars.lockSwipe = false; 10133 vars.overlay.css({ 10134 opacity: iL.options.overlay.opacity 10135 }); 10136 10137 $.each(hideElements, function(i, element) { 10138 element.show(); 10139 }); 10140 10141 vars.fullScreenButton.attr('title', opts.text.enterFullscreen); 10142 10143 currentHolder.data({ 10144 naturalWidth: currentHolder.data('naturalWidthOld'), 10145 naturalHeight: currentHolder.data('naturalHeightOld'), 10146 naturalWidthOld: null, 10147 naturalHeightOld: null 10148 }); 10149 10150 $.each(elements, function(key, val) { 10151 val.removeClass('ilightbox-fullscreen'); 10152 }); 10153 10154 //Trigger the onExitFullScreen callback 10155 if (typeof opts.callback.onExitFullScreen == 'function') opts.callback.onExitFullScreen.call(iL, iL.ui); 10156 } 10157 } else { 10158 if (!vars.isInFullScreen) vars.isInFullScreen = true; 10159 else vars.isInFullScreen = false; 10160 } 10161 iL.repositionPhoto(true); 10162 }, 10163 10164 closeAction: function() { 10165 var iL = this, 10166 vars = iL.vars, 10167 opts = iL.options; 10168 10169 $win.unbind('.iLightBox'); 10170 $doc.off('.iLightBox'); 10171 10172 if (vars.isInFullScreen) fullScreenApi.cancelFullScreen(document.documentElement); 10173 10174 $('.ilightbox-overlay, .ilightbox-holder, .ilightbox-thumbnails').off('.iLightBox'); 10175 10176 if (opts.hide.effect) vars.overlay.stop().fadeOut(opts.hide.speed, function() { 10177 vars.overlay.remove(); 10178 vars.BODY.removeClass('ilightbox-noscroll').off('.iLightBox'); 10179 }); 10180 else { 10181 vars.overlay.remove(); 10182 vars.BODY.removeClass('ilightbox-noscroll').off('.iLightBox'); 10183 } 10184 10185 var fadeOuts = [vars.toolbar, vars.holder, vars.nextPhoto, vars.prevPhoto, vars.nextButton, vars.prevButton, vars.loader, vars.thumbnails]; 10186 10187 $.each(fadeOuts, function(i, element) { 10188 element.removeAttr('style').remove(); 10189 }); 10190 10191 vars.dontGenerateThumbs = vars.isInFullScreen = false; 10192 10193 window.iLightBox = null; 10194 10195 if (opts.linkId) { 10196 vars.hashLock = true; 10197 removeHash(); 10198 setTimeout(function() { 10199 vars.hashLock = false; 10200 }, 55); 10201 } 10202 10203 vars.nextButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled'); 10204 10205 //Trigger the onHide callback 10206 if (typeof opts.callback.onHide == 'function') opts.callback.onHide.call(iL, iL.ui); 10207 }, 10208 10209 repositionPhoto: function() { 10210 var iL = this, 10211 vars = iL.vars, 10212 opts = iL.options, 10213 path = opts.path.toLowerCase(), 10214 viewport = getViewport(), 10215 winWidth = viewport.width, 10216 winHeight = viewport.height; 10217 10218 if (viewport.width < UNCODE.mediaQuery) opts.styles.nextOffsetX = 0; 10219 10220 var thumbsOffsetW = (vars.isInFullScreen && opts.fullAlone || vars.isMobile) ? 0 : ((path == 'horizontal') ? 0 : vars.thumbnails.outerWidth()), 10221 thumbsOffsetH = vars.isMobile ? vars.toolbar.outerHeight() : ((vars.isInFullScreen && opts.fullAlone) ? 0 : ((path == 'horizontal') ? vars.thumbnails.outerHeight() : 0)), 10222 width = (vars.isInFullScreen && opts.fullAlone) ? winWidth : (winWidth - (opts.styles.pageOffsetX)), 10223 height = (vars.isInFullScreen && opts.fullAlone) ? winHeight : (winHeight - (opts.styles.pageOffsetY)), 10224 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, 10225 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))); 10226 10227 var elObject = { 10228 type: 'current', 10229 width: width, 10230 height: height, 10231 item: iL.items[vars.current], 10232 offsetW: offsetW, 10233 offsetH: offsetH,
10234 thumbsOffsetW: thumbsOffsetW, 10235 thumbsOffsetH: thumbsOffsetH, 10236 animate: arguments.length, 10237 holder: vars.holder 10238 }; 10239 10240 iL.repositionEl(elObject); 10241 10242 if (iL.items[vars.next]) { 10243 elObject = $.extend(elObject, { 10244 type: 'next', 10245 item: iL.items[vars.next], 10246 offsetX: opts.styles.nextOffsetX, 10247 offsetY: opts.styles.nextOffsetY, 10248 holder: vars.nextPhoto 10249 }); 10250 10251 iL.repositionEl(elObject); 10252 } 10253 10254 if (iL.items[vars.prev]) { 10255 elObject = $.extend(elObject, { 10256 type: 'prev', 10257 item: iL.items[vars.prev], 10258 offsetX: opts.styles.nextOffsetX, 10259 offsetY: opts.styles.prevOffsetY, 10260 holder: vars.prevPhoto 10261 }); 10262 10263 iL.repositionEl(elObject); 10264 } 10265 10266 var loaderCss = (path == "horizontal") ? { 10267 left: parseInt((width / 2) - (vars.loader.outerWidth() / 2)) 10268 } : { 10269 top: parseInt((height / 2) - (vars.loader.outerHeight() / 2)) 10270 }; 10271 vars.loader.css(loaderCss); 10272 }, 10273 10274 repositionEl: function(obj) { 10275 var iL = this, 10276 vars = iL.vars, 10277 opts = iL.options, 10278 path = opts.path.toLowerCase(), 10279 widthAvail = (obj.type == 'current') ? ((vars.isInFullScreen && opts.fullAlone) ? obj.width : (obj.width - obj.offsetW)) : (obj.width - obj.offsetW), 10280 heightAvail = (obj.type == 'current') ? ((vars.isInFullScreen && opts.fullAlone) ? obj.height : (obj.height - obj.offsetH)) : (obj.height - obj.offsetH), 10281 itemParent = obj.item, 10282 item = obj.item.options, 10283 holder = obj.holder, 10284 offsetX = obj.offsetX || 0, 10285 offsetY = obj.offsetY || 0, 10286 //Uncode change ##START## 10287 toolbarHeight = $('.ilightbox-inner-toolbar', holder).length ? parseInt( $('.ilightbox-inner-toolbar', holder).outerHeight() ) : 0, 10288 //Uncode change ##END## 10289 thumbsOffsetW = obj.thumbsOffsetW, 10290 thumbsOffsetH = obj.thumbsOffsetH; 10291 10292 if (obj.type == 'current') { 10293 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); 10294 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); 10295 } else { 10296 if (typeof item.width == 'number' && item.width) widthAvail = (item.width > widthAvail) ? widthAvail : item.width; 10297 if (typeof item.height == 'number' && item.height) heightAvail = (item.height > heightAvail) ? heightAvail : item.height; 10298 } 10299 10300 10301 //Uncode change ##START## 10302 heightAvail = parseInt(heightAvail - toolbarHeight); 10303 // heightAvail = parseInt(heightAvail - $('.ilightbox-inner-toolbar', holder).outerHeight()); 10304 //Uncode change ##END## 10305 10306 var width = (typeof item.width == 'string' && item.width.indexOf('%') != -1) ? percentToValue(parseInt(item.width.replace('%', '')), obj.width) : holder.data('naturalWidth'), 10307 height = (typeof item.height == 'string' && item.height.indexOf('%') != -1) ? percentToValue(parseInt(item.height.replace('%', '')), obj.height) : holder.data('naturalHeight'); 10308 10309 var dims = ((typeof item.width == 'string' && item.width.indexOf('%') != -1 || typeof item.height == 'string' && item.height.indexOf('%') != -1) ? { 10310 width: width, 10311 height: height 10312 } : iL.getNewDimenstions(widthAvail, heightAvail, width, height)), 10313 newDims = $.extend({}, dims, {}); 10314 10315 if (obj.type == 'prev' || obj.type == 'next') 10316 width = parseInt(dims.width * ((obj.type == 'next') ? opts.styles.nextScale : opts.styles.prevScale)), 10317 height = parseInt(dims.height * ((obj.type == 'next') ? opts.styles.nextScale : opts.styles.prevScale)); 10318 else 10319 width = dims.width, 10320 height = dims.height; 10321 10322 var widthDiff = parseInt((getPixel(holder, 'padding-left') + getPixel(holder, 'padding-right') + getPixel(holder, 'border-left-width') + getPixel(holder, 'border-right-width')) / 2), 10323 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); 10324 10325 switch (obj.type) { 10326 case 'current': 10327 var top = parseInt((obj.height / 2) - (height / 2) - heightDiff - (thumbsOffsetH / 2)), 10328 left = parseInt((obj.width / 2) - (width / 2) - widthDiff - (thumbsOffsetW / 2)); 10329 break; 10330
10331 case 'next': 10332 var top = (path == 'horizontal') ? parseInt((obj.height / 2) - offsetY - (height / 2) - heightDiff - (thumbsOffsetH / 2)) : parseInt(obj.height - offsetX - heightDiff - (thumbsOffsetH / 2)), 10333 left = (path == 'horizontal') ? parseInt(obj.width - offsetX - widthDiff - (thumbsOffsetW / 2)) : parseInt((obj.width / 2) - (width / 2) - widthDiff - offsetY - (thumbsOffsetW / 2)); 10334 break; 10335 10336 case 'prev': 10337 var top = (path == 'horizontal') ? parseInt((obj.height / 2) - offsetY - (height / 2) - heightDiff - (thumbsOffsetH / 2)) : parseInt(offsetX - heightDiff - height - (thumbsOffsetH / 2)), 10338 left = (path == 'horizontal') ? parseInt(offsetX - widthDiff - width - (thumbsOffsetW / 2)) : parseInt((obj.width / 2) - offsetY - (width / 2) - widthDiff - (thumbsOffsetW / 2)); 10339 break; 10340 } 10341 10342 holder.data('offset', { 10343 top: top, 10344 left: left, 10345 newDims: newDims, 10346 diff: { 10347 W: widthDiff, 10348 H: heightDiff 10349 }, 10350 thumbsOffset: { 10351 W: thumbsOffsetW, 10352 H: thumbsOffsetH 10353 }, 10354 object: obj 10355 }); 10356 10357 var opacityMobile; 10358 if ( isMobile ) { 10359 opacityMobile = { 10360 opacity: 1, 10361 top: top, 10362 left: left 10363 }; 10364 } else { 10365 opacityMobile = { 10366 top: top, 10367 left: left 10368 }; 10369 } 10370 10371 if (obj.animate > 0 && opts.effects.reposition) { 10372 holder.css(transform, gpuAcceleration).stop().animate( 10373 opacityMobile, 10374 opts.effects.repositionSpeed, 'easeOutCirc', function() { 10375 holder.css(transform, ''); 10376 }); 10377 $('div.ilightbox-container', holder).stop().animate({ 10378 width: width, 10379 height: height 10380 }, opts.effects.repositionSpeed, 'easeOutCirc'); 10381 $('div.ilightbox-inner-toolbar', holder).stop().animate({ 10382 width: width 10383 }, opts.effects.repositionSpeed, 'easeOutCirc', function() { 10384 $(this).css('overflow', 'visible'); 10385 }); 10386 } else { 10387 holder.css(opacityMobile); 10388 $('div.ilightbox-container', holder).css({ 10389 width: width, 10390 height: height 10391 }); 10392 $('div.ilightbox-inner-toolbar', holder).css({ 10393 width: width 10394 }); 10395 } 10396 }, 10397 10398 10399 resume: function(priority) { 10400 var iL = this, 10401 vars = iL.vars, 10402 opts = iL.options; 10403 10404 if (!opts.slideshow.pauseTime || opts.controls.slideshow && vars.total <= 1 || priority < vars.isPaused) { 10405 return; 10406 } 10407 10408 vars.isPaused = 0; 10409 10410 if (vars.cycleID) { 10411 vars.cycleID = clearTimeout(vars.cycleID); 10412 } 10413 10414 vars.cycleID = setTimeout(function() { 10415 if (vars.current == vars.total - 1) iL.goTo(0); 10416 else iL.moveTo('next'); 10417 }, opts.slideshow.pauseTime); 10418 }, 10419 10420 pause: function(priority) { 10421 var iL = this, 10422 vars = iL.vars, 10423 opts = iL.options; 10424 10425 if (priority < vars.isPaused) { 10426 return; 10427 } 10428 10429 vars.isPaused = priority || 100; 10430 10431 if (vars.cycleID) { 10432 vars.cycleID = clearTimeout(vars.cycleID); 10433 } 10434 }, 10435 10436 resetCycle: function() { 10437 var iL = this, 10438 vars = iL.vars, 10439 opts = iL.options; 10440 10441 if (opts.controls.slideshow && vars.cycleID && !vars.isPaused) { 10442 iL.resume(); 10443 } 10444 }, 10445 10446 getNewDimenstions: function(width, height, width_old, height_old, thumb) { 10447 var iL = this; 10448 10449 if (!width) factor = height / height_old; 10450 else if (!height) factor = width / width_old; 10451 else factor = min(width / width_old, height / height_old); 10452 10453 if (!thumb) { 10454 if (factor > iL.options.maxScale) factor = iL.options.maxScale; 10455 else if (factor < iL.options.minScale) factor = iL.options.minScale; 10456 } 10457 10458 var final_width = (iL.options.keepAspectRatio) ? round(width_old * factor) : width, 10459 final_height = (iL.options.keepAspectRatio) ? round(height_old * factor) : height; 10460 10461 return { 10462 width: final_width, 10463 height: final_height, 10464 ratio: factor 10465 }; 10466 }, 10467 10468 setOption: function(options) { 10469 var iL = this; 10470 10471 iL.options = $.extend(true, iL.options, options || {}); 10472 iL.refresh(); 10473 }, 10474 10475 availPlugins: function() { 10476 var iL = this, 10477 testEl = document.createElement("video"); 10478 10479 iL.plugins = { 10480 flash: !isMobile, 10481 quicktime: (parseInt(PluginDetect.getVersion("QuickTime")) >= 0) ? true : false, 10482 html5H264: !!(testEl.canPlayType && testEl.canPlayType('video/mp4').replace(/no/, '')), 10483 html5WebM: !!(testEl.canPlayType && testEl.canPlayType('video/webm').replace(/no/, '')), 10484 html5Vorbis: !!(testEl.canPlayType && testEl.canPlayType('video/ogg').replace(/no/, '')), 10485 html5QuickTime: !!(testEl.canPlayType && testEl.canPlayType('video/quicktime').replace(/no/, '')) 10486 }; 10487 }, 10488 10489 addContent: function(element, obj) { 10490 var iL = this, 10491 el; 10492 10493 switch (obj.type) { 10494 case 'video': 10495 var HTML5 = false, 10496 videoType = obj.videoType, 10497 html5video = obj.options.html5video; 10498 10499 if (((videoType == 'video/mp4' || obj.ext == 'mp4' || obj.ext == 'm4v') || html5video.h264) && iL.plugins.html5H264) 10500 obj.ext = 'mp4', 10501 obj.URL = html5video.h264 || obj.URL; 10502 else if (html5video.webm && iL.plugins.html5WebM) 10503 obj.ext = 'webm', 10504 obj.URL = html5video.webm || obj.URL; 10505 else if (html5video.ogg && iL.plugins.html5Vorbis) 10506 obj.ext = 'ogv', 10507 obj.URL = html5video.ogg || obj.URL; 10508 10509 if (iL.plugins.html5H264 && (videoType == 'video/mp4' || obj.ext == 'mp4' || obj.ext == 'm4v')) HTML5 = true, videoType = "video/mp4"; 10510 else if (iL.plugins.html5WebM && (videoType == 'video/webm' || obj.ext == 'webm')) HTML5 = true, videoType = "video/webm"; 10511 else if (iL.plugins.html5Vorbis && (videoType == 'video/ogg' || obj.ext == 'ogv')) HTML5 = true, videoType = "video/ogg"; 10512 else if (iL.plugins.html5QuickTime && (videoType == 'video/quicktime' || obj.ext == 'mov' || obj.ext == 'qt')) HTML5 = true, videoType = "video/quicktime"; 10513 10514 if (HTML5) { 10515 el = $('<video />
10515', { 10516 "width": "100%", 10517 "height": "100%", 10518 "preload": html5video.preload, 10519 "autoplay": html5video.autoplay, 10520 "loop": html5video.loop, 10521 "poster": html5video.poster, 10522 "controls": html5video.controls, 10523 "controlslist": "nodownload" 10524 }).append($('<source />', { 10525 "src": obj.URL, 10526 "type": videoType 10527 })); 10528 } else { 10529 if (!iL.plugins.quicktime) el = $('<span />', { 10530 "class": "ilightbox-alert", 10531 html: iL.options.errors.missingPlugin.replace('{pluginspage}', pluginspages.quicktime).replace('{type}', 'QuickTime') 10532 }); 10533 else { 10534 10535 el = $('<object />', { 10536 "type": "video/quicktime", 10537 "pluginspage": pluginspages.quicktime 10538 }).attr({ 10539 "data": obj.URL, 10540 "width": "100%", 10541 "height": "100%" 10542 }).append($('<param />', { 10543 "name": "src", 10544 "value": obj.URL 10545 })).append($('<param />', { 10546 "name": "autoplay", 10547 "value": "false" 10548 })).append($('<param />', { 10549 "name": "loop", 10550 "value": "false" 10551 })).append($('<param />', { 10552 "name": "scale", 10553 "value": "tofit" 10554 })); 10555 10556 if (browser.msie) el = QT_GenerateOBJECTText(obj.URL, '100%', '100%', '', 'SCALE', 'tofit', 'AUTOPLAY', 'false', 'LOOP', 'false'); 10557 } 10558 } 10559 10560 break; 10561 10562 case 'flash': 10563 if (!iL.plugins.flash) el = $('<span />', { 10564 "class": "ilightbox-alert", 10565 html: iL.options.errors.missingPlugin.replace('{pluginspage}', pluginspages.flash).replace('{type}', 'Adobe Flash player') 10566 }); 10567 else { 10568 var flashvars = "", 10569 i = 0; 10570 10571 if (obj.options.flashvars) $.each(obj.options.flashvars, function(k, v) { 10572 if (i != 0) flashvars += "&"; 10573 flashvars += k + "=" + encodeURIComponent(v); 10574 i++; 10575 }); 10576 else flashvars = null; 10577 10578 el = $('<embed />').attr({ 10579 "type": "application/x-shockwave-flash", 10580 "src": obj.URL, 10581 "width": (typeof obj.options.width == 'number' && obj.options.width && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.width : "100%", 10582 "height": (typeof obj.options.height == 'number' && obj.options.height && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.height : "100%", 10583 "quality": "high", 10584 "bgcolor": "#000000", 10585 "play": "true", 10586 "loop": "true", 10587 "menu": "true", 10588 "wmode": "transparent", 10589 "scale": "showall", 10590 "allowScriptAccess": "always", 10591 "allowFullScreen": "true", 10592 "flashvars": flashvars, 10593 "fullscreen": "yes" 10594 }); 10595 } 10596 10597 break; 10598 10599 case 'iframe': 10600 el = $('<iframe />').attr({ 10601 "width": (typeof obj.options.width == 'number' && obj.options.width && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.width : "100%", 10602 "height": (typeof obj.options.height == 'number' && obj.options.height && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.height : "100%", 10603 src: obj.URL, 10604 frameborder: 0, 10605 'hspace': 0, 10606 'vspace': 0, 10607 'scrolling': supportTouch ? 'auto' : 'scroll', 10608 'webkitAllowFullScreen': '', 10609 'mozallowfullscreen': '', 10610 'allowFullScreen': '' 10611 }); 10612 10613 break; 10614 10615 case 'inline': 10616 el = $('<div class="ilightbox-wrapper"></div>').html($(obj.URL).clone(true)); 10617 10618 break; 10619 10620 case 'html': 10621 var object = obj.URL, 10622 el; 10623 10624 if (object[0].nodeName) { 10625 el = $('<div class="ilightbox-wrapper"></div>').html(object); 10626 } else { 10627 var dom = $(obj.URL), 10628 html = (dom.selector) ? $('<div>' + dom + '</div>') : dom; 10629 el = $('<div class="ilightbox-wrapper"></div>').html(html); 10630 } 10631 10632 break; 10633 } 10634 10635 $('div.ilightbox-container', element).empty().html(el); 10636 10637 // For fixing Chrome about just playing the video for first time 10638 if (el[0].tagName.toLowerCase() === 'video' && browser.webkit) setTimeout(function() { 10639 var src = el[0].currentSrc + '?' + floor(random() * 30000); 10640 el[0].currentSrc = src; 10641 el[0].src = src; 10642 }); 10643 10644 return el; 10645 }, 10646 10647 ogpRecognition: function(obj, callback) { 10648 var iL = this, 10649 url = obj.URL; 10650 10651 iL.showLoader(); 10652 doAjax(url, function(data) { 10653 iL.hideLoader(); 10654 if (data) { 10655 var object = new Object(); 10656 10657 object.length = false, 10658 object.url = data.url; 10659 10660 if (data.status == 200) { 10661 var result = data.results, 10662 type = result.type, 10663 source = result.source; 10664 10665 object.source = source.src, 10666 object.width = source.width && parseInt(source.width) || 0, 10667 object.height = source.height && parseInt(source.height) || 0, 10668 object.type = type, 10669 object.thumbnail = source.thumbnail || result.images && result.images[0], 10670 object.html5video = result.html5video || {}, 10671 object.length = true; 10672 10673 if (source.type == 'application/x-shockwave-flash') object.type = "flash"; 10674 else if (source.type.indexOf("video/") != -1) object.type = "video"; 10675 else if (source.type.indexOf("/html") != -1) object.type = "iframe"; 10676 else if (source.type.indexOf("image/") != -1) object.type = "image"; 10677 10678 } else if (typeof data.response != 'undefined') 10679 throw data.response; 10680 10681 callback.call(this, object.length ? object : false); 10682 } 10683 }); 10684 }, 10685 10686 hashChangeHandler: function(url) { 10687 var iL = this, 10688 vars = iL.vars, 10689 opts = iL.options, 10690 URL = url || window.location.href, 10691 hash = parseURI(URL).hash, 10692 split = hash.split('/'), 10693 index = split[1]; 10694 10695 if (vars.hashLock || ('#' + opts.linkId != split[0] && hash.length > 1)) return; 10696 10697 if (index) { 10698 var target = split[1] || 0; 10699 if (iL.items[target]) {
10700 var overlay = $('.ilightbox-overlay'); 10701 if (overlay.length && overlay.attr('linkid') == opts.linkId) { 10702 iL.goTo(target); 10703 } else { 10704 iL.itemsObject[target].trigger(ishybrid ? "itap click" : supportTouch ? 'itap' : 'click'); 10705 //iL.goTo(target); 10706 } 10707 } else { 10708 var overlay = $('.ilightbox-overlay'); 10709 if (overlay.length) iL.closeAction(); 10710 } 10711 } else { 10712 var overlay = $('.ilightbox-overlay'); 10713 if (overlay.length) iL.closeAction(); 10714 } 10715 } 10716 }; 10717 10718 /** 10719 * Parse style to pixels. 10720 * 10721 * @param {Object} $element jQuery object with element. 10722 * @param {Property} property CSS property to get the pixels from. 10723 * 10724 * @return {Int} 10725 */ 10726 function getPixel($element, property) { 10727 return parseInt($element.css(property), 10) || 0; 10728 } 10729 10730 /** 10731 * Make sure that number is within the limits. 10732 * 10733 * @param {Number} number 10734 * @param {Number} min 10735 * @param {Number} max 10736 * 10737 * @return {Number} 10738 */ 10739 function within(number, min, max) { 10740 return number < min ? min : number > max ? max : number; 10741 } 10742 10743 /** 10744 * Get viewport/window size (width and height). 10745 * 10746 * @return {Object} 10747 */ 10748 function getViewport() { 10749 var e = window, 10750 a = 'inner'; 10751 if (!('innerWidth' in window)) { 10752 a = 'client'; 10753 e = document.documentElement || document.body; 10754 } 10755 return { 10756 width: e[a + 'Width'], 10757 height: e[a + 'Height'] 10758 } 10759 } 10760 10761 /** 10762 * Remove hash tag from the URL 10763 * 10764 * @return {Void} 10765 */ 10766 function removeHash() { 10767 var scroll = getScrollXY(); 10768 10769 //UNCODE change 10770 //window.location.hash = ""; 10771 history.pushState("", document.title, window.location.pathname + window.location.search); 10772 10773 // Restore the scroll offset, should be flicker free 10774 window.scrollTo(scroll.x, scroll.y); 10775 } 10776 10777 /** 10778 * Do the ajax requests with callback. 10779 * 10780 * @param {String} url 10781 * @param {Function} callback 10782 * 10783 * @return {Void} 10784 */ 10785 function doAjax(url, callback) { 10786 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'); 10787 $.ajax({ 10788 url: url, 10789 dataType: 'jsonp' 10790 }); 10791 10792 iLCallback = function(data) { 10793 callback.call(this, data); 10794 }; 10795 } 10796 10797 /** 10798 * Find image from DOM elements 10799 * 10800 * @param {Element} element 10801 * 10802 * @return {Void} 10803 */ 10804 function findImageInElement(element) { 10805 var elements = $('*', element), 10806 imagesArr = new Array(); 10807 10808 elements.each(function() { 10809 var url = "", 10810 element = this; 10811 10812 if ($(element).css("background-image") != "none") { 10813 url = $(element).css("background-image"); 10814 } else if (typeof($(element).attr("src")) != "undefined" && element.nodeName.toLowerCase() == "img") { 10815 url = $(element).attr("src"); 10816 } 10817 10818 if (url.indexOf("gradient") == -1) { 10819 url = url.replace(/url\(\"/g, ""); 10820 url = url.replace(/url\(/g, ""); 10821 url = url.replace(/\"\)/g, ""); 10822 url = url.replace(/\)/g, ""); 10823 10824 var urls = url.split(","); 10825 10826 for (var i = 0; i < urls.length; i++) { 10827 if (urls[i].length > 0 && $.inArray(urls[i], imagesArr) == -1) { 10828 var extra = ""; 10829 if (browser.msie && browser.version < 9) { 10830 extra = "?" + floor(random() * 3000); 10831 } 10832 imagesArr.push(urls[i] + extra); 10833 } 10834 } 10835 } 10836 }); 10837 10838 return imagesArr; 10839 } 10840 10841 /** 10842 * Get file extension. 10843 * 10844 * @param {String} URL 10845 * 10846 * @return {String} 10847 */ 10848 function getExtension(URL) { 10849 if (URL !== null) { 10850 //UNCODE: fix issue to detect media type with query strings 10851 var ext = URL.indexOf('?') !== -1 ? URL.split('?')[0] : URL; 10852 ext = ext.split('.').pop().toLowerCase(); 10853 10854 return ext; 10855 } 10856 } 10857 10858 /** 10859 * Get type via extension. 10860 * 10861 * @param {String} URL 10862 * 10863 * @return {String} 10864 */ 10865 function getTypeByExtension(URL) { 10866 var type, 10867 ext = getExtension(URL); 10868 10869 //Uncode addition ##START## 10870 if (URL == undefined) { 10871 return false; 10872 } 10873 //Uncode addition ##END## 10874 10875 if (extensions.image.indexOf(ext) !== -1) type = 'image'; 10876 else if (extensions.flash.indexOf(ext) !== -1) type = 'flash'; 10877 else if (extensions.video.indexOf(ext) !== -1) type = 'video'; 10878 else if (ext.substring(0, 1) == "#") type = 'inline'; //Uncode addition 10879 else type = 'iframe'; 10880 10881 return type; 10882 } 10883 10884 /** 10885 * Return value from percent of a number. 10886 * 10887 * @param {Number} percent 10888 * @param {Number} total 10889 * 10890 * @return {Number} 10891 */ 10892 function percentToValue(percent, total) { 10893 return parseInt((total / 100) * percent); 10894 } 10895 10896 /** 10897 * A JavaScript equivalent of PHP’s parse_url. 10898 * 10899 * @param {String} url The URL to parse. 10900 * 10901 * @return {Mixed} 10902 */ 10903 function parseURI(url) { 10904 var m = String(url).replace(/^\s+|\s+$/g, '').match(/^([^:\/?#]+:)?(\/\/(?:[^:@]*(?::[^:@]*)?@)?(([^:\/?#]*)(?::(\d*))?))?([^?#]*)(\?[^#]*)?(#[\s\S]*)?/); 10905 // authority = '//' + user + ':' + pass '@' + hostname + ':' port 10906 return (m ? { 10907 href: m[0] || '', 10908 protocol: m[1] || '', 10909 authority: m[2] || '', 10910 host: m[3] || '', 10911 hostname: m[4] || '', 10912 port: m[5] || '', 10913 pathname: m[6] || '', 10914 search: m[7] || '', 10915 hash: m[8] || '' 10916 } : null); 10917 } 10918 10919 /** 10920 * Gets the absolute URI. 10921 * 10922 * @param {String} href The relative URL. 10923 * @param {String} base The base URL. 10924 * 10925 * @return {String} The absolute URL. 10926 */ 10927 function absolutizeURI(base, href) { // RFC 3986 10928 var iL = this; 10929 10930 function removeDotSegments(input) { 10931 var output = []; 10932 input.replace(/^(\.\.?(\/|$))+/, '') 10933 .replace(/\/(\.(\/|$))+/g, '/') 10934 .replace(/\/\.\.$/, '/../') 10935 .replace(/\/?[^\/]*/g, function(p) { 10936 if (p === '/..') { 10937 output.pop(); 10938 } else { 10939 output.push(p); 10940 } 10941 }); 10942 return output.join('').replace(/^\//, input.charAt(0) === '/' ? '/' : ''); 10943 } 10944 10945 href = parseURI(href || ''); 10946 base = parseURI(base || ''); 10947 10948 return !href || !base ? null : (href.protocol || base.protocol) + 10949 (href.protocol || href.authority ? href.authority : base.authority) + 10950 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)) + 10951 (href.protocol || href.authority || href.pathname ? href.search : (href.search || base.search)) + 10952 href.hash; 10953 } 10954 10955 /** 10956 * A JavaScript equivalent of PHP’s version_compare. 10957 * 10958 * @param {String} v1 10959 * @param {String} v2 10960 * @param {String} operator
10961 * 10962 * @return {Boolean} 10963 */ 10964 function version_compare(v1, v2, operator) { 10965 this.php_js = this.php_js || {}; 10966 this.php_js.ENV = this.php_js.ENV || {}; 10967 var i = 0, 10968 x = 0, 10969 compare = 0, 10970 vm = { 10971 'dev': -6, 10972 'alpha': -5, 10973 'a': -5, 10974 'beta': -4, 10975 'b': -4, 10976 'RC': -3, 10977 'rc': -3, 10978 '#': -2, 10979 'p': 1, 10980 'pl': 1 10981 }, 10982 prepVersion = function(v) { 10983 v = ('' + v).replace(/[_\-+]/g, '.'); 10984 v = v.replace(/([^.\d]+)/g, '.$1.').replace(/\.{2,}/g, '.'); 10985 return (!v.length ? [-8] : v.split('.')); 10986 }, 10987 numVersion = function(v) { 10988 return !v ? 0 : (isNaN(v) ? vm[v] || -7 : parseInt(v, 10)); 10989 }; 10990 v1 = prepVersion(v1); 10991 v2 = prepVersion(v2); 10992 x = max(v1.length, v2.length); 10993 for (i = 0; i < x; i++) { 10994 if (v1[i] == v2[i]) { 10995 continue; 10996 } 10997 v1[i] = numVersion(v1[i]); 10998 v2[i] = numVersion(v2[i]); 10999 if (v1[i] < v2[i]) { 11000 compare = -1; 11001 break; 11002 } else if (v1[i] > v2[i]) { 11003 compare = 1; 11004 break; 11005 } 11006 } 11007 if (!operator) { 11008 return compare; 11009 } 11010 11011 switch (operator) { 11012 case '>': 11013 case 'gt': 11014 return (compare > 0); 11015 case '>=': 11016 case 'ge': 11017 return (compare >= 0); 11018 case '<=': 11019 case 'le': 11020 return (compare <= 0); 11021 case '==': 11022 case '=': 11023 case 'eq': 11024 return (compare === 0); 11025 case '<>': 11026 case '!=': 11027 case 'ne': 11028 return (compare !== 0); 11029 case '': 11030 case '<': 11031 case 'lt': 11032 return (compare < 0); 11033 default: 11034 return null; 11035 } 11036 } 11037 11038 11039 // Begin the iLightBox plugin 11040 $.fn.iLightBox = function() { 11041 11042 var args = arguments, 11043 opt = ($.isPlainObject(args[0])) ? args[0] : args[1], 11044 items = ($.isArray(args[0]) || typeof args[0] == 'string') ? args[0] : args[1]; 11045 11046 if (!opt) opt = {}; 11047 11048 // Default options. Play carefully. 11049 var options = $.extend(true, { 11050 attr: 'href', 11051 path: 'vertical', 11052 skin: 'dark', 11053 linkId: false, 11054 infinite: false, 11055 startFrom: 0, 11056 randomStart: false, 11057 keepAspectRatio: true, 11058 maxScale: 1, 11059 minScale: .2, 11060 innerToolbar: false, 11061 smartRecognition: false, 11062 mobileOptimizer: true, 11063 fullAlone: true, 11064 fullViewPort: null, 11065 fullStretchTypes: 'flash, video', 11066 overlay: { 11067 blur: true, 11068 opacity: .85 11069 }, 11070 controls: { 11071 arrows: false, 11072 slideshow: false, 11073 toolbar: true, 11074 fullscreen: true, 11075 thumbnail: true, 11076 keyboard: true, 11077 mousewheel: true, 11078 swipe: true 11079 }, 11080 keyboard: { 11081 left: true, // previous 11082 right: true, // next 11083 up: true, // previous 11084 down: true, // next 11085 esc: true, // close 11086 shift_enter: true // fullscreen 11087 }, 11088 show: { 11089 effect: true, 11090 speed: 300, 11091 title: true 11092 }, 11093 hide: { 11094 effect: true, 11095 speed: 300 11096 }, 11097 caption: { 11098 start: true, 11099 show: 'mouseenter', 11100 hide: 'mouseleave' 11101 }, 11102 social: { 11103 start: true, 11104 show: 'mouseenter', 11105 hide: 'mouseleave',
11106 buttons: false 11107 }, 11108 styles: { 11109 pageOffsetX: 0, 11110 pageOffsetY: 0, 11111 nextOffsetX: 45, 11112 nextOffsetY: 0, 11113 nextOpacity: 1, 11114 nextScale: 1, 11115 prevOffsetX: 45, 11116 prevOffsetY: 0, 11117 prevOpacity: 1, 11118 prevScale: 1 11119 }, 11120 thumbnails: { 11121 maxWidth: 120, 11122 maxHeight: 80, 11123 normalOpacity: 1, 11124 activeOpacity: .6 11125 }, 11126 effects: { 11127 reposition: true, 11128 repositionSpeed: 200, 11129 switchSpeed: 500, 11130 loadedFadeSpeed: 180, 11131 fadeSpeed: 200 11132 }, 11133 slideshow: { 11134 pauseTime: 5000, 11135 pauseOnHover: false, 11136 startPaused: true 11137 }, 11138 text: { 11139 close: "Press Esc to close", 11140 enterFullscreen: "Enter Fullscreen (Shift+Enter)", 11141 exitFullscreen: "Exit Fullscreen (Shift+Enter)", 11142 slideShow: "Slideshow", 11143 next: "Next", 11144 previous: "Previous" 11145 }, 11146 errors: { 11147 loadImage: "An error occurred when trying to load photo.", 11148 loadContents: "An error occurred when trying to load contents.", 11149 missingPlugin: "The content your are attempting to view requires the <a href='{pluginspage}' target='_blank'>{type} plugin<\/a>." 11150 }, 11151 ajaxSetup: { 11152 url: '', 11153 beforeSend: function(jqXHR, settings) {}, 11154 cache: false, 11155 complete: function(jqXHR, textStatus) {}, 11156 crossDomain: false, 11157 error: function(jqXHR, textStatus, errorThrown) {}, 11158 success: function(data, textStatus, jqXHR) {}, 11159 global: true, 11160 ifModified: false, 11161 username: null, 11162 password: null, 11163 type: 'GET' 11164 }, 11165 callback: {} 11166 }, opt); 11167 11168 var instant = ($.isArray(items) || typeof items == 'string') ? true : false; 11169 11170 items = $.isArray(items) ? items : new Array(); 11171 11172 if (typeof args[0] == 'string') items[0] = args[0]; 11173 11174 if (version_compare($.fn.jquery, '1.8', '>=')) { 11175 var iLB = new iLightBox($(this), options, items, instant); 11176 return { 11177 close: function() { 11178 iLB.closeAction(); 11179 }, 11180 fullscreen: function() { 11181 iLB.fullScreenAction(); 11182 }, 11183 moveNext: function() { 11184 iLB.moveTo('next'); 11185 }, 11186 movePrev: function() { 11187 iLB.moveTo('prev'); 11188 }, 11189 goTo: function(index) { 11190 iLB.goTo(index); 11191 }, 11192 refresh: function() { 11193 iLB.refresh(); 11194 }, 11195 reposition: function() { 11196 (arguments.length > 0) ? iLB.repositionPhoto(true): iLB.repositionPhoto(); 11197 }, 11198 setOption: function(options) { 11199 iLB.setOption(options); 11200 }, 11201 destroy: function() { 11202 iLB.closeAction(); 11203 iLB.dispatchItemsEvents(); 11204 } 11205 }; 11206 } else { 11207 throw "The jQuery version that was loaded is too old. iLightBox requires jQuery 1.8+"; 11208 } 11209 11210 }; 11211 11212 11213 $.iLightBox = function() { 11214 return $.fn.iLightBox(arguments[0], arguments[1]); 11215 }; 11216 11217 function getScrollXY() { 11218 var scrOfX = 0, 11219 scrOfY = 0; 11220 if (typeof(window.pageYOffset) == 'number') { 11221 //Netscape compliant 11222 scrOfY = window.pageYOffset; 11223 scrOfX = window.pageXOffset; 11224 } else if (document.body && (document.body.scrollLeft || document.body.scrollTop)) { 11225 //DOM compliant 11226 scrOfY = document.body.scrollTop; 11227 scrOfX = document.body.scrollLeft; 11228 } else if (document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)) { 11229 //IE6 standards compliant mode 11230 scrOfY = document.documentElement.scrollTop; 11231 scrOfX = document.documentElement.scrollLeft; 11232 } 11233 return { 11234 x: scrOfX, 11235 y: scrOfY 11236 }; 11237 } 11238 11239 (function() { 11240 // add new event shortcuts 11241 $.each(("touchstart touchmove touchend " + 11242 "tap taphold " + 11243 "swipe swipeleft swiperight " + 11244 "scrollstart scrollstop").split(" "), function(i, name) { 11245 11246 $.fn[name] = function(fn) { 11247 return fn ? this.bind(name, fn) : this.trigger(name); 11248 }; 11249 11250 // jQuery < 1.8 11251 // if ($.attrFn) { 11252 // $.attrFn[name] = true; 11253 // } 11254 }); 11255 11256 var tapSettings = { 11257 startEvent: 'touchstart.iTap', 11258 endEvent: 'touchend.iTap' 11259 }; 11260 11261 // tap Event: 11262 $.event.special.itap = { 11263 setup: function() { 11264 11265 var self = this, 11266 $self = $(this), 11267 start, stop; 11268 11269 $self.bind(tapSettings.startEvent, function(event) { 11270 start = getScrollXY(); 11271 11272 $self.one(tapSettings.endEvent, function(event) { 11273 stop = getScrollXY(); 11274 11275 var orgEvent = event || window.event; 11276 event = $.event.fix(orgEvent); 11277 event.type = "itap"; 11278 11279 if ((start && stop) && (start.x == stop.x && start.y == stop.y))($.event.dispatch || $.event.handle).call(self, event); 11280 11281 start = stop = undefined; 11282 }); 11283 }); 11284 }, 11285 11286 teardown: function() { 11287 $(this).unbind(tapSettings.startEvent); 11288 } 11289 }; 11290 }()); 11291 11292 11293 //Fullscreen API 11294 (function() { 11295 fullScreenApi = { 11296 supportsFullScreen: false, 11297 isFullScreen: function() { 11298 return false;
11299 }, 11300 requestFullScreen: function() {}, 11301 cancelFullScreen: function() {}, 11302 fullScreenEventName: '', 11303 prefix: '' 11304 }, 11305 browserPrefixes = 'webkit moz o ms khtml'.split(' '); 11306 11307 // check for native support 11308 if (typeof document.cancelFullScreen != 'undefined') { 11309 fullScreenApi.supportsFullScreen = true; 11310 } else { 11311 // check for fullscreen support by vendor prefix 11312 for (var i = 0, il = browserPrefixes.length; i < il; i++) { 11313 fullScreenApi.prefix = browserPrefixes[i]; 11314 11315 if (typeof document[fullScreenApi.prefix + 'CancelFullScreen'] != 'undefined') { 11316 fullScreenApi.supportsFullScreen = true; 11317 11318 break; 11319 } 11320 } 11321 } 11322 11323 // update methods to do something useful 11324 if (fullScreenApi.supportsFullScreen) { 11325 fullScreenApi.fullScreenEventName = fullScreenApi.prefix + 'fullscreenchange'; 11326 11327 fullScreenApi.isFullScreen = function() { 11328 switch (this.prefix) { 11329 case '': 11330 return document.fullScreen; 11331 case 'webkit': 11332 return document.webkitIsFullScreen; 11333 default: 11334 return document[this.prefix + 'FullScreen']; 11335 } 11336 } 11337 fullScreenApi.requestFullScreen = function(el) { 11338 return (this.prefix === '') ? el.requestFullScreen() : el[this.prefix + 'RequestFullScreen'](); 11339 } 11340 fullScreenApi.cancelFullScreen = function(el) { 11341 return (this.prefix === '') ? document.cancelFullScreen() : document[this.prefix + 'CancelFullScreen'](); 11342 } 11343 } 11344 }()); 11345 11346 // Browser detect 11347 (function() { 11348 function uaMatch(ua) { 11349 ua = ua.toLowerCase(); 11350 11351 var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || 11352 /(webkit)[ \/]([\w.]+)/.exec(ua) || 11353 /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || 11354 /(msie) ([\w.]+)/.exec(ua) || 11355 ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || []; 11356 11357 return { 11358 browser: match[1] || "", 11359 version: match[2] || "0" 11360 }; 11361 } 11362 11363 var matched = uaMatch(navigator.userAgent); 11364 browser = {}; 11365 11366 if (matched.browser) { 11367 browser[matched.browser] = true; 11368 browser.version = matched.version; 11369 } 11370 11371 // Chrome is Webkit, but Webkit is also Safari. 11372 if (browser.chrome) { 11373 browser.webkit = true; 11374 } else if (browser.webkit) { 11375 browser.safari = true; 11376 } 11377 }()); 11378 11379 // Feature detects 11380 (function() { 11381 var prefixes = ['', 'webkit', 'moz', 'ms', 'o']; 11382 var el = document.createElement('div'); 11383 11384 function testProp(prop) { 11385 for (var p = 0, pl = prefixes.length; p < pl; p++) { 11386 var prefixedProp = prefixes[p] ? prefixes[p] + prop.charAt(0).toUpperCase() + prop.slice(1) : prop; 11387 if (el.style[prefixedProp] !== undefined) { 11388 return prefixedProp; 11389 } 11390 } 11391 } 11392 11393 // Global support indicators 11394 transform = testProp('transform') || ''; 11395 gpuAcceleration = testProp('perspective') ? 'translateZ(0) ' : ''; 11396 }()); 11397 11398 11399 /* 11400 PluginDetect v0.7.9 11401 www.pinlady.net/PluginDetect/license/ 11402 [ getVersion onWindowLoaded BetterIE ] 11403 [ Flash QuickTime Shockwave ] 11404 */ 11405 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;
11405d++){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);
11405d.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)}
11405c.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;
11405if(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(); 11406 11407 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)}; 11408 11409 11410 /* 11411 jQuery hashchange event v1.3 11412 https://github.com/cowboy/jquery-hashchange 11413 Copyright (c) 2010 "Cowboy" Ben Alman 11414 Dual licensed under the MIT and GPL licenses. 11415 */ 11416 (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= 11417 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|| 11418 "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;
11418a!==d&&(b.title=k.title,b.open(),e&&b.write('<script>document.domain="'+e+'"\x3c/script>'),b.close(),c.location.hash=a)}}();return h}()})(); 11419 11420 if (!Array.prototype.filter) { 11421 Array.prototype.filter = function(fun /*, thisp */ ) { 11422 "use strict"; 11423 11424 if (this == null) 11425 throw new TypeError(); 11426 11427 var t = Object(this); 11428 var len = t.length >>> 0; 11429 if (typeof fun != "function") 11430 throw new TypeError(); 11431 11432 var res = []; 11433 var thisp = arguments[1]; 11434 for (var i = 0; i < len; i++) { 11435 if (i in t) { 11436 var val = t[i]; // in case fun mutates this 11437 if (fun.call(thisp, val, i, t)) 11438 res.push(val); 11439 } 11440 } 11441 11442 return res; 11443 }; 11444 } 11445 11446 if (!Array.prototype.indexOf) { 11447 Array.prototype.indexOf = function(searchElement, fromIndex) { 11448 var k; 11449 11450 if (this == null) { 11451 throw new TypeError('"this" is null or not defined'); 11452 } 11453 11454 var O = Object(this); 11455 11456 var len = O.length >>> 0; 11457 11458 if (len === 0) { 11459 return -1; 11460 } 11461 11462 var n = +fromIndex || 0; 11463 11464 if (abs(n) === Infinity) { 11465 n = 0; 11466 } 11467 11468 if (n >= len) { 11469 return -1; 11470 } 11471 11472 k = max(n >= 0 ? n : len - abs(n), 0); 11473 11474 while (k < len) { 11475 var kValue; 11476 if (k in O && O[k] === searchElement) { 11477 return k; 11478 } 11479 k++; 11480 } 11481 return -1; 11482 }; 11483 } 11484 11485 if (!Array.prototype.lastIndexOf) { 11486 Array.prototype.lastIndexOf = function(searchElement /*, fromIndex*/ ) { 11487 "use strict"; 11488 11489 if (this == null) 11490 throw new TypeError(); 11491 11492 var t = Object(this); 11493 var len = t.length >>> 0; 11494 if (len === 0) 11495 return -1; 11496 11497 var n = len; 11498 if (arguments.length > 1) { 11499 n = Number(arguments[1]); 11500 if (n != n) 11501 n = 0; 11502 else if (n != 0 && n != (1 / 0) && n != -(1 / 0)) 11503 n = (n > 0 || -1) * floor(abs(n)); 11504 } 11505 11506 var k = n >= 0 ? min(n, len - 1) : len - abs(n); 11507 11508 for (; k >= 0; k--) { 11509 if (k in t && t[k] === searchElement) 11510 return k; 11511 } 11512 return -1; 11513 }; 11514 } 11515})(jQuery, this); 11516 11517/** 11518 * Owl carousel
vendor: 12,108 bytes, lines 11519-12025
11519 * @version 2.0.0-beta.3 11520 * @author Bartosz Wojciechowski 11521 * @license The MIT License (MIT) 11522 * @todo Lazy Load Icon 11523 * @todo prevent animationend bubling 11524 * @todo itemsScaleUp 11525 * @todo Test Zepto 11526 * @todo stagePadding calculate wrong active classes 11527 */ 11528;(function($, window, document, undefined) { 11529 11530 /** 11531 * Creates a carousel. 11532 * @class The Owl Carousel. 11533 * @public 11534 * @param {HTMLElement|jQuery} element - The element to create the carousel for. 11535 * @param {Object} [options] - The options 11536 */ 11537 function Owl(element, options) { 11538 11539 /** 11540 * Current settings for the carousel. 11541 * @public 11542 */ 11543 this.settings = null; 11544 11545 /** 11546 * Current options set by the caller including defaults. 11547 * @public 11548 */ 11549 this.options = $.extend({}, Owl.Defaults, options); 11550 11551 /** 11552 * Plugin element. 11553 * @public 11554 */ 11555 this.$element = $(element); 11556 11557 /** 11558 * Proxied event handlers. 11559 * @protected 11560 */ 11561 this._handlers = {}; 11562 11563 /** 11564 * References to the running plugins of this carousel. 11565 * @protected 11566 */ 11567 this._plugins = {}; 11568 11569 /** 11570 * Currently suppressed events to prevent them from beeing retriggered. 11571 * @protected 11572 */ 11573 this._supress = {}; 11574 11575 /** 11576 * Absolute current position. 11577 * @protected 11578 */ 11579 this._current = null; 11580 11581 /** 11582 * Animation speed in milliseconds. 11583 * @protected 11584 */ 11585 this._speed = null; 11586 11587 /** 11588 * Coordinates of all items in pixel. 11589 * @todo The name of this member is missleading. 11590 * @protected 11591 */ 11592 this._coordinates = []; 11593 11594 /** 11595 * Current breakpoint. 11596 * @todo Real media queries would be nice. 11597 * @protected 11598 */ 11599 this._breakpoint = null; 11600 11601 /** 11602 * Current width of the plugin element. 11603 */ 11604 this._width = null; 11605 11606 /** 11607 * All real items. 11608 * @protected 11609 */ 11610 this._items = []; 11611 11612 /** 11613 * All cloned items. 11614 * @protected 11615 */ 11616 this._clones = []; 11617 11618 /** 11619 * Merge values of all items. 11620 * @todo Maybe this could be part of a plugin. 11621 * @protected 11622 */ 11623 this._mergers = []; 11624 11625 /** 11626 * Widths of all items. 11627 */ 11628 this._widths = []; 11629 11630 /** 11631 * Invalidated parts within the update process. 11632 * @protected 11633 */ 11634 this._invalidated = {}; 11635 11636 /** 11637 * Ordered list of workers for the update process. 11638 * @protected 11639 */ 11640 this._pipe = []; 11641 11642 /** 11643 * Current state information for the drag operation. 11644 * @todo #261 11645 * @protected 11646 */ 11647 this._drag = { 11648 time: null, 11649 target: null, 11650 pointer: null, 11651 stage: { 11652 start: null, 11653 current: null 11654 }, 11655 direction: null 11656 }; 11657 11658 /** 11659 * Current state information and their tags. 11660 * @type {Object} 11661 * @protected 11662 */ 11663 this._states = { 11664 current: {}, 11665 tags: { 11666 'initializing': [ 'busy' ], 11667 'animating': [ 'busy' ], 11668 'dragging': [ 'interacting' ] 11669 } 11670 }; 11671 11672 $.each([ 'onResize', 'onThrottledResize' ], $.proxy(function(i, handler) { 11673 this._handlers[handler] = $.proxy(this[handler], this); 11674 }, this)); 11675 11676 $.each(Owl.Plugins, $.proxy(function(key, plugin) { 11677 this._plugins[key.charAt(0).toLowerCase() + key.slice(1)] 11678 = new plugin(this); 11679 }, this)); 11680 11681 $.each(Owl.Workers, $.proxy(function(priority, worker) { 11682 this._pipe.push({ 11683 'filter': worker.filter, 11684 'run': $.proxy(worker.run, this) 11685 }); 11686 }, this)); 11687 11688 this.setup(); 11689 this.initialize(); 11690 } 11691 11692 /** 11693 * Default options for the carousel. 11694 * @public 11695 */ 11696 Owl.Defaults = { 11697 items: 3, 11698 loop: false, 11699 center: false, 11700 rewind: false, 11701 11702 mouseDrag: true, 11703 touchDrag: true, 11704 pullDrag: true, 11705 freeDrag: false, 11706 11707 margin: 0, 11708 stagePadding: 0, 11709 11710 merge: false, 11711 mergeFit: true, 11712 autoWidth: false, 11713 11714 startPosition: 0, 11715 rtl: false, 11716 11717 smartSpeed: 250, 11718 fluidSpeed: false, 11719 dragEndSpeed: false, 11720 11721 responsive: {}, 11722 responsiveRefreshRate: 200, 11723 responsiveBaseElement: window, 11724 11725 fallbackEasing: 'swing', 11726 11727 info: false, 11728 11729 nestedItemSelector: false, 11730 itemElement: 'div', 11731 stageElement: 'div', 11732 11733 refreshClass: 'owl-refresh', 11734 loadedClass: 'owl-loaded', 11735 loadingClass: 'owl-loading', 11736 rtlClass: 'owl-rtl', 11737 responsiveClass: 'owl-responsive', 11738 dragClass: 'owl-drag', 11739 itemClass: 'owl-item', 11740 stageClass: 'owl-stage', 11741 stageOuterClass: 'owl-stage-outer', 11742 grabClass: 'owl-grab' 11743 }; 11744 11745 /** 11746 * Enumeration for width. 11747 * @public 11748 * @readonly 11749 * @enum {String} 11750 */ 11751 Owl.Width = { 11752 Default: 'default', 11753 Inner: 'inner', 11754 Outer: 'outer' 11755 }; 11756 11757 /** 11758 * Enumeration for types. 11759 * @public 11760 * @readonly 11761 * @enum {String} 11762 */ 11763 Owl.Type = { 11764 Event: 'event', 11765 State: 'state' 11766 }; 11767 11768 /** 11769 * Contains all registered plugins. 11770 * @public 11771 */ 11772 Owl.Plugins = {}; 11773 11774 /** 11775 * List of workers involved in the update process. 11776 */ 11777 Owl.Workers = [ { 11778 filter: [ 'width', 'settings' ], 11779 run: function() { 11780 this._width = (this.$element.closest('.px-gutter').length) ? 12 * Math.ceil(this.$element.width() / 12) : this.$element.width(); 11781 //this._width = (UNCODE.isMobile) ? this.$element.width() : 12 * Math.ceil(this.$element.width() / 12); 11782 } 11783 }, { 11784 filter: [ 'width', 'items', 'settings' ], 11785 run: function(cache) { 11786 cache.current = this._items && this._items[this.relative(this._current)]; 11787 } 11788 }, { 11789 filter: [ 'items', 'settings' ], 11790 run: function() { 11791 this.$stage.children('.cloned').remove(); 11792 } 11793 }, { 11794 filter: [ 'width', 'items', 'settings' ], 11795 run: function(cache) { 11796 var margin = this.settings.margin || '', 11797 grid = !this.settings.autoWidth, 11798 rtl = this.settings.rtl, 11799 css = { 11800 'width': 'auto', 11801 'margin-left': rtl ? margin : '', 11802 'margin-right': rtl ? '' : margin 11803 }; 11804 11805 !grid && this.$stage.children().css(css); 11806 11807 cache.css = css; 11808 } 11809 }, { 11810 filter: [ 'width', 'items', 'settings' ], 11811 run: function(cache) { 11812 //UNCODE edit to fix Chrome stage padding issue 11813 var width = Math.round((this.width() / this.settings.items).toFixed(3) - this.settings.margin), 11814 merge = null, 11815 iterator = this._items.length, 11816 grid = !this.settings.autoWidth, 11817 widths = []; 11818 11819 cache.items = { 11820 merge: false, 11821 width: width 11822 }; 11823 11824 while (iterator--) { 11825 merge = this._mergers[iterator]; 11826 merge = this.settings.mergeFit && Math.min(merge, this.settings.items) || merge; 11827 11828 cache.items.merge = merge > 1 || cache.items.merge; 11829 11830 widths[iterator] = !grid ? this._items[iterator].width() : width * merge; 11831 } 11832 11833 this._widths = widths; 11834 } 11835 }, { 11836 filter: [ 'items', 'settings' ], 11837 run: function() { 11838 var clones = [], 11839 items = this._items, 11840 settings = this.settings, 11841 view = Math.max(settings.items * 2, 4), 11842 size = Math.ceil(items.length / 2) * 2, 11843 repeat = settings.loop && items.length ? settings.rewind ? view : Math.max(view, size) : 0, 11844 append = '', 11845 prepend = ''; 11846 11847 repeat /= 2; 11848 11849 while (repeat--) { 11850 clones.push(this.normalize(clones.length / 2, true)); 11851 append = append + items[clones[clones.length - 1]][0].outerHTML; 11852 clones.push(this.normalize(items.length - 1 - (clones.length - 1) / 2, true)); 11853 prepend = items[clones[clones.length - 1]][0].outerHTML + prepend; 11854 } 11855 11856 this._clones = clones; 11857 11858 // var appendVideo = $(append).find('.uncode-video-container'); 11859 // if (appendVideo.length) { 11860 // appendVideo.attr('data-id', Math.round(Math.random() * 100000)); 11861 // } 11862 // var prependVideo = $(prepend).find('.uncode-video-container'); 11863 // if (prependVideo.length) { 11864 // prependVideo.attr('data-id', Math.round(Math.random() * 100000)); 11865 // } 11866 $(append).addClass('cloned').appendTo(this.$stage); 11867 $(prepend).addClass('cloned').prependTo(this.$stage); 11868 } 11869 }, { 11870 filter: [ 'width', 'items', 'settings' ], 11871 run: function() { 11872 var rtl = this.settings.rtl ? 1 : -1, 11873 size = this._clones.length + this._items.length, 11874 iterator = -1, 11875 previous = 0, 11876 current = 0, 11877 coordinates = []; 11878 11879 while (++iterator < size) { 11880 previous = coordinates[iterator - 1] || 0; 11881 current = this._widths[this.relative(iterator)] + this.settings.margin; 11882 coordinates.push(previous + current * rtl); 11883 } 11884 11885 this._coordinates = coordinates; 11886 } 11887 }, { 11888 filter: [ 'width', 'items', 'settings' ], 11889 run: function() { 11890 var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200, 11891 padding = stagePadding, 11892 coordinates = this._coordinates, 11893 css = { 11894 'width': Math.ceil(Math.abs(coordinates[coordinates.length - 1])) + padding * 2, 11895 'padding-left': padding || '', 11896 'padding-right': padding || '' 11897 }; 11898 11899 this.$stage.css(css); 11900 } 11901 }, { 11902 filter: [ 'width', 'items', 'settings' ], 11903 run: function(cache) { 11904 var iterator = this._coordinates.length, 11905 grid = !this.settings.autoWidth, 11906 items = this.$stage.children(); 11907 11908 if (grid && cache.items.merge) { 11909 while (iterator--) { 11910 cache.css.width = this._widths[this.relative(iterator)]; 11911 items.eq(iterator).css(cache.css); 11912 } 11913 } else if (grid) { 11914 cache.css.width = cache.items.width; 11915 items.css(cache.css); 11916 } 11917 } 11918 }, { 11919 filter: [ 'items' ], 11920 run: function() { 11921 this._coordinates.length < 1 && this.$stage.removeAttr('style'); 11922 } 11923 }, { 11924 filter: [ 'width', 'items', 'settings' ], 11925 run: function(cache) { 11926 cache.current = cache.current ? this.$stage.children().index(cache.current) : 0; 11927 cache.current = Math.max(this.minimum(), Math.min(this.maximum(), cache.current)); 11928 this.reset(cache.current); 11929 } 11930 }, { 11931 filter: [ 'position' ], 11932 run: function() { 11933 this.animate(this.coordinates(this._current)); 11934 } 11935 }, { 11936 filter: [ 'width', 'position', 'items', 'settings' ], 11937 run: function() { 11938 var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200, 11939 rtl = this.settings.rtl ? 1 : -1, 11940 padding = this.settings.stagePadding * 2, 11941 begin = this.coordinates(this.current()) + padding, 11942 end = begin + this.width() * rtl, 11943 inner, outer, matches = [], i, n; 11944 11945 for (i = 0, n = this._coordinates.length; i < n; i++) { 11946 inner = this._coordinates[i - 1] || 0; 11947 outer = Math.abs(this._coordinates[i]) + padding * rtl; 11948 11949 if ((this.op(inner, '<=', begin) && (this.op(inner, '>', end))) 11950 || (this.op(outer, '<', begin) && this.op(outer, '>', end))) { 11951 matches.push(i); 11952 } 11953 } 11954 11955 this.$stage.children('.active').removeClass('active'); 11956 this.$stage.children(':eq(' + matches.join('), :eq(') + ')').addClass('active'); 11957 11958 if (this.settings.center) { 11959 this.$stage.children('.center').removeClass('center'); 11960 this.$stage.children().eq(this.current()).addClass('center'); 11961 } 11962 } 11963 } ]; 11964 11965 /** 11966 * Initializes the carousel. 11967 * @protected 11968 */ 11969 Owl.prototype.initialize = function() { 11970 this.enter('initializing'); 11971 this.trigger('initialize'); 11972 11973 this.$element.toggleClass(this.settings.rtlClass, this.settings.rtl); 11974 11975 if (this.settings.autoWidth && !this.is('pre-loading')) { 11976 var imgs, nestedSelector, width; 11977 imgs = this.$element.find('img'); 11978 nestedSelector = this.settings.nestedItemSelector ? '.' + this.settings.nestedItemSelector : undefined; 11979 width = this.$element.children(nestedSelector).width(); 11980 11981 if (imgs.length && width <= 0) { 11982 this.preloadAutoWidthImages(imgs); 11983 } 11984 } 11985 11986 this.$element.addClass(this.options.loadingClass); 11987 11988 // create stage 11989 this.$stage = $('<' + this.settings.stageElement + ' class="' + this.settings.stageClass + '"/>') 11990 .wrap('<div class="' + this.settings.stageOuterClass + '"/>'); 11991 11992 // append stage 11993 this.$element.append(this.$stage.parent()); 11994 11995 // append content 11996 this.replace(this.$element.children().not(this.$stage.parent())); 11997 11998 // check visibility 11999 if (this.$element.is(':visible')) { 12000 // update view 12001 this.refresh(); 12002 } else { 12003 // invalidate width 12004 this.invalidate('width'); 12005 } 12006 12007 this.$element 12008 .removeClass(this.options.loadingClass) 12009 .addClass(this.options.loadedClass); 12010 12011 // register event handlers 12012 this.registerEventHandlers(); 12013 12014 this.leave('initializing'); 12015 this.trigger('initialized'); 12016 }; 12017 12018 /** 12019 * Setups the current settings. 12020 * @todo Remove responsive classes. Why should adaptive designs be brought into IE8? 12021 * @todo Support for media queries by using `matchMedia` would be nice. 12022 * @public 12023 */ 12024 Owl.prototype.setup = function() { 12025 var viewport = this.viewport(),
12026 overwrites = this.options.responsive, 12027 match = -1, 12028 settings = null; 12029 12030 if (!overwrites) { 12031 settings = $.extend({}, this.options); 12032 } else { 12033 $.each(overwrites, function(breakpoint) { 12034 if (breakpoint <= viewport && breakpoint > match) { 12035 match = Number(breakpoint); 12036 } 12037 }); 12038 12039 settings = $.extend({}, this.options, overwrites[match]); 12040 delete settings.responsive; 12041 12042 // responsive class 12043 if (settings.responsiveClass) { 12044 this.$element.attr('class', 12045 this.$element.attr('class').replace(new RegExp('(' + this.options.responsiveClass + '-)\\S+\\s', 'g'), '$1' + match) 12046 ); 12047 } 12048 } 12049 12050 if (this.settings === null || this._breakpoint !== match) { 12051 this.trigger('change', { property: { name: 'settings', value: settings } }); 12052 this._breakpoint = match; 12053 this.settings = settings; 12054 this.invalidate('settings'); 12055 this.trigger('changed', { property: { name: 'settings', value: this.settings } }); 12056 } 12057 }; 12058 12059 /** 12060 * Updates option logic if necessery. 12061 * @protected 12062 */ 12063 Owl.prototype.optionsLogic = function() { 12064 if (this.settings.autoWidth) { 12065 this.settings.stagePadding = false; 12066 this.settings.merge = false; 12067 } 12068 }; 12069 12070 /** 12071 * Prepares an item before add. 12072 * @todo Rename event parameter `content` to `item`. 12073 * @protected 12074 * @returns {jQuery|HTMLElement} - The item container. 12075 */ 12076 Owl.prototype.prepare = function(item, index) { 12077 var event = this.trigger('prepare', { content: item }); 12078 if (!event.data) { 12079 event.data = $('<' + this.settings.itemElement + '/>') 12080 .addClass(this.options.itemClass).attr('data-index', index + 1).append(item) 12081 } 12082 12083 this.trigger('prepared', { content: event.data }); 12084 12085 return event.data; 12086 }; 12087 12088 /** 12089 * Updates the view. 12090 * @public 12091 */ 12092 Owl.prototype.update = function() { 12093 var i = 0, 12094 n = this._pipe.length, 12095 filter = $.proxy(function(p) { return this[p] }, this._invalidated), 12096 cache = {}; 12097 12098 while (i < n) { 12099 if (this._invalidated.all || $.grep(this._pipe[i].filter, filter).length > 0) { 12100 this._pipe[i].run(cache); 12101 } 12102 i++; 12103 } 12104 12105 this._invalidated = {}; 12106 12107 !this.is('valid') && this.enter('valid'); 12108 }; 12109 12110 /** 12111 * Gets the width of the view. 12112 * @public 12113 * @param {Owl.Width} [dimension=Owl.Width.Default] - The dimension to return. 12114 * @returns {Number} - The width of the view in pixel. 12115 */ 12116 Owl.prototype.width = function(dimension) { 12117 dimension = dimension || Owl.Width.Default; 12118 var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200; 12119 switch (dimension) { 12120 case Owl.Width.Inner: 12121 case Owl.Width.Outer: 12122 return this._width; 12123 default: 12124 return this._width - stagePadding * 2 + this.settings.margin; 12125 } 12126 }; 12127 12128 /** 12129 * Refreshes the carousel primarily for adaptive purposes. 12130 * @public 12131 */ 12132 Owl.prototype.refresh = function() { 12133 this.enter('refreshing'); 12134 this.trigger('refresh'); 12135 12136 this.setup(); 12137 12138 this.optionsLogic(); 12139 12140 this.$element.addClass(this.options.refreshClass); 12141 12142 this.update(); 12143 12144 this.$element.removeClass(this.options.refreshClass); 12145 12146 this.leave('refreshing'); 12147 this.trigger('refreshed'); 12148 }; 12149 12150 /** 12151 * Checks window `resize` event. 12152 * @protected 12153 */ 12154 Owl.prototype.onThrottledResize = function() { 12155 window.clearTimeout(this.resizeTimer); 12156 this.resizeTimer = window.setTimeout(this._handlers.onResize, this.settings.responsiveRefreshRate); 12157 }; 12158 12159 /** 12160 * Checks window `resize` event. 12161 * @protected 12162 */ 12163 Owl.prototype.onResize = function() { 12164 if (!this._items.length) { 12165 return false; 12166 } 12167 12168 if (this._width === this.$element.width()) { 12169 return false; 12170 } 12171 12172 if (!this.$element.is(':visible')) { 12173 return false; 12174 } 12175 12176 this.enter('resizing'); 12177 12178 if (this.trigger('resize').isDefaultPrevented()) { 12179 this.leave('resizing'); 12180 return false; 12181 } 12182 12183 this.invalidate('width'); 12184 12185 this.refresh(); 12186 12187 this.leave('resizing'); 12188 this.trigger('resized'); 12189 }; 12190 12191 /** 12192 * Registers event handlers. 12193 * @todo Check `msPointerEnabled` 12194 * @todo #261 12195 * @protected 12196 */ 12197 Owl.prototype.registerEventHandlers = function() { 12198 if ($.support.transition) { 12199 this.$stage.on($.support.transition.end + '.owl.core', $.proxy(this.onTransitionEnd, this)); 12200 } 12201 12202 if (this.settings.responsive !== false) { 12203 this.on(window, 'resize', this._handlers.onThrottledResize); 12204 } 12205 12206 if (this.settings.mouseDrag) { 12207 this.$element.addClass(this.options.dragClass); 12208 this.$stage.on('mousedown.owl.core', $.proxy(this.onDragStart, this)); 12209 this.$stage.on('dragstart.owl.core selectstart.owl.core', function() { return false }); 12210 } 12211 12212 if (this.settings.touchDrag){ 12213 this.$stage.on('touchstart.owl.core', $.proxy(this.onDragStart, this)); 12214 this.$stage.on('touchcancel.owl.core', $.proxy(this.onDragEnd, this)); 12215 } 12216 }; 12217 12218 /** 12219 * Handles `touchstart` and `mousedown` events. 12220 * @todo Horizontal swipe threshold as option 12221 * @todo #261 12222 * @protected 12223 * @param {Event} event - The event arguments. 12224 */ 12225 Owl.prototype.onDragStart = function(event) { 12226 var stage = null; 12227 12228 if (event.which === 3) { 12229 return; 12230 } 12231
vendor: 9,106 bytes, lines 12232-12547
12232 if ($.support.transform) { 12233 stage = this.$stage.css('transform').replace(/.*\(|\)| /g, '').split(','); 12234 stage = { 12235 x: stage[stage.length === 16 ? 12 : 4], 12236 y: stage[stage.length === 16 ? 13 : 5] 12237 }; 12238 } else { 12239 stage = this.$stage.position(); 12240 stage = { 12241 x: this.settings.rtl ? 12242 stage.left + this.$stage.width() - this.width() + this.settings.margin : 12243 stage.left, 12244 y: stage.top 12245 }; 12246 } 12247 12248 if (this.is('animating')) { 12249 $.support.transform ? this.animate(stage.x) : this.$stage.stop() 12250 this.invalidate('position'); 12251 } 12252 12253 this.$element.toggleClass(this.options.grabClass, event.type === 'mousedown'); 12254 12255 this.speed(0); 12256 12257 this._drag.time = new Date().getTime(); 12258 this._drag.target = $(event.target); 12259 this._drag.stage.start = stage; 12260 this._drag.stage.current = stage; 12261 this._drag.pointer = this.pointer(event); 12262 12263 $(document).on('mouseup.owl.core touchend.owl.core', $.proxy(this.onDragEnd, this)); 12264 12265 $(document).one('mousemove.owl.core touchmove.owl.core', $.proxy(function(event) { 12266 var delta = this.difference(this._drag.pointer, this.pointer(event)); 12267 12268 $(document).on('mousemove.owl.core touchmove.owl.core', $.proxy(this.onDragMove, this)); 12269 12270 if (Math.abs(delta.x) < Math.abs(delta.y) && this.is('valid')) { 12271 return; 12272 } 12273 12274 event.preventDefault(); 12275 12276 this.enter('dragging'); 12277 this.trigger('drag'); 12278 }, this)); 12279 }; 12280 12281 /** 12282 * Handles the `touchmove` and `mousemove` events. 12283 * @todo #261 12284 * @protected 12285 * @param {Event} event - The event arguments. 12286 */ 12287 Owl.prototype.onDragMove = function(event) { 12288 var minimum = null, 12289 maximum = null, 12290 pull = null, 12291 delta = this.difference(this._drag.pointer, this.pointer(event)), 12292 stage = this.difference(this._drag.stage.start, delta); 12293 12294 if (!this.is('dragging')) { 12295 return; 12296 } 12297 12298 event.preventDefault(); 12299 12300 if (this.settings.loop) { 12301 minimum = this.coordinates(this.minimum()); 12302 maximum = this.coordinates(this.maximum() + 1) - minimum; 12303 stage.x = (((stage.x - minimum) % maximum + maximum) % maximum) + minimum; 12304 } else { 12305 minimum = this.settings.rtl ? this.coordinates(this.maximum()) : this.coordinates(this.minimum()); 12306 maximum = this.settings.rtl ? this.coordinates(this.minimum()) : this.coordinates(this.maximum()); 12307 pull = this.settings.pullDrag ? -1 * delta.x / 5 : 0; 12308 stage.x = Math.max(Math.min(stage.x, minimum + pull), maximum + pull); 12309 } 12310 12311 this._drag.stage.current = stage; 12312 12313 this.animate(stage.x); 12314 }; 12315 12316 /** 12317 * Handles the `touchend` and `mouseup` events. 12318 * @todo #261 12319 * @todo Threshold for click event 12320 * @protected 12321 * @param {Event} event - The event arguments. 12322 */ 12323 Owl.prototype.onDragEnd = function(event) { 12324 var delta = this.difference(this._drag.pointer, this.pointer(event)), 12325 stage = this._drag.stage.current, 12326 direction = delta.x > 0 ^ this.settings.rtl ? 'left' : 'right'; 12327 12328 $(document).off('.owl.core'); 12329 12330 this.$element.removeClass(this.options.grabClass); 12331 12332 if (delta.x !== 0 && this.is('dragging') || !this.is('valid')) { 12333 this.speed(this.settings.dragEndSpeed || this.settings.smartSpeed); 12334 this.current(this.closest(stage.x, delta.x !== 0 ? direction : this._drag.direction)); 12335 this.invalidate('position'); 12336 this.update(); 12337 12338 this._drag.direction = direction; 12339 12340 if (Math.abs(delta.x) > 3 || new Date().getTime() - this._drag.time > 300) { 12341 this._drag.target.one('click.owl.core', function() { return false; }); 12342 } 12343 } 12344 12345 if (!this.is('dragging')) { 12346 return; 12347 } 12348 12349 this.leave('dragging'); 12350 this.trigger('dragged'); 12351 }; 12352 12353 /** 12354 * Gets absolute position of the closest item for a coordinate. 12355 * @todo Setting `freeDrag` makes `closest` not reusable. See #165. 12356 * @protected 12357 * @param {Number} coordinate - The coordinate in pixel. 12358 * @param {String} direction - The direction to check for the closest item. Ether `left` or `right`. 12359 * @return {Number} - The absolute position of the closest item. 12360 */ 12361 Owl.prototype.closest = function(coordinate, direction) { 12362 var position = -1, 12363 pull = 30, 12364 width = this.width(), 12365 coordinates = this.coordinates(); 12366 12367 if (!this.settings.freeDrag) { 12368 // check closest item 12369 $.each(coordinates, $.proxy(function(index, value) { 12370 if (coordinate > value - pull && coordinate < value + pull) { 12371 position = index; 12372 } else if (this.op(coordinate, '<', value) 12373 && this.op(coordinate, '>', coordinates[index + 1] || value - width)) { 12374 position = direction === 'left' ? index + 1 : index; 12375 } 12376 return position === -1; 12377 }, this)); 12378 } 12379 12380 if (!this.settings.loop) { 12381 // non loop boundries 12382 if (this.op(coordinate, '>', coordinates[this.minimum()])) { 12383 position = coordinate = this.minimum(); 12384 } else if (this.op(coordinate, '<', coordinates[this.maximum()])) { 12385 position = coordinate = this.maximum(); 12386 } 12387 } 12388 12389 return position; 12390 }; 12391 12392 /** 12393 * Animates the stage. 12394 * @todo #270 12395 * @public 12396 * @param {Number} coordinate - The coordinate in pixels. 12397 */ 12398 Owl.prototype.animate = function(coordinate) { 12399 var animate = this.speed() > 0; 12400 12401 this.is('animating') && this.onTransitionEnd(); 12402 12403 if (animate) { 12404 this.enter('animating'); 12405 this.trigger('translate'); 12406 } 12407 12408 if ($.support.transform3d && $.support.transition) { 12409 this.$stage.css({ 12410 transform: 'translate3d(' + coordinate + 'px,0px,0px)', 12411 transition: (this.speed() / 1000) + 's' 12412 }); 12413 } else if (animate) { 12414 this.$stage.animate({ 12415 left: coordinate + 'px' 12416 }, this.speed(), this.settings.fallbackEasing, $.proxy(this.onTransitionEnd, this)); 12417 } else { 12418 this.$stage.css({ 12419 left: coordinate + 'px' 12420 }); 12421 } 12422 }; 12423 12424 /** 12425 * Checks whether the carousel is in a specific state or not. 12426 * @param {String} state - The state to check. 12427 * @returns {Boolean} - The flag which indicates if the carousel is busy. 12428 */ 12429 Owl.prototype.is = function(state) { 12430 return this._states.current[state] && this._states.current[state] > 0; 12431 }; 12432 12433 /** 12434 * Sets the absolute position of the current item. 12435 * @public 12436 * @param {Number} [position] - The new absolute position or nothing to leave it unchanged. 12437 * @returns {Number} - The absolute position of the current item. 12438 */ 12439 Owl.prototype.current = function(position) { 12440 if (position === undefined) { 12441 return this._current; 12442 } 12443 12444 if (this._items.length === 0) { 12445 return undefined; 12446 } 12447 12448 position = this.normalize(position); 12449 12450 if (this._current !== position) { 12451 var event = this.trigger('change', { property: { name: 'position', value: position } }); 12452 12453 if (event.data !== undefined) { 12454 position = this.normalize(event.data); 12455 } 12456 12457 this._current = position; 12458 12459 this.invalidate('position'); 12460 12461 this.trigger('changed', { property: { name: 'position', value: this._current } }); 12462 } 12463 12464 return this._current; 12465 }; 12466 12467 /** 12468 * Invalidates the given part of the update routine. 12469 * @param {String} [part] - The part to invalidate. 12470 * @returns {Array.<String>} - The invalidated parts. 12471 */ 12472 Owl.prototype.invalidate = function(part) { 12473 if ($.type(part) === 'string') { 12474 this._invalidated[part] = true; 12475 this.is('valid') && this.leave('valid'); 12476 } 12477 return $.map(this._invalidated, function(v, i) { return i }); 12478 }; 12479 12480 /** 12481 * Resets the absolute position of the current item. 12482 * @public 12483 * @param {Number} position - The absolute position of the new item. 12484 */ 12485 Owl.prototype.reset = function(position) { 12486 position = this.normalize(position); 12487 12488 if (position === undefined) { 12489 return; 12490 } 12491 12492 this._speed = 0; 12493 this._current = position; 12494 12495 this.suppress([ 'translate', 'translated' ]); 12496 12497 this.animate(this.coordinates(position)); 12498 12499 this.release([ 'translate', 'translated' ]); 12500 }; 12501 12502 /** 12503 * Normalizes an absolute or a relative position of an item. 12504 * @public 12505 * @param {Number} position - The absolute or relative position to normalize. 12506 * @param {Boolean} [relative=false] - Whether the given position is relative or not. 12507 * @returns {Number} - The normalized position. 12508 */ 12509 Owl.prototype.normalize = function(position, relative) { 12510 var n = this._items.length, 12511 m = relative ? 0 : this._clones.length; 12512 12513 if (!$.isNumeric(position) || n < 1) { 12514 position = undefined; 12515 } else if (position < 0 || position >= n + m) { 12516 position = ((position - m / 2) % n + n) % n + m / 2; 12517 } 12518 12519 return position; 12520 }; 12521 12522 /** 12523 * Converts an absolute position of an item into a relative one. 12524 * @public 12525 * @param {Number} position - The absolute position to convert. 12526 * @returns {Number} - The converted position. 12527 */ 12528 Owl.prototype.relative = function(position) { 12529 position -= this._clones.length / 2; 12530 return this.normalize(position, true); 12531 }; 12532 12533 /** 12534 * Gets the maximum position for the current item. 12535 * @public 12536 * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position. 12537 * @returns {Number} 12538 */ 12539 Owl.prototype.maximum = function(relative) { 12540 var settings = this.settings, 12541 maximum = this._coordinates.length, 12542 boundary = Math.abs(this._coordinates[maximum - 1]) - this._width, 12543 i = -1, j; 12544 12545 if (settings.loop) { 12546 maximum = this._clones.length / 2 + this._items.length - 1; 12547 } else if (settings.autoWidth || settings.merge) {
12548 // binary search 12549 while (maximum - i > 1) { 12550 Math.abs(this._coordinates[j = maximum + i >> 1]) < boundary 12551 ? i = j : maximum = j; 12552 } 12553 } else if (settings.center) { 12554 maximum = this._items.length - 1; 12555 } else { 12556 maximum = this._items.length - settings.items; 12557 } 12558 12559 if (relative) { 12560 maximum -= this._clones.length / 2; 12561 } 12562 12563 return Math.max(maximum, 0); 12564 }; 12565 12566 /** 12567 * Gets the minimum position for the current item. 12568 * @public 12569 * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position. 12570 * @returns {Number} 12571 */ 12572 Owl.prototype.minimum = function(relative) { 12573 return relative ? 0 : this._clones.length / 2; 12574 }; 12575 12576 /** 12577 * Gets an item at the specified relative position. 12578 * @public 12579 * @param {Number} [position] - The relative position of the item. 12580 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given. 12581 */ 12582 Owl.prototype.items = function(position) { 12583 if (position === undefined) { 12584 return this._items.slice(); 12585 } 12586 12587 position = this.normalize(position, true); 12588 return this._items[position]; 12589 }; 12590 12591 /** 12592 * Gets an item at the specified relative position. 12593 * @public 12594 * @param {Number} [position] - The relative position of the item. 12595 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given. 12596 */ 12597 Owl.prototype.mergers = function(position) { 12598 if (position === undefined) { 12599 return this._mergers.slice(); 12600 } 12601 12602 position = this.normalize(position, true); 12603 return this._mergers[position]; 12604 }; 12605 12606 /** 12607 * Gets the absolute positions of clones for an item. 12608 * @public 12609 * @param {Number} [position] - The relative position of the item. 12610 * @returns {Array.<Number>} - The absolute positions of clones for the item or all if no position was given. 12611 */ 12612 Owl.prototype.clones = function(position) { 12613 var odd = this._clones.length / 2, 12614 even = odd + this._items.length, 12615 map = function(index) { return index % 2 === 0 ? even + index / 2 : odd - (index + 1) / 2 }; 12616 12617 if (position === undefined) { 12618 return $.map(this._clones, function(v, i) { return map(i) }); 12619 } 12620 12621 return $.map(this._clones, function(v, i) { return v === position ? map(i) : null }); 12622 }; 12623 12624 /** 12625 * Sets the current animation speed. 12626 * @public 12627 * @param {Number} [speed] - The animation speed in milliseconds or nothing to leave it unchanged. 12628 * @returns {Number} - The current animation speed in milliseconds. 12629 */ 12630 Owl.prototype.speed = function(speed) { 12631 if (speed !== undefined) { 12632 this._speed = speed; 12633 } 12634 12635 return this._speed; 12636 }; 12637 12638 /** 12639 * Gets the coordinate of an item. 12640 * @todo The name of this method is missleanding. 12641 * @public 12642 * @param {Number} position - The absolute position of the item within `minimum()` and `maximum()`. 12643 * @returns {Number|Array.<Number>} - The coordinate of the item in pixel or all coordinates. 12644 */ 12645 Owl.prototype.coordinates = function(position) { 12646 var coordinate = null; 12647 12648 if (position === undefined) { 12649 return $.map(this._coordinates, $.proxy(function(coordinate, index) { 12650 return this.coordinates(index); 12651 }, this)); 12652 } 12653 12654 if (this.settings.center) { 12655 coordinate = this._coordinates[position]; 12656 coordinate += (this.width() - coordinate + (this._coordinates[position - 1] || 0)) / 2 * (this.settings.rtl ? -1 : 1); 12657 } else { 12658 coordinate = this._coordinates[position - 1] || 0; 12659 } 12660 12661 return coordinate; 12662 }; 12663 12664 /** 12665 * Calculates the speed for a translation. 12666 * @protected 12667 * @param {Number} from - The absolute position of the start item. 12668 * @param {Number} to - The absolute position of the target item. 12669 * @param {Number} [factor=undefined] - The time factor in milliseconds. 12670 * @returns {Number} - The time in milliseconds for the translation. 12671 */ 12672 Owl.prototype.duration = function(from, to, factor) { 12673 return Math.min(Math.max(Math.abs(to - from), 1), 6) * Math.abs((factor || this.settings.smartSpeed)); 12674 }; 12675 12676 /** 12677 * Slides to the specified item. 12678 * @public 12679 * @param {Number} position - The position of the item. 12680 * @param {Number} [speed] - The time in milliseconds for the transition. 12681 */ 12682 Owl.prototype.to = function(position, speed) { 12683 var current = this.current(), 12684 revert = null, 12685 distance = position - this.relative(current), 12686 direction = (distance > 0) - (distance < 0), 12687 items = this._items.length, 12688 minimum = this.minimum(), 12689 maximum = this.maximum(); 12690 12691 if (this.settings.loop) { 12692 if (!this.settings.rewind && Math.abs(distance) > items / 2) { 12693 distance += direction * -1 * items; 12694 } 12695 12696 position = current + distance; 12697 revert = ((position - minimum) % items + items) % items + minimum; 12698 12699 if (revert !== position && revert - distance <= maximum && revert - distance > 0) { 12700 current = revert - distance; 12701 position = revert; 12702 this.reset(current); 12703 } 12704 } else if (this.settings.rewind) { 12705 maximum += 1; 12706 position = (position % maximum + maximum) % maximum; 12707 } else { 12708 position = Math.max(minimum, Math.min(maximum, position)); 12709 } 12710 12711 this.speed(this.duration(current, position, speed)); 12712 this.current(position); 12713 12714 if (this.$element.is(':visible')) { 12715 this.update(); 12716 } 12717 }; 12718 12719 /** 12720 * Slides to the next item. 12721 * @public 12722 * @param {Number}
vendor: 12,284 bytes, lines 12722-13142
12722 [speed] - The time in milliseconds for the transition. 12723 */ 12724 Owl.prototype.next = function(speed) { 12725 speed = speed || false; 12726 this.to(this.relative(this.current()) + 1, speed); 12727 }; 12728 12729 /** 12730 * Slides to the previous item. 12731 * @public 12732 * @param {Number} [speed] - The time in milliseconds for the transition. 12733 */ 12734 Owl.prototype.prev = function(speed) { 12735 speed = speed || false; 12736 this.to(this.relative(this.current()) - 1, speed); 12737 }; 12738 12739 /** 12740 * Handles the end of an animation. 12741 * @protected 12742 * @param {Event} event - The event arguments. 12743 */ 12744 Owl.prototype.onTransitionEnd = function(event) { 12745 12746 // if css2 animation then event object is undefined 12747 if (event !== undefined) { 12748 event.stopPropagation(); 12749 12750 // Catch only owl-stage transitionEnd event 12751 if ((event.target || event.srcElement || event.originalTarget) !== this.$stage.get(0)) { 12752 return false; 12753 } 12754 } 12755 12756 this.leave('animating'); 12757 this.trigger('translated'); 12758 }; 12759 12760 /** 12761 * Gets viewport width. 12762 * @protected 12763 * @return {Number} - The width in pixel. 12764 */ 12765 Owl.prototype.viewport = function() { 12766 var width; 12767 if (this.options.responsiveBaseElement !== window) { 12768 width = $(this.options.responsiveBaseElement).width(); 12769 } else if (window.innerWidth) { 12770 width = window.innerWidth; 12771 } else if (document.documentElement && document.documentElement.clientWidth) { 12772 width = document.documentElement.clientWidth; 12773 } else { 12774 throw 'Can not detect viewport width.'; 12775 } 12776 12777 return width; 12778 }; 12779 12780 /** 12781 * Replaces the current content. 12782 * @public 12783 * @param {HTMLElement|jQuery|String} content - The new content. 12784 */ 12785 Owl.prototype.replace = function(content) { 12786 this.$stage.empty(); 12787 this._items = []; 12788 12789 if (content) { 12790 content = (content instanceof jQuery) ? content : $(content); 12791 } 12792 12793 if (this.settings.nestedItemSelector) { 12794 content = content.find('.' + this.settings.nestedItemSelector); 12795 } 12796 12797 content.filter(function() { 12798 return this.nodeType === 1; 12799 }).each($.proxy(function(index, item) { 12800 item = this.prepare(item, index); 12801 this.$stage.append(item); 12802 this._items.push(item); 12803 this._mergers.push(item.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1); 12804 }, this)); 12805 12806 this.reset($.isNumeric(this.settings.startPosition) ? this.settings.startPosition : 0); 12807 12808 this.invalidate('items'); 12809 }; 12810 12811 /** 12812 * Adds an item. 12813 * @todo Use `item` instead of `content` for the event arguments. 12814 * @public 12815 * @param {HTMLElement|jQuery|String} content - The item content to add. 12816 * @param {Number} [position] - The relative position at which to insert the item otherwise the item will be added to the end. 12817 */ 12818 Owl.prototype.add = function(content, position) { 12819 var current = this.relative(this._current); 12820 12821 position = position === undefined ? this._items.length : this.normalize(position, true); 12822 content = content instanceof jQuery ? content : $(content); 12823 12824 this.trigger('add', { content: content, position: position }); 12825 12826 content = this.prepare(content, this._items[current].index()); 12827 12828 if (this._items.length === 0 || position === this._items.length) { 12829 this._items.length === 0 && this.$stage.append(content); 12830 this._items.length !== 0 && this._items[position - 1].after(content); 12831 this._items.push(content); 12832 this._mergers.push(content.find('[data-merge]').andSelf('[data-merge]').attr('data-merge') * 1 || 1); 12833 } else { 12834 this._items[position].before(content); 12835 this._items.splice(position, 0, content); 12836 this._mergers.splice(position, 0, content.find('[data-merge]').andSelf('[data-merge]').attr('data-merge') * 1 || 1); 12837 } 12838 12839 this._items[current] && this.reset(this._items[current].index()); 12840 12841 this.invalidate('items'); 12842 12843 this.trigger('added', { content: content, position: position }); 12844 }; 12845 12846 /** 12847 * Removes an item by its position. 12848 * @todo Use `item` instead of `content` for the event arguments. 12849 * @public 12850 * @param {Number} position - The relative position of the item to remove. 12851 */ 12852 Owl.prototype.remove = function(position) { 12853 position = this.normalize(position, true); 12854 12855 if (position === undefined) { 12856 return; 12857 } 12858 12859 this.trigger('remove', { content: this._items[position], position: position }); 12860 12861 this._items[position].remove(); 12862 this._items.splice(position, 1); 12863 this._mergers.splice(position, 1); 12864 12865 this.invalidate('items'); 12866 12867 this.trigger('removed', { content: null, position: position }); 12868 }; 12869 12870 /** 12871 * Preloads images with auto width. 12872 * @todo Replace by a more generic approach 12873 * @protected 12874 */ 12875 Owl.prototype.preloadAutoWidthImages = function(images) { 12876 images.each($.proxy(function(i, element) { 12877 this.enter('pre-loading'); 12878 element = $(element); 12879 $(new Image()).one('load', $.proxy(function(e) { 12880 element.attr('src', e.target.src); 12881 element.css('opacity', 1); 12882 this.leave('pre-loading'); 12883 !this.is('pre-loading') && !this.is('initializing') && this.refresh(); 12884 }, this)).attr('src', element.attr('src') || element.attr('data-src') || element.attr('data-src-retina')); 12885 }, this)); 12886 }; 12887 12888 /** 12889 * Destroys the carousel. 12890 * @public 12891 */ 12892 Owl.prototype.destroy = function() { 12893 12894 this.$element.off('.owl.core'); 12895 this.$stage.off('.owl.core'); 12896 $(document).off('.owl.core'); 12897 12898 if (this.settings.responsive !== false) { 12899 window.clearTimeout(this.resizeTimer); 12900 this.off(window, 'resize', this._handlers.onThrottledResize); 12901 } 12902 12903 for (var i in this._plugins) { 12904 this._plugins[i].destroy(); 12905 } 12906 12907 this.$stage.children('.cloned').remove(); 12908 12909 this.$stage.unwrap(); 12910 this.$stage.children().contents().unwrap(); 12911 this.$stage.children().unwrap(); 12912 12913 this.$element 12914 .removeClass(this.options.refreshClass) 12915 .removeClass(this.options.loadingClass) 12916 .removeClass(this.options.loadedClass) 12917 .removeClass(this.options.rtlClass) 12918 .removeClass(this.options.dragClass) 12919 .removeClass(this.options.grabClass) 12920 .attr('class', this.$element.attr('class').replace(new RegExp(this.options.responsiveClass + '-\\S+\\s', 'g'), '')) 12921 .removeData('owl.carousel'); 12922 }; 12923 12924 /** 12925 * Operators to calculate right-to-left and left-to-right. 12926 * @protected 12927 * @param {Number} [a] - The left side operand. 12928 * @param {String} [o] - The operator. 12929 * @param {Number} [b] - The right side operand. 12930 */ 12931 Owl.prototype.op = function(a, o, b) { 12932 var rtl = this.settings.rtl; 12933 switch (o) { 12934 case '<': 12935 return rtl ? a > b : a < b; 12936 case '>': 12937 return rtl ? a < b : a > b; 12938 case '>=': 12939 return rtl ? a <= b : a >= b; 12940 case '<=': 12941 return rtl ? a >= b : a <= b; 12942 default: 12943 break; 12944 } 12945 }; 12946 12947 /** 12948 * Attaches to an internal event. 12949 * @protected 12950 * @param {HTMLElement} element - The event source. 12951 * @param {String} event - The event name. 12952 * @param {Function} listener - The event handler to attach. 12953 * @param {Boolean} capture - Wether the event should be handled at the capturing phase or not. 12954 */ 12955 Owl.prototype.on = function(element, event, listener, capture) { 12956 if (element.addEventListener) { 12957 element.addEventListener(event, listener, capture); 12958 } else if (element.attachEvent) { 12959 element.attachEvent('on' + event, listener); 12960 } 12961 }; 12962 12963 /** 12964 * Detaches from an internal event. 12965 * @protected 12966 * @param {HTMLElement} element - The event source. 12967 * @param {String} event - The event name. 12968 * @param {Function} listener - The attached event handler to detach. 12969 * @param {Boolean} capture - Wether the attached event handler was registered as a capturing listener or not. 12970 */ 12971 Owl.prototype.off = function(element, event, listener, capture) { 12972 if (element.removeEventListener) { 12973 element.removeEventListener(event, listener, capture); 12974 } else if (element.detachEvent) { 12975 element.detachEvent('on' + event, listener); 12976 } 12977 }; 12978 12979 /** 12980 * Triggers a public event. 12981 * @todo Remove `status`, `relatedTarget` should be used instead. 12982 * @protected 12983 * @param {String} name - The event name. 12984 * @param {*} [data=null] - The event data. 12985 * @param {String} [namespace=carousel] - The event namespace. 12986 * @param {String} [state] - The state which is associated with the event. 12987 * @param {Boolean} [enter=false] - Indicates if the call enters the specified state or not. 12988 * @returns {Event} - The event arguments. 12989 */ 12990 Owl.prototype.trigger = function(name, data, namespace, state, enter) { 12991 var status = { 12992 item: { count: this._items.length, index: this.current() } 12993 }, handler = $.camelCase( 12994 $.grep([ 'on', name, namespace ], function(v) { return v }) 12995 .join('-').toLowerCase() 12996 ), event = $.Event( 12997 [ name, 'owl', namespace || 'carousel' ].join('.').toLowerCase(), 12998 $.extend({ relatedTarget: this }, status, data) 12999 ); 13000 13001 if (!this._supress[name]) { 13002 $.each(this._plugins, function(name, plugin) { 13003 if (plugin.onTrigger) { 13004 plugin.onTrigger(event); 13005 } 13006 }); 13007 13008 this.register({ type: Owl.Type.Event, name: name }); 13009 this.$element.trigger(event); 13010 13011 if (this.settings && typeof this.settings[handler] === 'function') { 13012 this.settings[handler].call(this, event); 13013 } 13014 } 13015 13016 return event; 13017 }; 13018 13019 /** 13020 * Enters a state. 13021 * @param name - The state name. 13022 */ 13023 Owl.prototype.enter = function(name) { 13024 $.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) { 13025 if (this._states.current[name] === undefined) { 13026 this._states.current[name] = 0; 13027 } 13028 13029 this._states.current[name]++; 13030 }, this)); 13031 }; 13032 13033 /** 13034 * Leaves a state. 13035 * @param name - The state name. 13036 */ 13037 Owl.prototype.leave = function(name) { 13038 $.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) { 13039 this._states.current[name]--; 13040 }, this)); 13041 }; 13042 13043 /** 13044 * Registers an event or state. 13045 * @public 13046 * @param {Object} object - The event or state to register. 13047 */ 13048 Owl.prototype.register = function(object) { 13049 if (object.type === Owl.Type.Event) { 13050 if (!$.event.special[object.name]) { 13051 $.event.special[object.name] = {}; 13052 } 13053 13054 if (!$.event.special[object.name].owl) { 13055 var _default = $.event.special[object.name]._default; 13056 $.event.special[object.name]._default = function(e) { 13057 if (_default && _default.apply && (!e.namespace || e.namespace.indexOf('owl') === -1)) { 13058 return _default.apply(this, arguments); 13059 } 13060 return e.namespace && e.namespace.indexOf('owl') > -1; 13061 }; 13062 $.event.special[object.name].owl = true; 13063 } 13064 } else if (object.type === Owl.Type.State) { 13065 if (!this._states.tags[object.name]) { 13066 this._states.tags[object.name] = object.tags; 13067 } else { 13068 this._states.tags[object.name] = this._states.tags[object.name].concat(object.tags); 13069 } 13070 13071 this._states.tags[object.name] = $.grep(this._states.tags[object.name], $.proxy(function(tag, i) { 13072 return $.inArray(tag, this._states.tags[object.name]) === i; 13073 }, this)); 13074 } 13075 }; 13076 13077 /** 13078 * Suppresses events. 13079 * @protected 13080 * @param {Array.<String>} events - The events to suppress. 13081 */ 13082 Owl.prototype.suppress = function(events) { 13083 $.each(events, $.proxy(function(index, event) { 13084 this._supress[event] = true; 13085 }, this)); 13086 }; 13087 13088 /** 13089 * Releases suppressed events. 13090 * @protected 13091 * @param {Array.<String>} events - The events to release. 13092 */ 13093 Owl.prototype.release = function(events) { 13094 $.each(events, $.proxy(function(index, event) { 13095 delete this._supress[event]; 13096 }, this)); 13097 }; 13098 13099 /** 13100 * Gets unified pointer coordinates from event. 13101 * @todo #261 13102 * @protected 13103 * @param {Event} - The `mousedown` or `touchstart` event. 13104 * @returns {Object} - Contains `x` and `y` coordinates of current pointer position. 13105 */ 13106 Owl.prototype.pointer = function(event) { 13107 var result = { x: null, y: null }; 13108 13109 event = event.originalEvent || event || window.event; 13110 13111 event = event.touches && event.touches.length ? 13112 event.touches[0] : event.changedTouches && event.changedTouches.length ? 13113 event.changedTouches[0] : event; 13114 13115 if (event.pageX) { 13116 result.x = event.pageX; 13117 result.y = event.pageY; 13118 } else { 13119 result.x = event.clientX; 13120 result.y = event.clientY; 13121 } 13122 13123 return result; 13124 }; 13125 13126 /** 13127 * Gets the difference of two vectors. 13128 * @todo #261 13129 * @protected 13130 * @param {Object} - The first vector. 13131 * @param {Object} - The second vector. 13132 * @returns {Object} - The difference. 13133 */ 13134 Owl.prototype.difference = function(first, second) { 13135 return { 13136 x: first.x - second.x, 13137 y: first.y - second.y 13138 }; 13139 }; 13140 13141 /** 13142 * The jQuery Plugin for the Owl Carousel
vendor: 32,216 bytes, lines 13143-14425
13143 * @todo Navigation plugin `next` and `prev` 13144 * @public 13145 */ 13146 $.fn.owlCarousel = function(option) { 13147 var args = Array.prototype.slice.call(arguments, 1); 13148 13149 return this.each(function() { 13150 var $this = $(this), 13151 data = $this.data('owl.carousel'); 13152 13153 if (!data) { 13154 data = new Owl(this, typeof option == 'object' && option); 13155 $this.data('owl.carousel', data); 13156 13157 $.each([ 13158 'next', 'prev', 'to', 'destroy', 'refresh', 'replace', 'add', 'remove' 13159 ], function(i, event) { 13160 data.register({ type: Owl.Type.Event, name: event }); 13161 data.$element.on(event + '.owl.carousel.core', $.proxy(function(e) { 13162 if (e.namespace && e.relatedTarget !== this) { 13163 this.suppress([ event ]); 13164 data[event].apply(this, [].slice.call(arguments, 1)); 13165 this.release([ event ]); 13166 } 13167 }, data)); 13168 }); 13169 } 13170 13171 if (typeof option == 'string' && option.charAt(0) !== '_') { 13172 data[option].apply(data, args); 13173 } 13174 }); 13175 }; 13176 13177 /** 13178 * The constructor for the jQuery Plugin 13179 * @public 13180 */ 13181 $.fn.owlCarousel.Constructor = Owl; 13182 13183})(window.Zepto || window.jQuery, window, document); 13184 13185/** 13186 * AutoRefresh Plugin 13187 * @version 2.0.0-beta.3 13188 * @author Artus Kolanowski 13189 * @license The MIT License (MIT) 13190 */ 13191;(function($, window, document, undefined) { 13192 13193 /** 13194 * Creates the auto refresh plugin. 13195 * @class The Auto Refresh Plugin 13196 * @param {Owl} carousel - The Owl Carousel 13197 */ 13198 var AutoRefresh = function(carousel) { 13199 /** 13200 * Reference to the core. 13201 * @protected 13202 * @type {Owl} 13203 */ 13204 this._core = carousel; 13205 13206 /** 13207 * Refresh interval. 13208 * @protected 13209 * @type {number} 13210 */ 13211 this._interval = null; 13212 13213 /** 13214 * Whether the element is currently visible or not. 13215 * @protected 13216 * @type {Boolean} 13217 */ 13218 this._visible = null; 13219 13220 /** 13221 * All event handlers. 13222 * @protected 13223 * @type {Object} 13224 */ 13225 this._handlers = { 13226 'initialized.owl.carousel': $.proxy(function(e) { 13227 if (e.namespace && this._core.settings.autoRefresh) { 13228 this.watch(); 13229 } 13230 }, this) 13231 }; 13232 13233 // set default options 13234 this._core.options = $.extend({}, AutoRefresh.Defaults, this._core.options); 13235 13236 // register event handlers 13237 this._core.$element.on(this._handlers); 13238 }; 13239 13240 /** 13241 * Default options. 13242 * @public 13243 */ 13244 AutoRefresh.Defaults = { 13245 autoRefresh: true, 13246 autoRefreshInterval: 500 13247 }; 13248 13249 /** 13250 * Watches the element. 13251 */ 13252 AutoRefresh.prototype.watch = function() { 13253 if (this._interval) { 13254 return; 13255 } 13256 13257 this._visible = this._core.$element.is(':visible'); 13258 this._interval = window.setInterval($.proxy(this.refresh, this), this._core.settings.autoRefreshInterval); 13259 }; 13260 13261 /** 13262 * Refreshes the element. 13263 */ 13264 AutoRefresh.prototype.refresh = function() { 13265 if (this._core.$element.is(':visible') === this._visible) { 13266 return; 13267 } 13268 13269 this._visible = !this._visible; 13270 13271 this._core.$element.toggleClass('owl-hidden', !this._visible); 13272 13273 this._visible && (this._core.invalidate('width') && this._core.refresh()); 13274 }; 13275 13276 /** 13277 * Destroys the plugin. 13278 */ 13279 AutoRefresh.prototype.destroy = function() { 13280 var handler, property; 13281 13282 window.clearInterval(this._interval); 13283 13284 for (handler in this._handlers) { 13285 this._core.$element.off(handler, this._handlers[handler]); 13286 } 13287 for (property in Object.getOwnPropertyNames(this)) { 13288 typeof this[property] != 'function' && (this[property] = null); 13289 } 13290 }; 13291 13292 $.fn.owlCarousel.Constructor.Plugins.AutoRefresh = AutoRefresh; 13293 13294})(window.Zepto || window.jQuery, window, document); 13295 13296/** 13297 * Lazy Plugin 13298 * @version 2.0.0-beta.3 13299 * @author Bartosz Wojciechowski 13300 * @license The MIT License (MIT) 13301 */ 13302;(function($, window, document, undefined) { 13303 13304 /** 13305 * Creates the lazy plugin. 13306 * @class The Lazy Plugin 13307 * @param {Owl} carousel - The Owl Carousel 13308 */ 13309 var Lazy = function(carousel) { 13310 13311 /** 13312 * Reference to the core. 13313 * @protected 13314 * @type {Owl} 13315 */ 13316 this._core = carousel; 13317 13318 /** 13319 * Already loaded items. 13320 * @protected 13321 * @type {Array.<jQuery>} 13322 */ 13323 this._loaded = []; 13324 13325 /** 13326 * Event handlers. 13327 * @protected 13328 * @type {Object} 13329 */ 13330 this._handlers = { 13331 'initialized.owl.carousel change.owl.carousel': $.proxy(function(e) { 13332 if (!e.namespace) { 13333 return; 13334 } 13335 13336 if (!this._core.settings || !this._core.settings.lazyLoad) { 13337 return; 13338 } 13339 13340 if ((e.property && e.property.name == 'position') || e.type == 'initialized') { 13341 var settings = this._core.settings, 13342 n = (settings.center && Math.ceil(settings.items / 2) || settings.items), 13343 i = ((settings.center && n * -1) || 0), 13344 position = ((e.property && e.property.value) || this._core.current()) + i, 13345 clones = this._core.clones().length, 13346 load = $.proxy(function(i, v) { this.load(v) }, this); 13347 13348 while (i++ < n) { 13349 this.load(clones / 2 + this._core.relative(position)); 13350 clones && $.each(this._core.clones(this._core.relative(position)), load); 13351 position++; 13352 } 13353 } 13354 }, this) 13355 }; 13356 13357 // set the default options 13358 this._core.options = $.extend({}, Lazy.Defaults, this._core.options); 13359 13360 // register event handler 13361 this._core.$element.on(this._handlers); 13362 } 13363 13364 /** 13365 * Default options. 13366 * @public 13367 */ 13368 Lazy.Defaults = { 13369 lazyLoad: false 13370 } 13371 13372 /** 13373 * Loads all resources of an item at the specified position. 13374 * @param {Number} position - The absolute position of the item. 13375 * @protected 13376 */ 13377 Lazy.prototype.load = function(position) { 13378 var $item = this._core.$stage.children().eq(position), 13379 $elements = $item && $item.find('.owl-lazy'); 13380 13381 if (!$elements || $.inArray($item.get(0), this._loaded) > -1) { 13382 return; 13383 } 13384 13385 $elements.each($.proxy(function(index, element) { 13386 var $element = $(element), image, 13387 url = (window.devicePixelRatio > 1 && $element.attr('data-src-retina')) || $element.attr('data-src'); 13388 13389 this._core.trigger('load', { element: $element, url: url }, 'lazy'); 13390 13391 if ($element.is('img')) { 13392 $element.one('load.owl.lazy', $.proxy(function() { 13393 $element.css('opacity', 1); 13394 this._core.trigger('loaded', { element: $element, url: url }, 'lazy'); 13395 }, this)).attr('src', url); 13396 } else { 13397 image = new Image(); 13398 image.onload = $.proxy(function() { 13399 $element.css({ 13400 'background-image': 'url(' + url + ')', 13401 'opacity': '1' 13402 }); 13403 this._core.trigger('loaded', { element: $element, url: url }, 'lazy'); 13404 }, this); 13405 image.src = url; 13406 } 13407 }, this)); 13408 13409 this._loaded.push($item.get(0)); 13410 } 13411 13412 /** 13413 * Destroys the plugin. 13414 * @public 13415 */ 13416 Lazy.prototype.destroy = function() { 13417 var handler, property; 13418 13419 for (handler in this.handlers) { 13420 this._core.$element.off(handler, this.handlers[handler]); 13421 } 13422 for (property in Object.getOwnPropertyNames(this)) { 13423 typeof this[property] != 'function' && (this[property] = null); 13424 } 13425 }; 13426 13427 $.fn.owlCarousel.Constructor.Plugins.Lazy = Lazy; 13428 13429})(window.Zepto || window.jQuery, window, document); 13430 13431/** 13432 * AutoHeight Plugin 13433 * @version 2.0.0-beta.3 13434 * @author Bartosz Wojciechowski 13435 * @license The MIT License (MIT) 13436 */ 13437;(function($, window, document, undefined) { 13438 13439 /** 13440 * Creates the auto height plugin. 13441 * @class The Auto Height Plugin 13442 * @param {Owl} carousel - The Owl Carousel 13443 */ 13444 var AutoHeight = function(carousel) { 13445 /** 13446 * Reference to the core. 13447 * @protected 13448 * @type {Owl} 13449 */ 13450 this._core = carousel; 13451 13452 /** 13453 * All event handlers. 13454 * @protected 13455 * @type {Object} 13456 */ 13457 this._handlers = { 13458 'initialized.owl.carousel refreshed.owl.carousel': $.proxy(function(e) { 13459 if (e.namespace && this._core.settings.autoHeight) { 13460 this.update(); 13461 } 13462 }, this), 13463 'changed.owl.carousel': $.proxy(function(e) { 13464 if (e.namespace && this._core.settings.autoHeight && e.property.name == 'position'){ 13465 this.update(); 13466 } 13467 }, this), 13468 'loaded.owl.lazy': $.proxy(function(e) { 13469 if (e.namespace && this._core.settings.autoHeight 13470 && e.element.closest('.' + this._core.settings.itemClass).index() === this._core.current()) { 13471 this.update(); 13472 } 13473 }, this) 13474 }; 13475 13476 // set default options 13477 this._core.options = $.extend({}, AutoHeight.Defaults, this._core.options); 13478 13479 // register event handlers 13480 this._core.$element.on(this._handlers); 13481 }; 13482 13483 /** 13484 * Default options. 13485 * @public 13486 */ 13487 AutoHeight.Defaults = { 13488 autoHeight: false, 13489 autoHeightClass: 'owl-height' 13490 }; 13491 13492 /** 13493 * Updates the view. 13494 */ 13495 AutoHeight.prototype.update = function() { 13496 var start = this._core._current, 13497 end = start + this._core.settings.items, 13498 visible = this._core.$stage.children().toArray().slice(start, end); 13499 heights = [], 13500 maxheight = 0; 13501 13502 $.each(visible, function(index, item) { 13503 heights.push($(item).height()); 13504 }); 13505 13506 maxheight = Math.max.apply(null, heights); 13507 13508 this._core.$stage.parent() 13509 .height(maxheight) 13510 .addClass(this._core.settings.autoHeightClass); 13511 }; 13512 13513 AutoHeight.prototype.destroy = function() { 13514 var handler, property; 13515 13516 for (handler in this._handlers) { 13517 this._core.$element.off(handler, this._handlers[handler]); 13518 } 13519 for (property in Object.getOwnPropertyNames(this)) { 13520 typeof this[property] != 'function' && (this[property] = null); 13521 } 13522 }; 13523 13524 $.fn.owlCarousel.Constructor.Plugins.AutoHeight = AutoHeight; 13525 13526})(window.Zepto || window.jQuery, window, document); 13527 13528/** 13529 * Video Plugin 13530 * @version 2.0.0-beta.3 13531 * @author Bartosz Wojciechowski 13532 * @license The MIT License (MIT) 13533 */ 13534;(function($, window, document, undefined) { 13535 13536 /** 13537 * Creates the video plugin. 13538 * @class The Video Plugin 13539 * @param {Owl} carousel - The Owl Carousel 13540 */ 13541 var Video = function(carousel) { 13542 /** 13543 * Reference to the core. 13544 * @protected 13545 * @type {Owl} 13546 */ 13547 this._core = carousel; 13548 13549 /** 13550 * Cache all video URLs. 13551 * @protected 13552 * @type {Object} 13553 */ 13554 this._videos = {}; 13555 13556 /** 13557 * Current playing item. 13558 * @protected 13559 * @type {jQuery} 13560 */ 13561 this._playing = null; 13562 13563 /** 13564 * All event handlers. 13565 * @todo The cloned content removale is too late 13566 * @protected 13567 * @type {Object} 13568 */ 13569 this._handlers = { 13570 'initialized.owl.carousel': $.proxy(function(e) { 13571 if (e.namespace) { 13572 this._core.register({ type: 'state', name: 'playing', tags: [ 'interacting' ] }); 13573 } 13574 }, this), 13575 'resize.owl.carousel': $.proxy(function(e) { 13576 if (e.namespace && this._core.settings.video && this.isInFullScreen()) { 13577 e.preventDefault(); 13578 } 13579 }, this), 13580 'refreshed.owl.carousel': $.proxy(function(e) { 13581 if (e.namespace && this._core.is('resizing')) { 13582 this._core.$stage.find('.cloned .owl-video-frame').remove(); 13583 } 13584 }, this), 13585 'changed.owl.carousel': $.proxy(function(e) { 13586 if (e.namespace && e.property.name === 'position' && this._playing) { 13587 this.stop(); 13588 } 13589 }, this), 13590 'prepared.owl.carousel': $.proxy(function(e) { 13591 if (!e.namespace) { 13592 return; 13593 } 13594 13595 var $element = $(e.content).find('.owl-video'); 13596 13597 if ($element.length) { 13598 $element.css('display', 'none'); 13599 this.fetch($element, $(e.content)); 13600 } 13601 }, this) 13602 }; 13603 13604 // set default options 13605 this._core.options = $.extend({}, Video.Defaults, this._core.options); 13606 13607 // register event handlers 13608 this._core.$element.on(this._handlers); 13609 13610 this._core.$element.on('click.owl.video', '.owl-video-play-icon', $.proxy(function(e) { 13611 this.play(e); 13612 }, this)); 13613 }; 13614 13615 /** 13616 * Default options. 13617 * @public 13618 */ 13619 Video.Defaults = { 13620 video: false, 13621 videoHeight: false, 13622 videoWidth: false 13623 }; 13624 13625 /** 13626 * Gets the video ID and the type (YouTube/Vimeo only). 13627 * @protected 13628 * @param {jQuery} target - The target containing the video data. 13629 * @param {jQuery} item - The item containing the video. 13630 */ 13631 Video.prototype.fetch = function(target, item) { 13632 var type = target.attr('data-vimeo-id') ? 'vimeo' : 'youtube', 13633 id = target.attr('data-vimeo-id') || target.attr('data-youtube-id'), 13634 width = target.attr('data-width') || this._core.settings.videoWidth, 13635 height = target.attr('data-height') || this._core.settings.videoHeight, 13636 url = target.attr('href'); 13637 13638 if (url) { 13639 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+)?/); 13640 13641 if (id[3].indexOf('youtu') > -1) { 13642 type = 'youtube'; 13643 } else if (id[3].indexOf('vimeo') > -1) { 13644 type = 'vimeo'; 13645 } else { 13646 throw new Error('Video URL not supported.'); 13647 } 13648 id = id[6]; 13649 } else { 13650 throw new Error('Missing video URL.'); 13651 } 13652 13653 this._videos[url] = { 13654 type: type, 13655 id: id, 13656 width: width, 13657 height: height 13658 }; 13659 13660 item.attr('data-video', url); 13661 13662 this.thumbnail(target, this._videos[url]); 13663 }; 13664 13665 /** 13666 * Creates video thumbnail. 13667 * @protected 13668 * @param {jQuery} target - The target containing the video data. 13669 * @param {Object} info - The video info object. 13670 * @see `fetch` 13671 */ 13672 Video.prototype.thumbnail = function(target, video) { 13673 var tnLink, 13674 icon, 13675 path, 13676 dimensions = video.width && video.height ? 'style="width:' + video.width + 'px;height:' + video.height + 'px;"' : '', 13677 customTn = target.find('img'), 13678 srcType = 'src', 13679 lazyClass = '', 13680 settings = this._core.settings, 13681 create = function(path) { 13682 icon = '<div class="owl-video-play-icon"></div>'; 13683 13684 if (settings.lazyLoad) { 13685 tnLink = '<div class="owl-video-tn ' + lazyClass + '" ' + srcType + '="' + path + '"></div>'; 13686 } else { 13687 tnLink = '<div class="owl-video-tn" style="opacity:1;background-image:url(' + path + ')"></div>'; 13688 } 13689 target.after(tnLink); 13690 target.after(icon); 13691 }; 13692 13693 // wrap video content into owl-video-wrapper div 13694 target.wrap('<div class="owl-video-wrapper"' + dimensions + '></div>'); 13695 13696 if (this._core.settings.lazyLoad) { 13697 srcType = 'data-src'; 13698 lazyClass = 'owl-lazy'; 13699 } 13700 13701 // custom thumbnail 13702 if (customTn.length) { 13703 create(customTn.attr(srcType)); 13704 customTn.remove(); 13705 return false; 13706 } 13707 13708 if (video.type === 'youtube') { 13709 path = "//img.youtube.com/vi/" + video.id + "/hqdefault.jpg"; 13710 create(path); 13711 } else if (video.type === 'vimeo') { 13712 $.ajax({ 13713 type: 'GET', 13714 url: '//vimeo.com/api/v2/video/' + video.id + '.json', 13715 jsonp: 'callback', 13716 dataType: 'jsonp', 13717 success: function(data) { 13718 path = data[0].thumbnail_large; 13719 create(path); 13720 } 13721 }); 13722 } 13723 }; 13724 13725 /** 13726 * Stops the current video. 13727 * @public 13728 */ 13729 Video.prototype.stop = function() { 13730 this._core.trigger('stop', null, 'video'); 13731 this._playing.find('.owl-video-frame').remove(); 13732 this._playing.removeClass('owl-video-playing'); 13733 this._playing = null; 13734 this._core.leave('playing'); 13735 this._core.trigger('stopped', null, 'video'); 13736 }; 13737 13738 /** 13739 * Starts the current video. 13740 * @public 13741 * @param {Event} event - The event arguments. 13742 */ 13743 Video.prototype.play = function(event) { 13744 var target = $(event.target), 13745 item = target.closest('.' + this._core.settings.itemClass), 13746 video = this._videos[item.attr('data-video')], 13747 width = video.width || '100%', 13748 height = video.height || this._core.$stage.height(), 13749 html; 13750 13751 if (this._playing) { 13752 return; 13753 } 13754 13755 this._core.enter('playing'); 13756 this._core.trigger('play', null, 'video'); 13757 13758 item = this._core.items(this._core.relative(item.index())); 13759 13760 this._core.reset(item.index()); 13761 13762 if (video.type === 'youtube') { 13763 html = '<iframe width="' + width + '" height="' + height + '" src="//www.youtube.com/embed/' + 13764 video.id + '?autoplay=1&v=' + video.id + '" frameborder="0" allowfullscreen></iframe>'; 13765 } else if (video.type === 'vimeo') { 13766 html = '<iframe src="//player.vimeo.com/video/' + video.id + 13767 '?autoplay=1" width="' + width + '" height="' + height + 13768 '" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>'; 13769 } 13770 13771 $('<div class="owl-video-frame">' + html + '</div>').insertAfter(item.find('.owl-video')); 13772 13773 this._playing = item.addClass('owl-video-playing'); 13774 }; 13775 13776 /** 13777 * Checks whether an video is currently in full screen mode or not. 13778 * @todo Bad style because looks like a readonly method but changes members. 13779 * @protected 13780 * @returns {Boolean} 13781 */ 13782 Video.prototype.isInFullScreen = function() { 13783 var element = document.fullscreenElement || document.mozFullScreenElement || 13784 document.webkitFullscreenElement; 13785 13786 return element && $(element).parent().hasClass('owl-video-frame'); 13787 }; 13788 13789 /** 13790 * Destroys the plugin. 13791 */ 13792 Video.prototype.destroy = function() { 13793 var handler, property; 13794 13795 this._core.$element.off('click.owl.video'); 13796 13797 for (handler in this._handlers) { 13798 this._core.$element.off(handler, this._handlers[handler]); 13799 } 13800 for (property in Object.getOwnPropertyNames(this)) { 13801 typeof this[property] != 'function' && (this[property] = null); 13802 } 13803 }; 13804 13805 $.fn.owlCarousel.Constructor.Plugins.Video = Video; 13806 13807})(window.Zepto || window.jQuery, window, document); 13808 13809/** 13810 * Animate Plugin 13811 * @version 2.0.0-beta.3 13812 * @author Bartosz Wojciechowski 13813 * @license The MIT License (MIT) 13814 */ 13815;(function($, window, document, undefined) { 13816 13817 /** 13818 * Creates the animate plugin. 13819 * @class The Navigation Plugin 13820 * @param {Owl} scope - The Owl Carousel 13821 */ 13822 var Animate = function(scope) { 13823 this.core = scope; 13824 this.core.options = $.extend({}, Animate.Defaults, this.core.options); 13825 this.swapping = true; 13826 this.previous = undefined; 13827 this.next = undefined; 13828 13829 this.handlers = { 13830 'change.owl.carousel': $.proxy(function(e) { 13831 if (e.namespace && e.property.name == 'position') { 13832 this.previous = this.core.current(); 13833 this.next = e.property.value; 13834 } 13835 }, this), 13836 'drag.owl.carousel dragged.owl.carousel translated.owl.carousel': $.proxy(function(e) { 13837 if (e.namespace) { 13838 this.swapping = e.type == 'translated'; 13839 } 13840 }, this), 13841 'translate.owl.carousel': $.proxy(function(e) { 13842 if (e.namespace && this.swapping && (this.core.options.animateOut || this.core.options.animateIn)) { 13843 this.swap(); 13844 } 13845 }, this) 13846 }; 13847 13848 this.core.$element.on(this.handlers); 13849 }; 13850 13851 /** 13852 * Default options. 13853 * @public 13854 */ 13855 Animate.Defaults = { 13856 animateOut: false, 13857 animateIn: false 13858 }; 13859 13860 /** 13861 * Toggles the animation classes whenever an translations starts. 13862 * @protected 13863 * @returns {Boolean|undefined} 13864 */ 13865 Animate.prototype.swap = function() { 13866 13867 if (this.core.settings.items !== 1) { 13868 return; 13869 } 13870 13871 if (!$.support.animation || !$.support.transition) { 13872 return; 13873 } 13874 13875 this.core.speed(0); 13876 13877 var left, 13878 clear = $.proxy(this.clear, this), 13879 previous = this.core.$stage.children().eq(this.previous), 13880 next = this.core.$stage.children().eq(this.next), 13881 incoming = this.core.settings.animateIn, 13882 outgoing = this.core.settings.animateOut; 13883 13884 if (this.core.current() === this.previous) { 13885 return; 13886 } 13887 13888 if (outgoing) { 13889 left = this.core.coordinates(this.previous) - this.core.coordinates(this.next); 13890 previous.css( { 'left': left + 'px' } ) 13891 .addClass('animated owl-animated-out') 13892 .addClass(outgoing) 13893 .on($.support.animation.end, clear); 13894 } 13895 13896 if (incoming) { 13897 next.addClass('animated owl-animated-in') 13898 .addClass(incoming) 13899 .on($.support.animation.end, clear); 13900 } 13901 }; 13902 13903 Animate.prototype.clear = function(e) { 13904 if ($(e.target).hasClass('animated')) { 13905 $(e.target).css( { 'left': '' } ) 13906 .removeClass('animated owl-animated-out owl-animated-in') 13907 .removeClass(this.core.settings.animateIn) 13908 .removeClass(this.core.settings.animateOut); 13909 this.core.onTransitionEnd(); 13910 } 13911 }; 13912 13913 /** 13914 * Destroys the plugin. 13915 * @public 13916 */ 13917 Animate.prototype.destroy = function() { 13918 var handler, property; 13919 13920 for (handler in this.handlers) { 13921 this.core.$element.off(handler, this.handlers[handler]); 13922 } 13923 for (property in Object.getOwnPropertyNames(this)) { 13924 typeof this[property] != 'function' && (this[property] = null); 13925 } 13926 }; 13927 13928 $.fn.owlCarousel.Constructor.Plugins.Animate = Animate; 13929 13930})(window.Zepto || window.jQuery, window, document); 13931 13932/** 13933 * Autoplay Plugin 13934 * @version 2.0.0-beta.3 13935 * @author Bartosz Wojciechowski 13936 * @author Artus Kolanowski 13937 * @license The MIT License (MIT) 13938 */ 13939;(function($, window, document, undefined) { 13940 13941 /** 13942 * Creates the autoplay plugin. 13943 * @class The Autoplay Plugin 13944 * @param {Owl} scope - The Owl Carousel 13945 */ 13946 var Autoplay = function(carousel) { 13947 /** 13948 * Reference to the core. 13949 * @protected 13950 * @type {Owl} 13951 */ 13952 this._core = carousel; 13953 13954 /** 13955 * The autoplay interval. 13956 * @type {Number} 13957 */ 13958 this._interval = null; 13959 13960 /** 13961 * Indicates whenever the autoplay is paused. 13962 * @type {Boolean} 13963 */ 13964 this._paused = false; 13965 13966 /** 13967 * All event handlers. 13968 * @protected 13969 * @type {Object} 13970 */ 13971 this._handlers = { 13972 'changed.owl.carousel': $.proxy(function(e) { 13973 if (e.namespace && e.property.name === 'settings') { 13974 if (this._core.settings.autoplay) { 13975 this.play(); 13976 } else { 13977 this.stop(); 13978 } 13979 } 13980 }, this), 13981 'initialized.owl.carousel': $.proxy(function(e) { 13982 if (e.namespace && this._core.settings.autoplay) { 13983 this.play(); 13984 } 13985 }, this), 13986 'play.owl.autoplay': $.proxy(function(e, t, s) { 13987 if (e.namespace) { 13988 this.play(t, s); 13989 } 13990 }, this), 13991 'stop.owl.autoplay': $.proxy(function(e) { 13992 if (e.namespace) { 13993 this.stop(); 13994 } 13995 }, this), 13996 'mouseover.owl.autoplay': $.proxy(function() { 13997 if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) { 13998 this.pause(); 13999 } 14000 }, this), 14001 'mouseleave.owl.autoplay': $.proxy(function() { 14002 if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) { 14003 this.play(); 14004 } 14005 }, this) 14006 }; 14007 14008 // register event handlers 14009 this._core.$element.on(this._handlers); 14010 14011 // set default options 14012 this._core.options = $.extend({}, Autoplay.Defaults, this._core.options); 14013 }; 14014 14015 /** 14016 * Default options. 14017 * @public 14018 */ 14019 Autoplay.Defaults = { 14020 autoplay: false, 14021 autoplayTimeout: 5000, 14022 autoplayHoverPause: false, 14023 autoplaySpeed: false 14024 }; 14025 14026 /** 14027 * Starts the autoplay. 14028 * @public 14029 * @param {Number} [timeout] - The interval before the next animation starts. 14030 * @param {Number} [speed] - The animation speed for the animations. 14031 */ 14032 Autoplay.prototype.play = function(timeout, speed) { 14033 this._paused = false; 14034 14035 if (this._core.is('rotating')) { 14036 return; 14037 } 14038 14039 this._core.enter('rotating'); 14040 14041 this._interval = window.setInterval($.proxy(function() { 14042 if (this._paused || this._core.is('busy') || this._core.is('interacting') || document.hidden) { 14043 return; 14044 } 14045 this._core.next(speed || this._core.settings.autoplaySpeed); 14046 }, this), timeout || this._core.settings.autoplayTimeout); 14047 }; 14048 14049 /** 14050 * Stops the autoplay. 14051 * @public 14052 */ 14053 Autoplay.prototype.stop = function() { 14054 if (!this._core.is('rotating')) { 14055 return; 14056 } 14057 14058 window.clearInterval(this._interval); 14059 this._core.leave('rotating'); 14060 }; 14061 14062 /** 14063 * Stops the autoplay. 14064 * @public 14065 */ 14066 Autoplay.prototype.pause = function() { 14067 if (!this._core.is('rotating')) { 14068 return; 14069 } 14070 14071 this._paused = true; 14072 }; 14073 14074 /** 14075 * Destroys the plugin. 14076 */ 14077 Autoplay.prototype.destroy = function() { 14078 var handler, property; 14079 14080 this.stop(); 14081 14082 for (handler in this._handlers) { 14083 this._core.$element.off(handler, this._handlers[handler]); 14084 } 14085 for (property in Object.getOwnPropertyNames(this)) { 14086 typeof this[property] != 'function' && (this[property] = null); 14087 } 14088 }; 14089 14090 $.fn.owlCarousel.Constructor.Plugins.autoplay = Autoplay; 14091 14092})(window.Zepto || window.jQuery, window, document); 14093 14094/** 14095 * Navigation Plugin 14096 * @version 2.0.0-beta.3 14097 * @author Artus Kolanowski 14098 * @license The MIT License (MIT) 14099 */ 14100;(function($, window, document, undefined) { 14101 'use strict'; 14102 14103 /** 14104 * Creates the navigation plugin. 14105 * @class The Navigation Plugin 14106 * @param {Owl} carousel - The Owl Carousel. 14107 */ 14108 var Navigation = function(carousel) { 14109 /** 14110 * Reference to the core. 14111 * @protected 14112 * @type {Owl} 14113 */ 14114 this._core = carousel; 14115 14116 /** 14117 * Indicates whether the plugin is initialized or not. 14118 * @protected 14119 * @type {Boolean} 14120 */ 14121 this._initialized = false; 14122 14123 /** 14124 * The current paging indexes. 14125 * @protected 14126 * @type {Array} 14127 */ 14128 this._pages = []; 14129 14130 /** 14131 * All DOM elements of the user interface. 14132 * @protected 14133 * @type {Object} 14134 */ 14135 this._controls = {}; 14136 14137 /** 14138 * Markup for an indicator. 14139 * @protected 14140 * @type {Array.<String>} 14141 */ 14142 this._templates = []; 14143 14144 /** 14145 * The carousel element. 14146 * @type {jQuery} 14147 */ 14148 this.$element = this._core.$element; 14149 14150 /** 14151 * Overridden methods of the carousel. 14152 * @protected 14153 * @type {Object} 14154 */ 14155 this._overrides = { 14156 next: this._core.next, 14157 prev: this._core.prev, 14158 to: this._core.to 14159 }; 14160 14161 /** 14162 * All event handlers. 14163 * @protected 14164 * @type {Object} 14165 */ 14166 this._handlers = { 14167 'prepared.owl.carousel': $.proxy(function(e) { 14168 if (e.namespace && this._core.settings.dotsData) { 14169 this._templates.push('<div class="' + this._core.settings.dotClass + '">' + 14170 $(e.content).find('[data-dot]').andSelf('[data-dot]').attr('data-dot') + '</div>'); 14171 } 14172 }, this), 14173 'added.owl.carousel': $.proxy(function(e) { 14174 if (e.namespace && this._core.settings.dotsData) { 14175 this._templates.splice(e.position, 0, this._templates.pop()); 14176 } 14177 }, this), 14178 'remove.owl.carousel': $.proxy(function(e) { 14179 if (e.namespace && this._core.settings.dotsData) { 14180 this._templates.splice(e.position, 1); 14181 } 14182 }, this), 14183 'changed.owl.carousel': $.proxy(function(e) { 14184 if (e.namespace && e.property.name == 'position') { 14185 this.draw(); 14186 } 14187 }, this), 14188 'initialized.owl.carousel': $.proxy(function(e) { 14189 if (e.namespace && !this._initialized) { 14190 this._core.trigger('initialize', null, 'navigation'); 14191 this.initialize(); 14192 this.update(); 14193 this.draw(); 14194 this._initialized = true; 14195 this._core.trigger('initialized', null, 'navigation'); 14196 } 14197 }, this), 14198 'refreshed.owl.carousel': $.proxy(function(e) { 14199 if (e.namespace && this._initialized) { 14200 this._core.trigger('refresh', null, 'navigation'); 14201 this.update(); 14202 this.draw(); 14203 this._core.trigger('refreshed', null, 'navigation'); 14204 } 14205 }, this) 14206 }; 14207 14208 // set default options 14209 this._core.options = $.extend({}, Navigation.Defaults, this._core.options); 14210 14211 // register event handlers 14212 this.$element.on(this._handlers); 14213 }; 14214 14215 /** 14216 * Default options. 14217 * @public 14218 * @todo Rename `slideBy` to `navBy` 14219 */ 14220 Navigation.Defaults = { 14221 nav: false, 14222 navText: [ 'prev', 'next' ], 14223 navSpeed: false, 14224 navElement: 'div', 14225 navContainer: false, 14226 navContainerClass: 'owl-nav', 14227 navClass: [ 'owl-prev', 'owl-next' ], 14228 slideBy: 1, 14229 dotClass: 'owl-dot', 14230 dotsClass: 'owl-dots', 14231 dots: true, 14232 dotsEach: false, 14233 dotsData: false, 14234 dotsSpeed: false, 14235 dotsContainer: false 14236 }; 14237 14238 /** 14239 * Initializes the layout of the plugin and extends the carousel. 14240 * @protected 14241 */ 14242 Navigation.prototype.initialize = function() { 14243 var override, 14244 settings = this._core.settings; 14245 14246 // create DOM structure for relative navigation 14247 this._controls.$relative = (settings.navContainer ? $(settings.navContainer) 14248 : $('<div>').addClass(settings.navContainerClass).appendTo(this.$element)).addClass('disabled'); 14249 14250 this._controls.$previous = $('<' + settings.navElement + '>') 14251 .addClass(settings.navClass[0]) 14252 .html(settings.navText[0]) 14253 .prependTo(this._controls.$relative) 14254 .on('click', $.proxy(function(e) { 14255 this.prev(settings.navSpeed); 14256 }, this)); 14257 this._controls.$next = $('<' + settings.navElement + '>') 14258 .addClass(settings.navClass[1]) 14259 .html(settings.navText[1]) 14260 .appendTo(this._controls.$relative) 14261 .on('click', $.proxy(function(e) { 14262 this.next(settings.navSpeed); 14263 }, this)); 14264 14265 // create DOM structure for absolute navigation 14266 if (!settings.dotsData) { 14267 this._templates = [ $('<div>') 14268 .addClass(settings.dotClass) 14269 .append($('<span>')) 14270 .prop('outerHTML') ]; 14271 } 14272 14273 this._controls.$absolute = (settings.dotsContainer ? $(settings.dotsContainer) 14274 : $('<div>').addClass(settings.dotsClass).appendTo(this.$element)).addClass('disabled'); 14275 14276 this._controls.$absolute.on('click', 'div', $.proxy(function(e) { 14277 var index = $(e.target).parent().is(this._controls.$absolute) 14278 ? $(e.target).index() : $(e.target).parent().index(); 14279 14280 e.preventDefault(); 14281 14282 this.to(index, settings.dotsSpeed); 14283 }, this)); 14284 14285 // override public methods of the carousel 14286 for (override in this._overrides) { 14287 this._core[override] = $.proxy(this[override], this); 14288 } 14289 }; 14290 14291 /** 14292 * Destroys the plugin. 14293 * @protected 14294 */ 14295 Navigation.prototype.destroy = function() { 14296 var handler, control, property, override; 14297 14298 for (handler in this._handlers) { 14299 this.$element.off(handler, this._handlers[handler]); 14300 } 14301 for (control in this._controls) { 14302 this._controls[control].remove(); 14303 } 14304 for (override in this.overides) { 14305 this._core[override] = this._overrides[override]; 14306 } 14307 for (property in Object.getOwnPropertyNames(this)) { 14308 typeof this[property] != 'function' && (this[property] = null); 14309 } 14310 }; 14311 14312 /** 14313 * Updates the internal state. 14314 * @protected 14315 */ 14316 Navigation.prototype.update = function() { 14317 var i, j, k, 14318 lower = this._core.clones().length / 2, 14319 upper = lower + this._core.items().length, 14320 maximum = this._core.maximum(true), 14321 settings = this._core.settings, 14322 size = settings.center || settings.autoWidth || settings.dotsData 14323 ? 1 : settings.dotsEach || settings.items; 14324 14325 if (settings.slideBy !== 'page') { 14326 settings.slideBy = Math.min(settings.slideBy, settings.items); 14327 } 14328 14329 if (settings.dots || settings.slideBy == 'page') { 14330 this._pages = []; 14331 14332 for (i = lower, j = 0, k = 0; i < upper; i++) { 14333 if (j >= size || j === 0) { 14334 this._pages.push({ 14335 start: Math.min(maximum, i - lower), 14336 end: i - lower + size - 1 14337 }); 14338 if (Math.min(maximum, i - lower) === maximum) { 14339 break; 14340 } 14341 j = 0, ++k; 14342 } 14343 j += this._core.mergers(this._core.relative(i)); 14344 } 14345 } 14346 }; 14347 14348 /** 14349 * Draws the user interface. 14350 * @todo The option `dotsData` wont work. 14351 * @protected 14352 */ 14353 Navigation.prototype.draw = function() { 14354 var difference, 14355 settings = this._core.settings, 14356 disabled = this._core.items().length <= settings.items, 14357 index = this._core.relative(this._core.current()), 14358 loop = settings.loop || settings.rewind; 14359 14360 this._controls.$relative.toggleClass('disabled', !settings.nav || disabled); 14361 14362 if (settings.nav) { 14363 this._controls.$previous.toggleClass('disabled', !loop && index <= this._core.minimum(true)); 14364 this._controls.$next.toggleClass('disabled', !loop && index >= this._core.maximum(true)); 14365 } 14366 14367 this._controls.$absolute.toggleClass('disabled', !settings.dots || disabled); 14368 14369 if (settings.dots) { 14370 difference = this._pages.length - this._controls.$absolute.children().length; 14371 14372 if (settings.dotsData && difference !== 0) { 14373 this._controls.$absolute.html(this._templates.join('')); 14374 } else if (difference > 0) { 14375 this._controls.$absolute.append(new Array(difference + 1).join(this._templates[0])); 14376 } else if (difference < 0) { 14377 this._controls.$absolute.children().slice(difference).remove(); 14378 } 14379 14380 this._controls.$absolute.find('.active').removeClass('active'); 14381 this._controls.$absolute.children().eq($.inArray(this.current(), this._pages)).addClass('active'); 14382 } 14383 }; 14384 14385 /** 14386 * Extends event data. 14387 * @protected 14388 * @param {Event} event - The event object which gets thrown. 14389 */ 14390 Navigation.prototype.onTrigger = function(event) { 14391 var settings = this._core.settings; 14392 14393 event.page = { 14394 index: $.inArray(this.current(), this._pages), 14395 count: this._pages.length, 14396 size: settings && (settings.center || settings.autoWidth || settings.dotsData 14397 ? 1 : settings.dotsEach || settings.items) 14398 }; 14399 }; 14400 14401 /** 14402 * Gets the current page position of the carousel. 14403 * @protected 14404 * @returns {Number} 14405 */ 14406 Navigation.prototype.current = function() { 14407 var current = this._core.relative(this._core.current()); 14408 return $.grep(this._pages, $.proxy(function(page, index) { 14409 return page.start <= current && page.end >= current; 14410 }, this)).pop(); 14411 }; 14412 14413 /** 14414 * Gets the current succesor/predecessor position. 14415 * @protected 14416 * @returns {Number} 14417 */ 14418 Navigation.prototype.getPosition = function(successor) { 14419 var position, length, 14420 settings = this._core.settings; 14421 14422 if (settings.slideBy == 'page') { 14423 position = $.inArray(this.current(), this._pages); 14424 length = this._pages.length; 14425 successor ? ++position : --position;
vendor: 5,678 bytes, lines 14426-14650
14426 position = this._pages[((position % length) + length) % length].start; 14427 } else { 14428 position = this._core.relative(this._core.current()); 14429 length = this._core.items().length; 14430 successor ? position += settings.slideBy : position -= settings.slideBy; 14431 } 14432 14433 return position; 14434 }; 14435 14436 /** 14437 * Slides to the next item or page. 14438 * @public 14439 * @param {Number} [speed=false] - The time in milliseconds for the transition. 14440 */ 14441 Navigation.prototype.next = function(speed) { 14442 $.proxy(this._overrides.to, this._core)(this.getPosition(true), speed); 14443 }; 14444 14445 /** 14446 * Slides to the previous item or page. 14447 * @public 14448 * @param {Number} [speed=false] - The time in milliseconds for the transition. 14449 */ 14450 Navigation.prototype.prev = function(speed) { 14451 $.proxy(this._overrides.to, this._core)(this.getPosition(false), speed); 14452 }; 14453 14454 /** 14455 * Slides to the specified item or page. 14456 * @public 14457 * @param {Number} position - The position of the item or page. 14458 * @param {Number} [speed] - The time in milliseconds for the transition. 14459 * @param {Boolean} [standard=false] - Whether to use the standard behaviour or not. 14460 */ 14461 Navigation.prototype.to = function(position, speed, standard) { 14462 var length; 14463 14464 if (!standard) { 14465 length = this._pages.length; 14466 $.proxy(this._overrides.to, this._core)(this._pages[((position % length) + length) % length].start, speed); 14467 } else { 14468 $.proxy(this._overrides.to, this._core)(position, speed); 14469 } 14470 }; 14471 14472 $.fn.owlCarousel.Constructor.Plugins.Navigation = Navigation; 14473 14474})(window.Zepto || window.jQuery, window, document); 14475 14476/** 14477 * Hash Plugin 14478 * @version 2.0.0-beta.3 14479 * @author Artus Kolanowski 14480 * @license The MIT License (MIT) 14481 */ 14482;(function($, window, document, undefined) { 14483 'use strict'; 14484 14485 /** 14486 * Creates the hash plugin. 14487 * @class The Hash Plugin 14488 * @param {Owl} carousel - The Owl Carousel 14489 */ 14490 var Hash = function(carousel) { 14491 /** 14492 * Reference to the core. 14493 * @protected 14494 * @type {Owl} 14495 */ 14496 this._core = carousel; 14497 14498 /** 14499 * Hash index for the items. 14500 * @protected 14501 * @type {Object} 14502 */ 14503 this._hashes = {}; 14504 14505 /** 14506 * The carousel element. 14507 * @type {jQuery} 14508 */ 14509 this.$element = this._core.$element; 14510 14511 /** 14512 * All event handlers. 14513 * @protected 14514 * @type {Object} 14515 */ 14516 this._handlers = { 14517 /*'initialized.owl.carousel': $.proxy(function(e) { 14518 if (e.namespace && this._core.settings.startPosition === 'URLHash') { 14519 $(window).trigger('hashchange.owl.navigation'); 14520 } 14521 }, this),*/ 14522 'prepared.owl.carousel': $.proxy(function(e) { 14523 if (e.namespace) { 14524 var hash = $(e.content).find('[data-hash]').addBack('[data-hash]').attr('data-hash'); 14525 14526 if (!hash) { 14527 return; 14528 } 14529 14530 this._hashes[hash] = e.content; 14531 } 14532 }, this), 14533 'changed.owl.carousel': $.proxy(function(e) { 14534 if (e.namespace && e.property.name === 'position') { 14535 var current = this._core.items(this._core.relative(this._core.current())), 14536 hash = $.map(this._hashes, function(item, hash) { 14537 return item === current ? hash : null; 14538 }).join(); 14539 14540 if (!hash || window.location.hash.slice(1) === hash) { 14541 return; 14542 } 14543 14544 window.location.hash = hash; 14545 } 14546 }, this) 14547 }; 14548 14549 // set default options 14550 this._core.options = $.extend({}, Hash.Defaults, this._core.options); 14551 14552 // register the event handlers 14553 this.$element.on(this._handlers); 14554 14555 // register event listener for hash navigation 14556 /*$(window).on('hashchange.owl.navigation', $.proxy(function(e) { 14557 var hash = window.location.hash.substring(1), 14558 items = this._core.$stage.children(), 14559 position = this._hashes[hash] && items.index(this._hashes[hash]); 14560 14561 if (position === undefined || position === this._core.current()) { 14562 return; 14563 } 14564 14565 this._core.to(this._core.relative(position), false, true); 14566 }, this));*/ 14567 }; 14568 14569 /** 14570 * Default options. 14571 * @public 14572 */ 14573 Hash.Defaults = { 14574 URLhashListener: false 14575 }; 14576 14577 /** 14578 * Destroys the plugin. 14579 * @public 14580 */ 14581 Hash.prototype.destroy = function() { 14582 var handler, property; 14583 14584 $(window).off('hashchange.owl.navigation'); 14585 14586 for (handler in this._handlers) { 14587 this._core.$element.off(handler, this._handlers[handler]); 14588 } 14589 for (property in Object.getOwnPropertyNames(this)) { 14590 typeof this[property] != 'function' && (this[property] = null); 14591 } 14592 }; 14593 14594 $.fn.owlCarousel.Constructor.Plugins.Hash = Hash; 14595 14596})(window.Zepto || window.jQuery, window, document); 14597 14598/** 14599 * Support Plugin 14600 * 14601 * @version 2.0.0-beta.3 14602 * @author Vivid Planet Software GmbH 14603 * @author Artus Kolanowski 14604 * @license The MIT License (MIT) 14605 */ 14606;(function($, window, document, undefined) { 14607 14608 var style = $('<support>').get(0).style, 14609 prefixes = 'Webkit Moz O ms'.split(' '), 14610 events = { 14611 transition: { 14612 end: { 14613 WebkitTransition: 'webkitTransitionEnd', 14614 MozTransition: 'transitionend', 14615 OTransition: 'oTransitionEnd', 14616 transition: 'transitionend' 14617 } 14618 }, 14619 animation: { 14620 end: { 14621 WebkitAnimation: 'webkitAnimationEnd', 14622 MozAnimation: 'animationend', 14623 OAnimation: 'oAnimationEnd', 14624 animation: 'animationend' 14625 } 14626 } 14627 }, 14628 tests = { 14629 csstransforms: function() { 14630 return !!test('transform'); 14631 }, 14632 csstransforms3d: function() { 14633 return !!test('perspective'); 14634 }, 14635 csstransitions: function() { 14636 return !!test('transition'); 14637 }, 14638 cssanimations: function() { 14639 return !!test('animation'); 14640 } 14641 }; 14642 14643 function test(property, prefixed) { 14644 var result = false, 14645 upper = property.charAt(0).toUpperCase() + property.slice(1); 14646 14647 $.each((property + ' ' + prefixes.join(upper + ' ') + upper).split(' '), function(i, property) { 14648 if (style[property] !== undefined) { 14649 result = prefixed ? property : true; 14650 return false;
14651 } 14652 }); 14653 14654 return result; 14655 } 14656 14657 function prefixed(property) { 14658 return test(property, true); 14659 } 14660 14661 if (tests.csstransitions()) { 14662 /* jshint -W053 */ 14663 $.support.transition = new String(prefixed('transition')) 14664 $.support.transition.end = events.transition.end[ $.support.transition ]; 14665 } 14666 14667 if (tests.cssanimations()) { 14668 /* jshint -W053 */ 14669 $.support.animation = new String(prefixed('animation')) 14670 $.support.animation.end = events.animation.end[ $.support.animation ]; 14671 } 14672 14673 if (tests.csstransforms()) { 14674 /* jshint -W053 */ 14675 $.support.transform = new String(prefixed('transform')); 14676 $.support.transform3d = tests.csstransforms3d(); 14677 } 14678 14679})(window.Zepto || window.jQuery, window, document); 14680 14681(function(window, document, undefined) { 14682 14683 /** 14684 * Find the absolute position of an element 14685 */ 14686 var absPos = function(element) { 14687 var offsetLeft, offsetTop; 14688 offsetLeft = offsetTop = 0; 14689 if (element.offsetParent) { 14690 do { 14691 offsetLeft += element.offsetLeft; 14692 offsetTop += element.offsetTop; 14693 } while (element = element.offsetParent); 14694 } 14695 return [offsetLeft, offsetTop]; 14696 }; 14697 14698 /** 14699 * @constructor Progress Circle class 14700 * @param params.canvas Canvas on which the circles will be drawn. 14701 * @param params.minRadius Inner radius of the innermost circle, in px. 14702 * @param params.arcWidth Width of each circle(to be more accurate, ring). 14703 * @param params.gapWidth Space between each circle. 14704 * @param params.centerX X coordinate of the center of circles. 14705 * @param params.centerY Y coordinate of the center of circles. 14706 * @param params.infoLineBaseAngle Base angle of the info line. 14707 * @param params.infoLineAngleInterval Angles between the info lines. 14708 */ 14709 var ProgressCircle = function(params) { 14710 this.canvas = params.canvas; 14711 this.minRadius = params.minRadius || 15; 14712 this.arcWidth = params.arcWidth || 5; 14713 this.gapWidth = params.gapWidth || 3; 14714 this.centerX = params.centerX || this.canvas.width / 2; 14715 this.centerY = params.centerY || this.canvas.height / 2;
14716 this.infoLineLength = params.infoLineLength || 60; 14717 this.horizLineLength = params.horizLineLength || 10; 14718 this.infoLineAngleInterval = params.infoLineAngleInterval || Math.PI / 8; 14719 this.infoLineBaseAngle = params.infoLineBaseAngle || Math.PI / 6; 14720 14721 this.context = this.canvas.getContext('2d'); 14722 14723 this.width = this.canvas.width; 14724 this.height = this.canvas.height; 14725 14726 this.circles = []; 14727 this.runningCount = 0; 14728 }; 14729 14730 ProgressCircle.prototype = { 14731 constructor: ProgressCircle, 14732 14733 /** 14734 * @method Adds an progress monitor entry. 14735 * @param params.fillColor Color to fill in the circle. 14736 * @param params.outlineColor Color to outline the circle. 14737 * @param params.progressListener Callback function to fetch the progress. 14738 * @param params.infoListener Callback function to fetch the info. 14739 * @returns this 14740 */ 14741 addEntry: function(params) { 14742 this.circles.push(new Circle({ 14743 canvas: this.canvas, 14744 context: this.context, 14745 centerX: this.centerX, 14746 centerY: this.centerY, 14747 innerRadius: this.minRadius + this.circles.length * 14748 (this.gapWidth + this.arcWidth), 14749 arcWidth: this.arcWidth,
14750 infoLineLength: this.infoLineLength, 14751 horizLineLength: this.horizLineLength, 14752 14753 id: this.circles.length, 14754 fillColor: params.fillColor, 14755 outlineColor: params.outlineColor, 14756 progressListener: params.progressListener, 14757 infoListener: params.infoListener, 14758 infoLineAngle: this.infoLineBaseAngle + 14759 this.circles.length * this.infoLineAngleInterval, 14760 })); 14761 14762 return this; 14763 }, 14764 14765 /** 14766 * @method Starts the monitor and updates with the given interval. 14767 * @param interval Interval between updates, in millisecond. 14768 * @returns this 14769 */ 14770 start: function(interval) { 14771 var self = this; 14772 this.timer = setInterval(function() { 14773 self._update(); 14774 }, interval || 33); 14775 14776 return this; 14777 }, 14778 14779 /** 14780 * @method Stop the animation. 14781 */ 14782 stop: function() { 14783 clearTimeout(this.timer); 14784 }, 14785 14786 /** 14787 * @private 14788 * @method Call update on each circle and redraw them. 14789 * @returns this 14790 */ 14791 _update: function() { 14792 this._clear(); 14793 this.circles.forEach(function(circle, idx, array) { 14794 circle.update(); 14795 }); 14796 14797 return this; 14798 }, 14799 14800 /** 14801 * @private 14802 * @method Clear the canvas. 14803 * @returns this 14804 */ 14805 _clear: function() { 14806 this.context.clearRect(0, 0, this.canvas.width, this.canvas.height); 14807 14808 return this; 14809 }, 14810 14811 }; 14812 14813 /** 14814 * @private 14815 * @class Individual progress circle. 14816 * @param params.canvas Canvas on which the circle will be drawn. 14817 * @param params.context Context of the canvas. 14818 * @param params.innerRadius Inner radius of the circle, in px. 14819 * @param params.arcWidth Width of each arc(circle). 14820 * @param params.gapWidth Distance between each arc. 14821 * @param params.centerX X coordinate of the center of circles. 14822 * @param params.centerY Y coordinate of the center of circles. 14823 * @param params.fillColor Color to fill in the circle. 14824 * @param params.outlineColor Color to outline the circle. 14825 * @param params.progressListener Callback function to fetch the progress. 14826 * @param params.infoListener Callback function to fetch the info. 14827 * @param params.infoLineAngle Angle of info line. 14828 */ 14829 var Circle = function(params) { 14830 this.id = params.id; 14831 this.canvas = params.canvas; 14832 this.context = params.context; 14833 this.centerX = params.centerX; 14834 this.centerY = params.centerY; 14835 this.arcWidth = params.arcWidth; 14836 this.innerRadius = params.innerRadius || 0; 14837 this.fillColor = params.fillColor || '#fff'; 14838 this.outlineColor = params.outlineColor || this.fillColor; 14839 this.progressListener = params.progressListener;
14840 this.infoLineLength = params.infoLineLength || 250; 14841 this.horizLineLength = params.horizLineLength || 50; 14842 this.infoListener = params.infoListener; 14843 this.infoLineAngle = params.infoLineAngle; 14844 14845 this.outerRadius = this.innerRadius + this.arcWidth; 14846 14847 // If the info listener is not registered, then don't calculate 14848 // the related coordinates 14849 if (!this.infoListener) return; 14850 14851 // calculate the info-line turning points 14852 var angle = this.infoLineAngle, 14853 arcDistance = (this.innerRadius + this.outerRadius) / 2, 14854 14855 sinA = Math.sin(angle), 14856 cosA = Math.cos(angle); 14857 14858 this.infoLineStartX = this.centerX + sinA * arcDistance; 14859 this.infoLineStartY = this.centerY - cosA * arcDistance; 14860 14861 this.infoLineMidX = this.centerX + sinA * this.infoLineLength; 14862 this.infoLineMidY = this.centerY - cosA * this.infoLineLength; 14863 14864 this.infoLineEndX = this.infoLineMidX + 14865 (sinA < 0 ? -this.horizLineLength : this.horizLineLength); 14866 this.infoLineEndY = this.infoLineMidY; 14867 14868 var infoText = document.createElement('div'), 14869 style = infoText.style; 14870 14871 style.color = this.fillColor; 14872 style.position = 'absolute'; 14873 style.left = this.infoLineEndX + absPos(this.canvas)[0] + 'px'; 14874 // style.top will be calculated in the `drawInfo` method. Since 14875 // user may want to change the size of the font, so the top offset 14876 // must be updated in each loop. 14877 infoText.className = 'ProgressCircleInfo'; // For css styling 14878 infoText.id = 'progress_circle_info_' + this.id; 14879 document.body.appendChild(infoText); 14880 this.infoText = infoText; 14881 }; 14882 14883 Circle.prototype = { 14884 constructor: Circle, 14885 14886 update: function() { 14887 this.progress = this.progressListener(); 14888 this._draw(); 14889 14890 if (this.infoListener) { 14891 this.info = this.infoListener(); 14892 this._drawInfo(); 14893 } 14894 }, 14895 14896 /** 14897 * @private 14898 * @method Draw the circle on the canvas. 14899 * @returns this 14900 */ 14901 _draw: function() { 14902 var ctx = this.context, 14903 14904 ANGLE_OFFSET = -Math.PI / 2, 14905 14906 startAngle = 0 + ANGLE_OFFSET, 14907 endAngle= startAngle + this.progress * Math.PI * 2, 14908 14909 x = this.centerX, 14910 y = this.centerY, 14911 14912 innerRadius = this.innerRadius - this.arcWidth - 1, 14913 outerRadius = this.outerRadius - this.arcWidth - 1; 14914 14915 if ( innerRadius < 0 ) 14916 return; 14917 14918 ctx.fillStyle = this.fillColor; 14919 ctx.strokeStyle = this.outlineColor; 14920 14921 ctx.beginPath(); 14922 ctx.arc(x, y, innerRadius, startAngle, endAngle, false); 14923 ctx.arc(x, y, outerRadius, endAngle, startAngle, true); 14924 ctx.closePath(); 14925 ctx.stroke(); 14926 ctx.fill(); 14927 14928 return this; 14929 }, 14930 14931 /** 14932 * @private 14933 * @method Draw the info lines and info text. 14934 * @returns this 14935 */ 14936 _drawInfo: function() { 14937 14938 var pointList, lineHeight; 14939 14940 pointList = [ 14941 [this.infoLineStartX, this.infoLineStartY], 14942 [this.infoLineMidX, this.infoLineMidY], 14943 [this.infoLineEndX, this.infoLineEndY], 14944 ]; 14945 this._drawSegments(pointList, false); 14946 14947 this.infoText.innerHTML = this.info; 14948 14949 lineHeight = this.infoText.offsetHeight; 14950 this.infoText.style.top = this.infoLineEndY + 14951 absPos(this.canvas)[1] - lineHeight / 2 + 'px'; 14952 14953 return this; 14954 }, 14955 14956 /** 14957 * @private 14958 * @method Helper function to draw the segments 14959 * @param pointList An array of points in the form of [x, y]. 14960 * @param close Whether to connect the first and last point. 14961 */ 14962 _drawSegments: function(pointList, close) { 14963 var ctx = this.context; 14964 14965 ctx.beginPath(); 14966 ctx.moveTo(pointList[0][0], pointList[0][1]); 14967 for (var i = 1; i < pointList.length; ++i) { 14968 ctx.lineTo(pointList[i][0], pointList[i][1]); 14969 } 14970 14971 if (close) { 14972 ctx.closePath(); 14973 } 14974 ctx.stroke(); 14975 }, 14976 }; 14977 14978 window.ProgressCircle = ProgressCircle; 14979 14980})(window, document); 14981 14982 14983 14984 14985/* ========================================================= 14986 * jquery.vc_chart.js v1.0 14987 * ========================================================= 14988 * Copyright 2013 Wpbakery 14989 * 14990 * Jquery chart plugin for the Visual Composer. 14991 * ========================================================= */ 14992(function($){ 14993 /** 14994 * Pie chart animated. 14995 * @param element - DOM element 14996 * @param options - settings object. 14997 * @constructor 14998 */ 14999 var VcChart = function(element, options) { 15000 this.el = element; 15001 this.$el = $(this.el); 15002 var $this = this; 15003 $this.options = $.extend({ 15004 color: 'wpb_button', 15005 units: '', 15006 width: '', 15007 label_selector: '.vc_pie_chart_value', 15008 back_selector: '.vc_pie_chart_back', 15009 responsive: true 15010 }, options); 15011 $this.init(); 15012 }; 15013 VcChart.prototype = { 15014 constructor: VcChart, 15015 _progress_v: 0, 15016 animated: false, 15017 colors: { 15018 'wpb_button': 'rgba(247, 247, 247, 1)', 15019 'btn-primary': 'rgba(0, 136, 204, 1)', 15020 'btn-info': 'rgba(88, 185, 218, 1)', 15021 'btn-success': 'rgba(106, 177, 101, 1)', 15022 'btn-warning': 'rgba(255, 153, 0, 1)', 15023 'btn-danger': 'rgba(255, 103, 91, 1)', 15024 'btn-inverse': 'rgba(85, 85, 85, 1)' 15025 }, 15026 init: function() { 15027 this.setupColor(); 15028 this.value = this.$el.data('pie-value')/100; 15029 this.label_value = this.$el.data('pie-label-value') || this.$el.data('pie-value'); 15030 this.$wrapper = $('.vc_pie_wrapper', this.$el); 15031 this.$label = $(this.options.label_selector, this.$el); 15032 this.$back = $(this.options.back_selector, this.$el); 15033 this.$canvas = this.$el.find('canvas'); 15034 this.arcWidth = this.$el.data('pie-width') * 2; 15035 this.draw(); 15036 this.setWayPoint(); 15037 if(this.options.responsive === true) this.setResponsive(); 15038 if (UNCODE.isMobile) this._progress_v = this.value; 15039 }, 15040 setupColor: function() { 15041 // if(typeof this.colors[this.options.color] !== 'undefined') { 15042 // this.color = this.colors[this.options.color]; 15043 // } else if(typeof this.options.color === 'string' && this.options.color.match(/^rgba?\([^\)]+\)/)) { 15044 // this.color = this.options.color; 15045 // } else { 15046 // this.color = 'rgba(247, 247, 247, 0.2)'; 15047 // } 15048 if(typeof this.options.color !== 'undefined') { 15049 this.color = this.options.color; 15050 } else this.color = 'rgba(247, 247, 247, 0.2)'; 15051 15052 }, 15053 setResponsive: function() { 15054 var that = this; 15055 if (!UNCODE.isMobile) { 15056 $(window).resize(function(){ 15057 if(that.animated === true) that.circle.stop(); 15058 that.draw(true); 15059 }); 15060 } 15061 }, 15062 draw: function(redraw) { 15063 var w = this.$el.addClass('vc_ready').width() * 2, 15064 border_w = this.arcWidth, 15065 radius; 15066 if(!w) w = this.$el.parents(':visible').first().width()-2; 15067 //w = Math.round(w/100*80); 15068 //if (w < 250) w = 250; 15069 radius = w/2; 15070 this.$wrapper.css({"width" : (w / 2) + "px"}); 15071 this.$label.css({"width" : (w / 2), "height" : (w / 2), "line-height" : (w / 2)+"px"}); 15072 this.$back.css({"width" : (w / 2), "height" : (w / 2)}); 15073 this.$canvas.attr({"width" : w + "px", "height" : w + "px"}); 15074 this.$el.addClass('vc_ready'); 15075 this.circle = new ProgressCircle({ 15076 canvas: this.$canvas.get(0), 15077 minRadius: radius, 15078 arcWidth: border_w 15079 }); 15080 if(redraw === true && this.animated === true) { 15081 this._progress_v = this.value; 15082 this.circle.addEntry({ 15083 fillColor: this.color, 15084 progressListener: $.proxy(this.setProgress, this) 15085 }).start(); 15086 } 15087 }, 15088 setProgress: function() { 15089 if (this._progress_v >= this.value) { 15090 this.circle.stop(); 15091 this.animated = true; 15092 this.$label.html(this.label_value + this.options.units); 15093 return this._progress_v; 15094 } 15095 this._progress_v += 0.01; 15096 if (!isNaN(this.label_value)) { 15097 var label_value = this._progress_v/this.value*this.label_value; 15098 var val = Math.round(label_value) + this.options.units; 15099 this.$label.html(val); 15100 } else this.$label.html(this.label_value + this.options.units); 15101 return this._progress_v; 15102 }, 15103 animate: function() { 15104 if(this.animated !== true) { 15105 this.circle.addEntry({ 15106 fillColor: this.color, 15107 progressListener: $.proxy(this.setProgress, this) 15108 }).start(10); 15109 } 15110 }, 15111 setWayPoint: function() { 15112 if (typeof $.fn.waypoint !== 'undefined' && !UNCODE.isMobile) { 15113 this.$el.waypoint($.proxy(this.animate, this), { offset: '85%' }); 15114 } else { 15115 this.animate(); 15116 } 15117 } 15118 }; 15119 /** 15120 * jQuery plugin 15121 * @param option - object with settings 15122 * @return {*} 15123 */ 15124 $.fn.vcChat = function(option, value) { 15125 return this.each(function () { 15126 var $this = $(this), 15127 data = $this.data('vc_chart'), 15128 options = typeof option === 'object' ? option : { 15129 color: $this.data('pie-color'), 15130 units: $this.data('pie-units') 15131 }; 15132 if (typeof option == 'undefined') $this.data('vc_chart', (data = new VcChart(this, options))); 15133 if (typeof option == 'string') data[option](value); 15134 }); 15135 }; 15136 /** 15137 * Allows users to rewrite function inside theme. 15138 */ 15139 if ( typeof window['vc_pieChart'] !== 'function' ) { 15140 window.vc_pieChart = function() { 15141 $('.vc_pie_chart:visible:not(.vc_ready)').vcChat(); 15142 } 15143 } 15144 $(document).ready(function(){ 15145 !window.vc_iframe && vc_pieChart(); 15146 15147 /** 15148 * Tab and collapse integration. 15149 */ 15150 $('.nav-tabs a').on('shown.bs.tab', function(e){ 15151 var $cont = $(e.target).closest('.tab-container'), 15152 $active = $('.tab-pane.active', $cont); 15153 $('.vc_pie_chart:not(.vc_ready)', $active).vcChat(); 15154 }); 15155 15156 $('.panel-collapse').on('shown.bs.collapse', function (e) { 15157 $('.vc_pie_chart:not(.vc_ready)', e.target).vcChat(); 15158 }) 15159 }); 15160 15161})(window.jQuery); 15162 15163/* Progress bar 15164 ---------------------------------------------------------- */ 15165function uncode_progress_bar() {    15166 jQuery.each(jQuery('.vc_progress_bar'), function(index, val) { 15167 if (UNCODE.isUnmodalOpen && !val.closest('#unmodal-content')) { 15168 return; 15169 } 15170 if (!UNCODE.isMobile) { 15171 new Waypoint({ 15172 context: UNCODE.isUnmodalOpen ? document.getElementById('unmodal-content') : window, 15173 element: val, 15174 handler: function() { 15175 var element = jQuery(this.element); 15176 element.find('.vc_single_bar').each(function(index) {          15177 var $this = jQuery(this), 15178             bar = $this.find('.vc_bar'), 15179             val = bar.data('percentage-value');          15180 setTimeout(function() {            15181 bar.css({ 15182 "width": val + '%' 15183 });          15184 }, index * 200);        15185 }); 15186 }, 15187 offset: '80%' 15188 }); 15189 } else { 15190 var element = jQuery(val); 15191 element.find('.vc_single_bar').each(function(index) {          15192 var $this = jQuery(this), 15193             bar = $this.find('.vc_bar'), 15194             val = bar.data('percentage-value');          15195 setTimeout(function() {            15196 bar.css({ 15197 "width": val + '%' 15198 });          15199 }, index * 200);        15200 }); 15201 } 15202 }); 15203}; 15204uncode_progress_bar(); 15205 15206/*! 15207 * jquery.counterup.js 1.0 15208 * 15209 * Copyright 2013, Benjamin Intal http://gambit.ph @bfintal 15210 * Released under the GPL v2 License 15211 * 15212 * Date: Nov 26, 2013 15213 */ 15214(function($) { 15215 "use strict"; 15216 $.fn.counterUp = function(options) { 15217 // Defaults 15218 var settings = $.extend({ 15219 'time': 400, 15220 'delay': 10 15221 }, options); 15222 return this.each(function() { 15223 // Store the object 15224 var $this = $(this); 15225 var $settings = settings; 15226 var counterUpper = function() { 15227 var nums = []; 15228 var divisions = $settings.time / $settings.delay; 15229 var numReal = $this.attr('data-val'), 15230 num = numReal; 15231 var isComma = /[0-9]+,[0-9]+/.test(num); 15232 num = num.replace(/,/g, ''); 15233 var isInt = /^[0-9]+$/.test(num); 15234 var isFloat = /^[0-9]+\.[0-9]+$/.test(num); 15235 var decimalPlaces = isFloat ? (num.split('.')[1] || []).length : 0; 15236 // Generate list of incremental numbers to display 15237 for (var i = divisions; i >= 1; i--) { 15238 // Preserve as int if input was int 15239 var newNum = parseInt(num / divisions * i); 15240 // Preserve float if input was float 15241 if (isFloat) { 15242 newNum = parseFloat(num / divisions * i).toFixed(decimalPlaces); 15243 } 15244 // Preserve commas if input had commas 15245 if (isComma) { 15246 while (/(\d+)(\d{3})/.test(newNum.toString())) { 15247 newNum = newNum.toString().replace(/(\d+)(\d{3})/, '$1' + ',' + '$2'); 15248 } 15249 } 15250 nums.unshift(newNum); 15251 } 15252 nums.push(numReal); 15253 $this.data('counterup-nums', nums); 15254 $this.text('0'); 15255 // Updates the number until we're done 15256 var f = function() { 15257 if ($this.data('counterup-nums') != null) { 15258 $this.text($this.data('counterup-nums').shift()); 15259 if ($this.data('counterup-nums').length) { 15260 setTimeout($this.data('counterup-func'), $settings.delay); 15261 } else { 15262 delete $this.data('counterup-nums'); 15263 $this.data('counterup-nums', null); 15264 $this.data('counterup-func', null); 15265 } 15266 } 15267 }; 15268 $this.data('counterup-func', f); 15269 // Start the count up 15270 setTimeout($this.data('counterup-func'), $settings.delay); 15271 }; 15272 // Perform counts when the element gets into view 15273 new Waypoint({ 15274 context: UNCODE.isUnmodalOpen ? document.getElementById('unmodal-content') : window, 15275 element: this, 15276 handler: function() { 15277 counterUpper(); 15278 if (!UNCODE.isUnmodalOpen) { 15279 this.destroy(); 15280 } 15281 }, 15282 offset: '100%' 15283 }); 15284 }); 15285 }; 15286})(jQuery); 15287 15288/*! 15289 * The Final Countdown for jQuery v2.2.0 (http://hilios.github.io/jQuery.countdown/) 15290 * Copyright (c) 2016 Edson Hilios 15291 * 15292 * Permission is hereby granted, free of charge, to any person obtaining a copy of 15293 * this software and associated documentation files (the "Software"), to deal in 15294 * the Software without restriction, including without limitation the rights to 15295 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 15296 * the Software, and to permit persons to whom the Software is furnished to do so, 15297 * subject to the following conditions: 15298 * 15299 * The above copyright notice and this permission notice shall be included in all 15300 * copies or substantial portions of the Software. 15301 * 15302 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15303 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 15304 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15305 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 15306 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 15307 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15308 */ 15309(function(factory) { 15310 "use strict"; 15311 if (typeof define === "function" && define.amd) { 15312 define([ "jquery" ], factory); 15313 } else { 15314 factory(jQuery); 15315 } 15316})(function($) { 15317 "use strict"; 15318 var instances = [], matchers = [], defaultOptions = { 15319 precision: 100, 15320 elapse: false, 15321 defer: false 15322 }; 15323 matchers.push(/^[0-9]*$/.source); 15324 matchers.push(/([0-9]{1,2}\/){2}[0-9]{4}( [0-9]{1,2}(:[0-9]{2}){2})?/.source); 15325 matchers.push(/[0-9]{4}([\/\-][0-9]{1,2}){2}( [0-9]{1,2}(:[0-9]{2}){2})?/.source); 15326 matchers = new RegExp(matchers.join("|")); 15327 function parseDateString(dateString) { 15328 if (dateString instanceof Date) { 15329 return dateString; 15330 } 15331 if (String(dateString).match(matchers)) { 15332 if (String(dateString).match(/^[0-9]*$/)) { 15333 dateString = Number(dateString); 15334 } 15335 if (String(dateString).match(/\-/)) { 15336 dateString = String(dateString).replace(/\-/g, "/"); 15337 } 15338 return new Date(dateString); 15339 } else { 15340 throw new Error("Couldn't cast `" + dateString + "` to a date object."); 15341 } 15342 } 15343 var DIRECTIVE_KEY_MAP = { 15344 Y: "years", 15345 m: "months", 15346 n: "daysToMonth", 15347 d: "daysToWeek", 15348 w: "weeks", 15349 W: "weeksToMonth", 15350 H: "hours", 15351 M: "minutes", 15352 S: "seconds", 15353 D: "totalDays", 15354 I: "totalHours", 15355 N: "totalMinutes", 15356 T: "totalSeconds" 15357 }; 15358 function escapedRegExp(str) { 15359 var sanitize = str.toString().replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1"); 15360 return new RegExp(sanitize); 15361 } 15362 function strftime(offsetObject) { 15363 return function(format) { 15364 var directives = format.match(/%(-|!)?[A-Z]{1}(:[^;]+;)?/gi); 15365 if (directives) { 15366 for (var i = 0, len = directives.length; i < len; ++i) { 15367 var directive = directives[i].match(/%(-|!)?([a-zA-Z]{1})(:[^;]+;)?/), regexp = escapedRegExp(directive[0]), modifier = directive[1] || "", plural = directive[3] || "", value = null; 15368 directive = directive[2]; 15369 if (DIRECTIVE_KEY_MAP.hasOwnProperty(directive)) { 15370 value = DIRECTIVE_KEY_MAP[directive]; 15371 value = Number(offsetObject[value]); 15372 } 15373 if (value !== null) { 15374 if (modifier === "!") { 15375 value = pluralize(plural, value); 15376 } 15377 if (modifier === "") { 15378 if (value < 10) { 15379
vendor: 4,091 bytes, lines 15379-15516
15379 value = "0" + value.toString(); 15380 } 15381 } 15382 format = format.replace(regexp, value.toString()); 15383 } 15384 } 15385 } 15386 format = format.replace(/%%/, "%"); 15387 return format; 15388 }; 15389 } 15390 function pluralize(format, count) { 15391 var plural = "s", singular = ""; 15392 if (format) { 15393 format = format.replace(/(:|;|\s)/gi, "").split(/\,/); 15394 if (format.length === 1) { 15395 plural = format[0]; 15396 } else { 15397 singular = format[0]; 15398 plural = format[1]; 15399 } 15400 } 15401 if (Math.abs(count) > 1) { 15402 return plural; 15403 } else { 15404 return singular; 15405 } 15406 } 15407 var Countdown = function(el, finalDate, options) { 15408 this.el = el; 15409 this.$el = $(el); 15410 this.interval = null; 15411 this.offset = {}; 15412 this.options = $.extend({}, defaultOptions); 15413 this.instanceNumber = instances.length; 15414 instances.push(this); 15415 this.$el.data("countdown-instance", this.instanceNumber); 15416 if (options) { 15417 if (typeof options === "function") { 15418 this.$el.on("update.countdown", options); 15419 this.$el.on("stoped.countdown", options); 15420 this.$el.on("finish.countdown", options); 15421 } else { 15422 this.options = $.extend({}, defaultOptions, options); 15423 } 15424 } 15425 this.setFinalDate(finalDate); 15426 if (this.options.defer === false) { 15427 this.start(); 15428 } 15429 }; 15430 $.extend(Countdown.prototype, { 15431 start: function() { 15432 if (this.interval !== null) { 15433 clearInterval(this.interval); 15434 } 15435 var self = this; 15436 this.update(); 15437 this.interval = setInterval(function() { 15438 self.update.call(self); 15439 }, this.options.precision); 15440 }, 15441 stop: function() { 15442 clearInterval(this.interval); 15443 this.interval = null; 15444 this.dispatchEvent("stoped"); 15445 }, 15446 toggle: function() { 15447 if (this.interval) { 15448 this.stop(); 15449 } else { 15450 this.start(); 15451 } 15452 }, 15453 pause: function() { 15454 this.stop(); 15455 }, 15456 resume: function() { 15457 this.start(); 15458 }, 15459 remove: function() { 15460 this.stop.call(this); 15461 instances[this.instanceNumber] = null; 15462 delete this.$el.data().countdownInstance; 15463 }, 15464 setFinalDate: function(value) { 15465 this.finalDate = parseDateString(value); 15466 }, 15467 update: function() { 15468 if (this.$el.closest("html").length === 0) { 15469 this.remove(); 15470 return; 15471 } 15472 var hasEventsAttached = $._data(this.el, "events") !== undefined, now = new Date(), newTotalSecsLeft; 15473 newTotalSecsLeft = this.finalDate.getTime() - now.getTime(); 15474 newTotalSecsLeft = Math.ceil(newTotalSecsLeft / 1e3); 15475 newTotalSecsLeft = !this.options.elapse && newTotalSecsLeft < 0 ? 0 : Math.abs(newTotalSecsLeft); 15476 if (this.totalSecsLeft === newTotalSecsLeft || !hasEventsAttached) { 15477 return; 15478 } else { 15479 this.totalSecsLeft = newTotalSecsLeft; 15480 } 15481 this.elapsed = now >= this.finalDate; 15482 this.offset = { 15483 seconds: this.totalSecsLeft % 60, 15484 minutes: Math.floor(this.totalSecsLeft / 60) % 60, 15485 hours: Math.floor(this.totalSecsLeft / 60 / 60) % 24, 15486 days: Math.floor(this.totalSecsLeft / 60 / 60 / 24) % 7, 15487 daysToWeek: Math.floor(this.totalSecsLeft / 60 / 60 / 24) % 7, 15488 daysToMonth: Math.floor(this.totalSecsLeft / 60 / 60 / 24 % 30.4368), 15489 weeks: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 7), 15490 weeksToMonth: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 7) % 4, 15491 months: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 30.4368), 15492 years: Math.abs(this.finalDate.getFullYear() - now.getFullYear()), 15493 totalDays: Math.floor(this.totalSecsLeft / 60 / 60 / 24), 15494 totalHours: Math.floor(this.totalSecsLeft / 60 / 60), 15495 totalMinutes: Math.floor(this.totalSecsLeft / 60), 15496 totalSeconds: this.totalSecsLeft 15497 }; 15498 if (!this.options.elapse && this.totalSecsLeft === 0) { 15499 this.stop(); 15500 this.dispatchEvent("finish"); 15501 } else { 15502 this.dispatchEvent("update"); 15503 } 15504 }, 15505 dispatchEvent: function(eventName) { 15506 var event = $.Event(eventName + ".countdown"); 15507 event.finalDate = this.finalDate; 15508 event.elapsed = this.elapsed; 15509 event.offset = $.extend({}, this.offset); 15510 event.strftime = strftime(this.offset); 15511 this.$el.trigger(event); 15512 } 15513 }); 15514 $.fn.countdown = function() { 15515 var argumentsArray = Array.prototype.slice.call(arguments, 0); 15516 return this.each(function() {
15517 var instanceNumber = $(this).data("countdown-instance"); 15518 if (instanceNumber !== undefined) { 15519 var instance = instances[instanceNumber], method = argumentsArray[0]; 15520 if (Countdown.prototype.hasOwnProperty(method)) { 15521 instance[method].apply(instance, argumentsArray.slice(1)); 15522 } else if (String(method).match(/^[$A-Z_][0-9A-Z_$]*$/i) === null) { 15523 instance.setFinalDate.call(instance, method); 15524 instance.start(); 15525 } else { 15526 $.error("Method %s does not exist on jQuery.countdown".replace(/\%s/gi, method)); 15527 } 15528 } else { 15529 new Countdown(this, argumentsArray[0], argumentsArray[1]); 15530 } 15531 }); 15532 }; 15533}); 15534 15535/*! waitForImages jQuery Plugin - v2.0.2 - 2015-05-05 15536* https://github.com/alexanderdickson/waitForImages 15537* Copyright (c) 2015 Alex Dickson; Licensed MIT */ 15538;(function (factory) { 15539 if (typeof define === 'function' && define.amd) { 15540 // AMD. Register as an anonymous module. 15541 define(['jquery'], factory); 15542 } else if (typeof exports === 'object') { 15543 // CommonJS / nodejs module 15544 module.exports = factory(require('jquery')); 15545 } else { 15546 // Browser globals 15547 factory(jQuery); 15548 } 15549}(function ($) { 15550 // Namespace all events. 15551 var eventNamespace = 'waitForImages'; 15552 15553 // CSS properties which contain references to images. 15554 $.waitForImages = { 15555 hasImageProperties: [ 15556 'backgroundImage', 15557 'listStyleImage', 15558 'borderImage', 15559 'borderCornerImage', 15560 'cursor' 15561 ], 15562 hasImageAttributes: ['srcset'] 15563 }; 15564 15565 // Custom selector to find `img` elements that have a valid `src` 15566 // attribute and have not already loaded. 15567 $.expr[':'].uncached = function (obj) { 15568 // Ensure we are dealing with an `img` element with a valid 15569 // `src` attribute. 15570 if (!$(obj).is('img[src][src!=""]')) { 15571 return false; 15572 } 15573 15574 return !obj.complete; 15575 }; 15576 15577 $.fn.waitForImages = function () { 15578 15579 var allImgsLength = 0; 15580 var allImgsLoaded = 0; 15581 var deferred = $.Deferred(); 15582 15583 var finishedCallback; 15584 var eachCallback; 15585 var waitForAll; 15586 15587 // Handle options object (if passed). 15588 if ($.isPlainObject(arguments[0])) { 15589 15590 waitForAll = arguments[0].waitForAll; 15591 eachCallback = arguments[0].each; 15592 finishedCallback = arguments[0].finished; 15593 15594 } else { 15595 15596 // Handle if using deferred object and only one param was passed in. 15597 if (arguments.length === 1 && $.type(arguments[0]) === 'boolean') { 15598 waitForAll = arguments[0]; 15599 } else { 15600 finishedCallback = arguments[0]; 15601 eachCallback = arguments[1]; 15602 waitForAll = arguments[2]; 15603 } 15604 15605 } 15606 15607 // Handle missing callbacks. 15608 finishedCallback = finishedCallback || $.noop; 15609 eachCallback = eachCallback || $.noop; 15610 15611 // Convert waitForAll to Boolean 15612 waitForAll = !! waitForAll; 15613 15614 // Ensure callbacks are functions. 15615 if (!$.isFunction(finishedCallback) || !$.isFunction(eachCallback)) { 15616 throw new TypeError('An invalid callback was supplied.'); 15617 } 15618 15619 this.each(function () { 15620 // Build a list of all imgs, dependent on what images will 15621 // be considered. 15622 var obj = $(this); 15623 var allImgs = []; 15624 // CSS properties which may contain an image. 15625 var hasImgProperties = $.waitForImages.hasImageProperties || []; 15626 // Element attributes which may contain an image. 15627 var hasImageAttributes = $.waitForImages.hasImageAttributes || []; 15628 // To match `url()` references. 15629 // Spec: http://www.w3.org/TR/CSS2/syndata.html#value-def-uri 15630 var matchUrl = /url\(\s*(['"]?)(.*?)\1\s*\)/g; 15631 15632 if (waitForAll) { 15633 15634 // Get all elements (including the original), as any one of 15635 // them could have a background image. 15636 obj.find('*').addBack().each(function () { 15637 var element = $(this); 15638 15639 // If an `img` element, add it. But keep iterating in 15640 // case it has a background image too. 15641 if (element.is('img:uncached')) { 15642 allImgs.push({ 15643 src: element.attr('src'), 15644 element: element[0] 15645 }); 15646 } 15647 15648 $.each(hasImgProperties, function (i, property) { 15649 var propertyValue = element.css(property); 15650 var match; 15651 15652 // If it doesn't contain this property, skip. 15653 if (!propertyValue) { 15654 return true; 15655 } 15656 15657 // Get all url() of this element. 15658 while (match = matchUrl.exec(propertyValue)) { 15659 allImgs.push({ 15660 src: match[2], 15661 element: element[0] 15662 }); 15663 } 15664 }); 15665 15666 $.each(hasImageAttributes, function (i, attribute) { 15667 var attributeValue = element.attr(attribute); 15668 var attributeValues; 15669 15670 // If it doesn't contain this property, skip. 15671 if (!attributeValue) { 15672 return true; 15673 } 15674 15675 // Check for multiple comma separated images 15676 attributeValues = attributeValue.split(','); 15677 15678 $.each(attributeValues, function(i, value) { 15679 // Trim value and get string before first 15680 // whitespace (for use with srcset). 15681 value = $.trim(value).split(' ')[0]; 15682 allImgs.push({ 15683 src: value, 15684 element: element[0] 15685 }); 15686 }); 15687 }); 15688 }); 15689 } else { 15690 // For images only, the task is simpler. 15691 obj.find('img:uncached') 15692 .each(function () { 15693 allImgs.push({ 15694 src: this.src, 15695 element: this 15696 }); 15697 }); 15698 } 15699 15700 allImgsLength = allImgs.length; 15701 allImgsLoaded = 0; 15702 15703 // If no images found, don't bother. 15704 if (allImgsLength === 0) { 15705 finishedCallback.call(obj[0]); 15706 deferred.resolveWith(obj[0]); 15707 } 15708 15709 $.each(allImgs, function (i, img) { 15710 15711 var image = new Image(); 15712 var events = 15713 'load.' + eventNamespace + ' error.' + eventNamespace; 15714 15715 // Handle the image loading and error with the same callback. 15716 $(image).one(events, function me (event) { 15717 // If an error occurred with loading the image, set the 15718 // third argument accordingly. 15719 var eachArguments = [ 15720 allImgsLoaded, 15721 allImgsLength,
15722 event.type == 'load' 15723 ]; 15724 allImgsLoaded++; 15725 15726 eachCallback.apply(img.element, eachArguments); 15727 deferred.notifyWith(img.element, eachArguments); 15728 15729 // Unbind the event listeners. I use this in addition to 15730 // `one` as one of those events won't be called (either 15731 // 'load' or 'error' will be called). 15732 $(this).off(events, me); 15733 15734 if (allImgsLoaded == allImgsLength) { 15735 finishedCallback.call(obj[0]); 15736 deferred.resolveWith(obj[0]); 15737 return false; 15738 } 15739 15740 }); 15741 15742 image.src = img.src; 15743 }); 15744 }); 15745 15746 return deferred.promise(); 15747 15748 }; 15749})); 15750 15751/** 15752 * @preserve textfill 15753 * @name jquery.textfill.js 15754 * @author Russ Painter 15755 * @author Yu-Jie Lin 15756 * @author Alexandre Dantas 15757 * @version 0.6.0 15758 * @date 2014-08-19 15759 * @copyright (c) 2014 Alexandre Dantas 15760 * @copyright (c) 2012-2013 Yu-Jie Lin 15761 * @copyright (c) 2009 Russ Painter 15762 * @license MIT License 15763 * @homepage https://github.com/jquery-textfill/jquery-textfill 15764 * @example http://jquery-textfill.github.io/jquery-textfill/index.html 15765 */ 15766; (function($) { 15767 15768 /** 15769 * Resizes an inner element's font so that the 15770 * inner element completely fills the outer element. 15771 * 15772 * @param {Object} options User options that take 15773 * higher precedence when 15774 * merging with the default ones. 15775 * 15776 * @return All outer elements processed 15777 */ 15778 $.fn.textfill = function(options) { 15779 15780 // ______ _______ _______ _______ _ _ _______ _______ 15781 // | \ |______ |______ |_____| | | | | |______ 15782 // |_____/ |______ | | | |_____| |_____ | ______| 15783 // 15784 // Merging user options with the default values 15785 15786 var defaults = { 15787 debug : false, 15788 maxFontPixels : 40, 15789 minFontPixels : 4, 15790 innerTag : 'span', 15791 widthOnly : false, 15792 success : null, // callback when a resizing is done 15793 callback : null, // callback when a resizing is done (deprecated, use success) 15794 fail : null, // callback when a resizing is failed 15795 complete : null, // callback when all is done 15796 explicitWidth : null, 15797 explicitHeight : null, 15798 changeLineHeight : false 15799 }; 15800 15801 var Opts = $.extend(defaults, options); 15802 15803 // _______ _ _ __ _ _______ _______ _____ _____ __ _ _______ 15804 // |______ | | | \ | | | | | | | \ | |______ 15805 // | |_____| | \_| |_____ | __|__ |_____| | \_| ______| 15806 // 15807 // Predefining the awesomeness 15808 15809 // Output arguments to the Debug console 15810 // if "Debug Mode" is enabled 15811 function _debug() { 15812 if (!Opts.debug 15813 || typeof console == 'undefined' 15814 || typeof console.debug == 'undefined') { 15815 return; 15816 } 15817 console.debug.apply(console, arguments); 15818 } 15819 15820 // Output arguments to the Warning console 15821 function _warn() { 15822 if (typeof console == 'undefined' || 15823 typeof console.warn == 'undefined') { 15824 return; 15825 } 15826 console.warn.apply(console, arguments); 15827 } 15828 15829 // Outputs all information on the current sizing 15830 // of the font. 15831 function _debug_sizing(prefix, ourText, maxHeight, maxWidth, minFontPixels, maxFontPixels) { 15832 15833 function _m(v1, v2) { 15834 15835 var marker = ' / '; 15836 15837 if (v1 > v2) 15838 marker = ' > '; 15839 15840 else if (v1 == v2) 15841 marker = ' = '; 15842 15843 return marker; 15844 } 15845 15846 _debug( 15847 '[TextFill] ' + prefix + ' { ' + 15848 'font-size: ' + ourText.css('font-size') + ',' +
15849 'Height: ' + ourText.height() + 'px ' + _m(ourText.height(), maxHeight) + maxHeight + 'px,' + 15850 'Width: ' + ourText.width() + _m(ourText.width() , maxWidth) + maxWidth + ',' + 15851 'minFontPixels: ' + minFontPixels + 'px, ' + 15852 'maxFontPixels: ' + maxFontPixels + 'px }' 15853 ); 15854 } 15855 15856 /** 15857 * Calculates which size the font can get resized, 15858 * according to constrains. 15859 * 15860 * @param {String} prefix Gets shown on the console before 15861 * all the arguments, if debug mode is on. 15862 * @param {Object} ourText The DOM element to resize, 15863 * that contains the text. 15864 * @param {function} func Function called on `ourText` that's 15865 * used to compare with `max`. 15866 * @param {number} max Maximum value, that gets compared with 15867 * `func` called on `ourText`. 15868 * @param {number} minFontPixels Minimum value the font can 15869 * get resized to (in pixels). 15870 * @param {number} maxFontPixels Maximum value the font can 15871 * get resized to (in pixels). 15872 * 15873 * @return Size (in pixels) that the font can be resized. 15874 */ 15875 function _sizing(prefix, ourText, func, max, maxHeight, maxWidth, minFontPixels, maxFontPixels) { 15876 15877 _debug_sizing( 15878 prefix, ourText, 15879 maxHeight, maxWidth, 15880 minFontPixels, maxFontPixels 15881 ); 15882 15883 // The kernel of the whole plugin, take most attention 15884 // on this part. 15885 // 15886 // This is a loop that keeps increasing the `font-size` 15887 // until it fits the parent element. 15888 // 15889 // - Start from the minimal allowed value (`minFontPixels`) 15890 // - Guesses an average font size (in pixels) for the font, 15891 // - Resizes the text and sees if its size is within the 15892 // boundaries (`minFontPixels` and `maxFontPixels`). 15893 // - If so, keep guessing until we break. 15894 // - If not, return the last calculated size. 15895 // 15896 // I understand this is not optimized and we should 15897 // consider implementing something akin to 15898 // Daniel Hoffmann's answer here: 15899 // 15900 // http://stackoverflow.com/a/17433451/1094964 15901 // 15902 15903 while (minFontPixels < (maxFontPixels - 1)) { 15904 15905 var fontSize = Math.floor((minFontPixels + maxFontPixels) / 2); 15906 ourText.css('font-size', fontSize); 15907 15908 if (func.call(ourText) <= max) { 15909 minFontPixels = fontSize; 15910 15911 if (func.call(ourText) == max) 15912 break; 15913 } 15914 else 15915 maxFontPixels = fontSize; 15916 15917 _debug_sizing( 15918 prefix, ourText, 15919 maxHeight, maxWidth, 15920 minFontPixels, maxFontPixels 15921 ); 15922 } 15923 15924 ourText.css('font-size', maxFontPixels); 15925 15926 if (func.call(ourText) <= max) { 15927 minFontPixels = maxFontPixels; 15928 15929 _debug_sizing( 15930 prefix + '* ', ourText, 15931 maxHeight, maxWidth, 15932 minFontPixels, maxFontPixels 15933 ); 15934 } 15935 return minFontPixels; 15936 } 15937 15938 // _______ _______ _______ ______ _______ 15939 // |______ | |_____| |_____/ | 15940 // ______| | | | | \_ | 15941 // 15942 // Let's get it started (yeah)! 15943 15944 _debug('[TextFill] Start Debug'); 15945 15946 this.each(function() { 15947 15948 // Contains the child element we will resize. 15949 // $(this) means the parent container 15950 var ourText = $(Opts.innerTag + ':visible:first', this); 15951 15952 // Will resize to this dimensions. 15953 // Use explicit dimensions when specified 15954 var maxHeight = Opts.explicitHeight || $(this).height(); 15955 var maxWidth = Opts.explicitWidth || $(this).width(); 15956 15957 var oldFontSize = ourText.css('font-size'); 15958 15959 var lineHeight = parseFloat(ourText.css('line-height')) / parseFloat(oldFontSize); 15960 15961 _debug('[TextFill] Inner text: ' + ourText.text()); 15962 _debug('[TextFill] All options: ', Opts); 15963 _debug('[TextFill] Maximum sizes: { ' + 15964 'Height: ' + maxHeight + 'px, ' + 15965 'Width: ' + maxWidth + 'px' + ' }' 15966 ); 15967 15968 var minFontPixels = Opts.minFontPixels; 15969 15970 // Remember, if this `maxFontPixels` is negative, 15971 // the text will resize to as long as the container 15972 // can accomodate 15973 var maxFontPixels = (Opts.maxFontPixels <= 0 ? 15974 maxHeight : 15975 Opts.maxFontPixels); 15976 15977 15978 // Let's start it all! 15979 15980 // 1. Calculate which `font-size` would 15981 // be best for the Height 15982 var fontSizeHeight = undefined; 15983 15984 if (! Opts.widthOnly) 15985 fontSizeHeight = _sizing( 15986 'Height', ourText, 15987 $.fn.height, maxHeight, 15988 maxHeight, maxWidth, 15989 minFontPixels, maxFontPixels 15990 ); 15991 15992 // 2. Calculate which `font-size` would 15993 // be best for the Width 15994 var fontSizeWidth = undefined; 15995 15996 fontSizeWidth = _sizing( 15997 'Width', ourText, 15998 $.fn.width, maxWidth, 15999 maxHeight, maxWidth, 16000 minFontPixels, maxFontPixels 16001 ); 16002 16003 // 3. Actually resize the text! 16004 16005 if (Opts.widthOnly) { 16006 ourText.css({ 16007 'font-size' : fontSizeWidth, 16008 'white-space': 'nowrap' 16009 }); 16010 16011 if (Opts.changeLineHeight) 16012 ourText.parent().css( 16013 'line-height', 16014 (lineHeight * fontSizeWidth + 'px') 16015 ); 16016 } 16017 else { 16018 var fontSizeFinal = Math.min(fontSizeHeight, fontSizeWidth); 16019 16020 ourText.css('font-size', fontSizeFinal); 16021 16022 if (Opts.changeLineHeight) 16023 ourText.parent().css( 16024 'line-height', 16025 (lineHeight * fontSizeFinal) + 'px' 16026 ); 16027 } 16028 16029 _debug( 16030 '[TextFill] Finished { ' + 16031 'Old font-size: ' + oldFontSize + ', ' + 16032 'New font-size: ' + ourText.css('font-size') + ' }' 16033 ); 16034 16035 // Oops, something wrong happened! 16036 // We weren't supposed to exceed the original size 16037 if ((ourText.width() > maxWidth) ||
16038 (ourText.height() > maxHeight && !Opts.widthOnly)) { 16039 16040 ourText.css('font-size', oldFontSize); 16041 16042 // Failure callback 16043 if (Opts.fail) 16044 Opts.fail(this); 16045 16046 _debug( 16047 '[TextFill] Failure { ' + 16048 'Current Width: ' + ourText.width() + ', ' + 16049 'Maximum Width: ' + maxWidth + ', ' + 16050 'Current Height: ' + ourText.height() + ', ' + 16051 'Maximum Height: ' + maxHeight + ' }' 16052 ); 16053 } 16054 else if (Opts.success) { 16055 Opts.success(this); 16056 } 16057 else if (Opts.callback) { 16058 _warn('callback is deprecated, use success, instead'); 16059 16060 // Success callback 16061 Opts.callback(this); 16062 } 16063 }); 16064 16065 // Complete callback 16066 if (Opts.complete) 16067 Opts.complete(this); 16068 16069 _debug('[TextFill] End Debug'); 16070 return this; 16071 }; 16072 16073})(window.jQuery); 16074 16075!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; 16076function getStyles(config){ 16077 // 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;
16077left: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+"}" 16078}; 16079 var ShareUtils; 16080 16081if ((!("classList" in document.documentElement)) && Object.defineProperty && typeof HTMLElement !== "undefined") { 16082 Object.defineProperty(HTMLElement.prototype, "classList", { 16083 get: function() { 16084 var ret, self, update; 16085 update = function(fn) { 16086 return function(value) { 16087 var classes, index; 16088 classes = self.className.split(/\s+/); 16089 index = classes.indexOf(value); 16090 fn(classes, index, value); 16091 self.className = classes.join(" "); 16092 }; 16093 }; 16094 self = this; 16095 ret = { 16096 add: update(function(classes, index, value) { 16097 ~index || classes.push(value); 16098 }), 16099 remove: update(function(classes, index) { 16100 ~index && classes.splice(index, 1); 16101 }), 16102 toggle: update(function(classes, index, value) { 16103 if (~index) { 16104 classes.splice(index, 1); 16105 } else { 16106 classes.push(value); 16107 } 16108 }), 16109 contains: function(value) { 16110 return !!~self.className.split(/\s+/).indexOf(value); 16111 }, 16112 item: function(i) { 16113 return self.className.split(/\s+/)[i] || null; 16114 } 16115 }; 16116 Object.defineProperty(ret, "length", { 16117 get: function() { 16118 return self.className.split(/\s+/).length; 16119 } 16120 }); 16121 return ret; 16122 } 16123 }); 16124} 16125 16126String.prototype.to_rfc3986 = function() { 16127 var tmp; 16128 tmp = encodeURIComponent(this); 16129 return tmp.replace(/[!'()*]/g, function(c) { 16130 return "%" + c.charCodeAt(0).toString(16); 16131 }); 16132}; 16133 16134ShareUtils = (function() { 16135 function ShareUtils() {} 16136 16137 ShareUtils.prototype.extend = function(to, from, overwrite) { 16138 var hasProp, prop; 16139 for (prop in from) { 16140 hasProp = to[prop] !== undefined; 16141 if (hasProp && typeof from[prop] === "object") { 16142 this.extend(to[prop], from[prop], overwrite); 16143 } else { 16144 if (overwrite || !hasProp) { 16145 to[prop] = from[prop]; 16146 } 16147 } 16148 } 16149 }; 16150 16151 ShareUtils.prototype.hide = function(el) { 16152 return el.style.display = "none"; 16153 }; 16154 16155 ShareUtils.prototype.show = function(el) { 16156 return el.style.display = "block"; 16157 }; 16158 16159 ShareUtils.prototype.has_class = function(el, class_name) { 16160 return el.classList.contains(class_name); 16161 }; 16162 16163 ShareUtils.prototype.add_class = function(el, class_name) { 16164 return el.classList.add(class_name); 16165 }; 16166 16167 ShareUtils.prototype.remove_class = function(el, class_name) { 16168 return el.classList.remove(class_name); 16169 }; 16170 16171 ShareUtils.prototype.is_encoded = function(str) { 16172 str = str.to_rfc3986(); 16173 return decodeURIComponent(str) !== str; 16174 }; 16175 16176 ShareUtils.prototype.encode = function(str) { 16177 if (typeof str === "undefined" || this.is_encoded(str)) { 16178 return str; 16179 } else { 16180 return str.to_rfc3986(); 16181 } 16182 }; 16183 16184 ShareUtils.prototype.popup = function(url, params) { 16185 var k, popup, qs, v; 16186 if (params == null) { 16187 params = {}; 16188 } 16189 popup = { 16190 width: 500, 16191 height: 350 16192 }; 16193 popup.top = (screen.height / 2) - (popup.height / 2); 16194 popup.left = (screen.width / 2) - (popup.width / 2); 16195 qs = ((function() { 16196 var _results; 16197 _results = []; 16198 for (k in params) { 16199 v = params[k]; 16200 _results.push("" + k + "=" + (this.encode(v))); 16201 } 16202 return _results; 16203 }).call(this)).join('&'); 16204 if (qs) { 16205 qs = "?" + qs; 16206 } 16207 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="
16207+ popup.width + ",height=" + popup.height); 16208 }; 16209 16210 return ShareUtils; 16211 16212})(); 16213var Share, 16214 __hasProp = {}.hasOwnProperty, 16215 __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; }; 16216 16217Share = (function(_super) { 16218 __extends(Share, _super); 16219 16220 function Share(element, options) { 16221 this.element = element; 16222 this.el = { 16223 head: document.getElementsByTagName('head')[0], 16224 body: document.getElementsByTagName('body')[0] 16225 }; 16226 this.config = { 16227 enabled_networks: 0, 16228 protocol: ['http', 'https'].indexOf(window.location.href.split(':')[0]) === -1 ? 'https://' : '//', 16229 url: window.location.href.replace("&", "%26"), 16230 caption: null, 16231 title: this.default_title(), 16232 image: this.default_image(), 16233 description: this.default_description(), 16234 ui: { 16235 flyout: 'top center', 16236 button_text: 'Share', 16237 button_font: true, 16238 icon_font: true 16239 }, 16240 networks: { 16241 google_plus: { 16242 enabled: true, 16243 url: null 16244 }, 16245 twitter: { 16246 enabled: true, 16247 url: null, 16248 title: null, 16249 description: null 16250 }, 16251 facebook: { 16252 enabled: true, 16253 load_sdk: true, 16254 url: null, 16255 app_id: null, 16256 title: null, 16257 caption: null, 16258 description: null, 16259 image: null 16260 }, 16261 pinterest: { 16262 enabled: true, 16263 url: null, 16264 image: null, 16265 description: null 16266 }, 16267 reddit: { 16268 enabled: true, 16269 url: null, 16270 title: null 16271 }, 16272 linkedin: { 16273 enabled: true, 16274 url: null, 16275 title: null, 16276 description: null 16277 }, 16278 xing: { 16279 enabled: true, 16280 url: null, 16281 title: null, 16282 image: null, 16283 description: null 16284 }, 16285 whatsapp: { 16286 enabled: true, 16287 description: null, 16288 url: null 16289 }, 16290 email: { 16291 enabled: true, 16292 title: null, 16293 description: null, 16294 url: null 16295 } 16296 } 16297 }; 16298 this.setup(element, options); 16299 return this; 16300 } 16301 16302 Share.prototype.setup = function(element, opts) { 16303 var index, instance, instances, _i, _len; 16304 instances = document.querySelectorAll(element); 16305 this.extend(this.config, opts, true); 16306 this.set_global_configuration(); 16307 this.normalize_network_configuration(); 16308 if (this.config.ui.icon_font) { 16309 this.inject_icons(); 16310 } 16311 if (this.config.ui.button_font) { 16312 this.inject_fonts(); 16313 } 16314 if (this.config.networks.facebook.enabled && this.config.networks.facebook.load_sdk) { 16315 this.inject_facebook_sdk(); 16316 } 16317 for (index = _i = 0, _len = instances.length; _i < _len; index = ++_i) { 16318 instance = instances[index]; 16319 this.setup_instance(element, index); 16320 } 16321 }; 16322 16323 Share.prototype.setup_instance = function(element, index) { 16324 var button, instance, label, network, networks, _i, _len, _results, 16325 _this = this; 16326 instance = document.querySelectorAll(element)[index]; 16327 this.hide(instance); 16328 this.add_class(instance, "sharer-" + index); 16329 instance = document.querySelectorAll(element)[index]; 16330 this.inject_css(instance); 16331 this.inject_html(instance); 16332 this.show(instance); 16333 label = instance.getElementsByTagName("label")[0]; 16334 button = instance.getElementsByClassName("social")[0]; 16335 networks = instance.getElementsByTagName('li'); 16336 this.add_class(button, "networks-" + this.config.enabled_networks); 16337 label.addEventListener("click", function() { 16338 return _this.event_toggle(button); 16339 }); 16340 _this = this; 16341 _results = []; 16342 for (index = _i = 0, _len = networks.length; _i < _len; index = ++_i) { 16343 network = networks[index]; 16344 _results.push(network.addEventListener("click", function() { 16345 _this.event_network(instance, this); 16346 return _this.event_close(button); 16347 })); 16348 } 16349 return _results; 16350 }; 16351 16352 Share.prototype.event_toggle = function(button) { 16353 if (this.has_class(button, "active")) { 16354 return this.event_close(button); 16355 } else { 16356 return this.event_open(button); 16357 } 16358 }; 16359 16360 Share.prototype.event_open = function(button) { 16361 if (this.has_class(button, "load")) { 16362 this.remove_class(button, "load"); 16363 } 16364 return this.add_class(button, "active"); 16365 }; 16366 16367 Share.prototype.event_close = function(button) { 16368 return this.remove_class(button, "active"); 16369 }; 16370 16371 Share.prototype.event_network = function(instance, network) { 16372 var name; 16373 name = network.getAttribute("data-network"); 16374 this.hook("before", name, instance);
16375 this["network_" + name](); 16376 return this.hook("after", name, instance); 16377 }; 16378 16379 Share.prototype.open = function() { 16380 return this["public"]("open"); 16381 }; 16382 16383 Share.prototype.close = function() { 16384 return this["public"]("close"); 16385 }; 16386 16387 Share.prototype.toggle = function() { 16388 return this["public"]("toggle"); 16389 }; 16390 16391 Share.prototype["public"] = function(action) { 16392 var button, index, instance, _i, _len, _ref, _results; 16393 _ref = document.querySelectorAll(this.element); 16394 _results = []; 16395 for (index = _i = 0, _len = _ref.length; _i < _len; index = ++_i) { 16396 instance = _ref[index]; 16397 button = instance.getElementsByClassName("social")[0]; 16398 _results.push(this["event_" + action](button)); 16399 } 16400 return _results; 16401 }; 16402 16403 Share.prototype.network_facebook = function() { 16404 if (this.config.networks.facebook.load_sdk) { 16405 if (!window.FB) { 16406 return console.error("The Facebook JS SDK hasn't loaded yet."); 16407 } 16408 return FB.ui({ 16409 method: 'feed', 16410 name: this.config.networks.facebook.title, 16411 link: this.config.networks.facebook.url, 16412 picture: this.config.networks.facebook.image, 16413 caption: this.config.networks.facebook.caption, 16414 description: this.config.networks.facebook.description 16415 }); 16416 } else { 16417 return this.popup('https://www.facebook.com/sharer/sharer.php', { 16418 u: this.config.networks.facebook.url 16419 }); 16420 } 16421 }; 16422 16423 Share.prototype.network_twitter = function() { 16424 return this.popup('https://twitter.com/intent/tweet', { 16425 text: this.config.networks.twitter.title, 16426 url: this.config.networks.twitter.url 16427 }); 16428 }; 16429 16430 Share.prototype.network_google_plus = function() { 16431 return this.popup('https://plus.google.com/share', { 16432 url: this.config.networks.google_plus.url 16433 }); 16434 }; 16435 16436 Share.prototype.network_pinterest = function() { 16437 return this.popup('https://www.pinterest.com/pin/create/button', { 16438 url: this.config.networks.pinterest.url, 16439 media: this.config.networks.pinterest.image, 16440 description: this.config.networks.pinterest.description 16441 }); 16442 }; 16443 16444 Share.prototype.network_linkedin = function() { 16445 return this.popup('https://www.linkedin.com/shareArticle', { 16446 url: this.config.networks.linkedin.url, 16447 title: this.config.networks.linkedin.title, 16448 summary: this.config.networks.linkedin.description 16449 }); 16450 } 16451 16452 Share.prototype.network_xing = function() { 16453 return this.popup('https://www.xing.com/spi/shares/new', { 16454 url: this.config.networks.xing.url, 16455 image: this.config.networks.xing.image, 16456 title: this.config.networks.xing.title, 16457 summary: this.config.networks.xing.description 16458 }); 16459 } 16460 16461 Share.prototype.network_email = function() { 16462 return this.popup('mailto:', { 16463 subject: this.config.networks.email.title, 16464 body: this.config.networks.email.url + '%0A%0A' + this.config.networks.email.description, 16465 }); 16466 }; 16467 16468 Share.prototype.inject_icons = function() { 16469 // return this.inject_stylesheet("https://www.sharebutton.co/fonts/v2/entypo.min.css"); 16470 }; 16471 16472 Share.prototype.inject_fonts = function() { 16473 // return this.inject_stylesheet("http://fonts.googleapis.com/css?family=Lato:900&text=" + this.config.ui.button_text); 16474 }; 16475 16476 Share.prototype.inject_stylesheet = function(url) { 16477 var link; 16478 if (!this.el.head.querySelector("link[href=\"" + url + "\"]")) { 16479 link = document.createElement("link"); 16480 link.setAttribute("rel", "stylesheet"); 16481 link.setAttribute("href", url); 16482 return this.el.head.appendChild(link); 16483 } 16484 }; 16485 16486 Share.prototype.inject_css = function(instance) { 16487 var css, meta, selector, style; 16488 selector = "." + (instance.getAttribute('class').split(" ").join(".")); 16489 if (!this.el.head.querySelector("meta[name='sharer" + selector + "']")) { 16490 this.config.selector = selector; 16491 css = getStyles(this.config); 16492 style = document.createElement("style"); 16493 style.type = "text/css"; 16494 if (style.styleSheet) { 16495 style.styleSheet.cssText = css; 16496 } else { 16497 style.appendChild(document.createTextNode(css)); 16498 } 16499 this.el.head.appendChild(style); 16500 delete this.config.selector; 16501 meta = document.createElement("meta"); 16502 meta.setAttribute("name", "sharer" + selector); 16503 return this.el.head.appendChild(meta); 16504 } 16505 }; 16506 16507 Share.prototype.inject_html = function(instance) { 16508 //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>"; 16509 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>"; 16510 }; 16511 16512 Share.prototype.inject_facebook_sdk = function() { 16513 var fb_root, script; 16514 if (!window.FB && this.config.networks.facebook.app_id && !this.el.body.querySelector('#fb-root')) { 16515 script = document.createElement("script"); 16516 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')"; 16517 fb_root = document.createElement("div"); 16518 fb_root.id = "fb-root"; 16519 this.el.body.appendChild(fb_root); 16520 return this.el.body.appendChild(script); 16521 } 16522 }; 16523 16524 Share.prototype.hook = function(type, network, instance) { 16525 var fn, opts; 16526 fn = this.config.networks[network][type]; 16527 if (typeof fn === "function") { 16528 opts = fn.call(this.config.networks[network], instance); 16529 if (opts !== void 0) { 16530 opts = this.normalize_filter_config_updates(opts); 16531 this.extend(this.config.networks[network], opts, true); 16532 this.normalize_network_configuration(); 16533 } 16534 } 16535 }; 16536 16537 Share.prototype.default_title = function() { 16538 var content; 16539 if (content = document.querySelector('meta[property="og:title"]') || document.querySelector('meta[name="twitter:title"]')) { 16540 return encodeURIComponent(content.getAttribute('content')); 16541 } else if (content = document.querySelector('title')) { 16542 return encodeURIComponent(content.innerText); 16543 } 16544 }; 16545 16546 Share.prototype.default_image = function() { 16547 var content; 16548 if (content = document.querySelector('meta[property="og:image"]') || document.querySelector('meta[name="twitter:image"]')) { 16549 return content.getAttribute('content'); 16550 } 16551 }; 16552 16553 Share.prototype.default_description = function() { 16554 var content; 16555 if (content = document.querySelector('meta[property="og:description"]') || document.querySelector('meta[name="twitter:description"]') || document.querySelector('meta[name="description"]')) { 16556 return encodeURIComponent(content.getAttribute('content')); 16557 } else { 16558 return ''; 16559 } 16560 }; 16561 16562 Share.prototype.set_global_configuration = function() { 16563 var display, network, option, options, _ref, _results; 16564 _ref = this.config.networks; 16565 _results = []; 16566 for (network in _ref) { 16567 options = _ref[network]; 16568 for (option in options) { 16569 if (this.config.networks[network][option] == null) { 16570 this.config.networks[network][option] = this.config[option]; 16571 } 16572 } 16573 if (this.config.networks[network].enabled) { 16574 display = 'block'; 16575 this.config.enabled_networks += 1; 16576 } else { 16577 display = 'none'; 16578 } 16579 _results.push(this.config.networks[network].display = display); 16580 } 16581 return _results; 16582 }; 16583 16584 Share.prototype.normalize_network_configuration = function() { 16585 if (!this.config.networks.facebook.app_id) { 16586 this.config.networks.facebook.load_sdk = false;
16587 } 16588 if (!this.is_encoded(this.config.networks.twitter.description)) { 16589 this.config.networks.twitter.description = encodeURIComponent(this.config.networks.twitter.description); 16590 } 16591 if (typeof this.config.networks.facebook.app_id === 'number') { 16592 return this.config.networks.facebook.app_id = this.config.networks.facebook.app_id.toString(); 16593 } 16594 }; 16595 16596 Share.prototype.normalize_filter_config_updates = function(opts) { 16597 if (this.config.networks.facebook.app_id !== opts.app_id) { 16598 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."); 16599 delete opts.app_id; 16600 } 16601 if (this.config.networks.facebook.load_sdk !== opts.load_sdk) { 16602 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."); 16603 delete opts.app_id; 16604 } 16605 return opts; 16606 }; 16607 16608 return Share; 16609 16610})(ShareUtils); 16611 return Share; 16612}); 16613 16614// Generated by CoffeeScript 1.9.2 16615 16616// @license Sticky-kit v1.1.2 | WTFPL | Leaf Corcoran 2015 | http://leafo.net 16617 16618(function() { 16619 var $, win; 16620 16621 $ = this.jQuery || window.jQuery; 16622 16623 win = $(window); 16624 16625 $.fn.stick_in_parent = function(opts) { 16626 var doc, elm, enable_bottoming, fn, i, inner_scrolling, len, manual_spacer, offset_top, outer_width, parent_selector, recalc_every, sticky_class; 16627 if (opts == null) { 16628 opts = {}; 16629 } 16630 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; 16631 if (offset_top == null) { 16632 offset_top = 0; 16633 } 16634 if (parent_selector == null) { 16635 parent_selector = void 0; 16636 } 16637 if (inner_scrolling == null) { 16638 inner_scrolling = true; 16639 } 16640 if (sticky_class == null) { 16641 sticky_class = "is_stuck"; 16642 } 16643 doc = $(document); 16644 if (enable_bottoming == null) { 16645 enable_bottoming = true; 16646 } 16647 outer_width = function(el) { 16648 var _el, computed, w; 16649 if (window.getComputedStyle) { 16650 _el = el[0]; 16651 computed = window.getComputedStyle(el[0]); 16652 w = parseFloat(computed.getPropertyValue("width")) + parseFloat(computed.getPropertyValue("margin-left")) + parseFloat(computed.getPropertyValue("margin-right")); 16653 if (computed.getPropertyValue("box-sizing") !== "border-box") { 16654 w += parseFloat(computed.getPropertyValue("border-left-width")) + parseFloat(computed.getPropertyValue("border-right-width")) + parseFloat(computed.getPropertyValue("padding-left")) + parseFloat(computed.getPropertyValue("padding-right")); 16655 } 16656 return w; 16657 } else { 16658 return el.outerWidth(true); 16659 } 16660 }; 16661 fn = function(elm, padding_bottom, parent_top, parent_height, top, height, el_float, detached) { 16662 var bottomed, detach, fixed, last_pos, last_scroll_height, offset, parent, recalc, recalc_and_tick, recalc_counter, spacer, tick; 16663 if (elm.data("sticky_kit")) { 16664 return; 16665 } 16666 elm.data("sticky_kit", true); 16667 last_scroll_height = doc.height(); 16668 parent = elm.parent(); 16669 if (parent_selector != null) { 16670 parent = parent.closest(parent_selector); 16671 } 16672 if (!parent.length) { 16673 throw "failed to find stick parent"; 16674 } 16675 fixed = false; 16676 bottomed = false; 16677 spacer = manual_spacer != null ? manual_spacer && elm.closest(manual_spacer) : $("<div />"); 16678 if (spacer) { 16679 spacer.css('position', elm.css('position')); 16680 } 16681 recalc = function() { 16682 var border_top, padding_top, restore; 16683 if (detached) { 16684 return; 16685 } 16686 last_scroll_height = doc.height(); 16687 border_top = parseInt(parent.css("border-top-width"), 10); 16688 padding_top = parseInt(parent.css("padding-top"), 10); 16689 padding_bottom = parseInt(parent.css("padding-bottom"), 10); 16690 parent_top = parent.offset().top + border_top + padding_top; 16691 parent_height = parent.height(); 16692 if (fixed) { 16693 fixed = false;
vendor: 6,068 bytes, lines 16694-16888
16694 bottomed = false; 16695 if (manual_spacer == null) { 16696 elm.insertAfter(spacer); 16697 spacer.detach(); 16698 } 16699 elm.css({ 16700 position: "", 16701 top: "", 16702 width: "", 16703 bottom: "" 16704 }).removeClass(sticky_class); 16705 restore = true; 16706 } 16707 top = elm.offset().top - (parseInt(elm.css("margin-top"), 10) || 0) - offset_top; 16708 height = elm.outerHeight(true); 16709 el_float = elm.css("float"); 16710 if (spacer) { 16711 spacer.css({ 16712 width: outer_width(elm), 16713 height: height, 16714 display: elm.css("display"), 16715 "vertical-align": elm.css("vertical-align"), 16716 "float": el_float 16717 }); 16718 } 16719 if (restore) { 16720 return tick(); 16721 } 16722 }; 16723 recalc(); 16724 if (height === parent_height) { 16725 return; 16726 } 16727 last_pos = void 0; 16728 offset = offset_top; 16729 recalc_counter = recalc_every; 16730 tick = function() { 16731 var css, delta, recalced, scroll, will_bottom, win_height; 16732 if (detached) { 16733 return; 16734 } 16735 recalced = false; 16736 if (recalc_counter != null) { 16737 recalc_counter -= 1; 16738 if (recalc_counter <= 0) { 16739 recalc_counter = recalc_every; 16740 recalc(); 16741 recalced = true; 16742 } 16743 } 16744 if (!recalced && doc.height() !== last_scroll_height) { 16745 recalc(); 16746 recalced = true; 16747 } 16748 scroll = win.scrollTop(); 16749 if (last_pos != null) { 16750 delta = scroll - last_pos; 16751 } 16752 last_pos = scroll; 16753 if (fixed) { 16754 if (enable_bottoming) { 16755 will_bottom = scroll + height + offset > parent_height + parent_top; 16756 if (bottomed && !will_bottom) { 16757 bottomed = false; 16758 elm.css({ 16759 position: "fixed", 16760 bottom: "", 16761 top: offset 16762 }).trigger("sticky_kit:unbottom"); 16763 } 16764 } 16765 if (scroll < top) { 16766 fixed = false; 16767 offset = offset_top; 16768 if (manual_spacer == null) { 16769 if (el_float === "left" || el_float === "right") { 16770 elm.insertAfter(spacer); 16771 } 16772 spacer.detach(); 16773 } 16774 css = { 16775 position: "", 16776 width: "", 16777 top: "" 16778 }; 16779 elm.css(css).removeClass(sticky_class).trigger("sticky_kit:unstick"); 16780 } 16781 if (inner_scrolling) { 16782 win_height = win.height(); 16783 if (height + offset_top > win_height) { 16784 if (!bottomed) { 16785 offset -= delta; 16786 offset = Math.max(win_height - height, offset); 16787 offset = Math.min(offset_top, offset); 16788 if (fixed) { 16789 elm.css({ 16790 top: offset + "px" 16791 }); 16792 } 16793 } 16794 } 16795 } 16796 } else { 16797 if (scroll > top) { 16798 fixed = true; 16799 css = { 16800 position: "fixed", 16801 top: offset 16802 }; 16803 css.width = elm.css("box-sizing") === "border-box" ? elm.outerWidth() + "px" : elm.width() + "px"; 16804 elm.css(css).addClass(sticky_class); 16805 if (manual_spacer == null) { 16806 elm.after(spacer); 16807 if (el_float === "left" || el_float === "right") { 16808 spacer.append(elm); 16809 } 16810 } 16811 elm.trigger("sticky_kit:stick"); 16812 } 16813 } 16814 if (fixed && enable_bottoming) { 16815 if (will_bottom == null) { 16816 will_bottom = scroll + height + offset > parent_height + parent_top; 16817 } 16818 if (!bottomed && will_bottom) { 16819 bottomed = true; 16820 if (parent.css("position") === "static") { 16821 parent.css({ 16822 position: "relative" 16823 }); 16824 } 16825 return elm.css({ 16826 position: "absolute", 16827 bottom: padding_bottom, 16828 top: "auto" 16829 }).trigger("sticky_kit:bottom"); 16830 } 16831 } 16832 }; 16833 recalc_and_tick = function() { 16834 recalc(); 16835 return tick(); 16836 }; 16837 detach = function() { 16838 detached = true; 16839 win.off("touchmove", tick); 16840 win.off("scroll", tick); 16841 win.off("resize", recalc_and_tick); 16842 $(document.body).off("sticky_kit:recalc", recalc_and_tick); 16843 elm.off("sticky_kit:detach", detach); 16844 elm.removeData("sticky_kit"); 16845 elm.css({ 16846 position: "", 16847 bottom: "", 16848 top: "", 16849 width: "" 16850 }); 16851 parent.position("position", ""); 16852 if (fixed) { 16853 if (manual_spacer == null) { 16854 if (el_float === "left" || el_float === "right") { 16855 elm.insertAfter(spacer); 16856 } 16857 spacer.remove(); 16858 } 16859 return elm.removeClass(sticky_class); 16860 } 16861 }; 16862 win.on("touchmove", tick); 16863 win.on("scroll", tick); 16864 win.on("resize", recalc_and_tick); 16865 $(document.body).on("sticky_kit:recalc", recalc_and_tick); 16866 elm.on("sticky_kit:detach", detach); 16867 return setTimeout(tick, 0); 16868 }; 16869 for (i = 0, len = this.length; i < len; i++) { 16870 elm = this[i]; 16871 fn($(elm)); 16872 } 16873 return this; 16874 }; 16875 16876}).call(this); 16877/* ========================================================================== 16878 * bootstrap-tab-history.js 16879 * Author: Michael Narayan <[email protected]> 16880 * Repository: https://github.com/mnarayan01/bootstrap-tab-history/ 16881 * ========================================================================== 16882 * Licensed under the Apache License, Version 2.0 (the "License"); you may 16883 * not use this file except in compliance with the License. You may obtain a 16884 * copy of the License at 16885 * 16886 * http://www.apache.org/licenses/LICENSE-2.0 16887 * 16888 * Unless required by applicable law or agreed to in writing, softw
16888are 16889 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 16890 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 16891 * License for the specific language governing permissions and limitations 16892 * under the License. 16893 * ========================================================================== */ 16894 16895/* ========================================================================== */ 16896/* JSHint directives */ 16897/* */ 16898/* global BootstrapTabHistory: true */ 16899/* */ 16900/* global document */ 16901/* global jQuery */ 16902/* global history */ 16903/* global window */ 16904/* ========================================================================== */ 16905 16906/** 16907 * Integrate [HTML5 history state tracking](https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Manipulating_the_browser_history) 16908 * with [`bootstrap/tab.js`](http://getbootstrap.com/javascript/#tabs). To enable tracking on a tab element, simply set 16909 * the `data-tab-history` attribute to true (or a string denoting a tab grouping). 16910 * 16911 * See the README for additional information. 16912 * 16913 * Functionality based upon bootstrap/tab.js v3.1.0; reference it when making any changes. 16914 */ 16915 16916BootstrapTabHistory = { 16917 options: { 16918 /** 16919 * When the anchor portion of the URI is used to activate a tab, scroll down to the given offset, rather than the 16920 * element with the given `id` attribute. Set to null to disable. Only relevant if showTabsBasedOnAnchor is true. 16921 * 16922 * May be overriden on a per-element basis by the attribute `data-tab-history-anchor-y-offset`. 16923 * 16924 * @public 16925 * @type {?number} 16926 */ 16927 defaultAnchorYOffset: 0, 16928 /** 16929 * Either 'push' or 'replace', for whether to use `history.pushState` or `history.replaceState`, resp. 16930 * 16931 * May be overriden on a per-element basis by the attribute `data-tab-history-changer`. 16932 * 16933 * @public 16934 * @type {string} 16935 */ 16936 defaultChanger: 'replace', 16937 /** 16938 * If true, update the URL in onShownTab in the calls to `history.pushState` and `history.replaceState`. Otherwise, 16939 * `null` is passed as the third parameter to these calls. 16940 * 16941 * May be overriden on a per-element basis by the attribute `data-tab-history-update-url`. 16942 * 16943 * @public 16944 * @type {boolean} 16945 */ 16946 defaultUpdateURL: false, 16947 /** 16948 * Should the anchor portion of the loaded URI be used to activate a single tab if no history was present on page 16949 * load. 16950 * 16951 * @public 16952 * @type {boolean} 16953 */ 16954 showTabsBasedOnAnchor: true 16955 } 16956}; 16957 16958(function () { 16959 'use strict'; 16960 16961 jQuery(function () { 16962 if(history && history.pushState && history.replaceState) { 16963 var bootstrapTabHistory = history.state && history.state.bootstrapTabHistory; 16964 16965 if(bootstrapTabHistory) { 16966 showTabsBasedOnState(bootstrapTabHistory); 16967 } else { 16968 showTabsBasedOnAnchor(); 16969 } 16970 16971 backfillHistoryState(); 16972 16973 jQuery(document).on('shown.bs.tab show.bs.collapse', onShownTab); 16974 jQuery(window).on('popstate', onPopState); 16975 } else { 16976 showTabsBasedOnAnchor(); 16977 } 16978 }); 16979 16980 /** 16981 * Used to prevent onShownTab from registering shown events that we triggered via showTabsBasedOnState. 16982 * 16983 * @type {boolean} 16984 */ 16985 var showingTabsBasedOnState = false; 16986 16987 /** 16988 * Used to update `history.state` to reflect the default active tabs on initial page load. This supports proper 16989 * `history.back` handling when `data-tab-history-update-url` is true. 16990 */ 16991 function backfillHistoryState() { 16992 var newState = null; 16993 16994 jQuery('li.active > [data-tab-history], .panel-title.active [data-tab-history]').each(function () {//edited by Uncode 16995 var $activeTabElement = jQuery(this); 16996 var selector = getTabSelector($activeTabElement); 16997 16998 if(selector) { 16999 var tabGroup = getTabGroup($activeTabElement); 17000 17001 if(tabGroup) { 17002 newState = createNewHistoryState(newState || history.state, tabGroup, selector); 17003 } 17004 } 17005 }); 17006 17007 if(newState) { 17008 history.replaceState(newState, '', null); 17009 } 17010 } 17011 17012 /** 17013 * Clone the existing state, ensure its bootstrapTabHistory attribute is an Object, and add the provided tabGroup to 17014 * said bootstrapTabHistory attribute. 17015 * 17016 * @param {?object} existingState 17017 * @param {!string} tabGroup 17018 * @param {!string} selector 17019 * @returns {!object} 17020 */ 17021 function createNewHistoryState(existingState, tabGroup, selector) { 17022 // Clone history.state and ensure it has a bootstrapTabHistory entry. 17023 var newState = jQuery.extend(true, {}, existingState, { 17024 bootstrapTabHistory: {} 17025 }); 17026 17027 newState.bootstrapTabHistory[tabGroup] = selector; 17028 17029 return newState; 17030 } 17031 17032 /** 17033 * @param {jQuery} $tab
17034 * @returns {?string} 17035 */ 17036 function getTabGroup($tab) { 17037 return parseTruthyAttributeValue($tab.data('tab-history')); 17038 } 17039 17040 /** 17041 * @param {jQuery} $tab 17042 * @returns {?string} 17043 */ 17044 function getTabSelector($tab) { 17045 return $tab.data('target') || $tab.attr('href'); 17046 } 17047 17048 /** 17049 * Receives the `shown.bs.tab` event. Updates `history.state` as appropriate. 17050 * 17051 * @param {jQuery.Event} shownEvt 17052 */ 17053 function onShownTab(shownEvt) { 17054 if(!showingTabsBasedOnState) { 17055 var $activatedTab = jQuery(shownEvt.target); 17056 if ( $activatedTab.hasClass('panel-collapse') ) 17057 $activatedTab = $activatedTab.closest('.panel').find('a'); 17058 var selector = getTabSelector($activatedTab); 17059 17060 if(selector) { 17061 var tabGroup = getTabGroup($activatedTab); 17062 17063 if(tabGroup) { 17064 var historyChanger = $activatedTab.data('tab-history-changer') || BootstrapTabHistory.options.defaultChanger; 17065 var newState = createNewHistoryState(history.state, tabGroup, selector); 17066 var updateURL = (function ($activatedTab) { 17067 if(selector[0] === '#') { 17068 var elementUpdateURLOption = parseTruthyAttributeValue($activatedTab.data('tab-history-update-url')); 17069 17070 if(elementUpdateURLOption === undefined) { 17071 return BootstrapTabHistory.options.defaultUpdateURL; 17072 } else { 17073 return elementUpdateURLOption; 17074 } 17075 } else { 17076 return false; 17077 } 17078 })($activatedTab); 17079 17080 switch(historyChanger) { 17081 case 'push': 17082 history.pushState(newState, '', updateURL ? selector : null); 17083 break; 17084 case 'replace': 17085 history.replaceState(newState, '', updateURL ? selector : null); 17086 break; 17087 default: 17088 throw new Error('Unknown tab-history-changer: ' + historyChanger); 17089 } 17090 } 17091 } 17092 } 17093 } 17094 17095 /** 17096 * Receives the `popstate` event. Shows tabs based on the value of `history.state` as appropriate. 17097 */ 17098 function onPopState() { 17099 var bootstrapTabHistory = history.state && history.state.bootstrapTabHistory; 17100 17101 if(bootstrapTabHistory) { 17102 showTabsBasedOnState(bootstrapTabHistory); 17103 } 17104 } 17105 17106 /** 17107 * Returns the given value, _unless_ that value is an empty string, in which case `true` is returned. 17108 * 17109 * Rationale: HAML data attributes which are set to `true` are rendered as a blank string. 17110 * 17111 * @param {*} value 17112 * @returns {*} 17113 */ 17114 function parseTruthyAttributeValue(value) { 17115 if(value) { 17116 return value; 17117 } else if(value === '') { 17118 return true; 17119 } else { 17120 return value; 17121 } 17122 } 17123 17124 /** 17125 * Show tabs based upon the anchor component of `window.location`. 17126 */ 17127 function showTabsBasedOnAnchor() { 17128 if(BootstrapTabHistory.options.showTabsBasedOnAnchor) { 17129 var anchor = window.location && window.location.hash; 17130 17131 if(anchor) { 17132 var $tabElement = showTabForSelector(anchor); 17133 17134 if($tabElement && window.addEventListener && window.removeEventListener) { 17135 var anchorYOffset = (function ($tabElement) { 17136 var elementSetting = $tabElement.data('tab-history-anchor-y-offset'); 17137 17138 if(elementSetting === undefined) { 17139 return BootstrapTabHistory.options.defaultAnchorYOffset; 17140 } else { 17141 return elementSetting; 17142 } 17143 })($tabElement); 17144 17145 // HACK: This prevents scrolling to the tab on page load. This relies on the fact that we should never get 17146 // here on `history.forward`, `history.back`, or `location.reload`, since in all those situations the 17147 // `history.state` object should have been used (unless the browser did not support the modern History API). 17148 if(anchorYOffset || anchorYOffset === 0) { 17149 var scrollListener = function resetAnchorScroll () { 17150 window.removeEventListener('scroll', scrollListener); 17151 window.scrollTo(0, anchorYOffset); 17152 }; 17153 17154 window.addEventListener('scroll', scrollListener); 17155 } 17156 } 17157 } 17158 } 17159 } 17160 17161 /** 17162 * Show a tab which corresponds to the provided selector. 17163 * 17164 * @param {string} selector - A CSS selector. 17165 * @returns {?jQuery} - The tab which was found to show (even if said tab was already active). 17166 */ 17167 function showTabForSelector(selector) { 17168 var $tabElement = (function (selector) { 17169 var $ret = null; 17170 17171 jQuery('[data-toggle="tab"], [data-toggle="pill"], [data-toggle="collapse"]').each(function () { 17172 var $potentialTab = jQuery(this); 17173 17174 if(($potentialTab.attr('href') === selector || $potentialTab.data('target') === selector ) && getTabGroup($potentialTab)) { 17175 $ret = $potentialTab; 17176 return false;
vendor: 4,522 bytes, lines 17177-17326
17177 } else { 17178 return null; 17179 } 17180 }); 17181 17182 return $ret; 17183 })(selector); 17184 17185 if($tabElement) { 17186 $tabElement.trigger('click'); 17187 //$tabElement.tab('show'); 17188 } 17189 17190 return $tabElement; 17191 } 17192 17193 /** 17194 * Iterate through the provided set of tab tab groups, showing the tabs based on the stored selectors. 17195 * 17196 * @param {object} bootstrapTabHistory - Each of the values is passed to showTabForSelector; the keys are actually irrelevant. 17197 */ 17198 function showTabsBasedOnState(bootstrapTabHistory) { 17199 showingTabsBasedOnState = true; 17200 17201 try { 17202 for(var k in bootstrapTabHistory) { 17203 if(bootstrapTabHistory.hasOwnProperty(k)) { 17204 showTabForSelector(bootstrapTabHistory[k]); 17205 } 17206 } 17207 } finally { 17208 showingTabsBasedOnState = false; 17209 } 17210 } 17211})(); 17212 17213/*! 17214 * Justified Gallery - v3.6.3 17215 * http://miromannino.github.io/Justified-Gallery/ 17216 * Copyright (c) 2016 Miro Mannino 17217 * Licensed under the MIT license. 17218 */ 17219(function($) { 17220 17221 function hasScrollBar() { 17222 return $("body").height() > $(window).height(); 17223 } 17224 /** 17225 * Justified Gallery controller constructor 17226 * 17227 * @param $gallery the gallery to build 17228 * @param settings the settings (the defaults are in $.fn.justifiedGallery.defaults) 17229 * @constructor 17230 */ 17231 var JustifiedGallery = function ($gallery, settings) { 17232 17233 this.settings = settings; 17234 this.checkSettings(); 17235 17236 this.imgAnalyzerTimeout = null; 17237 this.entries = null; 17238 this.buildingRow = { 17239 entriesBuff : [], 17240 width : 0, 17241 height : 0, 17242 aspectRatio : 0 17243 }; 17244 this.lastFetchedEntry = null; 17245 this.lastAnalyzedIndex = -1; 17246 this.yield = { 17247 every : 2, // do a flush every n flushes (must be greater than 1) 17248 flushed : 0 // flushed rows without a yield 17249 }; 17250 this.border = settings.border >= 0 ? settings.border : settings.margins; 17251 this.maxRowHeight = this.retrieveMaxRowHeight(); 17252 this.suffixRanges = this.retrieveSuffixRanges(); 17253 this.offY = this.border; 17254 this.rows = 0; 17255 this.spinner = { 17256 phase : 0, 17257 timeSlot : 150, 17258 $el : $('<div class="spinner"><span></span><span></span><span></span></div>'), 17259 intervalId : null 17260 }; 17261 this.checkWidthIntervalId = null; 17262 this.galleryWidth = $gallery.width(); 17263 this.$gallery = $gallery; 17264 17265 }; 17266 17267 /** @returns {String} the best suffix given the width and the height */ 17268 JustifiedGallery.prototype.getSuffix = function (width, height) { 17269 var longestSide, i; 17270 longestSide = (width > height) ? width : height; 17271 for (i = 0; i < this.suffixRanges.length; i++) { 17272 if (longestSide <= this.suffixRanges[i]) { 17273 return this.settings.sizeRangeSuffixes[this.suffixRanges[i]]; 17274 } 17275 } 17276 return this.settings.sizeRangeSuffixes[this.suffixRanges[i - 1]]; 17277 }; 17278 17279 /** 17280 * Remove the suffix from the string 17281 * 17282 * @returns {string} a new string without the suffix 17283 */ 17284 JustifiedGallery.prototype.removeSuffix = function (str, suffix) { 17285 return str.substring(0, str.length - suffix.length); 17286 }; 17287 17288 /** 17289 * @returns {boolean} a boolean to say if the suffix is contained in the str or not 17290 */ 17291 JustifiedGallery.prototype.endsWith = function (str, suffix) { 17292 return str.indexOf(suffix, str.length - suffix.length) !== -1; 17293 }; 17294 17295 /** 17296 * Get the used suffix of a particular url 17297 * 17298 * @param str 17299 * @returns {String} return the used suffix 17300 */ 17301 JustifiedGallery.prototype.getUsedSuffix = function (str) { 17302 for (var si in this.settings.sizeRangeSuffixes) { 17303 if (this.settings.sizeRangeSuffixes.hasOwnProperty(si)) { 17304 if (this.settings.sizeRangeSuffixes[si].length === 0) continue; 17305 if (this.endsWith(str, this.settings.sizeRangeSuffixes[si])) return this.settings.sizeRangeSuffixes[si]; 17306 } 17307 } 17308 return ''; 17309 }; 17310 17311 /** 17312 * Given an image src, with the width and the height, returns the new image src with the 17313 * best suffix to show the best quality thumbnail. 17314 * 17315 * @returns {String} the suffix to use 17316 */ 17317 JustifiedGallery.prototype.newSrc = function (imageSrc, imgWidth, imgHeight, image) { 17318 var newImageSrc; 17319 17320 if (this.settings.thumbnailPath) { 17321 newImageSrc = this.settings.thumbnailPath(imageSrc, imgWidth, imgHeight, image); 17322 } else { 17323 var matchRes = imageSrc.match(this.settings.extension); 17324 var ext = (matchRes !== null) ? matchRes[0] : ''; 17325 newImageSrc = imageSrc.replace(this.settings.extension, ''); 17326 newImageSrc = this.removeSuffix(newImageSrc, this.getUsedSuffix(newImageSrc));
17327 newImageSrc += this.getSuffix(imgWidth, imgHeight) + ext; 17328 } 17329 17330 return newImageSrc; 17331 }; 17332 17333 /** 17334 * Shows the images that is in the given entry 17335 * 17336 * @param $entry the entry 17337 * @param callback the callback that is called when the show animation is finished 17338 */ 17339 JustifiedGallery.prototype.showImg = function ($entry, callback) { 17340 if (this.settings.cssAnimation) { 17341 $entry.addClass('entry-visible'); 17342 if (callback) callback(); 17343 } else { 17344 $entry.stop().fadeTo(this.settings.imagesAnimationDuration, 1.0, callback); 17345 $entry.find('> img, > a > img').stop().fadeTo(this.settings.imagesAnimationDuration, 1.0, callback); 17346 } 17347 }; 17348 17349 /** 17350 * Extract the image src form the image, looking from the 'safe-src', and if it can't be found, from the 17351 * 'src' attribute. It saves in the image data the 'jg.originalSrc' field, with the extracted src. 17352 * 17353 * @param $image the image to analyze 17354 * @returns {String} the extracted src 17355 */ 17356 JustifiedGallery.prototype.extractImgSrcFromImage = function ($image) { 17357 var imageSrc = (typeof $image.data('safe-src') !== 'undefined') ? $image.data('safe-src') : $image.attr('src'); 17358 $image.data('jg.originalSrc', imageSrc); 17359 return imageSrc; 17360 }; 17361 17362 /** @returns {jQuery} the image in the given entry */ 17363 JustifiedGallery.prototype.imgFromEntry = function ($entry) { 17364 var $img = $entry.find('> img'); 17365 if ($img.length === 0) $img = $entry.find('> a > img'); 17366 if ($img.length === 0) $img = $entry.find('.t-entry-visual-cont img');//hacked by Uncode 17367 return $img.length === 0 ? null : $img; 17368 }; 17369 17370 /** @returns {jQuery} the caption in the given entry */ 17371 JustifiedGallery.prototype.captionFromEntry = function ($entry) { 17372 var $caption = $entry.find('> .caption'); 17373 return $caption.length === 0 ? null : $caption; 17374 }; 17375 17376 /** 17377 * Display the entry 17378 * 17379 * @param {jQuery} $entry the entry to display 17380 * @param {int} x the x position where the entry must be positioned 17381 * @param y the y position where the entry must be positioned 17382 * @param imgWidth the image width 17383 * @param imgHeight the image height 17384 * @param rowHeight the row height of the row that owns the entry 17385 */ 17386 JustifiedGallery.prototype.displayEntry = function ($entry, x, y, imgWidth, imgHeight, rowHeight) { 17387 $entry.width(imgWidth); 17388 $entry.height(Math.floor(rowHeight));//hacked by Uncode 17389 $entry.css('top', Math.floor(y));//hacked by Uncode 17390 $entry.css('left', x); 17391 17392 var $image = this.imgFromEntry($entry); 17393 if ($image !== null) { 17394 $image.css('width', imgWidth); 17395 $image.css('height', imgHeight); 17396 $image.css('margin-left', - imgWidth / 2); 17397 $image.css('margin-top', - imgHeight / 2); 17398 17399 // Image reloading for an high quality of thumbnails 17400 var imageSrc = $image.attr('src'); 17401 var newImageSrc = this.newSrc(imageSrc, imgWidth, imgHeight, $image[0]); 17402 17403 $image.one('error', function () { 17404 $image.attr('src', $image.data('jg.originalSrc')); //revert to the original thumbnail, we got it. 17405 }); 17406 17407 var loadNewImage = function () { 17408 if (imageSrc !== newImageSrc) { //load the new image after the fadeIn 17409 $image.attr('src', newImageSrc); 17410 } 17411 }; 17412 17413 if ($entry.data('jg.loaded') === 'skipped') { 17414 this.onImageEvent(imageSrc, $.proxy(function() { 17415 this.showImg($entry, loadNewImage); 17416 $entry.data('jg.loaded', true); 17417 }, this)); 17418 } else { 17419 this.showImg($entry, loadNewImage); 17420 } 17421 17422 } else { 17423 this.showImg($entry); 17424 } 17425 17426 this.displayEntryCaption($entry); 17427 }; 17428 17429 /** 17430 * Display the entry caption. If the caption element doesn't exists, it creates the caption using the 'alt' 17431 * or the 'title' attributes. 17432 * 17433 * @param {jQuery} $entry the entry to process 17434 */ 17435 JustifiedGallery.prototype.displayEntryCaption = function ($entry) { 17436 var $image = this.imgFromEntry($entry); 17437 if ($image !== null && this.settings.captions) { 17438 var $imgCaption = this.captionFromEntry($entry); 17439 17440 // Create it if it doesn't exists 17441 if ($imgCaption === null) { 17442 var caption = $image.attr('alt'); 17443 if (!this.isValidCaption(caption)) caption = $entry.attr('title'); 17444 if (this.isValidCaption(caption)) { // Create only we found something 17445 $imgCaption = $('<div class="caption">' + caption + '</div>'); 17446 $entry.append($imgCaption); 17447 $entry.data('jg.createdCaption', true); 17448 } 17449 } 17450 17451 // Create events (we check again the $imgCaption because it can be still inexistent) 17452 if ($imgCaption !== null) { 17453 if (!this.settings.cssAnimation) $imgCaption.stop().fadeTo(0, this.settings.captionSettings.nonVisibleOpacity); 17454 this.addCaptionEventsHandlers($entry); 17455 } 17456 } else { 17457 this.removeCaptionEventsHandlers($entry); 17458 } 17459 }; 17460 17461 /** 17462 * Validates the caption 17463 * 17464 * @param caption The caption that should be validated 17465 * @return {boolean} Validation result 17466 */ 17467 JustifiedGallery.prototype.isValidCaption = function (caption) { 17468 return (typeof caption !== 'undefined' && caption.length > 0); 17469 }; 17470 17471 /** 17472 * The callback for the event 'mouseenter'. It assumes that the event currentTarget is an entry. 17473 * It shows the caption using jQuery (or using CSS if it is configured so) 17474 * 17475 * @param {Event} eventObject the event object 17476 */ 17477 JustifiedGallery.prototype.onEntryMouseEnterForCaption = function (eventObject) { 17478 var $caption = this.captionFromEntry($(eventObject.currentTarget)); 17479 if (this.settings.cssAnimation) { 17480 $caption.addClass('caption-visible').removeClass('caption-hidden'); 17481 } else { 17482 $caption.stop().fadeTo(this.settings.captionSettings.animationDuration, 17483 this.settings.captionSettings.visibleOpacity); 17484 } 17485 }; 17486 17487 /** 17488 * The callback for the event 'mouseleave'. It assumes that the event currentTarget is an entry. 17489 * It hides the caption using jQuery (or using CSS if it is configured so) 17490 * 17491 * @param {Event} eventObject the event object 17492 */ 17493 JustifiedGallery.prototype.onEntryMouseLeaveForCaption = function (eventObject) { 17494 var $caption = this.captionFromEntry($(eventObject.currentTarget)); 17495 if (this.settings.cssAnimation) { 17496 $caption.removeClass('caption-visible').removeClass('caption-hidden'); 17497 } else { 17498 $caption.stop().fadeTo(this.settings.captionSettings.animationDuration, 17499 this.settings.captionSettings.nonVisibleOpacity); 17500 } 17501 }; 17502 17503 /** 17504 * Add the handlers of the entry for the caption 17505 * 17506 * @param $entry the entry to modify 17507 */ 17508 JustifiedGallery.prototype.addCaptionEventsHandlers = function ($entry) { 17509 var captionMouseEvents = $entry.data('jg.captionMouseEvents'); 17510 if (typeof captionMouseEvents === 'undefined') { 17511 captionMouseEvents = { 17512 mouseenter: $.proxy(this.onEntryMouseEnterForCaption, this), 17513 mouseleave: $.proxy(this.onEntryMouseLeaveForCaption, this) 17514 }; 17515 $entry.on('mouseenter', undefined, undefined, captionMouseEvents.mouseenter); 17516 $entry.on('mouseleave', undefined, undefined, captionMouseEvents.mouseleave); 17517 $entry.data('jg.captionMouseEvents', captionMouseEvents); 17518 } 17519 }; 17520 17521 /** 17522 * Remove the handlers of the entry for the caption 17523 * 17524 * @param $entry the entry to modify 17525 */ 17526 JustifiedGallery.prototype.removeCaptionEventsHandlers = function ($entry) { 17527 var captionMouseEvents = $entry.data('jg.captionMouseEvents'); 17528 if (typeof captionMouseEvents !== 'undefined') { 17529 $entry.off('mouseenter', undefined, captionMouseEvents.mouseenter); 17530 $entry.off('mouseleave', undefined, captionMouseEvents.mouseleave); 17531 $entry.removeData('jg.captionMouseEvents'); 17532 } 17533 }; 17534 17535 /** 17536 * Justify the building row, preparing it to 17537 * 17538 * @param isLastRow 17539 * @returns a boolean to know if the row has been justified or not 17540 */ 17541 JustifiedGallery.prototype.prepareBuildingRow = function (isLastRow) { 17542 var i, $entry, imgAspectRatio, newImgW, newImgH, justify = true; 17543 var minHeight = 0; 17544 var availableWidth = this.galleryWidth - 2 * this.border - ( 17545 (this.buildingRow.entriesBuff.length - 1) * this.settings.margins); 17546 var rowHeight = Math.floor( availableWidth / this.buildingRow.aspectRatio );//hacked by Uncode 17547 var defaultRowHeight = this.settings.rowHeight; 17548 var justifiable = this.buildingRow.width / availableWidth > this.settings.justifyThreshold; 17549 17550 //Skip the last row if we can't justify it and the lastRow == 'hide' 17551 if (isLastRow && this.settings.lastRow === 'hide' && !justifiable) { 17552 for (i = 0; i < this.buildingRow.entriesBuff.length; i++) { 17553 $entry = this.buildingRow.entriesBuff[i]; 17554 if (this.settings.cssAnimation) 17555 $entry.removeClass('entry-visible'); 17556 else { 17557 $entry.stop().fadeTo(0, 0.1); 17558 $entry.find('> img, > a > img').fadeTo(0, 0); 17559 } 17560 } 17561 return -1; 17562 } 17563 17564 // With lastRow = nojustify, justify if is justificable (the images will not become too big) 17565 if (isLastRow && !justifiable && this.settings.lastRow !== 'justify' && this.settings.lastRow !== 'hide') { 17566 justify = false;
17567 17568 if (this.rows > 0) { 17569 defaultRowHeight = (this.offY - this.border - this.settings.margins * this.rows) / this.rows; 17570 justify = defaultRowHeight * this.buildingRow.aspectRatio / availableWidth > this.settings.justifyThreshold; 17571 } 17572 } 17573 17574 for (i = 0; i < this.buildingRow.entriesBuff.length; i++) { 17575 $entry = this.buildingRow.entriesBuff[i]; 17576 imgAspectRatio = $entry.data('jg.width') / $entry.data('jg.height'); 17577 17578 if (justify) { 17579 newImgW = (i === this.buildingRow.entriesBuff.length - 1) ? availableWidth : rowHeight * imgAspectRatio; 17580 newImgH = rowHeight; 17581 } else { 17582 newImgW = defaultRowHeight * imgAspectRatio; 17583 newImgH = defaultRowHeight; 17584 } 17585 17586 availableWidth -= Math.round(newImgW); 17587 $entry.data('jg.jwidth', Math.round(newImgW)); 17588 $entry.data('jg.jheight', Math.ceil(newImgH)); 17589 if (i === 0 || minHeight > newImgH) minHeight = newImgH; 17590 } 17591 17592 this.buildingRow.height = minHeight; 17593 return justify; 17594 }; 17595 17596 /** 17597 * Clear the building row data to be used for a new row 17598 */ 17599 JustifiedGallery.prototype.clearBuildingRow = function () { 17600 this.buildingRow.entriesBuff = []; 17601 this.buildingRow.aspectRatio = 0; 17602 this.buildingRow.width = 0; 17603 }; 17604 17605 /** 17606 * Flush a row: justify it, modify the gallery height accordingly to the row height 17607 * 17608 * @param isLastRow 17609 */ 17610 JustifiedGallery.prototype.flushRow = function (isLastRow) { 17611 var settings = this.settings; 17612 var $entry, buildingRowRes, offX = this.border, i; 17613 17614 buildingRowRes = this.prepareBuildingRow(isLastRow); 17615 if (isLastRow && settings.lastRow === 'hide' && buildingRowRes === -1) { 17616 this.clearBuildingRow(); 17617 return; 17618 } 17619 17620 if (this.maxRowHeight) { 17621 if (this.maxRowHeight.isPercentage && this.maxRowHeight.value * settings.rowHeight < this.buildingRow.height) { 17622 this.buildingRow.height = this.maxRowHeight.value * settings.rowHeight; 17623 } else if (this.maxRowHeight.value >= settings.rowHeight && this.maxRowHeight.value < this.buildingRow.height) { 17624 this.buildingRow.height = this.maxRowHeight.value; 17625 } 17626 } 17627 17628 //Align last (unjustified) row 17629 if (settings.lastRow === 'center' || settings.lastRow === 'right') { 17630 var availableWidth = this.galleryWidth - 2 * this.border - (this.buildingRow.entriesBuff.length - 1) * settings.margins; 17631 17632 for (i = 0; i < this.buildingRow.entriesBuff.length; i++) { 17633 $entry = this.buildingRow.entriesBuff[i]; 17634 availableWidth -= $entry.data('jg.jwidth'); 17635 } 17636 17637 if (settings.lastRow === 'center') 17638 offX += availableWidth / 2; 17639 else if (settings.lastRow === 'right') 17640 offX += availableWidth; 17641 } 17642 17643 for (i = 0; i < this.buildingRow.entriesBuff.length; i++) { 17644 $entry = this.buildingRow.entriesBuff[i]; 17645 this.displayEntry($entry, offX, this.offY, $entry.data('jg.jwidth'), $entry.data('jg.jheight'), this.buildingRow.height); 17646 offX += $entry.data('jg.jwidth') + settings.margins; 17647 } 17648 17649 //Gallery Height 17650 this.galleryHeightToSet = this.offY + this.buildingRow.height + this.border; 17651 this.$gallery.height(this.galleryHeightToSet + this.getSpinnerHeight()); 17652 17653 if (!isLastRow || (this.buildingRow.height <= settings.rowHeight && buildingRowRes)) { 17654 //Ready for a new row 17655 this.offY += this.buildingRow.height + settings.margins; 17656 this.rows += 1; 17657 this.clearBuildingRow(); 17658 this.$gallery.trigger('jg.rowflush'); 17659 } 17660 }; 17661 17662 /** 17663 * Checks the width of the gallery container, to know if a new justification is needed 17664 */ 17665 var scrollBarOn = false; 17666 JustifiedGallery.prototype.checkWidth = function () { 17667 this.checkWidthIntervalId = setInterval($.proxy(function () { 17668 var galleryWidth = parseFloat(this.$gallery.width()); 17669 if (hasScrollBar() === scrollBarOn) { 17670 if (Math.abs(galleryWidth - this.galleryWidth) > this.settings.refreshSensitivity) { 17671 this.galleryWidth = galleryWidth; 17672 this.rewind(); 17673 17674 // Restart to analyze 17675 this.startImgAnalyzer(true); 17676 } 17677 } else { 17678 scrollBarOn = hasScrollBar(); 17679 this.galleryWidth = galleryWidth; 17680 } 17681 }, this), this.settings.refreshTime); 17682 }; 17683 17684 /** 17685 * @returns {boolean} a boolean saying if the spinner is active or not 17686 */ 17687 JustifiedGallery.prototype.isSpinnerActive = function () { 17688 return this.spinner.intervalId !== null; 17689 }; 17690 17691 /** 17692 * @returns {int} the spinner height 17693 */ 17694 JustifiedGallery.prototype.getSpinnerHeight = function () {
17695 return this.spinner.$el.innerHeight(); 17696 }; 17697 17698 /** 17699 * Stops the spinner animation and modify the gallery height to exclude the spinner 17700 */ 17701 JustifiedGallery.prototype.stopLoadingSpinnerAnimation = function () { 17702 clearInterval(this.spinner.intervalId); 17703 this.spinner.intervalId = null; 17704 this.$gallery.height(this.$gallery.height() - this.getSpinnerHeight()); 17705 this.spinner.$el.detach(); 17706 }; 17707 17708 /** 17709 * Starts the spinner animation 17710 */ 17711 JustifiedGallery.prototype.startLoadingSpinnerAnimation = function () { 17712 var spinnerContext = this.spinner; 17713 var $spinnerPoints = spinnerContext.$el.find('span'); 17714 clearInterval(spinnerContext.intervalId); 17715 this.$gallery.append(spinnerContext.$el); 17716 this.$gallery.height(this.offY + this.buildingRow.height + this.getSpinnerHeight()); 17717 spinnerContext.intervalId = setInterval(function () { 17718 if (spinnerContext.phase < $spinnerPoints.length) { 17719 $spinnerPoints.eq(spinnerContext.phase).fadeTo(spinnerContext.timeSlot, 1); 17720 } else {
vendor: 4,333 bytes, lines 17721-17865
17721 $spinnerPoints.eq(spinnerContext.phase - $spinnerPoints.length).fadeTo(spinnerContext.timeSlot, 0); 17722 } 17723 spinnerContext.phase = (spinnerContext.phase + 1) % ($spinnerPoints.length * 2); 17724 }, spinnerContext.timeSlot); 17725 }; 17726 17727 /** 17728 * Rewind the image analysis to start from the first entry. 17729 */ 17730 JustifiedGallery.prototype.rewind = function () { 17731 this.lastFetchedEntry = null; 17732 this.lastAnalyzedIndex = -1; 17733 this.offY = this.border; 17734 this.rows = 0; 17735 this.clearBuildingRow(); 17736 }; 17737 17738 /** 17739 * Update the entries searching it from the justified gallery HTML element 17740 * 17741 * @param norewind if norewind only the new entries will be changed (i.e. randomized, sorted or filtered) 17742 * @returns {boolean} true if some entries has been founded 17743 */ 17744 JustifiedGallery.prototype.updateEntries = function (norewind) { 17745 var newEntries; 17746 17747 if (norewind && this.lastFetchedEntry != null) { 17748 newEntries = $(this.lastFetchedEntry).nextAll(this.settings.selector).toArray(); 17749 } else { 17750 this.entries = []; 17751 newEntries = this.$gallery.children(this.settings.selector).toArray(); 17752 } 17753 17754 if (newEntries.length > 0) { 17755 17756 // Sort or randomize 17757 if ($.isFunction(this.settings.sort)) { 17758 newEntries = this.sortArray(newEntries); 17759 } else if (this.settings.randomize) { 17760 newEntries = this.shuffleArray(newEntries); 17761 } 17762 this.lastFetchedEntry = newEntries[newEntries.length - 1]; 17763 17764 // Filter 17765 if (this.settings.filter) { 17766 newEntries = this.filterArray(newEntries); 17767 } else { 17768 this.resetFilters(newEntries); 17769 } 17770 17771 } 17772 17773 this.entries = this.entries.concat(newEntries); 17774 return true; 17775 }; 17776 17777 /** 17778 * Apply the entries order to the DOM, iterating the entries and appending the images 17779 * 17780 * @param entries the entries that has been modified and that must be re-ordered in the DOM 17781 */ 17782 JustifiedGallery.prototype.insertToGallery = function (entries) { 17783 var that = this; 17784 $.each(entries, function () { 17785 $(this).appendTo(that.$gallery); 17786 }); 17787 }; 17788 17789 /** 17790 * Shuffle the array using the Fisher-Yates shuffle algorithm 17791 * 17792 * @param a the array to shuffle 17793 * @return the shuffled array 17794 */ 17795 JustifiedGallery.prototype.shuffleArray = function (a) { 17796 var i, j, temp; 17797 for (i = a.length - 1; i > 0; i--) { 17798 j = Math.floor(Math.random() * (i + 1)); 17799 temp = a[i]; 17800 a[i] = a[j]; 17801 a[j] = temp; 17802 } 17803 this.insertToGallery(a); 17804 return a; 17805 }; 17806 17807 /** 17808 * Sort the array using settings.comparator as comparator 17809 * 17810 * @param a the array to sort (it is sorted) 17811 * @return the sorted array 17812 */ 17813 JustifiedGallery.prototype.sortArray = function (a) { 17814 a.sort(this.settings.sort); 17815 this.insertToGallery(a); 17816 return a; 17817 }; 17818 17819 /** 17820 * Reset the filters removing the 'jg-filtered' class from all the entries 17821 * 17822 * @param a the array to reset 17823 */ 17824 JustifiedGallery.prototype.resetFilters = function (a) { 17825 for (var i = 0; i < a.length; i++) $(a[i]).removeClass('jg-filtered'); 17826 }; 17827 17828 /** 17829 * Filter the entries considering theirs classes (if a string has been passed) or using a function for filtering. 17830 * 17831 * @param a the array to filter 17832 * @return the filtered array 17833 */ 17834 JustifiedGallery.prototype.filterArray = function (a) { 17835 var settings = this.settings; 17836 if ($.type(settings.filter) === 'string') { 17837 // Filter only keeping the entries passed in the string 17838 return a.filter(function (el) { 17839 var $el = $(el); 17840 if ($el.is(settings.filter)) { 17841 $el.removeClass('jg-filtered'); 17842 return true; 17843 } else { 17844 $el.addClass('jg-filtered').removeClass('jg-visible'); 17845 return false; 17846 } 17847 }); 17848 } else if ($.isFunction(settings.filter)) { 17849 // Filter using the passed function 17850 var filteredArr = a.filter(settings.filter); 17851 for (var i = 0; i < a.length; i++) { 17852 if (filteredArr.indexOf(a[i]) == -1) { 17853 $(a[i]).addClass('jg-filtered').removeClass('jg-visible'); 17854 } else { 17855 $(a[i]).removeClass('jg-filtered'); 17856 } 17857 } 17858 return filteredArr; 17859 } 17860 }; 17861 17862 /** 17863 * Destroy the Justified Gallery instance. 17864 * 17865 * It clears all the css properties added in the style attributes. We doesn't backup the original
17866 * values for those css attributes, because it costs (performance) and because in general one 17867 * shouldn't use the style attribute for an uniform set of images (where we suppose the use of 17868 * classes). Creating a backup is also difficult because JG could be called multiple times and 17869 * with different style attributes. 17870 */ 17871 JustifiedGallery.prototype.destroy = function () { 17872 clearInterval(this.checkWidthIntervalId); 17873 17874 $.each(this.entries, $.proxy(function(_, entry) { 17875 var $entry = $(entry); 17876 17877 // Reset entry style 17878 $entry.css('width', ''); 17879 $entry.css('height', ''); 17880 $entry.css('top', ''); 17881 $entry.css('left', ''); 17882 $entry.data('jg.loaded', undefined); 17883 $entry.removeClass('jg-entry'); 17884 17885 // Reset image style 17886 var $img = this.imgFromEntry($entry); 17887 $img.css('width', ''); 17888 $img.css('height', ''); 17889 $img.css('margin-left', ''); 17890 $img.css('margin-top', ''); 17891 $img.attr('src', $img.data('jg.originalSrc')); 17892 $img.data('jg.originalSrc', undefined); 17893 17894 // Remove caption 17895 this.removeCaptionEventsHandlers($entry); 17896 var $caption = this.captionFromEntry($entry); 17897 if ($entry.data('jg.createdCaption')) { 17898 // remove also the caption element (if created by jg) 17899 $entry.data('jg.createdCaption', undefined); 17900 if ($caption !== null) $caption.remove(); 17901 } else { 17902 if ($caption !== null) $caption.fadeTo(0, 1); 17903 } 17904 17905 }, this)); 17906 17907 this.$gallery.css('height', ''); 17908 this.$gallery.removeClass('justified-gallery'); 17909 this.$gallery.data('jg.controller', undefined); 17910 }; 17911 17912 /** 17913 * Analyze the images and builds the rows. It returns if it found an image that is not loaded. 17914 * 17915 * @param isForResize if the image analyzer is called for resizing or not, to call a different callback at the end 17916 */ 17917 JustifiedGallery.prototype.analyzeImages = function (isForResize) { 17918 for (var i = this.lastAnalyzedIndex + 1; i < this.entries.length; i++) { 17919 var $entry = $(this.entries[i]); 17920 if ($entry.data('jg.loaded') === true || $entry.data('jg.loaded') === 'skipped') { 17921 var availableWidth = this.galleryWidth - 2 * this.border - ( 17922 (this.buildingRow.entriesBuff.length - 1) * this.settings.margins); 17923 var imgAspectRatio = $entry.data('jg.width') / $entry.data('jg.height'); 17924 if (availableWidth / (this.buildingRow.aspectRatio + imgAspectRatio) < this.settings.rowHeight) { 17925 this.flushRow(false); 17926 if(++this.yield.flushed >= this.yield.every) { 17927 this.startImgAnalyzer(isForResize); 17928 return; 17929 } 17930 } 17931 17932 this.buildingRow.entriesBuff.push($entry); 17933 this.buildingRow.aspectRatio += imgAspectRatio; 17934 this.buildingRow.width += imgAspectRatio * this.settings.rowHeight; 17935 this.lastAnalyzedIndex = i; 17936 17937 } else if ($entry.data('jg.loaded') !== 'error') { 17938 return; 17939 } 17940 } 17941 17942 // Last row flush (the row is not full) 17943 if (this.buildingRow.entriesBuff.length > 0) this.flushRow(true); 17944 17945 if (this.isSpinnerActive()) { 17946 this.stopLoadingSpinnerAnimation(); 17947 } 17948 17949 /* Stop, if there is, the timeout to start the analyzeImages. 17950 This is because an image can be set loaded, and the timeout can be set, 17951 but this image can be analyzed yet. 17952 */ 17953 this.stopImgAnalyzerStarter(); 17954 17955 //On complete callback 17956 this.$gallery.trigger(isForResize ? 'jg.resize' : 'jg.complete'); 17957 this.$gallery.height(this.galleryHeightToSet); 17958 }; 17959 17960 /** 17961 * Stops any ImgAnalyzer starter (that has an assigned timeout) 17962 */ 17963 JustifiedGallery.prototype.stopImgAnalyzerStarter = function () { 17964 this.yield.flushed = 0; 17965 if (this.imgAnalyzerTimeout !== null) clearTimeout(this.imgAnalyzerTimeout); 17966 }; 17967 17968 /** 17969 * Starts the image analyzer. It is not immediately called to let the browser to update the view 17970 * 17971 * @param isForResize specifies if the image analyzer must be called for resizing or not 17972 */ 17973 JustifiedGallery.prototype.startImgAnalyzer = function (isForResize) { 17974 var that = this; 17975 this.stopImgAnalyzerStarter(); 17976 this.imgAnalyzerTimeout = setTimeout(function () { 17977 that.analyzeImages(isForResize); 17978 }, 0.001); // we can't start it immediately due to a IE different behaviour 17979 }; 17980 17981 /** 17982 * Checks if the image is loaded or not using another image object. We cannot use the 'complete' image property, 17983 * because some browsers, with a 404 set complete = true. 17984 * 17985 * @param imageSrc the image src to load 17986 * @param onLoad callback that is called when the image has been loaded
vendor: 13,320 bytes, lines 17987-18337
17987 * @param onError callback that is called in case of an error 17988 */ 17989 JustifiedGallery.prototype.onImageEvent = function (imageSrc, onLoad, onError) { 17990 if (!onLoad && !onError) return; 17991 17992 var memImage = new Image(); 17993 var $memImage = $(memImage); 17994 if (onLoad) { 17995 $memImage.one('load', function () { 17996 $memImage.off('load error'); 17997 onLoad(memImage); 17998 }); 17999 } 18000 if (onError) { 18001 $memImage.one('error', function() { 18002 $memImage.off('load error'); 18003 onError(memImage); 18004 }); 18005 } 18006 memImage.src = imageSrc; 18007 }; 18008 18009 /** 18010 * Init of Justified Gallery controlled 18011 * It analyzes all the entries starting theirs loading and calling the image analyzer (that works with loaded images) 18012 */ 18013 JustifiedGallery.prototype.init = function () { 18014 var imagesToLoad = false, skippedImages = false, that = this; 18015 $.each(this.entries, function (index, entry) { 18016 var $entry = $(entry); 18017 var $image = that.imgFromEntry($entry); 18018 18019 $entry.addClass('jg-entry'); 18020 18021 if ($entry.data('jg.loaded') !== true && $entry.data('jg.loaded') !== 'skipped') { 18022 18023 // Link Rel global overwrite 18024 if (that.settings.rel !== null) $entry.attr('rel', that.settings.rel); 18025 18026 // Link Target global overwrite 18027 if (that.settings.target !== null) $entry.attr('target', that.settings.target); 18028 18029 if ($image !== null) { 18030 18031 // Image src 18032 var imageSrc = that.extractImgSrcFromImage($image); 18033 $image.attr('src', imageSrc); 18034 18035 /* If we have the height and the width, we don't wait that the image is loaded, but we start directly 18036 * with the justification */ 18037 if (that.settings.waitThumbnailsLoad === false) { 18038 var width = parseFloat($image.attr('width')); 18039 var height = parseFloat($image.attr('height')); 18040 if (!isNaN(width) && !isNaN(height)) { 18041 $entry.data('jg.width', width); 18042 $entry.data('jg.height', height); 18043 $entry.data('jg.loaded', 'skipped'); 18044 skippedImages = true; 18045 that.startImgAnalyzer(false); 18046 return true; // continue 18047 } 18048 } 18049 18050 $entry.data('jg.loaded', false); 18051 imagesToLoad = true; 18052 18053 // Spinner start 18054 if (!that.isSpinnerActive()) that.startLoadingSpinnerAnimation(); 18055 18056 that.onImageEvent(imageSrc, function (loadImg) { // image loaded 18057 $entry.data('jg.width', loadImg.width); 18058 $entry.data('jg.height', loadImg.height); 18059 $entry.data('jg.loaded', true); 18060 that.startImgAnalyzer(false); 18061 }, function () { // image load error 18062 $entry.data('jg.loaded', 'error'); 18063 that.startImgAnalyzer(false); 18064 }); 18065 18066 } else { 18067 $entry.data('jg.loaded', true); 18068 $entry.data('jg.width', $entry.width() | parseFloat($entry.css('width')) | 1); 18069 $entry.data('jg.height', $entry.height() | parseFloat($entry.css('height')) | 1); 18070 } 18071 18072 } 18073 18074 }); 18075 18076 if (!imagesToLoad && !skippedImages) this.startImgAnalyzer(false); 18077 this.checkWidth(); 18078 }; 18079 18080 /** 18081 * Checks that it is a valid number. If a string is passed it is converted to a number 18082 * 18083 * @param settingContainer the object that contains the setting (to allow the conversion) 18084 * @param settingName the setting name 18085 */ 18086 JustifiedGallery.prototype.checkOrConvertNumber = function (settingContainer, settingName) { 18087 if ($.type(settingContainer[settingName]) === 'string') { 18088 settingContainer[settingName] = parseFloat(settingContainer[settingName]); 18089 } 18090 18091 if ($.type(settingContainer[settingName]) === 'number') { 18092 if (isNaN(settingContainer[settingName])) throw 'invalid number for ' + settingName; 18093 } else { 18094 throw settingName + ' must be a number'; 18095 } 18096 }; 18097 18098 /** 18099 * Checks the sizeRangeSuffixes and, if necessary, converts 18100 * its keys from string (e.g. old settings with 'lt100') to int. 18101 */ 18102 JustifiedGallery.prototype.checkSizeRangesSuffixes = function () { 18103 if ($.type(this.settings.sizeRangeSuffixes) !== 'object') { 18104 throw 'sizeRangeSuffixes must be defined and must be an object'; 18105 } 18106 18107 var suffixRanges = []; 18108 for (var rangeIdx in this.settings.sizeRangeSuffixes) { 18109 if (this.settings.sizeRangeSuffixes.hasOwnProperty(rangeIdx)) suffixRanges.push(rangeIdx); 18110 } 18111 18112 var newSizeRngSuffixes = {0: ''}; 18113 for (var i = 0; i < suffixRanges.length; i++) { 18114 if ($.type(suffixRanges[i]) === 'string') { 18115 try { 18116 var numIdx = parseInt(suffixRanges[i].replace(/^[a-z]+/, ''), 10); 18117 newSizeRngSuffixes[numIdx] = this.settings.sizeRangeSuffixes[suffixRanges[i]]; 18118 } catch (e) { 18119 throw 'sizeRangeSuffixes keys must contains correct numbers (' + e + ')'; 18120 } 18121 } else { 18122 newSizeRngSuffixes[suffixRanges[i]] = this.settings.sizeRangeSuffixes[suffixRanges[i]]; 18123 } 18124 } 18125 18126 this.settings.sizeRangeSuffixes = newSizeRngSuffixes; 18127 }; 18128 18129 /** 18130 * check and convert the maxRowHeight setting 18131 */ 18132 JustifiedGallery.prototype.retrieveMaxRowHeight = function () { 18133 var newMaxRowHeight = { }; 18134 18135 if ($.type(this.settings.maxRowHeight) === 'string') { 18136 if (this.settings.maxRowHeight.match(/^[0-9]+%$/)) { 18137 newMaxRowHeight.value = parseFloat(this.settings.maxRowHeight.match(/^([0-9]+)%$/)[1]) / 100; 18138 newMaxRowHeight.isPercentage = false; 18139 } else { 18140 newMaxRowHeight.value = parseFloat(this.settings.maxRowHeight); 18141 newMaxRowHeight.isPercentage = true; 18142 } 18143 } else if ($.type(this.settings.maxRowHeight) === 'number') { 18144 newMaxRowHeight.value = this.settings.maxRowHeight; 18145 newMaxRowHeight.isPercentage = false; 18146 } else if (this.settings.maxRowHeight === false || 18147 this.settings.maxRowHeight === null || 18148 typeof this.settings.maxRowHeight == 'undefined') { 18149 return null; 18150 } else { 18151 throw 'maxRowHeight must be a number or a percentage'; 18152 } 18153 18154 // check if the converted value is not a number 18155 if (isNaN(newMaxRowHeight.value)) throw 'invalid number for maxRowHeight'; 18156 18157 // check values 18158 if (newMaxRowHeight.isPercentage) { 18159 if (newMaxRowHeight.value < 100) newMaxRowHeight.value = 100; 18160 } 18161 18162 return newMaxRowHeight; 18163 }; 18164 18165 /** 18166 * Checks the settings 18167 */ 18168 JustifiedGallery.prototype.checkSettings = function () { 18169 this.checkSizeRangesSuffixes(); 18170 18171 this.checkOrConvertNumber(this.settings, 'rowHeight'); 18172 this.checkOrConvertNumber(this.settings, 'margins'); 18173 this.checkOrConvertNumber(this.settings, 'border'); 18174 18175 var lastRowModes = [ 18176 'justify', 18177 'nojustify', 18178 'left', 18179 'center', 18180 'right', 18181 'hide' 18182 ]; 18183 if (lastRowModes.indexOf(this.settings.lastRow) === -1) { 18184 throw 'lastRow must be one of: ' + lastRowModes.join(', '); 18185 } 18186 18187 this.checkOrConvertNumber(this.settings, 'justifyThreshold'); 18188 if (this.settings.justifyThreshold < 0 || this.settings.justifyThreshold > 1) { 18189 throw 'justifyThreshold must be in the interval [0,1]'; 18190 } 18191 if ($.type(this.settings.cssAnimation) !== 'boolean') { 18192 throw 'cssAnimation must be a boolean'; 18193 } 18194 18195 if ($.type(this.settings.captions) !== 'boolean') throw 'captions must be a boolean'; 18196 this.checkOrConvertNumber(this.settings.captionSettings, 'animationDuration'); 18197 18198 this.checkOrConvertNumber(this.settings.captionSettings, 'visibleOpacity'); 18199 if (this.settings.captionSettings.visibleOpacity < 0 || 18200 this.settings.captionSettings.visibleOpacity > 1) { 18201 throw 'captionSettings.visibleOpacity must be in the interval [0, 1]'; 18202 } 18203 18204 this.checkOrConvertNumber(this.settings.captionSettings, 'nonVisibleOpacity'); 18205 if (this.settings.captionSettings.nonVisibleOpacity < 0 || 18206 this.settings.captionSettings.nonVisibleOpacity > 1) { 18207 throw 'captionSettings.nonVisibleOpacity must be in the interval [0, 1]'; 18208 } 18209 18210 this.checkOrConvertNumber(this.settings, 'imagesAnimationDuration'); 18211 this.checkOrConvertNumber(this.settings, 'refreshTime'); 18212 this.checkOrConvertNumber(this.settings, 'refreshSensitivity'); 18213 if ($.type(this.settings.randomize) !== 'boolean') throw 'randomize must be a boolean'; 18214 if ($.type(this.settings.selector) !== 'string') throw 'selector must be a string'; 18215 18216 if (this.settings.sort !== false && !$.isFunction(this.settings.sort)) { 18217 throw 'sort must be false or a comparison function'; 18218 } 18219 18220 if (this.settings.filter !== false && !$.isFunction(this.settings.filter) && 18221 $.type(this.settings.filter) !== 'string') { 18222 throw 'filter must be false, a string or a filter function'; 18223 } 18224 }; 18225 18226 /** 18227 * It brings all the indexes from the sizeRangeSuffixes and it orders them. They are then sorted and returned. 18228 * @returns {Array} sorted suffix ranges 18229 */ 18230 JustifiedGallery.prototype.retrieveSuffixRanges = function () { 18231 var suffixRanges = []; 18232 for (var rangeIdx in this.settings.sizeRangeSuffixes) { 18233 if (this.settings.sizeRangeSuffixes.hasOwnProperty(rangeIdx)) suffixRanges.push(parseInt(rangeIdx, 10)); 18234 } 18235 suffixRanges.sort(function (a, b) { return a > b ? 1 : a < b ? -1 : 0; }); 18236 return suffixRanges; 18237 }; 18238 18239 /** 18240 * Update the existing settings only changing some of them 18241 * 18242 * @param newSettings the new settings (or a subgroup of them) 18243 */ 18244 JustifiedGallery.prototype.updateSettings = function (newSettings) { 18245 // In this case Justified Gallery has been called again changing only some options 18246 this.settings = $.extend({}, this.settings, newSettings); 18247 this.checkSettings(); 18248 18249 // As reported in the settings: negative value = same as margins, 0 = disabled 18250 this.border = this.settings.border >= 0 ? this.settings.border : this.settings.margins; 18251 18252 this.maxRowHeight = this.retrieveMaxRowHeight(); 18253 this.suffixRanges = this.retrieveSuffixRanges(); 18254 }; 18255 18256 /** 18257 * Justified Gallery plugin for jQuery 18258 * 18259 * Events 18260 * - jg.complete : called when all the gallery has been created 18261 * - jg.resize : called when the gallery has been resized 18262 * - jg.rowflush : when a new row appears 18263 * 18264 * @param arg the action (or the settings) passed when the plugin is called 18265 * @returns {*} the object itself 18266 */ 18267 $.fn.justifiedGallery = function (arg) { 18268 return this.each(function (index, gallery) { 18269 18270 var $gallery = $(gallery); 18271 $gallery.addClass('justified-gallery'); 18272 18273 var controller = $gallery.data('jg.controller'); 18274 if (typeof controller === 'undefined') { 18275 // Create controller and assign it to the object data 18276 if (typeof arg !== 'undefined' && arg !== null && $.type(arg) !== 'object') { 18277 if (arg === 'destroy') return; // Just a call to an unexisting object 18278 throw 'The argument must be an object'; 18279 } 18280 controller = new JustifiedGallery($gallery, $.extend({}, $.fn.justifiedGallery.defaults, arg)); 18281 $gallery.data('jg.controller', controller); 18282 } else if (arg === 'norewind') { 18283 // In this case we don't rewind: we analyze only the latest images (e.g. to complete the last unfinished row 18284 // ... left to be more readable 18285 } else if (arg === 'destroy') { 18286 controller.destroy(); 18287 return; 18288 } else { 18289 // In this case Justified Gallery has been called again changing only some options 18290 controller.updateSettings(arg); 18291 controller.rewind(); 18292 } 18293 18294 // Update the entries list 18295 if (!controller.updateEntries(arg === 'norewind')) return; 18296 18297 // Init justified gallery 18298 controller.init(); 18299 18300 }); 18301 }; 18302 18303 // Default options 18304 $.fn.justifiedGallery.defaults = { 18305 sizeRangeSuffixes: { }, /* e.g. Flickr configuration 18306 { 18307 100: '_t', // used when longest is less than 100px 18308 240: '_m', // used when longest is between 101px and 240px 18309 320: '_n', // ... 18310 500: '', 18311 640: '_z', 18312 1024: '_b' // used as else case because it is the last 18313 } 18314 */ 18315 thumbnailPath: undefined, /* If defined, sizeRangeSuffixes is not used, and this function is used to determine the 18316 path relative to a specific thumbnail size. The function should accept respectively three arguments: 18317 current path, width and height */ 18318 rowHeight: 120, 18319 maxRowHeight: false, // false or negative value to deactivate. Positive number to express the value in pixels, 18320 // A string '[0-9]+%' to express in percentage (e.g. 300% means that the row height 18321 // can't exceed 3 * rowHeight) 18322 margins: 1, 18323 border: -1, // negative value = same as margins, 0 = disabled, any other value to set the border 18324 18325 lastRow: 'nojustify', // … which is the same as 'left', or can be 'justify', 'center', 'right' or 'hide' 18326 18327 justifyThreshold: 0.90, /* if row width / available space > 0.90 it will be always justified 18328 * (i.e. lastRow setting is not considered) */ 18329 waitThumbnailsLoad: true, 18330 captions: true, 18331 cssAnimation: true, 18332 imagesAnimationDuration: 500, // ignored with css animations 18333 captionSettings: { // ignored with css animations 18334 animationDuration: 500, 18335 visibleOpacity: 0.7, 18336 nonVisibleOpacity: 0.0 18337 },
vendor: 5,759 bytes, lines 18338-18480
18338 rel: null, // rewrite the rel of each analyzed links 18339 target: null, // rewrite the target of all links 18340 extension: /\.[^.\\/]+$/, // regexp to capture the extension of an image 18341 refreshTime: 200, // time interval (in ms) to check if the page changes its width 18342 refreshSensitivity: 0, // change in width allowed (in px) without re-building the gallery 18343 randomize: false, 18344 sort: false, /* 18345 - false: to do not sort 18346 - function: to sort them using the function as comparator (see Array.prototype.sort()) 18347 */ 18348 filter: false, /* 18349 - false, null or undefined: for a disabled filter 18350 - a string: an entry is kept if entry.is(filter string) returns true 18351 see jQuery's .is() function for further information 18352 - a function: invoked with arguments (entry, index, array). Return true to keep the entry, false otherwise. 18353 It follows the specifications of the Array.prototype.filter() function of JavaScript. 18354 */ 18355 selector: 'a, div:not(.spinner)' // The selector that is used to know what are the entries of the gallery 18356 }; 18357 18358}(jQuery)); 18359/*! 18360* Customized version of iScroll.js 0.0.1 18361* It fixes bugs affecting its integration with fullpage.js 18362*/ 18363/*! iScroll v5.2.0 ~ (c) 2008-2016 Matteo Spinelli ~ http://cubiq.org/license */ 18364(function (window, document, Math) { 18365var rAF = window.requestAnimationFrame || 18366 window.webkitRequestAnimationFrame || 18367 window.mozRequestAnimationFrame || 18368 window.oRequestAnimationFrame || 18369 window.msRequestAnimationFrame || 18370 function (callback) { window.setTimeout(callback, 1000 / 60); }; 18371 18372var utils = (function () { 18373 var me = {}; 18374 18375 var _elementStyle = document.createElement('div').style; 18376 var _vendor = (function () { 18377 var vendors = ['t', 'webkitT', 'MozT', 'msT', 'OT'], 18378 transform, 18379 i = 0, 18380 l = vendors.length; 18381 18382 for ( ; i < l; i++ ) { 18383 transform = vendors[i] + 'ransform'; 18384 if ( transform in _elementStyle ) return vendors[i].substr(0, vendors[i].length-1); 18385 } 18386 18387 return false; 18388 })(); 18389 18390 function _prefixStyle (style) { 18391 if ( _vendor === false ) return false; 18392 if ( _vendor === '' ) return style; 18393 return _vendor + style.charAt(0).toUpperCase() + style.substr(1); 18394 } 18395 18396 me.getTime = Date.now || function getTime () { return new Date().getTime(); }; 18397 18398 me.extend = function (target, obj) { 18399 for ( var i in obj ) { 18400 target[i] = obj[i]; 18401 } 18402 }; 18403 18404 me.addEvent = function (el, type, fn, capture) { 18405 el.addEventListener(type, fn, !!capture); 18406 }; 18407 18408 me.removeEvent = function (el, type, fn, capture) { 18409 el.removeEventListener(type, fn, !!capture); 18410 }; 18411 18412 me.prefixPointerEvent = function (pointerEvent) { 18413 return window.MSPointerEvent ? 18414 'MSPointer' + pointerEvent.charAt(7).toUpperCase() + pointerEvent.substr(8): 18415 pointerEvent; 18416 }; 18417 18418 me.momentum = function (current, start, time, lowerMargin, wrapperSize, deceleration) { 18419 var distance = current - start, 18420 speed = Math.abs(distance) / time, 18421 destination, 18422 duration; 18423 18424 deceleration = deceleration === undefined ? 0.0006 : deceleration; 18425 18426 destination = current + ( speed * speed ) / ( 2 * deceleration ) * ( distance < 0 ? -1 : 1 ); 18427 duration = speed / deceleration; 18428 18429 if ( destination < lowerMargin ) { 18430 destination = wrapperSize ? lowerMargin - ( wrapperSize / 2.5 * ( speed / 8 ) ) : lowerMargin; 18431 distance = Math.abs(destination - current); 18432 duration = distance / speed; 18433 } else if ( destination > 0 ) { 18434 destination = wrapperSize ? wrapperSize / 2.5 * ( speed / 8 ) : 0; 18435 distance = Math.abs(current) + destination; 18436 duration = distance / speed; 18437 } 18438 18439 return { 18440 destination: Math.round(destination), 18441 duration: duration 18442 }; 18443 }; 18444 18445 var _transform = _prefixStyle('transform'); 18446 18447 me.extend(me, { 18448 hasTransform: _transform !== false, 18449 hasPerspective: _prefixStyle('perspective') in _elementStyle, 18450 hasTouch: 'ontouchstart' in window, 18451 hasPointer: !!(window.PointerEvent || window.MSPointerEvent), // IE10 is prefixed 18452 hasTransition: _prefixStyle('transition') in _elementStyle 18453 }); 18454 18455 /* 18456 This should find all Android browsers lower than build 535.19 (both stock browser and webview) 18457 - galaxy S2 is ok 18458 - 2.3.6 : `AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1` 18459 - 4.0.4 : `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30` 18460 - galaxy S3 is badAndroid (stock brower, webview) 18461 `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30` 18462 - galaxy S4 is badAndroid (stock brower, webview) 18463 `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30` 18464 - galaxy S5 is OK 18465 `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)` 18466 - galaxy S6 is OK 18467 `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)` 18468 */ 18469 me.isBadAndroid = (function() { 18470 var appVersion = window.navigator.appVersion; 18471 // Android browser is not a chrome browser. 18472 if (/Android/.test(appVersion) && !(/Chrome\/\d/.test(appVersion))) { 18473 var safariVersion = appVersion.match(/Safari\/(\d+.\d)/); 18474 if(safariVersion && typeof safariVersion === "object" && safariVersion.length >= 2) { 18475 return parseFloat(safariVersion[1]) < 535.19; 18476 } else { 18477 return true; 18478 } 18479 } else { 18480 return false;
vendor: 5,536 bytes, lines 18481-18673
18481 } 18482 })(); 18483 18484 me.extend(me.style = {}, { 18485 transform: _transform, 18486 transitionTimingFunction: _prefixStyle('transitionTimingFunction'), 18487 transitionDuration: _prefixStyle('transitionDuration'), 18488 transitionDelay: _prefixStyle('transitionDelay'), 18489 transformOrigin: _prefixStyle('transformOrigin') 18490 }); 18491 18492 me.hasClass = function (e, c) { 18493 var re = new RegExp("(^|\\s)" + c + "(\\s|$)"); 18494 return re.test(e.className); 18495 }; 18496 18497 me.addClass = function (e, c) { 18498 if ( me.hasClass(e, c) ) { 18499 return; 18500 } 18501 18502 var newclass = e.className.split(' '); 18503 newclass.push(c); 18504 e.className = newclass.join(' '); 18505 }; 18506 18507 me.removeClass = function (e, c) { 18508 if ( !me.hasClass(e, c) ) { 18509 return; 18510 } 18511 18512 var re = new RegExp("(^|\\s)" + c + "(\\s|$)", 'g'); 18513 e.className = e.className.replace(re, ' '); 18514 }; 18515 18516 me.offset = function (el) { 18517 var left = -el.offsetLeft, 18518 top = -el.offsetTop; 18519 18520 // jshint -W084 18521 while (el = el.offsetParent) { 18522 left -= el.offsetLeft; 18523 top -= el.offsetTop; 18524 } 18525 // jshint +W084 18526 18527 return { 18528 left: left, 18529 top: top 18530 }; 18531 }; 18532 18533 me.preventDefaultException = function (el, exceptions) { 18534 for ( var i in exceptions ) { 18535 if ( exceptions[i].test(el[i]) ) { 18536 return true; 18537 } 18538 } 18539 18540 return false; 18541 }; 18542 18543 me.extend(me.eventType = {}, { 18544 touchstart: 1, 18545 touchmove: 1, 18546 touchend: 1, 18547 18548 mousedown: 2, 18549 mousemove: 2, 18550 mouseup: 2, 18551 18552 pointerdown: 3, 18553 pointermove: 3, 18554 pointerup: 3, 18555 18556 MSPointerDown: 3, 18557 MSPointerMove: 3, 18558 MSPointerUp: 3 18559 }); 18560 18561 me.extend(me.ease = {}, { 18562 quadratic: { 18563 style: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)', 18564 fn: function (k) { 18565 return k * ( 2 - k ); 18566 } 18567 }, 18568 circular: { 18569 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) 18570 fn: function (k) { 18571 return Math.sqrt( 1 - ( --k * k ) ); 18572 } 18573 }, 18574 back: { 18575 style: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)', 18576 fn: function (k) { 18577 var b = 4; 18578 return ( k = k - 1 ) * k * ( ( b + 1 ) * k + b ) + 1; 18579 } 18580 }, 18581 bounce: { 18582 style: '', 18583 fn: function (k) { 18584 if ( ( k /= 1 ) < ( 1 / 2.75 ) ) { 18585 return 7.5625 * k * k; 18586 } else if ( k < ( 2 / 2.75 ) ) { 18587 return 7.5625 * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75; 18588 } else if ( k < ( 2.5 / 2.75 ) ) { 18589 return 7.5625 * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375; 18590 } else { 18591 return 7.5625 * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375; 18592 } 18593 } 18594 }, 18595 elastic: { 18596 style: '', 18597 fn: function (k) { 18598 var f = 0.22, 18599 e = 0.4; 18600 18601 if ( k === 0 ) { return 0; } 18602 if ( k == 1 ) { return 1; } 18603 18604 return ( e * Math.pow( 2, - 10 * k ) * Math.sin( ( k - f / 4 ) * ( 2 * Math.PI ) / f ) + 1 ); 18605 } 18606 } 18607 }); 18608 18609 me.tap = function (e, eventName) { 18610 var ev = document.createEvent('Event'); 18611 ev.initEvent(eventName, true, true); 18612 ev.pageX = e.pageX; 18613 ev.pageY = e.pageY; 18614 e.target.dispatchEvent(ev); 18615 }; 18616 18617 me.click = function (e) { 18618 var target = e.target, 18619 ev; 18620 18621 if ( !(/(SELECT|INPUT|TEXTAREA)/i).test(target.tagName) ) { 18622 // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/initMouseEvent 18623 // initMouseEvent is deprecated. 18624 ev = document.createEvent(window.MouseEvent ? 'MouseEvents' : 'Event'); 18625 ev.initEvent('click', true, true); 18626 ev.view = e.view || window; 18627 ev.detail = 1; 18628 ev.screenX = target.screenX || 0; 18629 ev.screenY = target.screenY || 0; 18630 ev.clientX = target.clientX || 0; 18631 ev.clientY = target.clientY || 0; 18632 ev.ctrlKey = !!e.ctrlKey; 18633 ev.altKey = !!e.altKey; 18634 ev.shiftKey = !!e.shiftKey; 18635 ev.metaKey = !!e.metaKey; 18636 ev.button = 0; 18637 ev.relatedTarget = null; 18638 ev._constructed = true; 18639 target.dispatchEvent(ev); 18640 } 18641 }; 18642 18643 return me; 18644})(); 18645function IScroll (el, options) { 18646 this.wrapper = typeof el == 'string' ? document.querySelector(el) : el; 18647 this.scroller = this.wrapper.children[0]; 18648 this.scrollerStyle = this.scroller.style; // cache style for better performance 18649 18650 this.options = { 18651 18652 resizeScrollbars: true, 18653 18654 mouseWheelSpeed: 20, 18655 18656 snapThreshold: 0.334, 18657 18658// INSERT POINT: OPTIONS 18659 disablePointer : !utils.hasPointer, 18660 disableTouch : utils.hasPointer || !utils.hasTouch, 18661 disableMouse : utils.hasPointer || utils.hasTouch, 18662 startX: 0, 18663 startY: 0, 18664 scrollY: true, 18665 directionLockThreshold: 5, 18666 momentum: true, 18667 18668 bounce: true, 18669 bounceTime: 600, 18670 bounceEasing: '', 18671 18672 preventDefault: true, 18673 preventDefaultException: { tagName: /^(INPUT|TEXTAREA|BUTTON|
vendor: 4,420 bytes, lines 18673-18817
18673SELECT|LABEL)$/ }, 18674 18675 HWCompositing: true, 18676 useTransition: true, 18677 useTransform: true, 18678 bindToWrapper: typeof window.onmousedown === "undefined" 18679 }; 18680 18681 for ( var i in options ) { 18682 this.options[i] = options[i]; 18683 } 18684 18685 // Normalize options 18686 this.translateZ = this.options.HWCompositing && utils.hasPerspective ? ' translateZ(0)' : ''; 18687 18688 this.options.useTransition = utils.hasTransition && this.options.useTransition; 18689 this.options.useTransform = utils.hasTransform && this.options.useTransform; 18690 18691 this.options.eventPassthrough = this.options.eventPassthrough === true ? 'vertical' : this.options.eventPassthrough; 18692 this.options.preventDefault = !this.options.eventPassthrough && this.options.preventDefault; 18693 18694 // If you want eventPassthrough I have to lock one of the axes 18695 this.options.scrollY = this.options.eventPassthrough == 'vertical' ? false : this.options.scrollY; 18696 this.options.scrollX = this.options.eventPassthrough == 'horizontal' ? false : this.options.scrollX; 18697 18698 // With eventPassthrough we also need lockDirection mechanism 18699 this.options.freeScroll = this.options.freeScroll && !this.options.eventPassthrough; 18700 this.options.directionLockThreshold = this.options.eventPassthrough ? 0 : this.options.directionLockThreshold; 18701 18702 this.options.bounceEasing = typeof this.options.bounceEasing == 'string' ? utils.ease[this.options.bounceEasing] || utils.ease.circular : this.options.bounceEasing; 18703 18704 this.options.resizePolling = this.options.resizePolling === undefined ? 60 : this.options.resizePolling; 18705 18706 if ( this.options.tap === true ) { 18707 this.options.tap = 'tap'; 18708 } 18709 18710 // https://github.com/cubiq/iscroll/issues/1029 18711 if (!this.options.useTransition && !this.options.useTransform) { 18712 if(!(/relative|absolute/i).test(this.scrollerStyle.position)) { 18713 this.scrollerStyle.position = "relative"; 18714 } 18715 } 18716 18717 if ( this.options.shrinkScrollbars == 'scale' ) { 18718 this.options.useTransition = false; 18719 } 18720 18721 this.options.invertWheelDirection = this.options.invertWheelDirection ? -1 : 1; 18722 18723// INSERT POINT: NORMALIZATION 18724 18725 // Some defaults 18726 this.x = 0; 18727 this.y = 0; 18728 this.directionX = 0; 18729 this.directionY = 0; 18730 this._events = {}; 18731 18732// INSERT POINT: DEFAULTS 18733 18734 this._init(); 18735 this.refresh(); 18736 18737 this.scrollTo(this.options.startX, this.options.startY); 18738 this.enable(); 18739} 18740 18741IScroll.prototype = { 18742 version: '5.2.0', 18743 18744 _init: function () { 18745 this._initEvents(); 18746 18747 if ( this.options.scrollbars || this.options.indicators ) { 18748 this._initIndicators(); 18749 } 18750 18751 if ( this.options.mouseWheel ) { 18752 this._initWheel(); 18753 } 18754 18755 if ( this.options.snap ) { 18756 this._initSnap(); 18757 } 18758 18759 if ( this.options.keyBindings ) { 18760 this._initKeys(); 18761 } 18762 18763// INSERT POINT: _init 18764 18765 }, 18766 18767 destroy: function () { 18768 this._initEvents(true); 18769 clearTimeout(this.resizeTimeout); 18770 this.resizeTimeout = null; 18771 this._execEvent('destroy'); 18772 }, 18773 18774 _transitionEnd: function (e) { 18775 if ( e.target != this.scroller || !this.isInTransition ) { 18776 return; 18777 } 18778 18779 this._transitionTime(); 18780 if ( !this.resetPosition(this.options.bounceTime) ) { 18781 this.isInTransition = false; 18782 this._execEvent('scrollEnd'); 18783 } 18784 }, 18785 18786 _start: function (e) { 18787 // React to left mouse button only 18788 if ( utils.eventType[e.type] != 1 ) { 18789 // for button property 18790 // http://unixpapa.com/js/mouse.html 18791 var button; 18792 if (!e.which) { 18793 /* IE case */ 18794 button = (e.button < 2) ? 0 : 18795 ((e.button == 4) ? 1 : 2); 18796 } else { 18797 /* All others */ 18798 button = e.button; 18799 } 18800 if ( button !== 0 ) { 18801 return; 18802 } 18803 } 18804 18805 if ( !this.enabled || (this.initiated && utils.eventType[e.type] !== this.initiated) ) { 18806 return; 18807 } 18808 18809 if ( this.options.preventDefault && !utils.isBadAndroid && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) { 18810 e.preventDefault(); 18811 } 18812 18813 var point = e.touches ? e.touches[0] : e, 18814 pos; 18815 18816 this.initiated = utils.eventType[e.type]; 18817 this.moved = false;
vendor: 5,928 bytes, lines 18818-18996
18818 this.distX = 0; 18819 this.distY = 0; 18820 this.directionX = 0; 18821 this.directionY = 0; 18822 this.directionLocked = 0; 18823 18824 this.startTime = utils.getTime(); 18825 18826 if ( this.options.useTransition && this.isInTransition ) { 18827 this._transitionTime(); 18828 this.isInTransition = false; 18829 pos = this.getComputedPosition(); 18830 this._translate(Math.round(pos.x), Math.round(pos.y)); 18831 this._execEvent('scrollEnd'); 18832 } else if ( !this.options.useTransition && this.isAnimating ) { 18833 this.isAnimating = false; 18834 this._execEvent('scrollEnd'); 18835 } 18836 18837 this.startX = this.x; 18838 this.startY = this.y; 18839 this.absStartX = this.x; 18840 this.absStartY = this.y; 18841 this.pointX = point.pageX; 18842 this.pointY = point.pageY; 18843 18844 this._execEvent('beforeScrollStart'); 18845 }, 18846 18847 _move: function (e) { 18848 if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) { 18849 return; 18850 } 18851 18852 if ( this.options.preventDefault ) { // increases performance on Android? TODO: check! 18853 e.preventDefault(); 18854 } 18855 18856 var point = e.touches ? e.touches[0] : e, 18857 deltaX = point.pageX - this.pointX, 18858 deltaY = point.pageY - this.pointY, 18859 timestamp = utils.getTime(), 18860 newX, newY, 18861 absDistX, absDistY; 18862 18863 this.pointX = point.pageX; 18864 this.pointY = point.pageY; 18865 18866 this.distX += deltaX; 18867 this.distY += deltaY; 18868 absDistX = Math.abs(this.distX); 18869 absDistY = Math.abs(this.distY); 18870 18871 // We need to move at least 10 pixels for the scrolling to initiate 18872 if ( timestamp - this.endTime > 300 && (absDistX < 10 && absDistY < 10) ) { 18873 return; 18874 } 18875 18876 // If you are scrolling in one direction lock the other 18877 if ( !this.directionLocked && !this.options.freeScroll ) { 18878 if ( absDistX > absDistY + this.options.directionLockThreshold ) { 18879 this.directionLocked = 'h'; // lock horizontally 18880 } else if ( absDistY >= absDistX + this.options.directionLockThreshold ) { 18881 this.directionLocked = 'v'; // lock vertically 18882 } else { 18883 this.directionLocked = 'n'; // no lock 18884 } 18885 } 18886 18887 if ( this.directionLocked == 'h' ) { 18888 if ( this.options.eventPassthrough == 'vertical' ) { 18889 e.preventDefault(); 18890 } else if ( this.options.eventPassthrough == 'horizontal' ) { 18891 this.initiated = false; 18892 return; 18893 } 18894 18895 deltaY = 0; 18896 } else if ( this.directionLocked == 'v' ) { 18897 if ( this.options.eventPassthrough == 'horizontal' ) { 18898 e.preventDefault(); 18899 } else if ( this.options.eventPassthrough == 'vertical' ) { 18900 this.initiated = false; 18901 return; 18902 } 18903 18904 deltaX = 0; 18905 } 18906 18907 deltaX = this.hasHorizontalScroll ? deltaX : 0; 18908 deltaY = this.hasVerticalScroll ? deltaY : 0; 18909 18910 newX = this.x + deltaX; 18911 newY = this.y + deltaY; 18912 18913 // Slow down if outside of the boundaries 18914 if ( newX > 0 || newX < this.maxScrollX ) { 18915 newX = this.options.bounce ? this.x + deltaX / 3 : newX > 0 ? 0 : this.maxScrollX; 18916 } 18917 if ( newY > 0 || newY < this.maxScrollY ) { 18918 newY = this.options.bounce ? this.y + deltaY / 3 : newY > 0 ? 0 : this.maxScrollY; 18919 } 18920 18921 this.directionX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0; 18922 this.directionY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0; 18923 18924 if ( !this.moved ) { 18925 this._execEvent('scrollStart'); 18926 } 18927 18928 this.moved = true; 18929 18930 this._translate(newX, newY); 18931 18932/* REPLACE START: _move */ 18933 18934 if ( timestamp - this.startTime > 300 ) { 18935 this.startTime = timestamp; 18936 this.startX = this.x; 18937 this.startY = this.y; 18938 } 18939 18940/* REPLACE END: _move */ 18941 18942 }, 18943 18944 _end: function (e) { 18945 if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) { 18946 return; 18947 } 18948 18949 if ( this.options.preventDefault && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) { 18950 e.preventDefault(); 18951 } 18952 18953 var point = e.changedTouches ? e.changedTouches[0] : e, 18954 momentumX, 18955 momentumY, 18956 duration = utils.getTime() - this.startTime, 18957 newX = Math.round(this.x), 18958 newY = Math.round(this.y), 18959 distanceX = Math.abs(newX - this.startX), 18960 distanceY = Math.abs(newY - this.startY), 18961 time = 0, 18962 easing = ''; 18963 18964 this.isInTransition = 0; 18965 this.initiated = 0; 18966 this.endTime = utils.getTime(); 18967 18968 // reset if we are outside of the boundaries 18969 if ( this.resetPosition(this.options.bounceTime) ) { 18970 return; 18971 } 18972 18973 this.scrollTo(newX, newY); // ensures that the last position is rounded 18974 18975 // we scrolled less than 10 pixels 18976 if ( !this.moved ) { 18977 if ( this.options.tap ) { 18978 utils.tap(e, this.options.tap); 18979 } 18980 18981 if ( this.options.click ) { 18982 utils.click(e); 18983 } 18984 18985 this._execEvent('scrollCancel'); 18986 return; 18987 } 18988 18989 if ( this._events.flick && duration < 200 && distanceX < 100 && distanceY < 100 ) { 18990 this._execEvent('flick'); 18991 return; 18992 } 18993 18994 // start momentum animation if needed 18995 if ( this.options.momentum && duration < 300 ) { 18996 momentumX = this.hasHorizontalScroll ? utils.momentum(this.x, this.startX, duration, this.maxScrollX, this.options.bounce ? this.wrapperW
vendor: 7,740 bytes, lines 18996-19269
18996idth : 0, this.options.deceleration) : { destination: newX, duration: 0 }; 18997 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 }; 18998 newX = momentumX.destination; 18999 newY = momentumY.destination; 19000 time = Math.max(momentumX.duration, momentumY.duration); 19001 this.isInTransition = 1; 19002 } 19003 19004 19005 if ( this.options.snap ) { 19006 var snap = this._nearestSnap(newX, newY); 19007 this.currentPage = snap; 19008 time = this.options.snapSpeed || Math.max( 19009 Math.max( 19010 Math.min(Math.abs(newX - snap.x), 1000), 19011 Math.min(Math.abs(newY - snap.y), 1000) 19012 ), 300); 19013 newX = snap.x; 19014 newY = snap.y; 19015 19016 this.directionX = 0; 19017 this.directionY = 0; 19018 easing = this.options.bounceEasing; 19019 } 19020 19021// INSERT POINT: _end 19022 19023 if ( newX != this.x || newY != this.y ) { 19024 // change easing function when scroller goes out of the boundaries 19025 if ( newX > 0 || newX < this.maxScrollX || newY > 0 || newY < this.maxScrollY ) { 19026 easing = utils.ease.quadratic; 19027 } 19028 19029 this.scrollTo(newX, newY, time, easing); 19030 return; 19031 } 19032 19033 this._execEvent('scrollEnd'); 19034 }, 19035 19036 _resize: function () { 19037 var that = this; 19038 19039 clearTimeout(this.resizeTimeout); 19040 19041 this.resizeTimeout = setTimeout(function () { 19042 that.refresh(); 19043 }, this.options.resizePolling); 19044 }, 19045 19046 resetPosition: function (time) { 19047 var x = this.x, 19048 y = this.y; 19049 19050 time = time || 0; 19051 19052 if ( !this.hasHorizontalScroll || this.x > 0 ) { 19053 x = 0; 19054 } else if ( this.x < this.maxScrollX ) { 19055 x = this.maxScrollX; 19056 } 19057 19058 if ( !this.hasVerticalScroll || this.y > 0 ) { 19059 y = 0; 19060 } else if ( this.y < this.maxScrollY ) { 19061 y = this.maxScrollY; 19062 } 19063 19064 if ( x == this.x && y == this.y ) { 19065 return false; 19066 } 19067 19068 this.scrollTo(x, y, time, this.options.bounceEasing); 19069 19070 return true; 19071 }, 19072 19073 disable: function () { 19074 this.enabled = false; 19075 }, 19076 19077 enable: function () { 19078 this.enabled = true; 19079 }, 19080 19081 refresh: function () { 19082 var rf = this.wrapper.offsetHeight; // Force reflow 19083 19084 this.wrapperWidth = this.wrapper.clientWidth; 19085 this.wrapperHeight = this.wrapper.clientHeight; 19086 19087/* REPLACE START: refresh */ 19088 19089 this.scrollerWidth = this.scroller.offsetWidth; 19090 this.scrollerHeight = this.scroller.offsetHeight; 19091 19092 this.maxScrollX = this.wrapperWidth - this.scrollerWidth; 19093 this.maxScrollY = this.wrapperHeight - this.scrollerHeight; 19094 19095/* REPLACE END: refresh */ 19096 19097 this.hasHorizontalScroll = this.options.scrollX && this.maxScrollX < 0; 19098 this.hasVerticalScroll = this.options.scrollY && this.maxScrollY < 0; 19099 19100 if ( !this.hasHorizontalScroll ) { 19101 this.maxScrollX = 0; 19102 this.scrollerWidth = this.wrapperWidth; 19103 } 19104 19105 if ( !this.hasVerticalScroll ) { 19106 this.maxScrollY = 0; 19107 this.scrollerHeight = this.wrapperHeight; 19108 } 19109 19110 this.endTime = 0; 19111 this.directionX = 0; 19112 this.directionY = 0; 19113 19114 this.wrapperOffset = utils.offset(this.wrapper); 19115 19116 this._execEvent('refresh'); 19117 19118 this.resetPosition(); 19119 19120// INSERT POINT: _refresh 19121 19122 }, 19123 19124 on: function (type, fn) { 19125 if ( !this._events[type] ) { 19126 this._events[type] = []; 19127 } 19128 19129 this._events[type].push(fn); 19130 }, 19131 19132 off: function (type, fn) { 19133 if ( !this._events[type] ) { 19134 return; 19135 } 19136 19137 var index = this._events[type].indexOf(fn); 19138 19139 if ( index > -1 ) { 19140 this._events[type].splice(index, 1); 19141 } 19142 }, 19143 19144 _execEvent: function (type) { 19145 if ( !this._events[type] ) { 19146 return; 19147 } 19148 19149 var i = 0, 19150 l = this._events[type].length; 19151 19152 if ( !l ) { 19153 return; 19154 } 19155 19156 for ( ; i < l; i++ ) { 19157 this._events[type][i].apply(this, [].slice.call(arguments, 1)); 19158 } 19159 }, 19160 19161 scrollBy: function (x, y, time, easing) { 19162 x = this.x + x; 19163 y = this.y + y; 19164 time = time || 0; 19165 19166 this.scrollTo(x, y, time, easing); 19167 }, 19168 19169 scrollTo: function (x, y, time, easing) { 19170 easing = easing || utils.ease.circular; 19171 19172 this.isInTransition = this.options.useTransition && time > 0; 19173 var transitionType = this.options.useTransition && easing.style; 19174 if ( !time || transitionType ) { 19175 if(transitionType) { 19176 this._transitionTimingFunction(easing.style); 19177 this._transitionTime(time); 19178 } 19179 this._translate(x, y); 19180 } else { 19181 this._animate(x, y, time, easing.fn); 19182 } 19183 }, 19184 19185 scrollToElement: function (el, time, offsetX, offsetY, easing) { 19186 el = el.nodeType ? el : this.scroller.querySelector(el); 19187 19188 if ( !el ) { 19189 return; 19190 } 19191 19192 var pos = utils.offset(el); 19193 19194 pos.left -= this.wrapperOffset.left; 19195 pos.top -= this.wrapperOffset.top; 19196 19197 // if offsetX/Y are true we center the element to the screen 19198 if ( offsetX === true ) { 19199 offsetX = Math.round(el.offsetWidth / 2 - this.wrapper.offsetWidth / 2); 19200 } 19201 if ( offsetY === true ) { 19202 offsetY = Math.round(el.offsetHeight / 2 - this.wrapper.offsetHeight / 2); 19203 } 19204 19205 pos.left -= offsetX || 0; 19206 pos.top -= offsetY || 0; 19207 19208 pos.left = pos.left > 0 ? 0 : pos.left < this.maxScrollX ? this.maxScrollX : pos.left; 19209 pos.top = pos.top > 0 ? 0 : pos.top < this.maxScrollY ? this.maxScrollY : pos.top; 19210 19211 time = time === undefined || time === null || time === 'auto' ? Math.max(Math.abs(this.x-pos.left), Math.abs(this.y-pos.top)) : time; 19212 19213 this.scrollTo(pos.left, pos.top, time, easing); 19214 }, 19215 19216 _transitionTime: function (time) { 19217 if (!this.options.useTransition) { 19218 return; 19219 } 19220 time = time || 0; 19221 var durationProp = utils.style.transitionDuration; 19222 if(!durationProp) { 19223 return; 19224 } 19225 19226 this.scrollerStyle[durationProp] = time + 'ms'; 19227 19228 if ( !time && utils.isBadAndroid ) { 19229 this.scrollerStyle[durationProp] = '0.0001ms'; 19230 // remove 0.0001ms 19231 var self = this; 19232 rAF(function() { 19233 if(self.scrollerStyle[durationProp] === '0.0001ms') { 19234 self.scrollerStyle[durationProp] = '0s'; 19235 } 19236 }); 19237 } 19238 19239 19240 if ( this.indicators ) { 19241 for ( var i = this.indicators.length; i--; ) { 19242 this.indicators[i].transitionTime(time); 19243 } 19244 } 19245 19246 19247// INSERT POINT: _transitionTime 19248 19249 }, 19250 19251 _transitionTimingFunction: function (easing) { 19252 this.scrollerStyle[utils.style.transitionTimingFunction] = easing; 19253 19254 19255 if ( this.indicators ) { 19256 for ( var i = this.indicators.length; i--; ) { 19257 this.indicators[i].transitionTimingFunction(easing); 19258 } 19259 } 19260 19261 19262// INSERT POINT: _transitionTimingFunction 19263 19264 }, 19265 19266 _translate: function (x, y) { 19267 //Uncode addition 19268 if ( (" " + this.wrapper.className + " ").replace(/[\n\t]/g, " ").indexOf(" no-scrolloverflow ") > -1 ) 19269 return false;
vendor: 9,939 bytes, lines 19270-19581
19270 19271 if ( this.options.useTransform ) { 19272 19273/* REPLACE START: _translate */ 19274 19275 this.scrollerStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.translateZ; 19276 19277/* REPLACE END: _translate */ 19278 19279 } else { 19280 x = Math.round(x); 19281 y = Math.round(y); 19282 this.scrollerStyle.left = x + 'px'; 19283 this.scrollerStyle.top = y + 'px'; 19284 } 19285 19286 this.x = x; 19287 this.y = y; 19288 19289 19290 if ( this.indicators ) { 19291 for ( var i = this.indicators.length; i--; ) { 19292 this.indicators[i].updatePosition(); 19293 } 19294 } 19295 19296 //Uncode addition 19297 var uncodevent = new CustomEvent('fp-slide-scroll'); 19298 window.dispatchEvent(uncodevent); 19299 19300// INSERT POINT: _translate 19301 19302 }, 19303 19304 _initEvents: function (remove) { 19305 var eventType = remove ? utils.removeEvent : utils.addEvent, 19306 target = this.options.bindToWrapper ? this.wrapper : window; 19307 19308 eventType(window, 'orientationchange', this); 19309 eventType(window, 'resize', this); 19310 19311 if ( this.options.click ) { 19312 eventType(this.wrapper, 'click', this, true); 19313 } 19314 19315 if ( !this.options.disableMouse ) { 19316 eventType(this.wrapper, 'mousedown', this); 19317 eventType(target, 'mousemove', this); 19318 eventType(target, 'mousecancel', this); 19319 eventType(target, 'mouseup', this); 19320 } 19321 19322 if ( utils.hasPointer && !this.options.disablePointer ) { 19323 eventType(this.wrapper, utils.prefixPointerEvent('pointerdown'), this); 19324 eventType(target, utils.prefixPointerEvent('pointermove'), this); 19325 eventType(target, utils.prefixPointerEvent('pointercancel'), this); 19326 eventType(target, utils.prefixPointerEvent('pointerup'), this); 19327 } 19328 19329 if ( utils.hasTouch && !this.options.disableTouch ) { 19330 eventType(this.wrapper, 'touchstart', this); 19331 eventType(target, 'touchmove', this); 19332 eventType(target, 'touchcancel', this); 19333 eventType(target, 'touchend', this); 19334 } 19335 19336 eventType(this.scroller, 'transitionend', this); 19337 eventType(this.scroller, 'webkitTransitionEnd', this); 19338 eventType(this.scroller, 'oTransitionEnd', this); 19339 eventType(this.scroller, 'MSTransitionEnd', this); 19340 }, 19341 19342 getComputedPosition: function () { 19343 var matrix = window.getComputedStyle(this.scroller, null), 19344 x, y; 19345 19346 if ( this.options.useTransform ) { 19347 matrix = matrix[utils.style.transform].split(')')[0].split(', '); 19348 x = +(matrix[12] || matrix[4]); 19349 y = +(matrix[13] || matrix[5]); 19350 } else { 19351 x = +matrix.left.replace(/[^-\d.]/g, ''); 19352 y = +matrix.top.replace(/[^-\d.]/g, ''); 19353 } 19354 19355 return { x: x, y: y }; 19356 }, 19357 _initIndicators: function () { 19358 var interactive = this.options.interactiveScrollbars, 19359 customStyle = typeof this.options.scrollbars != 'string', 19360 indicators = [], 19361 indicator; 19362 19363 var that = this; 19364 19365 this.indicators = []; 19366 19367 if ( this.options.scrollbars ) { 19368 // Vertical scrollbar 19369 if ( this.options.scrollY ) { 19370 indicator = { 19371 el: createDefaultScrollbar('v', interactive, this.options.scrollbars), 19372 interactive: interactive, 19373 defaultScrollbars: true, 19374 customStyle: customStyle, 19375 resize: this.options.resizeScrollbars, 19376 shrink: this.options.shrinkScrollbars, 19377 fade: this.options.fadeScrollbars, 19378 listenX: false 19379 }; 19380 19381 this.wrapper.appendChild(indicator.el); 19382 indicators.push(indicator); 19383 } 19384 19385 // Horizontal scrollbar 19386 if ( this.options.scrollX ) { 19387 indicator = { 19388 el: createDefaultScrollbar('h', interactive, this.options.scrollbars), 19389 interactive: interactive, 19390 defaultScrollbars: true, 19391 customStyle: customStyle, 19392 resize: this.options.resizeScrollbars, 19393 shrink: this.options.shrinkScrollbars, 19394 fade: this.options.fadeScrollbars, 19395 listenY: false 19396 }; 19397 19398 this.wrapper.appendChild(indicator.el); 19399 indicators.push(indicator); 19400 } 19401 } 19402 19403 if ( this.options.indicators ) { 19404 // TODO: check concat compatibility 19405 indicators = indicators.concat(this.options.indicators); 19406 } 19407 19408 for ( var i = indicators.length; i--; ) { 19409 this.indicators.push( new Indicator(this, indicators[i]) ); 19410 } 19411 19412 // TODO: check if we can use array.map (wide compatibility and performance issues) 19413 function _indicatorsMap (fn) { 19414 if (that.indicators) { 19415 for ( var i = that.indicators.length; i--; ) { 19416 fn.call(that.indicators[i]); 19417 } 19418 } 19419 } 19420 19421 if ( this.options.fadeScrollbars ) { 19422 this.on('scrollEnd', function () { 19423 _indicatorsMap(function () { 19424 this.fade(); 19425 }); 19426 }); 19427 19428 this.on('scrollCancel', function () { 19429 _indicatorsMap(function () { 19430 this.fade(); 19431 }); 19432 }); 19433 19434 this.on('scrollStart', function () { 19435 _indicatorsMap(function () { 19436 this.fade(1); 19437 }); 19438 }); 19439 19440 this.on('beforeScrollStart', function () { 19441 _indicatorsMap(function () { 19442 this.fade(1, true); 19443 }); 19444 }); 19445 } 19446 19447 19448 this.on('refresh', function () { 19449 _indicatorsMap(function () { 19450 this.refresh(); 19451 }); 19452 }); 19453 19454 this.on('destroy', function () { 19455 _indicatorsMap(function () { 19456 this.destroy(); 19457 }); 19458 19459 delete this.indicators; 19460 }); 19461 }, 19462 19463 _initWheel: function () { 19464 utils.addEvent(this.wrapper, 'wheel', this); 19465 utils.addEvent(this.wrapper, 'mousewheel', this); 19466 utils.addEvent(this.wrapper, 'DOMMouseScroll', this); 19467 19468 this.on('destroy', function () { 19469 clearTimeout(this.wheelTimeout); 19470 this.wheelTimeout = null; 19471 utils.removeEvent(this.wrapper, 'wheel', this); 19472 utils.removeEvent(this.wrapper, 'mousewheel', this); 19473 utils.removeEvent(this.wrapper, 'DOMMouseScroll', this); 19474 }); 19475 }, 19476 19477 _wheel: function (e) { 19478 if ( !this.enabled ) { 19479 return; 19480 } 19481 19482 var wheelDeltaX, wheelDeltaY, 19483 newX, newY, 19484 that = this; 19485 19486 if ( this.wheelTimeout === undefined ) { 19487 that._execEvent('scrollStart'); 19488 } 19489 19490 // Execute the scrollEnd event after 400ms the wheel stopped scrolling 19491 clearTimeout(this.wheelTimeout); 19492 this.wheelTimeout = setTimeout(function () { 19493 if(!that.options.snap) { 19494 that._execEvent('scrollEnd'); 19495 } 19496 that.wheelTimeout = undefined; 19497 }, 400); 19498 19499 if ( 'deltaX' in e ) { 19500 if (e.deltaMode === 1) { 19501 wheelDeltaX = -e.deltaX * this.options.mouseWheelSpeed; 19502 wheelDeltaY = -e.deltaY * this.options.mouseWheelSpeed; 19503 } else { 19504 wheelDeltaX = -e.deltaX; 19505 wheelDeltaY = -e.deltaY; 19506 } 19507 } else if ( 'wheelDeltaX' in e ) { 19508 wheelDeltaX = e.wheelDeltaX / 120 * this.options.mouseWheelSpeed; 19509 wheelDeltaY = e.wheelDeltaY / 120 * this.options.mouseWheelSpeed; 19510 } else if ( 'wheelDelta' in e ) { 19511 wheelDeltaX = wheelDeltaY = e.wheelDelta / 120 * this.options.mouseWheelSpeed; 19512 } else if ( 'detail' in e ) { 19513 wheelDeltaX = wheelDeltaY = -e.detail / 3 * this.options.mouseWheelSpeed; 19514 } else { 19515 return; 19516 } 19517 19518 wheelDeltaX *= this.options.invertWheelDirection; 19519 wheelDeltaY *= this.options.invertWheelDirection; 19520 19521 if ( !this.hasVerticalScroll ) { 19522 wheelDeltaX = wheelDeltaY; 19523 wheelDeltaY = 0; 19524 } 19525 19526 if ( this.options.snap ) { 19527 newX = this.currentPage.pageX; 19528 newY = this.currentPage.pageY; 19529 19530 if ( wheelDeltaX > 0 ) { 19531 newX--; 19532 } else if ( wheelDeltaX < 0 ) { 19533 newX++; 19534 } 19535 19536 if ( wheelDeltaY > 0 ) { 19537 newY--; 19538 } else if ( wheelDeltaY < 0 ) { 19539 newY++; 19540 } 19541 19542 this.goToPage(newX, newY); 19543 19544 return; 19545 } 19546 19547 newX = this.x + Math.round(this.hasHorizontalScroll ? wheelDeltaX : 0); 19548 newY = this.y + Math.round(this.hasVerticalScroll ? wheelDeltaY : 0); 19549 19550 this.directionX = wheelDeltaX > 0 ? -1 : wheelDeltaX < 0 ? 1 : 0; 19551 this.directionY = wheelDeltaY > 0 ? -1 : wheelDeltaY < 0 ? 1 : 0; 19552 19553 if ( newX > 0 ) { 19554 newX = 0; 19555 } else if ( newX < this.maxScrollX ) { 19556 newX = this.maxScrollX; 19557 } 19558 19559 if ( newY > 0 ) { 19560 newY = 0; 19561 } else if ( newY < this.maxScrollY ) { 19562 newY = this.maxScrollY; 19563 } 19564 19565 this.scrollTo(newX, newY, 0); 19566 19567// INSERT POINT: _wheel 19568 }, 19569 19570 _initSnap: function () { 19571 this.currentPage = {}; 19572 19573 if ( typeof this.options.snap == 'string' ) { 19574 this.options.snap = this.scroller.querySelectorAll(this.options.snap); 19575 } 19576 19577 this.on('refresh', function () { 19578 var i = 0, l, 19579 m = 0, n, 19580 cx, cy, 19581 x = 0, y,
vendor: 7,339 bytes, lines 19582-19835
19582 stepX = this.options.snapStepX || this.wrapperWidth, 19583 stepY = this.options.snapStepY || this.wrapperHeight, 19584 el; 19585 19586 this.pages = []; 19587 19588 if ( !this.wrapperWidth || !this.wrapperHeight || !this.scrollerWidth || !this.scrollerHeight ) { 19589 return; 19590 } 19591 19592 if ( this.options.snap === true ) { 19593 cx = Math.round( stepX / 2 ); 19594 cy = Math.round( stepY / 2 ); 19595 19596 while ( x > -this.scrollerWidth ) { 19597 this.pages[i] = []; 19598 l = 0; 19599 y = 0; 19600 19601 while ( y > -this.scrollerHeight ) { 19602 this.pages[i][l] = { 19603 x: Math.max(x, this.maxScrollX), 19604 y: Math.max(y, this.maxScrollY), 19605 width: stepX, 19606 height: stepY, 19607 cx: x - cx, 19608 cy: y - cy 19609 }; 19610 19611 y -= stepY; 19612 l++; 19613 } 19614 19615 x -= stepX; 19616 i++; 19617 } 19618 } else { 19619 el = this.options.snap; 19620 l = el.length; 19621 n = -1; 19622 19623 for ( ; i < l; i++ ) { 19624 if ( i === 0 || el[i].offsetLeft <= el[i-1].offsetLeft ) { 19625 m = 0; 19626 n++; 19627 } 19628 19629 if ( !this.pages[m] ) { 19630 this.pages[m] = []; 19631 } 19632 19633 x = Math.max(-el[i].offsetLeft, this.maxScrollX); 19634 y = Math.max(-el[i].offsetTop, this.maxScrollY); 19635 cx = x - Math.round(el[i].offsetWidth / 2); 19636 cy = y - Math.round(el[i].offsetHeight / 2); 19637 19638 this.pages[m][n] = { 19639 x: x, 19640 y: y, 19641 width: el[i].offsetWidth, 19642 height: el[i].offsetHeight, 19643 cx: cx, 19644 cy: cy 19645 }; 19646 19647 if ( x > this.maxScrollX ) { 19648 m++; 19649 } 19650 } 19651 } 19652 19653 this.goToPage(this.currentPage.pageX || 0, this.currentPage.pageY || 0, 0); 19654 19655 // Update snap threshold if needed 19656 if ( this.options.snapThreshold % 1 === 0 ) { 19657 this.snapThresholdX = this.options.snapThreshold; 19658 this.snapThresholdY = this.options.snapThreshold; 19659 } else { 19660 this.snapThresholdX = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].width * this.options.snapThreshold); 19661 this.snapThresholdY = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].height * this.options.snapThreshold); 19662 } 19663 }); 19664 19665 this.on('flick', function () { 19666 var time = this.options.snapSpeed || Math.max( 19667 Math.max( 19668 Math.min(Math.abs(this.x - this.startX), 1000), 19669 Math.min(Math.abs(this.y - this.startY), 1000) 19670 ), 300); 19671 19672 this.goToPage( 19673 this.currentPage.pageX + this.directionX, 19674 this.currentPage.pageY + this.directionY, 19675 time 19676 ); 19677 }); 19678 }, 19679 19680 _nearestSnap: function (x, y) { 19681 if ( !this.pages.length ) { 19682 return { x: 0, y: 0, pageX: 0, pageY: 0 }; 19683 } 19684 19685 var i = 0, 19686 l = this.pages.length, 19687 m = 0; 19688 19689 // Check if we exceeded the snap threshold 19690 if ( Math.abs(x - this.absStartX) < this.snapThresholdX && 19691 Math.abs(y - this.absStartY) < this.snapThresholdY ) { 19692 return this.currentPage; 19693 } 19694 19695 if ( x > 0 ) { 19696 x = 0; 19697 } else if ( x < this.maxScrollX ) { 19698 x = this.maxScrollX; 19699 } 19700 19701 if ( y > 0 ) { 19702 y = 0; 19703 } else if ( y < this.maxScrollY ) { 19704 y = this.maxScrollY; 19705 } 19706 19707 for ( ; i < l; i++ ) { 19708 if ( x >= this.pages[i][0].cx ) { 19709 x = this.pages[i][0].x; 19710 break; 19711 } 19712 } 19713 19714 l = this.pages[i].length; 19715 19716 for ( ; m < l; m++ ) { 19717 if ( y >= this.pages[0][m].cy ) { 19718 y = this.pages[0][m].y; 19719 break; 19720 } 19721 } 19722 19723 if ( i == this.currentPage.pageX ) { 19724 i += this.directionX; 19725 19726 if ( i < 0 ) { 19727 i = 0; 19728 } else if ( i >= this.pages.length ) { 19729 i = this.pages.length - 1; 19730 } 19731 19732 x = this.pages[i][0].x; 19733 } 19734 19735 if ( m == this.currentPage.pageY ) { 19736 m += this.directionY; 19737 19738 if ( m < 0 ) { 19739 m = 0; 19740 } else if ( m >= this.pages[0].length ) { 19741 m = this.pages[0].length - 1; 19742 } 19743 19744 y = this.pages[0][m].y; 19745 } 19746 19747 return { 19748 x: x, 19749 y: y, 19750 pageX: i, 19751 pageY: m 19752 }; 19753 }, 19754 19755 goToPage: function (x, y, time, easing) { 19756 easing = easing || this.options.bounceEasing; 19757 19758 if ( x >= this.pages.length ) { 19759 x = this.pages.length - 1; 19760 } else if ( x < 0 ) { 19761 x = 0; 19762 } 19763 19764 if ( y >= this.pages[x].length ) { 19765 y = this.pages[x].length - 1; 19766 } else if ( y < 0 ) { 19767 y = 0; 19768 } 19769 19770 var posX = this.pages[x][y].x, 19771 posY = this.pages[x][y].y; 19772 19773 time = time === undefined ? this.options.snapSpeed || Math.max( 19774 Math.max( 19775 Math.min(Math.abs(posX - this.x), 1000), 19776 Math.min(Math.abs(posY - this.y), 1000) 19777 ), 300) : time; 19778 19779 this.currentPage = { 19780 x: posX, 19781 y: posY, 19782 pageX: x, 19783 pageY: y 19784 }; 19785 19786 this.scrollTo(posX, posY, time, easing); 19787 }, 19788 19789 next: function (time, easing) { 19790 var x = this.currentPage.pageX, 19791 y = this.currentPage.pageY; 19792 19793 x++; 19794 19795 if ( x >= this.pages.length && this.hasVerticalScroll ) { 19796 x = 0; 19797 y++; 19798 } 19799 19800 this.goToPage(x, y, time, easing); 19801 }, 19802 19803 prev: function (time, easing) { 19804 var x = this.currentPage.pageX, 19805 y = this.currentPage.pageY; 19806 19807 x--; 19808 19809 if ( x < 0 && this.hasVerticalScroll ) { 19810 x = 0; 19811 y--; 19812 } 19813 19814 this.goToPage(x, y, time, easing); 19815 }, 19816 19817 _initKeys: function (e) { 19818 // default key bindings 19819 var keys = { 19820 pageUp: 33, 19821 pageDown: 34, 19822 end: 35, 19823 home: 36, 19824 left: 37, 19825 up: 38, 19826 right: 39, 19827 down: 40 19828 }; 19829 var i; 19830 19831 // if you give me characters I give you keycode 19832 if ( typeof this.options.keyBindings == 'object' ) { 19833 for ( i in this.options.keyBindings ) { 19834 if ( typeof this.options.keyBindings[i] == 'string' ) { 19835 this.options.keyBindings[i] = this.options.keyBindings[i].toUpperCase().charCo
vendor: 11,097 bytes, lines 19835-20188
19835deAt(0); 19836 } 19837 } 19838 } else { 19839 this.options.keyBindings = {}; 19840 } 19841 19842 for ( i in keys ) { 19843 this.options.keyBindings[i] = this.options.keyBindings[i] || keys[i]; 19844 } 19845 19846 utils.addEvent(window, 'keydown', this); 19847 19848 this.on('destroy', function () { 19849 utils.removeEvent(window, 'keydown', this); 19850 }); 19851 }, 19852 19853 _key: function (e) { 19854 if ( !this.enabled ) { 19855 return; 19856 } 19857 19858 var snap = this.options.snap, // we are using this alot, better to cache it 19859 newX = snap ? this.currentPage.pageX : this.x, 19860 newY = snap ? this.currentPage.pageY : this.y, 19861 now = utils.getTime(), 19862 prevTime = this.keyTime || 0, 19863 acceleration = 0.250, 19864 pos; 19865 19866 if ( this.options.useTransition && this.isInTransition ) { 19867 pos = this.getComputedPosition(); 19868 19869 this._translate(Math.round(pos.x), Math.round(pos.y)); 19870 this.isInTransition = false; 19871 } 19872 19873 this.keyAcceleration = now - prevTime < 200 ? Math.min(this.keyAcceleration + acceleration, 50) : 0; 19874 19875 switch ( e.keyCode ) { 19876 case this.options.keyBindings.pageUp: 19877 if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) { 19878 newX += snap ? 1 : this.wrapperWidth; 19879 } else { 19880 newY += snap ? 1 : this.wrapperHeight; 19881 } 19882 break; 19883 case this.options.keyBindings.pageDown: 19884 if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) { 19885 newX -= snap ? 1 : this.wrapperWidth; 19886 } else { 19887 newY -= snap ? 1 : this.wrapperHeight; 19888 } 19889 break; 19890 case this.options.keyBindings.end: 19891 newX = snap ? this.pages.length-1 : this.maxScrollX; 19892 newY = snap ? this.pages[0].length-1 : this.maxScrollY; 19893 break; 19894 case this.options.keyBindings.home: 19895 newX = 0; 19896 newY = 0; 19897 break; 19898 case this.options.keyBindings.left: 19899 newX += snap ? -1 : 5 + this.keyAcceleration>>0; 19900 break; 19901 case this.options.keyBindings.up: 19902 newY += snap ? 1 : 5 + this.keyAcceleration>>0; 19903 break; 19904 case this.options.keyBindings.right: 19905 newX -= snap ? -1 : 5 + this.keyAcceleration>>0; 19906 break; 19907 case this.options.keyBindings.down: 19908 newY -= snap ? 1 : 5 + this.keyAcceleration>>0; 19909 break; 19910 default: 19911 return; 19912 } 19913 19914 if ( snap ) { 19915 this.goToPage(newX, newY); 19916 return; 19917 } 19918 19919 if ( newX > 0 ) { 19920 newX = 0; 19921 this.keyAcceleration = 0; 19922 } else if ( newX < this.maxScrollX ) { 19923 newX = this.maxScrollX; 19924 this.keyAcceleration = 0; 19925 } 19926 19927 if ( newY > 0 ) { 19928 newY = 0; 19929 this.keyAcceleration = 0; 19930 } else if ( newY < this.maxScrollY ) { 19931 newY = this.maxScrollY; 19932 this.keyAcceleration = 0; 19933 } 19934 19935 this.scrollTo(newX, newY, 0); 19936 19937 this.keyTime = now; 19938 }, 19939 19940 _animate: function (destX, destY, duration, easingFn) { 19941 var that = this, 19942 startX = this.x, 19943 startY = this.y, 19944 startTime = utils.getTime(), 19945 destTime = startTime + duration; 19946 19947 function step () { 19948 var now = utils.getTime(), 19949 newX, newY, 19950 easing; 19951 19952 if ( now >= destTime ) { 19953 that.isAnimating = false; 19954 that._translate(destX, destY); 19955 19956 if ( !that.resetPosition(that.options.bounceTime) ) { 19957 that._execEvent('scrollEnd'); 19958 } 19959 19960 return; 19961 } 19962 19963 now = ( now - startTime ) / duration; 19964 easing = easingFn(now); 19965 newX = ( destX - startX ) * easing + startX; 19966 newY = ( destY - startY ) * easing + startY; 19967 that._translate(newX, newY); 19968 19969 if ( that.isAnimating ) { 19970 rAF(step); 19971 } 19972 } 19973 19974 this.isAnimating = true; 19975 step(); 19976 }, 19977 handleEvent: function (e) { 19978 switch ( e.type ) { 19979 case 'touchstart': 19980 case 'pointerdown': 19981 case 'MSPointerDown': 19982 case 'mousedown': 19983 this._start(e); 19984 break; 19985 case 'touchmove': 19986 case 'pointermove': 19987 case 'MSPointerMove': 19988 case 'mousemove': 19989 this._move(e); 19990 break; 19991 case 'touchend': 19992 case 'pointerup': 19993 case 'MSPointerUp': 19994 case 'mouseup': 19995 case 'touchcancel': 19996 case 'pointercancel': 19997 case 'MSPointerCancel': 19998 case 'mousecancel': 19999 this._end(e); 20000 break; 20001 case 'orientationchange': 20002 case 'resize': 20003 this._resize(); 20004 break; 20005 case 'transitionend': 20006 case 'webkitTransitionEnd': 20007 case 'oTransitionEnd': 20008 case 'MSTransitionEnd': 20009 this._transitionEnd(e); 20010 break; 20011 case 'wheel': 20012 case 'DOMMouseScroll': 20013 case 'mousewheel': 20014 this._wheel(e); 20015 break; 20016 case 'keydown': 20017 this._key(e); 20018 break; 20019 case 'click': 20020 if ( this.enabled && !e._constructed ) { 20021 e.preventDefault(); 20022 e.stopPropagation(); 20023 } 20024 break; 20025 } 20026 } 20027}; 20028function createDefaultScrollbar (direction, interactive, type) { 20029 var scrollbar = document.createElement('div'), 20030 indicator = document.createElement('div'); 20031 20032 if ( type === true ) { 20033 scrollbar.style.cssText = 'position:absolute;z-index:9999'; 20034 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'; 20035 } 20036 20037 indicator.className = 'iScrollIndicator'; 20038 20039 if ( direction == 'h' ) { 20040 if ( type === true ) { 20041 scrollbar.style.cssText += ';height:7px;left:2px;right:2px;bottom:0'; 20042 indicator.style.height = '100%'; 20043 } 20044 scrollbar.className = 'iScrollHorizontalScrollbar'; 20045 } else { 20046 if ( type === true ) { 20047 scrollbar.style.cssText += ';width:7px;bottom:2px;top:2px;right:1px'; 20048 indicator.style.width = '100%'; 20049 } 20050 scrollbar.className = 'iScrollVerticalScrollbar'; 20051 } 20052 20053 scrollbar.style.cssText += ';overflow:hidden'; 20054 20055 if ( !interactive ) { 20056 scrollbar.style.pointerEvents = 'none'; 20057 } 20058 20059 scrollbar.appendChild(indicator); 20060 20061 return scrollbar; 20062} 20063 20064function Indicator (scroller, options) { 20065 this.wrapper = typeof options.el == 'string' ? document.querySelector(options.el) : options.el; 20066 this.wrapperStyle = this.wrapper.style; 20067 this.indicator = this.wrapper.children[0]; 20068 this.indicatorStyle = this.indicator.style; 20069 this.scroller = scroller; 20070 20071 this.options = { 20072 listenX: true, 20073 listenY: true, 20074 interactive: false, 20075 resize: true, 20076 defaultScrollbars: false, 20077 shrink: false, 20078 fade: false, 20079 speedRatioX: 0, 20080 speedRatioY: 0 20081 }; 20082 20083 for ( var i in options ) { 20084 this.options[i] = options[i]; 20085 } 20086 20087 this.sizeRatioX = 1; 20088 this.sizeRatioY = 1; 20089 this.maxPosX = 0; 20090 this.maxPosY = 0; 20091 20092 if ( this.options.interactive ) { 20093 if ( !this.options.disableTouch ) { 20094 utils.addEvent(this.indicator, 'touchstart', this); 20095 utils.addEvent(window, 'touchend', this); 20096 } 20097 if ( !this.options.disablePointer ) { 20098 utils.addEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this); 20099 utils.addEvent(window, utils.prefixPointerEvent('pointerup'), this); 20100 } 20101 if ( !this.options.disableMouse ) { 20102 utils.addEvent(this.indicator, 'mousedown', this); 20103 utils.addEvent(window, 'mouseup', this); 20104 } 20105 } 20106 20107 if ( this.options.fade ) { 20108 this.wrapperStyle[utils.style.transform] = this.scroller.translateZ; 20109 var durationProp = utils.style.transitionDuration; 20110 if(!durationProp) { 20111 return; 20112 } 20113 this.wrapperStyle[durationProp] = utils.isBadAndroid ? '0.0001ms' : '0ms'; 20114 // remove 0.0001ms 20115 var self = this; 20116 if(utils.isBadAndroid) { 20117 rAF(function() { 20118 if(self.wrapperStyle[durationProp] === '0.0001ms') { 20119 self.wrapperStyle[durationProp] = '0s'; 20120 } 20121 }); 20122 } 20123 this.wrapperStyle.opacity = '0'; 20124 } 20125} 20126 20127Indicator.prototype = { 20128 handleEvent: function (e) { 20129 switch ( e.type ) { 20130 case 'touchstart': 20131 case 'pointerdown': 20132 case 'MSPointerDown': 20133 case 'mousedown': 20134 this._start(e); 20135 break; 20136 case 'touchmove': 20137 case 'pointermove': 20138 case 'MSPointerMove': 20139 case 'mousemove': 20140 this._move(e); 20141 break; 20142 case 'touchend': 20143 case 'pointerup': 20144 case 'MSPointerUp': 20145 case 'mouseup': 20146 case 'touchcancel': 20147 case 'pointercancel': 20148 case 'MSPointerCancel': 20149 case 'mousecancel': 20150 this._end(e); 20151 break; 20152 } 20153 }, 20154 20155 destroy: function () { 20156 if ( this.options.fadeScrollbars ) { 20157 clearTimeout(this.fadeTimeout); 20158 this.fadeTimeout = null; 20159 } 20160 if ( this.options.interactive ) { 20161 utils.removeEvent(this.indicator, 'touchstart', this); 20162 utils.removeEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this); 20163 utils.removeEvent(this.indicator, 'mousedown', this); 20164 20165 utils.removeEvent(window, 'touchmove', this); 20166 utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this); 20167 utils.removeEvent(window, 'mousemove', this); 20168 20169 utils.removeEvent(window, 'touchend', this); 20170 utils.removeEvent(window, utils.prefixPointerEvent('pointerup'), this); 20171 utils.removeEvent(window, 'mouseup', this); 20172 } 20173 20174 if ( this.options.defaultScrollbars ) { 20175 this.wrapper.parentNode.removeChild(this.wrapper); 20176 } 20177 }, 20178 20179 _start: function (e) { 20180 var point = e.touches ? e.touches[0] : e; 20181 20182 e.preventDefault(); 20183 e.stopPropagation(); 20184 20185 this.transitionTime(); 20186 20187 this.initiated = true; 20188 this.moved = false;
vendor: 9,615 bytes, lines 20189-20447
20189 this.lastPointX = point.pageX; 20190 this.lastPointY = point.pageY; 20191 20192 this.startTime = utils.getTime(); 20193 20194 if ( !this.options.disableTouch ) { 20195 utils.addEvent(window, 'touchmove', this); 20196 } 20197 if ( !this.options.disablePointer ) { 20198 utils.addEvent(window, utils.prefixPointerEvent('pointermove'), this); 20199 } 20200 if ( !this.options.disableMouse ) { 20201 utils.addEvent(window, 'mousemove', this); 20202 } 20203 20204 this.scroller._execEvent('beforeScrollStart'); 20205 }, 20206 20207 _move: function (e) { 20208 var point = e.touches ? e.touches[0] : e, 20209 deltaX, deltaY, 20210 newX, newY, 20211 timestamp = utils.getTime(); 20212 20213 if ( !this.moved ) { 20214 this.scroller._execEvent('scrollStart'); 20215 } 20216 20217 this.moved = true; 20218 20219 deltaX = point.pageX - this.lastPointX; 20220 this.lastPointX = point.pageX; 20221 20222 deltaY = point.pageY - this.lastPointY; 20223 this.lastPointY = point.pageY; 20224 20225 newX = this.x + deltaX; 20226 newY = this.y + deltaY; 20227 20228 this._pos(newX, newY); 20229 20230// INSERT POINT: indicator._move 20231 20232 e.preventDefault(); 20233 e.stopPropagation(); 20234 }, 20235 20236 _end: function (e) { 20237 if ( !this.initiated ) { 20238 return; 20239 } 20240 20241 this.initiated = false; 20242 20243 e.preventDefault(); 20244 e.stopPropagation(); 20245 20246 utils.removeEvent(window, 'touchmove', this); 20247 utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this); 20248 utils.removeEvent(window, 'mousemove', this); 20249 20250 if ( this.scroller.options.snap ) { 20251 var snap = this.scroller._nearestSnap(this.scroller.x, this.scroller.y); 20252 20253 var time = this.options.snapSpeed || Math.max( 20254 Math.max( 20255 Math.min(Math.abs(this.scroller.x - snap.x), 1000), 20256 Math.min(Math.abs(this.scroller.y - snap.y), 1000) 20257 ), 300); 20258 20259 if ( this.scroller.x != snap.x || this.scroller.y != snap.y ) { 20260 this.scroller.directionX = 0; 20261 this.scroller.directionY = 0; 20262 this.scroller.currentPage = snap; 20263 this.scroller.scrollTo(snap.x, snap.y, time, this.scroller.options.bounceEasing); 20264 } 20265 } 20266 20267 if ( this.moved ) { 20268 this.scroller._execEvent('scrollEnd'); 20269 } 20270 }, 20271 20272 transitionTime: function (time) { 20273 time = time || 0; 20274 var durationProp = utils.style.transitionDuration; 20275 if(!durationProp) { 20276 return; 20277 } 20278 20279 this.indicatorStyle[durationProp] = time + 'ms'; 20280 20281 if ( !time && utils.isBadAndroid ) { 20282 this.indicatorStyle[durationProp] = '0.0001ms'; 20283 // remove 0.0001ms 20284 var self = this; 20285 rAF(function() { 20286 if(self.indicatorStyle[durationProp] === '0.0001ms') { 20287 self.indicatorStyle[durationProp] = '0s'; 20288 } 20289 }); 20290 } 20291 }, 20292 20293 transitionTimingFunction: function (easing) { 20294 this.indicatorStyle[utils.style.transitionTimingFunction] = easing; 20295 }, 20296 20297 refresh: function () { 20298 this.transitionTime(); 20299 20300 if ( this.options.listenX && !this.options.listenY ) { 20301 this.indicatorStyle.display = this.scroller.hasHorizontalScroll ? 'block' : 'none'; 20302 } else if ( this.options.listenY && !this.options.listenX ) { 20303 this.indicatorStyle.display = this.scroller.hasVerticalScroll ? 'block' : 'none'; 20304 } else { 20305 this.indicatorStyle.display = this.scroller.hasHorizontalScroll || this.scroller.hasVerticalScroll ? 'block' : 'none'; 20306 } 20307 20308 if ( this.scroller.hasHorizontalScroll && this.scroller.hasVerticalScroll ) { 20309 utils.addClass(this.wrapper, 'iScrollBothScrollbars'); 20310 utils.removeClass(this.wrapper, 'iScrollLoneScrollbar'); 20311 20312 if ( this.options.defaultScrollbars && this.options.customStyle ) { 20313 if ( this.options.listenX ) { 20314 this.wrapper.style.right = '8px'; 20315 } else { 20316 this.wrapper.style.bottom = '8px'; 20317 } 20318 } 20319 } else { 20320 utils.removeClass(this.wrapper, 'iScrollBothScrollbars'); 20321 utils.addClass(this.wrapper, 'iScrollLoneScrollbar'); 20322 20323 if ( this.options.defaultScrollbars && this.options.customStyle ) { 20324 if ( this.options.listenX ) { 20325 this.wrapper.style.right = '2px'; 20326 } else { 20327 this.wrapper.style.bottom = '2px'; 20328 } 20329 } 20330 } 20331 20332 var r = this.wrapper.offsetHeight; // force refresh 20333 20334 if ( this.options.listenX ) { 20335 this.wrapperWidth = this.wrapper.clientWidth; 20336 if ( this.options.resize ) { 20337 this.indicatorWidth = Math.max(Math.round(this.wrapperWidth * this.wrapperWidth / (this.scroller.scrollerWidth || this.wrapperWidth || 1)), 8); 20338 this.indicatorStyle.width = this.indicatorWidth + 'px'; 20339 } else { 20340 this.indicatorWidth = this.indicator.clientWidth; 20341 } 20342 20343 this.maxPosX = this.wrapperWidth - this.indicatorWidth; 20344 20345 if ( this.options.shrink == 'clip' ) { 20346 this.minBoundaryX = -this.indicatorWidth + 8; 20347 this.maxBoundaryX = this.wrapperWidth - 8; 20348 } else { 20349 this.minBoundaryX = 0; 20350 this.maxBoundaryX = this.maxPosX; 20351 } 20352 20353 this.sizeRatioX = this.options.speedRatioX || (this.scroller.maxScrollX && (this.maxPosX / this.scroller.maxScrollX)); 20354 } 20355 20356 if ( this.options.listenY ) { 20357 this.wrapperHeight = this.wrapper.clientHeight; 20358 if ( this.options.resize ) { 20359 this.indicatorHeight = Math.max(Math.round(this.wrapperHeight * this.wrapperHeight / (this.scroller.scrollerHeight || this.wrapperHeight || 1)), 8); 20360 this.indicatorStyle.height = this.indicatorHeight + 'px'; 20361 } else { 20362 this.indicatorHeight = this.indicator.clientHeight; 20363 } 20364 20365 this.maxPosY = this.wrapperHeight - this.indicatorHeight; 20366 20367 if ( this.options.shrink == 'clip' ) { 20368 this.minBoundaryY = -this.indicatorHeight + 8; 20369 this.maxBoundaryY = this.wrapperHeight - 8; 20370 } else { 20371 this.minBoundaryY = 0; 20372 this.maxBoundaryY = this.maxPosY; 20373 } 20374 20375 this.maxPosY = this.wrapperHeight - this.indicatorHeight; 20376 this.sizeRatioY = this.options.speedRatioY || (this.scroller.maxScrollY && (this.maxPosY / this.scroller.maxScrollY)); 20377 } 20378 20379 this.updatePosition(); 20380 }, 20381 20382 updatePosition: function () { 20383 var x = this.options.listenX && Math.round(this.sizeRatioX * this.scroller.x) || 0, 20384 y = this.options.listenY && Math.round(this.sizeRatioY * this.scroller.y) || 0; 20385 20386 if ( !this.options.ignoreBoundaries ) { 20387 if ( x < this.minBoundaryX ) { 20388 if ( this.options.shrink == 'scale' ) { 20389 this.width = Math.max(this.indicatorWidth + x, 8); 20390 this.indicatorStyle.width = this.width + 'px'; 20391 } 20392 x = this.minBoundaryX; 20393 } else if ( x > this.maxBoundaryX ) { 20394 if ( this.options.shrink == 'scale' ) { 20395 this.width = Math.max(this.indicatorWidth - (x - this.maxPosX), 8); 20396 this.indicatorStyle.width = this.width + 'px'; 20397 x = this.maxPosX + this.indicatorWidth - this.width; 20398 } else { 20399 x = this.maxBoundaryX; 20400 } 20401 } else if ( this.options.shrink == 'scale' && this.width != this.indicatorWidth ) { 20402 this.width = this.indicatorWidth; 20403 this.indicatorStyle.width = this.width + 'px'; 20404 } 20405 20406 if ( y < this.minBoundaryY ) { 20407 if ( this.options.shrink == 'scale' ) { 20408 this.height = Math.max(this.indicatorHeight + y * 3, 8); 20409 this.indicatorStyle.height = this.height + 'px'; 20410 } 20411 y = this.minBoundaryY; 20412 } else if ( y > this.maxBoundaryY ) { 20413 if ( this.options.shrink == 'scale' ) { 20414 this.height = Math.max(this.indicatorHeight - (y - this.maxPosY) * 3, 8); 20415 this.indicatorStyle.height = this.height + 'px'; 20416 y = this.maxPosY + this.indicatorHeight - this.height; 20417 } else { 20418 y = this.maxBoundaryY; 20419 } 20420 } else if ( this.options.shrink == 'scale' && this.height != this.indicatorHeight ) { 20421 this.height = this.indicatorHeight; 20422 this.indicatorStyle.height = this.height + 'px'; 20423 } 20424 } 20425 20426 this.x = x; 20427 this.y = y; 20428 20429 if ( this.scroller.options.useTransform ) { 20430 this.indicatorStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.scroller.translateZ; 20431 } else { 20432 this.indicatorStyle.left = x + 'px'; 20433 this.indicatorStyle.top = y + 'px'; 20434 } 20435 }, 20436 20437 _pos: function (x, y) { 20438 if ( x < 0 ) { 20439 x = 0; 20440 } else if ( x > this.maxPosX ) { 20441 x = this.maxPosX; 20442 } 20443 20444 if ( y < 0 ) { 20445 y = 0; 20446 } else if ( y > this.maxPosY ) { 20447 y = this.maxPosY;
20448 } 20449 20450 x = this.options.listenX ? Math.round(x / this.sizeRatioX) : this.scroller.x; 20451 y = this.options.listenY ? Math.round(y / this.sizeRatioY) : this.scroller.y; 20452 20453 this.scroller.scrollTo(x, y); 20454 }, 20455 20456 fade: function (val, hold) { 20457 if ( hold && !this.visible ) { 20458 return; 20459 } 20460 20461 clearTimeout(this.fadeTimeout); 20462 this.fadeTimeout = null; 20463 20464 var time = val ? 250 : 500, 20465 delay = val ? 0 : 300; 20466 20467 val = val ? '1' : '0'; 20468 20469 this.wrapperStyle[utils.style.transitionDuration] = time + 'ms'; 20470 20471 this.fadeTimeout = setTimeout((function (val) { 20472 this.wrapperStyle.opacity = val; 20473 this.visible = +val; 20474 }).bind(this, val), delay); 20475 } 20476}; 20477 20478IScroll.utils = utils; 20479 20480if ( typeof module != 'undefined' && module.exports ) { 20481 module.exports = IScroll; 20482} else if ( typeof define == 'function' && define.amd ) { 20483 define( function () { return IScroll; } ); 20484} else { 20485 window.IScroll = IScroll; 20486} 20487 20488})(window, document, Math); 20489/*! 20490 * fullPage 2.9.4 20491 * https://github.com/alvarotrigo/fullPage.js 20492 * @license MIT licensed 20493 * 20494 * Copyright (C) 2015 alvarotrigo.com - A project by Alvaro Trigo 20495 */ 20496(function(global, factory) { 20497 'use strict'; 20498 if (typeof define === 'function' && define.amd) { 20499 define(['jquery'], function($) { 20500 return factory($, global, global.document, global.Math); 20501 }); 20502 } else if (typeof exports === "object" && exports) { 20503 module.exports = factory(require('jquery'), global, global.document, global.Math); 20504 } else { 20505 factory(jQuery, global, global.document, global.Math); 20506 } 20507})(typeof window !== 'undefined' ? window : this, function($, window, document, Math, undefined) { 20508 'use strict'; 20509 20510 // keeping central set of classnames and selectors 20511 var WRAPPER = 'fullpage-wrapper'; 20512 var WRAPPER_SEL = '.' + WRAPPER; 20513 20514 // slimscroll 20515 var SCROLLABLE = 'fp-scrollable'; 20516 var SCROLLABLE_SEL = '.' + SCROLLABLE; 20517 20518 // util 20519 var RESPONSIVE = 'fp-responsive'; 20520 var NO_TRANSITION = 'fp-notransition'; 20521 var DESTROYED = 'fp-destroyed'; 20522 var ENABLED = 'fp-enabled'; 20523 var VIEWING_PREFIX = 'fp-viewing'; 20524 var ACTIVE = 'active'; 20525 var ACTIVE_SEL = '.' + ACTIVE; 20526 var COMPLETELY = 'fp-completely'; 20527 var COMPLETELY_SEL = '.' + COMPLETELY; 20528 20529 // section 20530 var SECTION_DEFAULT_SEL = '.section'; 20531 var SECTION = 'fp-section'; 20532 var SECTION_SEL = '.' + SECTION; 20533 var SECTION_ACTIVE_SEL = SECTION_SEL + ACTIVE_SEL; 20534 var SECTION_FIRST_SEL = SECTION_SEL + ':first'; 20535 var SECTION_LAST_SEL = SECTION_SEL + ':last'; 20536 var TABLE_CELL = 'fp-tableCell'; 20537 var TABLE_CELL_SEL = '.' + TABLE_CELL; 20538 var AUTO_HEIGHT = 'fp-auto-height'; 20539 var AUTO_HEIGHT_SEL = '.fp-auto-height'; 20540 var NORMAL_SCROLL = 'fp-normal-scroll'; 20541 var NORMAL_SCROLL_SEL = '.fp-normal-scroll'; 20542 20543 // section nav 20544 var SECTION_NAV = 'fp-nav'; 20545 var SECTION_NAV_SEL = '#' + SECTION_NAV; 20546 var SECTION_NAV_TOOLTIP = 'fp-tooltip'; 20547 var SECTION_NAV_TOOLTIP_SEL='.'+SECTION_NAV_TOOLTIP; 20548 var SHOW_ACTIVE_TOOLTIP = 'fp-show-active'; 20549 20550 // slide 20551 var SLIDE_DEFAULT_SEL = '.slide'; 20552 var SLIDE = 'fp-slide'; 20553 var SLIDE_SEL = '.' + SLIDE; 20554 var SLIDE_ACTIVE_SEL = SLIDE_SEL + ACTIVE_SEL; 20555 var SLIDES_WRAPPER = 'fp-slides'; 20556 var SLIDES_WRAPPER_SEL = '.' + SLIDES_WRAPPER; 20557 var SLIDES_CONTAINER = 'fp-slidesContainer'; 20558 var SLIDES_CONTAINER_SEL = '.' + SLIDES_CONTAINER; 20559 var TABLE = 'fp-table'; 20560 20561 // slide nav 20562 var SLIDES_NAV = 'fp-slidesNav'; 20563 var SLIDES_NAV_SEL = '.' + SLIDES_NAV; 20564 var SLIDES_NAV_LINK_SEL = SLIDES_NAV_SEL + ' a'; 20565 var SLIDES_ARROW = 'fp-controlArrow'; 20566 var SLIDES_ARROW_SEL = '.' + SLIDES_ARROW; 20567 var SLIDES_PREV = 'fp-prev'; 20568 var SLIDES_PREV_SEL = '.' + SLIDES_PREV; 20569 var SLIDES_ARROW_PREV = SLIDES_ARROW + ' ' + SLIDES_PREV; 20570 var SLIDES_ARROW_PREV_SEL = SLIDES_ARROW_SEL + SLIDES_PREV_SEL; 20571 var SLIDES_NEXT = 'fp-next';
20572 var SLIDES_NEXT_SEL = '.' + SLIDES_NEXT; 20573 var SLIDES_ARROW_NEXT = SLIDES_ARROW + ' ' + SLIDES_NEXT; 20574 var SLIDES_ARROW_NEXT_SEL = SLIDES_ARROW_SEL + SLIDES_NEXT_SEL; 20575 20576 var $window = $(window); 20577 var $document = $(document); 20578 20579 // Default options for iScroll.js used when using scrollOverflow 20580 var iscrollOptions = { 20581 scrollbars: true, 20582 mouseWheel: true, 20583 hideScrollbars: false, 20584 fadeScrollbars: false, 20585 disableMouse: true, 20586 interactiveScrollbars: true, 20587 bounce: false, 20588 }; 20589 20590 $.fn.fullpage = function(options) { 20591 //only once my friend! 20592 if($('html').hasClass(ENABLED)){ displayWarnings(); return; } 20593 20594 // common jQuery objects 20595 var $htmlBody = $('html, body'); 20596 var $body = $('body'); 20597 20598 var FP = $.fn.fullpage; 20599 20600 // Creating some defaults, extending them with any options that were provided 20601 options = $.extend({ 20602 //navigation 20603 menu: false, 20604 anchors:[], 20605 lockAnchors: false, 20606 navigation: false, 20607 navigationPosition: 'right', 20608 navigationTooltips: [], 20609 showActiveTooltip: false, 20610 slidesNavigation: false, 20611 slidesNavPosition: 'bottom', 20612 scrollBar: false, 20613 hybrid: false, 20614 20615 //scrolling 20616 css3: true, 20617 scrollingSpeed: 700, 20618 autoScrolling: true, 20619 fitToSection: true, 20620 fitToSectionDelay: 1000, 20621 easing: 'easeInOutCubic', 20622 easingcss3: 'ease', 20623 loopBottom: false, 20624 loopTop: false, 20625 loopHorizontal: true, 20626 continuousVertical: false, 20627 continuousHorizontal: false, 20628 scrollHorizontally: false, 20629 interlockedSlides: false, 20630 dragAndMove: false, 20631 offsetSections: false, 20632 resetSliders: false, 20633 fadingEffect: false, 20634 normalScrollElements: null, 20635 scrollOverflow: false, 20636 scrollOverflowReset: false, 20637 scrollOverflowHandler: iscrollHandler, 20638 scrollOverflowOptions: null, 20639 touchSensitivity: 5, 20640 normalScrollElementTouchThreshold: 5, 20641 bigSectionsDestination: null, 20642 20643 //Accessibility 20644 keyboardScrolling: true, 20645 animateAnchor: true, 20646 recordHistory: true, 20647 20648 //design 20649 controlArrows: true, 20650 controlArrowColor: '#fff', 20651 verticalCentered: true, 20652 sectionsColor : [], 20653 paddingTop: 0, 20654 paddingBottom: 0, 20655 fixedElements: null, 20656 responsive: 0, //backwards compabitility with responsiveWiddth 20657 responsiveWidth: 0, 20658 responsiveHeight: 0, 20659 responsiveSlides: false, 20660 parallax: false, 20661 parallaxOptions: { 20662 type: 'reveal', 20663 percentage: 62, 20664 property: 'translate' 20665 }, 20666 20667 //Custom selectors 20668 sectionSelector: SECTION_DEFAULT_SEL, 20669 slideSelector: SLIDE_DEFAULT_SEL, 20670 20671 //events 20672 afterLoad: null, 20673 onLeave: null, 20674 afterRender: null, 20675 afterResize: null, 20676 afterReBuild: null, 20677 afterSlideLoad: null, 20678 onSlideLeave: null, 20679 afterResponsive: null, 20680 20681 lazyLoading: true 20682 }, options); 20683 20684 //flag to avoid very fast sliding for landscape sliders 20685 var slideMoving = false; 20686 20687 var isTouchDevice = navigator.userAgent.match(/(iPhone|iPod|iPad|Android|playbook|silk|BlackBerry|BB10|Windows Phone|Tizen|Bada|webOS|IEMobile|Opera Mini)/); 20688 var isTouch = (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0) || (navigator.maxTouchPoints)); 20689 var container = $(this); 20690 var windowsHeight = $window.height(); 20691 var isResizing = false; 20692 var isWindowFocused = true; 20693 var lastScrolledDestiny; 20694 var lastScrolledSlide; 20695 var canScroll = true; 20696 var scrollings = []; 20697 var controlPressed; 20698 var startingSection; 20699 var isScrollAllowed = {}; 20700 isScrollAllowed.m = { 'up':true, 'down':true, 'left':true, 'right':true }; 20701 isScrollAllowed.k = $.extend(true,{}, isScrollAllowed.m); 20702 var MSPointer = getMSPointer(); 20703 var events = { 20704 touchmove: 'ontouchmove' in window ? 'touchmove' : MSPointer.move, 20705 touchstart: 'ontouchstart' in window ? 'touchstart' : MSPointer.down 20706 }; 20707 20708 //cheks for passive event support 20709 //added by Uncode from new fullPage updates 20710 var g_supportsPassive = false;
20711 try { 20712 var opts = Object.defineProperty({}, 'passive', { 20713 get: function() { 20714 g_supportsPassive = true; 20715 } 20716 }); 20717 window.addEventListener("testPassive", null, opts); 20718 window.removeEventListener("testPassive", null, opts); 20719 } catch (e) {} 20720 20721 //timeouts 20722 var resizeId; 20723 var afterSectionLoadsId; 20724 var afterSlideLoadsId; 20725 var scrollId; 20726 var scrollId2; 20727 var keydownId; 20728 var originals = $.extend(true, {}, options); //deep copy 20729 20730 //Uncode addition 20731 var $masthead = $('#masthead'); 20732 var hideMenu = !$('body').hasClass('vmenu') && $('body').hasClass('uncode-fp-menu-hide') ? true : false; 20733 var menuHeight = $masthead.hasClass('menu-transparent') || hideMenu ? 0 : UNCODE.menuHeight; 20734 var bodyBorder = UNCODE.bodyBorder; 20735 var adminBarHeight = UNCODE.adminBarHeight; 20736 20737 displayWarnings(); 20738 20739 //fixing bug in iScroll with links: https://github.com/cubiq/iscroll/issues/783 20740 iscrollOptions.click = isTouch; // see #2035 20741 20742 //extending iScroll options with the user custom ones 20743 iscrollOptions = $.extend(iscrollOptions, options.scrollOverflowOptions); 20744 20745 //easeInOutCubic animation included in the plugin 20746 $.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;}}); 20747 20748 /** 20749 * Sets the autoScroll option. 20750 * It changes the scroll bar visibility and the history of the site as a result. 20751 */ 20752 function setAutoScrolling(value, type){ 20753 //removing the transformation 20754 if(!value){ 20755 silentScroll(0); 20756 } 20757 20758 setVariableState('autoScrolling', value, type); 20759 20760 var element = $(SECTION_ACTIVE_SEL); 20761 20762 if(options.autoScrolling && !options.scrollBar){ 20763 $htmlBody.css({ 20764 'overflow' : 'hidden !important', 20765 'height' : '100%' 20766 }); 20767 20768 //Uncode addition 20769 //setRecordHistory(originals.recordHistory, 'internal'); 20770 20771 //for IE touch devices 20772 container.css({ 20773 '-ms-touch-action': 'none', 20774 'touch-action': 'none' 20775 }); 20776 20777 if(element.length){ 20778 //moving the container up 20779 silentScroll(element.position().top); 20780 } 20781 20782 }else{ 20783 $htmlBody.css({ 20784 'overflow' : 'visible !important', 20785 'height' : 'initial' 20786 }); 20787 20788 //Uncode addition 20789 //setRecordHistory(false, 'internal'); 20790 20791 //for IE touch devices 20792 container.css({ 20793 '-ms-touch-action': '', 20794 'touch-action': '' 20795 }); 20796 20797 //scrolling the page to the section with no animation 20798 if (element.length) { 20799 $htmlBody.scrollTop(element.position().top); 20800 } 20801 } 20802 } 20803 20804 /** 20805 * Defines wheter to record the history for each hash change in the URL. 20806 */ 20807 function setRecordHistory(value, type){ 20808 setVariableState('recordHistory', value, type); 20809 } 20810 20811 /** 20812 * Defines the scrolling speed 20813 */ 20814 function setScrollingSpeed(value, type){ 20815 setVariableState('scrollingSpeed', value, type); 20816 } 20817 20818 /** 20819 * Sets fitToSection 20820 */ 20821 function setFitToSection(value, type){ 20822 setVariableState('fitToSection', value, type); 20823 } 20824 20825 /** 20826 * Sets lockAnchors 20827 */ 20828 function setLockAnchors(value){ 20829 options.lockAnchors = value; 20830 } 20831 20832 /** 20833 * Adds or remove the possiblity of scrolling through sections by using the mouse wheel or the trackpad. 20834 */ 20835 function setMouseWheelScrolling(value){ 20836 if(value){ 20837 addMouseWheelHandler(); 20838 addMiddleWheelHandler(); 20839 }else{ 20840 removeMouseWheelHandler(); 20841 removeMiddleWheelHandler(); 20842 } 20843 } 20844 20845 /** 20846 * Adds or remove the possibility of scrolling through sections by using the mouse wheel/trackpad or touch gestures. 20847 * Optionally a second parameter can be used to specify the direction for which the action will be applied. 20848 * 20849 * @param directions string containing the direction or directions separated by comma. 20850 */ 20851 function setAllowScrolling(value, directions){ 20852 if(typeof directions !== 'undefined'){ 20853 directions = directions.replace(/ /g,'').split(','); 20854 20855 $.each(directions, function (index, direction){ 20856 setIsScrollAllowed(value, direction, 'm'); 20857 }); 20858 } 20859 else if(value){ 20860 setMouseWheelScrolling(true); 20861 addTouchHandler(); 20862 }else{ 20863 setMouseWheelScrolling(false); 20864 removeTouchHandler(); 20865 } 20866 } 20867 20868 /** 20869 * Adds or remove the possibility of scrolling through sections by using the keyboard arrow keys 20870 */ 20871 function setKeyboardScrolling(value, directions){ 20872 if(typeof directions !== 'undefined'){ 20873 directions = directions.replace(/ /g,'').split(','); 20874 20875 $.each(directions, function (index, direction){ 20876 setIsScrollAllowed(value, direction, 'k'); 20877 }); 20878 }else{ 20879 options.keyboardScrolling = value; 20880 } 20881 } 20882 20883 /** 20884 * Moves the page up one section. 20885 */ 20886 function moveSectionUp(){ 20887 var prev = $(SECTION_ACTIVE_SEL).prev(SECTION_SEL); 20888 20889 //looping to the bottom if there's no more sections above 20890 if (!prev.length && (options.loopTop || options.continuousVertical)) {
20891 prev = $(SECTION_SEL).last(); 20892 } 20893 20894 if (prev.length) { 20895 scrollPage(prev, null, true); 20896 } 20897 } 20898 20899 /** 20900 * Moves the page down one section. 20901 */ 20902 function moveSectionDown(){ 20903 var next = $(SECTION_ACTIVE_SEL).next(SECTION_SEL); 20904 20905 //looping to the top if there's no more sections below 20906 if(!next.length && 20907 (options.loopBottom || options.continuousVertical)){ 20908 next = $(SECTION_SEL).first(); 20909 } 20910 20911 if(next.length){ 20912 scrollPage(next, null, false); 20913 } 20914 } 20915 20916 /** 20917 * Moves the page to the given section and slide with no animation. 20918 * Anchors or index positions can be used as params. 20919 */ 20920 function silentMoveTo(sectionAnchor, slideAnchor){ 20921 setScrollingSpeed (0, 'internal'); 20922 moveTo(sectionAnchor, slideAnchor); 20923 setScrollingSpeed (originals.scrollingSpeed, 'internal'); 20924 } 20925 20926 /** 20927 * Moves the page to the given section and slide. 20928 * Anchors or index positions can be used as params. 20929 */ 20930 function moveTo(sectionAnchor, slideAnchor){ 20931 var destiny = getSectionByAnchor(sectionAnchor); 20932 20933 if (typeof slideAnchor !== 'undefined'){ 20934 scrollPageAndSlide(sectionAnchor, slideAnchor); 20935 }else if(destiny.length > 0){ 20936 scrollPage(destiny); 20937 } 20938 } 20939 20940 /** 20941 * Slides right the slider of the active section. 20942 * Optional `section` param. 20943 */ 20944 function moveSlideRight(section){ 20945 moveSlide('right', section); 20946 } 20947 20948 /** 20949 * Slides left the slider of the active section. 20950 * Optional `section` param. 20951 */ 20952 function moveSlideLeft(section){ 20953 moveSlide('left', section); 20954 } 20955 20956 /** 20957 * When resizing is finished, we adjust the slides sizes and positions 20958 */ 20959 function reBuild(resizing){ 20960 if(container.hasClass(DESTROYED)){ return; } //nothing to do if the plugin was destroyed 20961 20962 isResizing = true; 20963 20964 windowsHeight = $window.height(); //updating global var 20965 20966 $(SECTION_SEL).each(function(){ 20967 var slidesWrap = $(this).find(SLIDES_WRAPPER_SEL); 20968 var slides = $(this).find(SLIDE_SEL); 20969 20970 //adjusting the height of the table-cell for IE and Firefox 20971 if(options.verticalCentered){ 20972 $(this).find(TABLE_CELL_SEL).css('height', getTableHeight($(this)) + 'px'); 20973 } 20974 20975 $(this).css('height', windowsHeight + 'px'); 20976 20977 //resizing the scrolling divs 20978 if(options.scrollOverflow){ 20979 if(slides.length){ 20980 slides.each(function(){ 20981 createScrollBar($(this)); 20982 }); 20983 }else{ 20984 createScrollBar($(this)); 20985 } 20986 } 20987 20988 //adjusting the position fo the FULL WIDTH slides... 20989 if (slides.length > 1) { 20990 landscapeScroll(slidesWrap, slidesWrap.find(SLIDE_ACTIVE_SEL)); 20991 } 20992 }); 20993 20994 var activeSection = $(SECTION_ACTIVE_SEL); 20995 var sectionIndex = activeSection.index(SECTION_SEL); 20996 20997 //isn't it the first section? 20998 if(sectionIndex){ 20999 //adjusting the position for the current section 21000 silentMoveTo(sectionIndex + 1); 21001 } 21002 21003 isResizing = false; 21004 $.isFunction( options.afterResize ) && resizing && options.afterResize.call(container); 21005 $.isFunction( options.afterReBuild ) && !resizing && options.afterReBuild.call(container); 21006 } 21007 21008 /** 21009 * Turns fullPage.js to normal scrolling mode when the viewport `width` or `height` 21010 * are smaller than the set limit values. 21011 */ 21012 function setResponsive(active){ 21013 var isResponsive = $body.hasClass(RESPONSIVE); 21014 21015 if(active){ 21016 if(!isResponsive){ 21017 setAutoScrolling(false, 'internal'); 21018 setFitToSection(false, 'internal'); 21019 $(SECTION_NAV_SEL).hide(); 21020 $body.addClass(RESPONSIVE); 21021 $.isFunction( options.afterResponsive ) && options.afterResponsive.call( container, active); 21022 } 21023 } 21024 else if(isResponsive){ 21025 setAutoScrolling(originals.autoScrolling, 'internal'); 21026 setFitToSection(originals.autoScrolling, 'internal'); 21027 $(SECTION_NAV_SEL).show(); 21028 $body.removeClass(RESPONSIVE); 21029 $.isFunction( options.afterResponsive ) && options.afterResponsive.call( container, active); 21030 } 21031 } 21032 21033 if($(this).length){ 21034 //public functions 21035 FP.setAutoScrolling = setAutoScrolling; 21036 FP.setRecordHistory = setRecordHistory; 21037 FP.setScrollingSpeed = setScrollingSpeed; 21038 FP.setFitToSection = setFitToSection; 21039 FP.setLockAnchors = setLockAnchors; 21040 FP.setMouseWheelScrolling = setMouseWheelScrolling; 21041 FP.setAllowScrolling = setAllowScrolling; 21042 FP.setKeyboardScrolling = setKeyboardScrolling; 21043 FP.moveSectionUp = moveSectionUp; 21044 FP.moveSectionDown = moveSectionDown; 21045 FP.silentMoveTo = silentMoveTo; 21046 FP.moveTo = moveTo; 21047 FP.moveSlideRight = moveSlideRight; 21048 FP.moveSlideLeft = moveSlideLeft; 21049 FP.fitToSection = fitToSection; 21050 FP.reBuild = reBuild; 21051 FP.setResponsive = setResponsive; 21052 FP.destroy = destroy; 21053 21054 init(); 21055 21056 bindEvents(); 21057 } 21058
21059 function init(){ 21060 //if css3 is not supported, it will use jQuery animations 21061 if(options.css3){ 21062 options.css3 = support3d(); 21063 } 21064 21065 options.scrollBar = options.scrollBar || options.hybrid; 21066 21067 setOptionsFromDOM(); 21068 prepareDom(); 21069 setAllowScrolling(true); 21070 setAutoScrolling(options.autoScrolling, 'internal'); 21071 responsive(); 21072 21073 //setting the class for the body element 21074 setBodyClass(); 21075 21076 //Uncode addition 21077 // if(document.readyState === 'complete'){ 21078 // scrollToAnchor(); 21079 // } 21080 // $window.on('load', scrollToAnchor); 21081 } 21082 21083 function bindEvents(){ 21084 $window 21085 //when scrolling... 21086 //.on('scroll', scrollHandler) 21087 21088 //detecting any change on the URL to scroll to the given anchor link 21089 //(a way to detect back history button as we play with the hashes on the URL) 21090 .on('hashchange', hashChangeHandler) 21091 21092 //when opening a new tab (ctrl + t), `control` won't be pressed when coming back. 21093 .blur(blurHandler) 21094 21095 //when resizing the site, we adjust the heights of the sections, slimScroll... 21096 .resize(resizeHandler); 21097 21098 $document 21099 //Sliding with arrow keys, both, vertical and horizontal 21100 .keydown(keydownHandler) 21101 21102 //to prevent scrolling while zooming 21103 .keyup(keyUpHandler) 21104 21105 //Scrolls to the section when clicking the navigation bullet 21106 .on('click touchstart', SECTION_NAV_SEL + ' a', sectionBulletHandler) 21107 21108 //Scrolls the slider to the given slide destination for the given section 21109 .on('click touchstart', SLIDES_NAV_LINK_SEL, slideBulletHandler) 21110 21111 .on('click', SECTION_NAV_TOOLTIP_SEL, tooltipTextHandler); 21112 21113 //Scrolling horizontally when clicking on the slider controls. 21114 $(SECTION_SEL).on('click touchstart', SLIDES_ARROW_SEL, slideArrowHandler); 21115 21116 /** 21117 * Applying normalScroll elements. 21118 * Ignoring the scrolls over the specified selectors. 21119 */ 21120 if(options.normalScrollElements){ 21121 $document.on('mouseenter', options.normalScrollElements, function () { 21122 setMouseWheelScrolling(false); 21123 }); 21124 21125 $document.on('mouseleave', options.normalScrollElements, function(){ 21126 setMouseWheelScrolling(true); 21127 }); 21128 } 21129 } 21130 21131 /** 21132 * Setting options from DOM elements if they are not provided. 21133 */ 21134 function setOptionsFromDOM(){ 21135 var sections = container.find(options.sectionSelector); 21136 21137 //no anchors option? Checking for them in the DOM attributes 21138 if(!options.anchors.length){ 21139 options.anchors = sections.filter('[data-anchor]').map(function(){ 21140 return $(this).data('anchor').toString(); 21141 }).get(); 21142 } 21143 21144 //no tooltips option? Checking for them in the DOM attributes 21145 if(!options.navigationTooltips.length){ 21146 options.navigationTooltips = sections.filter('[data-tooltip]').map(function(){ 21147 return $(this).data('tooltip').toString(); 21148 }).get(); 21149 } 21150 } 21151 21152 /** 21153 * Works over the DOM structure to set it up for the current fullpage options. 21154 */ 21155 function prepareDom(){ 21156 container.css({ 21157 'height': '100%', 21158 'position': 'relative' 21159 }); 21160 21161 //adding a class to recognize the container internally in the code 21162 container.addClass(WRAPPER); 21163 $('html').addClass(ENABLED); 21164 21165 windowsHeight = $window.height(); 21166 21167 container.removeClass(DESTROYED); //in case it was destroyed before initializing it again 21168 21169 addInternalSelectors(); 21170 21171 //styling the sections / slides / menu 21172 $(SECTION_SEL).each(function(index){ 21173 var section = $(this); 21174 var slides = section.find(SLIDE_SEL); 21175 var numSlides = slides.length; 21176 21177 styleSection(section, index); 21178 styleMenu(section, index); 21179 21180 // if there's any slide 21181 if (numSlides > 0) { 21182 styleSlides(section, slides, numSlides); 21183 }else{ 21184 if(options.verticalCentered){ 21185 addTableClass(section); 21186 } 21187 } 21188 }); 21189 21190 //fixed elements need to be moved out of the plugin container due to problems with CSS3. 21191 if(options.fixedElements && options.css3){ 21192 $(options.fixedElements).appendTo($body); 21193 } 21194 21195 //vertical centered of the navigation + active bullet 21196 if(options.navigation){ 21197 addVerticalNavigation(); 21198 } 21199 21200 enableYoutubeAPI(); 21201 21202 if(options.scrollOverflow){ 21203 if(document.readyState === 'complete'){ 21204 createScrollBarHandler(); 21205 } 21206 //after DOM and images are loaded 21207 $window.on('load', createScrollBarHandler); 21208 }else{ 21209 afterRenderActions(); 21210 } 21211 } 21212 21213 /** 21214 * Styles the horizontal slides for a section. 21215 */ 21216 function styleSlides(section, slides, numSlides){ 21217 var sliderWidth = numSlides * 100; 21218 var slideWidth = 100 / numSlides; 21219 21220 slides.wrapAll('<div class="' + SLIDES_CONTAINER + '" />'); 21221 slides.parent().wrap('<div class="' + SLIDES_WRAPPER + '" />'); 21222 21223 section.find(SLIDES_CONTAINER_SEL).css('width', sliderWidth + '%'); 21224 21225 if(numSlides > 1){ 21226 if(options.controlArrows){ 21227 createSlideArrows(section); 21228 } 21229 21230 if(options.slidesNavigation){ 21231 addSlidesNavigation(section, numSlides); 21232 } 21233 } 21234 21235 slides.each(function(index) { 21236 $(this).css('width', slideWidth + '%'); 21237 21238 if(options.verticalCentered){ 21239 addTableClass($(this)); 21240 } 21241 }); 21242 21243 var startingSlide = section.find(SLIDE_ACTIVE_SEL); 21244 21245 //if the slide won't be an starting point, the default will be the first one 21246 //the active section isn't the first one? Is not the first slide of the first section? Then we load that section/sl
21246ide by default. 21247 if( startingSlide.length && ($(SECTION_ACTIVE_SEL).index(SECTION_SEL) !== 0 || ($(SECTION_ACTIVE_SEL).index(SECTION_SEL) === 0 && startingSlide.index() !== 0))){ 21248 silentLandscapeScroll(startingSlide, 'internal'); 21249 }else{ 21250 slides.eq(0).addClass(ACTIVE); 21251 } 21252 } 21253 21254 /** 21255 * Styling vertical sections 21256 */ 21257 function styleSection(section, index){ 21258 //if no active section is defined, the 1st one will be the default one 21259 if(!index && $(SECTION_ACTIVE_SEL).length === 0) { 21260 section.addClass(ACTIVE); 21261 } 21262 startingSection = $(SECTION_ACTIVE_SEL); 21263 21264 section.css('height', windowsHeight + 'px'); 21265 21266 if(options.paddingTop){ 21267 section.css('padding-top', options.paddingTop); 21268 } 21269 21270 if(options.paddingBottom){ 21271 section.css('padding-bottom', options.paddingBottom); 21272 } 21273 21274 if (typeof options.sectionsColor[index] !== 'undefined') { 21275 section.css('background-color', options.sectionsColor[index]); 21276 } 21277 21278 if (typeof options.anchors[index] !== 'undefined') { 21279 section.attr('data-anchor', options.anchors[index]); 21280 } 21281 } 21282 21283 /** 21284 * Sets the data-anchor attributes to the menu elements and activates the current one. 21285 */ 21286 function styleMenu(section, index){ 21287 if (typeof options.anchors[index] !== 'undefined') { 21288 //activating the menu / nav element on load 21289 if(section.hasClass(ACTIVE)){ 21290 activateMenuAndNav(options.anchors[index], index); 21291 } 21292 } 21293 21294 //moving the menu outside the main container if it is inside (avoid problems with fixed positions when using CSS3 tranforms) 21295 if(options.menu && options.css3 && $(options.menu).closest(WRAPPER_SEL).length){ 21296 $(options.menu).appendTo($body); 21297 } 21298 } 21299 21300 /** 21301 * Adds internal classes to be able to provide customizable selectors 21302 * keeping the link with the style sheet. 21303 */ 21304 function addInternalSelectors(){ 21305 container.find(options.sectionSelector).addClass(SECTION); 21306 container.find(options.slideSelector).addClass(SLIDE); 21307 } 21308 21309 /** 21310 * Creates the control arrows for the given section 21311 */ 21312 function createSlideArrows(section){ 21313 section.find(SLIDES_WRAPPER_SEL).after('<div class="' + SLIDES_ARROW_PREV + '"></div><div class="' + SLIDES_ARROW_NEXT + '"></div>'); 21314 21315 if(options.controlArrowColor!='#fff'){ 21316 section.find(SLIDES_ARROW_NEXT_SEL).css('border-color', 'transparent transparent transparent '+options.controlArrowColor); 21317 section.find(SLIDES_ARROW_PREV_SEL).css('border-color', 'transparent '+ options.controlArrowColor + ' transparent transparent'); 21318 } 21319 21320 if(!options.loopHorizontal){ 21321 section.find(SLIDES_ARROW_PREV_SEL).hide(); 21322 } 21323 } 21324 21325 /** 21326 * Creates a vertical navigation bar. 21327 */ 21328 function addVerticalNavigation(){ 21329 $body.append('<div id="' + SECTION_NAV + '"><ul></ul></div>'); 21330 var nav = $(SECTION_NAV_SEL); 21331 21332 nav.addClass(function() { 21333 return options.showActiveTooltip ? SHOW_ACTIVE_TOOLTIP + ' ' + options.navigationPosition : options.navigationPosition; 21334 }); 21335 21336 for (var i = 0; i < $(SECTION_SEL).length; i++) { 21337 var link = ''; 21338 if (options.anchors.length) { 21339 link = options.anchors[i]; 21340 } 21341 21342 var li = '<li><a href="#' + link + '"><span></span></a>'; 21343 21344 // Only add tooltip if needed (defined by user) 21345 var tooltip = options.navigationTooltips[i]; 21346 21347 if (typeof tooltip !== 'undefined' && tooltip !== '') { 21348 li += '<div class="' + SECTION_NAV_TOOLTIP + ' ' + options.navigationPosition + '">' + tooltip + '</div>'; 21349 } 21350 21351 li += '</li>'; 21352 21353 nav.find('ul').append(li); 21354 } 21355 21356 //centering it vertically 21357 $(SECTION_NAV_SEL).css('margin-top', '-' + ($(SECTION_NAV_SEL).height()/2) + 'px'); 21358 21359 //activating the current active section 21360 $(SECTION_NAV_SEL).find('li').eq($(SECTION_ACTIVE_SEL).index(SECTION_SEL)).find('a').addClass(ACTIVE); 21361 } 21362 21363 /** 21364 * Creates the slim scroll scrollbar for the sections and slides inside them. 21365 */ 21366 function createScrollBarHandler(){ 21367 $(SECTION_SEL).each(function(){ 21368 var slides = $(this).find(SLIDE_SEL); 21369 21370 if(slides.length){ 21371 slides.each(function(){ 21372 createScrollBar($(this)); 21373 }); 21374 }else{ 21375 createScrollBar($(this)); 21376 } 21377 21378 }); 21379 afterRenderActions(); 21380 } 21381 21382 /*
21383 * Enables the Youtube videos API so we can control their flow if necessary. 21384 */ 21385 function enableYoutubeAPI(){ 21386 container.find('iframe[src*="youtube.com/embed/"]').each(function(){ 21387 addURLParam($(this), 'enablejsapi=1'); 21388 }); 21389 } 21390 21391 /** 21392 * Adds a new parameter and its value to the `src` of a given element 21393 */ 21394 function addURLParam(element, newParam){ 21395 var originalSrc = element.attr('src'); 21396 element.attr('src', originalSrc + getUrlParamSign(originalSrc) + newParam); 21397 } 21398 21399 /* 21400 * Returns the prefix sign to use for a new parameter in an existen URL. 21401 * 21402 * @return {String} ? | & 21403 */ 21404 function getUrlParamSign(url){ 21405 return ( !/\?/.test( url ) ) ? '?' : '&'; 21406 } 21407 21408 /** 21409 * Actions and callbacks to fire afterRender 21410 */ 21411 function afterRenderActions(){ 21412 var section = $(SECTION_ACTIVE_SEL); 21413 21414 section.addClass(COMPLETELY); 21415 21416 if(options.scrollOverflowHandler.afterRender){ 21417 options.scrollOverflowHandler.afterRender(section); 21418 } 21419 lazyLoad(section); 21420 playMedia(section); 21421 options.scrollOverflowHandler.afterLoad(); 21422 21423 if(isDestinyTheStartingSection()){ 21424 $.isFunction( options.afterLoad ) && options.afterLoad.call(section, section.data('anchor'), (section.index(SECTION_SEL) + 1)); 21425 } 21426 21427 $.isFunction( options.afterRender ) && options.afterRender.call(container); 21428 } 21429 21430 /** 21431 * Determines if the URL anchor destiny is the starting section (the one using 'active' class before initialization) 21432 */ 21433 function isDestinyTheStartingSection(){ 21434 var anchors = window.location.hash.replace('#', '').split('/'); 21435 var destinationSection = getSectionByAnchor(decodeURIComponent(anchors[0])); 21436 21437 return !destinationSection.length || destinationSection.length && destinationSection.index() === startingSection.index(); 21438 } 21439 21440 21441 var isScrolling = false; 21442 var lastScroll = 0; 21443 21444 //when scrolling... 21445 function scrollHandler(){ 21446 var currentSection; 21447 21448 if(!options.autoScrolling || options.scrollBar){ 21449 var currentScroll = $window.scrollTop(); 21450 var scrollDirection = getScrollDirection(currentScroll); 21451 var visibleSectionIndex = 0; 21452 var screen_mid = currentScroll + ($window.height() / 2.0); 21453 var isAtBottom = $body.height() - $window.height() === currentScroll; 21454 var sections = document.querySelectorAll(SECTION_SEL); 21455 21456 //when using `auto-height` for a small last section it won't be centered in the viewport 21457 if(isAtBottom){ 21458 visibleSectionIndex = sections.length - 1; 21459 } 21460 //is at top? when using `auto-height` for a small first section it won't be centered in the viewport 21461 else if(!currentScroll){ 21462 visibleSectionIndex = 0; 21463 } 21464 21465 //taking the section which is showing more content in the viewport 21466 else{ 21467 for (var i = 0; i < sections.length; ++i) { 21468 var section = sections[i]; 21469 21470 // Pick the the last section which passes the middle line of the screen. 21471 if (section.offsetTop <= screen_mid) 21472 { 21473 visibleSectionIndex = i; 21474 } 21475 } 21476 } 21477 21478 if(isCompletelyInViewPort(scrollDirection)){ 21479 if(!$(SECTION_ACTIVE_SEL).hasClass(COMPLETELY)){ 21480 $(SECTION_ACTIVE_SEL).addClass(COMPLETELY).siblings().removeClass(COMPLETELY); 21481 } 21482 } 21483 21484 //geting the last one, the current one on the screen 21485 currentSection = $(sections).eq(visibleSectionIndex); 21486 21487 //setting the visible section as active when manually scrolling 21488 //executing only once the first time we reach the section 21489 if(!currentSection.hasClass(ACTIVE)){ 21490 isScrolling = true; 21491 var leavingSection = $(SECTION_ACTIVE_SEL); 21492 var leavingSectionIndex = leavingSection.index(SECTION_SEL) + 1; 21493 var yMovement = getYmovement(currentSection); 21494 var anchorLink = currentSection.data('anchor'); 21495 var sectionIndex = currentSection.index(SECTION_SEL) + 1; 21496 var activeSlide = currentSection.find(SLIDE_ACTIVE_SEL); 21497 var slideIndex; 21498 var slideAnchorLink; 21499 21500 if(activeSlide.length){ 21501 slideAnchorLink = activeSlide.data('anchor'); 21502 slideIndex = activeSlide.index(); 21503 } 21504 21505 if(canScroll){ 21506 currentSection.addClass(ACTIVE).siblings().removeClass(ACTIVE); 21507 21508 $.isFunction( options.onLeave ) && options.onLeave.call( leavingSection, leavingSectionIndex, sectionIndex, yMovement); 21509 $.isFunction( options.afterLoad ) && options.afterLoad.call( currentSection, anchorLink, sectionIndex); 21510 21511 stopMedia(leavingSection); 21512 lazyLoad(currentSection); 21513 playMedia(currentSection); 21514 21515 activateMenuAndNav(anchorLink, sectionIndex - 1); 21516 21517 if(options.anchors.length){ 21518 //needed to enter in hashChange event when using the menu with anchor links 21519 lastScrolledDestiny = anchorLink; 21520 } 21521 setState(slideIndex, slideAnchorLink, anchorLink, sectionIndex); 21522 } 21523 21524 //small timeout in order to avoid entering in hashChange event when scrolling is not finished yet 21525 clearTimeout(scrollId); 21526 scrollId = setTimeout(function(){ 21527 isScrolling = false;
21528 }, 100); 21529 } 21530 21531 if(options.fitToSection){ 21532 //for the auto adjust of the viewport to fit a whole section 21533 clearTimeout(scrollId2); 21534 21535 scrollId2 = setTimeout(function(){ 21536 //checking it again in case it changed during the delay 21537 if(options.fitToSection){ 21538 fitToSection(); 21539 } 21540 }, options.fitToSectionDelay); 21541 } 21542 } 21543 } 21544 21545 /** 21546 * Fits the site to the nearest active section 21547 */ 21548 function fitToSection(){ 21549 //checking fitToSection again in case it was set to false before the timeout delay 21550 if(canScroll){ 21551 //allows to scroll to an active section and 21552 //if the section is already active, we prevent firing callbacks 21553 isResizing = true; 21554 21555 scrollPage($(SECTION_ACTIVE_SEL)); 21556 isResizing = false; 21557 } 21558 } 21559 21560 /** 21561 * Determines whether the active section has seen in its whole or not. 21562 */ 21563 function isCompletelyInViewPort(movement){ 21564 var top = $(SECTION_ACTIVE_SEL).position().top; 21565 var bottom = top + $window.height(); 21566 21567 if(movement == 'up'){ 21568 return bottom >= ($window.scrollTop() + $window.height()); 21569 } 21570 return top <= $window.scrollTop(); 21571 } 21572 21573 /** 21574 * Gets the directon of the the scrolling fired by the scroll event. 21575 */ 21576 function getScrollDirection(currentScroll){ 21577 var direction = currentScroll > lastScroll ? 'down' : 'up'; 21578 21579 lastScroll = currentScroll; 21580 21581 //needed for auto-height sections to determine if we want to scroll to the top or bottom of the destination 21582 previousDestTop = currentScroll; 21583 21584 return direction; 21585 } 21586 21587 /** 21588 * Determines the way of scrolling up or down: 21589 * by 'automatically' scrolling a section or by using the default and normal scrolling. 21590 */ 21591 function scrolling(type, scrollable){ 21592 if (!isScrollAllowed.m[type]){ 21593 return; 21594 } 21595 var check = (type === 'down') ? 'bottom' : 'top'; 21596 var scrollSection = (type === 'down') ? moveSectionDown : moveSectionUp; 21597 21598 if(scrollable.length > 0 ){ 21599 //is the scrollbar at the start/end of the scroll? 21600 if(options.scrollOverflowHandler.isScrolled(check, scrollable)){ 21601 scrollSection(); 21602 }else{ 21603 return true; 21604 } 21605 }else{ 21606 // moved up/down 21607 scrollSection(); 21608 } 21609 } 21610 21611 /* 21612 * Preventing bouncing in iOS #2285 21613 */ 21614 function preventBouncing(event){ 21615 var e = event.originalEvent; 21616 if(!checkParentForNormalScrollElement(event.target) && options.autoScrolling && isReallyTouch(e) && isScrollAllowed.m.up){ 21617 //preventing the easing on iOS devices 21618 event.preventDefault(); 21619 } 21620 } 21621 21622 var touchStartY = 0; 21623 var touchStartX = 0; 21624 var touchEndY = 0; 21625 var touchEndX = 0; 21626 21627 /* Detecting touch events 21628 21629 * As we are changing the top property of the page on scrolling, we can not use the traditional way to detect it. 21630 * This way, the touchstart and the touch moves shows an small difference between them which is the 21631 * used one to determine the direction. 21632 */ 21633 function touchMoveHandler(event){ 21634 var e = event.originalEvent; 21635 var activeSection = $(e.target).closest(SECTION_SEL); 21636 21637 // additional: if one of the normalScrollElements isn't within options.normalScrollElementTouchThreshold hops up the DOM chain 21638 if (!checkParentForNormalScrollElement(event.target) && isReallyTouch(e) ) { 21639 21640 if(options.autoScrolling){ 21641 //preventing the easing on iOS devices 21642 event.preventDefault(); 21643 } 21644 21645 var scrollable = options.scrollOverflowHandler.scrollable(activeSection); 21646 var touchEvents = getEventsPage(e); 21647 21648 touchEndY = touchEvents.y; 21649 touchEndX = touchEvents.x; 21650 21651 //if movement in the X axys is greater than in the Y and the currect section has slides... 21652 if (activeSection.find(SLIDES_WRAPPER_SEL).length && Math.abs(touchStartX - touchEndX) > (Math.abs(touchStartY - touchEndY))) { 21653 21654 //is the movement greater than the minimum resistance to scroll? 21655 if (!slideMoving && Math.abs(touchStartX - touchEndX) > ($window.outerWidth() / 100 * options.touchSensitivity)) { 21656 if (touchStartX > touchEndX) { 21657 if(isScrollAllowed.m.right){ 21658 moveSlideRight(activeSection); //next 21659 } 21660 } else { 21661 if(isScrollAllowed.m.left){ 21662 moveSlideLeft(activeSection); //prev 21663 } 21664 } 21665 } 21666 } 21667 21668 //vertical scrolling (only when autoScrolling is enabled) 21669 else if(options.autoScrolling && canScroll){ 21670 21671 //is the movement greater than the minimum resistance to scroll? 21672 if (Math.abs(touchStartY - touchEndY) > ($window.height() / 100 * options.touchSensitivity)) { 21673 if (touchStartY > touchEndY) { 21674 scrolling('down', scrollable); 21675 } else if (touchEndY > touchStartY) { 21676 scrolling('up', scrollable); 21677 } 21678 } 21679 } 21680 } 21681 } 21682 21683 /** 21684 * recursive function to loop up the parent nodes to check if one of them exists in options.normalScrollElements 21685 * Currently works well for iOS - Android might need some testing 21686 * @param {Element} el target element / jquery selector (in subsequent nodes) 21687 * @param {int} hop current hop compared to options.normalScrollElementTouchThreshold 21688 * @return {boolean} true if there is a match to options.normalScrollElements 21689 */ 21690 function checkParentForNormalScrollElement (el, hop) { 21691 hop = hop || 0; 21692 var parent = $(el).parent(); 21693 21694 if (hop < options.normalScrollElementTouchThreshold && 21695 parent.is(options.normalScrollElements) ) { 21696 return true; 21697 } else if (hop == options.normalScrollElementTouchThreshold) { 21698 return false;
21699 } else { 21700 return checkParentForNormalScrollElement(parent, ++hop); 21701 } 21702 } 21703 21704 /** 21705 * As IE >= 10 fires both touch and mouse events when using a mouse in a touchscreen 21706 * this way we make sure that is really a touch event what IE is detecting. 21707 */ 21708 function isReallyTouch(e){ 21709 //if is not IE || IE is detecting `touch` or `pen` 21710 return typeof e.pointerType === 'undefined' || e.pointerType != 'mouse'; 21711 } 21712 21713 /** 21714 * Handler for the touch start event. 21715 */ 21716 function touchStartHandler(event){ 21717 var e = event.originalEvent; 21718 21719 //stopping the auto scroll to adjust to a section 21720 if(options.fitToSection){ 21721 $htmlBody.stop(); 21722 } 21723 21724 if(isReallyTouch(e)){ 21725 var touchEvents = getEventsPage(e); 21726 touchStartY = touchEvents.y; 21727 touchStartX = touchEvents.x; 21728 } 21729 } 21730 21731 /** 21732 * Gets the average of the last `number` elements of the given array. 21733 */ 21734 function getAverage(elements, number){ 21735 var sum = 0; 21736 21737 //taking `number` elements from the end to make the average, if there are not enought, 1 21738 var lastElements = elements.slice(Math.max(elements.length - number, 1)); 21739 21740 for(var i = 0; i < lastElements.length; i++){ 21741 sum = sum + lastElements[i]; 21742 } 21743 21744 return Math.ceil(sum/number); 21745 } 21746 21747 /** 21748 * Detecting mousewheel scrolling 21749 * 21750 * http://blogs.sitepointstatic.com/examples/tech/mouse-wheel/index.html 21751 * http://www.sitepoint.com/html5-javascript-mouse-wheel/ 21752 */ 21753 var prevTime = new Date().getTime(); 21754 21755 function MouseWheelHandler(e) { 21756 var curTime = new Date().getTime(); 21757 var isNormalScroll = $(COMPLETELY_SEL).hasClass(NORMAL_SCROLL); 21758 21759 //autoscrolling and not zooming? 21760 if(options.autoScrolling && !controlPressed && !isNormalScroll){ 21761 // cross-browser wheel delta 21762 e = e || window.event; 21763 var value = e.wheelDelta || -e.deltaY || -e.detail; 21764 var delta = Math.max(-1, Math.min(1, value)); 21765 21766 var horizontalDetection = typeof e.wheelDeltaX !== 'undefined' || typeof e.deltaX !== 'undefined'; 21767 var isScrollingVertically = (Math.abs(e.wheelDeltaX) < Math.abs(e.wheelDelta)) || (Math.abs(e.deltaX ) < Math.abs(e.deltaY) || !horizontalDetection); 21768 21769 //Limiting the array to 150 (lets not waste memory!) 21770 if(scrollings.length > 149){ 21771 scrollings.shift(); 21772 } 21773 21774 //keeping record of the previous scrollings 21775 scrollings.push(Math.abs(value)); 21776 21777 //preventing to scroll the site on mouse wheel when scrollbar is present 21778 if(options.scrollBar){ 21779 e.preventDefault ? e.preventDefault() : e.returnValue = false; 21780 } 21781 21782 var activeSection = $(SECTION_ACTIVE_SEL); 21783 var scrollable = options.scrollOverflowHandler.scrollable(activeSection); 21784 21785 //time difference between the last scroll and the current one 21786 var timeDiff = curTime-prevTime; 21787 prevTime = curTime; 21788 21789 //haven't they scrolled in a while? 21790 //(enough to be consider a different scrolling action to scroll another section) 21791 if(timeDiff > 200){ 21792 //emptying the array, we dont care about old scrollings for our averages 21793 scrollings = []; 21794 } 21795 21796 if(canScroll){ 21797 var averageEnd = getAverage(scrollings, 10); 21798 var averageMiddle = getAverage(scrollings, 70); 21799 var isAccelerating = averageEnd >= averageMiddle; 21800 21801 //to avoid double swipes... 21802 if(isAccelerating && isScrollingVertically){ 21803 //scrolling down? 21804 if (delta < 0) { 21805 scrolling('down', scrollable); 21806 21807 //scrolling up? 21808 }else { 21809 scrolling('up', scrollable); 21810 } 21811 } 21812 } 21813 21814 return false;
21815 } 21816 21817 if(options.fitToSection){ 21818 //stopping the auto scroll to adjust to a section 21819 $htmlBody.stop(); 21820 } 21821 } 21822 21823 /** 21824 * Slides a slider to the given direction. 21825 * Optional `section` param. 21826 */ 21827 function moveSlide(direction, section){ 21828 var activeSection = typeof section === 'undefined' ? $(SECTION_ACTIVE_SEL) : section; 21829 var slides = activeSection.find(SLIDES_WRAPPER_SEL); 21830 var numSlides = slides.find(SLIDE_SEL).length; 21831 21832 // more than one slide needed and nothing should be sliding 21833 if (!slides.length || slideMoving || numSlides < 2) { 21834 return; 21835 } 21836 21837 var currentSlide = slides.find(SLIDE_ACTIVE_SEL); 21838 var destiny = null; 21839 21840 if(direction === 'left'){ 21841 destiny = currentSlide.prev(SLIDE_SEL); 21842 }else{ 21843 destiny = currentSlide.next(SLIDE_SEL); 21844 } 21845 21846 //isn't there a next slide in the secuence? 21847 if(!destiny.length){ 21848 //respect loopHorizontal settin 21849 if (!options.loopHorizontal) return; 21850 21851 if(direction === 'left'){ 21852 destiny = currentSlide.siblings(':last'); 21853 }else{ 21854 destiny = currentSlide.siblings(':first'); 21855 } 21856 } 21857 21858 slideMoving = true; 21859 21860 landscapeScroll(slides, destiny, direction); 21861 } 21862 21863 /** 21864 * Maintains the active slides in the viewport 21865 * (Because the `scroll` animation might get lost with some actions, such as when using continuousVertical) 21866 */ 21867 function keepSlidesPosition(){ 21868 $(SLIDE_ACTIVE_SEL).each(function(){ 21869 silentLandscapeScroll($(this), 'internal'); 21870 }); 21871 } 21872 21873 var previousDestTop = 0; 21874 /** 21875 * Returns the destination Y position based on the scrolling direction and 21876 * the height of the section. 21877 */ 21878 function getDestinationPosition(element){ 21879 var elemPosition = element.position(); 21880 21881 //top of the desination will be at the top of the viewport 21882 var position = elemPosition.top; 21883 var isScrollingDown = elemPosition.top > previousDestTop; 21884 var sectionBottom = position - windowsHeight + element.outerHeight(); 21885 var bigSectionsDestination = options.bigSectionsDestination; 21886 21887 //Uncode addition 21888 var containerH = container.outerHeight(); 21889 var containerPosition = container.offset(); 21890 21891 //########### Commented by Uncode - START ########### 21892 //is the destination element bigger than the viewport? 21893 // if(element.outerHeight() > windowsHeight){ 21894 // //scrolling up? 21895 // if(!isScrollingDown && !bigSectionsDestination || bigSectionsDestination === 'bottom' ){ 21896 // position = sectionBottom; 21897 // } 21898 // } 21899 21900 // //sections equal or smaller than the viewport height && scrolling down? || is resizing and its in the last section 21901 // else if(isScrollingDown || (isResizing && element.is(':last-child')) ){ 21902 // //The bottom of the destination will be at the bottom of the viewport 21903 // position = sectionBottom; 21904 // } 21905 //########### Commented by Uncode - END ########### 21906 21907 //Uncode addition 21908 if ( !$masthead.hasClass('menu-transparent') && $('body').hasClass('uncode-fp-menu-shrink') && !element.is(':first-child') ) 21909 position += 18; 21910 if ( ( containerH + menuHeight + bodyBorder + adminBarHeight - windowsHeight ) < position || ( isResizing && element.is(':last-child') ) ) { 21911 position = sectionBottom + menuHeight + bodyBorder*2 + adminBarHeight; 21912 } 21913 21914 /* 21915 Keeping record of the last scrolled position to determine the scrolling direction. 21916 No conventional methods can be used as the scroll bar might not be present 21917 AND the section might not be active if it is auto-height and didnt reach the middle 21918 of the viewport. 21919 */ 21920 previousDestTop = position; 21921 return position; 21922 } 21923 21924 /** 21925 * Scrolls the site to the given element and scrolls to the slide if a callback is given. 21926 */ 21927 function scrollPage(element, callback, isMovementUp){ 21928 if(typeof element === 'undefined'){ return; } //there's no element to scroll, leaving the function 21929 21930 var dtop = getDestinationPosition(element); 21931 var slideAnchorLink; 21932 var slideIndex; 21933 21934 //local variables 21935 var v = { 21936 element: element, 21937 callback: callback, 21938 isMovementUp: isMovementUp, 21939 dtop: dtop, 21940 yMovement: getYmovement(element), 21941 anchorLink: element.data('anchor'), 21942 sectionIndex: element.index(SECTION_SEL), 21943 activeSlide: element.find(SLIDE_ACTIVE_SEL), 21944 activeSection: $(SECTION_ACTIVE_SEL), 21945 leavingSection: $(SECTION_ACTIVE_SEL).index(SECTION_SEL) + 1, 21946 21947 //caching the value of isResizing at the momment the function is called 21948 //because it will be checked later inside a setTimeout and the value might change 21949 localIsResizing: isResizing 21950 }; 21951 21952 //quiting when destination scroll is the same as the current one 21953 if((v.activeSection.is(element) && !isResizing) || (options.scrollBar && $window.scrollTop() === v.dtop && !element.hasClass(AUTO_HEIGHT) )){ return; } 21954 21955 if(v.activeSlide.length){ 21956 slideAnchorLink = v.activeSlide.data('anchor'); 21957 slideIndex = v.activeSlide.index(); 21958 } 21959 21960 // If continuousVertical && we need to wrap around 21961 if (options.autoScrolling && options.continuousVertical && typeof (v.isMovementUp) !== "undefined" && 21962 ((!v.isMovementUp && v.yMovement == 'up') || // Intending to scroll down but about to go up or 21963 (v.isMovementUp && v.yMovement == 'down'))) { // intending to scroll up but about to go down 21964 21965 v = createInfiniteSections(v); 21966 } 21967 21968 //callback (onLeave) if the site is not just resizing and readjusting the slides 21969 if($.isFunction(options.onLeave) && !v.localIsResizing){ 21970 if(options.onLeave.call(v.activeSection, v.leavingSection, (v.sectionIndex + 1), v.yMovement) === false){ 21971 return; 21972 } 21973 } 21974 21975 //pausing media of the leaving section (if we are not just resizing, as destinatino will be the same one) 21976 if(!v.localIsResizing){ 21977 stopMedia(v.activeSection); 21978 } 21979 21980 options.scrollOverflowHandler.beforeLeave(); 21981 element.addClass(ACTIVE).siblings().removeClass(ACTIVE); 21982 lazyLoad(element); 21983 options.scrollOverflowHandler.onLeave(); 21984 21985 21986 //preventing from activating the MouseWheelHandler event 21987 //more than once if the page is scrolling 21988 canScroll = false;
21989 21990 setState(slideIndex, slideAnchorLink, v.anchorLink, v.sectionIndex); 21991 21992 performMovement(v); 21993 21994 //flag to avoid callingn `scrollPage()` twice in case of using anchor links 21995 lastScrolledDestiny = v.anchorLink; 21996 21997 //avoid firing it twice (as it does also on scroll) 21998 activateMenuAndNav(v.anchorLink, v.sectionIndex); 21999 } 22000 22001 /** 22002 * Performs the vertical movement (by CSS3 or by jQuery) 22003 */ 22004 function performMovement(v){ 22005 // using CSS3 translate functionality 22006 if (options.css3 && options.autoScrolling && !options.scrollBar) { 22007 22008 // The first section can have a negative value in iOS 10. Not quite sure why: -0.0142822265625 22009 // that's why we round it to 0. 22010 var translate3d = 'translate3d(0px, -' + Math.round(v.dtop) + 'px, 0px)'; 22011 transformContainer(translate3d, true); 22012 22013 //even when the scrollingSpeed is 0 there's a little delay, which might cause the 22014 //scrollingSpeed to change in case of using silentMoveTo(); 22015 if(options.scrollingSpeed){ 22016 clearTimeout(afterSectionLoadsId); 22017 afterSectionLoadsId = setTimeout(function () { 22018 afterSectionLoads(v); 22019 }, options.scrollingSpeed); 22020 }else{ 22021 afterSectionLoads(v); 22022 } 22023 } 22024 22025 // using jQuery animate 22026 else{ 22027 var scrollSettings = getScrollSettings(v); 22028 22029 $(scrollSettings.element).animate( 22030 scrollSettings.options, 22031 options.scrollingSpeed, options.easing).promise().done(function () { //only one single callback in case of animating `html, body` 22032 if(options.scrollBar){ 22033 22034 /* Hack! 22035 The timeout prevents setting the most dominant section in the viewport as "active" when the user 22036 scrolled to a smaller section by using the mousewheel (auto scrolling) rather than draging the scroll bar. 22037 22038 When using scrollBar:true It seems like the scroll events still getting propagated even after the scrolling animation has finished. 22039 */ 22040 setTimeout(function(){ 22041 afterSectionLoads(v); 22042 },30); 22043 }else{ 22044 afterSectionLoads(v); 22045 } 22046 }); 22047 } 22048 } 22049 22050 /** 22051 * Gets the scrolling settings depending on the plugin autoScrolling option 22052 */ 22053 function getScrollSettings(v){ 22054 var scroll = {}; 22055 22056 if(options.autoScrolling && !options.scrollBar){ 22057 scroll.options = { 'top': -v.dtop}; 22058 scroll.element = WRAPPER_SEL; 22059 }else{ 22060 scroll.options = { 'scrollTop': v.dtop}; 22061 scroll.element = 'html, body'; 22062 } 22063 22064 return scroll; 22065 } 22066 22067 /** 22068 * Adds sections before or after the current one to create the infinite effect. 22069 */ 22070 function createInfiniteSections(v){ 22071 // Scrolling down 22072 if (!v.isMovementUp) { 22073 // Move all previous sections to after the active section 22074 $(SECTION_ACTIVE_SEL).after(v.activeSection.prevAll(SECTION_SEL).get().reverse()); 22075 } 22076 else { // Scrolling up 22077 // Move all next sections to before the active section 22078 $(SECTION_ACTIVE_SEL).before(v.activeSection.nextAll(SECTION_SEL)); 22079 } 22080 22081 // Maintain the displayed position (now that we changed the element order) 22082 silentScroll($(SECTION_ACTIVE_SEL).position().top); 22083 22084 // Maintain the active slides visible in the viewport 22085 keepSlidesPosition(); 22086 22087 // save for later the elements that still need to be reordered 22088 v.wrapAroundElements = v.activeSection; 22089 22090 // Recalculate animation variables 22091 v.dtop = v.element.position().top; 22092 v.yMovement = getYmovement(v.element); 22093 22094 return v; 22095 } 22096 22097 /** 22098 * Fix section order after continuousVertical changes have been animated 22099 */ 22100 function continuousVerticalFixSectionOrder (v) {
22101 // If continuousVertical is in effect (and autoScrolling would also be in effect then), 22102 // finish moving the elements around so the direct navigation will function more simply 22103 if (!v.wrapAroundElements || !v.wrapAroundElements.length) { 22104 return; 22105 } 22106 22107 if (v.isMovementUp) { 22108 $(SECTION_FIRST_SEL).before(v.wrapAroundElements); 22109 } 22110 else { 22111 $(SECTION_LAST_SEL).after(v.wrapAroundElements); 22112 } 22113 22114 silentScroll($(SECTION_ACTIVE_SEL).position().top); 22115 22116 // Maintain the active slides visible in the viewport 22117 keepSlidesPosition(); 22118 } 22119 22120 22121 /** 22122 * Actions to do once the section is loaded. 22123 */ 22124 function afterSectionLoads (v){ 22125 continuousVerticalFixSectionOrder(v); 22126 22127 //callback (afterLoad) if the site is not just resizing and readjusting the slides 22128 $.isFunction(options.afterLoad) && !v.localIsResizing && options.afterLoad.call(v.element, v.anchorLink, (v.sectionIndex + 1)); 22129 options.scrollOverflowHandler.afterLoad(); 22130 22131 if(!v.localIsResizing){ 22132 playMedia(v.element); 22133 } 22134 22135 v.element.addClass(COMPLETELY).siblings().removeClass(COMPLETELY); 22136 22137 canScroll = true; 22138 22139 $.isFunction(v.callback) && v.callback.call(this); 22140 } 22141 22142 /** 22143 * Sets the value for the given attribute from the `data-` attribute with the same suffix 22144 * ie: data-srcset ==> srcset | data-src ==> src 22145 */ 22146 function setSrc(element, attribute){ 22147 element 22148 .attr(attribute, element.data(attribute)) 22149 .removeAttr('data-' + attribute); 22150 } 22151 22152 /** 22153 * Lazy loads image, video and audio elements. 22154 */ 22155 function lazyLoad(destiny){ 22156 if (!options.lazyLoading){ 22157 return; 22158 } 22159 22160 var panel = getSlideOrSection(destiny); 22161 var element; 22162 22163 panel.find('img[data-src], img[data-srcset], source[data-src], audio[data-src], iframe[data-src]').each(function(){ 22164 element = $(this); 22165 22166 $.each(['src', 'srcset'], function(index, type){ 22167 var attribute = element.attr('data-' + type); 22168 if(typeof attribute !== 'undefined' && attribute){ 22169 setSrc(element, type); 22170 } 22171 }); 22172 22173 if(element.is('source')){ 22174 element.closest('video').get(0).load(); 22175 } 22176 }); 22177 } 22178 22179 /** 22180 * Plays video and audio elements. 22181 */ 22182 function playMedia(destiny){ 22183 var panel = getSlideOrSection(destiny); 22184 22185 //playing HTML5 media elements 22186 panel.find('video, audio').each(function(){ 22187 var element = $(this).get(0); 22188 22189 if( element.hasAttribute('data-autoplay') && typeof element.play === 'function' ) { 22190 element.play(); 22191 } 22192 }); 22193 22194 //youtube videos 22195 panel.find('iframe[src*="youtube.com/embed/"]').each(function(){ 22196 var element = $(this).get(0); 22197 22198 if ( element.hasAttribute('data-autoplay') ){ 22199 playYoutube(element); 22200 } 22201 22202 //in case the URL was not loaded yet. On page load we need time for the new URL (with the API string) to load. 22203 element.onload = function() { 22204 if ( element.hasAttribute('data-autoplay') ){ 22205 playYoutube(element); 22206 } 22207 }; 22208 }); 22209 } 22210 22211 /** 22212 * Plays a youtube video 22213 */ 22214 function playYoutube(element){ 22215 element.contentWindow.postMessage('{"event":"command","func":"playVideo","args":""}', '*'); 22216 } 22217 22218 /** 22219 * Stops video and audio elements. 22220 */ 22221 function stopMedia(destiny){ 22222 var panel = getSlideOrSection(destiny); 22223 22224 //stopping HTML5 media elements 22225 panel.find('video, audio').each(function(){ 22226 var element = $(this).get(0); 22227 22228 if( !element.hasAttribute('data-keepplaying') && typeof element.pause === 'function' ) { 22229 element.pause(); 22230 } 22231 }); 22232 22233 //youtube videos 22234 panel.find('iframe[src*="youtube.com/embed/"]').each(function(){ 22235 var element = $(this).get(0); 22236 22237 if( /youtube\.com\/embed\//.test($(this).attr('src')) && !element.hasAttribute('data-keepplaying')){ 22238 $(this).get(0).contentWindow.postMessage('{"event":"command","func":"pauseVideo","args":""}','*'); 22239 } 22240 }); 22241 } 22242 22243 /** 22244 * Gets the active slide (or section) for the given section 22245 */ 22246 function getSlideOrSection(destiny){ 22247 var slide = destiny.find(SLIDE_ACTIVE_SEL); 22248 if( slide.length ) { 22249 destiny = $(slide); 22250 } 22251 22252 return destiny; 22253 } 22254 22255 /**
22256 * Scrolls to the anchor in the URL when loading the site 22257 */ 22258 function scrollToAnchor(){ 22259 //getting the anchor link in the URL and deleting the `#` 22260 var value = window.location.hash.replace('#', '').split('/'); 22261 var sectionAnchor = decodeURIComponent(value[0]); 22262 var slideAnchor = decodeURIComponent(value[1]); 22263 22264 if(sectionAnchor){ //if theres any # 22265 if(options.animateAnchor){ 22266 scrollPageAndSlide(sectionAnchor, slideAnchor); 22267 }else{ 22268 silentMoveTo(sectionAnchor, slideAnchor); 22269 } 22270 } 22271 } 22272 22273 /** 22274 * Detecting any change on the URL to scroll to the given anchor link 22275 * (a way to detect back history button as we play with the hashes on the URL) 22276 */ 22277 function hashChangeHandler(){ 22278 if(!isScrolling && !options.lockAnchors){ 22279 var value = window.location.hash.replace('#', '').split('/'); 22280 var sectionAnchor = decodeURIComponent(value[0]); 22281 var slideAnchor = decodeURIComponent(value[1]); 22282 22283 //when moving to a slide in the first section for the first time (first time to add an anchor to the URL) 22284 var isFirstSlideMove = (typeof lastScrolledDestiny === 'undefined'); 22285 var isFirstScrollMove = (typeof lastScrolledDestiny === 'undefined' && typeof slideAnchor === 'undefined' && !slideMoving); 22286 22287 22288 if(sectionAnchor.length){ 22289 /*in order to call scrollpage() only once for each destination at a time 22290 It is called twice for each scroll otherwise, as in case of using anchorlinks `hashChange` 22291 event is fired on every scroll too.*/ 22292 if ((sectionAnchor && sectionAnchor !== lastScrolledDestiny) && !isFirstSlideMove || isFirstScrollMove || (!slideMoving && lastScrolledSlide != slideAnchor )) { 22293 scrollPageAndSlide(sectionAnchor, slideAnchor); 22294 } 22295 } 22296 } 22297 } 22298 22299 //Sliding with arrow keys, both, vertical and horizontal 22300 function keydownHandler(e) { 22301 22302 clearTimeout(keydownId); 22303 22304 var activeElement = $(':focus'); 22305 22306 if(!activeElement.is('textarea') && !activeElement.is('input') && !activeElement.is('select') && 22307 activeElement.attr('contentEditable') !== "true" && activeElement.attr('contentEditable') !== '' && 22308 options.keyboardScrolling && options.autoScrolling){ 22309 var keyCode = e.which; 22310 22311 //preventing the scroll with arrow keys & spacebar & Page Up & Down keys 22312 var keyControls = [40, 38, 32, 33, 34]; 22313 if($.inArray(keyCode, keyControls) > -1){ 22314 e.preventDefault(); 22315 } 22316 22317 controlPressed = e.ctrlKey; 22318 22319 keydownId = setTimeout(function(){ 22320 onkeydown(e); 22321 },150); 22322 } 22323 } 22324 22325 function tooltipTextHandler(){ 22326 $(this).prev().trigger('click'); 22327 } 22328 22329 //to prevent scrolling while zooming 22330 function keyUpHandler(e){ 22331 if(isWindowFocused){ //the keyup gets fired on new tab ctrl + t in Firefox 22332 controlPressed = e.ctrlKey; 22333 } 22334 } 22335 22336 //binding the mousemove when the mouse's middle button is released 22337 function mouseDownHandler(e){ 22338 //middle button 22339 if (e.which == 2){ 22340 oldPageY = e.pageY; 22341 container.on('mousemove', mouseMoveHandler); 22342 } 22343 } 22344 22345 //unbinding the mousemove when the mouse's middle button is released 22346 function mouseUpHandler(e){ 22347 //middle button 22348 if (e.which == 2){ 22349 container.off('mousemove'); 22350 } 22351 } 22352 22353 //Scrolling horizontally when clicking on the slider controls. 22354 function slideArrowHandler(){ 22355 var section = $(this).closest(SECTION_SEL); 22356 22357 if ($(this).hasClass(SLIDES_PREV)) { 22358 if(isScrollAllowed.m.left){ 22359 moveSlideLeft(section); 22360 } 22361 } else { 22362 if(isScrollAllowed.m.right){ 22363 moveSlideRight(section); 22364 } 22365 } 22366 } 22367 22368 //when opening a new tab (ctrl + t), `control` won't be pressed when coming back. 22369 function blurHandler(){ 22370 isWindowFocused = false;
22371 controlPressed = false; 22372 } 22373 22374 //Scrolls to the section when clicking the navigation bullet 22375 function sectionBulletHandler(e){ 22376 e.preventDefault(); 22377 var index = $(this).parent().index(); 22378 scrollPage($(SECTION_SEL).eq(index)); 22379 } 22380 22381 //Scrolls the slider to the given slide destination for the given section 22382 function slideBulletHandler(e){ 22383 e.preventDefault(); 22384 var slides = $(this).closest(SECTION_SEL).find(SLIDES_WRAPPER_SEL); 22385 var destiny = slides.find(SLIDE_SEL).eq($(this).closest('li').index()); 22386 22387 landscapeScroll(slides, destiny); 22388 } 22389 22390 /** 22391 * Keydown event 22392 */ 22393 function onkeydown(e){ 22394 var shiftPressed = e.shiftKey; 22395 22396 //do nothing if we can not scroll or we are not using horizotnal key arrows. 22397 if(!canScroll && [37,39].indexOf(e.which) < 0){ 22398 return; 22399 } 22400 22401 switch (e.which) { 22402 //up 22403 case 38: 22404 case 33: 22405 if(isScrollAllowed.k.up){ 22406 moveSectionUp(); 22407 } 22408 break; 22409 22410 //down 22411 case 32: //spacebar 22412 if(shiftPressed && isScrollAllowed.k.up){ 22413 moveSectionUp(); 22414 break; 22415 } 22416 /* falls through */ 22417 case 40: 22418 case 34: 22419 if(isScrollAllowed.k.down){ 22420 moveSectionDown(); 22421 } 22422 break; 22423 22424 //Home 22425 case 36: 22426 if(isScrollAllowed.k.up){ 22427 moveTo(1); 22428 } 22429 break; 22430 22431 //End 22432 case 35: 22433 if(isScrollAllowed.k.down){ 22434 moveTo( $(SECTION_SEL).length ); 22435 } 22436 break; 22437 22438 //left 22439 case 37: 22440 if(isScrollAllowed.k.left){ 22441 moveSlideLeft(); 22442 } 22443 break; 22444 22445 //right 22446 case 39: 22447 if(isScrollAllowed.k.right){ 22448 moveSlideRight(); 22449 } 22450 break; 22451 22452 default: 22453 return; // exit this handler for other keys 22454 } 22455 } 22456 22457 /** 22458 * Detecting the direction of the mouse movement. 22459 * Used only for the middle button of the mouse. 22460 */ 22461 var oldPageY = 0; 22462 function mouseMoveHandler(e){ 22463 if(canScroll){ 22464 // moving up 22465 if (e.pageY < oldPageY && isScrollAllowed.m.up){ 22466 moveSectionUp(); 22467 } 22468 22469 // moving down 22470 else if(e.pageY > oldPageY && isScrollAllowed.m.down){ 22471 moveSectionDown(); 22472 } 22473 } 22474 oldPageY = e.pageY; 22475 } 22476 22477 /** 22478 * Scrolls horizontal sliders. 22479 */ 22480 function landscapeScroll(slides, destiny, direction){ 22481 var section = slides.closest(SECTION_SEL); 22482 var v = { 22483 slides: slides, 22484 destiny: destiny, 22485 direction: direction, 22486 destinyPos: destiny.position(), 22487 slideIndex: destiny.index(), 22488 section: section, 22489 sectionIndex: section.index(SECTION_SEL), 22490 anchorLink: section.data('anchor'), 22491 slidesNav: section.find(SLIDES_NAV_SEL), 22492 slideAnchor: getAnchor(destiny), 22493 prevSlide: section.find(SLIDE_ACTIVE_SEL), 22494 prevSlideIndex: section.find(SLIDE_ACTIVE_SEL).index(), 22495 22496 //caching the value of isResizing at the momment the function is called 22497 //because it will be checked later inside a setTimeout and the value might change 22498 localIsResizing: isResizing 22499 }; 22500 v.xMovement = getXmovement(v.prevSlideIndex, v.slideIndex); 22501 v.direction = v.direction ? v.direction : v.xMovement; 22502 22503 //important!! Only do it when not resizing 22504 if(!v.localIsResizing){ 22505 //preventing from scrolling to the next/prev section when using scrollHorizontally 22506 canScroll = false;
22507 } 22508 22509 if(options.onSlideLeave){ 22510 22511 //if the site is not just resizing and readjusting the slides 22512 if(!v.localIsResizing && v.xMovement!=='none'){ 22513 if($.isFunction( options.onSlideLeave )){ 22514 if(options.onSlideLeave.call( v.prevSlide, v.anchorLink, (v.sectionIndex + 1), v.prevSlideIndex, v.xMovement, v.slideIndex ) === false){ 22515 slideMoving = false; 22516 return; 22517 } 22518 } 22519 } 22520 } 22521 22522 destiny.addClass(ACTIVE).siblings().removeClass(ACTIVE); 22523 22524 if(!v.localIsResizing){ 22525 stopMedia(v.prevSlide); 22526 lazyLoad(destiny); 22527 } 22528 22529 if(!options.loopHorizontal && options.controlArrows){ 22530 //hidding it for the fist slide, showing for the rest 22531 section.find(SLIDES_ARROW_PREV_SEL).toggle(v.slideIndex!==0); 22532 22533 //hidding it for the last slide, showing for the rest 22534 section.find(SLIDES_ARROW_NEXT_SEL).toggle(!destiny.is(':last-child')); 22535 } 22536 22537 //only changing the URL if the slides are in the current section (not for resize re-adjusting) 22538 if(section.hasClass(ACTIVE) && !v.localIsResizing){ 22539 setState(v.slideIndex, v.slideAnchor, v.anchorLink, v.sectionIndex); 22540 } 22541 22542 performHorizontalMove(slides, v, true); 22543 } 22544 22545 22546 function afterSlideLoads(v){ 22547 activeSlidesNavigation(v.slidesNav, v.slideIndex); 22548 22549 //if the site is not just resizing and readjusting the slides 22550 if(!v.localIsResizing){ 22551 $.isFunction( options.afterSlideLoad ) && options.afterSlideLoad.call( v.destiny, v.anchorLink, (v.sectionIndex + 1), v.slideAnchor, v.slideIndex); 22552 22553 //needs to be inside the condition to prevent problems with continuousVertical and scrollHorizontally 22554 //and to prevent double scroll right after a windows resize 22555 canScroll = true; 22556 22557 playMedia(v.destiny); 22558 } 22559 22560 //letting them slide again 22561 slideMoving = false; 22562 } 22563 22564 /** 22565 * Performs the horizontal movement. (CSS3 or jQuery) 22566 * 22567 * @param fireCallback {Bool} - determines whether or not to fire the callback 22568 */ 22569 function performHorizontalMove(slides, v, fireCallback){ 22570 var destinyPos = v.destinyPos; 22571 22572 if(options.css3){ 22573 var translate3d = 'translate3d(-' + Math.round(destinyPos.left) + 'px, 0px, 0px)'; 22574 22575 addAnimation(slides.find(SLIDES_CONTAINER_SEL)).css(getTransforms(translate3d), v); 22576 22577 afterSlideLoadsId = setTimeout(function(){ 22578 fireCallback && afterSlideLoads(v); 22579 }, options.scrollingSpeed, options.easing); 22580 }else{ 22581 slides.animate({ 22582 scrollLeft : Math.round(destinyPos.left) 22583 }, options.scrollingSpeed, options.easing, function() { 22584 22585 fireCallback && afterSlideLoads(v); 22586 }); 22587 } 22588 } 22589 22590 /** 22591 * Sets the state for the horizontal bullet navigations. 22592 */ 22593 function activeSlidesNavigation(slidesNav, slideIndex){ 22594 slidesNav.find(ACTIVE_SEL).removeClass(ACTIVE); 22595 slidesNav.find('li').eq(slideIndex).find('a').addClass(ACTIVE); 22596 } 22597 22598 var previousHeight = windowsHeight; 22599 22600 //when resizing the site, we adjust the heights of the sections, slimScroll... 22601 function resizeHandler(){ 22602 //checking if it needs to get responsive 22603 responsive(); 22604 22605 // rebuild immediately on touch devices 22606 if (isTouchDevice) { 22607 var activeElement = $(document.activeElement); 22608 22609 //if the keyboard is NOT visible 22610 if (!activeElement.is('textarea') && !activeElement.is('input') && !activeElement.is('select')) { 22611 var currentHeight = $window.height(); 22612 22613 //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) 22614 if( Math.abs(currentHeight - previousHeight) > (20 * Math.max(previousHeight, currentHeight) / 100) ){ 22615 reBuild(true); 22616 previousHeight = currentHeight; 22617 } 22618 } 22619 }else{ 22620 //in order to call the functions only when the resize is finished 22621 //http://stackoverflow.com/questions/4298612/jquery-how-to-call-resize-event-only-once-its-finished-resizing 22622 clearTimeout(resizeId); 22623 22624 resizeId = setTimeout(function(){ 22625 reBuild(true); 22626 }, 350); 22627 } 22628 } 22629 22630 /** 22631 * Checks if the site needs to get responsive and disables autoScrolling if so. 22632 * A class `fp-responsive` is added to the plugin's container in case the user wants to use it for his own responsive CSS. 22633 */ 22634 function responsive(){ 22635 var widthLimit = options.responsive || options.responsiveWidth; //backwards compatiblity 22636 var heightLimit = options.responsiveHeight; 22637 22638 //only calculating what we need. Remember its called on the resize event. 22639 var isBreakingPointWidth = widthLimit && $window.outerWidth() < widthLimit; 22640 var isBreakingPointHeight = heightLimit && $window.height() < heightLimit; 22641 22642 if(widthLimit && heightLimit){ 22643 setResponsive(isBreakingPointWidth || isBreakingPointHeight); 22644 } 22645 else if(widthLimit){ 22646 setResponsive(isBreakingPointWidth); 22647 } 22648 else if(heightLimit){ 22649 setResponsive(isBreakingPointHeight); 22650 } 22651 } 22652 22653 /** 22654 * Adds transition animations for the given element 22655 */ 22656 function addAnimation(container, element){ 22657 var transition = 'all ' + options.scrollingSpeed + 'ms ' + options.easingcss3; 22658 22659 container.removeClass(NO_TRANSITION); 22660 return container.css({
22661 '-webkit-transition': transition, 22662 'transition': transition 22663 }); 22664 } 22665 22666 /** 22667 * Remove transition animations for the given element 22668 */ 22669 function removeAnimation(element){ 22670 return element.addClass(NO_TRANSITION); 22671 } 22672 22673 /** 22674 * Activating the vertical navigation bullets according to the given slide name. 22675 */ 22676 function activateNavDots(name, sectionIndex){ 22677 if(options.navigation){ 22678 $(SECTION_NAV_SEL).find(ACTIVE_SEL).removeClass(ACTIVE); 22679 if(name){ 22680 $(SECTION_NAV_SEL).find('a[href="#' + name + '"]').addClass(ACTIVE); 22681 }else{ 22682 $(SECTION_NAV_SEL).find('li').eq(sectionIndex).find('a').addClass(ACTIVE); 22683 } 22684 } 22685 } 22686 22687 /** 22688 * Activating the website main menu elements according to the given slide name. 22689 */ 22690 function activateMenuElement(name){ 22691 if(options.menu){ 22692 $(options.menu).find(ACTIVE_SEL).removeClass(ACTIVE); 22693 $(options.menu).find('[data-menuanchor="'+name+'"]').addClass(ACTIVE); 22694 } 22695 } 22696 22697 /** 22698 * Sets to active the current menu and vertical nav items. 22699 */ 22700 function activateMenuAndNav(anchor, index){ 22701 activateMenuElement(anchor); 22702 activateNavDots(anchor, index); 22703 } 22704 22705 /** 22706 * Retuns `up` or `down` depending on the scrolling movement to reach its destination 22707 * from the current section. 22708 */ 22709 function getYmovement(destiny){ 22710 var fromIndex = $(SECTION_ACTIVE_SEL).index(SECTION_SEL); 22711 var toIndex = destiny.index(SECTION_SEL); 22712 if( fromIndex == toIndex){ 22713 return 'none'; 22714 } 22715 if(fromIndex > toIndex){ 22716 return 'up'; 22717 } 22718 return 'down'; 22719 } 22720 22721 /** 22722 * Retuns `right` or `left` depending on the scrolling movement to reach its destination 22723 * from the current slide. 22724 */ 22725 function getXmovement(fromIndex, toIndex){ 22726 if( fromIndex == toIndex){ 22727 return 'none'; 22728 } 22729 if(fromIndex > toIndex){ 22730 return 'left'; 22731 } 22732 return 'right'; 22733 } 22734 22735 /** 22736 * Checks if the element needs scrollbar and if the user wants to apply it. 22737 * If so it creates it. 22738 * 22739 * @param {Object} element jQuery object of the section or slide 22740 */ 22741 function createScrollBar(element){ 22742 //User doesn't want scrollbar here? Sayonara baby! 22743 if(element.hasClass('fp-noscroll')) return; 22744 22745 //needed to make `scrollHeight` work under Opera 12 22746 element.css('overflow', 'hidden'); 22747 22748 var scrollOverflowHandler = options.scrollOverflowHandler; 22749 var wrap = scrollOverflowHandler.wrapContent(); 22750 //in case element is a slide 22751 var section = element.closest(SECTION_SEL); 22752 var scrollable = scrollOverflowHandler.scrollable(element); 22753 var contentHeight; 22754 22755 //if there was scroll, the contentHeight will be the one in the scrollable section 22756 if(scrollable.length){ 22757 contentHeight = scrollOverflowHandler.scrollHeight(element); 22758 }else{ 22759 contentHeight = element.get(0).scrollHeight; 22760 if(options.verticalCentered){ 22761 contentHeight = element.find(TABLE_CELL_SEL).get(0).scrollHeight; 22762 } 22763 } 22764 22765 var scrollHeight = windowsHeight - parseInt(section.css('padding-bottom')) - parseInt(section.css('padding-top')); 22766 22767 //needs scroll? 22768 if ( contentHeight > scrollHeight) { 22769 //did we already have an scrollbar ? Updating it 22770 if(scrollable.length){ 22771 scrollOverflowHandler.update(element, scrollHeight); 22772 } 22773 //creating the scrolling 22774 else{ 22775 if(options.verticalCentered){ 22776 element.find(TABLE_CELL_SEL).wrapInner(wrap); 22777 }else{ 22778 element.wrapInner(wrap); 22779 } 22780 scrollOverflowHandler.create(element, scrollHeight); 22781 } 22782 } 22783 //removing the scrolling when it is not necessary anymore 22784 else{ 22785 scrollOverflowHandler.remove(element); 22786 } 22787 22788 //undo 22789 element.css('overflow', ''); 22790 } 22791 22792 function addTableClass(element){ 22793 //In case we are styling for the 2nd time as in with reponsiveSlides 22794 if(!element.hasClass(TABLE)){ 22795 element.addClass(TABLE).wrapInner('<div class="' + TABLE_CELL + '" style="height:' + getTableHeight(element) + 'px;" />'); 22796 } 22797 } 22798 22799 function getTableHeight(element){ 22800 var sectionHeight = windowsHeight; 22801 22802 if(options.paddingTop || options.paddingBottom){ 22803 var section = element; 22804 if(!section.hasClass(SECTION)){ 22805 section = element.closest(SECTION_SEL); 22806 } 22807 22808 var paddings = parseInt(section.css('padding-top')) + parseInt(section.css('padding-bottom')); 22809 sectionHeight = (windowsHeight - paddings); 22810 } 22811 22812 return sectionHeight; 22813 } 22814 22815 /** 22816 * Adds a css3 transform property to the container class with or without animation depending on the animated param. 22817 */ 22818 function transformContainer(translate3d, animated){ 22819 if(animated){ 22820 addAnimation(container); 22821 }else{ 22822 removeAnimation(container); 22823 } 22824 22825 container.css(getTransforms(translate3d)); 22826 22827 //syncronously removing the class after the animation has been applied. 22828 setTimeout(function(){ 22829 container.removeClass(NO_TRANSITION); 22830 },10); 22831 } 22832 22833 /** 22834 * Gets a section by its anchor / index 22835 */ 22836 function getSectionByAnchor(sectionAnchor){ 22837 if(!sectionAnchor) return []; 22838 22839 var section = container.find(SECTION_SEL + '[data-anchor="'+sectionAnchor+'"]'); 22840 if(!section.length){ 22841 section = $(SECTION_SEL).eq( sectionAnchor -1); 22842 } 22843 22844 return section; 22845 } 22846 22847 /** 22848 * Gets a slide inside a given section by its anchor / index 22849 */ 22850 function getSlideByAnchor(slideAnchor, section){ 22851 var slides = section.find(SLIDES_WRAPPER_SEL); 22852 var slide = slides.find(SLIDE_SEL + '[data-anchor="'+slideAnchor+'"]'); 22853
22854 if(!slide.length){ 22855 slide = slides.find(SLIDE_SEL).eq(slideAnchor); 22856 } 22857 22858 return slide; 22859 } 22860 22861 /** 22862 * Scrolls to the given section and slide anchors 22863 */ 22864 function scrollPageAndSlide(destiny, slide){ 22865 var section = getSectionByAnchor(destiny); 22866 22867 //do nothing if there's no section with the given anchor name 22868 if(!section.length) return; 22869 22870 //default slide 22871 if (typeof slide === 'undefined') { 22872 slide = 0; 22873 } 22874 22875 //we need to scroll to the section and then to the slide 22876 if (destiny !== lastScrolledDestiny && !section.hasClass(ACTIVE)){ 22877 scrollPage(section, function(){ 22878 scrollSlider(section, slide); 22879 }); 22880 } 22881 //if we were already in the section 22882 else{ 22883 scrollSlider(section, slide); 22884 } 22885 } 22886 22887 /** 22888 * Scrolls the slider to the given slide destination for the given section 22889 */ 22890 function scrollSlider(section, slideAnchor){ 22891 if(typeof slideAnchor !== 'undefined'){ 22892 var slides = section.find(SLIDES_WRAPPER_SEL); 22893 var destiny = getSlideByAnchor(slideAnchor, section); 22894 22895 if(destiny.length){ 22896 landscapeScroll(slides, destiny); 22897 } 22898 } 22899 } 22900 22901 /** 22902 * Creates a landscape navigation bar with dots for horizontal sliders. 22903 */ 22904 function addSlidesNavigation(section, numSlides){ 22905 section.append('<div class="' + SLIDES_NAV + '"><ul></ul></div>'); 22906 var nav = section.find(SLIDES_NAV_SEL); 22907 22908 //top or bottom 22909 nav.addClass(options.slidesNavPosition); 22910 22911 for(var i=0; i< numSlides; i++){ 22912 nav.find('ul').append('<li><a href="#"><span></span></a></li>'); 22913 } 22914 22915 //centering it 22916 nav.css('margin-left', '-' + (nav.width()/2) + 'px'); 22917 22918 nav.find('li').first().find('a').addClass(ACTIVE); 22919 } 22920 22921 22922 /** 22923 * Sets the state of the website depending on the active section/slide. 22924 * It changes the URL hash when needed and updates the body class. 22925 */ 22926 function setState(slideIndex, slideAnchor, anchorLink, sectionIndex){ 22927 var sectionHash = ''; 22928 22929 if(options.anchors.length && !options.lockAnchors){ 22930 22931 //isn't it the first slide? 22932 if(slideIndex){ 22933 if(typeof anchorLink !== 'undefined'){ 22934 sectionHash = anchorLink; 22935 } 22936 22937 //slide without anchor link? We take the index instead. 22938 if(typeof slideAnchor === 'undefined'){ 22939 slideAnchor = slideIndex; 22940 } 22941 22942 lastScrolledSlide = slideAnchor; 22943 setUrlHash(sectionHash + '/' + slideAnchor); 22944 22945 //first slide won't have slide anchor, just the section one 22946 }else if(typeof slideIndex !== 'undefined'){ 22947 lastScrolledSlide = slideAnchor; 22948 setUrlHash(anchorLink); 22949 } 22950 22951 //section without slides 22952 else{ 22953 setUrlHash(anchorLink); 22954 } 22955 } 22956 22957 setBodyClass(); 22958 } 22959 22960 /** 22961 * Sets the URL hash. 22962 */ 22963 function setUrlHash(url){ 22964 //Uncode addition 22965 if ( typeof SiteParameters.slide_footer != 'undefined' && url == SiteParameters.slide_footer ) 22966 return false; 22967 22968 if(options.recordHistory){ 22969 location.hash = url; 22970 }else{ 22971 //Uncode addition 22972 //Mobile Chrome doesn't work the normal way, so... lets use HTML5 for phones :) 22973 // if(isTouchDevice || isTouch){ 22974 // window.history.replaceState(undefined, undefined, '#' + url); 22975 // }else{ 22976 // var baseUrl = window.location.href.split('#')[0]; 22977 // window.location.replace( baseUrl + '#' + url ); 22978 // } 22979 return false;
22980 } 22981 } 22982 22983 /** 22984 * Gets the anchor for the given slide / section. Its index will be used if there's none. 22985 */ 22986 function getAnchor(element){ 22987 var anchor = element.data('anchor'); 22988 var index = element.index(); 22989 22990 //Slide without anchor link? We take the index instead. 22991 if(typeof anchor === 'undefined'){ 22992 anchor = index; 22993 } 22994 22995 return anchor; 22996 } 22997 22998 /** 22999 * Sets a class for the body of the page depending on the active section / slide 23000 */ 23001 function setBodyClass(){ 23002 var section = $(SECTION_ACTIVE_SEL); 23003 var slide = section.find(SLIDE_ACTIVE_SEL); 23004 23005 var sectionAnchor = getAnchor(section); 23006 var slideAnchor = getAnchor(slide); 23007 23008 var text = String(sectionAnchor); 23009 23010 if(slide.length){ 23011 text = text + '-' + slideAnchor; 23012 } 23013 23014 //changing slash for dash to make it a valid CSS style 23015 text = text.replace('/', '-').replace('#',''); 23016 23017 //removing previous anchor classes 23018 var classRe = new RegExp('\\b\\s?' + VIEWING_PREFIX + '-[^\\s]+\\b', "g"); 23019 $body[0].className = $body[0].className.replace(classRe, ''); 23020 23021 //adding the current anchor 23022 $body.addClass(VIEWING_PREFIX + '-' + text); 23023 } 23024 23025 /** 23026 * Checks for translate3d support 23027 * @return boolean 23028 * http://stackoverflow.com/questions/5661671/detecting-transform-translate3d-support 23029 */ 23030 function support3d() { 23031 var el = document.createElement('p'), 23032 has3d, 23033 transforms = { 23034 'webkitTransform':'-webkit-transform', 23035 'OTransform':'-o-transform', 23036 'msTransform':'-ms-transform', 23037 'MozTransform':'-moz-transform', 23038 'transform':'transform' 23039 }; 23040 23041 // Add it to the body to get the computed style. 23042 document.body.insertBefore(el, null); 23043 23044 for (var t in transforms) { 23045 if (el.style[t] !== undefined) { 23046 el.style[t] = 'translate3d(1px,1px,1px)'; 23047 has3d = window.getComputedStyle(el).getPropertyValue(transforms[t]); 23048 } 23049 } 23050 23051 document.body.removeChild(el); 23052 23053 return (has3d !== undefined && has3d.length > 0 && has3d !== 'none'); 23054 } 23055 23056 /** 23057 * Removes the auto scrolling action fired by the mouse wheel and trackpad. 23058 * After this function is called, the mousewheel and trackpad movements won't scroll through sections. 23059 */ 23060 function removeMouseWheelHandler(){ 23061 if (document.addEventListener) { 23062 document.removeEventListener('mousewheel', MouseWheelHandler, false); //IE9, Chrome, Safari, Oper 23063 document.removeEventListener('wheel', MouseWheelHandler, false); //Firefox 23064 document.removeEventListener('MozMousePixelScroll', MouseWheelHandler, false); //old Firefox 23065 } else { 23066 document.detachEvent('onmousewheel', MouseWheelHandler); //IE 6/7/8 23067 } 23068 } 23069 23070 /** 23071 * Adds the auto scrolling action for the mouse wheel and trackpad. 23072 * After this function is called, the mousewheel and trackpad movements will scroll through sections 23073 * https://developer.mozilla.org/en-US/docs/Web/Events/wheel 23074 */ 23075 function addMouseWheelHandler(){ 23076 var prefix = ''; 23077 var _addEventListener; 23078 23079 if (window.addEventListener){ 23080 _addEventListener = "addEventListener"; 23081 }else{ 23082 _addEventListener = "attachEvent"; 23083 prefix = 'on'; 23084 } 23085 23086 // detect available wheel event 23087 var support = 'onwheel' in document.createElement('div') ? 'wheel' : // Modern browsers support "wheel" 23088 document.onmousewheel !== undefined ? 'mousewheel' : // Webkit and IE support at least "mousewheel" 23089 'DOMMouseScroll'; // let's assume that remaining browsers are older Firefox 23090 var passiveEvent = g_supportsPassive ? {passive: false }
23090: false; 23091 23092 23093 if(support == 'DOMMouseScroll'){ 23094 document[ _addEventListener ](prefix + 'MozMousePixelScroll', MouseWheelHandler, passiveEvent); 23095 } 23096 23097 //handle MozMousePixelScroll in older Firefox 23098 else{ 23099 document[ _addEventListener ](prefix + support, MouseWheelHandler, passiveEvent); 23100 } 23101 } 23102 23103 /** 23104 * Binding the mousemove when the mouse's middle button is pressed 23105 */ 23106 function addMiddleWheelHandler(){ 23107 container 23108 .on('mousedown', mouseDownHandler) 23109 .on('mouseup', mouseUpHandler); 23110 } 23111 23112 /** 23113 * Unbinding the mousemove when the mouse's middle button is released 23114 */ 23115 function removeMiddleWheelHandler(){ 23116 container 23117 .off('mousedown', mouseDownHandler) 23118 .off('mouseup', mouseUpHandler); 23119 } 23120 23121 /** 23122 * Adds the possibility to auto scroll through sections on touch devices. 23123 */ 23124 function addTouchHandler(){ 23125 if(isTouchDevice || isTouch){ 23126 if(options.autoScrolling){ 23127 $body.off(events.touchmove).on(events.touchmove, preventBouncing); 23128 } 23129 23130 $(WRAPPER_SEL) 23131 .off(events.touchstart).on(events.touchstart, touchStartHandler) 23132 .off(events.touchmove).on(events.touchmove, touchMoveHandler); 23133 } 23134 } 23135 23136 /** 23137 * Removes the auto scrolling for touch devices. 23138 */ 23139 function removeTouchHandler(){ 23140 if(isTouchDevice || isTouch){ 23141 $(WRAPPER_SEL) 23142 .off(events.touchstart) 23143 .off(events.touchmove); 23144 } 23145 } 23146 23147 /* 23148 * Returns and object with Microsoft pointers (for IE<11 and for IE >= 11) 23149 * http://msdn.microsoft.com/en-us/library/ie/dn304886(v=vs.85).aspx 23150 */ 23151 function getMSPointer(){ 23152 var pointer; 23153 23154 //IE >= 11 & rest of browsers 23155 if(window.PointerEvent){ 23156 pointer = { down: 'pointerdown', move: 'pointermove'}; 23157 } 23158 23159 //IE < 11 23160 else{ 23161 pointer = { down: 'MSPointerDown', move: 'MSPointerMove'}; 23162 } 23163 23164 return pointer; 23165 } 23166 23167 /** 23168 * Gets the pageX and pageY properties depending on the browser. 23169 * https://github.com/alvarotrigo/fullPage.js/issues/194#issuecomment-34069854 23170 */ 23171 function getEventsPage(e){ 23172 var events = []; 23173 23174 events.y = (typeof e.pageY !== 'undefined' && (e.pageY || e.pageX) ? e.pageY : e.touches[0].pageY); 23175 events.x = (typeof e.pageX !== 'undefined' && (e.pageY || e.pageX) ? e.pageX : e.touches[0].pageX); 23176 23177 //in touch devices with scrollBar:true, e.pageY is detected, but we have to deal with touch events. #1008 23178 if(isTouch && isReallyTouch(e) && options.scrollBar){ 23179 events.y = e.touches[0].pageY; 23180 events.x = e.touches[0].pageX; 23181 } 23182 23183 return events; 23184 } 23185 23186 /** 23187 * Slides silently (with no animation) the active slider to the given slide. 23188 * @param noCallback {bool} true or defined -> no callbacks 23189 */ 23190 function silentLandscapeScroll(activeSlide, noCallbacks){ 23191 setScrollingSpeed (0, 'internal'); 23192 23193 if(typeof noCallbacks !== 'undefined'){ 23194 //preventing firing callbacks afterSlideLoad etc. 23195 isResizing = true; 23196 } 23197 23198 landscapeScroll(activeSlide.closest(SLIDES_WRAPPER_SEL), activeSlide); 23199 23200 if(typeof noCallbacks !== 'undefined'){ 23201 isResizing = false; 23202 } 23203 23204 setScrollingSpeed(originals.scrollingSpeed, 'internal'); 23205 } 23206 23207 /** 23208 * Scrolls silently (with no animation) the page to the given Y position. 23209 */ 23210 function silentScroll(top){ 23211 // The first section can have a negative value in iOS 10. Not quite sure why: -0.0142822265625 23212 // that's why we round it to 0. 23213 var roundedTop = Math.round(top); 23214 23215 if (options.css3 && options.autoScrolling && !options.scrollBar){ 23216 var translate3d = 'translate3d(0px, -' + roundedTop + 'px, 0px)'; 23217 transformContainer(translate3d, false); 23218 } 23219 else if(options.autoScrolling && !options.scrollBar){ 23220 container.css('top', -roundedTop); 23221 } 23222 else{ 23223 $htmlBody.scrollTop(roundedTop); 23224 } 23225 } 23226 23227 /** 23228 * Returns the cross-browser transform string. 23229 */ 23230 function getTransforms(translate3d){ 23231 return {
23232 '-webkit-transform': translate3d, 23233 '-moz-transform': translate3d, 23234 '-ms-transform':translate3d, 23235 'transform': translate3d 23236 }; 23237 } 23238 23239 /** 23240 * Allowing or disallowing the mouse/swipe scroll in a given direction. (not for keyboard) 23241 * @type m (mouse) or k (keyboard) 23242 */ 23243 function setIsScrollAllowed(value, direction, type){ 23244 switch (direction){ 23245 case 'up': isScrollAllowed[type].up = value; break; 23246 case 'down': isScrollAllowed[type].down = value; break; 23247 case 'left': isScrollAllowed[type].left = value; break; 23248 case 'right': isScrollAllowed[type].right = value; break; 23249 case 'all': 23250 if(type == 'm'){ 23251 setAllowScrolling(value); 23252 }else{ 23253 setKeyboardScrolling(value); 23254 } 23255 } 23256 } 23257 23258 /* 23259 * Destroys fullpage.js plugin events and optinally its html markup and styles 23260 */ 23261 function destroy(all){ 23262 setAutoScrolling(false, 'internal'); 23263 setAllowScrolling(false); 23264 setKeyboardScrolling(false); 23265 container.addClass(DESTROYED); 23266 23267 clearTimeout(afterSlideLoadsId); 23268 clearTimeout(afterSectionLoadsId); 23269 clearTimeout(resizeId); 23270 clearTimeout(scrollId); 23271 clearTimeout(scrollId2); 23272 23273 $window 23274 .off('scroll', scrollHandler) 23275 .off('hashchange', hashChangeHandler) 23276 .off('resize', resizeHandler); 23277 23278 $document 23279 .off('click touchstart', SECTION_NAV_SEL + ' a') 23280 .off('mouseenter', SECTION_NAV_SEL + ' li') 23281 .off('mouseleave', SECTION_NAV_SEL + ' li') 23282 .off('click touchstart', SLIDES_NAV_LINK_SEL) 23283 .off('mouseover', options.normalScrollElements) 23284 .off('mouseout', options.normalScrollElements); 23285 23286 $(SECTION_SEL) 23287 .off('click touchstart', SLIDES_ARROW_SEL); 23288 23289 clearTimeout(afterSlideLoadsId); 23290 clearTimeout(afterSectionLoadsId); 23291 23292 //lets make a mess! 23293 if(all){ 23294 destroyStructure(); 23295 } 23296 } 23297 23298 /* 23299 * Removes inline styles added by fullpage.js 23300 */ 23301 function destroyStructure(){ 23302 //reseting the `top` or `translate` properties to 0 23303 silentScroll(0); 23304 23305 //loading all the lazy load content 23306 container.find('img[data-src], source[data-src], audio[data-src], iframe[data-src]').each(function(){ 23307 setSrc($(this), 'src'); 23308 }); 23309 23310 container.find('img[data-srcset]').each(function(){ 23311 setSrc($(this), 'srcset'); 23312 }); 23313 23314 $(SECTION_NAV_SEL + ', ' + SLIDES_NAV_SEL + ', ' + SLIDES_ARROW_SEL).remove(); 23315 23316 //removing inline styles 23317 $(SECTION_SEL).css( { 23318 'height': '', 23319 'background-color' : '', 23320 'padding': '' 23321 }); 23322 23323 $(SLIDE_SEL).css( { 23324 'width': '' 23325 }); 23326 23327 container.css({ 23328 'height': '', 23329 'position': '', 23330 '-ms-touch-action': '', 23331 'touch-action': '' 23332 }); 23333 23334 $htmlBody.css({ 23335 'overflow': '', 23336 'height': '' 23337 }); 23338 23339 // remove .fp-enabled class 23340 $('html').removeClass(ENABLED); 23341 23342 // remove .fp-responsive class 23343 $body.removeClass(RESPONSIVE); 23344 23345 // remove all of the .fp-viewing- classes 23346 $.each($body.get(0).className.split(/\s+/), function (index, className) { 23347 if (className.indexOf(VIEWING_PREFIX) === 0) { 23348 $body.removeClass(className); 23349 } 23350 }); 23351 23352 //removing added classes 23353 $(SECTION_SEL + ', ' + SLIDE_SEL).each(function(){ 23354 options.scrollOverflowHandler.remove($(this)); 23355 $(this).removeClass(TABLE + ' ' + ACTIVE); 23356 }); 23357 23358 removeAnimation(container); 23359 23360 //Unwrapping content 23361 container.find(TABLE_CELL_SEL + ', ' + SLIDES_CONTAINER_SEL + ', ' + SLIDES_WRAPPER_SEL).each(function(){ 23362 //unwrap not being use in case there's no child element inside and its just text 23363 $(this).replaceWith(this.childNodes); 23364 }); 23365 23366 //removing the applied transition from the fullpage wrapper 23367 container.css({
23368 '-webkit-transition': 'none', 23369 'transition': 'none' 23370 }); 23371 23372 //scrolling the page to the top with no animation 23373 $htmlBody.scrollTop(0); 23374 23375 //removing selectors 23376 var usedSelectors = [SECTION, SLIDE, SLIDES_CONTAINER]; 23377 $.each(usedSelectors, function(index, value){ 23378 $('.' + value).removeClass(value); 23379 }); 23380 } 23381 23382 /* 23383 * Sets the state for a variable with multiple states (original, and temporal) 23384 * Some variables such as `autoScrolling` or `recordHistory` might change automatically its state when using `responsive` or `autoScrolling:false`. 23385 * This function is used to keep track of both states, the original and the temporal one. 23386 * If type is not 'internal', then we assume the user is globally changing the variable. 23387 */ 23388 function setVariableState(variable, value, type){ 23389 options[variable] = value; 23390 if(type !== 'internal'){ 23391 originals[variable] = value; 23392 } 23393 } 23394 23395 /** 23396 * Displays warnings 23397 */ 23398 function displayWarnings(){ 23399 var extensions = ['fadingEffect', 'continuousHorizontal', 'scrollHorizontally', 'interlockedSlides', 'resetSliders', 'responsiveSlides', 'offsetSections', 'dragAndMove', 'scrollOverflowReset', 'parallax']; 23400 //UNCODE.addition 23401 // if($('html').hasClass(ENABLED)){ 23402 // showError('error', 'Fullpage.js can only be initialized once and you are doing it multiple times!'); 23403 // return; 23404 // } 23405 23406 // Disable mutually exclusive settings 23407 //UNCODE.addition 23408 // if (options.continuousVertical && 23409 // (options.loopTop || options.loopBottom)) { 23410 // options.continuousVertical = false;
23411 // showError('warn', 'Option `loopTop/loopBottom` is mutually exclusive with `continuousVertical`; `continuousVertical` disabled'); 23412 // } 23413 23414 // if(options.scrollBar && options.scrollOverflow){ 23415 // showError('warn', 'Option `scrollBar` is mutually exclusive with `scrollOverflow`. Sections with scrollOverflow might not work well in Firefox'); 23416 // } 23417 23418 // if(options.continuousVertical && (options.scrollBar || !options.autoScrolling)){ 23419 // options.continuousVertical = false; 23420 // showError('warn', 'Scroll bars (`scrollBar:true` or `autoScrolling:false`) are mutually exclusive with `continuousVertical`; `continuousVertical` disabled'); 23421 // } 23422 23423 //using extensions? Wrong file! 23424 $.each(extensions, function(index, extension){ 23425 //is the option set to true? 23426 if(options[extension]){ 23427 showError('warn', 'fullpage.js extensions require jquery.fullpage.extensions.min.js file instead of the usual jquery.fullpage.js. Requested: '+ extension); 23428 } 23429 }); 23430 23431 //anchors can not have the same value as any element ID or NAME 23432 $.each(options.anchors, function(index, name){ 23433 23434 //case insensitive selectors (http://stackoverflow.com/a/19465187/1081396) 23435 var nameAttr = $document.find('[name]').filter(function() { 23436 return $(this).attr('name') && $(this).attr('name').toLowerCase() == name.toLowerCase(); 23437 }); 23438 23439 var idAttr = $document.find('[id]').filter(function() { 23440 return $(this).attr('id') && $(this).attr('id').toLowerCase() == name.toLowerCase(); 23441 }); 23442 23443 if(idAttr.length || nameAttr.length ){ 23444 showError('error', 'data-anchor tags can not have the same value as any `id` element on the site (or `name` element for IE).'); 23445 idAttr.length && showError('error', '"' + name + '" is is being used by another element `id` property'); 23446 nameAttr.length && showError('error', '"' + name + '" is is being used by another element `name` property'); 23447 } 23448 }); 23449 } 23450 23451 /** 23452 * Shows a message in the console of the given type. 23453 */ 23454 function showError(type, text){ 23455 console && console[type] && console[type]('fullPage: ' + text); 23456 } 23457 23458 }; //end of $.fn.fullpage 23459 23460 if(typeof IScroll !== 'undefined'){ 23461 /* 23462 * Turns iScroll `mousewheel` option off dynamically 23463 * https://github.com/cubiq/iscroll/issues/1036 23464 */ 23465 IScroll.prototype.wheelOn = function () { 23466 this.wrapper.addEventListener('wheel', this); 23467 this.wrapper.addEventListener('mousewheel', this); 23468 this.wrapper.addEventListener('DOMMouseScroll', this); 23469 }; 23470 23471 /* 23472 * Turns iScroll `mousewheel` option on dynamically 23473 * https://github.com/cubiq/iscroll/issues/1036 23474 */ 23475 IScroll.prototype.wheelOff = function () { 23476 this.wrapper.removeEventListener('wheel', this); 23477 this.wrapper.removeEventListener('mousewheel', this); 23478 this.wrapper.removeEventListener('DOMMouseScroll', this); 23479 }; 23480 } 23481 23482 /** 23483 * An object to handle overflow scrolling. 23484 * This uses jquery.slimScroll to accomplish overflow scrolling. 23485 * It is possible to pass in an alternate scrollOverflowHandler 23486 * to the fullpage.js option that implements the same functions 23487 * as this handler. 23488 * 23489 * @type {Object} 23490 */ 23491 var iscrollHandler = { 23492 refreshId: null, 23493 iScrollInstances: [], 23494 23495 // Enables or disables the mouse wheel for the active section or all slides in it 23496 toggleWheel: function(value){ 23497 var scrollable = $(SECTION_ACTIVE_SEL).find(SCROLLABLE_SEL); 23498 scrollable.each(function(){ 23499 var iScrollInstance = $(this).data('iscrollInstance'); 23500 if(typeof iScrollInstance !== 'undefined' && iScrollInstance){ 23501 if(value){ 23502 iScrollInstance.wheelOn(); 23503 } 23504 else{ 23505 iScrollInstance.wheelOff(); 23506 } 23507 } 23508 }); 23509 }, 23510 23511 /** 23512 * Turns off iScroll for the destination section. 23513 * When scrolling very fast on some trackpads (and Apple laptops) the inertial scrolling would
23514 * scroll the destination section/slide before the sections animations ends. 23515 */ 23516 onLeave: function(){ 23517 iscrollHandler.toggleWheel(false); 23518 }, 23519 23520 // Turns off iScroll for the leaving section 23521 beforeLeave: function(){ 23522 iscrollHandler.onLeave() 23523 }, 23524 23525 // Turns on iScroll on section load 23526 afterLoad: function(){ 23527 iscrollHandler.toggleWheel(true); 23528 }, 23529 23530 /** 23531 * Called when overflow scrolling is needed for a section. 23532 * 23533 * @param {Object} element jQuery object containing current section 23534 * @param {Number} scrollHeight Current window height in pixels 23535 */ 23536 create: function(element, scrollHeight) { 23537 var scrollable = element.find(SCROLLABLE_SEL); 23538 23539 scrollable.height(scrollHeight); 23540 scrollable.each(function() { 23541 var $this = $(this); 23542 var iScrollInstance = $this.data('iscrollInstance'); 23543 if (iScrollInstance) { 23544 $.each(iscrollHandler.iScrollInstances, function(){ 23545 $(this).destroy(); 23546 }); 23547 } 23548 23549 iScrollInstance = new IScroll($this.get(0), iscrollOptions); 23550 iscrollHandler.iScrollInstances.push(iScrollInstance); 23551 23552 //off by default until the section gets active 23553 iScrollInstance.wheelOff(); 23554 23555 $this.data('iscrollInstance', iScrollInstance); 23556 }); 23557 }, 23558 23559 /** 23560 * Return a boolean depending on whether the scrollable element is a 23561 * the end or at the start of the scrolling depending on the given type. 23562 * 23563 * @param {String} type Either 'top' or 'bottom' 23564 * @param {Object} scrollable jQuery object for the scrollable element 23565 * @return {Boolean} 23566 */ 23567 isScrolled: function(type, scrollable) { 23568 var scroller = scrollable.data('iscrollInstance'); 23569 23570 //no scroller? 23571 if (!scroller) { 23572 return true; 23573 } 23574 23575 if (type === 'top') { 23576 return scroller.y >= 0 && !scrollable.scrollTop(); 23577 } else if (type === 'bottom') { 23578 return (0 - scroller.y) + scrollable.scrollTop() + 1 + scrollable.innerHeight() >= scrollable[0].scrollHeight; 23579 } 23580 }, 23581 23582 /** 23583 * Returns the scrollable element for the given section. 23584 * If there are landscape slides, will only return a scrollable element 23585 * if it is in the active slide. 23586 * 23587 * @param {Object} activeSection jQuery object containing current section 23588 * @return {Boolean} 23589 */ 23590 scrollable: function(activeSection){ 23591 // if there are landscape slides, we check if the scrolling bar is in the current one or not 23592 if (activeSection.find(SLIDES_WRAPPER_SEL).length) { 23593 return activeSection.find(SLIDE_ACTIVE_SEL).find(SCROLLABLE_SEL); 23594 } 23595 return activeSection.find(SCROLLABLE_SEL); 23596 }, 23597 23598 /** 23599 * Returns the scroll height of the wrapped content. 23600 * If this is larger than the window height minus section padding, 23601 * overflow scrolling is needed. 23602 * 23603 * @param {Object} element jQuery object containing current section 23604 * @return {Number} 23605 */ 23606 scrollHeight: function(element) { 23607 return element.find(SCROLLABLE_SEL).children().first().get(0).scrollHeight; 23608 }, 23609 23610 /** 23611 * Called when overflow scrolling is no longer needed for a section. 23612 * 23613 * @param {Object} element jQuery object containing current section 23614 */ 23615 remove: function(element) { 23616 var scrollable = element.find(SCROLLABLE_SEL); 23617 if (scrollable.length) { 23618 var iScrollInstance = scrollable.data('iscrollInstance'); 23619 iScrollInstance.destroy(); 23620 23621 scrollable.data('iscrollInstance', null); 23622 } 23623 element.find(SCROLLABLE_SEL).children().first().children().first().unwrap().unwrap(); 23624 }, 23625 23626 /** 23627 * Called when overflow scrolling has already been setup but the 23628 * window height has potentially changed. 23629 * 23630 * @param {Object}
vendor: 16,384 bytes, lines 23630-24181
23630 element jQuery object containing current section 23631 * @param {Number} scrollHeight Current window height in pixels 23632 */ 23633 update: function(element, scrollHeight) { 23634 //using a timeout in order to execute the refresh function only once when `update` is called multiple times in a 23635 //short period of time. 23636 //it also comes on handy because iScroll requires the use of timeout when using `refresh`. 23637 clearTimeout(iscrollHandler.refreshId); 23638 iscrollHandler.refreshId = setTimeout(function(){ 23639 $.each(iscrollHandler.iScrollInstances, function(){ 23640 $(this).get(0).refresh(); 23641 }); 23642 }, 150); 23643 23644 //updating the wrappers height 23645 element.find(SCROLLABLE_SEL).css('height', scrollHeight + 'px').parent().css('height', scrollHeight + 'px'); 23646 }, 23647 23648 /** 23649 * Called to get any additional elements needed to wrap the section 23650 * content in order to facilitate overflow scrolling. 23651 * 23652 * @return {String|Object} Can be a string containing HTML, 23653 * a DOM element, or jQuery object. 23654 */ 23655 wrapContent: function() { 23656 return '<div class="' + SCROLLABLE + '"><div class="fp-scroller"></div></div>'; 23657 } 23658 }; 23659}); 23660 23661/* ======================================================================== 23662 * Bootstrap: collapse.js v3.1.1 23663 * http://getbootstrap.com/javascript/#collapse 23664 * ======================================================================== 23665 * Copyright 2011-2014 Twitter, Inc. 23666 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 23667 * ======================================================================== */ 23668 23669 23670+function ($) { 23671 'use strict'; 23672 23673 // COLLAPSE PUBLIC CLASS DEFINITION 23674 // ================================ 23675 23676 var Collapse = function (element, options) { 23677 this.$element = $(element) 23678 this.options = $.extend({}, Collapse.DEFAULTS, options) 23679 this.transitioning = null 23680 23681 if (this.options.parent) this.$parent = $(this.options.parent) 23682 if (this.options.toggle) this.toggle() 23683 } 23684 23685 Collapse.DEFAULTS = { 23686 toggle: true 23687 } 23688 23689 Collapse.prototype.dimension = function () { 23690 var hasWidth = this.$element.hasClass('width') 23691 return hasWidth ? 'width' : 'height' 23692 } 23693 23694 Collapse.prototype.show = function () { 23695 if (this.transitioning || this.$element.hasClass('in')) return 23696 23697 var startEvent = $.Event('show.bs.collapse') 23698 this.$element.trigger(startEvent) 23699 if (startEvent.isDefaultPrevented()) return 23700 23701 var actives = this.$parent && this.$parent.find('> .panel > .in') 23702 23703 if (actives && actives.length) { 23704 var hasData = actives.data('bs.collapse') 23705 if (hasData && hasData.transitioning) return 23706 actives.collapse('hide') 23707 hasData || actives.data('bs.collapse', null) 23708 } 23709 23710 var dimension = this.dimension() 23711 23712 this.$element 23713 .removeClass('collapse') 23714 .addClass('collapsing')[dimension](0) 23715 23716 this.transitioning = 1 23717 23718 var complete = function (e) { 23719 if (e && e.target != this.$element[0]) return 23720 this.$element 23721 .removeClass('collapsing') 23722 .addClass('collapse in')[dimension]('auto') 23723 this.transitioning = 0 23724 this.$element.trigger('shown.bs.collapse') 23725 } 23726 23727 if (!$.support.transition) return complete.call(this) 23728 23729 var scrollSize = $.camelCase(['scroll', dimension].join('-')) 23730 23731 this.$element 23732 .one($.support.transition.end, $.proxy(complete, this)) 23733 .emulateTransitionEnd(350)[dimension](this.$element[0][scrollSize]) 23734 } 23735 23736 Collapse.prototype.hide = function () { 23737 if (this.transitioning || !this.$element.hasClass('in')) return 23738 23739 var startEvent = $.Event('hide.bs.collapse') 23740 this.$element.trigger(startEvent) 23741 if (startEvent.isDefaultPrevented()) return 23742 23743 var dimension = this.dimension() 23744 23745 this.$element[dimension](this.$element[dimension]())[0].offsetHeight 23746 23747 this.$element 23748 .addClass('collapsing') 23749 .removeClass('collapse') 23750 .removeClass('in') 23751 23752 this.transitioning = 1 23753 23754 var complete = function (e) { 23755 if (e && e.target != this.$element[0]) return 23756 this.transitioning = 0 23757 this.$element 23758 .trigger('hidden.bs.collapse') 23759 .removeClass('collapsing') 23760 .addClass('collapse') 23761 } 23762 23763 if (!$.support.transition) return complete.call(this) 23764 23765 this.$element 23766 [dimension](0) 23767 .one($.support.transition.end, $.proxy(complete, this)) 23768 .emulateTransitionEnd(350) 23769 } 23770 23771 Collapse.prototype.toggle = function () { 23772 this[this.$element.hasClass('in') ? 'hide' : 'show']() 23773 } 23774 23775 23776 // COLLAPSE PLUGIN DEFINITION 23777 // ========================== 23778 23779 var old = $.fn.collapse 23780 23781 $.fn.collapse = function (option) { 23782 return this.each(function () { 23783 var $this = $(this) 23784 var data = $this.data('bs.collapse') 23785 var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) 23786 23787 if (!data && options.toggle && option == 'show') option = !option 23788 if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) 23789 if (typeof option == 'string') data[option]() 23790 }) 23791 } 23792 23793 $.fn.collapse.Constructor = Collapse 23794 23795 23796 // COLLAPSE NO CONFLICT 23797 // ==================== 23798 23799 $.fn.collapse.noConflict = function () { 23800 $.fn.collapse = old 23801 return this 23802 } 23803 23804 23805 // COLLAPSE DATA-API 23806 // ================= 23807 23808 $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) { 23809 var $this = $(this), href 23810 var target = $this.attr('data-target') 23811 || e.preventDefault() 23812 || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 23813 //Edited by Uncode to replace ID in panel [START] 23814 var _target = href.replace(/^#/, ""); 23815 if ( $('[data-id="' + _target + '"]').length ) { 23816 var $target = $('[data-id="' + _target + '"]') 23817 } else { 23818 var $target = $(target) 23819 } 23820 //Edited by Uncode to replace ID in panel [END] 23821 var data = $target.data('bs.collapse') 23822 var option = data ? 'toggle' : $this.data() 23823 var parent = $this.attr('data-parent') 23824 var $parent = parent && $(parent) 23825 23826 if (!data || !data.transitioning) { 23827 if ($parent) $parent.find('[data-toggle="collapse"][data-parent="' + parent + '"]').not($this).addClass('collapsed') 23828 $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed') 23829 } 23830 23831 $target.collapse(option) 23832 }) 23833 23834}(jQuery); 23835 23836/* ======================================================================== 23837 * Bootstrap: tab.js v3.1.1 23838 * http://getbootstrap.com/javascript/#tabs 23839 * ======================================================================== 23840 * Copyright 2011-2014 Twitter, Inc. 23841 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 23842 * ======================================================================== */ 23843 23844 23845+function ($) { 23846 'use strict'; 23847 23848 // TAB CLASS DEFINITION 23849 // ==================== 23850 23851 var Tab = function (element) { 23852 this.element = $(element) 23853 } 23854 23855 Tab.prototype.show = function () { 23856 var $this = this.element 23857 var $ul = $this.closest('ul:not(.dropdown-menu)') 23858 var selector = $this.data('target') 23859 23860 if (!selector) { 23861 selector = $this.attr('href') 23862 selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 23863 } 23864 23865 if ($this.parent('li').hasClass('active')) return 23866 23867 var previous = $ul.find('.active:last a')[0] 23868 var e = $.Event('show.bs.tab', { 23869 relatedTarget: previous 23870 }) 23871 23872 $this.trigger(e) 23873 23874 if (e.isDefaultPrevented()) return 23875 23876 //Edited by Uncode to replace ID in panel [START] 23877 var _target = selector.replace(/^#/, ""); 23878 if ( $('[data-id="' + _target + '"]').length ) 23879 var $target = $('[data-id="' + _target + '"]') 23880 else 23881 var $target = $(selector) 23882 //Edited by Uncode to replace ID in panel [END] 23883 23884 this.activate($this.parent('li'), $ul) 23885 this.activate($target, $target.parent(), function () { 23886 $this.trigger({ 23887 type: 'shown.bs.tab', 23888 relatedTarget: previous 23889 }) 23890 }) 23891 } 23892 23893 Tab.prototype.activate = function (element, container, callback) { 23894 var $active = container.find('> .active') 23895 var transition = callback 23896 && $.support.transition 23897 && $active.hasClass('fade') 23898 23899 function next() { 23900 $active 23901 .removeClass('active') 23902 .find('> .dropdown-menu > .active') 23903 .removeClass('active') 23904 23905 element.addClass('active') 23906 23907 if (transition) { 23908 element[0].offsetWidth // reflow for transition 23909 element.addClass('in') 23910 } else { 23911 element.removeClass('fade') 23912 } 23913 23914 if (element.parent('.dropdown-menu')) { 23915 element.closest('li.dropdown').addClass('active') 23916 } 23917 23918 callback && callback() 23919 } 23920 23921 transition ? 23922 $active 23923 .one($.support.transition.end, next) 23924 .emulateTransitionEnd(150) : 23925 next() 23926 23927 $active.removeClass('in') 23928 } 23929 23930 23931 // TAB PLUGIN DEFINITION 23932 // ===================== 23933 23934 var old = $.fn.tab 23935 23936 $.fn.tab = function ( option ) { 23937 return this.each(function () { 23938 var $this = $(this) 23939 var data = $this.data('bs.tab') 23940 23941 if (!data) $this.data('bs.tab', (data = new Tab(this))) 23942 if (typeof option == 'string') data[option]() 23943 }) 23944 } 23945 23946 $.fn.tab.Constructor = Tab 23947 23948 23949 // TAB NO CONFLICT 23950 // =============== 23951 23952 $.fn.tab.noConflict = function () { 23953 $.fn.tab = old 23954 return this 23955 } 23956 23957 23958 // TAB DATA-API 23959 // ============ 23960 23961 $(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) { 23962 e.preventDefault() 23963 $(this).tab('show') 23964 }) 23965 23966}(jQuery); 23967 23968/* ======================================================================== 23969 * Bootstrap: tooltip.js v3.1.1 23970 * http://getbootstrap.com/javascript/#tooltip 23971 * Inspired by the original jQuery.tipsy by Jason Frame 23972 * ======================================================================== 23973 * Copyright 2011-2014 Twitter, Inc. 23974 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 23975 * ======================================================================== */ 23976 23977 23978+function ($) { 23979 'use strict'; 23980 23981 // TOOLTIP PUBLIC CLASS DEFINITION 23982 // =============================== 23983 23984 var Tooltip = function (element, options) { 23985 this.type = 23986 this.options = 23987 this.enabled = 23988 this.timeout = 23989 this.hoverState = 23990 this.$element = null 23991 23992 this.init('tooltip', element, options) 23993 } 23994 23995 Tooltip.DEFAULTS = { 23996 animation: true, 23997 placement: 'top', 23998 selector: false, 23999 template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>', 24000 trigger: 'hover focus', 24001 title: '', 24002 delay: 0, 24003 html: false, 24004 container: false, 24005 viewport: { 24006 selector: 'body', 24007 padding: 0 24008 } 24009 } 24010 24011 Tooltip.prototype.init = function (type, element, options) { 24012 this.enabled = true 24013 this.type = type 24014 this.$element = $(element) 24015 this.options = this.getOptions(options) 24016 this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport) 24017 24018 var triggers = this.options.trigger.split(' ') 24019 24020 for (var i = triggers.length; i--;) { 24021 var trigger = triggers[i] 24022 24023 if (trigger == 'click') { 24024 this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this)) 24025 } else if (trigger != 'manual') { 24026 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin' 24027 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout' 24028 24029 this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this)) 24030 this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this)) 24031 } 24032 } 24033 24034 this.options.selector ? 24035 (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) : 24036 this.fixTitle() 24037 } 24038 24039 Tooltip.prototype.getDefaults = function () { 24040 return Tooltip.DEFAULTS 24041 } 24042 24043 Tooltip.prototype.getOptions = function (options) { 24044 options = $.extend({}, this.getDefaults(), this.$element.data(), options) 24045 24046 if (options.delay && typeof options.delay == 'number') { 24047 options.delay = { 24048 show: options.delay, 24049 hide: options.delay 24050 } 24051 } 24052 24053 return options 24054 } 24055 24056 Tooltip.prototype.getDelegateOptions = function () { 24057 var options = {} 24058 var defaults = this.getDefaults() 24059 24060 this._options && $.each(this._options, function (key, value) { 24061 if (defaults[key] != value) options[key] = value 24062 }) 24063 24064 return options 24065 } 24066 24067 Tooltip.prototype.enter = function (obj) { 24068 var self = obj instanceof this.constructor ? 24069 obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) 24070 24071 clearTimeout(self.timeout) 24072 24073 self.hoverState = 'in' 24074 24075 if (!self.options.delay || !self.options.delay.show) return self.show() 24076 24077 self.timeout = setTimeout(function () { 24078 if (self.hoverState == 'in') self.show() 24079 }, self.options.delay.show) 24080 } 24081 24082 Tooltip.prototype.leave = function (obj) { 24083 var self = obj instanceof this.constructor ? 24084 obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) 24085 24086 clearTimeout(self.timeout) 24087 24088 self.hoverState = 'out' 24089 24090 if (!self.options.delay || !self.options.delay.hide) return self.hide() 24091 24092 self.timeout = setTimeout(function () { 24093 if (self.hoverState == 'out') self.hide() 24094 }, self.options.delay.hide) 24095 } 24096 24097 Tooltip.prototype.show = function () { 24098 var e = $.Event('show.bs.' + this.type) 24099 24100 if (this.hasContent() && this.enabled) { 24101 this.$element.trigger(e) 24102 24103 if (e.isDefaultPrevented()) return 24104 var that = this; 24105 24106 var $tip = this.tip() 24107 24108 this.setContent() 24109 24110 if (this.options.animation) $tip.addClass('fade') 24111 24112 var placement = typeof this.options.placement == 'function' ? 24113 this.options.placement.call(this, $tip[0], this.$element[0]) : 24114 this.options.placement 24115 24116 var autoToken = /\s?auto?\s?/i 24117 var autoPlace = autoToken.test(placement) 24118 if (autoPlace) placement = placement.replace(autoToken, '') || 'top' 24119 24120 $tip 24121 .detach() 24122 .css({ top: 0, left: 0, display: 'block' }) 24123 .addClass(placement) 24124 24125 this.options.container ? $tip.appendTo($(document).find(this.options.container)) : $tip.insertAfter(this.$element) 24126 24127 var pos = this.getPosition() 24128 var actualWidth = $tip[0].offsetWidth 24129 var actualHeight = $tip[0].offsetHeight 24130 24131 if (autoPlace) { 24132 var orgPlacement = placement 24133 var $parent = this.$element.parent() 24134 var parentDim = this.getPosition($parent) 24135 24136 placement = placement == 'bottom' && pos.top + pos.height + actualHeight - parentDim.scroll > parentDim.height ? 'top' : 24137 placement == 'top' && pos.top - parentDim.scroll - actualHeight < 0 ? 'bottom' : 24138 placement == 'right' && pos.right + actualWidth > parentDim.width ? 'left' : 24139 placement == 'left' && pos.left - actualWidth < parentDim.left ? 'right' : 24140 placement 24141 24142 $tip 24143 .removeClass(orgPlacement) 24144 .addClass(placement) 24145 } 24146 24147 var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight) 24148 24149 this.applyPlacement(calculatedOffset, placement) 24150 this.hoverState = null 24151 24152 var complete = function() { 24153 that.$element.trigger('shown.bs.' + that.type) 24154 } 24155 24156 $.support.transition && this.$tip.hasClass('fade') ? 24157 $tip 24158 .one($.support.transition.end, complete) 24159 .emulateTransitionEnd(150) : 24160 complete() 24161 } 24162 } 24163 24164 Tooltip.prototype.applyPlacement = function (offset, placement) { 24165 var $tip = this.tip() 24166 var width = $tip[0].offsetWidth 24167 var height = $tip[0].offsetHeight 24168 24169 // manually read margins because getBoundingClientRect includes difference 24170 var marginTop = parseInt($tip.css('margin-top'), 10) 24171 var marginLeft = parseInt($tip.css('margin-left'), 10) 24172 24173 // we must check for NaN for ie 8/9 24174 if (isNaN(marginTop)) marginTop = 0 24175 if (isNaN(marginLeft)) marginLeft = 0 24176 24177 offset.top = offset.top + marginTop 24178 offset.left = offset.left + marginLeft 24179 24180 // $.fn.offset doesn't round pixel values 24181 // so we use setOff
24181set directly with our own function B-0 24182 $.offset.setOffset($tip[0], $.extend({ 24183 using: function (props) { 24184 $tip.css({ 24185 top: Math.round(props.top), 24186 left: Math.round(props.left) 24187 }) 24188 } 24189 }, offset), 0) 24190 24191 $tip.addClass('in') 24192 24193 // check to see if placing tip in new offset caused the tip to resize itself 24194 var actualWidth = $tip[0].offsetWidth 24195 var actualHeight = $tip[0].offsetHeight 24196 24197 if (placement == 'top' && actualHeight != height) { 24198 offset.top = offset.top + height - actualHeight 24199 } 24200 24201 var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight) 24202 24203 if (delta.left) offset.left += delta.left 24204 else offset.top += delta.top 24205 24206 var arrowDelta = delta.left ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight 24207 var arrowPosition = delta.left ? 'left' : 'top' 24208 var arrowOffsetPosition = delta.left ? 'offsetWidth' : 'offsetHeight' 24209 24210 $tip.offset(offset) 24211 this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], arrowPosition) 24212 } 24213 24214 Tooltip.prototype.replaceArrow = function (delta, dimension, position) { 24215 this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + '%') : '') 24216 } 24217 24218 Tooltip.prototype.setContent = function () { 24219 var $tip = this.tip() 24220 var title = this.getTitle() 24221 24222 $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title) 24223 $tip.removeClass('fade in top bottom left right') 24224 } 24225 24226 Tooltip.prototype.hide = function () { 24227 var that = this 24228 var $tip = this.tip() 24229 var e = $.Event('hide.bs.' + this.type) 24230 24231 function complete() { 24232 if (that.hoverState != 'in') $tip.detach() 24233 that.$element.trigger('hidden.bs.' + that.type) 24234 } 24235 24236 this.$element.trigger(e) 24237 24238 if (e.isDefaultPrevented()) return 24239 24240 $tip.removeClass('in') 24241 24242 $.support.transition && this.$tip.hasClass('fade') ? 24243 $tip 24244 .one($.support.transition.end, complete) 24245 .emulateTransitionEnd(150) : 24246 complete() 24247 24248 this.hoverState = null 24249 24250 return this 24251 } 24252 24253 Tooltip.prototype.fixTitle = function () { 24254 var $e = this.$element 24255 if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') { 24256 $e.attr('data-original-title', $e.attr('title') || '').attr('title', '') 24257 } 24258 } 24259 24260 Tooltip.prototype.hasContent = function () { 24261 return this.getTitle() 24262 } 24263 24264 Tooltip.prototype.getPosition = function ($element) { 24265 $element = $element || this.$element 24266 var el = $element[0] 24267 var isBody = el.tagName == 'BODY' 24268 return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : null, { 24269 scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop(), 24270 width: isBody ? $(window).width() : $element.outerWidth(), 24271 height: isBody ? $(window).height() : $element.outerHeight() 24272 }, isBody ? {top: 0, left: 0} : $element.offset()) 24273 } 24274 24275 Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) { 24276 return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } : 24277 placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } : 24278 placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } : 24279 /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width } 24280 24281 } 24282 24283 Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) { 24284 var delta = { top: 0, left: 0 } 24285 if (!this.$viewport) return delta 24286 24287 var viewportPadding = this.options.viewport && this.options.viewport.padding || 0 24288 var viewportDimensions = this.getPosition(this.$viewport) 24289 24290 if (/right|left/.test(placement)) { 24291 var topEdgeOffset = pos.top - viewportPadding - viewportDimensions.scroll 24292 var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight 24293 if (topEdgeOffset < viewportDimensions.top) { // top overflow 24294 delta.top = viewportDimensions.top - topEdgeOffset 24295 } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow 24296 delta.top = viewportDimensions.top + viewportDimensions.height - bottom
24296EdgeOffset 24297 } 24298 } else { 24299 var leftEdgeOffset = pos.left - viewportPadding 24300 var rightEdgeOffset = pos.left + viewportPadding + actualWidth 24301 if (leftEdgeOffset < viewportDimensions.left) { // left overflow 24302 delta.left = viewportDimensions.left - leftEdgeOffset 24303 } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow 24304 delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset 24305 } 24306 } 24307 24308 return delta 24309 } 24310 24311 Tooltip.prototype.getTitle = function () { 24312 var title 24313 var $e = this.$element 24314 var o = this.options 24315 24316 title = $e.attr('data-original-title') 24317 || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title) 24318 24319 return title 24320 } 24321 24322 Tooltip.prototype.tip = function () { 24323 return this.$tip = this.$tip || $(this.options.template) 24324 } 24325 24326 Tooltip.prototype.arrow = function () { 24327 return this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow') 24328 } 24329 24330 Tooltip.prototype.validate = function () { 24331 if (!this.$element[0].parentNode) { 24332 this.hide() 24333 this.$element = null 24334 this.options = null 24335 } 24336 } 24337 24338 Tooltip.prototype.enable = function () { 24339 this.enabled = true 24340 } 24341 24342 Tooltip.prototype.disable = function () { 24343 this.enabled = false 24344 } 24345 24346 Tooltip.prototype.toggleEnabled = function () { 24347 this.enabled = !this.enabled 24348 } 24349 24350 Tooltip.prototype.toggle = function (e) { 24351 var self = e ? $(e.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) : this 24352 self.tip().hasClass('in') ? self.leave(self) : self.enter(self) 24353 } 24354 24355 Tooltip.prototype.destroy = function () { 24356 clearTimeout(this.timeout) 24357 this.hide().$element.off('.' + this.type).removeData('bs.' + this.type) 24358 } 24359 24360 24361 // TOOLTIP PLUGIN DEFINITION 24362 // ========================= 24363 24364 var old = $.fn.tooltip 24365 24366 $.fn.tooltip = function (option) { 24367 return this.each(function () { 24368 var $this = $(this) 24369 var data = $this.data('bs.tooltip') 24370 var options = typeof option == 'object' && option 24371 24372 if (!data && option == 'destroy') return 24373 if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options))) 24374 if (typeof option == 'string') data[option]() 24375 }) 24376 } 24377 24378 $.fn.tooltip.Constructor = Tooltip 24379 24380 24381 // TOOLTIP NO CONFLICT 24382 // =================== 24383 24384 $.fn.tooltip.noConflict = function () { 24385 $.fn.tooltip = old 24386 return this 24387 } 24388 24389}(jQuery); 24390 24391/* ======================================================================== 24392 * Bootstrap: transition.js v3.1.1 24393 * http://getbootstrap.com/javascript/#transitions 24394 * ======================================================================== 24395 * Copyright 2011-2014 Twitter, Inc. 24396 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 24397 * ======================================================================== */ 24398 24399 24400+function ($) { 24401 'use strict'; 24402 24403 // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) 24404 // ============================================================ 24405 24406 function transitionEnd() { 24407 var el = document.createElement('bootstrap') 24408 24409 var transEndEventNames = { 24410 WebkitTransition : 'webkitTransitionEnd', 24411 MozTransition : 'transitionend', 24412 OTransition : 'oTransitionEnd otransitionend', 24413 transition : 'transitionend' 24414 } 24415 24416 for (var name in transEndEventNames) { 24417 if (el.style[name] !== undefined) { 24418 return { end: transEndEventNames[name] } 24419 } 24420 } 24421 24422 return false // explicit for ie8 ( ._.) 24423 } 24424 24425 // http://blog.alexmaccaw.com/css-transitions 24426 $.fn.emulateTransitionEnd = function (duration) { 24427 var called = false, $el = this 24428 $(this).one($.support.transition.end, function () { called = true }) 24429 var callback = function () { if (!called) $($el).trigger($.support.transition.end) } 24430 setTimeout(callback, duration) 24431 return this 24432 } 24433 24434 $(function () { 24435 $.support.transition = transitionEnd() 24436 }) 24437 24438}(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.