1/** 2 * impress.js 3 * 4 * impress.js is a presentation tool based on the power of CSS3 transforms and transitions 5 * in modern browsers and inspired by the idea behind prezi.com. 6 * 7 * MIT Licensed. 8 * 9 * Copyright 2011 Bartek Szopka (@bartaz) 10 */ 11 12(function ( document, window ) { 13 'use strict'; 14 15 // HELPER FUNCTIONS 16 17 var pfx = (function () { 18 19 var style = document.createElement('dummy').style, 20 prefixes = 'Webkit Moz O ms Khtml'.split(' '), 21 memory = {}; 22 23 return function ( prop ) { 24 if ( typeof memory[ prop ] === "undefined" ) { 25 26 var ucProp = prop.charAt(0).toUpperCase() + prop.substr(1), 27 props = (prop + ' ' + prefixes.join(ucProp + ' ') + ucProp).split(' '); 28 29 memory[ prop ] = null; 30 for ( var i in props ) { 31 if ( style[ props[i] ] !== undefined ) { 32 memory[ prop ] = props[i]; 33 break; 34 } 35 } 36 37 } 38 39 return memory[ prop ]; 40 } 41 42 })(); 43 44 var arrayify = function ( a ) { 45 return [].slice.call( a ); 46 }; 47 48 var css = function ( el, props ) { 49 var key, pkey; 50 for ( key in props ) { 51 if ( props.hasOwnProperty(key) ) { 52 pkey = pfx(key); 53 if ( pkey != null ) { 54 el.style[pkey] = props[key]; 55 } 56 } 57 } 58 return el; 59 } 60 61 var byId = function ( id ) { 62 return document.getElementById(id); 63 } 64 65 var $ = function ( selector, context ) { 66 context = context || document; 67 return context.querySelector(selector); 68 }; 69 70 var $$ = function ( selector, context ) { 71 context = context || document; 72 return arrayify( context.querySelectorAll(selector) ); 73 }; 74 75 var translate = function ( t ) { 76 return " translate3d(" + t.x + "px," + t.y + "px," + t.z + "px) "; 77 }; 78 79 var rotate = function ( r, revert ) { 80 var rX = " rotateX(" + r.x + "deg) ", 81 rY = " rotateY(" + r.y + "deg) ", 82 rZ = " rotateZ(" + r.z + "deg) "; 83 84 return revert ? rZ+rY+rX : rX+rY+rZ; 85 }; 86 87 var scale = function ( s ) { 88 return " scale(" + s + ") "; 89 } 90 91 // CHECK SUPPORT 92 93 var ua = navigator.userAgent.toLowerCase(); 94 var impressSupported = ( pfx("perspective") != null ) && 95 ( ua.search(/(iphone)|(ipod)|(ipad)|(android)/) == -1 ); 96 97 // DOM ELEMENTS 98 99 var impress = byId("impress"); 100 101 if (!impressSupported) { 102 impress.className = "impress-not-supported"; 103 return; 104 } else { 105 impress.className = ""; 106 } 107 108 var canvas = document.createElement("div"); 109 canvas.className = "canvas"; 110 111 arrayify( impress.childNodes ).forEach(function ( el ) { 112 canvas.appendChild( el ); 113 }); 114 impress.appendChild(canvas); 115 116 var steps = $$(".step", impress); 117 118 // SETUP 119 // set initial values and defaults 120 121 document.documentElement.style.height = "100%"; 122 123 css(document.body, { 124 height: "100%", 125 overflow: "hidden" 126 }); 127 128 var props = { 129 position: "absolute", 130 transformOrigin: "top left", 131 transition: "all 0s ease-in-out", 132 transformStyle: "preserve-3d" 133 } 134 135 css(impress, props); 136 css(impress, { 137 top: "50%", 138 left: "50%", 139 perspective: "1000px" 140 }); 141 css(canvas, props); 142 143 var current = { 144 translate: { x: 0, y: 0, z: 0 }, 145 rotate: { x: 0, y: 0, z: 0 }, 146 scale: 1 147 }; 148 149 steps.forEach(function ( el, idx ) { 150 var data = el.dataset, 151 step = { 152 translate: { 153 x: data.x || 0, 154 y: data.y || 0, 155 z: data.z || 0 156 }, 157 rotate: { 158 x: data.rotateX || 0, 159 y: data.rotateY || 0, 160 z: data.rotateZ || data.rotate || 0 161 }, 162 scale: data.scale || 1 163 }; 164 165 el.stepData = step; 166 167 if ( !el.id ) { 168 el.id = "step-" + (idx + 1); 169 } 170 171 css(el, { 172 position: "absolute", 173 transform: "translate(-50%,-50%)" + 174 translate(step.translate) + 175 rotate(step.rotate) + 176 scale(step.scale), 177 transformStyle: "preserve-3d" 178 }); 179 180 }); 181 182 // making given step active 183 184 var active = null; 185 var hashTimeout = null; 186 187 var select = function ( el ) { 188 if ( !el || !el.stepData || el == active) { 189 // selected element is not defined as step or is already active 190 return false;
191 } 192 193 // Sometimes it's possible to trigger focus on first link with some keyboard action. 194 // Browser in such a case tries to scroll the page to make this element visible 195 // (even that body overflow is set to hidden) and it breaks our careful positioning. 196 // 197 // So, as a lousy (and lazy) workaround we will make the page scroll back to the top 198 // whenever slide is selected 199 // 200 // If you are reading this and know any better way to handle it, I'll be glad to hear about it! 201 window.scrollTo(0, 0); 202 203 var step = el.stepData; 204 205 if ( active ) { 206 active.classList.remove("active"); 207 } 208 el.classList.add("active"); 209 210 impress.className = "step-" + el.id; 211 212 // `#/step-id` is used instead of `#step-id` to prevent default browser 213 // scrolling to element in hash 214 // 215 // and it has to be set after animation finishes, because in chrome it 216 // causes transtion being laggy 217 window.clearTimeout( hashTimeout ); 218 hashTimeout = window.setTimeout(function () { 219 window.location.hash = "#/" + el.id; 220 }, 1000); 221 222 var target = { 223 rotate: { 224 x: -parseInt(step.rotate.x, 10), 225 y: -parseInt(step.rotate.y, 10), 226 z: -parseInt(step.rotate.z, 10) 227 }, 228 translate: { 229 x: -step.translate.x, 230 y: -step.translate.y, 231 z: -step.translate.z 232 }, 233 scale: 1 / parseFloat(step.scale) 234 }; 235 236 // check if the transition is zooming in or not 237 var zoomin = target.scale >= current.scale; 238 239 // if presentation starts (nothing is active yet) 240 // don't animate (set duration to 0) 241 var duration = (active) ? "600ms" : "0"; 242 243 css(impress, { 244 // to keep the perspective look similar for different scales 245 // we need to 'scale' the perspective, too 246 perspective: step.scale * 1000 + "px", 247 transform: scale(target.scale), 248 transitionDuration: duration, 249 transitionDelay: (zoomin ? "500ms" : "0ms") 250 }); 251 252 css(canvas, { 253 transform: rotate(target.rotate, true) + translate(target.translate), 254 transitionDuration: duration, 255 transitionDelay: (zoomin ? "0ms" : "500ms") 256 }); 257 258 current = target; 259 active = el; 260 261 return el; 262 }; 263 264 var selectPrev = function () { 265 var prev = steps.indexOf( active ) - 1; 266 prev = prev >= 0 ? steps[ prev ] : steps[ steps.length-1 ]; 267 268 return select(prev); 269 }; 270 271 var selectNext = function () { 272 var next = steps.indexOf( active ) + 1; 273 next = next < steps.length ? steps[ next ] : steps[ 0 ]; 274 275 return select(next); 276 }; 277 278 // EVENTS 279 280 document.addEventListener("keydown", function ( event ) { 281 if ( event.keyCode == 9 || ( event.keyCode >= 32 && event.keyCode <= 34 ) || (event.keyCode >= 37 && event.keyCode <= 40) ) { 282 switch( event.keyCode ) { 283 case 33: ; // pg up 284 case 37: ; // left 285 case 38: // up 286 selectPrev(); 287 break; 288 case 9: ; // tab 289 case 32: ; // space 290 case 34: ; // pg down 291 case 39: ; // right 292 case 40: // down 293 selectNext(); 294 break; 295 } 296 297 event.preventDefault(); 298 } 299 }, false); 300 301 document.addEventListener("click", function ( event ) { 302 // event delegation with "bubbling" 303 // check if event target (or any of its parents is a link or a step) 304 var target = event.target; 305 while ( (target.tagName != "A") && 306 (!target.stepData) && 307 (target != document.body) ) { 308 target = target.parentNode; 309 } 310 311 if ( target.tagName == "A" ) { 312 var href = target.getAttribute("href"); 313 314 // if it's a link to presentation step, target this step 315 if ( href && href[0] == '#' ) { 316 target = byId( href.slice(1) ); 317 } 318 } 319 320 if ( select(target) ) { 321 event.preventDefault(); 322 } 323 }, false); 324 325 var getElementFromUrl = function () { 326 // get id from url # by removing `#` or `#/` from the beginning, 327 // so both "fallback" `#slide-id` and "enhanced" `#/slide-id` will work 328 return byId( window.location.hash.replace(/^#\/?/,"") ); 329 } 330 331 window.addEventListener("hashchange", function () { 332 select( getElementFromUrl() ); 333 }, false); 334 335 // START 336 // by selecting step defined in url or first step of the presentation 337 select(getElementFromUrl() || steps[0]); 338 339})(document, window); 340
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.