1/* -------------------------------------------------------------------- 2 MaxImage 2.0 (Fullscreen Slideshow for use with jQuery Cycle Plugin) 3 -------------------------------------------------------------------- 4 5 Examples and documentation at: http://www.aaronvanderzwan.com/maximage/2.0/ 6 Copyright (c) 2007-2012 Aaron Vanderzwan 7 Dual licensed under the MIT and GPL licenses. 8 9 NOTES: 10 This plugin is intended to simplify the creation of fullscreen 11 background slideshows. It is intended to be used alongside the 12 jQuery Cycle plugin: 13 http://jquery.malsup.com/cycle/ 14 15 If you simply need a fullscreen background image, please 16 refer to the following document for ways to do this that 17 are much more simple: 18 http://css-tricks.com/perfect-full-page-background-image/ 19 20 If you have any questions please contact Aaron Vanderzwan 21 at http://www.aaronvanderzwan.com/blog/ 22 Documentation at: 23 http://blog.aaronvanderzwan.com/2012/07/maximage-2-0/ 24 25 HISTORY: 26 MaxImage 2.0 is a project first built as jQuery MaxImage Plugin 27 (http://www.aaronvanderzwan.com/maximage/). Once CSS3 came along, 28 the background-size:cover solved the problem MaxImage 29 was intended to solve. However, fully customizable 30 fullscreen slideshows is still fairly complex and I have not 31 found any helpers for integrating with the jQuery Cycle Plugin. 32 MaxCycle is intended to solve this problem. 33 34 TABLE OF CONTENTS: 35 @Modern 36 @setup 37 @resize 38 @preload 39 @Old 40 @setup 41 @preload 42 @onceloaded 43 @maximage 44 @windowresize 45 @doneresizing 46 @Cycle 47 @setup 48 @Adjust 49 @center 50 @fill 51 @maxcover 52 @maxcontain 53 @Utils 54 @browser_tests 55 @construct_slide_object 56 @sizes 57 @modern_browser 58 @debug 59 60*/ 61/*! 62 * Maximage Version: 2.0.8 (16-Jan-2012) - http://www.aaronvanderzwan.com/maximage/2.0/ 63 */ 64 65 66 67(function ($) { 68 "use strict"; 69 $.fn.maximage = function (settings, helperSettings) { 70 71 var config; 72 73 if (typeof settings == 'object' || settings === undefined) config = $.extend( $.fn.maximage.defaults, settings || {} ); 74 if (typeof settings == 'string') config = $.fn.maximage.defaults; 75 76 /*jslint browser: true*/ 77 $.Body = $('body'); 78 $.Window = $(window); 79 $.Scroll = $('html, body'); 80 $.Events = { 81 RESIZE: 'resize' 82 }; 83 84 this.each(function() { 85 var $self = $(this), 86 preload_count = 0, 87 imageCache = []; 88 89 /* --------------------- */ 90 91 // @Modern 92 93 /* 94 MODERN BROWSER NOTES: 95 Modern browsers have CSS3 background-size option so we setup the DOM to be the following structure for cycle plugin: 96 div = cycle 97 div = slide with background-size:cover 98 div = slide with background-size:cover 99 etc. 100 */ 101 102 var Modern = { 103 setup: function(){ 104 if($.Slides.length > 0){ 105 var i, 106 len = $.Slides.length; 107 108 // Setup images 109 for(i=0; i < len; i++) { 110 // Set our image 111 var $img = $.Slides[i]; 112 113 // Create a div with a background image so we can use CSS3's position cover (for modern browsers) 114 $self.append('<div class="mc-image ' + $img.theclass + '" title="' + $img.alt + '" style="background-image:url(\'' + $img.url + '\');' + $img.style + '" data-href="'+ $img.datahref +'">'+ $img.content +'</div>'); 115 } 116 117 // Begin our preload process (increments itself after load) 118 Modern.preload(0); 119 120 // If using Cycle, this resets the height and width of each div to always fill the window; otherwise can be done with CSS 121 Modern.resize(); 122 } 123 }, 124 preload: function(n){ 125 // Preload all of the images but never show them, just use their completion so we know that they are done 126 // and so that the browser can cache them / fade them in smoothly 127 128 // Create new image object 129 var $img = $('<img/>'); 130 $img.load(function() { 131 // Once the first image has completed loading, start the slideshow, etc. 132 if(preload_count==0) { 133 // Only start cycle after first image has loaded 134 Cycle.setup(); 135 136 // Run user defined onFirstImageLoaded() function 137 config.onFirstImageLoaded(); 138 } 139 140 // preload_count starts with 0, $.Slides.length starts with 1 141 if(preload_count==($.Slides.length-1)) { 142 // If we have just loaded the final image, run the user defined function onImagesLoaded() 143 config.onImagesLoaded( $self ); 144 }else{ 145 // Increment the counter 146 preload_count++; 147 148 // Load the next image 149 Modern.preload(preload_count); 150 } 151 }); 152 153 // Set the src... this triggers begin of load 154 $img[0].src = $.Slides[n].url; 155 156 // Push to external array to avoid cleanup by aggressive garbage collectors 157 imageCache.push($img[0]); 158 }, 159 resize: function(){ 160 // Cycle sets the height of each slide so when we resize our browser window this becomes a problem. 161 // - the cycle option 'slideResize' has to be set to false otherwise it will trump our resize 162 $.Window 163 .bind($.Events.RESIZE, 164 function(){ 165 // Remove scrollbars so we can take propper measurements 166 $.Scroll.addClass('mc-hide-scrolls'); 167 168 // Set vars so we don't have to constantly check it
169 $.Window 170 .data('h', Utils.sizes().h) 171 .data('w', Utils.sizes().w); 172 173 // Set container and slides height and width to match the window size 174 $self 175 .height($.Window.data('h')).width($.Window.data('w')) 176 .children() 177 .height($.Window.data('h')).width($.Window.data('w')); 178 179 // This is special noise for cycle (cycle has separate height and width for each slide) 180 $self.children().each(function(){ 181 this.cycleH = $.Window.data('h'); 182 this.cycleW = $.Window.data('w'); 183 }); 184 185 // Put the scrollbars back to how they were 186 $($.Scroll).removeClass('mc-hide-scrolls'); 187 }); 188 } 189 } 190 191 192 193 /* --------------------- */ 194 195 // @Old 196 197 /* 198 OLD BROWSER NOTES: 199 We setup the dom to be the following structure for cycle plugin on old browsers: 200 div = cycle 201 div = slide 202 img = full screen size image 203 div = slide 204 img = full screen size image 205 etc. 206 */ 207 208 var Old = { 209 setup: function(){ 210 var c, t, $div, j, slideLen = $.Slides.length; 211 212 // Clear container 213 if($.BrowserTests.msie && !config.overrideMSIEStop){ 214 // Stop IE from continually trying to preload images that we already removed 215 document.execCommand("Stop", false); 216 } 217 $self.html(''); 218 219 $.Body.addClass('mc-old-browser'); 220 221 if($.Slides.length > 0){ 222 // Remove scrollbars so we can take propper measurements 223 $.Scroll.addClass('mc-hide-scrolls'); 224 225 // Cache our new dimensions 226 $.Window 227 .data('h', Utils.sizes().h) 228 .data('w', Utils.sizes().w); 229 230 // Add our loading div to the DOM 231 $('body').append($("<div></div>").attr("class", "mc-loader").css({'position':'absolute','left':'-9999px'})); 232 233 // Loop through slides 234 for(j = 0; j < slideLen; j++) { 235 // Determine content (if container or image) 236 if($.Slides[j].content.length == 0){ 237 c = '<img src="' + $.Slides[j].url + '" />'; 238 }else{ 239 c = $.Slides[j].content; 240 } 241 242 // Create Div 243 $div = $("<div>" + c + "</div>").attr("class", "mc-image mc-image-n" + j + " " + $.Slides[j].theclass); 244 245 // Add new container div to the DOM 246 $self.append( $div ); 247 248 // Account for slides without images 249 if($('.mc-image-n' + j).children('img').length == 0){ 250 }else{ 251 // Add first image to loader to get that started 252 $('div.mc-loader').append( $('.mc-image-n' + j).children('img').first().clone().addClass('not-loaded') ); 253 } 254 } 255 256 // Begin preloading 257 Old.preload(); 258 259 // Setup the resize function to listen for window changes 260 Old.windowResize(); 261 } 262 }, 263 preload: function(){ 264 // Intervals to tell if an images have loaded 265 var t = setInterval(function() { 266 $('.mc-loader').children('img').each(function(i){ 267 // Check if image is loaded 268 var $img = $(this); 269 270 // Loop through not-loaded images 271 if($img.hasClass('not-loaded')){ 272 if( $img.height() > 0 ){ 273 // Remove Dom notice 274 $(this).removeClass('not-loaded'); 275 276 // Set the dimensions 277 var $img1 = $('div.mc-image-n' + i).children('img').first(); 278 279 $img1 280 .data('h', $img.height()) 281 .data('w', $img.width()) 282 .data('ar', ($img.width() / $img.height())); 283 284 // Go on 285 Old.onceLoaded(i) 286 } 287 } 288 }); 289 290 if( $('.not-loaded').length == 0){ 291 // Remove our loader element because all of our images are now loaded 292 $('.mc-loader').remove(); 293 294 // Clear interval when all images are loaded 295 clearInterval(t); 296 } 297 }, 1000); 298 }, 299 onceLoaded: function(m){ 300 // Do maximage magic 301 Old.maximage(m); 302 303 // Once the first image has completed loading, start the slideshow, etc. 304 if(m == 0) { 305 // If we changed the visibility before, make sure it is back on 306 $self.css({'visibility':'visible'}); 307 308 // Run user defined onFirstImageLoaded() function 309 config.onFirstImageLoaded(); 310 311 // After everything is done loading, clean up 312 }else if(m == $.Slides.length - 1){ 313 // Only start cycle after the first image has loaded 314 Cycle.setup(); 315 316 // Put the scrollbars back to how they were 317 $($.Scroll).removeClass('mc-hide-scrolls'); 318 319 // If we have just loaded the final image, run the user defined function onImagesLoaded() 320 config.onImagesLoaded( $self ); 321 322 if(config.debug) { 323 debug(' - Final Maximage - ');debug($self); 324 } 325 } 326 }, 327 maximage: function(p){ 328 // Cycle sets the height of each slide so when we resize our browser window this becomes a problem. 329 // - the cycle option 'slideResize' has to be set to false otherwise it will trump our resize 330 $('div.mc-image-n' + p) 331 .height($.Window.data('h')) 332 .width($.Window.data('w')) 333 .children('img') 334 .first() 335 .each(function(){ 336 Adjust.maxcover($(this)); 337 }); 338 }, 339 windowResize: function(){ 340 $.Window 341 .bind($.Events.RESIZE, 342 function(){
343 clearTimeout(this.id); 344 345 if($('.mc-image').length >= 1){ 346 this.id = setTimeout(Old.doneResizing, 200); 347 } 348 }); 349 }, 350 doneResizing: function(){ 351 // The final resize (on finish) 352 // Remove scrollbars so we can take propper measurements 353 $($.Scroll).addClass('mc-hide-scrolls'); 354 355 // Cache our window's new dimensions 356 $.Window 357 .data('h', Utils.sizes().h) 358 .data('w', Utils.sizes().w); 359 360 // Set the container's height and width 361 $self.height($.Window.data('h')).width($.Window.data('w')) 362 363 // Set slide's height and width to match the window size 364 $self.find('.mc-image').each(function(n){ 365 Old.maximage(n); 366 }); 367 368 // Update cycle's ideas of what our slide's height and width should be 369 var curr_opts = $self.data('cycle.opts'); 370 if(curr_opts != undefined){ 371 curr_opts.height = $.Window.data('h'); 372 curr_opts.width = $.Window.data('w'); 373 jQuery.each(curr_opts.elements, function(index, item) { 374 item.cycleW = $.Window.data('w'); 375 item.cycleH = $.Window.data('h'); 376 }); 377 } 378 379 // Put the scrollbars back to how they were 380 $($.Scroll).removeClass('mc-hide-scrolls'); 381 } 382 } 383 384 385 /* --------------------- */ 386 387 // @Cycle 388 389 var Cycle = { 390 setup: function(){ 391 var h,w; 392 393 $self.addClass('mc-cycle'); 394 395 // Container sizes (if not set) 396 $.Window 397 .data('h', Utils.sizes().h) 398 .data('w', Utils.sizes().w); 399 400 // Prefer CSS Transitions 401 jQuery.easing.easeForCSSTransition = function(x, t, b, c, d, s) { 402 return b+c; 403 }; 404 405 var cycleOptions = $.extend({ 406 fit:1, 407 containerResize:0, 408 height:$.Window.data('h'), 409 width:$.Window.data('w'), 410 slideResize: false, 411 easing: ($.BrowserTests.cssTransitions && config.cssTransitions ? 'easeForCSSTransition' : 'swing') 412 }, config.cycleOptions); 413 414 $self.cycle( cycleOptions ); 415 } 416 } 417 418 419 420 /* --------------------- */ 421 422 // @Adjust = Math to center and fill all elements 423 424 var Adjust = { 425 center: function($item){ 426 // Note: if alignment is 'left' or 'right' it can be controlled with CSS once verticalCenter 427 // and horizontal center are set to false in the plugin options 428 if(config.verticalCenter){ 429 $item.css({marginTop:(($item.height() - $.Window.data('h'))/2) * -1}) 430 } 431 if(config.horizontalCenter){ 432 $item.css({marginLeft:(($item.width() - $.Window.data('w'))/2) * -1}); 433 } 434 }, 435 fill: function($item){ 436 var $storageEl = $item.is('object') ? $item.parent().first() : $item; 437 438 if(typeof config.backgroundSize == 'function'){ 439 // If someone wants to write their own fill() function, they can: example customBackgroundSize.html 440 config.backgroundSize( $item ); 441 }else if(config.backgroundSize == 'cover'){ 442 if($.Window.data('w') / $.Window.data('h') < $storageEl.data('ar')){ 443 $item 444 .height($.Window.data('h')) 445 .width(($.Window.data('h') * $storageEl.data('ar')).toFixed(0)); 446 }else{ 447 $item 448 .height(($.Window.data('w') / $storageEl.data('ar')).toFixed(0)) 449 .width($.Window.data('w')); 450 } 451 }else if(config.backgroundSize == 'contain'){ 452 if($.Window.data('w') / $.Window.data('h') < $storageEl.data('ar')){ 453 $item 454 .height(($.Window.data('w') / $storageEl.data('ar')).toFixed(0)) 455 .width($.Window.data('w')); 456 }else{ 457 $item 458 .height($.Window.data('h')) 459 .width(($.Window.data('h') * $storageEl.data('ar')).toFixed(0)); 460 } 461 }else{ 462 debug('The backgroundSize option was not recognized for older browsers.'); 463 } 464 }, 465 maxcover: function($item){ 466 Adjust.fill($item); 467 Adjust.center($item); 468 }, 469 maxcontain: function($item){ 470 Adjust.fill($item); 471 Adjust.center($item); 472 } 473 } 474 475 476 477 /* --------------------- */ 478 479 // @Utils = General utilities for the plugin 480 481 var Utils = { 482 browser_tests: function(){
483 var $div = $('<div />')[0], 484 vendor = ['Moz', 'Webkit', 'Khtml', 'O', 'ms'], 485 p = 'transition', 486 obj = { 487 cssTransitions: false, 488 cssBackgroundSize: ( "backgroundSize" in $div.style && config.cssBackgroundSize ), // Can override cssBackgroundSize in options 489 html5Video: false, 490 msie: false 491 }; 492 493 // Test for CSS Transitions 494 if(config.cssTransitions){ 495 if(typeof $div.style[p] == 'string') { obj.cssTransitions = true } 496 497 // Tests for vendor specific prop 498 p = p.charAt(0).toUpperCase() + p.substr(1); 499 for(var i=0; i<vendor.length; i++) { 500 if(vendor[i] + p in $div.style) { obj.cssTransitions = true; } 501 } 502 } 503 504 // Check if we can play html5 videos 505 if( !!document.createElement('video').canPlayType ) { 506 obj.html5Video = true; 507 } 508 509 // Check for MSIE since we lost $.browser in jQuery 510 obj.msie = (Utils.msie() !== undefined); 511 512 513 if(config.debug) { 514 debug(' - Browser Test - ');debug(obj); 515 } 516 517 return obj; 518 }, 519 construct_slide_object: function(){ 520 var obj = new Object(), 521 arr = new Array(), 522 temp = ''; 523 524 $self.children().each(function(i){ 525 var $img = $(this).is('img') ? $(this).clone() : $(this).find('img').first().clone(); 526 527 // reset obj 528 obj = {}; 529 530 // set attributes to obj 531 obj.url = $img.attr('src'); 532 obj.title = $img.attr('title') != undefined ? $img.attr('title') : ''; 533 obj.alt = $img.attr('alt') != undefined ? $img.attr('alt') : ''; 534 obj.theclass = $img.attr('class') != undefined ? $img.attr('class') : ''; 535 obj.styles = $img.attr('style') != undefined ? $img.attr('style') : ''; 536 obj.orig = $img.clone(); 537 obj.datahref = $img.attr('data-href') != undefined ? $img.attr('data-href') : ''; 538 obj.content = ""; 539 540 // Setup content for within container 541 if($(this).find('img').length > 0){ 542 if($.BrowserTests.cssBackgroundSize){ 543 $(this).find('img').first().remove(); 544 } 545 obj.content = $(this).html(); 546 } 547 548 // Stop loading image so we can load them sequentiallyelse{ 549 $img[0].src = ""; 550 551 // Remove original object (only on nonIE. IE hangs if you remove an image during load) 552 if($.BrowserTests.cssBackgroundSize){ 553 $(this).remove(); 554 } 555 556 // attach obj to arr 557 arr.push(obj); 558 }); 559 560 561 if(config.debug) { 562 debug(' - Slide Object - ');debug(arr); 563 } 564 return arr; 565 }, 566 msie: function(){ 567 var undef, 568 v = 3, 569 div = document.createElement('div'), 570 all = div.getElementsByTagName('i'); 571 572 while ( 573 div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->', 574 all[0] 575 ); 576 577 return v > 4 ? v : undef; 578 }, 579 sizes: function(){ 580 var sizes = {h:0,w:0}; 581 582 if(config.fillElement == "window"){ 583 sizes.h = $.Window.height(); 584 sizes.w = $.Window.width(); 585 }else{ 586 var $fillElement = $self.parents(config.fillElement).first(); 587 588 // Height 589 if($fillElement.height() == 0 || $fillElement.data('windowHeight') == true){ 590 $fillElement.data('windowHeight',true); 591 sizes.h = $.Window.height(); 592 }else{ 593 sizes.h = $fillElement.height(); 594 } 595 596 // Width 597 if($fillElement.width() == 0 || $fillElement.data('windowWidth') == true){ 598 $fillElement.data('windowWidth',true); 599 sizes.w = $.Window.width(); 600 }else{ 601 sizes.w = $fillElement.width(); 602 } 603 } 604 605 return sizes; 606 } 607 } 608 609 610 611 /* --------------------- */ 612 613 // @Instantiation 614 615 // Helper Function 616 // Run tests to see what our browser can handle 617 $.BrowserTests = Utils.browser_tests(); 618 619 if(typeof settings == 'string'){ 620 // TODO: Resize object fallback for old browsers, If we are trying to size an HTML5 video and our browser doesn't support it 621 if($.BrowserTests.html5Video || !$self.is('video')) { 622 var to, 623 $storageEl = $self.is('object') ? $self.parent().first() : $self; // Can't assign .data() to '<object>' 624 625 if( !$.Body.hasClass('mc-old-browser') ) 626 $.Body.addClass('mc-old-browser'); 627 628 // Cache our window's new dimensions 629 $.Window 630 .data('h', Utils.sizes().h) 631 .data('w', Utils.sizes().w); 632 633 // Please include height and width attributes on your html elements 634 $storageEl 635 .data('h', $self.height()) 636 .data('w', $self.width()) 637 .data('ar', $self.width() / $self.height()); 638 639 // We want to resize these elements with the window 640 $.Window 641 .bind($.Events.RESIZE, 642 function(){ 643 // Cache our window's new dimensions 644 $.Window 645 .data('h', Utils.sizes().h) 646 .data('w', Utils.sizes().w); 647 648 // Limit resize runs 649 to = $self.data('resizer'); 650 clearTimeout(to); 651 to = setTimeout( Adjust[settings]($self), 200 ); 652 $self.data('resizer', to); 653 }); 654 655 // Initial run 656 Adjust[settings]($self); 657 } 658 }else{ 659 // Construct array of image objects for us to use 660 $.Slides = Utils.construct_slide_object(); 661 662 // If we are allowing background-size:cover run Modern
663 if($.BrowserTests.cssBackgroundSize){ 664 if(config.debug) debug(' - Using Modern - '); 665 Modern.setup(); 666 }else{ 667 if(config.debug) debug(' - Using Old - '); 668 Old.setup(); 669 } 670 } 671 }); 672 673 // private function for debugging 674 function debug($obj) { 675 if (window.console && window.console.log) { 676 window.console.log($obj); 677 } 678 } 679 } 680 681 // Default options 682 $.fn.maximage.defaults = { 683 debug: false, 684 cssBackgroundSize: true, // Force run the functionality used for newer browsers 685 cssTransitions: true, // Force run the functionality used for old browsers 686 verticalCenter: true, // Only necessary for old browsers 687 horizontalCenter: true, // Only necessary for old browsers 688 scaleInterval: 20, // Only necessary for old browsers 689 backgroundSize: 'cover', // Only necessary for old browsers (this can be function) 690 fillElement: 'window', // Either 'window' or a CSS selector for a parent element 691 overrideMSIEStop: false, // This gives the option to not 'stop' load for MSIE (stops coded background images from loading so we can preload)... 692 // If setting this option to true, please beware of IE7/8 "Stack Overflow" error but if there are more than 13 slides 693 // The description of the bug: http://blog.aaronvanderzwan.com/forums/topic/stack-overflow-in-ie-7-8/#post-33038 694 onFirstImageLoaded: function(){}, 695 onImagesLoaded: function(){} 696 } 697})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.