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 // START UNCODE EDIT 1667 // if ( !utils.isElement( elem ) ) { 1668 if ( !utils.isElement( elem ) && !SiteParameters.is_frontend_editor ) { 1669 // END UNCODE EDIT 1670 continue; 1671 } 1672 // filter & find items if we have a selector 1673 if ( selector ) { 1674 // filter siblings 1675 if ( matchesSelector( elem, selector ) ) { 1676 ffElems.push( elem ); 1677 } 1678 // find children 1679 var childElems = elem.querySelectorAll( selector ); 1680 // concat childElems to filterFound array 1681 for ( var j=0, jLen = childElems.length; j < jLen; j++ ) { 1682 ffElems.push( childElems[j] ); 1683 } 1684 } else { 1685 ffElems.push( elem ); 1686 } 1687 } 1688 1689 return ffElems; 1690}; 1691 1692// ----- debounceMethod ----- // 1693 1694utils.debounceMethod = function( _class, methodName, threshold ) { 1695 // original method 1696 var method = _class.prototype[ methodName ]; 1697 var timeoutName = methodName + 'Timeout'; 1698 1699 _class.prototype[ methodName ] = function() { 1700 var timeout = this[ timeoutName ]; 1701 if ( timeout ) { 1702 clearTimeout( timeout ); 1703 } 1704 var args = arguments; 1705 1706 var _this = this; 1707 this[ timeoutName ] = setTimeout( function() { 1708 method.apply( _this, args ); 1709 delete _this[ timeoutName ]; 1710 }, threshold || 100 ); 1711 }; 1712}; 1713 1714// ----- htmlInit ----- // 1715 1716// http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/ 1717utils.toDashed = function( str ) { 1718 return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) { 1719 return $1 + '-' + $2; 1720 }).toLowerCase(); 1721}; 1722
1723var console = window.console; 1724/** 1725 * allow user to initialize classes via .js-namespace class 1726 * htmlInit( Widget, 'widgetName' ) 1727 * options are parsed from data-namespace-option attribute 1728 */ 1729utils.htmlInit = function( WidgetClass, namespace ) { 1730 docReady( function() { 1731 var dashedNamespace = utils.toDashed( namespace ); 1732 var elems = document.querySelectorAll( '.js-' + dashedNamespace ); 1733 var dataAttr = 'data-' + dashedNamespace + '-options'; 1734 1735 for ( var i=0, len = elems.length; i < len; i++ ) { 1736 var elem = elems[i]; 1737 var attr = elem.getAttribute( dataAttr ); 1738 var options; 1739 try { 1740 options = attr && JSON.parse( attr ); 1741 } catch ( error ) { 1742 // log error, do not initialize 1743 if ( console ) { 1744 console.error( 'Error parsing ' + dataAttr + ' on ' + 1745 elem.nodeName.toLowerCase() + ( elem.id ? '#' + elem.id : '' ) + ': ' + 1746 error ); 1747 } 1748 continue; 1749 } 1750 // initialize 1751 var instance = new WidgetClass( elem, options ); 1752 // make available via $().data('layoutname') 1753 var jQuery = window.jQuery; 1754 if ( jQuery ) { 1755 jQuery.data( elem, namespace, instance ); 1756 } 1757 } 1758 }); 1759}; 1760 1761// ----- ----- // 1762 1763return utils; 1764 1765})); 1766 1767/** 1768 * Outlayer Item 1769 */ 1770 1771( function( window, factory ) { 1772 'use strict'; 1773 // universal module definition 1774 if ( typeof define === 'function' && define.amd ) { 1775 // AMD 1776 define( 'outlayer/item',[ 1777 'eventEmitter/EventEmitter', 1778 'get-size/get-size', 1779 'get-style-property/get-style-property', 1780 'fizzy-ui-utils/utils' 1781 ], 1782 function( EventEmitter, getSize, getStyleProperty, utils ) { 1783 return factory( window, EventEmitter, getSize, getStyleProperty, utils ); 1784 } 1785 ); 1786 } else if (typeof exports === 'object') { 1787 // CommonJS 1788 module.exports = factory( 1789 window, 1790 require('wolfy87-eventemitter'), 1791 require('get-size'), 1792 require('desandro-get-style-property'), 1793 require('fizzy-ui-utils') 1794 ); 1795 } else { 1796 // browser global 1797 window.Outlayer = {}; 1798 window.Outlayer.Item = factory( 1799 window, 1800 window.EventEmitter, 1801 window.getSize, 1802 window.getStyleProperty, 1803 window.fizzyUIUtils 1804 ); 1805 } 1806 1807}( window, function factory( window, EventEmitter, getSize, getStyleProperty, utils ) { 1808'use strict'; 1809 1810// ----- helpers ----- // 1811 1812var getComputedStyle = window.getComputedStyle; 1813var getStyle = getComputedStyle ? 1814 function( elem ) { 1815 return getComputedStyle( elem, null ); 1816 } : 1817 function( elem ) { 1818 return elem.currentStyle; 1819 }; 1820 1821 1822function isEmptyObj( obj ) { 1823 for ( var prop in obj ) { 1824 return false; 1825 } 1826 prop = null; 1827 return true; 1828} 1829 1830// -------------------------- CSS3 support -------------------------- // 1831 1832var transitionProperty = getStyleProperty('transition'); 1833var transformProperty = getStyleProperty('transform'); 1834var supportsCSS3 = transitionProperty && transformProperty; 1835var is3d = !!getStyleProperty('perspective'); 1836 1837var transitionEndEvent = { 1838 WebkitTransition: 'webkitTransitionEnd', 1839 MozTransition: 'transitionend', 1840 OTransition: 'otransitionend', 1841 transition: 'transitionend' 1842}[ transitionProperty ]; 1843 1844// properties that could have vendor prefix 1845var prefixableProperties = [ 1846 'transform', 1847 'transition', 1848 'transitionDuration', 1849 'transitionProperty' 1850]; 1851 1852// cache all vendor properties 1853var vendorProperties = ( function() { 1854 var cache = {}; 1855 for ( var i=0, len = prefixableProperties.length; i < len; i++ ) { 1856 var prop = prefixableProperties[i]; 1857 var supportedProp = getStyleProperty( prop ); 1858 if ( supportedProp && supportedProp !== prop ) { 1859 cache[ prop ] = supportedProp; 1860 } 1861 } 1862 return cache; 1863})(); 1864 1865// -------------------------- Item -------------------------- // 1866 1867function Item( element, layout ) { 1868 if ( !element ) { 1869 return; 1870 } 1871 1872 this.element = element; 1873 // parent layout class, i.e. Masonry, Isotope, or Packery 1874 this.layout = layout; 1875 this.position = { 1876 x: 0, 1877 y: 0 1878 }; 1879 1880 this._create(); 1881} 1882 1883// inherit EventEmitter 1884utils.extend( Item.prototype, EventEmitter.prototype ); 1885 1886Item.prototype._create = function() { 1887 // transition objects 1888 this._transn = { 1889 ingProperties: {}, 1890 clean: {}, 1891 onEnd: {} 1892 }; 1893 1894 this.css({ 1895 position: 'absolute' 1896 }); 1897}; 1898 1899// trigger specified handler for event type 1900Item.prototype.handleEvent = function( event ) { 1901 var method = 'on' + event.type; 1902 if ( this[ method ] ) { 1903 this[ method ]( event ); 1904 } 1905}; 1906 1907Item.prototype.getSize = function() { 1908 this.size = getSize( this.element ); 1909}; 1910 1911/** 1912 * apply CSS styles to element 1913 * @param {Object} style 1914 */ 1915Item.prototype.css = function( style ) { 1916 var elemStyle = this.element.style; 1917 1918 for ( var prop in style ) { 1919 // use vendor property if available
1920 var supportedProp = vendorProperties[ prop ] || prop; 1921 elemStyle[ supportedProp ] = style[ prop ]; 1922 } 1923}; 1924 1925 // measure position, and sets it 1926Item.prototype.getPosition = function() { 1927 var style = getStyle( this.element ); 1928 var layoutOptions = this.layout.options; 1929 var isOriginLeft = layoutOptions.isOriginLeft; 1930 var isOriginTop = layoutOptions.isOriginTop; 1931 var xValue = style[ isOriginLeft ? 'left' : 'right' ]; 1932 var yValue = style[ isOriginTop ? 'top' : 'bottom' ]; 1933 // convert percent to pixels 1934 var layoutSize = this.layout.size; 1935 var x = xValue.indexOf('%') != -1 ? 1936 ( parseFloat( xValue ) / 100 ) * layoutSize.width : parseInt( xValue, 10 ); 1937 var y = yValue.indexOf('%') != -1 ? 1938 ( parseFloat( yValue ) / 100 ) * layoutSize.height : parseInt( yValue, 10 ); 1939 1940 // clean up 'auto' or other non-integer values 1941 x = isNaN( x ) ? 0 : x; 1942 y = isNaN( y ) ? 0 : y; 1943 // remove padding from measurement 1944 x -= isOriginLeft ? layoutSize.paddingLeft : layoutSize.paddingRight; 1945 y -= isOriginTop ? layoutSize.paddingTop : layoutSize.paddingBottom; 1946 1947 this.position.x = x; 1948 this.position.y = y; 1949}; 1950 1951// set settled position, apply padding 1952Item.prototype.layoutPosition = function() { 1953 var layoutSize = this.layout.size; 1954 var layoutOptions = this.layout.options; 1955 var style = {}; 1956 1957 // x 1958 var xPadding = layoutOptions.isOriginLeft ? 'paddingLeft' : 'paddingRight'; 1959 var xProperty = layoutOptions.isOriginLeft ? 'left' : 'right'; 1960 var xResetProperty = layoutOptions.isOriginLeft ? 'right' : 'left'; 1961 1962 var x = this.position.x + layoutSize[ xPadding ]; 1963 // set in percentage or pixels 1964 style[ xProperty ] = this.getXValue( x ); 1965 // reset other property 1966 style[ xResetProperty ] = ''; 1967 1968 // y 1969 var yPadding = layoutOptions.isOriginTop ? 'paddingTop' : 'paddingBottom'; 1970 var yProperty = layoutOptions.isOriginTop ? 'top' : 'bottom'; 1971 var yResetProperty = layoutOptions.isOriginTop ? 'bottom' : 'top'; 1972 1973 var y = this.position.y + layoutSize[ yPadding ]; 1974 // set in percentage or pixels 1975 style[ yProperty ] = this.getYValue( y ); 1976 // reset other property 1977 style[ yResetProperty ] = ''; 1978 1979 this.css( style ); 1980 this.emitEvent( 'layout', [ this ] ); 1981}; 1982 1983Item.prototype.getXValue = function( x ) { 1984 var layoutOptions = this.layout.options; 1985 return layoutOptions.percentPosition && !layoutOptions.isHorizontal ? 1986 ( ( x / this.layout.size.width ) * 100 ) + '%' : x + 'px'; 1987}; 1988 1989Item.prototype.getYValue = function( y ) { 1990 var layoutOptions = this.layout.options; 1991 return layoutOptions.percentPosition && layoutOptions.isHorizontal ? 1992 ( ( y / this.layout.size.height ) * 100 ) + '%' : y + 'px'; 1993}; 1994 1995 1996Item.prototype._transitionTo = function( x, y ) { 1997 this.getPosition(); 1998 // get current x & y from top/left 1999 var curX = this.position.x; 2000 var curY = this.position.y; 2001 2002 var compareX = parseInt( x, 10 ); 2003 var compareY = parseInt( y, 10 ); 2004 var didNotMove = compareX === this.position.x && compareY === this.position.y; 2005 2006 // save end position 2007 this.setPosition( x, y ); 2008 2009 // if did not move and not transitioning, just go to layout 2010 if ( didNotMove && !this.isTransitioning ) { 2011 this.layoutPosition(); 2012 return; 2013 } 2014 2015 var transX = x - curX; 2016 var transY = y - curY; 2017 var transitionStyle = {}; 2018 transitionStyle.transform = this.getTranslate( transX, transY ); 2019 2020 this.transition({ 2021 to: transitionStyle, 2022 onTransitionEnd: { 2023 transform: this.layoutPosition 2024 }, 2025 isCleaning: true 2026 }); 2027}; 2028 2029Item.prototype.getTranslate = function( x, y ) { 2030 // flip cooridinates if origin on right or bottom 2031 var layoutOptions = this.layout.options; 2032 x = layoutOptions.isOriginLeft ? x : -x; 2033 y = layoutOptions.isOriginTop ? y : -y; 2034 2035 if ( is3d ) { 2036 return 'translate3d(' + x + 'px, ' + y + 'px, 0)'; 2037 } 2038 2039 return 'translate(' + x + 'px, ' + y + 'px)'; 2040}; 2041 2042// non transition + transform support 2043Item.prototype.goTo = function( x, y ) { 2044 this.setPosition( x, y ); 2045 this.layoutPosition(); 2046}; 2047 2048// use transition and transforms if supported 2049Item.prototype.moveTo = supportsCSS3 ? 2050 Item.prototype._transitionTo : Item.prototype.goTo; 2051 2052Item.prototype.setPosition = function( x, y ) { 2053 this.position.x = parseInt( x, 10 ); 2054 this.position.y = parseInt( y, 10 ); 2055}; 2056 2057// ----- transition ----- // 2058 2059/** 2060 * @param {Object} style - CSS 2061 * @param {Function} onTransitionEnd 2062 */ 2063 2064// non transition, just trigger callback 2065Item.prototype._nonTransition = function( args ) { 2066 this.css( args.to ); 2067 if ( args.isCleaning ) { 2068 this._removeStyles( args.to ); 2069 } 2070 for ( var prop in args.onTransitionEnd ) { 2071 args.onTransitionEnd[ prop ].call( this ); 2072 } 2073}; 2074 2075/** 2076 * proper transition 2077 * @param {Object} args - arguments 2078 * @param {Object} to - style to transition to 2079 * @param {Object} from - style to start transition from 2080 * @param {Boolean} isCleaning - removes transition styles after transition 2081 * @param {Function} onTransitionEnd - callback 2082 */ 2083Item.prototype._transition = function( args ) { 2084 // redirect to nonTransition if no transition duration 2085 if ( !parseFloat( this.layout.options.transitionDuration ) ) { 2086 this._nonTransition( args ); 2087 return; 2088 } 2089 2090 var _transition = this._transn; 2091 // keep track of onTransitionEnd callback by css property 2092 for ( var prop in args.onTransitionEnd ) { 2093 _transition.onEnd[ prop ] = args.onTransitionEnd[ prop ]; 2094 } 2095 // keep track of properties that are transitioning 2096 for ( prop in args.to ) { 2097 _transition.ingProperties[ prop ] = true; 2098 // keep track of properties to clean up when transition is done 2099 if ( args.isCleaning ) { 2100 _transition.clean[ prop ] = true; 2101 } 2102 } 2103 2104 // set from styles 2105 if ( args.from ) { 2106 this.css( args.from ); 2107 // force redraw. http://blog.alexmaccaw.com/css-transitions 2108 var h = this.element.offsetHeight; 2109 // hack for JSHint to hush about unused var 2110 h = null; 2111 } 2112 // enable transition 2113 this.enableTransition( args.to ); 2114 // set styles that are transitioning 2115 this.css( args.to ); 2116 2117 this.isTransitioning = true; 2118 2119}; 2120 2121// dash before all cap letters, including first for 2122// WebkitTransform => -webkit-transform 2123function toDashedAll( str ) { 2124 return str.replace( /([A-Z])/g, function( $1 ) { 2125 return '-' + $1.toLowerCase(); 2126 }); 2127} 2128 2129var transitionProps = 'opacity,' +
vendor: 11,190 bytes, lines 2130-2576
2130 toDashedAll( vendorProperties.transform || 'transform' ); 2131 2132Item.prototype.enableTransition = function(/* style */) { 2133 // HACK changing transitionProperty during a transition 2134 // will cause transition to jump 2135 if ( this.isTransitioning ) { 2136 return; 2137 } 2138 2139 // make `transition: foo, bar, baz` from style object 2140 // HACK un-comment this when enableTransition can work 2141 // while a transition is happening 2142 // var transitionValues = []; 2143 // for ( var prop in style ) { 2144 // // dash-ify camelCased properties like WebkitTransition 2145 // prop = vendorProperties[ prop ] || prop; 2146 // transitionValues.push( toDashedAll( prop ) ); 2147 // } 2148 // enable transition styles 2149 this.css({ 2150 transitionProperty: transitionProps, 2151 transitionDuration: this.layout.options.transitionDuration 2152 }); 2153 // listen for transition end event 2154 this.element.addEventListener( transitionEndEvent, this, false ); 2155}; 2156 2157Item.prototype.transition = Item.prototype[ transitionProperty ? '_transition' : '_nonTransition' ]; 2158 2159// ----- events ----- // 2160 2161Item.prototype.onwebkitTransitionEnd = function( event ) { 2162 this.ontransitionend( event ); 2163}; 2164 2165Item.prototype.onotransitionend = function( event ) { 2166 this.ontransitionend( event ); 2167}; 2168 2169// properties that I munge to make my life easier 2170var dashedVendorProperties = { 2171 '-webkit-transform': 'transform', 2172 '-moz-transform': 'transform', 2173 '-o-transform': 'transform' 2174}; 2175 2176Item.prototype.ontransitionend = function( event ) { 2177 // disregard bubbled events from children 2178 if ( event.target !== this.element ) { 2179 return; 2180 } 2181 var _transition = this._transn; 2182 // get property name of transitioned property, convert to prefix-free 2183 var propertyName = dashedVendorProperties[ event.propertyName ] || event.propertyName; 2184 2185 // remove property that has completed transitioning 2186 delete _transition.ingProperties[ propertyName ]; 2187 // check if any properties are still transitioning 2188 if ( isEmptyObj( _transition.ingProperties ) ) { 2189 // all properties have completed transitioning 2190 this.disableTransition(); 2191 } 2192 // clean style 2193 if ( propertyName in _transition.clean ) { 2194 // clean up style 2195 this.element.style[ event.propertyName ] = ''; 2196 delete _transition.clean[ propertyName ]; 2197 } 2198 // trigger onTransitionEnd callback 2199 if ( propertyName in _transition.onEnd ) { 2200 var onTransitionEnd = _transition.onEnd[ propertyName ]; 2201 onTransitionEnd.call( this ); 2202 delete _transition.onEnd[ propertyName ]; 2203 } 2204 2205 this.emitEvent( 'transitionEnd', [ this ] ); 2206}; 2207 2208Item.prototype.disableTransition = function() { 2209 this.removeTransitionStyles(); 2210 this.element.removeEventListener( transitionEndEvent, this, false ); 2211 this.isTransitioning = false; 2212}; 2213 2214/** 2215 * removes style property from element 2216 * @param {Object} style 2217**/ 2218Item.prototype._removeStyles = function( style ) { 2219 // clean up transition styles 2220 var cleanStyle = {}; 2221 for ( var prop in style ) { 2222 cleanStyle[ prop ] = ''; 2223 } 2224 this.css( cleanStyle ); 2225}; 2226 2227var cleanTransitionStyle = { 2228 transitionProperty: '', 2229 transitionDuration: '' 2230}; 2231 2232Item.prototype.removeTransitionStyles = function() { 2233 // remove transition 2234 this.css( cleanTransitionStyle ); 2235}; 2236 2237// ----- show/hide/remove ----- // 2238 2239// remove element from DOM 2240Item.prototype.removeElem = function() { 2241 this.element.parentNode.removeChild( this.element ); 2242 // remove display: none 2243 this.css({ display: '' }); 2244 this.emitEvent( 'remove', [ this ] ); 2245}; 2246 2247Item.prototype.remove = function() { 2248 // just remove element if no transition support or no transition 2249 if ( !transitionProperty || !parseFloat( this.layout.options.transitionDuration ) ) { 2250 this.removeElem(); 2251 return; 2252 } 2253 2254 // start transition 2255 var _this = this; 2256 this.once( 'transitionEnd', function() { 2257 _this.removeElem(); 2258 }); 2259 this.hide(); 2260}; 2261 2262Item.prototype.reveal = function() { 2263 delete this.isHidden; 2264 // remove display: none 2265 this.css({ display: '' }); 2266 2267 var options = this.layout.options; 2268 2269 var onTransitionEnd = {}; 2270 var transitionEndProperty = this.getHideRevealTransitionEndProperty('visibleStyle'); 2271 onTransitionEnd[ transitionEndProperty ] = this.onRevealTransitionEnd; 2272 2273 this.transition({ 2274 from: options.hiddenStyle, 2275 to: options.visibleStyle, 2276 isCleaning: true, 2277 onTransitionEnd: onTransitionEnd 2278 }); 2279}; 2280 2281Item.prototype.onRevealTransitionEnd = function() { 2282 // check if still visible 2283 // during transition, item may have been hidden 2284 if ( !this.isHidden ) { 2285 this.emitEvent('reveal'); 2286 } 2287}; 2288 2289/** 2290 * get style property use for hide/reveal transition end 2291 * @param {String} styleProperty - hiddenStyle/visibleStyle 2292 * @returns {String} 2293 */ 2294Item.prototype.getHideRevealTransitionEndProperty = function( styleProperty ) { 2295 var optionStyle = this.layout.options[ styleProperty ]; 2296 // use opacity 2297 if ( optionStyle.opacity ) { 2298 return 'opacity'; 2299 } 2300 // get first property 2301 for ( var prop in optionStyle ) { 2302 return prop; 2303 } 2304}; 2305 2306Item.prototype.hide = function() { 2307 // set flag 2308 this.isHidden = true; 2309 // remove display: none 2310 this.css({ display: '' }); 2311 2312 var options = this.layout.options; 2313 2314 var onTransitionEnd = {}; 2315 var transitionEndProperty = this.getHideRevealTransitionEndProperty('hiddenStyle'); 2316 onTransitionEnd[ transitionEndProperty ] = this.onHideTransitionEnd; 2317 2318 this.transition({ 2319 from: options.visibleStyle, 2320 to: options.hiddenStyle, 2321 // keep hidden stuff hidden 2322 isCleaning: true, 2323 onTransitionEnd: onTransitionEnd 2324 }); 2325}; 2326 2327Item.prototype.onHideTransitionEnd = function() { 2328 // check if still hidden 2329 // during transition, item may have been un-hidden 2330 if ( this.isHidden ) { 2331 this.css({ display: 'none' }); 2332 this.emitEvent('hide'); 2333 } 2334}; 2335 2336Item.prototype.destroy = function() { 2337 this.css({ 2338 position: '', 2339 left: '', 2340 right: '', 2341 top: '', 2342 bottom: '', 2343 transition: '', 2344 transform: '' 2345 }); 2346}; 2347 2348return Item; 2349 2350})); 2351 2352/*! 2353 * Outlayer v1.4.2 2354 * the brains and guts of a layout library 2355 * MIT license 2356 */ 2357 2358( function( window, factory ) { 2359 'use strict'; 2360 // universal module definition 2361 2362 if ( typeof define == 'function' && define.amd ) { 2363 // AMD 2364 define( 'outlayer/outlayer',[ 2365 'eventie/eventie', 2366 'eventEmitter/EventEmitter', 2367 'get-size/get-size', 2368 'fizzy-ui-utils/utils', 2369 './item' 2370 ], 2371 function( eventie, EventEmitter, getSize, utils, Item ) { 2372 return factory( window, eventie, EventEmitter, getSize, utils, Item); 2373 } 2374 ); 2375 } else if ( typeof exports == 'object' ) { 2376 // CommonJS 2377 module.exports = factory( 2378 window, 2379 require('eventie'), 2380 require('wolfy87-eventemitter'), 2381 require('get-size'), 2382 require('fizzy-ui-utils'), 2383 require('./item') 2384 ); 2385 } else { 2386 // browser global 2387 window.Outlayer = factory( 2388 window, 2389 window.eventie, 2390 window.EventEmitter, 2391 window.getSize, 2392 window.fizzyUIUtils, 2393 window.Outlayer.Item 2394 ); 2395 } 2396 2397}( window, function factory( window, eventie, EventEmitter, getSize, utils, Item ) { 2398'use strict'; 2399 2400// ----- vars ----- // 2401 2402var console = window.console; 2403var jQuery = window.jQuery; 2404var noop = function() {}; 2405 2406// -------------------------- Outlayer -------------------------- // 2407 2408// globally unique identifiers 2409var GUID = 0; 2410// internal store of all Outlayer intances 2411var instances = {}; 2412 2413 2414/** 2415 * @param {Element, String} element 2416 * @param {Object} options 2417 * @constructor 2418 */ 2419function Outlayer( element, options ) { 2420 var queryElement = utils.getQueryElement( element ); 2421 if ( !queryElement ) { 2422 if ( console ) { 2423 console.error( 'Bad element for ' + this.constructor.namespace + 2424 ': ' + ( queryElement || element ) ); 2425 } 2426 return; 2427 } 2428 this.element = queryElement; 2429 // add jQuery 2430 if ( jQuery ) { 2431 this.$element = jQuery( this.element ); 2432 } 2433 2434 // options 2435 this.options = utils.extend( {}, this.constructor.defaults ); 2436 this.option( options ); 2437 2438 // add id for Outlayer.getFromElement 2439 var id = ++GUID; 2440 this.element.outlayerGUID = id; // expando 2441 instances[ id ] = this; // associate via id 2442 2443 // kick it off 2444 this._create(); 2445 2446 if ( this.options.isInitLayout ) { 2447 this.layout(); 2448 } 2449} 2450 2451// settings are for internal use only 2452Outlayer.namespace = 'outlayer'; 2453Outlayer.Item = Item; 2454 2455// default options 2456Outlayer.defaults = { 2457 containerStyle: { 2458 position: 'relative' 2459 }, 2460 isInitLayout: true, 2461 isOriginLeft: true, 2462 isOriginTop: true, 2463 isResizeBound: true, 2464 isResizingContainer: true, 2465 // item options 2466 transitionDuration: '0.4s', 2467 hiddenStyle: { 2468 opacity: 0, 2469 transform: 'scale(0.001)' 2470 }, 2471 visibleStyle: { 2472 opacity: 1, 2473 transform: 'scale(1)' 2474 } 2475}; 2476 2477// inherit EventEmitter 2478utils.extend( Outlayer.prototype, EventEmitter.prototype ); 2479 2480/** 2481 * set options 2482 * @param {Object} opts 2483 */ 2484Outlayer.prototype.option = function( opts ) { 2485 utils.extend( this.options, opts ); 2486}; 2487 2488Outlayer.prototype._create = function() { 2489 // get items from children 2490 this.reloadItems(); 2491 // elements that affect layout, but are not laid out 2492 this.stamps = []; 2493 this.stamp( this.options.stamp ); 2494 // set container style 2495 utils.extend( this.element.style, this.options.containerStyle ); 2496 2497 // bind resize method 2498 if ( this.options.isResizeBound ) { 2499 this.bindResize(); 2500 } 2501}; 2502 2503// goes through all children again and gets bricks in proper order 2504Outlayer.prototype.reloadItems = function() { 2505 // collection of item elements 2506 this.items = this._itemize( this.element.children ); 2507}; 2508 2509 2510/** 2511 * turn elements into Outlayer.Items to be used in layout 2512 * @param {Array or NodeList or HTMLElement} elems 2513 * @returns {Array} items - collection of new Outlayer Items 2514 */ 2515Outlayer.prototype._itemize = function( elems ) { 2516 2517 var itemElems = this._filterFindItemElements( elems ); 2518 var Item = this.constructor.Item; 2519 2520 // create new Outlayer Items for collection 2521 var items = []; 2522 for ( var i=0, len = itemElems.length; i < len; i++ ) { 2523 var elem = itemElems[i]; 2524 var item = new Item( elem, this ); 2525 items.push( item ); 2526 } 2527 2528 return items; 2529}; 2530 2531/** 2532 * get item elements to be used in layout 2533 * @param {Array or NodeList or HTMLElement} elems 2534 * @returns {Array} items - item elements 2535 */ 2536Outlayer.prototype._filterFindItemElements = function( elems ) { 2537 return utils.filterFindElements( elems, this.options.itemSelector ); 2538}; 2539 2540/** 2541 * getter method for getting item elements 2542 * @returns {Array} elems - collection of item elements 2543 */ 2544Outlayer.prototype.getItemElements = function() { 2545 var elems = []; 2546 for ( var i=0, len = this.items.length; i < len; i++ ) { 2547 elems.push( this.items[i].element ); 2548 } 2549 return elems; 2550}; 2551 2552// ----- init & layout ----- // 2553 2554/** 2555 * lays out all items 2556 */ 2557Outlayer.prototype.layout = function() { 2558 this._resetLayout(); 2559 this._manageStamps(); 2560 2561 // don't animate first layout 2562 var isInstant = this.options.isLayoutInstant !== undefined ? 2563 this.options.isLayoutInstant : !this._isLayoutInited; 2564 this.layoutItems( this.items, isInstant ); 2565 2566 // flag for initalized 2567 this._isLayoutInited = true; 2568}; 2569 2570// _init is alias for layout 2571Outlayer.prototype._init = Outlayer.prototype.layout; 2572 2573/** 2574 * logic before any new layout 2575 */ 2576Outlayer.prototype._resetLayout = function() {
2577 this.getSize(); 2578}; 2579 2580 2581Outlayer.prototype.getSize = function() { 2582 this.size = getSize( this.element ); 2583}; 2584 2585/** 2586 * get measurement from option, for columnWidth, rowHeight, gutter 2587 * if option is String -> get element from selector string, & get size of element 2588 * if option is Element -> get size of element 2589 * else use option as a number 2590 * 2591 * @param {String} measurement 2592 * @param {String} size - width or height 2593 * @private 2594 */ 2595Outlayer.prototype._getMeasurement = function( measurement, size ) { 2596 var option = this.options[ measurement ]; 2597 var elem; 2598 if ( !option ) { 2599 // default to 0 2600 this[ measurement ] = 0; 2601 } else { 2602 // use option as an element 2603 if ( typeof option === 'string' ) { 2604 elem = this.element.querySelector( option ); 2605 } else if ( utils.isElement( option ) ) { 2606 elem = option; 2607 } 2608 // use size of element, if element 2609 this[ measurement ] = elem ? getSize( elem )[ size ] : option; 2610 } 2611}; 2612 2613/** 2614 * layout a collection of item elements 2615 * @api public 2616 */ 2617Outlayer.prototype.layoutItems = function( items, isInstant ) { 2618 items = this._getItemsForLayout( items ); 2619 2620 this._layoutItems( items, isInstant ); 2621 2622 this._postLayout(); 2623}; 2624 2625/** 2626 * get the items to be laid out 2627 * you may want to skip over some items 2628 * @param {Array} items 2629 * @returns {Array} items 2630 */ 2631Outlayer.prototype._getItemsForLayout = function( items ) { 2632 var layoutItems = []; 2633 for ( var i=0, len = items.length; i < len; i++ ) { 2634 var item = items[i]; 2635 if ( !item.isIgnored ) { 2636 layoutItems.push( item ); 2637 } 2638 } 2639 return layoutItems; 2640}; 2641 2642/** 2643 * layout items 2644 * @param {Array} items 2645 * @param {Boolean} isInstant 2646 */ 2647Outlayer.prototype._layoutItems = function( items, isInstant ) { 2648 this._emitCompleteOnItems( 'layout', items ); 2649 2650 if ( !items || !items.length ) { 2651 // no items, emit event with empty array 2652 return; 2653 } 2654 2655 var queue = []; 2656 2657 for ( var i=0, len = items.length; i < len; i++ ) { 2658 var item = items[i]; 2659 // get x/y object from method 2660 var position = this._getItemLayoutPosition( item ); 2661 // enqueue 2662 position.item = item; 2663 position.isInstant = isInstant || item.isLayoutInstant; 2664 queue.push( position ); 2665 } 2666 2667 this._processLayoutQueue( queue ); 2668}; 2669 2670/** 2671 * get item layout position 2672 * @param {Outlayer.Item} item 2673 * @returns {Object} x and y position 2674 */ 2675Outlayer.prototype._getItemLayoutPosition = function( /* item */ ) { 2676 return { 2677 x: 0, 2678 y: 0 2679 }; 2680}; 2681 2682/** 2683 * iterate over array and position each item 2684 * Reason being - separating this logic prevents 'layout invalidation' 2685 * thx @paul_irish 2686 * @param {Array} queue 2687 */ 2688Outlayer.prototype._processLayoutQueue = function( queue ) { 2689 for ( var i=0, len = queue.length; i < len; i++ ) { 2690 var obj = queue[i]; 2691 this._positionItem( obj.item, obj.x, obj.y, obj.isInstant ); 2692 } 2693}; 2694 2695/** 2696 * Sets position of item in DOM 2697 * @param {Outlayer.Item} item 2698 * @param {Number} x - horizontal position 2699 * @param {Number} y - vertical position 2700 * @param {Boolean} isInstant - disables transitions 2701 */ 2702Outlayer.prototype._positionItem = function( item, x, y, isInstant ) { 2703 if ( isInstant ) { 2704 // if not transition, just set CSS 2705 item.goTo( x, y ); 2706 } else { 2707 item.moveTo( x, y ); 2708 } 2709}; 2710 2711/** 2712 * Any logic you want to do after each layout, 2713 * i.e. size the container 2714 */ 2715Outlayer.prototype._postLayout = function() { 2716 this.resizeContainer(); 2717}; 2718 2719Outlayer.prototype.resizeContainer = function() { 2720 if ( !this.options.isResizingContainer ) { 2721 return; 2722 } 2723 var size = this._getContainerSize(); 2724 if ( size ) { 2725 this._setContainerMeasure( size.width, true ); 2726 this._setContainerMeasure( size.height, false ); 2727 } 2728}; 2729 2730/** 2731 * Sets width or height of container if returned 2732 * @returns {Object} size 2733 * @param {Number} width 2734 * @param {Number} height 2735 */ 2736Outlayer.prototype._getContainerSize = noop; 2737 2738/** 2739 * @param {Number} measure - size of width or height 2740 * @param {Boolean} isWidth 2741 */ 2742Outlayer.prototype._setContainerMeasure = function( measure, isWidth ) { 2743 if ( measure === undefined ) { 2744 return; 2745 } 2746 2747 var elemSize = this.size; 2748 // add padding and border width if border box 2749 if ( elemSize.isBorderBox ) { 2750 measure += isWidth ? elemSize.paddingLeft + elemSize.paddingRight + 2751 elemSize.borderLeftWidth + elemSize.borderRightWidth : 2752 elemSize.paddingBottom + elemSize.paddingTop + 2753 elemSize.borderTopWidth + elemSize.borderBottomWidth; 2754 } 2755 2756 measure = Math.max( measure, 0 ); 2757 this.element.style[ isWidth ? 'width' : 'height' ] = measure + 'px'; 2758}; 2759 2760/** 2761 * emit eventComplete on a collection of items events 2762 * @param {String} eventName 2763 * @param {Array} items - Outlayer.Items 2764 */ 2765Outlayer.prototype._emitCompleteOnItems = function( eventName, items ) { 2766 var _this = this; 2767 function onComplete() { 2768 _this.dispatchEvent( eventName + 'Complete', null, [ items ] ); 2769 } 2770 2771 var count = items.length; 2772 if ( !items || !count ) { 2773 onComplete(); 2774 return; 2775 } 2776 2777 var doneCount = 0; 2778 function tick() { 2779 doneCount++; 2780 if ( doneCount === count ) { 2781 onComplete(); 2782 } 2783 } 2784 2785 // bind callback 2786 for ( var i=0, len = items.length; i < len; i++ ) { 2787 var item = items[i]; 2788 item.once( eventName, tick ); 2789 } 2790}; 2791 2792/** 2793 * emits events via eventEmitter and jQuery events 2794 * @param {String} type - name of event 2795 * @param {Event} event - original event 2796 * @param {Array} args - extra arguments 2797 */ 2798Outlayer.prototype.dispatchEvent = function( type, event, args ) { 2799 // add original event to arguments 2800 var emitArgs = event ? [ event ].concat( args ) : args; 2801 this.emitEvent( type, emitArgs ); 2802 2803 if ( jQuery ) { 2804 // set this.$element 2805 this.$element = this.$element || jQuery( this.element ); 2806 if ( event ) { 2807 // create jQuery event 2808 var $event = jQuery.Event( event ); 2809 $event.type = type; 2810 this.$element.trigger( $event, args ); 2811 } else { 2812 // just trigger with type if no event available 2813 this.$element.trigger( type, args ); 2814 } 2815 } 2816}; 2817 2818// -------------------------- ignore & stamps -------------------------- // 2819 2820 2821/** 2822 * keep item in collection, but do not lay it out 2823 * ignored items do not get skipped in layout 2824 * @param {Element} elem 2825 */ 2826Outlayer.prototype.ignore = function( elem ) { 2827 var item = this.getItem( elem ); 2828 if ( item ) { 2829 item.isIgnored = true; 2830 } 2831}; 2832 2833/** 2834 * return item to layout collection 2835 * @param {Element} elem 2836 */ 2837Outlayer.prototype.unignore = function( elem ) { 2838 var item = this.getItem( elem ); 2839 if ( item ) { 2840 delete item.isIgnored; 2841 } 2842}; 2843 2844/** 2845 * adds elements to stamps 2846 * @param {NodeList, Array, Element, or String} elems 2847 */ 2848Outlayer.prototype.stamp = function( elems ) { 2849 elems = this._find( elems ); 2850 if ( !elems ) { 2851 return; 2852 } 2853
2854 this.stamps = this.stamps.concat( elems ); 2855 // ignore 2856 for ( var i=0, len = elems.length; i < len; i++ ) { 2857 var elem = elems[i]; 2858 this.ignore( elem ); 2859 } 2860}; 2861 2862/** 2863 * removes elements to stamps 2864 * @param {NodeList, Array, or Element} elems 2865 */ 2866Outlayer.prototype.unstamp = function( elems ) { 2867 elems = this._find( elems ); 2868 if ( !elems ){ 2869 return; 2870 } 2871 2872 for ( var i=0, len = elems.length; i < len; i++ ) { 2873 var elem = elems[i]; 2874 // filter out removed stamp elements 2875 utils.removeFrom( this.stamps, elem ); 2876 this.unignore( elem ); 2877 } 2878 2879}; 2880 2881/** 2882 * finds child elements 2883 * @param {NodeList, Array, Element, or String} elems 2884 * @returns {Array} elems 2885 */ 2886Outlayer.prototype._find = function( elems ) { 2887 if ( !elems ) { 2888 return; 2889 } 2890 // if string, use argument as selector string 2891 if ( typeof elems === 'string' ) { 2892 elems = this.element.querySelectorAll( elems ); 2893 } 2894 elems = utils.makeArray( elems ); 2895 return elems; 2896}; 2897 2898Outlayer.prototype._manageStamps = function() { 2899 if ( !this.stamps || !this.stamps.length ) { 2900 return; 2901 } 2902 2903 this._getBoundingRect(); 2904 2905 for ( var i=0, len = this.stamps.length; i < len; i++ ) { 2906 var stamp = this.stamps[i]; 2907 this._manageStamp( stamp ); 2908 } 2909}; 2910 2911// update boundingLeft / Top 2912Outlayer.prototype._getBoundingRect = function() { 2913 // get bounding rect for container element 2914 var boundingRect = this.element.getBoundingClientRect(); 2915 var size = this.size; 2916 this._boundingRect = { 2917 left: boundingRect.left + size.paddingLeft + size.borderLeftWidth, 2918 top: boundingRect.top + size.paddingTop + size.borderTopWidth, 2919 right: boundingRect.right - ( size.paddingRight + size.borderRightWidth ), 2920 bottom: boundingRect.bottom - ( size.paddingBottom + size.borderBottomWidth ) 2921 }; 2922}; 2923 2924/** 2925 * @param {Element} stamp 2926**/ 2927Outlayer.prototype._manageStamp = noop; 2928 2929/** 2930 * get x/y position of element relative to container element 2931 * @param {Element} elem 2932 * @returns {Object} offset - has left, top, right, bottom 2933 */ 2934Outlayer.prototype._getElementOffset = function( elem ) { 2935 var boundingRect = elem.getBoundingClientRect(); 2936 var thisRect = this._boundingRect; 2937 var size = getSize( elem ); 2938 var offset = { 2939 left: boundingRect.left - thisRect.left - size.marginLeft, 2940 top: boundingRect.top - thisRect.top - size.marginTop, 2941 right: thisRect.right - boundingRect.right - size.marginRight, 2942 bottom: thisRect.bottom - boundingRect.bottom - size.marginBottom 2943 }; 2944 return offset; 2945}; 2946 2947// -------------------------- resize -------------------------- // 2948 2949// enable event handlers for listeners 2950// i.e. resize -> onresize 2951Outlayer.prototype.handleEvent = function( event ) { 2952 var method = 'on' + event.type; 2953 if ( this[ method ] ) { 2954 this[ method ]( event ); 2955 } 2956}; 2957 2958/** 2959 * Bind layout to window resizing 2960 */ 2961Outlayer.prototype.bindResize = function() { 2962 // bind just one listener 2963 if ( this.isResizeBound ) { 2964 return; 2965 } 2966 eventie.bind( window, 'resize', this ); 2967 this.isResizeBound = true; 2968}; 2969 2970/** 2971 * Unbind layout to window resizing 2972 */ 2973Outlayer.prototype.unbindResize = function() { 2974 if ( this.isResizeBound ) { 2975 eventie.unbind( window, 'resize', this ); 2976 } 2977 this.isResizeBound = false; 2978}; 2979 2980// original debounce by John Hann 2981// http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/ 2982 2983// this fires every resize 2984Outlayer.prototype.onresize = function() { 2985 if ( this.resizeTimeout ) { 2986 clearTimeout( this.resizeTimeout ); 2987 } 2988 2989 var _this = this; 2990 function delayed() { 2991 _this.resize(); 2992 delete _this.resizeTimeout; 2993 } 2994 2995 this.resizeTimeout = setTimeout( delayed, 100 ); 2996}; 2997 2998// debounced, layout on resize 2999Outlayer.prototype.resize = function() { 3000 // don't trigger if size did not change 3001 // or if resize was unbound. See #9 3002 if ( !this.isResizeBound || !this.needsResizeLayout() ) { 3003 return; 3004 } 3005 3006 this.layout(); 3007}; 3008 3009/** 3010 * check if layout is needed post layout 3011 * @returns Boolean 3012 */ 3013Outlayer.prototype.needsResizeLayout = function() { 3014 var size = getSize( this.element ); 3015 // check that this.size and size are there 3016 // IE8 triggers resize on body size change, so they might not be 3017 var hasSizes = this.size && size; 3018 return hasSizes && size.innerWidth !== this.size.innerWidth; 3019}; 3020 3021// -------------------------- methods -------------------------- // 3022 3023/** 3024 * add items to Outlayer instance 3025 * @param {Array or NodeList or Element} elems 3026 * @returns {Array} items - Outlayer.Items 3027**/ 3028Outlayer.prototype.addItems = function( elems ) { 3029 var items = this._itemize( elems ); 3030 // add items to collection 3031 if ( items.length ) { 3032 this.items = this.items.concat( items ); 3033 } 3034 return items; 3035}; 3036 3037/** 3038 * Layout newly-appended item elements 3039 * @param {Array or NodeList or Element} elems 3040 */ 3041Outlayer.prototype.appended = function( elems ) { 3042 var items = this.addItems( elems ); 3043 if ( !items.length ) { 3044 return; 3045 } 3046 // layout and reveal just the new items 3047 this.layoutItems( items, true ); 3048 this.reveal( items ); 3049}; 3050 3051/** 3052 * Layout prepended elements 3053 * @param {Array or NodeList or Element} elems 3054 */ 3055Outlayer.prototype.prepended = function( elems ) { 3056 var items = this._itemize( elems ); 3057 if ( !items.length ) { 3058 return; 3059 } 3060 // add items to beginning of collection 3061 var previousItems = this.items.slice(0); 3062 this.items = items.concat( previousItems ); 3063 // start new layout 3064 this._resetLayout(); 3065 this._manageStamps(); 3066 // layout new stuff without transition 3067 this.layoutItems( items, true ); 3068 this.reveal( items ); 3069 // layout previous items 3070 this.layoutItems( previousItems ); 3071}; 3072 3073/** 3074 * reveal a collection of items 3075 * @param {Array of Outlayer.Items} items 3076 */ 3077Outlayer.prototype.reveal = function( items ) { 3078 this._emitCompleteOnItems( 'reveal', items ); 3079 3080 var len = items && items.length; 3081 for ( var i=0; len && i < len; i++ ) { 3082 var item = items[i]; 3083 item.reveal(); 3084 } 3085}; 3086 3087/** 3088 * hide a collection of items 3089 * @param {Array of Outlayer.Items} items 3090 */ 3091Outlayer.prototype.hide = function( items ) { 3092 this._emitCompleteOnItems( 'hide', items ); 3093 3094 var len = items && items.length; 3095 for ( var i=0; len && i < len; i++ ) { 3096 var item = items[i]; 3097 item.hide(); 3098 } 3099}; 3100 3101/** 3102 * reveal item elements 3103 * @param {Array}, {Element}, {NodeList} items 3104 */ 3105Outlayer.prototype.revealItemElements = function( elems ) { 3106 var items = this.getItems( elems ); 3107 this.reveal( items ); 3108}; 3109 3110/** 3111 * hide item elements 3112 * @param {Array}, {Element}, {NodeList} items 3113 */ 3114Outlayer.prototype.hideItemElements = function( elems ) { 3115 var items = this.getItems( elems ); 3116 this.hide( items ); 3117}; 3118 3119/** 3120 * get Outlayer.Item, given an Element 3121 * @param {Element} elem 3122 * @param {Function} callback 3123 * @returns {Outlayer.Item} item 3124 */ 3125Outlayer.prototype.getItem = function( elem ) { 3126 // loop through items to get the one that matches 3127 for ( var i=0, len = this.items.length; i < len; i++ ) { 3128 var item = this.items[i]; 3129 if ( item.element === elem ) { 3130 // return item 3131 return item; 3132 } 3133 } 3134}; 3135 3136/** 3137 * get collection of Outlayer.Items, given Elements 3138 * @param {Array} elems 3139 * @returns {Array} items - Outlayer.Items 3140 */ 3141Outlayer.prototype.getItems = function( elems ) { 3142 elems = utils.makeArray( elems ); 3143 var items = []; 3144 for ( var i=0, len = elems.length; i < len; i++ ) { 3145 var elem = elems[i]; 3146 var item = this.getItem( elem ); 3147 if ( item ) { 3148 items.push( item ); 3149 } 3150 } 3151 3152 return items; 3153}; 3154 3155/**
3156 * remove element(s) from instance and DOM 3157 * @param {Array or NodeList or Element} elems 3158 */ 3159Outlayer.prototype.remove = function( elems ) { 3160 var removeItems = this.getItems( elems ); 3161 3162 this._emitCompleteOnItems( 'remove', removeItems ); 3163 3164 // bail if no items to remove 3165 if ( !removeItems || !removeItems.length ) { 3166 return; 3167 } 3168 3169 for ( var i=0, len = removeItems.length; i < len; i++ ) { 3170 var item = removeItems[i]; 3171 item.remove(); 3172 // remove item from collection 3173 utils.removeFrom( this.items, item ); 3174 } 3175}; 3176 3177// ----- destroy ----- // 3178 3179// remove and disable Outlayer instance 3180Outlayer.prototype.destroy = function() { 3181 // clean up dynamic styles 3182 var style = this.element.style; 3183 style.height = ''; 3184 style.position = ''; 3185 style.width = ''; 3186 // destroy items 3187 for ( var i=0, len = this.items.length; i < len; i++ ) { 3188 var item = this.items[i]; 3189 item.destroy(); 3190 } 3191 3192 this.unbindResize(); 3193 3194 var id = this.element.outlayerGUID; 3195 delete instances[ id ]; // remove reference to instance by id 3196 delete this.element.outlayerGUID; 3197 // remove data for jQuery 3198 if ( jQuery ) { 3199 jQuery.removeData( this.element, this.constructor.namespace ); 3200 } 3201 3202}; 3203 3204// -------------------------- data -------------------------- // 3205 3206/** 3207 * get Outlayer instance from element 3208 * @param {Element} elem 3209 * @returns {Outlayer} 3210 */ 3211Outlayer.data = function( elem ) { 3212 elem = utils.getQueryElement( elem ); 3213 var id = elem && elem.outlayerGUID; 3214 return id && instances[ id ]; 3215}; 3216 3217 3218// -------------------------- create Outlayer class -------------------------- // 3219 3220/** 3221 * create a layout class 3222 * @param {String} namespace 3223 */ 3224Outlayer.create = function( namespace, options ) { 3225 // sub-class Outlayer 3226 function Layout() { 3227 Outlayer.apply( this, arguments ); 3228 } 3229 // inherit Outlayer prototype, use Object.create if there 3230 if ( Object.create ) { 3231 Layout.prototype = Object.create( Outlayer.prototype ); 3232 } else { 3233 utils.extend( Layout.prototype, Outlayer.prototype ); 3234 } 3235 // set contructor, used for namespace and Item 3236 Layout.prototype.constructor = Layout; 3237 3238 Layout.defaults = utils.extend( {}, Outlayer.defaults ); 3239 // apply new options 3240 utils.extend( Layout.defaults, options ); 3241 // keep prototype.settings for backwards compatibility (Packery v1.2.0) 3242 Layout.prototype.settings = {}; 3243 3244 Layout.namespace = namespace; 3245 3246 Layout.data = Outlayer.data; 3247 3248 // sub-class Item 3249 Layout.Item = function LayoutItem() { 3250 Item.apply( this, arguments ); 3251 }; 3252 3253 Layout.Item.prototype = new Item(); 3254 3255 // -------------------------- declarative -------------------------- // 3256 3257 utils.htmlInit( Layout, namespace ); 3258 3259 // -------------------------- jQuery bridge -------------------------- // 3260 3261 // make into jQuery plugin 3262 if ( jQuery && jQuery.bridget ) { 3263 jQuery.bridget( namespace, Layout ); 3264 } 3265 3266 return Layout; 3267}; 3268 3269// ----- fin ----- // 3270 3271// back in global 3272Outlayer.Item = Item; 3273 3274return Outlayer; 3275 3276})); 3277 3278 3279/** 3280 * Isotope Item 3281**/ 3282 3283( function( window, factory ) { 3284'use strict'; 3285 // universal module definition 3286 if ( typeof define == 'function' && define.amd ) { 3287 // AMD 3288 define( 'isotope/js/item',[ 3289 'outlayer/outlayer' 3290 ], 3291 factory ); 3292 } else if ( typeof exports == 'object' ) { 3293 // CommonJS 3294 module.exports = factory( 3295 require('outlayer') 3296 ); 3297 } else { 3298 // browser global 3299 window.Isotope = window.Isotope || {}; 3300 window.Isotope.Item = factory( 3301 window.Outlayer 3302 ); 3303 } 3304 3305}( window, function factory( Outlayer ) { 3306'use strict'; 3307 3308// -------------------------- Item -------------------------- // 3309 3310// sub-class Outlayer Item 3311function Item() { 3312 Outlayer.Item.apply( this, arguments ); 3313} 3314 3315Item.prototype = new Outlayer.Item(); 3316 3317Item.prototype._create = function() { 3318 // assign id, used for original-order sorting 3319 this.id = this.layout.itemGUID++; 3320 Outlayer.Item.prototype._create.call( this ); 3321 this.sortData = {}; 3322}; 3323 3324Item.prototype.updateSortData = function() { 3325 if ( this.isIgnored ) { 3326 return; 3327 } 3328 // default sorters 3329 this.sortData.id = this.id; 3330 // for backward compatibility 3331 this.sortData['original-order'] = this.id; 3332 this.sortData.random = Math.random(); 3333 // go thru getSortData obj and apply the sorters 3334 var getSortData = this.layout.options.getSortData; 3335 var sorters = this.layout._sorters; 3336 for ( var key in getSortData ) { 3337 var sorter = sorters[ key ]; 3338 this.sortData[ key ] = sorter( this.element, this ); 3339 } 3340}; 3341 3342var _destroy = Item.prototype.destroy; 3343Item.prototype.destroy = function() { 3344 // call super 3345 _destroy.apply( this, arguments ); 3346 // reset display, #741 3347 this.css({ 3348 display: '' 3349 }); 3350}; 3351 3352return Item; 3353 3354})); 3355 3356/** 3357 * Isotope LayoutMode 3358 */ 3359 3360( function( window, factory ) { 3361 'use strict'; 3362 // universal module definition 3363 3364 if ( typeof define == 'function' && define.amd ) { 3365 // AMD 3366 define( 'isotope/js/layout-mode',[ 3367 'get-size/get-size', 3368 'outlayer/outlayer' 3369 ], 3370 factory ); 3371 } else if ( typeof exports == 'object' ) { 3372 // CommonJS 3373 module.exports = factory( 3374 require('get-size'), 3375 require('outlayer') 3376 ); 3377 } else { 3378 // browser global 3379 window.Isotope = window.Isotope || {}; 3380 window.Isotope.LayoutMode = factory( 3381 window.getSize, 3382 window.Outlayer 3383 ); 3384 } 3385 3386}( window, function factory( getSize, Outlayer ) { 3387 'use strict'; 3388 3389 // layout mode class 3390 function LayoutMode( isotope ) { 3391 this.isotope = isotope; 3392 // link properties 3393 if ( isotope ) { 3394 this.options = isotope.options[ this.namespace ]; 3395 this.element = isotope.element; 3396 this.items = isotope.filteredItems; 3397 this.size = isotope.size; 3398 } 3399 } 3400 3401 /** 3402 * some methods should just defer to default Outlayer method 3403 * and reference the Isotope instance as `this` 3404 **/ 3405 ( function() { 3406 var facadeMethods = [ 3407 '_resetLayout', 3408 '_getItemLayoutPosition', 3409 '_manageStamp', 3410 '_getContainerSize', 3411 '_getElementOffset', 3412 'needsResizeLayout' 3413 ]; 3414 3415 for ( var i=0, len = facadeMethods.length; i < len; i++ ) { 3416 var methodName = facadeMethods[i]; 3417 LayoutMode.prototype[ methodName ] = getOutlayerMethod( methodName ); 3418 } 3419 3420 function getOutlayerMethod( methodName ) { 3421 return function() { 3422 return Outlayer.prototype[ methodName ].apply( this.isotope, arguments ); 3423 }; 3424 } 3425 })(); 3426 3427 // ----- ----- // 3428 3429 // for horizontal layout modes, check vertical size 3430 LayoutMode.prototype.needsVerticalResizeLayout = function() {
vendor: 20,029 bytes, lines 3431-4166
3431 // don't trigger if size did not change 3432 var size = getSize( this.isotope.element ); 3433 // check that this.size and size are there 3434 // IE8 triggers resize on body size change, so they might not be 3435 var hasSizes = this.isotope.size && size; 3436 return hasSizes && size.innerHeight != this.isotope.size.innerHeight; 3437 }; 3438 3439 // ----- measurements ----- // 3440 3441 LayoutMode.prototype._getMeasurement = function() { 3442 this.isotope._getMeasurement.apply( this, arguments ); 3443 }; 3444 3445 LayoutMode.prototype.getColumnWidth = function() { 3446 this.getSegmentSize( 'column', 'Width' ); 3447 }; 3448 3449 LayoutMode.prototype.getRowHeight = function() { 3450 this.getSegmentSize( 'row', 'Height' ); 3451 }; 3452 3453 /** 3454 * get columnWidth or rowHeight 3455 * segment: 'column' or 'row' 3456 * size 'Width' or 'Height' 3457 **/ 3458 LayoutMode.prototype.getSegmentSize = function( segment, size ) { 3459 var segmentName = segment + size; 3460 var outerSize = 'outer' + size; 3461 // columnWidth / outerWidth // rowHeight / outerHeight 3462 this._getMeasurement( segmentName, outerSize ); 3463 // got rowHeight or columnWidth, we can chill 3464 if ( this[ segmentName ] ) { 3465 return; 3466 } 3467 // fall back to item of first element 3468 var firstItemSize = this.getFirstItemSize(); 3469 this[ segmentName ] = firstItemSize && firstItemSize[ outerSize ] || 3470 // or size of container 3471 this.isotope.size[ 'inner' + size ]; 3472 }; 3473 3474 LayoutMode.prototype.getFirstItemSize = function() { 3475 var firstItem = this.isotope.filteredItems[0]; 3476 return firstItem && firstItem.element && getSize( firstItem.element ); 3477 }; 3478 3479 // ----- methods that should reference isotope ----- // 3480 3481 LayoutMode.prototype.layout = function() { 3482 this.isotope.layout.apply( this.isotope, arguments ); 3483 }; 3484 3485 LayoutMode.prototype.getSize = function() { 3486 this.isotope.getSize(); 3487 this.size = this.isotope.size; 3488 }; 3489 3490 // -------------------------- create -------------------------- // 3491 3492 LayoutMode.modes = {}; 3493 3494 LayoutMode.create = function( namespace, options ) { 3495 3496 function Mode() { 3497 LayoutMode.apply( this, arguments ); 3498 } 3499 3500 Mode.prototype = new LayoutMode(); 3501 3502 // default options 3503 if ( options ) { 3504 Mode.options = options; 3505 } 3506 3507 Mode.prototype.namespace = namespace; 3508 // register in Isotope 3509 LayoutMode.modes[ namespace ] = Mode; 3510 3511 return Mode; 3512 }; 3513 3514 return LayoutMode; 3515 3516})); 3517 3518/*! 3519 * Masonry v3.3.1 3520 * Cascading grid layout library 3521 * http://masonry.desandro.com 3522 * MIT License 3523 * by David DeSandro 3524 */ 3525 3526( function( window, factory ) { 3527 'use strict'; 3528 // universal module definition 3529 if ( typeof define === 'function' && define.amd ) { 3530 // AMD 3531 define( 'masonry/masonry',[ 3532 'outlayer/outlayer', 3533 'get-size/get-size', 3534 'fizzy-ui-utils/utils' 3535 ], 3536 factory ); 3537 } else if ( typeof exports === 'object' ) { 3538 // CommonJS 3539 module.exports = factory( 3540 require('outlayer'), 3541 require('get-size'), 3542 require('fizzy-ui-utils') 3543 ); 3544 } else { 3545 // browser global 3546 window.Masonry = factory( 3547 window.Outlayer, 3548 window.getSize, 3549 window.fizzyUIUtils 3550 ); 3551 } 3552 3553}( window, function factory( Outlayer, getSize, utils ) { 3554 3555 3556 3557// -------------------------- masonryDefinition -------------------------- // 3558 3559 // create an Outlayer layout class 3560 var Masonry = Outlayer.create('masonry'); 3561 3562 Masonry.prototype._resetLayout = function() { 3563 this.getSize(); 3564 this._getMeasurement( 'columnWidth', 'outerWidth' ); 3565 this._getMeasurement( 'gutter', 'outerWidth' ); 3566 this.measureColumns(); 3567 3568 // reset column Y 3569 var i = this.cols; 3570 this.colYs = []; 3571 while (i--) { 3572 this.colYs.push( 0 ); 3573 } 3574 3575 this.maxY = 0; 3576 }; 3577 3578 Masonry.prototype.measureColumns = function() { 3579 this.getContainerWidth(); 3580 // if columnWidth is 0, default to outerWidth of first item 3581 if ( !this.columnWidth ) { 3582 var firstItem = this.items[0]; 3583 var firstItemElem = firstItem && firstItem.element; 3584 // columnWidth fall back to item of first element 3585 this.columnWidth = firstItemElem && getSize( firstItemElem ).outerWidth || 3586 // if first elem has no width, default to size of container 3587 this.containerWidth; 3588 } 3589 3590 var columnWidth = this.columnWidth += this.gutter; 3591 3592 // calculate columns 3593 var containerWidth = this.containerWidth + this.gutter; 3594 var cols = containerWidth / columnWidth; 3595 // fix rounding errors, typically with gutters 3596 var excess = columnWidth - containerWidth % columnWidth; 3597 // if overshoot is less than a pixel, round up, otherwise floor it 3598 var mathMethod = excess && excess < 1 ? 'round' : 'floor'; 3599 cols = Math[ mathMethod ]( cols ); 3600 this.cols = Math.max( cols, 1 ); 3601 }; 3602 3603 Masonry.prototype.getContainerWidth = function() { 3604 // container is parent if fit width 3605 var container = this.options.isFitWidth ? this.element.parentNode : this.element; 3606 // check that this.size and size are there 3607 // IE8 triggers resize on body size change, so they might not be 3608 var size = getSize( container ); 3609 this.containerWidth = size && size.innerWidth; 3610 }; 3611 3612 Masonry.prototype._getItemLayoutPosition = function( item ) { 3613 item.getSize(); 3614 // how many columns does this brick span 3615 var remainder = item.size.outerWidth % this.columnWidth; 3616 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil'; 3617 // round if off by 1 pixel, otherwise use ceil 3618 var colSpan = Math[ mathMethod ]( item.size.outerWidth / this.columnWidth ); 3619 colSpan = Math.min( colSpan, this.cols ); 3620 3621 var colGroup = this._getColGroup( colSpan ); 3622 // get the minimum Y value from the columns 3623 var minimumY = Math.min.apply( Math, colGroup ); 3624 var shortColIndex = utils.indexOf( colGroup, minimumY ); 3625 3626 // position the brick 3627 var position = { 3628 x: this.columnWidth * shortColIndex, 3629 y: minimumY 3630 }; 3631 3632 // apply setHeight to necessary columns 3633 var setHeight = minimumY + item.size.outerHeight; 3634 var setSpan = this.cols + 1 - colGroup.length; 3635 for ( var i = 0; i < setSpan; i++ ) { 3636 this.colYs[ shortColIndex + i ] = setHeight; 3637 } 3638 3639 return position; 3640 }; 3641 3642 /** 3643 * @param {Number} colSpan - number of columns the element spans 3644 * @returns {Array} colGroup 3645 */ 3646 Masonry.prototype._getColGroup = function( colSpan ) { 3647 if ( colSpan < 2 ) { 3648 // if brick spans only one column, use all the column Ys 3649 return this.colYs; 3650 } 3651 3652 var colGroup = []; 3653 // how many different places could this brick fit horizontally 3654 var groupCount = this.cols + 1 - colSpan; 3655 // for each group potential horizontal position 3656 for ( var i = 0; i < groupCount; i++ ) { 3657 // make an array of colY values for that one group 3658 var groupColYs = this.colYs.slice( i, i + colSpan ); 3659 // and get the max value of the array 3660 colGroup[i] = Math.max.apply( Math, groupColYs ); 3661 } 3662 return colGroup; 3663 }; 3664 3665 Masonry.prototype._manageStamp = function( stamp ) { 3666 var stampSize = getSize( stamp ); 3667 var offset = this._getElementOffset( stamp ); 3668 // get the columns that this stamp affects 3669 var firstX = this.options.isOriginLeft ? offset.left : offset.right; 3670 var lastX = firstX + stampSize.outerWidth; 3671 var firstCol = Math.floor( firstX / this.columnWidth ); 3672 firstCol = Math.max( 0, firstCol ); 3673 var lastCol = Math.floor( lastX / this.columnWidth ); 3674 // lastCol should not go over if multiple of columnWidth #425 3675 lastCol -= lastX % this.columnWidth ? 0 : 1; 3676 lastCol = Math.min( this.cols - 1, lastCol ); 3677 // set colYs to bottom of the stamp 3678 var stampMaxY = ( this.options.isOriginTop ? offset.top : offset.bottom ) + 3679 stampSize.outerHeight; 3680 for ( var i = firstCol; i <= lastCol; i++ ) { 3681 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] ); 3682 } 3683 }; 3684 3685 Masonry.prototype._getContainerSize = function() { 3686 this.maxY = Math.max.apply( Math, this.colYs ); 3687 var size = { 3688 height: this.maxY 3689 }; 3690 3691 if ( this.options.isFitWidth ) { 3692 size.width = this._getContainerFitWidth(); 3693 } 3694 3695 return size; 3696 }; 3697 3698 Masonry.prototype._getContainerFitWidth = function() { 3699 var unusedCols = 0; 3700 // count unused columns 3701 var i = this.cols; 3702 while ( --i ) { 3703 if ( this.colYs[i] !== 0 ) { 3704 break; 3705 } 3706 unusedCols++; 3707 } 3708 // fit container to columns that have been used 3709 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter; 3710 }; 3711 3712 Masonry.prototype.needsResizeLayout = function() { 3713 var previousWidth = this.containerWidth; 3714 this.getContainerWidth(); 3715 return previousWidth !== this.containerWidth; 3716 }; 3717 3718 return Masonry; 3719 3720})); 3721 3722/*! 3723 * Masonry layout mode 3724 * sub-classes Masonry 3725 * http://masonry.desandro.com 3726 */ 3727 3728( function( window, factory ) { 3729 'use strict'; 3730 // universal module definition 3731 if ( typeof define == 'function' && define.amd ) { 3732 // AMD 3733 define( 'isotope/js/layout-modes/masonry',[ 3734 '../layout-mode', 3735 'masonry/masonry' 3736 ], 3737 factory ); 3738 } else if ( typeof exports == 'object' ) { 3739 // CommonJS 3740 module.exports = factory( 3741 require('../layout-mode'), 3742 require('masonry-layout') 3743 ); 3744 } else { 3745 // browser global 3746 factory( 3747 window.Isotope.LayoutMode, 3748 window.Masonry 3749 ); 3750 } 3751 3752}( window, function factory( LayoutMode, Masonry ) { 3753'use strict'; 3754 3755// -------------------------- helpers -------------------------- // 3756 3757// extend objects 3758function extend( a, b ) { 3759 for ( var prop in b ) { 3760 a[ prop ] = b[ prop ]; 3761 } 3762 return a; 3763} 3764 3765// -------------------------- masonryDefinition -------------------------- // 3766 3767 // create an Outlayer layout class 3768 var MasonryMode = LayoutMode.create('masonry'); 3769 3770 // save on to these methods 3771 var _getElementOffset = MasonryMode.prototype._getElementOffset; 3772 var layout = MasonryMode.prototype.layout; 3773 var _getMeasurement = MasonryMode.prototype._getMeasurement; 3774 3775 // sub-class Masonry 3776 extend( MasonryMode.prototype, Masonry.prototype ); 3777 3778 // set back, as it was overwritten by Masonry 3779 MasonryMode.prototype._getElementOffset = _getElementOffset; 3780 MasonryMode.prototype.layout = layout; 3781 MasonryMode.prototype._getMeasurement = _getMeasurement; 3782 3783 var measureColumns = MasonryMode.prototype.measureColumns; 3784 MasonryMode.prototype.measureColumns = function() { 3785 // set items, used if measuring first item 3786 this.items = this.isotope.filteredItems; 3787 measureColumns.call( this ); 3788 }; 3789 3790 // HACK copy over isOriginLeft/Top options 3791 var _manageStamp = MasonryMode.prototype._manageStamp; 3792 MasonryMode.prototype._manageStamp = function() { 3793 this.options.isOriginLeft = this.isotope.options.isOriginLeft; 3794 this.options.isOriginTop = this.isotope.options.isOriginTop; 3795 _manageStamp.apply( this, arguments ); 3796 }; 3797 3798 return MasonryMode; 3799 3800})); 3801 3802/** 3803 * fitRows layout mode 3804 */ 3805 3806( function( window, factory ) { 3807 'use strict'; 3808 // universal module definition 3809 if ( typeof define == 'function' && define.amd ) { 3810 // AMD 3811 define( 'isotope/js/layout-modes/fit-rows',[ 3812 '../layout-mode' 3813 ], 3814 factory ); 3815 } else if ( typeof exports == 'object' ) { 3816 // CommonJS 3817 module.exports = factory( 3818 require('../layout-mode') 3819 ); 3820 } else { 3821 // browser global 3822 factory( 3823 window.Isotope.LayoutMode 3824 ); 3825 } 3826 3827}( window, function factory( LayoutMode ) { 3828'use strict'; 3829 3830var FitRows = LayoutMode.create('fitRows'); 3831 3832FitRows.prototype._resetLayout = function() { 3833 this.x = 0; 3834 this.y = 0; 3835 this.maxY = 0; 3836 this._getMeasurement( 'gutter', 'outerWidth' ); 3837}; 3838 3839FitRows.prototype._getItemLayoutPosition = function( item ) { 3840 item.getSize(); 3841 3842 var itemWidth = item.size.outerWidth + this.gutter; 3843 // if this element cannot fit in the current row 3844 var containerWidth = this.isotope.size.innerWidth + this.gutter; 3845 if ( this.x !== 0 && itemWidth + this.x > containerWidth ) { 3846 this.x = 0; 3847 this.y = this.maxY; 3848 } 3849 3850 var position = { 3851 x: this.x, 3852 y: this.y 3853 }; 3854 3855 this.maxY = Math.max( this.maxY, this.y + item.size.outerHeight ); 3856 this.x += itemWidth; 3857 3858 return position; 3859}; 3860 3861FitRows.prototype._getContainerSize = function() { 3862 return { height: this.maxY }; 3863}; 3864 3865return FitRows; 3866 3867})); 3868 3869/** 3870 * vertical layout mode 3871 */ 3872 3873( function( window, factory ) { 3874 'use strict'; 3875 // universal module definition 3876 if ( typeof define == 'function' && define.amd ) { 3877 // AMD 3878 define( 'isotope/js/layout-modes/vertical',[ 3879 '../layout-mode' 3880 ], 3881 factory ); 3882 } else if ( typeof exports == 'object' ) { 3883 // CommonJS 3884 module.exports = factory( 3885 require('../layout-mode') 3886 ); 3887 } else { 3888 // browser global 3889 factory( 3890 window.Isotope.LayoutMode 3891 ); 3892 } 3893 3894}( window, function factory( LayoutMode ) { 3895'use strict'; 3896 3897var Vertical = LayoutMode.create( 'vertical', { 3898 horizontalAlignment: 0 3899}); 3900 3901Vertical.prototype._resetLayout = function() { 3902 this.y = 0; 3903}; 3904 3905Vertical.prototype._getItemLayoutPosition = function( item ) { 3906 item.getSize(); 3907 var x = ( this.isotope.size.innerWidth - item.size.outerWidth ) * 3908 this.options.horizontalAlignment; 3909 var y = this.y; 3910 this.y += item.size.outerHeight; 3911 return { x: x, y: y }; 3912}; 3913 3914Vertical.prototype._getContainerSize = function() { 3915 return { height: this.y }; 3916}; 3917 3918return Vertical; 3919 3920})); 3921 3922/*! 3923 * Isotope v2.2.2 3924 * 3925 * Licensed GPLv3 for open source use 3926 * or Isotope Commercial License for commercial use 3927 * 3928 * http://isotope.metafizzy.co 3929 * Copyright 2015 Metafizzy 3930 */ 3931 3932( function( window, factory ) { 3933 'use strict'; 3934 // universal module definition 3935 3936 if ( typeof define == 'function' && define.amd ) { 3937 // AMD 3938 define( [ 3939 'outlayer/outlayer', 3940 'get-size/get-size', 3941 'matches-selector/matches-selector', 3942 'fizzy-ui-utils/utils', 3943 'isotope/js/item', 3944 'isotope/js/layout-mode', 3945 // include default layout modes 3946 'isotope/js/layout-modes/masonry', 3947 'isotope/js/layout-modes/fit-rows', 3948 'isotope/js/layout-modes/vertical' 3949 ], 3950 function( Outlayer, getSize, matchesSelector, utils, Item, LayoutMode ) { 3951 return factory( window, Outlayer, getSize, matchesSelector, utils, Item, LayoutMode ); 3952 }); 3953 } else if ( typeof exports == 'object' ) { 3954 // CommonJS 3955 module.exports = factory( 3956 window, 3957 require('outlayer'), 3958 require('get-size'), 3959 require('desandro-matches-selector'), 3960 require('fizzy-ui-utils'), 3961 require('./item'), 3962 require('./layout-mode'), 3963 // include default layout modes 3964 require('./layout-modes/masonry'), 3965 require('./layout-modes/fit-rows'), 3966 require('./layout-modes/vertical') 3967 ); 3968 } else { 3969 // browser global 3970 window.Isotope = factory( 3971 window, 3972 window.Outlayer, 3973 window.getSize, 3974 window.matchesSelector, 3975 window.fizzyUIUtils, 3976 window.Isotope.Item, 3977 window.Isotope.LayoutMode 3978 ); 3979 } 3980 3981}( window, function factory( window, Outlayer, getSize, matchesSelector, utils, 3982 Item, LayoutMode ) { 3983 3984 3985 3986// -------------------------- vars -------------------------- // 3987 3988var jQuery = window.jQuery; 3989 3990// -------------------------- helpers -------------------------- // 3991 3992var trim = String.prototype.trim ? 3993 function( str ) { 3994 return str.trim(); 3995 } : 3996 function( str ) { 3997 return str.replace( /^\s+|\s+$/g, '' ); 3998 }; 3999 4000var docElem = document.documentElement; 4001 4002var getText = docElem.textContent ? 4003 function( elem ) { 4004 return elem.textContent; 4005 } : 4006 function( elem ) { 4007 return elem.innerText; 4008 }; 4009 4010// -------------------------- isotopeDefinition -------------------------- // 4011 4012 // create an Outlayer layout class 4013 var Isotope = Outlayer.create( 'isotope', { 4014 layoutMode: "masonry", 4015 isJQueryFiltering: true, 4016 sortAscending: true 4017 }); 4018 4019 Isotope.Item = Item; 4020 Isotope.LayoutMode = LayoutMode; 4021 4022 Isotope.prototype._create = function() { 4023 this.itemGUID = 0; 4024 // functions that sort items 4025 this._sorters = {}; 4026 this._getSorters(); 4027 // call super 4028 Outlayer.prototype._create.call( this ); 4029 4030 // create layout modes 4031 this.modes = {}; 4032 // start filteredItems with all items 4033 this.filteredItems = this.items; 4034 // keep of track of sortBys 4035 this.sortHistory = [ 'original-order' ]; 4036 // create from registered layout modes 4037 for ( var name in LayoutMode.modes ) { 4038 this._initLayoutMode( name ); 4039 } 4040 }; 4041 4042 Isotope.prototype.reloadItems = function() { 4043 // reset item ID counter 4044 this.itemGUID = 0; 4045 // call super 4046 Outlayer.prototype.reloadItems.call( this ); 4047 }; 4048 4049 Isotope.prototype._itemize = function() { 4050 var items = Outlayer.prototype._itemize.apply( this, arguments ); 4051 // assign ID for original-order 4052 for ( var i=0, len = items.length; i < len; i++ ) { 4053 var item = items[i]; 4054 item.id = this.itemGUID++; 4055 } 4056 this._updateItemsSortData( items ); 4057 return items; 4058 }; 4059 4060 4061 // -------------------------- layout -------------------------- // 4062 4063 Isotope.prototype._initLayoutMode = function( name ) { 4064 var Mode = LayoutMode.modes[ name ]; 4065 // set mode options 4066 // HACK extend initial options, back-fill in default options 4067 var initialOpts = this.options[ name ] || {}; 4068 this.options[ name ] = Mode.options ? 4069 utils.extend( Mode.options, initialOpts ) : initialOpts; 4070 // init layout mode instance 4071 this.modes[ name ] = new Mode( this ); 4072 }; 4073 4074 4075 Isotope.prototype.layout = function() { 4076 // if first time doing layout, do all magic 4077 if ( !this._isLayoutInited && this.options.isInitLayout ) { 4078 this.arrange(); 4079 return; 4080 } 4081 this._layout(); 4082 }; 4083 4084 // private method to be used in layout() & magic() 4085 Isotope.prototype._layout = function() { 4086 // don't animate first layout 4087 var isInstant = this._getIsInstant(); 4088 // layout flow 4089 this._resetLayout(); 4090 this._manageStamps(); 4091 this.layoutItems( this.filteredItems, isInstant ); 4092 4093 // flag for initalized 4094 this._isLayoutInited = true; 4095 }; 4096 4097 // filter + sort + layout 4098 Isotope.prototype.arrange = function( opts ) { 4099 // set any options pass 4100 this.option( opts ); 4101 this._getIsInstant(); 4102 // filter, sort, and layout 4103 4104 // filter 4105 var filtered = this._filter( this.items ); 4106 this.filteredItems = filtered.matches; 4107 4108 var _this = this; 4109 function hideReveal() { 4110 _this.reveal( filtered.needReveal ); 4111 _this.hide( filtered.needHide ); 4112 } 4113 4114 this._bindArrangeComplete(); 4115 4116 if ( this._isInstant ) { 4117 this._noTransition( hideReveal ); 4118 } else { 4119 hideReveal(); 4120 } 4121 4122 this._sort(); 4123 this._layout(); 4124 }; 4125 // alias to _init for main plugin method 4126 Isotope.prototype._init = Isotope.prototype.arrange; 4127 4128 // HACK 4129 // Don't animate/transition first layout 4130 // Or don't animate/transition other layouts 4131 Isotope.prototype._getIsInstant = function() { 4132 var isInstant = this.options.isLayoutInstant !== undefined ? 4133 this.options.isLayoutInstant : !this._isLayoutInited; 4134 this._isInstant = isInstant; 4135 return isInstant; 4136 }; 4137 4138 // listen for layoutComplete, hideComplete and revealComplete 4139 // to trigger arrangeComplete 4140 Isotope.prototype._bindArrangeComplete = function() { 4141 // listen for 3 events to trigger arrangeComplete 4142 var isLayoutComplete, isHideComplete, isRevealComplete; 4143 var _this = this; 4144 function arrangeParallelCallback() { 4145 if ( isLayoutComplete && isHideComplete && isRevealComplete ) { 4146 _this.dispatchEvent( 'arrangeComplete', null, [ _this.filteredItems ] ); 4147 } 4148 } 4149 this.once( 'layoutComplete', function() { 4150 isLayoutComplete = true; 4151 arrangeParallelCallback(); 4152 }); 4153 this.once( 'hideComplete', function() { 4154 isHideComplete = true; 4155 arrangeParallelCallback(); 4156 }); 4157 this.once( 'revealComplete', function() { 4158 isRevealComplete = true; 4159 arrangeParallelCallback(); 4160 }); 4161 }; 4162 4163 // -------------------------- filter -------------------------- // 4164 4165 Isotope.prototype._filter = function( items ) { 4166 var filter = this.options.filter;
4167 filter = filter || '*'; 4168 var matches = []; 4169 var hiddenMatched = []; 4170 var visibleUnmatched = []; 4171 4172 var test = this._getFilterTest( filter ); 4173 4174 // test each item 4175 for ( var i=0, len = items.length; i < len; i++ ) { 4176 var item = items[i]; 4177 if ( item.isIgnored ) { 4178 continue; 4179 } 4180 // add item to either matched or unmatched group 4181 var isMatched = test( item ); 4182 // item.isFilterMatched = isMatched; 4183 // add to matches if its a match 4184 if ( isMatched ) { 4185 matches.push( item ); 4186 } 4187 // add to additional group if item needs to be hidden or revealed 4188 if ( isMatched && item.isHidden ) { 4189 hiddenMatched.push( item ); 4190 } else if ( !isMatched && !item.isHidden ) { 4191 visibleUnmatched.push( item ); 4192 } 4193 } 4194 4195 // return collections of items to be manipulated 4196 return { 4197 matches: matches, 4198 needReveal: hiddenMatched, 4199 needHide: visibleUnmatched 4200 }; 4201 }; 4202 4203 // get a jQuery, function, or a matchesSelector test given the filter 4204 Isotope.prototype._getFilterTest = function( filter ) { 4205 if ( jQuery && this.options.isJQueryFiltering ) { 4206 // use jQuery 4207 return function( item ) { 4208 return jQuery( item.element ).is( filter ); 4209 }; 4210 } 4211 if ( typeof filter == 'function' ) { 4212 // use filter as function 4213 return function( item ) { 4214 return filter( item.element ); 4215 }; 4216 } 4217 // default, use filter as selector string 4218 return function( item ) { 4219 return matchesSelector( item.element, filter ); 4220 }; 4221 }; 4222 4223 // -------------------------- sorting -------------------------- // 4224 4225 /** 4226 * @params {Array} elems 4227 * @public 4228 */ 4229 Isotope.prototype.updateSortData = function( elems ) { 4230 // get items 4231 var items; 4232 if ( elems ) { 4233 elems = utils.makeArray( elems ); 4234 items = this.getItems( elems ); 4235 } else { 4236 // update all items if no elems provided 4237 items = this.items; 4238 } 4239 4240 this._getSorters(); 4241 this._updateItemsSortData( items ); 4242 }; 4243 4244 Isotope.prototype._getSorters = function() { 4245 var getSortData = this.options.getSortData; 4246 for ( var key in getSortData ) { 4247 var sorter = getSortData[ key ]; 4248 this._sorters[ key ] = mungeSorter( sorter ); 4249 } 4250 }; 4251 4252 /** 4253 * @params {Array} items - of Isotope.Items 4254 * @private 4255 */ 4256 Isotope.prototype._updateItemsSortData = function( items ) { 4257 // do not update if no items 4258 var len = items && items.length; 4259 4260 for ( var i=0; len && i < len; i++ ) { 4261 var item = items[i]; 4262 item.updateSortData(); 4263 } 4264 }; 4265 4266 // ----- munge sorter ----- // 4267 4268 // encapsulate this, as we just need mungeSorter 4269 // other functions in here are just for munging 4270 var mungeSorter = ( function() { 4271 // add a magic layer to sorters for convienent shorthands 4272 // `.foo-bar` will use the text of .foo-bar querySelector 4273 // `[foo-bar]` will use attribute 4274 // you can also add parser 4275 // `.foo-bar parseInt` will parse that as a number 4276 function mungeSorter( sorter ) { 4277 // if not a string, return function or whatever it is 4278 if ( typeof sorter != 'string' ) { 4279 return sorter; 4280 } 4281 // parse the sorter string 4282 var args = trim( sorter ).split(' '); 4283 var query = args[0]; 4284 // check if query looks like [an-attribute] 4285 var attrMatch = query.match( /^\[(.+)\]$/ ); 4286 var attr = attrMatch && attrMatch[1]; 4287 var getValue = getValueGetter( attr, query ); 4288 // use second argument as a parser 4289 var parser = Isotope.sortDataParsers[ args[1] ]; 4290 // parse the value, if there was a parser 4291 sorter = parser ? function( elem ) { 4292 return elem && parser( getValue( elem ) ); 4293 } : 4294 // otherwise just return value 4295 function( elem ) { 4296 return elem && getValue( elem ); 4297 }; 4298 4299 return sorter; 4300 } 4301 4302 // get an attribute getter, or get text of the querySelector 4303 function getValueGetter( attr, query ) { 4304 var getValue; 4305 // if query looks like [foo-bar], get attribute 4306 if ( attr ) { 4307 getValue = function( elem ) { 4308 return elem.getAttribute( attr ); 4309 }; 4310 } else { 4311 // otherwise, assume its a querySelector, and get its text 4312 getValue = function( elem ) { 4313 var child = elem.querySelector( query ); 4314 return child && getText( child ); 4315 }; 4316 } 4317 return getValue; 4318 } 4319 4320 return mungeSorter; 4321 })(); 4322 4323 // parsers used in getSortData shortcut strings 4324 Isotope.sortDataParsers = { 4325 'parseInt': function( val ) { 4326 return parseInt( val, 10 ); 4327 }, 4328 'parseFloat': function( val ) { 4329 return parseFloat( val ); 4330 } 4331 }; 4332 4333 // ----- sort method ----- // 4334 4335 // sort filteredItem order 4336 Isotope.prototype._sort = function() { 4337 var sortByOpt = this.options.sortBy; 4338 if ( !sortByOpt ) { 4339 return; 4340 } 4341 // concat all sortBy and sortHistory 4342 var sortBys = [].concat.apply( sortByOpt, this.sortHistory ); 4343 // sort magic 4344 var itemSorter = getItemSorter( sortBys, this.options.sortAscending ); 4345 this.filteredItems.sort( itemSorter ); 4346 // keep track of sortBy History 4347 if ( sortByOpt != this.sortHistory[0] ) { 4348 // add to front, oldest goes in last 4349 this.sortHistory.unshift( sortByOpt ); 4350 } 4351 }; 4352 4353 // returns a function used for sorting 4354 function getItemSorter( sortBys, sortAsc ) { 4355 return function sorter( itemA, itemB ) { 4356 // cycle through all sortKeys 4357 for ( var i = 0, len = sortBys.length; i < len; i++ ) { 4358 var sortBy = sortBys[i]; 4359 var a = itemA.sortData[ sortBy ]; 4360 var b = itemB.sortData[ sortBy ]; 4361 if ( a > b || a < b ) { 4362 // if sortAsc is an object, use the value given the sortBy key
4363 var isAscending = sortAsc[ sortBy ] !== undefined ? sortAsc[ sortBy ] : sortAsc; 4364 var direction = isAscending ? 1 : -1; 4365 return ( a > b ? 1 : -1 ) * direction; 4366 } 4367 } 4368 return 0; 4369 }; 4370 } 4371 4372 // -------------------------- methods -------------------------- // 4373 4374 // get layout mode 4375 Isotope.prototype._mode = function() { 4376 var layoutMode = this.options.layoutMode; 4377 var mode = this.modes[ layoutMode ]; 4378 if ( !mode ) { 4379 // TODO console.error 4380 throw new Error( 'No layout mode: ' + layoutMode ); 4381 } 4382 // HACK sync mode's options 4383 // any options set after init for layout mode need to be synced 4384 mode.options = this.options[ layoutMode ]; 4385 return mode; 4386 }; 4387 4388 Isotope.prototype._resetLayout = function() { 4389 // trigger original reset layout 4390 Outlayer.prototype._resetLayout.call( this ); 4391 this._mode()._resetLayout(); 4392 }; 4393 4394 Isotope.prototype._getItemLayoutPosition = function( item ) { 4395 return this._mode()._getItemLayoutPosition( item ); 4396 }; 4397 4398 Isotope.prototype._manageStamp = function( stamp ) { 4399 this._mode()._manageStamp( stamp ); 4400 }; 4401 4402 Isotope.prototype._getContainerSize = function() { 4403 return this._mode()._getContainerSize(); 4404 }; 4405 4406 Isotope.prototype.needsResizeLayout = function() { 4407 return this._mode().needsResizeLayout(); 4408 }; 4409 4410 // -------------------------- adding & removing -------------------------- // 4411 4412 // HEADS UP overwrites default Outlayer appended 4413 Isotope.prototype.appended = function( elems ) { 4414 var items = this.addItems( elems ); 4415 if ( !items.length ) { 4416 return; 4417 } 4418 // filter, layout, reveal new items 4419 var filteredItems = this._filterRevealAdded( items ); 4420 // add to filteredItems 4421 this.filteredItems = this.filteredItems.concat( filteredItems ); 4422 }; 4423 4424 // HEADS UP overwrites default Outlayer prepended 4425 Isotope.prototype.prepended = function( elems ) { 4426 var items = this._itemize( elems ); 4427 if ( !items.length ) { 4428 return; 4429 } 4430 // start new layout 4431 this._resetLayout(); 4432 this._manageStamps(); 4433 // filter, layout, reveal new items 4434 var filteredItems = this._filterRevealAdded( items ); 4435 // layout previous items 4436 this.layoutItems( this.filteredItems ); 4437 // add to items and filteredItems 4438 this.filteredItems = filteredItems.concat( this.filteredItems ); 4439 this.items = items.concat( this.items ); 4440 }; 4441 4442 Isotope.prototype._filterRevealAdded = function( items ) { 4443 var filtered = this._filter( items ); 4444 this.hide( filtered.needHide ); 4445 // reveal all new items 4446 this.reveal( filtered.matches ); 4447 // layout new items, no transition 4448 this.layoutItems( filtered.matches, true ); 4449 return filtered.matches; 4450 }; 4451 4452 /** 4453 * Filter, sort, and layout newly-appended item elements 4454 * @param {Array or NodeList or Element} elems 4455 */ 4456 Isotope.prototype.insert = function( elems ) { 4457 var items = this.addItems( elems ); 4458 if ( !items.length ) { 4459 return; 4460 } 4461 // append item elements 4462 var i, item; 4463 var len = items.length; 4464 for ( i=0; i < len; i++ ) { 4465 item = items[i]; 4466 this.element.appendChild( item.element ); 4467 } 4468 // filter new stuff 4469 var filteredInsertItems = this._filter( items ).matches; 4470 // set flag 4471 for ( i=0; i < len; i++ ) { 4472 items[i].isLayoutInstant = true; 4473 } 4474 this.arrange(); 4475 // reset flag 4476 for ( i=0; i < len; i++ ) { 4477 delete items[i].isLayoutInstant; 4478 } 4479 this.reveal( filteredInsertItems ); 4480 }; 4481 4482 var _remove = Isotope.prototype.remove; 4483 Isotope.prototype.remove = function( elems ) { 4484 elems = utils.makeArray( elems ); 4485 var removeItems = this.getItems( elems ); 4486 // do regular thing 4487 _remove.call( this, elems ); 4488 // bail if no items to remove 4489 var len = removeItems && removeItems.length; 4490 if ( !len ) { 4491 return; 4492 } 4493 // remove elems from filteredItems 4494 for ( var i=0; i < len; i++ ) { 4495 var item = removeItems[i]; 4496 // remove item from collection 4497 utils.removeFrom( this.filteredItems, item ); 4498 } 4499 }; 4500 4501 Isotope.prototype.shuffle = function() { 4502 // update random sortData 4503 for ( var i=0, len = this.items.length; i < len; i++ ) { 4504 var item = this.items[i]; 4505 item.sortData.random = Math.random(); 4506 } 4507 this.options.sortBy = 'random'; 4508 this._sort(); 4509 this._layout(); 4510 }; 4511 4512 /** 4513 * trigger fn without transition 4514 * kind of hacky to have this in the first place 4515 * @param {Function} fn 4516 * @returns ret 4517 * @private 4518 */ 4519 Isotope.prototype._noTransition = function( fn ) { 4520 // save transitionDuration before disabling 4521 var transitionDuration = this.options.transitionDuration; 4522 // disable transition 4523 this.options.transitionDuration = 0; 4524 // do it 4525 var returnValue = fn.call( this ); 4526 // re-enable transition for reveal 4527 this.options.transitionDuration = transitionDuration; 4528 return returnValue; 4529 }; 4530 4531 // ----- helper methods ----- // 4532 4533 /** 4534 * getter method for getting filtered item elements 4535 * @returns {Array} elems - collection of item elements 4536 */ 4537 Isotope.prototype.getFilteredItemElements = function() { 4538 var elems = []; 4539 for ( var i=0, len = this.filteredItems.length; i < len; i++ ) { 4540 elems.push( this.filteredItems[i].element ); 4541 } 4542 return elems; 4543 }; 4544 4545 // ----- ----- // 4546 4547 return Isotope; 4548 4549})); 4550
vendor: 29,252 bytes, lines 4551-5707
4551/*! 4552 * Packery layout mode PACKAGED v2.0.1 4553 * sub-classes Packery 4554 */ 4555 4556/** 4557 * Rect 4558 * low-level utility class for basic geometry 4559 */ 4560 4561( function( window, factory ) { 4562 // universal module definition 4563 /* jshint strict: false */ /* globals define, module */ 4564 if ( typeof define == 'function' && define.amd ) { 4565 // AMD 4566 define( 'packery/js/rect',factory ); 4567 } else if ( typeof module == 'object' && module.exports ) { 4568 // CommonJS 4569 module.exports = factory(); 4570 } else { 4571 // browser global 4572 window.Packery = window.Packery || {}; 4573 window.Packery.Rect = factory(); 4574 } 4575 4576}( window, function factory() { 4577 4578 4579// -------------------------- Rect -------------------------- // 4580 4581function Rect( props ) { 4582 // extend properties from defaults 4583 for ( var prop in Rect.defaults ) { 4584 this[ prop ] = Rect.defaults[ prop ]; 4585 } 4586 4587 for ( prop in props ) { 4588 this[ prop ] = props[ prop ]; 4589 } 4590 4591} 4592 4593Rect.defaults = { 4594 x: 0, 4595 y: 0, 4596 width: 0, 4597 height: 0 4598}; 4599 4600var proto = Rect.prototype; 4601 4602/** 4603 * Determines whether or not this rectangle wholly encloses another rectangle or point. 4604 * @param {Rect} rect 4605 * @returns {Boolean} 4606**/ 4607proto.contains = function( rect ) { 4608 // points don't have width or height 4609 var otherWidth = rect.width || 0; 4610 var otherHeight = rect.height || 0; 4611 return this.x <= rect.x && 4612 this.y <= rect.y && 4613 this.x + this.width >= rect.x + otherWidth && 4614 this.y + this.height >= rect.y + otherHeight; 4615}; 4616 4617/** 4618 * Determines whether or not the rectangle intersects with another. 4619 * @param {Rect} rect 4620 * @returns {Boolean} 4621**/ 4622proto.overlaps = function( rect ) { 4623 var thisRight = this.x + this.width; 4624 var thisBottom = this.y + this.height; 4625 var rectRight = rect.x + rect.width; 4626 var rectBottom = rect.y + rect.height; 4627 4628 // http://stackoverflow.com/a/306332 4629 return this.x < rectRight && 4630 thisRight > rect.x && 4631 this.y < rectBottom && 4632 thisBottom > rect.y; 4633}; 4634 4635/** 4636 * @param {Rect} rect - the overlapping rect 4637 * @returns {Array} freeRects - rects representing the area around the rect 4638**/ 4639proto.getMaximalFreeRects = function( rect ) { 4640 4641 // if no intersection, return false 4642 if ( !this.overlaps( rect ) ) { 4643 return false; 4644 } 4645 4646 var freeRects = []; 4647 var freeRect; 4648 4649 var thisRight = this.x + this.width; 4650 var thisBottom = this.y + this.height; 4651 var rectRight = rect.x + rect.width; 4652 var rectBottom = rect.y + rect.height; 4653 4654 // top 4655 if ( this.y < rect.y ) { 4656 freeRect = new Rect({ 4657 x: this.x, 4658 y: this.y, 4659 width: this.width, 4660 height: rect.y - this.y 4661 }); 4662 freeRects.push( freeRect ); 4663 } 4664 4665 // right 4666 if ( thisRight > rectRight ) { 4667 freeRect = new Rect({ 4668 x: rectRight, 4669 y: this.y, 4670 width: thisRight - rectRight, 4671 height: this.height 4672 }); 4673 freeRects.push( freeRect ); 4674 } 4675 4676 // bottom 4677 if ( thisBottom > rectBottom ) { 4678 freeRect = new Rect({ 4679 x: this.x, 4680 y: rectBottom, 4681 width: this.width, 4682 height: thisBottom - rectBottom 4683 }); 4684 freeRects.push( freeRect ); 4685 } 4686 4687 // left 4688 if ( this.x < rect.x ) { 4689 freeRect = new Rect({ 4690 x: this.x, 4691 y: this.y, 4692 width: rect.x - this.x, 4693 height: this.height 4694 }); 4695 freeRects.push( freeRect ); 4696 } 4697 4698 return freeRects; 4699}; 4700 4701proto.canFit = function( rect ) { 4702 return this.width >= rect.width && this.height >= rect.height; 4703}; 4704 4705return Rect; 4706 4707})); 4708 4709/** 4710 * Packer 4711 * bin-packing algorithm 4712 */ 4713 4714( function( window, factory ) { 4715 // universal module definition 4716 /* jshint strict: false */ /* globals define, module, require */ 4717 if ( typeof define == 'function' && define.amd ) { 4718 // AMD 4719 define( 'packery/js/packer',[ './rect' ], factory ); 4720 } else if ( typeof module == 'object' && module.exports ) { 4721 // CommonJS 4722 module.exports = factory( 4723 require('./rect') 4724 ); 4725 } else { 4726 // browser global 4727 var Packery = window.Packery = window.Packery || {}; 4728 Packery.Packer = factory( Packery.Rect ); 4729 } 4730 4731}( window, function factory( Rect ) { 4732 4733 4734// -------------------------- Packer -------------------------- // 4735 4736/** 4737 * @param {Number} width 4738 * @param {Number} height 4739 * @param {String} sortDirection 4740 * topLeft for vertical, leftTop for horizontal 4741 */ 4742function Packer( width, height, sortDirection ) { 4743 this.width = width || 0; 4744 this.height = height || 0; 4745 this.sortDirection = sortDirection || 'downwardLeftToRight'; 4746 4747 this.reset(); 4748} 4749 4750var proto = Packer.prototype; 4751 4752proto.reset = function() { 4753 this.spaces = []; 4754 4755 var initialSpace = new Rect({ 4756 x: 0, 4757 y: 0, 4758 width: this.width, 4759 height: this.height 4760 }); 4761 4762 this.spaces.push( initialSpace ); 4763 // set sorter 4764 this.sorter = sorters[ this.sortDirection ] || sorters.downwardLeftToRight; 4765}; 4766 4767// change x and y of rect to fit with in Packer's available spaces 4768proto.pack = function( rect ) { 4769 for ( var i=0; i < this.spaces.length; i++ ) { 4770 var space = this.spaces[i]; 4771 if ( space.canFit( rect ) ) { 4772 this.placeInSpace( rect, space ); 4773 break; 4774 } 4775 } 4776}; 4777 4778proto.columnPack = function( rect ) { 4779 for ( var i=0; i < this.spaces.length; i++ ) { 4780 var space = this.spaces[i]; 4781 var canFitInSpaceColumn = space.x <= rect.x && 4782 space.x + space.width >= rect.x + rect.width && 4783 space.height >= rect.height - 0.01; // fudge number for rounding error 4784 if ( canFitInSpaceColumn ) { 4785 rect.y = space.y; 4786 this.placed( rect ); 4787 break; 4788 } 4789 } 4790}; 4791 4792proto.rowPack = function( rect ) { 4793 for ( var i=0; i < this.spaces.length; i++ ) { 4794 var space = this.spaces[i]; 4795 var canFitInSpaceRow = space.y <= rect.y && 4796 space.y + space.height >= rect.y + rect.height && 4797 space.width >= rect.width - 0.01; // fudge number for rounding error 4798 if ( canFitInSpaceRow ) { 4799 rect.x = space.x; 4800 this.placed( rect ); 4801 break; 4802 } 4803 } 4804}; 4805 4806proto.placeInSpace = function( rect, space ) { 4807 // place rect in space 4808 rect.x = space.x; 4809 rect.y = space.y; 4810 4811 this.placed( rect ); 4812}; 4813 4814// update spaces with placed rect 4815proto.placed = function( rect ) { 4816 // update spaces 4817 var revisedSpaces = []; 4818 for ( var i=0; i < this.spaces.length; i++ ) { 4819 var space = this.spaces[i]; 4820 var newSpaces = space.getMaximalFreeRects( rect ); 4821 // add either the original space or the new spaces to the revised spaces 4822 if ( newSpaces ) { 4823 revisedSpaces.push.apply( revisedSpaces, newSpaces ); 4824 } else { 4825 revisedSpaces.push( space ); 4826 } 4827 } 4828 4829 this.spaces = revisedSpaces; 4830 4831 this.mergeSortSpaces(); 4832}; 4833 4834proto.mergeSortSpaces = function() { 4835 // remove redundant spaces 4836 Packer.mergeRects( this.spaces ); 4837 this.spaces.sort( this.sorter ); 4838}; 4839 4840// add a space back 4841proto.addSpace = function( rect ) { 4842 this.spaces.push( rect ); 4843 this.mergeSortSpaces(); 4844}; 4845 4846// -------------------------- utility functions -------------------------- // 4847 4848/** 4849 * Remove redundant rectangle from array of rectangles 4850 * @param {Array} rects: an array of Rects 4851 * @returns {Array} rects: an array of Rects 4852**/ 4853Packer.mergeRects = function( rects ) { 4854 var i = 0; 4855 var rect = rects[i]; 4856 4857 rectLoop: 4858 while ( rect ) { 4859 var j = 0; 4860 var compareRect = rects[ i + j ]; 4861 4862 while ( compareRect ) { 4863 if ( compareRect == rect ) { 4864 j++; // next 4865 } else if ( compareRect.contains( rect ) ) { 4866 // remove rect 4867 rects.splice( i, 1 ); 4868 rect = rects[i]; // set next rect 4869 continue rectLoop; // bail on compareLoop 4870 } else if ( rect.contains( compareRect ) ) { 4871 // remove compareRect 4872 rects.splice( i + j, 1 ); 4873 } else { 4874 j++; 4875 } 4876 compareRect = rects[ i + j ]; // set next compareRect 4877 } 4878 i++; 4879 rect = rects[i]; 4880 } 4881 4882 return rects; 4883}; 4884 4885 4886// -------------------------- sorters -------------------------- // 4887 4888// functions for sorting rects in order 4889var sorters = { 4890 // top down, then left to right 4891 downwardLeftToRight: function( a, b ) { 4892 return a.y - b.y || a.x - b.x; 4893 }, 4894 // left to right, then top down 4895 rightwardTopToBottom: function( a, b ) { 4896 return a.x - b.x || a.y - b.y; 4897 } 4898}; 4899 4900 4901// -------------------------- -------------------------- // 4902 4903return Packer; 4904 4905})); 4906 4907/** 4908 * Packery Item Element 4909**/ 4910 4911( function( window, factory ) { 4912 // universal module definition 4913 /* jshint strict: false */ /* globals define, module, require */ 4914 if ( typeof define == 'function' && define.amd ) { 4915 // AMD 4916 define( 'packery/js/item',[ 4917 'outlayer/outlayer', 4918 './rect' 4919 ], 4920 factory ); 4921 } else if ( typeof module == 'object' && module.exports ) { 4922 // CommonJS 4923 module.exports = factory( 4924 require('outlayer'), 4925 require('./rect') 4926 ); 4927 } else { 4928 // browser global 4929 window.Packery.Item = factory( 4930 window.Outlayer, 4931 window.Packery.Rect 4932 ); 4933 } 4934 4935}( window, function factory( Outlayer, Rect ) { 4936 4937 4938// -------------------------- Item -------------------------- // 4939 4940var docElemStyle = document.documentElement.style; 4941 4942var transformProperty = typeof docElemStyle.transform == 'string' ? 4943 'transform' : 'WebkitTransform'; 4944 4945// sub-class Item 4946var Item = function PackeryItem() { 4947 Outlayer.Item.apply( this, arguments ); 4948}; 4949 4950var proto = Item.prototype = Object.create( Outlayer.Item.prototype ); 4951 4952var __create = proto._create; 4953proto._create = function() { 4954 // call default _create logic 4955 __create.call( this ); 4956 this.rect = new Rect(); 4957}; 4958 4959var _moveTo = proto.moveTo; 4960proto.moveTo = function( x, y ) { 4961 // don't shift 1px while dragging 4962 var dx = Math.abs( this.position.x - x ); 4963 var dy = Math.abs( this.position.y - y ); 4964 4965 var canHackGoTo = this.layout.dragItemCount && !this.isPlacing && 4966 !this.isTransitioning && dx < 1 && dy < 1; 4967 if ( canHackGoTo ) { 4968 this.goTo( x, y ); 4969 return; 4970 } 4971 _moveTo.apply( this, arguments ); 4972}; 4973 4974// -------------------------- placing -------------------------- // 4975 4976proto.enablePlacing = function() { 4977 this.removeTransitionStyles(); 4978 // remove transform property from transition 4979 if ( this.isTransitioning && transformProperty ) { 4980 this.element.style[ transformProperty ] = 'none'; 4981 } 4982 this.isTransitioning = false; 4983 this.getSize(); 4984 this.layout._setRectSize( this.element, this.rect ); 4985 this.isPlacing = true; 4986}; 4987 4988proto.disablePlacing = function() { 4989 this.isPlacing = false; 4990}; 4991 4992// ----- ----- // 4993 4994// remove element from DOM 4995proto.removeElem = function() { 4996 this.element.parentNode.removeChild( this.element ); 4997 // add space back to packer 4998 this.layout.packer.addSpace( this.rect ); 4999 this.emitEvent( 'remove', [ this ] ); 5000}; 5001 5002// ----- dropPlaceholder ----- // 5003 5004proto.showDropPlaceholder = function() { 5005 var dropPlaceholder = this.dropPlaceholder; 5006 if ( !dropPlaceholder ) { 5007 // create dropPlaceholder 5008 dropPlaceholder = this.dropPlaceholder = document.createElement('div'); 5009 dropPlaceholder.className = 'packery-drop-placeholder'; 5010 dropPlaceholder.style.position = 'absolute'; 5011 } 5012 5013 dropPlaceholder.style.width = this.size.width + 'px'; 5014 dropPlaceholder.style.height = this.size.height + 'px'; 5015 this.positionDropPlaceholder(); 5016 this.layout.element.appendChild( dropPlaceholder ); 5017}; 5018 5019proto.positionDropPlaceholder = function() { 5020 this.dropPlaceholder.style[ transformProperty ] = 'translate(' + 5021 this.rect.x + 'px, ' + this.rect.y + 'px)'; 5022}; 5023 5024proto.hideDropPlaceholder = function() { 5025 this.layout.element.removeChild( this.dropPlaceholder ); 5026}; 5027 5028// ----- ----- // 5029 5030return Item; 5031 5032})); 5033 5034/*! 5035 * Packery v2.0.0 5036 * Gapless, draggable grid layouts 5037 * 5038 * Licensed GPLv3 for open source use 5039 * or Packery Commercial License for commercial use 5040 * 5041 * http://packery.metafizzy.co 5042 * Copyright 2016 Metafizzy 5043 */ 5044 5045( function( window, factory ) { 5046 // universal module definition 5047 /* jshint strict: false */ /* globals define, module, require */ 5048 if ( typeof define == 'function' && define.amd ) { 5049 // AMD 5050 define( 'packery/js/packery',[ 5051 'get-size/get-size', 5052 'outlayer/outlayer', 5053 './rect', 5054 './packer', 5055 './item' 5056 ], 5057 factory ); 5058 } else if ( typeof module == 'object' && module.exports ) { 5059 // CommonJS 5060 module.exports = factory( 5061 require('get-size'), 5062 require('outlayer'), 5063 require('./rect'), 5064 require('./packer'), 5065 require('./item') 5066 ); 5067 } else { 5068 // browser global 5069 window.Packery = factory( 5070 window.getSize, 5071 window.Outlayer, 5072 window.Packery.Rect, 5073 window.Packery.Packer, 5074 window.Packery.Item 5075 ); 5076 } 5077 5078}( window, function factory( getSize, Outlayer, Rect, Packer, Item ) { 5079 5080 5081// ----- Rect ----- // 5082 5083// allow for pixel rounding errors IE8-IE11 & Firefox; #227 5084Rect.prototype.canFit = function( rect ) { 5085 return this.width >= rect.width - 1 && this.height >= rect.height - 1; 5086}; 5087 5088// -------------------------- Packery -------------------------- // 5089 5090// create an Outlayer layout class 5091var Packery = Outlayer.create('packery'); 5092Packery.Item = Item; 5093 5094var proto = Packery.prototype; 5095 5096proto._create = function() { 5097 // call super 5098 Outlayer.prototype._create.call( this ); 5099 5100 // initial properties 5101 this.packer = new Packer(); 5102 // packer for drop targets 5103 this.shiftPacker = new Packer(); 5104 this.isEnabled = true; 5105 5106 this.dragItemCount = 0; 5107 5108 // create drag handlers 5109 var _this = this; 5110 this.handleDraggabilly = { 5111 dragStart: function() { 5112 _this.itemDragStart( this.element ); 5113 }, 5114 dragMove: function() { 5115 _this.itemDragMove( this.element, this.position.x, this.position.y ); 5116 }, 5117 dragEnd: function() { 5118 _this.itemDragEnd( this.element ); 5119 } 5120 }; 5121 5122 this.handleUIDraggable = { 5123 start: function handleUIDraggableStart( event, ui ) { 5124 // HTML5 may trigger dragstart, dismiss HTML5 dragging 5125 if ( !ui ) { 5126 return; 5127 } 5128 _this.itemDragStart( event.currentTarget ); 5129 }, 5130 drag: function handleUIDraggableDrag( event, ui ) { 5131 if ( !ui ) { 5132 return; 5133 } 5134 _this.itemDragMove( event.currentTarget, ui.position.left, ui.position.top ); 5135 }, 5136 stop: function handleUIDraggableStop( event, ui ) { 5137 if ( !ui ) { 5138 return; 5139 } 5140 _this.itemDragEnd( event.currentTarget ); 5141 } 5142 }; 5143 5144}; 5145 5146 5147// ----- init & layout ----- // 5148 5149/** 5150 * logic before any new layout 5151 */ 5152proto._resetLayout = function() { 5153 this.getSize(); 5154 5155 this._getMeasurements(); 5156 5157 // reset packer 5158 var width, height, sortDirection; 5159 // packer settings, if horizontal or vertical 5160 if ( this._getOption('horizontal') ) { 5161 width = Infinity; 5162 height = this.size.innerHeight + this.gutter; 5163 sortDirection = 'rightwardTopToBottom'; 5164 } else { 5165 width = this.size.innerWidth + this.gutter; 5166 height = Infinity; 5167 sortDirection = 'downwardLeftToRight'; 5168 } 5169 5170 this.packer.width = this.shiftPacker.width = width; 5171 this.packer.height = this.shiftPacker.height = height; 5172 this.packer.sortDirection = this.shiftPacker.sortDirection = sortDirection; 5173 5174 this.packer.reset(); 5175 5176 // layout 5177 this.maxY = 0; 5178 this.maxX = 0; 5179}; 5180 5181/** 5182 * update columnWidth, rowHeight, & gutter 5183 * @private 5184 */ 5185proto._getMeasurements = function() { 5186 this._getMeasurement( 'columnWidth', 'width' ); 5187 this._getMeasurement( 'rowHeight', 'height' ); 5188 this._getMeasurement( 'gutter', 'width' ); 5189}; 5190 5191proto._getItemLayoutPosition = function( item ) { 5192 this._setRectSize( item.element, item.rect ); 5193 if ( this.isShifting || this.dragItemCount > 0 ) { 5194 var packMethod = this._getPackMethod(); 5195 this.packer[ packMethod ]( item.rect ); 5196 } else { 5197 this.packer.pack( item.rect ); 5198 } 5199 5200 this._setMaxXY( item.rect ); 5201 return item.rect; 5202}; 5203 5204proto.shiftLayout = function() { 5205 this.isShifting = true; 5206 this.layout(); 5207 delete this.isShifting; 5208}; 5209 5210proto._getPackMethod = function() { 5211 return this._getOption('horizontal') ? 'rowPack' : 'columnPack'; 5212}; 5213 5214 5215/** 5216 * set max X and Y value, for size of container 5217 * @param {Packery.Rect} rect 5218 * @private 5219 */ 5220proto._setMaxXY = function( rect ) { 5221 this.maxX = Math.max( rect.x + rect.width, this.maxX ); 5222 this.maxY = Math.max( rect.y + rect.height, this.maxY ); 5223}; 5224 5225/** 5226 * set the width and height of a rect, applying columnWidth and rowHeight 5227 * @param {Element} elem 5228 * @param {Packery.Rect} rect 5229 */ 5230proto._setRectSize = function( elem, rect ) { 5231 var size = getSize( elem ); 5232 var w = size.outerWidth; 5233 var h = size.outerHeight; 5234 // size for columnWidth and rowHeight, if available 5235 // only check if size is non-zero, #177 5236 if ( w || h ) { 5237 w = this._applyGridGutter( w, this.columnWidth ); 5238 h = this._applyGridGutter( h, this.rowHeight ); 5239 } 5240 // rect must fit in packer 5241 rect.width = Math.min( w, this.packer.width ); 5242 rect.height = Math.min( h, this.packer.height ); 5243}; 5244 5245/** 5246 * fits item to columnWidth/rowHeight and adds gutter 5247 * @param {Number} measurement - item width or height 5248 * @param {Number} gridSize - columnWidth or rowHeight 5249 * @returns measurement 5250 */ 5251proto._applyGridGutter = function( measurement, gridSize ) { 5252 // just add gutter if no gridSize 5253 if ( !gridSize ) { 5254 return measurement + this.gutter; 5255 } 5256 gridSize += this.gutter; 5257 // fit item to columnWidth/rowHeight 5258 var remainder = measurement % gridSize; 5259 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil'; 5260 measurement = Math[ mathMethod ]( measurement / gridSize ) * gridSize; 5261 return measurement; 5262}; 5263 5264proto._getContainerSize = function() { 5265 if ( this._getOption('horizontal') ) { 5266 return { 5267 width: this.maxX - this.gutter 5268 }; 5269 } else { 5270 return { 5271 height: this.maxY - this.gutter 5272 }; 5273 } 5274}; 5275 5276 5277// -------------------------- stamp -------------------------- // 5278 5279/** 5280 * makes space for element 5281 * @param {Element} elem 5282 */ 5283proto._manageStamp = function( elem ) { 5284 5285 var item = this.getItem( elem ); 5286 var rect; 5287 if ( item && item.isPlacing ) { 5288 rect = item.rect; 5289 } else { 5290 var offset = this._getElementOffset( elem ); 5291 rect = new Rect({ 5292 x: this._getOption('originLeft') ? offset.left : offset.right, 5293 y: this._getOption('originTop') ? offset.top : offset.bottom 5294 }); 5295 } 5296 5297 this._setRectSize( elem, rect ); 5298 // save its space in the packer 5299 this.packer.placed( rect ); 5300 this._setMaxXY( rect ); 5301}; 5302 5303// -------------------------- methods -------------------------- // 5304 5305function verticalSorter( a, b ) { 5306 return a.position.y - b.position.y || a.position.x - b.position.x; 5307} 5308 5309function horizontalSorter( a, b ) { 5310 return a.position.x - b.position.x || a.position.y - b.position.y; 5311} 5312 5313proto.sortItemsByPosition = function() { 5314 var sorter = this._getOption('horizontal') ? horizontalSorter : verticalSorter; 5315 this.items.sort( sorter ); 5316}; 5317 5318/** 5319 * Fit item element in its current position 5320 * Packery will position elements around it 5321 * useful for expanding elements 5322 * 5323 * @param {Element} elem 5324 * @param {Number} x - horizontal destination position, optional 5325 * @param {Number} y - vertical destination position, optional 5326 */ 5327proto.fit = function( elem, x, y ) { 5328 var item = this.getItem( elem ); 5329 if ( !item ) { 5330 return; 5331 } 5332 5333 // stamp item to get it out of layout 5334 this.stamp( item.element ); 5335 // set placing flag 5336 item.enablePlacing(); 5337 this.updateShiftTargets( item ); 5338 // fall back to current position for fitting 5339 x = x === undefined ? item.rect.x: x; 5340 y = y === undefined ? item.rect.y: y; 5341 // position it best at its destination 5342 this.shift( item, x, y ); 5343 this._bindFitEvents( item ); 5344 item.moveTo( item.rect.x, item.rect.y ); 5345 // layout everything else 5346 this.shiftLayout(); 5347 // return back to regularly scheduled programming 5348 this.unstamp( item.element ); 5349 this.sortItemsByPosition(); 5350 item.disablePlacing(); 5351}; 5352 5353/** 5354 * emit event when item is fit and other items are laid out 5355 * @param {Packery.Item} item 5356 * @private 5357 */ 5358proto._bindFitEvents = function( item ) { 5359 var _this = this; 5360 var ticks = 0; 5361 function onLayout() { 5362 ticks++; 5363 if ( ticks != 2 ) { 5364 return; 5365 } 5366 _this.dispatchEvent( 'fitComplete', null, [ item ] ); 5367 } 5368 // when item is laid out 5369 item.once( 'layout', onLayout ); 5370 // when all items are laid out 5371 this.once( 'layoutComplete', onLayout ); 5372}; 5373 5374// -------------------------- resize -------------------------- // 5375 5376// debounced, layout on resize 5377proto.resize = function() { 5378 // don't trigger if size did not change 5379 // or if resize was unbound. See #285, outlayer#9 5380 if ( !this.isResizeBound || !this.needsResizeLayout() ) { 5381 return; 5382 } 5383 5384 if ( this.options.shiftPercentResize ) { 5385 this.resizeShiftPercentLayout(); 5386 } else { 5387 this.layout(); 5388 } 5389}; 5390 5391/** 5392 * check if layout is needed post layout 5393 * @returns Boolean 5394 */ 5395proto.needsResizeLayout = function() { 5396 var size = getSize( this.element ); 5397 var innerSize = this._getOption('horizontal') ? 'innerHeight' : 'innerWidth'; 5398 return size[ innerSize ] != this.size[ innerSize ]; 5399}; 5400 5401proto.resizeShiftPercentLayout = function() { 5402 var items = this._getItemsForLayout( this.items ); 5403 5404 var isHorizontal = this._getOption('horizontal'); 5405 var coord = isHorizontal ? 'y' : 'x'; 5406 var measure = isHorizontal ? 'height' : 'width'; 5407 var segmentName = isHorizontal ? 'rowHeight' : 'columnWidth'; 5408 var innerSize = isHorizontal ? 'innerHeight' : 'innerWidth'; 5409 5410 // proportional re-align items 5411 var previousSegment = this[ segmentName ]; 5412 previousSegment = previousSegment && previousSegment + this.gutter; 5413 5414 if ( previousSegment ) { 5415 this._getMeasurements(); 5416 var currentSegment = this[ segmentName ] + this.gutter; 5417 items.forEach( function( item ) { 5418 var seg = Math.round( item.rect[ coord ] / previousSegment ); 5419 item.rect[ coord ] = seg * currentSegment; 5420 }); 5421 } else { 5422 var currentSize = getSize( this.element )[ innerSize ] + this.gutter; 5423 var previousSize = this.packer[ measure ]; 5424 items.forEach( function( item ) { 5425 item.rect[ coord ] = ( item.rect[ coord ] / previousSize ) * currentSize; 5426 }); 5427 } 5428 5429 this.shiftLayout(); 5430}; 5431 5432// -------------------------- drag -------------------------- // 5433 5434/** 5435 * handle an item drag start event 5436 * @param {Element} elem 5437 */ 5438proto.itemDragStart = function( elem ) { 5439 if ( !this.isEnabled ) { 5440 return; 5441 } 5442 this.stamp( elem ); 5443 // this.ignore( elem ); 5444 var item = this.getItem( elem ); 5445 if ( !item ) { 5446 return; 5447 } 5448 5449 item.enablePlacing(); 5450 item.showDropPlaceholder(); 5451 this.dragItemCount++; 5452 this.updateShiftTargets( item ); 5453}; 5454 5455proto.updateShiftTargets = function( dropItem ) { 5456 this.shiftPacker.reset(); 5457 5458 // pack stamps 5459 this._getBoundingRect(); 5460 var isOriginLeft = this._getOption('originLeft'); 5461 var isOriginTop = this._getOption('originTop'); 5462 this.stamps.forEach( function( stamp ) { 5463 // ignore dragged item 5464 var item = this.getItem( stamp ); 5465 if ( item && item.isPlacing ) { 5466 return; 5467 } 5468 var offset = this._getElementOffset( stamp ); 5469 var rect = new Rect({ 5470 x: isOriginLeft ? offset.left : offset.right, 5471 y: isOriginTop ? offset.top : offset.bottom 5472 }); 5473 this._setRectSize( stamp, rect ); 5474 // save its space in the packer 5475 this.shiftPacker.placed( rect ); 5476 }, this ); 5477 5478 // reset shiftTargets 5479 var isHorizontal = this._getOption('horizontal'); 5480 var segmentName = isHorizontal ? 'rowHeight' : 'columnWidth'; 5481 var measure = isHorizontal ? 'height' : 'width'; 5482 5483 this.shiftTargetKeys = []; 5484 this.shiftTargets = []; 5485 var boundsSize; 5486 var segment = this[ segmentName ]; 5487 segment = segment && segment + this.gutter; 5488 5489 if ( segment ) { 5490 var segmentSpan = Math.ceil( dropItem.rect[ measure ] / segment ); 5491 var segs = Math.floor( ( this.shiftPacker[ measure ] + this.gutter ) / segment ); 5492 boundsSize = ( segs - segmentSpan ) * segment; 5493 // add targets on top 5494 for ( var i=0; i < segs; i++ ) { 5495 this._addShiftTarget( i * segment, 0, boundsSize ); 5496 } 5497 } else { 5498 boundsSize = ( this.shiftPacker[ measure ] + this.gutter ) - dropItem.rect[ measure ]; 5499 this._addShiftTarget( 0, 0, boundsSize ); 5500 } 5501 5502 // pack each item to measure where shiftTargets are 5503 var items = this._getItemsForLayout( this.items ); 5504 var packMethod = this._getPackMethod(); 5505 items.forEach( function( item ) { 5506 var rect = item.rect; 5507 this._setRectSize( item.element, rect ); 5508 this.shiftPacker[ packMethod ]( rect ); 5509 5510 // add top left corner 5511 this._addShiftTarget( rect.x, rect.y, boundsSize ); 5512 // add bottom left / top right corner 5513 var cornerX = isHorizontal ? rect.x + rect.width : rect.x; 5514 var cornerY = isHorizontal ? rect.y : rect.y + rect.height; 5515 this._addShiftTarget( cornerX, cornerY, boundsSize ); 5516 5517 if ( segment ) { 5518 // add targets for each column on bottom / row on right 5519 var segSpan = Math.round( rect[ measure ] / segment ); 5520 for ( var i=1; i < segSpan; i++ ) { 5521 var segX = isHorizontal ? cornerX : rect.x + segment * i; 5522 var segY = isHorizontal ? rect.y + segment * i : cornerY; 5523 this._addShiftTarget( segX, segY, boundsSize ); 5524 } 5525 } 5526 }, this ); 5527 5528}; 5529 5530proto._addShiftTarget = function( x, y, boundsSize ) { 5531 var checkCoord = this._getOption('horizontal') ? y : x; 5532 if ( checkCoord !== 0 && checkCoord > boundsSize ) { 5533 return; 5534 } 5535 // create string for a key, easier to keep track of what targets 5536 var key = x + ',' + y; 5537 var hasKey = this.shiftTargetKeys.indexOf( key ) != -1; 5538 if ( hasKey ) { 5539 return; 5540 } 5541 this.shiftTargetKeys.push( key ); 5542 this.shiftTargets.push({ x: x, y: y }); 5543}; 5544 5545// -------------------------- drop -------------------------- // 5546 5547proto.shift = function( item, x, y ) { 5548 var shiftPosition; 5549 var minDistance = Infinity; 5550 var position = { x: x, y: y }; 5551 this.shiftTargets.forEach( function( target ) { 5552 var distance = getDistance( target, position ); 5553 if ( distance < minDistance ) { 5554 shiftPosition = target; 5555 minDistance = distance; 5556 } 5557 }); 5558 item.rect.x = shiftPosition.x; 5559 item.rect.y = shiftPosition.y; 5560}; 5561 5562function getDistance( a, b ) { 5563 var dx = b.x - a.x; 5564 var dy = b.y - a.y; 5565 return Math.sqrt( dx * dx + dy * dy ); 5566} 5567 5568// -------------------------- drag move -------------------------- // 5569 5570var DRAG_THROTTLE_TIME = 120; 5571 5572/** 5573 * handle an item drag move event 5574 * @param {Element} elem 5575 * @param {Number} x - horizontal change in position 5576 * @param {Number} y - vertical change in position 5577 */ 5578proto.itemDragMove = function( elem, x, y ) { 5579 var item = this.isEnabled && this.getItem( elem ); 5580 if ( !item ) { 5581 return; 5582 } 5583 5584 x -= this.size.paddingLeft; 5585 y -= this.size.paddingTop; 5586 5587 var _this = this; 5588 function onDrag() { 5589 _this.shift( item, x, y ); 5590 item.positionDropPlaceholder(); 5591 _this.layout(); 5592 } 5593 5594 // throttle 5595 var now = new Date(); 5596 if ( this._itemDragTime && now - this._itemDragTime < DRAG_THROTTLE_TIME ) { 5597 clearTimeout( this.dragTimeout ); 5598 this.dragTimeout = setTimeout( onDrag, DRAG_THROTTLE_TIME ); 5599 } else { 5600 onDrag(); 5601 this._itemDragTime = now; 5602 } 5603}; 5604 5605// -------------------------- drag end -------------------------- // 5606 5607/** 5608 * handle an item drag end event 5609 * @param {Element} elem 5610 */ 5611proto.itemDragEnd = function( elem ) { 5612 var item = this.isEnabled && this.getItem( elem ); 5613 if ( !item ) { 5614 return; 5615 } 5616 5617 clearTimeout( this.dragTimeout ); 5618 item.element.classList.add('is-positioning-post-drag'); 5619 5620 var completeCount = 0; 5621 var _this = this; 5622 function onDragEndLayoutComplete() { 5623 completeCount++; 5624 if ( completeCount != 2 ) { 5625 return; 5626 } 5627 // reset drag item 5628 item.element.classList.remove('is-positioning-post-drag'); 5629 item.hideDropPlaceholder(); 5630 _this.dispatchEvent( 'dragItemPositioned', null, [ item ] ); 5631 } 5632 5633 item.once( 'layout', onDragEndLayoutComplete ); 5634 this.once( 'layoutComplete', onDragEndLayoutComplete ); 5635 item.moveTo( item.rect.x, item.rect.y ); 5636 this.layout(); 5637 this.dragItemCount = Math.max( 0, this.dragItemCount - 1 ); 5638 this.sortItemsByPosition(); 5639 item.disablePlacing(); 5640 this.unstamp( item.element ); 5641}; 5642 5643/** 5644 * binds Draggabilly events 5645 * @param {Draggabilly} draggie 5646 */ 5647proto.bindDraggabillyEvents = function( draggie ) { 5648 this._bindDraggabillyEvents( draggie, 'on' ); 5649}; 5650 5651proto.unbindDraggabillyEvents = function( draggie ) { 5652 this._bindDraggabillyEvents( draggie, 'off' ); 5653}; 5654 5655proto._bindDraggabillyEvents = function( draggie, method ) { 5656 var handlers = this.handleDraggabilly; 5657 draggie[ method ]( 'dragStart', handlers.dragStart ); 5658 draggie[ method ]( 'dragMove', handlers.dragMove ); 5659 draggie[ method ]( 'dragEnd', handlers.dragEnd ); 5660}; 5661 5662/** 5663 * binds jQuery UI Draggable events 5664 * @param {jQuery} $elems 5665 */ 5666proto.bindUIDraggableEvents = function( $elems ) { 5667 this._bindUIDraggableEvents( $elems, 'on' ); 5668}; 5669 5670proto.unbindUIDraggableEvents = function( $elems ) { 5671 this._bindUIDraggableEvents( $elems, 'off' ); 5672}; 5673 5674proto._bindUIDraggableEvents = function( $elems, method ) { 5675 var handlers = this.handleUIDraggable; 5676 $elems 5677 [ method ]( 'dragstart', handlers.start ) 5678 [ method ]( 'drag', handlers.drag ) 5679 [ method ]( 'dragstop', handlers.stop ); 5680}; 5681 5682// ----- destroy ----- // 5683 5684var _destroy = proto.destroy; 5685proto.destroy = function() { 5686 _destroy.apply( this, arguments ); 5687 // disable flag; prevent drag events from triggering. #72 5688 this.isEnabled = false; 5689}; 5690 5691// ----- ----- // 5692 5693Packery.Rect = Rect; 5694Packery.Packer = Packer; 5695 5696return Packery; 5697 5698})); 5699 5700/*! 5701 * Packery layout mode v2.0.1 5702 * sub-classes Packery 5703 */ 5704 5705/*jshint browser: true, strict: true, undef: true, unused: true */ 5706 5707( function( window, factory ) {
5708 5709 // universal module definition 5710 if ( typeof define == 'function' && define.amd ) { 5711 // AMD 5712 define( [ 5713 'isotope-layout/js/layout-mode', 5714 'packery/js/packery' 5715 ], 5716 factory ); 5717 } else if ( typeof module == 'object' && module.exports ) { 5718 // CommonJS 5719 module.exports = factory( 5720 require('isotope-layout/js/layout-mode'), 5721 require('packery') 5722 ); 5723 } else { 5724 // browser global 5725 factory( 5726 window.Isotope.LayoutMode, 5727 window.Packery 5728 ); 5729 } 5730 5731}( window, function factor( LayoutMode, Packery ) { 5732 5733 5734 // create an Outlayer layout class 5735 var PackeryMode = LayoutMode.create('packery'); 5736 var proto = PackeryMode.prototype; 5737 5738 var keepModeMethods = { 5739 _getElementOffset: true, 5740 _getMeasurement: true 5741 }; 5742 5743 // inherit Packery prototype 5744 for ( var method in Packery.prototype ) { 5745 // do not inherit mode methods 5746 if ( !keepModeMethods[ method ] ) { 5747 proto[ method ] = Packery.prototype[ method ]; 5748 } 5749 } 5750 5751 // set packer in _resetLayout 5752 var _resetLayout = proto._resetLayout; 5753 proto._resetLayout = function() { 5754 this.packer = this.packer || new Packery.Packer(); 5755 this.shiftPacker = this.shiftPacker || new Packery.Packer(); 5756 _resetLayout.apply( this, arguments ); 5757 }; 5758 5759 var _getItemLayoutPosition = proto._getItemLayoutPosition; 5760 proto._getItemLayoutPosition = function( item ) { 5761 // set packery rect 5762 item.rect = item.rect || new Packery.Rect(); 5763 return _getItemLayoutPosition.call( this, item ); 5764 }; 5765 5766 // needsResizeLayout for vertical or horizontal 5767 var _needsResizeLayout = proto.needsResizeLayout; 5768 proto.needsResizeLayout = function() { 5769 if ( this._getOption('horizontal') ) { 5770 return this.needsVerticalResizeLayout(); 5771 } else { 5772 return _needsResizeLayout.call( this ); 5773 } 5774 }; 5775 5776 // point to mode options for horizontal 5777 var _getOption = proto._getOption; 5778 proto._getOption = function( option ) { 5779 if ( option == 'horizontal' ) { 5780 return this.options.isHorizontal !== undefined ? 5781 this.options.isHorizontal : this.options.horizontal; 5782 } 5783 return _getOption.apply( this.isotope, arguments ); 5784 }; 5785 5786 return PackeryMode; 5787 5788})); 5789 5790/*! 5791 * cellsByRows layout mode for Isotope 5792 * v1.1.3 5793 * http://isotope.metafizzy.co/layout-modes/cellsbyrow.html 5794 */ 5795 5796/*jshint browser: true, devel: false, strict: true, undef: true, unused: true */ 5797 5798( function( window, factory ) { 5799 // universal module definition 5800 /* jshint strict: false */ /*globals define, module, require */ 5801 if ( typeof define === 'function' && define.amd ) { 5802 // AMD 5803 define( [ 5804 'isotope/js/layout-mode' 5805 ], 5806 factory ); 5807 } else if ( typeof exports === 'object' ) { 5808 // CommonJS 5809 module.exports = factory( 5810 require('isotope-layout/js/layout-mode') 5811 ); 5812 } else { 5813 // browser global 5814 factory( 5815 window.Isotope.LayoutMode 5816 ); 5817 } 5818 5819}( window, function factory( LayoutMode ) { 5820 'use strict'; 5821 5822 var CellsByRow = LayoutMode.create( 'cellsByRow' ); 5823 var proto = CellsByRow.prototype; 5824 5825 proto._resetLayout = function() { 5826 // reset properties 5827 this.itemIndex = 0; 5828 // measurements 5829 this.getColumnWidth(); 5830 this.getRowHeight(); 5831 // set cols 5832 this.cols = Math.floor( this.isotope.size.innerWidth / this.columnWidth ); 5833 this.cols = Math.max( this.cols, 1 ); 5834 }; 5835 5836 proto._getItemLayoutPosition = function( item ) { 5837 item.getSize(); 5838 var col = this.itemIndex % this.cols; 5839 var row = Math.floor( this.itemIndex / this.cols ); 5840 // center item within cell 5841 var x = ( col + 0.5 ) * this.columnWidth - item.size.outerWidth / 2; 5842 var y = ( row + 0.5 ) * this.rowHeight - item.size.outerHeight / 2; 5843 this.itemIndex++; 5844 return { x: x, y: y }; 5845 }; 5846 5847 proto._getContainerSize = function() { 5848 return { 5849 height: Math.ceil( this.itemIndex / this.cols ) * this.rowHeight 5850 }; 5851 }; 5852 5853 return CellsByRow; 5854 5855})); 5856/*global jQuery: true */ 5857 5858/*! 5859 -------------------------------- 5860 Infinite Scroll 5861 -------------------------------- 5862 + https://github.com/paulirish/infinite-scroll 5863 + version 2.1.0 5864 + Copyright 2011/12 Paul Irish & Luke Shumard 5865 + Licensed under the MIT license 5866 5867 + Documentation: http://infinite-scroll.com/ 5868*/ 5869 5870// Uses AMD or browser globals to create a jQuery plugin. 5871(function (factory) { 5872 if (typeof define === 'function' && define.amd) { 5873 // AMD. Register as an anonymous module. 5874 define(['jquery'], factory); 5875 } else { 5876 // Browser globals 5877 factory(jQuery); 5878 } 5879}(function ($, undefined) { 5880 'use strict'; 5881
5882 $.infinitescroll = function infscr(options, callback, element) { 5883 this.element = $(element); 5884 5885 // Flag the object in the event of a failed creation 5886 if (!this._create(options, callback)) { 5887 this.failed = true; 5888 } 5889 }; 5890 5891 $.infinitescroll.defaults = { 5892 loading: { 5893 finished: undefined, 5894 finishedMsg: "<em>Congratulations, you've reached the end of the internet.</em>", 5895 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
5895MzExnbRvQ2Sy7vN0zvVtNfU2tLY3rPgLdnDvca4VQS/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
5895iqpQpZ4apwSwRtjqrB3muoF9BboaXKmshlqWqsWiGt2wphJkQbAU5hoCACH5BAUKABsALAcABADOAAsAAAX/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', 5896 msg: null, 5897 msgText: '<em>Loading the next set of posts...</em>', 5898 selector: null, 5899 speed: 'fast', 5900 start: undefined 5901 }, 5902 state: { 5903 isDuringAjax: false, 5904 isInvalidPage: false,
5905 isDestroyed: false, 5906 isDone: false, // For when it goes all the way through the archive. 5907 isPaused: false, 5908 isBeyondMaxPage: false, 5909 currPage: 1 5910 }, 5911 debug: false, 5912 behavior: undefined, 5913 binder: $(window), // used to cache the selector 5914 nextSelector: 'div.navigation a:first', 5915 navSelector: 'div.navigation', 5916 contentSelector: null, // rename to pageFragment 5917 extraScrollPx: 150, 5918 itemSelector: 'div.post', 5919 animate: false, 5920 pathParse: undefined, 5921 dataType: 'html', 5922 appendCallback: true, 5923 bufferPx: 40, 5924 errorCallback: function () { }, 5925 infid: 0, //Instance ID 5926 pixelsFromNavToBottom: undefined, 5927 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 5928 prefill: false, // When the document is smaller than the window, load data until the document is larger or links are exhausted 5929 maxPage: undefined // to manually control maximum page (when maxPage is undefined, maximum page limitation is not work) 5930 }; 5931 5932 $.infinitescroll.prototype = { 5933 5934 /* 5935 ---------------------------- 5936 Private methods 5937 ---------------------------- 5938 */ 5939 5940 // Bind or unbind from scroll 5941 _binding: function infscr_binding(binding) { 5942 5943 var instance = this, 5944 opts = instance.options; 5945 5946 opts.v = '2.0b2.120520'; 5947 5948 // if behavior is defined and this function is extended, call that instead of default 5949 if (!!opts.behavior && this['_binding_'+opts.behavior] !== undefined) { 5950 this['_binding_'+opts.behavior].call(this); 5951 return; 5952 } 5953 5954 if (binding !== 'bind' && binding !== 'unbind') { 5955 this._debug('Binding value ' + binding + ' not valid'); 5956 return false; 5957 } 5958 5959 if (binding === 'unbind') { 5960 (this.options.binder).unbind('smartscroll.infscr.' + instance.options.infid); 5961 } else { 5962 (this.options.binder)[binding]('smartscroll.infscr.' + instance.options.infid, function () { 5963 instance.scroll(); 5964 }); 5965 } 5966 5967 this._debug('Binding', binding); 5968 }, 5969 5970 // Fundamental aspects of the plugin are initialized 5971 _create: function infscr_create(options, callback) { 5972 5973 // Add custom options to defaults 5974 var opts = $.extend(true, {}, $.infinitescroll.defaults, options); 5975 this.options = opts; 5976 var $window = $(window); 5977 var instance = this; 5978 5979 // Validate selectors 5980 if (!instance._validate(options)) { 5981 return false; 5982 } 5983 5984 // Validate page fragment path 5985 var path = $(opts.nextSelector).attr('href'); 5986 if (!path) { 5987 this._debug('Navigation selector not found'); 5988 return false; 5989 } 5990 5991 // Set the path to be a relative URL from root. 5992 opts.path = opts.path || this._determinepath(path); 5993 5994 // contentSelector is 'page fragment' option for .load() / .ajax() calls 5995 opts.contentSelector = opts.contentSelector || this.element; 5996 5997 // loading.selector - if we want to place the load message in a specific selector, defaulted to the contentSelector 5998 opts.loading.selector = opts.loading.selector || opts.contentSelector; 5999 6000 // Define loading.msg 6001 opts.loading.msg = opts.loading.msg || $('<div id="infscr-loading"><img alt="Loading..." src="' + opts.loading.img + '" /><div>' + opts.loading.msgText + '</div></div>'); 6002 6003 // Preload loading.img 6004 (new Image()).src = opts.loading.img; 6005 6006 // distance from nav links to bottom 6007 // computed as: height of the document + top offset of container - top offset of nav link 6008 if(opts.pixelsFromNavToBottom === undefined) { 6009 opts.pixelsFromNavToBottom = $(document).height() - $(opts.navSelector).offset().top; 6010 this._debug('pixelsFromNavToBottom: ' + opts.pixelsFromNavToBottom); 6011 } 6012 6013 var self = this; 6014 6015 // determine loading.start actions 6016 opts.loading.start = opts.loading.start || function() { 6017 $(opts.navSelector).hide(); 6018 opts.loading.msg 6019 .appendTo(opts.loading.selector) 6020 .show(opts.loading.speed, $.proxy(function() { 6021 this.beginAjax(opts); 6022 }, self)); 6023 }; 6024 6025 // determine loading.finished actions 6026 opts.loading.finished = opts.loading.finished || function() { 6027 if (!opts.state.isBeyondMaxPage) 6028 opts.loading.msg.fadeOut(opts.loading.speed); 6029 }; 6030 6031 // callback loading 6032 opts.callback = function(instance, data, url) { 6033 if (!!opts.behavior && instance['_callback_'+opts.behavior] !== undefined) { 6034 instance['_callback_'+opts.behavior].call($(opts.contentSelector)[0], data, url); 6035 } 6036 6037 if (callback) { 6038 callback.call($(opts.contentSelector)[0], data, opts, url); 6039 } 6040 6041 if (opts.prefill) { 6042 $window.bind('resize.infinite-scroll', instance._prefill); 6043 } 6044 }; 6045 6046 if (options.debug) { 6047 // Tell IE9 to use its built-in console 6048 if (Function.prototype.bind && (typeof console === 'object' || typeof console === 'function') && typeof console.log === 'object') { 6049 ['log','info','warn','error','assert','dir','clear','profile','profileEnd'] 6050 .forEach(function (method) { 6051 console[method] = this.call(console[method], console); 6052 }, Function.prototype.bind); 6053 } 6054 } 6055 6056 this._setup(); 6057 6058 // Setups the prefill method for use 6059 if (opts.prefill) { 6060 this._prefill(); 6061 } 6062 6063 // Return true to indicate successful creation 6064 return true; 6065 }, 6066 6067 _prefill: function infscr_prefill() { 6068 var instance = this; 6069 var $window = $(window); 6070 6071 function needsPrefill() { 6072 return ( $(instance.options.contentSelector).height() <= $window.height() ); 6073 } 6074 6075 this._prefill = function() { 6076 if (needsPrefill()) { 6077 instance.scroll(); 6078 } 6079 6080 $window.bind('resize.infinite-scroll', function() { 6081 if (needsPrefill()) { 6082 $window.unbind('resize.infinite-scroll'); 6083 instance.scroll(); 6084 } 6085 }); 6086 }; 6087 6088 // Call self after setting up the new function 6089 this._prefill(); 6090 }, 6091 6092 // Console log wrapper 6093 _debug: function infscr_debug() { 6094 if (true !== this.options.debug) { 6095 return; 6096 } 6097 6098 if (typeof console !== 'undefined' && typeof console.log === 'function') { 6099 // Modern browsers 6100 // Single argument, which is a string 6101 if ((Array.prototype.slice.call(arguments)).length === 1 && typeof Array.prototype.slice.call(arguments)[0] === 'string') { 6102 console.log( (Array.prototype.slice.call(arguments)).toString() ); 6103 } else { 6104 console.log( Array.prototype.slice.call(arguments) ); 6105 } 6106 } else if (!Function.prototype.bind && typeof console !== 'undefined' && typeof console.log === 'object') { 6107 // IE8 6108 Function.prototype.call.call(console.log, console, Array.prototype.slice.call(arguments)); 6109 } 6110 }, 6111 6112 // find the number to increment in the path.
6113 _determinepath: function infscr_determinepath(path) { 6114 6115 var opts = this.options; 6116 6117 // if behavior is defined and this function is extended, call that instead of default 6118 if (!!opts.behavior && this['_determinepath_'+opts.behavior] !== undefined) { 6119 return this['_determinepath_'+opts.behavior].call(this,path); 6120 } 6121 6122 if (!!opts.pathParse) { 6123 6124 this._debug('pathParse manual'); 6125 return opts.pathParse(path, this.options.state.currPage+1); 6126 6127 } else if (path.match(/^(.*?)\b2\b(.*?$)/)) { 6128 path = path.match(/^(.*?)\b2\b(.*?$)/).slice(1); 6129 6130 // if there is any 2 in the url at all. 6131 } else if (path.match(/^(.*?)2(.*?$)/)) { 6132 6133 // page= is used in django: 6134 // http://www.infinite-scroll.com/changelog/comment-page-1/#comment-127 6135 if (path.match(/^(.*?page=)2(\/.*|$)/)) { 6136 path = path.match(/^(.*?page=)2(\/.*|$)/).slice(1); 6137 return path; 6138 } 6139 6140 path = path.match(/^(.*?)2(.*?$)/).slice(1); 6141 6142 } else { 6143 6144 // page= is used in drupal too but second page is page=1 not page=2: 6145 // thx Jerod Fritz, vladikoff 6146 if (path.match(/^(.*?page=)1(\/.*|$)/)) { 6147 path = path.match(/^(.*?page=)1(\/.*|$)/).slice(1); 6148 return path; 6149 } else { 6150 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."); 6151 // Get rid of isInvalidPage to allow permalink to state 6152 opts.state.isInvalidPage = true; //prevent it from running on this page. 6153 } 6154 } 6155 this._debug('determinePath', path); 6156 return path; 6157 6158 }, 6159 6160 // Custom error 6161 _error: function infscr_error(xhr) { 6162 6163 var opts = this.options; 6164 6165 // if behavior is defined and this function is extended, call that instead of default 6166 if (!!opts.behavior && this['_error_'+opts.behavior] !== undefined) { 6167 this['_error_'+opts.behavior].call(this,xhr); 6168 return; 6169 } 6170 6171 if (xhr !== 'destroy' && xhr !== 'end') { 6172 xhr = 'unknown'; 6173 } 6174 6175 this._debug('Error', xhr); 6176 6177 if (xhr === 'end' || opts.state.isBeyondMaxPage) { 6178 this._showdonemsg(); 6179 } 6180 6181 opts.state.isDone = true; 6182 opts.state.currPage = 1; // if you need to go back to this instance 6183 opts.state.isPaused = false; 6184 opts.state.isBeyondMaxPage = false; 6185 this._binding('unbind'); 6186 6187 }, 6188 6189 // Load Callback 6190 _loadcallback: function infscr_loadcallback(box, data, url) { 6191 var opts = this.options, 6192 callback = this.options.callback, // GLOBAL OBJECT FOR CALLBACK 6193 result = (opts.state.isDone) ? 'done' : (!opts.appendCallback) ? 'no-append' : 'append', 6194 frag; 6195 6196 // if behavior is defined and this function is extended, call that instead of default 6197 if (!!opts.behavior && this['_loadcallback_'+opts.behavior] !== undefined) { 6198 this['_loadcallback_'+opts.behavior].call(this,box,data); 6199 return; 6200 } 6201 6202 switch (result) { 6203 case 'done': 6204 this._showdonemsg(); 6205 return false; 6206 6207 case 'no-append': 6208 if (opts.dataType === 'html') { 6209 data = '<div>' + data + '</div>'; 6210 data = $(data).find(opts.itemSelector); 6211 } 6212 6213 // if it didn't return anything 6214 if (data.length === 0) { 6215 return this._error('end'); 6216 } 6217 6218 break; 6219 6220 case 'append': 6221 var children = box.children(); 6222 // if it didn't return anything 6223 if (children.length === 0) { 6224 return this._error('end'); 6225 } 6226 6227 // use a documentFragment because it works when content is going into a table or UL 6228 frag = document.createDocumentFragment(); 6229 while (box[0].firstChild) { 6230 frag.appendChild(box[0].firstChild); 6231 } 6232 6233 this._debug('contentSelector', $(opts.contentSelector)[0]); 6234 $(opts.contentSelector)[0].appendChild(frag); 6235 // previously, we would pass in the new DOM element as context for the callback 6236 // however we're now using a documentfragment, which doesn't have parents or children, 6237 // so the context is the contentContainer guy, and we pass in an array 6238 // of the elements collected as the first argument. 6239 6240 data = children.get(); 6241 break; 6242 } 6243 6244 // loadingEnd function 6245 opts.loading.finished.call($(opts.contentSelector)[0],opts); 6246 6247 // smooth scroll to ease in the new content 6248 if (opts.animate) { 6249 var scrollTo = $(window).scrollTop() + $(opts.loading.msg).height() + opts.extraScrollPx + 'px'; 6250 $('html,body').animate({ scrollTop: scrollTo }, 800, function () { opts.state.isDuringAjax = false; }); 6251 } 6252 6253 if (!opts.animate) { 6254 // once the call is done, we can allow it again. 6255 opts.state.isDuringAjax = false;
6256 } 6257 6258 callback(this, data, url); 6259 6260 if (opts.prefill) { 6261 this._prefill(); 6262 } 6263 }, 6264 6265 _nearbottom: function infscr_nearbottom() { 6266 6267 var opts = this.options, 6268 pixelsFromWindowBottomToBottom = 0 + $(document).height() - (opts.binder.scrollTop()) - $(window).height(); 6269 6270 // if behavior is defined and this function is extended, call that instead of default 6271 if (!!opts.behavior && this['_nearbottom_'+opts.behavior] !== undefined) { 6272 return this['_nearbottom_'+opts.behavior].call(this); 6273 } 6274 6275 this._debug('math:', pixelsFromWindowBottomToBottom, opts.pixelsFromNavToBottom); 6276 6277 // if distance remaining in the scroll (including buffer) is less than the orignal nav to bottom.... 6278 return (pixelsFromWindowBottomToBottom - opts.bufferPx < opts.pixelsFromNavToBottom); 6279 6280 }, 6281 6282 // Pause / temporarily disable plugin from firing 6283 _pausing: function infscr_pausing(pause) { 6284 6285 var opts = this.options; 6286 6287 // if behavior is defined and this function is extended, call that instead of default 6288 if (!!opts.behavior && this['_pausing_'+opts.behavior] !== undefined) { 6289 this['_pausing_'+opts.behavior].call(this,pause); 6290 return; 6291 } 6292 6293 // If pause is not 'pause' or 'resume', toggle it's value 6294 if (pause !== 'pause' && pause !== 'resume' && pause !== null) { 6295 this._debug('Invalid argument. Toggling pause value instead'); 6296 } 6297 6298 pause = (pause && (pause === 'pause' || pause === 'resume')) ? pause : 'toggle'; 6299 6300 switch (pause) { 6301 case 'pause': 6302 opts.state.isPaused = true; 6303 break; 6304 6305 case 'resume': 6306 opts.state.isPaused = false; 6307 break; 6308 6309 case 'toggle': 6310 opts.state.isPaused = !opts.state.isPaused; 6311 break; 6312 } 6313 6314 this._debug('Paused', opts.state.isPaused); 6315 return false; 6316 6317 }, 6318 6319 // Behavior is determined 6320 // If the behavior option is undefined, it will set to default and bind to scroll 6321 _setup: function infscr_setup() { 6322 6323 var opts = this.options; 6324 6325 // if behavior is defined and this function is extended, call that instead of default 6326 if (!!opts.behavior && this['_setup_'+opts.behavior] !== undefined) { 6327 this['_setup_'+opts.behavior].call(this); 6328 return; 6329 } 6330 6331 this._binding('bind'); 6332 6333 return false; 6334 6335 }, 6336 6337 // Show done message 6338 _showdonemsg: function infscr_showdonemsg() { 6339 6340 var opts = this.options; 6341 6342 // if behavior is defined and this function is extended, call that instead of default 6343 if (!!opts.behavior && this['_showdonemsg_'+opts.behavior] !== undefined) { 6344 this['_showdonemsg_'+opts.behavior].call(this); 6345 return; 6346 } 6347 6348 opts.loading.msg 6349 .find('img') 6350 .hide() 6351 .parent() 6352 .find('div').html(opts.loading.finishedMsg).animate({ opacity: 1 }, 2000, function () { 6353 $(this).parent().fadeOut(opts.loading.speed); 6354 }); 6355 6356 // user provided callback when done 6357 opts.errorCallback.call($(opts.contentSelector)[0],'done'); 6358 }, 6359 6360 // grab each selector option and see if any fail 6361 _validate: function infscr_validate(opts) { 6362 for (var key in opts) { 6363 if (key.indexOf && key.indexOf('Selector') > -1 && $(opts[key]).length === 0) { 6364 this._debug('Your ' + key + ' found no elements.'); 6365 return false; 6366 } 6367 } 6368 6369 return true; 6370 }, 6371 6372 /* 6373 ---------------------------- 6374 Public methods 6375 ---------------------------- 6376 */ 6377 6378 // Bind to scroll 6379 bind: function infscr_bind() { 6380 this._binding('bind'); 6381 }, 6382 6383 // Destroy current instance of plugin 6384 destroy: function infscr_destroy() { 6385 this.options.state.isDestroyed = true; 6386 this.options.loading.finished(); 6387 return this._error('destroy'); 6388 }, 6389 6390 // Set pause value to false 6391 pause: function infscr_pause() { 6392 this._pausing('pause'); 6393 }, 6394 6395 // Set pause value to false 6396 resume: function infscr_resume() { 6397 this._pausing('resume'); 6398 }, 6399 6400 beginAjax: function infscr_ajax(opts) { 6401 var instance = this, 6402 path = opts.path, 6403 box, desturl, method, condition; 6404 6405 // increment the URL bit. e.g. /page/3/ 6406 opts.state.currPage++; 6407 6408 // Manually control maximum page 6409 if ( opts.maxPage !== undefined && opts.state.currPage > opts.maxPage ){ 6410 opts.state.isBeyondMaxPage = true; 6411 this.destroy(); 6412 return; 6413 } 6414 6415 // if we're dealing with a table we can't use DIVs 6416 box = $(opts.contentSelector).is('table, tbody') ? $('<tbody/>') : $('<div/>'); 6417 6418 desturl = (typeof path === 'function') ? path(opts.state.currPage) : path.join(opts.state.currPage); 6419 instance._debug('heading into ajax', desturl); 6420 6421 method = (opts.dataType === 'html' || opts.dataType === 'json' ) ? opts.dataType : 'html+callback'; 6422 if (opts.appendCallback && opts.dataType === 'html') { 6423 method += '+callback'; 6424 } 6425 6426 switch (method) { 6427 case 'html+callback': 6428 instance._debug('Using HTML via .load() method'); 6429 box.load(desturl + ' ' + opts.itemSelector, undefined, function infscr_ajax_callback(responseText) { 6430 instance._loadcallback(box, responseText, desturl); 6431 }); 6432 6433 break; 6434 6435 case 'html': 6436 instance._debug('Using ' + (method.toUpperCase()) + ' via $.ajax() method'); 6437 $.ajax({ 6438 // params 6439 url: desturl, 6440 dataType: opts.dataType, 6441 complete: function infscr_ajax_callback(jqXHR, textStatus) { 6442 condition = (typeof (jqXHR.isResolved) !== 'undefined') ? (jqXHR.isResolved()) : (textStatus === 'success' || textStatus === 'notmodified'); 6443 if (condition) { 6444 instance._loadcallback(box, jqXHR.responseText, desturl); 6445 } else { 6446 instance._error('end'); 6447 } 6448 } 6449 }); 6450 6451 break; 6452 case 'json': 6453 instance._debug('Using ' + (method.toUpperCase()) + ' via $.ajax() method'); 6454 $.ajax({ 6455 dataType: 'json', 6456 type: 'GET', 6457 url: desturl, 6458 success: function (data, textStatus, jqXHR) { 6459 condition = (typeof (jqXHR.isResolved) !== 'undefined') ? (jqXHR.isResolved()) : (textStatus === 'success' || textStatus === 'notmodified'); 6460 if (opts.appendCallback) { 6461 // if appendCallback is true, you must defined template in options. 6462 // note that data passed into _loadcallback is already an html (after processed in opts.template(data)). 6463 if (opts.template !== undefined) { 6464 var theData = opts.template(data); 6465 box.append(theData); 6466 if (condition) { 6467 instance._loadcallback(box, theData); 6468 } else { 6469 instance._error('end'); 6470 } 6471 } else { 6472 instance._debug('template must be defined.'); 6473 instance._error('end'); 6474 } 6475 } else { 6476 // if appendCallback is false, we will pass in the JSON object. you should handle it yourself in your callback. 6477 if (condition) { 6478 instance._loadcallback(box, data, desturl); 6479 } else { 6480 instance._error('end'); 6481 } 6482 } 6483 }, 6484 error: function() { 6485 instance._debug('JSON ajax request failed.'); 6486 instance._error('end'); 6487 } 6488 }); 6489 6490 break; 6491 } 6492 }, 6493 6494 // Retrieve next set of content items 6495 retrieve: function infscr_retrieve(pageNum) { 6496 pageNum = pageNum || null; 6497 6498 var instance = this, 6499 opts = instance.options; 6500 6501 // if behavior is defined and this function is extended, call that instead of default 6502 if (!!opts.behavior && this['retrieve_'+opts.behavior] !== undefined) { 6503 this['retrieve_'+opts.behavior].call(this,pageNum); 6504 return; 6505 } 6506 6507 // for manual triggers, if destroyed, get out of here 6508 if (opts.state.isDestroyed) { 6509 this._debug('Instance is destroyed'); 6510 return false;
6511 } 6512 6513 // we dont want to fire the ajax multiple times 6514 opts.state.isDuringAjax = true; 6515 6516 opts.loading.start.call($(opts.contentSelector)[0],opts); 6517 }, 6518 6519 // Check to see next page is needed 6520 scroll: function infscr_scroll() { 6521 6522 var opts = this.options, 6523 state = opts.state; 6524 6525 // if behavior is defined and this function is extended, call that instead of default 6526 if (!!opts.behavior && this['scroll_'+opts.behavior] !== undefined) { 6527 this['scroll_'+opts.behavior].call(this); 6528 return; 6529 } 6530 6531 if (state.isDuringAjax || state.isInvalidPage || state.isDone || state.isDestroyed || state.isPaused) { 6532 return; 6533 } 6534 6535 if (!this._nearbottom()) { 6536 return; 6537 } 6538 6539 this.retrieve(); 6540 6541 }, 6542 6543 // Toggle pause value 6544 toggle: function infscr_toggle() { 6545 this._pausing(); 6546 }, 6547 6548 // Unbind from scroll 6549 unbind: function infscr_unbind() { 6550 this._binding('unbind'); 6551 }, 6552 6553 // update options 6554 update: function infscr_options(key) { 6555 if ($.isPlainObject(key)) { 6556 this.options = $.extend(true,this.options,key); 6557 } 6558 } 6559 }; 6560 6561 6562 /* 6563 ---------------------------- 6564 Infinite Scroll function 6565 ---------------------------- 6566 6567 Borrowed logic from the following... 6568 6569 jQuery UI 6570 - https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.widget.js 6571 6572 jCarousel 6573 - https://github.com/jsor/jcarousel/blob/master/lib/jquery.jcarousel.js 6574 6575 Masonry 6576 - https://github.com/desandro/masonry/blob/master/jquery.masonry.js 6577 6578*/ 6579 6580 $.fn.infinitescroll = function infscr_init(options, callback) { 6581 6582 6583 var thisCall = typeof options; 6584 6585 switch (thisCall) { 6586 6587 // method 6588 case 'string': 6589 var args = Array.prototype.slice.call(arguments, 1); 6590 6591 this.each(function () { 6592 var instance = $.data(this, 'infinitescroll'); 6593 6594 if (!instance) { 6595 // not setup yet 6596 // return $.error('Method ' + options + ' cannot be called until Infinite Scroll is setup'); 6597 return false; 6598 } 6599 6600 if (!$.isFunction(instance[options]) || options.charAt(0) === '_') { 6601 // return $.error('No such method ' + options + ' for Infinite Scroll'); 6602 return false; 6603 } 6604 6605 // no errors! 6606 instance[options].apply(instance, args); 6607 }); 6608 6609 break; 6610 6611 // creation 6612 case 'object': 6613 6614 this.each(function () { 6615 6616 var instance = $.data(this, 'infinitescroll'); 6617 6618 if (instance) { 6619 6620 // update options of current instance 6621 instance.update(options); 6622 6623 } else { 6624 6625 // initialize new instance 6626 instance = new $.infinitescroll(options, callback, this); 6627 6628 // don't attach if instantiation failed 6629 if (!instance.failed) { 6630 $.data(this, 'infinitescroll', instance); 6631 } 6632 6633 } 6634 6635 }); 6636 6637 break; 6638 6639 } 6640 6641 return this; 6642 }; 6643 6644 6645 6646 /* 6647 * smartscroll: debounced scroll event for jQuery * 6648 * https://github.com/lukeshumard/smartscroll 6649 * Based on smartresize by @louis_remi: https://github.com/lrbabe/jquery.smartresize.js * 6650 * Copyright 2011 Louis-Remi & Luke Shumard * Licensed under the MIT license. * 6651 */ 6652 6653 var event = $.event, 6654 scrollTimeout; 6655 6656 event.special.smartscroll = { 6657 setup: function () { 6658 $(this).bind('scroll', event.special.smartscroll.handler); 6659 }, 6660 teardown: function () { 6661 $(this).unbind('scroll', event.special.smartscroll.handler); 6662 }, 6663 handler: function (event, execAsap) { 6664 // Save the context 6665 var context = this, 6666 args = arguments; 6667 6668 // set correct event type 6669 event.type = 'smartscroll'; 6670 6671 if (scrollTimeout) { clearTimeout(scrollTimeout); } 6672 scrollTimeout = setTimeout(function () { 6673 $(context).trigger('smartscroll', args); 6674 }, execAsap === 'execAsap' ? 0 : 100); 6675 } 6676 }; 6677 6678 $.fn.smartscroll = function (fn) {
6679 return fn ? this.bind('smartscroll', fn) : this.trigger('smartscroll', ['execAsap']); 6680 }; 6681 6682})); 6683 6684/*! 6685Waypoints - 4.0.1 6686Copyright © 2011-2016 Caleb Troughton 6687Licensed under the MIT license. 6688https://github.com/imakewebthings/waypoints/blob/master/licenses.txt 6689*/ 6690(function() { 6691 'use strict' 6692 6693 var keyCounter = 0 6694 var allWaypoints = {} 6695 6696 /* http://imakewebthings.com/waypoints/api/waypoint */ 6697 function Waypoint(options) { 6698 if (!options) { 6699 throw new Error('No options passed to Waypoint constructor') 6700 } 6701 if (!options.element) { 6702 throw new Error('No element option passed to Waypoint constructor') 6703 } 6704 if (!options.handler) { 6705 throw new Error('No handler option passed to Waypoint constructor') 6706 } 6707 6708 this.key = 'waypoint-' + keyCounter 6709 this.options = Waypoint.Adapter.extend({}, Waypoint.defaults, options) 6710 this.element = this.options.element 6711 this.adapter = new Waypoint.Adapter(this.element) 6712 this.callback = options.handler 6713 this.axis = this.options.horizontal ? 'horizontal' : 'vertical' 6714 this.enabled = this.options.enabled 6715 this.triggerPoint = null 6716 this.group = Waypoint.Group.findOrCreate({ 6717 name: this.options.group, 6718 axis: this.axis 6719 }) 6720 this.context = Waypoint.Context.findOrCreateByElement(this.options.context) 6721 6722 if (Waypoint.offsetAliases[this.options.offset]) { 6723 this.options.offset = Waypoint.offsetAliases[this.options.offset] 6724 } 6725 this.group.add(this) 6726 this.context.add(this) 6727 allWaypoints[this.key] = this 6728 keyCounter += 1 6729 } 6730 6731 /* Private */ 6732 Waypoint.prototype.queueTrigger = function(direction) { 6733 this.group.queueTrigger(this, direction) 6734 } 6735 6736 /* Private */ 6737 Waypoint.prototype.trigger = function(args) { 6738 if (!this.enabled) { 6739 return 6740 } 6741 if (this.callback) { 6742 this.callback.apply(this, args) 6743 } 6744 } 6745 6746 /* Public */ 6747 /* http://imakewebthings.com/waypoints/api/destroy */ 6748 Waypoint.prototype.destroy = function() { 6749 this.context.remove(this) 6750 this.group.remove(this) 6751 delete allWaypoints[this.key] 6752 } 6753 6754 /* Public */ 6755 /* http://imakewebthings.com/waypoints/api/disable */ 6756 Waypoint.prototype.disable = function() { 6757 this.enabled = false 6758 return this 6759 } 6760 6761 /* Public */ 6762 /* http://imakewebthings.com/waypoints/api/enable */ 6763 Waypoint.prototype.enable = function() { 6764 this.context.refresh() 6765 this.enabled = true 6766 return this 6767 } 6768 6769 /* Public */ 6770 /* http://imakewebthings.com/waypoints/api/next */ 6771 Waypoint.prototype.next = function() { 6772 return this.group.next(this) 6773 } 6774 6775 /* Public */ 6776 /* http://imakewebthings.com/waypoints/api/previous */ 6777 Waypoint.prototype.previous = function() { 6778 return this.group.previous(this) 6779 } 6780 6781 /* Private */ 6782 Waypoint.invokeAll = function(method) { 6783 var allWaypointsArray = []
6784 for (var waypointKey in allWaypoints) { 6785 allWaypointsArray.push(allWaypoints[waypointKey]) 6786 } 6787 for (var i = 0, end = allWaypointsArray.length; i < end; i++) { 6788 allWaypointsArray[i][method]() 6789 } 6790 } 6791 6792 /* Public */ 6793 /* http://imakewebthings.com/waypoints/api/destroy-all */ 6794 Waypoint.destroyAll = function() { 6795 Waypoint.invokeAll('destroy') 6796 } 6797 6798 /* Public */ 6799 /* http://imakewebthings.com/waypoints/api/disable-all */ 6800 Waypoint.disableAll = function() { 6801 Waypoint.invokeAll('disable') 6802 } 6803 6804 /* Public */ 6805 /* http://imakewebthings.com/waypoints/api/enable-all */ 6806 Waypoint.enableAll = function() { 6807 Waypoint.Context.refreshAll() 6808 for (var waypointKey in allWaypoints) { 6809 allWaypoints[waypointKey].enabled = true 6810 } 6811 return this 6812 } 6813 6814 /* Public */ 6815 /* http://imakewebthings.com/waypoints/api/refresh-all */ 6816 Waypoint.refreshAll = function() { 6817 Waypoint.Context.refreshAll() 6818 } 6819 6820 /* Public */ 6821 /* http://imakewebthings.com/waypoints/api/viewport-height */ 6822 Waypoint.viewportHeight = function() { 6823 return window.innerHeight || document.documentElement.clientHeight 6824 } 6825 6826 /* Public */ 6827 /* http://imakewebthings.com/waypoints/api/viewport-width */ 6828 Waypoint.viewportWidth = function() { 6829 return document.documentElement.clientWidth 6830 } 6831 6832 Waypoint.adapters = [] 6833 6834 Waypoint.defaults = { 6835 context: window, 6836 continuous: true, 6837 enabled: true, 6838 group: 'default', 6839 horizontal: false, 6840 offset: 0 6841 } 6842 6843 Waypoint.offsetAliases = { 6844 'bottom-in-view': function() { 6845 return this.context.innerHeight() - this.adapter.outerHeight() 6846 }, 6847 'right-in-view': function() { 6848 return this.context.innerWidth() - this.adapter.outerWidth() 6849 } 6850 } 6851 6852 window.Waypoint = Waypoint 6853}()) 6854;(function() { 6855 'use strict' 6856 6857 function requestAnimationFrameShim(callback) { 6858 window.setTimeout(callback, 1000 / 60) 6859 } 6860 6861 var keyCounter = 0 6862 var contexts = {} 6863 var Waypoint = window.Waypoint 6864 var oldWindowLoad = window.onload 6865 6866 /* http://imakewebthings.com/waypoints/api/context */ 6867 function Context(element) { 6868 this.element = element 6869 this.Adapter = Waypoint.Adapter 6870 this.adapter = new this.Adapter(element) 6871 this.key = 'waypoint-context-' + keyCounter 6872 this.didScroll = false 6873 this.didResize = false 6874 this.oldScroll = { 6875 x: this.adapter.scrollLeft(), 6876 y: this.adapter.scrollTop() 6877 } 6878 this.waypoints = { 6879 vertical: {}, 6880 horizontal: {} 6881 } 6882 6883 element.waypointContextKey = this.key 6884 contexts[element.waypointContextKey] = this 6885 keyCounter += 1 6886 if (!Waypoint.windowContext) { 6887 Waypoint.windowContext = true 6888 Waypoint.windowContext = new Context(window) 6889 } 6890 6891 this.createThrottledScrollHandler() 6892 this.createThrottledResizeHandler() 6893 } 6894 6895 /* Private */ 6896 Context.prototype.add = function(waypoint) { 6897 var axis = waypoint.options.horizontal ? 'horizontal' : 'vertical' 6898 this.waypoints[axis][waypoint.key] = waypoint 6899 this.refresh() 6900 } 6901 6902 /* Private */ 6903 Context.prototype.checkEmpty = function() { 6904 var horizontalEmpty = this.Adapter.isEmptyObject(this.waypoints.horizontal) 6905 var verticalEmpty = this.Adapter.isEmptyObject(this.waypoints.vertical) 6906 var isWindow = this.element == this.element.window 6907 if (horizontalEmpty && verticalEmpty && !isWindow) { 6908 this.adapter.off('.waypoints') 6909 delete contexts[this.key] 6910 } 6911 } 6912 6913 /* Private */ 6914 Context.prototype.createThrottledResizeHandler = function() { 6915 var self = this 6916 6917 function resizeHandler() { 6918 self.handleResize() 6919 self.didResize = false 6920 } 6921 6922 this.adapter.on('resize.waypoints', function() { 6923 if (!self.didResize) { 6924 self.didResize = true 6925 Waypoint.requestAnimationFrame(resizeHandler) 6926 } 6927 }) 6928 } 6929 6930 /* Private */ 6931 Context.prototype.createThrottledScrollHandler = function() { 6932 var self = this 6933 function scrollHandler() { 6934 self.handleScroll() 6935 self.didScroll = false 6936 } 6937 6938 this.adapter.on('scroll.waypoints', function() { 6939 if (!self.didScroll || Waypoint.isTouch) { 6940 self.didScroll = true 6941 Waypoint.requestAnimationFrame(scrollHandler) 6942 } 6943 }) 6944 } 6945 6946 /* Private */ 6947 Context.prototype.handleResize = function() { 6948 Waypoint.Context.refreshAll() 6949 } 6950 6951 /* Private */ 6952 Context.prototype.handleScroll = function() { 6953 var triggeredGroups = {} 6954 var axes = { 6955 horizontal: { 6956 newScroll: this.adapter.scrollLeft(), 6957 oldScroll: this.oldScroll.x, 6958 forward: 'right', 6959 backward: 'left' 6960 }, 6961 vertical: { 6962 newScroll: this.adapter.scrollTop(), 6963 oldScroll: this.oldScroll.y, 6964 forward: 'down', 6965 backward: 'up' 6966 } 6967 } 6968 6969 for (var axisKey in axes) { 6970 var axis = axes[axisKey] 6971 var isForward = axis.newScroll > axis.oldScroll 6972 var direction = isForward ? axis.forward : axis.backward 6973
6974 for (var waypointKey in this.waypoints[axisKey]) { 6975 var waypoint = this.waypoints[axisKey][waypointKey] 6976 if (waypoint.triggerPoint === null) { 6977 continue 6978 } 6979 var wasBeforeTriggerPoint = axis.oldScroll < waypoint.triggerPoint 6980 var nowAfterTriggerPoint = axis.newScroll >= waypoint.triggerPoint 6981 var crossedForward = wasBeforeTriggerPoint && nowAfterTriggerPoint 6982 var crossedBackward = !wasBeforeTriggerPoint && !nowAfterTriggerPoint 6983 if (crossedForward || crossedBackward) { 6984 waypoint.queueTrigger(direction) 6985 triggeredGroups[waypoint.group.id] = waypoint.group 6986 } 6987 } 6988 } 6989 6990 for (var groupKey in triggeredGroups) { 6991 triggeredGroups[groupKey].flushTriggers() 6992 } 6993 6994 this.oldScroll = { 6995 x: axes.horizontal.newScroll, 6996 y: axes.vertical.newScroll 6997 } 6998 } 6999 7000 /* Private */ 7001 Context.prototype.innerHeight = function() { 7002 /*eslint-disable eqeqeq */ 7003 if (this.element == this.element.window) { 7004 return Waypoint.viewportHeight() 7005 } 7006 /*eslint-enable eqeqeq */ 7007 return this.adapter.innerHeight() 7008 } 7009 7010 /* Private */ 7011 Context.prototype.remove = function(waypoint) { 7012 delete this.waypoints[waypoint.axis][waypoint.key] 7013 this.checkEmpty() 7014 } 7015 7016 /* Private */ 7017 Context.prototype.innerWidth = function() { 7018 /*eslint-disable eqeqeq */ 7019 if (this.element == this.element.window) { 7020 return Waypoint.viewportWidth() 7021 } 7022 /*eslint-enable eqeqeq */ 7023 return this.adapter.innerWidth() 7024 } 7025 7026 /* Public */ 7027 /* http://imakewebthings.com/waypoints/api/context-destroy */ 7028 Context.prototype.destroy = function() { 7029 var allWaypoints = [] 7030 for (var axis in this.waypoints) {
7031 for (var waypointKey in this.waypoints[axis]) { 7032 allWaypoints.push(this.waypoints[axis][waypointKey]) 7033 } 7034 } 7035 for (var i = 0, end = allWaypoints.length; i < end; i++) { 7036 allWaypoints[i].destroy() 7037 } 7038 } 7039 7040 /* Public */ 7041 /* http://imakewebthings.com/waypoints/api/context-refresh */ 7042 Context.prototype.refresh = function() { 7043 /*eslint-disable eqeqeq */ 7044 var isWindow = this.element == this.element.window 7045 /*eslint-enable eqeqeq */ 7046 var contextOffset = isWindow ? undefined : this.adapter.offset() 7047 var triggeredGroups = {} 7048 var axes 7049 7050 this.handleScroll() 7051 axes = { 7052 horizontal: { 7053 contextOffset: isWindow ? 0 : contextOffset.left, 7054 contextScroll: isWindow ? 0 : this.oldScroll.x, 7055 contextDimension: this.innerWidth(), 7056 oldScroll: this.oldScroll.x, 7057 forward: 'right', 7058 backward: 'left', 7059 offsetProp: 'left' 7060 }, 7061 vertical: { 7062 contextOffset: isWindow ? 0 : contextOffset.top, 7063 contextScroll: isWindow ? 0 : this.oldScroll.y, 7064 contextDimension: this.innerHeight(), 7065 oldScroll: this.oldScroll.y, 7066 forward: 'down', 7067 backward: 'up', 7068 offsetProp: 'top' 7069 } 7070 } 7071 7072 for (var axisKey in axes) { 7073 var axis = axes[axisKey]
7074 for (var waypointKey in this.waypoints[axisKey]) { 7075 var waypoint = this.waypoints[axisKey][waypointKey] 7076 var adjustment = waypoint.options.offset 7077 var oldTriggerPoint = waypoint.triggerPoint 7078 var elementOffset = 0 7079 var freshWaypoint = oldTriggerPoint == null 7080 var contextModifier, wasBeforeScroll, nowAfterScroll 7081 var triggeredBackward, triggeredForward 7082 7083 if (waypoint.element !== waypoint.element.window) { 7084 elementOffset = waypoint.adapter.offset()[axis.offsetProp] 7085 } 7086 7087 if (typeof adjustment === 'function') { 7088 adjustment = adjustment.apply(waypoint) 7089 } 7090 else if (typeof adjustment === 'string') { 7091 adjustment = parseFloat(adjustment) 7092 if (waypoint.options.offset.indexOf('%') > - 1) { 7093 adjustment = Math.ceil(axis.contextDimension * adjustment / 100) 7094 } 7095 } 7096 7097 contextModifier = axis.contextScroll - axis.contextOffset 7098 waypoint.triggerPoint = Math.floor(elementOffset + contextModifier - adjustment) 7099 wasBeforeScroll = oldTriggerPoint < axis.oldScroll 7100 nowAfterScroll = waypoint.triggerPoint >= axis.oldScroll 7101 triggeredBackward = wasBeforeScroll && nowAfterScroll 7102 triggeredForward = !wasBeforeScroll && !nowAfterScroll 7103 7104 if (!freshWaypoint && triggeredBackward) { 7105 waypoint.queueTrigger(axis.backward) 7106 triggeredGroups[waypoint.group.id] = waypoint.group 7107 } 7108 else if (!freshWaypoint && triggeredForward) { 7109 waypoint.queueTrigger(axis.forward) 7110 triggeredGroups[waypoint.group.id] = waypoint.group 7111 } 7112 else if (freshWaypoint && axis.oldScroll >= waypoint.triggerPoint) { 7113 waypoint.queueTrigger(axis.forward) 7114 triggeredGroups[waypoint.group.id] = waypoint.group 7115 } 7116 } 7117 } 7118 7119 Waypoint.requestAnimationFrame(function() { 7120 for (var groupKey in triggeredGroups) { 7121 triggeredGroups[groupKey].flushTriggers() 7122 } 7123 }) 7124 7125 return this 7126 } 7127 7128 /* Private */ 7129 Context.findOrCreateByElement = function(element) { 7130 return Context.findByElement(element) || new Context(element) 7131 } 7132 7133 /* Private */ 7134 Context.refreshAll = function() { 7135 for (var contextId in contexts) { 7136 contexts[contextId].refresh() 7137 } 7138 } 7139 7140 /* Public */ 7141 /* http://imakewebthings.com/waypoints/api/context-find-by-element */ 7142 Context.findByElement = function(element) { 7143 return contexts[element.waypointContextKey] 7144 } 7145 7146 window.onload = function() { 7147 if (oldWindowLoad) { 7148 oldWindowLoad() 7149 } 7150 Context.refreshAll() 7151 } 7152 7153 7154 Waypoint.requestAnimationFrame = function(callback) { 7155 var requestFn = window.requestAnimationFrame || 7156 window.mozRequestAnimationFrame || 7157 window.webkitRequestAnimationFrame || 7158 requestAnimationFrameShim 7159 requestFn.call(window, callback) 7160 } 7161 Waypoint.Context = Context 7162}()) 7163;(function() { 7164 'use strict' 7165 7166 function byTriggerPoint(a, b) { 7167 return a.triggerPoint - b.triggerPoint 7168 } 7169 7170 function byReverseTriggerPoint(a, b) { 7171 return b.triggerPoint - a.triggerPoint 7172 } 7173 7174 var groups = { 7175 vertical: {}, 7176 horizontal: {} 7177 } 7178 var Waypoint = window.Waypoint 7179 7180 /* http://imakewebthings.com/waypoints/api/group */ 7181 function Group(options) { 7182 this.name = options.name 7183 this.axis = options.axis 7184 this.id = this.name + '-' + this.axis 7185 this.waypoints = [] 7186 this.clearTriggerQueues() 7187 groups[this.axis][this.name] = this 7188 } 7189 7190 /* Private */ 7191 Group.prototype.add = function(waypoint) { 7192 this.waypoints.push(waypoint) 7193 } 7194 7195 /* Private */ 7196 Group.prototype.clearTriggerQueues = function() { 7197 this.triggerQueues = { 7198 up: [], 7199 down: [], 7200 left: [], 7201 right: [] 7202 } 7203 } 7204 7205 /* Private */ 7206 Group.prototype.flushTriggers = function() { 7207 for (var direction in this.triggerQueues) { 7208 var waypoints = this.triggerQueues[direction] 7209 var reverse = direction === 'up' || direction === 'left' 7210 waypoints.sort(reverse ? byReverseTriggerPoint : byTriggerPoint) 7211 for (var i = 0, end = waypoints.length; i < end; i += 1) { 7212 var waypoint = waypoints[i] 7213 if (waypoint.options.continuous || i === waypoints.length - 1) { 7214 waypoint.trigger([direction]) 7215 } 7216 } 7217 } 7218 this.clearTriggerQueues() 7219 } 7220 7221 /* Private */ 7222 Group.prototype.next = function(waypoint) { 7223 this.waypoints.sort(byTriggerPoint) 7224 var index = Waypoint.Adapter.inArray(waypoint, this.waypoints) 7225 var isLast = index === this.waypoints.length - 1 7226 return isLast ? null : this.waypoints[index + 1] 7227 } 7228 7229 /* Private */ 7230 Group.prototype.previous = function(waypoint) { 7231 this.waypoints.sort(byTriggerPoint) 7232 var index = Waypoint.Adapter.inArray(waypoint, this.waypoints) 7233 return index ? this.waypoints[index - 1] : null 7234 } 7235 7236 /* Private */ 7237 Group.prototype.queueTrigger = function(waypoint, direction) { 7238 this.triggerQueues[direction].push(waypoint) 7239 } 7240 7241 /* Private */ 7242 Group.prototype.remove = function(waypoint) { 7243 var index = Waypoint.Adapter.inArray(waypoint, this.waypoints) 7244 if (index > -1) { 7245 this.waypoints.splice(index, 1) 7246 } 7247 } 7248 7249 /* Public */ 7250 /* http://imakewebthings.com/waypoints/api/first */ 7251 Group.prototype.first = function() { 7252 return this.waypoints[0] 7253 } 7254 7255 /* Public */ 7256 /* http://imakewebthings.com/waypoints/api/last */ 7257 Group.prototype.last = function() { 7258 return this.waypoints[this.waypoints.length - 1] 7259 } 7260 7261 /* Private */ 7262 Group.findOrCreate = function(options) { 7263 return groups[options.axis][options.name] || new Group(options) 7264 } 7265 7266 Waypoint.Group = Group 7267}()) 7268;(function() { 7269 'use strict' 7270 7271 var $ = window.jQuery 7272 var Waypoint = window.Waypoint 7273 7274 function JQueryAdapter(element) { 7275 this.$element = $(element) 7276 } 7277 7278 $.each([
7279 'innerHeight', 7280 'innerWidth', 7281 'off', 7282 'offset', 7283 'on', 7284 'outerHeight', 7285 'outerWidth', 7286 'scrollLeft', 7287 'scrollTop' 7288 ], function(i, method) { 7289 JQueryAdapter.prototype[method] = function() { 7290 var args = Array.prototype.slice.call(arguments) 7291 return this.$element[method].apply(this.$element, args) 7292 } 7293 }) 7294 7295 $.each([ 7296 'extend', 7297 'inArray', 7298 'isEmptyObject' 7299 ], function(i, method) { 7300 JQueryAdapter[method] = $[method] 7301 }) 7302 7303 Waypoint.adapters.push({ 7304 name: 'jquery', 7305 Adapter: JQueryAdapter 7306 }) 7307 Waypoint.Adapter = JQueryAdapter 7308}()) 7309;(function() { 7310 'use strict' 7311 7312 var Waypoint = window.Waypoint 7313 7314 function createExtension(framework) { 7315 return function() { 7316 var waypoints = [] 7317 var overrides = arguments[0] 7318 7319 if (framework.isFunction(arguments[0])) { 7320 overrides = framework.extend({}, arguments[1]) 7321 overrides.handler = arguments[0] 7322 } 7323 7324 this.each(function() { 7325 var options = framework.extend({}, overrides, { 7326 element: this 7327 }) 7328 if (typeof options.context === 'string') { 7329 options.context = framework(this).closest(options.context)[0] 7330 } 7331 waypoints.push(new Waypoint(options)) 7332 }) 7333 7334 return waypoints 7335 } 7336 } 7337 7338 if (window.jQuery) { 7339 window.jQuery.fn.waypoint = createExtension(window.jQuery) 7340 } 7341 if (window.Zepto) { 7342 window.Zepto.fn.waypoint = createExtension(window.Zepto) 7343 } 7344}()) 7345; 7346/*! 7347Waypoints Inview Shortcut - 4.0.1 7348Copyright © 2011-2016 Caleb Troughton 7349Licensed under the MIT license. 7350https://github.com/imakewebthings/waypoints/blob/master/licenses.txt 7351*/ 7352(function() { 7353 'use strict' 7354 7355 function noop() {} 7356 7357 var Waypoint = window.Waypoint 7358 7359 /* http://imakewebthings.com/waypoints/shortcuts/inview */ 7360 function Inview(options) { 7361 this.options = Waypoint.Adapter.extend({}, Inview.defaults, options) 7362 this.axis = this.options.horizontal ? 'horizontal' : 'vertical' 7363 this.waypoints = [] 7364 this.element = this.options.element 7365 this.createWaypoints() 7366 } 7367 7368 /* Private */ 7369 Inview.prototype.createWaypoints = function() { 7370 var configs = { 7371 vertical: [{ 7372 down: 'enter', 7373 up: 'exited', 7374 offset: '100%' 7375 }, { 7376 down: 'entered', 7377 up: 'exit', 7378 offset: 'bottom-in-view' 7379 }, { 7380 down: 'exit', 7381 up: 'entered', 7382 offset: 0 7383 }, { 7384 down: 'exited', 7385 up: 'enter', 7386 offset: function() { 7387 return -this.adapter.outerHeight() 7388 } 7389 }], 7390 horizontal: [{ 7391 right: 'enter', 7392 left: 'exited', 7393 offset: '100%' 7394 }, { 7395 right: 'entered', 7396 left: 'exit', 7397 offset: 'right-in-view' 7398 }, { 7399 right: 'exit', 7400 left: 'entered', 7401 offset: 0 7402 }, { 7403 right: 'exited', 7404 left: 'enter', 7405 offset: function() { 7406 return -this.adapter.outerWidth() 7407 } 7408 }] 7409 } 7410 7411 for (var i = 0, end = configs[this.axis].length; i < end; i++) { 7412 var config = configs[this.axis][i] 7413 this.createWaypoint(config) 7414 } 7415 } 7416 7417 /* Private */ 7418 Inview.prototype.createWaypoint = function(config) { 7419 var self = this 7420 this.waypoints.push(new Waypoint({ 7421 context: this.options.context, 7422 element: this.options.element, 7423 enabled: this.options.enabled, 7424 handler: (function(config) { 7425 return function(direction) { 7426 self.options[config[direction]].call(self, direction) 7427 } 7428 }(config)), 7429 offset: config.offset, 7430 horizontal: this.options.horizontal 7431 })) 7432 } 7433 7434 /* Public */ 7435 Inview.prototype.destroy = function() { 7436 for (var i = 0, end = this.waypoints.length; i < end; i++) { 7437 this.waypoints[i].destroy() 7438 } 7439 this.waypoints = [] 7440 } 7441 7442 Inview.prototype.disable = function() { 7443 for (var i = 0, end = this.waypoints.length; i < end; i++) { 7444 this.waypoints[i].disable() 7445 } 7446 } 7447 7448 Inview.prototype.enable = function() { 7449 for (var i = 0, end = this.waypoints.length; i < end; i++) { 7450 this.waypoints[i].enable() 7451 } 7452 } 7453 7454 Inview.defaults = { 7455 context: window, 7456 enabled: true, 7457 enter: noop, 7458 entered: noop,
7459 exit: noop, 7460 exited: noop 7461 } 7462 7463 Waypoint.Inview = Inview 7464}()) 7465; 7466 7467/* 7468 * SmartMenus jQuery v0.9.6 7469 * http://www.smartmenus.org/ 7470 * 7471 * Copyright 2014 Vasil Dinkov, Vadikom Web Ltd. 7472 * http://vadikom.com/ 7473 * 7474 * Released under the MIT license: 7475 * http://www.opensource.org/licenses/MIT 7476 */ 7477 7478(function($) { 7479 7480 var menuTrees = [], 7481 IE = !!window.createPopup, // we need to detect it, unfortunately 7482 IElt9 = IE && !document.defaultView, 7483 IElt8 = IE && !document.querySelector, 7484 IE6 = IE && typeof document.documentElement.currentStyle.minWidth == 'undefined', 7485 mouse = false, // optimize for touch by default - we will detect for mouse input 7486 mouseDetectionEnabled = false; 7487 7488 // Handle detection for mouse input (i.e. desktop browsers, tablets with a mouse, etc.) 7489 function initMouseDetection(disable) { 7490 if (!mouseDetectionEnabled && !disable) { 7491 // if we get two consecutive mousemoves within 2 pixels from each other and within 300ms, we assume a real mouse/cursor is present 7492 // 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) 7493 var firstTime = true, 7494 lastMove = null; 7495 $(document).bind({ 7496 'mousemove.smartmenus_mouse': function(e) { 7497 var thisMove = { x: e.pageX, y: e.pageY, timeStamp: new Date().getTime() }; 7498 if (lastMove) { 7499 var deltaX = Math.abs(lastMove.x - thisMove.x), 7500 deltaY = Math.abs(lastMove.y - thisMove.y); 7501 if ((deltaX > 0 || deltaY > 0) && deltaX <= 2 && deltaY <= 2 && thisMove.timeStamp - lastMove.timeStamp <= 300) { 7502 mouse = true; 7503 // 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 7504 if (firstTime) { 7505 var $a = $(e.target).closest('a'); 7506 if ($a.is('a')) { 7507 $.each(menuTrees, function() { 7508 if ($.contains(this.$root[0], $a[0])) { 7509 this.itemEnter({ currentTarget: $a[0] }); 7510 return false; 7511 } 7512 }); 7513 } 7514 firstTime = false; 7515 } 7516 } 7517 } 7518 lastMove = thisMove; 7519 }, 7520 'touchstart.smartmenus_mouse pointerover.smartmenus_mouse MSPointerOver.smartmenus_mouse': function(e) { 7521 if (!/^(4|mouse)$/.test(e.originalEvent.pointerType)) { 7522 mouse = false; 7523 } 7524 } 7525 }); 7526 mouseDetectionEnabled = true; 7527 } else if (mouseDetectionEnabled && disable) { 7528 $(document).unbind('.smartmenus_mouse'); 7529 mouseDetectionEnabled = false; 7530 } 7531 }; 7532 7533 $.SmartMenus = function(elm, options) { 7534 this.$root = $(elm); 7535 this.opts = options; 7536 this.rootId = ''; // internal 7537 this.$subArrow = null; 7538 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) 7539 this.activatedItems = []; // stores last activated A's for each level 7540 this.visibleSubMenus = []; // stores visible sub menus UL's 7541 this.showTimeout = 0; 7542 this.hideTimeout = 0; 7543 this.scrollTimeout = 0; 7544 this.clickActivated = false; 7545 this.zIndexInc = 0; 7546 this.$firstLink = null; // we'll use these for some tests 7547 this.$firstSub = null; // at runtime so we'll cache them 7548 this.disabled = false; 7549 this.$disableOverlay = null; 7550 this.init(); 7551 }; 7552 7553 $.extend($.SmartMenus, { 7554 hideAll: function() { 7555 $.each(menuTrees, function() { 7556 this.menuHideAll(); 7557 }); 7558 }, 7559 destroy: function() { 7560 while (menuTrees.length) { 7561 menuTrees[0].destroy(); 7562 } 7563 initMouseDetection(true); 7564 }, 7565 prototype: { 7566 init: function(refresh) { 7567 var self = this; 7568 7569 if (!refresh) { 7570 menuTrees.push(this); 7571 7572 this.rootId = (new Date().getTime() + Math.random() + '').replace(/\D/g, ''); 7573 7574 if (this.$root.hasClass('sm-rtl')) { 7575 this.opts.rightToLeftSubMenus = true; 7576 } 7577 7578 // init root (main menu) 7579 this.$root 7580 .data('smartmenus', this) 7581 .attr('data-smartmenus-id', this.rootId) 7582 .dataSM('level', 1) 7583 .bind({ 7584 'mouseover.smartmenus focusin.smartmenus': $.proxy(this.rootOver, this),
7585 'mouseout.smartmenus focusout.smartmenus': $.proxy(this.rootOut, this) 7586 }) 7587 .delegate('a', { 7588 'mouseenter.smartmenus': $.proxy(this.itemEnter, this), 7589 'mouseleave.smartmenus': $.proxy(this.itemLeave, this), 7590 'mousedown.smartmenus': $.proxy(this.itemDown, this), 7591 'focus.smartmenus': $.proxy(this.itemFocus, this), 7592 'blur.smartmenus': $.proxy(this.itemBlur, this), 7593 'click.smartmenus': $.proxy(this.itemClick, this), 7594 'touchend.smartmenus': $.proxy(this.itemTouchEnd, this) 7595 }); 7596 7597 var eNamespace = '.smartmenus' + this.rootId; 7598 // hide menus on tap or click outside the root UL 7599 if (this.opts.hideOnClick) { 7600 $(document).bind('touchstart' + eNamespace, $.proxy(this.docTouchStart, this)) 7601 .bind('touchmove' + eNamespace, $.proxy(this.docTouchMove, this)) 7602 .bind('touchend' + eNamespace, $.proxy(this.docTouchEnd, this)) 7603 // for Opera Mobile < 11.5, webOS browser, etc. we'll check click too 7604 .bind('click' + eNamespace, $.proxy(this.docClick, this)); 7605 } 7606 // hide sub menus on resize 7607 $(window).bind('resize' + eNamespace + ' orientationchange' + eNamespace, $.proxy(this.winResize, this)); 7608 $(window).bind('scroll' + eNamespace + ' orientationchange' + eNamespace, $.proxy(this.winResize, this)); 7609 7610 if (this.opts.subIndicators) { 7611 this.$subArrow = $('<span/>').addClass('sub-arrow'); 7612 if (this.opts.subIndicatorsText) { 7613 this.$subArrow.html(this.opts.subIndicatorsText); 7614 } 7615 } 7616 7617 // make sure mouse detection is enabled 7618 initMouseDetection(); 7619 } 7620 7621 // init sub menus 7622 this.$firstSub = this.$root.find('ul').each(function() { self.menuInit($(this)); }).eq(0); 7623 7624 this.$firstLink = this.$root.find('a').eq(0); 7625 7626 // find current item 7627 if (this.opts.markCurrentItem) { 7628 var reDefaultDoc = /(index|default)\.[^#\?\/]*/i, 7629 reHash = /#.*/, 7630 locHref = window.location.href.replace(reDefaultDoc, ''), 7631 locHrefNoHash = locHref.replace(reHash, ''); 7632 this.$root.find('a').each(function() { 7633 var href = this.href.replace(reDefaultDoc, ''), 7634 $this = $(this); 7635 if (href == locHref || href == locHrefNoHash) { 7636 $this.addClass('current'); 7637 if (self.opts.markCurrentTree) { 7638 $this.parents('li').each(function() { 7639 var $this = $(this); 7640 if ($this.dataSM('sub')) { 7641 $this.children('a').addClass('current'); 7642 } 7643 }); 7644 } 7645 } 7646 }); 7647 } 7648 }, 7649 destroy: function() { 7650 this.menuHideAll(); 7651 this.$root 7652 .removeData('smartmenus') 7653 .removeAttr('data-smartmenus-id') 7654 .removeDataSM('level') 7655 .unbind('.smartmenus') 7656 .undelegate('.smartmenus'); 7657 var eNamespace = '.smartmenus' + this.rootId; 7658 $(document).unbind(eNamespace); 7659 $(window).unbind(eNamespace); 7660 if (this.opts.subIndicators) { 7661 this.$subArrow = null; 7662 } 7663 var self = this; 7664 $.each(this.subMenus, function() { 7665 if (this.hasClass('mega-menu')) { 7666 this.find('ul').removeDataSM('in-mega'); 7667 } 7668 if (this.dataSM('shown-before')) { 7669 if (IElt8) { 7670 this.children().css({ styleFloat: '', width: '' }); 7671 } 7672 if (self.opts.subMenusMinWidth || self.opts.subMenusMaxWidth) { 7673 if (!IE6) { 7674 this.css({ width: '', minWidth: '', maxWidth: '' }).removeClass('sm-nowrap'); 7675 } else { 7676 this.css({ width: '', overflowX: '', overflowY: '' }).children().children('a').css('white-space', ''); 7677 } 7678 } 7679 if (this.dataSM('scroll-arrows')) { 7680 this.dataSM('scroll-arrows').remove(); 7681 } 7682 this.css({ zIndex: '', top: '', left: '', marginLeft: '', marginTop: '', display: '' }); 7683 } 7684 if (self.opts.subIndicators) { 7685 this.dataSM('parent-a').removeClass('has-submenu').children('span.sub-arrow').remove(); 7686 } 7687 this.removeDataSM('shown-before') 7688 .removeDataSM('ie-shim') 7689 .removeDataSM('scroll-arrows') 7690 .removeDataSM('parent-a') 7691 .removeDataSM('level') 7692 .removeDataSM('beforefirstshowfired') 7693 .parent().removeDataSM('sub'); 7694 }); 7695 if (this.opts.markCurrentItem) { 7696 this.$root.find('a.current').removeClass('current'); 7697 } 7698 this.$root = null; 7699 this.$firstLink = null; 7700 this.$firstSub = null; 7701 if (this.$disableOverlay) { 7702 this.$disableOverlay.remove(); 7703 this.$disableOverlay = null; 7704 } 7705 menuTrees.splice($.inArray(this, menuTrees), 1); 7706 }, 7707 disable: function(noOverlay) { 7708 if (!this.disabled) { 7709 this.menuHideAll(); 7710 // display overlay over the menu to prevent interaction 7711 if (!noOverlay && !this.opts.isPopup && this.$root.is(':visible')) { 7712 var pos = this.$root.offset(); 7713 this.$disableOverlay = $('<div class="sm-jquery-disable-overlay"/>').css({ 7714 position: 'absolute', 7715 top: pos.top, 7716 left: pos.left, 7717 width: this.$root.outerWidth(), 7718 height: this.$root.outerHeight(),
7719 zIndex: this.getStartZIndex() + 1, 7720 opacity: 0 7721 }).appendTo(document.body); 7722 } 7723 this.disabled = true; 7724 } 7725 }, 7726 docClick: function(e) { 7727 // hide on any click outside the menu or on a menu link 7728 if (this.visibleSubMenus.length && !$.contains(this.$root[0], e.target) || $(e.target).is('a')) { 7729 this.menuHideAll($(e.target)); 7730 } 7731 }, 7732 docTouchEnd: function(e) { 7733 if (!this.lastTouch) { 7734 return; 7735 } 7736 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))) { 7737 if (this.hideTimeout) { 7738 clearTimeout(this.hideTimeout); 7739 this.hideTimeout = 0; 7740 } 7741 // hide with a delay to prevent triggering accidental unwanted click on some page element 7742 var self = this; 7743 this.hideTimeout = setTimeout(function() { self.menuHideAll($(e.target)); }, 350); 7744 } 7745 this.lastTouch = null; 7746 }, 7747 docTouchMove: function(e) { 7748 if (!this.lastTouch) { 7749 return; 7750 } 7751 var touchPoint = e.originalEvent.touches[0]; 7752 this.lastTouch.x2 = touchPoint.pageX; 7753 this.lastTouch.y2 = touchPoint.pageY; 7754 }, 7755 docTouchStart: function(e) { 7756 var touchPoint = e.originalEvent.touches[0]; 7757 this.lastTouch = { x1: touchPoint.pageX, y1: touchPoint.pageY, target: touchPoint.target }; 7758 }, 7759 enable: function() { 7760 if (this.disabled) { 7761 if (this.$disableOverlay) { 7762 this.$disableOverlay.remove(); 7763 this.$disableOverlay = null; 7764 } 7765 this.disabled = false; 7766 } 7767 }, 7768 getHeight: function($elm) { 7769 return this.getOffset($elm, true); 7770 }, 7771 // returns precise width/height float values in IE9+, FF4+, recent WebKit 7772 // http://vadikom.com/dailies/offsetwidth-offsetheight-useless-in-ie9-firefox4/ 7773 getOffset: function($elm, height) { 7774 var old; 7775 if ($elm.css('display') == 'none') { 7776 old = { position: $elm[0].style.position, visibility: $elm[0].style.visibility }; 7777 $elm.css({ position: 'absolute', visibility: 'hidden' }).show(); 7778 } 7779 var defaultView = $elm[0].ownerDocument.defaultView, 7780 compStyle = defaultView && defaultView.getComputedStyle && defaultView.getComputedStyle($elm[0], null), 7781 val = compStyle && parseFloat(compStyle[height ? 'height' : 'width']); 7782 if (val) { 7783 val += parseFloat(compStyle[height ? 'paddingTop' : 'paddingLeft']) 7784 + parseFloat(compStyle[height ? 'paddingBottom' : 'paddingRight']) 7785 + parseInt(compStyle[height ? 'borderTopWidth' : 'borderLeftWidth']) 7786 + parseInt(compStyle[height ? 'borderBottomWidth' : 'borderRightWidth']); 7787 } else { 7788 val = height ? $elm[0].offsetHeight : $elm[0].offsetWidth; 7789 } 7790 if (old) { 7791 $elm.hide().css(old); 7792 } 7793 return val; 7794 }, 7795 getWidth: function($elm) { 7796 return this.getOffset($elm); 7797 }, 7798 getStartZIndex: function() { 7799 var zIndex = parseInt(this.$root.css('z-index')); 7800 return !isNaN(zIndex) ? zIndex : 1; 7801 }, 7802 handleEvents: function() { 7803 return !this.disabled && this.isCSSOn(); 7804 }, 7805 handleItemEvents: function($a) { 7806 return this.handleEvents() && !this.isLinkInMegaMenu($a); 7807 }, 7808 isCollapsible: function() { 7809 return this.$firstSub.css('position') == 'static'; 7810 }, 7811 isCSSOn: function() { 7812 return this.$firstLink.css('display') == 'block' || this.$firstLink.css('display') == 'inline'; 7813 }, 7814 isFixed: function() { 7815 return this.$root.css('position') == 'fixed'; 7816 }, 7817 isLinkInMegaMenu: function($a) { 7818 return !$a.parent().parent().dataSM('level'); 7819 }, 7820 isTouchMode: function() { 7821 return !mouse || this.isCollapsible(); 7822 }, 7823 itemActivate: function($a) { 7824 var $li = $a.parent(), 7825 $ul = $li.parent(), 7826 level = $ul.dataSM('level'); 7827 // 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 7828 if (level > 1 && (!this.activatedItems[level - 2] || this.activatedItems[level - 2][0] != $ul.dataSM('parent-a')[0])) { 7829 var self = this; 7830 $($ul.parentsUntil('[data-smartmenus-id]', 'ul').get().reverse()).add($ul).each(function() { 7831 self.itemActivate($(this).dataSM('parent-a')); 7832 }); 7833 } 7834 // hide any visible deeper level sub menus 7835 if (this.visibleSubMenus.length > level) { 7836 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--) { 7837 this.menuHide(this.visibleSubMenus[i]); 7838 } 7839 } 7840 // save new active item and sub menu for this level 7841 this.activatedItems[level - 1] = $a; 7842 this.visibleSubMenus[level - 1] = $ul; 7843 if (this.$root.triggerHandler('activate.smapi', $a[0]) === false) { 7844 return; 7845 } 7846 // show the sub menu if this item has one 7847 var $sub = $li.dataSM('sub'); 7848 if ($sub && (this.isTouchMode() || (!this.opts.showOnClick || this.clickActivated))) { 7849 this.menuShow($sub); 7850 } 7851 }, 7852 itemBlur: function(e) { 7853 var $a = $(e.currentTarget); 7854 if (!this.handleItemEvents($a)) { 7855 return; 7856 } 7857 this.$root.triggerHandler('blur.smapi', $a[0]); 7858 }, 7859 itemClick: function(e) { 7860 var $a = $(e.currentTarget); 7861 7862 if (!this.handleItemEvents($a)) { 7863 return; 7864 } 7865 $a.removeDataSM('mousedown'); 7866 if (this.$root.triggerHandler('click.smapi', $a[0]) === false) { 7867 return false;
7868 } 7869 var $sub = $a.parent().dataSM('sub'); 7870 if (this.isTouchMode()) { 7871 // undo fix: prevent the address bar on iPhone from sliding down when expanding a sub menu 7872 if ($a.dataSM('href')) { 7873 $a.attr('href', $a.dataSM('href')).removeDataSM('href'); 7874 } 7875 // if the sub is not visible 7876 if ($sub && (!$sub.dataSM('shown-before') || !$sub.is(':visible'))) { 7877 // try to activate the item and show the sub 7878 this.itemActivate($a); 7879 // if "itemActivate" showed the sub, prevent the click so that the link is not loaded 7880 // 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 7881 if ($sub.is(':visible')) { 7882 return false; 7883 } 7884 } 7885 } else if (this.opts.showOnClick && $a.parent().parent().dataSM('level') == 1 && $sub) { 7886 this.clickActivated = true; 7887 this.menuShow($sub); 7888 return false; 7889 } 7890 if ($a.hasClass('disabled')) { 7891 return false; 7892 } 7893 if (this.$root.triggerHandler('select.smapi', $a[0]) === false) { 7894 return false; 7895 } 7896 }, 7897 itemDown: function(e) { 7898 var $a = $(e.currentTarget); 7899 if (!this.handleItemEvents($a)) { 7900 return; 7901 } 7902 $a.dataSM('mousedown', true); 7903 }, 7904 itemEnter: function(e) { 7905 var $a = $(e.currentTarget); 7906 if (!this.handleItemEvents($a)) { 7907 return; 7908 } 7909 if (!this.isTouchMode()) { 7910 if (this.showTimeout) { 7911 clearTimeout(this.showTimeout); 7912 this.showTimeout = 0; 7913 } 7914 var self = this; 7915 this.showTimeout = setTimeout(function() { self.itemActivate($a); }, this.opts.showOnClick && $a.parent().parent().dataSM('level') == 1 ? 1 : this.opts.showTimeout); 7916 } 7917 this.$root.triggerHandler('mouseenter.smapi', $a[0]); 7918 }, 7919 itemFocus: function(e) { 7920 var $a = $(e.currentTarget); 7921 if (!this.handleItemEvents($a)) { 7922 return; 7923 } 7924 // 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 7925 if ((!this.isTouchMode() || !$a.dataSM('mousedown')) && (!this.activatedItems.length || this.activatedItems[this.activatedItems.length - 1][0] != $a[0])) { 7926 this.itemActivate($a); 7927 } 7928 this.$root.triggerHandler('focus.smapi', $a[0]); 7929 }, 7930 itemLeave: function(e) { 7931 var $a = $(e.currentTarget); 7932 if (!this.handleItemEvents($a)) { 7933 return; 7934 } 7935 if (!this.isTouchMode()) { 7936 if ($a[0].blur) { 7937 $a[0].blur(); 7938 } 7939 if (this.showTimeout) { 7940 clearTimeout(this.showTimeout); 7941 this.showTimeout = 0; 7942 } 7943 } 7944 $a.removeDataSM('mousedown'); 7945 this.$root.triggerHandler('mouseleave.smapi', $a[0]); 7946 }, 7947 itemTouchEnd: function(e) { 7948 var $a = $(e.currentTarget); 7949 if (!this.handleItemEvents($a)) { 7950 return; 7951 } 7952 // prevent the address bar on iPhone from sliding down when expanding a sub menu 7953 var $sub = $a.parent().dataSM('sub'); 7954 if ($a.attr('href').charAt(0) !== '#' && $sub && (!$sub.dataSM('shown-before') || !$sub.is(':visible'))) { 7955 $a.dataSM('href', $a.attr('href')); 7956 $a.attr('href', '#'); 7957 } 7958 }, 7959 menuFixLayout: function($ul) { 7960 // fixes a menu that is being shown for the first time 7961 if (!$ul.dataSM('shown-before')) { 7962 $ul.hide().dataSM('shown-before', true); 7963 // fix the layout of the items in IE<8 7964 if (IElt8) { 7965 $ul.children().css({ styleFloat: 'left', width: '100%' }); 7966 } 7967 } 7968 }, 7969 menuHide: function($sub) { 7970 if (this.$root.triggerHandler('beforehide.smapi', $sub[0]) === false) { 7971 return; 7972 } 7973 $sub.stop(true, true); 7974 if ($sub.is(':visible')) { 7975 var complete = function() { 7976 // unset z-index 7977 if (IElt9) { 7978 $sub.parent().css('z-index', ''); 7979 } else { 7980 $sub.css('z-index', ''); 7981 } 7982 }; 7983 // if sub is collapsible (mobile view) 7984 if (this.isCollapsible()) { 7985 if (this.opts.collapsibleHideFunction) { 7986 this.opts.collapsibleHideFunction.call(this, $sub, complete); 7987 } else { 7988 $sub.hide(this.opts.collapsibleHideDuration, complete); 7989 } 7990 } else { 7991 if (this.opts.hideFunction) { 7992 this.opts.hideFunction.call(this, $sub, complete); 7993 } else { 7994 $sub.hide(this.opts.hideDuration, complete); 7995 } 7996 } 7997 // remove IE iframe shim 7998 if ($sub.dataSM('ie-shim')) { 7999 $sub.dataSM('ie-shim').remove(); 8000 } 8001 // deactivate scrolling if it is activated for this sub 8002 if ($sub.dataSM('scroll')) { 8003 $sub.unbind('.smartmenus_scroll').removeDataSM('scroll').dataSM('scroll-arrows').hide(); 8004 } 8005 // unhighlight parent item 8006 $sub.dataSM('parent-a').removeClass('highlighted'); 8007 var level = $sub.dataSM('level'); 8008 this.activatedItems.splice(level - 1, 1); 8009 this.visibleSubMenus.splice(level - 1, 1); 8010 this.$root.triggerHandler('hide.smapi', $sub[0]); 8011 } 8012 }, 8013 menuHideAll: function($item) { 8014 if ($item != undefined && $item.parent().hasClass('menu-item') && !$item.parent().hasClass('menu-item-has-children')) return; 8015 if ( $('body').hasClass('vmenu') ) return; 8016 if (this.showTimeout) { 8017 clearTimeout(this.showTimeout); 8018 this.showTimeout = 0; 8019 } 8020 // hide all subs 8021 for (var i = this.visibleSubMenus.length - 1; i > 0; i--) { 8022 this.menuHide(this.visibleSubMenus[i]); 8023 } 8024 // hide root if it's popup 8025 if (this.opts.isPopup) { 8026 this.$root.stop(true, true); 8027 if (this.$root.is(':visible')) { 8028 if (this.opts.hideFunction) { 8029 this.opts.hideFunction.call(this, this.$root); 8030 } else { 8031 this.$root.hide(this.opts.hideDuration); 8032 } 8033 // remove IE iframe shim 8034 if (this.$root.dataSM('ie-shim')) { 8035 this.$root.dataSM('ie-shim').remove(); 8036 } 8037 } 8038 } 8039 this.activatedItems = []; 8040 this.visibleSubMenus = []; 8041 this.clickActivated = false;
8042 // reset z-index increment 8043 this.zIndexInc = 0; 8044 }, 8045 menuIframeShim: function($ul) { 8046 // create iframe shim for the menu 8047 if (IE && this.opts.overlapControlsInIE && !$ul.dataSM('ie-shim')) { 8048 $ul.dataSM('ie-shim', $('<iframe/>').attr({ src: 'javascript:0', tabindex: -9 }) 8049 .css({ position: 'absolute', top: 'auto', left: '0', opacity: 0, border: '0' }) 8050 ); 8051 } 8052 }, 8053 menuInit: function($ul) { 8054 if (!$ul.dataSM('in-mega')) { 8055 this.subMenus.push($ul); 8056 // mark UL's in mega drop downs (if any) so we can neglect them 8057 if ($ul.hasClass('mega-menu')) { 8058 $ul.find('ul').dataSM('in-mega', true); 8059 } 8060 // get level (much faster than, for example, using parentsUntil) 8061 var level = 2, 8062 par = $ul[0]; 8063 while ((par = par.parentNode.parentNode) != this.$root[0]) { 8064 level++; 8065 } 8066 // cache stuff 8067 $ul.dataSM('parent-a', $ul.prevAll('a').eq(-1)) 8068 .dataSM('level', level) 8069 .parent().dataSM('sub', $ul); 8070 // add sub indicator to parent item 8071 if (this.opts.subIndicators) { 8072 $ul.dataSM('parent-a').addClass('has-submenu')[this.opts.subIndicatorsPos](this.$subArrow.clone()); 8073 } 8074 } 8075 }, 8076 menuPosition: function($sub) { 8077 var fixIE = $('html.ie').length; 8078 // if (fixIE) { 8079 // var $rowParent = $($sub).closest('.main-menu-container'); 8080 // $rowParent.height($rowParent.height()); 8081 // } 8082 var $a = $sub.dataSM('parent-a'), 8083 $li = $sub.parent(), 8084 $ul = $sub.parent().parent(), 8085 $container = $ul.closest('.row-menu-inner'), 8086 level = $sub.dataSM('level'), 8087 subW = this.getWidth($sub), 8088 subH = this.getHeight($sub), 8089 itemOffset = $a.offset(), 8090 itemX = itemOffset.left, 8091 itemY = itemOffset.top, 8092 itemW = this.getWidth($a), 8093 itemH = this.getHeight($a), 8094 $win = $(window), 8095 winX = $win.scrollLeft(), 8096 winY = $win.scrollTop(), 8097 winW = $win.width(), 8098 winH = $win.height(), 8099 containerW = $container.width(), 8100 containerOffsetX = containerW + ((winW - containerW) / 2), 8101 horizontalParent = $ul.hasClass('sm') && !$ul.hasClass('sm-vertical'), 8102 subOffsetX = level == 2 ? this.opts.mainMenuSubOffsetX : this.opts.subMenusSubOffsetX, 8103 subOffsetY = level == 2 ? this.opts.mainMenuSubOffsetY : this.opts.subMenusSubOffsetY, 8104 x, y, leftPos; 8105 if (horizontalParent) { 8106 x = this.opts.rightToLeftSubMenus ? itemW - subW - subOffsetX : subOffsetX; 8107 y = this.opts.bottomToTopSubMenus ? -subH - subOffsetY : itemH + subOffsetY; 8108 } else { 8109 x = this.opts.rightToLeftSubMenus ? subOffsetX - subW : itemW - subOffsetX; 8110 y = this.opts.bottomToTopSubMenus ? itemH - subOffsetY - subH : subOffsetY; 8111 } 8112 if (this.opts.keepInViewport && !this.isCollapsible()) { 8113 if (this.isFixed()) { 8114 itemX -= winX; 8115 itemY -= winY; 8116 winX = winY = 0; 8117 } 8118 var absX = itemX + x, 8119 absY = itemY + y; 8120 if (this.opts.rightToLeftSubMenus && absX < winX) { 8121 x = horizontalParent ? winX - absX + x : itemW - subOffsetX; 8122 } else if (!this.opts.rightToLeftSubMenus && absX + subW > winX + containerOffsetX ) { 8123 x = horizontalParent ? winX + containerOffsetX - subW - absX + x : subOffsetX - subW; 8124 } 8125 if (!horizontalParent) { 8126 if (subH < winH && absY + subH > winY + winH) { 8127 y += winY + winH - subH - absY; 8128 } else if (subH >= winH || absY < winY) { 8129 y += winY - absY; 8130 } 8131 } 8132 // do we need scrolling? 8133 // 0.49 added for the sake of IE9/FF4+ where we might be dealing with float numbers for "subH" 8134 if (mouse && (horizontalParent && (absY + subH > winY + winH + 0.49 || absY < winY) || !horizontalParent && subH > winH + 0.49)) { 8135 var self = this; 8136 if (!$sub.dataSM('scroll-arrows')) { 8137 $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]]) 8138 .bind({ 8139 mouseenter: function() { self.menuScroll($sub, $(this).hasClass('scroll-up')); }, 8140 mouseleave: function(e) { 8141 self.menuScrollStop($sub); 8142 self.menuScrollOut($sub, e); 8143 }, 8144 'mousewheel DOMMouseScroll': function(e) { e.preventDefault(); } 8145 }) 8146 .insertAfter($sub) 8147 ); 8148 } 8149 // bind events to show/hide arrows on hover and save scrolling data for this sub 8150 var vportY = winY - (itemY + itemH); 8151 $sub.dataSM('scroll', { 8152 vportY: vportY, 8153 subH: subH, 8154 winH: winH, 8155 step: 1 8156 }) 8157 .bind({ 8158 'mouseover.smartmenus_scroll': function(e) { self.menuScrollOver($sub, e); }, 8159 'mouseout.smartmenus_scroll': function(e) { self.menuScrollOut($sub, e); }, 8160 'mousewheel.smartmenus_scroll DOMMouseScroll.smartmenus_scroll': function(e) { self.menuScrollMousewheel($sub, e); } 8161 }) 8162 .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
8162StartZIndex() + this.zIndexInc }) 8163 .eq(0).css('margin-top', vportY).end() 8164 .eq(1).css('margin-top', vportY + winH - this.getHeight($sub.dataSM('scroll-arrows').eq(1))).end() 8165 .eq(horizontalParent && this.opts.bottomToTopSubMenus ? 0 : 1).show(); 8166 } 8167 } 8168 // if ($sub.hasClass('mega-menu-inner')) { 8169 // if ($('.menu-wrapper .megamenu-diff').length > 0) { 8170 // leftPos = parseFloat($('.menu-wrapper .megamenu-diff').outerWidth()); 8171 // leftPos = -leftPos; 8172 // } else leftPos = parseFloat($('.menu-wrapper .main-menu-container').css('paddingLeft')); 8173 8174 // if ($('body.header-full-width').length > 0) { 8175 // $sub.css({ width: $('.box-container').width()}); 8176 // leftPos = (leftPos - parseFloat($('.menu-wrapper .row-menu-inner').css('paddingLeft'))); 8177 // } else $sub.css({ width: containerW}); 8178 // leftPos = leftPos + 'px'; 8179 8180 // } else { 8181 // leftPos = $li.position().left + 'px'; 8182 // } 8183 if ($sub.hasClass('mega-menu-inner')) { 8184 $sub.css({ width: containerW}); 8185 if ( $('body.hmenu-center-double').length ) { 8186 leftPos = '0px'; 8187 } else { 8188 if ( $('body.hmenu-center-split').length > 0 && !$sub.closest('.navbar-cta').length && ! $('body.hormenu-position-right').length ) { 8189 leftPos = - ($sub.closest('.menu-primary-inner')[0].offsetLeft) + 'px'; 8190 } else { 8191 if ( $sub.closest('.navbar-cta').length && !$('body.hmenu').length && !$('body.hmenu-center').length ) { 8192 leftPos = - ( parseFloat($sub.closest('.navbar-cta').offset().left) - parseFloat($sub.closest('.row-menu-inner').find('.logo-container').offset().left) ) + 'px'; 8193 } else if ($sub.closest('.row-menu-inner').find('.logo-container').length > 0 && !$('body.hmenu-center-split').length) { 8194 leftPos = - (parseFloat($sub.closest('.row-menu-inner').find('.logo-container').css('paddingRight')) + ($sub.closest('.row-menu-inner').find('.logo-container').width())) + 'px'; 8195 } else { 8196 leftPos = '0px'; 8197 } 8198 } 8199 } 8200 } else { 8201 leftPos = (level > 2 ? $li.position().left - parseFloat($li.closest('ul').css('paddingLeft')) : $li.position().left ) + 'px'; 8202 x = (level > 2 && x >= 0) ? x + (parseFloat($li.closest('ul').css('paddingLeft')) * 2) + 1 : x - 1; 8203 } 8204 8205 $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) }); 8206 // IE iframe shim 8207 this.menuIframeShim($sub); 8208 if ($sub.dataSM('ie-shim')) { 8209 $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) }); 8210 } 8211 }, 8212 menuScroll: function($sub, up, wheel) { 8213 var y = parseFloat($sub.css('margin-top')), 8214 scroll = $sub.dataSM('scroll'), 8215 end = scroll.vportY + (up ? 0 : scroll.winH - scroll.subH), 8216 step = wheel || !this.opts.scrollAccelerate ? this.opts.scrollStep : Math.floor($sub.dataSM('scroll').step); 8217 $sub.add($sub.dataSM('ie-shim')).css('margin-top', Math.abs(end - y) > step ? y + (up ? step : -step) : end); 8218 y = parseFloat($sub.css('margin-top')); 8219 // show opposite arrow if appropriate 8220 if (up && y + scroll.subH > scroll.vportY + scroll.winH || !up && y < scroll.vportY) { 8221 $sub.dataSM('scroll-arrows').eq(up ? 1 : 0).show(); 8222 } 8223 // accelerate when not using mousewheel to scroll 8224 if (!wheel && this.opts.scrollAccelerate && $sub.dataSM('scroll').step < this.opts.scrollStep) { 8225 $sub.dataSM('scroll').step += 0.5; 8226 } 8227 // "y" and "end" might be float numbers in IE9/FF4+ so this weird way to check is used 8228 if (Math.abs(y - end) < 1) { 8229 $sub.dataSM('scroll-arrows').eq(up ? 0 : 1).hide(); 8230 $sub.dataSM('scroll').step = 1; 8231 } else if (!wheel) { 8232 var self = this; 8233 this.scrollTimeout = setTimeout(function() { self.menuScroll($sub, up); }, this.opts.scrollInterval); 8234 } 8235 }, 8236 menuScrollMousewheel: function($sub, e) { 8237 var $closestSub = $(e.target).closest('ul'); 8238 while ($closestSub.dataSM('in-mega')) { 8239 $closestSub = $closestSub.parent().closest('ul'); 8240 } 8241 if ($closestSub[0] == $sub[0]) { 8242 var up = (e.originalEvent.wheelDelta || -e.originalEvent.detail) > 0; 8243 if ($sub.dataSM('scroll-arrows').eq(up ? 0 : 1).is(':visible')) { 8244 this.menuScroll($sub, up, true); 8245 } 8246 } 8247 e.preventDefault(); 8248 }, 8249 menuScrollOut: function($sub, e) { 8250 var reClass = /^scroll-(up|down)/, 8251 $closestSub = $(e.relatedTarget).closest('ul'); 8252 while ($closestSub.dataSM('in-mega')) { 8253 $closestSub = $closestSub.parent().closest('ul'); 8254 } 8255 if (!reClass.test((e.relatedTarget || '').className) && ($sub[0] != e.relatedTarget && !$.contains($sub[0], e.relatedTarget) || $closestSub[0] != $sub[0])) { 8256 $sub.dataSM('scroll-arrows').css('visibility', 'hidden'); 8257 } 8258 }, 8259 menuScrollOver: function($sub, e) { 8260 var reClass = /^scroll-(up|down)/, 8261 $closestSub = $(e.target).closest('ul'); 8262 while ($closestSub.dataSM('in-mega')) { 8263 $closestSub = $closestSub.parent().closest('ul'); 8264 } 8265 if (!reClass.test(e.target.className) && $closestSub[0] == $sub[0]) { 8266 $sub.dataSM('scroll-arrows').css('visibility', 'visible'); 8267 } 8268 }, 8269 menuScrollStop: function($sub) { 8270 if (this.scrollTimeout) { 8271 clearTimeout(this.scrollTimeout); 8272 this.scrollTimeout = 0; 8273 $sub.dataSM('scroll').step = 1; 8274 } 8275 }, 8276 menuShow: function($sub) { 8277 if (!$sub.dataSM('beforefirstshowfired')) { 8278 $sub.dataSM('beforefirstshowfired', true); 8279 if (this.$root.triggerHandler('beforefirstshow.smapi', $sub[0]) === false) { 8280 return; 8281 } 8282 } 8283 if (this.$root.triggerHandler('beforeshow.smapi', $sub[0]) === false) { 8284 return; 8285 } 8286 this.menuFixLayout($sub); 8287 $sub.stop(true, true); 8288 if (!$sub.is(':visible')) { 8289 // set z-index - for IE < 9 set it to the parent LI
8290 var zIndex = this.getStartZIndex() + (++this.zIndexInc); 8291 if (IElt9) { 8292 $sub.parent().css('z-index', zIndex); 8293 } else { 8294 $sub.css('z-index', zIndex); 8295 } 8296 // highlight parent item 8297 if (this.opts.keepHighlighted || this.isCollapsible()) { 8298 if ($sub.dataSM('parent-a').attr('data-type') != 'title') 8299 $sub.dataSM('parent-a').addClass('highlighted'); 8300 } 8301 // min/max-width fix - no way to rely purely on CSS as all UL's are nested 8302 if (this.opts.subMenusMinWidth || this.opts.subMenusMaxWidth) { 8303 if (!IElt8) { 8304 $sub.css({ width: ($sub.hasClass('mega-menu-inner')) ? $('.box-container').outerWidth() + 'px' : 'auto', minWidth: '', maxWidth: '' }).addClass('sm-nowrap'); 8305 if (this.opts.subMenusMinWidth) { 8306 $sub.css('min-width', this.opts.subMenusMinWidth); 8307 } 8308 if (this.opts.subMenusMaxWidth) { 8309 var noMaxWidth = this.getWidth($sub); 8310 $sub.css('max-width', this.opts.subMenusMaxWidth); 8311 if (noMaxWidth > this.getWidth($sub)) { 8312 $sub.removeClass('sm-nowrap').css('width', this.opts.subMenusMaxWidth); 8313 } 8314 } 8315 // IE6,7 8316 } else { 8317 $sub.children().css('styleFloat', 'none'); 8318 if (IE6) { 8319 $sub.width(this.opts.subMenusMinWidth ? this.opts.subMenusMinWidth : 1) 8320 .children().children('a').css('white-space', 'nowrap'); 8321 } else { // IE7 8322 $sub.css({ width: ($sub.hasClass('mega-menu-inner')) ? $('.box-container').outerWidth() + 'px' : 'auto', minWidth: '', maxWidth: '' }).addClass('sm-nowrap'); 8323 if (this.opts.subMenusMinWidth) { 8324 $sub.css('min-width', this.opts.subMenusMinWidth); 8325 } 8326 } 8327 if (this.opts.subMenusMaxWidth) { 8328 var noMaxWidth = $sub.width(); 8329 if (IE6) { 8330 var maxWidth = $sub.css({ width: this.opts.subMenusMaxWidth, overflowX: 'hidden', overflowY: 'hidden' }).width(); 8331 if (noMaxWidth > maxWidth) { 8332 $sub.css({ width: maxWidth, overflowX: 'visible', overflowY: 'visible' }).children().children('a').css('white-space', ''); 8333 } else { 8334 $sub.css({ width: noMaxWidth, overflowX: 'visible', overflowY: 'visible' }); 8335 } 8336 } else { // IE7 8337 $sub.css('max-width', this.opts.subMenusMaxWidth); 8338 if (noMaxWidth > $sub.width()) { 8339 $sub.removeClass('sm-nowrap').css('width', this.opts.subMenusMaxWidth); 8340 } else { 8341 $sub.width(noMaxWidth); 8342 } 8343 } 8344 } else { 8345 $sub.width($sub.width()); 8346 } 8347 $sub.children().css('styleFloat', 'left'); 8348 } 8349 } 8350 this.menuPosition($sub); 8351 // insert IE iframe shim 8352 if ($sub.dataSM('ie-shim')) { 8353 $sub.dataSM('ie-shim').insertBefore($sub); 8354 } 8355 var complete = function() { 8356 // fix: "overflow: hidden;" is not reset on animation complete in jQuery < 1.9.0 in Chrome when global "box-sizing: border-box;" is used 8357 $sub.css('overflow', ''); 8358 }; 8359 // if sub is collapsible (mobile view) 8360 if (this.isCollapsible()) { 8361 if (this.opts.collapsibleShowFunction) { 8362 this.opts.collapsibleShowFunction.call(this, $sub, complete); 8363 } else { 8364 $sub.show(this.opts.collapsibleShowDuration, complete); 8365 } 8366 } else { 8367 if (this.opts.showFunction) { 8368 this.opts.showFunction.call(this, $sub, complete); 8369 } else { 8370 $sub.show(this.opts.showDuration, complete); 8371 } 8372 } 8373 // save new sub menu for this level 8374 this.visibleSubMenus[$sub.dataSM('level') - 1] = $sub; 8375 this.$root.triggerHandler('show.smapi', $sub[0]); 8376 } 8377 }, 8378 popupHide: function(noHideTimeout) { 8379 if (this.hideTimeout) { 8380 clearTimeout(this.hideTimeout); 8381 this.hideTimeout = 0; 8382 } 8383 var self = this; 8384 this.hideTimeout = setTimeout(function() { 8385 self.menuHideAll(); 8386 }, noHideTimeout ? 1 : this.opts.hideTimeout); 8387 }, 8388 popupShow: function(left, top) { 8389 if (!this.opts.isPopup) { 8390 alert('SmartMenus jQuery Error:\n\nIf you want to show this menu via the "popupShow" method, set the isPopup:true option.'); 8391 return; 8392 } 8393 if (this.hideTimeout) { 8394 clearTimeout(this.hideTimeout); 8395 this.hideTimeout = 0; 8396 } 8397 this.menuFixLayout(this.$root); 8398 this.$root.stop(true, true); 8399 if (!this.$root.is(':visible')) { 8400 this.$root.css({ left: left, top: top }); 8401 // IE iframe shim 8402 this.menuIframeShim(this.$root); 8403 if (this.$root.dataSM('ie-shim')) { 8404 this.$root.dataSM('ie-shim').css({ zIndex: this.$root.css('z-index'), width: this.getWidth(this.$root), height: this.getHeight(this.$root), left
8404: left, top: top }).insertBefore(this.$root); 8405 } 8406 // show menu 8407 if (this.opts.showFunction) { 8408 this.opts.showFunction.call(this, this.$root); 8409 } else { 8410 this.$root.show(this.opts.showDuration); 8411 } 8412 this.visibleSubMenus[0] = this.$root; 8413 } 8414 }, 8415 refresh: function() { 8416 this.menuHideAll(); 8417 this.$root.find('ul').each(function() { 8418 var $this = $(this); 8419 if ($this.dataSM('scroll-arrows')) { 8420 $this.dataSM('scroll-arrows').remove(); 8421 } 8422 }) 8423 .removeDataSM('in-mega') 8424 .removeDataSM('shown-before') 8425 .removeDataSM('ie-shim') 8426 .removeDataSM('scroll-arrows') 8427 .removeDataSM('parent-a') 8428 .removeDataSM('level') 8429 .removeDataSM('beforefirstshowfired'); 8430 this.$root.find('a.has-submenu').removeClass('has-submenu') 8431 .parent().removeDataSM('sub'); 8432 if (this.opts.subIndicators) { 8433 this.$root.find('span.sub-arrow').remove(); 8434 } 8435 if (this.opts.markCurrentItem) { 8436 this.$root.find('a.current').removeClass('current'); 8437 } 8438 this.subMenus = []; 8439 this.init(true); 8440 }, 8441 rootOut: function(e) { 8442 if (!this.handleEvents() || this.isTouchMode() || e.target == this.$root[0]) { 8443 return; 8444 } 8445 if (this.hideTimeout) { 8446 clearTimeout(this.hideTimeout); 8447 this.hideTimeout = 0; 8448 } 8449 if (!this.opts.showOnClick || !this.opts.hideOnClick) { 8450 var self = this; 8451 this.hideTimeout = setTimeout(function() { self.menuHideAll(); }, this.opts.hideTimeout); 8452 } 8453 }, 8454 rootOver: function(e) { 8455 if (!this.handleEvents() || this.isTouchMode() || e.target == this.$root[0]) { 8456 return; 8457 } 8458 if (this.hideTimeout) { 8459 clearTimeout(this.hideTimeout); 8460 this.hideTimeout = 0; 8461 } 8462 }, 8463 winResize: function(e) { 8464 if (!this.handleEvents()) { 8465 // we still need to resize the disable overlay if it's visible 8466 if (this.$disableOverlay) { 8467 var pos = this.$root.offset(); 8468 this.$disableOverlay.css({ 8469 top: pos.top, 8470 left: pos.left, 8471 width: this.$root.outerWidth(), 8472 height: this.$root.outerHeight() 8473 }); 8474 } 8475 return; 8476 } 8477 // hide sub menus on resize - on mobile do it only on orientation change 8478 if (!this.isCollapsible() && (!('onorientationchange' in window) || e.type == 'orientationchange')) { 8479 if (this.activatedItems.length) { 8480 this.activatedItems[this.activatedItems.length - 1][0].blur(); 8481 } 8482 this.menuHideAll(); 8483 } 8484 } 8485 } 8486 }); 8487 8488 $.fn.dataSM = function(key, val) { 8489 if (val) { 8490 return this.data(key + '_smartmenus', val); 8491 } 8492 return this.data(key + '_smartmenus'); 8493 } 8494 8495 $.fn.removeDataSM = function(key) { 8496 return this.removeData(key + '_smartmenus'); 8497 } 8498 8499 $.fn.smartmenus = function(options) { 8500 if (typeof options == 'string') { 8501 var args = arguments, 8502 method = options; 8503 Array.prototype.shift.call(args); 8504 return this.each(function() { 8505 var smartmenus = $(this).data('smartmenus'); 8506 if (smartmenus && smartmenus[method]) { 8507 smartmenus[method].apply(smartmenus, args); 8508 } 8509 }); 8510 } 8511 var opts = $.extend({}, $.fn.smartmenus.defaults, options); 8512 return this.each(function() { 8513 new $.SmartMenus(this, opts); 8514 }); 8515 } 8516 8517 // default settings 8518 $.fn.smartmenus.defaults = { 8519 isPopup: false, // is this a popup menu (can be shown via the popupShow/popupHide methods) or a permanent menu bar 8520 mainMenuSubOffsetX: 0, // pixels offset from default position
8521 mainMenuSubOffsetY: 0, // pixels offset from default position 8522 subMenusSubOffsetX: 0, // pixels offset from default position 8523 subMenusSubOffsetY: 0, // pixels offset from default position 8524 subMenusMinWidth: '10em', // min-width for the sub menus (any CSS unit) - if set, the fixed width set in CSS will be ignored 8525 subMenusMaxWidth: '20em', // max-width for the sub menus (any CSS unit) - if set, the fixed width set in CSS will be ignored 8526 subIndicators: true, // create sub menu indicators - creates a SPAN and inserts it in the A 8527 subIndicatorsPos: 'prepend', // position of the SPAN relative to the menu item content ('prepend', 'append') 8528 subIndicatorsText: '+', // [optionally] add text in the SPAN (e.g. '+') (you may want to check the CSS for the sub indicators too) 8529 scrollStep: 30, // pixels step when scrolling long sub menus that do not fit in the viewport height 8530 scrollInterval: 30, // interval between each scrolling step 8531 scrollAccelerate: true, // accelerate scrolling or use a fixed step 8532 showTimeout: 250, // timeout before showing the sub menus 8533 hideTimeout: 500, // timeout before hiding the sub menus 8534 showDuration: 0, // duration for show animation - set to 0 for no animation - matters only if showFunction:null 8535 showFunction: null, // custom function to use when showing a sub menu (the default is the jQuery 'show') 8536 // don't forget to call complete() at the end of whatever you do 8537 // e.g.: function($ul, complete) { $ul.fadeIn(250, complete); } 8538 hideDuration: 0, // duration for hide animation - set to 0 for no animation - matters only if hideFunction:null 8539 hideFunction: function($ul, complete) { $ul.fadeOut(200, complete); }, // custom function to use when hiding a sub menu (the default is the jQuery 'hide') 8540 // don't forget to call complete() at the end of whatever you do 8541 // e.g.: function($ul, complete) { $ul.fadeOut(250, complete); } 8542 collapsibleShowDuration:0, // duration for show animation for collapsible sub menus - matters only if collapsibleShowFunction:null 8543 collapsibleShowFunction:function($ul, complete) { $ul.slideDown(200, complete); }, // custom function to use when showing a collapsible sub menu 8544 // (i.e. when mobile styles are used to make the sub menus collapsible) 8545 collapsibleHideDuration:0, // duration for hide animation for collapsible sub menus - matters only if collapsibleHideFunction:null 8546 collapsibleHideFunction:function($ul, complete) { $ul.slideUp(200, complete); }, // custom function to use when hiding a collapsible sub menu 8547 // (i.e. when mobile styles are used to make the sub menus collapsible) 8548 showOnClick: false, // show the first-level sub menus onclick instead of onmouseover (matters only for mouse input) 8549 hideOnClick: true, // hide the sub menus on click/tap anywhere on the page 8550 keepInViewport: true, // reposition the sub menus if needed to make sure they always appear inside the viewport 8551 keepHighlighted: true, // keep all ancestor items of the current sub menu highlighted (adds the 'highlighted' class to the A's) 8552 markCurrentItem: false, // automatically add the 'current' class to the A element of the item linking to the current URL 8553 markCurrentTree: true, // add the 'current' class also to the A elements of all ancestor items of the current item 8554 rightToLeftSubMenus: false, // right to left display of the sub menus (check the CSS for the sub indicators' position) 8555 bottomToTopSubMenus: false, // bottom to top display of the sub menus 8556 overlapControlsInIE: true // make sure sub menus appear on top of special OS controls in IE (i.e. SELECT, OBJECT, EMBED, etc.) 8557 }; 8558 8559})(jQuery); 8560 8561/* 8562 * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/ 8563 * 8564 * Uses the built in easing capabilities added In jQuery 1.1 8565 * to offer multiple easing options 8566 * 8567 * TERMS OF USE - jQuery Easing 8568 * 8569 * Open source under the BSD License. 8570 * 8571 * Copyright © 2008 George McGinley Smith 8572 * All rights reserved. 8573 * 8574 * Redistribution and use in source and binary forms, with or without modification, 8575 * are permitted provided that the following conditions are met: 8576 * 8577 * Redistributions of source code must retain the above copyright notice, this list of 8578 * conditions and the following disclaimer. 8579 * Redistributions in binary form must reproduce the above copyright notice, this list 8580 * of conditions and the following disclaimer in the documentation and/or other materials 8581 * provided with the distribution. 8582 * 8583 * Neither the name of the author nor the names of contributors may be used to endorse 8584 * or promote products derived from this software without specific prior written permission. 8585 * 8586 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 8587 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 8588 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 8589 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
vendor: 5,091 bytes, lines 8590-8735
8590 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 8591 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 8592 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 8593 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 8594 * OF THE POSSIBILITY OF SUCH DAMAGE. 8595 * 8596*/ 8597 8598// t: current time, b: begInnIng value, c: change In value, d: duration 8599jQuery.easing['jswing'] = jQuery.easing['swing']; 8600 8601jQuery.extend( jQuery.easing, 8602{ 8603 def: 'easeOutQuad', 8604 swing: function (x, t, b, c, d) { 8605 //alert(jQuery.easing.default); 8606 return jQuery.easing[jQuery.easing.def](x, t, b, c, d); 8607 }, 8608 easeInQuad: function (x, t, b, c, d) { 8609 return c*(t/=d)*t + b; 8610 }, 8611 easeOutQuad: function (x, t, b, c, d) { 8612 return -c *(t/=d)*(t-2) + b; 8613 }, 8614 easeInOutQuad: function (x, t, b, c, d) { 8615 if ((t/=d/2) < 1) return c/2*t*t + b; 8616 return -c/2 * ((--t)*(t-2) - 1) + b; 8617 }, 8618 easeInCubic: function (x, t, b, c, d) { 8619 return c*(t/=d)*t*t + b; 8620 }, 8621 easeOutCubic: function (x, t, b, c, d) { 8622 return c*((t=t/d-1)*t*t + 1) + b; 8623 }, 8624 easeInOutCubic: function (x, t, b, c, d) { 8625 if ((t/=d/2) < 1) return c/2*t*t*t + b; 8626 return c/2*((t-=2)*t*t + 2) + b; 8627 }, 8628 easeInQuart: function (x, t, b, c, d) { 8629 return c*(t/=d)*t*t*t + b; 8630 }, 8631 easeOutQuart: function (x, t, b, c, d) { 8632 return -c * ((t=t/d-1)*t*t*t - 1) + b; 8633 }, 8634 easeInOutQuart: function (x, t, b, c, d) { 8635 if ((t/=d/2) < 1) return c/2*t*t*t*t + b; 8636 return -c/2 * ((t-=2)*t*t*t - 2) + b; 8637 }, 8638 easeInQuint: function (x, t, b, c, d) { 8639 return c*(t/=d)*t*t*t*t + b; 8640 }, 8641 easeOutQuint: function (x, t, b, c, d) { 8642 return c*((t=t/d-1)*t*t*t*t + 1) + b; 8643 }, 8644 easeInOutQuint: function (x, t, b, c, d) { 8645 if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b; 8646 return c/2*((t-=2)*t*t*t*t + 2) + b; 8647 }, 8648 easeInSine: function (x, t, b, c, d) { 8649 return -c * Math.cos(t/d * (Math.PI/2)) + c + b; 8650 }, 8651 easeOutSine: function (x, t, b, c, d) { 8652 return c * Math.sin(t/d * (Math.PI/2)) + b; 8653 }, 8654 easeInOutSine: function (x, t, b, c, d) { 8655 return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b; 8656 }, 8657 easeInExpo: function (x, t, b, c, d) { 8658 return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b; 8659 }, 8660 easeOutExpo: function (x, t, b, c, d) { 8661 return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b; 8662 }, 8663 easeInOutExpo: function (x, t, b, c, d) { 8664 if (t==0) return b; 8665 if (t==d) return b+c; 8666 if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b; 8667 return c/2 * (-Math.pow(2, -10 * --t) + 2) + b; 8668 }, 8669 easeInCirc: function (x, t, b, c, d) { 8670 return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b; 8671 }, 8672 easeOutCirc: function (x, t, b, c, d) { 8673 return c * Math.sqrt(1 - (t=t/d-1)*t) + b; 8674 }, 8675 easeInOutCirc: function (x, t, b, c, d) { 8676 if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b; 8677 return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b; 8678 }, 8679 easeInElastic: function (x, t, b, c, d) { 8680 var s=1.70158;var p=0;var a=c; 8681 if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; 8682 if (a < Math.abs(c)) { a=c; var s=p/4; } 8683 else var s = p/(2*Math.PI) * Math.asin (c/a); 8684 return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; 8685 }, 8686 easeOutElastic: function (x, t, b, c, d) { 8687 var s=1.70158;var p=0;var a=c; 8688 if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; 8689 if (a < Math.abs(c)) { a=c; var s=p/4; } 8690 else var s = p/(2*Math.PI) * Math.asin (c/a); 8691 return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b; 8692 }, 8693 easeInOutElastic: function (x, t, b, c, d) { 8694 var s=1.70158;var p=0;var a=c; 8695 if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5); 8696 if (a < Math.abs(c)) { a=c; var s=p/4; } 8697 else var s = p/(2*Math.PI) * Math.asin (c/a); 8698 if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; 8699 return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b; 8700 }, 8701 easeInBack: function (x, t, b, c, d, s) { 8702 if (s == undefined) s = 1.70158; 8703 return c*(t/=d)*t*((s+1)*t - s) + b; 8704 }, 8705 easeOutBack: function (x, t, b, c, d, s) { 8706 if (s == undefined) s = 1.70158; 8707 return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b; 8708 }, 8709 easeInOutBack: function (x, t, b, c, d, s) { 8710 if (s == undefined) s = 1.70158; 8711 if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b; 8712 return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b; 8713 }, 8714 easeInBounce: function (x, t, b, c, d) { 8715 return c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d) + b; 8716 }, 8717 easeOutBounce: function (x, t, b, c, d) { 8718 if ((t/=d) < (1/2.75)) { 8719 return c*(7.5625*t*t) + b; 8720 } else if (t < (2/2.75)) { 8721 return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b; 8722 } else if (t < (2.5/2.75)) { 8723 return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b; 8724 } else { 8725 return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b; 8726 } 8727 }, 8728 easeInOutBounce: function (x, t, b, c, d) { 8729 if (t < d/2) return jQuery.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b; 8730 return jQuery.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b; 8731 } 8732}); 8733 8734/* 8735 *
8736 * TERMS OF USE - EASING EQUATIONS 8737 * 8738 * Open source under the BSD License. 8739 * 8740 * Copyright © 2001 Robert Penner 8741 * All rights reserved. 8742 * 8743 * Redistribution and use in source and binary forms, with or without modification, 8744 * are permitted provided that the following conditions are met: 8745 * 8746 * Redistributions of source code must retain the above copyright notice, this list of 8747 * conditions and the following disclaimer. 8748 * Redistributions in binary form must reproduce the above copyright notice, this list 8749 * of conditions and the following disclaimer in the documentation and/or other materials 8750 * provided with the distribution. 8751 * 8752 * Neither the name of the author nor the names of contributors may be used to endorse 8753 * or promote products derived from this software without specific prior written permission. 8754 * 8755 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 8756 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 8757 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 8758 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 8759 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 8760 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 8761 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 8762 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 8763 * OF THE POSSIBILITY OF SUCH DAMAGE. 8764 * 8765 */ 8766(function($, window, undefined) { 8767 // http://paulirish.com/2011/requestanimationframe-for-smart-animating/ 8768 // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating 8769 8770 // requestAnimationFrame polyfill by Erik Möller 8771 // fixes from Paul Irish and Tino Zijdel 8772 8773 var lastTime = 0, 8774 running, 8775 animate = function (elem) { 8776 if (running) { 8777 window.requestAnimationFrame(animate, elem); 8778 jQuery.fx.tick(); 8779 } 8780 }, 8781 vendors = ['ms', 'moz', 'webkit', 'o']; 8782 8783 for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { 8784 window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame']; 8785 window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] 8786 || window[vendors[x]+'CancelRequestAnimationFrame']; 8787 } 8788 8789 if (!window.requestAnimationFrame) 8790 window.requestAnimationFrame = function(fn, element) { 8791 var currTime = new Date().getTime(), 8792 delta = currTime - lastTime, 8793 timeToCall = Math.max(0, 16 - delta); 8794 8795 var id = window.setTimeout(function() { 8796 fn(currTime + timeToCall); 8797 }, 8798 timeToCall 8799 ); 8800 8801 lastTime = currTime + timeToCall; 8802 8803 return id; 8804 }; 8805 8806 if (!window.cancelAnimationFrame) { 8807 window.cancelAnimationFrame = function(id) { 8808 clearTimeout(id); 8809 }; 8810 } 8811 8812 jQuery.fx.timer = function (timer) { 8813 if (timer() && jQuery.timers.push(timer) && !running) { 8814 running = true; 8815 animate(timer.elem); 8816 } 8817 }; 8818 8819 jQuery.fx.stop = function() { 8820 running = false; 8821 }; 8822 8823}(jQuery, this)); 8824/*! Copyright (c) 2011 Brandon Aaron (http://brandonaaron.net) 8825 * Licensed under the MIT License (LICENSE.txt). 8826 * 8827 * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers. 8828 * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix. 8829 * Thanks to: Seamus Leahy for adding deltaX and deltaY 8830 * 8831 * Version: 3.0.6 8832 * 8833 * Requires: 1.2.2+ 8834 */ 8835(function($) { 8836 var types = ['DOMMouseScroll', 'mousewheel']; 8837 if ($.event.fixHooks) { 8838 for (var i = types.length; i;) { 8839 $.event.fixHooks[types[--i]] = $.event.mouseHooks; 8840 } 8841 } 8842 $.event.special.mousewheel = { 8843 setup: function() { 8844 if (this.addEventListener) { 8845 for (var i = types.length; i;) { 8846 this.addEventListener(types[--i], handler, false); 8847 } 8848 } else { 8849 this.onmousewheel = handler; 8850 } 8851 }, 8852 teardown: function() { 8853 if (this.removeEventListener) { 8854 for (var i = types.length; i;) { 8855 this.removeEventListener(types[--i], handler, false); 8856 } 8857 } else { 8858 this.onmousewheel = null; 8859 } 8860 } 8861 }; 8862 $.fn.extend({ 8863 mousewheel: function(fn) { 8864 return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel"); 8865 }, 8866 unmousewheel: function(fn) { 8867 return this.unbind("mousewheel", fn); 8868 } 8869 }); 8870 8871 function handler(event) { 8872 var orgEvent = event || window.event, 8873 args = [].slice.call(arguments, 1), 8874 delta = 0, 8875 returnValue = true, 8876 deltaX = 0, 8877 deltaY = 0; 8878 event = $.event.fix(orgEvent); 8879 event.type = "mousewheel"; 8880 // Old school scrollwheel delta 8881 if (orgEvent.wheelDelta) { 8882 delta = orgEvent.wheelDelta / 120; 8883 } 8884 if (orgEvent.detail) { 8885 delta = -orgEvent.detail / 3; 8886 } 8887 // New school multidimensional scroll (touchpads) deltas 8888 deltaY = delta; 8889 // Gecko 8890 if (orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS) { 8891 deltaY = 0; 8892 deltaX = -1 * delta; 8893 } 8894 // Webkit 8895 if (orgEvent.wheelDeltaY !== undefined) { 8896 deltaY = orgEvent.wheelDeltaY / 120; 8897 } 8898 if (orgEvent.wheelDeltaX !== undefined) { 8899 deltaX = -1 * orgEvent.wheelDeltaX / 120; 8900 } 8901 // Add event and delta to the front of the arguments 8902 args.unshift(event, delta, deltaX, deltaY); 8903 return ($.event.dispatch || $.event.handle).apply(this, args); 8904 } 8905})(jQuery); 8906/** 8907 * jQuery iLightBox - Revolutionary Lightbox Plugin 8908 * http://www.ilightbox.net/ 8909 * 8910 * @version: 2.2.4 - October 14, 2017 8911 * 8912 * @author: iProDev (Hemn Chawroka) 8913 * http://www.iprodev.com/ 8914 * 8915 */ 8916(function($, window, undefined) { 8917 8918 var extensions = { 8919 flash: ['swf'], 8920 image: ['bmp', 'gif', 'jpeg', 'jpg', 'png', 'tiff', 'tif', 'jfif', 'jpe'], 8921 iframe: ['asp', 'aspx', 'cgi', 'cfm', 'htm', 'html', 'jsp', 'php', 'pl', 'php3', 'php4', 'php5', 'phtml', 'rb', 'rhtml', 'shtml', 'txt'], 8922 video: ['avi', 'mov', 'mpg', 'mpeg', 'movie', 'mp4', 'webm', 'ogv', 'ogg', '3gp', 'm4v'] 8923 }, 8924 8925 // Global DOM elements 8926 $win = $(window), 8927 $doc = $(document), 8928
8929 // Support indicators 8930 browser, 8931 transform, 8932 gpuAcceleration, 8933 fullScreenApi = '', 8934 userAgent = navigator.userAgent || navigator.vendor || window.opera, 8935 supportTouch = "ontouchstart" in window || navigator.msMaxTouchPoints, 8936 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)), 8937 8938 // Events 8939 clickEvent = supportTouch ? "itap.iLightBox" : "click.iLightBox", 8940 touchStartEvent = supportTouch ? "touchstart.iLightBox" : "mousedown.iLightBox", 8941 touchStopEvent = supportTouch ? "touchend.iLightBox" : "mouseup.iLightBox", 8942 touchMoveEvent = supportTouch ? "touchmove.iLightBox" : "mousemove.iLightBox", 8943 8944 // Math shorthands 8945 abs = Math.abs, 8946 sqrt = Math.sqrt, 8947 round = Math.round, 8948 max = Math.max, 8949 min = Math.min, 8950 floor = Math.floor, 8951 random = Math.random, 8952 8953 pluginspages = { 8954 quicktime: 'http://www.apple.com/quicktime/download', 8955 flash: 'http://www.adobe.com/go/getflash' 8956 }, 8957 8958 iLightBox = function(el, options, items, instant) { 8959 var iL = this; 8960 8961 iL.options = options, 8962 iL.selector = el.selector || el, 8963 iL.context = el.context, 8964 iL.instant = instant; 8965 8966 if (items.length < 1) iL.attachItems(); 8967 else iL.items = items; 8968 8969 iL.vars = { 8970 total: iL.items.length, 8971 start: 0, 8972 current: null, 8973 next: null, 8974 prev: null, 8975 BODY: $('body'), 8976 loadRequests: 0, 8977 overlay: $('<div class="ilightbox-overlay"></div>'), 8978 loader: $('<div class="ilightbox-loader"><div></div></div>'), 8979 toolbar: $('<div class="ilightbox-toolbar"></div>'), 8980 innerToolbar: $('<div class="ilightbox-inner-toolbar"></div>'), 8981 title: $('<div class="ilightbox-title"></div>'), 8982 closeButton: $('<a class="ilightbox-close" title="' + iL.options.text.close + '"></a>'), 8983 fullScreenButton: $('<a class="ilightbox-fullscreen" title="' + iL.options.text.enterFullscreen + '"></a>'), 8984 innerPlayButton: $('<a class="ilightbox-play" title="' + iL.options.text.slideShow + '"></a>'), 8985 innerNextButton: $('<a class="ilightbox-next-button" title="' + iL.options.text.next + '"></a>'), 8986 innerPrevButton: $('<a class="ilightbox-prev-button" title="' + iL.options.text.previous + '"></a>'), 8987 holder: $('<div class="ilightbox-holder' + (supportTouch ? ' supportTouch' : '') + '" ondragstart="return false;"><div class="ilightbox-container"></div></div>'), 8988 nextPhoto: $('<div class="ilightbox-holder' + (supportTouch ? ' supportTouch' : '') + ' ilightbox-next" ondragstart="return false;"><div class="ilightbox-container"></div></div>'), 8989 prevPhoto: $('<div class="ilightbox-holder' + (supportTouch ? ' supportTouch' : '') + ' ilightbox-prev" ondragstart="return false;"><div class="ilightbox-container"></div></div>'), 8990 nextButton: $('<a class="ilightbox-button ilightbox-next-button" ondragstart="return false;" title="' + iL.options.text.next + '"><span></span></a>'), 8991 prevButton: $('<a class="ilightbox-button ilightbox-prev-button" ondragstart="return false;" title="' + iL.options.text.previous + '"><span></span></a>'),
8992 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>'), 8993 thumbs: false, 8994 nextLock: false, 8995 prevLock: false, 8996 hashLock: false, 8997 isMobile: false, 8998 mobileMaxWidth: 980, 8999 isInFullScreen: false, 9000 isSwipe: false, 9001 mouseID: 0, 9002 cycleID: 0, 9003 isPaused: 0, 9004 captionHeight: 39, 9005 }; 9006 9007 // Hideable elements with mousemove event 9008 iL.vars.hideableElements = iL.vars.nextButton.add(iL.vars.prevButton); 9009 9010 iL.normalizeItems(); 9011 9012 //Check necessary plugins 9013 iL.availPlugins(); 9014 9015 //Set startFrom 9016 iL.options.startFrom = (iL.options.startFrom > 0 && iL.options.startFrom >= iL.vars.total) ? iL.vars.total - 1 : iL.options.startFrom; 9017 9018 //If randomStart 9019 iL.options.startFrom = (iL.options.randomStart) ? floor(random() * iL.vars.total) : iL.options.startFrom; 9020 iL.vars.start = iL.options.startFrom; 9021 9022 if (instant) iL.instantCall(); 9023 else iL.patchItemsEvents(); 9024 9025 if (iL.options.linkId) { 9026 iL.hashChangeHandler(); 9027 $win.iLightBoxHashChange(function() { 9028 iL.hashChangeHandler(); 9029 }); 9030 } 9031 9032 if (supportTouch) { 9033 var RegExp = /(click|mouseenter|mouseleave|mouseover|mouseout)/ig, 9034 replace = "itap"; 9035 iL.options.caption.show = iL.options.caption.show.replace(RegExp, replace), 9036 iL.options.caption.hide = iL.options.caption.hide.replace(RegExp, replace), 9037 iL.options.social.show = iL.options.social.show.replace(RegExp, replace), 9038 iL.options.social.hide = iL.options.social.hide.replace(RegExp, replace); 9039 } 9040 9041 if (iL.options.controls.arrows || $(window).width() < UNCODE.mediaQuery) { 9042 $.extend(iL.options.styles, { 9043 nextOffsetX: ($(window).width() > UNCODE.mediaQuery) ? 36 : 4, 9044 prevOffsetX: ($(window).width() > UNCODE.mediaQuery) ? 36 : 4, 9045 nextOpacity: 0, 9046 prevOpacity: 0 9047 }); 9048 } 9049 }; 9050 9051 //iLightBox helpers 9052 iLightBox.prototype = { 9053 showLoader: function() { 9054 var iL = this; 9055 iL.vars.loadRequests += 1; 9056 if (iL.options.path.toLowerCase() == "horizontal") iL.vars.loader.addClass('ilightbox-show').stop().animate({ 9057 //top: '-30px' 9058 opacity: '1' 9059 }, iL.options.show.speed, 'easeOutCirc'); 9060 else iL.vars.loader.addClass('ilightbox-show').stop().animate({ 9061 //left: '-30px' 9062 opacity: '1' 9063 }, iL.options.show.speed, 'easeOutCirc'); 9064 }, 9065 9066 hideLoader: function() { 9067 var iL = this; 9068 iL.vars.loadRequests -= 1; 9069 iL.vars.loadRequests = (iL.vars.loadRequests < 0) ? 0 : iL.vars.loadRequests; 9070 if (iL.options.path.toLowerCase() == "horizontal") { 9071 if (iL.vars.loadRequests <= 0) iL.vars.loader.removeClass('ilightbox-show').stop().animate({ 9072 //top: '-192px' 9073 opacity: '0' 9074 }, iL.options.show.speed, 'easeInCirc'); 9075 } else { 9076 if (iL.vars.loadRequests <= 0) iL.vars.loader.removeClass('ilightbox-show').stop().animate({ 9077 //left: '-192px' 9078 opacity: '0' 9079 }, iL.options.show.speed, 'easeInCirc'); 9080 } 9081 }, 9082 9083 createUI: function() { 9084 var iL = this; 9085 9086 iL.ui = { 9087 currentElement: iL.vars.holder, 9088 nextElement: iL.vars.nextPhoto, 9089 prevElement: iL.vars.prevPhoto, 9090 currentItem: iL.vars.current, 9091 nextItem: iL.vars.next, 9092 prevItem: iL.vars.prev, 9093 hide: function() { 9094 iL.closeAction(); 9095 }, 9096 refresh: function() { 9097 (arguments.length > 0) ? iL.repositionPhoto(true): iL.repositionPhoto(); 9098 }, 9099 fullscreen: function() { 9100 iL.fullScreenAction(); 9101 } 9102 }; 9103 }, 9104 9105 attachItems: function() { 9106 var iL = this, 9107 itemsObject = new Array(), 9108 items = new Array(); 9109 9110 $(iL.selector, iL.context).each(function() { 9111 var t = $(this), 9112 URL = t.attr(iL.options.attr) || null, 9113 options = t.data("options") && eval("({" + t.data("options") + "})") || {}, 9114 caption = t.data('caption'), 9115 title = t.data('title'), 9116 type = t.data('type') || getTypeByExtension(URL), 9117 clone = t.data('lbox-clone') || false; 9118 9119 if (t.data('lbox-clone') != undefined) return; 9120 9121 //Uncode addition ##START## 9122 if ( typeof t.attr('data-album') != 'undefined' && t.attr('data-album') != '' ) { 9123 var ALBUM_URLS = JSON.parse(t.attr('data-album')), 9124 URL_i, 9125 URLS_LENGHT = ALBUM_URLS.length; 9126 for (URL_i = 0; URL_i < URLS_LENGHT; URL_i++) { 9127 if ( typeof ALBUM_URLS[URL_i].url !== 'undefined' && ALBUM_URLS[URL_i].url != '' ) { 9128 var item_opts = 'width:' + ALBUM_URLS[URL_i].width + ',height:' + ALBUM_URLS[URL_i].height + ',thumbnail: \'' + ALBUM_URLS[URL_i].thumbnail + '\''; 9129 item_opts = item_opts && eval("({" + item_opts + "})") || {}, 9130 items.push({ 9131 URL: ALBUM_URLS[URL_i].url, 9132 caption: ALBUM_URLS[URL_i].caption, 9133 title: ALBUM_URLS[URL_i].title, 9134 type: getTypeByExtension(ALBUM_URLS[URL_i].url), 9135 options: item_opts, 9136 clone: clone 9137 }); 9138 var newT = t; 9139 newT.attr('href',ALBUM_URLS[URL_i].url); 9140 if (!iL.instant) itemsObject.push(newT); 9141 } 9142 } 9143 } else { 9144 //Uncode addition ##END## 9145 items.push({ 9146 URL: URL, 9147 caption: caption, 9148 title: title, 9149 type: type, 9150 options: options, 9151 clone: clone 9152 }); 9153 } 9154 9155 9156 if (iL.vars != undefined) iL.vars.total = items.length; 9157 9158 if (!iL.instant) itemsObject.push(t); 9159 }); 9160 9161 iL.items = items, 9162 iL.itemsObject = itemsObject; 9163 9164 }, 9165 9166 normalizeItems: function() { 9167 var iL = this, 9168 newItems = new Array(); 9169 9170 $.each(iL.items, function(key, val) { 9171 9172 if (typeof val == "string") val = { 9173 url: val 9174 }; 9175 9176 var URL = val.url || val.URL || null, 9177 options = val.options || {}, 9178 caption = val.caption || null, 9179 title = val.title || null, 9180 type = (val.type) ? val.type.toLowerCase() : getTypeByExtension(URL), 9181 ext = (typeof URL != 'object') ? getExtension(URL) : ''; 9182 9183 options.thumbnail = options.thumbnail || ((type == "image") ? URL : null),
9184 options.videoType = options.videoType || null, 9185 options.skin = options.skin || iL.options.skin, 9186 options.width = options.width || null, 9187 options.height = options.height || null, 9188 options.mousewheel = (typeof options.mousewheel != 'undefined') ? options.mousewheel : true, 9189 options.swipe = (typeof options.swipe != 'undefined') ? options.swipe : true, 9190 options.social = (typeof options.social != 'undefined') ? options.social : iL.options.social.buttons && $.extend({}, {}, iL.options.social.buttons); 9191 9192 if (type == "video") { 9193 options.html5video = (typeof options.html5video != 'undefined') ? options.html5video : {}; 9194 9195 options.html5video.webm = options.html5video.webm || options.html5video.WEBM || null; 9196 options.html5video.controls = (typeof options.html5video.controls != 'undefined') ? options.html5video.controls : "controls"; 9197 options.html5video.preload = options.html5video.preload || "metadata"; 9198 options.html5video.autoplay = (typeof options.html5video.autoplay != 'undefined') ? options.html5video.autoplay : false; 9199 //UNCODE addition 9200 options.html5video.loop = (typeof options.html5video.loop != 'undefined') ? options.html5video.loop : false; 9201 } 9202 9203 if (!options.width || !options.height) { 9204 if (type == "video") options.width = 1280, options.height = 720; 9205 else if (type == "iframe") options.width = '100%', options.height = '90%'; 9206 else if (type == "flash") options.width = 1280, options.height = 720; 9207 } 9208 9209 delete val.url; 9210 val.index = key; 9211 val.URL = URL; 9212 val.caption = caption; 9213 val.title = title; 9214 val.type = type; 9215 val.options = options; 9216 val.ext = ext; 9217 9218 newItems.push(val); 9219 }); 9220 9221 iL.items = newItems; 9222 }, 9223 9224 instantCall: function() { 9225 var iL = this, 9226 key = iL.vars.start; 9227 9228 iL.vars.current = key; 9229 iL.vars.next = (iL.items[key + 1]) ? key + 1 : null; 9230 iL.vars.prev = (iL.items[key - 1]) ? key - 1 : null; 9231 9232 iL.addContents(); 9233 iL.patchEvents(); 9234 }, 9235 9236 addContents: function() { 9237 var iL = this, 9238 vars = iL.vars, 9239 opts = iL.options, 9240 viewport = getViewport(), 9241 path = opts.path.toLowerCase(), 9242 recognizingItems = vars.total > 0 && iL.items.filter(function(e, i, arr) { 9243 return ['image', 'flash', 'video'].indexOf(e.type) === -1 && typeof e.recognized === 'undefined' && (opts.smartRecognition || e.options.smartRecognition); 9244 }), 9245 needRecognition = recognizingItems.length > 0; 9246 9247 if (opts.mobileOptimizer && !opts.innerToolbar) 9248 vars.isMobile = viewport.width <= vars.mobileMaxWidth; 9249 9250 vars.overlay.addClass(opts.skin).hide().css('opacity', opts.overlay.opacity); 9251 9252 if (opts.linkId) 9253 vars.overlay[0].setAttribute('linkid', opts.linkId); 9254 9255 //Add Toolbar Buttons 9256 if (opts.controls.toolbar) { 9257 vars.toolbar.addClass(opts.skin).append(vars.closeButton); 9258 if (opts.controls.fullscreen) 9259 vars.toolbar.append(vars.fullScreenButton); 9260 if (opts.controls.slideshow) 9261 vars.toolbar.append(vars.innerPlayButton); 9262 if (vars.total > 1) 9263 vars.toolbar.append(vars.innerPrevButton).append(vars.innerNextButton); 9264 } 9265 9266 //Append elements to body 9267 vars.BODY.addClass('ilightbox-noscroll').append(vars.overlay).append(vars.loader).append(vars.holder).append(vars.nextPhoto).append(vars.prevPhoto); 9268 9269 if (!opts.innerToolbar) 9270 vars.BODY.append(vars.toolbar); 9271 if (opts.controls.arrows) 9272 vars.BODY.append(vars.nextButton).append(vars.prevButton); 9273 9274 if (opts.controls.thumbnail && vars.total > 1) { 9275 vars.BODY.append(vars.thumbnails); 9276 vars.thumbnails.addClass(opts.skin).addClass('ilightbox-' + path); 9277 $('div.ilightbox-thumbnails-grid', vars.thumbnails).empty(); 9278 vars.thumbs = true; 9279 } 9280 9281 //Configure loader and arrows 9282 var loaderCss = (opts.path.toLowerCase() == "horizontal") ? { 9283 left: parseInt((viewport.width / 2) - (vars.loader.outerWidth() / 2)) 9284 } : { 9285 top: parseInt((viewport.height / 2) - (vars.loader.outerHeight() / 2)) 9286 }; 9287 vars.loader.addClass(opts.skin).css(loaderCss); 9288 vars.nextButton.add(vars.prevButton).addClass(opts.skin); 9289 if (path == "horizontal") 9290 vars.loader.add(vars.nextButton).add(vars.prevButton).addClass('horizontal'); 9291 9292 // Configure arrow buttons 9293 vars.BODY[vars.isMobile ? 'addClass' : 'removeClass']('isMobile'); 9294 9295 if (!opts.infinite) { 9296 vars.prevButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled'); 9297 9298 if (vars.current == 0) 9299 vars.prevButton.add(vars.innerPrevButton).addClass('disabled'); 9300 if (vars.current >= vars.total - 1) 9301 vars.nextButton.add(vars.innerNextButton).addClass('disabled'); 9302 } 9303 9304 if (opts.show.effect) { 9305 vars.overlay.stop().fadeIn(opts.show.speed); 9306 vars.toolbar.stop().fadeIn(opts.show.speed); 9307 } else { 9308 vars.overlay.show(); 9309 vars.toolbar.show(); 9310 } 9311 9312 var length = recognizingItems.length; 9313 if (needRecognition) { 9314 iL.showLoader(); 9315 9316 $.each(recognizingItems, function(key, val) { 9317 var resultFnc = function(result) { 9318 var key = -1, 9319 filter = iL.items.filter(function(e, i, arr) { 9320 if (e.URL == result.url) 9321 key = i; 9322 9323 return e.URL == result.url; 9324 }), 9325 self = iL.items[key]; 9326 9327 if (result) 9328 $.extend(true, self, { 9329 URL: result.source, 9330 type: result.type, 9331 recognized: true, 9332 options: { 9333 html5video: result.html5video, 9334 width: (result.type == "image") ? 0 : (result.width || self.width), 9335 height: (result.type == "image") ? 0 : (result.height || self.height), 9336 thumbnail: self.options.thumbnail || result.thumbnail 9337 } 9338 }); 9339 9340 length--; 9341 9342 if (length == 0) { 9343 iL.hideLoader(); 9344 9345 vars.dontGenerateThumbs = false;
9346 iL.generateThumbnails(); 9347 9348 if (opts.show.effect) 9349 setTimeout(function() { 9350 iL.generateBoxes(); 9351 }, opts.show.speed); 9352 else 9353 iL.generateBoxes(); 9354 } 9355 }; 9356 9357 iL.ogpRecognition(this, resultFnc); 9358 }); 9359 } 9360 else { 9361 if (opts.show.effect) 9362 setTimeout(function() { 9363 iL.generateBoxes(); 9364 }, opts.show.speed); 9365 else 9366 iL.generateBoxes(); 9367 } 9368 9369 iL.createUI(); 9370 9371 window.iLightBox = { 9372 close: function() { 9373 iL.closeAction(); 9374 }, 9375 fullscreen: function() { 9376 iL.fullScreenAction(); 9377 }, 9378 moveNext: function() { 9379 iL.moveTo('next'); 9380 }, 9381 movePrev: function() { 9382 iL.moveTo('prev'); 9383 }, 9384 goTo: function(index) { 9385 iL.goTo(index); 9386 }, 9387 refresh: function() { 9388 iL.refresh(); 9389 }, 9390 reposition: function() { 9391 (arguments.length > 0) ? iL.repositionPhoto(true): iL.repositionPhoto(); 9392 }, 9393 setOption: function(options) { 9394 iL.setOption(options); 9395 }, 9396 destroy: function() { 9397 iL.closeAction(); 9398 iL.dispatchItemsEvents(); 9399 } 9400 }; 9401 9402 if (opts.linkId) { 9403 vars.hashLock = true; 9404 window.location.hash = opts.linkId + '/' + vars.current; 9405 setTimeout(function() { 9406 vars.hashLock = false; 9407 }, 55); 9408 } 9409 9410 if (!opts.slideshow.startPaused) { 9411 iL.resume(); 9412 vars.innerPlayButton.removeClass('ilightbox-play').addClass('ilightbox-pause'); 9413 } 9414 9415 //Trigger the onOpen callback 9416 if (typeof iL.options.callback.onOpen == 'function') iL.options.callback.onOpen.call(iL); 9417 }, 9418 9419 loadContent: function(obj, opt, speed) { 9420 var iL = this, 9421 holder, item; 9422 9423 iL.createUI(); 9424 9425 obj.speed = speed || iL.options.effects.loadedFadeSpeed; 9426 9427 if (opt == 'current') { 9428 if (!obj.options.mousewheel) iL.vars.lockWheel = true; 9429 else iL.vars.lockWheel = false; 9430 9431 if (!obj.options.swipe) iL.vars.lockSwipe = true; 9432 else iL.vars.lockSwipe = false; 9433 } 9434 9435 switch (opt) { 9436 case 'current': 9437 holder = iL.vars.holder, item = iL.vars.current; 9438 break; 9439 case 'next': 9440 holder = iL.vars.nextPhoto, item = iL.vars.next; 9441 break; 9442 case 'prev': 9443 holder = iL.vars.prevPhoto, item = iL.vars.prev; 9444 break; 9445 } 9446 9447 holder.removeAttr('style class').addClass('ilightbox-holder' + (supportTouch ? ' supportTouch' : '')).addClass(obj.options.skin); 9448 $('div.ilightbox-inner-toolbar', holder).remove(); 9449 9450 if (obj.title || iL.options.innerToolbar) { 9451 var innerToolbar = iL.vars.innerToolbar.clone(); 9452 if (obj.title && iL.options.show.title) { 9453 var title = iL.vars.title.clone(); 9454 title.empty().html(obj.title); 9455 innerToolbar.append(title); 9456 } 9457 if (iL.options.innerToolbar) { 9458 innerToolbar.append((iL.vars.total > 1) ? iL.vars.toolbar.clone() : iL.vars.toolbar); 9459 } 9460 holder.prepend(innerToolbar); 9461 } 9462 9463 //console.warn('loadContent', arguments); 9464 9465 iL.loadSwitcher(obj, holder, item, opt); 9466 }, 9467 9468 loadSwitcher: function(obj, holder, item, opt) { 9469 var iL = this, 9470 opts = iL.options, 9471 api = { 9472 element: holder, 9473 position: item 9474 }; 9475 9476 switch (obj.type) { 9477 case 'image': 9478 //Trigger the onBeforeLoad callback 9479 if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item); 9480 if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api); 9481 9482 iL.loadImage(obj.URL, function(img) { 9483 //Trigger the onAfterLoad callback 9484 if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item); 9485 if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api); 9486 9487 var width = (img) ? img.width : 400, 9488 height = (img) ? img.height : 200; 9489 9490 holder.data({ 9491 naturalWidth: width, 9492 naturalHeight: height 9493 }); 9494 $('div.ilightbox-container', holder).empty().append((img) ? '<img src="' + obj.URL + '" class="ilightbox-image" />' : '<span class="ilightbox-alert">' + opts.errors.loadImage + '</span>'); 9495 9496 //Trigger the onRender callback 9497 if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item); 9498 if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api); 9499 9500 iL.configureHolder(obj, opt, holder); 9501 }); 9502 9503 break; 9504
9505 case 'video': 9506 holder.data({ 9507 naturalWidth: obj.options.width, 9508 naturalHeight: obj.options.height 9509 }); 9510 9511 if (opt === 'current') { 9512 iL.addContent(holder, obj); 9513 9514 //Trigger the onRender callback 9515 if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item); 9516 if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api); 9517 } else { 9518 $('div.ilightbox-container', holder).empty(); 9519 } 9520 9521 iL.configureHolder(obj, opt, holder); 9522 9523 break; 9524 9525 case 'iframe': 9526 //iL.showLoader(); 9527 holder.data({ 9528 naturalWidth: obj.options.width, 9529 naturalHeight: obj.options.height 9530 }); 9531 9532 iL.configureHolder(obj, opt, holder); 9533 9534 if (opt === 'current') { 9535 var el = iL.addContent(holder, obj); 9536 9537 //Trigger the onRender callback 9538 if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item); 9539 if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api); 9540 9541 //Trigger the onBeforeLoad callback 9542 if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item); 9543 if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api); 9544 9545 el.bind('load', function() { 9546 //Trigger the onAfterLoad callback 9547 if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item); 9548 if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api); 9549 9550 //iL.hideLoader(); 9551 el.unbind('load'); 9552 }); 9553 } else { 9554 $('div.ilightbox-container', holder).empty(); 9555 } 9556 9557 break; 9558 9559 case 'inline': 9560 var el = $(obj.URL), 9561 content = iL.addContent(holder, obj), 9562 images = findImageInElement(holder); 9563 9564 holder.data({ 9565 naturalWidth: (iL.items[item].options.width || el.outerWidth()), 9566 naturalHeight: (iL.items[item].options.height || el.outerHeight()) 9567 }); 9568 content.children().eq(0).show(); 9569 9570 //Trigger the onRender callback 9571 if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item); 9572 if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api); 9573 9574 //Trigger the onBeforeLoad callback 9575 if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item); 9576 if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api); 9577 9578 iL.loadImage(images, function() { 9579 //Trigger the onAfterLoad callback 9580 if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item); 9581 if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api); 9582 9583 iL.configureHolder(obj, opt, holder); 9584 }); 9585 9586 break; 9587 9588 case 'flash': 9589 var el = iL.addContent(holder, obj); 9590 9591 holder.data({ 9592 naturalWidth: (iL.items[item].options.width || el.outerWidth()), 9593 naturalHeight: (iL.items[item].options.height || el.outerHeight()) 9594 }); 9595 9596 //Trigger the onRender callback 9597 if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item); 9598 if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api); 9599 9600 iL.configureHolder(obj, opt, holder); 9601 9602 break; 9603 9604 case 'ajax': 9605 var ajax = obj.options.ajax || {}; 9606 //Trigger the onBeforeLoad callback 9607 if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item); 9608 if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api); 9609 9610 iL.showLoader(); 9611 $.ajax({ 9612 url: obj.URL || opts.ajaxSetup.url, 9613 data: ajax.data || null, 9614 dataType: ajax.dataType || "html", 9615 type: ajax.type || opts.ajaxSetup.type, 9616 cache: ajax.cache || opts.ajaxSetup.cache, 9617 crossDomain: ajax.crossDomain || opts.ajaxSetup.crossDomain, 9618 global: ajax.global || opts.ajaxSetup.global, 9619 ifModified: ajax.ifModified || opts.ajaxSetup.ifModified, 9620 username: ajax.username || opts.ajaxSetup.username, 9621 password: ajax.password || opts.ajaxSetup.password, 9622 beforeSend: ajax.beforeSend || opts.ajaxSetup.beforeSend, 9623 complete: ajax.complete || opts.ajaxSetup.complete, 9624 success: function(data, textStatus, jqXHR) { 9625 iL.hideLoader(); 9626 9627 var el = $(data), 9628 container = $('div.ilightbox-container', holder), 9629 elWidth = iL.items[item].options.width || parseInt(el[0].getAttribute('width')), 9630 elHeight = iL.items[item].options.height || parseInt(el[0].getAttribute('height')), 9631 css = (el[0].getAttribute('width') && el[0].getAttribute('height')) ? { 9632 'overflow': 'hidden' 9633 } : {}; 9634 9635 container.empty().append($('<div class="ilightbox-wrapper"></div>').css(css).html(el)); 9636 holder.show().data({
9637 naturalWidth: (elWidth || container.outerWidth()), 9638 naturalHeight: (elHeight || container.outerHeight()) 9639 }).hide(); 9640 9641 //Trigger the onRender callback 9642 if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item); 9643 if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api); 9644 9645 var images = findImageInElement(holder); 9646 iL.loadImage(images, function() { 9647 //Trigger the onAfterLoad callback 9648 if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item); 9649 if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api); 9650 9651 iL.configureHolder(obj, opt, holder); 9652 }); 9653 9654 opts.ajaxSetup.success(data, textStatus, jqXHR); 9655 if (typeof ajax.success == 'function') ajax.success(data, textStatus, jqXHR); 9656 }, 9657 error: function(jqXHR, textStatus, errorThrown) { 9658 //Trigger the onAfterLoad callback 9659 if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item); 9660 if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api); 9661 9662 iL.hideLoader(); 9663 $('div.ilightbox-container', holder).empty().append('<span class="ilightbox-alert">' + opts.errors.loadContents + '</span>'); 9664 iL.configureHolder(obj, opt, holder); 9665 9666 opts.ajaxSetup.error(jqXHR, textStatus, errorThrown); 9667 if (typeof ajax.error == 'function') ajax.error(jqXHR, textStatus, errorThrown); 9668 } 9669 }); 9670 9671 break; 9672 9673 case 'html': 9674 var object = obj.URL, 9675 el 9676 container = $('div.ilightbox-container', holder); 9677 9678 if (object[0].nodeName) el = object.clone(); 9679 else { 9680 var dom = $(object); 9681 if (dom.selector) el = $('<div>' + dom + '</div>'); 9682 else el = dom; 9683 } 9684 9685 var elWidth = iL.items[item].options.width || parseInt(el.attr('width')), 9686 elHeight = iL.items[item].options.height || parseInt(el.attr('height')); 9687 9688 iL.addContent(holder, obj); 9689 9690 el.appendTo(document.documentElement).hide(); 9691 9692 //Trigger the onRender callback 9693 if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item); 9694 if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api); 9695 9696 var images = findImageInElement(holder); 9697 9698 //Trigger the onBeforeLoad callback 9699 if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item); 9700 if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api); 9701 9702 iL.loadImage(images, function() { 9703 //Trigger the onAfterLoad callback 9704 if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item); 9705 if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api); 9706 9707 holder.show().data({ 9708 naturalWidth: (elWidth || container.outerWidth()), 9709 naturalHeight: (elHeight || container.outerHeight()) 9710 }).hide(); 9711 el.remove(); 9712 9713 iL.configureHolder(obj, opt, holder); 9714 }); 9715 9716 break; 9717 } 9718 }, 9719 9720 configureHolder: function(obj, opt, holder) { 9721 var iL = this, 9722 vars = iL.vars, 9723 opts = iL.options; 9724 9725 if (opt != "current")(opt == "next") ? holder.addClass('ilightbox-next') : holder.addClass('ilightbox-prev'); 9726 9727 if (opt == "current") 9728 var item = vars.current; 9729 else if (opt == "next") 9730 var opacity = opts.styles.nextOpacity, 9731 item = vars.next; 9732 else 9733 var opacity = opts.styles.prevOpacity, 9734 item = vars.prev; 9735 9736 var api = { 9737 element: holder, 9738 position: item 9739 }; 9740 9741 iL.items[item].options.width = iL.items[item].options.width || 0, 9742 iL.items[item].options.height = iL.items[item].options.height || 0; 9743 9744 if (opt == "current") { 9745 if (opts.show.effect) holder.css(transform, gpuAcceleration).fadeIn(obj.speed, function() { 9746 holder.css(transform, ''); 9747 if (obj.caption) { 9748 iL.setCaption(obj, holder); 9749 var caption = $('div.ilightbox-caption', holder), 9750 percent = parseInt((caption.outerHeight() / holder.outerHeight()) * 100); 9751 if (opts.caption.start & percent <= 50) caption.fadeIn(opts.effects.fade
9751Speed); 9752 } 9753 9754 var social = obj.options.social; 9755 if (social) { 9756 iL.setSocial(social, obj.URL, holder); 9757 if (opts.social.start) $('div.ilightbox-social', holder).fadeIn(opts.effects.fadeSpeed); 9758 } 9759 9760 //Generate thumbnails 9761 iL.generateThumbnails(); 9762 9763 //Trigger the onShow callback 9764 if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item); 9765 if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api); 9766 }); 9767 else { 9768 holder.show(); 9769 9770 //Generate thumbnails 9771 iL.generateThumbnails(); 9772 9773 //Trigger the onShow callback 9774 if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item); 9775 if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api); 9776 } 9777 } else { 9778 if (opts.show.effect) holder.fadeTo(obj.speed, opacity, function() { 9779 if (opt == "next") vars.nextLock = false; 9780 else vars.prevLock = false; 9781 9782 //Generate thumbnails 9783 iL.generateThumbnails(); 9784 9785 //Trigger the onShow callback 9786 if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item); 9787 if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api); 9788 }); 9789 else { 9790 holder.css({ 9791 opacity: opacity 9792 }).show(); 9793 if (opt == "next") vars.nextLock = false; 9794 else vars.prevLock = false; 9795 9796 //Generate thumbnails 9797 iL.generateThumbnails(); 9798 9799 //Trigger the onShow callback 9800 if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item); 9801 if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api); 9802 } 9803 } 9804 9805 setTimeout(function() { 9806 iL.repositionPhoto(); 9807 }, 0); 9808 }, 9809 9810 generateBoxes: function() { 9811 var iL = this, 9812 vars = iL.vars, 9813 opts = iL.options; 9814 9815 if (opts.infinite && vars.total >= 3) { 9816 if (vars.current == vars.total - 1) vars.next = 0; 9817 if (vars.current == 0) vars.prev = vars.total - 1; 9818 } else opts.infinite = false; 9819 9820 //UNCODE addition 9821 if ( typeof iL.items[vars.current] == 'undefined' ) 9822 vars.current = 0; 9823 9824 iL.loadContent(iL.items[vars.current], 'current', opts.show.speed); 9825 9826 if (iL.items[vars.next]) iL.loadContent(iL.items[vars.next], 'next', opts.show.speed); 9827 if (iL.items[vars.prev]) iL.loadContent(iL.items[vars.prev], 'prev', opts.show.speed); 9828 }, 9829 9830 generateThumbnails: function() { 9831 var iL = this, 9832 vars = iL.vars, 9833 opts = iL.options, 9834 timeOut = null; 9835 9836 if (vars.thumbs && !iL.vars.dontGenerateThumbs) { 9837 var thumbnails = vars.thumbnails, 9838 container = $('div.ilightbox-thumbnails-container', thumbnails), 9839 grid = $('div.ilightbox-thumbnails-grid', container), 9840 i = 0; 9841 9842 grid.removeAttr('style').empty(); 9843 9844 $.each(iL.items, function(key, val) { 9845 var isActive = (vars.current == key) ? 'ilightbox-active' : '', 9846 opacity = (vars.current == key) ? opts.thumbnails.activeOpacity : opts.thumbnails.normalOpacity, 9847 thumb = val.options.thumbnail, 9848 thumbnail = $('<div class="ilightbox-thumbnail"></div>'), 9849 icon = $('<div class="ilightbox-thumbnail-icon"></div>'); 9850 9851 thumbnail.css({ 9852 opacity: 0 9853 }).addClass(isActive); 9854 9855 if ((val.type == "video" || val.type == "flash") && typeof val.options.icon == 'undefined') { 9856 icon.addClass('ilightbox-thumbnail-video'); 9857 thumbnail.append(icon); 9858 } else if (val.options.icon) { 9859 icon.addClass('ilightbox-thumbnail-' + val.options.icon); 9860 thumbnail.append(icon); 9861 } 9862 9863 if (thumb) iL.loadImage(thumb, function(img) { 9864 i++; 9865 if (img) thumbnail.data({ 9866 naturalWidth: img.width, 9867 naturalHeight: img.height 9868 }).append('<img src="' + thumb + '" border="0" />'); 9869 else thumbnail.data({ 9870 naturalWidth: opts.thumbnails.maxWidth, 9871 naturalHeight: opts.thumbnails.maxHeight 9872 }); 9873 9874 clearTimeout(timeOut); 9875 timeOut = setTimeout(function() { 9876 iL.positionThumbnails(thumbnails, container, grid); 9877 }, 20); 9878 setTimeout(function() { 9879 thumbnail.fadeTo(opts.effects.loadedFadeSpeed, opacity); 9880 }, i * 20); 9881 }); 9882 9883 grid.append(thumbnail); 9884 }); 9885 iL.vars.dontGenerateThumbs = true; 9886 } 9887 }, 9888
9889 positionThumbnails: function(thumbnails, container, grid) { 9890 var iL = this, 9891 vars = iL.vars, 9892 opts = iL.options, 9893 viewport = getViewport(), 9894 path = opts.path.toLowerCase(); 9895 9896 if (!thumbnails) thumbnails = vars.thumbnails; 9897 if (!container) container = $('div.ilightbox-thumbnails-container', thumbnails); 9898 if (!grid) grid = $('div.ilightbox-thumbnails-grid', container); 9899 9900 var thumbs = $('.ilightbox-thumbnail', grid), 9901 widthAvail = (path == 'horizontal') ? viewport.width - opts.styles.pageOffsetX : thumbs.eq(0).outerWidth() - opts.styles.pageOffsetX, 9902 heightAvail = (path == 'horizontal') ? thumbs.eq(0).outerHeight() - opts.styles.pageOffsetY : viewport.height - opts.styles.pageOffsetY, 9903 gridWidth = (path == 'horizontal') ? 0 : widthAvail, 9904 gridHeight = (path == 'horizontal') ? heightAvail : 0, 9905 active = $('.ilightbox-active', grid), 9906 gridCss = {}, 9907 css = {}; 9908 9909 if (arguments.length < 3) { 9910 thumbs.css({ 9911 opacity: opts.thumbnails.normalOpacity 9912 }); 9913 active.css({ 9914 opacity: opts.thumbnails.activeOpacity 9915 }); 9916 } 9917 9918 thumbs.each(function(i) { 9919 var t = $(this), 9920 data = t.data(), 9921 width = (path == 'horizontal') ? 0 : opts.thumbnails.maxWidth; 9922 height = (path == 'horizontal') ? opts.thumbnails.maxHeight : 0; 9923 dims = iL.getNewDimenstions(width, height, data.naturalWidth, data.naturalHeight, true); 9924 9925 t.css({ 9926 width: dims.width, 9927 height: dims.height 9928 }); 9929 if (path == 'horizontal') t.css({ 9930 'float': 'left' 9931 }); 9932 9933 (path == 'horizontal') ? ( 9934 gridWidth += t.outerWidth() 9935 ) : ( 9936 gridHeight += t.outerHeight() 9937 ); 9938 }); 9939 9940 gridCss = { 9941 width: gridWidth, 9942 height: gridHeight 9943 }; 9944 9945 grid.css(gridCss); 9946 9947 gridCss = {}; 9948 9949 var gridOffset = grid.offset(), 9950 activeOffset = (active.length) ? active.offset() : { 9951 top: parseInt(heightAvail / 2), 9952 left: parseInt(widthAvail / 2) 9953 }; 9954 9955 gridOffset.top = (gridOffset.top - $doc.scrollTop()), 9956 gridOffset.left = (gridOffset.left - $doc.scrollLeft()), 9957 activeOffset.top = (activeOffset.top - gridOffset.top - $doc.scrollTop()), 9958 activeOffset.left = (activeOffset.left - gridOffset.left - $doc.scrollLeft()); 9959 9960 (path == 'horizontal') ? ( 9961 gridCss.top = 0, 9962 gridCss.left = parseInt((widthAvail / 2) - activeOffset.left - (active.outerWidth() / 2)) 9963 ) : ( 9964 gridCss.top = parseInt(((heightAvail / 2) - activeOffset.top - (active.outerHeight() / 2))), 9965 gridCss.left = 0 9966 ); 9967 9968 if (arguments.length < 3) grid.stop().animate(gridCss, opts.effects.repositionSpeed, 'easeOutCirc'); 9969 else grid.css(gridCss); 9970 }, 9971 9972 loadImage: function(image, callback) { 9973 if (!$.isArray(image)) image = [image]; 9974 9975 var iL = this, 9976 length = image.length; 9977 9978 if (length > 0) { 9979 iL.showLoader(); 9980 $.each(image, function(index, value) { 9981 var img = new Image(); 9982 img.onload = function() { 9983 length -= 1; 9984 if (length == 0) { 9985 iL.hideLoader(); 9986 callback(img); 9987 } 9988 }; 9989 img.onerror = img.onabort = function() { 9990 length -= 1; 9991 if (length == 0) { 9992 iL.hideLoader(); 9993 callback(false); 9994 } 9995 }; 9996 img.src = image[index]; 9997 }); 9998 } else callback(false); 9999 }, 10000 10001 patchItemsEvents: function() { 10002 var iL = this, 10003 vars = iL.vars, 10004 clickEvent = supportTouch ? "itap.iL" : "click.iL", 10005 vEvent = supportTouch ? "click.iL" : "itap.iL"; 10006 10007 if (iL.context && iL.selector) { 10008 var $items = $(iL.selector, iL.context); 10009 10010 $(iL.context).on(clickEvent, iL.selector, function() { 10011 var $this = $(this), 10012 //UNCODE addition 10013 key = typeof $(this).data('lb-index') !== '' && $(this).closest('.owl-item').length ? $(this).data('lb-index') : $items.index($this); 10014 if (UNCODE.isMobile) { 10015 var isCarousel = $this.closest('.owl-carousel'); 10016 if (isCarousel.length) { 10017 if (isCarousel.hasClass('owl-translating')) return false; 10018 } 10019 } 10020 10021 vars.current = key; 10022 vars.next = iL.items[key + 1] ? key + 1 : null; 10023 vars.prev = iL.items[key - 1] ? key - 1 : null; 10024 10025 //UNCODE addition 10026 if ( vars.BODY.hasClass('fp-slide-scrolling') ) 10027 return false;
10028 10029 iL.addContents(); 10030 iL.patchEvents(); 10031 10032 return false; 10033 }).on(vEvent, iL.selector, function() { 10034 return false; 10035 }); 10036 } else 10037 $.each(iL.itemsObject, function(key, val) { 10038 val.on(clickEvent, function() { 10039 vars.current = key; 10040 vars.next = iL.items[key + 1] ? key + 1 : null; 10041 vars.prev = iL.items[key - 1] ? key - 1 : null; 10042 10043 iL.addContents(); 10044 iL.patchEvents(); 10045 10046 return false; 10047 }).on(vEvent, function() { 10048 return false; 10049 }); 10050 }); 10051 }, 10052 10053 dispatchItemsEvents: function() { 10054 var iL = this, 10055 vars = iL.vars, 10056 opts = iL.options; 10057 10058 if (iL.context && iL.selector) 10059 $(iL.context).off('.iL', iL.selector); 10060 else 10061 $.each(iL.itemsObject, function(key, val) { 10062 val.off('.iL'); 10063 }); 10064 }, 10065 10066 refresh: function() { 10067 var iL = this; 10068 10069 iL.dispatchItemsEvents(); 10070 iL.attachItems(); 10071 iL.normalizeItems(); 10072 iL.patchItemsEvents(); 10073 }, 10074 10075 patchEvents: function() { 10076 var iL = this, 10077 vars = iL.vars, 10078 opts = iL.options, 10079 path = opts.path.toLowerCase(), 10080 holders = $('.ilightbox-holder'), 10081 fullscreenEvent = fullScreenApi.fullScreenEventName + '.iLightBox', 10082 durationThreshold = 1000, 10083 horizontalDistanceThreshold = 10084 verticalDistanceThreshold = 100, 10085 buttonsArray = [vars.nextButton[0], vars.prevButton[0], vars.nextButton[0].firstChild, vars.prevButton[0].firstChild]; 10086 10087 $win.bind('resize.iLightBox', function() { 10088 var viewport = getViewport(); 10089 10090 if (opts.mobileOptimizer && !opts.innerToolbar) vars.isMobile = viewport.width <= vars.mobileMaxWidth; 10091 vars.BODY[vars.isMobile ? 'addClass' : 'removeClass']('isMobile'); 10092 10093 iL.repositionPhoto(null); 10094 if (supportTouch) { 10095 clearTimeout(vars.setTime); 10096 vars.setTime = setTimeout(function() { 10097 var scrollTop = getScrollXY().y; 10098 window.scrollTo(0, scrollTop - 30); 10099 window.scrollTo(0, scrollTop + 30); 10100 window.scrollTo(0, scrollTop); 10101 }, 2000); 10102 } 10103 if (vars.thumbs) iL.positionThumbnails(); 10104 }).bind('keydown.iLightBox', function(event) { 10105 if (opts.controls.keyboard) { 10106 switch (event.keyCode) { 10107 case 13: 10108 if (event.shiftKey && opts.keyboard.shift_enter) iL.fullScreenAction(); 10109 break; 10110 case 27: 10111 if (opts.keyboard.esc) iL.closeAction(); 10112 break; 10113 case 37: 10114 if (opts.keyboard.left && !vars.lockKey) iL.moveTo('prev'); 10115 break; 10116 case 38: 10117 if (opts.keyboard.up && !vars.lockKey) iL.moveTo('prev'); 10118 break; 10119 case 39: 10120 if (opts.keyboard.right && !vars.lockKey) iL.moveTo('next'); 10121 break; 10122 case 40: 10123 if (opts.keyboard.down && !vars.lockKey) iL.moveTo('next'); 10124 break; 10125 } 10126 } 10127 }); 10128 10129 if (fullScreenApi.supportsFullScreen) $win.bind(fullscreenEvent, function() { 10130 iL.doFullscreen(); 10131 }); 10132 10133 var holderEventsArr = [opts.caption.show + '.iLightBox', opts.caption.hide + '.iLightBox', opts.social.show + '.iLightBox', opts.social.hide + '.iLightBox'].filter(function(e, i, arr) { 10134 return arr.lastIndexOf(e) === i; 10135 }), 10136 holderEvents = ""; 10137 10138 $.each(holderEventsArr, function(key, val) { 10139 if (key != 0) holderEvents += ' '; 10140 holderEvents += val; 10141 }); 10142 10143 $doc.on(clickEvent, '.ilightbox-overlay', function() { 10144 if (opts.overlay.blur) iL.closeAction(); 10145 }).on(clickEvent, '.ilightbox-next, .ilightbox-next-button', function() { 10146 iL.moveTo('next'); 10147 }).on(clickEvent, '.ilightbox-prev, .ilightbox-prev-button', function() { 10148 iL.moveTo('prev'); 10149 }).on(clickEvent, '.ilightbox-thumbnail', function() { 10150 var t = $(this), 10151 thumbs = $('.ilightbox-thumbnail', vars.thumbnails), 10152 index = thumbs.index(t); 10153 10154 if (index != vars.current) iL.goTo(index); 10155 }).on(holderEvents, '.ilightbox-holder:not(.ilightbox-next, .ilightbox-prev)', function(e) { 10156 var caption = $('div.ilightbox-caption', vars.holder), 10157 social = $('div.ilightbox-social', vars.holder), 10158 fadeSpeed = opts.effects.fadeSpeed; 10159 10160 if (vars.nextLock || vars.prevLock) { 10161 if (e.type == opts.caption.show && !caption.is(':visible')) caption.fadeIn(fadeSpeed); 10162 else if (e.type == opts.caption.hide && caption.is(':visible')) caption.fadeOut(fadeSpeed); 10163 10164 if (e.type == opts.social.show && !social.is(':visible')) social.fadeIn(fadeSpeed); 10165 else if (e.type == opts.social.hide && social.is(':visible')) social.fadeOut(fadeSpeed); 10166 } else { 10167 if (e.type == opts.caption.show && !caption.is(':visible')) caption.stop().fadeIn(fadeSpeed); 10168 else if (e.type == opts.caption.hide && caption.is(':visible')) caption.stop().fadeOut(fadeSpeed); 10169 10170 if (e.type == opts.social.show && !social.is(':visible')) social.stop().fadeIn(fadeSpeed); 10171 else if (e.type == opts.social.hide && social.is(':visible')) social.stop().fadeOut(fadeSpeed); 10172 } 10173 }).on('mouseenter.iLightBox mouseleave.iLightBox', '.ilightbox-wrapper', function(e) { 10174 if (e.type == 'mouseenter') vars.lockWheel = true; 10175 else vars.lockWheel = false;
10176 }).on(clickEvent, '.ilightbox-toolbar a.ilightbox-close, .ilightbox-toolbar a.ilightbox-fullscreen, .ilightbox-toolbar a.ilightbox-play, .ilightbox-toolbar a.ilightbox-pause', function() { 10177 var t = $(this); 10178 10179 if (t.hasClass('ilightbox-fullscreen')) iL.fullScreenAction(); 10180 else if (t.hasClass('ilightbox-play')) { 10181 iL.resume(); 10182 t.addClass('ilightbox-pause').removeClass('ilightbox-play'); 10183 } else if (t.hasClass('ilightbox-pause')) { 10184 iL.pause(); 10185 t.addClass('ilightbox-play').removeClass('ilightbox-pause'); 10186 } else iL.closeAction(); 10187 }).on(touchMoveEvent, '.ilightbox-overlay, .ilightbox-thumbnails-container', function(e) { 10188 // prevent scrolling 10189 e.preventDefault(); 10190 }); 10191 10192 function mouseMoveHandler(e) { 10193 if (!vars.isMobile) { 10194 if (!vars.mouseID) { 10195 vars.hideableElements.show(); 10196 } 10197 10198 vars.mouseID = clearTimeout(vars.mouseID); 10199 10200 if (buttonsArray.indexOf(e.target) === -1) 10201 vars.mouseID = setTimeout(function() { 10202 vars.hideableElements.hide(); 10203 vars.mouseID = clearTimeout(vars.mouseID); 10204 }, 3000); 10205 } 10206 } 10207 10208 if (opts.controls.arrows && !supportTouch) $doc.on('mousemove.iLightBox', mouseMoveHandler); 10209 10210 if (opts.controls.slideshow && opts.slideshow.pauseOnHover) $doc.on('mouseenter.iLightBox mouseleave.iLightBox', '.ilightbox-holder:not(.ilightbox-next, .ilightbox-prev)', function(e) { 10211 if (e.type == 'mouseenter' && vars.cycleID) iL.pause(); 10212 else if (e.type == 'mouseleave' && vars.isPaused) iL.resume(); 10213 }); 10214 10215 var switchers = $('.ilightbox-overlay, .ilightbox-holder, .ilightbox-thumbnails'); 10216 10217 if (opts.controls.mousewheel) switchers.on('mousewheel.iLightBox', function(event, delta) { 10218 if (!vars.lockWheel) { 10219 event.preventDefault(); 10220 if (delta < 0) iL.moveTo('next'); 10221 else if (delta > 0) iL.moveTo('prev'); 10222 } 10223 }); 10224 10225 if (opts.controls.swipe) holders.on(touchStartEvent, function(event) { 10226 if (vars.nextLock || vars.prevLock || vars.total == 1 || vars.lockSwipe) return; 10227 10228 vars.BODY.addClass('ilightbox-closedhand'); 10229 10230 var data = event.originalEvent.touches ? event.originalEvent.touches[0] : event, 10231 scrollTop = $doc.scrollTop(), 10232 scrollLeft = $doc.scrollLeft(), 10233 offsets = [ 10234 holders.eq(0).offset(), 10235 holders.eq(1).offset(), 10236 holders.eq(2).offset() 10237 ], 10238 offSet = [{ 10239 top: offsets[0].top - scrollTop, 10240 left: offsets[0].left - scrollLeft 10241 }, { 10242 top: offsets[1].top - scrollTop, 10243 left: offsets[1].left - scrollLeft 10244 }, { 10245 top: offsets[2].top - scrollTop, 10246 left: offsets[2].left - scrollLeft 10247 }], 10248 start = { 10249 time: (new Date()).getTime(), 10250 coords: [data.pageX - scrollLeft, data.pageY - scrollTop] 10251 }, 10252 stop; 10253 10254 function moveEachHandler(i) { 10255 var t = $(this), 10256 offset = offSet[i], 10257 scroll = [(start.coords[0] - stop.coords[0]), (start.coords[1] - stop.coords[1])]; 10258 10259 t[0].style[path == "horizontal" ? 'left' : 'top'] = (path == "horizontal" ? offset.left - scroll[0] : offset.top - scroll[1]) + 'px'; 10260 } 10261 10262 function moveHandler(event) { 10263 10264 if (!start) return; 10265 10266 var data = event.originalEvent.touches ? event.originalEvent.touches[0] : event; 10267 10268 stop = { 10269 time: (new Date()).getTime(), 10270 coords: [data.pageX - scrollLeft, data.pageY - scrollTop] 10271 }; 10272 10273 holders.each(moveEachHandler); 10274 10275 // prevent scrolling 10276 event.preventDefault(); 10277 } 10278 10279 function repositionHolders() { 10280 holders.each(function() { 10281 var t = $(this), 10282 offset = t.data('offset') || { 10283 top: t.offset().top - scrollTop, 10284 left: t.offset().left - scrollLeft 10285 }, 10286 top = offset.top, 10287 left = offset.left; 10288 10289 t.css(transform, gpuAcceleration).stop().animate({ 10290 top: top, 10291 left: left 10292 }, 500, 'easeOutCirc', function() { 10293 t.css(transform, ''); 10294 }); 10295 }); 10296 } 10297 10298 holders.bind(touchMoveEvent, moveHandler); 10299 $doc.one(touchStopEvent, function(event) { 10300 holders.unbind(touchMoveEvent, moveHandler); 10301 10302 vars.BODY.removeClass('ilightbox-closedhand'); 10303 10304 if (start && stop) { 10305 if (path == "horizontal" && stop.time - start.time < durationThreshold && abs(start.coords[0] - stop.coords[0]) > horizontalDistanceThreshold && abs(start.coords[1] - stop.coords[1]) < verticalDistanceThreshold) { 10306 if (start.coords[0] > stop.coords[0]) { 10307 if (vars.current == vars.total - 1 && !opts.infinite) repositionHolders(); 10308 else { 10309 vars.isSwipe = true; 10310 iL.moveTo('next'); 10311 } 10312 } else { 10313 if (vars.current == 0 && !opts.infinite) repositionHolders(); 10314 else { 10315 vars.isSwipe = true; 10316 iL.moveTo('prev'); 10317 } 10318 } 10319 } 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) { 10320 if (start.coords[1] > stop.coords[1]) { 10321 if (vars.current == vars.total - 1 && !opts.infinite) repositionHolders(); 10322 else { 10323 vars.isSwipe = true; 10324 iL.moveTo('next'); 10325 } 10326 } else { 10327 if (vars.current == 0 && !opts.infinite) repositionHolders(); 10328 else { 10329 vars.isSwipe = true; 10330 iL.moveTo('prev'); 10331 } 10332 } 10333 } else repositionHolders(); 10334 } 10335 start = stop = undefined; 10336 }); 10337 }); 10338 10339 }, 10340 10341 goTo: function(index) { 10342 var iL = this, 10343 vars = iL.vars, 10344 opts = iL.options, 10345 diff = (index - vars.current); 10346 10347 if (opts.infinite) { 10348 if (index == vars.total - 1 && vars.current == 0) diff = -1; 10349 if (vars.current == vars.total - 1 && index == 0) diff = 1; 10350 } 10351 10352 if (diff == 1) iL.moveTo('next'); 10353 else if (diff == -1) iL.moveTo('prev'); 10354 else { 10355 10356 if (vars.nextLock || vars.prevLock) return false;
10357 10358 //Trigger the onBeforeChange callback 10359 if (typeof opts.callback.onBeforeChange == 'function') opts.callback.onBeforeChange.call(iL, iL.ui); 10360 10361 if (opts.linkId) { 10362 vars.hashLock = true; 10363 window.location.hash = opts.linkId + '/' + index; 10364 } 10365 10366 if (iL.items[index]) { 10367 if (!iL.items[index].options.mousewheel) vars.lockWheel = true; 10368 else iL.vars.lockWheel = false; 10369 10370 if (!iL.items[index].options.swipe) vars.lockSwipe = true; 10371 else vars.lockSwipe = false; 10372 } 10373 10374 $.each([vars.holder, vars.nextPhoto, vars.prevPhoto], function(key, val) { 10375 val.css(transform, gpuAcceleration).fadeOut(opts.effects.loadedFadeSpeed); 10376 }); 10377 10378 vars.current = index; 10379 vars.next = index + 1; 10380 vars.prev = index - 1; 10381 10382 iL.createUI(); 10383 10384 setTimeout(function() { 10385 iL.generateBoxes(); 10386 }, opts.effects.loadedFadeSpeed + 50); 10387 10388 $('.ilightbox-thumbnail', vars.thumbnails).removeClass('ilightbox-active').eq(index).addClass('ilightbox-active'); 10389 iL.positionThumbnails(); 10390 10391 if (opts.linkId) setTimeout(function() { 10392 vars.hashLock = false; 10393 }, 55); 10394 10395 // Configure arrow buttons 10396 if (!opts.infinite) { 10397 vars.nextButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled'); 10398 10399 if (vars.current == 0) { 10400 vars.prevButton.add(vars.innerPrevButton).addClass('disabled'); 10401 } 10402 if (vars.current >= vars.total - 1) { 10403 vars.nextButton.add(vars.innerNextButton).addClass('disabled'); 10404 } 10405 } 10406 10407 // Reset next cycle timeout 10408 iL.resetCycle(); 10409 10410 //Trigger the onAfterChange callback 10411 if (typeof opts.callback.onAfterChange == 'function') opts.callback.onAfterChange.call(iL, iL.ui); 10412 } 10413 }, 10414 10415 moveTo: function(side) { 10416 var iL = this, 10417 vars = iL.vars, 10418 opts = iL.options, 10419 path = opts.path.toLowerCase(), 10420 viewport = getViewport(), 10421 switchSpeed = opts.effects.switchSpeed; 10422 10423 if (vars.nextLock || vars.prevLock) return false; 10424 else { 10425 10426 var item = (side == "next") ? vars.next : vars.prev; 10427 10428 if (opts.linkId) { 10429 vars.hashLock = true; 10430 window.location.hash = opts.linkId + '/' + item; 10431 } 10432 10433 if (side == "next") { 10434 if (!iL.items[item]) return false; 10435 var firstHolder = vars.nextPhoto, 10436 secondHolder = vars.holder, 10437 lastHolder = vars.prevPhoto, 10438 firstClass = 'ilightbox-prev', 10439 secondClass = 'ilightbox-next'; 10440 } else if (side == "prev") { 10441 if (!iL.items[item]) return false; 10442 var firstHolder = vars.prevPhoto, 10443 secondHolder = vars.holder, 10444 lastHolder = vars.nextPhoto, 10445 firstClass = 'ilightbox-next', 10446 secondClass = 'ilightbox-prev'; 10447 } 10448 10449 //Trigger the onBeforeChange callback 10450 if (typeof opts.callback.onBeforeChange == 'function') 10451 opts.callback.onBeforeChange.call(iL, iL.ui); 10452 10453 (side == "next") ? vars.nextLock = true: vars.prevLock = true; 10454 10455 var captionFirst = $('div.ilightbox-caption', secondHolder), 10456 socialFirst = $('div.ilightbox-social', secondHolder); 10457 10458 if (captionFirst.length) 10459 captionFirst.stop().fadeOut(switchSpeed, function() { 10460 $(this).remove(); 10461 }); 10462 if (socialFirst.length) 10463 socialFirst.stop().fadeOut(switchSpeed, function() { 10464 $(this).remove(); 10465 }); 10466 10467 if (iL.items[item].caption) { 10468 iL.setCaption(iL.items[item], firstHolder); 10469 var caption = $('div.ilightbox-caption', firstHolder), 10470 percent = parseInt((caption.outerHeight() / firstHolder.outerHeight()) * 100); 10471 if (opts.caption.start && percent <= 50) caption.fadeIn(switchSpeed); 10472 } 10473 10474 var social = iL.items[item].options.social; 10475 if (social) { 10476 iL.setSocial(social, iL.items[item].URL, firstHolder); 10477 if (opts.social.start) $('div.ilightbox-social', firstHolder).fadeIn(opts.effects.fadeSpeed); 10478 } 10479 10480 $.each([firstHolder, secondHolder, lastHolder], function(key, val) { 10481 val.removeClass('ilightbox-next ilightbox-prev'); 10482 }); 10483 10484 var firstOffset = firstHolder.data('offset'), 10485 winW = (viewport.width - (opts.styles.pageOffsetX)), 10486 winH = (viewport.height - (opts.styles.pageOffsetY)), 10487 width = firstOffset.newDims.width, 10488 height = firstOffset.newDims.height, 10489 thumbsOffset = firstOffset.thumbsOffset, 10490 diff = firstOffset.diff, 10491 top = parseInt((winH / 2) - (height / 2) - diff.H - (thumbsOffset.H / 2)), 10492 left = parseInt((winW / 2) - (width / 2) - diff.W - (thumbsOffset.W / 2)); 10493 10494 var secondOffset = secondHolder.data('offset'), 10495 object = secondOffset.object; 10496 10497 /*if (object.item.caption && !isNaN(width) && !isNaN(height) && UNCODE.wwidth > UNCODE.mediaQuery) { 10498 var objRatio = width / height; 10499 height = height - vars.captionHeight; 10500 width = height * objRatio; 10501 top = path == 'horizontal' ? parseInt((winH / 2) - (height / 2) - diff.H - (thumbsOffset.H / 2)) : top, 10502 left = parseInt((winW / 2) - (width / 2) - diff.W - (thumbsOffset.W / 2)); 10503 }*/ 10504 10505 firstHolder.show().css(transform, gpuAcceleration).animate({ 10506 top: top, 10507 left: left, 10508 opacity: 1 10509 }, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc', function() { 10510 firstHolder.css(transform, ''); 10511 }); 10512 10513 $('div.ilightbox-container', firstHolder).animate({ 10514 width: width, 10515 height: height 10516 }, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc'); 10517 10518 diff = secondOffset.diff; 10519 10520 width = secondOffset.newDims.width, 10521 height = secondOffset.newDims.height; 10522 10523 width = parseInt(width * opts.styles[side == 'next' ? 'prevScale' : 'nextScale']), 10524 height = parseInt(height * opts.styles[side == 'next' ? 'prevScale' : 'nextScale']), 10525 top = (path == 'horizontal') ? parseInt((winH / 2) - object.offsetY - (height / 2) - diff.H - (thumbsOffset.H / 2)) : parseInt(winH - object.offsetX - diff.H - (thumbsOffset.H / 2)); 10526 10527 if (side == 'prev') 10528 left = (path == 'horizontal') ? parseInt(winW - object.offsetX - diff.W - (thumbsOffset.W / 2)) : parseInt((winW / 2) - (width / 2) - diff.W - object.offsetY - (thumbsOffset.W / 2)); 10529 else { 10530 top = (path == 'horizontal') ? top : parseInt(object.offsetX - diff.H - height - (thumbsOffset.H / 2)), 10531 left = (path == 'horizontal') ? parseInt(object.offsetX - diff.W - width - (thumbsOffset.W / 2)) : parseInt((winW / 2) - object.offsetY - (width / 2) - diff.W - (thumbsOffset.W / 2)); 10532 } 10533 10534 /*if (object.item.caption && !isNaN(width) && !isNaN(height) && UNCODE.wwidth > UNCODE.mediaQuery) { 10535 var objRatio = width / height; 10536 height = height - vars.captionHeight; 10537 width = height * objRatio; 10538 top = path == 'horizontal' ? parseInt((winH / 2) - (height / 2) - diff.H - (thumbsOffset.H / 2)) : top; 10539 }*/ 10540 10541 $('div.ilightbox-container', secondHolder).animate({ 10542 width: width, 10543 height: height 10544 }, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc'); 10545 10546 secondHolder.addClass(firstClass).css(transform, gpuAcceleration).animate({ 10547 top: top, 10548 left: left, 10549 opacity: opts.styles.prevOpacity, 10550 }, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc', function() { 10551 secondHolder.css(transform, ''); 10552
10553 $('.ilightbox-thumbnail', vars.thumbnails).removeClass('ilightbox-active').eq(item).addClass('ilightbox-active'); 10554 iL.positionThumbnails(); 10555 10556 if (iL.items[item]) { 10557 if (!iL.items[item].options.mousewheel) vars.lockWheel = true; 10558 else vars.lockWheel = false; 10559 10560 if (!iL.items[item].options.swipe) vars.lockSwipe = true; 10561 else vars.lockSwipe = false; 10562 } 10563 10564 vars.isSwipe = false; 10565 10566 // Remove iframe & video from previous slide 10567 if (['iframe', 'video'].indexOf(iL.items[vars.current].type) !== -1) { 10568 $('div.ilightbox-container', secondHolder).empty(); 10569 } 10570 10571 if (side == "next") { 10572 vars.nextPhoto = lastHolder, 10573 vars.prevPhoto = secondHolder, 10574 vars.holder = firstHolder; 10575 10576 vars.nextPhoto.hide(); 10577 10578 vars.next = vars.next + 1, 10579 vars.prev = vars.current, 10580 vars.current = vars.current + 1; 10581 10582 if (opts.infinite) { 10583 if (vars.current > vars.total - 1) vars.current = 0; 10584 if (vars.current == vars.total - 1) vars.next = 0; 10585 if (vars.current == 0) vars.prev = vars.total - 1; 10586 } 10587 10588 iL.createUI(); 10589 10590 if (!iL.items[vars.next]) 10591 vars.nextLock = false; 10592 else 10593 iL.loadContent(iL.items[vars.next], 'next'); 10594 } else { 10595 vars.prevPhoto = lastHolder; 10596 vars.nextPhoto = secondHolder; 10597 vars.holder = firstHolder; 10598 10599 vars.prevPhoto.hide(); 10600 10601 vars.next = vars.current; 10602 vars.current = vars.prev; 10603 vars.prev = vars.current - 1; 10604 10605 if (opts.infinite) { 10606 if (vars.current == vars.total - 1) vars.next = 0; 10607 if (vars.current == 0) vars.prev = vars.total - 1; 10608 } 10609 10610 iL.createUI(); 10611 10612 if (!iL.items[vars.prev]) 10613 vars.prevLock = false; 10614 else 10615 iL.loadContent(iL.items[vars.prev], 'prev'); 10616 } 10617 10618 // Add iframe & video content for current slide 10619 if (['iframe', 'video'].indexOf(iL.items[vars.current].type) !== -1) { 10620 iL.loadContent(iL.items[vars.current], 'current'); 10621 } 10622 10623 if (opts.linkId) setTimeout(function() { 10624 vars.hashLock = false; 10625 }, 55); 10626 10627 // Configure arrow buttons 10628 if (!opts.infinite) { 10629 vars.nextButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled'); 10630 10631 if (vars.current == 0) 10632 vars.prevButton.add(vars.innerPrevButton).addClass('disabled'); 10633 if (vars.current >= vars.total - 1) 10634 vars.nextButton.add(vars.innerNextButton).addClass('disabled'); 10635 } 10636 10637 iL.repositionPhoto(); 10638 10639 // Reset next cycle timeout 10640 iL.resetCycle(); 10641 10642 //Trigger the onAfterChange callback 10643 if (typeof opts.callback.onAfterChange == 'function') 10644 opts.callback.onAfterChange.call(iL, iL.ui); 10645 }); 10646 10647 top = (path == 'horizontal') ? getPixel(lastHolder, 'top') : ((side == "next") ? parseInt(-(winH / 2) - lastHolder.outerHeight()) : parseInt(top * 2)), 10648 left = (path == 'horizontal') ? ((side == "next") ? parseInt(-(winW / 2) - lastHolder.outerWidth()) : parseInt(left * 2)) : getPixel(lastHolder, 'left'); 10649 10650 lastHolder.css(transform, gpuAcceleration).animate({ 10651 top: top, 10652 left: left, 10653 opacity: opts.styles.nextOpacity 10654 }, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc', function() { 10655 lastHolder.css(transform, ''); 10656 }).addClass(secondClass); 10657 } 10658 }, 10659 10660 setCaption: function(obj, target) { 10661 var iL = this, 10662 caption = $('<div class="ilightbox-caption"></div>'); 10663 10664 if (obj.caption) { 10665 caption.html(obj.caption); 10666 $('div.ilightbox-container', target).append(caption); 10667 } 10668 }, 10669 10670 normalizeSocial: function(obj, url) { 10671 var iL = this, 10672 vars = iL.vars, 10673 opts = iL.options, 10674 baseURL = window.location.href; 10675 10676 $.each(obj, function(key, value) { 10677 if (!value) 10678 return true; 10679 10680 var item = key.toLowerCase(), 10681 source, text; 10682 10683 switch (item) { 10684 case 'facebook': 10685 source = "http://www.facebook.com/share.php?v=4&src=bm&u={URL}", 10686 text = "Share on Facebook"; 10687 break; 10688 case 'twitter': 10689 source = "http://twitter.com/home?status={URL}", 10690 text = "Share on Twitter"; 10691 break; 10692 case 'googleplus': 10693 source = "https://plus.google.com/share?url={URL}", 10694 text = "Share on Google+"; 10695 break; 10696 case 'delicious': 10697 source = "http://delicious.com/post?url={URL}", 10698 text = "Share on Delicious"; 10699 break; 10700 case 'digg': 10701 source = "http://digg.com/submit?phase=2&url={URL}", 10702 text = "Share on Digg"; 10703 break; 10704 case 'reddit': 10705 source = "http://reddit.com/submit?url={URL}", 10706 text = "Share on reddit"; 10707 break; 10708 } 10709 10710 obj[key] = { 10711 URL: value.URL && absolutizeURI(baseURL, value.URL) || opts.linkId && window.location.href || typeof url !== 'string' && baseURL || url && absolutizeURI(baseURL, url) || baseURL, 10712 source: value.source || source || value.URL && absolutizeURI(baseURL, value.URL) || url && absolutizeURI(baseURL, url), 10713 text: value.text || text || "Share on " + key, 10714 width: (typeof(value.width) != 'undefined' && !isNaN(value.width)) ? parseInt(value.width) : 640, 10715 height: value.height || 360 10716 }; 10717 10718 }); 10719 10720 return obj; 10721 }, 10722 10723 setSocial: function(obj, url, target) { 10724 var iL = this, 10725 socialBar = $('<div class="ilightbox-social"></div>'), 10726 buttons = '<ul>'; 10727 10728 obj = iL.normalizeSocial(obj, url); 10729 10730 $.each(obj, function(key, value) { 10731 var item = key.toLowerCase(), 10732 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, '+')); 10733 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>'; 10734 }); 10735 10736 buttons += '</ul>'; 10737 10738 socialBar.html(buttons); 10739 $('div.ilightbox-container', target).append(socialBar); 10740 }, 10741 10742 fullScreenAction: function() { 10743 var iL = this, 10744 vars = iL.vars; 10745 10746 if (fullScreenApi.supportsFullScreen) { 10747 if (fullScreenApi.isFullScreen()) fullScreenApi.cancelFullScreen(document.documentElement); 10748 else fullScreenApi.requestFullScreen(document.documentElement); 10749 } else { 10750 iL.doFullscreen(); 10751 } 10752 }, 10753 10754 doFullscreen: function() { 10755 var iL = this, 10756 vars = iL.vars, 10757 viewport = getViewport(), 10758 opts = iL.options; 10759 10760 if (opts.fullAlone) { 10761 var currentHolder = vars.holder, 10762 current = iL.items[vars.current], 10763 windowWidth = viewport.width, 10764 windowHeight = viewport.height, 10765 elements = [currentHolder, vars.nextPhoto, vars.prevPhoto, vars.nextButton, vars.prevButton, vars.overlay, vars.toolbar, vars.thumbnails, vars.loader], 10766 hideElements = [vars.nextPhoto, vars.prevPhoto, vars.nextButton, vars.prevButton, vars.loader, vars.thumbnails]; 10767 10768 if (!vars.isInFullScreen) { 10769 vars.isInFullScreen = vars.lockKey = vars.lockWheel = vars.lockSwipe = true; 10770 vars.overlay.css({ 10771 opacity: 1 10772 }); 10773 10774 $.each(hideElements, function(i, element) { 10775 element.hide(); 10776 }); 10777 10778 vars.fullScreenButton.attr('title', opts.text.exitFullscreen); 10779 10780 if (opts.fullStretchTypes.indexOf(current.type) != -1) currentHolder.data({
10781 naturalWidthOld: currentHolder.data('naturalWidth'), 10782 naturalHeightOld: currentHolder.data('naturalHeight'), 10783 naturalWidth: windowWidth, 10784 naturalHeight: windowHeight 10785 }); 10786 else { 10787 var viewport = current.options.fullViewPort || opts.fullViewPort || '', 10788 newWidth = windowWidth, 10789 newHeight = windowHeight, 10790 width = currentHolder.data('naturalWidth'), 10791 height = currentHolder.data('naturalHeight'); 10792 10793 if (viewport.toLowerCase() == 'fill') { 10794 newHeight = (newWidth / width) * height; 10795 10796 if (newHeight < windowHeight) { 10797 newWidth = (windowHeight / height) * width, 10798 newHeight = windowHeight; 10799 } 10800 } else if (viewport.toLowerCase() == 'fit') { 10801 var dims = iL.getNewDimenstions(newWidth, newHeight, width, height, true); 10802 10803 newWidth = dims.width, 10804 newHeight = dims.height; 10805 } else if (viewport.toLowerCase() == 'stretch') { 10806 newWidth = newWidth, 10807 newHeight = newHeight; 10808 } else { 10809 var scale = (width > newWidth || height > newHeight) ? true : false, 10810 dims = iL.getNewDimenstions(newWidth, newHeight, width, height, scale); 10811 newWidth = dims.width, 10812 newHeight = dims.height; 10813 } 10814 10815 currentHolder.data({ 10816 naturalWidthOld: currentHolder.data('naturalWidth'), 10817 naturalHeightOld: currentHolder.data('naturalHeight'), 10818 naturalWidth: newWidth, 10819 naturalHeight: newHeight 10820 }); 10821 } 10822 10823 $.each(elements, function(key, val) { 10824 val.addClass('ilightbox-fullscreen'); 10825 }); 10826 10827 //Trigger the onEnterFullScreen callback 10828 if (typeof opts.callback.onEnterFullScreen == 'function') opts.callback.onEnterFullScreen.call(iL, iL.ui); 10829 } else { 10830 vars.isInFullScreen = vars.lockKey = vars.lockWheel = vars.lockSwipe = false; 10831 vars.overlay.css({ 10832 opacity: iL.options.overlay.opacity 10833 }); 10834 10835 $.each(hideElements, function(i, element) { 10836 element.show(); 10837 }); 10838 10839 vars.fullScreenButton.attr('title', opts.text.enterFullscreen); 10840 10841 currentHolder.data({ 10842 naturalWidth: currentHolder.data('naturalWidthOld'), 10843 naturalHeight: currentHolder.data('naturalHeightOld'), 10844 naturalWidthOld: null, 10845 naturalHeightOld: null 10846 }); 10847 10848 $.each(elements, function(key, val) { 10849 val.removeClass('ilightbox-fullscreen'); 10850 }); 10851 10852 //Trigger the onExitFullScreen callback 10853 if (typeof opts.callback.onExitFullScreen == 'function') opts.callback.onExitFullScreen.call(iL, iL.ui); 10854 } 10855 } else { 10856 if (!vars.isInFullScreen) vars.isInFullScreen = true; 10857 else vars.isInFullScreen = false; 10858 } 10859 iL.repositionPhoto(true); 10860 }, 10861 10862 closeAction: function() { 10863 var iL = this, 10864 vars = iL.vars, 10865 opts = iL.options; 10866 10867 $win.unbind('.iLightBox'); 10868 $doc.off('.iLightBox'); 10869 10870 if (vars.isInFullScreen) fullScreenApi.cancelFullScreen(document.documentElement); 10871 10872 $('.ilightbox-overlay, .ilightbox-holder, .ilightbox-thumbnails').off('.iLightBox'); 10873 10874 if (opts.hide.effect) vars.overlay.stop().fadeOut(opts.hide.speed, function() { 10875 vars.overlay.remove(); 10876 vars.BODY.removeClass('ilightbox-noscroll').off('.iLightBox'); 10877 }); 10878 else { 10879 vars.overlay.remove(); 10880 vars.BODY.removeClass('ilightbox-noscroll').off('.iLightBox'); 10881 } 10882 10883 var fadeOuts = [vars.toolbar, vars.holder, vars.nextPhoto, vars.prevPhoto, vars.nextButton, vars.prevButton, vars.loader, vars.thumbnails]; 10884 10885 $.each(fadeOuts, function(i, element) { 10886 element.removeAttr('style').remove(); 10887 }); 10888 10889 vars.dontGenerateThumbs = vars.isInFullScreen = false; 10890 10891 window.iLightBox = null; 10892 10893 if (opts.linkId) { 10894 vars.hashLock = true; 10895 removeHash(); 10896 setTimeout(function() { 10897 vars.hashLock = false; 10898 }, 55); 10899 } 10900 10901 //Trigger the onHide callback 10902 if (typeof opts.callback.onHide == 'function') opts.callback.onHide.call(iL, iL.ui); 10903 }, 10904 10905 repositionPhoto: function() { 10906 var iL = this, 10907 vars = iL.vars, 10908 opts = iL.options, 10909 path = opts.path.toLowerCase(), 10910 viewport = getViewport(), 10911 winWidth = viewport.width, 10912 winHeight = viewport.height; 10913 10914 if (viewport.width < UNCODE.mediaQuery) opts.styles.nextOffsetX = 0; 10915 10916 var thumbsOffsetW = (vars.isInFullScreen && opts.fullAlone || vars.isMobile) ? 0 : ((path == 'horizontal') ? 0 : vars.thumbnails.outerWidth()), 10917 thumbsOffsetH = vars.isMobile ? vars.toolbar.outerHeight() : ((vars.isInFullScreen && opts.fullAlone) ? 0 : ((path == 'horizontal') ? vars.thumbnails.outerHeight() : 0)), 10918 width = (vars.isInFullScreen && opts.fullAlone) ? winWidth : (winWidth - (opts.styles.pageOffsetX)), 10919 height = (vars.isInFullScreen && opts.fullAlone) ? winHeight : (winHeight - (opts.styles.pageOffsetY)), 10920 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, 10921 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))); 10922 10923 var elObject = { 10924 type: 'current', 10925 width: width, 10926 height: height, 10927 item: iL.items[vars.current], 10928 offsetW: offsetW, 10929 offsetH: offsetH,
10930 thumbsOffsetW: thumbsOffsetW, 10931 thumbsOffsetH: thumbsOffsetH, 10932 animate: arguments.length, 10933 holder: vars.holder 10934 }; 10935 10936 iL.repositionEl(elObject); 10937 10938 if (iL.items[vars.next]) { 10939 elObject = $.extend(elObject, { 10940 type: 'next', 10941 item: iL.items[vars.next], 10942 offsetX: opts.styles.nextOffsetX, 10943 offsetY: opts.styles.nextOffsetY, 10944 holder: vars.nextPhoto 10945 }); 10946 10947 iL.repositionEl(elObject); 10948 } 10949 10950 if (iL.items[vars.prev]) { 10951 elObject = $.extend(elObject, { 10952 type: 'prev', 10953 item: iL.items[vars.prev], 10954 offsetX: opts.styles.nextOffsetX, 10955 offsetY: opts.styles.prevOffsetY, 10956 holder: vars.prevPhoto 10957 }); 10958 10959 iL.repositionEl(elObject); 10960 } 10961 10962 var loaderCss = (path == "horizontal") ? { 10963 left: parseInt((width / 2) - (vars.loader.outerWidth() / 2)) 10964 } : { 10965 top: parseInt((height / 2) - (vars.loader.outerHeight() / 2)) 10966 }; 10967 vars.loader.css(loaderCss); 10968 }, 10969 10970 repositionEl: function(obj) { 10971 var iL = this, 10972 vars = iL.vars, 10973 opts = iL.options, 10974 path = opts.path.toLowerCase(), 10975 widthAvail = (obj.type == 'current') ? ((vars.isInFullScreen && opts.fullAlone) ? obj.width : (obj.width - obj.offsetW)) : (obj.width - obj.offsetW), 10976 heightAvail = (obj.type == 'current') ? ((vars.isInFullScreen && opts.fullAlone) ? obj.height : (obj.height - obj.offsetH)) : (obj.height - obj.offsetH), 10977 itemParent = obj.item, 10978 item = obj.item.options, 10979 holder = obj.holder, 10980 offsetX = obj.offsetX || 0, 10981 offsetY = obj.offsetY || 0, 10982 thumbsOffsetW = obj.thumbsOffsetW, 10983 thumbsOffsetH = obj.thumbsOffsetH; 10984 10985 if (obj.type == 'current') { 10986 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); 10987 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); 10988 } else { 10989 if (typeof item.width == 'number' && item.width) widthAvail = (item.width > widthAvail) ? widthAvail : item.width; 10990 if (typeof item.height == 'number' && item.height) heightAvail = (item.height > heightAvail) ? heightAvail : item.height; 10991 } 10992 10993 heightAvail = parseInt(heightAvail - $('.ilightbox-inner-toolbar', holder).outerHeight()); 10994 10995 var width = (typeof item.width == 'string' && item.width.indexOf('%') != -1) ? percentToValue(parseInt(item.width.replace('%', '')), obj.width) : holder.data('naturalWidth'), 10996 height = (typeof item.height == 'string' && item.height.indexOf('%') != -1) ? percentToValue(parseInt(item.height.replace('%', '')), obj.height) : holder.data('naturalHeight'); 10997 10998 var dims = ((typeof item.width == 'string' && item.width.indexOf('%') != -1 || typeof item.height == 'string' && item.height.indexOf('%') != -1) ? { 10999 width: width, 11000 height: height 11001 } : iL.getNewDimenstions(widthAvail, heightAvail, width, height)), 11002 newDims = $.extend({}, dims, {}); 11003 11004 if (obj.type == 'prev' || obj.type == 'next') 11005 width = parseInt(dims.width * ((obj.type == 'next') ? opts.styles.nextScale : opts.styles.prevScale)), 11006 height = parseInt(dims.height * ((obj.type == 'next') ? opts.styles.nextScale : opts.styles.prevScale)); 11007 else 11008 width = dims.width, 11009 height = dims.height; 11010 11011 var widthDiff = parseInt((getPixel(holder, 'padding-left') + getPixel(holder, 'padding-right') + getPixel(holder, 'border-left-width') + getPixel(holder, 'border-right-width')) / 2), 11012 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); 11013 11014 switch (obj.type) { 11015 case 'current': 11016 var top = parseInt((obj.height / 2) - (height / 2) - heightDiff - (thumbsOffsetH / 2)), 11017 left = parseInt((obj.width / 2) - (width / 2) - widthDiff - (thumbsOffsetW / 2)); 11018 break; 11019
11020 case 'next': 11021 var top = (path == 'horizontal') ? parseInt((obj.height / 2) - offsetY - (height / 2) - heightDiff - (thumbsOffsetH / 2)) : parseInt(obj.height - offsetX - heightDiff - (thumbsOffsetH / 2)), 11022 left = (path == 'horizontal') ? parseInt(obj.width - offsetX - widthDiff - (thumbsOffsetW / 2)) : parseInt((obj.width / 2) - (width / 2) - widthDiff - offsetY - (thumbsOffsetW / 2)); 11023 break; 11024 11025 case 'prev': 11026 var top = (path == 'horizontal') ? parseInt((obj.height / 2) - offsetY - (height / 2) - heightDiff - (thumbsOffsetH / 2)) : parseInt(offsetX - heightDiff - height - (thumbsOffsetH / 2)), 11027 left = (path == 'horizontal') ? parseInt(offsetX - widthDiff - width - (thumbsOffsetW / 2)) : parseInt((obj.width / 2) - offsetY - (width / 2) - widthDiff - (thumbsOffsetW / 2)); 11028 break; 11029 } 11030 11031 holder.data('offset', { 11032 top: top, 11033 left: left, 11034 newDims: newDims, 11035 diff: { 11036 W: widthDiff, 11037 H: heightDiff 11038 }, 11039 thumbsOffset: { 11040 W: thumbsOffsetW, 11041 H: thumbsOffsetH 11042 }, 11043 object: obj 11044 }); 11045 11046 var opacityMobile; 11047 if ( isMobile ) { 11048 opacityMobile = { 11049 opacity: 1, 11050 top: top, 11051 left: left 11052 }; 11053 } else { 11054 opacityMobile = { 11055 top: top, 11056 left: left 11057 }; 11058 } 11059 11060 if (obj.animate > 0 && opts.effects.reposition) { 11061 holder.css(transform, gpuAcceleration).stop().animate( 11062 opacityMobile, 11063 opts.effects.repositionSpeed, 'easeOutCirc', function() { 11064 holder.css(transform, ''); 11065 }); 11066 $('div.ilightbox-container', holder).stop().animate({ 11067 width: width, 11068 height: height 11069 }, opts.effects.repositionSpeed, 'easeOutCirc'); 11070 $('div.ilightbox-inner-toolbar', holder).stop().animate({ 11071 width: width 11072 }, opts.effects.repositionSpeed, 'easeOutCirc', function() { 11073 $(this).css('overflow', 'visible'); 11074 }); 11075 } else { 11076 holder.css(opacityMobile); 11077 $('div.ilightbox-container', holder).css({ 11078 width: width, 11079 height: height 11080 }); 11081 $('div.ilightbox-inner-toolbar', holder).css({ 11082 width: width 11083 }); 11084 } 11085 }, 11086 11087 11088 resume: function(priority) { 11089 var iL = this, 11090 vars = iL.vars, 11091 opts = iL.options; 11092 11093 if (!opts.slideshow.pauseTime || opts.controls.slideshow && vars.total <= 1 || priority < vars.isPaused) { 11094 return; 11095 } 11096 11097 vars.isPaused = 0; 11098 11099 if (vars.cycleID) { 11100 vars.cycleID = clearTimeout(vars.cycleID); 11101 } 11102 11103 vars.cycleID = setTimeout(function() { 11104 if (vars.current == vars.total - 1) iL.goTo(0); 11105 else iL.moveTo('next'); 11106 }, opts.slideshow.pauseTime); 11107 }, 11108 11109 pause: function(priority) { 11110 var iL = this, 11111 vars = iL.vars, 11112 opts = iL.options; 11113 11114 if (priority < vars.isPaused) { 11115 return; 11116 } 11117 11118 vars.isPaused = priority || 100; 11119 11120 if (vars.cycleID) { 11121 vars.cycleID = clearTimeout(vars.cycleID); 11122 } 11123 }, 11124 11125 resetCycle: function() { 11126 var iL = this, 11127 vars = iL.vars, 11128 opts = iL.options; 11129 11130 if (opts.controls.slideshow && vars.cycleID && !vars.isPaused) { 11131 iL.resume(); 11132 } 11133 }, 11134 11135 getNewDimenstions: function(width, height, width_old, height_old, thumb) { 11136 var iL = this; 11137 11138 if (!width) factor = height / height_old; 11139 else if (!height) factor = width / width_old; 11140 else factor = min(width / width_old, height / height_old); 11141 11142 if (!thumb) { 11143 if (factor > iL.options.maxScale) factor = iL.options.maxScale; 11144 else if (factor < iL.options.minScale) factor = iL.options.minScale; 11145 } 11146 11147 var final_width = (iL.options.keepAspectRatio) ? round(width_old * factor) : width, 11148 final_height = (iL.options.keepAspectRatio) ? round(height_old * factor) : height; 11149 11150 return { 11151 width: final_width, 11152 height: final_height, 11153 ratio: factor 11154 }; 11155 }, 11156 11157 setOption: function(options) { 11158 var iL = this; 11159 11160 iL.options = $.extend(true, iL.options, options || {}); 11161 iL.refresh(); 11162 }, 11163 11164 availPlugins: function() { 11165 var iL = this, 11166 testEl = document.createElement("video"); 11167 11168 iL.plugins = { 11169 flash: !isMobile, 11170 quicktime: (parseInt(PluginDetect.getVersion("QuickTime")) >= 0) ? true : false, 11171 html5H264: !!(testEl.canPlayType && testEl.canPlayType('video/mp4').replace(/no/, '')), 11172 html5WebM: !!(testEl.canPlayType && testEl.canPlayType('video/webm').replace(/no/, '')), 11173 html5Vorbis: !!(testEl.canPlayType && testEl.canPlayType('video/ogg').replace(/no/, '')), 11174 html5QuickTime: !!(testEl.canPlayType && testEl.canPlayType('video/quicktime').replace(/no/, '')) 11175 }; 11176 }, 11177 11178 addContent: function(element, obj) { 11179 var iL = this, 11180 el; 11181 11182 switch (obj.type) { 11183 case 'video': 11184 var HTML5 = false, 11185 videoType = obj.videoType, 11186 html5video = obj.options.html5video; 11187 11188 if (((videoType == 'video/mp4' || obj.ext == 'mp4' || obj.ext == 'm4v') || html5video.h264) && iL.plugins.html5H264) 11189 obj.ext = 'mp4', 11190 obj.URL = html5video.h264 || obj.URL; 11191 else if (html5video.webm && iL.plugins.html5WebM) 11192 obj.ext = 'webm', 11193 obj.URL = html5video.webm || obj.URL; 11194 else if (html5video.ogg && iL.plugins.html5Vorbis) 11195 obj.ext = 'ogv', 11196 obj.URL = html5video.ogg || obj.URL; 11197 11198 if (iL.plugins.html5H264 && (videoType == 'video/mp4' || obj.ext == 'mp4' || obj.ext == 'm4v')) HTML5 = true, videoType = "video/mp4"; 11199 else if (iL.plugins.html5WebM && (videoType == 'video/webm' || obj.ext == 'webm')) HTML5 = true, videoType = "video/webm"; 11200 else if (iL.plugins.html5Vorbis && (videoType == 'video/ogg' || obj.ext == 'ogv')) HTML5 = true, videoType = "video/ogg"; 11201 else if (iL.plugins.html5QuickTime && (videoType == 'video/quicktime' || obj.ext == 'mov' || obj.ext == 'qt')) HTML5 = true, videoType = "video/quicktime"; 11202 11203 if (HTML5) { 11204 el = $('<video />
11204', { 11205 "width": "100%", 11206 "height": "100%", 11207 "preload": html5video.preload, 11208 "autoplay": html5video.autoplay, 11209 "loop": html5video.loop, 11210 "poster": html5video.poster, 11211 "controls": html5video.controls, 11212 "controlslist": "nodownload" 11213 }).append($('<source />', { 11214 "src": obj.URL, 11215 "type": videoType 11216 })); 11217 } else { 11218 if (!iL.plugins.quicktime) el = $('<span />', { 11219 "class": "ilightbox-alert", 11220 html: iL.options.errors.missingPlugin.replace('{pluginspage}', pluginspages.quicktime).replace('{type}', 'QuickTime') 11221 }); 11222 else { 11223 11224 el = $('<object />', { 11225 "type": "video/quicktime", 11226 "pluginspage": pluginspages.quicktime 11227 }).attr({ 11228 "data": obj.URL, 11229 "width": "100%", 11230 "height": "100%" 11231 }).append($('<param />', { 11232 "name": "src", 11233 "value": obj.URL 11234 })).append($('<param />', { 11235 "name": "autoplay", 11236 "value": "false" 11237 })).append($('<param />', { 11238 "name": "loop", 11239 "value": "false" 11240 })).append($('<param />', { 11241 "name": "scale", 11242 "value": "tofit" 11243 })); 11244 11245 if (browser.msie) el = QT_GenerateOBJECTText(obj.URL, '100%', '100%', '', 'SCALE', 'tofit', 'AUTOPLAY', 'false', 'LOOP', 'false'); 11246 } 11247 } 11248 11249 break; 11250 11251 case 'flash': 11252 if (!iL.plugins.flash) el = $('<span />', { 11253 "class": "ilightbox-alert", 11254 html: iL.options.errors.missingPlugin.replace('{pluginspage}', pluginspages.flash).replace('{type}', 'Adobe Flash player') 11255 }); 11256 else { 11257 var flashvars = "", 11258 i = 0; 11259 11260 if (obj.options.flashvars) $.each(obj.options.flashvars, function(k, v) { 11261 if (i != 0) flashvars += "&"; 11262 flashvars += k + "=" + encodeURIComponent(v); 11263 i++; 11264 }); 11265 else flashvars = null; 11266 11267 el = $('<embed />').attr({ 11268 "type": "application/x-shockwave-flash", 11269 "src": obj.URL, 11270 "width": (typeof obj.options.width == 'number' && obj.options.width && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.width : "100%", 11271 "height": (typeof obj.options.height == 'number' && obj.options.height && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.height : "100%", 11272 "quality": "high", 11273 "bgcolor": "#000000", 11274 "play": "true", 11275 "loop": "true", 11276 "menu": "true", 11277 "wmode": "transparent", 11278 "scale": "showall", 11279 "allowScriptAccess": "always", 11280 "allowFullScreen": "true", 11281 "flashvars": flashvars, 11282 "fullscreen": "yes" 11283 }); 11284 } 11285 11286 break; 11287 11288 case 'iframe': 11289 el = $('<iframe />').attr({ 11290 "width": (typeof obj.options.width == 'number' && obj.options.width && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.width : "100%", 11291 "height": (typeof obj.options.height == 'number' && obj.options.height && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.height : "100%", 11292 src: obj.URL, 11293 frameborder: 0, 11294 'hspace': 0, 11295 'vspace': 0, 11296 'scrolling': supportTouch ? 'auto' : 'scroll', 11297 'webkitAllowFullScreen': '', 11298 'mozallowfullscreen': '', 11299 'allowFullScreen': '' 11300 }); 11301 11302 break; 11303 11304 case 'inline': 11305 el = $('<div class="ilightbox-wrapper"></div>').html($(obj.URL).clone(true)); 11306 11307 break; 11308 11309 case 'html': 11310 var object = obj.URL, 11311 el; 11312 11313 if (object[0].nodeName) { 11314 el = $('<div class="ilightbox-wrapper"></div>').html(object); 11315 } else { 11316 var dom = $(obj.URL), 11317 html = (dom.selector) ? $('<div>' + dom + '</div>') : dom; 11318 el = $('<div class="ilightbox-wrapper"></div>').html(html); 11319 } 11320 11321 break; 11322 } 11323 11324 $('div.ilightbox-container', element).empty().html(el); 11325 11326 // For fixing Chrome about just playing the video for first time 11327 if (el[0].tagName.toLowerCase() === 'video' && browser.webkit) setTimeout(function() { 11328 var src = el[0].currentSrc + '?' + floor(random() * 30000); 11329 el[0].currentSrc = src; 11330 el[0].src = src; 11331 }); 11332 11333 return el; 11334 }, 11335 11336 ogpRecognition: function(obj, callback) { 11337 var iL = this, 11338 url = obj.URL; 11339 11340 iL.showLoader(); 11341 doAjax(url, function(data) { 11342 iL.hideLoader(); 11343 if (data) { 11344 var object = new Object(); 11345 11346 object.length = false, 11347 object.url = data.url; 11348 11349 if (data.status == 200) { 11350 var result = data.results, 11351 type = result.type, 11352 source = result.source; 11353 11354 object.source = source.src, 11355 object.width = source.width && parseInt(source.width) || 0, 11356 object.height = source.height && parseInt(source.height) || 0, 11357 object.type = type, 11358 object.thumbnail = source.thumbnail || result.images && result.images[0], 11359 object.html5video = result.html5video || {}, 11360 object.length = true; 11361 11362 if (source.type == 'application/x-shockwave-flash') object.type = "flash"; 11363 else if (source.type.indexOf("video/") != -1) object.type = "video"; 11364 else if (source.type.indexOf("/html") != -1) object.type = "iframe"; 11365 else if (source.type.indexOf("image/") != -1) object.type = "image"; 11366 11367 } else if (typeof data.response != 'undefined') 11368 throw data.response; 11369 11370 callback.call(this, object.length ? object : false); 11371 } 11372 }); 11373 }, 11374 11375 hashChangeHandler: function(url) { 11376 var iL = this, 11377 vars = iL.vars, 11378 opts = iL.options, 11379 URL = url || window.location.href, 11380 hash = parseURI(URL).hash, 11381 split = hash.split('/'), 11382 index = split[1]; 11383 11384 if (vars.hashLock || ('#' + opts.linkId != split[0] && hash.length > 1)) return; 11385 11386 if (index) { 11387 var target = split[1] || 0; 11388 if (iL.items[target]) {
11389 var overlay = $('.ilightbox-overlay'); 11390 if (overlay.length && overlay.attr('linkid') == opts.linkId) { 11391 iL.goTo(target); 11392 } else { 11393 iL.itemsObject[target].trigger(supportTouch ? 'itap' : 'click'); 11394 //iL.goTo(target); 11395 } 11396 } else { 11397 var overlay = $('.ilightbox-overlay'); 11398 if (overlay.length) iL.closeAction(); 11399 } 11400 } else { 11401 var overlay = $('.ilightbox-overlay'); 11402 if (overlay.length) iL.closeAction(); 11403 } 11404 } 11405 }; 11406 11407 /** 11408 * Parse style to pixels. 11409 * 11410 * @param {Object} $element jQuery object with element. 11411 * @param {Property} property CSS property to get the pixels from. 11412 * 11413 * @return {Int} 11414 */ 11415 function getPixel($element, property) { 11416 return parseInt($element.css(property), 10) || 0; 11417 } 11418 11419 /** 11420 * Make sure that number is within the limits. 11421 * 11422 * @param {Number} number 11423 * @param {Number} min 11424 * @param {Number} max 11425 * 11426 * @return {Number} 11427 */ 11428 function within(number, min, max) { 11429 return number < min ? min : number > max ? max : number; 11430 } 11431 11432 /** 11433 * Get viewport/window size (width and height). 11434 * 11435 * @return {Object} 11436 */ 11437 function getViewport() { 11438 var e = window, 11439 a = 'inner'; 11440 if (!('innerWidth' in window)) { 11441 a = 'client'; 11442 e = document.documentElement || document.body; 11443 } 11444 return { 11445 width: e[a + 'Width'], 11446 height: e[a + 'Height'] 11447 } 11448 } 11449 11450 /** 11451 * Remove hash tag from the URL 11452 * 11453 * @return {Void} 11454 */ 11455 function removeHash() { 11456 var scroll = getScrollXY(); 11457 11458 //UNCODE change 11459 //window.location.hash = ""; 11460 history.pushState("", document.title, window.location.pathname + window.location.search); 11461 11462 // Restore the scroll offset, should be flicker free 11463 window.scrollTo(scroll.x, scroll.y); 11464 } 11465 11466 /** 11467 * Do the ajax requests with callback. 11468 * 11469 * @param {String} url 11470 * @param {Function} callback 11471 * 11472 * @return {Void} 11473 */ 11474 function doAjax(url, callback) { 11475 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'); 11476 $.ajax({ 11477 url: url, 11478 dataType: 'jsonp' 11479 }); 11480 11481 iLCallback = function(data) { 11482 callback.call(this, data); 11483 }; 11484 } 11485 11486 /** 11487 * Find image from DOM elements 11488 * 11489 * @param {Element} element 11490 * 11491 * @return {Void} 11492 */ 11493 function findImageInElement(element) { 11494 var elements = $('*', element), 11495 imagesArr = new Array(); 11496 11497 elements.each(function() { 11498 var url = "", 11499 element = this; 11500 11501 if ($(element).css("background-image") != "none") { 11502 url = $(element).css("background-image"); 11503 } else if (typeof($(element).attr("src")) != "undefined" && element.nodeName.toLowerCase() == "img") { 11504 url = $(element).attr("src"); 11505 } 11506 11507 if (url.indexOf("gradient") == -1) { 11508 url = url.replace(/url\(\"/g, ""); 11509 url = url.replace(/url\(/g, ""); 11510 url = url.replace(/\"\)/g, ""); 11511 url = url.replace(/\)/g, ""); 11512 11513 var urls = url.split(","); 11514 11515 for (var i = 0; i < urls.length; i++) { 11516 if (urls[i].length > 0 && $.inArray(urls[i], imagesArr) == -1) { 11517 var extra = ""; 11518 if (browser.msie && browser.version < 9) { 11519 extra = "?" + floor(random() * 3000); 11520 } 11521 imagesArr.push(urls[i] + extra); 11522 } 11523 } 11524 } 11525 }); 11526 11527 return imagesArr; 11528 } 11529 11530 /** 11531 * Get file extension. 11532 * 11533 * @param {String} URL 11534 * 11535 * @return {String} 11536 */ 11537 function getExtension(URL) { 11538 if (URL !== null) { 11539 //UNCODE: fix issue to detect media type with query strings 11540 var ext = URL.indexOf('?') !== -1 ? URL.split('?')[0] : URL; 11541 ext = ext.split('.').pop().toLowerCase(); 11542 11543 return ext; 11544 } 11545 } 11546 11547 /** 11548 * Get type via extension. 11549 * 11550 * @param {String} URL 11551 * 11552 * @return {String} 11553 */ 11554 function getTypeByExtension(URL) { 11555 var type, 11556 ext = getExtension(URL); 11557 11558 if (extensions.image.indexOf(ext) !== -1) type = 'image'; 11559 else if (extensions.flash.indexOf(ext) !== -1) type = 'flash'; 11560 else if (extensions.video.indexOf(ext) !== -1) type = 'video'; 11561 else if (ext.substring(0, 1) == "#") type = 'inline'; //Uncode addition 11562 else type = 'iframe'; 11563 11564 return type; 11565 } 11566 11567 /** 11568 * Return value from percent of a number. 11569 * 11570 * @param {Number} percent 11571 * @param {Number} total 11572 * 11573 * @return {Number} 11574 */ 11575 function percentToValue(percent, total) { 11576 return parseInt((total / 100) * percent); 11577 } 11578 11579 /** 11580 * A JavaScript equivalent of PHP’s parse_url. 11581 * 11582 * @param {String} url The URL to parse. 11583 * 11584 * @return {Mixed} 11585 */ 11586 function parseURI(url) { 11587 var m = String(url).replace(/^\s+|\s+$/g, '').match(/^([^:\/?#]+:)?(\/\/(?:[^:@]*(?::[^:@]*)?@)?(([^:\/?#]*)(?::(\d*))?))?([^?#]*)(\?[^#]*)?(#[\s\S]*)?/); 11588 // authority = '//' + user + ':' + pass '@' + hostname + ':' port 11589 return (m ? { 11590 href: m[0] || '', 11591 protocol: m[1] || '', 11592 authority: m[2] || '', 11593 host: m[3] || '', 11594 hostname: m[4] || '', 11595 port: m[5] || '', 11596 pathname: m[6] || '', 11597 search: m[7] || '', 11598 hash: m[8] || '' 11599 } : null); 11600 } 11601 11602 /** 11603 * Gets the absolute URI. 11604 * 11605 * @param {String} href The relative URL. 11606 * @param {String} base The base URL. 11607 * 11608 * @return {String} The absolute URL. 11609 */ 11610 function absolutizeURI(base, href) { // RFC 3986 11611 var iL = this; 11612 11613 function removeDotSegments(input) { 11614 var output = []; 11615 input.replace(/^(\.\.?(\/|$))+/, '') 11616 .replace(/\/(\.(\/|$))+/g, '/') 11617 .replace(/\/\.\.$/, '/../') 11618 .replace(/\/?[^\/]*/g, function(p) { 11619 if (p === '/..') { 11620 output.pop(); 11621 } else { 11622 output.push(p); 11623 } 11624 }); 11625 return output.join('').replace(/^\//, input.charAt(0) === '/' ? '/' : ''); 11626 } 11627 11628 href = parseURI(href || ''); 11629 base = parseURI(base || ''); 11630 11631 return !href || !base ? null : (href.protocol || base.protocol) + 11632 (href.protocol || href.authority ? href.authority : base.authority) + 11633 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)) + 11634 (href.protocol || href.authority || href.pathname ? href.search : (href.search || base.search)) + 11635 href.hash; 11636 } 11637 11638 /** 11639 * A JavaScript equivalent of PHP’s version_compare. 11640 * 11641 * @param {String} v1 11642 * @param {String} v2 11643 * @param {String} operator
11644 * 11645 * @return {Boolean} 11646 */ 11647 function version_compare(v1, v2, operator) { 11648 this.php_js = this.php_js || {}; 11649 this.php_js.ENV = this.php_js.ENV || {}; 11650 var i = 0, 11651 x = 0, 11652 compare = 0, 11653 vm = { 11654 'dev': -6, 11655 'alpha': -5, 11656 'a': -5, 11657 'beta': -4, 11658 'b': -4, 11659 'RC': -3, 11660 'rc': -3, 11661 '#': -2, 11662 'p': 1, 11663 'pl': 1 11664 }, 11665 prepVersion = function(v) { 11666 v = ('' + v).replace(/[_\-+]/g, '.'); 11667 v = v.replace(/([^.\d]+)/g, '.$1.').replace(/\.{2,}/g, '.'); 11668 return (!v.length ? [-8] : v.split('.')); 11669 }, 11670 numVersion = function(v) { 11671 return !v ? 0 : (isNaN(v) ? vm[v] || -7 : parseInt(v, 10)); 11672 }; 11673 v1 = prepVersion(v1); 11674 v2 = prepVersion(v2); 11675 x = max(v1.length, v2.length); 11676 for (i = 0; i < x; i++) { 11677 if (v1[i] == v2[i]) { 11678 continue; 11679 } 11680 v1[i] = numVersion(v1[i]); 11681 v2[i] = numVersion(v2[i]); 11682 if (v1[i] < v2[i]) { 11683 compare = -1; 11684 break; 11685 } else if (v1[i] > v2[i]) { 11686 compare = 1; 11687 break; 11688 } 11689 } 11690 if (!operator) { 11691 return compare; 11692 } 11693 11694 switch (operator) { 11695 case '>': 11696 case 'gt': 11697 return (compare > 0); 11698 case '>=': 11699 case 'ge': 11700 return (compare >= 0); 11701 case '<=': 11702 case 'le': 11703 return (compare <= 0); 11704 case '==': 11705 case '=': 11706 case 'eq': 11707 return (compare === 0); 11708 case '<>': 11709 case '!=': 11710 case 'ne': 11711 return (compare !== 0); 11712 case '': 11713 case '<': 11714 case 'lt': 11715 return (compare < 0); 11716 default: 11717 return null; 11718 } 11719 } 11720 11721 11722 // Begin the iLightBox plugin 11723 $.fn.iLightBox = function() { 11724 11725 var args = arguments, 11726 opt = ($.isPlainObject(args[0])) ? args[0] : args[1], 11727 items = ($.isArray(args[0]) || typeof args[0] == 'string') ? args[0] : args[1]; 11728 11729 if (!opt) opt = {}; 11730 11731 // Default options. Play carefully. 11732 var options = $.extend(true, { 11733 attr: 'href', 11734 path: 'vertical', 11735 skin: 'dark', 11736 linkId: false, 11737 infinite: false, 11738 startFrom: 0, 11739 randomStart: false, 11740 keepAspectRatio: true, 11741 maxScale: 1, 11742 minScale: .2, 11743 innerToolbar: false, 11744 smartRecognition: false, 11745 mobileOptimizer: true, 11746 fullAlone: true, 11747 fullViewPort: null, 11748 fullStretchTypes: 'flash, video', 11749 overlay: { 11750 blur: true, 11751 opacity: .85 11752 }, 11753 controls: { 11754 arrows: false, 11755 slideshow: false, 11756 toolbar: true, 11757 fullscreen: true, 11758 thumbnail: true, 11759 keyboard: true, 11760 mousewheel: true, 11761 swipe: true 11762 }, 11763 keyboard: { 11764 left: true, // previous 11765 right: true, // next 11766 up: true, // previous 11767 down: true, // next 11768 esc: true, // close 11769 shift_enter: true // fullscreen 11770 }, 11771 show: { 11772 effect: true, 11773 speed: 300, 11774 title: true 11775 }, 11776 hide: { 11777 effect: true, 11778 speed: 300 11779 }, 11780 caption: { 11781 start: true, 11782 show: 'mouseenter', 11783 hide: 'mouseleave' 11784 }, 11785 social: { 11786 start: true, 11787 show: 'mouseenter', 11788 hide: 'mouseleave',
11789 buttons: false 11790 }, 11791 styles: { 11792 pageOffsetX: 0, 11793 pageOffsetY: 0, 11794 nextOffsetX: 45, 11795 nextOffsetY: 0, 11796 nextOpacity: 1, 11797 nextScale: 1, 11798 prevOffsetX: 45, 11799 prevOffsetY: 0, 11800 prevOpacity: 1, 11801 prevScale: 1 11802 }, 11803 thumbnails: { 11804 maxWidth: 120, 11805 maxHeight: 80, 11806 normalOpacity: 1, 11807 activeOpacity: .6 11808 }, 11809 effects: { 11810 reposition: true, 11811 repositionSpeed: 200, 11812 switchSpeed: 500, 11813 loadedFadeSpeed: 180, 11814 fadeSpeed: 200 11815 }, 11816 slideshow: { 11817 pauseTime: 5000, 11818 pauseOnHover: false, 11819 startPaused: true 11820 }, 11821 text: { 11822 close: "Press Esc to close", 11823 enterFullscreen: "Enter Fullscreen (Shift+Enter)", 11824 exitFullscreen: "Exit Fullscreen (Shift+Enter)", 11825 slideShow: "Slideshow", 11826 next: "Next", 11827 previous: "Previous" 11828 }, 11829 errors: { 11830 loadImage: "An error occurred when trying to load photo.", 11831 loadContents: "An error occurred when trying to load contents.", 11832 missingPlugin: "The content your are attempting to view requires the <a href='{pluginspage}' target='_blank'>{type} plugin<\/a>." 11833 }, 11834 ajaxSetup: { 11835 url: '', 11836 beforeSend: function(jqXHR, settings) {}, 11837 cache: false, 11838 complete: function(jqXHR, textStatus) {}, 11839 crossDomain: false, 11840 error: function(jqXHR, textStatus, errorThrown) {}, 11841 success: function(data, textStatus, jqXHR) {}, 11842 global: true, 11843 ifModified: false, 11844 username: null, 11845 password: null, 11846 type: 'GET' 11847 }, 11848 callback: {} 11849 }, opt); 11850 11851 var instant = ($.isArray(items) || typeof items == 'string') ? true : false; 11852 11853 items = $.isArray(items) ? items : new Array(); 11854 11855 if (typeof args[0] == 'string') items[0] = args[0]; 11856 11857 if (version_compare($.fn.jquery, '1.8', '>=')) { 11858 var iLB = new iLightBox($(this), options, items, instant); 11859 return { 11860 close: function() { 11861 iLB.closeAction(); 11862 }, 11863 fullscreen: function() { 11864 iLB.fullScreenAction(); 11865 }, 11866 moveNext: function() { 11867 iLB.moveTo('next'); 11868 }, 11869 movePrev: function() { 11870 iLB.moveTo('prev'); 11871 }, 11872 goTo: function(index) { 11873 iLB.goTo(index); 11874 }, 11875 refresh: function() { 11876 iLB.refresh(); 11877 }, 11878 reposition: function() { 11879 (arguments.length > 0) ? iLB.repositionPhoto(true): iLB.repositionPhoto(); 11880 }, 11881 setOption: function(options) { 11882 iLB.setOption(options); 11883 }, 11884 destroy: function() { 11885 iLB.closeAction(); 11886 iLB.dispatchItemsEvents(); 11887 } 11888 }; 11889 } else { 11890 throw "The jQuery version that was loaded is too old. iLightBox requires jQuery 1.8+"; 11891 } 11892 11893 }; 11894 11895 11896 $.iLightBox = function() { 11897 return $.fn.iLightBox(arguments[0], arguments[1]); 11898 }; 11899 11900 11901 $.extend($.easing, { 11902 easeInCirc: function(x, t, b, c, d) { 11903 return -c * (sqrt(1 - (t /= d) * t) - 1) + b; 11904 }, 11905 easeOutCirc: function(x, t, b, c, d) { 11906 return c * sqrt(1 - (t = t / d - 1) * t) + b; 11907 }, 11908 easeInOutCirc: function(x, t, b, c, d) { 11909 if ((t /= d / 2) < 1) return -c / 2 * (sqrt(1 - t * t) - 1) + b; 11910 return c / 2 * (sqrt(1 - (t -= 2) * t) + 1) + b; 11911 } 11912 }); 11913 11914 function getScrollXY() { 11915 var scrOfX = 0, 11916 scrOfY = 0; 11917 if (typeof(window.pageYOffset) == 'number') { 11918 //Netscape compliant 11919 scrOfY = window.pageYOffset; 11920 scrOfX = window.pageXOffset; 11921 } else if (document.body && (document.body.scrollLeft || document.body.scrollTop)) { 11922 //DOM compliant 11923 scrOfY = document.body.scrollTop; 11924 scrOfX = document.body.scrollLeft; 11925 } else if (document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)) { 11926 //IE6 standards compliant mode 11927 scrOfY = document.documentElement.scrollTop; 11928 scrOfX = document.documentElement.scrollLeft; 11929 } 11930 return { 11931 x: scrOfX, 11932 y: scrOfY 11933 }; 11934 } 11935 11936 (function() { 11937 // add new event shortcuts 11938 $.each(("touchstart touchmove touchend " + 11939 "tap taphold " + 11940 "swipe swipeleft swiperight " + 11941 "scrollstart scrollstop").split(" "), function(i, name) { 11942 11943 $.fn[name] = function(fn) { 11944 return fn ? this.bind(name, fn) : this.trigger(name); 11945 }; 11946 11947 // jQuery < 1.8 11948 // if ($.attrFn) { 11949 // $.attrFn[name] = true; 11950 // } 11951 }); 11952 11953 var tapSettings = { 11954 startEvent: 'touchstart.iTap', 11955 endEvent: 'touchend.iTap' 11956 }; 11957 11958 // tap Event: 11959 $.event.special.itap = { 11960 setup: function() { 11961 11962 var self = this, 11963 $self = $(this), 11964 start, stop; 11965 11966 $self.bind(tapSettings.startEvent, function(event) { 11967 start = getScrollXY(); 11968 11969 $self.one(tapSettings.endEvent, function(event) { 11970 stop = getScrollXY(); 11971 11972 var orgEvent = event || window.event; 11973 event = $.event.fix(orgEvent); 11974 event.type = "itap"; 11975 11976 if ((start && stop) && (start.x == stop.x && start.y == stop.y))($.event.dispatch || $.event.handle).call(self, event); 11977 11978 start = stop = undefined; 11979 }); 11980 }); 11981 }, 11982 11983 teardown: function() { 11984 $(this).unbind(tapSettings.startEvent); 11985 } 11986 }; 11987 }()); 11988 11989 11990 //Fullscreen API 11991 (function() { 11992 fullScreenApi = { 11993 supportsFullScreen: false, 11994 isFullScreen: function() { 11995 return false;
11996 }, 11997 requestFullScreen: function() {}, 11998 cancelFullScreen: function() {}, 11999 fullScreenEventName: '', 12000 prefix: '' 12001 }, 12002 browserPrefixes = 'webkit moz o ms khtml'.split(' '); 12003 12004 // check for native support 12005 if (typeof document.cancelFullScreen != 'undefined') { 12006 fullScreenApi.supportsFullScreen = true; 12007 } else { 12008 // check for fullscreen support by vendor prefix 12009 for (var i = 0, il = browserPrefixes.length; i < il; i++) { 12010 fullScreenApi.prefix = browserPrefixes[i]; 12011 12012 if (typeof document[fullScreenApi.prefix + 'CancelFullScreen'] != 'undefined') { 12013 fullScreenApi.supportsFullScreen = true; 12014 12015 break; 12016 } 12017 } 12018 } 12019 12020 // update methods to do something useful 12021 if (fullScreenApi.supportsFullScreen) { 12022 fullScreenApi.fullScreenEventName = fullScreenApi.prefix + 'fullscreenchange'; 12023 12024 fullScreenApi.isFullScreen = function() { 12025 switch (this.prefix) { 12026 case '': 12027 return document.fullScreen; 12028 case 'webkit': 12029 return document.webkitIsFullScreen; 12030 default: 12031 return document[this.prefix + 'FullScreen']; 12032 } 12033 } 12034 fullScreenApi.requestFullScreen = function(el) { 12035 return (this.prefix === '') ? el.requestFullScreen() : el[this.prefix + 'RequestFullScreen'](); 12036 } 12037 fullScreenApi.cancelFullScreen = function(el) { 12038 return (this.prefix === '') ? document.cancelFullScreen() : document[this.prefix + 'CancelFullScreen'](); 12039 } 12040 } 12041 }()); 12042 12043 // Browser detect 12044 (function() { 12045 function uaMatch(ua) { 12046 ua = ua.toLowerCase(); 12047 12048 var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || 12049 /(webkit)[ \/]([\w.]+)/.exec(ua) || 12050 /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || 12051 /(msie) ([\w.]+)/.exec(ua) || 12052 ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || []; 12053 12054 return { 12055 browser: match[1] || "", 12056 version: match[2] || "0" 12057 }; 12058 } 12059 12060 var matched = uaMatch(navigator.userAgent); 12061 browser = {}; 12062 12063 if (matched.browser) { 12064 browser[matched.browser] = true; 12065 browser.version = matched.version; 12066 } 12067 12068 // Chrome is Webkit, but Webkit is also Safari. 12069 if (browser.chrome) { 12070 browser.webkit = true; 12071 } else if (browser.webkit) { 12072 browser.safari = true; 12073 } 12074 }()); 12075 12076 // Feature detects 12077 (function() { 12078 var prefixes = ['', 'webkit', 'moz', 'ms', 'o']; 12079 var el = document.createElement('div'); 12080 12081 function testProp(prop) { 12082 for (var p = 0, pl = prefixes.length; p < pl; p++) { 12083 var prefixedProp = prefixes[p] ? prefixes[p] + prop.charAt(0).toUpperCase() + prop.slice(1) : prop; 12084 if (el.style[prefixedProp] !== undefined) { 12085 return prefixedProp; 12086 } 12087 } 12088 } 12089 12090 // Global support indicators 12091 transform = testProp('transform') || ''; 12092 gpuAcceleration = testProp('perspective') ? 'translateZ(0) ' : ''; 12093 }()); 12094 12095 12096 /* 12097 PluginDetect v0.7.9 12098 www.pinlady.net/PluginDetect/license/ 12099 [ getVersion onWindowLoaded BetterIE ] 12100 [ Flash QuickTime Shockwave ] 12101 */ 12102 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;
12102d++){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);
12102d.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)}
12102c.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;
12102if(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(); 12103 12104 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)}; 12105 12106 12107 /* 12108 jQuery hashchange event v1.3 12109 https://github.com/cowboy/jquery-hashchange 12110 Copyright (c) 2010 "Cowboy" Ben Alman 12111 Dual licensed under the MIT and GPL licenses. 12112 */ 12113 (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= 12114 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|| 12115 "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;
12115a!==d&&(b.title=k.title,b.open(),e&&b.write('<script>document.domain="'+e+'"\x3c/script>'),b.close(),c.location.hash=a)}}();return h}()})(); 12116 12117 if (!Array.prototype.filter) { 12118 Array.prototype.filter = function(fun /*, thisp */ ) { 12119 "use strict"; 12120 12121 if (this == null) 12122 throw new TypeError(); 12123 12124 var t = Object(this); 12125 var len = t.length >>> 0; 12126 if (typeof fun != "function") 12127 throw new TypeError(); 12128 12129 var res = []; 12130 var thisp = arguments[1]; 12131 for (var i = 0; i < len; i++) { 12132 if (i in t) { 12133 var val = t[i]; // in case fun mutates this 12134 if (fun.call(thisp, val, i, t)) 12135 res.push(val); 12136 } 12137 } 12138 12139 return res; 12140 }; 12141 } 12142 12143 if (!Array.prototype.indexOf) { 12144 Array.prototype.indexOf = function(searchElement, fromIndex) { 12145 var k; 12146 12147 if (this == null) { 12148 throw new TypeError('"this" is null or not defined'); 12149 } 12150 12151 var O = Object(this); 12152 12153 var len = O.length >>> 0; 12154 12155 if (len === 0) { 12156 return -1; 12157 } 12158 12159 var n = +fromIndex || 0; 12160 12161 if (abs(n) === Infinity) { 12162 n = 0; 12163 } 12164 12165 if (n >= len) { 12166 return -1; 12167 } 12168 12169 k = max(n >= 0 ? n : len - abs(n), 0); 12170 12171 while (k < len) { 12172 var kValue; 12173 if (k in O && O[k] === searchElement) { 12174 return k; 12175 } 12176 k++; 12177 } 12178 return -1; 12179 }; 12180 } 12181 12182 if (!Array.prototype.lastIndexOf) { 12183 Array.prototype.lastIndexOf = function(searchElement /*, fromIndex*/ ) { 12184 "use strict"; 12185 12186 if (this == null) 12187 throw new TypeError(); 12188 12189 var t = Object(this); 12190 var len = t.length >>> 0; 12191 if (len === 0) 12192 return -1; 12193 12194 var n = len; 12195 if (arguments.length > 1) { 12196 n = Number(arguments[1]); 12197 if (n != n) 12198 n = 0; 12199 else if (n != 0 && n != (1 / 0) && n != -(1 / 0)) 12200 n = (n > 0 || -1) * floor(abs(n)); 12201 } 12202 12203 var k = n >= 0 ? min(n, len - 1) : len - abs(n); 12204 12205 for (; k >= 0; k--) { 12206 if (k in t && t[k] === searchElement) 12207 return k; 12208 } 12209 return -1; 12210 }; 12211 } 12212})(jQuery, this); 12213 12214/** 12215 * Owl carousel
vendor: 12,108 bytes, lines 12216-12722
12216 * @version 2.0.0-beta.3 12217 * @author Bartosz Wojciechowski 12218 * @license The MIT License (MIT) 12219 * @todo Lazy Load Icon 12220 * @todo prevent animationend bubling 12221 * @todo itemsScaleUp 12222 * @todo Test Zepto 12223 * @todo stagePadding calculate wrong active classes 12224 */ 12225;(function($, window, document, undefined) { 12226 12227 /** 12228 * Creates a carousel. 12229 * @class The Owl Carousel. 12230 * @public 12231 * @param {HTMLElement|jQuery} element - The element to create the carousel for. 12232 * @param {Object} [options] - The options 12233 */ 12234 function Owl(element, options) { 12235 12236 /** 12237 * Current settings for the carousel. 12238 * @public 12239 */ 12240 this.settings = null; 12241 12242 /** 12243 * Current options set by the caller including defaults. 12244 * @public 12245 */ 12246 this.options = $.extend({}, Owl.Defaults, options); 12247 12248 /** 12249 * Plugin element. 12250 * @public 12251 */ 12252 this.$element = $(element); 12253 12254 /** 12255 * Proxied event handlers. 12256 * @protected 12257 */ 12258 this._handlers = {}; 12259 12260 /** 12261 * References to the running plugins of this carousel. 12262 * @protected 12263 */ 12264 this._plugins = {}; 12265 12266 /** 12267 * Currently suppressed events to prevent them from beeing retriggered. 12268 * @protected 12269 */ 12270 this._supress = {}; 12271 12272 /** 12273 * Absolute current position. 12274 * @protected 12275 */ 12276 this._current = null; 12277 12278 /** 12279 * Animation speed in milliseconds. 12280 * @protected 12281 */ 12282 this._speed = null; 12283 12284 /** 12285 * Coordinates of all items in pixel. 12286 * @todo The name of this member is missleading. 12287 * @protected 12288 */ 12289 this._coordinates = []; 12290 12291 /** 12292 * Current breakpoint. 12293 * @todo Real media queries would be nice. 12294 * @protected 12295 */ 12296 this._breakpoint = null; 12297 12298 /** 12299 * Current width of the plugin element. 12300 */ 12301 this._width = null; 12302 12303 /** 12304 * All real items. 12305 * @protected 12306 */ 12307 this._items = []; 12308 12309 /** 12310 * All cloned items. 12311 * @protected 12312 */ 12313 this._clones = []; 12314 12315 /** 12316 * Merge values of all items. 12317 * @todo Maybe this could be part of a plugin. 12318 * @protected 12319 */ 12320 this._mergers = []; 12321 12322 /** 12323 * Widths of all items. 12324 */ 12325 this._widths = []; 12326 12327 /** 12328 * Invalidated parts within the update process. 12329 * @protected 12330 */ 12331 this._invalidated = {}; 12332 12333 /** 12334 * Ordered list of workers for the update process. 12335 * @protected 12336 */ 12337 this._pipe = []; 12338 12339 /** 12340 * Current state information for the drag operation. 12341 * @todo #261 12342 * @protected 12343 */ 12344 this._drag = { 12345 time: null, 12346 target: null, 12347 pointer: null, 12348 stage: { 12349 start: null, 12350 current: null 12351 }, 12352 direction: null 12353 }; 12354 12355 /** 12356 * Current state information and their tags. 12357 * @type {Object} 12358 * @protected 12359 */ 12360 this._states = { 12361 current: {}, 12362 tags: { 12363 'initializing': [ 'busy' ], 12364 'animating': [ 'busy' ], 12365 'dragging': [ 'interacting' ] 12366 } 12367 }; 12368 12369 $.each([ 'onResize', 'onThrottledResize' ], $.proxy(function(i, handler) { 12370 this._handlers[handler] = $.proxy(this[handler], this); 12371 }, this)); 12372 12373 $.each(Owl.Plugins, $.proxy(function(key, plugin) { 12374 this._plugins[key.charAt(0).toLowerCase() + key.slice(1)] 12375 = new plugin(this); 12376 }, this)); 12377 12378 $.each(Owl.Workers, $.proxy(function(priority, worker) { 12379 this._pipe.push({ 12380 'filter': worker.filter, 12381 'run': $.proxy(worker.run, this) 12382 }); 12383 }, this)); 12384 12385 this.setup(); 12386 this.initialize(); 12387 } 12388 12389 /** 12390 * Default options for the carousel. 12391 * @public 12392 */ 12393 Owl.Defaults = { 12394 items: 3, 12395 loop: false, 12396 center: false, 12397 rewind: false, 12398 12399 mouseDrag: true, 12400 touchDrag: true, 12401 pullDrag: true, 12402 freeDrag: false, 12403 12404 margin: 0, 12405 stagePadding: 0, 12406 12407 merge: false, 12408 mergeFit: true, 12409 autoWidth: false, 12410 12411 startPosition: 0, 12412 rtl: false, 12413 12414 smartSpeed: 250, 12415 fluidSpeed: false, 12416 dragEndSpeed: false, 12417 12418 responsive: {}, 12419 responsiveRefreshRate: 200, 12420 responsiveBaseElement: window, 12421 12422 fallbackEasing: 'swing', 12423 12424 info: false, 12425 12426 nestedItemSelector: false, 12427 itemElement: 'div', 12428 stageElement: 'div', 12429 12430 refreshClass: 'owl-refresh', 12431 loadedClass: 'owl-loaded', 12432 loadingClass: 'owl-loading', 12433 rtlClass: 'owl-rtl', 12434 responsiveClass: 'owl-responsive', 12435 dragClass: 'owl-drag', 12436 itemClass: 'owl-item', 12437 stageClass: 'owl-stage', 12438 stageOuterClass: 'owl-stage-outer', 12439 grabClass: 'owl-grab' 12440 }; 12441 12442 /** 12443 * Enumeration for width. 12444 * @public 12445 * @readonly 12446 * @enum {String} 12447 */ 12448 Owl.Width = { 12449 Default: 'default', 12450 Inner: 'inner', 12451 Outer: 'outer' 12452 }; 12453 12454 /** 12455 * Enumeration for types. 12456 * @public 12457 * @readonly 12458 * @enum {String} 12459 */ 12460 Owl.Type = { 12461 Event: 'event', 12462 State: 'state' 12463 }; 12464 12465 /** 12466 * Contains all registered plugins. 12467 * @public 12468 */ 12469 Owl.Plugins = {}; 12470 12471 /** 12472 * List of workers involved in the update process. 12473 */ 12474 Owl.Workers = [ { 12475 filter: [ 'width', 'settings' ], 12476 run: function() { 12477 this._width = (this.$element.closest('.px-gutter').length) ? 12 * Math.ceil(this.$element.width() / 12) : this.$element.width(); 12478 //this._width = (UNCODE.isMobile) ? this.$element.width() : 12 * Math.ceil(this.$element.width() / 12); 12479 } 12480 }, { 12481 filter: [ 'width', 'items', 'settings' ], 12482 run: function(cache) { 12483 cache.current = this._items && this._items[this.relative(this._current)]; 12484 } 12485 }, { 12486 filter: [ 'items', 'settings' ], 12487 run: function() { 12488 this.$stage.children('.cloned').remove(); 12489 } 12490 }, { 12491 filter: [ 'width', 'items', 'settings' ], 12492 run: function(cache) { 12493 var margin = this.settings.margin || '', 12494 grid = !this.settings.autoWidth, 12495 rtl = this.settings.rtl, 12496 css = { 12497 'width': 'auto', 12498 'margin-left': rtl ? margin : '', 12499 'margin-right': rtl ? '' : margin 12500 }; 12501 12502 !grid && this.$stage.children().css(css); 12503 12504 cache.css = css; 12505 } 12506 }, { 12507 filter: [ 'width', 'items', 'settings' ], 12508 run: function(cache) { 12509 //UNCODE edit to fix Chrome stage padding issue 12510 var width = Math.round((this.width() / this.settings.items).toFixed(3) - this.settings.margin), 12511 merge = null, 12512 iterator = this._items.length, 12513 grid = !this.settings.autoWidth, 12514 widths = []; 12515 12516 cache.items = { 12517 merge: false, 12518 width: width 12519 }; 12520 12521 while (iterator--) { 12522 merge = this._mergers[iterator]; 12523 merge = this.settings.mergeFit && Math.min(merge, this.settings.items) || merge; 12524 12525 cache.items.merge = merge > 1 || cache.items.merge; 12526 12527 widths[iterator] = !grid ? this._items[iterator].width() : width * merge; 12528 } 12529 12530 this._widths = widths; 12531 } 12532 }, { 12533 filter: [ 'items', 'settings' ], 12534 run: function() { 12535 var clones = [], 12536 items = this._items, 12537 settings = this.settings, 12538 view = Math.max(settings.items * 2, 4), 12539 size = Math.ceil(items.length / 2) * 2, 12540 repeat = settings.loop && items.length ? settings.rewind ? view : Math.max(view, size) : 0, 12541 append = '', 12542 prepend = ''; 12543 12544 repeat /= 2; 12545 12546 while (repeat--) { 12547 clones.push(this.normalize(clones.length / 2, true)); 12548 append = append + items[clones[clones.length - 1]][0].outerHTML; 12549 clones.push(this.normalize(items.length - 1 - (clones.length - 1) / 2, true)); 12550 prepend = items[clones[clones.length - 1]][0].outerHTML + prepend; 12551 } 12552 12553 this._clones = clones; 12554 12555 // var appendVideo = $(append).find('.uncode-video-container'); 12556 // if (appendVideo.length) { 12557 // appendVideo.attr('data-id', Math.round(Math.random() * 100000)); 12558 // } 12559 // var prependVideo = $(prepend).find('.uncode-video-container'); 12560 // if (prependVideo.length) { 12561 // prependVideo.attr('data-id', Math.round(Math.random() * 100000)); 12562 // } 12563 $(append).addClass('cloned').appendTo(this.$stage); 12564 $(prepend).addClass('cloned').prependTo(this.$stage); 12565 } 12566 }, { 12567 filter: [ 'width', 'items', 'settings' ], 12568 run: function() { 12569 var rtl = this.settings.rtl ? 1 : -1, 12570 size = this._clones.length + this._items.length, 12571 iterator = -1, 12572 previous = 0, 12573 current = 0, 12574 coordinates = []; 12575 12576 while (++iterator < size) { 12577 previous = coordinates[iterator - 1] || 0; 12578 current = this._widths[this.relative(iterator)] + this.settings.margin; 12579 coordinates.push(previous + current * rtl); 12580 } 12581 12582 this._coordinates = coordinates; 12583 } 12584 }, { 12585 filter: [ 'width', 'items', 'settings' ], 12586 run: function() { 12587 var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200, 12588 padding = stagePadding, 12589 coordinates = this._coordinates, 12590 css = { 12591 'width': Math.ceil(Math.abs(coordinates[coordinates.length - 1])) + padding * 2, 12592 'padding-left': padding || '', 12593 'padding-right': padding || '' 12594 }; 12595 12596 this.$stage.css(css); 12597 } 12598 }, { 12599 filter: [ 'width', 'items', 'settings' ], 12600 run: function(cache) { 12601 var iterator = this._coordinates.length, 12602 grid = !this.settings.autoWidth, 12603 items = this.$stage.children(); 12604 12605 if (grid && cache.items.merge) { 12606 while (iterator--) { 12607 cache.css.width = this._widths[this.relative(iterator)]; 12608 items.eq(iterator).css(cache.css); 12609 } 12610 } else if (grid) { 12611 cache.css.width = cache.items.width; 12612 items.css(cache.css); 12613 } 12614 } 12615 }, { 12616 filter: [ 'items' ], 12617 run: function() { 12618 this._coordinates.length < 1 && this.$stage.removeAttr('style'); 12619 } 12620 }, { 12621 filter: [ 'width', 'items', 'settings' ], 12622 run: function(cache) { 12623 cache.current = cache.current ? this.$stage.children().index(cache.current) : 0; 12624 cache.current = Math.max(this.minimum(), Math.min(this.maximum(), cache.current)); 12625 this.reset(cache.current); 12626 } 12627 }, { 12628 filter: [ 'position' ], 12629 run: function() { 12630 this.animate(this.coordinates(this._current)); 12631 } 12632 }, { 12633 filter: [ 'width', 'position', 'items', 'settings' ], 12634 run: function() { 12635 var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200, 12636 rtl = this.settings.rtl ? 1 : -1, 12637 padding = this.settings.stagePadding * 2, 12638 begin = this.coordinates(this.current()) + padding, 12639 end = begin + this.width() * rtl, 12640 inner, outer, matches = [], i, n; 12641 12642 for (i = 0, n = this._coordinates.length; i < n; i++) { 12643 inner = this._coordinates[i - 1] || 0; 12644 outer = Math.abs(this._coordinates[i]) + padding * rtl; 12645 12646 if ((this.op(inner, '<=', begin) && (this.op(inner, '>', end))) 12647 || (this.op(outer, '<', begin) && this.op(outer, '>', end))) { 12648 matches.push(i); 12649 } 12650 } 12651 12652 this.$stage.children('.active').removeClass('active'); 12653 this.$stage.children(':eq(' + matches.join('), :eq(') + ')').addClass('active'); 12654 12655 if (this.settings.center) { 12656 this.$stage.children('.center').removeClass('center'); 12657 this.$stage.children().eq(this.current()).addClass('center'); 12658 } 12659 } 12660 } ]; 12661 12662 /** 12663 * Initializes the carousel. 12664 * @protected 12665 */ 12666 Owl.prototype.initialize = function() { 12667 this.enter('initializing'); 12668 this.trigger('initialize'); 12669 12670 this.$element.toggleClass(this.settings.rtlClass, this.settings.rtl); 12671 12672 if (this.settings.autoWidth && !this.is('pre-loading')) { 12673 var imgs, nestedSelector, width; 12674 imgs = this.$element.find('img'); 12675 nestedSelector = this.settings.nestedItemSelector ? '.' + this.settings.nestedItemSelector : undefined; 12676 width = this.$element.children(nestedSelector).width(); 12677 12678 if (imgs.length && width <= 0) { 12679 this.preloadAutoWidthImages(imgs); 12680 } 12681 } 12682 12683 this.$element.addClass(this.options.loadingClass); 12684 12685 // create stage 12686 this.$stage = $('<' + this.settings.stageElement + ' class="' + this.settings.stageClass + '"/>') 12687 .wrap('<div class="' + this.settings.stageOuterClass + '"/>'); 12688 12689 // append stage 12690 this.$element.append(this.$stage.parent()); 12691 12692 // append content 12693 this.replace(this.$element.children().not(this.$stage.parent())); 12694 12695 // check visibility 12696 if (this.$element.is(':visible')) { 12697 // update view 12698 this.refresh(); 12699 } else { 12700 // invalidate width 12701 this.invalidate('width'); 12702 } 12703 12704 this.$element 12705 .removeClass(this.options.loadingClass) 12706 .addClass(this.options.loadedClass); 12707 12708 // register event handlers 12709 this.registerEventHandlers(); 12710 12711 this.leave('initializing'); 12712 this.trigger('initialized'); 12713 }; 12714 12715 /** 12716 * Setups the current settings. 12717 * @todo Remove responsive classes. Why should adaptive designs be brought into IE8? 12718 * @todo Support for media queries by using `matchMedia` would be nice. 12719 * @public 12720 */ 12721 Owl.prototype.setup = function() { 12722 var viewport = this.viewport(),
12723 overwrites = this.options.responsive, 12724 match = -1, 12725 settings = null; 12726 12727 if (!overwrites) { 12728 settings = $.extend({}, this.options); 12729 } else { 12730 $.each(overwrites, function(breakpoint) { 12731 if (breakpoint <= viewport && breakpoint > match) { 12732 match = Number(breakpoint); 12733 } 12734 }); 12735 12736 settings = $.extend({}, this.options, overwrites[match]); 12737 delete settings.responsive; 12738 12739 // responsive class 12740 if (settings.responsiveClass) { 12741 this.$element.attr('class', 12742 this.$element.attr('class').replace(new RegExp('(' + this.options.responsiveClass + '-)\\S+\\s', 'g'), '$1' + match) 12743 ); 12744 } 12745 } 12746 12747 if (this.settings === null || this._breakpoint !== match) { 12748 this.trigger('change', { property: { name: 'settings', value: settings } }); 12749 this._breakpoint = match; 12750 this.settings = settings; 12751 this.invalidate('settings'); 12752 this.trigger('changed', { property: { name: 'settings', value: this.settings } }); 12753 } 12754 }; 12755 12756 /** 12757 * Updates option logic if necessery. 12758 * @protected 12759 */ 12760 Owl.prototype.optionsLogic = function() { 12761 if (this.settings.autoWidth) { 12762 this.settings.stagePadding = false; 12763 this.settings.merge = false; 12764 } 12765 }; 12766 12767 /** 12768 * Prepares an item before add. 12769 * @todo Rename event parameter `content` to `item`. 12770 * @protected 12771 * @returns {jQuery|HTMLElement} - The item container. 12772 */ 12773 Owl.prototype.prepare = function(item, index) { 12774 var event = this.trigger('prepare', { content: item }); 12775 if (!event.data) { 12776 event.data = $('<' + this.settings.itemElement + '/>') 12777 .addClass(this.options.itemClass).attr('data-index', index + 1).append(item) 12778 } 12779 12780 this.trigger('prepared', { content: event.data }); 12781 12782 return event.data; 12783 }; 12784 12785 /** 12786 * Updates the view. 12787 * @public 12788 */ 12789 Owl.prototype.update = function() { 12790 var i = 0, 12791 n = this._pipe.length, 12792 filter = $.proxy(function(p) { return this[p] }, this._invalidated), 12793 cache = {}; 12794 12795 while (i < n) { 12796 if (this._invalidated.all || $.grep(this._pipe[i].filter, filter).length > 0) { 12797 this._pipe[i].run(cache); 12798 } 12799 i++; 12800 } 12801 12802 this._invalidated = {}; 12803 12804 !this.is('valid') && this.enter('valid'); 12805 }; 12806 12807 /** 12808 * Gets the width of the view. 12809 * @public 12810 * @param {Owl.Width} [dimension=Owl.Width.Default] - The dimension to return. 12811 * @returns {Number} - The width of the view in pixel. 12812 */ 12813 Owl.prototype.width = function(dimension) { 12814 dimension = dimension || Owl.Width.Default; 12815 var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200; 12816 switch (dimension) { 12817 case Owl.Width.Inner: 12818 case Owl.Width.Outer: 12819 return this._width; 12820 default: 12821 return this._width - stagePadding * 2 + this.settings.margin; 12822 } 12823 }; 12824 12825 /** 12826 * Refreshes the carousel primarily for adaptive purposes. 12827 * @public 12828 */ 12829 Owl.prototype.refresh = function() { 12830 this.enter('refreshing'); 12831 this.trigger('refresh'); 12832 12833 this.setup(); 12834 12835 this.optionsLogic(); 12836 12837 this.$element.addClass(this.options.refreshClass); 12838 12839 this.update(); 12840 12841 this.$element.removeClass(this.options.refreshClass); 12842 12843 this.leave('refreshing'); 12844 this.trigger('refreshed'); 12845 }; 12846 12847 /** 12848 * Checks window `resize` event. 12849 * @protected 12850 */ 12851 Owl.prototype.onThrottledResize = function() { 12852 window.clearTimeout(this.resizeTimer); 12853 this.resizeTimer = window.setTimeout(this._handlers.onResize, this.settings.responsiveRefreshRate); 12854 }; 12855 12856 /** 12857 * Checks window `resize` event. 12858 * @protected 12859 */ 12860 Owl.prototype.onResize = function() { 12861 if (!this._items.length) { 12862 return false; 12863 } 12864 12865 if (this._width === this.$element.width()) { 12866 return false; 12867 } 12868 12869 if (!this.$element.is(':visible')) { 12870 return false; 12871 } 12872 12873 this.enter('resizing'); 12874 12875 if (this.trigger('resize').isDefaultPrevented()) { 12876 this.leave('resizing'); 12877 return false; 12878 } 12879 12880 this.invalidate('width'); 12881 12882 this.refresh(); 12883 12884 this.leave('resizing'); 12885 this.trigger('resized'); 12886 }; 12887 12888 /** 12889 * Registers event handlers. 12890 * @todo Check `msPointerEnabled` 12891 * @todo #261 12892 * @protected 12893 */ 12894 Owl.prototype.registerEventHandlers = function() { 12895 if ($.support.transition) { 12896 this.$stage.on($.support.transition.end + '.owl.core', $.proxy(this.onTransitionEnd, this)); 12897 } 12898 12899 if (this.settings.responsive !== false) { 12900 this.on(window, 'resize', this._handlers.onThrottledResize); 12901 } 12902 12903 if (this.settings.mouseDrag) { 12904 this.$element.addClass(this.options.dragClass); 12905 this.$stage.on('mousedown.owl.core', $.proxy(this.onDragStart, this)); 12906 this.$stage.on('dragstart.owl.core selectstart.owl.core', function() { return false }); 12907 } 12908 12909 if (this.settings.touchDrag){ 12910 this.$stage.on('touchstart.owl.core', $.proxy(this.onDragStart, this)); 12911 this.$stage.on('touchcancel.owl.core', $.proxy(this.onDragEnd, this)); 12912 } 12913 }; 12914 12915 /** 12916 * Handles `touchstart` and `mousedown` events. 12917 * @todo Horizontal swipe threshold as option 12918 * @todo #261 12919 * @protected 12920 * @param {Event} event - The event arguments. 12921 */ 12922 Owl.prototype.onDragStart = function(event) { 12923 var stage = null; 12924 12925 if (event.which === 3) { 12926 return; 12927 } 12928
vendor: 9,106 bytes, lines 12929-13244
12929 if ($.support.transform) { 12930 stage = this.$stage.css('transform').replace(/.*\(|\)| /g, '').split(','); 12931 stage = { 12932 x: stage[stage.length === 16 ? 12 : 4], 12933 y: stage[stage.length === 16 ? 13 : 5] 12934 }; 12935 } else { 12936 stage = this.$stage.position(); 12937 stage = { 12938 x: this.settings.rtl ? 12939 stage.left + this.$stage.width() - this.width() + this.settings.margin : 12940 stage.left, 12941 y: stage.top 12942 }; 12943 } 12944 12945 if (this.is('animating')) { 12946 $.support.transform ? this.animate(stage.x) : this.$stage.stop() 12947 this.invalidate('position'); 12948 } 12949 12950 this.$element.toggleClass(this.options.grabClass, event.type === 'mousedown'); 12951 12952 this.speed(0); 12953 12954 this._drag.time = new Date().getTime(); 12955 this._drag.target = $(event.target); 12956 this._drag.stage.start = stage; 12957 this._drag.stage.current = stage; 12958 this._drag.pointer = this.pointer(event); 12959 12960 $(document).on('mouseup.owl.core touchend.owl.core', $.proxy(this.onDragEnd, this)); 12961 12962 $(document).one('mousemove.owl.core touchmove.owl.core', $.proxy(function(event) { 12963 var delta = this.difference(this._drag.pointer, this.pointer(event)); 12964 12965 $(document).on('mousemove.owl.core touchmove.owl.core', $.proxy(this.onDragMove, this)); 12966 12967 if (Math.abs(delta.x) < Math.abs(delta.y) && this.is('valid')) { 12968 return; 12969 } 12970 12971 event.preventDefault(); 12972 12973 this.enter('dragging'); 12974 this.trigger('drag'); 12975 }, this)); 12976 }; 12977 12978 /** 12979 * Handles the `touchmove` and `mousemove` events. 12980 * @todo #261 12981 * @protected 12982 * @param {Event} event - The event arguments. 12983 */ 12984 Owl.prototype.onDragMove = function(event) { 12985 var minimum = null, 12986 maximum = null, 12987 pull = null, 12988 delta = this.difference(this._drag.pointer, this.pointer(event)), 12989 stage = this.difference(this._drag.stage.start, delta); 12990 12991 if (!this.is('dragging')) { 12992 return; 12993 } 12994 12995 event.preventDefault(); 12996 12997 if (this.settings.loop) { 12998 minimum = this.coordinates(this.minimum()); 12999 maximum = this.coordinates(this.maximum() + 1) - minimum; 13000 stage.x = (((stage.x - minimum) % maximum + maximum) % maximum) + minimum; 13001 } else { 13002 minimum = this.settings.rtl ? this.coordinates(this.maximum()) : this.coordinates(this.minimum()); 13003 maximum = this.settings.rtl ? this.coordinates(this.minimum()) : this.coordinates(this.maximum()); 13004 pull = this.settings.pullDrag ? -1 * delta.x / 5 : 0; 13005 stage.x = Math.max(Math.min(stage.x, minimum + pull), maximum + pull); 13006 } 13007 13008 this._drag.stage.current = stage; 13009 13010 this.animate(stage.x); 13011 }; 13012 13013 /** 13014 * Handles the `touchend` and `mouseup` events. 13015 * @todo #261 13016 * @todo Threshold for click event 13017 * @protected 13018 * @param {Event} event - The event arguments. 13019 */ 13020 Owl.prototype.onDragEnd = function(event) { 13021 var delta = this.difference(this._drag.pointer, this.pointer(event)), 13022 stage = this._drag.stage.current, 13023 direction = delta.x > 0 ^ this.settings.rtl ? 'left' : 'right'; 13024 13025 $(document).off('.owl.core'); 13026 13027 this.$element.removeClass(this.options.grabClass); 13028 13029 if (delta.x !== 0 && this.is('dragging') || !this.is('valid')) { 13030 this.speed(this.settings.dragEndSpeed || this.settings.smartSpeed); 13031 this.current(this.closest(stage.x, delta.x !== 0 ? direction : this._drag.direction)); 13032 this.invalidate('position'); 13033 this.update(); 13034 13035 this._drag.direction = direction; 13036 13037 if (Math.abs(delta.x) > 3 || new Date().getTime() - this._drag.time > 300) { 13038 this._drag.target.one('click.owl.core', function() { return false; }); 13039 } 13040 } 13041 13042 if (!this.is('dragging')) { 13043 return; 13044 } 13045 13046 this.leave('dragging'); 13047 this.trigger('dragged'); 13048 }; 13049 13050 /** 13051 * Gets absolute position of the closest item for a coordinate. 13052 * @todo Setting `freeDrag` makes `closest` not reusable. See #165. 13053 * @protected 13054 * @param {Number} coordinate - The coordinate in pixel. 13055 * @param {String} direction - The direction to check for the closest item. Ether `left` or `right`. 13056 * @return {Number} - The absolute position of the closest item. 13057 */ 13058 Owl.prototype.closest = function(coordinate, direction) { 13059 var position = -1, 13060 pull = 30, 13061 width = this.width(), 13062 coordinates = this.coordinates(); 13063 13064 if (!this.settings.freeDrag) { 13065 // check closest item 13066 $.each(coordinates, $.proxy(function(index, value) { 13067 if (coordinate > value - pull && coordinate < value + pull) { 13068 position = index; 13069 } else if (this.op(coordinate, '<', value) 13070 && this.op(coordinate, '>', coordinates[index + 1] || value - width)) { 13071 position = direction === 'left' ? index + 1 : index; 13072 } 13073 return position === -1; 13074 }, this)); 13075 } 13076 13077 if (!this.settings.loop) { 13078 // non loop boundries 13079 if (this.op(coordinate, '>', coordinates[this.minimum()])) { 13080 position = coordinate = this.minimum(); 13081 } else if (this.op(coordinate, '<', coordinates[this.maximum()])) { 13082 position = coordinate = this.maximum(); 13083 } 13084 } 13085 13086 return position; 13087 }; 13088 13089 /** 13090 * Animates the stage. 13091 * @todo #270 13092 * @public 13093 * @param {Number} coordinate - The coordinate in pixels. 13094 */ 13095 Owl.prototype.animate = function(coordinate) { 13096 var animate = this.speed() > 0; 13097 13098 this.is('animating') && this.onTransitionEnd(); 13099 13100 if (animate) { 13101 this.enter('animating'); 13102 this.trigger('translate'); 13103 } 13104 13105 if ($.support.transform3d && $.support.transition) { 13106 this.$stage.css({ 13107 transform: 'translate3d(' + coordinate + 'px,0px,0px)', 13108 transition: (this.speed() / 1000) + 's' 13109 }); 13110 } else if (animate) { 13111 this.$stage.animate({ 13112 left: coordinate + 'px' 13113 }, this.speed(), this.settings.fallbackEasing, $.proxy(this.onTransitionEnd, this)); 13114 } else { 13115 this.$stage.css({ 13116 left: coordinate + 'px' 13117 }); 13118 } 13119 }; 13120 13121 /** 13122 * Checks whether the carousel is in a specific state or not. 13123 * @param {String} state - The state to check. 13124 * @returns {Boolean} - The flag which indicates if the carousel is busy. 13125 */ 13126 Owl.prototype.is = function(state) { 13127 return this._states.current[state] && this._states.current[state] > 0; 13128 }; 13129 13130 /** 13131 * Sets the absolute position of the current item. 13132 * @public 13133 * @param {Number} [position] - The new absolute position or nothing to leave it unchanged. 13134 * @returns {Number} - The absolute position of the current item. 13135 */ 13136 Owl.prototype.current = function(position) { 13137 if (position === undefined) { 13138 return this._current; 13139 } 13140 13141 if (this._items.length === 0) { 13142 return undefined; 13143 } 13144 13145 position = this.normalize(position); 13146 13147 if (this._current !== position) { 13148 var event = this.trigger('change', { property: { name: 'position', value: position } }); 13149 13150 if (event.data !== undefined) { 13151 position = this.normalize(event.data); 13152 } 13153 13154 this._current = position; 13155 13156 this.invalidate('position'); 13157 13158 this.trigger('changed', { property: { name: 'position', value: this._current } }); 13159 } 13160 13161 return this._current; 13162 }; 13163 13164 /** 13165 * Invalidates the given part of the update routine. 13166 * @param {String} [part] - The part to invalidate. 13167 * @returns {Array.<String>} - The invalidated parts. 13168 */ 13169 Owl.prototype.invalidate = function(part) { 13170 if ($.type(part) === 'string') { 13171 this._invalidated[part] = true; 13172 this.is('valid') && this.leave('valid'); 13173 } 13174 return $.map(this._invalidated, function(v, i) { return i }); 13175 }; 13176 13177 /** 13178 * Resets the absolute position of the current item. 13179 * @public 13180 * @param {Number} position - The absolute position of the new item. 13181 */ 13182 Owl.prototype.reset = function(position) { 13183 position = this.normalize(position); 13184 13185 if (position === undefined) { 13186 return; 13187 } 13188 13189 this._speed = 0; 13190 this._current = position; 13191 13192 this.suppress([ 'translate', 'translated' ]); 13193 13194 this.animate(this.coordinates(position)); 13195 13196 this.release([ 'translate', 'translated' ]); 13197 }; 13198 13199 /** 13200 * Normalizes an absolute or a relative position of an item. 13201 * @public 13202 * @param {Number} position - The absolute or relative position to normalize. 13203 * @param {Boolean} [relative=false] - Whether the given position is relative or not. 13204 * @returns {Number} - The normalized position. 13205 */ 13206 Owl.prototype.normalize = function(position, relative) { 13207 var n = this._items.length, 13208 m = relative ? 0 : this._clones.length; 13209 13210 if (!$.isNumeric(position) || n < 1) { 13211 position = undefined; 13212 } else if (position < 0 || position >= n + m) { 13213 position = ((position - m / 2) % n + n) % n + m / 2; 13214 } 13215 13216 return position; 13217 }; 13218 13219 /** 13220 * Converts an absolute position of an item into a relative one. 13221 * @public 13222 * @param {Number} position - The absolute position to convert. 13223 * @returns {Number} - The converted position. 13224 */ 13225 Owl.prototype.relative = function(position) { 13226 position -= this._clones.length / 2; 13227 return this.normalize(position, true); 13228 }; 13229 13230 /** 13231 * Gets the maximum position for the current item. 13232 * @public 13233 * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position. 13234 * @returns {Number} 13235 */ 13236 Owl.prototype.maximum = function(relative) { 13237 var settings = this.settings, 13238 maximum = this._coordinates.length, 13239 boundary = Math.abs(this._coordinates[maximum - 1]) - this._width, 13240 i = -1, j; 13241 13242 if (settings.loop) { 13243 maximum = this._clones.length / 2 + this._items.length - 1; 13244 } else if (settings.autoWidth || settings.merge) {
13245 // binary search 13246 while (maximum - i > 1) { 13247 Math.abs(this._coordinates[j = maximum + i >> 1]) < boundary 13248 ? i = j : maximum = j; 13249 } 13250 } else if (settings.center) { 13251 maximum = this._items.length - 1; 13252 } else { 13253 maximum = this._items.length - settings.items; 13254 } 13255 13256 if (relative) { 13257 maximum -= this._clones.length / 2; 13258 } 13259 13260 return Math.max(maximum, 0); 13261 }; 13262 13263 /** 13264 * Gets the minimum position for the current item. 13265 * @public 13266 * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position. 13267 * @returns {Number} 13268 */ 13269 Owl.prototype.minimum = function(relative) { 13270 return relative ? 0 : this._clones.length / 2; 13271 }; 13272 13273 /** 13274 * Gets an item at the specified relative position. 13275 * @public 13276 * @param {Number} [position] - The relative position of the item. 13277 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given. 13278 */ 13279 Owl.prototype.items = function(position) { 13280 if (position === undefined) { 13281 return this._items.slice(); 13282 } 13283 13284 position = this.normalize(position, true); 13285 return this._items[position]; 13286 }; 13287 13288 /** 13289 * Gets an item at the specified relative position. 13290 * @public 13291 * @param {Number} [position] - The relative position of the item. 13292 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given. 13293 */ 13294 Owl.prototype.mergers = function(position) { 13295 if (position === undefined) { 13296 return this._mergers.slice(); 13297 } 13298 13299 position = this.normalize(position, true); 13300 return this._mergers[position]; 13301 }; 13302 13303 /** 13304 * Gets the absolute positions of clones for an item. 13305 * @public 13306 * @param {Number} [position] - The relative position of the item. 13307 * @returns {Array.<Number>} - The absolute positions of clones for the item or all if no position was given. 13308 */ 13309 Owl.prototype.clones = function(position) { 13310 var odd = this._clones.length / 2, 13311 even = odd + this._items.length, 13312 map = function(index) { return index % 2 === 0 ? even + index / 2 : odd - (index + 1) / 2 }; 13313 13314 if (position === undefined) { 13315 return $.map(this._clones, function(v, i) { return map(i) }); 13316 } 13317 13318 return $.map(this._clones, function(v, i) { return v === position ? map(i) : null }); 13319 }; 13320 13321 /** 13322 * Sets the current animation speed. 13323 * @public 13324 * @param {Number} [speed] - The animation speed in milliseconds or nothing to leave it unchanged. 13325 * @returns {Number} - The current animation speed in milliseconds. 13326 */ 13327 Owl.prototype.speed = function(speed) { 13328 if (speed !== undefined) { 13329 this._speed = speed; 13330 } 13331 13332 return this._speed; 13333 }; 13334 13335 /** 13336 * Gets the coordinate of an item. 13337 * @todo The name of this method is missleanding. 13338 * @public 13339 * @param {Number} position - The absolute position of the item within `minimum()` and `maximum()`. 13340 * @returns {Number|Array.<Number>} - The coordinate of the item in pixel or all coordinates. 13341 */ 13342 Owl.prototype.coordinates = function(position) { 13343 var coordinate = null; 13344 13345 if (position === undefined) { 13346 return $.map(this._coordinates, $.proxy(function(coordinate, index) { 13347 return this.coordinates(index); 13348 }, this)); 13349 } 13350 13351 if (this.settings.center) { 13352 coordinate = this._coordinates[position]; 13353 coordinate += (this.width() - coordinate + (this._coordinates[position - 1] || 0)) / 2 * (this.settings.rtl ? -1 : 1); 13354 } else { 13355 coordinate = this._coordinates[position - 1] || 0; 13356 } 13357 13358 return coordinate; 13359 }; 13360 13361 /** 13362 * Calculates the speed for a translation. 13363 * @protected 13364 * @param {Number} from - The absolute position of the start item. 13365 * @param {Number} to - The absolute position of the target item. 13366 * @param {Number} [factor=undefined] - The time factor in milliseconds. 13367 * @returns {Number} - The time in milliseconds for the translation. 13368 */ 13369 Owl.prototype.duration = function(from, to, factor) { 13370 return Math.min(Math.max(Math.abs(to - from), 1), 6) * Math.abs((factor || this.settings.smartSpeed)); 13371 }; 13372 13373 /** 13374 * Slides to the specified item. 13375 * @public 13376 * @param {Number} position - The position of the item. 13377 * @param {Number} [speed] - The time in milliseconds for the transition. 13378 */ 13379 Owl.prototype.to = function(position, speed) { 13380 var current = this.current(), 13381 revert = null, 13382 distance = position - this.relative(current), 13383 direction = (distance > 0) - (distance < 0), 13384 items = this._items.length, 13385 minimum = this.minimum(), 13386 maximum = this.maximum(); 13387 13388 if (this.settings.loop) { 13389 if (!this.settings.rewind && Math.abs(distance) > items / 2) { 13390 distance += direction * -1 * items; 13391 } 13392 13393 position = current + distance; 13394 revert = ((position - minimum) % items + items) % items + minimum; 13395 13396 if (revert !== position && revert - distance <= maximum && revert - distance > 0) { 13397 current = revert - distance; 13398 position = revert; 13399 this.reset(current); 13400 } 13401 } else if (this.settings.rewind) { 13402 maximum += 1; 13403 position = (position % maximum + maximum) % maximum; 13404 } else { 13405 position = Math.max(minimum, Math.min(maximum, position)); 13406 } 13407 13408 this.speed(this.duration(current, position, speed)); 13409 this.current(position); 13410 13411 if (this.$element.is(':visible')) { 13412 this.update(); 13413 } 13414 }; 13415 13416 /** 13417 * Slides to the next item. 13418 * @public 13419 * @param {Number}
vendor: 12,284 bytes, lines 13419-13839
13419 [speed] - The time in milliseconds for the transition. 13420 */ 13421 Owl.prototype.next = function(speed) { 13422 speed = speed || false; 13423 this.to(this.relative(this.current()) + 1, speed); 13424 }; 13425 13426 /** 13427 * Slides to the previous item. 13428 * @public 13429 * @param {Number} [speed] - The time in milliseconds for the transition. 13430 */ 13431 Owl.prototype.prev = function(speed) { 13432 speed = speed || false; 13433 this.to(this.relative(this.current()) - 1, speed); 13434 }; 13435 13436 /** 13437 * Handles the end of an animation. 13438 * @protected 13439 * @param {Event} event - The event arguments. 13440 */ 13441 Owl.prototype.onTransitionEnd = function(event) { 13442 13443 // if css2 animation then event object is undefined 13444 if (event !== undefined) { 13445 event.stopPropagation(); 13446 13447 // Catch only owl-stage transitionEnd event 13448 if ((event.target || event.srcElement || event.originalTarget) !== this.$stage.get(0)) { 13449 return false; 13450 } 13451 } 13452 13453 this.leave('animating'); 13454 this.trigger('translated'); 13455 }; 13456 13457 /** 13458 * Gets viewport width. 13459 * @protected 13460 * @return {Number} - The width in pixel. 13461 */ 13462 Owl.prototype.viewport = function() { 13463 var width; 13464 if (this.options.responsiveBaseElement !== window) { 13465 width = $(this.options.responsiveBaseElement).width(); 13466 } else if (window.innerWidth) { 13467 width = window.innerWidth; 13468 } else if (document.documentElement && document.documentElement.clientWidth) { 13469 width = document.documentElement.clientWidth; 13470 } else { 13471 throw 'Can not detect viewport width.'; 13472 } 13473 13474 return width; 13475 }; 13476 13477 /** 13478 * Replaces the current content. 13479 * @public 13480 * @param {HTMLElement|jQuery|String} content - The new content. 13481 */ 13482 Owl.prototype.replace = function(content) { 13483 this.$stage.empty(); 13484 this._items = []; 13485 13486 if (content) { 13487 content = (content instanceof jQuery) ? content : $(content); 13488 } 13489 13490 if (this.settings.nestedItemSelector) { 13491 content = content.find('.' + this.settings.nestedItemSelector); 13492 } 13493 13494 content.filter(function() { 13495 return this.nodeType === 1; 13496 }).each($.proxy(function(index, item) { 13497 item = this.prepare(item, index); 13498 this.$stage.append(item); 13499 this._items.push(item); 13500 this._mergers.push(item.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1); 13501 }, this)); 13502 13503 this.reset($.isNumeric(this.settings.startPosition) ? this.settings.startPosition : 0); 13504 13505 this.invalidate('items'); 13506 }; 13507 13508 /** 13509 * Adds an item. 13510 * @todo Use `item` instead of `content` for the event arguments. 13511 * @public 13512 * @param {HTMLElement|jQuery|String} content - The item content to add. 13513 * @param {Number} [position] - The relative position at which to insert the item otherwise the item will be added to the end. 13514 */ 13515 Owl.prototype.add = function(content, position) { 13516 var current = this.relative(this._current); 13517 13518 position = position === undefined ? this._items.length : this.normalize(position, true); 13519 content = content instanceof jQuery ? content : $(content); 13520 13521 this.trigger('add', { content: content, position: position }); 13522 13523 content = this.prepare(content, this._items[current].index()); 13524 13525 if (this._items.length === 0 || position === this._items.length) { 13526 this._items.length === 0 && this.$stage.append(content); 13527 this._items.length !== 0 && this._items[position - 1].after(content); 13528 this._items.push(content); 13529 this._mergers.push(content.find('[data-merge]').andSelf('[data-merge]').attr('data-merge') * 1 || 1); 13530 } else { 13531 this._items[position].before(content); 13532 this._items.splice(position, 0, content); 13533 this._mergers.splice(position, 0, content.find('[data-merge]').andSelf('[data-merge]').attr('data-merge') * 1 || 1); 13534 } 13535 13536 this._items[current] && this.reset(this._items[current].index()); 13537 13538 this.invalidate('items'); 13539 13540 this.trigger('added', { content: content, position: position }); 13541 }; 13542 13543 /** 13544 * Removes an item by its position. 13545 * @todo Use `item` instead of `content` for the event arguments. 13546 * @public 13547 * @param {Number} position - The relative position of the item to remove. 13548 */ 13549 Owl.prototype.remove = function(position) { 13550 position = this.normalize(position, true); 13551 13552 if (position === undefined) { 13553 return; 13554 } 13555 13556 this.trigger('remove', { content: this._items[position], position: position }); 13557 13558 this._items[position].remove(); 13559 this._items.splice(position, 1); 13560 this._mergers.splice(position, 1); 13561 13562 this.invalidate('items'); 13563 13564 this.trigger('removed', { content: null, position: position }); 13565 }; 13566 13567 /** 13568 * Preloads images with auto width. 13569 * @todo Replace by a more generic approach 13570 * @protected 13571 */ 13572 Owl.prototype.preloadAutoWidthImages = function(images) { 13573 images.each($.proxy(function(i, element) { 13574 this.enter('pre-loading'); 13575 element = $(element); 13576 $(new Image()).one('load', $.proxy(function(e) { 13577 element.attr('src', e.target.src); 13578 element.css('opacity', 1); 13579 this.leave('pre-loading'); 13580 !this.is('pre-loading') && !this.is('initializing') && this.refresh(); 13581 }, this)).attr('src', element.attr('src') || element.attr('data-src') || element.attr('data-src-retina')); 13582 }, this)); 13583 }; 13584 13585 /** 13586 * Destroys the carousel. 13587 * @public 13588 */ 13589 Owl.prototype.destroy = function() { 13590 13591 this.$element.off('.owl.core'); 13592 this.$stage.off('.owl.core'); 13593 $(document).off('.owl.core'); 13594 13595 if (this.settings.responsive !== false) { 13596 window.clearTimeout(this.resizeTimer); 13597 this.off(window, 'resize', this._handlers.onThrottledResize); 13598 } 13599 13600 for (var i in this._plugins) { 13601 this._plugins[i].destroy(); 13602 } 13603 13604 this.$stage.children('.cloned').remove(); 13605 13606 this.$stage.unwrap(); 13607 this.$stage.children().contents().unwrap(); 13608 this.$stage.children().unwrap(); 13609 13610 this.$element 13611 .removeClass(this.options.refreshClass) 13612 .removeClass(this.options.loadingClass) 13613 .removeClass(this.options.loadedClass) 13614 .removeClass(this.options.rtlClass) 13615 .removeClass(this.options.dragClass) 13616 .removeClass(this.options.grabClass) 13617 .attr('class', this.$element.attr('class').replace(new RegExp(this.options.responsiveClass + '-\\S+\\s', 'g'), '')) 13618 .removeData('owl.carousel'); 13619 }; 13620 13621 /** 13622 * Operators to calculate right-to-left and left-to-right. 13623 * @protected 13624 * @param {Number} [a] - The left side operand. 13625 * @param {String} [o] - The operator. 13626 * @param {Number} [b] - The right side operand. 13627 */ 13628 Owl.prototype.op = function(a, o, b) { 13629 var rtl = this.settings.rtl; 13630 switch (o) { 13631 case '<': 13632 return rtl ? a > b : a < b; 13633 case '>': 13634 return rtl ? a < b : a > b; 13635 case '>=': 13636 return rtl ? a <= b : a >= b; 13637 case '<=': 13638 return rtl ? a >= b : a <= b; 13639 default: 13640 break; 13641 } 13642 }; 13643 13644 /** 13645 * Attaches to an internal event. 13646 * @protected 13647 * @param {HTMLElement} element - The event source. 13648 * @param {String} event - The event name. 13649 * @param {Function} listener - The event handler to attach. 13650 * @param {Boolean} capture - Wether the event should be handled at the capturing phase or not. 13651 */ 13652 Owl.prototype.on = function(element, event, listener, capture) { 13653 if (element.addEventListener) { 13654 element.addEventListener(event, listener, capture); 13655 } else if (element.attachEvent) { 13656 element.attachEvent('on' + event, listener); 13657 } 13658 }; 13659 13660 /** 13661 * Detaches from an internal event. 13662 * @protected 13663 * @param {HTMLElement} element - The event source. 13664 * @param {String} event - The event name. 13665 * @param {Function} listener - The attached event handler to detach. 13666 * @param {Boolean} capture - Wether the attached event handler was registered as a capturing listener or not. 13667 */ 13668 Owl.prototype.off = function(element, event, listener, capture) { 13669 if (element.removeEventListener) { 13670 element.removeEventListener(event, listener, capture); 13671 } else if (element.detachEvent) { 13672 element.detachEvent('on' + event, listener); 13673 } 13674 }; 13675 13676 /** 13677 * Triggers a public event. 13678 * @todo Remove `status`, `relatedTarget` should be used instead. 13679 * @protected 13680 * @param {String} name - The event name. 13681 * @param {*} [data=null] - The event data. 13682 * @param {String} [namespace=carousel] - The event namespace. 13683 * @param {String} [state] - The state which is associated with the event. 13684 * @param {Boolean} [enter=false] - Indicates if the call enters the specified state or not. 13685 * @returns {Event} - The event arguments. 13686 */ 13687 Owl.prototype.trigger = function(name, data, namespace, state, enter) { 13688 var status = { 13689 item: { count: this._items.length, index: this.current() } 13690 }, handler = $.camelCase( 13691 $.grep([ 'on', name, namespace ], function(v) { return v }) 13692 .join('-').toLowerCase() 13693 ), event = $.Event( 13694 [ name, 'owl', namespace || 'carousel' ].join('.').toLowerCase(), 13695 $.extend({ relatedTarget: this }, status, data) 13696 ); 13697 13698 if (!this._supress[name]) { 13699 $.each(this._plugins, function(name, plugin) { 13700 if (plugin.onTrigger) { 13701 plugin.onTrigger(event); 13702 } 13703 }); 13704 13705 this.register({ type: Owl.Type.Event, name: name }); 13706 this.$element.trigger(event); 13707 13708 if (this.settings && typeof this.settings[handler] === 'function') { 13709 this.settings[handler].call(this, event); 13710 } 13711 } 13712 13713 return event; 13714 }; 13715 13716 /** 13717 * Enters a state. 13718 * @param name - The state name. 13719 */ 13720 Owl.prototype.enter = function(name) { 13721 $.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) { 13722 if (this._states.current[name] === undefined) { 13723 this._states.current[name] = 0; 13724 } 13725 13726 this._states.current[name]++; 13727 }, this)); 13728 }; 13729 13730 /** 13731 * Leaves a state. 13732 * @param name - The state name. 13733 */ 13734 Owl.prototype.leave = function(name) { 13735 $.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) { 13736 this._states.current[name]--; 13737 }, this)); 13738 }; 13739 13740 /** 13741 * Registers an event or state. 13742 * @public 13743 * @param {Object} object - The event or state to register. 13744 */ 13745 Owl.prototype.register = function(object) { 13746 if (object.type === Owl.Type.Event) { 13747 if (!$.event.special[object.name]) { 13748 $.event.special[object.name] = {}; 13749 } 13750 13751 if (!$.event.special[object.name].owl) { 13752 var _default = $.event.special[object.name]._default; 13753 $.event.special[object.name]._default = function(e) { 13754 if (_default && _default.apply && (!e.namespace || e.namespace.indexOf('owl') === -1)) { 13755 return _default.apply(this, arguments); 13756 } 13757 return e.namespace && e.namespace.indexOf('owl') > -1; 13758 }; 13759 $.event.special[object.name].owl = true; 13760 } 13761 } else if (object.type === Owl.Type.State) { 13762 if (!this._states.tags[object.name]) { 13763 this._states.tags[object.name] = object.tags; 13764 } else { 13765 this._states.tags[object.name] = this._states.tags[object.name].concat(object.tags); 13766 } 13767 13768 this._states.tags[object.name] = $.grep(this._states.tags[object.name], $.proxy(function(tag, i) { 13769 return $.inArray(tag, this._states.tags[object.name]) === i; 13770 }, this)); 13771 } 13772 }; 13773 13774 /** 13775 * Suppresses events. 13776 * @protected 13777 * @param {Array.<String>} events - The events to suppress. 13778 */ 13779 Owl.prototype.suppress = function(events) { 13780 $.each(events, $.proxy(function(index, event) { 13781 this._supress[event] = true; 13782 }, this)); 13783 }; 13784 13785 /** 13786 * Releases suppressed events. 13787 * @protected 13788 * @param {Array.<String>} events - The events to release. 13789 */ 13790 Owl.prototype.release = function(events) { 13791 $.each(events, $.proxy(function(index, event) { 13792 delete this._supress[event]; 13793 }, this)); 13794 }; 13795 13796 /** 13797 * Gets unified pointer coordinates from event. 13798 * @todo #261 13799 * @protected 13800 * @param {Event} - The `mousedown` or `touchstart` event. 13801 * @returns {Object} - Contains `x` and `y` coordinates of current pointer position. 13802 */ 13803 Owl.prototype.pointer = function(event) { 13804 var result = { x: null, y: null }; 13805 13806 event = event.originalEvent || event || window.event; 13807 13808 event = event.touches && event.touches.length ? 13809 event.touches[0] : event.changedTouches && event.changedTouches.length ? 13810 event.changedTouches[0] : event; 13811 13812 if (event.pageX) { 13813 result.x = event.pageX; 13814 result.y = event.pageY; 13815 } else { 13816 result.x = event.clientX; 13817 result.y = event.clientY; 13818 } 13819 13820 return result; 13821 }; 13822 13823 /** 13824 * Gets the difference of two vectors. 13825 * @todo #261 13826 * @protected 13827 * @param {Object} - The first vector. 13828 * @param {Object} - The second vector. 13829 * @returns {Object} - The difference. 13830 */ 13831 Owl.prototype.difference = function(first, second) { 13832 return { 13833 x: first.x - second.x, 13834 y: first.y - second.y 13835 }; 13836 }; 13837 13838 /** 13839 * The jQuery Plugin for the Owl Carousel
vendor: 32,216 bytes, lines 13840-15122
13840 * @todo Navigation plugin `next` and `prev` 13841 * @public 13842 */ 13843 $.fn.owlCarousel = function(option) { 13844 var args = Array.prototype.slice.call(arguments, 1); 13845 13846 return this.each(function() { 13847 var $this = $(this), 13848 data = $this.data('owl.carousel'); 13849 13850 if (!data) { 13851 data = new Owl(this, typeof option == 'object' && option); 13852 $this.data('owl.carousel', data); 13853 13854 $.each([ 13855 'next', 'prev', 'to', 'destroy', 'refresh', 'replace', 'add', 'remove' 13856 ], function(i, event) { 13857 data.register({ type: Owl.Type.Event, name: event }); 13858 data.$element.on(event + '.owl.carousel.core', $.proxy(function(e) { 13859 if (e.namespace && e.relatedTarget !== this) { 13860 this.suppress([ event ]); 13861 data[event].apply(this, [].slice.call(arguments, 1)); 13862 this.release([ event ]); 13863 } 13864 }, data)); 13865 }); 13866 } 13867 13868 if (typeof option == 'string' && option.charAt(0) !== '_') { 13869 data[option].apply(data, args); 13870 } 13871 }); 13872 }; 13873 13874 /** 13875 * The constructor for the jQuery Plugin 13876 * @public 13877 */ 13878 $.fn.owlCarousel.Constructor = Owl; 13879 13880})(window.Zepto || window.jQuery, window, document); 13881 13882/** 13883 * AutoRefresh Plugin 13884 * @version 2.0.0-beta.3 13885 * @author Artus Kolanowski 13886 * @license The MIT License (MIT) 13887 */ 13888;(function($, window, document, undefined) { 13889 13890 /** 13891 * Creates the auto refresh plugin. 13892 * @class The Auto Refresh Plugin 13893 * @param {Owl} carousel - The Owl Carousel 13894 */ 13895 var AutoRefresh = function(carousel) { 13896 /** 13897 * Reference to the core. 13898 * @protected 13899 * @type {Owl} 13900 */ 13901 this._core = carousel; 13902 13903 /** 13904 * Refresh interval. 13905 * @protected 13906 * @type {number} 13907 */ 13908 this._interval = null; 13909 13910 /** 13911 * Whether the element is currently visible or not. 13912 * @protected 13913 * @type {Boolean} 13914 */ 13915 this._visible = null; 13916 13917 /** 13918 * All event handlers. 13919 * @protected 13920 * @type {Object} 13921 */ 13922 this._handlers = { 13923 'initialized.owl.carousel': $.proxy(function(e) { 13924 if (e.namespace && this._core.settings.autoRefresh) { 13925 this.watch(); 13926 } 13927 }, this) 13928 }; 13929 13930 // set default options 13931 this._core.options = $.extend({}, AutoRefresh.Defaults, this._core.options); 13932 13933 // register event handlers 13934 this._core.$element.on(this._handlers); 13935 }; 13936 13937 /** 13938 * Default options. 13939 * @public 13940 */ 13941 AutoRefresh.Defaults = { 13942 autoRefresh: true, 13943 autoRefreshInterval: 500 13944 }; 13945 13946 /** 13947 * Watches the element. 13948 */ 13949 AutoRefresh.prototype.watch = function() { 13950 if (this._interval) { 13951 return; 13952 } 13953 13954 this._visible = this._core.$element.is(':visible'); 13955 this._interval = window.setInterval($.proxy(this.refresh, this), this._core.settings.autoRefreshInterval); 13956 }; 13957 13958 /** 13959 * Refreshes the element. 13960 */ 13961 AutoRefresh.prototype.refresh = function() { 13962 if (this._core.$element.is(':visible') === this._visible) { 13963 return; 13964 } 13965 13966 this._visible = !this._visible; 13967 13968 this._core.$element.toggleClass('owl-hidden', !this._visible); 13969 13970 this._visible && (this._core.invalidate('width') && this._core.refresh()); 13971 }; 13972 13973 /** 13974 * Destroys the plugin. 13975 */ 13976 AutoRefresh.prototype.destroy = function() { 13977 var handler, property; 13978 13979 window.clearInterval(this._interval); 13980 13981 for (handler in this._handlers) { 13982 this._core.$element.off(handler, this._handlers[handler]); 13983 } 13984 for (property in Object.getOwnPropertyNames(this)) { 13985 typeof this[property] != 'function' && (this[property] = null); 13986 } 13987 }; 13988 13989 $.fn.owlCarousel.Constructor.Plugins.AutoRefresh = AutoRefresh; 13990 13991})(window.Zepto || window.jQuery, window, document); 13992 13993/** 13994 * Lazy Plugin 13995 * @version 2.0.0-beta.3 13996 * @author Bartosz Wojciechowski 13997 * @license The MIT License (MIT) 13998 */ 13999;(function($, window, document, undefined) { 14000 14001 /** 14002 * Creates the lazy plugin. 14003 * @class The Lazy Plugin 14004 * @param {Owl} carousel - The Owl Carousel 14005 */ 14006 var Lazy = function(carousel) { 14007 14008 /** 14009 * Reference to the core. 14010 * @protected 14011 * @type {Owl} 14012 */ 14013 this._core = carousel; 14014 14015 /** 14016 * Already loaded items. 14017 * @protected 14018 * @type {Array.<jQuery>} 14019 */ 14020 this._loaded = []; 14021 14022 /** 14023 * Event handlers. 14024 * @protected 14025 * @type {Object} 14026 */ 14027 this._handlers = { 14028 'initialized.owl.carousel change.owl.carousel': $.proxy(function(e) { 14029 if (!e.namespace) { 14030 return; 14031 } 14032 14033 if (!this._core.settings || !this._core.settings.lazyLoad) { 14034 return; 14035 } 14036 14037 if ((e.property && e.property.name == 'position') || e.type == 'initialized') { 14038 var settings = this._core.settings, 14039 n = (settings.center && Math.ceil(settings.items / 2) || settings.items), 14040 i = ((settings.center && n * -1) || 0), 14041 position = ((e.property && e.property.value) || this._core.current()) + i, 14042 clones = this._core.clones().length, 14043 load = $.proxy(function(i, v) { this.load(v) }, this); 14044 14045 while (i++ < n) { 14046 this.load(clones / 2 + this._core.relative(position)); 14047 clones && $.each(this._core.clones(this._core.relative(position)), load); 14048 position++; 14049 } 14050 } 14051 }, this) 14052 }; 14053 14054 // set the default options 14055 this._core.options = $.extend({}, Lazy.Defaults, this._core.options); 14056 14057 // register event handler 14058 this._core.$element.on(this._handlers); 14059 } 14060 14061 /** 14062 * Default options. 14063 * @public 14064 */ 14065 Lazy.Defaults = { 14066 lazyLoad: false 14067 } 14068 14069 /** 14070 * Loads all resources of an item at the specified position. 14071 * @param {Number} position - The absolute position of the item. 14072 * @protected 14073 */ 14074 Lazy.prototype.load = function(position) { 14075 var $item = this._core.$stage.children().eq(position), 14076 $elements = $item && $item.find('.owl-lazy'); 14077 14078 if (!$elements || $.inArray($item.get(0), this._loaded) > -1) { 14079 return; 14080 } 14081 14082 $elements.each($.proxy(function(index, element) { 14083 var $element = $(element), image, 14084 url = (window.devicePixelRatio > 1 && $element.attr('data-src-retina')) || $element.attr('data-src'); 14085 14086 this._core.trigger('load', { element: $element, url: url }, 'lazy'); 14087 14088 if ($element.is('img')) { 14089 $element.one('load.owl.lazy', $.proxy(function() { 14090 $element.css('opacity', 1); 14091 this._core.trigger('loaded', { element: $element, url: url }, 'lazy'); 14092 }, this)).attr('src', url); 14093 } else { 14094 image = new Image(); 14095 image.onload = $.proxy(function() { 14096 $element.css({ 14097 'background-image': 'url(' + url + ')', 14098 'opacity': '1' 14099 }); 14100 this._core.trigger('loaded', { element: $element, url: url }, 'lazy'); 14101 }, this); 14102 image.src = url; 14103 } 14104 }, this)); 14105 14106 this._loaded.push($item.get(0)); 14107 } 14108 14109 /** 14110 * Destroys the plugin. 14111 * @public 14112 */ 14113 Lazy.prototype.destroy = function() { 14114 var handler, property; 14115 14116 for (handler in this.handlers) { 14117 this._core.$element.off(handler, this.handlers[handler]); 14118 } 14119 for (property in Object.getOwnPropertyNames(this)) { 14120 typeof this[property] != 'function' && (this[property] = null); 14121 } 14122 }; 14123 14124 $.fn.owlCarousel.Constructor.Plugins.Lazy = Lazy; 14125 14126})(window.Zepto || window.jQuery, window, document); 14127 14128/** 14129 * AutoHeight Plugin 14130 * @version 2.0.0-beta.3 14131 * @author Bartosz Wojciechowski 14132 * @license The MIT License (MIT) 14133 */ 14134;(function($, window, document, undefined) { 14135 14136 /** 14137 * Creates the auto height plugin. 14138 * @class The Auto Height Plugin 14139 * @param {Owl} carousel - The Owl Carousel 14140 */ 14141 var AutoHeight = function(carousel) { 14142 /** 14143 * Reference to the core. 14144 * @protected 14145 * @type {Owl} 14146 */ 14147 this._core = carousel; 14148 14149 /** 14150 * All event handlers. 14151 * @protected 14152 * @type {Object} 14153 */ 14154 this._handlers = { 14155 'initialized.owl.carousel refreshed.owl.carousel': $.proxy(function(e) { 14156 if (e.namespace && this._core.settings.autoHeight) { 14157 this.update(); 14158 } 14159 }, this), 14160 'changed.owl.carousel': $.proxy(function(e) { 14161 if (e.namespace && this._core.settings.autoHeight && e.property.name == 'position'){ 14162 this.update(); 14163 } 14164 }, this), 14165 'loaded.owl.lazy': $.proxy(function(e) { 14166 if (e.namespace && this._core.settings.autoHeight 14167 && e.element.closest('.' + this._core.settings.itemClass).index() === this._core.current()) { 14168 this.update(); 14169 } 14170 }, this) 14171 }; 14172 14173 // set default options 14174 this._core.options = $.extend({}, AutoHeight.Defaults, this._core.options); 14175 14176 // register event handlers 14177 this._core.$element.on(this._handlers); 14178 }; 14179 14180 /** 14181 * Default options. 14182 * @public 14183 */ 14184 AutoHeight.Defaults = { 14185 autoHeight: false, 14186 autoHeightClass: 'owl-height' 14187 }; 14188 14189 /** 14190 * Updates the view. 14191 */ 14192 AutoHeight.prototype.update = function() { 14193 var start = this._core._current, 14194 end = start + this._core.settings.items, 14195 visible = this._core.$stage.children().toArray().slice(start, end); 14196 heights = [], 14197 maxheight = 0; 14198 14199 $.each(visible, function(index, item) { 14200 heights.push($(item).height()); 14201 }); 14202 14203 maxheight = Math.max.apply(null, heights); 14204 14205 this._core.$stage.parent() 14206 .height(maxheight) 14207 .addClass(this._core.settings.autoHeightClass); 14208 }; 14209 14210 AutoHeight.prototype.destroy = function() { 14211 var handler, property; 14212 14213 for (handler in this._handlers) { 14214 this._core.$element.off(handler, this._handlers[handler]); 14215 } 14216 for (property in Object.getOwnPropertyNames(this)) { 14217 typeof this[property] != 'function' && (this[property] = null); 14218 } 14219 }; 14220 14221 $.fn.owlCarousel.Constructor.Plugins.AutoHeight = AutoHeight; 14222 14223})(window.Zepto || window.jQuery, window, document); 14224 14225/** 14226 * Video Plugin 14227 * @version 2.0.0-beta.3 14228 * @author Bartosz Wojciechowski 14229 * @license The MIT License (MIT) 14230 */ 14231;(function($, window, document, undefined) { 14232 14233 /** 14234 * Creates the video plugin. 14235 * @class The Video Plugin 14236 * @param {Owl} carousel - The Owl Carousel 14237 */ 14238 var Video = function(carousel) { 14239 /** 14240 * Reference to the core. 14241 * @protected 14242 * @type {Owl} 14243 */ 14244 this._core = carousel; 14245 14246 /** 14247 * Cache all video URLs. 14248 * @protected 14249 * @type {Object} 14250 */ 14251 this._videos = {}; 14252 14253 /** 14254 * Current playing item. 14255 * @protected 14256 * @type {jQuery} 14257 */ 14258 this._playing = null; 14259 14260 /** 14261 * All event handlers. 14262 * @todo The cloned content removale is too late 14263 * @protected 14264 * @type {Object} 14265 */ 14266 this._handlers = { 14267 'initialized.owl.carousel': $.proxy(function(e) { 14268 if (e.namespace) { 14269 this._core.register({ type: 'state', name: 'playing', tags: [ 'interacting' ] }); 14270 } 14271 }, this), 14272 'resize.owl.carousel': $.proxy(function(e) { 14273 if (e.namespace && this._core.settings.video && this.isInFullScreen()) { 14274 e.preventDefault(); 14275 } 14276 }, this), 14277 'refreshed.owl.carousel': $.proxy(function(e) { 14278 if (e.namespace && this._core.is('resizing')) { 14279 this._core.$stage.find('.cloned .owl-video-frame').remove(); 14280 } 14281 }, this), 14282 'changed.owl.carousel': $.proxy(function(e) { 14283 if (e.namespace && e.property.name === 'position' && this._playing) { 14284 this.stop(); 14285 } 14286 }, this), 14287 'prepared.owl.carousel': $.proxy(function(e) { 14288 if (!e.namespace) { 14289 return; 14290 } 14291 14292 var $element = $(e.content).find('.owl-video'); 14293 14294 if ($element.length) { 14295 $element.css('display', 'none'); 14296 this.fetch($element, $(e.content)); 14297 } 14298 }, this) 14299 }; 14300 14301 // set default options 14302 this._core.options = $.extend({}, Video.Defaults, this._core.options); 14303 14304 // register event handlers 14305 this._core.$element.on(this._handlers); 14306 14307 this._core.$element.on('click.owl.video', '.owl-video-play-icon', $.proxy(function(e) { 14308 this.play(e); 14309 }, this)); 14310 }; 14311 14312 /** 14313 * Default options. 14314 * @public 14315 */ 14316 Video.Defaults = { 14317 video: false, 14318 videoHeight: false, 14319 videoWidth: false 14320 }; 14321 14322 /** 14323 * Gets the video ID and the type (YouTube/Vimeo only). 14324 * @protected 14325 * @param {jQuery} target - The target containing the video data. 14326 * @param {jQuery} item - The item containing the video. 14327 */ 14328 Video.prototype.fetch = function(target, item) { 14329 var type = target.attr('data-vimeo-id') ? 'vimeo' : 'youtube', 14330 id = target.attr('data-vimeo-id') || target.attr('data-youtube-id'), 14331 width = target.attr('data-width') || this._core.settings.videoWidth, 14332 height = target.attr('data-height') || this._core.settings.videoHeight, 14333 url = target.attr('href'); 14334 14335 if (url) { 14336 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+)?/); 14337 14338 if (id[3].indexOf('youtu') > -1) { 14339 type = 'youtube'; 14340 } else if (id[3].indexOf('vimeo') > -1) { 14341 type = 'vimeo'; 14342 } else { 14343 throw new Error('Video URL not supported.'); 14344 } 14345 id = id[6]; 14346 } else { 14347 throw new Error('Missing video URL.'); 14348 } 14349 14350 this._videos[url] = { 14351 type: type, 14352 id: id, 14353 width: width, 14354 height: height 14355 }; 14356 14357 item.attr('data-video', url); 14358 14359 this.thumbnail(target, this._videos[url]); 14360 }; 14361 14362 /** 14363 * Creates video thumbnail. 14364 * @protected 14365 * @param {jQuery} target - The target containing the video data. 14366 * @param {Object} info - The video info object. 14367 * @see `fetch` 14368 */ 14369 Video.prototype.thumbnail = function(target, video) { 14370 var tnLink, 14371 icon, 14372 path, 14373 dimensions = video.width && video.height ? 'style="width:' + video.width + 'px;height:' + video.height + 'px;"' : '', 14374 customTn = target.find('img'), 14375 srcType = 'src', 14376 lazyClass = '', 14377 settings = this._core.settings, 14378 create = function(path) { 14379 icon = '<div class="owl-video-play-icon"></div>'; 14380 14381 if (settings.lazyLoad) { 14382 tnLink = '<div class="owl-video-tn ' + lazyClass + '" ' + srcType + '="' + path + '"></div>'; 14383 } else { 14384 tnLink = '<div class="owl-video-tn" style="opacity:1;background-image:url(' + path + ')"></div>'; 14385 } 14386 target.after(tnLink); 14387 target.after(icon); 14388 }; 14389 14390 // wrap video content into owl-video-wrapper div 14391 target.wrap('<div class="owl-video-wrapper"' + dimensions + '></div>'); 14392 14393 if (this._core.settings.lazyLoad) { 14394 srcType = 'data-src'; 14395 lazyClass = 'owl-lazy'; 14396 } 14397 14398 // custom thumbnail 14399 if (customTn.length) { 14400 create(customTn.attr(srcType)); 14401 customTn.remove(); 14402 return false; 14403 } 14404 14405 if (video.type === 'youtube') { 14406 path = "//img.youtube.com/vi/" + video.id + "/hqdefault.jpg"; 14407 create(path); 14408 } else if (video.type === 'vimeo') { 14409 $.ajax({ 14410 type: 'GET', 14411 url: '//vimeo.com/api/v2/video/' + video.id + '.json', 14412 jsonp: 'callback', 14413 dataType: 'jsonp', 14414 success: function(data) { 14415 path = data[0].thumbnail_large; 14416 create(path); 14417 } 14418 }); 14419 } 14420 }; 14421 14422 /** 14423 * Stops the current video. 14424 * @public 14425 */ 14426 Video.prototype.stop = function() { 14427 this._core.trigger('stop', null, 'video'); 14428 this._playing.find('.owl-video-frame').remove(); 14429 this._playing.removeClass('owl-video-playing'); 14430 this._playing = null; 14431 this._core.leave('playing'); 14432 this._core.trigger('stopped', null, 'video'); 14433 }; 14434 14435 /** 14436 * Starts the current video. 14437 * @public 14438 * @param {Event} event - The event arguments. 14439 */ 14440 Video.prototype.play = function(event) { 14441 var target = $(event.target), 14442 item = target.closest('.' + this._core.settings.itemClass), 14443 video = this._videos[item.attr('data-video')], 14444 width = video.width || '100%', 14445 height = video.height || this._core.$stage.height(), 14446 html; 14447 14448 if (this._playing) { 14449 return; 14450 } 14451 14452 this._core.enter('playing'); 14453 this._core.trigger('play', null, 'video'); 14454 14455 item = this._core.items(this._core.relative(item.index())); 14456 14457 this._core.reset(item.index()); 14458 14459 if (video.type === 'youtube') { 14460 html = '<iframe width="' + width + '" height="' + height + '" src="//www.youtube.com/embed/' + 14461 video.id + '?autoplay=1&v=' + video.id + '" frameborder="0" allowfullscreen></iframe>'; 14462 } else if (video.type === 'vimeo') { 14463 html = '<iframe src="//player.vimeo.com/video/' + video.id + 14464 '?autoplay=1" width="' + width + '" height="' + height + 14465 '" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>'; 14466 } 14467 14468 $('<div class="owl-video-frame">' + html + '</div>').insertAfter(item.find('.owl-video')); 14469 14470 this._playing = item.addClass('owl-video-playing'); 14471 }; 14472 14473 /** 14474 * Checks whether an video is currently in full screen mode or not. 14475 * @todo Bad style because looks like a readonly method but changes members. 14476 * @protected 14477 * @returns {Boolean} 14478 */ 14479 Video.prototype.isInFullScreen = function() { 14480 var element = document.fullscreenElement || document.mozFullScreenElement || 14481 document.webkitFullscreenElement; 14482 14483 return element && $(element).parent().hasClass('owl-video-frame'); 14484 }; 14485 14486 /** 14487 * Destroys the plugin. 14488 */ 14489 Video.prototype.destroy = function() { 14490 var handler, property; 14491 14492 this._core.$element.off('click.owl.video'); 14493 14494 for (handler in this._handlers) { 14495 this._core.$element.off(handler, this._handlers[handler]); 14496 } 14497 for (property in Object.getOwnPropertyNames(this)) { 14498 typeof this[property] != 'function' && (this[property] = null); 14499 } 14500 }; 14501 14502 $.fn.owlCarousel.Constructor.Plugins.Video = Video; 14503 14504})(window.Zepto || window.jQuery, window, document); 14505 14506/** 14507 * Animate Plugin 14508 * @version 2.0.0-beta.3 14509 * @author Bartosz Wojciechowski 14510 * @license The MIT License (MIT) 14511 */ 14512;(function($, window, document, undefined) { 14513 14514 /** 14515 * Creates the animate plugin. 14516 * @class The Navigation Plugin 14517 * @param {Owl} scope - The Owl Carousel 14518 */ 14519 var Animate = function(scope) { 14520 this.core = scope; 14521 this.core.options = $.extend({}, Animate.Defaults, this.core.options); 14522 this.swapping = true; 14523 this.previous = undefined; 14524 this.next = undefined; 14525 14526 this.handlers = { 14527 'change.owl.carousel': $.proxy(function(e) { 14528 if (e.namespace && e.property.name == 'position') { 14529 this.previous = this.core.current(); 14530 this.next = e.property.value; 14531 } 14532 }, this), 14533 'drag.owl.carousel dragged.owl.carousel translated.owl.carousel': $.proxy(function(e) { 14534 if (e.namespace) { 14535 this.swapping = e.type == 'translated'; 14536 } 14537 }, this), 14538 'translate.owl.carousel': $.proxy(function(e) { 14539 if (e.namespace && this.swapping && (this.core.options.animateOut || this.core.options.animateIn)) { 14540 this.swap(); 14541 } 14542 }, this) 14543 }; 14544 14545 this.core.$element.on(this.handlers); 14546 }; 14547 14548 /** 14549 * Default options. 14550 * @public 14551 */ 14552 Animate.Defaults = { 14553 animateOut: false, 14554 animateIn: false 14555 }; 14556 14557 /** 14558 * Toggles the animation classes whenever an translations starts. 14559 * @protected 14560 * @returns {Boolean|undefined} 14561 */ 14562 Animate.prototype.swap = function() { 14563 14564 if (this.core.settings.items !== 1) { 14565 return; 14566 } 14567 14568 if (!$.support.animation || !$.support.transition) { 14569 return; 14570 } 14571 14572 this.core.speed(0); 14573 14574 var left, 14575 clear = $.proxy(this.clear, this), 14576 previous = this.core.$stage.children().eq(this.previous), 14577 next = this.core.$stage.children().eq(this.next), 14578 incoming = this.core.settings.animateIn, 14579 outgoing = this.core.settings.animateOut; 14580 14581 if (this.core.current() === this.previous) { 14582 return; 14583 } 14584 14585 if (outgoing) { 14586 left = this.core.coordinates(this.previous) - this.core.coordinates(this.next); 14587 previous.css( { 'left': left + 'px' } ) 14588 .addClass('animated owl-animated-out') 14589 .addClass(outgoing) 14590 .on($.support.animation.end, clear); 14591 } 14592 14593 if (incoming) { 14594 next.addClass('animated owl-animated-in') 14595 .addClass(incoming) 14596 .on($.support.animation.end, clear); 14597 } 14598 }; 14599 14600 Animate.prototype.clear = function(e) { 14601 if ($(e.target).hasClass('animated')) { 14602 $(e.target).css( { 'left': '' } ) 14603 .removeClass('animated owl-animated-out owl-animated-in') 14604 .removeClass(this.core.settings.animateIn) 14605 .removeClass(this.core.settings.animateOut); 14606 this.core.onTransitionEnd(); 14607 } 14608 }; 14609 14610 /** 14611 * Destroys the plugin. 14612 * @public 14613 */ 14614 Animate.prototype.destroy = function() { 14615 var handler, property; 14616 14617 for (handler in this.handlers) { 14618 this.core.$element.off(handler, this.handlers[handler]); 14619 } 14620 for (property in Object.getOwnPropertyNames(this)) { 14621 typeof this[property] != 'function' && (this[property] = null); 14622 } 14623 }; 14624 14625 $.fn.owlCarousel.Constructor.Plugins.Animate = Animate; 14626 14627})(window.Zepto || window.jQuery, window, document); 14628 14629/** 14630 * Autoplay Plugin 14631 * @version 2.0.0-beta.3 14632 * @author Bartosz Wojciechowski 14633 * @author Artus Kolanowski 14634 * @license The MIT License (MIT) 14635 */ 14636;(function($, window, document, undefined) { 14637 14638 /** 14639 * Creates the autoplay plugin. 14640 * @class The Autoplay Plugin 14641 * @param {Owl} scope - The Owl Carousel 14642 */ 14643 var Autoplay = function(carousel) { 14644 /** 14645 * Reference to the core. 14646 * @protected 14647 * @type {Owl} 14648 */ 14649 this._core = carousel; 14650 14651 /** 14652 * The autoplay interval. 14653 * @type {Number} 14654 */ 14655 this._interval = null; 14656 14657 /** 14658 * Indicates whenever the autoplay is paused. 14659 * @type {Boolean} 14660 */ 14661 this._paused = false; 14662 14663 /** 14664 * All event handlers. 14665 * @protected 14666 * @type {Object} 14667 */ 14668 this._handlers = { 14669 'changed.owl.carousel': $.proxy(function(e) { 14670 if (e.namespace && e.property.name === 'settings') { 14671 if (this._core.settings.autoplay) { 14672 this.play(); 14673 } else { 14674 this.stop(); 14675 } 14676 } 14677 }, this), 14678 'initialized.owl.carousel': $.proxy(function(e) { 14679 if (e.namespace && this._core.settings.autoplay) { 14680 this.play(); 14681 } 14682 }, this), 14683 'play.owl.autoplay': $.proxy(function(e, t, s) { 14684 if (e.namespace) { 14685 this.play(t, s); 14686 } 14687 }, this), 14688 'stop.owl.autoplay': $.proxy(function(e) { 14689 if (e.namespace) { 14690 this.stop(); 14691 } 14692 }, this), 14693 'mouseover.owl.autoplay': $.proxy(function() { 14694 if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) { 14695 this.pause(); 14696 } 14697 }, this), 14698 'mouseleave.owl.autoplay': $.proxy(function() { 14699 if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) { 14700 this.play(); 14701 } 14702 }, this) 14703 }; 14704 14705 // register event handlers 14706 this._core.$element.on(this._handlers); 14707 14708 // set default options 14709 this._core.options = $.extend({}, Autoplay.Defaults, this._core.options); 14710 }; 14711 14712 /** 14713 * Default options. 14714 * @public 14715 */ 14716 Autoplay.Defaults = { 14717 autoplay: false, 14718 autoplayTimeout: 5000, 14719 autoplayHoverPause: false, 14720 autoplaySpeed: false 14721 }; 14722 14723 /** 14724 * Starts the autoplay. 14725 * @public 14726 * @param {Number} [timeout] - The interval before the next animation starts. 14727 * @param {Number} [speed] - The animation speed for the animations. 14728 */ 14729 Autoplay.prototype.play = function(timeout, speed) { 14730 this._paused = false; 14731 14732 if (this._core.is('rotating')) { 14733 return; 14734 } 14735 14736 this._core.enter('rotating'); 14737 14738 this._interval = window.setInterval($.proxy(function() { 14739 if (this._paused || this._core.is('busy') || this._core.is('interacting') || document.hidden) { 14740 return; 14741 } 14742 this._core.next(speed || this._core.settings.autoplaySpeed); 14743 }, this), timeout || this._core.settings.autoplayTimeout); 14744 }; 14745 14746 /** 14747 * Stops the autoplay. 14748 * @public 14749 */ 14750 Autoplay.prototype.stop = function() { 14751 if (!this._core.is('rotating')) { 14752 return; 14753 } 14754 14755 window.clearInterval(this._interval); 14756 this._core.leave('rotating'); 14757 }; 14758 14759 /** 14760 * Stops the autoplay. 14761 * @public 14762 */ 14763 Autoplay.prototype.pause = function() { 14764 if (!this._core.is('rotating')) { 14765 return; 14766 } 14767 14768 this._paused = true; 14769 }; 14770 14771 /** 14772 * Destroys the plugin. 14773 */ 14774 Autoplay.prototype.destroy = function() { 14775 var handler, property; 14776 14777 this.stop(); 14778 14779 for (handler in this._handlers) { 14780 this._core.$element.off(handler, this._handlers[handler]); 14781 } 14782 for (property in Object.getOwnPropertyNames(this)) { 14783 typeof this[property] != 'function' && (this[property] = null); 14784 } 14785 }; 14786 14787 $.fn.owlCarousel.Constructor.Plugins.autoplay = Autoplay; 14788 14789})(window.Zepto || window.jQuery, window, document); 14790 14791/** 14792 * Navigation Plugin 14793 * @version 2.0.0-beta.3 14794 * @author Artus Kolanowski 14795 * @license The MIT License (MIT) 14796 */ 14797;(function($, window, document, undefined) { 14798 'use strict'; 14799 14800 /** 14801 * Creates the navigation plugin. 14802 * @class The Navigation Plugin 14803 * @param {Owl} carousel - The Owl Carousel. 14804 */ 14805 var Navigation = function(carousel) { 14806 /** 14807 * Reference to the core. 14808 * @protected 14809 * @type {Owl} 14810 */ 14811 this._core = carousel; 14812 14813 /** 14814 * Indicates whether the plugin is initialized or not. 14815 * @protected 14816 * @type {Boolean} 14817 */ 14818 this._initialized = false; 14819 14820 /** 14821 * The current paging indexes. 14822 * @protected 14823 * @type {Array} 14824 */ 14825 this._pages = []; 14826 14827 /** 14828 * All DOM elements of the user interface. 14829 * @protected 14830 * @type {Object} 14831 */ 14832 this._controls = {}; 14833 14834 /** 14835 * Markup for an indicator. 14836 * @protected 14837 * @type {Array.<String>} 14838 */ 14839 this._templates = []; 14840 14841 /** 14842 * The carousel element. 14843 * @type {jQuery} 14844 */ 14845 this.$element = this._core.$element; 14846 14847 /** 14848 * Overridden methods of the carousel. 14849 * @protected 14850 * @type {Object} 14851 */ 14852 this._overrides = { 14853 next: this._core.next, 14854 prev: this._core.prev, 14855 to: this._core.to 14856 }; 14857 14858 /** 14859 * All event handlers. 14860 * @protected 14861 * @type {Object} 14862 */ 14863 this._handlers = { 14864 'prepared.owl.carousel': $.proxy(function(e) { 14865 if (e.namespace && this._core.settings.dotsData) { 14866 this._templates.push('<div class="' + this._core.settings.dotClass + '">' + 14867 $(e.content).find('[data-dot]').andSelf('[data-dot]').attr('data-dot') + '</div>'); 14868 } 14869 }, this), 14870 'added.owl.carousel': $.proxy(function(e) { 14871 if (e.namespace && this._core.settings.dotsData) { 14872 this._templates.splice(e.position, 0, this._templates.pop()); 14873 } 14874 }, this), 14875 'remove.owl.carousel': $.proxy(function(e) { 14876 if (e.namespace && this._core.settings.dotsData) { 14877 this._templates.splice(e.position, 1); 14878 } 14879 }, this), 14880 'changed.owl.carousel': $.proxy(function(e) { 14881 if (e.namespace && e.property.name == 'position') { 14882 this.draw(); 14883 } 14884 }, this), 14885 'initialized.owl.carousel': $.proxy(function(e) { 14886 if (e.namespace && !this._initialized) { 14887 this._core.trigger('initialize', null, 'navigation'); 14888 this.initialize(); 14889 this.update(); 14890 this.draw(); 14891 this._initialized = true; 14892 this._core.trigger('initialized', null, 'navigation'); 14893 } 14894 }, this), 14895 'refreshed.owl.carousel': $.proxy(function(e) { 14896 if (e.namespace && this._initialized) { 14897 this._core.trigger('refresh', null, 'navigation'); 14898 this.update(); 14899 this.draw(); 14900 this._core.trigger('refreshed', null, 'navigation'); 14901 } 14902 }, this) 14903 }; 14904 14905 // set default options 14906 this._core.options = $.extend({}, Navigation.Defaults, this._core.options); 14907 14908 // register event handlers 14909 this.$element.on(this._handlers); 14910 }; 14911 14912 /** 14913 * Default options. 14914 * @public 14915 * @todo Rename `slideBy` to `navBy` 14916 */ 14917 Navigation.Defaults = { 14918 nav: false, 14919 navText: [ 'prev', 'next' ], 14920 navSpeed: false, 14921 navElement: 'div', 14922 navContainer: false, 14923 navContainerClass: 'owl-nav', 14924 navClass: [ 'owl-prev', 'owl-next' ], 14925 slideBy: 1, 14926 dotClass: 'owl-dot', 14927 dotsClass: 'owl-dots', 14928 dots: true, 14929 dotsEach: false, 14930 dotsData: false, 14931 dotsSpeed: false, 14932 dotsContainer: false 14933 }; 14934 14935 /** 14936 * Initializes the layout of the plugin and extends the carousel. 14937 * @protected 14938 */ 14939 Navigation.prototype.initialize = function() { 14940 var override, 14941 settings = this._core.settings; 14942 14943 // create DOM structure for relative navigation 14944 this._controls.$relative = (settings.navContainer ? $(settings.navContainer) 14945 : $('<div>').addClass(settings.navContainerClass).appendTo(this.$element)).addClass('disabled'); 14946 14947 this._controls.$previous = $('<' + settings.navElement + '>') 14948 .addClass(settings.navClass[0]) 14949 .html(settings.navText[0]) 14950 .prependTo(this._controls.$relative) 14951 .on('click', $.proxy(function(e) { 14952 this.prev(settings.navSpeed); 14953 }, this)); 14954 this._controls.$next = $('<' + settings.navElement + '>') 14955 .addClass(settings.navClass[1]) 14956 .html(settings.navText[1]) 14957 .appendTo(this._controls.$relative) 14958 .on('click', $.proxy(function(e) { 14959 this.next(settings.navSpeed); 14960 }, this)); 14961 14962 // create DOM structure for absolute navigation 14963 if (!settings.dotsData) { 14964 this._templates = [ $('<div>') 14965 .addClass(settings.dotClass) 14966 .append($('<span>')) 14967 .prop('outerHTML') ]; 14968 } 14969 14970 this._controls.$absolute = (settings.dotsContainer ? $(settings.dotsContainer) 14971 : $('<div>').addClass(settings.dotsClass).appendTo(this.$element)).addClass('disabled'); 14972 14973 this._controls.$absolute.on('click', 'div', $.proxy(function(e) { 14974 var index = $(e.target).parent().is(this._controls.$absolute) 14975 ? $(e.target).index() : $(e.target).parent().index(); 14976 14977 e.preventDefault(); 14978 14979 this.to(index, settings.dotsSpeed); 14980 }, this)); 14981 14982 // override public methods of the carousel 14983 for (override in this._overrides) { 14984 this._core[override] = $.proxy(this[override], this); 14985 } 14986 }; 14987 14988 /** 14989 * Destroys the plugin. 14990 * @protected 14991 */ 14992 Navigation.prototype.destroy = function() { 14993 var handler, control, property, override; 14994 14995 for (handler in this._handlers) { 14996 this.$element.off(handler, this._handlers[handler]); 14997 } 14998 for (control in this._controls) { 14999 this._controls[control].remove(); 15000 } 15001 for (override in this.overides) { 15002 this._core[override] = this._overrides[override]; 15003 } 15004 for (property in Object.getOwnPropertyNames(this)) { 15005 typeof this[property] != 'function' && (this[property] = null); 15006 } 15007 }; 15008 15009 /** 15010 * Updates the internal state. 15011 * @protected 15012 */ 15013 Navigation.prototype.update = function() { 15014 var i, j, k, 15015 lower = this._core.clones().length / 2, 15016 upper = lower + this._core.items().length, 15017 maximum = this._core.maximum(true), 15018 settings = this._core.settings, 15019 size = settings.center || settings.autoWidth || settings.dotsData 15020 ? 1 : settings.dotsEach || settings.items; 15021 15022 if (settings.slideBy !== 'page') { 15023 settings.slideBy = Math.min(settings.slideBy, settings.items); 15024 } 15025 15026 if (settings.dots || settings.slideBy == 'page') { 15027 this._pages = []; 15028 15029 for (i = lower, j = 0, k = 0; i < upper; i++) { 15030 if (j >= size || j === 0) { 15031 this._pages.push({ 15032 start: Math.min(maximum, i - lower), 15033 end: i - lower + size - 1 15034 }); 15035 if (Math.min(maximum, i - lower) === maximum) { 15036 break; 15037 } 15038 j = 0, ++k; 15039 } 15040 j += this._core.mergers(this._core.relative(i)); 15041 } 15042 } 15043 }; 15044 15045 /** 15046 * Draws the user interface. 15047 * @todo The option `dotsData` wont work. 15048 * @protected 15049 */ 15050 Navigation.prototype.draw = function() { 15051 var difference, 15052 settings = this._core.settings, 15053 disabled = this._core.items().length <= settings.items, 15054 index = this._core.relative(this._core.current()), 15055 loop = settings.loop || settings.rewind; 15056 15057 this._controls.$relative.toggleClass('disabled', !settings.nav || disabled); 15058 15059 if (settings.nav) { 15060 this._controls.$previous.toggleClass('disabled', !loop && index <= this._core.minimum(true)); 15061 this._controls.$next.toggleClass('disabled', !loop && index >= this._core.maximum(true)); 15062 } 15063 15064 this._controls.$absolute.toggleClass('disabled', !settings.dots || disabled); 15065 15066 if (settings.dots) { 15067 difference = this._pages.length - this._controls.$absolute.children().length; 15068 15069 if (settings.dotsData && difference !== 0) { 15070 this._controls.$absolute.html(this._templates.join('')); 15071 } else if (difference > 0) { 15072 this._controls.$absolute.append(new Array(difference + 1).join(this._templates[0])); 15073 } else if (difference < 0) { 15074 this._controls.$absolute.children().slice(difference).remove(); 15075 } 15076 15077 this._controls.$absolute.find('.active').removeClass('active'); 15078 this._controls.$absolute.children().eq($.inArray(this.current(), this._pages)).addClass('active'); 15079 } 15080 }; 15081 15082 /** 15083 * Extends event data. 15084 * @protected 15085 * @param {Event} event - The event object which gets thrown. 15086 */ 15087 Navigation.prototype.onTrigger = function(event) { 15088 var settings = this._core.settings; 15089 15090 event.page = { 15091 index: $.inArray(this.current(), this._pages), 15092 count: this._pages.length, 15093 size: settings && (settings.center || settings.autoWidth || settings.dotsData 15094 ? 1 : settings.dotsEach || settings.items) 15095 }; 15096 }; 15097 15098 /** 15099 * Gets the current page position of the carousel. 15100 * @protected 15101 * @returns {Number} 15102 */ 15103 Navigation.prototype.current = function() { 15104 var current = this._core.relative(this._core.current()); 15105 return $.grep(this._pages, $.proxy(function(page, index) { 15106 return page.start <= current && page.end >= current; 15107 }, this)).pop(); 15108 }; 15109 15110 /** 15111 * Gets the current succesor/predecessor position. 15112 * @protected 15113 * @returns {Number} 15114 */ 15115 Navigation.prototype.getPosition = function(successor) { 15116 var position, length, 15117 settings = this._core.settings; 15118 15119 if (settings.slideBy == 'page') { 15120 position = $.inArray(this.current(), this._pages); 15121 length = this._pages.length; 15122 successor ? ++position : --position;
vendor: 5,678 bytes, lines 15123-15347
15123 position = this._pages[((position % length) + length) % length].start; 15124 } else { 15125 position = this._core.relative(this._core.current()); 15126 length = this._core.items().length; 15127 successor ? position += settings.slideBy : position -= settings.slideBy; 15128 } 15129 15130 return position; 15131 }; 15132 15133 /** 15134 * Slides to the next item or page. 15135 * @public 15136 * @param {Number} [speed=false] - The time in milliseconds for the transition. 15137 */ 15138 Navigation.prototype.next = function(speed) { 15139 $.proxy(this._overrides.to, this._core)(this.getPosition(true), speed); 15140 }; 15141 15142 /** 15143 * Slides to the previous item or page. 15144 * @public 15145 * @param {Number} [speed=false] - The time in milliseconds for the transition. 15146 */ 15147 Navigation.prototype.prev = function(speed) { 15148 $.proxy(this._overrides.to, this._core)(this.getPosition(false), speed); 15149 }; 15150 15151 /** 15152 * Slides to the specified item or page. 15153 * @public 15154 * @param {Number} position - The position of the item or page. 15155 * @param {Number} [speed] - The time in milliseconds for the transition. 15156 * @param {Boolean} [standard=false] - Whether to use the standard behaviour or not. 15157 */ 15158 Navigation.prototype.to = function(position, speed, standard) { 15159 var length; 15160 15161 if (!standard) { 15162 length = this._pages.length; 15163 $.proxy(this._overrides.to, this._core)(this._pages[((position % length) + length) % length].start, speed); 15164 } else { 15165 $.proxy(this._overrides.to, this._core)(position, speed); 15166 } 15167 }; 15168 15169 $.fn.owlCarousel.Constructor.Plugins.Navigation = Navigation; 15170 15171})(window.Zepto || window.jQuery, window, document); 15172 15173/** 15174 * Hash Plugin 15175 * @version 2.0.0-beta.3 15176 * @author Artus Kolanowski 15177 * @license The MIT License (MIT) 15178 */ 15179;(function($, window, document, undefined) { 15180 'use strict'; 15181 15182 /** 15183 * Creates the hash plugin. 15184 * @class The Hash Plugin 15185 * @param {Owl} carousel - The Owl Carousel 15186 */ 15187 var Hash = function(carousel) { 15188 /** 15189 * Reference to the core. 15190 * @protected 15191 * @type {Owl} 15192 */ 15193 this._core = carousel; 15194 15195 /** 15196 * Hash index for the items. 15197 * @protected 15198 * @type {Object} 15199 */ 15200 this._hashes = {}; 15201 15202 /** 15203 * The carousel element. 15204 * @type {jQuery} 15205 */ 15206 this.$element = this._core.$element; 15207 15208 /** 15209 * All event handlers. 15210 * @protected 15211 * @type {Object} 15212 */ 15213 this._handlers = { 15214 /*'initialized.owl.carousel': $.proxy(function(e) { 15215 if (e.namespace && this._core.settings.startPosition === 'URLHash') { 15216 $(window).trigger('hashchange.owl.navigation'); 15217 } 15218 }, this),*/ 15219 'prepared.owl.carousel': $.proxy(function(e) { 15220 if (e.namespace) { 15221 var hash = $(e.content).find('[data-hash]').addBack('[data-hash]').attr('data-hash'); 15222 15223 if (!hash) { 15224 return; 15225 } 15226 15227 this._hashes[hash] = e.content; 15228 } 15229 }, this), 15230 'changed.owl.carousel': $.proxy(function(e) { 15231 if (e.namespace && e.property.name === 'position') { 15232 var current = this._core.items(this._core.relative(this._core.current())), 15233 hash = $.map(this._hashes, function(item, hash) { 15234 return item === current ? hash : null; 15235 }).join(); 15236 15237 if (!hash || window.location.hash.slice(1) === hash) { 15238 return; 15239 } 15240 15241 window.location.hash = hash; 15242 } 15243 }, this) 15244 }; 15245 15246 // set default options 15247 this._core.options = $.extend({}, Hash.Defaults, this._core.options); 15248 15249 // register the event handlers 15250 this.$element.on(this._handlers); 15251 15252 // register event listener for hash navigation 15253 /*$(window).on('hashchange.owl.navigation', $.proxy(function(e) { 15254 var hash = window.location.hash.substring(1), 15255 items = this._core.$stage.children(), 15256 position = this._hashes[hash] && items.index(this._hashes[hash]); 15257 15258 if (position === undefined || position === this._core.current()) { 15259 return; 15260 } 15261 15262 this._core.to(this._core.relative(position), false, true); 15263 }, this));*/ 15264 }; 15265 15266 /** 15267 * Default options. 15268 * @public 15269 */ 15270 Hash.Defaults = { 15271 URLhashListener: false 15272 }; 15273 15274 /** 15275 * Destroys the plugin. 15276 * @public 15277 */ 15278 Hash.prototype.destroy = function() { 15279 var handler, property; 15280 15281 $(window).off('hashchange.owl.navigation'); 15282 15283 for (handler in this._handlers) { 15284 this._core.$element.off(handler, this._handlers[handler]); 15285 } 15286 for (property in Object.getOwnPropertyNames(this)) { 15287 typeof this[property] != 'function' && (this[property] = null); 15288 } 15289 }; 15290 15291 $.fn.owlCarousel.Constructor.Plugins.Hash = Hash; 15292 15293})(window.Zepto || window.jQuery, window, document); 15294 15295/** 15296 * Support Plugin 15297 * 15298 * @version 2.0.0-beta.3 15299 * @author Vivid Planet Software GmbH 15300 * @author Artus Kolanowski 15301 * @license The MIT License (MIT) 15302 */ 15303;(function($, window, document, undefined) { 15304 15305 var style = $('<support>').get(0).style, 15306 prefixes = 'Webkit Moz O ms'.split(' '), 15307 events = { 15308 transition: { 15309 end: { 15310 WebkitTransition: 'webkitTransitionEnd', 15311 MozTransition: 'transitionend', 15312 OTransition: 'oTransitionEnd', 15313 transition: 'transitionend' 15314 } 15315 }, 15316 animation: { 15317 end: { 15318 WebkitAnimation: 'webkitAnimationEnd', 15319 MozAnimation: 'animationend', 15320 OAnimation: 'oAnimationEnd', 15321 animation: 'animationend' 15322 } 15323 } 15324 }, 15325 tests = { 15326 csstransforms: function() { 15327 return !!test('transform'); 15328 }, 15329 csstransforms3d: function() { 15330 return !!test('perspective'); 15331 }, 15332 csstransitions: function() { 15333 return !!test('transition'); 15334 }, 15335 cssanimations: function() { 15336 return !!test('animation'); 15337 } 15338 }; 15339 15340 function test(property, prefixed) { 15341 var result = false, 15342 upper = property.charAt(0).toUpperCase() + property.slice(1); 15343 15344 $.each((property + ' ' + prefixes.join(upper + ' ') + upper).split(' '), function(i, property) { 15345 if (style[property] !== undefined) { 15346 result = prefixed ? property : true; 15347 return false;
15348 } 15349 }); 15350 15351 return result; 15352 } 15353 15354 function prefixed(property) { 15355 return test(property, true); 15356 } 15357 15358 if (tests.csstransitions()) { 15359 /* jshint -W053 */ 15360 $.support.transition = new String(prefixed('transition')) 15361 $.support.transition.end = events.transition.end[ $.support.transition ]; 15362 } 15363 15364 if (tests.cssanimations()) { 15365 /* jshint -W053 */ 15366 $.support.animation = new String(prefixed('animation')) 15367 $.support.animation.end = events.animation.end[ $.support.animation ]; 15368 } 15369 15370 if (tests.csstransforms()) { 15371 /* jshint -W053 */ 15372 $.support.transform = new String(prefixed('transform')); 15373 $.support.transform3d = tests.csstransforms3d(); 15374 } 15375 15376})(window.Zepto || window.jQuery, window, document); 15377 15378(function(window, document, undefined) { 15379 15380 /** 15381 * Find the absolute position of an element 15382 */ 15383 var absPos = function(element) { 15384 var offsetLeft, offsetTop; 15385 offsetLeft = offsetTop = 0; 15386 if (element.offsetParent) { 15387 do { 15388 offsetLeft += element.offsetLeft; 15389 offsetTop += element.offsetTop; 15390 } while (element = element.offsetParent); 15391 } 15392 return [offsetLeft, offsetTop]; 15393 }; 15394 15395 /** 15396 * @constructor Progress Circle class 15397 * @param params.canvas Canvas on which the circles will be drawn. 15398 * @param params.minRadius Inner radius of the innermost circle, in px. 15399 * @param params.arcWidth Width of each circle(to be more accurate, ring). 15400 * @param params.gapWidth Space between each circle. 15401 * @param params.centerX X coordinate of the center of circles. 15402 * @param params.centerY Y coordinate of the center of circles. 15403 * @param params.infoLineBaseAngle Base angle of the info line. 15404 * @param params.infoLineAngleInterval Angles between the info lines. 15405 */ 15406 var ProgressCircle = function(params) { 15407 this.canvas = params.canvas; 15408 this.minRadius = params.minRadius || 15; 15409 this.arcWidth = params.arcWidth || 5; 15410 this.gapWidth = params.gapWidth || 3; 15411 this.centerX = params.centerX || this.canvas.width / 2; 15412 this.centerY = params.centerY || this.canvas.height / 2;
15413 this.infoLineLength = params.infoLineLength || 60; 15414 this.horizLineLength = params.horizLineLength || 10; 15415 this.infoLineAngleInterval = params.infoLineAngleInterval || Math.PI / 8; 15416 this.infoLineBaseAngle = params.infoLineBaseAngle || Math.PI / 6; 15417 15418 this.context = this.canvas.getContext('2d'); 15419 15420 this.width = this.canvas.width; 15421 this.height = this.canvas.height; 15422 15423 this.circles = []; 15424 this.runningCount = 0; 15425 }; 15426 15427 ProgressCircle.prototype = { 15428 constructor: ProgressCircle, 15429 15430 /** 15431 * @method Adds an progress monitor entry. 15432 * @param params.fillColor Color to fill in the circle. 15433 * @param params.outlineColor Color to outline the circle. 15434 * @param params.progressListener Callback function to fetch the progress. 15435 * @param params.infoListener Callback function to fetch the info. 15436 * @returns this 15437 */ 15438 addEntry: function(params) { 15439 this.circles.push(new Circle({ 15440 canvas: this.canvas, 15441 context: this.context, 15442 centerX: this.centerX, 15443 centerY: this.centerY, 15444 innerRadius: this.minRadius + this.circles.length * 15445 (this.gapWidth + this.arcWidth), 15446 arcWidth: this.arcWidth,
15447 infoLineLength: this.infoLineLength, 15448 horizLineLength: this.horizLineLength, 15449 15450 id: this.circles.length, 15451 fillColor: params.fillColor, 15452 outlineColor: params.outlineColor, 15453 progressListener: params.progressListener, 15454 infoListener: params.infoListener, 15455 infoLineAngle: this.infoLineBaseAngle + 15456 this.circles.length * this.infoLineAngleInterval, 15457 })); 15458 15459 return this; 15460 }, 15461 15462 /** 15463 * @method Starts the monitor and updates with the given interval. 15464 * @param interval Interval between updates, in millisecond. 15465 * @returns this 15466 */ 15467 start: function(interval) { 15468 var self = this; 15469 this.timer = setInterval(function() { 15470 self._update(); 15471 }, interval || 33); 15472 15473 return this; 15474 }, 15475 15476 /** 15477 * @method Stop the animation. 15478 */ 15479 stop: function() { 15480 clearTimeout(this.timer); 15481 }, 15482 15483 /** 15484 * @private 15485 * @method Call update on each circle and redraw them. 15486 * @returns this 15487 */ 15488 _update: function() { 15489 this._clear(); 15490 this.circles.forEach(function(circle, idx, array) { 15491 circle.update(); 15492 }); 15493 15494 return this; 15495 }, 15496 15497 /** 15498 * @private 15499 * @method Clear the canvas. 15500 * @returns this 15501 */ 15502 _clear: function() { 15503 this.context.clearRect(0, 0, this.canvas.width, this.canvas.height); 15504 15505 return this; 15506 }, 15507 15508 }; 15509 15510 /** 15511 * @private 15512 * @class Individual progress circle. 15513 * @param params.canvas Canvas on which the circle will be drawn. 15514 * @param params.context Context of the canvas. 15515 * @param params.innerRadius Inner radius of the circle, in px. 15516 * @param params.arcWidth Width of each arc(circle). 15517 * @param params.gapWidth Distance between each arc. 15518 * @param params.centerX X coordinate of the center of circles. 15519 * @param params.centerY Y coordinate of the center of circles. 15520 * @param params.fillColor Color to fill in the circle. 15521 * @param params.outlineColor Color to outline the circle. 15522 * @param params.progressListener Callback function to fetch the progress. 15523 * @param params.infoListener Callback function to fetch the info. 15524 * @param params.infoLineAngle Angle of info line. 15525 */ 15526 var Circle = function(params) { 15527 this.id = params.id; 15528 this.canvas = params.canvas; 15529 this.context = params.context; 15530 this.centerX = params.centerX; 15531 this.centerY = params.centerY; 15532 this.arcWidth = params.arcWidth; 15533 this.innerRadius = params.innerRadius || 0; 15534 this.fillColor = params.fillColor || '#fff'; 15535 this.outlineColor = params.outlineColor || this.fillColor; 15536 this.progressListener = params.progressListener;
15537 this.infoLineLength = params.infoLineLength || 250; 15538 this.horizLineLength = params.horizLineLength || 50; 15539 this.infoListener = params.infoListener; 15540 this.infoLineAngle = params.infoLineAngle; 15541 15542 this.outerRadius = this.innerRadius + this.arcWidth; 15543 15544 // If the info listener is not registered, then don't calculate 15545 // the related coordinates 15546 if (!this.infoListener) return; 15547 15548 // calculate the info-line turning points 15549 var angle = this.infoLineAngle, 15550 arcDistance = (this.innerRadius + this.outerRadius) / 2, 15551 15552 sinA = Math.sin(angle), 15553 cosA = Math.cos(angle); 15554 15555 this.infoLineStartX = this.centerX + sinA * arcDistance; 15556 this.infoLineStartY = this.centerY - cosA * arcDistance; 15557 15558 this.infoLineMidX = this.centerX + sinA * this.infoLineLength; 15559 this.infoLineMidY = this.centerY - cosA * this.infoLineLength; 15560 15561 this.infoLineEndX = this.infoLineMidX + 15562 (sinA < 0 ? -this.horizLineLength : this.horizLineLength); 15563 this.infoLineEndY = this.infoLineMidY; 15564 15565 var infoText = document.createElement('div'), 15566 style = infoText.style; 15567 15568 style.color = this.fillColor; 15569 style.position = 'absolute'; 15570 style.left = this.infoLineEndX + absPos(this.canvas)[0] + 'px'; 15571 // style.top will be calculated in the `drawInfo` method. Since 15572 // user may want to change the size of the font, so the top offset 15573 // must be updated in each loop. 15574 infoText.className = 'ProgressCircleInfo'; // For css styling 15575 infoText.id = 'progress_circle_info_' + this.id; 15576 document.body.appendChild(infoText); 15577 this.infoText = infoText; 15578 }; 15579 15580 Circle.prototype = { 15581 constructor: Circle, 15582 15583 update: function() { 15584 this.progress = this.progressListener(); 15585 this._draw(); 15586 15587 if (this.infoListener) { 15588 this.info = this.infoListener(); 15589 this._drawInfo(); 15590 } 15591 }, 15592 15593 /** 15594 * @private 15595 * @method Draw the circle on the canvas. 15596 * @returns this 15597 */ 15598 _draw: function() { 15599 var ctx = this.context, 15600 15601 ANGLE_OFFSET = -Math.PI / 2, 15602 15603 startAngle = 0 + ANGLE_OFFSET, 15604 endAngle= startAngle + this.progress * Math.PI * 2, 15605 15606 x = this.centerX, 15607 y = this.centerY, 15608 15609 innerRadius = this.innerRadius - this.arcWidth - 1, 15610 outerRadius = this.outerRadius - this.arcWidth - 1; 15611 15612 if ( innerRadius < 0 ) 15613 return; 15614 15615 ctx.fillStyle = this.fillColor; 15616 ctx.strokeStyle = this.outlineColor; 15617 15618 ctx.beginPath(); 15619 ctx.arc(x, y, innerRadius, startAngle, endAngle, false); 15620 ctx.arc(x, y, outerRadius, endAngle, startAngle, true); 15621 ctx.closePath(); 15622 ctx.stroke(); 15623 ctx.fill(); 15624 15625 return this; 15626 }, 15627 15628 /** 15629 * @private 15630 * @method Draw the info lines and info text. 15631 * @returns this 15632 */ 15633 _drawInfo: function() { 15634 15635 var pointList, lineHeight; 15636 15637 pointList = [ 15638 [this.infoLineStartX, this.infoLineStartY], 15639 [this.infoLineMidX, this.infoLineMidY], 15640 [this.infoLineEndX, this.infoLineEndY], 15641 ]; 15642 this._drawSegments(pointList, false); 15643 15644 this.infoText.innerHTML = this.info; 15645 15646 lineHeight = this.infoText.offsetHeight; 15647 this.infoText.style.top = this.infoLineEndY + 15648 absPos(this.canvas)[1] - lineHeight / 2 + 'px'; 15649 15650 return this; 15651 }, 15652 15653 /** 15654 * @private 15655 * @method Helper function to draw the segments 15656 * @param pointList An array of points in the form of [x, y]. 15657 * @param close Whether to connect the first and last point. 15658 */ 15659 _drawSegments: function(pointList, close) { 15660 var ctx = this.context; 15661 15662 ctx.beginPath(); 15663 ctx.moveTo(pointList[0][0], pointList[0][1]); 15664 for (var i = 1; i < pointList.length; ++i) { 15665 ctx.lineTo(pointList[i][0], pointList[i][1]); 15666 } 15667 15668 if (close) { 15669 ctx.closePath(); 15670 } 15671 ctx.stroke(); 15672 }, 15673 }; 15674 15675 window.ProgressCircle = ProgressCircle; 15676 15677})(window, document); 15678 15679 15680 15681 15682/* ========================================================= 15683 * jquery.vc_chart.js v1.0 15684 * ========================================================= 15685 * Copyright 2013 Wpbakery 15686 * 15687 * Jquery chart plugin for the Visual Composer.
15688 * ========================================================= */ 15689(function($){ 15690 /** 15691 * Pie chart animated. 15692 * @param element - DOM element 15693 * @param options - settings object. 15694 * @constructor 15695 */ 15696 var VcChart = function(element, options) { 15697 this.el = element; 15698 this.$el = $(this.el); 15699 var $this = this; 15700 $this.options = $.extend({ 15701 color: 'wpb_button', 15702 units: '', 15703 width: '', 15704 label_selector: '.vc_pie_chart_value', 15705 back_selector: '.vc_pie_chart_back', 15706 responsive: true 15707 }, options); 15708 $this.init(); 15709 }; 15710 VcChart.prototype = { 15711 constructor: VcChart, 15712 _progress_v: 0, 15713 animated: false, 15714 colors: { 15715 'wpb_button': 'rgba(247, 247, 247, 1)', 15716 'btn-primary': 'rgba(0, 136, 204, 1)', 15717 'btn-info': 'rgba(88, 185, 218, 1)', 15718 'btn-success': 'rgba(106, 177, 101, 1)', 15719 'btn-warning': 'rgba(255, 153, 0, 1)', 15720 'btn-danger': 'rgba(255, 103, 91, 1)', 15721 'btn-inverse': 'rgba(85, 85, 85, 1)' 15722 }, 15723 init: function() { 15724 this.setupColor(); 15725 this.value = this.$el.data('pie-value')/100; 15726 this.label_value = this.$el.data('pie-label-value') || this.$el.data('pie-value'); 15727 this.$wrapper = $('.vc_pie_wrapper', this.$el); 15728 this.$label = $(this.options.label_selector, this.$el); 15729 this.$back = $(this.options.back_selector, this.$el); 15730 this.$canvas = this.$el.find('canvas'); 15731 this.arcWidth = this.$el.data('pie-width') * 2; 15732 this.draw(); 15733 this.setWayPoint(); 15734 if(this.options.responsive === true) this.setResponsive(); 15735 if (UNCODE.isMobile) this._progress_v = this.value; 15736 }, 15737 setupColor: function() { 15738 // if(typeof this.colors[this.options.color] !== 'undefined') { 15739 // this.color = this.colors[this.options.color]; 15740 // } else if(typeof this.options.color === 'string' && this.options.color.match(/^rgba?\([^\)]+\)/)) { 15741 // this.color = this.options.color; 15742 // } else { 15743 // this.color = 'rgba(247, 247, 247, 0.2)'; 15744 // } 15745 if(typeof this.options.color !== 'undefined') { 15746 this.color = this.options.color; 15747 } else this.color = 'rgba(247, 247, 247, 0.2)'; 15748 15749 }, 15750 setResponsive: function() { 15751 var that = this; 15752 if (!UNCODE.isMobile) { 15753 $(window).resize(function(){ 15754 if(that.animated === true) that.circle.stop(); 15755 that.draw(true); 15756 }); 15757 } 15758 }, 15759 draw: function(redraw) { 15760 var w = this.$el.addClass('vc_ready').width() * 2, 15761 border_w = this.arcWidth, 15762 radius; 15763 if(!w) w = this.$el.parents(':visible').first().width()-2; 15764 //w = Math.round(w/100*80); 15765 //if (w < 250) w = 250; 15766 radius = w/2; 15767 this.$wrapper.css({"width" : (w / 2) + "px"}); 15768 this.$label.css({"width" : (w / 2), "height" : (w / 2), "line-height" : (w / 2)+"px"}); 15769 this.$back.css({"width" : (w / 2), "height" : (w / 2)}); 15770 this.$canvas.attr({"width" : w + "px", "height" : w + "px"}); 15771 this.$el.addClass('vc_ready'); 15772 this.circle = new ProgressCircle({ 15773 canvas: this.$canvas.get(0), 15774 minRadius: radius, 15775 arcWidth: border_w 15776 }); 15777 if(redraw === true && this.animated === true) { 15778 this._progress_v = this.value; 15779 this.circle.addEntry({ 15780 fillColor: this.color, 15781 progressListener: $.proxy(this.setProgress, this) 15782 }).start(); 15783 } 15784 }, 15785 setProgress: function() { 15786 if (this._progress_v >= this.value) { 15787 this.circle.stop(); 15788 this.animated = true; 15789 this.$label.html(this.label_value + this.options.units); 15790 return this._progress_v; 15791 } 15792 this._progress_v += 0.01; 15793 if (!isNaN(this.label_value)) { 15794 var label_value = this._progress_v/this.value*this.label_value; 15795 var val = Math.round(label_value) + this.options.units; 15796 this.$label.html(val); 15797 } else this.$label.html(this.label_value + this.options.units); 15798 return this._progress_v; 15799 }, 15800 animate: function() { 15801 if(this.animated !== true) { 15802 this.circle.addEntry({ 15803 fillColor: this.color, 15804 progressListener: $.proxy(this.setProgress, this) 15805 }).start(10); 15806 } 15807 }, 15808 setWayPoint: function() { 15809 if (typeof $.fn.waypoint !== 'undefined' && !UNCODE.isMobile) { 15810 this.$el.waypoint($.proxy(this.animate, this), { offset: '85%' }); 15811 } else { 15812 this.animate(); 15813 } 15814 } 15815 }; 15816 /** 15817 * jQuery plugin 15818 * @param option - object with settings 15819 * @return {*} 15820 */ 15821 $.fn.vcChat = function(option, value) { 15822 return this.each(function () { 15823 var $this = $(this), 15824 data = $this.data('vc_chart'), 15825 options = typeof option === 'object' ? option : { 15826 color: $this.data('pie-color'), 15827 units: $this.data('pie-units') 15828 }; 15829 if (typeof option == 'undefined') $this.data('vc_chart', (data = new VcChart(this, options))); 15830 if (typeof option == 'string') data[option](value); 15831 }); 15832 }; 15833 /** 15834 * Allows users to rewrite function inside theme. 15835 */ 15836 if ( typeof window['vc_pieChart'] !== 'function' ) { 15837 window.vc_pieChart = function() { 15838 $('.vc_pie_chart:visible:not(.vc_ready)').vcChat(); 15839 } 15840 } 15841 $(document).ready(function(){ 15842 !window.vc_iframe && vc_pieChart(); 15843 }); 15844 15845})(window.jQuery); 15846 15847/* Progress bar 15848 ---------------------------------------------------------- */ 15849function uncode_progress_bar() {    15850 jQuery.each(jQuery('.vc_progress_bar'), function(index, val) { 15851 if (!UNCODE.isMobile) { 15852 new Waypoint({ 15853 element: val, 15854 handler: function() { 15855 var element = jQuery(this.element); 15856 element.find('.vc_single_bar').each(function(index) {          15857 var $this = jQuery(this), 15858             bar = $this.find('.vc_bar'), 15859             val = bar.data('percentage-value');          15860 setTimeout(function() {            15861 bar.css({ 15862 "width": val + '%' 15863 });          15864 }, index * 200);        15865 }); 15866 }, 15867 offset: '80%' 15868 }); 15869 } else { 15870 var element = jQuery(val); 15871 element.find('.vc_single_bar').each(function(index) {          15872 var $this = jQuery(this), 15873             bar = $this.find('.vc_bar'), 15874             val = bar.data('percentage-value');          15875 setTimeout(function() {            15876 bar.css({ 15877 "width": val + '%' 15878 });          15879 }, index * 200);        15880 }); 15881 } 15882 }); 15883}; 15884uncode_progress_bar(); 15885/*! 15886 * jquery.counterup.js 1.0 15887 * 15888 * Copyright 2013, Benjamin Intal http://gambit.ph @bfintal 15889 * Released under the GPL v2 License 15890 * 15891 * Date: Nov 26, 2013 15892 */ 15893(function($) { 15894 "use strict"; 15895 $.fn.counterUp = function(options) { 15896 // Defaults 15897 var settings = $.extend({ 15898 'time': 400, 15899 'delay': 10 15900 }, options); 15901 return this.each(function() { 15902 // Store the object 15903 var $this = $(this); 15904 var $settings = settings; 15905 var counterUpper = function() { 15906 var nums = []; 15907 var divisions = $settings.time / $settings.delay; 15908 var numReal = $this.attr('data-val'), 15909 num = numReal; 15910 var isComma = /[0-9]+,[0-9]+/.test(num); 15911 num = num.replace(/,/g, ''); 15912 var isInt = /^[0-9]+$/.test(num); 15913 var isFloat = /^[0-9]+\.[0-9]+$/.test(num); 15914 var decimalPlaces = isFloat ? (num.split('.')[1] || []).length : 0; 15915 // Generate list of incremental numbers to display 15916 for (var i = divisions; i >= 1; i--) { 15917 // Preserve as int if input was int 15918 var newNum = parseInt(num / divisions * i); 15919 // Preserve float if input was float 15920 if (isFloat) { 15921 newNum = parseFloat(num / divisions * i).toFixed(decimalPlaces); 15922 } 15923 // Preserve commas if input had commas 15924 if (isComma) { 15925 while (/(\d+)(\d{3})/.test(newNum.toString())) { 15926 newNum = newNum.toString().replace(/(\d+)(\d{3})/, '$1' + ',' + '$2'); 15927 } 15928 } 15929 nums.unshift(newNum); 15930 } 15931 nums.push(numReal); 15932 $this.data('counterup-nums', nums); 15933 $this.text('0'); 15934 // Updates the number until we're done 15935 var f = function() { 15936 if ($this.data('counterup-nums') != null) { 15937 $this.text($this.data('counterup-nums').shift()); 15938 if ($this.data('counterup-nums').length) { 15939 setTimeout($this.data('counterup-func'), $settings.delay); 15940 } else { 15941 delete $this.data('counterup-nums'); 15942 $this.data('counterup-nums', null); 15943 $this.data('counterup-func', null); 15944 } 15945 } 15946 }; 15947 $this.data('counterup-func', f); 15948 // Start the count up 15949 setTimeout($this.data('counterup-func'), $settings.delay); 15950 }; 15951 // Perform counts when the element gets into view 15952 new Waypoint({ 15953 element: this, 15954 handler: function() { 15955 counterUpper(); 15956 this.destroy(); 15957 }, 15958 offset: '100%' 15959 }); 15960 }); 15961 }; 15962})(jQuery); 15963 15964/*! 15965 * The Final Countdown for jQuery v2.0.4 (http://hilios.github.io/jQuery.countdown/) 15966 * Copyright (c) 2014 Edson Hilios 15967 * 15968 * Permission is hereby granted, free of charge, to any person obtaining a copy of 15969 * this software and associated documentation files (the "Software"), to deal in 15970 * the Software without restriction, including without limitation the rights to 15971 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 15972 * the Software, and to permit persons to whom the Software is furnished to do so, 15973 * subject to the following conditions: 15974 * 15975 * The above copyright notice and this permission notice shall be included in all 15976 * copies or substantial portions of the Software. 15977 * 15978 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15979 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 15980 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15981 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 15982 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 15983 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15984 */ 15985(function(factory) { 15986 "use strict"; 15987 if (typeof define === "function" && define.amd) { 15988 define([ "jquery" ], factory); 15989 } else { 15990 factory(jQuery); 15991 } 15992})(function($) { 15993 "use strict"; 15994 var PRECISION = 100; 15995 var instances = [], matchers = []; 15996 matchers.push(/^[0-9]*$/.source); 15997 matchers.push(/([0-9]{1,2}\/){2}[0-9]{4}( [0-9]{1,2}(:[0-9]{2}){2})?/.source); 15998 matchers.push(/[0-9]{4}([\/\-][0-9]{1,2}){2}( [0-9]{1,2}(:[0-9]{2}){2})?/.source); 15999 matchers = new RegExp(matchers.join("|")); 16000 function parseDateString(dateString) { 16001 if (dateString instanceof Date) { 16002 return dateString; 16003 } 16004 if (String(dateString).match(matchers)) { 16005 if (String(dateString).match(/^[0-9]*$/)) { 16006 dateString = Number(dateString); 16007 } 16008 if (String(dateString).match(/\-/)) { 16009 dateString = String(dateString).replace(/\-/g, "/"); 16010 } 16011 return new Date(dateString); 16012 } else { 16013 throw new Error("Couldn't cast `" + dateString + "` to a date object."); 16014 } 16015 } 16016 var DIRECTIVE_KEY_MAP = { 16017 Y: "years", 16018 m: "months", 16019 w: "weeks", 16020 d: "days", 16021 D: "totalDays", 16022 H: "hours", 16023 M: "minutes", 16024 S: "seconds" 16025 }; 16026 function strftime(offsetObject) { 16027 return function(format) { 16028 var directives = format.match(/%(-|!)?[A-Z]{1}(:[^;]+;)?/gi); 16029 if (directives) { 16030 for (var i = 0, len = directives.length; i < len; ++i) { 16031 var directive = directives[i].match(/%(-|!)?([a-zA-Z]{1})(:[^;]+;)?/), regexp = new RegExp(directive[0]), modifier = directive[1] || "", plural = directive[3] || "", value = null; 16032 directive = directive[2]; 16033 if (DIRECTIVE_KEY_MAP.hasOwnProperty(directive)) { 16034 value = DIRECTIVE_KEY_MAP[directive]; 16035 value = Number(offsetObject[value]); 16036 } 16037 if (value !== null) { 16038 if (modifier === "!") { 16039 value = pluralize(plural, value); 16040 } 16041 if (modifier === "") { 16042 if (value < 10) { 16043 value = "0" + value.toString(); 16044 } 16045 } 16046 format = format.replace(regexp, value.toString()); 16047 } 16048 } 16049 } 16050 format = format.replace(/%%/, "%"); 16051 return format; 16052 }; 16053 } 16054 function pluralize(format, count) { 16055 var plural = "s", singular = ""; 16056 if (format) { 16057 format = format.replace(/(:|;|\s)/gi, "").split(/\,/); 16058 if (format.length === 1) { 16059 plural = format[0]; 16060 } else { 16061 singular = format[0]; 16062 plural = format[1]; 16063 } 16064 } 16065 if (Math.abs(count) === 1) { 16066 return singular; 16067 } else { 16068 return plural; 16069 } 16070 } 16071 var Countdown = function(el, finalDate, callback) { 16072 this.el = el; 16073 this.$el = $(el); 16074 this.interval = null; 16075 this.offset = {}; 16076 this.instanceNumber = instances.length; 16077 instances.push(this); 16078 this.$el.data("countdown-instance", this.instanceNumber); 16079 if (callback) { 16080 this.$el.on("update.countdown", callback);
16081 this.$el.on("stoped.countdown", callback); 16082 this.$el.on("finish.countdown", callback); 16083 } 16084 this.setFinalDate(finalDate); 16085 this.start(); 16086 }; 16087 $.extend(Countdown.prototype, { 16088 start: function() { 16089 if (this.interval !== null) { 16090 clearInterval(this.interval); 16091 } 16092 var self = this; 16093 this.update(); 16094 this.interval = setInterval(function() { 16095 self.update.call(self); 16096 }, PRECISION); 16097 }, 16098 stop: function() { 16099 clearInterval(this.interval); 16100 this.interval = null; 16101 this.dispatchEvent("stoped"); 16102 }, 16103 pause: function() { 16104 this.stop.call(this); 16105 }, 16106 resume: function() { 16107 this.start.call(this); 16108 }, 16109 remove: function() { 16110 this.stop(); 16111 instances[this.instanceNumber] = null; 16112 delete this.$el.data().countdownInstance; 16113 }, 16114 setFinalDate: function(value) { 16115 this.finalDate = parseDateString(value); 16116 }, 16117 update: function() { 16118 if (this.$el.closest("html").length === 0) { 16119 this.remove(); 16120 return; 16121 } 16122 this.totalSecsLeft = this.finalDate.getTime() - new Date().getTime(); 16123 this.totalSecsLeft = Math.ceil(this.totalSecsLeft / 1e3); 16124 this.totalSecsLeft = this.totalSecsLeft < 0 ? 0 : this.totalSecsLeft; 16125 this.offset = { 16126 seconds: this.totalSecsLeft % 60, 16127 minutes: Math.floor(this.totalSecsLeft / 60) % 60, 16128 hours: Math.floor(this.totalSecsLeft / 60 / 60) % 24, 16129 days: Math.floor(this.totalSecsLeft / 60 / 60 / 24) % 7, 16130 totalDays: Math.floor(this.totalSecsLeft / 60 / 60 / 24), 16131 weeks: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 7), 16132 months: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 30), 16133 years: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 365) 16134 }; 16135 if (this.totalSecsLeft === 0) { 16136 this.stop(); 16137 this.dispatchEvent("finish"); 16138 } else { 16139 this.dispatchEvent("update"); 16140 } 16141 }, 16142 dispatchEvent: function(eventName) { 16143 var event = $.Event(eventName + ".countdown"); 16144 event.finalDate = this.finalDate; 16145 event.offset = $.extend({}, this.offset); 16146 event.strftime = strftime(this.offset); 16147 this.$el.trigger(event); 16148 } 16149 }); 16150 $.fn.countdown = function() { 16151 var argumentsArray = Array.prototype.slice.call(arguments, 0); 16152 return this.each(function() { 16153 var instanceNumber = $(this).data("countdown-instance"); 16154 if (instanceNumber !== undefined) { 16155 var instance = instances[instanceNumber], method = argumentsArray[0]; 16156 if (Countdown.prototype.hasOwnProperty(method)) { 16157 instance[method].apply(instance, argumentsArray.slice(1)); 16158 } else if (String(method).match(/^[$A-Z_][0-9A-Z_$]*$/i) === null) { 16159 instance.setFinalDate.call(instance, method); 16160 instance.start(); 16161 } else { 16162 $.error("Method %s does not exist on jQuery.countdown".replace(/\%s/gi, method)); 16163 } 16164 } else { 16165 new Countdown(this, argumentsArray[0], argumentsArray[1]); 16166 } 16167 }); 16168 }; 16169}); 16170 16171/*! waitForImages jQuery Plugin - v2.0.2 - 2015-05-05 16172* https://github.com/alexanderdickson/waitForImages 16173* Copyright (c) 2015 Alex Dickson; Licensed MIT */ 16174;(function (factory) { 16175 if (typeof define === 'function' && define.amd) { 16176 // AMD. Register as an anonymous module. 16177 define(['jquery'], factory); 16178 } else if (typeof exports === 'object') { 16179 // CommonJS / nodejs module 16180 module.exports = factory(require('jquery')); 16181 } else { 16182 // Browser globals 16183 factory(jQuery); 16184 } 16185}(function ($) { 16186 // Namespace all events. 16187 var eventNamespace = 'waitForImages'; 16188 16189 // CSS properties which contain references to images. 16190 $.waitForImages = { 16191 hasImageProperties: [ 16192 'backgroundImage', 16193 'listStyleImage', 16194 'borderImage', 16195 'borderCornerImage', 16196 'cursor' 16197 ], 16198 hasImageAttributes: ['srcset'] 16199 }; 16200 16201 // Custom selector to find `img` elements that have a valid `src` 16202 // attribute and have not already loaded. 16203 $.expr[':'].uncached = function (obj) { 16204 // Ensure we are dealing with an `img` element with a valid 16205 // `src` attribute. 16206 if (!$(obj).is('img[src][src!=""]')) { 16207 return false;
16208 } 16209 16210 return !obj.complete; 16211 }; 16212 16213 $.fn.waitForImages = function () { 16214 16215 var allImgsLength = 0; 16216 var allImgsLoaded = 0; 16217 var deferred = $.Deferred(); 16218 16219 var finishedCallback; 16220 var eachCallback; 16221 var waitForAll; 16222 16223 // Handle options object (if passed). 16224 if ($.isPlainObject(arguments[0])) { 16225 16226 waitForAll = arguments[0].waitForAll; 16227 eachCallback = arguments[0].each; 16228 finishedCallback = arguments[0].finished; 16229 16230 } else { 16231 16232 // Handle if using deferred object and only one param was passed in. 16233 if (arguments.length === 1 && $.type(arguments[0]) === 'boolean') { 16234 waitForAll = arguments[0]; 16235 } else { 16236 finishedCallback = arguments[0]; 16237 eachCallback = arguments[1]; 16238 waitForAll = arguments[2]; 16239 } 16240 16241 } 16242 16243 // Handle missing callbacks. 16244 finishedCallback = finishedCallback || $.noop; 16245 eachCallback = eachCallback || $.noop; 16246 16247 // Convert waitForAll to Boolean 16248 waitForAll = !! waitForAll; 16249 16250 // Ensure callbacks are functions. 16251 if (!$.isFunction(finishedCallback) || !$.isFunction(eachCallback)) { 16252 throw new TypeError('An invalid callback was supplied.'); 16253 } 16254 16255 this.each(function () { 16256 // Build a list of all imgs, dependent on what images will 16257 // be considered. 16258 var obj = $(this); 16259 var allImgs = []; 16260 // CSS properties which may contain an image. 16261 var hasImgProperties = $.waitForImages.hasImageProperties || []; 16262 // Element attributes which may contain an image. 16263 var hasImageAttributes = $.waitForImages.hasImageAttributes || []; 16264 // To match `url()` references. 16265 // Spec: http://www.w3.org/TR/CSS2/syndata.html#value-def-uri 16266 var matchUrl = /url\(\s*(['"]?)(.*?)\1\s*\)/g; 16267 16268 if (waitForAll) { 16269 16270 // Get all elements (including the original), as any one of 16271 // them could have a background image. 16272 obj.find('*').addBack().each(function () { 16273 var element = $(this); 16274 16275 // If an `img` element, add it. But keep iterating in 16276 // case it has a background image too. 16277 if (element.is('img:uncached')) { 16278 allImgs.push({ 16279 src: element.attr('src'), 16280 element: element[0] 16281 }); 16282 } 16283 16284 $.each(hasImgProperties, function (i, property) { 16285 var propertyValue = element.css(property); 16286 var match; 16287 16288 // If it doesn't contain this property, skip. 16289 if (!propertyValue) { 16290 return true; 16291 } 16292 16293 // Get all url() of this element. 16294 while (match = matchUrl.exec(propertyValue)) { 16295 allImgs.push({ 16296 src: match[2], 16297 element: element[0] 16298 }); 16299 } 16300 }); 16301 16302 $.each(hasImageAttributes, function (i, attribute) { 16303 var attributeValue = element.attr(attribute); 16304 var attributeValues; 16305 16306 // If it doesn't contain this property, skip. 16307 if (!attributeValue) { 16308 return true; 16309 } 16310 16311 // Check for multiple comma separated images 16312 attributeValues = attributeValue.split(','); 16313 16314 $.each(attributeValues, function(i, value) { 16315 // Trim value and get string before first 16316 // whitespace (for use with srcset). 16317 value = $.trim(value).split(' ')[0]; 16318 allImgs.push({ 16319 src: value, 16320 element: element[0] 16321 }); 16322 }); 16323 }); 16324 }); 16325 } else { 16326 // For images only, the task is simpler. 16327 obj.find('img:uncached') 16328 .each(function () { 16329 allImgs.push({ 16330 src: this.src, 16331 element: this 16332 }); 16333 }); 16334 } 16335 16336 allImgsLength = allImgs.length; 16337 allImgsLoaded = 0; 16338 16339 // If no images found, don't bother. 16340 if (allImgsLength === 0) { 16341 finishedCallback.call(obj[0]); 16342 deferred.resolveWith(obj[0]); 16343 } 16344 16345 $.each(allImgs, function (i, img) { 16346 16347 var image = new Image(); 16348 var events = 16349 'load.' + eventNamespace + ' error.' + eventNamespace; 16350 16351 // Handle the image loading and error with the same callback. 16352 $(image).one(events, function me (event) { 16353 // If an error occurred with loading the image, set the 16354 // third argument accordingly. 16355 var eachArguments = [ 16356 allImgsLoaded, 16357 allImgsLength,
16358 event.type == 'load' 16359 ]; 16360 allImgsLoaded++; 16361 16362 eachCallback.apply(img.element, eachArguments); 16363 deferred.notifyWith(img.element, eachArguments); 16364 16365 // Unbind the event listeners. I use this in addition to 16366 // `one` as one of those events won't be called (either 16367 // 'load' or 'error' will be called). 16368 $(this).off(events, me); 16369 16370 if (allImgsLoaded == allImgsLength) { 16371 finishedCallback.call(obj[0]); 16372 deferred.resolveWith(obj[0]); 16373 return false; 16374 } 16375 16376 }); 16377 16378 image.src = img.src; 16379 }); 16380 }); 16381 16382 return deferred.promise(); 16383 16384 }; 16385})); 16386 16387/** 16388 * @preserve textfill 16389 * @name jquery.textfill.js 16390 * @author Russ Painter 16391 * @author Yu-Jie Lin 16392 * @author Alexandre Dantas 16393 * @version 0.6.0 16394 * @date 2014-08-19 16395 * @copyright (c) 2014 Alexandre Dantas 16396 * @copyright (c) 2012-2013 Yu-Jie Lin 16397 * @copyright (c) 2009 Russ Painter 16398 * @license MIT License 16399 * @homepage https://github.com/jquery-textfill/jquery-textfill 16400 * @example http://jquery-textfill.github.io/jquery-textfill/index.html 16401 */ 16402; (function($) { 16403 16404 /** 16405 * Resizes an inner element's font so that the 16406 * inner element completely fills the outer element. 16407 * 16408 * @param {Object} options User options that take 16409 * higher precedence when 16410 * merging with the default ones. 16411 * 16412 * @return All outer elements processed 16413 */ 16414 $.fn.textfill = function(options) { 16415 16416 // ______ _______ _______ _______ _ _ _______ _______ 16417 // | \ |______ |______ |_____| | | | | |______ 16418 // |_____/ |______ | | | |_____| |_____ | ______| 16419 // 16420 // Merging user options with the default values 16421 16422 var defaults = { 16423 debug : false, 16424 maxFontPixels : 40, 16425 minFontPixels : 4, 16426 innerTag : 'span', 16427 widthOnly : false, 16428 success : null, // callback when a resizing is done 16429 callback : null, // callback when a resizing is done (deprecated, use success) 16430 fail : null, // callback when a resizing is failed 16431 complete : null, // callback when all is done 16432 explicitWidth : null, 16433 explicitHeight : null, 16434 changeLineHeight : false 16435 }; 16436 16437 var Opts = $.extend(defaults, options); 16438 16439 // _______ _ _ __ _ _______ _______ _____ _____ __ _ _______ 16440 // |______ | | | \ | | | | | | | \ | |______ 16441 // | |_____| | \_| |_____ | __|__ |_____| | \_| ______| 16442 // 16443 // Predefining the awesomeness 16444 16445 // Output arguments to the Debug console 16446 // if "Debug Mode" is enabled 16447 function _debug() { 16448 if (!Opts.debug 16449 || typeof console == 'undefined' 16450 || typeof console.debug == 'undefined') { 16451 return; 16452 } 16453 console.debug.apply(console, arguments); 16454 } 16455 16456 // Output arguments to the Warning console 16457 function _warn() { 16458 if (typeof console == 'undefined' || 16459 typeof console.warn == 'undefined') { 16460 return; 16461 } 16462 console.warn.apply(console, arguments); 16463 } 16464 16465 // Outputs all information on the current sizing 16466 // of the font. 16467 function _debug_sizing(prefix, ourText, maxHeight, maxWidth, minFontPixels, maxFontPixels) { 16468 16469 function _m(v1, v2) { 16470 16471 var marker = ' / '; 16472 16473 if (v1 > v2) 16474 marker = ' > '; 16475 16476 else if (v1 == v2) 16477 marker = ' = '; 16478 16479 return marker; 16480 } 16481 16482 _debug( 16483 '[TextFill] ' + prefix + ' { ' + 16484 'font-size: ' + ourText.css('font-size') + ',' +
16485 'Height: ' + ourText.height() + 'px ' + _m(ourText.height(), maxHeight) + maxHeight + 'px,' + 16486 'Width: ' + ourText.width() + _m(ourText.width() , maxWidth) + maxWidth + ',' + 16487 'minFontPixels: ' + minFontPixels + 'px, ' + 16488 'maxFontPixels: ' + maxFontPixels + 'px }' 16489 ); 16490 } 16491 16492 /** 16493 * Calculates which size the font can get resized, 16494 * according to constrains. 16495 * 16496 * @param {String} prefix Gets shown on the console before 16497 * all the arguments, if debug mode is on. 16498 * @param {Object} ourText The DOM element to resize, 16499 * that contains the text. 16500 * @param {function} func Function called on `ourText` that's 16501 * used to compare with `max`. 16502 * @param {number} max Maximum value, that gets compared with 16503 * `func` called on `ourText`. 16504 * @param {number} minFontPixels Minimum value the font can 16505 * get resized to (in pixels). 16506 * @param {number} maxFontPixels Maximum value the font can 16507 * get resized to (in pixels). 16508 * 16509 * @return Size (in pixels) that the font can be resized. 16510 */ 16511 function _sizing(prefix, ourText, func, max, maxHeight, maxWidth, minFontPixels, maxFontPixels) { 16512 16513 _debug_sizing( 16514 prefix, ourText, 16515 maxHeight, maxWidth, 16516 minFontPixels, maxFontPixels 16517 ); 16518 16519 // The kernel of the whole plugin, take most attention 16520 // on this part. 16521 // 16522 // This is a loop that keeps increasing the `font-size` 16523 // until it fits the parent element. 16524 // 16525 // - Start from the minimal allowed value (`minFontPixels`) 16526 // - Guesses an average font size (in pixels) for the font, 16527 // - Resizes the text and sees if its size is within the 16528 // boundaries (`minFontPixels` and `maxFontPixels`). 16529 // - If so, keep guessing until we break. 16530 // - If not, return the last calculated size. 16531 // 16532 // I understand this is not optimized and we should 16533 // consider implementing something akin to 16534 // Daniel Hoffmann's answer here: 16535 // 16536 // http://stackoverflow.com/a/17433451/1094964 16537 // 16538 16539 while (minFontPixels < (maxFontPixels - 1)) { 16540 16541 var fontSize = Math.floor((minFontPixels + maxFontPixels) / 2); 16542 ourText.css('font-size', fontSize); 16543 16544 if (func.call(ourText) <= max) { 16545 minFontPixels = fontSize; 16546 16547 if (func.call(ourText) == max) 16548 break; 16549 } 16550 else 16551 maxFontPixels = fontSize; 16552 16553 _debug_sizing( 16554 prefix, ourText, 16555 maxHeight, maxWidth, 16556 minFontPixels, maxFontPixels 16557 ); 16558 } 16559 16560 ourText.css('font-size', maxFontPixels); 16561 16562 if (func.call(ourText) <= max) { 16563 minFontPixels = maxFontPixels; 16564 16565 _debug_sizing( 16566 prefix + '* ', ourText, 16567 maxHeight, maxWidth, 16568 minFontPixels, maxFontPixels 16569 ); 16570 } 16571 return minFontPixels; 16572 } 16573 16574 // _______ _______ _______ ______ _______ 16575 // |______ | |_____| |_____/ | 16576 // ______| | | | | \_ | 16577 // 16578 // Let's get it started (yeah)! 16579 16580 _debug('[TextFill] Start Debug'); 16581 16582 this.each(function() { 16583 16584 // Contains the child element we will resize. 16585 // $(this) means the parent container 16586 var ourText = $(Opts.innerTag + ':visible:first', this); 16587 16588 // Will resize to this dimensions. 16589 // Use explicit dimensions when specified 16590 var maxHeight = Opts.explicitHeight || $(this).height(); 16591 var maxWidth = Opts.explicitWidth || $(this).width(); 16592 16593 var oldFontSize = ourText.css('font-size'); 16594 16595 var lineHeight = parseFloat(ourText.css('line-height')) / parseFloat(oldFontSize); 16596 16597 _debug('[TextFill] Inner text: ' + ourText.text()); 16598 _debug('[TextFill] All options: ', Opts); 16599 _debug('[TextFill] Maximum sizes: { ' + 16600 'Height: ' + maxHeight + 'px, ' + 16601 'Width: ' + maxWidth + 'px' + ' }' 16602 ); 16603 16604 var minFontPixels = Opts.minFontPixels; 16605 16606 // Remember, if this `maxFontPixels` is negative, 16607 // the text will resize to as long as the container 16608 // can accomodate 16609 var maxFontPixels = (Opts.maxFontPixels <= 0 ? 16610 maxHeight : 16611 Opts.maxFontPixels); 16612 16613 16614 // Let's start it all! 16615 16616 // 1. Calculate which `font-size` would 16617 // be best for the Height 16618 var fontSizeHeight = undefined; 16619 16620 if (! Opts.widthOnly) 16621 fontSizeHeight = _sizing( 16622 'Height', ourText, 16623 $.fn.height, maxHeight, 16624 maxHeight, maxWidth, 16625 minFontPixels, maxFontPixels 16626 ); 16627 16628 // 2. Calculate which `font-size` would 16629 // be best for the Width 16630 var fontSizeWidth = undefined; 16631 16632 fontSizeWidth = _sizing( 16633 'Width', ourText, 16634 $.fn.width, maxWidth, 16635 maxHeight, maxWidth, 16636 minFontPixels, maxFontPixels 16637 ); 16638 16639 // 3. Actually resize the text! 16640 16641 if (Opts.widthOnly) { 16642 ourText.css({ 16643 'font-size' : fontSizeWidth, 16644 'white-space': 'nowrap' 16645 }); 16646 16647 if (Opts.changeLineHeight) 16648 ourText.parent().css( 16649 'line-height', 16650 (lineHeight * fontSizeWidth + 'px') 16651 ); 16652 } 16653 else { 16654 var fontSizeFinal = Math.min(fontSizeHeight, fontSizeWidth); 16655 16656 ourText.css('font-size', fontSizeFinal); 16657 16658 if (Opts.changeLineHeight) 16659 ourText.parent().css( 16660 'line-height', 16661 (lineHeight * fontSizeFinal) + 'px' 16662 ); 16663 } 16664 16665 _debug( 16666 '[TextFill] Finished { ' + 16667 'Old font-size: ' + oldFontSize + ', ' + 16668 'New font-size: ' + ourText.css('font-size') + ' }' 16669 ); 16670 16671 // Oops, something wrong happened! 16672 // We weren't supposed to exceed the original size 16673 if ((ourText.width() > maxWidth) ||
16674 (ourText.height() > maxHeight && !Opts.widthOnly)) { 16675 16676 ourText.css('font-size', oldFontSize); 16677 16678 // Failure callback 16679 if (Opts.fail) 16680 Opts.fail(this); 16681 16682 _debug( 16683 '[TextFill] Failure { ' + 16684 'Current Width: ' + ourText.width() + ', ' + 16685 'Maximum Width: ' + maxWidth + ', ' + 16686 'Current Height: ' + ourText.height() + ', ' + 16687 'Maximum Height: ' + maxHeight + ' }' 16688 ); 16689 } 16690 else if (Opts.success) { 16691 Opts.success(this); 16692 } 16693 else if (Opts.callback) { 16694 _warn('callback is deprecated, use success, instead'); 16695 16696 // Success callback 16697 Opts.callback(this); 16698 } 16699 }); 16700 16701 // Complete callback 16702 if (Opts.complete) 16703 Opts.complete(this); 16704 16705 _debug('[TextFill] End Debug'); 16706 return this; 16707 }; 16708 16709})(window.jQuery); 16710 16711!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; 16712function getStyles(config){ 16713 // 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;
16713left: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+"}" 16714}; 16715 var ShareUtils; 16716 16717if ((!("classList" in document.documentElement)) && Object.defineProperty && typeof HTMLElement !== "undefined") { 16718 Object.defineProperty(HTMLElement.prototype, "classList", { 16719 get: function() { 16720 var ret, self, update; 16721 update = function(fn) { 16722 return function(value) { 16723 var classes, index; 16724 classes = self.className.split(/\s+/); 16725 index = classes.indexOf(value); 16726 fn(classes, index, value); 16727 self.className = classes.join(" "); 16728 }; 16729 }; 16730 self = this; 16731 ret = { 16732 add: update(function(classes, index, value) { 16733 ~index || classes.push(value); 16734 }), 16735 remove: update(function(classes, index) { 16736 ~index && classes.splice(index, 1); 16737 }), 16738 toggle: update(function(classes, index, value) { 16739 if (~index) { 16740 classes.splice(index, 1); 16741 } else { 16742 classes.push(value); 16743 } 16744 }), 16745 contains: function(value) { 16746 return !!~self.className.split(/\s+/).indexOf(value); 16747 }, 16748 item: function(i) { 16749 return self.className.split(/\s+/)[i] || null; 16750 } 16751 }; 16752 Object.defineProperty(ret, "length", { 16753 get: function() { 16754 return self.className.split(/\s+/).length; 16755 } 16756 }); 16757 return ret; 16758 } 16759 }); 16760} 16761 16762String.prototype.to_rfc3986 = function() { 16763 var tmp; 16764 tmp = encodeURIComponent(this); 16765 return tmp.replace(/[!'()*]/g, function(c) { 16766 return "%" + c.charCodeAt(0).toString(16); 16767 }); 16768}; 16769 16770ShareUtils = (function() { 16771 function ShareUtils() {} 16772 16773 ShareUtils.prototype.extend = function(to, from, overwrite) { 16774 var hasProp, prop; 16775 for (prop in from) { 16776 hasProp = to[prop] !== undefined; 16777 if (hasProp && typeof from[prop] === "object") { 16778 this.extend(to[prop], from[prop], overwrite); 16779 } else { 16780 if (overwrite || !hasProp) { 16781 to[prop] = from[prop]; 16782 } 16783 } 16784 } 16785 }; 16786 16787 ShareUtils.prototype.hide = function(el) { 16788 return el.style.display = "none"; 16789 }; 16790 16791 ShareUtils.prototype.show = function(el) { 16792 return el.style.display = "block"; 16793 }; 16794 16795 ShareUtils.prototype.has_class = function(el, class_name) { 16796 return el.classList.contains(class_name); 16797 }; 16798 16799 ShareUtils.prototype.add_class = function(el, class_name) { 16800 return el.classList.add(class_name); 16801 }; 16802 16803 ShareUtils.prototype.remove_class = function(el, class_name) { 16804 return el.classList.remove(class_name); 16805 }; 16806 16807 ShareUtils.prototype.is_encoded = function(str) { 16808 str = str.to_rfc3986(); 16809 return decodeURIComponent(str) !== str; 16810 }; 16811 16812 ShareUtils.prototype.encode = function(str) { 16813 if (typeof str === "undefined" || this.is_encoded(str)) { 16814 return str; 16815 } else { 16816 return str.to_rfc3986(); 16817 } 16818 }; 16819 16820 ShareUtils.prototype.popup = function(url, params) { 16821 var k, popup, qs, v; 16822 if (params == null) { 16823 params = {}; 16824 } 16825 popup = { 16826 width: 500, 16827 height: 350 16828 }; 16829 popup.top = (screen.height / 2) - (popup.height / 2); 16830 popup.left = (screen.width / 2) - (popup.width / 2); 16831 qs = ((function() { 16832 var _results; 16833 _results = []; 16834 for (k in params) { 16835 v = params[k]; 16836 _results.push("" + k + "=" + (this.encode(v))); 16837 } 16838 return _results; 16839 }).call(this)).join('&'); 16840 if (qs) { 16841 qs = "?" + qs; 16842 } 16843 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="
16843+ popup.width + ",height=" + popup.height); 16844 }; 16845 16846 return ShareUtils; 16847 16848})(); 16849var Share, 16850 __hasProp = {}.hasOwnProperty, 16851 __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; }; 16852 16853Share = (function(_super) { 16854 __extends(Share, _super); 16855 16856 function Share(element, options) { 16857 this.element = element; 16858 this.el = { 16859 head: document.getElementsByTagName('head')[0], 16860 body: document.getElementsByTagName('body')[0] 16861 }; 16862 this.config = { 16863 enabled_networks: 0, 16864 protocol: ['http', 'https'].indexOf(window.location.href.split(':')[0]) === -1 ? 'https://' : '//', 16865 url: window.location.href.replace("&", "%26"), 16866 caption: null, 16867 title: this.default_title(), 16868 image: this.default_image(), 16869 description: this.default_description(), 16870 ui: { 16871 flyout: 'top center', 16872 button_text: 'Share', 16873 button_font: true, 16874 icon_font: true 16875 }, 16876 networks: { 16877 google_plus: { 16878 enabled: true, 16879 url: null 16880 }, 16881 twitter: { 16882 enabled: true, 16883 url: null, 16884 title: null, 16885 description: null 16886 }, 16887 facebook: { 16888 enabled: true, 16889 load_sdk: true, 16890 url: null, 16891 app_id: null, 16892 title: null, 16893 caption: null, 16894 description: null, 16895 image: null 16896 }, 16897 pinterest: { 16898 enabled: true, 16899 url: null, 16900 image: null, 16901 description: null 16902 }, 16903 reddit: { 16904 enabled: true, 16905 url: null, 16906 title: null 16907 }, 16908 linkedin: { 16909 enabled: true, 16910 url: null, 16911 title: null, 16912 description: null 16913 }, 16914 xing: { 16915 enabled: true, 16916 url: null, 16917 title: null, 16918 image: null, 16919 description: null 16920 }, 16921 whatsapp: { 16922 enabled: true, 16923 description: null, 16924 url: null 16925 }, 16926 email: { 16927 enabled: true, 16928 title: null, 16929 description: null, 16930 url: null 16931 } 16932 } 16933 }; 16934 this.setup(element, options); 16935 return this; 16936 } 16937 16938 Share.prototype.setup = function(element, opts) { 16939 var index, instance, instances, _i, _len; 16940 instances = document.querySelectorAll(element); 16941 this.extend(this.config, opts, true); 16942 this.set_global_configuration(); 16943 this.normalize_network_configuration(); 16944 if (this.config.ui.icon_font) { 16945 this.inject_icons(); 16946 } 16947 if (this.config.ui.button_font) { 16948 this.inject_fonts(); 16949 } 16950 if (this.config.networks.facebook.enabled && this.config.networks.facebook.load_sdk) { 16951 this.inject_facebook_sdk(); 16952 } 16953 for (index = _i = 0, _len = instances.length; _i < _len; index = ++_i) { 16954 instance = instances[index]; 16955 this.setup_instance(element, index); 16956 } 16957 }; 16958 16959 Share.prototype.setup_instance = function(element, index) { 16960 var button, instance, label, network, networks, _i, _len, _results, 16961 _this = this; 16962 instance = document.querySelectorAll(element)[index]; 16963 this.hide(instance); 16964 this.add_class(instance, "sharer-" + index); 16965 instance = document.querySelectorAll(element)[index]; 16966 this.inject_css(instance); 16967 this.inject_html(instance); 16968 this.show(instance); 16969 label = instance.getElementsByTagName("label")[0]; 16970 button = instance.getElementsByClassName("social")[0]; 16971 networks = instance.getElementsByTagName('li'); 16972 this.add_class(button, "networks-" + this.config.enabled_networks); 16973 label.addEventListener("click", function() { 16974 return _this.event_toggle(button); 16975 }); 16976 _this = this; 16977 _results = []; 16978 for (index = _i = 0, _len = networks.length; _i < _len; index = ++_i) { 16979 network = networks[index]; 16980 _results.push(network.addEventListener("click", function() { 16981 _this.event_network(instance, this); 16982 return _this.event_close(button); 16983 })); 16984 } 16985 return _results; 16986 }; 16987 16988 Share.prototype.event_toggle = function(button) { 16989 if (this.has_class(button, "active")) { 16990 return this.event_close(button); 16991 } else { 16992 return this.event_open(button); 16993 } 16994 }; 16995 16996 Share.prototype.event_open = function(button) { 16997 if (this.has_class(button, "load")) { 16998 this.remove_class(button, "load"); 16999 } 17000 return this.add_class(button, "active"); 17001 }; 17002 17003 Share.prototype.event_close = function(button) { 17004 return this.remove_class(button, "active"); 17005 }; 17006 17007 Share.prototype.event_network = function(instance, network) { 17008 var name; 17009 name = network.getAttribute("data-network"); 17010 this.hook("before", name, instance);
17011 this["network_" + name](); 17012 return this.hook("after", name, instance); 17013 }; 17014 17015 Share.prototype.open = function() { 17016 return this["public"]("open"); 17017 }; 17018 17019 Share.prototype.close = function() { 17020 return this["public"]("close"); 17021 }; 17022 17023 Share.prototype.toggle = function() { 17024 return this["public"]("toggle"); 17025 }; 17026 17027 Share.prototype["public"] = function(action) { 17028 var button, index, instance, _i, _len, _ref, _results; 17029 _ref = document.querySelectorAll(this.element); 17030 _results = []; 17031 for (index = _i = 0, _len = _ref.length; _i < _len; index = ++_i) { 17032 instance = _ref[index]; 17033 button = instance.getElementsByClassName("social")[0]; 17034 _results.push(this["event_" + action](button)); 17035 } 17036 return _results; 17037 }; 17038 17039 Share.prototype.network_facebook = function() { 17040 if (this.config.networks.facebook.load_sdk) { 17041 if (!window.FB) { 17042 return console.error("The Facebook JS SDK hasn't loaded yet."); 17043 } 17044 return FB.ui({ 17045 method: 'feed', 17046 name: this.config.networks.facebook.title, 17047 link: this.config.networks.facebook.url, 17048 picture: this.config.networks.facebook.image, 17049 caption: this.config.networks.facebook.caption, 17050 description: this.config.networks.facebook.description 17051 }); 17052 } else { 17053 return this.popup('https://www.facebook.com/sharer/sharer.php', { 17054 u: this.config.networks.facebook.url 17055 }); 17056 } 17057 }; 17058 17059 Share.prototype.network_twitter = function() { 17060 return this.popup('https://twitter.com/intent/tweet', { 17061 text: this.config.networks.twitter.title, 17062 url: this.config.networks.twitter.url 17063 }); 17064 }; 17065 17066 Share.prototype.network_google_plus = function() { 17067 return this.popup('https://plus.google.com/share', { 17068 url: this.config.networks.google_plus.url 17069 }); 17070 }; 17071 17072 Share.prototype.network_pinterest = function() { 17073 return this.popup('https://www.pinterest.com/pin/create/button', { 17074 url: this.config.networks.pinterest.url, 17075 media: this.config.networks.pinterest.image, 17076 description: this.config.networks.pinterest.description 17077 }); 17078 }; 17079 17080 Share.prototype.network_linkedin = function() { 17081 return this.popup('https://www.linkedin.com/shareArticle', { 17082 url: this.config.networks.linkedin.url, 17083 title: this.config.networks.linkedin.title, 17084 summary: this.config.networks.linkedin.description 17085 }); 17086 } 17087 17088 Share.prototype.network_xing = function() { 17089 return this.popup('https://www.xing.com/spi/shares/new', { 17090 url: this.config.networks.xing.url, 17091 image: this.config.networks.xing.image, 17092 title: this.config.networks.xing.title, 17093 summary: this.config.networks.xing.description 17094 }); 17095 } 17096 17097 Share.prototype.network_email = function() { 17098 return this.popup('mailto:', { 17099 subject: this.config.networks.email.title, 17100 body: this.config.networks.email.url + '%0A%0A' + this.config.networks.email.description, 17101 }); 17102 }; 17103 17104 Share.prototype.inject_icons = function() { 17105 // return this.inject_stylesheet("https://www.sharebutton.co/fonts/v2/entypo.min.css"); 17106 }; 17107 17108 Share.prototype.inject_fonts = function() { 17109 // return this.inject_stylesheet("http://fonts.googleapis.com/css?family=Lato:900&text=" + this.config.ui.button_text); 17110 }; 17111 17112 Share.prototype.inject_stylesheet = function(url) { 17113 var link; 17114 if (!this.el.head.querySelector("link[href=\"" + url + "\"]")) { 17115 link = document.createElement("link"); 17116 link.setAttribute("rel", "stylesheet"); 17117 link.setAttribute("href", url); 17118 return this.el.head.appendChild(link); 17119 } 17120 }; 17121 17122 Share.prototype.inject_css = function(instance) { 17123 var css, meta, selector, style; 17124 selector = "." + (instance.getAttribute('class').split(" ").join(".")); 17125 if (!this.el.head.querySelector("meta[name='sharer" + selector + "']")) { 17126 this.config.selector = selector; 17127 css = getStyles(this.config); 17128 style = document.createElement("style"); 17129 style.type = "text/css"; 17130 if (style.styleSheet) { 17131 style.styleSheet.cssText = css; 17132 } else { 17133 style.appendChild(document.createTextNode(css)); 17134 } 17135 this.el.head.appendChild(style); 17136 delete this.config.selector; 17137 meta = document.createElement("meta"); 17138 meta.setAttribute("name", "sharer" + selector); 17139 return this.el.head.appendChild(meta); 17140 } 17141 }; 17142 17143 Share.prototype.inject_html = function(instance) { 17144 //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>"; 17145 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>"; 17146 }; 17147 17148 Share.prototype.inject_facebook_sdk = function() { 17149 var fb_root, script; 17150 if (!window.FB && this.config.networks.facebook.app_id && !this.el.body.querySelector('#fb-root')) { 17151 script = document.createElement("script"); 17152 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')"; 17153 fb_root = document.createElement("div"); 17154 fb_root.id = "fb-root"; 17155 this.el.body.appendChild(fb_root); 17156 return this.el.body.appendChild(script); 17157 } 17158 }; 17159 17160 Share.prototype.hook = function(type, network, instance) { 17161 var fn, opts; 17162 fn = this.config.networks[network][type]; 17163 if (typeof fn === "function") { 17164 opts = fn.call(this.config.networks[network], instance); 17165 if (opts !== void 0) { 17166 opts = this.normalize_filter_config_updates(opts); 17167 this.extend(this.config.networks[network], opts, true); 17168 this.normalize_network_configuration(); 17169 } 17170 } 17171 }; 17172 17173 Share.prototype.default_title = function() { 17174 var content; 17175 if (content = document.querySelector('meta[property="og:title"]') || document.querySelector('meta[name="twitter:title"]')) { 17176 return encodeURIComponent(content.getAttribute('content')); 17177 } else if (content = document.querySelector('title')) { 17178 return encodeURIComponent(content.innerText); 17179 } 17180 }; 17181 17182 Share.prototype.default_image = function() { 17183 var content; 17184 if (content = document.querySelector('meta[property="og:image"]') || document.querySelector('meta[name="twitter:image"]')) { 17185 return content.getAttribute('content'); 17186 } 17187 }; 17188 17189 Share.prototype.default_description = function() { 17190 var content; 17191 if (content = document.querySelector('meta[property="og:description"]') || document.querySelector('meta[name="twitter:description"]') || document.querySelector('meta[name="description"]')) { 17192 return encodeURIComponent(content.getAttribute('content')); 17193 } else { 17194 return ''; 17195 } 17196 }; 17197 17198 Share.prototype.set_global_configuration = function() { 17199 var display, network, option, options, _ref, _results; 17200 _ref = this.config.networks; 17201 _results = []; 17202 for (network in _ref) { 17203 options = _ref[network]; 17204 for (option in options) { 17205 if (this.config.networks[network][option] == null) { 17206 this.config.networks[network][option] = this.config[option]; 17207 } 17208 } 17209 if (this.config.networks[network].enabled) { 17210 display = 'block'; 17211 this.config.enabled_networks += 1; 17212 } else { 17213 display = 'none'; 17214 } 17215 _results.push(this.config.networks[network].display = display); 17216 } 17217 return _results; 17218 }; 17219 17220 Share.prototype.normalize_network_configuration = function() { 17221 if (!this.config.networks.facebook.app_id) { 17222 this.config.networks.facebook.load_sdk = false;
17223 } 17224 if (!this.is_encoded(this.config.networks.twitter.description)) { 17225 this.config.networks.twitter.description = encodeURIComponent(this.config.networks.twitter.description); 17226 } 17227 if (typeof this.config.networks.facebook.app_id === 'number') { 17228 return this.config.networks.facebook.app_id = this.config.networks.facebook.app_id.toString(); 17229 } 17230 }; 17231 17232 Share.prototype.normalize_filter_config_updates = function(opts) { 17233 if (this.config.networks.facebook.app_id !== opts.app_id) { 17234 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."); 17235 delete opts.app_id; 17236 } 17237 if (this.config.networks.facebook.load_sdk !== opts.load_sdk) { 17238 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."); 17239 delete opts.app_id; 17240 } 17241 return opts; 17242 }; 17243 17244 return Share; 17245 17246})(ShareUtils); 17247 return Share; 17248}); 17249 17250// Generated by CoffeeScript 1.9.2 17251 17252// @license Sticky-kit v1.1.2 | WTFPL | Leaf Corcoran 2015 | http://leafo.net 17253 17254(function() { 17255 var $, win; 17256 17257 $ = this.jQuery || window.jQuery; 17258 17259 win = $(window); 17260 17261 $.fn.stick_in_parent = function(opts) { 17262 var doc, elm, enable_bottoming, fn, i, inner_scrolling, len, manual_spacer, offset_top, outer_width, parent_selector, recalc_every, sticky_class; 17263 if (opts == null) { 17264 opts = {}; 17265 } 17266 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; 17267 if (offset_top == null) { 17268 offset_top = 0; 17269 } 17270 if (parent_selector == null) { 17271 parent_selector = void 0; 17272 } 17273 if (inner_scrolling == null) { 17274 inner_scrolling = true; 17275 } 17276 if (sticky_class == null) { 17277 sticky_class = "is_stuck"; 17278 } 17279 doc = $(document); 17280 if (enable_bottoming == null) { 17281 enable_bottoming = true; 17282 } 17283 outer_width = function(el) { 17284 var _el, computed, w; 17285 if (window.getComputedStyle) { 17286 _el = el[0]; 17287 computed = window.getComputedStyle(el[0]); 17288 w = parseFloat(computed.getPropertyValue("width")) + parseFloat(computed.getPropertyValue("margin-left")) + parseFloat(computed.getPropertyValue("margin-right")); 17289 if (computed.getPropertyValue("box-sizing") !== "border-box") { 17290 w += parseFloat(computed.getPropertyValue("border-left-width")) + parseFloat(computed.getPropertyValue("border-right-width")) + parseFloat(computed.getPropertyValue("padding-left")) + parseFloat(computed.getPropertyValue("padding-right")); 17291 } 17292 return w; 17293 } else { 17294 return el.outerWidth(true); 17295 } 17296 }; 17297 fn = function(elm, padding_bottom, parent_top, parent_height, top, height, el_float, detached) { 17298 var bottomed, detach, fixed, last_pos, last_scroll_height, offset, parent, recalc, recalc_and_tick, recalc_counter, spacer, tick; 17299 if (elm.data("sticky_kit")) { 17300 return; 17301 } 17302 elm.data("sticky_kit", true); 17303 last_scroll_height = doc.height(); 17304 parent = elm.parent(); 17305 if (parent_selector != null) { 17306 parent = parent.closest(parent_selector); 17307 } 17308 if (!parent.length) { 17309 throw "failed to find stick parent"; 17310 } 17311 fixed = false; 17312 bottomed = false; 17313 spacer = manual_spacer != null ? manual_spacer && elm.closest(manual_spacer) : $("<div />"); 17314 if (spacer) { 17315 spacer.css('position', elm.css('position')); 17316 } 17317 recalc = function() { 17318 var border_top, padding_top, restore; 17319 if (detached) { 17320 return; 17321 } 17322 last_scroll_height = doc.height(); 17323 border_top = parseInt(parent.css("border-top-width"), 10); 17324 padding_top = parseInt(parent.css("padding-top"), 10); 17325 padding_bottom = parseInt(parent.css("padding-bottom"), 10); 17326 parent_top = parent.offset().top + border_top + padding_top; 17327 parent_height = parent.height(); 17328 if (fixed) { 17329 fixed = false;
vendor: 6,068 bytes, lines 17330-17524
17330 bottomed = false; 17331 if (manual_spacer == null) { 17332 elm.insertAfter(spacer); 17333 spacer.detach(); 17334 } 17335 elm.css({ 17336 position: "", 17337 top: "", 17338 width: "", 17339 bottom: "" 17340 }).removeClass(sticky_class); 17341 restore = true; 17342 } 17343 top = elm.offset().top - (parseInt(elm.css("margin-top"), 10) || 0) - offset_top; 17344 height = elm.outerHeight(true); 17345 el_float = elm.css("float"); 17346 if (spacer) { 17347 spacer.css({ 17348 width: outer_width(elm), 17349 height: height, 17350 display: elm.css("display"), 17351 "vertical-align": elm.css("vertical-align"), 17352 "float": el_float 17353 }); 17354 } 17355 if (restore) { 17356 return tick(); 17357 } 17358 }; 17359 recalc(); 17360 if (height === parent_height) { 17361 return; 17362 } 17363 last_pos = void 0; 17364 offset = offset_top; 17365 recalc_counter = recalc_every; 17366 tick = function() { 17367 var css, delta, recalced, scroll, will_bottom, win_height; 17368 if (detached) { 17369 return; 17370 } 17371 recalced = false; 17372 if (recalc_counter != null) { 17373 recalc_counter -= 1; 17374 if (recalc_counter <= 0) { 17375 recalc_counter = recalc_every; 17376 recalc(); 17377 recalced = true; 17378 } 17379 } 17380 if (!recalced && doc.height() !== last_scroll_height) { 17381 recalc(); 17382 recalced = true; 17383 } 17384 scroll = win.scrollTop(); 17385 if (last_pos != null) { 17386 delta = scroll - last_pos; 17387 } 17388 last_pos = scroll; 17389 if (fixed) { 17390 if (enable_bottoming) { 17391 will_bottom = scroll + height + offset > parent_height + parent_top; 17392 if (bottomed && !will_bottom) { 17393 bottomed = false; 17394 elm.css({ 17395 position: "fixed", 17396 bottom: "", 17397 top: offset 17398 }).trigger("sticky_kit:unbottom"); 17399 } 17400 } 17401 if (scroll < top) { 17402 fixed = false; 17403 offset = offset_top; 17404 if (manual_spacer == null) { 17405 if (el_float === "left" || el_float === "right") { 17406 elm.insertAfter(spacer); 17407 } 17408 spacer.detach(); 17409 } 17410 css = { 17411 position: "", 17412 width: "", 17413 top: "" 17414 }; 17415 elm.css(css).removeClass(sticky_class).trigger("sticky_kit:unstick"); 17416 } 17417 if (inner_scrolling) { 17418 win_height = win.height(); 17419 if (height + offset_top > win_height) { 17420 if (!bottomed) { 17421 offset -= delta; 17422 offset = Math.max(win_height - height, offset); 17423 offset = Math.min(offset_top, offset); 17424 if (fixed) { 17425 elm.css({ 17426 top: offset + "px" 17427 }); 17428 } 17429 } 17430 } 17431 } 17432 } else { 17433 if (scroll > top) { 17434 fixed = true; 17435 css = { 17436 position: "fixed", 17437 top: offset 17438 }; 17439 css.width = elm.css("box-sizing") === "border-box" ? elm.outerWidth() + "px" : elm.width() + "px"; 17440 elm.css(css).addClass(sticky_class); 17441 if (manual_spacer == null) { 17442 elm.after(spacer); 17443 if (el_float === "left" || el_float === "right") { 17444 spacer.append(elm); 17445 } 17446 } 17447 elm.trigger("sticky_kit:stick"); 17448 } 17449 } 17450 if (fixed && enable_bottoming) { 17451 if (will_bottom == null) { 17452 will_bottom = scroll + height + offset > parent_height + parent_top; 17453 } 17454 if (!bottomed && will_bottom) { 17455 bottomed = true; 17456 if (parent.css("position") === "static") { 17457 parent.css({ 17458 position: "relative" 17459 }); 17460 } 17461 return elm.css({ 17462 position: "absolute", 17463 bottom: padding_bottom, 17464 top: "auto" 17465 }).trigger("sticky_kit:bottom"); 17466 } 17467 } 17468 }; 17469 recalc_and_tick = function() { 17470 recalc(); 17471 return tick(); 17472 }; 17473 detach = function() { 17474 detached = true; 17475 win.off("touchmove", tick); 17476 win.off("scroll", tick); 17477 win.off("resize", recalc_and_tick); 17478 $(document.body).off("sticky_kit:recalc", recalc_and_tick); 17479 elm.off("sticky_kit:detach", detach); 17480 elm.removeData("sticky_kit"); 17481 elm.css({ 17482 position: "", 17483 bottom: "", 17484 top: "", 17485 width: "" 17486 }); 17487 parent.position("position", ""); 17488 if (fixed) { 17489 if (manual_spacer == null) { 17490 if (el_float === "left" || el_float === "right") { 17491 elm.insertAfter(spacer); 17492 } 17493 spacer.remove(); 17494 } 17495 return elm.removeClass(sticky_class); 17496 } 17497 }; 17498 win.on("touchmove", tick); 17499 win.on("scroll", tick); 17500 win.on("resize", recalc_and_tick); 17501 $(document.body).on("sticky_kit:recalc", recalc_and_tick); 17502 elm.on("sticky_kit:detach", detach); 17503 return setTimeout(tick, 0); 17504 }; 17505 for (i = 0, len = this.length; i < len; i++) { 17506 elm = this[i]; 17507 fn($(elm)); 17508 } 17509 return this; 17510 }; 17511 17512}).call(this); 17513/* ========================================================================== 17514 * bootstrap-tab-history.js 17515 * Author: Michael Narayan <[email protected]> 17516 * Repository: https://github.com/mnarayan01/bootstrap-tab-history/ 17517 * ========================================================================== 17518 * Licensed under the Apache License, Version 2.0 (the "License"); you may 17519 * not use this file except in compliance with the License. You may obtain a 17520 * copy of the License at 17521 * 17522 * http://www.apache.org/licenses/LICENSE-2.0 17523 * 17524 * Unless required by applicable law or agreed to in writing, softw
17524are 17525 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 17526 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 17527 * License for the specific language governing permissions and limitations 17528 * under the License. 17529 * ========================================================================== */ 17530 17531/* ========================================================================== */ 17532/* JSHint directives */ 17533/* */ 17534/* global BootstrapTabHistory: true */ 17535/* */ 17536/* global document */ 17537/* global jQuery */ 17538/* global history */ 17539/* global window */ 17540/* ========================================================================== */ 17541 17542/** 17543 * Integrate [HTML5 history state tracking](https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Manipulating_the_browser_history) 17544 * with [`bootstrap/tab.js`](http://getbootstrap.com/javascript/#tabs). To enable tracking on a tab element, simply set 17545 * the `data-tab-history` attribute to true (or a string denoting a tab grouping). 17546 * 17547 * See the README for additional information. 17548 * 17549 * Functionality based upon bootstrap/tab.js v3.1.0; reference it when making any changes. 17550 */ 17551 17552BootstrapTabHistory = { 17553 options: { 17554 /** 17555 * When the anchor portion of the URI is used to activate a tab, scroll down to the given offset, rather than the 17556 * element with the given `id` attribute. Set to null to disable. Only relevant if showTabsBasedOnAnchor is true. 17557 * 17558 * May be overriden on a per-element basis by the attribute `data-tab-history-anchor-y-offset`. 17559 * 17560 * @public 17561 * @type {?number} 17562 */ 17563 defaultAnchorYOffset: 0, 17564 /** 17565 * Either 'push' or 'replace', for whether to use `history.pushState` or `history.replaceState`, resp. 17566 * 17567 * May be overriden on a per-element basis by the attribute `data-tab-history-changer`. 17568 * 17569 * @public 17570 * @type {string} 17571 */ 17572 defaultChanger: 'replace', 17573 /** 17574 * If true, update the URL in onShownTab in the calls to `history.pushState` and `history.replaceState`. Otherwise, 17575 * `null` is passed as the third parameter to these calls. 17576 * 17577 * May be overriden on a per-element basis by the attribute `data-tab-history-update-url`. 17578 * 17579 * @public 17580 * @type {boolean} 17581 */ 17582 defaultUpdateURL: false, 17583 /** 17584 * Should the anchor portion of the loaded URI be used to activate a single tab if no history was present on page 17585 * load. 17586 * 17587 * @public 17588 * @type {boolean} 17589 */ 17590 showTabsBasedOnAnchor: true 17591 } 17592}; 17593 17594(function () { 17595 'use strict'; 17596 17597 jQuery(function () { 17598 if(history && history.pushState && history.replaceState) { 17599 var bootstrapTabHistory = history.state && history.state.bootstrapTabHistory; 17600 17601 if(bootstrapTabHistory) { 17602 showTabsBasedOnState(bootstrapTabHistory); 17603 } else { 17604 showTabsBasedOnAnchor(); 17605 } 17606 17607 backfillHistoryState(); 17608 17609 jQuery(document).on('shown.bs.tab show.bs.collapse', onShownTab); 17610 jQuery(window).on('popstate', onPopState); 17611 } else { 17612 showTabsBasedOnAnchor(); 17613 } 17614 }); 17615 17616 /** 17617 * Used to prevent onShownTab from registering shown events that we triggered via showTabsBasedOnState. 17618 * 17619 * @type {boolean} 17620 */ 17621 var showingTabsBasedOnState = false; 17622 17623 /** 17624 * Used to update `history.state` to reflect the default active tabs on initial page load. This supports proper 17625 * `history.back` handling when `data-tab-history-update-url` is true. 17626 */ 17627 function backfillHistoryState() { 17628 var newState = null; 17629 17630 jQuery('li.active > [data-tab-history], .panel-title.active [data-tab-history]').each(function () {//edited by Uncode 17631 var $activeTabElement = jQuery(this); 17632 var selector = getTabSelector($activeTabElement); 17633 17634 if(selector) { 17635 var tabGroup = getTabGroup($activeTabElement); 17636 17637 if(tabGroup) { 17638 newState = createNewHistoryState(newState || history.state, tabGroup, selector); 17639 } 17640 } 17641 }); 17642 17643 if(newState) { 17644 history.replaceState(newState, '', null); 17645 } 17646 } 17647 17648 /** 17649 * Clone the existing state, ensure its bootstrapTabHistory attribute is an Object, and add the provided tabGroup to 17650 * said bootstrapTabHistory attribute. 17651 * 17652 * @param {?object} existingState 17653 * @param {!string} tabGroup 17654 * @param {!string} selector 17655 * @returns {!object} 17656 */ 17657 function createNewHistoryState(existingState, tabGroup, selector) { 17658 // Clone history.state and ensure it has a bootstrapTabHistory entry. 17659 var newState = jQuery.extend(true, {}, existingState, { 17660 bootstrapTabHistory: {} 17661 }); 17662 17663 newState.bootstrapTabHistory[tabGroup] = selector; 17664 17665 return newState; 17666 } 17667 17668 /** 17669 * @param {jQuery} $tab
17670 * @returns {?string} 17671 */ 17672 function getTabGroup($tab) { 17673 return parseTruthyAttributeValue($tab.data('tab-history')); 17674 } 17675 17676 /** 17677 * @param {jQuery} $tab 17678 * @returns {?string} 17679 */ 17680 function getTabSelector($tab) { 17681 return $tab.data('target') || $tab.attr('href'); 17682 } 17683 17684 /** 17685 * Receives the `shown.bs.tab` event. Updates `history.state` as appropriate. 17686 * 17687 * @param {jQuery.Event} shownEvt 17688 */ 17689 function onShownTab(shownEvt) { 17690 if(!showingTabsBasedOnState) { 17691 var $activatedTab = jQuery(shownEvt.target); 17692 if ( $activatedTab.hasClass('panel-collapse') ) 17693 $activatedTab = $activatedTab.closest('.panel').find('a'); 17694 var selector = getTabSelector($activatedTab); 17695 17696 if(selector) { 17697 var tabGroup = getTabGroup($activatedTab); 17698 17699 if(tabGroup) { 17700 var historyChanger = $activatedTab.data('tab-history-changer') || BootstrapTabHistory.options.defaultChanger; 17701 var newState = createNewHistoryState(history.state, tabGroup, selector); 17702 var updateURL = (function ($activatedTab) { 17703 if(selector[0] === '#') { 17704 var elementUpdateURLOption = parseTruthyAttributeValue($activatedTab.data('tab-history-update-url')); 17705 17706 if(elementUpdateURLOption === undefined) { 17707 return BootstrapTabHistory.options.defaultUpdateURL; 17708 } else { 17709 return elementUpdateURLOption; 17710 } 17711 } else { 17712 return false; 17713 } 17714 })($activatedTab); 17715 17716 switch(historyChanger) { 17717 case 'push': 17718 history.pushState(newState, '', updateURL ? selector : null); 17719 break; 17720 case 'replace': 17721 history.replaceState(newState, '', updateURL ? selector : null); 17722 break; 17723 default: 17724 throw new Error('Unknown tab-history-changer: ' + historyChanger); 17725 } 17726 } 17727 } 17728 } 17729 } 17730 17731 /** 17732 * Receives the `popstate` event. Shows tabs based on the value of `history.state` as appropriate. 17733 */ 17734 function onPopState() { 17735 var bootstrapTabHistory = history.state && history.state.bootstrapTabHistory; 17736 17737 if(bootstrapTabHistory) { 17738 showTabsBasedOnState(bootstrapTabHistory); 17739 } 17740 } 17741 17742 /** 17743 * Returns the given value, _unless_ that value is an empty string, in which case `true` is returned. 17744 * 17745 * Rationale: HAML data attributes which are set to `true` are rendered as a blank string. 17746 * 17747 * @param {*} value 17748 * @returns {*} 17749 */ 17750 function parseTruthyAttributeValue(value) { 17751 if(value) { 17752 return value; 17753 } else if(value === '') { 17754 return true; 17755 } else { 17756 return value; 17757 } 17758 } 17759 17760 /** 17761 * Show tabs based upon the anchor component of `window.location`. 17762 */ 17763 function showTabsBasedOnAnchor() { 17764 if(BootstrapTabHistory.options.showTabsBasedOnAnchor) { 17765 var anchor = window.location && window.location.hash; 17766 17767 if(anchor) { 17768 var $tabElement = showTabForSelector(anchor); 17769 17770 if($tabElement && window.addEventListener && window.removeEventListener) { 17771 var anchorYOffset = (function ($tabElement) { 17772 var elementSetting = $tabElement.data('tab-history-anchor-y-offset'); 17773 17774 if(elementSetting === undefined) { 17775 return BootstrapTabHistory.options.defaultAnchorYOffset; 17776 } else { 17777 return elementSetting; 17778 } 17779 })($tabElement); 17780 17781 // HACK: This prevents scrolling to the tab on page load. This relies on the fact that we should never get 17782 // here on `history.forward`, `history.back`, or `location.reload`, since in all those situations the 17783 // `history.state` object should have been used (unless the browser did not support the modern History API). 17784 if(anchorYOffset || anchorYOffset === 0) { 17785 var scrollListener = function resetAnchorScroll () { 17786 window.removeEventListener('scroll', scrollListener); 17787 window.scrollTo(0, anchorYOffset); 17788 }; 17789 17790 window.addEventListener('scroll', scrollListener); 17791 } 17792 } 17793 } 17794 } 17795 } 17796 17797 /** 17798 * Show a tab which corresponds to the provided selector. 17799 * 17800 * @param {string} selector - A CSS selector. 17801 * @returns {?jQuery} - The tab which was found to show (even if said tab was already active). 17802 */ 17803 function showTabForSelector(selector) { 17804 var $tabElement = (function (selector) { 17805 var $ret = null; 17806 17807 jQuery('[data-toggle="tab"], [data-toggle="pill"], [data-toggle="collapse"]').each(function () { 17808 var $potentialTab = jQuery(this); 17809 17810 if(($potentialTab.attr('href') === selector || $potentialTab.data('target') === selector ) && getTabGroup($potentialTab)) { 17811 $ret = $potentialTab; 17812 return false;
vendor: 4,522 bytes, lines 17813-17962
17813 } else { 17814 return null; 17815 } 17816 }); 17817 17818 return $ret; 17819 })(selector); 17820 17821 if($tabElement) { 17822 $tabElement.trigger('click'); 17823 //$tabElement.tab('show'); 17824 } 17825 17826 return $tabElement; 17827 } 17828 17829 /** 17830 * Iterate through the provided set of tab tab groups, showing the tabs based on the stored selectors. 17831 * 17832 * @param {object} bootstrapTabHistory - Each of the values is passed to showTabForSelector; the keys are actually irrelevant. 17833 */ 17834 function showTabsBasedOnState(bootstrapTabHistory) { 17835 showingTabsBasedOnState = true; 17836 17837 try { 17838 for(var k in bootstrapTabHistory) { 17839 if(bootstrapTabHistory.hasOwnProperty(k)) { 17840 showTabForSelector(bootstrapTabHistory[k]); 17841 } 17842 } 17843 } finally { 17844 showingTabsBasedOnState = false; 17845 } 17846 } 17847})(); 17848 17849/*! 17850 * Justified Gallery - v3.6.3 17851 * http://miromannino.github.io/Justified-Gallery/ 17852 * Copyright (c) 2016 Miro Mannino 17853 * Licensed under the MIT license. 17854 */ 17855(function($) { 17856 17857 function hasScrollBar() { 17858 return $("body").height() > $(window).height(); 17859 } 17860 /** 17861 * Justified Gallery controller constructor 17862 * 17863 * @param $gallery the gallery to build 17864 * @param settings the settings (the defaults are in $.fn.justifiedGallery.defaults) 17865 * @constructor 17866 */ 17867 var JustifiedGallery = function ($gallery, settings) { 17868 17869 this.settings = settings; 17870 this.checkSettings(); 17871 17872 this.imgAnalyzerTimeout = null; 17873 this.entries = null; 17874 this.buildingRow = { 17875 entriesBuff : [], 17876 width : 0, 17877 height : 0, 17878 aspectRatio : 0 17879 }; 17880 this.lastFetchedEntry = null; 17881 this.lastAnalyzedIndex = -1; 17882 this.yield = { 17883 every : 2, // do a flush every n flushes (must be greater than 1) 17884 flushed : 0 // flushed rows without a yield 17885 }; 17886 this.border = settings.border >= 0 ? settings.border : settings.margins; 17887 this.maxRowHeight = this.retrieveMaxRowHeight(); 17888 this.suffixRanges = this.retrieveSuffixRanges(); 17889 this.offY = this.border; 17890 this.rows = 0; 17891 this.spinner = { 17892 phase : 0, 17893 timeSlot : 150, 17894 $el : $('<div class="spinner"><span></span><span></span><span></span></div>'), 17895 intervalId : null 17896 }; 17897 this.checkWidthIntervalId = null; 17898 this.galleryWidth = $gallery.width(); 17899 this.$gallery = $gallery; 17900 17901 }; 17902 17903 /** @returns {String} the best suffix given the width and the height */ 17904 JustifiedGallery.prototype.getSuffix = function (width, height) { 17905 var longestSide, i; 17906 longestSide = (width > height) ? width : height; 17907 for (i = 0; i < this.suffixRanges.length; i++) { 17908 if (longestSide <= this.suffixRanges[i]) { 17909 return this.settings.sizeRangeSuffixes[this.suffixRanges[i]]; 17910 } 17911 } 17912 return this.settings.sizeRangeSuffixes[this.suffixRanges[i - 1]]; 17913 }; 17914 17915 /** 17916 * Remove the suffix from the string 17917 * 17918 * @returns {string} a new string without the suffix 17919 */ 17920 JustifiedGallery.prototype.removeSuffix = function (str, suffix) { 17921 return str.substring(0, str.length - suffix.length); 17922 }; 17923 17924 /** 17925 * @returns {boolean} a boolean to say if the suffix is contained in the str or not 17926 */ 17927 JustifiedGallery.prototype.endsWith = function (str, suffix) { 17928 return str.indexOf(suffix, str.length - suffix.length) !== -1; 17929 }; 17930 17931 /** 17932 * Get the used suffix of a particular url 17933 * 17934 * @param str 17935 * @returns {String} return the used suffix 17936 */ 17937 JustifiedGallery.prototype.getUsedSuffix = function (str) { 17938 for (var si in this.settings.sizeRangeSuffixes) { 17939 if (this.settings.sizeRangeSuffixes.hasOwnProperty(si)) { 17940 if (this.settings.sizeRangeSuffixes[si].length === 0) continue; 17941 if (this.endsWith(str, this.settings.sizeRangeSuffixes[si])) return this.settings.sizeRangeSuffixes[si]; 17942 } 17943 } 17944 return ''; 17945 }; 17946 17947 /** 17948 * Given an image src, with the width and the height, returns the new image src with the 17949 * best suffix to show the best quality thumbnail. 17950 * 17951 * @returns {String} the suffix to use 17952 */ 17953 JustifiedGallery.prototype.newSrc = function (imageSrc, imgWidth, imgHeight, image) { 17954 var newImageSrc; 17955 17956 if (this.settings.thumbnailPath) { 17957 newImageSrc = this.settings.thumbnailPath(imageSrc, imgWidth, imgHeight, image); 17958 } else { 17959 var matchRes = imageSrc.match(this.settings.extension); 17960 var ext = (matchRes !== null) ? matchRes[0] : ''; 17961 newImageSrc = imageSrc.replace(this.settings.extension, ''); 17962 newImageSrc = this.removeSuffix(newImageSrc, this.getUsedSuffix(newImageSrc));
17963 newImageSrc += this.getSuffix(imgWidth, imgHeight) + ext; 17964 } 17965 17966 return newImageSrc; 17967 }; 17968 17969 /** 17970 * Shows the images that is in the given entry 17971 * 17972 * @param $entry the entry 17973 * @param callback the callback that is called when the show animation is finished 17974 */ 17975 JustifiedGallery.prototype.showImg = function ($entry, callback) { 17976 if (this.settings.cssAnimation) { 17977 $entry.addClass('entry-visible'); 17978 if (callback) callback(); 17979 } else { 17980 $entry.stop().fadeTo(this.settings.imagesAnimationDuration, 1.0, callback); 17981 $entry.find('> img, > a > img').stop().fadeTo(this.settings.imagesAnimationDuration, 1.0, callback); 17982 } 17983 }; 17984 17985 /** 17986 * Extract the image src form the image, looking from the 'safe-src', and if it can't be found, from the 17987 * 'src' attribute. It saves in the image data the 'jg.originalSrc' field, with the extracted src. 17988 * 17989 * @param $image the image to analyze 17990 * @returns {String} the extracted src 17991 */ 17992 JustifiedGallery.prototype.extractImgSrcFromImage = function ($image) { 17993 var imageSrc = (typeof $image.data('safe-src') !== 'undefined') ? $image.data('safe-src') : $image.attr('src'); 17994 $image.data('jg.originalSrc', imageSrc); 17995 return imageSrc; 17996 }; 17997 17998 /** @returns {jQuery} the image in the given entry */ 17999 JustifiedGallery.prototype.imgFromEntry = function ($entry) { 18000 var $img = $entry.find('> img'); 18001 if ($img.length === 0) $img = $entry.find('> a > img'); 18002 if ($img.length === 0) $img = $entry.find('.t-entry-visual-cont img');//hacked by Uncode 18003 return $img.length === 0 ? null : $img; 18004 }; 18005 18006 /** @returns {jQuery} the caption in the given entry */ 18007 JustifiedGallery.prototype.captionFromEntry = function ($entry) { 18008 var $caption = $entry.find('> .caption'); 18009 return $caption.length === 0 ? null : $caption; 18010 }; 18011 18012 /** 18013 * Display the entry 18014 * 18015 * @param {jQuery} $entry the entry to display 18016 * @param {int} x the x position where the entry must be positioned 18017 * @param y the y position where the entry must be positioned 18018 * @param imgWidth the image width 18019 * @param imgHeight the image height 18020 * @param rowHeight the row height of the row that owns the entry 18021 */ 18022 JustifiedGallery.prototype.displayEntry = function ($entry, x, y, imgWidth, imgHeight, rowHeight) { 18023 $entry.width(imgWidth); 18024 $entry.height(Math.floor(rowHeight));//hacked by Uncode 18025 $entry.css('top', Math.floor(y));//hacked by Uncode 18026 $entry.css('left', x); 18027 18028 var $image = this.imgFromEntry($entry); 18029 if ($image !== null) { 18030 $image.css('width', imgWidth); 18031 $image.css('height', imgHeight); 18032 $image.css('margin-left', - imgWidth / 2); 18033 $image.css('margin-top', - imgHeight / 2); 18034 18035 // Image reloading for an high quality of thumbnails 18036 var imageSrc = $image.attr('src'); 18037 var newImageSrc = this.newSrc(imageSrc, imgWidth, imgHeight, $image[0]); 18038 18039 $image.one('error', function () { 18040 $image.attr('src', $image.data('jg.originalSrc')); //revert to the original thumbnail, we got it. 18041 }); 18042 18043 var loadNewImage = function () { 18044 if (imageSrc !== newImageSrc) { //load the new image after the fadeIn 18045 $image.attr('src', newImageSrc); 18046 } 18047 }; 18048 18049 if ($entry.data('jg.loaded') === 'skipped') { 18050 this.onImageEvent(imageSrc, $.proxy(function() { 18051 this.showImg($entry, loadNewImage); 18052 $entry.data('jg.loaded', true); 18053 }, this)); 18054 } else { 18055 this.showImg($entry, loadNewImage); 18056 } 18057 18058 } else { 18059 this.showImg($entry); 18060 } 18061 18062 this.displayEntryCaption($entry); 18063 }; 18064 18065 /** 18066 * Display the entry caption. If the caption element doesn't exists, it creates the caption using the 'alt' 18067 * or the 'title' attributes. 18068 * 18069 * @param {jQuery} $entry the entry to process 18070 */ 18071 JustifiedGallery.prototype.displayEntryCaption = function ($entry) { 18072 var $image = this.imgFromEntry($entry); 18073 if ($image !== null && this.settings.captions) { 18074 var $imgCaption = this.captionFromEntry($entry); 18075 18076 // Create it if it doesn't exists 18077 if ($imgCaption === null) { 18078 var caption = $image.attr('alt'); 18079 if (!this.isValidCaption(caption)) caption = $entry.attr('title'); 18080 if (this.isValidCaption(caption)) { // Create only we found something 18081 $imgCaption = $('<div class="caption">' + caption + '</div>'); 18082 $entry.append($imgCaption); 18083 $entry.data('jg.createdCaption', true); 18084 } 18085 } 18086 18087 // Create events (we check again the $imgCaption because it can be still inexistent) 18088 if ($imgCaption !== null) { 18089 if (!this.settings.cssAnimation) $imgCaption.stop().fadeTo(0, this.settings.captionSettings.nonVisibleOpacity); 18090 this.addCaptionEventsHandlers($entry); 18091 } 18092 } else { 18093 this.removeCaptionEventsHandlers($entry); 18094 } 18095 }; 18096 18097 /** 18098 * Validates the caption 18099 * 18100 * @param caption The caption that should be validated 18101 * @return {boolean} Validation result 18102 */ 18103 JustifiedGallery.prototype.isValidCaption = function (caption) { 18104 return (typeof caption !== 'undefined' && caption.length > 0); 18105 }; 18106 18107 /** 18108 * The callback for the event 'mouseenter'. It assumes that the event currentTarget is an entry. 18109 * It shows the caption using jQuery (or using CSS if it is configured so) 18110 * 18111 * @param {Event} eventObject the event object 18112 */ 18113 JustifiedGallery.prototype.onEntryMouseEnterForCaption = function (eventObject) { 18114 var $caption = this.captionFromEntry($(eventObject.currentTarget)); 18115 if (this.settings.cssAnimation) { 18116 $caption.addClass('caption-visible').removeClass('caption-hidden'); 18117 } else { 18118 $caption.stop().fadeTo(this.settings.captionSettings.animationDuration, 18119 this.settings.captionSettings.visibleOpacity); 18120 } 18121 }; 18122 18123 /** 18124 * The callback for the event 'mouseleave'. It assumes that the event currentTarget is an entry. 18125 * It hides the caption using jQuery (or using CSS if it is configured so) 18126 * 18127 * @param {Event} eventObject the event object 18128 */ 18129 JustifiedGallery.prototype.onEntryMouseLeaveForCaption = function (eventObject) { 18130 var $caption = this.captionFromEntry($(eventObject.currentTarget)); 18131 if (this.settings.cssAnimation) { 18132 $caption.removeClass('caption-visible').removeClass('caption-hidden'); 18133 } else { 18134 $caption.stop().fadeTo(this.settings.captionSettings.animationDuration, 18135 this.settings.captionSettings.nonVisibleOpacity); 18136 } 18137 }; 18138 18139 /** 18140 * Add the handlers of the entry for the caption 18141 * 18142 * @param $entry the entry to modify 18143 */ 18144 JustifiedGallery.prototype.addCaptionEventsHandlers = function ($entry) { 18145 var captionMouseEvents = $entry.data('jg.captionMouseEvents'); 18146 if (typeof captionMouseEvents === 'undefined') { 18147 captionMouseEvents = { 18148 mouseenter: $.proxy(this.onEntryMouseEnterForCaption, this), 18149 mouseleave: $.proxy(this.onEntryMouseLeaveForCaption, this) 18150 }; 18151 $entry.on('mouseenter', undefined, undefined, captionMouseEvents.mouseenter); 18152 $entry.on('mouseleave', undefined, undefined, captionMouseEvents.mouseleave); 18153 $entry.data('jg.captionMouseEvents', captionMouseEvents); 18154 } 18155 }; 18156 18157 /** 18158 * Remove the handlers of the entry for the caption 18159 * 18160 * @param $entry the entry to modify 18161 */ 18162 JustifiedGallery.prototype.removeCaptionEventsHandlers = function ($entry) { 18163 var captionMouseEvents = $entry.data('jg.captionMouseEvents'); 18164 if (typeof captionMouseEvents !== 'undefined') { 18165 $entry.off('mouseenter', undefined, captionMouseEvents.mouseenter); 18166 $entry.off('mouseleave', undefined, captionMouseEvents.mouseleave); 18167 $entry.removeData('jg.captionMouseEvents'); 18168 } 18169 }; 18170 18171 /** 18172 * Justify the building row, preparing it to 18173 * 18174 * @param isLastRow 18175 * @returns a boolean to know if the row has been justified or not 18176 */ 18177 JustifiedGallery.prototype.prepareBuildingRow = function (isLastRow) { 18178 var i, $entry, imgAspectRatio, newImgW, newImgH, justify = true; 18179 var minHeight = 0; 18180 var availableWidth = this.galleryWidth - 2 * this.border - ( 18181 (this.buildingRow.entriesBuff.length - 1) * this.settings.margins); 18182 var rowHeight = Math.floor( availableWidth / this.buildingRow.aspectRatio );//hacked by Uncode 18183 var defaultRowHeight = this.settings.rowHeight; 18184 var justifiable = this.buildingRow.width / availableWidth > this.settings.justifyThreshold; 18185 18186 //Skip the last row if we can't justify it and the lastRow == 'hide' 18187 if (isLastRow && this.settings.lastRow === 'hide' && !justifiable) { 18188 for (i = 0; i < this.buildingRow.entriesBuff.length; i++) { 18189 $entry = this.buildingRow.entriesBuff[i]; 18190 if (this.settings.cssAnimation) 18191 $entry.removeClass('entry-visible'); 18192 else { 18193 $entry.stop().fadeTo(0, 0.1); 18194 $entry.find('> img, > a > img').fadeTo(0, 0); 18195 } 18196 } 18197 return -1; 18198 } 18199 18200 // With lastRow = nojustify, justify if is justificable (the images will not become too big) 18201 if (isLastRow && !justifiable && this.settings.lastRow !== 'justify' && this.settings.lastRow !== 'hide') { 18202 justify = false;
18203 18204 if (this.rows > 0) { 18205 defaultRowHeight = (this.offY - this.border - this.settings.margins * this.rows) / this.rows; 18206 justify = defaultRowHeight * this.buildingRow.aspectRatio / availableWidth > this.settings.justifyThreshold; 18207 } 18208 } 18209 18210 for (i = 0; i < this.buildingRow.entriesBuff.length; i++) { 18211 $entry = this.buildingRow.entriesBuff[i]; 18212 imgAspectRatio = $entry.data('jg.width') / $entry.data('jg.height'); 18213 18214 if (justify) { 18215 newImgW = (i === this.buildingRow.entriesBuff.length - 1) ? availableWidth : rowHeight * imgAspectRatio; 18216 newImgH = rowHeight; 18217 } else { 18218 newImgW = defaultRowHeight * imgAspectRatio; 18219 newImgH = defaultRowHeight; 18220 } 18221 18222 availableWidth -= Math.round(newImgW); 18223 $entry.data('jg.jwidth', Math.round(newImgW)); 18224 $entry.data('jg.jheight', Math.ceil(newImgH)); 18225 if (i === 0 || minHeight > newImgH) minHeight = newImgH; 18226 } 18227 18228 this.buildingRow.height = minHeight; 18229 return justify; 18230 }; 18231 18232 /** 18233 * Clear the building row data to be used for a new row 18234 */ 18235 JustifiedGallery.prototype.clearBuildingRow = function () { 18236 this.buildingRow.entriesBuff = []; 18237 this.buildingRow.aspectRatio = 0; 18238 this.buildingRow.width = 0; 18239 }; 18240 18241 /** 18242 * Flush a row: justify it, modify the gallery height accordingly to the row height 18243 * 18244 * @param isLastRow 18245 */ 18246 JustifiedGallery.prototype.flushRow = function (isLastRow) { 18247 var settings = this.settings; 18248 var $entry, buildingRowRes, offX = this.border, i; 18249 18250 buildingRowRes = this.prepareBuildingRow(isLastRow); 18251 if (isLastRow && settings.lastRow === 'hide' && buildingRowRes === -1) { 18252 this.clearBuildingRow(); 18253 return; 18254 } 18255 18256 if (this.maxRowHeight) { 18257 if (this.maxRowHeight.isPercentage && this.maxRowHeight.value * settings.rowHeight < this.buildingRow.height) { 18258 this.buildingRow.height = this.maxRowHeight.value * settings.rowHeight; 18259 } else if (this.maxRowHeight.value >= settings.rowHeight && this.maxRowHeight.value < this.buildingRow.height) { 18260 this.buildingRow.height = this.maxRowHeight.value; 18261 } 18262 } 18263 18264 //Align last (unjustified) row 18265 if (settings.lastRow === 'center' || settings.lastRow === 'right') { 18266 var availableWidth = this.galleryWidth - 2 * this.border - (this.buildingRow.entriesBuff.length - 1) * settings.margins; 18267 18268 for (i = 0; i < this.buildingRow.entriesBuff.length; i++) { 18269 $entry = this.buildingRow.entriesBuff[i]; 18270 availableWidth -= $entry.data('jg.jwidth'); 18271 } 18272 18273 if (settings.lastRow === 'center') 18274 offX += availableWidth / 2; 18275 else if (settings.lastRow === 'right') 18276 offX += availableWidth; 18277 } 18278 18279 for (i = 0; i < this.buildingRow.entriesBuff.length; i++) { 18280 $entry = this.buildingRow.entriesBuff[i]; 18281 this.displayEntry($entry, offX, this.offY, $entry.data('jg.jwidth'), $entry.data('jg.jheight'), this.buildingRow.height); 18282 offX += $entry.data('jg.jwidth') + settings.margins; 18283 } 18284 18285 //Gallery Height 18286 this.galleryHeightToSet = this.offY + this.buildingRow.height + this.border; 18287 this.$gallery.height(this.galleryHeightToSet + this.getSpinnerHeight()); 18288 18289 if (!isLastRow || (this.buildingRow.height <= settings.rowHeight && buildingRowRes)) { 18290 //Ready for a new row 18291 this.offY += this.buildingRow.height + settings.margins; 18292 this.rows += 1; 18293 this.clearBuildingRow(); 18294 this.$gallery.trigger('jg.rowflush'); 18295 } 18296 }; 18297 18298 /** 18299 * Checks the width of the gallery container, to know if a new justification is needed 18300 */ 18301 var scrollBarOn = false; 18302 JustifiedGallery.prototype.checkWidth = function () { 18303 this.checkWidthIntervalId = setInterval($.proxy(function () { 18304 var galleryWidth = parseFloat(this.$gallery.width()); 18305 if (hasScrollBar() === scrollBarOn) { 18306 if (Math.abs(galleryWidth - this.galleryWidth) > this.settings.refreshSensitivity) { 18307 this.galleryWidth = galleryWidth; 18308 this.rewind(); 18309 18310 // Restart to analyze 18311 this.startImgAnalyzer(true); 18312 } 18313 } else { 18314 scrollBarOn = hasScrollBar(); 18315 this.galleryWidth = galleryWidth; 18316 } 18317 }, this), this.settings.refreshTime); 18318 }; 18319 18320 /** 18321 * @returns {boolean} a boolean saying if the spinner is active or not 18322 */ 18323 JustifiedGallery.prototype.isSpinnerActive = function () { 18324 return this.spinner.intervalId !== null; 18325 }; 18326 18327 /** 18328 * @returns {int} the spinner height 18329 */ 18330 JustifiedGallery.prototype.getSpinnerHeight = function () {
18331 return this.spinner.$el.innerHeight(); 18332 }; 18333 18334 /** 18335 * Stops the spinner animation and modify the gallery height to exclude the spinner 18336 */ 18337 JustifiedGallery.prototype.stopLoadingSpinnerAnimation = function () { 18338 clearInterval(this.spinner.intervalId); 18339 this.spinner.intervalId = null; 18340 this.$gallery.height(this.$gallery.height() - this.getSpinnerHeight()); 18341 this.spinner.$el.detach(); 18342 }; 18343 18344 /** 18345 * Starts the spinner animation 18346 */ 18347 JustifiedGallery.prototype.startLoadingSpinnerAnimation = function () { 18348 var spinnerContext = this.spinner; 18349 var $spinnerPoints = spinnerContext.$el.find('span'); 18350 clearInterval(spinnerContext.intervalId); 18351 this.$gallery.append(spinnerContext.$el); 18352 this.$gallery.height(this.offY + this.buildingRow.height + this.getSpinnerHeight()); 18353 spinnerContext.intervalId = setInterval(function () { 18354 if (spinnerContext.phase < $spinnerPoints.length) { 18355 $spinnerPoints.eq(spinnerContext.phase).fadeTo(spinnerContext.timeSlot, 1); 18356 } else {
vendor: 4,333 bytes, lines 18357-18501
18357 $spinnerPoints.eq(spinnerContext.phase - $spinnerPoints.length).fadeTo(spinnerContext.timeSlot, 0); 18358 } 18359 spinnerContext.phase = (spinnerContext.phase + 1) % ($spinnerPoints.length * 2); 18360 }, spinnerContext.timeSlot); 18361 }; 18362 18363 /** 18364 * Rewind the image analysis to start from the first entry. 18365 */ 18366 JustifiedGallery.prototype.rewind = function () { 18367 this.lastFetchedEntry = null; 18368 this.lastAnalyzedIndex = -1; 18369 this.offY = this.border; 18370 this.rows = 0; 18371 this.clearBuildingRow(); 18372 }; 18373 18374 /** 18375 * Update the entries searching it from the justified gallery HTML element 18376 * 18377 * @param norewind if norewind only the new entries will be changed (i.e. randomized, sorted or filtered) 18378 * @returns {boolean} true if some entries has been founded 18379 */ 18380 JustifiedGallery.prototype.updateEntries = function (norewind) { 18381 var newEntries; 18382 18383 if (norewind && this.lastFetchedEntry != null) { 18384 newEntries = $(this.lastFetchedEntry).nextAll(this.settings.selector).toArray(); 18385 } else { 18386 this.entries = []; 18387 newEntries = this.$gallery.children(this.settings.selector).toArray(); 18388 } 18389 18390 if (newEntries.length > 0) { 18391 18392 // Sort or randomize 18393 if ($.isFunction(this.settings.sort)) { 18394 newEntries = this.sortArray(newEntries); 18395 } else if (this.settings.randomize) { 18396 newEntries = this.shuffleArray(newEntries); 18397 } 18398 this.lastFetchedEntry = newEntries[newEntries.length - 1]; 18399 18400 // Filter 18401 if (this.settings.filter) { 18402 newEntries = this.filterArray(newEntries); 18403 } else { 18404 this.resetFilters(newEntries); 18405 } 18406 18407 } 18408 18409 this.entries = this.entries.concat(newEntries); 18410 return true; 18411 }; 18412 18413 /** 18414 * Apply the entries order to the DOM, iterating the entries and appending the images 18415 * 18416 * @param entries the entries that has been modified and that must be re-ordered in the DOM 18417 */ 18418 JustifiedGallery.prototype.insertToGallery = function (entries) { 18419 var that = this; 18420 $.each(entries, function () { 18421 $(this).appendTo(that.$gallery); 18422 }); 18423 }; 18424 18425 /** 18426 * Shuffle the array using the Fisher-Yates shuffle algorithm 18427 * 18428 * @param a the array to shuffle 18429 * @return the shuffled array 18430 */ 18431 JustifiedGallery.prototype.shuffleArray = function (a) { 18432 var i, j, temp; 18433 for (i = a.length - 1; i > 0; i--) { 18434 j = Math.floor(Math.random() * (i + 1)); 18435 temp = a[i]; 18436 a[i] = a[j]; 18437 a[j] = temp; 18438 } 18439 this.insertToGallery(a); 18440 return a; 18441 }; 18442 18443 /** 18444 * Sort the array using settings.comparator as comparator 18445 * 18446 * @param a the array to sort (it is sorted) 18447 * @return the sorted array 18448 */ 18449 JustifiedGallery.prototype.sortArray = function (a) { 18450 a.sort(this.settings.sort); 18451 this.insertToGallery(a); 18452 return a; 18453 }; 18454 18455 /** 18456 * Reset the filters removing the 'jg-filtered' class from all the entries 18457 * 18458 * @param a the array to reset 18459 */ 18460 JustifiedGallery.prototype.resetFilters = function (a) { 18461 for (var i = 0; i < a.length; i++) $(a[i]).removeClass('jg-filtered'); 18462 }; 18463 18464 /** 18465 * Filter the entries considering theirs classes (if a string has been passed) or using a function for filtering. 18466 * 18467 * @param a the array to filter 18468 * @return the filtered array 18469 */ 18470 JustifiedGallery.prototype.filterArray = function (a) { 18471 var settings = this.settings; 18472 if ($.type(settings.filter) === 'string') { 18473 // Filter only keeping the entries passed in the string 18474 return a.filter(function (el) { 18475 var $el = $(el); 18476 if ($el.is(settings.filter)) { 18477 $el.removeClass('jg-filtered'); 18478 return true; 18479 } else { 18480 $el.addClass('jg-filtered').removeClass('jg-visible'); 18481 return false; 18482 } 18483 }); 18484 } else if ($.isFunction(settings.filter)) { 18485 // Filter using the passed function 18486 var filteredArr = a.filter(settings.filter); 18487 for (var i = 0; i < a.length; i++) { 18488 if (filteredArr.indexOf(a[i]) == -1) { 18489 $(a[i]).addClass('jg-filtered').removeClass('jg-visible'); 18490 } else { 18491 $(a[i]).removeClass('jg-filtered'); 18492 } 18493 } 18494 return filteredArr; 18495 } 18496 }; 18497 18498 /** 18499 * Destroy the Justified Gallery instance. 18500 * 18501 * It clears all the css properties added in the style attributes. We doesn't backup the original
18502 * values for those css attributes, because it costs (performance) and because in general one 18503 * shouldn't use the style attribute for an uniform set of images (where we suppose the use of 18504 * classes). Creating a backup is also difficult because JG could be called multiple times and 18505 * with different style attributes. 18506 */ 18507 JustifiedGallery.prototype.destroy = function () { 18508 clearInterval(this.checkWidthIntervalId); 18509 18510 $.each(this.entries, $.proxy(function(_, entry) { 18511 var $entry = $(entry); 18512 18513 // Reset entry style 18514 $entry.css('width', ''); 18515 $entry.css('height', ''); 18516 $entry.css('top', ''); 18517 $entry.css('left', ''); 18518 $entry.data('jg.loaded', undefined); 18519 $entry.removeClass('jg-entry'); 18520 18521 // Reset image style 18522 var $img = this.imgFromEntry($entry); 18523 $img.css('width', ''); 18524 $img.css('height', ''); 18525 $img.css('margin-left', ''); 18526 $img.css('margin-top', ''); 18527 $img.attr('src', $img.data('jg.originalSrc')); 18528 $img.data('jg.originalSrc', undefined); 18529 18530 // Remove caption 18531 this.removeCaptionEventsHandlers($entry); 18532 var $caption = this.captionFromEntry($entry); 18533 if ($entry.data('jg.createdCaption')) { 18534 // remove also the caption element (if created by jg) 18535 $entry.data('jg.createdCaption', undefined); 18536 if ($caption !== null) $caption.remove(); 18537 } else { 18538 if ($caption !== null) $caption.fadeTo(0, 1); 18539 } 18540 18541 }, this)); 18542 18543 this.$gallery.css('height', ''); 18544 this.$gallery.removeClass('justified-gallery'); 18545 this.$gallery.data('jg.controller', undefined); 18546 }; 18547 18548 /** 18549 * Analyze the images and builds the rows. It returns if it found an image that is not loaded. 18550 * 18551 * @param isForResize if the image analyzer is called for resizing or not, to call a different callback at the end 18552 */ 18553 JustifiedGallery.prototype.analyzeImages = function (isForResize) { 18554 for (var i = this.lastAnalyzedIndex + 1; i < this.entries.length; i++) { 18555 var $entry = $(this.entries[i]); 18556 if ($entry.data('jg.loaded') === true || $entry.data('jg.loaded') === 'skipped') { 18557 var availableWidth = this.galleryWidth - 2 * this.border - ( 18558 (this.buildingRow.entriesBuff.length - 1) * this.settings.margins); 18559 var imgAspectRatio = $entry.data('jg.width') / $entry.data('jg.height'); 18560 if (availableWidth / (this.buildingRow.aspectRatio + imgAspectRatio) < this.settings.rowHeight) { 18561 this.flushRow(false); 18562 if(++this.yield.flushed >= this.yield.every) { 18563 this.startImgAnalyzer(isForResize); 18564 return; 18565 } 18566 } 18567 18568 this.buildingRow.entriesBuff.push($entry); 18569 this.buildingRow.aspectRatio += imgAspectRatio; 18570 this.buildingRow.width += imgAspectRatio * this.settings.rowHeight; 18571 this.lastAnalyzedIndex = i; 18572 18573 } else if ($entry.data('jg.loaded') !== 'error') { 18574 return; 18575 } 18576 } 18577 18578 // Last row flush (the row is not full) 18579 if (this.buildingRow.entriesBuff.length > 0) this.flushRow(true); 18580 18581 if (this.isSpinnerActive()) { 18582 this.stopLoadingSpinnerAnimation(); 18583 } 18584 18585 /* Stop, if there is, the timeout to start the analyzeImages. 18586 This is because an image can be set loaded, and the timeout can be set, 18587 but this image can be analyzed yet. 18588 */ 18589 this.stopImgAnalyzerStarter(); 18590 18591 //On complete callback 18592 this.$gallery.trigger(isForResize ? 'jg.resize' : 'jg.complete'); 18593 this.$gallery.height(this.galleryHeightToSet); 18594 }; 18595 18596 /** 18597 * Stops any ImgAnalyzer starter (that has an assigned timeout) 18598 */ 18599 JustifiedGallery.prototype.stopImgAnalyzerStarter = function () { 18600 this.yield.flushed = 0; 18601 if (this.imgAnalyzerTimeout !== null) clearTimeout(this.imgAnalyzerTimeout); 18602 }; 18603 18604 /** 18605 * Starts the image analyzer. It is not immediately called to let the browser to update the view 18606 * 18607 * @param isForResize specifies if the image analyzer must be called for resizing or not 18608 */ 18609 JustifiedGallery.prototype.startImgAnalyzer = function (isForResize) { 18610 var that = this; 18611 this.stopImgAnalyzerStarter(); 18612 this.imgAnalyzerTimeout = setTimeout(function () { 18613 that.analyzeImages(isForResize); 18614 }, 0.001); // we can't start it immediately due to a IE different behaviour 18615 }; 18616 18617 /** 18618 * Checks if the image is loaded or not using another image object. We cannot use the 'complete' image property, 18619 * because some browsers, with a 404 set complete = true. 18620 * 18621 * @param imageSrc the image src to load 18622 * @param onLoad callback that is called when the image has been loaded
vendor: 13,320 bytes, lines 18623-18973
18623 * @param onError callback that is called in case of an error 18624 */ 18625 JustifiedGallery.prototype.onImageEvent = function (imageSrc, onLoad, onError) { 18626 if (!onLoad && !onError) return; 18627 18628 var memImage = new Image(); 18629 var $memImage = $(memImage); 18630 if (onLoad) { 18631 $memImage.one('load', function () { 18632 $memImage.off('load error'); 18633 onLoad(memImage); 18634 }); 18635 } 18636 if (onError) { 18637 $memImage.one('error', function() { 18638 $memImage.off('load error'); 18639 onError(memImage); 18640 }); 18641 } 18642 memImage.src = imageSrc; 18643 }; 18644 18645 /** 18646 * Init of Justified Gallery controlled 18647 * It analyzes all the entries starting theirs loading and calling the image analyzer (that works with loaded images) 18648 */ 18649 JustifiedGallery.prototype.init = function () { 18650 var imagesToLoad = false, skippedImages = false, that = this; 18651 $.each(this.entries, function (index, entry) { 18652 var $entry = $(entry); 18653 var $image = that.imgFromEntry($entry); 18654 18655 $entry.addClass('jg-entry'); 18656 18657 if ($entry.data('jg.loaded') !== true && $entry.data('jg.loaded') !== 'skipped') { 18658 18659 // Link Rel global overwrite 18660 if (that.settings.rel !== null) $entry.attr('rel', that.settings.rel); 18661 18662 // Link Target global overwrite 18663 if (that.settings.target !== null) $entry.attr('target', that.settings.target); 18664 18665 if ($image !== null) { 18666 18667 // Image src 18668 var imageSrc = that.extractImgSrcFromImage($image); 18669 $image.attr('src', imageSrc); 18670 18671 /* If we have the height and the width, we don't wait that the image is loaded, but we start directly 18672 * with the justification */ 18673 if (that.settings.waitThumbnailsLoad === false) { 18674 var width = parseFloat($image.attr('width')); 18675 var height = parseFloat($image.attr('height')); 18676 if (!isNaN(width) && !isNaN(height)) { 18677 $entry.data('jg.width', width); 18678 $entry.data('jg.height', height); 18679 $entry.data('jg.loaded', 'skipped'); 18680 skippedImages = true; 18681 that.startImgAnalyzer(false); 18682 return true; // continue 18683 } 18684 } 18685 18686 $entry.data('jg.loaded', false); 18687 imagesToLoad = true; 18688 18689 // Spinner start 18690 if (!that.isSpinnerActive()) that.startLoadingSpinnerAnimation(); 18691 18692 that.onImageEvent(imageSrc, function (loadImg) { // image loaded 18693 $entry.data('jg.width', loadImg.width); 18694 $entry.data('jg.height', loadImg.height); 18695 $entry.data('jg.loaded', true); 18696 that.startImgAnalyzer(false); 18697 }, function () { // image load error 18698 $entry.data('jg.loaded', 'error'); 18699 that.startImgAnalyzer(false); 18700 }); 18701 18702 } else { 18703 $entry.data('jg.loaded', true); 18704 $entry.data('jg.width', $entry.width() | parseFloat($entry.css('width')) | 1); 18705 $entry.data('jg.height', $entry.height() | parseFloat($entry.css('height')) | 1); 18706 } 18707 18708 } 18709 18710 }); 18711 18712 if (!imagesToLoad && !skippedImages) this.startImgAnalyzer(false); 18713 this.checkWidth(); 18714 }; 18715 18716 /** 18717 * Checks that it is a valid number. If a string is passed it is converted to a number 18718 * 18719 * @param settingContainer the object that contains the setting (to allow the conversion) 18720 * @param settingName the setting name 18721 */ 18722 JustifiedGallery.prototype.checkOrConvertNumber = function (settingContainer, settingName) { 18723 if ($.type(settingContainer[settingName]) === 'string') { 18724 settingContainer[settingName] = parseFloat(settingContainer[settingName]); 18725 } 18726 18727 if ($.type(settingContainer[settingName]) === 'number') { 18728 if (isNaN(settingContainer[settingName])) throw 'invalid number for ' + settingName; 18729 } else { 18730 throw settingName + ' must be a number'; 18731 } 18732 }; 18733 18734 /** 18735 * Checks the sizeRangeSuffixes and, if necessary, converts 18736 * its keys from string (e.g. old settings with 'lt100') to int. 18737 */ 18738 JustifiedGallery.prototype.checkSizeRangesSuffixes = function () { 18739 if ($.type(this.settings.sizeRangeSuffixes) !== 'object') { 18740 throw 'sizeRangeSuffixes must be defined and must be an object'; 18741 } 18742 18743 var suffixRanges = []; 18744 for (var rangeIdx in this.settings.sizeRangeSuffixes) { 18745 if (this.settings.sizeRangeSuffixes.hasOwnProperty(rangeIdx)) suffixRanges.push(rangeIdx); 18746 } 18747 18748 var newSizeRngSuffixes = {0: ''}; 18749 for (var i = 0; i < suffixRanges.length; i++) { 18750 if ($.type(suffixRanges[i]) === 'string') { 18751 try { 18752 var numIdx = parseInt(suffixRanges[i].replace(/^[a-z]+/, ''), 10); 18753 newSizeRngSuffixes[numIdx] = this.settings.sizeRangeSuffixes[suffixRanges[i]]; 18754 } catch (e) { 18755 throw 'sizeRangeSuffixes keys must contains correct numbers (' + e + ')'; 18756 } 18757 } else { 18758 newSizeRngSuffixes[suffixRanges[i]] = this.settings.sizeRangeSuffixes[suffixRanges[i]]; 18759 } 18760 } 18761 18762 this.settings.sizeRangeSuffixes = newSizeRngSuffixes; 18763 }; 18764 18765 /** 18766 * check and convert the maxRowHeight setting 18767 */ 18768 JustifiedGallery.prototype.retrieveMaxRowHeight = function () { 18769 var newMaxRowHeight = { }; 18770 18771 if ($.type(this.settings.maxRowHeight) === 'string') { 18772 if (this.settings.maxRowHeight.match(/^[0-9]+%$/)) { 18773 newMaxRowHeight.value = parseFloat(this.settings.maxRowHeight.match(/^([0-9]+)%$/)[1]) / 100; 18774 newMaxRowHeight.isPercentage = false; 18775 } else { 18776 newMaxRowHeight.value = parseFloat(this.settings.maxRowHeight); 18777 newMaxRowHeight.isPercentage = true; 18778 } 18779 } else if ($.type(this.settings.maxRowHeight) === 'number') { 18780 newMaxRowHeight.value = this.settings.maxRowHeight; 18781 newMaxRowHeight.isPercentage = false; 18782 } else if (this.settings.maxRowHeight === false || 18783 this.settings.maxRowHeight === null || 18784 typeof this.settings.maxRowHeight == 'undefined') { 18785 return null; 18786 } else { 18787 throw 'maxRowHeight must be a number or a percentage'; 18788 } 18789 18790 // check if the converted value is not a number 18791 if (isNaN(newMaxRowHeight.value)) throw 'invalid number for maxRowHeight'; 18792 18793 // check values 18794 if (newMaxRowHeight.isPercentage) { 18795 if (newMaxRowHeight.value < 100) newMaxRowHeight.value = 100; 18796 } 18797 18798 return newMaxRowHeight; 18799 }; 18800 18801 /** 18802 * Checks the settings 18803 */ 18804 JustifiedGallery.prototype.checkSettings = function () { 18805 this.checkSizeRangesSuffixes(); 18806 18807 this.checkOrConvertNumber(this.settings, 'rowHeight'); 18808 this.checkOrConvertNumber(this.settings, 'margins'); 18809 this.checkOrConvertNumber(this.settings, 'border'); 18810 18811 var lastRowModes = [ 18812 'justify', 18813 'nojustify', 18814 'left', 18815 'center', 18816 'right', 18817 'hide' 18818 ]; 18819 if (lastRowModes.indexOf(this.settings.lastRow) === -1) { 18820 throw 'lastRow must be one of: ' + lastRowModes.join(', '); 18821 } 18822 18823 this.checkOrConvertNumber(this.settings, 'justifyThreshold'); 18824 if (this.settings.justifyThreshold < 0 || this.settings.justifyThreshold > 1) { 18825 throw 'justifyThreshold must be in the interval [0,1]'; 18826 } 18827 if ($.type(this.settings.cssAnimation) !== 'boolean') { 18828 throw 'cssAnimation must be a boolean'; 18829 } 18830 18831 if ($.type(this.settings.captions) !== 'boolean') throw 'captions must be a boolean'; 18832 this.checkOrConvertNumber(this.settings.captionSettings, 'animationDuration'); 18833 18834 this.checkOrConvertNumber(this.settings.captionSettings, 'visibleOpacity'); 18835 if (this.settings.captionSettings.visibleOpacity < 0 || 18836 this.settings.captionSettings.visibleOpacity > 1) { 18837 throw 'captionSettings.visibleOpacity must be in the interval [0, 1]'; 18838 } 18839 18840 this.checkOrConvertNumber(this.settings.captionSettings, 'nonVisibleOpacity'); 18841 if (this.settings.captionSettings.nonVisibleOpacity < 0 || 18842 this.settings.captionSettings.nonVisibleOpacity > 1) { 18843 throw 'captionSettings.nonVisibleOpacity must be in the interval [0, 1]'; 18844 } 18845 18846 this.checkOrConvertNumber(this.settings, 'imagesAnimationDuration'); 18847 this.checkOrConvertNumber(this.settings, 'refreshTime'); 18848 this.checkOrConvertNumber(this.settings, 'refreshSensitivity'); 18849 if ($.type(this.settings.randomize) !== 'boolean') throw 'randomize must be a boolean'; 18850 if ($.type(this.settings.selector) !== 'string') throw 'selector must be a string'; 18851 18852 if (this.settings.sort !== false && !$.isFunction(this.settings.sort)) { 18853 throw 'sort must be false or a comparison function'; 18854 } 18855 18856 if (this.settings.filter !== false && !$.isFunction(this.settings.filter) && 18857 $.type(this.settings.filter) !== 'string') { 18858 throw 'filter must be false, a string or a filter function'; 18859 } 18860 }; 18861 18862 /** 18863 * It brings all the indexes from the sizeRangeSuffixes and it orders them. They are then sorted and returned. 18864 * @returns {Array} sorted suffix ranges 18865 */ 18866 JustifiedGallery.prototype.retrieveSuffixRanges = function () { 18867 var suffixRanges = []; 18868 for (var rangeIdx in this.settings.sizeRangeSuffixes) { 18869 if (this.settings.sizeRangeSuffixes.hasOwnProperty(rangeIdx)) suffixRanges.push(parseInt(rangeIdx, 10)); 18870 } 18871 suffixRanges.sort(function (a, b) { return a > b ? 1 : a < b ? -1 : 0; }); 18872 return suffixRanges; 18873 }; 18874 18875 /** 18876 * Update the existing settings only changing some of them 18877 * 18878 * @param newSettings the new settings (or a subgroup of them) 18879 */ 18880 JustifiedGallery.prototype.updateSettings = function (newSettings) { 18881 // In this case Justified Gallery has been called again changing only some options 18882 this.settings = $.extend({}, this.settings, newSettings); 18883 this.checkSettings(); 18884 18885 // As reported in the settings: negative value = same as margins, 0 = disabled 18886 this.border = this.settings.border >= 0 ? this.settings.border : this.settings.margins; 18887 18888 this.maxRowHeight = this.retrieveMaxRowHeight(); 18889 this.suffixRanges = this.retrieveSuffixRanges(); 18890 }; 18891 18892 /** 18893 * Justified Gallery plugin for jQuery 18894 * 18895 * Events 18896 * - jg.complete : called when all the gallery has been created 18897 * - jg.resize : called when the gallery has been resized 18898 * - jg.rowflush : when a new row appears 18899 * 18900 * @param arg the action (or the settings) passed when the plugin is called 18901 * @returns {*} the object itself 18902 */ 18903 $.fn.justifiedGallery = function (arg) { 18904 return this.each(function (index, gallery) { 18905 18906 var $gallery = $(gallery); 18907 $gallery.addClass('justified-gallery'); 18908 18909 var controller = $gallery.data('jg.controller'); 18910 if (typeof controller === 'undefined') { 18911 // Create controller and assign it to the object data 18912 if (typeof arg !== 'undefined' && arg !== null && $.type(arg) !== 'object') { 18913 if (arg === 'destroy') return; // Just a call to an unexisting object 18914 throw 'The argument must be an object'; 18915 } 18916 controller = new JustifiedGallery($gallery, $.extend({}, $.fn.justifiedGallery.defaults, arg)); 18917 $gallery.data('jg.controller', controller); 18918 } else if (arg === 'norewind') { 18919 // In this case we don't rewind: we analyze only the latest images (e.g. to complete the last unfinished row 18920 // ... left to be more readable 18921 } else if (arg === 'destroy') { 18922 controller.destroy(); 18923 return; 18924 } else { 18925 // In this case Justified Gallery has been called again changing only some options 18926 controller.updateSettings(arg); 18927 controller.rewind(); 18928 } 18929 18930 // Update the entries list 18931 if (!controller.updateEntries(arg === 'norewind')) return; 18932 18933 // Init justified gallery 18934 controller.init(); 18935 18936 }); 18937 }; 18938 18939 // Default options 18940 $.fn.justifiedGallery.defaults = { 18941 sizeRangeSuffixes: { }, /* e.g. Flickr configuration 18942 { 18943 100: '_t', // used when longest is less than 100px 18944 240: '_m', // used when longest is between 101px and 240px 18945 320: '_n', // ... 18946 500: '', 18947 640: '_z', 18948 1024: '_b' // used as else case because it is the last 18949 } 18950 */ 18951 thumbnailPath: undefined, /* If defined, sizeRangeSuffixes is not used, and this function is used to determine the 18952 path relative to a specific thumbnail size. The function should accept respectively three arguments: 18953 current path, width and height */ 18954 rowHeight: 120, 18955 maxRowHeight: false, // false or negative value to deactivate. Positive number to express the value in pixels, 18956 // A string '[0-9]+%' to express in percentage (e.g. 300% means that the row height 18957 // can't exceed 3 * rowHeight) 18958 margins: 1, 18959 border: -1, // negative value = same as margins, 0 = disabled, any other value to set the border 18960 18961 lastRow: 'nojustify', // … which is the same as 'left', or can be 'justify', 'center', 'right' or 'hide' 18962 18963 justifyThreshold: 0.90, /* if row width / available space > 0.90 it will be always justified 18964 * (i.e. lastRow setting is not considered) */ 18965 waitThumbnailsLoad: true, 18966 captions: true, 18967 cssAnimation: true, 18968 imagesAnimationDuration: 500, // ignored with css animations 18969 captionSettings: { // ignored with css animations 18970 animationDuration: 500, 18971 visibleOpacity: 0.7, 18972 nonVisibleOpacity: 0.0 18973 },
vendor: 5,759 bytes, lines 18974-19116
18974 rel: null, // rewrite the rel of each analyzed links 18975 target: null, // rewrite the target of all links 18976 extension: /\.[^.\\/]+$/, // regexp to capture the extension of an image 18977 refreshTime: 200, // time interval (in ms) to check if the page changes its width 18978 refreshSensitivity: 0, // change in width allowed (in px) without re-building the gallery 18979 randomize: false, 18980 sort: false, /* 18981 - false: to do not sort 18982 - function: to sort them using the function as comparator (see Array.prototype.sort()) 18983 */ 18984 filter: false, /* 18985 - false, null or undefined: for a disabled filter 18986 - a string: an entry is kept if entry.is(filter string) returns true 18987 see jQuery's .is() function for further information 18988 - a function: invoked with arguments (entry, index, array). Return true to keep the entry, false otherwise. 18989 It follows the specifications of the Array.prototype.filter() function of JavaScript. 18990 */ 18991 selector: 'a, div:not(.spinner)' // The selector that is used to know what are the entries of the gallery 18992 }; 18993 18994}(jQuery)); 18995/*! 18996* Customized version of iScroll.js 0.0.1 18997* It fixes bugs affecting its integration with fullpage.js 18998*/ 18999/*! iScroll v5.2.0 ~ (c) 2008-2016 Matteo Spinelli ~ http://cubiq.org/license */ 19000(function (window, document, Math) { 19001var rAF = window.requestAnimationFrame || 19002 window.webkitRequestAnimationFrame || 19003 window.mozRequestAnimationFrame || 19004 window.oRequestAnimationFrame || 19005 window.msRequestAnimationFrame || 19006 function (callback) { window.setTimeout(callback, 1000 / 60); }; 19007 19008var utils = (function () { 19009 var me = {}; 19010 19011 var _elementStyle = document.createElement('div').style; 19012 var _vendor = (function () { 19013 var vendors = ['t', 'webkitT', 'MozT', 'msT', 'OT'], 19014 transform, 19015 i = 0, 19016 l = vendors.length; 19017 19018 for ( ; i < l; i++ ) { 19019 transform = vendors[i] + 'ransform'; 19020 if ( transform in _elementStyle ) return vendors[i].substr(0, vendors[i].length-1); 19021 } 19022 19023 return false; 19024 })(); 19025 19026 function _prefixStyle (style) { 19027 if ( _vendor === false ) return false; 19028 if ( _vendor === '' ) return style; 19029 return _vendor + style.charAt(0).toUpperCase() + style.substr(1); 19030 } 19031 19032 me.getTime = Date.now || function getTime () { return new Date().getTime(); }; 19033 19034 me.extend = function (target, obj) { 19035 for ( var i in obj ) { 19036 target[i] = obj[i]; 19037 } 19038 }; 19039 19040 me.addEvent = function (el, type, fn, capture) { 19041 el.addEventListener(type, fn, !!capture); 19042 }; 19043 19044 me.removeEvent = function (el, type, fn, capture) { 19045 el.removeEventListener(type, fn, !!capture); 19046 }; 19047 19048 me.prefixPointerEvent = function (pointerEvent) { 19049 return window.MSPointerEvent ? 19050 'MSPointer' + pointerEvent.charAt(7).toUpperCase() + pointerEvent.substr(8): 19051 pointerEvent; 19052 }; 19053 19054 me.momentum = function (current, start, time, lowerMargin, wrapperSize, deceleration) { 19055 var distance = current - start, 19056 speed = Math.abs(distance) / time, 19057 destination, 19058 duration; 19059 19060 deceleration = deceleration === undefined ? 0.0006 : deceleration; 19061 19062 destination = current + ( speed * speed ) / ( 2 * deceleration ) * ( distance < 0 ? -1 : 1 ); 19063 duration = speed / deceleration; 19064 19065 if ( destination < lowerMargin ) { 19066 destination = wrapperSize ? lowerMargin - ( wrapperSize / 2.5 * ( speed / 8 ) ) : lowerMargin; 19067 distance = Math.abs(destination - current); 19068 duration = distance / speed; 19069 } else if ( destination > 0 ) { 19070 destination = wrapperSize ? wrapperSize / 2.5 * ( speed / 8 ) : 0; 19071 distance = Math.abs(current) + destination; 19072 duration = distance / speed; 19073 } 19074 19075 return { 19076 destination: Math.round(destination), 19077 duration: duration 19078 }; 19079 }; 19080 19081 var _transform = _prefixStyle('transform'); 19082 19083 me.extend(me, { 19084 hasTransform: _transform !== false, 19085 hasPerspective: _prefixStyle('perspective') in _elementStyle, 19086 hasTouch: 'ontouchstart' in window, 19087 hasPointer: !!(window.PointerEvent || window.MSPointerEvent), // IE10 is prefixed 19088 hasTransition: _prefixStyle('transition') in _elementStyle 19089 }); 19090 19091 /* 19092 This should find all Android browsers lower than build 535.19 (both stock browser and webview) 19093 - galaxy S2 is ok 19094 - 2.3.6 : `AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1` 19095 - 4.0.4 : `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30` 19096 - galaxy S3 is badAndroid (stock brower, webview) 19097 `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30` 19098 - galaxy S4 is badAndroid (stock brower, webview) 19099 `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30` 19100 - galaxy S5 is OK 19101 `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)` 19102 - galaxy S6 is OK 19103 `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)` 19104 */ 19105 me.isBadAndroid = (function() { 19106 var appVersion = window.navigator.appVersion; 19107 // Android browser is not a chrome browser. 19108 if (/Android/.test(appVersion) && !(/Chrome\/\d/.test(appVersion))) { 19109 var safariVersion = appVersion.match(/Safari\/(\d+.\d)/); 19110 if(safariVersion && typeof safariVersion === "object" && safariVersion.length >= 2) { 19111 return parseFloat(safariVersion[1]) < 535.19; 19112 } else { 19113 return true; 19114 } 19115 } else { 19116 return false;
vendor: 5,536 bytes, lines 19117-19309
19117 } 19118 })(); 19119 19120 me.extend(me.style = {}, { 19121 transform: _transform, 19122 transitionTimingFunction: _prefixStyle('transitionTimingFunction'), 19123 transitionDuration: _prefixStyle('transitionDuration'), 19124 transitionDelay: _prefixStyle('transitionDelay'), 19125 transformOrigin: _prefixStyle('transformOrigin') 19126 }); 19127 19128 me.hasClass = function (e, c) { 19129 var re = new RegExp("(^|\\s)" + c + "(\\s|$)"); 19130 return re.test(e.className); 19131 }; 19132 19133 me.addClass = function (e, c) { 19134 if ( me.hasClass(e, c) ) { 19135 return; 19136 } 19137 19138 var newclass = e.className.split(' '); 19139 newclass.push(c); 19140 e.className = newclass.join(' '); 19141 }; 19142 19143 me.removeClass = function (e, c) { 19144 if ( !me.hasClass(e, c) ) { 19145 return; 19146 } 19147 19148 var re = new RegExp("(^|\\s)" + c + "(\\s|$)", 'g'); 19149 e.className = e.className.replace(re, ' '); 19150 }; 19151 19152 me.offset = function (el) { 19153 var left = -el.offsetLeft, 19154 top = -el.offsetTop; 19155 19156 // jshint -W084 19157 while (el = el.offsetParent) { 19158 left -= el.offsetLeft; 19159 top -= el.offsetTop; 19160 } 19161 // jshint +W084 19162 19163 return { 19164 left: left, 19165 top: top 19166 }; 19167 }; 19168 19169 me.preventDefaultException = function (el, exceptions) { 19170 for ( var i in exceptions ) { 19171 if ( exceptions[i].test(el[i]) ) { 19172 return true; 19173 } 19174 } 19175 19176 return false; 19177 }; 19178 19179 me.extend(me.eventType = {}, { 19180 touchstart: 1, 19181 touchmove: 1, 19182 touchend: 1, 19183 19184 mousedown: 2, 19185 mousemove: 2, 19186 mouseup: 2, 19187 19188 pointerdown: 3, 19189 pointermove: 3, 19190 pointerup: 3, 19191 19192 MSPointerDown: 3, 19193 MSPointerMove: 3, 19194 MSPointerUp: 3 19195 }); 19196 19197 me.extend(me.ease = {}, { 19198 quadratic: { 19199 style: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)', 19200 fn: function (k) { 19201 return k * ( 2 - k ); 19202 } 19203 }, 19204 circular: { 19205 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) 19206 fn: function (k) { 19207 return Math.sqrt( 1 - ( --k * k ) ); 19208 } 19209 }, 19210 back: { 19211 style: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)', 19212 fn: function (k) { 19213 var b = 4; 19214 return ( k = k - 1 ) * k * ( ( b + 1 ) * k + b ) + 1; 19215 } 19216 }, 19217 bounce: { 19218 style: '', 19219 fn: function (k) { 19220 if ( ( k /= 1 ) < ( 1 / 2.75 ) ) { 19221 return 7.5625 * k * k; 19222 } else if ( k < ( 2 / 2.75 ) ) { 19223 return 7.5625 * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75; 19224 } else if ( k < ( 2.5 / 2.75 ) ) { 19225 return 7.5625 * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375; 19226 } else { 19227 return 7.5625 * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375; 19228 } 19229 } 19230 }, 19231 elastic: { 19232 style: '', 19233 fn: function (k) { 19234 var f = 0.22, 19235 e = 0.4; 19236 19237 if ( k === 0 ) { return 0; } 19238 if ( k == 1 ) { return 1; } 19239 19240 return ( e * Math.pow( 2, - 10 * k ) * Math.sin( ( k - f / 4 ) * ( 2 * Math.PI ) / f ) + 1 ); 19241 } 19242 } 19243 }); 19244 19245 me.tap = function (e, eventName) { 19246 var ev = document.createEvent('Event'); 19247 ev.initEvent(eventName, true, true); 19248 ev.pageX = e.pageX; 19249 ev.pageY = e.pageY; 19250 e.target.dispatchEvent(ev); 19251 }; 19252 19253 me.click = function (e) { 19254 var target = e.target, 19255 ev; 19256 19257 if ( !(/(SELECT|INPUT|TEXTAREA)/i).test(target.tagName) ) { 19258 // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/initMouseEvent 19259 // initMouseEvent is deprecated. 19260 ev = document.createEvent(window.MouseEvent ? 'MouseEvents' : 'Event'); 19261 ev.initEvent('click', true, true); 19262 ev.view = e.view || window; 19263 ev.detail = 1; 19264 ev.screenX = target.screenX || 0; 19265 ev.screenY = target.screenY || 0; 19266 ev.clientX = target.clientX || 0; 19267 ev.clientY = target.clientY || 0; 19268 ev.ctrlKey = !!e.ctrlKey; 19269 ev.altKey = !!e.altKey; 19270 ev.shiftKey = !!e.shiftKey; 19271 ev.metaKey = !!e.metaKey; 19272 ev.button = 0; 19273 ev.relatedTarget = null; 19274 ev._constructed = true; 19275 target.dispatchEvent(ev); 19276 } 19277 }; 19278 19279 return me; 19280})(); 19281function IScroll (el, options) { 19282 this.wrapper = typeof el == 'string' ? document.querySelector(el) : el; 19283 this.scroller = this.wrapper.children[0]; 19284 this.scrollerStyle = this.scroller.style; // cache style for better performance 19285 19286 this.options = { 19287 19288 resizeScrollbars: true, 19289 19290 mouseWheelSpeed: 20, 19291 19292 snapThreshold: 0.334, 19293 19294// INSERT POINT: OPTIONS 19295 disablePointer : !utils.hasPointer, 19296 disableTouch : utils.hasPointer || !utils.hasTouch, 19297 disableMouse : utils.hasPointer || utils.hasTouch, 19298 startX: 0, 19299 startY: 0, 19300 scrollY: true, 19301 directionLockThreshold: 5, 19302 momentum: true, 19303 19304 bounce: true, 19305 bounceTime: 600, 19306 bounceEasing: '', 19307 19308 preventDefault: true, 19309 preventDefaultException: { tagName: /^(INPUT|TEXTAREA|BUTTON|
vendor: 4,420 bytes, lines 19309-19453
19309SELECT|LABEL)$/ }, 19310 19311 HWCompositing: true, 19312 useTransition: true, 19313 useTransform: true, 19314 bindToWrapper: typeof window.onmousedown === "undefined" 19315 }; 19316 19317 for ( var i in options ) { 19318 this.options[i] = options[i]; 19319 } 19320 19321 // Normalize options 19322 this.translateZ = this.options.HWCompositing && utils.hasPerspective ? ' translateZ(0)' : ''; 19323 19324 this.options.useTransition = utils.hasTransition && this.options.useTransition; 19325 this.options.useTransform = utils.hasTransform && this.options.useTransform; 19326 19327 this.options.eventPassthrough = this.options.eventPassthrough === true ? 'vertical' : this.options.eventPassthrough; 19328 this.options.preventDefault = !this.options.eventPassthrough && this.options.preventDefault; 19329 19330 // If you want eventPassthrough I have to lock one of the axes 19331 this.options.scrollY = this.options.eventPassthrough == 'vertical' ? false : this.options.scrollY; 19332 this.options.scrollX = this.options.eventPassthrough == 'horizontal' ? false : this.options.scrollX; 19333 19334 // With eventPassthrough we also need lockDirection mechanism 19335 this.options.freeScroll = this.options.freeScroll && !this.options.eventPassthrough; 19336 this.options.directionLockThreshold = this.options.eventPassthrough ? 0 : this.options.directionLockThreshold; 19337 19338 this.options.bounceEasing = typeof this.options.bounceEasing == 'string' ? utils.ease[this.options.bounceEasing] || utils.ease.circular : this.options.bounceEasing; 19339 19340 this.options.resizePolling = this.options.resizePolling === undefined ? 60 : this.options.resizePolling; 19341 19342 if ( this.options.tap === true ) { 19343 this.options.tap = 'tap'; 19344 } 19345 19346 // https://github.com/cubiq/iscroll/issues/1029 19347 if (!this.options.useTransition && !this.options.useTransform) { 19348 if(!(/relative|absolute/i).test(this.scrollerStyle.position)) { 19349 this.scrollerStyle.position = "relative"; 19350 } 19351 } 19352 19353 if ( this.options.shrinkScrollbars == 'scale' ) { 19354 this.options.useTransition = false; 19355 } 19356 19357 this.options.invertWheelDirection = this.options.invertWheelDirection ? -1 : 1; 19358 19359// INSERT POINT: NORMALIZATION 19360 19361 // Some defaults 19362 this.x = 0; 19363 this.y = 0; 19364 this.directionX = 0; 19365 this.directionY = 0; 19366 this._events = {}; 19367 19368// INSERT POINT: DEFAULTS 19369 19370 this._init(); 19371 this.refresh(); 19372 19373 this.scrollTo(this.options.startX, this.options.startY); 19374 this.enable(); 19375} 19376 19377IScroll.prototype = { 19378 version: '5.2.0', 19379 19380 _init: function () { 19381 this._initEvents(); 19382 19383 if ( this.options.scrollbars || this.options.indicators ) { 19384 this._initIndicators(); 19385 } 19386 19387 if ( this.options.mouseWheel ) { 19388 this._initWheel(); 19389 } 19390 19391 if ( this.options.snap ) { 19392 this._initSnap(); 19393 } 19394 19395 if ( this.options.keyBindings ) { 19396 this._initKeys(); 19397 } 19398 19399// INSERT POINT: _init 19400 19401 }, 19402 19403 destroy: function () { 19404 this._initEvents(true); 19405 clearTimeout(this.resizeTimeout); 19406 this.resizeTimeout = null; 19407 this._execEvent('destroy'); 19408 }, 19409 19410 _transitionEnd: function (e) { 19411 if ( e.target != this.scroller || !this.isInTransition ) { 19412 return; 19413 } 19414 19415 this._transitionTime(); 19416 if ( !this.resetPosition(this.options.bounceTime) ) { 19417 this.isInTransition = false; 19418 this._execEvent('scrollEnd'); 19419 } 19420 }, 19421 19422 _start: function (e) { 19423 // React to left mouse button only 19424 if ( utils.eventType[e.type] != 1 ) { 19425 // for button property 19426 // http://unixpapa.com/js/mouse.html 19427 var button; 19428 if (!e.which) { 19429 /* IE case */ 19430 button = (e.button < 2) ? 0 : 19431 ((e.button == 4) ? 1 : 2); 19432 } else { 19433 /* All others */ 19434 button = e.button; 19435 } 19436 if ( button !== 0 ) { 19437 return; 19438 } 19439 } 19440 19441 if ( !this.enabled || (this.initiated && utils.eventType[e.type] !== this.initiated) ) { 19442 return; 19443 } 19444 19445 if ( this.options.preventDefault && !utils.isBadAndroid && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) { 19446 e.preventDefault(); 19447 } 19448 19449 var point = e.touches ? e.touches[0] : e, 19450 pos; 19451 19452 this.initiated = utils.eventType[e.type]; 19453 this.moved = false;
vendor: 5,928 bytes, lines 19454-19632
19454 this.distX = 0; 19455 this.distY = 0; 19456 this.directionX = 0; 19457 this.directionY = 0; 19458 this.directionLocked = 0; 19459 19460 this.startTime = utils.getTime(); 19461 19462 if ( this.options.useTransition && this.isInTransition ) { 19463 this._transitionTime(); 19464 this.isInTransition = false; 19465 pos = this.getComputedPosition(); 19466 this._translate(Math.round(pos.x), Math.round(pos.y)); 19467 this._execEvent('scrollEnd'); 19468 } else if ( !this.options.useTransition && this.isAnimating ) { 19469 this.isAnimating = false; 19470 this._execEvent('scrollEnd'); 19471 } 19472 19473 this.startX = this.x; 19474 this.startY = this.y; 19475 this.absStartX = this.x; 19476 this.absStartY = this.y; 19477 this.pointX = point.pageX; 19478 this.pointY = point.pageY; 19479 19480 this._execEvent('beforeScrollStart'); 19481 }, 19482 19483 _move: function (e) { 19484 if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) { 19485 return; 19486 } 19487 19488 if ( this.options.preventDefault ) { // increases performance on Android? TODO: check! 19489 e.preventDefault(); 19490 } 19491 19492 var point = e.touches ? e.touches[0] : e, 19493 deltaX = point.pageX - this.pointX, 19494 deltaY = point.pageY - this.pointY, 19495 timestamp = utils.getTime(), 19496 newX, newY, 19497 absDistX, absDistY; 19498 19499 this.pointX = point.pageX; 19500 this.pointY = point.pageY; 19501 19502 this.distX += deltaX; 19503 this.distY += deltaY; 19504 absDistX = Math.abs(this.distX); 19505 absDistY = Math.abs(this.distY); 19506 19507 // We need to move at least 10 pixels for the scrolling to initiate 19508 if ( timestamp - this.endTime > 300 && (absDistX < 10 && absDistY < 10) ) { 19509 return; 19510 } 19511 19512 // If you are scrolling in one direction lock the other 19513 if ( !this.directionLocked && !this.options.freeScroll ) { 19514 if ( absDistX > absDistY + this.options.directionLockThreshold ) { 19515 this.directionLocked = 'h'; // lock horizontally 19516 } else if ( absDistY >= absDistX + this.options.directionLockThreshold ) { 19517 this.directionLocked = 'v'; // lock vertically 19518 } else { 19519 this.directionLocked = 'n'; // no lock 19520 } 19521 } 19522 19523 if ( this.directionLocked == 'h' ) { 19524 if ( this.options.eventPassthrough == 'vertical' ) { 19525 e.preventDefault(); 19526 } else if ( this.options.eventPassthrough == 'horizontal' ) { 19527 this.initiated = false; 19528 return; 19529 } 19530 19531 deltaY = 0; 19532 } else if ( this.directionLocked == 'v' ) { 19533 if ( this.options.eventPassthrough == 'horizontal' ) { 19534 e.preventDefault(); 19535 } else if ( this.options.eventPassthrough == 'vertical' ) { 19536 this.initiated = false; 19537 return; 19538 } 19539 19540 deltaX = 0; 19541 } 19542 19543 deltaX = this.hasHorizontalScroll ? deltaX : 0; 19544 deltaY = this.hasVerticalScroll ? deltaY : 0; 19545 19546 newX = this.x + deltaX; 19547 newY = this.y + deltaY; 19548 19549 // Slow down if outside of the boundaries 19550 if ( newX > 0 || newX < this.maxScrollX ) { 19551 newX = this.options.bounce ? this.x + deltaX / 3 : newX > 0 ? 0 : this.maxScrollX; 19552 } 19553 if ( newY > 0 || newY < this.maxScrollY ) { 19554 newY = this.options.bounce ? this.y + deltaY / 3 : newY > 0 ? 0 : this.maxScrollY; 19555 } 19556 19557 this.directionX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0; 19558 this.directionY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0; 19559 19560 if ( !this.moved ) { 19561 this._execEvent('scrollStart'); 19562 } 19563 19564 this.moved = true; 19565 19566 this._translate(newX, newY); 19567 19568/* REPLACE START: _move */ 19569 19570 if ( timestamp - this.startTime > 300 ) { 19571 this.startTime = timestamp; 19572 this.startX = this.x; 19573 this.startY = this.y; 19574 } 19575 19576/* REPLACE END: _move */ 19577 19578 }, 19579 19580 _end: function (e) { 19581 if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) { 19582 return; 19583 } 19584 19585 if ( this.options.preventDefault && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) { 19586 e.preventDefault(); 19587 } 19588 19589 var point = e.changedTouches ? e.changedTouches[0] : e, 19590 momentumX, 19591 momentumY, 19592 duration = utils.getTime() - this.startTime, 19593 newX = Math.round(this.x), 19594 newY = Math.round(this.y), 19595 distanceX = Math.abs(newX - this.startX), 19596 distanceY = Math.abs(newY - this.startY), 19597 time = 0, 19598 easing = ''; 19599 19600 this.isInTransition = 0; 19601 this.initiated = 0; 19602 this.endTime = utils.getTime(); 19603 19604 // reset if we are outside of the boundaries 19605 if ( this.resetPosition(this.options.bounceTime) ) { 19606 return; 19607 } 19608 19609 this.scrollTo(newX, newY); // ensures that the last position is rounded 19610 19611 // we scrolled less than 10 pixels 19612 if ( !this.moved ) { 19613 if ( this.options.tap ) { 19614 utils.tap(e, this.options.tap); 19615 } 19616 19617 if ( this.options.click ) { 19618 utils.click(e); 19619 } 19620 19621 this._execEvent('scrollCancel'); 19622 return; 19623 } 19624 19625 if ( this._events.flick && duration < 200 && distanceX < 100 && distanceY < 100 ) { 19626 this._execEvent('flick'); 19627 return; 19628 } 19629 19630 // start momentum animation if needed 19631 if ( this.options.momentum && duration < 300 ) { 19632 momentumX = this.hasHorizontalScroll ? utils.momentum(this.x, this.startX, duration, this.maxScrollX, this.options.bounce ? this.wrapperW
vendor: 7,740 bytes, lines 19632-19905
19632idth : 0, this.options.deceleration) : { destination: newX, duration: 0 }; 19633 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 }; 19634 newX = momentumX.destination; 19635 newY = momentumY.destination; 19636 time = Math.max(momentumX.duration, momentumY.duration); 19637 this.isInTransition = 1; 19638 } 19639 19640 19641 if ( this.options.snap ) { 19642 var snap = this._nearestSnap(newX, newY); 19643 this.currentPage = snap; 19644 time = this.options.snapSpeed || Math.max( 19645 Math.max( 19646 Math.min(Math.abs(newX - snap.x), 1000), 19647 Math.min(Math.abs(newY - snap.y), 1000) 19648 ), 300); 19649 newX = snap.x; 19650 newY = snap.y; 19651 19652 this.directionX = 0; 19653 this.directionY = 0; 19654 easing = this.options.bounceEasing; 19655 } 19656 19657// INSERT POINT: _end 19658 19659 if ( newX != this.x || newY != this.y ) { 19660 // change easing function when scroller goes out of the boundaries 19661 if ( newX > 0 || newX < this.maxScrollX || newY > 0 || newY < this.maxScrollY ) { 19662 easing = utils.ease.quadratic; 19663 } 19664 19665 this.scrollTo(newX, newY, time, easing); 19666 return; 19667 } 19668 19669 this._execEvent('scrollEnd'); 19670 }, 19671 19672 _resize: function () { 19673 var that = this; 19674 19675 clearTimeout(this.resizeTimeout); 19676 19677 this.resizeTimeout = setTimeout(function () { 19678 that.refresh(); 19679 }, this.options.resizePolling); 19680 }, 19681 19682 resetPosition: function (time) { 19683 var x = this.x, 19684 y = this.y; 19685 19686 time = time || 0; 19687 19688 if ( !this.hasHorizontalScroll || this.x > 0 ) { 19689 x = 0; 19690 } else if ( this.x < this.maxScrollX ) { 19691 x = this.maxScrollX; 19692 } 19693 19694 if ( !this.hasVerticalScroll || this.y > 0 ) { 19695 y = 0; 19696 } else if ( this.y < this.maxScrollY ) { 19697 y = this.maxScrollY; 19698 } 19699 19700 if ( x == this.x && y == this.y ) { 19701 return false; 19702 } 19703 19704 this.scrollTo(x, y, time, this.options.bounceEasing); 19705 19706 return true; 19707 }, 19708 19709 disable: function () { 19710 this.enabled = false; 19711 }, 19712 19713 enable: function () { 19714 this.enabled = true; 19715 }, 19716 19717 refresh: function () { 19718 var rf = this.wrapper.offsetHeight; // Force reflow 19719 19720 this.wrapperWidth = this.wrapper.clientWidth; 19721 this.wrapperHeight = this.wrapper.clientHeight; 19722 19723/* REPLACE START: refresh */ 19724 19725 this.scrollerWidth = this.scroller.offsetWidth; 19726 this.scrollerHeight = this.scroller.offsetHeight; 19727 19728 this.maxScrollX = this.wrapperWidth - this.scrollerWidth; 19729 this.maxScrollY = this.wrapperHeight - this.scrollerHeight; 19730 19731/* REPLACE END: refresh */ 19732 19733 this.hasHorizontalScroll = this.options.scrollX && this.maxScrollX < 0; 19734 this.hasVerticalScroll = this.options.scrollY && this.maxScrollY < 0; 19735 19736 if ( !this.hasHorizontalScroll ) { 19737 this.maxScrollX = 0; 19738 this.scrollerWidth = this.wrapperWidth; 19739 } 19740 19741 if ( !this.hasVerticalScroll ) { 19742 this.maxScrollY = 0; 19743 this.scrollerHeight = this.wrapperHeight; 19744 } 19745 19746 this.endTime = 0; 19747 this.directionX = 0; 19748 this.directionY = 0; 19749 19750 this.wrapperOffset = utils.offset(this.wrapper); 19751 19752 this._execEvent('refresh'); 19753 19754 this.resetPosition(); 19755 19756// INSERT POINT: _refresh 19757 19758 }, 19759 19760 on: function (type, fn) { 19761 if ( !this._events[type] ) { 19762 this._events[type] = []; 19763 } 19764 19765 this._events[type].push(fn); 19766 }, 19767 19768 off: function (type, fn) { 19769 if ( !this._events[type] ) { 19770 return; 19771 } 19772 19773 var index = this._events[type].indexOf(fn); 19774 19775 if ( index > -1 ) { 19776 this._events[type].splice(index, 1); 19777 } 19778 }, 19779 19780 _execEvent: function (type) { 19781 if ( !this._events[type] ) { 19782 return; 19783 } 19784 19785 var i = 0, 19786 l = this._events[type].length; 19787 19788 if ( !l ) { 19789 return; 19790 } 19791 19792 for ( ; i < l; i++ ) { 19793 this._events[type][i].apply(this, [].slice.call(arguments, 1)); 19794 } 19795 }, 19796 19797 scrollBy: function (x, y, time, easing) { 19798 x = this.x + x; 19799 y = this.y + y; 19800 time = time || 0; 19801 19802 this.scrollTo(x, y, time, easing); 19803 }, 19804 19805 scrollTo: function (x, y, time, easing) { 19806 easing = easing || utils.ease.circular; 19807 19808 this.isInTransition = this.options.useTransition && time > 0; 19809 var transitionType = this.options.useTransition && easing.style; 19810 if ( !time || transitionType ) { 19811 if(transitionType) { 19812 this._transitionTimingFunction(easing.style); 19813 this._transitionTime(time); 19814 } 19815 this._translate(x, y); 19816 } else { 19817 this._animate(x, y, time, easing.fn); 19818 } 19819 }, 19820 19821 scrollToElement: function (el, time, offsetX, offsetY, easing) { 19822 el = el.nodeType ? el : this.scroller.querySelector(el); 19823 19824 if ( !el ) { 19825 return; 19826 } 19827 19828 var pos = utils.offset(el); 19829 19830 pos.left -= this.wrapperOffset.left; 19831 pos.top -= this.wrapperOffset.top; 19832 19833 // if offsetX/Y are true we center the element to the screen 19834 if ( offsetX === true ) { 19835 offsetX = Math.round(el.offsetWidth / 2 - this.wrapper.offsetWidth / 2); 19836 } 19837 if ( offsetY === true ) { 19838 offsetY = Math.round(el.offsetHeight / 2 - this.wrapper.offsetHeight / 2); 19839 } 19840 19841 pos.left -= offsetX || 0; 19842 pos.top -= offsetY || 0; 19843 19844 pos.left = pos.left > 0 ? 0 : pos.left < this.maxScrollX ? this.maxScrollX : pos.left; 19845 pos.top = pos.top > 0 ? 0 : pos.top < this.maxScrollY ? this.maxScrollY : pos.top; 19846 19847 time = time === undefined || time === null || time === 'auto' ? Math.max(Math.abs(this.x-pos.left), Math.abs(this.y-pos.top)) : time; 19848 19849 this.scrollTo(pos.left, pos.top, time, easing); 19850 }, 19851 19852 _transitionTime: function (time) { 19853 if (!this.options.useTransition) { 19854 return; 19855 } 19856 time = time || 0; 19857 var durationProp = utils.style.transitionDuration; 19858 if(!durationProp) { 19859 return; 19860 } 19861 19862 this.scrollerStyle[durationProp] = time + 'ms'; 19863 19864 if ( !time && utils.isBadAndroid ) { 19865 this.scrollerStyle[durationProp] = '0.0001ms'; 19866 // remove 0.0001ms 19867 var self = this; 19868 rAF(function() { 19869 if(self.scrollerStyle[durationProp] === '0.0001ms') { 19870 self.scrollerStyle[durationProp] = '0s'; 19871 } 19872 }); 19873 } 19874 19875 19876 if ( this.indicators ) { 19877 for ( var i = this.indicators.length; i--; ) { 19878 this.indicators[i].transitionTime(time); 19879 } 19880 } 19881 19882 19883// INSERT POINT: _transitionTime 19884 19885 }, 19886 19887 _transitionTimingFunction: function (easing) { 19888 this.scrollerStyle[utils.style.transitionTimingFunction] = easing; 19889 19890 19891 if ( this.indicators ) { 19892 for ( var i = this.indicators.length; i--; ) { 19893 this.indicators[i].transitionTimingFunction(easing); 19894 } 19895 } 19896 19897 19898// INSERT POINT: _transitionTimingFunction 19899 19900 }, 19901 19902 _translate: function (x, y) { 19903 //Uncode addition 19904 if ( (" " + this.wrapper.className + " ").replace(/[\n\t]/g, " ").indexOf(" no-scrolloverflow ") > -1 ) 19905 return false;
vendor: 9,939 bytes, lines 19906-20217
19906 19907 if ( this.options.useTransform ) { 19908 19909/* REPLACE START: _translate */ 19910 19911 this.scrollerStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.translateZ; 19912 19913/* REPLACE END: _translate */ 19914 19915 } else { 19916 x = Math.round(x); 19917 y = Math.round(y); 19918 this.scrollerStyle.left = x + 'px'; 19919 this.scrollerStyle.top = y + 'px'; 19920 } 19921 19922 this.x = x; 19923 this.y = y; 19924 19925 19926 if ( this.indicators ) { 19927 for ( var i = this.indicators.length; i--; ) { 19928 this.indicators[i].updatePosition(); 19929 } 19930 } 19931 19932 //Uncode addition 19933 var uncodevent = new CustomEvent('fp-slide-scroll'); 19934 window.dispatchEvent(uncodevent); 19935 19936// INSERT POINT: _translate 19937 19938 }, 19939 19940 _initEvents: function (remove) { 19941 var eventType = remove ? utils.removeEvent : utils.addEvent, 19942 target = this.options.bindToWrapper ? this.wrapper : window; 19943 19944 eventType(window, 'orientationchange', this); 19945 eventType(window, 'resize', this); 19946 19947 if ( this.options.click ) { 19948 eventType(this.wrapper, 'click', this, true); 19949 } 19950 19951 if ( !this.options.disableMouse ) { 19952 eventType(this.wrapper, 'mousedown', this); 19953 eventType(target, 'mousemove', this); 19954 eventType(target, 'mousecancel', this); 19955 eventType(target, 'mouseup', this); 19956 } 19957 19958 if ( utils.hasPointer && !this.options.disablePointer ) { 19959 eventType(this.wrapper, utils.prefixPointerEvent('pointerdown'), this); 19960 eventType(target, utils.prefixPointerEvent('pointermove'), this); 19961 eventType(target, utils.prefixPointerEvent('pointercancel'), this); 19962 eventType(target, utils.prefixPointerEvent('pointerup'), this); 19963 } 19964 19965 if ( utils.hasTouch && !this.options.disableTouch ) { 19966 eventType(this.wrapper, 'touchstart', this); 19967 eventType(target, 'touchmove', this); 19968 eventType(target, 'touchcancel', this); 19969 eventType(target, 'touchend', this); 19970 } 19971 19972 eventType(this.scroller, 'transitionend', this); 19973 eventType(this.scroller, 'webkitTransitionEnd', this); 19974 eventType(this.scroller, 'oTransitionEnd', this); 19975 eventType(this.scroller, 'MSTransitionEnd', this); 19976 }, 19977 19978 getComputedPosition: function () { 19979 var matrix = window.getComputedStyle(this.scroller, null), 19980 x, y; 19981 19982 if ( this.options.useTransform ) { 19983 matrix = matrix[utils.style.transform].split(')')[0].split(', '); 19984 x = +(matrix[12] || matrix[4]); 19985 y = +(matrix[13] || matrix[5]); 19986 } else { 19987 x = +matrix.left.replace(/[^-\d.]/g, ''); 19988 y = +matrix.top.replace(/[^-\d.]/g, ''); 19989 } 19990 19991 return { x: x, y: y }; 19992 }, 19993 _initIndicators: function () { 19994 var interactive = this.options.interactiveScrollbars, 19995 customStyle = typeof this.options.scrollbars != 'string', 19996 indicators = [], 19997 indicator; 19998 19999 var that = this; 20000 20001 this.indicators = []; 20002 20003 if ( this.options.scrollbars ) { 20004 // Vertical scrollbar 20005 if ( this.options.scrollY ) { 20006 indicator = { 20007 el: createDefaultScrollbar('v', interactive, this.options.scrollbars), 20008 interactive: interactive, 20009 defaultScrollbars: true, 20010 customStyle: customStyle, 20011 resize: this.options.resizeScrollbars, 20012 shrink: this.options.shrinkScrollbars, 20013 fade: this.options.fadeScrollbars, 20014 listenX: false 20015 }; 20016 20017 this.wrapper.appendChild(indicator.el); 20018 indicators.push(indicator); 20019 } 20020 20021 // Horizontal scrollbar 20022 if ( this.options.scrollX ) { 20023 indicator = { 20024 el: createDefaultScrollbar('h', interactive, this.options.scrollbars), 20025 interactive: interactive, 20026 defaultScrollbars: true, 20027 customStyle: customStyle, 20028 resize: this.options.resizeScrollbars, 20029 shrink: this.options.shrinkScrollbars, 20030 fade: this.options.fadeScrollbars, 20031 listenY: false 20032 }; 20033 20034 this.wrapper.appendChild(indicator.el); 20035 indicators.push(indicator); 20036 } 20037 } 20038 20039 if ( this.options.indicators ) { 20040 // TODO: check concat compatibility 20041 indicators = indicators.concat(this.options.indicators); 20042 } 20043 20044 for ( var i = indicators.length; i--; ) { 20045 this.indicators.push( new Indicator(this, indicators[i]) ); 20046 } 20047 20048 // TODO: check if we can use array.map (wide compatibility and performance issues) 20049 function _indicatorsMap (fn) { 20050 if (that.indicators) { 20051 for ( var i = that.indicators.length; i--; ) { 20052 fn.call(that.indicators[i]); 20053 } 20054 } 20055 } 20056 20057 if ( this.options.fadeScrollbars ) { 20058 this.on('scrollEnd', function () { 20059 _indicatorsMap(function () { 20060 this.fade(); 20061 }); 20062 }); 20063 20064 this.on('scrollCancel', function () { 20065 _indicatorsMap(function () { 20066 this.fade(); 20067 }); 20068 }); 20069 20070 this.on('scrollStart', function () { 20071 _indicatorsMap(function () { 20072 this.fade(1); 20073 }); 20074 }); 20075 20076 this.on('beforeScrollStart', function () { 20077 _indicatorsMap(function () { 20078 this.fade(1, true); 20079 }); 20080 }); 20081 } 20082 20083 20084 this.on('refresh', function () { 20085 _indicatorsMap(function () { 20086 this.refresh(); 20087 }); 20088 }); 20089 20090 this.on('destroy', function () { 20091 _indicatorsMap(function () { 20092 this.destroy(); 20093 }); 20094 20095 delete this.indicators; 20096 }); 20097 }, 20098 20099 _initWheel: function () { 20100 utils.addEvent(this.wrapper, 'wheel', this); 20101 utils.addEvent(this.wrapper, 'mousewheel', this); 20102 utils.addEvent(this.wrapper, 'DOMMouseScroll', this); 20103 20104 this.on('destroy', function () { 20105 clearTimeout(this.wheelTimeout); 20106 this.wheelTimeout = null; 20107 utils.removeEvent(this.wrapper, 'wheel', this); 20108 utils.removeEvent(this.wrapper, 'mousewheel', this); 20109 utils.removeEvent(this.wrapper, 'DOMMouseScroll', this); 20110 }); 20111 }, 20112 20113 _wheel: function (e) { 20114 if ( !this.enabled ) { 20115 return; 20116 } 20117 20118 var wheelDeltaX, wheelDeltaY, 20119 newX, newY, 20120 that = this; 20121 20122 if ( this.wheelTimeout === undefined ) { 20123 that._execEvent('scrollStart'); 20124 } 20125 20126 // Execute the scrollEnd event after 400ms the wheel stopped scrolling 20127 clearTimeout(this.wheelTimeout); 20128 this.wheelTimeout = setTimeout(function () { 20129 if(!that.options.snap) { 20130 that._execEvent('scrollEnd'); 20131 } 20132 that.wheelTimeout = undefined; 20133 }, 400); 20134 20135 if ( 'deltaX' in e ) { 20136 if (e.deltaMode === 1) { 20137 wheelDeltaX = -e.deltaX * this.options.mouseWheelSpeed; 20138 wheelDeltaY = -e.deltaY * this.options.mouseWheelSpeed; 20139 } else { 20140 wheelDeltaX = -e.deltaX; 20141 wheelDeltaY = -e.deltaY; 20142 } 20143 } else if ( 'wheelDeltaX' in e ) { 20144 wheelDeltaX = e.wheelDeltaX / 120 * this.options.mouseWheelSpeed; 20145 wheelDeltaY = e.wheelDeltaY / 120 * this.options.mouseWheelSpeed; 20146 } else if ( 'wheelDelta' in e ) { 20147 wheelDeltaX = wheelDeltaY = e.wheelDelta / 120 * this.options.mouseWheelSpeed; 20148 } else if ( 'detail' in e ) { 20149 wheelDeltaX = wheelDeltaY = -e.detail / 3 * this.options.mouseWheelSpeed; 20150 } else { 20151 return; 20152 } 20153 20154 wheelDeltaX *= this.options.invertWheelDirection; 20155 wheelDeltaY *= this.options.invertWheelDirection; 20156 20157 if ( !this.hasVerticalScroll ) { 20158 wheelDeltaX = wheelDeltaY; 20159 wheelDeltaY = 0; 20160 } 20161 20162 if ( this.options.snap ) { 20163 newX = this.currentPage.pageX; 20164 newY = this.currentPage.pageY; 20165 20166 if ( wheelDeltaX > 0 ) { 20167 newX--; 20168 } else if ( wheelDeltaX < 0 ) { 20169 newX++; 20170 } 20171 20172 if ( wheelDeltaY > 0 ) { 20173 newY--; 20174 } else if ( wheelDeltaY < 0 ) { 20175 newY++; 20176 } 20177 20178 this.goToPage(newX, newY); 20179 20180 return; 20181 } 20182 20183 newX = this.x + Math.round(this.hasHorizontalScroll ? wheelDeltaX : 0); 20184 newY = this.y + Math.round(this.hasVerticalScroll ? wheelDeltaY : 0); 20185 20186 this.directionX = wheelDeltaX > 0 ? -1 : wheelDeltaX < 0 ? 1 : 0; 20187 this.directionY = wheelDeltaY > 0 ? -1 : wheelDeltaY < 0 ? 1 : 0; 20188 20189 if ( newX > 0 ) { 20190 newX = 0; 20191 } else if ( newX < this.maxScrollX ) { 20192 newX = this.maxScrollX; 20193 } 20194 20195 if ( newY > 0 ) { 20196 newY = 0; 20197 } else if ( newY < this.maxScrollY ) { 20198 newY = this.maxScrollY; 20199 } 20200 20201 this.scrollTo(newX, newY, 0); 20202 20203// INSERT POINT: _wheel 20204 }, 20205 20206 _initSnap: function () { 20207 this.currentPage = {}; 20208 20209 if ( typeof this.options.snap == 'string' ) { 20210 this.options.snap = this.scroller.querySelectorAll(this.options.snap); 20211 } 20212 20213 this.on('refresh', function () { 20214 var i = 0, l, 20215 m = 0, n, 20216 cx, cy, 20217 x = 0, y,
vendor: 7,339 bytes, lines 20218-20471
20218 stepX = this.options.snapStepX || this.wrapperWidth, 20219 stepY = this.options.snapStepY || this.wrapperHeight, 20220 el; 20221 20222 this.pages = []; 20223 20224 if ( !this.wrapperWidth || !this.wrapperHeight || !this.scrollerWidth || !this.scrollerHeight ) { 20225 return; 20226 } 20227 20228 if ( this.options.snap === true ) { 20229 cx = Math.round( stepX / 2 ); 20230 cy = Math.round( stepY / 2 ); 20231 20232 while ( x > -this.scrollerWidth ) { 20233 this.pages[i] = []; 20234 l = 0; 20235 y = 0; 20236 20237 while ( y > -this.scrollerHeight ) { 20238 this.pages[i][l] = { 20239 x: Math.max(x, this.maxScrollX), 20240 y: Math.max(y, this.maxScrollY), 20241 width: stepX, 20242 height: stepY, 20243 cx: x - cx, 20244 cy: y - cy 20245 }; 20246 20247 y -= stepY; 20248 l++; 20249 } 20250 20251 x -= stepX; 20252 i++; 20253 } 20254 } else { 20255 el = this.options.snap; 20256 l = el.length; 20257 n = -1; 20258 20259 for ( ; i < l; i++ ) { 20260 if ( i === 0 || el[i].offsetLeft <= el[i-1].offsetLeft ) { 20261 m = 0; 20262 n++; 20263 } 20264 20265 if ( !this.pages[m] ) { 20266 this.pages[m] = []; 20267 } 20268 20269 x = Math.max(-el[i].offsetLeft, this.maxScrollX); 20270 y = Math.max(-el[i].offsetTop, this.maxScrollY); 20271 cx = x - Math.round(el[i].offsetWidth / 2); 20272 cy = y - Math.round(el[i].offsetHeight / 2); 20273 20274 this.pages[m][n] = { 20275 x: x, 20276 y: y, 20277 width: el[i].offsetWidth, 20278 height: el[i].offsetHeight, 20279 cx: cx, 20280 cy: cy 20281 }; 20282 20283 if ( x > this.maxScrollX ) { 20284 m++; 20285 } 20286 } 20287 } 20288 20289 this.goToPage(this.currentPage.pageX || 0, this.currentPage.pageY || 0, 0); 20290 20291 // Update snap threshold if needed 20292 if ( this.options.snapThreshold % 1 === 0 ) { 20293 this.snapThresholdX = this.options.snapThreshold; 20294 this.snapThresholdY = this.options.snapThreshold; 20295 } else { 20296 this.snapThresholdX = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].width * this.options.snapThreshold); 20297 this.snapThresholdY = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].height * this.options.snapThreshold); 20298 } 20299 }); 20300 20301 this.on('flick', function () { 20302 var time = this.options.snapSpeed || Math.max( 20303 Math.max( 20304 Math.min(Math.abs(this.x - this.startX), 1000), 20305 Math.min(Math.abs(this.y - this.startY), 1000) 20306 ), 300); 20307 20308 this.goToPage( 20309 this.currentPage.pageX + this.directionX, 20310 this.currentPage.pageY + this.directionY, 20311 time 20312 ); 20313 }); 20314 }, 20315 20316 _nearestSnap: function (x, y) { 20317 if ( !this.pages.length ) { 20318 return { x: 0, y: 0, pageX: 0, pageY: 0 }; 20319 } 20320 20321 var i = 0, 20322 l = this.pages.length, 20323 m = 0; 20324 20325 // Check if we exceeded the snap threshold 20326 if ( Math.abs(x - this.absStartX) < this.snapThresholdX && 20327 Math.abs(y - this.absStartY) < this.snapThresholdY ) { 20328 return this.currentPage; 20329 } 20330 20331 if ( x > 0 ) { 20332 x = 0; 20333 } else if ( x < this.maxScrollX ) { 20334 x = this.maxScrollX; 20335 } 20336 20337 if ( y > 0 ) { 20338 y = 0; 20339 } else if ( y < this.maxScrollY ) { 20340 y = this.maxScrollY; 20341 } 20342 20343 for ( ; i < l; i++ ) { 20344 if ( x >= this.pages[i][0].cx ) { 20345 x = this.pages[i][0].x; 20346 break; 20347 } 20348 } 20349 20350 l = this.pages[i].length; 20351 20352 for ( ; m < l; m++ ) { 20353 if ( y >= this.pages[0][m].cy ) { 20354 y = this.pages[0][m].y; 20355 break; 20356 } 20357 } 20358 20359 if ( i == this.currentPage.pageX ) { 20360 i += this.directionX; 20361 20362 if ( i < 0 ) { 20363 i = 0; 20364 } else if ( i >= this.pages.length ) { 20365 i = this.pages.length - 1; 20366 } 20367 20368 x = this.pages[i][0].x; 20369 } 20370 20371 if ( m == this.currentPage.pageY ) { 20372 m += this.directionY; 20373 20374 if ( m < 0 ) { 20375 m = 0; 20376 } else if ( m >= this.pages[0].length ) { 20377 m = this.pages[0].length - 1; 20378 } 20379 20380 y = this.pages[0][m].y; 20381 } 20382 20383 return { 20384 x: x, 20385 y: y, 20386 pageX: i, 20387 pageY: m 20388 }; 20389 }, 20390 20391 goToPage: function (x, y, time, easing) { 20392 easing = easing || this.options.bounceEasing; 20393 20394 if ( x >= this.pages.length ) { 20395 x = this.pages.length - 1; 20396 } else if ( x < 0 ) { 20397 x = 0; 20398 } 20399 20400 if ( y >= this.pages[x].length ) { 20401 y = this.pages[x].length - 1; 20402 } else if ( y < 0 ) { 20403 y = 0; 20404 } 20405 20406 var posX = this.pages[x][y].x, 20407 posY = this.pages[x][y].y; 20408 20409 time = time === undefined ? this.options.snapSpeed || Math.max( 20410 Math.max( 20411 Math.min(Math.abs(posX - this.x), 1000), 20412 Math.min(Math.abs(posY - this.y), 1000) 20413 ), 300) : time; 20414 20415 this.currentPage = { 20416 x: posX, 20417 y: posY, 20418 pageX: x, 20419 pageY: y 20420 }; 20421 20422 this.scrollTo(posX, posY, time, easing); 20423 }, 20424 20425 next: function (time, easing) { 20426 var x = this.currentPage.pageX, 20427 y = this.currentPage.pageY; 20428 20429 x++; 20430 20431 if ( x >= this.pages.length && this.hasVerticalScroll ) { 20432 x = 0; 20433 y++; 20434 } 20435 20436 this.goToPage(x, y, time, easing); 20437 }, 20438 20439 prev: function (time, easing) { 20440 var x = this.currentPage.pageX, 20441 y = this.currentPage.pageY; 20442 20443 x--; 20444 20445 if ( x < 0 && this.hasVerticalScroll ) { 20446 x = 0; 20447 y--; 20448 } 20449 20450 this.goToPage(x, y, time, easing); 20451 }, 20452 20453 _initKeys: function (e) { 20454 // default key bindings 20455 var keys = { 20456 pageUp: 33, 20457 pageDown: 34, 20458 end: 35, 20459 home: 36, 20460 left: 37, 20461 up: 38, 20462 right: 39, 20463 down: 40 20464 }; 20465 var i; 20466 20467 // if you give me characters I give you keycode 20468 if ( typeof this.options.keyBindings == 'object' ) { 20469 for ( i in this.options.keyBindings ) { 20470 if ( typeof this.options.keyBindings[i] == 'string' ) { 20471 this.options.keyBindings[i] = this.options.keyBindings[i].toUpperCase().charCo
vendor: 11,097 bytes, lines 20471-20824
20471deAt(0); 20472 } 20473 } 20474 } else { 20475 this.options.keyBindings = {}; 20476 } 20477 20478 for ( i in keys ) { 20479 this.options.keyBindings[i] = this.options.keyBindings[i] || keys[i]; 20480 } 20481 20482 utils.addEvent(window, 'keydown', this); 20483 20484 this.on('destroy', function () { 20485 utils.removeEvent(window, 'keydown', this); 20486 }); 20487 }, 20488 20489 _key: function (e) { 20490 if ( !this.enabled ) { 20491 return; 20492 } 20493 20494 var snap = this.options.snap, // we are using this alot, better to cache it 20495 newX = snap ? this.currentPage.pageX : this.x, 20496 newY = snap ? this.currentPage.pageY : this.y, 20497 now = utils.getTime(), 20498 prevTime = this.keyTime || 0, 20499 acceleration = 0.250, 20500 pos; 20501 20502 if ( this.options.useTransition && this.isInTransition ) { 20503 pos = this.getComputedPosition(); 20504 20505 this._translate(Math.round(pos.x), Math.round(pos.y)); 20506 this.isInTransition = false; 20507 } 20508 20509 this.keyAcceleration = now - prevTime < 200 ? Math.min(this.keyAcceleration + acceleration, 50) : 0; 20510 20511 switch ( e.keyCode ) { 20512 case this.options.keyBindings.pageUp: 20513 if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) { 20514 newX += snap ? 1 : this.wrapperWidth; 20515 } else { 20516 newY += snap ? 1 : this.wrapperHeight; 20517 } 20518 break; 20519 case this.options.keyBindings.pageDown: 20520 if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) { 20521 newX -= snap ? 1 : this.wrapperWidth; 20522 } else { 20523 newY -= snap ? 1 : this.wrapperHeight; 20524 } 20525 break; 20526 case this.options.keyBindings.end: 20527 newX = snap ? this.pages.length-1 : this.maxScrollX; 20528 newY = snap ? this.pages[0].length-1 : this.maxScrollY; 20529 break; 20530 case this.options.keyBindings.home: 20531 newX = 0; 20532 newY = 0; 20533 break; 20534 case this.options.keyBindings.left: 20535 newX += snap ? -1 : 5 + this.keyAcceleration>>0; 20536 break; 20537 case this.options.keyBindings.up: 20538 newY += snap ? 1 : 5 + this.keyAcceleration>>0; 20539 break; 20540 case this.options.keyBindings.right: 20541 newX -= snap ? -1 : 5 + this.keyAcceleration>>0; 20542 break; 20543 case this.options.keyBindings.down: 20544 newY -= snap ? 1 : 5 + this.keyAcceleration>>0; 20545 break; 20546 default: 20547 return; 20548 } 20549 20550 if ( snap ) { 20551 this.goToPage(newX, newY); 20552 return; 20553 } 20554 20555 if ( newX > 0 ) { 20556 newX = 0; 20557 this.keyAcceleration = 0; 20558 } else if ( newX < this.maxScrollX ) { 20559 newX = this.maxScrollX; 20560 this.keyAcceleration = 0; 20561 } 20562 20563 if ( newY > 0 ) { 20564 newY = 0; 20565 this.keyAcceleration = 0; 20566 } else if ( newY < this.maxScrollY ) { 20567 newY = this.maxScrollY; 20568 this.keyAcceleration = 0; 20569 } 20570 20571 this.scrollTo(newX, newY, 0); 20572 20573 this.keyTime = now; 20574 }, 20575 20576 _animate: function (destX, destY, duration, easingFn) { 20577 var that = this, 20578 startX = this.x, 20579 startY = this.y, 20580 startTime = utils.getTime(), 20581 destTime = startTime + duration; 20582 20583 function step () { 20584 var now = utils.getTime(), 20585 newX, newY, 20586 easing; 20587 20588 if ( now >= destTime ) { 20589 that.isAnimating = false; 20590 that._translate(destX, destY); 20591 20592 if ( !that.resetPosition(that.options.bounceTime) ) { 20593 that._execEvent('scrollEnd'); 20594 } 20595 20596 return; 20597 } 20598 20599 now = ( now - startTime ) / duration; 20600 easing = easingFn(now); 20601 newX = ( destX - startX ) * easing + startX; 20602 newY = ( destY - startY ) * easing + startY; 20603 that._translate(newX, newY); 20604 20605 if ( that.isAnimating ) { 20606 rAF(step); 20607 } 20608 } 20609 20610 this.isAnimating = true; 20611 step(); 20612 }, 20613 handleEvent: function (e) { 20614 switch ( e.type ) { 20615 case 'touchstart': 20616 case 'pointerdown': 20617 case 'MSPointerDown': 20618 case 'mousedown': 20619 this._start(e); 20620 break; 20621 case 'touchmove': 20622 case 'pointermove': 20623 case 'MSPointerMove': 20624 case 'mousemove': 20625 this._move(e); 20626 break; 20627 case 'touchend': 20628 case 'pointerup': 20629 case 'MSPointerUp': 20630 case 'mouseup': 20631 case 'touchcancel': 20632 case 'pointercancel': 20633 case 'MSPointerCancel': 20634 case 'mousecancel': 20635 this._end(e); 20636 break; 20637 case 'orientationchange': 20638 case 'resize': 20639 this._resize(); 20640 break; 20641 case 'transitionend': 20642 case 'webkitTransitionEnd': 20643 case 'oTransitionEnd': 20644 case 'MSTransitionEnd': 20645 this._transitionEnd(e); 20646 break; 20647 case 'wheel': 20648 case 'DOMMouseScroll': 20649 case 'mousewheel': 20650 this._wheel(e); 20651 break; 20652 case 'keydown': 20653 this._key(e); 20654 break; 20655 case 'click': 20656 if ( this.enabled && !e._constructed ) { 20657 e.preventDefault(); 20658 e.stopPropagation(); 20659 } 20660 break; 20661 } 20662 } 20663}; 20664function createDefaultScrollbar (direction, interactive, type) { 20665 var scrollbar = document.createElement('div'), 20666 indicator = document.createElement('div'); 20667 20668 if ( type === true ) { 20669 scrollbar.style.cssText = 'position:absolute;z-index:9999'; 20670 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'; 20671 } 20672 20673 indicator.className = 'iScrollIndicator'; 20674 20675 if ( direction == 'h' ) { 20676 if ( type === true ) { 20677 scrollbar.style.cssText += ';height:7px;left:2px;right:2px;bottom:0'; 20678 indicator.style.height = '100%'; 20679 } 20680 scrollbar.className = 'iScrollHorizontalScrollbar'; 20681 } else { 20682 if ( type === true ) { 20683 scrollbar.style.cssText += ';width:7px;bottom:2px;top:2px;right:1px'; 20684 indicator.style.width = '100%'; 20685 } 20686 scrollbar.className = 'iScrollVerticalScrollbar'; 20687 } 20688 20689 scrollbar.style.cssText += ';overflow:hidden'; 20690 20691 if ( !interactive ) { 20692 scrollbar.style.pointerEvents = 'none'; 20693 } 20694 20695 scrollbar.appendChild(indicator); 20696 20697 return scrollbar; 20698} 20699 20700function Indicator (scroller, options) { 20701 this.wrapper = typeof options.el == 'string' ? document.querySelector(options.el) : options.el; 20702 this.wrapperStyle = this.wrapper.style; 20703 this.indicator = this.wrapper.children[0]; 20704 this.indicatorStyle = this.indicator.style; 20705 this.scroller = scroller; 20706 20707 this.options = { 20708 listenX: true, 20709 listenY: true, 20710 interactive: false, 20711 resize: true, 20712 defaultScrollbars: false, 20713 shrink: false, 20714 fade: false, 20715 speedRatioX: 0, 20716 speedRatioY: 0 20717 }; 20718 20719 for ( var i in options ) { 20720 this.options[i] = options[i]; 20721 } 20722 20723 this.sizeRatioX = 1; 20724 this.sizeRatioY = 1; 20725 this.maxPosX = 0; 20726 this.maxPosY = 0; 20727 20728 if ( this.options.interactive ) { 20729 if ( !this.options.disableTouch ) { 20730 utils.addEvent(this.indicator, 'touchstart', this); 20731 utils.addEvent(window, 'touchend', this); 20732 } 20733 if ( !this.options.disablePointer ) { 20734 utils.addEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this); 20735 utils.addEvent(window, utils.prefixPointerEvent('pointerup'), this); 20736 } 20737 if ( !this.options.disableMouse ) { 20738 utils.addEvent(this.indicator, 'mousedown', this); 20739 utils.addEvent(window, 'mouseup', this); 20740 } 20741 } 20742 20743 if ( this.options.fade ) { 20744 this.wrapperStyle[utils.style.transform] = this.scroller.translateZ; 20745 var durationProp = utils.style.transitionDuration; 20746 if(!durationProp) { 20747 return; 20748 } 20749 this.wrapperStyle[durationProp] = utils.isBadAndroid ? '0.0001ms' : '0ms'; 20750 // remove 0.0001ms 20751 var self = this; 20752 if(utils.isBadAndroid) { 20753 rAF(function() { 20754 if(self.wrapperStyle[durationProp] === '0.0001ms') { 20755 self.wrapperStyle[durationProp] = '0s'; 20756 } 20757 }); 20758 } 20759 this.wrapperStyle.opacity = '0'; 20760 } 20761} 20762 20763Indicator.prototype = { 20764 handleEvent: function (e) { 20765 switch ( e.type ) { 20766 case 'touchstart': 20767 case 'pointerdown': 20768 case 'MSPointerDown': 20769 case 'mousedown': 20770 this._start(e); 20771 break; 20772 case 'touchmove': 20773 case 'pointermove': 20774 case 'MSPointerMove': 20775 case 'mousemove': 20776 this._move(e); 20777 break; 20778 case 'touchend': 20779 case 'pointerup': 20780 case 'MSPointerUp': 20781 case 'mouseup': 20782 case 'touchcancel': 20783 case 'pointercancel': 20784 case 'MSPointerCancel': 20785 case 'mousecancel': 20786 this._end(e); 20787 break; 20788 } 20789 }, 20790 20791 destroy: function () { 20792 if ( this.options.fadeScrollbars ) { 20793 clearTimeout(this.fadeTimeout); 20794 this.fadeTimeout = null; 20795 } 20796 if ( this.options.interactive ) { 20797 utils.removeEvent(this.indicator, 'touchstart', this); 20798 utils.removeEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this); 20799 utils.removeEvent(this.indicator, 'mousedown', this); 20800 20801 utils.removeEvent(window, 'touchmove', this); 20802 utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this); 20803 utils.removeEvent(window, 'mousemove', this); 20804 20805 utils.removeEvent(window, 'touchend', this); 20806 utils.removeEvent(window, utils.prefixPointerEvent('pointerup'), this); 20807 utils.removeEvent(window, 'mouseup', this); 20808 } 20809 20810 if ( this.options.defaultScrollbars ) { 20811 this.wrapper.parentNode.removeChild(this.wrapper); 20812 } 20813 }, 20814 20815 _start: function (e) { 20816 var point = e.touches ? e.touches[0] : e; 20817 20818 e.preventDefault(); 20819 e.stopPropagation(); 20820 20821 this.transitionTime(); 20822 20823 this.initiated = true; 20824 this.moved = false;
vendor: 9,615 bytes, lines 20825-21083
20825 this.lastPointX = point.pageX; 20826 this.lastPointY = point.pageY; 20827 20828 this.startTime = utils.getTime(); 20829 20830 if ( !this.options.disableTouch ) { 20831 utils.addEvent(window, 'touchmove', this); 20832 } 20833 if ( !this.options.disablePointer ) { 20834 utils.addEvent(window, utils.prefixPointerEvent('pointermove'), this); 20835 } 20836 if ( !this.options.disableMouse ) { 20837 utils.addEvent(window, 'mousemove', this); 20838 } 20839 20840 this.scroller._execEvent('beforeScrollStart'); 20841 }, 20842 20843 _move: function (e) { 20844 var point = e.touches ? e.touches[0] : e, 20845 deltaX, deltaY, 20846 newX, newY, 20847 timestamp = utils.getTime(); 20848 20849 if ( !this.moved ) { 20850 this.scroller._execEvent('scrollStart'); 20851 } 20852 20853 this.moved = true; 20854 20855 deltaX = point.pageX - this.lastPointX; 20856 this.lastPointX = point.pageX; 20857 20858 deltaY = point.pageY - this.lastPointY; 20859 this.lastPointY = point.pageY; 20860 20861 newX = this.x + deltaX; 20862 newY = this.y + deltaY; 20863 20864 this._pos(newX, newY); 20865 20866// INSERT POINT: indicator._move 20867 20868 e.preventDefault(); 20869 e.stopPropagation(); 20870 }, 20871 20872 _end: function (e) { 20873 if ( !this.initiated ) { 20874 return; 20875 } 20876 20877 this.initiated = false; 20878 20879 e.preventDefault(); 20880 e.stopPropagation(); 20881 20882 utils.removeEvent(window, 'touchmove', this); 20883 utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this); 20884 utils.removeEvent(window, 'mousemove', this); 20885 20886 if ( this.scroller.options.snap ) { 20887 var snap = this.scroller._nearestSnap(this.scroller.x, this.scroller.y); 20888 20889 var time = this.options.snapSpeed || Math.max( 20890 Math.max( 20891 Math.min(Math.abs(this.scroller.x - snap.x), 1000), 20892 Math.min(Math.abs(this.scroller.y - snap.y), 1000) 20893 ), 300); 20894 20895 if ( this.scroller.x != snap.x || this.scroller.y != snap.y ) { 20896 this.scroller.directionX = 0; 20897 this.scroller.directionY = 0; 20898 this.scroller.currentPage = snap; 20899 this.scroller.scrollTo(snap.x, snap.y, time, this.scroller.options.bounceEasing); 20900 } 20901 } 20902 20903 if ( this.moved ) { 20904 this.scroller._execEvent('scrollEnd'); 20905 } 20906 }, 20907 20908 transitionTime: function (time) { 20909 time = time || 0; 20910 var durationProp = utils.style.transitionDuration; 20911 if(!durationProp) { 20912 return; 20913 } 20914 20915 this.indicatorStyle[durationProp] = time + 'ms'; 20916 20917 if ( !time && utils.isBadAndroid ) { 20918 this.indicatorStyle[durationProp] = '0.0001ms'; 20919 // remove 0.0001ms 20920 var self = this; 20921 rAF(function() { 20922 if(self.indicatorStyle[durationProp] === '0.0001ms') { 20923 self.indicatorStyle[durationProp] = '0s'; 20924 } 20925 }); 20926 } 20927 }, 20928 20929 transitionTimingFunction: function (easing) { 20930 this.indicatorStyle[utils.style.transitionTimingFunction] = easing; 20931 }, 20932 20933 refresh: function () { 20934 this.transitionTime(); 20935 20936 if ( this.options.listenX && !this.options.listenY ) { 20937 this.indicatorStyle.display = this.scroller.hasHorizontalScroll ? 'block' : 'none'; 20938 } else if ( this.options.listenY && !this.options.listenX ) { 20939 this.indicatorStyle.display = this.scroller.hasVerticalScroll ? 'block' : 'none'; 20940 } else { 20941 this.indicatorStyle.display = this.scroller.hasHorizontalScroll || this.scroller.hasVerticalScroll ? 'block' : 'none'; 20942 } 20943 20944 if ( this.scroller.hasHorizontalScroll && this.scroller.hasVerticalScroll ) { 20945 utils.addClass(this.wrapper, 'iScrollBothScrollbars'); 20946 utils.removeClass(this.wrapper, 'iScrollLoneScrollbar'); 20947 20948 if ( this.options.defaultScrollbars && this.options.customStyle ) { 20949 if ( this.options.listenX ) { 20950 this.wrapper.style.right = '8px'; 20951 } else { 20952 this.wrapper.style.bottom = '8px'; 20953 } 20954 } 20955 } else { 20956 utils.removeClass(this.wrapper, 'iScrollBothScrollbars'); 20957 utils.addClass(this.wrapper, 'iScrollLoneScrollbar'); 20958 20959 if ( this.options.defaultScrollbars && this.options.customStyle ) { 20960 if ( this.options.listenX ) { 20961 this.wrapper.style.right = '2px'; 20962 } else { 20963 this.wrapper.style.bottom = '2px'; 20964 } 20965 } 20966 } 20967 20968 var r = this.wrapper.offsetHeight; // force refresh 20969 20970 if ( this.options.listenX ) { 20971 this.wrapperWidth = this.wrapper.clientWidth; 20972 if ( this.options.resize ) { 20973 this.indicatorWidth = Math.max(Math.round(this.wrapperWidth * this.wrapperWidth / (this.scroller.scrollerWidth || this.wrapperWidth || 1)), 8); 20974 this.indicatorStyle.width = this.indicatorWidth + 'px'; 20975 } else { 20976 this.indicatorWidth = this.indicator.clientWidth; 20977 } 20978 20979 this.maxPosX = this.wrapperWidth - this.indicatorWidth; 20980 20981 if ( this.options.shrink == 'clip' ) { 20982 this.minBoundaryX = -this.indicatorWidth + 8; 20983 this.maxBoundaryX = this.wrapperWidth - 8; 20984 } else { 20985 this.minBoundaryX = 0; 20986 this.maxBoundaryX = this.maxPosX; 20987 } 20988 20989 this.sizeRatioX = this.options.speedRatioX || (this.scroller.maxScrollX && (this.maxPosX / this.scroller.maxScrollX)); 20990 } 20991 20992 if ( this.options.listenY ) { 20993 this.wrapperHeight = this.wrapper.clientHeight; 20994 if ( this.options.resize ) { 20995 this.indicatorHeight = Math.max(Math.round(this.wrapperHeight * this.wrapperHeight / (this.scroller.scrollerHeight || this.wrapperHeight || 1)), 8); 20996 this.indicatorStyle.height = this.indicatorHeight + 'px'; 20997 } else { 20998 this.indicatorHeight = this.indicator.clientHeight; 20999 } 21000 21001 this.maxPosY = this.wrapperHeight - this.indicatorHeight; 21002 21003 if ( this.options.shrink == 'clip' ) { 21004 this.minBoundaryY = -this.indicatorHeight + 8; 21005 this.maxBoundaryY = this.wrapperHeight - 8; 21006 } else { 21007 this.minBoundaryY = 0; 21008 this.maxBoundaryY = this.maxPosY; 21009 } 21010 21011 this.maxPosY = this.wrapperHeight - this.indicatorHeight; 21012 this.sizeRatioY = this.options.speedRatioY || (this.scroller.maxScrollY && (this.maxPosY / this.scroller.maxScrollY)); 21013 } 21014 21015 this.updatePosition(); 21016 }, 21017 21018 updatePosition: function () { 21019 var x = this.options.listenX && Math.round(this.sizeRatioX * this.scroller.x) || 0, 21020 y = this.options.listenY && Math.round(this.sizeRatioY * this.scroller.y) || 0; 21021 21022 if ( !this.options.ignoreBoundaries ) { 21023 if ( x < this.minBoundaryX ) { 21024 if ( this.options.shrink == 'scale' ) { 21025 this.width = Math.max(this.indicatorWidth + x, 8); 21026 this.indicatorStyle.width = this.width + 'px'; 21027 } 21028 x = this.minBoundaryX; 21029 } else if ( x > this.maxBoundaryX ) { 21030 if ( this.options.shrink == 'scale' ) { 21031 this.width = Math.max(this.indicatorWidth - (x - this.maxPosX), 8); 21032 this.indicatorStyle.width = this.width + 'px'; 21033 x = this.maxPosX + this.indicatorWidth - this.width; 21034 } else { 21035 x = this.maxBoundaryX; 21036 } 21037 } else if ( this.options.shrink == 'scale' && this.width != this.indicatorWidth ) { 21038 this.width = this.indicatorWidth; 21039 this.indicatorStyle.width = this.width + 'px'; 21040 } 21041 21042 if ( y < this.minBoundaryY ) { 21043 if ( this.options.shrink == 'scale' ) { 21044 this.height = Math.max(this.indicatorHeight + y * 3, 8); 21045 this.indicatorStyle.height = this.height + 'px'; 21046 } 21047 y = this.minBoundaryY; 21048 } else if ( y > this.maxBoundaryY ) { 21049 if ( this.options.shrink == 'scale' ) { 21050 this.height = Math.max(this.indicatorHeight - (y - this.maxPosY) * 3, 8); 21051 this.indicatorStyle.height = this.height + 'px'; 21052 y = this.maxPosY + this.indicatorHeight - this.height; 21053 } else { 21054 y = this.maxBoundaryY; 21055 } 21056 } else if ( this.options.shrink == 'scale' && this.height != this.indicatorHeight ) { 21057 this.height = this.indicatorHeight; 21058 this.indicatorStyle.height = this.height + 'px'; 21059 } 21060 } 21061 21062 this.x = x; 21063 this.y = y; 21064 21065 if ( this.scroller.options.useTransform ) { 21066 this.indicatorStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.scroller.translateZ; 21067 } else { 21068 this.indicatorStyle.left = x + 'px'; 21069 this.indicatorStyle.top = y + 'px'; 21070 } 21071 }, 21072 21073 _pos: function (x, y) { 21074 if ( x < 0 ) { 21075 x = 0; 21076 } else if ( x > this.maxPosX ) { 21077 x = this.maxPosX; 21078 } 21079 21080 if ( y < 0 ) { 21081 y = 0; 21082 } else if ( y > this.maxPosY ) { 21083 y = this.maxPosY;
21084 } 21085 21086 x = this.options.listenX ? Math.round(x / this.sizeRatioX) : this.scroller.x; 21087 y = this.options.listenY ? Math.round(y / this.sizeRatioY) : this.scroller.y; 21088 21089 this.scroller.scrollTo(x, y); 21090 }, 21091 21092 fade: function (val, hold) { 21093 if ( hold && !this.visible ) { 21094 return; 21095 } 21096 21097 clearTimeout(this.fadeTimeout); 21098 this.fadeTimeout = null; 21099 21100 var time = val ? 250 : 500, 21101 delay = val ? 0 : 300; 21102 21103 val = val ? '1' : '0'; 21104 21105 this.wrapperStyle[utils.style.transitionDuration] = time + 'ms'; 21106 21107 this.fadeTimeout = setTimeout((function (val) { 21108 this.wrapperStyle.opacity = val; 21109 this.visible = +val; 21110 }).bind(this, val), delay); 21111 } 21112}; 21113 21114IScroll.utils = utils; 21115 21116if ( typeof module != 'undefined' && module.exports ) { 21117 module.exports = IScroll; 21118} else if ( typeof define == 'function' && define.amd ) { 21119 define( function () { return IScroll; } ); 21120} else { 21121 window.IScroll = IScroll; 21122} 21123 21124})(window, document, Math); 21125/*! 21126 * fullPage 2.9.4 21127 * https://github.com/alvarotrigo/fullPage.js 21128 * @license MIT licensed 21129 * 21130 * Copyright (C) 2015 alvarotrigo.com - A project by Alvaro Trigo 21131 */ 21132(function(global, factory) { 21133 'use strict'; 21134 if (typeof define === 'function' && define.amd) { 21135 define(['jquery'], function($) { 21136 return factory($, global, global.document, global.Math); 21137 }); 21138 } else if (typeof exports === "object" && exports) { 21139 module.exports = factory(require('jquery'), global, global.document, global.Math); 21140 } else { 21141 factory(jQuery, global, global.document, global.Math); 21142 } 21143})(typeof window !== 'undefined' ? window : this, function($, window, document, Math, undefined) { 21144 'use strict'; 21145 21146 // keeping central set of classnames and selectors 21147 var WRAPPER = 'fullpage-wrapper'; 21148 var WRAPPER_SEL = '.' + WRAPPER; 21149 21150 // slimscroll 21151 var SCROLLABLE = 'fp-scrollable'; 21152 var SCROLLABLE_SEL = '.' + SCROLLABLE; 21153 21154 // util 21155 var RESPONSIVE = 'fp-responsive'; 21156 var NO_TRANSITION = 'fp-notransition'; 21157 var DESTROYED = 'fp-destroyed'; 21158 var ENABLED = 'fp-enabled'; 21159 var VIEWING_PREFIX = 'fp-viewing'; 21160 var ACTIVE = 'active'; 21161 var ACTIVE_SEL = '.' + ACTIVE; 21162 var COMPLETELY = 'fp-completely'; 21163 var COMPLETELY_SEL = '.' + COMPLETELY; 21164 21165 // section 21166 var SECTION_DEFAULT_SEL = '.section'; 21167 var SECTION = 'fp-section'; 21168 var SECTION_SEL = '.' + SECTION; 21169 var SECTION_ACTIVE_SEL = SECTION_SEL + ACTIVE_SEL; 21170 var SECTION_FIRST_SEL = SECTION_SEL + ':first'; 21171 var SECTION_LAST_SEL = SECTION_SEL + ':last'; 21172 var TABLE_CELL = 'fp-tableCell'; 21173 var TABLE_CELL_SEL = '.' + TABLE_CELL; 21174 var AUTO_HEIGHT = 'fp-auto-height'; 21175 var AUTO_HEIGHT_SEL = '.fp-auto-height'; 21176 var NORMAL_SCROLL = 'fp-normal-scroll'; 21177 var NORMAL_SCROLL_SEL = '.fp-normal-scroll'; 21178 21179 // section nav 21180 var SECTION_NAV = 'fp-nav'; 21181 var SECTION_NAV_SEL = '#' + SECTION_NAV; 21182 var SECTION_NAV_TOOLTIP = 'fp-tooltip'; 21183 var SECTION_NAV_TOOLTIP_SEL='.'+SECTION_NAV_TOOLTIP; 21184 var SHOW_ACTIVE_TOOLTIP = 'fp-show-active'; 21185 21186 // slide 21187 var SLIDE_DEFAULT_SEL = '.slide'; 21188 var SLIDE = 'fp-slide'; 21189 var SLIDE_SEL = '.' + SLIDE; 21190 var SLIDE_ACTIVE_SEL = SLIDE_SEL + ACTIVE_SEL; 21191 var SLIDES_WRAPPER = 'fp-slides'; 21192 var SLIDES_WRAPPER_SEL = '.' + SLIDES_WRAPPER; 21193 var SLIDES_CONTAINER = 'fp-slidesContainer'; 21194 var SLIDES_CONTAINER_SEL = '.' + SLIDES_CONTAINER; 21195 var TABLE = 'fp-table'; 21196 21197 // slide nav 21198 var SLIDES_NAV = 'fp-slidesNav'; 21199 var SLIDES_NAV_SEL = '.' + SLIDES_NAV; 21200 var SLIDES_NAV_LINK_SEL = SLIDES_NAV_SEL + ' a'; 21201 var SLIDES_ARROW = 'fp-controlArrow'; 21202 var SLIDES_ARROW_SEL = '.' + SLIDES_ARROW; 21203 var SLIDES_PREV = 'fp-prev'; 21204 var SLIDES_PREV_SEL = '.' + SLIDES_PREV; 21205 var SLIDES_ARROW_PREV = SLIDES_ARROW + ' ' + SLIDES_PREV; 21206 var SLIDES_ARROW_PREV_SEL = SLIDES_ARROW_SEL + SLIDES_PREV_SEL; 21207 var SLIDES_NEXT = 'fp-next';
21208 var SLIDES_NEXT_SEL = '.' + SLIDES_NEXT; 21209 var SLIDES_ARROW_NEXT = SLIDES_ARROW + ' ' + SLIDES_NEXT; 21210 var SLIDES_ARROW_NEXT_SEL = SLIDES_ARROW_SEL + SLIDES_NEXT_SEL; 21211 21212 var $window = $(window); 21213 var $document = $(document); 21214 21215 // Default options for iScroll.js used when using scrollOverflow 21216 var iscrollOptions = { 21217 scrollbars: true, 21218 mouseWheel: true, 21219 hideScrollbars: false, 21220 fadeScrollbars: false, 21221 disableMouse: true, 21222 interactiveScrollbars: true, 21223 bounce: false, 21224 }; 21225 21226 $.fn.fullpage = function(options) { 21227 //only once my friend! 21228 if($('html').hasClass(ENABLED)){ displayWarnings(); return; } 21229 21230 // common jQuery objects 21231 var $htmlBody = $('html, body'); 21232 var $body = $('body'); 21233 21234 var FP = $.fn.fullpage; 21235 21236 // Creating some defaults, extending them with any options that were provided 21237 options = $.extend({ 21238 //navigation 21239 menu: false, 21240 anchors:[], 21241 lockAnchors: false, 21242 navigation: false, 21243 navigationPosition: 'right', 21244 navigationTooltips: [], 21245 showActiveTooltip: false, 21246 slidesNavigation: false, 21247 slidesNavPosition: 'bottom', 21248 scrollBar: false, 21249 hybrid: false, 21250 21251 //scrolling 21252 css3: true, 21253 scrollingSpeed: 700, 21254 autoScrolling: true, 21255 fitToSection: true, 21256 fitToSectionDelay: 1000, 21257 easing: 'easeInOutCubic', 21258 easingcss3: 'ease', 21259 loopBottom: false, 21260 loopTop: false, 21261 loopHorizontal: true, 21262 continuousVertical: false, 21263 continuousHorizontal: false, 21264 scrollHorizontally: false, 21265 interlockedSlides: false, 21266 dragAndMove: false, 21267 offsetSections: false, 21268 resetSliders: false, 21269 fadingEffect: false, 21270 normalScrollElements: null, 21271 scrollOverflow: false, 21272 scrollOverflowReset: false, 21273 scrollOverflowHandler: iscrollHandler, 21274 scrollOverflowOptions: null, 21275 touchSensitivity: 5, 21276 normalScrollElementTouchThreshold: 5, 21277 bigSectionsDestination: null, 21278 21279 //Accessibility 21280 keyboardScrolling: true, 21281 animateAnchor: true, 21282 recordHistory: true, 21283 21284 //design 21285 controlArrows: true, 21286 controlArrowColor: '#fff', 21287 verticalCentered: true, 21288 sectionsColor : [], 21289 paddingTop: 0, 21290 paddingBottom: 0, 21291 fixedElements: null, 21292 responsive: 0, //backwards compabitility with responsiveWiddth 21293 responsiveWidth: 0, 21294 responsiveHeight: 0, 21295 responsiveSlides: false, 21296 parallax: false, 21297 parallaxOptions: { 21298 type: 'reveal', 21299 percentage: 62, 21300 property: 'translate' 21301 }, 21302 21303 //Custom selectors 21304 sectionSelector: SECTION_DEFAULT_SEL, 21305 slideSelector: SLIDE_DEFAULT_SEL, 21306 21307 //events 21308 afterLoad: null, 21309 onLeave: null, 21310 afterRender: null, 21311 afterResize: null, 21312 afterReBuild: null, 21313 afterSlideLoad: null, 21314 onSlideLeave: null, 21315 afterResponsive: null, 21316 21317 lazyLoading: true 21318 }, options); 21319 21320 //flag to avoid very fast sliding for landscape sliders 21321 var slideMoving = false; 21322 21323 var isTouchDevice = navigator.userAgent.match(/(iPhone|iPod|iPad|Android|playbook|silk|BlackBerry|BB10|Windows Phone|Tizen|Bada|webOS|IEMobile|Opera Mini)/); 21324 var isTouch = (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0) || (navigator.maxTouchPoints)); 21325 var container = $(this); 21326 var windowsHeight = $window.height(); 21327 var isResizing = false; 21328 var isWindowFocused = true; 21329 var lastScrolledDestiny; 21330 var lastScrolledSlide; 21331 var canScroll = true; 21332 var scrollings = []; 21333 var controlPressed; 21334 var startingSection; 21335 var isScrollAllowed = {}; 21336 isScrollAllowed.m = { 'up':true, 'down':true, 'left':true, 'right':true }; 21337 isScrollAllowed.k = $.extend(true,{}, isScrollAllowed.m); 21338 var MSPointer = getMSPointer(); 21339 var events = { 21340 touchmove: 'ontouchmove' in window ? 'touchmove' : MSPointer.move, 21341 touchstart: 'ontouchstart' in window ? 'touchstart' : MSPointer.down 21342 }; 21343 21344 //cheks for passive event support 21345 //added by Uncode from new fullPage updates 21346 var g_supportsPassive = false;
21347 try { 21348 var opts = Object.defineProperty({}, 'passive', { 21349 get: function() { 21350 g_supportsPassive = true; 21351 } 21352 }); 21353 window.addEventListener("testPassive", null, opts); 21354 window.removeEventListener("testPassive", null, opts); 21355 } catch (e) {} 21356 21357 //timeouts 21358 var resizeId; 21359 var afterSectionLoadsId; 21360 var afterSlideLoadsId; 21361 var scrollId; 21362 var scrollId2; 21363 var keydownId; 21364 var originals = $.extend(true, {}, options); //deep copy 21365 21366 //Uncode addition 21367 var $masthead = $('#masthead'); 21368 var hideMenu = !$('body').hasClass('vmenu') && $('body').hasClass('uncode-fp-menu-hide') ? true : false; 21369 var menuHeight = $masthead.hasClass('menu-transparent') || hideMenu ? 0 : UNCODE.menuHeight; 21370 var bodyBorder = UNCODE.bodyBorder; 21371 var adminBarHeight = UNCODE.adminBarHeight; 21372 21373 displayWarnings(); 21374 21375 //fixing bug in iScroll with links: https://github.com/cubiq/iscroll/issues/783 21376 iscrollOptions.click = isTouch; // see #2035 21377 21378 //extending iScroll options with the user custom ones 21379 iscrollOptions = $.extend(iscrollOptions, options.scrollOverflowOptions); 21380 21381 //easeInOutCubic animation included in the plugin 21382 $.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;}}); 21383 21384 /** 21385 * Sets the autoScroll option. 21386 * It changes the scroll bar visibility and the history of the site as a result. 21387 */ 21388 function setAutoScrolling(value, type){ 21389 //removing the transformation 21390 if(!value){ 21391 silentScroll(0); 21392 } 21393 21394 setVariableState('autoScrolling', value, type); 21395 21396 var element = $(SECTION_ACTIVE_SEL); 21397 21398 if(options.autoScrolling && !options.scrollBar){ 21399 $htmlBody.css({ 21400 'overflow' : 'hidden !important', 21401 'height' : '100%' 21402 }); 21403 21404 //Uncode addition 21405 //setRecordHistory(originals.recordHistory, 'internal'); 21406 21407 //for IE touch devices 21408 container.css({ 21409 '-ms-touch-action': 'none', 21410 'touch-action': 'none' 21411 }); 21412 21413 if(element.length){ 21414 //moving the container up 21415 silentScroll(element.position().top); 21416 } 21417 21418 }else{ 21419 $htmlBody.css({ 21420 'overflow' : 'visible !important', 21421 'height' : 'initial' 21422 }); 21423 21424 //Uncode addition 21425 //setRecordHistory(false, 'internal'); 21426 21427 //for IE touch devices 21428 container.css({ 21429 '-ms-touch-action': '', 21430 'touch-action': '' 21431 }); 21432 21433 //scrolling the page to the section with no animation 21434 if (element.length) { 21435 $htmlBody.scrollTop(element.position().top); 21436 } 21437 } 21438 } 21439 21440 /** 21441 * Defines wheter to record the history for each hash change in the URL. 21442 */ 21443 function setRecordHistory(value, type){ 21444 setVariableState('recordHistory', value, type); 21445 } 21446 21447 /** 21448 * Defines the scrolling speed 21449 */ 21450 function setScrollingSpeed(value, type){ 21451 setVariableState('scrollingSpeed', value, type); 21452 } 21453 21454 /** 21455 * Sets fitToSection 21456 */ 21457 function setFitToSection(value, type){ 21458 setVariableState('fitToSection', value, type); 21459 } 21460 21461 /** 21462 * Sets lockAnchors 21463 */ 21464 function setLockAnchors(value){ 21465 options.lockAnchors = value; 21466 } 21467 21468 /** 21469 * Adds or remove the possiblity of scrolling through sections by using the mouse wheel or the trackpad. 21470 */ 21471 function setMouseWheelScrolling(value){ 21472 if(value){ 21473 addMouseWheelHandler(); 21474 addMiddleWheelHandler(); 21475 }else{ 21476 removeMouseWheelHandler(); 21477 removeMiddleWheelHandler(); 21478 } 21479 } 21480 21481 /** 21482 * Adds or remove the possibility of scrolling through sections by using the mouse wheel/trackpad or touch gestures. 21483 * Optionally a second parameter can be used to specify the direction for which the action will be applied. 21484 * 21485 * @param directions string containing the direction or directions separated by comma. 21486 */ 21487 function setAllowScrolling(value, directions){ 21488 if(typeof directions !== 'undefined'){ 21489 directions = directions.replace(/ /g,'').split(','); 21490 21491 $.each(directions, function (index, direction){ 21492 setIsScrollAllowed(value, direction, 'm'); 21493 }); 21494 } 21495 else if(value){ 21496 setMouseWheelScrolling(true); 21497 addTouchHandler(); 21498 }else{ 21499 setMouseWheelScrolling(false); 21500 removeTouchHandler(); 21501 } 21502 } 21503 21504 /** 21505 * Adds or remove the possibility of scrolling through sections by using the keyboard arrow keys 21506 */ 21507 function setKeyboardScrolling(value, directions){ 21508 if(typeof directions !== 'undefined'){ 21509 directions = directions.replace(/ /g,'').split(','); 21510 21511 $.each(directions, function (index, direction){ 21512 setIsScrollAllowed(value, direction, 'k'); 21513 }); 21514 }else{ 21515 options.keyboardScrolling = value; 21516 } 21517 } 21518 21519 /** 21520 * Moves the page up one section. 21521 */ 21522 function moveSectionUp(){ 21523 var prev = $(SECTION_ACTIVE_SEL).prev(SECTION_SEL); 21524 21525 //looping to the bottom if there's no more sections above 21526 if (!prev.length && (options.loopTop || options.continuousVertical)) {
21527 prev = $(SECTION_SEL).last(); 21528 } 21529 21530 if (prev.length) { 21531 scrollPage(prev, null, true); 21532 } 21533 } 21534 21535 /** 21536 * Moves the page down one section. 21537 */ 21538 function moveSectionDown(){ 21539 var next = $(SECTION_ACTIVE_SEL).next(SECTION_SEL); 21540 21541 //looping to the top if there's no more sections below 21542 if(!next.length && 21543 (options.loopBottom || options.continuousVertical)){ 21544 next = $(SECTION_SEL).first(); 21545 } 21546 21547 if(next.length){ 21548 scrollPage(next, null, false); 21549 } 21550 } 21551 21552 /** 21553 * Moves the page to the given section and slide with no animation. 21554 * Anchors or index positions can be used as params. 21555 */ 21556 function silentMoveTo(sectionAnchor, slideAnchor){ 21557 setScrollingSpeed (0, 'internal'); 21558 moveTo(sectionAnchor, slideAnchor); 21559 setScrollingSpeed (originals.scrollingSpeed, 'internal'); 21560 } 21561 21562 /** 21563 * Moves the page to the given section and slide. 21564 * Anchors or index positions can be used as params. 21565 */ 21566 function moveTo(sectionAnchor, slideAnchor){ 21567 var destiny = getSectionByAnchor(sectionAnchor); 21568 21569 if (typeof slideAnchor !== 'undefined'){ 21570 scrollPageAndSlide(sectionAnchor, slideAnchor); 21571 }else if(destiny.length > 0){ 21572 scrollPage(destiny); 21573 } 21574 } 21575 21576 /** 21577 * Slides right the slider of the active section. 21578 * Optional `section` param. 21579 */ 21580 function moveSlideRight(section){ 21581 moveSlide('right', section); 21582 } 21583 21584 /** 21585 * Slides left the slider of the active section. 21586 * Optional `section` param. 21587 */ 21588 function moveSlideLeft(section){ 21589 moveSlide('left', section); 21590 } 21591 21592 /** 21593 * When resizing is finished, we adjust the slides sizes and positions 21594 */ 21595 function reBuild(resizing){ 21596 if(container.hasClass(DESTROYED)){ return; } //nothing to do if the plugin was destroyed 21597 21598 isResizing = true; 21599 21600 windowsHeight = $window.height(); //updating global var 21601 21602 $(SECTION_SEL).each(function(){ 21603 var slidesWrap = $(this).find(SLIDES_WRAPPER_SEL); 21604 var slides = $(this).find(SLIDE_SEL); 21605 21606 //adjusting the height of the table-cell for IE and Firefox 21607 if(options.verticalCentered){ 21608 $(this).find(TABLE_CELL_SEL).css('height', getTableHeight($(this)) + 'px'); 21609 } 21610 21611 $(this).css('height', windowsHeight + 'px'); 21612 21613 //resizing the scrolling divs 21614 if(options.scrollOverflow){ 21615 if(slides.length){ 21616 slides.each(function(){ 21617 createScrollBar($(this)); 21618 }); 21619 }else{ 21620 createScrollBar($(this)); 21621 } 21622 } 21623 21624 //adjusting the position fo the FULL WIDTH slides... 21625 if (slides.length > 1) { 21626 landscapeScroll(slidesWrap, slidesWrap.find(SLIDE_ACTIVE_SEL)); 21627 } 21628 }); 21629 21630 var activeSection = $(SECTION_ACTIVE_SEL); 21631 var sectionIndex = activeSection.index(SECTION_SEL); 21632 21633 //isn't it the first section? 21634 if(sectionIndex){ 21635 //adjusting the position for the current section 21636 silentMoveTo(sectionIndex + 1); 21637 } 21638 21639 isResizing = false; 21640 $.isFunction( options.afterResize ) && resizing && options.afterResize.call(container); 21641 $.isFunction( options.afterReBuild ) && !resizing && options.afterReBuild.call(container); 21642 } 21643 21644 /** 21645 * Turns fullPage.js to normal scrolling mode when the viewport `width` or `height` 21646 * are smaller than the set limit values. 21647 */ 21648 function setResponsive(active){ 21649 var isResponsive = $body.hasClass(RESPONSIVE); 21650 21651 if(active){ 21652 if(!isResponsive){ 21653 setAutoScrolling(false, 'internal'); 21654 setFitToSection(false, 'internal'); 21655 $(SECTION_NAV_SEL).hide(); 21656 $body.addClass(RESPONSIVE); 21657 $.isFunction( options.afterResponsive ) && options.afterResponsive.call( container, active); 21658 } 21659 } 21660 else if(isResponsive){ 21661 setAutoScrolling(originals.autoScrolling, 'internal'); 21662 setFitToSection(originals.autoScrolling, 'internal'); 21663 $(SECTION_NAV_SEL).show(); 21664 $body.removeClass(RESPONSIVE); 21665 $.isFunction( options.afterResponsive ) && options.afterResponsive.call( container, active); 21666 } 21667 } 21668 21669 if($(this).length){ 21670 //public functions 21671 FP.setAutoScrolling = setAutoScrolling; 21672 FP.setRecordHistory = setRecordHistory; 21673 FP.setScrollingSpeed = setScrollingSpeed; 21674 FP.setFitToSection = setFitToSection; 21675 FP.setLockAnchors = setLockAnchors; 21676 FP.setMouseWheelScrolling = setMouseWheelScrolling; 21677 FP.setAllowScrolling = setAllowScrolling; 21678 FP.setKeyboardScrolling = setKeyboardScrolling; 21679 FP.moveSectionUp = moveSectionUp; 21680 FP.moveSectionDown = moveSectionDown; 21681 FP.silentMoveTo = silentMoveTo; 21682 FP.moveTo = moveTo; 21683 FP.moveSlideRight = moveSlideRight; 21684 FP.moveSlideLeft = moveSlideLeft; 21685 FP.fitToSection = fitToSection; 21686 FP.reBuild = reBuild; 21687 FP.setResponsive = setResponsive; 21688 FP.destroy = destroy; 21689 21690 init(); 21691 21692 bindEvents(); 21693 } 21694
21695 function init(){ 21696 //if css3 is not supported, it will use jQuery animations 21697 if(options.css3){ 21698 options.css3 = support3d(); 21699 } 21700 21701 options.scrollBar = options.scrollBar || options.hybrid; 21702 21703 setOptionsFromDOM(); 21704 prepareDom(); 21705 setAllowScrolling(true); 21706 setAutoScrolling(options.autoScrolling, 'internal'); 21707 responsive(); 21708 21709 //setting the class for the body element 21710 setBodyClass(); 21711 21712 //Uncode addition 21713 // if(document.readyState === 'complete'){ 21714 // scrollToAnchor(); 21715 // } 21716 // $window.on('load', scrollToAnchor); 21717 } 21718 21719 function bindEvents(){ 21720 $window 21721 //when scrolling... 21722 //.on('scroll', scrollHandler) 21723 21724 //detecting any change on the URL to scroll to the given anchor link 21725 //(a way to detect back history button as we play with the hashes on the URL) 21726 .on('hashchange', hashChangeHandler) 21727 21728 //when opening a new tab (ctrl + t), `control` won't be pressed when coming back. 21729 .blur(blurHandler) 21730 21731 //when resizing the site, we adjust the heights of the sections, slimScroll... 21732 .resize(resizeHandler); 21733 21734 $document 21735 //Sliding with arrow keys, both, vertical and horizontal 21736 .keydown(keydownHandler) 21737 21738 //to prevent scrolling while zooming 21739 .keyup(keyUpHandler) 21740 21741 //Scrolls to the section when clicking the navigation bullet 21742 .on('click touchstart', SECTION_NAV_SEL + ' a', sectionBulletHandler) 21743 21744 //Scrolls the slider to the given slide destination for the given section 21745 .on('click touchstart', SLIDES_NAV_LINK_SEL, slideBulletHandler) 21746 21747 .on('click', SECTION_NAV_TOOLTIP_SEL, tooltipTextHandler); 21748 21749 //Scrolling horizontally when clicking on the slider controls. 21750 $(SECTION_SEL).on('click touchstart', SLIDES_ARROW_SEL, slideArrowHandler); 21751 21752 /** 21753 * Applying normalScroll elements. 21754 * Ignoring the scrolls over the specified selectors. 21755 */ 21756 if(options.normalScrollElements){ 21757 $document.on('mouseenter', options.normalScrollElements, function () { 21758 setMouseWheelScrolling(false); 21759 }); 21760 21761 $document.on('mouseleave', options.normalScrollElements, function(){ 21762 setMouseWheelScrolling(true); 21763 }); 21764 } 21765 } 21766 21767 /** 21768 * Setting options from DOM elements if they are not provided. 21769 */ 21770 function setOptionsFromDOM(){ 21771 var sections = container.find(options.sectionSelector); 21772 21773 //no anchors option? Checking for them in the DOM attributes 21774 if(!options.anchors.length){ 21775 options.anchors = sections.filter('[data-anchor]').map(function(){ 21776 return $(this).data('anchor').toString(); 21777 }).get(); 21778 } 21779 21780 //no tooltips option? Checking for them in the DOM attributes 21781 if(!options.navigationTooltips.length){ 21782 options.navigationTooltips = sections.filter('[data-tooltip]').map(function(){ 21783 return $(this).data('tooltip').toString(); 21784 }).get(); 21785 } 21786 } 21787 21788 /** 21789 * Works over the DOM structure to set it up for the current fullpage options. 21790 */ 21791 function prepareDom(){ 21792 container.css({ 21793 'height': '100%', 21794 'position': 'relative' 21795 }); 21796 21797 //adding a class to recognize the container internally in the code 21798 container.addClass(WRAPPER); 21799 $('html').addClass(ENABLED); 21800 21801 windowsHeight = $window.height(); 21802 21803 container.removeClass(DESTROYED); //in case it was destroyed before initializing it again 21804 21805 addInternalSelectors(); 21806 21807 //styling the sections / slides / menu 21808 $(SECTION_SEL).each(function(index){ 21809 var section = $(this); 21810 var slides = section.find(SLIDE_SEL); 21811 var numSlides = slides.length; 21812 21813 styleSection(section, index); 21814 styleMenu(section, index); 21815 21816 // if there's any slide 21817 if (numSlides > 0) { 21818 styleSlides(section, slides, numSlides); 21819 }else{ 21820 if(options.verticalCentered){ 21821 addTableClass(section); 21822 } 21823 } 21824 }); 21825 21826 //fixed elements need to be moved out of the plugin container due to problems with CSS3. 21827 if(options.fixedElements && options.css3){ 21828 $(options.fixedElements).appendTo($body); 21829 } 21830 21831 //vertical centered of the navigation + active bullet 21832 if(options.navigation){ 21833 addVerticalNavigation(); 21834 } 21835 21836 enableYoutubeAPI(); 21837 21838 if(options.scrollOverflow){ 21839 if(document.readyState === 'complete'){ 21840 createScrollBarHandler(); 21841 } 21842 //after DOM and images are loaded 21843 $window.on('load', createScrollBarHandler); 21844 }else{ 21845 afterRenderActions(); 21846 } 21847 } 21848 21849 /** 21850 * Styles the horizontal slides for a section. 21851 */ 21852 function styleSlides(section, slides, numSlides){ 21853 var sliderWidth = numSlides * 100; 21854 var slideWidth = 100 / numSlides; 21855 21856 slides.wrapAll('<div class="' + SLIDES_CONTAINER + '" />'); 21857 slides.parent().wrap('<div class="' + SLIDES_WRAPPER + '" />'); 21858 21859 section.find(SLIDES_CONTAINER_SEL).css('width', sliderWidth + '%'); 21860 21861 if(numSlides > 1){ 21862 if(options.controlArrows){ 21863 createSlideArrows(section); 21864 } 21865 21866 if(options.slidesNavigation){ 21867 addSlidesNavigation(section, numSlides); 21868 } 21869 } 21870 21871 slides.each(function(index) { 21872 $(this).css('width', slideWidth + '%'); 21873 21874 if(options.verticalCentered){ 21875 addTableClass($(this)); 21876 } 21877 }); 21878 21879 var startingSlide = section.find(SLIDE_ACTIVE_SEL); 21880 21881 //if the slide won't be an starting point, the default will be the first one 21882 //the active section isn't the first one? Is not the first slide of the first section? Then we load that section/sl
21882ide by default. 21883 if( startingSlide.length && ($(SECTION_ACTIVE_SEL).index(SECTION_SEL) !== 0 || ($(SECTION_ACTIVE_SEL).index(SECTION_SEL) === 0 && startingSlide.index() !== 0))){ 21884 silentLandscapeScroll(startingSlide, 'internal'); 21885 }else{ 21886 slides.eq(0).addClass(ACTIVE); 21887 } 21888 } 21889 21890 /** 21891 * Styling vertical sections 21892 */ 21893 function styleSection(section, index){ 21894 //if no active section is defined, the 1st one will be the default one 21895 if(!index && $(SECTION_ACTIVE_SEL).length === 0) { 21896 section.addClass(ACTIVE); 21897 } 21898 startingSection = $(SECTION_ACTIVE_SEL); 21899 21900 section.css('height', windowsHeight + 'px'); 21901 21902 if(options.paddingTop){ 21903 section.css('padding-top', options.paddingTop); 21904 } 21905 21906 if(options.paddingBottom){ 21907 section.css('padding-bottom', options.paddingBottom); 21908 } 21909 21910 if (typeof options.sectionsColor[index] !== 'undefined') { 21911 section.css('background-color', options.sectionsColor[index]); 21912 } 21913 21914 if (typeof options.anchors[index] !== 'undefined') { 21915 section.attr('data-anchor', options.anchors[index]); 21916 } 21917 } 21918 21919 /** 21920 * Sets the data-anchor attributes to the menu elements and activates the current one. 21921 */ 21922 function styleMenu(section, index){ 21923 if (typeof options.anchors[index] !== 'undefined') { 21924 //activating the menu / nav element on load 21925 if(section.hasClass(ACTIVE)){ 21926 activateMenuAndNav(options.anchors[index], index); 21927 } 21928 } 21929 21930 //moving the menu outside the main container if it is inside (avoid problems with fixed positions when using CSS3 tranforms) 21931 if(options.menu && options.css3 && $(options.menu).closest(WRAPPER_SEL).length){ 21932 $(options.menu).appendTo($body); 21933 } 21934 } 21935 21936 /** 21937 * Adds internal classes to be able to provide customizable selectors 21938 * keeping the link with the style sheet. 21939 */ 21940 function addInternalSelectors(){ 21941 container.find(options.sectionSelector).addClass(SECTION); 21942 container.find(options.slideSelector).addClass(SLIDE); 21943 } 21944 21945 /** 21946 * Creates the control arrows for the given section 21947 */ 21948 function createSlideArrows(section){ 21949 section.find(SLIDES_WRAPPER_SEL).after('<div class="' + SLIDES_ARROW_PREV + '"></div><div class="' + SLIDES_ARROW_NEXT + '"></div>'); 21950 21951 if(options.controlArrowColor!='#fff'){ 21952 section.find(SLIDES_ARROW_NEXT_SEL).css('border-color', 'transparent transparent transparent '+options.controlArrowColor); 21953 section.find(SLIDES_ARROW_PREV_SEL).css('border-color', 'transparent '+ options.controlArrowColor + ' transparent transparent'); 21954 } 21955 21956 if(!options.loopHorizontal){ 21957 section.find(SLIDES_ARROW_PREV_SEL).hide(); 21958 } 21959 } 21960 21961 /** 21962 * Creates a vertical navigation bar. 21963 */ 21964 function addVerticalNavigation(){ 21965 $body.append('<div id="' + SECTION_NAV + '"><ul></ul></div>'); 21966 var nav = $(SECTION_NAV_SEL); 21967 21968 nav.addClass(function() { 21969 return options.showActiveTooltip ? SHOW_ACTIVE_TOOLTIP + ' ' + options.navigationPosition : options.navigationPosition; 21970 }); 21971 21972 for (var i = 0; i < $(SECTION_SEL).length; i++) { 21973 var link = ''; 21974 if (options.anchors.length) { 21975 link = options.anchors[i]; 21976 } 21977 21978 var li = '<li><a href="#' + link + '"><span></span></a>'; 21979 21980 // Only add tooltip if needed (defined by user) 21981 var tooltip = options.navigationTooltips[i]; 21982 21983 if (typeof tooltip !== 'undefined' && tooltip !== '') { 21984 li += '<div class="' + SECTION_NAV_TOOLTIP + ' ' + options.navigationPosition + '">' + tooltip + '</div>'; 21985 } 21986 21987 li += '</li>'; 21988 21989 nav.find('ul').append(li); 21990 } 21991 21992 //centering it vertically 21993 $(SECTION_NAV_SEL).css('margin-top', '-' + ($(SECTION_NAV_SEL).height()/2) + 'px'); 21994 21995 //activating the current active section 21996 $(SECTION_NAV_SEL).find('li').eq($(SECTION_ACTIVE_SEL).index(SECTION_SEL)).find('a').addClass(ACTIVE); 21997 } 21998 21999 /** 22000 * Creates the slim scroll scrollbar for the sections and slides inside them. 22001 */ 22002 function createScrollBarHandler(){ 22003 $(SECTION_SEL).each(function(){ 22004 var slides = $(this).find(SLIDE_SEL); 22005 22006 if(slides.length){ 22007 slides.each(function(){ 22008 createScrollBar($(this)); 22009 }); 22010 }else{ 22011 createScrollBar($(this)); 22012 } 22013 22014 }); 22015 afterRenderActions(); 22016 } 22017 22018 /*
22019 * Enables the Youtube videos API so we can control their flow if necessary. 22020 */ 22021 function enableYoutubeAPI(){ 22022 container.find('iframe[src*="youtube.com/embed/"]').each(function(){ 22023 addURLParam($(this), 'enablejsapi=1'); 22024 }); 22025 } 22026 22027 /** 22028 * Adds a new parameter and its value to the `src` of a given element 22029 */ 22030 function addURLParam(element, newParam){ 22031 var originalSrc = element.attr('src'); 22032 element.attr('src', originalSrc + getUrlParamSign(originalSrc) + newParam); 22033 } 22034 22035 /* 22036 * Returns the prefix sign to use for a new parameter in an existen URL. 22037 * 22038 * @return {String} ? | & 22039 */ 22040 function getUrlParamSign(url){ 22041 return ( !/\?/.test( url ) ) ? '?' : '&'; 22042 } 22043 22044 /** 22045 * Actions and callbacks to fire afterRender 22046 */ 22047 function afterRenderActions(){ 22048 var section = $(SECTION_ACTIVE_SEL); 22049 22050 section.addClass(COMPLETELY); 22051 22052 if(options.scrollOverflowHandler.afterRender){ 22053 options.scrollOverflowHandler.afterRender(section); 22054 } 22055 lazyLoad(section); 22056 playMedia(section); 22057 options.scrollOverflowHandler.afterLoad(); 22058 22059 if(isDestinyTheStartingSection()){ 22060 $.isFunction( options.afterLoad ) && options.afterLoad.call(section, section.data('anchor'), (section.index(SECTION_SEL) + 1)); 22061 } 22062 22063 $.isFunction( options.afterRender ) && options.afterRender.call(container); 22064 } 22065 22066 /** 22067 * Determines if the URL anchor destiny is the starting section (the one using 'active' class before initialization) 22068 */ 22069 function isDestinyTheStartingSection(){ 22070 var anchors = window.location.hash.replace('#', '').split('/'); 22071 var destinationSection = getSectionByAnchor(decodeURIComponent(anchors[0])); 22072 22073 return !destinationSection.length || destinationSection.length && destinationSection.index() === startingSection.index(); 22074 } 22075 22076 22077 var isScrolling = false; 22078 var lastScroll = 0; 22079 22080 //when scrolling... 22081 function scrollHandler(){ 22082 var currentSection; 22083 22084 if(!options.autoScrolling || options.scrollBar){ 22085 var currentScroll = $window.scrollTop(); 22086 var scrollDirection = getScrollDirection(currentScroll); 22087 var visibleSectionIndex = 0; 22088 var screen_mid = currentScroll + ($window.height() / 2.0); 22089 var isAtBottom = $body.height() - $window.height() === currentScroll; 22090 var sections = document.querySelectorAll(SECTION_SEL); 22091 22092 //when using `auto-height` for a small last section it won't be centered in the viewport 22093 if(isAtBottom){ 22094 visibleSectionIndex = sections.length - 1; 22095 } 22096 //is at top? when using `auto-height` for a small first section it won't be centered in the viewport 22097 else if(!currentScroll){ 22098 visibleSectionIndex = 0; 22099 } 22100 22101 //taking the section which is showing more content in the viewport 22102 else{ 22103 for (var i = 0; i < sections.length; ++i) { 22104 var section = sections[i]; 22105 22106 // Pick the the last section which passes the middle line of the screen. 22107 if (section.offsetTop <= screen_mid) 22108 { 22109 visibleSectionIndex = i; 22110 } 22111 } 22112 } 22113 22114 if(isCompletelyInViewPort(scrollDirection)){ 22115 if(!$(SECTION_ACTIVE_SEL).hasClass(COMPLETELY)){ 22116 $(SECTION_ACTIVE_SEL).addClass(COMPLETELY).siblings().removeClass(COMPLETELY); 22117 } 22118 } 22119 22120 //geting the last one, the current one on the screen 22121 currentSection = $(sections).eq(visibleSectionIndex); 22122 22123 //setting the visible section as active when manually scrolling 22124 //executing only once the first time we reach the section 22125 if(!currentSection.hasClass(ACTIVE)){ 22126 isScrolling = true; 22127 var leavingSection = $(SECTION_ACTIVE_SEL); 22128 var leavingSectionIndex = leavingSection.index(SECTION_SEL) + 1; 22129 var yMovement = getYmovement(currentSection); 22130 var anchorLink = currentSection.data('anchor'); 22131 var sectionIndex = currentSection.index(SECTION_SEL) + 1; 22132 var activeSlide = currentSection.find(SLIDE_ACTIVE_SEL); 22133 var slideIndex; 22134 var slideAnchorLink; 22135 22136 if(activeSlide.length){ 22137 slideAnchorLink = activeSlide.data('anchor'); 22138 slideIndex = activeSlide.index(); 22139 } 22140 22141 if(canScroll){ 22142 currentSection.addClass(ACTIVE).siblings().removeClass(ACTIVE); 22143 22144 $.isFunction( options.onLeave ) && options.onLeave.call( leavingSection, leavingSectionIndex, sectionIndex, yMovement); 22145 $.isFunction( options.afterLoad ) && options.afterLoad.call( currentSection, anchorLink, sectionIndex); 22146 22147 stopMedia(leavingSection); 22148 lazyLoad(currentSection); 22149 playMedia(currentSection); 22150 22151 activateMenuAndNav(anchorLink, sectionIndex - 1); 22152 22153 if(options.anchors.length){ 22154 //needed to enter in hashChange event when using the menu with anchor links 22155 lastScrolledDestiny = anchorLink; 22156 } 22157 setState(slideIndex, slideAnchorLink, anchorLink, sectionIndex); 22158 } 22159 22160 //small timeout in order to avoid entering in hashChange event when scrolling is not finished yet 22161 clearTimeout(scrollId); 22162 scrollId = setTimeout(function(){ 22163 isScrolling = false;
22164 }, 100); 22165 } 22166 22167 if(options.fitToSection){ 22168 //for the auto adjust of the viewport to fit a whole section 22169 clearTimeout(scrollId2); 22170 22171 scrollId2 = setTimeout(function(){ 22172 //checking it again in case it changed during the delay 22173 if(options.fitToSection){ 22174 fitToSection(); 22175 } 22176 }, options.fitToSectionDelay); 22177 } 22178 } 22179 } 22180 22181 /** 22182 * Fits the site to the nearest active section 22183 */ 22184 function fitToSection(){ 22185 //checking fitToSection again in case it was set to false before the timeout delay 22186 if(canScroll){ 22187 //allows to scroll to an active section and 22188 //if the section is already active, we prevent firing callbacks 22189 isResizing = true; 22190 22191 scrollPage($(SECTION_ACTIVE_SEL)); 22192 isResizing = false; 22193 } 22194 } 22195 22196 /** 22197 * Determines whether the active section has seen in its whole or not. 22198 */ 22199 function isCompletelyInViewPort(movement){ 22200 var top = $(SECTION_ACTIVE_SEL).position().top; 22201 var bottom = top + $window.height(); 22202 22203 if(movement == 'up'){ 22204 return bottom >= ($window.scrollTop() + $window.height()); 22205 } 22206 return top <= $window.scrollTop(); 22207 } 22208 22209 /** 22210 * Gets the directon of the the scrolling fired by the scroll event. 22211 */ 22212 function getScrollDirection(currentScroll){ 22213 var direction = currentScroll > lastScroll ? 'down' : 'up'; 22214 22215 lastScroll = currentScroll; 22216 22217 //needed for auto-height sections to determine if we want to scroll to the top or bottom of the destination 22218 previousDestTop = currentScroll; 22219 22220 return direction; 22221 } 22222 22223 /** 22224 * Determines the way of scrolling up or down: 22225 * by 'automatically' scrolling a section or by using the default and normal scrolling. 22226 */ 22227 function scrolling(type, scrollable){ 22228 if (!isScrollAllowed.m[type]){ 22229 return; 22230 } 22231 var check = (type === 'down') ? 'bottom' : 'top'; 22232 var scrollSection = (type === 'down') ? moveSectionDown : moveSectionUp; 22233 22234 if(scrollable.length > 0 ){ 22235 //is the scrollbar at the start/end of the scroll? 22236 if(options.scrollOverflowHandler.isScrolled(check, scrollable)){ 22237 scrollSection(); 22238 }else{ 22239 return true; 22240 } 22241 }else{ 22242 // moved up/down 22243 scrollSection(); 22244 } 22245 } 22246 22247 /* 22248 * Preventing bouncing in iOS #2285 22249 */ 22250 function preventBouncing(event){ 22251 var e = event.originalEvent; 22252 if(!checkParentForNormalScrollElement(event.target) && options.autoScrolling && isReallyTouch(e) && isScrollAllowed.m.up){ 22253 //preventing the easing on iOS devices 22254 event.preventDefault(); 22255 } 22256 } 22257 22258 var touchStartY = 0; 22259 var touchStartX = 0; 22260 var touchEndY = 0; 22261 var touchEndX = 0; 22262 22263 /* Detecting touch events 22264 22265 * As we are changing the top property of the page on scrolling, we can not use the traditional way to detect it. 22266 * This way, the touchstart and the touch moves shows an small difference between them which is the 22267 * used one to determine the direction. 22268 */ 22269 function touchMoveHandler(event){ 22270 var e = event.originalEvent; 22271 var activeSection = $(e.target).closest(SECTION_SEL); 22272 22273 // additional: if one of the normalScrollElements isn't within options.normalScrollElementTouchThreshold hops up the DOM chain 22274 if (!checkParentForNormalScrollElement(event.target) && isReallyTouch(e) ) { 22275 22276 if(options.autoScrolling){ 22277 //preventing the easing on iOS devices 22278 event.preventDefault(); 22279 } 22280 22281 var scrollable = options.scrollOverflowHandler.scrollable(activeSection); 22282 var touchEvents = getEventsPage(e); 22283 22284 touchEndY = touchEvents.y; 22285 touchEndX = touchEvents.x; 22286 22287 //if movement in the X axys is greater than in the Y and the currect section has slides... 22288 if (activeSection.find(SLIDES_WRAPPER_SEL).length && Math.abs(touchStartX - touchEndX) > (Math.abs(touchStartY - touchEndY))) { 22289 22290 //is the movement greater than the minimum resistance to scroll? 22291 if (!slideMoving && Math.abs(touchStartX - touchEndX) > ($window.outerWidth() / 100 * options.touchSensitivity)) { 22292 if (touchStartX > touchEndX) { 22293 if(isScrollAllowed.m.right){ 22294 moveSlideRight(activeSection); //next 22295 } 22296 } else { 22297 if(isScrollAllowed.m.left){ 22298 moveSlideLeft(activeSection); //prev 22299 } 22300 } 22301 } 22302 } 22303 22304 //vertical scrolling (only when autoScrolling is enabled) 22305 else if(options.autoScrolling && canScroll){ 22306 22307 //is the movement greater than the minimum resistance to scroll? 22308 if (Math.abs(touchStartY - touchEndY) > ($window.height() / 100 * options.touchSensitivity)) { 22309 if (touchStartY > touchEndY) { 22310 scrolling('down', scrollable); 22311 } else if (touchEndY > touchStartY) { 22312 scrolling('up', scrollable); 22313 } 22314 } 22315 } 22316 } 22317 } 22318 22319 /** 22320 * recursive function to loop up the parent nodes to check if one of them exists in options.normalScrollElements 22321 * Currently works well for iOS - Android might need some testing 22322 * @param {Element} el target element / jquery selector (in subsequent nodes) 22323 * @param {int} hop current hop compared to options.normalScrollElementTouchThreshold 22324 * @return {boolean} true if there is a match to options.normalScrollElements 22325 */ 22326 function checkParentForNormalScrollElement (el, hop) { 22327 hop = hop || 0; 22328 var parent = $(el).parent(); 22329 22330 if (hop < options.normalScrollElementTouchThreshold && 22331 parent.is(options.normalScrollElements) ) { 22332 return true; 22333 } else if (hop == options.normalScrollElementTouchThreshold) { 22334 return false;
22335 } else { 22336 return checkParentForNormalScrollElement(parent, ++hop); 22337 } 22338 } 22339 22340 /** 22341 * As IE >= 10 fires both touch and mouse events when using a mouse in a touchscreen 22342 * this way we make sure that is really a touch event what IE is detecting. 22343 */ 22344 function isReallyTouch(e){ 22345 //if is not IE || IE is detecting `touch` or `pen` 22346 return typeof e.pointerType === 'undefined' || e.pointerType != 'mouse'; 22347 } 22348 22349 /** 22350 * Handler for the touch start event. 22351 */ 22352 function touchStartHandler(event){ 22353 var e = event.originalEvent; 22354 22355 //stopping the auto scroll to adjust to a section 22356 if(options.fitToSection){ 22357 $htmlBody.stop(); 22358 } 22359 22360 if(isReallyTouch(e)){ 22361 var touchEvents = getEventsPage(e); 22362 touchStartY = touchEvents.y; 22363 touchStartX = touchEvents.x; 22364 } 22365 } 22366 22367 /** 22368 * Gets the average of the last `number` elements of the given array. 22369 */ 22370 function getAverage(elements, number){ 22371 var sum = 0; 22372 22373 //taking `number` elements from the end to make the average, if there are not enought, 1 22374 var lastElements = elements.slice(Math.max(elements.length - number, 1)); 22375 22376 for(var i = 0; i < lastElements.length; i++){ 22377 sum = sum + lastElements[i]; 22378 } 22379 22380 return Math.ceil(sum/number); 22381 } 22382 22383 /** 22384 * Detecting mousewheel scrolling 22385 * 22386 * http://blogs.sitepointstatic.com/examples/tech/mouse-wheel/index.html 22387 * http://www.sitepoint.com/html5-javascript-mouse-wheel/ 22388 */ 22389 var prevTime = new Date().getTime(); 22390 22391 function MouseWheelHandler(e) { 22392 var curTime = new Date().getTime(); 22393 var isNormalScroll = $(COMPLETELY_SEL).hasClass(NORMAL_SCROLL); 22394 22395 //autoscrolling and not zooming? 22396 if(options.autoScrolling && !controlPressed && !isNormalScroll){ 22397 // cross-browser wheel delta 22398 e = e || window.event; 22399 var value = e.wheelDelta || -e.deltaY || -e.detail; 22400 var delta = Math.max(-1, Math.min(1, value)); 22401 22402 var horizontalDetection = typeof e.wheelDeltaX !== 'undefined' || typeof e.deltaX !== 'undefined'; 22403 var isScrollingVertically = (Math.abs(e.wheelDeltaX) < Math.abs(e.wheelDelta)) || (Math.abs(e.deltaX ) < Math.abs(e.deltaY) || !horizontalDetection); 22404 22405 //Limiting the array to 150 (lets not waste memory!) 22406 if(scrollings.length > 149){ 22407 scrollings.shift(); 22408 } 22409 22410 //keeping record of the previous scrollings 22411 scrollings.push(Math.abs(value)); 22412 22413 //preventing to scroll the site on mouse wheel when scrollbar is present 22414 if(options.scrollBar){ 22415 e.preventDefault ? e.preventDefault() : e.returnValue = false; 22416 } 22417 22418 var activeSection = $(SECTION_ACTIVE_SEL); 22419 var scrollable = options.scrollOverflowHandler.scrollable(activeSection); 22420 22421 //time difference between the last scroll and the current one 22422 var timeDiff = curTime-prevTime; 22423 prevTime = curTime; 22424 22425 //haven't they scrolled in a while? 22426 //(enough to be consider a different scrolling action to scroll another section) 22427 if(timeDiff > 200){ 22428 //emptying the array, we dont care about old scrollings for our averages 22429 scrollings = []; 22430 } 22431 22432 if(canScroll){ 22433 var averageEnd = getAverage(scrollings, 10); 22434 var averageMiddle = getAverage(scrollings, 70); 22435 var isAccelerating = averageEnd >= averageMiddle; 22436 22437 //to avoid double swipes... 22438 if(isAccelerating && isScrollingVertically){ 22439 //scrolling down? 22440 if (delta < 0) { 22441 scrolling('down', scrollable); 22442 22443 //scrolling up? 22444 }else { 22445 scrolling('up', scrollable); 22446 } 22447 } 22448 } 22449 22450 return false;
22451 } 22452 22453 if(options.fitToSection){ 22454 //stopping the auto scroll to adjust to a section 22455 $htmlBody.stop(); 22456 } 22457 } 22458 22459 /** 22460 * Slides a slider to the given direction. 22461 * Optional `section` param. 22462 */ 22463 function moveSlide(direction, section){ 22464 var activeSection = typeof section === 'undefined' ? $(SECTION_ACTIVE_SEL) : section; 22465 var slides = activeSection.find(SLIDES_WRAPPER_SEL); 22466 var numSlides = slides.find(SLIDE_SEL).length; 22467 22468 // more than one slide needed and nothing should be sliding 22469 if (!slides.length || slideMoving || numSlides < 2) { 22470 return; 22471 } 22472 22473 var currentSlide = slides.find(SLIDE_ACTIVE_SEL); 22474 var destiny = null; 22475 22476 if(direction === 'left'){ 22477 destiny = currentSlide.prev(SLIDE_SEL); 22478 }else{ 22479 destiny = currentSlide.next(SLIDE_SEL); 22480 } 22481 22482 //isn't there a next slide in the secuence? 22483 if(!destiny.length){ 22484 //respect loopHorizontal settin 22485 if (!options.loopHorizontal) return; 22486 22487 if(direction === 'left'){ 22488 destiny = currentSlide.siblings(':last'); 22489 }else{ 22490 destiny = currentSlide.siblings(':first'); 22491 } 22492 } 22493 22494 slideMoving = true; 22495 22496 landscapeScroll(slides, destiny, direction); 22497 } 22498 22499 /** 22500 * Maintains the active slides in the viewport 22501 * (Because the `scroll` animation might get lost with some actions, such as when using continuousVertical) 22502 */ 22503 function keepSlidesPosition(){ 22504 $(SLIDE_ACTIVE_SEL).each(function(){ 22505 silentLandscapeScroll($(this), 'internal'); 22506 }); 22507 } 22508 22509 var previousDestTop = 0; 22510 /** 22511 * Returns the destination Y position based on the scrolling direction and 22512 * the height of the section. 22513 */ 22514 function getDestinationPosition(element){ 22515 var elemPosition = element.position(); 22516 22517 //top of the desination will be at the top of the viewport 22518 var position = elemPosition.top; 22519 var isScrollingDown = elemPosition.top > previousDestTop; 22520 var sectionBottom = position - windowsHeight + element.outerHeight(); 22521 var bigSectionsDestination = options.bigSectionsDestination; 22522 22523 //Uncode addition 22524 var containerH = container.outerHeight(); 22525 var containerPosition = container.offset(); 22526 22527 //########### Commented by Uncode - START ########### 22528 //is the destination element bigger than the viewport? 22529 // if(element.outerHeight() > windowsHeight){ 22530 // //scrolling up? 22531 // if(!isScrollingDown && !bigSectionsDestination || bigSectionsDestination === 'bottom' ){ 22532 // position = sectionBottom; 22533 // } 22534 // } 22535 22536 // //sections equal or smaller than the viewport height && scrolling down? || is resizing and its in the last section 22537 // else if(isScrollingDown || (isResizing && element.is(':last-child')) ){ 22538 // //The bottom of the destination will be at the bottom of the viewport 22539 // position = sectionBottom; 22540 // } 22541 //########### Commented by Uncode - END ########### 22542 22543 //Uncode addition 22544 if ( !$masthead.hasClass('menu-transparent') && $('body').hasClass('uncode-fp-menu-shrink') && !element.is(':first-child') ) 22545 position += 18; 22546 if ( ( containerH + menuHeight + bodyBorder + adminBarHeight - windowsHeight ) < position || ( isResizing && element.is(':last-child') ) ) { 22547 position = sectionBottom + menuHeight + bodyBorder*2 + adminBarHeight; 22548 } 22549 22550 /* 22551 Keeping record of the last scrolled position to determine the scrolling direction. 22552 No conventional methods can be used as the scroll bar might not be present 22553 AND the section might not be active if it is auto-height and didnt reach the middle 22554 of the viewport. 22555 */ 22556 previousDestTop = position; 22557 return position; 22558 } 22559 22560 /** 22561 * Scrolls the site to the given element and scrolls to the slide if a callback is given. 22562 */ 22563 function scrollPage(element, callback, isMovementUp){ 22564 if(typeof element === 'undefined'){ return; } //there's no element to scroll, leaving the function 22565 22566 var dtop = getDestinationPosition(element); 22567 var slideAnchorLink; 22568 var slideIndex; 22569 22570 //local variables 22571 var v = { 22572 element: element, 22573 callback: callback, 22574 isMovementUp: isMovementUp, 22575 dtop: dtop, 22576 yMovement: getYmovement(element), 22577 anchorLink: element.data('anchor'), 22578 sectionIndex: element.index(SECTION_SEL), 22579 activeSlide: element.find(SLIDE_ACTIVE_SEL), 22580 activeSection: $(SECTION_ACTIVE_SEL), 22581 leavingSection: $(SECTION_ACTIVE_SEL).index(SECTION_SEL) + 1, 22582 22583 //caching the value of isResizing at the momment the function is called 22584 //because it will be checked later inside a setTimeout and the value might change 22585 localIsResizing: isResizing 22586 }; 22587 22588 //quiting when destination scroll is the same as the current one 22589 if((v.activeSection.is(element) && !isResizing) || (options.scrollBar && $window.scrollTop() === v.dtop && !element.hasClass(AUTO_HEIGHT) )){ return; } 22590 22591 if(v.activeSlide.length){ 22592 slideAnchorLink = v.activeSlide.data('anchor'); 22593 slideIndex = v.activeSlide.index(); 22594 } 22595 22596 // If continuousVertical && we need to wrap around 22597 if (options.autoScrolling && options.continuousVertical && typeof (v.isMovementUp) !== "undefined" && 22598 ((!v.isMovementUp && v.yMovement == 'up') || // Intending to scroll down but about to go up or 22599 (v.isMovementUp && v.yMovement == 'down'))) { // intending to scroll up but about to go down 22600 22601 v = createInfiniteSections(v); 22602 } 22603 22604 //callback (onLeave) if the site is not just resizing and readjusting the slides 22605 if($.isFunction(options.onLeave) && !v.localIsResizing){ 22606 if(options.onLeave.call(v.activeSection, v.leavingSection, (v.sectionIndex + 1), v.yMovement) === false){ 22607 return; 22608 } 22609 } 22610 22611 //pausing media of the leaving section (if we are not just resizing, as destinatino will be the same one) 22612 if(!v.localIsResizing){ 22613 stopMedia(v.activeSection); 22614 } 22615 22616 options.scrollOverflowHandler.beforeLeave(); 22617 element.addClass(ACTIVE).siblings().removeClass(ACTIVE); 22618 lazyLoad(element); 22619 options.scrollOverflowHandler.onLeave(); 22620 22621 22622 //preventing from activating the MouseWheelHandler event 22623 //more than once if the page is scrolling 22624 canScroll = false;
22625 22626 setState(slideIndex, slideAnchorLink, v.anchorLink, v.sectionIndex); 22627 22628 performMovement(v); 22629 22630 //flag to avoid callingn `scrollPage()` twice in case of using anchor links 22631 lastScrolledDestiny = v.anchorLink; 22632 22633 //avoid firing it twice (as it does also on scroll) 22634 activateMenuAndNav(v.anchorLink, v.sectionIndex); 22635 } 22636 22637 /** 22638 * Performs the vertical movement (by CSS3 or by jQuery) 22639 */ 22640 function performMovement(v){ 22641 // using CSS3 translate functionality 22642 if (options.css3 && options.autoScrolling && !options.scrollBar) { 22643 22644 // The first section can have a negative value in iOS 10. Not quite sure why: -0.0142822265625 22645 // that's why we round it to 0. 22646 var translate3d = 'translate3d(0px, -' + Math.round(v.dtop) + 'px, 0px)'; 22647 transformContainer(translate3d, true); 22648 22649 //even when the scrollingSpeed is 0 there's a little delay, which might cause the 22650 //scrollingSpeed to change in case of using silentMoveTo(); 22651 if(options.scrollingSpeed){ 22652 clearTimeout(afterSectionLoadsId); 22653 afterSectionLoadsId = setTimeout(function () { 22654 afterSectionLoads(v); 22655 }, options.scrollingSpeed); 22656 }else{ 22657 afterSectionLoads(v); 22658 } 22659 } 22660 22661 // using jQuery animate 22662 else{ 22663 var scrollSettings = getScrollSettings(v); 22664 22665 $(scrollSettings.element).animate( 22666 scrollSettings.options, 22667 options.scrollingSpeed, options.easing).promise().done(function () { //only one single callback in case of animating `html, body` 22668 if(options.scrollBar){ 22669 22670 /* Hack! 22671 The timeout prevents setting the most dominant section in the viewport as "active" when the user 22672 scrolled to a smaller section by using the mousewheel (auto scrolling) rather than draging the scroll bar. 22673 22674 When using scrollBar:true It seems like the scroll events still getting propagated even after the scrolling animation has finished. 22675 */ 22676 setTimeout(function(){ 22677 afterSectionLoads(v); 22678 },30); 22679 }else{ 22680 afterSectionLoads(v); 22681 } 22682 }); 22683 } 22684 } 22685 22686 /** 22687 * Gets the scrolling settings depending on the plugin autoScrolling option 22688 */ 22689 function getScrollSettings(v){ 22690 var scroll = {}; 22691 22692 if(options.autoScrolling && !options.scrollBar){ 22693 scroll.options = { 'top': -v.dtop}; 22694 scroll.element = WRAPPER_SEL; 22695 }else{ 22696 scroll.options = { 'scrollTop': v.dtop}; 22697 scroll.element = 'html, body'; 22698 } 22699 22700 return scroll; 22701 } 22702 22703 /** 22704 * Adds sections before or after the current one to create the infinite effect. 22705 */ 22706 function createInfiniteSections(v){ 22707 // Scrolling down 22708 if (!v.isMovementUp) { 22709 // Move all previous sections to after the active section 22710 $(SECTION_ACTIVE_SEL).after(v.activeSection.prevAll(SECTION_SEL).get().reverse()); 22711 } 22712 else { // Scrolling up 22713 // Move all next sections to before the active section 22714 $(SECTION_ACTIVE_SEL).before(v.activeSection.nextAll(SECTION_SEL)); 22715 } 22716 22717 // Maintain the displayed position (now that we changed the element order) 22718 silentScroll($(SECTION_ACTIVE_SEL).position().top); 22719 22720 // Maintain the active slides visible in the viewport 22721 keepSlidesPosition(); 22722 22723 // save for later the elements that still need to be reordered 22724 v.wrapAroundElements = v.activeSection; 22725 22726 // Recalculate animation variables 22727 v.dtop = v.element.position().top; 22728 v.yMovement = getYmovement(v.element); 22729 22730 return v; 22731 } 22732 22733 /** 22734 * Fix section order after continuousVertical changes have been animated 22735 */ 22736 function continuousVerticalFixSectionOrder (v) {
22737 // If continuousVertical is in effect (and autoScrolling would also be in effect then), 22738 // finish moving the elements around so the direct navigation will function more simply 22739 if (!v.wrapAroundElements || !v.wrapAroundElements.length) { 22740 return; 22741 } 22742 22743 if (v.isMovementUp) { 22744 $(SECTION_FIRST_SEL).before(v.wrapAroundElements); 22745 } 22746 else { 22747 $(SECTION_LAST_SEL).after(v.wrapAroundElements); 22748 } 22749 22750 silentScroll($(SECTION_ACTIVE_SEL).position().top); 22751 22752 // Maintain the active slides visible in the viewport 22753 keepSlidesPosition(); 22754 } 22755 22756 22757 /** 22758 * Actions to do once the section is loaded. 22759 */ 22760 function afterSectionLoads (v){ 22761 continuousVerticalFixSectionOrder(v); 22762 22763 //callback (afterLoad) if the site is not just resizing and readjusting the slides 22764 $.isFunction(options.afterLoad) && !v.localIsResizing && options.afterLoad.call(v.element, v.anchorLink, (v.sectionIndex + 1)); 22765 options.scrollOverflowHandler.afterLoad(); 22766 22767 if(!v.localIsResizing){ 22768 playMedia(v.element); 22769 } 22770 22771 v.element.addClass(COMPLETELY).siblings().removeClass(COMPLETELY); 22772 22773 canScroll = true; 22774 22775 $.isFunction(v.callback) && v.callback.call(this); 22776 } 22777 22778 /** 22779 * Sets the value for the given attribute from the `data-` attribute with the same suffix 22780 * ie: data-srcset ==> srcset | data-src ==> src 22781 */ 22782 function setSrc(element, attribute){ 22783 element 22784 .attr(attribute, element.data(attribute)) 22785 .removeAttr('data-' + attribute); 22786 } 22787 22788 /** 22789 * Lazy loads image, video and audio elements. 22790 */ 22791 function lazyLoad(destiny){ 22792 if (!options.lazyLoading){ 22793 return; 22794 } 22795 22796 var panel = getSlideOrSection(destiny); 22797 var element; 22798 22799 panel.find('img[data-src], img[data-srcset], source[data-src], audio[data-src], iframe[data-src]').each(function(){ 22800 element = $(this); 22801 22802 $.each(['src', 'srcset'], function(index, type){ 22803 var attribute = element.attr('data-' + type); 22804 if(typeof attribute !== 'undefined' && attribute){ 22805 setSrc(element, type); 22806 } 22807 }); 22808 22809 if(element.is('source')){ 22810 element.closest('video').get(0).load(); 22811 } 22812 }); 22813 } 22814 22815 /** 22816 * Plays video and audio elements. 22817 */ 22818 function playMedia(destiny){ 22819 var panel = getSlideOrSection(destiny); 22820 22821 //playing HTML5 media elements 22822 panel.find('video, audio').each(function(){ 22823 var element = $(this).get(0); 22824 22825 if( element.hasAttribute('data-autoplay') && typeof element.play === 'function' ) { 22826 element.play(); 22827 } 22828 }); 22829 22830 //youtube videos 22831 panel.find('iframe[src*="youtube.com/embed/"]').each(function(){ 22832 var element = $(this).get(0); 22833 22834 if ( element.hasAttribute('data-autoplay') ){ 22835 playYoutube(element); 22836 } 22837 22838 //in case the URL was not loaded yet. On page load we need time for the new URL (with the API string) to load. 22839 element.onload = function() { 22840 if ( element.hasAttribute('data-autoplay') ){ 22841 playYoutube(element); 22842 } 22843 }; 22844 }); 22845 } 22846 22847 /** 22848 * Plays a youtube video 22849 */ 22850 function playYoutube(element){ 22851 element.contentWindow.postMessage('{"event":"command","func":"playVideo","args":""}', '*'); 22852 } 22853 22854 /** 22855 * Stops video and audio elements. 22856 */ 22857 function stopMedia(destiny){ 22858 var panel = getSlideOrSection(destiny); 22859 22860 //stopping HTML5 media elements 22861 panel.find('video, audio').each(function(){ 22862 var element = $(this).get(0); 22863 22864 if( !element.hasAttribute('data-keepplaying') && typeof element.pause === 'function' ) { 22865 element.pause(); 22866 } 22867 }); 22868 22869 //youtube videos 22870 panel.find('iframe[src*="youtube.com/embed/"]').each(function(){ 22871 var element = $(this).get(0); 22872 22873 if( /youtube\.com\/embed\//.test($(this).attr('src')) && !element.hasAttribute('data-keepplaying')){ 22874 $(this).get(0).contentWindow.postMessage('{"event":"command","func":"pauseVideo","args":""}','*'); 22875 } 22876 }); 22877 } 22878 22879 /** 22880 * Gets the active slide (or section) for the given section 22881 */ 22882 function getSlideOrSection(destiny){ 22883 var slide = destiny.find(SLIDE_ACTIVE_SEL); 22884 if( slide.length ) { 22885 destiny = $(slide); 22886 } 22887 22888 return destiny; 22889 } 22890 22891 /**
22892 * Scrolls to the anchor in the URL when loading the site 22893 */ 22894 function scrollToAnchor(){ 22895 //getting the anchor link in the URL and deleting the `#` 22896 var value = window.location.hash.replace('#', '').split('/'); 22897 var sectionAnchor = decodeURIComponent(value[0]); 22898 var slideAnchor = decodeURIComponent(value[1]); 22899 22900 if(sectionAnchor){ //if theres any # 22901 if(options.animateAnchor){ 22902 scrollPageAndSlide(sectionAnchor, slideAnchor); 22903 }else{ 22904 silentMoveTo(sectionAnchor, slideAnchor); 22905 } 22906 } 22907 } 22908 22909 /** 22910 * Detecting any change on the URL to scroll to the given anchor link 22911 * (a way to detect back history button as we play with the hashes on the URL) 22912 */ 22913 function hashChangeHandler(){ 22914 if(!isScrolling && !options.lockAnchors){ 22915 var value = window.location.hash.replace('#', '').split('/'); 22916 var sectionAnchor = decodeURIComponent(value[0]); 22917 var slideAnchor = decodeURIComponent(value[1]); 22918 22919 //when moving to a slide in the first section for the first time (first time to add an anchor to the URL) 22920 var isFirstSlideMove = (typeof lastScrolledDestiny === 'undefined'); 22921 var isFirstScrollMove = (typeof lastScrolledDestiny === 'undefined' && typeof slideAnchor === 'undefined' && !slideMoving); 22922 22923 22924 if(sectionAnchor.length){ 22925 /*in order to call scrollpage() only once for each destination at a time 22926 It is called twice for each scroll otherwise, as in case of using anchorlinks `hashChange` 22927 event is fired on every scroll too.*/ 22928 if ((sectionAnchor && sectionAnchor !== lastScrolledDestiny) && !isFirstSlideMove || isFirstScrollMove || (!slideMoving && lastScrolledSlide != slideAnchor )) { 22929 scrollPageAndSlide(sectionAnchor, slideAnchor); 22930 } 22931 } 22932 } 22933 } 22934 22935 //Sliding with arrow keys, both, vertical and horizontal 22936 function keydownHandler(e) { 22937 22938 clearTimeout(keydownId); 22939 22940 var activeElement = $(':focus'); 22941 22942 if(!activeElement.is('textarea') && !activeElement.is('input') && !activeElement.is('select') && 22943 activeElement.attr('contentEditable') !== "true" && activeElement.attr('contentEditable') !== '' && 22944 options.keyboardScrolling && options.autoScrolling){ 22945 var keyCode = e.which; 22946 22947 //preventing the scroll with arrow keys & spacebar & Page Up & Down keys 22948 var keyControls = [40, 38, 32, 33, 34]; 22949 if($.inArray(keyCode, keyControls) > -1){ 22950 e.preventDefault(); 22951 } 22952 22953 controlPressed = e.ctrlKey; 22954 22955 keydownId = setTimeout(function(){ 22956 onkeydown(e); 22957 },150); 22958 } 22959 } 22960 22961 function tooltipTextHandler(){ 22962 $(this).prev().trigger('click'); 22963 } 22964 22965 //to prevent scrolling while zooming 22966 function keyUpHandler(e){ 22967 if(isWindowFocused){ //the keyup gets fired on new tab ctrl + t in Firefox 22968 controlPressed = e.ctrlKey; 22969 } 22970 } 22971 22972 //binding the mousemove when the mouse's middle button is released 22973 function mouseDownHandler(e){ 22974 //middle button 22975 if (e.which == 2){ 22976 oldPageY = e.pageY; 22977 container.on('mousemove', mouseMoveHandler); 22978 } 22979 } 22980 22981 //unbinding the mousemove when the mouse's middle button is released 22982 function mouseUpHandler(e){ 22983 //middle button 22984 if (e.which == 2){ 22985 container.off('mousemove'); 22986 } 22987 } 22988 22989 //Scrolling horizontally when clicking on the slider controls. 22990 function slideArrowHandler(){ 22991 var section = $(this).closest(SECTION_SEL); 22992 22993 if ($(this).hasClass(SLIDES_PREV)) { 22994 if(isScrollAllowed.m.left){ 22995 moveSlideLeft(section); 22996 } 22997 } else { 22998 if(isScrollAllowed.m.right){ 22999 moveSlideRight(section); 23000 } 23001 } 23002 } 23003 23004 //when opening a new tab (ctrl + t), `control` won't be pressed when coming back. 23005 function blurHandler(){ 23006 isWindowFocused = false;
23007 controlPressed = false; 23008 } 23009 23010 //Scrolls to the section when clicking the navigation bullet 23011 function sectionBulletHandler(e){ 23012 e.preventDefault(); 23013 var index = $(this).parent().index(); 23014 scrollPage($(SECTION_SEL).eq(index)); 23015 } 23016 23017 //Scrolls the slider to the given slide destination for the given section 23018 function slideBulletHandler(e){ 23019 e.preventDefault(); 23020 var slides = $(this).closest(SECTION_SEL).find(SLIDES_WRAPPER_SEL); 23021 var destiny = slides.find(SLIDE_SEL).eq($(this).closest('li').index()); 23022 23023 landscapeScroll(slides, destiny); 23024 } 23025 23026 /** 23027 * Keydown event 23028 */ 23029 function onkeydown(e){ 23030 var shiftPressed = e.shiftKey; 23031 23032 //do nothing if we can not scroll or we are not using horizotnal key arrows. 23033 if(!canScroll && [37,39].indexOf(e.which) < 0){ 23034 return; 23035 } 23036 23037 switch (e.which) { 23038 //up 23039 case 38: 23040 case 33: 23041 if(isScrollAllowed.k.up){ 23042 moveSectionUp(); 23043 } 23044 break; 23045 23046 //down 23047 case 32: //spacebar 23048 if(shiftPressed && isScrollAllowed.k.up){ 23049 moveSectionUp(); 23050 break; 23051 } 23052 /* falls through */ 23053 case 40: 23054 case 34: 23055 if(isScrollAllowed.k.down){ 23056 moveSectionDown(); 23057 } 23058 break; 23059 23060 //Home 23061 case 36: 23062 if(isScrollAllowed.k.up){ 23063 moveTo(1); 23064 } 23065 break; 23066 23067 //End 23068 case 35: 23069 if(isScrollAllowed.k.down){ 23070 moveTo( $(SECTION_SEL).length ); 23071 } 23072 break; 23073 23074 //left 23075 case 37: 23076 if(isScrollAllowed.k.left){ 23077 moveSlideLeft(); 23078 } 23079 break; 23080 23081 //right 23082 case 39: 23083 if(isScrollAllowed.k.right){ 23084 moveSlideRight(); 23085 } 23086 break; 23087 23088 default: 23089 return; // exit this handler for other keys 23090 } 23091 } 23092 23093 /** 23094 * Detecting the direction of the mouse movement. 23095 * Used only for the middle button of the mouse. 23096 */ 23097 var oldPageY = 0; 23098 function mouseMoveHandler(e){ 23099 if(canScroll){ 23100 // moving up 23101 if (e.pageY < oldPageY && isScrollAllowed.m.up){ 23102 moveSectionUp(); 23103 } 23104 23105 // moving down 23106 else if(e.pageY > oldPageY && isScrollAllowed.m.down){ 23107 moveSectionDown(); 23108 } 23109 } 23110 oldPageY = e.pageY; 23111 } 23112 23113 /** 23114 * Scrolls horizontal sliders. 23115 */ 23116 function landscapeScroll(slides, destiny, direction){ 23117 var section = slides.closest(SECTION_SEL); 23118 var v = { 23119 slides: slides, 23120 destiny: destiny, 23121 direction: direction, 23122 destinyPos: destiny.position(), 23123 slideIndex: destiny.index(), 23124 section: section, 23125 sectionIndex: section.index(SECTION_SEL), 23126 anchorLink: section.data('anchor'), 23127 slidesNav: section.find(SLIDES_NAV_SEL), 23128 slideAnchor: getAnchor(destiny), 23129 prevSlide: section.find(SLIDE_ACTIVE_SEL), 23130 prevSlideIndex: section.find(SLIDE_ACTIVE_SEL).index(), 23131 23132 //caching the value of isResizing at the momment the function is called 23133 //because it will be checked later inside a setTimeout and the value might change 23134 localIsResizing: isResizing 23135 }; 23136 v.xMovement = getXmovement(v.prevSlideIndex, v.slideIndex); 23137 v.direction = v.direction ? v.direction : v.xMovement; 23138 23139 //important!! Only do it when not resizing 23140 if(!v.localIsResizing){ 23141 //preventing from scrolling to the next/prev section when using scrollHorizontally 23142 canScroll = false;
23143 } 23144 23145 if(options.onSlideLeave){ 23146 23147 //if the site is not just resizing and readjusting the slides 23148 if(!v.localIsResizing && v.xMovement!=='none'){ 23149 if($.isFunction( options.onSlideLeave )){ 23150 if(options.onSlideLeave.call( v.prevSlide, v.anchorLink, (v.sectionIndex + 1), v.prevSlideIndex, v.xMovement, v.slideIndex ) === false){ 23151 slideMoving = false; 23152 return; 23153 } 23154 } 23155 } 23156 } 23157 23158 destiny.addClass(ACTIVE).siblings().removeClass(ACTIVE); 23159 23160 if(!v.localIsResizing){ 23161 stopMedia(v.prevSlide); 23162 lazyLoad(destiny); 23163 } 23164 23165 if(!options.loopHorizontal && options.controlArrows){ 23166 //hidding it for the fist slide, showing for the rest 23167 section.find(SLIDES_ARROW_PREV_SEL).toggle(v.slideIndex!==0); 23168 23169 //hidding it for the last slide, showing for the rest 23170 section.find(SLIDES_ARROW_NEXT_SEL).toggle(!destiny.is(':last-child')); 23171 } 23172 23173 //only changing the URL if the slides are in the current section (not for resize re-adjusting) 23174 if(section.hasClass(ACTIVE) && !v.localIsResizing){ 23175 setState(v.slideIndex, v.slideAnchor, v.anchorLink, v.sectionIndex); 23176 } 23177 23178 performHorizontalMove(slides, v, true); 23179 } 23180 23181 23182 function afterSlideLoads(v){ 23183 activeSlidesNavigation(v.slidesNav, v.slideIndex); 23184 23185 //if the site is not just resizing and readjusting the slides 23186 if(!v.localIsResizing){ 23187 $.isFunction( options.afterSlideLoad ) && options.afterSlideLoad.call( v.destiny, v.anchorLink, (v.sectionIndex + 1), v.slideAnchor, v.slideIndex); 23188 23189 //needs to be inside the condition to prevent problems with continuousVertical and scrollHorizontally 23190 //and to prevent double scroll right after a windows resize 23191 canScroll = true; 23192 23193 playMedia(v.destiny); 23194 } 23195 23196 //letting them slide again 23197 slideMoving = false; 23198 } 23199 23200 /** 23201 * Performs the horizontal movement. (CSS3 or jQuery) 23202 * 23203 * @param fireCallback {Bool} - determines whether or not to fire the callback 23204 */ 23205 function performHorizontalMove(slides, v, fireCallback){ 23206 var destinyPos = v.destinyPos; 23207 23208 if(options.css3){ 23209 var translate3d = 'translate3d(-' + Math.round(destinyPos.left) + 'px, 0px, 0px)'; 23210 23211 addAnimation(slides.find(SLIDES_CONTAINER_SEL)).css(getTransforms(translate3d), v); 23212 23213 afterSlideLoadsId = setTimeout(function(){ 23214 fireCallback && afterSlideLoads(v); 23215 }, options.scrollingSpeed, options.easing); 23216 }else{ 23217 slides.animate({ 23218 scrollLeft : Math.round(destinyPos.left) 23219 }, options.scrollingSpeed, options.easing, function() { 23220 23221 fireCallback && afterSlideLoads(v); 23222 }); 23223 } 23224 } 23225 23226 /** 23227 * Sets the state for the horizontal bullet navigations. 23228 */ 23229 function activeSlidesNavigation(slidesNav, slideIndex){ 23230 slidesNav.find(ACTIVE_SEL).removeClass(ACTIVE); 23231 slidesNav.find('li').eq(slideIndex).find('a').addClass(ACTIVE); 23232 } 23233 23234 var previousHeight = windowsHeight; 23235 23236 //when resizing the site, we adjust the heights of the sections, slimScroll... 23237 function resizeHandler(){ 23238 //checking if it needs to get responsive 23239 responsive(); 23240 23241 // rebuild immediately on touch devices 23242 if (isTouchDevice) { 23243 var activeElement = $(document.activeElement); 23244 23245 //if the keyboard is NOT visible 23246 if (!activeElement.is('textarea') && !activeElement.is('input') && !activeElement.is('select')) { 23247 var currentHeight = $window.height(); 23248 23249 //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) 23250 if( Math.abs(currentHeight - previousHeight) > (20 * Math.max(previousHeight, currentHeight) / 100) ){ 23251 reBuild(true); 23252 previousHeight = currentHeight; 23253 } 23254 } 23255 }else{ 23256 //in order to call the functions only when the resize is finished 23257 //http://stackoverflow.com/questions/4298612/jquery-how-to-call-resize-event-only-once-its-finished-resizing 23258 clearTimeout(resizeId); 23259 23260 resizeId = setTimeout(function(){ 23261 reBuild(true); 23262 }, 350); 23263 } 23264 } 23265 23266 /** 23267 * Checks if the site needs to get responsive and disables autoScrolling if so. 23268 * A class `fp-responsive` is added to the plugin's container in case the user wants to use it for his own responsive CSS. 23269 */ 23270 function responsive(){ 23271 var widthLimit = options.responsive || options.responsiveWidth; //backwards compatiblity 23272 var heightLimit = options.responsiveHeight; 23273 23274 //only calculating what we need. Remember its called on the resize event. 23275 var isBreakingPointWidth = widthLimit && $window.outerWidth() < widthLimit; 23276 var isBreakingPointHeight = heightLimit && $window.height() < heightLimit; 23277 23278 if(widthLimit && heightLimit){ 23279 setResponsive(isBreakingPointWidth || isBreakingPointHeight); 23280 } 23281 else if(widthLimit){ 23282 setResponsive(isBreakingPointWidth); 23283 } 23284 else if(heightLimit){ 23285 setResponsive(isBreakingPointHeight); 23286 } 23287 } 23288 23289 /** 23290 * Adds transition animations for the given element 23291 */ 23292 function addAnimation(container, element){ 23293 var transition = 'all ' + options.scrollingSpeed + 'ms ' + options.easingcss3; 23294 23295 container.removeClass(NO_TRANSITION); 23296 return container.css({
23297 '-webkit-transition': transition, 23298 'transition': transition 23299 }); 23300 } 23301 23302 /** 23303 * Remove transition animations for the given element 23304 */ 23305 function removeAnimation(element){ 23306 return element.addClass(NO_TRANSITION); 23307 } 23308 23309 /** 23310 * Activating the vertical navigation bullets according to the given slide name. 23311 */ 23312 function activateNavDots(name, sectionIndex){ 23313 if(options.navigation){ 23314 $(SECTION_NAV_SEL).find(ACTIVE_SEL).removeClass(ACTIVE); 23315 if(name){ 23316 $(SECTION_NAV_SEL).find('a[href="#' + name + '"]').addClass(ACTIVE); 23317 }else{ 23318 $(SECTION_NAV_SEL).find('li').eq(sectionIndex).find('a').addClass(ACTIVE); 23319 } 23320 } 23321 } 23322 23323 /** 23324 * Activating the website main menu elements according to the given slide name. 23325 */ 23326 function activateMenuElement(name){ 23327 if(options.menu){ 23328 $(options.menu).find(ACTIVE_SEL).removeClass(ACTIVE); 23329 $(options.menu).find('[data-menuanchor="'+name+'"]').addClass(ACTIVE); 23330 } 23331 } 23332 23333 /** 23334 * Sets to active the current menu and vertical nav items. 23335 */ 23336 function activateMenuAndNav(anchor, index){ 23337 activateMenuElement(anchor); 23338 activateNavDots(anchor, index); 23339 } 23340 23341 /** 23342 * Retuns `up` or `down` depending on the scrolling movement to reach its destination 23343 * from the current section. 23344 */ 23345 function getYmovement(destiny){ 23346 var fromIndex = $(SECTION_ACTIVE_SEL).index(SECTION_SEL); 23347 var toIndex = destiny.index(SECTION_SEL); 23348 if( fromIndex == toIndex){ 23349 return 'none'; 23350 } 23351 if(fromIndex > toIndex){ 23352 return 'up'; 23353 } 23354 return 'down'; 23355 } 23356 23357 /** 23358 * Retuns `right` or `left` depending on the scrolling movement to reach its destination 23359 * from the current slide. 23360 */ 23361 function getXmovement(fromIndex, toIndex){ 23362 if( fromIndex == toIndex){ 23363 return 'none'; 23364 } 23365 if(fromIndex > toIndex){ 23366 return 'left'; 23367 } 23368 return 'right'; 23369 } 23370 23371 /** 23372 * Checks if the element needs scrollbar and if the user wants to apply it. 23373 * If so it creates it. 23374 * 23375 * @param {Object} element jQuery object of the section or slide 23376 */ 23377 function createScrollBar(element){ 23378 //User doesn't want scrollbar here? Sayonara baby! 23379 if(element.hasClass('fp-noscroll')) return; 23380 23381 //needed to make `scrollHeight` work under Opera 12 23382 element.css('overflow', 'hidden'); 23383 23384 var scrollOverflowHandler = options.scrollOverflowHandler; 23385 var wrap = scrollOverflowHandler.wrapContent(); 23386 //in case element is a slide 23387 var section = element.closest(SECTION_SEL); 23388 var scrollable = scrollOverflowHandler.scrollable(element); 23389 var contentHeight; 23390 23391 //if there was scroll, the contentHeight will be the one in the scrollable section 23392 if(scrollable.length){ 23393 contentHeight = scrollOverflowHandler.scrollHeight(element); 23394 }else{ 23395 contentHeight = element.get(0).scrollHeight; 23396 if(options.verticalCentered){ 23397 contentHeight = element.find(TABLE_CELL_SEL).get(0).scrollHeight; 23398 } 23399 } 23400 23401 var scrollHeight = windowsHeight - parseInt(section.css('padding-bottom')) - parseInt(section.css('padding-top')); 23402 23403 //needs scroll? 23404 if ( contentHeight > scrollHeight) { 23405 //did we already have an scrollbar ? Updating it 23406 if(scrollable.length){ 23407 scrollOverflowHandler.update(element, scrollHeight); 23408 } 23409 //creating the scrolling 23410 else{ 23411 if(options.verticalCentered){ 23412 element.find(TABLE_CELL_SEL).wrapInner(wrap); 23413 }else{ 23414 element.wrapInner(wrap); 23415 } 23416 scrollOverflowHandler.create(element, scrollHeight); 23417 } 23418 } 23419 //removing the scrolling when it is not necessary anymore 23420 else{ 23421 scrollOverflowHandler.remove(element); 23422 } 23423 23424 //undo 23425 element.css('overflow', ''); 23426 } 23427 23428 function addTableClass(element){ 23429 //In case we are styling for the 2nd time as in with reponsiveSlides 23430 if(!element.hasClass(TABLE)){ 23431 element.addClass(TABLE).wrapInner('<div class="' + TABLE_CELL + '" style="height:' + getTableHeight(element) + 'px;" />'); 23432 } 23433 } 23434 23435 function getTableHeight(element){ 23436 var sectionHeight = windowsHeight; 23437 23438 if(options.paddingTop || options.paddingBottom){ 23439 var section = element; 23440 if(!section.hasClass(SECTION)){ 23441 section = element.closest(SECTION_SEL); 23442 } 23443 23444 var paddings = parseInt(section.css('padding-top')) + parseInt(section.css('padding-bottom')); 23445 sectionHeight = (windowsHeight - paddings); 23446 } 23447 23448 return sectionHeight; 23449 } 23450 23451 /** 23452 * Adds a css3 transform property to the container class with or without animation depending on the animated param. 23453 */ 23454 function transformContainer(translate3d, animated){ 23455 if(animated){ 23456 addAnimation(container); 23457 }else{ 23458 removeAnimation(container); 23459 } 23460 23461 container.css(getTransforms(translate3d)); 23462 23463 //syncronously removing the class after the animation has been applied. 23464 setTimeout(function(){ 23465 container.removeClass(NO_TRANSITION); 23466 },10); 23467 } 23468 23469 /** 23470 * Gets a section by its anchor / index 23471 */ 23472 function getSectionByAnchor(sectionAnchor){ 23473 if(!sectionAnchor) return []; 23474 23475 var section = container.find(SECTION_SEL + '[data-anchor="'+sectionAnchor+'"]'); 23476 if(!section.length){ 23477 section = $(SECTION_SEL).eq( sectionAnchor -1); 23478 } 23479 23480 return section; 23481 } 23482 23483 /** 23484 * Gets a slide inside a given section by its anchor / index 23485 */ 23486 function getSlideByAnchor(slideAnchor, section){ 23487 var slides = section.find(SLIDES_WRAPPER_SEL); 23488 var slide = slides.find(SLIDE_SEL + '[data-anchor="'+slideAnchor+'"]'); 23489
23490 if(!slide.length){ 23491 slide = slides.find(SLIDE_SEL).eq(slideAnchor); 23492 } 23493 23494 return slide; 23495 } 23496 23497 /** 23498 * Scrolls to the given section and slide anchors 23499 */ 23500 function scrollPageAndSlide(destiny, slide){ 23501 var section = getSectionByAnchor(destiny); 23502 23503 //do nothing if there's no section with the given anchor name 23504 if(!section.length) return; 23505 23506 //default slide 23507 if (typeof slide === 'undefined') { 23508 slide = 0; 23509 } 23510 23511 //we need to scroll to the section and then to the slide 23512 if (destiny !== lastScrolledDestiny && !section.hasClass(ACTIVE)){ 23513 scrollPage(section, function(){ 23514 scrollSlider(section, slide); 23515 }); 23516 } 23517 //if we were already in the section 23518 else{ 23519 scrollSlider(section, slide); 23520 } 23521 } 23522 23523 /** 23524 * Scrolls the slider to the given slide destination for the given section 23525 */ 23526 function scrollSlider(section, slideAnchor){ 23527 if(typeof slideAnchor !== 'undefined'){ 23528 var slides = section.find(SLIDES_WRAPPER_SEL); 23529 var destiny = getSlideByAnchor(slideAnchor, section); 23530 23531 if(destiny.length){ 23532 landscapeScroll(slides, destiny); 23533 } 23534 } 23535 } 23536 23537 /** 23538 * Creates a landscape navigation bar with dots for horizontal sliders. 23539 */ 23540 function addSlidesNavigation(section, numSlides){ 23541 section.append('<div class="' + SLIDES_NAV + '"><ul></ul></div>'); 23542 var nav = section.find(SLIDES_NAV_SEL); 23543 23544 //top or bottom 23545 nav.addClass(options.slidesNavPosition); 23546 23547 for(var i=0; i< numSlides; i++){ 23548 nav.find('ul').append('<li><a href="#"><span></span></a></li>'); 23549 } 23550 23551 //centering it 23552 nav.css('margin-left', '-' + (nav.width()/2) + 'px'); 23553 23554 nav.find('li').first().find('a').addClass(ACTIVE); 23555 } 23556 23557 23558 /** 23559 * Sets the state of the website depending on the active section/slide. 23560 * It changes the URL hash when needed and updates the body class. 23561 */ 23562 function setState(slideIndex, slideAnchor, anchorLink, sectionIndex){ 23563 var sectionHash = ''; 23564 23565 if(options.anchors.length && !options.lockAnchors){ 23566 23567 //isn't it the first slide? 23568 if(slideIndex){ 23569 if(typeof anchorLink !== 'undefined'){ 23570 sectionHash = anchorLink; 23571 } 23572 23573 //slide without anchor link? We take the index instead. 23574 if(typeof slideAnchor === 'undefined'){ 23575 slideAnchor = slideIndex; 23576 } 23577 23578 lastScrolledSlide = slideAnchor; 23579 setUrlHash(sectionHash + '/' + slideAnchor); 23580 23581 //first slide won't have slide anchor, just the section one 23582 }else if(typeof slideIndex !== 'undefined'){ 23583 lastScrolledSlide = slideAnchor; 23584 setUrlHash(anchorLink); 23585 } 23586 23587 //section without slides 23588 else{ 23589 setUrlHash(anchorLink); 23590 } 23591 } 23592 23593 setBodyClass(); 23594 } 23595 23596 /** 23597 * Sets the URL hash. 23598 */ 23599 function setUrlHash(url){ 23600 //Uncode addition 23601 if ( typeof SiteParameters.slide_footer != 'undefined' && url == SiteParameters.slide_footer ) 23602 return false; 23603 23604 if(options.recordHistory){ 23605 location.hash = url; 23606 }else{ 23607 //Uncode addition 23608 //Mobile Chrome doesn't work the normal way, so... lets use HTML5 for phones :) 23609 // if(isTouchDevice || isTouch){ 23610 // window.history.replaceState(undefined, undefined, '#' + url); 23611 // }else{ 23612 // var baseUrl = window.location.href.split('#')[0]; 23613 // window.location.replace( baseUrl + '#' + url ); 23614 // } 23615 return false;
23616 } 23617 } 23618 23619 /** 23620 * Gets the anchor for the given slide / section. Its index will be used if there's none. 23621 */ 23622 function getAnchor(element){ 23623 var anchor = element.data('anchor'); 23624 var index = element.index(); 23625 23626 //Slide without anchor link? We take the index instead. 23627 if(typeof anchor === 'undefined'){ 23628 anchor = index; 23629 } 23630 23631 return anchor; 23632 } 23633 23634 /** 23635 * Sets a class for the body of the page depending on the active section / slide 23636 */ 23637 function setBodyClass(){ 23638 var section = $(SECTION_ACTIVE_SEL); 23639 var slide = section.find(SLIDE_ACTIVE_SEL); 23640 23641 var sectionAnchor = getAnchor(section); 23642 var slideAnchor = getAnchor(slide); 23643 23644 var text = String(sectionAnchor); 23645 23646 if(slide.length){ 23647 text = text + '-' + slideAnchor; 23648 } 23649 23650 //changing slash for dash to make it a valid CSS style 23651 text = text.replace('/', '-').replace('#',''); 23652 23653 //removing previous anchor classes 23654 var classRe = new RegExp('\\b\\s?' + VIEWING_PREFIX + '-[^\\s]+\\b', "g"); 23655 $body[0].className = $body[0].className.replace(classRe, ''); 23656 23657 //adding the current anchor 23658 $body.addClass(VIEWING_PREFIX + '-' + text); 23659 } 23660 23661 /** 23662 * Checks for translate3d support 23663 * @return boolean 23664 * http://stackoverflow.com/questions/5661671/detecting-transform-translate3d-support 23665 */ 23666 function support3d() { 23667 var el = document.createElement('p'), 23668 has3d, 23669 transforms = { 23670 'webkitTransform':'-webkit-transform', 23671 'OTransform':'-o-transform', 23672 'msTransform':'-ms-transform', 23673 'MozTransform':'-moz-transform', 23674 'transform':'transform' 23675 }; 23676 23677 // Add it to the body to get the computed style. 23678 document.body.insertBefore(el, null); 23679 23680 for (var t in transforms) { 23681 if (el.style[t] !== undefined) { 23682 el.style[t] = 'translate3d(1px,1px,1px)'; 23683 has3d = window.getComputedStyle(el).getPropertyValue(transforms[t]); 23684 } 23685 } 23686 23687 document.body.removeChild(el); 23688 23689 return (has3d !== undefined && has3d.length > 0 && has3d !== 'none'); 23690 } 23691 23692 /** 23693 * Removes the auto scrolling action fired by the mouse wheel and trackpad. 23694 * After this function is called, the mousewheel and trackpad movements won't scroll through sections. 23695 */ 23696 function removeMouseWheelHandler(){ 23697 if (document.addEventListener) { 23698 document.removeEventListener('mousewheel', MouseWheelHandler, false); //IE9, Chrome, Safari, Oper 23699 document.removeEventListener('wheel', MouseWheelHandler, false); //Firefox 23700 document.removeEventListener('MozMousePixelScroll', MouseWheelHandler, false); //old Firefox 23701 } else { 23702 document.detachEvent('onmousewheel', MouseWheelHandler); //IE 6/7/8 23703 } 23704 } 23705 23706 /** 23707 * Adds the auto scrolling action for the mouse wheel and trackpad. 23708 * After this function is called, the mousewheel and trackpad movements will scroll through sections 23709 * https://developer.mozilla.org/en-US/docs/Web/Events/wheel 23710 */ 23711 function addMouseWheelHandler(){ 23712 var prefix = ''; 23713 var _addEventListener; 23714 23715 if (window.addEventListener){ 23716 _addEventListener = "addEventListener"; 23717 }else{ 23718 _addEventListener = "attachEvent"; 23719 prefix = 'on'; 23720 } 23721 23722 // detect available wheel event 23723 var support = 'onwheel' in document.createElement('div') ? 'wheel' : // Modern browsers support "wheel" 23724 document.onmousewheel !== undefined ? 'mousewheel' : // Webkit and IE support at least "mousewheel" 23725 'DOMMouseScroll'; // let's assume that remaining browsers are older Firefox 23726 var passiveEvent = g_supportsPassive ? {passive: false }
23726: false; 23727 23728 23729 if(support == 'DOMMouseScroll'){ 23730 document[ _addEventListener ](prefix + 'MozMousePixelScroll', MouseWheelHandler, passiveEvent); 23731 } 23732 23733 //handle MozMousePixelScroll in older Firefox 23734 else{ 23735 document[ _addEventListener ](prefix + support, MouseWheelHandler, passiveEvent); 23736 } 23737 } 23738 23739 /** 23740 * Binding the mousemove when the mouse's middle button is pressed 23741 */ 23742 function addMiddleWheelHandler(){ 23743 container 23744 .on('mousedown', mouseDownHandler) 23745 .on('mouseup', mouseUpHandler); 23746 } 23747 23748 /** 23749 * Unbinding the mousemove when the mouse's middle button is released 23750 */ 23751 function removeMiddleWheelHandler(){ 23752 container 23753 .off('mousedown', mouseDownHandler) 23754 .off('mouseup', mouseUpHandler); 23755 } 23756 23757 /** 23758 * Adds the possibility to auto scroll through sections on touch devices. 23759 */ 23760 function addTouchHandler(){ 23761 if(isTouchDevice || isTouch){ 23762 if(options.autoScrolling){ 23763 $body.off(events.touchmove).on(events.touchmove, preventBouncing); 23764 } 23765 23766 $(WRAPPER_SEL) 23767 .off(events.touchstart).on(events.touchstart, touchStartHandler) 23768 .off(events.touchmove).on(events.touchmove, touchMoveHandler); 23769 } 23770 } 23771 23772 /** 23773 * Removes the auto scrolling for touch devices. 23774 */ 23775 function removeTouchHandler(){ 23776 if(isTouchDevice || isTouch){ 23777 $(WRAPPER_SEL) 23778 .off(events.touchstart) 23779 .off(events.touchmove); 23780 } 23781 } 23782 23783 /* 23784 * Returns and object with Microsoft pointers (for IE<11 and for IE >= 11) 23785 * http://msdn.microsoft.com/en-us/library/ie/dn304886(v=vs.85).aspx 23786 */ 23787 function getMSPointer(){ 23788 var pointer; 23789 23790 //IE >= 11 & rest of browsers 23791 if(window.PointerEvent){ 23792 pointer = { down: 'pointerdown', move: 'pointermove'}; 23793 } 23794 23795 //IE < 11 23796 else{ 23797 pointer = { down: 'MSPointerDown', move: 'MSPointerMove'}; 23798 } 23799 23800 return pointer; 23801 } 23802 23803 /** 23804 * Gets the pageX and pageY properties depending on the browser. 23805 * https://github.com/alvarotrigo/fullPage.js/issues/194#issuecomment-34069854 23806 */ 23807 function getEventsPage(e){ 23808 var events = []; 23809 23810 events.y = (typeof e.pageY !== 'undefined' && (e.pageY || e.pageX) ? e.pageY : e.touches[0].pageY); 23811 events.x = (typeof e.pageX !== 'undefined' && (e.pageY || e.pageX) ? e.pageX : e.touches[0].pageX); 23812 23813 //in touch devices with scrollBar:true, e.pageY is detected, but we have to deal with touch events. #1008 23814 if(isTouch && isReallyTouch(e) && options.scrollBar){ 23815 events.y = e.touches[0].pageY; 23816 events.x = e.touches[0].pageX; 23817 } 23818 23819 return events; 23820 } 23821 23822 /** 23823 * Slides silently (with no animation) the active slider to the given slide. 23824 * @param noCallback {bool} true or defined -> no callbacks 23825 */ 23826 function silentLandscapeScroll(activeSlide, noCallbacks){ 23827 setScrollingSpeed (0, 'internal'); 23828 23829 if(typeof noCallbacks !== 'undefined'){ 23830 //preventing firing callbacks afterSlideLoad etc. 23831 isResizing = true; 23832 } 23833 23834 landscapeScroll(activeSlide.closest(SLIDES_WRAPPER_SEL), activeSlide); 23835 23836 if(typeof noCallbacks !== 'undefined'){ 23837 isResizing = false; 23838 } 23839 23840 setScrollingSpeed(originals.scrollingSpeed, 'internal'); 23841 } 23842 23843 /** 23844 * Scrolls silently (with no animation) the page to the given Y position. 23845 */ 23846 function silentScroll(top){ 23847 // The first section can have a negative value in iOS 10. Not quite sure why: -0.0142822265625 23848 // that's why we round it to 0. 23849 var roundedTop = Math.round(top); 23850 23851 if (options.css3 && options.autoScrolling && !options.scrollBar){ 23852 var translate3d = 'translate3d(0px, -' + roundedTop + 'px, 0px)'; 23853 transformContainer(translate3d, false); 23854 } 23855 else if(options.autoScrolling && !options.scrollBar){ 23856 container.css('top', -roundedTop); 23857 } 23858 else{ 23859 $htmlBody.scrollTop(roundedTop); 23860 } 23861 } 23862 23863 /** 23864 * Returns the cross-browser transform string. 23865 */ 23866 function getTransforms(translate3d){ 23867 return {
23868 '-webkit-transform': translate3d, 23869 '-moz-transform': translate3d, 23870 '-ms-transform':translate3d, 23871 'transform': translate3d 23872 }; 23873 } 23874 23875 /** 23876 * Allowing or disallowing the mouse/swipe scroll in a given direction. (not for keyboard) 23877 * @type m (mouse) or k (keyboard) 23878 */ 23879 function setIsScrollAllowed(value, direction, type){ 23880 switch (direction){ 23881 case 'up': isScrollAllowed[type].up = value; break; 23882 case 'down': isScrollAllowed[type].down = value; break; 23883 case 'left': isScrollAllowed[type].left = value; break; 23884 case 'right': isScrollAllowed[type].right = value; break; 23885 case 'all': 23886 if(type == 'm'){ 23887 setAllowScrolling(value); 23888 }else{ 23889 setKeyboardScrolling(value); 23890 } 23891 } 23892 } 23893 23894 /* 23895 * Destroys fullpage.js plugin events and optinally its html markup and styles 23896 */ 23897 function destroy(all){ 23898 setAutoScrolling(false, 'internal'); 23899 setAllowScrolling(false); 23900 setKeyboardScrolling(false); 23901 container.addClass(DESTROYED); 23902 23903 clearTimeout(afterSlideLoadsId); 23904 clearTimeout(afterSectionLoadsId); 23905 clearTimeout(resizeId); 23906 clearTimeout(scrollId); 23907 clearTimeout(scrollId2); 23908 23909 $window 23910 .off('scroll', scrollHandler) 23911 .off('hashchange', hashChangeHandler) 23912 .off('resize', resizeHandler); 23913 23914 $document 23915 .off('click touchstart', SECTION_NAV_SEL + ' a') 23916 .off('mouseenter', SECTION_NAV_SEL + ' li') 23917 .off('mouseleave', SECTION_NAV_SEL + ' li') 23918 .off('click touchstart', SLIDES_NAV_LINK_SEL) 23919 .off('mouseover', options.normalScrollElements) 23920 .off('mouseout', options.normalScrollElements); 23921 23922 $(SECTION_SEL) 23923 .off('click touchstart', SLIDES_ARROW_SEL); 23924 23925 clearTimeout(afterSlideLoadsId); 23926 clearTimeout(afterSectionLoadsId); 23927 23928 //lets make a mess! 23929 if(all){ 23930 destroyStructure(); 23931 } 23932 } 23933 23934 /* 23935 * Removes inline styles added by fullpage.js 23936 */ 23937 function destroyStructure(){ 23938 //reseting the `top` or `translate` properties to 0 23939 silentScroll(0); 23940 23941 //loading all the lazy load content 23942 container.find('img[data-src], source[data-src], audio[data-src], iframe[data-src]').each(function(){ 23943 setSrc($(this), 'src'); 23944 }); 23945 23946 container.find('img[data-srcset]').each(function(){ 23947 setSrc($(this), 'srcset'); 23948 }); 23949 23950 $(SECTION_NAV_SEL + ', ' + SLIDES_NAV_SEL + ', ' + SLIDES_ARROW_SEL).remove(); 23951 23952 //removing inline styles 23953 $(SECTION_SEL).css( { 23954 'height': '', 23955 'background-color' : '', 23956 'padding': '' 23957 }); 23958 23959 $(SLIDE_SEL).css( { 23960 'width': '' 23961 }); 23962 23963 container.css({ 23964 'height': '', 23965 'position': '', 23966 '-ms-touch-action': '', 23967 'touch-action': '' 23968 }); 23969 23970 $htmlBody.css({ 23971 'overflow': '', 23972 'height': '' 23973 }); 23974 23975 // remove .fp-enabled class 23976 $('html').removeClass(ENABLED); 23977 23978 // remove .fp-responsive class 23979 $body.removeClass(RESPONSIVE); 23980 23981 // remove all of the .fp-viewing- classes 23982 $.each($body.get(0).className.split(/\s+/), function (index, className) { 23983 if (className.indexOf(VIEWING_PREFIX) === 0) { 23984 $body.removeClass(className); 23985 } 23986 }); 23987 23988 //removing added classes 23989 $(SECTION_SEL + ', ' + SLIDE_SEL).each(function(){ 23990 options.scrollOverflowHandler.remove($(this)); 23991 $(this).removeClass(TABLE + ' ' + ACTIVE); 23992 }); 23993 23994 removeAnimation(container); 23995 23996 //Unwrapping content 23997 container.find(TABLE_CELL_SEL + ', ' + SLIDES_CONTAINER_SEL + ', ' + SLIDES_WRAPPER_SEL).each(function(){ 23998 //unwrap not being use in case there's no child element inside and its just text 23999 $(this).replaceWith(this.childNodes); 24000 }); 24001 24002 //removing the applied transition from the fullpage wrapper 24003 container.css({
24004 '-webkit-transition': 'none', 24005 'transition': 'none' 24006 }); 24007 24008 //scrolling the page to the top with no animation 24009 $htmlBody.scrollTop(0); 24010 24011 //removing selectors 24012 var usedSelectors = [SECTION, SLIDE, SLIDES_CONTAINER]; 24013 $.each(usedSelectors, function(index, value){ 24014 $('.' + value).removeClass(value); 24015 }); 24016 } 24017 24018 /* 24019 * Sets the state for a variable with multiple states (original, and temporal) 24020 * Some variables such as `autoScrolling` or `recordHistory` might change automatically its state when using `responsive` or `autoScrolling:false`. 24021 * This function is used to keep track of both states, the original and the temporal one. 24022 * If type is not 'internal', then we assume the user is globally changing the variable. 24023 */ 24024 function setVariableState(variable, value, type){ 24025 options[variable] = value; 24026 if(type !== 'internal'){ 24027 originals[variable] = value; 24028 } 24029 } 24030 24031 /** 24032 * Displays warnings 24033 */ 24034 function displayWarnings(){ 24035 var extensions = ['fadingEffect', 'continuousHorizontal', 'scrollHorizontally', 'interlockedSlides', 'resetSliders', 'responsiveSlides', 'offsetSections', 'dragAndMove', 'scrollOverflowReset', 'parallax']; 24036 //UNCODE.addition 24037 // if($('html').hasClass(ENABLED)){ 24038 // showError('error', 'Fullpage.js can only be initialized once and you are doing it multiple times!'); 24039 // return; 24040 // } 24041 24042 // Disable mutually exclusive settings 24043 //UNCODE.addition 24044 // if (options.continuousVertical && 24045 // (options.loopTop || options.loopBottom)) { 24046 // options.continuousVertical = false;
24047 // showError('warn', 'Option `loopTop/loopBottom` is mutually exclusive with `continuousVertical`; `continuousVertical` disabled'); 24048 // } 24049 24050 // if(options.scrollBar && options.scrollOverflow){ 24051 // showError('warn', 'Option `scrollBar` is mutually exclusive with `scrollOverflow`. Sections with scrollOverflow might not work well in Firefox'); 24052 // } 24053 24054 // if(options.continuousVertical && (options.scrollBar || !options.autoScrolling)){ 24055 // options.continuousVertical = false; 24056 // showError('warn', 'Scroll bars (`scrollBar:true` or `autoScrolling:false`) are mutually exclusive with `continuousVertical`; `continuousVertical` disabled'); 24057 // } 24058 24059 //using extensions? Wrong file! 24060 $.each(extensions, function(index, extension){ 24061 //is the option set to true? 24062 if(options[extension]){ 24063 showError('warn', 'fullpage.js extensions require jquery.fullpage.extensions.min.js file instead of the usual jquery.fullpage.js. Requested: '+ extension); 24064 } 24065 }); 24066 24067 //anchors can not have the same value as any element ID or NAME 24068 $.each(options.anchors, function(index, name){ 24069 24070 //case insensitive selectors (http://stackoverflow.com/a/19465187/1081396) 24071 var nameAttr = $document.find('[name]').filter(function() { 24072 return $(this).attr('name') && $(this).attr('name').toLowerCase() == name.toLowerCase(); 24073 }); 24074 24075 var idAttr = $document.find('[id]').filter(function() { 24076 return $(this).attr('id') && $(this).attr('id').toLowerCase() == name.toLowerCase(); 24077 }); 24078 24079 if(idAttr.length || nameAttr.length ){ 24080 showError('error', 'data-anchor tags can not have the same value as any `id` element on the site (or `name` element for IE).'); 24081 idAttr.length && showError('error', '"' + name + '" is is being used by another element `id` property'); 24082 nameAttr.length && showError('error', '"' + name + '" is is being used by another element `name` property'); 24083 } 24084 }); 24085 } 24086 24087 /** 24088 * Shows a message in the console of the given type. 24089 */ 24090 function showError(type, text){ 24091 console && console[type] && console[type]('fullPage: ' + text); 24092 } 24093 24094 }; //end of $.fn.fullpage 24095 24096 if(typeof IScroll !== 'undefined'){ 24097 /* 24098 * Turns iScroll `mousewheel` option off dynamically 24099 * https://github.com/cubiq/iscroll/issues/1036 24100 */ 24101 IScroll.prototype.wheelOn = function () { 24102 this.wrapper.addEventListener('wheel', this); 24103 this.wrapper.addEventListener('mousewheel', this); 24104 this.wrapper.addEventListener('DOMMouseScroll', this); 24105 }; 24106 24107 /* 24108 * Turns iScroll `mousewheel` option on dynamically 24109 * https://github.com/cubiq/iscroll/issues/1036 24110 */ 24111 IScroll.prototype.wheelOff = function () { 24112 this.wrapper.removeEventListener('wheel', this); 24113 this.wrapper.removeEventListener('mousewheel', this); 24114 this.wrapper.removeEventListener('DOMMouseScroll', this); 24115 }; 24116 } 24117 24118 /** 24119 * An object to handle overflow scrolling. 24120 * This uses jquery.slimScroll to accomplish overflow scrolling. 24121 * It is possible to pass in an alternate scrollOverflowHandler 24122 * to the fullpage.js option that implements the same functions 24123 * as this handler. 24124 * 24125 * @type {Object} 24126 */ 24127 var iscrollHandler = { 24128 refreshId: null, 24129 iScrollInstances: [], 24130 24131 // Enables or disables the mouse wheel for the active section or all slides in it 24132 toggleWheel: function(value){ 24133 var scrollable = $(SECTION_ACTIVE_SEL).find(SCROLLABLE_SEL); 24134 scrollable.each(function(){ 24135 var iScrollInstance = $(this).data('iscrollInstance'); 24136 if(typeof iScrollInstance !== 'undefined' && iScrollInstance){ 24137 if(value){ 24138 iScrollInstance.wheelOn(); 24139 } 24140 else{ 24141 iScrollInstance.wheelOff(); 24142 } 24143 } 24144 }); 24145 }, 24146 24147 /** 24148 * Turns off iScroll for the destination section. 24149 * When scrolling very fast on some trackpads (and Apple laptops) the inertial scrolling would
24150 * scroll the destination section/slide before the sections animations ends. 24151 */ 24152 onLeave: function(){ 24153 iscrollHandler.toggleWheel(false); 24154 }, 24155 24156 // Turns off iScroll for the leaving section 24157 beforeLeave: function(){ 24158 iscrollHandler.onLeave() 24159 }, 24160 24161 // Turns on iScroll on section load 24162 afterLoad: function(){ 24163 iscrollHandler.toggleWheel(true); 24164 }, 24165 24166 /** 24167 * Called when overflow scrolling is needed for a section. 24168 * 24169 * @param {Object} element jQuery object containing current section 24170 * @param {Number} scrollHeight Current window height in pixels 24171 */ 24172 create: function(element, scrollHeight) { 24173 var scrollable = element.find(SCROLLABLE_SEL); 24174 24175 scrollable.height(scrollHeight); 24176 scrollable.each(function() { 24177 var $this = $(this); 24178 var iScrollInstance = $this.data('iscrollInstance'); 24179 if (iScrollInstance) { 24180 $.each(iscrollHandler.iScrollInstances, function(){ 24181 $(this).destroy(); 24182 }); 24183 } 24184 24185 iScrollInstance = new IScroll($this.get(0), iscrollOptions); 24186 iscrollHandler.iScrollInstances.push(iScrollInstance); 24187 24188 //off by default until the section gets active 24189 iScrollInstance.wheelOff(); 24190 24191 $this.data('iscrollInstance', iScrollInstance); 24192 }); 24193 }, 24194 24195 /** 24196 * Return a boolean depending on whether the scrollable element is a 24197 * the end or at the start of the scrolling depending on the given type. 24198 * 24199 * @param {String} type Either 'top' or 'bottom' 24200 * @param {Object} scrollable jQuery object for the scrollable element 24201 * @return {Boolean} 24202 */ 24203 isScrolled: function(type, scrollable) { 24204 var scroller = scrollable.data('iscrollInstance'); 24205 24206 //no scroller? 24207 if (!scroller) { 24208 return true; 24209 } 24210 24211 if (type === 'top') { 24212 return scroller.y >= 0 && !scrollable.scrollTop(); 24213 } else if (type === 'bottom') { 24214 return (0 - scroller.y) + scrollable.scrollTop() + 1 + scrollable.innerHeight() >= scrollable[0].scrollHeight; 24215 } 24216 }, 24217 24218 /** 24219 * Returns the scrollable element for the given section. 24220 * If there are landscape slides, will only return a scrollable element 24221 * if it is in the active slide. 24222 * 24223 * @param {Object} activeSection jQuery object containing current section 24224 * @return {Boolean} 24225 */ 24226 scrollable: function(activeSection){ 24227 // if there are landscape slides, we check if the scrolling bar is in the current one or not 24228 if (activeSection.find(SLIDES_WRAPPER_SEL).length) { 24229 return activeSection.find(SLIDE_ACTIVE_SEL).find(SCROLLABLE_SEL); 24230 } 24231 return activeSection.find(SCROLLABLE_SEL); 24232 }, 24233 24234 /** 24235 * Returns the scroll height of the wrapped content. 24236 * If this is larger than the window height minus section padding, 24237 * overflow scrolling is needed. 24238 * 24239 * @param {Object} element jQuery object containing current section 24240 * @return {Number} 24241 */ 24242 scrollHeight: function(element) { 24243 return element.find(SCROLLABLE_SEL).children().first().get(0).scrollHeight; 24244 }, 24245 24246 /** 24247 * Called when overflow scrolling is no longer needed for a section. 24248 * 24249 * @param {Object} element jQuery object containing current section 24250 */ 24251 remove: function(element) { 24252 var scrollable = element.find(SCROLLABLE_SEL); 24253 if (scrollable.length) { 24254 var iScrollInstance = scrollable.data('iscrollInstance'); 24255 iScrollInstance.destroy(); 24256 24257 scrollable.data('iscrollInstance', null); 24258 } 24259 element.find(SCROLLABLE_SEL).children().first().children().first().unwrap().unwrap(); 24260 }, 24261 24262 /** 24263 * Called when overflow scrolling has already been setup but the 24264 * window height has potentially changed. 24265 * 24266 * @param {Object}
vendor: 16,384 bytes, lines 24266-24809
24266 element jQuery object containing current section 24267 * @param {Number} scrollHeight Current window height in pixels 24268 */ 24269 update: function(element, scrollHeight) { 24270 //using a timeout in order to execute the refresh function only once when `update` is called multiple times in a 24271 //short period of time. 24272 //it also comes on handy because iScroll requires the use of timeout when using `refresh`. 24273 clearTimeout(iscrollHandler.refreshId); 24274 iscrollHandler.refreshId = setTimeout(function(){ 24275 $.each(iscrollHandler.iScrollInstances, function(){ 24276 $(this).get(0).refresh(); 24277 }); 24278 }, 150); 24279 24280 //updating the wrappers height 24281 element.find(SCROLLABLE_SEL).css('height', scrollHeight + 'px').parent().css('height', scrollHeight + 'px'); 24282 }, 24283 24284 /** 24285 * Called to get any additional elements needed to wrap the section 24286 * content in order to facilitate overflow scrolling. 24287 * 24288 * @return {String|Object} Can be a string containing HTML, 24289 * a DOM element, or jQuery object. 24290 */ 24291 wrapContent: function() { 24292 return '<div class="' + SCROLLABLE + '"><div class="fp-scroller"></div></div>'; 24293 } 24294 }; 24295}); 24296 24297/* ======================================================================== 24298 * Bootstrap: collapse.js v3.1.1 24299 * http://getbootstrap.com/javascript/#collapse 24300 * ======================================================================== 24301 * Copyright 2011-2014 Twitter, Inc. 24302 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 24303 * ======================================================================== */ 24304 24305 24306+function ($) { 24307 'use strict'; 24308 24309 // COLLAPSE PUBLIC CLASS DEFINITION 24310 // ================================ 24311 24312 var Collapse = function (element, options) { 24313 this.$element = $(element) 24314 this.options = $.extend({}, Collapse.DEFAULTS, options) 24315 this.transitioning = null 24316 24317 if (this.options.parent) this.$parent = $(this.options.parent) 24318 if (this.options.toggle) this.toggle() 24319 } 24320 24321 Collapse.DEFAULTS = { 24322 toggle: true 24323 } 24324 24325 Collapse.prototype.dimension = function () { 24326 var hasWidth = this.$element.hasClass('width') 24327 return hasWidth ? 'width' : 'height' 24328 } 24329 24330 Collapse.prototype.show = function () { 24331 if (this.transitioning || this.$element.hasClass('in')) return 24332 24333 var startEvent = $.Event('show.bs.collapse') 24334 this.$element.trigger(startEvent) 24335 if (startEvent.isDefaultPrevented()) return 24336 24337 var actives = this.$parent && this.$parent.find('> .panel > .in') 24338 24339 if (actives && actives.length) { 24340 var hasData = actives.data('bs.collapse') 24341 if (hasData && hasData.transitioning) return 24342 actives.collapse('hide') 24343 hasData || actives.data('bs.collapse', null) 24344 } 24345 24346 var dimension = this.dimension() 24347 24348 this.$element 24349 .removeClass('collapse') 24350 .addClass('collapsing')[dimension](0) 24351 24352 this.transitioning = 1 24353 24354 var complete = function (e) { 24355 if (e && e.target != this.$element[0]) return 24356 this.$element 24357 .removeClass('collapsing') 24358 .addClass('collapse in')[dimension]('auto') 24359 this.transitioning = 0 24360 this.$element.trigger('shown.bs.collapse') 24361 } 24362 24363 if (!$.support.transition) return complete.call(this) 24364 24365 var scrollSize = $.camelCase(['scroll', dimension].join('-')) 24366 24367 this.$element 24368 .one($.support.transition.end, $.proxy(complete, this)) 24369 .emulateTransitionEnd(350)[dimension](this.$element[0][scrollSize]) 24370 } 24371 24372 Collapse.prototype.hide = function () { 24373 if (this.transitioning || !this.$element.hasClass('in')) return 24374 24375 var startEvent = $.Event('hide.bs.collapse') 24376 this.$element.trigger(startEvent) 24377 if (startEvent.isDefaultPrevented()) return 24378 24379 var dimension = this.dimension() 24380 24381 this.$element[dimension](this.$element[dimension]())[0].offsetHeight 24382 24383 this.$element 24384 .addClass('collapsing') 24385 .removeClass('collapse') 24386 .removeClass('in') 24387 24388 this.transitioning = 1 24389 24390 var complete = function (e) { 24391 if (e && e.target != this.$element[0]) return 24392 this.transitioning = 0 24393 this.$element 24394 .trigger('hidden.bs.collapse') 24395 .removeClass('collapsing') 24396 .addClass('collapse') 24397 } 24398 24399 if (!$.support.transition) return complete.call(this) 24400 24401 this.$element 24402 [dimension](0) 24403 .one($.support.transition.end, $.proxy(complete, this)) 24404 .emulateTransitionEnd(350) 24405 } 24406 24407 Collapse.prototype.toggle = function () { 24408 this[this.$element.hasClass('in') ? 'hide' : 'show']() 24409 } 24410 24411 24412 // COLLAPSE PLUGIN DEFINITION 24413 // ========================== 24414 24415 var old = $.fn.collapse 24416 24417 $.fn.collapse = function (option) { 24418 return this.each(function () { 24419 var $this = $(this) 24420 var data = $this.data('bs.collapse') 24421 var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) 24422 24423 if (!data && options.toggle && option == 'show') option = !option 24424 if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) 24425 if (typeof option == 'string') data[option]() 24426 }) 24427 } 24428 24429 $.fn.collapse.Constructor = Collapse 24430 24431 24432 // COLLAPSE NO CONFLICT 24433 // ==================== 24434 24435 $.fn.collapse.noConflict = function () { 24436 $.fn.collapse = old 24437 return this 24438 } 24439 24440 24441 // COLLAPSE DATA-API 24442 // ================= 24443 24444 $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) { 24445 var $this = $(this), href 24446 var target = $this.attr('data-target') 24447 || e.preventDefault() 24448 || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 24449 //Edited by Uncode to replace ID in panel [START] 24450 var _target = href.replace(/^#/, ""); 24451 if ( $('[data-id="' + _target + '"]').length ) { 24452 var $target = $('[data-id="' + _target + '"]') 24453 } else { 24454 var $target = $(target) 24455 } 24456 //Edited by Uncode to replace ID in panel [END] 24457 var data = $target.data('bs.collapse') 24458 var option = data ? 'toggle' : $this.data() 24459 var parent = $this.attr('data-parent') 24460 var $parent = parent && $(parent) 24461 24462 if (!data || !data.transitioning) { 24463 if ($parent) $parent.find('[data-toggle="collapse"][data-parent="' + parent + '"]').not($this).addClass('collapsed') 24464 $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed') 24465 } 24466 24467 $target.collapse(option) 24468 }) 24469 24470}(jQuery); 24471 24472/* ======================================================================== 24473 * Bootstrap: tab.js v3.1.1 24474 * http://getbootstrap.com/javascript/#tabs 24475 * ======================================================================== 24476 * Copyright 2011-2014 Twitter, Inc. 24477 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 24478 * ======================================================================== */ 24479 24480 24481+function ($) { 24482 'use strict'; 24483 24484 // TAB CLASS DEFINITION 24485 // ==================== 24486 24487 var Tab = function (element) { 24488 this.element = $(element) 24489 } 24490 24491 Tab.prototype.show = function () { 24492 var $this = this.element 24493 var $ul = $this.closest('ul:not(.dropdown-menu)') 24494 var selector = $this.data('target') 24495 24496 if (!selector) { 24497 selector = $this.attr('href') 24498 selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 24499 } 24500 24501 if ($this.parent('li').hasClass('active')) return 24502 24503 var previous = $ul.find('.active:last a')[0] 24504 var e = $.Event('show.bs.tab', { 24505 relatedTarget: previous 24506 }) 24507 24508 $this.trigger(e) 24509 24510 if (e.isDefaultPrevented()) return 24511 24512 //Edited by Uncode to replace ID in panel [START] 24513 var _target = selector.replace(/^#/, ""); 24514 if ( $('[data-id="' + _target + '"]').length ) 24515 var $target = $('[data-id="' + _target + '"]') 24516 else 24517 var $target = $(selector) 24518 //Edited by Uncode to replace ID in panel [END] 24519 24520 this.activate($this.parent('li'), $ul) 24521 this.activate($target, $target.parent(), function () { 24522 $this.trigger({ 24523 type: 'shown.bs.tab', 24524 relatedTarget: previous 24525 }) 24526 }) 24527 } 24528 24529 Tab.prototype.activate = function (element, container, callback) { 24530 var $active = container.find('> .active') 24531 var transition = callback 24532 && $.support.transition 24533 && $active.hasClass('fade') 24534 24535 function next() { 24536 $active 24537 .removeClass('active') 24538 .find('> .dropdown-menu > .active') 24539 .removeClass('active') 24540 24541 element.addClass('active') 24542 24543 if (transition) { 24544 element[0].offsetWidth // reflow for transition 24545 element.addClass('in') 24546 } else { 24547 element.removeClass('fade') 24548 } 24549 24550 if (element.parent('.dropdown-menu')) { 24551 element.closest('li.dropdown').addClass('active') 24552 } 24553 24554 callback && callback() 24555 } 24556 24557 transition ? 24558 $active 24559 .one($.support.transition.end, next) 24560 .emulateTransitionEnd(150) : 24561 next() 24562 24563 $active.removeClass('in') 24564 } 24565 24566 24567 // TAB PLUGIN DEFINITION 24568 // ===================== 24569 24570 var old = $.fn.tab 24571 24572 $.fn.tab = function ( option ) { 24573 return this.each(function () { 24574 var $this = $(this) 24575 var data = $this.data('bs.tab') 24576 24577 if (!data) $this.data('bs.tab', (data = new Tab(this))) 24578 if (typeof option == 'string') data[option]() 24579 }) 24580 } 24581 24582 $.fn.tab.Constructor = Tab 24583 24584 24585 // TAB NO CONFLICT 24586 // =============== 24587 24588 $.fn.tab.noConflict = function () { 24589 $.fn.tab = old 24590 return this 24591 } 24592 24593 24594 // TAB DATA-API 24595 // ============ 24596 24597 $(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) { 24598 e.preventDefault() 24599 $(this).tab('show') 24600 }) 24601 24602}(jQuery); 24603 24604/* ======================================================================== 24605 * Bootstrap: tooltip.js v3.1.1 24606 * http://getbootstrap.com/javascript/#tooltip 24607 * Inspired by the original jQuery.tipsy by Jason Frame 24608 * ======================================================================== 24609 * Copyright 2011-2014 Twitter, Inc. 24610 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 24611 * ======================================================================== */ 24612 24613 24614+function ($) { 24615 'use strict'; 24616 24617 // TOOLTIP PUBLIC CLASS DEFINITION 24618 // =============================== 24619 24620 var Tooltip = function (element, options) { 24621 this.type = 24622 this.options = 24623 this.enabled = 24624 this.timeout = 24625 this.hoverState = 24626 this.$element = null 24627 24628 this.init('tooltip', element, options) 24629 } 24630 24631 Tooltip.DEFAULTS = { 24632 animation: true, 24633 placement: 'top', 24634 selector: false, 24635 template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>', 24636 trigger: 'hover focus', 24637 title: '', 24638 delay: 0, 24639 html: false, 24640 container: false, 24641 viewport: { 24642 selector: 'body', 24643 padding: 0 24644 } 24645 } 24646 24647 Tooltip.prototype.init = function (type, element, options) { 24648 this.enabled = true 24649 this.type = type 24650 this.$element = $(element) 24651 this.options = this.getOptions(options) 24652 this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport) 24653 24654 var triggers = this.options.trigger.split(' ') 24655 24656 for (var i = triggers.length; i--;) { 24657 var trigger = triggers[i] 24658 24659 if (trigger == 'click') { 24660 this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this)) 24661 } else if (trigger != 'manual') { 24662 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin' 24663 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout' 24664 24665 this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this)) 24666 this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this)) 24667 } 24668 } 24669 24670 this.options.selector ? 24671 (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) : 24672 this.fixTitle() 24673 } 24674 24675 Tooltip.prototype.getDefaults = function () { 24676 return Tooltip.DEFAULTS 24677 } 24678 24679 Tooltip.prototype.getOptions = function (options) { 24680 options = $.extend({}, this.getDefaults(), this.$element.data(), options) 24681 24682 if (options.delay && typeof options.delay == 'number') { 24683 options.delay = { 24684 show: options.delay, 24685 hide: options.delay 24686 } 24687 } 24688 24689 return options 24690 } 24691 24692 Tooltip.prototype.getDelegateOptions = function () { 24693 var options = {} 24694 var defaults = this.getDefaults() 24695 24696 this._options && $.each(this._options, function (key, value) { 24697 if (defaults[key] != value) options[key] = value 24698 }) 24699 24700 return options 24701 } 24702 24703 Tooltip.prototype.enter = function (obj) { 24704 var self = obj instanceof this.constructor ? 24705 obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) 24706 24707 clearTimeout(self.timeout) 24708 24709 self.hoverState = 'in' 24710 24711 if (!self.options.delay || !self.options.delay.show) return self.show() 24712 24713 self.timeout = setTimeout(function () { 24714 if (self.hoverState == 'in') self.show() 24715 }, self.options.delay.show) 24716 } 24717 24718 Tooltip.prototype.leave = function (obj) { 24719 var self = obj instanceof this.constructor ? 24720 obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) 24721 24722 clearTimeout(self.timeout) 24723 24724 self.hoverState = 'out' 24725 24726 if (!self.options.delay || !self.options.delay.hide) return self.hide() 24727 24728 self.timeout = setTimeout(function () { 24729 if (self.hoverState == 'out') self.hide() 24730 }, self.options.delay.hide) 24731 } 24732 24733 Tooltip.prototype.show = function () { 24734 var e = $.Event('show.bs.' + this.type) 24735 24736 if (this.hasContent() && this.enabled) { 24737 this.$element.trigger(e) 24738 24739 if (e.isDefaultPrevented()) return 24740 var that = this; 24741 24742 var $tip = this.tip() 24743 24744 this.setContent() 24745 24746 if (this.options.animation) $tip.addClass('fade') 24747 24748 var placement = typeof this.options.placement == 'function' ? 24749 this.options.placement.call(this, $tip[0], this.$element[0]) : 24750 this.options.placement 24751 24752 var autoToken = /\s?auto?\s?/i 24753 var autoPlace = autoToken.test(placement) 24754 if (autoPlace) placement = placement.replace(autoToken, '') || 'top' 24755 24756 $tip 24757 .detach() 24758 .css({ top: 0, left: 0, display: 'block' }) 24759 .addClass(placement) 24760 24761 this.options.container ? $tip.appendTo($(document).find(this.options.container)) : $tip.insertAfter(this.$element) 24762 24763 var pos = this.getPosition() 24764 var actualWidth = $tip[0].offsetWidth 24765 var actualHeight = $tip[0].offsetHeight 24766 24767 if (autoPlace) { 24768 var orgPlacement = placement 24769 var $parent = this.$element.parent() 24770 var parentDim = this.getPosition($parent) 24771 24772 placement = placement == 'bottom' && pos.top + pos.height + actualHeight - parentDim.scroll > parentDim.height ? 'top' : 24773 placement == 'top' && pos.top - parentDim.scroll - actualHeight < 0 ? 'bottom' : 24774 placement == 'right' && pos.right + actualWidth > parentDim.width ? 'left' : 24775 placement == 'left' && pos.left - actualWidth < parentDim.left ? 'right' : 24776 placement 24777 24778 $tip 24779 .removeClass(orgPlacement) 24780 .addClass(placement) 24781 } 24782 24783 var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight) 24784 24785 this.applyPlacement(calculatedOffset, placement) 24786 this.hoverState = null 24787 24788 var complete = function() { 24789 that.$element.trigger('shown.bs.' + that.type) 24790 } 24791 24792 $.support.transition && this.$tip.hasClass('fade') ? 24793 $tip 24794 .one($.support.transition.end, complete) 24795 .emulateTransitionEnd(150) : 24796 complete() 24797 } 24798 } 24799 24800 Tooltip.prototype.applyPlacement = function (offset, placement) { 24801 var $tip = this.tip() 24802 var width = $tip[0].offsetWidth 24803 var height = $tip[0].offsetHeight 24804 24805 // manually read margins because getBoundingClientRect includes difference 24806 var marginTop = parseInt($tip.css('margin-top'), 10) 24807 var marginLeft = parseInt($tip.css('margin-left'), 10) 24808 24809 // we must check
24809 for NaN for ie 8/9 24810 if (isNaN(marginTop)) marginTop = 0 24811 if (isNaN(marginLeft)) marginLeft = 0 24812 24813 offset.top = offset.top + marginTop 24814 offset.left = offset.left + marginLeft 24815 24816 // $.fn.offset doesn't round pixel values 24817 // so we use setOffset directly with our own function B-0 24818 $.offset.setOffset($tip[0], $.extend({ 24819 using: function (props) { 24820 $tip.css({ 24821 top: Math.round(props.top), 24822 left: Math.round(props.left) 24823 }) 24824 } 24825 }, offset), 0) 24826 24827 $tip.addClass('in') 24828 24829 // check to see if placing tip in new offset caused the tip to resize itself 24830 var actualWidth = $tip[0].offsetWidth 24831 var actualHeight = $tip[0].offsetHeight 24832 24833 if (placement == 'top' && actualHeight != height) { 24834 offset.top = offset.top + height - actualHeight 24835 } 24836 24837 var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight) 24838 24839 if (delta.left) offset.left += delta.left 24840 else offset.top += delta.top 24841 24842 var arrowDelta = delta.left ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight 24843 var arrowPosition = delta.left ? 'left' : 'top' 24844 var arrowOffsetPosition = delta.left ? 'offsetWidth' : 'offsetHeight' 24845 24846 $tip.offset(offset) 24847 this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], arrowPosition) 24848 } 24849 24850 Tooltip.prototype.replaceArrow = function (delta, dimension, position) { 24851 this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + '%') : '') 24852 } 24853 24854 Tooltip.prototype.setContent = function () { 24855 var $tip = this.tip() 24856 var title = this.getTitle() 24857 24858 $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title) 24859 $tip.removeClass('fade in top bottom left right') 24860 } 24861 24862 Tooltip.prototype.hide = function () { 24863 var that = this 24864 var $tip = this.tip() 24865 var e = $.Event('hide.bs.' + this.type) 24866 24867 function complete() { 24868 if (that.hoverState != 'in') $tip.detach() 24869 that.$element.trigger('hidden.bs.' + that.type) 24870 } 24871 24872 this.$element.trigger(e) 24873 24874 if (e.isDefaultPrevented()) return 24875 24876 $tip.removeClass('in') 24877 24878 $.support.transition && this.$tip.hasClass('fade') ? 24879 $tip 24880 .one($.support.transition.end, complete) 24881 .emulateTransitionEnd(150) : 24882 complete() 24883 24884 this.hoverState = null 24885 24886 return this 24887 } 24888 24889 Tooltip.prototype.fixTitle = function () { 24890 var $e = this.$element 24891 if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') { 24892 $e.attr('data-original-title', $e.attr('title') || '').attr('title', '') 24893 } 24894 } 24895 24896 Tooltip.prototype.hasContent = function () { 24897 return this.getTitle() 24898 } 24899 24900 Tooltip.prototype.getPosition = function ($element) { 24901 $element = $element || this.$element 24902 var el = $element[0] 24903 var isBody = el.tagName == 'BODY' 24904 return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : null, { 24905 scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop(), 24906 width: isBody ? $(window).width() : $element.outerWidth(), 24907 height: isBody ? $(window).height() : $element.outerHeight() 24908 }, isBody ? {top: 0, left: 0} : $element.offset()) 24909 } 24910 24911 Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) { 24912 return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } : 24913 placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } : 24914 placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } : 24915 /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width } 24916 24917 } 24918 24919 Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) { 24920 var delta = { top: 0, left: 0 } 24921 if (!this.$viewport) return delta 24922 24923 var viewportPadding = this.options.viewport && this.options.viewport.padding || 0 24924 var viewportDimensions = this.getPosition(this.$viewport) 24925 24926 if (/right|left/.test(placement)) { 24927 var topEdgeOffset = pos.top - viewportPadding - viewportDimensions.scroll 24928 var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight 24929 if (topEdgeOffset < viewportDimensions.top) { // top overflow 24930 delta.top = viewportDimensions.top - topEdgeOffset 24931 } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow 24932 delta.top = viewportDimensions.top + viewportDimensions.height - bottom
24932EdgeOffset 24933 } 24934 } else { 24935 var leftEdgeOffset = pos.left - viewportPadding 24936 var rightEdgeOffset = pos.left + viewportPadding + actualWidth 24937 if (leftEdgeOffset < viewportDimensions.left) { // left overflow 24938 delta.left = viewportDimensions.left - leftEdgeOffset 24939 } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow 24940 delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset 24941 } 24942 } 24943 24944 return delta 24945 } 24946 24947 Tooltip.prototype.getTitle = function () { 24948 var title 24949 var $e = this.$element 24950 var o = this.options 24951 24952 title = $e.attr('data-original-title') 24953 || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title) 24954 24955 return title 24956 } 24957 24958 Tooltip.prototype.tip = function () { 24959 return this.$tip = this.$tip || $(this.options.template) 24960 } 24961 24962 Tooltip.prototype.arrow = function () { 24963 return this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow') 24964 } 24965 24966 Tooltip.prototype.validate = function () { 24967 if (!this.$element[0].parentNode) { 24968 this.hide() 24969 this.$element = null 24970 this.options = null 24971 } 24972 } 24973 24974 Tooltip.prototype.enable = function () { 24975 this.enabled = true 24976 } 24977 24978 Tooltip.prototype.disable = function () { 24979 this.enabled = false 24980 } 24981 24982 Tooltip.prototype.toggleEnabled = function () { 24983 this.enabled = !this.enabled 24984 } 24985 24986 Tooltip.prototype.toggle = function (e) { 24987 var self = e ? $(e.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) : this 24988 self.tip().hasClass('in') ? self.leave(self) : self.enter(self) 24989 } 24990 24991 Tooltip.prototype.destroy = function () { 24992 clearTimeout(this.timeout) 24993 this.hide().$element.off('.' + this.type).removeData('bs.' + this.type) 24994 } 24995 24996 24997 // TOOLTIP PLUGIN DEFINITION 24998 // ========================= 24999 25000 var old = $.fn.tooltip 25001 25002 $.fn.tooltip = function (option) { 25003 return this.each(function () { 25004 var $this = $(this) 25005 var data = $this.data('bs.tooltip') 25006 var options = typeof option == 'object' && option 25007 25008 if (!data && option == 'destroy') return 25009 if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options))) 25010 if (typeof option == 'string') data[option]() 25011 }) 25012 } 25013 25014 $.fn.tooltip.Constructor = Tooltip 25015 25016 25017 // TOOLTIP NO CONFLICT 25018 // =================== 25019 25020 $.fn.tooltip.noConflict = function () { 25021 $.fn.tooltip = old 25022 return this 25023 } 25024 25025}(jQuery); 25026 25027/* ======================================================================== 25028 * Bootstrap: transition.js v3.1.1 25029 * http://getbootstrap.com/javascript/#transitions 25030 * ======================================================================== 25031 * Copyright 2011-2014 Twitter, Inc. 25032 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 25033 * ======================================================================== */ 25034 25035 25036+function ($) { 25037 'use strict'; 25038 25039 // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) 25040 // ============================================================ 25041 25042 function transitionEnd() { 25043 var el = document.createElement('bootstrap') 25044 25045 var transEndEventNames = { 25046 WebkitTransition : 'webkitTransitionEnd', 25047 MozTransition : 'transitionend', 25048 OTransition : 'oTransitionEnd otransitionend', 25049 transition : 'transitionend' 25050 } 25051 25052 for (var name in transEndEventNames) { 25053 if (el.style[name] !== undefined) { 25054 return { end: transEndEventNames[name] } 25055 } 25056 } 25057 25058 return false // explicit for ie8 ( ._.) 25059 } 25060 25061 // http://blog.alexmaccaw.com/css-transitions 25062 $.fn.emulateTransitionEnd = function (duration) { 25063 var called = false, $el = this 25064 $(this).one($.support.transition.end, function () { called = true }) 25065 var callback = function () { if (!called) $($el).trigger($.support.transition.end) } 25066 setTimeout(callback, duration) 25067 return this 25068 } 25069 25070 $(function () { 25071 $.support.transition = transitionEnd() 25072 }) 25073 25074}(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.