From 4bec5db356e5a764b27fac4a010681b0ddc6483f Mon Sep 17 00:00:00 2001 From: Henrik Ingo Date: Mon, 23 Oct 2017 23:01:02 +0300 Subject: [PATCH] Add autoplay plugin The autoplay plugin will automatically advance to the next slide after N seconds. --- src/plugins/autoplay/autoplay.js | 159 +++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 src/plugins/autoplay/autoplay.js diff --git a/src/plugins/autoplay/autoplay.js b/src/plugins/autoplay/autoplay.js new file mode 100644 index 0000000..86dc8eb --- /dev/null +++ b/src/plugins/autoplay/autoplay.js @@ -0,0 +1,159 @@ +/** + * Autoplay plugin - Automatically advance slideshow after N seconds + * + * Copyright 2016 Henrik Ingo, henrik.ingo@avoinelama.fi + * Released under the MIT license. + */ +/* global clearTimeout, setTimeout, document */ + +( function( document ) { + "use strict"; + + var autoplayDefault = 0; + var currentStepTimeout = 0; + var api = null; + var timeoutHandle = null; + var root = null; + var util; + + // On impress:init, check whether there is a default setting, as well as + // handle step-1. + document.addEventListener( "impress:init", function( event ) { + util = event.detail.api.lib.util; + + // Getting API from event data instead of global impress().init(). + // You don't even need to know what is the id of the root element + // or anything. `impress:init` event data gives you everything you + // need to control the presentation that was just initialized. + api = event.detail.api; + root = event.target; + + // Element attributes starting with "data-", become available under + // element.dataset. In addition hyphenized words become camelCased. + var data = root.dataset; + + if ( data.autoplay ) { + autoplayDefault = util.toNumber( data.autoplay, 0 ); + } + + var toolbar = document.querySelector( "#impress-toolbar" ); + if ( toolbar ) { + addToolbarButton( toolbar ); + } + + api.lib.gc.addCallback( function() { + clearTimeout( timeoutHandle ); + } ); + + // Note that right after impress:init event, also impress:stepenter is + // triggered for the first slide, so that's where code flow continues. + }, false ); + + // If default autoplay time was defined in the presentation root, or + // in this step, set timeout. + var reloadTimeout = function( event ) { + var step = event.target; + currentStepTimeout = util.toNumber( step.dataset.autoplay, autoplayDefault ); + if ( status === "paused" ) { + setAutoplayTimeout( 0 ); + } else { + setAutoplayTimeout( currentStepTimeout ); + } + }; + + document.addEventListener( "impress:stepenter", function( event ) { + reloadTimeout( event ); + }, false ); + + document.addEventListener( "impress:substep:stepleaveaborted", function( event ) { + reloadTimeout( event ); + }, false ); + + /** + * Set timeout after which we move to next() step. + */ + var setAutoplayTimeout = function( timeout ) { + if ( timeoutHandle ) { + clearTimeout( timeoutHandle ); + } + + if ( timeout > 0 ) { + timeoutHandle = setTimeout( function() { api.next(); }, timeout * 1000 ); + } + setButtonText(); + }; + + /*** Toolbar plugin integration *******************************************/ + var status = "not clicked"; + var toolbarButton = null; + + // Copied from core impress.js. Good candidate for moving to a utilities collection. + var triggerEvent = function( el, eventName, detail ) { + var event = document.createEvent( "CustomEvent" ); + event.initCustomEvent( eventName, true, true, detail ); + el.dispatchEvent( event ); + }; + + var makeDomElement = function( html ) { + var tempDiv = document.createElement( "div" ); + tempDiv.innerHTML = html; + return tempDiv.firstChild; + }; + + var toggleStatus = function() { + if ( currentStepTimeout > 0 && status !== "paused" ) { + status = "paused"; + } else { + status = "playing"; + } + }; + + var getButtonText = function() { + if ( currentStepTimeout > 0 && status !== "paused" ) { + return "||"; // Pause + } else { + return "▶"; // Play + } + }; + + var setButtonText = function() { + if ( toolbarButton ) { + + // Keep button size the same even if label content is changing + var buttonWidth = toolbarButton.offsetWidth; + var buttonHeight = toolbarButton.offsetHeight; + toolbarButton.innerHTML = getButtonText(); + if ( !toolbarButton.style.width ) { + toolbarButton.style.width = buttonWidth + "px"; + } + if ( !toolbarButton.style.height ) { + toolbarButton.style.height = buttonHeight + "px"; + } + } + }; + + var addToolbarButton = function( toolbar ) { + var html = '"; // jshint ignore:line + toolbarButton = makeDomElement( html ); + toolbarButton.addEventListener( "click", function() { + toggleStatus(); + if ( status === "playing" ) { + if ( autoplayDefault === 0 ) { + autoplayDefault = 7; + } + if ( currentStepTimeout === 0 ) { + currentStepTimeout = autoplayDefault; + } + setAutoplayTimeout( currentStepTimeout ); + } else if ( status === "paused" ) { + setAutoplayTimeout( 0 ); + } + } ); + + triggerEvent( toolbar, "impress:toolbar:appendChild", + { group: 10, element: toolbarButton } ); + }; + +} )( document );