1 /*
  2  * ***** BEGIN LICENSE BLOCK *****
  3  * Zimbra Collaboration Suite Web Client
  4  * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2013, 2014, 2015, 2016 Synacor, Inc.
  5  *
  6  * The contents of this file are subject to the Common Public Attribution License Version 1.0 (the "License");
  7  * you may not use this file except in compliance with the License.
  8  * You may obtain a copy of the License at: https://www.zimbra.com/license
  9  * The License is based on the Mozilla Public License Version 1.1 but Sections 14 and 15
 10  * have been added to cover use of software over a computer network and provide for limited attribution
 11  * for the Original Developer. In addition, Exhibit A has been modified to be consistent with Exhibit B.
 12  *
 13  * Software distributed under the License is distributed on an "AS IS" basis,
 14  * WITHOUT WARRANTY OF ANY KIND, either express or implied.
 15  * See the License for the specific language governing rights and limitations under the License.
 16  * The Original Code is Zimbra Open Source Web Client.
 17  * The Initial Developer of the Original Code is Zimbra, Inc.  All rights to the Original Code were
 18  * transferred by Zimbra, Inc. to Synacor, Inc. on September 14, 2015.
 19  *
 20  * All portions of the code are Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2013, 2014, 2015, 2016 Synacor, Inc. All Rights Reserved.
 21  * ***** END LICENSE BLOCK *****
 22  */
 23 
 24 /**
 25  * @overview
 26  * This file defines a label.
 27  *
 28  */
 29 
 30 /**
 31  * Creates a label.
 32  * @constructor
 33  * @class
 34  * This class represents a label, which consists of an image and/or text. It is used
 35  * both as a concrete class and as the base class for {@link DwtButton}. The label
 36  * components are managed within a table. The label can be enabled or disabled, which are reflected in 
 37  * its display. A disabled label looks greyed out.
 38  * 
 39  * <h4>CSS</h4>
 40  * <ul>
 41  * <li><code>.className table</code> - the label table</li>
 42  * <li><code>.className .Icon</code> - class name for the icon image cell</li>
 43  * <li><code>.className .Text</code> - enabled text cell</li>
 44  * <li><code>.className .DisabledText</code> - disabled text cell</li>
 45  * </ul>
 46  * 
 47  * <h4>Keyboard Actions</h4>
 48  * None
 49  * 
 50  * <h4>Events</h4>
 51  * None
 52  * 
 53  * @author Ross Dargahi
 54  * 
 55  * @param {hash}		params		the hash of parameters
 56  * @param	{DwtComposite}	params.parent	the parent widget
 57  * @param	{constant}	params.style		the label style: May be one of: {@link DwtLabel.IMAGE_LEFT} 
 58  * 											or {@link DwtLabel.IMAGE_RIGHT} arithmetically or'd (|) with  one of:
 59  * 											{@link DwtLabel.ALIGN_LEFT}, {@link DwtLabel.ALIGN_CENTER}, or {@link DwtLabel.ALIGN_LEFT}
 60  * 											The first determines were in the label the icon will appear (if one is set), the second
 61  * 											determine how the content of the label will be aligned. The default value for
 62  * 											this parameter is: {@link DwtLabel.IMAGE_LEFT} | {@link DwtLabel.ALIGN_CENTER}
 63  * @param	{string}	params.className	the CSS class
 64  * @param	{constant}	params.posStyle		the positioning style (see {@link DwtControl})
 65  * @param	{string}	params.id			the to use for the control HTML element
 66  * @param	{number}	params.index 		the index at which to add this control among parent's children
 67  *        
 68  * @extends DwtComposite
 69  */
 70 DwtLabel = function(params) {
 71 	if (arguments.length == 0) { return; }
 72 	params = Dwt.getParams(arguments, DwtLabel.PARAMS);
 73 	
 74 	params.className = params.className || "DwtLabel";
 75 	DwtComposite.call(this, params);
 76 
 77 	/**
 78 	 * The label style. See the constructor for more info.
 79 	 */
 80 	this._style = params.style || (DwtLabel.IMAGE_LEFT | DwtLabel.ALIGN_CENTER);
 81 	
 82 	/**
 83 	 * The label text background color.
 84 	 */
 85 	this._textBackground = null;
 86 	
 87 	/**
 88 	 * The label text foreground color.
 89 	 */
 90 	this._textForeground = null;
 91 
 92     this._createHtml(params.template);
 93     //MOW:  this.setCursor("default");
 94 }
 95 
 96 DwtLabel.PARAMS = ["parent", "style", "className", "posStyle", "id", "index"];
 97 
 98 DwtLabel.prototype = new DwtComposite;
 99 DwtLabel.prototype.constructor = DwtLabel;
100 
101 DwtLabel.prototype.isFocusable = true;
102 
103 /**
104  * Returns a string representation of the object.
105  * 
106  * @return		{string}		a string representation of the object
107  */
108 DwtLabel.prototype.toString =
109 function() {
110 	return "DwtLabel";
111 }
112 
113 //
114 // Constants
115 //
116 
117 // display styles
118 /**
119  * Defines the "left" align image (i.e. align to the left of text, if both present).
120  */
121 DwtLabel.IMAGE_LEFT = 1;
122 
123 /**
124  * Defines the "right" align image (i.e. align to the right of text, if both present).
125  */
126 DwtLabel.IMAGE_RIGHT = 2;
127 
128 /**
129  * Defines both "right" and "left" align images (i.e. align to the left and to the right of text, if all present).
130  */
131 DwtLabel.IMAGE_BOTH = 4;
132 
133 /**
134  * Defines the "left" align label.
135  */
136 DwtLabel.ALIGN_LEFT = 8;
137 
138 /**
139  * Defines the "right" align label.
140  */
141 DwtLabel.ALIGN_RIGHT = 16;
142 
143 /**
144  * Defines the "center" align label.
145  */
146 DwtLabel.ALIGN_CENTER = 32;
147 
148 /**
149  * Defines the last style label (used for subclasses).
150  * @private
151  */
152 DwtLabel._LAST_STYLE = 32;
153 
154 /**
155  * Defines the "left" side icon
156  */
157 DwtLabel.LEFT = "left";
158 
159 /**
160  * Defines the "right" side icon
161  */
162 DwtLabel.RIGHT = "right";
163 
164 //
165 // Data
166 //
167 
168 DwtLabel.prototype.TEMPLATE = "dwt.Widgets#ZLabel";
169 
170 //
171 // Public methods
172 //
173 
174 /**
175  * Disposes of the label.
176  * 
177  */
178 DwtLabel.prototype.dispose =
179 function() {
180 	delete this._dropDownEl;
181 	delete this._iconEl;
182 	delete this._textEl;
183 	DwtControl.prototype.dispose.call(this);
184 };
185 
186 /**
187  * Sets the enabled/disabled state of the label. A disabled label may have a different
188  * image, and greyed out text. This method overrides {@link DwtControl#setEnabled}.
189  *
190  * @param {boolean} enabled 		if <code>true</code>, set the label as enabled
191  */
192 DwtLabel.prototype.setEnabled =
193 function(enabled) {
194 	if (enabled != this._enabled) {
195 		DwtControl.prototype.setEnabled.call(this, enabled);
196 		var direction = this._style & DwtLabel.IMAGE_RIGHT ? DwtLabel.RIGHT : DwtLabel.LEFT;
197 		this.__imageInfo = this.__imageInfo || {};
198 		this.__setImage(this.__imageInfo[direction]);
199 	}
200 }
201 
202 /**
203  * Gets the current image info.
204  *
205  * @param	{string}	direction		position of the image
206  *
207  * @return	{string}	the image info
208  */
209 DwtLabel.prototype.getImage =
210 function(direction) {
211 	direction = direction || (this._style & DwtLabel.IMAGE_RIGHT ? DwtLabel.RIGHT : DwtLabel.LEFT);
212 	return this.__imageInfo[direction];
213 }
214 
215 /**
216  * Sets the main (enabled) image. If the label is currently enabled, the image is updated.
217  *
218  * @param	{string}	imageInfo		the image
219  * @param	{string}	direction		position of the image
220  * @param	{string}	altText			alternate text for non-visual users
221  */
222 DwtLabel.prototype.setImage =
223 function(imageInfo, direction, altText) {
224 	direction = direction || (this._style & DwtLabel.IMAGE_RIGHT ? DwtLabel.RIGHT : DwtLabel.LEFT);
225 	this.__imageInfo = this.__imageInfo || {};
226 	this.__imageInfo[direction] = imageInfo;
227 	this.__setImage(imageInfo, direction, altText);
228 }
229 
230 /**
231  *
232  * Set _iconEl, used for buttons that contains only images
233  *
234  * @param	htmlElement/DOM node
235  * @param	{string}				direction		position of the image
236  *
237  */
238 DwtLabel.prototype.setIconEl = function(iconElement, direction) {
239 	this._iconEl = this._iconEl || {};
240 	direction = direction || (this._style & DwtLabel.IMAGE_RIGHT ? DwtLabel.RIGHT : DwtLabel.LEFT);
241 	this._iconEl[direction] =  iconElement;
242 }
243 
244 /**
245  * Sets the disabled image. If the label is currently disabled, its image is updated.
246  *
247  * @param	{string}	imageInfo		the image
248  * @deprecated		no longer support different images for disabled
249  * @see		#setImage
250  */
251 DwtLabel.prototype.setDisabledImage =
252 function(imageInfo) {
253 	// DEPRECATED -- we no longer support different images for disabled.
254 	//	See __setImage() for details.
255 }
256 
257 /**
258  * Gets the label text.
259  * 
260  * @return	{string}	the text or <code>null</code> if not set
261  */
262 DwtLabel.prototype.getText =
263 function() {
264 	return (this.__text != null) ? this.__text : null;
265 }
266 
267 /**
268 * Sets the label text, and manages the placement and display.
269 *
270 * @param {string}	text	the new label text
271 */
272 DwtLabel.prototype.setText = function(text) {
273 
274     if (!this._textEl) {
275 	    return;
276     }
277 
278     if (text == null || text == "") {
279         this.__text = null;
280         this._textEl.innerHTML = "";
281     }
282     else {
283 		this.__text = text;
284         this._textEl.innerHTML = text;
285     }
286 
287 	this._textSet(text);
288 };
289 
290 /**
291  * Sets the text background.
292  * 
293  * @param	{string}	color	the background color
294  */
295 DwtLabel.prototype.setTextBackground =
296 function(color) {
297 	this._textBackground = color;
298     if (this._textEl) {
299         this._textEl.style.backgroundColor = color;
300     }
301 }
302 
303 /**
304  * Sets the text foreground.
305  * 
306  * @param	{string}	color	the foreground color
307  */
308 DwtLabel.prototype.setTextForeground =
309 function(color) {
310 	this._textForeground = color;
311     if (this._textEl) {
312 		this._textEl.style.color = color;
313     }
314 }
315 
316 /**
317  * Sets the align style.
318  * 
319  * @param		{constant}		alignStyle		the align style (see {@link DwtControl})
320  */
321 DwtLabel.prototype.setAlign =
322 function(alignStyle) {
323 	this._style = alignStyle;
324 
325 	// reset dom since alignment style may have changed
326 	var direction = this._style & DwtLabel.IMAGE_RIGHT ? DwtLabel.RIGHT : DwtLabel.LEFT;
327 	this.__imageInfo = this.__imageInfo || {};
328     this.__setImage(this.__imageInfo[direction]);
329 }
330 
331 /**
332  * Checks if the given style is set as the current label style.
333  * 
334  * @param	{constant}	style	the style
335  * @return	{boolean}	<code>true</code> if the style is set
336  */
337 DwtLabel.prototype.isStyle = function(style) {
338     return this._style & style;
339 };
340 
341 DwtLabel.prototype.getTabGroupMember =
342 function() {
343 	// DwtLabel descends from DwtComposite, as some buttons contain nested
344 	// members; it's a widget, however, and should be directly focusable
345 	return DwtControl.prototype.getTabGroupMember.apply(this, arguments);
346 }
347 
348 //
349 // Protected methods
350 //
351 
352 /**
353  * @private
354  */
355 DwtLabel.prototype._createHtml = function(templateId) {
356     var data = { id: this._htmlElId };
357     this._createHtmlFromTemplate(templateId || this.TEMPLATE, data);
358 };
359 
360 /**
361  * @private
362  */
363 DwtLabel.prototype._createHtmlFromTemplate = function(templateId, data) {
364     DwtControl.prototype._createHtmlFromTemplate.call(this, templateId, data);
365     this._textEl = document.getElementById(data.id+"_title");
366 };
367 
368 /**
369  * @private
370  *
371  * @param	{string}	direction		position of the image
372  */
373 DwtLabel.prototype._getIconEl = function(direction) {
374     var _dir = this._style & DwtLabel.IMAGE_RIGHT ? DwtLabel.RIGHT : DwtLabel.LEFT;
375     direction = typeof direction === 'boolean' ? _dir : (direction || _dir);    // fix for Bug 90130
376 	// MOW: getting the proper icon element on demand rather than all the time for speed
377 	this._iconEl = this._iconEl || {};
378 	return this._iconEl[direction] ||
379 		(this._iconEl[direction] = document.getElementById(this._htmlElId+"_"+direction+"_icon"));
380 };
381 
382 //
383 // Private methods
384 //
385 
386 /**
387  * Set the label's image, and manage its placement.
388  *
389  * @private
390  *
391  * @param	{string}	imageInfo		the image
392  * @param	{string}	direction		position of the image
393  * @param	{string}	altText			alternate text for non-visual users
394  */
395 DwtLabel.prototype.__setImage =
396 function(imageInfo, direction, altText) {
397 	this.__altText = altText || this.__altText;
398 
399 	var iconEl = this._getIconEl(direction);
400 	if (iconEl) {
401 		if (imageInfo) {
402 			AjxImg.setImage(iconEl, imageInfo, null, !this._enabled, null, this.__altText);
403 
404 			// set a ZHasRightIcon or ZHasLeftIcon on the outer element, depending on which we set
405 			var elementClass = (this._style & DwtLabel.IMAGE_RIGHT ? "ZHasRightIcon" : "ZHasLeftIcon");
406 			Dwt.addClass(this.getHtmlElement(), elementClass);
407 		} else {
408 			iconEl.innerHTML = "";
409 		}
410 	}
411 };
412 
413 // Accessibility
414 DwtLabel.prototype._textSet = function(text) {
415 
416 	// assign the ARIA label directly; we want it to override the tooltip, if any
417 	if (!this.hasAttribute('aria-labelledby')) {
418 		if (text) {
419 			this.setAttribute('aria-label', text);
420 		} else {
421 			this.removeAttribute('aria-label');
422 		}
423 	}
424 };
425