View Larger plugin for Conde Nast Slideshow. (c) Conde Nast Publications, All Rights Reserved
/*global CN, console, window, alert, location, document, jQuery, setTimeout, clearTimeout, clearInterval, setInterval */ /* for jsLint */ | |
CN.slideshow = CN.slideshow || {}; | |
CN.slideshow.plugin = CN.slideshow.plugin || {}; | |
/** | |
* Plugin to add support for View Larger to the MPP Slideshow. | |
* Encapsulates view larger creation, data population and destruction. | |
* | |
* @namespace CN.slideshow | |
* @class viewLarger | |
* @requires CN.slideshow | |
* @author Eric Shepherd | |
* @history 1.0.0 EBS 06.01.2009 Production | |
* 1.0.1 YC 03.20.2010 Added unbinding of history to fix bug with double counting | |
* 1.0.2 EBS 07.21.2010 Added config for width instead of hardcoded value | |
*/ | |
CN.slideshow.plugin.viewLarger = (function() { | |
var build, | |
remove, | |
create, | |
destroyElements, | |
cleanupOriginatingSlideshow, | |
close, | |
setKeyEvents, | |
prepareDomElements, | |
$overlay, | |
$largerEl, | |
buildInstructions, | |
addExtraSlides, | |
insertInitialSlideMarkup, | |
createExtraControls, | |
createViewLargerObject, | |
elementResize; | |
/** | |
* Model helper which creates the slides for the View Larger module. | |
* | |
* @method build | |
* @private | |
* @param {Slides} slideshow A slideshow to build View Larger with | |
*/ | |
build = function(slideshow) { | |
var i, | |
il; | |
for (i = 0, il = slideshow.data.length; i < il; i++) { | |
slideshow.append(new CN.slideshow.Slide(slideshow.data[i], 'enlargedItem')); | |
} | |
CN.slideshow.util.dataReady(slideshow); | |
}; | |
/** | |
* Helper which removes the View Larger slideshow specified along | |
* with its navigation objects | |
* | |
* @method remove | |
* @private | |
* @param {Slides} slideshow A slideshow to remove | |
*/ | |
remove = function(slideshow) { | |
// Calls the page method which can tap into the view larger instance | |
try { | |
CN.page.config.slideshowViewLargerCloseCallback(slideshow); | |
} catch(e) { | |
CN.debug.warn('Tried to call view larger close callback, perhaps no callback function exists at CN.page.config.slideshowViewLargerCloseCallback : ' + e.message); | |
} | |
jQuery(document).unbind('keydown'); | |
destroyElements(slideshow); | |
CN.slideshow.util.removeNavigations(slideshow); | |
CN.slideshow.util.destroyTimer(slideshow); | |
slideshow = null; | |
}; | |
/** | |
* Handles behaviors for a view larger instance | |
* | |
* @method create | |
* @public | |
* @param {Slides} slideshow The slideshow to build view larger for | |
* @param {Object} config The view larger configuration object | |
* @param {Object} oldCommands The command object from the original slideshow | |
*/ | |
create = function(slideshow, config, oldCommands) { | |
var larger = createViewLargerObject(slideshow, config.transition || null), | |
viewLargerCommands; | |
cleanupOriginatingSlideshow(slideshow); | |
prepareDomElements(larger, oldCommands); | |
// Updates the slideshow when the history changes, only if view larger element is present | |
if (larger.useHistory) { | |
jQuery(window).bind('history', function(e, currentHash, previousHash) { | |
var dest = currentHash.split('=')[1]; | |
close(larger, oldCommands, dest); | |
}); | |
} | |
elementResize(); // Necessary to resize before showing overlay for it to fade in properly | |
jQuery(window).resize(function() { | |
elementResize(); | |
}); | |
jQuery('body').append($overlay); | |
$overlay.hide().fadeIn('slow', function() { | |
jQuery('body').append($largerEl); | |
buildInstructions(); | |
// Recurses on the init function to initialize and get commands | |
viewLargerCommands = CN.slideshow.controller.init(larger, { | |
goForward : { container: '.slideshow-view-larger-util' }, | |
goBackward : { container: '.slideshow-view-larger-util' }, | |
stopSlideshow : { container: '.slideshow-view-larger-util' }, | |
playSlideshow : { container: '.slideshow-view-larger-util', sliderEl: '.slideshow-control-stop' } | |
}); | |
CN.slideshow.util.destroyTimer(slideshow); | |
createExtraControls(slideshow, viewLargerCommands); | |
setKeyEvents(larger, viewLargerCommands, oldCommands); | |
build(larger); | |
addExtraSlides(slideshow, larger); | |
insertInitialSlideMarkup(slideshow, larger); | |
elementResize(); | |
// Calls the page method which can tap into the view larger instance for ad refreshing, etc. | |
try { | |
CN.page.config.slideshowViewLargerCallback(larger, viewLargerCommands); | |
} catch(e) { | |
CN.debug.warn('Tried to call view larger callback; perhaps no callback function exists at CN.page.config.slideshowViewLargerCallback : ' + e.message); | |
} | |
}); | |
}; | |
/** | |
* Removes view larger slideshow dom elements | |
* | |
* @method destroyElements | |
* @private | |
* @param {Slides} slideshow A slideshow object | |
*/ | |
destroyElements = function(slideshow) { | |
CN.slideshow.view.removeSlide(slideshow.$el.find('.items').children()); | |
slideshow.$el.remove(); | |
jQuery('.slideshow-view-larger-overlay').fadeOut('slow', function() { | |
jQuery('.slideshow-view-larger-overlay').remove(); | |
}); | |
}; | |
/** | |
* Cleans up the existing slideshow before creating its view larger instance | |
* | |
* @method cleanupOriginatingSlideshow | |
* @private | |
* @param {Slides} slideshow A slideshow object | |
*/ | |
cleanupOriginatingSlideshow = function(slideshow) { | |
// In case slideshow is playing | |
CN.slideshow.view.hideSlider(slideshow, function() { | |
CN.slideshow.view.hideStopButton(slideshow); | |
}); | |
// In case view all is open | |
if (slideshow.navigationItems.hasOwnProperty('navigationViewAll')) { | |
slideshow.navigationItems.navigationViewAll.hide(); | |
} | |
}; | |
/** | |
* Closes up shop, cleans up | |
* | |
* @method close | |
* @private | |
* @param {Slides} slideshow A view larger slideshow | |
* @param {Object} oldCommands A collection of commands for the originating slideshow | |
* @param {Number} destinationSlide An optional slide to jump to when closing the view larger slideshow | |
*/ | |
close = function(slideshow, oldCommands, destinationSlide) { | |
// Communicates with originating slideshow on close | |
oldCommands.jumpToSlideCommand.execute(destinationSlide || slideshow.currentSlideIndex + 1); | |
jQuery(window).unbind('history'); | |
remove(slideshow); | |
jQuery(window).bind('history', { | |
useIntro : slideshow.useIntro, | |
commands : oldCommands | |
}, CN.slideshow.util.bindHistory); | |
}; | |
/** | |
* Sets the keyboard commands for view larger | |
* | |
* @method setKeyEvents | |
* @private | |
* @param {Sldies} larger A view larger slideshow | |
* @param {Object} commands A collection of commands for the larger slideshow | |
* @param {Object} oldCommands A collection of commands for the originating slideshow | |
*/ | |
setKeyEvents = function(larger, commands, oldCommands) { | |
jQuery(document).keydown(function(e) { | |
switch(e.keyCode) { | |
case 27 : | |
close(larger, oldCommands); | |
break; | |
case 39 : | |
commands.goForwardCommand.execute(); | |
break; | |
case 37 : | |
commands.goBackwardCommand.execute(); | |
break; | |
case 32 : | |
if (larger.isAlreadyPlaying()) { | |
commands.stopSlideshowCommand.execute(); | |
} else { | |
commands.playSlideshowCommand.execute(); | |
} | |
break; | |
} | |
e.preventDefault(); | |
return false; | |
}); | |
}; | |
/** | |
* Preps the document for view larger | |
* | |
* @method prepareDomElements | |
* @private | |
* @param {Slides} slideshow The view larger slideshow instance | |
* @param {Object} oldCommands A collection of commands for the original slideshow | |
*/ | |
prepareDomElements = function(slideshow, oldCommands) { | |
var $closeBox = jQuery('<div class="slideshow-view-larger-close">Close</div>'), | |
$utilBox = jQuery('<div class="slideshow-view-larger-util"><div class="count">' + (slideshow.currentSlideIndex + 1) + ' / ' + slideshow.slides.length + '</div></div>'); | |
$overlay = jQuery('<div class="slideshow-view-larger-overlay">'); | |
$closeBox.click(function() { | |
close(slideshow, oldCommands); | |
}); | |
slideshow.$el.addClass('slideshow-view-larger-container').prepend($closeBox).append($utilBox).append('<h1>' + jQuery('.list h1').eq(0).text() + '</h1>'); | |
}; | |
/** | |
* Creates additional controls not created by the shell | |
* | |
* @method createExtraControls | |
* @private | |
* @param {Slides} slideshow A view larger slideshow instance | |
* @param {Object} commands Commands for the view larger instance | |
*/ | |
createExtraControls = function(slideshow, commands) { | |
var $previous, | |
$next; | |
$previous = jQuery('<div class="slideshow-view-larger-previous">').click(function() { | |
commands.goBackwardCommand.execute(); | |
}); | |
$next = jQuery('<div class="slideshow-view-larger-next">').click(function() { | |
commands.goForwardCommand.execute(); | |
}); | |
$largerEl.append($previous).append($next); | |
}; | |
/** | |
* Recalculates the DOM element sizes | |
* | |
* @method elementResize | |
* @private | |
*/ | |
elementResize = function() { | |
var topOffset = jQuery('body,html').scrollTop(); | |
$overlay.css({ | |
height : jQuery(document).height(), | |
width : jQuery(document).width() | |
}); | |
$largerEl.css({ | |
width : (CN.slideshow.config && CN.slideshow.config.viewLargerWidth) ? | |
CN.slideshow.config.viewLargerWidth : | |
990, | |
top : topOffset, | |
left : jQuery(document).width() / 2 - 475 - 20 // account for scrollbars on browser... | |
}); | |
// Sets position fixed if the browser supports it and the window is big enough to see the entire slideshow. | |
if ((jQuery(window).height() < ($largerEl.height() + 50)) || (jQuery.browser.msie && jQuery.browser.version < 7) || (jQuery.browser.mozilla && jQuery.browser.version.substr(0, 3) < 1.9)) { | |
$largerEl.css('position', 'absolute'); | |
$largerEl.css('top', topOffset); | |
} else { | |
$largerEl.css('position', 'fixed'); | |
$largerEl.css('top', 0); | |
} | |
}; | |
/** | |
* Creates the instruction box and handles the cookie for showing it | |
* | |
* @method buildInstructions | |
* @private | |
*/ | |
buildInstructions = function() { | |
var $instructions = jQuery('<div class="slideshow-view-larger-instructions instructions-default"><strong>Press ESC to close</strong><b>Right Arrow</b> moves forward.<br /><b>Left Arrow</b> moves backward.<br /><b>Space Bar</b> starts and stops play.</p></div>').appendTo($largerEl), | |
$instructionsTrigger = jQuery('<div class="slideshow-view-larger-instructions-trigger">? <span>Help</span></div>').insertBefore($instructions), | |
$instructionsClose = jQuery('<div class="slideshow-view-larger-instructions-close">Close</div>').prependTo($instructions), | |
instructionsTimer, | |
repeatVisitor = CN.cookie.get('slideshow_repeat'); | |
// Adds cookie for displaying instructions | |
if (repeatVisitor === 'yes') { | |
$instructions.hide(); | |
$largerEl.hide().fadeIn('slow'); | |
} else { | |
$largerEl.hide().fadeIn('slow', function() { | |
instructionsTimer = setTimeout(function() { | |
$instructions.fadeOut('slow'); | |
}, 3000); | |
CN.cookie.set('slideshow_repeat', 'yes', { domain: CN.site.domain, path: '/' }); | |
}); | |
} | |
$instructionsClose.click(function() { | |
$instructions.fadeOut('fast'); | |
clearTimeout(instructionsTimer); | |
}); | |
$instructionsTrigger.css('display', 'block').click(function() { | |
$instructions.fadeIn('fast'); | |
}); | |
}; | |
/** | |
* Adds extra slides that are not part of the data object | |
* | |
* @method addExtraSlides | |
* @private | |
* @param {Slides} slideshow The original slideshow object | |
* @param {Slides} larger The new view larger slideshow object | |
*/ | |
addExtraSlides = function(slideshow, larger) { | |
var i, | |
il; | |
// Adds anything not of type 'slide' into the view larger slides array | |
for (i = 0, il = slideshow.slides.length; i < il; i++) { | |
if (slideshow.slides[i].getLabel() !== 'slide') { | |
larger.slides.splice(i, 0, slideshow.slides[i]); | |
larger.onSlideAppended.fire(); // Updates count and interstitial frequency | |
} | |
} | |
}; | |
/** | |
* Creates the view larger object | |
* | |
* @method createViewLargerObject | |
* @private | |
* @param {Slides} slideshow A slideshow object to build view larger from | |
* @param {String} transition An optional transition | |
* @return {Slides} A view larger object | |
*/ | |
createViewLargerObject = function(slideshow, transition) { | |
// Builds the new slideshow and copies over what we need from the old | |
var larger = new CN.slideshow.Slides(document.createElement('div'), { | |
transition : transition || 'standard', | |
useHistory : slideshow.useHistory | |
}); | |
larger.data = slideshow.data; | |
larger.interstitialManager = slideshow.interstitialManager; | |
larger.currentSlideIndex = slideshow.currentSlideIndex; | |
$largerEl = larger.$el; | |
return larger; | |
}; | |
/** | |
* Adds the items container and current slide markup for the initial view larger view | |
* | |
* @method insertInitialSlideMarkup | |
* @private | |
* @param {Slides} slideshow The originating slideshow for this view larger instance (only needed to accurately get the current slide number) | |
* @param {Slides} larger The current view larger slideshow instance | |
*/ | |
insertInitialSlideMarkup = function(slideshow, larger) { | |
var $container = jQuery('<div class="items slideshow-items">'); | |
$largerEl.find('.slideshow-view-larger-close').after($container); | |
// Note: using slideshow's index to find the slide because larger's index sometimes returns 0. Might be a timing issue, | |
// but it stabilizes things to use the slideshow's and they are always the same anyway. | |
$container.append(jQuery(larger.slides[slideshow.currentSlideIndex].getHtml())); // getHtml(), unintuitively, could return a jQuery selector | |
}; | |
return { | |
create : create | |
}; | |
}()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment