/**
* @private
* Base class for iOS and Android viewports.
*/
Ext.define('Ext.viewport.Default', {
extend: 'Ext.Container',
xtype: 'viewport',
PORTRAIT: 'portrait',
LANDSCAPE: 'landscape',
requires: [
'Ext.LoadMask',
'Ext.layout.Card',
'Ext.util.InputBlocker'
],
/**
* @event ready
* Fires when the Viewport is in the DOM and ready.
* @param {Ext.Viewport} this
*/
/**
* @event maximize
* Fires when the Viewport is maximized.
* @param {Ext.Viewport} this
*/
/**
* @event orientationchange
* Fires when the Viewport orientation has changed.
* @param {Ext.Viewport} this
* @param {String} newOrientation The new orientation.
* @param {Number} width The width of the Viewport.
* @param {Number} height The height of the Viewport.
*/
config: {
/**
* @cfg {Boolean} autoMaximize
* Whether or not to always automatically maximize the viewport on first load and all subsequent orientation changes.
*
* This is set to `false` by default for a number of reasons:
*
* - Orientation change performance is drastically reduced when this is enabled, on all devices.
* - On some devices (mostly Android) this can sometimes cause issues when the default browser zoom setting is changed.
* - When wrapping your phone in a native shell, you may get a blank screen.
* - When bookmarked to the homescreen (iOS), you may get a blank screen.
*
* @accessor
*/
autoMaximize: false,
/**
* @private
*/
autoBlurInput: true,
/**
* @cfg {Boolean} preventPanning
* Whether or not to always prevent default panning behavior of the
* browser's viewport.
* @accessor
*/
preventPanning: true,
/**
* @cfg {Boolean} preventZooming
* `true` to attempt to stop zooming when you double tap on the screen on mobile devices,
* typically HTC devices with HTC Sense UI.
* @accessor
*/
preventZooming: false,
/**
* @cfg
* @private
*/
autoRender: true,
/**
* @cfg {Object/String} layout Configuration for this Container's layout. Example:
*
* Ext.create('Ext.Container', {
* layout: {
* type: 'hbox',
* align: 'middle'
* },
* items: [
* {
* xtype: 'panel',
* flex: 1,
* style: 'background-color: red;'
* },
* {
* xtype: 'panel',
* flex: 2,
* style: 'background-color: green'
* }
* ]
* });
*
* See the [layouts guide](#!/guides/layouts) for more information.
*
* @accessor
*/
layout: 'card',
/**
* @cfg
* @private
*/
width: '100%',
/**
* @cfg
* @private
*/
height: '100%',
useBodyElement: true,
* An object of all the menus on this viewport.
* @private
*/
menus: {}
},
/**
* @property {Boolean} isReady
* `true` if the DOM is ready.
*/
isReady: false,
isViewport: true,
isMaximizing: false,
id: 'ext-viewport',
isInputRegex: /^(input|textarea|select|a)$/i,
focusedElement: null,
/**
* @private
*/
fullscreenItemCls: Ext.baseCSSPrefix + 'fullscreen',
constructor: function(config) {
var bind = Ext.Function.bind;
this.doPreventPanning = bind(this.doPreventPanning, this);
this.doPreventZooming = bind(this.doPreventZooming, this);
this.doBlurInput = bind(this.doBlurInput, this);
this.maximizeOnEvents = [
'ready',
'orientationchange'
];
// set default devicePixelRatio if it is not explicitly defined
window.devicePixelRatio = window.devicePixelRatio || 1;
this.callSuper([config]);
this.orientation = this.determineOrientation();
this.windowWidth = this.getWindowWidth();
this.windowHeight = this.getWindowHeight();
this.windowOuterHeight = this.getWindowOuterHeight();
if (!this.stretchHeights) {
this.stretchHeights = {};
}
// Android is handled separately
if (!Ext.os.is.Android || Ext.browser.is.ChromeMobile) {
if (this.supportsOrientation()) {
this.addWindowListener('orientationchange', bind(this.onOrientationChange, this));
}
else {
this.addWindowListener('resize', bind(this.onResize, this));
}
}
document.addEventListener('focus', bind(this.onElementFocus, this), true);
document.addEventListener('blur', bind(this.onElementBlur, this), true);
Ext.onDocumentReady(this.onDomReady, this);
this.on('ready', this.onReady, this, {single: true});
this.getEventDispatcher().addListener('component', '*', 'fullscreen', 'onItemFullscreenChange', this);
return this;
},
onDomReady: function() {
this.isReady = true;
this.updateSize();
this.fireEvent('ready', this);
},
onReady: function() {
if (this.getAutoRender()) {
this.render();
}
if (Ext.browser.name == 'ChromeiOS') {
this.setHeight('-webkit-calc(100% - ' + ((window.outerHeight - window.innerHeight) / 2) + 'px)');
}
},
onElementFocus: function(e) {
this.focusedElement = e.target;
},
onElementBlur: function() {
this.focusedElement = null;
},
render: function() {
if (!this.rendered) {
var body = Ext.getBody(),
clsPrefix = Ext.baseCSSPrefix,
classList = [],
osEnv = Ext.os,
osName = osEnv.name.toLowerCase(),
browserName = Ext.browser.name.toLowerCase(),
osMajorVersion = osEnv.version.getMajor(),
orientation = this.getOrientation();
this.renderTo(body);
classList.push(clsPrefix + osEnv.deviceType.toLowerCase());
if (osEnv.is.iPad) {
classList.push(clsPrefix + 'ipad');
}
classList.push(clsPrefix + osName);
classList.push(clsPrefix + browserName);
if (osMajorVersion) {
classList.push(clsPrefix + osName + '-' + osMajorVersion);
}
if (osEnv.is.BlackBerry) {
classList.push(clsPrefix + 'bb');
if (Ext.browser.userAgent.match(/Kbd/gi)) {
classList.push(clsPrefix + 'bb-keyboard');
}
}
if (Ext.browser.is.WebKit) {
classList.push(clsPrefix + 'webkit');
}
if (Ext.browser.is.Standalone) {
classList.push(clsPrefix + 'standalone');
}
if (Ext.browser.is.AndroidStock) {
classList.push(clsPrefix + 'android-stock');
}
if (Ext.browser.is.GoogleGlass) {
classList.push(clsPrefix + 'google-glass');
}
classList.push(clsPrefix + orientation);
body.addCls(classList);
}
},
applyAutoBlurInput: function(autoBlurInput) {
var touchstart = (Ext.feature.has.Touch) ? 'touchstart' : 'mousedown';
if (autoBlurInput) {
this.addWindowListener(touchstart, this.doBlurInput, false);
}
else {
this.removeWindowListener(touchstart, this.doBlurInput, false);
}
return autoBlurInput;
},
applyAutoMaximize: function(autoMaximize) {
if (Ext.browser.is.WebView) {
autoMaximize = false;
}
if (autoMaximize) {
this.on('ready', 'doAutoMaximizeOnReady', this, { single: true });
this.on('orientationchange', 'doAutoMaximizeOnOrientationChange', this);
}
else {
this.un('ready', 'doAutoMaximizeOnReady', this);
this.un('orientationchange', 'doAutoMaximizeOnOrientationChange', this);
}
return autoMaximize;
},
applyPreventPanning: function(preventPanning) {
if (preventPanning) {
this.addWindowListener('touchmove', this.doPreventPanning, false);
}
else {
this.removeWindowListener('touchmove', this.doPreventPanning, false);
}
return preventPanning;
},
applyPreventZooming: function(preventZooming) {
var touchstart = (Ext.feature.has.Touch) ? 'touchstart' : 'mousedown';
if (preventZooming) {
this.addWindowListener(touchstart, this.doPreventZooming, false);
}
else {
this.removeWindowListener(touchstart, this.doPreventZooming, false);
}
return preventZooming;
},
doAutoMaximizeOnReady: function() {
var controller = arguments[arguments.length - 1];
controller.pause();
this.isMaximizing = true;
this.on('maximize', function() {
this.isMaximizing = false;
this.updateSize();
controller.resume();
this.fireEvent('ready', this);
}, this, { single: true });
this.maximize();
},
doAutoMaximizeOnOrientationChange: function() {
var controller = arguments[arguments.length - 1],
firingArguments = controller.firingArguments;
controller.pause();
this.isMaximizing = true;
this.on('maximize', function() {
this.isMaximizing = false;
this.updateSize();
firingArguments[2] = this.windowWidth;
firingArguments[3] = this.windowHeight;
controller.resume();
}, this, { single: true });
this.maximize();
},
doBlurInput: function(e) {
var target = e.target,
focusedElement = this.focusedElement;
//In IE9/10 browser window loses focus and becomes inactive if focused element is <body>. So we shouldn't call blur for <body>
if (focusedElement && focusedElement.nodeName.toUpperCase() != 'BODY' && !this.isInputRegex.test(target.tagName)) {
delete this.focusedElement;
focusedElement.blur();
}
},
doPreventPanning: function(e) {
e.preventDefault();
},
doPreventZooming: function(e) {
// Don't prevent right mouse event
if ('button' in e && e.button !== 0) {
return;
}
var target = e.target;
if (target && target.nodeType === 1 && !this.isInputRegex.test(target.tagName)) {
e.preventDefault();
}
},
addWindowListener: function(eventName, fn, capturing) {
window.addEventListener(eventName, fn, Boolean(capturing));
},
removeWindowListener: function(eventName, fn, capturing) {
window.removeEventListener(eventName, fn, Boolean(capturing));
},
doAddListener: function(eventName, fn, scope, options) {
if (eventName === 'ready' && this.isReady && !this.isMaximizing) {
fn.call(scope);
return this;
}
return this.callSuper(arguments);
},
supportsOrientation: function() {
return Ext.feature.has.Orientation;
},
onResize: function() {
var oldWidth = this.windowWidth,
oldHeight = this.windowHeight,
width = this.getWindowWidth(),
height = this.getWindowHeight(),
currentOrientation = this.getOrientation(),
newOrientation = this.determineOrientation();
// Determine orientation change via resize. BOTH width AND height much change, otherwise
// this is a keyboard popping up.
if ((oldWidth !== width && oldHeight !== height) && currentOrientation !== newOrientation) {
this.fireOrientationChangeEvent(newOrientation, currentOrientation);
}
},
onOrientationChange: function() {
var currentOrientation = this.getOrientation(),
newOrientation = this.determineOrientation();
if (newOrientation !== currentOrientation) {
this.fireOrientationChangeEvent(newOrientation, currentOrientation);
}
},
fireOrientationChangeEvent: function(newOrientation, oldOrientation) {
var clsPrefix = Ext.baseCSSPrefix;
Ext.getBody().replaceCls(clsPrefix + oldOrientation, clsPrefix + newOrientation);
this.orientation = newOrientation;
this.updateSize();
this.fireEvent('orientationchange', this, newOrientation, this.windowWidth, this.windowHeight);
},
updateSize: function(width, height) {
this.windowWidth = width !== undefined ? width : this.getWindowWidth();
this.windowHeight = height !== undefined ? height : this.getWindowHeight();
return this;
},
waitUntil: function(condition, onSatisfied, onTimeout, delay, timeoutDuration) {
if (!delay) {
delay = 50;
}
if (!timeoutDuration) {
timeoutDuration = 2000;
}
var scope = this,
elapse = 0;
setTimeout(function repeat() {
elapse += delay;
if (condition.call(scope) === true) {
if (onSatisfied) {
onSatisfied.call(scope);
}
}
else {
if (elapse >= timeoutDuration) {
if (onTimeout) {
onTimeout.call(scope);
}
}
else {
setTimeout(repeat, delay);
}
}
}, delay);
},
maximize: function() {
this.fireMaximizeEvent();
},
fireMaximizeEvent: function() {
this.updateSize();
this.fireEvent('maximize', this);
},
doSetHeight: function(height) {
Ext.getBody().setHeight(height);
this.callParent(arguments);
},
doSetWidth: function(width) {
Ext.getBody().setWidth(width);
this.callParent(arguments);
},
scrollToTop: function() {
window.scrollTo(0, -1);
},
/**
* Retrieves the document width.
* @return {Number} width in pixels.
*/
getWindowWidth: function() {
return window.innerWidth;
},
/**
* Retrieves the document height.
* @return {Number} height in pixels.
*/
getWindowHeight: function() {
return window.innerHeight;
},
getWindowOuterHeight: function() {
return window.outerHeight;
},
getWindowOrientation: function() {
return window.orientation;
},
/**
* Returns the current orientation.
* @return {String} `portrait` or `landscape`
*/
getOrientation: function() {
return this.orientation;
},
getSize: function() {
return {
width: this.windowWidth,
height: this.windowHeight
};
},
determineOrientation: function() {
var portrait = this.PORTRAIT,
landscape = this.LANDSCAPE;
if (!Ext.os.is.Android && this.supportsOrientation()) {
if (this.getWindowOrientation() % 180 === 0) {
return portrait;
}
return landscape;
}
else {
if (this.getWindowHeight() >= this.getWindowWidth()) {
return portrait;
}
return landscape;
}
},
onItemFullscreenChange: function(item) {
item.addCls(this.fullscreenItemCls);
this.add(item);
},
* Sets a menu for a given side of the Viewport.
*
* Adds functionality to show the menu by swiping from the side of the screen from the given side.
*
* If a menu is already set for a given side, it will be removed.
*
* Available sides are: `left`, `right`, `top`, and `bottom`.
*
* @param {Ext.Menu} menu The menu to assign to the viewport
* @param {Object} config The configuration for the menu.
* @param {String} config.side The side to put the menu on.
* @param {Boolean} config.cover True to cover the viewport content. Defaults to `true`.
*/
setMenu: function(menu, config) {
var me = this;
config = config || {};
// Temporary workaround for body shifting issue
if (Ext.os.is.iOS && !this.hasiOSOrientationFix) {
this.hasiOSOrientationFix = true;
this.on('orientationchange', function() {
window.scrollTo(0, 0);
}, this);
}
if (!menu) {
//<debug error>
Ext.Logger.error("You must specify a side to dock the menu.");
//</debug>
return;
}
if (!config.side) {
//<debug error>
Ext.Logger.error("You must specify a side to dock the menu.");
//</debug>
return;
}
if (['left', 'right', 'top', 'bottom'].indexOf(config.side) == -1) {
//<debug error>
Ext.Logger.error("You must specify a valid side (left, right, top or botom) to dock the menu.");
//</debug>
return;
}
var menus = me.getMenus();
if (!menus) {
menus = {};
}
// Add a listener to show this menu on swipe
if (!me.addedSwipeListener) {
me.addedSwipeListener = true;
me.element.on({
tap: me.onTap,
swipestart: me.onSwipeStart,
edgeswipestart: me.onEdgeSwipeStart,
edgeswipe: me.onEdgeSwipe,
edgeswipeend: me.onEdgeSwipeEnd,
scope: me
});
// Add BB10 webworks API for swipe down.
if (window.blackberry) {
var toggleMenu = function() {
var menus = me.getMenus(),
menu = menus['top'];
if (!menu) {
return;
}
if (menu.isHidden()) {
me.showMenu('top');
} else {
me.hideMenu('top');
}
};
if (blackberry.app && blackberry.app.event && blackberry.app.event.onSwipeDown) {
blackberry.app.event.onSwipeDown(toggleMenu); // PlayBook
}
else if (blackberry.event && blackberry.event.addEventListener) {
blackberry.event.addEventListener("swipedown", toggleMenu); // BB10
}
}
}
menus[config.side] = menu;
menu.$reveal = Boolean(config.reveal);
menu.$cover = config.cover !== false && !menu.$reveal;
menu.$side = config.side;
me.fixMenuSize(menu, config.side);
if (config.side == 'left') {
menu.setLeft(0);
menu.setRight(null);
menu.setTop(0);
menu.setBottom(0);
}
else if (config.side == 'right') {
menu.setLeft(null);
menu.setRight(0);
menu.setTop(0);
menu.setBottom(0);
}
else if (config.side == 'top') {
menu.setLeft(0);
menu.setRight(0);
menu.setTop(0);
menu.setBottom(null);
}
else if (config.side == 'bottom') {
menu.setLeft(0);
menu.setRight(0);
menu.setTop(null);
menu.setBottom(0);
}
me.setMenus(menus);
},
* Removes a menu from a specified side.
* @param {String} side The side to remove the menu from
*/
removeMenu: function(side) {
var menus = this.getMenus() || {},
menu = menus[side];
if(menu) this.hideMenu(side);
delete menus[side];
this.setMenus(menus);
},
* @private
* Changes the sizing of the specified menu so that it displays correctly when shown.
*/
fixMenuSize: function(menu, side) {
if (side == 'top' || side == 'bottom') {
menu.setWidth('100%');
}
else if (side == 'left' || side == 'right') {
menu.setHeight('100%');
}
},
* Shows a menu specified by the menu's side.
* @param {String} side The side which the menu is placed.
*/
showMenu: function(side) {
var menus = this.getMenus(),
menu = menus[side],
before, after,
viewportBefore, viewportAfter;
if (!menu || menu.isAnimating) {
return;
}
this.hideOtherMenus(side);
before = {
translateX: 0,
translateY: 0
};
after = {
translateX: 0,
translateY: 0
};
viewportBefore = {
translateX: 0,
translateY: 0
};
viewportAfter = {
translateX: 0,
translateY: 0
};
if (menu.$reveal) {
Ext.getBody().insertFirst(menu.element);
}
else {
Ext.Viewport.add(menu);
}
menu.show();
menu.addCls('x-' + side);
var size = (side == 'left' || side == 'right') ? menu.element.getWidth() : menu.element.getHeight();
if (side == 'left') {
before.translateX = -size;
viewportAfter.translateX = size;
}
else if (side == 'right') {
before.translateX = size;
viewportAfter.translateX = -size;
}
else if (side == 'top') {
before.translateY = -size;
viewportAfter.translateY = size;
}
else if (side == 'bottom') {
before.translateY = size;
viewportAfter.translateY = -size;
}
if (menu.$reveal) {
if (Ext.browser.getPreferredTranslationMethod() != 'scrollposition') {
menu.translate(0, 0);
}
}
else {
menu.translate(before.translateX, before.translateY);
}
if (menu.$cover) {
menu.getTranslatable().on('animationend', function() {
menu.isAnimating = false;
}, this, {
single: true
});
menu.translate(after.translateX, after.translateY, {
preserveEndState: true,
duration: 200
});
}
else {
this.translate(viewportBefore.translateX, viewportBefore.translateY);
this.getTranslatable().on('animationend', function() {
menu.isAnimating = false;
}, this, {
single: true
});
this.translate(viewportAfter.translateX, viewportAfter.translateY, {
preserveEndState: true,
duration: 200
});
}
// Make the menu as animating
menu.isAnimating = true;
},
* Hides a menu specified by the menu's side.
* @param {String} side The side which the menu is placed.
*/
hideMenu: function(side, animate) {
var menus = this.getMenus(),
menu = menus[side],
after, viewportAfter,
size;
animate = (animate === false) ? false : true;
if (!menu || (menu.isHidden() || menu.isAnimating)) {
return;
}
after = {
translateX: 0,
translateY: 0
};
viewportAfter = {
translateX: 0,
translateY: 0
};
size = (side == 'left' || side == 'right') ? menu.element.getWidth() : menu.element.getHeight();
if (side == 'left') {
after.translateX = -size;
}
else if (side == 'right') {
after.translateX = size;
}
else if (side == 'top') {
after.translateY = -size;
}
else if (side == 'bottom') {
after.translateY = size;
}
if (menu.$cover) {
if (animate) {
menu.getTranslatable().on('animationend', function() {
menu.isAnimating = false;
menu.hide();
}, this, {
single: true
});
menu.translate(after.translateX, after.translateY, {
preserveEndState: true,
duration: 200
});
}
else {
menu.translate(after.translateX, after.translateY);
menu.hide()
}
}
else {
if (animate) {
this.getTranslatable().on('animationend', function() {
menu.isAnimating = false;
menu.hide();
}, this, {
single: true
});
this.translate(viewportAfter.translateX, viewportAfter.translateY, {
preserveEndState: true,
duration: 200
});
}
else {
this.translate(viewportAfter.translateX, viewportAfter.translateY);
menu.hide();
}
}
},
* Hides all visible menus.
*/
hideAllMenus: function(animation) {
var menus = this.getMenus();
for (var side in menus) {
this.hideMenu(side, animation);
}
},
* Hides all menus except for the side specified
* @param {String} side Side(s) not to hide
* @param {String} animation Animation to hide with
*/
hideOtherMenus: function(side, animation){
var menus = this.getMenus();
for (var menu in menus) {
if (side != menu) {
this.hideMenu(menu, animation);
}
}
},
* Toggles the menu specified by side
* @param {String} side The side which the menu is placed.
*/
toggleMenu: function(side) {
var menus = this.getMenus(), menu;
if (menus[side]) {
menu = menus[side];
if (menu.isHidden()) {
this.showMenu(side);
} else {
this.hideMenu(side);
}
}
},
/**
* @private
*/
sideForDirection: function(direction) {
if (direction == 'left') {
return 'right';
}
else if (direction == 'right') {
return 'left';
}
else if (direction == 'up') {
return 'bottom';
}
else if (direction == 'down') {
return 'top';
}
},
/**
* @private
*/
sideForSwipeDirection: function(direction) {
if (direction == "up") {
return "top";
}
else if (direction == "down") {
return "bottom";
}
return direction;
},
/**
* @private
*/
onTap: function(e) {
// this.hideAllMenus();
},
/**
* @private
*/
onSwipeStart: function(e) {
var side = this.sideForSwipeDirection(e.direction);
this.hideMenu(side);
},
/**
* @private
*/
onEdgeSwipeStart: function(e) {
var side = this.sideForDirection(e.direction),
menus = this.getMenus(),
menu = menus[side],
menuSide, checkMenu;
if (!menu || !menu.isHidden()) {
return;
}
for (menuSide in menus) {
checkMenu = menus[menuSide];
if (checkMenu.isHidden() !== false) {
return;
}
}
this.$swiping = true;
this.hideAllMenus(false);
// show the menu first so we can calculate the size
if (menu.$reveal) {
Ext.getBody().insertFirst(menu.element);
}
else {
Ext.Viewport.add(menu);
}
menu.show();
var size = (side == 'left' || side == 'right') ? menu.element.getWidth() : menu.element.getHeight(),
after, viewportAfter;
after = {
translateX: 0,
translateY: 0
};
viewportAfter = {
translateX: 0,
translateY: 0
};
if (side == 'left') {
after.translateX = -size;
}
else if (side == 'right') {
after.translateX = size;
}
else if (side == 'top') {
after.translateY = -size;
}
else if (side == 'bottom') {
after.translateY = size;
}
var transformStyleName = 'webkitTransform' in document.createElement('div').style ? 'webkitTransform' : 'transform',
setTransform = menu.element.dom.style[transformStyleName];
if (setTransform) {
menu.element.dom.style[transformStyleName] = '';
}
if (menu.$reveal) {
if (Ext.browser.getPreferredTranslationMethod() != 'scrollposition') {
menu.translate(0, 0);
}
}
else {
menu.translate(after.translateX, after.translateY);
}
if (!menu.$cover) {
if (setTransform) {
this.innerElement.dom.style[transformStyleName] = '';
}
this.translate(viewportAfter.translateX, viewportAfter.translateY);
}
},
/**
* @private
*/
onEdgeSwipe: function(e) {
var side = this.sideForDirection(e.direction),
menu = this.getMenus()[side];
if (!menu || !this.$swiping) {
return;
}
var size = (side == 'left' || side == 'right') ? menu.element.getWidth() : menu.element.getHeight(),
after, viewportAfter,
movement = Math.min(e.distance - size, 0),
viewportMovement = Math.min(e.distance, size);
after = {
translateX: 0,
translateY: 0
};
viewportAfter = {
translateX: 0,
translateY: 0
};
if (side == 'left') {
after.translateX = movement;
viewportAfter.translateX = viewportMovement;
}
else if (side == 'right') {
after.translateX = -movement;
viewportAfter.translateX = -viewportMovement;
}
else if (side == 'top') {
after.translateY = movement;
viewportAfter.translateY = viewportMovement;
}
else if (side == 'bottom') {
after.translateY = -movement;
viewportAfter.translateY = -viewportMovement;
}
if (menu.$cover) {
menu.translate(after.translateX, after.translateY);
}
else {
this.translate(viewportAfter.translateX, viewportAfter.translateY);
}
},
/**
* @private
*/
onEdgeSwipeEnd: function(e) {
var side = this.sideForDirection(e.direction),
menu = this.getMenus()[side],
shouldRevert = false;
if (!menu) {
return;
}
var size = (side == 'left' || side == 'right') ? menu.element.getWidth() : menu.element.getHeight(),
velocity = (e.flick) ? e.flick.velocity : 0;
// check if continuing in the right direction
if (side == 'right') {
if (velocity.x > 0) {
shouldRevert = true;
}
}
else if (side == 'left') {
if (velocity.x < 0) {
shouldRevert = true;
}
}
else if (side == 'top') {
if (velocity.y < 0) {
shouldRevert = true;
}
}
else if (side == 'bottom') {
if (velocity.y > 0) {
shouldRevert = true;
}
}
var movement = (shouldRevert) ? size : 0,
viewportMovement = (shouldRevert) ? 0 : -size,
after, viewportAfter;
after = {
translateX: 0,
translateY: 0
};
viewportAfter = {
translateX: 0,
translateY: 0
};
if (side == 'left') {
after.translateX = -movement;
viewportAfter.translateX = -viewportMovement;
}
else if (side == 'right') {
after.translateX = movement;
viewportAfter.translateX = viewportMovement;
}
else if (side == 'top') {
after.translateY = -movement;
viewportAfter.translateY = -viewportMovement;
}
else if (side == 'bottom') {
after.translateY = movement;
viewportAfter.translateY = viewportMovement;
}
// Move the viewport if cover is not enabled
if (menu.$cover) {
menu.getTranslatable().on('animationend', function() {
if (shouldRevert) {
menu.hide();
}
}, this, {
single: true
});
menu.translate(after.translateX, after.translateY, {
preserveEndState: true,
duration: 200
});
}
else {
this.getTranslatable().on('animationend', function() {
if (shouldRevert) {
menu.hide();
}
}, this, {
single: true
});
this.translate(viewportAfter.translateX, viewportAfter.translateY, {
preserveEndState: true,
duration: 200
});
}
this.$swiping = false;
}
});