1 /*
  2  * ***** BEGIN LICENSE BLOCK *****
  3  * Zimbra Collaboration Suite Web Client
  4  * Copyright (C) 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) 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 contains classes for a Dwt dialog pop-up.
 27  */
 28 
 29 /**
 30  * @class
 31  * This class represents a popup dialog with a title and standard buttons.
 32  * A client or subclass sets the dialog content. Dialogs always hang-off the main shell
 33  * since their stacking order is managed through z-index.
 34  *
 35  * @author Ross Dargahi
 36  * @author Conrad Damon
 37  *
 38  * @param {hash}		params			a hash of parameters
 39  * @param	{DwtComposite}		params.parent			 		the parent widget (the shell)
 40  * @param	{string}	params.className					the CSS class
 41  * @param	{string}	params.title						the title of dialog
 42  * @param	{array|constant}	params.standardButtons		an array of standard buttons to include. Defaults to {@link DwtDialog.OK_BUTTON} and {@link DwtDialog.CANCEL_BUTTON}.
 43  * @param	{array}	params.extraButtons		  			a list of {@link DwtDialog_ButtonDescriptor} objects describing custom buttons to add to the dialog
 44  * @param	{number}	params.zIndex							the z-index to set for this dialog when it is visible. Defaults to {@link Dwt.Z_DIALOG}.
 45  * @param	{DwtDialog.MODELESS|DwtDialog.MODAL}	params.mode 						the modality of the dialog. Defaults to {@link DwtDialog.MODAL}.
 46  * @param	{boolean}		params.disposeOnPopDown		    destroy the content of dialog on popdown, Defaults to false
 47  * @param	{DwtPoint}		params.loc						the location at which to popup the dialog. Defaults to centered within its parent.
 48  * 
 49  * @see		DwtDialog.CANCEL_BUTTON
 50  * @see		DwtDialog.OK_BUTTON
 51  * @see		DwtDialog.DISMISS_BUTTON
 52  * @see		DwtDialog.NO_BUTTON
 53  * @see		DwtDialog.YES_BUTTON
 54  * @see		DwtDialog.ALL_BUTTONS
 55  * @see		DwtDialog.NO_BUTTONS
 56  * 
 57  * @extends	DwtBaseDialog
 58  */
 59 DwtDialog = function(params) {
 60 	if (arguments.length == 0) { return; }
 61 	params = Dwt.getParams(arguments, DwtDialog.PARAMS);
 62 	params.className = params.className || "DwtDialog";
 63 	this._title = params.title = params.title || "";
 64 
 65 	// standard buttons default to OK / Cancel
 66 	var standardButtons = params.standardButtons;
 67 	var extraButtons = params.extraButtons;
 68 	if (!standardButtons) {
 69 		standardButtons = [DwtDialog.OK_BUTTON, DwtDialog.CANCEL_BUTTON];
 70 	} else if (standardButtons == DwtDialog.NO_BUTTONS) {
 71 		standardButtons = null;
 72 	} else if (standardButtons && !standardButtons.length) {
 73 		standardButtons = [standardButtons];
 74 	}
 75 
 76 	// assemble the list of button IDs, and the list of button descriptors
 77 	this._buttonList = [];
 78 	var buttonOrder = {};
 79 	buttonOrder[DwtDialog.ALIGN_LEFT] = [];
 80 	buttonOrder[DwtDialog.ALIGN_CENTER] = [];
 81 	buttonOrder[DwtDialog.ALIGN_RIGHT] = [];
 82 	if (standardButtons || extraButtons) {
 83 		this._buttonDesc = {};
 84 		if (standardButtons && standardButtons.length) {
 85 			this._initialEnterButtonId = this._enterButtonId = standardButtons[0];
 86 			for (var i = 0; i < standardButtons.length; i++) {
 87 				var buttonId = standardButtons[i];
 88 				this._buttonList.push(buttonId);
 89 				var align = DwtDialog.ALIGN[buttonId];
 90 				if (align) {
 91 					buttonOrder[align].push(buttonId);
 92 				}
 93 				// creating standard button descriptors on file read didn't work, so we create them here
 94 				this._buttonDesc[buttonId] = new DwtDialog_ButtonDescriptor(buttonId, AjxMsg[DwtDialog.MSG_KEY[buttonId]], align);
 95 			}
 96 			// set standard callbacks
 97 			this._resetCallbacks();
 98 		}
 99 		if (extraButtons && extraButtons.length) {
100 			if (!this._enterButtonId) {
101 				this._initialEnterButtonId = this._enterButtonId = extraButtons[0];
102 			}
103 			for (var i = 0; i < extraButtons.length; i++) {
104 				var buttonId = extraButtons[i].id;
105 				this._buttonList.push(buttonId);
106 				var align = extraButtons[i].align;
107 				if (align) {
108 					buttonOrder[align].push(buttonId);
109 				}
110 				this._buttonDesc[buttonId] = extraButtons[i];
111 			}
112 		}
113 	}
114 
115 	// get button IDs
116 	this._buttonElementId = {};
117 	for (var i = 0; i < this._buttonList.length; i++) {
118 		var buttonId = this._buttonList[i];
119 		//this._buttonElementId[this._buttonList[i]] = params.id + "_button" + buttonId + "_cell";
120 		this._buttonElementId[buttonId] = this._buttonDesc[buttonId].label? this._buttonDesc[buttonId].label + "_" + Dwt.getNextId():Dwt.getNextId();
121 	}
122 
123 	DwtBaseDialog.call(this, params);
124 
125 	// set up buttons
126 	this._button = {};
127 	for (var i = 0; i < this._buttonList.length; i++) {
128 		var buttonId = this._buttonList[i];
129 		var b = this._button[buttonId] = new DwtButton({parent:this,id:this._htmlElId+"_button"+buttonId});
130 		b.setText(this._buttonDesc[buttonId].label);
131 		b.buttonId = buttonId;
132 		b.addSelectionListener(new AjxListener(this, this._buttonListener));
133 		var el = document.getElementById(this._buttonElementId[buttonId]);
134 		if (el) {
135 			el.appendChild(b.getHtmlElement());
136 		}
137 	}
138 	// add to tab group, in order
139 	var list = buttonOrder[DwtDialog.ALIGN_LEFT].concat(buttonOrder[DwtDialog.ALIGN_CENTER], buttonOrder[DwtDialog.ALIGN_RIGHT]);
140 	for (var i = 0; i < list.length; i++) {
141 		var button = this._button[list[i]];
142 		this._tabGroup.addMember(button);		
143 	}
144 };
145 
146 DwtDialog.PARAMS = ["parent", "className", "title", "standardButtons", "extraButtons", "zIndex", "mode", "loc", "id"];
147 
148 DwtDialog.prototype = new DwtBaseDialog;
149 DwtDialog.prototype.constructor = DwtDialog;
150 
151 DwtDialog.prototype.isDwtDialog = true;
152 DwtDialog.prototype.toString = function() { return "DwtDialog"; };
153 
154 //
155 // Constants
156 //
157 
158 /**
159  * Defines the "left" align.
160  */
161 DwtDialog.ALIGN_LEFT 		= 1;
162 /**
163  * Defines the "right" align.
164  */
165 DwtDialog.ALIGN_RIGHT 		= 2;
166 /**
167  * Defines the "center" align.
168  */
169 DwtDialog.ALIGN_CENTER 		= 3;
170 
171 // standard buttons, their labels, and their positioning
172 
173 /**
174  * Defines the "Cancel" button.
175  */
176 DwtDialog.CANCEL_BUTTON 	= 1;
177 /**
178  * Defines the "OK" button.
179  */
180 DwtDialog.OK_BUTTON 		= 2;
181 /**
182  * Defines the "Dismiss" button.
183  */
184 DwtDialog.DISMISS_BUTTON 	= 3;
185 /**
186  * Defines the "No" button.
187  */
188 DwtDialog.NO_BUTTON 		= 4;
189 /**
190  * Defines the "Yes" button.
191  */
192 DwtDialog.YES_BUTTON 		= 5;
193 
194 DwtDialog.LAST_BUTTON 		= 5;
195 
196 /**
197  * Defines "no" buttons. This constant is used to show no buttons.
198  */
199 DwtDialog.NO_BUTTONS 		= 256;
200 /**
201  * Defines "all" buttons. This constant is used to show all buttons.
202  */
203 DwtDialog.ALL_BUTTONS 		= [DwtDialog.CANCEL_BUTTON, DwtDialog.OK_BUTTON, 
204 							   DwtDialog.DISMISS_BUTTON, DwtDialog.NO_BUTTON, 
205 							   DwtDialog.YES_BUTTON];
206 
207 DwtDialog.MSG_KEY = {};
208 DwtDialog.MSG_KEY[DwtDialog.CANCEL_BUTTON] 	= "cancel";
209 DwtDialog.MSG_KEY[DwtDialog.OK_BUTTON] 		= "ok";
210 DwtDialog.MSG_KEY[DwtDialog.DISMISS_BUTTON] = "close";
211 DwtDialog.MSG_KEY[DwtDialog.NO_BUTTON] 		= "no";
212 DwtDialog.MSG_KEY[DwtDialog.YES_BUTTON] 	= "yes";
213 
214 DwtDialog.ALIGN = {};
215 DwtDialog.ALIGN[DwtDialog.CANCEL_BUTTON]	= DwtDialog.ALIGN_RIGHT;
216 DwtDialog.ALIGN[DwtDialog.OK_BUTTON] 		= DwtDialog.ALIGN_RIGHT;
217 DwtDialog.ALIGN[DwtDialog.DISMISS_BUTTON] 	= DwtDialog.ALIGN_RIGHT;
218 DwtDialog.ALIGN[DwtDialog.NO_BUTTON] 		= DwtDialog.ALIGN_RIGHT;
219 DwtDialog.ALIGN[DwtDialog.YES_BUTTON] 		= DwtDialog.ALIGN_RIGHT;
220 
221 /**
222  * Defines a "modeless" dialog.
223  * 
224  * @see	DwtBaseDialog.MODELESS
225  */
226 DwtDialog.MODELESS = DwtBaseDialog.MODELESS;
227 
228 /**
229  * Defines a "modal" dialog.
230  * 
231  * @see	DwtBaseDialog.MODAL
232  */
233 DwtDialog.MODAL = DwtBaseDialog.MODAL;
234 
235 //
236 // Data
237 //
238 /**
239  * @private
240  */
241 DwtDialog.prototype.CONTROLS_TEMPLATE = "dwt.Widgets#DwtDialogControls";
242 
243 //
244 // Public methods
245 //
246 
247 DwtDialog.prototype.popdown =
248 function() {
249 	DwtBaseDialog.prototype.popdown.call(this);
250 	if (!this._disposeOnPopDown) {
251 		this.resetButtonStates();
252 	}
253 };
254 
255 /**
256  * This method will pop-up the dialog.
257  * 
258  * @param	{DwtPoint}	loc		the location
259  * @param	{constant}	focusButtonId		the button Id
260  */
261 DwtDialog.prototype.popup =
262 function(loc, focusButtonId) {
263 	this._focusButtonId = focusButtonId;
264 	DwtBaseDialog.prototype.popup.call(this, loc);
265 };
266 
267 /**
268  * @private
269  */
270 DwtDialog.prototype._resetTabFocus =
271 function(){
272 	if (this._focusButtonId) {
273 		var focusButton = this.getButton(this._focusButtonId);
274 		this._tabGroup.setFocusMember(focusButton, true);
275 	} else {
276 		DwtBaseDialog.prototype._resetTabFocus.call(this);
277 	}
278 };
279 
280 DwtDialog.prototype.reset =
281 function() {
282 	this._resetCallbacks();
283 	this.resetButtonStates();
284 	DwtBaseDialog.prototype.reset.call(this);
285 };
286 
287 /**
288  * Sets all buttons back to inactive state.
289  * 
290  */
291 DwtDialog.prototype.resetButtonStates =
292 function() {
293 	for (b in this._button) {
294 		this._button[b].setEnabled(true);
295 		this._button[b].setHovered(false);
296 	}
297 	this.associateEnterWithButton(this._initialEnterButtonId);
298 };
299 
300 /**
301  * Gets a button by the specified Id.
302  * 
303  * @param	{constant}		buttonId		the button Id
304  * @return	{DwtButton}		the button or <code>null</code> if not found
305  */
306 DwtDialog.prototype.getButton =
307 function(buttonId) {
308 	return this._button[buttonId];
309 };
310 
311 /**
312  * Sets the button enabled state.
313  * 
314  * @param	{constant}		buttonId		the button Id
315  * @param	{boolean}		enabled		if <code>true</code>, enable the button; <code>false</code> otherwise
316  */
317 DwtDialog.prototype.setButtonEnabled = 
318 function(buttonId, enabled) {
319 	if (!this._button[buttonId]) {
320 		return;
321 	}
322 	this._button[buttonId].setEnabled(enabled);
323 };
324 
325 /**
326  * Sets the button visible state.
327  * 
328  * @param	{constant}		buttonId		the button Id
329  * @param	{boolean}		enabled		if <code>true</code>, make the button visible; <code>false</code> otherwise
330  */
331 DwtDialog.prototype.setButtonVisible = 
332 function(buttonId, visible) {
333 	if (!this._button[buttonId]) {
334 		return;
335 	}
336 	this._button[buttonId].setVisible(visible);
337 };
338 
339 /**
340  * Gets the button enabled state.
341  * 
342  * @param	{constant}		buttonId		the button Id
343  * @return	{boolean}	<code>true</code> if the button is enabled; <code>false</code> otherwise
344  */
345 DwtDialog.prototype.getButtonEnabled = 
346 function(buttonId) {
347 	return this._button[buttonId].getEnabled();
348 };
349 
350 /**
351  * Registers a callback for a given button. Can be passed an AjxCallback,
352  * the params needed to create one, or as a bound function.
353  *
354  * @param {constant}		buttonId	one of the standard dialog buttons
355  * @param {AjxCallback}	func		the callback method
356  * @param {Object}		obj			the callback object
357  * @param {array}		args		the callback args
358  */
359 DwtDialog.prototype.registerCallback =
360 function(buttonId, func, obj, args) {
361 	this._buttonDesc[buttonId].callback = (func && (func.isAjxCallback || (!obj && !args))) ? func : (new AjxCallback(obj, func, args));
362 };
363 
364 /**
365  * Unregisters a callback for a given button.
366  *
367  * @param {constant}		buttonId	one of the standard dialog buttons
368  */
369 DwtDialog.prototype.unregisterCallback =
370 function(buttonId) {
371 	this._buttonDesc[buttonId].callback = null;
372 };
373 
374 /**
375  * Sets the given listener as the only listener for the given button.
376  *
377  * @param {constant}		buttonId	one of the standard dialog buttons
378  * @param {AjxListener}			listener	a listener
379  */
380 DwtDialog.prototype.setButtonListener =
381 function(buttonId, listener) {
382 	this._button[buttonId].removeSelectionListeners();
383 	this._button[buttonId].addSelectionListener(listener);
384 };
385 
386 /**
387  * Sets the enter key listener.
388  * 
389  * @param	{AjxListener}	listener	a listener
390  */
391 DwtDialog.prototype.setEnterListener =
392 function(listener) {
393 	this.removeAllListeners(DwtEvent.ENTER);
394 	this.addEnterListener(listener);
395 };
396 
397 /**
398  * Associates the "enter" key with a given button.
399  * 
400  * @param {constant}		buttonId	one of the standard dialog buttons
401  */
402 DwtDialog.prototype.associateEnterWithButton =
403 function(id) {
404 	this._enterButtonId = id;
405 };
406 
407 DwtDialog.prototype.getKeyMapName = 
408 function() {
409 	return DwtKeyMap.MAP_DIALOG;
410 };
411 
412 DwtDialog.prototype.handleKeyAction =
413 function(actionCode, ev) {
414 	switch (actionCode) {
415 		
416 		case DwtKeyMap.ENTER:
417 			this.notifyListeners(DwtEvent.ENTER, ev);
418 			break;
419 			
420 		case DwtKeyMap.CANCEL:
421 			// hitting ESC should act as a cancel
422             //TODO: dialog should set ESC/Enter listeners so we don't have to guess the action to take
423 			var handled = false;
424 			handled = handled || this._runCallbackForButtonId(DwtDialog.CANCEL_BUTTON);
425 			handled = handled || this._runCallbackForButtonId(DwtDialog.NO_BUTTON);
426 			handled = handled || this._runCallbackForButtonId(DwtDialog.DISMISS_BUTTON);
427 
428             //don't let OK act as cancel if there are other buttons
429             if (!handled && this._buttonDesc[DwtDialog.OK_BUTTON] && this._buttonList.length == 1) {
430                 handled = handled || this._runCallbackForButtonId(DwtDialog.OK_BUTTON);
431             }
432             this.popdown();
433 			return true;
434 
435 		case DwtKeyMap.YES:
436 			if (this._buttonDesc[DwtDialog.YES_BUTTON]) {
437 				this._runCallbackForButtonId(DwtDialog.YES_BUTTON);
438 			}
439 			break;
440 
441 		case DwtKeyMap.NO:
442 			if (this._buttonDesc[DwtDialog.NO_BUTTON]) {
443 				this._runCallbackForButtonId(DwtDialog.NO_BUTTON);
444 			}
445 			break;
446 
447 		default:
448 			return false;
449 	}
450 	return true;
451 };
452 
453 //
454 // Protected methods
455 //
456 
457 /**
458  * @private
459  */
460 DwtDialog.prototype._createHtmlFromTemplate =
461 function(templateId, data) {
462 	DwtBaseDialog.prototype._createHtmlFromTemplate.call(this, templateId, data);
463 
464 	var focusId = data.id+"_focus";
465 	if (document.getElementById(focusId)) {
466 		this._focusElementId = focusId;
467 	}
468 	this._buttonsEl = document.getElementById(data.id+"_buttons");
469 	if (this._buttonsEl) {
470 		var html = [];
471 		var idx = 0;
472 		this._addButtonsHtml(html,idx);
473 		this._buttonsEl.innerHTML = html.join("");
474 	}
475 };
476 
477 // TODO: Get rid of these button template methods!
478 /**
479  * @private
480  */
481 DwtDialog.prototype._getButtonsContainerStartTemplate =
482 function () {
483 	return "<table role='presentation' width='100%'><tr>";
484 };
485 
486 /**
487  * @private
488  */
489 DwtDialog.prototype._getButtonsAlignStartTemplate =
490 function () {
491 	return "<td align=\"{0}\"><table role='presentation'><tr>";
492 };
493 
494 /**
495  * @private
496  */
497 DwtDialog.prototype._getButtonsAlignEndTemplate =
498 function () {
499 	return "</tr></table></td>";
500 };
501 
502 /**
503  * @private
504  */
505 DwtDialog.prototype._getButtonsCellTemplate =
506 function () {
507 	return "<td id=\"{0}\"></td>";
508 };
509 
510 /**
511  * @private
512  */
513 DwtDialog.prototype._getButtonsContainerEndTemplate =
514 function () {
515 	return  "</tr></table>";
516 };
517 
518 /**
519  * @private
520  */
521 DwtDialog.prototype._addButtonsHtml =
522 function(html, idx) {
523 	if (this._buttonList && this._buttonList.length) {
524 		var leftButtons = new Array();
525 		var rightButtons = new Array();
526 		var centerButtons = new Array();
527 		for (var i = 0; i < this._buttonList.length; i++) {
528 			var buttonId = this._buttonList[i];
529 			switch (this._buttonDesc[buttonId].align) {
530 				case DwtDialog.ALIGN_RIGHT: 	rightButtons.push(buttonId); break;
531 				case DwtDialog.ALIGN_LEFT: 		leftButtons.push(buttonId); break;
532 				case DwtDialog.ALIGN_CENTER:	centerButtons.push(buttonId); break;
533 			}
534 		}
535 		html[idx++] = this._getButtonsContainerStartTemplate();
536 		
537 		if (leftButtons.length) {
538 			html[idx++] = AjxMessageFormat.format(
539 								  this._getButtonsAlignStartTemplate(),
540 								  ["left"]);
541 			for (var i = 0; i < leftButtons.length; i++) {
542 				var buttonId = leftButtons[i];
543 				var cellTemplate = this._buttonDesc[buttonId].cellTemplate ? 
544 					this._buttonDesc[buttonId].cellTemplate : this._getButtonsCellTemplate();
545 		 		html[idx++] = AjxMessageFormat.format(
546 								  cellTemplate,
547 								  [this._buttonElementId[buttonId]]);
548 		 	}
549 			html[idx++] = this._getButtonsAlignEndTemplate();
550 		}
551 		if (centerButtons.length){
552 			html[idx++] = AjxMessageFormat.format(
553 								this._getButtonsAlignStartTemplate(),
554 								["center"]);
555 			for (var i = 0; i < centerButtons.length; i++) {
556 				var buttonId = centerButtons[i];
557 				var cellTemplate = this._buttonDesc[buttonId].cellTemplate ? 
558 					this._buttonDesc[buttonId].cellTemplate : this._getButtonsCellTemplate();				
559 		 		html[idx++] = AjxMessageFormat.format(
560 								cellTemplate,
561 								[this._buttonElementId[buttonId]]);
562 		 	}
563 			html[idx++] = this._getButtonsAlignEndTemplate();
564 		}
565 		if (rightButtons.length) {
566 			html[idx++] = AjxMessageFormat.format(
567 								this._getButtonsAlignStartTemplate(),
568 								["right"]);
569 			for (var i = 0; i < rightButtons.length; i++) {
570 				var buttonId = rightButtons[i];
571 				var cellTemplate = this._buttonDesc[buttonId].cellTemplate ? 
572 					this._buttonDesc[buttonId].cellTemplate : this._getButtonsCellTemplate();				
573 
574 		 		html[idx++] = AjxMessageFormat.format(cellTemplate,
575 													[this._buttonElementId[buttonId]]);
576 		 	}
577 			html[idx++] = this._getButtonsAlignEndTemplate();
578 		}
579 		html[idx++] = this._getButtonsContainerEndTemplate();
580 	}	
581 	return idx;
582 };
583 
584 /**
585  * Button listener that checks for callbacks.
586  * 
587  * @private
588  */
589 DwtDialog.prototype._buttonListener =
590 function(ev, args) {
591 	var obj = DwtControl.getTargetControl(ev);
592 	var buttonId = (obj && obj.buttonId) || this._enterButtonId;
593 	if (buttonId) {
594 		this._runCallbackForButtonId(buttonId, args);
595 	}
596 };
597 
598 /**
599  * @private
600  */
601 DwtDialog.prototype._runCallbackForButtonId =
602 function(id, args) {
603 	var buttonDesc = this._buttonDesc[id];
604 	var callback = buttonDesc && buttonDesc.callback;
605 	if (!callback) {
606 		return false;
607 	}
608 	args = (args instanceof Array) ? args : [args];
609 	callback.run.apply(callback, args);
610 	return true;
611 };
612 
613 /**
614  * @private
615  */
616 DwtDialog.prototype._runEnterCallback =
617 function(args) {
618 	if (this._enterButtonId && this.getButtonEnabled(this._enterButtonId)) {
619 		this._runCallbackForButtonId(this._enterButtonId, args);
620 	}
621 };
622 
623 /**
624  * Default callbacks for the standard buttons.
625  * 
626  * @private
627  */
628 DwtDialog.prototype._resetCallbacks =
629 function() {
630 	if (this._buttonDesc) {
631 		for (var i = 0; i < DwtDialog.ALL_BUTTONS.length; i++) {
632 			var id = DwtDialog.ALL_BUTTONS[i];
633 			if (this._buttonDesc[id])
634 				this._buttonDesc[id].callback = new AjxCallback(this, this.popdown);
635 		}
636 	}
637 };
638 
639 //
640 // Classes
641 //
642 
643 /**
644  * @class
645  * This class represents a button descriptor.
646  * 
647  * @param	{string}	id		the button Id
648  * @param	{string}	label		the button label
649  * @param	{constant}	align		the alignment
650  * @param	{AjxCallback}	callback		the callback
651  * @param	{string}	cellTemplate		the template
652  */
653 DwtDialog_ButtonDescriptor = function(id, label, align, callback, cellTemplate) {
654 	this.id = id;
655 	this.label = label;
656 	this.align = align;
657 	this.callback = callback;
658 	this.cellTemplate = cellTemplate;
659 };
660