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