cuny-academic-commons / cbox-theme

Default theme for Commons In A Box
GNU General Public License v2.0
20 stars 15 forks source link

Enable bxSlider API #230

Closed christianwach closed 9 years ago

christianwach commented 9 years ago

I've been making progress with #207 for a client project but can't get the bxSlider API to function without the changes to the way it's being initialised. When inited with auto = true, subsequent calls to startAuto() and stopAuto() fail silently, so this PR issues startAuto() directly after the slider init. This does not change how the slider behaves, but does enable starting and stopping the slideshow via code.

The PR also introduces a global scope variable cbox_slider which is the slider instance because there are no methods of retrieving the bxSlider instance in its API. This variable means that the slider can be addressed and controlled externally, which is necessary for making it play better with videos.

At present, I have only got the slider to work better with YouTube videos, but it looks like it's possible to do this with Vimeo too. Here's how to get things working...

In 'functions.php' or in a plugin, add the following filter which enables the YouTube API on the videos that are embedded in the slider:

/**
 * Filter YouTube URL to enable API
 */
function my_wp_embed_handler_youtube( $html, $url, $attr, $post_ID ) {
    // do we have an oembed?
    if ( false !== strpos( $html, 'feature=oembed' ) ) {
        // enable YouTube API on video
        $html = str_replace( 'feature=oembed', 'feature=oembed&enablejsapi=1', $html );
    }
    return $html;
}
add_filter( 'embed_oembed_html', 'my_wp_embed_handler_youtube', 10, 4 );

Next, enqueue the following Javascript on the homepage:

// load YouTube Frame API
(function() { // closure, so as not to leak scope
    var s = document.createElement("script");
    s.src = (location.protocol == 'https:' ? 'https' : 'http') + "://www.youtube.com/player_api";
    var before = document.getElementsByTagName("script")[0];
    before.parentNode.insertBefore(s, before);
})();

/**
 * Define what happens when the page is ready
 */
jQuery(document).ready( function($) {

    /**
     * Trap clicks on the pager
     */
    $('.bx-pager.bx-default-pager').click( function( event ) {
        // stop auto slider
        cbox_slider.stopAuto();
        // pause all videos
        $('.slide-video-embed iframe').each( function() {
            $(this).data('player').pauseVideo();
        });
    });

    /**
     * Callback for the YouTube API that fires when the API is ready
     */
    window.onYouTubeIframeAPIReady = function(){
        // iterate through videos
        $('.slide-video-embed iframe').each( function(){
            // create a new player pointer
            var player = new YT.Player( document.getElementById( $(this).attr('id') ) );
            // watch for changes on the player
            player.addEventListener( 'onStateChange', function(state) {
                switch( state.data ) {
                    // if a video is playing, stop the slider
                    case YT.PlayerState.PLAYING:
                        cbox_slider.stopAuto();
                        break;
                    // if the video is paused, start the slider
                    case YT.PlayerState.PAUSED:
                        cbox_slider.startAuto();
                        break;
                    // if the video has finished, go straight to next slide
                    case YT.PlayerState.ENDED:
                        cbox_slider.goToNextSlide();
                        break;
                }
            });
            // store
            $(this).data('player', player);
        });
    }
});

What you should see is that playing a YouTube video now pauses the slideshow, whilst pausing it restarts the slideshow. And when a video finishes, the next slide is immediately loaded.

I'd like to add a number of filters (or one monolithic filter) that allows the bxSlider init in 'engine/includes/feature-slider/setup.php' to be more adaptable. Thoughts?

christianwach commented 9 years ago

I've wrapped the above code into a plugin for testing this more easily. Requires the slider-control branch to work: https://github.com/christianwach/cbox-slider-video-fixes

christianwach commented 9 years ago

Wanted to add that I haven't included the YouTube API code in the PR because each video service that oembed supports needs to be supported individually. This PR allows the plugin above to be developed with a view to integrating once it supports enough services. Anyone had a chance to test yet?

r-a-y commented 9 years ago

PR looks fine to me.

Remove the blank lines for lines 208 and 222 and you got yourself a merge!

christianwach commented 9 years ago

@r-a-y Done. Also removed the redundant and commented-out auto option.

r-a-y commented 9 years ago

Thanks Christian!