2870 lines
79 KiB
JavaScript
2870 lines
79 KiB
JavaScript
/**
|
|
* 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' ](); // eslint-disable-line no-unexpected-multiline
|
|
}
|
|
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 );
|