1 /*
  2  * ***** BEGIN LICENSE BLOCK *****
  3  * Zimbra Collaboration Suite Web Client
  4  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 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) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Synacor, Inc. All Rights Reserved.
 21  * ***** END LICENSE BLOCK *****
 22  */
 23 
 24 /**
 25  * @overview
 26  * This file defines a toolbar.
 27  */
 28 
 29 /**
 30  * Creates a toolbar.
 31  * @class
 32  * This class represents a basic toolbar which can add buttons, manage listeners, and
 33  * enable/disabled its buttons.
 34  *
 35  * @author Conrad Damon
 36  *
 37  * @param {Hash}	params		a hash of parameters
 38  * @param	{DwtComposite}	params.parent		the containing widget
 39  * @param	{String}	params.className	the CSS class
 40  * @param	{constant}	params.posStyle		the positioning style
 41  * @param	{String}	params.id			an explicit ID to use for the control's HTML element
 42  * @param	{ZmController}	params.controller	the owning controller
 43  * @param	{String}	params.refElementId	the id of element that contains toolbar
 44  *        
 45  * @extends	DwtToolBar
 46  */
 47 ZmToolBar = function(params) {
 48 	if (arguments.length == 0) return;
 49 
 50 	params.posStyle = params.posStyle || DwtControl.ABSOLUTE_STYLE;
 51 	DwtToolBar.call(this, params);
 52 
 53 	var controller = params.controller || appCtxt.getCurrentController();
 54 	if (controller) {
 55 		this._controller = controller;
 56 		this._keyMap = this._controller.getKeyMapName();
 57 	}
 58 
 59 	this._refElementId = params.refElementId;
 60 	this._buttons = {};
 61 };
 62 
 63 ZmToolBar.prototype = new DwtToolBar;
 64 ZmToolBar.prototype.constructor = ZmToolBar;
 65 
 66 ZmToolBar.prototype.isZmToolBar = true;
 67 ZmToolBar.prototype.toString = function() { return "ZmToolBar"; };
 68 
 69 /**
 70  * Adds a selection listener.
 71  * 
 72  * @param	{String}	buttonId	the button id
 73  * @param	{AjxListener}	listener	the listener
 74  */
 75 ZmToolBar.prototype.addSelectionListener =
 76 function(buttonId, listener) {
 77 	var button = this._buttons[buttonId];
 78 	if (button) {
 79 		button.addSelectionListener(listener);
 80 	}
 81 };
 82 
 83 /**
 84  * Removes a selection listener.
 85  * 
 86  * @param	{String}	buttonId	the button id
 87  * @param	{AjxListener}	listener	the listener
 88  */
 89 ZmToolBar.prototype.removeSelectionListener =
 90 function(buttonId, listener) {
 91 	var button = this._buttons[buttonId];
 92 	if (button) {
 93 		button.removeSelectionListener(listener);
 94 	}
 95 };
 96 
 97 /**
 98  * Gets the button.
 99  * 
100  * @param	{String}	buttonId	the button id
101  * @return	{ZmAppButton}	the button
102  */
103 ZmToolBar.prototype.getButton =
104 function(buttonId) {
105 	return this._buttons[buttonId];
106 };
107 
108 /**
109  * sets an item visibility. finds the button by id. 
110  *
111  * @param	{String}	buttonId	the button id
112  * @param	{Boolean}	visible
113  */
114 ZmToolBar.prototype.setItemVisible =
115 function(buttonId, visible) {
116 	var button = this.getButton(buttonId);
117 	if (!button) {
118 		return;
119 	}
120 	button.setVisible(visible);
121 };
122 
123 
124 /**
125  * Sets the data.
126  * 
127  * @param	{String}	buttonId	the button id
128  * @param	{String}	key		the data key
129  * @param	{Object}	data	the data
130  */
131 ZmToolBar.prototype.setData = 
132 function(buttonId, key, data) {
133 	this._buttons[buttonId].setData(key, data);
134 };
135 
136 /**
137  * Enables or disables the specified buttons.
138  *
139  * @param {Array}	ids		a list of button ids
140  * @param {Boolean}	enabled	if <code>true</code>, enable the buttons
141  */
142 ZmToolBar.prototype.enable =
143 function(ids, enabled) {
144 	ids = (ids instanceof Array) ? ids : [ids];
145 	for (var i = 0; i < ids.length; i++) {
146 		if (this._buttons[ids[i]]) {
147 			this._buttons[ids[i]].setEnabled(enabled);
148 		}
149 	}
150 };
151 
152 ZmToolBar.prototype.setSelected =
153 function(id) {
154     var oldButton = this._selectedId ? this._buttons[this._selectedId] : null;
155     var newButton = id ? this._buttons[id] : null;
156     if (oldButton) {
157         oldButton.setSelected(false);
158     }
159     if (newButton) {
160         newButton.setSelected(true);
161         this._selectedId = id;
162     }
163 };
164 
165 /**
166  * Enables or disables all buttons.
167  *
168  * @param {Boolean}	enabled			if <code>true</code>, enable the buttons
169  */
170 ZmToolBar.prototype.enableAll =
171 function(enabled) {
172 	for (var i in this._buttons) {
173 		this._buttons[i].setEnabled(enabled);
174 	}
175 };
176 
177 /**
178  * Creates a button and adds the button to this toolbar.
179  *
180  * @param {String}	id			the button id
181  * @param {Hash}	params		a hash of parameters:
182  * @param {function}	params.constructor	the constructor for button object (default is {@link DwtToolBarButton})
183  * @param {String}	params.template		the button template
184  * @param {String}	params.text			the button text
185  * @param {String}	params.tooltip		the button tooltip text
186  * @param {String}	params.image		the icon class for the button
187  * @param {String}	params.disImage	the disabled version of icon
188  * @param {Boolean}	params.enabled		if <code>true</code>, button is enabled
189  * @param {String}	params.className	the CSS class name
190  * @param {String}	params.style		the button style
191  * @param {int}	params.index			the position at which to add the button
192  * @param {constant}	params.shortcut		the shortcut id (from {@link ZmKeyMap}) for showing hint
193  * @param {AjxCallback|DwtMenu}	params.menu				the menu creation callback (recommended) or menu
194  * @param {Boolean}	params.menuAbove	if <code>true</code>, popup menu above the button.
195  *
196  * @param {Object}	params.whatToShow		if exists, determines what to show as follows: (for usage, see ZmToolBar.prototype._createButton and DwtButton.prototype.setImage and DwtButton.prototype.setText
197  * @param {Boolean}	params.whatToShow.showImage		if <code>true</code>, display image
198  * @param {Boolean}	params.whatToShow.showText		if <code>true</code>, display text
199  *
200  */
201 ZmToolBar.prototype.createButton =
202 function(id, params) {
203 	var b = this._buttons[id] = this._createButton(params);
204 	if (params.image) {
205 		b.setImage(params.image);
206 	}
207 	if (params.text) {
208 		b.setText(params.text);
209 	}
210 	if (params.tooltip) {
211 		b.setToolTipContent(ZmOperation.getToolTip(id, this._keyMap) || params.tooltip, true);
212 	}
213 	b.setEnabled(params.enabled !== false);
214 	b.setData("_buttonId", id);
215 	if (params.menu) {
216 		b.setMenu(params.menu, false, null, params.menuAbove);
217 	}
218 
219 	return b;
220 };
221 
222 //
223 // Data
224 //
225 
226 ZmToolBar.prototype.SEPARATOR_TEMPLATE = "share.Widgets#ZmToolBarSeparator";
227 
228 //
229 // Protected methods
230 //
231 
232 /**
233  * @private
234  */
235 ZmToolBar.prototype._createButton =
236 function(params, className) {
237 	var ctor = params.ctor || DwtToolBarButton;
238     var button = new ctor({
239 		parent:this,
240 		style:params.style,
241 		className:className,
242 		index:params.index,
243 		id:params.id,
244 		template: params.template
245 	});
246 	button.textPrecedence = params.textPrecedence;
247 	button.imagePrecedence = params.imagePrecedence;
248 	button.whatToShow = params.whatToShow;
249 
250 	return button;
251 };
252 
253 /**
254  * @private
255  */
256 ZmToolBar.prototype._buttonId =
257 function(button) {
258 	return button.getData("_buttonId");
259 };
260 
261 /**
262  * Creates an ordered list of which bits of text or images get removed when we need space.
263  * 
264  * @private
265  */
266 ZmToolBar.prototype._createPrecedenceList =
267 function() {
268 	this._precedenceList = [];
269 	for (var id in this._buttons) {
270 		if (ZmOperation.isSep(id)) { continue; }
271 		var b = this._buttons[id];
272 		var tp = b.textPrecedence;
273 		if (tp) {
274 			this._precedenceList.push({id:id, type:"text", precedence:tp});
275 		}
276 		var ip = b.imagePrecedence;
277 		if (ip) {
278 			this._precedenceList.push({id:id, type:"image", precedence:ip});
279 		}
280 	}
281 	this._precedenceList.sort(function(a, b) {
282 		return (a.precedence > b.precedence) ? 1 : (a.precedence < b.precedence) ? -1 : 0;
283 	});
284 };
285 
286 // The following overrides are so that we check our width after a call to a function that
287 // may affect our size.
288 
289 /**
290  * Sets the size. This method is called by the application view manager <code>fitToContainer()</code>,
291  * which happens during initial layout as well as in response to the user changing the browser size.
292  * 
293  * @param	{int}	width	the width (in pixels)
294  * @param	{int}	height	the height (in pixels)
295  */
296 ZmToolBar.prototype.setSize =
297 function(width, height) {
298 	DBG.println("tb", "------ setSize " + width + " x " + height);
299 	var sz = this.getSize();
300 	if (sz && (width != sz.x || height != sz.y)) {
301 		DwtToolBar.prototype.setSize.apply(this, arguments);
302 	}
303 };
304 
305 ZmToolBar.prototype.adjustSize =
306 function() {
307 	if (!this._refElementId || !this._inited) { return; }
308     if (!this._refElement) {
309         this._refElement = document.getElementById(this._refElementId);
310     }
311     var container = this._refElement && this._refElement.parentNode;
312     var offsetWidth;
313     if (container && ((offsetWidth = container.offsetWidth) >= 30)) {
314         var style = this._refElement.style;
315 		style.maxWidth = style.width =  (offsetWidth - 30) + "px";
316         style.overflow = "hidden";
317     }
318 }
319 
320 /**
321  * Adds a button to the element with the given ID. Designed to handle non-ZmToolBar toolbars.
322  * 
323  * @param params	[hash]			hash of params:
324  * 		  parent	[DwtControl]	parent control
325  *        setting	[const]			setting that must be true for this button to be added
326  *        tdId		[string]		ID of TD that is to contain this button
327  *        buttonId	[string]*		ID of the button
328  *        style		[const]*		button style
329  *        type		[string]*		used to differentiate between regular and toolbar buttons
330  *        lbl		[string]*		button text
331  *        icon		[string]*		button icon
332  *        tooltip	[string]*		button tooltip
333  */
334 ZmToolBar.addButton =
335 function(params) {
336 
337 	if (params.setting && !appCtxt.get(params.setting)) { return; }
338 
339 	var button;
340 	var tdId = params.parent._htmlElId + (params.tdId || params.buttonId);
341 	var buttonEl = document.getElementById(tdId);
342 	if (buttonEl) {
343 		var btnParams = {parent:params.parent, index: params.index, style:params.style, id:params.buttonId, template: params.template, className: params.className};
344 		button = (params.type && params.type == "toolbar") ? (new DwtToolBarButton(btnParams)) : (new DwtButton(btnParams));
345 		var hint = Dwt.getAttr(buttonEl, "hint");
346 		ZmToolBar._setButtonStyle(button, hint, params.lbl, params.icon);
347 		if (params.tooltip) {
348 			button.setToolTipContent(params.tooltip, true);
349 		}
350 		button.reparentHtmlElement(tdId);
351 	}
352 
353 	return button;
354 };
355 
356 ZmToolBar._setButtonStyle =
357 function(button, hint, text, image) {
358 	if (hint == "text") {
359 		button.whatToShow = { showText: true };
360 	} else if (hint == "icon") {
361 		button.whatToShow = { showImage: true };
362 	} else { // add icon and text if no hint (or unsupported hint) provided
363 		button.whatToShow = { showImage: true, showText: true };
364 	}
365 
366 	button.setText(text);
367 	button.setImage(image);
368 };
369