1 /* ************************************************************************
3 qooxdoo - the new era of web development
8 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org
11 LGPL: http://www.gnu.org/licenses/lgpl.html
12 EPL: http://www.eclipse.org/org/documents/epl-v10.php
13 See the LICENSE file in the project's top-level directory for details.
16 * Sebastian Werner (wpbasti)
17 * Andreas Ecker (ecker)
19 ************************************************************************ */
21 /* ************************************************************************
24 #require(qx.renderer.font.FontCache)
25 #after(qx.renderer.font.FontObject)
27 ************************************************************************ */
29 qx.OO.defineClass("qx.ui.basic.Label", qx.ui.basic.Terminator,
30 function(vHtml, vMnemonic)
32 qx.ui.basic.Terminator.call(this);
34 // Apply constructor arguments
39 if (vMnemonic != null) {
40 this.setMnemonic(vMnemonic);
43 // Prohibit stretching through layout handler
44 this.setAllowStretchX(false);
45 this.setAllowStretchY(false);
51 qx.Class._measureNodes = {};
58 ---------------------------------------------------------------------------
60 ---------------------------------------------------------------------------
63 qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "label" });
66 Any text string which can contain HTML, too
68 qx.OO.addProperty({ name : "html" });
71 The alignment of the text.
73 qx.OO.addProperty({ name : "textAlign", type : "string", defaultValue : "left", possibleValues : [ "left", "center", "right", "justify" ] });
76 The styles which should be copied
78 qx.OO.addProperty({ name : "fontPropertiesProfile", type : "string", defaultValue : "default", possibleValues : [ "none", "default", "extended", "multiline", "extendedmultiline", "all" ] });
81 A single character which will be underlined inside the text.
83 qx.OO.addProperty({ name : "mnemonic", type : "string" });
86 The font property describes how to paint the font on the widget.
88 qx.OO.addProperty({ name : "font", type : "object", instance : "qx.renderer.font.Font", convert : qx.renderer.font.FontCache, allowMultipleArguments : true });
93 qx.OO.addProperty({ name : "wrap", type : "boolean", defaultValue : true });
103 /* ************************************************************************
104 Class data, properties and methods
105 ************************************************************************ */
108 ---------------------------------------------------------------------------
110 ---------------------------------------------------------------------------
113 qx.ui.basic.Label.SYMBOL_ELLIPSIS = String.fromCharCode(8230);
114 qx.ui.basic.Label.SUPPORT_NATIVE_ELLIPSIS = qx.core.Client.getInstance().isMshtml();
116 // these are the properties what will be copied to the measuring frame.
117 qx.ui.basic.Label._fontProperties =
121 "default" : ["fontFamily", "fontSize", "fontStyle", "fontWeight", "textDecoration"],
122 "extended" : ["fontFamily", "fontSize", "fontStyle", "fontWeight", "letterSpacing", "textDecoration", "textTransform", "whiteSpace", "wordSpacing"],
124 "multiline" : ["fontFamily", "fontSize", "fontStyle", "fontWeight", "textDecoration", "lineHeight", "wordWrap"],
125 "extendedmultiline" : ["fontFamily", "fontSize", "fontStyle", "fontWeight", "letterSpacing", "textDecoration", "textTransform", "whiteSpace", "wordSpacing", "lineHeight", "wordBreak", "wordWrap", "quotes"],
127 "all" : ["fontFamily", "fontSize", "fontStyle", "fontVariant", "fontWeight", "letterSpacing", "lineBreak", "lineHeight", "quotes", "textDecoration", "textIndent", "textShadow", "textTransform", "textUnderlinePosition", "whiteSpace", "wordBreak", "wordSpacing", "wordWrap"]
131 qx.ui.basic.Label.createMeasureNode = function(vId)
133 var vNode = qx.ui.basic.Label._measureNodes[vId];
137 vNode = document.createElement("div");
138 var vStyle = vNode.style;
140 vStyle.width = vStyle.height = "auto";
141 vStyle.visibility = "hidden";
142 vStyle.position = "absolute";
143 vStyle.zIndex = "-1";
145 document.body.appendChild(vNode);
147 qx.ui.basic.Label._measureNodes[vId] = vNode;
160 /* ************************************************************************
161 Instance data, properties and methods
162 ************************************************************************ */
165 ---------------------------------------------------------------------------
167 ---------------------------------------------------------------------------
170 qx.Proto._localized = false;
171 qx.Proto._htmlContent = "";
172 qx.Proto._htmlMode = false;
173 qx.Proto._hasMnemonic = false;
174 qx.Proto._mnemonicHtml = "";
175 qx.Proto._mnemonicTest = null;
177 qx.Proto._modifyHtml = function(propValue, propOldValue, propData)
179 this._localized = this.getHtml() instanceof qx.locale.LocalizedString;
184 qx.Proto._updateHtml = function()
188 this._htmlContent = this.getHtml().toString();
189 qx.locale.Manager.getInstance().addEventListener("changeLocale", this._updateHtml, this);
193 this._htmlContent = this.getHtml() || "";
194 qx.locale.Manager.getInstance().removeEventListener("changeLocale", this._updateHtml, this);
197 this._htmlMode = qx.util.Validation.isValidString(this._htmlContent) && this._htmlContent.match(/<.*>/) ? true : false;
199 if (this._isCreated) {
200 this._applyContent();
205 qx.Proto._modifyTextAlign = function(propValue, propOldValue, propData)
207 this.setStyleProperty("textAlign", propValue);
211 qx.Proto._modifyMnemonic = function(propValue, propOldValue, propData)
213 this._hasMnemonic = qx.util.Validation.isValidString(propValue) && propValue.length == 1;
215 this._mnemonicHtml = this._hasMnemonic ? "(<span style=\"text-decoration:underline\">" + propValue + "</span>)" : "";
216 this._mnemonicTest = this._hasMnemonic ? new RegExp("^(((<([^>]|" + propValue + ")+>)|(&([^;]|" + propValue + ")+;)|[^&" + propValue + "])*)(" + propValue + ")", "i") : null;
221 qx.Proto._modifyFont = function(propValue, propOldValue, propData)
223 this._invalidatePreferredInnerDimensions();
226 propValue._applyWidget(this);
227 } else if (propOldValue) {
228 propOldValue._resetWidget(this);
234 qx.Proto._modifyWrap = function(propValue, propOldValue, propData)
236 this.setStyleProperty("whiteSpace", propValue ? "normal" : "nowrap");
245 ---------------------------------------------------------------------------
246 HELPER FOR PREFERRED DIMENSION
247 ---------------------------------------------------------------------------
250 qx.Proto._computeObjectNeededDimensions = function()
253 var vNode = this._copyStyles();
256 var vHtml = this._htmlContent;
258 // test for mnemonic and fix content
259 if (this._hasMnemonic && !this._mnemonicTest.test(vHtml)) {
260 vHtml += this._mnemonicHtml;
264 vNode.innerHTML = vHtml;
267 this._cachedPreferredInnerWidth = vNode.scrollWidth;
268 this._cachedPreferredInnerHeight = vNode.scrollHeight;
271 qx.Proto._copyStyles = function()
273 var vProps = this.getFontPropertiesProfile();
274 var vNode = qx.ui.basic.Label.createMeasureNode(vProps);
275 var vUseProperties=qx.ui.basic.Label._fontProperties[vProps];
276 var vUsePropertiesLength=vUseProperties.length-1;
277 var vProperty=vUseProperties[vUsePropertiesLength--];
279 var vStyle = vNode.style;
287 vStyle[vProperty] = qx.util.Validation.isValid(vTemp = this.getStyleProperty([vProperty])) ? vTemp : "";
288 } while(vProperty=vUseProperties[vUsePropertiesLength--]);
299 ---------------------------------------------------------------------------
301 ---------------------------------------------------------------------------
304 qx.Proto._computePreferredInnerWidth = function()
306 this._computeObjectNeededDimensions();
307 return this._cachedPreferredInnerWidth;
310 qx.Proto._computePreferredInnerHeight = function()
312 this._computeObjectNeededDimensions();
313 return this._cachedPreferredInnerHeight;
322 ---------------------------------------------------------------------------
324 ---------------------------------------------------------------------------
327 qx.Proto._postApply = function()
329 var vHtml = this._htmlContent;
330 var vElement = this._getTargetNode();
331 var vMnemonicMode = 0;
333 if (qx.util.Validation.isInvalidString(vHtml)) {
334 vElement.innerHTML = "";
338 if (this._hasMnemonic) {
339 vMnemonicMode = this._mnemonicTest.test(vHtml) ? 1 : 2;
342 // works only with text, don't use when wrap is enabled
343 if (!this._htmlMode && !this.getWrap())
345 switch(this._computedWidthType)
347 case qx.ui.core.Widget.TYPE_PIXEL:
348 case qx.ui.core.Widget.TYPE_PERCENT:
350 //carstenl: enabled truncation code for flex sizing, too. Appears to work except for the
351 // truncation code (gecko version), which I have disabled (see below).
352 case qx.ui.core.Widget.TYPE_FLEX:
353 var vNeeded = this.getPreferredInnerWidth();
354 var vInner = this.getInnerWidth();
356 if (vInner < vNeeded)
358 vElement.style.overflow = "hidden";
360 if (qx.ui.basic.Label.SUPPORT_NATIVE_ELLIPSIS)
362 vElement.style.textOverflow = "ellipsis";
363 vHtml += this._mnemonicHtml;
367 var vMeasureNode = this._copyStyles();
369 var vSplitString = vHtml.split(" ");
370 var vSplitLength = vSplitString.length;
372 var vWordIterator = 0;
373 var vCharaterIterator = 0;
375 var vPost = qx.ui.basic.Label.SYMBOL_ELLIPSIS;
377 var vUseInnerText = true;
378 if (vMnemonicMode == 2)
380 var vPost = this._mnemonicHtml + vPost;
381 vUseInnerText = false;
384 // Measure Words (if more than one)
385 if (vSplitLength > 1)
389 for (vWordIterator=0; vWordIterator<vSplitLength; vWordIterator++)
391 vSplitTemp.push(vSplitString[vWordIterator]);
393 var vLabelText = vSplitTemp.join(" ") + vPost;
395 qx.dom.Element.setTextContent(vMeasureNode, vLabelText);
397 vMeasureNode.innerHTML = vLabelText;
400 if ((vMeasureNode.scrollWidth > vInner)
401 /* carstenl: The following code (truncate the text to fit in the available
402 * space, append ellipsis to indicate truncation) did not reliably
403 * work in my tests. Problem was that sometimes the measurer returned
404 * insanely high values for short texts, like "I..." requiring 738 px.
406 * I don't have time to examine this code in detail. Since all of my
407 * tests used flex width and the truncation code never was intended
408 * for this, I am disabling truncation if flex is active.
410 && (this._computedWidthType != qx.ui.core.Widget.TYPE_FLEX)){
415 // Remove last word which does not fit
418 // Building new temportary array
419 vSplitTemp = [ vSplitTemp.join(" ") ];
421 // Extracting remaining string
422 vCharaterString = vHtml.replace(vSplitTemp[0], "");
427 vCharaterString = vHtml;
430 var vCharaterLength = vCharaterString.length;
433 for (var vCharaterIterator=0; vCharaterIterator<vCharaterLength; vCharaterIterator++)
435 vSplitTemp.push(vCharaterString.charAt(vCharaterIterator));
437 var vLabelText = vSplitTemp.join("") + vPost;
439 qx.dom.Element.setTextContent(vMeasureNode, vLabelText);
441 vMeasureNode.innerHTML = vLabelText;
444 if (vMeasureNode.scrollWidth > vInner) {
449 // Remove last char which does not fit
452 // Add mnemonic and ellipsis symbol
453 vSplitTemp.push(vPost);
455 // Building Final HTML String
456 vHtml = vSplitTemp.join("");
463 vHtml += this._mnemonicHtml;
469 vElement.style.overflow = "";
471 if (qx.ui.basic.Label.SUPPORT_NATIVE_ELLIPSIS) {
472 vElement.style.textOverflow = "";
477 if (vMnemonicMode == 1)
479 // re-test: needed to make ellipsis handling correct
480 this._mnemonicTest.test(vHtml);
481 vHtml = RegExp.$1 + "<span style=\"text-decoration:underline\">" + RegExp.$7 + "</span>" + RegExp.rightContext;
484 return this._postApplyHtml(vElement, vHtml, vMnemonicMode);
488 qx.Proto._postApplyHtml = function(vElement, vHtml, vMnemonicMode)
490 if (this._htmlMode || vMnemonicMode > 0)
492 vElement.innerHTML = vHtml;
497 qx.dom.Element.setTextContent(vElement, vHtml);
499 vElement.innerHTML = vHtml;