Template:Peking/Javascript/jquery maximage

/* -------------------------------------------------------------------- MaxImage 2.0 (Fullscreen Slideshow for use with jQuery Cycle Plugin) --------------------------------------------------------------------

Examples and documentation at: http://www.aaronvanderzwan.com/maximage/2.0/ Copyright (c) 2007-2012 Aaron Vanderzwan Dual licensed under the MIT and GPL licenses.

NOTES: This plugin is intended to simplify the creation of fullscreen background slideshows. It is intended to be used alongside the jQuery Cycle plugin: http://jquery.malsup.com/cycle/

If you simply need a fullscreen background image, please refer to the following document for ways to do this that are much more simple: http://css-tricks.com/perfect-full-page-background-image/

If you have any questions please contact Aaron Vanderzwan at http://www.aaronvanderzwan.com/blog/ Documentation at: http://blog.aaronvanderzwan.com/2012/07/maximage-2-0/

HISTORY: MaxImage 2.0 is a project first built as jQuery MaxImage Plugin (http://www.aaronvanderzwan.com/maximage/). Once CSS3 came along, the background-size:cover solved the problem MaxImage was intended to solve. However, fully customizable fullscreen slideshows is still fairly complex and I have not found any helpers for integrating with the jQuery Cycle Plugin. MaxCycle is intended to solve this problem.

TABLE OF CONTENTS: @Modern @setup @resize @preload @Old @setup @preload @onceloaded @maximage @windowresize @doneresizing @Cycle @setup @Adjust @center @fill @maxcover @maxcontain @Utils @browser_tests @construct_slide_object @sizes @modern_browser @debug

  • /

/*!

* Maximage Version: 2.0.8 (16-Jan-2012) - http://www.aaronvanderzwan.com/maximage/2.0/
*/


(function ($) { "use strict"; $.fn.maximage = function (settings, helperSettings) {

var config;

if (typeof settings == 'object' || settings === undefined) config = $.extend( $.fn.maximage.defaults, settings || {} ); if (typeof settings == 'string') config = $.fn.maximage.defaults;

/*jslint browser: true*/ $.Body = $('body'); $.Window = $(window); $.Scroll = $('html, body'); $.Events = { RESIZE: 'resize' };

this.each(function() { var $self = $(this), preload_count = 0, imageCache = [];

/* --------------------- */

// @Modern

/* MODERN BROWSER NOTES: Modern browsers have CSS3 background-size option so we setup the DOM to be the following structure for cycle plugin: div = cycle div = slide with background-size:cover div = slide with background-size:cover etc. */

var Modern = { setup: function(){ if($.Slides.length > 0){ var i, len = $.Slides.length;

// Setup images for(i=0; i < len; i++) { // Set our image var $img = $.Slides[i];

// Create a div with a background image so we can use CSS3's position cover (for modern browsers)

$self.append('
'+ $img.content +'
');

}

// Begin our preload process (increments itself after load) Modern.preload(0);

// If using Cycle, this resets the height and width of each div to always fill the window; otherwise can be done with CSS Modern.resize(); } }, preload: function(n){ // Preload all of the images but never show them, just use their completion so we know that they are done // and so that the browser can cache them / fade them in smoothly

// Create new image object var $img = $('<img/>'); $img.load(function() { // Once the first image has completed loading, start the slideshow, etc. if(preload_count==0) { // Only start cycle after first image has loaded Cycle.setup();

// Run user defined onFirstImageLoaded() function config.onFirstImageLoaded(); }

// preload_count starts with 0, $.Slides.length starts with 1 if(preload_count==($.Slides.length-1)) { // If we have just loaded the final image, run the user defined function onImagesLoaded() config.onImagesLoaded( $self ); }else{ // Increment the counter preload_count++;

// Load the next image Modern.preload(preload_count); } });

// Set the src... this triggers begin of load $img[0].src = $.Slides[n].url;

// Push to external array to avoid cleanup by aggressive garbage collectors imageCache.push($img[0]); }, resize: function(){ // Cycle sets the height of each slide so when we resize our browser window this becomes a problem. // - the cycle option 'slideResize' has to be set to false otherwise it will trump our resize $.Window .bind($.Events.RESIZE, function(){ // Remove scrollbars so we can take propper measurements $.Scroll.addClass('mc-hide-scrolls');

// Set vars so we don't have to constantly check it $.Window .data('h', Utils.sizes().h) .data('w', Utils.sizes().w);

// Set container and slides height and width to match the window size $self .height($.Window.data('h')).width($.Window.data('w')) .children() .height($.Window.data('h')).width($.Window.data('w'));

// This is special noise for cycle (cycle has separate height and width for each slide) $self.children().each(function(){ this.cycleH = $.Window.data('h'); this.cycleW = $.Window.data('w'); });

// Put the scrollbars back to how they were $($.Scroll).removeClass('mc-hide-scrolls'); }); } }


/* --------------------- */

// @Old

/* OLD BROWSER NOTES: We setup the dom to be the following structure for cycle plugin on old browsers: div = cycle div = slide img = full screen size image div = slide img = full screen size image etc. */

var Old = { setup: function(){ var c, t, $div, j, slideLen = $.Slides.length;

// Clear container if($.BrowserTests.msie && !config.overrideMSIEStop){ // Stop IE from continually trying to preload images that we already removed document.execCommand("Stop", false); } $self.html();

$.Body.addClass('mc-old-browser');

if($.Slides.length > 0){ // Remove scrollbars so we can take propper measurements $.Scroll.addClass('mc-hide-scrolls');

// Cache our new dimensions $.Window .data('h', Utils.sizes().h) .data('w', Utils.sizes().w);

// Add our loading div to the DOM

$('body').append($("
").attr("class", "mc-loader").css({'position':'absolute','left':'-9999px'}));

// Loop through slides for(j = 0; j < slideLen; j++) { // Determine content (if container or image) if($.Slides[j].content.length == 0){ c = '<img src="' + $.Slides[j].url + '" />'; }else{ c = $.Slides[j].content; }

// Create Div

$div = $("
" + c + "
").attr("class", "mc-image mc-image-n" + j + " " + $.Slides[j].theclass);

// Add new container div to the DOM $self.append( $div );

// Account for slides without images if($('.mc-image-n' + j).children('img').length == 0){ }else{ // Add first image to loader to get that started $('div.mc-loader').append( $('.mc-image-n' + j).children('img').first().clone().addClass('not-loaded') ); } }

// Begin preloading Old.preload();

// Setup the resize function to listen for window changes Old.windowResize(); } }, preload: function(){ // Intervals to tell if an images have loaded var t = setInterval(function() { $('.mc-loader').children('img').each(function(i){ // Check if image is loaded var $img = $(this);

// Loop through not-loaded images if($img.hasClass('not-loaded')){ if( $img.height() > 0 ){ // Remove Dom notice $(this).removeClass('not-loaded');

// Set the dimensions var $img1 = $('div.mc-image-n' + i).children('img').first();

$img1 .data('h', $img.height()) .data('w', $img.width()) .data('ar', ($img.width() / $img.height()));

// Go on Old.onceLoaded(i) } } });

if( $('.not-loaded').length == 0){ // Remove our loader element because all of our images are now loaded $('.mc-loader').remove();

// Clear interval when all images are loaded clearInterval(t); } }, 1000); }, onceLoaded: function(m){ // Do maximage magic Old.maximage(m);

// Once the first image has completed loading, start the slideshow, etc. if(m == 0) { // If we changed the visibility before, make sure it is back on $self.css({'visibility':'visible'});

// Run user defined onFirstImageLoaded() function config.onFirstImageLoaded();

// After everything is done loading, clean up }else if(m == $.Slides.length - 1){ // Only start cycle after the first image has loaded Cycle.setup();

// Put the scrollbars back to how they were $($.Scroll).removeClass('mc-hide-scrolls');

// If we have just loaded the final image, run the user defined function onImagesLoaded() config.onImagesLoaded( $self );

if(config.debug) { debug(' - Final Maximage - ');debug($self); } } }, maximage: function(p){ // Cycle sets the height of each slide so when we resize our browser window this becomes a problem. // - the cycle option 'slideResize' has to be set to false otherwise it will trump our resize $('div.mc-image-n' + p) .height($.Window.data('h')) .width($.Window.data('w')) .children('img') .first() .each(function(){ Adjust.maxcover($(this)); }); }, windowResize: function(){ $.Window .bind($.Events.RESIZE, function(){ clearTimeout(this.id);

if($('.mc-image').length >= 1){ this.id = setTimeout(Old.doneResizing, 200); } }); }, doneResizing: function(){ // The final resize (on finish) // Remove scrollbars so we can take propper measurements $($.Scroll).addClass('mc-hide-scrolls');

// Cache our window's new dimensions $.Window .data('h', Utils.sizes().h) .data('w', Utils.sizes().w);

// Set the container's height and width $self.height($.Window.data('h')).width($.Window.data('w'))

// Set slide's height and width to match the window size $self.find('.mc-image').each(function(n){ Old.maximage(n); });

// Update cycle's ideas of what our slide's height and width should be var curr_opts = $self.data('cycle.opts'); if(curr_opts != undefined){ curr_opts.height = $.Window.data('h'); curr_opts.width = $.Window.data('w'); jQuery.each(curr_opts.elements, function(index, item) { item.cycleW = $.Window.data('w'); item.cycleH = $.Window.data('h'); }); }

// Put the scrollbars back to how they were $($.Scroll).removeClass('mc-hide-scrolls'); } }


/* --------------------- */

// @Cycle

var Cycle = { setup: function(){ var h,w;

$self.addClass('mc-cycle');

// Container sizes (if not set) $.Window .data('h', Utils.sizes().h) .data('w', Utils.sizes().w);

// Prefer CSS Transitions jQuery.easing.easeForCSSTransition = function(x, t, b, c, d, s) { return b+c; };

var cycleOptions = $.extend({ fit:1, containerResize:0, height:$.Window.data('h'), width:$.Window.data('w'), slideResize: false, easing: ($.BrowserTests.cssTransitions && config.cssTransitions ? 'easeForCSSTransition' : 'swing') }, config.cycleOptions);

$self.cycle( cycleOptions ); } }


/* --------------------- */

// @Adjust = Math to center and fill all elements

var Adjust = { center: function($item){ // Note: if alignment is 'left' or 'right' it can be controlled with CSS once verticalCenter // and horizontal center are set to false in the plugin options if(config.verticalCenter){ $item.css({marginTop:(($item.height() - $.Window.data('h'))/2) * -1}) } if(config.horizontalCenter){ $item.css({marginLeft:(($item.width() - $.Window.data('w'))/2) * -1}); } }, fill: function($item){ var $storageEl = $item.is('object') ? $item.parent().first() : $item;

if(typeof config.backgroundSize == 'function'){ // If someone wants to write their own fill() function, they can: example customBackgroundSize.html config.backgroundSize( $item ); }else if(config.backgroundSize == 'cover'){ if($.Window.data('w') / $.Window.data('h') < $storageEl.data('ar')){ $item .height($.Window.data('h')) .width(($.Window.data('h') * $storageEl.data('ar')).toFixed(0)); }else{ $item .height(($.Window.data('w') / $storageEl.data('ar')).toFixed(0)) .width($.Window.data('w')); } }else if(config.backgroundSize == 'contain'){ if($.Window.data('w') / $.Window.data('h') < $storageEl.data('ar')){ $item .height(($.Window.data('w') / $storageEl.data('ar')).toFixed(0)) .width($.Window.data('w')); }else{ $item .height($.Window.data('h')) .width(($.Window.data('h') * $storageEl.data('ar')).toFixed(0)); } }else{ debug('The backgroundSize option was not recognized for older browsers.'); } }, maxcover: function($item){ Adjust.fill($item); Adjust.center($item); }, maxcontain: function($item){ Adjust.fill($item); Adjust.center($item); } }


/* --------------------- */

// @Utils = General utilities for the plugin

var Utils = { browser_tests: function(){ var $div = $('<div />')[0], vendor = ['Moz', 'Webkit', 'Khtml', 'O', 'ms'], p = 'transition', obj = { cssTransitions: false, cssBackgroundSize: ( "backgroundSize" in $div.style && config.cssBackgroundSize ), // Can override cssBackgroundSize in options html5Video: false, msie: false };

// Test for CSS Transitions if(config.cssTransitions){ if(typeof $div.style[p] == 'string') { obj.cssTransitions = true }

// Tests for vendor specific prop p = p.charAt(0).toUpperCase() + p.substr(1); for(var i=0; i<vendor.length; i++) { if(vendor[i] + p in $div.style) { obj.cssTransitions = true; } } }

// Check if we can play html5 videos if( !!document.createElement('video').canPlayType ) { obj.html5Video = true; }

// Check for MSIE since we lost $.browser in jQuery obj.msie = (Utils.msie() !== undefined);


if(config.debug) { debug(' - Browser Test - ');debug(obj); }

return obj; }, construct_slide_object: function(){ var obj = new Object(), arr = new Array(), temp = ;

$self.children().each(function(i){ var $img = $(this).is('img') ? $(this).clone() : $(this).find('img').first().clone();

// reset obj obj = {};

// set attributes to obj obj.url = $img.attr('src'); obj.title = $img.attr('title') != undefined ? $img.attr('title') : ; obj.alt = $img.attr('alt') != undefined ? $img.attr('alt') : ; obj.theclass = $img.attr('class') != undefined ? $img.attr('class') : ; obj.styles = $img.attr('style') != undefined ? $img.attr('style') : ; obj.orig = $img.clone(); obj.datahref = $img.attr('data-href') != undefined ? $img.attr('data-href') : ; obj.content = "";

// Setup content for within container if($(this).find('img').length > 0){ if($.BrowserTests.cssBackgroundSize){ $(this).find('img').first().remove(); } obj.content = $(this).html(); }

// Stop loading image so we can load them sequentiallyelse{ $img[0].src = "";

// Remove original object (only on nonIE. IE hangs if you remove an image during load) if($.BrowserTests.cssBackgroundSize){ $(this).remove(); }

// attach obj to arr arr.push(obj); });


if(config.debug) { debug(' - Slide Object - ');debug(arr); } return arr; }, msie: function(){ var undef, v = 3, div = document.createElement('div'), all = div.getElementsByTagName('i');

while ( div.innerHTML = , all[0] );

return v > 4 ? v : undef; }, sizes: function(){ var sizes = {h:0,w:0};

if(config.fillElement == "window"){ sizes.h = $.Window.height(); sizes.w = $.Window.width(); }else{ var $fillElement = $self.parents(config.fillElement).first();

// Height if($fillElement.height() == 0 || $fillElement.data('windowHeight') == true){ $fillElement.data('windowHeight',true); sizes.h = $.Window.height(); }else{ sizes.h = $fillElement.height(); }

// Width if($fillElement.width() == 0 || $fillElement.data('windowWidth') == true){ $fillElement.data('windowWidth',true); sizes.w = $.Window.width(); }else{ sizes.w = $fillElement.width(); } }

return sizes; } }


/* --------------------- */

// @Instantiation

// Helper Function // Run tests to see what our browser can handle $.BrowserTests = Utils.browser_tests();

if(typeof settings == 'string'){ // TODO: Resize object fallback for old browsers, If we are trying to size an HTML5 video and our browser doesn't support it if($.BrowserTests.html5Video || !$self.is('video')) { var to, $storageEl = $self.is('object') ? $self.parent().first() : $self; // Can't assign .data() to '<object>'

if( !$.Body.hasClass('mc-old-browser') ) $.Body.addClass('mc-old-browser');

// Cache our window's new dimensions $.Window .data('h', Utils.sizes().h) .data('w', Utils.sizes().w);

// Please include height and width attributes on your html elements $storageEl .data('h', $self.height()) .data('w', $self.width()) .data('ar', $self.width() / $self.height());

// We want to resize these elements with the window $.Window .bind($.Events.RESIZE, function(){ // Cache our window's new dimensions $.Window .data('h', Utils.sizes().h) .data('w', Utils.sizes().w);

// Limit resize runs to = $self.data('resizer'); clearTimeout(to); to = setTimeout( Adjust[settings]($self), 200 ); $self.data('resizer', to); });

// Initial run Adjust[settings]($self); } }else{ // Construct array of image objects for us to use $.Slides = Utils.construct_slide_object();

// If we are allowing background-size:cover run Modern if($.BrowserTests.cssBackgroundSize){ if(config.debug) debug(' - Using Modern - '); Modern.setup(); }else{ if(config.debug) debug(' - Using Old - '); Old.setup(); } } });

// private function for debugging function debug($obj) { if (window.console && window.console.log) { window.console.log($obj); } } }

// Default options $.fn.maximage.defaults = { debug: false, cssBackgroundSize: true, // Force run the functionality used for newer browsers cssTransitions: true, // Force run the functionality used for old browsers verticalCenter: true, // Only necessary for old browsers horizontalCenter: true, // Only necessary for old browsers scaleInterval: 20, // Only necessary for old browsers backgroundSize: 'cover', // Only necessary for old browsers (this can be function) fillElement: 'window', // Either 'window' or a CSS selector for a parent element overrideMSIEStop: false, // This gives the option to not 'stop' load for MSIE (stops coded background images from loading so we can preload)... // If setting this option to true, please beware of IE7/8 "Stack Overflow" error but if there are more than 13 slides // The description of the bug: http://blog.aaronvanderzwan.com/forums/topic/stack-overflow-in-ie-7-8/#post-33038 onFirstImageLoaded: function(){}, onImagesLoaded: function(){} } })(jQuery);