var isPad = (navigator.userAgent.match(/iPad/i) != null); Slides = function() { // context var t = this; // member variables t.domReady = false; t.config = {}; t.global = new Global; t.configLoaded = false; t.current = -1; t.slideImageClass = 'slide-main-image'; t.slideClass = 'slide'; t.layerClass = 'layer'; t.slideshowControlsId = 'slideshow-controls'; t.flashVideoPlayerIdStub = 'flash-video-player-container-'; t.flashVideoPlayerClass = 'flash-video-player-container'; t.isTransitioning = false; t.timeoutId = null; t.slideStartedAt = null; t.paused = false; t.elapsedTimeAtPause = null; t.stoppedAtEnd = false; t.playPauseButtonOver = false; t.videoSupport = ''; // will equal 'html5' | 'flash' | 'none' t.flashLoadedBinds = []; t.firstSlideShowCompleteEvent = 'FirstSlideShowCompleteEvent'; // when DOM is ready, alert this object and try to run setup $(function() { t.domReady = true; t.setup(); }); // set up and load the config from external JSON t.loadConfig = function() { // bail if conditions already met if (t.configLoaded) return; $.ajax(t.global.configURL, { 'dataType': 'json', 'success': function(data){ t.config = data; t.configLoaded = true; t.setup(); }, 'error': function(jqXHR, textStatus, errorThrown) { // console.log('axaj error', jqXHR, textStatus, errorThrown); } }); }; // when config is loaded and DOM is ready, setup our slides t.setup = function() { // bail if conditions not met if (!t.domReady || !t.configLoaded) return; // DISABLED: SEE COMMENT BELOW // detect what kind of video support we have /*if (Modernizr.video && Modernizr.video.h264) { t.videoSupport = 'html5'; } else if (swfobject.hasFlashPlayerVersion(t.global.flashPlayerVersion)) { t.videoSupport = 'flash'; } else { t.videoSupport = 'none'; }*/ // COMMENT // This Slides file once supports a flash version of just the // video player (VideoPlayer.swf), but we're disabling that for // clarity. If the HTML5 video tag is not supported, this Slides // should never been run. t.videoSupport = 'html5'; // change the config for the iPad if (isPad) { for (var i in t.config.slides) { if (t.config.slides[i].type == 'video') { var slide = t.config.slides[i]; var layer = slide.layers[0]; slide.type = 'image'; layer.type = 'image'; layer.src = layer.poster; } } } t.clearAllSlides(); for (index in t.config.slides) { t.config.slides[index]['loaded'] = false; t.addSlide(t.config.slides[index], index); } $(window).resize(t.adjustSlideBackgrounds); t.adjustSlideBackgrounds(); var controlsHTML = '<div id="'+t.slideshowControlsId+'" style="display:none;">'; controlsHTML += '<a href="#" class="play-pause">Play/Pause</a>'; controlsHTML += '<a href="#" class="previous">Previous</a>'; controlsHTML += '<span></span>'; controlsHTML += '<a href="#" class="next">Next</a>'; controlsHTML += '</div>'; $(t.global.containerQuery).append(controlsHTML); $('#'+t.slideshowControlsId+' a.play-pause') .mouseenter(t.playPauseOver) .mouseleave(t.playPauseOut) .click(function(event){ event.preventDefault(); t.playPause(); }); $('#'+t.slideshowControlsId+' a.previous').click(function(event) { event.preventDefault(); t.previousSlideFromButton(); }); $('#'+t.slideshowControlsId+' a.next').click(function(event) { event.preventDefault(); t.nextSlideFromButton(); }); if (t.config.autoplay) { t.showSlide(0); t.paused = false; } else { t.paused = true; t.setControllerState(0); t.showSlide(0, true); } t.playPauseSetState(); } // remove all slides t.clearAllSlides = function() { $('#'+t.global.slideshowId).empty(); } // add slide t.addSlide = function(data, index) { var setFlashVideoPlayerLater = false; var tag = $('<div class="'+t.slideClass+'"></div>'); tag.fadeTo(0, 0); for (layerIndex in data.layers) { var layer = data.layers[layerIndex]; var d = null; if (layerIndex == 0) { if (layer.type == 'image') { tag.append('<div class="'+t.slideImageClass+'"><img src="'+t.config.baseURL+layer.src+'"/></div>'); d = tag.find('div:last'); var i = d.find('img'); i.load(function(){ data.loaded = true; }) if (data.zoomAlign == 'topLeft') i.css({'top':0,'left':0}); else if (data.zoomAlign == 'top') i.css({'top':0,'right':0,'left':0}); else if (data.zoomAlign == 'topRight') i.css({'top':0,'right':0}); else if (data.zoomAlign == 'left') i.css({'top':0,'bottom':0,'left':0}); else if (data.zoomAlign == 'center') i.css({'top':0,'right':0,'bottom':0,'left':0}); else if (data.zoomAlign == 'right') i.css({'top':0,'right':0,'bottom':0}); else if (data.zoomAlign == 'bottomLeft') i.css({'bottom':0,'left':0}); else if (data.zoomAlign == 'bottom') i.css({'right':0,'bottom':0,'left':0}); else if (data.zoomAlign == 'bottomRight') i.css({'right':0,'bottom':0}); } else if (layer.type == 'video' && t.videoSupport == 'html5') { tag.append('<video><source src="'+t.config.baseURL+layer.src+'" type="video/mp4"/></video>'); d = tag.find('video:last'); tag.find('video').css({'z-index':layerIndex}); tag.find('video').bind('canplaythrough', function(){ data.loaded = true; }); } else if (layer.type == 'video' && t.videoSupport == 'flash') { var flashVideoPlayerId = t.flashVideoPlayerIdStub+index; tag.append('<div id="'+flashVideoPlayerId+'"></div>'); d = tag.find('div:last'); d.addClass(t.flashVideoPlayerClass); var flashvars = {}; var params = {}; var attributes = {}; flashvars.index = index; flashvars.width = t.config.width; flashvars.height = t.config.height; flashvars.videoURL = t.config.baseURL+layer.src; params.wmode = 'opaque'; attributes.wmode = 'opaque'; d = $('#'+flashVideoPlayerId); setFlashVideoPlayerLater = true; } // unknown type! bail! else return; // if (d != null) // { // if (data.align == 'topLeft') d.css({'top':0,'left':0}); // else if (data.align == 'top') d.css({'top':0,'right':0,'left':0}); // else if (data.align == 'topRight') d.css({'top':0,'right':0}); // else if (data.align == 'left') d.css({'top':0,'bottom':0,'left':0}); // //else if (data.align == 'center') d.css({'top':'-100%','right':'-100%','bottom':'-100%','left':'-100%'}); // else if (data.align == 'right') d.css({'top':0,'right':0,'bottom':0}); // else if (data.align == 'bottomLeft') d.css({'bottom':0,'left':0}); // else if (data.align == 'bottom') d.css({'right':0,'bottom':0,'left':0}); // else if (data.align == 'bottomRight') d.css({'right':0,'bottom':0}); // } } else { // any type that is a link if (layer.url) { tag.append('<a href="'+layer.url+'"></a>'); d = tag.find('a:last'); if (layer.target) d.attr('target', layer.target); if (layer.type == 'sprite') d.mouseenter(function(){ $(this).css({'background-position':'0 -'+layer.height+'px'}); }).mouseleave(function(){ $(this).css({'background-position':'0 0'}); }); } // if just text else if (layer.type == 'text') { tag.append('<div></div>'); d = tag.find('div:last'); } else if (layer.type == 'image') { tag.append('<img src="'+t.config.baseURL+blank.png"/>'); d = tag.find('img:last'); } // apply to all layers d.addClass(t.layerClass); d.addClass(layer.type); if (layer.text) d.append(layer.text); if (layer.x && layer.y) d.css({ 'left':layer.x, 'top':layer.y }); if (layer.width) d.width(layer.width); if (layer.height) d.height(layer.height); if (layer.layerClass) d.addClass(layer.layerClass); if (layer.size) d.css({'font-size':layer.size}); if (layer.font) d.css({'font-family':layer.font}); if (layer.color) d.css({'color':layer.color}); if (layer.lineHeight) d.css({'line-height':layer.lineHeight+'px'}); if (layer.src && layer.type != 'video') d.css({ 'backgroundImage':'url('+t.config.baseURL+layer.src+')', 'textIndent':-5000 }); d.css({ 'overflow':'hidden' }); } if (d) d.css({'z-index':layerIndex}); } $('#'+t.global.slideshowId).append(tag); if (setFlashVideoPlayerLater) swfobject.embedSWF(t.global.flashVideoPlayerURL, flashVideoPlayerId, '100%', '100%', t.global.flashPlayerVersion, t.global.flashPlayerExpressInstallURL, flashvars, params, attributes); } // show slide based on index t.showSlide = function(index, pauseSlide) { // if we're in the middle of a transition, bail. if (t.isTransitioning) return; if (typeof(pauseSlide) == 'undefined') pauseSlide = false; t.isTransitioning = true; var data = t.config.slides[index]; var doIt = function() { // current slide var currentSlide = $('#'+t.global.slideshowId+' .'+t.slideClass).eq(index); // move z-index of new slide to top currentSlide.css({'z-index':t.config.slides.length-1}); var j = 0; for (var i = 0; i < t.config.slides.length; i++) { if (i == index) continue; $('#'+t.global.slideshowId+' .'+t.slideClass).eq(i).css({'z-index':j}); j++; } // set current state in controller t.setControllerState(index); if (t.current != -1) { var fadeOutCurrent = t.current; $('#'+t.global.slideshowId+' .'+t.slideClass).eq(t.current).fadeTo(data.transition * 1000, 0, function(){ t.stopVideo(fadeOutCurrent, true); }); } t.elapsedTimeAtPause = 0; // start playing if video if (data.type == 'video' && !pauseSlide) { t.playVideo(index, true); } else if (data.type == 'video' && pauseSlide) { } // otherwise if image, do ken burns effect else if (data.type == 'image' && !pauseSlide) { t.startKenBurns(index, t.getSlideDuration(index, true), true); } else if (data.type == 'image' && pauseSlide) { var c = t.calculateZoom(data.zoomStart); var img = currentSlide.find('img'); img.width(c).height(c); } t.adjustSlideBackgrounds(); var previous = t.current; currentSlide.fadeTo(data.transition * 1000, 1, function(){ if (index == 0 && previous == -1) $('#'+t.global.slideshowId).trigger(t.firstSlideShowCompleteEvent); t.isTransitioning = false; }); t.current = index; if (!pauseSlide) { t.setSlideTimeout(); } } if (data.loaded) { doIt(); } else { if (data.type == 'image') $('#'+t.global.slideshowId+' .'+t.slideClass).eq(index).find('.'+t.slideImageClass+' img').load(doIt); else t.bindFunctionToVideoReady(index, doIt); } } // if possible, show next slide t.nextSlide = function() { if (t.current >= t.config.slides.length - 1 && !t.config.loop) { t.stoppedAtEnd = true; t.paused = true; t.playPauseSetState(); t.stopVideo(t.current); } else if (t.current >= t.config.slides.length - 1 && t.config.loop) { t.showSlide(0); } else { t.showSlide(t.current + 1); } } t.previousSlideFromButton = function() { if (t.isTransitioning) return; if (t.current == 0 && !t.config.loop) return; if (t.timeoutId) clearTimeout(t.timeoutId); if (t.stoppedAtEnd && t.config.slides.length > 1) { t.showSlide(t.config.slides.length - 2); t.paused = false; t.stoppedAtEnd = false; t.playPauseSetState(); } else { var slideId; if (t.current > 0) slideId = t.current - 1; else if (t.current == 0 && t.config.loop) slideId = t.config.slides.length - 1; else slideId = 0; // should never happen if (slideId == t.current) t.previous = null; t.showSlide(slideId, t.paused); } } t.nextSlideFromButton = function() { if (t.isTransitioning) return; var lastSlide = t.config.slides.length - 1; if (t.current == lastSlide && !t.config.loop) return; if (t.timeoutId) clearTimeout(t.timeoutId); var slideId; if (t.current == lastSlide && t.config.loop) slideId = 0; else if (t.current < lastSlide) slideId = t.current + 1; else return; // this should never happen if (slideId == t.current) t.previous = null; t.showSlide(slideId, t.paused); } t.setSlideTimeout = function() { // calculate how long the slide should be on-screen var index = t.current; var slideDuration = t.getSlideDuration(index); // set the timeout to transition to next slide if (t.timeoutId) clearTimeout(t.timeoutId); t.timeoutId = setTimeout(t.nextSlide, slideDuration); // set time this was set to object var d = new Date(); t.slideStartedAt = d.getTime(); } t.getSlideDuration = function(index, excludeNextTransition) { if (typeof(excludeNextTransition) == 'undefined') excludeNextTransition = false; var data = t.config.slides[index]; var currentSlide = $('#'+t.global.slideshowId+' .'+t.slideClass).eq(index); var nextIndex = (index < t.config.slides.length - 1) ? index + 1 : 0; var nextTransition = (excludeNextTransition) ? 0 : t.config.slides[nextIndex].transition; var slideDuration = (data.type == 'video') ? t.getDuration(index) : data.interval; return ((slideDuration - nextTransition) * 1000) - t.elapsedTimeAtPause; } t.startKenBurns = function(index, duration, reset) { if (!t.isSlideImage(index)) return; if (typeof(reset) == 'undefined') reset = false; t.stopKenBurns(index); var img = $('#'+t.global.slideshowId+' .'+t.slideClass).eq(index).find('img'); var data = t.config.slides[index]; if (reset) { var c1 = t.calculateZoom(data.zoomStart); img.width(c1).height(c1); } var c2 = t.calculateZoom(data.zoomEnd); img.animate({ 'width':c2, 'height':c2 }, { 'duration':duration, 'easing':'linear' }); } t.stopKenBurns = function(index) { if (!t.isSlideImage(index)) return; var img = $('#'+t.global.slideshowId+' .'+t.slideClass).eq(index).find('img'); var data = t.config.slides[index]; img.stop(); } t.calculateZoom = function(zoom) { if (zoom < 100) zoom = 100; else if (zoom > 200) zoom = 200; return zoom + '%'; } t.playPause = function() { if (t.isTransitioning) return; // if stopped at the end. start the whole thing over if (t.stoppedAtEnd && !t.config.loop) { t.showSlide(0); t.paused = false; t.stoppedAtEnd = false; t.playPauseSetState(); return; } // find current video if it exists // var currentVideo = $('#'+t.global.slideshowId+' .'+t.slideClass).eq(t.current).find('video'); var index = t.current; // unpause if (t.paused) { t.setSlideTimeout(); t.paused = false; t.playPauseSetState(); t.playVideo(index); t.startKenBurns(index, t.getSlideDuration(index, true)); // if (currentVideo.length > 0) // currentVideo.get(0).play(); } // pause else { if (t.timeoutId) clearTimeout(t.timeoutId); var d = new Date(); t.elapsedTimeAtPause += d.getTime() - t.slideStartedAt; t.paused = true; t.playPauseSetState(); t.stopVideo(index); t.stopKenBurns(index); // if (currentVideo.length > 0) // currentVideo.get(0).pause(); } } t.playPauseOver = function() { t.playPauseButtonOver = true; t.playPauseSetState(); } t.playPauseOut = function() { t.playPauseButtonOver = false; t.playPauseSetState(); } t.playPauseSetState = function() { var xPos = (t.paused) ? '0' : '-9px'; var yPos = (t.playPauseButtonOver) ? '-11px' : '0'; $('#'+t.slideshowControlsId+' a.play-pause').css({'background-position':xPos+' '+yPos}); } t.stopVideo = function(index, seekToBegining) { if (!t.isSlideVideo(index)) return; if (typeof(seekToBegining) == 'undefined') seekToBegining = false; if (t.videoSupport == 'html5') { $('#'+t.global.slideshowId+' .'+t.slideClass).eq(index).find('video').each(function(){ this.pause(); if (seekToBegining) this.currentTime = 0; }); } else if (t.videoSupport == 'flash') { var flashObj = $('#'+t.flashVideoPlayerIdStub+index).get(0); if (seekToBegining) flashObj.stopVideo(); else flashObj.pauseVideo(); } } t.playVideo = function(index, startFromBegining) { if (!t.isSlideVideo(index)) return; if (typeof(startFromBegining) == 'undefined') startFromBegining = false; if (t.videoSupport == 'html5') { $('#'+t.global.slideshowId+' .'+t.slideClass).eq(index).find('video').each(function(){ if (startFromBegining) this.currentTime = 0; this.play(); }); } else if (t.videoSupport == 'flash') { var flashObj = $('#'+t.flashVideoPlayerIdStub+index).get(0); if (startFromBegining) { flashObj.playVideoFromBeginning(); } else flashObj.playVideo(); } } t.restartVideo = function(index) { if (!t.isSlideVideo(index)) return; if (t.videoSupport == 'html5') { $('#'+t.global.slideshowId+' .'+t.slideClass).eq(index).find('video').each(function(){ if (startFromBegining) this.currentTime = 0; this.play(); }); } } t.bindFunctionToVideoReady = function(index, func) { if (!t.isSlideVideo(index)) return; if (t.videoSupport == 'html5') { $('#'+t.global.slideshowId+' .'+t.slideClass).eq(index).find('video').bind('canplaythrough', func); } else if (t.videoSupport == 'flash') { t.flashLoadedBinds.push({'index':index, 'func':func}); } } t.getDuration = function(index) { if (!t.isSlideVideo(index)) return; if (t.videoSupport == 'html5') { return $('#'+t.global.slideshowId+' .'+t.slideClass).eq(index).find('video').get(0).duration; } else if (t.videoSupport == 'flash') { var flashObj = $('#'+t.flashVideoPlayerIdStub+index).get(0); return flashObj.getDuration(); } } t.setControllerState = function(index) { $('#'+t.slideshowControlsId+' span').html((index+1) + '/' + t.config.slides.length); if ($('#'+t.slideshowControlsId+':hidden').length > 0) { var c = $('#'+t.slideshowControlsId); if ($.support.opacity) c.fadeTo(500, 1); else c.show(); } } t.setFlashSlideAsLoaded = function(index) { t.config.slides[index].loaded = true; for (var i = 0; i < t.flashLoadedBinds.length; i++) { if (t.flashLoadedBinds[i].index == index) { t.flashLoadedBinds[i].func(); t.flashLoadedBinds.splice(i, 1); break; } } } t.isSlideVideo = function(index) { return (t.config.slides[index].type == 'video'); } t.isSlideImage = function(index) { return (t.config.slides[index].type == 'image'); } // durring slideshow setup, this gets set to window resize to adjust the size of all slide // bottom layers (images and videos) t.adjustSlideBackgrounds = function() { var c = $(t.global.containerQuery); var w = parseInt(c.width()); var h = parseInt(c.height()); if (h == 0) { setTimeout(t.adjustSlideBackgrounds, 50); return; } var i = $('#'+t.global.slideshowId).find('.'+t.slideImageClass+', video'); var rw = w / t.config.width; var rh = h / t.config.height; var r = (rw > rh) ? rw : rh; var iw = t.config.width * r; var ih = t.config.height * r; i.width(Math.round(iw)); i.height(Math.round(ih)); i.each(function(index){ var a = t.config.slides[index].align; var left = 0; if ($.inArray(a, ['top', 'center', 'bottom']) != -1) left = Math.round((w - iw) / 2); else if ($.inArray(a, ['topRight', 'right', 'bottomRight']) != -1) left = Math.round(w - iw); var top = 0; if ($.inArray(a, ['left', 'center', 'right']) != -1) top = Math.round((h - ih) / 2); else if ($.inArray(a, ['bottomLeft', 'bottom', 'bottomRight']) != -1) top = Math.round(h - ih); $(this).css({ 'left': left, 'top': top }); }); } };