Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Refactored impress.js into an object while maintaining backward-compatibility with v0.3 #112

Closed
wants to merge 20 commits into from

2 participants

@jeady

I refactored the impress.js source into an object with a couple of goals:

  • Easier to extend and customize
  • More concise source
  • More comments in the source
  • Backwards compatibility

I've managed to shave ~40 lines of code while (in my opinion at least) enhancing readability. The new impress function can either be constructed with new impress() in which case most CSS styles and parameters can be customized before beginning the presentation, or if simply called using impress() should return the same API you provided in v0.3. This is an enormous refactoring, I understand, so if you don't want to accept such a large pull request no worries at all, this was largely for my own use. I thought I'd offer my changes back in case anybody else is interested. Impress.js is fantastic, by the way. I'm really looking forward to seeing the kinds of presentations and websites that come out of tools like impress.js.

Keep up the fantastic work and let me know if you'd like to integrate my changes but would like me to make any more modifications first,
James

jeady added some commits
@jeady jeady Refactored impress.js into single monolithic function, to be converte…
…d to a class
509ffda
@jeady jeady Objectified impress 544fbaf
@jeady jeady Cleaned up setBrowserSpecificProperty, removed memoization because th…
…e overhead of not memoizing doesn't justify the added code complexity
cf1020c
@jeady jeady Replaced roots with a simple boolean because only one presentation ca…
…n run at a time anyways
c40d636
@jeady jeady Removed rootId as a parameter to start(), now use impress.root member…
… to change the root to something other than #impress
b9eae37
@jeady jeady Converted goto, next, and prev to be instance methods 64d6963
@jeady jeady Changed this.start to self.start to be consistent db49296
@jeady jeady Began cleaning up start. Moved a bunch of initial setup code to be co…
…nfigurable before calling start, removed unnecessary spaces, etc.
113272b
@jeady jeady First pass, full refactoring. Goto, prev, and next are public methods…
… now. Consolidated steps information into steps member variable
90aa04e
@jeady jeady I guess I forgot to move next() and prev(). They have now been moved. 3cd80d4
@jeady jeady Eliminated self.current and target 54ed6e0
@jeady jeady Consolidated click handlers 5193c47
@jeady jeady Lots of misc. cleanups f99db4a
@jeady jeady Merge branch 'master' of https://github.com/bartaz/impress.js 9f01682
@jeady jeady Updated comments, a little more cleanup 31f8c2e
@jeady jeady Moved the properties applied to each step to a customizable member va…
…riable
5fe486f
@jeady jeady Removed unnecessary self.presenting boolean e752a4d
@jeady jeady Added backward compatibility with impress.js 0.3 f8b89b5
@jeady jeady Reverting index.html because backward-compatibility has meen maintained b2bc34b
@jeady jeady Fixed some spacing issues, added usage comment, moved compatibility c…
…heck to be more prominent
37ae132
@bartaz
Owner

Impressive refactoring indeed.

But it's way to much for me to use it as it is. And I don't agree with all decisions you made there. I don't see allowing to use new impress() syntax as an improvement - there is no need for it at all (especially if you assume there can be only one impress object). Also removing memoization from prefixing function - it maybe saved you 2-3 lines of code, but it really is useful to save this results as most of the time the same properties are checked - transition transition-delay transform, etc. It doesn't make sense to check for them every time (I know it's just a short for loop).

So, thanks for your input. For sure I will be looking at your code in more details to search for inspiration and improvements.

@bartaz bartaz closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Feb 29, 2012
  1. @jeady
  2. @jeady

    Objectified impress

    jeady authored
  3. @jeady

    Cleaned up setBrowserSpecificProperty, removed memoization because th…

    jeady authored
    …e overhead of not memoizing doesn't justify the added code complexity
  4. @jeady
  5. @jeady

    Removed rootId as a parameter to start(), now use impress.root member…

    jeady authored
    … to change the root to something other than #impress
  6. @jeady
  7. @jeady
Commits on Mar 1, 2012
  1. @jeady

    Began cleaning up start. Moved a bunch of initial setup code to be co…

    jeady authored
    …nfigurable before calling start, removed unnecessary spaces, etc.
  2. @jeady

    First pass, full refactoring. Goto, prev, and next are public methods…

    jeady authored
    … now. Consolidated steps information into steps member variable
  3. @jeady
  4. @jeady
  5. @jeady

    Consolidated click handlers

    jeady authored
  6. @jeady

    Lots of misc. cleanups

    jeady authored
Commits on Mar 3, 2012
  1. @jeady
  2. @jeady
  3. @jeady
  4. @jeady
Commits on Mar 4, 2012
  1. @jeady
  2. @jeady
  3. @jeady

    Fixed some spacing issues, added usage comment, moved compatibility c…

    jeady authored
    …heck to be more prominent
This page is out of date. Refresh to see the latest.
Showing with 355 additions and 396 deletions.
  1. +355 −396 js/impress.js
View
751 js/impress.js
@@ -15,412 +15,371 @@
* source: http://github.com/bartaz/impress.js/
*/
-(function ( document, window ) {
- 'use strict';
-
- // HELPER FUNCTIONS
-
- var pfx = (function () {
-
- var style = document.createElement('dummy').style,
- prefixes = 'Webkit Moz O ms Khtml'.split(' '),
- memory = {};
-
- return function ( prop ) {
- if ( typeof memory[ prop ] === "undefined" ) {
-
- var ucProp = prop.charAt(0).toUpperCase() + prop.substr(1),
- props = (prop + ' ' + prefixes.join(ucProp + ' ') + ucProp).split(' ');
-
- memory[ prop ] = null;
- for ( var i in props ) {
- if ( style[ props[i] ] !== undefined ) {
- memory[ prop ] = props[i];
- break;
- }
- }
-
- }
-
- return memory[ prop ];
- }
+// Usage:
+//
+// | var i = new impress();
+// | i.start();
+//
+function impress() {
+ // Added for backwards compatibility. If we're not being constructed as an object, behave like the old impress()
+ // function.
+ if (this.constructor != impress) {
+ var i = new impress();
+ i.start();
+ return {
+ goto: i.goto,
+ next: i.next,
+ prev: i.prev
+ };
+ }
+ var self = this;
- })();
+ // Change these before calling start() to alter the presentation configuration
+ self.root = null; // Set this to some HTMLElement to set the root element to somehing besides #impress
+ self.documentProperties = { // These properties are applied to the document element
+ height: "100%"
+ }
+ self.bodyProperties = { // These properties are applied to the body element when the presentation starts
+ height: "100%",
+ overflow: "hidden"
+ }
+ self.metaContent = { // These are converted to a string and applied as the meta viewport tag's content
+ 'width': '1024',
+ 'minimum-scale': '0.75',
+ 'maximum-scale': '0.75',
+ 'user-scalable': 'no'
+ }
+ self.rootProperties = { // These are applied only to the root
+ top: "50%",
+ left: "50%",
+ perspective: "1000px"
+ }
+ self.canvasProperties = { // These are applied to both the root and the canvas injected into it
+ position: "absolute",
+ transformOrigin: "top left",
+ transition: "all 0s ease-in-out",
+ transformStyle: "preserve-3d"
+ }
+ self.perStepProperties = { // These are applied to each step individually upon the start of the presentation
+ position: "absolute",
+ transform: "translate(-50%, -50%)",
+ transformStyle: "preserve-3d"
+ }
+ self.steps = null; // Once the presentation has started, this will contain the processed slide data
+ self.active_index = null;
+ self.hashTimeout = null;
+ // Check for browser support
+ self.supported = (setBrowserSpecificProperty("perspective") != null) &&
+ (document.body.classList) &&
+ (document.body.dataset) &&
+ (navigator.userAgent.toLowerCase().search(/(iphone)|(ipod)|(android)/) == - 1);
- var arrayify = function ( a ) {
- return [].slice.call( a );
- };
-
- var css = function ( el, props ) {
- var key, pkey;
- for ( key in props ) {
- if ( props.hasOwnProperty(key) ) {
- pkey = pfx(key);
- if ( pkey != null ) {
- el.style[pkey] = props[key];
- }
- }
- }
- return el;
+ // Pans to the slide specified by index_or_id, which is either a css ID, step element, or an index into self.steps
+ self.goto = function(index_el_or_id) {
+ var index = index_el_or_id;
+
+ // If we were passed a string (an id), convert it the index of the slide to go to
+ if (typeof index_el_or_id === "string") {
+ var el = self.steps.filter(function(e){return e.node.id == index_el_or_id;});
+ if (el && el.length > 0)
+ index = self.steps.indexOf(el[0]);
+ } else if (index_el_or_id instanceof HTMLElement) {
+ var el = self.steps.filter(function(e){return e.node == index_el_or_id;});
+ if (el && el.length > 0)
+ index = self.steps.indexOf(el[0]);
}
-
- var byId = function ( id ) {
- return document.getElementById(id);
+
+ // Make sure we successfully converted whatever the user passed in into a valid index
+ if (typeof index !== "number" || index < 0 || index >= self.steps.length || self.active_index == index)
+ return false;
+
+ // Sometimes it's possible to trigger focus on first link with some keyboard action.
+ // Browser in such a case tries to scroll the page to make this element visible
+ // (even that body overflow is set to hidden) and it breaks our careful positioning.
+ //
+ // So, as a lousy (and lazy) workaround we will make the page scroll back to the top
+ // whenever slide is selected
+ //
+ // If you are reading this and know any better way to handle it, I'll be glad to hear about it!
+ window.scrollTo(0, 0);
+
+ // step is the slide we are transitioning to, active is the one we are transitioning from
+ var step = self.steps[index];
+ var active = (null != self.active_index ? self.steps[self.active_index] : null);
+
+ // Change the .active class from active to step, update the root to reflect the classname of the current step
+ if (null != active)
+ active.node.classList.remove("active");
+ step.node.classList.add("active");
+ self.root.className = "step-" + step.node.id;
+
+ // `#/step-id` is used instead of `#step-id` to prevent default browser
+ // scrolling to element in hash
+ //
+ // and it has to be set after animation finishes, because in chrome it
+ // causes transtion being laggy
+ window.clearTimeout(self.hashTimeout);
+ self.hashTimeout = window.setTimeout(function() {
+ window.location.hash = "#/" + step.node.id;
+ }, 1000);
+
+ // check if the transition is zooming in or not
+ var zoomin = (1 / step.scale) >= (null != active ? 1 / active.scale : 1);
+
+ // if presentation starts (nothing is active yet), don't animate (set duration to 0)
+ var duration = (null != self.active_index) ? "1s": "0";
+
+ css(self.root, {
+ // to keep the perspective look similar for different scales
+ // we need to 'scale' the perspective, too
+ perspective: step.scale * 1000 + "px",
+ transform: scale(1 / step.scale),
+ transitionDuration: duration,
+ transitionDelay: (zoomin ? "500ms": "0ms")
+ });
+ css(self.canvas, {
+ transform: rotate(step.rotate, true) + translate(step.translate, true),
+ transitionDuration: duration,
+ transitionDelay: (zoomin ? "0ms": "500ms")
+ });
+ self.active_index = index;
+
+ return step.node;
+ };
+
+ // Immediately pan to the previous slide
+ self.prev = function() {
+ return self.goto((self.active_index + self.steps.length - 1) % self.steps.length);
+ };
+
+ // Immediately pan to the next slide
+ self.next = function() {
+ return self.goto((self.active_index + 1) % self.steps.length);
+ };
+
+ // Takes a property that is still only implemented using vendor-specific styles and applies the correct
+ // vendor-specific style for the current browser, e.g.
+ //
+ // setBrowserSpecificProperty("perspective")
+ // -> "WebkitPerspective"
+ function setBrowserSpecificProperty(prop) {
+ var style = document.body.style; // No reason for this particular tag, just want the style
+ var prefixes = ['Webkit', 'Moz', 'O', 'ms', 'Khtml'];
+ var ucProp = prop.charAt(0).toUpperCase() + prop.substr(1);
+ var props = prefixes.map(function(prefix){return prefix + ucProp;}).concat(prop);
+
+ for (var i in props) {
+ if (style[props[i]] !== undefined) {
+ return props[i];
+ }
}
-
- var $ = function ( selector, context ) {
- context = context || document;
- return context.querySelector(selector);
- };
-
- var $$ = function ( selector, context ) {
- context = context || document;
- return arrayify( context.querySelectorAll(selector) );
- };
-
- var translate = function ( t ) {
- return " translate3d(" + t.x + "px," + t.y + "px," + t.z + "px) ";
- };
-
- var rotate = function ( r, revert ) {
- var rX = " rotateX(" + r.x + "deg) ",
- rY = " rotateY(" + r.y + "deg) ",
- rZ = " rotateZ(" + r.z + "deg) ";
-
- return revert ? rZ+rY+rX : rX+rY+rZ;
- };
-
- var scale = function ( s ) {
- return " scale(" + s + ") ";
- };
-
- var getElementFromUrl = function () {
- // get id from url # by removing `#` or `#/` from the beginning,
- // so both "fallback" `#slide-id` and "enhanced" `#/slide-id` will work
- return byId( window.location.hash.replace(/^#\/?/,"") );
- };
-
- // CHECK SUPPORT
-
- var ua = navigator.userAgent.toLowerCase();
- var impressSupported = ( pfx("perspective") != null ) &&
- ( document.body.classList ) &&
- ( document.body.dataset ) &&
- ( ua.search(/(iphone)|(ipod)|(android)/) == -1 );
-
- var roots = {};
-
- var impress = window.impress = function ( rootId ) {
-
- rootId = rootId || "impress";
-
- // if already initialized just return the API
- if (roots["impress-root-" + rootId]) {
- return roots["impress-root-" + rootId];
- }
-
- // DOM ELEMENTS
-
- var root = byId( rootId );
-
- if (!impressSupported) {
- root.className = "impress-not-supported";
- return;
- } else {
- root.className = "";
- }
-
- // viewport updates for iPad
- var meta = $("meta[name='viewport']") || document.createElement("meta");
- // hardcoding these values looks pretty bad, as they kind of depend on the content
- // so they should be at least configurable
- meta.content = "width=1024, minimum-scale=0.75, maximum-scale=0.75, user-scalable=no";
- if (meta.parentNode != document.head) {
- meta.name = 'viewport';
- document.head.appendChild(meta);
- }
-
- var canvas = document.createElement("div");
- canvas.className = "canvas";
-
- arrayify( root.childNodes ).forEach(function ( el ) {
- canvas.appendChild( el );
- });
- root.appendChild(canvas);
-
- var steps = $$(".step", root);
-
- // SETUP
- // set initial values and defaults
-
- document.documentElement.style.height = "100%";
-
- css(document.body, {
- height: "100%",
- overflow: "hidden"
- });
-
- var props = {
- position: "absolute",
- transformOrigin: "top left",
- transition: "all 0s ease-in-out",
- transformStyle: "preserve-3d"
- }
-
- css(root, props);
- css(root, {
- top: "50%",
- left: "50%",
- perspective: "1000px"
- });
- css(canvas, props);
-
- var current = {
- translate: { x: 0, y: 0, z: 0 },
- rotate: { x: 0, y: 0, z: 0 },
- scale: 1
- };
-
- var stepData = {};
-
- var isStep = function ( el ) {
- return !!(el && el.id && stepData["impress-" + el.id]);
- }
-
- steps.forEach(function ( el, idx ) {
- var data = el.dataset,
- step = {
- translate: {
- x: data.x || 0,
- y: data.y || 0,
- z: data.z || 0
- },
- rotate: {
- x: data.rotateX || 0,
- y: data.rotateY || 0,
- z: data.rotateZ || data.rotate || 0
- },
- scale: data.scale || 1,
- el: el
- };
-
- if ( !el.id ) {
- el.id = "step-" + (idx + 1);
- }
-
- stepData["impress-" + el.id] = step;
-
- css(el, {
- position: "absolute",
- transform: "translate(-50%,-50%)" +
- translate(step.translate) +
- rotate(step.rotate) +
- scale(step.scale),
- transformStyle: "preserve-3d"
- });
-
- });
-
- // making given step active
-
- var active = null;
- var hashTimeout = null;
-
- var goto = function ( el ) {
- if ( !isStep(el) || el == active) {
- // selected element is not defined as step or is already active
- return false;
- }
-
- // Sometimes it's possible to trigger focus on first link with some keyboard action.
- // Browser in such a case tries to scroll the page to make this element visible
- // (even that body overflow is set to hidden) and it breaks our careful positioning.
- //
- // So, as a lousy (and lazy) workaround we will make the page scroll back to the top
- // whenever slide is selected
- //
- // If you are reading this and know any better way to handle it, I'll be glad to hear about it!
- window.scrollTo(0, 0);
-
- var step = stepData["impress-" + el.id];
-
- if ( active ) {
- active.classList.remove("active");
- }
- el.classList.add("active");
-
- root.className = "step-" + el.id;
-
- // `#/step-id` is used instead of `#step-id` to prevent default browser
- // scrolling to element in hash
- //
- // and it has to be set after animation finishes, because in chrome it
- // causes transtion being laggy
- window.clearTimeout( hashTimeout );
- hashTimeout = window.setTimeout(function () {
- window.location.hash = "#/" + el.id;
- }, 1000);
-
- var target = {
- rotate: {
- x: -parseInt(step.rotate.x, 10),
- y: -parseInt(step.rotate.y, 10),
- z: -parseInt(step.rotate.z, 10)
- },
- translate: {
- x: -step.translate.x,
- y: -step.translate.y,
- z: -step.translate.z
- },
- scale: 1 / parseFloat(step.scale)
- };
-
- // check if the transition is zooming in or not
- var zoomin = target.scale >= current.scale;
-
- // if presentation starts (nothing is active yet)
- // don't animate (set duration to 0)
- var duration = (active) ? "1s" : "0";
-
- css(root, {
- // to keep the perspective look similar for different scales
- // we need to 'scale' the perspective, too
- perspective: step.scale * 1000 + "px",
- transform: scale(target.scale),
- transitionDuration: duration,
- transitionDelay: (zoomin ? "500ms" : "0ms")
- });
-
- css(canvas, {
- transform: rotate(target.rotate, true) + translate(target.translate),
- transitionDuration: duration,
- transitionDelay: (zoomin ? "0ms" : "500ms")
- });
-
- current = target;
- active = el;
-
- return el;
- };
-
- var prev = function () {
- var prev = steps.indexOf( active ) - 1;
- prev = prev >= 0 ? steps[ prev ] : steps[ steps.length-1 ];
-
- return goto(prev);
- };
-
- var next = function () {
- var next = steps.indexOf( active ) + 1;
- next = next < steps.length ? steps[ next ] : steps[ 0 ];
-
- return goto(next);
- };
-
- window.addEventListener("hashchange", function () {
- goto( getElementFromUrl() );
- }, false);
-
- window.addEventListener("orientationchange", function () {
- window.scrollTo(0, 0);
- }, false);
-
- // START
- // by selecting step defined in url or first step of the presentation
- goto(getElementFromUrl() || steps[0]);
-
- return (roots[ "impress-root-" + rootId ] = {
- goto: goto,
- next: next,
- prev: prev
- });
+ }
+ // Used to ease iterating over NodeLists
+ Object.prototype.arrayify = function() {
+ return [].slice.call(this);
+ };
+
+ // Used to convert self.metaContent into a valid meta content string
+ Object.prototype.stringify = function() {
+ var fields = [];
+ for (var key in this) {
+ if (this.hasOwnProperty(key))
+ fields.push(key + '=' + this[key]);
}
-})(document, window);
-
-// EVENTS
-
-(function ( document, window ) {
- 'use strict';
-
- // keyboard navigation handler
- document.addEventListener("keydown", function ( event ) {
- if ( event.keyCode == 9 || ( event.keyCode >= 32 && event.keyCode <= 34 ) || (event.keyCode >= 37 && event.keyCode <= 40) ) {
- switch( event.keyCode ) {
- case 33: ; // pg up
- case 37: ; // left
- case 38: // up
- impress().prev();
- break;
- case 9: ; // tab
- case 32: ; // space
- case 34: ; // pg down
- case 39: ; // right
- case 40: // down
- impress().next();
- break;
- }
-
- event.preventDefault();
+ return fields.join(',');
+ };
+
+ // Set the specified properties on the specified HTML element, converting properties
+ // to their browser-specific counterparts when necessary
+ function css(el, props) {
+ var key, pkey;
+ for (key in props) {
+ if (props.hasOwnProperty(key)) {
+ pkey = setBrowserSpecificProperty(key);
+ if (pkey != null) {
+ el.style[pkey] = props[key];
}
+ }
+ }
+ return el;
+ }
+
+ // Shorthand to create translate3d CSS property from an object of the form {x:..., y:..., z:...}.
+ // Revert specifies whether this property should be negated. Negation is used to that we can move
+ // the canvas so that the current slide is centered (has a translation of {0,0,0}).
+ function translate(t, revert) {
+ var negate = revert ? -1 : 1;
+ return " translate3d(" + negate * t.x + "px," + negate * t.y + "px," + negate * t.z + "px) ";
+ };
+
+ // Shorthand to create the rotate3d CSS property from an object of the form {x:..., y:..., z:...}.
+ // Revert specifies whether this property should be negated, so that when the same property is applied
+ // to the canvas and a slide, once negated and once not, the result will be oriented normally.
+ function rotate(r, revert) {
+ var negate = revert ? -1 : 1;
+ var rX = " rotateX(" + negate * r.x + "deg) ",
+ rY = " rotateY(" + negate * r.y + "deg) ",
+ rZ = " rotateZ(" + negate * r.z + "deg) ";
+
+ return revert ? rZ + rY + rX: rX + rY + rZ;
+ };
+
+ // Shorthand for CSS scale property
+ function scale(s) {
+ return " scale(" + s + ") ";
+ };
+
+ // Call this to begin the impress presentation
+ self.start = function() {
+
+ // Only allow a single presentation at a time
+ if (null != self.steps)
+ return;
+
+ // If the user has overridden the root, use their root instead of #impress
+ if (null == self.root)
+ self.root = document.getElementById('impress');
+
+ // If impress is not supported, set the error style and exit
+ if (!self.supported) {
+ self.root.className = "impress-not-supported";
+ return;
+ } else {
+ self.root.className = "";
+ }
+
+ // Set the viewport for iPad
+ var meta = document.querySelector("meta[name='viewport']") || document.createElement("meta");
+ meta.content = self.metaContent.stringify();
+ if (meta.parentNode != document.head) {
+ meta.name = 'viewport';
+ document.head.appendChild(meta);
+ }
+
+ // Inject the canvas element to draw on between the root and its children
+ self.canvas = document.createElement("div");
+ self.canvas.className = "canvas";
+ self.root.childNodes.arrayify().forEach(function(el) {
+ self.canvas.appendChild(el);
+ });
+ self.root.appendChild(self.canvas);
+
+ // set initial values and defaults
+ css(document.documentElement, self.documentProperties);
+ css(document.body, self.bodyProperties);
+ css(self.root, self.canvasProperties);
+ css(self.root, self.rootProperties);
+ css(self.canvas, self.canvasProperties);
+
+ // Calculate the transformations required for each step
+ self.steps = [];
+ self.root.querySelectorAll(".step").arrayify().forEach(function(el, idx) {
+ var data = el.dataset,
+ step = {
+ node: el,
+ translate: {
+ x: parseInt(data.x, 10) || 0,
+ y: parseInt(data.y, 10) || 0,
+ z: parseInt(data.z, 10) || 0
+ },
+ rotate: {
+ x: data.rotateX || 0,
+ y: data.rotateY || 0,
+ z: data.rotateZ || data.rotate || 0
+ },
+ scale: parseFloat(data.scale) || 1,
+ el: el
+ };
+
+ if (!el.id) {
+ el.id = "step-" + (idx + 1);
+ }
+
+ self.steps.push(step);
+
+ // Apply the transformation. We use self.perStepProperties for extensibility, but are going to
+ // have to change the transform property. So remember what it was before and reset it afterwards.
+ var oldTransform = self.perStepProperties.transform;
+ if ("string" !== typeof oldTransform)
+ self.perStepProperties.transform = ""
+ self.perStepProperties.transform += translate(step.translate) + rotate(step.rotate) + scale(step.scale);
+ css(el, self.perStepProperties);
+ self.perStepProperties.transform = oldTransform
+ });
+
+ window.addEventListener("hashchange", function() {
+ self.goto(getElementFromUrl());
}, false);
-
- // delegated handler for clicking on the links to presentation steps
- document.addEventListener("click", function ( event ) {
- // event delegation with "bubbling"
- // check if event target (or any of its parents is a link)
- var target = event.target;
- while ( (target.tagName != "A") &&
- (target != document.body) ) {
- target = target.parentNode;
- }
-
- if ( target.tagName == "A" ) {
- var href = target.getAttribute("href");
-
- // if it's a link to presentation step, target this step
- if ( href && href[0] == '#' ) {
- target = document.getElementById( href.slice(1) );
- }
- }
-
- if ( impress().goto(target) ) {
- event.stopImmediatePropagation();
- event.preventDefault();
- }
+
+ window.addEventListener("orientationchange", function() {
+ window.scrollTo(0, 0);
}, false);
-
- // delegated handler for clicking on step elements
- document.addEventListener("click", function ( event ) {
- var target = event.target;
- // find closest step element
- while ( !target.classList.contains("step") &&
- (target != document.body) ) {
- target = target.parentNode;
- }
-
- if ( impress().goto(target) ) {
- event.preventDefault();
- }
+
+ // Attempt to get the id from url # by removing `#` or `#/` from the beginning,
+ // so both "fallback" `#slide-id` and "enhanced" `#/slide-id` will work. If we fail
+ // to get the id from the url, just go to the first slide.
+ self.goto(window.location.hash.replace(/^#\/?/, "") || 0);
+
+ document.addEventListener("keydown", function(event) {
+ switch (event.keyCode) {
+ case 33: // pg up
+ case 37: // left
+ case 38: // up
+ self.prev();
+ event.preventDefault();
+ break;
+ case 9: // tab
+ case 32: // space
+ case 34: // pg down
+ case 39: // right
+ case 40: // down
+ self.next();
+ event.preventDefault();
+ break;
+ }
}, false);
-
- // touch handler to detect taps on the left and right side of the screen
- 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 = impress().prev();
- } else if ( x > window.innerWidth - width ) {
- result = impress().next();
- }
-
- if (result) {
- event.preventDefault();
- }
+
+ // delegated handler for clicking on the links to presentation steps
+ document.addEventListener("click", function(event) {
+ // event delegation with "bubbling"
+ // check if event target (or any of its parents is a link)
+ var target = event.target;
+ while ((target.tagName != "A") && !target.classList.contains("step") && (target != document.body))
+ target = target.parentNode;
+
+ if (target.tagName == "A") {
+ var href = target.getAttribute("href");
+
+ // if it's a link to presentation step, target this step
+ if (href && href[0] == '#') {
+ target = href.slice(1);
}
+ } else {
+ target = target.id;
+ }
+
+ if (self.goto(target)) {
+ event.stopImmediatePropagation();
+ event.preventDefault();
+ }
}, false);
-})(document, window);
+ // touch handler to detect taps on the left and right side of the screen
+ 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 = self.prev();
+ else if (x > window.innerWidth - width)
+ result = self.next();
+
+ if (result)
+ event.preventDefault();
+ }
+ }, false);
+ }
+}
Something went wrong with that request. Please try again.