You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

611 lines
18 KiB

/**
*
* jPanelMenu 1.3.0 CSS Transform Build (http://jpanelmenu.com)
* By Anthony Colangelo (http://acolangelo.com)
*
* */
(function($){
$.jPanelMenu = function(options) {
if ( typeof(options) == "undefined" || options == null ) { options = {}; };
var jP = {
options: $.extend({
menu: '#menu',
trigger: '.menu-trigger',
excludedPanelContent: 'style, script',
direction: 'left',
openPosition: '250px',
animated: true,
closeOnContentClick: true,
keyboardShortcuts: [
{
code: 27,
open: false,
close: true
},
{
code: 37,
open: false,
close: true
},
{
code: 39,
open: true,
close: true
},
{
code: 77,
open: true,
close: true
}
],
duration: 150,
openDuration: options.duration || 150,
closeDuration: options.duration || 150,
easing: 'ease-in-out',
openEasing: options.easing || 'ease-in-out',
closeEasing: options.easing || 'ease-in-out',
before: function(){ },
beforeOpen: function(){ },
beforeClose: function(){ },
after: function(){ },
afterOpen: function(){ },
afterClose: function(){ },
beforeOn: function(){ },
afterOn: function(){ },
beforeOff: function(){ },
afterOff: function(){ }
},options),
settings: {
transitionsSupported: 'WebkitTransition' in document.body.style ||
'MozTransition' in document.body.style ||
'msTransition' in document.body.style ||
'OTransition' in document.body.style ||
'Transition' in document.body.style
,
transformsSupported: 'WebkitTransform' in document.body.style ||
'MozTransform' in document.body.style ||
'msTransform' in document.body.style ||
'OTransform' in document.body.style ||
'Transform' in document.body.style
,
cssPrefix: '',
shiftFixedChildren: false,
panelPosition: 'relative',
positionUnits: 'px'
},
menu: '#jPanelMenu-menu',
panel: '.jPanelMenu-panel',
fixedChildren: [],
timeouts: {},
clearTimeouts: function() {
clearTimeout(jP.timeouts.open);
clearTimeout(jP.timeouts.afterOpen);
clearTimeout(jP.timeouts.afterClose);
},
setPositionUnits: function() {
var foundUnit = false,
allowedUnits = ['%','px','em']
;
for ( unitID in allowedUnits ) {
var unit = allowedUnits[unitID];
if ( jP.options.openPosition.toString().substr(-unit.length) == unit )
{
foundUnit = true;
jP.settings.positionUnits = unit;
}
}
if ( !foundUnit ) { jP.options.openPosition = parseInt(jP.options.openPosition) + jP.settings.positionUnits }
},
computePositionStyle: function(open, string) {
var position = (open)?jP.options.openPosition:'0' + jP.settings.positionUnits;
var property = {};
if ( jP.settings.transformsSupported ) {
var direction = (open && jP.options.direction == 'right')?'-':'';
var translate = 'translate3d(' + direction + position + ',0,0)';
var transform = 'transform';
if ( string ) {
property = '';
if ( jP.settings.cssPrefix != '' ) { property = jP.settings.cssPrefix + transform + ':' + translate + ';' }
property += transform + ':' + translate + ';';
} else {
if ( jP.settings.cssPrefix != '' ) { property[jP.settings.cssPrefix + transform] = translate; }
property[transform] = translate;
}
} else {
if ( string ) {
property = '';
property = jP.options.direction + ': ' + position + ';';
} else {
property[jP.options.direction] = position;
}
}
return property;
},
setCSSPrefix: function() {
jP.settings.cssPrefix = jP.getCSSPrefix();
},
checkFixedChildren: function() {
jP.disableTransitions();
var defaultPanelStyle = { position: $(jP.panel).css('position') };
defaultPanelStyle[jP.options.direction] = ($(jP.panel).css(jP.options.direction) == 'auto')?0:$(jP.panel).css(jP.options.direction);
$(jP.panel).find('> *').each(function(){
if ( $(this).css('position') == 'fixed' && $(this).css(jP.options.direction) == 'auto' ) { jP.fixedChildren.push(this); }
});
if ( jP.fixedChildren.length > 0 )
{
var newPanelStyle = { position: 'relative' };
newPanelStyle[jP.options.direction] = '1px';
jP.setPanelStyle(newPanelStyle);
if ( parseInt($(jP.fixedChildren[0]).offset().left) == 0 ) { jP.settings.shiftFixedChildren = true; }
}
jP.setPanelStyle(defaultPanelStyle);
},
setjPanelMenuStyles: function() {
var bgColor = '#fff';
var htmlBG = $('html').css('background-color');
var bodyBG = $('body').css('background-color');
if ( bodyBG != 'transparent' && bodyBG != "rgba(0, 0, 0, 0)") { bgColor = bodyBG; }
else if ( htmlBG != 'transparent' && htmlBG != "rgba(0, 0, 0, 0)") { bgColor = htmlBG; }
else { bgColor = '#fff'; }
if ( $('#jPanelMenu-style-master').length == 0 )
{
$('body').append('<style id="jPanelMenu-style-master">body{width:100%}.jPanelMenu,body{overflow-x:hidden}#jPanelMenu-menu{display:block;position:fixed;top:0;'+jP.options.direction+':0;height:100%;z-index:-1;overflow-x:hidden;overflow-y:scroll;-webkit-overflow-scrolling:touch}.jPanelMenu-panel{position:static;'+jP.computePositionStyle(false,true)+'z-index:2;width:100%;min-height:100%;background:' + bgColor + '}</style>');
}
},
setMenuState: function(open) {
var position = (open)?'open':'closed';
$('body').attr('data-menu-position', position);
},
getMenuState: function() {
return $('body').attr('data-menu-position');
},
menuIsOpen: function() {
if ( jP.getMenuState() == 'open' ) return true;
else return false;
},
setMenuStyle: function(styles) {
$(jP.menu).css(styles);
},
setPanelStyle: function(styles) {
$(jP.panel).css(styles);
},
showMenu: function() {
jP.setMenuStyle({
display: 'block'
});
jP.setMenuStyle({
'z-index': '1'
});
},
hideMenu: function() {
jP.setMenuStyle({
'z-index': '-1'
});
jP.setMenuStyle({
display: 'none'
});
},
enableTransitions: function(duration, easing) {
var formattedDuration = duration/1000;
var formattedEasing = jP.getCSSEasingFunction(easing);
jP.disableTransitions();
$('body').append('<style id="jPanelMenu-style-transitions">.jPanelMenu-panel{' + jP.settings.cssPrefix + 'transition: all ' + formattedDuration + 's ' + formattedEasing + '; transition: all ' + formattedDuration + 's ' + formattedEasing + ';}</style>');
},
disableTransitions: function() {
$('#jPanelMenu-style-transitions').remove();
},
enableFixedTransitions: function(selector, id, duration, easing) {
var formattedDuration = duration/1000;
var formattedEasing = jP.getCSSEasingFunction(easing);
jP.disableFixedTransitions(id);
$('body').append('<style id="jPanelMenu-style-fixed-' + id + '">' + selector + '{' + jP.settings.cssPrefix + 'transition: all ' + formattedDuration + 's ' + formattedEasing + '; transition: all ' + formattedDuration + 's ' + formattedEasing + ';}</style>');
},
disableFixedTransitions: function(id) {
$('#jPanelMenu-style-fixed-' + id).remove();
},
getCSSEasingFunction: function(name) {
switch ( name )
{
case 'linear':
return name;
break;
case 'ease':
return name;
break;
case 'ease-in':
return name;
break;
case 'ease-out':
return name;
break;
case 'ease-in-out':
return name;
break;
default:
return 'ease-in-out';
break;
}
},
getJSEasingFunction: function(name) {
switch ( name )
{
case 'linear':
return name;
break;
default:
return 'swing';
break;
}
},
getVendorPrefix: function() {
// Thanks to Lea Verou for this beautiful function. (http://lea.verou.me/2009/02/find-the-vendor-prefix-of-the-current-browser)
if('result' in arguments.callee) return arguments.callee.result;
var regex = /^(Moz|Webkit|Khtml|O|ms|Icab)(?=[A-Z])/;
var someScript = document.getElementsByTagName('script')[0];
for(var prop in someScript.style)
{
if(regex.test(prop))
{
// test is faster than match, so it's better to perform
// that on the lot and match only when necessary
return arguments.callee.result = prop.match(regex)[0];
}
}
// Nothing found so far? Webkit does not enumerate over the CSS properties of the style object.
// However (prop in style) returns the correct value, so we'll have to test for
// the precence of a specific property
if('WebkitOpacity' in someScript.style) return arguments.callee.result = 'Webkit';
if('KhtmlOpacity' in someScript.style) return arguments.callee.result = 'Khtml';
return arguments.callee.result = '';
},
getCSSPrefix: function() {
var prefix = jP.getVendorPrefix();
if ( prefix != '' ) { return '-' + prefix.toLowerCase() + '-'; }
return '';
},
openMenu: function(animated) {
if ( typeof(animated) == "undefined" || animated == null ) { animated = jP.options.animated };
jP.clearTimeouts();
jP.options.before();
jP.options.beforeOpen();
jP.setMenuState(true);
jP.setPanelStyle({ position: 'relative' });
jP.showMenu();
var animationChecks = {
none: (!animated)?true:false,
transitions: (animated && jP.settings.transitionsSupported)?true:false
};
if ( animationChecks.transitions || animationChecks.none ) {
if ( animationChecks.none ) jP.disableTransitions();
if ( animationChecks.transitions ) jP.enableTransitions(jP.options.openDuration, jP.options.openEasing);
var newPanelStyle = jP.computePositionStyle(true);
jP.setPanelStyle(newPanelStyle);
if ( jP.settings.shiftFixedChildren ) {
$(jP.fixedChildren).each(function(){
var id = $(this).prop("tagName").toLowerCase() + ' ' + $(this).attr('class'),
selector = id.replace(' ','.'),
id = id.replace(' ','-')
;
if ( animationChecks.none ) jP.disableFixedTransitions(id);
if ( animationChecks.transitions ) jP.enableFixedTransitions(selector, id, jP.options.openDuration, jP.options.openEasing);
var newChildrenStyle = {};
newChildrenStyle[jP.options.direction] = jP.options.openPosition;
$(this).css(newChildrenStyle);
});
}
jP.timeouts.afterOpen = setTimeout(function(){
jP.disableTransitions();
if ( jP.settings.shiftFixedChildren ) {
$(jP.fixedChildren).each(function(){
var id = $(this).prop("tagName").toLowerCase() + ' ' + $(this).attr('class'),
id = id.replace(' ','-')
;
jP.disableFixedTransitions(id);
});
}
jP.options.after();
jP.options.afterOpen();
jP.initiateContentClickListeners();
}, jP.options.openDuration);
}
else {
var formattedEasing = jP.getJSEasingFunction(jP.options.openEasing);
var animationOptions = {};
animationOptions[jP.options.direction] = jP.options.openPosition;
$(jP.panel).stop().animate(animationOptions, jP.options.openDuration, formattedEasing, function(){
jP.options.after();
jP.options.afterOpen();
jP.initiateContentClickListeners();
});
if ( jP.settings.shiftFixedChildren ) {
$(jP.fixedChildren).each(function(){
var childrenAnimationOptions = {};
childrenAnimationOptions[jP.options.direction] = jP.options.openPosition;
$(this).stop().animate(childrenAnimationOptions, jP.options.openDuration, formattedEasing);
});
}
}
},
closeMenu: function(animated) {
if ( typeof(animated) == "undefined" || animated == null ) { animated = jP.options.animated };
jP.clearTimeouts();
jP.options.before();
jP.options.beforeClose();
jP.setMenuState(false);
var animationChecks = {
none: (!animated)?true:false,
transitions: (animated && jP.settings.transitionsSupported)?true:false
};
if ( animationChecks.transitions || animationChecks.none ) {
if ( animationChecks.none ) jP.disableTransitions();
if ( animationChecks.transitions ) jP.enableTransitions(jP.options.closeDuration, jP.options.closeEasing);
var newPanelStyle = jP.computePositionStyle();
jP.setPanelStyle(newPanelStyle);
if ( jP.settings.shiftFixedChildren ) {
$(jP.fixedChildren).each(function(){
var id = $(this).prop("tagName").toLowerCase() + ' ' + $(this).attr('class'),
selector = id.replace(' ','.'),
id = id.replace(' ','-')
;
if ( animationChecks.none ) jP.disableFixedTransitions(id);
if ( animationChecks.transitions ) jP.enableFixedTransitions(selector, id, jP.options.closeDuration, jP.options.closeEasing);
var newChildrenStyle = {};
newChildrenStyle[jP.options.direction] = 0 + jP.settings.positionUnits;
$(this).css(newChildrenStyle);
});
}
jP.timeouts.afterClose = setTimeout(function(){
jP.setPanelStyle({ position: jP.settings.panelPosition });
jP.disableTransitions();
if ( jP.settings.shiftFixedChildren ) {
$(jP.fixedChildren).each(function(){
var id = $(this).prop("tagName").toLowerCase() + ' ' + $(this).attr('class'),
id = id.replace(' ','-')
;
jP.disableFixedTransitions(id);
});
}
jP.hideMenu();
jP.options.after();
jP.options.afterClose();
jP.destroyContentClickListeners();
}, jP.options.closeDuration);
}
else {
var formattedEasing = jP.getJSEasingFunction(jP.options.closeEasing);
var animationOptions = {};
animationOptions[jP.options.direction] = 0 + jP.settings.positionUnits;
$(jP.panel).stop().animate(animationOptions, jP.options.closeDuration, formattedEasing, function(){
jP.setPanelStyle({ position: jP.settings.panelPosition });
jP.hideMenu();
jP.options.after();
jP.options.afterClose();
jP.destroyContentClickListeners();
});
if ( jP.settings.shiftFixedChildren ) {
$(jP.fixedChildren).each(function(){
var childrenAnimationOptions = {};
childrenAnimationOptions[jP.options.direction] = 0 + jP.settings.positionUnits;
$(this).stop().animate(childrenAnimationOptions, jP.options.closeDuration, formattedEasing);
});
}
}
},
triggerMenu: function(animated) {
if ( jP.menuIsOpen() ) jP.closeMenu(animated);
else jP.openMenu(animated);
},
initiateClickListeners: function() {
$(document).on('click',jP.options.trigger,function(){ jP.triggerMenu(jP.options.animated); return false; });
},
destroyClickListeners: function() {
$(document).off('click',jP.options.trigger,null);
},
initiateContentClickListeners: function() {
if ( !jP.options.closeOnContentClick ) return false;
$(document).on('click',jP.panel,function(e){
if ( jP.menuIsOpen() ) jP.closeMenu(jP.options.animated);
});
$(document).on('touchend',jP.panel,function(e){
if ( jP.menuIsOpen() ) jP.closeMenu(jP.options.animated);
});
},
destroyContentClickListeners: function() {
if ( !jP.options.closeOnContentClick ) return false;
$(document).off('click',jP.panel,null);
$(document).off('touchend',jP.panel,null);
},
initiateKeyboardListeners: function() {
var preventKeyListeners = ['input', 'textarea'];
$(document).on('keydown',function(e){
var target = $(e.target),
prevent = false;
$.each(preventKeyListeners, function(){
if (target.is(this.toString())) { prevent = true; }
});
if ( prevent ) { return true; }
for ( mapping in jP.options.keyboardShortcuts ) {
if ( e.which == jP.options.keyboardShortcuts[mapping].code ) {
var key = jP.options.keyboardShortcuts[mapping];
if ( key.open && key.close ) { jP.triggerMenu(jP.options.animated); }
else if ( (key.open && !key.close) && !jP.menuIsOpen() ) { jP.openMenu(jP.options.animated); }
else if ( (!key.open && key.close) && jP.menuIsOpen() ) { jP.closeMenu(jP.options.animated); }
return false;
}
}
});
},
destroyKeyboardListeners: function() {
$(document).off('keydown',null);
},
setupMarkup: function() {
$('html').addClass('jPanelMenu');
$('body > *').not(jP.menu + ', ' + jP.options.excludedPanelContent).wrapAll('<div class="' + jP.panel.replace('.','') + '"/>');
$(jP.options.menu).clone().attr('id', jP.menu.replace('#','')).insertAfter('body > ' + jP.panel);
},
resetMarkup: function() {
$('html').removeClass('jPanelMenu');
$('body > ' + jP.panel + ' > *').unwrap();
$(jP.menu).remove();
},
init: function() {
jP.options.beforeOn();
jP.setPositionUnits();
jP.setCSSPrefix();
jP.initiateClickListeners();
if ( Object.prototype.toString.call(jP.options.keyboardShortcuts) === '[object Array]' ) { jP.initiateKeyboardListeners(); }
jP.setjPanelMenuStyles();
jP.setMenuState(false);
jP.setupMarkup();
jP.setMenuStyle({ width: jP.options.openPosition });
if ( !jP.settings.transformsSupported ) { jP.checkFixedChildren(); }
jP.closeMenu(false);
jP.options.afterOn();
},
destroy: function() {
jP.options.beforeOff();
jP.closeMenu();
jP.destroyClickListeners();
if ( Object.prototype.toString.call(jP.options.keyboardShortcuts) === '[object Array]' ) { jP.destroyKeyboardListeners(); }
jP.resetMarkup();
var childrenStyles = {};
childrenStyles[jP.options.direction] = 'auto';
$(jP.fixedChildren).each(function(){ $(this).css(childrenStyles); });
jP.fixedChildren = [];
jP.options.afterOff();
}
};
return {
on: jP.init,
off: jP.destroy,
trigger: jP.triggerMenu,
open: jP.openMenu,
close: jP.closeMenu,
isOpen: jP.menuIsOpen,
menu: jP.menu,
getMenu: function() { return $(jP.menu); },
panel: jP.panel,
getPanel: function() { return $(jP.panel); }
};
};
})(jQuery);