From 1bbf205bc71b89b0f72a83ac6a1e7f5c4c0f46b1 Mon Sep 17 00:00:00 2001 From: Bartek Szopka Date: Sat, 10 Mar 2012 22:36:08 +0000 Subject: [PATCH] "added impressive events when step is entered and left, triggered by transition end" --- js/impress.js | 95 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 76 insertions(+), 19 deletions(-) diff --git a/js/impress.js b/js/impress.js index c2458f43c..bf824e256 100644 --- a/js/impress.js +++ b/js/impress.js @@ -108,7 +108,7 @@ var getElementFromUrl = function () { // get id from url # by removing `#` or `#/` from the beginning, - // so both `#slide-id` and "legacy" `#/slide-id` will work + // so both "fallback" `#slide-id` and "enhanced" `#/slide-id` will work return byId( window.location.hash.replace(/^#\/?/,"") ); }; @@ -130,6 +130,16 @@ body.classList.add("impress-supported"); } + // cross-browser transitionEnd event name + // based on https://developer.mozilla.org/en/CSS/CSS_transitions + var transitionEnd = ({ + 'transition':'transitionEnd', + 'OTransition':'oTransitionEnd', + 'msTransition':'MSTransitionEnd', // who knows how it will end up? + 'MozTransition':'transitionend', + 'WebkitTransition':'webkitTransitionEnd' + })[pfx("transition")]; + var roots = {}; var defaults = { @@ -276,10 +286,44 @@ }); - // making given step active - var active = null; - var hashTimeout = null; + + // step events + + var triggerEvent = function (el, eventName) { + var event = document.createEvent("CustomEvent"); + event.initCustomEvent(eventName, true, true); + el.dispatchEvent(event); + }; + + var lastEntered = null; + var onStepEnter = function (step) { + if (lastEntered !== step) { + triggerEvent(step, "impressStepEnter"); + lastEntered = step; + } + }; + + var onStepLeave = function (step) { + if (lastEntered === step) { + triggerEvent(step, "impressStepLeave"); + } + }; + + + // transitionEnd event handler + + var expectedTransitionTarget = null; + + var onTransitionEnd = function (event) { + // we only care about transitions on `root` and `canvas` elements + if (event.target === expectedTransitionTarget) { + onStepEnter(active); + event.stopPropagation(); // prevent propagation from `canvas` to `root` + } + }; + root.addEventListener(transitionEnd, onTransitionEnd, false); + canvas.addEventListener(transitionEnd, onTransitionEnd, false); var windowScale = computeWindowScale(); @@ -309,15 +353,6 @@ body.classList.add("impress-on-" + el.id); - // Setting fragment URL with `history.pushState` - // and it has to be set after animation finishes, because in Chrome it - // causes transtion being laggy - // BUG: http://code.google.com/p/chromium/issues/detail?id=62820 - window.clearTimeout( hashTimeout ); - hashTimeout = window.setTimeout(function () { - window.location.hash = "#/" + el.id; - }, config.transitionDuration); - var target = { rotate: { x: -step.rotate.x, @@ -337,8 +372,8 @@ // if presentation starts (nothing is active yet) // don't animate (set duration to 0) - var duration = (active) ? config.transitionDuration + "ms" : "0ms", - delay = (config.transitionDuration / 2) + "ms"; + var duration = (active) ? config.transitionDuration : 0, + delay = (config.transitionDuration / 2); if (force) { windowScale = computeWindowScale(); @@ -346,23 +381,33 @@ var targetScale = target.scale * windowScale; + expectedTransitionTarget = target.scale > current.scale ? root : canvas; + + if (active) { + onStepLeave(active); + } + css(root, { // to keep the perspective look similar for different scales // we need to 'scale' the perspective, too transform: perspective( config.perspective / targetScale ) + scale( targetScale ), - transitionDuration: duration, - transitionDelay: (zoomin ? delay : "0ms") + transitionDuration: duration + "ms", + transitionDelay: (zoomin ? delay : 0) + "ms" }); css(canvas, { transform: rotate(target.rotate, true) + translate(target.translate), - transitionDuration: duration, - transitionDelay: (zoomin ? "0ms" : delay) + transitionDuration: duration + "ms", + transitionDelay: (zoomin ? 0 : delay) + "ms" }); current = target; active = el; + if (duration === 0) { + onStepEnter(active); + } + return el; }; @@ -380,6 +425,18 @@ return stepTo(next); }; + // HASH CHANGE + + // `#/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 + // BUG: http://code.google.com/p/chromium/issues/detail?id=62820 + document.addEventListener("impressStepEnter", function (event) { + window.location.hash = "#/" + event.target.id; + }, false); + window.addEventListener("hashchange", function () { stepTo( getElementFromUrl() ); }, false);