1/** 2 * Galleria v 1.2.8 2012-08-09 3 * http://galleria.io 4 * 5 * Licensed under the MIT license 6 * https://raw.github.com/aino/galleria/master/LICENSE 7 * 8 */ 9 10(function( $ ) { 11 12/*global jQuery, navigator, Galleria:true, Image */ 13 14// some references 15var undef, 16 window = this, 17 doc = window.document, 18 $doc = $( doc ), 19 $win = $( window ), 20 21// native prototypes 22 protoArray = Array.prototype, 23 24// internal constants 25 VERSION = 1.28, 26 DEBUG = true, 27 TIMEOUT = 30000, 28 DUMMY = false, 29 NAV = navigator.userAgent.toLowerCase(), 30 HASH = window.location.hash.replace(/#\//, ''), 31 F = function(){}, 32 FALSE = function() { return false; }, 33 IE = (function() { 34 35 var v = 3, 36 div = doc.createElement( 'div' ), 37 all = div.getElementsByTagName( 'i' ); 38 39 do { 40 div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->'; 41 } while ( all[0] ); 42 43 return v > 4 ? v : undef; 44 45 }() ), 46 DOM = function() { 47 return { 48 html: doc.documentElement, 49 body: doc.body, 50 head: doc.getElementsByTagName('head')[0], 51 title: doc.title 52 }; 53 }, 54 55 // list of Galleria events 56 _eventlist = 'data ready thumbnail loadstart loadfinish image play pause progress ' + 57 'fullscreen_enter fullscreen_exit idle_enter idle_exit rescale ' + 58 'lightbox_open lightbox_close lightbox_image', 59 60 _events = (function() { 61 62 var evs = []; 63 64 $.each( _eventlist.split(' '), function( i, ev ) { 65 evs.push( ev ); 66 67 // legacy events 68 if ( /_/.test( ev ) ) { 69 evs.push( ev.replace( /_/g, '' ) ); 70 } 71 }); 72 73 return evs; 74 75 }()), 76 77 // legacy options 78 // allows the old my_setting syntax and converts it to camel case 79 80 _legacyOptions = function( options ) { 81 82 var n; 83 84 if ( typeof options !== 'object' ) { 85 86 // return whatever it was... 87 return options; 88 } 89 90 $.each( options, function( key, value ) { 91 if ( /^[a-z]+_/.test( key ) ) { 92 n = ''; 93 $.each( key.split('_'), function( i, k ) { 94 n += i > 0 ? k.substr( 0, 1 ).toUpperCase() + k.substr( 1 ) : k; 95 }); 96 options[ n ] = value; 97 delete options[ key ]; 98 } 99 }); 100 101 return options; 102 }, 103 104 _patchEvent = function( type ) { 105 106 // allow 'image' instead of Galleria.IMAGE 107 if ( $.inArray( type, _events ) > -1 ) { 108 return Galleria[ type.toUpperCase() ]; 109 } 110 111 return type; 112 }, 113 114 // video providers 115 _video = { 116 youtube: { 117 reg: /https?:\/\/(?:[a-zA_Z]{2,3}.)?(?:youtube\.com\/watch\?)((?:[\w\d\-\_\=]+&(?:amp;)?)*v(?:<[A-Z]+>)?=([0-9a-zA-Z\-\_]+))/i, 118 embed: function(id) { 119 return 'http://www.youtube.com/embed/'+id; 120 }, 121 getThumb: function( id, success, fail ) { 122 fail = fail || F; 123 $.getJSON('http://gdata.youtube.com/feeds/api/videos/' + id + '?v=2&alt=json-in-script&callback=?', function(data) { 124 try { 125 success( data.entry.media$group.media$thumbnail[0].url ); 126 } catch(e) { 127 fail(); 128 } 129 }).error(fail); 130 } 131 }, 132 vimeo: { 133 reg: /https?:\/\/(?:www\.)?(vimeo\.com)\/(?:hd#)?([0-9]+)/i, 134 embed: function(id) { 135 return 'http://player.vimeo.com/video/'+id; 136 }, 137 getThumb: function( id, success, fail ) { 138 fail = fail || F; 139 $.getJSON('http://vimeo.com/api/v2/video/' + id + '.json?callback=?', function(data) { 140 try { 141 success( data[0].thumbnail_medium ); 142 } catch(e) { 143 fail(); 144 } 145 }).error(fail); 146 } 147 }, 148 dailymotion: { 149 reg: /https?:\/\/(?:www\.)?(dailymotion\.com)\/video\/([^_]+)/, 150 embed: function(id) { 151 return 'http://www.dailymotion.com/embed/video/'+id; 152 }, 153 getThumb: function( id, success, fail ) { 154 fail = fail || F; 155 $.getJSON('https://api.dailymotion.com/video/'+id+'?fields=thumbnail_medium_url&callback=?', function(data) { 156 try { 157 success( data.thumbnail_medium_url ); 158 } catch(e) { 159 fail(); 160 } 161 }).error(fail); 162 } 163 } 164 }, 165 166 // utility for testing the video URL and getting the video ID 167 _videoTest = function( url ) { 168 var match; 169 for ( var v in _video ) { 170 match = url && url.match( _video[v].reg ); 171 if( match && match.length ) { 172 return { 173 id: match[2], 174 provider: v 175 }; 176 } 177 } 178 return false;
179 }, 180 181 // native fullscreen handler 182 _nativeFullscreen = { 183 184 support: (function() { 185 var html = DOM().html; 186 return html.requestFullscreen || html.mozRequestFullScreen || html.webkitRequestFullScreen; 187 }()), 188 189 callback: F, 190 191 enter: function( instance, callback ) { 192 193 this.instance = instance; 194 195 this.callback = callback || F; 196 197 var html = DOM().html; 198 if ( html.requestFullscreen ) { 199 html.requestFullscreen(); 200 } 201 else if ( html.mozRequestFullScreen ) { 202 html.mozRequestFullScreen(); 203 } 204 else if ( html.webkitRequestFullScreen ) { 205 html.webkitRequestFullScreen(); 206 } 207 }, 208 209 exit: function( callback ) { 210 211 this.callback = callback || F; 212 213 if ( doc.exitFullscreen ) { 214 doc.exitFullscreen(); 215 } 216 else if ( doc.mozCancelFullScreen ) { 217 doc.mozCancelFullScreen(); 218 } 219 else if ( doc.webkitCancelFullScreen ) { 220 doc.webkitCancelFullScreen(); 221 } 222 }, 223 224 instance: null, 225 226 listen: function() { 227 228 if ( !this.support ) { 229 return; 230 } 231 232 var handler = function() { 233 234 if ( !_nativeFullscreen.instance ) { 235 return; 236 } 237 var fs = _nativeFullscreen.instance._fullscreen; 238 239 if ( doc.fullscreen || doc.mozFullScreen || doc.webkitIsFullScreen ) { 240 fs._enter( _nativeFullscreen.callback ); 241 } else { 242 fs._exit( _nativeFullscreen.callback ); 243 } 244 }; 245 doc.addEventListener( 'fullscreenchange', handler, false ); 246 doc.addEventListener( 'mozfullscreenchange', handler, false ); 247 doc.addEventListener( 'webkitfullscreenchange', handler, false ); 248 } 249 }, 250 251 // the internal gallery holder 252 _galleries = [], 253 254 // the internal instance holder 255 _instances = [], 256 257 // flag for errors 258 _hasError = false, 259 260 // canvas holder 261 _canvas = false, 262 263 // instance pool, holds the galleries until themeLoad is triggered 264 _pool = [], 265 266 // themeLoad trigger 267 _themeLoad = function( theme ) { 268 Galleria.theme = theme; 269 270 // run the instances we have in the pool 271 $.each( _pool, function( i, instance ) { 272 if ( !instance._initialized ) { 273 instance._init.call( instance ); 274 } 275 }); 276 }, 277 278 // the Utils singleton 279 Utils = (function() { 280 281 return { 282 283 // legacy support for clearTimer 284 clearTimer: function( id ) { 285 $.each( Galleria.get(), function() { 286 this.clearTimer( id ); 287 }); 288 }, 289 290 // legacy support for addTimer 291 addTimer: function( id ) { 292 $.each( Galleria.get(), function() { 293 this.addTimer( id ); 294 }); 295 }, 296 297 array : function( obj ) { 298 return protoArray.slice.call(obj, 0); 299 }, 300 301 create : function( className, nodeName ) { 302 nodeName = nodeName || 'div'; 303 var elem = doc.createElement( nodeName ); 304 elem.className = className; 305 return elem; 306 }, 307 308 getScriptPath : function( src ) { 309 310 // the currently executing script is always the last 311 src = src || $('script:last').attr('src'); 312 var slices = src.split('/'); 313 314 if (slices.length == 1) { 315 return ''; 316 } 317 318 slices.pop(); 319 320 return slices.join('/') + '/'; 321 }, 322 323 // CSS3 transitions, added in 1.2.4 324 animate : (function() { 325 326 // detect transition 327 var transition = (function( style ) { 328 var props = 'transition WebkitTransition MozTransition OTransition'.split(' '), 329 i; 330 331 // disable css3 animations in opera until stable 332 if ( window.opera ) { 333 return false;
vendor: 4,170 bytes, lines 334-439
334 } 335 336 for ( i = 0; props[i]; i++ ) { 337 if ( typeof style[ props[ i ] ] !== 'undefined' ) { 338 return props[ i ]; 339 } 340 } 341 return false; 342 }(( doc.body || doc.documentElement).style )); 343 344 // map transitionend event 345 var endEvent = { 346 MozTransition: 'transitionend', 347 OTransition: 'oTransitionEnd', 348 WebkitTransition: 'webkitTransitionEnd', 349 transition: 'transitionend' 350 }[ transition ]; 351 352 // map bezier easing conversions 353 var easings = { 354 _default: [0.25, 0.1, 0.25, 1], 355 galleria: [0.645, 0.045, 0.355, 1], 356 galleriaIn: [0.55, 0.085, 0.68, 0.53], 357 galleriaOut: [0.25, 0.46, 0.45, 0.94], 358 ease: [0.25, 0, 0.25, 1], 359 linear: [0.25, 0.25, 0.75, 0.75], 360 'ease-in': [0.42, 0, 1, 1], 361 'ease-out': [0, 0, 0.58, 1], 362 'ease-in-out': [0.42, 0, 0.58, 1] 363 }; 364 365 // function for setting transition css for all browsers 366 var setStyle = function( elem, value, suffix ) { 367 var css = {}; 368 suffix = suffix || 'transition'; 369 $.each( 'webkit moz ms o'.split(' '), function() { 370 css[ '-' + this + '-' + suffix ] = value; 371 }); 372 elem.css( css ); 373 }; 374 375 // clear styles 376 var clearStyle = function( elem ) { 377 setStyle( elem, 'none', 'transition' ); 378 if ( Galleria.WEBKIT && Galleria.TOUCH ) { 379 setStyle( elem, 'translate3d(0,0,0)', 'transform' ); 380 if ( elem.data('revert') ) { 381 elem.css( elem.data('revert') ); 382 elem.data('revert', null); 383 } 384 } 385 }; 386 387 // various variables 388 var change, strings, easing, syntax, revert, form, css; 389 390 // the actual animation method 391 return function( elem, to, options ) { 392 393 // extend defaults 394 options = $.extend({ 395 duration: 400, 396 complete: F, 397 stop: false 398 }, options); 399 400 // cache jQuery instance 401 elem = $( elem ); 402 403 if ( !options.duration ) { 404 elem.css( to ); 405 options.complete.call( elem[0] ); 406 return; 407 } 408 409 // fallback to jQuery's animate if transition is not supported 410 if ( !transition ) { 411 elem.animate(to, options); 412 return; 413 } 414 415 // stop 416 if ( options.stop ) { 417 // clear the animation 418 elem.unbind( endEvent ); 419 clearStyle( elem ); 420 } 421 422 // see if there is a change 423 change = false; 424 $.each( to, function( key, val ) { 425 css = elem.css( key ); 426 if ( Utils.parseValue( css ) != Utils.parseValue( val ) ) { 427 change = true; 428 } 429 // also add computed styles for FF 430 elem.css( key, css ); 431 }); 432 if ( !change ) { 433 window.setTimeout( function() { 434 options.complete.call( elem[0] ); 435 }, options.duration ); 436 return; 437 } 438 439 // the css strings to be applied
440 strings = []; 441 442 // the easing bezier 443 easing = options.easing in easings ? easings[ options.easing ] : easings._default; 444 445 // the syntax 446 syntax = ' ' + options.duration + 'ms' + ' cubic-bezier(' + easing.join(',') + ')'; 447 448 // add a tiny timeout so that the browsers catches any css changes before animating 449 window.setTimeout( (function(elem, endEvent, to, syntax) { 450 return function() { 451 452 // attach the end event 453 elem.one(endEvent, (function( elem ) { 454 return function() { 455 456 // clear the animation 457 clearStyle(elem); 458 459 // run the complete method 460 options.complete.call(elem[0]); 461 }; 462 }( elem ))); 463 464 // do the webkit translate3d for better performance on iOS 465 if( Galleria.WEBKIT && Galleria.TOUCH ) { 466 467 revert = {}; 468 form = [0,0,0]; 469 470 $.each( ['left', 'top'], function(i, m) { 471 if ( m in to ) { 472 form[ i ] = ( Utils.parseValue( to[ m ] ) - Utils.parseValue(elem.css( m )) ) + 'px'; 473 revert[ m ] = to[ m ]; 474 delete to[ m ]; 475 } 476 }); 477 478 if ( form[0] || form[1]) { 479 480 elem.data('revert', revert); 481 482 strings.push('-webkit-transform' + syntax); 483 484 // 3d animate 485 setStyle( elem, 'translate3d(' + form.join(',') + ')', 'transform'); 486 } 487 } 488 489 // push the animation props 490 $.each(to, function( p, val ) { 491 strings.push(p + syntax); 492 }); 493 494 // set the animation styles 495 setStyle( elem, strings.join(',') ); 496 497 // animate 498 elem.css( to ); 499 500 }; 501 }(elem, endEvent, to, syntax)), 2); 502 }; 503 }()), 504 505 removeAlpha : function( elem ) { 506 if ( IE < 9 && elem ) { 507 508 var style = elem.style, 509 currentStyle = elem.currentStyle, 510 filter = currentStyle && currentStyle.filter || style.filter || ""; 511 512 if ( /alpha/.test( filter ) ) { 513 style.filter = filter.replace( /alpha\([^)]*\)/i, '' ); 514 } 515 } 516 }, 517 518 forceStyles : function( elem, styles ) { 519 elem = $(elem); 520 if ( elem.attr( 'style' ) ) { 521 elem.data( 'styles', elem.attr( 'style' ) ).removeAttr( 'style' ); 522 } 523 elem.css( styles ); 524 }, 525 526 revertStyles : function() { 527 $.each( Utils.array( arguments ), function( i, elem ) { 528 529 elem = $( elem ); 530 elem.removeAttr( 'style' ); 531 532 elem.attr('style',''); // "fixes" webkit bug 533 534 if ( elem.data( 'styles' ) ) { 535 elem.attr( 'style', elem.data('styles') ).data( 'styles', null ); 536 } 537 }); 538 }, 539 540 moveOut : function( elem ) { 541 Utils.forceStyles( elem, { 542 position: 'absolute', 543 left: -10000 544 }); 545 }, 546 547 moveIn : function() { 548 Utils.revertStyles.apply( Utils, Utils.array( arguments ) ); 549 }, 550 551 elem : function( elem ) { 552 if (elem instanceof $) { 553 return { 554 $: elem, 555 dom: elem[0] 556 }; 557 } else { 558 return { 559 $: $(elem), 560 dom: elem 561 }; 562 } 563 }, 564 565 hide : function( elem, speed, callback ) { 566 567 callback = callback || F; 568 569 var el = Utils.elem( elem ), 570 $elem = el.$; 571 572 elem = el.dom; 573 574 // save the value if not exist 575 if (! $elem.data('opacity') ) { 576 $elem.data('opacity', $elem.css('opacity') ); 577 } 578 579 // always hide 580 var style = { opacity: 0 }; 581 582 if (speed) { 583 584 var complete = IE < 9 && elem ? function() { 585 Utils.removeAlpha( elem ); 586 elem.style.visibility = 'hidden'; 587 callback.call( elem ); 588 } : callback; 589 590 Utils.animate( elem, style, { 591 duration: speed, 592 complete: complete, 593 stop: true 594 }); 595 } else { 596 if ( IE < 9 && elem ) { 597 Utils.removeAlpha( elem ); 598 elem.style.visibility = 'hidden'; 599 } else { 600 $elem.css( style ); 601 } 602 } 603 }, 604 605 show : function( elem, speed, callback ) { 606 607 callback = callback || F; 608 609 var el = Utils.elem( elem ), 610 $elem = el.$; 611 612 elem = el.dom; 613 614 // bring back saved opacity 615 var saved = parseFloat( $elem.data('opacity') ) || 1, 616 style = { opacity: saved }; 617 618 // animate or toggle 619 if (speed) { 620 621 if ( IE < 9 ) { 622 $elem.css('opacity', 0); 623 elem.style.visibility = 'visible'; 624 } 625 626 var complete = IE < 9 && elem ? function() { 627 if ( style.opacity == 1 ) { 628 Utils.removeAlpha( elem ); 629 } 630 callback.call( elem ); 631 } : callback; 632 633 Utils.animate( elem, style, { 634 duration: speed, 635 complete: complete, 636 stop: true 637 }); 638 } else { 639 if ( IE < 9 && style.opacity == 1 && elem ) { 640 Utils.removeAlpha( elem ); 641 elem.style.visibility = 'visible'; 642 } else { 643 $elem.css( style ); 644 } 645 } 646 }, 647 648 649 // enhanced click for mobile devices 650 // we bind a touchend and hijack any click event in the bubble 651 // then we execute the click directly and save it in a separate data object for later 652 optimizeTouch: (function() { 653 654 var node, 655 evs, 656 fakes, 657 travel, 658 evt = {}, 659 handler = function( e ) { 660 e.preventDefault(); 661 evt = $.extend({}, e, true); 662 }, 663 attach = function() { 664 this.evt = evt; 665 }, 666 fake = function() { 667 this.handler.call(node, this.evt); 668 }; 669 670 return function( elem ) { 671 672 $(elem).bind('touchend', function( e ) { 673 674 node = e.target; 675 travel = true; 676 677 while( node.parentNode && node != e.currentTarget && travel ) { 678 679 evs = $(node).data('events'); 680 fakes = $(node).data('fakes'); 681 682 if (evs && 'click' in evs) { 683 684 travel = false;
685 e.preventDefault(); 686 687 // fake the click and save the event object 688 $(node).click(handler).click(); 689 690 // remove the faked click 691 evs.click.pop(); 692 693 // attach the faked event 694 $.each( evs.click, attach); 695 696 // save the faked clicks in a new data object 697 $(node).data('fakes', evs.click); 698 699 // remove all clicks 700 delete evs.click; 701 702 } else if ( fakes ) { 703 704 travel = false; 705 e.preventDefault(); 706 707 // fake all clicks 708 $.each( fakes, fake ); 709 } 710 711 // bubble 712 node = node.parentNode; 713 } 714 }); 715 }; 716 }()), 717 718 wait : function(options) { 719 options = $.extend({ 720 until : FALSE, 721 success : F, 722 error : function() { Galleria.raise('Could not complete wait function.'); }, 723 timeout: 3000 724 }, options); 725 726 var start = Utils.timestamp(), 727 elapsed, 728 now, 729 fn = function() { 730 now = Utils.timestamp(); 731 elapsed = now - start; 732 if ( options.until( elapsed ) ) { 733 options.success(); 734 return false; 735 } 736 737 if (typeof options.timeout == 'number' && now >= start + options.timeout) { 738 options.error(); 739 return false; 740 } 741 window.setTimeout(fn, 10); 742 }; 743 744 window.setTimeout(fn, 10); 745 }, 746 747 toggleQuality : function( img, force ) { 748 749 if ( ( IE !== 7 && IE !== 8 ) || !img || img.nodeName.toUpperCase() != 'IMG' ) { 750 return; 751 } 752 753 if ( typeof force === 'undefined' ) { 754 force = img.style.msInterpolationMode === 'nearest-neighbor'; 755 } 756 757 img.style.msInterpolationMode = force ? 'bicubic' : 'nearest-neighbor'; 758 }, 759 760 insertStyleTag : function( styles ) { 761 var style = doc.createElement( 'style' ); 762 DOM().head.appendChild( style ); 763 764 if ( style.styleSheet ) { // IE 765 style.styleSheet.cssText = styles; 766 } else { 767 var cssText = doc.createTextNode( styles ); 768 style.appendChild( cssText ); 769 } 770 }, 771 772 // a loadscript method that works for local scripts 773 loadScript: function( url, callback ) { 774 775 var done = false, 776 script = $('<scr'+'ipt>').attr({ 777 src: url, 778 async: true 779 }).get(0); 780 781 // Attach handlers for all browsers 782 script.onload = script.onreadystatechange = function() { 783 if ( !done && (!this.readyState || 784 this.readyState === 'loaded' || this.readyState === 'complete') ) { 785 786 done = true; 787 788 // Handle memory leak in IE 789 script.onload = script.onreadystatechange = null; 790 791 if (typeof callback === 'function') { 792 callback.call( this, this ); 793 } 794 } 795 }; 796 797 DOM().head.appendChild( script ); 798 }, 799
vendor: 19,778 bytes, lines 800-1453
800 // parse anything into a number 801 parseValue: function( val ) { 802 if (typeof val === 'number') { 803 return val; 804 } else if (typeof val === 'string') { 805 var arr = val.match(/\-?\d|\./g); 806 return arr && arr.constructor === Array ? arr.join('')*1 : 0; 807 } else { 808 return 0; 809 } 810 }, 811 812 // timestamp abstraction 813 timestamp: function() { 814 return new Date().getTime(); 815 }, 816 817 loadCSS : function( href, id, callback ) { 818 819 var link, 820 length; 821 822 // look for manual css 823 $('link[rel=stylesheet]').each(function() { 824 if ( new RegExp( href ).test( this.href ) ) { 825 link = this; 826 return false; 827 } 828 }); 829 830 if ( typeof id === 'function' ) { 831 callback = id; 832 id = undef; 833 } 834 835 callback = callback || F; // dirty 836 837 // if already present, return 838 if ( link ) { 839 callback.call( link, link ); 840 return link; 841 } 842 843 // save the length of stylesheets to check against 844 length = doc.styleSheets.length; 845 846 // check for existing id 847 if( $( '#' + id ).length ) { 848 849 $( '#' + id ).attr( 'href', href ); 850 length--; 851 852 } else { 853 link = $( '<link>' ).attr({ 854 rel: 'stylesheet', 855 href: href, 856 id: id 857 }).get(0); 858 859 var styles = $('link[rel="stylesheet"], style'); 860 if ( styles.length ) { 861 styles.get(0).parentNode.insertBefore( link, styles[0] ); 862 } else { 863 DOM().head.appendChild( link ); 864 } 865 866 if ( IE ) { 867 868 // IE has a limit of 31 stylesheets in one document 869 if( length >= 31 ) { 870 Galleria.raise( 'You have reached the browser stylesheet limit (31)', true ); 871 return; 872 } 873 } 874 } 875 876 if ( typeof callback === 'function' ) { 877 878 // First check for dummy element (new in 1.2.8) 879 var $loader = $('<s>').attr( 'id', 'galleria-loader' ).hide().appendTo( DOM().body ); 880 881 Utils.wait({ 882 until: function() { 883 return $loader.height() == 1; 884 }, 885 success: function() { 886 $loader.remove(); 887 callback.call( link, link ); 888 }, 889 error: function() { 890 $loader.remove(); 891 892 // If failed, tell the dev to download the latest theme 893 Galleria.raise( 'Theme CSS could not load after 20 sec. Please download the latest theme at http://galleria.io/customer/', true ); 894 895 }, 896 timeout: 20000 897 }); 898 } 899 return link; 900 } 901 }; 902 }()), 903 904 // the transitions holder 905 _transitions = (function() { 906 907 var _slide = function(params, complete, fade, door) { 908 909 var easing = this.getOptions('easing'), 910 distance = this.getStageWidth(), 911 from = { left: distance * ( params.rewind ? -1 : 1 ) }, 912 to = { left: 0 }; 913 914 if ( fade ) { 915 from.opacity = 0; 916 to.opacity = 1; 917 } else { 918 from.opacity = 1; 919 } 920 921 $(params.next).css(from); 922 923 Utils.animate(params.next, to, { 924 duration: params.speed, 925 complete: (function( elems ) { 926 return function() { 927 complete(); 928 elems.css({ 929 left: 0 930 }); 931 }; 932 }( $( params.next ).add( params.prev ) )), 933 queue: false, 934 easing: easing 935 }); 936 937 if (door) { 938 params.rewind = !params.rewind; 939 } 940 941 if (params.prev) { 942 943 from = { left: 0 }; 944 to = { left: distance * ( params.rewind ? 1 : -1 ) }; 945 946 if ( fade ) { 947 from.opacity = 1; 948 to.opacity = 0; 949 } 950 951 $(params.prev).css(from); 952 Utils.animate(params.prev, to, { 953 duration: params.speed, 954 queue: false, 955 easing: easing, 956 complete: function() { 957 $(this).css('opacity', 0); 958 } 959 }); 960 } 961 }; 962 963 return { 964 965 active: false, 966 967 init: function( effect, params, complete ) { 968 if ( _transitions.effects.hasOwnProperty( effect ) ) { 969 _transitions.effects[ effect ].call( this, params, complete ); 970 } 971 }, 972 973 effects: { 974 975 fade: function(params, complete) { 976 $(params.next).css({ 977 opacity: 0, 978 left: 0 979 }).show(); 980 Utils.animate(params.next, { 981 opacity: 1 982 },{ 983 duration: params.speed, 984 complete: complete 985 }); 986 if (params.prev) { 987 $(params.prev).css('opacity',1).show(); 988 Utils.animate(params.prev, { 989 opacity: 0 990 },{ 991 duration: params.speed 992 }); 993 } 994 }, 995 996 flash: function(params, complete) { 997 $(params.next).css({ 998 opacity: 0, 999 left: 0 1000 }); 1001 if (params.prev) { 1002 Utils.animate( params.prev, { 1003 opacity: 0 1004 },{ 1005 duration: params.speed/2, 1006 complete: function() { 1007 Utils.animate( params.next, { 1008 opacity:1 1009 },{ 1010 duration: params.speed, 1011 complete: complete 1012 }); 1013 } 1014 }); 1015 } else { 1016 Utils.animate( params.next, { 1017 opacity: 1 1018 },{ 1019 duration: params.speed, 1020 complete: complete 1021 }); 1022 } 1023 }, 1024 1025 pulse: function(params, complete) { 1026 if (params.prev) { 1027 $(params.prev).hide(); 1028 } 1029 $(params.next).css({ 1030 opacity: 0, 1031 left: 0 1032 }).show(); 1033 Utils.animate(params.next, { 1034 opacity:1 1035 },{ 1036 duration: params.speed, 1037 complete: complete 1038 }); 1039 }, 1040 1041 slide: function(params, complete) { 1042 _slide.apply( this, Utils.array( arguments ) ); 1043 }, 1044 1045 fadeslide: function(params, complete) { 1046 _slide.apply( this, Utils.array( arguments ).concat( [true] ) ); 1047 }, 1048 1049 doorslide: function(params, complete) { 1050 _slide.apply( this, Utils.array( arguments ).concat( [false, true] ) ); 1051 } 1052 } 1053 }; 1054 }()); 1055 1056_nativeFullscreen.listen(); 1057 1058/** 1059 The main Galleria class 1060 1061 @class 1062 @constructor 1063 1064 @example var gallery = new Galleria(); 1065 1066 @author http://aino.se 1067 1068 @requires jQuery 1069 1070*/ 1071 1072Galleria = function() { 1073 1074 var self = this; 1075 1076 // internal options 1077 this._options = {}; 1078 1079 // flag for controlling play/pause 1080 this._playing = false; 1081 1082 // internal interval for slideshow 1083 this._playtime = 5000; 1084 1085 // internal variable for the currently active image 1086 this._active = null; 1087 1088 // the internal queue, arrayified 1089 this._queue = { length: 0 }; 1090 1091 // the internal data array 1092 this._data = []; 1093 1094 // the internal dom collection 1095 this._dom = {}; 1096 1097 // the internal thumbnails array 1098 this._thumbnails = []; 1099 1100 // the internal layers array 1101 this._layers = []; 1102 1103 // internal init flag 1104 this._initialized = false; 1105 1106 // internal firstrun flag 1107 this._firstrun = false; 1108 1109 // global stagewidth/height 1110 this._stageWidth = 0; 1111 this._stageHeight = 0; 1112 1113 // target holder 1114 this._target = undef; 1115 1116 // bind hashes 1117 this._binds = []; 1118 1119 // instance id 1120 this._id = parseInt(Math.random()*10000, 10); 1121 1122 // add some elements 1123 var divs = 'container stage images image-nav image-nav-left image-nav-right ' + 1124 'info info-text info-title info-description ' + 1125 'thumbnails thumbnails-list thumbnails-container thumb-nav-left thumb-nav-right ' + 1126 'loader counter tooltip', 1127 spans = 'current total'; 1128 1129 $.each( divs.split(' '), function( i, elemId ) { 1130 self._dom[ elemId ] = Utils.create( 'galleria-' + elemId ); 1131 }); 1132 1133 $.each( spans.split(' '), function( i, elemId ) { 1134 self._dom[ elemId ] = Utils.create( 'galleria-' + elemId, 'span' ); 1135 }); 1136 1137 // the internal keyboard object 1138 // keeps reference of the keybinds and provides helper methods for binding keys 1139 var keyboard = this._keyboard = { 1140 1141 keys : { 1142 'UP': 38, 1143 'DOWN': 40, 1144 'LEFT': 37, 1145 'RIGHT': 39, 1146 'RETURN': 13, 1147 'ESCAPE': 27, 1148 'BACKSPACE': 8, 1149 'SPACE': 32 1150 }, 1151 1152 map : {}, 1153 1154 bound: false, 1155 1156 press: function(e) { 1157 var key = e.keyCode || e.which; 1158 if ( key in keyboard.map && typeof keyboard.map[key] === 'function' ) { 1159 keyboard.map[key].call(self, e); 1160 } 1161 }, 1162 1163 attach: function(map) { 1164 1165 var key, up; 1166 1167 for( key in map ) { 1168 if ( map.hasOwnProperty( key ) ) { 1169 up = key.toUpperCase(); 1170 if ( up in keyboard.keys ) { 1171 keyboard.map[ keyboard.keys[up] ] = map[key]; 1172 } else { 1173 keyboard.map[ up ] = map[key]; 1174 } 1175 } 1176 } 1177 if ( !keyboard.bound ) { 1178 keyboard.bound = true; 1179 $doc.bind('keydown', keyboard.press); 1180 } 1181 }, 1182 1183 detach: function() { 1184 keyboard.bound = false; 1185 keyboard.map = {}; 1186 $doc.unbind('keydown', keyboard.press); 1187 } 1188 }; 1189 1190 // internal controls for keeping track of active / inactive images 1191 var controls = this._controls = { 1192 1193 0: undef, 1194 1195 1: undef, 1196 1197 active : 0, 1198 1199 swap : function() { 1200 controls.active = controls.active ? 0 : 1; 1201 }, 1202 1203 getActive : function() { 1204 return controls[ controls.active ]; 1205 }, 1206 1207 getNext : function() { 1208 return controls[ 1 - controls.active ]; 1209 } 1210 }; 1211 1212 // internal carousel object 1213 var carousel = this._carousel = { 1214 1215 // shortcuts 1216 next: self.$('thumb-nav-right'), 1217 prev: self.$('thumb-nav-left'), 1218 1219 // cache the width 1220 width: 0, 1221 1222 // track the current position 1223 current: 0, 1224 1225 // cache max value 1226 max: 0, 1227 1228 // save all hooks for each width in an array 1229 hooks: [], 1230 1231 // update the carousel 1232 // you can run this method anytime, f.ex on window.resize 1233 update: function() { 1234 var w = 0, 1235 h = 0, 1236 hooks = [0]; 1237 1238 $.each( self._thumbnails, function( i, thumb ) { 1239 if ( thumb.ready ) { 1240 w += thumb.outerWidth || $( thumb.container ).outerWidth( true ); 1241 hooks[ i+1 ] = w; 1242 h = Math.max( h, thumb.outerHeight || $( thumb.container).outerHeight( true ) ); 1243 } 1244 }); 1245 1246 self.$( 'thumbnails' ).css({ 1247 width: w, 1248 height: h 1249 }); 1250 1251 carousel.max = w; 1252 carousel.hooks = hooks; 1253 carousel.width = self.$( 'thumbnails-list' ).width(); 1254 carousel.setClasses(); 1255 1256 self.$( 'thumbnails-container' ).toggleClass( 'galleria-carousel', w > carousel.width ); 1257 1258 // one extra calculation 1259 carousel.width = self.$( 'thumbnails-list' ).width(); 1260 1261 // todo: fix so the carousel moves to the left 1262 }, 1263 1264 bindControls: function() { 1265 1266 var i; 1267 1268 carousel.next.bind( 'click', function(e) { 1269 e.preventDefault(); 1270 1271 if ( self._options.carouselSteps === 'auto' ) { 1272 1273 for ( i = carousel.current; i < carousel.hooks.length; i++ ) { 1274 if ( carousel.hooks[i] - carousel.hooks[ carousel.current ] > carousel.width ) { 1275 carousel.set(i - 2); 1276 break; 1277 } 1278 } 1279 1280 } else { 1281 carousel.set( carousel.current + self._options.carouselSteps); 1282 } 1283 }); 1284 1285 carousel.prev.bind( 'click', function(e) { 1286 e.preventDefault(); 1287 1288 if ( self._options.carouselSteps === 'auto' ) { 1289 1290 for ( i = carousel.current; i >= 0; i-- ) { 1291 if ( carousel.hooks[ carousel.current ] - carousel.hooks[i] > carousel.width ) { 1292 carousel.set( i + 2 ); 1293 break; 1294 } else if ( i === 0 ) { 1295 carousel.set( 0 ); 1296 break; 1297 } 1298 } 1299 } else { 1300 carousel.set( carousel.current - self._options.carouselSteps ); 1301 } 1302 }); 1303 }, 1304 1305 // calculate and set positions 1306 set: function( i ) { 1307 i = Math.max( i, 0 ); 1308 while ( carousel.hooks[i - 1] + carousel.width >= carousel.max && i >= 0 ) { 1309 i--; 1310 } 1311 carousel.current = i; 1312 carousel.animate(); 1313 }, 1314 1315 // get the last position 1316 getLast: function(i) { 1317 return ( i || carousel.current ) - 1; 1318 }, 1319 1320 // follow the active image 1321 follow: function(i) { 1322 1323 //don't follow if position fits 1324 if ( i === 0 || i === carousel.hooks.length - 2 ) { 1325 carousel.set( i ); 1326 return; 1327 } 1328 1329 // calculate last position 1330 var last = carousel.current; 1331 while( carousel.hooks[last] - carousel.hooks[ carousel.current ] < 1332 carousel.width && last <= carousel.hooks.length ) { 1333 last ++; 1334 } 1335 1336 // set position 1337 if ( i - 1 < carousel.current ) { 1338 carousel.set( i - 1 ); 1339 } else if ( i + 2 > last) { 1340 carousel.set( i - last + carousel.current + 2 ); 1341 } 1342 }, 1343 1344 // helper for setting disabled classes 1345 setClasses: function() { 1346 carousel.prev.toggleClass( 'disabled', !carousel.current ); 1347 carousel.next.toggleClass( 'disabled', carousel.hooks[ carousel.current ] + carousel.width >= carousel.max ); 1348 }, 1349 1350 // the animation method 1351 animate: function(to) { 1352 carousel.setClasses(); 1353 var num = carousel.hooks[ carousel.current ] * -1; 1354 1355 if ( isNaN( num ) ) { 1356 return; 1357 } 1358 1359 Utils.animate(self.get( 'thumbnails' ), { 1360 left: num 1361 },{ 1362 duration: self._options.carouselSpeed, 1363 easing: self._options.easing, 1364 queue: false 1365 }); 1366 } 1367 }; 1368 1369 // tooltip control 1370 // added in 1.2 1371 var tooltip = this._tooltip = { 1372 1373 initialized : false, 1374 1375 open: false, 1376 1377 timer: 'tooltip' + self._id, 1378 1379 swapTimer: 'swap' + self._id, 1380 1381 init: function() { 1382 1383 tooltip.initialized = true; 1384 1385 var css = '.galleria-tooltip{padding:3px 8px;max-width:50%;background:#ffe;color:#000;z-index:3;position:absolute;font-size:11px;line-height:1.3;' + 1386 'opacity:0;box-shadow:0 0 2px rgba(0,0,0,.4);-moz-box-shadow:0 0 2px rgba(0,0,0,.4);-webkit-box-shadow:0 0 2px rgba(0,0,0,.4);}'; 1387 1388 Utils.insertStyleTag(css); 1389 1390 self.$( 'tooltip' ).css({ 1391 opacity: 0.8, 1392 visibility: 'visible', 1393 display: 'none' 1394 }); 1395 1396 }, 1397 1398 // move handler 1399 move: function( e ) { 1400 var mouseX = self.getMousePosition(e).x, 1401 mouseY = self.getMousePosition(e).y, 1402 $elem = self.$( 'tooltip' ), 1403 x = mouseX, 1404 y = mouseY, 1405 height = $elem.outerHeight( true ) + 1, 1406 width = $elem.outerWidth( true ), 1407 limitY = height + 15; 1408 1409 var maxX = self.$( 'container').width() - width - 2, 1410 maxY = self.$( 'container').height() - height - 2; 1411 1412 if ( !isNaN(x) && !isNaN(y) ) { 1413 1414 x += 10; 1415 y -= 30; 1416 1417 x = Math.max( 0, Math.min( maxX, x ) ); 1418 y = Math.max( 0, Math.min( maxY, y ) ); 1419 1420 if( mouseY < limitY ) { 1421 y = limitY; 1422 } 1423 1424 $elem.css({ left: x, top: y }); 1425 } 1426 }, 1427 1428 // bind elements to the tooltip 1429 // you can bind multiple elementIDs using { elemID : function } or { elemID : string } 1430 // you can also bind single DOM elements using bind(elem, string) 1431 bind: function( elem, value ) { 1432 1433 // todo: revise if alternative tooltip is needed for mobile devices 1434 if (Galleria.TOUCH) { 1435 return; 1436 } 1437 1438 if (! tooltip.initialized ) { 1439 tooltip.init(); 1440 } 1441 1442 var mouseout = function() { 1443 self.$( 'container' ).unbind( 'mousemove', tooltip.move ); 1444 self.clearTimer( tooltip.timer ); 1445 1446 self.$( 'tooltip' ).stop().animate({ 1447 opacity: 0 1448 }, 200, function() { 1449 1450 self.$( 'tooltip' ).hide(); 1451 1452 self.addTimer( tooltip.swapTimer, function() { 1453 tooltip.open = false;
1454 }, 1000); 1455 }); 1456 }; 1457 1458 var hover = function( elem, value) { 1459 1460 tooltip.define( elem, value ); 1461 1462 $( elem ).hover(function() { 1463 1464 self.clearTimer( tooltip.swapTimer ); 1465 self.$('container').unbind( 'mousemove', tooltip.move ).bind( 'mousemove', tooltip.move ).trigger( 'mousemove' ); 1466 tooltip.show( elem ); 1467 1468 self.addTimer( tooltip.timer, function() { 1469 self.$( 'tooltip' ).stop().show().animate({ 1470 opacity: 1 1471 }); 1472 tooltip.open = true; 1473 1474 }, tooltip.open ? 0 : 500); 1475 1476 }, mouseout).click(mouseout); 1477 }; 1478 1479 if ( typeof value === 'string' ) { 1480 hover( ( elem in self._dom ? self.get( elem ) : elem ), value ); 1481 } else { 1482 // asume elemID here 1483 $.each( elem, function( elemID, val ) { 1484 hover( self.get(elemID), val ); 1485 }); 1486 } 1487 }, 1488 1489 show: function( elem ) { 1490 1491 elem = $( elem in self._dom ? self.get(elem) : elem ); 1492 1493 var text = elem.data( 'tt' ), 1494 mouseup = function( e ) { 1495 1496 // attach a tiny settimeout to make sure the new tooltip is filled 1497 window.setTimeout( (function( ev ) { 1498 return function() { 1499 tooltip.move( ev ); 1500 }; 1501 }( e )), 10); 1502 1503 elem.unbind( 'mouseup', mouseup ); 1504 1505 }; 1506 1507 text = typeof text === 'function' ? text() : text; 1508 1509 if ( ! text ) { 1510 return; 1511 } 1512 1513 self.$( 'tooltip' ).html( text.replace(/\s/, ' ') ); 1514 1515 // trigger mousemove on mouseup in case of click 1516 elem.bind( 'mouseup', mouseup ); 1517 }, 1518 1519 define: function( elem, value ) { 1520 1521 // we store functions, not strings 1522 if (typeof value !== 'function') { 1523 var s = value; 1524 value = function() { 1525 return s; 1526 }; 1527 } 1528 1529 elem = $( elem in self._dom ? self.get(elem) : elem ).data('tt', value); 1530 1531 tooltip.show( elem ); 1532 1533 } 1534 }; 1535 1536 // internal fullscreen control 1537 var fullscreen = this._fullscreen = { 1538 1539 scrolled: 0, 1540 1541 crop: undef, 1542 1543 transition: undef, 1544 1545 active: false, 1546 1547 keymap: self._keyboard.map, 1548 1549 parseCallback: function( callback, enter ) { 1550 1551 return _transitions.active ? function() { 1552 if ( typeof callback == 'function' ) { 1553 callback(); 1554 } 1555 var active = self._controls.getActive(), 1556 next = self._controls.getNext(); 1557 1558 self._scaleImage( next ); 1559 self._scaleImage( active ); 1560 1561 if ( enter && self._options.trueFullscreen ) { 1562 // Firefox bug, revise later 1563 $( active.container ).add( next.container ).trigger( 'transitionend' ); 1564 } 1565 1566 } : callback; 1567 1568 }, 1569 1570 enter: function( callback ) { 1571 1572 callback = fullscreen.parseCallback( callback, true ); 1573 1574 if ( self._options.trueFullscreen && _nativeFullscreen.support ) { 1575 _nativeFullscreen.enter( self, callback ); 1576 } else { 1577 fullscreen._enter( callback ); 1578 } 1579 }, 1580 1581 _enter: function( callback ) { 1582 1583 fullscreen.active = true; 1584 1585 // hide the image until rescale is complete 1586 Utils.hide( self.getActiveImage() ); 1587 1588 self.$( 'container' ).addClass( 'fullscreen' ); 1589 1590 fullscreen.scrolled = $win.scrollTop(); 1591 1592 // begin styleforce 1593 Utils.forceStyles(self.get('container'), { 1594 position: 'fixed', 1595 top: 0, 1596 left: 0, 1597 width: '100%', 1598 height: '100%', 1599 zIndex: 10000 1600 }); 1601 1602 var htmlbody = { 1603 height: '100%', 1604 overflow: 'hidden', 1605 margin:0, 1606 padding:0 1607 }, 1608 1609 data = self.getData(), 1610 1611 options = self._options; 1612 1613 Utils.forceStyles( DOM().html, htmlbody ); 1614 Utils.forceStyles( DOM().body, htmlbody ); 1615 1616 // temporarily attach some keys 1617 // save the old ones first in a cloned object 1618 fullscreen.keymap = $.extend({}, self._keyboard.map); 1619 1620 self.attachKeyboard({ 1621 escape: self.exitFullscreen, 1622 right: self.next, 1623 left: self.prev 1624 }); 1625 1626 // temporarily save the crop 1627 fullscreen.crop = options.imageCrop; 1628 1629 // set fullscreen options 1630 if ( options.fullscreenCrop != undef ) { 1631 options.imageCrop = options.fullscreenCrop; 1632 } 1633 1634 // swap to big image if it's different from the display image 1635 if ( data && data.big && data.image !== data.big ) { 1636 var big = new Galleria.Picture(), 1637 cached = big.isCached( data.big ), 1638 index = self.getIndex(), 1639 thumb = self._thumbnails[ index ]; 1640 1641 self.trigger( { 1642 type: Galleria.LOADSTART, 1643 cached: cached, 1644 rewind: false, 1645 index: index, 1646 imageTarget: self.getActiveImage(), 1647 thumbTarget: thumb, 1648 galleriaData: data 1649 }); 1650 1651 big.load( data.big, function( big ) { 1652 self._scaleImage( big, { 1653 complete: function( big ) { 1654 self.trigger({ 1655 type: Galleria.LOADFINISH, 1656 cached: cached, 1657 index: index, 1658 rewind: false, 1659 imageTarget: big.image, 1660 thumbTarget: thumb 1661 }); 1662 var image = self._controls.getActive().image; 1663 if ( image ) { 1664 $( image ).width( big.image.width ).height( big.image.height ) 1665 .attr( 'style', $( big.image ).attr('style') ) 1666 .attr( 'src', big.image.src ); 1667 } 1668 } 1669 }); 1670 }); 1671 } 1672 1673 // init the first rescale and attach callbacks 1674 self.rescale(function() { 1675 1676 self.addTimer(false, function() { 1677 // show the image after 50 ms 1678 Utils.show( self.getActiveImage() ); 1679 1680 if (typeof callback === 'function') { 1681 callback.call( self ); 1682 } 1683 1684 }, 100); 1685 1686 self.trigger( Galleria.FULLSCREEN_ENTER ); 1687 }); 1688 1689 // bind the scaling to the resize event 1690 $win.resize( function() { 1691 fullscreen.scale(); 1692 } ); 1693 }, 1694 1695 scale : function() { 1696 self.rescale(); 1697 }, 1698 1699 exit: function( callback ) { 1700 1701 callback = fullscreen.parseCallback( callback ); 1702 1703 if ( self._options.trueFullscreen && _nativeFullscreen.support ) { 1704 _nativeFullscreen.exit( callback ); 1705 } else { 1706 fullscreen._exit( callback ); 1707 } 1708 }, 1709 1710 _exit: function( callback ) { 1711 1712 fullscreen.active = false;
vendor: 13,641 bytes, lines 1713-2121
1713 1714 Utils.hide( self.getActiveImage() ); 1715 1716 self.$('container').removeClass( 'fullscreen' ); 1717 1718 // revert all styles 1719 Utils.revertStyles( self.get('container'), DOM().html, DOM().body ); 1720 1721 // scroll back 1722 window.scrollTo(0, fullscreen.scrolled); 1723 1724 // detach all keyboard events and apply the old keymap 1725 self.detachKeyboard(); 1726 self.attachKeyboard( fullscreen.keymap ); 1727 1728 // bring back cached options 1729 self._options.imageCrop = fullscreen.crop; 1730 //self._options.transition = fullscreen.transition; 1731 1732 // return to original image 1733 var big = self.getData().big, 1734 image = self._controls.getActive().image; 1735 1736 if ( !self.getData().iframe && image && big && big == image.src ) { 1737 1738 window.setTimeout(function(src) { 1739 return function() { 1740 image.src = src; 1741 }; 1742 }( self.getData().image ), 1 ); 1743 1744 } 1745 1746 self.rescale(function() { 1747 self.addTimer(false, function() { 1748 1749 // show the image after 50 ms 1750 Utils.show( self.getActiveImage() ); 1751 1752 if ( typeof callback === 'function' ) { 1753 callback.call( self ); 1754 } 1755 1756 $win.trigger( 'resize' ); 1757 1758 }, 50); 1759 self.trigger( Galleria.FULLSCREEN_EXIT ); 1760 }); 1761 1762 1763 $win.unbind('resize', fullscreen.scale); 1764 } 1765 }; 1766 1767 // the internal idle object for controlling idle states 1768 var idle = this._idle = { 1769 1770 trunk: [], 1771 1772 bound: false, 1773 1774 active: false, 1775 1776 add: function(elem, to, from, hide) { 1777 if (!elem) { 1778 return; 1779 } 1780 if (!idle.bound) { 1781 idle.addEvent(); 1782 } 1783 elem = $(elem); 1784 1785 if ( typeof from == 'boolean' ) { 1786 hide = from; 1787 from = {}; 1788 } 1789 1790 from = from || {}; 1791 1792 var extract = {}, 1793 style; 1794 1795 for ( style in to ) { 1796 if ( to.hasOwnProperty( style ) ) { 1797 extract[ style ] = elem.css( style ); 1798 } 1799 } 1800 1801 elem.data('idle', { 1802 from: $.extend( extract, from ), 1803 to: to, 1804 complete: true, 1805 busy: false 1806 }); 1807 1808 if ( !hide ) { 1809 idle.addTimer(); 1810 } else { 1811 elem.css( to ); 1812 } 1813 idle.trunk.push(elem); 1814 }, 1815 1816 remove: function(elem) { 1817 1818 elem = $(elem); 1819 1820 $.each(idle.trunk, function(i, el) { 1821 if ( el && el.length && !el.not(elem).length ) { 1822 elem.css( elem.data( 'idle' ).from ); 1823 idle.trunk.splice(i, 1); 1824 } 1825 }); 1826 1827 if (!idle.trunk.length) { 1828 idle.removeEvent(); 1829 self.clearTimer( idle.timer ); 1830 } 1831 }, 1832 1833 addEvent : function() { 1834 idle.bound = true; 1835 self.$('container').bind( 'mousemove click', idle.showAll ); 1836 if ( self._options.idleMode == 'hover' ) { 1837 self.$('container').bind( 'mouseleave', idle.hide ); 1838 } 1839 }, 1840 1841 removeEvent : function() { 1842 idle.bound = false; 1843 self.$('container').bind( 'mousemove click', idle.showAll ); 1844 if ( self._options.idleMode == 'hover' ) { 1845 self.$('container').unbind( 'mouseleave', idle.hide ); 1846 } 1847 }, 1848 1849 addTimer : function() { 1850 if( self._options.idleMode == 'hover' ) { 1851 return; 1852 } 1853 self.addTimer( 'idle', function() { 1854 idle.hide(); 1855 }, self._options.idleTime ); 1856 }, 1857 1858 hide : function() { 1859 1860 if ( !self._options.idleMode || self.getIndex() === false || self.getData().iframe ) { 1861 return; 1862 } 1863 1864 self.trigger( Galleria.IDLE_ENTER ); 1865 1866 var len = idle.trunk.length; 1867 1868 $.each( idle.trunk, function(i, elem) { 1869 1870 var data = elem.data('idle'); 1871 1872 if (! data) { 1873 return; 1874 } 1875 1876 elem.data('idle').complete = false; 1877 1878 Utils.animate( elem, data.to, { 1879 duration: self._options.idleSpeed, 1880 complete: function() { 1881 if ( i == len-1 ) { 1882 idle.active = false; 1883 } 1884 } 1885 }); 1886 }); 1887 }, 1888 1889 showAll : function() { 1890 1891 self.clearTimer( 'idle' ); 1892 1893 $.each( idle.trunk, function( i, elem ) { 1894 idle.show( elem ); 1895 }); 1896 }, 1897 1898 show: function(elem) { 1899 1900 var data = elem.data('idle'); 1901 1902 if ( !idle.active || ( !data.busy && !data.complete ) ) { 1903 1904 data.busy = true; 1905 1906 self.trigger( Galleria.IDLE_EXIT ); 1907 1908 self.clearTimer( 'idle' ); 1909 1910 Utils.animate( elem, data.from, { 1911 duration: self._options.idleSpeed/2, 1912 complete: function() { 1913 idle.active = true; 1914 $(elem).data('idle').busy = false; 1915 $(elem).data('idle').complete = true; 1916 } 1917 }); 1918 1919 } 1920 idle.addTimer(); 1921 } 1922 }; 1923 1924 // internal lightbox object 1925 // creates a predesigned lightbox for simple popups of images in galleria 1926 var lightbox = this._lightbox = { 1927 1928 width : 0, 1929 1930 height : 0, 1931 1932 initialized : false, 1933 1934 active : null, 1935 1936 image : null, 1937 1938 elems : {}, 1939 1940 keymap: false, 1941 1942 init : function() { 1943 1944 // trigger the event 1945 self.trigger( Galleria.LIGHTBOX_OPEN ); 1946 1947 if ( lightbox.initialized ) { 1948 return; 1949 } 1950 lightbox.initialized = true; 1951 1952 // create some elements to work with 1953 var elems = 'overlay box content shadow title info close prevholder prev nextholder next counter image', 1954 el = {}, 1955 op = self._options, 1956 css = '', 1957 abs = 'position:absolute;', 1958 prefix = 'lightbox-', 1959 cssMap = { 1960 overlay: 'position:fixed;display:none;opacity:'+op.overlayOpacity+';filter:alpha(opacity='+(op.overlayOpacity*100)+ 1961 ');top:0;left:0;width:100%;height:100%;background:'+op.overlayBackground+';z-index:99990', 1962 box: 'position:fixed;display:none;width:400px;height:400px;top:50%;left:50%;margin-top:-200px;margin-left:-200px;z-index:99991', 1963 shadow: abs+'background:#000;width:100%;height:100%;', 1964 content: abs+'background-color:#fff;top:10px;left:10px;right:10px;bottom:10px;overflow:hidden', 1965 info: abs+'bottom:10px;left:10px;right:10px;color:#444;font:11px/13px arial,sans-serif;height:13px', 1966 close: abs+'top:10px;right:10px;height:20px;width:20px;background:#fff;text-align:center;cursor:pointer;color:#444;font:16px/22px arial,sans-serif;z-index:99999', 1967 image: abs+'top:10px;left:10px;right:10px;bottom:30px;overflow:hidden;display:block;', 1968 prevholder: abs+'width:50%;top:0;bottom:40px;cursor:pointer;', 1969 nextholder: abs+'width:50%;top:0;bottom:40px;right:-1px;cursor:pointer;', 1970 prev: abs+'top:50%;margin-top:-20px;height:40px;width:30px;background:#fff;left:20px;display:none;text-align:center;color:#000;font:bold 16px/36px arial,sans-serif', 1971 next: abs+'top:50%;margin-top:-20px;height:40px;width:30px;background:#fff;right:20px;left:auto;display:none;font:bold 16px/36px arial,sans-serif;text-align:center;color:#000', 1972 title: 'float:left', 1973 counter: 'float:right;margin-left:8px;' 1974 }, 1975 hover = function(elem) { 1976 return elem.hover( 1977 function() { $(this).css( 'color', '#bbb' ); }, 1978 function() { $(this).css( 'color', '#444' ); } 1979 ); 1980 }, 1981 appends = {}; 1982 1983 // IE8 fix for IE's transparent background event "feature" 1984 if ( IE && IE > 7 ) { 1985 cssMap.nextholder += 'background:#000;filter:alpha(opacity=0);'; 1986 cssMap.prevholder += 'background:#000;filter:alpha(opacity=0);'; 1987 } 1988 1989 // create and insert CSS 1990 $.each(cssMap, function( key, value ) { 1991 css += '.galleria-'+prefix+key+'{'+value+'}'; 1992 }); 1993 1994 css += '.galleria-'+prefix+'box.iframe .galleria-'+prefix+'prevholder,'+ 1995 '.galleria-'+prefix+'box.iframe .galleria-'+prefix+'nextholder{'+ 1996 'width:100px;height:100px;top:50%;margin-top:-70px}'; 1997 1998 Utils.insertStyleTag( css ); 1999 2000 // create the elements 2001 $.each(elems.split(' '), function( i, elemId ) { 2002 self.addElement( 'lightbox-' + elemId ); 2003 el[ elemId ] = lightbox.elems[ elemId ] = self.get( 'lightbox-' + elemId ); 2004 }); 2005 2006 // initiate the image 2007 lightbox.image = new Galleria.Picture(); 2008 2009 // append the elements 2010 $.each({ 2011 box: 'shadow content close prevholder nextholder', 2012 info: 'title counter', 2013 content: 'info image', 2014 prevholder: 'prev', 2015 nextholder: 'next' 2016 }, function( key, val ) { 2017 var arr = []; 2018 $.each( val.split(' '), function( i, prop ) { 2019 arr.push( prefix + prop ); 2020 }); 2021 appends[ prefix+key ] = arr; 2022 }); 2023 2024 self.append( appends ); 2025 2026 $( el.image ).append( lightbox.image.container ); 2027 2028 $( DOM().body ).append( el.overlay, el.box ); 2029 2030 Utils.optimizeTouch( el.box ); 2031 2032 // add the prev/next nav and bind some controls 2033 2034 hover( $( el.close ).bind( 'click', lightbox.hide ).html('×') ); 2035 2036 $.each( ['Prev','Next'], function(i, dir) { 2037 2038 var $d = $( el[ dir.toLowerCase() ] ).html( /v/.test( dir ) ? '‹ ' : ' ›' ), 2039 $e = $( el[ dir.toLowerCase()+'holder'] ); 2040 2041 $e.bind( 'click', function() { 2042 lightbox[ 'show' + dir ](); 2043 }); 2044 2045 // IE7 and touch devices will simply show the nav 2046 if ( IE < 8 || Galleria.TOUCH ) { 2047 $d.show(); 2048 return; 2049 } 2050 2051 $e.hover( function() { 2052 $d.show(); 2053 }, function(e) { 2054 $d.stop().fadeOut( 200 ); 2055 }); 2056 2057 }); 2058 $( el.overlay ).bind( 'click', lightbox.hide ); 2059 2060 // the lightbox animation is slow on ipad 2061 if ( Galleria.IPAD ) { 2062 self._options.lightboxTransitionSpeed = 0; 2063 } 2064 2065 }, 2066 2067 rescale: function(event) { 2068 2069 // calculate 2070 var width = Math.min( $win.width()-40, lightbox.width ), 2071 height = Math.min( $win.height()-60, lightbox.height ), 2072 ratio = Math.min( width / lightbox.width, height / lightbox.height ), 2073 destWidth = Math.round( lightbox.width * ratio ) + 40, 2074 destHeight = Math.round( lightbox.height * ratio ) + 60, 2075 to = { 2076 width: destWidth, 2077 height: destHeight, 2078 'margin-top': Math.ceil( destHeight / 2 ) *- 1, 2079 'margin-left': Math.ceil( destWidth / 2 ) *- 1 2080 }; 2081 2082 // if rescale event, don't animate 2083 if ( event ) { 2084 $( lightbox.elems.box ).css( to ); 2085 } else { 2086 $( lightbox.elems.box ).animate( to, { 2087 duration: self._options.lightboxTransitionSpeed, 2088 easing: self._options.easing, 2089 complete: function() { 2090 var image = lightbox.image, 2091 speed = self._options.lightboxFadeSpeed; 2092 2093 self.trigger({ 2094 type: Galleria.LIGHTBOX_IMAGE, 2095 imageTarget: image.image 2096 }); 2097 2098 $( image.container ).show(); 2099 2100 $( image.image ).animate({ opacity: 1 }, speed); 2101 Utils.show( lightbox.elems.info, speed ); 2102 } 2103 }); 2104 } 2105 }, 2106 2107 hide: function() { 2108 2109 // remove the image 2110 lightbox.image.image = null; 2111 2112 $win.unbind('resize', lightbox.rescale); 2113 2114 $( lightbox.elems.box ).hide(); 2115 2116 Utils.hide( lightbox.elems.info ); 2117 2118 self.detachKeyboard(); 2119 self.attachKeyboard( lightbox.keymap ); 2120 2121 lightbox.keymap = false;
2122 2123 Utils.hide( lightbox.elems.overlay, 200, function() { 2124 $( this ).hide().css( 'opacity', self._options.overlayOpacity ); 2125 self.trigger( Galleria.LIGHTBOX_CLOSE ); 2126 }); 2127 }, 2128 2129 showNext: function() { 2130 lightbox.show( self.getNext( lightbox.active ) ); 2131 }, 2132 2133 showPrev: function() { 2134 lightbox.show( self.getPrev( lightbox.active ) ); 2135 }, 2136 2137 show: function(index) { 2138 2139 lightbox.active = index = typeof index === 'number' ? index : self.getIndex() || 0; 2140 2141 if ( !lightbox.initialized ) { 2142 lightbox.init(); 2143 } 2144 2145 // temporarily attach some keys 2146 // save the old ones first in a cloned object 2147 if ( !lightbox.keymap ) { 2148 2149 lightbox.keymap = $.extend({}, self._keyboard.map); 2150 2151 self.attachKeyboard({ 2152 escape: lightbox.hide, 2153 right: lightbox.showNext, 2154 left: lightbox.showPrev 2155 }); 2156 } 2157 2158 $win.unbind('resize', lightbox.rescale ); 2159 2160 var data = self.getData(index), 2161 total = self.getDataLength(), 2162 n = self.getNext( index ), 2163 ndata, p, i; 2164 2165 Utils.hide( lightbox.elems.info ); 2166 2167 try { 2168 for ( i = self._options.preload; i > 0; i-- ) { 2169 p = new Galleria.Picture(); 2170 ndata = self.getData( n ); 2171 p.preload( 'big' in ndata ? ndata.big : ndata.image ); 2172 n = self.getNext( n ); 2173 } 2174 } catch(e) {} 2175 2176 lightbox.image.isIframe = !!data.iframe; 2177 2178 $(lightbox.elems.box).toggleClass( 'iframe', !!data.iframe ); 2179 2180 lightbox.image.load( data.iframe || data.big || data.image, function( image ) { 2181 2182 lightbox.width = image.isIframe ? $(window).width() : image.original.width; 2183 lightbox.height = image.isIframe ? $(window).height() : image.original.height; 2184 2185 $( image.image ).css({ 2186 width: image.isIframe ? '100%' : '100.1%', 2187 height: image.isIframe ? '100%' : '100.1%', 2188 top: 0, 2189 zIndex: 99998, 2190 opacity: 0, 2191 visibility: 'visible' 2192 }); 2193 2194 lightbox.elems.title.innerHTML = data.title || ''; 2195 lightbox.elems.counter.innerHTML = (index + 1) + ' / ' + total; 2196 $win.resize( lightbox.rescale ); 2197 lightbox.rescale(); 2198 }); 2199 2200 $( lightbox.elems.overlay ).show().css( 'visibility', 'visible' ); 2201 $( lightbox.elems.box ).show(); 2202 } 2203 }; 2204 2205 // the internal timeouts object 2206 // provides helper methods for controlling timeouts 2207 2208 var _timer = this._timer = { 2209 2210 trunk: {}, 2211 2212 add: function( id, fn, delay, loop ) { 2213 id = id || new Date().getTime(); 2214 loop = loop || false; 2215 this.clear( id ); 2216 if ( loop ) { 2217 var old = fn; 2218 fn = function() { 2219 old(); 2220 _timer.add( id, fn, delay ); 2221 }; 2222 } 2223 this.trunk[ id ] = window.setTimeout( fn, delay ); 2224 }, 2225 2226 clear: function( id ) { 2227 2228 var del = function( i ) { 2229 window.clearTimeout( this.trunk[ i ] ); 2230 delete this.trunk[ i ]; 2231 }, i; 2232 2233 if ( !!id && id in this.trunk ) { 2234 del.call( this, id ); 2235 2236 } else if ( typeof id === 'undefined' ) { 2237 for ( i in this.trunk ) { 2238 if ( this.trunk.hasOwnProperty( i ) ) { 2239 del.call( this, i ); 2240 } 2241 } 2242 } 2243 } 2244 }; 2245 2246 return this; 2247}; 2248 2249// end Galleria constructor 2250 2251Galleria.prototype = { 2252 2253 // bring back the constructor reference 2254 2255 constructor: Galleria, 2256 2257 /** 2258 Use this function to initialize the gallery and start loading. 2259 Should only be called once per instance. 2260 2261 @param {HTMLElement} target The target element 2262 @param {Object} options The gallery options 2263 2264 @returns Instance 2265 */ 2266 2267 init: function( target, options ) { 2268 2269 var self = this; 2270 2271 options = _legacyOptions( options ); 2272 2273 // save the original ingredients 2274 this._original = { 2275 target: target, 2276 options: options, 2277 data: null 2278 }; 2279 2280 // save the target here
2281 this._target = this._dom.target = target.nodeName ? target : $( target ).get(0); 2282 2283 // save the original content for destruction 2284 this._original.html = this._target.innerHTML; 2285 2286 // push the instance 2287 _instances.push( this ); 2288 2289 // raise error if no target is detected 2290 if ( !this._target ) { 2291 Galleria.raise('Target not found', true); 2292 return; 2293 } 2294 2295 // apply options 2296 this._options = { 2297 autoplay: false, 2298 carousel: true, 2299 carouselFollow: true, // legacy, deprecate at 1.3 2300 carouselSpeed: 400, 2301 carouselSteps: 'auto', 2302 clicknext: false, 2303 dailymotion: { 2304 foreground: '%23EEEEEE', 2305 highlight: '%235BCEC5', 2306 background: '%23222222', 2307 logo: 0, 2308 hideInfos: 1 2309 }, 2310 dataConfig : function( elem ) { return {}; }, 2311 dataSelector: 'img', 2312 dataSort: false, 2313 dataSource: this._target, 2314 debug: undef, 2315 dummy: undef, // 1.2.5 2316 easing: 'galleria', 2317 extend: function(options) {}, 2318 fullscreenCrop: undef, // 1.2.5 2319 fullscreenDoubleTap: true, // 1.2.4 toggles fullscreen on double-tap for touch devices 2320 fullscreenTransition: undef, // 1.2.6 2321 height: 0, 2322 idleMode: true, // 1.2.4 toggles idleMode 2323 idleTime: 3000, 2324 idleSpeed: 200, 2325 imageCrop: false, 2326 imageMargin: 0, 2327 imagePan: false, 2328 imagePanSmoothness: 12, 2329 imagePosition: '50%', 2330 imageTimeout: undef, // 1.2.5 2331 initialTransition: undef, // 1.2.4, replaces transitionInitial 2332 keepSource: false, 2333 layerFollow: true, // 1.2.5 2334 lightbox: false, // 1.2.3 2335 lightboxFadeSpeed: 200, 2336 lightboxTransitionSpeed: 200, 2337 linkSourceImages: true, 2338 maxScaleRatio: undef, 2339 minScaleRatio: undef, 2340 overlayOpacity: 0.85, 2341 overlayBackground: '#0b0b0b', 2342 pauseOnInteraction: true, 2343 popupLinks: false, 2344 preload: 2, 2345 queue: true, 2346 responsive: true, 2347 show: 0, 2348 showInfo: true, 2349 showCounter: true, 2350 showImagenav: true, 2351 swipe: true, // 1.2.4 2352 thumbCrop: true, 2353 thumbEventType: 'click', 2354 thumbFit: true, // legacy, deprecate at 1.3 2355 thumbMargin: 0, 2356 thumbQuality: 'auto', 2357 thumbDisplayOrder: true, // 1.2.8 2358 thumbnails: true, 2359 touchTransition: undef, // 1.2.6 2360 transition: 'fade', 2361 transitionInitial: undef, // legacy, deprecate in 1.3. Use initialTransition instead. 2362 transitionSpeed: 400, 2363 trueFullscreen: true, // 1.2.7 2364 useCanvas: false, // 1.2.4 2365 vimeo: { 2366 title: 0, 2367 byline: 0, 2368 portrait: 0, 2369 color: 'aaaaaa' 2370 }, 2371 wait: 5000, // 1.2.7 2372 width: 'auto', 2373 youtube: { 2374 modestbranding: 1, 2375 autohide: 1, 2376 color: 'white', 2377 hd: 1, 2378 rel: 0, 2379 showinfo: 0 2380 } 2381 }; 2382 2383 // legacy support for transitionInitial 2384 this._options.initialTransition = this._options.initialTransition || this._options.transitionInitial; 2385 2386 // turn off debug 2387 if ( options && options.debug === false ) { 2388 DEBUG = false; 2389 } 2390 2391 // set timeout 2392 if ( options && typeof options.imageTimeout === 'number' ) { 2393 TIMEOUT = options.imageTimeout; 2394 } 2395 2396 // set dummy 2397 if ( options && typeof options.dummy === 'string' ) { 2398 DUMMY = options.dummy; 2399 } 2400 2401 // hide all content 2402 $( this._target ).children().hide(); 2403 2404 // now we just have to wait for the theme... 2405 if ( typeof Galleria.theme === 'object' ) { 2406 this._init(); 2407 } else { 2408 // push the instance into the pool and run it when the theme is ready 2409 _pool.push( this ); 2410 } 2411 2412 return this; 2413 }, 2414 2415 // this method should only be called once per instance 2416 // for manipulation of data, use the .load method 2417 2418 _init: function() { 2419 2420 var self = this, 2421 options = this._options; 2422 2423 if ( this._initialized ) { 2424 Galleria.raise( 'Init failed: Gallery instance already initialized.' ); 2425 return this; 2426 } 2427 2428 this._initialized = true; 2429 2430 if ( !Galleria.theme ) { 2431 Galleria.raise( 'Init failed: No theme found.', true ); 2432 return this; 2433 } 2434 2435 // merge the theme & caller options 2436 $.extend( true, options, Galleria.theme.defaults, this._original.options, Galleria.configure.options ); 2437 2438 // check for canvas support 2439 (function( can ) { 2440 2441 if ( !( 'getContext' in can ) ) { 2442 can = null; 2443 return; 2444 } 2445 2446 _canvas = _canvas || { 2447 elem: can, 2448 context: can.getContext( '2d' ), 2449 cache: {}, 2450 length: 0 2451 }; 2452 2453 }
vendor: 4,163 bytes, lines 2453-2565
2453( doc.createElement( 'canvas' ) ) ); 2454 2455 // bind the gallery to run when data is ready 2456 this.bind( Galleria.DATA, function() { 2457 2458 // Warn for quirks mode 2459 if ( Galleria.QUIRK ) { 2460 Galleria.raise('Your page is in Quirks mode, Galleria may not render correctly. Please validate your HTML.'); 2461 } 2462 2463 // save the new data 2464 this._original.data = this._data; 2465 2466 // lets show the counter here 2467 this.get('total').innerHTML = this.getDataLength(); 2468 2469 // cache the container 2470 var $container = this.$( 'container' ); 2471 2472 // set ratio if height is < 2 2473 if ( self._options.height < 2 ) { 2474 self._ratio = self._options.height; 2475 } 2476 2477 // the gallery is ready, let's just wait for the css 2478 var num = { width: 0, height: 0 }; 2479 var testHeight = function() { 2480 return self.$( 'stage' ).height(); 2481 }; 2482 2483 // check container and thumbnail height 2484 Utils.wait({ 2485 until: function() { 2486 2487 // keep trying to get the value 2488 num = self._getWH(); 2489 $container.width( num.width ).height( num.height ); 2490 return testHeight() && num.width && num.height > 50; 2491 2492 }, 2493 success: function() { 2494 2495 self._width = num.width; 2496 self._height = num.height; 2497 self._ratio = self._ratio || num.height/num.width; 2498 2499 // for some strange reason, webkit needs a single setTimeout to play ball 2500 if ( Galleria.WEBKIT ) { 2501 window.setTimeout( function() { 2502 self._run(); 2503 }, 1); 2504 } else { 2505 self._run(); 2506 } 2507 }, 2508 error: function() { 2509 2510 // Height was probably not set, raise hard errors 2511 2512 if ( testHeight() ) { 2513 Galleria.raise('Could not extract sufficient width/height of the gallery container. Traced measures: width:' + num.width + 'px, height: ' + num.height + 'px.', true); 2514 } else { 2515 Galleria.raise('Could not extract a stage height from the CSS. Traced height: ' + testHeight() + 'px.', true); 2516 } 2517 }, 2518 timeout: typeof this._options.wait == 'number' ? this._options.wait : false 2519 }); 2520 }); 2521 2522 // build the gallery frame 2523 this.append({ 2524 'info-text' : 2525 ['info-title', 'info-description'], 2526 'info' : 2527 ['info-text'], 2528 'image-nav' : 2529 ['image-nav-right', 'image-nav-left'], 2530 'stage' : 2531 ['images', 'loader', 'counter', 'image-nav'], 2532 'thumbnails-list' : 2533 ['thumbnails'], 2534 'thumbnails-container' : 2535 ['thumb-nav-left', 'thumbnails-list', 'thumb-nav-right'], 2536 'container' : 2537 ['stage', 'thumbnails-container', 'info', 'tooltip'] 2538 }); 2539 2540 Utils.hide( this.$( 'counter' ).append( 2541 this.get( 'current' ), 2542 doc.createTextNode(' / '), 2543 this.get( 'total' ) 2544 ) ); 2545 2546 this.setCounter('–'); 2547 2548 Utils.hide( self.get('tooltip') ); 2549 2550 // add a notouch class on the container to prevent unwanted :hovers on touch devices 2551 this.$( 'container' ).addClass( Galleria.TOUCH ? 'touch' : 'notouch' ); 2552 2553 // add images to the controls 2554 $.each( new Array(2), function( i ) { 2555 2556 // create a new Picture instance 2557 var image = new Galleria.Picture(); 2558 2559 // apply some styles, create & prepend overlay 2560 $( image.container ).css({ 2561 position: 'absolute', 2562 top: 0, 2563 left: 0 2564 }).prepend( self._layers[i] = $( Utils.create('galleria-layer') ).css({ 2565 position: 'absolute',
2566 top:0, left:0, right:0, bottom:0, 2567 zIndex:2 2568 })[0] ); 2569 2570 // append the image 2571 self.$( 'images' ).append( image.container ); 2572 2573 // reload the controls 2574 self._controls[i] = image; 2575 2576 }); 2577 2578 // some forced generic styling 2579 this.$( 'images' ).css({ 2580 position: 'relative', 2581 top: 0, 2582 left: 0, 2583 width: '100%', 2584 height: '100%' 2585 }); 2586 2587 this.$( 'thumbnails, thumbnails-list' ).css({ 2588 overflow: 'hidden', 2589 position: 'relative' 2590 }); 2591 //modified by JoomlaShine Team - BEGINNING - Align all images to center 2592 this.$( 'thumbnails' ).css({ 2593 margin : 'auto' 2594 }); 2595 //modified by JoomlaShine Team - END 2596 // bind image navigation arrows 2597 this.$( 'image-nav-right, image-nav-left' ).bind( 'click', function(e) { 2598 2599 // tune the clicknext option 2600 if ( options.clicknext ) { 2601 e.stopPropagation(); 2602 } 2603 2604 // pause if options is set 2605 if ( options.pauseOnInteraction ) { 2606 self.pause(); 2607 } 2608 2609 // navigate 2610 var fn = /right/.test( this.className ) ? 'next' : 'prev'; 2611 self[ fn ](); 2612 2613 }); 2614 /******************** Joomlashine dev BEGIN ********************/ 2615 // bind information panel 2616 if (self._options.informationPanelClickAction) 2617 { 2618 var jsntouch = Galleria.TOUCH, 2619 jsnclick = jsntouch ? 'touchstart' : 'click'; 2620 this.$('info-text').css({ 2621 cursor: 'pointer' 2622 }).bind(jsnclick, function(e) { 2623 var index = self.getIndex(); 2624 var link = self._data[index].link; 2625 if (link) 2626 { 2627 if (self._options.infoPanelPopupLinks) 2628 { 2629 win = window.open(link, '_blank'); 2630 } 2631 else 2632 { 2633 window.location.href = link; 2634 } 2635 return; 2636 }}); 2637 } 2638 /******************** Joomlashine dev END ********************/ 2639 // hide controls if chosen to 2640 $.each( ['info','counter','image-nav'], function( i, el ) { 2641 if ( options[ 'show' + el.substr(0,1).toUpperCase() + el.substr(1).replace(/-/,'') ] === false ) { 2642 Utils.moveOut( self.get( el.toLowerCase() ) ); 2643 } 2644 }); 2645 2646 // load up target content 2647 this.load(); 2648 2649 // now it's usually safe to remove the content 2650 // IE will never stop loading if we remove it, so let's keep it hidden for IE (it's usually fast enough anyway) 2651 if ( !options.keepSource && !IE ) { 2652 this._target.innerHTML = ''; 2653 } 2654 2655 // re-append the errors, if they happened before clearing 2656 if ( this.get( 'errors' ) ) { 2657 this.appendChild( 'target', 'errors' ); 2658 } 2659 2660 // append the gallery frame 2661 this.appendChild( 'target', 'container' ); 2662 2663 // parse the carousel on each thumb load 2664 if ( options.carousel ) { 2665 var count = 0, 2666 show = options.show; 2667 this.bind( Galleria.THUMBNAIL, function() { 2668 this.updateCarousel(); 2669 if ( ++count == this.getDataLength() && typeof show == 'number' && show > 0 ) { 2670 this._carousel.follow( show ); 2671 } 2672 }); 2673 } 2674 2675 // bind window resize for responsiveness 2676 if ( options.responsive ) { 2677 $win.bind( 'resize', function() { 2678 if ( !self.isFullscreen() ) { 2679 self.resize(); 2680 } 2681 }); 2682 } 2683 2684 // bind swipe gesture 2685 if ( options.swipe ) { 2686 2687 (function( images ) { 2688 2689 var swipeStart = [0,0], 2690 swipeStop = [0,0], 2691 limitX = 30, 2692 limitY = 100, 2693 multi = false, 2694 tid = 0, 2695 data, 2696 ev = { 2697 start: 'touchstart', 2698 move: 'touchmove', 2699 stop: 'touchend' 2700 }, 2701 getData = function(e) { 2702 return e.originalEvent.touches ? e.originalEvent.touches[0] : e; 2703 }, 2704 moveHandler = function( e ) { 2705 2706 if ( e.originalEvent.touches && e.originalEvent.touches.length > 1 ) { 2707 return; 2708 } 2709 2710 data = getData( e ); 2711 swipeStop = [ data.pageX, data.pageY ]; 2712 2713 if ( !swipeStart[0] ) { 2714 swipeStart = swipeStop; 2715 } 2716 2717 if ( Math.abs( swipeStart[0] - swipeStop[0] ) > 10 ) { 2718 e.preventDefault(); 2719 } 2720 }, 2721 upHandler = function( e ) { 2722 2723 images.unbind( ev.move, moveHandler ); 2724 2725 // if multitouch (possibly zooming), abort 2726 if ( ( e.originalEvent.touches && e.originalEvent.touches.length ) || multi ) { 2727 multi = !multi; 2728 return; 2729 } 2730 2731 if ( Utils.timestamp() - tid < 1000 && 2732 Math.abs( swipeStart[0] - swipeStop[0] ) > limitX && 2733 Math.abs( swipeStart[1] - swipeStop[1] ) < limitY ) { 2734 2735 e.preventDefault(); 2736 self[ swipeStart[0] > swipeStop[0] ? 'next' : 'prev' ](); 2737 } 2738 2739 swipeStart = swipeStop = [0,0]; 2740 }; 2741 2742 images.bind(ev.start, function(e) { 2743 2744 if ( e.originalEvent.touches && e.originalEvent.touches.length > 1 ) { 2745 return; 2746 } 2747 2748 data = getData(e); 2749 tid = Utils.timestamp(); 2750 swipeStart = swipeStop = [ data.pageX, data.pageY ]; 2751 images.bind(ev.move, moveHandler ).one(ev.stop, upHandler); 2752 2753 }); 2754 2755 }( self.$( 'images' ) )); 2756 2757 // double-tap/click fullscreen toggle 2758 2759 if ( options.fullscreenDoubleTap ) { 2760 2761 this.$( 'stage' ).bind( 'touchstart', (function() { 2762 var last, cx, cy, lx, ly, now, 2763 getData = function(e) { 2764 return e.originalEvent.touches ? e.originalEvent.touches[0] : e; 2765 }; 2766 return function(e) { 2767 now = Galleria.utils.timestamp(); 2768 cx = getData(e).pageX; 2769 cy = getData(e).pageY; 2770 if ( ( now - last < 500 ) && ( cx - lx < 20) && ( cy - ly < 20) ) { 2771 self.toggleFullscreen(); 2772 e.preventDefault(); 2773 self.$( 'stage' ).unbind( 'touchend', arguments.callee ); 2774 return; 2775 } 2776 last = now; 2777 lx = cx; 2778 ly = cy; 2779 }; 2780 }())); 2781 } 2782 2783 } 2784 2785 // optimize touch for container 2786 Utils.optimizeTouch( this.get( 'container' ) ); 2787 2788 // bind the ons 2789 $.each( Galleria.on.binds, function(i, bind) { 2790 // check if already bound 2791 if ( $.inArray( bind.hash, self._binds ) == -1 ) { 2792 self.bind( bind.type, bind.callback ); 2793 } 2794 }); 2795 2796 return this; 2797 }, 2798 2799 addTimer : function() { 2800 this._timer.add.apply( this._timer, Utils.array( arguments ) ); 2801 return this; 2802 }, 2803 2804 clearTimer : function() { 2805 this._timer.clear.apply( this._timer, Utils.array( arguments ) ); 2806 return this; 2807 }, 2808 2809 // parse width & height from CSS or options 2810 2811 _getWH : function() { 2812 2813 var $container = this.$( 'container' ), 2814 $target = this.$( 'target' ), 2815 self = this, 2816 num = {}, 2817 arr; 2818 2819 $.each(['width', 'height'], function( i, m ) { 2820 2821 // first check if options is set 2822 if ( self._options[ m ] && typeof self._options[ m ] === 'number') { 2823 num[ m ] = self._options[ m ]; 2824 } else { 2825 2826 arr = [ 2827 Utils.parseValue( $container.css( m ) ), // the container css height 2828 Utils.parseValue( $target.css( m ) ), // the target css height 2829 $container[ m ](), // the container jQuery method 2830 $target[ m ]() // the target jQuery method 2831 ]; 2832 2833 // if first time, include the min-width & min-height 2834 if ( !self[ '_'+m ] ) { 2835 arr.splice(arr.length, 2836 Utils.parseValue( $container.css( 'min-'+m ) ), 2837 Utils.parseValue( $target.css( 'min-'+m ) ) 2838 ); 2839 } 2840 2841 // else extract the measures from different sources and grab the highest value 2842 num[ m ] = Math.max.apply( Math, arr ); 2843 } 2844 }); 2845 2846 // allow setting a height ratio instead of exact value 2847 // useful when doing responsive galleries 2848 2849 if ( self._ratio ) { 2850 num.height = num.width * self._ratio; 2851 } 2852 2853 return num; 2854 }, 2855 2856 // Creates the thumbnails and carousel
vendor: 6,798 bytes, lines 2857-3039
2857 // can be used at any time, f.ex when the data object is manipulated 2858 // push is an optional argument with pushed images 2859 2860 _createThumbnails : function( push ) { 2861 2862 this.get( 'total' ).innerHTML = this.getDataLength(); 2863 2864 var src, 2865 thumb, 2866 data, 2867 special, 2868 2869 $container, 2870 2871 self = this, 2872 o = this._options, 2873 2874 i = push ? this._data.length - push.length : 0, 2875 chunk = i, 2876 2877 thumbchunk = [], 2878 loadindex = 0, 2879 2880 gif = IE < 8 ? 'http://upload.wikimedia.org/wikipedia/commons/c/c0/Blank.gif' : 2881 'data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw%3D%3D', 2882 2883 // get previously active thumbnail, if exists 2884 active = (function() { 2885 var a = self.$('thumbnails').find('.active'); 2886 if ( !a.length ) { 2887 return false; 2888 } 2889 return a.find('img').attr('src'); 2890 }()), 2891 2892 // cache the thumbnail option 2893 optval = typeof o.thumbnails === 'string' ? o.thumbnails.toLowerCase() : null, 2894 2895 // move some data into the instance 2896 // for some reason, jQuery cant handle css(property) when zooming in FF, breaking the gallery 2897 // so we resort to getComputedStyle for browsers who support it 2898 getStyle = function( prop ) { 2899 return doc.defaultView && doc.defaultView.getComputedStyle ? 2900 doc.defaultView.getComputedStyle( thumb.container, null )[ prop ] : 2901 $container.css( prop ); 2902 }, 2903 2904 fake = function(image, index, container) { 2905 return function() { 2906 $( container ).append( image ); 2907 self.trigger({ 2908 type: Galleria.THUMBNAIL, 2909 thumbTarget: image, 2910 index: index, 2911 galleriaData: self.getData( index ) 2912 }); 2913 }; 2914 }, 2915 2916 onThumbEvent = function( e ) { 2917 2918 // pause if option is set 2919 if ( o.pauseOnInteraction ) { 2920 self.pause(); 2921 } 2922 2923 // extract the index from the data 2924 var index = $( e.currentTarget ).data( 'index' ); 2925 if ( self.getIndex() !== index ) { 2926 self.show( index ); 2927 } 2928 2929 e.preventDefault(); 2930 }, 2931 2932 thumbComplete = function( thumb, callback ) { 2933 2934 $( thumb.container ).css( 'visibility', 'visible' ); 2935 self.trigger({ 2936 type: Galleria.THUMBNAIL, 2937 thumbTarget: thumb.image, 2938 index: thumb.data.order, 2939 galleriaData: self.getData( thumb.data.order ) 2940 }); 2941 2942 if ( typeof callback == 'function' ) { 2943 callback.call( self, thumb ); 2944 } 2945 }, 2946 2947 onThumbLoad = function( thumb, callback ) { 2948 2949 // scale when ready 2950 thumb.scale({ 2951 width: thumb.data.width, 2952 height: thumb.data.height, 2953 crop: o.thumbCrop, 2954 margin: o.thumbMargin, 2955 canvas: o.useCanvas, 2956 complete: function( thumb ) { 2957 2958 // shrink thumbnails to fit 2959 var top = ['left', 'top'], 2960 arr = ['Width', 'Height'], 2961 m, 2962 css, 2963 data = self.getData( thumb.index ), 2964 special = data.thumb.split(':'); 2965 2966 // calculate shrinked positions 2967 $.each(arr, function( i, measure ) { 2968 m = measure.toLowerCase(); 2969 if ( (o.thumbCrop !== true || o.thumbCrop === m ) && o.thumbFit ) { 2970 css = {}; 2971 css[ m ] = thumb[ m ]; 2972 $( thumb.container ).css( css ); 2973 css = {}; 2974 css[ top[ i ] ] = 0; 2975 $( thumb.image ).css( css ); 2976 } 2977 2978 // cache outer measures 2979 thumb[ 'outer' + measure ] = $( thumb.container )[ 'outer' + measure ]( true ); 2980 }); 2981 2982 // set high quality if downscale is moderate 2983 Utils.toggleQuality( thumb.image, 2984 o.thumbQuality === true || 2985 ( o.thumbQuality === 'auto' && thumb.original.width < thumb.width * 3 ) 2986 ); 2987 2988 // get "special" thumbs from provider 2989 if( data.iframe && special.length == 2 && special[0] in _video ) { 2990 2991 _video[ special[0] ].getThumb( special[1], (function(img) { 2992 return function(src) { 2993 img.src = src; 2994 thumbComplete( thumb, callback ); 2995 }; 2996 }( thumb.image ) )); 2997 2998 } else if ( o.thumbDisplayOrder && !thumb.lazy ) { 2999 3000 $.each( thumbchunk, function( i, th ) { 3001 if ( i === loadindex && th.ready && !th.displayed ) { 3002 3003 loadindex++; 3004 th.displayed = true; 3005 3006 thumbComplete( th, callback ); 3007 3008 return; 3009 } 3010 }); 3011 } else { 3012 thumbComplete( thumb, callback ); 3013 } 3014 } 3015 }); 3016 }; 3017 3018 if ( !push ) { 3019 this._thumbnails = []; 3020 this.$( 'thumbnails' ).empty(); 3021 } 3022 3023 // loop through data and create thumbnails 3024 for( ; this._data[ i ]; i++ ) { 3025 3026 data = this._data[ i ]; 3027 3028 // get source from thumb or image 3029 src = data.thumb || data.image; 3030 3031 if ( ( o.thumbnails === true || optval == 'lazy' ) && ( data.thumb || data.image ) ) { 3032 3033 // add a new Picture instance 3034 thumb = new Galleria.Picture(i); 3035 3036 // save the index 3037 thumb.index = i; 3038 3039 // flag displayed
3040 thumb.displayed = false; 3041 3042 // flag lazy 3043 thumb.lazy = false; 3044 3045 // flag video 3046 thumb.video = false; 3047 3048 // append the thumbnail 3049 this.$( 'thumbnails' ).append( thumb.container ); 3050 3051 // cache the container 3052 $container = $( thumb.container ); 3053 3054 // hide it 3055 $container.css( 'visibility', 'hidden' ); 3056 3057 thumb.data = { 3058 width : Utils.parseValue( getStyle( 'width' ) ), 3059 height : Utils.parseValue( getStyle( 'height' ) ), 3060 order : i, 3061 src : src 3062 }; 3063 3064 // grab & reset size for smoother thumbnail loads 3065 if ( o.thumbFit && o.thumbCrop !== true ) { 3066 $container.css( { width: 'auto', height: 'auto' } ); 3067 } else { 3068 $container.css( { width: thumb.data.width, height: thumb.data.height } ); 3069 } 3070 3071 // load the thumbnail 3072 special = src.split(':'); 3073 3074 if ( special.length == 2 && special[0] in _video ) { 3075 3076 thumb.video = true; 3077 thumb.ready = true; 3078 3079 thumb.load( gif, { 3080 height: thumb.data.height, 3081 width: thumb.data.height*1.25 3082 }, onThumbLoad); 3083 3084 } else if ( optval == 'lazy' ) { 3085 3086 $container.addClass( 'lazy' ); 3087 3088 thumb.lazy = true; 3089 3090 thumb.load( gif, { 3091 height: thumb.data.height, 3092 width: thumb.data.width 3093 }); 3094 3095 } else { 3096 thumb.load( src, onThumbLoad ); 3097 } 3098 3099 // preload all images here 3100 if ( o.preload === 'all' ) { 3101 thumb.preload( data.image ); 3102 } 3103 3104 // create empty spans if thumbnails is set to 'empty' 3105 } else if ( data.iframe || optval === 'empty' || optval === 'numbers' ) { 3106 3107 thumb = { 3108 container: Utils.create( 'galleria-image' ), 3109 image: Utils.create( 'img', 'span' ), 3110 ready: true 3111 }; 3112 3113 // create numbered thumbnails 3114 if ( optval === 'numbers' ) { 3115 $( thumb.image ).text( i + 1 ); 3116 } 3117 3118 if ( data.iframe ) { 3119 $( thumb.image ).addClass( 'iframe' ); 3120 } 3121 3122 this.$( 'thumbnails' ).append( thumb.container ); 3123 3124 // we need to "fake" a loading delay before we append and trigger 3125 // 50+ should be enough 3126 3127 window.setTimeout( ( fake )( thumb.image, i, thumb.container ), 50 + ( i*20 ) ); 3128 3129 // create null object to silent errors 3130 } else { 3131 thumb = { 3132 container: null, 3133 image: null 3134 }; 3135 } 3136 3137 // add events for thumbnails 3138 // you can control the event type using thumb_event_type 3139 // we'll add the same event to the source if it's kept 3140 3141 $( thumb.container ).add( o.keepSource && o.linkSourceImages ? data.original : null ) 3142 .data('index', i).bind( o.thumbEventType, onThumbEvent ) 3143 .data('thumbload', onThumbLoad); 3144 3145 if (active === src) { 3146 $( thumb.container ).addClass( 'active' ); 3147 } 3148 3149 this._thumbnails.push( thumb ); 3150 } 3151 3152 thumbchunk = this._thumbnails.slice( chunk ); 3153 3154 return this; 3155 }, 3156 3157 /** 3158 Lazy-loads thumbnails. 3159 You can call this method to load lazy thumbnails at run time 3160 3161 @param {Array|Number} index Index or array of indexes of thumbnails to be loaded 3162 @param {Function} complete Callback that is called when all lazy thumbnails have been loaded 3163 3164 @returns Instance 3165 */ 3166 3167 lazyLoad: function( index, complete ) { 3168 3169 var arr = index.constructor == Array ? index : [ index ], 3170 self = this, 3171 thumbnails = this.$( 'thumbnails' ).children().filter(function() { 3172 return $(this).data('lazy-src'); 3173 }), 3174 loaded = 0; 3175 3176 $.each( arr, function(i, ind) { 3177 3178 if ( ind > self._thumbnails.length - 1 ) { 3179 return; 3180 } 3181 3182 var thumb = self._thumbnails[ ind ], 3183 data = thumb.data, 3184 special = data.src.split(':'), 3185 callback = function() { 3186 if ( ++loaded == arr.length && typeof complete == 'function' ) { 3187 complete.call( self ); 3188 } 3189 }, 3190 thumbload = $( thumb.container ).data( 'thumbload' ); 3191 if ( thumb.video ) { 3192 thumbload.call( self, thumb, callback ); 3193 } else { 3194 thumb.load( data.src , function( thumb ) { 3195 thumbload.call( self, thumb, callback ); 3196 }); 3197 } 3198 }); 3199 3200 return this; 3201 3202 }, 3203 3204 /** 3205 Lazy-loads thumbnails in chunks. 3206 This method automatcally chops up the loading process of many thumbnails into chunks 3207 3208 @param {Number} size Size of each chunk to be loaded 3209 @param {Number} [delay] Delay between each loads 3210 3211 @returns Instance 3212 */ 3213 3214 lazyLoadChunks: function( size, delay ) { 3215 3216 var len = this.getDataLength(), 3217 i = 0, 3218 n = 0, 3219 arr = [], 3220 temp = [], 3221 self = this; 3222
vendor: 6,369 bytes, lines 3223-3428
3223 delay = delay || 0; 3224 3225 for( ; i<len; i++ ) { 3226 temp.push(i); 3227 if ( ++n == size || i == len-1 ) { 3228 arr.push( temp ); 3229 n = 0; 3230 temp = []; 3231 } 3232 } 3233 3234 var init = function( wait ) { 3235 var a = arr.shift(); 3236 if ( a ) { 3237 window.setTimeout(function() { 3238 self.lazyLoad(a, function() { 3239 init( true ); 3240 }); 3241 }, ( delay && wait ) ? delay : 0 ); 3242 } 3243 }; 3244 3245 init( false ); 3246 3247 return this; 3248 3249 }, 3250 3251 // the internal _run method should be called after loading data into galleria 3252 // makes sure the gallery has proper measurements before postrun & ready 3253 _run : function() { 3254 3255 var self = this; 3256 3257 self._createThumbnails(); 3258 3259 // make sure we have a stageHeight && stageWidth 3260 3261 Utils.wait({ 3262 3263 timeout: 10000, 3264 3265 until: function() { 3266 3267 // Opera crap 3268 if ( Galleria.OPERA ) { 3269 self.$( 'stage' ).css( 'display', 'inline-block' ); 3270 } 3271 3272 self._stageWidth = self.$( 'stage' ).width(); 3273 self._stageHeight = self.$( 'stage' ).height(); 3274 3275 return( self._stageWidth && 3276 self._stageHeight > 50 ); // what is an acceptable height? 3277 }, 3278 3279 success: function() { 3280 3281 // save the instance 3282 _galleries.push( self ); 3283 3284 // postrun some stuff after the gallery is ready 3285 3286 // show counter 3287 Utils.show( self.get('counter') ); 3288 3289 // bind carousel nav 3290 if ( self._options.carousel ) { 3291 self._carousel.bindControls(); 3292 } 3293 3294 // start autoplay 3295 if ( self._options.autoplay ) { 3296 3297 self.pause(); 3298 3299 if ( typeof self._options.autoplay === 'number' ) { 3300 self._playtime = self._options.autoplay; 3301 } 3302 3303 self._playing = true; 3304 } 3305 // if second load, just do the show and return 3306 if ( self._firstrun ) { 3307 3308 if ( self._options.autoplay ) { 3309 self.trigger( Galleria.PLAY ); 3310 } 3311 3312 if ( typeof self._options.show === 'number' ) { 3313 self.show( self._options.show ); 3314 } 3315 return; 3316 } 3317 3318 self._firstrun = true; 3319 3320 // initialize the History plugin 3321 if ( Galleria.History ) { 3322 3323 // bind the show method 3324 Galleria.History.change(function( value ) { 3325 3326 // if ID is NaN, the user pressed back from the first image 3327 // return to previous address 3328 if ( isNaN( value ) ) { 3329 window.history.go(-1); 3330 3331 // else show the image 3332 } else { 3333 self.show( value, undef, true ); 3334 } 3335 }); 3336 } 3337 3338 self.trigger( Galleria.READY ); 3339 3340 // call the theme init method 3341 Galleria.theme.init.call( self, self._options ); 3342 3343 // Trigger Galleria.ready 3344 $.each( Galleria.ready.callbacks, function(i ,fn) { 3345 if ( typeof fn == 'function' ) { 3346 fn.call( self, self._options ); 3347 } 3348 }); 3349 3350 // call the extend option 3351 self._options.extend.call( self, self._options ); 3352 3353 // show the initial image 3354 // first test for permalinks in history 3355 if ( /^[0-9]{1,4}$/.test( HASH ) && Galleria.History ) { 3356 self.show( HASH, undef, true ); 3357 3358 } else if( self._data[ self._options.show ] ) { 3359 self.show( self._options.show ); 3360 } 3361 3362 // play trigger 3363 if ( self._options.autoplay ) { 3364 self.trigger( Galleria.PLAY ); 3365 } 3366 }, 3367 3368 error: function() { 3369 Galleria.raise('Stage width or height is too small to show the gallery. Traced measures: width:' + self._stageWidth + 'px, height: ' + self._stageHeight + 'px.', true); 3370 } 3371 3372 }); 3373 }, 3374 3375 /** 3376 Loads data into the gallery. 3377 You can call this method on an existing gallery to reload the gallery with new data. 3378 3379 @param {Array|string} [source] Optional JSON array of data or selector of where to find data in the document. 3380 Defaults to the Galleria target or dataSource option. 3381 3382 @param {string} [selector] Optional element selector of what elements to parse. 3383 Defaults to 'img'. 3384 3385 @param {Function} [config] Optional function to modify the data extraction proceedure from the selector. 3386 See the dataConfig option for more information. 3387 3388 @returns Instance 3389 */ 3390 3391 load : function( source, selector, config ) { 3392 3393 var self = this, 3394 o = this._options; 3395 3396 // empty the data array 3397 this._data = []; 3398 3399 // empty the thumbnails 3400 this._thumbnails = []; 3401 this.$('thumbnails').empty(); 3402 3403 // shorten the arguments 3404 if ( typeof selector === 'function' ) { 3405 config = selector; 3406 selector = null; 3407 } 3408 3409 // use the source set by target 3410 source = source || o.dataSource; 3411 3412 // use selector set by option 3413 selector = selector || o.dataSelector; 3414 3415 // use the dataConfig set by option 3416 config = config || o.dataConfig; 3417 3418 // if source is a true object, make it into an array 3419 if( /^function Object/.test( source.constructor ) ) { 3420 source = [source]; 3421 } 3422 3423 // check if the data is an array already 3424 if ( source.constructor === Array ) { 3425 if ( this.validate( source ) ) { 3426 this._data = source; 3427 } else { 3428 Galleria.raise( 'Load failed: JSON Array not val
3428id.' ); 3429 } 3430 } else { 3431 3432 // add .video and .iframe to the selector (1.2.7) 3433 selector += ',.video,.iframe'; 3434 3435 // loop through images and set data 3436 $( source ).find( selector ).each( function( i, elem ) { 3437 3438 elem = $( elem ); 3439 var data = {}, 3440 parent = elem.parent(), 3441 href = parent.attr( 'href' ), 3442 rel = parent.attr( 'rel' ); 3443 3444 if( href && ( elem[0].nodeName == 'IMG' || elem.hasClass('video') ) && _videoTest( href ) ) { 3445 data.video = href; 3446 } else if( href && elem.hasClass('iframe') ) { 3447 data.iframe = href; 3448 } else { 3449 data.image = data.big = href; 3450 } 3451 3452 if ( rel ) { 3453 data.big = rel; 3454 } 3455 3456 // alternative extraction from HTML5 data attribute, added in 1.2.7 3457 $.each( 'big title description link layer'.split(' '), function( i, val ) { 3458 if ( elem.data(val) ) { 3459 data[ val ] = elem.data(val); 3460 } 3461 }); 3462 3463 // mix default extractions with the hrefs and config 3464 // and push it into the data array 3465 self._data.push( $.extend({ 3466 3467 title: elem.attr('title') || '', 3468 thumb: elem.attr('src'), 3469 image: elem.attr('src'), 3470 big: elem.attr('src'), 3471 description: elem.attr('alt') || '', 3472 link: elem.attr('longdesc'), 3473 original: elem.get(0) // saved as a reference 3474 3475 }, data, config( elem ) ) ); 3476 3477 }); 3478 } 3479 3480 if ( typeof o.dataSort == 'function' ) { 3481 protoArray.sort.call( this._data, o.dataSort ); 3482 } else if ( o.dataSort == 'random' ) { 3483 this._data.sort( function() { 3484 return Math.round(Math.random())-0.5; 3485 }); 3486 } 3487 3488 3489 3490 // trigger the DATA event and return 3491 if ( this.getDataLength() ) { 3492 this._parseData().trigger( Galleria.DATA ); 3493 } 3494 return this; 3495 3496 }, 3497 3498 // make sure the data works properly 3499 _parseData : function() { 3500 3501 var self = this, 3502 current; 3503 3504 $.each( this._data, function( i, data ) { 3505 3506 current = self._data[ i ]; 3507 3508 // copy image as thumb if no thumb exists 3509 if ( 'thumb' in data === false ) { 3510 current.thumb = data.image; 3511 } 3512 // copy image as big image if no biggie exists 3513 if ( !'big' in data ) { 3514 current.big = data.image; 3515 } 3516 // parse video 3517 if ( 'video' in data ) { 3518 var result = _videoTest( data.video ); 3519 3520 if ( result ) { 3521 current.iframe = _video[ result.provider ].embed( result.id ) + (function() { 3522 3523 // add options 3524 if ( typeof self._options[ result.provider ] == 'object' ) { 3525 var str = '?', arr = []; 3526 $.each( self._options[ result.provider ], function( key, val ) { 3527 arr.push( key + '=' + val ); 3528 }); 3529 3530 // small youtube specifics, perhaps move to _video later 3531 if ( result.provider == 'youtube' ) { 3532 arr = ['wmode=opaque'].concat(arr); 3533 } 3534 return str + arr.join('&'); 3535 } 3536 return ''; 3537 }()); 3538 delete current.video; 3539 if( !('thumb' in current) || !current.thumb ) { 3540 current.thumb = result.provider+':'+result.id; 3541 } 3542 } 3543 } 3544 }); 3545 3546 return this; 3547 }, 3548 3549 /** 3550 Destroy the Galleria instance and recover the original content 3551 3552 @example this.destroy(); 3553 3554 @returns Instance 3555 */ 3556 3557 destroy : function() { 3558 this.get('target').innerHTML = this._original.html; 3559 this.clearTimer(); 3560 return this; 3561 }, 3562 3563 /**
vendor: 17,686 bytes, lines 3564-4208
3564 Adds and/or removes images from the gallery 3565 Works just like Array.splice 3566 https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/splice 3567 3568 @example this.splice( 2, 4 ); // removes 4 images after the second image 3569 3570 @returns Instance 3571 */ 3572 3573 splice : function() { 3574 var self = this, 3575 args = Utils.array( arguments ); 3576 window.setTimeout(function() { 3577 protoArray.splice.apply( self._data, args ); 3578 self._parseData()._createThumbnails(); 3579 },2); 3580 return self; 3581 }, 3582 3583 /** 3584 Append images to the gallery 3585 Works just like Array.push 3586 https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/push 3587 3588 @example this.push({ image: 'image1.jpg' }); // appends the image to the gallery 3589 3590 @returns Instance 3591 */ 3592 3593 push : function() { 3594 var self = this, 3595 args = Utils.array( arguments ); 3596 3597 if ( args.length == 1 && args[0].constructor == Array ) { 3598 args = args[0]; 3599 } 3600 3601 window.setTimeout(function() { 3602 protoArray.push.apply( self._data, args ); 3603 self._parseData()._createThumbnails( args ); 3604 },2); 3605 return self; 3606 }, 3607 3608 _getActive: function() { 3609 return this._controls.getActive(); 3610 }, 3611 3612 validate : function( data ) { 3613 // todo: validate a custom data array 3614 return true; 3615 }, 3616 3617 /** 3618 Bind any event to Galleria 3619 3620 @param {string} type The Event type to listen for 3621 @param {Function} fn The function to execute when the event is triggered 3622 3623 @example this.bind( 'image', function() { Galleria.log('image shown') }); 3624 3625 @returns Instance 3626 */ 3627 3628 bind : function(type, fn) { 3629 3630 // allow 'image' instead of Galleria.IMAGE 3631 type = _patchEvent( type ); 3632 3633 this.$( 'container' ).bind( type, this.proxy(fn) ); 3634 return this; 3635 }, 3636 3637 /** 3638 Unbind any event to Galleria 3639 3640 @param {string} type The Event type to forget 3641 3642 @returns Instance 3643 */ 3644 3645 unbind : function(type) { 3646 3647 type = _patchEvent( type ); 3648 3649 this.$( 'container' ).unbind( type ); 3650 return this; 3651 }, 3652 3653 /** 3654 Manually trigger a Galleria event 3655 3656 @param {string} type The Event to trigger 3657 3658 @returns Instance 3659 */ 3660 3661 trigger : function( type ) { 3662 3663 type = typeof type === 'object' ? 3664 $.extend( type, { scope: this } ) : 3665 { type: _patchEvent( type ), scope: this }; 3666 3667 this.$( 'container' ).trigger( type ); 3668 3669 return this; 3670 }, 3671 3672 /** 3673 Assign an "idle state" to any element. 3674 The idle state will be applied after a certain amount of idle time 3675 Useful to hide f.ex navigation when the gallery is inactive 3676 3677 @param {HTMLElement|string} elem The Dom node or selector to apply the idle state to 3678 @param {Object} styles the CSS styles to apply when in idle mode 3679 @param {Object} [from] the CSS styles to apply when in normal 3680 @param {Boolean} [hide] set to true if you want to hide it first 3681 3682 @example addIdleState( this.get('image-nav'), { opacity: 0 }); 3683 @example addIdleState( '.galleria-image-nav', { top: -200 }, true); 3684 3685 @returns Instance 3686 */ 3687 3688 addIdleState: function( elem, styles, from, hide ) { 3689 this._idle.add.apply( this._idle, Utils.array( arguments ) ); 3690 return this; 3691 }, 3692 3693 /** 3694 Removes any idle state previously set using addIdleState() 3695 3696 @param {HTMLElement|string} elem The Dom node or selector to remove the idle state from. 3697 3698 @returns Instance 3699 */ 3700 3701 removeIdleState: function( elem ) { 3702 this._idle.remove.apply( this._idle, Utils.array( arguments ) ); 3703 return this; 3704 }, 3705 3706 /** 3707 Force Galleria to enter idle mode. 3708 3709 @returns Instance 3710 */ 3711 3712 enterIdleMode: function() { 3713 this._idle.hide(); 3714 return this; 3715 }, 3716 3717 /** 3718 Force Galleria to exit idle mode. 3719 3720 @returns Instance 3721 */ 3722 3723 exitIdleMode: function() { 3724 this._idle.showAll(); 3725 return this; 3726 }, 3727 3728 /** 3729 Enter FullScreen mode 3730 3731 @param {Function} callback the function to be executed when the fullscreen mode is fully applied. 3732 3733 @returns Instance 3734 */ 3735 3736 enterFullscreen: function( callback ) { 3737 this._fullscreen.enter.apply( this, Utils.array( arguments ) ); 3738 return this; 3739 }, 3740 3741 /** 3742 Exits FullScreen mode 3743 3744 @param {Function} callback the function to be executed when the fullscreen mode is fully applied. 3745 3746 @returns Instance 3747 */ 3748 3749 exitFullscreen: function( callback ) { 3750 this._fullscreen.exit.apply( this, Utils.array( arguments ) ); 3751 return this; 3752 }, 3753 3754 /** 3755 Toggle FullScreen mode 3756 3757 @param {Function} callback the function to be executed when the fullscreen mode is fully applied or removed. 3758 3759 @returns Instance 3760 */ 3761 3762 toggleFullscreen: function( callback ) { 3763 this._fullscreen[ this.isFullscreen() ? 'exit' : 'enter'].apply( this, Utils.array( arguments ) ); 3764 return this; 3765 }, 3766 3767 /** 3768 Adds a tooltip to any element. 3769 You can also call this method with an object as argument with elemID:value pairs to apply tooltips to (see examples) 3770 3771 @param {HTMLElement} elem The DOM Node to attach the event to 3772 @param {string|Function} value The tooltip message. Can also be a function that returns a string. 3773 3774 @example this.bindTooltip( this.get('thumbnails'), 'My thumbnails'); 3775 @example this.bindTooltip( this.get('thumbnails'), function() { return 'My thumbs' }); 3776 @example this.bindTooltip( { image_nav: 'Navigation' }); 3777 3778 @returns Instance 3779 */ 3780 3781 bindTooltip: function( elem, value ) { 3782 this._tooltip.bind.apply( this._tooltip, Utils.array(arguments) ); 3783 return this; 3784 }, 3785 3786 /** 3787 Note: this method is deprecated. Use refreshTooltip() instead. 3788 3789 Redefine a tooltip. 3790 Use this if you want to re-apply a tooltip value to an already bound tooltip element. 3791 3792 @param {HTMLElement} elem The DOM Node to attach the event to 3793 @param {string|Function} value The tooltip message. Can also be a function that returns a string. 3794 3795 @returns Instance 3796 */ 3797 3798 defineTooltip: function( elem, value ) { 3799 this._tooltip.define.apply( this._tooltip, Utils.array(arguments) ); 3800 return this; 3801 }, 3802 3803 /** 3804 Refresh a tooltip value. 3805 Use this if you want to change the tooltip value at runtime, f.ex if you have a play/pause toggle. 3806 3807 @param {HTMLElement} elem The DOM Node that has a tooltip that should be refreshed 3808 3809 @returns Instance 3810 */ 3811 3812 refreshTooltip: function( elem ) { 3813 this._tooltip.show.apply( this._tooltip, Utils.array(arguments) ); 3814 return this; 3815 }, 3816 3817 /** 3818 Open a pre-designed lightbox with the currently active image. 3819 You can control some visuals using gallery options. 3820 3821 @returns Instance 3822 */ 3823 3824 openLightbox: function() { 3825 this._lightbox.show.apply( this._lightbox, Utils.array( arguments ) ); 3826 return this; 3827 }, 3828 3829 /** 3830 Close the lightbox. 3831 3832 @returns Instance 3833 */ 3834 3835 closeLightbox: function() { 3836 this._lightbox.hide.apply( this._lightbox, Utils.array( arguments ) ); 3837 return this; 3838 }, 3839 3840 /** 3841 Get the currently active image element. 3842 3843 @returns {HTMLElement} The image element 3844 */ 3845 3846 getActiveImage: function() { 3847 return this._getActive().image || undef; 3848 }, 3849 3850 /** 3851 Get the currently active thumbnail element. 3852 3853 @returns {HTMLElement} The thumbnail element 3854 */ 3855 3856 getActiveThumb: function() { 3857 return this._thumbnails[ this._active ].image || undef; 3858 }, 3859 3860 /** 3861 Get the mouse position relative to the gallery container 3862 3863 @param e The mouse event 3864 3865 @example 3866 3867var gallery = this; 3868$(document).mousemove(function(e) { 3869 console.log( gallery.getMousePosition(e).x ); 3870}); 3871 3872 @returns {Object} Object with x & y of the relative mouse postion 3873 */ 3874 3875 getMousePosition : function(e) { 3876 return { 3877 x: e.pageX - this.$( 'container' ).offset().left, 3878 y: e.pageY - this.$( 'container' ).offset().top 3879 }; 3880 }, 3881 3882 /** 3883 Adds a panning effect to the image 3884 3885 @param [img] The optional image element. If not specified it takes the currently active image 3886 3887 @returns Instance 3888 */ 3889 3890 addPan : function( img ) { 3891 3892 if ( this._options.imageCrop === false ) { 3893 return; 3894 } 3895 3896 img = $( img || this.getActiveImage() ); 3897 3898 // define some variables and methods 3899 var self = this, 3900 x = img.width() / 2, 3901 y = img.height() / 2, 3902 destX = parseInt( img.css( 'left' ), 10 ), 3903 destY = parseInt( img.css( 'top' ), 10 ), 3904 curX = destX || 0, 3905 curY = destY || 0, 3906 distX = 0, 3907 distY = 0, 3908 active = false, 3909 ts = Utils.timestamp(), 3910 cache = 0, 3911 move = 0, 3912 3913 // positions the image 3914 position = function( dist, cur, pos ) { 3915 if ( dist > 0 ) { 3916 move = Math.round( Math.max( dist * -1, Math.min( 0, cur ) ) ); 3917 if ( cache !== move ) { 3918 3919 cache = move; 3920 3921 if ( IE === 8 ) { // scroll is faster for IE 3922 img.parent()[ 'scroll' + pos ]( move * -1 ); 3923 } else { 3924 var css = {}; 3925 css[ pos.toLowerCase() ] = move; 3926 img.css(css); 3927 } 3928 } 3929 } 3930 }, 3931 3932 // calculates mouse position after 50ms 3933 calculate = function(e) { 3934 if (Utils.timestamp() - ts < 50) { 3935 return; 3936 } 3937 active = true; 3938 x = self.getMousePosition(e).x; 3939 y = self.getMousePosition(e).y; 3940 }, 3941 3942 // the main loop to check 3943 loop = function(e) { 3944 3945 if (!active) { 3946 return; 3947 } 3948 3949 distX = img.width() - self._stageWidth; 3950 distY = img.height() - self._stageHeight; 3951 destX = x / self._stageWidth * distX * -1; 3952 destY = y / self._stageHeight * distY * -1; 3953 curX += ( destX - curX ) / self._options.imagePanSmoothness; 3954 curY += ( destY - curY ) / self._options.imagePanSmoothness; 3955 3956 position( distY, curY, 'Top' ); 3957 position( distX, curX, 'Left' ); 3958 3959 }; 3960 3961 // we need to use scroll in IE8 to speed things up 3962 if ( IE === 8 ) { 3963 3964 img.parent().scrollTop( curY * -1 ).scrollLeft( curX * -1 ); 3965 img.css({ 3966 top: 0, 3967 left: 0 3968 }); 3969 3970 } 3971 3972 // unbind and bind event 3973 this.$( 'stage' ).unbind( 'mousemove', calculate ).bind( 'mousemove', calculate ); 3974 3975 // loop the loop 3976 this.addTimer( 'pan' + self._id, loop, 50, true); 3977 3978 return this; 3979 }, 3980 3981 /** 3982 Brings the scope into any callback 3983 3984 @param fn The callback to bring the scope into 3985 @param [scope] Optional scope to bring 3986 3987 @example $('#fullscreen').click( this.proxy(function() { this.enterFullscreen(); }) ) 3988 3989 @returns {Function} Return the callback with the gallery scope 3990 */ 3991 3992 proxy : function( fn, scope ) { 3993 if ( typeof fn !== 'function' ) { 3994 return F; 3995 } 3996 scope = scope || this; 3997 return function() { 3998 return fn.apply( scope, Utils.array( arguments ) ); 3999 }; 4000 }, 4001 4002 /** 4003 Removes the panning effect set by addPan() 4004 4005 @returns Instance 4006 */ 4007 4008 removePan: function() { 4009 4010 // todo: doublecheck IE8 4011 4012 this.$( 'stage' ).unbind( 'mousemove' ); 4013 4014 this.clearTimer( 'pan' + this._id ); 4015 4016 return this; 4017 }, 4018 4019 /** 4020 Adds an element to the Galleria DOM array. 4021 When you add an element here, you can access it using element ID in many API calls 4022 4023 @param {string} id The element ID you wish to use. You can add many elements by adding more arguments. 4024 4025 @example addElement('mybutton'); 4026 @example addElement('mybutton','mylink'); 4027 4028 @returns Instance 4029 */ 4030 4031 addElement : function( id ) { 4032 4033 var dom = this._dom; 4034 4035 $.each( Utils.array(arguments), function( i, blueprint ) { 4036 dom[ blueprint ] = Utils.create( 'galleria-' + blueprint ); 4037 }); 4038 4039 return this; 4040 }, 4041 4042 /** 4043 Attach keyboard events to Galleria 4044 4045 @param {Object} map The map object of events. 4046 Possible keys are 'UP', 'DOWN', 'LEFT', 'RIGHT', 'RETURN', 'ESCAPE', 'BACKSPACE', and 'SPACE'. 4047 4048 @example 4049 4050this.attachKeyboard({ 4051 right: this.next, 4052 left: this.prev, 4053 up: function() { 4054 console.log( 'up key pressed' ) 4055 } 4056}); 4057 4058 @returns Instance 4059 */ 4060 4061 attachKeyboard : function( map ) { 4062 this._keyboard.attach.apply( this._keyboard, Utils.array( arguments ) ); 4063 return this; 4064 }, 4065 4066 /** 4067 Detach all keyboard events to Galleria 4068 4069 @returns Instance 4070 */ 4071 4072 detachKeyboard : function() { 4073 this._keyboard.detach.apply( this._keyboard, Utils.array( arguments ) ); 4074 return this; 4075 }, 4076 4077 /** 4078 Fast helper for appending galleria elements that you added using addElement() 4079 4080 @param {string} parentID The parent element ID where the element will be appended 4081 @param {string} childID the element ID that should be appended 4082 4083 @example this.addElement('myElement'); 4084 this.appendChild( 'info', 'myElement' ); 4085 4086 @returns Instance 4087 */ 4088 4089 appendChild : function( parentID, childID ) { 4090 this.$( parentID ).append( this.get( childID ) || childID ); 4091 return this; 4092 }, 4093 4094 /** 4095 Fast helper for prepending galleria elements that you added using addElement() 4096 4097 @param {string} parentID The parent element ID where the element will be prepended 4098 @param {string} childID the element ID that should be prepended 4099 4100 @example 4101 4102this.addElement('myElement'); 4103this.prependChild( 'info', 'myElement' ); 4104 4105 @returns Instance 4106 */ 4107 4108 prependChild : function( parentID, childID ) { 4109 this.$( parentID ).prepend( this.get( childID ) || childID ); 4110 return this; 4111 }, 4112 4113 /** 4114 Remove an element by blueprint 4115 4116 @param {string} elemID The element to be removed. 4117 You can remove multiple elements by adding arguments. 4118 4119 @returns Instance 4120 */ 4121 4122 remove : function( elemID ) { 4123 this.$( Utils.array( arguments ).join(',') ).remove(); 4124 return this; 4125 }, 4126 4127 // a fast helper for building dom structures 4128 // leave this out of the API for now 4129 4130 append : function( data ) { 4131 var i, j; 4132 for( i in data ) { 4133 if ( data.hasOwnProperty( i ) ) { 4134 if ( data[i].constructor === Array ) { 4135 for( j = 0; data[i][j]; j++ ) { 4136 this.appendChild( i, data[i][j] ); 4137 } 4138 } else { 4139 this.appendChild( i, data[i] ); 4140 } 4141 } 4142 } 4143 return this; 4144 }, 4145 4146 // an internal helper for scaling according to options 4147 _scaleImage : function( image, options ) { 4148 4149 image = image || this._controls.getActive(); 4150 4151 // janpub (JH) fix: 4152 // image might be unselected yet 4153 // e.g. when external logics rescales the gallery on window resize events 4154 if( !image ) { 4155 return; 4156 } 4157 4158 var self = this, 4159 4160 complete, 4161 4162 scaleLayer = function( img ) { 4163 $( img.container ).children(':first').css({ 4164 top: Math.max(0, Utils.parseValue( img.image.style.top )), 4165 left: Math.max(0, Utils.parseValue( img.image.style.left )), 4166 width: Utils.parseValue( img.image.width ), 4167 height: Utils.parseValue( img.image.height ) 4168 }); 4169 }; 4170 4171 options = $.extend({ 4172 width: this._stageWidth, 4173 height: this._stageHeight, 4174 crop: this._options.imageCrop, 4175 max: this._options.maxScaleRatio, 4176 min: this._options.minScaleRatio, 4177 margin: this._options.imageMargin, 4178 position: this._options.imagePosition 4179 }, options ); 4180 4181 if ( this._options.layerFollow && this._options.imageCrop !== true ) { 4182 4183 if ( typeof options.complete == 'function' ) { 4184 complete = options.complete; 4185 options.complete = function() { 4186 complete.call( image, image ); 4187 scaleLayer( image ); 4188 }; 4189 } else { 4190 options.complete = scaleLayer; 4191 } 4192 4193 } else { 4194 $( image.container ).children(':first').css({ top: 0, left: 0 }); 4195 } 4196 4197 image.scale( options ); 4198 return this; 4199 }, 4200 4201 /** 4202 Updates the carousel, 4203 useful if you resize the gallery and want to re-check if the carousel nav is needed. 4204 4205 @returns Instance 4206 */ 4207 4208 updateCarousel : function() {
4209 this._carousel.update(); 4210 return this; 4211 }, 4212 4213 /** 4214 Resize the entire gallery container 4215 4216 @param {Object} [measures] Optional object with width/height specified 4217 @param {Function} [complete] The callback to be called when the scaling is complete 4218 4219 @returns Instance 4220 */ 4221 4222 resize : function( measures, complete ) { 4223 4224 if ( typeof measures == 'function' ) { 4225 complete = measures; 4226 measures = undef; 4227 } 4228 4229 measures = $.extend( { width:0, height:0 }, measures ); 4230 4231 var self = this, 4232 $container = this.$( 'container' ); 4233 4234 $.each( measures, function( m, val ) { 4235 if ( !val ) { 4236 $container[ m ]( 'auto' ); 4237 measures[ m ] = self._getWH()[ m ]; 4238 } 4239 }); 4240 4241 $.each( measures, function( m, val ) { 4242 $container[ m ]( val ); 4243 }); 4244 4245 return this.rescale( complete ); 4246 4247 }, 4248 4249 /** 4250 Rescales the gallery 4251 4252 @param {number} width The target width 4253 @param {number} height The target height 4254 @param {Function} complete The callback to be called when the scaling is complete 4255 4256 @returns Instance 4257 */ 4258 4259 rescale : function( width, height, complete ) { 4260 4261 var self = this; 4262 4263 // allow rescale(fn) 4264 if ( typeof width === 'function' ) { 4265 complete = width; 4266 width = undef; 4267 } 4268 4269 var scale = function() { 4270 4271 // set stagewidth 4272 self._stageWidth = width || self.$( 'stage' ).width(); 4273 self._stageHeight = height || self.$( 'stage' ).height(); 4274 4275 // scale the active image 4276 self._scaleImage(); 4277 4278 if ( self._options.carousel ) { 4279 self.updateCarousel(); 4280 } 4281 4282 self.trigger( Galleria.RESCALE ); 4283 4284 if ( typeof complete === 'function' ) { 4285 complete.call( self ); 4286 } 4287 }; 4288 4289 scale.call( self ); 4290 4291 return this; 4292 }, 4293 4294 /** 4295 Refreshes the gallery. 4296 Useful if you change image options at runtime and want to apply the changes to the active image. 4297 4298 @returns Instance 4299 */ 4300 4301 refreshImage : function() { 4302 this._scaleImage(); 4303 if ( this._options.imagePan ) { 4304 this.addPan(); 4305 } 4306 return this; 4307 }, 4308 4309 /** 4310 Shows an image by index 4311 4312 @param {number|boolean} index The index to show 4313 @param {Boolean} rewind A boolean that should be true if you want the transition to go back 4314 4315 @returns Instance 4316 */ 4317 4318 show : function( index, rewind, _history ) { 4319 4320 // do nothing if index is false or queue is false and transition is in progress 4321 if ( index === false || ( !this._options.queue && this._queue.stalled ) ) { 4322 return; 4323 } 4324 4325 index = Math.max( 0, Math.min( parseInt( index, 10 ), this.getDataLength() - 1 ) ); 4326 4327 rewind = typeof rewind !== 'undefined' ? !!rewind : index < this.getIndex(); 4328 4329 _history = _history || false; 4330 4331 // do the history thing and return 4332 if ( !_history && Galleria.History ) { 4333 Galleria.History.set( index.toString() ); 4334 return; 4335 } 4336 4337 this._active = index; 4338 4339 protoArray.push.call( this._queue, { 4340 index : index, 4341 rewind : rewind 4342 }); 4343 if ( !this._queue.stalled ) { 4344 this._show(); 4345 } 4346 4347 return this; 4348 }, 4349 4350 // the internal _show method does the actual showing 4351 _show : function() { 4352 4353 // shortcuts 4354 var self = this, 4355 queue = this._queue[ 0 ], 4356 data = this.getData( queue.index ); 4357 4358 if ( !data ) { 4359 return; 4360 } 4361 4362 var src = data.iframe || ( this.isFullscreen() && 'big' in data ? data.big : data.image ), // use big image if fullscreen mode 4363 active = this._controls.getActive(), 4364 next = this._controls.getNext(), 4365 cached = next.isCached( src ), 4366 thumb = this._thumbnails[ queue.index ], 4367 mousetrigger = function() { 4368 $( next.image ).trigger( 'mouseup' ); 4369 }; 4370 4371 // to be fired when loading & transition is complete: 4372 var complete = (function( data, next, active, queue, thumb ) { 4373 4374 return function() { 4375 4376 var win; 4377 4378 _transitions.active = false;
4379 4380 // remove stalled 4381 self._queue.stalled = false; 4382 4383 // optimize quality 4384 Utils.toggleQuality( next.image, self._options.imageQuality ); 4385 4386 // remove old layer 4387 self._layers[ self._controls.active ].innerHTML = ''; 4388 4389 // swap 4390 $( active.container ).css({ 4391 zIndex: 0, 4392 opacity: 0 4393 }).show(); 4394 4395 if( active.isIframe ) { 4396 $( active.container ).find( 'iframe' ).remove(); 4397 } 4398 4399 self.$('container').toggleClass('iframe', !!data.iframe); 4400 4401 $( next.container ).css({ 4402 zIndex: 1, 4403 left: 0, 4404 top: 0 4405 }).show(); 4406 4407 self._controls.swap(); 4408 4409 // add pan according to option 4410 if ( self._options.imagePan ) { 4411 self.addPan( next.image ); 4412 } 4413 4414 // make the image link or add lightbox 4415 // link takes precedence over lightbox if both are detected 4416 if(self._options.imageClickAction) 4417 { 4418 if ( data.link || self._options.lightbox || self._options.clicknext ) { 4419 4420 $( next.image ).css({ 4421 cursor: 'pointer' 4422 }).bind( 'mouseup', function() { 4423 4424 // clicknext 4425 if ( self._options.clicknext && !Galleria.TOUCH ) { 4426 if ( self._options.pauseOnInteraction ) { 4427 self.pause(); 4428 } 4429 self.next(); 4430 return; 4431 } 4432 4433 // popup link 4434 if ( data.link ) { 4435 if ( self._options.popupLinks ) { 4436 win = window.open( data.link, '_blank' ); 4437 } else { 4438 window.location.href = data.link; 4439 } 4440 return; 4441 } 4442 4443 if ( self._options.lightbox ) { 4444 self.openLightbox(); 4445 } 4446 4447 }); 4448 } 4449 } 4450 4451 // remove the queued image 4452 protoArray.shift.call( self._queue ); 4453 4454 // if we still have images in the queue, show it 4455 if ( self._queue.length ) { 4456 self._show(); 4457 } 4458 4459 // check if we are playing 4460 self._playCheck(); 4461 4462 // trigger IMAGE event 4463 self.trigger({ 4464 type: Galleria.IMAGE, 4465 index: queue.index, 4466 imageTarget: next.image, 4467 thumbTarget: thumb.image, 4468 galleriaData: data 4469 }); 4470 }; 4471 }( data, next, active, queue, thumb )); 4472 4473 // let the carousel follow 4474 if ( this._options.carousel && this._options.carouselFollow ) { 4475 this._carousel.follow( queue.index ); 4476 } 4477 4478 // preload images 4479 if ( this._options.preload ) { 4480 4481 var p, i, 4482 n = this.getNext(), 4483 ndata; 4484 4485 try { 4486 for ( i = this._options.preload; i > 0; i-- ) { 4487 p = new Galleria.Picture(); 4488 ndata = self.getData( n ); 4489 p.preload( this.isFullscreen() && 'big' in ndata ? ndata.big : ndata.image ); 4490 n = self.getNext( n ); 4491 } 4492 } catch(e) {} 4493 } 4494 4495 // show the next image, just in case 4496 Utils.show( next.container ); 4497 4498 next.isIframe = !!data.iframe; 4499 4500 // add active classes 4501 $( self._thumbnails[ queue.index ].container ) 4502 .addClass( 'active' ) 4503 .siblings( '.active' ) 4504 .removeClass( 'active' ); 4505 4506 // trigger the LOADSTART event 4507 self.trigger( { 4508 type: Galleria.LOADSTART, 4509 cached: cached, 4510 index: queue.index, 4511 rewind: queue.rewind, 4512 imageTarget: next.image, 4513 thumbTarget: thumb.image, 4514 galleriaData: data 4515 }); 4516 4517 // begin loading the next image 4518 next.load( src, function( next ) { 4519 4520 // add layer HTML 4521 var layer = $( self._layers[ 1-self._controls.active ] ).html( data.layer || '' ).hide(); 4522 4523 self._scaleImage( next, { 4524 4525 complete: function( next ) { 4526 4527 // toggle low quality for IE 4528 if ( 'image' in active ) { 4529 Utils.toggleQuality( active.image, false ); 4530 } 4531 Utils.toggleQuality( next.image, false ); 4532 4533 // stall the queue 4534 self._queue.stalled = true; 4535 4536 // remove the image panning, if applied 4537 // TODO: rethink if this is necessary 4538 self.removePan(); 4539 4540 // set the captions and counter
vendor: 10,705 bytes, lines 4541-4956
4541 self.setInfo( queue.index ); 4542 self.setCounter( queue.index ); 4543 4544 // show the layer now 4545 if ( data.layer ) { 4546 layer.show(); 4547 // inherit click events set on image 4548 if ( data.link || self._options.lightbox || self._options.clicknext ) { 4549 layer.css( 'cursor', 'pointer' ).unbind( 'mouseup' ).mouseup( mousetrigger ); 4550 } 4551 } 4552 4553 // trigger the LOADFINISH event 4554 self.trigger({ 4555 type: Galleria.LOADFINISH, 4556 cached: cached, 4557 index: queue.index, 4558 rewind: queue.rewind, 4559 imageTarget: next.image, 4560 thumbTarget: self._thumbnails[ queue.index ].image, 4561 galleriaData: self.getData( queue.index ) 4562 }); 4563 4564 var transition = self._options.transition; 4565 4566 // can JavaScript loop through objects in order? yes. 4567 $.each({ 4568 initial: active.image === null, 4569 touch: Galleria.TOUCH, 4570 fullscreen: self.isFullscreen() 4571 }, function( type, arg ) { 4572 if ( arg && self._options[ type + 'Transition' ] !== undef ) { 4573 transition = self._options[ type + 'Transition' ]; 4574 return false; 4575 } 4576 }); 4577 4578 // validate the transition 4579 if ( transition in _transitions.effects === false ) { 4580 complete(); 4581 } else { 4582 var params = { 4583 prev: active.container, 4584 next: next.container, 4585 rewind: queue.rewind, 4586 speed: self._options.transitionSpeed || 400 4587 }; 4588 4589 _transitions.active = true; 4590 4591 // call the transition function and send some stuff 4592 _transitions.init.call( self, transition, params, complete ); 4593 4594 } 4595 } 4596 }); 4597 }); 4598 }, 4599 4600 /** 4601 Gets the next index 4602 4603 @param {number} [base] Optional starting point 4604 4605 @returns {number} the next index, or the first if you are at the first (looping) 4606 */ 4607 4608 getNext : function( base ) { 4609 base = typeof base === 'number' ? base : this.getIndex(); 4610 return base === this.getDataLength() - 1 ? 0 : base + 1; 4611 }, 4612 4613 /** 4614 Gets the previous index 4615 4616 @param {number} [base] Optional starting point 4617 4618 @returns {number} the previous index, or the last if you are at the first (looping) 4619 */ 4620 4621 getPrev : function( base ) { 4622 base = typeof base === 'number' ? base : this.getIndex(); 4623 return base === 0 ? this.getDataLength() - 1 : base - 1; 4624 }, 4625 4626 /** 4627 Shows the next image in line 4628 4629 @returns Instance 4630 */ 4631 4632 next : function() { 4633 if ( this.getDataLength() > 1 ) { 4634 this.show( this.getNext(), false ); 4635 } 4636 return this; 4637 }, 4638 4639 /** 4640 Shows the previous image in line 4641 4642 @returns Instance 4643 */ 4644 4645 prev : function() { 4646 if ( this.getDataLength() > 1 ) { 4647 this.show( this.getPrev(), true ); 4648 } 4649 return this; 4650 }, 4651 4652 /** 4653 Retrieve a DOM element by element ID 4654 4655 @param {string} elemId The delement ID to fetch 4656 4657 @returns {HTMLElement} The elements DOM node or null if not found. 4658 */ 4659 4660 get : function( elemId ) { 4661 return elemId in this._dom ? this._dom[ elemId ] : null; 4662 }, 4663 4664 /** 4665 Retrieve a data object 4666 4667 @param {number} index The data index to retrieve. 4668 If no index specified it will take the currently active image 4669 4670 @returns {Object} The data object 4671 */ 4672 4673 getData : function( index ) { 4674 return index in this._data ? 4675 this._data[ index ] : this._data[ this._active ]; 4676 }, 4677 4678 /** 4679 Retrieve the number of data items 4680 4681 @returns {number} The data length 4682 */ 4683 getDataLength : function() { 4684 return this._data.length; 4685 }, 4686 4687 /** 4688 Retrieve the currently active index 4689 4690 @returns {number|boolean} The active index or false if none found 4691 */ 4692 4693 getIndex : function() { 4694 return typeof this._active === 'number' ? this._active : false; 4695 }, 4696 4697 /** 4698 Retrieve the stage height 4699 4700 @returns {number} The stage height 4701 */ 4702 4703 getStageHeight : function() { 4704 return this._stageHeight; 4705 }, 4706 4707 /** 4708 Retrieve the stage width 4709 4710 @returns {number} The stage width 4711 */ 4712 4713 getStageWidth : function() { 4714 return this._stageWidth; 4715 }, 4716 4717 /** 4718 Retrieve the option 4719 4720 @param {string} key The option key to retrieve. If no key specified it will return all options in an object. 4721 4722 @returns option or options 4723 */ 4724 4725 getOptions : function( key ) { 4726 return typeof key === 'undefined' ? this._options : this._options[ key ]; 4727 }, 4728 4729 /** 4730 Set options to the instance. 4731 You can set options using a key & value argument or a single object argument (see examples) 4732 4733 @param {string} key The option key 4734 @param {string} value the the options value 4735 4736 @example setOptions( 'autoplay', true ) 4737 @example setOptions({ autoplay: true }); 4738 4739 @returns Instance 4740 */ 4741 4742 setOptions : function( key, value ) { 4743 if ( typeof key === 'object' ) { 4744 $.extend( this._options, key ); 4745 } else { 4746 this._options[ key ] = value; 4747 } 4748 return this; 4749 }, 4750 4751 /** 4752 Starts playing the slideshow 4753 4754 @param {number} delay Sets the slideshow interval in milliseconds. 4755 If you set it once, you can just call play() and get the same interval the next time. 4756 4757 @returns Instance 4758 */ 4759 4760 play : function( delay ) { 4761 4762 this._playing = true; 4763 4764 this._playtime = delay || this._playtime; 4765 4766 this._playCheck(); 4767 4768 this.trigger( Galleria.PLAY ); 4769 4770 return this; 4771 }, 4772 4773 /** 4774 Stops the slideshow if currently playing 4775 4776 @returns Instance 4777 */ 4778 4779 pause : function() { 4780 4781 this._playing = false; 4782 4783 this.trigger( Galleria.PAUSE ); 4784 4785 return this; 4786 }, 4787 4788 /** 4789 Toggle between play and pause events. 4790 4791 @param {number} delay Sets the slideshow interval in milliseconds. 4792 4793 @returns Instance 4794 */ 4795 4796 playToggle : function( delay ) { 4797 return ( this._playing ) ? this.pause() : this.play( delay ); 4798 }, 4799 4800 /** 4801 Checks if the gallery is currently playing 4802 4803 @returns {Boolean} 4804 */ 4805 4806 isPlaying : function() { 4807 return this._playing; 4808 }, 4809 4810 /** 4811 Checks if the gallery is currently in fullscreen mode 4812 4813 @returns {Boolean} 4814 */ 4815 4816 isFullscreen : function() { 4817 return this._fullscreen.active; 4818 }, 4819 4820 _playCheck : function() { 4821 var self = this, 4822 played = 0, 4823 interval = 20, 4824 now = Utils.timestamp(), 4825 timer_id = 'play' + this._id; 4826 4827 if ( this._playing ) { 4828 4829 this.clearTimer( timer_id ); 4830 4831 var fn = function() { 4832 4833 played = Utils.timestamp() - now; 4834 if ( played >= self._playtime && self._playing ) { 4835 self.clearTimer( timer_id ); 4836 self.next(); 4837 return; 4838 } 4839 if ( self._playing ) { 4840 4841 // trigger the PROGRESS event 4842 self.trigger({ 4843 type: Galleria.PROGRESS, 4844 percent: Math.ceil( played / self._playtime * 100 ), 4845 seconds: Math.floor( played / 1000 ), 4846 milliseconds: played 4847 }); 4848 4849 self.addTimer( timer_id, fn, interval ); 4850 } 4851 }; 4852 self.addTimer( timer_id, fn, interval ); 4853 } 4854 }, 4855 4856 /** 4857 Modify the slideshow delay 4858 4859 @param {number} delay the number of milliseconds between slides, 4860 4861 @returns Instance 4862 */ 4863 4864 setPlaytime: function( delay ) { 4865 this._playtime = delay; 4866 return this; 4867 }, 4868 4869 setIndex: function( val ) { 4870 this._active = val; 4871 return this; 4872 }, 4873 4874 /** 4875 Manually modify the counter 4876 4877 @param {number} [index] Optional data index to fectch, 4878 if no index found it assumes the currently active index 4879 4880 @returns Instance 4881 */ 4882 4883 setCounter: function( index ) { 4884 4885 if ( typeof index === 'number' ) { 4886 index++; 4887 } else if ( typeof index === 'undefined' ) { 4888 index = this.getIndex()+1; 4889 } 4890 4891 this.get( 'current' ).innerHTML = index; 4892 4893 if ( IE ) { // weird IE bug 4894 4895 var count = this.$( 'counter' ), 4896 opacity = count.css( 'opacity' ); 4897 4898 if ( parseInt( opacity, 10 ) === 1) { 4899 Utils.removeAlpha( count[0] ); 4900 } else { 4901 this.$( 'counter' ).css( 'opacity', opacity ); 4902 } 4903 4904 } 4905 4906 return this; 4907 }, 4908 4909 /** 4910 Manually set captions 4911 4912 @param {number} [index] Optional data index to fectch and apply as caption, 4913 if no index found it assumes the currently active index 4914 4915 @returns Instance 4916 */ 4917 4918 setInfo : function( index ) { 4919 4920 var self = this, 4921 data = this.getData( index ); 4922 4923 $.each( ['title','description'], function( i, type ) { 4924 4925 var elem = self.$( 'info-' + type ); 4926 4927 if ( !!data[type] ) { 4928 elem[ data[ type ].length ? 'show' : 'hide' ]().html( data[ type ] ); 4929 } else { 4930 elem.empty().hide(); 4931 } 4932 }); 4933 4934 return this; 4935 }, 4936 4937 /** 4938 Checks if the data contains any captions 4939 4940 @param {number} [index] Optional data index to fectch, 4941 if no index found it assumes the currently active index. 4942 4943 @returns {boolean} 4944 */ 4945 4946 hasInfo : function( index ) { 4947 4948 var check = 'title description'.split(' '), 4949 i; 4950 4951 for ( i = 0; check[i]; i++ ) { 4952 if ( !!this.getData( index )[ check[i] ] ) { 4953 return true; 4954 } 4955 } 4956 return false;
4957 4958 }, 4959 4960 jQuery : function( str ) { 4961 4962 var self = this, 4963 ret = []; 4964 4965 $.each( str.split(','), function( i, elemId ) { 4966 elemId = $.trim( elemId ); 4967 4968 if ( self.get( elemId ) ) { 4969 ret.push( elemId ); 4970 } 4971 }); 4972 4973 var jQ = $( self.get( ret.shift() ) ); 4974 4975 $.each( ret, function( i, elemId ) { 4976 jQ = jQ.add( self.get( elemId ) ); 4977 }); 4978 4979 return jQ; 4980 4981 }, 4982 4983 /** 4984 Converts element IDs into a jQuery collection 4985 You can call for multiple IDs separated with commas. 4986 4987 @param {string} str One or more element IDs (comma-separated) 4988 4989 @returns jQuery 4990 4991 @example this.$('info,container').hide(); 4992 */ 4993 4994 $ : function( str ) { 4995 return this.jQuery.apply( this, Utils.array( arguments ) ); 4996 } 4997 4998}; 4999 5000// End of Galleria prototype 5001 5002// Add events as static variables 5003$.each( _events, function( i, ev ) { 5004 5005 // legacy events 5006 var type = /_/.test( ev ) ? ev.replace( /_/g, '' ) : ev; 5007 5008 Galleria[ ev.toUpperCase() ] = 'galleria.'+type; 5009 5010} ); 5011 5012$.extend( Galleria, { 5013 5014 // Browser helpers 5015 IE9: IE === 9, 5016 IE8: IE === 8, 5017 IE7: IE === 7, 5018 IE6: IE === 6, 5019 IE: IE, 5020 WEBKIT: /webkit/.test( NAV ), 5021 CHROME: /chrome/.test( NAV ), 5022 SAFARI: /safari/.test( NAV ) && !(/chrome/.test( NAV )), 5023 QUIRK: ( IE && doc.compatMode && doc.compatMode === "BackCompat" ), 5024 MAC: /mac/.test( navigator.platform.toLowerCase() ), 5025 OPERA: !!window.opera, 5026 IPHONE: /iphone/.test( NAV ), 5027 IPAD: /ipad/.test( NAV ), 5028 ANDROID: /android/.test( NAV ), 5029 TOUCH: ('ontouchstart' in doc) 5030 5031}); 5032 5033// Galleria static methods 5034 5035/** 5036 Adds a theme that you can use for your Gallery 5037 5038 @param {Object} theme Object that should contain all your theme settings. 5039 <ul> 5040 <li>name - name of the theme</li> 5041 <li>author - name of the author</li> 5042 <li>css - css file name (not path)</li> 5043 <li>defaults - default options to apply, including theme-specific options</li> 5044 <li>init - the init function</li> 5045 </ul> 5046 5047 @returns {Object} theme 5048*/ 5049 5050Galleria.addTheme = function( theme ) { 5051 5052 // make sure we have a name 5053 if ( !theme.name ) { 5054 Galleria.raise('No theme name specified'); 5055 } 5056 5057 if ( typeof theme.defaults !== 'object' ) { 5058 theme.defaults = {}; 5059 } else { 5060 theme.defaults = _legacyOptions( theme.defaults ); 5061 } 5062 5063 var css = false, 5064 reg; 5065 5066 if ( typeof theme.css === 'string' ) { 5067 5068 // look for manually added CSS 5069 $('link').each(function( i, link ) { 5070 reg = new RegExp( theme.css ); 5071 if ( reg.test( link.href ) ) { 5072 5073 // we found the css 5074 css = true; 5075 5076 // the themeload trigger 5077 _themeLoad( theme ); 5078 5079 return false; 5080 } 5081 }); 5082 5083 // else look for the absolute path and load the CSS dynamic 5084 if ( !css ) { 5085 5086 $('script').each(function( i, script ) { 5087 5088 // look for the theme script 5089 reg = new RegExp( 'galleria\\.' + theme.name.toLowerCase() + '\\.' ); 5090 if( reg.test( script.src )) { 5091 5092 // we have a match 5093 css = script.src.replace(/[^\/]*$/, '') + theme.css; 5094 5095 window.setTimeout(function() { 5096 Utils.loadCSS( css, 'galleria-theme', function() { 5097 5098 // the themeload trigger 5099 _themeLoad( theme ); 5100 5101 }); 5102 }, 1); 5103 5104 } 5105 }); 5106 } 5107 5108 if ( !css ) { 5109 Galleria.raise('No theme CSS loaded'); 5110 } 5111 } else { 5112 5113 // pass 5114 _themeLoad( theme ); 5115 } 5116 return theme; 5117}; 5118 5119/** 5120 loadTheme loads a theme js file and attaches a load event to Galleria 5121 5122 @param {string} src The relative path to the theme source file 5123 5124 @param {Object} [options] Optional options you want to apply 5125 5126 @returns Galleria 5127*/ 5128 5129Galleria.loadTheme = function( src, options ) { 5130 5131 var loaded = false, 5132 length = _galleries.length, 5133 err = window.setTimeout( function() { 5134 Galleria.raise( "Theme at " + src + " could not load, check theme path.", true ); 5135 }, 5000 ); 5136 5137 // first clear the current theme, if exists 5138 Galleria.theme = undef; 5139 5140 // load the theme 5141 Utils.loadScript( src, function() { 5142 5143 window.clearTimeout( err ); 5144 5145 // check for existing galleries and reload them with the new theme 5146 if ( length ) { 5147 5148 // temporary save the new galleries 5149 var refreshed = []; 5150 5151 // refresh all instances 5152 // when adding a new theme to an existing gallery, all options will be resetted but the data will be kept 5153 // you can apply new options as a second argument 5154 $.each( Galleria.get(), function(i, instance) { 5155 5156 // mix the old data and options into the new instance 5157 var op = $.extend( instance._original.options, { 5158 data_source: instance._data 5159 }, options); 5160 5161 // remove the old container 5162 instance.$('container').remove(); 5163 5164 // create a new instance 5165 var g = new Galleria(); 5166 5167 // move the id 5168 g._id = instance._id; 5169 5170 // initialize the new instance 5171 g.init( instance._original.target, op ); 5172 5173 // push the new instance 5174 refreshed.push( g ); 5175 }); 5176 5177 // now overwrite the old holder with the new instances 5178 _galleries = refreshed; 5179 } 5180 5181 }); 5182 5183 return Galleria; 5184}; 5185 5186/** 5187 Retrieves a Galleria instance. 5188 5189 @param {number} [index] Optional index to retrieve. 5190 If no index is supplied, the method will return all instances in an array.
vendor: 5,523 bytes, lines 5191-5428
5191 5192 @returns Instance or Array of instances 5193*/ 5194 5195Galleria.get = function( index ) { 5196 if ( !!_instances[ index ] ) { 5197 return _instances[ index ]; 5198 } else if ( typeof index !== 'number' ) { 5199 return _instances; 5200 } else { 5201 Galleria.raise('Gallery index ' + index + ' not found'); 5202 } 5203}; 5204 5205/** 5206 5207 Configure Galleria options via a static function. 5208 The options will be applied to all instances 5209 5210 @param {string|object} key The options to apply or a key 5211 5212 @param [value] If key is a string, this is the value 5213 5214 @returns Galleria 5215 5216*/ 5217 5218Galleria.configure = function( key, value ) { 5219 5220 var opts = {}; 5221 5222 if( typeof key == 'string' && value ) { 5223 opts[key] = value; 5224 key = opts; 5225 } else { 5226 $.extend( opts, key ); 5227 } 5228 5229 Galleria.configure.options = opts; 5230 5231 $.each( Galleria.get(), function(i, instance) { 5232 instance.setOptions( opts ); 5233 }); 5234 5235 return Galleria; 5236}; 5237 5238Galleria.configure.options = {}; 5239 5240/** 5241 5242 Bind a Galleria event to the gallery 5243 5244 @param {string} type A string representing the galleria event 5245 5246 @param {function} callback The function that should run when the event is triggered 5247 5248 @returns Galleria 5249 5250*/ 5251 5252Galleria.on = function( type, callback ) { 5253 if ( !type ) { 5254 return; 5255 } 5256 5257 callback = callback || F; 5258 5259 // hash the bind 5260 var hash = type + callback.toString().replace(/\s/g,'') + Utils.timestamp(); 5261 5262 // for existing instances 5263 $.each( Galleria.get(), function(i, instance) { 5264 instance._binds.push( hash ); 5265 instance.bind( type, callback ); 5266 }); 5267 5268 // for future instances 5269 Galleria.on.binds.push({ 5270 type: type, 5271 callback: callback, 5272 hash: hash 5273 }); 5274 5275 return Galleria; 5276}; 5277 5278Galleria.on.binds = []; 5279 5280/** 5281 5282 Run Galleria 5283 Alias for $(selector).galleria(options) 5284 5285 @param {string} selector A selector of element(s) to intialize galleria to 5286 5287 @param {object} options The options to apply 5288 5289 @returns Galleria 5290 5291*/ 5292 5293Galleria.run = function( selector, options ) { 5294 $( selector || '#galleria' ).galleria( options ); 5295 return Galleria; 5296}; 5297 5298/** 5299 Creates a transition to be used in your gallery 5300 5301 @param {string} name The name of the transition that you will use as an option 5302 5303 @param {Function} fn The function to be executed in the transition. 5304 The function contains two arguments, params and complete. 5305 Use the params Object to integrate the transition, and then call complete when you are done. 5306 5307 @returns Galleria 5308 5309*/ 5310 5311Galleria.addTransition = function( name, fn ) { 5312 _transitions.effects[name] = fn; 5313 return Galleria; 5314}; 5315 5316/** 5317 The Galleria utilites 5318*/ 5319 5320Galleria.utils = Utils; 5321 5322/** 5323 A helper metod for cross-browser logging. 5324 It uses the console log if available otherwise it falls back to alert 5325 5326 @example Galleria.log("hello", document.body, [1,2,3]); 5327*/ 5328 5329Galleria.log = function() { 5330 var args = Utils.array( arguments ); 5331 if( 'console' in window && 'log' in window.console ) { 5332 try { 5333 return window.console.log.apply( window.console, args ); 5334 } catch( e ) { 5335 $.each( args, function() { 5336 window.console.log(this); 5337 }); 5338 } 5339 } else { 5340 return window.alert( args.join('<br>') ); 5341 } 5342}; 5343 5344/** 5345 A ready method for adding callbacks when a gallery is ready 5346 Each method is call before the extend option for every instance 5347 5348 @param {function} callback The function to call 5349 5350 @returns Galleria 5351*/ 5352 5353Galleria.ready = function( fn ) { 5354 if ( typeof fn != 'function' ) { 5355 return Galleria; 5356 } 5357 $.each( _galleries, function( i, gallery ) { 5358 fn.call( gallery, gallery._options ); 5359 }); 5360 Galleria.ready.callbacks.push( fn ); 5361 return Galleria; 5362}; 5363 5364Galleria.ready.callbacks = []; 5365 5366/** 5367 Method for raising errors 5368 5369 @param {string} msg The message to throw 5370 5371 @param {boolean} [fatal] Set this to true to override debug settings and display a fatal error 5372*/ 5373 5374Galleria.raise = function( msg, fatal ) { 5375 5376 var type = fatal ? 'Fatal error' : 'Error', 5377 5378 self = this, 5379 5380 css = { 5381 color: '#fff', 5382 position: 'absolute', 5383 top: 0, 5384 left: 0, 5385 zIndex: 100000 5386 }, 5387 5388 echo = function( msg ) { 5389 5390 var html = '<div style="padding:4px;margin:0 0 2px;background:#' + 5391 ( fatal ? '811' : '222' ) + '";>' + 5392 ( fatal ? '<strong>' + type + ': </strong>' : '' ) + 5393 msg + '</div>'; 5394 5395 $.each( _instances, function() { 5396 5397 var cont = this.$( 'errors' ), 5398 target = this.$( 'target' ); 5399 5400 if ( !cont.length ) { 5401 5402 target.css( 'position', 'relative' ); 5403 5404 cont = this.addElement( 'errors' ).appendChild( 'target', 'errors' ).$( 'errors' ).css(css); 5405 } 5406 cont.append( html ); 5407 5408 }); 5409 5410 if ( !_instances.length ) { 5411 $('<div>').css( $.extend( css, { position: 'fixed' } ) ).append( html ).appendTo( DOM().body ); 5412 } 5413 }; 5414 5415 // if debug is on, display errors and throw exception if fatal 5416 if ( DEBUG ) { 5417 echo( msg ); 5418 if ( fatal ) { 5419 throw new Error(type + ': ' + msg); 5420 } 5421 5422 // else just echo a silent generic error if fatal 5423 } else if ( fatal ) { 5424 if ( _hasError ) { 5425 return; 5426 } 5427 _hasError = true; 5428 fatal = false;
5429 echo( 'Gallery could not load.' ); 5430 } 5431}; 5432 5433// Add the version 5434Galleria.version = VERSION; 5435 5436/** 5437 A method for checking what version of Galleria the user has installed and throws a readable error if the user needs to upgrade. 5438 Useful when building plugins that requires a certain version to function. 5439 5440 @param {number} version The minimum version required 5441 5442 @param {string} [msg] Optional message to display. If not specified, Galleria will throw a generic error. 5443 5444 @returns Galleria 5445*/ 5446 5447Galleria.requires = function( version, msg ) { 5448 msg = msg || 'You need to upgrade Galleria to version ' + version + ' to use one or more components.'; 5449 if ( Galleria.version < version ) { 5450 Galleria.raise(msg, true); 5451 } 5452 return Galleria; 5453}; 5454 5455/** 5456 Adds preload, cache, scale and crop functionality 5457 5458 @constructor 5459 5460 @requires jQuery 5461 5462 @param {number} [id] Optional id to keep track of instances 5463*/ 5464 5465Galleria.Picture = function( id ) { 5466 5467 // save the id 5468 this.id = id || null; 5469 5470 // the image should be null until loaded 5471 this.image = null; 5472 5473 // Create a new container 5474 this.container = Utils.create('galleria-image'); 5475 5476 // add container styles 5477 $( this.container ).css({ 5478 overflow: 'hidden', 5479 position: 'relative' // for IE Standards mode 5480 }); 5481 5482 // saves the original measurements 5483 this.original = { 5484 width: 0, 5485 height: 0 5486 }; 5487 5488 // flag when the image is ready 5489 this.ready = false; 5490 5491 // flag for iframe Picture 5492 this.isIframe = false; 5493 5494}; 5495 5496Galleria.Picture.prototype = { 5497 5498 // the inherited cache object 5499 cache: {}, 5500 5501 // show the image on stage 5502 show: function() { 5503 Utils.show( this.image ); 5504 }, 5505 5506 // hide the image 5507 hide: function() { 5508 Utils.moveOut( this.image ); 5509 }, 5510 5511 clear: function() { 5512 this.image = null; 5513 }, 5514 5515 /** 5516 Checks if an image is in cache 5517 5518 @param {string} src The image source path, ex '/path/to/img.jpg' 5519 5520 @returns {boolean} 5521 */ 5522 5523 isCached: function( src ) { 5524 return !!this.cache[src]; 5525 }, 5526 5527 /** 5528 Preloads an image into the cache 5529 5530 @param {string} src The image source path, ex '/path/to/img.jpg' 5531 5532 @returns Galleria.Picture 5533 */ 5534 5535 preload: function( src ) { 5536 $( new Image() ).load((function(src, cache) { 5537 return function() { 5538 cache[ src ] = src; 5539 }; 5540 }( src, this.cache ))).attr( 'src', src ); 5541 }, 5542 5543 /** 5544 Loads an image and call the callback when ready. 5545 Will also add the image to cache. 5546 5547 @param {string} src The image source path, ex '/path/to/img.jpg' 5548 @param {Object} [size] The forced size of the image, defined as an object { width: xx, height:xx } 5549 @param {Function} callback The function to be executed when the image is loaded & scaled 5550 5551 @returns The image container (jQuery object) 5552 */ 5553 5554 load: function(src, size, callback) { 5555 5556 if ( typeof size == 'function' ) { 5557 callback = size; 5558 size = null; 5559 } 5560 5561 if( this.isIframe ) { 5562 var id = 'if'+new Date().getTime(); 5563 5564 this.image = $('<iframe>', { 5565 src: src, 5566 frameborder: 0, 5567 id: id, 5568 allowfullscreen: true, 5569 css: { visibility: 'hidden' } 5570 })[0]; 5571 5572 $( this.container ).find( 'iframe,img' ).remove(); 5573 5574 this.container.appendChild( this.image ); 5575 5576 $('#'+id).load( (function( self, callback ) { 5577 return function() { 5578 window.setTimeout(function() { 5579 $( self.image ).css( 'visibility', 'visible' ); 5580 if( typeof callback == 'function' ) { 5581 callback.call( self, self ); 5582 } 5583 }, 10); 5584 }; 5585 }( this, callback ))); 5586 5587 return this.container; 5588 } 5589 5590 this.image = new Image(); 5591 5592 var i = 0, 5593 reload = false, 5594 resort = false, 5595 5596 // some jquery cache 5597 $container = $( this.container ), 5598 $image = $( this.image ), 5599 5600 onerror = function() { 5601 if ( !reload ) { 5602 reload = true; 5603 // reload the image with a timestamp 5604 window.setTimeout((function(image, src) { 5605 return function() { 5606 image.attr('src', src + '?' + Utils.timestamp() ); 5607 }; 5608 }( $(this), src )), 50); 5609 } else { 5610 // apply the dummy image if it exists 5611 if ( DUMMY ) { 5612 $( this ).attr( 'src', DUMMY ); 5613 } else { 5614 Galleria.raise('Image not found: ' + src); 5615 } 5616 } 5617 }, 5618 5619 // the onload method 5620 onload = (function( self, callback, src ) { 5621 5622 return function() { 5623 5624 var complete = function() { 5625 5626 $( this ).unbind( 'load' ); 5627 5628 // save the original size 5629 self.original = size || { 5630 height: this.height, 5631 width: this.width 5632 }; 5633 5634 //self.container.appendChild( this ); 5635 5636 self.cache[ src ] = src; // will override old cache 5637 5638 if (typeof callback == 'function' ) { 5639 window.setTimeout(function() { 5640 callback.call( self, self ); 5641 },1); 5642 } 5643 }; 5644 5645 // Delay the callback to "fix" the Adblock Bug
5646 // http://code.google.com/p/adblockforchrome/issues/detail?id=3701 5647 if ( ( !this.width || !this.height ) ) { 5648 window.setTimeout( (function( img ) { 5649 return function() { 5650 if ( img.width && img.height ) { 5651 complete.call( img ); 5652 } else { 5653 // last resort, this should never happen but just in case it does... 5654 if ( !resort ) { 5655 $(new Image()).load( onload ).attr( 'src', img.src ); 5656 resort = true; 5657 } else { 5658 Galleria.raise('Could not extract width/height from image: ' + img.src + 5659 '. Traced measures: width:' + img.width + 'px, height: ' + img.height + 'px.'); 5660 } 5661 } 5662 }; 5663 }( this )), 2); 5664 } else { 5665 complete.call( this ); 5666 } 5667 }; 5668 }( this, callback, src )); 5669 5670 // remove any previous images 5671 $container.find( 'iframe,img' ).remove(); 5672 5673 // append the image 5674 $image.css( 'display', 'block'); 5675 5676 // hide it for now 5677 Utils.hide( this.image ); 5678 5679 // remove any max/min scaling 5680 $.each('minWidth minHeight maxWidth maxHeight'.split(' '), function(i, prop) { 5681 $image.css(prop, (/min/.test(prop) ? '0' : 'none')); 5682 }); 5683 5684 $container.append( $image ); 5685 // begin load and insert in cache when done 5686 $image.load( onload ).error( onerror ).attr( 'src', src ); 5687 5688 // return the container 5689 return this.container; 5690 }, 5691 5692 /** 5693 Scales and crops the image 5694 5695 @param {Object} options The method takes an object with a number of options: 5696 5697 <ul> 5698 <li>width - width of the container</li> 5699 <li>height - height of the container</li> 5700 <li>min - minimum scale ratio</li> 5701 <li>max - maximum scale ratio</li> 5702 <li>margin - distance in pixels from the image border to the container</li> 5703 <li>complete - a callback that fires when scaling is complete</li> 5704 <li>position - positions the image, works like the css background-image property.</li> 5705 <li>crop - defines how to crop. Can be true, false, 'width' or 'height'</li> 5706 <li>canvas - set to true to try a canvas-based rescale</li> 5707 </ul> 5708 5709 @returns The image container object (jQuery) 5710 */ 5711 5712 scale: function( options ) { 5713 5714 var self = this; 5715 5716 // extend some defaults 5717 options = $.extend({ 5718 width: 0, 5719 height: 0, 5720 min: undef, 5721 max: undef, 5722 margin: 0, 5723 complete: F, 5724 position: 'center', 5725 crop: false, 5726 canvas: false 5727 }, options); 5728 5729 if( this.isIframe ) { 5730 $( this.image ).width( options.width ).height( options.height ).removeAttr( 'width' ).removeAttr( 'height' ); 5731 $( this.container ).width( options.width ).height( options.height) ; 5732 options.complete.call(self, self); 5733 try { 5734 if( this.image.contentWindow ) { 5735 $( this.image.contentWindow ).trigger('resize'); 5736 } 5737 } catch(e) {} 5738 return this.container; 5739 } 5740 5741 // return the element if no image found 5742 if (!this.image) { 5743 return this.container; 5744 } 5745 5746 // store locale variables 5747 var width, 5748 height, 5749 $container = $( self.container ), 5750 data; 5751 5752 // wait for the width/height 5753 Utils.wait({ 5754 until: function() { 5755 width = options.width || 5756 $container.width() || 5757 Utils.parseValue( $container.css('width') ); 5758 5759 height = options.height || 5760 $container.height() || 5761 Utils.parseValue( $container.css('height') ); 5762 5763 return width && height; 5764 }, 5765 success: function() { 5766 5767 // calculate some cropping 5768 var newWidth = ( width - options.margin * 2 ) / self.original.width, 5769 newHeight = ( height - options.margin * 2 ) / self.original.height, 5770 min = Math.min( newWidth, newHeight ), 5771 max = Math.max( newWidth, newHeight ), 5772 cropMap = { 5773 'true' : max, 5774 'width' : newWidth, 5775 'height': newHeight, 5776 'false' : min, 5777 'landscape': self.original.width > self.original.height ? max : min, 5778 'portrait': self.original.width < self.original.height ? max : min 5779 }, 5780 ratio = cropMap[ options.crop.toString() ],
vendor: 5,434 bytes, lines 5781-5958
5781 canvasKey = ''; 5782 5783 // allow maxScaleRatio 5784 if ( options.max ) { 5785 ratio = Math.min( options.max, ratio ); 5786 } 5787 5788 // allow minScaleRatio 5789 if ( options.min ) { 5790 ratio = Math.max( options.min, ratio ); 5791 } 5792 5793 $.each( ['width','height'], function( i, m ) { 5794 $( self.image )[ m ]( self[ m ] = self.image[ m ] = Math.round( self.original[ m ] * ratio ) ); 5795 }); 5796 5797 $( self.container ).width( width ).height( height ); 5798 5799 if ( options.canvas && _canvas ) { 5800 5801 _canvas.elem.width = self.width; 5802 _canvas.elem.height = self.height; 5803 5804 canvasKey = self.image.src + ':' + self.width + 'x' + self.height; 5805 5806 self.image.src = _canvas.cache[ canvasKey ] || (function( key ) { 5807 5808 _canvas.context.drawImage(self.image, 0, 0, self.original.width*ratio, self.original.height*ratio); 5809 5810 try { 5811 5812 data = _canvas.elem.toDataURL(); 5813 _canvas.length += data.length; 5814 _canvas.cache[ key ] = data; 5815 return data; 5816 5817 } catch( e ) { 5818 return self.image.src; 5819 } 5820 5821 }( canvasKey ) ); 5822 5823 } 5824 5825 // calculate image_position 5826 var pos = {}, 5827 mix = {}, 5828 getPosition = function(value, measure, margin) { 5829 var result = 0; 5830 if (/\%/.test(value)) { 5831 var flt = parseInt( value, 10 ) / 100, 5832 m = self.image[ measure ] || $( self.image )[ measure ](); 5833 5834 result = Math.ceil( m * -1 * flt + margin * flt ); 5835 } else { 5836 result = Utils.parseValue( value ); 5837 } 5838 return result; 5839 }, 5840 positionMap = { 5841 'top': { top: 0 }, 5842 'left': { left: 0 }, 5843 'right': { left: '100%' }, 5844 'bottom': { top: '100%' } 5845 }; 5846 5847 $.each( options.position.toLowerCase().split(' '), function( i, value ) { 5848 if ( value === 'center' ) { 5849 value = '50%'; 5850 } 5851 pos[i ? 'top' : 'left'] = value; 5852 }); 5853 5854 $.each( pos, function( i, value ) { 5855 if ( positionMap.hasOwnProperty( value ) ) { 5856 $.extend( mix, positionMap[ value ] ); 5857 } 5858 }); 5859 5860 pos = pos.top ? $.extend( pos, mix ) : mix; 5861 5862 pos = $.extend({ 5863 top: '50%', 5864 left: '50%' 5865 }, pos); 5866 5867 // apply position 5868 $( self.image ).css({ 5869 position : 'absolute', 5870 top : getPosition(pos.top, 'height', height), 5871 left : getPosition(pos.left, 'width', width) 5872 }); 5873 5874 // show the image 5875 self.show(); 5876 5877 // flag ready and call the callback 5878 self.ready = true; 5879 options.complete.call( self, self ); 5880 5881 }, 5882 error: function() { 5883 Galleria.raise('Could not scale image: '+self.image.src); 5884 }, 5885 timeout: 1000 5886 }); 5887 return this; 5888 } 5889}; 5890 5891// our own easings 5892$.extend( $.easing, { 5893 5894 galleria: function (_, t, b, c, d) { 5895 if ((t/=d/2) < 1) { 5896 return c/2*t*t*t + b; 5897 } 5898 return c/2*((t-=2)*t*t + 2) + b; 5899 }, 5900 5901 galleriaIn: function (_, t, b, c, d) { 5902 return c*(t/=d)*t + b; 5903 }, 5904 5905 galleriaOut: function (_, t, b, c, d) { 5906 return -c *(t/=d)*(t-2) + b; 5907 } 5908 5909}); 5910 5911// the plugin initializer 5912$.fn.galleria = function( options ) { 5913 5914 var selector = this.selector; 5915 5916 // try domReady if element not found 5917 if ( !$(this).length ) { 5918 5919 $(function() { 5920 if ( $( selector ).length ) { 5921 5922 // if found on domReady, go ahead 5923 $( selector ).galleria( options ); 5924 5925 } else { 5926 5927 // if not, try fetching the element for 5 secs, then raise a warning. 5928 Galleria.utils.wait({ 5929 until: function() { 5930 return $( selector ).length; 5931 }, 5932 success: function() { 5933 $( selector ).galleria( options ); 5934 }, 5935 error: function() { 5936 Galleria.raise('Init failed: Galleria could not find the element "'+selector+'".'); 5937 }, 5938 timeout: 5000 5939 }); 5940 5941 } 5942 }); 5943 return this; 5944 } 5945 5946 return this.each(function() { 5947 5948 // fail silent if already run 5949 if ( !$.data(this, 'galleria') ) { 5950 $.data( this, 'galleria', new Galleria().init( this, options ) ); 5951 } 5952 }); 5953 5954}; 5955 5956// phew 5957 5958}( jsnThemeClassicjQuery ) );
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.