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