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 * Default constructor. 26 * @constructor 27 * @class 28 * Dwt is a static class that defines a number of constants and helper methods that 29 * support the <code>ajax.dwt.*</code> package. 30 * 31 * @author Ross Dargahi 32 * @author Conrad Damon 33 */ 34 35 Dwt = function() { 36 }; 37 38 // Constants for positioning 39 /** 40 * Static position style. 41 */ 42 Dwt.STATIC_STYLE = "static"; 43 44 /** 45 * Absolute position style. 46 */ 47 Dwt.ABSOLUTE_STYLE = "absolute"; 48 49 /** 50 * Relative position style. 51 */ 52 Dwt.RELATIVE_STYLE = "relative"; 53 54 /** 55 * Fixed position style. 56 */ 57 Dwt.FIXED_STYLE = "fixed"; 58 59 // Background repeat 60 /** 61 * Do not repeat background image. 62 */ 63 Dwt.NO_REPEAT = "no-repeat"; 64 65 /** 66 * Repeat background image. 67 */ 68 Dwt.REPEAT = "repeat"; 69 70 /** 71 * Repeat background image horizontally. 72 */ 73 Dwt.REPEAT_X = "repeat-x"; 74 75 /** 76 * Repeat background image vertically. 77 */ 78 Dwt.REPEAT_Y = "repeat-y"; 79 80 81 // display style 82 /** 83 * Inline display style. 84 */ 85 Dwt.DISPLAY_INLINE = "inline"; 86 87 /** 88 * Block display style. 89 */ 90 Dwt.DISPLAY_BLOCK = "block"; 91 92 /** 93 * No display style. 94 */ 95 Dwt.DISPLAY_NONE = "none"; 96 97 /** 98 * Table row style. 99 */ 100 Dwt.DISPLAY_TABLE_ROW = "table-row"; 101 102 /** 103 * Table cell style. 104 */ 105 Dwt.DISPLAY_TABLE_CELL = "table-cell"; 106 107 // Scroll constants 108 /** 109 * Clip on overflow. 110 */ 111 Dwt.CLIP = 1; 112 113 /** 114 * Allow overflow to be visible. 115 */ 116 Dwt.VISIBLE = 2; 117 118 /** 119 * Automatically create scrollbars if content overflows. 120 */ 121 Dwt.SCROLL = 3; 122 123 /** 124 * Always have scrollbars whether content overflows or not. 125 */ 126 Dwt.FIXED_SCROLL = 4; 127 128 /** 129 * Only show scrollbars on Y when content overflows. 130 */ 131 Dwt.SCROLL_Y = 5; 132 133 /** 134 * Only show scrollbars on X when content overflows. 135 */ 136 Dwt.SCROLL_X = 6; 137 138 139 // z-index order 140 /** 141 * Hidden layer. Elements at this layer will be hidden from view. 142 */ 143 Dwt.Z_HIDDEN = 100; 144 145 /** 146 * The curtain layer. 147 * @type int 148 * @see DwtShell 149 */ 150 Dwt.Z_CURTAIN = 200; 151 152 153 /** 154 * Visible layer. Elements at this layer will be in view. 155 */ 156 Dwt.Z_VIEW = 300; 157 158 /** 159 * Popup menu layer. Used by the menu components. 160 */ 161 Dwt.Z_MENU = 500; 162 163 /** 164 * Veil layer. The veil appears just behind modal dialogs render other components 165 * unable to receive mouse input. 166 */ 167 Dwt.Z_VEIL = 600; 168 169 /** 170 * Dialog layer. Dialogs are positioned at this layer. 171 */ 172 Dwt.Z_DIALOG = 700; 173 174 /** 175 * Used by menus that are part of a dialog. 176 */ 177 Dwt.Z_DIALOG_MENU = 750; 178 179 /** 180 * Tooltips layer. 181 */ 182 Dwt.Z_TOOLTIP = 775; 183 184 /** 185 * Drag and Drop (DnD) icon layer. DnD icons are positioned at this layer so they 186 * move across the top of other components. 187 */ 188 Dwt.Z_DND = 800; // Drag N Drop icons 189 190 /** 191 * This layer appears in front of other layers to block all user mouse input. 192 */ 193 Dwt.Z_BUSY = 900; 194 195 /** 196 * The toast layer. 197 */ 198 Dwt.Z_TOAST = 950; 199 200 /** 201 * Used by the splash screens. 202 */ 203 Dwt.Z_SPLASH = 1000; 204 205 206 /** 207 * Default value. Used when setting such things as size and bounds to indicate a 208 * component should not be set. For example if setting size and not wishing to set 209 * the height. 210 * <pre> 211 * Dwt.setSize(htmlElement, 100, Dwt.DEFAULT) 212 * </pre> 213 * 214 */ 215 Dwt.DEFAULT = -123456789; 216 217 /** 218 * Used to clear a value. 219 */ 220 Dwt.CLEAR = -20000; 221 222 /** 223 * Offscreen position. Used when setting a elements position. 224 */ 225 Dwt.LOC_NOWHERE = -10000; 226 227 // Drag N Drop action constants. These are bit fields. 228 /** 229 * No drag and drop operation. 230 */ 231 Dwt.DND_DROP_NONE = 0; 232 233 /** 234 * Copy drag and drop operation. 235 */ 236 Dwt.DND_DROP_COPY = 1; 237 238 /** 239 * Move drag and drop operation. 240 */ 241 Dwt.DND_DROP_MOVE = 2; 242 243 /** 244 * Ballpark figure for width of a scrollbar. 245 */ 246 Dwt.SCROLLBAR_WIDTH = 22; 247 248 // Editor formats 249 Dwt.HTML = "text/html"; 250 Dwt.TEXT = "text/plain"; 251 252 // Keys used for retrieving data 253 // TODO JSDoc 254 Dwt.KEY_OBJECT = "_object_"; 255 Dwt.KEY_ID = "_id_"; 256 257 /** 258 * z-index increment unit. Used by components if they need to bump their z-index. 259 */ 260 Dwt._Z_INC = 1; 261 262 263 /** 264 * @private 265 */ 266 Dwt.__nextId = {}; 267 268 /** 269 * This method is used to generate a unique id to be used for an HTML element's id 270 * attribute. 271 * 272 * @return {string} the next available element ID 273 */ 274 Dwt.getNextId = 275 function(prefix) { 276 prefix = prefix || "DWT"; 277 if (!Dwt.__nextId[prefix]) { 278 Dwt.__nextId[prefix] = 1; 279 } 280 return prefix + Dwt.__nextId[prefix]++; 281 }; 282 283 /** 284 * This method is used to query an element for its id, generating one if it 285 * isn't set. 286 * 287 * @return {string} the element ID 288 */ 289 Dwt.getId = 290 function(element, prefix) { 291 return element ? element.id || (element.id = Dwt.getNextId(prefix)) : null; 292 }; 293 294 /** 295 * @deprecated 296 * The association between an element and a control is now via DwtControl.ALL_BY_ID, 297 * where the unique element ID is a key to the control. The association is made when 298 * the control is initialized. 299 * 300 * This method builds an indirect association between a DOM object and a JavaScript 301 * object. This indirection is important to prevent memory leaks (particularly in IE) by 302 * not directly creating a circular reference between a DOM object 303 * 304 * @param {DOMElement} domElement the DOM element (typically an HTML element) 305 * @param {Object} jsObject the JavaScript object 306 * 307 * @private 308 */ 309 Dwt.associateElementWithObject = 310 function(domElement, jsObject, attrName) { 311 domElement[attrName||"dwtObj"] = jsObject.__internalId = AjxCore.assignId(jsObject); 312 }; 313 314 /** 315 * @deprecated 316 * The association will be broken by the control when it is disposed. 317 * 318 * This method breaks the indirect association between a DOM object and a JavaScript 319 * object that was created by the <code>Dwt.associateElementWithObject</code>method 320 * 321 * @param {DOMElement} domElement the DOM element (typically an HTML element) 322 * @param {Object} jsObject the JavaScript object 323 * 324 * @private 325 */ 326 Dwt.disassociateElementFromObject = 327 function(domElement, jsObject, attrName) { 328 if (domElement){ 329 domElement.removeAttribute(attrName||"dwtObj"); 330 } 331 if (jsObject.__internalId){ 332 AjxCore.unassignId(jsObject.__internalId); 333 } 334 }; 335 336 /** 337 * @deprecated use {@link DwtControl.fromElement} 338 * 339 * @private 340 */ 341 Dwt.getObjectFromElement = 342 function(domElement, attrName) { 343 return AjxCore.objectWithId(domElement[attrName||"dwtObj"]); 344 }; 345 346 Dwt.getElement = 347 function(el) { 348 return (typeof(el) == "string") ? document.getElementById(el) : el; 349 }; 350 351 /** 352 * Finds an ancestor element with a non-empty value for the given attr. 353 * 354 * @param {DOMElement} domElement the starting DOM element 355 * @param {string} attrName the attribute name 356 * 357 * @return {DOMElement} the DOM element 358 */ 359 Dwt.findAncestor = 360 function(domElement, attrName) { 361 var attr = Dwt.getAttr(domElement, attrName); 362 while (domElement && (attr == null || attr == "")) { 363 domElement = domElement.parentNode; 364 attr = Dwt.getAttr(domElement, attrName); 365 } 366 return domElement; 367 }; 368 369 /** 370 * Returns true if el1 is an ancestor (in the parent chain) of el2, or if 371 * el1 and el2 are the same element. 372 * 373 * @param {DOMElement} el1 374 * @param {DOMElement} el2 375 */ 376 Dwt.isAncestor = 377 function(el1, el2) { 378 379 if (el1 == el2) { 380 return true; 381 } 382 383 var el = el2; 384 while (el) { 385 el = el.parentNode; 386 if (el == el1) { 387 return true; 388 } 389 } 390 return false; 391 }; 392 393 Dwt.setHandler = 394 function(htmlElement, event, func) { 395 if (!(htmlElement = Dwt.getElement(htmlElement))) { return; } 396 if (event == DwtEvent.ONMOUSEWHEEL && AjxEnv.isGeckoBased) { 397 Dwt.clearHandler(htmlElement, event); 398 } 399 htmlElement[event] = func; 400 if (event == DwtEvent.ONMOUSEWHEEL && AjxEnv.isGeckoBased) { 401 htmlElement.addEventListener("DOMMouseScroll", func, true); 402 } 403 }; 404 405 Dwt.clearHandler = 406 function(htmlElement, event) { 407 if (!(htmlElement = Dwt.getElement(htmlElement))) { return; } 408 if (event == DwtEvent.ONMOUSEWHEEL && AjxEnv.isGeckoBased) { 409 if (htmlElement[event]) { 410 var func = htmlElement[event]; 411 htmlElement.removeEventListener("DOMMouseScroll", func, true); 412 } 413 } 414 htmlElement[event] = null; 415 }; 416 417 Dwt.getBackgroundRepeat = 418 function(htmlElement) { 419 if (!(htmlElement = Dwt.getElement(htmlElement))) { return; } 420 return DwtCssStyle.getProperty(htmlElement, "background-repeat"); 421 }; 422 423 Dwt.setBackgroundRepeat = 424 function(htmlElement, style) { 425 if (!(htmlElement = Dwt.getElement(htmlElement))) { return; } 426 htmlElement.style.backgroundRepeat = style; 427 }; 428 429 /** 430 * Gets the bounds of an HTML element. 431 * 432 * @param {HTMLElement} htmlElement the HTML element 433 * 434 * @return {DwtRectangle} the elements bounds 435 * 436 * @see #setBounds 437 * @see #getInsetBounds 438 * @see #getLocation 439 * @see #getSize 440 */ 441 Dwt.getBounds = 442 function(htmlElement, rect) { 443 if (!(htmlElement = Dwt.getElement(htmlElement))) { return null; } 444 var tmpPt = DwtPoint.tmp; 445 446 Dwt.getLocation(htmlElement, tmpPt); 447 var locX = tmpPt.x; 448 var locY = tmpPt.y; 449 450 Dwt.getSize(htmlElement, tmpPt); 451 452 if (!rect) { 453 return new DwtRectangle(locX, locY, tmpPt.x, tmpPt.y); 454 } else { 455 rect.set(locX, locY, tmpPt.x, tmpPt.y); 456 return rect; 457 } 458 }; 459 460 /** 461 * Sets the bounds of an HTML element. The position type of the element must 462 * be absolute or else an exception is thrown. To omit setting a value set the 463 * actual parameter value to <i>Dwt.DEFAULT</i> 464 * 465 * @param {HTMLElement} htmlElement absolutely positioned HTML element 466 * @param {number|string} x the x coordinate of the element (for example: 10, "10px", {@link Dwt.DEFAULT}) 467 * @param {number|string} y the y coordinate of the element (for example: 10, "10px", {@link Dwt.DEFAULT}) 468 * @param {number} width the width of the element (for example: 100, "100px", "75%", {@link Dwt.DEFAULT}) 469 * @param {number} height the height of the element (for example: 100, "100px", "75%", {@link Dwt.DEFAULT}) 470 * 471 * @throws DwtException 472 * 473 * @see #getBounds 474 * @see #setLocation 475 * @see #setSize 476 */ 477 Dwt.setBounds = 478 function(htmlElement, x, y, width, height) { 479 if (!(htmlElement = Dwt.getElement(htmlElement))) { return; } 480 Dwt.setLocation(htmlElement, x, y); 481 Dwt.setSize(htmlElement, width, height); 482 }; 483 484 /** 485 * Gets the element cursor for a given HTML element. 486 * 487 * @param {HTMLElement} htmlElement the HTML element 488 * 489 * @return {string} the html elements cursor 490 * 491 * @see #setCursor 492 */ 493 Dwt.getCursor = 494 function(htmlElement) { 495 if (!(htmlElement = Dwt.getElement(htmlElement))) { return ""; } 496 return DwtCssStyle.getProperty(htmlElement, "cursor"); 497 }; 498 499 /** 500 * Sets an HTML element cursor. 501 * 502 * @param {HTMLElement} htmlElement the element for which to set the cursor 503 * @param {string} cursorName name of the new cursor 504 * 505 * @see #setCursor 506 */ 507 Dwt.setCursor = 508 function(htmlElement, cursorName) { 509 if (!(htmlElement = Dwt.getElement(htmlElement))) { return; } 510 htmlElement.style.cursor = cursorName; 511 }; 512 513 /** 514 * Gets the location of an HTML element. 515 * 516 * @param {HTMLElement} htmlElement the HTML element 517 * 518 * @return {DwtPoint} the location of the HTML element 519 * 520 * @see #setLocation 521 * @see #getBounds 522 * @see #getSize 523 */ 524 Dwt.getLocation = 525 function(htmlElement, point) { 526 if (!(htmlElement = Dwt.getElement(htmlElement))) { return null; } 527 point = point || new DwtPoint(0, 0); 528 529 if (htmlElement.style.position == Dwt.ABSOLUTE_STYLE) { 530 // parseInt will return NaN if "top" or "left" is "auto" or not set. 531 // TODO: We should test for that and just go to toWindow in that case. 532 point.set(parseInt(DwtCssStyle.getProperty(htmlElement, "left")), 533 parseInt(DwtCssStyle.getProperty(htmlElement, "top"))); 534 return point; 535 } 536 537 return Dwt.toWindow(htmlElement, 0, 0, null, null, point); 538 }; 539 540 /** 541 * Sets the location of an HTML element. The position type of the element must 542 * be absolute or else an exception is thrown. To only set one of the coordinates, 543 * pass in a value of {@link Dwt.DEFAULT} for the coordinate for which the value is 544 * not to be set 545 * 546 * @param {HTMLElement} htmlElement the absolutely positioned HTML element 547 * @param {number|string} x the x coordinate of the element (for example: 10, "10px", {@link Dwt.DEFAULT}) 548 * @param {number|string} y the y coordinate of the element (for example: 10, "10px", {@link Dwt.DEFAULT}) 549 * 550 * @throws DwtException 551 * 552 * @see #getLocation 553 * @see #setBounds 554 * @see #setSize 555 */ 556 Dwt.setLocation = 557 function(htmlElement, x, y) { 558 if (!(htmlElement = Dwt.getElement(htmlElement))) { return; } 559 var position = DwtCssStyle.getProperty(htmlElement, 'position'); 560 if (position != Dwt.ABSOLUTE_STYLE && position != Dwt.RELATIVE_STYLE && position != Dwt.FIXED_STYLE) { 561 DBG.println(AjxDebug.DBG1, "Cannot position static widget " + htmlElement.className); 562 throw new DwtException("Static widgets may not be positioned", DwtException.INVALID_OP, "Dwt.setLocation"); 563 } 564 if (x = Dwt.__checkPxVal(x)) { 565 htmlElement.style.left = x; 566 } 567 if (y = Dwt.__checkPxVal(y)) { 568 htmlElement.style.top = y; 569 } 570 }; 571 572 Dwt.getPosition = 573 function(htmlElement) { 574 if (!(htmlElement = Dwt.getElement(htmlElement))) { return; } 575 return htmlElement.style.position; 576 }; 577 578 Dwt.setPosition = 579 function(htmlElement, posStyle) { 580 if (!(htmlElement = Dwt.getElement(htmlElement))) { return; } 581 htmlElement.style.position = posStyle; 582 }; 583 584 /** 585 * Returns <code>htmlElement</code>'s scroll style. The scroll style determines the element's 586 * behaviour when content overflows its boundaries. Possible values are: 587 * <ul> 588 * <li><i>Dwt.CLIP</i> - Clip on overflow</li> 589 * <li><i>Dwt.VISIBLE</i> - Allow overflow to be visible</li> 590 * <li><i>Dwt.SCROLL</i> - Automatically create scrollbars if content overflows</li> 591 * <li><i>Dwt.FIXED_SCROLL</i> - Always have scrollbars whether content overflows or not</li> 592 * </ul> 593 * 594 * @param {HTMLElement} htmlElement HTML element 595 * 596 * @return {Dwt.CLIP|Dwt.VISIBLE|Dwt.SCROLL|Dwt.FIXED_SCROLL} the elements scroll style 597 */ 598 Dwt.getScrollStyle = 599 function(htmlElement) { 600 if (!(htmlElement = Dwt.getElement(htmlElement))) { return ""; } 601 var overflow = DwtCssStyle.getProperty(htmlElement, "overflow"); 602 603 if (overflow == "hidden") { return Dwt.CLIP; } 604 if (overflow =="auto") { return Dwt.SCROLL; } 605 if (overflow =="scroll") { return Dwt.FIXED_SCROLL; } 606 607 if (overflow == '') { 608 var overflowX = DwtCssStyle.getProperty(htmlElement, "overflowX"); 609 var overflowY = DwtCssStyle.getProperty(htmlElement, "overflowY"); 610 611 if (overflowX == 'scroll') { return Dwt.SCROLL_X; } 612 if (overflowY == 'scroll') { return Dwt.SCROLL_Y; } 613 } 614 return Dwt.VISIBLE; 615 }; 616 617 /** 618 * Sets the <code>htmlElement</code>'s scroll style. The scroll style determines the elements's 619 * behaviour when content overflows its div's boundaries. Possible values are: 620 * <ul> 621 * <li><i>Dwt.CLIP</i> - Clip on overflow</li> 622 * <li><i>Dwt.VISIBLE</i> - Allow overflow to be visible</li> 623 * <li><i>Dwt.SCROLL</i> - Automatically create scrollbars if content overflows</li> 624 * <li><i>Dwt.FIXED_SCROLL</i> - Always have scrollbars whether content overflows or not</li> 625 * </ul> 626 * 627 * @param {HTMLElement} htmlElement HTML element 628 * @param {Dwt.CLIP|Dwt.VISIBLE|Dwt.SCROLL|Dwt.FIXED_SCROLL} scrollStyle the elements scroll style 629 */ 630 Dwt.setScrollStyle = 631 function(htmlElement, scrollStyle) { 632 if (!(htmlElement = Dwt.getElement(htmlElement))) { return; } 633 if (scrollStyle == Dwt.CLIP) 634 htmlElement.style.overflow = "hidden"; 635 else if (scrollStyle == Dwt.SCROLL) 636 htmlElement.style.overflow = "auto"; 637 else if (scrollStyle == Dwt.FIXED_SCROLL) 638 htmlElement.style.overflow = "scroll"; 639 else if (scrollStyle == Dwt.SCROLL_Y) { 640 htmlElement.style.overflowX = "hidden"; 641 htmlElement.style.overflowY = "auto"; 642 } else if (scrollStyle == Dwt.SCROLL_X) { 643 htmlElement.style.overflowY = "hidden"; 644 htmlElement.style.overflowX = "auto"; 645 } else { 646 htmlElement.style.overflow = "visible"; 647 } 648 }; 649 650 651 /** 652 * Gets the size of an HTML element. Normally, this yields the 653 * calculated size of the element. However, if 'getFromStyle' is 654 * true, the style is obtained directly from the CSS style. 655 * 656 * @param {HTMLElement} htmlElement the HTML element 657 * @param {DwtPoint} point if given, reuse this point 658 * @param {Boolean} getFromStyle whether to use the calculated size 659 * 660 * @return {DwtPoint} the elements size, margins included 661 * 662 * @see #getBounds 663 * @see #setBounds 664 * @see #getInsetBounds 665 * @see #getLocation 666 * @see #getOuterSize 667 */ 668 Dwt.getSize = 669 function(htmlElement, point, getFromStyle) { 670 // Note: in FireFox, offsetHeight includes border and clientHeight does not; 671 // may want to look at clientHeight for FF 672 673 if (!(htmlElement = Dwt.getElement(htmlElement))) { return; } 674 var p; 675 if (!point) { 676 p = new DwtPoint(0, 0); 677 } else { 678 p = point; 679 p.set(0, 0); 680 } 681 682 if (!htmlElement) { return p; } 683 684 if (getFromStyle) { 685 if (htmlElement.style.width) { //assumption - the caller only cares about the dimension that is set via the style. So ok to keep 0 if it's not set. for simplicity. 686 p.x = parseInt(htmlElement.style.width); 687 } 688 if (htmlElement.style.height) { 689 p.y = parseInt(htmlElement.style.height); 690 } 691 692 return p; 693 } 694 695 p.x = htmlElement.offsetWidth; 696 if (p.x != null) { 697 p.y = htmlElement.offsetHeight; 698 } else if (htmlElement.clip && htmlElement.clip.width != null) { 699 p.x = parseInt(htmlElement.clip.width); 700 p.y = parseInt(htmlElement.clip.height); 701 } else if (htmlElement.style && htmlElement.style.pixelWidth != null) { 702 p.x = parseInt(htmlElement.style.pixelWidth); 703 p.y = parseInt(htmlElement.style.pixelHeight); 704 } 705 706 return p; 707 }; 708 709 710 /** 711 * Gets the outer size -- that is, the size including margins, padding, and borders -- of an 712 * HTML element. 713 * 714 * @param {HTMLElement} htmlElement the HTML element 715 * 716 * @return {DwtPoint} the elements size, margins included 717 * 718 * @see #getSize 719 * @see #getBounds 720 * @see #setBounds 721 * @see #getInsetBounds 722 * @see #getLocation 723 */ 724 Dwt.getOuterSize = 725 function(htmlElement, point) { 726 var p = Dwt.getSize(htmlElement, point); 727 728 if (p && Dwt.getVisible(htmlElement)) { 729 var margins = Dwt.getMargins(htmlElement); 730 var insets = Dwt.getInsets(htmlElement); 731 p.x += margins.left + margins.right + insets.left + insets.right; 732 p.y += margins.top + margins.bottom + insets.top + insets.bottom; 733 } 734 735 return p; 736 }; 737 738 Dwt.setSize = 739 function(htmlElement, width, height) { 740 if (!(htmlElement = Dwt.getElement(htmlElement))) { return; } 741 if (!htmlElement.style) { return; } 742 743 if (width == Dwt.CLEAR) { 744 htmlElement.style.width = null; 745 } else if (width = Dwt.__checkPxVal(width, true)) { 746 htmlElement.style.width = width; 747 } 748 749 if (height == Dwt.CLEAR) { 750 htmlElement.style.height = null; 751 } else if (height = Dwt.__checkPxVal(height, true)) { 752 htmlElement.style.height = height; 753 } 754 }; 755 756 /** 757 * Measure the extent in pixels of a section of html. This is not the worlds cheapest 758 * method to invoke so do so judiciously 759 * 760 * @param {string} html the html content for which that extents are to be calculated 761 * 762 * @return {DwtPoint} the extent of the content 763 */ 764 Dwt.getHtmlExtent = 765 function(html) { 766 var div = AjxStringUtil.calcDIV(); 767 div.innerHTML = html; 768 return Dwt.getSize(div); 769 }; 770 771 Dwt.toDocumentFragment = 772 function(html, id) { 773 var div = AjxStringUtil.calcDIV(); 774 div.innerHTML = html; 775 776 var fragment = document.createDocumentFragment(); 777 var container = id && document.getElementById(id); 778 if (container) { 779 fragment.appendChild(container); 780 } 781 else { 782 for (var child = div.firstChild; child; child = div.firstChild) { 783 fragment.appendChild(child); 784 } 785 } 786 return fragment; 787 }; 788 789 Dwt.getAttr = 790 function(htmlEl, attr, recursive) { 791 // test for tagName so we dont try to eval non-html elements (i.e. document) 792 if (!recursive) { 793 return htmlEl && htmlEl.tagName 794 ? (htmlEl.getAttribute(attr) || htmlEl[attr]) 795 : null; 796 } else { 797 while (htmlEl) { 798 if (Dwt.getAttr(htmlEl, attr) != null) { 799 return htmlEl; 800 } 801 htmlEl = htmlEl.parentNode; 802 } 803 return null; 804 } 805 }; 806 807 Dwt.getVisible = 808 function(htmlElement) { 809 if (!(htmlElement = Dwt.getElement(htmlElement))) { return; } 810 var disp = DwtCssStyle.getProperty(htmlElement, "display"); 811 return (disp != Dwt.DISPLAY_NONE); 812 }; 813 814 Dwt.setVisible = 815 function(htmlElement, visible) { 816 if (!(htmlElement = Dwt.getElement(htmlElement))) { return; } 817 if (visible) { 818 if (htmlElement.nodeName.match(/tr/i)) { 819 htmlElement.style.display = Dwt.DISPLAY_TABLE_ROW; 820 } 821 else if (htmlElement.nodeName.match(/td|th/i)) { 822 htmlElement.style.display = Dwt.DISPLAY_TABLE_CELL; 823 } 824 else { 825 htmlElement.style.display = htmlElement.getAttribute("x-display") || 826 Dwt.DISPLAY_BLOCK; 827 } 828 } else { 829 var display = DwtCssStyle.getComputedStyleObject(htmlElement).display; 830 if (display != "none") { 831 htmlElement.setAttribute("x-display", display); 832 } 833 htmlElement.style.display = Dwt.DISPLAY_NONE; 834 } 835 }; 836 837 Dwt.getVisibility = 838 function(htmlElement) { 839 if (!(htmlElement = Dwt.getElement(htmlElement))) { return; } 840 var vis = DwtCssStyle.getProperty(htmlElement, "visibility"); 841 return (vis == "visible"); 842 }; 843 844 Dwt.setVisibility = 845 function(htmlElement, visible) { 846 if (!(htmlElement = Dwt.getElement(htmlElement))) { return; } 847 htmlElement.style.visibility = visible ? "visible" : "hidden"; 848 }; 849 850 Dwt.__MSIE_OPACITY_RE = /alpha\(opacity=(\d+)\)/; 851 852 Dwt.getOpacity = 853 function(htmlElement) { 854 if (!(htmlElement = Dwt.getElement(htmlElement))) { return; } 855 if (AjxEnv.isIE && !AjxEnv.isIE9up) { 856 var filter = Dwt.getIEFilter(htmlElement, "alpha"); 857 var m = Dwt.__MSIE_OPACITY_RE.exec(filter) || [ filter, "100" ]; 858 return Number(m[1]); 859 } 860 return Number(htmlElement.style.opacity || 1) * 100; 861 }; 862 863 Dwt.setOpacity = 864 function(htmlElement, opacity) { 865 if (!(htmlElement = Dwt.getElement(htmlElement))) { return; } 866 if (AjxEnv.isIE && !AjxEnv.isIE9up) { 867 var filterVal = opacity < 100 ? "alpha(opacity="+opacity+")" : ""; 868 Dwt.alterIEFilter(htmlElement, "alpha", filterVal); 869 } else { 870 htmlElement.style.opacity = opacity/100; 871 } 872 }; 873 874 875 /** 876 * Get the z-index of an element. 877 * 878 * @param {boolean} getFromStyle get the value from the style attribute of 879 * this element, or a parent 880 * 881 * @return {number} the z-index value 882 */ 883 Dwt.getZIndex = 884 function(htmlElement, getFromStyle) { 885 if (!(htmlElement = Dwt.getElement(htmlElement))) { return; } 886 887 if (getFromStyle) { 888 while (htmlElement.style.zIndex === "" && htmlElement.parentNode) { 889 htmlElement = htmlElement.parentNode; 890 } 891 892 return htmlElement.style.zIndex; 893 } 894 895 return DwtCssStyle.getProperty(htmlElement, "z-index"); 896 }; 897 898 Dwt.setZIndex = 899 function(htmlElement, idx) { 900 if (!(htmlElement = Dwt.getElement(htmlElement))) { return; } 901 htmlElement.style.zIndex = idx; 902 if (idx < Dwt.Z_VIEW) { 903 htmlElement.setAttribute('aria-hidden', true); 904 } else { 905 htmlElement.removeAttribute('aria-hidden'); 906 } 907 }; 908 909 Dwt.getDisplay = 910 function(htmlElement) { 911 DwtCssStyle.getProperty(htmlElement, "display"); 912 }; 913 914 Dwt.setDisplay = 915 function(htmlElement, value) { 916 if (!(htmlElement = Dwt.getElement(htmlElement))) { return; } 917 htmlElement.style.display = value; 918 }; 919 920 /** 921 * Gets the window size of the browser. 922 * 923 * @param {DwtPoint} point the point to hold the windows x/y size 924 * @return {DwtPoint} the point holding the window x/y size 925 */ 926 Dwt.getWindowSize = 927 function(point) { 928 var p = (!point) ? new DwtPoint(0, 0) : point; 929 if (window.innerWidth) { 930 p.x = window.innerWidth; 931 p.y = window.innerHeight; 932 } else if (AjxEnv.isIE6CSS) { 933 p.x = document.body.parentElement.clientWidth; 934 p.y = document.body.parentElement.clientHeight; 935 } else if (document.body && document.body.clientWidth) { 936 p.x = document.body.clientWidth; 937 p.y = document.body.clientHeight; 938 } 939 return p; 940 }; 941 942 Dwt.toWindow = 943 function(htmlElement, x, y, containerElement, dontIncScrollTop, point) { 944 var p; 945 if (!point) { 946 p = new DwtPoint(x, y); 947 } else { 948 p = point; 949 p.set(x, y); 950 } 951 952 htmlElement = Dwt.getElement(htmlElement); 953 var offsetParent = htmlElement; 954 while (offsetParent && offsetParent != containerElement) { 955 p.x += offsetParent.offsetLeft - offsetParent.scrollLeft; 956 p.y += offsetParent.offsetTop; 957 if (!dontIncScrollTop) { 958 var scrollTop = AjxEnv.isOpera ? offsetParent.pageYOffset : offsetParent.scrollTop; 959 if (scrollTop) { 960 p.y -= scrollTop; 961 } 962 var parentNode = offsetParent.parentNode; 963 while (parentNode != offsetParent.offsetParent && parentNode != containerElement) { 964 scrollTop = AjxEnv.isOpera ? parentNode.pageYOffset : parentNode.scrollTop; 965 if (scrollTop) { 966 p.y -= scrollTop; 967 } 968 parentNode = parentNode.parentNode; 969 } 970 } 971 offsetParent = offsetParent.offsetParent; 972 } 973 return p; 974 }; 975 976 Dwt.getInsets = function(htmlElement) { 977 // return an object with the insets (border + padding size) for each side of the element, eg: 978 // { left: 3, top:0, right:3, bottom:0 } 979 // NOTE: assumes values from computedStyle are returned in pixels!!! 980 981 if (!(htmlElement = Dwt.getElement(htmlElement))) { return; } 982 var style = DwtCssStyle.getComputedStyleObject(htmlElement); 983 984 var bl = parseInt(style.borderLeftWidth) || 0; 985 var bt = parseInt(style.borderTopWidth) || 0; 986 var br = parseInt(style.borderRightWidth) || 0; 987 var bb = parseInt(style.borderBottomWidth) || 0; 988 989 var pl = parseInt(style.paddingLeft) || 0; 990 var pt = parseInt(style.paddingTop) || 0; 991 var pr = parseInt(style.paddingRight) || 0; 992 var pb = parseInt(style.paddingBottom) || 0; 993 994 return { 995 left : bl + pl, 996 top : bt + pt, 997 right : br + pr, 998 bottom : bb + pb 999 }; 1000 }; 1001 1002 Dwt.insetBounds = function(bounds, insets) { 1003 1004 // given a 'bounds' object [from Dwt.getBounds()] 1005 // and an 'insets' object [from Dwt.getInsets()] 1006 // munge the bounds so it takes the insets into account. 1007 // Useful to get the inner dimensions of an element. 1008 if (!bounds) { 1009 return null; 1010 } 1011 1012 bounds.x += insets.left; 1013 bounds.y += insets.top; 1014 bounds.width -= insets.left + insets.right; 1015 bounds.height -= insets.top + insets.bottom; 1016 1017 return bounds; 1018 }; 1019 1020 /** 1021 * Gets the bounds of an HTML element, excluding borders and paddings. 1022 * 1023 * @param {HTMLElement} htmlElement the HTML element 1024 * 1025 * @return {DwtRectangle} the elements bounds 1026 * 1027 * @see #setBounds 1028 * @see #getInsetBounds 1029 * @see #getLocation 1030 * @see #getSize 1031 */ 1032 Dwt.getInsetBounds = function(htmlElement) { 1033 if (!(htmlElement = Dwt.getElement(htmlElement))) { return; } 1034 1035 var bounds = Dwt.getBounds(htmlElement); 1036 var insets = Dwt.getInsets(htmlElement); 1037 1038 return Dwt.insetBounds(bounds, insets); 1039 }; 1040 1041 Dwt.getMargins = function(htmlElement) { 1042 // return an object with the margins for each side of the element, eg: 1043 // { left: 3, top:0, right:3, bottom:0 } 1044 // NOTE: assumes values from computedStyle are returned in pixels!!! 1045 1046 if (!(htmlElement = Dwt.getElement(htmlElement))) { return; } 1047 var style = DwtCssStyle.getComputedStyleObject(htmlElement); 1048 1049 return { 1050 left : parseInt(style.marginLeft) || 0, 1051 top : parseInt(style.marginTop) || 0, 1052 right : parseInt(style.marginRight) || 0, 1053 bottom : parseInt(style.marginBottom) || 0 1054 }; 1055 }; 1056 1057 /** 1058 * Get ancestor elements of the given node, up to and including the given 1059 * parent node. If no parent is given, assume the root document node. If the 1060 * parent node is not an ancestor of the child, return <code>null</code>. 1061 * 1062 * @param {HTMLElement} childNode the child HTML element 1063 * @param {HTMLElement} parentNode the parent HTML element 1064 * @param {Boolean} includeChild if true, include the child itself 1065 * 1066 * @return {Array} a list of HTML elements 1067 */ 1068 Dwt.getAncestors = 1069 function(childNode, parentNode, includeChild) { 1070 var ancestors = []; 1071 1072 // a reasonable default 1073 if (!parentNode) { 1074 parentNode = document.documentElement; 1075 } 1076 1077 if (includeChild) { 1078 ancestors.push(childNode); 1079 } 1080 1081 while (childNode && childNode != parentNode) { 1082 ancestors.push(childNode.parentNode); 1083 childNode = childNode.parentNode; 1084 } 1085 1086 // check if the parent was an ancestor 1087 if (ancestors[ancestors.length - 1] != parentNode) { 1088 return null; 1089 } 1090 1091 return ancestors; 1092 }; 1093 1094 Dwt.setStatus = 1095 function(text) { 1096 window.status = text; 1097 }; 1098 1099 Dwt.getTitle = 1100 function() { 1101 return window.document.title; 1102 }; 1103 1104 Dwt.setTitle = 1105 function(text) { 1106 window.document.title = text; 1107 }; 1108 1109 Dwt.getIframeDoc = 1110 function(iframeObj) { 1111 if (iframeObj) { 1112 return AjxEnv.isIE 1113 ? iframeObj.contentWindow.document 1114 : iframeObj.contentDocument; 1115 } 1116 return null; 1117 }; 1118 1119 Dwt.getIframeWindow = 1120 function(iframeObj) { 1121 return iframeObj.contentWindow; 1122 }; 1123 1124 /** 1125 * Creates and returns an element from a string of HTML. 1126 * 1127 * @param {string} html the HTML text 1128 * @param {boolean} isRow if <code>true</code>, if the element is a <code><tr></code> 1129 * 1130 * @return {HTMLElement} an HTMLElement with the <code>html</code> as its content. if <code>isRow</code> 1131 * is <code>true</code>, then the element will be a table 1132 */ 1133 Dwt.parseHtmlFragment = 1134 function(html, isRow) { 1135 if (!Dwt._div) { 1136 Dwt._div = document.createElement('div'); 1137 } 1138 // TR element needs to have surrounding table 1139 if (isRow) { 1140 html = "<table style='table-layout:fixed'>" + html + "</table>"; 1141 } 1142 Dwt._div.innerHTML = html; 1143 1144 if (isRow) { 1145 var fragment = document.createDocumentFragment(); 1146 var rows = Dwt._div.firstChild.rows; 1147 for (var i = rows.length - 1; i >= 0; i--) { 1148 // NOTE: We always grab the first row because once we append it 1149 // to the fragment, it will be removed from the table. 1150 fragment.appendChild(rows[0]); 1151 } 1152 return fragment.childNodes.length > 1 ? fragment : fragment.firstChild; 1153 } 1154 return Dwt._div.firstChild; 1155 }; 1156 1157 Dwt.contains = 1158 function(parentEl, childEl) { 1159 var isContained = false; 1160 if (parentEl.compareDocumentPosition) { 1161 var relPos = parentEl.compareDocumentPosition(childEl); 1162 if ((relPos == (document.DOCUMENT_POSITION_CONTAINED_BY | document.DOCUMENT_POSITION_FOLLOWING))) { 1163 isContained = true; 1164 } 1165 } else if (parentEl.contains) { 1166 isContained = parentEl.contains(childEl); 1167 } 1168 return isContained; 1169 }; 1170 1171 Dwt.removeChildren = 1172 function(htmlEl) { 1173 while (htmlEl.hasChildNodes()) { 1174 htmlEl.removeChild(htmlEl.firstChild); 1175 } 1176 }; 1177 1178 /** 1179 * Opera always returns zero for cellIndex property of TD element :( 1180 * 1181 * @param cell TD object we want cell index for 1182 * 1183 * @private 1184 */ 1185 Dwt.getCellIndex = 1186 function(cell) { 1187 if (AjxEnv.isOpera) { 1188 if (cell.tagName && cell.tagName.toLowerCase() == "td") { 1189 // get the cells collection from the TD's parent TR 1190 var cells = cell.parentNode.cells; 1191 var len = cells.length; 1192 for (var i = 0; i < len; i++) { 1193 if (cells[i] == cell) 1194 return i; 1195 } 1196 } 1197 } else { 1198 return cell.cellIndex; 1199 } 1200 return -1; 1201 }; 1202 1203 /** 1204 * Remove the <code>del</code> class name from the element's CSS class names and 1205 * optionally add <code>add</code> class name if given provided 1206 * 1207 * @param {HTMLElement} el HTML Element to which to add/delete class names 1208 * @param {string} [del] the class name to delete 1209 * @param {string} [add] the class name to add 1210 */ 1211 Dwt.delClass = 1212 function(el, del, add) { 1213 1214 if (el == null) { return } 1215 if (!del && !add) { return; } 1216 1217 if (typeof del == "string" && del.length) { 1218 del = Dwt._DELCLASS_CACHE[del] || (Dwt._DELCLASS_CACHE[del] = new RegExp("\\b" + del + "\\b", "ig")); 1219 } 1220 var className = el.className || ""; 1221 className = className.replace(del, " "); 1222 className = AjxStringUtil.trim(className); 1223 el.className = add ? className + " " + add : className; 1224 }; 1225 1226 // cache the regexps here to avoid compiling the same regexp multiple times 1227 Dwt._DELCLASS_CACHE = {}; 1228 1229 /** 1230 * Adds the given class name to the element's CSS class names 1231 * 1232 * @param {HTMLElement} el the HTML Element to which to add the class name 1233 * @param {string} c the class name 1234 * 1235 * @see #delClass 1236 */ 1237 Dwt.addClass = 1238 function(el, c) { 1239 Dwt.delClass(el, c, c); 1240 }; 1241 1242 /** 1243 * Conditionally add or remove a class name from an element 1244 * 1245 * @param {HTMLElement} el the target element 1246 * @param {boolean} condition the condition to check 1247 * @param {string} a the class name when condition is <code>true</code> 1248 * @param {string} b the class name when condition is <code>false</code> 1249 */ 1250 Dwt.condClass = 1251 function(el, condition, a, b) { 1252 if (!!condition) { 1253 if (b) { 1254 Dwt.delClass(el, b); 1255 } 1256 Dwt.addClass(el, a); 1257 } else { 1258 Dwt.delClass(el, a); 1259 if (b) { 1260 Dwt.addClass(el, b); 1261 } 1262 } 1263 }; 1264 1265 /** Returns true if the specified element has the given class. */ 1266 Dwt.hasClass = function(el, className) { 1267 if (!el || !className) return false; 1268 return el.className.match(new RegExp("\\b"+className+"\\b")); 1269 }; 1270 1271 /** 1272 * Sets the selection range. 1273 * 1274 * @param {input|iframe} input input for which to find the selection start point. This 1275 * may be a text input field or an iframe in design mode 1276 * @param {number} start the starting position 1277 * @param {number} end the ending position 1278 * 1279 * @see #getSelectionStart 1280 * @see #getSelectionEnd 1281 * @see #setSelectionText 1282 * @see #moveCursorToEnd 1283 */ 1284 Dwt.setSelectionRange = 1285 function(input, start, end) { 1286 if (input.setSelectionRange) { 1287 input.focus(); 1288 input.setSelectionRange(start, end); 1289 } else if (input.createTextRange) { 1290 var range = input.createTextRange(); 1291 range.collapse(true); 1292 range.moveStart("character", start); 1293 range.moveEnd("character", end - start); 1294 range.select(); 1295 } else if (input.select) { 1296 // FIXME: find solutions for other browsers 1297 input.select(); 1298 } 1299 }; 1300 1301 /** 1302 * Retrieves the start of the selection. For a collapsed range, this is 1303 * equivalent to {@link #getSelectionEnd}. 1304 * 1305 * @param {input|iframe} input input for which to find the selection start point. This 1306 * may be a text input field or an iframe in design mode 1307 * 1308 * @return {number} starting position of the selection 1309 * 1310 * @see #getSelectionEnd 1311 * @see #setSelectionText 1312 * @see #setSelectionRange 1313 * @see #moveCursorToEnd 1314 */ 1315 Dwt.getSelectionStart = 1316 function(input) { 1317 if (AjxUtil.isSpecified(input.selectionStart)) { 1318 return input.selectionStart; 1319 } else if (document.selection) { 1320 var range = document.selection.createRange(); 1321 var isCollapsed = range.compareEndPoints("StartToEnd", range) == 0; 1322 if (!isCollapsed) 1323 range.collapse(true); 1324 var b = range.getBookmark(); 1325 var offset = input.createTextRange().getBookmark().charCodeAt(2); 1326 return Math.max(b.charCodeAt(2) - offset, 0); 1327 } 1328 1329 // FIXME: find solutions for other browsers 1330 return input.value.length; 1331 }; 1332 1333 /** 1334 * Retrieves the end of the selection. 1335 * 1336 * @param {input|iframe} input the input for which to find the selection end point. This 1337 * may be a text input field or an iframe in design mode 1338 * 1339 * @return {number} the starting position of the selection 1340 * 1341 * @see #getSelectionStart 1342 * @see #setSelectionText 1343 * @see #setSelectionRange 1344 * @see #moveCursorToEnd 1345 */ 1346 Dwt.getSelectionEnd = 1347 function(input) { 1348 if (AjxUtil.isSpecified(input.selectionEnd)) { 1349 return input.selectionEnd; 1350 } else if (document.selection) { 1351 var range = document.selection.createRange(); 1352 var isCollapsed = range.compareEndPoints("StartToEnd", range) == 0; 1353 if (!isCollapsed) 1354 range.collapse(false); 1355 var b = range.getBookmark(); 1356 var offset = input.createTextRange().getBookmark().charCodeAt(2); 1357 return Math.max(b.charCodeAt(2) - offset, 0); 1358 } 1359 1360 // FIXME: find solutions for other browsers 1361 return input.value.length; 1362 }; 1363 1364 /** 1365 * Sets the selection text 1366 * 1367 * @param {input|iframe} input the input for which to set the selection text. This 1368 * may be a text input field or an iframe in design mode 1369 * @param {string} text the text to set as the selection 1370 * 1371 * @see #getSelectionStart 1372 * @see #getSelectionEnd 1373 * @see #setSelectionRange 1374 * @see #moveCursorToEnd 1375 */ 1376 Dwt.setSelectionText = 1377 function(input, text) { 1378 var start = Dwt.getSelectionStart(input); 1379 var end = Dwt.getSelectionEnd(input); 1380 var str = input.value; 1381 var val = [ 1382 str.substr(0, start), 1383 text, 1384 str.substr(end) 1385 ].join(""); 1386 1387 if (typeof input.setValue == "function") { 1388 input.setValue(val); 1389 } else { 1390 input.value = val; 1391 } 1392 Dwt.setSelectionRange(input, start, start + text.length); 1393 }; 1394 1395 /** 1396 * Move cursor to the end of an input. 1397 * 1398 * @param {input} input text input 1399 * 1400 * @see #getSelectionStart 1401 * @see #getSelectionEnd 1402 * @see #setSelectionText 1403 * @see #setSelectionRange 1404 */ 1405 Dwt.moveCursorToEnd = 1406 function(input) { 1407 Dwt.setSelectionRange(input, input.value.length, input.value.length); 1408 }; 1409 1410 Dwt.instanceOf = 1411 function(objOrClassName, className) { 1412 if (typeof objOrClassName == "string") { 1413 return window[objOrClassName] && 1414 (objOrClassName == className || window[objOrClassName].prototype instanceof window[className]); 1415 } 1416 return (window[className] && objOrClassName instanceof window[className]); 1417 }; 1418 1419 /** 1420 * Normalizes an argument list into a hash with the given argument names. 1421 * If a single hash argument is passed, it is recognized as a params hash 1422 * and returned. Otherwise, the argument list is exploded into a params 1423 * hash with the given param names. 1424 * 1425 * @param {Object} args Array-like structure of arguments 1426 * @param {array} paramNames an ordered list of param names 1427 */ 1428 Dwt.getParams = function(args, paramNames) { 1429 1430 if (!args || args.length === 0 || (args.length === 1 && !args[0])) { 1431 return {}; 1432 } 1433 1434 // Check for arg-list style of passing params. There will almost always 1435 // be more than one arg, and the first one may be the parent DwtControl. 1436 // Conversion is not done if there is a single argument that is a simple 1437 // hash, or a proxy for a simple hash (see AjxUtil.createProxy). 1438 1439 if (args.length > 1 || !AjxUtil.isHash(args[0]._object_ || args[0])) { 1440 var params = {}; 1441 for (var i = 0; i < args.length; i++) { 1442 params[paramNames[i]] = args[i]; 1443 } 1444 return params; 1445 } 1446 if (args.length === 1) { 1447 return args[0]; 1448 } 1449 return {}; 1450 }; 1451 1452 ////////////////////////////////////////////////////////////////////////////////// 1453 // PRIVATE METHODS 1454 ////////////////////////////////////////////////////////////////////////////////// 1455 1456 Dwt.__REM_RE = /^(-?[0-9]+(?:\.[0-9]*)?)rem$/; 1457 1458 /** 1459 * @private 1460 */ 1461 Dwt.__checkPxVal = 1462 function(val, check) { 1463 if (val == Dwt.DEFAULT) { return false; } 1464 if (isNaN(parseInt(val))) { return false; } 1465 1466 if (check && val < 0 && val != Dwt.LOC_NOWHERE) { 1467 DBG.println(AjxDebug.DBG1, "negative pixel value: " + val); 1468 val = 0; 1469 } 1470 if (typeof(val) == "number") { 1471 val = val + "px"; 1472 } 1473 if (!AjxEnv.supportsCSS3RemUnits && Dwt.__REM_RE.test(val)) { 1474 val = DwtCssStyle.asPixelCount(val) + "px"; 1475 } 1476 return val; 1477 }; 1478 1479 1480 1481 1482 1483 1484 ///////////// 1485 // NEW STUFF FROM OWEN 1486 ///////////// 1487 Dwt.byId = 1488 function(id, ancestor) { 1489 if (!ancestor) { 1490 return (typeof id == "string" ? document.getElementById(id) : id); 1491 } 1492 1493 // Find node with id that descends from ancestor (also works on DOM trees 1494 // that are not attached to the document object) 1495 if (ancestor == id || ancestor.id == id) { 1496 return ancestor; 1497 } 1498 1499 for (var i = 0; i < ancestor.childNodes.length; i++) { 1500 if (ancestor.childNodes[i].nodeType == 1) { 1501 var cnode = Dwt.byId(id, ancestor.childNodes[i]); 1502 if (cnode) { return cnode; } 1503 } 1504 } 1505 return null; 1506 }; 1507 1508 /** 1509 * Get all elements of a certain tag name. Similar to 1510 * document.getElementsByTagName(), but returning an Array instead of 1511 * a NodeList. 1512 * 1513 * @param {String} tagName the tag name, such as "A" 1514 * @param {HTMLElement} ancestor An optional ancestor element, 1515 * defaults to the document 1516 * @return {Array} 1517 */ 1518 Dwt.byTag = 1519 function(tagName, ancestor) { 1520 if (!ancestor) { 1521 ancestor = document; 1522 } 1523 1524 return AjxUtil.toArray(ancestor.getElementsByTagName(tagName)); 1525 }; 1526 1527 /** 1528 * Get all elements of the given class name. Similar to 1529 * document.getElementsByClassName(), but returning an Array instead 1530 * of a NodeList. 1531 * 1532 * @param {String} className 1533 * @param {HTMLElement} ancestor An optional ancestor element, 1534 * defaults to the document 1535 * @return {Array} 1536 */ 1537 Dwt.byClassName = 1538 function(className, ancestor) { 1539 if (!ancestor) { 1540 ancestor = document; 1541 } 1542 1543 var nodes; 1544 1545 if (ancestor.getElementsByClassName) { 1546 nodes = ancestor.getElementsByClassName(className); 1547 } else { 1548 nodes = ancestor.querySelectorAll('.' + className); 1549 } 1550 1551 return AjxUtil.toArray(nodes); 1552 }; 1553 1554 Dwt.show = 1555 function(it) { 1556 var el = Dwt.byId(it); 1557 if (el) { 1558 Dwt.setVisible(el,true); 1559 } 1560 }; 1561 1562 Dwt.hide = 1563 function(it) { 1564 var el = Dwt.byId(it); 1565 if (el) { 1566 Dwt.setVisible(el,false); 1567 } 1568 }; 1569 1570 //setText Methods 1571 1572 Dwt.setText = 1573 function(htmlEl,text){ 1574 htmlEl.appendChild(document.createTextNode(text)); 1575 }; 1576 1577 Dwt.populateText = 1578 function(){ 1579 if (arguments.length == 0 ) { return; } 1580 1581 var node, index = 0, length = arguments.length; 1582 while (index < length) { 1583 node = document.getElementById(arguments[index]); 1584 if (node) { 1585 Dwt.setText(node,arguments[index+1]); 1586 } 1587 index += 2; 1588 } 1589 }; 1590 1591 //setHtml Methods 1592 1593 Dwt.setInnerHtml = 1594 function(htmlEl,html){ 1595 htmlEl.innerHTML = html; 1596 }; 1597 1598 /** 1599 * Sets the favicon. 1600 * 1601 * @param {string} the url to the icon to display 1602 * 1603 * @private 1604 */ 1605 Dwt.setFavIcon = 1606 function(iconURL) { 1607 1608 // Look for an existing fav icon to modify. 1609 var favIcon = null; 1610 if (Dwt._favIconId) { 1611 favIcon = document.getElementById(Dwt._favIconId); 1612 } else { 1613 var docHead = document.getElementsByTagName("head")[0]; 1614 var links = docHead.getElementsByTagName("link"); 1615 for (var i = 0; i < links.length; i++) { 1616 var link = links[i]; 1617 if (link.rel.toUpperCase() == "SHORTCUT ICON") { 1618 if (!link.id) { 1619 link.id = Dwt._favIconId = Dwt.getNextId(); 1620 } 1621 favIcon = link; 1622 break; 1623 } 1624 } 1625 } 1626 // If available, change the existing favicon. 1627 // (Need to remove/add to dom in order to force a redraw.) 1628 if (favIcon) { 1629 favIcon.href=iconURL; 1630 favIcon.type = 'image/x-icon'; 1631 var parent = favIcon.parentNode; 1632 parent.removeChild(favIcon); 1633 parent.appendChild(favIcon); 1634 } 1635 // If no favicon was found in the document, create a new one. 1636 else { 1637 var newLink = document.createElement("link"); 1638 newLink.id = Dwt._favIconId = Dwt.getNextId() 1639 newLink.rel = "SHORTCUT ICON"; 1640 newLink.href = iconURL; 1641 newLink.type = "image/x-icon"; 1642 docHead = docHead || document.getElementsByTagName("head")[0]; 1643 docHead.appendChild(newLink); 1644 } 1645 }; 1646 1647 Dwt.enableDesignMode = 1648 function(doc, on) { 1649 if (!AjxEnv.isIE) { 1650 doc.designMode = on ? "on" : "off"; 1651 } else { 1652 var editorBody = doc.body; 1653 if (!editorBody || editorBody.contentEditable === undefined) { 1654 doc.designMode = on ? "on" : "off"; 1655 } else { 1656 editorBody.contentEditable = on ? true : false; 1657 } 1658 } 1659 }; 1660 1661 /** 1662 * Hack to work around FF 3.6 change in behavior with regard to mouse down/up in 1663 * scrollbar, which breaks this list view's scrollbar. Return true and tell DOM 1664 * not to call <code>preventDefault()</code>, since we want default browser behavior. 1665 * <p> 1666 * Note: Callers should set up their elements so that a click that is not within 1667 * a scrollbar goes to a more specific element (and not the one that scrolls). 1668 * That way we don't have to perform sketchy math to see if the click was in the 1669 * scrollbar. 1670 * </p> 1671 * <p> 1672 * <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=489667">https://bugzilla.mozilla.org/show_bug.cgi?id=489667</a> 1673 * </p> 1674 * <p>It looks like the FF bug will be fixed with the release of 3.6.4.</p> 1675 * @param {DwtMouseEvent} ev the event 1676 * @return {boolean} <code>true</code> if FF3.6+ scrollbar click was detected and handled 1677 * 1678 * @private 1679 */ 1680 Dwt.ffScrollbarCheck = 1681 function(ev) { 1682 if (AjxEnv.isFirefox3_6up || AjxEnv.isDesktop2up) { 1683 var t = ev.target; 1684 if (t && (t.clientHeight && t.scrollHeight && (t.clientHeight != t.scrollHeight)) || 1685 (t.clientWidth && t.scrollWidth && (t.clientWidth != t.scrollWidth))) 1686 { 1687 ev._dontCallPreventDefault = true; 1688 ev._stopPropagation = false; 1689 ev._returnValue = true; 1690 return true; 1691 } 1692 } 1693 return false; 1694 }; 1695 1696 Dwt.selectText = 1697 function(el) { 1698 1699 if (!el) { 1700 Dwt.deselectText(); 1701 return; 1702 } 1703 1704 if (document.selection) { 1705 // IE 1706 var range = el.parentTextEdit.createTextRange(); 1707 range.moveToElementText(el); 1708 range.select(); 1709 } 1710 else if (window.getSelection) { 1711 var range = document.createRange(); 1712 range.selectNode(el); 1713 var sel = window.getSelection(); 1714 sel.addRange(range); 1715 } 1716 }; 1717 1718 Dwt.deselectText = 1719 function() { 1720 1721 if (document.selection) { 1722 // IE 1723 document.selection.empty(); 1724 } 1725 else if (window.getSelection) { 1726 window.getSelection().removeAllRanges(); 1727 } 1728 }; 1729 1730 /** 1731 * Inserts some text into an input at the caret. 1732 * 1733 * @param {Element} input INPUT or TEXTAREA 1734 * @param {String} text text to insert 1735 */ 1736 Dwt.insertText = function(input, text) { 1737 1738 if (!input || !text) { 1739 return; 1740 } 1741 1742 if (document.selection) { 1743 // IE 1744 input.focus(); 1745 var sel = document.selection.createRange(); 1746 sel.text = text; 1747 input.focus(); 1748 } 1749 else if (AjxUtil.isSpecified(input.selectionStart)) { 1750 var start = input.selectionStart, 1751 end = input.selectionEnd; 1752 input.value = input.value.substring(0, start) + text + input.value.substring(end, input.value.length); 1753 input.selectionStart = start + text.length; 1754 input.selectionEnd = end + text.length; 1755 } 1756 else { 1757 input.value += text; 1758 } 1759 }; 1760 1761 /** 1762 * Returns true if the two elements overlap. 1763 * 1764 * @param el1 1765 * @param el2 1766 */ 1767 Dwt.doOverlap = 1768 function(el1, el2) { 1769 1770 if (!el1 || !el2) { return false; } 1771 1772 var loc1 = Dwt.getLocation(el1), loc2 = Dwt.getLocation(el2); 1773 var size1 = Dwt.getSize(el1), size2 = Dwt.getSize(el2); 1774 var left1 = loc1.x, left2 = loc2.x, top1 = loc1.y, top2 = loc2.y; 1775 var right1 = left1 + size1.x, right2 = left2 + size2.x; 1776 var bottom1 = top1 + size1.y, bottom2 = top2 + size2.y; 1777 1778 return !(left1 > right2 || right1 < left2 || top1 > bottom2 || bottom1 < top2); 1779 }; 1780 1781 /** 1782 * Resets the scrollTop of container (if necessary) to ensure that element is visible. 1783 * 1784 * @param {Element} element the element to be made visible 1785 * @param {Element} container the containing element to possibly scroll 1786 * @private 1787 */ 1788 Dwt.scrollIntoView = 1789 function(element, container) { 1790 1791 if (!element || !container) { return; } 1792 1793 var elementTop = Dwt.toWindow(element, 0, 0, null, null, DwtPoint.tmp).y; 1794 var containerTop = Dwt.toWindow(container, 0, 0, null, null, DwtPoint.tmp).y + container.scrollTop; 1795 1796 var diff = elementTop - containerTop; 1797 if (diff < 0) { 1798 container.scrollTop += diff; 1799 } else { 1800 var containerH = Dwt.getSize(container, DwtPoint.tmp).y; 1801 var elementH = Dwt.getSize(element, DwtPoint.tmp).y; 1802 diff = (elementTop + elementH) - (containerTop + containerH); 1803 if (diff > 0) { 1804 container.scrollTop += diff; 1805 } 1806 } 1807 }; 1808 1809 /** 1810 * Sets up a hidden div for performance metrics. Use to set the start of object rendering 1811 * @param id {String} 1812 * @param date {Date} 1813 */ 1814 Dwt.setLoadingTime = 1815 function(id, date) { 1816 if (!window.isPerfMetric) { return; } 1817 date = date || new Date(); 1818 id += "_loading"; 1819 var div = document.getElementById(id); 1820 if (!div) { 1821 div = document.createElement("div"); 1822 div.id = id; 1823 div.style.display = "none"; 1824 document.body.appendChild(div); 1825 } 1826 div.innerHTML = date.getTime(); 1827 if (window.appDevMode) { 1828 console.profile(id); 1829 } 1830 }; 1831 1832 /** 1833 * Sets up a hidden div for performance metrics. Use to set the end of object rendering 1834 * @param id {String} 1835 * @param date {Date} 1836 */ 1837 Dwt.setLoadedTime = 1838 function(id, date) { 1839 if (!window.isPerfMetric) { return; } 1840 date = date || new Date(); 1841 id += "_loaded"; 1842 var div = document.getElementById(id); 1843 if (!div) { 1844 div = document.createElement("div"); 1845 div.id = id; 1846 div.style.display = "none"; 1847 document.body.appendChild(div); 1848 } 1849 div.innerHTML = date.getTime(); 1850 if (window.appDevMode) { 1851 console.profileEnd(); 1852 } 1853 }; 1854 1855 /** 1856 * Prints the computed time from performance metrics data 1857 */ 1858 Dwt.printPerfMetric = 1859 function() { 1860 //code to print all loading stats 1861 $.each($('div[id*="_loaded"]'), function(index, elem) { 1862 var end_id = $(elem).attr("id"); 1863 var start_id_prefix = end_id.substring(0,end_id.indexOf("_")); 1864 var end_elem = $("#" + start_id_prefix+"_launched"); 1865 if (end_elem && end_elem.length > 0) { 1866 var end_time = $("#" + start_id_prefix+"_launched").html(); 1867 } else { 1868 end_time = $("#" + start_id_prefix+"_loading").html(); 1869 } 1870 var log = "Load time for " + start_id_prefix + " is " + ($(elem).html()-end_time); 1871 DBG.println(AjxDebug.DBG1,log); 1872 if (console) { 1873 console.log(log); 1874 } 1875 }); 1876 } 1877 1878 // Css for Templates 1879 Dwt.createLinearGradientCss = 1880 function(startColor, endColor, direction) { 1881 var gradientCss = null; 1882 var gradient = this.createLinearGradientInfo(startColor, endColor, direction); 1883 if (gradient.field) { 1884 gradientCss = gradient.field + ":" + gradient.css + ";"; 1885 } 1886 return gradientCss; 1887 } 1888 1889 /** 1890 * -- FF 3.6+ 1891 * background: -moz-linear-gradient(black, white); 1892 * -- Safari 4+, Chrome 2+ 1893 * background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #000000), color-stop(100%, #ffffff)); 1894 * -- Safari 5.1+, Chrome 10+ 1895 * background: -webkit-linear-gradient(top, black, white); 1896 * -- Opera 11.10 1897 * background: -o-linear-gradient(black, white); 1898 * -- IE6 & IE7 1899 * filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#000000', endColorstr='#ffffff'); 1900 * -- IE8 & IE9 1901 * -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#000000', endColorstr='#ffffff')"; 1902 * -- IE10 1903 * background: -ms-linear-gradient(black, white); 1904 * -- the standard 1905 * background: linear-gradient(black, white); 1906 */ 1907 Dwt.createLinearGradientInfo = 1908 function(startColor, endColor, direction) { 1909 1910 var cssDirection; 1911 var gradient = {}; 1912 if (AjxEnv.isIE && !AjxEnv.isIE9up) { 1913 cssDirection = (direction == 'v') ? 0 : 1; 1914 gradient.field = "filter"; 1915 gradient.name = "DXImageTransform.Microsoft.Gradient"; 1916 gradient.css = "progid:" + gradient.name + "(" + 1917 "GradientType=" + cssDirection + ",startColorstr=" + startColor + 1918 ",endColorstr=" + endColor + "); zoom:1;"; 1919 } else if (AjxEnv.isIE9) { 1920 var params = { 1921 x1: "0%", 1922 x2: direction == 'v' ? "0%" : "100%", 1923 y1: "0%", 1924 y2: direction == 'v' ? "100%" : "0%", 1925 startColor: startColor, 1926 endColor: endColor 1927 }; 1928 var svgsrc = 1929 AjxTemplate.expand('dwt.Widgets#SVGGradient', params); 1930 gradient.field = "background"; 1931 gradient.css = ('url(data:image/svg+xml,' + 1932 escape(svgsrc.replace(/\s+/g, ' ')) + ')'); 1933 } else if (AjxEnv.isFirefox3_6up) { 1934 cssDirection = (direction == 'v') ? 'top' : 'left'; 1935 gradient.field = "background"; 1936 gradient.css = "-moz-linear-gradient(" + cssDirection + "," + startColor + ", " + endColor + ")"; 1937 } else if ((AjxEnv.isSafari && AjxEnv.isSafari5_1up) || AjxEnv.isChrome10up) { 1938 cssDirection = (direction == 'v') ? 'top' : 'left'; 1939 gradient.field = "background"; 1940 gradient.css = "-webkit-linear-gradient(" + cssDirection + ","+ 1941 startColor + ", " + endColor + ")"; 1942 } else if ((AjxEnv.isSafari && AjxEnv.isSafari4up) || AjxEnv.isChrome2up) { 1943 var startPt = 'left top'; 1944 var endPt = (direction == 'v') ? "left bottom" : "right top"; 1945 gradient.field = "background"; 1946 gradient.css = "-webkit-gradient(linear, " + startPt + ", " + endPt + 1947 ", color-stop(0%, " + startColor + "), color-stop(100%, " + endColor + "))"; 1948 } else { 1949 cssDirection = (direction == 'v') ? 'to bottom' : 'to right'; 1950 gradient.field = "background"; 1951 gradient.css = "linear-gradient(" + cssDirection + "," + startColor + ", " + endColor + ")"; 1952 } 1953 return gradient; 1954 } 1955 1956 Dwt.setLinearGradient = 1957 function(htmlElement, startColor, endColor, direction) { 1958 var gradient = Dwt.createLinearGradientInfo(startColor, endColor, direction); 1959 if (gradient.field == 'filter') { 1960 Dwt.alterIEFilter(htmlElement, gradient.name, gradient.css); 1961 } else { 1962 htmlElement.style[gradient.field] = gradient.css; 1963 } 1964 } 1965 1966 Dwt.alterIEFilter = 1967 function(htmlElement, filterName, newFilter) { 1968 if (htmlElement.style.filter) { 1969 var found = false; 1970 var filters = htmlElement.style.filter.split(" "); 1971 for (var i = 0; i < filters.length; i++) { 1972 if (filters[i].indexOf(filterName) != -1) { 1973 filters[i] = newFilter; 1974 found = true; 1975 break; 1976 } 1977 } 1978 if (!found) { 1979 filters[filters.length] = newFilter; 1980 } 1981 htmlElement.style.filter = filters.join(" "); 1982 } else { 1983 htmlElement.style.filter = newFilter; 1984 } 1985 } 1986 1987 Dwt.getIEFilter = 1988 function(htmlElement, filterName) { 1989 var filter = ""; 1990 if (htmlElement.style.filter) { 1991 var filters = htmlElement.style.filter.split(" "); 1992 for (var i = 0; i < filters.length; i++) { 1993 if (filters[i].indexOf(filterName) != -1) { 1994 filter = filters[i]; 1995 break; 1996 } 1997 } 1998 } 1999 return filter 2000 } 2001 2002 // Used for an unattached DOM subtree. 2003 Dwt.getDescendant = 2004 function(htmlElement, id) { 2005 var descendant = null; 2006 for (var i = 0; i < htmlElement.childNodes.length; i++) { 2007 var child = htmlElement.childNodes[i]; 2008 if (child.id == id) { 2009 descendant = child; 2010 } else { 2011 descendant = Dwt.getDescendant(child, id); 2012 } 2013 if (descendant != null) { 2014 break; 2015 } 2016 } 2017 return descendant; 2018 }; 2019 2020 Dwt.getPreviousElementSibling = 2021 function(element) { 2022 var sibling = element.previousElementSibling; 2023 2024 if (sibling !== undefined) { 2025 return sibling; 2026 } 2027 2028 // workaround for missing previousElementSibling in MSIE 8 2029 for (sibling = element.previousSibling; 2030 sibling && sibling.nodeType !== 1; 2031 sibling = sibling.previousSibling); 2032 2033 return sibling; 2034 } 2035 2036 Dwt.getNextElementSibling = 2037 function(element) { 2038 var sibling = element.nextElementSibling; 2039 2040 if (sibling !== undefined) { 2041 return sibling; 2042 } 2043 2044 // workaround for missing nextElementSibling in MSIE 8 2045 for (sibling = element.nextSibling; 2046 sibling && sibling.nodeType !== 1; 2047 sibling = sibling.nextSibling); 2048 2049 return sibling; 2050 } 2051 2052 Dwt.getScrollbarSizes = function(node) { 2053 var insets = Dwt.getInsets(node); 2054 var style = DwtCssStyle.getComputedStyleObject(node); 2055 2056 var bl = parseInt(style.borderLeftWidth) || 0; 2057 var bt = parseInt(style.borderTopWidth) || 0; 2058 var br = parseInt(style.borderRightWidth) || 0; 2059 var bb = parseInt(style.borderBottomWidth) || 0; 2060 2061 var width = node.offsetWidth - node.clientWidth - bl - br; 2062 var height = node.offsetHeight - node.clientHeight - bt - bb; 2063 2064 return new DwtPoint(width, height); 2065 }; 2066