PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 13.5.2
Jetpack – WP Security, Backup, Speed, & Growth v13.5.2
12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 14.4.2 14.5.1 14.6.1 14.7.1 14.8.1 14.9.2 15.0.3 15.1.2 15.2.1 15.3.2 15.4.1 15.5.1 15.6.1 15.7.2 15.8.1 15.9.2 16.0.2 16.1.3 16.2-a.5 16.2-a.3 16.1.2 16.2-a.1 16.1.1 16.1 16.1-beta 16.1-beta.2 16.1-beta.3 16.1-a.5 16.1-a.3 16.0.1 16.1-a.1 16.0 16.0-beta 16.0-a.7 16.0-a.5 15.9.1 16.0-a.3 16.0-a.1 15.9 15.9-beta 15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / modules / shortcodes / js / jmpress.js
jetpack / modules / shortcodes / js Last commit date
brightcove.js 6 years ago jmpress.js 6 years ago jquery.cycle.min.js 9 years ago main.js 6 years ago quiz.js 5 years ago recipes-printthis.js 4 years ago recipes.js 6 years ago slideshow-shortcode.js 4 years ago
jmpress.js
2871 lines
1 /**
2 * jmpress.js v0.4.5
3 * http://jmpressjs.github.com/jmpress.js
4 *
5 * A jQuery plugin to build a website on the infinite canvas.
6 *
7 * Copyright 2013 Kyle Robinson Young @shama & Tobias Koppers @sokra
8 * Licensed MIT
9 * http://www.opensource.org/licenses/mit-license.php
10 *
11 * Based on the foundation laid by Bartek Szopka @bartaz
12 */ /*
13 * core.js
14 * The core of jmpress.js
15 */
16 ( function ( $, document, window, undefined ) {
17 'use strict';
18
19 /**
20 * Set supported prefixes
21 *
22 * @access protected
23 * @return Function to get prefixed property
24 */
25 var pfx = ( function () {
26 var style = document.createElement( 'dummy' ).style,
27 prefixes = 'Webkit Moz O ms Khtml'.split( ' ' ),
28 memory = {};
29 return function ( prop ) {
30 if ( typeof memory[ prop ] === 'undefined' ) {
31 var ucProp = prop.charAt( 0 ).toUpperCase() + prop.substr( 1 ),
32 props = ( prop + ' ' + prefixes.join( ucProp + ' ' ) + ucProp ).split( ' ' );
33 memory[ prop ] = null;
34 for ( var i in props ) {
35 if ( style[ props[ i ] ] !== undefined ) {
36 memory[ prop ] = props[ i ];
37 break;
38 }
39 }
40 }
41 return memory[ prop ];
42 };
43 } )();
44
45 /**
46 * map ex. "WebkitTransform" to "-webkit-transform"
47 */
48 function mapProperty( name ) {
49 if ( ! name ) {
50 return;
51 }
52 var index = 1 + name.substr( 1 ).search( /[A-Z]/ );
53 var prefix = name.substr( 0, index ).toLowerCase();
54 var postfix = name.substr( index ).toLowerCase();
55 return '-' + prefix + '-' + postfix;
56 }
57 function addComma( attribute ) {
58 if ( ! attribute ) {
59 return '';
60 }
61 return attribute + ',';
62 }
63 /**
64 * Return an jquery object only if it's not empty
65 */
66 function ifNotEmpty( el ) {
67 if ( el.length > 0 ) {
68 return el;
69 }
70 return null;
71 }
72
73 /**
74 * Default Settings
75 */
76 var defaults = {
77 /* CLASSES */
78 stepSelector: '.step',
79 containerClass: '',
80 canvasClass: '',
81 areaClass: '',
82 notSupportedClass: 'not-supported',
83
84 /* CONFIG */
85 fullscreen: true,
86
87 /* ANIMATION */
88 animation: {
89 transformOrigin: 'top left',
90 transitionProperty:
91 addComma( mapProperty( pfx( 'transform' ) ) ) +
92 addComma( mapProperty( pfx( 'perspective' ) ) ) +
93 'opacity',
94 transitionDuration: '1s',
95 transitionDelay: '500ms',
96 transitionTimingFunction: 'ease-in-out',
97 transformStyle: 'preserve-3d',
98 },
99 transitionDuration: 1500,
100 };
101 var callbacks = {
102 beforeChange: 1,
103 beforeInitStep: 1,
104 initStep: 1,
105 beforeInit: 1,
106 afterInit: 1,
107 beforeDeinit: 1,
108 afterDeinit: 1,
109 applyStep: 1,
110 unapplyStep: 1,
111 setInactive: 1,
112 beforeActive: 1,
113 setActive: 1,
114 selectInitialStep: 1,
115 selectPrev: 1,
116 selectNext: 1,
117 selectHome: 1,
118 selectEnd: 1,
119 idle: 1,
120 applyTarget: 1,
121 };
122 for ( var callbackName in callbacks ) {
123 defaults[ callbackName ] = [];
124 }
125
126 /**
127 * Initialize jmpress
128 */
129 function init( args ) {
130 args = $.extend( true, {}, args || {} );
131
132 // accept functions and arrays of functions as callbacks
133 var callbackArgs = {};
134 var callbackName = null;
135 for ( callbackName in callbacks ) {
136 callbackArgs[ callbackName ] = $.isFunction( args[ callbackName ] )
137 ? [ args[ callbackName ] ]
138 : args[ callbackName ];
139 args[ callbackName ] = [];
140 }
141
142 // MERGE SETTINGS
143 var settings = $.extend( true, {}, defaults, args );
144
145 for ( callbackName in callbacks ) {
146 if ( callbackArgs[ callbackName ] ) {
147 Array.prototype.push.apply( settings[ callbackName ], callbackArgs[ callbackName ] );
148 }
149 }
150
151 /*** MEMBER VARS ***/
152
153 var jmpress = $( this ),
154 container = null,
155 area = null,
156 oldStyle = {
157 container: '',
158 area: '',
159 },
160 canvas = null,
161 current = null,
162 active = false,
163 activeSubstep = null,
164 activeDelegated = false;
165
166 /*** MEMBER FUNCTIONS ***/
167 // functions have to be called with this
168
169 /**
170 * Init a single step
171 *
172 * @param element the element of the step
173 * @param idx number of step
174 */
175 function doStepInit( element, idx ) {
176 var data = dataset( element );
177 var step = {
178 oldStyle: $( element ).attr( 'style' ) || '',
179 };
180
181 var callbackData = {
182 data: data,
183 stepData: step,
184 };
185 callCallback.call( this, 'beforeInitStep', $( element ), callbackData );
186 step.delegate = data.delegate;
187 callCallback.call( this, 'initStep', $( element ), callbackData );
188
189 $( element ).data( 'stepData', step );
190
191 if ( ! $( element ).attr( 'id' ) ) {
192 $( element ).attr( 'id', 'step-' + ( idx + 1 ) );
193 }
194
195 callCallback.call( this, 'applyStep', $( element ), callbackData );
196 }
197 /**
198 * Deinit a single step
199 *
200 * @param element the element of the step
201 */
202 function doStepDeinit( element ) {
203 var stepData = $( element ).data( 'stepData' );
204
205 $( element ).attr( 'style', stepData.oldStyle );
206
207 callCallback.call( this, 'unapplyStep', $( element ), {
208 stepData: stepData,
209 } );
210 }
211 /**
212 * Reapplies stepData to the element
213 *
214 * @param element
215 */
216 function doStepReapply( element ) {
217 callCallback.call( this, 'unapplyStep', $( element ), {
218 stepData: element.data( 'stepData' ),
219 } );
220
221 callCallback.call( this, 'applyStep', $( element ), {
222 stepData: element.data( 'stepData' ),
223 } );
224 }
225 /**
226 * Completly deinit jmpress
227 *
228 */
229 function deinit() {
230 if ( active ) {
231 callCallback.call( this, 'setInactive', active, {
232 stepData: $( active ).data( 'stepData' ),
233 reason: 'deinit',
234 } );
235 }
236 if ( current.jmpressClass ) {
237 $( jmpress ).removeClass( current.jmpressClass );
238 }
239
240 callCallback.call( this, 'beforeDeinit', $( this ), {} );
241
242 $( settings.stepSelector, jmpress ).each( function ( idx ) {
243 doStepDeinit.call( jmpress, this );
244 } );
245
246 container.attr( 'style', oldStyle.container );
247 if ( settings.fullscreen ) {
248 $( 'html' ).attr( 'style', '' );
249 }
250 area.attr( 'style', oldStyle.area );
251 $( canvas )
252 .children()
253 .each( function () {
254 jmpress.append( $( this ) );
255 } );
256 if ( settings.fullscreen ) {
257 canvas.remove();
258 } else {
259 canvas.remove();
260 area.remove();
261 }
262
263 callCallback.call( this, 'afterDeinit', $( this ), {} );
264
265 $( jmpress ).data( 'jmpressmethods', false );
266 }
267 /**
268 * Call a callback
269 *
270 * @param callbackName String callback which should be called
271 * @param element some arguments to the callback
272 * @param eventData
273 */
274 function callCallback( callbackName, element, eventData ) {
275 eventData.settings = settings;
276 eventData.current = current;
277 eventData.container = container;
278 eventData.parents = element ? getStepParents( element ) : null;
279 eventData.current = current;
280 eventData.jmpress = this;
281 var result = {};
282 $.each( settings[ callbackName ], function ( idx, callback ) {
283 result.value = callback.call( jmpress, element, eventData ) || result.value;
284 } );
285 return result.value;
286 }
287 /**
288 *
289 */
290 function getStepParents( el ) {
291 return $( el ).parentsUntil( jmpress ).not( jmpress ).filter( settings.stepSelector );
292 }
293 /**
294 * Reselect the active step
295 *
296 * @param String type reason of reselecting step
297 */
298 function reselect( type ) {
299 return select( { step: active, substep: activeSubstep }, type );
300 }
301 /**
302 * Select a given step
303 *
304 * @param el element to select
305 * @param type reason of changing step
306 * @return Object element selected
307 */
308 function select( el, type ) {
309 var substep;
310 if ( $.isPlainObject( el ) ) {
311 substep = el.substep;
312 el = el.step;
313 }
314 if ( typeof el === 'string' ) {
315 el = jmpress.find( el ).first();
316 }
317 if ( ! el || ! $( el ).data( 'stepData' ) ) {
318 return false;
319 }
320
321 scrollFix.call( this );
322
323 var step = $( el ).data( 'stepData' );
324
325 var cancelSelect = false;
326 callCallback.call( this, 'beforeChange', el, {
327 stepData: step,
328 reason: type,
329 cancel: function () {
330 cancelSelect = true;
331 },
332 } );
333 if ( cancelSelect ) {
334 return undefined;
335 }
336
337 var target = {};
338
339 var delegated = el;
340 if ( $( el ).data( 'stepData' ).delegate ) {
341 delegated =
342 ifNotEmpty(
343 $( el ).parentsUntil( jmpress ).filter( settings.stepSelector ).filter( step.delegate )
344 ) ||
345 ifNotEmpty( $( el ).near( step.delegate ) ) ||
346 ifNotEmpty( $( el ).near( step.delegate, true ) ) ||
347 ifNotEmpty( $( step.delegate, jmpress ) );
348 if ( delegated ) {
349 step = delegated.data( 'stepData' );
350 } else {
351 // Do not delegate if expression not found
352 delegated = el;
353 }
354 }
355 if ( activeDelegated ) {
356 callCallback.call( this, 'setInactive', activeDelegated, {
357 stepData: $( activeDelegated ).data( 'stepData' ),
358 delegatedFrom: active,
359 reason: type,
360 target: target,
361 nextStep: delegated,
362 nextSubstep: substep,
363 nextStepData: step,
364 } );
365 }
366 var callbackData = {
367 stepData: step,
368 delegatedFrom: el,
369 reason: type,
370 target: target,
371 substep: substep,
372 prevStep: activeDelegated,
373 prevSubstep: activeSubstep,
374 prevStepData: activeDelegated && $( activeDelegated ).data( 'stepData' ),
375 };
376 callCallback.call( this, 'beforeActive', delegated, callbackData );
377 callCallback.call( this, 'setActive', delegated, callbackData );
378
379 // Set on step class on root element
380 if ( current.jmpressClass ) {
381 $( jmpress ).removeClass( current.jmpressClass );
382 }
383 $( jmpress ).addClass( ( current.jmpressClass = 'step-' + $( delegated ).attr( 'id' ) ) );
384 if ( current.jmpressDelegatedClass ) {
385 $( jmpress ).removeClass( current.jmpressDelegatedClass );
386 }
387 $( jmpress ).addClass(
388 ( current.jmpressDelegatedClass = 'delegating-step-' + $( el ).attr( 'id' ) )
389 );
390
391 callCallback.call(
392 this,
393 'applyTarget',
394 delegated,
395 $.extend(
396 {
397 canvas: canvas,
398 area: area,
399 beforeActive: activeDelegated,
400 },
401 callbackData
402 )
403 );
404
405 active = el;
406 activeSubstep = callbackData.substep;
407 activeDelegated = delegated;
408
409 if ( current.idleTimeout ) {
410 clearTimeout( current.idleTimeout );
411 }
412 current.idleTimeout = setTimeout( function () {
413 callCallback.call( this, 'idle', delegated, callbackData );
414 }, Math.max( 1, settings.transitionDuration - 100 ) );
415
416 return delegated;
417 }
418 /**
419 * This should fix ANY kind of buggy scrolling
420 */
421 function scrollFix() {
422 ( function fix() {
423 if ( $( container )[ 0 ].tagName === 'BODY' ) {
424 try {
425 window.scrollTo( 0, 0 );
426 } catch ( e ) {}
427 }
428 $( container ).scrollTop( 0 );
429 $( container ).scrollLeft( 0 );
430 function check() {
431 if ( $( container ).scrollTop() !== 0 || $( container ).scrollLeft() !== 0 ) {
432 fix();
433 }
434 }
435 setTimeout( check, 1 );
436 setTimeout( check, 10 );
437 setTimeout( check, 100 );
438 setTimeout( check, 200 );
439 setTimeout( check, 400 );
440 } )();
441 }
442 /**
443 * Alias for select
444 */
445 function goTo( el ) {
446 return select.call( this, el, 'jump' );
447 }
448 /**
449 * Goto Next Slide
450 *
451 * @return Object newly active slide
452 */
453 function next() {
454 return select.call(
455 this,
456 callCallback.call( this, 'selectNext', active, {
457 stepData: $( active ).data( 'stepData' ),
458 substep: activeSubstep,
459 } ),
460 'next'
461 );
462 }
463 /**
464 * Goto Previous Slide
465 *
466 * @return Object newly active slide
467 */
468 function prev() {
469 return select.call(
470 this,
471 callCallback.call( this, 'selectPrev', active, {
472 stepData: $( active ).data( 'stepData' ),
473 substep: activeSubstep,
474 } ),
475 'prev'
476 );
477 }
478 /**
479 * Goto First Slide
480 *
481 * @return Object newly active slide
482 */
483 function home() {
484 return select.call(
485 this,
486 callCallback.call( this, 'selectHome', active, {
487 stepData: $( active ).data( 'stepData' ),
488 } ),
489 'home'
490 );
491 }
492 /**
493 * Goto Last Slide
494 *
495 * @return Object newly active slide
496 */
497 function end() {
498 return select.call(
499 this,
500 callCallback.call( this, 'selectEnd', active, {
501 stepData: $( active ).data( 'stepData' ),
502 } ),
503 'end'
504 );
505 }
506 /**
507 * Manipulate the canvas
508 *
509 * @param props
510 * @return Object
511 */
512 function canvasMod( props ) {
513 css( canvas, props || {} );
514 return $( canvas );
515 }
516 /**
517 * Return current step
518 *
519 * @return Object
520 */
521 function getActive() {
522 return activeDelegated && $( activeDelegated );
523 }
524 /**
525 * fire a callback
526 *
527 * @param callbackName
528 * @param element
529 * @param eventData
530 * @return void
531 */
532 function fire( callbackName, element, eventData ) {
533 if ( ! callbacks[ callbackName ] ) {
534 $.error( 'callback ' + callbackName + ' is not registered.' );
535 } else {
536 return callCallback.call( this, callbackName, element, eventData );
537 }
538 }
539
540 /**
541 * PUBLIC METHODS LIST
542 */
543 jmpress.data( 'jmpressmethods', {
544 select: select,
545 reselect: reselect,
546 scrollFix: scrollFix,
547 goTo: goTo,
548 next: next,
549 prev: prev,
550 home: home,
551 end: end,
552 canvas: canvasMod,
553 container: function () {
554 return container;
555 },
556 settings: function () {
557 return settings;
558 },
559 active: getActive,
560 current: function () {
561 return current;
562 },
563 fire: fire,
564 init: function ( step ) {
565 doStepInit.call( this, $( step ), current.nextIdNumber++ );
566 },
567 deinit: function ( step ) {
568 if ( step ) {
569 doStepDeinit.call( this, $( step ) );
570 } else {
571 deinit.call( this );
572 }
573 },
574 reapply: doStepReapply,
575 } );
576
577 /**
578 * Check for support
579 * This will be removed in near future, when support is coming
580 *
581 * @access protected
582 * @return void
583 */
584 function checkSupport() {
585 var ua = navigator.userAgent.toLowerCase();
586 return ua.search( /(iphone)|(ipod)|(android)/ ) === -1 || ua.search( /(chrome)/ ) !== -1;
587 }
588
589 // BEGIN INIT
590
591 // CHECK FOR SUPPORT
592 if ( checkSupport() === false ) {
593 if ( settings.notSupportedClass ) {
594 jmpress.addClass( settings.notSupportedClass );
595 }
596 return;
597 } else {
598 if ( settings.notSupportedClass ) {
599 jmpress.removeClass( settings.notSupportedClass );
600 }
601 }
602
603 // grabbing all steps
604 var steps = $( settings.stepSelector, jmpress );
605
606 // GERNERAL INIT OF FRAME
607 container = jmpress;
608 area = $( '<div />' );
609 canvas = $( '<div />' );
610 $( jmpress )
611 .children()
612 .filter( steps )
613 .each( function () {
614 canvas.append( $( this ) );
615 } );
616 if ( settings.fullscreen ) {
617 container = $( 'body' );
618 $( 'html' ).css( {
619 overflow: 'hidden',
620 } );
621 area = jmpress;
622 }
623 oldStyle.area = area.attr( 'style' ) || '';
624 oldStyle.container = container.attr( 'style' ) || '';
625 if ( settings.fullscreen ) {
626 container.css( {
627 height: '100%',
628 } );
629 jmpress.append( canvas );
630 } else {
631 container.css( {
632 position: 'relative',
633 } );
634 area.append( canvas );
635 jmpress.append( area );
636 }
637
638 $( container ).addClass( settings.containerClass );
639 $( area ).addClass( settings.areaClass );
640 $( canvas ).addClass( settings.canvasClass );
641
642 document.documentElement.style.height = '100%';
643 container.css( {
644 overflow: 'hidden',
645 } );
646
647 var props = {
648 position: 'absolute',
649 transitionDuration: '0s',
650 };
651 props = $.extend( {}, settings.animation, props );
652 css( area, props );
653 css( area, {
654 top: '50%',
655 left: '50%',
656 perspective: '1000px',
657 } );
658 css( canvas, props );
659
660 current = {};
661
662 callCallback.call( this, 'beforeInit', null, {} );
663
664 // INITIALIZE EACH STEP
665 steps.each( function ( idx ) {
666 doStepInit.call( jmpress, this, idx );
667 } );
668 current.nextIdNumber = steps.length;
669
670 callCallback.call( this, 'afterInit', null, {} );
671
672 // START
673 select.call( this, callCallback.call( this, 'selectInitialStep', 'init', {} ) );
674
675 if ( settings.initClass ) {
676 $( steps ).removeClass( settings.initClass );
677 }
678 }
679 /**
680 * Return default settings
681 *
682 * @return Object
683 */
684 function getDefaults() {
685 return defaults;
686 }
687 /**
688 * Register a callback or a jmpress function
689 *
690 * @access public
691 * @param name String the name of the callback or function
692 * @param func Function? the function to be added
693 */
694 function register( name, func ) {
695 if ( $.isFunction( func ) ) {
696 if ( methods[ name ] ) {
697 $.error( 'function ' + name + ' is already registered.' );
698 } else {
699 methods[ name ] = func;
700 }
701 } else {
702 if ( callbacks[ name ] ) {
703 $.error( 'callback ' + name + ' is already registered.' );
704 } else {
705 callbacks[ name ] = 1;
706 defaults[ name ] = [];
707 }
708 }
709 }
710 /**
711 * Set CSS on element w/ prefixes
712 *
713 * @return Object element which properties were set
714 *
715 * TODO: Consider bypassing pfx and blindly set as jQuery
716 * already checks for support
717 */
718 function css( el, props ) {
719 var key,
720 pkey,
721 cssObj = {};
722 for ( key in props ) {
723 if ( props.hasOwnProperty( key ) ) {
724 pkey = pfx( key );
725 if ( pkey !== null ) {
726 cssObj[ pkey ] = props[ key ];
727 }
728 }
729 }
730 $( el ).css( cssObj );
731 return el;
732 }
733 /**
734 * Return dataset for element
735 *
736 * @param el element
737 * @return Object
738 */
739 function dataset( el ) {
740 if ( $( el )[ 0 ].dataset ) {
741 return $.extend( {}, $( el )[ 0 ].dataset );
742 }
743 function toCamelcase( str ) {
744 str = str.split( '-' );
745 for ( var i = 1; i < str.length; i++ ) {
746 str[ i ] = str[ i ].substr( 0, 1 ).toUpperCase() + str[ i ].substr( 1 );
747 }
748 return str.join( '' );
749 }
750 var returnDataset = {};
751 var attrs = $( el )[ 0 ].attributes;
752 $.each( attrs, function ( idx, attr ) {
753 if ( attr.nodeName.substr( 0, 5 ) === 'data-' ) {
754 returnDataset[ toCamelcase( attr.nodeName.substr( 5 ) ) ] = attr.nodeValue;
755 }
756 } );
757 return returnDataset;
758 }
759 /**
760 * Returns true, if jmpress is initialized
761 *
762 * @return bool
763 */
764 function initialized() {
765 return !! $( this ).data( 'jmpressmethods' );
766 }
767
768 /**
769 * PUBLIC STATIC METHODS LIST
770 */
771 var methods = {
772 init: init,
773 initialized: initialized,
774 deinit: function () {},
775 css: css,
776 pfx: pfx,
777 defaults: getDefaults,
778 register: register,
779 dataset: dataset,
780 };
781
782 /**
783 * $.jmpress()
784 */
785 $.fn.jmpress = function ( method ) {
786 function f() {
787 var jmpressmethods = $( this ).data( 'jmpressmethods' );
788 if ( jmpressmethods && jmpressmethods[ method ] ) {
789 return jmpressmethods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ) );
790 } else if ( methods[ method ] ) {
791 return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ) );
792 } else if ( callbacks[ method ] && jmpressmethods ) {
793 var settings = jmpressmethods.settings();
794 var func = Array.prototype.slice.call( arguments, 1 )[ 0 ];
795 if ( $.isFunction( func ) ) {
796 settings[ method ] = settings[ method ] || [];
797 settings[ method ].push( func );
798 }
799 } else if ( typeof method === 'object' || ! method ) {
800 return init.apply( this, arguments );
801 } else {
802 $.error( 'Method ' + method + ' does not exist on jQuery.jmpress' );
803 }
804 // to allow chaining
805 return this;
806 }
807 var args = arguments;
808 var result;
809 $( this ).each( function ( idx, element ) {
810 result = f.apply( element, args );
811 } );
812 return result;
813 };
814 $.extend( {
815 jmpress: function ( method ) {
816 if ( methods[ method ] ) {
817 return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ) );
818 } else if ( callbacks[ method ] ) {
819 // plugin interface
820 var func = Array.prototype.slice.call( arguments, 1 )[ 0 ];
821 if ( $.isFunction( func ) ) {
822 defaults[ method ].push( func );
823 } else {
824 $.error(
825 'Second parameter should be a function: $.jmpress( callbackName, callbackFunction )'
826 );
827 }
828 } else {
829 $.error( 'Method ' + method + ' does not exist on jQuery.jmpress' );
830 }
831 },
832 } );
833 } )( jQuery, document, window );
834
835 /*
836 * near.js
837 * Find steps near each other
838 */
839 ( function ( $, document, window, undefined ) {
840 'use strict';
841
842 // add near( selector, backwards = false) to jquery
843
844 function checkAndGo( elements, func, selector, backwards ) {
845 var next;
846 elements.each( function ( idx, element ) {
847 if ( backwards ) {
848 next = func( element, selector, backwards );
849 if ( next ) {
850 return false;
851 }
852 }
853 if ( $( element ).is( selector ) ) {
854 next = element;
855 return false;
856 }
857 if ( ! backwards ) {
858 next = func( element, selector, backwards );
859 if ( next ) {
860 return false;
861 }
862 }
863 } );
864 return next;
865 }
866 function findNextInChildren( item, selector, backwards ) {
867 var children = $( item ).children();
868 if ( backwards ) {
869 children = $( children.get().reverse() );
870 }
871 return checkAndGo( children, findNextInChildren, selector, backwards );
872 }
873 function findNextInSiblings( item, selector, backwards ) {
874 return checkAndGo(
875 $( item )[ backwards ? 'prevAll' : 'nextAll' ](),
876 findNextInChildren,
877 selector,
878 backwards
879 );
880 }
881 function findNextInParents( item, selector, backwards ) {
882 var next;
883 var parents = $( item ).parents();
884 parents = $( parents.get() );
885 $.each( parents.get(), function ( idx, element ) {
886 if ( backwards && $( element ).is( selector ) ) {
887 next = element;
888 return false;
889 }
890 next = findNextInSiblings( element, selector, backwards );
891 if ( next ) {
892 return false;
893 }
894 } );
895 return next;
896 }
897
898 $.fn.near = function ( selector, backwards ) {
899 var array = [];
900 $( this ).each( function ( idx, element ) {
901 var near =
902 ( backwards ? false : findNextInChildren( element, selector, backwards ) ) ||
903 findNextInSiblings( element, selector, backwards ) ||
904 findNextInParents( element, selector, backwards );
905 if ( near ) {
906 array.push( near );
907 }
908 } );
909 return $( array );
910 };
911 } )( jQuery, document, window );
912 /*
913 * transform.js
914 * The engine that powers the transforms or falls back to other methods
915 */
916 ( function ( $, document, window, undefined ) {
917 'use strict';
918
919 /* FUNCTIONS */
920 function toCssNumber( number ) {
921 return Math.round( 10000 * number ) / 10000 + '';
922 }
923
924 /**
925 * 3D and 2D engines
926 */
927 var engines = {
928 3: {
929 transform: function ( el, data ) {
930 var transform = 'translate(-50%,-50%)';
931 $.each( data, function ( idx, item ) {
932 var coord = [ 'X', 'Y', 'Z' ];
933 var i;
934 if ( item[ 0 ] === 'translate' ) {
935 // ["translate", x, y, z]
936 transform +=
937 ' translate3d(' +
938 toCssNumber( item[ 1 ] || 0 ) +
939 'px,' +
940 toCssNumber( item[ 2 ] || 0 ) +
941 'px,' +
942 toCssNumber( item[ 3 ] || 0 ) +
943 'px)';
944 } else if ( item[ 0 ] === 'rotate' ) {
945 var order = item[ 4 ] ? [ 1, 2, 3 ] : [ 3, 2, 1 ];
946 for ( i = 0; i < 3; i++ ) {
947 transform +=
948 ' rotate' +
949 coord[ order[ i ] - 1 ] +
950 '(' +
951 toCssNumber( item[ order[ i ] ] || 0 ) +
952 'deg)';
953 }
954 } else if ( item[ 0 ] === 'scale' ) {
955 for ( i = 0; i < 3; i++ ) {
956 transform += ' scale' + coord[ i ] + '(' + toCssNumber( item[ i + 1 ] || 1 ) + ')';
957 }
958 }
959 } );
960 $.jmpress( 'css', el, $.extend( {}, { transform: transform } ) );
961 },
962 },
963 2: {
964 transform: function ( el, data ) {
965 var transform = 'translate(-50%,-50%)';
966 $.each( data, function ( idx, item ) {
967 var coord = [ 'X', 'Y' ];
968 if ( item[ 0 ] === 'translate' ) {
969 // ["translate", x, y, z]
970 transform +=
971 ' translate(' +
972 toCssNumber( item[ 1 ] || 0 ) +
973 'px,' +
974 toCssNumber( item[ 2 ] || 0 ) +
975 'px)';
976 } else if ( item[ 0 ] === 'rotate' ) {
977 transform += ' rotate(' + toCssNumber( item[ 3 ] || 0 ) + 'deg)';
978 } else if ( item[ 0 ] === 'scale' ) {
979 for ( var i = 0; i < 2; i++ ) {
980 transform += ' scale' + coord[ i ] + '(' + toCssNumber( item[ i + 1 ] || 1 ) + ')';
981 }
982 }
983 } );
984 $.jmpress( 'css', el, $.extend( {}, { transform: transform } ) );
985 },
986 },
987 1: {
988 // CHECK IF SUPPORT IS REALLY NEEDED?
989 // this not even work without scaling...
990 // it may better to display the normal view
991 transform: function ( el, data ) {
992 var anitarget = { top: 0, left: 0 };
993 $.each( data, function ( idx, item ) {
994 var coord = [ 'X', 'Y' ];
995 if ( item[ 0 ] === 'translate' ) {
996 // ["translate", x, y, z]
997 anitarget.left = Math.round( item[ 1 ] || 0 ) + 'px';
998 anitarget.top = Math.round( item[ 2 ] || 0 ) + 'px';
999 }
1000 } );
1001 el.animate( anitarget, 1000 ); // TODO: Use animation duration
1002 },
1003 },
1004 };
1005
1006 /**
1007 * Engine to power cross-browser translate, scale and rotate.
1008 */
1009 var engine = ( function () {
1010 if ( $.jmpress( 'pfx', 'perspective' ) ) {
1011 return engines[ 3 ];
1012 } else if ( $.jmpress( 'pfx', 'transform' ) ) {
1013 return engines[ 2 ];
1014 } else {
1015 // CHECK IF SUPPORT IS REALLY NEEDED?
1016 return engines[ 1 ];
1017 }
1018 } )();
1019
1020 $.jmpress( 'defaults' ).reasonableAnimation = {};
1021 $.jmpress( 'initStep', function ( step, eventData ) {
1022 var data = eventData.data;
1023 var stepData = eventData.stepData;
1024 var pf = parseFloat;
1025 $.extend( stepData, {
1026 x: pf( data.x ) || 0,
1027 y: pf( data.y ) || 0,
1028 z: pf( data.z ) || 0,
1029 r: pf( data.r ) || 0,
1030 phi: pf( data.phi ) || 0,
1031 rotate: pf( data.rotate ) || 0,
1032 rotateX: pf( data.rotateX ) || 0,
1033 rotateY: pf( data.rotateY ) || 0,
1034 rotateZ: pf( data.rotateZ ) || 0,
1035 revertRotate: false,
1036 scale: pf( data.scale ) || 1,
1037 scaleX: pf( data.scaleX ) || false,
1038 scaleY: pf( data.scaleY ) || false,
1039 scaleZ: pf( data.scaleZ ) || 1,
1040 } );
1041 } );
1042 $.jmpress( 'afterInit', function ( nil, eventData ) {
1043 var stepSelector = eventData.settings.stepSelector,
1044 current = eventData.current;
1045 current.perspectiveScale = 1;
1046 current.maxNestedDepth = 0;
1047 var nestedSteps = $( eventData.jmpress ).find( stepSelector ).children( stepSelector );
1048 while ( nestedSteps.length ) {
1049 current.maxNestedDepth++;
1050 nestedSteps = nestedSteps.children( stepSelector );
1051 }
1052 } );
1053 $.jmpress( 'applyStep', function ( step, eventData ) {
1054 $.jmpress( 'css', $( step ), {
1055 position: 'absolute',
1056 transformStyle: 'preserve-3d',
1057 } );
1058 if ( eventData.parents.length > 0 ) {
1059 $.jmpress( 'css', $( step ), {
1060 top: '50%',
1061 left: '50%',
1062 } );
1063 }
1064 var sd = eventData.stepData;
1065 var transform = [
1066 [
1067 'translate',
1068 sd.x || sd.r * Math.sin( ( sd.phi * Math.PI ) / 180 ),
1069 sd.y || -sd.r * Math.cos( ( sd.phi * Math.PI ) / 180 ),
1070 sd.z,
1071 ],
1072 [ 'rotate', sd.rotateX, sd.rotateY, sd.rotateZ || sd.rotate, true ],
1073 [ 'scale', sd.scaleX || sd.scale, sd.scaleY || sd.scale, sd.scaleZ || sd.scale ],
1074 ];
1075 engine.transform( step, transform );
1076 } );
1077 $.jmpress( 'setActive', function ( element, eventData ) {
1078 var target = eventData.target;
1079 var step = eventData.stepData;
1080 var tf = ( target.transform = [] );
1081 target.perspectiveScale = 1;
1082
1083 for ( var i = eventData.current.maxNestedDepth; i > ( eventData.parents.length || 0 ); i-- ) {
1084 tf.push( [ 'scale' ], [ 'rotate' ], [ 'translate' ] );
1085 }
1086
1087 tf.push( [
1088 'scale',
1089 1 / ( step.scaleX || step.scale ),
1090 1 / ( step.scaleY || step.scale ),
1091 1 / step.scaleZ,
1092 ] );
1093 tf.push( [ 'rotate', -step.rotateX, -step.rotateY, -( step.rotateZ || step.rotate ) ] );
1094 tf.push( [
1095 'translate',
1096 -( step.x || step.r * Math.sin( ( step.phi * Math.PI ) / 180 ) ),
1097 -( step.y || -step.r * Math.cos( ( step.phi * Math.PI ) / 180 ) ),
1098 -step.z,
1099 ] );
1100 target.perspectiveScale *= step.scaleX || step.scale;
1101
1102 $.each( eventData.parents, function ( idx, element ) {
1103 var step = $( element ).data( 'stepData' );
1104 tf.push( [
1105 'scale',
1106 1 / ( step.scaleX || step.scale ),
1107 1 / ( step.scaleY || step.scale ),
1108 1 / step.scaleZ,
1109 ] );
1110 tf.push( [ 'rotate', -step.rotateX, -step.rotateY, -( step.rotateZ || step.rotate ) ] );
1111 tf.push( [
1112 'translate',
1113 -( step.x || step.r * Math.sin( ( step.phi * Math.PI ) / 180 ) ),
1114 -( step.y || -step.r * Math.cos( ( step.phi * Math.PI ) / 180 ) ),
1115 -step.z,
1116 ] );
1117 target.perspectiveScale *= step.scaleX || step.scale;
1118 } );
1119
1120 $.each( tf, function ( idx, item ) {
1121 if ( item[ 0 ] !== 'rotate' ) {
1122 return;
1123 }
1124 function lowRotate( name ) {
1125 if ( eventData.current[ 'rotate' + name + '-' + idx ] === undefined ) {
1126 eventData.current[ 'rotate' + name + '-' + idx ] = item[ name ] || 0;
1127 }
1128 var cur = eventData.current[ 'rotate' + name + '-' + idx ],
1129 tar = item[ name ] || 0,
1130 curmod = cur % 360,
1131 tarmod = tar % 360;
1132 if ( curmod < 0 ) {
1133 curmod += 360;
1134 }
1135 if ( tarmod < 0 ) {
1136 tarmod += 360;
1137 }
1138 var diff = tarmod - curmod;
1139 if ( diff < -180 ) {
1140 diff += 360;
1141 } else if ( diff > 180 ) {
1142 diff -= 360;
1143 }
1144 eventData.current[ 'rotate' + name + '-' + idx ] = item[ name ] = cur + diff;
1145 }
1146 lowRotate( 1 );
1147 lowRotate( 2 );
1148 lowRotate( 3 );
1149 } );
1150 } );
1151 $.jmpress( 'applyTarget', function ( active, eventData ) {
1152 var target = eventData.target,
1153 props,
1154 step = eventData.stepData,
1155 settings = eventData.settings,
1156 zoomin = target.perspectiveScale * 1.3 < eventData.current.perspectiveScale,
1157 zoomout = target.perspectiveScale > eventData.current.perspectiveScale * 1.3;
1158
1159 // extract first scale from transform
1160 var lastScale = -1;
1161 $.each( target.transform, function ( idx, item ) {
1162 if ( item.length <= 1 ) {
1163 return;
1164 }
1165 if (
1166 item[ 0 ] === 'rotate' &&
1167 item[ 1 ] % 360 === 0 &&
1168 item[ 2 ] % 360 === 0 &&
1169 item[ 3 ] % 360 === 0
1170 ) {
1171 return;
1172 }
1173 if ( item[ 0 ] === 'scale' ) {
1174 lastScale = idx;
1175 } else {
1176 return false;
1177 }
1178 } );
1179
1180 if ( lastScale !== eventData.current.oldLastScale ) {
1181 zoomin = zoomout = false;
1182 eventData.current.oldLastScale = lastScale;
1183 }
1184
1185 var extracted = [];
1186 if ( lastScale !== -1 ) {
1187 while ( lastScale >= 0 ) {
1188 if ( target.transform[ lastScale ][ 0 ] === 'scale' ) {
1189 extracted.push( target.transform[ lastScale ] );
1190 target.transform[ lastScale ] = [ 'scale' ];
1191 }
1192 lastScale--;
1193 }
1194 }
1195
1196 var animation = settings.animation;
1197 if ( settings.reasonableAnimation[ eventData.reason ] ) {
1198 animation = $.extend( {}, animation, settings.reasonableAnimation[ eventData.reason ] );
1199 }
1200
1201 props = {
1202 // to keep the perspective look similar for different scales
1203 // we need to 'scale' the perspective, too
1204 perspective: Math.round( target.perspectiveScale * 1000 ) + 'px',
1205 };
1206 props = $.extend( {}, animation, props );
1207 if ( ! zoomin ) {
1208 props.transitionDelay = '0s';
1209 }
1210 if ( ! eventData.beforeActive ) {
1211 props.transitionDuration = '0s';
1212 props.transitionDelay = '0s';
1213 }
1214 $.jmpress( 'css', eventData.area, props );
1215 engine.transform( eventData.area, extracted );
1216
1217 props = $.extend( {}, animation );
1218 if ( ! zoomout ) {
1219 props.transitionDelay = '0s';
1220 }
1221 if ( ! eventData.beforeActive ) {
1222 props.transitionDuration = '0s';
1223 props.transitionDelay = '0s';
1224 }
1225
1226 eventData.current.perspectiveScale = target.perspectiveScale;
1227
1228 $.jmpress( 'css', eventData.canvas, props );
1229 engine.transform( eventData.canvas, target.transform );
1230 } );
1231 } )( jQuery, document, window );
1232 /*
1233 * active.js
1234 * Set the active classes on steps
1235 */
1236 ( function ( $, document, window, undefined ) {
1237 'use strict';
1238 var $jmpress = $.jmpress;
1239
1240 /* DEFINES */
1241 var activeClass = 'activeClass',
1242 nestedActiveClass = 'nestedActiveClass';
1243
1244 /* DEFAULTS */
1245 var defaults = $jmpress( 'defaults' );
1246 defaults[ nestedActiveClass ] = 'nested-active';
1247 defaults[ activeClass ] = 'active';
1248
1249 /* HOOKS */
1250 $jmpress( 'setInactive', function ( step, eventData ) {
1251 var settings = eventData.settings,
1252 activeClassSetting = settings[ activeClass ],
1253 nestedActiveClassSettings = settings[ nestedActiveClass ];
1254 if ( activeClassSetting ) {
1255 $( step ).removeClass( activeClassSetting );
1256 }
1257 if ( nestedActiveClassSettings ) {
1258 $.each( eventData.parents, function ( idx, element ) {
1259 $( element ).removeClass( nestedActiveClassSettings );
1260 } );
1261 }
1262 } );
1263 $jmpress( 'setActive', function ( step, eventData ) {
1264 var settings = eventData.settings,
1265 activeClassSetting = settings[ activeClass ],
1266 nestedActiveClassSettings = settings[ nestedActiveClass ];
1267 if ( activeClassSetting ) {
1268 $( step ).addClass( activeClassSetting );
1269 }
1270 if ( nestedActiveClassSettings ) {
1271 $.each( eventData.parents, function ( idx, element ) {
1272 $( element ).addClass( nestedActiveClassSettings );
1273 } );
1274 }
1275 } );
1276 } )( jQuery, document, window );
1277 /*
1278 * circular.js
1279 * Repeat from start after end
1280 */
1281 ( function ( $, document, window, undefined ) {
1282 'use strict';
1283 var $jmpress = $.jmpress;
1284
1285 /* FUNCTIONS */
1286 function firstSlide( step, eventData ) {
1287 return $( this ).find( eventData.settings.stepSelector ).first();
1288 }
1289 function prevOrNext( jmpress, step, eventData, prev ) {
1290 if ( ! step ) {
1291 return false;
1292 }
1293 var stepSelector = eventData.settings.stepSelector;
1294 step = $( step );
1295 do {
1296 var item = step.near( stepSelector, prev );
1297 if ( item.length === 0 || item.closest( jmpress ).length === 0 ) {
1298 item = $( jmpress ).find( stepSelector )[ prev ? 'last' : 'first' ](); // eslint-disable-line no-unexpected-multiline
1299 }
1300 if ( ! item.length ) {
1301 return false;
1302 }
1303 step = item;
1304 } while ( step.data( 'stepData' ).exclude );
1305 return step;
1306 }
1307
1308 /* HOOKS */
1309 $jmpress( 'initStep', function ( step, eventData ) {
1310 eventData.stepData.exclude =
1311 eventData.data.exclude && [ 'false', 'no' ].indexOf( eventData.data.exclude ) === -1;
1312 } );
1313 $jmpress( 'selectInitialStep', firstSlide );
1314 $jmpress( 'selectHome', firstSlide );
1315 $jmpress( 'selectEnd', function ( step, eventData ) {
1316 return $( this ).find( eventData.settings.stepSelector ).last();
1317 } );
1318 $jmpress( 'selectPrev', function ( step, eventData ) {
1319 return prevOrNext( this, step, eventData, true );
1320 } );
1321 $jmpress( 'selectNext', function ( step, eventData ) {
1322 return prevOrNext( this, step, eventData );
1323 } );
1324 } )( jQuery, document, window );
1325 /*
1326 * start.js
1327 * Set the first step to start on
1328 */
1329 ( function ( $, document, window, undefined ) {
1330 'use strict';
1331
1332 /* HOOKS */
1333 $.jmpress( 'selectInitialStep', function ( nil, eventData ) {
1334 return eventData.settings.start;
1335 } );
1336 } )( jQuery, document, window );
1337 /*
1338 * ways.js
1339 * Control the flow of the steps
1340 */
1341 ( function ( $, document, window, undefined ) {
1342 'use strict';
1343 var $jmpress = $.jmpress;
1344
1345 /* FUNCTIONS */
1346 function routeFunc( jmpress, route, type ) {
1347 for ( var i = 0; i < route.length - 1; i++ ) {
1348 var from = route[ i ];
1349 var to = route[ i + 1 ];
1350 if ( $( jmpress ).jmpress( 'initialized' ) ) {
1351 $( from, jmpress ).data( 'stepData' )[ type ] = to;
1352 } else {
1353 $( from, jmpress ).attr( 'data-' + type, to );
1354 }
1355 }
1356 }
1357 function selectPrevOrNext( step, eventData, attr, prev ) {
1358 var stepData = eventData.stepData;
1359 if ( stepData[ attr ] ) {
1360 var near = $( step ).near( stepData[ attr ], prev );
1361 if ( near && near.length ) {
1362 return near;
1363 }
1364 near = $( stepData[ attr ], this )[ prev ? 'last' : 'first' ]();
1365 if ( near && near.length ) {
1366 return near;
1367 }
1368 }
1369 }
1370
1371 /* EXPORTED FUNCTIONS */
1372 $jmpress( 'register', 'route', function ( route, unidirectional, reversedRoute ) {
1373 if ( typeof route === 'string' ) {
1374 route = [ route, route ];
1375 }
1376 routeFunc( this, route, reversedRoute ? 'prev' : 'next' );
1377 if ( ! unidirectional ) {
1378 routeFunc( this, route.reverse(), reversedRoute ? 'next' : 'prev' );
1379 }
1380 } );
1381
1382 /* HOOKS */
1383 $jmpress( 'initStep', function ( step, eventData ) {
1384 for ( var attr in { next: 1, prev: 1 } ) {
1385 eventData.stepData[ attr ] = eventData.data[ attr ];
1386 }
1387 } );
1388 $jmpress( 'selectNext', function ( step, eventData ) {
1389 return selectPrevOrNext.call( this, step, eventData, 'next' );
1390 } );
1391 $jmpress( 'selectPrev', function ( step, eventData ) {
1392 return selectPrevOrNext.call( this, step, eventData, 'prev', true );
1393 } );
1394 } )( jQuery, document, window );
1395 /*
1396 * ajax.js
1397 * Load steps via ajax
1398 */
1399 ( function ( $, document, window, undefined ) {
1400 'use strict';
1401 var $jmpress = $.jmpress;
1402
1403 /* DEFINES */
1404 var afterStepLoaded = 'ajax:afterStepLoaded',
1405 loadStep = 'ajax:loadStep';
1406
1407 /* REGISTER EVENTS */
1408 $jmpress( 'register', loadStep );
1409 $jmpress( 'register', afterStepLoaded );
1410
1411 /* DEFAULTS */
1412 $jmpress( 'defaults' ).ajaxLoadedClass = 'loaded';
1413
1414 /* HOOKS */
1415 $jmpress( 'initStep', function ( step, eventData ) {
1416 eventData.stepData.src = $( step ).attr( 'href' ) || eventData.data.src || false;
1417 eventData.stepData.srcLoaded = false;
1418 } );
1419 $jmpress( loadStep, function ( step, eventData ) {
1420 var stepData = eventData.stepData,
1421 href = stepData && stepData.src,
1422 settings = eventData.settings;
1423 if ( href ) {
1424 $( step ).addClass( settings.ajaxLoadedClass );
1425 stepData.srcLoaded = true;
1426 $( step ).load( href, function ( response, status, xhr ) {
1427 $( eventData.jmpress ).jmpress(
1428 'fire',
1429 afterStepLoaded,
1430 step,
1431 $.extend( {}, eventData, {
1432 response: response,
1433 status: status,
1434 xhr: xhr,
1435 } )
1436 );
1437 } );
1438 }
1439 } );
1440 $jmpress( 'idle', function ( step, eventData ) {
1441 if ( ! step ) {
1442 return;
1443 }
1444 var settings = eventData.settings,
1445 jmpress = $( this ),
1446 stepData = eventData.stepData;
1447 var siblings = $( step )
1448 .add( $( step ).near( settings.stepSelector ) )
1449 .add( $( step ).near( settings.stepSelector, true ) )
1450 .add(
1451 jmpress.jmpress( 'fire', 'selectPrev', step, {
1452 stepData: $( step ).data( 'stepData' ),
1453 } )
1454 )
1455 .add(
1456 jmpress.jmpress( 'fire', 'selectNext', step, {
1457 stepData: $( step ).data( 'stepData' ),
1458 } )
1459 );
1460 siblings.each( function () {
1461 var step = this,
1462 stepData = $( step ).data( 'stepData' );
1463 if ( ! stepData.src || stepData.srcLoaded ) {
1464 return;
1465 }
1466 jmpress.jmpress( 'fire', loadStep, step, {
1467 stepData: $( step ).data( 'stepData' ),
1468 } );
1469 } );
1470 } );
1471 $jmpress( 'setActive', function ( step, eventData ) {
1472 var stepData = $( step ).data( 'stepData' );
1473 if ( ! stepData.src || stepData.srcLoaded ) {
1474 return;
1475 }
1476 $( this ).jmpress( 'fire', loadStep, step, {
1477 stepData: $( step ).data( 'stepData' ),
1478 } );
1479 } );
1480 } )( jQuery, document, window );
1481 /*
1482 * hash.js
1483 * Detect and set the URL hash
1484 */
1485 ( function ( $, document, window, undefined ) {
1486 'use strict';
1487 var $jmpress = $.jmpress,
1488 hashLink = "a[href^='#']";
1489
1490 /* FUNCTIONS */
1491 function randomString() {
1492 return '' + Math.round( Math.random() * 100000, 0 );
1493 }
1494 /**
1495 * getElementFromUrl
1496 *
1497 * @return String or undefined
1498 */
1499 function getElementFromUrl( settings ) {
1500 // get id from url # by removing `#` or `#/` from the beginning,
1501 // so both "fallback" `#slide-id` and "enhanced" `#/slide-id` will work
1502 // TODO SECURITY check user input to be valid!
1503 try {
1504 var el = $( '#' + window.location.hash.replace( /^#\/?/, '' ) );
1505 return el.length > 0 && el.is( settings.stepSelector ) ? el : undefined;
1506 } catch ( e ) {}
1507 }
1508 function setHash( stepid ) {
1509 var shouldBeHash = '#/' + stepid;
1510 if ( window.history && window.history.pushState ) {
1511 // shouldBeHash = "#" + stepid;
1512 // consider this for future versions
1513 // it has currently issues, when startup with a link with hash (webkit)
1514 if ( window.location.hash !== shouldBeHash ) {
1515 window.history.pushState( {}, '', shouldBeHash );
1516 }
1517 } else {
1518 if ( window.location.hash !== shouldBeHash ) {
1519 window.location.hash = shouldBeHash;
1520 }
1521 }
1522 }
1523
1524 /* DEFAULTS */
1525 $jmpress( 'defaults' ).hash = {
1526 use: true,
1527 update: true,
1528 bindChange: true,
1529 // NOTICE: {use: true, update: false, bindChange: true}
1530 // will cause a error after clicking on a link to the current step
1531 };
1532
1533 /* HOOKS */
1534 $jmpress( 'selectInitialStep', function ( step, eventData ) {
1535 var settings = eventData.settings,
1536 hashSettings = settings.hash,
1537 current = eventData.current,
1538 jmpress = $( this );
1539 eventData.current.hashNamespace = '.jmpress-' + randomString();
1540 // HASH CHANGE EVENT
1541 if ( hashSettings.use ) {
1542 if ( hashSettings.bindChange ) {
1543 $( window ).bind( 'hashchange' + current.hashNamespace, function ( event ) {
1544 var urlItem = getElementFromUrl( settings );
1545 if ( jmpress.jmpress( 'initialized' ) ) {
1546 jmpress.jmpress( 'scrollFix' );
1547 }
1548 if ( urlItem && urlItem.length ) {
1549 if ( urlItem.attr( 'id' ) !== jmpress.jmpress( 'active' ).attr( 'id' ) ) {
1550 jmpress.jmpress( 'select', urlItem );
1551 }
1552 setHash( urlItem.attr( 'id' ) );
1553 }
1554 event.preventDefault();
1555 } );
1556 $( hashLink ).on( 'click' + current.hashNamespace, function ( event ) {
1557 var href = $( this ).attr( 'href' );
1558 try {
1559 if ( $( href ).is( settings.stepSelector ) ) {
1560 jmpress.jmpress( 'select', href );
1561 event.preventDefault();
1562 event.stopPropagation();
1563 }
1564 } catch ( e ) {}
1565 } );
1566 }
1567 return getElementFromUrl( settings );
1568 }
1569 } );
1570 $jmpress( 'afterDeinit', function ( nil, eventData ) {
1571 $( hashLink ).off( eventData.current.hashNamespace );
1572 $( window ).unbind( eventData.current.hashNamespace );
1573 } );
1574 $jmpress( 'setActive', function ( step, eventData ) {
1575 var settings = eventData.settings,
1576 current = eventData.current;
1577 // `#/step-id` is used instead of `#step-id` to prevent default browser
1578 // scrolling to element in hash
1579 if ( settings.hash.use && settings.hash.update ) {
1580 clearTimeout( current.hashtimeout );
1581 current.hashtimeout = setTimeout( function () {
1582 setHash( $( eventData.delegatedFrom ).attr( 'id' ) );
1583 }, settings.transitionDuration + 200 );
1584 }
1585 } );
1586 } )( jQuery, document, window );
1587 /*
1588 * keyboard.js
1589 * Keyboard event mapping and default keyboard actions
1590 */
1591 ( function ( $, document, window, undefined ) {
1592 'use strict';
1593 var $jmpress = $.jmpress,
1594 jmpressNext = 'next',
1595 jmpressPrev = 'prev';
1596
1597 /* FUNCTIONS */
1598 function randomString() {
1599 return '' + Math.round( Math.random() * 100000, 0 );
1600 }
1601 function stopEvent( event ) {
1602 event.preventDefault();
1603 event.stopPropagation();
1604 }
1605
1606 /* DEFAULTS */
1607 $jmpress( 'defaults' ).keyboard = {
1608 use: true,
1609 keys: {
1610 33: jmpressPrev, // pg up
1611 37: jmpressPrev, // left
1612 38: jmpressPrev, // up
1613
1614 9: jmpressNext + ':' + jmpressPrev, // tab
1615 32: jmpressNext, // space
1616 34: jmpressNext, // pg down
1617 39: jmpressNext, // right
1618 40: jmpressNext, // down
1619
1620 36: 'home', // home
1621
1622 35: 'end', // end
1623 },
1624 ignore: {
1625 INPUT: [
1626 32, // space
1627 37, // left
1628 38, // up
1629 39, // right
1630 40, // down
1631 ],
1632 TEXTAREA: [
1633 32, // space
1634 37, // left
1635 38, // up
1636 39, // right
1637 40, // down
1638 ],
1639 SELECT: [
1640 38, // up
1641 40, // down
1642 ],
1643 },
1644 tabSelector: 'a[href]:visible, :input:visible',
1645 };
1646
1647 /* HOOKS */
1648 $jmpress( 'afterInit', function ( nil, eventData ) {
1649 var settings = eventData.settings,
1650 keyboardSettings = settings.keyboard,
1651 ignoreKeyboardSettings = keyboardSettings.ignore,
1652 current = eventData.current,
1653 jmpress = $( this );
1654
1655 // tabindex make it focusable so that it can receive key events
1656 if ( ! settings.fullscreen ) {
1657 jmpress.attr( 'tabindex', 0 );
1658 }
1659
1660 current.keyboardNamespace = '.jmpress-' + randomString();
1661
1662 // KEYPRESS EVENT: this fixes a Opera bug
1663 $( settings.fullscreen ? document : jmpress ).bind(
1664 'keypress' + current.keyboardNamespace,
1665 function ( event ) {
1666 for ( var nodeName in ignoreKeyboardSettings ) {
1667 if (
1668 event.target.nodeName === nodeName &&
1669 ignoreKeyboardSettings[ nodeName ].indexOf( event.which ) !== -1
1670 ) {
1671 return;
1672 }
1673 }
1674 if ( ( event.which >= 37 && event.which <= 40 ) || event.which === 32 ) {
1675 stopEvent( event );
1676 }
1677 }
1678 );
1679 // KEYDOWN EVENT
1680 $( settings.fullscreen ? document : jmpress ).bind(
1681 'keydown' + current.keyboardNamespace,
1682 function ( event ) {
1683 var eventTarget = $( event.target );
1684
1685 if (
1686 ( ! settings.fullscreen && ! eventTarget.closest( jmpress ).length ) ||
1687 ! keyboardSettings.use
1688 ) {
1689 return;
1690 }
1691
1692 for ( var nodeName in ignoreKeyboardSettings ) {
1693 if (
1694 eventTarget[ 0 ].nodeName === nodeName &&
1695 ignoreKeyboardSettings[ nodeName ].indexOf( event.which ) !== -1
1696 ) {
1697 return;
1698 }
1699 }
1700
1701 var reverseSelect = false;
1702 var nextFocus;
1703 if ( event.which === 9 ) {
1704 // tab
1705 if ( ! eventTarget.closest( jmpress.jmpress( 'active' ) ).length ) {
1706 if ( ! event.shiftKey ) {
1707 nextFocus = jmpress
1708 .jmpress( 'active' )
1709 .find( 'a[href], :input' )
1710 .filter( ':visible' )
1711 .first();
1712 } else {
1713 reverseSelect = true;
1714 }
1715 } else {
1716 nextFocus = eventTarget.near( keyboardSettings.tabSelector, event.shiftKey );
1717 if (
1718 ! $( nextFocus ).closest( settings.stepSelector ).is( jmpress.jmpress( 'active' ) )
1719 ) {
1720 nextFocus = undefined;
1721 }
1722 }
1723 if ( nextFocus && nextFocus.length > 0 ) {
1724 nextFocus.focus();
1725 jmpress.jmpress( 'scrollFix' );
1726 stopEvent( event );
1727 return;
1728 } else {
1729 if ( event.shiftKey ) {
1730 reverseSelect = true;
1731 }
1732 }
1733 }
1734
1735 var action = keyboardSettings.keys[ event.which ];
1736 if ( typeof action === 'string' ) {
1737 if ( action.indexOf( ':' ) !== -1 ) {
1738 action = action.split( ':' );
1739 action = event.shiftKey ? action[ 1 ] : action[ 0 ];
1740 }
1741 jmpress.jmpress( action );
1742 stopEvent( event );
1743 } else if ( $.isFunction( action ) ) {
1744 action.call( jmpress, event );
1745 } else if ( action ) {
1746 jmpress.jmpress.apply( jmpress, action );
1747 stopEvent( event );
1748 }
1749
1750 if ( reverseSelect ) {
1751 // tab
1752 nextFocus = jmpress
1753 .jmpress( 'active' )
1754 .find( 'a[href], :input' )
1755 .filter( ':visible' )
1756 .last();
1757 nextFocus.focus();
1758 jmpress.jmpress( 'scrollFix' );
1759 }
1760 }
1761 );
1762 } );
1763 $jmpress( 'afterDeinit', function ( nil, eventData ) {
1764 $( document ).unbind( eventData.current.keyboardNamespace );
1765 } );
1766 } )( jQuery, document, window );
1767 /*
1768 * viewport.js
1769 * Scale to fit a given viewport
1770 */
1771 ( function ( $, document, window, undefined ) {
1772 'use strict';
1773
1774 function randomString() {
1775 return '' + Math.round( Math.random() * 100000, 0 );
1776 }
1777
1778 var browser = ( function () {
1779 var ua = navigator.userAgent.toLowerCase();
1780 var match =
1781 /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
1782 /(webkit)[ \/]([\w.]+)/.exec( ua ) ||
1783 /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
1784 /(msie) ([\w.]+)/.exec( ua ) ||
1785 ( ua.indexOf( 'compatible' ) < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ) ||
1786 [];
1787 return match[ 1 ] || '';
1788 } )();
1789
1790 var defaults = $.jmpress( 'defaults' );
1791 defaults.viewPort = {
1792 width: false,
1793 height: false,
1794 maxScale: 0,
1795 minScale: 0,
1796 zoomable: 0,
1797 zoomBindMove: true,
1798 zoomBindWheel: true,
1799 };
1800 var keys = defaults.keyboard.keys;
1801 keys[ browser === 'mozilla' ? 107 : 187 ] = 'zoomIn'; // +
1802 keys[ browser === 'mozilla' ? 109 : 189 ] = 'zoomOut'; // -
1803 defaults.reasonableAnimation.resize = {
1804 transitionDuration: '0s',
1805 transitionDelay: '0ms',
1806 };
1807 defaults.reasonableAnimation.zoom = {
1808 transitionDuration: '0s',
1809 transitionDelay: '0ms',
1810 };
1811 $.jmpress( 'initStep', function ( step, eventData ) {
1812 for ( var variable in {
1813 viewPortHeight: 1,
1814 viewPortWidth: 1,
1815 viewPortMinScale: 1,
1816 viewPortMaxScale: 1,
1817 viewPortZoomable: 1,
1818 } ) {
1819 eventData.stepData[ variable ] =
1820 eventData.data[ variable ] && parseFloat( eventData.data[ variable ] );
1821 }
1822 } );
1823 $.jmpress( 'afterInit', function ( nil, eventData ) {
1824 var jmpress = this;
1825 eventData.current.viewPortNamespace = '.jmpress-' + randomString();
1826 $( window ).bind( 'resize' + eventData.current.viewPortNamespace, function ( event ) {
1827 $( jmpress ).jmpress( 'reselect', 'resize' );
1828 } );
1829 eventData.current.userZoom = 0;
1830 eventData.current.userTranslateX = 0;
1831 eventData.current.userTranslateY = 0;
1832 if ( eventData.settings.viewPort.zoomBindWheel ) {
1833 $( eventData.settings.fullscreen ? document : this ).bind(
1834 'mousewheel' +
1835 eventData.current.viewPortNamespace +
1836 ' DOMMouseScroll' +
1837 eventData.current.viewPortNamespace,
1838 function ( event, delta ) {
1839 delta =
1840 delta || event.originalEvent.wheelDelta || -event.originalEvent.detail /* mozilla */;
1841 var direction = delta / Math.abs( delta );
1842 if ( direction < 0 ) {
1843 $( eventData.jmpress ).jmpress(
1844 'zoomOut',
1845 event.originalEvent.x,
1846 event.originalEvent.y
1847 );
1848 } else if ( direction > 0 ) {
1849 $( eventData.jmpress ).jmpress(
1850 'zoomIn',
1851 event.originalEvent.x,
1852 event.originalEvent.y
1853 );
1854 }
1855 return false;
1856 }
1857 );
1858 }
1859 if ( eventData.settings.viewPort.zoomBindMove ) {
1860 $( eventData.settings.fullscreen ? document : this )
1861 .bind( 'mousedown' + eventData.current.viewPortNamespace, function ( event ) {
1862 if ( eventData.current.userZoom ) {
1863 eventData.current.userTranslating = { x: event.clientX, y: event.clientY };
1864 event.preventDefault();
1865 event.stopImmediatePropagation();
1866 }
1867 } )
1868 .bind( 'mousemove' + eventData.current.viewPortNamespace, function ( event ) {
1869 var userTranslating = eventData.current.userTranslating;
1870 if ( userTranslating ) {
1871 $( jmpress ).jmpress(
1872 'zoomTranslate',
1873 event.clientX - userTranslating.x,
1874 event.clientY - userTranslating.y
1875 );
1876 userTranslating.x = event.clientX;
1877 userTranslating.y = event.clientY;
1878 event.preventDefault();
1879 event.stopImmediatePropagation();
1880 }
1881 } )
1882 .bind( 'mouseup' + eventData.current.viewPortNamespace, function ( event ) {
1883 if ( eventData.current.userTranslating ) {
1884 eventData.current.userTranslating = undefined;
1885 event.preventDefault();
1886 event.stopImmediatePropagation();
1887 }
1888 } );
1889 }
1890 } );
1891 function maxAbs( value, range ) {
1892 return Math.max( Math.min( value, range ), -range );
1893 }
1894 function zoom( x, y, direction ) {
1895 var current = $( this ).jmpress( 'current' ),
1896 settings = $( this ).jmpress( 'settings' ),
1897 stepData = $( this ).jmpress( 'active' ).data( 'stepData' ),
1898 container = $( this ).jmpress( 'container' );
1899 if ( current.userZoom === 0 && direction < 0 ) {
1900 return;
1901 }
1902 var zoomableSteps = stepData.viewPortZoomable || settings.viewPort.zoomable;
1903 if ( current.userZoom === zoomableSteps && direction > 0 ) {
1904 return;
1905 }
1906 current.userZoom += direction;
1907
1908 var halfWidth = $( container ).innerWidth() / 2,
1909 halfHeight = $( container ).innerHeight() / 2;
1910
1911 x = x ? x - halfWidth : x;
1912 y = y ? y - halfHeight : y;
1913
1914 // TODO this is not perfect... too much math... :(
1915 current.userTranslateX = maxAbs(
1916 current.userTranslateX - ( direction * x ) / current.zoomOriginWindowScale / zoomableSteps,
1917 ( halfWidth * current.userZoom * current.userZoom ) / zoomableSteps
1918 );
1919 current.userTranslateY = maxAbs(
1920 current.userTranslateY - ( direction * y ) / current.zoomOriginWindowScale / zoomableSteps,
1921 ( halfHeight * current.userZoom * current.userZoom ) / zoomableSteps
1922 );
1923
1924 $( this ).jmpress( 'reselect', 'zoom' );
1925 }
1926 $.jmpress( 'register', 'zoomIn', function ( x, y ) {
1927 zoom.call( this, x || 0, y || 0, 1 );
1928 } );
1929 $.jmpress( 'register', 'zoomOut', function ( x, y ) {
1930 zoom.call( this, x || 0, y || 0, -1 );
1931 } );
1932 $.jmpress( 'register', 'zoomTranslate', function ( x, y ) {
1933 var current = $( this ).jmpress( 'current' ),
1934 settings = $( this ).jmpress( 'settings' ),
1935 stepData = $( this ).jmpress( 'active' ).data( 'stepData' ),
1936 container = $( this ).jmpress( 'container' );
1937 var zoomableSteps = stepData.viewPortZoomable || settings.viewPort.zoomable;
1938 var halfWidth = $( container ).innerWidth(),
1939 halfHeight = $( container ).innerHeight();
1940 current.userTranslateX = maxAbs(
1941 current.userTranslateX + x / current.zoomOriginWindowScale,
1942 ( halfWidth * current.userZoom * current.userZoom ) / zoomableSteps
1943 );
1944 current.userTranslateY = maxAbs(
1945 current.userTranslateY + y / current.zoomOriginWindowScale,
1946 ( halfHeight * current.userZoom * current.userZoom ) / zoomableSteps
1947 );
1948 $( this ).jmpress( 'reselect', 'zoom' );
1949 } );
1950 $.jmpress( 'afterDeinit', function ( nil, eventData ) {
1951 $( eventData.settings.fullscreen ? document : this ).unbind(
1952 eventData.current.viewPortNamespace
1953 );
1954 $( window ).unbind( eventData.current.viewPortNamespace );
1955 } );
1956 $.jmpress( 'setActive', function ( step, eventData ) {
1957 var viewPort = eventData.settings.viewPort;
1958 var viewPortHeight = eventData.stepData.viewPortHeight || viewPort.height;
1959 var viewPortWidth = eventData.stepData.viewPortWidth || viewPort.width;
1960 var viewPortMaxScale = eventData.stepData.viewPortMaxScale || viewPort.maxScale;
1961 var viewPortMinScale = eventData.stepData.viewPortMinScale || viewPort.minScale;
1962 // Correct the scale based on the window's size
1963 var windowScaleY = viewPortHeight && $( eventData.container ).innerHeight() / viewPortHeight;
1964 var windowScaleX = viewPortWidth && $( eventData.container ).innerWidth() / viewPortWidth;
1965 var windowScale =
1966 ( windowScaleX || windowScaleY ) &&
1967 Math.min( windowScaleX || windowScaleY, windowScaleY || windowScaleX );
1968
1969 if ( windowScale ) {
1970 windowScale = windowScale || 1;
1971 if ( viewPortMaxScale ) {
1972 windowScale = Math.min( windowScale, viewPortMaxScale );
1973 }
1974 if ( viewPortMinScale ) {
1975 windowScale = Math.max( windowScale, viewPortMinScale );
1976 }
1977
1978 var zoomableSteps =
1979 eventData.stepData.viewPortZoomable || eventData.settings.viewPort.zoomable;
1980 if ( zoomableSteps ) {
1981 var diff = 1 / windowScale - 1 / viewPortMaxScale;
1982 diff /= zoomableSteps;
1983 windowScale = 1 / ( 1 / windowScale - diff * eventData.current.userZoom );
1984 }
1985
1986 eventData.target.transform.reverse();
1987 if ( eventData.current.userTranslateX && eventData.current.userTranslateY ) {
1988 eventData.target.transform.push( [
1989 'translate',
1990 eventData.current.userTranslateX,
1991 eventData.current.userTranslateY,
1992 0,
1993 ] );
1994 } else {
1995 eventData.target.transform.push( [ 'translate' ] );
1996 }
1997 eventData.target.transform.push( [ 'scale', windowScale, windowScale, 1 ] );
1998 eventData.target.transform.reverse();
1999 eventData.target.perspectiveScale /= windowScale;
2000 }
2001 eventData.current.zoomOriginWindowScale = windowScale;
2002 } );
2003 $.jmpress( 'setInactive', function ( step, eventData ) {
2004 if (
2005 ! eventData.nextStep ||
2006 ! step ||
2007 $( eventData.nextStep ).attr( 'id' ) !== $( step ).attr( 'id' )
2008 ) {
2009 eventData.current.userZoom = 0;
2010 eventData.current.userTranslateX = 0;
2011 eventData.current.userTranslateY = 0;
2012 }
2013 } );
2014 } )( jQuery, document, window );
2015
2016 /*
2017 * mouse.js
2018 * Clicking to select a step
2019 */
2020 ( function ( $, document, window, undefined ) {
2021 'use strict';
2022 var $jmpress = $.jmpress;
2023
2024 /* FUNCTIONS */
2025 function randomString() {
2026 return '' + Math.round( Math.random() * 100000, 0 );
2027 }
2028
2029 /* DEFAULTS */
2030 $jmpress( 'defaults' ).mouse = {
2031 clickSelects: true,
2032 };
2033
2034 /* HOOKS */
2035 $jmpress( 'afterInit', function ( nil, eventData ) {
2036 var settings = eventData.settings,
2037 stepSelector = settings.stepSelector,
2038 current = eventData.current,
2039 jmpress = $( this );
2040 current.clickableStepsNamespace = '.jmpress-' + randomString();
2041 jmpress.bind( 'click' + current.clickableStepsNamespace, function ( event ) {
2042 if ( ! settings.mouse.clickSelects || current.userZoom ) {
2043 return;
2044 }
2045
2046 // get clicked step
2047 var clickedStep = $( event.target ).closest( stepSelector );
2048
2049 // clicks on the active step do default
2050 if ( clickedStep.is( jmpress.jmpress( 'active' ) ) ) {
2051 return;
2052 }
2053
2054 if ( clickedStep.length ) {
2055 // select the clicked step
2056 jmpress.jmpress( 'select', clickedStep[ 0 ], 'click' );
2057 event.preventDefault();
2058 event.stopPropagation();
2059 }
2060 } );
2061 } );
2062 $jmpress( 'afterDeinit', function ( nil, eventData ) {
2063 $( this ).unbind( eventData.current.clickableStepsNamespace );
2064 } );
2065 } )( jQuery, document, window );
2066 /*
2067 * mobile.js
2068 * Adds support for swipe on touch supported browsers
2069 */
2070 ( function ( $, document, window, undefined ) {
2071 'use strict';
2072 var $jmpress = $.jmpress;
2073
2074 /* FUNCTIONS */
2075 function randomString() {
2076 return '' + Math.round( Math.random() * 100000, 0 );
2077 }
2078
2079 /* HOOKS */
2080 $jmpress( 'afterInit', function ( step, eventData ) {
2081 var settings = eventData.settings,
2082 current = eventData.current,
2083 jmpress = eventData.jmpress;
2084 current.mobileNamespace = '.jmpress-' + randomString();
2085 var data,
2086 start = [ 0, 0 ];
2087 $( settings.fullscreen ? document : jmpress )
2088 .bind( 'touchstart' + current.mobileNamespace, function ( event ) {
2089 data = event.originalEvent.touches[ 0 ];
2090 start = [ data.pageX, data.pageY ];
2091 } )
2092 .bind( 'touchmove' + current.mobileNamespace, function ( event ) {
2093 data = event.originalEvent.touches[ 0 ];
2094 event.preventDefault();
2095 return false;
2096 } )
2097 .bind( 'touchend' + current.mobileNamespace, function ( event ) {
2098 var end = [ data.pageX, data.pageY ],
2099 diff = [ end[ 0 ] - start[ 0 ], end[ 1 ] - start[ 1 ] ];
2100
2101 if ( Math.max( Math.abs( diff[ 0 ] ), Math.abs( diff[ 1 ] ) ) > 50 ) {
2102 diff = Math.abs( diff[ 0 ] ) > Math.abs( diff[ 1 ] ) ? diff[ 0 ] : diff[ 1 ];
2103 $( jmpress ).jmpress( diff > 0 ? 'prev' : 'next' );
2104 event.preventDefault();
2105 return false;
2106 }
2107 } );
2108 } );
2109 $jmpress( 'afterDeinit', function ( nil, eventData ) {
2110 var settings = eventData.settings,
2111 current = eventData.current,
2112 jmpress = eventData.jmpress;
2113 $( settings.fullscreen ? document : jmpress ).unbind( current.mobileNamespace );
2114 } );
2115 } )( jQuery, document, window );
2116 /*
2117 * templates.js
2118 * The amazing template engine
2119 */
2120 ( function ( $, document, window, undefined ) {
2121 'use strict';
2122 var $jmpress = $.jmpress,
2123 templateFromParentIdent = '_template_',
2124 templateFromApplyIdent = '_applied_template_';
2125
2126 /* STATIC VARS */
2127 var templates = {};
2128
2129 /* FUNCTIONS */
2130 function addUndefined( target, values, prefix ) {
2131 for ( var name in values ) {
2132 var targetName = name;
2133 if ( prefix ) {
2134 targetName = prefix + targetName.substr( 0, 1 ).toUpperCase() + targetName.substr( 1 );
2135 }
2136 if ( $.isPlainObject( values[ name ] ) ) {
2137 addUndefined( target, values[ name ], targetName );
2138 } else if ( target[ targetName ] === undefined ) {
2139 target[ targetName ] = values[ name ];
2140 }
2141 }
2142 }
2143 function applyChildrenTemplates( children, templateChildren ) {
2144 if ( $.isArray( templateChildren ) ) {
2145 if ( templateChildren.length < children.length ) {
2146 $.error( 'more nested steps than children in template' );
2147 } else {
2148 children.each( function ( idx, child ) {
2149 child = $( child );
2150 var tmpl = child.data( templateFromParentIdent ) || {};
2151 addUndefined( tmpl, templateChildren[ idx ] );
2152 child.data( templateFromParentIdent, tmpl );
2153 } );
2154 }
2155 } else if ( $.isFunction( templateChildren ) ) {
2156 children.each( function ( idx, child ) {
2157 child = $( child );
2158 var tmpl = child.data( templateFromParentIdent ) || {};
2159 addUndefined( tmpl, templateChildren( idx, child, children ) );
2160 child.data( templateFromParentIdent, tmpl );
2161 } );
2162 } // TODO: else if(object)
2163 }
2164 function applyTemplate( data, element, template, eventData ) {
2165 if ( template.children ) {
2166 var children = element.children( eventData.settings.stepSelector );
2167 applyChildrenTemplates( children, template.children );
2168 }
2169 applyTemplateData( data, template );
2170 }
2171 function applyTemplateData( data, template ) {
2172 addUndefined( data, template );
2173 }
2174
2175 /* HOOKS */
2176 $jmpress( 'beforeInitStep', function ( step, eventData ) {
2177 step = $( step );
2178 var data = eventData.data,
2179 templateFromAttr = data.template,
2180 templateFromApply = step.data( templateFromApplyIdent ),
2181 templateFromParent = step.data( templateFromParentIdent );
2182 if ( templateFromAttr ) {
2183 $.each( templateFromAttr.split( ' ' ), function ( idx, tmpl ) {
2184 var template = templates[ tmpl ];
2185 applyTemplate( data, step, template, eventData );
2186 } );
2187 }
2188 if ( templateFromApply ) {
2189 applyTemplate( data, step, templateFromApply, eventData );
2190 }
2191 if ( templateFromParent ) {
2192 applyTemplate( data, step, templateFromParent, eventData );
2193 step.data( templateFromParentIdent, null );
2194 if ( templateFromParent.template ) {
2195 $.each( templateFromParent.template.split( ' ' ), function ( idx, tmpl ) {
2196 var template = templates[ tmpl ];
2197 applyTemplate( data, step, template, eventData );
2198 } );
2199 }
2200 }
2201 } );
2202 $jmpress( 'beforeInit', function ( nil, eventData ) {
2203 var data = $jmpress( 'dataset', this ),
2204 dataTemplate = data.template,
2205 stepSelector = eventData.settings.stepSelector;
2206 if ( dataTemplate ) {
2207 var template = templates[ dataTemplate ];
2208 applyChildrenTemplates(
2209 $( this )
2210 .find( stepSelector )
2211 .filter( function () {
2212 return ! $( this ).parent().is( stepSelector );
2213 } ),
2214 template.children
2215 );
2216 }
2217 } );
2218
2219 /* EXPORTED FUNCTIONS */
2220 $jmpress( 'register', 'template', function ( name, tmpl ) {
2221 if ( templates[ name ] ) {
2222 templates[ name ] = $.extend( true, {}, templates[ name ], tmpl );
2223 } else {
2224 templates[ name ] = $.extend( true, {}, tmpl );
2225 }
2226 } );
2227 $jmpress( 'register', 'apply', function ( selector, tmpl ) {
2228 if ( ! tmpl ) {
2229 // TODO ERROR because settings not found
2230 var stepSelector = $( this ).jmpress( 'settings' ).stepSelector;
2231 applyChildrenTemplates(
2232 $( this )
2233 .find( stepSelector )
2234 .filter( function () {
2235 return ! $( this ).parent().is( stepSelector );
2236 } ),
2237 selector
2238 );
2239 } else if ( $.isArray( tmpl ) ) {
2240 applyChildrenTemplates( $( selector ), tmpl );
2241 } else {
2242 var template;
2243 if ( typeof tmpl === 'string' ) {
2244 template = templates[ tmpl ];
2245 } else {
2246 template = $.extend( true, {}, tmpl );
2247 }
2248 $( selector ).each( function ( idx, element ) {
2249 element = $( element );
2250 var tmpl = element.data( templateFromApplyIdent ) || {};
2251 addUndefined( tmpl, template );
2252 element.data( templateFromApplyIdent, tmpl );
2253 } );
2254 }
2255 } );
2256 } )( jQuery, document, window );
2257 /*
2258 * jqevents.js
2259 * Fires jQuery events
2260 */
2261 ( function ( $, document, window, undefined ) {
2262 'use strict';
2263
2264 /* HOOKS */
2265 // the events should not bubble up the tree
2266 // elsewise nested jmpress would cause buggy behavior
2267 $.jmpress( 'setActive', function ( step, eventData ) {
2268 if ( eventData.prevStep !== step ) {
2269 $( step ).triggerHandler( 'enterStep' );
2270 }
2271 } );
2272 $.jmpress( 'setInactive', function ( step, eventData ) {
2273 if ( eventData.nextStep !== step ) {
2274 $( step ).triggerHandler( 'leaveStep' );
2275 }
2276 } );
2277 } )( jQuery, document, window );
2278 /*
2279 * animation.js
2280 * Apply custom animations to steps
2281 */
2282 ( function ( $, document, window, undefined ) {
2283 'use strict';
2284
2285 function parseSubstepInfo( str ) {
2286 var arr = str.split( ' ' );
2287 var className = arr[ 0 ];
2288 var config = {
2289 willClass: 'will-' + className,
2290 doClass: 'do-' + className,
2291 hasClass: 'has-' + className,
2292 };
2293 var state = '';
2294 for ( var i = 1; i < arr.length; i++ ) {
2295 var s = arr[ i ];
2296 switch ( state ) {
2297 case '':
2298 if ( s === 'after' ) {
2299 state = 'after';
2300 } else {
2301 $.warn( "unknown keyword in '" + str + "'. '" + s + "' unknown." );
2302 }
2303 break;
2304 case 'after':
2305 if ( s.match( /^[1-9][0-9]*m?s?/ ) ) {
2306 var value = parseFloat( s );
2307 if ( s.indexOf( 'ms' ) !== -1 ) {
2308 value *= 1;
2309 } else if ( s.indexOf( 's' ) !== -1 ) {
2310 value *= 1000;
2311 } else if ( s.indexOf( 'm' ) !== -1 ) {
2312 value *= 60000;
2313 }
2314 config.delay = value;
2315 } else {
2316 config.after = Array.prototype.slice.call( arr, i ).join( ' ' );
2317 i = arr.length;
2318 }
2319 }
2320 }
2321 return config;
2322 }
2323 function find( array, selector, start, end ) {
2324 end = end || array.length - 1;
2325 start = start || 0;
2326 for ( var i = start; i < end + 1; i++ ) {
2327 if ( $( array[ i ].element ).is( selector ) ) {
2328 return i;
2329 }
2330 }
2331 }
2332 function addOn( list, substep, delay ) {
2333 $.each( substep._on, function ( idx, child ) {
2334 list.push( { substep: child.substep, delay: child.delay + delay } );
2335 addOn( list, child.substep, child.delay + delay );
2336 } );
2337 }
2338 $.jmpress( 'defaults' ).customAnimationDataAttribute = 'jmpress';
2339 $.jmpress( 'afterInit', function ( nil, eventData ) {
2340 eventData.current.animationTimeouts = [];
2341 eventData.current.animationCleanupWaiting = [];
2342 } );
2343 $.jmpress( 'applyStep', function ( step, eventData ) {
2344 // read custom animation from elements
2345 var substepsData = {};
2346 var listOfSubsteps = [];
2347 $( step )
2348 .find( '[data-' + eventData.settings.customAnimationDataAttribute + ']' )
2349 .each( function ( idx, element ) {
2350 if ( $( element ).closest( eventData.settings.stepSelector ).is( step ) ) {
2351 listOfSubsteps.push( { element: element } );
2352 }
2353 } );
2354 if ( listOfSubsteps.length === 0 ) {
2355 return;
2356 }
2357 $.each( listOfSubsteps, function ( idx, substep ) {
2358 substep.info = parseSubstepInfo(
2359 $( substep.element ).data( eventData.settings.customAnimationDataAttribute )
2360 );
2361 $( substep.element ).addClass( substep.info.willClass );
2362 substep._on = [];
2363 substep._after = null;
2364 } );
2365 var current = { _after: undefined, _on: [], info: {} }; // virtual zero step
2366 $.each( listOfSubsteps, function ( idx, substep ) {
2367 var other = substep.info.after;
2368 if ( other ) {
2369 if ( other === 'step' ) {
2370 other = current;
2371 } else if ( other === 'prev' ) {
2372 other = listOfSubsteps[ idx - 1 ];
2373 } else {
2374 var index = find( listOfSubsteps, other, 0, idx - 1 );
2375 if ( index === undefined ) {
2376 index = find( listOfSubsteps, other );
2377 }
2378 other =
2379 index === undefined || index === idx
2380 ? listOfSubsteps[ idx - 1 ]
2381 : listOfSubsteps[ index ];
2382 }
2383 } else {
2384 other = listOfSubsteps[ idx - 1 ];
2385 }
2386 if ( other ) {
2387 if ( ! substep.info.delay ) {
2388 if ( ! other._after ) {
2389 other._after = substep;
2390 return;
2391 }
2392 other = other._after;
2393 }
2394 other._on.push( { substep: substep, delay: substep.info.delay || 0 } );
2395 }
2396 } );
2397 if ( current._after === undefined && current._on.length === 0 ) {
2398 var startStep = find( listOfSubsteps, eventData.stepData.startSubstep ) || 0;
2399 current._after = listOfSubsteps[ startStep ];
2400 }
2401 var substepsInOrder = [];
2402 function findNextFunc( idx, item ) {
2403 if ( item.substep._after ) {
2404 current = item.substep._after;
2405 return false;
2406 }
2407 }
2408 do {
2409 var substepList = [ { substep: current, delay: 0 } ];
2410 addOn( substepList, current, 0 );
2411 substepsInOrder.push( substepList );
2412 current = null;
2413 $.each( substepList, findNextFunc );
2414 } while ( current );
2415 substepsData.list = substepsInOrder;
2416 $( step ).data( 'substepsData', substepsData );
2417 } );
2418 $.jmpress( 'unapplyStep', function ( step, eventData ) {
2419 var substepsData = $( step ).data( 'substepsData' );
2420 if ( substepsData ) {
2421 $.each( substepsData.list, function ( idx, activeSubsteps ) {
2422 $.each( activeSubsteps, function ( idx, substep ) {
2423 if ( substep.substep.info.willClass ) {
2424 $( substep.substep.element ).removeClass( substep.substep.info.willClass );
2425 }
2426 if ( substep.substep.info.hasClass ) {
2427 $( substep.substep.element ).removeClass( substep.substep.info.hasClass );
2428 }
2429 if ( substep.substep.info.doClass ) {
2430 $( substep.substep.element ).removeClass( substep.substep.info.doClass );
2431 }
2432 } );
2433 } );
2434 }
2435 } );
2436 $.jmpress( 'setActive', function ( step, eventData ) {
2437 var substepsData = $( step ).data( 'substepsData' );
2438 if ( ! substepsData ) {
2439 return;
2440 }
2441 if ( eventData.substep === undefined ) {
2442 eventData.substep = eventData.reason === 'prev' ? substepsData.list.length - 1 : 0;
2443 }
2444 var substep = eventData.substep;
2445 $.each( eventData.current.animationTimeouts, function ( idx, timeout ) {
2446 clearTimeout( timeout );
2447 } );
2448 eventData.current.animationTimeouts = [];
2449 $.each( substepsData.list, function ( idx, activeSubsteps ) {
2450 var applyHas = idx < substep;
2451 var applyDo = idx <= substep;
2452 $.each( activeSubsteps, function ( idx, substep ) {
2453 if ( substep.substep.info.hasClass ) {
2454 $( substep.substep.element )[ ( applyHas ? 'add' : 'remove' ) + 'Class' ](
2455 substep.substep.info.hasClass
2456 );
2457 }
2458 function applyIt() {
2459 $( substep.substep.element ).addClass( substep.substep.info.doClass );
2460 }
2461 if ( applyDo && ! applyHas && substep.delay && eventData.reason !== 'prev' ) {
2462 if ( substep.substep.info.doClass ) {
2463 $( substep.substep.element ).removeClass( substep.substep.info.doClass );
2464 eventData.current.animationTimeouts.push( setTimeout( applyIt, substep.delay ) );
2465 }
2466 } else {
2467 if ( substep.substep.info.doClass ) {
2468 $( substep.substep.element )[ ( applyDo ? 'add' : 'remove' ) + 'Class' ](
2469 substep.substep.info.doClass
2470 );
2471 }
2472 }
2473 } );
2474 } );
2475 } );
2476 $.jmpress( 'setInactive', function ( step, eventData ) {
2477 if ( eventData.nextStep === step ) {
2478 return;
2479 }
2480 function cleanupAnimation( substepsData ) {
2481 $.each( substepsData.list, function ( idx, activeSubsteps ) {
2482 $.each( activeSubsteps, function ( idx, substep ) {
2483 if ( substep.substep.info.hasClass ) {
2484 $( substep.substep.element ).removeClass( substep.substep.info.hasClass );
2485 }
2486 if ( substep.substep.info.doClass ) {
2487 $( substep.substep.element ).removeClass( substep.substep.info.doClass );
2488 }
2489 } );
2490 } );
2491 }
2492 $.each( eventData.current.animationCleanupWaiting, function ( idx, item ) {
2493 cleanupAnimation( item );
2494 } );
2495 eventData.current.animationCleanupWaiting = [];
2496 var substepsData = $( step ).data( 'substepsData' );
2497 if ( substepsData ) {
2498 eventData.current.animationCleanupWaiting.push( substepsData );
2499 }
2500 } );
2501 $.jmpress( 'selectNext', function ( step, eventData ) {
2502 if ( eventData.substep === undefined ) {
2503 return;
2504 }
2505 var substepsData = $( step ).data( 'substepsData' );
2506 if ( ! substepsData ) {
2507 return;
2508 }
2509 if ( eventData.substep < substepsData.list.length - 1 ) {
2510 return { step: step, substep: eventData.substep + 1 };
2511 }
2512 } );
2513 $.jmpress( 'selectPrev', function ( step, eventData ) {
2514 if ( eventData.substep === undefined ) {
2515 return;
2516 }
2517 var substepsData = $( step ).data( 'substepsData' );
2518 if ( ! substepsData ) {
2519 return;
2520 }
2521 if ( eventData.substep > 0 ) {
2522 return { step: step, substep: eventData.substep - 1 };
2523 }
2524 } );
2525 } )( jQuery, document, window );
2526 /*
2527 * jmpress.toggle plugin
2528 * For binding a key to toggle de/initialization of jmpress.js.
2529 */
2530 /*!
2531 * plugin for jmpress.js v0.4.5
2532 *
2533 * Copyright 2013 Kyle Robinson Young @shama & Tobias Koppers @sokra
2534 * Licensed MIT
2535 * http://www.opensource.org/licenses/mit-license.php
2536 */ ( function ( $, document, window, undefined ) {
2537 'use strict';
2538 $.jmpress( 'register', 'toggle', function ( key, config, initial ) {
2539 var jmpress = this;
2540 $( document ).bind( 'keydown', function ( event ) {
2541 if ( event.keyCode === key ) {
2542 if ( $( jmpress ).jmpress( 'initialized' ) ) {
2543 $( jmpress ).jmpress( 'deinit' );
2544 } else {
2545 $( jmpress ).jmpress( config );
2546 }
2547 }
2548 } );
2549 if ( initial ) {
2550 $( jmpress ).jmpress( config );
2551 }
2552 } );
2553 } )( jQuery, document, window );
2554
2555 /*
2556 * jmpress.secondary plugin
2557 * Apply a secondary animation when step is selected.
2558 */
2559 ( function ( $, document, window, undefined ) {
2560 'use strict';
2561 $.jmpress( 'initStep', function ( step, eventData ) {
2562 for ( var name in eventData.data ) {
2563 if ( name.indexOf( 'secondary' ) === 0 ) {
2564 eventData.stepData[ name ] = eventData.data[ name ];
2565 }
2566 }
2567 } );
2568 function exchangeIf( childStepData, condition, step ) {
2569 if (
2570 childStepData.secondary &&
2571 childStepData.secondary.split( ' ' ).indexOf( condition ) !== -1
2572 ) {
2573 for ( var name in childStepData ) {
2574 if ( name.length > 9 && name.indexOf( 'secondary' ) === 0 ) {
2575 var tmp = childStepData[ name ];
2576 var normal = name.substr( 9 );
2577 normal = normal.substr( 0, 1 ).toLowerCase() + normal.substr( 1 );
2578 childStepData[ name ] = childStepData[ normal ];
2579 childStepData[ normal ] = tmp;
2580 }
2581 }
2582 $( this ).jmpress( 'reapply', $( step ) );
2583 }
2584 }
2585 $.jmpress( 'beforeActive', function ( step, eventData ) {
2586 exchangeIf.call( eventData.jmpress, $( step ).data( 'stepData' ), 'self', step );
2587 var parent = $( step ).parent();
2588 $( parent )
2589 .children( eventData.settings.stepSelector )
2590 .each( function ( idx, child ) {
2591 var childStepData = $( child ).data( 'stepData' );
2592 exchangeIf.call( eventData.jmpress, childStepData, 'siblings', child );
2593 } );
2594 function grandchildrenFunc( idx, child ) {
2595 var childStepData = $( child ).data( 'stepData' );
2596 exchangeIf.call( eventData.jmpress, childStepData, 'grandchildren', child );
2597 }
2598 for ( var i = 1; i < eventData.parents.length; i++ ) {
2599 $( eventData.parents[ i ] ).children( eventData.settings.stepSelector ).each();
2600 }
2601 } );
2602 $.jmpress( 'setInactive', function ( step, eventData ) {
2603 exchangeIf.call( eventData.jmpress, $( step ).data( 'stepData' ), 'self', step );
2604 var parent = $( step ).parent();
2605 $( parent )
2606 .children( eventData.settings.stepSelector )
2607 .each( function ( idx, child ) {
2608 var childStepData = $( child ).data( 'stepData' );
2609 exchangeIf.call( eventData.jmpress, childStepData, 'siblings', child );
2610 } );
2611 function grandchildrenFunc( idx, child ) {
2612 var childStepData = $( child ).data( 'stepData' );
2613 exchangeIf.call( eventData.jmpress, childStepData, 'grandchildren', child );
2614 }
2615 for ( var i = 1; i < eventData.parents.length; i++ ) {
2616 $( eventData.parents[ i ] )
2617 .children( eventData.settings.stepSelector )
2618 .each( grandchildrenFunc );
2619 }
2620 } );
2621 } )( jQuery, document, window );
2622
2623 /*
2624 * jmpress.duration plugin
2625 * For auto advancing steps after a given duration and optionally displaying a
2626 * progress bar.
2627 */
2628 ( function ( $, document, window, undefined ) {
2629 'use strict';
2630
2631 $.jmpress( 'defaults' ).duration = {
2632 defaultValue: -1,
2633 defaultAction: 'next',
2634 barSelector: undefined,
2635 barProperty: 'width',
2636 barPropertyStart: '0',
2637 barPropertyEnd: '100%',
2638 };
2639 $.jmpress( 'initStep', function ( step, eventData ) {
2640 eventData.stepData.duration =
2641 eventData.data.duration && parseInt( eventData.data.duration, 10 );
2642 eventData.stepData.durationAction = eventData.data.durationAction;
2643 } );
2644 $.jmpress( 'setInactive', function ( step, eventData ) {
2645 var settings = eventData.settings,
2646 durationSettings = settings.duration,
2647 current = eventData.current;
2648 var dur = eventData.stepData.duration || durationSettings.defaultValue;
2649 if ( current.durationTimeout ) {
2650 if ( durationSettings.barSelector ) {
2651 var css = {
2652 transitionProperty: durationSettings.barProperty,
2653 transitionDuration: '0',
2654 transitionDelay: '0',
2655 transitionTimingFunction: 'linear',
2656 };
2657 css[ durationSettings.barProperty ] = durationSettings.barPropertyStart;
2658 var bars = $( durationSettings.barSelector );
2659 $.jmpress( 'css', bars, css );
2660 bars.each( function ( idx, element ) {
2661 var next = $( element ).next();
2662 var parent = $( element ).parent();
2663 $( element ).detach();
2664 if ( next.length ) {
2665 next.insertBefore( element );
2666 } else {
2667 parent.append( element );
2668 }
2669 } );
2670 }
2671 clearTimeout( current.durationTimeout );
2672 delete current.durationTimeout;
2673 }
2674 } );
2675 $.jmpress( 'setActive', function ( step, eventData ) {
2676 var settings = eventData.settings,
2677 durationSettings = settings.duration,
2678 current = eventData.current;
2679 var dur = eventData.stepData.duration || durationSettings.defaultValue;
2680 if ( dur && dur > 0 ) {
2681 if ( durationSettings.barSelector ) {
2682 var css = {
2683 transitionProperty: durationSettings.barProperty,
2684 transitionDuration: dur - ( settings.transitionDuration * 2 ) / 3 - 100 + 'ms',
2685 transitionDelay: ( settings.transitionDuration * 2 ) / 3 + 'ms',
2686 transitionTimingFunction: 'linear',
2687 };
2688 css[ durationSettings.barProperty ] = durationSettings.barPropertyEnd;
2689 $.jmpress( 'css', $( durationSettings.barSelector ), css );
2690 }
2691 var jmpress = this;
2692 if ( current.durationTimeout ) {
2693 clearTimeout( current.durationTimeout );
2694 current.durationTimeout = undefined;
2695 }
2696 current.durationTimeout = setTimeout( function () {
2697 var action = eventData.stepData.durationAction || durationSettings.defaultAction;
2698 $( jmpress ).jmpress( action );
2699 }, dur );
2700 }
2701 } );
2702 } )( jQuery, document, window );
2703
2704 /*
2705 * jmpress.presentation-mode plugin
2706 * Display a window for the presenter with notes and a control and view of the
2707 * presentation
2708 */
2709 ( function ( $, document, window, undefined ) {
2710 'use strict';
2711 var $jmpress = $.jmpress;
2712
2713 var PREFIX = 'jmpress-presentation-';
2714
2715 /* FUNCTIONS */
2716 function randomString() {
2717 return '' + Math.round( Math.random() * 100000, 0 );
2718 }
2719
2720 /* DEFAULTS */
2721 $jmpress( 'defaults' ).presentationMode = {
2722 use: true,
2723 url: 'presentation-screen.html',
2724 notesUrl: false,
2725 transferredValues: [ 'userZoom', 'userTranslateX', 'userTranslateY' ],
2726 };
2727 $jmpress( 'defaults' ).keyboard.keys[ 80 ] = 'presentationPopup'; // p key
2728
2729 /* HOOKS */
2730 $jmpress( 'afterInit', function ( nil, eventData ) {
2731 var current = eventData.current;
2732
2733 current.selectMessageListeners = [];
2734
2735 if ( eventData.settings.presentationMode.use ) {
2736 window.addEventListener( 'message', function ( event ) {
2737 // We do not test orgin, because we want to accept messages
2738 // from all orgins
2739 try {
2740 if ( typeof event.data !== 'string' || event.data.indexOf( PREFIX ) !== 0 ) {
2741 return;
2742 }
2743 var json = JSON.parse( event.data.slice( PREFIX.length ) );
2744 switch ( json.type ) {
2745 case 'select':
2746 $.each( eventData.settings.presentationMode.transferredValues, function (
2747 idx,
2748 name
2749 ) {
2750 eventData.current[ name ] = json[ name ];
2751 } );
2752 if (
2753 /[a-z0-9\-]+/i.test( json.targetId ) &&
2754 typeof json.substep in { number: 1, undefined: 1 }
2755 ) {
2756 $( eventData.jmpress ).jmpress(
2757 'select',
2758 { step: '#' + json.targetId, substep: json.substep },
2759 json.reason
2760 );
2761 } else {
2762 $.error(
2763 'For security reasons the targetId must match /[a-z0-9\\-]+/i and substep must be a number.'
2764 );
2765 }
2766 break;
2767 case 'listen':
2768 current.selectMessageListeners.push( event.source );
2769 break;
2770 case 'ok':
2771 clearTimeout( current.presentationPopupTimeout );
2772 break;
2773 case 'read':
2774 try {
2775 event.source.postMessage(
2776 PREFIX +
2777 JSON.stringify( {
2778 type: 'url',
2779 url: window.location.href,
2780 notesUrl: eventData.settings.presentationMode.notesUrl,
2781 } ),
2782 '*'
2783 );
2784 } catch ( e ) {
2785 $.error( 'Cannot post message to source: ' + e );
2786 }
2787 break;
2788 default:
2789 throw 'Unknown message type: ' + json.type;
2790 }
2791 } catch ( e ) {
2792 $.error( 'Received message is malformed: ' + e );
2793 }
2794 } );
2795 try {
2796 if ( window.parent && window.parent !== window ) {
2797 window.parent.postMessage(
2798 PREFIX +
2799 JSON.stringify( {
2800 type: 'afterInit',
2801 } ),
2802 '*'
2803 );
2804 }
2805 } catch ( e ) {
2806 $.error( 'Cannot post message to parent: ' + e );
2807 }
2808 }
2809 } );
2810 $jmpress( 'afterDeinit', function ( nil, eventData ) {
2811 if ( eventData.settings.presentationMode.use ) {
2812 try {
2813 if ( window.parent && window.parent !== window ) {
2814 window.parent.postMessage(
2815 PREFIX +
2816 JSON.stringify( {
2817 type: 'afterDeinit',
2818 } ),
2819 '*'
2820 );
2821 }
2822 } catch ( e ) {
2823 $.error( 'Cannot post message to parent: ' + e );
2824 }
2825 }
2826 } );
2827 $jmpress( 'setActive', function ( step, eventData ) {
2828 var stepId = $( eventData.delegatedFrom ).attr( 'id' ),
2829 substep = eventData.substep,
2830 reason = eventData.reason;
2831 $.each( eventData.current.selectMessageListeners, function ( idx, listener ) {
2832 try {
2833 var msg = {
2834 type: 'select',
2835 targetId: stepId,
2836 substep: substep,
2837 reason: reason,
2838 };
2839 $.each( eventData.settings.presentationMode.transferredValues, function ( idx, name ) {
2840 msg[ name ] = eventData.current[ name ];
2841 } );
2842 listener.postMessage( PREFIX + JSON.stringify( msg ), '*' );
2843 } catch ( e ) {
2844 $.error( 'Cannot post message to listener: ' + e );
2845 }
2846 } );
2847 } );
2848 $jmpress( 'register', 'presentationPopup', function () {
2849 function trySend() {
2850 jmpress.jmpress( 'current' ).presentationPopupTimeout = setTimeout( trySend, 100 );
2851 try {
2852 popup.postMessage(
2853 PREFIX +
2854 JSON.stringify( {
2855 type: 'url',
2856 url: window.location.href,
2857 notesUrl: jmpress.jmpress( 'settings' ).presentationMode.notesUrl,
2858 } ),
2859 '*'
2860 );
2861 } catch ( e ) {}
2862 }
2863 var jmpress = $( this ),
2864 popup;
2865 if ( jmpress.jmpress( 'settings' ).presentationMode.use ) {
2866 popup = window.open( $( this ).jmpress( 'settings' ).presentationMode.url );
2867 jmpress.jmpress( 'current' ).presentationPopupTimeout = setTimeout( trySend, 100 );
2868 }
2869 } );
2870 } )( jQuery, document, window );
2871