I've implemented the AnythingSlider (http://css-tricks.com/anythingslider-jquery-plugin/) using image and video content (videos use the longtail flv player - licensed version 5).
Problem: When the user plays the video, the slideshow doesn't know this has happened, so the slideshow keeps cycling while the video runs. So you have the slideshow running - and user can hear the audio but the video has cycled off.
- UPDATE - here is a link to see what's going on: http://silverberry.org/beta/slider-longtail/
I'm trying to figure out an event-listener that will look and see when the LONGTAIL player is in PLAYING state and signals to the AnythingSlider that it needs to STOP.
Here's what I've got so far ... the video player event listeners are working (right now I have alerts popping up so that I can be sure the events are being heard). An alert pops up with the player is initialized .. and alert pops up when we press the PLAY button on the video ... and an alert pops up when the video STOPS playing. But ... I've yet to work out the proper syntax for signaling to the anythingslider to STOP!
I thought it would be this:
$VUslider.startStop(false);
Below is the code I have so far ... beginning with the code that initializes the slider.
function formatText(index, panel) {
return index + "";
}
$(function () {
$('.VUslider').VUslider({
autoPlay: true,
delay: 7000,
startStopped: false,
animationTime: 200,
hashTags: true,
buildNavigation: false,
pauseOnHover: true,
navigationFormatter: formatText
});
});
var player = null;
function playerReadyCallback(obj) {
player = document.getElementsByName(obj.id)[0];
alert('the videoplayer '+obj['id']+' has been instantiated');
player.addModelListener('STATE', 'stateMonitor');
}
function stateMonitor(obj) {
currentState = obj['newstate'];
if(currentState == 'PLAYING') {
alert ('the videoplayer '+obj['id']+' is playing now!');
$VUslider.startStop(false); // Trigger slideshow stop
}
if(obj.newstate == 'COMPLETED') {
alert ('the videoplayer '+obj['id']+' has stopped playing now!');
$VUslider.startStop(true); // Trigger slideshow start
}
}
FOR REFERENCE ... HERE IS THE ANYTHING SLIDER CODE:
(function($){
$.VUslider = function(el, options){
// To avoid scope issues, use 'base' instead of 'this'
// to reference this class from internal events and functions.
var base = this;
// Access to jQuery and DOM versions of element
base.$el = $(el);
base.el = el;
// Set up a few defaults
base.currentPage = 1;
base.timer = null;
base.playing = false;
// Add a reverse reference to the DOM object
base.$el.data("AnythingSlider", base);
base.init = function(){
base.options = $.extend({},$.VUslider.defaults, options);
// Cache existing DOM elements for later
base.$wrapper = base.$el.find('> div').css('overflow', 'hidden');
base.$slider = base.$wrapper.find('> ul');
base.$items = base.$slider.find('> li');
base.$single = base.$items.filter(':first');
// Build the navigation if needed
if(base.options.buildNavigation) base.buildNavigation();
// Get the details
base.singleWidth = base.$single.outerWidth();
base.pages = base.$items.length;
// Top and tail the list with 'visible' number of items, top has the last section, and tail has the first
// This supports the "infinite" scrolling
base.$items.filter(':first').before(base.$items.filter(':last').clone().addClass('cloned'));
base.$items.filter(':last' ).after(base.$items.filter(':first').clone().addClass('cloned'));
// We just added two items, time to re-cache the list
base.$items = base.$slider.find('> li'); // reselect
// Setup our forward/backward navigation
base.buildNextBackButtons();
// If autoPlay functionality is included, then initialize the settings
if(base.options.autoPlay) {
base.playing = !base.options.startStopped; // Sets the playing variable to false if startStopped is true
base.buildAutoPlay();
};
// If pauseOnHover then add hover effects
if(base.options.pauseOnHover) {
base.$el.hover(function(){
base.clearTimer();
}, function(){
base.startStop(base.playing);
});
}
// If a hash can not be used to trigger the plugin, then go to page 1
if((base.options.hashTags == true && !base.gotoHash()) || base.options.hashTags == false){
base.setCurrentPage(1);
};
};
base.gotoPage = function(page, autoplay){
// When autoplay isn't passed, we stop the timer
if(autoplay !== true) autoplay = false;
if(!autoplay) base.startStop(false);
if(typeof(page) == "undefined" || page == null) {
page = 1;
base.setCurrentPage(1);
};
// Just check for bounds
if(page > base.pages + 1) page = base.pages;
if(page < 0 ) page = 1;
var dir = page < base.currentPage ? -1 : 1,
n = Math.abs(base.currentPage - page),
left = base.singleWidth * dir * n;
base.$wrapper.filter(':not(:animated)').animate({
scrollLeft : '+=' + left
}, base.options.animationTime, base.options.easing, function () {
if (page == 0) {
base.$wrapper.scrollLeft(base.singleWidth * base.pages);
page = base.pages;
} else if (page > base.pages) {
base.$wrapper.scrollLeft(base.singleWidth);
// reset back to start position
page = 1;
};
base.setCurrentPage(page);
});
};
base.setCurrentPage = function(page, move){
// Set visual
if(base.options.buildNavigation){
base.$nav.find('.cur').removeClass('cur');
$(base.$navLinks[page - 1]).addClass('cur');
};
// Only change left if move does not equal false
if(move !== false) base.$wrapper.scrollLeft(base.singleWidth * page);
// Update local variable
base.currentPage = page;
};
base.goForward = function(autoplay){
if(autoplay !== true) autoplay = false;
base.gotoPage(base.currentPage + 1, autoplay);
};
base.goBack = function(){
base.gotoPage(base.currentPage - 1);
};
// This method tries to find a hash that matches panel-X
// If found, it tries to find a matching item
// If that is found as well, then that item starts visible
base.gotoHash = function(){
if(/^#?panel-\d+$/.test(window.location.hash)){
var index = parseInt(window.location.hash.substr(7));
var $item = base.$items.filter(':eq(' + index + ')');
if($item.length != 0){
base.setCurrentPage(index);
return true;
};
};
return false; // A item wasn't found;
};
// Creates the numbered navigation links
base.buildNavigation = function(){
base.$nav = $("<div id='thumbNav'></div>").appendTo(base.$el);
base.$items.each(function(i,el){
var index = i + 1;
var $a = $("<a href='#'></a>");
// If a formatter function is present, use it
if( typeof(base.options.navigationFormatter) == "function"){
$a.html(base.options.navigationFormatter(index, $(this)));
} else {
$a.text(index);
}
$a.click(function(e){
base.gotoPage(index);
if (base.options.hashTags)
base.setHash('panel-' + index);
e.preventDefault();
});
base.$nav.append($a);
});
base.$navLinks = base.$nav.find('> a');
};
// Creates the Forward/Backward buttons
base.buildNextBackButtons = function(){
var $forward = $('<a class="arrow forward">></a>'),
$back = $('<a class="arrow back"><</a>');
// Bind to the forward and back buttons
$back.click(function(e){
base.goBack();
e.preventDefault();
});
$forward.click(function(e){
base.goForward();
e.preventDefault();
});
// Append elements to page
base.$wrapper.after($back).after($forward);
};
// Creates the Start/Stop button
base.buildAutoPlay = function(){
base.$startStop = $("<a href='#' id='start-stop'></a>").html(base.playing ? base.options.stopText : base.options.startText);
base.$el.append(base.$startStop);
base.$startStop.click(function(e){
base.startStop(!base.playing);
e.preventDefault();
});
// Use the same setting, but trigger the start;
base.startStop(base.playing);
};
// Handles stopping and playing the slideshow
// Pass startStop(false) to stop and startStop(true) to play
base.startStop = function(playing){
if(playing !== true) playing = false; // Default if not supplied is false
// Update variable
base.playing = playing;
// Toggle playing and text
if(base.options.autoPlay) base.$startStop.toggleClass("playing", playing).html( playing ? base.options.stopText : base.options.startText );
if(playing){
base.clearTimer(); // Just in case this was triggered twice in a row
base.timer = window.setInterval(function(){
base.goForward(true);
}, base.options.delay);
} else {
base.clearTimer();
};
};
base.clearTimer = function(){
// Clear the timer only if it is set
if(base.timer) window.clearInterval(base.timer);
};
// Taken from AJAXY jquery.history Plugin
base.setHash = function ( hash ) {
// Write hash
if ( typeof window.location.hash !== 'undefined' ) {
if ( window.location.hash !== hash ) {
window.location.hash = hash;
};
} else if ( location.hash !== hash ) {
location.hash = hash;
};
// Done
return hash;
};
// <-- End AJAXY code
// Trigger the initialization
base.init();
};
$.VUslider.defaults = {
easing: "swing", // Anything other than "linear" or "swing" requires the easing plugin
autoPlay: true, // This turns off the entire FUNCTIONALY, not just if it starts running or not
startStopped: false, // If autoPlay is on, this can force it to start stopped
delay: 3000, // How long between slide transitions in AutoPlay mode
animationTime: 600, // How long the slide transition takes
hashTags: true, // Should links change the hashtag in the URL?
buildNavigation: true, // If true, builds and list of anchor links to link to each slide
pauseOnHover: true, // If true, and autoPlay is enabled, the show will pause on hover
startText: "Start", // Start text
stopText: "Stop", // Stop text
navigationFormatter: null // Details at the top of the file on this use (advanced use)
};
$.fn.VUslider = function(options){
if(typeof(options) == "object"){
return this.each(function(i){
(new $.VUslider(this, options));
// This plugin supports multiple instances, but only one can support hash-tag support
// This disables hash-tags on all items but the first one
options.hashTags = false;
});
} else if (typeof(options) == "number") {
return this.each(function(i){
var anySlide = $(this).data('AnythingSlider');
if(anySlide){
anySlide.gotoPage(options);
}
});
}
};
})(jQuery);