+ *
+ * Following html attributes are supported for step elements:
+ *
+ * data-rel-x
+ * data-rel-y
+ * data-rel-z
+ *
+ * These values are also inherited from the previous step. This makes it easy to
+ * create a boring presentation where each slide shifts for example 1000px down
+ * from the previous.
+ *
+ * In addition to plain numbers, which are pixel values, it is also possible to
+ * define relative positions as a multiple of screen height and width, using
+ * a unit of "h" and "w", respectively, appended to the number.
+ *
+ * Example:
+ *
+ *
+ *
+ * This plugin is a *pre-init plugin*. It is called synchronously from impress.js
+ * core at the beginning of `impress().init()`. This allows it to process its own
+ * data attributes first, and possibly alter the data-x, data-y and data-z attributes
+ * that will then be processed by `impress().init()`.
+ *
+ * (Another name for this kind of plugin might be called a *filter plugin*, but
+ * *pre-init plugin* is more generic, as a plugin might do whatever it wants in
+ * the pre-init stage.)
+ *
+ * Copyright 2016 Henrik Ingo (@henrikingo)
+ * Released under the MIT license.
+ */
+
+/* global document, window */
+
+( function( document, window ) {
+ "use strict";
+
+ var startingState = {};
+
+ /**
+ * Copied from core impress.js. We currently lack a library mechanism to
+ * to share utility functions like this.
+ */
+ var toNumber = function( numeric, fallback ) {
+ return isNaN( numeric ) ? ( fallback || 0 ) : Number( numeric );
+ };
+
+ /**
+ * Extends toNumber() to correctly compute also relative-to-screen-size values 5w and 5h.
+ *
+ * Returns the computed value in pixels with w/h postfix removed.
+ */
+ var toNumberAdvanced = function( numeric, fallback ) {
+ if ( typeof numeric !== "string" ) {
+ return toNumber( numeric, fallback );
+ }
+ var ratio = numeric.match( /^([+-]*[\d\.]+)([wh])$/ );
+ if ( ratio == null ) {
+ return toNumber( numeric, fallback );
+ } else {
+ var value = parseFloat( ratio[ 1 ] );
+ var multiplier = ratio[ 2 ] === "w" ? window.innerWidth : window.innerHeight;
+ return value * multiplier;
+ }
+ };
+
+ var computeRelativePositions = function( el, prev ) {
+ var data = el.dataset;
+
+ if ( !prev ) {
+
+ // For the first step, inherit these defaults
+ prev = { x:0, y:0, z:0, relative: { x:0, y:0, z:0 } };
+ }
+
+ var step = {
+ x: toNumber( data.x, prev.x ),
+ y: toNumber( data.y, prev.y ),
+ z: toNumber( data.z, prev.z ),
+ relative: {
+ x: toNumberAdvanced( data.relX, prev.relative.x ),
+ y: toNumberAdvanced( data.relY, prev.relative.y ),
+ z: toNumberAdvanced( data.relZ, prev.relative.z )
+ }
+ };
+
+ // Relative position is ignored/zero if absolute is given.
+ // Note that this also has the effect of resetting any inherited relative values.
+ if ( data.x !== undefined ) {
+ step.relative.x = 0;
+ }
+ if ( data.y !== undefined ) {
+ step.relative.y = 0;
+ }
+ if ( data.z !== undefined ) {
+ step.relative.z = 0;
+ }
+
+ // Apply relative position to absolute position, if non-zero
+ // Note that at this point, the relative values contain a number value of pixels.
+ step.x = step.x + step.relative.x;
+ step.y = step.y + step.relative.y;
+ step.z = step.z + step.relative.z;
+
+ return step;
+ };
+
+ var rel = function( root ) {
+ var steps = root.querySelectorAll( ".step" );
+ var prev;
+ startingState[ root.id ] = [];
+ for ( var i = 0; i < steps.length; i++ ) {
+ var el = steps[ i ];
+ startingState[ root.id ].push( {
+ el: el,
+ x: el.getAttribute( "data-x" ),
+ y: el.getAttribute( "data-y" ),
+ z: el.getAttribute( "data-z" )
+ } );
+ var step = computeRelativePositions( el, prev );
+
+ // Apply relative position (if non-zero)
+ el.setAttribute( "data-x", step.x );
+ el.setAttribute( "data-y", step.y );
+ el.setAttribute( "data-z", step.z );
+ prev = step;
+ }
+ };
+
+ // Register the plugin to be called in pre-init phase
+ window.impress.addPreInitPlugin( rel );
+
+ // Register teardown callback to reset the data.x, .y, .z values.
+ document.addEventListener( "impress:init", function( event ) {
+ var root = event.target;
+ event.detail.api.lib.gc.addCallback( function() {
+ var steps = startingState[ root.id ];
+ var step;
+ while ( step = steps.pop() ) {
+ if ( step.x === null ) {
+ step.el.removeAttribute( "data-x" );
+ } else {
+ step.el.setAttribute( "data-x", step.x );
+ }
+ if ( step.y === null ) {
+ step.el.removeAttribute( "data-y" );
+ } else {
+ step.el.setAttribute( "data-y", step.y );
+ }
+ if ( step.z === null ) {
+ step.el.removeAttribute( "data-z" );
+ } else {
+ step.el.setAttribute( "data-z", step.z );
+ }
+ }
+ delete startingState[ root.id ];
+ } );
+ }, false );
+} )( document, window );
+
+
/**
* Resize plugin
*
@@ -1316,3 +1665,39 @@
} )( document, window );
+
+/**
+ * Stop Plugin
+ *
+ * Example:
+ *
+ *
+ *
+ *
+ * Copyright 2016 Henrik Ingo (@henrikingo)
+ * Released under the MIT license.
+ */
+/* global document, window */
+( function( document, window ) {
+ "use strict";
+
+ var stop = function( event ) {
+ if ( ( !event ) || ( !event.target ) ) {
+ return;
+ }
+
+ if ( event.target.classList.contains( "stop" ) ) {
+ if ( event.detail.reason === "next" ) {
+ return false;
+ }
+ }
+ };
+
+ // Register the plugin to be called in pre-stepleave phase
+ // The weight makes this plugin run fairly early.
+ window.impress.addPreStepLeavePlugin( stop, 2 );
+
+} )( document, window );
+
diff --git a/src/plugins/rel/rel.js b/src/plugins/rel/rel.js
index 4a0204a..c57fe54 100644
--- a/src/plugins/rel/rel.js
+++ b/src/plugins/rel/rel.js
@@ -47,10 +47,17 @@
( function( document, window ) {
"use strict";
- var lib;
var startingState = {};
+ /**
+ * Copied from core impress.js. We currently lack a library mechanism to
+ * to share utility functions like this.
+ */
+ var toNumber = function( numeric, fallback ) {
+ return isNaN( numeric ) ? ( fallback || 0 ) : Number( numeric );
+ };
+
/**
* Extends toNumber() to correctly compute also relative-to-screen-size values 5w and 5h.
*
@@ -58,11 +65,11 @@
*/
var toNumberAdvanced = function( numeric, fallback ) {
if ( typeof numeric !== "string" ) {
- return lib.util.toNumber( numeric, fallback );
+ return toNumber( numeric, fallback );
}
var ratio = numeric.match( /^([+-]*[\d\.]+)([wh])$/ );
if ( ratio == null ) {
- return lib.util.toNumber( numeric, fallback );
+ return toNumber( numeric, fallback );
} else {
var value = parseFloat( ratio[ 1 ] );
var multiplier = ratio[ 2 ] === "w" ? window.innerWidth : window.innerHeight;
@@ -80,9 +87,9 @@
}
var step = {
- x: lib.util.toNumber( data.x, prev.x ),
- y: lib.util.toNumber( data.y, prev.y ),
- z: lib.util.toNumber( data.z, prev.z ),
+ x: toNumber( data.x, prev.x ),
+ y: toNumber( data.y, prev.y ),
+ z: toNumber( data.z, prev.z ),
relative: {
x: toNumberAdvanced( data.relX, prev.relative.x ),
y: toNumberAdvanced( data.relY, prev.relative.y ),
@@ -139,8 +146,7 @@
// Register teardown callback to reset the data.x, .y, .z values.
document.addEventListener( "impress:init", function( event ) {
var root = event.target;
- lib = event.detail.api.lib;
- lib.gc.addCallback( function() {
+ event.detail.api.lib.gc.addCallback( function() {
var steps = startingState[ root.id ];
var step;
while ( step = steps.pop() ) {