Skip to content

Commit

Permalink
Merge pull request #622 from henrikingo/plugin-framework
Browse files Browse the repository at this point in the history
Introduce plugin framework
  • Loading branch information
henrikingo authored Oct 2, 2017
2 parents c58b7b8 + ab30317 commit 9198ca8
Show file tree
Hide file tree
Showing 12 changed files with 1,471 additions and 106 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/js/impress.min.js
/node_modules
/npm-debug.log
1 change: 1 addition & 0 deletions .jshintrc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"module": true
},
"boss": true,
"browser": true,
"curly": true,
"eqeqeq": true,
"eqnull": true,
Expand Down
12 changes: 12 additions & 0 deletions build.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
var buildify = require('buildify');

buildify()
.load('src/impress.js')
.concat(['src/plugins/navigation/navigation.js',
'src/plugins/resize/resize.js'])
.save('js/impress.js');
/*
* Disabled until uglify supports ES6: https://github.com/mishoo/UglifyJS2/issues/448
.uglify()
.save('js/impress.min.js');
*/
255 changes: 155 additions & 100 deletions js/impress.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@
* source: http://github.com/bartaz/impress.js/
*/

/*jshint bitwise:true, curly:true, eqeqeq:true, forin:true, latedef:true, newcap:true,
noarg:true, noempty:true, undef:true, strict:true, browser:true */

// You are one of those who like to know how things work inside?
// Let me show you the cogs that make impress.js run...
( function( document, window ) {
Expand Down Expand Up @@ -213,7 +210,7 @@

// And that's where interesting things will start to happen.
// It's the core `impress` function that returns the impress.js API
// for a presentation based on the element with given id ('impress'
// for a presentation based on the element with given id ("impress"
// by default).
var impress = window.impress = function( rootId ) {

Expand Down Expand Up @@ -419,9 +416,8 @@
// Used to reset timeout for `impress:stepenter` event
var stepEnterTimeout = null;

// `goto` API function that moves to step given with `el` parameter
// (by index, id or element), with a transition `duration` optionally
// given as second parameter.
// `goto` API function that moves to step given as `el` parameter (by index, id or element).
// `duration` optionally given as second parameter, is the transition duration in css.
var goto = function( el, duration ) {

if ( !initialized || !( el = getStep( el ) ) ) {
Expand Down Expand Up @@ -496,16 +492,15 @@
// being animated separately:
// `root` is used for scaling and `canvas` for translate and rotations.
// Transitions on them are triggered with different delays (to make
// visually nice and 'natural' looking transitions), so we need to know
// visually nice and "natural" looking transitions), so we need to know
// that both of them are finished.
css( root, {

// To keep the perspective look similar for different scales
// we need to "scale" the perspective, too
// For IE 11 support we must specify perspective independent
// of transform.
perspective: ( config.perspective / targetScale ) + "px",

// To keep the perspective look similar for different scales
// we need to 'scale' the perspective, too
transform: scale( targetScale ),
transitionDuration: duration + "ms",
transitionDelay: ( zoomin ? delay : 0 ) + "ms"
Expand All @@ -526,8 +521,7 @@
// account.
//
// I know that this `if` statement looks scary, but it's pretty simple when you know
// what is going on
// - it's simply comparing all the values.
// what is going on - it's simply comparing all the values.
if ( currentState.scale === target.scale ||
( currentState.rotate.x === target.rotate.x &&
currentState.rotate.y === target.rotate.y &&
Expand All @@ -543,22 +537,20 @@
activeStep = el;

// And here is where we trigger `impress:stepenter` event.
// We simply set up a timeout to fire it taking transition duration
// (and possible delay) into account.
// We simply set up a timeout to fire it taking transition duration (and possible delay)
// into account.
//
// I really wanted to make it in more elegant way. The `transitionend` event seemed to
// be the best way to do it, but the fact that I'm using transitions on two separate
// elements and that the `transitionend` event is only triggered when there was a
// transition (change in the values) caused some bugs and made the code really
// complicated, cause I had to handle all the conditions separately. And it still
// needed a `setTimeout` fallback for the situations when there is no transition at
// all.
// needed a `setTimeout` fallback for the situations when there is no transition at all.
// So I decided that I'd rather make the code simpler than use shiny new
// `transitionend`.
//
// If you want learn something interesting and see how it was done with `transitionend`
// go back to
// version 0.5.2 of impress.js:
// go back to version 0.5.2 of impress.js:
// http://github.com/bartaz/impress.js/blob/0.5.2/js/impress.js
window.clearTimeout( stepEnterTimeout );
stepEnterTimeout = window.setTimeout( function() {
Expand Down Expand Up @@ -667,28 +659,45 @@

} )( document, window );

// NAVIGATION EVENTS

// As you can see this part is separate from the impress.js core code.
// It's because these navigation actions only need what impress.js provides with
// its simple API.
// THAT'S ALL FOLKS!
//
// In future I think about moving it to make them optional, move to separate files
// and treat more like a 'plugins'.
( function( document, window ) {
// Thanks for reading it all.
// Or thanks for scrolling down and reading the last part.
//
// I've learnt a lot when building impress.js and I hope this code and comments
// will help somebody learn at least some part of it.

/**
* Navigation events plugin
*
* As you can see this part is separate from the impress.js core code.
* It's because these navigation actions only need what impress.js provides with
* its simple API.
*
* This plugin is what we call an _init plugin_. It's a simple kind of
* impress.js plugin. When loaded, it starts listening to the `impress:init`
* event. That event listener initializes the plugin functionality - in this
* case we listen to some keypress and mouse events. The only dependencies on
* core impress.js functionality is the `impress:init` method, as well as using
* the public api `next(), prev(),` etc when keys are pressed.
*
* Copyright 2011-2012 Bartek Szopka (@bartaz)
* Released under the MIT license.
* ------------------------------------------------
* author: Bartek Szopka
* version: 0.5.3
* url: http://bartaz.github.com/impress.js/
* source: http://github.com/bartaz/impress.js/
*
*/
/* global document */
( function( document ) {
"use strict";

// Throttling function calls, by Remy Sharp
// http://remysharp.com/2010/07/21/throttling-function-calls/
var throttle = function( fn, delay ) {
var timer = null;
return function() {
var context = this, args = arguments;
clearTimeout( timer );
timer = setTimeout( function() {
fn.apply( context, args );
}, delay );
};
var triggerEvent = function( el, eventName, detail ) {
var event = document.createEvent( "CustomEvent" );
event.initCustomEvent( eventName, true, true, detail );
el.dispatchEvent( event );
};

// Wait for impress.js to be initialized
Expand All @@ -700,19 +709,6 @@
// need to control the presentation that was just initialized.
var api = event.detail.api;

// KEYBOARD NAVIGATION HANDLERS

// Prevent default keydown action when one of supported key is pressed.
document.addEventListener( "keydown", function( event ) {
if ( event.keyCode === 9 ||
( event.keyCode >= 32 && event.keyCode <= 34 ) ||
( event.keyCode >= 37 && event.keyCode <= 40 ) ) {
event.preventDefault();
}
}, false );

// Trigger impress action (next or prev) on keyup.

// Supported keys are:
// [space] - quite common in presentation software to move forward
// [up] [right] / [down] [left] - again common and natural addition,
Expand All @@ -726,30 +722,71 @@
// positioning. I didn't want to just prevent this default action, so I used [tab]
// as another way to moving to next step... And yes, I know that for the sake of
// consistency I should add [shift+tab] as opposite action...
document.addEventListener( "keyup", function( event ) {
var isNavigationEvent = function( event ) {

// Don't trigger navigation for example when user returns to browser window with ALT+TAB
if ( event.altKey || event.ctrlKey || event.metaKey ) {
return false;
}

if ( event.shiftKey || event.altKey || event.ctrlKey || event.metaKey ) {
return;
// In the case of TAB, we force step navigation always, overriding the browser
// navigation between input elements, buttons and links.
if ( event.keyCode === 9 ) {
return true;
}

if ( event.keyCode === 9 ||
( event.keyCode >= 32 && event.keyCode <= 34 ) ||
( event.keyCode >= 37 && event.keyCode <= 40 ) ) {
switch ( event.keyCode ) {
case 33: // Page up
case 37: // Left
case 38: // Up
api.prev();
break;
case 9: // Tab
case 32: // Space
case 34: // Page down
case 39: // Right
case 40: // Down
api.next();
break;
}
// With the sole exception of TAB, we also ignore keys pressed if shift is down.
if ( event.shiftKey ) {
return false;
}

// For arrows, etc, check that event target is html or body element. This is to allow
// presentations to have, for example, forms with input elements where user can type
// text, including space, and not move to next step.
if ( event.target.nodeName !== "BODY" && event.target.nodeName !== "HTML" ) {
return false;
}

if ( ( event.keyCode >= 32 && event.keyCode <= 34 ) ||
( event.keyCode >= 37 && event.keyCode <= 40 ) ) {
return true;
}
};

// KEYBOARD NAVIGATION HANDLERS

// Prevent default keydown action when one of supported key is pressed.
document.addEventListener( "keydown", function( event ) {
if ( isNavigationEvent( event ) ) {
event.preventDefault();
}
}, false );

// Trigger impress action (next or prev) on keyup.
document.addEventListener( "keyup", function( event ) {
if ( isNavigationEvent( event ) ) {
if ( event.shiftKey ) {
switch ( event.keyCode ) {
case 9: // Shift+tab
api.prev();
break;
}
} else {
switch ( event.keyCode ) {
case 33: // Pg up
case 37: // Left
case 38: // Up
api.prev( event );
break;
case 9: // Tab
case 32: // Space
case 34: // Pg down
case 39: // Right
case 40: // Down
api.next( event );
break;
}
}
event.preventDefault();
}
}, false );
Expand All @@ -758,7 +795,7 @@
document.addEventListener( "click", function( event ) {

// Event delegation with "bubbling"
// Check if event target (or any of its parents is a link)
// check if event target (or any of its parents is a link)
var target = event.target;
while ( ( target.tagName !== "A" ) &&
( target !== document.documentElement ) ) {
Expand Down Expand Up @@ -786,8 +823,8 @@

// Find closest step element that is not active
while ( !( target.classList.contains( "step" ) &&
!target.classList.contains( "active" ) ) &&
( target !== document.documentElement ) ) {
!target.classList.contains( "active" ) ) &&
( target !== document.documentElement ) ) {
target = target.parentNode;
}

Expand All @@ -796,41 +833,59 @@
}
}, false );

// Touch handler to detect taps on the left and right side of the screen
// based on awesome work of @hakimel: https://github.com/hakimel/reveal.js
document.addEventListener( "touchstart", function( event ) {
if ( event.touches.length === 1 ) {
var x = event.touches[ 0 ].clientX,
width = window.innerWidth * 0.3,
result = null;

if ( x < width ) {
result = api.prev();
} else if ( x > window.innerWidth - width ) {
result = api.next();
}
// Add a line to the help popup
triggerEvent( document, "impress:help:add",
{ command: "Left &amp; Right", text: "Previous &amp; Next step", row: 1 } );

if ( result ) {
event.preventDefault();
}
}
}, false );
}, false );

} )( document );


/**
* Resize plugin
*
* Rescale the presentation after a window resize.
*
* Copyright 2011-2012 Bartek Szopka (@bartaz)
* Released under the MIT license.
* ------------------------------------------------
* author: Bartek Szopka
* version: 0.5.3
* url: http://bartaz.github.com/impress.js/
* source: http://github.com/bartaz/impress.js/
*
*/

/* global document, window */

( function( document, window ) {
"use strict";

// Throttling function calls, by Remy Sharp
// http://remysharp.com/2010/07/21/throttling-function-calls/
var throttle = function( fn, delay ) {
var timer = null;
return function() {
var context = this, args = arguments;
window.clearTimeout( timer );
timer = window.setTimeout( function() {
fn.apply( context, args );
}, delay );
};
};

// Wait for impress.js to be initialized
document.addEventListener( "impress:init", function( event ) {
var api = event.detail.api;

// Rescale presentation when window is resized
window.addEventListener( "resize", throttle( function() {

// Force going to active step again, to trigger rescaling
api.goto( document.querySelector( ".step.active" ), 500 );
}, 250 ), false );

}, false );

} )( document, window );

// THAT'S ALL FOLKS!
//
// Thanks for reading it all.
// Or thanks for scrolling down and reading the last part.
//
// I've learnt a lot when building impress.js and I hope this code and comments
// will help somebody learn at least some part of it.
Loading

0 comments on commit 9198ca8

Please sign in to comment.