1 /* 2 * ***** BEGIN LICENSE BLOCK ***** 3 * Zimbra Collaboration Suite Web Client 4 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 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, 2013, 2014, 2015, 2016 Synacor, Inc. All Rights Reserved. 21 * ***** END LICENSE BLOCK ***** 22 */ 23 24 /** 25 * Creates a shell. 26 * @constructor 27 * @class 28 * This class represents a shell, the first widget that must be instantiated in a Dwt based 29 * application. By default the shell covers the whole browser window, though it may also be 30 * instantiated within an HTML element. 31 * <p> 32 * {@link DwtShell} should <b>NOT</b> be subclassed. 33 * </p> 34 * 35 * @author Ross Dargahi 36 * 37 * @param {hash} params a hash of parameters 38 * @param {string} params.className the CSS class name 39 * @param {boolean} params.docBodyScrollable if <code>true</code>, then the document body is set to be scrollable 40 * @param {Element} params.userShell an HTML element that will be reparented into an absolutely 41 * postioned container in this shell. This is useful in the situation where you have an HTML 42 * template and want to use this in context of Dwt. 43 * @param {Boolean} params.useCurtain if <code>true</code>, a curtain overlay is created to be used between hidden and viewable elements 44 * using z-index (see {@link Dwt}) for various layering constants) 45 * 46 * @extends DwtComposite 47 */ 48 DwtShell = function(params) { 49 if (window._dwtShellId) { 50 throw new DwtException("DwtShell already exists for window", DwtException.INVALID_OP, "DwtShell"); 51 } 52 53 var className = params.className || "DwtShell"; 54 DwtComposite.call(this, {className:className}); 55 56 // HACK! This is a hack to make sure that the control methods work 57 // with DwtShell since the parent of DwtShell is null. 58 this.__ctrlInited = true; 59 60 document.body.style.margin = 0; 61 if (!params.docBodyScrollable) { 62 if (AjxEnv.isIE) { 63 document.body.onscroll = DwtShell.__onBodyScroll; 64 } 65 document.body.style.overflow = "hidden"; 66 } 67 68 document.body.onselect = DwtShell._preventDefaultSelectPrt; 69 document.body.onselectstart = DwtShell._preventDefaultSelectPrt; 70 document.body.oncontextmenu = DwtShell._preventDefaultPrt; 71 window.onresize = DwtShell._resizeHdlr; 72 73 var htmlElement = document.createElement("div"); 74 this._htmlElId = window._dwtShellId = htmlElement.id = params.id || Dwt.getNextId(); 75 DwtControl.ALL_BY_ID[this._htmlElId] = this; 76 77 htmlElement.className = className; 78 htmlElement.style.width = htmlElement.style.height = "100%"; 79 Dwt.setPosition(htmlElement, DwtControl.ABSOLUTE_STYLE); 80 81 if (htmlElement.style.overflow) { 82 htmlElement.style.overflow = null; 83 } 84 85 // if there is a user shell (body content), move it below this shell 86 // into a container that's absolutely positioned 87 try { 88 if (params.userShell) { 89 document.body.removeChild(params.userShell); 90 } 91 } catch (ex) {} 92 document.body.appendChild(htmlElement); 93 if (params.userShell) { 94 var userShellContainer = new DwtControl({parent:this, posStyle:Dwt.ABSOLUTE_STYLE}); 95 userShellContainer.getHtmlElement().appendChild(params.userShell); 96 userShellContainer.setSize("100%", "100%"); 97 userShellContainer.zShow(true); 98 this._userShell = params.userShell; 99 } else { 100 this._userShell = null; 101 } 102 this.shell = this; 103 104 // Busy overlay - used when we want to enforce a modal busy state 105 this._createBusyOverlay(htmlElement); 106 107 // Veil overlay - used by DwtDialog to disable underlying app 108 this._veilOverlay = document.createElement("div"); 109 this._veilOverlay.className = (!AjxEnv.isLinux) ? "VeilOverlay" : "VeilOverlay-linux"; 110 this._veilOverlay.style.position = "absolute"; 111 this._veilOverlay.style.cursor = AjxEnv.isIE6up ? "not-allowed" : "wait"; 112 Dwt.setBounds(this._veilOverlay, 0, 0, "100%", "100%"); 113 Dwt.setZIndex(this._veilOverlay, Dwt.Z_HIDDEN); 114 this._veilOverlay.veilZ = new Array(); 115 this._veilOverlay.veilZ.push(Dwt.Z_HIDDEN); 116 this._veilOverlay.dialogZ = new Array(); 117 this._veilOverlay.activeDialogs = new Array(); 118 this._veilOverlay.innerHTML = "<table cellspacing=0 cellpadding=0 style='width:100%; height:100%'><tr><td> </td></tr></table>"; 119 htmlElement.appendChild(this._veilOverlay); 120 121 // Curtain overlay - used between hidden and viewable elements using z-index 122 if (params.useCurtain) { 123 this._curtainOverlay = document.createElement("div"); 124 this._curtainOverlay.className = "CurtainOverlay"; 125 this._curtainOverlay.style.position = "absolute"; 126 Dwt.setBounds(this._curtainOverlay, 0, 0, "100%", "100%") 127 Dwt.setZIndex(this._curtainOverlay, Dwt.Z_CURTAIN); 128 this._curtainOverlay.innerHTML = "<table cellspacing=0 cellpadding=0 style='width:100%; height:100%'><tr><td> </td></tr></table>"; 129 htmlElement.appendChild(this._curtainOverlay); 130 } 131 132 this._uiEvent = new DwtUiEvent(true); 133 this.relayout(); 134 135 // tooltip singleton used by all controls in shell 136 this._toolTip = new DwtToolTip(this); 137 this._hoverMgr = new DwtHoverMgr(); 138 139 this._keyboardMgr = new DwtKeyboardMgr(this); 140 } 141 142 DwtShell.prototype = new DwtComposite; 143 DwtShell.prototype.constructor = DwtShell; 144 145 /** 146 * DwtDialog not defined yet, can't base ID on it 147 * @private 148 */ 149 DwtShell.CANCEL_BUTTON = -1; 150 151 // Event objects used to populate events so we dont need to create them for each event 152 DwtShell.controlEvent = new DwtControlEvent(); 153 DwtShell.focusEvent = new DwtFocusEvent(); 154 DwtShell.keyEvent = new DwtKeyEvent(); 155 DwtShell.mouseEvent = new DwtMouseEvent(); 156 DwtShell.selectionEvent = new DwtSelectionEvent(true); 157 DwtShell.treeEvent = new DwtTreeEvent(); 158 159 DwtShell._GLOBAL_SELECTION = "GlobalSelection"; 160 161 // Public methods 162 163 DwtShell.prototype.toString = 164 function() { 165 return "DwtShell"; 166 } 167 168 /** 169 * Gets the shell managing the browser window (if any). 170 * 171 * @param {Window} win the global context 172 * @return {DwtShell} the shell or <code>null</code> 173 */ 174 DwtShell.getShell = function(win) { 175 win = win || window; 176 return DwtControl.fromElementId(win._dwtShellId); 177 }; 178 179 /** 180 * Gets the shell's keyboard manager. 181 * 182 * @return {DwtKeyboardMgr} the keyboard manager 183 * 184 * @private 185 */ 186 DwtShell.prototype.getKeyboardMgr = 187 function() { 188 return this._keyboardMgr; 189 } 190 191 /** 192 * Sets the busy overlay. The busy overlay disables input to the application and makes the 193 * cursor a wait cursor. Optionally a work in progress (WIP) dialog may be requested. Since 194 * multiple calls to this method may be interleaved, it accepts a unique ID to keep them 195 * separate. We also maintain a count of outstanding calls to <code>setBusy(true)</code>. When that count 196 * changes between 0 and 1, the busy overlay is applied or removed. 197 * 198 * @param {boolean} busy if <code>true</code>, set the busy overlay, otherwise hide the busy overlay 199 * @param {number} id a unique ID for this instance 200 * @param {boolean} showBusyDialog if <code>true</code>, show the WIP dialog 201 * @param {number} busyDialogDelay the number of ms to delay before popping up the WIP dialog 202 * @param {AjxCallback} cancelBusyCallback the callback to run when OK button is pressed in WIP dialog 203 */ 204 DwtShell.prototype.setBusy = 205 function(busy, id, showBusyDialog, busyDialogDelay, cancelBusyCallback) { 206 if (busy) { 207 this._setBusyCount++; 208 } else if (this._setBusyCount > 0) { 209 this._setBusyCount--; 210 } 211 212 if (!this._setBusy && (this._setBusyCount > 0)) { 213 // transition from non-busy to busy state 214 Dwt.setCursor(this._busyOverlay, "wait"); 215 Dwt.setVisible(this._busyOverlay, true); 216 this._setBusy = this._blockInput = true; 217 DBG.println(AjxDebug.DBG2, "set busy overlay, id = " + id); 218 } else if (this._setBusy && (this._setBusyCount <= 0)) { 219 // transition from busy to non-busy state 220 Dwt.setCursor(this._busyOverlay, "default"); 221 Dwt.setVisible(this._busyOverlay, false); 222 this._setBusy = this._blockInput = false; 223 DBG.println(AjxDebug.DBG2, "remove busy overlay, id = " + id); 224 } 225 226 // handle busy dialog whether we've changed state or not 227 if (busy && showBusyDialog) { 228 if (busyDialogDelay && busyDialogDelay > 0) { 229 this._busyActionId[id] = AjxTimedAction.scheduleAction(this._busyTimedAction, busyDialogDelay); 230 } else { 231 this._showBusyDialogAction(id); 232 } 233 234 this._cancelBusyCallback = cancelBusyCallback; 235 if (this._busyDialog) { 236 this._busyDialog.setButtonEnabled(DwtShell.CANCEL_BUTTON, (cancelBusyCallback != null)); 237 } 238 } else { 239 if (this._busyActionId[id] && (this._busyActionId[id] != -1)) { 240 AjxTimedAction.cancelAction(this._busyActionId[id]); 241 this._busyActionId[id] = -1; 242 } 243 if (this._busyDialog && this._busyDialog.isPoppedUp) { 244 this._busyDialog.popdown(); 245 } 246 } 247 } 248 249 // (hee hee) 250 DwtShell.prototype.getBusy = 251 function() { 252 return this._setBusy; 253 }; 254 255 /** 256 * Sets the text for the shell busy dialog 257 * 258 * @param {string} text the text to set (may be HTML) 259 */ 260 DwtShell.prototype.setBusyDialogText = 261 function(text) { 262 this._busyDialogText = text; 263 if (this._busyDialogTxt) { 264 this._busyDialogTxt.innerHTML = (text) ? text : ""; 265 } 266 } 267 268 /** 269 * Sets the shell busy dialog title. 270 * 271 * @param {string} title the title text 272 */ 273 DwtShell.prototype.setBusyDialogTitle = 274 function(title) { 275 this._busyDialogTitle = title; 276 if (this._busyDialog) { 277 this._busyDialog.setTitle((title) ? title : AjxMsg.workInProgress); 278 } 279 } 280 281 DwtShell.prototype.getHoverMgr = 282 function() { 283 return this._hoverMgr; 284 } 285 286 /** 287 * Gets the tool tip. 288 * 289 * @return {string} the tool tip 290 */ 291 DwtShell.prototype.getToolTip = 292 function() { 293 return this._toolTip; 294 } 295 296 DwtShell.prototype.getH = 297 function(incScroll) { 298 return (!this._virtual) ? Dwt.getSize(this.getHtmlElement(), incScroll).y 299 : Dwt.getSize(document.body, incScroll).y; 300 } 301 302 DwtShell.prototype.getW = 303 function(incScroll) { 304 return (!this._virtual) ? Dwt.getSize(this.getHtmlElement(), incScroll).x 305 : Dwt.getSize(document.body, incScroll).x; 306 } 307 308 DwtShell.prototype.getSize = 309 function(incScroll) { 310 return (!this._virtual) ? Dwt.getSize(this.getHtmlElement(), incScroll) 311 : Dwt.getSize(document.body, incScroll); 312 } 313 314 DwtShell.prototype.getLocation = 315 function() { 316 return (!this._virtual) ? Dwt.getLocation(this.getHtmlElement()) 317 : Dwt.getLocation(document.body); 318 } 319 320 DwtShell.prototype.getX = 321 function() { 322 return (!this._virtual) ? Dwt.getLocation(this.getHtmlElement()).x 323 : Dwt.getLocation(document.body).x; 324 } 325 326 DwtShell.prototype.getY = 327 function() { 328 return (!this._virtual) ? Dwt.getLocation(this.getHtmlElement()).y 329 : Dwt.getLocation(document.body).y; 330 } 331 332 333 DwtShell.prototype.getBounds = 334 function(incScroll) { 335 return (!this._virtual) ? Dwt.getBounds(this.getHtmlElement(), incScroll) 336 : Dwt.getBounds(document.body, incScroll); 337 } 338 339 /** 340 * If the shell is set as a virtual shell, then all children that are 341 * directly added to the shell become children on the page's body element. This 342 * is useful in the cases where Dwt is to beused with existing HTML documents 343 * rather than as the foundation for an application. 344 * 345 * @private 346 */ 347 DwtShell.prototype.setVirtual = 348 function() { 349 this._virtual = true; 350 this.setVisible(false); 351 } 352 353 /** 354 * Adds a focus listener. 355 * 356 * @param {AjxListener} listener the listener 357 */ 358 DwtShell.prototype.addFocusListener = 359 function(listener) { 360 if (!this._hasFocusHandler) { 361 var doc = document; 362 if ((typeof doc.onfocusin != "undefined" ) && doc.attachEvent) { // if (IE) 363 doc.attachEvent("onfocusin", DwtShell.__focusHdlr); 364 } else if (window.addEventListener) { 365 window.addEventListener("focus", DwtShell.__focusHdlr, false); 366 } 367 this._hasFocusHandler = true; 368 } 369 this.addListener(DwtEvent.ONFOCUS, listener); 370 }; 371 372 /** 373 * Adds a blur listener. 374 * 375 * @param {AjxListener} listener the listener 376 */ 377 DwtShell.prototype.addBlurListener = 378 function(listener) { 379 if (!this._hasBlurHandler) { 380 var doc = document; 381 if ((typeof doc.onfocusin != "undefined" ) && doc.attachEvent) { // if (IE) 382 doc.attachEvent("onfocusout", DwtShell.__blurHdlr); 383 } else if (window.addEventListener) { 384 window.addEventListener("blur", DwtShell.__blurHdlr, false); 385 } 386 this._hasBlurHandler = true; 387 } 388 this.addListener(DwtEvent.ONBLUR, listener); 389 }; 390 391 /** 392 * Adds a global selection listener. 393 * 394 * @param {AjxListener} listener the listener 395 */ 396 DwtShell.prototype.addGlobalSelectionListener = 397 function(listener) { 398 this.addListener(DwtShell._GLOBAL_SELECTION, listener); 399 }; 400 401 /** 402 * Removes a global selection listener. 403 * 404 * @param {AjxListener} listener the listener 405 */ 406 DwtShell.prototype.removeGlobalSelectionListener = 407 function(listener) { 408 this.removeListener(DwtShell._GLOBAL_SELECTION, listener); 409 }; 410 411 DwtShell.prototype.notifyGlobalSelection = 412 function(event) { 413 this.notifyListeners(DwtShell._GLOBAL_SELECTION, event); 414 }; 415 416 /** 417 * @return {boolean} <code>true</code> if the shell is virtual 418 * 419 * @private 420 */ 421 DwtShell.prototype.isVirtual = 422 function() { 423 return this._virtual; 424 } 425 426 427 // Private / protected methods 428 429 DwtShell.prototype._showBusyDialogAction = 430 function(id) { 431 var bd = this._getBusyDialog(); 432 bd.popup(); 433 this._busyActionId[id] = -1; 434 } 435 436 DwtShell.prototype._createBusyOverlay = 437 function(htmlElement) { 438 this._busyOverlay = document.createElement("div"); 439 this._busyOverlay.className = (!AjxEnv.isLinux) ? "BusyOverlay" : "BusyOverlay-linux"; 440 this._busyOverlay.style.position = "absolute"; 441 Dwt.setBounds(this._busyOverlay, 0, 0, "100%", "100%") 442 Dwt.setZIndex(this._busyOverlay, Dwt.Z_VEIL); 443 this._busyOverlay.innerHTML = "<table cellspacing=0 cellpadding=0 style='width:100%; height:100%'><tr><td> </td></tr></table>"; 444 htmlElement.appendChild(this._busyOverlay); 445 Dwt.setVisible(this._busyOverlay, false); 446 447 this._busyTimedAction = new AjxTimedAction(this, this._showBusyDialogAction); 448 this._busyActionId = {}; 449 450 this._setBusyCount = 0; 451 this._setBusy = false; 452 } 453 454 DwtShell.prototype._getBusyDialog = 455 function(htmlElement) { 456 if (!this._busyDialog) { 457 var cancelButton = new DwtDialog_ButtonDescriptor(DwtShell.CANCEL_BUTTON, AjxMsg.cancelRequest, DwtDialog.ALIGN_CENTER); 458 this._busyDialog = new DwtDialog({parent:this, className:"DwtShellBusyDialog", title:AjxMsg.workInProgress, 459 standardButtons:DwtDialog.NO_BUTTONS, extraButtons:[cancelButton], zIndex:Dwt.BUSY + 10}); 460 this._busyDialog.registerCallback(DwtShell.CANCEL_BUTTON, this._busyCancelButtonListener, this); 461 var txtId = Dwt.getNextId(); 462 var html = [ 463 "<table class='DialogContent'><tr>", 464 "<td><div class='WaitIcon'></div></td><td class='MsgText' id='", txtId, "'> </td>", 465 "</tr></table>"].join(""); 466 467 this._busyDialog.setContent(html); 468 this._busyDialogTxt = document.getElementById(txtId); 469 if (this._busyDialogText) { 470 this._busyDialogTxt.innerHTML = this._busyDialogText; 471 } 472 if (this._busyDialogTitle) { 473 this._busyDialog.setTitle(this._busyDialogTitle); 474 } 475 this._busyDialog.setButtonEnabled(DwtShell.CANCEL_BUTTON, (this._cancelBusyCallback != null)); 476 } 477 return this._busyDialog; 478 }; 479 480 /** 481 * 482 * Relayout user skin elements. Called whenever hiding or showing a 483 * part of the user skin, or when resizing the window. 484 * 485 * The layout works on elements of class "skin_layout_filler" -- which 486 * must also be of either class "skin_layout_row" or 487 * "skin_layout_cell". It finds the size of our parent, subtract the 488 * sizes all sibling rows or cells (excluding other fillers) and 489 * divide the remaining size between this filler and any sibling 490 * fillers. 491 */ 492 DwtShell.prototype.relayout = 493 function() { 494 this._currWinSize = Dwt.getWindowSize(); 495 496 if (this._userShell) { 497 var fillers = Dwt.byClassName('skin_layout_filler', this._userShell); 498 499 AjxUtil.foreach(fillers, function(elem) { 500 if (Dwt.hasClass(elem, 'skin_layout_row')) { 501 var row = elem; 502 var table = row.parentNode; 503 var height = Dwt.getSize(table).y; 504 var nfillers = 0; 505 506 var insets = Dwt.getInsets(table); 507 height -= insets.top + insets.bottom; 508 var margins = Dwt.getMargins(row); 509 height -= margins.top + margins.bottom; 510 511 AjxUtil.foreach(table.children, function(otherrow) { 512 var margins = Dwt.getMargins(otherrow); 513 height -= margins.top + margins.bottom; 514 515 if (Dwt.hasClass(otherrow, 'skin_layout_filler')) { 516 nfillers += 1; 517 } else { 518 var otherheight = Dwt.getSize(otherrow).y; 519 520 AjxUtil.foreach(otherrow.children, function(cell) { 521 var margins = Dwt.getMargins(cell); 522 var height = Dwt.getSize(cell).y + 523 margins.top + margins.bottom; 524 otherheight = Math.max(otherheight, height); 525 }); 526 527 height -= otherheight; 528 } 529 }); 530 531 row.style.height = Math.max(height / nfillers, 0) + 'px'; 532 533 } else if (Dwt.hasClass(elem, 'skin_layout_cell')) { 534 var cell = elem; 535 var row = cell.parentNode; 536 var table = row.parentNode; 537 var width = Dwt.getSize(table).x; 538 var nfillers = 0; 539 540 var insets = Dwt.getInsets(table); 541 width -= insets.left + insets.right; 542 var margins = Dwt.getMargins(row); 543 width -= margins.left + margins.right; 544 545 AjxUtil.foreach(row.children, function(othercell) { 546 var margins = Dwt.getMargins(othercell); 547 width -= margins.left + margins.right; 548 549 if (Dwt.hasClass(othercell, 'skin_layout_filler')) { 550 nfillers += 1; 551 } else { 552 553 if (cell.id === "skin_td_main" && othercell.id === "skin_td_tree_app_sash" && 554 AjxEnv.isChrome && !AjxUtil.isInt(window.devicePixelRatio)) { 555 // See bug #96808. 556 // Chrome seems to change the hardcoded pixel value. 557 // Depending on the zoom level it fluctuates +/- 1. This messes up elements' width calculation. 558 // The problematic element is #skin_td_tree_app_sash when calculating width for #skin_td_main. 559 // The value of sash's width is set in skins. 560 // Decreasing the width by 3 works on all zoom levels. 561 // Only do this on non-integer devicePixelRatio 562 // (e.g. skip 100% zoom on retina and non-retina displays where devicePixelRatio is 2 and 1). 563 width -= 3; 564 } 565 566 width -= Dwt.getSize(othercell).x; 567 } 568 }); 569 570 cell.style.width = Math.max(width / nfillers, 0) + 'px'; 571 572 } else if (window.console) { 573 console.warn('not fixing sizes for element!', elem); 574 } 575 }); 576 } 577 }; 578 579 // Listeners 580 581 DwtShell.prototype._busyCancelButtonListener = 582 function(ev) { 583 this._cancelBusyCallback.run(); 584 if (this._busyDialog) { 585 this._busyDialog.popdown(); 586 } 587 } 588 589 590 // Static methods 591 592 DwtShell._preventDefaultSelectPrt = 593 function(ev) { 594 var evt = DwtControl.fromElementId(window._dwtShellId)._uiEvent; 595 evt.setFromDhtmlEvent(ev, true); 596 597 if (evt.dwtObj && evt.dwtObj instanceof DwtControl && !evt.dwtObj.preventSelection(evt.target)) { 598 evt._stopPropagation = false; 599 evt._returnValue = true; 600 } else { 601 evt._stopPropagation = true; 602 evt._returnValue = false; 603 } 604 evt.setToDhtmlEvent(ev); 605 return !evt._stopPropagation; 606 }; 607 608 DwtShell._preventDefaultPrt = 609 function(ev) { 610 ev = DwtUiEvent.getEvent(ev); 611 var target = ev.target ? ev.target : ev.srcElement; 612 613 var evt = DwtControl.fromElementId(window._dwtShellId)._uiEvent; 614 evt.setFromDhtmlEvent(ev, true); 615 //default behavior 616 evt._stopPropagation = true; 617 evt._returnValue = false; 618 if (evt.dwtObj && evt.dwtObj instanceof DwtControl && !evt.dwtObj.preventContextMenu(evt.target)) { 619 evt._stopPropagation = false; 620 evt._returnValue = true; 621 } else if (target != null && typeof(target) == 'object') { 622 if ((target.tagName == "A" || target.tagName == "a") && target.href) { 623 evt._stopPropagation = false; 624 evt._returnValue = true; 625 } 626 } 627 628 evt.setToDhtmlEvent(ev); 629 return evt._returnValue; 630 }; 631 632 633 /* This the resize handler to track when the browser window size changes */ 634 DwtShell._resizeHdlr = 635 function(ev) { 636 var shell = DwtControl.fromElementId(window._dwtShellId); 637 if (shell.isListenerRegistered(DwtEvent.CONTROL)) { 638 var evt = DwtShell.controlEvent; 639 evt.reset(); 640 evt.oldWidth = shell._currWinSize.x; 641 evt.oldHeight = shell._currWinSize.y; 642 shell.relayout(); 643 evt.newWidth = shell._currWinSize.x; 644 evt.newHeight = shell._currWinSize.y; 645 shell.notifyListeners(DwtEvent.CONTROL, evt); 646 } else { 647 shell.relayout(); 648 } 649 }; 650 651 DwtShell.__onBodyScroll = function() { 652 // alert(document.body.scrollTop + "/" + document.body.scrollLeft); 653 document.body.scrollTop = 0; 654 document.body.scrollLeft = 0; 655 // DwtShell._resizeHdlr(); 656 }; 657 658 DwtShell.__focusHdlr = 659 function() { 660 var focusEvent = DwtShell.focusEvent; 661 var self = DwtShell.getShell(window); 662 focusEvent.dwtObj = self; 663 focusEvent.state = DwtFocusEvent.FOCUS; 664 self.notifyListeners(DwtEvent.ONFOCUS, focusEvent); 665 }; 666 667 DwtShell.__blurHdlr = 668 function() { 669 var focusEvent = DwtShell.focusEvent; 670 var self = DwtShell.getShell(window); 671 focusEvent.dwtObj = self; 672 focusEvent.state = DwtFocusEvent.BLUR; 673 self.notifyListeners(DwtEvent.ONBLUR, focusEvent); 674 }; 675