UNPKG

@qooxdoo/framework

Version:

The JS Framework for Coders

433 lines (381 loc) 13.2 kB
/* ************************************************************************ qooxdoo - the new era of web development http://qooxdoo.org Copyright: 2004-2008 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: * Sebastian Werner (wpbasti) * Fabian Jakobs (fjakobs) ************************************************************************ */ /** * Contains information about images (size, format, clipping, ...) and * other resources like CSS files, local data, ... */ qx.Class.define("qx.util.ResourceManager", { extend : qx.core.Object, type : "singleton", /* ***************************************************************************** CONSTRUCTOR ***************************************************************************** */ construct : function() { this.base(arguments); }, /* ***************************************************************************** STATICS ***************************************************************************** */ statics : { /** @type {Map} the shared image registry */ __registry : qx.$$resources || {}, /** @type {Map} prefix per library used in HTTPS mode for IE */ __urlPrefix : {} }, /* ***************************************************************************** MEMBERS ***************************************************************************** */ members : { /** * Detects whether there is a high-resolution image available. * A high-resolution image is assumed to have the same file name as * the parameter source, but with a pixelRatio identifier before the file * extension, like "@2x". * Medium Resolution: "example.png", high-resolution: "example@2x.png" * * @param lowResImgSrc {String} source of the low resolution image. * @param factor {Number} Factor to find the right image. If not set calculated by getDevicePixelRatio() * @return {String|Boolean} If a high-resolution image source. */ findHighResolutionSource: function(lowResImgSrc, factor) { var pixelRatioCandidates = ["3", "2", "1.5"]; // Calculate the optimal ratio, based on the rem scale factor of the application and the device pixel ratio. if (!factor) { factor = parseFloat(qx.bom.client.Device.getDevicePixelRatio().toFixed(2)); } if (factor <= 1) { return false; } var i = pixelRatioCandidates.length; while (i > 0 && factor > pixelRatioCandidates[--i]) {} var hiResImgSrc; var k; // Search for best img with a higher resolution. for (k = i; k >= 0; k--) { hiResImgSrc = this.getHighResolutionSource(lowResImgSrc, pixelRatioCandidates[k]); if (hiResImgSrc) { return hiResImgSrc; } } // Search for best img with a lower resolution. for (k = i + 1; k < pixelRatioCandidates.length; k++) { hiResImgSrc = this.getHighResolutionSource(lowResImgSrc, pixelRatioCandidates[k]); if (hiResImgSrc) { return hiResImgSrc; } } return null; }, /** * Returns the source name for the high-resolution image based on the passed * parameters. * @param source {String} the source of the medium resolution image. * @param pixelRatio {Number} the pixel ratio of the high-resolution image. * @return {String} the high-resolution source name or null if no source could be found. */ getHighResolutionSource : function(source, pixelRatio) { var fileExtIndex = source.lastIndexOf('.'); if (fileExtIndex > -1) { var pixelRatioIdentifier = "@" + pixelRatio + "x"; var candidate = source.slice(0, fileExtIndex) + pixelRatioIdentifier + source.slice(fileExtIndex); if(this.has(candidate)) { return candidate; } } return null; }, /** * Get all known resource IDs. * * @param pathfragment{String|null|undefined} an optional path fragment to check against with id.indexOf(pathfragment) * @return {Array|null} an array containing the IDs or null if the registry is not initialized */ getIds : function(pathfragment) { var registry = this.self(arguments).__registry; if(!registry) { return null; } var ids = []; for (var id in registry) { if (registry.hasOwnProperty(id)) { if(pathfragment && id.indexOf(pathfragment) == -1) { continue; } ids.push(id); } } return ids; }, /** * Whether the registry has information about the given resource. * * @param id {String} The resource to get the information for * @return {Boolean} <code>true</code> when the resource is known. */ has : function(id) { return !!this.self(arguments).__registry[id]; }, /** * Get information about an resource. * * @param id {String} The resource to get the information for * @return {Array} Registered data or <code>null</code> */ getData : function(id) { return this.self(arguments).__registry[id] || null; }, /** * Returns the width of the given resource ID, * when it is not a known image <code>0</code> is * returned. * * @param id {String} Resource identifier * @return {Integer} The image width, maybe <code>null</code> when the width is unknown */ getImageWidth : function(id) { var size; if (id && id.startsWith("@")) { var part = id.split("/"); size = parseInt(part[2],10); if (size) { id = part[0]+"/"+part[1]; } } var entry = this.self(arguments).__registry[id]; // [ width, height, codepoint ] if (size && entry) { var width = Math.ceil(size / entry[1] * entry[0]); return width; } return entry ? entry[0] : null; }, /** * Returns the height of the given resource ID, * when it is not a known image <code>0</code> is * returned. * * @param id {String} Resource identifier * @return {Integer} The image height, maybe <code>null</code> when the height is unknown */ getImageHeight : function(id) { if (id && id.startsWith("@")) { var part = id.split("/"); var size = parseInt(part[2],10); if (size) { return size; } } var entry = this.self(arguments).__registry[id]; return entry ? entry[1] : null; }, /** * Returns the format of the given resource ID, * when it is not a known image <code>null</code> * is returned. * * @param id {String} Resource identifier * @return {String} File format of the image */ getImageFormat : function(id) { if (id && id.startsWith("@")) { return "font"; } var entry = this.self(arguments).__registry[id]; return entry ? entry[2] : null; }, /** * Returns the format of the combined image (png, gif, ...), if the given * resource identifier is an image contained in one, or the empty string * otherwise. * * @param id {String} Resource identifier * @return {String} The type of the combined image containing id */ getCombinedFormat : function(id) { var clippedtype = ""; var entry = this.self(arguments).__registry[id]; var isclipped = entry && entry.length > 4 && typeof(entry[4]) == "string" && this.constructor.__registry[entry[4]]; if (isclipped){ var combId = entry[4]; var combImg = this.constructor.__registry[combId]; clippedtype = combImg[2]; } return clippedtype; }, /** * Converts the given resource ID to a full qualified URI * * @param id {String} Resource ID * @return {String} Resulting URI */ toUri : function(id) { if (id == null) { return id; } var entry = this.self(arguments).__registry[id]; if (!entry) { return id; } if (typeof entry === "string") { var lib = entry; } else { var lib = entry[3]; // no lib reference // may mean that the image has been registered dynamically if (!lib) { return id; } } var urlPrefix = ""; if ((qx.core.Environment.get("engine.name") == "mshtml") && qx.core.Environment.get("io.ssl")) { urlPrefix = this.self(arguments).__urlPrefix[lib]; } return urlPrefix + qx.util.LibraryManager.getInstance().get(lib, "resourceUri") + "/" + id; }, /** * Construct a data: URI for an image resource. * * Constructs a data: URI for a given resource id, if this resource is * contained in a base64 combined image. If this is not the case (e.g. * because the combined image has not been loaded yet), returns the direct * URI to the image file itself. * * @param resid {String} resource id of the image * @return {String} "data:" or "http:" URI */ toDataUri : function (resid) { var resentry = this.constructor.__registry[resid]; var combined = resentry ? this.constructor.__registry[resentry[4]] : null; var uri; if (combined) { var resstruct = combined[4][resid]; uri = "data:image/" + resstruct["type"] + ";" + resstruct["encoding"] + "," + resstruct["data"]; } else { uri = this.toUri(resid); } return uri; }, /** * Checks whether a given resource id for an image is a font handle. * * @param resid {String} resource id of the image * @return {Boolean} True if it's a font URI */ isFontUri : function (resid) { return resid ? resid.startsWith("@") : false; } }, defer : function(statics) { if ((qx.core.Environment.get("engine.name") == "mshtml")) { // To avoid a "mixed content" warning in IE when the application is // delivered via HTTPS a prefix has to be added. This will transform the // relative URL to an absolute one in IE. // Though this warning is only displayed in conjunction with images which // are referenced as a CSS "background-image", every resource path is // changed when the application is served with HTTPS. if (qx.core.Environment.get("io.ssl")) { for (var lib in qx.$$libraries) { var resourceUri; if (qx.util.LibraryManager.getInstance().get(lib, "resourceUri")) { resourceUri = qx.util.LibraryManager.getInstance().get(lib, "resourceUri"); } else { // default for libraries without a resourceUri set statics.__urlPrefix[lib] = ""; continue; } var href; //first check if there is base url set var baseElements = document.getElementsByTagName("base"); if (baseElements.length > 0) { href = baseElements[0].href; } // It is valid to to begin a URL with "//" so this case has to // be considered. If the to resolved URL begins with "//" the // manager prefixes it with "https:" to avoid any problems for IE if (resourceUri.match(/^\/\//) != null) { statics.__urlPrefix[lib] = window.location.protocol; } // If the resourceUri begins with a single slash, include the current // hostname else if (resourceUri.match(/^\//) != null) { if (href) { statics.__urlPrefix[lib] = href; } else { statics.__urlPrefix[lib] = window.location.protocol + "//" + window.location.host; } } // If the resolved URL begins with "./" the final URL has to be // put together using the document.URL property. // IMPORTANT: this is only applicable for the source version else if (resourceUri.match(/^\.\//) != null) { var url = document.URL; statics.__urlPrefix[lib] = url.substring(0, url.lastIndexOf("/") + 1); } else if (resourceUri.match(/^http/) != null) { // Let absolute URLs pass through statics.__urlPrefix[lib] = ""; } else { if (!href) { // check for parameters with URLs as value var index = window.location.href.indexOf("?"); if (index == -1) { href = window.location.href; } else { href = window.location.href.substring(0, index); } } statics.__urlPrefix[lib] = href.substring(0, href.lastIndexOf("/") + 1); } } } } } });