init repo

This commit is contained in:
nikolay ivanov
2014-07-05 18:22:49 +00:00
commit a8be6b9e72
17348 changed files with 9229832 additions and 0 deletions

View File

@@ -0,0 +1,289 @@
/**
* @private
* Android version of viewport.
*/
Ext.define('Ext.viewport.Android', {
extend: 'Ext.viewport.Default',
constructor: function() {
this.on('orientationchange', 'doFireOrientationChangeEvent', this, { prepend: true });
this.on('orientationchange', 'hideKeyboardIfNeeded', this, { prepend: true });
this.callParent(arguments);
this.addWindowListener('resize', Ext.Function.bind(this.onResize, this));
},
getDummyInput: function() {
var input = this.dummyInput,
focusedElement = this.focusedElement,
box = Ext.fly(focusedElement).getPageBox();
if (!input) {
this.dummyInput = input = document.createElement('input');
input.style.position = 'absolute';
input.style.opacity = '0';
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();
setTimeout(function() {
dummy.style.display = 'none';
}, 100);
}
},
hideKeyboardIfNeeded: function() {
var eventController = arguments[arguments.length - 1],
focusedElement = this.focusedElement;
if (focusedElement) {
delete this.focusedElement;
eventController.pause();
if (Ext.os.version.lt('4')) {
focusedElement.style.display = 'none';
}
else {
focusedElement.blur();
}
setTimeout(function() {
focusedElement.style.display = '';
eventController.resume();
}, 1000);
}
},
doFireOrientationChangeEvent: function() {
var eventController = arguments[arguments.length - 1];
this.orientationChanging = true;
eventController.pause();
this.waitUntil(function() {
return this.getWindowOuterHeight() !== this.windowOuterHeight;
}, function() {
this.windowOuterHeight = this.getWindowOuterHeight();
this.updateSize();
eventController.firingArguments[2] = this.windowWidth;
eventController.firingArguments[3] = this.windowHeight;
eventController.resume();
this.orientationChanging = false;
}, function() {
//<debug error>
Ext.Logger.error("Timeout waiting for viewport's outerHeight to change before firing orientationchange", this);
//</debug>
});
return this;
},
applyAutoMaximize: function(autoMaximize) {
autoMaximize = this.callParent(arguments);
this.on('add', 'fixSize', this, { single: true });
if (!autoMaximize) {
this.on('ready', 'fixSize', this, { single: true });
this.onAfter('orientationchange', 'doFixSize', this, { buffer: 100 });
}
else {
this.un('ready', 'fixSize', this);
this.unAfter('orientationchange', 'doFixSize', this);
}
},
fixSize: function() {
this.doFixSize();
},
doFixSize: function() {
this.setHeight(this.getWindowHeight());
},
determineOrientation: function() {
return (this.getWindowHeight() >= this.getWindowWidth()) ? this.PORTRAIT : this.LANDSCAPE;
},
getActualWindowOuterHeight: function() {
return Math.round(this.getWindowOuterHeight() / window.devicePixelRatio);
},
maximize: function() {
var stretchHeights = this.stretchHeights,
orientation = this.orientation,
height;
height = stretchHeights[orientation];
if (!height) {
stretchHeights[orientation] = height = this.getActualWindowOuterHeight();
}
if (!this.addressBarHeight) {
this.addressBarHeight = height - this.getWindowHeight();
}
this.setHeight(height);
var isHeightMaximized = Ext.Function.bind(this.isHeightMaximized, this, [height]);
this.scrollToTop();
this.waitUntil(isHeightMaximized, this.fireMaximizeEvent, this.fireMaximizeEvent);
},
isHeightMaximized: function(height) {
this.scrollToTop();
return this.getWindowHeight() === height;
}
}, function() {
if (!Ext.os.is.Android) {
return;
}
var 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 = Ext.Function.bind(this.watchDogTick, this);
setInterval(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', Ext.Function.bind(this.onWindowResize, 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();
}
},
fixSize: function() {
var orientation = this.getOrientation(),
outerHeight = window.outerHeight,
outerWidth = window.outerWidth,
actualOuterHeight;
// On some Android 2 devices such as the Kindle Fire, outerWidth and outerHeight are reported wrongly
// when navigating from another page that has larger size.
if (orientation === 'landscape' && (outerHeight < outerWidth)
|| orientation === 'portrait' && (outerHeight >= outerWidth)) {
actualOuterHeight = this.getActualWindowOuterHeight();
}
else {
actualOuterHeight = this.getWindowHeight();
}
this.waitUntil(function() {
return actualOuterHeight > this.getWindowHeight();
}, this.doFixSize, this.doFixSize, 50, 1000);
}
});
}
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
});
}
});

View File

@@ -0,0 +1,554 @@
/**
* @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'
],
/**
* @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
},
/**
* @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'];
this.orientation = this.determineOrientation();
this.windowWidth = this.getWindowWidth();
this.windowHeight = this.getWindowHeight();
this.windowOuterHeight = this.getWindowOuterHeight();
if (!this.stretchHeights) {
this.stretchHeights = {};
}
this.callParent([config]);
// Android is handled separately
if (!Ext.os.is.Android || Ext.browser.name == '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();
}
},
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.is.Standalone) {
classList.push(clsPrefix + 'standalone');
}
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;
if (focusedElement && !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 (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);
}
});

View File

@@ -0,0 +1,143 @@
/**
* @private
* iOS version of viewport.
*/
Ext.define('Ext.viewport.Ios', {
extend: 'Ext.viewport.Default',
isFullscreen: function() {
return this.isHomeScreen();
},
isHomeScreen: function() {
return window.navigator.standalone === true;
},
constructor: function() {
this.callParent(arguments);
if (this.getAutoMaximize() && !this.isFullscreen()) {
this.addWindowListener('touchstart', Ext.Function.bind(this.onTouchStart, this));
}
},
maximize: function() {
if (this.isFullscreen()) {
return this.callParent();
}
var stretchHeights = this.stretchHeights,
orientation = this.orientation,
currentHeight = this.getWindowHeight(),
height = stretchHeights[orientation];
if (window.scrollY > 0) {
this.scrollToTop();
if (!height) {
stretchHeights[orientation] = height = this.getWindowHeight();
}
this.setHeight(height);
this.fireMaximizeEvent();
}
else {
if (!height) {
height = this.getScreenHeight();
}
this.setHeight(height);
this.waitUntil(function() {
this.scrollToTop();
return currentHeight !== this.getWindowHeight();
}, function() {
if (!stretchHeights[orientation]) {
height = stretchHeights[orientation] = this.getWindowHeight();
this.setHeight(height);
}
this.fireMaximizeEvent();
}, function() {
//<debug error>
Ext.Logger.error("Timeout waiting for window.innerHeight to change", this);
//</debug>
height = stretchHeights[orientation] = this.getWindowHeight();
this.setHeight(height);
this.fireMaximizeEvent();
}, 50, 1000);
}
},
getScreenHeight: function() {
return window.screen[this.orientation === this.PORTRAIT ? 'height' : 'width'];
},
onElementFocus: function() {
if (this.getAutoMaximize() && !this.isFullscreen()) {
clearTimeout(this.scrollToTopTimer);
}
this.callParent(arguments);
},
onElementBlur: function() {
if (this.getAutoMaximize() && !this.isFullscreen()) {
this.scrollToTopTimer = setTimeout(this.scrollToTop, 500);
}
this.callParent(arguments);
},
onTouchStart: function() {
if (this.focusedElement === null) {
this.scrollToTop();
}
},
scrollToTop: function() {
window.scrollTo(0, 0);
}
}, function() {
if (!Ext.os.is.iOS) {
return;
}
if (Ext.os.version.lt('3.2')) {
this.override({
constructor: function() {
var stretchHeights = this.stretchHeights = {};
stretchHeights[this.PORTRAIT] = 416;
stretchHeights[this.LANDSCAPE] = 268;
return this.callOverridden(arguments);
}
});
}
if (Ext.os.version.lt('5')) {
this.override({
fieldMaskClsTest: '-field-mask',
doPreventZooming: function(e) {
var target = e.target;
if (target && target.nodeType === 1 &&
!this.isInputRegex.test(target.tagName) &&
target.className.indexOf(this.fieldMaskClsTest) == -1) {
e.preventDefault();
}
}
});
}
if (Ext.os.is.iPad) {
this.override({
isFullscreen: function() {
return true;
}
});
}
});

View File

@@ -0,0 +1,71 @@
/**
* This class acts as a factory for environment-specific viewport implementations.
*
* Please refer to the {@link Ext.Viewport} documentation about using the global instance.
* @private
*/
Ext.define('Ext.viewport.Viewport', {
requires: [
'Ext.viewport.Ios',
'Ext.viewport.Android'
],
constructor: function(config) {
var osName = Ext.os.name,
viewportName, viewport;
switch (osName) {
case 'Android':
viewportName = (Ext.browser.name == 'ChromeMobile') ? 'Default' : 'Android';
break;
case 'iOS':
viewportName = 'Ios';
break;
default:
viewportName = 'Default';
}
viewport = Ext.create('Ext.viewport.' + viewportName, config);
return viewport;
}
});
// Docs for the singleton instance created by above factory:
/**
* @class Ext.Viewport
* @extends Ext.viewport.Default
* @singleton
*
* Ext.Viewport is a instance created when you use {@link Ext#setup}. Because {@link Ext.Viewport} extends from
* {@link Ext.Container}, it has as {@link #layout} (which defaults to {@link Ext.layout.Card}). This means you
* can add items to it at any time, from anywhere in your code. The {@link Ext.Viewport} {@link #cfg-fullscreen}
* configuration is `true` by default, so it will take up your whole screen.
*
* @example raw
* Ext.setup({
* onReady: function() {
* Ext.Viewport.add({
* xtype: 'container',
* html: 'My new container!'
* });
* }
* });
*
* If you want to customize anything about this {@link Ext.Viewport} instance, you can do so by adding a property
* called `viewport` into your {@link Ext#setup} object:
*
* @example raw
* Ext.setup({
* viewport: {
* layout: 'vbox'
* },
* onReady: function() {
* //do something
* }
* });
*
* **Note** if you use {@link Ext#onReady}, this instance of {@link Ext.Viewport} will **not** be created. Though, in most cases,
* you should **not** use {@link Ext#onReady}.
*/