3 * Base class for iOS and Android viewports.
5 Ext
.define('Ext.viewport.Default', {
6 extend
: 'Ext.Container',
12 LANDSCAPE
: 'landscape',
17 'Ext.util.InputBlocker'
22 * Fires when the Viewport is in the DOM and ready.
23 * @param {Ext.Viewport} this
28 * Fires when the Viewport is maximized.
29 * @param {Ext.Viewport} this
33 * @event orientationchange
34 * Fires when the Viewport orientation has changed.
35 * @param {Ext.Viewport} this
36 * @param {String} newOrientation The new orientation.
37 * @param {Number} width The width of the Viewport.
38 * @param {Number} height The height of the Viewport.
53 * @cfg {Boolean} preventPanning
54 * Whether or not to always prevent default panning behavior of the
61 * @cfg {Boolean} preventZooming
62 * `true` to attempt to stop zooming when you double tap on the screen on mobile devices,
63 * typically HTC devices with HTC Sense UI.
66 preventZooming
: false,
75 * @cfg {Object/String} layout Configuration for this Container's layout. Example:
77 * Ext.create('Ext.Container', {
86 * style: 'background-color: red;'
91 * style: 'background-color: green'
96 * See the [layouts guide](../../../core_concepts/layouts.html) for more information.
114 useBodyElement
: true,
117 * An object of all the menus on this viewport.
128 getElementConfig: function() {
129 var cfg
= this.callParent(arguments
);
131 // Used in legacy browser that do not support matchMedia. Hidden element is used for checking of orientation
132 if (!Ext
.feature
.has
.MatchMedia
) {
133 cfg
.children
.unshift({reference
: 'orientationElement', className
: 'x-orientation-inspector'});
139 * @property {Boolean} isReady
140 * `true` if the DOM is ready.
150 isInputRegex
: /^(input|textarea|select|a)$/i,
152 isInteractiveWebComponentRegEx
: /^(audio|video)$/i,
154 focusedElement
: null,
159 fullscreenItemCls
: Ext
.baseCSSPrefix
+ 'fullscreen',
161 constructor: function(config
) {
162 var bind
= Ext
.Function
.bind
;
164 this.doPreventPanning
= bind(this.doPreventPanning
, this);
165 this.doPreventZooming
= bind(this.doPreventZooming
, this);
166 this.doBlurInput
= bind(this.doBlurInput
, this);
168 this.maximizeOnEvents
= [
173 // set default devicePixelRatio if it is not explicitly defined
174 window
.devicePixelRatio
= window
.devicePixelRatio
|| 1;
176 this.callSuper([config
]);
178 this.windowWidth
= this.getWindowWidth();
179 this.windowHeight
= this.getWindowHeight();
180 this.windowOuterHeight
= this.getWindowOuterHeight();
182 if (!this.stretchHeights
) {
183 this.stretchHeights
= {};
186 if(Ext
.feature
.has
.OrientationChange
) {
187 this.addWindowListener('orientationchange', bind(this.onOrientationChange
, this));
189 this.addWindowListener('resize', bind(this.onResize
, this));
192 document
.addEventListener('focus', bind(this.onElementFocus
, this), true);
193 document
.addEventListener('blur', bind(this.onElementBlur
, this), true);
195 Ext
.onDocumentReady(this.onDomReady
, this);
197 this.on('ready', this.onReady
, this, {single
: true});
198 this.getEventDispatcher().addListener('component', '*', 'fullscreen', 'onItemFullscreenChange', this);
202 onDomReady: function() {
205 this.fireEvent('ready', this);
208 onReady: function() {
209 if (this.getAutoRender()) {
212 if (Ext
.browser
.name
== 'ChromeiOS') {
213 this.setHeight('-webkit-calc(100% - ' + ((window
.outerHeight
- window
.innerHeight
) / 2) + 'px)');
217 onElementFocus: function(e
) {
218 this.focusedElement
= e
.target
;
221 onElementBlur: function() {
222 this.focusedElement
= null;
226 if (!this.rendered
) {
227 var body
= Ext
.getBody(),
228 clsPrefix
= Ext
.baseCSSPrefix
,
231 osName
= osEnv
.name
.toLowerCase(),
232 browserName
= Ext
.browser
.name
.toLowerCase(),
233 osMajorVersion
= osEnv
.version
.getMajor();
237 classList
.push(clsPrefix
+ osEnv
.deviceType
.toLowerCase());
240 classList
.push(clsPrefix
+ 'ipad');
243 classList
.push(clsPrefix
+ osName
);
244 classList
.push(clsPrefix
+ browserName
);
246 if (osMajorVersion
) {
247 classList
.push(clsPrefix
+ osName
+ '-' + osMajorVersion
);
250 if (osEnv
.is
.BlackBerry
) {
251 classList
.push(clsPrefix
+ 'bb');
252 if (Ext
.browser
.userAgent
.match(/Kbd/gi)) {
253 classList
.push(clsPrefix
+ 'bb-keyboard');
257 if (Ext
.browser
.is
.WebKit
) {
258 classList
.push(clsPrefix
+ 'webkit');
261 if (Ext
.browser
.is
.Standalone
) {
262 classList
.push(clsPrefix
+ 'standalone');
265 if (Ext
.browser
.is
.AndroidStock
) {
266 classList
.push(clsPrefix
+ 'android-stock');
269 if (Ext
.browser
.is
.GoogleGlass
) {
270 classList
.push(clsPrefix
+ 'google-glass');
273 this.setOrientation(this.determineOrientation());
274 classList
.push(clsPrefix
+ this.getOrientation());
275 body
.addCls(classList
);
279 applyAutoBlurInput: function(autoBlurInput
) {
280 var touchstart
= (Ext
.feature
.has
.Touch
) ? 'touchstart' : 'mousedown';
283 this.addWindowListener(touchstart
, this.doBlurInput
, false);
286 this.removeWindowListener(touchstart
, this.doBlurInput
, false);
289 return autoBlurInput
;
292 applyAutoMaximize: function(autoMaximize
) {
293 if (Ext
.browser
.is
.WebView
) {
294 autoMaximize
= false;
297 this.on('ready', 'doAutoMaximizeOnReady', this, { single
: true });
298 this.on('orientationchange', 'doAutoMaximizeOnOrientationChange', this);
301 this.un('ready', 'doAutoMaximizeOnReady', this);
302 this.un('orientationchange', 'doAutoMaximizeOnOrientationChange', this);
308 applyPreventPanning: function(preventPanning
) {
309 if (preventPanning
) {
310 this.addWindowListener('touchmove', this.doPreventPanning
, false);
313 this.removeWindowListener('touchmove', this.doPreventPanning
, false);
316 return preventPanning
;
319 applyPreventZooming: function(preventZooming
) {
320 var touchstart
= (Ext
.feature
.has
.Touch
) ? 'touchstart' : 'mousedown';
322 if (preventZooming
) {
323 this.addWindowListener(touchstart
, this.doPreventZooming
, false);
326 this.removeWindowListener(touchstart
, this.doPreventZooming
, false);
329 return preventZooming
;
332 doAutoMaximizeOnReady: function() {
333 var controller
= arguments
[arguments
.length
- 1];
337 this.isMaximizing
= true;
339 this.on('maximize', function() {
340 this.isMaximizing
= false;
346 this.fireEvent('ready', this);
347 }, this, { single
: true });
352 doAutoMaximizeOnOrientationChange: function() {
353 var controller
= arguments
[arguments
.length
- 1],
354 firingArguments
= controller
.firingArguments
;
358 this.isMaximizing
= true;
360 this.on('maximize', function() {
361 this.isMaximizing
= false;
365 firingArguments
[2] = this.windowWidth
;
366 firingArguments
[3] = this.windowHeight
;
369 }, this, { single
: true });
374 doBlurInput: function(e
) {
375 var target
= e
.target
,
376 focusedElement
= this.focusedElement
;
377 //In IE9/10 browser window loses focus and becomes inactive if focused element is <body>. So we shouldn't call blur for <body>
378 if (focusedElement
&& focusedElement
.nodeName
.toUpperCase() != 'BODY' && !this.isInputRegex
.test(target
.tagName
)) {
379 delete this.focusedElement
;
380 focusedElement
.blur();
384 doPreventPanning: function(e
) {
385 var target
= e
.target
, touch
;
387 // If we have an interaction on a WebComponent we need to check the actual shadow dom element selected
388 // to determine if it is an input before preventing default behavior
389 // Side effect to this is if the shadow input does not do anything with 'touchmove' the user could pan
391 if (this.isInteractiveWebComponentRegEx
.test(target
.tagName
) && e
.touches
&& e
.touches
.length
> 0) {
392 touch
= e
.touches
[0];
393 if (touch
&& touch
.target
&& this.isInputRegex
.test(touch
.target
.tagName
)) {
398 if (target
&& target
.nodeType
=== 1 && !this.isInputRegex
.test(target
.tagName
)) {
403 doPreventZooming: function(e
) {
404 // Don't prevent right mouse event
405 if ('button' in e
&& e
.button
!== 0) {
409 var target
= e
.target
, touch
;
410 if (this.isInteractiveWebComponentRegEx
.test(target
.tagName
) && e
.touches
&& e
.touches
.length
> 0) {
411 touch
= e
.touches
[0];
412 if (touch
&& touch
.target
&& this.isInputRegex
.test(touch
.target
.tagName
)) {
417 if (target
&& target
.nodeType
=== 1 && !this.isInputRegex
.test(target
.tagName
)) {
422 addWindowListener: function(eventName
, fn
, capturing
) {
423 window
.addEventListener(eventName
, fn
, Boolean(capturing
));
426 removeWindowListener: function(eventName
, fn
, capturing
) {
427 window
.removeEventListener(eventName
, fn
, Boolean(capturing
));
430 doAddListener: function(eventName
, fn
, scope
, options
) {
431 if (eventName
=== 'ready' && this.isReady
&& !this.isMaximizing
) {
436 return this.callSuper(arguments
);
439 determineOrientation: function() {
440 // First attempt will be to use Native Orientation information
441 if (Ext
.feature
.has
.Orientation
) {
442 var nativeOrientation
= this.getWindowOrientation();
443 // 90 || -90 || 270 is landscape
444 if (Math
.abs(nativeOrientation
) === 90 || nativeOrientation
=== 270) {
445 return this.LANDSCAPE
;
447 return this.PORTRAIT
;
449 // Second attempt will be to use MatchMedia and a media query
450 } else if (Ext
.feature
.has
.MatchMedia
) {
451 return window
.matchMedia('(orientation : landscape)').matches
? this.LANDSCAPE
: this.PORTRAIT
;
452 // Fall back on hidden element with media query attached to it (media query in Base Theme)
453 } else if (this.orientationElement
) {
454 return this.orientationElement
.getStyle('content');
458 updateOrientation: function(newValue
, oldValue
) {
460 this.fireOrientationChangeEvent(newValue
, oldValue
);
465 * Listener for Orientation Change in environments that support orientationchange events
468 onOrientationChange: function() {
469 this.setOrientation(this.determineOrientation());
473 * Listener for Orientation Change in environments that do no support orientationchange events
476 onResize: function() {
478 this.setOrientation(this.determineOrientation());
481 fireOrientationChangeEvent: function(newOrientation
, oldOrientation
) {
482 var clsPrefix
= Ext
.baseCSSPrefix
;
483 Ext
.getBody().replaceCls(clsPrefix
+ oldOrientation
, clsPrefix
+ newOrientation
);
486 this.fireEvent('orientationchange', this, newOrientation
, this.windowWidth
, this.windowHeight
);
489 updateSize: function(width
, height
) {
490 this.windowWidth
= width
!== undefined ? width
: this.getWindowWidth();
491 this.windowHeight
= height
!== undefined ? height
: this.getWindowHeight();
496 maximize: function() {
497 this.fireMaximizeEvent();
500 fireMaximizeEvent: function() {
502 this.fireEvent('maximize', this);
505 doSetHeight: function(height
) {
506 Ext
.getBody().setHeight(height
);
508 this.callParent(arguments
);
511 doSetWidth: function(width
) {
512 Ext
.getBody().setWidth(width
);
514 this.callParent(arguments
);
517 scrollToTop: function() {
518 window
.scrollTo(0, -1);
522 * Retrieves the document width.
523 * @return {Number} width in pixels.
525 getWindowWidth: function() {
526 return window
.innerWidth
;
530 * Retrieves the document height.
531 * @return {Number} height in pixels.
533 getWindowHeight: function() {
534 return window
.innerHeight
;
537 getWindowOuterHeight: function() {
538 return window
.outerHeight
;
541 getWindowOrientation: function() {
542 return window
.orientation
;
545 getSize: function() {
547 width
: this.windowWidth
,
548 height
: this.windowHeight
552 onItemFullscreenChange: function(item
) {
553 item
.addCls(this.fullscreenItemCls
);
556 waitUntil: function(condition
, onSatisfied
, onTimeout
, delay
, timeoutDuration
) {
561 if (!timeoutDuration
) {
562 timeoutDuration
= 2000;
568 setTimeout(function repeat() {
571 if (condition
.call(scope
) === true) {
573 onSatisfied
.call(scope
);
577 if (elapse
>= timeoutDuration
) {
579 onTimeout
.call(scope
);
583 setTimeout(repeat
, delay
);
590 * Sets a menu for a given side of the Viewport.
592 * Adds functionality to show the menu by swiping from the side of the screen from the given side.
594 * If a menu is already set for a given side, it will be removed.
596 * Available sides are: `left`, `right`, `top`, and `bottom`.
598 * @param {Ext.Menu} menu The menu to assign to the viewport
599 * @param {Object} config The configuration for the menu.
600 * @param {String} config.side The side to put the menu on.
601 * @param {Boolean} config.cover True to cover the viewport content. Defaults to `true`.
603 setMenu: function(menu
, config
) {
605 config
= config
|| {};
607 // Temporary workaround for body shifting issue
608 if (Ext
.os
.is
.iOS
&& !this.hasiOSOrientationFix
) {
609 this.hasiOSOrientationFix
= true;
610 this.on('orientationchange', function() {
611 window
.scrollTo(0, 0);
617 Ext
.Logger
.error("You must specify a side to dock the menu.");
624 Ext
.Logger
.error("You must specify a side to dock the menu.");
629 if (['left', 'right', 'top', 'bottom'].indexOf(config
.side
) == -1) {
631 Ext
.Logger
.error("You must specify a valid side (left, right, top or botom) to dock the menu.");
636 var menus
= me
.getMenus();
642 // Add a listener to show this menu on swipe
643 if (!me
.addedSwipeListener
) {
644 me
.addedSwipeListener
= true;
648 swipestart
: me
.onSwipeStart
,
649 edgeswipestart
: me
.onEdgeSwipeStart
,
650 edgeswipe
: me
.onEdgeSwipe
,
651 edgeswipeend
: me
.onEdgeSwipeEnd
,
655 // Add BB10 webworks API for swipe down.
656 if (window
.blackberry
) {
657 var toggleMenu = function() {
658 var menus
= me
.getMenus(),
665 if (menu
.isHidden()) {
672 if (blackberry
.app
&& blackberry
.app
.event
&& blackberry
.app
.event
.onSwipeDown
) {
673 blackberry
.app
.event
.onSwipeDown(toggleMenu
); // PlayBook
675 else if (blackberry
.event
&& blackberry
.event
.addEventListener
) {
676 blackberry
.event
.addEventListener("swipedown", toggleMenu
); // BB10
681 menus
[config
.side
] = menu
;
682 menu
.$reveal
= Boolean(config
.reveal
);
683 menu
.$cover
= config
.cover
!== false && !menu
.$reveal
;
684 menu
.$side
= config
.side
;
686 me
.fixMenuSize(menu
, config
.side
);
688 if (config
.side
== 'left') {
694 else if (config
.side
== 'right') {
700 else if (config
.side
== 'top') {
704 menu
.setBottom(null);
706 else if (config
.side
== 'bottom') {
717 * Removes a menu from a specified side.
718 * @param {String} side The side to remove the menu from
720 removeMenu: function(side
) {
721 var menus
= this.getMenus() || {},
724 if(menu
) this.hideMenu(side
);
726 this.setMenus(menus
);
731 * Changes the sizing of the specified menu so that it displays correctly when shown.
733 fixMenuSize: function(menu
, side
) {
734 if (side
== 'top' || side
== 'bottom') {
735 menu
.setWidth('100%');
737 else if (side
== 'left' || side
== 'right') {
738 menu
.setHeight('100%');
743 * Shows a menu specified by the menu's side.
744 * @param {String} side The side which the menu is placed.
746 showMenu: function(side
) {
747 var menus
= this.getMenus(),
750 viewportBefore
, viewportAfter
;
752 if (!menu
|| menu
.isAnimating
) {
756 this.hideOtherMenus(side
);
779 Ext
.getBody().insertFirst(menu
.element
);
782 Ext
.Viewport
.add(menu
);
786 menu
.addCls('x-' + side
);
788 var size
= (side
== 'left' || side
== 'right') ? menu
.element
.getWidth() : menu
.element
.getHeight();
790 if (side
== 'left') {
791 before
.translateX
= -size
;
792 viewportAfter
.translateX
= size
;
794 else if (side
== 'right') {
795 before
.translateX
= size
;
796 viewportAfter
.translateX
= -size
;
798 else if (side
== 'top') {
799 before
.translateY
= -size
;
800 viewportAfter
.translateY
= size
;
802 else if (side
== 'bottom') {
803 before
.translateY
= size
;
804 viewportAfter
.translateY
= -size
;
808 if (Ext
.browser
.getPreferredTranslationMethod() != 'scrollposition') {
809 menu
.translate(0, 0);
813 menu
.translate(before
.translateX
, before
.translateY
);
817 menu
.getTranslatable().on('animationend', function() {
818 menu
.isAnimating
= false;
823 menu
.translate(after
.translateX
, after
.translateY
, {
824 preserveEndState
: true,
830 this.translate(viewportBefore
.translateX
, viewportBefore
.translateY
);
833 this.getTranslatable().on('animationend', function() {
834 menu
.isAnimating
= false;
839 this.translate(viewportAfter
.translateX
, viewportAfter
.translateY
, {
840 preserveEndState
: true,
845 // Make the menu as animating
846 menu
.isAnimating
= true;
850 * Hides a menu specified by the menu's side.
851 * @param {String} side The side which the menu is placed.
853 hideMenu: function(side
, animate
) {
854 var menus
= this.getMenus(),
856 after
, viewportAfter
,
859 animate
= (animate
=== false) ? false : true;
861 if (!menu
|| (menu
.isHidden() || menu
.isAnimating
)) {
875 size
= (side
== 'left' || side
== 'right') ? menu
.element
.getWidth() : menu
.element
.getHeight();
877 if (side
== 'left') {
878 after
.translateX
= -size
;
880 else if (side
== 'right') {
881 after
.translateX
= size
;
883 else if (side
== 'top') {
884 after
.translateY
= -size
;
886 else if (side
== 'bottom') {
887 after
.translateY
= size
;
892 menu
.getTranslatable().on('animationend', function() {
893 menu
.isAnimating
= false;
899 menu
.translate(after
.translateX
, after
.translateY
, {
900 preserveEndState
: true,
905 menu
.translate(after
.translateX
, after
.translateY
);
911 this.getTranslatable().on('animationend', function() {
912 menu
.isAnimating
= false;
918 this.translate(viewportAfter
.translateX
, viewportAfter
.translateY
, {
919 preserveEndState
: true,
924 this.translate(viewportAfter
.translateX
, viewportAfter
.translateY
);
931 * Hides all visible menus.
933 hideAllMenus: function(animation
) {
934 var menus
= this.getMenus();
936 for (var side
in menus
) {
937 this.hideMenu(side
, animation
);
942 * Hides all menus except for the side specified
943 * @param {String} side Side(s) not to hide
944 * @param {String} animation Animation to hide with
946 hideOtherMenus: function(side
, animation
){
947 var menus
= this.getMenus();
949 for (var menu
in menus
) {
951 this.hideMenu(menu
, animation
);
957 * Toggles the menu specified by side
958 * @param {String} side The side which the menu is placed.
960 toggleMenu: function(side
) {
961 var menus
= this.getMenus(), menu
;
964 if (menu
.isHidden()) {
975 sideForDirection: function(direction
) {
976 if (direction
== 'left') {
979 else if (direction
== 'right') {
982 else if (direction
== 'up') {
985 else if (direction
== 'down') {
993 sideForSwipeDirection: function(direction
) {
994 if (direction
== "up") {
997 else if (direction
== "down") {
1006 onTap: function(e
) {
1007 // this.hideAllMenus();
1013 onSwipeStart: function(e
) {
1014 var side
= this.sideForSwipeDirection(e
.direction
);
1015 this.hideMenu(side
);
1021 onEdgeSwipeStart: function(e
) {
1022 var side
= this.sideForDirection(e
.direction
),
1023 menus
= this.getMenus(),
1025 menuSide
, checkMenu
;
1027 if (!menu
|| !menu
.isHidden()) {
1031 for (menuSide
in menus
) {
1032 checkMenu
= menus
[menuSide
];
1033 if (checkMenu
.isHidden() !== false) {
1038 this.$swiping
= true;
1040 this.hideAllMenus(false);
1042 // show the menu first so we can calculate the size
1044 Ext
.getBody().insertFirst(menu
.element
);
1047 Ext
.Viewport
.add(menu
);
1051 var size
= (side
== 'left' || side
== 'right') ? menu
.element
.getWidth() : menu
.element
.getHeight(),
1052 after
, viewportAfter
;
1064 if (side
== 'left') {
1065 after
.translateX
= -size
;
1067 else if (side
== 'right') {
1068 after
.translateX
= size
;
1070 else if (side
== 'top') {
1071 after
.translateY
= -size
;
1073 else if (side
== 'bottom') {
1074 after
.translateY
= size
;
1077 var transformStyleName
= 'webkitTransform' in document
.createElement('div').style
? 'webkitTransform' : 'transform',
1078 setTransform
= menu
.element
.dom
.style
[transformStyleName
];
1081 menu
.element
.dom
.style
[transformStyleName
] = '';
1085 if (Ext
.browser
.getPreferredTranslationMethod() != 'scrollposition') {
1086 menu
.translate(0, 0);
1090 menu
.translate(after
.translateX
, after
.translateY
);
1095 this.innerElement
.dom
.style
[transformStyleName
] = '';
1098 this.translate(viewportAfter
.translateX
, viewportAfter
.translateY
);
1105 onEdgeSwipe: function(e
) {
1106 var side
= this.sideForDirection(e
.direction
),
1107 menu
= this.getMenus()[side
];
1109 if (!menu
|| !this.$swiping
) {
1113 var size
= (side
== 'left' || side
== 'right') ? menu
.element
.getWidth() : menu
.element
.getHeight(),
1114 after
, viewportAfter
,
1115 movement
= Math
.min(e
.distance
- size
, 0),
1116 viewportMovement
= Math
.min(e
.distance
, size
);
1128 if (side
== 'left') {
1129 after
.translateX
= movement
;
1130 viewportAfter
.translateX
= viewportMovement
;
1132 else if (side
== 'right') {
1133 after
.translateX
= -movement
;
1134 viewportAfter
.translateX
= -viewportMovement
;
1136 else if (side
== 'top') {
1137 after
.translateY
= movement
;
1138 viewportAfter
.translateY
= viewportMovement
;
1140 else if (side
== 'bottom') {
1141 after
.translateY
= -movement
;
1142 viewportAfter
.translateY
= -viewportMovement
;
1146 menu
.translate(after
.translateX
, after
.translateY
);
1149 this.translate(viewportAfter
.translateX
, viewportAfter
.translateY
);
1156 onEdgeSwipeEnd: function(e
) {
1157 var side
= this.sideForDirection(e
.direction
),
1158 menu
= this.getMenus()[side
],
1159 shouldRevert
= false;
1165 var size
= (side
== 'left' || side
== 'right') ? menu
.element
.getWidth() : menu
.element
.getHeight(),
1166 velocity
= (e
.flick
) ? e
.flick
.velocity
: 0;
1168 // check if continuing in the right direction
1169 if (side
== 'right') {
1170 if (velocity
.x
> 0) {
1171 shouldRevert
= true;
1174 else if (side
== 'left') {
1175 if (velocity
.x
< 0) {
1176 shouldRevert
= true;
1179 else if (side
== 'top') {
1180 if (velocity
.y
< 0) {
1181 shouldRevert
= true;
1184 else if (side
== 'bottom') {
1185 if (velocity
.y
> 0) {
1186 shouldRevert
= true;
1190 var movement
= (shouldRevert
) ? size
: 0,
1191 viewportMovement
= (shouldRevert
) ? 0 : -size
,
1192 after
, viewportAfter
;
1204 if (side
== 'left') {
1205 after
.translateX
= -movement
;
1206 viewportAfter
.translateX
= -viewportMovement
;
1208 else if (side
== 'right') {
1209 after
.translateX
= movement
;
1210 viewportAfter
.translateX
= viewportMovement
;
1212 else if (side
== 'top') {
1213 after
.translateY
= -movement
;
1214 viewportAfter
.translateY
= -viewportMovement
;
1216 else if (side
== 'bottom') {
1217 after
.translateY
= movement
;
1218 viewportAfter
.translateY
= viewportMovement
;
1221 // Move the viewport if cover is not enabled
1223 menu
.getTranslatable().on('animationend', function() {
1231 menu
.translate(after
.translateX
, after
.translateY
, {
1232 preserveEndState
: true,
1238 this.getTranslatable().on('animationend', function() {
1246 this.translate(viewportAfter
.translateX
, viewportAfter
.translateY
, {
1247 preserveEndState
: true,
1252 this.$swiping
= false;