UNPKG

@qooxdoo/framework

Version:

The JS Framework for Coders

369 lines (305 loc) 9.98 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) ************************************************************************ */ /** * Cross browser abstractions to work with labels. */ qx.Bootstrap.define("qx.bom.Label", { /* ***************************************************************************** STATICS ***************************************************************************** */ statics : { /** @type {Map} Contains all supported styles */ __styles : { fontFamily : 1, fontSize : 1, fontWeight : 1, fontStyle : 1, lineHeight : 1 }, /** * Generates the helper DOM element for text measuring * * @return {Element} Helper DOM element */ __prepareText : function() { var el = this.__createMeasureElement(false); document.body.insertBefore(el, document.body.firstChild); return this._textElement = el; }, /** * Generates the helper DOM element for HTML measuring * * @return {Element} Helper DOM element */ __prepareHtml : function() { var el = this.__createMeasureElement(true); document.body.insertBefore(el, document.body.firstChild); return this._htmlElement = el; }, /** * Creates the measure element * * @param html {Boolean?false} Whether HTML markup should be used. * @return {Element} The measure element */ __createMeasureElement : function(html) { var el = qx.dom.Element.create("div"); var style = el.style; style.width = style.height = "auto"; style.left = style.top = "-1000px"; style.visibility = "hidden"; style.position = "absolute"; style.overflow = "visible"; style.display = "block"; if (html) { style.whiteSpace = "normal"; } else { style.whiteSpace = "nowrap"; if (!qx.core.Environment.get("css.textoverflow") && qx.core.Environment.get("html.xul")) { var inner = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "label"); // Force style inheritance for font styles to omit usage of // CSS "label" selector, See bug #1349 for details. var style = inner.style; style.padding = "0"; style.margin = "0"; style.width = "auto"; for (var key in this.__styles) { style[key] = "inherit"; } el.appendChild(inner); } } return el; }, /** * Returns a map of all styles which should be applied as * a basic set. * * @param html {Boolean?false} Whether HTML markup should be used. * @return {Map} Initial styles which should be applied to a label element. */ __getStyles : function(html) { var styles = {}; styles.overflow = "hidden"; if (html) { styles.whiteSpace = "normal"; } else if (!qx.core.Environment.get("css.textoverflow") && qx.core.Environment.get("html.xul")) { styles.display = "block"; } else { styles.whiteSpace = "nowrap"; styles[qx.core.Environment.get("css.textoverflow")] = "ellipsis"; } return styles; }, /** * Creates a label. * * The default mode is 'text' which means that the overlapping text is cut off * using ellipsis automatically. Text wrapping is disabled in this mode * as well. Spaces are normalized. Umlauts and other special symbols are only * allowed in unicode mode as normal characters. * * In the HTML mode you can insert any HTML, but loose the capability to cut * of overlapping text. Automatic text wrapping is enabled by default. * * It is not possible to modify the mode afterwards. * * @param content {String} Content of the label * @param html {Boolean?false} Whether HTML markup should be used. * @param win {Window?null} Window to create the element for * @return {Element} The created iframe node */ create : function(content, html, win) { if (!win) { win = window; } var el = win.document.createElement("div"); if (html) { el.useHtml = true; } if (!qx.core.Environment.get("css.textoverflow") && qx.core.Environment.get("html.xul")) { // Gecko as of Firefox 2.x and 3.0 does not support ellipsis // for text overflow. We use this feature from XUL instead. var xulel = win.document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "label"); var style = xulel.style; style.cursor = "inherit"; style.color = "inherit"; style.overflow = "hidden"; style.maxWidth = "100%"; style.padding = "0"; style.margin = "0"; style.width = "auto"; // Force style inheritance for font styles to omit usage of // CSS "label" selector, See bug #1349 for details. for (var key in this.__styles) { xulel.style[key] = "inherit"; } xulel.setAttribute("crop", "end"); el.appendChild(xulel); } else { qx.bom.element.Style.setStyles(el, this.__getStyles(html)); } if (content) { this.setValue(el, content); } return el; }, /** Sanitizer function */ __sanitizer : null, /** * Sets a function to sanitize values. It will be used by {@link #setValue}. * The function to sanitize will get the <code>string</code> value and * should return a sanitized / cleared <code>string</code>. * * @param func {Function | null} Function to sanitize / clean HTML code * from given string parameter */ setSanitizer : function(func) { if (qx.core.Environment.get("qx.debug")) { if (func) { qx.core.Assert.assertFunction(func); } } qx.bom.Label.__sanitizer = func; }, /** * Sets the content of the element. * * The possibilities of the value depends on the mode * defined using {@link #create}. * * @param element {Element} DOM element to modify. * @param value {String} Content to insert. */ setValue : function(element, value) { value = value || ""; if (element.useHtml) { if (qx.bom.Label.__sanitizer && typeof(qx.bom.Label.__sanitizer) === "function") { value = qx.bom.Label.__sanitizer(value); } element.innerHTML = value; } else if (!qx.core.Environment.get("css.textoverflow") && qx.core.Environment.get("html.xul")) { element.firstChild.setAttribute("value", value); } else { qx.bom.element.Attribute.set(element, "text", value); } }, /** * Returns the content of the element. * * @param element {Element} DOM element to query. * @return {String} Content stored in the element. */ getValue : function(element) { if (element.useHtml) { return element.innerHTML; } else if (!qx.core.Environment.get("css.textoverflow") && qx.core.Environment.get("html.xul")) { return element.firstChild.getAttribute("value") || ""; } else { return qx.bom.element.Attribute.get(element, "text"); } }, /** * Returns the preferred dimensions of the given HTML content. * * @param content {String} The HTML markup to measure * @param styles {Map?null} Optional styles to apply * @param width {Integer} To support width for height it is possible to limit the width * @return {Map} A map with preferred <code>width</code> and <code>height</code>. */ getHtmlSize : function(content, styles, width) { var element = this._htmlElement || this.__prepareHtml(); // apply width element.style.width = width != undefined ? width + "px" : "auto"; // insert content element.innerHTML = content; return this.__measureSize(element, styles); }, /** * Returns the preferred dimensions of the given text. * * @param text {String} The text to measure * @param styles {Map} Optional styles to apply * @return {Map} A map with preferred <code>width</code> and <code>height</code>. */ getTextSize : function(text, styles) { var element = this._textElement || this.__prepareText(); if (!qx.core.Environment.get("css.textoverflow") && qx.core.Environment.get("html.xul")) { element.firstChild.setAttribute("value", text); } else { qx.bom.element.Attribute.set(element, "text", text); } return this.__measureSize(element, styles); }, /** * Measure the size of the given element * * @param element {Element} The element to measure * @param styles {Map?null} Optional styles to apply * @return {Map} A map with preferred <code>width</code> and <code>height</code>. */ __measureSize : function(element, styles) { // sync styles var keys = this.__styles; if (!styles) { styles = {}; } for (var key in keys) { element.style[key] = styles[key] || ""; } // detect size var size = qx.bom.element.Dimension.getSize(element); // all modern browser are needing one more pixel for width size.width++; return size; } } });