X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/0494b8d9b9bb03ab6c22b34dae81261e3cd7e3e6..7a654f8d43fdb43d78b63d90528bed6e86b608cc:/src/core/src/Support.js diff --git a/src/core/src/Support.js b/src/core/src/Support.js new file mode 100644 index 00000000..c925915e --- /dev/null +++ b/src/core/src/Support.js @@ -0,0 +1,518 @@ +/** + * @class Ext.is + * + * Determines information about the current platform the application is running on. + * + * @singleton + */ +Ext.is = { + init : function(navigator) { + var platforms = this.platforms, + ln = platforms.length, + i, platform; + + navigator = navigator || window.navigator; + + for (i = 0; i < ln; i++) { + platform = platforms[i]; + this[platform.identity] = platform.regex.test(navigator[platform.property]); + } + + /** + * @property Desktop True if the browser is running on a desktop machine + * @type {Boolean} + */ + this.Desktop = this.Mac || this.Windows || (this.Linux && !this.Android); + /** + * @property Tablet True if the browser is running on a tablet (iPad) + */ + this.Tablet = this.iPad; + /** + * @property Phone True if the browser is running on a phone. + * @type {Boolean} + */ + this.Phone = !this.Desktop && !this.Tablet; + /** + * @property iOS True if the browser is running on iOS + * @type {Boolean} + */ + this.iOS = this.iPhone || this.iPad || this.iPod; + + /** + * @property Standalone Detects when application has been saved to homescreen. + * @type {Boolean} + */ + this.Standalone = !!window.navigator.standalone; + }, + + /** + * @property iPhone True when the browser is running on a iPhone + * @type {Boolean} + */ + platforms: [{ + property: 'platform', + regex: /iPhone/i, + identity: 'iPhone' + }, + + /** + * @property iPod True when the browser is running on a iPod + * @type {Boolean} + */ + { + property: 'platform', + regex: /iPod/i, + identity: 'iPod' + }, + + /** + * @property iPad True when the browser is running on a iPad + * @type {Boolean} + */ + { + property: 'userAgent', + regex: /iPad/i, + identity: 'iPad' + }, + + /** + * @property Blackberry True when the browser is running on a Blackberry + * @type {Boolean} + */ + { + property: 'userAgent', + regex: /Blackberry/i, + identity: 'Blackberry' + }, + + /** + * @property Android True when the browser is running on an Android device + * @type {Boolean} + */ + { + property: 'userAgent', + regex: /Android/i, + identity: 'Android' + }, + + /** + * @property Mac True when the browser is running on a Mac + * @type {Boolean} + */ + { + property: 'platform', + regex: /Mac/i, + identity: 'Mac' + }, + + /** + * @property Windows True when the browser is running on Windows + * @type {Boolean} + */ + { + property: 'platform', + regex: /Win/i, + identity: 'Windows' + }, + + /** + * @property Linux True when the browser is running on Linux + * @type {Boolean} + */ + { + property: 'platform', + regex: /Linux/i, + identity: 'Linux' + }] +}; + +Ext.is.init(); + +/** + * @class Ext.supports + * + * Determines information about features are supported in the current environment + * + * @singleton + */ +Ext.supports = { + init : function() { + var doc = document, + div = doc.createElement('div'), + tests = this.tests, + ln = tests.length, + i, test; + + div.innerHTML = [ + '
', + '
', + '
', + '
', + '
', + '
', + '
' + ].join(''); + + doc.body.appendChild(div); + + for (i = 0; i < ln; i++) { + test = tests[i]; + this[test.identity] = test.fn.call(this, doc, div); + } + + doc.body.removeChild(div); + }, + + /** + * @property CSS3BoxShadow True if document environment supports the CSS3 box-shadow style. + * @type {Boolean} + */ + CSS3BoxShadow: Ext.isDefined(document.documentElement.style.boxShadow), + + /** + * @property ClassList True if document environment supports the HTML5 classList API. + * @type {Boolean} + */ + ClassList: !!document.documentElement.classList, + + /** + * @property OrientationChange True if the device supports orientation change + * @type {Boolean} + */ + OrientationChange: ((typeof window.orientation != 'undefined') && ('onorientationchange' in window)), + + /** + * @property DeviceMotion True if the device supports device motion (acceleration and rotation rate) + * @type {Boolean} + */ + DeviceMotion: ('ondevicemotion' in window), + + /** + * @property Touch True if the device supports touch + * @type {Boolean} + */ + // is.Desktop is needed due to the bug in Chrome 5.0.375, Safari 3.1.2 + // and Safari 4.0 (they all have 'ontouchstart' in the window object). + Touch: ('ontouchstart' in window) && (!Ext.is.Desktop), + + tests: [ + /** + * @property Transitions True if the device supports CSS3 Transitions + * @type {Boolean} + */ + { + identity: 'Transitions', + fn: function(doc, div) { + var prefix = [ + 'webkit', + 'Moz', + 'o', + 'ms', + 'khtml' + ], + TE = 'TransitionEnd', + transitionEndName = [ + prefix[0] + TE, + 'transitionend', //Moz bucks the prefixing convention + prefix[2] + TE, + prefix[3] + TE, + prefix[4] + TE + ], + ln = prefix.length, + i = 0, + out = false; + div = Ext.get(div); + for (; i < ln; i++) { + if (div.getStyle(prefix[i] + "TransitionProperty")) { + Ext.supports.CSS3Prefix = prefix[i]; + Ext.supports.CSS3TransitionEnd = transitionEndName[i]; + out = true; + break; + } + } + return out; + } + }, + + /** + * @property RightMargin True if the device supports right margin. + * See https://bugs.webkit.org/show_bug.cgi?id=13343 for why this is needed. + * @type {Boolean} + */ + { + identity: 'RightMargin', + fn: function(doc, div, view) { + view = doc.defaultView; + return !(view && view.getComputedStyle(div.firstChild.firstChild, null).marginRight != '0px'); + } + }, + + /** + * @property TransparentColor True if the device supports transparent color + * @type {Boolean} + */ + { + identity: 'TransparentColor', + fn: function(doc, div, view) { + view = doc.defaultView; + return !(view && view.getComputedStyle(div.lastChild, null).backgroundColor != 'transparent'); + } + }, + + /** + * @property ComputedStyle True if the browser supports document.defaultView.getComputedStyle() + * @type {Boolean} + */ + { + identity: 'ComputedStyle', + fn: function(doc, div, view) { + view = doc.defaultView; + return view && view.getComputedStyle; + } + }, + + /** + * @property SVG True if the device supports SVG + * @type {Boolean} + */ + { + identity: 'Svg', + fn: function(doc) { + return !!doc.createElementNS && !!doc.createElementNS( "http:/" + "/www.w3.org/2000/svg", "svg").createSVGRect; + } + }, + + /** + * @property Canvas True if the device supports Canvas + * @type {Boolean} + */ + { + identity: 'Canvas', + fn: function(doc) { + return !!doc.createElement('canvas').getContext; + } + }, + + /** + * @property VML True if the device supports VML + * @type {Boolean} + */ + { + identity: 'Vml', + fn: function(doc) { + var d = doc.createElement("div"); + d.innerHTML = ""; + return (d.childNodes.length == 2); + } + }, + + /** + * @property Float True if the device supports CSS float + * @type {Boolean} + */ + { + identity: 'Float', + fn: function(doc, div) { + return !!div.lastChild.style.cssFloat; + } + }, + + /** + * @property AudioTag True if the device supports the HTML5 audio tag + * @type {Boolean} + */ + { + identity: 'AudioTag', + fn: function(doc) { + return !!doc.createElement('audio').canPlayType; + } + }, + + /** + * @property History True if the device supports HTML5 history + * @type {Boolean} + */ + { + identity: 'History', + fn: function() { + return !!(window.history && history.pushState); + } + }, + + /** + * @property CSS3DTransform True if the device supports CSS3DTransform + * @type {Boolean} + */ + { + identity: 'CSS3DTransform', + fn: function() { + return (typeof WebKitCSSMatrix != 'undefined' && new WebKitCSSMatrix().hasOwnProperty('m41')); + } + }, + + /** + * @property CSS3LinearGradient True if the device supports CSS3 linear gradients + * @type {Boolean} + */ + { + identity: 'CSS3LinearGradient', + fn: function(doc, div) { + var property = 'background-image:', + webkit = '-webkit-gradient(linear, left top, right bottom, from(black), to(white))', + w3c = 'linear-gradient(left top, black, white)', + moz = '-moz-' + w3c, + options = [property + webkit, property + w3c, property + moz]; + + div.style.cssText = options.join(';'); + + return ("" + div.style.backgroundImage).indexOf('gradient') !== -1; + } + }, + + /** + * @property CSS3BorderRadius True if the device supports CSS3 border radius + * @type {Boolean} + */ + { + identity: 'CSS3BorderRadius', + fn: function(doc, div) { + var domPrefixes = ['borderRadius', 'BorderRadius', 'MozBorderRadius', 'WebkitBorderRadius', 'OBorderRadius', 'KhtmlBorderRadius'], + pass = false, + i; + for (i = 0; i < domPrefixes.length; i++) { + if (document.body.style[domPrefixes[i]] !== undefined) { + return true; + } + } + return pass; + } + }, + + /** + * @property GeoLocation True if the device supports GeoLocation + * @type {Boolean} + */ + { + identity: 'GeoLocation', + fn: function() { + return (typeof navigator != 'undefined' && typeof navigator.geolocation != 'undefined') || (typeof google != 'undefined' && typeof google.gears != 'undefined'); + } + }, + /** + * @property MouseEnterLeave True if the browser supports mouseenter and mouseleave events + * @type {Boolean} + */ + { + identity: 'MouseEnterLeave', + fn: function(doc, div){ + return ('onmouseenter' in div && 'onmouseleave' in div); + } + }, + /** + * @property MouseWheel True if the browser supports the mousewheel event + * @type {Boolean} + */ + { + identity: 'MouseWheel', + fn: function(doc, div) { + return ('onmousewheel' in div); + } + }, + /** + * @property Opacity True if the browser supports normal css opacity + * @type {Boolean} + */ + { + identity: 'Opacity', + fn: function(doc, div){ + // Not a strict equal comparison in case opacity can be converted to a number. + if (Ext.isIE6 || Ext.isIE7 || Ext.isIE8) { + return false; + } + div.firstChild.style.cssText = 'opacity:0.73'; + return div.firstChild.style.opacity == '0.73'; + } + }, + /** + * @property Placeholder True if the browser supports the HTML5 placeholder attribute on inputs + * @type {Boolean} + */ + { + identity: 'Placeholder', + fn: function(doc) { + return 'placeholder' in doc.createElement('input'); + } + }, + + /** + * @property Direct2DBug True if when asking for an element's dimension via offsetWidth or offsetHeight, + * getBoundingClientRect, etc. the browser returns the subpixel width rounded to the nearest pixel. + * @type {Boolean} + */ + { + identity: 'Direct2DBug', + fn: function() { + return Ext.isString(document.body.style.msTransformOrigin); + } + }, + /** + * @property BoundingClientRect True if the browser supports the getBoundingClientRect method on elements + * @type {Boolean} + */ + { + identity: 'BoundingClientRect', + fn: function(doc, div) { + return Ext.isFunction(div.getBoundingClientRect); + } + }, + { + identity: 'IncludePaddingInWidthCalculation', + fn: function(doc, div){ + var el = Ext.get(div.childNodes[1].firstChild); + return el.getWidth() == 210; + } + }, + { + identity: 'IncludePaddingInHeightCalculation', + fn: function(doc, div){ + var el = Ext.get(div.childNodes[1].firstChild); + return el.getHeight() == 210; + } + }, + + /** + * @property ArraySort True if the Array sort native method isn't bugged. + * @type {Boolean} + */ + { + identity: 'ArraySort', + fn: function() { + var a = [1,2,3,4,5].sort(function(){ return 0; }); + return a[0] === 1 && a[1] === 2 && a[2] === 3 && a[3] === 4 && a[4] === 5; + } + }, + /** + * @property Range True if browser support document.createRange native method. + * @type {Boolean} + */ + { + identity: 'Range', + fn: function() { + return !!document.createRange; + } + }, + /** + * @property CreateContextualFragment True if browser support CreateContextualFragment range native methods. + * @type {Boolean} + */ + { + identity: 'CreateContextualFragment', + fn: function() { + var range = Ext.supports.Range ? document.createRange() : false; + + return range && !!range.createContextualFragment; + } + } + + ] +};