UNPKG

@qooxdoo/framework

Version:

The JS Framework for Coders

551 lines (474 loc) 17.4 kB
/* ************************************************************************ qooxdoo - the new era of web development http://qooxdoo.org Copyright: 2004-2011 1&1 Internet AG, Germany, http://www.1und1.de License: MIT: https://opensource.org/licenses/MIT See the LICENSE file in the project's top-level directory for details. Authors: * Martin Wittemann (martinwittemann) ************************************************************************ */ /** * The purpose of this class is to contain all checks about css. * * This class is used by {@link qx.core.Environment} and should not be used * directly. Please check its class comment for details how to use it. * * @internal * @ignore(WebKitCSSMatrix) * @require(qx.bom.Style) */ qx.Bootstrap.define("qx.bom.client.Css", { statics : { __WEBKIT_LEGACY_GRADIENT : null, /** * Checks what box model is used in the current environment. * @return {String} It either returns "content" or "border". * @internal */ getBoxModel : function() { var content = qx.bom.client.Engine.getName() !== "mshtml" || !qx.bom.client.Browser.getQuirksMode() ; return content ? "content" : "border"; }, /** * Returns the (possibly vendor-prefixed) name the browser uses for the * <code>textOverflow</code> style property. * * @return {String|null} textOverflow property name or <code>null</code> if * textOverflow is not supported. * @internal */ getTextOverflow : function() { return qx.bom.Style.getPropertyName("textOverflow"); }, /** * Checks if a placeholder could be used. * @return {Boolean} <code>true</code>, if it could be used. * @internal */ getPlaceholder : function() { var i = document.createElement("input"); return "placeholder" in i; }, /** * Returns the (possibly vendor-prefixed) name the browser uses for the * <code>appearance</code> style property. * * @return {String|null} appearance property name or <code>null</code> if * appearance is not supported. * @internal */ getAppearance : function() { return qx.bom.Style.getPropertyName("appearance"); }, /** * Returns the (possibly vendor-prefixed) name the browser uses for the * <code>borderRadius</code> style property. * * @return {String|null} borderRadius property name or <code>null</code> if * borderRadius is not supported. * @internal */ getBorderRadius : function() { return qx.bom.Style.getPropertyName("borderRadius"); }, /** * Returns the (possibly vendor-prefixed) name the browser uses for the * <code>boxShadow</code> style property. * * @return {String|null} boxShadow property name or <code>null</code> if * boxShadow is not supported. * @internal */ getBoxShadow : function() { return qx.bom.Style.getPropertyName("boxShadow"); }, /** * Returns the (possibly vendor-prefixed) name the browser uses for the * <code>borderImage</code> style property. * * @return {String|null} borderImage property name or <code>null</code> if * borderImage is not supported. * @internal */ getBorderImage : function() { return qx.bom.Style.getPropertyName("borderImage"); }, /** * Returns the type of syntax this client supports for its CSS border-image * implementation. Some browsers do not support the "fill" keyword defined * in the W3C draft (http://www.w3.org/TR/css3-background/) and will not * show the border image if it's set. Others follow the standard closely and * will omit the center image if "fill" is not set. * * @return {Boolean|null} <code>true</code> if the standard syntax is supported. * <code>null</code> if the supported syntax could not be detected. * @internal */ getBorderImageSyntax : function() { var styleName = qx.bom.client.Css.getBorderImage(); if (!styleName) { return null; } var el = document.createElement("div"); if (styleName === "borderImage") { // unprefixed implementation: check individual properties el.style[styleName] = 'url("foo.png") 4 4 4 4 fill stretch'; if (el.style.borderImageSource.indexOf("foo.png") >= 0 && el.style.borderImageSlice.indexOf("4 fill") >= 0 && el.style.borderImageRepeat.indexOf("stretch") >= 0) { return true; } } else { // prefixed implementation, assume no support for "fill" el.style[styleName] = 'url("foo.png") 4 4 4 4 stretch'; // serialized value is unreliable, so just a simple check if (el.style[styleName].indexOf("foo.png") >= 0) { return false; } } // unable to determine syntax return null; }, /** * Returns the (possibly vendor-prefixed) name the browser uses for the * <code>userSelect</code> style property. * * @return {String|null} userSelect property name or <code>null</code> if * userSelect is not supported. * @internal */ getUserSelect : function() { return qx.bom.Style.getPropertyName("userSelect"); }, /** * Returns the (possibly vendor-prefixed) value for the * <code>userSelect</code> style property that disables selection. For Gecko, * "-moz-none" is returned since "none" only makes the target element appear * as if its text could not be selected * * @internal * @return {String|null} the userSelect property value that disables * selection or <code>null</code> if userSelect is not supported */ getUserSelectNone : function() { var styleProperty = qx.bom.client.Css.getUserSelect(); if (styleProperty) { var el = document.createElement("span"); el.style[styleProperty] = "-moz-none"; return el.style[styleProperty] === "-moz-none" ? "-moz-none" : "none"; } return null; }, /** * Returns the (possibly vendor-prefixed) name the browser uses for the * <code>userModify</code> style property. * * @return {String|null} userModify property name or <code>null</code> if * userModify is not supported. * @internal */ getUserModify : function() { return qx.bom.Style.getPropertyName("userModify"); }, /** * Returns the vendor-specific name of the <code>float</code> style property * * @return {String|null} <code>cssFloat</code> for standards-compliant * browsers, <code>styleFloat</code> for legacy IEs, <code>null</code> if * the client supports neither property. * @internal */ getFloat : function() { var style = document.documentElement.style; return style.cssFloat !== undefined ? "cssFloat" : style.styleFloat !== undefined ? "styleFloat" : null; }, /** * Returns the (possibly vendor-prefixed) name this client uses for * <code>linear-gradient</code>. * http://dev.w3.org/csswg/css3-images/#linear-gradients * * @return {String|null} Prefixed linear-gradient name or <code>null</code> * if linear gradients are not supported * @internal */ getLinearGradient : function() { qx.bom.client.Css.__WEBKIT_LEGACY_GRADIENT = false; var value = "linear-gradient(0deg, #fff, #000)"; var el = document.createElement("div"); var style = qx.bom.Style.getAppliedStyle(el, "backgroundImage", value); if (!style) { //try old WebKit syntax (versions 528 - 534.16) value = "-webkit-gradient(linear,0% 0%,100% 100%,from(white), to(red))"; var style = qx.bom.Style.getAppliedStyle(el, "backgroundImage", value, false); if (style) { qx.bom.client.Css.__WEBKIT_LEGACY_GRADIENT = true; } } // not supported if (!style) { return null; } var match = /(.*?)\(/.exec(style); return match ? match[1] : null; }, /** * Returns <code>true</code> if the browser supports setting gradients * using the filter style. This usually only applies for IE browsers * starting from IE5.5. * http://msdn.microsoft.com/en-us/library/ms532997(v=vs.85).aspx * * @return {Boolean} <code>true</code> if supported. * @internal */ getFilterGradient : function() { return qx.bom.client.Css.__isFilterSupported( "DXImageTransform.Microsoft.Gradient", "startColorStr=#550000FF, endColorStr=#55FFFF00"); }, /** * Returns the (possibly vendor-prefixed) name this client uses for * <code>radial-gradient</code>. * * @return {String|null} Prefixed radial-gradient name or <code>null</code> * if radial gradients are not supported * @internal */ getRadialGradient : function() { var value = "radial-gradient(0px 0px, cover, red 50%, blue 100%)"; var el = document.createElement("div"); var style = qx.bom.Style.getAppliedStyle(el, "backgroundImage", value); if (!style) { return null; } var match = /(.*?)\(/.exec(style); return match ? match[1] : null; }, /** * Checks if **only** the old WebKit (version < 534.16) syntax for * linear gradients is supported, e.g. * <code>linear-gradient(0deg, #fff, #000)</code> * * @return {Boolean} <code>true</code> if the legacy syntax must be used * @internal */ getLegacyWebkitGradient : function() { if (qx.bom.client.Css.__WEBKIT_LEGACY_GRADIENT === null) { qx.bom.client.Css.getLinearGradient(); } return qx.bom.client.Css.__WEBKIT_LEGACY_GRADIENT; }, /** * Checks if rgba colors can be used: * http://www.w3.org/TR/2010/PR-css3-color-20101028/#rgba-color * * @return {Boolean} <code>true</code>, if rgba colors are supported. * @internal */ getRgba : function() { var el; try { el = document.createElement("div"); } catch (ex) { el = document.createElement(); } // try catch for IE try { el.style["color"] = "rgba(1, 2, 3, 0.5)"; if (el.style["color"].indexOf("rgba") != -1) { return true; } } catch (ex) {} return false; }, /** * Returns the (possibly vendor-prefixed) name the browser uses for the * <code>boxSizing</code> style property. * * @return {String|null} boxSizing property name or <code>null</code> if * boxSizing is not supported. * @internal */ getBoxSizing : function() { return qx.bom.Style.getPropertyName("boxSizing"); }, /** * Returns the browser-specific name used for the <code>display</code> style * property's <code>inline-block</code> value. * * @internal * @return {String|null} */ getInlineBlock : function() { var el = document.createElement("span"); el.style.display = "inline-block"; if (el.style.display == "inline-block") { return "inline-block"; } el.style.display = "-moz-inline-box"; if (el.style.display !== "-moz-inline-box") { return "-moz-inline-box"; } return null; }, /** * Checks if CSS opacity is supported * * @internal * @return {Boolean} <code>true</code> if opacity is supported */ getOpacity : function() { return (typeof document.documentElement.style.opacity == "string"); }, /** * Checks if CSS texShadow is supported * * @internal * @return {Boolean} <code>true</code> if textShadow is supported */ getTextShadow : function() { return !!qx.bom.Style.getPropertyName("textShadow"); }, /** * Returns <code>true</code> if the browser supports setting text shadow * using the filter style. This usually only applies for IE browsers * starting from IE5.5. * * @internal * @return {Boolean} <code>true</code> if textShadow is supported */ getFilterTextShadow : function() { return qx.bom.client.Css.__isFilterSupported( "DXImageTransform.Microsoft.Shadow", "color=#666666,direction=45"); }, /** * Checks if the given filter is supported. * * @param filterClass {String} The name of the filter class * @param initParams {String} Init values for the filter * @return {Boolean} <code>true</code> if the given filter is supported */ __isFilterSupported : function(filterClass, initParams) { var supported = false; var value = "progid:" + filterClass + "(" + initParams + ");"; var el = document.createElement("div"); document.body.appendChild(el); el.style.filter = value; if (el.filters && el.filters.length > 0 && el.filters.item(filterClass).enabled == true) { supported = true; } document.body.removeChild(el); return supported; }, /** * Checks if the Alpha Image Loader must be used to display transparent PNGs. * * @return {Boolean} <code>true</code> if the Alpha Image Loader is required */ getAlphaImageLoaderNeeded : function() { return qx.bom.client.Engine.getName() == "mshtml" && qx.bom.client.Browser.getDocumentMode() < 9; }, /** * Checks if pointer events are available. * * @internal * @return {Boolean} <code>true</code> if pointer events are supported. */ getPointerEvents : function() { var el = document.documentElement; // Check if browser reports that pointerEvents is a known style property if ("pointerEvents" in el.style) { // The property is defined in Opera and IE9 but setting it has no effect var initial = el.style.pointerEvents; el.style.pointerEvents = "auto"; // don't assume support if a nonsensical value isn't ignored el.style.pointerEvents = "foo"; var supported = el.style.pointerEvents == "auto"; el.style.pointerEvents = initial; return supported; } return false; }, /** * Returns which Flexbox syntax is supported by the browser. * <code>display: box;</code> old 2009 version of Flexbox. * <code>display: flexbox;</code> tweener phase in 2011. * <code>display: flex;</code> current specification. * @internal * @return {String} <code>flex</code>,<code>flexbox</code>,<code>box</code> or <code>null</code> */ getFlexboxSyntax : function() { var detectedSyntax = null; var detector = document.createElement("detect"); var flexSyntax = [{ value: "flex", syntax: "flex" }, { value: "-ms-flexbox", syntax: "flexbox" }, { value: "-webkit-flex", syntax: "flex" }]; for (var i = 0; i < flexSyntax.length; i++) { // old IEs will throw an "Invalid argument" exception here try { detector.style.display = flexSyntax[i].value; } catch(ex) { return null; } if (detector.style.display === flexSyntax[i].value) { detectedSyntax = flexSyntax[i].syntax; break; } } detector = null; return detectedSyntax; } }, defer : function(statics) { qx.core.Environment.add("css.textoverflow", statics.getTextOverflow); qx.core.Environment.add("css.placeholder", statics.getPlaceholder); qx.core.Environment.add("css.borderradius", statics.getBorderRadius); qx.core.Environment.add("css.boxshadow", statics.getBoxShadow); qx.core.Environment.add("css.gradient.linear", statics.getLinearGradient); qx.core.Environment.add("css.gradient.filter", statics.getFilterGradient); qx.core.Environment.add("css.gradient.radial", statics.getRadialGradient); qx.core.Environment.add("css.gradient.legacywebkit", statics.getLegacyWebkitGradient); qx.core.Environment.add("css.boxmodel", statics.getBoxModel); qx.core.Environment.add("css.rgba", statics.getRgba); qx.core.Environment.add("css.borderimage", statics.getBorderImage); qx.core.Environment.add("css.borderimage.standardsyntax", statics.getBorderImageSyntax); qx.core.Environment.add("css.usermodify", statics.getUserModify); qx.core.Environment.add("css.userselect", statics.getUserSelect); qx.core.Environment.add("css.userselect.none", statics.getUserSelectNone); qx.core.Environment.add("css.appearance", statics.getAppearance); qx.core.Environment.add("css.float", statics.getFloat); qx.core.Environment.add("css.boxsizing", statics.getBoxSizing); qx.core.Environment.add("css.inlineblock", statics.getInlineBlock); qx.core.Environment.add("css.opacity", statics.getOpacity); qx.core.Environment.add("css.textShadow", statics.getTextShadow); qx.core.Environment.add("css.textShadow.filter", statics.getFilterTextShadow); qx.core.Environment.add("css.alphaimageloaderneeded", statics.getAlphaImageLoaderNeeded); qx.core.Environment.add("css.pointerevents", statics.getPointerEvents); qx.core.Environment.add("css.flexboxSyntax", statics.getFlexboxSyntax); } });