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 v2.2.2 293 * 294 * Licensed GPLv3 for open source use 295 * or Isotope Commercial License for commercial use 296 * 297 * http://isotope.metafizzy.co 298 * Copyright 2015 Metafizzy 299 */ 300 301/** 302 * Bridget makes jQuery widgets 303 * v1.1.0 304 * MIT license 305 */ 306 307( function( window ) { 308 309 310 311// -------------------------- utils -------------------------- // 312 313var slice = Array.prototype.slice; 314 315function noop() {} 316 317// -------------------------- definition -------------------------- // 318 319function defineBridget( $ ) { 320 321// bail if no jQuery 322if ( !$ ) { 323 return; 324} 325 326// -------------------------- addOptionMethod -------------------------- // 327 328/** 329 * adds option method -> $().plugin('option', {...}) 330 * @param {Function} PluginClass - constructor class 331 */ 332function addOptionMethod( PluginClass ) { 333 // don't overwrite original option method 334 if ( PluginClass.prototype.option ) { 335 return; 336 } 337 338 // option setter 339 PluginClass.prototype.option = function( opts ) { 340 // bail out if not an object 341 if ( !$.isPlainObject( opts ) ){ 342 return; 343 } 344 this.options = $.extend( true, this.options, opts ); 345 }; 346} 347 348// -------------------------- plugin bridge -------------------------- // 349 350// helper function for logging errors 351// $.error breaks jQuery chaining 352var logError = typeof console === 'undefined' ? noop : 353 function( message ) { 354 console.error( message ); 355 }; 356 357/** 358 * jQuery plugin bridge, access methods like $elem.plugin('method') 359 * @param {String} namespace - plugin name 360 * @param {Function} PluginClass - constructor class 361 */ 362function bridge( namespace, PluginClass ) { 363 // add to jQuery fn namespace 364 $.fn[ namespace ] = function( options ) { 365 if ( typeof options === 'string' ) { 366 // call plugin method when first argument is a string 367 // get arguments for method 368 var args = slice.call( arguments, 1 ); 369 370 for ( var i=0, len = this.length; i < len; i++ ) { 371 var elem = this[i]; 372 var instance = $.data( elem, namespace ); 373 if ( !instance ) { 374 logError( "cannot call methods on " + namespace + " prior to initialization; " + 375 "attempted to call '" + options + "'" ); 376 continue; 377 } 378 if ( !$.isFunction( instance[options] ) || options.charAt(0) === '_' ) { 379 logError( "no such method '" + options + "' for " + namespace + " instance" ); 380 continue; 381 } 382 383 // trigger method with arguments 384 var returnValue = instance[ options ].apply( instance, args ); 385 386 // break look and return first value if provided 387 if ( returnValue !== undefined ) { 388 return returnValue; 389 } 390 } 391 // return this if no return value 392 return this; 393 } else { 394 return this.each( function() { 395 var instance = $.data( this, namespace ); 396 if ( instance ) { 397 // apply options & init 398 instance.option( options ); 399 instance._init(); 400 } else { 401 // initialize new instance 402 instance = new PluginClass( this, options ); 403 $.data( this, namespace, instance ); 404 } 405 }); 406 } 407 }; 408 409} 410 411// -------------------------- bridget -------------------------- // 412 413/** 414 * converts a Prototypical class into a proper jQuery plugin 415 * the class must have a ._init method 416 * @param {String} namespace - plugin name, used in $().pluginName 417 * @param {Function} PluginClass - constructor class 418 */ 419$.bridget = function( namespace, PluginClass ) { 420 addOptionMethod( PluginClass ); 421 bridge( namespace, PluginClass ); 422}; 423 424return $.bridget; 425 426} 427 428// transport 429if ( typeof define === 'function' && define.amd ) { 430 // AMD 431 define( 'jquery-bridget/jquery.bridget',[ 'jquery' ], defineBridget ); 432} else if ( typeof exports === 'object' ) { 433 defineBridget( require('jquery') ); 434} else { 435 // get jquery from browser global 436 defineBridget( window.jQuery ); 437} 438 439})( window ); 440 441/*! 442 * eventie v1.0.6 443 * event binding helper 444 * eventie.bind( elem, 'click', myFn ) 445 * eventie.unbind( elem, 'click', myFn ) 446 * MIT license 447 */ 448 449/*jshint browser: true, undef: true, unused: true */ 450/*global define: false, module: false */ 451 452( function( window ) { 453 454 455 456var docElem = document.documentElement; 457 458var bind = function() {}; 459 460function getIEEvent( obj ) { 461 var event = window.event; 462 // add event.target 463 event.target = event.target || event.srcElement || obj; 464 return event; 465} 466 467if ( docElem.addEventListener ) { 468 bind = function( obj, type, fn ) { 469 obj.addEventListener( type, fn, false ); 470 }; 471} else if ( docElem.attachEvent ) { 472 bind = function( obj, type, fn ) { 473 obj[ type + fn ] = fn.handleEvent ? 474 function() { 475 var event = getIEEvent( obj ); 476 fn.handleEvent.call( fn, event ); 477 } : 478 function() { 479 var event = getIEEvent( obj ); 480 fn.call( obj, event ); 481 }; 482 obj.attachEvent( "on" + type, obj[ type + fn ] ); 483 }; 484} 485 486var unbind = function() {}; 487 488if ( docElem.removeEventListener ) { 489 unbind = function( obj, type, fn ) { 490 obj.removeEventListener( type, fn, false ); 491 }; 492} else if ( docElem.detachEvent ) { 493 unbind = function( obj, type, fn ) { 494 obj.detachEvent( "on" + type, obj[ type + fn ] ); 495 try { 496 delete obj[ type + fn ]; 497 } catch ( err ) { 498 // can't delete window object properties 499 obj[ type + fn ] = undefined; 500 } 501 }; 502} 503 504var eventie = { 505 bind: bind, 506 unbind: unbind 507}; 508 509// ----- module definition ----- // 510 511if ( typeof define === 'function' && define.amd ) { 512 // AMD 513 define( 'eventie/eventie',eventie ); 514} else if ( typeof exports === 'object' ) { 515 // CommonJS 516 module.exports = eventie; 517} else { 518 // browser global 519 window.eventie = eventie; 520} 521 522})( window ); 523 524/*! 525 * EventEmitter v4.2.11 - git.io/ee 526 * Unlicense - http://unlicense.org/ 527 * Oliver Caldwell - http://oli.me.uk/ 528 * @preserve 529 */ 530 531;(function () { 532 'use strict'; 533 534 /** 535 * Class for managing events. 536 * Can be extended to provide event functionality in other classes. 537 * 538 * @class EventEmitter Manages event registering and emitting. 539 */ 540 function EventEmitter() {} 541 542 // Shortcuts to improve speed and size 543 var proto = EventEmitter.prototype; 544 var exports = this; 545 var originalGlobalValue = exports.EventEmitter; 546 547 /** 548 * Finds the index of the listener for the event in its storage array. 549 * 550 * @param {Function[]} listeners Array of listeners to search through. 551 * @param {Function} listener Method to look for. 552 * @return {Number} Index of the specified listener, -1 if not found 553 * @api private 554 */ 555 function indexOfListener(listeners, listener) { 556 var i = listeners.length; 557 while (i--) { 558 if (listeners[i].listener === listener) { 559 return i; 560 } 561 } 562 563 return -1; 564 } 565 566 /** 567 * Alias a method while keeping the context correct, to allow for over
vendor: 16,384 bytes, lines 567-970
567writing of target method. 568 * 569 * @param {String} name The name of the target method. 570 * @return {Function} The aliased method 571 * @api private 572 */ 573 function alias(name) { 574 return function aliasClosure() { 575 return this[name].apply(this, arguments); 576 }; 577 } 578 579 /** 580 * Returns the listener array for the specified event. 581 * Will initialise the event object and listener arrays if required. 582 * Will return an object if you use a regex search. The object contains keys for each matched event. So /ba[rz]/ might return an object containing bar and baz. But only if you have either defined them with defineEvent or added some listeners to them. 583 * Each property in the object response is an array of listener functions. 584 * 585 * @param {String|RegExp} evt Name of the event to return the listeners from. 586 * @return {Function[]|Object} All listener functions for the event. 587 */ 588 proto.getListeners = function getListeners(evt) { 589 var events = this._getEvents(); 590 var response; 591 var key; 592 593 // Return a concatenated array of all matching events if 594 // the selector is a regular expression. 595 if (evt instanceof RegExp) { 596 response = {}; 597 for (key in events) { 598 if (events.hasOwnProperty(key) && evt.test(key)) { 599 response[key] = events[key]; 600 } 601 } 602 } 603 else { 604 response = events[evt] || (events[evt] = []); 605 } 606 607 return response; 608 }; 609 610 /** 611 * Takes a list of listener objects and flattens it into a list of listener functions. 612 * 613 * @param {Object[]} listeners Raw listener objects. 614 * @return {Function[]} Just the listener functions. 615 */ 616 proto.flattenListeners = function flattenListeners(listeners) { 617 var flatListeners = []; 618 var i; 619 620 for (i = 0; i < listeners.length; i += 1) { 621 flatListeners.push(listeners[i].listener); 622 } 623 624 return flatListeners; 625 }; 626 627 /** 628 * Fetches the requested listeners via getListeners but will always return the results inside an object. This is mainly for internal use but others may find it useful. 629 * 630 * @param {String|RegExp} evt Name of the event to return the listeners from. 631 * @return {Object} All listener functions for an event in an object. 632 */ 633 proto.getListenersAsObject = function getListenersAsObject(evt) { 634 var listeners = this.getListeners(evt); 635 var response; 636 637 if (listeners instanceof Array) { 638 response = {}; 639 response[evt] = listeners; 640 } 641 642 return response || listeners; 643 }; 644 645 /** 646 * Adds a listener function to the specified event. 647 * The listener will not be added if it is a duplicate. 648 * If the listener returns true then it will be removed after it is called. 649 * If you pass a regular expression as the event name then the listener will be added to all events that match it. 650 * 651 * @param {String|RegExp} evt Name of the event to attach the listener to. 652 * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling. 653 * @return {Object} Current instance of EventEmitter for chaining. 654 */ 655 proto.addListener = function addListener(evt, listener) { 656 var listeners = this.getListenersAsObject(evt); 657 var listenerIsWrapped = typeof listener === 'object'; 658 var key; 659 660 for (key in listeners) { 661 if (listeners.hasOwnProperty(key) && indexOfListener(listeners[key], listener) === -1) { 662 listeners[key].push(listenerIsWrapped ? listener : { 663 listener: listener, 664 once: false 665 }); 666 } 667 } 668 669 return this; 670 }; 671 672 /** 673 * Alias of addListener 674 */ 675 proto.on = alias('addListener'); 676 677 /** 678 * Semi-alias of addListener. It will add a listener that will be 679 * automatically removed after its first execution. 680 * 681 * @param {String|RegExp} evt Name of the event to attach the listener to. 682 * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling. 683 * @return {Object} Current instance of EventEmitter for chaining. 684 */ 685 proto.addOnceListener = function addOnceListener(evt, listener) { 686 return this.addListener(evt, { 687 listener: listener, 688 once: true 689 }); 690 }; 691 692 /** 693 * Alias of addOnceListener. 694 */ 695 proto.once = alias('addOnceListener'); 696 697 /** 698 * Defines an event name. This is required if you want to use a regex to add a listener to multiple events at once. If you don't do this then how do you expect it to know what event to add to? Should it just add to every possible match for a regex? No. That is scary and bad. 699 * You need to tell it what event names should be matched by a regex. 700 * 701 * @param {String} evt Name of the event to create. 702 * @return {Object} Current instance of EventEmitter for chaining. 703 */ 704 proto.defineEvent = function defineEvent(evt) { 705 this.getListeners(evt); 706 return this; 707 }; 708 709 /** 710 * Uses defineEvent to define multiple events. 711 * 712 * @param {String[]} evts An array of event names to define. 713 * @return {Object} Current instance of EventEmitter for chaining. 714 */ 715 proto.defineEvents = function defineEvents(evts) { 716 for (var i = 0; i < evts.length; i += 1) { 717 this.defineEvent(evts[i]); 718 } 719 return this; 720 }; 721 722 /** 723 * Removes a listener function from the specified event. 724 * When passed a regular expression as the event name, it will remove the listener from all events that match it. 725 * 726 * @param {String|RegExp} evt Name of the event to remove the listener from. 727 * @param {Function} listener Method to remove from the event. 728 * @return {Object} Current instance of EventEmitter for chaining. 729 */ 730 proto.removeListener = function removeListener(evt, listener) { 731 var listeners = this.getListenersAsObject(evt); 732 var index; 733 var key; 734 735 for (key in listeners) { 736 if (listeners.hasOwnProperty(key)) { 737 index = indexOfListener(listeners[key], listener); 738 739 if (index !== -1) { 740 listeners[key].splice(index, 1); 741 } 742 } 743 } 744 745 return this; 746 }; 747 748 /** 749 * Alias of removeListener 750 */ 751 proto.off = alias('removeListener'); 752 753 /** 754 * Adds listeners in bulk using the manipulateListeners method. 755 * If you pass an object as the second argument you can add to multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. You can also pass it an event name and an array of listeners to be added. 756 * You can also pass it a regular expression to add the array of listeners to all events that match it. 757 * Yeah, this function does quite a bit. That's probably a bad thing. 758 * 759 * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add to multiple events at once. 760 * @param {Function[]} [listeners] An optional array of listener functions to add. 761 * @return {Object} Current instance of EventEmitter for chaining. 762 */ 763 proto.addListeners = function addListeners(evt, listeners) { 764 // Pass through to manipulateListeners 765 return this.manipulateListeners(false, evt, listeners); 766 }; 767 768 /** 769 * Removes listeners in bulk using the manipulateListeners method. 770 * If you pass an object as the second argument you can remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. 771 * You can also pass it an event name and an array of listeners to be removed. 772 * You can also pass it a regular expression to remove the listeners from all events that match it. 773 * 774 * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to remove from multiple events at once. 775 * @param {Function[]} [listeners] An optional array of listener functions to remove. 776 * @return {Object} Current instance of EventEmitter for chaining. 777 */ 778 proto.removeListeners = function removeListeners(evt, listeners) { 779 // Pass through to manipulateListeners 780 return this.manipulateListeners(true, evt, listeners); 781 }; 782 783 /** 784 * Edits listeners in bulk. The addListeners and removeListeners methods both use this to do their job. You should really use those instead, this is a little lower level. 785 * The first argument will determine if the listeners are removed (true) or added (false). 786 * If you pass an object as the second argument you can add/remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. 787 * You can also pass it an event name and an array of listeners to be added/removed. 788 * You can also pass it a regular expression to manipulate the listeners of all events that match it. 789 * 790 * @param {Boolean} remove True if you want to remove listeners, false if you want to add. 791 * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add/remove from multiple events at once. 792 * @param {Function[]} [listeners] An optional array of listener functions to add/remove. 793 * @return {Object} Current instance of EventEmitter for chaining. 794 */ 795 proto.manipulateListeners = function manipulateListeners(remove, evt, listeners) { 796 var i; 797 var value; 798 var single = remove ? this.removeListener : this.addListener; 799 var multiple = remove ? this.removeListeners : this.addListeners; 800 801 // If evt is an object then pass each of its properties to this method 802 if (typeof evt === 'object' && !(evt instanceof RegExp)) { 803 for (i in evt) { 804 if (evt.hasOwnProperty(i) && (value = evt[i])) { 805 // Pass the single listener straight through to the singular method 806 if (typeof value === 'function') { 807 single.call(this, i, value); 808 } 809 else { 810 // Otherwise pass back to the multiple function 811 multiple.call(this, i, value); 812 } 813 } 814 } 815 } 816 else { 817 // So evt must be a string 818 // And listeners must be an array of listeners 819 // Loop over it and pass each one to the multiple method 820 i = listeners.length; 821 while (i--) { 822 single.call(this, evt, listeners[i]); 823 } 824 } 825 826 return this; 827 }; 828 829 /** 830 * Removes all listeners from a specified event. 831 * If you do not specify an event then all listeners will be removed. 832 * That means every event will be emptied. 833 * You can also pass a regex to remove all events that match it. 834 * 835 * @param {String|RegExp} [evt] Optional name of the event to remove all listeners for. Will remove from every event if not passed. 836 * @return {Object} Current instance of EventEmitter for chaining. 837 */ 838 proto.removeEvent = function removeEvent(evt) { 839 var type = typeof evt; 840 var events = this._getEvents(); 841 var key; 842 843 // Remove different things depending on the state of evt 844 if (type === 'string') { 845 // Remove all listeners for the specified event 846 delete events[evt]; 847 } 848 else if (evt instanceof RegExp) { 849 // Remove all events matching the regex. 850 for (key in events) { 851 if (events.hasOwnProperty(key) && evt.test(key)) { 852 delete events[key]; 853 } 854 } 855 } 856 else { 857 // Remove all listeners in all events 858 delete this._events; 859 } 860 861 return this; 862 }; 863 864 /** 865 * Alias of removeEvent. 866 * 867 * Added to mirror the node API. 868 */ 869 proto.removeAllListeners = alias('removeEvent'); 870 871 /** 872 * Emits an event of your choice. 873 * When emitted, every listener attached to that event will be executed. 874 * If you pass the optional argument array then those arguments will be passed to every listener upon execution. 875 * Because it uses `apply`, your array of arguments will be passed as if you wrote them out separately. 876 * So they will not arrive within the array on the other side, they will be separate. 877 * You can also pass a regular expression to emit to all events that match it. 878 * 879 * @param {String|RegExp} evt Name of the event to emit and execute listeners for. 880 * @param {Array} [args] Optional array of arguments to be passed to each listener. 881 * @return {Object} Current instance of EventEmitter for chaining. 882 */ 883 proto.emitEvent = function emitEvent(evt, args) { 884 var listeners = this.getListenersAsObject(evt); 885 var listener; 886 var i; 887 var key; 888 var response; 889 890 for (key in listeners) { 891 if (listeners.hasOwnProperty(key)) { 892 i = listeners[key].length; 893 894 while (i--) { 895 // If the listener returns true then it shall be removed from the event 896 // The function is executed either with a basic call or an apply if there is an args array 897 listener = listeners[key][i]; 898 899 if (listener.once === true) { 900 this.removeListener(evt, listener.listener); 901 } 902 903 response = listener.listener.apply(this, args || []); 904 905 if (response === this._getOnceReturnValue()) { 906 this.removeListener(evt, listener.listener); 907 } 908 } 909 } 910 } 911 912 return this; 913 }; 914 915 /** 916 * Alias of emitEvent 917 */ 918 proto.trigger = alias('emitEvent'); 919 920 /** 921 * Subtly different from emitEvent in that it will pass its arguments on to the listeners, as opposed to taking a single array of arguments to pass on. 922 * As with emitEvent, you can pass a regex in place of the event name to emit to all events that match it. 923 * 924 * @param {String|RegExp} evt Name of the event to emit and execute listeners for. 925 * @param {...*} Optional additional arguments to be passed to each listener. 926 * @return {Object} Current instance of EventEmitter for chaining. 927 */ 928 proto.emit = function emit(evt) { 929 var args = Array.prototype.slice.call(arguments, 1); 930 return this.emitEvent(evt, args); 931 }; 932 933 /** 934 * Sets the current value to check against when executing listeners. If a 935 * listeners return value matches the one set here then it will be removed 936 * after execution. This value defaults to true. 937 * 938 * @param {*} value The new value to check for when executing listeners. 939 * @return {Object} Current instance of EventEmitter for chaining. 940 */ 941 proto.setOnceReturnValue = function setOnceReturnValue(value) { 942 this._onceReturnValue = value; 943 return this; 944 }; 945 946 /** 947 * Fetches the current value to check against when executing listeners. If 948 * the listeners return value matches this one then it should be removed 949 * automatically. It will return true by default. 950 * 951 * @return {*|Boolean} The current value to check for or the default, true. 952 * @api private 953 */ 954 proto._getOnceReturnValue = function _getOnceReturnValue() { 955 if (this.hasOwnProperty('_onceReturnValue')) { 956 return this._onceReturnValue; 957 } 958 else { 959 return true; 960 } 961 }; 962 963 /** 964 * Fetches the events object and creates one if required. 965 * 966 * @return {Object} The events storage object. 967 * @api private 968 */ 969 proto._getEvents = function _getEvents() { 970 return this._events || (this
970._events = {}); 971 }; 972 973 /** 974 * Reverts the global {@link EventEmitter} to its previous value and returns a reference to this version. 975 * 976 * @return {Function} Non conflicting EventEmitter class. 977 */ 978 EventEmitter.noConflict = function noConflict() { 979 exports.EventEmitter = originalGlobalValue; 980 return EventEmitter; 981 }; 982 983 // Expose the class either via AMD, CommonJS or the global object 984 if (typeof define === 'function' && define.amd) { 985 define('eventEmitter/EventEmitter',[],function () { 986 return EventEmitter; 987 }); 988 } 989 else if (typeof module === 'object' && module.exports){ 990 module.exports = EventEmitter; 991 } 992 else { 993 exports.EventEmitter = EventEmitter; 994 } 995}.call(this)); 996 997/*! 998 * getStyleProperty v1.0.4 999 * original by kangax 1000 * http://perfectionkills.com/feature-testing-css-properties/ 1001 * MIT license 1002 */ 1003 1004/*jshint browser: true, strict: true, undef: true */ 1005/*global define: false, exports: false, module: false */ 1006 1007( function( window ) { 1008 1009 1010 1011var prefixes = 'Webkit Moz ms Ms O'.split(' '); 1012var docElemStyle = document.documentElement.style; 1013 1014function getStyleProperty( propName ) { 1015 if ( !propName ) { 1016 return; 1017 } 1018 1019 // test standard property first 1020 if ( typeof docElemStyle[ propName ] === 'string' ) { 1021 return propName; 1022 } 1023 1024 // capitalize 1025 propName = propName.charAt(0).toUpperCase() + propName.slice(1); 1026 1027 // test vendor specific properties 1028 var prefixed; 1029 for ( var i=0, len = prefixes.length; i < len; i++ ) { 1030 prefixed = prefixes[i] + propName; 1031 if ( typeof docElemStyle[ prefixed ] === 'string' ) { 1032 return prefixed; 1033 } 1034 } 1035} 1036 1037// transport 1038if ( typeof define === 'function' && define.amd ) { 1039 // AMD 1040 define( 'get-style-property/get-style-property',[],function() { 1041 return getStyleProperty; 1042 }); 1043} else if ( typeof exports === 'object' ) { 1044 // CommonJS for Component 1045 module.exports = getStyleProperty; 1046} else { 1047 // browser global 1048 window.getStyleProperty = getStyleProperty; 1049} 1050 1051})( window ); 1052 1053/*! 1054 * getSize v1.2.2 1055 * measure size of elements 1056 * MIT license 1057 */ 1058 1059/*jshint browser: true, strict: true, undef: true, unused: true */ 1060/*global define: false, exports: false, require: false, module: false, console: false */ 1061 1062( function( window, undefined ) { 1063 1064 1065 1066// -------------------------- helpers -------------------------- // 1067 1068// get a number from a string, not a percentage 1069function getStyleSize( value ) { 1070 var num = parseFloat( value ); 1071 // not a percent like '100%', and a number 1072 var isValid = value.indexOf('%') === -1 && !isNaN( num ); 1073 return isValid && num; 1074} 1075 1076function noop() {} 1077 1078var logError = typeof console === 'undefined' ? noop : 1079 function( message ) { 1080 console.error( message ); 1081 }; 1082 1083// -------------------------- measurements -------------------------- // 1084 1085var measurements = [ 1086 'paddingLeft', 1087 'paddingRight', 1088 'paddingTop', 1089 'paddingBottom', 1090 'marginLeft', 1091 'marginRight', 1092 'marginTop', 1093 'marginBottom', 1094 'borderLeftWidth', 1095 'borderRightWidth', 1096 'borderTopWidth', 1097 'borderBottomWidth' 1098]; 1099 1100function getZeroSize() { 1101 var size = { 1102 width: 0, 1103 height: 0, 1104 innerWidth: 0, 1105 innerHeight: 0, 1106 outerWidth: 0, 1107 outerHeight: 0 1108 }; 1109 for ( var i=0, len = measurements.length; i < len; i++ ) { 1110 var measurement = measurements[i]; 1111 size[ measurement ] = 0; 1112 } 1113 return size; 1114} 1115 1116 1117 1118function defineGetSize( getStyleProperty ) { 1119 1120// -------------------------- setup -------------------------- // 1121 1122var isSetup = false; 1123 1124var getStyle, boxSizingProp, isBoxSizeOuter; 1125 1126/** 1127 * setup vars and functions 1128 * do it on initial getSize(), rather than on script load 1129 * For Firefox bug https://bugzilla.mozilla.org/show_bug.cgi?id=548397 1130 */ 1131function setup() { 1132 // setup once 1133 if ( isSetup ) { 1134 return; 1135 } 1136 isSetup = true; 1137 1138 var getComputedStyle = window.getComputedStyle; 1139 getStyle = ( function() { 1140 var getStyleFn = getComputedStyle ? 1141 function( elem ) { 1142 return getComputedStyle( elem, null ); 1143 } : 1144 function( elem ) { 1145 return elem.currentStyle; 1146 }; 1147 1148 return function getStyle( elem ) { 1149 var style = getStyleFn( elem ); 1150 if ( !style ) { 1151 logError( 'Style returned ' + style + 1152 '. Are you running this code in a hidden iframe on Firefox? ' + 1153 'See http://bit.ly/getsizebug1' ); 1154 } 1155 return style; 1156 }; 1157 })(); 1158 1159 // -------------------------- box sizing -------------------------- // 1160 1161 boxSizingProp = getStyleProperty('boxSizing'); 1162 1163 /** 1164 * WebKit measures the outer-width on style.width on border-box elems 1165 * IE & Firefox measures the inner-width 1166 */ 1167 if ( boxSizingProp ) { 1168 var div = document.createElement('div'); 1169 div.style.width = '200px'; 1170 div.style.padding = '1px 2px 3px 4px'; 1171 div.style.borderStyle = 'solid'; 1172 div.style.borderWidth = '1px 2px 3px 4px'; 1173 div.style[ boxSizingProp ] = 'border-box'; 1174 1175 var body = document.body || document.documentElement; 1176 body.appendChild( div ); 1177 var style = getStyle( div ); 1178 1179 isBoxSizeOuter = getStyleSize( style.width ) === 200; 1180 body.removeChild( div ); 1181 } 1182 1183} 1184 1185// -------------------------- getSize -------------------------- // 1186 1187function getSize( elem ) { 1188 setup(); 1189 1190 // use querySeletor if elem is string 1191 if ( typeof elem === 'string' ) { 1192 elem = document.querySelector( elem ); 1193 } 1194 1195 // do not proceed on non-objects 1196 if ( !elem || typeof elem !== 'object' || !elem.nodeType ) { 1197 return; 1198 } 1199 1200 var style = getStyle( elem ); 1201 1202 // if hidden, everything is 0 1203 if ( style.display === 'none' ) { 1204 return getZeroSize(); 1205 } 1206 1207 var size = {}; 1208 size.width = elem.offsetWidth; 1209 size.height = elem.offsetHeight; 1210 1211 var isBorderBox = size.isBorderBox = !!( boxSizingProp && 1212 style[ boxSizingProp ] && style[ boxSizingProp ] === 'border-box' ); 1213 1214 // get all measurements 1215 for ( var i=0, len = measurements.length; i < len; i++ ) { 1216 var measurement = measurements[i]; 1217 var value = style[ measurement ]; 1218 value = mungeNonPixel( elem, value ); 1219 var num = parseFloat( value ); 1220 // any 'auto', 'medium' value will be 0 1221 size[ measurement ] = !isNaN( num ) ? num : 0; 1222 } 1223 1224 var paddingWidth = size.paddingLeft + size.paddingRight; 1225 var paddingHeight = size.paddingTop + size.paddingBottom; 1226 var marginWidth = size.marginLeft + size.marginRight; 1227 var marginHeight = size.marginTop + size.marginBottom; 1228 var borderWidth = size.borderLeftWidth + size.borderRightWidth; 1229 var borderHeight = size.borderTopWidth + size.borderBottomWidth; 1230 1231 var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter; 1232 1233 // overwrite width and height if we can get it from style 1234 var styleWidth = getStyleSize( style.width ); 1235 if ( styleWidth !== false ) { 1236 size.width = styleWidth + 1237 // add padding and border unless it's already including it 1238 ( isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth ); 1239 } 1240 1241 var styleHeight = getStyleSize( style.height ); 1242 if ( styleHeight !== false ) { 1243 size.height = styleHeight + 1244 // add padding and border unless it's already including it 1245 ( isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight ); 1246 } 1247 1248 size.innerWidth = size.width - ( paddingWidth + borderWidth );
1249 size.innerHeight = size.height - ( paddingHeight + borderHeight ); 1250 1251 size.outerWidth = size.width + marginWidth; 1252 size.outerHeight = size.height + marginHeight; 1253 1254 return size; 1255} 1256 1257// IE8 returns percent values, not pixels 1258// taken from jQuery's curCSS 1259function mungeNonPixel( elem, value ) { 1260 // IE8 and has percent value 1261 if ( window.getComputedStyle || value.indexOf('%') === -1 ) { 1262 return value; 1263 } 1264 var style = elem.style; 1265 // Remember the original values 1266 var left = style.left; 1267 var rs = elem.runtimeStyle; 1268 var rsLeft = rs && rs.left; 1269 1270 // Put in the new values to get a computed value out 1271 if ( rsLeft ) { 1272 rs.left = elem.currentStyle.left; 1273 } 1274 style.left = value; 1275 value = style.pixelLeft; 1276 1277 // Revert the changed values 1278 style.left = left; 1279 if ( rsLeft ) { 1280 rs.left = rsLeft; 1281 } 1282 1283 return value; 1284} 1285 1286return getSize; 1287 1288} 1289 1290// transport 1291if ( typeof define === 'function' && define.amd ) { 1292 // AMD for RequireJS 1293 define( 'get-size/get-size',[ 'get-style-property/get-style-property' ], defineGetSize ); 1294} else if ( typeof exports === 'object' ) { 1295 // CommonJS for Component 1296 module.exports = defineGetSize( require('desandro-get-style-property') ); 1297} else { 1298 // browser global 1299 window.getSize = defineGetSize( window.getStyleProperty ); 1300} 1301 1302})( window ); 1303 1304/*! 1305 * docReady v1.0.4 1306 * Cross browser DOMContentLoaded event emitter 1307 * MIT license 1308 */ 1309 1310/*jshint browser: true, strict: true, undef: true, unused: true*/ 1311/*global define: false, require: false, module: false */ 1312 1313( function( window ) { 1314 1315 1316 1317var document = window.document; 1318// collection of functions to be triggered on ready 1319var queue = []; 1320 1321function docReady( fn ) { 1322 // throw out non-functions 1323 if ( typeof fn !== 'function' ) { 1324 return; 1325 } 1326 1327 if ( docReady.isReady ) { 1328 // ready now, hit it 1329 fn(); 1330 } else { 1331 // queue function when ready 1332 queue.push( fn ); 1333 } 1334} 1335 1336docReady.isReady = false; 1337 1338// triggered on various doc ready events 1339function onReady( event ) { 1340 // bail if already triggered or IE8 document is not ready just yet 1341 var isIE8NotReady = event.type === 'readystatechange' && document.readyState !== 'complete'; 1342 if ( docReady.isReady || isIE8NotReady ) { 1343 return; 1344 } 1345 1346 trigger(); 1347} 1348 1349function trigger() { 1350 docReady.isReady = true; 1351 // process queue 1352 for ( var i=0, len = queue.length; i < len; i++ ) { 1353 var fn = queue[i]; 1354 fn(); 1355 } 1356} 1357 1358function defineDocReady( eventie ) { 1359 // trigger ready if page is ready 1360 if ( document.readyState === 'complete' ) { 1361 trigger(); 1362 } else { 1363 // listen for events 1364 eventie.bind( document, 'DOMContentLoaded', onReady ); 1365 eventie.bind( document, 'readystatechange', onReady ); 1366 eventie.bind( window, 'load', onReady ); 1367 } 1368 1369 return docReady; 1370} 1371 1372// transport 1373if ( typeof define === 'function' && define.amd ) { 1374 // AMD 1375 define( 'doc-ready/doc-ready',[ 'eventie/eventie' ], defineDocReady ); 1376} else if ( typeof exports === 'object' ) { 1377 module.exports = defineDocReady( require('eventie') ); 1378} else { 1379 // browser global 1380 window.docReady = defineDocReady( window.eventie ); 1381} 1382 1383})( window ); 1384 1385/** 1386 * matchesSelector v1.0.3 1387 * matchesSelector( element, '.selector' ) 1388 * MIT license 1389 */ 1390 1391/*jshint browser: true, strict: true, undef: true, unused: true */ 1392/*global define: false, module: false */ 1393 1394( function( ElemProto ) { 1395 1396 'use strict'; 1397 1398 var matchesMethod = ( function() { 1399 // check for the standard method name first 1400 if ( ElemProto.matches ) { 1401 return 'matches'; 1402 } 1403 // check un-prefixed 1404 if ( ElemProto.matchesSelector ) { 1405 return 'matchesSelector'; 1406 } 1407 // check vendor prefixes 1408 var prefixes = [ 'webkit', 'moz', 'ms', 'o' ]; 1409 1410 for ( var i=0, len = prefixes.length; i < len; i++ ) { 1411 var prefix = prefixes[i]; 1412 var method = prefix + 'MatchesSelector'; 1413 if ( ElemProto[ method ] ) { 1414 return method; 1415 } 1416 } 1417 })(); 1418 1419 // ----- match ----- // 1420 1421 function match( elem, selector ) { 1422 return elem[ matchesMethod ]( selector ); 1423 } 1424 1425 // ----- appendToFragment ----- // 1426 1427 function checkParent( elem ) { 1428 // not needed if already has parent 1429 if ( elem.parentNode ) { 1430 return; 1431 } 1432 var fragment = document.createDocumentFragment(); 1433 fragment.appendChild( elem ); 1434 } 1435 1436 // ----- query ----- // 1437 1438 // fall back to using QSA 1439 // thx @jonathantneal https://gist.github.com/3062955 1440 function query( elem, selector ) { 1441 // append to fragment if no parent 1442 checkParent( elem ); 1443 1444 // match elem with all selected elems of parent 1445 var elems = elem.parentNode.querySelectorAll( selector ); 1446 for ( var i=0, len = elems.length; i < len; i++ ) { 1447 // return true if match 1448 if ( elems[i] === elem ) { 1449 return true; 1450 } 1451 } 1452 // otherwise return false 1453 return false;
1454 } 1455 1456 // ----- matchChild ----- // 1457 1458 function matchChild( elem, selector ) { 1459 checkParent( elem ); 1460 return match( elem, selector ); 1461 } 1462 1463 // ----- matchesSelector ----- // 1464 1465 var matchesSelector; 1466 1467 if ( matchesMethod ) { 1468 // IE9 supports matchesSelector, but doesn't work on orphaned elems 1469 // check for that 1470 var div = document.createElement('div'); 1471 var supportsOrphans = match( div, 'div' ); 1472 matchesSelector = supportsOrphans ? match : matchChild; 1473 } else { 1474 matchesSelector = query; 1475 } 1476 1477 // transport 1478 if ( typeof define === 'function' && define.amd ) { 1479 // AMD 1480 define( 'matches-selector/matches-selector',[],function() { 1481 return matchesSelector; 1482 }); 1483 } else if ( typeof exports === 'object' ) { 1484 module.exports = matchesSelector; 1485 } 1486 else { 1487 // browser global 1488 window.matchesSelector = matchesSelector; 1489 } 1490 1491})( Element.prototype ); 1492 1493/** 1494 * Fizzy UI utils v1.0.1 1495 * MIT license 1496 */ 1497 1498/*jshint browser: true, undef: true, unused: true, strict: true */ 1499 1500( function( window, factory ) { 1501 /*global define: false, module: false, require: false */ 1502 'use strict'; 1503 // universal module definition 1504 1505 if ( typeof define == 'function' && define.amd ) { 1506 // AMD 1507 define( 'fizzy-ui-utils/utils',[ 1508 'doc-ready/doc-ready', 1509 'matches-selector/matches-selector' 1510 ], function( docReady, matchesSelector ) { 1511 return factory( window, docReady, matchesSelector ); 1512 }); 1513 } else if ( typeof exports == 'object' ) { 1514 // CommonJS 1515 module.exports = factory( 1516 window, 1517 require('doc-ready'), 1518 require('desandro-matches-selector') 1519 ); 1520 } else { 1521 // browser global 1522 window.fizzyUIUtils = factory( 1523 window, 1524 window.docReady, 1525 window.matchesSelector 1526 ); 1527 } 1528 1529}( window, function factory( window, docReady, matchesSelector ) { 1530 1531 1532 1533var utils = {}; 1534 1535// ----- extend ----- // 1536 1537// extends objects 1538utils.extend = function( a, b ) { 1539 for ( var prop in b ) { 1540 a[ prop ] = b[ prop ]; 1541 } 1542 return a; 1543}; 1544 1545// ----- modulo ----- // 1546 1547utils.modulo = function( num, div ) { 1548 return ( ( num % div ) + div ) % div; 1549}; 1550 1551// ----- isArray ----- // 1552 1553var objToString = Object.prototype.toString; 1554utils.isArray = function( obj ) { 1555 return objToString.call( obj ) == '[object Array]'; 1556}; 1557 1558// ----- makeArray ----- // 1559 1560// turn element or nodeList into an array 1561utils.makeArray = function( obj ) { 1562 var ary = []; 1563 if ( utils.isArray( obj ) ) { 1564 // use object if already an array 1565 ary = obj; 1566 } else if ( obj && typeof obj.length == 'number' ) { 1567 // convert nodeList to array 1568 for ( var i=0, len = obj.length; i < len; i++ ) { 1569 ary.push( obj[i] ); 1570 } 1571 } else { 1572 // array of single index 1573 ary.push( obj ); 1574 } 1575 return ary; 1576}; 1577 1578// ----- indexOf ----- // 1579 1580// index of helper cause IE8 1581utils.indexOf = Array.prototype.indexOf ? function( ary, obj ) { 1582 return ary.indexOf( obj ); 1583 } : function( ary, obj ) { 1584 for ( var i=0, len = ary.length; i < len; i++ ) { 1585 if ( ary[i] === obj ) { 1586 return i; 1587 } 1588 } 1589 return -1; 1590 }; 1591 1592// ----- removeFrom ----- // 1593 1594utils.removeFrom = function( ary, obj ) { 1595 var index = utils.indexOf( ary, obj ); 1596 if ( index != -1 ) { 1597 ary.splice( index, 1 ); 1598 } 1599}; 1600 1601// ----- isElement ----- // 1602 1603// http://stackoverflow.com/a/384380/182183 1604utils.isElement = ( typeof HTMLElement == 'function' || typeof HTMLElement == 'object' ) ? 1605 function isElementDOM2( obj ) { 1606 return obj instanceof HTMLElement; 1607 } : 1608 function isElementQuirky( obj ) { 1609 return obj && typeof obj == 'object' && 1610 obj.nodeType == 1 && typeof obj.nodeName == 'string'; 1611 }; 1612 1613// ----- setText ----- // 1614 1615utils.setText = ( function() { 1616 var setTextProperty; 1617 function setText( elem, text ) { 1618 // only check setTextProperty once 1619 setTextProperty = setTextProperty || ( document.documentElement.textContent !== undefined ? 'textContent' : 'innerText' ); 1620 elem[ setTextProperty ] = text; 1621 } 1622 return setText; 1623})(); 1624 1625// ----- getParent ----- // 1626 1627utils.getParent = function( elem, selector ) { 1628 while ( elem != document.body ) { 1629 elem = elem.parentNode; 1630 if ( matchesSelector( elem, selector ) ) { 1631 return elem; 1632 } 1633 } 1634}; 1635 1636// ----- getQueryElement ----- // 1637 1638// use element as selector string 1639utils.getQueryElement = function( elem ) { 1640 if ( typeof elem == 'string' ) { 1641 return document.querySelector( elem ); 1642 } 1643 return elem; 1644}; 1645 1646// ----- handleEvent ----- // 1647 1648// enable .ontype to trigger from .addEventListener( elem, 'type' ) 1649utils.handleEvent = function( event ) { 1650 var method = 'on' + event.type; 1651 if ( this[ method ] ) { 1652 this[ method ]( event ); 1653 } 1654}; 1655 1656// ----- filterFindElements ----- // 1657 1658utils.filterFindElements = function( elems, selector ) { 1659 // make array of elems 1660 elems = utils.makeArray( elems ); 1661 var ffElems = []; 1662 1663 for ( var i=0, len = elems.length; i < len; i++ ) { 1664 var elem = elems[i]; 1665 // check that elem is an actual element 1666 if ( !utils.isElement( elem ) ) { 1667 continue; 1668 } 1669 // filter & find items if we have a selector 1670 if ( selector ) { 1671 // filter siblings 1672 if ( matchesSelector( elem, selector ) ) { 1673 ffElems.push( elem ); 1674 } 1675 // find children 1676 var childElems = elem.querySelectorAll( selector ); 1677 // concat childElems to filterFound array 1678 for ( var j=0, jLen = childElems.length; j < jLen; j++ ) { 1679 ffElems.push( childElems[j] ); 1680 } 1681 } else { 1682 ffElems.push( elem ); 1683 } 1684 } 1685 1686 return ffElems; 1687}; 1688 1689// ----- debounceMethod ----- // 1690 1691utils.debounceMethod = function( _class, methodName, threshold ) { 1692 // original method 1693 var method = _class.prototype[ methodName ]; 1694 var timeoutName = methodName + 'Timeout'; 1695 1696 _class.prototype[ methodName ] = function() { 1697 var timeout = this[ timeoutName ]; 1698 if ( timeout ) { 1699 clearTimeout( timeout ); 1700 } 1701 var args = arguments; 1702 1703 var _this = this; 1704 this[ timeoutName ] = setTimeout( function() { 1705 method.apply( _this, args ); 1706 delete _this[ timeoutName ]; 1707 }, threshold || 100 ); 1708 }; 1709}; 1710 1711// ----- htmlInit ----- // 1712 1713// http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/ 1714utils.toDashed = function( str ) { 1715 return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) { 1716 return $1 + '-' + $2; 1717 }).toLowerCase(); 1718}; 1719
1720var console = window.console; 1721/** 1722 * allow user to initialize classes via .js-namespace class 1723 * htmlInit( Widget, 'widgetName' ) 1724 * options are parsed from data-namespace-option attribute 1725 */ 1726utils.htmlInit = function( WidgetClass, namespace ) { 1727 docReady( function() { 1728 var dashedNamespace = utils.toDashed( namespace ); 1729 var elems = document.querySelectorAll( '.js-' + dashedNamespace ); 1730 var dataAttr = 'data-' + dashedNamespace + '-options'; 1731 1732 for ( var i=0, len = elems.length; i < len; i++ ) { 1733 var elem = elems[i]; 1734 var attr = elem.getAttribute( dataAttr ); 1735 var options; 1736 try { 1737 options = attr && JSON.parse( attr ); 1738 } catch ( error ) { 1739 // log error, do not initialize 1740 if ( console ) { 1741 console.error( 'Error parsing ' + dataAttr + ' on ' + 1742 elem.nodeName.toLowerCase() + ( elem.id ? '#' + elem.id : '' ) + ': ' + 1743 error ); 1744 } 1745 continue; 1746 } 1747 // initialize 1748 var instance = new WidgetClass( elem, options ); 1749 // make available via $().data('layoutname') 1750 var jQuery = window.jQuery; 1751 if ( jQuery ) { 1752 jQuery.data( elem, namespace, instance ); 1753 } 1754 } 1755 }); 1756}; 1757 1758// ----- ----- // 1759 1760return utils; 1761 1762})); 1763 1764/** 1765 * Outlayer Item 1766 */ 1767 1768( function( window, factory ) { 1769 'use strict'; 1770 // universal module definition 1771 if ( typeof define === 'function' && define.amd ) { 1772 // AMD 1773 define( 'outlayer/item',[ 1774 'eventEmitter/EventEmitter', 1775 'get-size/get-size', 1776 'get-style-property/get-style-property', 1777 'fizzy-ui-utils/utils' 1778 ], 1779 function( EventEmitter, getSize, getStyleProperty, utils ) { 1780 return factory( window, EventEmitter, getSize, getStyleProperty, utils ); 1781 } 1782 ); 1783 } else if (typeof exports === 'object') { 1784 // CommonJS 1785 module.exports = factory( 1786 window, 1787 require('wolfy87-eventemitter'), 1788 require('get-size'), 1789 require('desandro-get-style-property'), 1790 require('fizzy-ui-utils') 1791 ); 1792 } else { 1793 // browser global 1794 window.Outlayer = {}; 1795 window.Outlayer.Item = factory( 1796 window, 1797 window.EventEmitter, 1798 window.getSize, 1799 window.getStyleProperty, 1800 window.fizzyUIUtils 1801 ); 1802 } 1803 1804}( window, function factory( window, EventEmitter, getSize, getStyleProperty, utils ) { 1805'use strict'; 1806 1807// ----- helpers ----- // 1808 1809var getComputedStyle = window.getComputedStyle; 1810var getStyle = getComputedStyle ? 1811 function( elem ) { 1812 return getComputedStyle( elem, null ); 1813 } : 1814 function( elem ) { 1815 return elem.currentStyle; 1816 }; 1817 1818 1819function isEmptyObj( obj ) { 1820 for ( var prop in obj ) { 1821 return false; 1822 } 1823 prop = null; 1824 return true; 1825} 1826 1827// -------------------------- CSS3 support -------------------------- // 1828 1829var transitionProperty = getStyleProperty('transition'); 1830var transformProperty = getStyleProperty('transform'); 1831var supportsCSS3 = transitionProperty && transformProperty; 1832var is3d = !!getStyleProperty('perspective'); 1833 1834var transitionEndEvent = { 1835 WebkitTransition: 'webkitTransitionEnd', 1836 MozTransition: 'transitionend', 1837 OTransition: 'otransitionend', 1838 transition: 'transitionend' 1839}[ transitionProperty ]; 1840 1841// properties that could have vendor prefix 1842var prefixableProperties = [ 1843 'transform', 1844 'transition', 1845 'transitionDuration', 1846 'transitionProperty' 1847]; 1848 1849// cache all vendor properties 1850var vendorProperties = ( function() { 1851 var cache = {}; 1852 for ( var i=0, len = prefixableProperties.length; i < len; i++ ) { 1853 var prop = prefixableProperties[i]; 1854 var supportedProp = getStyleProperty( prop ); 1855 if ( supportedProp && supportedProp !== prop ) { 1856 cache[ prop ] = supportedProp; 1857 } 1858 } 1859 return cache; 1860})(); 1861 1862// -------------------------- Item -------------------------- // 1863 1864function Item( element, layout ) { 1865 if ( !element ) { 1866 return; 1867 } 1868 1869 this.element = element; 1870 // parent layout class, i.e. Masonry, Isotope, or Packery 1871 this.layout = layout; 1872 this.position = { 1873 x: 0, 1874 y: 0 1875 }; 1876 1877 this._create(); 1878} 1879 1880// inherit EventEmitter 1881utils.extend( Item.prototype, EventEmitter.prototype ); 1882 1883Item.prototype._create = function() { 1884 // transition objects 1885 this._transn = { 1886 ingProperties: {}, 1887 clean: {}, 1888 onEnd: {} 1889 }; 1890 1891 this.css({ 1892 position: 'absolute' 1893 }); 1894}; 1895 1896// trigger specified handler for event type 1897Item.prototype.handleEvent = function( event ) { 1898 var method = 'on' + event.type; 1899 if ( this[ method ] ) { 1900 this[ method ]( event ); 1901 } 1902}; 1903 1904Item.prototype.getSize = function() { 1905 this.size = getSize( this.element ); 1906}; 1907 1908/** 1909 * apply CSS styles to element 1910 * @param {Object} style 1911 */ 1912Item.prototype.css = function( style ) { 1913 var elemStyle = this.element.style; 1914 1915 for ( var prop in style ) { 1916 // use vendor property if available
1917 var supportedProp = vendorProperties[ prop ] || prop; 1918 elemStyle[ supportedProp ] = style[ prop ]; 1919 } 1920}; 1921 1922 // measure position, and sets it 1923Item.prototype.getPosition = function() { 1924 var style = getStyle( this.element ); 1925 var layoutOptions = this.layout.options; 1926 var isOriginLeft = layoutOptions.isOriginLeft; 1927 var isOriginTop = layoutOptions.isOriginTop; 1928 var xValue = style[ isOriginLeft ? 'left' : 'right' ]; 1929 var yValue = style[ isOriginTop ? 'top' : 'bottom' ]; 1930 // convert percent to pixels 1931 var layoutSize = this.layout.size; 1932 var x = xValue.indexOf('%') != -1 ? 1933 ( parseFloat( xValue ) / 100 ) * layoutSize.width : parseInt( xValue, 10 ); 1934 var y = yValue.indexOf('%') != -1 ? 1935 ( parseFloat( yValue ) / 100 ) * layoutSize.height : parseInt( yValue, 10 ); 1936 1937 // clean up 'auto' or other non-integer values 1938 x = isNaN( x ) ? 0 : x; 1939 y = isNaN( y ) ? 0 : y; 1940 // remove padding from measurement 1941 x -= isOriginLeft ? layoutSize.paddingLeft : layoutSize.paddingRight; 1942 y -= isOriginTop ? layoutSize.paddingTop : layoutSize.paddingBottom; 1943 1944 this.position.x = x; 1945 this.position.y = y; 1946}; 1947 1948// set settled position, apply padding 1949Item.prototype.layoutPosition = function() { 1950 var layoutSize = this.layout.size; 1951 var layoutOptions = this.layout.options; 1952 var style = {}; 1953 1954 // x 1955 var xPadding = layoutOptions.isOriginLeft ? 'paddingLeft' : 'paddingRight'; 1956 var xProperty = layoutOptions.isOriginLeft ? 'left' : 'right'; 1957 var xResetProperty = layoutOptions.isOriginLeft ? 'right' : 'left'; 1958 1959 var x = this.position.x + layoutSize[ xPadding ]; 1960 // set in percentage or pixels 1961 style[ xProperty ] = this.getXValue( x ); 1962 // reset other property 1963 style[ xResetProperty ] = ''; 1964 1965 // y 1966 var yPadding = layoutOptions.isOriginTop ? 'paddingTop' : 'paddingBottom'; 1967 var yProperty = layoutOptions.isOriginTop ? 'top' : 'bottom'; 1968 var yResetProperty = layoutOptions.isOriginTop ? 'bottom' : 'top'; 1969 1970 var y = this.position.y + layoutSize[ yPadding ]; 1971 // set in percentage or pixels 1972 style[ yProperty ] = this.getYValue( y ); 1973 // reset other property 1974 style[ yResetProperty ] = ''; 1975 1976 this.css( style ); 1977 this.emitEvent( 'layout', [ this ] ); 1978}; 1979 1980Item.prototype.getXValue = function( x ) { 1981 var layoutOptions = this.layout.options; 1982 return layoutOptions.percentPosition && !layoutOptions.isHorizontal ? 1983 ( ( x / this.layout.size.width ) * 100 ) + '%' : x + 'px'; 1984}; 1985 1986Item.prototype.getYValue = function( y ) { 1987 var layoutOptions = this.layout.options; 1988 return layoutOptions.percentPosition && layoutOptions.isHorizontal ? 1989 ( ( y / this.layout.size.height ) * 100 ) + '%' : y + 'px'; 1990}; 1991 1992 1993Item.prototype._transitionTo = function( x, y ) { 1994 this.getPosition(); 1995 // get current x & y from top/left 1996 var curX = this.position.x; 1997 var curY = this.position.y; 1998 1999 var compareX = parseInt( x, 10 ); 2000 var compareY = parseInt( y, 10 ); 2001 var didNotMove = compareX === this.position.x && compareY === this.position.y; 2002 2003 // save end position 2004 this.setPosition( x, y ); 2005 2006 // if did not move and not transitioning, just go to layout 2007 if ( didNotMove && !this.isTransitioning ) { 2008 this.layoutPosition(); 2009 return; 2010 } 2011 2012 var transX = x - curX; 2013 var transY = y - curY; 2014 var transitionStyle = {}; 2015 transitionStyle.transform = this.getTranslate( transX, transY ); 2016 2017 this.transition({ 2018 to: transitionStyle, 2019 onTransitionEnd: { 2020 transform: this.layoutPosition 2021 }, 2022 isCleaning: true 2023 }); 2024}; 2025 2026Item.prototype.getTranslate = function( x, y ) { 2027 // flip cooridinates if origin on right or bottom 2028 var layoutOptions = this.layout.options; 2029 x = layoutOptions.isOriginLeft ? x : -x; 2030 y = layoutOptions.isOriginTop ? y : -y; 2031 2032 if ( is3d ) { 2033 return 'translate3d(' + x + 'px, ' + y + 'px, 0)'; 2034 } 2035 2036 return 'translate(' + x + 'px, ' + y + 'px)'; 2037}; 2038 2039// non transition + transform support 2040Item.prototype.goTo = function( x, y ) { 2041 this.setPosition( x, y ); 2042 this.layoutPosition(); 2043}; 2044 2045// use transition and transforms if supported 2046Item.prototype.moveTo = supportsCSS3 ? 2047 Item.prototype._transitionTo : Item.prototype.goTo; 2048 2049Item.prototype.setPosition = function( x, y ) { 2050 this.position.x = parseInt( x, 10 ); 2051 this.position.y = parseInt( y, 10 ); 2052}; 2053 2054// ----- transition ----- // 2055 2056/** 2057 * @param {Object} style - CSS 2058 * @param {Function} onTransitionEnd 2059 */ 2060 2061// non transition, just trigger callback 2062Item.prototype._nonTransition = function( args ) { 2063 this.css( args.to ); 2064 if ( args.isCleaning ) { 2065 this._removeStyles( args.to ); 2066 } 2067 for ( var prop in args.onTransitionEnd ) { 2068 args.onTransitionEnd[ prop ].call( this ); 2069 } 2070}; 2071 2072/** 2073 * proper transition 2074 * @param {Object} args - arguments 2075 * @param {Object} to - style to transition to 2076 * @param {Object} from - style to start transition from 2077 * @param {Boolean} isCleaning - removes transition styles after transition 2078 * @param {Function} onTransitionEnd - callback 2079 */ 2080Item.prototype._transition = function( args ) { 2081 // redirect to nonTransition if no transition duration 2082 if ( !parseFloat( this.layout.options.transitionDuration ) ) { 2083 this._nonTransition( args ); 2084 return; 2085 } 2086 2087 var _transition = this._transn; 2088 // keep track of onTransitionEnd callback by css property 2089 for ( var prop in args.onTransitionEnd ) { 2090 _transition.onEnd[ prop ] = args.onTransitionEnd[ prop ]; 2091 } 2092 // keep track of properties that are transitioning 2093 for ( prop in args.to ) { 2094 _transition.ingProperties[ prop ] = true; 2095 // keep track of properties to clean up when transition is done 2096 if ( args.isCleaning ) { 2097 _transition.clean[ prop ] = true; 2098 } 2099 } 2100 2101 // set from styles 2102 if ( args.from ) { 2103 this.css( args.from ); 2104 // force redraw. http://blog.alexmaccaw.com/css-transitions 2105 var h = this.element.offsetHeight; 2106 // hack for JSHint to hush about unused var 2107 h = null; 2108 } 2109 // enable transition 2110 this.enableTransition( args.to ); 2111 // set styles that are transitioning 2112 this.css( args.to ); 2113 2114 this.isTransitioning = true; 2115 2116}; 2117 2118// dash before all cap letters, including first for 2119// WebkitTransform => -webkit-transform 2120function toDashedAll( str ) { 2121 return str.replace( /([A-Z])/g, function( $1 ) { 2122 return '-' + $1.toLowerCase(); 2123 }); 2124} 2125 2126var transitionProps = 'opacity,' +
vendor: 11,190 bytes, lines 2127-2573
2127 toDashedAll( vendorProperties.transform || 'transform' ); 2128 2129Item.prototype.enableTransition = function(/* style */) { 2130 // HACK changing transitionProperty during a transition 2131 // will cause transition to jump 2132 if ( this.isTransitioning ) { 2133 return; 2134 } 2135 2136 // make `transition: foo, bar, baz` from style object 2137 // HACK un-comment this when enableTransition can work 2138 // while a transition is happening 2139 // var transitionValues = []; 2140 // for ( var prop in style ) { 2141 // // dash-ify camelCased properties like WebkitTransition 2142 // prop = vendorProperties[ prop ] || prop; 2143 // transitionValues.push( toDashedAll( prop ) ); 2144 // } 2145 // enable transition styles 2146 this.css({ 2147 transitionProperty: transitionProps, 2148 transitionDuration: this.layout.options.transitionDuration 2149 }); 2150 // listen for transition end event 2151 this.element.addEventListener( transitionEndEvent, this, false ); 2152}; 2153 2154Item.prototype.transition = Item.prototype[ transitionProperty ? '_transition' : '_nonTransition' ]; 2155 2156// ----- events ----- // 2157 2158Item.prototype.onwebkitTransitionEnd = function( event ) { 2159 this.ontransitionend( event ); 2160}; 2161 2162Item.prototype.onotransitionend = function( event ) { 2163 this.ontransitionend( event ); 2164}; 2165 2166// properties that I munge to make my life easier 2167var dashedVendorProperties = { 2168 '-webkit-transform': 'transform', 2169 '-moz-transform': 'transform', 2170 '-o-transform': 'transform' 2171}; 2172 2173Item.prototype.ontransitionend = function( event ) { 2174 // disregard bubbled events from children 2175 if ( event.target !== this.element ) { 2176 return; 2177 } 2178 var _transition = this._transn; 2179 // get property name of transitioned property, convert to prefix-free 2180 var propertyName = dashedVendorProperties[ event.propertyName ] || event.propertyName; 2181 2182 // remove property that has completed transitioning 2183 delete _transition.ingProperties[ propertyName ]; 2184 // check if any properties are still transitioning 2185 if ( isEmptyObj( _transition.ingProperties ) ) { 2186 // all properties have completed transitioning 2187 this.disableTransition(); 2188 } 2189 // clean style 2190 if ( propertyName in _transition.clean ) { 2191 // clean up style 2192 this.element.style[ event.propertyName ] = ''; 2193 delete _transition.clean[ propertyName ]; 2194 } 2195 // trigger onTransitionEnd callback 2196 if ( propertyName in _transition.onEnd ) { 2197 var onTransitionEnd = _transition.onEnd[ propertyName ]; 2198 onTransitionEnd.call( this ); 2199 delete _transition.onEnd[ propertyName ]; 2200 } 2201 2202 this.emitEvent( 'transitionEnd', [ this ] ); 2203}; 2204 2205Item.prototype.disableTransition = function() { 2206 this.removeTransitionStyles(); 2207 this.element.removeEventListener( transitionEndEvent, this, false ); 2208 this.isTransitioning = false; 2209}; 2210 2211/** 2212 * removes style property from element 2213 * @param {Object} style 2214**/ 2215Item.prototype._removeStyles = function( style ) { 2216 // clean up transition styles 2217 var cleanStyle = {}; 2218 for ( var prop in style ) { 2219 cleanStyle[ prop ] = ''; 2220 } 2221 this.css( cleanStyle ); 2222}; 2223 2224var cleanTransitionStyle = { 2225 transitionProperty: '', 2226 transitionDuration: '' 2227}; 2228 2229Item.prototype.removeTransitionStyles = function() { 2230 // remove transition 2231 this.css( cleanTransitionStyle ); 2232}; 2233 2234// ----- show/hide/remove ----- // 2235 2236// remove element from DOM 2237Item.prototype.removeElem = function() { 2238 this.element.parentNode.removeChild( this.element ); 2239 // remove display: none 2240 this.css({ display: '' }); 2241 this.emitEvent( 'remove', [ this ] ); 2242}; 2243 2244Item.prototype.remove = function() { 2245 // just remove element if no transition support or no transition 2246 if ( !transitionProperty || !parseFloat( this.layout.options.transitionDuration ) ) { 2247 this.removeElem(); 2248 return; 2249 } 2250 2251 // start transition 2252 var _this = this; 2253 this.once( 'transitionEnd', function() { 2254 _this.removeElem(); 2255 }); 2256 this.hide(); 2257}; 2258 2259Item.prototype.reveal = function() { 2260 delete this.isHidden; 2261 // remove display: none 2262 this.css({ display: '' }); 2263 2264 var options = this.layout.options; 2265 2266 var onTransitionEnd = {}; 2267 var transitionEndProperty = this.getHideRevealTransitionEndProperty('visibleStyle'); 2268 onTransitionEnd[ transitionEndProperty ] = this.onRevealTransitionEnd; 2269 2270 this.transition({ 2271 from: options.hiddenStyle, 2272 to: options.visibleStyle, 2273 isCleaning: true, 2274 onTransitionEnd: onTransitionEnd 2275 }); 2276}; 2277 2278Item.prototype.onRevealTransitionEnd = function() { 2279 // check if still visible 2280 // during transition, item may have been hidden 2281 if ( !this.isHidden ) { 2282 this.emitEvent('reveal'); 2283 } 2284}; 2285 2286/** 2287 * get style property use for hide/reveal transition end 2288 * @param {String} styleProperty - hiddenStyle/visibleStyle 2289 * @returns {String} 2290 */ 2291Item.prototype.getHideRevealTransitionEndProperty = function( styleProperty ) { 2292 var optionStyle = this.layout.options[ styleProperty ]; 2293 // use opacity 2294 if ( optionStyle.opacity ) { 2295 return 'opacity'; 2296 } 2297 // get first property 2298 for ( var prop in optionStyle ) { 2299 return prop; 2300 } 2301}; 2302 2303Item.prototype.hide = function() { 2304 // set flag 2305 this.isHidden = true; 2306 // remove display: none 2307 this.css({ display: '' }); 2308 2309 var options = this.layout.options; 2310 2311 var onTransitionEnd = {}; 2312 var transitionEndProperty = this.getHideRevealTransitionEndProperty('hiddenStyle'); 2313 onTransitionEnd[ transitionEndProperty ] = this.onHideTransitionEnd; 2314 2315 this.transition({ 2316 from: options.visibleStyle, 2317 to: options.hiddenStyle, 2318 // keep hidden stuff hidden 2319 isCleaning: true, 2320 onTransitionEnd: onTransitionEnd 2321 }); 2322}; 2323 2324Item.prototype.onHideTransitionEnd = function() { 2325 // check if still hidden 2326 // during transition, item may have been un-hidden 2327 if ( this.isHidden ) { 2328 this.css({ display: 'none' }); 2329 this.emitEvent('hide'); 2330 } 2331}; 2332 2333Item.prototype.destroy = function() { 2334 this.css({ 2335 position: '', 2336 left: '', 2337 right: '', 2338 top: '', 2339 bottom: '', 2340 transition: '', 2341 transform: '' 2342 }); 2343}; 2344 2345return Item; 2346 2347})); 2348 2349/*! 2350 * Outlayer v1.4.2 2351 * the brains and guts of a layout library 2352 * MIT license 2353 */ 2354 2355( function( window, factory ) { 2356 'use strict'; 2357 // universal module definition 2358 2359 if ( typeof define == 'function' && define.amd ) { 2360 // AMD 2361 define( 'outlayer/outlayer',[ 2362 'eventie/eventie', 2363 'eventEmitter/EventEmitter', 2364 'get-size/get-size', 2365 'fizzy-ui-utils/utils', 2366 './item' 2367 ], 2368 function( eventie, EventEmitter, getSize, utils, Item ) { 2369 return factory( window, eventie, EventEmitter, getSize, utils, Item); 2370 } 2371 ); 2372 } else if ( typeof exports == 'object' ) { 2373 // CommonJS 2374 module.exports = factory( 2375 window, 2376 require('eventie'), 2377 require('wolfy87-eventemitter'), 2378 require('get-size'), 2379 require('fizzy-ui-utils'), 2380 require('./item') 2381 ); 2382 } else { 2383 // browser global 2384 window.Outlayer = factory( 2385 window, 2386 window.eventie, 2387 window.EventEmitter, 2388 window.getSize, 2389 window.fizzyUIUtils, 2390 window.Outlayer.Item 2391 ); 2392 } 2393 2394}( window, function factory( window, eventie, EventEmitter, getSize, utils, Item ) { 2395'use strict'; 2396 2397// ----- vars ----- // 2398 2399var console = window.console; 2400var jQuery = window.jQuery; 2401var noop = function() {}; 2402 2403// -------------------------- Outlayer -------------------------- // 2404 2405// globally unique identifiers 2406var GUID = 0; 2407// internal store of all Outlayer intances 2408var instances = {}; 2409 2410 2411/** 2412 * @param {Element, String} element 2413 * @param {Object} options 2414 * @constructor 2415 */ 2416function Outlayer( element, options ) { 2417 var queryElement = utils.getQueryElement( element ); 2418 if ( !queryElement ) { 2419 if ( console ) { 2420 console.error( 'Bad element for ' + this.constructor.namespace + 2421 ': ' + ( queryElement || element ) ); 2422 } 2423 return; 2424 } 2425 this.element = queryElement; 2426 // add jQuery 2427 if ( jQuery ) { 2428 this.$element = jQuery( this.element ); 2429 } 2430 2431 // options 2432 this.options = utils.extend( {}, this.constructor.defaults ); 2433 this.option( options ); 2434 2435 // add id for Outlayer.getFromElement 2436 var id = ++GUID; 2437 this.element.outlayerGUID = id; // expando 2438 instances[ id ] = this; // associate via id 2439 2440 // kick it off 2441 this._create(); 2442 2443 if ( this.options.isInitLayout ) { 2444 this.layout(); 2445 } 2446} 2447 2448// settings are for internal use only 2449Outlayer.namespace = 'outlayer'; 2450Outlayer.Item = Item; 2451 2452// default options 2453Outlayer.defaults = { 2454 containerStyle: { 2455 position: 'relative' 2456 }, 2457 isInitLayout: true, 2458 isOriginLeft: true, 2459 isOriginTop: true, 2460 isResizeBound: true, 2461 isResizingContainer: true, 2462 // item options 2463 transitionDuration: '0.4s', 2464 hiddenStyle: { 2465 opacity: 0, 2466 transform: 'scale(0.001)' 2467 }, 2468 visibleStyle: { 2469 opacity: 1, 2470 transform: 'scale(1)' 2471 } 2472}; 2473 2474// inherit EventEmitter 2475utils.extend( Outlayer.prototype, EventEmitter.prototype ); 2476 2477/** 2478 * set options 2479 * @param {Object} opts 2480 */ 2481Outlayer.prototype.option = function( opts ) { 2482 utils.extend( this.options, opts ); 2483}; 2484 2485Outlayer.prototype._create = function() { 2486 // get items from children 2487 this.reloadItems(); 2488 // elements that affect layout, but are not laid out 2489 this.stamps = []; 2490 this.stamp( this.options.stamp ); 2491 // set container style 2492 utils.extend( this.element.style, this.options.containerStyle ); 2493 2494 // bind resize method 2495 if ( this.options.isResizeBound ) { 2496 this.bindResize(); 2497 } 2498}; 2499 2500// goes through all children again and gets bricks in proper order 2501Outlayer.prototype.reloadItems = function() { 2502 // collection of item elements 2503 this.items = this._itemize( this.element.children ); 2504}; 2505 2506 2507/** 2508 * turn elements into Outlayer.Items to be used in layout 2509 * @param {Array or NodeList or HTMLElement} elems 2510 * @returns {Array} items - collection of new Outlayer Items 2511 */ 2512Outlayer.prototype._itemize = function( elems ) { 2513 2514 var itemElems = this._filterFindItemElements( elems ); 2515 var Item = this.constructor.Item; 2516 2517 // create new Outlayer Items for collection 2518 var items = []; 2519 for ( var i=0, len = itemElems.length; i < len; i++ ) { 2520 var elem = itemElems[i]; 2521 var item = new Item( elem, this ); 2522 items.push( item ); 2523 } 2524 2525 return items; 2526}; 2527 2528/** 2529 * get item elements to be used in layout 2530 * @param {Array or NodeList or HTMLElement} elems 2531 * @returns {Array} items - item elements 2532 */ 2533Outlayer.prototype._filterFindItemElements = function( elems ) { 2534 return utils.filterFindElements( elems, this.options.itemSelector ); 2535}; 2536 2537/** 2538 * getter method for getting item elements 2539 * @returns {Array} elems - collection of item elements 2540 */ 2541Outlayer.prototype.getItemElements = function() { 2542 var elems = []; 2543 for ( var i=0, len = this.items.length; i < len; i++ ) { 2544 elems.push( this.items[i].element ); 2545 } 2546 return elems; 2547}; 2548 2549// ----- init & layout ----- // 2550 2551/** 2552 * lays out all items 2553 */ 2554Outlayer.prototype.layout = function() { 2555 this._resetLayout(); 2556 this._manageStamps(); 2557 2558 // don't animate first layout 2559 var isInstant = this.options.isLayoutInstant !== undefined ? 2560 this.options.isLayoutInstant : !this._isLayoutInited; 2561 this.layoutItems( this.items, isInstant ); 2562 2563 // flag for initalized 2564 this._isLayoutInited = true; 2565}; 2566 2567// _init is alias for layout 2568Outlayer.prototype._init = Outlayer.prototype.layout; 2569 2570/** 2571 * logic before any new layout 2572 */ 2573Outlayer.prototype._resetLayout = function() {
2574 this.getSize(); 2575}; 2576 2577 2578Outlayer.prototype.getSize = function() { 2579 this.size = getSize( this.element ); 2580}; 2581 2582/** 2583 * get measurement from option, for columnWidth, rowHeight, gutter 2584 * if option is String -> get element from selector string, & get size of element 2585 * if option is Element -> get size of element 2586 * else use option as a number 2587 * 2588 * @param {String} measurement 2589 * @param {String} size - width or height 2590 * @private 2591 */ 2592Outlayer.prototype._getMeasurement = function( measurement, size ) { 2593 var option = this.options[ measurement ]; 2594 var elem; 2595 if ( !option ) { 2596 // default to 0 2597 this[ measurement ] = 0; 2598 } else { 2599 // use option as an element 2600 if ( typeof option === 'string' ) { 2601 elem = this.element.querySelector( option ); 2602 } else if ( utils.isElement( option ) ) { 2603 elem = option; 2604 } 2605 // use size of element, if element 2606 this[ measurement ] = elem ? getSize( elem )[ size ] : option; 2607 } 2608}; 2609 2610/** 2611 * layout a collection of item elements 2612 * @api public 2613 */ 2614Outlayer.prototype.layoutItems = function( items, isInstant ) { 2615 items = this._getItemsForLayout( items ); 2616 2617 this._layoutItems( items, isInstant ); 2618 2619 this._postLayout(); 2620}; 2621 2622/** 2623 * get the items to be laid out 2624 * you may want to skip over some items 2625 * @param {Array} items 2626 * @returns {Array} items 2627 */ 2628Outlayer.prototype._getItemsForLayout = function( items ) { 2629 var layoutItems = []; 2630 for ( var i=0, len = items.length; i < len; i++ ) { 2631 var item = items[i]; 2632 if ( !item.isIgnored ) { 2633 layoutItems.push( item ); 2634 } 2635 } 2636 return layoutItems; 2637}; 2638 2639/** 2640 * layout items 2641 * @param {Array} items 2642 * @param {Boolean} isInstant 2643 */ 2644Outlayer.prototype._layoutItems = function( items, isInstant ) { 2645 this._emitCompleteOnItems( 'layout', items ); 2646 2647 if ( !items || !items.length ) { 2648 // no items, emit event with empty array 2649 return; 2650 } 2651 2652 var queue = []; 2653 2654 for ( var i=0, len = items.length; i < len; i++ ) { 2655 var item = items[i]; 2656 // get x/y object from method 2657 var position = this._getItemLayoutPosition( item ); 2658 // enqueue 2659 position.item = item; 2660 position.isInstant = isInstant || item.isLayoutInstant; 2661 queue.push( position ); 2662 } 2663 2664 this._processLayoutQueue( queue ); 2665}; 2666 2667/** 2668 * get item layout position 2669 * @param {Outlayer.Item} item 2670 * @returns {Object} x and y position 2671 */ 2672Outlayer.prototype._getItemLayoutPosition = function( /* item */ ) { 2673 return { 2674 x: 0, 2675 y: 0 2676 }; 2677}; 2678 2679/** 2680 * iterate over array and position each item 2681 * Reason being - separating this logic prevents 'layout invalidation' 2682 * thx @paul_irish 2683 * @param {Array} queue 2684 */ 2685Outlayer.prototype._processLayoutQueue = function( queue ) { 2686 for ( var i=0, len = queue.length; i < len; i++ ) { 2687 var obj = queue[i]; 2688 this._positionItem( obj.item, obj.x, obj.y, obj.isInstant ); 2689 } 2690}; 2691 2692/** 2693 * Sets position of item in DOM 2694 * @param {Outlayer.Item} item 2695 * @param {Number} x - horizontal position 2696 * @param {Number} y - vertical position 2697 * @param {Boolean} isInstant - disables transitions 2698 */ 2699Outlayer.prototype._positionItem = function( item, x, y, isInstant ) { 2700 if ( isInstant ) { 2701 // if not transition, just set CSS 2702 item.goTo( x, y ); 2703 } else { 2704 item.moveTo( x, y ); 2705 } 2706}; 2707 2708/** 2709 * Any logic you want to do after each layout, 2710 * i.e. size the container 2711 */ 2712Outlayer.prototype._postLayout = function() { 2713 this.resizeContainer(); 2714}; 2715 2716Outlayer.prototype.resizeContainer = function() { 2717 if ( !this.options.isResizingContainer ) { 2718 return; 2719 } 2720 var size = this._getContainerSize(); 2721 if ( size ) { 2722 this._setContainerMeasure( size.width, true ); 2723 this._setContainerMeasure( size.height, false ); 2724 } 2725}; 2726 2727/** 2728 * Sets width or height of container if returned 2729 * @returns {Object} size 2730 * @param {Number} width 2731 * @param {Number} height 2732 */ 2733Outlayer.prototype._getContainerSize = noop; 2734 2735/** 2736 * @param {Number} measure - size of width or height 2737 * @param {Boolean} isWidth 2738 */ 2739Outlayer.prototype._setContainerMeasure = function( measure, isWidth ) { 2740 if ( measure === undefined ) { 2741 return; 2742 } 2743 2744 var elemSize = this.size; 2745 // add padding and border width if border box 2746 if ( elemSize.isBorderBox ) { 2747 measure += isWidth ? elemSize.paddingLeft + elemSize.paddingRight + 2748 elemSize.borderLeftWidth + elemSize.borderRightWidth : 2749 elemSize.paddingBottom + elemSize.paddingTop + 2750 elemSize.borderTopWidth + elemSize.borderBottomWidth; 2751 } 2752 2753 measure = Math.max( measure, 0 ); 2754 this.element.style[ isWidth ? 'width' : 'height' ] = measure + 'px'; 2755}; 2756 2757/** 2758 * emit eventComplete on a collection of items events 2759 * @param {String} eventName 2760 * @param {Array} items - Outlayer.Items 2761 */ 2762Outlayer.prototype._emitCompleteOnItems = function( eventName, items ) { 2763 var _this = this; 2764 function onComplete() { 2765 _this.dispatchEvent( eventName + 'Complete', null, [ items ] ); 2766 } 2767 2768 var count = items.length; 2769 if ( !items || !count ) { 2770 onComplete(); 2771 return; 2772 } 2773 2774 var doneCount = 0; 2775 function tick() { 2776 doneCount++; 2777 if ( doneCount === count ) { 2778 onComplete(); 2779 } 2780 } 2781 2782 // bind callback 2783 for ( var i=0, len = items.length; i < len; i++ ) { 2784 var item = items[i]; 2785 item.once( eventName, tick ); 2786 } 2787}; 2788 2789/** 2790 * emits events via eventEmitter and jQuery events 2791 * @param {String} type - name of event 2792 * @param {Event} event - original event 2793 * @param {Array} args - extra arguments 2794 */ 2795Outlayer.prototype.dispatchEvent = function( type, event, args ) { 2796 // add original event to arguments 2797 var emitArgs = event ? [ event ].concat( args ) : args; 2798 this.emitEvent( type, emitArgs ); 2799 2800 if ( jQuery ) { 2801 // set this.$element 2802 this.$element = this.$element || jQuery( this.element ); 2803 if ( event ) { 2804 // create jQuery event 2805 var $event = jQuery.Event( event ); 2806 $event.type = type; 2807 this.$element.trigger( $event, args ); 2808 } else { 2809 // just trigger with type if no event available 2810 this.$element.trigger( type, args ); 2811 } 2812 } 2813}; 2814 2815// -------------------------- ignore & stamps -------------------------- // 2816 2817 2818/** 2819 * keep item in collection, but do not lay it out 2820 * ignored items do not get skipped in layout 2821 * @param {Element} elem 2822 */ 2823Outlayer.prototype.ignore = function( elem ) { 2824 var item = this.getItem( elem ); 2825 if ( item ) { 2826 item.isIgnored = true; 2827 } 2828}; 2829 2830/** 2831 * return item to layout collection 2832 * @param {Element} elem 2833 */ 2834Outlayer.prototype.unignore = function( elem ) { 2835 var item = this.getItem( elem ); 2836 if ( item ) { 2837 delete item.isIgnored; 2838 } 2839}; 2840 2841/** 2842 * adds elements to stamps 2843 * @param {NodeList, Array, Element, or String} elems 2844 */ 2845Outlayer.prototype.stamp = function( elems ) { 2846 elems = this._find( elems ); 2847 if ( !elems ) { 2848 return; 2849 } 2850
2851 this.stamps = this.stamps.concat( elems ); 2852 // ignore 2853 for ( var i=0, len = elems.length; i < len; i++ ) { 2854 var elem = elems[i]; 2855 this.ignore( elem ); 2856 } 2857}; 2858 2859/** 2860 * removes elements to stamps 2861 * @param {NodeList, Array, or Element} elems 2862 */ 2863Outlayer.prototype.unstamp = function( elems ) { 2864 elems = this._find( elems ); 2865 if ( !elems ){ 2866 return; 2867 } 2868 2869 for ( var i=0, len = elems.length; i < len; i++ ) { 2870 var elem = elems[i]; 2871 // filter out removed stamp elements 2872 utils.removeFrom( this.stamps, elem ); 2873 this.unignore( elem ); 2874 } 2875 2876}; 2877 2878/** 2879 * finds child elements 2880 * @param {NodeList, Array, Element, or String} elems 2881 * @returns {Array} elems 2882 */ 2883Outlayer.prototype._find = function( elems ) { 2884 if ( !elems ) { 2885 return; 2886 } 2887 // if string, use argument as selector string 2888 if ( typeof elems === 'string' ) { 2889 elems = this.element.querySelectorAll( elems ); 2890 } 2891 elems = utils.makeArray( elems ); 2892 return elems; 2893}; 2894 2895Outlayer.prototype._manageStamps = function() { 2896 if ( !this.stamps || !this.stamps.length ) { 2897 return; 2898 } 2899 2900 this._getBoundingRect(); 2901 2902 for ( var i=0, len = this.stamps.length; i < len; i++ ) { 2903 var stamp = this.stamps[i]; 2904 this._manageStamp( stamp ); 2905 } 2906}; 2907 2908// update boundingLeft / Top 2909Outlayer.prototype._getBoundingRect = function() { 2910 // get bounding rect for container element 2911 var boundingRect = this.element.getBoundingClientRect(); 2912 var size = this.size; 2913 this._boundingRect = { 2914 left: boundingRect.left + size.paddingLeft + size.borderLeftWidth, 2915 top: boundingRect.top + size.paddingTop + size.borderTopWidth, 2916 right: boundingRect.right - ( size.paddingRight + size.borderRightWidth ), 2917 bottom: boundingRect.bottom - ( size.paddingBottom + size.borderBottomWidth ) 2918 }; 2919}; 2920 2921/** 2922 * @param {Element} stamp 2923**/ 2924Outlayer.prototype._manageStamp = noop; 2925 2926/** 2927 * get x/y position of element relative to container element 2928 * @param {Element} elem 2929 * @returns {Object} offset - has left, top, right, bottom 2930 */ 2931Outlayer.prototype._getElementOffset = function( elem ) { 2932 var boundingRect = elem.getBoundingClientRect(); 2933 var thisRect = this._boundingRect; 2934 var size = getSize( elem ); 2935 var offset = { 2936 left: boundingRect.left - thisRect.left - size.marginLeft, 2937 top: boundingRect.top - thisRect.top - size.marginTop, 2938 right: thisRect.right - boundingRect.right - size.marginRight, 2939 bottom: thisRect.bottom - boundingRect.bottom - size.marginBottom 2940 }; 2941 return offset; 2942}; 2943 2944// -------------------------- resize -------------------------- // 2945 2946// enable event handlers for listeners 2947// i.e. resize -> onresize 2948Outlayer.prototype.handleEvent = function( event ) { 2949 var method = 'on' + event.type; 2950 if ( this[ method ] ) { 2951 this[ method ]( event ); 2952 } 2953}; 2954 2955/** 2956 * Bind layout to window resizing 2957 */ 2958Outlayer.prototype.bindResize = function() { 2959 // bind just one listener 2960 if ( this.isResizeBound ) { 2961 return; 2962 } 2963 eventie.bind( window, 'resize', this ); 2964 this.isResizeBound = true; 2965}; 2966 2967/** 2968 * Unbind layout to window resizing 2969 */ 2970Outlayer.prototype.unbindResize = function() { 2971 if ( this.isResizeBound ) { 2972 eventie.unbind( window, 'resize', this ); 2973 } 2974 this.isResizeBound = false; 2975}; 2976 2977// original debounce by John Hann 2978// http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/ 2979 2980// this fires every resize 2981Outlayer.prototype.onresize = function() { 2982 if ( this.resizeTimeout ) { 2983 clearTimeout( this.resizeTimeout ); 2984 } 2985 2986 var _this = this; 2987 function delayed() { 2988 _this.resize(); 2989 delete _this.resizeTimeout; 2990 } 2991 2992 this.resizeTimeout = setTimeout( delayed, 100 ); 2993}; 2994 2995// debounced, layout on resize 2996Outlayer.prototype.resize = function() { 2997 // don't trigger if size did not change 2998 // or if resize was unbound. See #9 2999 if ( !this.isResizeBound || !this.needsResizeLayout() ) { 3000 return; 3001 } 3002 3003 this.layout(); 3004}; 3005 3006/** 3007 * check if layout is needed post layout 3008 * @returns Boolean 3009 */ 3010Outlayer.prototype.needsResizeLayout = function() { 3011 var size = getSize( this.element ); 3012 // check that this.size and size are there 3013 // IE8 triggers resize on body size change, so they might not be 3014 var hasSizes = this.size && size; 3015 return hasSizes && size.innerWidth !== this.size.innerWidth; 3016}; 3017 3018// -------------------------- methods -------------------------- // 3019 3020/** 3021 * add items to Outlayer instance 3022 * @param {Array or NodeList or Element} elems 3023 * @returns {Array} items - Outlayer.Items 3024**/ 3025Outlayer.prototype.addItems = function( elems ) { 3026 var items = this._itemize( elems ); 3027 // add items to collection 3028 if ( items.length ) { 3029 this.items = this.items.concat( items ); 3030 } 3031 return items; 3032}; 3033 3034/** 3035 * Layout newly-appended item elements 3036 * @param {Array or NodeList or Element} elems 3037 */ 3038Outlayer.prototype.appended = function( elems ) { 3039 var items = this.addItems( elems ); 3040 if ( !items.length ) { 3041 return; 3042 } 3043 // layout and reveal just the new items 3044 this.layoutItems( items, true ); 3045 this.reveal( items ); 3046}; 3047 3048/** 3049 * Layout prepended elements 3050 * @param {Array or NodeList or Element} elems 3051 */ 3052Outlayer.prototype.prepended = function( elems ) { 3053 var items = this._itemize( elems ); 3054 if ( !items.length ) { 3055 return; 3056 } 3057 // add items to beginning of collection 3058 var previousItems = this.items.slice(0); 3059 this.items = items.concat( previousItems ); 3060 // start new layout 3061 this._resetLayout(); 3062 this._manageStamps(); 3063 // layout new stuff without transition 3064 this.layoutItems( items, true ); 3065 this.reveal( items ); 3066 // layout previous items 3067 this.layoutItems( previousItems ); 3068}; 3069 3070/** 3071 * reveal a collection of items 3072 * @param {Array of Outlayer.Items} items 3073 */ 3074Outlayer.prototype.reveal = function( items ) { 3075 this._emitCompleteOnItems( 'reveal', items ); 3076 3077 var len = items && items.length; 3078 for ( var i=0; len && i < len; i++ ) { 3079 var item = items[i]; 3080 item.reveal(); 3081 } 3082}; 3083 3084/** 3085 * hide a collection of items 3086 * @param {Array of Outlayer.Items} items 3087 */ 3088Outlayer.prototype.hide = function( items ) { 3089 this._emitCompleteOnItems( 'hide', items ); 3090 3091 var len = items && items.length; 3092 for ( var i=0; len && i < len; i++ ) { 3093 var item = items[i]; 3094 item.hide(); 3095 } 3096}; 3097 3098/** 3099 * reveal item elements 3100 * @param {Array}, {Element}, {NodeList} items 3101 */ 3102Outlayer.prototype.revealItemElements = function( elems ) { 3103 var items = this.getItems( elems ); 3104 this.reveal( items ); 3105}; 3106 3107/** 3108 * hide item elements 3109 * @param {Array}, {Element}, {NodeList} items 3110 */ 3111Outlayer.prototype.hideItemElements = function( elems ) { 3112 var items = this.getItems( elems ); 3113 this.hide( items ); 3114}; 3115 3116/** 3117 * get Outlayer.Item, given an Element 3118 * @param {Element} elem 3119 * @param {Function} callback 3120 * @returns {Outlayer.Item} item 3121 */ 3122Outlayer.prototype.getItem = function( elem ) { 3123 // loop through items to get the one that matches 3124 for ( var i=0, len = this.items.length; i < len; i++ ) { 3125 var item = this.items[i]; 3126 if ( item.element === elem ) { 3127 // return item 3128 return item; 3129 } 3130 } 3131}; 3132 3133/** 3134 * get collection of Outlayer.Items, given Elements 3135 * @param {Array} elems 3136 * @returns {Array} items - Outlayer.Items 3137 */ 3138Outlayer.prototype.getItems = function( elems ) { 3139 elems = utils.makeArray( elems ); 3140 var items = []; 3141 for ( var i=0, len = elems.length; i < len; i++ ) { 3142 var elem = elems[i]; 3143 var item = this.getItem( elem ); 3144 if ( item ) { 3145 items.push( item ); 3146 } 3147 } 3148 3149 return items; 3150}; 3151 3152/**
3153 * remove element(s) from instance and DOM 3154 * @param {Array or NodeList or Element} elems 3155 */ 3156Outlayer.prototype.remove = function( elems ) { 3157 var removeItems = this.getItems( elems ); 3158 3159 this._emitCompleteOnItems( 'remove', removeItems ); 3160 3161 // bail if no items to remove 3162 if ( !removeItems || !removeItems.length ) { 3163 return; 3164 } 3165 3166 for ( var i=0, len = removeItems.length; i < len; i++ ) { 3167 var item = removeItems[i]; 3168 item.remove(); 3169 // remove item from collection 3170 utils.removeFrom( this.items, item ); 3171 } 3172}; 3173 3174// ----- destroy ----- // 3175 3176// remove and disable Outlayer instance 3177Outlayer.prototype.destroy = function() { 3178 // clean up dynamic styles 3179 var style = this.element.style; 3180 style.height = ''; 3181 style.position = ''; 3182 style.width = ''; 3183 // destroy items 3184 for ( var i=0, len = this.items.length; i < len; i++ ) { 3185 var item = this.items[i]; 3186 item.destroy(); 3187 } 3188 3189 this.unbindResize(); 3190 3191 var id = this.element.outlayerGUID; 3192 delete instances[ id ]; // remove reference to instance by id 3193 delete this.element.outlayerGUID; 3194 // remove data for jQuery 3195 if ( jQuery ) { 3196 jQuery.removeData( this.element, this.constructor.namespace ); 3197 } 3198 3199}; 3200 3201// -------------------------- data -------------------------- // 3202 3203/** 3204 * get Outlayer instance from element 3205 * @param {Element} elem 3206 * @returns {Outlayer} 3207 */ 3208Outlayer.data = function( elem ) { 3209 elem = utils.getQueryElement( elem ); 3210 var id = elem && elem.outlayerGUID; 3211 return id && instances[ id ]; 3212}; 3213 3214 3215// -------------------------- create Outlayer class -------------------------- // 3216 3217/** 3218 * create a layout class 3219 * @param {String} namespace 3220 */ 3221Outlayer.create = function( namespace, options ) { 3222 // sub-class Outlayer 3223 function Layout() { 3224 Outlayer.apply( this, arguments ); 3225 } 3226 // inherit Outlayer prototype, use Object.create if there 3227 if ( Object.create ) { 3228 Layout.prototype = Object.create( Outlayer.prototype ); 3229 } else { 3230 utils.extend( Layout.prototype, Outlayer.prototype ); 3231 } 3232 // set contructor, used for namespace and Item 3233 Layout.prototype.constructor = Layout; 3234 3235 Layout.defaults = utils.extend( {}, Outlayer.defaults ); 3236 // apply new options 3237 utils.extend( Layout.defaults, options ); 3238 // keep prototype.settings for backwards compatibility (Packery v1.2.0) 3239 Layout.prototype.settings = {}; 3240 3241 Layout.namespace = namespace; 3242 3243 Layout.data = Outlayer.data; 3244 3245 // sub-class Item 3246 Layout.Item = function LayoutItem() { 3247 Item.apply( this, arguments ); 3248 }; 3249 3250 Layout.Item.prototype = new Item(); 3251 3252 // -------------------------- declarative -------------------------- // 3253 3254 utils.htmlInit( Layout, namespace ); 3255 3256 // -------------------------- jQuery bridge -------------------------- // 3257 3258 // make into jQuery plugin 3259 if ( jQuery && jQuery.bridget ) { 3260 jQuery.bridget( namespace, Layout ); 3261 } 3262 3263 return Layout; 3264}; 3265 3266// ----- fin ----- // 3267 3268// back in global 3269Outlayer.Item = Item; 3270 3271return Outlayer; 3272 3273})); 3274 3275 3276/** 3277 * Isotope Item 3278**/ 3279 3280( function( window, factory ) { 3281'use strict'; 3282 // universal module definition 3283 if ( typeof define == 'function' && define.amd ) { 3284 // AMD 3285 define( 'isotope/js/item',[ 3286 'outlayer/outlayer' 3287 ], 3288 factory ); 3289 } else if ( typeof exports == 'object' ) { 3290 // CommonJS 3291 module.exports = factory( 3292 require('outlayer') 3293 ); 3294 } else { 3295 // browser global 3296 window.Isotope = window.Isotope || {}; 3297 window.Isotope.Item = factory( 3298 window.Outlayer 3299 ); 3300 } 3301 3302}( window, function factory( Outlayer ) { 3303'use strict'; 3304 3305// -------------------------- Item -------------------------- // 3306 3307// sub-class Outlayer Item 3308function Item() { 3309 Outlayer.Item.apply( this, arguments ); 3310} 3311 3312Item.prototype = new Outlayer.Item(); 3313 3314Item.prototype._create = function() { 3315 // assign id, used for original-order sorting 3316 this.id = this.layout.itemGUID++; 3317 Outlayer.Item.prototype._create.call( this ); 3318 this.sortData = {}; 3319}; 3320 3321Item.prototype.updateSortData = function() { 3322 if ( this.isIgnored ) { 3323 return; 3324 } 3325 // default sorters 3326 this.sortData.id = this.id; 3327 // for backward compatibility 3328 this.sortData['original-order'] = this.id; 3329 this.sortData.random = Math.random(); 3330 // go thru getSortData obj and apply the sorters 3331 var getSortData = this.layout.options.getSortData; 3332 var sorters = this.layout._sorters; 3333 for ( var key in getSortData ) { 3334 var sorter = sorters[ key ]; 3335 this.sortData[ key ] = sorter( this.element, this ); 3336 } 3337}; 3338 3339var _destroy = Item.prototype.destroy; 3340Item.prototype.destroy = function() { 3341 // call super 3342 _destroy.apply( this, arguments ); 3343 // reset display, #741 3344 this.css({ 3345 display: '' 3346 }); 3347}; 3348 3349return Item; 3350 3351})); 3352 3353/** 3354 * Isotope LayoutMode 3355 */ 3356 3357( function( window, factory ) { 3358 'use strict'; 3359 // universal module definition 3360 3361 if ( typeof define == 'function' && define.amd ) { 3362 // AMD 3363 define( 'isotope/js/layout-mode',[ 3364 'get-size/get-size', 3365 'outlayer/outlayer' 3366 ], 3367 factory ); 3368 } else if ( typeof exports == 'object' ) { 3369 // CommonJS 3370 module.exports = factory( 3371 require('get-size'), 3372 require('outlayer') 3373 ); 3374 } else { 3375 // browser global 3376 window.Isotope = window.Isotope || {}; 3377 window.Isotope.LayoutMode = factory( 3378 window.getSize, 3379 window.Outlayer 3380 ); 3381 } 3382 3383}( window, function factory( getSize, Outlayer ) { 3384 'use strict'; 3385 3386 // layout mode class 3387 function LayoutMode( isotope ) { 3388 this.isotope = isotope; 3389 // link properties 3390 if ( isotope ) { 3391 this.options = isotope.options[ this.namespace ]; 3392 this.element = isotope.element; 3393 this.items = isotope.filteredItems; 3394 this.size = isotope.size; 3395 } 3396 } 3397 3398 /** 3399 * some methods should just defer to default Outlayer method 3400 * and reference the Isotope instance as `this` 3401 **/ 3402 ( function() { 3403 var facadeMethods = [ 3404 '_resetLayout', 3405 '_getItemLayoutPosition', 3406 '_manageStamp', 3407 '_getContainerSize', 3408 '_getElementOffset', 3409 'needsResizeLayout' 3410 ]; 3411 3412 for ( var i=0, len = facadeMethods.length; i < len; i++ ) { 3413 var methodName = facadeMethods[i]; 3414 LayoutMode.prototype[ methodName ] = getOutlayerMethod( methodName ); 3415 } 3416 3417 function getOutlayerMethod( methodName ) { 3418 return function() { 3419 return Outlayer.prototype[ methodName ].apply( this.isotope, arguments ); 3420 }; 3421 } 3422 })(); 3423 3424 // ----- ----- // 3425 3426 // for horizontal layout modes, check vertical size 3427 LayoutMode.prototype.needsVerticalResizeLayout = function() {
vendor: 20,029 bytes, lines 3428-4163
3428 // don't trigger if size did not change 3429 var size = getSize( this.isotope.element ); 3430 // check that this.size and size are there 3431 // IE8 triggers resize on body size change, so they might not be 3432 var hasSizes = this.isotope.size && size; 3433 return hasSizes && size.innerHeight != this.isotope.size.innerHeight; 3434 }; 3435 3436 // ----- measurements ----- // 3437 3438 LayoutMode.prototype._getMeasurement = function() { 3439 this.isotope._getMeasurement.apply( this, arguments ); 3440 }; 3441 3442 LayoutMode.prototype.getColumnWidth = function() { 3443 this.getSegmentSize( 'column', 'Width' ); 3444 }; 3445 3446 LayoutMode.prototype.getRowHeight = function() { 3447 this.getSegmentSize( 'row', 'Height' ); 3448 }; 3449 3450 /** 3451 * get columnWidth or rowHeight 3452 * segment: 'column' or 'row' 3453 * size 'Width' or 'Height' 3454 **/ 3455 LayoutMode.prototype.getSegmentSize = function( segment, size ) { 3456 var segmentName = segment + size; 3457 var outerSize = 'outer' + size; 3458 // columnWidth / outerWidth // rowHeight / outerHeight 3459 this._getMeasurement( segmentName, outerSize ); 3460 // got rowHeight or columnWidth, we can chill 3461 if ( this[ segmentName ] ) { 3462 return; 3463 } 3464 // fall back to item of first element 3465 var firstItemSize = this.getFirstItemSize(); 3466 this[ segmentName ] = firstItemSize && firstItemSize[ outerSize ] || 3467 // or size of container 3468 this.isotope.size[ 'inner' + size ]; 3469 }; 3470 3471 LayoutMode.prototype.getFirstItemSize = function() { 3472 var firstItem = this.isotope.filteredItems[0]; 3473 return firstItem && firstItem.element && getSize( firstItem.element ); 3474 }; 3475 3476 // ----- methods that should reference isotope ----- // 3477 3478 LayoutMode.prototype.layout = function() { 3479 this.isotope.layout.apply( this.isotope, arguments ); 3480 }; 3481 3482 LayoutMode.prototype.getSize = function() { 3483 this.isotope.getSize(); 3484 this.size = this.isotope.size; 3485 }; 3486 3487 // -------------------------- create -------------------------- // 3488 3489 LayoutMode.modes = {}; 3490 3491 LayoutMode.create = function( namespace, options ) { 3492 3493 function Mode() { 3494 LayoutMode.apply( this, arguments ); 3495 } 3496 3497 Mode.prototype = new LayoutMode(); 3498 3499 // default options 3500 if ( options ) { 3501 Mode.options = options; 3502 } 3503 3504 Mode.prototype.namespace = namespace; 3505 // register in Isotope 3506 LayoutMode.modes[ namespace ] = Mode; 3507 3508 return Mode; 3509 }; 3510 3511 return LayoutMode; 3512 3513})); 3514 3515/*! 3516 * Masonry v3.3.1 3517 * Cascading grid layout library 3518 * http://masonry.desandro.com 3519 * MIT License 3520 * by David DeSandro 3521 */ 3522 3523( function( window, factory ) { 3524 'use strict'; 3525 // universal module definition 3526 if ( typeof define === 'function' && define.amd ) { 3527 // AMD 3528 define( 'masonry/masonry',[ 3529 'outlayer/outlayer', 3530 'get-size/get-size', 3531 'fizzy-ui-utils/utils' 3532 ], 3533 factory ); 3534 } else if ( typeof exports === 'object' ) { 3535 // CommonJS 3536 module.exports = factory( 3537 require('outlayer'), 3538 require('get-size'), 3539 require('fizzy-ui-utils') 3540 ); 3541 } else { 3542 // browser global 3543 window.Masonry = factory( 3544 window.Outlayer, 3545 window.getSize, 3546 window.fizzyUIUtils 3547 ); 3548 } 3549 3550}( window, function factory( Outlayer, getSize, utils ) { 3551 3552 3553 3554// -------------------------- masonryDefinition -------------------------- // 3555 3556 // create an Outlayer layout class 3557 var Masonry = Outlayer.create('masonry'); 3558 3559 Masonry.prototype._resetLayout = function() { 3560 this.getSize(); 3561 this._getMeasurement( 'columnWidth', 'outerWidth' ); 3562 this._getMeasurement( 'gutter', 'outerWidth' ); 3563 this.measureColumns(); 3564 3565 // reset column Y 3566 var i = this.cols; 3567 this.colYs = []; 3568 while (i--) { 3569 this.colYs.push( 0 ); 3570 } 3571 3572 this.maxY = 0; 3573 }; 3574 3575 Masonry.prototype.measureColumns = function() { 3576 this.getContainerWidth(); 3577 // if columnWidth is 0, default to outerWidth of first item 3578 if ( !this.columnWidth ) { 3579 var firstItem = this.items[0]; 3580 var firstItemElem = firstItem && firstItem.element; 3581 // columnWidth fall back to item of first element 3582 this.columnWidth = firstItemElem && getSize( firstItemElem ).outerWidth || 3583 // if first elem has no width, default to size of container 3584 this.containerWidth; 3585 } 3586 3587 var columnWidth = this.columnWidth += this.gutter; 3588 3589 // calculate columns 3590 var containerWidth = this.containerWidth + this.gutter; 3591 var cols = containerWidth / columnWidth; 3592 // fix rounding errors, typically with gutters 3593 var excess = columnWidth - containerWidth % columnWidth; 3594 // if overshoot is less than a pixel, round up, otherwise floor it 3595 var mathMethod = excess && excess < 1 ? 'round' : 'floor'; 3596 cols = Math[ mathMethod ]( cols ); 3597 this.cols = Math.max( cols, 1 ); 3598 }; 3599 3600 Masonry.prototype.getContainerWidth = function() { 3601 // container is parent if fit width 3602 var container = this.options.isFitWidth ? this.element.parentNode : this.element; 3603 // check that this.size and size are there 3604 // IE8 triggers resize on body size change, so they might not be 3605 var size = getSize( container ); 3606 this.containerWidth = size && size.innerWidth; 3607 }; 3608 3609 Masonry.prototype._getItemLayoutPosition = function( item ) { 3610 item.getSize(); 3611 // how many columns does this brick span 3612 var remainder = item.size.outerWidth % this.columnWidth; 3613 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil'; 3614 // round if off by 1 pixel, otherwise use ceil 3615 var colSpan = Math[ mathMethod ]( item.size.outerWidth / this.columnWidth ); 3616 colSpan = Math.min( colSpan, this.cols ); 3617 3618 var colGroup = this._getColGroup( colSpan ); 3619 // get the minimum Y value from the columns 3620 var minimumY = Math.min.apply( Math, colGroup ); 3621 var shortColIndex = utils.indexOf( colGroup, minimumY ); 3622 3623 // position the brick 3624 var position = { 3625 x: this.columnWidth * shortColIndex, 3626 y: minimumY 3627 }; 3628 3629 // apply setHeight to necessary columns 3630 var setHeight = minimumY + item.size.outerHeight; 3631 var setSpan = this.cols + 1 - colGroup.length; 3632 for ( var i = 0; i < setSpan; i++ ) { 3633 this.colYs[ shortColIndex + i ] = setHeight; 3634 } 3635 3636 return position; 3637 }; 3638 3639 /** 3640 * @param {Number} colSpan - number of columns the element spans 3641 * @returns {Array} colGroup 3642 */ 3643 Masonry.prototype._getColGroup = function( colSpan ) { 3644 if ( colSpan < 2 ) { 3645 // if brick spans only one column, use all the column Ys 3646 return this.colYs; 3647 } 3648 3649 var colGroup = []; 3650 // how many different places could this brick fit horizontally 3651 var groupCount = this.cols + 1 - colSpan; 3652 // for each group potential horizontal position 3653 for ( var i = 0; i < groupCount; i++ ) { 3654 // make an array of colY values for that one group 3655 var groupColYs = this.colYs.slice( i, i + colSpan ); 3656 // and get the max value of the array 3657 colGroup[i] = Math.max.apply( Math, groupColYs ); 3658 } 3659 return colGroup; 3660 }; 3661 3662 Masonry.prototype._manageStamp = function( stamp ) { 3663 var stampSize = getSize( stamp ); 3664 var offset = this._getElementOffset( stamp ); 3665 // get the columns that this stamp affects 3666 var firstX = this.options.isOriginLeft ? offset.left : offset.right; 3667 var lastX = firstX + stampSize.outerWidth; 3668 var firstCol = Math.floor( firstX / this.columnWidth ); 3669 firstCol = Math.max( 0, firstCol ); 3670 var lastCol = Math.floor( lastX / this.columnWidth ); 3671 // lastCol should not go over if multiple of columnWidth #425 3672 lastCol -= lastX % this.columnWidth ? 0 : 1; 3673 lastCol = Math.min( this.cols - 1, lastCol ); 3674 // set colYs to bottom of the stamp 3675 var stampMaxY = ( this.options.isOriginTop ? offset.top : offset.bottom ) + 3676 stampSize.outerHeight; 3677 for ( var i = firstCol; i <= lastCol; i++ ) { 3678 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] ); 3679 } 3680 }; 3681 3682 Masonry.prototype._getContainerSize = function() { 3683 this.maxY = Math.max.apply( Math, this.colYs ); 3684 var size = { 3685 height: this.maxY 3686 }; 3687 3688 if ( this.options.isFitWidth ) { 3689 size.width = this._getContainerFitWidth(); 3690 } 3691 3692 return size; 3693 }; 3694 3695 Masonry.prototype._getContainerFitWidth = function() { 3696 var unusedCols = 0; 3697 // count unused columns 3698 var i = this.cols; 3699 while ( --i ) { 3700 if ( this.colYs[i] !== 0 ) { 3701 break; 3702 } 3703 unusedCols++; 3704 } 3705 // fit container to columns that have been used 3706 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter; 3707 }; 3708 3709 Masonry.prototype.needsResizeLayout = function() { 3710 var previousWidth = this.containerWidth; 3711 this.getContainerWidth(); 3712 return previousWidth !== this.containerWidth; 3713 }; 3714 3715 return Masonry; 3716 3717})); 3718 3719/*! 3720 * Masonry layout mode 3721 * sub-classes Masonry 3722 * http://masonry.desandro.com 3723 */ 3724 3725( function( window, factory ) { 3726 'use strict'; 3727 // universal module definition 3728 if ( typeof define == 'function' && define.amd ) { 3729 // AMD 3730 define( 'isotope/js/layout-modes/masonry',[ 3731 '../layout-mode', 3732 'masonry/masonry' 3733 ], 3734 factory ); 3735 } else if ( typeof exports == 'object' ) { 3736 // CommonJS 3737 module.exports = factory( 3738 require('../layout-mode'), 3739 require('masonry-layout') 3740 ); 3741 } else { 3742 // browser global 3743 factory( 3744 window.Isotope.LayoutMode, 3745 window.Masonry 3746 ); 3747 } 3748 3749}( window, function factory( LayoutMode, Masonry ) { 3750'use strict'; 3751 3752// -------------------------- helpers -------------------------- // 3753 3754// extend objects 3755function extend( a, b ) { 3756 for ( var prop in b ) { 3757 a[ prop ] = b[ prop ]; 3758 } 3759 return a; 3760} 3761 3762// -------------------------- masonryDefinition -------------------------- // 3763 3764 // create an Outlayer layout class 3765 var MasonryMode = LayoutMode.create('masonry'); 3766 3767 // save on to these methods 3768 var _getElementOffset = MasonryMode.prototype._getElementOffset; 3769 var layout = MasonryMode.prototype.layout; 3770 var _getMeasurement = MasonryMode.prototype._getMeasurement; 3771 3772 // sub-class Masonry 3773 extend( MasonryMode.prototype, Masonry.prototype ); 3774 3775 // set back, as it was overwritten by Masonry 3776 MasonryMode.prototype._getElementOffset = _getElementOffset; 3777 MasonryMode.prototype.layout = layout; 3778 MasonryMode.prototype._getMeasurement = _getMeasurement; 3779 3780 var measureColumns = MasonryMode.prototype.measureColumns; 3781 MasonryMode.prototype.measureColumns = function() { 3782 // set items, used if measuring first item 3783 this.items = this.isotope.filteredItems; 3784 measureColumns.call( this ); 3785 }; 3786 3787 // HACK copy over isOriginLeft/Top options 3788 var _manageStamp = MasonryMode.prototype._manageStamp; 3789 MasonryMode.prototype._manageStamp = function() { 3790 this.options.isOriginLeft = this.isotope.options.isOriginLeft; 3791 this.options.isOriginTop = this.isotope.options.isOriginTop; 3792 _manageStamp.apply( this, arguments ); 3793 }; 3794 3795 return MasonryMode; 3796 3797})); 3798 3799/** 3800 * fitRows layout mode 3801 */ 3802 3803( function( window, factory ) { 3804 'use strict'; 3805 // universal module definition 3806 if ( typeof define == 'function' && define.amd ) { 3807 // AMD 3808 define( 'isotope/js/layout-modes/fit-rows',[ 3809 '../layout-mode' 3810 ], 3811 factory ); 3812 } else if ( typeof exports == 'object' ) { 3813 // CommonJS 3814 module.exports = factory( 3815 require('../layout-mode') 3816 ); 3817 } else { 3818 // browser global 3819 factory( 3820 window.Isotope.LayoutMode 3821 ); 3822 } 3823 3824}( window, function factory( LayoutMode ) { 3825'use strict'; 3826 3827var FitRows = LayoutMode.create('fitRows'); 3828 3829FitRows.prototype._resetLayout = function() { 3830 this.x = 0; 3831 this.y = 0; 3832 this.maxY = 0; 3833 this._getMeasurement( 'gutter', 'outerWidth' ); 3834}; 3835 3836FitRows.prototype._getItemLayoutPosition = function( item ) { 3837 item.getSize(); 3838 3839 var itemWidth = item.size.outerWidth + this.gutter; 3840 // if this element cannot fit in the current row 3841 var containerWidth = this.isotope.size.innerWidth + this.gutter; 3842 if ( this.x !== 0 && itemWidth + this.x > containerWidth ) { 3843 this.x = 0; 3844 this.y = this.maxY; 3845 } 3846 3847 var position = { 3848 x: this.x, 3849 y: this.y 3850 }; 3851 3852 this.maxY = Math.max( this.maxY, this.y + item.size.outerHeight ); 3853 this.x += itemWidth; 3854 3855 return position; 3856}; 3857 3858FitRows.prototype._getContainerSize = function() { 3859 return { height: this.maxY }; 3860}; 3861 3862return FitRows; 3863 3864})); 3865 3866/** 3867 * vertical layout mode 3868 */ 3869 3870( function( window, factory ) { 3871 'use strict'; 3872 // universal module definition 3873 if ( typeof define == 'function' && define.amd ) { 3874 // AMD 3875 define( 'isotope/js/layout-modes/vertical',[ 3876 '../layout-mode' 3877 ], 3878 factory ); 3879 } else if ( typeof exports == 'object' ) { 3880 // CommonJS 3881 module.exports = factory( 3882 require('../layout-mode') 3883 ); 3884 } else { 3885 // browser global 3886 factory( 3887 window.Isotope.LayoutMode 3888 ); 3889 } 3890 3891}( window, function factory( LayoutMode ) { 3892'use strict'; 3893 3894var Vertical = LayoutMode.create( 'vertical', { 3895 horizontalAlignment: 0 3896}); 3897 3898Vertical.prototype._resetLayout = function() { 3899 this.y = 0; 3900}; 3901 3902Vertical.prototype._getItemLayoutPosition = function( item ) { 3903 item.getSize(); 3904 var x = ( this.isotope.size.innerWidth - item.size.outerWidth ) * 3905 this.options.horizontalAlignment; 3906 var y = this.y; 3907 this.y += item.size.outerHeight; 3908 return { x: x, y: y }; 3909}; 3910 3911Vertical.prototype._getContainerSize = function() { 3912 return { height: this.y }; 3913}; 3914 3915return Vertical; 3916 3917})); 3918 3919/*! 3920 * Isotope v2.2.2 3921 * 3922 * Licensed GPLv3 for open source use 3923 * or Isotope Commercial License for commercial use 3924 * 3925 * http://isotope.metafizzy.co 3926 * Copyright 2015 Metafizzy 3927 */ 3928 3929( function( window, factory ) { 3930 'use strict'; 3931 // universal module definition 3932 3933 if ( typeof define == 'function' && define.amd ) { 3934 // AMD 3935 define( [ 3936 'outlayer/outlayer', 3937 'get-size/get-size', 3938 'matches-selector/matches-selector', 3939 'fizzy-ui-utils/utils', 3940 'isotope/js/item', 3941 'isotope/js/layout-mode', 3942 // include default layout modes 3943 'isotope/js/layout-modes/masonry', 3944 'isotope/js/layout-modes/fit-rows', 3945 'isotope/js/layout-modes/vertical' 3946 ], 3947 function( Outlayer, getSize, matchesSelector, utils, Item, LayoutMode ) { 3948 return factory( window, Outlayer, getSize, matchesSelector, utils, Item, LayoutMode ); 3949 }); 3950 } else if ( typeof exports == 'object' ) { 3951 // CommonJS 3952 module.exports = factory( 3953 window, 3954 require('outlayer'), 3955 require('get-size'), 3956 require('desandro-matches-selector'), 3957 require('fizzy-ui-utils'), 3958 require('./item'), 3959 require('./layout-mode'), 3960 // include default layout modes 3961 require('./layout-modes/masonry'), 3962 require('./layout-modes/fit-rows'), 3963 require('./layout-modes/vertical') 3964 ); 3965 } else { 3966 // browser global 3967 window.Isotope = factory( 3968 window, 3969 window.Outlayer, 3970 window.getSize, 3971 window.matchesSelector, 3972 window.fizzyUIUtils, 3973 window.Isotope.Item, 3974 window.Isotope.LayoutMode 3975 ); 3976 } 3977 3978}( window, function factory( window, Outlayer, getSize, matchesSelector, utils, 3979 Item, LayoutMode ) { 3980 3981 3982 3983// -------------------------- vars -------------------------- // 3984 3985var jQuery = window.jQuery; 3986 3987// -------------------------- helpers -------------------------- // 3988 3989var trim = String.prototype.trim ? 3990 function( str ) { 3991 return str.trim(); 3992 } : 3993 function( str ) { 3994 return str.replace( /^\s+|\s+$/g, '' ); 3995 }; 3996 3997var docElem = document.documentElement; 3998 3999var getText = docElem.textContent ? 4000 function( elem ) { 4001 return elem.textContent; 4002 } : 4003 function( elem ) { 4004 return elem.innerText; 4005 }; 4006 4007// -------------------------- isotopeDefinition -------------------------- // 4008 4009 // create an Outlayer layout class 4010 var Isotope = Outlayer.create( 'isotope', { 4011 layoutMode: "masonry", 4012 isJQueryFiltering: true, 4013 sortAscending: true 4014 }); 4015 4016 Isotope.Item = Item; 4017 Isotope.LayoutMode = LayoutMode; 4018 4019 Isotope.prototype._create = function() { 4020 this.itemGUID = 0; 4021 // functions that sort items 4022 this._sorters = {}; 4023 this._getSorters(); 4024 // call super 4025 Outlayer.prototype._create.call( this ); 4026 4027 // create layout modes 4028 this.modes = {}; 4029 // start filteredItems with all items 4030 this.filteredItems = this.items; 4031 // keep of track of sortBys 4032 this.sortHistory = [ 'original-order' ]; 4033 // create from registered layout modes 4034 for ( var name in LayoutMode.modes ) { 4035 this._initLayoutMode( name ); 4036 } 4037 }; 4038 4039 Isotope.prototype.reloadItems = function() { 4040 // reset item ID counter 4041 this.itemGUID = 0; 4042 // call super 4043 Outlayer.prototype.reloadItems.call( this ); 4044 }; 4045 4046 Isotope.prototype._itemize = function() { 4047 var items = Outlayer.prototype._itemize.apply( this, arguments ); 4048 // assign ID for original-order 4049 for ( var i=0, len = items.length; i < len; i++ ) { 4050 var item = items[i]; 4051 item.id = this.itemGUID++; 4052 } 4053 this._updateItemsSortData( items ); 4054 return items; 4055 }; 4056 4057 4058 // -------------------------- layout -------------------------- // 4059 4060 Isotope.prototype._initLayoutMode = function( name ) { 4061 var Mode = LayoutMode.modes[ name ]; 4062 // set mode options 4063 // HACK extend initial options, back-fill in default options 4064 var initialOpts = this.options[ name ] || {}; 4065 this.options[ name ] = Mode.options ? 4066 utils.extend( Mode.options, initialOpts ) : initialOpts; 4067 // init layout mode instance 4068 this.modes[ name ] = new Mode( this ); 4069 }; 4070 4071 4072 Isotope.prototype.layout = function() { 4073 // if first time doing layout, do all magic 4074 if ( !this._isLayoutInited && this.options.isInitLayout ) { 4075 this.arrange(); 4076 return; 4077 } 4078 this._layout(); 4079 }; 4080 4081 // private method to be used in layout() & magic() 4082 Isotope.prototype._layout = function() { 4083 // don't animate first layout 4084 var isInstant = this._getIsInstant(); 4085 // layout flow 4086 this._resetLayout(); 4087 this._manageStamps(); 4088 this.layoutItems( this.filteredItems, isInstant ); 4089 4090 // flag for initalized 4091 this._isLayoutInited = true; 4092 }; 4093 4094 // filter + sort + layout 4095 Isotope.prototype.arrange = function( opts ) { 4096 // set any options pass 4097 this.option( opts ); 4098 this._getIsInstant(); 4099 // filter, sort, and layout 4100 4101 // filter 4102 var filtered = this._filter( this.items ); 4103 this.filteredItems = filtered.matches; 4104 4105 var _this = this; 4106 function hideReveal() { 4107 _this.reveal( filtered.needReveal ); 4108 _this.hide( filtered.needHide ); 4109 } 4110 4111 this._bindArrangeComplete(); 4112 4113 if ( this._isInstant ) { 4114 this._noTransition( hideReveal ); 4115 } else { 4116 hideReveal(); 4117 } 4118 4119 this._sort(); 4120 this._layout(); 4121 }; 4122 // alias to _init for main plugin method 4123 Isotope.prototype._init = Isotope.prototype.arrange; 4124 4125 // HACK 4126 // Don't animate/transition first layout 4127 // Or don't animate/transition other layouts 4128 Isotope.prototype._getIsInstant = function() { 4129 var isInstant = this.options.isLayoutInstant !== undefined ? 4130 this.options.isLayoutInstant : !this._isLayoutInited; 4131 this._isInstant = isInstant; 4132 return isInstant; 4133 }; 4134 4135 // listen for layoutComplete, hideComplete and revealComplete 4136 // to trigger arrangeComplete 4137 Isotope.prototype._bindArrangeComplete = function() { 4138 // listen for 3 events to trigger arrangeComplete 4139 var isLayoutComplete, isHideComplete, isRevealComplete; 4140 var _this = this; 4141 function arrangeParallelCallback() { 4142 if ( isLayoutComplete && isHideComplete && isRevealComplete ) { 4143 _this.dispatchEvent( 'arrangeComplete', null, [ _this.filteredItems ] ); 4144 } 4145 } 4146 this.once( 'layoutComplete', function() { 4147 isLayoutComplete = true; 4148 arrangeParallelCallback(); 4149 }); 4150 this.once( 'hideComplete', function() { 4151 isHideComplete = true; 4152 arrangeParallelCallback(); 4153 }); 4154 this.once( 'revealComplete', function() { 4155 isRevealComplete = true; 4156 arrangeParallelCallback(); 4157 }); 4158 }; 4159 4160 // -------------------------- filter -------------------------- // 4161 4162 Isotope.prototype._filter = function( items ) { 4163 var filter = this.options.filter;
4164 filter = filter || '*'; 4165 var matches = []; 4166 var hiddenMatched = []; 4167 var visibleUnmatched = []; 4168 4169 var test = this._getFilterTest( filter ); 4170 4171 // test each item 4172 for ( var i=0, len = items.length; i < len; i++ ) { 4173 var item = items[i]; 4174 if ( item.isIgnored ) { 4175 continue; 4176 } 4177 // add item to either matched or unmatched group 4178 var isMatched = test( item ); 4179 // item.isFilterMatched = isMatched; 4180 // add to matches if its a match 4181 if ( isMatched ) { 4182 matches.push( item ); 4183 } 4184 // add to additional group if item needs to be hidden or revealed 4185 if ( isMatched && item.isHidden ) { 4186 hiddenMatched.push( item ); 4187 } else if ( !isMatched && !item.isHidden ) { 4188 visibleUnmatched.push( item ); 4189 } 4190 } 4191 4192 // return collections of items to be manipulated 4193 return { 4194 matches: matches, 4195 needReveal: hiddenMatched, 4196 needHide: visibleUnmatched 4197 }; 4198 }; 4199 4200 // get a jQuery, function, or a matchesSelector test given the filter 4201 Isotope.prototype._getFilterTest = function( filter ) { 4202 if ( jQuery && this.options.isJQueryFiltering ) { 4203 // use jQuery 4204 return function( item ) { 4205 return jQuery( item.element ).is( filter ); 4206 }; 4207 } 4208 if ( typeof filter == 'function' ) { 4209 // use filter as function 4210 return function( item ) { 4211 return filter( item.element ); 4212 }; 4213 } 4214 // default, use filter as selector string 4215 return function( item ) { 4216 return matchesSelector( item.element, filter ); 4217 }; 4218 }; 4219 4220 // -------------------------- sorting -------------------------- // 4221 4222 /** 4223 * @params {Array} elems 4224 * @public 4225 */ 4226 Isotope.prototype.updateSortData = function( elems ) { 4227 // get items 4228 var items; 4229 if ( elems ) { 4230 elems = utils.makeArray( elems ); 4231 items = this.getItems( elems ); 4232 } else { 4233 // update all items if no elems provided 4234 items = this.items; 4235 } 4236 4237 this._getSorters(); 4238 this._updateItemsSortData( items ); 4239 }; 4240 4241 Isotope.prototype._getSorters = function() { 4242 var getSortData = this.options.getSortData; 4243 for ( var key in getSortData ) { 4244 var sorter = getSortData[ key ]; 4245 this._sorters[ key ] = mungeSorter( sorter ); 4246 } 4247 }; 4248 4249 /** 4250 * @params {Array} items - of Isotope.Items 4251 * @private 4252 */ 4253 Isotope.prototype._updateItemsSortData = function( items ) { 4254 // do not update if no items 4255 var len = items && items.length; 4256 4257 for ( var i=0; len && i < len; i++ ) { 4258 var item = items[i]; 4259 item.updateSortData(); 4260 } 4261 }; 4262 4263 // ----- munge sorter ----- // 4264 4265 // encapsulate this, as we just need mungeSorter 4266 // other functions in here are just for munging 4267 var mungeSorter = ( function() { 4268 // add a magic layer to sorters for convienent shorthands 4269 // `.foo-bar` will use the text of .foo-bar querySelector 4270 // `[foo-bar]` will use attribute 4271 // you can also add parser 4272 // `.foo-bar parseInt` will parse that as a number 4273 function mungeSorter( sorter ) { 4274 // if not a string, return function or whatever it is 4275 if ( typeof sorter != 'string' ) { 4276 return sorter; 4277 } 4278 // parse the sorter string 4279 var args = trim( sorter ).split(' '); 4280 var query = args[0]; 4281 // check if query looks like [an-attribute] 4282 var attrMatch = query.match( /^\[(.+)\]$/ ); 4283 var attr = attrMatch && attrMatch[1]; 4284 var getValue = getValueGetter( attr, query ); 4285 // use second argument as a parser 4286 var parser = Isotope.sortDataParsers[ args[1] ]; 4287 // parse the value, if there was a parser 4288 sorter = parser ? function( elem ) { 4289 return elem && parser( getValue( elem ) ); 4290 } : 4291 // otherwise just return value 4292 function( elem ) { 4293 return elem && getValue( elem ); 4294 }; 4295 4296 return sorter; 4297 } 4298 4299 // get an attribute getter, or get text of the querySelector 4300 function getValueGetter( attr, query ) { 4301 var getValue; 4302 // if query looks like [foo-bar], get attribute 4303 if ( attr ) { 4304 getValue = function( elem ) { 4305 return elem.getAttribute( attr ); 4306 }; 4307 } else { 4308 // otherwise, assume its a querySelector, and get its text 4309 getValue = function( elem ) { 4310 var child = elem.querySelector( query ); 4311 return child && getText( child ); 4312 }; 4313 } 4314 return getValue; 4315 } 4316 4317 return mungeSorter; 4318 })(); 4319 4320 // parsers used in getSortData shortcut strings 4321 Isotope.sortDataParsers = { 4322 'parseInt': function( val ) { 4323 return parseInt( val, 10 ); 4324 }, 4325 'parseFloat': function( val ) { 4326 return parseFloat( val ); 4327 } 4328 }; 4329 4330 // ----- sort method ----- // 4331 4332 // sort filteredItem order 4333 Isotope.prototype._sort = function() { 4334 var sortByOpt = this.options.sortBy; 4335 if ( !sortByOpt ) { 4336 return; 4337 } 4338 // concat all sortBy and sortHistory 4339 var sortBys = [].concat.apply( sortByOpt, this.sortHistory ); 4340 // sort magic 4341 var itemSorter = getItemSorter( sortBys, this.options.sortAscending ); 4342 this.filteredItems.sort( itemSorter ); 4343 // keep track of sortBy History 4344 if ( sortByOpt != this.sortHistory[0] ) { 4345 // add to front, oldest goes in last 4346 this.sortHistory.unshift( sortByOpt ); 4347 } 4348 }; 4349 4350 // returns a function used for sorting 4351 function getItemSorter( sortBys, sortAsc ) { 4352 return function sorter( itemA, itemB ) { 4353 // cycle through all sortKeys 4354 for ( var i = 0, len = sortBys.length; i < len; i++ ) { 4355 var sortBy = sortBys[i]; 4356 var a = itemA.sortData[ sortBy ]; 4357 var b = itemB.sortData[ sortBy ]; 4358 if ( a > b || a < b ) { 4359 // if sortAsc is an object, use the value given the sortBy key
4360 var isAscending = sortAsc[ sortBy ] !== undefined ? sortAsc[ sortBy ] : sortAsc; 4361 var direction = isAscending ? 1 : -1; 4362 return ( a > b ? 1 : -1 ) * direction; 4363 } 4364 } 4365 return 0; 4366 }; 4367 } 4368 4369 // -------------------------- methods -------------------------- // 4370 4371 // get layout mode 4372 Isotope.prototype._mode = function() { 4373 var layoutMode = this.options.layoutMode; 4374 var mode = this.modes[ layoutMode ]; 4375 if ( !mode ) { 4376 // TODO console.error 4377 throw new Error( 'No layout mode: ' + layoutMode ); 4378 } 4379 // HACK sync mode's options 4380 // any options set after init for layout mode need to be synced 4381 mode.options = this.options[ layoutMode ]; 4382 return mode; 4383 }; 4384 4385 Isotope.prototype._resetLayout = function() { 4386 // trigger original reset layout 4387 Outlayer.prototype._resetLayout.call( this ); 4388 this._mode()._resetLayout(); 4389 }; 4390 4391 Isotope.prototype._getItemLayoutPosition = function( item ) { 4392 return this._mode()._getItemLayoutPosition( item ); 4393 }; 4394 4395 Isotope.prototype._manageStamp = function( stamp ) { 4396 this._mode()._manageStamp( stamp ); 4397 }; 4398 4399 Isotope.prototype._getContainerSize = function() { 4400 return this._mode()._getContainerSize(); 4401 }; 4402 4403 Isotope.prototype.needsResizeLayout = function() { 4404 return this._mode().needsResizeLayout(); 4405 }; 4406 4407 // -------------------------- adding & removing -------------------------- // 4408 4409 // HEADS UP overwrites default Outlayer appended 4410 Isotope.prototype.appended = function( elems ) { 4411 var items = this.addItems( elems ); 4412 if ( !items.length ) { 4413 return; 4414 } 4415 // filter, layout, reveal new items 4416 var filteredItems = this._filterRevealAdded( items ); 4417 // add to filteredItems 4418 this.filteredItems = this.filteredItems.concat( filteredItems ); 4419 }; 4420 4421 // HEADS UP overwrites default Outlayer prepended 4422 Isotope.prototype.prepended = function( elems ) { 4423 var items = this._itemize( elems ); 4424 if ( !items.length ) { 4425 return; 4426 } 4427 // start new layout 4428 this._resetLayout(); 4429 this._manageStamps(); 4430 // filter, layout, reveal new items 4431 var filteredItems = this._filterRevealAdded( items ); 4432 // layout previous items 4433 this.layoutItems( this.filteredItems ); 4434 // add to items and filteredItems 4435 this.filteredItems = filteredItems.concat( this.filteredItems ); 4436 this.items = items.concat( this.items ); 4437 }; 4438 4439 Isotope.prototype._filterRevealAdded = function( items ) { 4440 var filtered = this._filter( items ); 4441 this.hide( filtered.needHide ); 4442 // reveal all new items 4443 this.reveal( filtered.matches ); 4444 // layout new items, no transition 4445 this.layoutItems( filtered.matches, true ); 4446 return filtered.matches; 4447 }; 4448 4449 /** 4450 * Filter, sort, and layout newly-appended item elements 4451 * @param {Array or NodeList or Element} elems 4452 */ 4453 Isotope.prototype.insert = function( elems ) { 4454 var items = this.addItems( elems ); 4455 if ( !items.length ) { 4456 return; 4457 } 4458 // append item elements 4459 var i, item; 4460 var len = items.length; 4461 for ( i=0; i < len; i++ ) { 4462 item = items[i]; 4463 this.element.appendChild( item.element ); 4464 } 4465 // filter new stuff 4466 var filteredInsertItems = this._filter( items ).matches; 4467 // set flag 4468 for ( i=0; i < len; i++ ) { 4469 items[i].isLayoutInstant = true; 4470 } 4471 this.arrange(); 4472 // reset flag 4473 for ( i=0; i < len; i++ ) { 4474 delete items[i].isLayoutInstant; 4475 } 4476 this.reveal( filteredInsertItems ); 4477 }; 4478 4479 var _remove = Isotope.prototype.remove; 4480 Isotope.prototype.remove = function( elems ) { 4481 elems = utils.makeArray( elems ); 4482 var removeItems = this.getItems( elems ); 4483 // do regular thing 4484 _remove.call( this, elems ); 4485 // bail if no items to remove 4486 var len = removeItems && removeItems.length; 4487 if ( !len ) { 4488 return; 4489 } 4490 // remove elems from filteredItems 4491 for ( var i=0; i < len; i++ ) { 4492 var item = removeItems[i]; 4493 // remove item from collection 4494 utils.removeFrom( this.filteredItems, item ); 4495 } 4496 }; 4497 4498 Isotope.prototype.shuffle = function() { 4499 // update random sortData 4500 for ( var i=0, len = this.items.length; i < len; i++ ) { 4501 var item = this.items[i]; 4502 item.sortData.random = Math.random(); 4503 } 4504 this.options.sortBy = 'random'; 4505 this._sort(); 4506 this._layout(); 4507 }; 4508 4509 /** 4510 * trigger fn without transition 4511 * kind of hacky to have this in the first place 4512 * @param {Function} fn 4513 * @returns ret 4514 * @private 4515 */ 4516 Isotope.prototype._noTransition = function( fn ) { 4517 // save transitionDuration before disabling 4518 var transitionDuration = this.options.transitionDuration; 4519 // disable transition 4520 this.options.transitionDuration = 0; 4521 // do it 4522 var returnValue = fn.call( this ); 4523 // re-enable transition for reveal 4524 this.options.transitionDuration = transitionDuration; 4525 return returnValue; 4526 }; 4527 4528 // ----- helper methods ----- // 4529 4530 /** 4531 * getter method for getting filtered item elements 4532 * @returns {Array} elems - collection of item elements 4533 */ 4534 Isotope.prototype.getFilteredItemElements = function() { 4535 var elems = []; 4536 for ( var i=0, len = this.filteredItems.length; i < len; i++ ) { 4537 elems.push( this.filteredItems[i].element ); 4538 } 4539 return elems; 4540 }; 4541 4542 // ----- ----- // 4543 4544 return Isotope; 4545 4546})); 4547
vendor: 29,252 bytes, lines 4548-5704
4548/*! 4549 * Packery layout mode PACKAGED v2.0.1 4550 * sub-classes Packery 4551 */ 4552 4553/** 4554 * Rect 4555 * low-level utility class for basic geometry 4556 */ 4557 4558( function( window, factory ) { 4559 // universal module definition 4560 /* jshint strict: false */ /* globals define, module */ 4561 if ( typeof define == 'function' && define.amd ) { 4562 // AMD 4563 define( 'packery/js/rect',factory ); 4564 } else if ( typeof module == 'object' && module.exports ) { 4565 // CommonJS 4566 module.exports = factory(); 4567 } else { 4568 // browser global 4569 window.Packery = window.Packery || {}; 4570 window.Packery.Rect = factory(); 4571 } 4572 4573}( window, function factory() { 4574 4575 4576// -------------------------- Rect -------------------------- // 4577 4578function Rect( props ) { 4579 // extend properties from defaults 4580 for ( var prop in Rect.defaults ) { 4581 this[ prop ] = Rect.defaults[ prop ]; 4582 } 4583 4584 for ( prop in props ) { 4585 this[ prop ] = props[ prop ]; 4586 } 4587 4588} 4589 4590Rect.defaults = { 4591 x: 0, 4592 y: 0, 4593 width: 0, 4594 height: 0 4595}; 4596 4597var proto = Rect.prototype; 4598 4599/** 4600 * Determines whether or not this rectangle wholly encloses another rectangle or point. 4601 * @param {Rect} rect 4602 * @returns {Boolean} 4603**/ 4604proto.contains = function( rect ) { 4605 // points don't have width or height 4606 var otherWidth = rect.width || 0; 4607 var otherHeight = rect.height || 0; 4608 return this.x <= rect.x && 4609 this.y <= rect.y && 4610 this.x + this.width >= rect.x + otherWidth && 4611 this.y + this.height >= rect.y + otherHeight; 4612}; 4613 4614/** 4615 * Determines whether or not the rectangle intersects with another. 4616 * @param {Rect} rect 4617 * @returns {Boolean} 4618**/ 4619proto.overlaps = function( rect ) { 4620 var thisRight = this.x + this.width; 4621 var thisBottom = this.y + this.height; 4622 var rectRight = rect.x + rect.width; 4623 var rectBottom = rect.y + rect.height; 4624 4625 // http://stackoverflow.com/a/306332 4626 return this.x < rectRight && 4627 thisRight > rect.x && 4628 this.y < rectBottom && 4629 thisBottom > rect.y; 4630}; 4631 4632/** 4633 * @param {Rect} rect - the overlapping rect 4634 * @returns {Array} freeRects - rects representing the area around the rect 4635**/ 4636proto.getMaximalFreeRects = function( rect ) { 4637 4638 // if no intersection, return false 4639 if ( !this.overlaps( rect ) ) { 4640 return false; 4641 } 4642 4643 var freeRects = []; 4644 var freeRect; 4645 4646 var thisRight = this.x + this.width; 4647 var thisBottom = this.y + this.height; 4648 var rectRight = rect.x + rect.width; 4649 var rectBottom = rect.y + rect.height; 4650 4651 // top 4652 if ( this.y < rect.y ) { 4653 freeRect = new Rect({ 4654 x: this.x, 4655 y: this.y, 4656 width: this.width, 4657 height: rect.y - this.y 4658 }); 4659 freeRects.push( freeRect ); 4660 } 4661 4662 // right 4663 if ( thisRight > rectRight ) { 4664 freeRect = new Rect({ 4665 x: rectRight, 4666 y: this.y, 4667 width: thisRight - rectRight, 4668 height: this.height 4669 }); 4670 freeRects.push( freeRect ); 4671 } 4672 4673 // bottom 4674 if ( thisBottom > rectBottom ) { 4675 freeRect = new Rect({ 4676 x: this.x, 4677 y: rectBottom, 4678 width: this.width, 4679 height: thisBottom - rectBottom 4680 }); 4681 freeRects.push( freeRect ); 4682 } 4683 4684 // left 4685 if ( this.x < rect.x ) { 4686 freeRect = new Rect({ 4687 x: this.x, 4688 y: this.y, 4689 width: rect.x - this.x, 4690 height: this.height 4691 }); 4692 freeRects.push( freeRect ); 4693 } 4694 4695 return freeRects; 4696}; 4697 4698proto.canFit = function( rect ) { 4699 return this.width >= rect.width && this.height >= rect.height; 4700}; 4701 4702return Rect; 4703 4704})); 4705 4706/** 4707 * Packer 4708 * bin-packing algorithm 4709 */ 4710 4711( function( window, factory ) { 4712 // universal module definition 4713 /* jshint strict: false */ /* globals define, module, require */ 4714 if ( typeof define == 'function' && define.amd ) { 4715 // AMD 4716 define( 'packery/js/packer',[ './rect' ], factory ); 4717 } else if ( typeof module == 'object' && module.exports ) { 4718 // CommonJS 4719 module.exports = factory( 4720 require('./rect') 4721 ); 4722 } else { 4723 // browser global 4724 var Packery = window.Packery = window.Packery || {}; 4725 Packery.Packer = factory( Packery.Rect ); 4726 } 4727 4728}( window, function factory( Rect ) { 4729 4730 4731// -------------------------- Packer -------------------------- // 4732 4733/** 4734 * @param {Number} width 4735 * @param {Number} height 4736 * @param {String} sortDirection 4737 * topLeft for vertical, leftTop for horizontal 4738 */ 4739function Packer( width, height, sortDirection ) { 4740 this.width = width || 0; 4741 this.height = height || 0; 4742 this.sortDirection = sortDirection || 'downwardLeftToRight'; 4743 4744 this.reset(); 4745} 4746 4747var proto = Packer.prototype; 4748 4749proto.reset = function() { 4750 this.spaces = []; 4751 4752 var initialSpace = new Rect({ 4753 x: 0, 4754 y: 0, 4755 width: this.width, 4756 height: this.height 4757 }); 4758 4759 this.spaces.push( initialSpace ); 4760 // set sorter 4761 this.sorter = sorters[ this.sortDirection ] || sorters.downwardLeftToRight; 4762}; 4763 4764// change x and y of rect to fit with in Packer's available spaces 4765proto.pack = function( rect ) { 4766 for ( var i=0; i < this.spaces.length; i++ ) { 4767 var space = this.spaces[i]; 4768 if ( space.canFit( rect ) ) { 4769 this.placeInSpace( rect, space ); 4770 break; 4771 } 4772 } 4773}; 4774 4775proto.columnPack = function( rect ) { 4776 for ( var i=0; i < this.spaces.length; i++ ) { 4777 var space = this.spaces[i]; 4778 var canFitInSpaceColumn = space.x <= rect.x && 4779 space.x + space.width >= rect.x + rect.width && 4780 space.height >= rect.height - 0.01; // fudge number for rounding error 4781 if ( canFitInSpaceColumn ) { 4782 rect.y = space.y; 4783 this.placed( rect ); 4784 break; 4785 } 4786 } 4787}; 4788 4789proto.rowPack = function( rect ) { 4790 for ( var i=0; i < this.spaces.length; i++ ) { 4791 var space = this.spaces[i]; 4792 var canFitInSpaceRow = space.y <= rect.y && 4793 space.y + space.height >= rect.y + rect.height && 4794 space.width >= rect.width - 0.01; // fudge number for rounding error 4795 if ( canFitInSpaceRow ) { 4796 rect.x = space.x; 4797 this.placed( rect ); 4798 break; 4799 } 4800 } 4801}; 4802 4803proto.placeInSpace = function( rect, space ) { 4804 // place rect in space 4805 rect.x = space.x; 4806 rect.y = space.y; 4807 4808 this.placed( rect ); 4809}; 4810 4811// update spaces with placed rect 4812proto.placed = function( rect ) { 4813 // update spaces 4814 var revisedSpaces = []; 4815 for ( var i=0; i < this.spaces.length; i++ ) { 4816 var space = this.spaces[i]; 4817 var newSpaces = space.getMaximalFreeRects( rect ); 4818 // add either the original space or the new spaces to the revised spaces 4819 if ( newSpaces ) { 4820 revisedSpaces.push.apply( revisedSpaces, newSpaces ); 4821 } else { 4822 revisedSpaces.push( space ); 4823 } 4824 } 4825 4826 this.spaces = revisedSpaces; 4827 4828 this.mergeSortSpaces(); 4829}; 4830 4831proto.mergeSortSpaces = function() { 4832 // remove redundant spaces 4833 Packer.mergeRects( this.spaces ); 4834 this.spaces.sort( this.sorter ); 4835}; 4836 4837// add a space back 4838proto.addSpace = function( rect ) { 4839 this.spaces.push( rect ); 4840 this.mergeSortSpaces(); 4841}; 4842 4843// -------------------------- utility functions -------------------------- // 4844 4845/** 4846 * Remove redundant rectangle from array of rectangles 4847 * @param {Array} rects: an array of Rects 4848 * @returns {Array} rects: an array of Rects 4849**/ 4850Packer.mergeRects = function( rects ) { 4851 var i = 0; 4852 var rect = rects[i]; 4853 4854 rectLoop: 4855 while ( rect ) { 4856 var j = 0; 4857 var compareRect = rects[ i + j ]; 4858 4859 while ( compareRect ) { 4860 if ( compareRect == rect ) { 4861 j++; // next 4862 } else if ( compareRect.contains( rect ) ) { 4863 // remove rect 4864 rects.splice( i, 1 ); 4865 rect = rects[i]; // set next rect 4866 continue rectLoop; // bail on compareLoop 4867 } else if ( rect.contains( compareRect ) ) { 4868 // remove compareRect 4869 rects.splice( i + j, 1 ); 4870 } else { 4871 j++; 4872 } 4873 compareRect = rects[ i + j ]; // set next compareRect 4874 } 4875 i++; 4876 rect = rects[i]; 4877 } 4878 4879 return rects; 4880}; 4881 4882 4883// -------------------------- sorters -------------------------- // 4884 4885// functions for sorting rects in order 4886var sorters = { 4887 // top down, then left to right 4888 downwardLeftToRight: function( a, b ) { 4889 return a.y - b.y || a.x - b.x; 4890 }, 4891 // left to right, then top down 4892 rightwardTopToBottom: function( a, b ) { 4893 return a.x - b.x || a.y - b.y; 4894 } 4895}; 4896 4897 4898// -------------------------- -------------------------- // 4899 4900return Packer; 4901 4902})); 4903 4904/** 4905 * Packery Item Element 4906**/ 4907 4908( function( window, factory ) { 4909 // universal module definition 4910 /* jshint strict: false */ /* globals define, module, require */ 4911 if ( typeof define == 'function' && define.amd ) { 4912 // AMD 4913 define( 'packery/js/item',[ 4914 'outlayer/outlayer', 4915 './rect' 4916 ], 4917 factory ); 4918 } else if ( typeof module == 'object' && module.exports ) { 4919 // CommonJS 4920 module.exports = factory( 4921 require('outlayer'), 4922 require('./rect') 4923 ); 4924 } else { 4925 // browser global 4926 window.Packery.Item = factory( 4927 window.Outlayer, 4928 window.Packery.Rect 4929 ); 4930 } 4931 4932}( window, function factory( Outlayer, Rect ) { 4933 4934 4935// -------------------------- Item -------------------------- // 4936 4937var docElemStyle = document.documentElement.style; 4938 4939var transformProperty = typeof docElemStyle.transform == 'string' ? 4940 'transform' : 'WebkitTransform'; 4941 4942// sub-class Item 4943var Item = function PackeryItem() { 4944 Outlayer.Item.apply( this, arguments ); 4945}; 4946 4947var proto = Item.prototype = Object.create( Outlayer.Item.prototype ); 4948 4949var __create = proto._create; 4950proto._create = function() { 4951 // call default _create logic 4952 __create.call( this ); 4953 this.rect = new Rect(); 4954}; 4955 4956var _moveTo = proto.moveTo; 4957proto.moveTo = function( x, y ) { 4958 // don't shift 1px while dragging 4959 var dx = Math.abs( this.position.x - x ); 4960 var dy = Math.abs( this.position.y - y ); 4961 4962 var canHackGoTo = this.layout.dragItemCount && !this.isPlacing && 4963 !this.isTransitioning && dx < 1 && dy < 1; 4964 if ( canHackGoTo ) { 4965 this.goTo( x, y ); 4966 return; 4967 } 4968 _moveTo.apply( this, arguments ); 4969}; 4970 4971// -------------------------- placing -------------------------- // 4972 4973proto.enablePlacing = function() { 4974 this.removeTransitionStyles(); 4975 // remove transform property from transition 4976 if ( this.isTransitioning && transformProperty ) { 4977 this.element.style[ transformProperty ] = 'none'; 4978 } 4979 this.isTransitioning = false; 4980 this.getSize(); 4981 this.layout._setRectSize( this.element, this.rect ); 4982 this.isPlacing = true; 4983}; 4984 4985proto.disablePlacing = function() { 4986 this.isPlacing = false; 4987}; 4988 4989// ----- ----- // 4990 4991// remove element from DOM 4992proto.removeElem = function() { 4993 this.element.parentNode.removeChild( this.element ); 4994 // add space back to packer 4995 this.layout.packer.addSpace( this.rect ); 4996 this.emitEvent( 'remove', [ this ] ); 4997}; 4998 4999// ----- dropPlaceholder ----- // 5000 5001proto.showDropPlaceholder = function() { 5002 var dropPlaceholder = this.dropPlaceholder; 5003 if ( !dropPlaceholder ) { 5004 // create dropPlaceholder 5005 dropPlaceholder = this.dropPlaceholder = document.createElement('div'); 5006 dropPlaceholder.className = 'packery-drop-placeholder'; 5007 dropPlaceholder.style.position = 'absolute'; 5008 } 5009 5010 dropPlaceholder.style.width = this.size.width + 'px'; 5011 dropPlaceholder.style.height = this.size.height + 'px'; 5012 this.positionDropPlaceholder(); 5013 this.layout.element.appendChild( dropPlaceholder ); 5014}; 5015 5016proto.positionDropPlaceholder = function() { 5017 this.dropPlaceholder.style[ transformProperty ] = 'translate(' + 5018 this.rect.x + 'px, ' + this.rect.y + 'px)'; 5019}; 5020 5021proto.hideDropPlaceholder = function() { 5022 this.layout.element.removeChild( this.dropPlaceholder ); 5023}; 5024 5025// ----- ----- // 5026 5027return Item; 5028 5029})); 5030 5031/*! 5032 * Packery v2.0.0 5033 * Gapless, draggable grid layouts 5034 * 5035 * Licensed GPLv3 for open source use 5036 * or Packery Commercial License for commercial use 5037 * 5038 * http://packery.metafizzy.co 5039 * Copyright 2016 Metafizzy 5040 */ 5041 5042( function( window, factory ) { 5043 // universal module definition 5044 /* jshint strict: false */ /* globals define, module, require */ 5045 if ( typeof define == 'function' && define.amd ) { 5046 // AMD 5047 define( 'packery/js/packery',[ 5048 'get-size/get-size', 5049 'outlayer/outlayer', 5050 './rect', 5051 './packer', 5052 './item' 5053 ], 5054 factory ); 5055 } else if ( typeof module == 'object' && module.exports ) { 5056 // CommonJS 5057 module.exports = factory( 5058 require('get-size'), 5059 require('outlayer'), 5060 require('./rect'), 5061 require('./packer'), 5062 require('./item') 5063 ); 5064 } else { 5065 // browser global 5066 window.Packery = factory( 5067 window.getSize, 5068 window.Outlayer, 5069 window.Packery.Rect, 5070 window.Packery.Packer, 5071 window.Packery.Item 5072 ); 5073 } 5074 5075}( window, function factory( getSize, Outlayer, Rect, Packer, Item ) { 5076 5077 5078// ----- Rect ----- // 5079 5080// allow for pixel rounding errors IE8-IE11 & Firefox; #227 5081Rect.prototype.canFit = function( rect ) { 5082 return this.width >= rect.width - 1 && this.height >= rect.height - 1; 5083}; 5084 5085// -------------------------- Packery -------------------------- // 5086 5087// create an Outlayer layout class 5088var Packery = Outlayer.create('packery'); 5089Packery.Item = Item; 5090 5091var proto = Packery.prototype; 5092 5093proto._create = function() { 5094 // call super 5095 Outlayer.prototype._create.call( this ); 5096 5097 // initial properties 5098 this.packer = new Packer(); 5099 // packer for drop targets 5100 this.shiftPacker = new Packer(); 5101 this.isEnabled = true; 5102 5103 this.dragItemCount = 0; 5104 5105 // create drag handlers 5106 var _this = this; 5107 this.handleDraggabilly = { 5108 dragStart: function() { 5109 _this.itemDragStart( this.element ); 5110 }, 5111 dragMove: function() { 5112 _this.itemDragMove( this.element, this.position.x, this.position.y ); 5113 }, 5114 dragEnd: function() { 5115 _this.itemDragEnd( this.element ); 5116 } 5117 }; 5118 5119 this.handleUIDraggable = { 5120 start: function handleUIDraggableStart( event, ui ) { 5121 // HTML5 may trigger dragstart, dismiss HTML5 dragging 5122 if ( !ui ) { 5123 return; 5124 } 5125 _this.itemDragStart( event.currentTarget ); 5126 }, 5127 drag: function handleUIDraggableDrag( event, ui ) { 5128 if ( !ui ) { 5129 return; 5130 } 5131 _this.itemDragMove( event.currentTarget, ui.position.left, ui.position.top ); 5132 }, 5133 stop: function handleUIDraggableStop( event, ui ) { 5134 if ( !ui ) { 5135 return; 5136 } 5137 _this.itemDragEnd( event.currentTarget ); 5138 } 5139 }; 5140 5141}; 5142 5143 5144// ----- init & layout ----- // 5145 5146/** 5147 * logic before any new layout 5148 */ 5149proto._resetLayout = function() { 5150 this.getSize(); 5151 5152 this._getMeasurements(); 5153 5154 // reset packer 5155 var width, height, sortDirection; 5156 // packer settings, if horizontal or vertical 5157 if ( this._getOption('horizontal') ) { 5158 width = Infinity; 5159 height = this.size.innerHeight + this.gutter; 5160 sortDirection = 'rightwardTopToBottom'; 5161 } else { 5162 width = this.size.innerWidth + this.gutter; 5163 height = Infinity; 5164 sortDirection = 'downwardLeftToRight'; 5165 } 5166 5167 this.packer.width = this.shiftPacker.width = width; 5168 this.packer.height = this.shiftPacker.height = height; 5169 this.packer.sortDirection = this.shiftPacker.sortDirection = sortDirection; 5170 5171 this.packer.reset(); 5172 5173 // layout 5174 this.maxY = 0; 5175 this.maxX = 0; 5176}; 5177 5178/** 5179 * update columnWidth, rowHeight, & gutter 5180 * @private 5181 */ 5182proto._getMeasurements = function() { 5183 this._getMeasurement( 'columnWidth', 'width' ); 5184 this._getMeasurement( 'rowHeight', 'height' ); 5185 this._getMeasurement( 'gutter', 'width' ); 5186}; 5187 5188proto._getItemLayoutPosition = function( item ) { 5189 this._setRectSize( item.element, item.rect ); 5190 if ( this.isShifting || this.dragItemCount > 0 ) { 5191 var packMethod = this._getPackMethod(); 5192 this.packer[ packMethod ]( item.rect ); 5193 } else { 5194 this.packer.pack( item.rect ); 5195 } 5196 5197 this._setMaxXY( item.rect ); 5198 return item.rect; 5199}; 5200 5201proto.shiftLayout = function() { 5202 this.isShifting = true; 5203 this.layout(); 5204 delete this.isShifting; 5205}; 5206 5207proto._getPackMethod = function() { 5208 return this._getOption('horizontal') ? 'rowPack' : 'columnPack'; 5209}; 5210 5211 5212/** 5213 * set max X and Y value, for size of container 5214 * @param {Packery.Rect} rect 5215 * @private 5216 */ 5217proto._setMaxXY = function( rect ) { 5218 this.maxX = Math.max( rect.x + rect.width, this.maxX ); 5219 this.maxY = Math.max( rect.y + rect.height, this.maxY ); 5220}; 5221 5222/** 5223 * set the width and height of a rect, applying columnWidth and rowHeight 5224 * @param {Element} elem 5225 * @param {Packery.Rect} rect 5226 */ 5227proto._setRectSize = function( elem, rect ) { 5228 var size = getSize( elem ); 5229 var w = size.outerWidth; 5230 var h = size.outerHeight; 5231 // size for columnWidth and rowHeight, if available 5232 // only check if size is non-zero, #177 5233 if ( w || h ) { 5234 w = this._applyGridGutter( w, this.columnWidth ); 5235 h = this._applyGridGutter( h, this.rowHeight ); 5236 } 5237 // rect must fit in packer 5238 rect.width = Math.min( w, this.packer.width ); 5239 rect.height = Math.min( h, this.packer.height ); 5240}; 5241 5242/** 5243 * fits item to columnWidth/rowHeight and adds gutter 5244 * @param {Number} measurement - item width or height 5245 * @param {Number} gridSize - columnWidth or rowHeight 5246 * @returns measurement 5247 */ 5248proto._applyGridGutter = function( measurement, gridSize ) { 5249 // just add gutter if no gridSize 5250 if ( !gridSize ) { 5251 return measurement + this.gutter; 5252 } 5253 gridSize += this.gutter; 5254 // fit item to columnWidth/rowHeight 5255 var remainder = measurement % gridSize; 5256 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil'; 5257 measurement = Math[ mathMethod ]( measurement / gridSize ) * gridSize; 5258 return measurement; 5259}; 5260 5261proto._getContainerSize = function() { 5262 if ( this._getOption('horizontal') ) { 5263 return { 5264 width: this.maxX - this.gutter 5265 }; 5266 } else { 5267 return { 5268 height: this.maxY - this.gutter 5269 }; 5270 } 5271}; 5272 5273 5274// -------------------------- stamp -------------------------- // 5275 5276/** 5277 * makes space for element 5278 * @param {Element} elem 5279 */ 5280proto._manageStamp = function( elem ) { 5281 5282 var item = this.getItem( elem ); 5283 var rect; 5284 if ( item && item.isPlacing ) { 5285 rect = item.rect; 5286 } else { 5287 var offset = this._getElementOffset( elem ); 5288 rect = new Rect({ 5289 x: this._getOption('originLeft') ? offset.left : offset.right, 5290 y: this._getOption('originTop') ? offset.top : offset.bottom 5291 }); 5292 } 5293 5294 this._setRectSize( elem, rect ); 5295 // save its space in the packer 5296 this.packer.placed( rect ); 5297 this._setMaxXY( rect ); 5298}; 5299 5300// -------------------------- methods -------------------------- // 5301 5302function verticalSorter( a, b ) { 5303 return a.position.y - b.position.y || a.position.x - b.position.x; 5304} 5305 5306function horizontalSorter( a, b ) { 5307 return a.position.x - b.position.x || a.position.y - b.position.y; 5308} 5309 5310proto.sortItemsByPosition = function() { 5311 var sorter = this._getOption('horizontal') ? horizontalSorter : verticalSorter; 5312 this.items.sort( sorter ); 5313}; 5314 5315/** 5316 * Fit item element in its current position 5317 * Packery will position elements around it 5318 * useful for expanding elements 5319 * 5320 * @param {Element} elem 5321 * @param {Number} x - horizontal destination position, optional 5322 * @param {Number} y - vertical destination position, optional 5323 */ 5324proto.fit = function( elem, x, y ) { 5325 var item = this.getItem( elem ); 5326 if ( !item ) { 5327 return; 5328 } 5329 5330 // stamp item to get it out of layout 5331 this.stamp( item.element ); 5332 // set placing flag 5333 item.enablePlacing(); 5334 this.updateShiftTargets( item ); 5335 // fall back to current position for fitting 5336 x = x === undefined ? item.rect.x: x; 5337 y = y === undefined ? item.rect.y: y; 5338 // position it best at its destination 5339 this.shift( item, x, y ); 5340 this._bindFitEvents( item ); 5341 item.moveTo( item.rect.x, item.rect.y ); 5342 // layout everything else 5343 this.shiftLayout(); 5344 // return back to regularly scheduled programming 5345 this.unstamp( item.element ); 5346 this.sortItemsByPosition(); 5347 item.disablePlacing(); 5348}; 5349 5350/** 5351 * emit event when item is fit and other items are laid out 5352 * @param {Packery.Item} item 5353 * @private 5354 */ 5355proto._bindFitEvents = function( item ) { 5356 var _this = this; 5357 var ticks = 0; 5358 function onLayout() { 5359 ticks++; 5360 if ( ticks != 2 ) { 5361 return; 5362 } 5363 _this.dispatchEvent( 'fitComplete', null, [ item ] ); 5364 } 5365 // when item is laid out 5366 item.once( 'layout', onLayout ); 5367 // when all items are laid out 5368 this.once( 'layoutComplete', onLayout ); 5369}; 5370 5371// -------------------------- resize -------------------------- // 5372 5373// debounced, layout on resize 5374proto.resize = function() { 5375 // don't trigger if size did not change 5376 // or if resize was unbound. See #285, outlayer#9 5377 if ( !this.isResizeBound || !this.needsResizeLayout() ) { 5378 return; 5379 } 5380 5381 if ( this.options.shiftPercentResize ) { 5382 this.resizeShiftPercentLayout(); 5383 } else { 5384 this.layout(); 5385 } 5386}; 5387 5388/** 5389 * check if layout is needed post layout 5390 * @returns Boolean 5391 */ 5392proto.needsResizeLayout = function() { 5393 var size = getSize( this.element ); 5394 var innerSize = this._getOption('horizontal') ? 'innerHeight' : 'innerWidth'; 5395 return size[ innerSize ] != this.size[ innerSize ]; 5396}; 5397 5398proto.resizeShiftPercentLayout = function() { 5399 var items = this._getItemsForLayout( this.items ); 5400 5401 var isHorizontal = this._getOption('horizontal'); 5402 var coord = isHorizontal ? 'y' : 'x'; 5403 var measure = isHorizontal ? 'height' : 'width'; 5404 var segmentName = isHorizontal ? 'rowHeight' : 'columnWidth'; 5405 var innerSize = isHorizontal ? 'innerHeight' : 'innerWidth'; 5406 5407 // proportional re-align items 5408 var previousSegment = this[ segmentName ]; 5409 previousSegment = previousSegment && previousSegment + this.gutter; 5410 5411 if ( previousSegment ) { 5412 this._getMeasurements(); 5413 var currentSegment = this[ segmentName ] + this.gutter; 5414 items.forEach( function( item ) { 5415 var seg = Math.round( item.rect[ coord ] / previousSegment ); 5416 item.rect[ coord ] = seg * currentSegment; 5417 }); 5418 } else { 5419 var currentSize = getSize( this.element )[ innerSize ] + this.gutter; 5420 var previousSize = this.packer[ measure ]; 5421 items.forEach( function( item ) { 5422 item.rect[ coord ] = ( item.rect[ coord ] / previousSize ) * currentSize; 5423 }); 5424 } 5425 5426 this.shiftLayout(); 5427}; 5428 5429// -------------------------- drag -------------------------- // 5430 5431/** 5432 * handle an item drag start event 5433 * @param {Element} elem 5434 */ 5435proto.itemDragStart = function( elem ) { 5436 if ( !this.isEnabled ) { 5437 return; 5438 } 5439 this.stamp( elem ); 5440 // this.ignore( elem ); 5441 var item = this.getItem( elem ); 5442 if ( !item ) { 5443 return; 5444 } 5445 5446 item.enablePlacing(); 5447 item.showDropPlaceholder(); 5448 this.dragItemCount++; 5449 this.updateShiftTargets( item ); 5450}; 5451 5452proto.updateShiftTargets = function( dropItem ) { 5453 this.shiftPacker.reset(); 5454 5455 // pack stamps 5456 this._getBoundingRect(); 5457 var isOriginLeft = this._getOption('originLeft'); 5458 var isOriginTop = this._getOption('originTop'); 5459 this.stamps.forEach( function( stamp ) { 5460 // ignore dragged item 5461 var item = this.getItem( stamp ); 5462 if ( item && item.isPlacing ) { 5463 return; 5464 } 5465 var offset = this._getElementOffset( stamp ); 5466 var rect = new Rect({ 5467 x: isOriginLeft ? offset.left : offset.right, 5468 y: isOriginTop ? offset.top : offset.bottom 5469 }); 5470 this._setRectSize( stamp, rect ); 5471 // save its space in the packer 5472 this.shiftPacker.placed( rect ); 5473 }, this ); 5474 5475 // reset shiftTargets 5476 var isHorizontal = this._getOption('horizontal'); 5477 var segmentName = isHorizontal ? 'rowHeight' : 'columnWidth'; 5478 var measure = isHorizontal ? 'height' : 'width'; 5479 5480 this.shiftTargetKeys = []; 5481 this.shiftTargets = []; 5482 var boundsSize; 5483 var segment = this[ segmentName ]; 5484 segment = segment && segment + this.gutter; 5485 5486 if ( segment ) { 5487 var segmentSpan = Math.ceil( dropItem.rect[ measure ] / segment ); 5488 var segs = Math.floor( ( this.shiftPacker[ measure ] + this.gutter ) / segment ); 5489 boundsSize = ( segs - segmentSpan ) * segment; 5490 // add targets on top 5491 for ( var i=0; i < segs; i++ ) { 5492 this._addShiftTarget( i * segment, 0, boundsSize ); 5493 } 5494 } else { 5495 boundsSize = ( this.shiftPacker[ measure ] + this.gutter ) - dropItem.rect[ measure ]; 5496 this._addShiftTarget( 0, 0, boundsSize ); 5497 } 5498 5499 // pack each item to measure where shiftTargets are 5500 var items = this._getItemsForLayout( this.items ); 5501 var packMethod = this._getPackMethod(); 5502 items.forEach( function( item ) { 5503 var rect = item.rect; 5504 this._setRectSize( item.element, rect ); 5505 this.shiftPacker[ packMethod ]( rect ); 5506 5507 // add top left corner 5508 this._addShiftTarget( rect.x, rect.y, boundsSize ); 5509 // add bottom left / top right corner 5510 var cornerX = isHorizontal ? rect.x + rect.width : rect.x; 5511 var cornerY = isHorizontal ? rect.y : rect.y + rect.height; 5512 this._addShiftTarget( cornerX, cornerY, boundsSize ); 5513 5514 if ( segment ) { 5515 // add targets for each column on bottom / row on right 5516 var segSpan = Math.round( rect[ measure ] / segment ); 5517 for ( var i=1; i < segSpan; i++ ) { 5518 var segX = isHorizontal ? cornerX : rect.x + segment * i; 5519 var segY = isHorizontal ? rect.y + segment * i : cornerY; 5520 this._addShiftTarget( segX, segY, boundsSize ); 5521 } 5522 } 5523 }, this ); 5524 5525}; 5526 5527proto._addShiftTarget = function( x, y, boundsSize ) { 5528 var checkCoord = this._getOption('horizontal') ? y : x; 5529 if ( checkCoord !== 0 && checkCoord > boundsSize ) { 5530 return; 5531 } 5532 // create string for a key, easier to keep track of what targets 5533 var key = x + ',' + y; 5534 var hasKey = this.shiftTargetKeys.indexOf( key ) != -1; 5535 if ( hasKey ) { 5536 return; 5537 } 5538 this.shiftTargetKeys.push( key ); 5539 this.shiftTargets.push({ x: x, y: y }); 5540}; 5541 5542// -------------------------- drop -------------------------- // 5543 5544proto.shift = function( item, x, y ) { 5545 var shiftPosition; 5546 var minDistance = Infinity; 5547 var position = { x: x, y: y }; 5548 this.shiftTargets.forEach( function( target ) { 5549 var distance = getDistance( target, position ); 5550 if ( distance < minDistance ) { 5551 shiftPosition = target; 5552 minDistance = distance; 5553 } 5554 }); 5555 item.rect.x = shiftPosition.x; 5556 item.rect.y = shiftPosition.y; 5557}; 5558 5559function getDistance( a, b ) { 5560 var dx = b.x - a.x; 5561 var dy = b.y - a.y; 5562 return Math.sqrt( dx * dx + dy * dy ); 5563} 5564 5565// -------------------------- drag move -------------------------- // 5566 5567var DRAG_THROTTLE_TIME = 120; 5568 5569/** 5570 * handle an item drag move event 5571 * @param {Element} elem 5572 * @param {Number} x - horizontal change in position 5573 * @param {Number} y - vertical change in position 5574 */ 5575proto.itemDragMove = function( elem, x, y ) { 5576 var item = this.isEnabled && this.getItem( elem ); 5577 if ( !item ) { 5578 return; 5579 } 5580 5581 x -= this.size.paddingLeft; 5582 y -= this.size.paddingTop; 5583 5584 var _this = this; 5585 function onDrag() { 5586 _this.shift( item, x, y ); 5587 item.positionDropPlaceholder(); 5588 _this.layout(); 5589 } 5590 5591 // throttle 5592 var now = new Date(); 5593 if ( this._itemDragTime && now - this._itemDragTime < DRAG_THROTTLE_TIME ) { 5594 clearTimeout( this.dragTimeout ); 5595 this.dragTimeout = setTimeout( onDrag, DRAG_THROTTLE_TIME ); 5596 } else { 5597 onDrag(); 5598 this._itemDragTime = now; 5599 } 5600}; 5601 5602// -------------------------- drag end -------------------------- // 5603 5604/** 5605 * handle an item drag end event 5606 * @param {Element} elem 5607 */ 5608proto.itemDragEnd = function( elem ) { 5609 var item = this.isEnabled && this.getItem( elem ); 5610 if ( !item ) { 5611 return; 5612 } 5613 5614 clearTimeout( this.dragTimeout ); 5615 item.element.classList.add('is-positioning-post-drag'); 5616 5617 var completeCount = 0; 5618 var _this = this; 5619 function onDragEndLayoutComplete() { 5620 completeCount++; 5621 if ( completeCount != 2 ) { 5622 return; 5623 } 5624 // reset drag item 5625 item.element.classList.remove('is-positioning-post-drag'); 5626 item.hideDropPlaceholder(); 5627 _this.dispatchEvent( 'dragItemPositioned', null, [ item ] ); 5628 } 5629 5630 item.once( 'layout', onDragEndLayoutComplete ); 5631 this.once( 'layoutComplete', onDragEndLayoutComplete ); 5632 item.moveTo( item.rect.x, item.rect.y ); 5633 this.layout(); 5634 this.dragItemCount = Math.max( 0, this.dragItemCount - 1 ); 5635 this.sortItemsByPosition(); 5636 item.disablePlacing(); 5637 this.unstamp( item.element ); 5638}; 5639 5640/** 5641 * binds Draggabilly events 5642 * @param {Draggabilly} draggie 5643 */ 5644proto.bindDraggabillyEvents = function( draggie ) { 5645 this._bindDraggabillyEvents( draggie, 'on' ); 5646}; 5647 5648proto.unbindDraggabillyEvents = function( draggie ) { 5649 this._bindDraggabillyEvents( draggie, 'off' ); 5650}; 5651 5652proto._bindDraggabillyEvents = function( draggie, method ) { 5653 var handlers = this.handleDraggabilly; 5654 draggie[ method ]( 'dragStart', handlers.dragStart ); 5655 draggie[ method ]( 'dragMove', handlers.dragMove ); 5656 draggie[ method ]( 'dragEnd', handlers.dragEnd ); 5657}; 5658 5659/** 5660 * binds jQuery UI Draggable events 5661 * @param {jQuery} $elems 5662 */ 5663proto.bindUIDraggableEvents = function( $elems ) { 5664 this._bindUIDraggableEvents( $elems, 'on' ); 5665}; 5666 5667proto.unbindUIDraggableEvents = function( $elems ) { 5668 this._bindUIDraggableEvents( $elems, 'off' ); 5669}; 5670 5671proto._bindUIDraggableEvents = function( $elems, method ) { 5672 var handlers = this.handleUIDraggable; 5673 $elems 5674 [ method ]( 'dragstart', handlers.start ) 5675 [ method ]( 'drag', handlers.drag ) 5676 [ method ]( 'dragstop', handlers.stop ); 5677}; 5678 5679// ----- destroy ----- // 5680 5681var _destroy = proto.destroy; 5682proto.destroy = function() { 5683 _destroy.apply( this, arguments ); 5684 // disable flag; prevent drag events from triggering. #72 5685 this.isEnabled = false; 5686}; 5687 5688// ----- ----- // 5689 5690Packery.Rect = Rect; 5691Packery.Packer = Packer; 5692 5693return Packery; 5694 5695})); 5696 5697/*! 5698 * Packery layout mode v2.0.1 5699 * sub-classes Packery 5700 */ 5701 5702/*jshint browser: true, strict: true, undef: true, unused: true */ 5703 5704( function( window, factory ) {
5705 5706 // universal module definition 5707 if ( typeof define == 'function' && define.amd ) { 5708 // AMD 5709 define( [ 5710 'isotope-layout/js/layout-mode', 5711 'packery/js/packery' 5712 ], 5713 factory ); 5714 } else if ( typeof module == 'object' && module.exports ) { 5715 // CommonJS 5716 module.exports = factory( 5717 require('isotope-layout/js/layout-mode'), 5718 require('packery') 5719 ); 5720 } else { 5721 // browser global 5722 factory( 5723 window.Isotope.LayoutMode, 5724 window.Packery 5725 ); 5726 } 5727 5728}( window, function factor( LayoutMode, Packery ) { 5729 5730 5731 // create an Outlayer layout class 5732 var PackeryMode = LayoutMode.create('packery'); 5733 var proto = PackeryMode.prototype; 5734 5735 var keepModeMethods = { 5736 _getElementOffset: true, 5737 _getMeasurement: true 5738 }; 5739 5740 // inherit Packery prototype 5741 for ( var method in Packery.prototype ) { 5742 // do not inherit mode methods 5743 if ( !keepModeMethods[ method ] ) { 5744 proto[ method ] = Packery.prototype[ method ]; 5745 } 5746 } 5747 5748 // set packer in _resetLayout 5749 var _resetLayout = proto._resetLayout; 5750 proto._resetLayout = function() { 5751 this.packer = this.packer || new Packery.Packer(); 5752 this.shiftPacker = this.shiftPacker || new Packery.Packer(); 5753 _resetLayout.apply( this, arguments ); 5754 }; 5755 5756 var _getItemLayoutPosition = proto._getItemLayoutPosition; 5757 proto._getItemLayoutPosition = function( item ) { 5758 // set packery rect 5759 item.rect = item.rect || new Packery.Rect(); 5760 return _getItemLayoutPosition.call( this, item ); 5761 }; 5762 5763 // needsResizeLayout for vertical or horizontal 5764 var _needsResizeLayout = proto.needsResizeLayout; 5765 proto.needsResizeLayout = function() { 5766 if ( this._getOption('horizontal') ) { 5767 return this.needsVerticalResizeLayout(); 5768 } else { 5769 return _needsResizeLayout.call( this ); 5770 } 5771 }; 5772 5773 // point to mode options for horizontal 5774 var _getOption = proto._getOption; 5775 proto._getOption = function( option ) { 5776 if ( option == 'horizontal' ) { 5777 return this.options.isHorizontal !== undefined ? 5778 this.options.isHorizontal : this.options.horizontal; 5779 } 5780 return _getOption.apply( this.isotope, arguments ); 5781 }; 5782 5783 return PackeryMode; 5784 5785})); 5786 5787/*! 5788 * cellsByRows layout mode for Isotope 5789 * v1.1.3 5790 * http://isotope.metafizzy.co/layout-modes/cellsbyrow.html 5791 */ 5792 5793/*jshint browser: true, devel: false, strict: true, undef: true, unused: true */ 5794 5795( function( window, factory ) { 5796 // universal module definition 5797 /* jshint strict: false */ /*globals define, module, require */ 5798 if ( typeof define === 'function' && define.amd ) { 5799 // AMD 5800 define( [ 5801 'isotope/js/layout-mode' 5802 ], 5803 factory ); 5804 } else if ( typeof exports === 'object' ) { 5805 // CommonJS 5806 module.exports = factory( 5807 require('isotope-layout/js/layout-mode') 5808 ); 5809 } else { 5810 // browser global 5811 factory( 5812 window.Isotope.LayoutMode 5813 ); 5814 } 5815 5816}( window, function factory( LayoutMode ) { 5817 'use strict'; 5818 5819 var CellsByRow = LayoutMode.create( 'cellsByRow' ); 5820 var proto = CellsByRow.prototype; 5821 5822 proto._resetLayout = function() { 5823 // reset properties 5824 this.itemIndex = 0; 5825 // measurements 5826 this.getColumnWidth(); 5827 this.getRowHeight(); 5828 // set cols 5829 this.cols = Math.floor( this.isotope.size.innerWidth / this.columnWidth ); 5830 this.cols = Math.max( this.cols, 1 ); 5831 }; 5832 5833 proto._getItemLayoutPosition = function( item ) { 5834 item.getSize(); 5835 var col = this.itemIndex % this.cols; 5836 var row = Math.floor( this.itemIndex / this.cols ); 5837 // center item within cell 5838 var x = ( col + 0.5 ) * this.columnWidth - item.size.outerWidth / 2; 5839 var y = ( row + 0.5 ) * this.rowHeight - item.size.outerHeight / 2; 5840 this.itemIndex++; 5841 return { x: x, y: y }; 5842 }; 5843 5844 proto._getContainerSize = function() { 5845 return { 5846 height: Math.ceil( this.itemIndex / this.cols ) * this.rowHeight 5847 }; 5848 }; 5849 5850 return CellsByRow; 5851 5852})); 5853/*global jQuery: true */ 5854 5855/*! 5856 -------------------------------- 5857 Infinite Scroll 5858 -------------------------------- 5859 + https://github.com/paulirish/infinite-scroll 5860 + version 2.1.0 5861 + Copyright 2011/12 Paul Irish & Luke Shumard 5862 + Licensed under the MIT license 5863 5864 + Documentation: http://infinite-scroll.com/ 5865*/ 5866 5867// Uses AMD or browser globals to create a jQuery plugin. 5868(function (factory) { 5869 if (typeof define === 'function' && define.amd) { 5870 // AMD. Register as an anonymous module. 5871 define(['jquery'], factory); 5872 } else { 5873 // Browser globals 5874 factory(jQuery); 5875 } 5876}(function ($, undefined) { 5877 'use strict'; 5878
5879 $.infinitescroll = function infscr(options, callback, element) { 5880 this.element = $(element); 5881 5882 // Flag the object in the event of a failed creation 5883 if (!this._create(options, callback)) { 5884 this.failed = true; 5885 } 5886 }; 5887 5888 $.infinitescroll.defaults = { 5889 loading: { 5890 finished: undefined, 5891 finishedMsg: "<em>Congratulations, you've reached the end of the internet.</em>", 5892 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
5892MzExnbRvQ2Sy7vN0zvVtNfU2tLY3rPgLdnDvca4VQS/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
5892iqpQpZ4apwSwRtjqrB3muoF9BboaXKmshlqWqsWiGt2wphJkQbAU5hoCACH5BAUKABsALAcABADOAAsAAAX/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', 5893 msg: null, 5894 msgText: '<em>Loading the next set of posts...</em>', 5895 selector: null, 5896 speed: 'fast', 5897 start: undefined 5898 }, 5899 state: { 5900 isDuringAjax: false, 5901 isInvalidPage: false,
5902 isDestroyed: false, 5903 isDone: false, // For when it goes all the way through the archive. 5904 isPaused: false, 5905 isBeyondMaxPage: false, 5906 currPage: 1 5907 }, 5908 debug: false, 5909 behavior: undefined, 5910 binder: $(window), // used to cache the selector 5911 nextSelector: 'div.navigation a:first', 5912 navSelector: 'div.navigation', 5913 contentSelector: null, // rename to pageFragment 5914 extraScrollPx: 150, 5915 itemSelector: 'div.post', 5916 animate: false, 5917 pathParse: undefined, 5918 dataType: 'html', 5919 appendCallback: true, 5920 bufferPx: 40, 5921 errorCallback: function () { }, 5922 infid: 0, //Instance ID 5923 pixelsFromNavToBottom: undefined, 5924 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 5925 prefill: false, // When the document is smaller than the window, load data until the document is larger or links are exhausted 5926 maxPage: undefined // to manually control maximum page (when maxPage is undefined, maximum page limitation is not work) 5927 }; 5928 5929 $.infinitescroll.prototype = { 5930 5931 /* 5932 ---------------------------- 5933 Private methods 5934 ---------------------------- 5935 */ 5936 5937 // Bind or unbind from scroll 5938 _binding: function infscr_binding(binding) { 5939 5940 var instance = this, 5941 opts = instance.options; 5942 5943 opts.v = '2.0b2.120520'; 5944 5945 // if behavior is defined and this function is extended, call that instead of default 5946 if (!!opts.behavior && this['_binding_'+opts.behavior] !== undefined) { 5947 this['_binding_'+opts.behavior].call(this); 5948 return; 5949 } 5950 5951 if (binding !== 'bind' && binding !== 'unbind') { 5952 this._debug('Binding value ' + binding + ' not valid'); 5953 return false; 5954 } 5955 5956 if (binding === 'unbind') { 5957 (this.options.binder).unbind('smartscroll.infscr.' + instance.options.infid); 5958 } else { 5959 (this.options.binder)[binding]('smartscroll.infscr.' + instance.options.infid, function () { 5960 instance.scroll(); 5961 }); 5962 } 5963 5964 this._debug('Binding', binding); 5965 }, 5966 5967 // Fundamental aspects of the plugin are initialized 5968 _create: function infscr_create(options, callback) { 5969 5970 // Add custom options to defaults 5971 var opts = $.extend(true, {}, $.infinitescroll.defaults, options); 5972 this.options = opts; 5973 var $window = $(window); 5974 var instance = this; 5975 5976 // Validate selectors 5977 if (!instance._validate(options)) { 5978 return false; 5979 } 5980 5981 // Validate page fragment path 5982 var path = $(opts.nextSelector).attr('href'); 5983 if (!path) { 5984 this._debug('Navigation selector not found'); 5985 return false; 5986 } 5987 5988 // Set the path to be a relative URL from root. 5989 opts.path = opts.path || this._determinepath(path); 5990 5991 // contentSelector is 'page fragment' option for .load() / .ajax() calls 5992 opts.contentSelector = opts.contentSelector || this.element; 5993 5994 // loading.selector - if we want to place the load message in a specific selector, defaulted to the contentSelector 5995 opts.loading.selector = opts.loading.selector || opts.contentSelector; 5996 5997 // Define loading.msg 5998 opts.loading.msg = opts.loading.msg || $('<div id="infscr-loading"><img alt="Loading..." src="' + opts.loading.img + '" /><div>' + opts.loading.msgText + '</div></div>'); 5999 6000 // Preload loading.img 6001 (new Image()).src = opts.loading.img; 6002 6003 // distance from nav links to bottom 6004 // computed as: height of the document + top offset of container - top offset of nav link 6005 if(opts.pixelsFromNavToBottom === undefined) { 6006 opts.pixelsFromNavToBottom = $(document).height() - $(opts.navSelector).offset().top; 6007 this._debug('pixelsFromNavToBottom: ' + opts.pixelsFromNavToBottom); 6008 } 6009 6010 var self = this; 6011 6012 // determine loading.start actions 6013 opts.loading.start = opts.loading.start || function() { 6014 $(opts.navSelector).hide(); 6015 opts.loading.msg 6016 .appendTo(opts.loading.selector) 6017 .show(opts.loading.speed, $.proxy(function() { 6018 this.beginAjax(opts); 6019 }, self)); 6020 }; 6021 6022 // determine loading.finished actions 6023 opts.loading.finished = opts.loading.finished || function() { 6024 if (!opts.state.isBeyondMaxPage) 6025 opts.loading.msg.fadeOut(opts.loading.speed); 6026 }; 6027 6028 // callback loading 6029 opts.callback = function(instance, data, url) { 6030 if (!!opts.behavior && instance['_callback_'+opts.behavior] !== undefined) { 6031 instance['_callback_'+opts.behavior].call($(opts.contentSelector)[0], data, url); 6032 } 6033 6034 if (callback) { 6035 callback.call($(opts.contentSelector)[0], data, opts, url); 6036 } 6037 6038 if (opts.prefill) { 6039 $window.bind('resize.infinite-scroll', instance._prefill); 6040 } 6041 }; 6042 6043 if (options.debug) { 6044 // Tell IE9 to use its built-in console 6045 if (Function.prototype.bind && (typeof console === 'object' || typeof console === 'function') && typeof console.log === 'object') { 6046 ['log','info','warn','error','assert','dir','clear','profile','profileEnd'] 6047 .forEach(function (method) { 6048 console[method] = this.call(console[method], console); 6049 }, Function.prototype.bind); 6050 } 6051 } 6052 6053 this._setup(); 6054 6055 // Setups the prefill method for use 6056 if (opts.prefill) { 6057 this._prefill(); 6058 } 6059 6060 // Return true to indicate successful creation 6061 return true; 6062 }, 6063 6064 _prefill: function infscr_prefill() { 6065 var instance = this; 6066 var $window = $(window); 6067 6068 function needsPrefill() { 6069 return ( $(instance.options.contentSelector).height() <= $window.height() ); 6070 } 6071 6072 this._prefill = function() { 6073 if (needsPrefill()) { 6074 instance.scroll(); 6075 } 6076 6077 $window.bind('resize.infinite-scroll', function() { 6078 if (needsPrefill()) { 6079 $window.unbind('resize.infinite-scroll'); 6080 instance.scroll(); 6081 } 6082 }); 6083 }; 6084 6085 // Call self after setting up the new function 6086 this._prefill(); 6087 }, 6088 6089 // Console log wrapper 6090 _debug: function infscr_debug() { 6091 if (true !== this.options.debug) { 6092 return; 6093 } 6094 6095 if (typeof console !== 'undefined' && typeof console.log === 'function') { 6096 // Modern browsers 6097 // Single argument, which is a string 6098 if ((Array.prototype.slice.call(arguments)).length === 1 && typeof Array.prototype.slice.call(arguments)[0] === 'string') { 6099 console.log( (Array.prototype.slice.call(arguments)).toString() ); 6100 } else { 6101 console.log( Array.prototype.slice.call(arguments) ); 6102 } 6103 } else if (!Function.prototype.bind && typeof console !== 'undefined' && typeof console.log === 'object') { 6104 // IE8 6105 Function.prototype.call.call(console.log, console, Array.prototype.slice.call(arguments)); 6106 } 6107 }, 6108 6109 // find the number to increment in the path.
6110 _determinepath: function infscr_determinepath(path) { 6111 6112 var opts = this.options; 6113 6114 // if behavior is defined and this function is extended, call that instead of default 6115 if (!!opts.behavior && this['_determinepath_'+opts.behavior] !== undefined) { 6116 return this['_determinepath_'+opts.behavior].call(this,path); 6117 } 6118 6119 if (!!opts.pathParse) { 6120 6121 this._debug('pathParse manual'); 6122 return opts.pathParse(path, this.options.state.currPage+1); 6123 6124 } else if (path.match(/^(.*?)\b2\b(.*?$)/)) { 6125 path = path.match(/^(.*?)\b2\b(.*?$)/).slice(1); 6126 6127 // if there is any 2 in the url at all. 6128 } else if (path.match(/^(.*?)2(.*?$)/)) { 6129 6130 // page= is used in django: 6131 // http://www.infinite-scroll.com/changelog/comment-page-1/#comment-127 6132 if (path.match(/^(.*?page=)2(\/.*|$)/)) { 6133 path = path.match(/^(.*?page=)2(\/.*|$)/).slice(1); 6134 return path; 6135 } 6136 6137 path = path.match(/^(.*?)2(.*?$)/).slice(1); 6138 6139 } else { 6140 6141 // page= is used in drupal too but second page is page=1 not page=2: 6142 // thx Jerod Fritz, vladikoff 6143 if (path.match(/^(.*?page=)1(\/.*|$)/)) { 6144 path = path.match(/^(.*?page=)1(\/.*|$)/).slice(1); 6145 return path; 6146 } else { 6147 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."); 6148 // Get rid of isInvalidPage to allow permalink to state 6149 opts.state.isInvalidPage = true; //prevent it from running on this page. 6150 } 6151 } 6152 this._debug('determinePath', path); 6153 return path; 6154 6155 }, 6156 6157 // Custom error 6158 _error: function infscr_error(xhr) { 6159 6160 var opts = this.options; 6161 6162 // if behavior is defined and this function is extended, call that instead of default 6163 if (!!opts.behavior && this['_error_'+opts.behavior] !== undefined) { 6164 this['_error_'+opts.behavior].call(this,xhr); 6165 return; 6166 } 6167 6168 if (xhr !== 'destroy' && xhr !== 'end') { 6169 xhr = 'unknown'; 6170 } 6171 6172 this._debug('Error', xhr); 6173 6174 if (xhr === 'end' || opts.state.isBeyondMaxPage) { 6175 this._showdonemsg(); 6176 } 6177 6178 opts.state.isDone = true; 6179 opts.state.currPage = 1; // if you need to go back to this instance 6180 opts.state.isPaused = false; 6181 opts.state.isBeyondMaxPage = false; 6182 this._binding('unbind'); 6183 6184 }, 6185 6186 // Load Callback 6187 _loadcallback: function infscr_loadcallback(box, data, url) { 6188 var opts = this.options, 6189 callback = this.options.callback, // GLOBAL OBJECT FOR CALLBACK 6190 result = (opts.state.isDone) ? 'done' : (!opts.appendCallback) ? 'no-append' : 'append', 6191 frag; 6192 6193 // if behavior is defined and this function is extended, call that instead of default 6194 if (!!opts.behavior && this['_loadcallback_'+opts.behavior] !== undefined) { 6195 this['_loadcallback_'+opts.behavior].call(this,box,data); 6196 return; 6197 } 6198 6199 switch (result) { 6200 case 'done': 6201 this._showdonemsg(); 6202 return false; 6203 6204 case 'no-append': 6205 if (opts.dataType === 'html') { 6206 data = '<div>' + data + '</div>'; 6207 data = $(data).find(opts.itemSelector); 6208 } 6209 6210 // if it didn't return anything 6211 if (data.length === 0) { 6212 return this._error('end'); 6213 } 6214 6215 break; 6216 6217 case 'append': 6218 var children = box.children(); 6219 // if it didn't return anything 6220 if (children.length === 0) { 6221 return this._error('end'); 6222 } 6223 6224 // use a documentFragment because it works when content is going into a table or UL 6225 frag = document.createDocumentFragment(); 6226 while (box[0].firstChild) { 6227 frag.appendChild(box[0].firstChild); 6228 } 6229 6230 this._debug('contentSelector', $(opts.contentSelector)[0]); 6231 $(opts.contentSelector)[0].appendChild(frag); 6232 // previously, we would pass in the new DOM element as context for the callback 6233 // however we're now using a documentfragment, which doesn't have parents or children, 6234 // so the context is the contentContainer guy, and we pass in an array 6235 // of the elements collected as the first argument. 6236 6237 data = children.get(); 6238 break; 6239 } 6240 6241 // loadingEnd function 6242 opts.loading.finished.call($(opts.contentSelector)[0],opts); 6243 6244 // smooth scroll to ease in the new content 6245 if (opts.animate) { 6246 var scrollTo = $(window).scrollTop() + $(opts.loading.msg).height() + opts.extraScrollPx + 'px'; 6247 $('html,body').animate({ scrollTop: scrollTo }, 800, function () { opts.state.isDuringAjax = false; }); 6248 } 6249 6250 if (!opts.animate) { 6251 // once the call is done, we can allow it again. 6252 opts.state.isDuringAjax = false;
6253 } 6254 6255 callback(this, data, url); 6256 6257 if (opts.prefill) { 6258 this._prefill(); 6259 } 6260 }, 6261 6262 _nearbottom: function infscr_nearbottom() { 6263 6264 var opts = this.options, 6265 pixelsFromWindowBottomToBottom = 0 + $(document).height() - (opts.binder.scrollTop()) - $(window).height(); 6266 6267 // if behavior is defined and this function is extended, call that instead of default 6268 if (!!opts.behavior && this['_nearbottom_'+opts.behavior] !== undefined) { 6269 return this['_nearbottom_'+opts.behavior].call(this); 6270 } 6271 6272 this._debug('math:', pixelsFromWindowBottomToBottom, opts.pixelsFromNavToBottom); 6273 6274 // if distance remaining in the scroll (including buffer) is less than the orignal nav to bottom.... 6275 return (pixelsFromWindowBottomToBottom - opts.bufferPx < opts.pixelsFromNavToBottom); 6276 6277 }, 6278 6279 // Pause / temporarily disable plugin from firing 6280 _pausing: function infscr_pausing(pause) { 6281 6282 var opts = this.options; 6283 6284 // if behavior is defined and this function is extended, call that instead of default 6285 if (!!opts.behavior && this['_pausing_'+opts.behavior] !== undefined) { 6286 this['_pausing_'+opts.behavior].call(this,pause); 6287 return; 6288 } 6289 6290 // If pause is not 'pause' or 'resume', toggle it's value 6291 if (pause !== 'pause' && pause !== 'resume' && pause !== null) { 6292 this._debug('Invalid argument. Toggling pause value instead'); 6293 } 6294 6295 pause = (pause && (pause === 'pause' || pause === 'resume')) ? pause : 'toggle'; 6296 6297 switch (pause) { 6298 case 'pause': 6299 opts.state.isPaused = true; 6300 break; 6301 6302 case 'resume': 6303 opts.state.isPaused = false; 6304 break; 6305 6306 case 'toggle': 6307 opts.state.isPaused = !opts.state.isPaused; 6308 break; 6309 } 6310 6311 this._debug('Paused', opts.state.isPaused); 6312 return false; 6313 6314 }, 6315 6316 // Behavior is determined 6317 // If the behavior option is undefined, it will set to default and bind to scroll 6318 _setup: function infscr_setup() { 6319 6320 var opts = this.options; 6321 6322 // if behavior is defined and this function is extended, call that instead of default 6323 if (!!opts.behavior && this['_setup_'+opts.behavior] !== undefined) { 6324 this['_setup_'+opts.behavior].call(this); 6325 return; 6326 } 6327 6328 this._binding('bind'); 6329 6330 return false; 6331 6332 }, 6333 6334 // Show done message 6335 _showdonemsg: function infscr_showdonemsg() { 6336 6337 var opts = this.options; 6338 6339 // if behavior is defined and this function is extended, call that instead of default 6340 if (!!opts.behavior && this['_showdonemsg_'+opts.behavior] !== undefined) { 6341 this['_showdonemsg_'+opts.behavior].call(this); 6342 return; 6343 } 6344 6345 opts.loading.msg 6346 .find('img') 6347 .hide() 6348 .parent() 6349 .find('div').html(opts.loading.finishedMsg).animate({ opacity: 1 }, 2000, function () { 6350 $(this).parent().fadeOut(opts.loading.speed); 6351 }); 6352 6353 // user provided callback when done 6354 opts.errorCallback.call($(opts.contentSelector)[0],'done'); 6355 }, 6356 6357 // grab each selector option and see if any fail 6358 _validate: function infscr_validate(opts) { 6359 for (var key in opts) { 6360 if (key.indexOf && key.indexOf('Selector') > -1 && $(opts[key]).length === 0) { 6361 this._debug('Your ' + key + ' found no elements.'); 6362 return false; 6363 } 6364 } 6365 6366 return true; 6367 }, 6368 6369 /* 6370 ---------------------------- 6371 Public methods 6372 ---------------------------- 6373 */ 6374 6375 // Bind to scroll 6376 bind: function infscr_bind() { 6377 this._binding('bind'); 6378 }, 6379 6380 // Destroy current instance of plugin 6381 destroy: function infscr_destroy() { 6382 this.options.state.isDestroyed = true; 6383 this.options.loading.finished(); 6384 return this._error('destroy'); 6385 }, 6386 6387 // Set pause value to false 6388 pause: function infscr_pause() { 6389 this._pausing('pause'); 6390 }, 6391 6392 // Set pause value to false 6393 resume: function infscr_resume() { 6394 this._pausing('resume'); 6395 }, 6396 6397 beginAjax: function infscr_ajax(opts) { 6398 var instance = this, 6399 path = opts.path, 6400 box, desturl, method, condition; 6401 6402 // increment the URL bit. e.g. /page/3/ 6403 opts.state.currPage++; 6404 6405 // Manually control maximum page 6406 if ( opts.maxPage !== undefined && opts.state.currPage > opts.maxPage ){ 6407 opts.state.isBeyondMaxPage = true; 6408 this.destroy(); 6409 return; 6410 } 6411 6412 // if we're dealing with a table we can't use DIVs 6413 box = $(opts.contentSelector).is('table, tbody') ? $('<tbody/>') : $('<div/>'); 6414 6415 desturl = (typeof path === 'function') ? path(opts.state.currPage) : path.join(opts.state.currPage); 6416 instance._debug('heading into ajax', desturl); 6417 6418 method = (opts.dataType === 'html' || opts.dataType === 'json' ) ? opts.dataType : 'html+callback'; 6419 if (opts.appendCallback && opts.dataType === 'html') { 6420 method += '+callback'; 6421 } 6422 6423 switch (method) { 6424 case 'html+callback': 6425 instance._debug('Using HTML via .load() method'); 6426 box.load(desturl + ' ' + opts.itemSelector, undefined, function infscr_ajax_callback(responseText) { 6427 instance._loadcallback(box, responseText, desturl); 6428 }); 6429 6430 break; 6431 6432 case 'html': 6433 instance._debug('Using ' + (method.toUpperCase()) + ' via $.ajax() method'); 6434 $.ajax({ 6435 // params 6436 url: desturl, 6437 dataType: opts.dataType, 6438 complete: function infscr_ajax_callback(jqXHR, textStatus) { 6439 condition = (typeof (jqXHR.isResolved) !== 'undefined') ? (jqXHR.isResolved()) : (textStatus === 'success' || textStatus === 'notmodified'); 6440 if (condition) { 6441 instance._loadcallback(box, jqXHR.responseText, desturl); 6442 } else { 6443 instance._error('end'); 6444 } 6445 } 6446 }); 6447 6448 break; 6449 case 'json': 6450 instance._debug('Using ' + (method.toUpperCase()) + ' via $.ajax() method'); 6451 $.ajax({ 6452 dataType: 'json', 6453 type: 'GET', 6454 url: desturl, 6455 success: function (data, textStatus, jqXHR) { 6456 condition = (typeof (jqXHR.isResolved) !== 'undefined') ? (jqXHR.isResolved()) : (textStatus === 'success' || textStatus === 'notmodified'); 6457 if (opts.appendCallback) { 6458 // if appendCallback is true, you must defined template in options. 6459 // note that data passed into _loadcallback is already an html (after processed in opts.template(data)). 6460 if (opts.template !== undefined) { 6461 var theData = opts.template(data); 6462 box.append(theData); 6463 if (condition) { 6464 instance._loadcallback(box, theData); 6465 } else { 6466 instance._error('end'); 6467 } 6468 } else { 6469 instance._debug('template must be defined.'); 6470 instance._error('end'); 6471 } 6472 } else { 6473 // if appendCallback is false, we will pass in the JSON object. you should handle it yourself in your callback. 6474 if (condition) { 6475 instance._loadcallback(box, data, desturl); 6476 } else { 6477 instance._error('end'); 6478 } 6479 } 6480 }, 6481 error: function() { 6482 instance._debug('JSON ajax request failed.'); 6483 instance._error('end'); 6484 } 6485 }); 6486 6487 break; 6488 } 6489 }, 6490 6491 // Retrieve next set of content items 6492 retrieve: function infscr_retrieve(pageNum) { 6493 pageNum = pageNum || null; 6494 6495 var instance = this, 6496 opts = instance.options; 6497 6498 // if behavior is defined and this function is extended, call that instead of default 6499 if (!!opts.behavior && this['retrieve_'+opts.behavior] !== undefined) { 6500 this['retrieve_'+opts.behavior].call(this,pageNum); 6501 return; 6502 } 6503 6504 // for manual triggers, if destroyed, get out of here 6505 if (opts.state.isDestroyed) { 6506 this._debug('Instance is destroyed'); 6507 return false;
6508 } 6509 6510 // we dont want to fire the ajax multiple times 6511 opts.state.isDuringAjax = true; 6512 6513 opts.loading.start.call($(opts.contentSelector)[0],opts); 6514 }, 6515 6516 // Check to see next page is needed 6517 scroll: function infscr_scroll() { 6518 6519 var opts = this.options, 6520 state = opts.state; 6521 6522 // if behavior is defined and this function is extended, call that instead of default 6523 if (!!opts.behavior && this['scroll_'+opts.behavior] !== undefined) { 6524 this['scroll_'+opts.behavior].call(this); 6525 return; 6526 } 6527 6528 if (state.isDuringAjax || state.isInvalidPage || state.isDone || state.isDestroyed || state.isPaused) { 6529 return; 6530 } 6531 6532 if (!this._nearbottom()) { 6533 return; 6534 } 6535 6536 this.retrieve(); 6537 6538 }, 6539 6540 // Toggle pause value 6541 toggle: function infscr_toggle() { 6542 this._pausing(); 6543 }, 6544 6545 // Unbind from scroll 6546 unbind: function infscr_unbind() { 6547 this._binding('unbind'); 6548 }, 6549 6550 // update options 6551 update: function infscr_options(key) { 6552 if ($.isPlainObject(key)) { 6553 this.options = $.extend(true,this.options,key); 6554 } 6555 } 6556 }; 6557 6558 6559 /* 6560 ---------------------------- 6561 Infinite Scroll function 6562 ---------------------------- 6563 6564 Borrowed logic from the following... 6565 6566 jQuery UI 6567 - https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.widget.js 6568 6569 jCarousel 6570 - https://github.com/jsor/jcarousel/blob/master/lib/jquery.jcarousel.js 6571 6572 Masonry 6573 - https://github.com/desandro/masonry/blob/master/jquery.masonry.js 6574 6575*/ 6576 6577 $.fn.infinitescroll = function infscr_init(options, callback) { 6578 6579 6580 var thisCall = typeof options; 6581 6582 switch (thisCall) { 6583 6584 // method 6585 case 'string': 6586 var args = Array.prototype.slice.call(arguments, 1); 6587 6588 this.each(function () { 6589 var instance = $.data(this, 'infinitescroll'); 6590 6591 if (!instance) { 6592 // not setup yet 6593 // return $.error('Method ' + options + ' cannot be called until Infinite Scroll is setup'); 6594 return false; 6595 } 6596 6597 if (!$.isFunction(instance[options]) || options.charAt(0) === '_') { 6598 // return $.error('No such method ' + options + ' for Infinite Scroll'); 6599 return false; 6600 } 6601 6602 // no errors! 6603 instance[options].apply(instance, args); 6604 }); 6605 6606 break; 6607 6608 // creation 6609 case 'object': 6610 6611 this.each(function () { 6612 6613 var instance = $.data(this, 'infinitescroll'); 6614 6615 if (instance) { 6616 6617 // update options of current instance 6618 instance.update(options); 6619 6620 } else { 6621 6622 // initialize new instance 6623 instance = new $.infinitescroll(options, callback, this); 6624 6625 // don't attach if instantiation failed 6626 if (!instance.failed) { 6627 $.data(this, 'infinitescroll', instance); 6628 } 6629 6630 } 6631 6632 }); 6633 6634 break; 6635 6636 } 6637 6638 return this; 6639 }; 6640 6641 6642 6643 /* 6644 * smartscroll: debounced scroll event for jQuery * 6645 * https://github.com/lukeshumard/smartscroll 6646 * Based on smartresize by @louis_remi: https://github.com/lrbabe/jquery.smartresize.js * 6647 * Copyright 2011 Louis-Remi & Luke Shumard * Licensed under the MIT license. * 6648 */ 6649 6650 var event = $.event, 6651 scrollTimeout; 6652 6653 event.special.smartscroll = { 6654 setup: function () { 6655 $(this).bind('scroll', event.special.smartscroll.handler); 6656 }, 6657 teardown: function () { 6658 $(this).unbind('scroll', event.special.smartscroll.handler); 6659 }, 6660 handler: function (event, execAsap) { 6661 // Save the context 6662 var context = this, 6663 args = arguments; 6664 6665 // set correct event type 6666 event.type = 'smartscroll'; 6667 6668 if (scrollTimeout) { clearTimeout(scrollTimeout); } 6669 scrollTimeout = setTimeout(function () { 6670 $(context).trigger('smartscroll', args); 6671 }, execAsap === 'execAsap' ? 0 : 100); 6672 } 6673 }; 6674 6675 $.fn.smartscroll = function (fn) {
6676 return fn ? this.bind('smartscroll', fn) : this.trigger('smartscroll', ['execAsap']); 6677 }; 6678 6679})); 6680 6681/*! 6682Waypoints - 4.0.1 6683Copyright © 2011-2016 Caleb Troughton 6684Licensed under the MIT license. 6685https://github.com/imakewebthings/waypoints/blob/master/licenses.txt 6686*/ 6687(function() { 6688 'use strict' 6689 6690 var keyCounter = 0 6691 var allWaypoints = {} 6692 6693 /* http://imakewebthings.com/waypoints/api/waypoint */ 6694 function Waypoint(options) { 6695 if (!options) { 6696 throw new Error('No options passed to Waypoint constructor') 6697 } 6698 if (!options.element) { 6699 throw new Error('No element option passed to Waypoint constructor') 6700 } 6701 if (!options.handler) { 6702 throw new Error('No handler option passed to Waypoint constructor') 6703 } 6704 6705 this.key = 'waypoint-' + keyCounter 6706 this.options = Waypoint.Adapter.extend({}, Waypoint.defaults, options) 6707 this.element = this.options.element 6708 this.adapter = new Waypoint.Adapter(this.element) 6709 this.callback = options.handler 6710 this.axis = this.options.horizontal ? 'horizontal' : 'vertical' 6711 this.enabled = this.options.enabled 6712 this.triggerPoint = null 6713 this.group = Waypoint.Group.findOrCreate({ 6714 name: this.options.group, 6715 axis: this.axis 6716 }) 6717 this.context = Waypoint.Context.findOrCreateByElement(this.options.context) 6718 6719 if (Waypoint.offsetAliases[this.options.offset]) { 6720 this.options.offset = Waypoint.offsetAliases[this.options.offset] 6721 } 6722 this.group.add(this) 6723 this.context.add(this) 6724 allWaypoints[this.key] = this 6725 keyCounter += 1 6726 } 6727 6728 /* Private */ 6729 Waypoint.prototype.queueTrigger = function(direction) { 6730 this.group.queueTrigger(this, direction) 6731 } 6732 6733 /* Private */ 6734 Waypoint.prototype.trigger = function(args) { 6735 if (!this.enabled) { 6736 return 6737 } 6738 if (this.callback) { 6739 this.callback.apply(this, args) 6740 } 6741 } 6742 6743 /* Public */ 6744 /* http://imakewebthings.com/waypoints/api/destroy */ 6745 Waypoint.prototype.destroy = function() { 6746 this.context.remove(this) 6747 this.group.remove(this) 6748 delete allWaypoints[this.key] 6749 } 6750 6751 /* Public */ 6752 /* http://imakewebthings.com/waypoints/api/disable */ 6753 Waypoint.prototype.disable = function() { 6754 this.enabled = false 6755 return this 6756 } 6757 6758 /* Public */ 6759 /* http://imakewebthings.com/waypoints/api/enable */ 6760 Waypoint.prototype.enable = function() { 6761 this.context.refresh() 6762 this.enabled = true 6763 return this 6764 } 6765 6766 /* Public */ 6767 /* http://imakewebthings.com/waypoints/api/next */ 6768 Waypoint.prototype.next = function() { 6769 return this.group.next(this) 6770 } 6771 6772 /* Public */ 6773 /* http://imakewebthings.com/waypoints/api/previous */ 6774 Waypoint.prototype.previous = function() { 6775 return this.group.previous(this) 6776 } 6777 6778 /* Private */ 6779 Waypoint.invokeAll = function(method) { 6780 var allWaypointsArray = []
6781 for (var waypointKey in allWaypoints) { 6782 allWaypointsArray.push(allWaypoints[waypointKey]) 6783 } 6784 for (var i = 0, end = allWaypointsArray.length; i < end; i++) { 6785 allWaypointsArray[i][method]() 6786 } 6787 } 6788 6789 /* Public */ 6790 /* http://imakewebthings.com/waypoints/api/destroy-all */ 6791 Waypoint.destroyAll = function() { 6792 Waypoint.invokeAll('destroy') 6793 } 6794 6795 /* Public */ 6796 /* http://imakewebthings.com/waypoints/api/disable-all */ 6797 Waypoint.disableAll = function() { 6798 Waypoint.invokeAll('disable') 6799 } 6800 6801 /* Public */ 6802 /* http://imakewebthings.com/waypoints/api/enable-all */ 6803 Waypoint.enableAll = function() { 6804 Waypoint.Context.refreshAll() 6805 for (var waypointKey in allWaypoints) { 6806 allWaypoints[waypointKey].enabled = true 6807 } 6808 return this 6809 } 6810 6811 /* Public */ 6812 /* http://imakewebthings.com/waypoints/api/refresh-all */ 6813 Waypoint.refreshAll = function() { 6814 Waypoint.Context.refreshAll() 6815 } 6816 6817 /* Public */ 6818 /* http://imakewebthings.com/waypoints/api/viewport-height */ 6819 Waypoint.viewportHeight = function() { 6820 return window.innerHeight || document.documentElement.clientHeight 6821 } 6822 6823 /* Public */ 6824 /* http://imakewebthings.com/waypoints/api/viewport-width */ 6825 Waypoint.viewportWidth = function() { 6826 return document.documentElement.clientWidth 6827 } 6828 6829 Waypoint.adapters = [] 6830 6831 Waypoint.defaults = { 6832 context: window, 6833 continuous: true, 6834 enabled: true, 6835 group: 'default', 6836 horizontal: false, 6837 offset: 0 6838 } 6839 6840 Waypoint.offsetAliases = { 6841 'bottom-in-view': function() { 6842 return this.context.innerHeight() - this.adapter.outerHeight() 6843 }, 6844 'right-in-view': function() { 6845 return this.context.innerWidth() - this.adapter.outerWidth() 6846 } 6847 } 6848 6849 window.Waypoint = Waypoint 6850}()) 6851;(function() { 6852 'use strict' 6853 6854 function requestAnimationFrameShim(callback) { 6855 window.setTimeout(callback, 1000 / 60) 6856 } 6857 6858 var keyCounter = 0 6859 var contexts = {} 6860 var Waypoint = window.Waypoint 6861 var oldWindowLoad = window.onload 6862 6863 /* http://imakewebthings.com/waypoints/api/context */ 6864 function Context(element) { 6865 this.element = element 6866 this.Adapter = Waypoint.Adapter 6867 this.adapter = new this.Adapter(element) 6868 this.key = 'waypoint-context-' + keyCounter 6869 this.didScroll = false 6870 this.didResize = false 6871 this.oldScroll = { 6872 x: this.adapter.scrollLeft(), 6873 y: this.adapter.scrollTop() 6874 } 6875 this.waypoints = { 6876 vertical: {}, 6877 horizontal: {} 6878 } 6879 6880 element.waypointContextKey = this.key 6881 contexts[element.waypointContextKey] = this 6882 keyCounter += 1 6883 if (!Waypoint.windowContext) { 6884 Waypoint.windowContext = true 6885 Waypoint.windowContext = new Context(window) 6886 } 6887 6888 this.createThrottledScrollHandler() 6889 this.createThrottledResizeHandler() 6890 } 6891 6892 /* Private */ 6893 Context.prototype.add = function(waypoint) { 6894 var axis = waypoint.options.horizontal ? 'horizontal' : 'vertical' 6895 this.waypoints[axis][waypoint.key] = waypoint 6896 this.refresh() 6897 } 6898 6899 /* Private */ 6900 Context.prototype.checkEmpty = function() { 6901 var horizontalEmpty = this.Adapter.isEmptyObject(this.waypoints.horizontal) 6902 var verticalEmpty = this.Adapter.isEmptyObject(this.waypoints.vertical) 6903 var isWindow = this.element == this.element.window 6904 if (horizontalEmpty && verticalEmpty && !isWindow) { 6905 this.adapter.off('.waypoints') 6906 delete contexts[this.key] 6907 } 6908 } 6909 6910 /* Private */ 6911 Context.prototype.createThrottledResizeHandler = function() { 6912 var self = this 6913 6914 function resizeHandler() { 6915 self.handleResize() 6916 self.didResize = false 6917 } 6918 6919 this.adapter.on('resize.waypoints', function() { 6920 if (!self.didResize) { 6921 self.didResize = true 6922 Waypoint.requestAnimationFrame(resizeHandler) 6923 } 6924 }) 6925 } 6926 6927 /* Private */ 6928 Context.prototype.createThrottledScrollHandler = function() { 6929 var self = this 6930 function scrollHandler() { 6931 self.handleScroll() 6932 self.didScroll = false 6933 } 6934 6935 this.adapter.on('scroll.waypoints', function() { 6936 if (!self.didScroll || Waypoint.isTouch) { 6937 self.didScroll = true 6938 Waypoint.requestAnimationFrame(scrollHandler) 6939 } 6940 }) 6941 } 6942 6943 /* Private */ 6944 Context.prototype.handleResize = function() { 6945 Waypoint.Context.refreshAll() 6946 } 6947 6948 /* Private */ 6949 Context.prototype.handleScroll = function() { 6950 var triggeredGroups = {} 6951 var axes = { 6952 horizontal: { 6953 newScroll: this.adapter.scrollLeft(), 6954 oldScroll: this.oldScroll.x, 6955 forward: 'right', 6956 backward: 'left' 6957 }, 6958 vertical: { 6959 newScroll: this.adapter.scrollTop(), 6960 oldScroll: this.oldScroll.y, 6961 forward: 'down', 6962 backward: 'up' 6963 } 6964 } 6965 6966 for (var axisKey in axes) { 6967 var axis = axes[axisKey] 6968 var isForward = axis.newScroll > axis.oldScroll 6969 var direction = isForward ? axis.forward : axis.backward 6970
6971 for (var waypointKey in this.waypoints[axisKey]) { 6972 var waypoint = this.waypoints[axisKey][waypointKey] 6973 if (waypoint.triggerPoint === null) { 6974 continue 6975 } 6976 var wasBeforeTriggerPoint = axis.oldScroll < waypoint.triggerPoint 6977 var nowAfterTriggerPoint = axis.newScroll >= waypoint.triggerPoint 6978 var crossedForward = wasBeforeTriggerPoint && nowAfterTriggerPoint 6979 var crossedBackward = !wasBeforeTriggerPoint && !nowAfterTriggerPoint 6980 if (crossedForward || crossedBackward) { 6981 waypoint.queueTrigger(direction) 6982 triggeredGroups[waypoint.group.id] = waypoint.group 6983 } 6984 } 6985 } 6986 6987 for (var groupKey in triggeredGroups) { 6988 triggeredGroups[groupKey].flushTriggers() 6989 } 6990 6991 this.oldScroll = { 6992 x: axes.horizontal.newScroll, 6993 y: axes.vertical.newScroll 6994 } 6995 } 6996 6997 /* Private */ 6998 Context.prototype.innerHeight = function() { 6999 /*eslint-disable eqeqeq */ 7000 if (this.element == this.element.window) { 7001 return Waypoint.viewportHeight() 7002 } 7003 /*eslint-enable eqeqeq */ 7004 return this.adapter.innerHeight() 7005 } 7006 7007 /* Private */ 7008 Context.prototype.remove = function(waypoint) { 7009 delete this.waypoints[waypoint.axis][waypoint.key] 7010 this.checkEmpty() 7011 } 7012 7013 /* Private */ 7014 Context.prototype.innerWidth = function() { 7015 /*eslint-disable eqeqeq */ 7016 if (this.element == this.element.window) { 7017 return Waypoint.viewportWidth() 7018 } 7019 /*eslint-enable eqeqeq */ 7020 return this.adapter.innerWidth() 7021 } 7022 7023 /* Public */ 7024 /* http://imakewebthings.com/waypoints/api/context-destroy */ 7025 Context.prototype.destroy = function() { 7026 var allWaypoints = [] 7027 for (var axis in this.waypoints) {
7028 for (var waypointKey in this.waypoints[axis]) { 7029 allWaypoints.push(this.waypoints[axis][waypointKey]) 7030 } 7031 } 7032 for (var i = 0, end = allWaypoints.length; i < end; i++) { 7033 allWaypoints[i].destroy() 7034 } 7035 } 7036 7037 /* Public */ 7038 /* http://imakewebthings.com/waypoints/api/context-refresh */ 7039 Context.prototype.refresh = function() { 7040 /*eslint-disable eqeqeq */ 7041 var isWindow = this.element == this.element.window 7042 /*eslint-enable eqeqeq */ 7043 var contextOffset = isWindow ? undefined : this.adapter.offset() 7044 var triggeredGroups = {} 7045 var axes 7046 7047 this.handleScroll() 7048 axes = { 7049 horizontal: { 7050 contextOffset: isWindow ? 0 : contextOffset.left, 7051 contextScroll: isWindow ? 0 : this.oldScroll.x, 7052 contextDimension: this.innerWidth(), 7053 oldScroll: this.oldScroll.x, 7054 forward: 'right', 7055 backward: 'left', 7056 offsetProp: 'left' 7057 }, 7058 vertical: { 7059 contextOffset: isWindow ? 0 : contextOffset.top, 7060 contextScroll: isWindow ? 0 : this.oldScroll.y, 7061 contextDimension: this.innerHeight(), 7062 oldScroll: this.oldScroll.y, 7063 forward: 'down', 7064 backward: 'up', 7065 offsetProp: 'top' 7066 } 7067 } 7068 7069 for (var axisKey in axes) { 7070 var axis = axes[axisKey]
7071 for (var waypointKey in this.waypoints[axisKey]) { 7072 var waypoint = this.waypoints[axisKey][waypointKey] 7073 var adjustment = waypoint.options.offset 7074 var oldTriggerPoint = waypoint.triggerPoint 7075 var elementOffset = 0 7076 var freshWaypoint = oldTriggerPoint == null 7077 var contextModifier, wasBeforeScroll, nowAfterScroll 7078 var triggeredBackward, triggeredForward 7079 7080 if (waypoint.element !== waypoint.element.window) { 7081 elementOffset = waypoint.adapter.offset()[axis.offsetProp] 7082 } 7083 7084 if (typeof adjustment === 'function') { 7085 adjustment = adjustment.apply(waypoint) 7086 } 7087 else if (typeof adjustment === 'string') { 7088 adjustment = parseFloat(adjustment) 7089 if (waypoint.options.offset.indexOf('%') > - 1) { 7090 adjustment = Math.ceil(axis.contextDimension * adjustment / 100) 7091 } 7092 } 7093 7094 contextModifier = axis.contextScroll - axis.contextOffset 7095 waypoint.triggerPoint = Math.floor(elementOffset + contextModifier - adjustment) 7096 wasBeforeScroll = oldTriggerPoint < axis.oldScroll 7097 nowAfterScroll = waypoint.triggerPoint >= axis.oldScroll 7098 triggeredBackward = wasBeforeScroll && nowAfterScroll 7099 triggeredForward = !wasBeforeScroll && !nowAfterScroll 7100 7101 if (!freshWaypoint && triggeredBackward) { 7102 waypoint.queueTrigger(axis.backward) 7103 triggeredGroups[waypoint.group.id] = waypoint.group 7104 } 7105 else if (!freshWaypoint && triggeredForward) { 7106 waypoint.queueTrigger(axis.forward) 7107 triggeredGroups[waypoint.group.id] = waypoint.group 7108 } 7109 else if (freshWaypoint && axis.oldScroll >= waypoint.triggerPoint) { 7110 waypoint.queueTrigger(axis.forward) 7111 triggeredGroups[waypoint.group.id] = waypoint.group 7112 } 7113 } 7114 } 7115 7116 Waypoint.requestAnimationFrame(function() { 7117 for (var groupKey in triggeredGroups) { 7118 triggeredGroups[groupKey].flushTriggers() 7119 } 7120 }) 7121 7122 return this 7123 } 7124 7125 /* Private */ 7126 Context.findOrCreateByElement = function(element) { 7127 return Context.findByElement(element) || new Context(element) 7128 } 7129 7130 /* Private */ 7131 Context.refreshAll = function() { 7132 for (var contextId in contexts) { 7133 contexts[contextId].refresh() 7134 } 7135 } 7136 7137 /* Public */ 7138 /* http://imakewebthings.com/waypoints/api/context-find-by-element */ 7139 Context.findByElement = function(element) { 7140 return contexts[element.waypointContextKey] 7141 } 7142 7143 window.onload = function() { 7144 if (oldWindowLoad) { 7145 oldWindowLoad() 7146 } 7147 Context.refreshAll() 7148 } 7149 7150 7151 Waypoint.requestAnimationFrame = function(callback) { 7152 var requestFn = window.requestAnimationFrame || 7153 window.mozRequestAnimationFrame || 7154 window.webkitRequestAnimationFrame || 7155 requestAnimationFrameShim 7156 requestFn.call(window, callback) 7157 } 7158 Waypoint.Context = Context 7159}()) 7160;(function() { 7161 'use strict' 7162 7163 function byTriggerPoint(a, b) { 7164 return a.triggerPoint - b.triggerPoint 7165 } 7166 7167 function byReverseTriggerPoint(a, b) { 7168 return b.triggerPoint - a.triggerPoint 7169 } 7170 7171 var groups = { 7172 vertical: {}, 7173 horizontal: {} 7174 } 7175 var Waypoint = window.Waypoint 7176 7177 /* http://imakewebthings.com/waypoints/api/group */ 7178 function Group(options) { 7179 this.name = options.name 7180 this.axis = options.axis 7181 this.id = this.name + '-' + this.axis 7182 this.waypoints = [] 7183 this.clearTriggerQueues() 7184 groups[this.axis][this.name] = this 7185 } 7186 7187 /* Private */ 7188 Group.prototype.add = function(waypoint) { 7189 this.waypoints.push(waypoint) 7190 } 7191 7192 /* Private */ 7193 Group.prototype.clearTriggerQueues = function() { 7194 this.triggerQueues = { 7195 up: [], 7196 down: [], 7197 left: [], 7198 right: [] 7199 } 7200 } 7201 7202 /* Private */ 7203 Group.prototype.flushTriggers = function() { 7204 for (var direction in this.triggerQueues) { 7205 var waypoints = this.triggerQueues[direction] 7206 var reverse = direction === 'up' || direction === 'left' 7207 waypoints.sort(reverse ? byReverseTriggerPoint : byTriggerPoint) 7208 for (var i = 0, end = waypoints.length; i < end; i += 1) { 7209 var waypoint = waypoints[i] 7210 if (waypoint.options.continuous || i === waypoints.length - 1) { 7211 waypoint.trigger([direction]) 7212 } 7213 } 7214 } 7215 this.clearTriggerQueues() 7216 } 7217 7218 /* Private */ 7219 Group.prototype.next = function(waypoint) { 7220 this.waypoints.sort(byTriggerPoint) 7221 var index = Waypoint.Adapter.inArray(waypoint, this.waypoints) 7222 var isLast = index === this.waypoints.length - 1 7223 return isLast ? null : this.waypoints[index + 1] 7224 } 7225 7226 /* Private */ 7227 Group.prototype.previous = function(waypoint) { 7228 this.waypoints.sort(byTriggerPoint) 7229 var index = Waypoint.Adapter.inArray(waypoint, this.waypoints) 7230 return index ? this.waypoints[index - 1] : null 7231 } 7232 7233 /* Private */ 7234 Group.prototype.queueTrigger = function(waypoint, direction) { 7235 this.triggerQueues[direction].push(waypoint) 7236 } 7237 7238 /* Private */ 7239 Group.prototype.remove = function(waypoint) { 7240 var index = Waypoint.Adapter.inArray(waypoint, this.waypoints) 7241 if (index > -1) { 7242 this.waypoints.splice(index, 1) 7243 } 7244 } 7245 7246 /* Public */ 7247 /* http://imakewebthings.com/waypoints/api/first */ 7248 Group.prototype.first = function() { 7249 return this.waypoints[0] 7250 } 7251 7252 /* Public */ 7253 /* http://imakewebthings.com/waypoints/api/last */ 7254 Group.prototype.last = function() { 7255 return this.waypoints[this.waypoints.length - 1] 7256 } 7257 7258 /* Private */ 7259 Group.findOrCreate = function(options) { 7260 return groups[options.axis][options.name] || new Group(options) 7261 } 7262 7263 Waypoint.Group = Group 7264}()) 7265;(function() { 7266 'use strict' 7267 7268 var $ = window.jQuery 7269 var Waypoint = window.Waypoint 7270 7271 function JQueryAdapter(element) { 7272 this.$element = $(element) 7273 } 7274 7275 $.each([
7276 'innerHeight', 7277 'innerWidth', 7278 'off', 7279 'offset', 7280 'on', 7281 'outerHeight', 7282 'outerWidth', 7283 'scrollLeft', 7284 'scrollTop' 7285 ], function(i, method) { 7286 JQueryAdapter.prototype[method] = function() { 7287 var args = Array.prototype.slice.call(arguments) 7288 return this.$element[method].apply(this.$element, args) 7289 } 7290 }) 7291 7292 $.each([ 7293 'extend', 7294 'inArray', 7295 'isEmptyObject' 7296 ], function(i, method) { 7297 JQueryAdapter[method] = $[method] 7298 }) 7299 7300 Waypoint.adapters.push({ 7301 name: 'jquery', 7302 Adapter: JQueryAdapter 7303 }) 7304 Waypoint.Adapter = JQueryAdapter 7305}()) 7306;(function() { 7307 'use strict' 7308 7309 var Waypoint = window.Waypoint 7310 7311 function createExtension(framework) { 7312 return function() { 7313 var waypoints = [] 7314 var overrides = arguments[0] 7315 7316 if (framework.isFunction(arguments[0])) { 7317 overrides = framework.extend({}, arguments[1]) 7318 overrides.handler = arguments[0] 7319 } 7320 7321 this.each(function() { 7322 var options = framework.extend({}, overrides, { 7323 element: this 7324 }) 7325 if (typeof options.context === 'string') { 7326 options.context = framework(this).closest(options.context)[0] 7327 } 7328 waypoints.push(new Waypoint(options)) 7329 }) 7330 7331 return waypoints 7332 } 7333 } 7334 7335 if (window.jQuery) { 7336 window.jQuery.fn.waypoint = createExtension(window.jQuery) 7337 } 7338 if (window.Zepto) { 7339 window.Zepto.fn.waypoint = createExtension(window.Zepto) 7340 } 7341}()) 7342; 7343/*! 7344Waypoints Inview Shortcut - 4.0.1 7345Copyright © 2011-2016 Caleb Troughton 7346Licensed under the MIT license. 7347https://github.com/imakewebthings/waypoints/blob/master/licenses.txt 7348*/ 7349(function() { 7350 'use strict' 7351 7352 function noop() {} 7353 7354 var Waypoint = window.Waypoint 7355 7356 /* http://imakewebthings.com/waypoints/shortcuts/inview */ 7357 function Inview(options) { 7358 this.options = Waypoint.Adapter.extend({}, Inview.defaults, options) 7359 this.axis = this.options.horizontal ? 'horizontal' : 'vertical' 7360 this.waypoints = [] 7361 this.element = this.options.element 7362 this.createWaypoints() 7363 } 7364 7365 /* Private */ 7366 Inview.prototype.createWaypoints = function() { 7367 var configs = { 7368 vertical: [{ 7369 down: 'enter', 7370 up: 'exited', 7371 offset: '100%' 7372 }, { 7373 down: 'entered', 7374 up: 'exit', 7375 offset: 'bottom-in-view' 7376 }, { 7377 down: 'exit', 7378 up: 'entered', 7379 offset: 0 7380 }, { 7381 down: 'exited', 7382 up: 'enter', 7383 offset: function() { 7384 return -this.adapter.outerHeight() 7385 } 7386 }], 7387 horizontal: [{ 7388 right: 'enter', 7389 left: 'exited', 7390 offset: '100%' 7391 }, { 7392 right: 'entered', 7393 left: 'exit', 7394 offset: 'right-in-view' 7395 }, { 7396 right: 'exit', 7397 left: 'entered', 7398 offset: 0 7399 }, { 7400 right: 'exited', 7401 left: 'enter', 7402 offset: function() { 7403 return -this.adapter.outerWidth() 7404 } 7405 }] 7406 } 7407 7408 for (var i = 0, end = configs[this.axis].length; i < end; i++) { 7409 var config = configs[this.axis][i] 7410 this.createWaypoint(config) 7411 } 7412 } 7413 7414 /* Private */ 7415 Inview.prototype.createWaypoint = function(config) { 7416 var self = this 7417 this.waypoints.push(new Waypoint({ 7418 context: this.options.context, 7419 element: this.options.element, 7420 enabled: this.options.enabled, 7421 handler: (function(config) { 7422 return function(direction) { 7423 self.options[config[direction]].call(self, direction) 7424 } 7425 }(config)), 7426 offset: config.offset, 7427 horizontal: this.options.horizontal 7428 })) 7429 } 7430 7431 /* Public */ 7432 Inview.prototype.destroy = function() { 7433 for (var i = 0, end = this.waypoints.length; i < end; i++) { 7434 this.waypoints[i].destroy() 7435 } 7436 this.waypoints = [] 7437 } 7438 7439 Inview.prototype.disable = function() { 7440 for (var i = 0, end = this.waypoints.length; i < end; i++) { 7441 this.waypoints[i].disable() 7442 } 7443 } 7444 7445 Inview.prototype.enable = function() { 7446 for (var i = 0, end = this.waypoints.length; i < end; i++) { 7447 this.waypoints[i].enable() 7448 } 7449 } 7450 7451 Inview.defaults = { 7452 context: window, 7453 enabled: true, 7454 enter: noop, 7455 entered: noop,
7456 exit: noop, 7457 exited: noop 7458 } 7459 7460 Waypoint.Inview = Inview 7461}()) 7462; 7463 7464/* 7465 * SmartMenus jQuery v0.9.6 7466 * http://www.smartmenus.org/ 7467 * 7468 * Copyright 2014 Vasil Dinkov, Vadikom Web Ltd. 7469 * http://vadikom.com/ 7470 * 7471 * Released under the MIT license: 7472 * http://www.opensource.org/licenses/MIT 7473 */ 7474 7475(function($) { 7476 7477 var menuTrees = [], 7478 IE = !!window.createPopup, // we need to detect it, unfortunately 7479 IElt9 = IE && !document.defaultView, 7480 IElt8 = IE && !document.querySelector, 7481 IE6 = IE && typeof document.documentElement.currentStyle.minWidth == 'undefined', 7482 mouse = false, // optimize for touch by default - we will detect for mouse input 7483 mouseDetectionEnabled = false; 7484 7485 // Handle detection for mouse input (i.e. desktop browsers, tablets with a mouse, etc.) 7486 function initMouseDetection(disable) { 7487 if (!mouseDetectionEnabled && !disable) { 7488 // if we get two consecutive mousemoves within 2 pixels from each other and within 300ms, we assume a real mouse/cursor is present 7489 // 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) 7490 var firstTime = true, 7491 lastMove = null; 7492 $(document).bind({ 7493 'mousemove.smartmenus_mouse': function(e) { 7494 var thisMove = { x: e.pageX, y: e.pageY, timeStamp: new Date().getTime() }; 7495 if (lastMove) { 7496 var deltaX = Math.abs(lastMove.x - thisMove.x), 7497 deltaY = Math.abs(lastMove.y - thisMove.y); 7498 if ((deltaX > 0 || deltaY > 0) && deltaX <= 2 && deltaY <= 2 && thisMove.timeStamp - lastMove.timeStamp <= 300) { 7499 mouse = true; 7500 // 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 7501 if (firstTime) { 7502 var $a = $(e.target).closest('a'); 7503 if ($a.is('a')) { 7504 $.each(menuTrees, function() { 7505 if ($.contains(this.$root[0], $a[0])) { 7506 this.itemEnter({ currentTarget: $a[0] }); 7507 return false; 7508 } 7509 }); 7510 } 7511 firstTime = false; 7512 } 7513 } 7514 } 7515 lastMove = thisMove; 7516 }, 7517 'touchstart.smartmenus_mouse pointerover.smartmenus_mouse MSPointerOver.smartmenus_mouse': function(e) { 7518 if (!/^(4|mouse)$/.test(e.originalEvent.pointerType)) { 7519 mouse = false; 7520 } 7521 } 7522 }); 7523 mouseDetectionEnabled = true; 7524 } else if (mouseDetectionEnabled && disable) { 7525 $(document).unbind('.smartmenus_mouse'); 7526 mouseDetectionEnabled = false; 7527 } 7528 }; 7529 7530 $.SmartMenus = function(elm, options) { 7531 this.$root = $(elm); 7532 this.opts = options; 7533 this.rootId = ''; // internal 7534 this.$subArrow = null; 7535 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) 7536 this.activatedItems = []; // stores last activated A's for each level 7537 this.visibleSubMenus = []; // stores visible sub menus UL's 7538 this.showTimeout = 0; 7539 this.hideTimeout = 0; 7540 this.scrollTimeout = 0; 7541 this.clickActivated = false; 7542 this.zIndexInc = 0; 7543 this.$firstLink = null; // we'll use these for some tests 7544 this.$firstSub = null; // at runtime so we'll cache them 7545 this.disabled = false; 7546 this.$disableOverlay = null; 7547 this.init(); 7548 }; 7549 7550 $.extend($.SmartMenus, { 7551 hideAll: function() { 7552 $.each(menuTrees, function() { 7553 this.menuHideAll(); 7554 }); 7555 }, 7556 destroy: function() { 7557 while (menuTrees.length) { 7558 menuTrees[0].destroy(); 7559 } 7560 initMouseDetection(true); 7561 }, 7562 prototype: { 7563 init: function(refresh) { 7564 var self = this; 7565 7566 if (!refresh) { 7567 menuTrees.push(this); 7568 7569 this.rootId = (new Date().getTime() + Math.random() + '').replace(/\D/g, ''); 7570 7571 if (this.$root.hasClass('sm-rtl')) { 7572 this.opts.rightToLeftSubMenus = true; 7573 } 7574 7575 // init root (main menu) 7576 this.$root 7577 .data('smartmenus', this) 7578 .attr('data-smartmenus-id', this.rootId) 7579 .dataSM('level', 1) 7580 .bind({ 7581 'mouseover.smartmenus focusin.smartmenus': $.proxy(this.rootOver, this),
7582 'mouseout.smartmenus focusout.smartmenus': $.proxy(this.rootOut, this) 7583 }) 7584 .delegate('a', { 7585 'mouseenter.smartmenus': $.proxy(this.itemEnter, this), 7586 'mouseleave.smartmenus': $.proxy(this.itemLeave, this), 7587 'mousedown.smartmenus': $.proxy(this.itemDown, this), 7588 'focus.smartmenus': $.proxy(this.itemFocus, this), 7589 'blur.smartmenus': $.proxy(this.itemBlur, this), 7590 'click.smartmenus': $.proxy(this.itemClick, this), 7591 'touchend.smartmenus': $.proxy(this.itemTouchEnd, this) 7592 }); 7593 7594 var eNamespace = '.smartmenus' + this.rootId; 7595 // hide menus on tap or click outside the root UL 7596 if (this.opts.hideOnClick) { 7597 $(document).bind('touchstart' + eNamespace, $.proxy(this.docTouchStart, this)) 7598 .bind('touchmove' + eNamespace, $.proxy(this.docTouchMove, this)) 7599 .bind('touchend' + eNamespace, $.proxy(this.docTouchEnd, this)) 7600 // for Opera Mobile < 11.5, webOS browser, etc. we'll check click too 7601 .bind('click' + eNamespace, $.proxy(this.docClick, this)); 7602 } 7603 // hide sub menus on resize 7604 $(window).bind('resize' + eNamespace + ' orientationchange' + eNamespace, $.proxy(this.winResize, this)); 7605 $(window).bind('scroll' + eNamespace + ' orientationchange' + eNamespace, $.proxy(this.winResize, this)); 7606 7607 if (this.opts.subIndicators) { 7608 this.$subArrow = $('<span/>').addClass('sub-arrow'); 7609 if (this.opts.subIndicatorsText) { 7610 this.$subArrow.html(this.opts.subIndicatorsText); 7611 } 7612 } 7613 7614 // make sure mouse detection is enabled 7615 initMouseDetection(); 7616 } 7617 7618 // init sub menus 7619 this.$firstSub = this.$root.find('ul').each(function() { self.menuInit($(this)); }).eq(0); 7620 7621 this.$firstLink = this.$root.find('a').eq(0); 7622 7623 // find current item 7624 if (this.opts.markCurrentItem) { 7625 var reDefaultDoc = /(index|default)\.[^#\?\/]*/i, 7626 reHash = /#.*/, 7627 locHref = window.location.href.replace(reDefaultDoc, ''), 7628 locHrefNoHash = locHref.replace(reHash, ''); 7629 this.$root.find('a').each(function() { 7630 var href = this.href.replace(reDefaultDoc, ''), 7631 $this = $(this); 7632 if (href == locHref || href == locHrefNoHash) { 7633 $this.addClass('current'); 7634 if (self.opts.markCurrentTree) { 7635 $this.parents('li').each(function() { 7636 var $this = $(this); 7637 if ($this.dataSM('sub')) { 7638 $this.children('a').addClass('current'); 7639 } 7640 }); 7641 } 7642 } 7643 }); 7644 } 7645 }, 7646 destroy: function() { 7647 this.menuHideAll(); 7648 this.$root 7649 .removeData('smartmenus') 7650 .removeAttr('data-smartmenus-id') 7651 .removeDataSM('level') 7652 .unbind('.smartmenus') 7653 .undelegate('.smartmenus'); 7654 var eNamespace = '.smartmenus' + this.rootId; 7655 $(document).unbind(eNamespace); 7656 $(window).unbind(eNamespace); 7657 if (this.opts.subIndicators) { 7658 this.$subArrow = null; 7659 } 7660 var self = this; 7661 $.each(this.subMenus, function() { 7662 if (this.hasClass('mega-menu')) { 7663 this.find('ul').removeDataSM('in-mega'); 7664 } 7665 if (this.dataSM('shown-before')) { 7666 if (IElt8) { 7667 this.children().css({ styleFloat: '', width: '' }); 7668 } 7669 if (self.opts.subMenusMinWidth || self.opts.subMenusMaxWidth) { 7670 if (!IE6) { 7671 this.css({ width: '', minWidth: '', maxWidth: '' }).removeClass('sm-nowrap'); 7672 } else { 7673 this.css({ width: '', overflowX: '', overflowY: '' }).children().children('a').css('white-space', ''); 7674 } 7675 } 7676 if (this.dataSM('scroll-arrows')) { 7677 this.dataSM('scroll-arrows').remove(); 7678 } 7679 this.css({ zIndex: '', top: '', left: '', marginLeft: '', marginTop: '', display: '' }); 7680 } 7681 if (self.opts.subIndicators) { 7682 this.dataSM('parent-a').removeClass('has-submenu').children('span.sub-arrow').remove(); 7683 } 7684 this.removeDataSM('shown-before') 7685 .removeDataSM('ie-shim') 7686 .removeDataSM('scroll-arrows') 7687 .removeDataSM('parent-a') 7688 .removeDataSM('level') 7689 .removeDataSM('beforefirstshowfired') 7690 .parent().removeDataSM('sub'); 7691 }); 7692 if (this.opts.markCurrentItem) { 7693 this.$root.find('a.current').removeClass('current'); 7694 } 7695 this.$root = null; 7696 this.$firstLink = null; 7697 this.$firstSub = null; 7698 if (this.$disableOverlay) { 7699 this.$disableOverlay.remove(); 7700 this.$disableOverlay = null; 7701 } 7702 menuTrees.splice($.inArray(this, menuTrees), 1); 7703 }, 7704 disable: function(noOverlay) { 7705 if (!this.disabled) { 7706 this.menuHideAll(); 7707 // display overlay over the menu to prevent interaction 7708 if (!noOverlay && !this.opts.isPopup && this.$root.is(':visible')) { 7709 var pos = this.$root.offset(); 7710 this.$disableOverlay = $('<div class="sm-jquery-disable-overlay"/>').css({ 7711 position: 'absolute', 7712 top: pos.top, 7713 left: pos.left, 7714 width: this.$root.outerWidth(), 7715 height: this.$root.outerHeight(),
7716 zIndex: this.getStartZIndex() + 1, 7717 opacity: 0 7718 }).appendTo(document.body); 7719 } 7720 this.disabled = true; 7721 } 7722 }, 7723 docClick: function(e) { 7724 // hide on any click outside the menu or on a menu link 7725 if (this.visibleSubMenus.length && !$.contains(this.$root[0], e.target) || $(e.target).is('a')) { 7726 this.menuHideAll($(e.target)); 7727 } 7728 }, 7729 docTouchEnd: function(e) { 7730 if (!this.lastTouch) { 7731 return; 7732 } 7733 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))) { 7734 if (this.hideTimeout) { 7735 clearTimeout(this.hideTimeout); 7736 this.hideTimeout = 0; 7737 } 7738 // hide with a delay to prevent triggering accidental unwanted click on some page element 7739 var self = this; 7740 this.hideTimeout = setTimeout(function() { self.menuHideAll($(e.target)); }, 350); 7741 } 7742 this.lastTouch = null; 7743 }, 7744 docTouchMove: function(e) { 7745 if (!this.lastTouch) { 7746 return; 7747 } 7748 var touchPoint = e.originalEvent.touches[0]; 7749 this.lastTouch.x2 = touchPoint.pageX; 7750 this.lastTouch.y2 = touchPoint.pageY; 7751 }, 7752 docTouchStart: function(e) { 7753 var touchPoint = e.originalEvent.touches[0]; 7754 this.lastTouch = { x1: touchPoint.pageX, y1: touchPoint.pageY, target: touchPoint.target }; 7755 }, 7756 enable: function() { 7757 if (this.disabled) { 7758 if (this.$disableOverlay) { 7759 this.$disableOverlay.remove(); 7760 this.$disableOverlay = null; 7761 } 7762 this.disabled = false; 7763 } 7764 }, 7765 getHeight: function($elm) { 7766 return this.getOffset($elm, true); 7767 }, 7768 // returns precise width/height float values in IE9+, FF4+, recent WebKit 7769 // http://vadikom.com/dailies/offsetwidth-offsetheight-useless-in-ie9-firefox4/ 7770 getOffset: function($elm, height) { 7771 var old; 7772 if ($elm.css('display') == 'none') { 7773 old = { position: $elm[0].style.position, visibility: $elm[0].style.visibility }; 7774 $elm.css({ position: 'absolute', visibility: 'hidden' }).show(); 7775 } 7776 var defaultView = $elm[0].ownerDocument.defaultView, 7777 compStyle = defaultView && defaultView.getComputedStyle && defaultView.getComputedStyle($elm[0], null), 7778 val = compStyle && parseFloat(compStyle[height ? 'height' : 'width']); 7779 if (val) { 7780 val += parseFloat(compStyle[height ? 'paddingTop' : 'paddingLeft']) 7781 + parseFloat(compStyle[height ? 'paddingBottom' : 'paddingRight']) 7782 + parseInt(compStyle[height ? 'borderTopWidth' : 'borderLeftWidth']) 7783 + parseInt(compStyle[height ? 'borderBottomWidth' : 'borderRightWidth']); 7784 } else { 7785 val = height ? $elm[0].offsetHeight : $elm[0].offsetWidth; 7786 } 7787 if (old) { 7788 $elm.hide().css(old); 7789 } 7790 return val; 7791 }, 7792 getWidth: function($elm) { 7793 return this.getOffset($elm); 7794 }, 7795 getStartZIndex: function() { 7796 var zIndex = parseInt(this.$root.css('z-index')); 7797 return !isNaN(zIndex) ? zIndex : 1; 7798 }, 7799 handleEvents: function() { 7800 return !this.disabled && this.isCSSOn(); 7801 }, 7802 handleItemEvents: function($a) { 7803 return this.handleEvents() && !this.isLinkInMegaMenu($a); 7804 }, 7805 isCollapsible: function() { 7806 return this.$firstSub.css('position') == 'static'; 7807 }, 7808 isCSSOn: function() { 7809 return this.$firstLink.css('display') == 'block' || this.$firstLink.css('display') == 'inline'; 7810 }, 7811 isFixed: function() { 7812 return this.$root.css('position') == 'fixed'; 7813 }, 7814 isLinkInMegaMenu: function($a) { 7815 return !$a.parent().parent().dataSM('level'); 7816 }, 7817 isTouchMode: function() { 7818 return !mouse || this.isCollapsible(); 7819 }, 7820 itemActivate: function($a) { 7821 var $li = $a.parent(), 7822 $ul = $li.parent(), 7823 level = $ul.dataSM('level'); 7824 // 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 7825 if (level > 1 && (!this.activatedItems[level - 2] || this.activatedItems[level - 2][0] != $ul.dataSM('parent-a')[0])) { 7826 var self = this; 7827 $($ul.parentsUntil('[data-smartmenus-id]', 'ul').get().reverse()).add($ul).each(function() { 7828 self.itemActivate($(this).dataSM('parent-a')); 7829 }); 7830 } 7831 // hide any visible deeper level sub menus 7832 if (this.visibleSubMenus.length > level) { 7833 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--) { 7834 this.menuHide(this.visibleSubMenus[i]); 7835 } 7836 } 7837 // save new active item and sub menu for this level 7838 this.activatedItems[level - 1] = $a; 7839 this.visibleSubMenus[level - 1] = $ul; 7840 if (this.$root.triggerHandler('activate.smapi', $a[0]) === false) { 7841 return; 7842 } 7843 // show the sub menu if this item has one 7844 var $sub = $li.dataSM('sub'); 7845 if ($sub && (this.isTouchMode() || (!this.opts.showOnClick || this.clickActivated))) { 7846 this.menuShow($sub); 7847 } 7848 }, 7849 itemBlur: function(e) { 7850 var $a = $(e.currentTarget); 7851 if (!this.handleItemEvents($a)) { 7852 return; 7853 } 7854 this.$root.triggerHandler('blur.smapi', $a[0]); 7855 }, 7856 itemClick: function(e) { 7857 var $a = $(e.currentTarget); 7858 7859 if (!this.handleItemEvents($a)) { 7860 return; 7861 } 7862 $a.removeDataSM('mousedown'); 7863 if (this.$root.triggerHandler('click.smapi', $a[0]) === false) { 7864 return false;
7865 } 7866 var $sub = $a.parent().dataSM('sub'); 7867 if (this.isTouchMode()) { 7868 // undo fix: prevent the address bar on iPhone from sliding down when expanding a sub menu 7869 if ($a.dataSM('href')) { 7870 $a.attr('href', $a.dataSM('href')).removeDataSM('href'); 7871 } 7872 // if the sub is not visible 7873 if ($sub && (!$sub.dataSM('shown-before') || !$sub.is(':visible'))) { 7874 // try to activate the item and show the sub 7875 this.itemActivate($a); 7876 // if "itemActivate" showed the sub, prevent the click so that the link is not loaded 7877 // 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 7878 if ($sub.is(':visible')) { 7879 return false; 7880 } 7881 } 7882 } else if (this.opts.showOnClick && $a.parent().parent().dataSM('level') == 1 && $sub) { 7883 this.clickActivated = true; 7884 this.menuShow($sub); 7885 return false; 7886 } 7887 if ($a.hasClass('disabled')) { 7888 return false; 7889 } 7890 if (this.$root.triggerHandler('select.smapi', $a[0]) === false) { 7891 return false; 7892 } 7893 }, 7894 itemDown: function(e) { 7895 var $a = $(e.currentTarget); 7896 if (!this.handleItemEvents($a)) { 7897 return; 7898 } 7899 $a.dataSM('mousedown', true); 7900 }, 7901 itemEnter: function(e) { 7902 var $a = $(e.currentTarget); 7903 if (!this.handleItemEvents($a)) { 7904 return; 7905 } 7906 if (!this.isTouchMode()) { 7907 if (this.showTimeout) { 7908 clearTimeout(this.showTimeout); 7909 this.showTimeout = 0; 7910 } 7911 var self = this; 7912 this.showTimeout = setTimeout(function() { self.itemActivate($a); }, this.opts.showOnClick && $a.parent().parent().dataSM('level') == 1 ? 1 : this.opts.showTimeout); 7913 } 7914 this.$root.triggerHandler('mouseenter.smapi', $a[0]); 7915 }, 7916 itemFocus: function(e) { 7917 var $a = $(e.currentTarget); 7918 if (!this.handleItemEvents($a)) { 7919 return; 7920 } 7921 // 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 7922 if ((!this.isTouchMode() || !$a.dataSM('mousedown')) && (!this.activatedItems.length || this.activatedItems[this.activatedItems.length - 1][0] != $a[0])) { 7923 this.itemActivate($a); 7924 } 7925 this.$root.triggerHandler('focus.smapi', $a[0]); 7926 }, 7927 itemLeave: function(e) { 7928 var $a = $(e.currentTarget); 7929 if (!this.handleItemEvents($a)) { 7930 return; 7931 } 7932 if (!this.isTouchMode()) { 7933 if ($a[0].blur) { 7934 $a[0].blur(); 7935 } 7936 if (this.showTimeout) { 7937 clearTimeout(this.showTimeout); 7938 this.showTimeout = 0; 7939 } 7940 } 7941 $a.removeDataSM('mousedown'); 7942 this.$root.triggerHandler('mouseleave.smapi', $a[0]); 7943 }, 7944 itemTouchEnd: function(e) { 7945 var $a = $(e.currentTarget); 7946 if (!this.handleItemEvents($a)) { 7947 return; 7948 } 7949 // prevent the address bar on iPhone from sliding down when expanding a sub menu 7950 var $sub = $a.parent().dataSM('sub'); 7951 if ($a.attr('href').charAt(0) !== '#' && $sub && (!$sub.dataSM('shown-before') || !$sub.is(':visible'))) { 7952 $a.dataSM('href', $a.attr('href')); 7953 $a.attr('href', '#'); 7954 } 7955 }, 7956 menuFixLayout: function($ul) { 7957 // fixes a menu that is being shown for the first time 7958 if (!$ul.dataSM('shown-before')) { 7959 $ul.hide().dataSM('shown-before', true); 7960 // fix the layout of the items in IE<8 7961 if (IElt8) { 7962 $ul.children().css({ styleFloat: 'left', width: '100%' }); 7963 } 7964 } 7965 }, 7966 menuHide: function($sub) { 7967 if (this.$root.triggerHandler('beforehide.smapi', $sub[0]) === false) { 7968 return; 7969 } 7970 $sub.stop(true, true); 7971 if ($sub.is(':visible')) { 7972 var complete = function() { 7973 // unset z-index 7974 if (IElt9) { 7975 $sub.parent().css('z-index', ''); 7976 } else { 7977 $sub.css('z-index', ''); 7978 } 7979 }; 7980 // if sub is collapsible (mobile view) 7981 if (this.isCollapsible()) { 7982 if (this.opts.collapsibleHideFunction) { 7983 this.opts.collapsibleHideFunction.call(this, $sub, complete); 7984 } else { 7985 $sub.hide(this.opts.collapsibleHideDuration, complete); 7986 } 7987 } else { 7988 if (this.opts.hideFunction) { 7989 this.opts.hideFunction.call(this, $sub, complete); 7990 } else { 7991 $sub.hide(this.opts.hideDuration, complete); 7992 } 7993 } 7994 // remove IE iframe shim 7995 if ($sub.dataSM('ie-shim')) { 7996 $sub.dataSM('ie-shim').remove(); 7997 } 7998 // deactivate scrolling if it is activated for this sub 7999 if ($sub.dataSM('scroll')) { 8000 $sub.unbind('.smartmenus_scroll').removeDataSM('scroll').dataSM('scroll-arrows').hide(); 8001 } 8002 // unhighlight parent item 8003 $sub.dataSM('parent-a').removeClass('highlighted'); 8004 var level = $sub.dataSM('level'); 8005 this.activatedItems.splice(level - 1, 1); 8006 this.visibleSubMenus.splice(level - 1, 1); 8007 this.$root.triggerHandler('hide.smapi', $sub[0]); 8008 } 8009 }, 8010 menuHideAll: function($item) { 8011 if ($item != undefined && $item.parent().hasClass('menu-item') && !$item.parent().hasClass('menu-item-has-children')) return; 8012 if ( $('body').hasClass('vmenu') ) return; 8013 if (this.showTimeout) { 8014 clearTimeout(this.showTimeout); 8015 this.showTimeout = 0; 8016 } 8017 // hide all subs 8018 for (var i = this.visibleSubMenus.length - 1; i > 0; i--) { 8019 this.menuHide(this.visibleSubMenus[i]); 8020 } 8021 // hide root if it's popup 8022 if (this.opts.isPopup) { 8023 this.$root.stop(true, true); 8024 if (this.$root.is(':visible')) { 8025 if (this.opts.hideFunction) { 8026 this.opts.hideFunction.call(this, this.$root); 8027 } else { 8028 this.$root.hide(this.opts.hideDuration); 8029 } 8030 // remove IE iframe shim 8031 if (this.$root.dataSM('ie-shim')) { 8032 this.$root.dataSM('ie-shim').remove(); 8033 } 8034 } 8035 } 8036 this.activatedItems = []; 8037 this.visibleSubMenus = []; 8038 this.clickActivated = false;
8039 // reset z-index increment 8040 this.zIndexInc = 0; 8041 }, 8042 menuIframeShim: function($ul) { 8043 // create iframe shim for the menu 8044 if (IE && this.opts.overlapControlsInIE && !$ul.dataSM('ie-shim')) { 8045 $ul.dataSM('ie-shim', $('<iframe/>').attr({ src: 'javascript:0', tabindex: -9 }) 8046 .css({ position: 'absolute', top: 'auto', left: '0', opacity: 0, border: '0' }) 8047 ); 8048 } 8049 }, 8050 menuInit: function($ul) { 8051 if (!$ul.dataSM('in-mega')) { 8052 this.subMenus.push($ul); 8053 // mark UL's in mega drop downs (if any) so we can neglect them 8054 if ($ul.hasClass('mega-menu')) { 8055 $ul.find('ul').dataSM('in-mega', true); 8056 } 8057 // get level (much faster than, for example, using parentsUntil) 8058 var level = 2, 8059 par = $ul[0]; 8060 while ((par = par.parentNode.parentNode) != this.$root[0]) { 8061 level++; 8062 } 8063 // cache stuff 8064 $ul.dataSM('parent-a', $ul.prevAll('a').eq(-1)) 8065 .dataSM('level', level) 8066 .parent().dataSM('sub', $ul); 8067 // add sub indicator to parent item 8068 if (this.opts.subIndicators) { 8069 $ul.dataSM('parent-a').addClass('has-submenu')[this.opts.subIndicatorsPos](this.$subArrow.clone()); 8070 } 8071 } 8072 }, 8073 menuPosition: function($sub) { 8074 var fixIE = $('html.ie').length; 8075 // if (fixIE) { 8076 // var $rowParent = $($sub).closest('.main-menu-container'); 8077 // $rowParent.height($rowParent.height()); 8078 // } 8079 var $a = $sub.dataSM('parent-a'), 8080 $li = $sub.parent(), 8081 $ul = $sub.parent().parent(), 8082 $container = $ul.closest('.row-menu-inner'), 8083 level = $sub.dataSM('level'), 8084 subW = this.getWidth($sub), 8085 subH = this.getHeight($sub), 8086 itemOffset = $a.offset(), 8087 itemX = itemOffset.left, 8088 itemY = itemOffset.top, 8089 itemW = this.getWidth($a), 8090 itemH = this.getHeight($a), 8091 $win = $(window), 8092 winX = $win.scrollLeft(), 8093 winY = $win.scrollTop(), 8094 winW = $win.width(), 8095 winH = $win.height(), 8096 containerW = $container.width(), 8097 containerOffsetX = containerW + ((winW - containerW) / 2), 8098 horizontalParent = $ul.hasClass('sm') && !$ul.hasClass('sm-vertical'), 8099 subOffsetX = level == 2 ? this.opts.mainMenuSubOffsetX : this.opts.subMenusSubOffsetX, 8100 subOffsetY = level == 2 ? this.opts.mainMenuSubOffsetY : this.opts.subMenusSubOffsetY, 8101 x, y, leftPos; 8102 if (horizontalParent) { 8103 x = this.opts.rightToLeftSubMenus ? itemW - subW - subOffsetX : subOffsetX; 8104 y = this.opts.bottomToTopSubMenus ? -subH - subOffsetY : itemH + subOffsetY; 8105 } else { 8106 x = this.opts.rightToLeftSubMenus ? subOffsetX - subW : itemW - subOffsetX; 8107 y = this.opts.bottomToTopSubMenus ? itemH - subOffsetY - subH : subOffsetY; 8108 } 8109 if (this.opts.keepInViewport && !this.isCollapsible()) { 8110 if (this.isFixed()) { 8111 itemX -= winX; 8112 itemY -= winY; 8113 winX = winY = 0; 8114 } 8115 var absX = itemX + x, 8116 absY = itemY + y; 8117 if (this.opts.rightToLeftSubMenus && absX < winX) { 8118 x = horizontalParent ? winX - absX + x : itemW - subOffsetX; 8119 } else if (!this.opts.rightToLeftSubMenus && absX + subW > winX + containerOffsetX ) { 8120 x = horizontalParent ? winX + containerOffsetX - subW - absX + x : subOffsetX - subW; 8121 } 8122 if (!horizontalParent) { 8123 if (subH < winH && absY + subH > winY + winH) { 8124 y += winY + winH - subH - absY; 8125 } else if (subH >= winH || absY < winY) { 8126 y += winY - absY; 8127 } 8128 } 8129 // do we need scrolling? 8130 // 0.49 added for the sake of IE9/FF4+ where we might be dealing with float numbers for "subH" 8131 if (mouse && (horizontalParent && (absY + subH > winY + winH + 0.49 || absY < winY) || !horizontalParent && subH > winH + 0.49)) { 8132 var self = this; 8133 if (!$sub.dataSM('scroll-arrows')) { 8134 $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]]) 8135 .bind({ 8136 mouseenter: function() { self.menuScroll($sub, $(this).hasClass('scroll-up')); }, 8137 mouseleave: function(e) { 8138 self.menuScrollStop($sub); 8139 self.menuScrollOut($sub, e); 8140 }, 8141 'mousewheel DOMMouseScroll': function(e) { e.preventDefault(); } 8142 }) 8143 .insertAfter($sub) 8144 ); 8145 } 8146 // bind events to show/hide arrows on hover and save scrolling data for this sub 8147 var vportY = winY - (itemY + itemH); 8148 $sub.dataSM('scroll', { 8149 vportY: vportY, 8150 subH: subH, 8151 winH: winH, 8152 step: 1 8153 }) 8154 .bind({ 8155 'mouseover.smartmenus_scroll': function(e) { self.menuScrollOver($sub, e); }, 8156 'mouseout.smartmenus_scroll': function(e) { self.menuScrollOut($sub, e); }, 8157 'mousewheel.smartmenus_scroll DOMMouseScroll.smartmenus_scroll': function(e) { self.menuScrollMousewheel($sub, e); } 8158 }) 8159 .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
8159StartZIndex() + this.zIndexInc }) 8160 .eq(0).css('margin-top', vportY).end() 8161 .eq(1).css('margin-top', vportY + winH - this.getHeight($sub.dataSM('scroll-arrows').eq(1))).end() 8162 .eq(horizontalParent && this.opts.bottomToTopSubMenus ? 0 : 1).show(); 8163 } 8164 } 8165 // if ($sub.hasClass('mega-menu-inner')) { 8166 // if ($('.menu-wrapper .megamenu-diff').length > 0) { 8167 // leftPos = parseFloat($('.menu-wrapper .megamenu-diff').outerWidth()); 8168 // leftPos = -leftPos; 8169 // } else leftPos = parseFloat($('.menu-wrapper .main-menu-container').css('paddingLeft')); 8170 8171 // if ($('body.header-full-width').length > 0) { 8172 // $sub.css({ width: $('.box-container').width()}); 8173 // leftPos = (leftPos - parseFloat($('.menu-wrapper .row-menu-inner').css('paddingLeft'))); 8174 // } else $sub.css({ width: containerW}); 8175 // leftPos = leftPos + 'px'; 8176 8177 // } else { 8178 // leftPos = $li.position().left + 'px'; 8179 // } 8180 if ($sub.hasClass('mega-menu-inner')) { 8181 $sub.css({ width: containerW}); 8182 if ( $('body.hmenu-center-double').length ) { 8183 leftPos = '0px'; 8184 } else { 8185 if ( $('body.hmenu-center-split').length > 0 && !$sub.closest('.navbar-cta').length && ! $('body.hormenu-position-right').length ) { 8186 leftPos = - ($sub.closest('.menu-primary-inner')[0].offsetLeft) + 'px'; 8187 } else { 8188 if ( $sub.closest('.navbar-cta').length && !$('body.hmenu').length && !$('body.hmenu-center').length ) { 8189 leftPos = - ( parseFloat($sub.closest('.navbar-cta').offset().left) - parseFloat($sub.closest('.row-menu-inner').find('.logo-container').offset().left) ) + 'px'; 8190 } else if ($sub.closest('.row-menu-inner').find('.logo-container').length > 0 && !$('body.hmenu-center-split').length) { 8191 leftPos = - (parseFloat($sub.closest('.row-menu-inner').find('.logo-container').css('paddingRight')) + ($sub.closest('.row-menu-inner').find('.logo-container').width())) + 'px'; 8192 } else { 8193 leftPos = '0px'; 8194 } 8195 } 8196 } 8197 } else { 8198 leftPos = (level > 2 ? $li.position().left - parseFloat($li.closest('ul').css('paddingLeft')) : $li.position().left ) + 'px'; 8199 x = (level > 2 && x >= 0) ? x + (parseFloat($li.closest('ul').css('paddingLeft')) * 2) + 1 : x - 1; 8200 } 8201 8202 $sub.css({ top: (level > 2) ? $a[0].offsetTop : (fixIE ? itemH : '100%'), left: leftPos, marginLeft: x, marginTop: (level > 2) ? 0 : y - itemH + ($sub.closest('.menu-mini').length ? 0 : 1) }); 8203 // IE iframe shim 8204 this.menuIframeShim($sub); 8205 if ($sub.dataSM('ie-shim')) { 8206 $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) }); 8207 } 8208 }, 8209 menuScroll: function($sub, up, wheel) { 8210 var y = parseFloat($sub.css('margin-top')), 8211 scroll = $sub.dataSM('scroll'), 8212 end = scroll.vportY + (up ? 0 : scroll.winH - scroll.subH), 8213 step = wheel || !this.opts.scrollAccelerate ? this.opts.scrollStep : Math.floor($sub.dataSM('scroll').step); 8214 $sub.add($sub.dataSM('ie-shim')).css('margin-top', Math.abs(end - y) > step ? y + (up ? step : -step) : end); 8215 y = parseFloat($sub.css('margin-top')); 8216 // show opposite arrow if appropriate 8217 if (up && y + scroll.subH > scroll.vportY + scroll.winH || !up && y < scroll.vportY) { 8218 $sub.dataSM('scroll-arrows').eq(up ? 1 : 0).show(); 8219 } 8220 // accelerate when not using mousewheel to scroll 8221 if (!wheel && this.opts.scrollAccelerate && $sub.dataSM('scroll').step < this.opts.scrollStep) { 8222 $sub.dataSM('scroll').step += 0.5; 8223 } 8224 // "y" and "end" might be float numbers in IE9/FF4+ so this weird way to check is used 8225 if (Math.abs(y - end) < 1) { 8226 $sub.dataSM('scroll-arrows').eq(up ? 0 : 1).hide(); 8227 $sub.dataSM('scroll').step = 1; 8228 } else if (!wheel) { 8229 var self = this; 8230 this.scrollTimeout = setTimeout(function() { self.menuScroll($sub, up); }, this.opts.scrollInterval); 8231 } 8232 }, 8233 menuScrollMousewheel: function($sub, e) { 8234 var $closestSub = $(e.target).closest('ul'); 8235 while ($closestSub.dataSM('in-mega')) { 8236 $closestSub = $closestSub.parent().closest('ul'); 8237 } 8238 if ($closestSub[0] == $sub[0]) { 8239 var up = (e.originalEvent.wheelDelta || -e.originalEvent.detail) > 0; 8240 if ($sub.dataSM('scroll-arrows').eq(up ? 0 : 1).is(':visible')) { 8241 this.menuScroll($sub, up, true); 8242 } 8243 } 8244 e.preventDefault(); 8245 }, 8246 menuScrollOut: function($sub, e) { 8247 var reClass = /^scroll-(up|down)/, 8248 $closestSub = $(e.relatedTarget).closest('ul'); 8249 while ($closestSub.dataSM('in-mega')) { 8250 $closestSub = $closestSub.parent().closest('ul'); 8251 } 8252 if (!reClass.test((e.relatedTarget || '').className) && ($sub[0] != e.relatedTarget && !$.contains($sub[0], e.relatedTarget) || $closestSub[0] != $sub[0])) { 8253 $sub.dataSM('scroll-arrows').css('visibility', 'hidden'); 8254 } 8255 }, 8256 menuScrollOver: function($sub, e) { 8257 var reClass = /^scroll-(up|down)/, 8258 $closestSub = $(e.target).closest('ul'); 8259 while ($closestSub.dataSM('in-mega')) { 8260 $closestSub = $closestSub.parent().closest('ul'); 8261 } 8262 if (!reClass.test(e.target.className) && $closestSub[0] == $sub[0]) { 8263 $sub.dataSM('scroll-arrows').css('visibility', 'visible'); 8264 } 8265 }, 8266 menuScrollStop: function($sub) { 8267 if (this.scrollTimeout) { 8268 clearTimeout(this.scrollTimeout); 8269 this.scrollTimeout = 0; 8270 $sub.dataSM('scroll').step = 1; 8271 } 8272 }, 8273 menuShow: function($sub) { 8274 if (!$sub.dataSM('beforefirstshowfired')) { 8275 $sub.dataSM('beforefirstshowfired', true); 8276 if (this.$root.triggerHandler('beforefirstshow.smapi', $sub[0]) === false) { 8277 return; 8278 } 8279 } 8280 if (this.$root.triggerHandler('beforeshow.smapi', $sub[0]) === false) { 8281 return; 8282 } 8283 this.menuFixLayout($sub); 8284 $sub.stop(true, true); 8285 if (!$sub.is(':visible')) { 8286 // set z-index - for IE < 9 set it to the parent LI
8287 var zIndex = this.getStartZIndex() + (++this.zIndexInc); 8288 if (IElt9) { 8289 $sub.parent().css('z-index', zIndex); 8290 } else { 8291 $sub.css('z-index', zIndex); 8292 } 8293 // highlight parent item 8294 if (this.opts.keepHighlighted || this.isCollapsible()) { 8295 if ($sub.dataSM('parent-a').attr('data-type') != 'title') 8296 $sub.dataSM('parent-a').addClass('highlighted'); 8297 } 8298 // min/max-width fix - no way to rely purely on CSS as all UL's are nested 8299 if (this.opts.subMenusMinWidth || this.opts.subMenusMaxWidth) { 8300 if (!IElt8) { 8301 $sub.css({ width: ($sub.hasClass('mega-menu-inner')) ? $('.box-container').outerWidth() + 'px' : 'auto', minWidth: '', maxWidth: '' }).addClass('sm-nowrap'); 8302 if (this.opts.subMenusMinWidth) { 8303 $sub.css('min-width', this.opts.subMenusMinWidth); 8304 } 8305 if (this.opts.subMenusMaxWidth) { 8306 var noMaxWidth = this.getWidth($sub); 8307 $sub.css('max-width', this.opts.subMenusMaxWidth); 8308 if (noMaxWidth > this.getWidth($sub)) { 8309 $sub.removeClass('sm-nowrap').css('width', this.opts.subMenusMaxWidth); 8310 } 8311 } 8312 // IE6,7 8313 } else { 8314 $sub.children().css('styleFloat', 'none'); 8315 if (IE6) { 8316 $sub.width(this.opts.subMenusMinWidth ? this.opts.subMenusMinWidth : 1) 8317 .children().children('a').css('white-space', 'nowrap'); 8318 } else { // IE7 8319 $sub.css({ width: ($sub.hasClass('mega-menu-inner')) ? $('.box-container').outerWidth() + 'px' : 'auto', minWidth: '', maxWidth: '' }).addClass('sm-nowrap'); 8320 if (this.opts.subMenusMinWidth) { 8321 $sub.css('min-width', this.opts.subMenusMinWidth); 8322 } 8323 } 8324 if (this.opts.subMenusMaxWidth) { 8325 var noMaxWidth = $sub.width(); 8326 if (IE6) { 8327 var maxWidth = $sub.css({ width: this.opts.subMenusMaxWidth, overflowX: 'hidden', overflowY: 'hidden' }).width(); 8328 if (noMaxWidth > maxWidth) { 8329 $sub.css({ width: maxWidth, overflowX: 'visible', overflowY: 'visible' }).children().children('a').css('white-space', ''); 8330 } else { 8331 $sub.css({ width: noMaxWidth, overflowX: 'visible', overflowY: 'visible' }); 8332 } 8333 } else { // IE7 8334 $sub.css('max-width', this.opts.subMenusMaxWidth); 8335 if (noMaxWidth > $sub.width()) { 8336 $sub.removeClass('sm-nowrap').css('width', this.opts.subMenusMaxWidth); 8337 } else { 8338 $sub.width(noMaxWidth); 8339 } 8340 } 8341 } else { 8342 $sub.width($sub.width()); 8343 } 8344 $sub.children().css('styleFloat', 'left'); 8345 } 8346 } 8347 this.menuPosition($sub); 8348 // insert IE iframe shim 8349 if ($sub.dataSM('ie-shim')) { 8350 $sub.dataSM('ie-shim').insertBefore($sub); 8351 } 8352 var complete = function() { 8353 // fix: "overflow: hidden;" is not reset on animation complete in jQuery < 1.9.0 in Chrome when global "box-sizing: border-box;" is used 8354 $sub.css('overflow', ''); 8355 }; 8356 // if sub is collapsible (mobile view) 8357 if (this.isCollapsible()) { 8358 if (this.opts.collapsibleShowFunction) { 8359 this.opts.collapsibleShowFunction.call(this, $sub, complete); 8360 } else { 8361 $sub.show(this.opts.collapsibleShowDuration, complete); 8362 } 8363 } else { 8364 if (this.opts.showFunction) { 8365 this.opts.showFunction.call(this, $sub, complete); 8366 } else { 8367 $sub.show(this.opts.showDuration, complete); 8368 } 8369 } 8370 // save new sub menu for this level 8371 this.visibleSubMenus[$sub.dataSM('level') - 1] = $sub; 8372 this.$root.triggerHandler('show.smapi', $sub[0]); 8373 } 8374 }, 8375 popupHide: function(noHideTimeout) { 8376 if (this.hideTimeout) { 8377 clearTimeout(this.hideTimeout); 8378 this.hideTimeout = 0; 8379 } 8380 var self = this; 8381 this.hideTimeout = setTimeout(function() { 8382 self.menuHideAll(); 8383 }, noHideTimeout ? 1 : this.opts.hideTimeout); 8384 }, 8385 popupShow: function(left, top) { 8386 if (!this.opts.isPopup) { 8387 alert('SmartMenus jQuery Error:\n\nIf you want to show this menu via the "popupShow" method, set the isPopup:true option.'); 8388 return; 8389 } 8390 if (this.hideTimeout) { 8391 clearTimeout(this.hideTimeout); 8392 this.hideTimeout = 0; 8393 } 8394 this.menuFixLayout(this.$root); 8395 this.$root.stop(true, true); 8396 if (!this.$root.is(':visible')) { 8397 this.$root.css({ left: left, top: top }); 8398 // IE iframe shim 8399 this.menuIframeShim(this.$root); 8400 if (this.$root.dataSM('ie-shim')) { 8401 this.$root.dataSM('ie-shim').css({ zIndex: this.$root.css('z-index'), width: this.getWidth(this.$root), height: this.getHeight(this.$root), left
8401: left, top: top }).insertBefore(this.$root); 8402 } 8403 // show menu 8404 if (this.opts.showFunction) { 8405 this.opts.showFunction.call(this, this.$root); 8406 } else { 8407 this.$root.show(this.opts.showDuration); 8408 } 8409 this.visibleSubMenus[0] = this.$root; 8410 } 8411 }, 8412 refresh: function() { 8413 this.menuHideAll(); 8414 this.$root.find('ul').each(function() { 8415 var $this = $(this); 8416 if ($this.dataSM('scroll-arrows')) { 8417 $this.dataSM('scroll-arrows').remove(); 8418 } 8419 }) 8420 .removeDataSM('in-mega') 8421 .removeDataSM('shown-before') 8422 .removeDataSM('ie-shim') 8423 .removeDataSM('scroll-arrows') 8424 .removeDataSM('parent-a') 8425 .removeDataSM('level') 8426 .removeDataSM('beforefirstshowfired'); 8427 this.$root.find('a.has-submenu').removeClass('has-submenu') 8428 .parent().removeDataSM('sub'); 8429 if (this.opts.subIndicators) { 8430 this.$root.find('span.sub-arrow').remove(); 8431 } 8432 if (this.opts.markCurrentItem) { 8433 this.$root.find('a.current').removeClass('current'); 8434 } 8435 this.subMenus = []; 8436 this.init(true); 8437 }, 8438 rootOut: function(e) { 8439 if (!this.handleEvents() || this.isTouchMode() || e.target == this.$root[0]) { 8440 return; 8441 } 8442 if (this.hideTimeout) { 8443 clearTimeout(this.hideTimeout); 8444 this.hideTimeout = 0; 8445 } 8446 if (!this.opts.showOnClick || !this.opts.hideOnClick) { 8447 var self = this; 8448 this.hideTimeout = setTimeout(function() { self.menuHideAll(); }, this.opts.hideTimeout); 8449 } 8450 }, 8451 rootOver: function(e) { 8452 if (!this.handleEvents() || this.isTouchMode() || e.target == this.$root[0]) { 8453 return; 8454 } 8455 if (this.hideTimeout) { 8456 clearTimeout(this.hideTimeout); 8457 this.hideTimeout = 0; 8458 } 8459 }, 8460 winResize: function(e) { 8461 if (!this.handleEvents()) { 8462 // we still need to resize the disable overlay if it's visible 8463 if (this.$disableOverlay) { 8464 var pos = this.$root.offset(); 8465 this.$disableOverlay.css({ 8466 top: pos.top, 8467 left: pos.left, 8468 width: this.$root.outerWidth(), 8469 height: this.$root.outerHeight() 8470 }); 8471 } 8472 return; 8473 } 8474 // hide sub menus on resize - on mobile do it only on orientation change 8475 if (!this.isCollapsible() && (!('onorientationchange' in window) || e.type == 'orientationchange')) { 8476 if (this.activatedItems.length) { 8477 this.activatedItems[this.activatedItems.length - 1][0].blur(); 8478 } 8479 this.menuHideAll(); 8480 } 8481 } 8482 } 8483 }); 8484 8485 $.fn.dataSM = function(key, val) { 8486 if (val) { 8487 return this.data(key + '_smartmenus', val); 8488 } 8489 return this.data(key + '_smartmenus'); 8490 } 8491 8492 $.fn.removeDataSM = function(key) { 8493 return this.removeData(key + '_smartmenus'); 8494 } 8495 8496 $.fn.smartmenus = function(options) { 8497 if (typeof options == 'string') { 8498 var args = arguments, 8499 method = options; 8500 Array.prototype.shift.call(args); 8501 return this.each(function() { 8502 var smartmenus = $(this).data('smartmenus'); 8503 if (smartmenus && smartmenus[method]) { 8504 smartmenus[method].apply(smartmenus, args); 8505 } 8506 }); 8507 } 8508 var opts = $.extend({}, $.fn.smartmenus.defaults, options); 8509 return this.each(function() { 8510 new $.SmartMenus(this, opts); 8511 }); 8512 } 8513 8514 // default settings 8515 $.fn.smartmenus.defaults = { 8516 isPopup: false, // is this a popup menu (can be shown via the popupShow/popupHide methods) or a permanent menu bar 8517 mainMenuSubOffsetX: 0, // pixels offset from default position
8518 mainMenuSubOffsetY: 0, // pixels offset from default position 8519 subMenusSubOffsetX: 0, // pixels offset from default position 8520 subMenusSubOffsetY: 0, // pixels offset from default position 8521 subMenusMinWidth: '10em', // min-width for the sub menus (any CSS unit) - if set, the fixed width set in CSS will be ignored 8522 subMenusMaxWidth: '20em', // max-width for the sub menus (any CSS unit) - if set, the fixed width set in CSS will be ignored 8523 subIndicators: true, // create sub menu indicators - creates a SPAN and inserts it in the A 8524 subIndicatorsPos: 'prepend', // position of the SPAN relative to the menu item content ('prepend', 'append') 8525 subIndicatorsText: '+', // [optionally] add text in the SPAN (e.g. '+') (you may want to check the CSS for the sub indicators too) 8526 scrollStep: 30, // pixels step when scrolling long sub menus that do not fit in the viewport height 8527 scrollInterval: 30, // interval between each scrolling step 8528 scrollAccelerate: true, // accelerate scrolling or use a fixed step 8529 showTimeout: 250, // timeout before showing the sub menus 8530 hideTimeout: 500, // timeout before hiding the sub menus 8531 showDuration: 0, // duration for show animation - set to 0 for no animation - matters only if showFunction:null 8532 showFunction: null, // custom function to use when showing a sub menu (the default is the jQuery 'show') 8533 // don't forget to call complete() at the end of whatever you do 8534 // e.g.: function($ul, complete) { $ul.fadeIn(250, complete); } 8535 hideDuration: 0, // duration for hide animation - set to 0 for no animation - matters only if hideFunction:null 8536 hideFunction: function($ul, complete) { $ul.fadeOut(200, complete); }, // custom function to use when hiding a sub menu (the default is the jQuery 'hide') 8537 // don't forget to call complete() at the end of whatever you do 8538 // e.g.: function($ul, complete) { $ul.fadeOut(250, complete); } 8539 collapsibleShowDuration:0, // duration for show animation for collapsible sub menus - matters only if collapsibleShowFunction:null 8540 collapsibleShowFunction:function($ul, complete) { $ul.slideDown(200, complete); }, // custom function to use when showing a collapsible sub menu 8541 // (i.e. when mobile styles are used to make the sub menus collapsible) 8542 collapsibleHideDuration:0, // duration for hide animation for collapsible sub menus - matters only if collapsibleHideFunction:null 8543 collapsibleHideFunction:function($ul, complete) { $ul.slideUp(200, complete); }, // custom function to use when hiding a collapsible sub menu 8544 // (i.e. when mobile styles are used to make the sub menus collapsible) 8545 showOnClick: false, // show the first-level sub menus onclick instead of onmouseover (matters only for mouse input) 8546 hideOnClick: true, // hide the sub menus on click/tap anywhere on the page 8547 keepInViewport: true, // reposition the sub menus if needed to make sure they always appear inside the viewport 8548 keepHighlighted: true, // keep all ancestor items of the current sub menu highlighted (adds the 'highlighted' class to the A's) 8549 markCurrentItem: false, // automatically add the 'current' class to the A element of the item linking to the current URL 8550 markCurrentTree: true, // add the 'current' class also to the A elements of all ancestor items of the current item 8551 rightToLeftSubMenus: false, // right to left display of the sub menus (check the CSS for the sub indicators' position) 8552 bottomToTopSubMenus: false, // bottom to top display of the sub menus 8553 overlapControlsInIE: true // make sure sub menus appear on top of special OS controls in IE (i.e. SELECT, OBJECT, EMBED, etc.) 8554 }; 8555 8556})(jQuery); 8557 8558/* 8559 * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/ 8560 * 8561 * Uses the built in easing capabilities added In jQuery 1.1 8562 * to offer multiple easing options 8563 * 8564 * TERMS OF USE - jQuery Easing 8565 * 8566 * Open source under the BSD License. 8567 * 8568 * Copyright © 2008 George McGinley Smith 8569 * All rights reserved. 8570 * 8571 * Redistribution and use in source and binary forms, with or without modification, 8572 * are permitted provided that the following conditions are met: 8573 * 8574 * Redistributions of source code must retain the above copyright notice, this list of 8575 * conditions and the following disclaimer. 8576 * Redistributions in binary form must reproduce the above copyright notice, this list 8577 * of conditions and the following disclaimer in the documentation and/or other materials 8578 * provided with the distribution. 8579 * 8580 * Neither the name of the author nor the names of contributors may be used to endorse 8581 * or promote products derived from this software without specific prior written permission. 8582 * 8583 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 8584 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 8585 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 8586 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
vendor: 5,091 bytes, lines 8587-8732
8587 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 8588 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 8589 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 8590 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 8591 * OF THE POSSIBILITY OF SUCH DAMAGE. 8592 * 8593*/ 8594 8595// t: current time, b: begInnIng value, c: change In value, d: duration 8596jQuery.easing['jswing'] = jQuery.easing['swing']; 8597 8598jQuery.extend( jQuery.easing, 8599{ 8600 def: 'easeOutQuad', 8601 swing: function (x, t, b, c, d) { 8602 //alert(jQuery.easing.default); 8603 return jQuery.easing[jQuery.easing.def](x, t, b, c, d); 8604 }, 8605 easeInQuad: function (x, t, b, c, d) { 8606 return c*(t/=d)*t + b; 8607 }, 8608 easeOutQuad: function (x, t, b, c, d) { 8609 return -c *(t/=d)*(t-2) + b; 8610 }, 8611 easeInOutQuad: function (x, t, b, c, d) { 8612 if ((t/=d/2) < 1) return c/2*t*t + b; 8613 return -c/2 * ((--t)*(t-2) - 1) + b; 8614 }, 8615 easeInCubic: function (x, t, b, c, d) { 8616 return c*(t/=d)*t*t + b; 8617 }, 8618 easeOutCubic: function (x, t, b, c, d) { 8619 return c*((t=t/d-1)*t*t + 1) + b; 8620 }, 8621 easeInOutCubic: function (x, t, b, c, d) { 8622 if ((t/=d/2) < 1) return c/2*t*t*t + b; 8623 return c/2*((t-=2)*t*t + 2) + b; 8624 }, 8625 easeInQuart: function (x, t, b, c, d) { 8626 return c*(t/=d)*t*t*t + b; 8627 }, 8628 easeOutQuart: function (x, t, b, c, d) { 8629 return -c * ((t=t/d-1)*t*t*t - 1) + b; 8630 }, 8631 easeInOutQuart: function (x, t, b, c, d) { 8632 if ((t/=d/2) < 1) return c/2*t*t*t*t + b; 8633 return -c/2 * ((t-=2)*t*t*t - 2) + b; 8634 }, 8635 easeInQuint: function (x, t, b, c, d) { 8636 return c*(t/=d)*t*t*t*t + b; 8637 }, 8638 easeOutQuint: function (x, t, b, c, d) { 8639 return c*((t=t/d-1)*t*t*t*t + 1) + b; 8640 }, 8641 easeInOutQuint: function (x, t, b, c, d) { 8642 if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b; 8643 return c/2*((t-=2)*t*t*t*t + 2) + b; 8644 }, 8645 easeInSine: function (x, t, b, c, d) { 8646 return -c * Math.cos(t/d * (Math.PI/2)) + c + b; 8647 }, 8648 easeOutSine: function (x, t, b, c, d) { 8649 return c * Math.sin(t/d * (Math.PI/2)) + b; 8650 }, 8651 easeInOutSine: function (x, t, b, c, d) { 8652 return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b; 8653 }, 8654 easeInExpo: function (x, t, b, c, d) { 8655 return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b; 8656 }, 8657 easeOutExpo: function (x, t, b, c, d) { 8658 return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b; 8659 }, 8660 easeInOutExpo: function (x, t, b, c, d) { 8661 if (t==0) return b; 8662 if (t==d) return b+c; 8663 if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b; 8664 return c/2 * (-Math.pow(2, -10 * --t) + 2) + b; 8665 }, 8666 easeInCirc: function (x, t, b, c, d) { 8667 return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b; 8668 }, 8669 easeOutCirc: function (x, t, b, c, d) { 8670 return c * Math.sqrt(1 - (t=t/d-1)*t) + b; 8671 }, 8672 easeInOutCirc: function (x, t, b, c, d) { 8673 if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b; 8674 return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b; 8675 }, 8676 easeInElastic: function (x, t, b, c, d) { 8677 var s=1.70158;var p=0;var a=c; 8678 if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; 8679 if (a < Math.abs(c)) { a=c; var s=p/4; } 8680 else var s = p/(2*Math.PI) * Math.asin (c/a); 8681 return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; 8682 }, 8683 easeOutElastic: function (x, t, b, c, d) { 8684 var s=1.70158;var p=0;var a=c; 8685 if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; 8686 if (a < Math.abs(c)) { a=c; var s=p/4; } 8687 else var s = p/(2*Math.PI) * Math.asin (c/a); 8688 return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b; 8689 }, 8690 easeInOutElastic: function (x, t, b, c, d) { 8691 var s=1.70158;var p=0;var a=c; 8692 if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5); 8693 if (a < Math.abs(c)) { a=c; var s=p/4; } 8694 else var s = p/(2*Math.PI) * Math.asin (c/a); 8695 if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; 8696 return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b; 8697 }, 8698 easeInBack: function (x, t, b, c, d, s) { 8699 if (s == undefined) s = 1.70158; 8700 return c*(t/=d)*t*((s+1)*t - s) + b; 8701 }, 8702 easeOutBack: function (x, t, b, c, d, s) { 8703 if (s == undefined) s = 1.70158; 8704 return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b; 8705 }, 8706 easeInOutBack: function (x, t, b, c, d, s) { 8707 if (s == undefined) s = 1.70158; 8708 if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b; 8709 return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b; 8710 }, 8711 easeInBounce: function (x, t, b, c, d) { 8712 return c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d) + b; 8713 }, 8714 easeOutBounce: function (x, t, b, c, d) { 8715 if ((t/=d) < (1/2.75)) { 8716 return c*(7.5625*t*t) + b; 8717 } else if (t < (2/2.75)) { 8718 return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b; 8719 } else if (t < (2.5/2.75)) { 8720 return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b; 8721 } else { 8722 return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b; 8723 } 8724 }, 8725 easeInOutBounce: function (x, t, b, c, d) { 8726 if (t < d/2) return jQuery.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b; 8727 return jQuery.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b; 8728 } 8729}); 8730 8731/* 8732 *
8733 * TERMS OF USE - EASING EQUATIONS 8734 * 8735 * Open source under the BSD License. 8736 * 8737 * Copyright © 2001 Robert Penner 8738 * All rights reserved. 8739 * 8740 * Redistribution and use in source and binary forms, with or without modification, 8741 * are permitted provided that the following conditions are met: 8742 * 8743 * Redistributions of source code must retain the above copyright notice, this list of 8744 * conditions and the following disclaimer. 8745 * Redistributions in binary form must reproduce the above copyright notice, this list 8746 * of conditions and the following disclaimer in the documentation and/or other materials 8747 * provided with the distribution. 8748 * 8749 * Neither the name of the author nor the names of contributors may be used to endorse 8750 * or promote products derived from this software without specific prior written permission. 8751 * 8752 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 8753 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 8754 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 8755 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 8756 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 8757 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 8758 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 8759 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 8760 * OF THE POSSIBILITY OF SUCH DAMAGE. 8761 * 8762 */ 8763(function($, window, undefined) { 8764 // http://paulirish.com/2011/requestanimationframe-for-smart-animating/ 8765 // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating 8766 8767 // requestAnimationFrame polyfill by Erik Möller 8768 // fixes from Paul Irish and Tino Zijdel 8769 8770 var lastTime = 0, 8771 running, 8772 animate = function (elem) { 8773 if (running) { 8774 window.requestAnimationFrame(animate, elem); 8775 jQuery.fx.tick(); 8776 } 8777 }, 8778 vendors = ['ms', 'moz', 'webkit', 'o']; 8779 8780 for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { 8781 window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame']; 8782 window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] 8783 || window[vendors[x]+'CancelRequestAnimationFrame']; 8784 } 8785 8786 if (!window.requestAnimationFrame) 8787 window.requestAnimationFrame = function(fn, element) { 8788 var currTime = new Date().getTime(), 8789 delta = currTime - lastTime, 8790 timeToCall = Math.max(0, 16 - delta); 8791 8792 var id = window.setTimeout(function() { 8793 fn(currTime + timeToCall); 8794 }, 8795 timeToCall 8796 ); 8797 8798 lastTime = currTime + timeToCall; 8799 8800 return id; 8801 }; 8802 8803 if (!window.cancelAnimationFrame) { 8804 window.cancelAnimationFrame = function(id) { 8805 clearTimeout(id); 8806 }; 8807 } 8808 8809 jQuery.fx.timer = function (timer) { 8810 if (timer() && jQuery.timers.push(timer) && !running) { 8811 running = true; 8812 animate(timer.elem); 8813 } 8814 }; 8815 8816 jQuery.fx.stop = function() { 8817 running = false; 8818 }; 8819 8820}(jQuery, this)); 8821/*! Copyright (c) 2011 Brandon Aaron (http://brandonaaron.net) 8822 * Licensed under the MIT License (LICENSE.txt). 8823 * 8824 * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers. 8825 * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix. 8826 * Thanks to: Seamus Leahy for adding deltaX and deltaY 8827 * 8828 * Version: 3.0.6 8829 * 8830 * Requires: 1.2.2+ 8831 */ 8832(function($) { 8833 var types = ['DOMMouseScroll', 'mousewheel']; 8834 if ($.event.fixHooks) { 8835 for (var i = types.length; i;) { 8836 $.event.fixHooks[types[--i]] = $.event.mouseHooks; 8837 } 8838 } 8839 $.event.special.mousewheel = { 8840 setup: function() { 8841 if (this.addEventListener) { 8842 for (var i = types.length; i;) { 8843 this.addEventListener(types[--i], handler, false); 8844 } 8845 } else { 8846 this.onmousewheel = handler; 8847 } 8848 }, 8849 teardown: function() { 8850 if (this.removeEventListener) { 8851 for (var i = types.length; i;) { 8852 this.removeEventListener(types[--i], handler, false); 8853 } 8854 } else { 8855 this.onmousewheel = null; 8856 } 8857 } 8858 }; 8859 $.fn.extend({ 8860 mousewheel: function(fn) { 8861 return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel"); 8862 }, 8863 unmousewheel: function(fn) { 8864 return this.unbind("mousewheel", fn); 8865 } 8866 }); 8867 8868 function handler(event) { 8869 var orgEvent = event || window.event, 8870 args = [].slice.call(arguments, 1), 8871 delta = 0, 8872 returnValue = true, 8873 deltaX = 0, 8874 deltaY = 0; 8875 event = $.event.fix(orgEvent); 8876 event.type = "mousewheel"; 8877 // Old school scrollwheel delta 8878 if (orgEvent.wheelDelta) { 8879 delta = orgEvent.wheelDelta / 120; 8880 } 8881 if (orgEvent.detail) { 8882 delta = -orgEvent.detail / 3; 8883 } 8884 // New school multidimensional scroll (touchpads) deltas 8885 deltaY = delta; 8886 // Gecko 8887 if (orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS) { 8888 deltaY = 0; 8889 deltaX = -1 * delta; 8890 } 8891 // Webkit 8892 if (orgEvent.wheelDeltaY !== undefined) { 8893 deltaY = orgEvent.wheelDeltaY / 120; 8894 } 8895 if (orgEvent.wheelDeltaX !== undefined) { 8896 deltaX = -1 * orgEvent.wheelDeltaX / 120; 8897 } 8898 // Add event and delta to the front of the arguments 8899 args.unshift(event, delta, deltaX, deltaY); 8900 return ($.event.dispatch || $.event.handle).apply(this, args); 8901 } 8902})(jQuery); 8903/** 8904 * jQuery iLightBox - Revolutionary Lightbox Plugin 8905 * http://www.ilightbox.net/ 8906 * 8907 * @version: 2.2.4 - October 14, 2017 8908 * 8909 * @author: iProDev (Hemn Chawroka) 8910 * http://www.iprodev.com/ 8911 * 8912 */ 8913(function($, window, undefined) { 8914 8915 var extensions = { 8916 flash: ['swf'], 8917 image: ['bmp', 'gif', 'jpeg', 'jpg', 'png', 'tiff', 'tif', 'jfif', 'jpe'], 8918 iframe: ['asp', 'aspx', 'cgi', 'cfm', 'htm', 'html', 'jsp', 'php', 'pl', 'php3', 'php4', 'php5', 'phtml', 'rb', 'rhtml', 'shtml', 'txt'], 8919 video: ['avi', 'mov', 'mpg', 'mpeg', 'movie', 'mp4', 'webm', 'ogv', 'ogg', '3gp', 'm4v'] 8920 }, 8921 8922 // Global DOM elements 8923 $win = $(window), 8924 $doc = $(document), 8925
8926 // Support indicators 8927 browser, 8928 transform, 8929 gpuAcceleration, 8930 fullScreenApi = '', 8931 userAgent = navigator.userAgent || navigator.vendor || window.opera, 8932 supportTouch = !!('ontouchstart' in window) && (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent)), 8933 isMobile = /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(userAgent) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(userAgent.substr(0, 4)), 8934 8935 // Events 8936 clickEvent = supportTouch ? "itap.iLightBox" : "click.iLightBox", 8937 touchStartEvent = supportTouch ? "touchstart.iLightBox" : "mousedown.iLightBox", 8938 touchStopEvent = supportTouch ? "touchend.iLightBox" : "mouseup.iLightBox", 8939 touchMoveEvent = supportTouch ? "touchmove.iLightBox" : "mousemove.iLightBox", 8940 8941 // Math shorthands 8942 abs = Math.abs, 8943 sqrt = Math.sqrt, 8944 round = Math.round, 8945 max = Math.max, 8946 min = Math.min, 8947 floor = Math.floor, 8948 random = Math.random, 8949 8950 pluginspages = { 8951 quicktime: 'http://www.apple.com/quicktime/download', 8952 flash: 'http://www.adobe.com/go/getflash' 8953 }, 8954 8955 iLightBox = function(el, options, items, instant) { 8956 var iL = this; 8957 8958 iL.options = options, 8959 iL.selector = el.selector || el, 8960 iL.context = el.context, 8961 iL.instant = instant; 8962 8963 if (items.length < 1) iL.attachItems(); 8964 else iL.items = items; 8965 8966 iL.vars = { 8967 total: iL.items.length, 8968 start: 0, 8969 current: null, 8970 next: null, 8971 prev: null, 8972 BODY: $('body'), 8973 loadRequests: 0, 8974 overlay: $('<div class="ilightbox-overlay"></div>'), 8975 loader: $('<div class="ilightbox-loader"><div></div></div>'), 8976 toolbar: $('<div class="ilightbox-toolbar"></div>'), 8977 innerToolbar: $('<div class="ilightbox-inner-toolbar"></div>'), 8978 title: $('<div class="ilightbox-title"></div>'), 8979 closeButton: $('<a class="ilightbox-close" title="' + iL.options.text.close + '"></a>'), 8980 fullScreenButton: $('<a class="ilightbox-fullscreen" title="' + iL.options.text.enterFullscreen + '"></a>'), 8981 innerPlayButton: $('<a class="ilightbox-play" title="' + iL.options.text.slideShow + '"></a>'), 8982 innerNextButton: $('<a class="ilightbox-next-button" title="' + iL.options.text.next + '"></a>'), 8983 innerPrevButton: $('<a class="ilightbox-prev-button" title="' + iL.options.text.previous + '"></a>'), 8984 holder: $('<div class="ilightbox-holder' + (supportTouch ? ' supportTouch' : '') + '" ondragstart="return false;"><div class="ilightbox-container"></div></div>'), 8985 nextPhoto: $('<div class="ilightbox-holder' + (supportTouch ? ' supportTouch' : '') + ' ilightbox-next" ondragstart="return false;"><div class="ilightbox-container"></div></div>'), 8986 prevPhoto: $('<div class="ilightbox-holder' + (supportTouch ? ' supportTouch' : '') + ' ilightbox-prev" ondragstart="return false;"><div class="ilightbox-container"></div></div>'), 8987 nextButton: $('<a class="ilightbox-button ilightbox-next-button" ondragstart="return false;" title="' + iL.options.text.next + '"><span></span></a>'), 8988 prevButton: $('<a class="ilightbox-button ilightbox-prev-button" ondragstart="return false;" title="' + iL.options.text.previous + '"><span></span></a>'),
8989 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>'), 8990 thumbs: false, 8991 nextLock: false, 8992 prevLock: false, 8993 hashLock: false, 8994 isMobile: false, 8995 mobileMaxWidth: 980, 8996 isInFullScreen: false, 8997 isSwipe: false, 8998 mouseID: 0, 8999 cycleID: 0, 9000 isPaused: 0, 9001 captionHeight: 39, 9002 }; 9003 9004 // Hideable elements with mousemove event 9005 iL.vars.hideableElements = iL.vars.nextButton.add(iL.vars.prevButton); 9006 9007 iL.normalizeItems(); 9008 9009 //Check necessary plugins 9010 iL.availPlugins(); 9011 9012 //Set startFrom 9013 iL.options.startFrom = (iL.options.startFrom > 0 && iL.options.startFrom >= iL.vars.total) ? iL.vars.total - 1 : iL.options.startFrom; 9014 9015 //If randomStart 9016 iL.options.startFrom = (iL.options.randomStart) ? floor(random() * iL.vars.total) : iL.options.startFrom; 9017 iL.vars.start = iL.options.startFrom; 9018 9019 if (instant) iL.instantCall(); 9020 else iL.patchItemsEvents(); 9021 9022 if (iL.options.linkId) { 9023 iL.hashChangeHandler(); 9024 $win.iLightBoxHashChange(function() { 9025 iL.hashChangeHandler(); 9026 }); 9027 } 9028 9029 if (supportTouch) { 9030 var RegExp = /(click|mouseenter|mouseleave|mouseover|mouseout)/ig, 9031 replace = "itap"; 9032 iL.options.caption.show = iL.options.caption.show.replace(RegExp, replace), 9033 iL.options.caption.hide = iL.options.caption.hide.replace(RegExp, replace), 9034 iL.options.social.show = iL.options.social.show.replace(RegExp, replace), 9035 iL.options.social.hide = iL.options.social.hide.replace(RegExp, replace); 9036 } 9037 9038 if (iL.options.controls.arrows || $(window).width() < UNCODE.mediaQuery) { 9039 $.extend(iL.options.styles, { 9040 nextOffsetX: ($(window).width() > UNCODE.mediaQuery) ? 36 : 4, 9041 prevOffsetX: ($(window).width() > UNCODE.mediaQuery) ? 36 : 4, 9042 nextOpacity: 0, 9043 prevOpacity: 0 9044 }); 9045 } 9046 }; 9047 9048 //iLightBox helpers 9049 iLightBox.prototype = { 9050 showLoader: function() { 9051 var iL = this; 9052 iL.vars.loadRequests += 1; 9053 if (iL.options.path.toLowerCase() == "horizontal") iL.vars.loader.addClass('ilightbox-show').stop().animate({ 9054 //top: '-30px' 9055 opacity: '1' 9056 }, iL.options.show.speed, 'easeOutCirc'); 9057 else iL.vars.loader.addClass('ilightbox-show').stop().animate({ 9058 //left: '-30px' 9059 opacity: '1' 9060 }, iL.options.show.speed, 'easeOutCirc'); 9061 }, 9062 9063 hideLoader: function() { 9064 var iL = this; 9065 iL.vars.loadRequests -= 1; 9066 iL.vars.loadRequests = (iL.vars.loadRequests < 0) ? 0 : iL.vars.loadRequests; 9067 if (iL.options.path.toLowerCase() == "horizontal") { 9068 if (iL.vars.loadRequests <= 0) iL.vars.loader.removeClass('ilightbox-show').stop().animate({ 9069 //top: '-192px' 9070 opacity: '0' 9071 }, iL.options.show.speed, 'easeInCirc'); 9072 } else { 9073 if (iL.vars.loadRequests <= 0) iL.vars.loader.removeClass('ilightbox-show').stop().animate({ 9074 //left: '-192px' 9075 opacity: '0' 9076 }, iL.options.show.speed, 'easeInCirc'); 9077 } 9078 }, 9079 9080 createUI: function() { 9081 var iL = this; 9082 9083 iL.ui = { 9084 currentElement: iL.vars.holder, 9085 nextElement: iL.vars.nextPhoto, 9086 prevElement: iL.vars.prevPhoto, 9087 currentItem: iL.vars.current, 9088 nextItem: iL.vars.next, 9089 prevItem: iL.vars.prev, 9090 hide: function() { 9091 iL.closeAction(); 9092 }, 9093 refresh: function() { 9094 (arguments.length > 0) ? iL.repositionPhoto(true): iL.repositionPhoto(); 9095 }, 9096 fullscreen: function() { 9097 iL.fullScreenAction(); 9098 } 9099 }; 9100 }, 9101 9102 attachItems: function() { 9103 var iL = this, 9104 itemsObject = new Array(), 9105 items = new Array(); 9106 9107 $(iL.selector, iL.context).each(function() { 9108 var t = $(this), 9109 URL = t.attr(iL.options.attr) || null, 9110 options = t.data("options") && eval("({" + t.data("options") + "})") || {}, 9111 caption = t.data('caption'), 9112 title = t.data('title'), 9113 type = t.data('type') || getTypeByExtension(URL), 9114 clone = t.data('lbox-clone') || false; 9115 9116 if (t.data('lbox-clone') != undefined) return; 9117 9118 //Uncode addition ##START## 9119 if ( typeof t.attr('data-album') != 'undefined' && t.attr('data-album') != '' ) { 9120 var ALBUM_URLS = JSON.parse(t.attr('data-album')), 9121 URL_i, 9122 URLS_LENGHT = ALBUM_URLS.length; 9123 for (URL_i = 0; URL_i < URLS_LENGHT; URL_i++) { 9124 if ( typeof ALBUM_URLS[URL_i].url !== 'undefined' && ALBUM_URLS[URL_i].url != '' ) { 9125 var item_opts = 'width:' + ALBUM_URLS[URL_i].width + ',height:' + ALBUM_URLS[URL_i].height + ',thumbnail: \'' + ALBUM_URLS[URL_i].thumbnail + '\''; 9126 item_opts = item_opts && eval("({" + item_opts + "})") || {}, 9127 items.push({ 9128 URL: ALBUM_URLS[URL_i].url, 9129 caption: ALBUM_URLS[URL_i].caption, 9130 title: ALBUM_URLS[URL_i].title, 9131 type: getTypeByExtension(ALBUM_URLS[URL_i].url), 9132 options: item_opts, 9133 clone: clone 9134 }); 9135 var newT = t; 9136 newT.attr('href',ALBUM_URLS[URL_i].url); 9137 if (!iL.instant) itemsObject.push(newT); 9138 } 9139 } 9140 } else { 9141 //Uncode addition ##END## 9142 items.push({ 9143 URL: URL, 9144 caption: caption, 9145 title: title, 9146 type: type, 9147 options: options, 9148 clone: clone 9149 }); 9150 } 9151 9152 9153 if (iL.vars != undefined) iL.vars.total = items.length; 9154 9155 if (!iL.instant) itemsObject.push(t); 9156 }); 9157 9158 iL.items = items, 9159 iL.itemsObject = itemsObject; 9160 9161 }, 9162 9163 normalizeItems: function() { 9164 var iL = this, 9165 newItems = new Array(); 9166 9167 $.each(iL.items, function(key, val) { 9168 9169 if (typeof val == "string") val = { 9170 url: val 9171 }; 9172 9173 var URL = val.url || val.URL || null, 9174 options = val.options || {}, 9175 caption = val.caption || null, 9176 title = val.title || null, 9177 type = (val.type) ? val.type.toLowerCase() : getTypeByExtension(URL), 9178 ext = (typeof URL != 'object') ? getExtension(URL) : ''; 9179 9180 options.thumbnail = options.thumbnail || ((type == "image") ? URL : null),
9181 options.videoType = options.videoType || null, 9182 options.skin = options.skin || iL.options.skin, 9183 options.width = options.width || null, 9184 options.height = options.height || null, 9185 options.mousewheel = (typeof options.mousewheel != 'undefined') ? options.mousewheel : true, 9186 options.swipe = (typeof options.swipe != 'undefined') ? options.swipe : true, 9187 options.social = (typeof options.social != 'undefined') ? options.social : iL.options.social.buttons && $.extend({}, {}, iL.options.social.buttons); 9188 9189 if (type == "video") { 9190 options.html5video = (typeof options.html5video != 'undefined') ? options.html5video : {}; 9191 9192 options.html5video.webm = options.html5video.webm || options.html5video.WEBM || null; 9193 options.html5video.controls = (typeof options.html5video.controls != 'undefined') ? options.html5video.controls : "controls"; 9194 options.html5video.preload = options.html5video.preload || "metadata"; 9195 options.html5video.autoplay = (typeof options.html5video.autoplay != 'undefined') ? options.html5video.autoplay : false; 9196 //UNCODE addition 9197 options.html5video.loop = (typeof options.html5video.loop != 'undefined') ? options.html5video.loop : false; 9198 } 9199 9200 if (!options.width || !options.height) { 9201 if (type == "video") options.width = 1280, options.height = 720; 9202 else if (type == "iframe") options.width = '100%', options.height = '90%'; 9203 else if (type == "flash") options.width = 1280, options.height = 720; 9204 } 9205 9206 delete val.url; 9207 val.index = key; 9208 val.URL = URL; 9209 val.caption = caption; 9210 val.title = title; 9211 val.type = type; 9212 val.options = options; 9213 val.ext = ext; 9214 9215 newItems.push(val); 9216 }); 9217 9218 iL.items = newItems; 9219 }, 9220 9221 instantCall: function() { 9222 var iL = this, 9223 key = iL.vars.start; 9224 9225 iL.vars.current = key; 9226 iL.vars.next = (iL.items[key + 1]) ? key + 1 : null; 9227 iL.vars.prev = (iL.items[key - 1]) ? key - 1 : null; 9228 9229 iL.addContents(); 9230 iL.patchEvents(); 9231 }, 9232 9233 addContents: function() { 9234 var iL = this, 9235 vars = iL.vars, 9236 opts = iL.options, 9237 viewport = getViewport(), 9238 path = opts.path.toLowerCase(), 9239 recognizingItems = vars.total > 0 && iL.items.filter(function(e, i, arr) { 9240 return ['image', 'flash', 'video'].indexOf(e.type) === -1 && typeof e.recognized === 'undefined' && (opts.smartRecognition || e.options.smartRecognition); 9241 }), 9242 needRecognition = recognizingItems.length > 0; 9243 9244 if (opts.mobileOptimizer && !opts.innerToolbar) 9245 vars.isMobile = viewport.width <= vars.mobileMaxWidth; 9246 9247 vars.overlay.addClass(opts.skin).hide().css('opacity', opts.overlay.opacity); 9248 9249 if (opts.linkId) 9250 vars.overlay[0].setAttribute('linkid', opts.linkId); 9251 9252 //Add Toolbar Buttons 9253 if (opts.controls.toolbar) { 9254 vars.toolbar.addClass(opts.skin).append(vars.closeButton); 9255 if (opts.controls.fullscreen) 9256 vars.toolbar.append(vars.fullScreenButton); 9257 if (opts.controls.slideshow) 9258 vars.toolbar.append(vars.innerPlayButton); 9259 if (vars.total > 1) 9260 vars.toolbar.append(vars.innerPrevButton).append(vars.innerNextButton); 9261 } 9262 9263 //Append elements to body 9264 vars.BODY.addClass('ilightbox-noscroll').append(vars.overlay).append(vars.loader).append(vars.holder).append(vars.nextPhoto).append(vars.prevPhoto); 9265 9266 if (!opts.innerToolbar) 9267 vars.BODY.append(vars.toolbar); 9268 if (opts.controls.arrows) 9269 vars.BODY.append(vars.nextButton).append(vars.prevButton); 9270 9271 if (opts.controls.thumbnail && vars.total > 1) { 9272 vars.BODY.append(vars.thumbnails); 9273 vars.thumbnails.addClass(opts.skin).addClass('ilightbox-' + path); 9274 $('div.ilightbox-thumbnails-grid', vars.thumbnails).empty(); 9275 vars.thumbs = true; 9276 } 9277 9278 //Configure loader and arrows 9279 var loaderCss = (opts.path.toLowerCase() == "horizontal") ? { 9280 left: parseInt((viewport.width / 2) - (vars.loader.outerWidth() / 2)) 9281 } : { 9282 top: parseInt((viewport.height / 2) - (vars.loader.outerHeight() / 2)) 9283 }; 9284 vars.loader.addClass(opts.skin).css(loaderCss); 9285 vars.nextButton.add(vars.prevButton).addClass(opts.skin); 9286 if (path == "horizontal") 9287 vars.loader.add(vars.nextButton).add(vars.prevButton).addClass('horizontal'); 9288 9289 // Configure arrow buttons 9290 vars.BODY[vars.isMobile ? 'addClass' : 'removeClass']('isMobile'); 9291 9292 if (!opts.infinite) { 9293 vars.prevButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled'); 9294 9295 if (vars.current == 0) 9296 vars.prevButton.add(vars.innerPrevButton).addClass('disabled'); 9297 if (vars.current >= vars.total - 1) 9298 vars.nextButton.add(vars.innerNextButton).addClass('disabled'); 9299 } 9300 9301 if (opts.show.effect) { 9302 vars.overlay.stop().fadeIn(opts.show.speed); 9303 vars.toolbar.stop().fadeIn(opts.show.speed); 9304 } else { 9305 vars.overlay.show(); 9306 vars.toolbar.show(); 9307 } 9308 9309 var length = recognizingItems.length; 9310 if (needRecognition) { 9311 iL.showLoader(); 9312 9313 $.each(recognizingItems, function(key, val) { 9314 var resultFnc = function(result) { 9315 var key = -1, 9316 filter = iL.items.filter(function(e, i, arr) { 9317 if (e.URL == result.url) 9318 key = i; 9319 9320 return e.URL == result.url; 9321 }), 9322 self = iL.items[key]; 9323 9324 if (result) 9325 $.extend(true, self, { 9326 URL: result.source, 9327 type: result.type, 9328 recognized: true, 9329 options: { 9330 html5video: result.html5video, 9331 width: (result.type == "image") ? 0 : (result.width || self.width), 9332 height: (result.type == "image") ? 0 : (result.height || self.height), 9333 thumbnail: self.options.thumbnail || result.thumbnail 9334 } 9335 }); 9336 9337 length--; 9338 9339 if (length == 0) { 9340 iL.hideLoader(); 9341 9342 vars.dontGenerateThumbs = false;
9343 iL.generateThumbnails(); 9344 9345 if (opts.show.effect) 9346 setTimeout(function() { 9347 iL.generateBoxes(); 9348 }, opts.show.speed); 9349 else 9350 iL.generateBoxes(); 9351 } 9352 }; 9353 9354 iL.ogpRecognition(this, resultFnc); 9355 }); 9356 } 9357 else { 9358 if (opts.show.effect) 9359 setTimeout(function() { 9360 iL.generateBoxes(); 9361 }, opts.show.speed); 9362 else 9363 iL.generateBoxes(); 9364 } 9365 9366 iL.createUI(); 9367 9368 window.iLightBox = { 9369 close: function() { 9370 iL.closeAction(); 9371 }, 9372 fullscreen: function() { 9373 iL.fullScreenAction(); 9374 }, 9375 moveNext: function() { 9376 iL.moveTo('next'); 9377 }, 9378 movePrev: function() { 9379 iL.moveTo('prev'); 9380 }, 9381 goTo: function(index) { 9382 iL.goTo(index); 9383 }, 9384 refresh: function() { 9385 iL.refresh(); 9386 }, 9387 reposition: function() { 9388 (arguments.length > 0) ? iL.repositionPhoto(true): iL.repositionPhoto(); 9389 }, 9390 setOption: function(options) { 9391 iL.setOption(options); 9392 }, 9393 destroy: function() { 9394 iL.closeAction(); 9395 iL.dispatchItemsEvents(); 9396 } 9397 }; 9398 9399 if (opts.linkId) { 9400 vars.hashLock = true; 9401 window.location.hash = opts.linkId + '/' + vars.current; 9402 setTimeout(function() { 9403 vars.hashLock = false; 9404 }, 55); 9405 } 9406 9407 if (!opts.slideshow.startPaused) { 9408 iL.resume(); 9409 vars.innerPlayButton.removeClass('ilightbox-play').addClass('ilightbox-pause'); 9410 } 9411 9412 //Trigger the onOpen callback 9413 if (typeof iL.options.callback.onOpen == 'function') iL.options.callback.onOpen.call(iL); 9414 }, 9415 9416 loadContent: function(obj, opt, speed) { 9417 var iL = this, 9418 holder, item; 9419 9420 iL.createUI(); 9421 9422 obj.speed = speed || iL.options.effects.loadedFadeSpeed; 9423 9424 if (opt == 'current') { 9425 if (!obj.options.mousewheel) iL.vars.lockWheel = true; 9426 else iL.vars.lockWheel = false; 9427 9428 if (!obj.options.swipe) iL.vars.lockSwipe = true; 9429 else iL.vars.lockSwipe = false; 9430 } 9431 9432 switch (opt) { 9433 case 'current': 9434 holder = iL.vars.holder, item = iL.vars.current; 9435 break; 9436 case 'next': 9437 holder = iL.vars.nextPhoto, item = iL.vars.next; 9438 break; 9439 case 'prev': 9440 holder = iL.vars.prevPhoto, item = iL.vars.prev; 9441 break; 9442 } 9443 9444 holder.removeAttr('style class').addClass('ilightbox-holder' + (supportTouch ? ' supportTouch' : '')).addClass(obj.options.skin); 9445 $('div.ilightbox-inner-toolbar', holder).remove(); 9446 9447 if (obj.title || iL.options.innerToolbar) { 9448 var innerToolbar = iL.vars.innerToolbar.clone(); 9449 if (obj.title && iL.options.show.title) { 9450 var title = iL.vars.title.clone(); 9451 title.empty().html(obj.title); 9452 innerToolbar.append(title); 9453 } 9454 if (iL.options.innerToolbar) { 9455 innerToolbar.append((iL.vars.total > 1) ? iL.vars.toolbar.clone() : iL.vars.toolbar); 9456 } 9457 holder.prepend(innerToolbar); 9458 } 9459 9460 //console.warn('loadContent', arguments); 9461 9462 iL.loadSwitcher(obj, holder, item, opt); 9463 }, 9464 9465 loadSwitcher: function(obj, holder, item, opt) { 9466 var iL = this, 9467 opts = iL.options, 9468 api = { 9469 element: holder, 9470 position: item 9471 }; 9472 9473 switch (obj.type) { 9474 case 'image': 9475 //Trigger the onBeforeLoad callback 9476 if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item); 9477 if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api); 9478 9479 iL.loadImage(obj.URL, function(img) { 9480 //Trigger the onAfterLoad callback 9481 if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item); 9482 if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api); 9483 9484 var width = (img) ? img.width : 400, 9485 height = (img) ? img.height : 200; 9486 9487 holder.data({ 9488 naturalWidth: width, 9489 naturalHeight: height 9490 }); 9491 $('div.ilightbox-container', holder).empty().append((img) ? '<img src="' + obj.URL + '" class="ilightbox-image" />' : '<span class="ilightbox-alert">' + opts.errors.loadImage + '</span>'); 9492 9493 //Trigger the onRender callback 9494 if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item); 9495 if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api); 9496 9497 iL.configureHolder(obj, opt, holder); 9498 }); 9499 9500 break; 9501
9502 case 'video': 9503 holder.data({ 9504 naturalWidth: obj.options.width, 9505 naturalHeight: obj.options.height 9506 }); 9507 9508 if (opt === 'current') { 9509 iL.addContent(holder, obj); 9510 9511 //Trigger the onRender callback 9512 if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item); 9513 if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api); 9514 } else { 9515 $('div.ilightbox-container', holder).empty(); 9516 } 9517 9518 iL.configureHolder(obj, opt, holder); 9519 9520 break; 9521 9522 case 'iframe': 9523 //iL.showLoader(); 9524 holder.data({ 9525 naturalWidth: obj.options.width, 9526 naturalHeight: obj.options.height 9527 }); 9528 9529 iL.configureHolder(obj, opt, holder); 9530 9531 if (opt === 'current') { 9532 var el = iL.addContent(holder, obj); 9533 9534 //Trigger the onRender callback 9535 if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item); 9536 if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api); 9537 9538 //Trigger the onBeforeLoad callback 9539 if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item); 9540 if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api); 9541 9542 el.bind('load', function() { 9543 //Trigger the onAfterLoad callback 9544 if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item); 9545 if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api); 9546 9547 //iL.hideLoader(); 9548 el.unbind('load'); 9549 }); 9550 } else { 9551 $('div.ilightbox-container', holder).empty(); 9552 } 9553 9554 break; 9555 9556 case 'inline': 9557 var el = $(obj.URL), 9558 content = iL.addContent(holder, obj), 9559 images = findImageInElement(holder); 9560 9561 holder.data({ 9562 naturalWidth: (iL.items[item].options.width || el.outerWidth()), 9563 naturalHeight: (iL.items[item].options.height || el.outerHeight()) 9564 }); 9565 content.children().eq(0).show(); 9566 9567 //Trigger the onRender callback 9568 if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item); 9569 if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api); 9570 9571 //Trigger the onBeforeLoad callback 9572 if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item); 9573 if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api); 9574 9575 iL.loadImage(images, function() { 9576 //Trigger the onAfterLoad callback 9577 if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item); 9578 if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api); 9579 9580 iL.configureHolder(obj, opt, holder); 9581 }); 9582 9583 break; 9584 9585 case 'flash': 9586 var el = iL.addContent(holder, obj); 9587 9588 holder.data({ 9589 naturalWidth: (iL.items[item].options.width || el.outerWidth()), 9590 naturalHeight: (iL.items[item].options.height || el.outerHeight()) 9591 }); 9592 9593 //Trigger the onRender callback 9594 if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item); 9595 if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api); 9596 9597 iL.configureHolder(obj, opt, holder); 9598 9599 break; 9600 9601 case 'ajax': 9602 var ajax = obj.options.ajax || {}; 9603 //Trigger the onBeforeLoad callback 9604 if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item); 9605 if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api); 9606 9607 iL.showLoader(); 9608 $.ajax({ 9609 url: obj.URL || opts.ajaxSetup.url, 9610 data: ajax.data || null, 9611 dataType: ajax.dataType || "html", 9612 type: ajax.type || opts.ajaxSetup.type, 9613 cache: ajax.cache || opts.ajaxSetup.cache, 9614 crossDomain: ajax.crossDomain || opts.ajaxSetup.crossDomain, 9615 global: ajax.global || opts.ajaxSetup.global, 9616 ifModified: ajax.ifModified || opts.ajaxSetup.ifModified, 9617 username: ajax.username || opts.ajaxSetup.username, 9618 password: ajax.password || opts.ajaxSetup.password, 9619 beforeSend: ajax.beforeSend || opts.ajaxSetup.beforeSend, 9620 complete: ajax.complete || opts.ajaxSetup.complete, 9621 success: function(data, textStatus, jqXHR) { 9622 iL.hideLoader(); 9623 9624 var el = $(data), 9625 container = $('div.ilightbox-container', holder), 9626 elWidth = iL.items[item].options.width || parseInt(el[0].getAttribute('width')), 9627 elHeight = iL.items[item].options.height || parseInt(el[0].getAttribute('height')), 9628 css = (el[0].getAttribute('width') && el[0].getAttribute('height')) ? { 9629 'overflow': 'hidden' 9630 } : {}; 9631 9632 container.empty().append($('<div class="ilightbox-wrapper"></div>').css(css).html(el)); 9633 holder.show().data({
9634 naturalWidth: (elWidth || container.outerWidth()), 9635 naturalHeight: (elHeight || container.outerHeight()) 9636 }).hide(); 9637 9638 //Trigger the onRender callback 9639 if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item); 9640 if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api); 9641 9642 var images = findImageInElement(holder); 9643 iL.loadImage(images, function() { 9644 //Trigger the onAfterLoad callback 9645 if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item); 9646 if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api); 9647 9648 iL.configureHolder(obj, opt, holder); 9649 }); 9650 9651 opts.ajaxSetup.success(data, textStatus, jqXHR); 9652 if (typeof ajax.success == 'function') ajax.success(data, textStatus, jqXHR); 9653 }, 9654 error: function(jqXHR, textStatus, errorThrown) { 9655 //Trigger the onAfterLoad callback 9656 if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item); 9657 if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api); 9658 9659 iL.hideLoader(); 9660 $('div.ilightbox-container', holder).empty().append('<span class="ilightbox-alert">' + opts.errors.loadContents + '</span>'); 9661 iL.configureHolder(obj, opt, holder); 9662 9663 opts.ajaxSetup.error(jqXHR, textStatus, errorThrown); 9664 if (typeof ajax.error == 'function') ajax.error(jqXHR, textStatus, errorThrown); 9665 } 9666 }); 9667 9668 break; 9669 9670 case 'html': 9671 var object = obj.URL, 9672 el 9673 container = $('div.ilightbox-container', holder); 9674 9675 if (object[0].nodeName) el = object.clone(); 9676 else { 9677 var dom = $(object); 9678 if (dom.selector) el = $('<div>' + dom + '</div>'); 9679 else el = dom; 9680 } 9681 9682 var elWidth = iL.items[item].options.width || parseInt(el.attr('width')), 9683 elHeight = iL.items[item].options.height || parseInt(el.attr('height')); 9684 9685 iL.addContent(holder, obj); 9686 9687 el.appendTo(document.documentElement).hide(); 9688 9689 //Trigger the onRender callback 9690 if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item); 9691 if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api); 9692 9693 var images = findImageInElement(holder); 9694 9695 //Trigger the onBeforeLoad callback 9696 if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item); 9697 if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api); 9698 9699 iL.loadImage(images, function() { 9700 //Trigger the onAfterLoad callback 9701 if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item); 9702 if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api); 9703 9704 holder.show().data({ 9705 naturalWidth: (elWidth || container.outerWidth()), 9706 naturalHeight: (elHeight || container.outerHeight()) 9707 }).hide(); 9708 el.remove(); 9709 9710 iL.configureHolder(obj, opt, holder); 9711 }); 9712 9713 break; 9714 } 9715 }, 9716 9717 configureHolder: function(obj, opt, holder) { 9718 var iL = this, 9719 vars = iL.vars, 9720 opts = iL.options; 9721 9722 if (opt != "current")(opt == "next") ? holder.addClass('ilightbox-next') : holder.addClass('ilightbox-prev'); 9723 9724 if (opt == "current") 9725 var item = vars.current; 9726 else if (opt == "next") 9727 var opacity = opts.styles.nextOpacity, 9728 item = vars.next; 9729 else 9730 var opacity = opts.styles.prevOpacity, 9731 item = vars.prev; 9732 9733 var api = { 9734 element: holder, 9735 position: item 9736 }; 9737 9738 iL.items[item].options.width = iL.items[item].options.width || 0, 9739 iL.items[item].options.height = iL.items[item].options.height || 0; 9740 9741 if (opt == "current") { 9742 if (opts.show.effect) holder.css(transform, gpuAcceleration).fadeIn(obj.speed, function() { 9743 holder.css(transform, ''); 9744 if (obj.caption) { 9745 iL.setCaption(obj, holder); 9746 var caption = $('div.ilightbox-caption', holder), 9747 percent = parseInt((caption.outerHeight() / holder.outerHeight()) * 100); 9748 if (opts.caption.start & percent <= 50) caption.fadeIn(opts.effects.fade
9748Speed); 9749 } 9750 9751 var social = obj.options.social; 9752 if (social) { 9753 iL.setSocial(social, obj.URL, holder); 9754 if (opts.social.start) $('div.ilightbox-social', holder).fadeIn(opts.effects.fadeSpeed); 9755 } 9756 9757 //Generate thumbnails 9758 iL.generateThumbnails(); 9759 9760 //Trigger the onShow callback 9761 if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item); 9762 if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api); 9763 }); 9764 else { 9765 holder.show(); 9766 9767 //Generate thumbnails 9768 iL.generateThumbnails(); 9769 9770 //Trigger the onShow callback 9771 if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item); 9772 if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api); 9773 } 9774 } else { 9775 if (opts.show.effect) holder.fadeTo(obj.speed, opacity, function() { 9776 if (opt == "next") vars.nextLock = false; 9777 else vars.prevLock = false; 9778 9779 //Generate thumbnails 9780 iL.generateThumbnails(); 9781 9782 //Trigger the onShow callback 9783 if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item); 9784 if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api); 9785 }); 9786 else { 9787 holder.css({ 9788 opacity: opacity 9789 }).show(); 9790 if (opt == "next") vars.nextLock = false; 9791 else vars.prevLock = false; 9792 9793 //Generate thumbnails 9794 iL.generateThumbnails(); 9795 9796 //Trigger the onShow callback 9797 if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item); 9798 if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api); 9799 } 9800 } 9801 9802 setTimeout(function() { 9803 iL.repositionPhoto(); 9804 }, 0); 9805 }, 9806 9807 generateBoxes: function() { 9808 var iL = this, 9809 vars = iL.vars, 9810 opts = iL.options; 9811 9812 if (opts.infinite && vars.total >= 3) { 9813 if (vars.current == vars.total - 1) vars.next = 0; 9814 if (vars.current == 0) vars.prev = vars.total - 1; 9815 } else opts.infinite = false; 9816 9817 //UNCODE addition 9818 if ( typeof iL.items[vars.current] == 'undefined' ) 9819 vars.current = 0; 9820 9821 iL.loadContent(iL.items[vars.current], 'current', opts.show.speed); 9822 9823 if (iL.items[vars.next]) iL.loadContent(iL.items[vars.next], 'next', opts.show.speed); 9824 if (iL.items[vars.prev]) iL.loadContent(iL.items[vars.prev], 'prev', opts.show.speed); 9825 }, 9826 9827 generateThumbnails: function() { 9828 var iL = this, 9829 vars = iL.vars, 9830 opts = iL.options, 9831 timeOut = null; 9832 9833 if (vars.thumbs && !iL.vars.dontGenerateThumbs) { 9834 var thumbnails = vars.thumbnails, 9835 container = $('div.ilightbox-thumbnails-container', thumbnails), 9836 grid = $('div.ilightbox-thumbnails-grid', container), 9837 i = 0; 9838 9839 grid.removeAttr('style').empty(); 9840 9841 $.each(iL.items, function(key, val) { 9842 var isActive = (vars.current == key) ? 'ilightbox-active' : '', 9843 opacity = (vars.current == key) ? opts.thumbnails.activeOpacity : opts.thumbnails.normalOpacity, 9844 thumb = val.options.thumbnail, 9845 thumbnail = $('<div class="ilightbox-thumbnail"></div>'), 9846 icon = $('<div class="ilightbox-thumbnail-icon"></div>'); 9847 9848 thumbnail.css({ 9849 opacity: 0 9850 }).addClass(isActive); 9851 9852 if ((val.type == "video" || val.type == "flash") && typeof val.options.icon == 'undefined') { 9853 icon.addClass('ilightbox-thumbnail-video'); 9854 thumbnail.append(icon); 9855 } else if (val.options.icon) { 9856 icon.addClass('ilightbox-thumbnail-' + val.options.icon); 9857 thumbnail.append(icon); 9858 } 9859 9860 if (thumb) iL.loadImage(thumb, function(img) { 9861 i++; 9862 if (img) thumbnail.data({ 9863 naturalWidth: img.width, 9864 naturalHeight: img.height 9865 }).append('<img src="' + thumb + '" border="0" />'); 9866 else thumbnail.data({ 9867 naturalWidth: opts.thumbnails.maxWidth, 9868 naturalHeight: opts.thumbnails.maxHeight 9869 }); 9870 9871 clearTimeout(timeOut); 9872 timeOut = setTimeout(function() { 9873 iL.positionThumbnails(thumbnails, container, grid); 9874 }, 20); 9875 setTimeout(function() { 9876 thumbnail.fadeTo(opts.effects.loadedFadeSpeed, opacity); 9877 }, i * 20); 9878 }); 9879 9880 grid.append(thumbnail); 9881 }); 9882 iL.vars.dontGenerateThumbs = true; 9883 } 9884 }, 9885
9886 positionThumbnails: function(thumbnails, container, grid) { 9887 var iL = this, 9888 vars = iL.vars, 9889 opts = iL.options, 9890 viewport = getViewport(), 9891 path = opts.path.toLowerCase(); 9892 9893 if (!thumbnails) thumbnails = vars.thumbnails; 9894 if (!container) container = $('div.ilightbox-thumbnails-container', thumbnails); 9895 if (!grid) grid = $('div.ilightbox-thumbnails-grid', container); 9896 9897 var thumbs = $('.ilightbox-thumbnail', grid), 9898 widthAvail = (path == 'horizontal') ? viewport.width - opts.styles.pageOffsetX : thumbs.eq(0).outerWidth() - opts.styles.pageOffsetX, 9899 heightAvail = (path == 'horizontal') ? thumbs.eq(0).outerHeight() - opts.styles.pageOffsetY : viewport.height - opts.styles.pageOffsetY, 9900 gridWidth = (path == 'horizontal') ? 0 : widthAvail, 9901 gridHeight = (path == 'horizontal') ? heightAvail : 0, 9902 active = $('.ilightbox-active', grid), 9903 gridCss = {}, 9904 css = {}; 9905 9906 if (arguments.length < 3) { 9907 thumbs.css({ 9908 opacity: opts.thumbnails.normalOpacity 9909 }); 9910 active.css({ 9911 opacity: opts.thumbnails.activeOpacity 9912 }); 9913 } 9914 9915 thumbs.each(function(i) { 9916 var t = $(this), 9917 data = t.data(), 9918 width = (path == 'horizontal') ? 0 : opts.thumbnails.maxWidth; 9919 height = (path == 'horizontal') ? opts.thumbnails.maxHeight : 0; 9920 dims = iL.getNewDimenstions(width, height, data.naturalWidth, data.naturalHeight, true); 9921 9922 t.css({ 9923 width: dims.width, 9924 height: dims.height 9925 }); 9926 if (path == 'horizontal') t.css({ 9927 'float': 'left' 9928 }); 9929 9930 (path == 'horizontal') ? ( 9931 gridWidth += t.outerWidth() 9932 ) : ( 9933 gridHeight += t.outerHeight() 9934 ); 9935 }); 9936 9937 gridCss = { 9938 width: gridWidth, 9939 height: gridHeight 9940 }; 9941 9942 grid.css(gridCss); 9943 9944 gridCss = {}; 9945 9946 var gridOffset = grid.offset(), 9947 activeOffset = (active.length) ? active.offset() : { 9948 top: parseInt(heightAvail / 2), 9949 left: parseInt(widthAvail / 2) 9950 }; 9951 9952 gridOffset.top = (gridOffset.top - $doc.scrollTop()), 9953 gridOffset.left = (gridOffset.left - $doc.scrollLeft()), 9954 activeOffset.top = (activeOffset.top - gridOffset.top - $doc.scrollTop()), 9955 activeOffset.left = (activeOffset.left - gridOffset.left - $doc.scrollLeft()); 9956 9957 (path == 'horizontal') ? ( 9958 gridCss.top = 0, 9959 gridCss.left = parseInt((widthAvail / 2) - activeOffset.left - (active.outerWidth() / 2)) 9960 ) : ( 9961 gridCss.top = parseInt(((heightAvail / 2) - activeOffset.top - (active.outerHeight() / 2))), 9962 gridCss.left = 0 9963 ); 9964 9965 if (arguments.length < 3) grid.stop().animate(gridCss, opts.effects.repositionSpeed, 'easeOutCirc'); 9966 else grid.css(gridCss); 9967 }, 9968 9969 loadImage: function(image, callback) { 9970 if (!$.isArray(image)) image = [image]; 9971 9972 var iL = this, 9973 length = image.length; 9974 9975 if (length > 0) { 9976 iL.showLoader(); 9977 $.each(image, function(index, value) { 9978 var img = new Image(); 9979 img.onload = function() { 9980 length -= 1; 9981 if (length == 0) { 9982 iL.hideLoader(); 9983 callback(img); 9984 } 9985 }; 9986 img.onerror = img.onabort = function() { 9987 length -= 1; 9988 if (length == 0) { 9989 iL.hideLoader(); 9990 callback(false); 9991 } 9992 }; 9993 img.src = image[index]; 9994 }); 9995 } else callback(false); 9996 }, 9997 9998 patchItemsEvents: function() { 9999 var iL = this, 10000 vars = iL.vars, 10001 clickEvent = supportTouch ? "itap.iL" : "click.iL", 10002 vEvent = supportTouch ? "click.iL" : "itap.iL"; 10003 10004 if (iL.context && iL.selector) { 10005 var $items = $(iL.selector, iL.context); 10006 10007 $(iL.context).on(clickEvent, iL.selector, function() { 10008 var $this = $(this), 10009 //UNCODE addition 10010 key = typeof $(this).data('lb-index') !== '' && $(this).closest('.owl-item').length ? $(this).data('lb-index') : $items.index($this); 10011 if (UNCODE.isMobile) { 10012 var isCarousel = $this.closest('.owl-carousel'); 10013 if (isCarousel.length) { 10014 if (isCarousel.hasClass('owl-translating')) return false; 10015 } 10016 } 10017 10018 vars.current = key; 10019 vars.next = iL.items[key + 1] ? key + 1 : null; 10020 vars.prev = iL.items[key - 1] ? key - 1 : null; 10021 10022 //UNCODE addition 10023 if ( vars.BODY.hasClass('fp-slide-scrolling') ) 10024 return false;
10025 10026 iL.addContents(); 10027 iL.patchEvents(); 10028 10029 return false; 10030 }).on(vEvent, iL.selector, function() { 10031 return false; 10032 }); 10033 } else 10034 $.each(iL.itemsObject, function(key, val) { 10035 val.on(clickEvent, function() { 10036 vars.current = key; 10037 vars.next = iL.items[key + 1] ? key + 1 : null; 10038 vars.prev = iL.items[key - 1] ? key - 1 : null; 10039 10040 iL.addContents(); 10041 iL.patchEvents(); 10042 10043 return false; 10044 }).on(vEvent, function() { 10045 return false; 10046 }); 10047 }); 10048 }, 10049 10050 dispatchItemsEvents: function() { 10051 var iL = this, 10052 vars = iL.vars, 10053 opts = iL.options; 10054 10055 if (iL.context && iL.selector) 10056 $(iL.context).off('.iL', iL.selector); 10057 else 10058 $.each(iL.itemsObject, function(key, val) { 10059 val.off('.iL'); 10060 }); 10061 }, 10062 10063 refresh: function() { 10064 var iL = this; 10065 10066 iL.dispatchItemsEvents(); 10067 iL.attachItems(); 10068 iL.normalizeItems(); 10069 iL.patchItemsEvents(); 10070 }, 10071 10072 patchEvents: function() { 10073 var iL = this, 10074 vars = iL.vars, 10075 opts = iL.options, 10076 path = opts.path.toLowerCase(), 10077 holders = $('.ilightbox-holder'), 10078 fullscreenEvent = fullScreenApi.fullScreenEventName + '.iLightBox', 10079 durationThreshold = 1000, 10080 horizontalDistanceThreshold = 10081 verticalDistanceThreshold = 100, 10082 buttonsArray = [vars.nextButton[0], vars.prevButton[0], vars.nextButton[0].firstChild, vars.prevButton[0].firstChild]; 10083 10084 $win.bind('resize.iLightBox', function() { 10085 var viewport = getViewport(); 10086 10087 if (opts.mobileOptimizer && !opts.innerToolbar) vars.isMobile = viewport.width <= vars.mobileMaxWidth; 10088 vars.BODY[vars.isMobile ? 'addClass' : 'removeClass']('isMobile'); 10089 10090 iL.repositionPhoto(null); 10091 if (supportTouch) { 10092 clearTimeout(vars.setTime); 10093 vars.setTime = setTimeout(function() { 10094 var scrollTop = getScrollXY().y; 10095 window.scrollTo(0, scrollTop - 30); 10096 window.scrollTo(0, scrollTop + 30); 10097 window.scrollTo(0, scrollTop); 10098 }, 2000); 10099 } 10100 if (vars.thumbs) iL.positionThumbnails(); 10101 }).bind('keydown.iLightBox', function(event) { 10102 if (opts.controls.keyboard) { 10103 switch (event.keyCode) { 10104 case 13: 10105 if (event.shiftKey && opts.keyboard.shift_enter) iL.fullScreenAction(); 10106 break; 10107 case 27: 10108 if (opts.keyboard.esc) iL.closeAction(); 10109 break; 10110 case 37: 10111 if (opts.keyboard.left && !vars.lockKey) iL.moveTo('prev'); 10112 break; 10113 case 38: 10114 if (opts.keyboard.up && !vars.lockKey) iL.moveTo('prev'); 10115 break; 10116 case 39: 10117 if (opts.keyboard.right && !vars.lockKey) iL.moveTo('next'); 10118 break; 10119 case 40: 10120 if (opts.keyboard.down && !vars.lockKey) iL.moveTo('next'); 10121 break; 10122 } 10123 } 10124 }); 10125 10126 if (fullScreenApi.supportsFullScreen) $win.bind(fullscreenEvent, function() { 10127 iL.doFullscreen(); 10128 }); 10129 10130 var holderEventsArr = [opts.caption.show + '.iLightBox', opts.caption.hide + '.iLightBox', opts.social.show + '.iLightBox', opts.social.hide + '.iLightBox'].filter(function(e, i, arr) { 10131 return arr.lastIndexOf(e) === i; 10132 }), 10133 holderEvents = ""; 10134 10135 $.each(holderEventsArr, function(key, val) { 10136 if (key != 0) holderEvents += ' '; 10137 holderEvents += val; 10138 }); 10139 10140 $doc.on(clickEvent, '.ilightbox-overlay', function() { 10141 if (opts.overlay.blur) iL.closeAction(); 10142 }).on(clickEvent, '.ilightbox-next, .ilightbox-next-button', function() { 10143 iL.moveTo('next'); 10144 }).on(clickEvent, '.ilightbox-prev, .ilightbox-prev-button', function() { 10145 iL.moveTo('prev'); 10146 }).on(clickEvent, '.ilightbox-thumbnail', function() { 10147 var t = $(this), 10148 thumbs = $('.ilightbox-thumbnail', vars.thumbnails), 10149 index = thumbs.index(t); 10150 10151 if (index != vars.current) iL.goTo(index); 10152 }).on(holderEvents, '.ilightbox-holder:not(.ilightbox-next, .ilightbox-prev)', function(e) { 10153 var caption = $('div.ilightbox-caption', vars.holder), 10154 social = $('div.ilightbox-social', vars.holder), 10155 fadeSpeed = opts.effects.fadeSpeed; 10156 10157 if (vars.nextLock || vars.prevLock) { 10158 if (e.type == opts.caption.show && !caption.is(':visible')) caption.fadeIn(fadeSpeed); 10159 else if (e.type == opts.caption.hide && caption.is(':visible')) caption.fadeOut(fadeSpeed); 10160 10161 if (e.type == opts.social.show && !social.is(':visible')) social.fadeIn(fadeSpeed); 10162 else if (e.type == opts.social.hide && social.is(':visible')) social.fadeOut(fadeSpeed); 10163 } else { 10164 if (e.type == opts.caption.show && !caption.is(':visible')) caption.stop().fadeIn(fadeSpeed); 10165 else if (e.type == opts.caption.hide && caption.is(':visible')) caption.stop().fadeOut(fadeSpeed); 10166 10167 if (e.type == opts.social.show && !social.is(':visible')) social.stop().fadeIn(fadeSpeed); 10168 else if (e.type == opts.social.hide && social.is(':visible')) social.stop().fadeOut(fadeSpeed); 10169 } 10170 }).on('mouseenter.iLightBox mouseleave.iLightBox', '.ilightbox-wrapper', function(e) { 10171 if (e.type == 'mouseenter') vars.lockWheel = true; 10172 else vars.lockWheel = false;
10173 }).on(clickEvent, '.ilightbox-toolbar a.ilightbox-close, .ilightbox-toolbar a.ilightbox-fullscreen, .ilightbox-toolbar a.ilightbox-play, .ilightbox-toolbar a.ilightbox-pause', function() { 10174 var t = $(this); 10175 10176 if (t.hasClass('ilightbox-fullscreen')) iL.fullScreenAction(); 10177 else if (t.hasClass('ilightbox-play')) { 10178 iL.resume(); 10179 t.addClass('ilightbox-pause').removeClass('ilightbox-play'); 10180 } else if (t.hasClass('ilightbox-pause')) { 10181 iL.pause(); 10182 t.addClass('ilightbox-play').removeClass('ilightbox-pause'); 10183 } else iL.closeAction(); 10184 }).on(touchMoveEvent, '.ilightbox-overlay, .ilightbox-thumbnails-container', function(e) { 10185 // prevent scrolling 10186 e.preventDefault(); 10187 }); 10188 10189 function mouseMoveHandler(e) { 10190 if (!vars.isMobile) { 10191 if (!vars.mouseID) { 10192 vars.hideableElements.show(); 10193 } 10194 10195 vars.mouseID = clearTimeout(vars.mouseID); 10196 10197 if (buttonsArray.indexOf(e.target) === -1) 10198 vars.mouseID = setTimeout(function() { 10199 vars.hideableElements.hide(); 10200 vars.mouseID = clearTimeout(vars.mouseID); 10201 }, 3000); 10202 } 10203 } 10204 10205 if (opts.controls.arrows && !supportTouch) $doc.on('mousemove.iLightBox', mouseMoveHandler); 10206 10207 if (opts.controls.slideshow && opts.slideshow.pauseOnHover) $doc.on('mouseenter.iLightBox mouseleave.iLightBox', '.ilightbox-holder:not(.ilightbox-next, .ilightbox-prev)', function(e) { 10208 if (e.type == 'mouseenter' && vars.cycleID) iL.pause(); 10209 else if (e.type == 'mouseleave' && vars.isPaused) iL.resume(); 10210 }); 10211 10212 var switchers = $('.ilightbox-overlay, .ilightbox-holder, .ilightbox-thumbnails'); 10213 10214 if (opts.controls.mousewheel) switchers.on('mousewheel.iLightBox', function(event, delta) { 10215 if (!vars.lockWheel) { 10216 event.preventDefault(); 10217 if (delta < 0) iL.moveTo('next'); 10218 else if (delta > 0) iL.moveTo('prev'); 10219 } 10220 }); 10221 10222 if (opts.controls.swipe) holders.on(touchStartEvent, function(event) { 10223 if (vars.nextLock || vars.prevLock || vars.total == 1 || vars.lockSwipe) return; 10224 10225 vars.BODY.addClass('ilightbox-closedhand'); 10226 10227 var data = event.originalEvent.touches ? event.originalEvent.touches[0] : event, 10228 scrollTop = $doc.scrollTop(), 10229 scrollLeft = $doc.scrollLeft(), 10230 offsets = [ 10231 holders.eq(0).offset(), 10232 holders.eq(1).offset(), 10233 holders.eq(2).offset() 10234 ], 10235 offSet = [{ 10236 top: offsets[0].top - scrollTop, 10237 left: offsets[0].left - scrollLeft 10238 }, { 10239 top: offsets[1].top - scrollTop, 10240 left: offsets[1].left - scrollLeft 10241 }, { 10242 top: offsets[2].top - scrollTop, 10243 left: offsets[2].left - scrollLeft 10244 }], 10245 start = { 10246 time: (new Date()).getTime(), 10247 coords: [data.pageX - scrollLeft, data.pageY - scrollTop] 10248 }, 10249 stop; 10250 10251 function moveEachHandler(i) { 10252 var t = $(this), 10253 offset = offSet[i], 10254 scroll = [(start.coords[0] - stop.coords[0]), (start.coords[1] - stop.coords[1])]; 10255 10256 t[0].style[path == "horizontal" ? 'left' : 'top'] = (path == "horizontal" ? offset.left - scroll[0] : offset.top - scroll[1]) + 'px'; 10257 } 10258 10259 function moveHandler(event) { 10260 10261 if (!start) return; 10262 10263 var data = event.originalEvent.touches ? event.originalEvent.touches[0] : event; 10264 10265 stop = { 10266 time: (new Date()).getTime(), 10267 coords: [data.pageX - scrollLeft, data.pageY - scrollTop] 10268 }; 10269 10270 holders.each(moveEachHandler); 10271 10272 // prevent scrolling 10273 event.preventDefault(); 10274 } 10275 10276 function repositionHolders() { 10277 holders.each(function() { 10278 var t = $(this), 10279 offset = t.data('offset') || { 10280 top: t.offset().top - scrollTop, 10281 left: t.offset().left - scrollLeft 10282 }, 10283 top = offset.top, 10284 left = offset.left; 10285 10286 t.css(transform, gpuAcceleration).stop().animate({ 10287 top: top, 10288 left: left 10289 }, 500, 'easeOutCirc', function() { 10290 t.css(transform, ''); 10291 }); 10292 }); 10293 } 10294 10295 holders.bind(touchMoveEvent, moveHandler); 10296 $doc.one(touchStopEvent, function(event) { 10297 holders.unbind(touchMoveEvent, moveHandler); 10298 10299 vars.BODY.removeClass('ilightbox-closedhand'); 10300 10301 if (start && stop) { 10302 if (path == "horizontal" && stop.time - start.time < durationThreshold && abs(start.coords[0] - stop.coords[0]) > horizontalDistanceThreshold && abs(start.coords[1] - stop.coords[1]) < verticalDistanceThreshold) { 10303 if (start.coords[0] > stop.coords[0]) { 10304 if (vars.current == vars.total - 1 && !opts.infinite) repositionHolders(); 10305 else { 10306 vars.isSwipe = true; 10307 iL.moveTo('next'); 10308 } 10309 } else { 10310 if (vars.current == 0 && !opts.infinite) repositionHolders(); 10311 else { 10312 vars.isSwipe = true; 10313 iL.moveTo('prev'); 10314 } 10315 } 10316 } 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) { 10317 if (start.coords[1] > stop.coords[1]) { 10318 if (vars.current == vars.total - 1 && !opts.infinite) repositionHolders(); 10319 else { 10320 vars.isSwipe = true; 10321 iL.moveTo('next'); 10322 } 10323 } else { 10324 if (vars.current == 0 && !opts.infinite) repositionHolders(); 10325 else { 10326 vars.isSwipe = true; 10327 iL.moveTo('prev'); 10328 } 10329 } 10330 } else repositionHolders(); 10331 } 10332 start = stop = undefined; 10333 }); 10334 }); 10335 10336 }, 10337 10338 goTo: function(index) { 10339 var iL = this, 10340 vars = iL.vars, 10341 opts = iL.options, 10342 diff = (index - vars.current); 10343 10344 if (opts.infinite) { 10345 if (index == vars.total - 1 && vars.current == 0) diff = -1; 10346 if (vars.current == vars.total - 1 && index == 0) diff = 1; 10347 } 10348 10349 if (diff == 1) iL.moveTo('next'); 10350 else if (diff == -1) iL.moveTo('prev'); 10351 else { 10352 10353 if (vars.nextLock || vars.prevLock) return false;
10354 10355 //Trigger the onBeforeChange callback 10356 if (typeof opts.callback.onBeforeChange == 'function') opts.callback.onBeforeChange.call(iL, iL.ui); 10357 10358 if (opts.linkId) { 10359 vars.hashLock = true; 10360 window.location.hash = opts.linkId + '/' + index; 10361 } 10362 10363 if (iL.items[index]) { 10364 if (!iL.items[index].options.mousewheel) vars.lockWheel = true; 10365 else iL.vars.lockWheel = false; 10366 10367 if (!iL.items[index].options.swipe) vars.lockSwipe = true; 10368 else vars.lockSwipe = false; 10369 } 10370 10371 $.each([vars.holder, vars.nextPhoto, vars.prevPhoto], function(key, val) { 10372 val.css(transform, gpuAcceleration).fadeOut(opts.effects.loadedFadeSpeed); 10373 }); 10374 10375 vars.current = index; 10376 vars.next = index + 1; 10377 vars.prev = index - 1; 10378 10379 iL.createUI(); 10380 10381 setTimeout(function() { 10382 iL.generateBoxes(); 10383 }, opts.effects.loadedFadeSpeed + 50); 10384 10385 $('.ilightbox-thumbnail', vars.thumbnails).removeClass('ilightbox-active').eq(index).addClass('ilightbox-active'); 10386 iL.positionThumbnails(); 10387 10388 if (opts.linkId) setTimeout(function() { 10389 vars.hashLock = false; 10390 }, 55); 10391 10392 // Configure arrow buttons 10393 if (!opts.infinite) { 10394 vars.nextButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled'); 10395 10396 if (vars.current == 0) { 10397 vars.prevButton.add(vars.innerPrevButton).addClass('disabled'); 10398 } 10399 if (vars.current >= vars.total - 1) { 10400 vars.nextButton.add(vars.innerNextButton).addClass('disabled'); 10401 } 10402 } 10403 10404 // Reset next cycle timeout 10405 iL.resetCycle(); 10406 10407 //Trigger the onAfterChange callback 10408 if (typeof opts.callback.onAfterChange == 'function') opts.callback.onAfterChange.call(iL, iL.ui); 10409 } 10410 }, 10411 10412 moveTo: function(side) { 10413 var iL = this, 10414 vars = iL.vars, 10415 opts = iL.options, 10416 path = opts.path.toLowerCase(), 10417 viewport = getViewport(), 10418 switchSpeed = opts.effects.switchSpeed; 10419 10420 if (vars.nextLock || vars.prevLock) return false; 10421 else { 10422 10423 var item = (side == "next") ? vars.next : vars.prev; 10424 10425 if (opts.linkId) { 10426 vars.hashLock = true; 10427 window.location.hash = opts.linkId + '/' + item; 10428 } 10429 10430 if (side == "next") { 10431 if (!iL.items[item]) return false; 10432 var firstHolder = vars.nextPhoto, 10433 secondHolder = vars.holder, 10434 lastHolder = vars.prevPhoto, 10435 firstClass = 'ilightbox-prev', 10436 secondClass = 'ilightbox-next'; 10437 } else if (side == "prev") { 10438 if (!iL.items[item]) return false; 10439 var firstHolder = vars.prevPhoto, 10440 secondHolder = vars.holder, 10441 lastHolder = vars.nextPhoto, 10442 firstClass = 'ilightbox-next', 10443 secondClass = 'ilightbox-prev'; 10444 } 10445 10446 //Trigger the onBeforeChange callback 10447 if (typeof opts.callback.onBeforeChange == 'function') 10448 opts.callback.onBeforeChange.call(iL, iL.ui); 10449 10450 (side == "next") ? vars.nextLock = true: vars.prevLock = true; 10451 10452 var captionFirst = $('div.ilightbox-caption', secondHolder), 10453 socialFirst = $('div.ilightbox-social', secondHolder); 10454 10455 if (captionFirst.length) 10456 captionFirst.stop().fadeOut(switchSpeed, function() { 10457 $(this).remove(); 10458 }); 10459 if (socialFirst.length) 10460 socialFirst.stop().fadeOut(switchSpeed, function() { 10461 $(this).remove(); 10462 }); 10463 10464 if (iL.items[item].caption) { 10465 iL.setCaption(iL.items[item], firstHolder); 10466 var caption = $('div.ilightbox-caption', firstHolder), 10467 percent = parseInt((caption.outerHeight() / firstHolder.outerHeight()) * 100); 10468 if (opts.caption.start && percent <= 50) caption.fadeIn(switchSpeed); 10469 } 10470 10471 var social = iL.items[item].options.social; 10472 if (social) { 10473 iL.setSocial(social, iL.items[item].URL, firstHolder); 10474 if (opts.social.start) $('div.ilightbox-social', firstHolder).fadeIn(opts.effects.fadeSpeed); 10475 } 10476 10477 $.each([firstHolder, secondHolder, lastHolder], function(key, val) { 10478 val.removeClass('ilightbox-next ilightbox-prev'); 10479 }); 10480 10481 var firstOffset = firstHolder.data('offset'), 10482 winW = (viewport.width - (opts.styles.pageOffsetX)), 10483 winH = (viewport.height - (opts.styles.pageOffsetY)), 10484 width = firstOffset.newDims.width, 10485 height = firstOffset.newDims.height, 10486 thumbsOffset = firstOffset.thumbsOffset, 10487 diff = firstOffset.diff, 10488 top = parseInt((winH / 2) - (height / 2) - diff.H - (thumbsOffset.H / 2)), 10489 left = parseInt((winW / 2) - (width / 2) - diff.W - (thumbsOffset.W / 2)); 10490 10491 var secondOffset = secondHolder.data('offset'), 10492 object = secondOffset.object; 10493 10494 /*if (object.item.caption && !isNaN(width) && !isNaN(height) && UNCODE.wwidth > UNCODE.mediaQuery) { 10495 var objRatio = width / height; 10496 height = height - vars.captionHeight; 10497 width = height * objRatio; 10498 top = path == 'horizontal' ? parseInt((winH / 2) - (height / 2) - diff.H - (thumbsOffset.H / 2)) : top, 10499 left = parseInt((winW / 2) - (width / 2) - diff.W - (thumbsOffset.W / 2)); 10500 }*/ 10501 10502 firstHolder.show().css(transform, gpuAcceleration).animate({ 10503 top: top, 10504 left: left, 10505 opacity: 1 10506 }, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc', function() { 10507 firstHolder.css(transform, ''); 10508 }); 10509 10510 $('div.ilightbox-container', firstHolder).animate({ 10511 width: width, 10512 height: height 10513 }, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc'); 10514 10515 diff = secondOffset.diff; 10516 10517 width = secondOffset.newDims.width, 10518 height = secondOffset.newDims.height; 10519 10520 width = parseInt(width * opts.styles[side == 'next' ? 'prevScale' : 'nextScale']), 10521 height = parseInt(height * opts.styles[side == 'next' ? 'prevScale' : 'nextScale']), 10522 top = (path == 'horizontal') ? parseInt((winH / 2) - object.offsetY - (height / 2) - diff.H - (thumbsOffset.H / 2)) : parseInt(winH - object.offsetX - diff.H - (thumbsOffset.H / 2)); 10523 10524 if (side == 'prev') 10525 left = (path == 'horizontal') ? parseInt(winW - object.offsetX - diff.W - (thumbsOffset.W / 2)) : parseInt((winW / 2) - (width / 2) - diff.W - object.offsetY - (thumbsOffset.W / 2)); 10526 else { 10527 top = (path == 'horizontal') ? top : parseInt(object.offsetX - diff.H - height - (thumbsOffset.H / 2)), 10528 left = (path == 'horizontal') ? parseInt(object.offsetX - diff.W - width - (thumbsOffset.W / 2)) : parseInt((winW / 2) - object.offsetY - (width / 2) - diff.W - (thumbsOffset.W / 2)); 10529 } 10530 10531 /*if (object.item.caption && !isNaN(width) && !isNaN(height) && UNCODE.wwidth > UNCODE.mediaQuery) { 10532 var objRatio = width / height; 10533 height = height - vars.captionHeight; 10534 width = height * objRatio; 10535 top = path == 'horizontal' ? parseInt((winH / 2) - (height / 2) - diff.H - (thumbsOffset.H / 2)) : top; 10536 }*/ 10537 10538 $('div.ilightbox-container', secondHolder).animate({ 10539 width: width, 10540 height: height 10541 }, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc'); 10542 10543 secondHolder.addClass(firstClass).css(transform, gpuAcceleration).animate({ 10544 top: top, 10545 left: left, 10546 opacity: opts.styles.prevOpacity, 10547 }, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc', function() { 10548 secondHolder.css(transform, ''); 10549
10550 $('.ilightbox-thumbnail', vars.thumbnails).removeClass('ilightbox-active').eq(item).addClass('ilightbox-active'); 10551 iL.positionThumbnails(); 10552 10553 if (iL.items[item]) { 10554 if (!iL.items[item].options.mousewheel) vars.lockWheel = true; 10555 else vars.lockWheel = false; 10556 10557 if (!iL.items[item].options.swipe) vars.lockSwipe = true; 10558 else vars.lockSwipe = false; 10559 } 10560 10561 vars.isSwipe = false; 10562 10563 // Remove iframe & video from previous slide 10564 if (['iframe', 'video'].indexOf(iL.items[vars.current].type) !== -1) { 10565 $('div.ilightbox-container', secondHolder).empty(); 10566 } 10567 10568 if (side == "next") { 10569 vars.nextPhoto = lastHolder, 10570 vars.prevPhoto = secondHolder, 10571 vars.holder = firstHolder; 10572 10573 vars.nextPhoto.hide(); 10574 10575 vars.next = vars.next + 1, 10576 vars.prev = vars.current, 10577 vars.current = vars.current + 1; 10578 10579 if (opts.infinite) { 10580 if (vars.current > vars.total - 1) vars.current = 0; 10581 if (vars.current == vars.total - 1) vars.next = 0; 10582 if (vars.current == 0) vars.prev = vars.total - 1; 10583 } 10584 10585 iL.createUI(); 10586 10587 if (!iL.items[vars.next]) 10588 vars.nextLock = false; 10589 else 10590 iL.loadContent(iL.items[vars.next], 'next'); 10591 } else { 10592 vars.prevPhoto = lastHolder; 10593 vars.nextPhoto = secondHolder; 10594 vars.holder = firstHolder; 10595 10596 vars.prevPhoto.hide(); 10597 10598 vars.next = vars.current; 10599 vars.current = vars.prev; 10600 vars.prev = vars.current - 1; 10601 10602 if (opts.infinite) { 10603 if (vars.current == vars.total - 1) vars.next = 0; 10604 if (vars.current == 0) vars.prev = vars.total - 1; 10605 } 10606 10607 iL.createUI(); 10608 10609 if (!iL.items[vars.prev]) 10610 vars.prevLock = false; 10611 else 10612 iL.loadContent(iL.items[vars.prev], 'prev'); 10613 } 10614 10615 // Add iframe & video content for current slide 10616 if (['iframe', 'video'].indexOf(iL.items[vars.current].type) !== -1) { 10617 iL.loadContent(iL.items[vars.current], 'current'); 10618 } 10619 10620 if (opts.linkId) setTimeout(function() { 10621 vars.hashLock = false; 10622 }, 55); 10623 10624 // Configure arrow buttons 10625 if (!opts.infinite) { 10626 vars.nextButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled'); 10627 10628 if (vars.current == 0) 10629 vars.prevButton.add(vars.innerPrevButton).addClass('disabled'); 10630 if (vars.current >= vars.total - 1) 10631 vars.nextButton.add(vars.innerNextButton).addClass('disabled'); 10632 } 10633 10634 iL.repositionPhoto(); 10635 10636 // Reset next cycle timeout 10637 iL.resetCycle(); 10638 10639 //Trigger the onAfterChange callback 10640 if (typeof opts.callback.onAfterChange == 'function') 10641 opts.callback.onAfterChange.call(iL, iL.ui); 10642 }); 10643 10644 top = (path == 'horizontal') ? getPixel(lastHolder, 'top') : ((side == "next") ? parseInt(-(winH / 2) - lastHolder.outerHeight()) : parseInt(top * 2)), 10645 left = (path == 'horizontal') ? ((side == "next") ? parseInt(-(winW / 2) - lastHolder.outerWidth()) : parseInt(left * 2)) : getPixel(lastHolder, 'left'); 10646 10647 lastHolder.css(transform, gpuAcceleration).animate({ 10648 top: top, 10649 left: left, 10650 opacity: opts.styles.nextOpacity 10651 }, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc', function() { 10652 lastHolder.css(transform, ''); 10653 }).addClass(secondClass); 10654 } 10655 }, 10656 10657 setCaption: function(obj, target) { 10658 var iL = this, 10659 caption = $('<div class="ilightbox-caption"></div>'); 10660 10661 if (obj.caption) { 10662 caption.html(obj.caption); 10663 $('div.ilightbox-container', target).append(caption); 10664 } 10665 }, 10666 10667 normalizeSocial: function(obj, url) { 10668 var iL = this, 10669 vars = iL.vars, 10670 opts = iL.options, 10671 baseURL = window.location.href; 10672 10673 $.each(obj, function(key, value) { 10674 if (!value) 10675 return true; 10676 10677 var item = key.toLowerCase(), 10678 source, text; 10679 10680 switch (item) { 10681 case 'facebook': 10682 source = "http://www.facebook.com/share.php?v=4&src=bm&u={URL}", 10683 text = "Share on Facebook"; 10684 break; 10685 case 'twitter': 10686 source = "http://twitter.com/home?status={URL}", 10687 text = "Share on Twitter"; 10688 break; 10689 case 'googleplus': 10690 source = "https://plus.google.com/share?url={URL}", 10691 text = "Share on Google+"; 10692 break; 10693 case 'delicious': 10694 source = "http://delicious.com/post?url={URL}", 10695 text = "Share on Delicious"; 10696 break; 10697 case 'digg': 10698 source = "http://digg.com/submit?phase=2&url={URL}", 10699 text = "Share on Digg"; 10700 break; 10701 case 'reddit': 10702 source = "http://reddit.com/submit?url={URL}", 10703 text = "Share on reddit"; 10704 break; 10705 } 10706 10707 obj[key] = { 10708 URL: value.URL && absolutizeURI(baseURL, value.URL) || opts.linkId && window.location.href || typeof url !== 'string' && baseURL || url && absolutizeURI(baseURL, url) || baseURL, 10709 source: value.source || source || value.URL && absolutizeURI(baseURL, value.URL) || url && absolutizeURI(baseURL, url), 10710 text: value.text || text || "Share on " + key, 10711 width: (typeof(value.width) != 'undefined' && !isNaN(value.width)) ? parseInt(value.width) : 640, 10712 height: value.height || 360 10713 }; 10714 10715 }); 10716 10717 return obj; 10718 }, 10719 10720 setSocial: function(obj, url, target) { 10721 var iL = this, 10722 socialBar = $('<div class="ilightbox-social"></div>'), 10723 buttons = '<ul>'; 10724 10725 obj = iL.normalizeSocial(obj, url); 10726 10727 $.each(obj, function(key, value) { 10728 var item = key.toLowerCase(), 10729 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, '+')); 10730 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>'; 10731 }); 10732 10733 buttons += '</ul>'; 10734 10735 socialBar.html(buttons); 10736 $('div.ilightbox-container', target).append(socialBar); 10737 }, 10738 10739 fullScreenAction: function() { 10740 var iL = this, 10741 vars = iL.vars; 10742 10743 if (fullScreenApi.supportsFullScreen) { 10744 if (fullScreenApi.isFullScreen()) fullScreenApi.cancelFullScreen(document.documentElement); 10745 else fullScreenApi.requestFullScreen(document.documentElement); 10746 } else { 10747 iL.doFullscreen(); 10748 } 10749 }, 10750 10751 doFullscreen: function() { 10752 var iL = this, 10753 vars = iL.vars, 10754 viewport = getViewport(), 10755 opts = iL.options; 10756 10757 if (opts.fullAlone) { 10758 var currentHolder = vars.holder, 10759 current = iL.items[vars.current], 10760 windowWidth = viewport.width, 10761 windowHeight = viewport.height, 10762 elements = [currentHolder, vars.nextPhoto, vars.prevPhoto, vars.nextButton, vars.prevButton, vars.overlay, vars.toolbar, vars.thumbnails, vars.loader], 10763 hideElements = [vars.nextPhoto, vars.prevPhoto, vars.nextButton, vars.prevButton, vars.loader, vars.thumbnails]; 10764 10765 if (!vars.isInFullScreen) { 10766 vars.isInFullScreen = vars.lockKey = vars.lockWheel = vars.lockSwipe = true; 10767 vars.overlay.css({ 10768 opacity: 1 10769 }); 10770 10771 $.each(hideElements, function(i, element) { 10772 element.hide(); 10773 }); 10774 10775 vars.fullScreenButton.attr('title', opts.text.exitFullscreen); 10776 10777 if (opts.fullStretchTypes.indexOf(current.type) != -1) currentHolder.data({
10778 naturalWidthOld: currentHolder.data('naturalWidth'), 10779 naturalHeightOld: currentHolder.data('naturalHeight'), 10780 naturalWidth: windowWidth, 10781 naturalHeight: windowHeight 10782 }); 10783 else { 10784 var viewport = current.options.fullViewPort || opts.fullViewPort || '', 10785 newWidth = windowWidth, 10786 newHeight = windowHeight, 10787 width = currentHolder.data('naturalWidth'), 10788 height = currentHolder.data('naturalHeight'); 10789 10790 if (viewport.toLowerCase() == 'fill') { 10791 newHeight = (newWidth / width) * height; 10792 10793 if (newHeight < windowHeight) { 10794 newWidth = (windowHeight / height) * width, 10795 newHeight = windowHeight; 10796 } 10797 } else if (viewport.toLowerCase() == 'fit') { 10798 var dims = iL.getNewDimenstions(newWidth, newHeight, width, height, true); 10799 10800 newWidth = dims.width, 10801 newHeight = dims.height; 10802 } else if (viewport.toLowerCase() == 'stretch') { 10803 newWidth = newWidth, 10804 newHeight = newHeight; 10805 } else { 10806 var scale = (width > newWidth || height > newHeight) ? true : false, 10807 dims = iL.getNewDimenstions(newWidth, newHeight, width, height, scale); 10808 newWidth = dims.width, 10809 newHeight = dims.height; 10810 } 10811 10812 currentHolder.data({ 10813 naturalWidthOld: currentHolder.data('naturalWidth'), 10814 naturalHeightOld: currentHolder.data('naturalHeight'), 10815 naturalWidth: newWidth, 10816 naturalHeight: newHeight 10817 }); 10818 } 10819 10820 $.each(elements, function(key, val) { 10821 val.addClass('ilightbox-fullscreen'); 10822 }); 10823 10824 //Trigger the onEnterFullScreen callback 10825 if (typeof opts.callback.onEnterFullScreen == 'function') opts.callback.onEnterFullScreen.call(iL, iL.ui); 10826 } else { 10827 vars.isInFullScreen = vars.lockKey = vars.lockWheel = vars.lockSwipe = false; 10828 vars.overlay.css({ 10829 opacity: iL.options.overlay.opacity 10830 }); 10831 10832 $.each(hideElements, function(i, element) { 10833 element.show(); 10834 }); 10835 10836 vars.fullScreenButton.attr('title', opts.text.enterFullscreen); 10837 10838 currentHolder.data({ 10839 naturalWidth: currentHolder.data('naturalWidthOld'), 10840 naturalHeight: currentHolder.data('naturalHeightOld'), 10841 naturalWidthOld: null, 10842 naturalHeightOld: null 10843 }); 10844 10845 $.each(elements, function(key, val) { 10846 val.removeClass('ilightbox-fullscreen'); 10847 }); 10848 10849 //Trigger the onExitFullScreen callback 10850 if (typeof opts.callback.onExitFullScreen == 'function') opts.callback.onExitFullScreen.call(iL, iL.ui); 10851 } 10852 } else { 10853 if (!vars.isInFullScreen) vars.isInFullScreen = true; 10854 else vars.isInFullScreen = false; 10855 } 10856 iL.repositionPhoto(true); 10857 }, 10858 10859 closeAction: function() { 10860 var iL = this, 10861 vars = iL.vars, 10862 opts = iL.options; 10863 10864 $win.unbind('.iLightBox'); 10865 $doc.off('.iLightBox'); 10866 10867 if (vars.isInFullScreen) fullScreenApi.cancelFullScreen(document.documentElement); 10868 10869 $('.ilightbox-overlay, .ilightbox-holder, .ilightbox-thumbnails').off('.iLightBox'); 10870 10871 if (opts.hide.effect) vars.overlay.stop().fadeOut(opts.hide.speed, function() { 10872 vars.overlay.remove(); 10873 vars.BODY.removeClass('ilightbox-noscroll').off('.iLightBox'); 10874 }); 10875 else { 10876 vars.overlay.remove(); 10877 vars.BODY.removeClass('ilightbox-noscroll').off('.iLightBox'); 10878 } 10879 10880 var fadeOuts = [vars.toolbar, vars.holder, vars.nextPhoto, vars.prevPhoto, vars.nextButton, vars.prevButton, vars.loader, vars.thumbnails]; 10881 10882 $.each(fadeOuts, function(i, element) { 10883 element.removeAttr('style').remove(); 10884 }); 10885 10886 vars.dontGenerateThumbs = vars.isInFullScreen = false; 10887 10888 window.iLightBox = null; 10889 10890 if (opts.linkId) { 10891 vars.hashLock = true; 10892 removeHash(); 10893 setTimeout(function() { 10894 vars.hashLock = false; 10895 }, 55); 10896 } 10897 10898 //Trigger the onHide callback 10899 if (typeof opts.callback.onHide == 'function') opts.callback.onHide.call(iL, iL.ui); 10900 }, 10901 10902 repositionPhoto: function() { 10903 var iL = this, 10904 vars = iL.vars, 10905 opts = iL.options, 10906 path = opts.path.toLowerCase(), 10907 viewport = getViewport(), 10908 winWidth = viewport.width, 10909 winHeight = viewport.height; 10910 10911 if (viewport.width < UNCODE.mediaQuery) opts.styles.nextOffsetX = 0; 10912 10913 var thumbsOffsetW = (vars.isInFullScreen && opts.fullAlone || vars.isMobile) ? 0 : ((path == 'horizontal') ? 0 : vars.thumbnails.outerWidth()), 10914 thumbsOffsetH = vars.isMobile ? vars.toolbar.outerHeight() : ((vars.isInFullScreen && opts.fullAlone) ? 0 : ((path == 'horizontal') ? vars.thumbnails.outerHeight() : 0)), 10915 width = (vars.isInFullScreen && opts.fullAlone) ? winWidth : (winWidth - (opts.styles.pageOffsetX)), 10916 height = (vars.isInFullScreen && opts.fullAlone) ? winHeight : (winHeight - (opts.styles.pageOffsetY)), 10917 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, 10918 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))); 10919 10920 var elObject = { 10921 type: 'current', 10922 width: width, 10923 height: height, 10924 item: iL.items[vars.current], 10925 offsetW: offsetW, 10926 offsetH: offsetH,
10927 thumbsOffsetW: thumbsOffsetW, 10928 thumbsOffsetH: thumbsOffsetH, 10929 animate: arguments.length, 10930 holder: vars.holder 10931 }; 10932 10933 iL.repositionEl(elObject); 10934 10935 if (iL.items[vars.next]) { 10936 elObject = $.extend(elObject, { 10937 type: 'next', 10938 item: iL.items[vars.next], 10939 offsetX: opts.styles.nextOffsetX, 10940 offsetY: opts.styles.nextOffsetY, 10941 holder: vars.nextPhoto 10942 }); 10943 10944 iL.repositionEl(elObject); 10945 } 10946 10947 if (iL.items[vars.prev]) { 10948 elObject = $.extend(elObject, { 10949 type: 'prev', 10950 item: iL.items[vars.prev], 10951 offsetX: opts.styles.nextOffsetX, 10952 offsetY: opts.styles.prevOffsetY, 10953 holder: vars.prevPhoto 10954 }); 10955 10956 iL.repositionEl(elObject); 10957 } 10958 10959 var loaderCss = (path == "horizontal") ? { 10960 left: parseInt((width / 2) - (vars.loader.outerWidth() / 2)) 10961 } : { 10962 top: parseInt((height / 2) - (vars.loader.outerHeight() / 2)) 10963 }; 10964 vars.loader.css(loaderCss); 10965 }, 10966 10967 repositionEl: function(obj) { 10968 var iL = this, 10969 vars = iL.vars, 10970 opts = iL.options, 10971 path = opts.path.toLowerCase(), 10972 widthAvail = (obj.type == 'current') ? ((vars.isInFullScreen && opts.fullAlone) ? obj.width : (obj.width - obj.offsetW)) : (obj.width - obj.offsetW), 10973 heightAvail = (obj.type == 'current') ? ((vars.isInFullScreen && opts.fullAlone) ? obj.height : (obj.height - obj.offsetH)) : (obj.height - obj.offsetH), 10974 itemParent = obj.item, 10975 item = obj.item.options, 10976 holder = obj.holder, 10977 offsetX = obj.offsetX || 0, 10978 offsetY = obj.offsetY || 0, 10979 thumbsOffsetW = obj.thumbsOffsetW, 10980 thumbsOffsetH = obj.thumbsOffsetH; 10981 10982 if (obj.type == 'current') { 10983 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); 10984 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); 10985 } else { 10986 if (typeof item.width == 'number' && item.width) widthAvail = (item.width > widthAvail) ? widthAvail : item.width; 10987 if (typeof item.height == 'number' && item.height) heightAvail = (item.height > heightAvail) ? heightAvail : item.height; 10988 } 10989 10990 heightAvail = parseInt(heightAvail - $('.ilightbox-inner-toolbar', holder).outerHeight()); 10991 10992 var width = (typeof item.width == 'string' && item.width.indexOf('%') != -1) ? percentToValue(parseInt(item.width.replace('%', '')), obj.width) : holder.data('naturalWidth'), 10993 height = (typeof item.height == 'string' && item.height.indexOf('%') != -1) ? percentToValue(parseInt(item.height.replace('%', '')), obj.height) : holder.data('naturalHeight'); 10994 10995 var dims = ((typeof item.width == 'string' && item.width.indexOf('%') != -1 || typeof item.height == 'string' && item.height.indexOf('%') != -1) ? { 10996 width: width, 10997 height: height 10998 } : iL.getNewDimenstions(widthAvail, heightAvail, width, height)), 10999 newDims = $.extend({}, dims, {}); 11000 11001 if (obj.type == 'prev' || obj.type == 'next') 11002 width = parseInt(dims.width * ((obj.type == 'next') ? opts.styles.nextScale : opts.styles.prevScale)), 11003 height = parseInt(dims.height * ((obj.type == 'next') ? opts.styles.nextScale : opts.styles.prevScale)); 11004 else 11005 width = dims.width, 11006 height = dims.height; 11007 11008 var widthDiff = parseInt((getPixel(holder, 'padding-left') + getPixel(holder, 'padding-right') + getPixel(holder, 'border-left-width') + getPixel(holder, 'border-right-width')) / 2), 11009 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); 11010 11011 switch (obj.type) { 11012 case 'current': 11013 var top = parseInt((obj.height / 2) - (height / 2) - heightDiff - (thumbsOffsetH / 2)), 11014 left = parseInt((obj.width / 2) - (width / 2) - widthDiff - (thumbsOffsetW / 2)); 11015 break; 11016
11017 case 'next': 11018 var top = (path == 'horizontal') ? parseInt((obj.height / 2) - offsetY - (height / 2) - heightDiff - (thumbsOffsetH / 2)) : parseInt(obj.height - offsetX - heightDiff - (thumbsOffsetH / 2)), 11019 left = (path == 'horizontal') ? parseInt(obj.width - offsetX - widthDiff - (thumbsOffsetW / 2)) : parseInt((obj.width / 2) - (width / 2) - widthDiff - offsetY - (thumbsOffsetW / 2)); 11020 break; 11021 11022 case 'prev': 11023 var top = (path == 'horizontal') ? parseInt((obj.height / 2) - offsetY - (height / 2) - heightDiff - (thumbsOffsetH / 2)) : parseInt(offsetX - heightDiff - height - (thumbsOffsetH / 2)), 11024 left = (path == 'horizontal') ? parseInt(offsetX - widthDiff - width - (thumbsOffsetW / 2)) : parseInt((obj.width / 2) - offsetY - (width / 2) - widthDiff - (thumbsOffsetW / 2)); 11025 break; 11026 } 11027 11028 holder.data('offset', { 11029 top: top, 11030 left: left, 11031 newDims: newDims, 11032 diff: { 11033 W: widthDiff, 11034 H: heightDiff 11035 }, 11036 thumbsOffset: { 11037 W: thumbsOffsetW, 11038 H: thumbsOffsetH 11039 }, 11040 object: obj 11041 }); 11042 11043 var opacityMobile; 11044 if ( isMobile ) { 11045 opacityMobile = { 11046 opacity: 1, 11047 top: top, 11048 left: left 11049 }; 11050 } else { 11051 opacityMobile = { 11052 top: top, 11053 left: left 11054 }; 11055 } 11056 11057 if (obj.animate > 0 && opts.effects.reposition) { 11058 holder.css(transform, gpuAcceleration).stop().animate( 11059 opacityMobile, 11060 opts.effects.repositionSpeed, 'easeOutCirc', function() { 11061 holder.css(transform, ''); 11062 }); 11063 $('div.ilightbox-container', holder).stop().animate({ 11064 width: width, 11065 height: height 11066 }, opts.effects.repositionSpeed, 'easeOutCirc'); 11067 $('div.ilightbox-inner-toolbar', holder).stop().animate({ 11068 width: width 11069 }, opts.effects.repositionSpeed, 'easeOutCirc', function() { 11070 $(this).css('overflow', 'visible'); 11071 }); 11072 } else { 11073 holder.css(opacityMobile); 11074 $('div.ilightbox-container', holder).css({ 11075 width: width, 11076 height: height 11077 }); 11078 $('div.ilightbox-inner-toolbar', holder).css({ 11079 width: width 11080 }); 11081 } 11082 }, 11083 11084 11085 resume: function(priority) { 11086 var iL = this, 11087 vars = iL.vars, 11088 opts = iL.options; 11089 11090 if (!opts.slideshow.pauseTime || opts.controls.slideshow && vars.total <= 1 || priority < vars.isPaused) { 11091 return; 11092 } 11093 11094 vars.isPaused = 0; 11095 11096 if (vars.cycleID) { 11097 vars.cycleID = clearTimeout(vars.cycleID); 11098 } 11099 11100 vars.cycleID = setTimeout(function() { 11101 if (vars.current == vars.total - 1) iL.goTo(0); 11102 else iL.moveTo('next'); 11103 }, opts.slideshow.pauseTime); 11104 }, 11105 11106 pause: function(priority) { 11107 var iL = this, 11108 vars = iL.vars, 11109 opts = iL.options; 11110 11111 if (priority < vars.isPaused) { 11112 return; 11113 } 11114 11115 vars.isPaused = priority || 100; 11116 11117 if (vars.cycleID) { 11118 vars.cycleID = clearTimeout(vars.cycleID); 11119 } 11120 }, 11121 11122 resetCycle: function() { 11123 var iL = this, 11124 vars = iL.vars, 11125 opts = iL.options; 11126 11127 if (opts.controls.slideshow && vars.cycleID && !vars.isPaused) { 11128 iL.resume(); 11129 } 11130 }, 11131 11132 getNewDimenstions: function(width, height, width_old, height_old, thumb) { 11133 var iL = this; 11134 11135 if (!width) factor = height / height_old; 11136 else if (!height) factor = width / width_old; 11137 else factor = min(width / width_old, height / height_old); 11138 11139 if (!thumb) { 11140 if (factor > iL.options.maxScale) factor = iL.options.maxScale; 11141 else if (factor < iL.options.minScale) factor = iL.options.minScale; 11142 } 11143 11144 var final_width = (iL.options.keepAspectRatio) ? round(width_old * factor) : width, 11145 final_height = (iL.options.keepAspectRatio) ? round(height_old * factor) : height; 11146 11147 return { 11148 width: final_width, 11149 height: final_height, 11150 ratio: factor 11151 }; 11152 }, 11153 11154 setOption: function(options) { 11155 var iL = this; 11156 11157 iL.options = $.extend(true, iL.options, options || {}); 11158 iL.refresh(); 11159 }, 11160 11161 availPlugins: function() { 11162 var iL = this, 11163 testEl = document.createElement("video"); 11164 11165 iL.plugins = { 11166 flash: !isMobile, 11167 quicktime: (parseInt(PluginDetect.getVersion("QuickTime")) >= 0) ? true : false, 11168 html5H264: !!(testEl.canPlayType && testEl.canPlayType('video/mp4').replace(/no/, '')), 11169 html5WebM: !!(testEl.canPlayType && testEl.canPlayType('video/webm').replace(/no/, '')), 11170 html5Vorbis: !!(testEl.canPlayType && testEl.canPlayType('video/ogg').replace(/no/, '')), 11171 html5QuickTime: !!(testEl.canPlayType && testEl.canPlayType('video/quicktime').replace(/no/, '')) 11172 }; 11173 }, 11174 11175 addContent: function(element, obj) { 11176 var iL = this, 11177 el; 11178 11179 switch (obj.type) { 11180 case 'video': 11181 var HTML5 = false, 11182 videoType = obj.videoType, 11183 html5video = obj.options.html5video; 11184 11185 if (((videoType == 'video/mp4' || obj.ext == 'mp4' || obj.ext == 'm4v') || html5video.h264) && iL.plugins.html5H264) 11186 obj.ext = 'mp4', 11187 obj.URL = html5video.h264 || obj.URL; 11188 else if (html5video.webm && iL.plugins.html5WebM) 11189 obj.ext = 'webm', 11190 obj.URL = html5video.webm || obj.URL; 11191 else if (html5video.ogg && iL.plugins.html5Vorbis) 11192 obj.ext = 'ogv', 11193 obj.URL = html5video.ogg || obj.URL; 11194 11195 if (iL.plugins.html5H264 && (videoType == 'video/mp4' || obj.ext == 'mp4' || obj.ext == 'm4v')) HTML5 = true, videoType = "video/mp4"; 11196 else if (iL.plugins.html5WebM && (videoType == 'video/webm' || obj.ext == 'webm')) HTML5 = true, videoType = "video/webm"; 11197 else if (iL.plugins.html5Vorbis && (videoType == 'video/ogg' || obj.ext == 'ogv')) HTML5 = true, videoType = "video/ogg"; 11198 else if (iL.plugins.html5QuickTime && (videoType == 'video/quicktime' || obj.ext == 'mov' || obj.ext == 'qt')) HTML5 = true, videoType = "video/quicktime"; 11199 11200 if (HTML5) { 11201 el = $('<video />
11201', { 11202 "width": "100%", 11203 "height": "100%", 11204 "preload": html5video.preload, 11205 "autoplay": html5video.autoplay, 11206 "loop": html5video.loop, 11207 "poster": html5video.poster, 11208 "controls": html5video.controls, 11209 "controlslist": "nodownload" 11210 }).append($('<source />', { 11211 "src": obj.URL, 11212 "type": videoType 11213 })); 11214 } else { 11215 if (!iL.plugins.quicktime) el = $('<span />', { 11216 "class": "ilightbox-alert", 11217 html: iL.options.errors.missingPlugin.replace('{pluginspage}', pluginspages.quicktime).replace('{type}', 'QuickTime') 11218 }); 11219 else { 11220 11221 el = $('<object />', { 11222 "type": "video/quicktime", 11223 "pluginspage": pluginspages.quicktime 11224 }).attr({ 11225 "data": obj.URL, 11226 "width": "100%", 11227 "height": "100%" 11228 }).append($('<param />', { 11229 "name": "src", 11230 "value": obj.URL 11231 })).append($('<param />', { 11232 "name": "autoplay", 11233 "value": "false" 11234 })).append($('<param />', { 11235 "name": "loop", 11236 "value": "false" 11237 })).append($('<param />', { 11238 "name": "scale", 11239 "value": "tofit" 11240 })); 11241 11242 if (browser.msie) el = QT_GenerateOBJECTText(obj.URL, '100%', '100%', '', 'SCALE', 'tofit', 'AUTOPLAY', 'false', 'LOOP', 'false'); 11243 } 11244 } 11245 11246 break; 11247 11248 case 'flash': 11249 if (!iL.plugins.flash) el = $('<span />', { 11250 "class": "ilightbox-alert", 11251 html: iL.options.errors.missingPlugin.replace('{pluginspage}', pluginspages.flash).replace('{type}', 'Adobe Flash player') 11252 }); 11253 else { 11254 var flashvars = "", 11255 i = 0; 11256 11257 if (obj.options.flashvars) $.each(obj.options.flashvars, function(k, v) { 11258 if (i != 0) flashvars += "&"; 11259 flashvars += k + "=" + encodeURIComponent(v); 11260 i++; 11261 }); 11262 else flashvars = null; 11263 11264 el = $('<embed />').attr({ 11265 "type": "application/x-shockwave-flash", 11266 "src": obj.URL, 11267 "width": (typeof obj.options.width == 'number' && obj.options.width && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.width : "100%", 11268 "height": (typeof obj.options.height == 'number' && obj.options.height && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.height : "100%", 11269 "quality": "high", 11270 "bgcolor": "#000000", 11271 "play": "true", 11272 "loop": "true", 11273 "menu": "true", 11274 "wmode": "transparent", 11275 "scale": "showall", 11276 "allowScriptAccess": "always", 11277 "allowFullScreen": "true", 11278 "flashvars": flashvars, 11279 "fullscreen": "yes" 11280 }); 11281 } 11282 11283 break; 11284 11285 case 'iframe': 11286 el = $('<iframe />').attr({ 11287 "width": (typeof obj.options.width == 'number' && obj.options.width && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.width : "100%", 11288 "height": (typeof obj.options.height == 'number' && obj.options.height && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.height : "100%", 11289 src: obj.URL, 11290 frameborder: 0, 11291 'hspace': 0, 11292 'vspace': 0, 11293 'scrolling': supportTouch ? 'auto' : 'scroll', 11294 'webkitAllowFullScreen': '', 11295 'mozallowfullscreen': '', 11296 'allowFullScreen': '' 11297 }); 11298 11299 break; 11300 11301 case 'inline': 11302 el = $('<div class="ilightbox-wrapper"></div>').html($(obj.URL).clone(true)); 11303 11304 break; 11305 11306 case 'html': 11307 var object = obj.URL, 11308 el; 11309 11310 if (object[0].nodeName) { 11311 el = $('<div class="ilightbox-wrapper"></div>').html(object); 11312 } else { 11313 var dom = $(obj.URL), 11314 html = (dom.selector) ? $('<div>' + dom + '</div>') : dom; 11315 el = $('<div class="ilightbox-wrapper"></div>').html(html); 11316 } 11317 11318 break; 11319 } 11320 11321 $('div.ilightbox-container', element).empty().html(el); 11322 11323 // For fixing Chrome about just playing the video for first time 11324 if (el[0].tagName.toLowerCase() === 'video' && browser.webkit) setTimeout(function() { 11325 var src = el[0].currentSrc + '?' + floor(random() * 30000); 11326 el[0].currentSrc = src; 11327 el[0].src = src; 11328 }); 11329 11330 return el; 11331 }, 11332 11333 ogpRecognition: function(obj, callback) { 11334 var iL = this, 11335 url = obj.URL; 11336 11337 iL.showLoader(); 11338 doAjax(url, function(data) { 11339 iL.hideLoader(); 11340 if (data) { 11341 var object = new Object(); 11342 11343 object.length = false, 11344 object.url = data.url; 11345 11346 if (data.status == 200) { 11347 var result = data.results, 11348 type = result.type, 11349 source = result.source; 11350 11351 object.source = source.src, 11352 object.width = source.width && parseInt(source.width) || 0, 11353 object.height = source.height && parseInt(source.height) || 0, 11354 object.type = type, 11355 object.thumbnail = source.thumbnail || result.images && result.images[0], 11356 object.html5video = result.html5video || {}, 11357 object.length = true; 11358 11359 if (source.type == 'application/x-shockwave-flash') object.type = "flash"; 11360 else if (source.type.indexOf("video/") != -1) object.type = "video"; 11361 else if (source.type.indexOf("/html") != -1) object.type = "iframe"; 11362 else if (source.type.indexOf("image/") != -1) object.type = "image"; 11363 11364 } else if (typeof data.response != 'undefined') 11365 throw data.response; 11366 11367 callback.call(this, object.length ? object : false); 11368 } 11369 }); 11370 }, 11371 11372 hashChangeHandler: function(url) { 11373 var iL = this, 11374 vars = iL.vars, 11375 opts = iL.options, 11376 URL = url || window.location.href, 11377 hash = parseURI(URL).hash, 11378 split = hash.split('/'), 11379 index = split[1]; 11380 11381 if (vars.hashLock || ('#' + opts.linkId != split[0] && hash.length > 1)) return; 11382 11383 if (index) { 11384 var target = split[1] || 0; 11385 if (iL.items[target]) {
11386 var overlay = $('.ilightbox-overlay'); 11387 if (overlay.length && overlay.attr('linkid') == opts.linkId) { 11388 iL.goTo(target); 11389 } else { 11390 iL.itemsObject[target].trigger(supportTouch ? 'itap' : 'click'); 11391 //iL.goTo(target); 11392 } 11393 } else { 11394 var overlay = $('.ilightbox-overlay'); 11395 if (overlay.length) iL.closeAction(); 11396 } 11397 } else { 11398 var overlay = $('.ilightbox-overlay'); 11399 if (overlay.length) iL.closeAction(); 11400 } 11401 } 11402 }; 11403 11404 /** 11405 * Parse style to pixels. 11406 * 11407 * @param {Object} $element jQuery object with element. 11408 * @param {Property} property CSS property to get the pixels from. 11409 * 11410 * @return {Int} 11411 */ 11412 function getPixel($element, property) { 11413 return parseInt($element.css(property), 10) || 0; 11414 } 11415 11416 /** 11417 * Make sure that number is within the limits. 11418 * 11419 * @param {Number} number 11420 * @param {Number} min 11421 * @param {Number} max 11422 * 11423 * @return {Number} 11424 */ 11425 function within(number, min, max) { 11426 return number < min ? min : number > max ? max : number; 11427 } 11428 11429 /** 11430 * Get viewport/window size (width and height). 11431 * 11432 * @return {Object} 11433 */ 11434 function getViewport() { 11435 var e = window, 11436 a = 'inner'; 11437 if (!('innerWidth' in window)) { 11438 a = 'client'; 11439 e = document.documentElement || document.body; 11440 } 11441 return { 11442 width: e[a + 'Width'], 11443 height: e[a + 'Height'] 11444 } 11445 } 11446 11447 /** 11448 * Remove hash tag from the URL 11449 * 11450 * @return {Void} 11451 */ 11452 function removeHash() { 11453 var scroll = getScrollXY(); 11454 11455 //UNCODE change 11456 //window.location.hash = ""; 11457 history.pushState("", document.title, window.location.pathname + window.location.search); 11458 11459 // Restore the scroll offset, should be flicker free 11460 window.scrollTo(scroll.x, scroll.y); 11461 } 11462 11463 /** 11464 * Do the ajax requests with callback. 11465 * 11466 * @param {String} url 11467 * @param {Function} callback 11468 * 11469 * @return {Void} 11470 */ 11471 function doAjax(url, callback) { 11472 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'); 11473 $.ajax({ 11474 url: url, 11475 dataType: 'jsonp' 11476 }); 11477 11478 iLCallback = function(data) { 11479 callback.call(this, data); 11480 }; 11481 } 11482 11483 /** 11484 * Find image from DOM elements 11485 * 11486 * @param {Element} element 11487 * 11488 * @return {Void} 11489 */ 11490 function findImageInElement(element) { 11491 var elements = $('*', element), 11492 imagesArr = new Array(); 11493 11494 elements.each(function() { 11495 var url = "", 11496 element = this; 11497 11498 if ($(element).css("background-image") != "none") { 11499 url = $(element).css("background-image"); 11500 } else if (typeof($(element).attr("src")) != "undefined" && element.nodeName.toLowerCase() == "img") { 11501 url = $(element).attr("src"); 11502 } 11503 11504 if (url.indexOf("gradient") == -1) { 11505 url = url.replace(/url\(\"/g, ""); 11506 url = url.replace(/url\(/g, ""); 11507 url = url.replace(/\"\)/g, ""); 11508 url = url.replace(/\)/g, ""); 11509 11510 var urls = url.split(","); 11511 11512 for (var i = 0; i < urls.length; i++) { 11513 if (urls[i].length > 0 && $.inArray(urls[i], imagesArr) == -1) { 11514 var extra = ""; 11515 if (browser.msie && browser.version < 9) { 11516 extra = "?" + floor(random() * 3000); 11517 } 11518 imagesArr.push(urls[i] + extra); 11519 } 11520 } 11521 } 11522 }); 11523 11524 return imagesArr; 11525 } 11526 11527 /** 11528 * Get file extension. 11529 * 11530 * @param {String} URL 11531 * 11532 * @return {String} 11533 */ 11534 function getExtension(URL) { 11535 if (URL !== null) { 11536 var ext = URL.split('.').pop().toLowerCase(), 11537 extra = ext.indexOf('?') !== -1 ? ext.split('?').pop() : ''; 11538 11539 //UNCODE: fix issue to detect media type with query strings 11540 ext = ext.replace('?'+extra, ''); 11541 11542 return ext.replace(extra, ''); 11543 } 11544 } 11545 11546 /** 11547 * Get type via extension. 11548 * 11549 * @param {String} URL 11550 * 11551 * @return {String} 11552 */ 11553 function getTypeByExtension(URL) { 11554 var type, 11555 ext = getExtension(URL); 11556 11557 if (extensions.image.indexOf(ext) !== -1) type = 'image'; 11558 else if (extensions.flash.indexOf(ext) !== -1) type = 'flash'; 11559 else if (extensions.video.indexOf(ext) !== -1) type = 'video'; 11560 else if (ext.substring(0, 1) == "#") type = 'inline'; //Uncode addition 11561 else type = 'iframe'; 11562 11563 return type; 11564 } 11565 11566 /** 11567 * Return value from percent of a number. 11568 * 11569 * @param {Number} percent 11570 * @param {Number} total 11571 * 11572 * @return {Number} 11573 */ 11574 function percentToValue(percent, total) { 11575 return parseInt((total / 100) * percent); 11576 } 11577 11578 /** 11579 * A JavaScript equivalent of PHP’s parse_url. 11580 * 11581 * @param {String} url The URL to parse. 11582 * 11583 * @return {Mixed} 11584 */ 11585 function parseURI(url) { 11586 var m = String(url).replace(/^\s+|\s+$/g, '').match(/^([^:\/?#]+:)?(\/\/(?:[^:@]*(?::[^:@]*)?@)?(([^:\/?#]*)(?::(\d*))?))?([^?#]*)(\?[^#]*)?(#[\s\S]*)?/); 11587 // authority = '//' + user + ':' + pass '@' + hostname + ':' port 11588 return (m ? { 11589 href: m[0] || '', 11590 protocol: m[1] || '', 11591 authority: m[2] || '', 11592 host: m[3] || '', 11593 hostname: m[4] || '', 11594 port: m[5] || '', 11595 pathname: m[6] || '', 11596 search: m[7] || '', 11597 hash: m[8] || '' 11598 } : null); 11599 } 11600 11601 /** 11602 * Gets the absolute URI. 11603 * 11604 * @param {String} href The relative URL. 11605 * @param {String} base The base URL. 11606 * 11607 * @return {String} The absolute URL. 11608 */ 11609 function absolutizeURI(base, href) { // RFC 3986 11610 var iL = this; 11611 11612 function removeDotSegments(input) { 11613 var output = []; 11614 input.replace(/^(\.\.?(\/|$))+/, '') 11615 .replace(/\/(\.(\/|$))+/g, '/') 11616 .replace(/\/\.\.$/, '/../') 11617 .replace(/\/?[^\/]*/g, function(p) { 11618 if (p === '/..') { 11619 output.pop(); 11620 } else { 11621 output.push(p); 11622 } 11623 }); 11624 return output.join('').replace(/^\//, input.charAt(0) === '/' ? '/' : ''); 11625 } 11626 11627 href = parseURI(href || ''); 11628 base = parseURI(base || ''); 11629 11630 return !href || !base ? null : (href.protocol || base.protocol) + 11631 (href.protocol || href.authority ? href.authority : base.authority) + 11632 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)) + 11633 (href.protocol || href.authority || href.pathname ? href.search : (href.search || base.search)) + 11634 href.hash; 11635 } 11636 11637 /** 11638 * A JavaScript equivalent of PHP’s version_compare. 11639 * 11640 * @param {String} v1 11641 * @param {String} v2 11642 * @param {String} operator
11643 * 11644 * @return {Boolean} 11645 */ 11646 function version_compare(v1, v2, operator) { 11647 this.php_js = this.php_js || {}; 11648 this.php_js.ENV = this.php_js.ENV || {}; 11649 var i = 0, 11650 x = 0, 11651 compare = 0, 11652 vm = { 11653 'dev': -6, 11654 'alpha': -5, 11655 'a': -5, 11656 'beta': -4, 11657 'b': -4, 11658 'RC': -3, 11659 'rc': -3, 11660 '#': -2, 11661 'p': 1, 11662 'pl': 1 11663 }, 11664 prepVersion = function(v) { 11665 v = ('' + v).replace(/[_\-+]/g, '.'); 11666 v = v.replace(/([^.\d]+)/g, '.$1.').replace(/\.{2,}/g, '.'); 11667 return (!v.length ? [-8] : v.split('.')); 11668 }, 11669 numVersion = function(v) { 11670 return !v ? 0 : (isNaN(v) ? vm[v] || -7 : parseInt(v, 10)); 11671 }; 11672 v1 = prepVersion(v1); 11673 v2 = prepVersion(v2); 11674 x = max(v1.length, v2.length); 11675 for (i = 0; i < x; i++) { 11676 if (v1[i] == v2[i]) { 11677 continue; 11678 } 11679 v1[i] = numVersion(v1[i]); 11680 v2[i] = numVersion(v2[i]); 11681 if (v1[i] < v2[i]) { 11682 compare = -1; 11683 break; 11684 } else if (v1[i] > v2[i]) { 11685 compare = 1; 11686 break; 11687 } 11688 } 11689 if (!operator) { 11690 return compare; 11691 } 11692 11693 switch (operator) { 11694 case '>': 11695 case 'gt': 11696 return (compare > 0); 11697 case '>=': 11698 case 'ge': 11699 return (compare >= 0); 11700 case '<=': 11701 case 'le': 11702 return (compare <= 0); 11703 case '==': 11704 case '=': 11705 case 'eq': 11706 return (compare === 0); 11707 case '<>': 11708 case '!=': 11709 case 'ne': 11710 return (compare !== 0); 11711 case '': 11712 case '<': 11713 case 'lt': 11714 return (compare < 0); 11715 default: 11716 return null; 11717 } 11718 } 11719 11720 11721 // Begin the iLightBox plugin 11722 $.fn.iLightBox = function() { 11723 11724 var args = arguments, 11725 opt = ($.isPlainObject(args[0])) ? args[0] : args[1], 11726 items = ($.isArray(args[0]) || typeof args[0] == 'string') ? args[0] : args[1]; 11727 11728 if (!opt) opt = {}; 11729 11730 // Default options. Play carefully. 11731 var options = $.extend(true, { 11732 attr: 'href', 11733 path: 'vertical', 11734 skin: 'dark', 11735 linkId: false, 11736 infinite: false, 11737 startFrom: 0, 11738 randomStart: false, 11739 keepAspectRatio: true, 11740 maxScale: 1, 11741 minScale: .2, 11742 innerToolbar: false, 11743 smartRecognition: false, 11744 mobileOptimizer: true, 11745 fullAlone: true, 11746 fullViewPort: null, 11747 fullStretchTypes: 'flash, video', 11748 overlay: { 11749 blur: true, 11750 opacity: .85 11751 }, 11752 controls: { 11753 arrows: false, 11754 slideshow: false, 11755 toolbar: true, 11756 fullscreen: true, 11757 thumbnail: true, 11758 keyboard: true, 11759 mousewheel: true, 11760 swipe: true 11761 }, 11762 keyboard: { 11763 left: true, // previous 11764 right: true, // next 11765 up: true, // previous 11766 down: true, // next 11767 esc: true, // close 11768 shift_enter: true // fullscreen 11769 }, 11770 show: { 11771 effect: true, 11772 speed: 300, 11773 title: true 11774 }, 11775 hide: { 11776 effect: true, 11777 speed: 300 11778 }, 11779 caption: { 11780 start: true, 11781 show: 'mouseenter', 11782 hide: 'mouseleave' 11783 }, 11784 social: { 11785 start: true, 11786 show: 'mouseenter', 11787 hide: 'mouseleave',
11788 buttons: false 11789 }, 11790 styles: { 11791 pageOffsetX: 0, 11792 pageOffsetY: 0, 11793 nextOffsetX: 45, 11794 nextOffsetY: 0, 11795 nextOpacity: 1, 11796 nextScale: 1, 11797 prevOffsetX: 45, 11798 prevOffsetY: 0, 11799 prevOpacity: 1, 11800 prevScale: 1 11801 }, 11802 thumbnails: { 11803 maxWidth: 120, 11804 maxHeight: 80, 11805 normalOpacity: 1, 11806 activeOpacity: .6 11807 }, 11808 effects: { 11809 reposition: true, 11810 repositionSpeed: 200, 11811 switchSpeed: 500, 11812 loadedFadeSpeed: 180, 11813 fadeSpeed: 200 11814 }, 11815 slideshow: { 11816 pauseTime: 5000, 11817 pauseOnHover: false, 11818 startPaused: true 11819 }, 11820 text: { 11821 close: "Press Esc to close", 11822 enterFullscreen: "Enter Fullscreen (Shift+Enter)", 11823 exitFullscreen: "Exit Fullscreen (Shift+Enter)", 11824 slideShow: "Slideshow", 11825 next: "Next", 11826 previous: "Previous" 11827 }, 11828 errors: { 11829 loadImage: "An error occurred when trying to load photo.", 11830 loadContents: "An error occurred when trying to load contents.", 11831 missingPlugin: "The content your are attempting to view requires the <a href='{pluginspage}' target='_blank'>{type} plugin<\/a>." 11832 }, 11833 ajaxSetup: { 11834 url: '', 11835 beforeSend: function(jqXHR, settings) {}, 11836 cache: false, 11837 complete: function(jqXHR, textStatus) {}, 11838 crossDomain: false, 11839 error: function(jqXHR, textStatus, errorThrown) {}, 11840 success: function(data, textStatus, jqXHR) {}, 11841 global: true, 11842 ifModified: false, 11843 username: null, 11844 password: null, 11845 type: 'GET' 11846 }, 11847 callback: {} 11848 }, opt); 11849 11850 var instant = ($.isArray(items) || typeof items == 'string') ? true : false; 11851 11852 items = $.isArray(items) ? items : new Array(); 11853 11854 if (typeof args[0] == 'string') items[0] = args[0]; 11855 11856 if (version_compare($.fn.jquery, '1.8', '>=')) { 11857 var iLB = new iLightBox($(this), options, items, instant); 11858 return { 11859 close: function() { 11860 iLB.closeAction(); 11861 }, 11862 fullscreen: function() { 11863 iLB.fullScreenAction(); 11864 }, 11865 moveNext: function() { 11866 iLB.moveTo('next'); 11867 }, 11868 movePrev: function() { 11869 iLB.moveTo('prev'); 11870 }, 11871 goTo: function(index) { 11872 iLB.goTo(index); 11873 }, 11874 refresh: function() { 11875 iLB.refresh(); 11876 }, 11877 reposition: function() { 11878 (arguments.length > 0) ? iLB.repositionPhoto(true): iLB.repositionPhoto(); 11879 }, 11880 setOption: function(options) { 11881 iLB.setOption(options); 11882 }, 11883 destroy: function() { 11884 iLB.closeAction(); 11885 iLB.dispatchItemsEvents(); 11886 } 11887 }; 11888 } else { 11889 throw "The jQuery version that was loaded is too old. iLightBox requires jQuery 1.8+"; 11890 } 11891 11892 }; 11893 11894 11895 $.iLightBox = function() { 11896 return $.fn.iLightBox(arguments[0], arguments[1]); 11897 }; 11898 11899 11900 $.extend($.easing, { 11901 easeInCirc: function(x, t, b, c, d) { 11902 return -c * (sqrt(1 - (t /= d) * t) - 1) + b; 11903 }, 11904 easeOutCirc: function(x, t, b, c, d) { 11905 return c * sqrt(1 - (t = t / d - 1) * t) + b; 11906 }, 11907 easeInOutCirc: function(x, t, b, c, d) { 11908 if ((t /= d / 2) < 1) return -c / 2 * (sqrt(1 - t * t) - 1) + b; 11909 return c / 2 * (sqrt(1 - (t -= 2) * t) + 1) + b; 11910 } 11911 }); 11912 11913 function getScrollXY() { 11914 var scrOfX = 0, 11915 scrOfY = 0; 11916 if (typeof(window.pageYOffset) == 'number') { 11917 //Netscape compliant 11918 scrOfY = window.pageYOffset; 11919 scrOfX = window.pageXOffset; 11920 } else if (document.body && (document.body.scrollLeft || document.body.scrollTop)) { 11921 //DOM compliant 11922 scrOfY = document.body.scrollTop; 11923 scrOfX = document.body.scrollLeft; 11924 } else if (document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)) { 11925 //IE6 standards compliant mode 11926 scrOfY = document.documentElement.scrollTop; 11927 scrOfX = document.documentElement.scrollLeft; 11928 } 11929 return { 11930 x: scrOfX, 11931 y: scrOfY 11932 }; 11933 } 11934 11935 (function() { 11936 // add new event shortcuts 11937 $.each(("touchstart touchmove touchend " + 11938 "tap taphold " + 11939 "swipe swipeleft swiperight " + 11940 "scrollstart scrollstop").split(" "), function(i, name) { 11941 11942 $.fn[name] = function(fn) { 11943 return fn ? this.bind(name, fn) : this.trigger(name); 11944 }; 11945 11946 // jQuery < 1.8 11947 // if ($.attrFn) { 11948 // $.attrFn[name] = true; 11949 // } 11950 }); 11951 11952 var tapSettings = { 11953 startEvent: 'touchstart.iTap', 11954 endEvent: 'touchend.iTap' 11955 }; 11956 11957 // tap Event: 11958 $.event.special.itap = { 11959 setup: function() { 11960 11961 var self = this, 11962 $self = $(this), 11963 start, stop; 11964 11965 $self.bind(tapSettings.startEvent, function(event) { 11966 start = getScrollXY(); 11967 11968 $self.one(tapSettings.endEvent, function(event) { 11969 stop = getScrollXY(); 11970 11971 var orgEvent = event || window.event; 11972 event = $.event.fix(orgEvent); 11973 event.type = "itap"; 11974 11975 if ((start && stop) && (start.x == stop.x && start.y == stop.y))($.event.dispatch || $.event.handle).call(self, event); 11976 11977 start = stop = undefined; 11978 }); 11979 }); 11980 }, 11981 11982 teardown: function() { 11983 $(this).unbind(tapSettings.startEvent); 11984 } 11985 }; 11986 }()); 11987 11988 11989 //Fullscreen API 11990 (function() { 11991 fullScreenApi = { 11992 supportsFullScreen: false, 11993 isFullScreen: function() { 11994 return false;
11995 }, 11996 requestFullScreen: function() {}, 11997 cancelFullScreen: function() {}, 11998 fullScreenEventName: '', 11999 prefix: '' 12000 }, 12001 browserPrefixes = 'webkit moz o ms khtml'.split(' '); 12002 12003 // check for native support 12004 if (typeof document.cancelFullScreen != 'undefined') { 12005 fullScreenApi.supportsFullScreen = true; 12006 } else { 12007 // check for fullscreen support by vendor prefix 12008 for (var i = 0, il = browserPrefixes.length; i < il; i++) { 12009 fullScreenApi.prefix = browserPrefixes[i]; 12010 12011 if (typeof document[fullScreenApi.prefix + 'CancelFullScreen'] != 'undefined') { 12012 fullScreenApi.supportsFullScreen = true; 12013 12014 break; 12015 } 12016 } 12017 } 12018 12019 // update methods to do something useful 12020 if (fullScreenApi.supportsFullScreen) { 12021 fullScreenApi.fullScreenEventName = fullScreenApi.prefix + 'fullscreenchange'; 12022 12023 fullScreenApi.isFullScreen = function() { 12024 switch (this.prefix) { 12025 case '': 12026 return document.fullScreen; 12027 case 'webkit': 12028 return document.webkitIsFullScreen; 12029 default: 12030 return document[this.prefix + 'FullScreen']; 12031 } 12032 } 12033 fullScreenApi.requestFullScreen = function(el) { 12034 return (this.prefix === '') ? el.requestFullScreen() : el[this.prefix + 'RequestFullScreen'](); 12035 } 12036 fullScreenApi.cancelFullScreen = function(el) { 12037 return (this.prefix === '') ? document.cancelFullScreen() : document[this.prefix + 'CancelFullScreen'](); 12038 } 12039 } 12040 }()); 12041 12042 // Browser detect 12043 (function() { 12044 function uaMatch(ua) { 12045 ua = ua.toLowerCase(); 12046 12047 var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || 12048 /(webkit)[ \/]([\w.]+)/.exec(ua) || 12049 /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || 12050 /(msie) ([\w.]+)/.exec(ua) || 12051 ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || []; 12052 12053 return { 12054 browser: match[1] || "", 12055 version: match[2] || "0" 12056 }; 12057 } 12058 12059 var matched = uaMatch(navigator.userAgent); 12060 browser = {}; 12061 12062 if (matched.browser) { 12063 browser[matched.browser] = true; 12064 browser.version = matched.version; 12065 } 12066 12067 // Chrome is Webkit, but Webkit is also Safari. 12068 if (browser.chrome) { 12069 browser.webkit = true; 12070 } else if (browser.webkit) { 12071 browser.safari = true; 12072 } 12073 }()); 12074 12075 // Feature detects 12076 (function() { 12077 var prefixes = ['', 'webkit', 'moz', 'ms', 'o']; 12078 var el = document.createElement('div'); 12079 12080 function testProp(prop) { 12081 for (var p = 0, pl = prefixes.length; p < pl; p++) { 12082 var prefixedProp = prefixes[p] ? prefixes[p] + prop.charAt(0).toUpperCase() + prop.slice(1) : prop; 12083 if (el.style[prefixedProp] !== undefined) { 12084 return prefixedProp; 12085 } 12086 } 12087 } 12088 12089 // Global support indicators 12090 transform = testProp('transform') || ''; 12091 gpuAcceleration = testProp('perspective') ? 'translateZ(0) ' : ''; 12092 }()); 12093 12094 12095 /* 12096 PluginDetect v0.7.9 12097 www.pinlady.net/PluginDetect/license/ 12098 [ getVersion onWindowLoaded BetterIE ] 12099 [ Flash QuickTime Shockwave ] 12100 */ 12101 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;
12101d++){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);
12101d.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)}
12101c.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;
12101if(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(); 12102 12103 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)}; 12104 12105 12106 /* 12107 jQuery hashchange event v1.3 12108 https://github.com/cowboy/jquery-hashchange 12109 Copyright (c) 2010 "Cowboy" Ben Alman 12110 Dual licensed under the MIT and GPL licenses. 12111 */ 12112 (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= 12113 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|| 12114 "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;
12114a!==d&&(b.title=k.title,b.open(),e&&b.write('<script>document.domain="'+e+'"\x3c/script>'),b.close(),c.location.hash=a)}}();return h}()})(); 12115 12116 if (!Array.prototype.filter) { 12117 Array.prototype.filter = function(fun /*, thisp */ ) { 12118 "use strict"; 12119 12120 if (this == null) 12121 throw new TypeError(); 12122 12123 var t = Object(this); 12124 var len = t.length >>> 0; 12125 if (typeof fun != "function") 12126 throw new TypeError(); 12127 12128 var res = []; 12129 var thisp = arguments[1]; 12130 for (var i = 0; i < len; i++) { 12131 if (i in t) { 12132 var val = t[i]; // in case fun mutates this 12133 if (fun.call(thisp, val, i, t)) 12134 res.push(val); 12135 } 12136 } 12137 12138 return res; 12139 }; 12140 } 12141 12142 if (!Array.prototype.indexOf) { 12143 Array.prototype.indexOf = function(searchElement, fromIndex) { 12144 var k; 12145 12146 if (this == null) { 12147 throw new TypeError('"this" is null or not defined'); 12148 } 12149 12150 var O = Object(this); 12151 12152 var len = O.length >>> 0; 12153 12154 if (len === 0) { 12155 return -1; 12156 } 12157 12158 var n = +fromIndex || 0; 12159 12160 if (abs(n) === Infinity) { 12161 n = 0; 12162 } 12163 12164 if (n >= len) { 12165 return -1; 12166 } 12167 12168 k = max(n >= 0 ? n : len - abs(n), 0); 12169 12170 while (k < len) { 12171 var kValue; 12172 if (k in O && O[k] === searchElement) { 12173 return k; 12174 } 12175 k++; 12176 } 12177 return -1; 12178 }; 12179 } 12180 12181 if (!Array.prototype.lastIndexOf) { 12182 Array.prototype.lastIndexOf = function(searchElement /*, fromIndex*/ ) { 12183 "use strict"; 12184 12185 if (this == null) 12186 throw new TypeError(); 12187 12188 var t = Object(this); 12189 var len = t.length >>> 0; 12190 if (len === 0) 12191 return -1; 12192 12193 var n = len; 12194 if (arguments.length > 1) { 12195 n = Number(arguments[1]); 12196 if (n != n) 12197 n = 0; 12198 else if (n != 0 && n != (1 / 0) && n != -(1 / 0)) 12199 n = (n > 0 || -1) * floor(abs(n)); 12200 } 12201 12202 var k = n >= 0 ? min(n, len - 1) : len - abs(n); 12203 12204 for (; k >= 0; k--) { 12205 if (k in t && t[k] === searchElement) 12206 return k; 12207 } 12208 return -1; 12209 }; 12210 } 12211})(jQuery, this); 12212 12213/** 12214 * Owl carousel
vendor: 12,109 bytes, lines 12215-12721
12215 * @version 2.0.0-beta.3 12216 * @author Bartosz Wojciechowski 12217 * @license The MIT License (MIT) 12218 * @todo Lazy Load Icon 12219 * @todo prevent animationend bubling 12220 * @todo itemsScaleUp 12221 * @todo Test Zepto 12222 * @todo stagePadding calculate wrong active classes 12223 */ 12224;(function($, window, document, undefined) { 12225 12226 /** 12227 * Creates a carousel. 12228 * @class The Owl Carousel. 12229 * @public 12230 * @param {HTMLElement|jQuery} element - The element to create the carousel for. 12231 * @param {Object} [options] - The options 12232 */ 12233 function Owl(element, options) { 12234 12235 /** 12236 * Current settings for the carousel. 12237 * @public 12238 */ 12239 this.settings = null; 12240 12241 /** 12242 * Current options set by the caller including defaults. 12243 * @public 12244 */ 12245 this.options = $.extend({}, Owl.Defaults, options); 12246 12247 /** 12248 * Plugin element. 12249 * @public 12250 */ 12251 this.$element = $(element); 12252 12253 /** 12254 * Proxied event handlers. 12255 * @protected 12256 */ 12257 this._handlers = {}; 12258 12259 /** 12260 * References to the running plugins of this carousel. 12261 * @protected 12262 */ 12263 this._plugins = {}; 12264 12265 /** 12266 * Currently suppressed events to prevent them from beeing retriggered. 12267 * @protected 12268 */ 12269 this._supress = {}; 12270 12271 /** 12272 * Absolute current position. 12273 * @protected 12274 */ 12275 this._current = null; 12276 12277 /** 12278 * Animation speed in milliseconds. 12279 * @protected 12280 */ 12281 this._speed = null; 12282 12283 /** 12284 * Coordinates of all items in pixel. 12285 * @todo The name of this member is missleading. 12286 * @protected 12287 */ 12288 this._coordinates = []; 12289 12290 /** 12291 * Current breakpoint. 12292 * @todo Real media queries would be nice. 12293 * @protected 12294 */ 12295 this._breakpoint = null; 12296 12297 /** 12298 * Current width of the plugin element. 12299 */ 12300 this._width = null; 12301 12302 /** 12303 * All real items. 12304 * @protected 12305 */ 12306 this._items = []; 12307 12308 /** 12309 * All cloned items. 12310 * @protected 12311 */ 12312 this._clones = []; 12313 12314 /** 12315 * Merge values of all items. 12316 * @todo Maybe this could be part of a plugin. 12317 * @protected 12318 */ 12319 this._mergers = []; 12320 12321 /** 12322 * Widths of all items. 12323 */ 12324 this._widths = []; 12325 12326 /** 12327 * Invalidated parts within the update process. 12328 * @protected 12329 */ 12330 this._invalidated = {}; 12331 12332 /** 12333 * Ordered list of workers for the update process. 12334 * @protected 12335 */ 12336 this._pipe = []; 12337 12338 /** 12339 * Current state information for the drag operation. 12340 * @todo #261 12341 * @protected 12342 */ 12343 this._drag = { 12344 time: null, 12345 target: null, 12346 pointer: null, 12347 stage: { 12348 start: null, 12349 current: null 12350 }, 12351 direction: null 12352 }; 12353 12354 /** 12355 * Current state information and their tags. 12356 * @type {Object} 12357 * @protected 12358 */ 12359 this._states = { 12360 current: {}, 12361 tags: { 12362 'initializing': [ 'busy' ], 12363 'animating': [ 'busy' ], 12364 'dragging': [ 'interacting' ] 12365 } 12366 }; 12367 12368 $.each([ 'onResize', 'onThrottledResize' ], $.proxy(function(i, handler) { 12369 this._handlers[handler] = $.proxy(this[handler], this); 12370 }, this)); 12371 12372 $.each(Owl.Plugins, $.proxy(function(key, plugin) { 12373 this._plugins[key.charAt(0).toLowerCase() + key.slice(1)] 12374 = new plugin(this); 12375 }, this)); 12376 12377 $.each(Owl.Workers, $.proxy(function(priority, worker) { 12378 this._pipe.push({ 12379 'filter': worker.filter, 12380 'run': $.proxy(worker.run, this) 12381 }); 12382 }, this)); 12383 12384 this.setup(); 12385 this.initialize(); 12386 } 12387 12388 /** 12389 * Default options for the carousel. 12390 * @public 12391 */ 12392 Owl.Defaults = { 12393 items: 3, 12394 loop: false, 12395 center: false, 12396 rewind: false, 12397 12398 mouseDrag: true, 12399 touchDrag: true, 12400 pullDrag: true, 12401 freeDrag: false, 12402 12403 margin: 0, 12404 stagePadding: 0, 12405 12406 merge: false, 12407 mergeFit: true, 12408 autoWidth: false, 12409 12410 startPosition: 0, 12411 rtl: false, 12412 12413 smartSpeed: 250, 12414 fluidSpeed: false, 12415 dragEndSpeed: false, 12416 12417 responsive: {}, 12418 responsiveRefreshRate: 200, 12419 responsiveBaseElement: window, 12420 12421 fallbackEasing: 'swing', 12422 12423 info: false, 12424 12425 nestedItemSelector: false, 12426 itemElement: 'div', 12427 stageElement: 'div', 12428 12429 refreshClass: 'owl-refresh', 12430 loadedClass: 'owl-loaded', 12431 loadingClass: 'owl-loading', 12432 rtlClass: 'owl-rtl', 12433 responsiveClass: 'owl-responsive', 12434 dragClass: 'owl-drag', 12435 itemClass: 'owl-item', 12436 stageClass: 'owl-stage', 12437 stageOuterClass: 'owl-stage-outer', 12438 grabClass: 'owl-grab' 12439 }; 12440 12441 /** 12442 * Enumeration for width. 12443 * @public 12444 * @readonly 12445 * @enum {String} 12446 */ 12447 Owl.Width = { 12448 Default: 'default', 12449 Inner: 'inner', 12450 Outer: 'outer' 12451 }; 12452 12453 /** 12454 * Enumeration for types. 12455 * @public 12456 * @readonly 12457 * @enum {String} 12458 */ 12459 Owl.Type = { 12460 Event: 'event', 12461 State: 'state' 12462 }; 12463 12464 /** 12465 * Contains all registered plugins. 12466 * @public 12467 */ 12468 Owl.Plugins = {}; 12469 12470 /** 12471 * List of workers involved in the update process. 12472 */ 12473 Owl.Workers = [ { 12474 filter: [ 'width', 'settings' ], 12475 run: function() { 12476 this._width = (this.$element.closest('.px-gutter').length) ? 12 * Math.ceil(this.$element.width() / 12) : this.$element.width(); 12477 //this._width = (UNCODE.isMobile) ? this.$element.width() : 12 * Math.ceil(this.$element.width() / 12); 12478 } 12479 }, { 12480 filter: [ 'width', 'items', 'settings' ], 12481 run: function(cache) { 12482 cache.current = this._items && this._items[this.relative(this._current)]; 12483 } 12484 }, { 12485 filter: [ 'items', 'settings' ], 12486 run: function() { 12487 this.$stage.children('.cloned').remove(); 12488 } 12489 }, { 12490 filter: [ 'width', 'items', 'settings' ], 12491 run: function(cache) { 12492 var margin = this.settings.margin || '', 12493 grid = !this.settings.autoWidth, 12494 rtl = this.settings.rtl, 12495 css = { 12496 'width': 'auto', 12497 'margin-left': rtl ? margin : '', 12498 'margin-right': rtl ? '' : margin 12499 }; 12500 12501 !grid && this.$stage.children().css(css); 12502 12503 cache.css = css; 12504 } 12505 }, { 12506 filter: [ 'width', 'items', 'settings' ], 12507 run: function(cache) { 12508 //UNCODE edit to fix Chrome stage padding issue 12509 var width = Math.round((this.width() / this.settings.items).toFixed(3) - this.settings.margin), 12510 merge = null, 12511 iterator = this._items.length, 12512 grid = !this.settings.autoWidth, 12513 widths = []; 12514 12515 cache.items = { 12516 merge: false, 12517 width: width 12518 }; 12519 12520 while (iterator--) { 12521 merge = this._mergers[iterator]; 12522 merge = this.settings.mergeFit && Math.min(merge, this.settings.items) || merge; 12523 12524 cache.items.merge = merge > 1 || cache.items.merge; 12525 12526 widths[iterator] = !grid ? this._items[iterator].width() : width * merge; 12527 } 12528 12529 this._widths = widths; 12530 } 12531 }, { 12532 filter: [ 'items', 'settings' ], 12533 run: function() { 12534 var clones = [], 12535 items = this._items, 12536 settings = this.settings, 12537 view = Math.max(settings.items * 2, 4), 12538 size = Math.ceil(items.length / 2) * 2, 12539 repeat = settings.loop && items.length ? settings.rewind ? view : Math.max(view, size) : 0, 12540 append = '', 12541 prepend = ''; 12542 12543 repeat /= 2; 12544 12545 while (repeat--) { 12546 clones.push(this.normalize(clones.length / 2, true)); 12547 append = append + items[clones[clones.length - 1]][0].outerHTML; 12548 clones.push(this.normalize(items.length - 1 - (clones.length - 1) / 2, true)); 12549 prepend = items[clones[clones.length - 1]][0].outerHTML + prepend; 12550 } 12551 12552 this._clones = clones; 12553 12554 // var appendVideo = $(append).find('.uncode-video-container'); 12555 // if (appendVideo.length) { 12556 // appendVideo.attr('data-id', Math.round(Math.random() * 100000)); 12557 // } 12558 // var prependVideo = $(prepend).find('.uncode-video-container'); 12559 // if (prependVideo.length) { 12560 // prependVideo.attr('data-id', Math.round(Math.random() * 100000)); 12561 // } 12562 $(append).addClass('cloned').appendTo(this.$stage); 12563 $(prepend).addClass('cloned').prependTo(this.$stage); 12564 } 12565 }, { 12566 filter: [ 'width', 'items', 'settings' ], 12567 run: function() { 12568 var rtl = this.settings.rtl ? 1 : -1, 12569 size = this._clones.length + this._items.length, 12570 iterator = -1, 12571 previous = 0, 12572 current = 0, 12573 coordinates = []; 12574 12575 while (++iterator < size) { 12576 previous = coordinates[iterator - 1] || 0; 12577 current = this._widths[this.relative(iterator)] + this.settings.margin; 12578 coordinates.push(previous + current * rtl); 12579 } 12580 12581 this._coordinates = coordinates; 12582 } 12583 }, { 12584 filter: [ 'width', 'items', 'settings' ], 12585 run: function() { 12586 var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200, 12587 padding = stagePadding, 12588 coordinates = this._coordinates, 12589 css = { 12590 'width': Math.ceil(Math.abs(coordinates[coordinates.length - 1])) + padding * 2, 12591 'padding-left': padding || '', 12592 'padding-right': padding || '' 12593 }; 12594 12595 this.$stage.css(css); 12596 } 12597 }, { 12598 filter: [ 'width', 'items', 'settings' ], 12599 run: function(cache) { 12600 var iterator = this._coordinates.length, 12601 grid = !this.settings.autoWidth, 12602 items = this.$stage.children(); 12603 12604 if (grid && cache.items.merge) { 12605 while (iterator--) { 12606 cache.css.width = this._widths[this.relative(iterator)]; 12607 items.eq(iterator).css(cache.css); 12608 } 12609 } else if (grid) { 12610 cache.css.width = cache.items.width; 12611 items.css(cache.css); 12612 } 12613 } 12614 }, { 12615 filter: [ 'items' ], 12616 run: function() { 12617 this._coordinates.length < 1 && this.$stage.removeAttr('style'); 12618 } 12619 }, { 12620 filter: [ 'width', 'items', 'settings' ], 12621 run: function(cache) { 12622 cache.current = cache.current ? this.$stage.children().index(cache.current) : 0; 12623 cache.current = Math.max(this.minimum(), Math.min(this.maximum(), cache.current)); 12624 this.reset(cache.current); 12625 } 12626 }, { 12627 filter: [ 'position' ], 12628 run: function() { 12629 this.animate(this.coordinates(this._current)); 12630 } 12631 }, { 12632 filter: [ 'width', 'position', 'items', 'settings' ], 12633 run: function() { 12634 var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200, 12635 rtl = this.settings.rtl ? 1 : -1, 12636 padding = this.settings.stagePadding * 2, 12637 begin = this.coordinates(this.current()) + padding, 12638 end = begin + this.width() * rtl, 12639 inner, outer, matches = [], i, n; 12640 12641 for (i = 0, n = this._coordinates.length; i < n; i++) { 12642 inner = this._coordinates[i - 1] || 0; 12643 outer = Math.abs(this._coordinates[i]) + padding * rtl; 12644 12645 if ((this.op(inner, '<=', begin) && (this.op(inner, '>', end))) 12646 || (this.op(outer, '<', begin) && this.op(outer, '>', end))) { 12647 matches.push(i); 12648 } 12649 } 12650 12651 this.$stage.children('.active').removeClass('active'); 12652 this.$stage.children(':eq(' + matches.join('), :eq(') + ')').addClass('active'); 12653 12654 if (this.settings.center) { 12655 this.$stage.children('.center').removeClass('center'); 12656 this.$stage.children().eq(this.current()).addClass('center'); 12657 } 12658 } 12659 } ]; 12660 12661 /** 12662 * Initializes the carousel. 12663 * @protected 12664 */ 12665 Owl.prototype.initialize = function() { 12666 this.enter('initializing'); 12667 this.trigger('initialize'); 12668 12669 this.$element.toggleClass(this.settings.rtlClass, this.settings.rtl); 12670 12671 if (this.settings.autoWidth && !this.is('pre-loading')) { 12672 var imgs, nestedSelector, width; 12673 imgs = this.$element.find('img'); 12674 nestedSelector = this.settings.nestedItemSelector ? '.' + this.settings.nestedItemSelector : undefined; 12675 width = this.$element.children(nestedSelector).width(); 12676 12677 if (imgs.length && width <= 0) { 12678 this.preloadAutoWidthImages(imgs); 12679 } 12680 } 12681 12682 this.$element.addClass(this.options.loadingClass); 12683 12684 // create stage 12685 this.$stage = $('<' + this.settings.stageElement + ' class="' + this.settings.stageClass + '"/>') 12686 .wrap('<div class="' + this.settings.stageOuterClass + '"/>'); 12687 12688 // append stage 12689 this.$element.append(this.$stage.parent()); 12690 12691 // append content 12692 this.replace(this.$element.children().not(this.$stage.parent())); 12693 12694 // check visibility 12695 if (this.$element.is(':visible')) { 12696 // update view 12697 this.refresh(); 12698 } else { 12699 // invalidate width 12700 this.invalidate('width'); 12701 } 12702 12703 this.$element 12704 .removeClass(this.options.loadingClass) 12705 .addClass(this.options.loadedClass); 12706 12707 // register event handlers 12708 this.registerEventHandlers(); 12709 12710 this.leave('initializing'); 12711 this.trigger('initialized'); 12712 }; 12713 12714 /** 12715 * Setups the current settings. 12716 * @todo Remove responsive classes. Why should adaptive designs be brought into IE8? 12717 * @todo Support for media queries by using `matchMedia` would be nice. 12718 * @public 12719 */ 12720 Owl.prototype.setup = function() { 12721 var viewport = this.viewport(),
12722 overwrites = this.options.responsive, 12723 match = -1, 12724 settings = null; 12725 12726 if (!overwrites) { 12727 settings = $.extend({}, this.options); 12728 } else { 12729 $.each(overwrites, function(breakpoint) { 12730 if (breakpoint <= viewport && breakpoint > match) { 12731 match = Number(breakpoint); 12732 } 12733 }); 12734 12735 settings = $.extend({}, this.options, overwrites[match]); 12736 delete settings.responsive; 12737 12738 // responsive class 12739 if (settings.responsiveClass) { 12740 this.$element.attr('class', 12741 this.$element.attr('class').replace(new RegExp('(' + this.options.responsiveClass + '-)\\S+\\s', 'g'), '$1' + match) 12742 ); 12743 } 12744 } 12745 12746 if (this.settings === null || this._breakpoint !== match) { 12747 this.trigger('change', { property: { name: 'settings', value: settings } }); 12748 this._breakpoint = match; 12749 this.settings = settings; 12750 this.invalidate('settings'); 12751 this.trigger('changed', { property: { name: 'settings', value: this.settings } }); 12752 } 12753 }; 12754 12755 /** 12756 * Updates option logic if necessery. 12757 * @protected 12758 */ 12759 Owl.prototype.optionsLogic = function() { 12760 if (this.settings.autoWidth) { 12761 this.settings.stagePadding = false; 12762 this.settings.merge = false; 12763 } 12764 }; 12765 12766 /** 12767 * Prepares an item before add. 12768 * @todo Rename event parameter `content` to `item`. 12769 * @protected 12770 * @returns {jQuery|HTMLElement} - The item container. 12771 */ 12772 Owl.prototype.prepare = function(item, index) { 12773 var event = this.trigger('prepare', { content: item }); 12774 if (!event.data) { 12775 event.data = $('<' + this.settings.itemElement + '/>') 12776 .addClass(this.options.itemClass).attr('data-index', index + 1).append(item) 12777 } 12778 12779 this.trigger('prepared', { content: event.data }); 12780 12781 return event.data; 12782 }; 12783 12784 /** 12785 * Updates the view. 12786 * @public 12787 */ 12788 Owl.prototype.update = function() { 12789 var i = 0, 12790 n = this._pipe.length, 12791 filter = $.proxy(function(p) { return this[p] }, this._invalidated), 12792 cache = {}; 12793 12794 while (i < n) { 12795 if (this._invalidated.all || $.grep(this._pipe[i].filter, filter).length > 0) { 12796 this._pipe[i].run(cache); 12797 } 12798 i++; 12799 } 12800 12801 this._invalidated = {}; 12802 12803 !this.is('valid') && this.enter('valid'); 12804 }; 12805 12806 /** 12807 * Gets the width of the view. 12808 * @public 12809 * @param {Owl.Width} [dimension=Owl.Width.Default] - The dimension to return. 12810 * @returns {Number} - The width of the view in pixel. 12811 */ 12812 Owl.prototype.width = function(dimension) { 12813 dimension = dimension || Owl.Width.Default; 12814 var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200; 12815 switch (dimension) { 12816 case Owl.Width.Inner: 12817 case Owl.Width.Outer: 12818 return this._width; 12819 default: 12820 return this._width - stagePadding * 2 + this.settings.margin; 12821 } 12822 }; 12823 12824 /** 12825 * Refreshes the carousel primarily for adaptive purposes. 12826 * @public 12827 */ 12828 Owl.prototype.refresh = function() { 12829 this.enter('refreshing'); 12830 this.trigger('refresh'); 12831 12832 this.setup(); 12833 12834 this.optionsLogic(); 12835 12836 this.$element.addClass(this.options.refreshClass); 12837 12838 this.update(); 12839 12840 this.$element.removeClass(this.options.refreshClass); 12841 12842 this.leave('refreshing'); 12843 this.trigger('refreshed'); 12844 }; 12845 12846 /** 12847 * Checks window `resize` event. 12848 * @protected 12849 */ 12850 Owl.prototype.onThrottledResize = function() { 12851 window.clearTimeout(this.resizeTimer); 12852 this.resizeTimer = window.setTimeout(this._handlers.onResize, this.settings.responsiveRefreshRate); 12853 }; 12854 12855 /** 12856 * Checks window `resize` event. 12857 * @protected 12858 */ 12859 Owl.prototype.onResize = function() { 12860 if (!this._items.length) { 12861 return false; 12862 } 12863 12864 if (this._width === this.$element.width()) { 12865 return false; 12866 } 12867 12868 if (!this.$element.is(':visible')) { 12869 return false; 12870 } 12871 12872 this.enter('resizing'); 12873 12874 if (this.trigger('resize').isDefaultPrevented()) { 12875 this.leave('resizing'); 12876 return false; 12877 } 12878 12879 this.invalidate('width'); 12880 12881 this.refresh(); 12882 12883 this.leave('resizing'); 12884 this.trigger('resized'); 12885 }; 12886 12887 /** 12888 * Registers event handlers. 12889 * @todo Check `msPointerEnabled` 12890 * @todo #261 12891 * @protected 12892 */ 12893 Owl.prototype.registerEventHandlers = function() { 12894 if ($.support.transition) { 12895 this.$stage.on($.support.transition.end + '.owl.core', $.proxy(this.onTransitionEnd, this)); 12896 } 12897 12898 if (this.settings.responsive !== false) { 12899 this.on(window, 'resize', this._handlers.onThrottledResize); 12900 } 12901 12902 if (this.settings.mouseDrag) { 12903 this.$element.addClass(this.options.dragClass); 12904 this.$stage.on('mousedown.owl.core', $.proxy(this.onDragStart, this)); 12905 this.$stage.on('dragstart.owl.core selectstart.owl.core', function() { return false }); 12906 } 12907 12908 if (this.settings.touchDrag){ 12909 this.$stage.on('touchstart.owl.core', $.proxy(this.onDragStart, this)); 12910 this.$stage.on('touchcancel.owl.core', $.proxy(this.onDragEnd, this)); 12911 } 12912 }; 12913 12914 /** 12915 * Handles `touchstart` and `mousedown` events. 12916 * @todo Horizontal swipe threshold as option 12917 * @todo #261 12918 * @protected 12919 * @param {Event} event - The event arguments. 12920 */ 12921 Owl.prototype.onDragStart = function(event) { 12922 var stage = null; 12923 12924 if (event.which === 3) { 12925 return; 12926 } 12927
vendor: 9,106 bytes, lines 12928-13243
12928 if ($.support.transform) { 12929 stage = this.$stage.css('transform').replace(/.*\(|\)| /g, '').split(','); 12930 stage = { 12931 x: stage[stage.length === 16 ? 12 : 4], 12932 y: stage[stage.length === 16 ? 13 : 5] 12933 }; 12934 } else { 12935 stage = this.$stage.position(); 12936 stage = { 12937 x: this.settings.rtl ? 12938 stage.left + this.$stage.width() - this.width() + this.settings.margin : 12939 stage.left, 12940 y: stage.top 12941 }; 12942 } 12943 12944 if (this.is('animating')) { 12945 $.support.transform ? this.animate(stage.x) : this.$stage.stop() 12946 this.invalidate('position'); 12947 } 12948 12949 this.$element.toggleClass(this.options.grabClass, event.type === 'mousedown'); 12950 12951 this.speed(0); 12952 12953 this._drag.time = new Date().getTime(); 12954 this._drag.target = $(event.target); 12955 this._drag.stage.start = stage; 12956 this._drag.stage.current = stage; 12957 this._drag.pointer = this.pointer(event); 12958 12959 $(document).on('mouseup.owl.core touchend.owl.core', $.proxy(this.onDragEnd, this)); 12960 12961 $(document).one('mousemove.owl.core touchmove.owl.core', $.proxy(function(event) { 12962 var delta = this.difference(this._drag.pointer, this.pointer(event)); 12963 12964 $(document).on('mousemove.owl.core touchmove.owl.core', $.proxy(this.onDragMove, this)); 12965 12966 if (Math.abs(delta.x) < Math.abs(delta.y) && this.is('valid')) { 12967 return; 12968 } 12969 12970 event.preventDefault(); 12971 12972 this.enter('dragging'); 12973 this.trigger('drag'); 12974 }, this)); 12975 }; 12976 12977 /** 12978 * Handles the `touchmove` and `mousemove` events. 12979 * @todo #261 12980 * @protected 12981 * @param {Event} event - The event arguments. 12982 */ 12983 Owl.prototype.onDragMove = function(event) { 12984 var minimum = null, 12985 maximum = null, 12986 pull = null, 12987 delta = this.difference(this._drag.pointer, this.pointer(event)), 12988 stage = this.difference(this._drag.stage.start, delta); 12989 12990 if (!this.is('dragging')) { 12991 return; 12992 } 12993 12994 event.preventDefault(); 12995 12996 if (this.settings.loop) { 12997 minimum = this.coordinates(this.minimum()); 12998 maximum = this.coordinates(this.maximum() + 1) - minimum; 12999 stage.x = (((stage.x - minimum) % maximum + maximum) % maximum) + minimum; 13000 } else { 13001 minimum = this.settings.rtl ? this.coordinates(this.maximum()) : this.coordinates(this.minimum()); 13002 maximum = this.settings.rtl ? this.coordinates(this.minimum()) : this.coordinates(this.maximum()); 13003 pull = this.settings.pullDrag ? -1 * delta.x / 5 : 0; 13004 stage.x = Math.max(Math.min(stage.x, minimum + pull), maximum + pull); 13005 } 13006 13007 this._drag.stage.current = stage; 13008 13009 this.animate(stage.x); 13010 }; 13011 13012 /** 13013 * Handles the `touchend` and `mouseup` events. 13014 * @todo #261 13015 * @todo Threshold for click event 13016 * @protected 13017 * @param {Event} event - The event arguments. 13018 */ 13019 Owl.prototype.onDragEnd = function(event) { 13020 var delta = this.difference(this._drag.pointer, this.pointer(event)), 13021 stage = this._drag.stage.current, 13022 direction = delta.x > 0 ^ this.settings.rtl ? 'left' : 'right'; 13023 13024 $(document).off('.owl.core'); 13025 13026 this.$element.removeClass(this.options.grabClass); 13027 13028 if (delta.x !== 0 && this.is('dragging') || !this.is('valid')) { 13029 this.speed(this.settings.dragEndSpeed || this.settings.smartSpeed); 13030 this.current(this.closest(stage.x, delta.x !== 0 ? direction : this._drag.direction)); 13031 this.invalidate('position'); 13032 this.update(); 13033 13034 this._drag.direction = direction; 13035 13036 if (Math.abs(delta.x) > 3 || new Date().getTime() - this._drag.time > 300) { 13037 this._drag.target.one('click.owl.core', function() { return false; }); 13038 } 13039 } 13040 13041 if (!this.is('dragging')) { 13042 return; 13043 } 13044 13045 this.leave('dragging'); 13046 this.trigger('dragged'); 13047 }; 13048 13049 /** 13050 * Gets absolute position of the closest item for a coordinate. 13051 * @todo Setting `freeDrag` makes `closest` not reusable. See #165. 13052 * @protected 13053 * @param {Number} coordinate - The coordinate in pixel. 13054 * @param {String} direction - The direction to check for the closest item. Ether `left` or `right`. 13055 * @return {Number} - The absolute position of the closest item. 13056 */ 13057 Owl.prototype.closest = function(coordinate, direction) { 13058 var position = -1, 13059 pull = 30, 13060 width = this.width(), 13061 coordinates = this.coordinates(); 13062 13063 if (!this.settings.freeDrag) { 13064 // check closest item 13065 $.each(coordinates, $.proxy(function(index, value) { 13066 if (coordinate > value - pull && coordinate < value + pull) { 13067 position = index; 13068 } else if (this.op(coordinate, '<', value) 13069 && this.op(coordinate, '>', coordinates[index + 1] || value - width)) { 13070 position = direction === 'left' ? index + 1 : index; 13071 } 13072 return position === -1; 13073 }, this)); 13074 } 13075 13076 if (!this.settings.loop) { 13077 // non loop boundries 13078 if (this.op(coordinate, '>', coordinates[this.minimum()])) { 13079 position = coordinate = this.minimum(); 13080 } else if (this.op(coordinate, '<', coordinates[this.maximum()])) { 13081 position = coordinate = this.maximum(); 13082 } 13083 } 13084 13085 return position; 13086 }; 13087 13088 /** 13089 * Animates the stage. 13090 * @todo #270 13091 * @public 13092 * @param {Number} coordinate - The coordinate in pixels. 13093 */ 13094 Owl.prototype.animate = function(coordinate) { 13095 var animate = this.speed() > 0; 13096 13097 this.is('animating') && this.onTransitionEnd(); 13098 13099 if (animate) { 13100 this.enter('animating'); 13101 this.trigger('translate'); 13102 } 13103 13104 if ($.support.transform3d && $.support.transition) { 13105 this.$stage.css({ 13106 transform: 'translate3d(' + coordinate + 'px,0px,0px)', 13107 transition: (this.speed() / 1000) + 's' 13108 }); 13109 } else if (animate) { 13110 this.$stage.animate({ 13111 left: coordinate + 'px' 13112 }, this.speed(), this.settings.fallbackEasing, $.proxy(this.onTransitionEnd, this)); 13113 } else { 13114 this.$stage.css({ 13115 left: coordinate + 'px' 13116 }); 13117 } 13118 }; 13119 13120 /** 13121 * Checks whether the carousel is in a specific state or not. 13122 * @param {String} state - The state to check. 13123 * @returns {Boolean} - The flag which indicates if the carousel is busy. 13124 */ 13125 Owl.prototype.is = function(state) { 13126 return this._states.current[state] && this._states.current[state] > 0; 13127 }; 13128 13129 /** 13130 * Sets the absolute position of the current item. 13131 * @public 13132 * @param {Number} [position] - The new absolute position or nothing to leave it unchanged. 13133 * @returns {Number} - The absolute position of the current item. 13134 */ 13135 Owl.prototype.current = function(position) { 13136 if (position === undefined) { 13137 return this._current; 13138 } 13139 13140 if (this._items.length === 0) { 13141 return undefined; 13142 } 13143 13144 position = this.normalize(position); 13145 13146 if (this._current !== position) { 13147 var event = this.trigger('change', { property: { name: 'position', value: position } }); 13148 13149 if (event.data !== undefined) { 13150 position = this.normalize(event.data); 13151 } 13152 13153 this._current = position; 13154 13155 this.invalidate('position'); 13156 13157 this.trigger('changed', { property: { name: 'position', value: this._current } }); 13158 } 13159 13160 return this._current; 13161 }; 13162 13163 /** 13164 * Invalidates the given part of the update routine. 13165 * @param {String} [part] - The part to invalidate. 13166 * @returns {Array.<String>} - The invalidated parts. 13167 */ 13168 Owl.prototype.invalidate = function(part) { 13169 if ($.type(part) === 'string') { 13170 this._invalidated[part] = true; 13171 this.is('valid') && this.leave('valid'); 13172 } 13173 return $.map(this._invalidated, function(v, i) { return i }); 13174 }; 13175 13176 /** 13177 * Resets the absolute position of the current item. 13178 * @public 13179 * @param {Number} position - The absolute position of the new item. 13180 */ 13181 Owl.prototype.reset = function(position) { 13182 position = this.normalize(position); 13183 13184 if (position === undefined) { 13185 return; 13186 } 13187 13188 this._speed = 0; 13189 this._current = position; 13190 13191 this.suppress([ 'translate', 'translated' ]); 13192 13193 this.animate(this.coordinates(position)); 13194 13195 this.release([ 'translate', 'translated' ]); 13196 }; 13197 13198 /** 13199 * Normalizes an absolute or a relative position of an item. 13200 * @public 13201 * @param {Number} position - The absolute or relative position to normalize. 13202 * @param {Boolean} [relative=false] - Whether the given position is relative or not. 13203 * @returns {Number} - The normalized position. 13204 */ 13205 Owl.prototype.normalize = function(position, relative) { 13206 var n = this._items.length, 13207 m = relative ? 0 : this._clones.length; 13208 13209 if (!$.isNumeric(position) || n < 1) { 13210 position = undefined; 13211 } else if (position < 0 || position >= n + m) { 13212 position = ((position - m / 2) % n + n) % n + m / 2; 13213 } 13214 13215 return position; 13216 }; 13217 13218 /** 13219 * Converts an absolute position of an item into a relative one. 13220 * @public 13221 * @param {Number} position - The absolute position to convert. 13222 * @returns {Number} - The converted position. 13223 */ 13224 Owl.prototype.relative = function(position) { 13225 position -= this._clones.length / 2; 13226 return this.normalize(position, true); 13227 }; 13228 13229 /** 13230 * Gets the maximum position for the current item. 13231 * @public 13232 * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position. 13233 * @returns {Number} 13234 */ 13235 Owl.prototype.maximum = function(relative) { 13236 var settings = this.settings, 13237 maximum = this._coordinates.length, 13238 boundary = Math.abs(this._coordinates[maximum - 1]) - this._width, 13239 i = -1, j; 13240 13241 if (settings.loop) { 13242 maximum = this._clones.length / 2 + this._items.length - 1; 13243 } else if (settings.autoWidth || settings.merge) {
13244 // binary search 13245 while (maximum - i > 1) { 13246 Math.abs(this._coordinates[j = maximum + i >> 1]) < boundary 13247 ? i = j : maximum = j; 13248 } 13249 } else if (settings.center) { 13250 maximum = this._items.length - 1; 13251 } else { 13252 maximum = this._items.length - settings.items; 13253 } 13254 13255 if (relative) { 13256 maximum -= this._clones.length / 2; 13257 } 13258 13259 return Math.max(maximum, 0); 13260 }; 13261 13262 /** 13263 * Gets the minimum position for the current item. 13264 * @public 13265 * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position. 13266 * @returns {Number} 13267 */ 13268 Owl.prototype.minimum = function(relative) { 13269 return relative ? 0 : this._clones.length / 2; 13270 }; 13271 13272 /** 13273 * Gets an item at the specified relative position. 13274 * @public 13275 * @param {Number} [position] - The relative position of the item. 13276 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given. 13277 */ 13278 Owl.prototype.items = function(position) { 13279 if (position === undefined) { 13280 return this._items.slice(); 13281 } 13282 13283 position = this.normalize(position, true); 13284 return this._items[position]; 13285 }; 13286 13287 /** 13288 * Gets an item at the specified relative position. 13289 * @public 13290 * @param {Number} [position] - The relative position of the item. 13291 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given. 13292 */ 13293 Owl.prototype.mergers = function(position) { 13294 if (position === undefined) { 13295 return this._mergers.slice(); 13296 } 13297 13298 position = this.normalize(position, true); 13299 return this._mergers[position]; 13300 }; 13301 13302 /** 13303 * Gets the absolute positions of clones for an item. 13304 * @public 13305 * @param {Number} [position] - The relative position of the item. 13306 * @returns {Array.<Number>} - The absolute positions of clones for the item or all if no position was given. 13307 */ 13308 Owl.prototype.clones = function(position) { 13309 var odd = this._clones.length / 2, 13310 even = odd + this._items.length, 13311 map = function(index) { return index % 2 === 0 ? even + index / 2 : odd - (index + 1) / 2 }; 13312 13313 if (position === undefined) { 13314 return $.map(this._clones, function(v, i) { return map(i) }); 13315 } 13316 13317 return $.map(this._clones, function(v, i) { return v === position ? map(i) : null }); 13318 }; 13319 13320 /** 13321 * Sets the current animation speed. 13322 * @public 13323 * @param {Number} [speed] - The animation speed in milliseconds or nothing to leave it unchanged. 13324 * @returns {Number} - The current animation speed in milliseconds. 13325 */ 13326 Owl.prototype.speed = function(speed) { 13327 if (speed !== undefined) { 13328 this._speed = speed; 13329 } 13330 13331 return this._speed; 13332 }; 13333 13334 /** 13335 * Gets the coordinate of an item. 13336 * @todo The name of this method is missleanding. 13337 * @public 13338 * @param {Number} position - The absolute position of the item within `minimum()` and `maximum()`. 13339 * @returns {Number|Array.<Number>} - The coordinate of the item in pixel or all coordinates. 13340 */ 13341 Owl.prototype.coordinates = function(position) { 13342 var coordinate = null; 13343 13344 if (position === undefined) { 13345 return $.map(this._coordinates, $.proxy(function(coordinate, index) { 13346 return this.coordinates(index); 13347 }, this)); 13348 } 13349 13350 if (this.settings.center) { 13351 coordinate = this._coordinates[position]; 13352 coordinate += (this.width() - coordinate + (this._coordinates[position - 1] || 0)) / 2 * (this.settings.rtl ? -1 : 1); 13353 } else { 13354 coordinate = this._coordinates[position - 1] || 0; 13355 } 13356 13357 return coordinate; 13358 }; 13359 13360 /** 13361 * Calculates the speed for a translation. 13362 * @protected 13363 * @param {Number} from - The absolute position of the start item. 13364 * @param {Number} to - The absolute position of the target item. 13365 * @param {Number} [factor=undefined] - The time factor in milliseconds. 13366 * @returns {Number} - The time in milliseconds for the translation. 13367 */ 13368 Owl.prototype.duration = function(from, to, factor) { 13369 return Math.min(Math.max(Math.abs(to - from), 1), 6) * Math.abs((factor || this.settings.smartSpeed)); 13370 }; 13371 13372 /** 13373 * Slides to the specified item. 13374 * @public 13375 * @param {Number} position - The position of the item. 13376 * @param {Number} [speed] - The time in milliseconds for the transition. 13377 */ 13378 Owl.prototype.to = function(position, speed) { 13379 var current = this.current(), 13380 revert = null, 13381 distance = position - this.relative(current), 13382 direction = (distance > 0) - (distance < 0), 13383 items = this._items.length, 13384 minimum = this.minimum(), 13385 maximum = this.maximum(); 13386 13387 if (this.settings.loop) { 13388 if (!this.settings.rewind && Math.abs(distance) > items / 2) { 13389 distance += direction * -1 * items; 13390 } 13391 13392 position = current + distance; 13393 revert = ((position - minimum) % items + items) % items + minimum; 13394 13395 if (revert !== position && revert - distance <= maximum && revert - distance > 0) { 13396 current = revert - distance; 13397 position = revert; 13398 this.reset(current); 13399 } 13400 } else if (this.settings.rewind) { 13401 maximum += 1; 13402 position = (position % maximum + maximum) % maximum; 13403 } else { 13404 position = Math.max(minimum, Math.min(maximum, position)); 13405 } 13406 13407 this.speed(this.duration(current, position, speed)); 13408 this.current(position); 13409 13410 if (this.$element.is(':visible')) { 13411 this.update(); 13412 } 13413 }; 13414 13415 /** 13416 * Slides to the next item. 13417 * @public 13418 * @param {Number}
vendor: 12,284 bytes, lines 13418-13838
13418 [speed] - The time in milliseconds for the transition. 13419 */ 13420 Owl.prototype.next = function(speed) { 13421 speed = speed || false; 13422 this.to(this.relative(this.current()) + 1, speed); 13423 }; 13424 13425 /** 13426 * Slides to the previous item. 13427 * @public 13428 * @param {Number} [speed] - The time in milliseconds for the transition. 13429 */ 13430 Owl.prototype.prev = function(speed) { 13431 speed = speed || false; 13432 this.to(this.relative(this.current()) - 1, speed); 13433 }; 13434 13435 /** 13436 * Handles the end of an animation. 13437 * @protected 13438 * @param {Event} event - The event arguments. 13439 */ 13440 Owl.prototype.onTransitionEnd = function(event) { 13441 13442 // if css2 animation then event object is undefined 13443 if (event !== undefined) { 13444 event.stopPropagation(); 13445 13446 // Catch only owl-stage transitionEnd event 13447 if ((event.target || event.srcElement || event.originalTarget) !== this.$stage.get(0)) { 13448 return false; 13449 } 13450 } 13451 13452 this.leave('animating'); 13453 this.trigger('translated'); 13454 }; 13455 13456 /** 13457 * Gets viewport width. 13458 * @protected 13459 * @return {Number} - The width in pixel. 13460 */ 13461 Owl.prototype.viewport = function() { 13462 var width; 13463 if (this.options.responsiveBaseElement !== window) { 13464 width = $(this.options.responsiveBaseElement).width(); 13465 } else if (window.innerWidth) { 13466 width = window.innerWidth; 13467 } else if (document.documentElement && document.documentElement.clientWidth) { 13468 width = document.documentElement.clientWidth; 13469 } else { 13470 throw 'Can not detect viewport width.'; 13471 } 13472 13473 return width; 13474 }; 13475 13476 /** 13477 * Replaces the current content. 13478 * @public 13479 * @param {HTMLElement|jQuery|String} content - The new content. 13480 */ 13481 Owl.prototype.replace = function(content) { 13482 this.$stage.empty(); 13483 this._items = []; 13484 13485 if (content) { 13486 content = (content instanceof jQuery) ? content : $(content); 13487 } 13488 13489 if (this.settings.nestedItemSelector) { 13490 content = content.find('.' + this.settings.nestedItemSelector); 13491 } 13492 13493 content.filter(function() { 13494 return this.nodeType === 1; 13495 }).each($.proxy(function(index, item) { 13496 item = this.prepare(item, index); 13497 this.$stage.append(item); 13498 this._items.push(item); 13499 this._mergers.push(item.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1); 13500 }, this)); 13501 13502 this.reset($.isNumeric(this.settings.startPosition) ? this.settings.startPosition : 0); 13503 13504 this.invalidate('items'); 13505 }; 13506 13507 /** 13508 * Adds an item. 13509 * @todo Use `item` instead of `content` for the event arguments. 13510 * @public 13511 * @param {HTMLElement|jQuery|String} content - The item content to add. 13512 * @param {Number} [position] - The relative position at which to insert the item otherwise the item will be added to the end. 13513 */ 13514 Owl.prototype.add = function(content, position) { 13515 var current = this.relative(this._current); 13516 13517 position = position === undefined ? this._items.length : this.normalize(position, true); 13518 content = content instanceof jQuery ? content : $(content); 13519 13520 this.trigger('add', { content: content, position: position }); 13521 13522 content = this.prepare(content, this._items[current].index()); 13523 13524 if (this._items.length === 0 || position === this._items.length) { 13525 this._items.length === 0 && this.$stage.append(content); 13526 this._items.length !== 0 && this._items[position - 1].after(content); 13527 this._items.push(content); 13528 this._mergers.push(content.find('[data-merge]').andSelf('[data-merge]').attr('data-merge') * 1 || 1); 13529 } else { 13530 this._items[position].before(content); 13531 this._items.splice(position, 0, content); 13532 this._mergers.splice(position, 0, content.find('[data-merge]').andSelf('[data-merge]').attr('data-merge') * 1 || 1); 13533 } 13534 13535 this._items[current] && this.reset(this._items[current].index()); 13536 13537 this.invalidate('items'); 13538 13539 this.trigger('added', { content: content, position: position }); 13540 }; 13541 13542 /** 13543 * Removes an item by its position. 13544 * @todo Use `item` instead of `content` for the event arguments. 13545 * @public 13546 * @param {Number} position - The relative position of the item to remove. 13547 */ 13548 Owl.prototype.remove = function(position) { 13549 position = this.normalize(position, true); 13550 13551 if (position === undefined) { 13552 return; 13553 } 13554 13555 this.trigger('remove', { content: this._items[position], position: position }); 13556 13557 this._items[position].remove(); 13558 this._items.splice(position, 1); 13559 this._mergers.splice(position, 1); 13560 13561 this.invalidate('items'); 13562 13563 this.trigger('removed', { content: null, position: position }); 13564 }; 13565 13566 /** 13567 * Preloads images with auto width. 13568 * @todo Replace by a more generic approach 13569 * @protected 13570 */ 13571 Owl.prototype.preloadAutoWidthImages = function(images) { 13572 images.each($.proxy(function(i, element) { 13573 this.enter('pre-loading'); 13574 element = $(element); 13575 $(new Image()).one('load', $.proxy(function(e) { 13576 element.attr('src', e.target.src); 13577 element.css('opacity', 1); 13578 this.leave('pre-loading'); 13579 !this.is('pre-loading') && !this.is('initializing') && this.refresh(); 13580 }, this)).attr('src', element.attr('src') || element.attr('data-src') || element.attr('data-src-retina')); 13581 }, this)); 13582 }; 13583 13584 /** 13585 * Destroys the carousel. 13586 * @public 13587 */ 13588 Owl.prototype.destroy = function() { 13589 13590 this.$element.off('.owl.core'); 13591 this.$stage.off('.owl.core'); 13592 $(document).off('.owl.core'); 13593 13594 if (this.settings.responsive !== false) { 13595 window.clearTimeout(this.resizeTimer); 13596 this.off(window, 'resize', this._handlers.onThrottledResize); 13597 } 13598 13599 for (var i in this._plugins) { 13600 this._plugins[i].destroy(); 13601 } 13602 13603 this.$stage.children('.cloned').remove(); 13604 13605 this.$stage.unwrap(); 13606 this.$stage.children().contents().unwrap(); 13607 this.$stage.children().unwrap(); 13608 13609 this.$element 13610 .removeClass(this.options.refreshClass) 13611 .removeClass(this.options.loadingClass) 13612 .removeClass(this.options.loadedClass) 13613 .removeClass(this.options.rtlClass) 13614 .removeClass(this.options.dragClass) 13615 .removeClass(this.options.grabClass) 13616 .attr('class', this.$element.attr('class').replace(new RegExp(this.options.responsiveClass + '-\\S+\\s', 'g'), '')) 13617 .removeData('owl.carousel'); 13618 }; 13619 13620 /** 13621 * Operators to calculate right-to-left and left-to-right. 13622 * @protected 13623 * @param {Number} [a] - The left side operand. 13624 * @param {String} [o] - The operator. 13625 * @param {Number} [b] - The right side operand. 13626 */ 13627 Owl.prototype.op = function(a, o, b) { 13628 var rtl = this.settings.rtl; 13629 switch (o) { 13630 case '<': 13631 return rtl ? a > b : a < b; 13632 case '>': 13633 return rtl ? a < b : a > b; 13634 case '>=': 13635 return rtl ? a <= b : a >= b; 13636 case '<=': 13637 return rtl ? a >= b : a <= b; 13638 default: 13639 break; 13640 } 13641 }; 13642 13643 /** 13644 * Attaches to an internal event. 13645 * @protected 13646 * @param {HTMLElement} element - The event source. 13647 * @param {String} event - The event name. 13648 * @param {Function} listener - The event handler to attach. 13649 * @param {Boolean} capture - Wether the event should be handled at the capturing phase or not. 13650 */ 13651 Owl.prototype.on = function(element, event, listener, capture) { 13652 if (element.addEventListener) { 13653 element.addEventListener(event, listener, capture); 13654 } else if (element.attachEvent) { 13655 element.attachEvent('on' + event, listener); 13656 } 13657 }; 13658 13659 /** 13660 * Detaches from an internal event. 13661 * @protected 13662 * @param {HTMLElement} element - The event source. 13663 * @param {String} event - The event name. 13664 * @param {Function} listener - The attached event handler to detach. 13665 * @param {Boolean} capture - Wether the attached event handler was registered as a capturing listener or not. 13666 */ 13667 Owl.prototype.off = function(element, event, listener, capture) { 13668 if (element.removeEventListener) { 13669 element.removeEventListener(event, listener, capture); 13670 } else if (element.detachEvent) { 13671 element.detachEvent('on' + event, listener); 13672 } 13673 }; 13674 13675 /** 13676 * Triggers a public event. 13677 * @todo Remove `status`, `relatedTarget` should be used instead. 13678 * @protected 13679 * @param {String} name - The event name. 13680 * @param {*} [data=null] - The event data. 13681 * @param {String} [namespace=carousel] - The event namespace. 13682 * @param {String} [state] - The state which is associated with the event. 13683 * @param {Boolean} [enter=false] - Indicates if the call enters the specified state or not. 13684 * @returns {Event} - The event arguments. 13685 */ 13686 Owl.prototype.trigger = function(name, data, namespace, state, enter) { 13687 var status = { 13688 item: { count: this._items.length, index: this.current() } 13689 }, handler = $.camelCase( 13690 $.grep([ 'on', name, namespace ], function(v) { return v }) 13691 .join('-').toLowerCase() 13692 ), event = $.Event( 13693 [ name, 'owl', namespace || 'carousel' ].join('.').toLowerCase(), 13694 $.extend({ relatedTarget: this }, status, data) 13695 ); 13696 13697 if (!this._supress[name]) { 13698 $.each(this._plugins, function(name, plugin) { 13699 if (plugin.onTrigger) { 13700 plugin.onTrigger(event); 13701 } 13702 }); 13703 13704 this.register({ type: Owl.Type.Event, name: name }); 13705 this.$element.trigger(event); 13706 13707 if (this.settings && typeof this.settings[handler] === 'function') { 13708 this.settings[handler].call(this, event); 13709 } 13710 } 13711 13712 return event; 13713 }; 13714 13715 /** 13716 * Enters a state. 13717 * @param name - The state name. 13718 */ 13719 Owl.prototype.enter = function(name) { 13720 $.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) { 13721 if (this._states.current[name] === undefined) { 13722 this._states.current[name] = 0; 13723 } 13724 13725 this._states.current[name]++; 13726 }, this)); 13727 }; 13728 13729 /** 13730 * Leaves a state. 13731 * @param name - The state name. 13732 */ 13733 Owl.prototype.leave = function(name) { 13734 $.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) { 13735 this._states.current[name]--; 13736 }, this)); 13737 }; 13738 13739 /** 13740 * Registers an event or state. 13741 * @public 13742 * @param {Object} object - The event or state to register. 13743 */ 13744 Owl.prototype.register = function(object) { 13745 if (object.type === Owl.Type.Event) { 13746 if (!$.event.special[object.name]) { 13747 $.event.special[object.name] = {}; 13748 } 13749 13750 if (!$.event.special[object.name].owl) { 13751 var _default = $.event.special[object.name]._default; 13752 $.event.special[object.name]._default = function(e) { 13753 if (_default && _default.apply && (!e.namespace || e.namespace.indexOf('owl') === -1)) { 13754 return _default.apply(this, arguments); 13755 } 13756 return e.namespace && e.namespace.indexOf('owl') > -1; 13757 }; 13758 $.event.special[object.name].owl = true; 13759 } 13760 } else if (object.type === Owl.Type.State) { 13761 if (!this._states.tags[object.name]) { 13762 this._states.tags[object.name] = object.tags; 13763 } else { 13764 this._states.tags[object.name] = this._states.tags[object.name].concat(object.tags); 13765 } 13766 13767 this._states.tags[object.name] = $.grep(this._states.tags[object.name], $.proxy(function(tag, i) { 13768 return $.inArray(tag, this._states.tags[object.name]) === i; 13769 }, this)); 13770 } 13771 }; 13772 13773 /** 13774 * Suppresses events. 13775 * @protected 13776 * @param {Array.<String>} events - The events to suppress. 13777 */ 13778 Owl.prototype.suppress = function(events) { 13779 $.each(events, $.proxy(function(index, event) { 13780 this._supress[event] = true; 13781 }, this)); 13782 }; 13783 13784 /** 13785 * Releases suppressed events. 13786 * @protected 13787 * @param {Array.<String>} events - The events to release. 13788 */ 13789 Owl.prototype.release = function(events) { 13790 $.each(events, $.proxy(function(index, event) { 13791 delete this._supress[event]; 13792 }, this)); 13793 }; 13794 13795 /** 13796 * Gets unified pointer coordinates from event. 13797 * @todo #261 13798 * @protected 13799 * @param {Event} - The `mousedown` or `touchstart` event. 13800 * @returns {Object} - Contains `x` and `y` coordinates of current pointer position. 13801 */ 13802 Owl.prototype.pointer = function(event) { 13803 var result = { x: null, y: null }; 13804 13805 event = event.originalEvent || event || window.event; 13806 13807 event = event.touches && event.touches.length ? 13808 event.touches[0] : event.changedTouches && event.changedTouches.length ? 13809 event.changedTouches[0] : event; 13810 13811 if (event.pageX) { 13812 result.x = event.pageX; 13813 result.y = event.pageY; 13814 } else { 13815 result.x = event.clientX; 13816 result.y = event.clientY; 13817 } 13818 13819 return result; 13820 }; 13821 13822 /** 13823 * Gets the difference of two vectors. 13824 * @todo #261 13825 * @protected 13826 * @param {Object} - The first vector. 13827 * @param {Object} - The second vector. 13828 * @returns {Object} - The difference. 13829 */ 13830 Owl.prototype.difference = function(first, second) { 13831 return { 13832 x: first.x - second.x, 13833 y: first.y - second.y 13834 }; 13835 }; 13836 13837 /** 13838 * The jQuery Plugin for the Owl Carousel
vendor: 32,216 bytes, lines 13839-15121
13839 * @todo Navigation plugin `next` and `prev` 13840 * @public 13841 */ 13842 $.fn.owlCarousel = function(option) { 13843 var args = Array.prototype.slice.call(arguments, 1); 13844 13845 return this.each(function() { 13846 var $this = $(this), 13847 data = $this.data('owl.carousel'); 13848 13849 if (!data) { 13850 data = new Owl(this, typeof option == 'object' && option); 13851 $this.data('owl.carousel', data); 13852 13853 $.each([ 13854 'next', 'prev', 'to', 'destroy', 'refresh', 'replace', 'add', 'remove' 13855 ], function(i, event) { 13856 data.register({ type: Owl.Type.Event, name: event }); 13857 data.$element.on(event + '.owl.carousel.core', $.proxy(function(e) { 13858 if (e.namespace && e.relatedTarget !== this) { 13859 this.suppress([ event ]); 13860 data[event].apply(this, [].slice.call(arguments, 1)); 13861 this.release([ event ]); 13862 } 13863 }, data)); 13864 }); 13865 } 13866 13867 if (typeof option == 'string' && option.charAt(0) !== '_') { 13868 data[option].apply(data, args); 13869 } 13870 }); 13871 }; 13872 13873 /** 13874 * The constructor for the jQuery Plugin 13875 * @public 13876 */ 13877 $.fn.owlCarousel.Constructor = Owl; 13878 13879})(window.Zepto || window.jQuery, window, document); 13880 13881/** 13882 * AutoRefresh Plugin 13883 * @version 2.0.0-beta.3 13884 * @author Artus Kolanowski 13885 * @license The MIT License (MIT) 13886 */ 13887;(function($, window, document, undefined) { 13888 13889 /** 13890 * Creates the auto refresh plugin. 13891 * @class The Auto Refresh Plugin 13892 * @param {Owl} carousel - The Owl Carousel 13893 */ 13894 var AutoRefresh = function(carousel) { 13895 /** 13896 * Reference to the core. 13897 * @protected 13898 * @type {Owl} 13899 */ 13900 this._core = carousel; 13901 13902 /** 13903 * Refresh interval. 13904 * @protected 13905 * @type {number} 13906 */ 13907 this._interval = null; 13908 13909 /** 13910 * Whether the element is currently visible or not. 13911 * @protected 13912 * @type {Boolean} 13913 */ 13914 this._visible = null; 13915 13916 /** 13917 * All event handlers. 13918 * @protected 13919 * @type {Object} 13920 */ 13921 this._handlers = { 13922 'initialized.owl.carousel': $.proxy(function(e) { 13923 if (e.namespace && this._core.settings.autoRefresh) { 13924 this.watch(); 13925 } 13926 }, this) 13927 }; 13928 13929 // set default options 13930 this._core.options = $.extend({}, AutoRefresh.Defaults, this._core.options); 13931 13932 // register event handlers 13933 this._core.$element.on(this._handlers); 13934 }; 13935 13936 /** 13937 * Default options. 13938 * @public 13939 */ 13940 AutoRefresh.Defaults = { 13941 autoRefresh: true, 13942 autoRefreshInterval: 500 13943 }; 13944 13945 /** 13946 * Watches the element. 13947 */ 13948 AutoRefresh.prototype.watch = function() { 13949 if (this._interval) { 13950 return; 13951 } 13952 13953 this._visible = this._core.$element.is(':visible'); 13954 this._interval = window.setInterval($.proxy(this.refresh, this), this._core.settings.autoRefreshInterval); 13955 }; 13956 13957 /** 13958 * Refreshes the element. 13959 */ 13960 AutoRefresh.prototype.refresh = function() { 13961 if (this._core.$element.is(':visible') === this._visible) { 13962 return; 13963 } 13964 13965 this._visible = !this._visible; 13966 13967 this._core.$element.toggleClass('owl-hidden', !this._visible); 13968 13969 this._visible && (this._core.invalidate('width') && this._core.refresh()); 13970 }; 13971 13972 /** 13973 * Destroys the plugin. 13974 */ 13975 AutoRefresh.prototype.destroy = function() { 13976 var handler, property; 13977 13978 window.clearInterval(this._interval); 13979 13980 for (handler in this._handlers) { 13981 this._core.$element.off(handler, this._handlers[handler]); 13982 } 13983 for (property in Object.getOwnPropertyNames(this)) { 13984 typeof this[property] != 'function' && (this[property] = null); 13985 } 13986 }; 13987 13988 $.fn.owlCarousel.Constructor.Plugins.AutoRefresh = AutoRefresh; 13989 13990})(window.Zepto || window.jQuery, window, document); 13991 13992/** 13993 * Lazy Plugin 13994 * @version 2.0.0-beta.3 13995 * @author Bartosz Wojciechowski 13996 * @license The MIT License (MIT) 13997 */ 13998;(function($, window, document, undefined) { 13999 14000 /** 14001 * Creates the lazy plugin. 14002 * @class The Lazy Plugin 14003 * @param {Owl} carousel - The Owl Carousel 14004 */ 14005 var Lazy = function(carousel) { 14006 14007 /** 14008 * Reference to the core. 14009 * @protected 14010 * @type {Owl} 14011 */ 14012 this._core = carousel; 14013 14014 /** 14015 * Already loaded items. 14016 * @protected 14017 * @type {Array.<jQuery>} 14018 */ 14019 this._loaded = []; 14020 14021 /** 14022 * Event handlers. 14023 * @protected 14024 * @type {Object} 14025 */ 14026 this._handlers = { 14027 'initialized.owl.carousel change.owl.carousel': $.proxy(function(e) { 14028 if (!e.namespace) { 14029 return; 14030 } 14031 14032 if (!this._core.settings || !this._core.settings.lazyLoad) { 14033 return; 14034 } 14035 14036 if ((e.property && e.property.name == 'position') || e.type == 'initialized') { 14037 var settings = this._core.settings, 14038 n = (settings.center && Math.ceil(settings.items / 2) || settings.items), 14039 i = ((settings.center && n * -1) || 0), 14040 position = ((e.property && e.property.value) || this._core.current()) + i, 14041 clones = this._core.clones().length, 14042 load = $.proxy(function(i, v) { this.load(v) }, this); 14043 14044 while (i++ < n) { 14045 this.load(clones / 2 + this._core.relative(position)); 14046 clones && $.each(this._core.clones(this._core.relative(position)), load); 14047 position++; 14048 } 14049 } 14050 }, this) 14051 }; 14052 14053 // set the default options 14054 this._core.options = $.extend({}, Lazy.Defaults, this._core.options); 14055 14056 // register event handler 14057 this._core.$element.on(this._handlers); 14058 } 14059 14060 /** 14061 * Default options. 14062 * @public 14063 */ 14064 Lazy.Defaults = { 14065 lazyLoad: false 14066 } 14067 14068 /** 14069 * Loads all resources of an item at the specified position. 14070 * @param {Number} position - The absolute position of the item. 14071 * @protected 14072 */ 14073 Lazy.prototype.load = function(position) { 14074 var $item = this._core.$stage.children().eq(position), 14075 $elements = $item && $item.find('.owl-lazy'); 14076 14077 if (!$elements || $.inArray($item.get(0), this._loaded) > -1) { 14078 return; 14079 } 14080 14081 $elements.each($.proxy(function(index, element) { 14082 var $element = $(element), image, 14083 url = (window.devicePixelRatio > 1 && $element.attr('data-src-retina')) || $element.attr('data-src'); 14084 14085 this._core.trigger('load', { element: $element, url: url }, 'lazy'); 14086 14087 if ($element.is('img')) { 14088 $element.one('load.owl.lazy', $.proxy(function() { 14089 $element.css('opacity', 1); 14090 this._core.trigger('loaded', { element: $element, url: url }, 'lazy'); 14091 }, this)).attr('src', url); 14092 } else { 14093 image = new Image(); 14094 image.onload = $.proxy(function() { 14095 $element.css({ 14096 'background-image': 'url(' + url + ')', 14097 'opacity': '1' 14098 }); 14099 this._core.trigger('loaded', { element: $element, url: url }, 'lazy'); 14100 }, this); 14101 image.src = url; 14102 } 14103 }, this)); 14104 14105 this._loaded.push($item.get(0)); 14106 } 14107 14108 /** 14109 * Destroys the plugin. 14110 * @public 14111 */ 14112 Lazy.prototype.destroy = function() { 14113 var handler, property; 14114 14115 for (handler in this.handlers) { 14116 this._core.$element.off(handler, this.handlers[handler]); 14117 } 14118 for (property in Object.getOwnPropertyNames(this)) { 14119 typeof this[property] != 'function' && (this[property] = null); 14120 } 14121 }; 14122 14123 $.fn.owlCarousel.Constructor.Plugins.Lazy = Lazy; 14124 14125})(window.Zepto || window.jQuery, window, document); 14126 14127/** 14128 * AutoHeight Plugin 14129 * @version 2.0.0-beta.3 14130 * @author Bartosz Wojciechowski 14131 * @license The MIT License (MIT) 14132 */ 14133;(function($, window, document, undefined) { 14134 14135 /** 14136 * Creates the auto height plugin. 14137 * @class The Auto Height Plugin 14138 * @param {Owl} carousel - The Owl Carousel 14139 */ 14140 var AutoHeight = function(carousel) { 14141 /** 14142 * Reference to the core. 14143 * @protected 14144 * @type {Owl} 14145 */ 14146 this._core = carousel; 14147 14148 /** 14149 * All event handlers. 14150 * @protected 14151 * @type {Object} 14152 */ 14153 this._handlers = { 14154 'initialized.owl.carousel refreshed.owl.carousel': $.proxy(function(e) { 14155 if (e.namespace && this._core.settings.autoHeight) { 14156 this.update(); 14157 } 14158 }, this), 14159 'changed.owl.carousel': $.proxy(function(e) { 14160 if (e.namespace && this._core.settings.autoHeight && e.property.name == 'position'){ 14161 this.update(); 14162 } 14163 }, this), 14164 'loaded.owl.lazy': $.proxy(function(e) { 14165 if (e.namespace && this._core.settings.autoHeight 14166 && e.element.closest('.' + this._core.settings.itemClass).index() === this._core.current()) { 14167 this.update(); 14168 } 14169 }, this) 14170 }; 14171 14172 // set default options 14173 this._core.options = $.extend({}, AutoHeight.Defaults, this._core.options); 14174 14175 // register event handlers 14176 this._core.$element.on(this._handlers); 14177 }; 14178 14179 /** 14180 * Default options. 14181 * @public 14182 */ 14183 AutoHeight.Defaults = { 14184 autoHeight: false, 14185 autoHeightClass: 'owl-height' 14186 }; 14187 14188 /** 14189 * Updates the view. 14190 */ 14191 AutoHeight.prototype.update = function() { 14192 var start = this._core._current, 14193 end = start + this._core.settings.items, 14194 visible = this._core.$stage.children().toArray().slice(start, end); 14195 heights = [], 14196 maxheight = 0; 14197 14198 $.each(visible, function(index, item) { 14199 heights.push($(item).height()); 14200 }); 14201 14202 maxheight = Math.max.apply(null, heights); 14203 14204 this._core.$stage.parent() 14205 .height(maxheight) 14206 .addClass(this._core.settings.autoHeightClass); 14207 }; 14208 14209 AutoHeight.prototype.destroy = function() { 14210 var handler, property; 14211 14212 for (handler in this._handlers) { 14213 this._core.$element.off(handler, this._handlers[handler]); 14214 } 14215 for (property in Object.getOwnPropertyNames(this)) { 14216 typeof this[property] != 'function' && (this[property] = null); 14217 } 14218 }; 14219 14220 $.fn.owlCarousel.Constructor.Plugins.AutoHeight = AutoHeight; 14221 14222})(window.Zepto || window.jQuery, window, document); 14223 14224/** 14225 * Video Plugin 14226 * @version 2.0.0-beta.3 14227 * @author Bartosz Wojciechowski 14228 * @license The MIT License (MIT) 14229 */ 14230;(function($, window, document, undefined) { 14231 14232 /** 14233 * Creates the video plugin. 14234 * @class The Video Plugin 14235 * @param {Owl} carousel - The Owl Carousel 14236 */ 14237 var Video = function(carousel) { 14238 /** 14239 * Reference to the core. 14240 * @protected 14241 * @type {Owl} 14242 */ 14243 this._core = carousel; 14244 14245 /** 14246 * Cache all video URLs. 14247 * @protected 14248 * @type {Object} 14249 */ 14250 this._videos = {}; 14251 14252 /** 14253 * Current playing item. 14254 * @protected 14255 * @type {jQuery} 14256 */ 14257 this._playing = null; 14258 14259 /** 14260 * All event handlers. 14261 * @todo The cloned content removale is too late 14262 * @protected 14263 * @type {Object} 14264 */ 14265 this._handlers = { 14266 'initialized.owl.carousel': $.proxy(function(e) { 14267 if (e.namespace) { 14268 this._core.register({ type: 'state', name: 'playing', tags: [ 'interacting' ] }); 14269 } 14270 }, this), 14271 'resize.owl.carousel': $.proxy(function(e) { 14272 if (e.namespace && this._core.settings.video && this.isInFullScreen()) { 14273 e.preventDefault(); 14274 } 14275 }, this), 14276 'refreshed.owl.carousel': $.proxy(function(e) { 14277 if (e.namespace && this._core.is('resizing')) { 14278 this._core.$stage.find('.cloned .owl-video-frame').remove(); 14279 } 14280 }, this), 14281 'changed.owl.carousel': $.proxy(function(e) { 14282 if (e.namespace && e.property.name === 'position' && this._playing) { 14283 this.stop(); 14284 } 14285 }, this), 14286 'prepared.owl.carousel': $.proxy(function(e) { 14287 if (!e.namespace) { 14288 return; 14289 } 14290 14291 var $element = $(e.content).find('.owl-video'); 14292 14293 if ($element.length) { 14294 $element.css('display', 'none'); 14295 this.fetch($element, $(e.content)); 14296 } 14297 }, this) 14298 }; 14299 14300 // set default options 14301 this._core.options = $.extend({}, Video.Defaults, this._core.options); 14302 14303 // register event handlers 14304 this._core.$element.on(this._handlers); 14305 14306 this._core.$element.on('click.owl.video', '.owl-video-play-icon', $.proxy(function(e) { 14307 this.play(e); 14308 }, this)); 14309 }; 14310 14311 /** 14312 * Default options. 14313 * @public 14314 */ 14315 Video.Defaults = { 14316 video: false, 14317 videoHeight: false, 14318 videoWidth: false 14319 }; 14320 14321 /** 14322 * Gets the video ID and the type (YouTube/Vimeo only). 14323 * @protected 14324 * @param {jQuery} target - The target containing the video data. 14325 * @param {jQuery} item - The item containing the video. 14326 */ 14327 Video.prototype.fetch = function(target, item) { 14328 var type = target.attr('data-vimeo-id') ? 'vimeo' : 'youtube', 14329 id = target.attr('data-vimeo-id') || target.attr('data-youtube-id'), 14330 width = target.attr('data-width') || this._core.settings.videoWidth, 14331 height = target.attr('data-height') || this._core.settings.videoHeight, 14332 url = target.attr('href'); 14333 14334 if (url) { 14335 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+)?/); 14336 14337 if (id[3].indexOf('youtu') > -1) { 14338 type = 'youtube'; 14339 } else if (id[3].indexOf('vimeo') > -1) { 14340 type = 'vimeo'; 14341 } else { 14342 throw new Error('Video URL not supported.'); 14343 } 14344 id = id[6]; 14345 } else { 14346 throw new Error('Missing video URL.'); 14347 } 14348 14349 this._videos[url] = { 14350 type: type, 14351 id: id, 14352 width: width, 14353 height: height 14354 }; 14355 14356 item.attr('data-video', url); 14357 14358 this.thumbnail(target, this._videos[url]); 14359 }; 14360 14361 /** 14362 * Creates video thumbnail. 14363 * @protected 14364 * @param {jQuery} target - The target containing the video data. 14365 * @param {Object} info - The video info object. 14366 * @see `fetch` 14367 */ 14368 Video.prototype.thumbnail = function(target, video) { 14369 var tnLink, 14370 icon, 14371 path, 14372 dimensions = video.width && video.height ? 'style="width:' + video.width + 'px;height:' + video.height + 'px;"' : '', 14373 customTn = target.find('img'), 14374 srcType = 'src', 14375 lazyClass = '', 14376 settings = this._core.settings, 14377 create = function(path) { 14378 icon = '<div class="owl-video-play-icon"></div>'; 14379 14380 if (settings.lazyLoad) { 14381 tnLink = '<div class="owl-video-tn ' + lazyClass + '" ' + srcType + '="' + path + '"></div>'; 14382 } else { 14383 tnLink = '<div class="owl-video-tn" style="opacity:1;background-image:url(' + path + ')"></div>'; 14384 } 14385 target.after(tnLink); 14386 target.after(icon); 14387 }; 14388 14389 // wrap video content into owl-video-wrapper div 14390 target.wrap('<div class="owl-video-wrapper"' + dimensions + '></div>'); 14391 14392 if (this._core.settings.lazyLoad) { 14393 srcType = 'data-src'; 14394 lazyClass = 'owl-lazy'; 14395 } 14396 14397 // custom thumbnail 14398 if (customTn.length) { 14399 create(customTn.attr(srcType)); 14400 customTn.remove(); 14401 return false; 14402 } 14403 14404 if (video.type === 'youtube') { 14405 path = "//img.youtube.com/vi/" + video.id + "/hqdefault.jpg"; 14406 create(path); 14407 } else if (video.type === 'vimeo') { 14408 $.ajax({ 14409 type: 'GET', 14410 url: '//vimeo.com/api/v2/video/' + video.id + '.json', 14411 jsonp: 'callback', 14412 dataType: 'jsonp', 14413 success: function(data) { 14414 path = data[0].thumbnail_large; 14415 create(path); 14416 } 14417 }); 14418 } 14419 }; 14420 14421 /** 14422 * Stops the current video. 14423 * @public 14424 */ 14425 Video.prototype.stop = function() { 14426 this._core.trigger('stop', null, 'video'); 14427 this._playing.find('.owl-video-frame').remove(); 14428 this._playing.removeClass('owl-video-playing'); 14429 this._playing = null; 14430 this._core.leave('playing'); 14431 this._core.trigger('stopped', null, 'video'); 14432 }; 14433 14434 /** 14435 * Starts the current video. 14436 * @public 14437 * @param {Event} event - The event arguments. 14438 */ 14439 Video.prototype.play = function(event) { 14440 var target = $(event.target), 14441 item = target.closest('.' + this._core.settings.itemClass), 14442 video = this._videos[item.attr('data-video')], 14443 width = video.width || '100%', 14444 height = video.height || this._core.$stage.height(), 14445 html; 14446 14447 if (this._playing) { 14448 return; 14449 } 14450 14451 this._core.enter('playing'); 14452 this._core.trigger('play', null, 'video'); 14453 14454 item = this._core.items(this._core.relative(item.index())); 14455 14456 this._core.reset(item.index()); 14457 14458 if (video.type === 'youtube') { 14459 html = '<iframe width="' + width + '" height="' + height + '" src="//www.youtube.com/embed/' + 14460 video.id + '?autoplay=1&v=' + video.id + '" frameborder="0" allowfullscreen></iframe>'; 14461 } else if (video.type === 'vimeo') { 14462 html = '<iframe src="//player.vimeo.com/video/' + video.id + 14463 '?autoplay=1" width="' + width + '" height="' + height + 14464 '" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>'; 14465 } 14466 14467 $('<div class="owl-video-frame">' + html + '</div>').insertAfter(item.find('.owl-video')); 14468 14469 this._playing = item.addClass('owl-video-playing'); 14470 }; 14471 14472 /** 14473 * Checks whether an video is currently in full screen mode or not. 14474 * @todo Bad style because looks like a readonly method but changes members. 14475 * @protected 14476 * @returns {Boolean} 14477 */ 14478 Video.prototype.isInFullScreen = function() { 14479 var element = document.fullscreenElement || document.mozFullScreenElement || 14480 document.webkitFullscreenElement; 14481 14482 return element && $(element).parent().hasClass('owl-video-frame'); 14483 }; 14484 14485 /** 14486 * Destroys the plugin. 14487 */ 14488 Video.prototype.destroy = function() { 14489 var handler, property; 14490 14491 this._core.$element.off('click.owl.video'); 14492 14493 for (handler in this._handlers) { 14494 this._core.$element.off(handler, this._handlers[handler]); 14495 } 14496 for (property in Object.getOwnPropertyNames(this)) { 14497 typeof this[property] != 'function' && (this[property] = null); 14498 } 14499 }; 14500 14501 $.fn.owlCarousel.Constructor.Plugins.Video = Video; 14502 14503})(window.Zepto || window.jQuery, window, document); 14504 14505/** 14506 * Animate Plugin 14507 * @version 2.0.0-beta.3 14508 * @author Bartosz Wojciechowski 14509 * @license The MIT License (MIT) 14510 */ 14511;(function($, window, document, undefined) { 14512 14513 /** 14514 * Creates the animate plugin. 14515 * @class The Navigation Plugin 14516 * @param {Owl} scope - The Owl Carousel 14517 */ 14518 var Animate = function(scope) { 14519 this.core = scope; 14520 this.core.options = $.extend({}, Animate.Defaults, this.core.options); 14521 this.swapping = true; 14522 this.previous = undefined; 14523 this.next = undefined; 14524 14525 this.handlers = { 14526 'change.owl.carousel': $.proxy(function(e) { 14527 if (e.namespace && e.property.name == 'position') { 14528 this.previous = this.core.current(); 14529 this.next = e.property.value; 14530 } 14531 }, this), 14532 'drag.owl.carousel dragged.owl.carousel translated.owl.carousel': $.proxy(function(e) { 14533 if (e.namespace) { 14534 this.swapping = e.type == 'translated'; 14535 } 14536 }, this), 14537 'translate.owl.carousel': $.proxy(function(e) { 14538 if (e.namespace && this.swapping && (this.core.options.animateOut || this.core.options.animateIn)) { 14539 this.swap(); 14540 } 14541 }, this) 14542 }; 14543 14544 this.core.$element.on(this.handlers); 14545 }; 14546 14547 /** 14548 * Default options. 14549 * @public 14550 */ 14551 Animate.Defaults = { 14552 animateOut: false, 14553 animateIn: false 14554 }; 14555 14556 /** 14557 * Toggles the animation classes whenever an translations starts. 14558 * @protected 14559 * @returns {Boolean|undefined} 14560 */ 14561 Animate.prototype.swap = function() { 14562 14563 if (this.core.settings.items !== 1) { 14564 return; 14565 } 14566 14567 if (!$.support.animation || !$.support.transition) { 14568 return; 14569 } 14570 14571 this.core.speed(0); 14572 14573 var left, 14574 clear = $.proxy(this.clear, this), 14575 previous = this.core.$stage.children().eq(this.previous), 14576 next = this.core.$stage.children().eq(this.next), 14577 incoming = this.core.settings.animateIn, 14578 outgoing = this.core.settings.animateOut; 14579 14580 if (this.core.current() === this.previous) { 14581 return; 14582 } 14583 14584 if (outgoing) { 14585 left = this.core.coordinates(this.previous) - this.core.coordinates(this.next); 14586 previous.css( { 'left': left + 'px' } ) 14587 .addClass('animated owl-animated-out') 14588 .addClass(outgoing) 14589 .on($.support.animation.end, clear); 14590 } 14591 14592 if (incoming) { 14593 next.addClass('animated owl-animated-in') 14594 .addClass(incoming) 14595 .on($.support.animation.end, clear); 14596 } 14597 }; 14598 14599 Animate.prototype.clear = function(e) { 14600 if ($(e.target).hasClass('animated')) { 14601 $(e.target).css( { 'left': '' } ) 14602 .removeClass('animated owl-animated-out owl-animated-in') 14603 .removeClass(this.core.settings.animateIn) 14604 .removeClass(this.core.settings.animateOut); 14605 this.core.onTransitionEnd(); 14606 } 14607 }; 14608 14609 /** 14610 * Destroys the plugin. 14611 * @public 14612 */ 14613 Animate.prototype.destroy = function() { 14614 var handler, property; 14615 14616 for (handler in this.handlers) { 14617 this.core.$element.off(handler, this.handlers[handler]); 14618 } 14619 for (property in Object.getOwnPropertyNames(this)) { 14620 typeof this[property] != 'function' && (this[property] = null); 14621 } 14622 }; 14623 14624 $.fn.owlCarousel.Constructor.Plugins.Animate = Animate; 14625 14626})(window.Zepto || window.jQuery, window, document); 14627 14628/** 14629 * Autoplay Plugin 14630 * @version 2.0.0-beta.3 14631 * @author Bartosz Wojciechowski 14632 * @author Artus Kolanowski 14633 * @license The MIT License (MIT) 14634 */ 14635;(function($, window, document, undefined) { 14636 14637 /** 14638 * Creates the autoplay plugin. 14639 * @class The Autoplay Plugin 14640 * @param {Owl} scope - The Owl Carousel 14641 */ 14642 var Autoplay = function(carousel) { 14643 /** 14644 * Reference to the core. 14645 * @protected 14646 * @type {Owl} 14647 */ 14648 this._core = carousel; 14649 14650 /** 14651 * The autoplay interval. 14652 * @type {Number} 14653 */ 14654 this._interval = null; 14655 14656 /** 14657 * Indicates whenever the autoplay is paused. 14658 * @type {Boolean} 14659 */ 14660 this._paused = false; 14661 14662 /** 14663 * All event handlers. 14664 * @protected 14665 * @type {Object} 14666 */ 14667 this._handlers = { 14668 'changed.owl.carousel': $.proxy(function(e) { 14669 if (e.namespace && e.property.name === 'settings') { 14670 if (this._core.settings.autoplay) { 14671 this.play(); 14672 } else { 14673 this.stop(); 14674 } 14675 } 14676 }, this), 14677 'initialized.owl.carousel': $.proxy(function(e) { 14678 if (e.namespace && this._core.settings.autoplay) { 14679 this.play(); 14680 } 14681 }, this), 14682 'play.owl.autoplay': $.proxy(function(e, t, s) { 14683 if (e.namespace) { 14684 this.play(t, s); 14685 } 14686 }, this), 14687 'stop.owl.autoplay': $.proxy(function(e) { 14688 if (e.namespace) { 14689 this.stop(); 14690 } 14691 }, this), 14692 'mouseover.owl.autoplay': $.proxy(function() { 14693 if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) { 14694 this.pause(); 14695 } 14696 }, this), 14697 'mouseleave.owl.autoplay': $.proxy(function() { 14698 if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) { 14699 this.play(); 14700 } 14701 }, this) 14702 }; 14703 14704 // register event handlers 14705 this._core.$element.on(this._handlers); 14706 14707 // set default options 14708 this._core.options = $.extend({}, Autoplay.Defaults, this._core.options); 14709 }; 14710 14711 /** 14712 * Default options. 14713 * @public 14714 */ 14715 Autoplay.Defaults = { 14716 autoplay: false, 14717 autoplayTimeout: 5000, 14718 autoplayHoverPause: false, 14719 autoplaySpeed: false 14720 }; 14721 14722 /** 14723 * Starts the autoplay. 14724 * @public 14725 * @param {Number} [timeout] - The interval before the next animation starts. 14726 * @param {Number} [speed] - The animation speed for the animations. 14727 */ 14728 Autoplay.prototype.play = function(timeout, speed) { 14729 this._paused = false; 14730 14731 if (this._core.is('rotating')) { 14732 return; 14733 } 14734 14735 this._core.enter('rotating'); 14736 14737 this._interval = window.setInterval($.proxy(function() { 14738 if (this._paused || this._core.is('busy') || this._core.is('interacting') || document.hidden) { 14739 return; 14740 } 14741 this._core.next(speed || this._core.settings.autoplaySpeed); 14742 }, this), timeout || this._core.settings.autoplayTimeout); 14743 }; 14744 14745 /** 14746 * Stops the autoplay. 14747 * @public 14748 */ 14749 Autoplay.prototype.stop = function() { 14750 if (!this._core.is('rotating')) { 14751 return; 14752 } 14753 14754 window.clearInterval(this._interval); 14755 this._core.leave('rotating'); 14756 }; 14757 14758 /** 14759 * Stops the autoplay. 14760 * @public 14761 */ 14762 Autoplay.prototype.pause = function() { 14763 if (!this._core.is('rotating')) { 14764 return; 14765 } 14766 14767 this._paused = true; 14768 }; 14769 14770 /** 14771 * Destroys the plugin. 14772 */ 14773 Autoplay.prototype.destroy = function() { 14774 var handler, property; 14775 14776 this.stop(); 14777 14778 for (handler in this._handlers) { 14779 this._core.$element.off(handler, this._handlers[handler]); 14780 } 14781 for (property in Object.getOwnPropertyNames(this)) { 14782 typeof this[property] != 'function' && (this[property] = null); 14783 } 14784 }; 14785 14786 $.fn.owlCarousel.Constructor.Plugins.autoplay = Autoplay; 14787 14788})(window.Zepto || window.jQuery, window, document); 14789 14790/** 14791 * Navigation Plugin 14792 * @version 2.0.0-beta.3 14793 * @author Artus Kolanowski 14794 * @license The MIT License (MIT) 14795 */ 14796;(function($, window, document, undefined) { 14797 'use strict'; 14798 14799 /** 14800 * Creates the navigation plugin. 14801 * @class The Navigation Plugin 14802 * @param {Owl} carousel - The Owl Carousel. 14803 */ 14804 var Navigation = function(carousel) { 14805 /** 14806 * Reference to the core. 14807 * @protected 14808 * @type {Owl} 14809 */ 14810 this._core = carousel; 14811 14812 /** 14813 * Indicates whether the plugin is initialized or not. 14814 * @protected 14815 * @type {Boolean} 14816 */ 14817 this._initialized = false; 14818 14819 /** 14820 * The current paging indexes. 14821 * @protected 14822 * @type {Array} 14823 */ 14824 this._pages = []; 14825 14826 /** 14827 * All DOM elements of the user interface. 14828 * @protected 14829 * @type {Object} 14830 */ 14831 this._controls = {}; 14832 14833 /** 14834 * Markup for an indicator. 14835 * @protected 14836 * @type {Array.<String>} 14837 */ 14838 this._templates = []; 14839 14840 /** 14841 * The carousel element. 14842 * @type {jQuery} 14843 */ 14844 this.$element = this._core.$element; 14845 14846 /** 14847 * Overridden methods of the carousel. 14848 * @protected 14849 * @type {Object} 14850 */ 14851 this._overrides = { 14852 next: this._core.next, 14853 prev: this._core.prev, 14854 to: this._core.to 14855 }; 14856 14857 /** 14858 * All event handlers. 14859 * @protected 14860 * @type {Object} 14861 */ 14862 this._handlers = { 14863 'prepared.owl.carousel': $.proxy(function(e) { 14864 if (e.namespace && this._core.settings.dotsData) { 14865 this._templates.push('<div class="' + this._core.settings.dotClass + '">' + 14866 $(e.content).find('[data-dot]').andSelf('[data-dot]').attr('data-dot') + '</div>'); 14867 } 14868 }, this), 14869 'added.owl.carousel': $.proxy(function(e) { 14870 if (e.namespace && this._core.settings.dotsData) { 14871 this._templates.splice(e.position, 0, this._templates.pop()); 14872 } 14873 }, this), 14874 'remove.owl.carousel': $.proxy(function(e) { 14875 if (e.namespace && this._core.settings.dotsData) { 14876 this._templates.splice(e.position, 1); 14877 } 14878 }, this), 14879 'changed.owl.carousel': $.proxy(function(e) { 14880 if (e.namespace && e.property.name == 'position') { 14881 this.draw(); 14882 } 14883 }, this), 14884 'initialized.owl.carousel': $.proxy(function(e) { 14885 if (e.namespace && !this._initialized) { 14886 this._core.trigger('initialize', null, 'navigation'); 14887 this.initialize(); 14888 this.update(); 14889 this.draw(); 14890 this._initialized = true; 14891 this._core.trigger('initialized', null, 'navigation'); 14892 } 14893 }, this), 14894 'refreshed.owl.carousel': $.proxy(function(e) { 14895 if (e.namespace && this._initialized) { 14896 this._core.trigger('refresh', null, 'navigation'); 14897 this.update(); 14898 this.draw(); 14899 this._core.trigger('refreshed', null, 'navigation'); 14900 } 14901 }, this) 14902 }; 14903 14904 // set default options 14905 this._core.options = $.extend({}, Navigation.Defaults, this._core.options); 14906 14907 // register event handlers 14908 this.$element.on(this._handlers); 14909 }; 14910 14911 /** 14912 * Default options. 14913 * @public 14914 * @todo Rename `slideBy` to `navBy` 14915 */ 14916 Navigation.Defaults = { 14917 nav: false, 14918 navText: [ 'prev', 'next' ], 14919 navSpeed: false, 14920 navElement: 'div', 14921 navContainer: false, 14922 navContainerClass: 'owl-nav', 14923 navClass: [ 'owl-prev', 'owl-next' ], 14924 slideBy: 1, 14925 dotClass: 'owl-dot', 14926 dotsClass: 'owl-dots', 14927 dots: true, 14928 dotsEach: false, 14929 dotsData: false, 14930 dotsSpeed: false, 14931 dotsContainer: false 14932 }; 14933 14934 /** 14935 * Initializes the layout of the plugin and extends the carousel. 14936 * @protected 14937 */ 14938 Navigation.prototype.initialize = function() { 14939 var override, 14940 settings = this._core.settings; 14941 14942 // create DOM structure for relative navigation 14943 this._controls.$relative = (settings.navContainer ? $(settings.navContainer) 14944 : $('<div>').addClass(settings.navContainerClass).appendTo(this.$element)).addClass('disabled'); 14945 14946 this._controls.$previous = $('<' + settings.navElement + '>') 14947 .addClass(settings.navClass[0]) 14948 .html(settings.navText[0]) 14949 .prependTo(this._controls.$relative) 14950 .on('click', $.proxy(function(e) { 14951 this.prev(settings.navSpeed); 14952 }, this)); 14953 this._controls.$next = $('<' + settings.navElement + '>') 14954 .addClass(settings.navClass[1]) 14955 .html(settings.navText[1]) 14956 .appendTo(this._controls.$relative) 14957 .on('click', $.proxy(function(e) { 14958 this.next(settings.navSpeed); 14959 }, this)); 14960 14961 // create DOM structure for absolute navigation 14962 if (!settings.dotsData) { 14963 this._templates = [ $('<div>') 14964 .addClass(settings.dotClass) 14965 .append($('<span>')) 14966 .prop('outerHTML') ]; 14967 } 14968 14969 this._controls.$absolute = (settings.dotsContainer ? $(settings.dotsContainer) 14970 : $('<div>').addClass(settings.dotsClass).appendTo(this.$element)).addClass('disabled'); 14971 14972 this._controls.$absolute.on('click', 'div', $.proxy(function(e) { 14973 var index = $(e.target).parent().is(this._controls.$absolute) 14974 ? $(e.target).index() : $(e.target).parent().index(); 14975 14976 e.preventDefault(); 14977 14978 this.to(index, settings.dotsSpeed); 14979 }, this)); 14980 14981 // override public methods of the carousel 14982 for (override in this._overrides) { 14983 this._core[override] = $.proxy(this[override], this); 14984 } 14985 }; 14986 14987 /** 14988 * Destroys the plugin. 14989 * @protected 14990 */ 14991 Navigation.prototype.destroy = function() { 14992 var handler, control, property, override; 14993 14994 for (handler in this._handlers) { 14995 this.$element.off(handler, this._handlers[handler]); 14996 } 14997 for (control in this._controls) { 14998 this._controls[control].remove(); 14999 } 15000 for (override in this.overides) { 15001 this._core[override] = this._overrides[override]; 15002 } 15003 for (property in Object.getOwnPropertyNames(this)) { 15004 typeof this[property] != 'function' && (this[property] = null); 15005 } 15006 }; 15007 15008 /** 15009 * Updates the internal state. 15010 * @protected 15011 */ 15012 Navigation.prototype.update = function() { 15013 var i, j, k, 15014 lower = this._core.clones().length / 2, 15015 upper = lower + this._core.items().length, 15016 maximum = this._core.maximum(true), 15017 settings = this._core.settings, 15018 size = settings.center || settings.autoWidth || settings.dotsData 15019 ? 1 : settings.dotsEach || settings.items; 15020 15021 if (settings.slideBy !== 'page') { 15022 settings.slideBy = Math.min(settings.slideBy, settings.items); 15023 } 15024 15025 if (settings.dots || settings.slideBy == 'page') { 15026 this._pages = []; 15027 15028 for (i = lower, j = 0, k = 0; i < upper; i++) { 15029 if (j >= size || j === 0) { 15030 this._pages.push({ 15031 start: Math.min(maximum, i - lower), 15032 end: i - lower + size - 1 15033 }); 15034 if (Math.min(maximum, i - lower) === maximum) { 15035 break; 15036 } 15037 j = 0, ++k; 15038 } 15039 j += this._core.mergers(this._core.relative(i)); 15040 } 15041 } 15042 }; 15043 15044 /** 15045 * Draws the user interface. 15046 * @todo The option `dotsData` wont work. 15047 * @protected 15048 */ 15049 Navigation.prototype.draw = function() { 15050 var difference, 15051 settings = this._core.settings, 15052 disabled = this._core.items().length <= settings.items, 15053 index = this._core.relative(this._core.current()), 15054 loop = settings.loop || settings.rewind; 15055 15056 this._controls.$relative.toggleClass('disabled', !settings.nav || disabled); 15057 15058 if (settings.nav) { 15059 this._controls.$previous.toggleClass('disabled', !loop && index <= this._core.minimum(true)); 15060 this._controls.$next.toggleClass('disabled', !loop && index >= this._core.maximum(true)); 15061 } 15062 15063 this._controls.$absolute.toggleClass('disabled', !settings.dots || disabled); 15064 15065 if (settings.dots) { 15066 difference = this._pages.length - this._controls.$absolute.children().length; 15067 15068 if (settings.dotsData && difference !== 0) { 15069 this._controls.$absolute.html(this._templates.join('')); 15070 } else if (difference > 0) { 15071 this._controls.$absolute.append(new Array(difference + 1).join(this._templates[0])); 15072 } else if (difference < 0) { 15073 this._controls.$absolute.children().slice(difference).remove(); 15074 } 15075 15076 this._controls.$absolute.find('.active').removeClass('active'); 15077 this._controls.$absolute.children().eq($.inArray(this.current(), this._pages)).addClass('active'); 15078 } 15079 }; 15080 15081 /** 15082 * Extends event data. 15083 * @protected 15084 * @param {Event} event - The event object which gets thrown. 15085 */ 15086 Navigation.prototype.onTrigger = function(event) { 15087 var settings = this._core.settings; 15088 15089 event.page = { 15090 index: $.inArray(this.current(), this._pages), 15091 count: this._pages.length, 15092 size: settings && (settings.center || settings.autoWidth || settings.dotsData 15093 ? 1 : settings.dotsEach || settings.items) 15094 }; 15095 }; 15096 15097 /** 15098 * Gets the current page position of the carousel. 15099 * @protected 15100 * @returns {Number} 15101 */ 15102 Navigation.prototype.current = function() { 15103 var current = this._core.relative(this._core.current()); 15104 return $.grep(this._pages, $.proxy(function(page, index) { 15105 return page.start <= current && page.end >= current; 15106 }, this)).pop(); 15107 }; 15108 15109 /** 15110 * Gets the current succesor/predecessor position. 15111 * @protected 15112 * @returns {Number} 15113 */ 15114 Navigation.prototype.getPosition = function(successor) { 15115 var position, length, 15116 settings = this._core.settings; 15117 15118 if (settings.slideBy == 'page') { 15119 position = $.inArray(this.current(), this._pages); 15120 length = this._pages.length; 15121 successor ? ++position : --position;
vendor: 5,678 bytes, lines 15122-15346
15122 position = this._pages[((position % length) + length) % length].start; 15123 } else { 15124 position = this._core.relative(this._core.current()); 15125 length = this._core.items().length; 15126 successor ? position += settings.slideBy : position -= settings.slideBy; 15127 } 15128 15129 return position; 15130 }; 15131 15132 /** 15133 * Slides to the next item or page. 15134 * @public 15135 * @param {Number} [speed=false] - The time in milliseconds for the transition. 15136 */ 15137 Navigation.prototype.next = function(speed) { 15138 $.proxy(this._overrides.to, this._core)(this.getPosition(true), speed); 15139 }; 15140 15141 /** 15142 * Slides to the previous item or page. 15143 * @public 15144 * @param {Number} [speed=false] - The time in milliseconds for the transition. 15145 */ 15146 Navigation.prototype.prev = function(speed) { 15147 $.proxy(this._overrides.to, this._core)(this.getPosition(false), speed); 15148 }; 15149 15150 /** 15151 * Slides to the specified item or page. 15152 * @public 15153 * @param {Number} position - The position of the item or page. 15154 * @param {Number} [speed] - The time in milliseconds for the transition. 15155 * @param {Boolean} [standard=false] - Whether to use the standard behaviour or not. 15156 */ 15157 Navigation.prototype.to = function(position, speed, standard) { 15158 var length; 15159 15160 if (!standard) { 15161 length = this._pages.length; 15162 $.proxy(this._overrides.to, this._core)(this._pages[((position % length) + length) % length].start, speed); 15163 } else { 15164 $.proxy(this._overrides.to, this._core)(position, speed); 15165 } 15166 }; 15167 15168 $.fn.owlCarousel.Constructor.Plugins.Navigation = Navigation; 15169 15170})(window.Zepto || window.jQuery, window, document); 15171 15172/** 15173 * Hash Plugin 15174 * @version 2.0.0-beta.3 15175 * @author Artus Kolanowski 15176 * @license The MIT License (MIT) 15177 */ 15178;(function($, window, document, undefined) { 15179 'use strict'; 15180 15181 /** 15182 * Creates the hash plugin. 15183 * @class The Hash Plugin 15184 * @param {Owl} carousel - The Owl Carousel 15185 */ 15186 var Hash = function(carousel) { 15187 /** 15188 * Reference to the core. 15189 * @protected 15190 * @type {Owl} 15191 */ 15192 this._core = carousel; 15193 15194 /** 15195 * Hash index for the items. 15196 * @protected 15197 * @type {Object} 15198 */ 15199 this._hashes = {}; 15200 15201 /** 15202 * The carousel element. 15203 * @type {jQuery} 15204 */ 15205 this.$element = this._core.$element; 15206 15207 /** 15208 * All event handlers. 15209 * @protected 15210 * @type {Object} 15211 */ 15212 this._handlers = { 15213 /*'initialized.owl.carousel': $.proxy(function(e) { 15214 if (e.namespace && this._core.settings.startPosition === 'URLHash') { 15215 $(window).trigger('hashchange.owl.navigation'); 15216 } 15217 }, this),*/ 15218 'prepared.owl.carousel': $.proxy(function(e) { 15219 if (e.namespace) { 15220 var hash = $(e.content).find('[data-hash]').addBack('[data-hash]').attr('data-hash'); 15221 15222 if (!hash) { 15223 return; 15224 } 15225 15226 this._hashes[hash] = e.content; 15227 } 15228 }, this), 15229 'changed.owl.carousel': $.proxy(function(e) { 15230 if (e.namespace && e.property.name === 'position') { 15231 var current = this._core.items(this._core.relative(this._core.current())), 15232 hash = $.map(this._hashes, function(item, hash) { 15233 return item === current ? hash : null; 15234 }).join(); 15235 15236 if (!hash || window.location.hash.slice(1) === hash) { 15237 return; 15238 } 15239 15240 window.location.hash = hash; 15241 } 15242 }, this) 15243 }; 15244 15245 // set default options 15246 this._core.options = $.extend({}, Hash.Defaults, this._core.options); 15247 15248 // register the event handlers 15249 this.$element.on(this._handlers); 15250 15251 // register event listener for hash navigation 15252 /*$(window).on('hashchange.owl.navigation', $.proxy(function(e) { 15253 var hash = window.location.hash.substring(1), 15254 items = this._core.$stage.children(), 15255 position = this._hashes[hash] && items.index(this._hashes[hash]); 15256 15257 if (position === undefined || position === this._core.current()) { 15258 return; 15259 } 15260 15261 this._core.to(this._core.relative(position), false, true); 15262 }, this));*/ 15263 }; 15264 15265 /** 15266 * Default options. 15267 * @public 15268 */ 15269 Hash.Defaults = { 15270 URLhashListener: false 15271 }; 15272 15273 /** 15274 * Destroys the plugin. 15275 * @public 15276 */ 15277 Hash.prototype.destroy = function() { 15278 var handler, property; 15279 15280 $(window).off('hashchange.owl.navigation'); 15281 15282 for (handler in this._handlers) { 15283 this._core.$element.off(handler, this._handlers[handler]); 15284 } 15285 for (property in Object.getOwnPropertyNames(this)) { 15286 typeof this[property] != 'function' && (this[property] = null); 15287 } 15288 }; 15289 15290 $.fn.owlCarousel.Constructor.Plugins.Hash = Hash; 15291 15292})(window.Zepto || window.jQuery, window, document); 15293 15294/** 15295 * Support Plugin 15296 * 15297 * @version 2.0.0-beta.3 15298 * @author Vivid Planet Software GmbH 15299 * @author Artus Kolanowski 15300 * @license The MIT License (MIT) 15301 */ 15302;(function($, window, document, undefined) { 15303 15304 var style = $('<support>').get(0).style, 15305 prefixes = 'Webkit Moz O ms'.split(' '), 15306 events = { 15307 transition: { 15308 end: { 15309 WebkitTransition: 'webkitTransitionEnd', 15310 MozTransition: 'transitionend', 15311 OTransition: 'oTransitionEnd', 15312 transition: 'transitionend' 15313 } 15314 }, 15315 animation: { 15316 end: { 15317 WebkitAnimation: 'webkitAnimationEnd', 15318 MozAnimation: 'animationend', 15319 OAnimation: 'oAnimationEnd', 15320 animation: 'animationend' 15321 } 15322 } 15323 }, 15324 tests = { 15325 csstransforms: function() { 15326 return !!test('transform'); 15327 }, 15328 csstransforms3d: function() { 15329 return !!test('perspective'); 15330 }, 15331 csstransitions: function() { 15332 return !!test('transition'); 15333 }, 15334 cssanimations: function() { 15335 return !!test('animation'); 15336 } 15337 }; 15338 15339 function test(property, prefixed) { 15340 var result = false, 15341 upper = property.charAt(0).toUpperCase() + property.slice(1); 15342 15343 $.each((property + ' ' + prefixes.join(upper + ' ') + upper).split(' '), function(i, property) { 15344 if (style[property] !== undefined) { 15345 result = prefixed ? property : true; 15346 return false;
15347 } 15348 }); 15349 15350 return result; 15351 } 15352 15353 function prefixed(property) { 15354 return test(property, true); 15355 } 15356 15357 if (tests.csstransitions()) { 15358 /* jshint -W053 */ 15359 $.support.transition = new String(prefixed('transition')) 15360 $.support.transition.end = events.transition.end[ $.support.transition ]; 15361 } 15362 15363 if (tests.cssanimations()) { 15364 /* jshint -W053 */ 15365 $.support.animation = new String(prefixed('animation')) 15366 $.support.animation.end = events.animation.end[ $.support.animation ]; 15367 } 15368 15369 if (tests.csstransforms()) { 15370 /* jshint -W053 */ 15371 $.support.transform = new String(prefixed('transform')); 15372 $.support.transform3d = tests.csstransforms3d(); 15373 } 15374 15375})(window.Zepto || window.jQuery, window, document); 15376(function(window, document, undefined) { 15377 15378 /** 15379 * Find the absolute position of an element 15380 */ 15381 var absPos = function(element) { 15382 var offsetLeft, offsetTop; 15383 offsetLeft = offsetTop = 0; 15384 if (element.offsetParent) { 15385 do { 15386 offsetLeft += element.offsetLeft; 15387 offsetTop += element.offsetTop; 15388 } while (element = element.offsetParent); 15389 } 15390 return [offsetLeft, offsetTop]; 15391 }; 15392 15393 /** 15394 * @constructor Progress Circle class 15395 * @param params.canvas Canvas on which the circles will be drawn. 15396 * @param params.minRadius Inner radius of the innermost circle, in px. 15397 * @param params.arcWidth Width of each circle(to be more accurate, ring). 15398 * @param params.gapWidth Space between each circle. 15399 * @param params.centerX X coordinate of the center of circles. 15400 * @param params.centerY Y coordinate of the center of circles. 15401 * @param params.infoLineBaseAngle Base angle of the info line. 15402 * @param params.infoLineAngleInterval Angles between the info lines. 15403 */ 15404 var ProgressCircle = function(params) { 15405 this.canvas = params.canvas; 15406 this.minRadius = params.minRadius || 15; 15407 this.arcWidth = params.arcWidth || 5; 15408 this.gapWidth = params.gapWidth || 3; 15409 this.centerX = params.centerX || this.canvas.width / 2; 15410 this.centerY = params.centerY || this.canvas.height / 2;
15411 this.infoLineLength = params.infoLineLength || 60; 15412 this.horizLineLength = params.horizLineLength || 10; 15413 this.infoLineAngleInterval = params.infoLineAngleInterval || Math.PI / 8; 15414 this.infoLineBaseAngle = params.infoLineBaseAngle || Math.PI / 6; 15415 15416 this.context = this.canvas.getContext('2d'); 15417 15418 this.width = this.canvas.width; 15419 this.height = this.canvas.height; 15420 15421 this.circles = []; 15422 this.runningCount = 0; 15423 }; 15424 15425 ProgressCircle.prototype = { 15426 constructor: ProgressCircle, 15427 15428 /** 15429 * @method Adds an progress monitor entry. 15430 * @param params.fillColor Color to fill in the circle. 15431 * @param params.outlineColor Color to outline the circle. 15432 * @param params.progressListener Callback function to fetch the progress. 15433 * @param params.infoListener Callback function to fetch the info. 15434 * @returns this 15435 */ 15436 addEntry: function(params) { 15437 this.circles.push(new Circle({ 15438 canvas: this.canvas, 15439 context: this.context, 15440 centerX: this.centerX, 15441 centerY: this.centerY, 15442 innerRadius: this.minRadius + this.circles.length * 15443 (this.gapWidth + this.arcWidth), 15444 arcWidth: this.arcWidth,
15445 infoLineLength: this.infoLineLength, 15446 horizLineLength: this.horizLineLength, 15447 15448 id: this.circles.length, 15449 fillColor: params.fillColor, 15450 outlineColor: params.outlineColor, 15451 progressListener: params.progressListener, 15452 infoListener: params.infoListener, 15453 infoLineAngle: this.infoLineBaseAngle + 15454 this.circles.length * this.infoLineAngleInterval, 15455 })); 15456 15457 return this; 15458 }, 15459 15460 /** 15461 * @method Starts the monitor and updates with the given interval. 15462 * @param interval Interval between updates, in millisecond. 15463 * @returns this 15464 */ 15465 start: function(interval) { 15466 var self = this; 15467 this.timer = setInterval(function() { 15468 self._update(); 15469 }, interval || 33); 15470 15471 return this; 15472 }, 15473 15474 /** 15475 * @method Stop the animation. 15476 */ 15477 stop: function() { 15478 clearTimeout(this.timer); 15479 }, 15480 15481 /** 15482 * @private 15483 * @method Call update on each circle and redraw them. 15484 * @returns this 15485 */ 15486 _update: function() { 15487 this._clear(); 15488 this.circles.forEach(function(circle, idx, array) { 15489 circle.update(); 15490 }); 15491 15492 return this; 15493 }, 15494 15495 /** 15496 * @private 15497 * @method Clear the canvas. 15498 * @returns this 15499 */ 15500 _clear: function() { 15501 this.context.clearRect(0, 0, this.canvas.width, this.canvas.height); 15502 15503 return this; 15504 }, 15505 15506 }; 15507 15508 /** 15509 * @private 15510 * @class Individual progress circle. 15511 * @param params.canvas Canvas on which the circle will be drawn. 15512 * @param params.context Context of the canvas. 15513 * @param params.innerRadius Inner radius of the circle, in px. 15514 * @param params.arcWidth Width of each arc(circle). 15515 * @param params.gapWidth Distance between each arc. 15516 * @param params.centerX X coordinate of the center of circles. 15517 * @param params.centerY Y coordinate of the center of circles. 15518 * @param params.fillColor Color to fill in the circle. 15519 * @param params.outlineColor Color to outline the circle. 15520 * @param params.progressListener Callback function to fetch the progress. 15521 * @param params.infoListener Callback function to fetch the info. 15522 * @param params.infoLineAngle Angle of info line. 15523 */ 15524 var Circle = function(params) { 15525 this.id = params.id; 15526 this.canvas = params.canvas; 15527 this.context = params.context; 15528 this.centerX = params.centerX; 15529 this.centerY = params.centerY; 15530 this.arcWidth = params.arcWidth; 15531 this.innerRadius = params.innerRadius || 0; 15532 this.fillColor = params.fillColor || '#fff'; 15533 this.outlineColor = params.outlineColor || this.fillColor; 15534 this.progressListener = params.progressListener;
15535 this.infoLineLength = params.infoLineLength || 250; 15536 this.horizLineLength = params.horizLineLength || 50; 15537 this.infoListener = params.infoListener; 15538 this.infoLineAngle = params.infoLineAngle; 15539 15540 this.outerRadius = this.innerRadius + this.arcWidth; 15541 15542 // If the info listener is not registered, then don't calculate 15543 // the related coordinates 15544 if (!this.infoListener) return; 15545 15546 // calculate the info-line turning points 15547 var angle = this.infoLineAngle, 15548 arcDistance = (this.innerRadius + this.outerRadius) / 2, 15549 15550 sinA = Math.sin(angle), 15551 cosA = Math.cos(angle); 15552 15553 this.infoLineStartX = this.centerX + sinA * arcDistance; 15554 this.infoLineStartY = this.centerY - cosA * arcDistance; 15555 15556 this.infoLineMidX = this.centerX + sinA * this.infoLineLength; 15557 this.infoLineMidY = this.centerY - cosA * this.infoLineLength; 15558 15559 this.infoLineEndX = this.infoLineMidX + 15560 (sinA < 0 ? -this.horizLineLength : this.horizLineLength); 15561 this.infoLineEndY = this.infoLineMidY; 15562 15563 var infoText = document.createElement('div'), 15564 style = infoText.style; 15565 15566 style.color = this.fillColor; 15567 style.position = 'absolute'; 15568 style.left = this.infoLineEndX + absPos(this.canvas)[0] + 'px'; 15569 // style.top will be calculated in the `drawInfo` method. Since 15570 // user may want to change the size of the font, so the top offset 15571 // must be updated in each loop. 15572 infoText.className = 'ProgressCircleInfo'; // For css styling 15573 infoText.id = 'progress_circle_info_' + this.id; 15574 document.body.appendChild(infoText); 15575 this.infoText = infoText; 15576 }; 15577 15578 Circle.prototype = { 15579 constructor: Circle, 15580 15581 update: function() { 15582 this.progress = this.progressListener(); 15583 this._draw(); 15584 15585 if (this.infoListener) { 15586 this.info = this.infoListener(); 15587 this._drawInfo(); 15588 } 15589 }, 15590 15591 /** 15592 * @private 15593 * @method Draw the circle on the canvas. 15594 * @returns this 15595 */ 15596 _draw: function() { 15597 var ctx = this.context, 15598 15599 ANGLE_OFFSET = -Math.PI / 2, 15600 15601 startAngle = 0 + ANGLE_OFFSET, 15602 endAngle= startAngle + this.progress * Math.PI * 2, 15603 15604 x = this.centerX, 15605 y = this.centerY, 15606 15607 innerRadius = this.innerRadius - this.arcWidth - 1, 15608 outerRadius = this.outerRadius - this.arcWidth - 1; 15609 15610 ctx.fillStyle = this.fillColor; 15611 ctx.strokeStyle = this.outlineColor; 15612 15613 ctx.beginPath(); 15614 ctx.arc(x, y, innerRadius, startAngle, endAngle, false); 15615 ctx.arc(x, y, outerRadius, endAngle, startAngle, true); 15616 ctx.closePath(); 15617 ctx.stroke(); 15618 ctx.fill(); 15619 15620 return this; 15621 }, 15622 15623 /** 15624 * @private 15625 * @method Draw the info lines and info text. 15626 * @returns this 15627 */ 15628 _drawInfo: function() { 15629 15630 var pointList, lineHeight; 15631 15632 pointList = [ 15633 [this.infoLineStartX, this.infoLineStartY], 15634 [this.infoLineMidX, this.infoLineMidY], 15635 [this.infoLineEndX, this.infoLineEndY], 15636 ]; 15637 this._drawSegments(pointList, false); 15638 15639 this.infoText.innerHTML = this.info; 15640 15641 lineHeight = this.infoText.offsetHeight; 15642 this.infoText.style.top = this.infoLineEndY + 15643 absPos(this.canvas)[1] - lineHeight / 2 + 'px'; 15644 15645 return this; 15646 }, 15647 15648 /** 15649 * @private 15650 * @method Helper function to draw the segments 15651 * @param pointList An array of points in the form of [x, y]. 15652 * @param close Whether to connect the first and last point. 15653 */ 15654 _drawSegments: function(pointList, close) { 15655 var ctx = this.context; 15656 15657 ctx.beginPath(); 15658 ctx.moveTo(pointList[0][0], pointList[0][1]); 15659 for (var i = 1; i < pointList.length; ++i) { 15660 ctx.lineTo(pointList[i][0], pointList[i][1]); 15661 } 15662 15663 if (close) { 15664 ctx.closePath(); 15665 } 15666 ctx.stroke(); 15667 }, 15668 }; 15669 15670 window.ProgressCircle = ProgressCircle; 15671 15672})(window, document); 15673 15674 15675 15676 15677/* ========================================================= 15678 * jquery.vc_chart.js v1.0 15679 * ========================================================= 15680 * Copyright 2013 Wpbakery 15681 * 15682 * Jquery chart plugin for the Visual Composer.
15683 * ========================================================= */ 15684(function($){ 15685 /** 15686 * Pie chart animated. 15687 * @param element - DOM element 15688 * @param options - settings object. 15689 * @constructor 15690 */ 15691 var VcChart = function(element, options) { 15692 this.el = element; 15693 this.$el = $(this.el); 15694 this.options = $.extend({ 15695 color: 'wpb_button', 15696 units: '', 15697 width: '', 15698 label_selector: '.vc_pie_chart_value', 15699 back_selector: '.vc_pie_chart_back', 15700 responsive: true 15701 }, options); 15702 this.init(); 15703 }; 15704 VcChart.prototype = { 15705 constructor: VcChart, 15706 _progress_v: 0, 15707 animated: false, 15708 colors: { 15709 'wpb_button': 'rgba(247, 247, 247, 1)', 15710 'btn-primary': 'rgba(0, 136, 204, 1)', 15711 'btn-info': 'rgba(88, 185, 218, 1)', 15712 'btn-success': 'rgba(106, 177, 101, 1)', 15713 'btn-warning': 'rgba(255, 153, 0, 1)', 15714 'btn-danger': 'rgba(255, 103, 91, 1)', 15715 'btn-inverse': 'rgba(85, 85, 85, 1)' 15716 }, 15717 init: function() { 15718 this.setupColor(); 15719 this.value = this.$el.data('pie-value')/100; 15720 this.label_value = this.$el.data('pie-label-value') || this.$el.data('pie-value'); 15721 this.$wrapper = $('.vc_pie_wrapper', this.$el); 15722 this.$label = $(this.options.label_selector, this.$el); 15723 this.$back = $(this.options.back_selector, this.$el); 15724 this.$canvas = this.$el.find('canvas'); 15725 this.arcWidth = this.$el.data('pie-width') * 2; 15726 this.draw(); 15727 this.setWayPoint(); 15728 if(this.options.responsive === true) this.setResponsive(); 15729 if (UNCODE.isMobile) this._progress_v = this.value; 15730 }, 15731 setupColor: function() { 15732 // if(typeof this.colors[this.options.color] !== 'undefined') { 15733 // this.color = this.colors[this.options.color]; 15734 // } else if(typeof this.options.color === 'string' && this.options.color.match(/^rgba?\([^\)]+\)/)) { 15735 // this.color = this.options.color; 15736 // } else { 15737 // this.color = 'rgba(247, 247, 247, 0.2)'; 15738 // } 15739 if(typeof this.options.color !== 'undefined') { 15740 this.color = this.options.color; 15741 } else this.color = 'rgba(247, 247, 247, 0.2)'; 15742 15743 }, 15744 setResponsive: function() { 15745 var that = this; 15746 if (!UNCODE.isMobile) { 15747 $(window).resize(function(){ 15748 if(that.animated === true) that.circle.stop(); 15749 that.draw(true); 15750 }); 15751 } 15752 }, 15753 draw: function(redraw) { 15754 var w = this.$el.addClass('vc_ready').width() * 2, 15755 border_w = this.arcWidth, 15756 radius; 15757 if(!w) w = this.$el.parents(':visible').first().width()-2; 15758 //w = Math.round(w/100*80); 15759 //if (w < 250) w = 250; 15760 radius = w/2; 15761 this.$wrapper.css({"width" : (w / 2) + "px"}); 15762 this.$label.css({"width" : (w / 2), "height" : (w / 2), "line-height" : (w / 2)+"px"}); 15763 this.$back.css({"width" : (w / 2), "height" : (w / 2)}); 15764 this.$canvas.attr({"width" : w + "px", "height" : w + "px"}); 15765 this.$el.addClass('vc_ready'); 15766 this.circle = new ProgressCircle({ 15767 canvas: this.$canvas.get(0), 15768 minRadius: radius, 15769 arcWidth: border_w 15770 }); 15771 if(redraw === true && this.animated === true) { 15772 this._progress_v = this.value; 15773 this.circle.addEntry({ 15774 fillColor: this.color, 15775 progressListener: $.proxy(this.setProgress, this) 15776 }).start(); 15777 } 15778 }, 15779 setProgress: function() { 15780 if (this._progress_v >= this.value) { 15781 this.circle.stop(); 15782 this.animated = true; 15783 this.$label.html(this.label_value + this.options.units); 15784 return this._progress_v; 15785 } 15786 this._progress_v += 0.01; 15787 if (!isNaN(this.label_value)) { 15788 var label_value = this._progress_v/this.value*this.label_value; 15789 var val = Math.round(label_value) + this.options.units; 15790 this.$label.html(val); 15791 } else this.$label.html(this.label_value + this.options.units); 15792 return this._progress_v; 15793 }, 15794 animate: function() { 15795 if(this.animated !== true) { 15796 this.circle.addEntry({ 15797 fillColor: this.color, 15798 progressListener: $.proxy(this.setProgress, this) 15799 }).start(10); 15800 } 15801 }, 15802 setWayPoint: function() { 15803 if (typeof $.fn.waypoint !== 'undefined' && !UNCODE.isMobile) { 15804 this.$el.waypoint($.proxy(this.animate, this), { offset: '85%' }); 15805 } else { 15806 this.animate(); 15807 } 15808 } 15809 }; 15810 /** 15811 * jQuery plugin 15812 * @param option - object with settings 15813 * @return {*} 15814 */ 15815 $.fn.vcChat = function(option, value) { 15816 return this.each(function () { 15817 var $this = $(this), 15818 data = $this.data('vc_chart'), 15819 options = typeof option === 'object' ? option : { 15820 color: $this.data('pie-color'), 15821 units: $this.data('pie-units') 15822 }; 15823 if (typeof option == 'undefined') $this.data('vc_chart', (data = new VcChart(this, options))); 15824 if (typeof option == 'string') data[option](value); 15825 }); 15826 }; 15827 /** 15828 * Allows users to rewrite function inside theme. 15829 */ 15830 if ( typeof window['vc_pieChart'] !== 'function' ) { 15831 window.vc_pieChart = function() { 15832 $('.vc_pie_chart:visible').vcChat(); 15833 } 15834 } 15835 $(document).ready(function(){ 15836 !window.vc_iframe && vc_pieChart(); 15837 }); 15838 15839})(window.jQuery); 15840 15841/* Progress bar 15842 ---------------------------------------------------------- */ 15843function uncode_progress_bar() {    15844 jQuery.each(jQuery('.vc_progress_bar'), function(index, val) { 15845 if (!UNCODE.isMobile) { 15846 new Waypoint({ 15847 element: val, 15848 handler: function() { 15849 var element = jQuery(this.element); 15850 element.find('.vc_single_bar').each(function(index) {          15851 var $this = jQuery(this), 15852             bar = $this.find('.vc_bar'), 15853             val = bar.data('percentage-value');          15854 setTimeout(function() {            15855 bar.css({ 15856 "width": val + '%' 15857 });          15858 }, index * 200);        15859 }); 15860 }, 15861 offset: '80%' 15862 }); 15863 } else { 15864 var element = jQuery(val); 15865 element.find('.vc_single_bar').each(function(index) {          15866 var $this = jQuery(this), 15867             bar = $this.find('.vc_bar'), 15868             val = bar.data('percentage-value');          15869 setTimeout(function() {            15870 bar.css({ 15871 "width": val + '%' 15872 });          15873 }, index * 200);        15874 }); 15875 } 15876 }); 15877}; 15878uncode_progress_bar(); 15879/*! 15880 * jquery.counterup.js 1.0 15881 * 15882 * Copyright 2013, Benjamin Intal http://gambit.ph @bfintal 15883 * Released under the GPL v2 License 15884 * 15885 * Date: Nov 26, 2013 15886 */ 15887(function($) { 15888 "use strict"; 15889 $.fn.counterUp = function(options) { 15890 // Defaults 15891 var settings = $.extend({ 15892 'time': 400, 15893 'delay': 10 15894 }, options); 15895 return this.each(function() { 15896 // Store the object 15897 var $this = $(this); 15898 var $settings = settings; 15899 var counterUpper = function() { 15900 var nums = []; 15901 var divisions = $settings.time / $settings.delay; 15902 var numReal = $this.attr('data-val'), 15903 num = numReal; 15904 var isComma = /[0-9]+,[0-9]+/.test(num); 15905 num = num.replace(/,/g, ''); 15906 var isInt = /^[0-9]+$/.test(num); 15907 var isFloat = /^[0-9]+\.[0-9]+$/.test(num); 15908 var decimalPlaces = isFloat ? (num.split('.')[1] || []).length : 0; 15909 // Generate list of incremental numbers to display 15910 for (var i = divisions; i >= 1; i--) { 15911 // Preserve as int if input was int 15912 var newNum = parseInt(num / divisions * i); 15913 // Preserve float if input was float 15914 if (isFloat) { 15915 newNum = parseFloat(num / divisions * i).toFixed(decimalPlaces); 15916 } 15917 // Preserve commas if input had commas 15918 if (isComma) { 15919 while (/(\d+)(\d{3})/.test(newNum.toString())) { 15920 newNum = newNum.toString().replace(/(\d+)(\d{3})/, '$1' + ',' + '$2'); 15921 } 15922 } 15923 nums.unshift(newNum); 15924 } 15925 nums.push(numReal); 15926 $this.data('counterup-nums', nums); 15927 $this.text('0'); 15928 // Updates the number until we're done 15929 var f = function() { 15930 if ($this.data('counterup-nums') != null) { 15931 $this.text($this.data('counterup-nums').shift()); 15932 if ($this.data('counterup-nums').length) { 15933 setTimeout($this.data('counterup-func'), $settings.delay); 15934 } else { 15935 delete $this.data('counterup-nums'); 15936 $this.data('counterup-nums', null); 15937 $this.data('counterup-func', null); 15938 } 15939 } 15940 }; 15941 $this.data('counterup-func', f); 15942 // Start the count up 15943 setTimeout($this.data('counterup-func'), $settings.delay); 15944 }; 15945 // Perform counts when the element gets into view 15946 new Waypoint({ 15947 element: this, 15948 handler: function() { 15949 counterUpper(); 15950 this.destroy(); 15951 }, 15952 offset: '100%' 15953 }); 15954 }); 15955 }; 15956})(jQuery); 15957 15958/*! 15959 * The Final Countdown for jQuery v2.0.4 (http://hilios.github.io/jQuery.countdown/) 15960 * Copyright (c) 2014 Edson Hilios 15961 * 15962 * Permission is hereby granted, free of charge, to any person obtaining a copy of 15963 * this software and associated documentation files (the "Software"), to deal in 15964 * the Software without restriction, including without limitation the rights to 15965 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 15966 * the Software, and to permit persons to whom the Software is furnished to do so, 15967 * subject to the following conditions: 15968 * 15969 * The above copyright notice and this permission notice shall be included in all 15970 * copies or substantial portions of the Software. 15971 * 15972 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15973 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 15974 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15975 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 15976 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 15977 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15978 */ 15979(function(factory) { 15980 "use strict"; 15981 if (typeof define === "function" && define.amd) { 15982 define([ "jquery" ], factory); 15983 } else { 15984 factory(jQuery); 15985 } 15986})(function($) { 15987 "use strict"; 15988 var PRECISION = 100; 15989 var instances = [], matchers = []; 15990 matchers.push(/^[0-9]*$/.source); 15991 matchers.push(/([0-9]{1,2}\/){2}[0-9]{4}( [0-9]{1,2}(:[0-9]{2}){2})?/.source); 15992 matchers.push(/[0-9]{4}([\/\-][0-9]{1,2}){2}( [0-9]{1,2}(:[0-9]{2}){2})?/.source); 15993 matchers = new RegExp(matchers.join("|")); 15994 function parseDateString(dateString) { 15995 if (dateString instanceof Date) { 15996 return dateString; 15997 } 15998 if (String(dateString).match(matchers)) { 15999 if (String(dateString).match(/^[0-9]*$/)) { 16000 dateString = Number(dateString); 16001 } 16002 if (String(dateString).match(/\-/)) { 16003 dateString = String(dateString).replace(/\-/g, "/"); 16004 } 16005 return new Date(dateString); 16006 } else { 16007 throw new Error("Couldn't cast `" + dateString + "` to a date object."); 16008 } 16009 } 16010 var DIRECTIVE_KEY_MAP = { 16011 Y: "years", 16012 m: "months", 16013 w: "weeks", 16014 d: "days", 16015 D: "totalDays", 16016 H: "hours", 16017 M: "minutes", 16018 S: "seconds" 16019 }; 16020 function strftime(offsetObject) { 16021 return function(format) { 16022 var directives = format.match(/%(-|!)?[A-Z]{1}(:[^;]+;)?/gi); 16023 if (directives) { 16024 for (var i = 0, len = directives.length; i < len; ++i) { 16025 var directive = directives[i].match(/%(-|!)?([a-zA-Z]{1})(:[^;]+;)?/), regexp = new RegExp(directive[0]), modifier = directive[1] || "", plural = directive[3] || "", value = null; 16026 directive = directive[2]; 16027 if (DIRECTIVE_KEY_MAP.hasOwnProperty(directive)) { 16028 value = DIRECTIVE_KEY_MAP[directive]; 16029 value = Number(offsetObject[value]); 16030 } 16031 if (value !== null) { 16032 if (modifier === "!") { 16033 value = pluralize(plural, value); 16034 } 16035 if (modifier === "") { 16036 if (value < 10) { 16037 value = "0" + value.toString(); 16038 } 16039 } 16040 format = format.replace(regexp, value.toString()); 16041 } 16042 } 16043 } 16044 format = format.replace(/%%/, "%"); 16045 return format; 16046 }; 16047 } 16048 function pluralize(format, count) { 16049 var plural = "s", singular = ""; 16050 if (format) { 16051 format = format.replace(/(:|;|\s)/gi, "").split(/\,/); 16052 if (format.length === 1) { 16053 plural = format[0]; 16054 } else { 16055 singular = format[0]; 16056 plural = format[1]; 16057 } 16058 } 16059 if (Math.abs(count) === 1) { 16060 return singular; 16061 } else { 16062 return plural; 16063 } 16064 } 16065 var Countdown = function(el, finalDate, callback) { 16066 this.el = el; 16067 this.$el = $(el); 16068 this.interval = null; 16069 this.offset = {}; 16070 this.instanceNumber = instances.length; 16071 instances.push(this); 16072 this.$el.data("countdown-instance", this.instanceNumber); 16073 if (callback) { 16074 this.$el.on("update.countdown", callback);
16075 this.$el.on("stoped.countdown", callback); 16076 this.$el.on("finish.countdown", callback); 16077 } 16078 this.setFinalDate(finalDate); 16079 this.start(); 16080 }; 16081 $.extend(Countdown.prototype, { 16082 start: function() { 16083 if (this.interval !== null) { 16084 clearInterval(this.interval); 16085 } 16086 var self = this; 16087 this.update(); 16088 this.interval = setInterval(function() { 16089 self.update.call(self); 16090 }, PRECISION); 16091 }, 16092 stop: function() { 16093 clearInterval(this.interval); 16094 this.interval = null; 16095 this.dispatchEvent("stoped"); 16096 }, 16097 pause: function() { 16098 this.stop.call(this); 16099 }, 16100 resume: function() { 16101 this.start.call(this); 16102 }, 16103 remove: function() { 16104 this.stop(); 16105 instances[this.instanceNumber] = null; 16106 delete this.$el.data().countdownInstance; 16107 }, 16108 setFinalDate: function(value) { 16109 this.finalDate = parseDateString(value); 16110 }, 16111 update: function() { 16112 if (this.$el.closest("html").length === 0) { 16113 this.remove(); 16114 return; 16115 } 16116 this.totalSecsLeft = this.finalDate.getTime() - new Date().getTime(); 16117 this.totalSecsLeft = Math.ceil(this.totalSecsLeft / 1e3); 16118 this.totalSecsLeft = this.totalSecsLeft < 0 ? 0 : this.totalSecsLeft; 16119 this.offset = { 16120 seconds: this.totalSecsLeft % 60, 16121 minutes: Math.floor(this.totalSecsLeft / 60) % 60, 16122 hours: Math.floor(this.totalSecsLeft / 60 / 60) % 24, 16123 days: Math.floor(this.totalSecsLeft / 60 / 60 / 24) % 7, 16124 totalDays: Math.floor(this.totalSecsLeft / 60 / 60 / 24), 16125 weeks: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 7), 16126 months: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 30), 16127 years: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 365) 16128 }; 16129 if (this.totalSecsLeft === 0) { 16130 this.stop(); 16131 this.dispatchEvent("finish"); 16132 } else { 16133 this.dispatchEvent("update"); 16134 } 16135 }, 16136 dispatchEvent: function(eventName) { 16137 var event = $.Event(eventName + ".countdown"); 16138 event.finalDate = this.finalDate; 16139 event.offset = $.extend({}, this.offset); 16140 event.strftime = strftime(this.offset); 16141 this.$el.trigger(event); 16142 } 16143 }); 16144 $.fn.countdown = function() { 16145 var argumentsArray = Array.prototype.slice.call(arguments, 0); 16146 return this.each(function() { 16147 var instanceNumber = $(this).data("countdown-instance"); 16148 if (instanceNumber !== undefined) { 16149 var instance = instances[instanceNumber], method = argumentsArray[0]; 16150 if (Countdown.prototype.hasOwnProperty(method)) { 16151 instance[method].apply(instance, argumentsArray.slice(1)); 16152 } else if (String(method).match(/^[$A-Z_][0-9A-Z_$]*$/i) === null) { 16153 instance.setFinalDate.call(instance, method); 16154 instance.start(); 16155 } else { 16156 $.error("Method %s does not exist on jQuery.countdown".replace(/\%s/gi, method)); 16157 } 16158 } else { 16159 new Countdown(this, argumentsArray[0], argumentsArray[1]); 16160 } 16161 }); 16162 }; 16163}); 16164 16165/*! waitForImages jQuery Plugin - v2.0.2 - 2015-05-05 16166* https://github.com/alexanderdickson/waitForImages 16167* Copyright (c) 2015 Alex Dickson; Licensed MIT */ 16168;(function (factory) { 16169 if (typeof define === 'function' && define.amd) { 16170 // AMD. Register as an anonymous module. 16171 define(['jquery'], factory); 16172 } else if (typeof exports === 'object') { 16173 // CommonJS / nodejs module 16174 module.exports = factory(require('jquery')); 16175 } else { 16176 // Browser globals 16177 factory(jQuery); 16178 } 16179}(function ($) { 16180 // Namespace all events. 16181 var eventNamespace = 'waitForImages'; 16182 16183 // CSS properties which contain references to images. 16184 $.waitForImages = { 16185 hasImageProperties: [ 16186 'backgroundImage', 16187 'listStyleImage', 16188 'borderImage', 16189 'borderCornerImage', 16190 'cursor' 16191 ], 16192 hasImageAttributes: ['srcset'] 16193 }; 16194 16195 // Custom selector to find `img` elements that have a valid `src` 16196 // attribute and have not already loaded. 16197 $.expr[':'].uncached = function (obj) { 16198 // Ensure we are dealing with an `img` element with a valid 16199 // `src` attribute. 16200 if (!$(obj).is('img[src][src!=""]')) { 16201 return false;
16202 } 16203 16204 return !obj.complete; 16205 }; 16206 16207 $.fn.waitForImages = function () { 16208 16209 var allImgsLength = 0; 16210 var allImgsLoaded = 0; 16211 var deferred = $.Deferred(); 16212 16213 var finishedCallback; 16214 var eachCallback; 16215 var waitForAll; 16216 16217 // Handle options object (if passed). 16218 if ($.isPlainObject(arguments[0])) { 16219 16220 waitForAll = arguments[0].waitForAll; 16221 eachCallback = arguments[0].each; 16222 finishedCallback = arguments[0].finished; 16223 16224 } else { 16225 16226 // Handle if using deferred object and only one param was passed in. 16227 if (arguments.length === 1 && $.type(arguments[0]) === 'boolean') { 16228 waitForAll = arguments[0]; 16229 } else { 16230 finishedCallback = arguments[0]; 16231 eachCallback = arguments[1]; 16232 waitForAll = arguments[2]; 16233 } 16234 16235 } 16236 16237 // Handle missing callbacks. 16238 finishedCallback = finishedCallback || $.noop; 16239 eachCallback = eachCallback || $.noop; 16240 16241 // Convert waitForAll to Boolean 16242 waitForAll = !! waitForAll; 16243 16244 // Ensure callbacks are functions. 16245 if (!$.isFunction(finishedCallback) || !$.isFunction(eachCallback)) { 16246 throw new TypeError('An invalid callback was supplied.'); 16247 } 16248 16249 this.each(function () { 16250 // Build a list of all imgs, dependent on what images will 16251 // be considered. 16252 var obj = $(this); 16253 var allImgs = []; 16254 // CSS properties which may contain an image. 16255 var hasImgProperties = $.waitForImages.hasImageProperties || []; 16256 // Element attributes which may contain an image. 16257 var hasImageAttributes = $.waitForImages.hasImageAttributes || []; 16258 // To match `url()` references. 16259 // Spec: http://www.w3.org/TR/CSS2/syndata.html#value-def-uri 16260 var matchUrl = /url\(\s*(['"]?)(.*?)\1\s*\)/g; 16261 16262 if (waitForAll) { 16263 16264 // Get all elements (including the original), as any one of 16265 // them could have a background image. 16266 obj.find('*').addBack().each(function () { 16267 var element = $(this); 16268 16269 // If an `img` element, add it. But keep iterating in 16270 // case it has a background image too. 16271 if (element.is('img:uncached')) { 16272 allImgs.push({ 16273 src: element.attr('src'), 16274 element: element[0] 16275 }); 16276 } 16277 16278 $.each(hasImgProperties, function (i, property) { 16279 var propertyValue = element.css(property); 16280 var match; 16281 16282 // If it doesn't contain this property, skip. 16283 if (!propertyValue) { 16284 return true; 16285 } 16286 16287 // Get all url() of this element. 16288 while (match = matchUrl.exec(propertyValue)) { 16289 allImgs.push({ 16290 src: match[2], 16291 element: element[0] 16292 }); 16293 } 16294 }); 16295 16296 $.each(hasImageAttributes, function (i, attribute) { 16297 var attributeValue = element.attr(attribute); 16298 var attributeValues; 16299 16300 // If it doesn't contain this property, skip. 16301 if (!attributeValue) { 16302 return true; 16303 } 16304 16305 // Check for multiple comma separated images 16306 attributeValues = attributeValue.split(','); 16307 16308 $.each(attributeValues, function(i, value) { 16309 // Trim value and get string before first 16310 // whitespace (for use with srcset). 16311 value = $.trim(value).split(' ')[0]; 16312 allImgs.push({ 16313 src: value, 16314 element: element[0] 16315 }); 16316 }); 16317 }); 16318 }); 16319 } else { 16320 // For images only, the task is simpler. 16321 obj.find('img:uncached') 16322 .each(function () { 16323 allImgs.push({ 16324 src: this.src, 16325 element: this 16326 }); 16327 }); 16328 } 16329 16330 allImgsLength = allImgs.length; 16331 allImgsLoaded = 0; 16332 16333 // If no images found, don't bother. 16334 if (allImgsLength === 0) { 16335 finishedCallback.call(obj[0]); 16336 deferred.resolveWith(obj[0]); 16337 } 16338 16339 $.each(allImgs, function (i, img) { 16340 16341 var image = new Image(); 16342 var events = 16343 'load.' + eventNamespace + ' error.' + eventNamespace; 16344 16345 // Handle the image loading and error with the same callback. 16346 $(image).one(events, function me (event) { 16347 // If an error occurred with loading the image, set the 16348 // third argument accordingly. 16349 var eachArguments = [ 16350 allImgsLoaded, 16351 allImgsLength,
16352 event.type == 'load' 16353 ]; 16354 allImgsLoaded++; 16355 16356 eachCallback.apply(img.element, eachArguments); 16357 deferred.notifyWith(img.element, eachArguments); 16358 16359 // Unbind the event listeners. I use this in addition to 16360 // `one` as one of those events won't be called (either 16361 // 'load' or 'error' will be called). 16362 $(this).off(events, me); 16363 16364 if (allImgsLoaded == allImgsLength) { 16365 finishedCallback.call(obj[0]); 16366 deferred.resolveWith(obj[0]); 16367 return false; 16368 } 16369 16370 }); 16371 16372 image.src = img.src; 16373 }); 16374 }); 16375 16376 return deferred.promise(); 16377 16378 }; 16379})); 16380 16381/** 16382 * @preserve textfill 16383 * @name jquery.textfill.js 16384 * @author Russ Painter 16385 * @author Yu-Jie Lin 16386 * @author Alexandre Dantas 16387 * @version 0.6.0 16388 * @date 2014-08-19 16389 * @copyright (c) 2014 Alexandre Dantas 16390 * @copyright (c) 2012-2013 Yu-Jie Lin 16391 * @copyright (c) 2009 Russ Painter 16392 * @license MIT License 16393 * @homepage https://github.com/jquery-textfill/jquery-textfill 16394 * @example http://jquery-textfill.github.io/jquery-textfill/index.html 16395 */ 16396; (function($) { 16397 16398 /** 16399 * Resizes an inner element's font so that the 16400 * inner element completely fills the outer element. 16401 * 16402 * @param {Object} options User options that take 16403 * higher precedence when 16404 * merging with the default ones. 16405 * 16406 * @return All outer elements processed 16407 */ 16408 $.fn.textfill = function(options) { 16409 16410 // ______ _______ _______ _______ _ _ _______ _______ 16411 // | \ |______ |______ |_____| | | | | |______ 16412 // |_____/ |______ | | | |_____| |_____ | ______| 16413 // 16414 // Merging user options with the default values 16415 16416 var defaults = { 16417 debug : false, 16418 maxFontPixels : 40, 16419 minFontPixels : 4, 16420 innerTag : 'span', 16421 widthOnly : false, 16422 success : null, // callback when a resizing is done 16423 callback : null, // callback when a resizing is done (deprecated, use success) 16424 fail : null, // callback when a resizing is failed 16425 complete : null, // callback when all is done 16426 explicitWidth : null, 16427 explicitHeight : null, 16428 changeLineHeight : false 16429 }; 16430 16431 var Opts = $.extend(defaults, options); 16432 16433 // _______ _ _ __ _ _______ _______ _____ _____ __ _ _______ 16434 // |______ | | | \ | | | | | | | \ | |______ 16435 // | |_____| | \_| |_____ | __|__ |_____| | \_| ______| 16436 // 16437 // Predefining the awesomeness 16438 16439 // Output arguments to the Debug console 16440 // if "Debug Mode" is enabled 16441 function _debug() { 16442 if (!Opts.debug 16443 || typeof console == 'undefined' 16444 || typeof console.debug == 'undefined') { 16445 return; 16446 } 16447 console.debug.apply(console, arguments); 16448 } 16449 16450 // Output arguments to the Warning console 16451 function _warn() { 16452 if (typeof console == 'undefined' || 16453 typeof console.warn == 'undefined') { 16454 return; 16455 } 16456 console.warn.apply(console, arguments); 16457 } 16458 16459 // Outputs all information on the current sizing 16460 // of the font. 16461 function _debug_sizing(prefix, ourText, maxHeight, maxWidth, minFontPixels, maxFontPixels) { 16462 16463 function _m(v1, v2) { 16464 16465 var marker = ' / '; 16466 16467 if (v1 > v2) 16468 marker = ' > '; 16469 16470 else if (v1 == v2) 16471 marker = ' = '; 16472 16473 return marker; 16474 } 16475 16476 _debug( 16477 '[TextFill] ' + prefix + ' { ' + 16478 'font-size: ' + ourText.css('font-size') + ',' +
16479 'Height: ' + ourText.height() + 'px ' + _m(ourText.height(), maxHeight) + maxHeight + 'px,' + 16480 'Width: ' + ourText.width() + _m(ourText.width() , maxWidth) + maxWidth + ',' + 16481 'minFontPixels: ' + minFontPixels + 'px, ' + 16482 'maxFontPixels: ' + maxFontPixels + 'px }' 16483 ); 16484 } 16485 16486 /** 16487 * Calculates which size the font can get resized, 16488 * according to constrains. 16489 * 16490 * @param {String} prefix Gets shown on the console before 16491 * all the arguments, if debug mode is on. 16492 * @param {Object} ourText The DOM element to resize, 16493 * that contains the text. 16494 * @param {function} func Function called on `ourText` that's 16495 * used to compare with `max`. 16496 * @param {number} max Maximum value, that gets compared with 16497 * `func` called on `ourText`. 16498 * @param {number} minFontPixels Minimum value the font can 16499 * get resized to (in pixels). 16500 * @param {number} maxFontPixels Maximum value the font can 16501 * get resized to (in pixels). 16502 * 16503 * @return Size (in pixels) that the font can be resized. 16504 */ 16505 function _sizing(prefix, ourText, func, max, maxHeight, maxWidth, minFontPixels, maxFontPixels) { 16506 16507 _debug_sizing( 16508 prefix, ourText, 16509 maxHeight, maxWidth, 16510 minFontPixels, maxFontPixels 16511 ); 16512 16513 // The kernel of the whole plugin, take most attention 16514 // on this part. 16515 // 16516 // This is a loop that keeps increasing the `font-size` 16517 // until it fits the parent element. 16518 // 16519 // - Start from the minimal allowed value (`minFontPixels`) 16520 // - Guesses an average font size (in pixels) for the font, 16521 // - Resizes the text and sees if its size is within the 16522 // boundaries (`minFontPixels` and `maxFontPixels`). 16523 // - If so, keep guessing until we break. 16524 // - If not, return the last calculated size. 16525 // 16526 // I understand this is not optimized and we should 16527 // consider implementing something akin to 16528 // Daniel Hoffmann's answer here: 16529 // 16530 // http://stackoverflow.com/a/17433451/1094964 16531 // 16532 16533 while (minFontPixels < (maxFontPixels - 1)) { 16534 16535 var fontSize = Math.floor((minFontPixels + maxFontPixels) / 2); 16536 ourText.css('font-size', fontSize); 16537 16538 if (func.call(ourText) <= max) { 16539 minFontPixels = fontSize; 16540 16541 if (func.call(ourText) == max) 16542 break; 16543 } 16544 else 16545 maxFontPixels = fontSize; 16546 16547 _debug_sizing( 16548 prefix, ourText, 16549 maxHeight, maxWidth, 16550 minFontPixels, maxFontPixels 16551 ); 16552 } 16553 16554 ourText.css('font-size', maxFontPixels); 16555 16556 if (func.call(ourText) <= max) { 16557 minFontPixels = maxFontPixels; 16558 16559 _debug_sizing( 16560 prefix + '* ', ourText, 16561 maxHeight, maxWidth, 16562 minFontPixels, maxFontPixels 16563 ); 16564 } 16565 return minFontPixels; 16566 } 16567 16568 // _______ _______ _______ ______ _______ 16569 // |______ | |_____| |_____/ | 16570 // ______| | | | | \_ | 16571 // 16572 // Let's get it started (yeah)! 16573 16574 _debug('[TextFill] Start Debug'); 16575 16576 this.each(function() { 16577 16578 // Contains the child element we will resize. 16579 // $(this) means the parent container 16580 var ourText = $(Opts.innerTag + ':visible:first', this); 16581 16582 // Will resize to this dimensions. 16583 // Use explicit dimensions when specified 16584 var maxHeight = Opts.explicitHeight || $(this).height(); 16585 var maxWidth = Opts.explicitWidth || $(this).width(); 16586 16587 var oldFontSize = ourText.css('font-size'); 16588 16589 var lineHeight = parseFloat(ourText.css('line-height')) / parseFloat(oldFontSize); 16590 16591 _debug('[TextFill] Inner text: ' + ourText.text()); 16592 _debug('[TextFill] All options: ', Opts); 16593 _debug('[TextFill] Maximum sizes: { ' + 16594 'Height: ' + maxHeight + 'px, ' + 16595 'Width: ' + maxWidth + 'px' + ' }' 16596 ); 16597 16598 var minFontPixels = Opts.minFontPixels; 16599 16600 // Remember, if this `maxFontPixels` is negative, 16601 // the text will resize to as long as the container 16602 // can accomodate 16603 var maxFontPixels = (Opts.maxFontPixels <= 0 ? 16604 maxHeight : 16605 Opts.maxFontPixels); 16606 16607 16608 // Let's start it all! 16609 16610 // 1. Calculate which `font-size` would 16611 // be best for the Height 16612 var fontSizeHeight = undefined; 16613 16614 if (! Opts.widthOnly) 16615 fontSizeHeight = _sizing( 16616 'Height', ourText, 16617 $.fn.height, maxHeight, 16618 maxHeight, maxWidth, 16619 minFontPixels, maxFontPixels 16620 ); 16621 16622 // 2. Calculate which `font-size` would 16623 // be best for the Width 16624 var fontSizeWidth = undefined; 16625 16626 fontSizeWidth = _sizing( 16627 'Width', ourText, 16628 $.fn.width, maxWidth, 16629 maxHeight, maxWidth, 16630 minFontPixels, maxFontPixels 16631 ); 16632 16633 // 3. Actually resize the text! 16634 16635 if (Opts.widthOnly) { 16636 ourText.css({ 16637 'font-size' : fontSizeWidth, 16638 'white-space': 'nowrap' 16639 }); 16640 16641 if (Opts.changeLineHeight) 16642 ourText.parent().css( 16643 'line-height', 16644 (lineHeight * fontSizeWidth + 'px') 16645 ); 16646 } 16647 else { 16648 var fontSizeFinal = Math.min(fontSizeHeight, fontSizeWidth); 16649 16650 ourText.css('font-size', fontSizeFinal); 16651 16652 if (Opts.changeLineHeight) 16653 ourText.parent().css( 16654 'line-height', 16655 (lineHeight * fontSizeFinal) + 'px' 16656 ); 16657 } 16658 16659 _debug( 16660 '[TextFill] Finished { ' + 16661 'Old font-size: ' + oldFontSize + ', ' + 16662 'New font-size: ' + ourText.css('font-size') + ' }' 16663 ); 16664 16665 // Oops, something wrong happened! 16666 // We weren't supposed to exceed the original size 16667 if ((ourText.width() > maxWidth) ||
16668 (ourText.height() > maxHeight && !Opts.widthOnly)) { 16669 16670 ourText.css('font-size', oldFontSize); 16671 16672 // Failure callback 16673 if (Opts.fail) 16674 Opts.fail(this); 16675 16676 _debug( 16677 '[TextFill] Failure { ' + 16678 'Current Width: ' + ourText.width() + ', ' + 16679 'Maximum Width: ' + maxWidth + ', ' + 16680 'Current Height: ' + ourText.height() + ', ' + 16681 'Maximum Height: ' + maxHeight + ' }' 16682 ); 16683 } 16684 else if (Opts.success) { 16685 Opts.success(this); 16686 } 16687 else if (Opts.callback) { 16688 _warn('callback is deprecated, use success, instead'); 16689 16690 // Success callback 16691 Opts.callback(this); 16692 } 16693 }); 16694 16695 // Complete callback 16696 if (Opts.complete) 16697 Opts.complete(this); 16698 16699 _debug('[TextFill] End Debug'); 16700 return this; 16701 }; 16702 16703})(window.jQuery); 16704 16705!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; 16706function getStyles(config){ 16707 // 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;
16707left: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+"}" 16708}; 16709 var ShareUtils; 16710 16711if ((!("classList" in document.documentElement)) && Object.defineProperty && typeof HTMLElement !== "undefined") { 16712 Object.defineProperty(HTMLElement.prototype, "classList", { 16713 get: function() { 16714 var ret, self, update; 16715 update = function(fn) { 16716 return function(value) { 16717 var classes, index; 16718 classes = self.className.split(/\s+/); 16719 index = classes.indexOf(value); 16720 fn(classes, index, value); 16721 self.className = classes.join(" "); 16722 }; 16723 }; 16724 self = this; 16725 ret = { 16726 add: update(function(classes, index, value) { 16727 ~index || classes.push(value); 16728 }), 16729 remove: update(function(classes, index) { 16730 ~index && classes.splice(index, 1); 16731 }), 16732 toggle: update(function(classes, index, value) { 16733 if (~index) { 16734 classes.splice(index, 1); 16735 } else { 16736 classes.push(value); 16737 } 16738 }), 16739 contains: function(value) { 16740 return !!~self.className.split(/\s+/).indexOf(value); 16741 }, 16742 item: function(i) { 16743 return self.className.split(/\s+/)[i] || null; 16744 } 16745 }; 16746 Object.defineProperty(ret, "length", { 16747 get: function() { 16748 return self.className.split(/\s+/).length; 16749 } 16750 }); 16751 return ret; 16752 } 16753 }); 16754} 16755 16756String.prototype.to_rfc3986 = function() { 16757 var tmp; 16758 tmp = encodeURIComponent(this); 16759 return tmp.replace(/[!'()*]/g, function(c) { 16760 return "%" + c.charCodeAt(0).toString(16); 16761 }); 16762}; 16763 16764ShareUtils = (function() { 16765 function ShareUtils() {} 16766 16767 ShareUtils.prototype.extend = function(to, from, overwrite) { 16768 var hasProp, prop; 16769 for (prop in from) { 16770 hasProp = to[prop] !== undefined; 16771 if (hasProp && typeof from[prop] === "object") { 16772 this.extend(to[prop], from[prop], overwrite); 16773 } else { 16774 if (overwrite || !hasProp) { 16775 to[prop] = from[prop]; 16776 } 16777 } 16778 } 16779 }; 16780 16781 ShareUtils.prototype.hide = function(el) { 16782 return el.style.display = "none"; 16783 }; 16784 16785 ShareUtils.prototype.show = function(el) { 16786 return el.style.display = "block"; 16787 }; 16788 16789 ShareUtils.prototype.has_class = function(el, class_name) { 16790 return el.classList.contains(class_name); 16791 }; 16792 16793 ShareUtils.prototype.add_class = function(el, class_name) { 16794 return el.classList.add(class_name); 16795 }; 16796 16797 ShareUtils.prototype.remove_class = function(el, class_name) { 16798 return el.classList.remove(class_name); 16799 }; 16800 16801 ShareUtils.prototype.is_encoded = function(str) { 16802 str = str.to_rfc3986(); 16803 return decodeURIComponent(str) !== str; 16804 }; 16805 16806 ShareUtils.prototype.encode = function(str) { 16807 if (typeof str === "undefined" || this.is_encoded(str)) { 16808 return str; 16809 } else { 16810 return str.to_rfc3986(); 16811 } 16812 }; 16813 16814 ShareUtils.prototype.popup = function(url, params) { 16815 var k, popup, qs, v; 16816 if (params == null) { 16817 params = {}; 16818 } 16819 popup = { 16820 width: 500, 16821 height: 350 16822 }; 16823 popup.top = (screen.height / 2) - (popup.height / 2); 16824 popup.left = (screen.width / 2) - (popup.width / 2); 16825 qs = ((function() { 16826 var _results; 16827 _results = []; 16828 for (k in params) { 16829 v = params[k]; 16830 _results.push("" + k + "=" + (this.encode(v))); 16831 } 16832 return _results; 16833 }).call(this)).join('&'); 16834 if (qs) { 16835 qs = "?" + qs; 16836 } 16837 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="
16837+ popup.width + ",height=" + popup.height); 16838 }; 16839 16840 return ShareUtils; 16841 16842})(); 16843var Share, 16844 __hasProp = {}.hasOwnProperty, 16845 __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; }; 16846 16847Share = (function(_super) { 16848 __extends(Share, _super); 16849 16850 function Share(element, options) { 16851 this.element = element; 16852 this.el = { 16853 head: document.getElementsByTagName('head')[0], 16854 body: document.getElementsByTagName('body')[0] 16855 }; 16856 this.config = { 16857 enabled_networks: 0, 16858 protocol: ['http', 'https'].indexOf(window.location.href.split(':')[0]) === -1 ? 'https://' : '//', 16859 url: window.location.href.replace("&", "%26"), 16860 caption: null, 16861 title: this.default_title(), 16862 image: this.default_image(), 16863 description: this.default_description(), 16864 ui: { 16865 flyout: 'top center', 16866 button_text: 'Share', 16867 button_font: true, 16868 icon_font: true 16869 }, 16870 networks: { 16871 google_plus: { 16872 enabled: true, 16873 url: null 16874 }, 16875 twitter: { 16876 enabled: true, 16877 url: null, 16878 title: null, 16879 description: null 16880 }, 16881 facebook: { 16882 enabled: true, 16883 load_sdk: true, 16884 url: null, 16885 app_id: null, 16886 title: null, 16887 caption: null, 16888 description: null, 16889 image: null 16890 }, 16891 pinterest: { 16892 enabled: true, 16893 url: null, 16894 image: null, 16895 description: null 16896 }, 16897 reddit: { 16898 enabled: true, 16899 url: null, 16900 title: null 16901 }, 16902 linkedin: { 16903 enabled: true, 16904 url: null, 16905 title: null, 16906 description: null 16907 }, 16908 xing: { 16909 enabled: true, 16910 url: null, 16911 title: null, 16912 image: null, 16913 description: null 16914 }, 16915 whatsapp: { 16916 enabled: true, 16917 description: null, 16918 url: null 16919 }, 16920 email: { 16921 enabled: true, 16922 title: null, 16923 description: null, 16924 url: null 16925 } 16926 } 16927 }; 16928 this.setup(element, options); 16929 return this; 16930 } 16931 16932 Share.prototype.setup = function(element, opts) { 16933 var index, instance, instances, _i, _len; 16934 instances = document.querySelectorAll(element); 16935 this.extend(this.config, opts, true); 16936 this.set_global_configuration(); 16937 this.normalize_network_configuration(); 16938 if (this.config.ui.icon_font) { 16939 this.inject_icons(); 16940 } 16941 if (this.config.ui.button_font) { 16942 this.inject_fonts(); 16943 } 16944 if (this.config.networks.facebook.enabled && this.config.networks.facebook.load_sdk) { 16945 this.inject_facebook_sdk(); 16946 } 16947 for (index = _i = 0, _len = instances.length; _i < _len; index = ++_i) { 16948 instance = instances[index]; 16949 this.setup_instance(element, index); 16950 } 16951 }; 16952 16953 Share.prototype.setup_instance = function(element, index) { 16954 var button, instance, label, network, networks, _i, _len, _results, 16955 _this = this; 16956 instance = document.querySelectorAll(element)[index]; 16957 this.hide(instance); 16958 this.add_class(instance, "sharer-" + index); 16959 instance = document.querySelectorAll(element)[index]; 16960 this.inject_css(instance); 16961 this.inject_html(instance); 16962 this.show(instance); 16963 label = instance.getElementsByTagName("label")[0]; 16964 button = instance.getElementsByClassName("social")[0]; 16965 networks = instance.getElementsByTagName('li'); 16966 this.add_class(button, "networks-" + this.config.enabled_networks); 16967 label.addEventListener("click", function() { 16968 return _this.event_toggle(button); 16969 }); 16970 _this = this; 16971 _results = []; 16972 for (index = _i = 0, _len = networks.length; _i < _len; index = ++_i) { 16973 network = networks[index]; 16974 _results.push(network.addEventListener("click", function() { 16975 _this.event_network(instance, this); 16976 return _this.event_close(button); 16977 })); 16978 } 16979 return _results; 16980 }; 16981 16982 Share.prototype.event_toggle = function(button) { 16983 if (this.has_class(button, "active")) { 16984 return this.event_close(button); 16985 } else { 16986 return this.event_open(button); 16987 } 16988 }; 16989 16990 Share.prototype.event_open = function(button) { 16991 if (this.has_class(button, "load")) { 16992 this.remove_class(button, "load"); 16993 } 16994 return this.add_class(button, "active"); 16995 }; 16996 16997 Share.prototype.event_close = function(button) { 16998 return this.remove_class(button, "active"); 16999 }; 17000 17001 Share.prototype.event_network = function(instance, network) { 17002 var name; 17003 name = network.getAttribute("data-network"); 17004 this.hook("before", name, instance);
17005 this["network_" + name](); 17006 return this.hook("after", name, instance); 17007 }; 17008 17009 Share.prototype.open = function() { 17010 return this["public"]("open"); 17011 }; 17012 17013 Share.prototype.close = function() { 17014 return this["public"]("close"); 17015 }; 17016 17017 Share.prototype.toggle = function() { 17018 return this["public"]("toggle"); 17019 }; 17020 17021 Share.prototype["public"] = function(action) { 17022 var button, index, instance, _i, _len, _ref, _results; 17023 _ref = document.querySelectorAll(this.element); 17024 _results = []; 17025 for (index = _i = 0, _len = _ref.length; _i < _len; index = ++_i) { 17026 instance = _ref[index]; 17027 button = instance.getElementsByClassName("social")[0]; 17028 _results.push(this["event_" + action](button)); 17029 } 17030 return _results; 17031 }; 17032 17033 Share.prototype.network_facebook = function() { 17034 if (this.config.networks.facebook.load_sdk) { 17035 if (!window.FB) { 17036 return console.error("The Facebook JS SDK hasn't loaded yet."); 17037 } 17038 return FB.ui({ 17039 method: 'feed', 17040 name: this.config.networks.facebook.title, 17041 link: this.config.networks.facebook.url, 17042 picture: this.config.networks.facebook.image, 17043 caption: this.config.networks.facebook.caption, 17044 description: this.config.networks.facebook.description 17045 }); 17046 } else { 17047 return this.popup('https://www.facebook.com/sharer/sharer.php', { 17048 u: this.config.networks.facebook.url 17049 }); 17050 } 17051 }; 17052 17053 Share.prototype.network_twitter = function() { 17054 return this.popup('https://twitter.com/intent/tweet', { 17055 text: this.config.networks.twitter.title, 17056 url: this.config.networks.twitter.url 17057 }); 17058 }; 17059 17060 Share.prototype.network_google_plus = function() { 17061 return this.popup('https://plus.google.com/share', { 17062 url: this.config.networks.google_plus.url 17063 }); 17064 }; 17065 17066 Share.prototype.network_pinterest = function() { 17067 return this.popup('https://www.pinterest.com/pin/create/button', { 17068 url: this.config.networks.pinterest.url, 17069 media: this.config.networks.pinterest.image, 17070 description: this.config.networks.pinterest.description 17071 }); 17072 }; 17073 17074 Share.prototype.network_linkedin = function() { 17075 return this.popup('https://www.linkedin.com/shareArticle', { 17076 url: this.config.networks.linkedin.url, 17077 title: this.config.networks.linkedin.title, 17078 summary: this.config.networks.linkedin.description 17079 }); 17080 } 17081 17082 Share.prototype.network_xing = function() { 17083 return this.popup('https://www.xing.com/spi/shares/new', { 17084 url: this.config.networks.xing.url, 17085 image: this.config.networks.xing.image, 17086 title: this.config.networks.xing.title, 17087 summary: this.config.networks.xing.description 17088 }); 17089 } 17090 17091 Share.prototype.network_email = function() { 17092 return this.popup('mailto:', { 17093 subject: this.config.networks.email.title, 17094 body: this.config.networks.email.url + '%0A%0A' + this.config.networks.email.description, 17095 }); 17096 }; 17097 17098 Share.prototype.inject_icons = function() { 17099 // return this.inject_stylesheet("https://www.sharebutton.co/fonts/v2/entypo.min.css"); 17100 }; 17101 17102 Share.prototype.inject_fonts = function() { 17103 // return this.inject_stylesheet("http://fonts.googleapis.com/css?family=Lato:900&text=" + this.config.ui.button_text); 17104 }; 17105 17106 Share.prototype.inject_stylesheet = function(url) { 17107 var link; 17108 if (!this.el.head.querySelector("link[href=\"" + url + "\"]")) { 17109 link = document.createElement("link"); 17110 link.setAttribute("rel", "stylesheet"); 17111 link.setAttribute("href", url); 17112 return this.el.head.appendChild(link); 17113 } 17114 }; 17115 17116 Share.prototype.inject_css = function(instance) { 17117 var css, meta, selector, style; 17118 selector = "." + (instance.getAttribute('class').split(" ").join(".")); 17119 if (!this.el.head.querySelector("meta[name='sharer" + selector + "']")) { 17120 this.config.selector = selector; 17121 css = getStyles(this.config); 17122 style = document.createElement("style"); 17123 style.type = "text/css"; 17124 if (style.styleSheet) { 17125 style.styleSheet.cssText = css; 17126 } else { 17127 style.appendChild(document.createTextNode(css)); 17128 } 17129 this.el.head.appendChild(style); 17130 delete this.config.selector; 17131 meta = document.createElement("meta"); 17132 meta.setAttribute("name", "sharer" + selector); 17133 return this.el.head.appendChild(meta); 17134 } 17135 }; 17136 17137 Share.prototype.inject_html = function(instance) { 17138 //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>"; 17139 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>"; 17140 }; 17141 17142 Share.prototype.inject_facebook_sdk = function() { 17143 var fb_root, script; 17144 if (!window.FB && this.config.networks.facebook.app_id && !this.el.body.querySelector('#fb-root')) { 17145 script = document.createElement("script"); 17146 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')"; 17147 fb_root = document.createElement("div"); 17148 fb_root.id = "fb-root"; 17149 this.el.body.appendChild(fb_root); 17150 return this.el.body.appendChild(script); 17151 } 17152 }; 17153 17154 Share.prototype.hook = function(type, network, instance) { 17155 var fn, opts; 17156 fn = this.config.networks[network][type]; 17157 if (typeof fn === "function") { 17158 opts = fn.call(this.config.networks[network], instance); 17159 if (opts !== void 0) { 17160 opts = this.normalize_filter_config_updates(opts); 17161 this.extend(this.config.networks[network], opts, true); 17162 this.normalize_network_configuration(); 17163 } 17164 } 17165 }; 17166 17167 Share.prototype.default_title = function() { 17168 var content; 17169 if (content = document.querySelector('meta[property="og:title"]') || document.querySelector('meta[name="twitter:title"]')) { 17170 return encodeURIComponent(content.getAttribute('content')); 17171 } else if (content = document.querySelector('title')) { 17172 return encodeURIComponent(content.innerText); 17173 } 17174 }; 17175 17176 Share.prototype.default_image = function() { 17177 var content; 17178 if (content = document.querySelector('meta[property="og:image"]') || document.querySelector('meta[name="twitter:image"]')) { 17179 return content.getAttribute('content'); 17180 } 17181 }; 17182 17183 Share.prototype.default_description = function() { 17184 var content; 17185 if (content = document.querySelector('meta[property="og:description"]') || document.querySelector('meta[name="twitter:description"]') || document.querySelector('meta[name="description"]')) { 17186 return encodeURIComponent(content.getAttribute('content')); 17187 } else { 17188 return ''; 17189 } 17190 }; 17191 17192 Share.prototype.set_global_configuration = function() { 17193 var display, network, option, options, _ref, _results; 17194 _ref = this.config.networks; 17195 _results = []; 17196 for (network in _ref) { 17197 options = _ref[network]; 17198 for (option in options) { 17199 if (this.config.networks[network][option] == null) { 17200 this.config.networks[network][option] = this.config[option]; 17201 } 17202 } 17203 if (this.config.networks[network].enabled) { 17204 display = 'block'; 17205 this.config.enabled_networks += 1; 17206 } else { 17207 display = 'none'; 17208 } 17209 _results.push(this.config.networks[network].display = display); 17210 } 17211 return _results; 17212 }; 17213 17214 Share.prototype.normalize_network_configuration = function() { 17215 if (!this.config.networks.facebook.app_id) { 17216 this.config.networks.facebook.load_sdk = false;
17217 } 17218 if (!this.is_encoded(this.config.networks.twitter.description)) { 17219 this.config.networks.twitter.description = encodeURIComponent(this.config.networks.twitter.description); 17220 } 17221 if (typeof this.config.networks.facebook.app_id === 'number') { 17222 return this.config.networks.facebook.app_id = this.config.networks.facebook.app_id.toString(); 17223 } 17224 }; 17225 17226 Share.prototype.normalize_filter_config_updates = function(opts) { 17227 if (this.config.networks.facebook.app_id !== opts.app_id) { 17228 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."); 17229 delete opts.app_id; 17230 } 17231 if (this.config.networks.facebook.load_sdk !== opts.load_sdk) { 17232 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."); 17233 delete opts.app_id; 17234 } 17235 return opts; 17236 }; 17237 17238 return Share; 17239 17240})(ShareUtils); 17241 return Share; 17242}); 17243 17244// Generated by CoffeeScript 1.9.2 17245 17246// @license Sticky-kit v1.1.2 | WTFPL | Leaf Corcoran 2015 | http://leafo.net 17247 17248(function() { 17249 var $, win; 17250 17251 $ = this.jQuery || window.jQuery; 17252 17253 win = $(window); 17254 17255 $.fn.stick_in_parent = function(opts) { 17256 var doc, elm, enable_bottoming, fn, i, inner_scrolling, len, manual_spacer, offset_top, outer_width, parent_selector, recalc_every, sticky_class; 17257 if (opts == null) { 17258 opts = {}; 17259 } 17260 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; 17261 if (offset_top == null) { 17262 offset_top = 0; 17263 } 17264 if (parent_selector == null) { 17265 parent_selector = void 0; 17266 } 17267 if (inner_scrolling == null) { 17268 inner_scrolling = true; 17269 } 17270 if (sticky_class == null) { 17271 sticky_class = "is_stuck"; 17272 } 17273 doc = $(document); 17274 if (enable_bottoming == null) { 17275 enable_bottoming = true; 17276 } 17277 outer_width = function(el) { 17278 var _el, computed, w; 17279 if (window.getComputedStyle) { 17280 _el = el[0]; 17281 computed = window.getComputedStyle(el[0]); 17282 w = parseFloat(computed.getPropertyValue("width")) + parseFloat(computed.getPropertyValue("margin-left")) + parseFloat(computed.getPropertyValue("margin-right")); 17283 if (computed.getPropertyValue("box-sizing") !== "border-box") { 17284 w += parseFloat(computed.getPropertyValue("border-left-width")) + parseFloat(computed.getPropertyValue("border-right-width")) + parseFloat(computed.getPropertyValue("padding-left")) + parseFloat(computed.getPropertyValue("padding-right")); 17285 } 17286 return w; 17287 } else { 17288 return el.outerWidth(true); 17289 } 17290 }; 17291 fn = function(elm, padding_bottom, parent_top, parent_height, top, height, el_float, detached) { 17292 var bottomed, detach, fixed, last_pos, last_scroll_height, offset, parent, recalc, recalc_and_tick, recalc_counter, spacer, tick; 17293 if (elm.data("sticky_kit")) { 17294 return; 17295 } 17296 elm.data("sticky_kit", true); 17297 last_scroll_height = doc.height(); 17298 parent = elm.parent(); 17299 if (parent_selector != null) { 17300 parent = parent.closest(parent_selector); 17301 } 17302 if (!parent.length) { 17303 throw "failed to find stick parent"; 17304 } 17305 fixed = false; 17306 bottomed = false; 17307 spacer = manual_spacer != null ? manual_spacer && elm.closest(manual_spacer) : $("<div />"); 17308 if (spacer) { 17309 spacer.css('position', elm.css('position')); 17310 } 17311 recalc = function() { 17312 var border_top, padding_top, restore; 17313 if (detached) { 17314 return; 17315 } 17316 last_scroll_height = doc.height(); 17317 border_top = parseInt(parent.css("border-top-width"), 10); 17318 padding_top = parseInt(parent.css("padding-top"), 10); 17319 padding_bottom = parseInt(parent.css("padding-bottom"), 10); 17320 parent_top = parent.offset().top + border_top + padding_top; 17321 parent_height = parent.height(); 17322 if (fixed) { 17323 fixed = false;
vendor: 6,068 bytes, lines 17324-17518
17324 bottomed = false; 17325 if (manual_spacer == null) { 17326 elm.insertAfter(spacer); 17327 spacer.detach(); 17328 } 17329 elm.css({ 17330 position: "", 17331 top: "", 17332 width: "", 17333 bottom: "" 17334 }).removeClass(sticky_class); 17335 restore = true; 17336 } 17337 top = elm.offset().top - (parseInt(elm.css("margin-top"), 10) || 0) - offset_top; 17338 height = elm.outerHeight(true); 17339 el_float = elm.css("float"); 17340 if (spacer) { 17341 spacer.css({ 17342 width: outer_width(elm), 17343 height: height, 17344 display: elm.css("display"), 17345 "vertical-align": elm.css("vertical-align"), 17346 "float": el_float 17347 }); 17348 } 17349 if (restore) { 17350 return tick(); 17351 } 17352 }; 17353 recalc(); 17354 if (height === parent_height) { 17355 return; 17356 } 17357 last_pos = void 0; 17358 offset = offset_top; 17359 recalc_counter = recalc_every; 17360 tick = function() { 17361 var css, delta, recalced, scroll, will_bottom, win_height; 17362 if (detached) { 17363 return; 17364 } 17365 recalced = false; 17366 if (recalc_counter != null) { 17367 recalc_counter -= 1; 17368 if (recalc_counter <= 0) { 17369 recalc_counter = recalc_every; 17370 recalc(); 17371 recalced = true; 17372 } 17373 } 17374 if (!recalced && doc.height() !== last_scroll_height) { 17375 recalc(); 17376 recalced = true; 17377 } 17378 scroll = win.scrollTop(); 17379 if (last_pos != null) { 17380 delta = scroll - last_pos; 17381 } 17382 last_pos = scroll; 17383 if (fixed) { 17384 if (enable_bottoming) { 17385 will_bottom = scroll + height + offset > parent_height + parent_top; 17386 if (bottomed && !will_bottom) { 17387 bottomed = false; 17388 elm.css({ 17389 position: "fixed", 17390 bottom: "", 17391 top: offset 17392 }).trigger("sticky_kit:unbottom"); 17393 } 17394 } 17395 if (scroll < top) { 17396 fixed = false; 17397 offset = offset_top; 17398 if (manual_spacer == null) { 17399 if (el_float === "left" || el_float === "right") { 17400 elm.insertAfter(spacer); 17401 } 17402 spacer.detach(); 17403 } 17404 css = { 17405 position: "", 17406 width: "", 17407 top: "" 17408 }; 17409 elm.css(css).removeClass(sticky_class).trigger("sticky_kit:unstick"); 17410 } 17411 if (inner_scrolling) { 17412 win_height = win.height(); 17413 if (height + offset_top > win_height) { 17414 if (!bottomed) { 17415 offset -= delta; 17416 offset = Math.max(win_height - height, offset); 17417 offset = Math.min(offset_top, offset); 17418 if (fixed) { 17419 elm.css({ 17420 top: offset + "px" 17421 }); 17422 } 17423 } 17424 } 17425 } 17426 } else { 17427 if (scroll > top) { 17428 fixed = true; 17429 css = { 17430 position: "fixed", 17431 top: offset 17432 }; 17433 css.width = elm.css("box-sizing") === "border-box" ? elm.outerWidth() + "px" : elm.width() + "px"; 17434 elm.css(css).addClass(sticky_class); 17435 if (manual_spacer == null) { 17436 elm.after(spacer); 17437 if (el_float === "left" || el_float === "right") { 17438 spacer.append(elm); 17439 } 17440 } 17441 elm.trigger("sticky_kit:stick"); 17442 } 17443 } 17444 if (fixed && enable_bottoming) { 17445 if (will_bottom == null) { 17446 will_bottom = scroll + height + offset > parent_height + parent_top; 17447 } 17448 if (!bottomed && will_bottom) { 17449 bottomed = true; 17450 if (parent.css("position") === "static") { 17451 parent.css({ 17452 position: "relative" 17453 }); 17454 } 17455 return elm.css({ 17456 position: "absolute", 17457 bottom: padding_bottom, 17458 top: "auto" 17459 }).trigger("sticky_kit:bottom"); 17460 } 17461 } 17462 }; 17463 recalc_and_tick = function() { 17464 recalc(); 17465 return tick(); 17466 }; 17467 detach = function() { 17468 detached = true; 17469 win.off("touchmove", tick); 17470 win.off("scroll", tick); 17471 win.off("resize", recalc_and_tick); 17472 $(document.body).off("sticky_kit:recalc", recalc_and_tick); 17473 elm.off("sticky_kit:detach", detach); 17474 elm.removeData("sticky_kit"); 17475 elm.css({ 17476 position: "", 17477 bottom: "", 17478 top: "", 17479 width: "" 17480 }); 17481 parent.position("position", ""); 17482 if (fixed) { 17483 if (manual_spacer == null) { 17484 if (el_float === "left" || el_float === "right") { 17485 elm.insertAfter(spacer); 17486 } 17487 spacer.remove(); 17488 } 17489 return elm.removeClass(sticky_class); 17490 } 17491 }; 17492 win.on("touchmove", tick); 17493 win.on("scroll", tick); 17494 win.on("resize", recalc_and_tick); 17495 $(document.body).on("sticky_kit:recalc", recalc_and_tick); 17496 elm.on("sticky_kit:detach", detach); 17497 return setTimeout(tick, 0); 17498 }; 17499 for (i = 0, len = this.length; i < len; i++) { 17500 elm = this[i]; 17501 fn($(elm)); 17502 } 17503 return this; 17504 }; 17505 17506}).call(this); 17507/* ========================================================================== 17508 * bootstrap-tab-history.js 17509 * Author: Michael Narayan <[email protected]> 17510 * Repository: https://github.com/mnarayan01/bootstrap-tab-history/ 17511 * ========================================================================== 17512 * Licensed under the Apache License, Version 2.0 (the "License"); you may 17513 * not use this file except in compliance with the License. You may obtain a 17514 * copy of the License at 17515 * 17516 * http://www.apache.org/licenses/LICENSE-2.0 17517 * 17518 * Unless required by applicable law or agreed to in writing, softw
17518are 17519 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 17520 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 17521 * License for the specific language governing permissions and limitations 17522 * under the License. 17523 * ========================================================================== */ 17524 17525/* ========================================================================== */ 17526/* JSHint directives */ 17527/* */ 17528/* global BootstrapTabHistory: true */ 17529/* */ 17530/* global document */ 17531/* global jQuery */ 17532/* global history */ 17533/* global window */ 17534/* ========================================================================== */ 17535 17536/** 17537 * Integrate [HTML5 history state tracking](https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Manipulating_the_browser_history) 17538 * with [`bootstrap/tab.js`](http://getbootstrap.com/javascript/#tabs). To enable tracking on a tab element, simply set 17539 * the `data-tab-history` attribute to true (or a string denoting a tab grouping). 17540 * 17541 * See the README for additional information. 17542 * 17543 * Functionality based upon bootstrap/tab.js v3.1.0; reference it when making any changes. 17544 */ 17545 17546BootstrapTabHistory = { 17547 options: { 17548 /** 17549 * When the anchor portion of the URI is used to activate a tab, scroll down to the given offset, rather than the 17550 * element with the given `id` attribute. Set to null to disable. Only relevant if showTabsBasedOnAnchor is true. 17551 * 17552 * May be overriden on a per-element basis by the attribute `data-tab-history-anchor-y-offset`. 17553 * 17554 * @public 17555 * @type {?number} 17556 */ 17557 defaultAnchorYOffset: 0, 17558 /** 17559 * Either 'push' or 'replace', for whether to use `history.pushState` or `history.replaceState`, resp. 17560 * 17561 * May be overriden on a per-element basis by the attribute `data-tab-history-changer`. 17562 * 17563 * @public 17564 * @type {string} 17565 */ 17566 defaultChanger: 'replace', 17567 /** 17568 * If true, update the URL in onShownTab in the calls to `history.pushState` and `history.replaceState`. Otherwise, 17569 * `null` is passed as the third parameter to these calls. 17570 * 17571 * May be overriden on a per-element basis by the attribute `data-tab-history-update-url`. 17572 * 17573 * @public 17574 * @type {boolean} 17575 */ 17576 defaultUpdateURL: false, 17577 /** 17578 * Should the anchor portion of the loaded URI be used to activate a single tab if no history was present on page 17579 * load. 17580 * 17581 * @public 17582 * @type {boolean} 17583 */ 17584 showTabsBasedOnAnchor: true 17585 } 17586}; 17587 17588(function () { 17589 'use strict'; 17590 17591 jQuery(function () { 17592 if(history && history.pushState && history.replaceState) { 17593 var bootstrapTabHistory = history.state && history.state.bootstrapTabHistory; 17594 17595 if(bootstrapTabHistory) { 17596 showTabsBasedOnState(bootstrapTabHistory); 17597 } else { 17598 showTabsBasedOnAnchor(); 17599 } 17600 17601 backfillHistoryState(); 17602 17603 jQuery(document).on('shown.bs.tab show.bs.collapse', onShownTab); 17604 jQuery(window).on('popstate', onPopState); 17605 } else { 17606 showTabsBasedOnAnchor(); 17607 } 17608 }); 17609 17610 /** 17611 * Used to prevent onShownTab from registering shown events that we triggered via showTabsBasedOnState. 17612 * 17613 * @type {boolean} 17614 */ 17615 var showingTabsBasedOnState = false; 17616 17617 /** 17618 * Used to update `history.state` to reflect the default active tabs on initial page load. This supports proper 17619 * `history.back` handling when `data-tab-history-update-url` is true. 17620 */ 17621 function backfillHistoryState() { 17622 var newState = null; 17623 17624 jQuery('li.active > [data-tab-history], .panel-title.active [data-tab-history]').each(function () {//edited by Uncode 17625 var $activeTabElement = jQuery(this); 17626 var selector = getTabSelector($activeTabElement); 17627 17628 if(selector) { 17629 var tabGroup = getTabGroup($activeTabElement); 17630 17631 if(tabGroup) { 17632 newState = createNewHistoryState(newState || history.state, tabGroup, selector); 17633 } 17634 } 17635 }); 17636 17637 if(newState) { 17638 history.replaceState(newState, '', null); 17639 } 17640 } 17641 17642 /** 17643 * Clone the existing state, ensure its bootstrapTabHistory attribute is an Object, and add the provided tabGroup to 17644 * said bootstrapTabHistory attribute. 17645 * 17646 * @param {?object} existingState 17647 * @param {!string} tabGroup 17648 * @param {!string} selector 17649 * @returns {!object} 17650 */ 17651 function createNewHistoryState(existingState, tabGroup, selector) { 17652 // Clone history.state and ensure it has a bootstrapTabHistory entry. 17653 var newState = jQuery.extend(true, {}, existingState, { 17654 bootstrapTabHistory: {} 17655 }); 17656 17657 newState.bootstrapTabHistory[tabGroup] = selector; 17658 17659 return newState; 17660 } 17661 17662 /** 17663 * @param {jQuery} $tab
17664 * @returns {?string} 17665 */ 17666 function getTabGroup($tab) { 17667 return parseTruthyAttributeValue($tab.data('tab-history')); 17668 } 17669 17670 /** 17671 * @param {jQuery} $tab 17672 * @returns {?string} 17673 */ 17674 function getTabSelector($tab) { 17675 return $tab.data('target') || $tab.attr('href'); 17676 } 17677 17678 /** 17679 * Receives the `shown.bs.tab` event. Updates `history.state` as appropriate. 17680 * 17681 * @param {jQuery.Event} shownEvt 17682 */ 17683 function onShownTab(shownEvt) { 17684 if(!showingTabsBasedOnState) { 17685 var $activatedTab = jQuery(shownEvt.target); 17686 if ( $activatedTab.hasClass('panel-collapse') ) 17687 $activatedTab = $activatedTab.closest('.panel').find('a'); 17688 var selector = getTabSelector($activatedTab); 17689 17690 if(selector) { 17691 var tabGroup = getTabGroup($activatedTab); 17692 17693 if(tabGroup) { 17694 var historyChanger = $activatedTab.data('tab-history-changer') || BootstrapTabHistory.options.defaultChanger; 17695 var newState = createNewHistoryState(history.state, tabGroup, selector); 17696 var updateURL = (function ($activatedTab) { 17697 if(selector[0] === '#') { 17698 var elementUpdateURLOption = parseTruthyAttributeValue($activatedTab.data('tab-history-update-url')); 17699 17700 if(elementUpdateURLOption === undefined) { 17701 return BootstrapTabHistory.options.defaultUpdateURL; 17702 } else { 17703 return elementUpdateURLOption; 17704 } 17705 } else { 17706 return false; 17707 } 17708 })($activatedTab); 17709 17710 switch(historyChanger) { 17711 case 'push': 17712 history.pushState(newState, '', updateURL ? selector : null); 17713 break; 17714 case 'replace': 17715 history.replaceState(newState, '', updateURL ? selector : null); 17716 break; 17717 default: 17718 throw new Error('Unknown tab-history-changer: ' + historyChanger); 17719 } 17720 } 17721 } 17722 } 17723 } 17724 17725 /** 17726 * Receives the `popstate` event. Shows tabs based on the value of `history.state` as appropriate. 17727 */ 17728 function onPopState() { 17729 var bootstrapTabHistory = history.state && history.state.bootstrapTabHistory; 17730 17731 if(bootstrapTabHistory) { 17732 showTabsBasedOnState(bootstrapTabHistory); 17733 } 17734 } 17735 17736 /** 17737 * Returns the given value, _unless_ that value is an empty string, in which case `true` is returned. 17738 * 17739 * Rationale: HAML data attributes which are set to `true` are rendered as a blank string. 17740 * 17741 * @param {*} value 17742 * @returns {*} 17743 */ 17744 function parseTruthyAttributeValue(value) { 17745 if(value) { 17746 return value; 17747 } else if(value === '') { 17748 return true; 17749 } else { 17750 return value; 17751 } 17752 } 17753 17754 /** 17755 * Show tabs based upon the anchor component of `window.location`. 17756 */ 17757 function showTabsBasedOnAnchor() { 17758 if(BootstrapTabHistory.options.showTabsBasedOnAnchor) { 17759 var anchor = window.location && window.location.hash; 17760 17761 if(anchor) { 17762 var $tabElement = showTabForSelector(anchor); 17763 17764 if($tabElement && window.addEventListener && window.removeEventListener) { 17765 var anchorYOffset = (function ($tabElement) { 17766 var elementSetting = $tabElement.data('tab-history-anchor-y-offset'); 17767 17768 if(elementSetting === undefined) { 17769 return BootstrapTabHistory.options.defaultAnchorYOffset; 17770 } else { 17771 return elementSetting; 17772 } 17773 })($tabElement); 17774 17775 // HACK: This prevents scrolling to the tab on page load. This relies on the fact that we should never get 17776 // here on `history.forward`, `history.back`, or `location.reload`, since in all those situations the 17777 // `history.state` object should have been used (unless the browser did not support the modern History API). 17778 if(anchorYOffset || anchorYOffset === 0) { 17779 var scrollListener = function resetAnchorScroll () { 17780 window.removeEventListener('scroll', scrollListener); 17781 window.scrollTo(0, anchorYOffset); 17782 }; 17783 17784 window.addEventListener('scroll', scrollListener); 17785 } 17786 } 17787 } 17788 } 17789 } 17790 17791 /** 17792 * Show a tab which corresponds to the provided selector. 17793 * 17794 * @param {string} selector - A CSS selector. 17795 * @returns {?jQuery} - The tab which was found to show (even if said tab was already active). 17796 */ 17797 function showTabForSelector(selector) { 17798 var $tabElement = (function (selector) { 17799 var $ret = null; 17800 17801 jQuery('[data-toggle="tab"], [data-toggle="pill"], [data-toggle="collapse"]').each(function () { 17802 var $potentialTab = jQuery(this); 17803 17804 if(($potentialTab.attr('href') === selector || $potentialTab.data('target') === selector ) && getTabGroup($potentialTab)) { 17805 $ret = $potentialTab; 17806 return false;
vendor: 4,522 bytes, lines 17807-17956
17807 } else { 17808 return null; 17809 } 17810 }); 17811 17812 return $ret; 17813 })(selector); 17814 17815 if($tabElement) { 17816 $tabElement.trigger('click'); 17817 //$tabElement.tab('show'); 17818 } 17819 17820 return $tabElement; 17821 } 17822 17823 /** 17824 * Iterate through the provided set of tab tab groups, showing the tabs based on the stored selectors. 17825 * 17826 * @param {object} bootstrapTabHistory - Each of the values is passed to showTabForSelector; the keys are actually irrelevant. 17827 */ 17828 function showTabsBasedOnState(bootstrapTabHistory) { 17829 showingTabsBasedOnState = true; 17830 17831 try { 17832 for(var k in bootstrapTabHistory) { 17833 if(bootstrapTabHistory.hasOwnProperty(k)) { 17834 showTabForSelector(bootstrapTabHistory[k]); 17835 } 17836 } 17837 } finally { 17838 showingTabsBasedOnState = false; 17839 } 17840 } 17841})(); 17842 17843/*! 17844 * Justified Gallery - v3.6.3 17845 * http://miromannino.github.io/Justified-Gallery/ 17846 * Copyright (c) 2016 Miro Mannino 17847 * Licensed under the MIT license. 17848 */ 17849(function($) { 17850 17851 function hasScrollBar() { 17852 return $("body").height() > $(window).height(); 17853 } 17854 /** 17855 * Justified Gallery controller constructor 17856 * 17857 * @param $gallery the gallery to build 17858 * @param settings the settings (the defaults are in $.fn.justifiedGallery.defaults) 17859 * @constructor 17860 */ 17861 var JustifiedGallery = function ($gallery, settings) { 17862 17863 this.settings = settings; 17864 this.checkSettings(); 17865 17866 this.imgAnalyzerTimeout = null; 17867 this.entries = null; 17868 this.buildingRow = { 17869 entriesBuff : [], 17870 width : 0, 17871 height : 0, 17872 aspectRatio : 0 17873 }; 17874 this.lastFetchedEntry = null; 17875 this.lastAnalyzedIndex = -1; 17876 this.yield = { 17877 every : 2, // do a flush every n flushes (must be greater than 1) 17878 flushed : 0 // flushed rows without a yield 17879 }; 17880 this.border = settings.border >= 0 ? settings.border : settings.margins; 17881 this.maxRowHeight = this.retrieveMaxRowHeight(); 17882 this.suffixRanges = this.retrieveSuffixRanges(); 17883 this.offY = this.border; 17884 this.rows = 0; 17885 this.spinner = { 17886 phase : 0, 17887 timeSlot : 150, 17888 $el : $('<div class="spinner"><span></span><span></span><span></span></div>'), 17889 intervalId : null 17890 }; 17891 this.checkWidthIntervalId = null; 17892 this.galleryWidth = $gallery.width(); 17893 this.$gallery = $gallery; 17894 17895 }; 17896 17897 /** @returns {String} the best suffix given the width and the height */ 17898 JustifiedGallery.prototype.getSuffix = function (width, height) { 17899 var longestSide, i; 17900 longestSide = (width > height) ? width : height; 17901 for (i = 0; i < this.suffixRanges.length; i++) { 17902 if (longestSide <= this.suffixRanges[i]) { 17903 return this.settings.sizeRangeSuffixes[this.suffixRanges[i]]; 17904 } 17905 } 17906 return this.settings.sizeRangeSuffixes[this.suffixRanges[i - 1]]; 17907 }; 17908 17909 /** 17910 * Remove the suffix from the string 17911 * 17912 * @returns {string} a new string without the suffix 17913 */ 17914 JustifiedGallery.prototype.removeSuffix = function (str, suffix) { 17915 return str.substring(0, str.length - suffix.length); 17916 }; 17917 17918 /** 17919 * @returns {boolean} a boolean to say if the suffix is contained in the str or not 17920 */ 17921 JustifiedGallery.prototype.endsWith = function (str, suffix) { 17922 return str.indexOf(suffix, str.length - suffix.length) !== -1; 17923 }; 17924 17925 /** 17926 * Get the used suffix of a particular url 17927 * 17928 * @param str 17929 * @returns {String} return the used suffix 17930 */ 17931 JustifiedGallery.prototype.getUsedSuffix = function (str) { 17932 for (var si in this.settings.sizeRangeSuffixes) { 17933 if (this.settings.sizeRangeSuffixes.hasOwnProperty(si)) { 17934 if (this.settings.sizeRangeSuffixes[si].length === 0) continue; 17935 if (this.endsWith(str, this.settings.sizeRangeSuffixes[si])) return this.settings.sizeRangeSuffixes[si]; 17936 } 17937 } 17938 return ''; 17939 }; 17940 17941 /** 17942 * Given an image src, with the width and the height, returns the new image src with the 17943 * best suffix to show the best quality thumbnail. 17944 * 17945 * @returns {String} the suffix to use 17946 */ 17947 JustifiedGallery.prototype.newSrc = function (imageSrc, imgWidth, imgHeight, image) { 17948 var newImageSrc; 17949 17950 if (this.settings.thumbnailPath) { 17951 newImageSrc = this.settings.thumbnailPath(imageSrc, imgWidth, imgHeight, image); 17952 } else { 17953 var matchRes = imageSrc.match(this.settings.extension); 17954 var ext = (matchRes !== null) ? matchRes[0] : ''; 17955 newImageSrc = imageSrc.replace(this.settings.extension, ''); 17956 newImageSrc = this.removeSuffix(newImageSrc, this.getUsedSuffix(newImageSrc));
17957 newImageSrc += this.getSuffix(imgWidth, imgHeight) + ext; 17958 } 17959 17960 return newImageSrc; 17961 }; 17962 17963 /** 17964 * Shows the images that is in the given entry 17965 * 17966 * @param $entry the entry 17967 * @param callback the callback that is called when the show animation is finished 17968 */ 17969 JustifiedGallery.prototype.showImg = function ($entry, callback) { 17970 if (this.settings.cssAnimation) { 17971 $entry.addClass('entry-visible'); 17972 if (callback) callback(); 17973 } else { 17974 $entry.stop().fadeTo(this.settings.imagesAnimationDuration, 1.0, callback); 17975 $entry.find('> img, > a > img').stop().fadeTo(this.settings.imagesAnimationDuration, 1.0, callback); 17976 } 17977 }; 17978 17979 /** 17980 * Extract the image src form the image, looking from the 'safe-src', and if it can't be found, from the 17981 * 'src' attribute. It saves in the image data the 'jg.originalSrc' field, with the extracted src. 17982 * 17983 * @param $image the image to analyze 17984 * @returns {String} the extracted src 17985 */ 17986 JustifiedGallery.prototype.extractImgSrcFromImage = function ($image) { 17987 var imageSrc = (typeof $image.data('safe-src') !== 'undefined') ? $image.data('safe-src') : $image.attr('src'); 17988 $image.data('jg.originalSrc', imageSrc); 17989 return imageSrc; 17990 }; 17991 17992 /** @returns {jQuery} the image in the given entry */ 17993 JustifiedGallery.prototype.imgFromEntry = function ($entry) { 17994 var $img = $entry.find('> img'); 17995 if ($img.length === 0) $img = $entry.find('> a > img'); 17996 if ($img.length === 0) $img = $entry.find('.t-entry-visual-cont img');//hacked by Uncode 17997 return $img.length === 0 ? null : $img; 17998 }; 17999 18000 /** @returns {jQuery} the caption in the given entry */ 18001 JustifiedGallery.prototype.captionFromEntry = function ($entry) { 18002 var $caption = $entry.find('> .caption'); 18003 return $caption.length === 0 ? null : $caption; 18004 }; 18005 18006 /** 18007 * Display the entry 18008 * 18009 * @param {jQuery} $entry the entry to display 18010 * @param {int} x the x position where the entry must be positioned 18011 * @param y the y position where the entry must be positioned 18012 * @param imgWidth the image width 18013 * @param imgHeight the image height 18014 * @param rowHeight the row height of the row that owns the entry 18015 */ 18016 JustifiedGallery.prototype.displayEntry = function ($entry, x, y, imgWidth, imgHeight, rowHeight) { 18017 $entry.width(imgWidth); 18018 $entry.height(Math.floor(rowHeight));//hacked by Uncode 18019 $entry.css('top', Math.floor(y));//hacked by Uncode 18020 $entry.css('left', x); 18021 18022 var $image = this.imgFromEntry($entry); 18023 if ($image !== null) { 18024 $image.css('width', imgWidth); 18025 $image.css('height', imgHeight); 18026 $image.css('margin-left', - imgWidth / 2); 18027 $image.css('margin-top', - imgHeight / 2); 18028 18029 // Image reloading for an high quality of thumbnails 18030 var imageSrc = $image.attr('src'); 18031 var newImageSrc = this.newSrc(imageSrc, imgWidth, imgHeight, $image[0]); 18032 18033 $image.one('error', function () { 18034 $image.attr('src', $image.data('jg.originalSrc')); //revert to the original thumbnail, we got it. 18035 }); 18036 18037 var loadNewImage = function () { 18038 if (imageSrc !== newImageSrc) { //load the new image after the fadeIn 18039 $image.attr('src', newImageSrc); 18040 } 18041 }; 18042 18043 if ($entry.data('jg.loaded') === 'skipped') { 18044 this.onImageEvent(imageSrc, $.proxy(function() { 18045 this.showImg($entry, loadNewImage); 18046 $entry.data('jg.loaded', true); 18047 }, this)); 18048 } else { 18049 this.showImg($entry, loadNewImage); 18050 } 18051 18052 } else { 18053 this.showImg($entry); 18054 } 18055 18056 this.displayEntryCaption($entry); 18057 }; 18058 18059 /** 18060 * Display the entry caption. If the caption element doesn't exists, it creates the caption using the 'alt' 18061 * or the 'title' attributes. 18062 * 18063 * @param {jQuery} $entry the entry to process 18064 */ 18065 JustifiedGallery.prototype.displayEntryCaption = function ($entry) { 18066 var $image = this.imgFromEntry($entry); 18067 if ($image !== null && this.settings.captions) { 18068 var $imgCaption = this.captionFromEntry($entry); 18069 18070 // Create it if it doesn't exists 18071 if ($imgCaption === null) { 18072 var caption = $image.attr('alt'); 18073 if (!this.isValidCaption(caption)) caption = $entry.attr('title'); 18074 if (this.isValidCaption(caption)) { // Create only we found something 18075 $imgCaption = $('<div class="caption">' + caption + '</div>'); 18076 $entry.append($imgCaption); 18077 $entry.data('jg.createdCaption', true); 18078 } 18079 } 18080 18081 // Create events (we check again the $imgCaption because it can be still inexistent) 18082 if ($imgCaption !== null) { 18083 if (!this.settings.cssAnimation) $imgCaption.stop().fadeTo(0, this.settings.captionSettings.nonVisibleOpacity); 18084 this.addCaptionEventsHandlers($entry); 18085 } 18086 } else { 18087 this.removeCaptionEventsHandlers($entry); 18088 } 18089 }; 18090 18091 /** 18092 * Validates the caption 18093 * 18094 * @param caption The caption that should be validated 18095 * @return {boolean} Validation result 18096 */ 18097 JustifiedGallery.prototype.isValidCaption = function (caption) { 18098 return (typeof caption !== 'undefined' && caption.length > 0); 18099 }; 18100 18101 /** 18102 * The callback for the event 'mouseenter'. It assumes that the event currentTarget is an entry. 18103 * It shows the caption using jQuery (or using CSS if it is configured so) 18104 * 18105 * @param {Event} eventObject the event object 18106 */ 18107 JustifiedGallery.prototype.onEntryMouseEnterForCaption = function (eventObject) { 18108 var $caption = this.captionFromEntry($(eventObject.currentTarget)); 18109 if (this.settings.cssAnimation) { 18110 $caption.addClass('caption-visible').removeClass('caption-hidden'); 18111 } else { 18112 $caption.stop().fadeTo(this.settings.captionSettings.animationDuration, 18113 this.settings.captionSettings.visibleOpacity); 18114 } 18115 }; 18116 18117 /** 18118 * The callback for the event 'mouseleave'. It assumes that the event currentTarget is an entry. 18119 * It hides the caption using jQuery (or using CSS if it is configured so) 18120 * 18121 * @param {Event} eventObject the event object 18122 */ 18123 JustifiedGallery.prototype.onEntryMouseLeaveForCaption = function (eventObject) { 18124 var $caption = this.captionFromEntry($(eventObject.currentTarget)); 18125 if (this.settings.cssAnimation) { 18126 $caption.removeClass('caption-visible').removeClass('caption-hidden'); 18127 } else { 18128 $caption.stop().fadeTo(this.settings.captionSettings.animationDuration, 18129 this.settings.captionSettings.nonVisibleOpacity); 18130 } 18131 }; 18132 18133 /** 18134 * Add the handlers of the entry for the caption 18135 * 18136 * @param $entry the entry to modify 18137 */ 18138 JustifiedGallery.prototype.addCaptionEventsHandlers = function ($entry) { 18139 var captionMouseEvents = $entry.data('jg.captionMouseEvents'); 18140 if (typeof captionMouseEvents === 'undefined') { 18141 captionMouseEvents = { 18142 mouseenter: $.proxy(this.onEntryMouseEnterForCaption, this), 18143 mouseleave: $.proxy(this.onEntryMouseLeaveForCaption, this) 18144 }; 18145 $entry.on('mouseenter', undefined, undefined, captionMouseEvents.mouseenter); 18146 $entry.on('mouseleave', undefined, undefined, captionMouseEvents.mouseleave); 18147 $entry.data('jg.captionMouseEvents', captionMouseEvents); 18148 } 18149 }; 18150 18151 /** 18152 * Remove the handlers of the entry for the caption 18153 * 18154 * @param $entry the entry to modify 18155 */ 18156 JustifiedGallery.prototype.removeCaptionEventsHandlers = function ($entry) { 18157 var captionMouseEvents = $entry.data('jg.captionMouseEvents'); 18158 if (typeof captionMouseEvents !== 'undefined') { 18159 $entry.off('mouseenter', undefined, captionMouseEvents.mouseenter); 18160 $entry.off('mouseleave', undefined, captionMouseEvents.mouseleave); 18161 $entry.removeData('jg.captionMouseEvents'); 18162 } 18163 }; 18164 18165 /** 18166 * Justify the building row, preparing it to 18167 * 18168 * @param isLastRow 18169 * @returns a boolean to know if the row has been justified or not 18170 */ 18171 JustifiedGallery.prototype.prepareBuildingRow = function (isLastRow) { 18172 var i, $entry, imgAspectRatio, newImgW, newImgH, justify = true; 18173 var minHeight = 0; 18174 var availableWidth = this.galleryWidth - 2 * this.border - ( 18175 (this.buildingRow.entriesBuff.length - 1) * this.settings.margins); 18176 var rowHeight = Math.floor( availableWidth / this.buildingRow.aspectRatio );//hacked by Uncode 18177 var defaultRowHeight = this.settings.rowHeight; 18178 var justifiable = this.buildingRow.width / availableWidth > this.settings.justifyThreshold; 18179 18180 //Skip the last row if we can't justify it and the lastRow == 'hide' 18181 if (isLastRow && this.settings.lastRow === 'hide' && !justifiable) { 18182 for (i = 0; i < this.buildingRow.entriesBuff.length; i++) { 18183 $entry = this.buildingRow.entriesBuff[i]; 18184 if (this.settings.cssAnimation) 18185 $entry.removeClass('entry-visible'); 18186 else { 18187 $entry.stop().fadeTo(0, 0.1); 18188 $entry.find('> img, > a > img').fadeTo(0, 0); 18189 } 18190 } 18191 return -1; 18192 } 18193 18194 // With lastRow = nojustify, justify if is justificable (the images will not become too big) 18195 if (isLastRow && !justifiable && this.settings.lastRow !== 'justify' && this.settings.lastRow !== 'hide') { 18196 justify = false;
18197 18198 if (this.rows > 0) { 18199 defaultRowHeight = (this.offY - this.border - this.settings.margins * this.rows) / this.rows; 18200 justify = defaultRowHeight * this.buildingRow.aspectRatio / availableWidth > this.settings.justifyThreshold; 18201 } 18202 } 18203 18204 for (i = 0; i < this.buildingRow.entriesBuff.length; i++) { 18205 $entry = this.buildingRow.entriesBuff[i]; 18206 imgAspectRatio = $entry.data('jg.width') / $entry.data('jg.height'); 18207 18208 if (justify) { 18209 newImgW = (i === this.buildingRow.entriesBuff.length - 1) ? availableWidth : rowHeight * imgAspectRatio; 18210 newImgH = rowHeight; 18211 } else { 18212 newImgW = defaultRowHeight * imgAspectRatio; 18213 newImgH = defaultRowHeight; 18214 } 18215 18216 availableWidth -= Math.round(newImgW); 18217 $entry.data('jg.jwidth', Math.round(newImgW)); 18218 $entry.data('jg.jheight', Math.ceil(newImgH)); 18219 if (i === 0 || minHeight > newImgH) minHeight = newImgH; 18220 } 18221 18222 this.buildingRow.height = minHeight; 18223 return justify; 18224 }; 18225 18226 /** 18227 * Clear the building row data to be used for a new row 18228 */ 18229 JustifiedGallery.prototype.clearBuildingRow = function () { 18230 this.buildingRow.entriesBuff = []; 18231 this.buildingRow.aspectRatio = 0; 18232 this.buildingRow.width = 0; 18233 }; 18234 18235 /** 18236 * Flush a row: justify it, modify the gallery height accordingly to the row height 18237 * 18238 * @param isLastRow 18239 */ 18240 JustifiedGallery.prototype.flushRow = function (isLastRow) { 18241 var settings = this.settings; 18242 var $entry, buildingRowRes, offX = this.border, i; 18243 18244 buildingRowRes = this.prepareBuildingRow(isLastRow); 18245 if (isLastRow && settings.lastRow === 'hide' && buildingRowRes === -1) { 18246 this.clearBuildingRow(); 18247 return; 18248 } 18249 18250 if (this.maxRowHeight) { 18251 if (this.maxRowHeight.isPercentage && this.maxRowHeight.value * settings.rowHeight < this.buildingRow.height) { 18252 this.buildingRow.height = this.maxRowHeight.value * settings.rowHeight; 18253 } else if (this.maxRowHeight.value >= settings.rowHeight && this.maxRowHeight.value < this.buildingRow.height) { 18254 this.buildingRow.height = this.maxRowHeight.value; 18255 } 18256 } 18257 18258 //Align last (unjustified) row 18259 if (settings.lastRow === 'center' || settings.lastRow === 'right') { 18260 var availableWidth = this.galleryWidth - 2 * this.border - (this.buildingRow.entriesBuff.length - 1) * settings.margins; 18261 18262 for (i = 0; i < this.buildingRow.entriesBuff.length; i++) { 18263 $entry = this.buildingRow.entriesBuff[i]; 18264 availableWidth -= $entry.data('jg.jwidth'); 18265 } 18266 18267 if (settings.lastRow === 'center') 18268 offX += availableWidth / 2; 18269 else if (settings.lastRow === 'right') 18270 offX += availableWidth; 18271 } 18272 18273 for (i = 0; i < this.buildingRow.entriesBuff.length; i++) { 18274 $entry = this.buildingRow.entriesBuff[i]; 18275 this.displayEntry($entry, offX, this.offY, $entry.data('jg.jwidth'), $entry.data('jg.jheight'), this.buildingRow.height); 18276 offX += $entry.data('jg.jwidth') + settings.margins; 18277 } 18278 18279 //Gallery Height 18280 this.galleryHeightToSet = this.offY + this.buildingRow.height + this.border; 18281 this.$gallery.height(this.galleryHeightToSet + this.getSpinnerHeight()); 18282 18283 if (!isLastRow || (this.buildingRow.height <= settings.rowHeight && buildingRowRes)) { 18284 //Ready for a new row 18285 this.offY += this.buildingRow.height + settings.margins; 18286 this.rows += 1; 18287 this.clearBuildingRow(); 18288 this.$gallery.trigger('jg.rowflush'); 18289 } 18290 }; 18291 18292 /** 18293 * Checks the width of the gallery container, to know if a new justification is needed 18294 */ 18295 var scrollBarOn = false; 18296 JustifiedGallery.prototype.checkWidth = function () { 18297 this.checkWidthIntervalId = setInterval($.proxy(function () { 18298 var galleryWidth = parseFloat(this.$gallery.width()); 18299 if (hasScrollBar() === scrollBarOn) { 18300 if (Math.abs(galleryWidth - this.galleryWidth) > this.settings.refreshSensitivity) { 18301 this.galleryWidth = galleryWidth; 18302 this.rewind(); 18303 18304 // Restart to analyze 18305 this.startImgAnalyzer(true); 18306 } 18307 } else { 18308 scrollBarOn = hasScrollBar(); 18309 this.galleryWidth = galleryWidth; 18310 } 18311 }, this), this.settings.refreshTime); 18312 }; 18313 18314 /** 18315 * @returns {boolean} a boolean saying if the spinner is active or not 18316 */ 18317 JustifiedGallery.prototype.isSpinnerActive = function () { 18318 return this.spinner.intervalId !== null; 18319 }; 18320 18321 /** 18322 * @returns {int} the spinner height 18323 */ 18324 JustifiedGallery.prototype.getSpinnerHeight = function () {
18325 return this.spinner.$el.innerHeight(); 18326 }; 18327 18328 /** 18329 * Stops the spinner animation and modify the gallery height to exclude the spinner 18330 */ 18331 JustifiedGallery.prototype.stopLoadingSpinnerAnimation = function () { 18332 clearInterval(this.spinner.intervalId); 18333 this.spinner.intervalId = null; 18334 this.$gallery.height(this.$gallery.height() - this.getSpinnerHeight()); 18335 this.spinner.$el.detach(); 18336 }; 18337 18338 /** 18339 * Starts the spinner animation 18340 */ 18341 JustifiedGallery.prototype.startLoadingSpinnerAnimation = function () { 18342 var spinnerContext = this.spinner; 18343 var $spinnerPoints = spinnerContext.$el.find('span'); 18344 clearInterval(spinnerContext.intervalId); 18345 this.$gallery.append(spinnerContext.$el); 18346 this.$gallery.height(this.offY + this.buildingRow.height + this.getSpinnerHeight()); 18347 spinnerContext.intervalId = setInterval(function () { 18348 if (spinnerContext.phase < $spinnerPoints.length) { 18349 $spinnerPoints.eq(spinnerContext.phase).fadeTo(spinnerContext.timeSlot, 1); 18350 } else {
vendor: 4,333 bytes, lines 18351-18495
18351 $spinnerPoints.eq(spinnerContext.phase - $spinnerPoints.length).fadeTo(spinnerContext.timeSlot, 0); 18352 } 18353 spinnerContext.phase = (spinnerContext.phase + 1) % ($spinnerPoints.length * 2); 18354 }, spinnerContext.timeSlot); 18355 }; 18356 18357 /** 18358 * Rewind the image analysis to start from the first entry. 18359 */ 18360 JustifiedGallery.prototype.rewind = function () { 18361 this.lastFetchedEntry = null; 18362 this.lastAnalyzedIndex = -1; 18363 this.offY = this.border; 18364 this.rows = 0; 18365 this.clearBuildingRow(); 18366 }; 18367 18368 /** 18369 * Update the entries searching it from the justified gallery HTML element 18370 * 18371 * @param norewind if norewind only the new entries will be changed (i.e. randomized, sorted or filtered) 18372 * @returns {boolean} true if some entries has been founded 18373 */ 18374 JustifiedGallery.prototype.updateEntries = function (norewind) { 18375 var newEntries; 18376 18377 if (norewind && this.lastFetchedEntry != null) { 18378 newEntries = $(this.lastFetchedEntry).nextAll(this.settings.selector).toArray(); 18379 } else { 18380 this.entries = []; 18381 newEntries = this.$gallery.children(this.settings.selector).toArray(); 18382 } 18383 18384 if (newEntries.length > 0) { 18385 18386 // Sort or randomize 18387 if ($.isFunction(this.settings.sort)) { 18388 newEntries = this.sortArray(newEntries); 18389 } else if (this.settings.randomize) { 18390 newEntries = this.shuffleArray(newEntries); 18391 } 18392 this.lastFetchedEntry = newEntries[newEntries.length - 1]; 18393 18394 // Filter 18395 if (this.settings.filter) { 18396 newEntries = this.filterArray(newEntries); 18397 } else { 18398 this.resetFilters(newEntries); 18399 } 18400 18401 } 18402 18403 this.entries = this.entries.concat(newEntries); 18404 return true; 18405 }; 18406 18407 /** 18408 * Apply the entries order to the DOM, iterating the entries and appending the images 18409 * 18410 * @param entries the entries that has been modified and that must be re-ordered in the DOM 18411 */ 18412 JustifiedGallery.prototype.insertToGallery = function (entries) { 18413 var that = this; 18414 $.each(entries, function () { 18415 $(this).appendTo(that.$gallery); 18416 }); 18417 }; 18418 18419 /** 18420 * Shuffle the array using the Fisher-Yates shuffle algorithm 18421 * 18422 * @param a the array to shuffle 18423 * @return the shuffled array 18424 */ 18425 JustifiedGallery.prototype.shuffleArray = function (a) { 18426 var i, j, temp; 18427 for (i = a.length - 1; i > 0; i--) { 18428 j = Math.floor(Math.random() * (i + 1)); 18429 temp = a[i]; 18430 a[i] = a[j]; 18431 a[j] = temp; 18432 } 18433 this.insertToGallery(a); 18434 return a; 18435 }; 18436 18437 /** 18438 * Sort the array using settings.comparator as comparator 18439 * 18440 * @param a the array to sort (it is sorted) 18441 * @return the sorted array 18442 */ 18443 JustifiedGallery.prototype.sortArray = function (a) { 18444 a.sort(this.settings.sort); 18445 this.insertToGallery(a); 18446 return a; 18447 }; 18448 18449 /** 18450 * Reset the filters removing the 'jg-filtered' class from all the entries 18451 * 18452 * @param a the array to reset 18453 */ 18454 JustifiedGallery.prototype.resetFilters = function (a) { 18455 for (var i = 0; i < a.length; i++) $(a[i]).removeClass('jg-filtered'); 18456 }; 18457 18458 /** 18459 * Filter the entries considering theirs classes (if a string has been passed) or using a function for filtering. 18460 * 18461 * @param a the array to filter 18462 * @return the filtered array 18463 */ 18464 JustifiedGallery.prototype.filterArray = function (a) { 18465 var settings = this.settings; 18466 if ($.type(settings.filter) === 'string') { 18467 // Filter only keeping the entries passed in the string 18468 return a.filter(function (el) { 18469 var $el = $(el); 18470 if ($el.is(settings.filter)) { 18471 $el.removeClass('jg-filtered'); 18472 return true; 18473 } else { 18474 $el.addClass('jg-filtered').removeClass('jg-visible'); 18475 return false; 18476 } 18477 }); 18478 } else if ($.isFunction(settings.filter)) { 18479 // Filter using the passed function 18480 var filteredArr = a.filter(settings.filter); 18481 for (var i = 0; i < a.length; i++) { 18482 if (filteredArr.indexOf(a[i]) == -1) { 18483 $(a[i]).addClass('jg-filtered').removeClass('jg-visible'); 18484 } else { 18485 $(a[i]).removeClass('jg-filtered'); 18486 } 18487 } 18488 return filteredArr; 18489 } 18490 }; 18491 18492 /** 18493 * Destroy the Justified Gallery instance. 18494 * 18495 * It clears all the css properties added in the style attributes. We doesn't backup the original
18496 * values for those css attributes, because it costs (performance) and because in general one 18497 * shouldn't use the style attribute for an uniform set of images (where we suppose the use of 18498 * classes). Creating a backup is also difficult because JG could be called multiple times and 18499 * with different style attributes. 18500 */ 18501 JustifiedGallery.prototype.destroy = function () { 18502 clearInterval(this.checkWidthIntervalId); 18503 18504 $.each(this.entries, $.proxy(function(_, entry) { 18505 var $entry = $(entry); 18506 18507 // Reset entry style 18508 $entry.css('width', ''); 18509 $entry.css('height', ''); 18510 $entry.css('top', ''); 18511 $entry.css('left', ''); 18512 $entry.data('jg.loaded', undefined); 18513 $entry.removeClass('jg-entry'); 18514 18515 // Reset image style 18516 var $img = this.imgFromEntry($entry); 18517 $img.css('width', ''); 18518 $img.css('height', ''); 18519 $img.css('margin-left', ''); 18520 $img.css('margin-top', ''); 18521 $img.attr('src', $img.data('jg.originalSrc')); 18522 $img.data('jg.originalSrc', undefined); 18523 18524 // Remove caption 18525 this.removeCaptionEventsHandlers($entry); 18526 var $caption = this.captionFromEntry($entry); 18527 if ($entry.data('jg.createdCaption')) { 18528 // remove also the caption element (if created by jg) 18529 $entry.data('jg.createdCaption', undefined); 18530 if ($caption !== null) $caption.remove(); 18531 } else { 18532 if ($caption !== null) $caption.fadeTo(0, 1); 18533 } 18534 18535 }, this)); 18536 18537 this.$gallery.css('height', ''); 18538 this.$gallery.removeClass('justified-gallery'); 18539 this.$gallery.data('jg.controller', undefined); 18540 }; 18541 18542 /** 18543 * Analyze the images and builds the rows. It returns if it found an image that is not loaded. 18544 * 18545 * @param isForResize if the image analyzer is called for resizing or not, to call a different callback at the end 18546 */ 18547 JustifiedGallery.prototype.analyzeImages = function (isForResize) { 18548 for (var i = this.lastAnalyzedIndex + 1; i < this.entries.length; i++) { 18549 var $entry = $(this.entries[i]); 18550 if ($entry.data('jg.loaded') === true || $entry.data('jg.loaded') === 'skipped') { 18551 var availableWidth = this.galleryWidth - 2 * this.border - ( 18552 (this.buildingRow.entriesBuff.length - 1) * this.settings.margins); 18553 var imgAspectRatio = $entry.data('jg.width') / $entry.data('jg.height'); 18554 if (availableWidth / (this.buildingRow.aspectRatio + imgAspectRatio) < this.settings.rowHeight) { 18555 this.flushRow(false); 18556 if(++this.yield.flushed >= this.yield.every) { 18557 this.startImgAnalyzer(isForResize); 18558 return; 18559 } 18560 } 18561 18562 this.buildingRow.entriesBuff.push($entry); 18563 this.buildingRow.aspectRatio += imgAspectRatio; 18564 this.buildingRow.width += imgAspectRatio * this.settings.rowHeight; 18565 this.lastAnalyzedIndex = i; 18566 18567 } else if ($entry.data('jg.loaded') !== 'error') { 18568 return; 18569 } 18570 } 18571 18572 // Last row flush (the row is not full) 18573 if (this.buildingRow.entriesBuff.length > 0) this.flushRow(true); 18574 18575 if (this.isSpinnerActive()) { 18576 this.stopLoadingSpinnerAnimation(); 18577 } 18578 18579 /* Stop, if there is, the timeout to start the analyzeImages. 18580 This is because an image can be set loaded, and the timeout can be set, 18581 but this image can be analyzed yet. 18582 */ 18583 this.stopImgAnalyzerStarter(); 18584 18585 //On complete callback 18586 this.$gallery.trigger(isForResize ? 'jg.resize' : 'jg.complete'); 18587 this.$gallery.height(this.galleryHeightToSet); 18588 }; 18589 18590 /** 18591 * Stops any ImgAnalyzer starter (that has an assigned timeout) 18592 */ 18593 JustifiedGallery.prototype.stopImgAnalyzerStarter = function () { 18594 this.yield.flushed = 0; 18595 if (this.imgAnalyzerTimeout !== null) clearTimeout(this.imgAnalyzerTimeout); 18596 }; 18597 18598 /** 18599 * Starts the image analyzer. It is not immediately called to let the browser to update the view 18600 * 18601 * @param isForResize specifies if the image analyzer must be called for resizing or not 18602 */ 18603 JustifiedGallery.prototype.startImgAnalyzer = function (isForResize) { 18604 var that = this; 18605 this.stopImgAnalyzerStarter(); 18606 this.imgAnalyzerTimeout = setTimeout(function () { 18607 that.analyzeImages(isForResize); 18608 }, 0.001); // we can't start it immediately due to a IE different behaviour 18609 }; 18610 18611 /** 18612 * Checks if the image is loaded or not using another image object. We cannot use the 'complete' image property, 18613 * because some browsers, with a 404 set complete = true. 18614 * 18615 * @param imageSrc the image src to load 18616 * @param onLoad callback that is called when the image has been loaded
vendor: 13,320 bytes, lines 18617-18967
18617 * @param onError callback that is called in case of an error 18618 */ 18619 JustifiedGallery.prototype.onImageEvent = function (imageSrc, onLoad, onError) { 18620 if (!onLoad && !onError) return; 18621 18622 var memImage = new Image(); 18623 var $memImage = $(memImage); 18624 if (onLoad) { 18625 $memImage.one('load', function () { 18626 $memImage.off('load error'); 18627 onLoad(memImage); 18628 }); 18629 } 18630 if (onError) { 18631 $memImage.one('error', function() { 18632 $memImage.off('load error'); 18633 onError(memImage); 18634 }); 18635 } 18636 memImage.src = imageSrc; 18637 }; 18638 18639 /** 18640 * Init of Justified Gallery controlled 18641 * It analyzes all the entries starting theirs loading and calling the image analyzer (that works with loaded images) 18642 */ 18643 JustifiedGallery.prototype.init = function () { 18644 var imagesToLoad = false, skippedImages = false, that = this; 18645 $.each(this.entries, function (index, entry) { 18646 var $entry = $(entry); 18647 var $image = that.imgFromEntry($entry); 18648 18649 $entry.addClass('jg-entry'); 18650 18651 if ($entry.data('jg.loaded') !== true && $entry.data('jg.loaded') !== 'skipped') { 18652 18653 // Link Rel global overwrite 18654 if (that.settings.rel !== null) $entry.attr('rel', that.settings.rel); 18655 18656 // Link Target global overwrite 18657 if (that.settings.target !== null) $entry.attr('target', that.settings.target); 18658 18659 if ($image !== null) { 18660 18661 // Image src 18662 var imageSrc = that.extractImgSrcFromImage($image); 18663 $image.attr('src', imageSrc); 18664 18665 /* If we have the height and the width, we don't wait that the image is loaded, but we start directly 18666 * with the justification */ 18667 if (that.settings.waitThumbnailsLoad === false) { 18668 var width = parseFloat($image.attr('width')); 18669 var height = parseFloat($image.attr('height')); 18670 if (!isNaN(width) && !isNaN(height)) { 18671 $entry.data('jg.width', width); 18672 $entry.data('jg.height', height); 18673 $entry.data('jg.loaded', 'skipped'); 18674 skippedImages = true; 18675 that.startImgAnalyzer(false); 18676 return true; // continue 18677 } 18678 } 18679 18680 $entry.data('jg.loaded', false); 18681 imagesToLoad = true; 18682 18683 // Spinner start 18684 if (!that.isSpinnerActive()) that.startLoadingSpinnerAnimation(); 18685 18686 that.onImageEvent(imageSrc, function (loadImg) { // image loaded 18687 $entry.data('jg.width', loadImg.width); 18688 $entry.data('jg.height', loadImg.height); 18689 $entry.data('jg.loaded', true); 18690 that.startImgAnalyzer(false); 18691 }, function () { // image load error 18692 $entry.data('jg.loaded', 'error'); 18693 that.startImgAnalyzer(false); 18694 }); 18695 18696 } else { 18697 $entry.data('jg.loaded', true); 18698 $entry.data('jg.width', $entry.width() | parseFloat($entry.css('width')) | 1); 18699 $entry.data('jg.height', $entry.height() | parseFloat($entry.css('height')) | 1); 18700 } 18701 18702 } 18703 18704 }); 18705 18706 if (!imagesToLoad && !skippedImages) this.startImgAnalyzer(false); 18707 this.checkWidth(); 18708 }; 18709 18710 /** 18711 * Checks that it is a valid number. If a string is passed it is converted to a number 18712 * 18713 * @param settingContainer the object that contains the setting (to allow the conversion) 18714 * @param settingName the setting name 18715 */ 18716 JustifiedGallery.prototype.checkOrConvertNumber = function (settingContainer, settingName) { 18717 if ($.type(settingContainer[settingName]) === 'string') { 18718 settingContainer[settingName] = parseFloat(settingContainer[settingName]); 18719 } 18720 18721 if ($.type(settingContainer[settingName]) === 'number') { 18722 if (isNaN(settingContainer[settingName])) throw 'invalid number for ' + settingName; 18723 } else { 18724 throw settingName + ' must be a number'; 18725 } 18726 }; 18727 18728 /** 18729 * Checks the sizeRangeSuffixes and, if necessary, converts 18730 * its keys from string (e.g. old settings with 'lt100') to int. 18731 */ 18732 JustifiedGallery.prototype.checkSizeRangesSuffixes = function () { 18733 if ($.type(this.settings.sizeRangeSuffixes) !== 'object') { 18734 throw 'sizeRangeSuffixes must be defined and must be an object'; 18735 } 18736 18737 var suffixRanges = []; 18738 for (var rangeIdx in this.settings.sizeRangeSuffixes) { 18739 if (this.settings.sizeRangeSuffixes.hasOwnProperty(rangeIdx)) suffixRanges.push(rangeIdx); 18740 } 18741 18742 var newSizeRngSuffixes = {0: ''}; 18743 for (var i = 0; i < suffixRanges.length; i++) { 18744 if ($.type(suffixRanges[i]) === 'string') { 18745 try { 18746 var numIdx = parseInt(suffixRanges[i].replace(/^[a-z]+/, ''), 10); 18747 newSizeRngSuffixes[numIdx] = this.settings.sizeRangeSuffixes[suffixRanges[i]]; 18748 } catch (e) { 18749 throw 'sizeRangeSuffixes keys must contains correct numbers (' + e + ')'; 18750 } 18751 } else { 18752 newSizeRngSuffixes[suffixRanges[i]] = this.settings.sizeRangeSuffixes[suffixRanges[i]]; 18753 } 18754 } 18755 18756 this.settings.sizeRangeSuffixes = newSizeRngSuffixes; 18757 }; 18758 18759 /** 18760 * check and convert the maxRowHeight setting 18761 */ 18762 JustifiedGallery.prototype.retrieveMaxRowHeight = function () { 18763 var newMaxRowHeight = { }; 18764 18765 if ($.type(this.settings.maxRowHeight) === 'string') { 18766 if (this.settings.maxRowHeight.match(/^[0-9]+%$/)) { 18767 newMaxRowHeight.value = parseFloat(this.settings.maxRowHeight.match(/^([0-9]+)%$/)[1]) / 100; 18768 newMaxRowHeight.isPercentage = false; 18769 } else { 18770 newMaxRowHeight.value = parseFloat(this.settings.maxRowHeight); 18771 newMaxRowHeight.isPercentage = true; 18772 } 18773 } else if ($.type(this.settings.maxRowHeight) === 'number') { 18774 newMaxRowHeight.value = this.settings.maxRowHeight; 18775 newMaxRowHeight.isPercentage = false; 18776 } else if (this.settings.maxRowHeight === false || 18777 this.settings.maxRowHeight === null || 18778 typeof this.settings.maxRowHeight == 'undefined') { 18779 return null; 18780 } else { 18781 throw 'maxRowHeight must be a number or a percentage'; 18782 } 18783 18784 // check if the converted value is not a number 18785 if (isNaN(newMaxRowHeight.value)) throw 'invalid number for maxRowHeight'; 18786 18787 // check values 18788 if (newMaxRowHeight.isPercentage) { 18789 if (newMaxRowHeight.value < 100) newMaxRowHeight.value = 100; 18790 } 18791 18792 return newMaxRowHeight; 18793 }; 18794 18795 /** 18796 * Checks the settings 18797 */ 18798 JustifiedGallery.prototype.checkSettings = function () { 18799 this.checkSizeRangesSuffixes(); 18800 18801 this.checkOrConvertNumber(this.settings, 'rowHeight'); 18802 this.checkOrConvertNumber(this.settings, 'margins'); 18803 this.checkOrConvertNumber(this.settings, 'border'); 18804 18805 var lastRowModes = [ 18806 'justify', 18807 'nojustify', 18808 'left', 18809 'center', 18810 'right', 18811 'hide' 18812 ]; 18813 if (lastRowModes.indexOf(this.settings.lastRow) === -1) { 18814 throw 'lastRow must be one of: ' + lastRowModes.join(', '); 18815 } 18816 18817 this.checkOrConvertNumber(this.settings, 'justifyThreshold'); 18818 if (this.settings.justifyThreshold < 0 || this.settings.justifyThreshold > 1) { 18819 throw 'justifyThreshold must be in the interval [0,1]'; 18820 } 18821 if ($.type(this.settings.cssAnimation) !== 'boolean') { 18822 throw 'cssAnimation must be a boolean'; 18823 } 18824 18825 if ($.type(this.settings.captions) !== 'boolean') throw 'captions must be a boolean'; 18826 this.checkOrConvertNumber(this.settings.captionSettings, 'animationDuration'); 18827 18828 this.checkOrConvertNumber(this.settings.captionSettings, 'visibleOpacity'); 18829 if (this.settings.captionSettings.visibleOpacity < 0 || 18830 this.settings.captionSettings.visibleOpacity > 1) { 18831 throw 'captionSettings.visibleOpacity must be in the interval [0, 1]'; 18832 } 18833 18834 this.checkOrConvertNumber(this.settings.captionSettings, 'nonVisibleOpacity'); 18835 if (this.settings.captionSettings.nonVisibleOpacity < 0 || 18836 this.settings.captionSettings.nonVisibleOpacity > 1) { 18837 throw 'captionSettings.nonVisibleOpacity must be in the interval [0, 1]'; 18838 } 18839 18840 this.checkOrConvertNumber(this.settings, 'imagesAnimationDuration'); 18841 this.checkOrConvertNumber(this.settings, 'refreshTime'); 18842 this.checkOrConvertNumber(this.settings, 'refreshSensitivity'); 18843 if ($.type(this.settings.randomize) !== 'boolean') throw 'randomize must be a boolean'; 18844 if ($.type(this.settings.selector) !== 'string') throw 'selector must be a string'; 18845 18846 if (this.settings.sort !== false && !$.isFunction(this.settings.sort)) { 18847 throw 'sort must be false or a comparison function'; 18848 } 18849 18850 if (this.settings.filter !== false && !$.isFunction(this.settings.filter) && 18851 $.type(this.settings.filter) !== 'string') { 18852 throw 'filter must be false, a string or a filter function'; 18853 } 18854 }; 18855 18856 /** 18857 * It brings all the indexes from the sizeRangeSuffixes and it orders them. They are then sorted and returned. 18858 * @returns {Array} sorted suffix ranges 18859 */ 18860 JustifiedGallery.prototype.retrieveSuffixRanges = function () { 18861 var suffixRanges = []; 18862 for (var rangeIdx in this.settings.sizeRangeSuffixes) { 18863 if (this.settings.sizeRangeSuffixes.hasOwnProperty(rangeIdx)) suffixRanges.push(parseInt(rangeIdx, 10)); 18864 } 18865 suffixRanges.sort(function (a, b) { return a > b ? 1 : a < b ? -1 : 0; }); 18866 return suffixRanges; 18867 }; 18868 18869 /** 18870 * Update the existing settings only changing some of them 18871 * 18872 * @param newSettings the new settings (or a subgroup of them) 18873 */ 18874 JustifiedGallery.prototype.updateSettings = function (newSettings) { 18875 // In this case Justified Gallery has been called again changing only some options 18876 this.settings = $.extend({}, this.settings, newSettings); 18877 this.checkSettings(); 18878 18879 // As reported in the settings: negative value = same as margins, 0 = disabled 18880 this.border = this.settings.border >= 0 ? this.settings.border : this.settings.margins; 18881 18882 this.maxRowHeight = this.retrieveMaxRowHeight(); 18883 this.suffixRanges = this.retrieveSuffixRanges(); 18884 }; 18885 18886 /** 18887 * Justified Gallery plugin for jQuery 18888 * 18889 * Events 18890 * - jg.complete : called when all the gallery has been created 18891 * - jg.resize : called when the gallery has been resized 18892 * - jg.rowflush : when a new row appears 18893 * 18894 * @param arg the action (or the settings) passed when the plugin is called 18895 * @returns {*} the object itself 18896 */ 18897 $.fn.justifiedGallery = function (arg) { 18898 return this.each(function (index, gallery) { 18899 18900 var $gallery = $(gallery); 18901 $gallery.addClass('justified-gallery'); 18902 18903 var controller = $gallery.data('jg.controller'); 18904 if (typeof controller === 'undefined') { 18905 // Create controller and assign it to the object data 18906 if (typeof arg !== 'undefined' && arg !== null && $.type(arg) !== 'object') { 18907 if (arg === 'destroy') return; // Just a call to an unexisting object 18908 throw 'The argument must be an object'; 18909 } 18910 controller = new JustifiedGallery($gallery, $.extend({}, $.fn.justifiedGallery.defaults, arg)); 18911 $gallery.data('jg.controller', controller); 18912 } else if (arg === 'norewind') { 18913 // In this case we don't rewind: we analyze only the latest images (e.g. to complete the last unfinished row 18914 // ... left to be more readable 18915 } else if (arg === 'destroy') { 18916 controller.destroy(); 18917 return; 18918 } else { 18919 // In this case Justified Gallery has been called again changing only some options 18920 controller.updateSettings(arg); 18921 controller.rewind(); 18922 } 18923 18924 // Update the entries list 18925 if (!controller.updateEntries(arg === 'norewind')) return; 18926 18927 // Init justified gallery 18928 controller.init(); 18929 18930 }); 18931 }; 18932 18933 // Default options 18934 $.fn.justifiedGallery.defaults = { 18935 sizeRangeSuffixes: { }, /* e.g. Flickr configuration 18936 { 18937 100: '_t', // used when longest is less than 100px 18938 240: '_m', // used when longest is between 101px and 240px 18939 320: '_n', // ... 18940 500: '', 18941 640: '_z', 18942 1024: '_b' // used as else case because it is the last 18943 } 18944 */ 18945 thumbnailPath: undefined, /* If defined, sizeRangeSuffixes is not used, and this function is used to determine the 18946 path relative to a specific thumbnail size. The function should accept respectively three arguments: 18947 current path, width and height */ 18948 rowHeight: 120, 18949 maxRowHeight: false, // false or negative value to deactivate. Positive number to express the value in pixels, 18950 // A string '[0-9]+%' to express in percentage (e.g. 300% means that the row height 18951 // can't exceed 3 * rowHeight) 18952 margins: 1, 18953 border: -1, // negative value = same as margins, 0 = disabled, any other value to set the border 18954 18955 lastRow: 'nojustify', // … which is the same as 'left', or can be 'justify', 'center', 'right' or 'hide' 18956 18957 justifyThreshold: 0.90, /* if row width / available space > 0.90 it will be always justified 18958 * (i.e. lastRow setting is not considered) */ 18959 waitThumbnailsLoad: true, 18960 captions: true, 18961 cssAnimation: true, 18962 imagesAnimationDuration: 500, // ignored with css animations 18963 captionSettings: { // ignored with css animations 18964 animationDuration: 500, 18965 visibleOpacity: 0.7, 18966 nonVisibleOpacity: 0.0 18967 },
vendor: 5,759 bytes, lines 18968-19110
18968 rel: null, // rewrite the rel of each analyzed links 18969 target: null, // rewrite the target of all links 18970 extension: /\.[^.\\/]+$/, // regexp to capture the extension of an image 18971 refreshTime: 200, // time interval (in ms) to check if the page changes its width 18972 refreshSensitivity: 0, // change in width allowed (in px) without re-building the gallery 18973 randomize: false, 18974 sort: false, /* 18975 - false: to do not sort 18976 - function: to sort them using the function as comparator (see Array.prototype.sort()) 18977 */ 18978 filter: false, /* 18979 - false, null or undefined: for a disabled filter 18980 - a string: an entry is kept if entry.is(filter string) returns true 18981 see jQuery's .is() function for further information 18982 - a function: invoked with arguments (entry, index, array). Return true to keep the entry, false otherwise. 18983 It follows the specifications of the Array.prototype.filter() function of JavaScript. 18984 */ 18985 selector: 'a, div:not(.spinner)' // The selector that is used to know what are the entries of the gallery 18986 }; 18987 18988}(jQuery)); 18989/*! 18990* Customized version of iScroll.js 0.0.1 18991* It fixes bugs affecting its integration with fullpage.js 18992*/ 18993/*! iScroll v5.2.0 ~ (c) 2008-2016 Matteo Spinelli ~ http://cubiq.org/license */ 18994(function (window, document, Math) { 18995var rAF = window.requestAnimationFrame || 18996 window.webkitRequestAnimationFrame || 18997 window.mozRequestAnimationFrame || 18998 window.oRequestAnimationFrame || 18999 window.msRequestAnimationFrame || 19000 function (callback) { window.setTimeout(callback, 1000 / 60); }; 19001 19002var utils = (function () { 19003 var me = {}; 19004 19005 var _elementStyle = document.createElement('div').style; 19006 var _vendor = (function () { 19007 var vendors = ['t', 'webkitT', 'MozT', 'msT', 'OT'], 19008 transform, 19009 i = 0, 19010 l = vendors.length; 19011 19012 for ( ; i < l; i++ ) { 19013 transform = vendors[i] + 'ransform'; 19014 if ( transform in _elementStyle ) return vendors[i].substr(0, vendors[i].length-1); 19015 } 19016 19017 return false; 19018 })(); 19019 19020 function _prefixStyle (style) { 19021 if ( _vendor === false ) return false; 19022 if ( _vendor === '' ) return style; 19023 return _vendor + style.charAt(0).toUpperCase() + style.substr(1); 19024 } 19025 19026 me.getTime = Date.now || function getTime () { return new Date().getTime(); }; 19027 19028 me.extend = function (target, obj) { 19029 for ( var i in obj ) { 19030 target[i] = obj[i]; 19031 } 19032 }; 19033 19034 me.addEvent = function (el, type, fn, capture) { 19035 el.addEventListener(type, fn, !!capture); 19036 }; 19037 19038 me.removeEvent = function (el, type, fn, capture) { 19039 el.removeEventListener(type, fn, !!capture); 19040 }; 19041 19042 me.prefixPointerEvent = function (pointerEvent) { 19043 return window.MSPointerEvent ? 19044 'MSPointer' + pointerEvent.charAt(7).toUpperCase() + pointerEvent.substr(8): 19045 pointerEvent; 19046 }; 19047 19048 me.momentum = function (current, start, time, lowerMargin, wrapperSize, deceleration) { 19049 var distance = current - start, 19050 speed = Math.abs(distance) / time, 19051 destination, 19052 duration; 19053 19054 deceleration = deceleration === undefined ? 0.0006 : deceleration; 19055 19056 destination = current + ( speed * speed ) / ( 2 * deceleration ) * ( distance < 0 ? -1 : 1 ); 19057 duration = speed / deceleration; 19058 19059 if ( destination < lowerMargin ) { 19060 destination = wrapperSize ? lowerMargin - ( wrapperSize / 2.5 * ( speed / 8 ) ) : lowerMargin; 19061 distance = Math.abs(destination - current); 19062 duration = distance / speed; 19063 } else if ( destination > 0 ) { 19064 destination = wrapperSize ? wrapperSize / 2.5 * ( speed / 8 ) : 0; 19065 distance = Math.abs(current) + destination; 19066 duration = distance / speed; 19067 } 19068 19069 return { 19070 destination: Math.round(destination), 19071 duration: duration 19072 }; 19073 }; 19074 19075 var _transform = _prefixStyle('transform'); 19076 19077 me.extend(me, { 19078 hasTransform: _transform !== false, 19079 hasPerspective: _prefixStyle('perspective') in _elementStyle, 19080 hasTouch: 'ontouchstart' in window, 19081 hasPointer: !!(window.PointerEvent || window.MSPointerEvent), // IE10 is prefixed 19082 hasTransition: _prefixStyle('transition') in _elementStyle 19083 }); 19084 19085 /* 19086 This should find all Android browsers lower than build 535.19 (both stock browser and webview) 19087 - galaxy S2 is ok 19088 - 2.3.6 : `AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1` 19089 - 4.0.4 : `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30` 19090 - galaxy S3 is badAndroid (stock brower, webview) 19091 `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30` 19092 - galaxy S4 is badAndroid (stock brower, webview) 19093 `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30` 19094 - galaxy S5 is OK 19095 `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)` 19096 - galaxy S6 is OK 19097 `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)` 19098 */ 19099 me.isBadAndroid = (function() { 19100 var appVersion = window.navigator.appVersion; 19101 // Android browser is not a chrome browser. 19102 if (/Android/.test(appVersion) && !(/Chrome\/\d/.test(appVersion))) { 19103 var safariVersion = appVersion.match(/Safari\/(\d+.\d)/); 19104 if(safariVersion && typeof safariVersion === "object" && safariVersion.length >= 2) { 19105 return parseFloat(safariVersion[1]) < 535.19; 19106 } else { 19107 return true; 19108 } 19109 } else { 19110 return false;
vendor: 5,536 bytes, lines 19111-19303
19111 } 19112 })(); 19113 19114 me.extend(me.style = {}, { 19115 transform: _transform, 19116 transitionTimingFunction: _prefixStyle('transitionTimingFunction'), 19117 transitionDuration: _prefixStyle('transitionDuration'), 19118 transitionDelay: _prefixStyle('transitionDelay'), 19119 transformOrigin: _prefixStyle('transformOrigin') 19120 }); 19121 19122 me.hasClass = function (e, c) { 19123 var re = new RegExp("(^|\\s)" + c + "(\\s|$)"); 19124 return re.test(e.className); 19125 }; 19126 19127 me.addClass = function (e, c) { 19128 if ( me.hasClass(e, c) ) { 19129 return; 19130 } 19131 19132 var newclass = e.className.split(' '); 19133 newclass.push(c); 19134 e.className = newclass.join(' '); 19135 }; 19136 19137 me.removeClass = function (e, c) { 19138 if ( !me.hasClass(e, c) ) { 19139 return; 19140 } 19141 19142 var re = new RegExp("(^|\\s)" + c + "(\\s|$)", 'g'); 19143 e.className = e.className.replace(re, ' '); 19144 }; 19145 19146 me.offset = function (el) { 19147 var left = -el.offsetLeft, 19148 top = -el.offsetTop; 19149 19150 // jshint -W084 19151 while (el = el.offsetParent) { 19152 left -= el.offsetLeft; 19153 top -= el.offsetTop; 19154 } 19155 // jshint +W084 19156 19157 return { 19158 left: left, 19159 top: top 19160 }; 19161 }; 19162 19163 me.preventDefaultException = function (el, exceptions) { 19164 for ( var i in exceptions ) { 19165 if ( exceptions[i].test(el[i]) ) { 19166 return true; 19167 } 19168 } 19169 19170 return false; 19171 }; 19172 19173 me.extend(me.eventType = {}, { 19174 touchstart: 1, 19175 touchmove: 1, 19176 touchend: 1, 19177 19178 mousedown: 2, 19179 mousemove: 2, 19180 mouseup: 2, 19181 19182 pointerdown: 3, 19183 pointermove: 3, 19184 pointerup: 3, 19185 19186 MSPointerDown: 3, 19187 MSPointerMove: 3, 19188 MSPointerUp: 3 19189 }); 19190 19191 me.extend(me.ease = {}, { 19192 quadratic: { 19193 style: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)', 19194 fn: function (k) { 19195 return k * ( 2 - k ); 19196 } 19197 }, 19198 circular: { 19199 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) 19200 fn: function (k) { 19201 return Math.sqrt( 1 - ( --k * k ) ); 19202 } 19203 }, 19204 back: { 19205 style: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)', 19206 fn: function (k) { 19207 var b = 4; 19208 return ( k = k - 1 ) * k * ( ( b + 1 ) * k + b ) + 1; 19209 } 19210 }, 19211 bounce: { 19212 style: '', 19213 fn: function (k) { 19214 if ( ( k /= 1 ) < ( 1 / 2.75 ) ) { 19215 return 7.5625 * k * k; 19216 } else if ( k < ( 2 / 2.75 ) ) { 19217 return 7.5625 * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75; 19218 } else if ( k < ( 2.5 / 2.75 ) ) { 19219 return 7.5625 * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375; 19220 } else { 19221 return 7.5625 * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375; 19222 } 19223 } 19224 }, 19225 elastic: { 19226 style: '', 19227 fn: function (k) { 19228 var f = 0.22, 19229 e = 0.4; 19230 19231 if ( k === 0 ) { return 0; } 19232 if ( k == 1 ) { return 1; } 19233 19234 return ( e * Math.pow( 2, - 10 * k ) * Math.sin( ( k - f / 4 ) * ( 2 * Math.PI ) / f ) + 1 ); 19235 } 19236 } 19237 }); 19238 19239 me.tap = function (e, eventName) { 19240 var ev = document.createEvent('Event'); 19241 ev.initEvent(eventName, true, true); 19242 ev.pageX = e.pageX; 19243 ev.pageY = e.pageY; 19244 e.target.dispatchEvent(ev); 19245 }; 19246 19247 me.click = function (e) { 19248 var target = e.target, 19249 ev; 19250 19251 if ( !(/(SELECT|INPUT|TEXTAREA)/i).test(target.tagName) ) { 19252 // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/initMouseEvent 19253 // initMouseEvent is deprecated. 19254 ev = document.createEvent(window.MouseEvent ? 'MouseEvents' : 'Event'); 19255 ev.initEvent('click', true, true); 19256 ev.view = e.view || window; 19257 ev.detail = 1; 19258 ev.screenX = target.screenX || 0; 19259 ev.screenY = target.screenY || 0; 19260 ev.clientX = target.clientX || 0; 19261 ev.clientY = target.clientY || 0; 19262 ev.ctrlKey = !!e.ctrlKey; 19263 ev.altKey = !!e.altKey; 19264 ev.shiftKey = !!e.shiftKey; 19265 ev.metaKey = !!e.metaKey; 19266 ev.button = 0; 19267 ev.relatedTarget = null; 19268 ev._constructed = true; 19269 target.dispatchEvent(ev); 19270 } 19271 }; 19272 19273 return me; 19274})(); 19275function IScroll (el, options) { 19276 this.wrapper = typeof el == 'string' ? document.querySelector(el) : el; 19277 this.scroller = this.wrapper.children[0]; 19278 this.scrollerStyle = this.scroller.style; // cache style for better performance 19279 19280 this.options = { 19281 19282 resizeScrollbars: true, 19283 19284 mouseWheelSpeed: 20, 19285 19286 snapThreshold: 0.334, 19287 19288// INSERT POINT: OPTIONS 19289 disablePointer : !utils.hasPointer, 19290 disableTouch : utils.hasPointer || !utils.hasTouch, 19291 disableMouse : utils.hasPointer || utils.hasTouch, 19292 startX: 0, 19293 startY: 0, 19294 scrollY: true, 19295 directionLockThreshold: 5, 19296 momentum: true, 19297 19298 bounce: true, 19299 bounceTime: 600, 19300 bounceEasing: '', 19301 19302 preventDefault: true, 19303 preventDefaultException: { tagName: /^(INPUT|TEXTAREA|BUTTON|
vendor: 4,420 bytes, lines 19303-19447
19303SELECT|LABEL)$/ }, 19304 19305 HWCompositing: true, 19306 useTransition: true, 19307 useTransform: true, 19308 bindToWrapper: typeof window.onmousedown === "undefined" 19309 }; 19310 19311 for ( var i in options ) { 19312 this.options[i] = options[i]; 19313 } 19314 19315 // Normalize options 19316 this.translateZ = this.options.HWCompositing && utils.hasPerspective ? ' translateZ(0)' : ''; 19317 19318 this.options.useTransition = utils.hasTransition && this.options.useTransition; 19319 this.options.useTransform = utils.hasTransform && this.options.useTransform; 19320 19321 this.options.eventPassthrough = this.options.eventPassthrough === true ? 'vertical' : this.options.eventPassthrough; 19322 this.options.preventDefault = !this.options.eventPassthrough && this.options.preventDefault; 19323 19324 // If you want eventPassthrough I have to lock one of the axes 19325 this.options.scrollY = this.options.eventPassthrough == 'vertical' ? false : this.options.scrollY; 19326 this.options.scrollX = this.options.eventPassthrough == 'horizontal' ? false : this.options.scrollX; 19327 19328 // With eventPassthrough we also need lockDirection mechanism 19329 this.options.freeScroll = this.options.freeScroll && !this.options.eventPassthrough; 19330 this.options.directionLockThreshold = this.options.eventPassthrough ? 0 : this.options.directionLockThreshold; 19331 19332 this.options.bounceEasing = typeof this.options.bounceEasing == 'string' ? utils.ease[this.options.bounceEasing] || utils.ease.circular : this.options.bounceEasing; 19333 19334 this.options.resizePolling = this.options.resizePolling === undefined ? 60 : this.options.resizePolling; 19335 19336 if ( this.options.tap === true ) { 19337 this.options.tap = 'tap'; 19338 } 19339 19340 // https://github.com/cubiq/iscroll/issues/1029 19341 if (!this.options.useTransition && !this.options.useTransform) { 19342 if(!(/relative|absolute/i).test(this.scrollerStyle.position)) { 19343 this.scrollerStyle.position = "relative"; 19344 } 19345 } 19346 19347 if ( this.options.shrinkScrollbars == 'scale' ) { 19348 this.options.useTransition = false; 19349 } 19350 19351 this.options.invertWheelDirection = this.options.invertWheelDirection ? -1 : 1; 19352 19353// INSERT POINT: NORMALIZATION 19354 19355 // Some defaults 19356 this.x = 0; 19357 this.y = 0; 19358 this.directionX = 0; 19359 this.directionY = 0; 19360 this._events = {}; 19361 19362// INSERT POINT: DEFAULTS 19363 19364 this._init(); 19365 this.refresh(); 19366 19367 this.scrollTo(this.options.startX, this.options.startY); 19368 this.enable(); 19369} 19370 19371IScroll.prototype = { 19372 version: '5.2.0', 19373 19374 _init: function () { 19375 this._initEvents(); 19376 19377 if ( this.options.scrollbars || this.options.indicators ) { 19378 this._initIndicators(); 19379 } 19380 19381 if ( this.options.mouseWheel ) { 19382 this._initWheel(); 19383 } 19384 19385 if ( this.options.snap ) { 19386 this._initSnap(); 19387 } 19388 19389 if ( this.options.keyBindings ) { 19390 this._initKeys(); 19391 } 19392 19393// INSERT POINT: _init 19394 19395 }, 19396 19397 destroy: function () { 19398 this._initEvents(true); 19399 clearTimeout(this.resizeTimeout); 19400 this.resizeTimeout = null; 19401 this._execEvent('destroy'); 19402 }, 19403 19404 _transitionEnd: function (e) { 19405 if ( e.target != this.scroller || !this.isInTransition ) { 19406 return; 19407 } 19408 19409 this._transitionTime(); 19410 if ( !this.resetPosition(this.options.bounceTime) ) { 19411 this.isInTransition = false; 19412 this._execEvent('scrollEnd'); 19413 } 19414 }, 19415 19416 _start: function (e) { 19417 // React to left mouse button only 19418 if ( utils.eventType[e.type] != 1 ) { 19419 // for button property 19420 // http://unixpapa.com/js/mouse.html 19421 var button; 19422 if (!e.which) { 19423 /* IE case */ 19424 button = (e.button < 2) ? 0 : 19425 ((e.button == 4) ? 1 : 2); 19426 } else { 19427 /* All others */ 19428 button = e.button; 19429 } 19430 if ( button !== 0 ) { 19431 return; 19432 } 19433 } 19434 19435 if ( !this.enabled || (this.initiated && utils.eventType[e.type] !== this.initiated) ) { 19436 return; 19437 } 19438 19439 if ( this.options.preventDefault && !utils.isBadAndroid && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) { 19440 e.preventDefault(); 19441 } 19442 19443 var point = e.touches ? e.touches[0] : e, 19444 pos; 19445 19446 this.initiated = utils.eventType[e.type]; 19447 this.moved = false;
vendor: 5,928 bytes, lines 19448-19626
19448 this.distX = 0; 19449 this.distY = 0; 19450 this.directionX = 0; 19451 this.directionY = 0; 19452 this.directionLocked = 0; 19453 19454 this.startTime = utils.getTime(); 19455 19456 if ( this.options.useTransition && this.isInTransition ) { 19457 this._transitionTime(); 19458 this.isInTransition = false; 19459 pos = this.getComputedPosition(); 19460 this._translate(Math.round(pos.x), Math.round(pos.y)); 19461 this._execEvent('scrollEnd'); 19462 } else if ( !this.options.useTransition && this.isAnimating ) { 19463 this.isAnimating = false; 19464 this._execEvent('scrollEnd'); 19465 } 19466 19467 this.startX = this.x; 19468 this.startY = this.y; 19469 this.absStartX = this.x; 19470 this.absStartY = this.y; 19471 this.pointX = point.pageX; 19472 this.pointY = point.pageY; 19473 19474 this._execEvent('beforeScrollStart'); 19475 }, 19476 19477 _move: function (e) { 19478 if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) { 19479 return; 19480 } 19481 19482 if ( this.options.preventDefault ) { // increases performance on Android? TODO: check! 19483 e.preventDefault(); 19484 } 19485 19486 var point = e.touches ? e.touches[0] : e, 19487 deltaX = point.pageX - this.pointX, 19488 deltaY = point.pageY - this.pointY, 19489 timestamp = utils.getTime(), 19490 newX, newY, 19491 absDistX, absDistY; 19492 19493 this.pointX = point.pageX; 19494 this.pointY = point.pageY; 19495 19496 this.distX += deltaX; 19497 this.distY += deltaY; 19498 absDistX = Math.abs(this.distX); 19499 absDistY = Math.abs(this.distY); 19500 19501 // We need to move at least 10 pixels for the scrolling to initiate 19502 if ( timestamp - this.endTime > 300 && (absDistX < 10 && absDistY < 10) ) { 19503 return; 19504 } 19505 19506 // If you are scrolling in one direction lock the other 19507 if ( !this.directionLocked && !this.options.freeScroll ) { 19508 if ( absDistX > absDistY + this.options.directionLockThreshold ) { 19509 this.directionLocked = 'h'; // lock horizontally 19510 } else if ( absDistY >= absDistX + this.options.directionLockThreshold ) { 19511 this.directionLocked = 'v'; // lock vertically 19512 } else { 19513 this.directionLocked = 'n'; // no lock 19514 } 19515 } 19516 19517 if ( this.directionLocked == 'h' ) { 19518 if ( this.options.eventPassthrough == 'vertical' ) { 19519 e.preventDefault(); 19520 } else if ( this.options.eventPassthrough == 'horizontal' ) { 19521 this.initiated = false; 19522 return; 19523 } 19524 19525 deltaY = 0; 19526 } else if ( this.directionLocked == 'v' ) { 19527 if ( this.options.eventPassthrough == 'horizontal' ) { 19528 e.preventDefault(); 19529 } else if ( this.options.eventPassthrough == 'vertical' ) { 19530 this.initiated = false; 19531 return; 19532 } 19533 19534 deltaX = 0; 19535 } 19536 19537 deltaX = this.hasHorizontalScroll ? deltaX : 0; 19538 deltaY = this.hasVerticalScroll ? deltaY : 0; 19539 19540 newX = this.x + deltaX; 19541 newY = this.y + deltaY; 19542 19543 // Slow down if outside of the boundaries 19544 if ( newX > 0 || newX < this.maxScrollX ) { 19545 newX = this.options.bounce ? this.x + deltaX / 3 : newX > 0 ? 0 : this.maxScrollX; 19546 } 19547 if ( newY > 0 || newY < this.maxScrollY ) { 19548 newY = this.options.bounce ? this.y + deltaY / 3 : newY > 0 ? 0 : this.maxScrollY; 19549 } 19550 19551 this.directionX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0; 19552 this.directionY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0; 19553 19554 if ( !this.moved ) { 19555 this._execEvent('scrollStart'); 19556 } 19557 19558 this.moved = true; 19559 19560 this._translate(newX, newY); 19561 19562/* REPLACE START: _move */ 19563 19564 if ( timestamp - this.startTime > 300 ) { 19565 this.startTime = timestamp; 19566 this.startX = this.x; 19567 this.startY = this.y; 19568 } 19569 19570/* REPLACE END: _move */ 19571 19572 }, 19573 19574 _end: function (e) { 19575 if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) { 19576 return; 19577 } 19578 19579 if ( this.options.preventDefault && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) { 19580 e.preventDefault(); 19581 } 19582 19583 var point = e.changedTouches ? e.changedTouches[0] : e, 19584 momentumX, 19585 momentumY, 19586 duration = utils.getTime() - this.startTime, 19587 newX = Math.round(this.x), 19588 newY = Math.round(this.y), 19589 distanceX = Math.abs(newX - this.startX), 19590 distanceY = Math.abs(newY - this.startY), 19591 time = 0, 19592 easing = ''; 19593 19594 this.isInTransition = 0; 19595 this.initiated = 0; 19596 this.endTime = utils.getTime(); 19597 19598 // reset if we are outside of the boundaries 19599 if ( this.resetPosition(this.options.bounceTime) ) { 19600 return; 19601 } 19602 19603 this.scrollTo(newX, newY); // ensures that the last position is rounded 19604 19605 // we scrolled less than 10 pixels 19606 if ( !this.moved ) { 19607 if ( this.options.tap ) { 19608 utils.tap(e, this.options.tap); 19609 } 19610 19611 if ( this.options.click ) { 19612 utils.click(e); 19613 } 19614 19615 this._execEvent('scrollCancel'); 19616 return; 19617 } 19618 19619 if ( this._events.flick && duration < 200 && distanceX < 100 && distanceY < 100 ) { 19620 this._execEvent('flick'); 19621 return; 19622 } 19623 19624 // start momentum animation if needed 19625 if ( this.options.momentum && duration < 300 ) { 19626 momentumX = this.hasHorizontalScroll ? utils.momentum(this.x, this.startX, duration, this.maxScrollX, this.options.bounce ? this.wrapperW
vendor: 7,740 bytes, lines 19626-19899
19626idth : 0, this.options.deceleration) : { destination: newX, duration: 0 }; 19627 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 }; 19628 newX = momentumX.destination; 19629 newY = momentumY.destination; 19630 time = Math.max(momentumX.duration, momentumY.duration); 19631 this.isInTransition = 1; 19632 } 19633 19634 19635 if ( this.options.snap ) { 19636 var snap = this._nearestSnap(newX, newY); 19637 this.currentPage = snap; 19638 time = this.options.snapSpeed || Math.max( 19639 Math.max( 19640 Math.min(Math.abs(newX - snap.x), 1000), 19641 Math.min(Math.abs(newY - snap.y), 1000) 19642 ), 300); 19643 newX = snap.x; 19644 newY = snap.y; 19645 19646 this.directionX = 0; 19647 this.directionY = 0; 19648 easing = this.options.bounceEasing; 19649 } 19650 19651// INSERT POINT: _end 19652 19653 if ( newX != this.x || newY != this.y ) { 19654 // change easing function when scroller goes out of the boundaries 19655 if ( newX > 0 || newX < this.maxScrollX || newY > 0 || newY < this.maxScrollY ) { 19656 easing = utils.ease.quadratic; 19657 } 19658 19659 this.scrollTo(newX, newY, time, easing); 19660 return; 19661 } 19662 19663 this._execEvent('scrollEnd'); 19664 }, 19665 19666 _resize: function () { 19667 var that = this; 19668 19669 clearTimeout(this.resizeTimeout); 19670 19671 this.resizeTimeout = setTimeout(function () { 19672 that.refresh(); 19673 }, this.options.resizePolling); 19674 }, 19675 19676 resetPosition: function (time) { 19677 var x = this.x, 19678 y = this.y; 19679 19680 time = time || 0; 19681 19682 if ( !this.hasHorizontalScroll || this.x > 0 ) { 19683 x = 0; 19684 } else if ( this.x < this.maxScrollX ) { 19685 x = this.maxScrollX; 19686 } 19687 19688 if ( !this.hasVerticalScroll || this.y > 0 ) { 19689 y = 0; 19690 } else if ( this.y < this.maxScrollY ) { 19691 y = this.maxScrollY; 19692 } 19693 19694 if ( x == this.x && y == this.y ) { 19695 return false; 19696 } 19697 19698 this.scrollTo(x, y, time, this.options.bounceEasing); 19699 19700 return true; 19701 }, 19702 19703 disable: function () { 19704 this.enabled = false; 19705 }, 19706 19707 enable: function () { 19708 this.enabled = true; 19709 }, 19710 19711 refresh: function () { 19712 var rf = this.wrapper.offsetHeight; // Force reflow 19713 19714 this.wrapperWidth = this.wrapper.clientWidth; 19715 this.wrapperHeight = this.wrapper.clientHeight; 19716 19717/* REPLACE START: refresh */ 19718 19719 this.scrollerWidth = this.scroller.offsetWidth; 19720 this.scrollerHeight = this.scroller.offsetHeight; 19721 19722 this.maxScrollX = this.wrapperWidth - this.scrollerWidth; 19723 this.maxScrollY = this.wrapperHeight - this.scrollerHeight; 19724 19725/* REPLACE END: refresh */ 19726 19727 this.hasHorizontalScroll = this.options.scrollX && this.maxScrollX < 0; 19728 this.hasVerticalScroll = this.options.scrollY && this.maxScrollY < 0; 19729 19730 if ( !this.hasHorizontalScroll ) { 19731 this.maxScrollX = 0; 19732 this.scrollerWidth = this.wrapperWidth; 19733 } 19734 19735 if ( !this.hasVerticalScroll ) { 19736 this.maxScrollY = 0; 19737 this.scrollerHeight = this.wrapperHeight; 19738 } 19739 19740 this.endTime = 0; 19741 this.directionX = 0; 19742 this.directionY = 0; 19743 19744 this.wrapperOffset = utils.offset(this.wrapper); 19745 19746 this._execEvent('refresh'); 19747 19748 this.resetPosition(); 19749 19750// INSERT POINT: _refresh 19751 19752 }, 19753 19754 on: function (type, fn) { 19755 if ( !this._events[type] ) { 19756 this._events[type] = []; 19757 } 19758 19759 this._events[type].push(fn); 19760 }, 19761 19762 off: function (type, fn) { 19763 if ( !this._events[type] ) { 19764 return; 19765 } 19766 19767 var index = this._events[type].indexOf(fn); 19768 19769 if ( index > -1 ) { 19770 this._events[type].splice(index, 1); 19771 } 19772 }, 19773 19774 _execEvent: function (type) { 19775 if ( !this._events[type] ) { 19776 return; 19777 } 19778 19779 var i = 0, 19780 l = this._events[type].length; 19781 19782 if ( !l ) { 19783 return; 19784 } 19785 19786 for ( ; i < l; i++ ) { 19787 this._events[type][i].apply(this, [].slice.call(arguments, 1)); 19788 } 19789 }, 19790 19791 scrollBy: function (x, y, time, easing) { 19792 x = this.x + x; 19793 y = this.y + y; 19794 time = time || 0; 19795 19796 this.scrollTo(x, y, time, easing); 19797 }, 19798 19799 scrollTo: function (x, y, time, easing) { 19800 easing = easing || utils.ease.circular; 19801 19802 this.isInTransition = this.options.useTransition && time > 0; 19803 var transitionType = this.options.useTransition && easing.style; 19804 if ( !time || transitionType ) { 19805 if(transitionType) { 19806 this._transitionTimingFunction(easing.style); 19807 this._transitionTime(time); 19808 } 19809 this._translate(x, y); 19810 } else { 19811 this._animate(x, y, time, easing.fn); 19812 } 19813 }, 19814 19815 scrollToElement: function (el, time, offsetX, offsetY, easing) { 19816 el = el.nodeType ? el : this.scroller.querySelector(el); 19817 19818 if ( !el ) { 19819 return; 19820 } 19821 19822 var pos = utils.offset(el); 19823 19824 pos.left -= this.wrapperOffset.left; 19825 pos.top -= this.wrapperOffset.top; 19826 19827 // if offsetX/Y are true we center the element to the screen 19828 if ( offsetX === true ) { 19829 offsetX = Math.round(el.offsetWidth / 2 - this.wrapper.offsetWidth / 2); 19830 } 19831 if ( offsetY === true ) { 19832 offsetY = Math.round(el.offsetHeight / 2 - this.wrapper.offsetHeight / 2); 19833 } 19834 19835 pos.left -= offsetX || 0; 19836 pos.top -= offsetY || 0; 19837 19838 pos.left = pos.left > 0 ? 0 : pos.left < this.maxScrollX ? this.maxScrollX : pos.left; 19839 pos.top = pos.top > 0 ? 0 : pos.top < this.maxScrollY ? this.maxScrollY : pos.top; 19840 19841 time = time === undefined || time === null || time === 'auto' ? Math.max(Math.abs(this.x-pos.left), Math.abs(this.y-pos.top)) : time; 19842 19843 this.scrollTo(pos.left, pos.top, time, easing); 19844 }, 19845 19846 _transitionTime: function (time) { 19847 if (!this.options.useTransition) { 19848 return; 19849 } 19850 time = time || 0; 19851 var durationProp = utils.style.transitionDuration; 19852 if(!durationProp) { 19853 return; 19854 } 19855 19856 this.scrollerStyle[durationProp] = time + 'ms'; 19857 19858 if ( !time && utils.isBadAndroid ) { 19859 this.scrollerStyle[durationProp] = '0.0001ms'; 19860 // remove 0.0001ms 19861 var self = this; 19862 rAF(function() { 19863 if(self.scrollerStyle[durationProp] === '0.0001ms') { 19864 self.scrollerStyle[durationProp] = '0s'; 19865 } 19866 }); 19867 } 19868 19869 19870 if ( this.indicators ) { 19871 for ( var i = this.indicators.length; i--; ) { 19872 this.indicators[i].transitionTime(time); 19873 } 19874 } 19875 19876 19877// INSERT POINT: _transitionTime 19878 19879 }, 19880 19881 _transitionTimingFunction: function (easing) { 19882 this.scrollerStyle[utils.style.transitionTimingFunction] = easing; 19883 19884 19885 if ( this.indicators ) { 19886 for ( var i = this.indicators.length; i--; ) { 19887 this.indicators[i].transitionTimingFunction(easing); 19888 } 19889 } 19890 19891 19892// INSERT POINT: _transitionTimingFunction 19893 19894 }, 19895 19896 _translate: function (x, y) { 19897 //Uncode addition 19898 if ( (" " + this.wrapper.className + " ").replace(/[\n\t]/g, " ").indexOf(" no-scrolloverflow ") > -1 ) 19899 return false;
vendor: 9,939 bytes, lines 19900-20211
19900 19901 if ( this.options.useTransform ) { 19902 19903/* REPLACE START: _translate */ 19904 19905 this.scrollerStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.translateZ; 19906 19907/* REPLACE END: _translate */ 19908 19909 } else { 19910 x = Math.round(x); 19911 y = Math.round(y); 19912 this.scrollerStyle.left = x + 'px'; 19913 this.scrollerStyle.top = y + 'px'; 19914 } 19915 19916 this.x = x; 19917 this.y = y; 19918 19919 19920 if ( this.indicators ) { 19921 for ( var i = this.indicators.length; i--; ) { 19922 this.indicators[i].updatePosition(); 19923 } 19924 } 19925 19926 //Uncode addition 19927 var uncodevent = new CustomEvent('fp-slide-scroll'); 19928 window.dispatchEvent(uncodevent); 19929 19930// INSERT POINT: _translate 19931 19932 }, 19933 19934 _initEvents: function (remove) { 19935 var eventType = remove ? utils.removeEvent : utils.addEvent, 19936 target = this.options.bindToWrapper ? this.wrapper : window; 19937 19938 eventType(window, 'orientationchange', this); 19939 eventType(window, 'resize', this); 19940 19941 if ( this.options.click ) { 19942 eventType(this.wrapper, 'click', this, true); 19943 } 19944 19945 if ( !this.options.disableMouse ) { 19946 eventType(this.wrapper, 'mousedown', this); 19947 eventType(target, 'mousemove', this); 19948 eventType(target, 'mousecancel', this); 19949 eventType(target, 'mouseup', this); 19950 } 19951 19952 if ( utils.hasPointer && !this.options.disablePointer ) { 19953 eventType(this.wrapper, utils.prefixPointerEvent('pointerdown'), this); 19954 eventType(target, utils.prefixPointerEvent('pointermove'), this); 19955 eventType(target, utils.prefixPointerEvent('pointercancel'), this); 19956 eventType(target, utils.prefixPointerEvent('pointerup'), this); 19957 } 19958 19959 if ( utils.hasTouch && !this.options.disableTouch ) { 19960 eventType(this.wrapper, 'touchstart', this); 19961 eventType(target, 'touchmove', this); 19962 eventType(target, 'touchcancel', this); 19963 eventType(target, 'touchend', this); 19964 } 19965 19966 eventType(this.scroller, 'transitionend', this); 19967 eventType(this.scroller, 'webkitTransitionEnd', this); 19968 eventType(this.scroller, 'oTransitionEnd', this); 19969 eventType(this.scroller, 'MSTransitionEnd', this); 19970 }, 19971 19972 getComputedPosition: function () { 19973 var matrix = window.getComputedStyle(this.scroller, null), 19974 x, y; 19975 19976 if ( this.options.useTransform ) { 19977 matrix = matrix[utils.style.transform].split(')')[0].split(', '); 19978 x = +(matrix[12] || matrix[4]); 19979 y = +(matrix[13] || matrix[5]); 19980 } else { 19981 x = +matrix.left.replace(/[^-\d.]/g, ''); 19982 y = +matrix.top.replace(/[^-\d.]/g, ''); 19983 } 19984 19985 return { x: x, y: y }; 19986 }, 19987 _initIndicators: function () { 19988 var interactive = this.options.interactiveScrollbars, 19989 customStyle = typeof this.options.scrollbars != 'string', 19990 indicators = [], 19991 indicator; 19992 19993 var that = this; 19994 19995 this.indicators = []; 19996 19997 if ( this.options.scrollbars ) { 19998 // Vertical scrollbar 19999 if ( this.options.scrollY ) { 20000 indicator = { 20001 el: createDefaultScrollbar('v', interactive, this.options.scrollbars), 20002 interactive: interactive, 20003 defaultScrollbars: true, 20004 customStyle: customStyle, 20005 resize: this.options.resizeScrollbars, 20006 shrink: this.options.shrinkScrollbars, 20007 fade: this.options.fadeScrollbars, 20008 listenX: false 20009 }; 20010 20011 this.wrapper.appendChild(indicator.el); 20012 indicators.push(indicator); 20013 } 20014 20015 // Horizontal scrollbar 20016 if ( this.options.scrollX ) { 20017 indicator = { 20018 el: createDefaultScrollbar('h', interactive, this.options.scrollbars), 20019 interactive: interactive, 20020 defaultScrollbars: true, 20021 customStyle: customStyle, 20022 resize: this.options.resizeScrollbars, 20023 shrink: this.options.shrinkScrollbars, 20024 fade: this.options.fadeScrollbars, 20025 listenY: false 20026 }; 20027 20028 this.wrapper.appendChild(indicator.el); 20029 indicators.push(indicator); 20030 } 20031 } 20032 20033 if ( this.options.indicators ) { 20034 // TODO: check concat compatibility 20035 indicators = indicators.concat(this.options.indicators); 20036 } 20037 20038 for ( var i = indicators.length; i--; ) { 20039 this.indicators.push( new Indicator(this, indicators[i]) ); 20040 } 20041 20042 // TODO: check if we can use array.map (wide compatibility and performance issues) 20043 function _indicatorsMap (fn) { 20044 if (that.indicators) { 20045 for ( var i = that.indicators.length; i--; ) { 20046 fn.call(that.indicators[i]); 20047 } 20048 } 20049 } 20050 20051 if ( this.options.fadeScrollbars ) { 20052 this.on('scrollEnd', function () { 20053 _indicatorsMap(function () { 20054 this.fade(); 20055 }); 20056 }); 20057 20058 this.on('scrollCancel', function () { 20059 _indicatorsMap(function () { 20060 this.fade(); 20061 }); 20062 }); 20063 20064 this.on('scrollStart', function () { 20065 _indicatorsMap(function () { 20066 this.fade(1); 20067 }); 20068 }); 20069 20070 this.on('beforeScrollStart', function () { 20071 _indicatorsMap(function () { 20072 this.fade(1, true); 20073 }); 20074 }); 20075 } 20076 20077 20078 this.on('refresh', function () { 20079 _indicatorsMap(function () { 20080 this.refresh(); 20081 }); 20082 }); 20083 20084 this.on('destroy', function () { 20085 _indicatorsMap(function () { 20086 this.destroy(); 20087 }); 20088 20089 delete this.indicators; 20090 }); 20091 }, 20092 20093 _initWheel: function () { 20094 utils.addEvent(this.wrapper, 'wheel', this); 20095 utils.addEvent(this.wrapper, 'mousewheel', this); 20096 utils.addEvent(this.wrapper, 'DOMMouseScroll', this); 20097 20098 this.on('destroy', function () { 20099 clearTimeout(this.wheelTimeout); 20100 this.wheelTimeout = null; 20101 utils.removeEvent(this.wrapper, 'wheel', this); 20102 utils.removeEvent(this.wrapper, 'mousewheel', this); 20103 utils.removeEvent(this.wrapper, 'DOMMouseScroll', this); 20104 }); 20105 }, 20106 20107 _wheel: function (e) { 20108 if ( !this.enabled ) { 20109 return; 20110 } 20111 20112 var wheelDeltaX, wheelDeltaY, 20113 newX, newY, 20114 that = this; 20115 20116 if ( this.wheelTimeout === undefined ) { 20117 that._execEvent('scrollStart'); 20118 } 20119 20120 // Execute the scrollEnd event after 400ms the wheel stopped scrolling 20121 clearTimeout(this.wheelTimeout); 20122 this.wheelTimeout = setTimeout(function () { 20123 if(!that.options.snap) { 20124 that._execEvent('scrollEnd'); 20125 } 20126 that.wheelTimeout = undefined; 20127 }, 400); 20128 20129 if ( 'deltaX' in e ) { 20130 if (e.deltaMode === 1) { 20131 wheelDeltaX = -e.deltaX * this.options.mouseWheelSpeed; 20132 wheelDeltaY = -e.deltaY * this.options.mouseWheelSpeed; 20133 } else { 20134 wheelDeltaX = -e.deltaX; 20135 wheelDeltaY = -e.deltaY; 20136 } 20137 } else if ( 'wheelDeltaX' in e ) { 20138 wheelDeltaX = e.wheelDeltaX / 120 * this.options.mouseWheelSpeed; 20139 wheelDeltaY = e.wheelDeltaY / 120 * this.options.mouseWheelSpeed; 20140 } else if ( 'wheelDelta' in e ) { 20141 wheelDeltaX = wheelDeltaY = e.wheelDelta / 120 * this.options.mouseWheelSpeed; 20142 } else if ( 'detail' in e ) { 20143 wheelDeltaX = wheelDeltaY = -e.detail / 3 * this.options.mouseWheelSpeed; 20144 } else { 20145 return; 20146 } 20147 20148 wheelDeltaX *= this.options.invertWheelDirection; 20149 wheelDeltaY *= this.options.invertWheelDirection; 20150 20151 if ( !this.hasVerticalScroll ) { 20152 wheelDeltaX = wheelDeltaY; 20153 wheelDeltaY = 0; 20154 } 20155 20156 if ( this.options.snap ) { 20157 newX = this.currentPage.pageX; 20158 newY = this.currentPage.pageY; 20159 20160 if ( wheelDeltaX > 0 ) { 20161 newX--; 20162 } else if ( wheelDeltaX < 0 ) { 20163 newX++; 20164 } 20165 20166 if ( wheelDeltaY > 0 ) { 20167 newY--; 20168 } else if ( wheelDeltaY < 0 ) { 20169 newY++; 20170 } 20171 20172 this.goToPage(newX, newY); 20173 20174 return; 20175 } 20176 20177 newX = this.x + Math.round(this.hasHorizontalScroll ? wheelDeltaX : 0); 20178 newY = this.y + Math.round(this.hasVerticalScroll ? wheelDeltaY : 0); 20179 20180 this.directionX = wheelDeltaX > 0 ? -1 : wheelDeltaX < 0 ? 1 : 0; 20181 this.directionY = wheelDeltaY > 0 ? -1 : wheelDeltaY < 0 ? 1 : 0; 20182 20183 if ( newX > 0 ) { 20184 newX = 0; 20185 } else if ( newX < this.maxScrollX ) { 20186 newX = this.maxScrollX; 20187 } 20188 20189 if ( newY > 0 ) { 20190 newY = 0; 20191 } else if ( newY < this.maxScrollY ) { 20192 newY = this.maxScrollY; 20193 } 20194 20195 this.scrollTo(newX, newY, 0); 20196 20197// INSERT POINT: _wheel 20198 }, 20199 20200 _initSnap: function () { 20201 this.currentPage = {}; 20202 20203 if ( typeof this.options.snap == 'string' ) { 20204 this.options.snap = this.scroller.querySelectorAll(this.options.snap); 20205 } 20206 20207 this.on('refresh', function () { 20208 var i = 0, l, 20209 m = 0, n, 20210 cx, cy, 20211 x = 0, y,
vendor: 7,339 bytes, lines 20212-20465
20212 stepX = this.options.snapStepX || this.wrapperWidth, 20213 stepY = this.options.snapStepY || this.wrapperHeight, 20214 el; 20215 20216 this.pages = []; 20217 20218 if ( !this.wrapperWidth || !this.wrapperHeight || !this.scrollerWidth || !this.scrollerHeight ) { 20219 return; 20220 } 20221 20222 if ( this.options.snap === true ) { 20223 cx = Math.round( stepX / 2 ); 20224 cy = Math.round( stepY / 2 ); 20225 20226 while ( x > -this.scrollerWidth ) { 20227 this.pages[i] = []; 20228 l = 0; 20229 y = 0; 20230 20231 while ( y > -this.scrollerHeight ) { 20232 this.pages[i][l] = { 20233 x: Math.max(x, this.maxScrollX), 20234 y: Math.max(y, this.maxScrollY), 20235 width: stepX, 20236 height: stepY, 20237 cx: x - cx, 20238 cy: y - cy 20239 }; 20240 20241 y -= stepY; 20242 l++; 20243 } 20244 20245 x -= stepX; 20246 i++; 20247 } 20248 } else { 20249 el = this.options.snap; 20250 l = el.length; 20251 n = -1; 20252 20253 for ( ; i < l; i++ ) { 20254 if ( i === 0 || el[i].offsetLeft <= el[i-1].offsetLeft ) { 20255 m = 0; 20256 n++; 20257 } 20258 20259 if ( !this.pages[m] ) { 20260 this.pages[m] = []; 20261 } 20262 20263 x = Math.max(-el[i].offsetLeft, this.maxScrollX); 20264 y = Math.max(-el[i].offsetTop, this.maxScrollY); 20265 cx = x - Math.round(el[i].offsetWidth / 2); 20266 cy = y - Math.round(el[i].offsetHeight / 2); 20267 20268 this.pages[m][n] = { 20269 x: x, 20270 y: y, 20271 width: el[i].offsetWidth, 20272 height: el[i].offsetHeight, 20273 cx: cx, 20274 cy: cy 20275 }; 20276 20277 if ( x > this.maxScrollX ) { 20278 m++; 20279 } 20280 } 20281 } 20282 20283 this.goToPage(this.currentPage.pageX || 0, this.currentPage.pageY || 0, 0); 20284 20285 // Update snap threshold if needed 20286 if ( this.options.snapThreshold % 1 === 0 ) { 20287 this.snapThresholdX = this.options.snapThreshold; 20288 this.snapThresholdY = this.options.snapThreshold; 20289 } else { 20290 this.snapThresholdX = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].width * this.options.snapThreshold); 20291 this.snapThresholdY = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].height * this.options.snapThreshold); 20292 } 20293 }); 20294 20295 this.on('flick', function () { 20296 var time = this.options.snapSpeed || Math.max( 20297 Math.max( 20298 Math.min(Math.abs(this.x - this.startX), 1000), 20299 Math.min(Math.abs(this.y - this.startY), 1000) 20300 ), 300); 20301 20302 this.goToPage( 20303 this.currentPage.pageX + this.directionX, 20304 this.currentPage.pageY + this.directionY, 20305 time 20306 ); 20307 }); 20308 }, 20309 20310 _nearestSnap: function (x, y) { 20311 if ( !this.pages.length ) { 20312 return { x: 0, y: 0, pageX: 0, pageY: 0 }; 20313 } 20314 20315 var i = 0, 20316 l = this.pages.length, 20317 m = 0; 20318 20319 // Check if we exceeded the snap threshold 20320 if ( Math.abs(x - this.absStartX) < this.snapThresholdX && 20321 Math.abs(y - this.absStartY) < this.snapThresholdY ) { 20322 return this.currentPage; 20323 } 20324 20325 if ( x > 0 ) { 20326 x = 0; 20327 } else if ( x < this.maxScrollX ) { 20328 x = this.maxScrollX; 20329 } 20330 20331 if ( y > 0 ) { 20332 y = 0; 20333 } else if ( y < this.maxScrollY ) { 20334 y = this.maxScrollY; 20335 } 20336 20337 for ( ; i < l; i++ ) { 20338 if ( x >= this.pages[i][0].cx ) { 20339 x = this.pages[i][0].x; 20340 break; 20341 } 20342 } 20343 20344 l = this.pages[i].length; 20345 20346 for ( ; m < l; m++ ) { 20347 if ( y >= this.pages[0][m].cy ) { 20348 y = this.pages[0][m].y; 20349 break; 20350 } 20351 } 20352 20353 if ( i == this.currentPage.pageX ) { 20354 i += this.directionX; 20355 20356 if ( i < 0 ) { 20357 i = 0; 20358 } else if ( i >= this.pages.length ) { 20359 i = this.pages.length - 1; 20360 } 20361 20362 x = this.pages[i][0].x; 20363 } 20364 20365 if ( m == this.currentPage.pageY ) { 20366 m += this.directionY; 20367 20368 if ( m < 0 ) { 20369 m = 0; 20370 } else if ( m >= this.pages[0].length ) { 20371 m = this.pages[0].length - 1; 20372 } 20373 20374 y = this.pages[0][m].y; 20375 } 20376 20377 return { 20378 x: x, 20379 y: y, 20380 pageX: i, 20381 pageY: m 20382 }; 20383 }, 20384 20385 goToPage: function (x, y, time, easing) { 20386 easing = easing || this.options.bounceEasing; 20387 20388 if ( x >= this.pages.length ) { 20389 x = this.pages.length - 1; 20390 } else if ( x < 0 ) { 20391 x = 0; 20392 } 20393 20394 if ( y >= this.pages[x].length ) { 20395 y = this.pages[x].length - 1; 20396 } else if ( y < 0 ) { 20397 y = 0; 20398 } 20399 20400 var posX = this.pages[x][y].x, 20401 posY = this.pages[x][y].y; 20402 20403 time = time === undefined ? this.options.snapSpeed || Math.max( 20404 Math.max( 20405 Math.min(Math.abs(posX - this.x), 1000), 20406 Math.min(Math.abs(posY - this.y), 1000) 20407 ), 300) : time; 20408 20409 this.currentPage = { 20410 x: posX, 20411 y: posY, 20412 pageX: x, 20413 pageY: y 20414 }; 20415 20416 this.scrollTo(posX, posY, time, easing); 20417 }, 20418 20419 next: function (time, easing) { 20420 var x = this.currentPage.pageX, 20421 y = this.currentPage.pageY; 20422 20423 x++; 20424 20425 if ( x >= this.pages.length && this.hasVerticalScroll ) { 20426 x = 0; 20427 y++; 20428 } 20429 20430 this.goToPage(x, y, time, easing); 20431 }, 20432 20433 prev: function (time, easing) { 20434 var x = this.currentPage.pageX, 20435 y = this.currentPage.pageY; 20436 20437 x--; 20438 20439 if ( x < 0 && this.hasVerticalScroll ) { 20440 x = 0; 20441 y--; 20442 } 20443 20444 this.goToPage(x, y, time, easing); 20445 }, 20446 20447 _initKeys: function (e) { 20448 // default key bindings 20449 var keys = { 20450 pageUp: 33, 20451 pageDown: 34, 20452 end: 35, 20453 home: 36, 20454 left: 37, 20455 up: 38, 20456 right: 39, 20457 down: 40 20458 }; 20459 var i; 20460 20461 // if you give me characters I give you keycode 20462 if ( typeof this.options.keyBindings == 'object' ) { 20463 for ( i in this.options.keyBindings ) { 20464 if ( typeof this.options.keyBindings[i] == 'string' ) { 20465 this.options.keyBindings[i] = this.options.keyBindings[i].toUpperCase().charCo
vendor: 11,097 bytes, lines 20465-20818
20465deAt(0); 20466 } 20467 } 20468 } else { 20469 this.options.keyBindings = {}; 20470 } 20471 20472 for ( i in keys ) { 20473 this.options.keyBindings[i] = this.options.keyBindings[i] || keys[i]; 20474 } 20475 20476 utils.addEvent(window, 'keydown', this); 20477 20478 this.on('destroy', function () { 20479 utils.removeEvent(window, 'keydown', this); 20480 }); 20481 }, 20482 20483 _key: function (e) { 20484 if ( !this.enabled ) { 20485 return; 20486 } 20487 20488 var snap = this.options.snap, // we are using this alot, better to cache it 20489 newX = snap ? this.currentPage.pageX : this.x, 20490 newY = snap ? this.currentPage.pageY : this.y, 20491 now = utils.getTime(), 20492 prevTime = this.keyTime || 0, 20493 acceleration = 0.250, 20494 pos; 20495 20496 if ( this.options.useTransition && this.isInTransition ) { 20497 pos = this.getComputedPosition(); 20498 20499 this._translate(Math.round(pos.x), Math.round(pos.y)); 20500 this.isInTransition = false; 20501 } 20502 20503 this.keyAcceleration = now - prevTime < 200 ? Math.min(this.keyAcceleration + acceleration, 50) : 0; 20504 20505 switch ( e.keyCode ) { 20506 case this.options.keyBindings.pageUp: 20507 if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) { 20508 newX += snap ? 1 : this.wrapperWidth; 20509 } else { 20510 newY += snap ? 1 : this.wrapperHeight; 20511 } 20512 break; 20513 case this.options.keyBindings.pageDown: 20514 if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) { 20515 newX -= snap ? 1 : this.wrapperWidth; 20516 } else { 20517 newY -= snap ? 1 : this.wrapperHeight; 20518 } 20519 break; 20520 case this.options.keyBindings.end: 20521 newX = snap ? this.pages.length-1 : this.maxScrollX; 20522 newY = snap ? this.pages[0].length-1 : this.maxScrollY; 20523 break; 20524 case this.options.keyBindings.home: 20525 newX = 0; 20526 newY = 0; 20527 break; 20528 case this.options.keyBindings.left: 20529 newX += snap ? -1 : 5 + this.keyAcceleration>>0; 20530 break; 20531 case this.options.keyBindings.up: 20532 newY += snap ? 1 : 5 + this.keyAcceleration>>0; 20533 break; 20534 case this.options.keyBindings.right: 20535 newX -= snap ? -1 : 5 + this.keyAcceleration>>0; 20536 break; 20537 case this.options.keyBindings.down: 20538 newY -= snap ? 1 : 5 + this.keyAcceleration>>0; 20539 break; 20540 default: 20541 return; 20542 } 20543 20544 if ( snap ) { 20545 this.goToPage(newX, newY); 20546 return; 20547 } 20548 20549 if ( newX > 0 ) { 20550 newX = 0; 20551 this.keyAcceleration = 0; 20552 } else if ( newX < this.maxScrollX ) { 20553 newX = this.maxScrollX; 20554 this.keyAcceleration = 0; 20555 } 20556 20557 if ( newY > 0 ) { 20558 newY = 0; 20559 this.keyAcceleration = 0; 20560 } else if ( newY < this.maxScrollY ) { 20561 newY = this.maxScrollY; 20562 this.keyAcceleration = 0; 20563 } 20564 20565 this.scrollTo(newX, newY, 0); 20566 20567 this.keyTime = now; 20568 }, 20569 20570 _animate: function (destX, destY, duration, easingFn) { 20571 var that = this, 20572 startX = this.x, 20573 startY = this.y, 20574 startTime = utils.getTime(), 20575 destTime = startTime + duration; 20576 20577 function step () { 20578 var now = utils.getTime(), 20579 newX, newY, 20580 easing; 20581 20582 if ( now >= destTime ) { 20583 that.isAnimating = false; 20584 that._translate(destX, destY); 20585 20586 if ( !that.resetPosition(that.options.bounceTime) ) { 20587 that._execEvent('scrollEnd'); 20588 } 20589 20590 return; 20591 } 20592 20593 now = ( now - startTime ) / duration; 20594 easing = easingFn(now); 20595 newX = ( destX - startX ) * easing + startX; 20596 newY = ( destY - startY ) * easing + startY; 20597 that._translate(newX, newY); 20598 20599 if ( that.isAnimating ) { 20600 rAF(step); 20601 } 20602 } 20603 20604 this.isAnimating = true; 20605 step(); 20606 }, 20607 handleEvent: function (e) { 20608 switch ( e.type ) { 20609 case 'touchstart': 20610 case 'pointerdown': 20611 case 'MSPointerDown': 20612 case 'mousedown': 20613 this._start(e); 20614 break; 20615 case 'touchmove': 20616 case 'pointermove': 20617 case 'MSPointerMove': 20618 case 'mousemove': 20619 this._move(e); 20620 break; 20621 case 'touchend': 20622 case 'pointerup': 20623 case 'MSPointerUp': 20624 case 'mouseup': 20625 case 'touchcancel': 20626 case 'pointercancel': 20627 case 'MSPointerCancel': 20628 case 'mousecancel': 20629 this._end(e); 20630 break; 20631 case 'orientationchange': 20632 case 'resize': 20633 this._resize(); 20634 break; 20635 case 'transitionend': 20636 case 'webkitTransitionEnd': 20637 case 'oTransitionEnd': 20638 case 'MSTransitionEnd': 20639 this._transitionEnd(e); 20640 break; 20641 case 'wheel': 20642 case 'DOMMouseScroll': 20643 case 'mousewheel': 20644 this._wheel(e); 20645 break; 20646 case 'keydown': 20647 this._key(e); 20648 break; 20649 case 'click': 20650 if ( this.enabled && !e._constructed ) { 20651 e.preventDefault(); 20652 e.stopPropagation(); 20653 } 20654 break; 20655 } 20656 } 20657}; 20658function createDefaultScrollbar (direction, interactive, type) { 20659 var scrollbar = document.createElement('div'), 20660 indicator = document.createElement('div'); 20661 20662 if ( type === true ) { 20663 scrollbar.style.cssText = 'position:absolute;z-index:9999'; 20664 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'; 20665 } 20666 20667 indicator.className = 'iScrollIndicator'; 20668 20669 if ( direction == 'h' ) { 20670 if ( type === true ) { 20671 scrollbar.style.cssText += ';height:7px;left:2px;right:2px;bottom:0'; 20672 indicator.style.height = '100%'; 20673 } 20674 scrollbar.className = 'iScrollHorizontalScrollbar'; 20675 } else { 20676 if ( type === true ) { 20677 scrollbar.style.cssText += ';width:7px;bottom:2px;top:2px;right:1px'; 20678 indicator.style.width = '100%'; 20679 } 20680 scrollbar.className = 'iScrollVerticalScrollbar'; 20681 } 20682 20683 scrollbar.style.cssText += ';overflow:hidden'; 20684 20685 if ( !interactive ) { 20686 scrollbar.style.pointerEvents = 'none'; 20687 } 20688 20689 scrollbar.appendChild(indicator); 20690 20691 return scrollbar; 20692} 20693 20694function Indicator (scroller, options) { 20695 this.wrapper = typeof options.el == 'string' ? document.querySelector(options.el) : options.el; 20696 this.wrapperStyle = this.wrapper.style; 20697 this.indicator = this.wrapper.children[0]; 20698 this.indicatorStyle = this.indicator.style; 20699 this.scroller = scroller; 20700 20701 this.options = { 20702 listenX: true, 20703 listenY: true, 20704 interactive: false, 20705 resize: true, 20706 defaultScrollbars: false, 20707 shrink: false, 20708 fade: false, 20709 speedRatioX: 0, 20710 speedRatioY: 0 20711 }; 20712 20713 for ( var i in options ) { 20714 this.options[i] = options[i]; 20715 } 20716 20717 this.sizeRatioX = 1; 20718 this.sizeRatioY = 1; 20719 this.maxPosX = 0; 20720 this.maxPosY = 0; 20721 20722 if ( this.options.interactive ) { 20723 if ( !this.options.disableTouch ) { 20724 utils.addEvent(this.indicator, 'touchstart', this); 20725 utils.addEvent(window, 'touchend', this); 20726 } 20727 if ( !this.options.disablePointer ) { 20728 utils.addEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this); 20729 utils.addEvent(window, utils.prefixPointerEvent('pointerup'), this); 20730 } 20731 if ( !this.options.disableMouse ) { 20732 utils.addEvent(this.indicator, 'mousedown', this); 20733 utils.addEvent(window, 'mouseup', this); 20734 } 20735 } 20736 20737 if ( this.options.fade ) { 20738 this.wrapperStyle[utils.style.transform] = this.scroller.translateZ; 20739 var durationProp = utils.style.transitionDuration; 20740 if(!durationProp) { 20741 return; 20742 } 20743 this.wrapperStyle[durationProp] = utils.isBadAndroid ? '0.0001ms' : '0ms'; 20744 // remove 0.0001ms 20745 var self = this; 20746 if(utils.isBadAndroid) { 20747 rAF(function() { 20748 if(self.wrapperStyle[durationProp] === '0.0001ms') { 20749 self.wrapperStyle[durationProp] = '0s'; 20750 } 20751 }); 20752 } 20753 this.wrapperStyle.opacity = '0'; 20754 } 20755} 20756 20757Indicator.prototype = { 20758 handleEvent: function (e) { 20759 switch ( e.type ) { 20760 case 'touchstart': 20761 case 'pointerdown': 20762 case 'MSPointerDown': 20763 case 'mousedown': 20764 this._start(e); 20765 break; 20766 case 'touchmove': 20767 case 'pointermove': 20768 case 'MSPointerMove': 20769 case 'mousemove': 20770 this._move(e); 20771 break; 20772 case 'touchend': 20773 case 'pointerup': 20774 case 'MSPointerUp': 20775 case 'mouseup': 20776 case 'touchcancel': 20777 case 'pointercancel': 20778 case 'MSPointerCancel': 20779 case 'mousecancel': 20780 this._end(e); 20781 break; 20782 } 20783 }, 20784 20785 destroy: function () { 20786 if ( this.options.fadeScrollbars ) { 20787 clearTimeout(this.fadeTimeout); 20788 this.fadeTimeout = null; 20789 } 20790 if ( this.options.interactive ) { 20791 utils.removeEvent(this.indicator, 'touchstart', this); 20792 utils.removeEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this); 20793 utils.removeEvent(this.indicator, 'mousedown', this); 20794 20795 utils.removeEvent(window, 'touchmove', this); 20796 utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this); 20797 utils.removeEvent(window, 'mousemove', this); 20798 20799 utils.removeEvent(window, 'touchend', this); 20800 utils.removeEvent(window, utils.prefixPointerEvent('pointerup'), this); 20801 utils.removeEvent(window, 'mouseup', this); 20802 } 20803 20804 if ( this.options.defaultScrollbars ) { 20805 this.wrapper.parentNode.removeChild(this.wrapper); 20806 } 20807 }, 20808 20809 _start: function (e) { 20810 var point = e.touches ? e.touches[0] : e; 20811 20812 e.preventDefault(); 20813 e.stopPropagation(); 20814 20815 this.transitionTime(); 20816 20817 this.initiated = true; 20818 this.moved = false;
vendor: 9,615 bytes, lines 20819-21077
20819 this.lastPointX = point.pageX; 20820 this.lastPointY = point.pageY; 20821 20822 this.startTime = utils.getTime(); 20823 20824 if ( !this.options.disableTouch ) { 20825 utils.addEvent(window, 'touchmove', this); 20826 } 20827 if ( !this.options.disablePointer ) { 20828 utils.addEvent(window, utils.prefixPointerEvent('pointermove'), this); 20829 } 20830 if ( !this.options.disableMouse ) { 20831 utils.addEvent(window, 'mousemove', this); 20832 } 20833 20834 this.scroller._execEvent('beforeScrollStart'); 20835 }, 20836 20837 _move: function (e) { 20838 var point = e.touches ? e.touches[0] : e, 20839 deltaX, deltaY, 20840 newX, newY, 20841 timestamp = utils.getTime(); 20842 20843 if ( !this.moved ) { 20844 this.scroller._execEvent('scrollStart'); 20845 } 20846 20847 this.moved = true; 20848 20849 deltaX = point.pageX - this.lastPointX; 20850 this.lastPointX = point.pageX; 20851 20852 deltaY = point.pageY - this.lastPointY; 20853 this.lastPointY = point.pageY; 20854 20855 newX = this.x + deltaX; 20856 newY = this.y + deltaY; 20857 20858 this._pos(newX, newY); 20859 20860// INSERT POINT: indicator._move 20861 20862 e.preventDefault(); 20863 e.stopPropagation(); 20864 }, 20865 20866 _end: function (e) { 20867 if ( !this.initiated ) { 20868 return; 20869 } 20870 20871 this.initiated = false; 20872 20873 e.preventDefault(); 20874 e.stopPropagation(); 20875 20876 utils.removeEvent(window, 'touchmove', this); 20877 utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this); 20878 utils.removeEvent(window, 'mousemove', this); 20879 20880 if ( this.scroller.options.snap ) { 20881 var snap = this.scroller._nearestSnap(this.scroller.x, this.scroller.y); 20882 20883 var time = this.options.snapSpeed || Math.max( 20884 Math.max( 20885 Math.min(Math.abs(this.scroller.x - snap.x), 1000), 20886 Math.min(Math.abs(this.scroller.y - snap.y), 1000) 20887 ), 300); 20888 20889 if ( this.scroller.x != snap.x || this.scroller.y != snap.y ) { 20890 this.scroller.directionX = 0; 20891 this.scroller.directionY = 0; 20892 this.scroller.currentPage = snap; 20893 this.scroller.scrollTo(snap.x, snap.y, time, this.scroller.options.bounceEasing); 20894 } 20895 } 20896 20897 if ( this.moved ) { 20898 this.scroller._execEvent('scrollEnd'); 20899 } 20900 }, 20901 20902 transitionTime: function (time) { 20903 time = time || 0; 20904 var durationProp = utils.style.transitionDuration; 20905 if(!durationProp) { 20906 return; 20907 } 20908 20909 this.indicatorStyle[durationProp] = time + 'ms'; 20910 20911 if ( !time && utils.isBadAndroid ) { 20912 this.indicatorStyle[durationProp] = '0.0001ms'; 20913 // remove 0.0001ms 20914 var self = this; 20915 rAF(function() { 20916 if(self.indicatorStyle[durationProp] === '0.0001ms') { 20917 self.indicatorStyle[durationProp] = '0s'; 20918 } 20919 }); 20920 } 20921 }, 20922 20923 transitionTimingFunction: function (easing) { 20924 this.indicatorStyle[utils.style.transitionTimingFunction] = easing; 20925 }, 20926 20927 refresh: function () { 20928 this.transitionTime(); 20929 20930 if ( this.options.listenX && !this.options.listenY ) { 20931 this.indicatorStyle.display = this.scroller.hasHorizontalScroll ? 'block' : 'none'; 20932 } else if ( this.options.listenY && !this.options.listenX ) { 20933 this.indicatorStyle.display = this.scroller.hasVerticalScroll ? 'block' : 'none'; 20934 } else { 20935 this.indicatorStyle.display = this.scroller.hasHorizontalScroll || this.scroller.hasVerticalScroll ? 'block' : 'none'; 20936 } 20937 20938 if ( this.scroller.hasHorizontalScroll && this.scroller.hasVerticalScroll ) { 20939 utils.addClass(this.wrapper, 'iScrollBothScrollbars'); 20940 utils.removeClass(this.wrapper, 'iScrollLoneScrollbar'); 20941 20942 if ( this.options.defaultScrollbars && this.options.customStyle ) { 20943 if ( this.options.listenX ) { 20944 this.wrapper.style.right = '8px'; 20945 } else { 20946 this.wrapper.style.bottom = '8px'; 20947 } 20948 } 20949 } else { 20950 utils.removeClass(this.wrapper, 'iScrollBothScrollbars'); 20951 utils.addClass(this.wrapper, 'iScrollLoneScrollbar'); 20952 20953 if ( this.options.defaultScrollbars && this.options.customStyle ) { 20954 if ( this.options.listenX ) { 20955 this.wrapper.style.right = '2px'; 20956 } else { 20957 this.wrapper.style.bottom = '2px'; 20958 } 20959 } 20960 } 20961 20962 var r = this.wrapper.offsetHeight; // force refresh 20963 20964 if ( this.options.listenX ) { 20965 this.wrapperWidth = this.wrapper.clientWidth; 20966 if ( this.options.resize ) { 20967 this.indicatorWidth = Math.max(Math.round(this.wrapperWidth * this.wrapperWidth / (this.scroller.scrollerWidth || this.wrapperWidth || 1)), 8); 20968 this.indicatorStyle.width = this.indicatorWidth + 'px'; 20969 } else { 20970 this.indicatorWidth = this.indicator.clientWidth; 20971 } 20972 20973 this.maxPosX = this.wrapperWidth - this.indicatorWidth; 20974 20975 if ( this.options.shrink == 'clip' ) { 20976 this.minBoundaryX = -this.indicatorWidth + 8; 20977 this.maxBoundaryX = this.wrapperWidth - 8; 20978 } else { 20979 this.minBoundaryX = 0; 20980 this.maxBoundaryX = this.maxPosX; 20981 } 20982 20983 this.sizeRatioX = this.options.speedRatioX || (this.scroller.maxScrollX && (this.maxPosX / this.scroller.maxScrollX)); 20984 } 20985 20986 if ( this.options.listenY ) { 20987 this.wrapperHeight = this.wrapper.clientHeight; 20988 if ( this.options.resize ) { 20989 this.indicatorHeight = Math.max(Math.round(this.wrapperHeight * this.wrapperHeight / (this.scroller.scrollerHeight || this.wrapperHeight || 1)), 8); 20990 this.indicatorStyle.height = this.indicatorHeight + 'px'; 20991 } else { 20992 this.indicatorHeight = this.indicator.clientHeight; 20993 } 20994 20995 this.maxPosY = this.wrapperHeight - this.indicatorHeight; 20996 20997 if ( this.options.shrink == 'clip' ) { 20998 this.minBoundaryY = -this.indicatorHeight + 8; 20999 this.maxBoundaryY = this.wrapperHeight - 8; 21000 } else { 21001 this.minBoundaryY = 0; 21002 this.maxBoundaryY = this.maxPosY; 21003 } 21004 21005 this.maxPosY = this.wrapperHeight - this.indicatorHeight; 21006 this.sizeRatioY = this.options.speedRatioY || (this.scroller.maxScrollY && (this.maxPosY / this.scroller.maxScrollY)); 21007 } 21008 21009 this.updatePosition(); 21010 }, 21011 21012 updatePosition: function () { 21013 var x = this.options.listenX && Math.round(this.sizeRatioX * this.scroller.x) || 0, 21014 y = this.options.listenY && Math.round(this.sizeRatioY * this.scroller.y) || 0; 21015 21016 if ( !this.options.ignoreBoundaries ) { 21017 if ( x < this.minBoundaryX ) { 21018 if ( this.options.shrink == 'scale' ) { 21019 this.width = Math.max(this.indicatorWidth + x, 8); 21020 this.indicatorStyle.width = this.width + 'px'; 21021 } 21022 x = this.minBoundaryX; 21023 } else if ( x > this.maxBoundaryX ) { 21024 if ( this.options.shrink == 'scale' ) { 21025 this.width = Math.max(this.indicatorWidth - (x - this.maxPosX), 8); 21026 this.indicatorStyle.width = this.width + 'px'; 21027 x = this.maxPosX + this.indicatorWidth - this.width; 21028 } else { 21029 x = this.maxBoundaryX; 21030 } 21031 } else if ( this.options.shrink == 'scale' && this.width != this.indicatorWidth ) { 21032 this.width = this.indicatorWidth; 21033 this.indicatorStyle.width = this.width + 'px'; 21034 } 21035 21036 if ( y < this.minBoundaryY ) { 21037 if ( this.options.shrink == 'scale' ) { 21038 this.height = Math.max(this.indicatorHeight + y * 3, 8); 21039 this.indicatorStyle.height = this.height + 'px'; 21040 } 21041 y = this.minBoundaryY; 21042 } else if ( y > this.maxBoundaryY ) { 21043 if ( this.options.shrink == 'scale' ) { 21044 this.height = Math.max(this.indicatorHeight - (y - this.maxPosY) * 3, 8); 21045 this.indicatorStyle.height = this.height + 'px'; 21046 y = this.maxPosY + this.indicatorHeight - this.height; 21047 } else { 21048 y = this.maxBoundaryY; 21049 } 21050 } else if ( this.options.shrink == 'scale' && this.height != this.indicatorHeight ) { 21051 this.height = this.indicatorHeight; 21052 this.indicatorStyle.height = this.height + 'px'; 21053 } 21054 } 21055 21056 this.x = x; 21057 this.y = y; 21058 21059 if ( this.scroller.options.useTransform ) { 21060 this.indicatorStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.scroller.translateZ; 21061 } else { 21062 this.indicatorStyle.left = x + 'px'; 21063 this.indicatorStyle.top = y + 'px'; 21064 } 21065 }, 21066 21067 _pos: function (x, y) { 21068 if ( x < 0 ) { 21069 x = 0; 21070 } else if ( x > this.maxPosX ) { 21071 x = this.maxPosX; 21072 } 21073 21074 if ( y < 0 ) { 21075 y = 0; 21076 } else if ( y > this.maxPosY ) { 21077 y = this.maxPosY;
21078 } 21079 21080 x = this.options.listenX ? Math.round(x / this.sizeRatioX) : this.scroller.x; 21081 y = this.options.listenY ? Math.round(y / this.sizeRatioY) : this.scroller.y; 21082 21083 this.scroller.scrollTo(x, y); 21084 }, 21085 21086 fade: function (val, hold) { 21087 if ( hold && !this.visible ) { 21088 return; 21089 } 21090 21091 clearTimeout(this.fadeTimeout); 21092 this.fadeTimeout = null; 21093 21094 var time = val ? 250 : 500, 21095 delay = val ? 0 : 300; 21096 21097 val = val ? '1' : '0'; 21098 21099 this.wrapperStyle[utils.style.transitionDuration] = time + 'ms'; 21100 21101 this.fadeTimeout = setTimeout((function (val) { 21102 this.wrapperStyle.opacity = val; 21103 this.visible = +val; 21104 }).bind(this, val), delay); 21105 } 21106}; 21107 21108IScroll.utils = utils; 21109 21110if ( typeof module != 'undefined' && module.exports ) { 21111 module.exports = IScroll; 21112} else if ( typeof define == 'function' && define.amd ) { 21113 define( function () { return IScroll; } ); 21114} else { 21115 window.IScroll = IScroll; 21116} 21117 21118})(window, document, Math); 21119/*! 21120 * fullPage 2.9.4 21121 * https://github.com/alvarotrigo/fullPage.js 21122 * @license MIT licensed 21123 * 21124 * Copyright (C) 2015 alvarotrigo.com - A project by Alvaro Trigo 21125 */ 21126(function(global, factory) { 21127 'use strict'; 21128 if (typeof define === 'function' && define.amd) { 21129 define(['jquery'], function($) { 21130 return factory($, global, global.document, global.Math); 21131 }); 21132 } else if (typeof exports === "object" && exports) { 21133 module.exports = factory(require('jquery'), global, global.document, global.Math); 21134 } else { 21135 factory(jQuery, global, global.document, global.Math); 21136 } 21137})(typeof window !== 'undefined' ? window : this, function($, window, document, Math, undefined) { 21138 'use strict'; 21139 21140 // keeping central set of classnames and selectors 21141 var WRAPPER = 'fullpage-wrapper'; 21142 var WRAPPER_SEL = '.' + WRAPPER; 21143 21144 // slimscroll 21145 var SCROLLABLE = 'fp-scrollable'; 21146 var SCROLLABLE_SEL = '.' + SCROLLABLE; 21147 21148 // util 21149 var RESPONSIVE = 'fp-responsive'; 21150 var NO_TRANSITION = 'fp-notransition'; 21151 var DESTROYED = 'fp-destroyed'; 21152 var ENABLED = 'fp-enabled'; 21153 var VIEWING_PREFIX = 'fp-viewing'; 21154 var ACTIVE = 'active'; 21155 var ACTIVE_SEL = '.' + ACTIVE; 21156 var COMPLETELY = 'fp-completely'; 21157 var COMPLETELY_SEL = '.' + COMPLETELY; 21158 21159 // section 21160 var SECTION_DEFAULT_SEL = '.section'; 21161 var SECTION = 'fp-section'; 21162 var SECTION_SEL = '.' + SECTION; 21163 var SECTION_ACTIVE_SEL = SECTION_SEL + ACTIVE_SEL; 21164 var SECTION_FIRST_SEL = SECTION_SEL + ':first'; 21165 var SECTION_LAST_SEL = SECTION_SEL + ':last'; 21166 var TABLE_CELL = 'fp-tableCell'; 21167 var TABLE_CELL_SEL = '.' + TABLE_CELL; 21168 var AUTO_HEIGHT = 'fp-auto-height'; 21169 var AUTO_HEIGHT_SEL = '.fp-auto-height'; 21170 var NORMAL_SCROLL = 'fp-normal-scroll'; 21171 var NORMAL_SCROLL_SEL = '.fp-normal-scroll'; 21172 21173 // section nav 21174 var SECTION_NAV = 'fp-nav'; 21175 var SECTION_NAV_SEL = '#' + SECTION_NAV; 21176 var SECTION_NAV_TOOLTIP = 'fp-tooltip'; 21177 var SECTION_NAV_TOOLTIP_SEL='.'+SECTION_NAV_TOOLTIP; 21178 var SHOW_ACTIVE_TOOLTIP = 'fp-show-active'; 21179 21180 // slide 21181 var SLIDE_DEFAULT_SEL = '.slide'; 21182 var SLIDE = 'fp-slide'; 21183 var SLIDE_SEL = '.' + SLIDE; 21184 var SLIDE_ACTIVE_SEL = SLIDE_SEL + ACTIVE_SEL; 21185 var SLIDES_WRAPPER = 'fp-slides'; 21186 var SLIDES_WRAPPER_SEL = '.' + SLIDES_WRAPPER; 21187 var SLIDES_CONTAINER = 'fp-slidesContainer'; 21188 var SLIDES_CONTAINER_SEL = '.' + SLIDES_CONTAINER; 21189 var TABLE = 'fp-table'; 21190 21191 // slide nav 21192 var SLIDES_NAV = 'fp-slidesNav'; 21193 var SLIDES_NAV_SEL = '.' + SLIDES_NAV; 21194 var SLIDES_NAV_LINK_SEL = SLIDES_NAV_SEL + ' a'; 21195 var SLIDES_ARROW = 'fp-controlArrow'; 21196 var SLIDES_ARROW_SEL = '.' + SLIDES_ARROW; 21197 var SLIDES_PREV = 'fp-prev'; 21198 var SLIDES_PREV_SEL = '.' + SLIDES_PREV; 21199 var SLIDES_ARROW_PREV = SLIDES_ARROW + ' ' + SLIDES_PREV; 21200 var SLIDES_ARROW_PREV_SEL = SLIDES_ARROW_SEL + SLIDES_PREV_SEL; 21201 var SLIDES_NEXT = 'fp-next';
21202 var SLIDES_NEXT_SEL = '.' + SLIDES_NEXT; 21203 var SLIDES_ARROW_NEXT = SLIDES_ARROW + ' ' + SLIDES_NEXT; 21204 var SLIDES_ARROW_NEXT_SEL = SLIDES_ARROW_SEL + SLIDES_NEXT_SEL; 21205 21206 var $window = $(window); 21207 var $document = $(document); 21208 21209 // Default options for iScroll.js used when using scrollOverflow 21210 var iscrollOptions = { 21211 scrollbars: true, 21212 mouseWheel: true, 21213 hideScrollbars: false, 21214 fadeScrollbars: false, 21215 disableMouse: true, 21216 interactiveScrollbars: true, 21217 bounce: false, 21218 }; 21219 21220 $.fn.fullpage = function(options) { 21221 //only once my friend! 21222 if($('html').hasClass(ENABLED)){ displayWarnings(); return; } 21223 21224 // common jQuery objects 21225 var $htmlBody = $('html, body'); 21226 var $body = $('body'); 21227 21228 var FP = $.fn.fullpage; 21229 21230 // Creating some defaults, extending them with any options that were provided 21231 options = $.extend({ 21232 //navigation 21233 menu: false, 21234 anchors:[], 21235 lockAnchors: false, 21236 navigation: false, 21237 navigationPosition: 'right', 21238 navigationTooltips: [], 21239 showActiveTooltip: false, 21240 slidesNavigation: false, 21241 slidesNavPosition: 'bottom', 21242 scrollBar: false, 21243 hybrid: false, 21244 21245 //scrolling 21246 css3: true, 21247 scrollingSpeed: 700, 21248 autoScrolling: true, 21249 fitToSection: true, 21250 fitToSectionDelay: 1000, 21251 easing: 'easeInOutCubic', 21252 easingcss3: 'ease', 21253 loopBottom: false, 21254 loopTop: false, 21255 loopHorizontal: true, 21256 continuousVertical: false, 21257 continuousHorizontal: false, 21258 scrollHorizontally: false, 21259 interlockedSlides: false, 21260 dragAndMove: false, 21261 offsetSections: false, 21262 resetSliders: false, 21263 fadingEffect: false, 21264 normalScrollElements: null, 21265 scrollOverflow: false, 21266 scrollOverflowReset: false, 21267 scrollOverflowHandler: iscrollHandler, 21268 scrollOverflowOptions: null, 21269 touchSensitivity: 5, 21270 normalScrollElementTouchThreshold: 5, 21271 bigSectionsDestination: null, 21272 21273 //Accessibility 21274 keyboardScrolling: true, 21275 animateAnchor: true, 21276 recordHistory: true, 21277 21278 //design 21279 controlArrows: true, 21280 controlArrowColor: '#fff', 21281 verticalCentered: true, 21282 sectionsColor : [], 21283 paddingTop: 0, 21284 paddingBottom: 0, 21285 fixedElements: null, 21286 responsive: 0, //backwards compabitility with responsiveWiddth 21287 responsiveWidth: 0, 21288 responsiveHeight: 0, 21289 responsiveSlides: false, 21290 parallax: false, 21291 parallaxOptions: { 21292 type: 'reveal', 21293 percentage: 62, 21294 property: 'translate' 21295 }, 21296 21297 //Custom selectors 21298 sectionSelector: SECTION_DEFAULT_SEL, 21299 slideSelector: SLIDE_DEFAULT_SEL, 21300 21301 //events 21302 afterLoad: null, 21303 onLeave: null, 21304 afterRender: null, 21305 afterResize: null, 21306 afterReBuild: null, 21307 afterSlideLoad: null, 21308 onSlideLeave: null, 21309 afterResponsive: null, 21310 21311 lazyLoading: true 21312 }, options); 21313 21314 //flag to avoid very fast sliding for landscape sliders 21315 var slideMoving = false; 21316 21317 var isTouchDevice = navigator.userAgent.match(/(iPhone|iPod|iPad|Android|playbook|silk|BlackBerry|BB10|Windows Phone|Tizen|Bada|webOS|IEMobile|Opera Mini)/); 21318 var isTouch = (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0) || (navigator.maxTouchPoints)); 21319 var container = $(this); 21320 var windowsHeight = $window.height(); 21321 var isResizing = false; 21322 var isWindowFocused = true; 21323 var lastScrolledDestiny; 21324 var lastScrolledSlide; 21325 var canScroll = true; 21326 var scrollings = []; 21327 var controlPressed; 21328 var startingSection; 21329 var isScrollAllowed = {}; 21330 isScrollAllowed.m = { 'up':true, 'down':true, 'left':true, 'right':true }; 21331 isScrollAllowed.k = $.extend(true,{}, isScrollAllowed.m); 21332 var MSPointer = getMSPointer(); 21333 var events = { 21334 touchmove: 'ontouchmove' in window ? 'touchmove' : MSPointer.move, 21335 touchstart: 'ontouchstart' in window ? 'touchstart' : MSPointer.down 21336 }; 21337 21338 //cheks for passive event support 21339 //added by Uncode from new fullPage updates 21340 var g_supportsPassive = false;
21341 try { 21342 var opts = Object.defineProperty({}, 'passive', { 21343 get: function() { 21344 g_supportsPassive = true; 21345 } 21346 }); 21347 window.addEventListener("testPassive", null, opts); 21348 window.removeEventListener("testPassive", null, opts); 21349 } catch (e) {} 21350 21351 //timeouts 21352 var resizeId; 21353 var afterSectionLoadsId; 21354 var afterSlideLoadsId; 21355 var scrollId; 21356 var scrollId2; 21357 var keydownId; 21358 var originals = $.extend(true, {}, options); //deep copy 21359 21360 //Uncode addition 21361 var $masthead = $('#masthead'); 21362 var hideMenu = !$('body').hasClass('vmenu') && $('body').hasClass('uncode-fp-menu-hide') ? true : false; 21363 var menuHeight = $masthead.hasClass('menu-transparent') || hideMenu ? 0 : UNCODE.menuHeight; 21364 var bodyBorder = UNCODE.bodyBorder; 21365 var adminBarHeight = UNCODE.adminBarHeight; 21366 21367 displayWarnings(); 21368 21369 //fixing bug in iScroll with links: https://github.com/cubiq/iscroll/issues/783 21370 iscrollOptions.click = isTouch; // see #2035 21371 21372 //extending iScroll options with the user custom ones 21373 iscrollOptions = $.extend(iscrollOptions, options.scrollOverflowOptions); 21374 21375 //easeInOutCubic animation included in the plugin 21376 $.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;}}); 21377 21378 /** 21379 * Sets the autoScroll option. 21380 * It changes the scroll bar visibility and the history of the site as a result. 21381 */ 21382 function setAutoScrolling(value, type){ 21383 //removing the transformation 21384 if(!value){ 21385 silentScroll(0); 21386 } 21387 21388 setVariableState('autoScrolling', value, type); 21389 21390 var element = $(SECTION_ACTIVE_SEL); 21391 21392 if(options.autoScrolling && !options.scrollBar){ 21393 $htmlBody.css({ 21394 'overflow' : 'hidden !important', 21395 'height' : '100%' 21396 }); 21397 21398 //Uncode addition 21399 //setRecordHistory(originals.recordHistory, 'internal'); 21400 21401 //for IE touch devices 21402 container.css({ 21403 '-ms-touch-action': 'none', 21404 'touch-action': 'none' 21405 }); 21406 21407 if(element.length){ 21408 //moving the container up 21409 silentScroll(element.position().top); 21410 } 21411 21412 }else{ 21413 $htmlBody.css({ 21414 'overflow' : 'visible !important', 21415 'height' : 'initial' 21416 }); 21417 21418 //Uncode addition 21419 //setRecordHistory(false, 'internal'); 21420 21421 //for IE touch devices 21422 container.css({ 21423 '-ms-touch-action': '', 21424 'touch-action': '' 21425 }); 21426 21427 //scrolling the page to the section with no animation 21428 if (element.length) { 21429 $htmlBody.scrollTop(element.position().top); 21430 } 21431 } 21432 } 21433 21434 /** 21435 * Defines wheter to record the history for each hash change in the URL. 21436 */ 21437 function setRecordHistory(value, type){ 21438 setVariableState('recordHistory', value, type); 21439 } 21440 21441 /** 21442 * Defines the scrolling speed 21443 */ 21444 function setScrollingSpeed(value, type){ 21445 setVariableState('scrollingSpeed', value, type); 21446 } 21447 21448 /** 21449 * Sets fitToSection 21450 */ 21451 function setFitToSection(value, type){ 21452 setVariableState('fitToSection', value, type); 21453 } 21454 21455 /** 21456 * Sets lockAnchors 21457 */ 21458 function setLockAnchors(value){ 21459 options.lockAnchors = value; 21460 } 21461 21462 /** 21463 * Adds or remove the possiblity of scrolling through sections by using the mouse wheel or the trackpad. 21464 */ 21465 function setMouseWheelScrolling(value){ 21466 if(value){ 21467 addMouseWheelHandler(); 21468 addMiddleWheelHandler(); 21469 }else{ 21470 removeMouseWheelHandler(); 21471 removeMiddleWheelHandler(); 21472 } 21473 } 21474 21475 /** 21476 * Adds or remove the possibility of scrolling through sections by using the mouse wheel/trackpad or touch gestures. 21477 * Optionally a second parameter can be used to specify the direction for which the action will be applied. 21478 * 21479 * @param directions string containing the direction or directions separated by comma. 21480 */ 21481 function setAllowScrolling(value, directions){ 21482 if(typeof directions !== 'undefined'){ 21483 directions = directions.replace(/ /g,'').split(','); 21484 21485 $.each(directions, function (index, direction){ 21486 setIsScrollAllowed(value, direction, 'm'); 21487 }); 21488 } 21489 else if(value){ 21490 setMouseWheelScrolling(true); 21491 addTouchHandler(); 21492 }else{ 21493 setMouseWheelScrolling(false); 21494 removeTouchHandler(); 21495 } 21496 } 21497 21498 /** 21499 * Adds or remove the possibility of scrolling through sections by using the keyboard arrow keys 21500 */ 21501 function setKeyboardScrolling(value, directions){ 21502 if(typeof directions !== 'undefined'){ 21503 directions = directions.replace(/ /g,'').split(','); 21504 21505 $.each(directions, function (index, direction){ 21506 setIsScrollAllowed(value, direction, 'k'); 21507 }); 21508 }else{ 21509 options.keyboardScrolling = value; 21510 } 21511 } 21512 21513 /** 21514 * Moves the page up one section. 21515 */ 21516 function moveSectionUp(){ 21517 var prev = $(SECTION_ACTIVE_SEL).prev(SECTION_SEL); 21518 21519 //looping to the bottom if there's no more sections above 21520 if (!prev.length && (options.loopTop || options.continuousVertical)) {
21521 prev = $(SECTION_SEL).last(); 21522 } 21523 21524 if (prev.length) { 21525 scrollPage(prev, null, true); 21526 } 21527 } 21528 21529 /** 21530 * Moves the page down one section. 21531 */ 21532 function moveSectionDown(){ 21533 var next = $(SECTION_ACTIVE_SEL).next(SECTION_SEL); 21534 21535 //looping to the top if there's no more sections below 21536 if(!next.length && 21537 (options.loopBottom || options.continuousVertical)){ 21538 next = $(SECTION_SEL).first(); 21539 } 21540 21541 if(next.length){ 21542 scrollPage(next, null, false); 21543 } 21544 } 21545 21546 /** 21547 * Moves the page to the given section and slide with no animation. 21548 * Anchors or index positions can be used as params. 21549 */ 21550 function silentMoveTo(sectionAnchor, slideAnchor){ 21551 setScrollingSpeed (0, 'internal'); 21552 moveTo(sectionAnchor, slideAnchor); 21553 setScrollingSpeed (originals.scrollingSpeed, 'internal'); 21554 } 21555 21556 /** 21557 * Moves the page to the given section and slide. 21558 * Anchors or index positions can be used as params. 21559 */ 21560 function moveTo(sectionAnchor, slideAnchor){ 21561 var destiny = getSectionByAnchor(sectionAnchor); 21562 21563 if (typeof slideAnchor !== 'undefined'){ 21564 scrollPageAndSlide(sectionAnchor, slideAnchor); 21565 }else if(destiny.length > 0){ 21566 scrollPage(destiny); 21567 } 21568 } 21569 21570 /** 21571 * Slides right the slider of the active section. 21572 * Optional `section` param. 21573 */ 21574 function moveSlideRight(section){ 21575 moveSlide('right', section); 21576 } 21577 21578 /** 21579 * Slides left the slider of the active section. 21580 * Optional `section` param. 21581 */ 21582 function moveSlideLeft(section){ 21583 moveSlide('left', section); 21584 } 21585 21586 /** 21587 * When resizing is finished, we adjust the slides sizes and positions 21588 */ 21589 function reBuild(resizing){ 21590 if(container.hasClass(DESTROYED)){ return; } //nothing to do if the plugin was destroyed 21591 21592 isResizing = true; 21593 21594 windowsHeight = $window.height(); //updating global var 21595 21596 $(SECTION_SEL).each(function(){ 21597 var slidesWrap = $(this).find(SLIDES_WRAPPER_SEL); 21598 var slides = $(this).find(SLIDE_SEL); 21599 21600 //adjusting the height of the table-cell for IE and Firefox 21601 if(options.verticalCentered){ 21602 $(this).find(TABLE_CELL_SEL).css('height', getTableHeight($(this)) + 'px'); 21603 } 21604 21605 $(this).css('height', windowsHeight + 'px'); 21606 21607 //resizing the scrolling divs 21608 if(options.scrollOverflow){ 21609 if(slides.length){ 21610 slides.each(function(){ 21611 createScrollBar($(this)); 21612 }); 21613 }else{ 21614 createScrollBar($(this)); 21615 } 21616 } 21617 21618 //adjusting the position fo the FULL WIDTH slides... 21619 if (slides.length > 1) { 21620 landscapeScroll(slidesWrap, slidesWrap.find(SLIDE_ACTIVE_SEL)); 21621 } 21622 }); 21623 21624 var activeSection = $(SECTION_ACTIVE_SEL); 21625 var sectionIndex = activeSection.index(SECTION_SEL); 21626 21627 //isn't it the first section? 21628 if(sectionIndex){ 21629 //adjusting the position for the current section 21630 silentMoveTo(sectionIndex + 1); 21631 } 21632 21633 isResizing = false; 21634 $.isFunction( options.afterResize ) && resizing && options.afterResize.call(container); 21635 $.isFunction( options.afterReBuild ) && !resizing && options.afterReBuild.call(container); 21636 } 21637 21638 /** 21639 * Turns fullPage.js to normal scrolling mode when the viewport `width` or `height` 21640 * are smaller than the set limit values. 21641 */ 21642 function setResponsive(active){ 21643 var isResponsive = $body.hasClass(RESPONSIVE); 21644 21645 if(active){ 21646 if(!isResponsive){ 21647 setAutoScrolling(false, 'internal'); 21648 setFitToSection(false, 'internal'); 21649 $(SECTION_NAV_SEL).hide(); 21650 $body.addClass(RESPONSIVE); 21651 $.isFunction( options.afterResponsive ) && options.afterResponsive.call( container, active); 21652 } 21653 } 21654 else if(isResponsive){ 21655 setAutoScrolling(originals.autoScrolling, 'internal'); 21656 setFitToSection(originals.autoScrolling, 'internal'); 21657 $(SECTION_NAV_SEL).show(); 21658 $body.removeClass(RESPONSIVE); 21659 $.isFunction( options.afterResponsive ) && options.afterResponsive.call( container, active); 21660 } 21661 } 21662 21663 if($(this).length){ 21664 //public functions 21665 FP.setAutoScrolling = setAutoScrolling; 21666 FP.setRecordHistory = setRecordHistory; 21667 FP.setScrollingSpeed = setScrollingSpeed; 21668 FP.setFitToSection = setFitToSection; 21669 FP.setLockAnchors = setLockAnchors; 21670 FP.setMouseWheelScrolling = setMouseWheelScrolling; 21671 FP.setAllowScrolling = setAllowScrolling; 21672 FP.setKeyboardScrolling = setKeyboardScrolling; 21673 FP.moveSectionUp = moveSectionUp; 21674 FP.moveSectionDown = moveSectionDown; 21675 FP.silentMoveTo = silentMoveTo; 21676 FP.moveTo = moveTo; 21677 FP.moveSlideRight = moveSlideRight; 21678 FP.moveSlideLeft = moveSlideLeft; 21679 FP.fitToSection = fitToSection; 21680 FP.reBuild = reBuild; 21681 FP.setResponsive = setResponsive; 21682 FP.destroy = destroy; 21683 21684 init(); 21685 21686 bindEvents(); 21687 } 21688
21689 function init(){ 21690 //if css3 is not supported, it will use jQuery animations 21691 if(options.css3){ 21692 options.css3 = support3d(); 21693 } 21694 21695 options.scrollBar = options.scrollBar || options.hybrid; 21696 21697 setOptionsFromDOM(); 21698 prepareDom(); 21699 setAllowScrolling(true); 21700 setAutoScrolling(options.autoScrolling, 'internal'); 21701 responsive(); 21702 21703 //setting the class for the body element 21704 setBodyClass(); 21705 21706 //Uncode addition 21707 // if(document.readyState === 'complete'){ 21708 // scrollToAnchor(); 21709 // } 21710 // $window.on('load', scrollToAnchor); 21711 } 21712 21713 function bindEvents(){ 21714 $window 21715 //when scrolling... 21716 //.on('scroll', scrollHandler) 21717 21718 //detecting any change on the URL to scroll to the given anchor link 21719 //(a way to detect back history button as we play with the hashes on the URL) 21720 .on('hashchange', hashChangeHandler) 21721 21722 //when opening a new tab (ctrl + t), `control` won't be pressed when coming back. 21723 .blur(blurHandler) 21724 21725 //when resizing the site, we adjust the heights of the sections, slimScroll... 21726 .resize(resizeHandler); 21727 21728 $document 21729 //Sliding with arrow keys, both, vertical and horizontal 21730 .keydown(keydownHandler) 21731 21732 //to prevent scrolling while zooming 21733 .keyup(keyUpHandler) 21734 21735 //Scrolls to the section when clicking the navigation bullet 21736 .on('click touchstart', SECTION_NAV_SEL + ' a', sectionBulletHandler) 21737 21738 //Scrolls the slider to the given slide destination for the given section 21739 .on('click touchstart', SLIDES_NAV_LINK_SEL, slideBulletHandler) 21740 21741 .on('click', SECTION_NAV_TOOLTIP_SEL, tooltipTextHandler); 21742 21743 //Scrolling horizontally when clicking on the slider controls. 21744 $(SECTION_SEL).on('click touchstart', SLIDES_ARROW_SEL, slideArrowHandler); 21745 21746 /** 21747 * Applying normalScroll elements. 21748 * Ignoring the scrolls over the specified selectors. 21749 */ 21750 if(options.normalScrollElements){ 21751 $document.on('mouseenter', options.normalScrollElements, function () { 21752 setMouseWheelScrolling(false); 21753 }); 21754 21755 $document.on('mouseleave', options.normalScrollElements, function(){ 21756 setMouseWheelScrolling(true); 21757 }); 21758 } 21759 } 21760 21761 /** 21762 * Setting options from DOM elements if they are not provided. 21763 */ 21764 function setOptionsFromDOM(){ 21765 var sections = container.find(options.sectionSelector); 21766 21767 //no anchors option? Checking for them in the DOM attributes 21768 if(!options.anchors.length){ 21769 options.anchors = sections.filter('[data-anchor]').map(function(){ 21770 return $(this).data('anchor').toString(); 21771 }).get(); 21772 } 21773 21774 //no tooltips option? Checking for them in the DOM attributes 21775 if(!options.navigationTooltips.length){ 21776 options.navigationTooltips = sections.filter('[data-tooltip]').map(function(){ 21777 return $(this).data('tooltip').toString(); 21778 }).get(); 21779 } 21780 } 21781 21782 /** 21783 * Works over the DOM structure to set it up for the current fullpage options. 21784 */ 21785 function prepareDom(){ 21786 container.css({ 21787 'height': '100%', 21788 'position': 'relative' 21789 }); 21790 21791 //adding a class to recognize the container internally in the code 21792 container.addClass(WRAPPER); 21793 $('html').addClass(ENABLED); 21794 21795 windowsHeight = $window.height(); 21796 21797 container.removeClass(DESTROYED); //in case it was destroyed before initializing it again 21798 21799 addInternalSelectors(); 21800 21801 //styling the sections / slides / menu 21802 $(SECTION_SEL).each(function(index){ 21803 var section = $(this); 21804 var slides = section.find(SLIDE_SEL); 21805 var numSlides = slides.length; 21806 21807 styleSection(section, index); 21808 styleMenu(section, index); 21809 21810 // if there's any slide 21811 if (numSlides > 0) { 21812 styleSlides(section, slides, numSlides); 21813 }else{ 21814 if(options.verticalCentered){ 21815 addTableClass(section); 21816 } 21817 } 21818 }); 21819 21820 //fixed elements need to be moved out of the plugin container due to problems with CSS3. 21821 if(options.fixedElements && options.css3){ 21822 $(options.fixedElements).appendTo($body); 21823 } 21824 21825 //vertical centered of the navigation + active bullet 21826 if(options.navigation){ 21827 addVerticalNavigation(); 21828 } 21829 21830 enableYoutubeAPI(); 21831 21832 if(options.scrollOverflow){ 21833 if(document.readyState === 'complete'){ 21834 createScrollBarHandler(); 21835 } 21836 //after DOM and images are loaded 21837 $window.on('load', createScrollBarHandler); 21838 }else{ 21839 afterRenderActions(); 21840 } 21841 } 21842 21843 /** 21844 * Styles the horizontal slides for a section. 21845 */ 21846 function styleSlides(section, slides, numSlides){ 21847 var sliderWidth = numSlides * 100; 21848 var slideWidth = 100 / numSlides; 21849 21850 slides.wrapAll('<div class="' + SLIDES_CONTAINER + '" />'); 21851 slides.parent().wrap('<div class="' + SLIDES_WRAPPER + '" />'); 21852 21853 section.find(SLIDES_CONTAINER_SEL).css('width', sliderWidth + '%'); 21854 21855 if(numSlides > 1){ 21856 if(options.controlArrows){ 21857 createSlideArrows(section); 21858 } 21859 21860 if(options.slidesNavigation){ 21861 addSlidesNavigation(section, numSlides); 21862 } 21863 } 21864 21865 slides.each(function(index) { 21866 $(this).css('width', slideWidth + '%'); 21867 21868 if(options.verticalCentered){ 21869 addTableClass($(this)); 21870 } 21871 }); 21872 21873 var startingSlide = section.find(SLIDE_ACTIVE_SEL); 21874 21875 //if the slide won't be an starting point, the default will be the first one 21876 //the active section isn't the first one? Is not the first slide of the first section? Then we load that section/sl
21876ide by default. 21877 if( startingSlide.length && ($(SECTION_ACTIVE_SEL).index(SECTION_SEL) !== 0 || ($(SECTION_ACTIVE_SEL).index(SECTION_SEL) === 0 && startingSlide.index() !== 0))){ 21878 silentLandscapeScroll(startingSlide, 'internal'); 21879 }else{ 21880 slides.eq(0).addClass(ACTIVE); 21881 } 21882 } 21883 21884 /** 21885 * Styling vertical sections 21886 */ 21887 function styleSection(section, index){ 21888 //if no active section is defined, the 1st one will be the default one 21889 if(!index && $(SECTION_ACTIVE_SEL).length === 0) { 21890 section.addClass(ACTIVE); 21891 } 21892 startingSection = $(SECTION_ACTIVE_SEL); 21893 21894 section.css('height', windowsHeight + 'px'); 21895 21896 if(options.paddingTop){ 21897 section.css('padding-top', options.paddingTop); 21898 } 21899 21900 if(options.paddingBottom){ 21901 section.css('padding-bottom', options.paddingBottom); 21902 } 21903 21904 if (typeof options.sectionsColor[index] !== 'undefined') { 21905 section.css('background-color', options.sectionsColor[index]); 21906 } 21907 21908 if (typeof options.anchors[index] !== 'undefined') { 21909 section.attr('data-anchor', options.anchors[index]); 21910 } 21911 } 21912 21913 /** 21914 * Sets the data-anchor attributes to the menu elements and activates the current one. 21915 */ 21916 function styleMenu(section, index){ 21917 if (typeof options.anchors[index] !== 'undefined') { 21918 //activating the menu / nav element on load 21919 if(section.hasClass(ACTIVE)){ 21920 activateMenuAndNav(options.anchors[index], index); 21921 } 21922 } 21923 21924 //moving the menu outside the main container if it is inside (avoid problems with fixed positions when using CSS3 tranforms) 21925 if(options.menu && options.css3 && $(options.menu).closest(WRAPPER_SEL).length){ 21926 $(options.menu).appendTo($body); 21927 } 21928 } 21929 21930 /** 21931 * Adds internal classes to be able to provide customizable selectors 21932 * keeping the link with the style sheet. 21933 */ 21934 function addInternalSelectors(){ 21935 container.find(options.sectionSelector).addClass(SECTION); 21936 container.find(options.slideSelector).addClass(SLIDE); 21937 } 21938 21939 /** 21940 * Creates the control arrows for the given section 21941 */ 21942 function createSlideArrows(section){ 21943 section.find(SLIDES_WRAPPER_SEL).after('<div class="' + SLIDES_ARROW_PREV + '"></div><div class="' + SLIDES_ARROW_NEXT + '"></div>'); 21944 21945 if(options.controlArrowColor!='#fff'){ 21946 section.find(SLIDES_ARROW_NEXT_SEL).css('border-color', 'transparent transparent transparent '+options.controlArrowColor); 21947 section.find(SLIDES_ARROW_PREV_SEL).css('border-color', 'transparent '+ options.controlArrowColor + ' transparent transparent'); 21948 } 21949 21950 if(!options.loopHorizontal){ 21951 section.find(SLIDES_ARROW_PREV_SEL).hide(); 21952 } 21953 } 21954 21955 /** 21956 * Creates a vertical navigation bar. 21957 */ 21958 function addVerticalNavigation(){ 21959 $body.append('<div id="' + SECTION_NAV + '"><ul></ul></div>'); 21960 var nav = $(SECTION_NAV_SEL); 21961 21962 nav.addClass(function() { 21963 return options.showActiveTooltip ? SHOW_ACTIVE_TOOLTIP + ' ' + options.navigationPosition : options.navigationPosition; 21964 }); 21965 21966 for (var i = 0; i < $(SECTION_SEL).length; i++) { 21967 var link = ''; 21968 if (options.anchors.length) { 21969 link = options.anchors[i]; 21970 } 21971 21972 var li = '<li><a href="#' + link + '"><span></span></a>'; 21973 21974 // Only add tooltip if needed (defined by user) 21975 var tooltip = options.navigationTooltips[i]; 21976 21977 if (typeof tooltip !== 'undefined' && tooltip !== '') { 21978 li += '<div class="' + SECTION_NAV_TOOLTIP + ' ' + options.navigationPosition + '">' + tooltip + '</div>'; 21979 } 21980 21981 li += '</li>'; 21982 21983 nav.find('ul').append(li); 21984 } 21985 21986 //centering it vertically 21987 $(SECTION_NAV_SEL).css('margin-top', '-' + ($(SECTION_NAV_SEL).height()/2) + 'px'); 21988 21989 //activating the current active section 21990 $(SECTION_NAV_SEL).find('li').eq($(SECTION_ACTIVE_SEL).index(SECTION_SEL)).find('a').addClass(ACTIVE); 21991 } 21992 21993 /** 21994 * Creates the slim scroll scrollbar for the sections and slides inside them. 21995 */ 21996 function createScrollBarHandler(){ 21997 $(SECTION_SEL).each(function(){ 21998 var slides = $(this).find(SLIDE_SEL); 21999 22000 if(slides.length){ 22001 slides.each(function(){ 22002 createScrollBar($(this)); 22003 }); 22004 }else{ 22005 createScrollBar($(this)); 22006 } 22007 22008 }); 22009 afterRenderActions(); 22010 } 22011 22012 /*
22013 * Enables the Youtube videos API so we can control their flow if necessary. 22014 */ 22015 function enableYoutubeAPI(){ 22016 container.find('iframe[src*="youtube.com/embed/"]').each(function(){ 22017 addURLParam($(this), 'enablejsapi=1'); 22018 }); 22019 } 22020 22021 /** 22022 * Adds a new parameter and its value to the `src` of a given element 22023 */ 22024 function addURLParam(element, newParam){ 22025 var originalSrc = element.attr('src'); 22026 element.attr('src', originalSrc + getUrlParamSign(originalSrc) + newParam); 22027 } 22028 22029 /* 22030 * Returns the prefix sign to use for a new parameter in an existen URL. 22031 * 22032 * @return {String} ? | & 22033 */ 22034 function getUrlParamSign(url){ 22035 return ( !/\?/.test( url ) ) ? '?' : '&'; 22036 } 22037 22038 /** 22039 * Actions and callbacks to fire afterRender 22040 */ 22041 function afterRenderActions(){ 22042 var section = $(SECTION_ACTIVE_SEL); 22043 22044 section.addClass(COMPLETELY); 22045 22046 if(options.scrollOverflowHandler.afterRender){ 22047 options.scrollOverflowHandler.afterRender(section); 22048 } 22049 lazyLoad(section); 22050 playMedia(section); 22051 options.scrollOverflowHandler.afterLoad(); 22052 22053 if(isDestinyTheStartingSection()){ 22054 $.isFunction( options.afterLoad ) && options.afterLoad.call(section, section.data('anchor'), (section.index(SECTION_SEL) + 1)); 22055 } 22056 22057 $.isFunction( options.afterRender ) && options.afterRender.call(container); 22058 } 22059 22060 /** 22061 * Determines if the URL anchor destiny is the starting section (the one using 'active' class before initialization) 22062 */ 22063 function isDestinyTheStartingSection(){ 22064 var anchors = window.location.hash.replace('#', '').split('/'); 22065 var destinationSection = getSectionByAnchor(decodeURIComponent(anchors[0])); 22066 22067 return !destinationSection.length || destinationSection.length && destinationSection.index() === startingSection.index(); 22068 } 22069 22070 22071 var isScrolling = false; 22072 var lastScroll = 0; 22073 22074 //when scrolling... 22075 function scrollHandler(){ 22076 var currentSection; 22077 22078 if(!options.autoScrolling || options.scrollBar){ 22079 var currentScroll = $window.scrollTop(); 22080 var scrollDirection = getScrollDirection(currentScroll); 22081 var visibleSectionIndex = 0; 22082 var screen_mid = currentScroll + ($window.height() / 2.0); 22083 var isAtBottom = $body.height() - $window.height() === currentScroll; 22084 var sections = document.querySelectorAll(SECTION_SEL); 22085 22086 //when using `auto-height` for a small last section it won't be centered in the viewport 22087 if(isAtBottom){ 22088 visibleSectionIndex = sections.length - 1; 22089 } 22090 //is at top? when using `auto-height` for a small first section it won't be centered in the viewport 22091 else if(!currentScroll){ 22092 visibleSectionIndex = 0; 22093 } 22094 22095 //taking the section which is showing more content in the viewport 22096 else{ 22097 for (var i = 0; i < sections.length; ++i) { 22098 var section = sections[i]; 22099 22100 // Pick the the last section which passes the middle line of the screen. 22101 if (section.offsetTop <= screen_mid) 22102 { 22103 visibleSectionIndex = i; 22104 } 22105 } 22106 } 22107 22108 if(isCompletelyInViewPort(scrollDirection)){ 22109 if(!$(SECTION_ACTIVE_SEL).hasClass(COMPLETELY)){ 22110 $(SECTION_ACTIVE_SEL).addClass(COMPLETELY).siblings().removeClass(COMPLETELY); 22111 } 22112 } 22113 22114 //geting the last one, the current one on the screen 22115 currentSection = $(sections).eq(visibleSectionIndex); 22116 22117 //setting the visible section as active when manually scrolling 22118 //executing only once the first time we reach the section 22119 if(!currentSection.hasClass(ACTIVE)){ 22120 isScrolling = true; 22121 var leavingSection = $(SECTION_ACTIVE_SEL); 22122 var leavingSectionIndex = leavingSection.index(SECTION_SEL) + 1; 22123 var yMovement = getYmovement(currentSection); 22124 var anchorLink = currentSection.data('anchor'); 22125 var sectionIndex = currentSection.index(SECTION_SEL) + 1; 22126 var activeSlide = currentSection.find(SLIDE_ACTIVE_SEL); 22127 var slideIndex; 22128 var slideAnchorLink; 22129 22130 if(activeSlide.length){ 22131 slideAnchorLink = activeSlide.data('anchor'); 22132 slideIndex = activeSlide.index(); 22133 } 22134 22135 if(canScroll){ 22136 currentSection.addClass(ACTIVE).siblings().removeClass(ACTIVE); 22137 22138 $.isFunction( options.onLeave ) && options.onLeave.call( leavingSection, leavingSectionIndex, sectionIndex, yMovement); 22139 $.isFunction( options.afterLoad ) && options.afterLoad.call( currentSection, anchorLink, sectionIndex); 22140 22141 stopMedia(leavingSection); 22142 lazyLoad(currentSection); 22143 playMedia(currentSection); 22144 22145 activateMenuAndNav(anchorLink, sectionIndex - 1); 22146 22147 if(options.anchors.length){ 22148 //needed to enter in hashChange event when using the menu with anchor links 22149 lastScrolledDestiny = anchorLink; 22150 } 22151 setState(slideIndex, slideAnchorLink, anchorLink, sectionIndex); 22152 } 22153 22154 //small timeout in order to avoid entering in hashChange event when scrolling is not finished yet 22155 clearTimeout(scrollId); 22156 scrollId = setTimeout(function(){ 22157 isScrolling = false;
22158 }, 100); 22159 } 22160 22161 if(options.fitToSection){ 22162 //for the auto adjust of the viewport to fit a whole section 22163 clearTimeout(scrollId2); 22164 22165 scrollId2 = setTimeout(function(){ 22166 //checking it again in case it changed during the delay 22167 if(options.fitToSection){ 22168 fitToSection(); 22169 } 22170 }, options.fitToSectionDelay); 22171 } 22172 } 22173 } 22174 22175 /** 22176 * Fits the site to the nearest active section 22177 */ 22178 function fitToSection(){ 22179 //checking fitToSection again in case it was set to false before the timeout delay 22180 if(canScroll){ 22181 //allows to scroll to an active section and 22182 //if the section is already active, we prevent firing callbacks 22183 isResizing = true; 22184 22185 scrollPage($(SECTION_ACTIVE_SEL)); 22186 isResizing = false; 22187 } 22188 } 22189 22190 /** 22191 * Determines whether the active section has seen in its whole or not. 22192 */ 22193 function isCompletelyInViewPort(movement){ 22194 var top = $(SECTION_ACTIVE_SEL).position().top; 22195 var bottom = top + $window.height(); 22196 22197 if(movement == 'up'){ 22198 return bottom >= ($window.scrollTop() + $window.height()); 22199 } 22200 return top <= $window.scrollTop(); 22201 } 22202 22203 /** 22204 * Gets the directon of the the scrolling fired by the scroll event. 22205 */ 22206 function getScrollDirection(currentScroll){ 22207 var direction = currentScroll > lastScroll ? 'down' : 'up'; 22208 22209 lastScroll = currentScroll; 22210 22211 //needed for auto-height sections to determine if we want to scroll to the top or bottom of the destination 22212 previousDestTop = currentScroll; 22213 22214 return direction; 22215 } 22216 22217 /** 22218 * Determines the way of scrolling up or down: 22219 * by 'automatically' scrolling a section or by using the default and normal scrolling. 22220 */ 22221 function scrolling(type, scrollable){ 22222 if (!isScrollAllowed.m[type]){ 22223 return; 22224 } 22225 var check = (type === 'down') ? 'bottom' : 'top'; 22226 var scrollSection = (type === 'down') ? moveSectionDown : moveSectionUp; 22227 22228 if(scrollable.length > 0 ){ 22229 //is the scrollbar at the start/end of the scroll? 22230 if(options.scrollOverflowHandler.isScrolled(check, scrollable)){ 22231 scrollSection(); 22232 }else{ 22233 return true; 22234 } 22235 }else{ 22236 // moved up/down 22237 scrollSection(); 22238 } 22239 } 22240 22241 /* 22242 * Preventing bouncing in iOS #2285 22243 */ 22244 function preventBouncing(event){ 22245 var e = event.originalEvent; 22246 if(!checkParentForNormalScrollElement(event.target) && options.autoScrolling && isReallyTouch(e) && isScrollAllowed.m.up){ 22247 //preventing the easing on iOS devices 22248 event.preventDefault(); 22249 } 22250 } 22251 22252 var touchStartY = 0; 22253 var touchStartX = 0; 22254 var touchEndY = 0; 22255 var touchEndX = 0; 22256 22257 /* Detecting touch events 22258 22259 * As we are changing the top property of the page on scrolling, we can not use the traditional way to detect it. 22260 * This way, the touchstart and the touch moves shows an small difference between them which is the 22261 * used one to determine the direction. 22262 */ 22263 function touchMoveHandler(event){ 22264 var e = event.originalEvent; 22265 var activeSection = $(e.target).closest(SECTION_SEL); 22266 22267 // additional: if one of the normalScrollElements isn't within options.normalScrollElementTouchThreshold hops up the DOM chain 22268 if (!checkParentForNormalScrollElement(event.target) && isReallyTouch(e) ) { 22269 22270 if(options.autoScrolling){ 22271 //preventing the easing on iOS devices 22272 event.preventDefault(); 22273 } 22274 22275 var scrollable = options.scrollOverflowHandler.scrollable(activeSection); 22276 var touchEvents = getEventsPage(e); 22277 22278 touchEndY = touchEvents.y; 22279 touchEndX = touchEvents.x; 22280 22281 //if movement in the X axys is greater than in the Y and the currect section has slides... 22282 if (activeSection.find(SLIDES_WRAPPER_SEL).length && Math.abs(touchStartX - touchEndX) > (Math.abs(touchStartY - touchEndY))) { 22283 22284 //is the movement greater than the minimum resistance to scroll? 22285 if (!slideMoving && Math.abs(touchStartX - touchEndX) > ($window.outerWidth() / 100 * options.touchSensitivity)) { 22286 if (touchStartX > touchEndX) { 22287 if(isScrollAllowed.m.right){ 22288 moveSlideRight(activeSection); //next 22289 } 22290 } else { 22291 if(isScrollAllowed.m.left){ 22292 moveSlideLeft(activeSection); //prev 22293 } 22294 } 22295 } 22296 } 22297 22298 //vertical scrolling (only when autoScrolling is enabled) 22299 else if(options.autoScrolling && canScroll){ 22300 22301 //is the movement greater than the minimum resistance to scroll? 22302 if (Math.abs(touchStartY - touchEndY) > ($window.height() / 100 * options.touchSensitivity)) { 22303 if (touchStartY > touchEndY) { 22304 scrolling('down', scrollable); 22305 } else if (touchEndY > touchStartY) { 22306 scrolling('up', scrollable); 22307 } 22308 } 22309 } 22310 } 22311 } 22312 22313 /** 22314 * recursive function to loop up the parent nodes to check if one of them exists in options.normalScrollElements 22315 * Currently works well for iOS - Android might need some testing 22316 * @param {Element} el target element / jquery selector (in subsequent nodes) 22317 * @param {int} hop current hop compared to options.normalScrollElementTouchThreshold 22318 * @return {boolean} true if there is a match to options.normalScrollElements 22319 */ 22320 function checkParentForNormalScrollElement (el, hop) { 22321 hop = hop || 0; 22322 var parent = $(el).parent(); 22323 22324 if (hop < options.normalScrollElementTouchThreshold && 22325 parent.is(options.normalScrollElements) ) { 22326 return true; 22327 } else if (hop == options.normalScrollElementTouchThreshold) { 22328 return false;
22329 } else { 22330 return checkParentForNormalScrollElement(parent, ++hop); 22331 } 22332 } 22333 22334 /** 22335 * As IE >= 10 fires both touch and mouse events when using a mouse in a touchscreen 22336 * this way we make sure that is really a touch event what IE is detecting. 22337 */ 22338 function isReallyTouch(e){ 22339 //if is not IE || IE is detecting `touch` or `pen` 22340 return typeof e.pointerType === 'undefined' || e.pointerType != 'mouse'; 22341 } 22342 22343 /** 22344 * Handler for the touch start event. 22345 */ 22346 function touchStartHandler(event){ 22347 var e = event.originalEvent; 22348 22349 //stopping the auto scroll to adjust to a section 22350 if(options.fitToSection){ 22351 $htmlBody.stop(); 22352 } 22353 22354 if(isReallyTouch(e)){ 22355 var touchEvents = getEventsPage(e); 22356 touchStartY = touchEvents.y; 22357 touchStartX = touchEvents.x; 22358 } 22359 } 22360 22361 /** 22362 * Gets the average of the last `number` elements of the given array. 22363 */ 22364 function getAverage(elements, number){ 22365 var sum = 0; 22366 22367 //taking `number` elements from the end to make the average, if there are not enought, 1 22368 var lastElements = elements.slice(Math.max(elements.length - number, 1)); 22369 22370 for(var i = 0; i < lastElements.length; i++){ 22371 sum = sum + lastElements[i]; 22372 } 22373 22374 return Math.ceil(sum/number); 22375 } 22376 22377 /** 22378 * Detecting mousewheel scrolling 22379 * 22380 * http://blogs.sitepointstatic.com/examples/tech/mouse-wheel/index.html 22381 * http://www.sitepoint.com/html5-javascript-mouse-wheel/ 22382 */ 22383 var prevTime = new Date().getTime(); 22384 22385 function MouseWheelHandler(e) { 22386 var curTime = new Date().getTime(); 22387 var isNormalScroll = $(COMPLETELY_SEL).hasClass(NORMAL_SCROLL); 22388 22389 //autoscrolling and not zooming? 22390 if(options.autoScrolling && !controlPressed && !isNormalScroll){ 22391 // cross-browser wheel delta 22392 e = e || window.event; 22393 var value = e.wheelDelta || -e.deltaY || -e.detail; 22394 var delta = Math.max(-1, Math.min(1, value)); 22395 22396 var horizontalDetection = typeof e.wheelDeltaX !== 'undefined' || typeof e.deltaX !== 'undefined'; 22397 var isScrollingVertically = (Math.abs(e.wheelDeltaX) < Math.abs(e.wheelDelta)) || (Math.abs(e.deltaX ) < Math.abs(e.deltaY) || !horizontalDetection); 22398 22399 //Limiting the array to 150 (lets not waste memory!) 22400 if(scrollings.length > 149){ 22401 scrollings.shift(); 22402 } 22403 22404 //keeping record of the previous scrollings 22405 scrollings.push(Math.abs(value)); 22406 22407 //preventing to scroll the site on mouse wheel when scrollbar is present 22408 if(options.scrollBar){ 22409 e.preventDefault ? e.preventDefault() : e.returnValue = false; 22410 } 22411 22412 var activeSection = $(SECTION_ACTIVE_SEL); 22413 var scrollable = options.scrollOverflowHandler.scrollable(activeSection); 22414 22415 //time difference between the last scroll and the current one 22416 var timeDiff = curTime-prevTime; 22417 prevTime = curTime; 22418 22419 //haven't they scrolled in a while? 22420 //(enough to be consider a different scrolling action to scroll another section) 22421 if(timeDiff > 200){ 22422 //emptying the array, we dont care about old scrollings for our averages 22423 scrollings = []; 22424 } 22425 22426 if(canScroll){ 22427 var averageEnd = getAverage(scrollings, 10); 22428 var averageMiddle = getAverage(scrollings, 70); 22429 var isAccelerating = averageEnd >= averageMiddle; 22430 22431 //to avoid double swipes... 22432 if(isAccelerating && isScrollingVertically){ 22433 //scrolling down? 22434 if (delta < 0) { 22435 scrolling('down', scrollable); 22436 22437 //scrolling up? 22438 }else { 22439 scrolling('up', scrollable); 22440 } 22441 } 22442 } 22443 22444 return false;
22445 } 22446 22447 if(options.fitToSection){ 22448 //stopping the auto scroll to adjust to a section 22449 $htmlBody.stop(); 22450 } 22451 } 22452 22453 /** 22454 * Slides a slider to the given direction. 22455 * Optional `section` param. 22456 */ 22457 function moveSlide(direction, section){ 22458 var activeSection = typeof section === 'undefined' ? $(SECTION_ACTIVE_SEL) : section; 22459 var slides = activeSection.find(SLIDES_WRAPPER_SEL); 22460 var numSlides = slides.find(SLIDE_SEL).length; 22461 22462 // more than one slide needed and nothing should be sliding 22463 if (!slides.length || slideMoving || numSlides < 2) { 22464 return; 22465 } 22466 22467 var currentSlide = slides.find(SLIDE_ACTIVE_SEL); 22468 var destiny = null; 22469 22470 if(direction === 'left'){ 22471 destiny = currentSlide.prev(SLIDE_SEL); 22472 }else{ 22473 destiny = currentSlide.next(SLIDE_SEL); 22474 } 22475 22476 //isn't there a next slide in the secuence? 22477 if(!destiny.length){ 22478 //respect loopHorizontal settin 22479 if (!options.loopHorizontal) return; 22480 22481 if(direction === 'left'){ 22482 destiny = currentSlide.siblings(':last'); 22483 }else{ 22484 destiny = currentSlide.siblings(':first'); 22485 } 22486 } 22487 22488 slideMoving = true; 22489 22490 landscapeScroll(slides, destiny, direction); 22491 } 22492 22493 /** 22494 * Maintains the active slides in the viewport 22495 * (Because the `scroll` animation might get lost with some actions, such as when using continuousVertical) 22496 */ 22497 function keepSlidesPosition(){ 22498 $(SLIDE_ACTIVE_SEL).each(function(){ 22499 silentLandscapeScroll($(this), 'internal'); 22500 }); 22501 } 22502 22503 var previousDestTop = 0; 22504 /** 22505 * Returns the destination Y position based on the scrolling direction and 22506 * the height of the section. 22507 */ 22508 function getDestinationPosition(element){ 22509 var elemPosition = element.position(); 22510 22511 //top of the desination will be at the top of the viewport 22512 var position = elemPosition.top; 22513 var isScrollingDown = elemPosition.top > previousDestTop; 22514 var sectionBottom = position - windowsHeight + element.outerHeight(); 22515 var bigSectionsDestination = options.bigSectionsDestination; 22516 22517 //Uncode addition 22518 var containerH = container.outerHeight(); 22519 var containerPosition = container.offset(); 22520 22521 //########### Commented by Uncode - START ########### 22522 //is the destination element bigger than the viewport? 22523 // if(element.outerHeight() > windowsHeight){ 22524 // //scrolling up? 22525 // if(!isScrollingDown && !bigSectionsDestination || bigSectionsDestination === 'bottom' ){ 22526 // position = sectionBottom; 22527 // } 22528 // } 22529 22530 // //sections equal or smaller than the viewport height && scrolling down? || is resizing and its in the last section 22531 // else if(isScrollingDown || (isResizing && element.is(':last-child')) ){ 22532 // //The bottom of the destination will be at the bottom of the viewport 22533 // position = sectionBottom; 22534 // } 22535 //########### Commented by Uncode - END ########### 22536 22537 //Uncode addition 22538 if ( !$masthead.hasClass('menu-transparent') && $('body').hasClass('uncode-fp-menu-shrink') && !element.is(':first-child') ) 22539 position += 18; 22540 if ( ( containerH + menuHeight + bodyBorder + adminBarHeight - windowsHeight ) < position || ( isResizing && element.is(':last-child') ) ) { 22541 position = sectionBottom + menuHeight + bodyBorder*2 + adminBarHeight; 22542 } 22543 22544 /* 22545 Keeping record of the last scrolled position to determine the scrolling direction. 22546 No conventional methods can be used as the scroll bar might not be present 22547 AND the section might not be active if it is auto-height and didnt reach the middle 22548 of the viewport. 22549 */ 22550 previousDestTop = position; 22551 return position; 22552 } 22553 22554 /** 22555 * Scrolls the site to the given element and scrolls to the slide if a callback is given. 22556 */ 22557 function scrollPage(element, callback, isMovementUp){ 22558 if(typeof element === 'undefined'){ return; } //there's no element to scroll, leaving the function 22559 22560 var dtop = getDestinationPosition(element); 22561 var slideAnchorLink; 22562 var slideIndex; 22563 22564 //local variables 22565 var v = { 22566 element: element, 22567 callback: callback, 22568 isMovementUp: isMovementUp, 22569 dtop: dtop, 22570 yMovement: getYmovement(element), 22571 anchorLink: element.data('anchor'), 22572 sectionIndex: element.index(SECTION_SEL), 22573 activeSlide: element.find(SLIDE_ACTIVE_SEL), 22574 activeSection: $(SECTION_ACTIVE_SEL), 22575 leavingSection: $(SECTION_ACTIVE_SEL).index(SECTION_SEL) + 1, 22576 22577 //caching the value of isResizing at the momment the function is called 22578 //because it will be checked later inside a setTimeout and the value might change 22579 localIsResizing: isResizing 22580 }; 22581 22582 //quiting when destination scroll is the same as the current one 22583 if((v.activeSection.is(element) && !isResizing) || (options.scrollBar && $window.scrollTop() === v.dtop && !element.hasClass(AUTO_HEIGHT) )){ return; } 22584 22585 if(v.activeSlide.length){ 22586 slideAnchorLink = v.activeSlide.data('anchor'); 22587 slideIndex = v.activeSlide.index(); 22588 } 22589 22590 // If continuousVertical && we need to wrap around 22591 if (options.autoScrolling && options.continuousVertical && typeof (v.isMovementUp) !== "undefined" && 22592 ((!v.isMovementUp && v.yMovement == 'up') || // Intending to scroll down but about to go up or 22593 (v.isMovementUp && v.yMovement == 'down'))) { // intending to scroll up but about to go down 22594 22595 v = createInfiniteSections(v); 22596 } 22597 22598 //callback (onLeave) if the site is not just resizing and readjusting the slides 22599 if($.isFunction(options.onLeave) && !v.localIsResizing){ 22600 if(options.onLeave.call(v.activeSection, v.leavingSection, (v.sectionIndex + 1), v.yMovement) === false){ 22601 return; 22602 } 22603 } 22604 22605 //pausing media of the leaving section (if we are not just resizing, as destinatino will be the same one) 22606 if(!v.localIsResizing){ 22607 stopMedia(v.activeSection); 22608 } 22609 22610 options.scrollOverflowHandler.beforeLeave(); 22611 element.addClass(ACTIVE).siblings().removeClass(ACTIVE); 22612 lazyLoad(element); 22613 options.scrollOverflowHandler.onLeave(); 22614 22615 22616 //preventing from activating the MouseWheelHandler event 22617 //more than once if the page is scrolling 22618 canScroll = false;
22619 22620 setState(slideIndex, slideAnchorLink, v.anchorLink, v.sectionIndex); 22621 22622 performMovement(v); 22623 22624 //flag to avoid callingn `scrollPage()` twice in case of using anchor links 22625 lastScrolledDestiny = v.anchorLink; 22626 22627 //avoid firing it twice (as it does also on scroll) 22628 activateMenuAndNav(v.anchorLink, v.sectionIndex); 22629 } 22630 22631 /** 22632 * Performs the vertical movement (by CSS3 or by jQuery) 22633 */ 22634 function performMovement(v){ 22635 // using CSS3 translate functionality 22636 if (options.css3 && options.autoScrolling && !options.scrollBar) { 22637 22638 // The first section can have a negative value in iOS 10. Not quite sure why: -0.0142822265625 22639 // that's why we round it to 0. 22640 var translate3d = 'translate3d(0px, -' + Math.round(v.dtop) + 'px, 0px)'; 22641 transformContainer(translate3d, true); 22642 22643 //even when the scrollingSpeed is 0 there's a little delay, which might cause the 22644 //scrollingSpeed to change in case of using silentMoveTo(); 22645 if(options.scrollingSpeed){ 22646 clearTimeout(afterSectionLoadsId); 22647 afterSectionLoadsId = setTimeout(function () { 22648 afterSectionLoads(v); 22649 }, options.scrollingSpeed); 22650 }else{ 22651 afterSectionLoads(v); 22652 } 22653 } 22654 22655 // using jQuery animate 22656 else{ 22657 var scrollSettings = getScrollSettings(v); 22658 22659 $(scrollSettings.element).animate( 22660 scrollSettings.options, 22661 options.scrollingSpeed, options.easing).promise().done(function () { //only one single callback in case of animating `html, body` 22662 if(options.scrollBar){ 22663 22664 /* Hack! 22665 The timeout prevents setting the most dominant section in the viewport as "active" when the user 22666 scrolled to a smaller section by using the mousewheel (auto scrolling) rather than draging the scroll bar. 22667 22668 When using scrollBar:true It seems like the scroll events still getting propagated even after the scrolling animation has finished. 22669 */ 22670 setTimeout(function(){ 22671 afterSectionLoads(v); 22672 },30); 22673 }else{ 22674 afterSectionLoads(v); 22675 } 22676 }); 22677 } 22678 } 22679 22680 /** 22681 * Gets the scrolling settings depending on the plugin autoScrolling option 22682 */ 22683 function getScrollSettings(v){ 22684 var scroll = {}; 22685 22686 if(options.autoScrolling && !options.scrollBar){ 22687 scroll.options = { 'top': -v.dtop}; 22688 scroll.element = WRAPPER_SEL; 22689 }else{ 22690 scroll.options = { 'scrollTop': v.dtop}; 22691 scroll.element = 'html, body'; 22692 } 22693 22694 return scroll; 22695 } 22696 22697 /** 22698 * Adds sections before or after the current one to create the infinite effect. 22699 */ 22700 function createInfiniteSections(v){ 22701 // Scrolling down 22702 if (!v.isMovementUp) { 22703 // Move all previous sections to after the active section 22704 $(SECTION_ACTIVE_SEL).after(v.activeSection.prevAll(SECTION_SEL).get().reverse()); 22705 } 22706 else { // Scrolling up 22707 // Move all next sections to before the active section 22708 $(SECTION_ACTIVE_SEL).before(v.activeSection.nextAll(SECTION_SEL)); 22709 } 22710 22711 // Maintain the displayed position (now that we changed the element order) 22712 silentScroll($(SECTION_ACTIVE_SEL).position().top); 22713 22714 // Maintain the active slides visible in the viewport 22715 keepSlidesPosition(); 22716 22717 // save for later the elements that still need to be reordered 22718 v.wrapAroundElements = v.activeSection; 22719 22720 // Recalculate animation variables 22721 v.dtop = v.element.position().top; 22722 v.yMovement = getYmovement(v.element); 22723 22724 return v; 22725 } 22726 22727 /** 22728 * Fix section order after continuousVertical changes have been animated 22729 */ 22730 function continuousVerticalFixSectionOrder (v) {
22731 // If continuousVertical is in effect (and autoScrolling would also be in effect then), 22732 // finish moving the elements around so the direct navigation will function more simply 22733 if (!v.wrapAroundElements || !v.wrapAroundElements.length) { 22734 return; 22735 } 22736 22737 if (v.isMovementUp) { 22738 $(SECTION_FIRST_SEL).before(v.wrapAroundElements); 22739 } 22740 else { 22741 $(SECTION_LAST_SEL).after(v.wrapAroundElements); 22742 } 22743 22744 silentScroll($(SECTION_ACTIVE_SEL).position().top); 22745 22746 // Maintain the active slides visible in the viewport 22747 keepSlidesPosition(); 22748 } 22749 22750 22751 /** 22752 * Actions to do once the section is loaded. 22753 */ 22754 function afterSectionLoads (v){ 22755 continuousVerticalFixSectionOrder(v); 22756 22757 //callback (afterLoad) if the site is not just resizing and readjusting the slides 22758 $.isFunction(options.afterLoad) && !v.localIsResizing && options.afterLoad.call(v.element, v.anchorLink, (v.sectionIndex + 1)); 22759 options.scrollOverflowHandler.afterLoad(); 22760 22761 if(!v.localIsResizing){ 22762 playMedia(v.element); 22763 } 22764 22765 v.element.addClass(COMPLETELY).siblings().removeClass(COMPLETELY); 22766 22767 canScroll = true; 22768 22769 $.isFunction(v.callback) && v.callback.call(this); 22770 } 22771 22772 /** 22773 * Sets the value for the given attribute from the `data-` attribute with the same suffix 22774 * ie: data-srcset ==> srcset | data-src ==> src 22775 */ 22776 function setSrc(element, attribute){ 22777 element 22778 .attr(attribute, element.data(attribute)) 22779 .removeAttr('data-' + attribute); 22780 } 22781 22782 /** 22783 * Lazy loads image, video and audio elements. 22784 */ 22785 function lazyLoad(destiny){ 22786 if (!options.lazyLoading){ 22787 return; 22788 } 22789 22790 var panel = getSlideOrSection(destiny); 22791 var element; 22792 22793 panel.find('img[data-src], img[data-srcset], source[data-src], audio[data-src], iframe[data-src]').each(function(){ 22794 element = $(this); 22795 22796 $.each(['src', 'srcset'], function(index, type){ 22797 var attribute = element.attr('data-' + type); 22798 if(typeof attribute !== 'undefined' && attribute){ 22799 setSrc(element, type); 22800 } 22801 }); 22802 22803 if(element.is('source')){ 22804 element.closest('video').get(0).load(); 22805 } 22806 }); 22807 } 22808 22809 /** 22810 * Plays video and audio elements. 22811 */ 22812 function playMedia(destiny){ 22813 var panel = getSlideOrSection(destiny); 22814 22815 //playing HTML5 media elements 22816 panel.find('video, audio').each(function(){ 22817 var element = $(this).get(0); 22818 22819 if( element.hasAttribute('data-autoplay') && typeof element.play === 'function' ) { 22820 element.play(); 22821 } 22822 }); 22823 22824 //youtube videos 22825 panel.find('iframe[src*="youtube.com/embed/"]').each(function(){ 22826 var element = $(this).get(0); 22827 22828 if ( element.hasAttribute('data-autoplay') ){ 22829 playYoutube(element); 22830 } 22831 22832 //in case the URL was not loaded yet. On page load we need time for the new URL (with the API string) to load. 22833 element.onload = function() { 22834 if ( element.hasAttribute('data-autoplay') ){ 22835 playYoutube(element); 22836 } 22837 }; 22838 }); 22839 } 22840 22841 /** 22842 * Plays a youtube video 22843 */ 22844 function playYoutube(element){ 22845 element.contentWindow.postMessage('{"event":"command","func":"playVideo","args":""}', '*'); 22846 } 22847 22848 /** 22849 * Stops video and audio elements. 22850 */ 22851 function stopMedia(destiny){ 22852 var panel = getSlideOrSection(destiny); 22853 22854 //stopping HTML5 media elements 22855 panel.find('video, audio').each(function(){ 22856 var element = $(this).get(0); 22857 22858 if( !element.hasAttribute('data-keepplaying') && typeof element.pause === 'function' ) { 22859 element.pause(); 22860 } 22861 }); 22862 22863 //youtube videos 22864 panel.find('iframe[src*="youtube.com/embed/"]').each(function(){ 22865 var element = $(this).get(0); 22866 22867 if( /youtube\.com\/embed\//.test($(this).attr('src')) && !element.hasAttribute('data-keepplaying')){ 22868 $(this).get(0).contentWindow.postMessage('{"event":"command","func":"pauseVideo","args":""}','*'); 22869 } 22870 }); 22871 } 22872 22873 /** 22874 * Gets the active slide (or section) for the given section 22875 */ 22876 function getSlideOrSection(destiny){ 22877 var slide = destiny.find(SLIDE_ACTIVE_SEL); 22878 if( slide.length ) { 22879 destiny = $(slide); 22880 } 22881 22882 return destiny; 22883 } 22884 22885 /**
22886 * Scrolls to the anchor in the URL when loading the site 22887 */ 22888 function scrollToAnchor(){ 22889 //getting the anchor link in the URL and deleting the `#` 22890 var value = window.location.hash.replace('#', '').split('/'); 22891 var sectionAnchor = decodeURIComponent(value[0]); 22892 var slideAnchor = decodeURIComponent(value[1]); 22893 22894 if(sectionAnchor){ //if theres any # 22895 if(options.animateAnchor){ 22896 scrollPageAndSlide(sectionAnchor, slideAnchor); 22897 }else{ 22898 silentMoveTo(sectionAnchor, slideAnchor); 22899 } 22900 } 22901 } 22902 22903 /** 22904 * Detecting any change on the URL to scroll to the given anchor link 22905 * (a way to detect back history button as we play with the hashes on the URL) 22906 */ 22907 function hashChangeHandler(){ 22908 if(!isScrolling && !options.lockAnchors){ 22909 var value = window.location.hash.replace('#', '').split('/'); 22910 var sectionAnchor = decodeURIComponent(value[0]); 22911 var slideAnchor = decodeURIComponent(value[1]); 22912 22913 //when moving to a slide in the first section for the first time (first time to add an anchor to the URL) 22914 var isFirstSlideMove = (typeof lastScrolledDestiny === 'undefined'); 22915 var isFirstScrollMove = (typeof lastScrolledDestiny === 'undefined' && typeof slideAnchor === 'undefined' && !slideMoving); 22916 22917 22918 if(sectionAnchor.length){ 22919 /*in order to call scrollpage() only once for each destination at a time 22920 It is called twice for each scroll otherwise, as in case of using anchorlinks `hashChange` 22921 event is fired on every scroll too.*/ 22922 if ((sectionAnchor && sectionAnchor !== lastScrolledDestiny) && !isFirstSlideMove || isFirstScrollMove || (!slideMoving && lastScrolledSlide != slideAnchor )) { 22923 scrollPageAndSlide(sectionAnchor, slideAnchor); 22924 } 22925 } 22926 } 22927 } 22928 22929 //Sliding with arrow keys, both, vertical and horizontal 22930 function keydownHandler(e) { 22931 22932 clearTimeout(keydownId); 22933 22934 var activeElement = $(':focus'); 22935 22936 if(!activeElement.is('textarea') && !activeElement.is('input') && !activeElement.is('select') && 22937 activeElement.attr('contentEditable') !== "true" && activeElement.attr('contentEditable') !== '' && 22938 options.keyboardScrolling && options.autoScrolling){ 22939 var keyCode = e.which; 22940 22941 //preventing the scroll with arrow keys & spacebar & Page Up & Down keys 22942 var keyControls = [40, 38, 32, 33, 34]; 22943 if($.inArray(keyCode, keyControls) > -1){ 22944 e.preventDefault(); 22945 } 22946 22947 controlPressed = e.ctrlKey; 22948 22949 keydownId = setTimeout(function(){ 22950 onkeydown(e); 22951 },150); 22952 } 22953 } 22954 22955 function tooltipTextHandler(){ 22956 $(this).prev().trigger('click'); 22957 } 22958 22959 //to prevent scrolling while zooming 22960 function keyUpHandler(e){ 22961 if(isWindowFocused){ //the keyup gets fired on new tab ctrl + t in Firefox 22962 controlPressed = e.ctrlKey; 22963 } 22964 } 22965 22966 //binding the mousemove when the mouse's middle button is released 22967 function mouseDownHandler(e){ 22968 //middle button 22969 if (e.which == 2){ 22970 oldPageY = e.pageY; 22971 container.on('mousemove', mouseMoveHandler); 22972 } 22973 } 22974 22975 //unbinding the mousemove when the mouse's middle button is released 22976 function mouseUpHandler(e){ 22977 //middle button 22978 if (e.which == 2){ 22979 container.off('mousemove'); 22980 } 22981 } 22982 22983 //Scrolling horizontally when clicking on the slider controls. 22984 function slideArrowHandler(){ 22985 var section = $(this).closest(SECTION_SEL); 22986 22987 if ($(this).hasClass(SLIDES_PREV)) { 22988 if(isScrollAllowed.m.left){ 22989 moveSlideLeft(section); 22990 } 22991 } else { 22992 if(isScrollAllowed.m.right){ 22993 moveSlideRight(section); 22994 } 22995 } 22996 } 22997 22998 //when opening a new tab (ctrl + t), `control` won't be pressed when coming back. 22999 function blurHandler(){ 23000 isWindowFocused = false;
23001 controlPressed = false; 23002 } 23003 23004 //Scrolls to the section when clicking the navigation bullet 23005 function sectionBulletHandler(e){ 23006 e.preventDefault(); 23007 var index = $(this).parent().index(); 23008 scrollPage($(SECTION_SEL).eq(index)); 23009 } 23010 23011 //Scrolls the slider to the given slide destination for the given section 23012 function slideBulletHandler(e){ 23013 e.preventDefault(); 23014 var slides = $(this).closest(SECTION_SEL).find(SLIDES_WRAPPER_SEL); 23015 var destiny = slides.find(SLIDE_SEL).eq($(this).closest('li').index()); 23016 23017 landscapeScroll(slides, destiny); 23018 } 23019 23020 /** 23021 * Keydown event 23022 */ 23023 function onkeydown(e){ 23024 var shiftPressed = e.shiftKey; 23025 23026 //do nothing if we can not scroll or we are not using horizotnal key arrows. 23027 if(!canScroll && [37,39].indexOf(e.which) < 0){ 23028 return; 23029 } 23030 23031 switch (e.which) { 23032 //up 23033 case 38: 23034 case 33: 23035 if(isScrollAllowed.k.up){ 23036 moveSectionUp(); 23037 } 23038 break; 23039 23040 //down 23041 case 32: //spacebar 23042 if(shiftPressed && isScrollAllowed.k.up){ 23043 moveSectionUp(); 23044 break; 23045 } 23046 /* falls through */ 23047 case 40: 23048 case 34: 23049 if(isScrollAllowed.k.down){ 23050 moveSectionDown(); 23051 } 23052 break; 23053 23054 //Home 23055 case 36: 23056 if(isScrollAllowed.k.up){ 23057 moveTo(1); 23058 } 23059 break; 23060 23061 //End 23062 case 35: 23063 if(isScrollAllowed.k.down){ 23064 moveTo( $(SECTION_SEL).length ); 23065 } 23066 break; 23067 23068 //left 23069 case 37: 23070 if(isScrollAllowed.k.left){ 23071 moveSlideLeft(); 23072 } 23073 break; 23074 23075 //right 23076 case 39: 23077 if(isScrollAllowed.k.right){ 23078 moveSlideRight(); 23079 } 23080 break; 23081 23082 default: 23083 return; // exit this handler for other keys 23084 } 23085 } 23086 23087 /** 23088 * Detecting the direction of the mouse movement. 23089 * Used only for the middle button of the mouse. 23090 */ 23091 var oldPageY = 0; 23092 function mouseMoveHandler(e){ 23093 if(canScroll){ 23094 // moving up 23095 if (e.pageY < oldPageY && isScrollAllowed.m.up){ 23096 moveSectionUp(); 23097 } 23098 23099 // moving down 23100 else if(e.pageY > oldPageY && isScrollAllowed.m.down){ 23101 moveSectionDown(); 23102 } 23103 } 23104 oldPageY = e.pageY; 23105 } 23106 23107 /** 23108 * Scrolls horizontal sliders. 23109 */ 23110 function landscapeScroll(slides, destiny, direction){ 23111 var section = slides.closest(SECTION_SEL); 23112 var v = { 23113 slides: slides, 23114 destiny: destiny, 23115 direction: direction, 23116 destinyPos: destiny.position(), 23117 slideIndex: destiny.index(), 23118 section: section, 23119 sectionIndex: section.index(SECTION_SEL), 23120 anchorLink: section.data('anchor'), 23121 slidesNav: section.find(SLIDES_NAV_SEL), 23122 slideAnchor: getAnchor(destiny), 23123 prevSlide: section.find(SLIDE_ACTIVE_SEL), 23124 prevSlideIndex: section.find(SLIDE_ACTIVE_SEL).index(), 23125 23126 //caching the value of isResizing at the momment the function is called 23127 //because it will be checked later inside a setTimeout and the value might change 23128 localIsResizing: isResizing 23129 }; 23130 v.xMovement = getXmovement(v.prevSlideIndex, v.slideIndex); 23131 v.direction = v.direction ? v.direction : v.xMovement; 23132 23133 //important!! Only do it when not resizing 23134 if(!v.localIsResizing){ 23135 //preventing from scrolling to the next/prev section when using scrollHorizontally 23136 canScroll = false;
23137 } 23138 23139 if(options.onSlideLeave){ 23140 23141 //if the site is not just resizing and readjusting the slides 23142 if(!v.localIsResizing && v.xMovement!=='none'){ 23143 if($.isFunction( options.onSlideLeave )){ 23144 if(options.onSlideLeave.call( v.prevSlide, v.anchorLink, (v.sectionIndex + 1), v.prevSlideIndex, v.xMovement, v.slideIndex ) === false){ 23145 slideMoving = false; 23146 return; 23147 } 23148 } 23149 } 23150 } 23151 23152 destiny.addClass(ACTIVE).siblings().removeClass(ACTIVE); 23153 23154 if(!v.localIsResizing){ 23155 stopMedia(v.prevSlide); 23156 lazyLoad(destiny); 23157 } 23158 23159 if(!options.loopHorizontal && options.controlArrows){ 23160 //hidding it for the fist slide, showing for the rest 23161 section.find(SLIDES_ARROW_PREV_SEL).toggle(v.slideIndex!==0); 23162 23163 //hidding it for the last slide, showing for the rest 23164 section.find(SLIDES_ARROW_NEXT_SEL).toggle(!destiny.is(':last-child')); 23165 } 23166 23167 //only changing the URL if the slides are in the current section (not for resize re-adjusting) 23168 if(section.hasClass(ACTIVE) && !v.localIsResizing){ 23169 setState(v.slideIndex, v.slideAnchor, v.anchorLink, v.sectionIndex); 23170 } 23171 23172 performHorizontalMove(slides, v, true); 23173 } 23174 23175 23176 function afterSlideLoads(v){ 23177 activeSlidesNavigation(v.slidesNav, v.slideIndex); 23178 23179 //if the site is not just resizing and readjusting the slides 23180 if(!v.localIsResizing){ 23181 $.isFunction( options.afterSlideLoad ) && options.afterSlideLoad.call( v.destiny, v.anchorLink, (v.sectionIndex + 1), v.slideAnchor, v.slideIndex); 23182 23183 //needs to be inside the condition to prevent problems with continuousVertical and scrollHorizontally 23184 //and to prevent double scroll right after a windows resize 23185 canScroll = true; 23186 23187 playMedia(v.destiny); 23188 } 23189 23190 //letting them slide again 23191 slideMoving = false; 23192 } 23193 23194 /** 23195 * Performs the horizontal movement. (CSS3 or jQuery) 23196 * 23197 * @param fireCallback {Bool} - determines whether or not to fire the callback 23198 */ 23199 function performHorizontalMove(slides, v, fireCallback){ 23200 var destinyPos = v.destinyPos; 23201 23202 if(options.css3){ 23203 var translate3d = 'translate3d(-' + Math.round(destinyPos.left) + 'px, 0px, 0px)'; 23204 23205 addAnimation(slides.find(SLIDES_CONTAINER_SEL)).css(getTransforms(translate3d), v); 23206 23207 afterSlideLoadsId = setTimeout(function(){ 23208 fireCallback && afterSlideLoads(v); 23209 }, options.scrollingSpeed, options.easing); 23210 }else{ 23211 slides.animate({ 23212 scrollLeft : Math.round(destinyPos.left) 23213 }, options.scrollingSpeed, options.easing, function() { 23214 23215 fireCallback && afterSlideLoads(v); 23216 }); 23217 } 23218 } 23219 23220 /** 23221 * Sets the state for the horizontal bullet navigations. 23222 */ 23223 function activeSlidesNavigation(slidesNav, slideIndex){ 23224 slidesNav.find(ACTIVE_SEL).removeClass(ACTIVE); 23225 slidesNav.find('li').eq(slideIndex).find('a').addClass(ACTIVE); 23226 } 23227 23228 var previousHeight = windowsHeight; 23229 23230 //when resizing the site, we adjust the heights of the sections, slimScroll... 23231 function resizeHandler(){ 23232 //checking if it needs to get responsive 23233 responsive(); 23234 23235 // rebuild immediately on touch devices 23236 if (isTouchDevice) { 23237 var activeElement = $(document.activeElement); 23238 23239 //if the keyboard is NOT visible 23240 if (!activeElement.is('textarea') && !activeElement.is('input') && !activeElement.is('select')) { 23241 var currentHeight = $window.height(); 23242 23243 //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) 23244 if( Math.abs(currentHeight - previousHeight) > (20 * Math.max(previousHeight, currentHeight) / 100) ){ 23245 reBuild(true); 23246 previousHeight = currentHeight; 23247 } 23248 } 23249 }else{ 23250 //in order to call the functions only when the resize is finished 23251 //http://stackoverflow.com/questions/4298612/jquery-how-to-call-resize-event-only-once-its-finished-resizing 23252 clearTimeout(resizeId); 23253 23254 resizeId = setTimeout(function(){ 23255 reBuild(true); 23256 }, 350); 23257 } 23258 } 23259 23260 /** 23261 * Checks if the site needs to get responsive and disables autoScrolling if so. 23262 * A class `fp-responsive` is added to the plugin's container in case the user wants to use it for his own responsive CSS. 23263 */ 23264 function responsive(){ 23265 var widthLimit = options.responsive || options.responsiveWidth; //backwards compatiblity 23266 var heightLimit = options.responsiveHeight; 23267 23268 //only calculating what we need. Remember its called on the resize event. 23269 var isBreakingPointWidth = widthLimit && $window.outerWidth() < widthLimit; 23270 var isBreakingPointHeight = heightLimit && $window.height() < heightLimit; 23271 23272 if(widthLimit && heightLimit){ 23273 setResponsive(isBreakingPointWidth || isBreakingPointHeight); 23274 } 23275 else if(widthLimit){ 23276 setResponsive(isBreakingPointWidth); 23277 } 23278 else if(heightLimit){ 23279 setResponsive(isBreakingPointHeight); 23280 } 23281 } 23282 23283 /** 23284 * Adds transition animations for the given element 23285 */ 23286 function addAnimation(container, element){ 23287 var transition = 'all ' + options.scrollingSpeed + 'ms ' + options.easingcss3; 23288 23289 container.removeClass(NO_TRANSITION); 23290 return container.css({
23291 '-webkit-transition': transition, 23292 'transition': transition 23293 }); 23294 } 23295 23296 /** 23297 * Remove transition animations for the given element 23298 */ 23299 function removeAnimation(element){ 23300 return element.addClass(NO_TRANSITION); 23301 } 23302 23303 /** 23304 * Activating the vertical navigation bullets according to the given slide name. 23305 */ 23306 function activateNavDots(name, sectionIndex){ 23307 if(options.navigation){ 23308 $(SECTION_NAV_SEL).find(ACTIVE_SEL).removeClass(ACTIVE); 23309 if(name){ 23310 $(SECTION_NAV_SEL).find('a[href="#' + name + '"]').addClass(ACTIVE); 23311 }else{ 23312 $(SECTION_NAV_SEL).find('li').eq(sectionIndex).find('a').addClass(ACTIVE); 23313 } 23314 } 23315 } 23316 23317 /** 23318 * Activating the website main menu elements according to the given slide name. 23319 */ 23320 function activateMenuElement(name){ 23321 if(options.menu){ 23322 $(options.menu).find(ACTIVE_SEL).removeClass(ACTIVE); 23323 $(options.menu).find('[data-menuanchor="'+name+'"]').addClass(ACTIVE); 23324 } 23325 } 23326 23327 /** 23328 * Sets to active the current menu and vertical nav items. 23329 */ 23330 function activateMenuAndNav(anchor, index){ 23331 activateMenuElement(anchor); 23332 activateNavDots(anchor, index); 23333 } 23334 23335 /** 23336 * Retuns `up` or `down` depending on the scrolling movement to reach its destination 23337 * from the current section. 23338 */ 23339 function getYmovement(destiny){ 23340 var fromIndex = $(SECTION_ACTIVE_SEL).index(SECTION_SEL); 23341 var toIndex = destiny.index(SECTION_SEL); 23342 if( fromIndex == toIndex){ 23343 return 'none'; 23344 } 23345 if(fromIndex > toIndex){ 23346 return 'up'; 23347 } 23348 return 'down'; 23349 } 23350 23351 /** 23352 * Retuns `right` or `left` depending on the scrolling movement to reach its destination 23353 * from the current slide. 23354 */ 23355 function getXmovement(fromIndex, toIndex){ 23356 if( fromIndex == toIndex){ 23357 return 'none'; 23358 } 23359 if(fromIndex > toIndex){ 23360 return 'left'; 23361 } 23362 return 'right'; 23363 } 23364 23365 /** 23366 * Checks if the element needs scrollbar and if the user wants to apply it. 23367 * If so it creates it. 23368 * 23369 * @param {Object} element jQuery object of the section or slide 23370 */ 23371 function createScrollBar(element){ 23372 //User doesn't want scrollbar here? Sayonara baby! 23373 if(element.hasClass('fp-noscroll')) return; 23374 23375 //needed to make `scrollHeight` work under Opera 12 23376 element.css('overflow', 'hidden'); 23377 23378 var scrollOverflowHandler = options.scrollOverflowHandler; 23379 var wrap = scrollOverflowHandler.wrapContent(); 23380 //in case element is a slide 23381 var section = element.closest(SECTION_SEL); 23382 var scrollable = scrollOverflowHandler.scrollable(element); 23383 var contentHeight; 23384 23385 //if there was scroll, the contentHeight will be the one in the scrollable section 23386 if(scrollable.length){ 23387 contentHeight = scrollOverflowHandler.scrollHeight(element); 23388 }else{ 23389 contentHeight = element.get(0).scrollHeight; 23390 if(options.verticalCentered){ 23391 contentHeight = element.find(TABLE_CELL_SEL).get(0).scrollHeight; 23392 } 23393 } 23394 23395 var scrollHeight = windowsHeight - parseInt(section.css('padding-bottom')) - parseInt(section.css('padding-top')); 23396 23397 //needs scroll? 23398 if ( contentHeight > scrollHeight) { 23399 //did we already have an scrollbar ? Updating it 23400 if(scrollable.length){ 23401 scrollOverflowHandler.update(element, scrollHeight); 23402 } 23403 //creating the scrolling 23404 else{ 23405 if(options.verticalCentered){ 23406 element.find(TABLE_CELL_SEL).wrapInner(wrap); 23407 }else{ 23408 element.wrapInner(wrap); 23409 } 23410 scrollOverflowHandler.create(element, scrollHeight); 23411 } 23412 } 23413 //removing the scrolling when it is not necessary anymore 23414 else{ 23415 scrollOverflowHandler.remove(element); 23416 } 23417 23418 //undo 23419 element.css('overflow', ''); 23420 } 23421 23422 function addTableClass(element){ 23423 //In case we are styling for the 2nd time as in with reponsiveSlides 23424 if(!element.hasClass(TABLE)){ 23425 element.addClass(TABLE).wrapInner('<div class="' + TABLE_CELL + '" style="height:' + getTableHeight(element) + 'px;" />'); 23426 } 23427 } 23428 23429 function getTableHeight(element){ 23430 var sectionHeight = windowsHeight; 23431 23432 if(options.paddingTop || options.paddingBottom){ 23433 var section = element; 23434 if(!section.hasClass(SECTION)){ 23435 section = element.closest(SECTION_SEL); 23436 } 23437 23438 var paddings = parseInt(section.css('padding-top')) + parseInt(section.css('padding-bottom')); 23439 sectionHeight = (windowsHeight - paddings); 23440 } 23441 23442 return sectionHeight; 23443 } 23444 23445 /** 23446 * Adds a css3 transform property to the container class with or without animation depending on the animated param. 23447 */ 23448 function transformContainer(translate3d, animated){ 23449 if(animated){ 23450 addAnimation(container); 23451 }else{ 23452 removeAnimation(container); 23453 } 23454 23455 container.css(getTransforms(translate3d)); 23456 23457 //syncronously removing the class after the animation has been applied. 23458 setTimeout(function(){ 23459 container.removeClass(NO_TRANSITION); 23460 },10); 23461 } 23462 23463 /** 23464 * Gets a section by its anchor / index 23465 */ 23466 function getSectionByAnchor(sectionAnchor){ 23467 if(!sectionAnchor) return []; 23468 23469 var section = container.find(SECTION_SEL + '[data-anchor="'+sectionAnchor+'"]'); 23470 if(!section.length){ 23471 section = $(SECTION_SEL).eq( sectionAnchor -1); 23472 } 23473 23474 return section; 23475 } 23476 23477 /** 23478 * Gets a slide inside a given section by its anchor / index 23479 */ 23480 function getSlideByAnchor(slideAnchor, section){ 23481 var slides = section.find(SLIDES_WRAPPER_SEL); 23482 var slide = slides.find(SLIDE_SEL + '[data-anchor="'+slideAnchor+'"]'); 23483
23484 if(!slide.length){ 23485 slide = slides.find(SLIDE_SEL).eq(slideAnchor); 23486 } 23487 23488 return slide; 23489 } 23490 23491 /** 23492 * Scrolls to the given section and slide anchors 23493 */ 23494 function scrollPageAndSlide(destiny, slide){ 23495 var section = getSectionByAnchor(destiny); 23496 23497 //do nothing if there's no section with the given anchor name 23498 if(!section.length) return; 23499 23500 //default slide 23501 if (typeof slide === 'undefined') { 23502 slide = 0; 23503 } 23504 23505 //we need to scroll to the section and then to the slide 23506 if (destiny !== lastScrolledDestiny && !section.hasClass(ACTIVE)){ 23507 scrollPage(section, function(){ 23508 scrollSlider(section, slide); 23509 }); 23510 } 23511 //if we were already in the section 23512 else{ 23513 scrollSlider(section, slide); 23514 } 23515 } 23516 23517 /** 23518 * Scrolls the slider to the given slide destination for the given section 23519 */ 23520 function scrollSlider(section, slideAnchor){ 23521 if(typeof slideAnchor !== 'undefined'){ 23522 var slides = section.find(SLIDES_WRAPPER_SEL); 23523 var destiny = getSlideByAnchor(slideAnchor, section); 23524 23525 if(destiny.length){ 23526 landscapeScroll(slides, destiny); 23527 } 23528 } 23529 } 23530 23531 /** 23532 * Creates a landscape navigation bar with dots for horizontal sliders. 23533 */ 23534 function addSlidesNavigation(section, numSlides){ 23535 section.append('<div class="' + SLIDES_NAV + '"><ul></ul></div>'); 23536 var nav = section.find(SLIDES_NAV_SEL); 23537 23538 //top or bottom 23539 nav.addClass(options.slidesNavPosition); 23540 23541 for(var i=0; i< numSlides; i++){ 23542 nav.find('ul').append('<li><a href="#"><span></span></a></li>'); 23543 } 23544 23545 //centering it 23546 nav.css('margin-left', '-' + (nav.width()/2) + 'px'); 23547 23548 nav.find('li').first().find('a').addClass(ACTIVE); 23549 } 23550 23551 23552 /** 23553 * Sets the state of the website depending on the active section/slide. 23554 * It changes the URL hash when needed and updates the body class. 23555 */ 23556 function setState(slideIndex, slideAnchor, anchorLink, sectionIndex){ 23557 var sectionHash = ''; 23558 23559 if(options.anchors.length && !options.lockAnchors){ 23560 23561 //isn't it the first slide? 23562 if(slideIndex){ 23563 if(typeof anchorLink !== 'undefined'){ 23564 sectionHash = anchorLink; 23565 } 23566 23567 //slide without anchor link? We take the index instead. 23568 if(typeof slideAnchor === 'undefined'){ 23569 slideAnchor = slideIndex; 23570 } 23571 23572 lastScrolledSlide = slideAnchor; 23573 setUrlHash(sectionHash + '/' + slideAnchor); 23574 23575 //first slide won't have slide anchor, just the section one 23576 }else if(typeof slideIndex !== 'undefined'){ 23577 lastScrolledSlide = slideAnchor; 23578 setUrlHash(anchorLink); 23579 } 23580 23581 //section without slides 23582 else{ 23583 setUrlHash(anchorLink); 23584 } 23585 } 23586 23587 setBodyClass(); 23588 } 23589 23590 /** 23591 * Sets the URL hash. 23592 */ 23593 function setUrlHash(url){ 23594 //Uncode addition 23595 if ( typeof SiteParameters.slide_footer != 'undefined' && url == SiteParameters.slide_footer ) 23596 return false; 23597 23598 if(options.recordHistory){ 23599 location.hash = url; 23600 }else{ 23601 //Uncode addition 23602 //Mobile Chrome doesn't work the normal way, so... lets use HTML5 for phones :) 23603 // if(isTouchDevice || isTouch){ 23604 // window.history.replaceState(undefined, undefined, '#' + url); 23605 // }else{ 23606 // var baseUrl = window.location.href.split('#')[0]; 23607 // window.location.replace( baseUrl + '#' + url ); 23608 // } 23609 return false;
23610 } 23611 } 23612 23613 /** 23614 * Gets the anchor for the given slide / section. Its index will be used if there's none. 23615 */ 23616 function getAnchor(element){ 23617 var anchor = element.data('anchor'); 23618 var index = element.index(); 23619 23620 //Slide without anchor link? We take the index instead. 23621 if(typeof anchor === 'undefined'){ 23622 anchor = index; 23623 } 23624 23625 return anchor; 23626 } 23627 23628 /** 23629 * Sets a class for the body of the page depending on the active section / slide 23630 */ 23631 function setBodyClass(){ 23632 var section = $(SECTION_ACTIVE_SEL); 23633 var slide = section.find(SLIDE_ACTIVE_SEL); 23634 23635 var sectionAnchor = getAnchor(section); 23636 var slideAnchor = getAnchor(slide); 23637 23638 var text = String(sectionAnchor); 23639 23640 if(slide.length){ 23641 text = text + '-' + slideAnchor; 23642 } 23643 23644 //changing slash for dash to make it a valid CSS style 23645 text = text.replace('/', '-').replace('#',''); 23646 23647 //removing previous anchor classes 23648 var classRe = new RegExp('\\b\\s?' + VIEWING_PREFIX + '-[^\\s]+\\b', "g"); 23649 $body[0].className = $body[0].className.replace(classRe, ''); 23650 23651 //adding the current anchor 23652 $body.addClass(VIEWING_PREFIX + '-' + text); 23653 } 23654 23655 /** 23656 * Checks for translate3d support 23657 * @return boolean 23658 * http://stackoverflow.com/questions/5661671/detecting-transform-translate3d-support 23659 */ 23660 function support3d() { 23661 var el = document.createElement('p'), 23662 has3d, 23663 transforms = { 23664 'webkitTransform':'-webkit-transform', 23665 'OTransform':'-o-transform', 23666 'msTransform':'-ms-transform', 23667 'MozTransform':'-moz-transform', 23668 'transform':'transform' 23669 }; 23670 23671 // Add it to the body to get the computed style. 23672 document.body.insertBefore(el, null); 23673 23674 for (var t in transforms) { 23675 if (el.style[t] !== undefined) { 23676 el.style[t] = 'translate3d(1px,1px,1px)'; 23677 has3d = window.getComputedStyle(el).getPropertyValue(transforms[t]); 23678 } 23679 } 23680 23681 document.body.removeChild(el); 23682 23683 return (has3d !== undefined && has3d.length > 0 && has3d !== 'none'); 23684 } 23685 23686 /** 23687 * Removes the auto scrolling action fired by the mouse wheel and trackpad. 23688 * After this function is called, the mousewheel and trackpad movements won't scroll through sections. 23689 */ 23690 function removeMouseWheelHandler(){ 23691 if (document.addEventListener) { 23692 document.removeEventListener('mousewheel', MouseWheelHandler, false); //IE9, Chrome, Safari, Oper 23693 document.removeEventListener('wheel', MouseWheelHandler, false); //Firefox 23694 document.removeEventListener('MozMousePixelScroll', MouseWheelHandler, false); //old Firefox 23695 } else { 23696 document.detachEvent('onmousewheel', MouseWheelHandler); //IE 6/7/8 23697 } 23698 } 23699 23700 /** 23701 * Adds the auto scrolling action for the mouse wheel and trackpad. 23702 * After this function is called, the mousewheel and trackpad movements will scroll through sections 23703 * https://developer.mozilla.org/en-US/docs/Web/Events/wheel 23704 */ 23705 function addMouseWheelHandler(){ 23706 var prefix = ''; 23707 var _addEventListener; 23708 23709 if (window.addEventListener){ 23710 _addEventListener = "addEventListener"; 23711 }else{ 23712 _addEventListener = "attachEvent"; 23713 prefix = 'on'; 23714 } 23715 23716 // detect available wheel event 23717 var support = 'onwheel' in document.createElement('div') ? 'wheel' : // Modern browsers support "wheel" 23718 document.onmousewheel !== undefined ? 'mousewheel' : // Webkit and IE support at least "mousewheel" 23719 'DOMMouseScroll'; // let's assume that remaining browsers are older Firefox 23720 var passiveEvent = g_supportsPassive ? {passive: false }
23720: false; 23721 23722 23723 if(support == 'DOMMouseScroll'){ 23724 document[ _addEventListener ](prefix + 'MozMousePixelScroll', MouseWheelHandler, passiveEvent); 23725 } 23726 23727 //handle MozMousePixelScroll in older Firefox 23728 else{ 23729 document[ _addEventListener ](prefix + support, MouseWheelHandler, passiveEvent); 23730 } 23731 } 23732 23733 /** 23734 * Binding the mousemove when the mouse's middle button is pressed 23735 */ 23736 function addMiddleWheelHandler(){ 23737 container 23738 .on('mousedown', mouseDownHandler) 23739 .on('mouseup', mouseUpHandler); 23740 } 23741 23742 /** 23743 * Unbinding the mousemove when the mouse's middle button is released 23744 */ 23745 function removeMiddleWheelHandler(){ 23746 container 23747 .off('mousedown', mouseDownHandler) 23748 .off('mouseup', mouseUpHandler); 23749 } 23750 23751 /** 23752 * Adds the possibility to auto scroll through sections on touch devices. 23753 */ 23754 function addTouchHandler(){ 23755 if(isTouchDevice || isTouch){ 23756 if(options.autoScrolling){ 23757 $body.off(events.touchmove).on(events.touchmove, preventBouncing); 23758 } 23759 23760 $(WRAPPER_SEL) 23761 .off(events.touchstart).on(events.touchstart, touchStartHandler) 23762 .off(events.touchmove).on(events.touchmove, touchMoveHandler); 23763 } 23764 } 23765 23766 /** 23767 * Removes the auto scrolling for touch devices. 23768 */ 23769 function removeTouchHandler(){ 23770 if(isTouchDevice || isTouch){ 23771 $(WRAPPER_SEL) 23772 .off(events.touchstart) 23773 .off(events.touchmove); 23774 } 23775 } 23776 23777 /* 23778 * Returns and object with Microsoft pointers (for IE<11 and for IE >= 11) 23779 * http://msdn.microsoft.com/en-us/library/ie/dn304886(v=vs.85).aspx 23780 */ 23781 function getMSPointer(){ 23782 var pointer; 23783 23784 //IE >= 11 & rest of browsers 23785 if(window.PointerEvent){ 23786 pointer = { down: 'pointerdown', move: 'pointermove'}; 23787 } 23788 23789 //IE < 11 23790 else{ 23791 pointer = { down: 'MSPointerDown', move: 'MSPointerMove'}; 23792 } 23793 23794 return pointer; 23795 } 23796 23797 /** 23798 * Gets the pageX and pageY properties depending on the browser. 23799 * https://github.com/alvarotrigo/fullPage.js/issues/194#issuecomment-34069854 23800 */ 23801 function getEventsPage(e){ 23802 var events = []; 23803 23804 events.y = (typeof e.pageY !== 'undefined' && (e.pageY || e.pageX) ? e.pageY : e.touches[0].pageY); 23805 events.x = (typeof e.pageX !== 'undefined' && (e.pageY || e.pageX) ? e.pageX : e.touches[0].pageX); 23806 23807 //in touch devices with scrollBar:true, e.pageY is detected, but we have to deal with touch events. #1008 23808 if(isTouch && isReallyTouch(e) && options.scrollBar){ 23809 events.y = e.touches[0].pageY; 23810 events.x = e.touches[0].pageX; 23811 } 23812 23813 return events; 23814 } 23815 23816 /** 23817 * Slides silently (with no animation) the active slider to the given slide. 23818 * @param noCallback {bool} true or defined -> no callbacks 23819 */ 23820 function silentLandscapeScroll(activeSlide, noCallbacks){ 23821 setScrollingSpeed (0, 'internal'); 23822 23823 if(typeof noCallbacks !== 'undefined'){ 23824 //preventing firing callbacks afterSlideLoad etc. 23825 isResizing = true; 23826 } 23827 23828 landscapeScroll(activeSlide.closest(SLIDES_WRAPPER_SEL), activeSlide); 23829 23830 if(typeof noCallbacks !== 'undefined'){ 23831 isResizing = false; 23832 } 23833 23834 setScrollingSpeed(originals.scrollingSpeed, 'internal'); 23835 } 23836 23837 /** 23838 * Scrolls silently (with no animation) the page to the given Y position. 23839 */ 23840 function silentScroll(top){ 23841 // The first section can have a negative value in iOS 10. Not quite sure why: -0.0142822265625 23842 // that's why we round it to 0. 23843 var roundedTop = Math.round(top); 23844 23845 if (options.css3 && options.autoScrolling && !options.scrollBar){ 23846 var translate3d = 'translate3d(0px, -' + roundedTop + 'px, 0px)'; 23847 transformContainer(translate3d, false); 23848 } 23849 else if(options.autoScrolling && !options.scrollBar){ 23850 container.css('top', -roundedTop); 23851 } 23852 else{ 23853 $htmlBody.scrollTop(roundedTop); 23854 } 23855 } 23856 23857 /** 23858 * Returns the cross-browser transform string. 23859 */ 23860 function getTransforms(translate3d){ 23861 return {
23862 '-webkit-transform': translate3d, 23863 '-moz-transform': translate3d, 23864 '-ms-transform':translate3d, 23865 'transform': translate3d 23866 }; 23867 } 23868 23869 /** 23870 * Allowing or disallowing the mouse/swipe scroll in a given direction. (not for keyboard) 23871 * @type m (mouse) or k (keyboard) 23872 */ 23873 function setIsScrollAllowed(value, direction, type){ 23874 switch (direction){ 23875 case 'up': isScrollAllowed[type].up = value; break; 23876 case 'down': isScrollAllowed[type].down = value; break; 23877 case 'left': isScrollAllowed[type].left = value; break; 23878 case 'right': isScrollAllowed[type].right = value; break; 23879 case 'all': 23880 if(type == 'm'){ 23881 setAllowScrolling(value); 23882 }else{ 23883 setKeyboardScrolling(value); 23884 } 23885 } 23886 } 23887 23888 /* 23889 * Destroys fullpage.js plugin events and optinally its html markup and styles 23890 */ 23891 function destroy(all){ 23892 setAutoScrolling(false, 'internal'); 23893 setAllowScrolling(false); 23894 setKeyboardScrolling(false); 23895 container.addClass(DESTROYED); 23896 23897 clearTimeout(afterSlideLoadsId); 23898 clearTimeout(afterSectionLoadsId); 23899 clearTimeout(resizeId); 23900 clearTimeout(scrollId); 23901 clearTimeout(scrollId2); 23902 23903 $window 23904 .off('scroll', scrollHandler) 23905 .off('hashchange', hashChangeHandler) 23906 .off('resize', resizeHandler); 23907 23908 $document 23909 .off('click touchstart', SECTION_NAV_SEL + ' a') 23910 .off('mouseenter', SECTION_NAV_SEL + ' li') 23911 .off('mouseleave', SECTION_NAV_SEL + ' li') 23912 .off('click touchstart', SLIDES_NAV_LINK_SEL) 23913 .off('mouseover', options.normalScrollElements) 23914 .off('mouseout', options.normalScrollElements); 23915 23916 $(SECTION_SEL) 23917 .off('click touchstart', SLIDES_ARROW_SEL); 23918 23919 clearTimeout(afterSlideLoadsId); 23920 clearTimeout(afterSectionLoadsId); 23921 23922 //lets make a mess! 23923 if(all){ 23924 destroyStructure(); 23925 } 23926 } 23927 23928 /* 23929 * Removes inline styles added by fullpage.js 23930 */ 23931 function destroyStructure(){ 23932 //reseting the `top` or `translate` properties to 0 23933 silentScroll(0); 23934 23935 //loading all the lazy load content 23936 container.find('img[data-src], source[data-src], audio[data-src], iframe[data-src]').each(function(){ 23937 setSrc($(this), 'src'); 23938 }); 23939 23940 container.find('img[data-srcset]').each(function(){ 23941 setSrc($(this), 'srcset'); 23942 }); 23943 23944 $(SECTION_NAV_SEL + ', ' + SLIDES_NAV_SEL + ', ' + SLIDES_ARROW_SEL).remove(); 23945 23946 //removing inline styles 23947 $(SECTION_SEL).css( { 23948 'height': '', 23949 'background-color' : '', 23950 'padding': '' 23951 }); 23952 23953 $(SLIDE_SEL).css( { 23954 'width': '' 23955 }); 23956 23957 container.css({ 23958 'height': '', 23959 'position': '', 23960 '-ms-touch-action': '', 23961 'touch-action': '' 23962 }); 23963 23964 $htmlBody.css({ 23965 'overflow': '', 23966 'height': '' 23967 }); 23968 23969 // remove .fp-enabled class 23970 $('html').removeClass(ENABLED); 23971 23972 // remove .fp-responsive class 23973 $body.removeClass(RESPONSIVE); 23974 23975 // remove all of the .fp-viewing- classes 23976 $.each($body.get(0).className.split(/\s+/), function (index, className) { 23977 if (className.indexOf(VIEWING_PREFIX) === 0) { 23978 $body.removeClass(className); 23979 } 23980 }); 23981 23982 //removing added classes 23983 $(SECTION_SEL + ', ' + SLIDE_SEL).each(function(){ 23984 options.scrollOverflowHandler.remove($(this)); 23985 $(this).removeClass(TABLE + ' ' + ACTIVE); 23986 }); 23987 23988 removeAnimation(container); 23989 23990 //Unwrapping content 23991 container.find(TABLE_CELL_SEL + ', ' + SLIDES_CONTAINER_SEL + ', ' + SLIDES_WRAPPER_SEL).each(function(){ 23992 //unwrap not being use in case there's no child element inside and its just text 23993 $(this).replaceWith(this.childNodes); 23994 }); 23995 23996 //removing the applied transition from the fullpage wrapper 23997 container.css({
23998 '-webkit-transition': 'none', 23999 'transition': 'none' 24000 }); 24001 24002 //scrolling the page to the top with no animation 24003 $htmlBody.scrollTop(0); 24004 24005 //removing selectors 24006 var usedSelectors = [SECTION, SLIDE, SLIDES_CONTAINER]; 24007 $.each(usedSelectors, function(index, value){ 24008 $('.' + value).removeClass(value); 24009 }); 24010 } 24011 24012 /* 24013 * Sets the state for a variable with multiple states (original, and temporal) 24014 * Some variables such as `autoScrolling` or `recordHistory` might change automatically its state when using `responsive` or `autoScrolling:false`. 24015 * This function is used to keep track of both states, the original and the temporal one. 24016 * If type is not 'internal', then we assume the user is globally changing the variable. 24017 */ 24018 function setVariableState(variable, value, type){ 24019 options[variable] = value; 24020 if(type !== 'internal'){ 24021 originals[variable] = value; 24022 } 24023 } 24024 24025 /** 24026 * Displays warnings 24027 */ 24028 function displayWarnings(){ 24029 var extensions = ['fadingEffect', 'continuousHorizontal', 'scrollHorizontally', 'interlockedSlides', 'resetSliders', 'responsiveSlides', 'offsetSections', 'dragAndMove', 'scrollOverflowReset', 'parallax']; 24030 //UNCODE.addition 24031 // if($('html').hasClass(ENABLED)){ 24032 // showError('error', 'Fullpage.js can only be initialized once and you are doing it multiple times!'); 24033 // return; 24034 // } 24035 24036 // Disable mutually exclusive settings 24037 //UNCODE.addition 24038 // if (options.continuousVertical && 24039 // (options.loopTop || options.loopBottom)) { 24040 // options.continuousVertical = false;
24041 // showError('warn', 'Option `loopTop/loopBottom` is mutually exclusive with `continuousVertical`; `continuousVertical` disabled'); 24042 // } 24043 24044 // if(options.scrollBar && options.scrollOverflow){ 24045 // showError('warn', 'Option `scrollBar` is mutually exclusive with `scrollOverflow`. Sections with scrollOverflow might not work well in Firefox'); 24046 // } 24047 24048 // if(options.continuousVertical && (options.scrollBar || !options.autoScrolling)){ 24049 // options.continuousVertical = false; 24050 // showError('warn', 'Scroll bars (`scrollBar:true` or `autoScrolling:false`) are mutually exclusive with `continuousVertical`; `continuousVertical` disabled'); 24051 // } 24052 24053 //using extensions? Wrong file! 24054 $.each(extensions, function(index, extension){ 24055 //is the option set to true? 24056 if(options[extension]){ 24057 showError('warn', 'fullpage.js extensions require jquery.fullpage.extensions.min.js file instead of the usual jquery.fullpage.js. Requested: '+ extension); 24058 } 24059 }); 24060 24061 //anchors can not have the same value as any element ID or NAME 24062 $.each(options.anchors, function(index, name){ 24063 24064 //case insensitive selectors (http://stackoverflow.com/a/19465187/1081396) 24065 var nameAttr = $document.find('[name]').filter(function() { 24066 return $(this).attr('name') && $(this).attr('name').toLowerCase() == name.toLowerCase(); 24067 }); 24068 24069 var idAttr = $document.find('[id]').filter(function() { 24070 return $(this).attr('id') && $(this).attr('id').toLowerCase() == name.toLowerCase(); 24071 }); 24072 24073 if(idAttr.length || nameAttr.length ){ 24074 showError('error', 'data-anchor tags can not have the same value as any `id` element on the site (or `name` element for IE).'); 24075 idAttr.length && showError('error', '"' + name + '" is is being used by another element `id` property'); 24076 nameAttr.length && showError('error', '"' + name + '" is is being used by another element `name` property'); 24077 } 24078 }); 24079 } 24080 24081 /** 24082 * Shows a message in the console of the given type. 24083 */ 24084 function showError(type, text){ 24085 console && console[type] && console[type]('fullPage: ' + text); 24086 } 24087 24088 }; //end of $.fn.fullpage 24089 24090 if(typeof IScroll !== 'undefined'){ 24091 /* 24092 * Turns iScroll `mousewheel` option off dynamically 24093 * https://github.com/cubiq/iscroll/issues/1036 24094 */ 24095 IScroll.prototype.wheelOn = function () { 24096 this.wrapper.addEventListener('wheel', this); 24097 this.wrapper.addEventListener('mousewheel', this); 24098 this.wrapper.addEventListener('DOMMouseScroll', this); 24099 }; 24100 24101 /* 24102 * Turns iScroll `mousewheel` option on dynamically 24103 * https://github.com/cubiq/iscroll/issues/1036 24104 */ 24105 IScroll.prototype.wheelOff = function () { 24106 this.wrapper.removeEventListener('wheel', this); 24107 this.wrapper.removeEventListener('mousewheel', this); 24108 this.wrapper.removeEventListener('DOMMouseScroll', this); 24109 }; 24110 } 24111 24112 /** 24113 * An object to handle overflow scrolling. 24114 * This uses jquery.slimScroll to accomplish overflow scrolling. 24115 * It is possible to pass in an alternate scrollOverflowHandler 24116 * to the fullpage.js option that implements the same functions 24117 * as this handler. 24118 * 24119 * @type {Object} 24120 */ 24121 var iscrollHandler = { 24122 refreshId: null, 24123 iScrollInstances: [], 24124 24125 // Enables or disables the mouse wheel for the active section or all slides in it 24126 toggleWheel: function(value){ 24127 var scrollable = $(SECTION_ACTIVE_SEL).find(SCROLLABLE_SEL); 24128 scrollable.each(function(){ 24129 var iScrollInstance = $(this).data('iscrollInstance'); 24130 if(typeof iScrollInstance !== 'undefined' && iScrollInstance){ 24131 if(value){ 24132 iScrollInstance.wheelOn(); 24133 } 24134 else{ 24135 iScrollInstance.wheelOff(); 24136 } 24137 } 24138 }); 24139 }, 24140 24141 /** 24142 * Turns off iScroll for the destination section. 24143 * When scrolling very fast on some trackpads (and Apple laptops) the inertial scrolling would
24144 * scroll the destination section/slide before the sections animations ends. 24145 */ 24146 onLeave: function(){ 24147 iscrollHandler.toggleWheel(false); 24148 }, 24149 24150 // Turns off iScroll for the leaving section 24151 beforeLeave: function(){ 24152 iscrollHandler.onLeave() 24153 }, 24154 24155 // Turns on iScroll on section load 24156 afterLoad: function(){ 24157 iscrollHandler.toggleWheel(true); 24158 }, 24159 24160 /** 24161 * Called when overflow scrolling is needed for a section. 24162 * 24163 * @param {Object} element jQuery object containing current section 24164 * @param {Number} scrollHeight Current window height in pixels 24165 */ 24166 create: function(element, scrollHeight) { 24167 var scrollable = element.find(SCROLLABLE_SEL); 24168 24169 scrollable.height(scrollHeight); 24170 scrollable.each(function() { 24171 var $this = $(this); 24172 var iScrollInstance = $this.data('iscrollInstance'); 24173 if (iScrollInstance) { 24174 $.each(iscrollHandler.iScrollInstances, function(){ 24175 $(this).destroy(); 24176 }); 24177 } 24178 24179 iScrollInstance = new IScroll($this.get(0), iscrollOptions); 24180 iscrollHandler.iScrollInstances.push(iScrollInstance); 24181 24182 //off by default until the section gets active 24183 iScrollInstance.wheelOff(); 24184 24185 $this.data('iscrollInstance', iScrollInstance); 24186 }); 24187 }, 24188 24189 /** 24190 * Return a boolean depending on whether the scrollable element is a 24191 * the end or at the start of the scrolling depending on the given type. 24192 * 24193 * @param {String} type Either 'top' or 'bottom' 24194 * @param {Object} scrollable jQuery object for the scrollable element 24195 * @return {Boolean} 24196 */ 24197 isScrolled: function(type, scrollable) { 24198 var scroller = scrollable.data('iscrollInstance'); 24199 24200 //no scroller? 24201 if (!scroller) { 24202 return true; 24203 } 24204 24205 if (type === 'top') { 24206 return scroller.y >= 0 && !scrollable.scrollTop(); 24207 } else if (type === 'bottom') { 24208 return (0 - scroller.y) + scrollable.scrollTop() + 1 + scrollable.innerHeight() >= scrollable[0].scrollHeight; 24209 } 24210 }, 24211 24212 /** 24213 * Returns the scrollable element for the given section. 24214 * If there are landscape slides, will only return a scrollable element 24215 * if it is in the active slide. 24216 * 24217 * @param {Object} activeSection jQuery object containing current section 24218 * @return {Boolean} 24219 */ 24220 scrollable: function(activeSection){ 24221 // if there are landscape slides, we check if the scrolling bar is in the current one or not 24222 if (activeSection.find(SLIDES_WRAPPER_SEL).length) { 24223 return activeSection.find(SLIDE_ACTIVE_SEL).find(SCROLLABLE_SEL); 24224 } 24225 return activeSection.find(SCROLLABLE_SEL); 24226 }, 24227 24228 /** 24229 * Returns the scroll height of the wrapped content. 24230 * If this is larger than the window height minus section padding, 24231 * overflow scrolling is needed. 24232 * 24233 * @param {Object} element jQuery object containing current section 24234 * @return {Number} 24235 */ 24236 scrollHeight: function(element) { 24237 return element.find(SCROLLABLE_SEL).children().first().get(0).scrollHeight; 24238 }, 24239 24240 /** 24241 * Called when overflow scrolling is no longer needed for a section. 24242 * 24243 * @param {Object} element jQuery object containing current section 24244 */ 24245 remove: function(element) { 24246 var scrollable = element.find(SCROLLABLE_SEL); 24247 if (scrollable.length) { 24248 var iScrollInstance = scrollable.data('iscrollInstance'); 24249 iScrollInstance.destroy(); 24250 24251 scrollable.data('iscrollInstance', null); 24252 } 24253 element.find(SCROLLABLE_SEL).children().first().children().first().unwrap().unwrap(); 24254 }, 24255 24256 /** 24257 * Called when overflow scrolling has already been setup but the 24258 * window height has potentially changed. 24259 * 24260 * @param {Object}
vendor: 16,384 bytes, lines 24260-24803
24260 element jQuery object containing current section 24261 * @param {Number} scrollHeight Current window height in pixels 24262 */ 24263 update: function(element, scrollHeight) { 24264 //using a timeout in order to execute the refresh function only once when `update` is called multiple times in a 24265 //short period of time. 24266 //it also comes on handy because iScroll requires the use of timeout when using `refresh`. 24267 clearTimeout(iscrollHandler.refreshId); 24268 iscrollHandler.refreshId = setTimeout(function(){ 24269 $.each(iscrollHandler.iScrollInstances, function(){ 24270 $(this).get(0).refresh(); 24271 }); 24272 }, 150); 24273 24274 //updating the wrappers height 24275 element.find(SCROLLABLE_SEL).css('height', scrollHeight + 'px').parent().css('height', scrollHeight + 'px'); 24276 }, 24277 24278 /** 24279 * Called to get any additional elements needed to wrap the section 24280 * content in order to facilitate overflow scrolling. 24281 * 24282 * @return {String|Object} Can be a string containing HTML, 24283 * a DOM element, or jQuery object. 24284 */ 24285 wrapContent: function() { 24286 return '<div class="' + SCROLLABLE + '"><div class="fp-scroller"></div></div>'; 24287 } 24288 }; 24289}); 24290 24291/* ======================================================================== 24292 * Bootstrap: collapse.js v3.1.1 24293 * http://getbootstrap.com/javascript/#collapse 24294 * ======================================================================== 24295 * Copyright 2011-2014 Twitter, Inc. 24296 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 24297 * ======================================================================== */ 24298 24299 24300+function ($) { 24301 'use strict'; 24302 24303 // COLLAPSE PUBLIC CLASS DEFINITION 24304 // ================================ 24305 24306 var Collapse = function (element, options) { 24307 this.$element = $(element) 24308 this.options = $.extend({}, Collapse.DEFAULTS, options) 24309 this.transitioning = null 24310 24311 if (this.options.parent) this.$parent = $(this.options.parent) 24312 if (this.options.toggle) this.toggle() 24313 } 24314 24315 Collapse.DEFAULTS = { 24316 toggle: true 24317 } 24318 24319 Collapse.prototype.dimension = function () { 24320 var hasWidth = this.$element.hasClass('width') 24321 return hasWidth ? 'width' : 'height' 24322 } 24323 24324 Collapse.prototype.show = function () { 24325 if (this.transitioning || this.$element.hasClass('in')) return 24326 24327 var startEvent = $.Event('show.bs.collapse') 24328 this.$element.trigger(startEvent) 24329 if (startEvent.isDefaultPrevented()) return 24330 24331 var actives = this.$parent && this.$parent.find('> .panel > .in') 24332 24333 if (actives && actives.length) { 24334 var hasData = actives.data('bs.collapse') 24335 if (hasData && hasData.transitioning) return 24336 actives.collapse('hide') 24337 hasData || actives.data('bs.collapse', null) 24338 } 24339 24340 var dimension = this.dimension() 24341 24342 this.$element 24343 .removeClass('collapse') 24344 .addClass('collapsing')[dimension](0) 24345 24346 this.transitioning = 1 24347 24348 var complete = function (e) { 24349 if (e && e.target != this.$element[0]) return 24350 this.$element 24351 .removeClass('collapsing') 24352 .addClass('collapse in')[dimension]('auto') 24353 this.transitioning = 0 24354 this.$element.trigger('shown.bs.collapse') 24355 } 24356 24357 if (!$.support.transition) return complete.call(this) 24358 24359 var scrollSize = $.camelCase(['scroll', dimension].join('-')) 24360 24361 this.$element 24362 .one($.support.transition.end, $.proxy(complete, this)) 24363 .emulateTransitionEnd(350)[dimension](this.$element[0][scrollSize]) 24364 } 24365 24366 Collapse.prototype.hide = function () { 24367 if (this.transitioning || !this.$element.hasClass('in')) return 24368 24369 var startEvent = $.Event('hide.bs.collapse') 24370 this.$element.trigger(startEvent) 24371 if (startEvent.isDefaultPrevented()) return 24372 24373 var dimension = this.dimension() 24374 24375 this.$element[dimension](this.$element[dimension]())[0].offsetHeight 24376 24377 this.$element 24378 .addClass('collapsing') 24379 .removeClass('collapse') 24380 .removeClass('in') 24381 24382 this.transitioning = 1 24383 24384 var complete = function (e) { 24385 if (e && e.target != this.$element[0]) return 24386 this.transitioning = 0 24387 this.$element 24388 .trigger('hidden.bs.collapse') 24389 .removeClass('collapsing') 24390 .addClass('collapse') 24391 } 24392 24393 if (!$.support.transition) return complete.call(this) 24394 24395 this.$element 24396 [dimension](0) 24397 .one($.support.transition.end, $.proxy(complete, this)) 24398 .emulateTransitionEnd(350) 24399 } 24400 24401 Collapse.prototype.toggle = function () { 24402 this[this.$element.hasClass('in') ? 'hide' : 'show']() 24403 } 24404 24405 24406 // COLLAPSE PLUGIN DEFINITION 24407 // ========================== 24408 24409 var old = $.fn.collapse 24410 24411 $.fn.collapse = function (option) { 24412 return this.each(function () { 24413 var $this = $(this) 24414 var data = $this.data('bs.collapse') 24415 var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) 24416 24417 if (!data && options.toggle && option == 'show') option = !option 24418 if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) 24419 if (typeof option == 'string') data[option]() 24420 }) 24421 } 24422 24423 $.fn.collapse.Constructor = Collapse 24424 24425 24426 // COLLAPSE NO CONFLICT 24427 // ==================== 24428 24429 $.fn.collapse.noConflict = function () { 24430 $.fn.collapse = old 24431 return this 24432 } 24433 24434 24435 // COLLAPSE DATA-API 24436 // ================= 24437 24438 $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) { 24439 var $this = $(this), href 24440 var target = $this.attr('data-target') 24441 || e.preventDefault() 24442 || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 24443 //Edited by Uncode to replace ID in panel [START] 24444 var _target = href.replace(/^#/, ""); 24445 if ( $('[data-id="' + _target + '"]').length ) { 24446 var $target = $('[data-id="' + _target + '"]') 24447 } else { 24448 var $target = $(target) 24449 } 24450 //Edited by Uncode to replace ID in panel [END] 24451 var data = $target.data('bs.collapse') 24452 var option = data ? 'toggle' : $this.data() 24453 var parent = $this.attr('data-parent') 24454 var $parent = parent && $(parent) 24455 24456 if (!data || !data.transitioning) { 24457 if ($parent) $parent.find('[data-toggle="collapse"][data-parent="' + parent + '"]').not($this).addClass('collapsed') 24458 $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed') 24459 } 24460 24461 $target.collapse(option) 24462 }) 24463 24464}(jQuery); 24465 24466/* ======================================================================== 24467 * Bootstrap: tab.js v3.1.1 24468 * http://getbootstrap.com/javascript/#tabs 24469 * ======================================================================== 24470 * Copyright 2011-2014 Twitter, Inc. 24471 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 24472 * ======================================================================== */ 24473 24474 24475+function ($) { 24476 'use strict'; 24477 24478 // TAB CLASS DEFINITION 24479 // ==================== 24480 24481 var Tab = function (element) { 24482 this.element = $(element) 24483 } 24484 24485 Tab.prototype.show = function () { 24486 var $this = this.element 24487 var $ul = $this.closest('ul:not(.dropdown-menu)') 24488 var selector = $this.data('target') 24489 24490 if (!selector) { 24491 selector = $this.attr('href') 24492 selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 24493 } 24494 24495 if ($this.parent('li').hasClass('active')) return 24496 24497 var previous = $ul.find('.active:last a')[0] 24498 var e = $.Event('show.bs.tab', { 24499 relatedTarget: previous 24500 }) 24501 24502 $this.trigger(e) 24503 24504 if (e.isDefaultPrevented()) return 24505 24506 //Edited by Uncode to replace ID in panel [START] 24507 var _target = selector.replace(/^#/, ""); 24508 if ( $('[data-id="' + _target + '"]').length ) 24509 var $target = $('[data-id="' + _target + '"]') 24510 else 24511 var $target = $(selector) 24512 //Edited by Uncode to replace ID in panel [END] 24513 24514 this.activate($this.parent('li'), $ul) 24515 this.activate($target, $target.parent(), function () { 24516 $this.trigger({ 24517 type: 'shown.bs.tab', 24518 relatedTarget: previous 24519 }) 24520 }) 24521 } 24522 24523 Tab.prototype.activate = function (element, container, callback) { 24524 var $active = container.find('> .active') 24525 var transition = callback 24526 && $.support.transition 24527 && $active.hasClass('fade') 24528 24529 function next() { 24530 $active 24531 .removeClass('active') 24532 .find('> .dropdown-menu > .active') 24533 .removeClass('active') 24534 24535 element.addClass('active') 24536 24537 if (transition) { 24538 element[0].offsetWidth // reflow for transition 24539 element.addClass('in') 24540 } else { 24541 element.removeClass('fade') 24542 } 24543 24544 if (element.parent('.dropdown-menu')) { 24545 element.closest('li.dropdown').addClass('active') 24546 } 24547 24548 callback && callback() 24549 } 24550 24551 transition ? 24552 $active 24553 .one($.support.transition.end, next) 24554 .emulateTransitionEnd(150) : 24555 next() 24556 24557 $active.removeClass('in') 24558 } 24559 24560 24561 // TAB PLUGIN DEFINITION 24562 // ===================== 24563 24564 var old = $.fn.tab 24565 24566 $.fn.tab = function ( option ) { 24567 return this.each(function () { 24568 var $this = $(this) 24569 var data = $this.data('bs.tab') 24570 24571 if (!data) $this.data('bs.tab', (data = new Tab(this))) 24572 if (typeof option == 'string') data[option]() 24573 }) 24574 } 24575 24576 $.fn.tab.Constructor = Tab 24577 24578 24579 // TAB NO CONFLICT 24580 // =============== 24581 24582 $.fn.tab.noConflict = function () { 24583 $.fn.tab = old 24584 return this 24585 } 24586 24587 24588 // TAB DATA-API 24589 // ============ 24590 24591 $(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) { 24592 e.preventDefault() 24593 $(this).tab('show') 24594 }) 24595 24596}(jQuery); 24597 24598/* ======================================================================== 24599 * Bootstrap: tooltip.js v3.1.1 24600 * http://getbootstrap.com/javascript/#tooltip 24601 * Inspired by the original jQuery.tipsy by Jason Frame 24602 * ======================================================================== 24603 * Copyright 2011-2014 Twitter, Inc. 24604 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 24605 * ======================================================================== */ 24606 24607 24608+function ($) { 24609 'use strict'; 24610 24611 // TOOLTIP PUBLIC CLASS DEFINITION 24612 // =============================== 24613 24614 var Tooltip = function (element, options) { 24615 this.type = 24616 this.options = 24617 this.enabled = 24618 this.timeout = 24619 this.hoverState = 24620 this.$element = null 24621 24622 this.init('tooltip', element, options) 24623 } 24624 24625 Tooltip.DEFAULTS = { 24626 animation: true, 24627 placement: 'top', 24628 selector: false, 24629 template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>', 24630 trigger: 'hover focus', 24631 title: '', 24632 delay: 0, 24633 html: false, 24634 container: false, 24635 viewport: { 24636 selector: 'body', 24637 padding: 0 24638 } 24639 } 24640 24641 Tooltip.prototype.init = function (type, element, options) { 24642 this.enabled = true 24643 this.type = type 24644 this.$element = $(element) 24645 this.options = this.getOptions(options) 24646 this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport) 24647 24648 var triggers = this.options.trigger.split(' ') 24649 24650 for (var i = triggers.length; i--;) { 24651 var trigger = triggers[i] 24652 24653 if (trigger == 'click') { 24654 this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this)) 24655 } else if (trigger != 'manual') { 24656 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin' 24657 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout' 24658 24659 this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this)) 24660 this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this)) 24661 } 24662 } 24663 24664 this.options.selector ? 24665 (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) : 24666 this.fixTitle() 24667 } 24668 24669 Tooltip.prototype.getDefaults = function () { 24670 return Tooltip.DEFAULTS 24671 } 24672 24673 Tooltip.prototype.getOptions = function (options) { 24674 options = $.extend({}, this.getDefaults(), this.$element.data(), options) 24675 24676 if (options.delay && typeof options.delay == 'number') { 24677 options.delay = { 24678 show: options.delay, 24679 hide: options.delay 24680 } 24681 } 24682 24683 return options 24684 } 24685 24686 Tooltip.prototype.getDelegateOptions = function () { 24687 var options = {} 24688 var defaults = this.getDefaults() 24689 24690 this._options && $.each(this._options, function (key, value) { 24691 if (defaults[key] != value) options[key] = value 24692 }) 24693 24694 return options 24695 } 24696 24697 Tooltip.prototype.enter = function (obj) { 24698 var self = obj instanceof this.constructor ? 24699 obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) 24700 24701 clearTimeout(self.timeout) 24702 24703 self.hoverState = 'in' 24704 24705 if (!self.options.delay || !self.options.delay.show) return self.show() 24706 24707 self.timeout = setTimeout(function () { 24708 if (self.hoverState == 'in') self.show() 24709 }, self.options.delay.show) 24710 } 24711 24712 Tooltip.prototype.leave = function (obj) { 24713 var self = obj instanceof this.constructor ? 24714 obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) 24715 24716 clearTimeout(self.timeout) 24717 24718 self.hoverState = 'out' 24719 24720 if (!self.options.delay || !self.options.delay.hide) return self.hide() 24721 24722 self.timeout = setTimeout(function () { 24723 if (self.hoverState == 'out') self.hide() 24724 }, self.options.delay.hide) 24725 } 24726 24727 Tooltip.prototype.show = function () { 24728 var e = $.Event('show.bs.' + this.type) 24729 24730 if (this.hasContent() && this.enabled) { 24731 this.$element.trigger(e) 24732 24733 if (e.isDefaultPrevented()) return 24734 var that = this; 24735 24736 var $tip = this.tip() 24737 24738 this.setContent() 24739 24740 if (this.options.animation) $tip.addClass('fade') 24741 24742 var placement = typeof this.options.placement == 'function' ? 24743 this.options.placement.call(this, $tip[0], this.$element[0]) : 24744 this.options.placement 24745 24746 var autoToken = /\s?auto?\s?/i 24747 var autoPlace = autoToken.test(placement) 24748 if (autoPlace) placement = placement.replace(autoToken, '') || 'top' 24749 24750 $tip 24751 .detach() 24752 .css({ top: 0, left: 0, display: 'block' }) 24753 .addClass(placement) 24754 24755 this.options.container ? $tip.appendTo($(document).find(this.options.container)) : $tip.insertAfter(this.$element) 24756 24757 var pos = this.getPosition() 24758 var actualWidth = $tip[0].offsetWidth 24759 var actualHeight = $tip[0].offsetHeight 24760 24761 if (autoPlace) { 24762 var orgPlacement = placement 24763 var $parent = this.$element.parent() 24764 var parentDim = this.getPosition($parent) 24765 24766 placement = placement == 'bottom' && pos.top + pos.height + actualHeight - parentDim.scroll > parentDim.height ? 'top' : 24767 placement == 'top' && pos.top - parentDim.scroll - actualHeight < 0 ? 'bottom' : 24768 placement == 'right' && pos.right + actualWidth > parentDim.width ? 'left' : 24769 placement == 'left' && pos.left - actualWidth < parentDim.left ? 'right' : 24770 placement 24771 24772 $tip 24773 .removeClass(orgPlacement) 24774 .addClass(placement) 24775 } 24776 24777 var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight) 24778 24779 this.applyPlacement(calculatedOffset, placement) 24780 this.hoverState = null 24781 24782 var complete = function() { 24783 that.$element.trigger('shown.bs.' + that.type) 24784 } 24785 24786 $.support.transition && this.$tip.hasClass('fade') ? 24787 $tip 24788 .one($.support.transition.end, complete) 24789 .emulateTransitionEnd(150) : 24790 complete() 24791 } 24792 } 24793 24794 Tooltip.prototype.applyPlacement = function (offset, placement) { 24795 var $tip = this.tip() 24796 var width = $tip[0].offsetWidth 24797 var height = $tip[0].offsetHeight 24798 24799 // manually read margins because getBoundingClientRect includes difference 24800 var marginTop = parseInt($tip.css('margin-top'), 10) 24801 var marginLeft = parseInt($tip.css('margin-left'), 10) 24802 24803 // we must check
24803 for NaN for ie 8/9 24804 if (isNaN(marginTop)) marginTop = 0 24805 if (isNaN(marginLeft)) marginLeft = 0 24806 24807 offset.top = offset.top + marginTop 24808 offset.left = offset.left + marginLeft 24809 24810 // $.fn.offset doesn't round pixel values 24811 // so we use setOffset directly with our own function B-0 24812 $.offset.setOffset($tip[0], $.extend({ 24813 using: function (props) { 24814 $tip.css({ 24815 top: Math.round(props.top), 24816 left: Math.round(props.left) 24817 }) 24818 } 24819 }, offset), 0) 24820 24821 $tip.addClass('in') 24822 24823 // check to see if placing tip in new offset caused the tip to resize itself 24824 var actualWidth = $tip[0].offsetWidth 24825 var actualHeight = $tip[0].offsetHeight 24826 24827 if (placement == 'top' && actualHeight != height) { 24828 offset.top = offset.top + height - actualHeight 24829 } 24830 24831 var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight) 24832 24833 if (delta.left) offset.left += delta.left 24834 else offset.top += delta.top 24835 24836 var arrowDelta = delta.left ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight 24837 var arrowPosition = delta.left ? 'left' : 'top' 24838 var arrowOffsetPosition = delta.left ? 'offsetWidth' : 'offsetHeight' 24839 24840 $tip.offset(offset) 24841 this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], arrowPosition) 24842 } 24843 24844 Tooltip.prototype.replaceArrow = function (delta, dimension, position) { 24845 this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + '%') : '') 24846 } 24847 24848 Tooltip.prototype.setContent = function () { 24849 var $tip = this.tip() 24850 var title = this.getTitle() 24851 24852 $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title) 24853 $tip.removeClass('fade in top bottom left right') 24854 } 24855 24856 Tooltip.prototype.hide = function () { 24857 var that = this 24858 var $tip = this.tip() 24859 var e = $.Event('hide.bs.' + this.type) 24860 24861 function complete() { 24862 if (that.hoverState != 'in') $tip.detach() 24863 that.$element.trigger('hidden.bs.' + that.type) 24864 } 24865 24866 this.$element.trigger(e) 24867 24868 if (e.isDefaultPrevented()) return 24869 24870 $tip.removeClass('in') 24871 24872 $.support.transition && this.$tip.hasClass('fade') ? 24873 $tip 24874 .one($.support.transition.end, complete) 24875 .emulateTransitionEnd(150) : 24876 complete() 24877 24878 this.hoverState = null 24879 24880 return this 24881 } 24882 24883 Tooltip.prototype.fixTitle = function () { 24884 var $e = this.$element 24885 if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') { 24886 $e.attr('data-original-title', $e.attr('title') || '').attr('title', '') 24887 } 24888 } 24889 24890 Tooltip.prototype.hasContent = function () { 24891 return this.getTitle() 24892 } 24893 24894 Tooltip.prototype.getPosition = function ($element) { 24895 $element = $element || this.$element 24896 var el = $element[0] 24897 var isBody = el.tagName == 'BODY' 24898 return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : null, { 24899 scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop(), 24900 width: isBody ? $(window).width() : $element.outerWidth(), 24901 height: isBody ? $(window).height() : $element.outerHeight() 24902 }, isBody ? {top: 0, left: 0} : $element.offset()) 24903 } 24904 24905 Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) { 24906 return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } : 24907 placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } : 24908 placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } : 24909 /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width } 24910 24911 } 24912 24913 Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) { 24914 var delta = { top: 0, left: 0 } 24915 if (!this.$viewport) return delta 24916 24917 var viewportPadding = this.options.viewport && this.options.viewport.padding || 0 24918 var viewportDimensions = this.getPosition(this.$viewport) 24919 24920 if (/right|left/.test(placement)) { 24921 var topEdgeOffset = pos.top - viewportPadding - viewportDimensions.scroll 24922 var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight 24923 if (topEdgeOffset < viewportDimensions.top) { // top overflow 24924 delta.top = viewportDimensions.top - topEdgeOffset 24925 } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow 24926 delta.top = viewportDimensions.top + viewportDimensions.height - bottom
24926EdgeOffset 24927 } 24928 } else { 24929 var leftEdgeOffset = pos.left - viewportPadding 24930 var rightEdgeOffset = pos.left + viewportPadding + actualWidth 24931 if (leftEdgeOffset < viewportDimensions.left) { // left overflow 24932 delta.left = viewportDimensions.left - leftEdgeOffset 24933 } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow 24934 delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset 24935 } 24936 } 24937 24938 return delta 24939 } 24940 24941 Tooltip.prototype.getTitle = function () { 24942 var title 24943 var $e = this.$element 24944 var o = this.options 24945 24946 title = $e.attr('data-original-title') 24947 || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title) 24948 24949 return title 24950 } 24951 24952 Tooltip.prototype.tip = function () { 24953 return this.$tip = this.$tip || $(this.options.template) 24954 } 24955 24956 Tooltip.prototype.arrow = function () { 24957 return this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow') 24958 } 24959 24960 Tooltip.prototype.validate = function () { 24961 if (!this.$element[0].parentNode) { 24962 this.hide() 24963 this.$element = null 24964 this.options = null 24965 } 24966 } 24967 24968 Tooltip.prototype.enable = function () { 24969 this.enabled = true 24970 } 24971 24972 Tooltip.prototype.disable = function () { 24973 this.enabled = false 24974 } 24975 24976 Tooltip.prototype.toggleEnabled = function () { 24977 this.enabled = !this.enabled 24978 } 24979 24980 Tooltip.prototype.toggle = function (e) { 24981 var self = e ? $(e.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) : this 24982 self.tip().hasClass('in') ? self.leave(self) : self.enter(self) 24983 } 24984 24985 Tooltip.prototype.destroy = function () { 24986 clearTimeout(this.timeout) 24987 this.hide().$element.off('.' + this.type).removeData('bs.' + this.type) 24988 } 24989 24990 24991 // TOOLTIP PLUGIN DEFINITION 24992 // ========================= 24993 24994 var old = $.fn.tooltip 24995 24996 $.fn.tooltip = function (option) { 24997 return this.each(function () { 24998 var $this = $(this) 24999 var data = $this.data('bs.tooltip') 25000 var options = typeof option == 'object' && option 25001 25002 if (!data && option == 'destroy') return 25003 if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options))) 25004 if (typeof option == 'string') data[option]() 25005 }) 25006 } 25007 25008 $.fn.tooltip.Constructor = Tooltip 25009 25010 25011 // TOOLTIP NO CONFLICT 25012 // =================== 25013 25014 $.fn.tooltip.noConflict = function () { 25015 $.fn.tooltip = old 25016 return this 25017 } 25018 25019}(jQuery); 25020 25021/* ======================================================================== 25022 * Bootstrap: transition.js v3.1.1 25023 * http://getbootstrap.com/javascript/#transitions 25024 * ======================================================================== 25025 * Copyright 2011-2014 Twitter, Inc. 25026 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 25027 * ======================================================================== */ 25028 25029 25030+function ($) { 25031 'use strict'; 25032 25033 // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) 25034 // ============================================================ 25035 25036 function transitionEnd() { 25037 var el = document.createElement('bootstrap') 25038 25039 var transEndEventNames = { 25040 WebkitTransition : 'webkitTransitionEnd', 25041 MozTransition : 'transitionend', 25042 OTransition : 'oTransitionEnd otransitionend', 25043 transition : 'transitionend' 25044 } 25045 25046 for (var name in transEndEventNames) { 25047 if (el.style[name] !== undefined) { 25048 return { end: transEndEventNames[name] } 25049 } 25050 } 25051 25052 return false // explicit for ie8 ( ._.) 25053 } 25054 25055 // http://blog.alexmaccaw.com/css-transitions 25056 $.fn.emulateTransitionEnd = function (duration) { 25057 var called = false, $el = this 25058 $(this).one($.support.transition.end, function () { called = true }) 25059 var callback = function () { if (!called) $($el).trigger($.support.transition.end) } 25060 setTimeout(callback, duration) 25061 return this 25062 } 25063 25064 $(function () { 25065 $.support.transition = transitionEnd() 25066 }) 25067 25068}(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.