/** * @private * Android version of viewport. */Ext.define('Ext.viewport.Android', { extend: 'Ext.viewport.Default', config: { translatable: { type: 'csstransform' } }, /** * @property {Boolean} preventPullRefresh * Disables built-in pull-refresh of a page in Chrome */ preventPullRefresh: true, constructor: function() { var me = this; me.callParent(arguments); me.on({ orientationchange: 'hideKeyboardIfNeeded', scope: me, // run our handler before user code priority: 1001 }); // https://sencha.jira.com/browse/EXTJS-25292 if (me.preventPullRefresh) { Ext.getBody().setStyle({ overflow: 'hidden' }); } }, getWindowWidth: function() { return this.element.getWidth(); }, getWindowHeight: function() { return this.element.getHeight(); }, getDummyInput: function() { var input = this.dummyInput, focusedElement = this.focusedElement, box = Ext.fly(focusedElement).getBox(); if (!input) { this.dummyInput = input = document.createElement('input'); input.style.position = 'absolute'; input.style.opacity = '0'; input.style.pointerEvents = 'none'; document.body.appendChild(input); } input.style.left = box.left + 'px'; input.style.top = box.top + 'px'; input.style.display = ''; return input; }, doBlurInput: function(e) { var target = e.target, focusedElement = this.focusedElement, dummy; if (focusedElement && !this.isInputRegex.test(target.tagName)) { dummy = this.getDummyInput(); delete this.focusedElement; dummy.focus(); Ext.defer(function() { dummy.style.display = 'none'; }, 100); } }, hideKeyboardIfNeeded: function() { var focusedElement = this.focusedElement; if (focusedElement) { delete this.focusedElement; if (Ext.os.version.lt('4')) { focusedElement.style.display = 'none'; } else { focusedElement.blur(); } Ext.defer(function() { focusedElement.style.display = ''; }, 1000); } }, doFireOrientationChangeEvent: function() { this.orientationChanging = true; this.waitUntil(function() { return this.getWindowOuterHeight() !== this.windowOuterHeight; }, function() { this.windowOuterHeight = this.getWindowOuterHeight(); this.updateSize(); this.orientationChanging = false; }, function() { //<debug> Ext.Logger.error( "Timeout waiting for viewport's outerHeight to change " + "before firing orientationchange", this ); //</debug> }); return this; }, getActualWindowOuterHeight: function() { return Math.round(this.getWindowOuterHeight() / window.devicePixelRatio); }, maximize: function() { var stretchHeights = this.stretchHeights, orientation = this.orientation, isHeightMaximized, height; height = stretchHeights[orientation]; if (!height) { stretchHeights[orientation] = height = this.getActualWindowOuterHeight(); } if (!this.addressBarHeight) { this.addressBarHeight = height - this.getWindowHeight(); } this.setHeight(height); isHeightMaximized = this.isHeightMaximized.bind(this, height); this.scrollToTop(); this.waitUntil(isHeightMaximized, this.fireMaximizeEvent, this.fireMaximizeEvent); }, isHeightMaximized: function(height) { this.scrollToTop(); return this.getWindowHeight() === height; }, doPreventZooming: function(e) { var target; // Don't prevent right mouse event if ('button' in e && e.button !== 0) { return; } target = e.target; if ( target && target.nodeType === 1 && !this.isInputRegex.test(target.tagName) && !this.focusedElement ) { e.preventDefault(); } } }, function() { var version, userAgent, isBuggy; if (!Ext.os.is.Android) { return; } version = Ext.os.version; userAgent = Ext.browser.userAgent; // These Android devices have a nasty bug which causes JavaScript timers to be completely frozen // when the browser's viewport is being panned. isBuggy = /(htc|desire|incredible|ADR6300)/i.test(userAgent) && version.lt('2.3'); if (isBuggy) { this.override({ constructor: function(config) { if (!config) { config = {}; } config.autoMaximize = false; this.watchDogTick = this.watchDogTick.bind(this); Ext.interval(this.watchDogTick, 1000); return this.callParent([config]); }, watchDogTick: function() { this.watchDogLastTick = Ext.Date.now(); }, doPreventPanning: function() { var now = Ext.Date.now(), lastTick = this.watchDogLastTick, deltaTime = now - lastTick; // Timers are frozen if (deltaTime >= 2000) { return; } return this.callParent(arguments); }, doPreventZooming: function() { var now = Ext.Date.now(), lastTick = this.watchDogLastTick, deltaTime = now - lastTick; // Timers are frozen if (deltaTime >= 2000) { return; } return this.callParent(arguments); } }); } if (version.match('2')) { this.override({ onReady: function() { this.addWindowListener('resize', this.onWindowResize.bind(this)); this.callParent(arguments); }, scrollToTop: function() { document.body.scrollTop = 100; }, onWindowResize: function() { var oldWidth = this.windowWidth, oldHeight = this.windowHeight, width = this.getWindowWidth(), height = this.getWindowHeight(); if (this.getAutoMaximize() && !this.isMaximizing && !this.orientationChanging && window.scrollY === 0 && oldWidth === width && height < oldHeight && ((height >= oldHeight - this.addressBarHeight) || !this.focusedElement)) { this.scrollToTop(); } } }); } else if (version.gtEq('3.1')) { this.override({ isHeightMaximized: function(height) { this.scrollToTop(); return this.getWindowHeight() === height - 1; } }); } else if (version.match('3')) { this.override({ isHeightMaximized: function() { this.scrollToTop(); return true; } }); } if (version.gtEq('4')) { this.override({ doBlurInput: Ext.emptyFn }); }});