/** * */ Ext.define('Ext.viewport.Default', { extend: 'Ext.Container', xtype: 'viewport', PORTRAIT: 'portrait', LANDSCAPE: 'landscape', config: { /** * @cfg {Boolean} autoMaximize * Whether or not to always automatically maximize the viewport on * first load and all subsequent orientation changes * @accessor */ autoMaximize: Ext.browser.is.WebView ? false : true, /** * @cfg {Boolean} preventPanning * Whether or not to always prevent default panning behavior of the * browser's viewport * @accessor */ preventPanning: true, /** * @cfg {Boolean} preventZooming * Whether or not to always prevent default zooming feature of the * browser's viewport via finger gestures such as pinching and / or double-tapping * @accessor */ preventZooming: true, autoRender: true, layout: 'card', width: '100%', height: '100%' }, isReady: false, isViewport: true, isMaximizing: false, id: 'ext-viewport', isInputRegex: /^(input|textarea|select)$/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.maximizeOnEvents = ['ready', 'orientationchange']; this.orientation = this.determineOrientation(); this.windowWidth = this.getWindowWidth(); this.windowHeight = this.getWindowHeight(); this.windowOuterHeight = this.getWindowOuterHeight(); if (!this.stretchHeights) { this.stretchHeights = {}; } this.callParent([config]); 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.fireEvent('ready'); }, onReady: function() { if (this.getAutoRender()) { this.render(); } }, 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(), osMajorVersion = osEnv.version.getMajor(), orientation = this.getOrientation(); this.renderTo(body); //TODO Clean me up, this is not good classList.push(clsPrefix + osEnv.deviceType.toLowerCase()); if (osEnv.is.iPad) { classList.push(clsPrefix + 'ipad'); } classList.push(clsPrefix + osName); if (osMajorVersion) { classList.push(clsPrefix + osName + '-' + osMajorVersion); } if (osEnv.is.BlackBerry) { classList.push(clsPrefix + 'bb'); } if (Ext.browser.is.Standalone) { classList.push(clsPrefix + 'standalone'); } classList.push(clsPrefix + orientation); body.addCls(classList); } }, applyAutoMaximize: function(autoMaximize) { 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) { 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, { 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[1] = this.windowWidth; firingArguments[2] = this.windowHeight; controller.resume(); }, this, { single: true }); this.maximize(); }, doPreventPanning: function(e) { e.preventDefault(); }, doPreventZooming: function(e) { 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, capturing); }, removeWindowListener: function(eventName, fn, capturing) { window.removeEventListener(eventName, fn, capturing); }, doAddListener: function(eventName, fn, scope, options) { if (eventName === 'ready' && this.isReady && !this.isMaximizing) { fn.call(scope); return this; } this.mixins.observable.doAddListener.apply(this, 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(); if (oldWidth !== width || oldHeight !== height) { this.fireResizeEvent(width, height); if (currentOrientation !== newOrientation) { this.fireOrientationChangeEvent(newOrientation, currentOrientation); } } }, fireResizeEvent: function(width, height) { this.updateSize(width, height); this.fireEvent('resize', width, height); }, onOrientationChange: function() { var currentOrientation = this.getOrientation(), newOrientation = this.determineOrientation(); if (newOrientation !== currentOrientation) { this.fireOrientationChangeEvent(newOrientation, currentOrientation); this.fireResizeEvent(this.windowWidth, this.windowHeight); } }, fireOrientationChangeEvent: function(newOrientation, oldOrientation) { var clsPrefix = Ext.baseCSSPrefix; Ext.getBody().replaceCls(clsPrefix + oldOrientation, clsPrefix + newOrientation); this.orientation = newOrientation; this.updateSize(); this.fireEvent('orientationchange', 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'); }, 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); }, getWindowWidth: function() { return window.innerWidth; }, getWindowHeight: function() { return window.innerHeight; }, getWindowOuterHeight: function() { return window.outerHeight; }, getWindowOrientation: function() { return window.orientation; }, getOrientation: function() { return this.orientation; }, getSize: function() { return { width: this.windowWidth, height: this.windowHeight }; }, determineOrientation: function() { var portrait = this.PORTRAIT, landscape = this.LANDSCAPE; if (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); } });