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 a Dwt control.
 27  */
 28 
 29 /**
 30  * Creates a control.
 31  * @class
 32  * This class is the root class of the Dwt component hierarchy. All
 33  * Dwt components either directly or indirectly inherit from this class.
 34  * <p>
 35  * A {@link DwtControl} may also be directly instantiated. In this case it is essentially
 36  * a div into which any content may be "drawn"
 37  * <p>
 38  * A control may be created in "deferred" mode, meaning that the UI portion of the control
 39  * will be created "Just In Time". This is useful for widgets which may want to defer construction
 40  * of elements (e.g. {@link DwtTreeItem}) until such time as is needed, in the interest of efficiency.
 41  * Note that if the control is a child of the shell, it won't become visible until its z-index is set.
 42  *
 43  * <h4>Events</h4><ul>
 44  * <li><i>DwtEvent.CONTROL</i></li>
 45  * <li><i>DwtEvent.DISPOSE</i></li>
 46  * <li><i>DwtEvent.HOVEROVER</i></li>
 47  * <li><i>DwtEvent.HOVEROUT</i></li>
 48  * <li><i>DwtEvent.ONCONTEXTMENU</i></li>
 49  * <li><i>DwtEvent.ONCLICK</i></li>
 50  * <li><i>DwtEvent.ONDBLCLICK</i></li>
 51  * <li><i>DwtEvent.ONFOCUS</i></li>
 52  * <li><i>DwtEvent.ONBLUR</i></li>
 53  * <li><i>DwtEvent.ONMOUSEDOWN</i></li>
 54  * <li><i>DwtEvent.ONMOUSEENTER</i></li>
 55  * <li><i>DwtEvent.ONMOUSELEAVE</i></li>
 56  * <li><i>DwtEvent.ONMOUSEMOVE</i></li>
 57  * <li><i>DwtEvent.ONMOUSEOUT</i></li>
 58  * <li><i>DwtEvent.ONMOUSEOVER</i></li>
 59  * <li><i>DwtEvent.ONMOUSEUP</i></li>
 60  * <li><i>DwtEvent.ONMOUSEWHEEL</i></li>
 61  * <li><i>DwtEvent.ONSELECTSTART</i></li>
 62  * </ul>
 63  *
 64  * @author Ross Dargahi
 65  * 
 66  * @param {hash}		params			a hash of parameters
 67  * @param	{DwtComposite}	parent		the parent widget, except in the case of {@link DwtShell}, the parent will be a control that is a subclass of {@link DwtComposite}
 68  * @param	{string}	className		the CSS class
 69  * @param	{constant}	posStyle		the positioning style (absolute, static, or relative). Defaults to {@link DwtControl.STATIC_STYLE}.
 70  * @param	{boolean}	deferred		if <code>true</code>, postpone initialization until needed
 71  * @param	{string}	id			    an explicit ID to use for the control's HTML element. If not provided, defaults to an auto-generated ID.
 72  * @param	{string|HTMLElement}	parentElement   the parent element
 73  * @param	{number}	index 		    the index at which to add this control among parent's children
 74  * @param   {boolean}   isFocusable     if false, this control does not take browser focus (its element will not have a tabindex); defaults to true
 75  * @param   {string}    role            ARIA role for this control
 76  *
 77  */
 78 DwtControl = function(params) {
 79 
 80 	if (arguments.length == 0) { return; }
 81 	params = Dwt.getParams(arguments, DwtControl.PARAMS);
 82 
 83 	/**
 84 	 * parent component. Read-Only
 85 	 * 
 86 	 * @private
 87 	 */
 88 	var parent = this.parent = params.parent;
 89 	if (parent && !(parent.isDwtComposite)) {
 90 		throw new DwtException("Parent must be a subclass of Composite", DwtException.INVALIDPARENT, "DwtControl");
 91 	}
 92 
 93 	/**
 94 	 * the control's <i>DwtShell</i>
 95 	 * @private
 96 	 */
 97 	this.shell = null;
 98 
 99 	/**
100 	 * Data object used to store "client data" on the widget via the
101 	 * <code>setData</code> and <code>getData</code> methods
102 	 * 
103 	 * @type hash
104 	 * @private
105 	 */
106 	this._data = {};
107 
108 	/**
109 	 * The event manager controls the mapping between event types and the registered listeners.
110 	 * @type AjxEventMgr
111 	 * @private
112 	 */
113 	this._eventMgr = new AjxEventMgr();
114 
115 	/** true if the control is disposed, else false. The public api to this
116 	 * member is <code>isDisposed</code>.
117 	 * 
118 	 * @type boolean
119 	 * @private
120 	 */
121 	this._disposed = false;
122 
123 	// set to true for an event type to override default behavior of swallowing the event
124 	this._propagateEvent = {};
125 
126 	// don't swallow mouse wheel events; we often want to react to them, while
127 	// letting the browser continue to scroll
128 	this._propagateEvent[DwtEvent.ONMOUSEWHEEL] = true;
129 
130  	if (!parent) { return; }
131 
132 	/** CSS class name
133 	 * @type string
134 	 * @private
135 	 */
136 	this._className = params.className || "DwtControl";
137 
138 	/**
139 	 * @private
140 	 */
141 	this.__posStyle = params.posStyle;
142 
143 	/**
144 	 * id of the control's HTML element
145 	 * @type string
146 	 * @private
147 	 */
148 	if (params.id) {
149 		this._htmlElId = params.id;
150 	}
151 
152 	this.isFocusable = (params.isFocusable !== false);
153 
154 	if (params.role != null) {
155 		this.role = params.role;
156 	}
157 
158 	/**
159 	 * @private
160 	 */
161 	this.__index = params.index;
162 
163 	this.__parentElement = params.parentElement;
164 
165 	/**
166 	 * enabled state of this control. Public APIs to this member are
167 	 * <code>getEnabled</code> and <code>setEnabled</code>.
168 	 * 
169 	 * @type boolean
170 	 * @private
171 	 */
172 	this._enabled = false;
173 
174 	/**
175 	 * Indicates the drag state of the control. Valid values are:
176 	 * <ul>
177 	 * <li>DwtControl._NO_DRAG<li>
178 	 * <li>DwtControl._DRAGGING<li>
179 	 * <li>DwtControl._DRAG_REJECTED<li>
180 	 * </ul>
181 	 * 
182 	 * @type number
183 	 * @private
184 	 */
185 	this._dragging = null;
186 
187 	/**
188 	 * Drag n drop icon. Valid when a drag and drop operation is occurring.
189 	 * 
190 	 * @type HTMLElement
191 	 * @private
192 	 */
193 	this._dndProxy = null;
194 
195 	/**
196 	 * Flag indicating whether the control has keyboard focus or not.
197 	 * 
198 	 * @type boolean
199 	 * @private
200 	 */
201 	this._hasFocus = false;
202 
203 	if (!params.deferred) {
204 		this.__initCtrl();
205 	}
206 
207 	/**
208 	 * Hover over listener.
209 	 * 
210 	 * @type AjxListener
211 	 * @private
212 	 */
213 	this._hoverOverListener = new AjxListener(this, this.__handleHoverOver);
214 
215 	/**
216 	 * Hover out listener.
217 	 * 
218 	 * @type AjxListener
219 	 * @private
220 	 */
221 	this._hoverOutListener = new AjxListener(this, this.__handleHoverOut);
222 
223 	// turn this on to receive only the dblclick event (rather than click,
224 	// click, dblclick); penalty is that single click's timer must expire
225 	// before it is processed; useful if control has both single and double
226 	// click actions, and single click action is heavy
227 	this._dblClickIsolation = false;
228 
229 	// set to true to ignore OVER and OUT mouse events between elements in the same control
230 	this._ignoreInternalOverOut = false;
231 	
232 	// override this control's default template
233 	this.TEMPLATE = params.template || this.TEMPLATE;
234 };
235 
236 DwtControl.prototype.isDwtControl = true;
237 DwtControl.prototype.toString = function() { return "DwtControl"; };
238 
239 DwtControl.prototype.isFocusable = null;
240 
241 DwtControl.PARAMS = ["parent", "className", "posStyle", "deferred", "id", "index", "template"];
242 
243 DwtControl.ALL_BY_ID = {};
244 
245 
246 //
247 // Constants
248 //
249 
250 // Display states
251 /**
252  * Defines the "normal" display state.
253  */
254 DwtControl.NORMAL = "";
255 /**
256  * Defines the "active" display state.
257  */
258 DwtControl.ACTIVE = "ZActive";
259 /**
260  * Defines the "focused" display state.
261  */
262 DwtControl.FOCUSED = "ZFocused";
263 /**
264  * Defines the "disabled" display state.
265  */
266 DwtControl.DISABLED = "ZDisabled";
267 /**
268  * Defines the "hover" display state.
269  */
270 DwtControl.HOVER = "ZHover";
271 /**
272  * Defines the "selected" display state.
273  */
274 DwtControl.SELECTED = "ZSelected";
275 /**
276  * Defines the "default" display state.
277  */
278 DwtControl.DEFAULT = "ZDefault";
279 /**
280  * Defines the "error" display state.
281  */
282 DwtControl.ERROR = "ZError";
283 
284 DwtControl._STATES = [
285 	DwtControl.ACTIVE,  DwtControl.FOCUSED,     DwtControl.DISABLED,
286 	DwtControl.HOVER,   DwtControl.SELECTED,    DwtControl.DEFAULT,
287 	DwtControl.ERROR
288 ];
289 
290 DwtControl._RE_STATES = new RegExp(
291     "\\b(" + DwtControl._STATES.join("|") + ")\\b", "g"
292 );
293 
294 DwtControl._RE_STATE = AjxUtil.arrayAsHash(
295 	DwtControl._STATES,
296 	function(state) {
297 		return new RegExp("\\b" + state + "\\b", "g");
298 	});
299 
300 DwtControl._ARIA_STATES = {};
301 DwtControl._ARIA_STATES[DwtControl.DISABLED] = 'aria-disabled';
302 DwtControl._ARIA_STATES[DwtControl.SELECTED] = 'aria-selected';
303 DwtControl._ARIA_STATES[DwtControl.ERROR] = 'aria-invalid';
304 
305 // Try to use browser tooltips (setting 'title' attribute) if possible
306 DwtControl.useBrowserTooltips = false;
307 
308 
309 /*
310  * Position styles
311  * 
312  */
313 
314 /**
315  * Defines the static position style.
316  * 
317  * @see  Dwt.STATIC_STYLE
318  */
319 DwtControl.STATIC_STYLE = Dwt.STATIC_STYLE;
320 
321 /**
322  * Defines the absolute position style.
323  * 
324  * @see Dwt.ABSOLUTE_STYLE
325  */
326 DwtControl.ABSOLUTE_STYLE = Dwt.ABSOLUTE_STYLE;
327 
328 /**
329  * Defines the relative position style.
330  * 
331  * @see Dwt.RELATIVE_STYLE
332  */
333 DwtControl.RELATIVE_STYLE = Dwt.RELATIVE_STYLE;
334 
335 /**
336  * Defines the fixed position style.
337  * 
338  * @see Dwt.FIXED_STYLE
339  */
340 DwtControl.FIXED_STYLE = Dwt.FIXED_STYLE;
341 
342 
343 /*
344  * 
345  * Overflow style
346  * 
347  */
348 
349 /**
350  * 
351  * Defines clip on overflow.
352  * 
353  * @see Dwt.CLIP
354  */
355 DwtControl.CLIP = Dwt.CLIP;
356 
357 /**
358  * Defines allow overflow to be visible.
359  * 
360  * @see Dwt.VISIBLE
361  */
362 DwtControl.VISIBLE = Dwt.VISIBLE;
363 
364 /**
365  * Defines automatically create scrollbars if content overflows.
366  * 
367  * @see Dwt.SCROLL
368  */
369 DwtControl.SCROLL = Dwt.SCROLL;
370 
371 /**
372  * Defines always have scrollbars whether content overflows or not.
373  * 
374  * @see Dwt.FIXED_SCROLL
375  */
376 DwtControl.FIXED_SCROLL = Dwt.FIXED_SCROLL;
377 
378 
379 // DnD states
380 /**
381  * Defines "no drag" in progress.
382  * 
383  * @private
384  */
385 DwtControl._NO_DRAG = "NO_DRAG";
386 
387 /**
388  * Defines "drag" in progress.
389  *
390  * @private
391  */
392 DwtControl._DRAGGING = "DRAGGING";
393 
394 /**
395  * Defines "drag rejected".
396  * 
397  * @private
398  */
399 DwtControl._DRAG_REJECTED = "DRAG_REJECTED";
400 
401 /**
402  * Defines "drag threshold".
403  * 
404  * @private
405  */
406 DwtControl.__DRAG_THRESHOLD = 3;
407 
408 /**
409  * Defines "tooltip threshold".
410  *
411  * @private
412  */
413 DwtControl.__TOOLTIP_THRESHOLD = 5;
414 
415 /**
416  * @private
417  */
418 DwtControl.__DND_HOVER_DELAY = 750;
419 
420 /**
421  * @private
422  */
423 DwtControl.__controlEvent = new DwtControlEvent();
424 
425 /**
426  * Applies only if control has turned on _doubleClickIsolation (see above)
427  * want to hit sweet spot where value is more than actual dbl click speed,
428  * but as low as possible since it also the length of single click pause.
429  * 
430  * @private
431  */
432 DwtControl.__DBL_CLICK_TIMEOUT = 300;
433 
434 //
435 // Data
436 //
437 
438 /**
439  * @private
440  */
441 DwtControl.prototype._displayState = "";
442 
443 //
444 // Public methods
445 //
446 
447 /**
448  * Adds a control event listener for control events. Control events are essentially
449  * resize and coordinate change events.
450  *
451  * @param {AjxListener} listener		the listener to be registered (may not be <code>null</code>)
452  *
453  * @see DwtControlEvent
454  * @see #removeControlListener
455  * @see #removeAllListeners
456  */
457 DwtControl.prototype.addControlListener =
458 function(listener) {
459 	this.addListener(DwtEvent.CONTROL, listener);
460 };
461 
462 /**
463  * Removes a control event listener for control events. Control events are essentially
464  * resize and coordinate change events.
465  *
466  * @param {AjxListener} listener		the listener to remove
467  *
468  * @see DwtControlEvent
469  * @see #addControlListener
470  * @see #removeAllListeners
471  */
472 DwtControl.prototype.removeControlListener =
473 function(listener) {
474 	this.removeListener(DwtEvent.CONTROL, listener);
475 };
476 
477 /**
478  * Registers a dispose listener for control events. Dispose events are fired when
479  * a control is "destroyed" via the {@link #dispose} call.
480  *
481  * @param {AjxListener} listener		the listener to be registered (may not be <code>null</code>)
482  *
483  * @see DwtDisposeEvent
484  * @see #removeDisposeListener
485  * @see #removeAllListeners
486  * @see #dispose
487  * @see #isDisposed
488  */
489 DwtControl.prototype.addDisposeListener =
490 function(listener) {
491 	this.addListener(DwtEvent.DISPOSE, listener);
492 };
493 
494 /**
495  * Removes a dispose event listener for control events. Dispose events are fired when
496  * a control is "destroyed" via the {@link #dispose} method call.
497  *
498  * @param {AjxListener} listener		the listener to remove
499  *
500  * @see DwtDisposeEvent
501  * @see #addDisposeListener
502  * @see #removeAllListeners
503  * @see #dispose
504  * @see #isDisposed
505  */
506 DwtControl.prototype.removeDisposeListener =
507 function(listener) {
508 	this.removeListener(DwtEvent.DISPOSE, listener);
509 };
510 
511 /**
512  * Adds a listener to the control. The listener will be call when events
513  * of type <code>eventType</code> fire.
514  *
515  * @param {string} eventType		the event type for which to listen (may not be <code>null</code>)
516  * @param {AjxListener} listener	the listener to register (may not be <code>null</code>)
517  * @param {number}		index		the index at which to add listener
518  *
519  * @see DwtEvent
520  * @see #removeListener
521  * @see #removeAllListeners
522  * @see #notifyListeners
523  */
524 DwtControl.prototype.addListener =
525 function(eventType, listener, index) {
526 	return this._eventMgr.addListener(eventType, listener, index);
527 };
528 
529 /**
530  * Removes a listener from the control.
531  *
532  * @param {string} eventType		the event type for which to listen (may not be <code>null</code>)
533  * @param {AjxListener} listener	the listener to remove (may not be <code>null</code>)
534  *
535  * @see DwtEvent
536  * @see #addListener
537  * @see #removeAllListeners
538  */
539 DwtControl.prototype.removeListener =
540 function(eventType, listener) {
541 	return this._eventMgr.removeListener(eventType, listener);
542 };
543 
544 /**
545  * Removes all listeners for a particular event type.
546  *
547  * @param {string} eventType		the event type (may not be <code>null</code>)
548  * @return	{boolean}	<code>true</code> if all listeners are removed
549  * 
550  * @see DwtEvent
551  * @see #addListener
552  * @see #removeListener
553  */
554 DwtControl.prototype.removeAllListeners =
555 function(eventType) {
556 	return this._eventMgr.removeAll(eventType);
557 };
558 
559 /**
560  * Checks if there are any listeners registered for a particular event type.
561  *
562  * @param {string} eventType		the event type (may not be <code>null</code>)
563  *
564  * @return {boolean}	<code>true</code> if there is an listener registered for the specified event type
565  * @see DwtEvent
566  */
567 DwtControl.prototype.isListenerRegistered =
568 function(eventType) {
569 	return this._eventMgr.isListenerRegistered(eventType);
570 };
571 
572 /**
573  * Notifies all listeners of type <code>eventType</code> with <code>event</code>.
574  *
575  * @param {string} eventType		the event type (may not be <code>null</code>)
576  * @param {DwtEvent} event		the event
577  */
578 DwtControl.prototype.notifyListeners =
579 function(eventType, event) {
580 	return this._eventMgr.notifyListeners(eventType, event);
581 };
582 
583 /**
584  * Disposes of the control. This method will remove the control from under the
585  * control of its parent and release any resources associate with the component
586  * it will also notify any event listeners on registered {@link DwtEvent.DISPOSE} event type.
587  *
588  * <p>
589  * Subclasses may override this method to perform their own dispose functionality but
590  * should generally call up to the parent method.
591  *
592  * @see #isDisposed
593  * @see #addDisposeListener
594  * @see #removeDisposeListener
595  */
596 DwtControl.prototype.dispose =
597 function() {
598 	if (this._disposed) { return; }
599 
600 	if (this.parent && this.parent.isDwtComposite) {
601 		this.parent.removeChild(this);
602 	}
603 	this._elRef = null;
604 	
605     DwtControl.ALL_BY_ID[this._htmlElId] = null;
606     delete DwtControl.ALL_BY_ID[this._htmlElId];
607 
608 	this._disposed = true;
609 	var ev = new DwtDisposeEvent();
610 	ev.dwtObj = this;
611 	this.notifyListeners(DwtEvent.DISPOSE, ev);
612     this._eventMgr.clearAllEvents();
613 };
614 
615 /**
616  * This method is deprecated. Please use "document" directly.
617  * @deprecated
618  * @private
619  */
620 DwtControl.prototype.getDocument =
621 function() {
622 	return document;
623 };
624 
625 /**
626  * Gets the tab group member for this control. Tab group members can
627  * be a native HTML form element, a {@link DwtControl}, or a {@link DwtTabGroup} (for more
628  * complex or explicit tab-ordering.
629  * 
630  * @return	{DwtControl}	by default, returns this object
631  */
632 DwtControl.prototype.getTabGroupMember = function() {
633 
634     return this.tabGroupMember || this;
635 };
636 
637 /**
638  * Gets the data associated with the specified key.
639  *
640  * @param {string} key		the key
641  * @return {Object}		the associated data
642  * 
643  * @see #setData
644  */
645 DwtControl.prototype.getData =
646 function(key) {
647 	return this._data[key];
648 };
649 
650 /**
651  * Sets the data for a given key. This method is useful for associating client data with a control.
652  *
653  * @param {string} key		the key
654  * @param {Object} value	the data
655  * 
656  * @see #getData
657  */
658 DwtControl.prototype.setData =
659 function(key, value) {
660   this._data[key] = value;
661 };
662 
663 /**
664  * Checks if the control is disposed.
665  * 
666  * @return {boolean}	<code>true</code> if the control is in a disposed state; <code>false</code> otherwise
667  *
668  * @see #dispose
669  * @see #addDisposeListener
670  * @see #removeDisposeListener
671  */
672 DwtControl.prototype.isDisposed =
673 function() {
674 	return this._disposed;
675 };
676 
677 /**
678  * Checks if the control is initialized. In general, a control will not be
679  * initialized if it has been created in deferred mode and has not yet been initialized.
680  * 
681  * @return {boolean}	<code>true</code> if the control is in a initialized; <code>false</code> otherwise
682  */
683 DwtControl.prototype.isInitialized =
684 function() {
685 	return this.__ctrlInited;
686 };
687 
688 /**
689  * Sets browser and keyboard focus to this control.
690  *
691  *  @return  {DwtControl|Element}   control or element that actually got focused
692  */
693 DwtControl.prototype.focus = function() {
694 
695     DBG.println(AjxDebug.FOCUS, "DwtControl FOCUS: " + [this, this._htmlElId].join(' / '));
696     if (!this._checkState()) {
697         return;
698     }
699 
700     var el = this.getFocusElement();
701     if (el && el.focus) {
702         AjxTimedAction.scheduleAction(this._focusAction);
703 
704         // retain the scroll position if the user scrolled, since setting focus will cause browser to scroll this control into view
705         var scrollContainer = this.getScrollContainer(),
706             scrollTop = scrollContainer && scrollContainer.scrollTop;
707 
708         el.focus();
709 
710         if (scrollTop > 0) {
711             DBG.println(AjxDebug.DBG1, "Resetting scroll after focus to: " + scrollTop);
712             scrollContainer.scrollTop = scrollTop;
713         }
714     }
715 
716     return this;
717 };
718 
719 /**
720  * Takes browser and keyboard focus away from this control.
721  *
722  *  @return   {DwtControl|Element}  control or element that actually got blurred
723  */
724 DwtControl.prototype.blur = function() {
725 
726     DBG.println(AjxDebug.FOCUS, "DwtControl BLUR: " + [this, this._htmlElId].join(' / '));
727     if (!this._checkState()) {
728         return;
729     }
730     var el = this.getFocusElement();
731     if (el && el.blur) {
732         AjxTimedAction.scheduleAction(this._blurAction);
733         el.blur();
734     }
735 
736     return this;
737 };
738 
739 /**
740  * Checks if this control has focus.
741  * 
742  * @return {boolean}	<code>true</code> if this control has keyboard focus; <code>false</code> otherwise
743  */
744 DwtControl.prototype.hasFocus =
745 function() {
746 	return this._hasFocus;
747 };
748 
749 /**
750  * Handles key actions and is called by the keyboard navigation framework. Subclasses
751  * should override this method to provide behavior for supported key actions.
752  * 
753  * @param	{DwtKeyMap}	actionCode	the key action code
754  * @param	{DwtKeyEvent}	ev		the key event
755  * @return	{boolean}	<code>true</code> if the event is handled; <code>false</code> otherwise
756  * 
757  * @private
758  *
759  */
760 DwtControl.prototype.handleKeyAction =
761 function(actionCode, ev) {
762 	return false;
763 };
764 
765 /**
766  * Re-parents the control within the component hierarchy. Unlike <i>reparentHtmlElement</i>
767  * which re-parents the controls <i>div</i> within the DOM hierarchy, this method re-parents
768  * the whole control.
769  *
770  * @param {DwtComposite} newParent 	the control's new parent
771  * @param	{number}	index	the index
772  * 
773  * @see #reparentHtmlElement
774  */
775 DwtControl.prototype.reparent =
776 function(newParent, index) {
777 	if (!this._checkState()) { return; }
778 
779 	var htmlEl = this.getHtmlElement();
780 	this.parent.removeChild(this, true);
781 	DwtComposite._pendingElements[this._htmlElId] = htmlEl;
782 	newParent.addChild(this, index);
783 	this.parent = newParent;
784 	// TODO do we need a reparent event?
785 };
786 
787 /**
788  * Re-parents the HTML element of the control to the html element supplied as the
789  * parameter to this method. Note this method only re-parents the control's <i>div</i>
790  * element and does not affect the component hierarchy. To re-parent the control within
791  * the component hierarchy, use the <i>reparent</i> method.
792  *
793  * @param {string|HTMLElement} htmlEl a string representing an element ID or an HTML element
794  * @param {number} position 	the position to insert the element
795  *
796  * @see #reparent
797  */
798 DwtControl.prototype.reparentHtmlElement =
799 function(htmlEl, position) {
800 
801 	// If htmlEl is a string, then it is an ID so lookup the html element that
802 	// has the corresponding ID
803 	if (typeof htmlEl == "string") {
804 		htmlEl = document.getElementById(htmlEl);
805 	}
806 	if (!htmlEl) { return; }
807 
808 	var el = this.getHtmlElement();
809 	if (position == null) {
810 		htmlEl.appendChild(el);
811 	} else if (typeof position == "object") {
812 		htmlEl.insertBefore(el, position);
813 	} else {
814 		if (htmlEl.childNodes[position]) {
815 			htmlEl.insertBefore(el, htmlEl.childNodes[position]);
816 		} else {
817 			htmlEl.appendChild(el);
818 		}
819 	}
820 };
821 
822 /**
823  * Sets the event handling function for a given event type. This method
824  * should be used judiciously as it can lead to unexpected results (for example if
825  * overriding the control's mouse handlers). This method calls through to <i>Dwt.setHandler</i>
826  *
827  * @param {string} eventType 	the event type (defined in {@see DwtEvent}) to override 
828  * @param {function} hdlrFunc Event handler function
829  *
830  * @see DwtEvent
831  */
832 DwtControl.prototype.setHandler =
833 function(eventType, hdlrFunc) {
834 	if (!this._checkState()) { return; }
835 
836 	var htmlElement = this.getHtmlElement();
837 	Dwt.setHandler(htmlElement, eventType, hdlrFunc);
838 };
839 
840 /**
841  * Clears the event handling function for a given event type. This method
842  * should be used judiciously as it can lead to unexpected results (for example if
843  * overriding the control's mouse handlers)
844  *
845  * @param {string} eventType 	the event type (defined in {@see DwtEvent}) to override 
846  *
847  * @see DwtEvent
848  */
849 DwtControl.prototype.clearHandler =
850 function(eventType) {
851 	if (!this._checkState()) { return; }
852 
853 	var htmlElement = this.getHtmlElement();
854 	Dwt.clearHandler(htmlElement, eventType);
855 };
856 
857 /**
858  * Set the default behavior for whether an event will propagate (bubble up).
859  * 
860  * @param {boolean}		propagate		if true, event will propagate
861  * @param {array}		events			one or more events
862  */
863 DwtControl.prototype.setEventPropagation =
864 function(propagate, events) {
865 	events = AjxUtil.toArray(events);
866 	for (var i = 0; i < events.length; i++) {
867 		this._propagateEvent[events[i]] = propagate;
868 	}
869 };
870 
871 /**
872  * Gets the bounds of the component. Bounds includes the location (not relevant for
873  * statically position elements) and dimensions of the control (i.e. the <code><div></code> element).
874  *
875  * @return {DwtRectangle}		the control bounds
876  *
877  * @see DwtRectangle
878  * @see #getInsetBounds
879  * @see #getInsets
880  * @see #getSize
881  * @see #getLocation
882  * @see #getH
883  * @see #getW
884  * @see #getX
885  * @see #getXW
886  * @see #getY
887  * @see #getYH
888  * @see #setBounds
889  * @see #setSize
890  * @see #setLocation
891  */
892 DwtControl.prototype.getBounds =
893 function() {
894 	if (!this._checkState()) { return; }
895 
896 	return Dwt.getBounds(this.getHtmlElement());
897 };
898 
899 /**
900  * Gets the inset bounds of the component. Similar to the bounds, but excluding borders and paddings.
901  *
902  * @return {DwtRectangle}		the control inset bounds
903  *
904  * @see DwtRectangle
905  * @see #getBounds
906  * @see #getInsets
907  * @see #getSize
908  * @see #getLocation
909  * @see #getH
910  * @see #getW
911  * @see #getX
912  * @see #getXW
913  * @see #getY
914  * @see #getYH
915  * @see #setBounds
916  * @see #setSize
917  * @see #setLocation
918  */
919 DwtControl.prototype.getInsetBounds =
920 function() {
921 	if (!this._checkState()) { return; }
922 
923 	return Dwt.getInsetBounds(this.getHtmlElement());
924 };
925 
926 /**
927  * Gets the insets of the component, i.e. the width of borders and paddings.
928  *
929  * @return {DwtRectangle}		the control insets
930  *
931  * @see DwtRectangle
932  * @see #getBounds
933  * @see #getInsetBounds
934  * @see #getMargins
935  * @see #getSize
936  * @see #getLocation
937  * @see #getH
938  * @see #getW
939  * @see #getX
940  * @see #getXW
941  * @see #getY
942  * @see #getYH
943  * @see #setBounds
944  * @see #setSize
945  * @see #setLocation
946  */
947 DwtControl.prototype.getInsets =
948 function() {
949 	if (!this._checkState()) { return; }
950 
951 	return Dwt.getInsets(this.getHtmlElement());
952 };
953 
954 /**
955  * Gets the margins of the component.
956  *
957  * @return {DwtRectangle}		the control margins
958  *
959  * @see DwtRectangle
960  * @see #getBounds
961  * @see #getInsetBounds
962  * @see #getInsets
963  * @see #getSize
964  * @see #getLocation
965  * @see #getH
966  * @see #getW
967  * @see #getX
968  * @see #getXW
969  * @see #getY
970  * @see #getYH
971  * @see #setBounds
972  * @see #setSize
973  * @see #setLocation
974  */
975 DwtControl.prototype.getMargins =
976 function() {
977 	if (!this._checkState()) {
978 		return;
979 	}
980 
981 	return Dwt.getMargins(this.getHtmlElement());
982 };
983 
984 /**
985  * Sets the bounds of a control. The position type of the control must
986  * be absolute or else an exception is thrown. To omit setting a value set the
987  * actual parameter value to <i>Dwt.DEFAULT</i>
988  *
989  * @param {number|string} x		the x coordinate of the element (for example: 10, "10px", Dwt.DEFAULT)
990  * @param {number|string} y		the y coordinate of the element (for example: 10, "10px", Dwt.DEFAULT)
991  * @param {number|string} width	the width of the element (for example: 100, "100px", "75%", Dwt.DEFAULT)
992  * @param {number|string} height	the height of the element (for example: 100, "100px", "75%", Dwt.DEFAULT)
993  *
994  * @return {DwtControl}		this control
995  *
996  * @see DwtRectangle
997  * @see #getBounds
998  * @see #getInsetBounds
999  * @see #getInsets
1000  * @see #setSize
1001  * @see #setLocation
1002  * @see #getSize
1003  * @see #getLocation
1004  * @see #getH
1005  * @see #getW
1006  * @see #getX
1007  * @see #getXW
1008  * @see #getY
1009  * @see #getYH
1010  */
1011 DwtControl.prototype.setBounds =
1012 function(x, y, width, height) {
1013 	if (!this._checkState()) { return; }
1014 
1015 	var htmlElement = this.getHtmlElement();
1016 	if (this.isListenerRegistered(DwtEvent.CONTROL)) {
1017 		this.__controlEvent.reset(DwtControlEvent.RESIZE | DwtControlEvent.MOVE);
1018 		var bds = Dwt.getBounds(htmlElement);
1019 		this.__controlEvent.oldX = bds.x;
1020 		this.__controlEvent.oldY = bds.y;
1021 		this.__controlEvent.oldWidth = bds.width;
1022 		this.__controlEvent.oldHeight = bds.height;
1023         //TODO: notifyListeners() called atleast 3 times. Should minimize the calls.
1024 		this.setLocation(x, y);
1025 		this.setSize(width, height);
1026 		bds = Dwt.getBounds(htmlElement);
1027 		this.__controlEvent.newX = bds.x;
1028 		this.__controlEvent.newY = bds.y;
1029 		this.__controlEvent.newWidth = (AjxUtil.isNumber(width)) ? width : bds.width; //if it's exact number, no need to use the bounds, especially since they are not accurate, wrong in about 2 pixels at least in the case I'm testing.
1030 		this.__controlEvent.newHeight = (AjxUtil.isNumber(height)) ? height : bds.height;
1031 		this.__controlEvent.requestedWidth = width;
1032 		this.__controlEvent.requestedHeight = height;
1033 		this.notifyListeners(DwtEvent.CONTROL, this.__controlEvent);
1034 	} else {
1035 		this.setLocation(x, y);
1036 		this.setSize(width, height);
1037 	}
1038 
1039 	return this;
1040 }
1041 
1042 /**
1043  * Gets the class name of this control. The class name may be set
1044  * when constructing the control. If it is not passed into the constructor, it
1045  * defaults to the control's class name. The class name is generally used as the
1046  * CSS class name for the control, although control's that change visual behaviour
1047  * based on state may append (or even use different) class names. See the documentation
1048  * of the specific component for details.
1049  *
1050  * @return {string}		the control class name
1051  *
1052  * @see #setClassName
1053  */
1054 DwtControl.prototype.getClassName =
1055 function() {
1056 	return this._className;
1057 };
1058 
1059 /**
1060  * Sets the control class name. This also automatically sets the control CSS
1061  * class name (i.e. the control htmlElement class name). Subclasses of <i>DwtControl</i>
1062  * may override this method to perform a different behavior.
1063  *
1064  * @param {string} className		the new class name for the control
1065  *
1066  * @see #getClassName
1067  */
1068 DwtControl.prototype.setClassName =
1069 function(className) {
1070 	if (!this._checkState()) { return; }
1071 
1072 	this._className = className;
1073     var el = this.getHtmlElement();
1074     el.className = className;
1075     Dwt.addClass(el, this._displayState);
1076 };
1077 
1078 /**
1079  * Adds a class name to this control HTML element.
1080  *
1081  * @param {string} className		the class name to add
1082  */
1083 DwtControl.prototype.addClassName =
1084 function(className) {
1085 	Dwt.addClass(this.getHtmlElement(), className);
1086 };
1087 
1088 /**
1089  * Removes a class name from this control's HTML element. Optionally adds a new class name, if specified.
1090  *
1091  * @param {string} delClass		the class to remove
1092  * @param {string} addClass		the class to add (may be <code>null</code>)
1093  */
1094 DwtControl.prototype.delClassName =
1095 function(delClass, addClass) {
1096 	Dwt.delClass(this.getHtmlElement(), delClass, addClass);
1097 };
1098 
1099 /**
1100  * Conditionally adds or removes a class name to this control HTML element.
1101  * The class names are used exclusively, that is: when condition is true,
1102  * <code>classWhenTrue</code> is added and <code>classWhenFalse</code> is removed (if present and
1103  * specified).  When condition is false, <code>classWhenTrue</code> is removed and
1104  * <code>classWhenFalse</code> is added (again, if present and specified).
1105  *
1106  * @param {string} condition	the condition
1107  * @param {string} classWhenTrue	the class name to add when condition is <code>true</code>
1108  * @param {string} classWhenFalse	the class name to add when contition is <code>false</code> (may be <code>null</code>)
1109  */
1110 DwtControl.prototype.condClassName = function(condition, classWhenTrue, classWhenFalse) {
1111 	Dwt.condClass(this.getHtmlElement(), condition, classWhenTrue, classWhenFalse);
1112 };
1113 
1114 /**
1115  * Sets the display state.
1116  * 
1117  * @param	{Object}		state		the state
1118  */
1119 DwtControl.prototype.setDisplayState =
1120 function(state) {
1121     if (!this._enabled) {
1122 		state = DwtControl.DISABLED;
1123 	}
1124 
1125     if (arguments.length > 1) {
1126         var a = [];
1127         for (var i = 0; i < arguments.length; i++) {
1128             a.push(arguments[i]);
1129         }
1130         state = a.join(" ");
1131     }
1132 
1133     if (this._displayState == state) {
1134         return;
1135     }
1136 
1137 	var oldState = this._displayState;
1138 
1139     this._displayState = state;
1140     Dwt.delClass(this.getHtmlElement(), DwtControl._RE_STATES, state);
1141 
1142     AjxUtil.foreach(DwtControl._ARIA_STATES, (function(attribute, state) {
1143         if (DwtControl._RE_STATE[state].test(this._displayState)) {
1144             this.setAttribute(attribute, true);
1145         } else {
1146             this.removeAttribute(attribute);
1147         }
1148     }).bind(this));
1149 
1150 	if (this.isListenerRegistered(DwtEvent.STATE_CHANGE)) {
1151 		this.__controlEvent.reset(DwtControlEvent.STATE);
1152 		this.__controlEvent.oldState = oldState;
1153 		this.__controlEvent.newState = state;
1154 		this.__controlEvent.dwtObj = this;
1155 		this.notifyListeners(DwtEvent.STATE_CHANGE, this.__controlEvent);
1156 	}
1157 };
1158 
1159 /**
1160 * Shows an alert in the control. For example, to indicate that a new message has arrived.
1161 *
1162 * @param	{string}	alert		the alert
1163 */
1164 DwtControl.prototype.showAlert =
1165 function(alert) {
1166 	if (alert && !this._alert) {
1167 		this.delClassName(null, "ZAlert");
1168 	} else if (!alert && this._alert) {
1169 		this.delClassName("ZAlert", null);
1170 	}
1171 	this._alert = alert;
1172 };
1173 
1174 /**
1175 * Checks if the control is showing an alert.
1176 * 
1177 * @return	{boolean}	<code>true</code> if showing an altert; <code>false</code> otherwise
1178 */
1179 DwtControl.prototype.isAlertShown =
1180 function() {
1181 	return this._alert;
1182 };
1183 
1184 /**
1185  * @private
1186  */
1187 DwtControl.prototype._createHtmlFromTemplate =
1188 function(templateId, data) {
1189     // set html content
1190     this.getHtmlElement().innerHTML = AjxTemplate.expand(templateId, data);
1191 
1192     // set container class name, if needed
1193     var params = AjxTemplate.getParams(templateId);
1194     var className = params && params["class"];
1195     if (className) {
1196         className = [ this._className, className ].join(" ");
1197         this.setClassName(className);
1198     }
1199 };
1200 
1201 /**
1202  * Gets the control cursor.
1203  * 
1204  * @return {string}		the control cursor
1205  *
1206  * @see #setCursor
1207  */
1208 DwtControl.prototype.getCursor =
1209 function() {
1210 	if (!this._checkState()) { return; }
1211 
1212 	return Dwt.getCursor(this.getHtmlElement());
1213 };
1214 
1215 /**
1216  * Sets the control cursor.
1217  *
1218  * @param {string} cursorName		the name of the new cursor
1219  *
1220  * @see #getCursor
1221  */
1222 DwtControl.prototype.setCursor =
1223 function(cursorName) {
1224 	if (!this._checkState()) { return; }
1225 
1226 	Dwt.setCursor(this.getHtmlElement(), cursorName);
1227 };
1228 
1229 /**
1230  * Gets the control drag source.
1231  * 
1232  * @return {DwtDragSource}		the control drag source or <code>null</code> for none
1233  *
1234  * @see #setDragSource
1235  */
1236 DwtControl.prototype.getDragSource =
1237 function() {
1238 	return this._dragSource;
1239 };
1240 
1241 /**
1242  * Set the control drag source. The drag source binds the drag-and-drop system with
1243  * an application. Setting a control drag source makes the control "draggable".
1244  *
1245  * @param {DwtDragSource} dragSource		the control drag source
1246  *
1247  * @see #getDragSource
1248  */
1249 DwtControl.prototype.setDragSource =
1250 function(dragSource) {
1251 	this._dragSource = dragSource;
1252 	if (dragSource && !this._ctrlCaptureObj) {
1253 		this.__initCapture();
1254 		this._dndHoverAction = new AjxTimedAction(null, this.__dndDoHover);
1255 	}
1256 };
1257 
1258 /**
1259  * Gets the control drop target.
1260  * 
1261  * @return	{DwtDropTarget}		the control drop target or <code>null</code> for none
1262  *
1263  * @see #setDropTarget
1264  */
1265 DwtControl.prototype.getDropTarget =
1266 function() {
1267 	return this._dropTarget;
1268 };
1269 
1270 /**
1271  * Sets the drop target for the control. The drop target binds the drag-and-drop system with
1272  * an application. Setting a control drop target makes the control a potential drop
1273  * target within an application.
1274  *
1275  * @param {DwtDropTarget} dropTarget		the control drop target
1276  *
1277  * @see #getDropTarget
1278  */
1279 DwtControl.prototype.setDropTarget =
1280 function(dropTarget) {
1281 	this._dropTarget = dropTarget;
1282 };
1283 
1284 /**
1285  * Gets the control drag box.
1286  *
1287  * @return {DwtDragBox}		the control drag box or <code>null</code> for none
1288  *
1289  * @see #setDragBox
1290  */
1291 DwtControl.prototype.getDragBox =
1292 function() {
1293 	return this._dragBox;
1294 };
1295 
1296 /**
1297  * Set the control drag box. The drag box handles the display of a dotted rectangle
1298  * that is typically used to select items.
1299  *
1300  * @param {DwtDragBox} dragBox		the control drag box
1301  *
1302  * @see #getDragBox
1303  */
1304 DwtControl.prototype.setDragBox =
1305 function(dragBox) {
1306 	this._dragBox = dragBox;
1307 	if (dragBox && !this._ctrlCaptureObj) {
1308 		this.__initCapture();
1309 	}
1310 };
1311 
1312 DwtControl.prototype.__initCapture =
1313 function(dragBox) {
1314 	this._ctrlCaptureObj = new DwtMouseEventCapture({
1315 		targetObj:		this,
1316 		id:				"DwtControl",
1317 		mouseOverHdlr:	DwtControl.__mouseOverHdlr,
1318 		mouseDownHdlr:	DwtControl.__mouseDownHdlr,
1319 		mouseMoveHdlr:	DwtControl.__mouseMoveHdlr,
1320 		mouseUpHdlr:	DwtControl.__mouseUpHdlr,
1321 		mouseOutHdlr:	DwtControl.__mouseOutHdlr
1322 	});
1323 };
1324 
1325 /**
1326  * Gets the enabled state.
1327  * 
1328  * @return {boolean}		<code>true</code> if the control is enabled; <code>false</code> otherwise
1329  *
1330  * @see #setEnabled
1331  */
1332 DwtControl.prototype.getEnabled =
1333 function() {
1334 	if (!this._checkState()) { return; }
1335 
1336 	return this._enabled;
1337 };
1338 
1339 /**
1340  * Sets the control enabled state. If <code>setHtmlElement</code> is true, then
1341  * this method will also set the control HTML element disabled attribute.
1342  *
1343  * @param {boolean} enabled		<code>true</code> if the control is enabled
1344  * @param {boolean} setHtmlElement	<code>true</code> to set the control HTML element disabled attribute
1345  */
1346 DwtControl.prototype.setEnabled =
1347 function(enabled, setHtmlElement) {
1348 	if (!this._checkState()) { return; }
1349 
1350 	if (enabled != this._enabled) {
1351 		this._enabled = enabled;
1352         this.setDisplayState(enabled ? DwtControl.NORMAL : DwtControl.DISABLED);
1353         if (setHtmlElement)
1354 			this.getHtmlElement().disabled = !enabled;
1355 	}
1356 };
1357 
1358 /**
1359  * Gets the ID of the control containing HTML element.
1360  *
1361  * @return {string} 	the ID of the control containing HTML element
1362  */
1363 DwtControl.prototype.getHTMLElId =
1364 function () {
1365 	return this._htmlElId;
1366 };
1367 
1368 /**
1369  * Gets the control containing HTML element. By default this is a <code>div</code> element
1370  *
1371  * @return {HTMLElement}		the control containing HTML element
1372  */
1373 DwtControl.prototype.getHtmlElement =
1374 function() {
1375 	if (!this._checkState()) { return; }
1376 
1377 	var htmlEl = this._elRef || document.getElementById(this._htmlElId);
1378 	if (htmlEl == null) {
1379 		htmlEl = DwtComposite._pendingElements[this._htmlElId];
1380 	} else if (!htmlEl._rendered) {
1381 		delete DwtComposite._pendingElements[this._htmlElId];
1382 		htmlEl._rendered = true;
1383 	}
1384 	return this._elRef = htmlEl;
1385 };
1386 
1387 /**
1388  * Returns the element that should get browser focus when this control is focused.
1389  *
1390  * @returns {HTMLElement}
1391  */
1392 DwtControl.prototype.getFocusElement = function() {
1393 
1394     return this.isFocusable ? this._focusElement : null;
1395 };
1396 
1397 /**
1398  * Sets the "focus element" if this control is focusable. Adds focus/blur event handlers and a tabIndex to the focus element.
1399  * If no element is provided, defaults to the control's input element or its container (DIV).
1400  *
1401  * @param {HTMLElement} el      (optional) new focus element
1402  */
1403 DwtControl.prototype.setFocusElement = function(el) {
1404 
1405     if (!this.isFocusable) {
1406         return;
1407     }
1408 
1409     var hadFocus = (document.activeElement === this._focusElement),
1410         focusEl = el || (this.getInputElement && this.getInputElement()) || this.getHtmlElement();
1411 
1412     if (this._focusElement && this._focusElement !== focusEl) {
1413         this._makeFocusable(this._focusElement, false);
1414     }
1415 
1416     this._focusElement = focusEl;
1417 
1418     if (focusEl) {
1419         this._makeFocusable(this._focusElement, true);
1420         if (hadFocus) {
1421             focusEl.focus();
1422         }
1423     }
1424 };
1425 
1426 /**
1427  * Returns the control associated with the given element, if any.
1428  * 
1429  * @param {Element}		htmlEl	an HTML element
1430  * @return	{DwtControl}		the control element or <code>null</code> for none
1431  */
1432 DwtControl.fromElement = function(htmlEl)  {
1433 
1434 	return DwtControl.ALL_BY_ID[htmlEl.id];
1435 };
1436 
1437 /**
1438  * Returns the control associated with the given element ID, if any.
1439  * 
1440  * @param {string}		htmlElId	an HTML element Id
1441  * @return	{DwtControl}		the control element or <code>null</code> for none
1442  */
1443 DwtControl.fromElementId = function(htmlElId)  {
1444 
1445 	return DwtControl.ALL_BY_ID[htmlElId];
1446 };
1447 
1448 /**
1449  * Finds a control and starts the search at the given element and works
1450  * up the element chain until it finds one with an ID that maps to a {@link DwtControl}.
1451  * 
1452  * @param {Element}		htmlEl	an HTML element
1453  * @return	{DwtControl}	the control or <code>null</code> for none
1454  */
1455 DwtControl.findControl =
1456 function(htmlEl)  {
1457 
1458 	// FF 3.5 throws protection error if we dereference a chrome element, so bail
1459 	if (AjxEnv.isFirefox3_5up && !AjxEnv.isFirefox3_6up) {
1460 		var s = HTMLElement.prototype.toString.call(htmlEl);
1461 		if (s == '[xpconnect wrapped native prototype]' || s == '[object XULElement]') { return null; }
1462 	}
1463 
1464 	try{
1465 		while (htmlEl) {
1466 			if (htmlEl.id && DwtControl.ALL_BY_ID[htmlEl.id]) {
1467 				return DwtControl.ALL_BY_ID[htmlEl.id];
1468 			}
1469 			htmlEl = htmlEl.parentNode;
1470 		}
1471 	} catch(e) {
1472 		//In some FF, we might get permission denied error. Ignore it.
1473 	}
1474 	return null;
1475 };
1476 
1477 /**
1478  * Returns the control associated with the given event. Starts with the
1479  * event target and works its way up the element chain until it finds one
1480  * with an ID that maps to a {@link DwtControl}.
1481  * 
1482  * @param {Event}		ev				the DHTML event
1483  * @param {boolean}		useRelatedTarget	if <code>true</code>, use element that was related to this event
1484  * @return {DwtControl}	the control or <code>null</code> for none
1485  */
1486 DwtControl.getTargetControl =
1487 function(ev, useRelatedTarget)  {
1488 	var htmlEl = DwtUiEvent.getTarget(ev, useRelatedTarget);
1489 	return htmlEl ? DwtControl.findControl(htmlEl) : null;
1490 };
1491 
1492 /**
1493  * Sets the control HTML element id attribute.
1494  *
1495  * @param {string} id 		the new element Id
1496  */
1497 DwtControl.prototype.setHtmlElementId =
1498 function(id) {
1499 	if (this._disposed) { return; }
1500 
1501 	if (this.__ctrlInited) {
1502 		var htmlEl = this.getHtmlElement();
1503 		if (!htmlEl._rendered) {
1504 			delete DwtComposite._pendingElements[this._htmlElId];
1505 			DwtComposite._pendingElements[id] = htmlEl;
1506 		}
1507 		else {
1508 			delete DwtControl.ALL_BY_ID[this._htmlElId];
1509 			DwtControl.ALL_BY_ID[id] = this;
1510 		}
1511 		htmlEl.id = id;
1512 	}
1513 	this._htmlElId = id;
1514 };
1515 
1516 /**
1517  * Gets the X coordinate of the control (if absolutely positioned).
1518  * 
1519  * @return {number}		the X coordinate of the control 
1520  *
1521  * @see #getBounds
1522  * @see #getInsetBounds
1523  * @see #getInsets
1524  * @see #getSize
1525  * @see #getLocation
1526  * @see #getH
1527  * @see #getW
1528  * @see #getXW
1529  * @see #getY
1530  * @see #getYH
1531  * @see #setBounds
1532  * @see #setSize
1533  * @see #setLocation
1534  */
1535 DwtControl.prototype.getX =
1536 function() {
1537 	if (!this._checkState()) { return; }
1538 
1539 	return Dwt.getLocation(this.getHtmlElement()).x;
1540 };
1541 
1542 /**
1543  * Gets the horizontal extent of the control (if absolutely positioned).
1544  * 
1545  * @return {number} 	the horizontal extent of the control
1546  *
1547  * @see #getBounds
1548  * @see #getInsetBounds
1549  * @see #getInsets
1550  * @see #getSize
1551  * @see #getLocation
1552  * @see #getH
1553  * @see #getW
1554  * @see #getX
1555  * @see #getY
1556  * @see #getYH
1557  * @see #setBounds
1558  * @see #setSize
1559  * @see #setLocation
1560  */
1561 DwtControl.prototype.getXW =
1562 function() {
1563 	if (!this._checkState()) { return; }
1564 
1565     var bounds = this.getBounds();
1566 	return bounds.x+bounds.width;
1567 };
1568 
1569 /**
1570  * Gets the Y coordinate of the control (if it is absolutely positioned).
1571  * 
1572  * @return {number}		the Y coordinate of the control 
1573  *
1574  * @see #getBounds
1575  * @see #getInsetBounds
1576  * @see #getInsets
1577  * @see #getSize
1578  * @see #getLocation
1579  * @see #getH
1580  * @see #getW
1581  * @see #getX
1582  * @see #getXW
1583  * @see #getYH
1584  * @see #setBounds
1585  * @see #setSize
1586  * @see #setLocation
1587  */
1588 DwtControl.prototype.getY =
1589 function() {
1590 	if (!this._checkState()) { return; }
1591 
1592 	return Dwt.getLocation(this.getHtmlElement()).y;
1593 };
1594 
1595 /**
1596  * Gets the vertical extent of the control (if it is absolutely positioned).
1597  * 
1598  * @return {number}		the vertical extent of the control
1599  *
1600  * @see #getBounds
1601  * @see #getInsetBounds
1602  * @see #getInsets
1603  * @see #getSize
1604  * @see #getLocation
1605  * @see #getH
1606  * @see #getW
1607  * @see #getX
1608  * @see #getXW
1609  * @see #getY
1610  * @see #setBounds
1611  * @see #setSize
1612  * @see #setLocation
1613  */
1614 DwtControl.prototype.getYH =
1615 function() {
1616 	if (!this._checkState()) { return; }
1617 
1618     var bounds = this.getBounds();
1619 	return bounds.y+bounds.height;
1620 };
1621 
1622 /**
1623  * Returns the positioning style
1624  */
1625 DwtControl.prototype.getPosition =
1626 function() {
1627 	if (!this._checkState()) { return; }
1628 
1629 	return Dwt.getPosition(this.getHtmlElement());
1630 };
1631 
1632 /**
1633  * Sets the positioning style
1634  * 
1635  * @param 	{constant}	posStyle	positioning style (Dwt.*_STYLE)
1636  */
1637 DwtControl.prototype.setPosition =
1638 function(posStyle) {
1639 	if (!this._checkState()) { return; }
1640 
1641 	return Dwt.setPosition(this.getHtmlElement(), posStyle);
1642 };
1643 
1644 /**
1645  * Gets the location of the control.
1646  *
1647  * @return {DwtPoint}		the location of the control
1648  *
1649  * @see #getBounds
1650  * @see #getInsetBounds
1651  * @see #getInsets
1652  * @see #getSize
1653  * @see #setLocation
1654  * @see #getH
1655  * @see #getW
1656  * @see #getX
1657  * @see #getXW
1658  * @see #getY
1659  * @see #setBounds
1660  * @see #setSize
1661  * @see Dwt
1662  */
1663 DwtControl.prototype.getLocation =
1664 function() {
1665 	if (!this._checkState()) { return; }
1666 
1667 	return Dwt.getLocation(this.getHtmlElement());
1668 };
1669 
1670 /**
1671  * Sets the location of the control. The position style of the control must
1672  * be absolute or else an exception is thrown. To only set one of the coordinates,
1673  * pass in a value of <i>Dwt.DEFAULT</i> for the coordinate for which the value is
1674  * not to be set. Any <i>DwtEvent.CONTROL</i> listeners registered on the control
1675  * will be called.
1676  *
1677  * @param {number|string} x	the x coordinate of the element (for example: 10, "10px", Dwt.DEFAULT)
1678  * @param {number|string} y	the y coordinate of the element (for example: 10, "10px", Dwt.DEFAULT)
1679  *
1680  * @return {DwtControl}		this control
1681  *
1682  * @see #getBounds
1683  * @see #getInsetBounds
1684  * @see #getInsets
1685  * @see #getSize
1686  * @see #getLocation
1687  * @see #getH
1688  * @see #getW
1689  * @see #getX
1690  * @see #getXW
1691  * @see #getY
1692  * @see #setBounds
1693  * @see #setSize
1694  * @see Dwt
1695  */
1696 DwtControl.prototype.setLocation =
1697 function(x, y) {
1698 	if (!this._checkState()) { return; }
1699 
1700 	if (this.isListenerRegistered(DwtEvent.CONTROL)) {
1701 		var htmlElement = this.getHtmlElement();
1702 		this.__controlEvent.reset(DwtControlEvent.MOVE);
1703 		var loc = Dwt.getLocation(htmlElement);
1704 		this.__controlEvent.oldX = loc.x;
1705 		this.__controlEvent.oldY = loc.y;
1706 		Dwt.setLocation(htmlElement, x, y);
1707 		loc = Dwt.getLocation(htmlElement);
1708 		this.__controlEvent.newX = loc.x;
1709 		this.__controlEvent.newY = loc.y;
1710 		this.notifyListeners(DwtEvent.CONTROL, this.__controlEvent);
1711 	} else {
1712 		Dwt.setLocation(this.getHtmlElement(), x, y);
1713 	}
1714 	return this;
1715 };
1716 
1717 /**
1718  * Gets the control scroll style. The scroll style determines the control
1719  * behavior when content overflows its div's boundaries. Possible values are:
1720  * <ul>
1721  * <li>{@link Dwt.CLIP} - Clip on overflow</li>
1722  * <li>{@link Dwt.VISIBLE} - Allow overflow to be visible</li>
1723  * <li>{@link Dwt.SCROLL} - Automatically create scrollbars if content overflows</li>
1724  * <li>{@link Dwt.FIXED_SCROLL} - Always have scrollbars whether content overflows or not</li>
1725  * </ul>
1726  *
1727  * @return {number}		the control scroll style
1728  */
1729 DwtControl.prototype.getScrollStyle =
1730 function() {
1731 	if (!this._checkState()) { return; }
1732 
1733 	return Dwt.getScrollStyle(this.getHtmlElement());
1734 };
1735 
1736 /**
1737  * Sets the control scroll style. The scroll style determines the control's
1738  * behavior when content overflows its div's boundaries. Possible values are:
1739  * <ul>
1740  * <li>{@link Dwt.CLIP} - Clip on overflow</li>
1741  * <li>{@link Dwt.VISIBLE} - Allow overflow to be visible</li>
1742  * <li>{@link Dwt.SCROLL} - Automatically create scrollbars if content overflows</li>
1743  * <li>{@link Dwt.FIXED_SCROLL} - Always have scrollbars whether content overflows or not</li>
1744  * </ul>
1745  *
1746  * @param {int} scrollStyle		the control new scroll style
1747  */
1748 DwtControl.prototype.setScrollStyle =
1749 function(scrollStyle) {
1750 	if (!this._checkState()) { return; }
1751 
1752 	Dwt.setScrollStyle(this.getHtmlElement(), scrollStyle);
1753 };
1754 
1755 /**
1756  * Returns the element that this control scrolls within.
1757  *
1758  * @returns {HTMLElement}
1759  */
1760 DwtControl.prototype.getScrollContainer = function() {
1761 
1762     return this.parent && this.parent.getHtmlElement();
1763 };
1764 
1765 /**
1766  * Sets the control position. The position determines the control's
1767  * location within the context of which it was created. Possible values are:
1768  * <ul>
1769  * <li>{@link DwtControl.STATIC_STYLE} - Allow browser to control content flow</li>
1770  * <li>{@link DwtControl.ABSOLUTE_STYLE} - Allow content to be positioned relative to parent or body</li>
1771  * <li>{@link DwtControl.RELATIVE_STYLE} - Allow browser to control content flow but relative to parent</li>
1772  * </ul>
1773  *
1774  * @param {number} position		the control new position
1775  */
1776 DwtControl.prototype.setPosition =
1777 function(position) {
1778 	if (!this._checkState()) { return; }
1779 
1780 	if (position == DwtControl.STATIC_STYLE ||
1781 		position == DwtControl.ABSOLUTE_STYLE ||
1782 		position == DwtControl.RELATIVE_STYLE)
1783 	{
1784 		this.__posStyle = position;
1785 		Dwt.setPosition(this.getHtmlElement(), position);
1786 	}
1787 };
1788 
1789 /**
1790  * Gets the width of the control.
1791  * 
1792  * @return	{number}		the width of the control
1793  *
1794  * @see #getBounds
1795  * @see #getInsetBounds
1796  * @see #getInsets
1797  * @see #getSize
1798  * @see #getLocation
1799  * @see #getH
1800  * @see #getX
1801  * @see #getXW
1802  * @see #getY
1803  * @see #getYH
1804  * @see #setBounds
1805  * @see #setSize
1806  * @see #setLocation
1807  */
1808 DwtControl.prototype.getW =
1809 function() {
1810 	if (!this._checkState()) { return; }
1811 
1812 	return Dwt.getSize(this.getHtmlElement()).x;
1813 };
1814 
1815 /**
1816  * Gets the height of the control.
1817  * 
1818  * @return {number}	the height of the control
1819  *
1820  * @see #getBounds
1821  * @see #getInsetBounds
1822  * @see #getInsets
1823  * @see #getSize
1824  * @see #getLocation
1825  * @see #getW
1826  * @see #getX
1827  * @see #getXW
1828  * @see #getY
1829  * @see #getYH
1830  * @see #setBounds
1831  * @see #setLocation
1832  * @see #setSize
1833  */
1834 DwtControl.prototype.getH =
1835 function() {
1836 	if (!this._checkState()) { return; }
1837 
1838 	return Dwt.getSize(this.getHtmlElement()).y;
1839 };
1840 
1841 /**
1842  * Gets the size of the control. The x value of the returned point is the width
1843  * and the y is the height.
1844  * 
1845  * @return {DwtPoint}		the control size
1846  *
1847  * @see #getBounds
1848  * @see #getInsetBounds
1849  * @see #getInsets
1850  * @see #getLocation
1851  * @see #getH
1852  * @see #getW
1853  * @see #getX
1854  * @see #getXW
1855  * @see #getY
1856  * @see #getYH
1857  * @see #setBounds
1858  * @see #setSize
1859  * @see #setLocation
1860  */
1861 DwtControl.prototype.getSize =
1862 function(getFromStyle) {
1863 	if (!this._checkState()) { return; }
1864 
1865 	return Dwt.getSize(this.getHtmlElement(), null, getFromStyle);
1866 };
1867 
1868 /**
1869  * Gets the outer size -- that is, the size including margins, padding, and borders -- of an
1870  * HTML element.
1871  *
1872  * @return {DwtPoint}	the elements size, margins, padding, and borders included
1873  */
1874 DwtControl.prototype.getOuterSize =
1875 function() {
1876 	if (!this._checkState()) { return; }
1877 
1878 	return Dwt.getOuterSize(this.getHtmlElement(), null);
1879 };
1880 
1881 /**
1882  * Sets the size of the control
1883  *
1884  * @param {number|string} width	the width of the control (for example: 100, "100px", "75%", Dwt.DEFAULT)
1885  * @param {number|string} height	the height of the control (for example: 100, "100px", "75%", Dwt.DEFAULT)
1886  *
1887  * @return {DwtControl}	this control
1888  *
1889  * @see #getBounds
1890  * @see #getInsetBounds
1891  * @see #getInsets
1892  * @see #getSize
1893  * @see #setLocation
1894  * @see #getH
1895  * @see #getW
1896  * @see #getX
1897  * @see #getXW
1898  * @see #getY
1899  * @see #getYH
1900  * @see #setBounds
1901  */
1902 DwtControl.prototype.setSize =
1903 function(width, height) {
1904 	if (!this._checkState()) { return; }
1905 
1906 	if (this.isListenerRegistered(DwtEvent.CONTROL)) {
1907 		var htmlElement = this.getHtmlElement();
1908 		this.__controlEvent.reset(DwtControlEvent.RESIZE);
1909 		var sz = Dwt.getSize(htmlElement);
1910 		this.__controlEvent.oldWidth = sz.x;
1911 		this.__controlEvent.oldHeight = sz.y;
1912 		Dwt.setSize(htmlElement, width, height);
1913 		sz = Dwt.getSize(htmlElement);
1914 		this.__controlEvent.newWidth = sz.x;
1915 		this.__controlEvent.newHeight = sz.y;
1916 		this.notifyListeners(DwtEvent.CONTROL, this.__controlEvent);
1917 	} else {
1918 		Dwt.setSize(this.getHtmlElement(), width, height);
1919 	}
1920 	return this;
1921 };
1922 
1923 /**
1924  * Gets the tooltip content (typically set using {@link #setToolTipContent}). Controls
1925  * that want to return dynamic tooltip content should override this method.
1926  *
1927  * @param {DwtEvent}	ev	the mouseover event
1928  * @return {string}		the tooltip content set for the control
1929  */
1930 DwtControl.prototype.getToolTipContent =
1931 function(ev) {
1932 	if (this._disposed) { return null; }
1933 
1934 	return this.__toolTipContent;
1935 };
1936 
1937 /**
1938  * Sets tooltip content for the control. The toolTip passed in may be plain text,
1939  * HTML or an object containing a callback function.
1940  * If DwtControl.useBrowserTooltips is set to true, and the tooltip does not have
1941  * HTML, returns, or tabs, use a browser tooltip by setting the 'title' attribute
1942  * on the element.
1943  *
1944  * @param {string/object} 	toolTip		the tooltip content
1945  */
1946 DwtControl.prototype.setToolTipContent =
1947 function(toolTip, useBrowser) {
1948 	if (this._disposed) { return; }
1949 	if (toolTip && (typeof(toolTip) == "string")  && DwtControl.useBrowserTooltips) {
1950 		// browser tooltip can't have return, tab, or HTML
1951 		if (!toolTip || (!toolTip.match(/[\n\r\t]/) && !toolTip.match(/<[a-zA-Z]+/))) {
1952 			var el = this.getHtmlElement();
1953 			if (el) {
1954 				el.title = toolTip;
1955 				this._browserToolTip = true;
1956 				return;
1957 			}
1958 		}
1959 	}
1960 
1961 	this._browserToolTip = false;
1962 	this.__toolTipContent = toolTip;
1963 };
1964 
1965 /**
1966  * Gets the visible state of the control. For example, the control HTML elements display style attribute is not "none".
1967  * 
1968  * @return {boolean}	if <code>true</code>, the control is visible
1969  *
1970  * @see Dwt#getVisibile
1971  */
1972 DwtControl.prototype.getVisible =
1973 function() {
1974 	if (!this._checkState()) { return; }
1975 
1976 	return Dwt.getVisible(this.getHtmlElement());
1977 };
1978 
1979 /**
1980  * Sets the the visible state of the control HTML element. <i>Note: Gets style
1981  * "display: none", don't confuse with {@link setVisibility}).</i>
1982  *
1983  * @param {boolean} visible 	if <code>true</code>, the control should be displayed; if <code>false</code>, the control should not be displayed
1984  *
1985  * @see Dwt#setVisible
1986  */
1987 DwtControl.prototype.setVisible =
1988 function(visible) {
1989 	if (!this._checkState()) { return; }
1990 
1991 	Dwt.setVisible(this.getHtmlElement(), visible);
1992 };
1993 
1994 /**
1995  * Sets the visibility of the control HTML element.
1996  *
1997  * @param {boolean} visible		if <code>true</code> then the control is visible
1998  *
1999  * @see Dwt#setVisibility
2000  */
2001 DwtControl.prototype.setVisibility =
2002 function(visible) {
2003 	if (!this._checkState()) { return; }
2004 
2005 	Dwt.setVisibility(this.getHtmlElement(), visible);
2006 };
2007 
2008 /**
2009  * Gets the visibility of the control HTML element.
2010  * 
2011  * @return {boolean}	if <code>true</code>, the control is visible (i.e. the HTML elements visibility play style attribute is not "hidden")
2012  *
2013  * @see Dwt#getVisibility
2014  */
2015 DwtControl.prototype.getVisibility =
2016 function() {
2017 	if (!this._checkState()) { return; }
2018 
2019 	return Dwt.getVisibility(this.getHtmlElement());
2020 };
2021 
2022 
2023 /**
2024  * Gets the control z-index value.
2025  *
2026  * @param {boolean} getFromStyle    get the value from the style attribute of
2027  *                                  the control element, or a parent
2028  *
2029  * @return	{number}	the z-index value
2030  */
2031 DwtControl.prototype.getZIndex =
2032 function(getFromStyle) {
2033 	if (!this._checkState()) { return; }
2034 
2035 	return Dwt.getZIndex(this.getHtmlElement(), getFromStyle);
2036 };
2037 
2038 /**
2039  * Sets the z-index for the control HTML element. Since z-index is only relevant among peer
2040  * elements, we make sure that all elements that are being displayed via z-index hang off the
2041  * main shell.
2042  *
2043  * @param {number} idx		the new z-index for this element
2044  */
2045 DwtControl.prototype.setZIndex =
2046 function(idx) {
2047 	if (!this._checkState()) { return; }
2048 
2049 	Dwt.setZIndex(this.getHtmlElement(), idx);
2050 };
2051 
2052 /**
2053  * Convenience function to toggle visibility using z-index. It uses the two lowest level
2054  * z-indexes ({@link Dwt.Z_VIEW} and {@link Dwt.Z_HIDDEN} respectively). Any further
2055  * stacking will have to use {@link #setZIndex} directly.
2056  *
2057  * @param {boolean} show		if <code>true</code>, show the element; <code>false</code> to hide the element
2058  *
2059  * @see #setZIndex
2060  */
2061 DwtControl.prototype.zShow =
2062 function(show) {
2063 	this.setZIndex(show ? Dwt.Z_VIEW : Dwt.Z_HIDDEN);
2064 };
2065 
2066 /**
2067  * Sets the display.
2068  * 
2069  * @param	{string}	value		the display value
2070  */
2071 DwtControl.prototype.setDisplay =
2072 function(value) {
2073 	if (!this._checkState()) { return; }
2074 
2075 	Dwt.setDisplay(this.getHtmlElement(), value);
2076 };
2077 
2078 /**
2079  * Sets the opacity of the control HTML element.
2080  *
2081  * @param {Number} opacity		opacity, as a percentage between 0 and 100
2082  *
2083  * @see Dwt#setOpacity
2084  */
2085 DwtControl.prototype.setOpacity =
2086 function(opacity) {
2087 	if (!this._checkState()) { return; }
2088 
2089 	Dwt.setOpacity(this.getHtmlElement(), opacity);
2090 };
2091 
2092 /**
2093  * Gets the opacity of the control HTML element.
2094  *
2095  * @return {Number}	opacity, as a percentage between 0 and 100
2096  *
2097  * @see Dwt#getOpacity
2098  */
2099 DwtControl.prototype.getOpacity =
2100 function() {
2101 	if (!this._checkState()) { return; }
2102 
2103 	return Dwt.getOpacity(this.getHtmlElement());
2104 };
2105 
2106 /**
2107  * Prevents selection on the specified element.
2108  *
2109  * @param	{Element}	targetEl	the element
2110  */
2111 DwtControl.prototype.preventSelection =
2112 function(targetEl) {
2113 	return !this.__isInputEl(targetEl);
2114 };
2115 
2116 /**
2117  * Prevents a context menu on the specified element.
2118  * 
2119  * @param	{Element}	targetEl	the element
2120  */
2121 DwtControl.prototype.preventContextMenu =
2122 function(targetEl) {
2123 	return targetEl ? (!this.__isInputEl(targetEl)) : true;
2124 };
2125 
2126 /**
2127  * Returns the content of the control HTML element.
2128  * 
2129  * @return {string}		HTML content
2130  */
2131 DwtControl.prototype.getContent =
2132 function() {
2133 	return this.getHtmlElement().innerHTML;
2134 };
2135 
2136 /**
2137  * Sets the content of the control HTML element to the provided
2138  * content. Care should be taken when using this method as it can blow away all
2139  * the content of the control which can be particularly bad if the control is
2140  * a <i>DwtComposite</i> with children. Generally this method should be used
2141  * controls which are being directly instantiated and used as a canvas
2142  *
2143  * @param {string} content		the HTML content
2144  */
2145 DwtControl.prototype.setContent =
2146 function(content) {
2147 	if (content) {
2148 		this.getHtmlElement().innerHTML = content;
2149 	}
2150 };
2151 
2152 /**
2153  * Clears the content of the control HTML element.
2154  * Care should be taken when using this method as it can blow away all
2155  * the content of the control which can be particularly bad if the control is
2156  * a {@link DwtComposite} with children. Generally this method should be used
2157  * controls which are being directly instantiated and used as a canvas.
2158  */
2159 DwtControl.prototype.clearContent =
2160 function() {
2161 	this.getHtmlElement().innerHTML = "";
2162 };
2163 
2164 /**
2165  * Appends this control element to the specified element.
2166  *
2167  * @param {Element|string}	elemOrId  the DOM element or an element id
2168  */
2169 DwtControl.prototype.appendElement =
2170 function(elemOrId) {
2171     var el = AjxUtil.isString(elemOrId) ? document.getElementById(elemOrId) : elemOrId;
2172     if (el) {
2173         el.appendChild(this.getHtmlElement(), el);
2174     }
2175 };
2176 
2177 /**
2178  * Replaces the specified element with this control element.
2179  *
2180  * @param {Element|string}	elemOrId  the DOM element or an element id
2181  */
2182 DwtControl.prototype.replaceElement =
2183 function(elemOrId, inheritClass, inheritStyle) {
2184     var oel = AjxUtil.isString(elemOrId) ? document.getElementById(elemOrId) : elemOrId;
2185     if (oel) {
2186         var nel = this.getHtmlElement();
2187         oel.parentNode.replaceChild(nel, oel);
2188         this._replaceElementHook(oel, nel, inheritClass, inheritStyle);
2189     }
2190 };
2191 
2192 /**
2193  * This method is a hook for sub-classes that want to intercept the
2194  * inheriting of class and style when an element is replaced. By
2195  * default, the new will will inherit the class and style. In order
2196  * to prevent this behavior, you must pass in a <code>true</code>
2197  * or <code>false</code> value.
2198  * 
2199  * @private
2200  */
2201 DwtControl.prototype._replaceElementHook =
2202 function(oel, nel, inheritClass, inheritStyle) {
2203     if ((inheritClass == null || inheritClass) && oel.className) {
2204         Dwt.addClass(nel, oel.className);
2205     }
2206     if (inheritStyle == null || inheritStyle) {
2207         var style = oel.getAttribute("style") || oel.style;
2208         if (style) {
2209             if (AjxUtil.isString(style)) { // All non-IE browsers
2210                 nel.setAttribute("style", [nel.getAttribute("style"),style].join(";"));
2211             } else if (AjxUtil.isString(style.cssText)) {
2212 				if (style.cssText) {
2213 					nel.setAttribute("style", [nel.getAttribute("style"),style.cssText].join(";"));
2214 				}
2215 			} else {
2216 				for (var attribute in style) {
2217 					if (style[attribute]) {
2218 						try {
2219 							nel.style[attribute] = style[attribute];
2220 						} catch (e) {}
2221 					}
2222 				}
2223 			}
2224         }
2225     }
2226 };
2227 
2228 /**
2229  * This protected method is called by the keyboard navigate infrastructure when a control
2230  * gains focus. This method should be overridden by derived classes to provide
2231  * the visual behavior for the component losing focus
2232  *
2233  * @see #_focus
2234  * @see #_focusByMouseUpEvent
2235  * @see #focus
2236  * 
2237  * @private
2238  */
2239 DwtControl.prototype._blur =
2240 function() {
2241 };
2242 
2243 /**
2244  * This protected method should be overridden by derived classes to provide
2245  * behavior for the component gaining focus e.g. providing a border or
2246  * highlighting etc...
2247  *
2248  * @see #_blur
2249  * @see #_focusByMouseUpEvent
2250  * @see #focus
2251  * 
2252  * @private
2253  */
2254 DwtControl.prototype._focus =
2255 function() {
2256 };
2257 
2258 /**
2259  * This protected method is called from mouseUpHdl. Subclasses may override this method
2260  * if they have their own specialized focus management code.
2261  *
2262  * @see #_blur
2263  * @see #_focus
2264  * @see #focus
2265  * 
2266  * @private
2267  */
2268 DwtControl.prototype._focusByMouseUpEvent =
2269 function(ev)  {
2270     DBG.println(AjxDebug.FOCUS, "DwtControl FOCUSONMOUSEUP: " + [this, this._htmlElId].join(' / '));
2271  	if (this.getEnabled()) {
2272         this.shell.getKeyboardMgr().grabFocus(this);
2273     }
2274 };
2275 
2276 /**
2277  * This is for bug 11827.
2278  * 
2279  * TODO: we should remove _focusByMouseUpEvent and update all classes
2280  * that define it to use _focusByMouseDownEvent instead.
2281  * 
2282  * @private
2283  */
2284 DwtControl.prototype._focusByMouseDownEvent =
2285 function(ev) {
2286     DBG.println(AjxDebug.FOCUS, "DwtControl FOCUSONMOUSEDOWN: " + [this, this._htmlElId].join(' / '));
2287 	this._duringFocusByMouseDown = true;
2288 	this._focusByMouseUpEvent(ev);
2289 	this._duringFocusByMouseDown = false;
2290 };
2291 
2292 /**
2293  * Returns the type of drag operation we are performing.
2294  *
2295  * @param mouseEv
2296  */
2297 DwtControl.prototype._getDragOp =
2298 function(mouseEv) {
2299 	return mouseEv.ctrlKey ? Dwt.DND_DROP_COPY : Dwt.DND_DROP_MOVE;
2300 };
2301 
2302 /**
2303  * Subclasses may override this protected method to return an HTML element that will represent
2304  * the dragging icon. The icon must be created on the DwtShell widget. This means that the
2305  * icon must be a child of the shells HTML component If this method returns
2306  * null, it indicates that the drag failed. This method is called when a control is
2307  * being dragged and it has a valid drag source
2308  *
2309  * @return {HTMLElement}	the DnD dragging icon. This is typically a div element
2310  *
2311  * @see #_setDragProxyState
2312  * @see #_destroyDragProxy
2313  * @see #_isValidDragObject
2314  * @see #_dragEnter
2315  * @see #_dragOver
2316  * @see #_dragHover
2317  * @see #_dragLeave
2318  * @see #_drop
2319  * @see #setDragSource
2320  * @see DwtDropTarget
2321  * @see DwtDragSource
2322  * 
2323  * @private
2324  */
2325 DwtControl.prototype._getDragProxy =
2326 function(dragOp) {
2327 	DBG.println(AjxDebug.DBG2, "DwtControl.prototype._getDragProxy");
2328 	return null;
2329 };
2330 
2331 DwtControl.prototype.getDragSelectionBox =
2332 function(dragOp) {
2333 
2334 	if (!this._dragSelectionBox) {
2335 		var box = this._dragSelectionBox = document.createElement("div");
2336 		box.className = "dndSelectionBox";
2337 		Dwt.setPosition(box, Dwt.ABSOLUTE_STYLE);
2338 		this.shell.getHtmlElement().appendChild(box);
2339 		Dwt.setZIndex(box, Dwt.Z_DND);
2340 	}
2341 	return this._dragSelectionBox;
2342 };
2343 
2344 /**
2345  * Subclasses may override this method to set the DnD icon properties based on whether drops are
2346  * allowed. The default implementation sets the class on the HTML element obtained
2347  * from <code>_getDragProxy</code> to DwtCssStyle.DROPPABLE if <code>dropAllowed</code> is true and
2348  * to DwtCssStyle.NOT_DROPPABLE if false
2349  *
2350  * @param {boolean} dropAllowed		if <code>true</code>, then dropping is allowed on the drop zone so set
2351  * 		DnD icon to the visually reflect this
2352  *
2353  * @see #_getDragProxy
2354  * @see #_destroyDragProxy
2355  * @see #_isValidDragObject
2356  * @see #_dragEnter
2357  * @see #_dragOver
2358  * @see #_dragHover
2359  * @see #_dragLeave
2360  * @see #_drop
2361  * @see #setDragSource
2362  * @see DwtDropTarget
2363  * @see DwtDragSource
2364  * 
2365  * @private
2366  */
2367 DwtControl.prototype._setDragProxyState =
2368 function(dropAllowed) {
2369 	if (this._dndProxy) {
2370 		Dwt.condClass(this._dndProxy, dropAllowed, DwtCssStyle.DROPPABLE, DwtCssStyle.NOT_DROPPABLE);
2371 	}
2372 };
2373 
2374 
2375 /**
2376  * @private
2377  */
2378 DwtControl.__junkIconId = 0;
2379 
2380 /**
2381  * Subclasses may override this method to destroy the DnD icon HTML element
2382  *
2383  * @see #_getDragProxy
2384  * @see #_setDragProxyState
2385  * @see #_isValidDragObject
2386  * @see #_dragEnter
2387  * @see #_dragOver
2388  * @see #_dragHover
2389  * @see #_dragLeave
2390  * @see #_drop
2391  * @see #setDragSource
2392  * @see DwtDropTarget
2393  * @see DwtDragSource
2394  * 
2395  * @private
2396  */
2397 DwtControl.prototype._destroyDragProxy =
2398 function(icon) {
2399 	if (icon) {
2400 		// not sure why there is no parent node, but if there isn't one,
2401 		// let's try and do our best to get rid of the icon
2402 		if (icon.parentNode) {
2403 			icon.parentNode.removeChild(icon);
2404 		} else {
2405 			// at least hide the icon, and change the id so we can't get it back later
2406 			icon.style.zIndex = -100;
2407 			icon.id = "DwtJunkIcon" + DwtControl.__junkIconId++;
2408 			icon = null;
2409 		}
2410 	}
2411 };
2412 
2413 DwtControl.prototype.destroyDragSelectionBox =
2414 function() {
2415 
2416 	var box = this._dragSelectionBox;
2417 	if (box && box.parentNode) {
2418 		box.parentNode.removeChild(box);
2419 	}
2420 	this._dragSelectionBox = null;
2421 };
2422 
2423 /**
2424  * Subclasses may override this method to provide feedback as to whether a possibly
2425  * valid capture is taking place. For example, there are instances such as when a mouse
2426  * down happens on a scroll bar in a DwtListView that are reported in the context of
2427  * the DwtListView, but which are not really a valid mouse down i.e. on a list item. In
2428  * such cases this function would return false.
2429  *
2430  * @return {boolean}	<code>true</code> if the object is a valid drag object
2431  *
2432  * @see #_getDragProxy
2433  * @see #_setDragProxyState
2434  * @see #_destroyDragProxy
2435  * @see #_dragEnter
2436  * @see #_dragOver
2437  * @see #_dragHover
2438  * @see #_dragLeave
2439  * @see #_drop
2440  * @see #setDragSource
2441  * @see DwtDropTarget
2442  * @see DwtDragSource
2443  * 
2444  * @private
2445  */
2446  DwtControl.prototype._isValidDragObject =
2447  function(ev) {
2448  	return true;
2449  };
2450 
2451 /**
2452  * _dragHover is called multiple times as the user hovers over
2453  * the control. _dragLeave is called when the drag operation exits the control.
2454  * _drop is called when the item is dropped on the target.
2455  */
2456 
2457  /**
2458   * This protected method is called when a drag operation enters a control. Subclasses
2459   * supporting drop targets should implement this method to visual indicate that they are a
2460   * drop target. This could be by changing the background etc. Note that it is the
2461   * responsibility of the drag source (the control being dragged) to change its icon state
2462   * to reflect whether the drop target is valid for the drag source
2463   *
2464   * @param {DwtMouseEvent} ev	the mouse event that is associated with the drag operation
2465   *
2466   * @see #_getDragProxy
2467   * @see #_setDragProxyState
2468   * @see #_destroyDragProxy
2469   * @see #_isValidDragObject
2470   * @see #_dragOver
2471   * @see #_dragHover
2472   * @see #_dragLeave
2473   * @see #_drop
2474   * @see #setDragSource
2475   * @see DwtDropTarget
2476   * @see DwtDragSource
2477   * 
2478   * @private
2479   */
2480 DwtControl.prototype._dragEnter =
2481 function(ev) {
2482 };
2483 
2484  /**
2485   * This protected method is called multiple times as a dragged control crosses over this control
2486   * Subclasses supporting drop targets may implement this method for additional visual
2487   * indication, such as indicating "landing zones" in the control for drop operations
2488   *
2489   * @param {DwtMouseEvent} ev	the mouse event that is associated with the drag operation
2490   *
2491   * @see #_getDragProxy
2492   * @see #_setDragProxyState
2493   * @see #_destroyDragProxy
2494   * @see #_isValidDragObject
2495   * @see #_dragEnter
2496   * @see #_dragHover
2497   * @see #_dragLeave
2498   * @see #_drop
2499   * @see #setDragSource
2500   * @see DwtDropTarget
2501   * @see DwtDragSource
2502   * @private
2503   */
2504 DwtControl.prototype._dragOver =
2505 function(ev) {
2506 };
2507 
2508  /**
2509   * This protected method is called every 750ms as an item hovers over this control
2510   * Subclasses supporting drop targets may implement this method for additional visual
2511   * indication or actions, such as expanding a collapsed tree node if the user hovers
2512   * over the node for a period of time.
2513   *
2514   * @param {DwtMouseEvent} ev	the mouse event that is associated with the drag operation
2515   *
2516   * @see #_getDragProxy
2517   * @see #_setDragProxyState
2518   * @see #_destroyDragProxy
2519   * @see #_isValidDragObject
2520   * @see #_dragEnter
2521   * @see #_dragHover
2522   * @see #_dragLeave
2523   * @see #_drop
2524   * @see #setDragSource
2525   * @see DwtDropTarget
2526   * @see DwtDragSource
2527   * @private
2528   */
2529 DwtControl.prototype._dragHover =
2530 function(ev) {
2531 };
2532 
2533  /**
2534   * This protected method is called when the drag operation exits the control
2535   * Subclasses supporting drop targets should implement this method to reset the
2536   * visual to the default (i.e. reset the actions performed as part of the
2537   * <code>_dragEnter</code> method.
2538   *
2539   * @param {DwtMouseEvent} ev	the mouse event that is associated with the drag operation
2540   *
2541   * @see #_getDragProxy
2542   * @see #_setDragProxyState
2543   * @see #_destroyDragProxy
2544   * @see #_isValidDragObject
2545   * @see #_dragEnter
2546   * @see #_dragHover
2547   * @see #_drop
2548   * @see #setDragSource
2549   * @see DwtDropTarget
2550   * @see DwtDragSource
2551   * @private
2552   */
2553 DwtControl.prototype._dragLeave =
2554 function(ev) {
2555 };
2556 
2557 
2558 /**
2559   * This protected method is called when the a drop occurs on the control
2560   * Subclasses supporting drop targets may implement this method to provide a
2561   * visual indication that the drop succeeded (e.g. an animation such as flashing
2562   * the drop target).
2563   *
2564   * @param {DwtMouseEvent} ev	the mouse event that is associated with the drag operation
2565   *
2566   * @see #_getDragProxy
2567   * @see #_setDragProxyState
2568   * @see #_destroyDragProxy
2569   * @see #_isValidDragObject
2570   * @see #_dragEnter
2571   * @see #_dragHover
2572   * @see #_dragLeave
2573   * @see #setDragSource
2574   * @see DwtDropTarget
2575   * @see DwtDragSource
2576   * @private
2577   */
2578 DwtControl.prototype._drop =
2579 function(ev) {
2580 };
2581 
2582 /**
2583   * Makes an element focusable or unfocusable by the browser. It manages the "tabIndex" attribute,
2584   * and sets or unsets the element's onfocus and onblur handlers.
2585   *
2586   * @param {HTMLElement}    element	    element to make (not) focusable
2587   * @param {boolean}        focusable   if true (default), make element focusable by the browser
2588   *
2589   * @private
2590   */
2591 DwtControl.prototype._makeFocusable = function(element, focusable) {
2592 
2593     focusable = (focusable !== false);
2594     DBG.println(AjxDebug.FOCUS, "MAKE " + (focusable ? '' : 'NOT ') + "FOCUSABLE: " + this + ', ' + (element || ''));
2595 
2596     this._setEventHdlrs([ DwtEvent.ONFOCUS, DwtEvent.ONBLUR ], true, element);
2597     if (focusable) {
2598         this._setEventHdlrs([ DwtEvent.ONFOCUS, DwtEvent.ONBLUR ], false, element);
2599         element.tabIndex = 0;
2600     }
2601     else {
2602         element.removeAttribute('tabIndex');
2603     }
2604 };
2605 
2606 /**
2607  * This convenience methods sets or clears the control's event handler for key
2608  * press events as defined by {@link DwtEvent.ONKEYPRESS}.
2609  *
2610  * @param {boolean} clear	if <code>true</code>, clear the keypress events handler
2611  * @param {HTMLElement} element	if specified, assign event handlers to this element (optional)
2612  *
2613  * @private
2614  */
2615 DwtControl.prototype._setKeyPressEventHdlr =
2616 function(clear, element) {
2617 	this._setEventHdlrs([DwtEvent.ONKEYPRESS], clear, element);
2618 };
2619 
2620 /**
2621  * This convenience methods sets or clears the control's event handlers for mouse
2622  * events as defined by <i>DwtEvent.MOUSE_EVENTS</i>
2623  *
2624  * @param {boolean} clear	if <code>true</code>, clear the mouse events handlers
2625  * @param {HTMLElement} element	if specified, assign event handlers to this element (optional)
2626  *
2627  * @private
2628  */
2629 DwtControl.prototype._setMouseEventHdlrs =
2630 function(clear, element) {
2631 	this._setEventHdlrs(DwtEvent.MOUSE_EVENTS, clear, element);
2632 };
2633 
2634 /**
2635  * This convenience methods sets or clears the control's event handlers for keyboard
2636  * events as defined by <i>DwtEvent.KEY_EVENTS</i>
2637  *
2638  * @param {boolean} clear	if <code>true</code>, clear the mouse events handlers
2639  * @param {HTMLElement} element	if specified, assign event handlers to this element (optional)
2640  *
2641  * @private
2642  */
2643 DwtControl.prototype._setKeyEventHdlrs =
2644 function(clear, element) {
2645 	this._setEventHdlrs(DwtEvent.KEY_EVENTS, clear, element);
2646 };
2647 
2648 /**
2649  * This protected method will set or clear the event handlers for the provided array
2650  * of events.
2651  *
2652  * @param {array} events		an array of events for which to set or clear the
2653  * 		control's event handlers. The set of events supported by the control are:
2654  * 		<ul>
2655  * 		<li><i>DwtEvent.ONCONTEXTMENU</i></li>
2656  * 		<li><i>DwtEvent.ONCLICK</i></li>
2657  * 		<li><i>DwtEvent.ONDBLCLICK</i></li>
2658  * 		<li><i>DwtEvent.ONMOUSEDOWN</i></li>
2659  * 		<li><i>DwtEvent.ONMOUSEENTER</i></li>
2660  * 		<li><i>DwtEvent.ONMOUSELEAVE</i></li>
2661  * 		<li><i>DwtEvent.ONMOUSEMOVE</i></li>
2662  * 		<li><i>DwtEvent.ONMOUSEOUT</i></li>
2663  * 		<li><i>DwtEvent.ONMOUSEOVER</i></li>
2664  * 		<li><i>DwtEvent.ONMOUSEUP</i></li>
2665  * 		<li><i>DwtEvent.ONMOUSEWHEEL</i></li>
2666  * 		<li><i>DwtEvent.ONSELECTSTART</i></li>
2667  * 		<li><i>DwtEvent.ONKEYPRESS</i></li>
2668  * 		</ul>
2669  * @param {boolean} clear	if <code>true</code>, the event handlers are cleared for the set of events
2670  * @param {HTMLElement} element	if specified, assign event handlers to this element (optional)
2671  *
2672  * @see Dwt#setHandler
2673  * @see Dwt#clearHandler
2674  * @private
2675  */
2676 DwtControl.prototype._setEventHdlrs =
2677 function(events, clear, element) {
2678 	if (!this._checkState()) { return; }
2679 
2680 	var htmlElement = element || this.getHtmlElement();
2681 	for (var i = 0; i < events.length; i++) {
2682 		if (clear !== true) {
2683 			Dwt.setHandler(htmlElement, events[i], DwtControl.__HANDLER[events[i]]);
2684 		} else {
2685 			Dwt.clearHandler(htmlElement, events[i]);
2686 		}
2687 	}
2688 };
2689 
2690 /**
2691  * @private
2692  */
2693 DwtControl.prototype._setMouseEvents =
2694 function() {
2695 	// add custom mouse handlers to standard ones
2696 	var mouseEvents = [DwtEvent.ONCONTEXTMENU, DwtEvent.ONCLICK, DwtEvent.ONDBLCLICK, DwtEvent.ONMOUSEDOWN,
2697 					   DwtEvent.ONMOUSEMOVE, DwtEvent.ONMOUSEUP, DwtEvent.ONSELECTSTART];
2698 	if (AjxEnv.isIE) {
2699 		mouseEvents.push(DwtEvent.ONMOUSEENTER, DwtEvent.ONMOUSELEAVE);
2700 	} else {
2701 		mouseEvents.push(DwtEvent.ONMOUSEOVER, DwtEvent.ONMOUSEOUT);
2702 	}
2703 	this._setEventHdlrs(mouseEvents);
2704 };
2705 
2706 /**
2707  * Populates a fake mouse event in preparation for the direct call of a listener (rather
2708  * than via an event handler).
2709  * 
2710  * @param {DwtMouseEvent}	mev		the mouse event
2711  * @param {hash}	params		the hash of event properties
2712  * 
2713  * @see DwtUiEvent.copy
2714  * @private
2715  */
2716 DwtControl.prototype._setMouseEvent =
2717 function(mev, params) {
2718 	mev.reset();
2719 	params.ersatz = true;
2720 	DwtUiEvent.copy(mev, params);
2721 	mev.button = params.button;
2722 };
2723 
2724 /**
2725  * TODO
2726  * @private
2727  */
2728 DwtControl.prototype._getStopPropagationValForMouseEv =
2729 function(ev) {
2730 	// overload me for dealing w/ browsers w/ weird quirks
2731 	return true;
2732 };
2733 
2734 /**
2735  * TODO
2736  * @private
2737  */
2738 DwtControl.prototype._getEventReturnValForMouseEv =
2739 function(ev) {
2740 	// overload me for dealing w/ browsers w/ weird quirks
2741 	return false;
2742 };
2743 
2744 
2745 /**
2746  * Check the state of the control, if it is not disposed and is not initialized, then
2747  * as a side-effect it will initialize it (meaning it will create the HTML element
2748  * for the control and insert it into the DOM. This is pertinent for controls that
2749  * were created <i>deferred</i> (see the constructor documentation)
2750  *
2751  * @return {boolean}	<code>true</code> if the control is not disposed; <code>false</code> otherwise
2752  * @private
2753  */
2754 DwtControl.prototype._checkState =
2755 function() {
2756 	if (this._disposed) { return false; }
2757 	if (!this.__ctrlInited) {
2758 		this.__initCtrl();
2759 	}
2760 	return true;
2761 };
2762 
2763 /**
2764  * Positions this control at the given point. If no location is provided, centers it
2765  * within the shell.
2766  *
2767  * @param {DwtPoint}	loc		the point at which to position this control
2768  * @private
2769  */
2770 DwtControl.prototype._position =
2771 function(loc) {
2772 	this._checkState();
2773 	var sizeShell = this.shell.getSize();
2774 	var sizeThis = this.getSize();
2775 	var x, y;
2776 	if (!loc) {
2777 		// if no location, go for the middle
2778 		x = Math.round((sizeShell.x - sizeThis.x) / 2);
2779 		y = Math.round((sizeShell.y - sizeThis.y) / 2);
2780 	} else {
2781 		x = loc.x;
2782 		y = loc.y;
2783 	}
2784 	// try to stay within shell boundaries
2785 	if ((x + sizeThis.x) > sizeShell.x) {
2786 		x = sizeShell.x - sizeThis.x;
2787 	}
2788 	if ((y + sizeThis.y) > sizeShell.y) {
2789 		y = sizeShell.y - sizeThis.y;
2790 	}
2791 	this.setLocation(x, y);
2792 };
2793 
2794 /**
2795  * Handles scrolling of a drop area for an object being dragged. The scrolling is based on proximity to
2796  * the top or bottom edge of the area (only vertical scrolling is done). The scrolling is done via a
2797  * looping timer, so that the scrolling is smooth and does not depend on additional mouse movement.
2798  *
2799  * @param {hash}	params		a hash of parameters
2800  * @param {Element}      params.container		the DOM element that may need to be scrolled
2801  * @param {number}      params.threshold		if mouse is within this many pixels of top or bottom of container,
2802  * 										check if scrolling is needed
2803  * @param {number}      params.amount		the number of pixels to scroll at each interval
2804  * @param {number}      params.interval		the number of milliseconds to wait before continuing to scroll
2805  * @param {string}      params.id			the ID for determining if we have moved out of container
2806  * @param {DwtEvent}	ev		the event
2807  * 
2808  * @private
2809  */
2810 DwtControl._dndScrollCallback =
2811 function(params, ev) {
2812 
2813 	var container = params.container;
2814 	if (!container) { return; }
2815 
2816 	// stop scrolling if mouse has moved out of the scrolling area, or dnd object has been released;
2817 	// a bit tricky because this callback is run as the mouse moves among objects within the scroll area,
2818 	// so we need to see if mouse has moved from within to outside of scroll area
2819 	var dwtObjId = ev.dwtObj && ev.dwtObj._dndScrollId;
2820 	if (ev.type == "mouseup" || !dwtObjId || (params.id && dwtObjId != params.id)) {
2821 		if (container._dndScrollActionId != -1) {
2822 			AjxTimedAction.cancelAction(container._dndScrollActionId);
2823 			container._dndScrollActionId = -1;
2824 		}
2825 		return;
2826 	}
2827 
2828 	container._scrollAmt = 0;
2829 	if (container.clientHeight < container.scrollHeight) {
2830 		var containerTop = Dwt.toWindow(container, 0, 0, null, null, DwtPoint.tmp).y;
2831 		var realTop = containerTop + container.scrollTop;
2832 		var scroll = container.scrollTop;
2833 		var diff = ev.docY - realTop; // do we need to scroll up?
2834 		// account for horizontal scrollbar
2835 		var threshold = (container.clientWidth < container.scrollWidth) ? params.threshold + Dwt.SCROLLBAR_WIDTH :
2836 																		  params.threshold;
2837 		var scrollAmt = (diff <= threshold) ? -1 * params.amount : 0;
2838 		if (scrollAmt == 0) {
2839 			var containerH = Dwt.getSize(container, DwtPoint.tmp).y;
2840 			var containerBottom = realTop + containerH;
2841 			diff = containerBottom - ev.docY; // do we need to scroll down?
2842 			scrollAmt = (diff <= threshold) ? params.amount : 0;
2843 		}
2844 		container._scrollAmt = scrollAmt;
2845 		if (scrollAmt) {
2846 			if (!container._dndScrollAction) {
2847 				container._dndScrollAction = new AjxTimedAction(null, DwtControl._dndScroll, [params]);
2848 				container._dndScrollActionId = -1;
2849 			}
2850 			// launch scrolling loop
2851 			if (container._dndScrollActionId == -1) {
2852 				container._dndScrollActionId = AjxTimedAction.scheduleAction(container._dndScrollAction, 0);
2853 			}
2854 		} else {
2855 			// stop scrolling
2856 			if (container._dndScrollActionId != -1) {
2857 				AjxTimedAction.cancelAction(container._dndScrollActionId);
2858 				container._dndScrollActionId = -1;
2859 			}
2860 		}
2861 	}
2862 };
2863 
2864 /**
2865  * @private
2866  */
2867 DwtControl._dndScroll =
2868 function(params) {
2869 	var container = params.container;
2870 	var containerTop = Dwt.toWindow(container, 0, 0, null, null, DwtPoint.tmp).y;
2871 	var containerH = Dwt.getSize(container, DwtPoint.tmp).y;
2872 	var scroll = container.scrollTop;
2873 	// if we are to scroll, make sure there is more scrolling to be done
2874 	if ((container._scrollAmt < 0 && scroll > 0) || (container._scrollAmt > 0 && (scroll + containerH < container.scrollHeight))) {
2875 		container.scrollTop += container._scrollAmt;
2876 		container._dndScrollActionId = AjxTimedAction.scheduleAction(container._dndScrollAction, params.interval);
2877 	}
2878 };
2879 
2880 /**
2881  * @private
2882  */
2883 DwtControl.__keyPressHdlr =
2884 function(ev) {
2885 	var obj = obj ? obj : DwtControl.getTargetControl(ev);
2886 	if (!obj) return false;
2887 
2888 	if (obj.__hasToolTipContent()) {
2889 		var shell = DwtShell.getShell(window);
2890 		var manager = shell.getHoverMgr();
2891 		manager.setHoverOutListener(obj._hoverOutListener);
2892 		manager.hoverOut();
2893 		obj.__tooltipClosed = false;
2894 	}
2895 };
2896 
2897 
2898 /**
2899  * @private
2900  */
2901 DwtControl.__keyUpHdlr = function(ev) {
2902 
2903 	return DwtKeyboardMgr.__keyUpHdlr.apply(this, arguments);
2904 };
2905 
2906 /**
2907  * @private
2908  */
2909 DwtControl.__keyDownHdlr = function(ev) {
2910 
2911 	return DwtKeyboardMgr.__keyDownHdlr.apply(this, arguments);
2912 };
2913 
2914 /**
2915  * @private
2916  */
2917 DwtControl.__focusHdlr = function(ev, evType, obj) {
2918 
2919 	obj = obj || DwtControl.getTargetControl(ev);
2920 	if (!obj) {
2921         return false;
2922     }
2923 
2924     obj._cancelFocusBlurActions();
2925 
2926     return obj.__doFocus(ev);
2927 };
2928 
2929 /**
2930  * @private
2931  */
2932 DwtControl.__blurHdlr = function(ev, evType, obj) {
2933 
2934     obj = obj || DwtControl.getTargetControl(ev);
2935     if (!obj) {
2936         return false;
2937     }
2938 
2939     obj._cancelFocusBlurActions();
2940 
2941 	return obj.__doBlur(ev);
2942 };
2943 
2944 DwtControl.prototype._cancelFocusBlurActions = function() {
2945 
2946     if (this._focusAction._id !== -1) {
2947         AjxTimedAction.cancelAction(this._focusAction._id);
2948     }
2949     if (this._blurAction._id !== -1) {
2950         AjxTimedAction.cancelAction(this._blurAction._id);
2951     }
2952 };
2953 
2954 /**
2955  * Returns true if the control has static tooltip content, or if it has overridden
2956  * getToolTipContent() to return dynamic content. Essentially, it means that this
2957  * control provides tooltips and will need to use the hover mgr.
2958  *
2959  * @private
2960  */
2961 DwtControl.prototype.__hasToolTipContent =
2962 function() {
2963 	if (this._disposed) { return false; }
2964 	return Boolean(!this._browserToolTip && (this.__toolTipContent || (this.getToolTipContent != DwtControl.prototype.getToolTipContent)));
2965 };
2966 
2967 /**
2968  * This control has gotten focus, so do some housekeeping: tell the keyboard mgr, notify listeners, and update our UI and state.
2969  * @private
2970  */
2971 DwtControl.prototype.__doFocus = function(ev) {
2972 
2973     DBG.println(AjxDebug.FOCUS, "DwtControl.__doFocus for " + this.toString() + ", id: " + this._htmlElId);
2974 
2975     if (!this._checkState()) {
2976         return false;
2977     }
2978 
2979     this._hasFocus = true;
2980 
2981     this.shell.getKeyboardMgr().updateFocus(this, ev);
2982 
2983     if (this.isListenerRegistered(DwtEvent.ONFOCUS)) {
2984         ev = ev || DwtShell.focusEvent;
2985         ev.dwtObj = this;
2986         ev.state = DwtFocusEvent.FOCUS;
2987         this.notifyListeners(DwtEvent.ONFOCUS, ev);
2988     }
2989 
2990     this._focus();
2991 
2992     return true;
2993 };
2994 
2995 /**
2996  * This control has lost focus, so do some housekeeping: notify listeners, and update our UI and state.
2997  * @private
2998  */
2999 DwtControl.prototype.__doBlur = function(ev) {
3000 
3001 	DBG.println(AjxDebug.FOCUS, "DwtControl.__doBlur for " + this.toString() + ", id: " + this._htmlElId);
3002 
3003     if (!this._checkState()) {
3004         return false;
3005     }
3006 
3007 	this._hasFocus = false;
3008 	if (this.isListenerRegistered(DwtEvent.ONBLUR)) {
3009         ev = ev || DwtShell.focusEvent;
3010 		ev.dwtObj = this;
3011 		ev.state = DwtFocusEvent.BLUR;
3012 		this.notifyListeners(DwtEvent.ONBLUR, ev);
3013 	}
3014 
3015 	this._blur();
3016 
3017     return true;
3018 };
3019 
3020 /**
3021  * @private
3022  */
3023 DwtControl.__clickHdlr =
3024 function(ev) {
3025 	var obj = DwtControl.getTargetControl(ev);
3026 	if (obj && obj._clickPending) {
3027 		return;
3028 	}
3029 
3030 	try {
3031 
3032 	return DwtControl.__mouseEvent(ev, DwtEvent.ONCLICK);
3033 
3034 	} catch (ex) {
3035 		AjxException.reportScriptError(ex);
3036 	}
3037 };
3038 
3039 /**
3040  * @private
3041  */
3042 DwtControl.__dblClickHdlr =
3043 function(ev) {
3044 
3045 	try {
3046 
3047 	var obj = DwtControl.getTargetControl(ev);
3048 	if (obj && obj._dblClickIsolation) {
3049 		obj._clickPending = false;
3050 		AjxTimedAction.cancelAction(obj._dblClickActionId);
3051 	}
3052 	return DwtControl.__mouseEvent(ev, DwtEvent.ONDBLCLICK);
3053 
3054 	} catch (ex) {
3055 		AjxException.reportScriptError(ex);
3056 	}
3057 };
3058 
3059 /**
3060  * @private
3061  */
3062 DwtControl.__mouseOverHdlr =
3063 function(ev, evType) {
3064 
3065 	try {
3066 
3067 	// Check to see if a drag is occurring. If so, don't process the mouse
3068 	// over events.
3069 	var captureObj = (DwtMouseEventCapture.getId() == "DwtControl") ? DwtMouseEventCapture.getCaptureObj() : null;
3070 	if (captureObj != null) {
3071 		ev = DwtUiEvent.getEvent(ev);
3072 		ev._stopPropagation = true;
3073 		return false;
3074 	}
3075 	var obj = DwtControl.getTargetControl(ev);
3076 	if (!obj) { return false; }
3077 	evType = evType || DwtEvent.ONMOUSEOVER;
3078 	if ((evType == DwtEvent.ONMOUSEOVER) && obj._ignoreInternalOverOut) {
3079 		var otherObj = DwtControl.getTargetControl(ev, true);
3080 		if (obj == otherObj) {
3081 			return false;
3082 		}
3083 	}
3084 
3085 	var mouseEv = DwtShell.mouseEvent;
3086 	if (obj._dragging == DwtControl._NO_DRAG) {
3087 		mouseEv.setFromDhtmlEvent(ev, obj);
3088 		mouseEv.hoverStarted = false;	// don't handle hover if it has already begun
3089 		if (obj.isListenerRegistered(evType)) {
3090 			obj.notifyListeners(evType, mouseEv);
3091 		}
3092 		// Call the tooltip after the listeners to give them a
3093 		// chance to change the tooltip text.
3094 		if (obj.__hasToolTipContent(mouseEv) && !mouseEv.hoverStarted) {
3095 			var shell = DwtShell.getShell(window);
3096 			var manager = shell.getHoverMgr();
3097 			if ((!manager.isHovering() || manager.getHoverObject() != obj) && !DwtMenu.menuShowing()) {
3098 				manager.reset();
3099 				manager.setHoverObject(obj);
3100 				manager.setHoverOverData(mouseEv);
3101 				manager.setHoverOverDelay(DwtToolTip.TOOLTIP_DELAY);
3102 				manager.setHoverOverListener(obj._hoverOverListener);
3103 				manager.hoverOver(mouseEv.docX, mouseEv.docY);
3104 			}
3105 		}
3106 	}
3107 	mouseEv._stopPropagation = true;
3108 	mouseEv._returnValue = false;
3109 	mouseEv.setToDhtmlEvent(ev);
3110 	return false;
3111 
3112 	} catch (ex) {
3113 		AjxException.reportScriptError(ex);
3114 	}
3115 };
3116 
3117 /**
3118  * @private
3119  */
3120 DwtControl.__mouseEnterHdlr =
3121 function(ev) {
3122 	return DwtControl.__mouseOverHdlr(ev, DwtEvent.ONMOUSEENTER);
3123 };
3124 
3125 /**
3126  * @private
3127  */
3128 DwtControl.__mouseDownHdlr =
3129 function(ev) {
3130 
3131 	try {
3132 
3133 	var obj = DwtControl.getTargetControl(ev);
3134 	if (!obj) { return false; }
3135 
3136 	ev = DwtUiEvent.getEvent(ev);
3137 	var mouseEv = DwtShell.mouseEvent;
3138 	mouseEv.setFromDhtmlEvent(ev, obj);
3139 	if (mouseEv.button == DwtMouseEvent.LEFT) {
3140 		obj._focusByMouseDownEvent(ev);
3141 		// reset our event - above call can set type to "blur" (at least in FF)
3142 		mouseEv.setFromDhtmlEvent(ev, obj);
3143 	}
3144 
3145 	if (obj.__hasToolTipContent()) {
3146 		var shell = DwtShell.getShell(window);
3147 		var manager = shell.getHoverMgr();
3148 		manager.setHoverOutListener(obj._hoverOutListener);
3149 		manager.hoverOut();
3150 	}
3151 
3152 	// If we have a dragSource, then we need to start capturing mouse events
3153 	if (obj._dragSource && (mouseEv.button == DwtMouseEvent.LEFT) && obj._isValidDragObject(mouseEv))	{
3154 		try {
3155 			obj._ctrlCaptureObj.capture();
3156 		} catch (ex) {
3157 			DBG.dumpObj(ex);
3158 		}
3159 		obj._dragOp = obj._getDragOp(mouseEv);
3160 		obj.__dragStartX = mouseEv.docX;
3161 		obj.__dragStartY = mouseEv.docY;
3162 	}
3163 	else if (obj._dragBox) {
3164 		// We do mouse capture for drag boxes mostly because the mouseup can come from anywhere, and we
3165 		// want to handle it, usually by destroying the box.
3166 		if (obj._dragBox._setStart(mouseEv, obj)) {
3167 			try {
3168 				obj._ctrlCaptureObj.capture();
3169 			} catch (ex) {
3170 				DBG.dumpObj(ex);
3171 			}
3172 		}
3173 	}
3174 
3175 	return DwtControl.__mouseEvent(ev, DwtEvent.ONMOUSEDOWN, obj, mouseEv);
3176 
3177 	} catch (ex) {
3178 		AjxException.reportScriptError(ex);
3179 	}
3180 };
3181 
3182 /**
3183  * @private
3184  */
3185 DwtControl.__mouseMoveHdlr =
3186 function(ev) {
3187 
3188 	try {
3189 
3190 	// Find the target control. If we're doing capture (DnD), we get it from the capture object.
3191 	var captureObj = (DwtMouseEventCapture.getId() == "DwtControl") ? DwtMouseEventCapture.getCaptureObj() : null;
3192 	var obj = captureObj ? captureObj.targetObj : DwtControl.getTargetControl(ev);
3193  	if (!obj) { return false; }
3194 
3195 	// DnD hover cancel point
3196 	if (obj.__dndHoverActionId != -1) {
3197 		AjxTimedAction.cancelAction(obj.__dndHoverActionId);
3198 		obj.__dndHoverActionId = -1;
3199 	}
3200 
3201 	var mouseEv = DwtShell.mouseEvent;
3202 	mouseEv.setFromDhtmlEvent(ev, captureObj ? true : obj);
3203 
3204 	// This following can happen during a DnD operation if the mouse moves
3205 	// out the window. This seems to happen on IE only.
3206 	if (mouseEv.docX < 0 || mouseEv.docY < 0) {
3207 		mouseEv._stopPropagation = true;
3208 		mouseEv._returnValue = false;
3209 		mouseEv.setToDhtmlEvent(ev);
3210 		return false;
3211 	}
3212 
3213 	// If we are not draggable or if we have not started dragging and are
3214 	// within the Drag threshold then handle it as a move.
3215 	var doingDnD = (obj._dragSource && captureObj &&
3216 			(Math.abs(obj.__dragStartX - mouseEv.docX) >= DwtControl.__DRAG_THRESHOLD ||
3217 			 Math.abs(obj.__dragStartY - mouseEv.docY) >= DwtControl.__DRAG_THRESHOLD));
3218 	var doingDragBox = (captureObj && obj._dragBox && obj._dragBox._dragObj == obj);
3219 
3220 	if (!doingDnD && !doingDragBox) {
3221 		if (obj.__hasToolTipContent()) {
3222 			var shell = DwtShell.getShell(window);
3223 			var manager = shell.getHoverMgr();
3224 			if (!obj.__tooltipClosed && !DwtMenu.menuShowing()) {
3225 				// NOTE: mouseOver already init'd other hover settings
3226 				// We do hoverOver() here since the mouse may have moved during
3227 				// the delay, and we want to use latest x,y
3228 				manager.hoverOver(mouseEv.docX, mouseEv.docY);
3229 			} else {
3230 				var deltaX = obj.__lastTooltipX ? Math.abs(mouseEv.docX - obj.__lastTooltipX) : null;
3231 				var deltaY = obj.__lastTooltipY ? Math.abs(mouseEv.docY - obj.__lastTooltipY) : null;
3232 				if ((deltaX != null && deltaX > DwtControl.__TOOLTIP_THRESHOLD) ||
3233 					(deltaY != null && deltaY > DwtControl.__TOOLTIP_THRESHOLD)) {
3234 					manager.setHoverOutListener(obj._hoverOutListener);
3235 					manager.hoverOut();
3236 					obj.__tooltipClosed = true; // prevent tooltip popup during moves in this object
3237 				}
3238 			}
3239 		}
3240 		return DwtControl.__mouseEvent(ev, DwtEvent.ONMOUSEMOVE, obj, mouseEv);
3241 	} else {
3242 		// If we are not dragging, try to begin a drag operation, which may be either DnD or drawing a box.
3243 		if (obj._dragging == DwtControl._NO_DRAG) {
3244 			if (obj._dragSource) {
3245 				obj._dragOp = obj._dragSource._beginDrag(obj._dragOp, obj);
3246 				if (obj._dragOp != Dwt.DND_DROP_NONE) {
3247 					obj._dragging = DwtControl._DRAGGING;
3248 					obj._dndProxy = obj._getDragProxy(obj._dragOp);
3249 					Dwt.addClass(obj._dndProxy, "DwtDragProxy");
3250 					if (!obj._dndProxy) {
3251 						obj._dragging = DwtControl._DRAG_REJECTED;
3252 					}
3253 				} else {
3254 					obj._dragging = DwtControl._DRAG_REJECTED;
3255 				}
3256 			}
3257 			else if (obj._dragBox) {
3258 				obj._dragging = DwtControl._DRAGGING;
3259 				obj._dragBox._beginDrag(obj);
3260 			}
3261 		}
3262 
3263 		if (obj._dragging != DwtControl._DRAG_REJECTED) {
3264 			var targetObj = mouseEv.dwtObj;
3265 			if (obj._dragSource) {
3266 				var dropTarget = targetObj && targetObj._dropTarget;
3267 				var lastTargetObj = obj.__lastTargetObj;
3268 				if (targetObj) {
3269 					// Set up the drag hover event. we will even let this item hover over itself as there may be
3270 					// scenarios where that will hold true
3271 					obj._dndHoverAction.args = [ targetObj ];
3272 					obj.__dndHoverActionId = AjxTimedAction.scheduleAction(obj._dndHoverAction, DwtControl.__DND_HOVER_DELAY);
3273 				}
3274 
3275 				// See if the target will allow us to be dropped on it. We have to be an allowable type, and the
3276 				// target's drop listener may perform additional checks. The DnD icon will typically turn green or
3277 				// red to indicate whether a drop is allowed.
3278 				if (targetObj && dropTarget && ((targetObj != obj) || dropTarget.hasMultipleTargets())) {
3279 					if (targetObj != lastTargetObj || dropTarget.hasMultipleTargets()) {
3280 						var data = obj._dragSource._getData();
3281 						if (dropTarget._dragEnter(obj._dragOp, targetObj, data, mouseEv, obj._dndProxy)) {
3282 							obj._setDragProxyState(true);
3283 							obj.__dropAllowed = true;
3284 							targetObj._dragEnter(mouseEv);
3285 						} else {
3286 							obj._setDragProxyState(false);
3287 							obj.__dropAllowed = false;
3288 						}
3289 					} else if (obj.__dropAllowed) {
3290 						targetObj._dragOver(mouseEv);
3291 					}
3292 				} else {
3293 					obj._setDragProxyState(false);
3294 				}
3295 
3296 				// Tell the previous target that we're no longer being dragged over it.
3297 				if (lastTargetObj && lastTargetObj != targetObj && lastTargetObj._dropTarget && lastTargetObj != obj) {
3298 					// check if obj dragged out of scrollable container
3299 					if (targetObj && !targetObj._dndScrollCallback && lastTargetObj._dndScrollCallback) {
3300 						lastTargetObj._dndScrollCallback.run(mouseEv);
3301 					}
3302 
3303 					lastTargetObj._dragLeave(mouseEv);
3304 					lastTargetObj._dropTarget._dragLeave();
3305 				}
3306 
3307 				obj.__lastTargetObj = targetObj;
3308 
3309 				if ((targetObj != obj) && targetObj && targetObj._dndScrollCallback) {
3310 					targetObj._dndScrollCallback.run(mouseEv);
3311 				}
3312 
3313 				// Move the DnD icon. We offset the location slightly so the icon doesn't receive the mousemove events.
3314 				Dwt.setLocation(obj._dndProxy, mouseEv.docX + 2, mouseEv.docY + 2);
3315 			}
3316 
3317 			// We keep drawing a drag box as long as we're still over the owning object. We need to check its child
3318 			// objects, and whether we're over the box itself (in case the user reverses direction).
3319 			else if (obj._dragBox) {
3320 				var evTarget = DwtUiEvent.getTarget(ev);
3321 				if (targetObj && (Dwt.isAncestor(obj.getHtmlElement(), evTarget) || evTarget == obj._dragSelectionBox)) {
3322 					obj._dragBox._dragMove(mouseEv, obj);
3323 				}
3324 			}
3325 
3326 		} else {
3327 			DwtControl.__mouseEvent(ev, DwtEvent.ONMOUSEMOVE, obj, mouseEv);
3328 		}
3329 		mouseEv._stopPropagation = true;
3330 		mouseEv._returnValue = false;
3331 		mouseEv.setToDhtmlEvent(ev);
3332 		return false;
3333 	}
3334 
3335 	} catch (ex) {
3336 		AjxException.reportScriptError(ex);
3337 	}
3338 };
3339 
3340 /**
3341  * @private
3342  */
3343 DwtControl.__mouseUpHdlr =
3344 function(ev) {
3345 
3346 	try {
3347 
3348 	// Find the target control. If we're doing capture (DnD), we get it from the capture object.
3349 	var captureObj = (DwtMouseEventCapture.getId() == "DwtControl") ? DwtMouseEventCapture.getCaptureObj() : null;
3350 	var obj = captureObj ? captureObj.targetObj : DwtControl.getTargetControl(ev);
3351 	if (!obj) { return false; }
3352 
3353 	// DnD hover cancel point
3354 	if (obj.__dndHoverActionId != -1) {
3355 		AjxTimedAction.cancelAction(obj.__dndHoverActionId);
3356 		obj.__dndHoverActionId = -1;
3357 	}
3358 
3359 	var mouseEv = DwtShell.mouseEvent;
3360 	mouseEv.setFromDhtmlEvent(ev, captureObj ? true : obj);
3361 	if (!(captureObj && (obj._dragSource || obj._dragBox))) {
3362 		return DwtControl.__processMouseUpEvent(ev, obj, mouseEv);
3363 	} else {
3364 		captureObj.release();
3365 		if (obj._dragging != DwtControl._DRAGGING) {
3366 			obj._dragging = DwtControl._NO_DRAG;
3367 			return DwtControl.__processMouseUpEvent(ev, obj, mouseEv);
3368 		}
3369 		if (obj._dragSource) {
3370 			obj.__lastTargetObj = null;
3371 			var targetObj = mouseEv.dwtObj;
3372 			var dropTarget = targetObj && targetObj._dropTarget;
3373 			// Perform the drop if the target has allowed it
3374 			if (targetObj && dropTarget && obj.__dropAllowed && ((targetObj != obj) || dropTarget.hasMultipleTargets())) {
3375 				targetObj._drop(mouseEv);
3376 				dropTarget._drop(obj._dragSource._getData(), mouseEv);
3377 				obj._dragSource._endDrag();
3378 				obj._destroyDragProxy(obj._dndProxy);
3379 				obj._dragging = DwtControl._NO_DRAG;
3380 			} else {
3381 				DwtControl.__badDrop(obj, mouseEv);
3382 			}
3383 			if (targetObj && targetObj._dndScrollCallback) {
3384 				targetObj._dndScrollCallback.run(mouseEv);
3385 			}
3386 		}
3387 		else if (obj._dragBox) {
3388 			obj._dragBox._endDrag(obj);
3389 		}
3390 		mouseEv._stopPropagation = true;
3391 		mouseEv._returnValue = false;
3392 		mouseEv.setToDhtmlEvent(ev);
3393 		return false;
3394 	}
3395 
3396 	} catch (ex) {
3397 		AjxException.reportScriptError(ex);
3398 	}
3399 };
3400 
3401 /**
3402  * Handles a bad DND drop operation by showing an animation of the icon flying
3403  * back to its origin.
3404  *
3405  * @param obj		[DwtControl]	control that underlies drag operation
3406  * @param mouseEv	[DwtMouseEvent]	mouse event
3407  * @private
3408  */
3409 DwtControl.__badDrop =
3410 function(obj, mouseEv) {
3411 	if (obj._dragSource) {
3412 		obj._dragSource._cancelDrag();
3413 	}
3414     var targetObj = mouseEv.dwtObj;
3415     if (targetObj) {
3416        targetObj._drop(mouseEv);
3417     }
3418 	// The following code sets up the drop effect for when an
3419 	// item is dropped onto an invalid target. Basically the
3420 	// drag icon will spring back to its starting location.
3421 	obj.__dragEndX = mouseEv.docX;
3422 	obj.__dragEndY = mouseEv.docY;
3423 	if (obj.__badDropAction == null) {
3424 		obj.__badDropAction = new AjxTimedAction(obj, obj.__badDropEffect);
3425 	}
3426 
3427 	// Line equation is y = mx + c. Solve for c, and set up d (direction)
3428 	var m = (obj.__dragEndY - obj.__dragStartY) / (obj.__dragEndX - obj.__dragStartX);
3429 	obj.__badDropAction.args = [m, obj.__dragStartY - (m * obj.__dragStartX), (obj.__dragStartX - obj.__dragEndX < 0) ? -1 : 1];
3430 	AjxTimedAction.scheduleAction(obj.__badDropAction, 0);
3431 };
3432 
3433 /**
3434  * Handle double clicks in isolation, if requested (if not, events are handled
3435  * normally). On the first click, we set a 'click pending' flag and start a timer.
3436  * If the timer expires before another click arrives, we process the single click.
3437  * If a double-click event arrives before the timer expires, then we process the
3438  * double-click event.
3439  * @private
3440  */
3441 DwtControl.__processMouseUpEvent =
3442 function(ev, obj, mouseEv) {
3443 	var shell = DwtShell.getShell(window);
3444 	var hoverMgr = shell.getHoverMgr();
3445 	hoverMgr.ignoreHoverOverOnClick();
3446 
3447 	if (obj._dblClickIsolation && mouseEv && (mouseEv.button == DwtMouseEvent.LEFT)) {
3448 		if (obj._clickPending) {
3449 			// wait for real dblclick event
3450 			return false;
3451 		} else {
3452 			obj._clickPending = true;
3453 			var ta = new AjxTimedAction(null, DwtControl.__timedClick, [ev, obj, mouseEv]);
3454 			obj._dblClickActionId = AjxTimedAction.scheduleAction(ta, DwtControl.__DBL_CLICK_TIMEOUT);
3455 			DwtUiEvent.setBehaviour(ev, true, false);
3456 			obj._st = new Date();
3457 			return false;
3458 		}
3459 	} else {
3460 		obj._clickPending = false;
3461 		return DwtControl.__mouseEvent(ev, DwtEvent.ONMOUSEUP, obj, mouseEv);
3462 	}
3463 };
3464 
3465 DwtControl.__timedClick =
3466 function(ev, obj, mouseEv) {
3467 	obj._clickPending = false;
3468 	DwtControl.__mouseEvent(ev, DwtEvent.ONMOUSEUP, obj, mouseEv);
3469 };
3470 
3471 /**
3472  * @private
3473  */
3474 DwtControl.__mouseOutHdlr =
3475 function(ev, evType) {
3476 
3477 	try {
3478 
3479 	var obj = DwtControl.getTargetControl(ev);
3480 	if (!obj) { return false; }
3481 	evType = evType || DwtEvent.ONMOUSEOUT;
3482 	if ((evType == DwtEvent.ONMOUSEOUT) && obj._ignoreInternalOverOut) {
3483 		var otherObj = DwtControl.getTargetControl(ev, true);
3484 		if (obj == otherObj) {
3485 			return false;
3486 		}
3487 	}
3488 
3489 	if (obj.__hasToolTipContent()) {
3490 		var shell = DwtShell.getShell(window);
3491 		var manager = shell.getHoverMgr();
3492 			manager.setHoverOutListener(obj._hoverOutListener);
3493 			manager.hoverOut();
3494 			obj.__tooltipClosed = false;
3495 	}
3496 	return DwtControl.__mouseEvent(ev, evType || DwtEvent.ONMOUSEOUT, obj);
3497 
3498 	} catch (ex) {
3499 		AjxException.reportScriptError(ex);
3500 	}
3501 };
3502 
3503 /**
3504  * @private
3505  */
3506 DwtControl.__mouseLeaveHdlr =
3507 function(ev) {
3508 	return DwtControl.__mouseOutHdlr(ev, DwtEvent.ONMOUSELEAVE);
3509 };
3510 
3511 /**
3512  * @private
3513  */
3514 DwtControl.__mouseWheelHdlr =
3515 function(ev) {
3516 
3517 	try {
3518 
3519 	return DwtControl.__mouseEvent(ev, DwtEvent.ONMOUSEWHEEL);
3520 
3521 	} catch (ex) {
3522 		AjxException.reportScriptError(ex);
3523 	}
3524 };
3525 
3526 /**
3527  * @private
3528  */
3529 DwtControl.__selectStartHdlr =
3530 function(ev) {
3531 
3532 	try {
3533 
3534 	return DwtControl.__mouseEvent(ev, DwtEvent.ONSELECTSTART);
3535 
3536 	} catch (ex) {
3537 		AjxException.reportScriptError(ex);
3538 	}
3539 };
3540 
3541 /**
3542  * Note: if there is also a mousedown handler, oncontextmenu is no longer sent, so be careful.
3543  *
3544  * @private
3545  */
3546 DwtControl.__contextMenuHdlr =
3547 function(ev) {
3548 
3549 	try {
3550 
3551 	// for Safari, we have to fake a right click
3552 	if (AjxEnv.isSafari) {
3553 		var obj = DwtControl.getTargetControl(ev);
3554 		var prevent = obj ? obj.preventContextMenu() : true;
3555 		if (prevent) {
3556 			DwtControl.__mouseEvent(ev, DwtEvent.ONMOUSEDOWN);
3557 			return DwtControl.__mouseEvent(ev, DwtEvent.ONMOUSEUP);
3558 		}
3559 	}
3560 	return DwtControl.__mouseEvent(ev, DwtEvent.ONCONTEXTMENU);
3561 
3562 	} catch (ex) {
3563 		AjxException.reportScriptError(ex);
3564 	}
3565 };
3566 
3567 /**
3568  * @private
3569  */
3570 DwtControl.__mouseEvent =
3571 function(ev, eventType, obj, mouseEv) {
3572 
3573 	var obj = obj ? obj : DwtControl.getTargetControl(ev);
3574 	if (!obj) { return false; }
3575 
3576 	if (!mouseEv) {
3577 		mouseEv = DwtShell.mouseEvent;
3578 		mouseEv.setFromDhtmlEvent(ev, obj);
3579 	}
3580 
3581 	// By default, we halt event processing. The default can be overridden here through
3582 	// the use of setEventPropagation(). A listener may also change the event props when called.
3583 	var tn = mouseEv.target.tagName && mouseEv.target.tagName.toLowerCase();
3584 	var propagate = obj._propagateEvent[eventType] || (tn === "input" || tn === "textarea" || tn === "a" || tn === "label" || tn === "select");
3585 	//todo - not sure if _stopPropagation and _dontCallPreventDefault should not the the SAME. Since if you stop propagation and dontCallPreventDefault,
3586 	//it DOES allow selection (or context menu, etc, any default browser stuff). But if you allow to propagate, this might be overriden by a DOM element
3587 	//higher up, which might not be what we want. Very confusing.
3588 	mouseEv._stopPropagation = !propagate;
3589 	mouseEv._dontCallPreventDefault = propagate;
3590 	mouseEv._returnValue = propagate;
3591 
3592 	// notify global listeners
3593 	DwtEventManager.notifyListeners(eventType, mouseEv);
3594 
3595 	// notify widget listeners
3596 	if (obj.isListenerRegistered && obj.isListenerRegistered(eventType)) {
3597 		obj.notifyListeners(eventType, mouseEv);
3598 	}
3599 
3600 	// publish our settings to the DOM
3601 	mouseEv.setToDhtmlEvent(ev);
3602 
3603 	// Some screen readers exclusively trigger ONCLICK events, but
3604 	// Zimbra relies on ONMOUSEDOWN/ONMOUSEUP sequences for buttons
3605 	// and some other controls, so we detect non-mouse clicks and
3606 	// introduce the ability to 'fake' ONMOUSEDOWN/ONMOUSEUP sequences
3607 	// for them. This triggers when the control element has a listener
3608 	// for ONCLICK, but the DwtControl doesn't.
3609 	if (eventType == DwtEvent.ONMOUSELEAVE ||
3610 		eventType == DwtEvent.ONMOUSEOUT) {
3611 		// we're 'switching' elements, so the browser won't
3612 		// trigger a click event
3613 		obj.__ignoreNextClick = false;
3614 
3615 	} else if (eventType == DwtEvent.ONMOUSEUP) {
3616 		// yes, ignore the next click -- ZCS' built-in click-ish
3617 		// thing will work just fine
3618 		obj.__ignoreNextClick = true;
3619 
3620 	} else if (eventType == DwtEvent.ONCLICK) {
3621 		if (obj.__ignoreNextClick) {
3622 			DBG.println(AjxDebug.ACCESSIBILITY,
3623 			            "DwtControl: ignoring a click!");
3624 			obj.__ignoreNextClick = false;
3625 			return true;
3626 		}
3627 
3628 		// check whether the target control listens for clicks,
3629 		// and if not, fake a mouseup/mousedown event pair
3630 		if (obj.isListenerRegistered && !obj.isListenerRegistered(DwtEvent.ONCLICK)) {
3631 			DBG.println(AjxDebug.ACCESSIBILITY,
3632 			            "DwtControl: faking a click!");
3633 
3634 			eventType = DwtEvent.ONMOUSEDOWN;
3635 			if (ev) {
3636 				ev.type = eventType;
3637 			}
3638 
3639 			DwtControl.__mouseEvent(ev, eventType, obj, DwtShell.mouseEvent);
3640 
3641 			eventType = DwtEvent.ONMOUSEUP;
3642 			if (ev) {
3643 				ev.type = eventType;
3644 			}
3645 
3646 			DwtControl.__mouseEvent(ev, eventType, obj, DwtShell.mouseEvent);
3647 
3648 			return DwtShell.mouseEvent._returnValue;
3649 		} else {
3650 			DBG.println(AjxDebug.ACCESSIBILITY,
3651 			            "DwtControl: skipping a click!");
3652 			window.console && console.warn('skipping a click!');
3653 		}
3654 	}
3655 
3656 	return mouseEv._returnValue;
3657 };
3658 
3659 // need to populate this hash after methods are defined
3660 /**
3661  * @private
3662  */
3663 DwtControl.__HANDLER = {};
3664 DwtControl.__HANDLER[DwtEvent.ONCONTEXTMENU] = DwtControl.__contextMenuHdlr;
3665 DwtControl.__HANDLER[DwtEvent.ONCLICK] = DwtControl.__clickHdlr;
3666 DwtControl.__HANDLER[DwtEvent.ONDBLCLICK] = DwtControl.__dblClickHdlr;
3667 DwtControl.__HANDLER[DwtEvent.ONMOUSEDOWN] = DwtControl.__mouseDownHdlr;
3668 DwtControl.__HANDLER[DwtEvent.ONMOUSEENTER] = DwtControl.__mouseEnterHdlr;
3669 DwtControl.__HANDLER[DwtEvent.ONMOUSELEAVE] = DwtControl.__mouseLeaveHdlr;
3670 DwtControl.__HANDLER[DwtEvent.ONMOUSEMOVE] = DwtControl.__mouseMoveHdlr;
3671 DwtControl.__HANDLER[DwtEvent.ONMOUSEOUT] = DwtControl.__mouseOutHdlr;
3672 DwtControl.__HANDLER[DwtEvent.ONMOUSEOVER] = DwtControl.__mouseOverHdlr;
3673 DwtControl.__HANDLER[DwtEvent.ONMOUSEUP] = DwtControl.__mouseUpHdlr;
3674 DwtControl.__HANDLER[DwtEvent.ONMOUSEWHEEL] = DwtControl.__mouseWheelHdlr;
3675 DwtControl.__HANDLER[DwtEvent.ONSELECTSTART] = DwtControl.__selectStartHdlr;
3676 DwtControl.__HANDLER[DwtEvent.ONKEYPRESS] = DwtControl.__keyPressHdlr;
3677 DwtControl.__HANDLER[DwtEvent.ONKEYUP] = DwtControl.__keyUpHdlr;
3678 DwtControl.__HANDLER[DwtEvent.ONKEYDOWN] = DwtControl.__keyDownHdlr;
3679 DwtControl.__HANDLER[DwtEvent.ONFOCUS] = DwtControl.__focusHdlr;
3680 DwtControl.__HANDLER[DwtEvent.ONBLUR] = DwtControl.__blurHdlr;
3681 
3682 /**
3683  * @private
3684  */
3685 DwtControl.prototype.__initCtrl =
3686 function() {
3687 	this.shell = this.parent.shell || this.parent;
3688 	// __internalId is for back-compatibility (was side effect of Dwt.associateElementWithObject)
3689 	this._htmlElId = this.__internalId = this._htmlElId || Dwt.getNextId();
3690 	var htmlElement = this._elRef = this._createElement(this._htmlElId);
3691 	htmlElement.id = this._htmlElId;
3692     if (DwtControl.ALL_BY_ID[this._htmlElId]) {
3693         DBG.println(AjxDebug.DBG1, "Duplicate ID for " + this.toString() + ": " + this._htmlElId);
3694         this._htmlElId = htmlElement.id = this.__internalId = DwtId.makeId(this._htmlElId, Dwt.getNextId());
3695     }
3696     DwtControl.ALL_BY_ID[this._htmlElId] = this;
3697 	DwtComposite._pendingElements[this._htmlElId] = htmlElement;
3698 	htmlElement.style.position = this.__posStyle || DwtControl.STATIC_STYLE;
3699 	htmlElement.className = this._className;
3700 	htmlElement.style.overflow = "visible";
3701 	if (this.role) {
3702 		htmlElement.setAttribute('role', this.role);
3703 	}
3704 	this._enabled = true;
3705 	this.__controlEvent = DwtControl.__controlEvent;
3706 	this._dragging = DwtControl._NO_DRAG;
3707 	this.__ctrlInited = true;
3708 
3709     this.setFocusElement();
3710 
3711     // timed actions in case we don't get focus/blur events when we programmatically focus/blur
3712     this._focusAction = new AjxTimedAction(null, DwtControl.__focusHdlr, [ DwtShell.focusEvent, DwtEvent.ONFOCUS, this ]);
3713     this._blurAction = new AjxTimedAction(null, DwtControl.__blurHdlr, [ DwtShell.focusEvent, DwtEvent.ONBLUR, this ]);
3714 
3715 	// Make sure this is the last thing we do
3716 	this.parent.addChild(this, this.__index);
3717 };
3718 
3719 /**
3720  * Returns the container element to be used for this control.
3721  * <p>
3722  * <strong>Note:</strong>
3723  * The caller will overwrite the id of the returned element with the
3724  * specified id.
3725  *
3726  * @param id [string] The id of the container element.
3727  * @private
3728  */
3729 DwtControl.prototype._createElement = function(id) {
3730 	return document.createElement("DIV")
3731 };
3732 
3733 /**
3734  * @private
3735  */
3736 DwtControl.prototype.__dndDoHover =
3737 function(control) {
3738 	//TODO Add allow hover?
3739 	control._dragHover();
3740 };
3741 
3742 /**
3743  * This method is called when a drop happens on an invalid target. The code will
3744  * animate the Drag icon back to its source before destroying it via <code>_destroyDragProxy</code>
3745  * @private
3746  */
3747 DwtControl.prototype.__badDropEffect =
3748 function(m, c, d) {
3749 	var usingX = (Math.abs(m) <= 1);
3750 	// Use the bigger delta to control the snap effect
3751 	var delta = usingX ? this.__dragStartX - this.__dragEndX : this.__dragStartY - this.__dragEndY;
3752     if (delta * d > 0 && !(this.__dragEndY == this.__dragStartY || this.__dragEndX == this.__dragStartX) ) {
3753 		if (usingX) {
3754 			this.__dragEndX += (30 * d);
3755 			this._dndProxy.style.top = m * this.__dragEndX + c;
3756 			this._dndProxy.style.left = this.__dragEndX;
3757 		} else {
3758 			this.__dragEndY += (30 * d);
3759 			this._dndProxy.style.top = this.__dragEndY;
3760 			this._dndProxy.style.left = (this.__dragEndY - c) / m;
3761 		}
3762 		AjxTimedAction.scheduleAction(this.__badDropAction, 0);
3763  	} else {
3764   		this._destroyDragProxy(this._dndProxy);
3765 		this._dragging = DwtControl._NO_DRAG;
3766   	}
3767 };
3768 
3769 /**
3770  * Attempts to display a tooltip for this control, triggered by the cursor having been
3771  * over the control for a period of time. The tooltip may have already been set (if it's
3772  * a static tooltip). For dynamic tooltip content, the control implements getToolTipContent()
3773  * to return the content or a callback. It should return a callback if it makes an
3774  * async server call to get data.
3775  *
3776  * @private
3777  */
3778 DwtControl.prototype.__handleHoverOver =
3779 function(event) {
3780 
3781 	if (this._eventMgr.isListenerRegistered(DwtEvent.HOVEROVER)) {
3782 		this._eventMgr.notifyListeners(DwtEvent.HOVEROVER, event);
3783 	}
3784 
3785 	var mouseEv = event && event.object;
3786 	var tooltip = this.getToolTipContent(mouseEv);
3787 	var content, callback;
3788 	if (!tooltip) {
3789 		content = "";
3790 	} else if (typeof(tooltip) == "string") {
3791 		content = tooltip;
3792 	} else if (tooltip.isAjxCallback || AjxUtil.isFunction(tooltip)) {
3793 		callback = tooltip;
3794 	} else if (typeof(tooltip) == "object") {
3795 		content = tooltip.content;
3796 		callback = tooltip.callback;
3797 	}
3798 
3799 	if (!content && callback && tooltip.loading) {
3800 		content = AjxMsg.loading;
3801 	}
3802 
3803 	if (content) {
3804 		this.__showToolTip(event, content);
3805 	}
3806 
3807 	if (callback) {
3808 		var callback1 = new AjxCallback(this, this.__showToolTip, [event]);
3809 		AjxTimedAction.scheduleAction(new AjxTimedAction(null, function() { callback.run(callback1); }), 0);
3810 	}
3811 };
3812 
3813 /**
3814  * @private
3815  */
3816 DwtControl.prototype.__showToolTip =
3817 function(event, content) {
3818 
3819 	if (!content) { return; }
3820     DwtControl.showToolTip(content, event.x, event.y, this, event);
3821 	this.__lastTooltipX = event.x;
3822 	this.__lastTooltipY = event.y;
3823 	this.__tooltipClosed = false;
3824 };
3825 
3826 /**
3827  * @private
3828  */
3829 DwtControl.prototype.__handleHoverOut =
3830 function(event) {
3831 	if (this._eventMgr.isListenerRegistered(DwtEvent.HOVEROUT)) {
3832 		this._eventMgr.notifyListeners(DwtEvent.HOVEROUT, event);
3833 	}
3834     DwtControl.hideToolTip();
3835 	this.__lastTooltipX = null;
3836 	this.__lastTooltipY = null;
3837 };
3838 
3839 /**
3840  * @private
3841  */
3842 DwtControl.prototype.__isInputEl =
3843 function(targetEl) {
3844 	var bIsInput = false;
3845 	if(!targetEl || !targetEl.tagName) {
3846 		return bIsInput;
3847 	}
3848 	var tagName = targetEl.tagName.toLowerCase();
3849 	var type = tagName == "input" ? targetEl.type.toLowerCase() : null;
3850 
3851 	if (tagName == "textarea" || (type && (type == "text" || type == "password")))
3852 		bIsInput = true;
3853 
3854 	return bIsInput;
3855 };
3856 
3857 
3858 /**
3859  * onunload hacking
3860  * @private
3861  */
3862 DwtControl.ON_UNLOAD =
3863 function() {
3864 	// break widget-element references
3865 	var h = DwtControl.ALL_BY_ID, i;
3866 	for (i in h) {
3867 		h[i]._elRef = null;
3868 	}
3869 	DwtControl.ALL_BY_ID = {};
3870 };
3871 
3872 if (window.attachEvent) {
3873 	window.attachEvent("onunload", DwtControl.ON_UNLOAD);
3874 }
3875 else if (window.addEventListener) {
3876 	window.addEventListener("unload", DwtControl.ON_UNLOAD, false);
3877 }
3878 
3879 /**
3880  *  A helper method to show the toolTips.
3881  * @param content
3882  * @param x [Number] The x coordinate of the toolTip.
3883  * @param y [Number] The y coordinate of the toolTip.
3884  */
3885 DwtControl.showToolTip =
3886 function(content, x, y, obj, hoverEv) {
3887 	if (!content) { return; }
3888 	var tooltip = DwtShell.getShell(window).getToolTip();
3889 	tooltip.setContent(content);
3890 	tooltip.popup(x, y, false, false, obj, hoverEv);
3891 };
3892 
3893 /**
3894  * A helper method to hide the toolTip.
3895  */
3896 DwtControl.hideToolTip =
3897 function() {
3898 	DwtShell.getShell(window).getToolTip().popdown();
3899 };
3900 
3901 /**
3902  * Returns the element that should be used as a base for positioning the tooltip.
3903  * If overridden to return null, the cursor position will be used as the base.
3904  * 
3905  * @param {DwtHoverEvent}	hoverEv		hover event (from hover mgr)
3906  */
3907 DwtControl.prototype.getTooltipBase =
3908 function(hoverEv) {
3909 	return this.getHtmlElement();
3910 };
3911 
3912 DwtControl.prototype.boundsForChild =
3913 function(child) {
3914 	if (child && child.getHtmlElement) {
3915 		child = child.getHtmlElement();
3916 	}
3917 
3918 	var fn = function(bounds, node) {
3919 		var margins = Dwt.getMargins(node);
3920 		var bounds = Dwt.insetBounds(bounds, Dwt.getInsets(node));
3921 		bounds.width =
3922 			Math.max(bounds.width - margins.left - margins.right, 0);
3923 		bounds.height =
3924 			Math.max(bounds.height - margins.top - margins.bottom, 0);
3925 		return bounds;
3926 	};
3927 
3928 	var bounds = new DwtRectangle(0, 0, this.getHtmlElement().clientWidth,
3929 	                              this.getHtmlElement().clientHeight);
3930 
3931 	return AjxUtil.reduce(Dwt.getAncestors(child, this.getHtmlElement(), true),
3932 	                      fn, bounds);
3933 };
3934 
3935 // Convenience methods for manipulating attributes of this control's DIV
3936 DwtControl.prototype.hasAttribute = function(attr) {
3937 	return this.getHtmlElement().hasAttribute(attr);
3938 };
3939 DwtControl.prototype.getAttribute = function(attr) {
3940 	return this.getHtmlElement().getAttribute(attr);
3941 };
3942 DwtControl.prototype.setAttribute = function(attr, value) {
3943 	this.getHtmlElement().setAttribute(attr, value);
3944 };
3945 DwtControl.prototype.removeAttribute = function(attr) {
3946 	this.getHtmlElement().removeAttribute(attr);
3947 };
3948 
3949