summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/jetpack/modules/shortcodes/js/jmpress.js')
-rw-r--r--plugins/jetpack/modules/shortcodes/js/jmpress.js2897
1 files changed, 2897 insertions, 0 deletions
diff --git a/plugins/jetpack/modules/shortcodes/js/jmpress.js b/plugins/jetpack/modules/shortcodes/js/jmpress.js
new file mode 100644
index 00000000..c6519cd9
--- /dev/null
+++ b/plugins/jetpack/modules/shortcodes/js/jmpress.js
@@ -0,0 +1,2897 @@
+/**
+ * jmpress.js v0.4.5
+ * http://jmpressjs.github.com/jmpress.js
+ *
+ * A jQuery plugin to build a website on the infinite canvas.
+ *
+ * Copyright 2013 Kyle Robinson Young @shama & Tobias Koppers @sokra
+ * Licensed MIT
+ * http://www.opensource.org/licenses/mit-license.php
+ *
+ * Based on the foundation laid by Bartek Szopka @bartaz
+ */ /*
+ * core.js
+ * The core of jmpress.js
+ */
+( function( $, document, window, undefined ) {
+ 'use strict';
+
+ /**
+ * Set supported prefixes
+ *
+ * @access protected
+ * @return Function to get prefixed property
+ */
+ var pfx = ( function() {
+ var style = document.createElement( 'dummy' ).style,
+ prefixes = 'Webkit Moz O ms Khtml'.split( ' ' ),
+ memory = {};
+ return function( prop ) {
+ if ( typeof memory[ prop ] === 'undefined' ) {
+ var ucProp = prop.charAt( 0 ).toUpperCase() + prop.substr( 1 ),
+ props = ( prop + ' ' + prefixes.join( ucProp + ' ' ) + ucProp ).split( ' ' );
+ memory[ prop ] = null;
+ for ( var i in props ) {
+ if ( style[ props[ i ] ] !== undefined ) {
+ memory[ prop ] = props[ i ];
+ break;
+ }
+ }
+ }
+ return memory[ prop ];
+ };
+ } )();
+
+ /**
+ * map ex. "WebkitTransform" to "-webkit-transform"
+ */
+ function mapProperty( name ) {
+ if ( ! name ) {
+ return;
+ }
+ var index = 1 + name.substr( 1 ).search( /[A-Z]/ );
+ var prefix = name.substr( 0, index ).toLowerCase();
+ var postfix = name.substr( index ).toLowerCase();
+ return '-' + prefix + '-' + postfix;
+ }
+ function addComma( attribute ) {
+ if ( ! attribute ) {
+ return '';
+ }
+ return attribute + ',';
+ }
+ /**
+ * Return an jquery object only if it's not empty
+ */
+ function ifNotEmpty( el ) {
+ if ( el.length > 0 ) {
+ return el;
+ }
+ return null;
+ }
+
+ /**
+ * Default Settings
+ */
+ var defaults = {
+ /* CLASSES */
+ stepSelector: '.step',
+ containerClass: '',
+ canvasClass: '',
+ areaClass: '',
+ notSupportedClass: 'not-supported',
+
+ /* CONFIG */
+ fullscreen: true,
+
+ /* ANIMATION */
+ animation: {
+ transformOrigin: 'top left',
+ transitionProperty:
+ addComma( mapProperty( pfx( 'transform' ) ) ) +
+ addComma( mapProperty( pfx( 'perspective' ) ) ) +
+ 'opacity',
+ transitionDuration: '1s',
+ transitionDelay: '500ms',
+ transitionTimingFunction: 'ease-in-out',
+ transformStyle: 'preserve-3d',
+ },
+ transitionDuration: 1500,
+ };
+ var callbacks = {
+ beforeChange: 1,
+ beforeInitStep: 1,
+ initStep: 1,
+ beforeInit: 1,
+ afterInit: 1,
+ beforeDeinit: 1,
+ afterDeinit: 1,
+ applyStep: 1,
+ unapplyStep: 1,
+ setInactive: 1,
+ beforeActive: 1,
+ setActive: 1,
+ selectInitialStep: 1,
+ selectPrev: 1,
+ selectNext: 1,
+ selectHome: 1,
+ selectEnd: 1,
+ idle: 1,
+ applyTarget: 1,
+ };
+ for ( var callbackName in callbacks ) {
+ defaults[ callbackName ] = [];
+ }
+
+ /**
+ * Initialize jmpress
+ */
+ function init( args ) {
+ args = $.extend( true, {}, args || {} );
+
+ // accept functions and arrays of functions as callbacks
+ var callbackArgs = {};
+ var callbackName = null;
+ for ( callbackName in callbacks ) {
+ callbackArgs[ callbackName ] = $.isFunction( args[ callbackName ] )
+ ? [ args[ callbackName ] ]
+ : args[ callbackName ];
+ args[ callbackName ] = [];
+ }
+
+ // MERGE SETTINGS
+ var settings = $.extend( true, {}, defaults, args );
+
+ for ( callbackName in callbacks ) {
+ if ( callbackArgs[ callbackName ] ) {
+ Array.prototype.push.apply( settings[ callbackName ], callbackArgs[ callbackName ] );
+ }
+ }
+
+ /*** MEMBER VARS ***/
+
+ var jmpress = $( this ),
+ container = null,
+ area = null,
+ oldStyle = {
+ container: '',
+ area: '',
+ },
+ canvas = null,
+ current = null,
+ active = false,
+ activeSubstep = null,
+ activeDelegated = false;
+
+ /*** MEMBER FUNCTIONS ***/
+ // functions have to be called with this
+
+ /**
+ * Init a single step
+ *
+ * @param element the element of the step
+ * @param idx number of step
+ */
+ function doStepInit( element, idx ) {
+ var data = dataset( element );
+ var step = {
+ oldStyle: $( element ).attr( 'style' ) || '',
+ };
+
+ var callbackData = {
+ data: data,
+ stepData: step,
+ };
+ callCallback.call( this, 'beforeInitStep', $( element ), callbackData );
+ step.delegate = data.delegate;
+ callCallback.call( this, 'initStep', $( element ), callbackData );
+
+ $( element ).data( 'stepData', step );
+
+ if ( ! $( element ).attr( 'id' ) ) {
+ $( element ).attr( 'id', 'step-' + ( idx + 1 ) );
+ }
+
+ callCallback.call( this, 'applyStep', $( element ), callbackData );
+ }
+ /**
+ * Deinit a single step
+ *
+ * @param element the element of the step
+ */
+ function doStepDeinit( element ) {
+ var stepData = $( element ).data( 'stepData' );
+
+ $( element ).attr( 'style', stepData.oldStyle );
+
+ callCallback.call( this, 'unapplyStep', $( element ), {
+ stepData: stepData,
+ } );
+ }
+ /**
+ * Reapplies stepData to the element
+ *
+ * @param element
+ */
+ function doStepReapply( element ) {
+ callCallback.call( this, 'unapplyStep', $( element ), {
+ stepData: element.data( 'stepData' ),
+ } );
+
+ callCallback.call( this, 'applyStep', $( element ), {
+ stepData: element.data( 'stepData' ),
+ } );
+ }
+ /**
+ * Completly deinit jmpress
+ *
+ */
+ function deinit() {
+ if ( active ) {
+ callCallback.call( this, 'setInactive', active, {
+ stepData: $( active ).data( 'stepData' ),
+ reason: 'deinit',
+ } );
+ }
+ if ( current.jmpressClass ) {
+ $( jmpress ).removeClass( current.jmpressClass );
+ }
+
+ callCallback.call( this, 'beforeDeinit', $( this ), {} );
+
+ $( settings.stepSelector, jmpress ).each( function( idx ) {
+ doStepDeinit.call( jmpress, this );
+ } );
+
+ container.attr( 'style', oldStyle.container );
+ if ( settings.fullscreen ) {
+ $( 'html' ).attr( 'style', '' );
+ }
+ area.attr( 'style', oldStyle.area );
+ $( canvas )
+ .children()
+ .each( function() {
+ jmpress.append( $( this ) );
+ } );
+ if ( settings.fullscreen ) {
+ canvas.remove();
+ } else {
+ canvas.remove();
+ area.remove();
+ }
+
+ callCallback.call( this, 'afterDeinit', $( this ), {} );
+
+ $( jmpress ).data( 'jmpressmethods', false );
+ }
+ /**
+ * Call a callback
+ *
+ * @param callbackName String callback which should be called
+ * @param element some arguments to the callback
+ * @param eventData
+ */
+ function callCallback( callbackName, element, eventData ) {
+ eventData.settings = settings;
+ eventData.current = current;
+ eventData.container = container;
+ eventData.parents = element ? getStepParents( element ) : null;
+ eventData.current = current;
+ eventData.jmpress = this;
+ var result = {};
+ $.each( settings[ callbackName ], function( idx, callback ) {
+ result.value = callback.call( jmpress, element, eventData ) || result.value;
+ } );
+ return result.value;
+ }
+ /**
+ *
+ */
+ function getStepParents( el ) {
+ return $( el )
+ .parentsUntil( jmpress )
+ .not( jmpress )
+ .filter( settings.stepSelector );
+ }
+ /**
+ * Reselect the active step
+ *
+ * @param String type reason of reselecting step
+ */
+ function reselect( type ) {
+ return select( { step: active, substep: activeSubstep }, type );
+ }
+ /**
+ * Select a given step
+ *
+ * @param el element to select
+ * @param type reason of changing step
+ * @return Object element selected
+ */
+ function select( el, type ) {
+ var substep;
+ if ( $.isPlainObject( el ) ) {
+ substep = el.substep;
+ el = el.step;
+ }
+ if ( typeof el === 'string' ) {
+ el = jmpress.find( el ).first();
+ }
+ if ( ! el || ! $( el ).data( 'stepData' ) ) {
+ return false;
+ }
+
+ scrollFix.call( this );
+
+ var step = $( el ).data( 'stepData' );
+
+ var cancelSelect = false;
+ callCallback.call( this, 'beforeChange', el, {
+ stepData: step,
+ reason: type,
+ cancel: function() {
+ cancelSelect = true;
+ },
+ } );
+ if ( cancelSelect ) {
+ return undefined;
+ }
+
+ var target = {};
+
+ var delegated = el;
+ if ( $( el ).data( 'stepData' ).delegate ) {
+ delegated =
+ ifNotEmpty(
+ $( el )
+ .parentsUntil( jmpress )
+ .filter( settings.stepSelector )
+ .filter( step.delegate )
+ ) ||
+ ifNotEmpty( $( el ).near( step.delegate ) ) ||
+ ifNotEmpty( $( el ).near( step.delegate, true ) ) ||
+ ifNotEmpty( $( step.delegate, jmpress ) );
+ if ( delegated ) {
+ step = delegated.data( 'stepData' );
+ } else {
+ // Do not delegate if expression not found
+ delegated = el;
+ }
+ }
+ if ( activeDelegated ) {
+ callCallback.call( this, 'setInactive', activeDelegated, {
+ stepData: $( activeDelegated ).data( 'stepData' ),
+ delegatedFrom: active,
+ reason: type,
+ target: target,
+ nextStep: delegated,
+ nextSubstep: substep,
+ nextStepData: step,
+ } );
+ }
+ var callbackData = {
+ stepData: step,
+ delegatedFrom: el,
+ reason: type,
+ target: target,
+ substep: substep,
+ prevStep: activeDelegated,
+ prevSubstep: activeSubstep,
+ prevStepData: activeDelegated && $( activeDelegated ).data( 'stepData' ),
+ };
+ callCallback.call( this, 'beforeActive', delegated, callbackData );
+ callCallback.call( this, 'setActive', delegated, callbackData );
+
+ // Set on step class on root element
+ if ( current.jmpressClass ) {
+ $( jmpress ).removeClass( current.jmpressClass );
+ }
+ $( jmpress ).addClass( ( current.jmpressClass = 'step-' + $( delegated ).attr( 'id' ) ) );
+ if ( current.jmpressDelegatedClass ) {
+ $( jmpress ).removeClass( current.jmpressDelegatedClass );
+ }
+ $( jmpress ).addClass(
+ ( current.jmpressDelegatedClass = 'delegating-step-' + $( el ).attr( 'id' ) )
+ );
+
+ callCallback.call(
+ this,
+ 'applyTarget',
+ delegated,
+ $.extend(
+ {
+ canvas: canvas,
+ area: area,
+ beforeActive: activeDelegated,
+ },
+ callbackData
+ )
+ );
+
+ active = el;
+ activeSubstep = callbackData.substep;
+ activeDelegated = delegated;
+
+ if ( current.idleTimeout ) {
+ clearTimeout( current.idleTimeout );
+ }
+ current.idleTimeout = setTimeout( function() {
+ callCallback.call( this, 'idle', delegated, callbackData );
+ }, Math.max( 1, settings.transitionDuration - 100 ) );
+
+ return delegated;
+ }
+ /**
+ * This should fix ANY kind of buggy scrolling
+ */
+ function scrollFix() {
+ ( function fix() {
+ if ( $( container )[ 0 ].tagName === 'BODY' ) {
+ try {
+ window.scrollTo( 0, 0 );
+ } catch ( e ) {}
+ }
+ $( container ).scrollTop( 0 );
+ $( container ).scrollLeft( 0 );
+ function check() {
+ if ( $( container ).scrollTop() !== 0 || $( container ).scrollLeft() !== 0 ) {
+ fix();
+ }
+ }
+ setTimeout( check, 1 );
+ setTimeout( check, 10 );
+ setTimeout( check, 100 );
+ setTimeout( check, 200 );
+ setTimeout( check, 400 );
+ } )();
+ }
+ /**
+ * Alias for select
+ */
+ function goTo( el ) {
+ return select.call( this, el, 'jump' );
+ }
+ /**
+ * Goto Next Slide
+ *
+ * @return Object newly active slide
+ */
+ function next() {
+ return select.call(
+ this,
+ callCallback.call( this, 'selectNext', active, {
+ stepData: $( active ).data( 'stepData' ),
+ substep: activeSubstep,
+ } ),
+ 'next'
+ );
+ }
+ /**
+ * Goto Previous Slide
+ *
+ * @return Object newly active slide
+ */
+ function prev() {
+ return select.call(
+ this,
+ callCallback.call( this, 'selectPrev', active, {
+ stepData: $( active ).data( 'stepData' ),
+ substep: activeSubstep,
+ } ),
+ 'prev'
+ );
+ }
+ /**
+ * Goto First Slide
+ *
+ * @return Object newly active slide
+ */
+ function home() {
+ return select.call(
+ this,
+ callCallback.call( this, 'selectHome', active, {
+ stepData: $( active ).data( 'stepData' ),
+ } ),
+ 'home'
+ );
+ }
+ /**
+ * Goto Last Slide
+ *
+ * @return Object newly active slide
+ */
+ function end() {
+ return select.call(
+ this,
+ callCallback.call( this, 'selectEnd', active, {
+ stepData: $( active ).data( 'stepData' ),
+ } ),
+ 'end'
+ );
+ }
+ /**
+ * Manipulate the canvas
+ *
+ * @param props
+ * @return Object
+ */
+ function canvasMod( props ) {
+ css( canvas, props || {} );
+ return $( canvas );
+ }
+ /**
+ * Return current step
+ *
+ * @return Object
+ */
+ function getActive() {
+ return activeDelegated && $( activeDelegated );
+ }
+ /**
+ * fire a callback
+ *
+ * @param callbackName
+ * @param element
+ * @param eventData
+ * @return void
+ */
+ function fire( callbackName, element, eventData ) {
+ if ( ! callbacks[ callbackName ] ) {
+ $.error( 'callback ' + callbackName + ' is not registered.' );
+ } else {
+ return callCallback.call( this, callbackName, element, eventData );
+ }
+ }
+
+ /**
+ * PUBLIC METHODS LIST
+ */
+ jmpress.data( 'jmpressmethods', {
+ select: select,
+ reselect: reselect,
+ scrollFix: scrollFix,
+ goTo: goTo,
+ next: next,
+ prev: prev,
+ home: home,
+ end: end,
+ canvas: canvasMod,
+ container: function() {
+ return container;
+ },
+ settings: function() {
+ return settings;
+ },
+ active: getActive,
+ current: function() {
+ return current;
+ },
+ fire: fire,
+ init: function( step ) {
+ doStepInit.call( this, $( step ), current.nextIdNumber++ );
+ },
+ deinit: function( step ) {
+ if ( step ) {
+ doStepDeinit.call( this, $( step ) );
+ } else {
+ deinit.call( this );
+ }
+ },
+ reapply: doStepReapply,
+ } );
+
+ /**
+ * Check for support
+ * This will be removed in near future, when support is coming
+ *
+ * @access protected
+ * @return void
+ */
+ function checkSupport() {
+ var ua = navigator.userAgent.toLowerCase();
+ return ua.search( /(iphone)|(ipod)|(android)/ ) === -1 || ua.search( /(chrome)/ ) !== -1;
+ }
+
+ // BEGIN INIT
+
+ // CHECK FOR SUPPORT
+ if ( checkSupport() === false ) {
+ if ( settings.notSupportedClass ) {
+ jmpress.addClass( settings.notSupportedClass );
+ }
+ return;
+ } else {
+ if ( settings.notSupportedClass ) {
+ jmpress.removeClass( settings.notSupportedClass );
+ }
+ }
+
+ // grabbing all steps
+ var steps = $( settings.stepSelector, jmpress );
+
+ // GERNERAL INIT OF FRAME
+ container = jmpress;
+ area = $( '<div />' );
+ canvas = $( '<div />' );
+ $( jmpress )
+ .children()
+ .filter( steps )
+ .each( function() {
+ canvas.append( $( this ) );
+ } );
+ if ( settings.fullscreen ) {
+ container = $( 'body' );
+ $( 'html' ).css( {
+ overflow: 'hidden',
+ } );
+ area = jmpress;
+ }
+ oldStyle.area = area.attr( 'style' ) || '';
+ oldStyle.container = container.attr( 'style' ) || '';
+ if ( settings.fullscreen ) {
+ container.css( {
+ height: '100%',
+ } );
+ jmpress.append( canvas );
+ } else {
+ container.css( {
+ position: 'relative',
+ } );
+ area.append( canvas );
+ jmpress.append( area );
+ }
+
+ $( container ).addClass( settings.containerClass );
+ $( area ).addClass( settings.areaClass );
+ $( canvas ).addClass( settings.canvasClass );
+
+ document.documentElement.style.height = '100%';
+ container.css( {
+ overflow: 'hidden',
+ } );
+
+ var props = {
+ position: 'absolute',
+ transitionDuration: '0s',
+ };
+ props = $.extend( {}, settings.animation, props );
+ css( area, props );
+ css( area, {
+ top: '50%',
+ left: '50%',
+ perspective: '1000px',
+ } );
+ css( canvas, props );
+
+ current = {};
+
+ callCallback.call( this, 'beforeInit', null, {} );
+
+ // INITIALIZE EACH STEP
+ steps.each( function( idx ) {
+ doStepInit.call( jmpress, this, idx );
+ } );
+ current.nextIdNumber = steps.length;
+
+ callCallback.call( this, 'afterInit', null, {} );
+
+ // START
+ select.call( this, callCallback.call( this, 'selectInitialStep', 'init', {} ) );
+
+ if ( settings.initClass ) {
+ $( steps ).removeClass( settings.initClass );
+ }
+ }
+ /**
+ * Return default settings
+ *
+ * @return Object
+ */
+ function getDefaults() {
+ return defaults;
+ }
+ /**
+ * Register a callback or a jmpress function
+ *
+ * @access public
+ * @param name String the name of the callback or function
+ * @param func Function? the function to be added
+ */
+ function register( name, func ) {
+ if ( $.isFunction( func ) ) {
+ if ( methods[ name ] ) {
+ $.error( 'function ' + name + ' is already registered.' );
+ } else {
+ methods[ name ] = func;
+ }
+ } else {
+ if ( callbacks[ name ] ) {
+ $.error( 'callback ' + name + ' is already registered.' );
+ } else {
+ callbacks[ name ] = 1;
+ defaults[ name ] = [];
+ }
+ }
+ }
+ /**
+ * Set CSS on element w/ prefixes
+ *
+ * @return Object element which properties were set
+ *
+ * TODO: Consider bypassing pfx and blindly set as jQuery
+ * already checks for support
+ */
+ function css( el, props ) {
+ var key,
+ pkey,
+ cssObj = {};
+ for ( key in props ) {
+ if ( props.hasOwnProperty( key ) ) {
+ pkey = pfx( key );
+ if ( pkey !== null ) {
+ cssObj[ pkey ] = props[ key ];
+ }
+ }
+ }
+ $( el ).css( cssObj );
+ return el;
+ }
+ /**
+ * Return dataset for element
+ *
+ * @param el element
+ * @return Object
+ */
+ function dataset( el ) {
+ if ( $( el )[ 0 ].dataset ) {
+ return $.extend( {}, $( el )[ 0 ].dataset );
+ }
+ function toCamelcase( str ) {
+ str = str.split( '-' );
+ for ( var i = 1; i < str.length; i++ ) {
+ str[ i ] = str[ i ].substr( 0, 1 ).toUpperCase() + str[ i ].substr( 1 );
+ }
+ return str.join( '' );
+ }
+ var returnDataset = {};
+ var attrs = $( el )[ 0 ].attributes;
+ $.each( attrs, function( idx, attr ) {
+ if ( attr.nodeName.substr( 0, 5 ) === 'data-' ) {
+ returnDataset[ toCamelcase( attr.nodeName.substr( 5 ) ) ] = attr.nodeValue;
+ }
+ } );
+ return returnDataset;
+ }
+ /**
+ * Returns true, if jmpress is initialized
+ *
+ * @return bool
+ */
+ function initialized() {
+ return !! $( this ).data( 'jmpressmethods' );
+ }
+
+ /**
+ * PUBLIC STATIC METHODS LIST
+ */
+ var methods = {
+ init: init,
+ initialized: initialized,
+ deinit: function() {},
+ css: css,
+ pfx: pfx,
+ defaults: getDefaults,
+ register: register,
+ dataset: dataset,
+ };
+
+ /**
+ * $.jmpress()
+ */
+ $.fn.jmpress = function( method ) {
+ function f() {
+ var jmpressmethods = $( this ).data( 'jmpressmethods' );
+ if ( jmpressmethods && jmpressmethods[ method ] ) {
+ return jmpressmethods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ) );
+ } else if ( methods[ method ] ) {
+ return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ) );
+ } else if ( callbacks[ method ] && jmpressmethods ) {
+ var settings = jmpressmethods.settings();
+ var func = Array.prototype.slice.call( arguments, 1 )[ 0 ];
+ if ( $.isFunction( func ) ) {
+ settings[ method ] = settings[ method ] || [];
+ settings[ method ].push( func );
+ }
+ } else if ( typeof method === 'object' || ! method ) {
+ return init.apply( this, arguments );
+ } else {
+ $.error( 'Method ' + method + ' does not exist on jQuery.jmpress' );
+ }
+ // to allow chaining
+ return this;
+ }
+ var args = arguments;
+ var result;
+ $( this ).each( function( idx, element ) {
+ result = f.apply( element, args );
+ } );
+ return result;
+ };
+ $.extend( {
+ jmpress: function( method ) {
+ if ( methods[ method ] ) {
+ return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ) );
+ } else if ( callbacks[ method ] ) {
+ // plugin interface
+ var func = Array.prototype.slice.call( arguments, 1 )[ 0 ];
+ if ( $.isFunction( func ) ) {
+ defaults[ method ].push( func );
+ } else {
+ $.error(
+ 'Second parameter should be a function: $.jmpress( callbackName, callbackFunction )'
+ );
+ }
+ } else {
+ $.error( 'Method ' + method + ' does not exist on jQuery.jmpress' );
+ }
+ },
+ } );
+} )( jQuery, document, window );
+
+/*
+ * near.js
+ * Find steps near each other
+ */
+( function( $, document, window, undefined ) {
+ 'use strict';
+
+ // add near( selector, backwards = false) to jquery
+
+ function checkAndGo( elements, func, selector, backwards ) {
+ var next;
+ elements.each( function( idx, element ) {
+ if ( backwards ) {
+ next = func( element, selector, backwards );
+ if ( next ) {
+ return false;
+ }
+ }
+ if ( $( element ).is( selector ) ) {
+ next = element;
+ return false;
+ }
+ if ( ! backwards ) {
+ next = func( element, selector, backwards );
+ if ( next ) {
+ return false;
+ }
+ }
+ } );
+ return next;
+ }
+ function findNextInChildren( item, selector, backwards ) {
+ var children = $( item ).children();
+ if ( backwards ) {
+ children = $( children.get().reverse() );
+ }
+ return checkAndGo( children, findNextInChildren, selector, backwards );
+ }
+ function findNextInSiblings( item, selector, backwards ) {
+ return checkAndGo(
+ $( item )[ backwards ? 'prevAll' : 'nextAll' ](),
+ findNextInChildren,
+ selector,
+ backwards
+ );
+ }
+ function findNextInParents( item, selector, backwards ) {
+ var next;
+ var parents = $( item ).parents();
+ parents = $( parents.get() );
+ $.each( parents.get(), function( idx, element ) {
+ if ( backwards && $( element ).is( selector ) ) {
+ next = element;
+ return false;
+ }
+ next = findNextInSiblings( element, selector, backwards );
+ if ( next ) {
+ return false;
+ }
+ } );
+ return next;
+ }
+
+ $.fn.near = function( selector, backwards ) {
+ var array = [];
+ $( this ).each( function( idx, element ) {
+ var near =
+ ( backwards ? false : findNextInChildren( element, selector, backwards ) ) ||
+ findNextInSiblings( element, selector, backwards ) ||
+ findNextInParents( element, selector, backwards );
+ if ( near ) {
+ array.push( near );
+ }
+ } );
+ return $( array );
+ };
+} )( jQuery, document, window );
+/*
+ * transform.js
+ * The engine that powers the transforms or falls back to other methods
+ */
+( function( $, document, window, undefined ) {
+ 'use strict';
+
+ /* FUNCTIONS */
+ function toCssNumber( number ) {
+ return Math.round( 10000 * number ) / 10000 + '';
+ }
+
+ /**
+ * 3D and 2D engines
+ */
+ var engines = {
+ 3: {
+ transform: function( el, data ) {
+ var transform = 'translate(-50%,-50%)';
+ $.each( data, function( idx, item ) {
+ var coord = [ 'X', 'Y', 'Z' ];
+ var i;
+ if ( item[ 0 ] === 'translate' ) {
+ // ["translate", x, y, z]
+ transform +=
+ ' translate3d(' +
+ toCssNumber( item[ 1 ] || 0 ) +
+ 'px,' +
+ toCssNumber( item[ 2 ] || 0 ) +
+ 'px,' +
+ toCssNumber( item[ 3 ] || 0 ) +
+ 'px)';
+ } else if ( item[ 0 ] === 'rotate' ) {
+ var order = item[ 4 ] ? [ 1, 2, 3 ] : [ 3, 2, 1 ];
+ for ( i = 0; i < 3; i++ ) {
+ transform +=
+ ' rotate' +
+ coord[ order[ i ] - 1 ] +
+ '(' +
+ toCssNumber( item[ order[ i ] ] || 0 ) +
+ 'deg)';
+ }
+ } else if ( item[ 0 ] === 'scale' ) {
+ for ( i = 0; i < 3; i++ ) {
+ transform += ' scale' + coord[ i ] + '(' + toCssNumber( item[ i + 1 ] || 1 ) + ')';
+ }
+ }
+ } );
+ $.jmpress( 'css', el, $.extend( {}, { transform: transform } ) );
+ },
+ },
+ 2: {
+ transform: function( el, data ) {
+ var transform = 'translate(-50%,-50%)';
+ $.each( data, function( idx, item ) {
+ var coord = [ 'X', 'Y' ];
+ if ( item[ 0 ] === 'translate' ) {
+ // ["translate", x, y, z]
+ transform +=
+ ' translate(' +
+ toCssNumber( item[ 1 ] || 0 ) +
+ 'px,' +
+ toCssNumber( item[ 2 ] || 0 ) +
+ 'px)';
+ } else if ( item[ 0 ] === 'rotate' ) {
+ transform += ' rotate(' + toCssNumber( item[ 3 ] || 0 ) + 'deg)';
+ } else if ( item[ 0 ] === 'scale' ) {
+ for ( var i = 0; i < 2; i++ ) {
+ transform += ' scale' + coord[ i ] + '(' + toCssNumber( item[ i + 1 ] || 1 ) + ')';
+ }
+ }
+ } );
+ $.jmpress( 'css', el, $.extend( {}, { transform: transform } ) );
+ },
+ },
+ 1: {
+ // CHECK IF SUPPORT IS REALLY NEEDED?
+ // this not even work without scaling...
+ // it may better to display the normal view
+ transform: function( el, data ) {
+ var anitarget = { top: 0, left: 0 };
+ $.each( data, function( idx, item ) {
+ var coord = [ 'X', 'Y' ];
+ if ( item[ 0 ] === 'translate' ) {
+ // ["translate", x, y, z]
+ anitarget.left = Math.round( item[ 1 ] || 0 ) + 'px';
+ anitarget.top = Math.round( item[ 2 ] || 0 ) + 'px';
+ }
+ } );
+ el.animate( anitarget, 1000 ); // TODO: Use animation duration
+ },
+ },
+ };
+
+ /**
+ * Engine to power cross-browser translate, scale and rotate.
+ */
+ var engine = ( function() {
+ if ( $.jmpress( 'pfx', 'perspective' ) ) {
+ return engines[ 3 ];
+ } else if ( $.jmpress( 'pfx', 'transform' ) ) {
+ return engines[ 2 ];
+ } else {
+ // CHECK IF SUPPORT IS REALLY NEEDED?
+ return engines[ 1 ];
+ }
+ } )();
+
+ $.jmpress( 'defaults' ).reasonableAnimation = {};
+ $.jmpress( 'initStep', function( step, eventData ) {
+ var data = eventData.data;
+ var stepData = eventData.stepData;
+ var pf = parseFloat;
+ $.extend( stepData, {
+ x: pf( data.x ) || 0,
+ y: pf( data.y ) || 0,
+ z: pf( data.z ) || 0,
+ r: pf( data.r ) || 0,
+ phi: pf( data.phi ) || 0,
+ rotate: pf( data.rotate ) || 0,
+ rotateX: pf( data.rotateX ) || 0,
+ rotateY: pf( data.rotateY ) || 0,
+ rotateZ: pf( data.rotateZ ) || 0,
+ revertRotate: false,
+ scale: pf( data.scale ) || 1,
+ scaleX: pf( data.scaleX ) || false,
+ scaleY: pf( data.scaleY ) || false,
+ scaleZ: pf( data.scaleZ ) || 1,
+ } );
+ } );
+ $.jmpress( 'afterInit', function( nil, eventData ) {
+ var stepSelector = eventData.settings.stepSelector,
+ current = eventData.current;
+ current.perspectiveScale = 1;
+ current.maxNestedDepth = 0;
+ var nestedSteps = $( eventData.jmpress )
+ .find( stepSelector )
+ .children( stepSelector );
+ while ( nestedSteps.length ) {
+ current.maxNestedDepth++;
+ nestedSteps = nestedSteps.children( stepSelector );
+ }
+ } );
+ $.jmpress( 'applyStep', function( step, eventData ) {
+ $.jmpress( 'css', $( step ), {
+ position: 'absolute',
+ transformStyle: 'preserve-3d',
+ } );
+ if ( eventData.parents.length > 0 ) {
+ $.jmpress( 'css', $( step ), {
+ top: '50%',
+ left: '50%',
+ } );
+ }
+ var sd = eventData.stepData;
+ var transform = [
+ [
+ 'translate',
+ sd.x || sd.r * Math.sin( ( sd.phi * Math.PI ) / 180 ),
+ sd.y || -sd.r * Math.cos( ( sd.phi * Math.PI ) / 180 ),
+ sd.z,
+ ],
+ [ 'rotate', sd.rotateX, sd.rotateY, sd.rotateZ || sd.rotate, true ],
+ [ 'scale', sd.scaleX || sd.scale, sd.scaleY || sd.scale, sd.scaleZ || sd.scale ],
+ ];
+ engine.transform( step, transform );
+ } );
+ $.jmpress( 'setActive', function( element, eventData ) {
+ var target = eventData.target;
+ var step = eventData.stepData;
+ var tf = ( target.transform = [] );
+ target.perspectiveScale = 1;
+
+ for ( var i = eventData.current.maxNestedDepth; i > ( eventData.parents.length || 0 ); i-- ) {
+ tf.push( [ 'scale' ], [ 'rotate' ], [ 'translate' ] );
+ }
+
+ tf.push( [
+ 'scale',
+ 1 / ( step.scaleX || step.scale ),
+ 1 / ( step.scaleY || step.scale ),
+ 1 / step.scaleZ,
+ ] );
+ tf.push( [ 'rotate', -step.rotateX, -step.rotateY, -( step.rotateZ || step.rotate ) ] );
+ tf.push( [
+ 'translate',
+ -( step.x || step.r * Math.sin( ( step.phi * Math.PI ) / 180 ) ),
+ -( step.y || -step.r * Math.cos( ( step.phi * Math.PI ) / 180 ) ),
+ -step.z,
+ ] );
+ target.perspectiveScale *= step.scaleX || step.scale;
+
+ $.each( eventData.parents, function( idx, element ) {
+ var step = $( element ).data( 'stepData' );
+ tf.push( [
+ 'scale',
+ 1 / ( step.scaleX || step.scale ),
+ 1 / ( step.scaleY || step.scale ),
+ 1 / step.scaleZ,
+ ] );
+ tf.push( [ 'rotate', -step.rotateX, -step.rotateY, -( step.rotateZ || step.rotate ) ] );
+ tf.push( [
+ 'translate',
+ -( step.x || step.r * Math.sin( ( step.phi * Math.PI ) / 180 ) ),
+ -( step.y || -step.r * Math.cos( ( step.phi * Math.PI ) / 180 ) ),
+ -step.z,
+ ] );
+ target.perspectiveScale *= step.scaleX || step.scale;
+ } );
+
+ $.each( tf, function( idx, item ) {
+ if ( item[ 0 ] !== 'rotate' ) {
+ return;
+ }
+ function lowRotate( name ) {
+ if ( eventData.current[ 'rotate' + name + '-' + idx ] === undefined ) {
+ eventData.current[ 'rotate' + name + '-' + idx ] = item[ name ] || 0;
+ }
+ var cur = eventData.current[ 'rotate' + name + '-' + idx ],
+ tar = item[ name ] || 0,
+ curmod = cur % 360,
+ tarmod = tar % 360;
+ if ( curmod < 0 ) {
+ curmod += 360;
+ }
+ if ( tarmod < 0 ) {
+ tarmod += 360;
+ }
+ var diff = tarmod - curmod;
+ if ( diff < -180 ) {
+ diff += 360;
+ } else if ( diff > 180 ) {
+ diff -= 360;
+ }
+ eventData.current[ 'rotate' + name + '-' + idx ] = item[ name ] = cur + diff;
+ }
+ lowRotate( 1 );
+ lowRotate( 2 );
+ lowRotate( 3 );
+ } );
+ } );
+ $.jmpress( 'applyTarget', function( active, eventData ) {
+ var target = eventData.target,
+ props,
+ step = eventData.stepData,
+ settings = eventData.settings,
+ zoomin = target.perspectiveScale * 1.3 < eventData.current.perspectiveScale,
+ zoomout = target.perspectiveScale > eventData.current.perspectiveScale * 1.3;
+
+ // extract first scale from transform
+ var lastScale = -1;
+ $.each( target.transform, function( idx, item ) {
+ if ( item.length <= 1 ) {
+ return;
+ }
+ if (
+ item[ 0 ] === 'rotate' &&
+ item[ 1 ] % 360 === 0 &&
+ item[ 2 ] % 360 === 0 &&
+ item[ 3 ] % 360 === 0
+ ) {
+ return;
+ }
+ if ( item[ 0 ] === 'scale' ) {
+ lastScale = idx;
+ } else {
+ return false;
+ }
+ } );
+
+ if ( lastScale !== eventData.current.oldLastScale ) {
+ zoomin = zoomout = false;
+ eventData.current.oldLastScale = lastScale;
+ }
+
+ var extracted = [];
+ if ( lastScale !== -1 ) {
+ while ( lastScale >= 0 ) {
+ if ( target.transform[ lastScale ][ 0 ] === 'scale' ) {
+ extracted.push( target.transform[ lastScale ] );
+ target.transform[ lastScale ] = [ 'scale' ];
+ }
+ lastScale--;
+ }
+ }
+
+ var animation = settings.animation;
+ if ( settings.reasonableAnimation[ eventData.reason ] ) {
+ animation = $.extend( {}, animation, settings.reasonableAnimation[ eventData.reason ] );
+ }
+
+ props = {
+ // to keep the perspective look similar for different scales
+ // we need to 'scale' the perspective, too
+ perspective: Math.round( target.perspectiveScale * 1000 ) + 'px',
+ };
+ props = $.extend( {}, animation, props );
+ if ( ! zoomin ) {
+ props.transitionDelay = '0s';
+ }
+ if ( ! eventData.beforeActive ) {
+ props.transitionDuration = '0s';
+ props.transitionDelay = '0s';
+ }
+ $.jmpress( 'css', eventData.area, props );
+ engine.transform( eventData.area, extracted );
+
+ props = $.extend( {}, animation );
+ if ( ! zoomout ) {
+ props.transitionDelay = '0s';
+ }
+ if ( ! eventData.beforeActive ) {
+ props.transitionDuration = '0s';
+ props.transitionDelay = '0s';
+ }
+
+ eventData.current.perspectiveScale = target.perspectiveScale;
+
+ $.jmpress( 'css', eventData.canvas, props );
+ engine.transform( eventData.canvas, target.transform );
+ } );
+} )( jQuery, document, window );
+/*
+ * active.js
+ * Set the active classes on steps
+ */
+( function( $, document, window, undefined ) {
+ 'use strict';
+ var $jmpress = $.jmpress;
+
+ /* DEFINES */
+ var activeClass = 'activeClass',
+ nestedActiveClass = 'nestedActiveClass';
+
+ /* DEFAULTS */
+ var defaults = $jmpress( 'defaults' );
+ defaults[ nestedActiveClass ] = 'nested-active';
+ defaults[ activeClass ] = 'active';
+
+ /* HOOKS */
+ $jmpress( 'setInactive', function( step, eventData ) {
+ var settings = eventData.settings,
+ activeClassSetting = settings[ activeClass ],
+ nestedActiveClassSettings = settings[ nestedActiveClass ];
+ if ( activeClassSetting ) {
+ $( step ).removeClass( activeClassSetting );
+ }
+ if ( nestedActiveClassSettings ) {
+ $.each( eventData.parents, function( idx, element ) {
+ $( element ).removeClass( nestedActiveClassSettings );
+ } );
+ }
+ } );
+ $jmpress( 'setActive', function( step, eventData ) {
+ var settings = eventData.settings,
+ activeClassSetting = settings[ activeClass ],
+ nestedActiveClassSettings = settings[ nestedActiveClass ];
+ if ( activeClassSetting ) {
+ $( step ).addClass( activeClassSetting );
+ }
+ if ( nestedActiveClassSettings ) {
+ $.each( eventData.parents, function( idx, element ) {
+ $( element ).addClass( nestedActiveClassSettings );
+ } );
+ }
+ } );
+} )( jQuery, document, window );
+/*
+ * circular.js
+ * Repeat from start after end
+ */
+( function( $, document, window, undefined ) {
+ 'use strict';
+ var $jmpress = $.jmpress;
+
+ /* FUNCTIONS */
+ function firstSlide( step, eventData ) {
+ return $( this )
+ .find( eventData.settings.stepSelector )
+ .first();
+ }
+ function prevOrNext( jmpress, step, eventData, prev ) {
+ if ( ! step ) {
+ return false;
+ }
+ var stepSelector = eventData.settings.stepSelector;
+ step = $( step );
+ do {
+ var item = step.near( stepSelector, prev );
+ if ( item.length === 0 || item.closest( jmpress ).length === 0 ) {
+ item = $( jmpress )
+ .find( stepSelector )
+ [ prev ? 'last' : 'first' ]();
+ }
+ if ( ! item.length ) {
+ return false;
+ }
+ step = item;
+ } while ( step.data( 'stepData' ).exclude );
+ return step;
+ }
+
+ /* HOOKS */
+ $jmpress( 'initStep', function( step, eventData ) {
+ eventData.stepData.exclude =
+ eventData.data.exclude && [ 'false', 'no' ].indexOf( eventData.data.exclude ) === -1;
+ } );
+ $jmpress( 'selectInitialStep', firstSlide );
+ $jmpress( 'selectHome', firstSlide );
+ $jmpress( 'selectEnd', function( step, eventData ) {
+ return $( this )
+ .find( eventData.settings.stepSelector )
+ .last();
+ } );
+ $jmpress( 'selectPrev', function( step, eventData ) {
+ return prevOrNext( this, step, eventData, true );
+ } );
+ $jmpress( 'selectNext', function( step, eventData ) {
+ return prevOrNext( this, step, eventData );
+ } );
+} )( jQuery, document, window );
+/*
+ * start.js
+ * Set the first step to start on
+ */
+( function( $, document, window, undefined ) {
+ 'use strict';
+
+ /* HOOKS */
+ $.jmpress( 'selectInitialStep', function( nil, eventData ) {
+ return eventData.settings.start;
+ } );
+} )( jQuery, document, window );
+/*
+ * ways.js
+ * Control the flow of the steps
+ */
+( function( $, document, window, undefined ) {
+ 'use strict';
+ var $jmpress = $.jmpress;
+
+ /* FUNCTIONS */
+ function routeFunc( jmpress, route, type ) {
+ for ( var i = 0; i < route.length - 1; i++ ) {
+ var from = route[ i ];
+ var to = route[ i + 1 ];
+ if ( $( jmpress ).jmpress( 'initialized' ) ) {
+ $( from, jmpress ).data( 'stepData' )[ type ] = to;
+ } else {
+ $( from, jmpress ).attr( 'data-' + type, to );
+ }
+ }
+ }
+ function selectPrevOrNext( step, eventData, attr, prev ) {
+ var stepData = eventData.stepData;
+ if ( stepData[ attr ] ) {
+ var near = $( step ).near( stepData[ attr ], prev );
+ if ( near && near.length ) {
+ return near;
+ }
+ near = $( stepData[ attr ], this )[ prev ? 'last' : 'first' ]();
+ if ( near && near.length ) {
+ return near;
+ }
+ }
+ }
+
+ /* EXPORTED FUNCTIONS */
+ $jmpress( 'register', 'route', function( route, unidirectional, reversedRoute ) {
+ if ( typeof route === 'string' ) {
+ route = [ route, route ];
+ }
+ routeFunc( this, route, reversedRoute ? 'prev' : 'next' );
+ if ( ! unidirectional ) {
+ routeFunc( this, route.reverse(), reversedRoute ? 'next' : 'prev' );
+ }
+ } );
+
+ /* HOOKS */
+ $jmpress( 'initStep', function( step, eventData ) {
+ for ( var attr in { next: 1, prev: 1 } ) {
+ eventData.stepData[ attr ] = eventData.data[ attr ];
+ }
+ } );
+ $jmpress( 'selectNext', function( step, eventData ) {
+ return selectPrevOrNext.call( this, step, eventData, 'next' );
+ } );
+ $jmpress( 'selectPrev', function( step, eventData ) {
+ return selectPrevOrNext.call( this, step, eventData, 'prev', true );
+ } );
+} )( jQuery, document, window );
+/*
+ * ajax.js
+ * Load steps via ajax
+ */
+( function( $, document, window, undefined ) {
+ 'use strict';
+ var $jmpress = $.jmpress;
+
+ /* DEFINES */
+ var afterStepLoaded = 'ajax:afterStepLoaded',
+ loadStep = 'ajax:loadStep';
+
+ /* REGISTER EVENTS */
+ $jmpress( 'register', loadStep );
+ $jmpress( 'register', afterStepLoaded );
+
+ /* DEFAULTS */
+ $jmpress( 'defaults' ).ajaxLoadedClass = 'loaded';
+
+ /* HOOKS */
+ $jmpress( 'initStep', function( step, eventData ) {
+ eventData.stepData.src = $( step ).attr( 'href' ) || eventData.data.src || false;
+ eventData.stepData.srcLoaded = false;
+ } );
+ $jmpress( loadStep, function( step, eventData ) {
+ var stepData = eventData.stepData,
+ href = stepData && stepData.src,
+ settings = eventData.settings;
+ if ( href ) {
+ $( step ).addClass( settings.ajaxLoadedClass );
+ stepData.srcLoaded = true;
+ $( step ).load( href, function( response, status, xhr ) {
+ $( eventData.jmpress ).jmpress(
+ 'fire',
+ afterStepLoaded,
+ step,
+ $.extend( {}, eventData, {
+ response: response,
+ status: status,
+ xhr: xhr,
+ } )
+ );
+ } );
+ }
+ } );
+ $jmpress( 'idle', function( step, eventData ) {
+ if ( ! step ) {
+ return;
+ }
+ var settings = eventData.settings,
+ jmpress = $( this ),
+ stepData = eventData.stepData;
+ var siblings = $( step )
+ .add( $( step ).near( settings.stepSelector ) )
+ .add( $( step ).near( settings.stepSelector, true ) )
+ .add(
+ jmpress.jmpress( 'fire', 'selectPrev', step, {
+ stepData: $( step ).data( 'stepData' ),
+ } )
+ )
+ .add(
+ jmpress.jmpress( 'fire', 'selectNext', step, {
+ stepData: $( step ).data( 'stepData' ),
+ } )
+ );
+ siblings.each( function() {
+ var step = this,
+ stepData = $( step ).data( 'stepData' );
+ if ( ! stepData.src || stepData.srcLoaded ) {
+ return;
+ }
+ jmpress.jmpress( 'fire', loadStep, step, {
+ stepData: $( step ).data( 'stepData' ),
+ } );
+ } );
+ } );
+ $jmpress( 'setActive', function( step, eventData ) {
+ var stepData = $( step ).data( 'stepData' );
+ if ( ! stepData.src || stepData.srcLoaded ) {
+ return;
+ }
+ $( this ).jmpress( 'fire', loadStep, step, {
+ stepData: $( step ).data( 'stepData' ),
+ } );
+ } );
+} )( jQuery, document, window );
+/*
+ * hash.js
+ * Detect and set the URL hash
+ */
+( function( $, document, window, undefined ) {
+ 'use strict';
+ var $jmpress = $.jmpress,
+ hashLink = "a[href^='#']";
+
+ /* FUNCTIONS */
+ function randomString() {
+ return '' + Math.round( Math.random() * 100000, 0 );
+ }
+ /**
+ * getElementFromUrl
+ *
+ * @return String or undefined
+ */
+ function getElementFromUrl( settings ) {
+ // get id from url # by removing `#` or `#/` from the beginning,
+ // so both "fallback" `#slide-id` and "enhanced" `#/slide-id` will work
+ // TODO SECURITY check user input to be valid!
+ try {
+ var el = $( '#' + window.location.hash.replace( /^#\/?/, '' ) );
+ return el.length > 0 && el.is( settings.stepSelector ) ? el : undefined;
+ } catch ( e ) {}
+ }
+ function setHash( stepid ) {
+ var shouldBeHash = '#/' + stepid;
+ if ( window.history && window.history.pushState ) {
+ // shouldBeHash = "#" + stepid;
+ // consider this for future versions
+ // it has currently issues, when startup with a link with hash (webkit)
+ if ( window.location.hash !== shouldBeHash ) {
+ window.history.pushState( {}, '', shouldBeHash );
+ }
+ } else {
+ if ( window.location.hash !== shouldBeHash ) {
+ window.location.hash = shouldBeHash;
+ }
+ }
+ }
+
+ /* DEFAULTS */
+ $jmpress( 'defaults' ).hash = {
+ use: true,
+ update: true,
+ bindChange: true,
+ // NOTICE: {use: true, update: false, bindChange: true}
+ // will cause a error after clicking on a link to the current step
+ };
+
+ /* HOOKS */
+ $jmpress( 'selectInitialStep', function( step, eventData ) {
+ var settings = eventData.settings,
+ hashSettings = settings.hash,
+ current = eventData.current,
+ jmpress = $( this );
+ eventData.current.hashNamespace = '.jmpress-' + randomString();
+ // HASH CHANGE EVENT
+ if ( hashSettings.use ) {
+ if ( hashSettings.bindChange ) {
+ $( window ).bind( 'hashchange' + current.hashNamespace, function( event ) {
+ var urlItem = getElementFromUrl( settings );
+ if ( jmpress.jmpress( 'initialized' ) ) {
+ jmpress.jmpress( 'scrollFix' );
+ }
+ if ( urlItem && urlItem.length ) {
+ if ( urlItem.attr( 'id' ) !== jmpress.jmpress( 'active' ).attr( 'id' ) ) {
+ jmpress.jmpress( 'select', urlItem );
+ }
+ setHash( urlItem.attr( 'id' ) );
+ }
+ event.preventDefault();
+ } );
+ $( hashLink ).on( 'click' + current.hashNamespace, function( event ) {
+ var href = $( this ).attr( 'href' );
+ try {
+ if ( $( href ).is( settings.stepSelector ) ) {
+ jmpress.jmpress( 'select', href );
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ } catch ( e ) {}
+ } );
+ }
+ return getElementFromUrl( settings );
+ }
+ } );
+ $jmpress( 'afterDeinit', function( nil, eventData ) {
+ $( hashLink ).off( eventData.current.hashNamespace );
+ $( window ).unbind( eventData.current.hashNamespace );
+ } );
+ $jmpress( 'setActive', function( step, eventData ) {
+ var settings = eventData.settings,
+ current = eventData.current;
+ // `#/step-id` is used instead of `#step-id` to prevent default browser
+ // scrolling to element in hash
+ if ( settings.hash.use && settings.hash.update ) {
+ clearTimeout( current.hashtimeout );
+ current.hashtimeout = setTimeout( function() {
+ setHash( $( eventData.delegatedFrom ).attr( 'id' ) );
+ }, settings.transitionDuration + 200 );
+ }
+ } );
+} )( jQuery, document, window );
+/*
+ * keyboard.js
+ * Keyboard event mapping and default keyboard actions
+ */
+( function( $, document, window, undefined ) {
+ 'use strict';
+ var $jmpress = $.jmpress,
+ jmpressNext = 'next',
+ jmpressPrev = 'prev';
+
+ /* FUNCTIONS */
+ function randomString() {
+ return '' + Math.round( Math.random() * 100000, 0 );
+ }
+ function stopEvent( event ) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+
+ /* DEFAULTS */
+ $jmpress( 'defaults' ).keyboard = {
+ use: true,
+ keys: {
+ 33: jmpressPrev, // pg up
+ 37: jmpressPrev, // left
+ 38: jmpressPrev, // up
+
+ 9: jmpressNext + ':' + jmpressPrev, // tab
+ 32: jmpressNext, // space
+ 34: jmpressNext, // pg down
+ 39: jmpressNext, // right
+ 40: jmpressNext, // down
+
+ 36: 'home', // home
+
+ 35: 'end', // end
+ },
+ ignore: {
+ INPUT: [
+ 32, // space
+ 37, // left
+ 38, // up
+ 39, // right
+ 40, // down
+ ],
+ TEXTAREA: [
+ 32, // space
+ 37, // left
+ 38, // up
+ 39, // right
+ 40, // down
+ ],
+ SELECT: [
+ 38, // up
+ 40, // down
+ ],
+ },
+ tabSelector: 'a[href]:visible, :input:visible',
+ };
+
+ /* HOOKS */
+ $jmpress( 'afterInit', function( nil, eventData ) {
+ var settings = eventData.settings,
+ keyboardSettings = settings.keyboard,
+ ignoreKeyboardSettings = keyboardSettings.ignore,
+ current = eventData.current,
+ jmpress = $( this );
+
+ // tabindex make it focusable so that it can receive key events
+ if ( ! settings.fullscreen ) {
+ jmpress.attr( 'tabindex', 0 );
+ }
+
+ current.keyboardNamespace = '.jmpress-' + randomString();
+
+ // KEYPRESS EVENT: this fixes a Opera bug
+ $( settings.fullscreen ? document : jmpress ).bind(
+ 'keypress' + current.keyboardNamespace,
+ function( event ) {
+ for ( var nodeName in ignoreKeyboardSettings ) {
+ if (
+ event.target.nodeName === nodeName &&
+ ignoreKeyboardSettings[ nodeName ].indexOf( event.which ) !== -1
+ ) {
+ return;
+ }
+ }
+ if ( ( event.which >= 37 && event.which <= 40 ) || event.which === 32 ) {
+ stopEvent( event );
+ }
+ }
+ );
+ // KEYDOWN EVENT
+ $( settings.fullscreen ? document : jmpress ).bind(
+ 'keydown' + current.keyboardNamespace,
+ function( event ) {
+ var eventTarget = $( event.target );
+
+ if (
+ ( ! settings.fullscreen && ! eventTarget.closest( jmpress ).length ) ||
+ ! keyboardSettings.use
+ ) {
+ return;
+ }
+
+ for ( var nodeName in ignoreKeyboardSettings ) {
+ if (
+ eventTarget[ 0 ].nodeName === nodeName &&
+ ignoreKeyboardSettings[ nodeName ].indexOf( event.which ) !== -1
+ ) {
+ return;
+ }
+ }
+
+ var reverseSelect = false;
+ var nextFocus;
+ if ( event.which === 9 ) {
+ // tab
+ if ( ! eventTarget.closest( jmpress.jmpress( 'active' ) ).length ) {
+ if ( ! event.shiftKey ) {
+ nextFocus = jmpress
+ .jmpress( 'active' )
+ .find( 'a[href], :input' )
+ .filter( ':visible' )
+ .first();
+ } else {
+ reverseSelect = true;
+ }
+ } else {
+ nextFocus = eventTarget.near( keyboardSettings.tabSelector, event.shiftKey );
+ if (
+ ! $( nextFocus )
+ .closest( settings.stepSelector )
+ .is( jmpress.jmpress( 'active' ) )
+ ) {
+ nextFocus = undefined;
+ }
+ }
+ if ( nextFocus && nextFocus.length > 0 ) {
+ nextFocus.focus();
+ jmpress.jmpress( 'scrollFix' );
+ stopEvent( event );
+ return;
+ } else {
+ if ( event.shiftKey ) {
+ reverseSelect = true;
+ }
+ }
+ }
+
+ var action = keyboardSettings.keys[ event.which ];
+ if ( typeof action === 'string' ) {
+ if ( action.indexOf( ':' ) !== -1 ) {
+ action = action.split( ':' );
+ action = event.shiftKey ? action[ 1 ] : action[ 0 ];
+ }
+ jmpress.jmpress( action );
+ stopEvent( event );
+ } else if ( $.isFunction( action ) ) {
+ action.call( jmpress, event );
+ } else if ( action ) {
+ jmpress.jmpress.apply( jmpress, action );
+ stopEvent( event );
+ }
+
+ if ( reverseSelect ) {
+ // tab
+ nextFocus = jmpress
+ .jmpress( 'active' )
+ .find( 'a[href], :input' )
+ .filter( ':visible' )
+ .last();
+ nextFocus.focus();
+ jmpress.jmpress( 'scrollFix' );
+ }
+ }
+ );
+ } );
+ $jmpress( 'afterDeinit', function( nil, eventData ) {
+ $( document ).unbind( eventData.current.keyboardNamespace );
+ } );
+} )( jQuery, document, window );
+/*
+ * viewport.js
+ * Scale to fit a given viewport
+ */
+( function( $, document, window, undefined ) {
+ 'use strict';
+
+ function randomString() {
+ return '' + Math.round( Math.random() * 100000, 0 );
+ }
+
+ var browser = ( function() {
+ var ua = navigator.userAgent.toLowerCase();
+ var match =
+ /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
+ /(webkit)[ \/]([\w.]+)/.exec( ua ) ||
+ /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
+ /(msie) ([\w.]+)/.exec( ua ) ||
+ ( ua.indexOf( 'compatible' ) < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ) ||
+ [];
+ return match[ 1 ] || '';
+ } )();
+
+ var defaults = $.jmpress( 'defaults' );
+ defaults.viewPort = {
+ width: false,
+ height: false,
+ maxScale: 0,
+ minScale: 0,
+ zoomable: 0,
+ zoomBindMove: true,
+ zoomBindWheel: true,
+ };
+ var keys = defaults.keyboard.keys;
+ keys[ browser === 'mozilla' ? 107 : 187 ] = 'zoomIn'; // +
+ keys[ browser === 'mozilla' ? 109 : 189 ] = 'zoomOut'; // -
+ defaults.reasonableAnimation.resize = {
+ transitionDuration: '0s',
+ transitionDelay: '0ms',
+ };
+ defaults.reasonableAnimation.zoom = {
+ transitionDuration: '0s',
+ transitionDelay: '0ms',
+ };
+ $.jmpress( 'initStep', function( step, eventData ) {
+ for ( var variable in {
+ viewPortHeight: 1,
+ viewPortWidth: 1,
+ viewPortMinScale: 1,
+ viewPortMaxScale: 1,
+ viewPortZoomable: 1,
+ } ) {
+ eventData.stepData[ variable ] =
+ eventData.data[ variable ] && parseFloat( eventData.data[ variable ] );
+ }
+ } );
+ $.jmpress( 'afterInit', function( nil, eventData ) {
+ var jmpress = this;
+ eventData.current.viewPortNamespace = '.jmpress-' + randomString();
+ $( window ).bind( 'resize' + eventData.current.viewPortNamespace, function( event ) {
+ $( jmpress ).jmpress( 'reselect', 'resize' );
+ } );
+ eventData.current.userZoom = 0;
+ eventData.current.userTranslateX = 0;
+ eventData.current.userTranslateY = 0;
+ if ( eventData.settings.viewPort.zoomBindWheel ) {
+ $( eventData.settings.fullscreen ? document : this ).bind(
+ 'mousewheel' +
+ eventData.current.viewPortNamespace +
+ ' DOMMouseScroll' +
+ eventData.current.viewPortNamespace,
+ function( event, delta ) {
+ delta =
+ delta || event.originalEvent.wheelDelta || -event.originalEvent.detail /* mozilla */;
+ var direction = delta / Math.abs( delta );
+ if ( direction < 0 ) {
+ $( eventData.jmpress ).jmpress(
+ 'zoomOut',
+ event.originalEvent.x,
+ event.originalEvent.y
+ );
+ } else if ( direction > 0 ) {
+ $( eventData.jmpress ).jmpress(
+ 'zoomIn',
+ event.originalEvent.x,
+ event.originalEvent.y
+ );
+ }
+ return false;
+ }
+ );
+ }
+ if ( eventData.settings.viewPort.zoomBindMove ) {
+ $( eventData.settings.fullscreen ? document : this )
+ .bind( 'mousedown' + eventData.current.viewPortNamespace, function( event ) {
+ if ( eventData.current.userZoom ) {
+ eventData.current.userTranslating = { x: event.clientX, y: event.clientY };
+ event.preventDefault();
+ event.stopImmediatePropagation();
+ }
+ } )
+ .bind( 'mousemove' + eventData.current.viewPortNamespace, function( event ) {
+ var userTranslating = eventData.current.userTranslating;
+ if ( userTranslating ) {
+ $( jmpress ).jmpress(
+ 'zoomTranslate',
+ event.clientX - userTranslating.x,
+ event.clientY - userTranslating.y
+ );
+ userTranslating.x = event.clientX;
+ userTranslating.y = event.clientY;
+ event.preventDefault();
+ event.stopImmediatePropagation();
+ }
+ } )
+ .bind( 'mouseup' + eventData.current.viewPortNamespace, function( event ) {
+ if ( eventData.current.userTranslating ) {
+ eventData.current.userTranslating = undefined;
+ event.preventDefault();
+ event.stopImmediatePropagation();
+ }
+ } );
+ }
+ } );
+ function maxAbs( value, range ) {
+ return Math.max( Math.min( value, range ), -range );
+ }
+ function zoom( x, y, direction ) {
+ var current = $( this ).jmpress( 'current' ),
+ settings = $( this ).jmpress( 'settings' ),
+ stepData = $( this )
+ .jmpress( 'active' )
+ .data( 'stepData' ),
+ container = $( this ).jmpress( 'container' );
+ if ( current.userZoom === 0 && direction < 0 ) {
+ return;
+ }
+ var zoomableSteps = stepData.viewPortZoomable || settings.viewPort.zoomable;
+ if ( current.userZoom === zoomableSteps && direction > 0 ) {
+ return;
+ }
+ current.userZoom += direction;
+
+ var halfWidth = $( container ).innerWidth() / 2,
+ halfHeight = $( container ).innerHeight() / 2;
+
+ x = x ? x - halfWidth : x;
+ y = y ? y - halfHeight : y;
+
+ // TODO this is not perfect... too much math... :(
+ current.userTranslateX = maxAbs(
+ current.userTranslateX - ( direction * x ) / current.zoomOriginWindowScale / zoomableSteps,
+ ( halfWidth * current.userZoom * current.userZoom ) / zoomableSteps
+ );
+ current.userTranslateY = maxAbs(
+ current.userTranslateY - ( direction * y ) / current.zoomOriginWindowScale / zoomableSteps,
+ ( halfHeight * current.userZoom * current.userZoom ) / zoomableSteps
+ );
+
+ $( this ).jmpress( 'reselect', 'zoom' );
+ }
+ $.jmpress( 'register', 'zoomIn', function( x, y ) {
+ zoom.call( this, x || 0, y || 0, 1 );
+ } );
+ $.jmpress( 'register', 'zoomOut', function( x, y ) {
+ zoom.call( this, x || 0, y || 0, -1 );
+ } );
+ $.jmpress( 'register', 'zoomTranslate', function( x, y ) {
+ var current = $( this ).jmpress( 'current' ),
+ settings = $( this ).jmpress( 'settings' ),
+ stepData = $( this )
+ .jmpress( 'active' )
+ .data( 'stepData' ),
+ container = $( this ).jmpress( 'container' );
+ var zoomableSteps = stepData.viewPortZoomable || settings.viewPort.zoomable;
+ var halfWidth = $( container ).innerWidth(),
+ halfHeight = $( container ).innerHeight();
+ current.userTranslateX = maxAbs(
+ current.userTranslateX + x / current.zoomOriginWindowScale,
+ ( halfWidth * current.userZoom * current.userZoom ) / zoomableSteps
+ );
+ current.userTranslateY = maxAbs(
+ current.userTranslateY + y / current.zoomOriginWindowScale,
+ ( halfHeight * current.userZoom * current.userZoom ) / zoomableSteps
+ );
+ $( this ).jmpress( 'reselect', 'zoom' );
+ } );
+ $.jmpress( 'afterDeinit', function( nil, eventData ) {
+ $( eventData.settings.fullscreen ? document : this ).unbind(
+ eventData.current.viewPortNamespace
+ );
+ $( window ).unbind( eventData.current.viewPortNamespace );
+ } );
+ $.jmpress( 'setActive', function( step, eventData ) {
+ var viewPort = eventData.settings.viewPort;
+ var viewPortHeight = eventData.stepData.viewPortHeight || viewPort.height;
+ var viewPortWidth = eventData.stepData.viewPortWidth || viewPort.width;
+ var viewPortMaxScale = eventData.stepData.viewPortMaxScale || viewPort.maxScale;
+ var viewPortMinScale = eventData.stepData.viewPortMinScale || viewPort.minScale;
+ // Correct the scale based on the window's size
+ var windowScaleY = viewPortHeight && $( eventData.container ).innerHeight() / viewPortHeight;
+ var windowScaleX = viewPortWidth && $( eventData.container ).innerWidth() / viewPortWidth;
+ var windowScale =
+ ( windowScaleX || windowScaleY ) &&
+ Math.min( windowScaleX || windowScaleY, windowScaleY || windowScaleX );
+
+ if ( windowScale ) {
+ windowScale = windowScale || 1;
+ if ( viewPortMaxScale ) {
+ windowScale = Math.min( windowScale, viewPortMaxScale );
+ }
+ if ( viewPortMinScale ) {
+ windowScale = Math.max( windowScale, viewPortMinScale );
+ }
+
+ var zoomableSteps =
+ eventData.stepData.viewPortZoomable || eventData.settings.viewPort.zoomable;
+ if ( zoomableSteps ) {
+ var diff = 1 / windowScale - 1 / viewPortMaxScale;
+ diff /= zoomableSteps;
+ windowScale = 1 / ( 1 / windowScale - diff * eventData.current.userZoom );
+ }
+
+ eventData.target.transform.reverse();
+ if ( eventData.current.userTranslateX && eventData.current.userTranslateY ) {
+ eventData.target.transform.push( [
+ 'translate',
+ eventData.current.userTranslateX,
+ eventData.current.userTranslateY,
+ 0,
+ ] );
+ } else {
+ eventData.target.transform.push( [ 'translate' ] );
+ }
+ eventData.target.transform.push( [ 'scale', windowScale, windowScale, 1 ] );
+ eventData.target.transform.reverse();
+ eventData.target.perspectiveScale /= windowScale;
+ }
+ eventData.current.zoomOriginWindowScale = windowScale;
+ } );
+ $.jmpress( 'setInactive', function( step, eventData ) {
+ if (
+ ! eventData.nextStep ||
+ ! step ||
+ $( eventData.nextStep ).attr( 'id' ) !== $( step ).attr( 'id' )
+ ) {
+ eventData.current.userZoom = 0;
+ eventData.current.userTranslateX = 0;
+ eventData.current.userTranslateY = 0;
+ }
+ } );
+} )( jQuery, document, window );
+
+/*
+ * mouse.js
+ * Clicking to select a step
+ */
+( function( $, document, window, undefined ) {
+ 'use strict';
+ var $jmpress = $.jmpress;
+
+ /* FUNCTIONS */
+ function randomString() {
+ return '' + Math.round( Math.random() * 100000, 0 );
+ }
+
+ /* DEFAULTS */
+ $jmpress( 'defaults' ).mouse = {
+ clickSelects: true,
+ };
+
+ /* HOOKS */
+ $jmpress( 'afterInit', function( nil, eventData ) {
+ var settings = eventData.settings,
+ stepSelector = settings.stepSelector,
+ current = eventData.current,
+ jmpress = $( this );
+ current.clickableStepsNamespace = '.jmpress-' + randomString();
+ jmpress.bind( 'click' + current.clickableStepsNamespace, function( event ) {
+ if ( ! settings.mouse.clickSelects || current.userZoom ) {
+ return;
+ }
+
+ // get clicked step
+ var clickedStep = $( event.target ).closest( stepSelector );
+
+ // clicks on the active step do default
+ if ( clickedStep.is( jmpress.jmpress( 'active' ) ) ) {
+ return;
+ }
+
+ if ( clickedStep.length ) {
+ // select the clicked step
+ jmpress.jmpress( 'select', clickedStep[ 0 ], 'click' );
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ } );
+ } );
+ $jmpress( 'afterDeinit', function( nil, eventData ) {
+ $( this ).unbind( eventData.current.clickableStepsNamespace );
+ } );
+} )( jQuery, document, window );
+/*
+ * mobile.js
+ * Adds support for swipe on touch supported browsers
+ */
+( function( $, document, window, undefined ) {
+ 'use strict';
+ var $jmpress = $.jmpress;
+
+ /* FUNCTIONS */
+ function randomString() {
+ return '' + Math.round( Math.random() * 100000, 0 );
+ }
+
+ /* HOOKS */
+ $jmpress( 'afterInit', function( step, eventData ) {
+ var settings = eventData.settings,
+ current = eventData.current,
+ jmpress = eventData.jmpress;
+ current.mobileNamespace = '.jmpress-' + randomString();
+ var data,
+ start = [ 0, 0 ];
+ $( settings.fullscreen ? document : jmpress )
+ .bind( 'touchstart' + current.mobileNamespace, function( event ) {
+ data = event.originalEvent.touches[ 0 ];
+ start = [ data.pageX, data.pageY ];
+ } )
+ .bind( 'touchmove' + current.mobileNamespace, function( event ) {
+ data = event.originalEvent.touches[ 0 ];
+ event.preventDefault();
+ return false;
+ } )
+ .bind( 'touchend' + current.mobileNamespace, function( event ) {
+ var end = [ data.pageX, data.pageY ],
+ diff = [ end[ 0 ] - start[ 0 ], end[ 1 ] - start[ 1 ] ];
+
+ if ( Math.max( Math.abs( diff[ 0 ] ), Math.abs( diff[ 1 ] ) ) > 50 ) {
+ diff = Math.abs( diff[ 0 ] ) > Math.abs( diff[ 1 ] ) ? diff[ 0 ] : diff[ 1 ];
+ $( jmpress ).jmpress( diff > 0 ? 'prev' : 'next' );
+ event.preventDefault();
+ return false;
+ }
+ } );
+ } );
+ $jmpress( 'afterDeinit', function( nil, eventData ) {
+ var settings = eventData.settings,
+ current = eventData.current,
+ jmpress = eventData.jmpress;
+ $( settings.fullscreen ? document : jmpress ).unbind( current.mobileNamespace );
+ } );
+} )( jQuery, document, window );
+/*
+ * templates.js
+ * The amazing template engine
+ */
+( function( $, document, window, undefined ) {
+ 'use strict';
+ var $jmpress = $.jmpress,
+ templateFromParentIdent = '_template_',
+ templateFromApplyIdent = '_applied_template_';
+
+ /* STATIC VARS */
+ var templates = {};
+
+ /* FUNCTIONS */
+ function addUndefined( target, values, prefix ) {
+ for ( var name in values ) {
+ var targetName = name;
+ if ( prefix ) {
+ targetName = prefix + targetName.substr( 0, 1 ).toUpperCase() + targetName.substr( 1 );
+ }
+ if ( $.isPlainObject( values[ name ] ) ) {
+ addUndefined( target, values[ name ], targetName );
+ } else if ( target[ targetName ] === undefined ) {
+ target[ targetName ] = values[ name ];
+ }
+ }
+ }
+ function applyChildrenTemplates( children, templateChildren ) {
+ if ( $.isArray( templateChildren ) ) {
+ if ( templateChildren.length < children.length ) {
+ $.error( 'more nested steps than children in template' );
+ } else {
+ children.each( function( idx, child ) {
+ child = $( child );
+ var tmpl = child.data( templateFromParentIdent ) || {};
+ addUndefined( tmpl, templateChildren[ idx ] );
+ child.data( templateFromParentIdent, tmpl );
+ } );
+ }
+ } else if ( $.isFunction( templateChildren ) ) {
+ children.each( function( idx, child ) {
+ child = $( child );
+ var tmpl = child.data( templateFromParentIdent ) || {};
+ addUndefined( tmpl, templateChildren( idx, child, children ) );
+ child.data( templateFromParentIdent, tmpl );
+ } );
+ } // TODO: else if(object)
+ }
+ function applyTemplate( data, element, template, eventData ) {
+ if ( template.children ) {
+ var children = element.children( eventData.settings.stepSelector );
+ applyChildrenTemplates( children, template.children );
+ }
+ applyTemplateData( data, template );
+ }
+ function applyTemplateData( data, template ) {
+ addUndefined( data, template );
+ }
+
+ /* HOOKS */
+ $jmpress( 'beforeInitStep', function( step, eventData ) {
+ step = $( step );
+ var data = eventData.data,
+ templateFromAttr = data.template,
+ templateFromApply = step.data( templateFromApplyIdent ),
+ templateFromParent = step.data( templateFromParentIdent );
+ if ( templateFromAttr ) {
+ $.each( templateFromAttr.split( ' ' ), function( idx, tmpl ) {
+ var template = templates[ tmpl ];
+ applyTemplate( data, step, template, eventData );
+ } );
+ }
+ if ( templateFromApply ) {
+ applyTemplate( data, step, templateFromApply, eventData );
+ }
+ if ( templateFromParent ) {
+ applyTemplate( data, step, templateFromParent, eventData );
+ step.data( templateFromParentIdent, null );
+ if ( templateFromParent.template ) {
+ $.each( templateFromParent.template.split( ' ' ), function( idx, tmpl ) {
+ var template = templates[ tmpl ];
+ applyTemplate( data, step, template, eventData );
+ } );
+ }
+ }
+ } );
+ $jmpress( 'beforeInit', function( nil, eventData ) {
+ var data = $jmpress( 'dataset', this ),
+ dataTemplate = data.template,
+ stepSelector = eventData.settings.stepSelector;
+ if ( dataTemplate ) {
+ var template = templates[ dataTemplate ];
+ applyChildrenTemplates(
+ $( this )
+ .find( stepSelector )
+ .filter( function() {
+ return ! $( this )
+ .parent()
+ .is( stepSelector );
+ } ),
+ template.children
+ );
+ }
+ } );
+
+ /* EXPORTED FUNCTIONS */
+ $jmpress( 'register', 'template', function( name, tmpl ) {
+ if ( templates[ name ] ) {
+ templates[ name ] = $.extend( true, {}, templates[ name ], tmpl );
+ } else {
+ templates[ name ] = $.extend( true, {}, tmpl );
+ }
+ } );
+ $jmpress( 'register', 'apply', function( selector, tmpl ) {
+ if ( ! tmpl ) {
+ // TODO ERROR because settings not found
+ var stepSelector = $( this ).jmpress( 'settings' ).stepSelector;
+ applyChildrenTemplates(
+ $( this )
+ .find( stepSelector )
+ .filter( function() {
+ return ! $( this )
+ .parent()
+ .is( stepSelector );
+ } ),
+ selector
+ );
+ } else if ( $.isArray( tmpl ) ) {
+ applyChildrenTemplates( $( selector ), tmpl );
+ } else {
+ var template;
+ if ( typeof tmpl === 'string' ) {
+ template = templates[ tmpl ];
+ } else {
+ template = $.extend( true, {}, tmpl );
+ }
+ $( selector ).each( function( idx, element ) {
+ element = $( element );
+ var tmpl = element.data( templateFromApplyIdent ) || {};
+ addUndefined( tmpl, template );
+ element.data( templateFromApplyIdent, tmpl );
+ } );
+ }
+ } );
+} )( jQuery, document, window );
+/*
+ * jqevents.js
+ * Fires jQuery events
+ */
+( function( $, document, window, undefined ) {
+ 'use strict';
+
+ /* HOOKS */
+ // the events should not bubble up the tree
+ // elsewise nested jmpress would cause buggy behavior
+ $.jmpress( 'setActive', function( step, eventData ) {
+ if ( eventData.prevStep !== step ) {
+ $( step ).triggerHandler( 'enterStep' );
+ }
+ } );
+ $.jmpress( 'setInactive', function( step, eventData ) {
+ if ( eventData.nextStep !== step ) {
+ $( step ).triggerHandler( 'leaveStep' );
+ }
+ } );
+} )( jQuery, document, window );
+/*
+ * animation.js
+ * Apply custom animations to steps
+ */
+( function( $, document, window, undefined ) {
+ 'use strict';
+
+ function parseSubstepInfo( str ) {
+ var arr = str.split( ' ' );
+ var className = arr[ 0 ];
+ var config = {
+ willClass: 'will-' + className,
+ doClass: 'do-' + className,
+ hasClass: 'has-' + className,
+ };
+ var state = '';
+ for ( var i = 1; i < arr.length; i++ ) {
+ var s = arr[ i ];
+ switch ( state ) {
+ case '':
+ if ( s === 'after' ) {
+ state = 'after';
+ } else {
+ $.warn( "unknown keyword in '" + str + "'. '" + s + "' unknown." );
+ }
+ break;
+ case 'after':
+ if ( s.match( /^[1-9][0-9]*m?s?/ ) ) {
+ var value = parseFloat( s );
+ if ( s.indexOf( 'ms' ) !== -1 ) {
+ value *= 1;
+ } else if ( s.indexOf( 's' ) !== -1 ) {
+ value *= 1000;
+ } else if ( s.indexOf( 'm' ) !== -1 ) {
+ value *= 60000;
+ }
+ config.delay = value;
+ } else {
+ config.after = Array.prototype.slice.call( arr, i ).join( ' ' );
+ i = arr.length;
+ }
+ }
+ }
+ return config;
+ }
+ function find( array, selector, start, end ) {
+ end = end || array.length - 1;
+ start = start || 0;
+ for ( var i = start; i < end + 1; i++ ) {
+ if ( $( array[ i ].element ).is( selector ) ) {
+ return i;
+ }
+ }
+ }
+ function addOn( list, substep, delay ) {
+ $.each( substep._on, function( idx, child ) {
+ list.push( { substep: child.substep, delay: child.delay + delay } );
+ addOn( list, child.substep, child.delay + delay );
+ } );
+ }
+ $.jmpress( 'defaults' ).customAnimationDataAttribute = 'jmpress';
+ $.jmpress( 'afterInit', function( nil, eventData ) {
+ eventData.current.animationTimeouts = [];
+ eventData.current.animationCleanupWaiting = [];
+ } );
+ $.jmpress( 'applyStep', function( step, eventData ) {
+ // read custom animation from elements
+ var substepsData = {};
+ var listOfSubsteps = [];
+ $( step )
+ .find( '[data-' + eventData.settings.customAnimationDataAttribute + ']' )
+ .each( function( idx, element ) {
+ if (
+ $( element )
+ .closest( eventData.settings.stepSelector )
+ .is( step )
+ ) {
+ listOfSubsteps.push( { element: element } );
+ }
+ } );
+ if ( listOfSubsteps.length === 0 ) {
+ return;
+ }
+ $.each( listOfSubsteps, function( idx, substep ) {
+ substep.info = parseSubstepInfo(
+ $( substep.element ).data( eventData.settings.customAnimationDataAttribute )
+ );
+ $( substep.element ).addClass( substep.info.willClass );
+ substep._on = [];
+ substep._after = null;
+ } );
+ var current = { _after: undefined, _on: [], info: {} }; // virtual zero step
+ $.each( listOfSubsteps, function( idx, substep ) {
+ var other = substep.info.after;
+ if ( other ) {
+ if ( other === 'step' ) {
+ other = current;
+ } else if ( other === 'prev' ) {
+ other = listOfSubsteps[ idx - 1 ];
+ } else {
+ var index = find( listOfSubsteps, other, 0, idx - 1 );
+ if ( index === undefined ) {
+ index = find( listOfSubsteps, other );
+ }
+ other =
+ index === undefined || index === idx
+ ? listOfSubsteps[ idx - 1 ]
+ : listOfSubsteps[ index ];
+ }
+ } else {
+ other = listOfSubsteps[ idx - 1 ];
+ }
+ if ( other ) {
+ if ( ! substep.info.delay ) {
+ if ( ! other._after ) {
+ other._after = substep;
+ return;
+ }
+ other = other._after;
+ }
+ other._on.push( { substep: substep, delay: substep.info.delay || 0 } );
+ }
+ } );
+ if ( current._after === undefined && current._on.length === 0 ) {
+ var startStep = find( listOfSubsteps, eventData.stepData.startSubstep ) || 0;
+ current._after = listOfSubsteps[ startStep ];
+ }
+ var substepsInOrder = [];
+ function findNextFunc( idx, item ) {
+ if ( item.substep._after ) {
+ current = item.substep._after;
+ return false;
+ }
+ }
+ do {
+ var substepList = [ { substep: current, delay: 0 } ];
+ addOn( substepList, current, 0 );
+ substepsInOrder.push( substepList );
+ current = null;
+ $.each( substepList, findNextFunc );
+ } while ( current );
+ substepsData.list = substepsInOrder;
+ $( step ).data( 'substepsData', substepsData );
+ } );
+ $.jmpress( 'unapplyStep', function( step, eventData ) {
+ var substepsData = $( step ).data( 'substepsData' );
+ if ( substepsData ) {
+ $.each( substepsData.list, function( idx, activeSubsteps ) {
+ $.each( activeSubsteps, function( idx, substep ) {
+ if ( substep.substep.info.willClass ) {
+ $( substep.substep.element ).removeClass( substep.substep.info.willClass );
+ }
+ if ( substep.substep.info.hasClass ) {
+ $( substep.substep.element ).removeClass( substep.substep.info.hasClass );
+ }
+ if ( substep.substep.info.doClass ) {
+ $( substep.substep.element ).removeClass( substep.substep.info.doClass );
+ }
+ } );
+ } );
+ }
+ } );
+ $.jmpress( 'setActive', function( step, eventData ) {
+ var substepsData = $( step ).data( 'substepsData' );
+ if ( ! substepsData ) {
+ return;
+ }
+ if ( eventData.substep === undefined ) {
+ eventData.substep = eventData.reason === 'prev' ? substepsData.list.length - 1 : 0;
+ }
+ var substep = eventData.substep;
+ $.each( eventData.current.animationTimeouts, function( idx, timeout ) {
+ clearTimeout( timeout );
+ } );
+ eventData.current.animationTimeouts = [];
+ $.each( substepsData.list, function( idx, activeSubsteps ) {
+ var applyHas = idx < substep;
+ var applyDo = idx <= substep;
+ $.each( activeSubsteps, function( idx, substep ) {
+ if ( substep.substep.info.hasClass ) {
+ $( substep.substep.element )[ ( applyHas ? 'add' : 'remove' ) + 'Class' ](
+ substep.substep.info.hasClass
+ );
+ }
+ function applyIt() {
+ $( substep.substep.element ).addClass( substep.substep.info.doClass );
+ }
+ if ( applyDo && ! applyHas && substep.delay && eventData.reason !== 'prev' ) {
+ if ( substep.substep.info.doClass ) {
+ $( substep.substep.element ).removeClass( substep.substep.info.doClass );
+ eventData.current.animationTimeouts.push( setTimeout( applyIt, substep.delay ) );
+ }
+ } else {
+ if ( substep.substep.info.doClass ) {
+ $( substep.substep.element )[ ( applyDo ? 'add' : 'remove' ) + 'Class' ](
+ substep.substep.info.doClass
+ );
+ }
+ }
+ } );
+ } );
+ } );
+ $.jmpress( 'setInactive', function( step, eventData ) {
+ if ( eventData.nextStep === step ) {
+ return;
+ }
+ function cleanupAnimation( substepsData ) {
+ $.each( substepsData.list, function( idx, activeSubsteps ) {
+ $.each( activeSubsteps, function( idx, substep ) {
+ if ( substep.substep.info.hasClass ) {
+ $( substep.substep.element ).removeClass( substep.substep.info.hasClass );
+ }
+ if ( substep.substep.info.doClass ) {
+ $( substep.substep.element ).removeClass( substep.substep.info.doClass );
+ }
+ } );
+ } );
+ }
+ $.each( eventData.current.animationCleanupWaiting, function( idx, item ) {
+ cleanupAnimation( item );
+ } );
+ eventData.current.animationCleanupWaiting = [];
+ var substepsData = $( step ).data( 'substepsData' );
+ if ( substepsData ) {
+ eventData.current.animationCleanupWaiting.push( substepsData );
+ }
+ } );
+ $.jmpress( 'selectNext', function( step, eventData ) {
+ if ( eventData.substep === undefined ) {
+ return;
+ }
+ var substepsData = $( step ).data( 'substepsData' );
+ if ( ! substepsData ) {
+ return;
+ }
+ if ( eventData.substep < substepsData.list.length - 1 ) {
+ return { step: step, substep: eventData.substep + 1 };
+ }
+ } );
+ $.jmpress( 'selectPrev', function( step, eventData ) {
+ if ( eventData.substep === undefined ) {
+ return;
+ }
+ var substepsData = $( step ).data( 'substepsData' );
+ if ( ! substepsData ) {
+ return;
+ }
+ if ( eventData.substep > 0 ) {
+ return { step: step, substep: eventData.substep - 1 };
+ }
+ } );
+} )( jQuery, document, window );
+/*
+ * jmpress.toggle plugin
+ * For binding a key to toggle de/initialization of jmpress.js.
+ */
+/*!
+ * plugin for jmpress.js v0.4.5
+ *
+ * Copyright 2013 Kyle Robinson Young @shama & Tobias Koppers @sokra
+ * Licensed MIT
+ * http://www.opensource.org/licenses/mit-license.php
+ */ ( function( $, document, window, undefined ) {
+ 'use strict';
+ $.jmpress( 'register', 'toggle', function( key, config, initial ) {
+ var jmpress = this;
+ $( document ).bind( 'keydown', function( event ) {
+ if ( event.keyCode === key ) {
+ if ( $( jmpress ).jmpress( 'initialized' ) ) {
+ $( jmpress ).jmpress( 'deinit' );
+ } else {
+ $( jmpress ).jmpress( config );
+ }
+ }
+ } );
+ if ( initial ) {
+ $( jmpress ).jmpress( config );
+ }
+ } );
+} )( jQuery, document, window );
+
+/*
+ * jmpress.secondary plugin
+ * Apply a secondary animation when step is selected.
+ */
+( function( $, document, window, undefined ) {
+ 'use strict';
+ $.jmpress( 'initStep', function( step, eventData ) {
+ for ( var name in eventData.data ) {
+ if ( name.indexOf( 'secondary' ) === 0 ) {
+ eventData.stepData[ name ] = eventData.data[ name ];
+ }
+ }
+ } );
+ function exchangeIf( childStepData, condition, step ) {
+ if (
+ childStepData.secondary &&
+ childStepData.secondary.split( ' ' ).indexOf( condition ) !== -1
+ ) {
+ for ( var name in childStepData ) {
+ if ( name.length > 9 && name.indexOf( 'secondary' ) === 0 ) {
+ var tmp = childStepData[ name ];
+ var normal = name.substr( 9 );
+ normal = normal.substr( 0, 1 ).toLowerCase() + normal.substr( 1 );
+ childStepData[ name ] = childStepData[ normal ];
+ childStepData[ normal ] = tmp;
+ }
+ }
+ $( this ).jmpress( 'reapply', $( step ) );
+ }
+ }
+ $.jmpress( 'beforeActive', function( step, eventData ) {
+ exchangeIf.call( eventData.jmpress, $( step ).data( 'stepData' ), 'self', step );
+ var parent = $( step ).parent();
+ $( parent )
+ .children( eventData.settings.stepSelector )
+ .each( function( idx, child ) {
+ var childStepData = $( child ).data( 'stepData' );
+ exchangeIf.call( eventData.jmpress, childStepData, 'siblings', child );
+ } );
+ function grandchildrenFunc( idx, child ) {
+ var childStepData = $( child ).data( 'stepData' );
+ exchangeIf.call( eventData.jmpress, childStepData, 'grandchildren', child );
+ }
+ for ( var i = 1; i < eventData.parents.length; i++ ) {
+ $( eventData.parents[ i ] )
+ .children( eventData.settings.stepSelector )
+ .each();
+ }
+ } );
+ $.jmpress( 'setInactive', function( step, eventData ) {
+ exchangeIf.call( eventData.jmpress, $( step ).data( 'stepData' ), 'self', step );
+ var parent = $( step ).parent();
+ $( parent )
+ .children( eventData.settings.stepSelector )
+ .each( function( idx, child ) {
+ var childStepData = $( child ).data( 'stepData' );
+ exchangeIf.call( eventData.jmpress, childStepData, 'siblings', child );
+ } );
+ function grandchildrenFunc( idx, child ) {
+ var childStepData = $( child ).data( 'stepData' );
+ exchangeIf.call( eventData.jmpress, childStepData, 'grandchildren', child );
+ }
+ for ( var i = 1; i < eventData.parents.length; i++ ) {
+ $( eventData.parents[ i ] )
+ .children( eventData.settings.stepSelector )
+ .each( grandchildrenFunc );
+ }
+ } );
+} )( jQuery, document, window );
+
+/*
+ * jmpress.duration plugin
+ * For auto advancing steps after a given duration and optionally displaying a
+ * progress bar.
+ */
+( function( $, document, window, undefined ) {
+ 'use strict';
+
+ $.jmpress( 'defaults' ).duration = {
+ defaultValue: -1,
+ defaultAction: 'next',
+ barSelector: undefined,
+ barProperty: 'width',
+ barPropertyStart: '0',
+ barPropertyEnd: '100%',
+ };
+ $.jmpress( 'initStep', function( step, eventData ) {
+ eventData.stepData.duration =
+ eventData.data.duration && parseInt( eventData.data.duration, 10 );
+ eventData.stepData.durationAction = eventData.data.durationAction;
+ } );
+ $.jmpress( 'setInactive', function( step, eventData ) {
+ var settings = eventData.settings,
+ durationSettings = settings.duration,
+ current = eventData.current;
+ var dur = eventData.stepData.duration || durationSettings.defaultValue;
+ if ( current.durationTimeout ) {
+ if ( durationSettings.barSelector ) {
+ var css = {
+ transitionProperty: durationSettings.barProperty,
+ transitionDuration: '0',
+ transitionDelay: '0',
+ transitionTimingFunction: 'linear',
+ };
+ css[ durationSettings.barProperty ] = durationSettings.barPropertyStart;
+ var bars = $( durationSettings.barSelector );
+ $.jmpress( 'css', bars, css );
+ bars.each( function( idx, element ) {
+ var next = $( element ).next();
+ var parent = $( element ).parent();
+ $( element ).detach();
+ if ( next.length ) {
+ next.insertBefore( element );
+ } else {
+ parent.append( element );
+ }
+ } );
+ }
+ clearTimeout( current.durationTimeout );
+ delete current.durationTimeout;
+ }
+ } );
+ $.jmpress( 'setActive', function( step, eventData ) {
+ var settings = eventData.settings,
+ durationSettings = settings.duration,
+ current = eventData.current;
+ var dur = eventData.stepData.duration || durationSettings.defaultValue;
+ if ( dur && dur > 0 ) {
+ if ( durationSettings.barSelector ) {
+ var css = {
+ transitionProperty: durationSettings.barProperty,
+ transitionDuration: dur - ( settings.transitionDuration * 2 ) / 3 - 100 + 'ms',
+ transitionDelay: ( settings.transitionDuration * 2 ) / 3 + 'ms',
+ transitionTimingFunction: 'linear',
+ };
+ css[ durationSettings.barProperty ] = durationSettings.barPropertyEnd;
+ $.jmpress( 'css', $( durationSettings.barSelector ), css );
+ }
+ var jmpress = this;
+ if ( current.durationTimeout ) {
+ clearTimeout( current.durationTimeout );
+ current.durationTimeout = undefined;
+ }
+ current.durationTimeout = setTimeout( function() {
+ var action = eventData.stepData.durationAction || durationSettings.defaultAction;
+ $( jmpress ).jmpress( action );
+ }, dur );
+ }
+ } );
+} )( jQuery, document, window );
+
+/*
+ * jmpress.presentation-mode plugin
+ * Display a window for the presenter with notes and a control and view of the
+ * presentation
+ */
+( function( $, document, window, undefined ) {
+ 'use strict';
+ var $jmpress = $.jmpress;
+
+ var PREFIX = 'jmpress-presentation-';
+
+ /* FUNCTIONS */
+ function randomString() {
+ return '' + Math.round( Math.random() * 100000, 0 );
+ }
+
+ /* DEFAULTS */
+ $jmpress( 'defaults' ).presentationMode = {
+ use: true,
+ url: 'presentation-screen.html',
+ notesUrl: false,
+ transferredValues: [ 'userZoom', 'userTranslateX', 'userTranslateY' ],
+ };
+ $jmpress( 'defaults' ).keyboard.keys[ 80 ] = 'presentationPopup'; // p key
+
+ /* HOOKS */
+ $jmpress( 'afterInit', function( nil, eventData ) {
+ var current = eventData.current;
+
+ current.selectMessageListeners = [];
+
+ if ( eventData.settings.presentationMode.use ) {
+ window.addEventListener( 'message', function( event ) {
+ // We do not test orgin, because we want to accept messages
+ // from all orgins
+ try {
+ if ( typeof event.data !== 'string' || event.data.indexOf( PREFIX ) !== 0 ) {
+ return;
+ }
+ var json = JSON.parse( event.data.slice( PREFIX.length ) );
+ switch ( json.type ) {
+ case 'select':
+ $.each( eventData.settings.presentationMode.transferredValues, function( idx, name ) {
+ eventData.current[ name ] = json[ name ];
+ } );
+ if (
+ /[a-z0-9\-]+/i.test( json.targetId ) &&
+ typeof json.substep in { number: 1, undefined: 1 }
+ ) {
+ $( eventData.jmpress ).jmpress(
+ 'select',
+ { step: '#' + json.targetId, substep: json.substep },
+ json.reason
+ );
+ } else {
+ $.error(
+ 'For security reasons the targetId must match /[a-z0-9\\-]+/i and substep must be a number.'
+ );
+ }
+ break;
+ case 'listen':
+ current.selectMessageListeners.push( event.source );
+ break;
+ case 'ok':
+ clearTimeout( current.presentationPopupTimeout );
+ break;
+ case 'read':
+ try {
+ event.source.postMessage(
+ PREFIX +
+ JSON.stringify( {
+ type: 'url',
+ url: window.location.href,
+ notesUrl: eventData.settings.presentationMode.notesUrl,
+ } ),
+ '*'
+ );
+ } catch ( e ) {
+ $.error( 'Cannot post message to source: ' + e );
+ }
+ break;
+ default:
+ throw 'Unknown message type: ' + json.type;
+ }
+ } catch ( e ) {
+ $.error( 'Received message is malformed: ' + e );
+ }
+ } );
+ try {
+ if ( window.parent && window.parent !== window ) {
+ window.parent.postMessage(
+ PREFIX +
+ JSON.stringify( {
+ type: 'afterInit',
+ } ),
+ '*'
+ );
+ }
+ } catch ( e ) {
+ $.error( 'Cannot post message to parent: ' + e );
+ }
+ }
+ } );
+ $jmpress( 'afterDeinit', function( nil, eventData ) {
+ if ( eventData.settings.presentationMode.use ) {
+ try {
+ if ( window.parent && window.parent !== window ) {
+ window.parent.postMessage(
+ PREFIX +
+ JSON.stringify( {
+ type: 'afterDeinit',
+ } ),
+ '*'
+ );
+ }
+ } catch ( e ) {
+ $.error( 'Cannot post message to parent: ' + e );
+ }
+ }
+ } );
+ $jmpress( 'setActive', function( step, eventData ) {
+ var stepId = $( eventData.delegatedFrom ).attr( 'id' ),
+ substep = eventData.substep,
+ reason = eventData.reason;
+ $.each( eventData.current.selectMessageListeners, function( idx, listener ) {
+ try {
+ var msg = {
+ type: 'select',
+ targetId: stepId,
+ substep: substep,
+ reason: reason,
+ };
+ $.each( eventData.settings.presentationMode.transferredValues, function( idx, name ) {
+ msg[ name ] = eventData.current[ name ];
+ } );
+ listener.postMessage( PREFIX + JSON.stringify( msg ), '*' );
+ } catch ( e ) {
+ $.error( 'Cannot post message to listener: ' + e );
+ }
+ } );
+ } );
+ $jmpress( 'register', 'presentationPopup', function() {
+ function trySend() {
+ jmpress.jmpress( 'current' ).presentationPopupTimeout = setTimeout( trySend, 100 );
+ try {
+ popup.postMessage(
+ PREFIX +
+ JSON.stringify( {
+ type: 'url',
+ url: window.location.href,
+ notesUrl: jmpress.jmpress( 'settings' ).presentationMode.notesUrl,
+ } ),
+ '*'
+ );
+ } catch ( e ) {}
+ }
+ var jmpress = $( this ),
+ popup;
+ if ( jmpress.jmpress( 'settings' ).presentationMode.use ) {
+ popup = window.open( $( this ).jmpress( 'settings' ).presentationMode.url );
+ jmpress.jmpress( 'current' ).presentationPopupTimeout = setTimeout( trySend, 100 );
+ }
+ } );
+} )( jQuery, document, window );