home *** CD-ROM | disk | FTP | other *** search
/ Computer Active Guide 2009 July / CAG7.ISO / Internetas / SafariSetup.exe / AppleApplicationSupport.msi / WebKit.resources_inspector_Popover.js < prev    next >
Encoding:
Text File  |  2010-06-03  |  9.5 KB  |  246 lines

  1. /*
  2.  * Copyright (C) 2009 Google Inc. All rights reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without
  5.  * modification, are permitted provided that the following conditions are
  6.  * met:
  7.  *
  8.  *     * Redistributions of source code must retain the above copyright
  9.  * notice, this list of conditions and the following disclaimer.
  10.  *     * Redistributions in binary form must reproduce the above
  11.  * copyright notice, this list of conditions and the following disclaimer
  12.  * in the documentation and/or other materials provided with the
  13.  * distribution.
  14.  *     * Neither the name of Google Inc. nor the names of its
  15.  * contributors may be used to endorse or promote products derived from
  16.  * this software without specific prior written permission.
  17.  *
  18.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19.  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20.  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21.  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  22.  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  24.  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  28.  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29.  */
  30.  
  31. WebInspector.Popover = function(contentElement)
  32. {
  33.     this.element = document.createElement("div");
  34.     this.element.className = "popover";
  35.  
  36.     this._popupArrowElement = document.createElement("div");
  37.     this._popupArrowElement.className = "arrow";
  38.     this.element.appendChild(this._popupArrowElement);
  39.  
  40.     this.contentElement = contentElement;
  41.     this._contentDiv = document.createElement("div");
  42.     this._contentDiv.className = "content";
  43. }
  44.  
  45. WebInspector.Popover.prototype = {
  46.     show: function(anchor, preferredWidth, preferredHeight)
  47.     {
  48.         // This should not happen, but we hide previous popup to be on the safe side.
  49.         if (WebInspector.Popover._popoverElement)
  50.             document.body.removeChild(WebInspector.Popover._popoverElement);
  51.         WebInspector.Popover._popoverElement = this.element;
  52.  
  53.         // Temporarily attach in order to measure preferred dimensions.
  54.         this.contentElement.positionAt(0, 0);
  55.         document.body.appendChild(this.contentElement);
  56.         var preferredWidth = preferredWidth || this.contentElement.offsetWidth;
  57.         var preferredHeight = preferredHeight || this.contentElement.offsetHeight;
  58.  
  59.         this._contentDiv.appendChild(this.contentElement);
  60.         this.element.appendChild(this._contentDiv);
  61.         document.body.appendChild(this.element);
  62.         this._positionElement(anchor, preferredWidth, preferredHeight);
  63.     },
  64.  
  65.     hide: function()
  66.     {
  67.         if (WebInspector.Popover._popoverElement) {
  68.             delete WebInspector.Popover._popoverElement;
  69.             document.body.removeChild(this.element);
  70.         }
  71.     },
  72.  
  73.     _positionElement: function(anchorElement, preferredWidth, preferredHeight)
  74.     {
  75.         const borderWidth = 25;
  76.         const scrollerWidth = 11;
  77.         const arrowHeight = 15;
  78.         const arrowOffset = 10;
  79.         const borderRadius = 10;
  80.  
  81.         // Skinny tooltips are not pretty, their arrow location is not nice.
  82.         preferredWidth = Math.max(preferredWidth, 50);
  83.         const totalWidth = window.innerWidth;
  84.         const totalHeight = window.innerHeight;
  85.  
  86.         var anchorBox = {x: anchorElement.totalOffsetLeft, y: anchorElement.totalOffsetTop, width: anchorElement.offsetWidth, height: anchorElement.offsetHeight};
  87.         while (anchorElement !== document.body) {
  88.             if (anchorElement.scrollLeft)
  89.                 anchorBox.x -= anchorElement.scrollLeft;
  90.             if (anchorElement.scrollTop)
  91.                 anchorBox.y -= anchorElement.scrollTop;
  92.             anchorElement = anchorElement.parentElement;
  93.         }
  94.  
  95.         var newElementPosition = { x: 0, y: 0, width: preferredWidth + scrollerWidth, height: preferredHeight };
  96.  
  97.         var verticalAlignment;
  98.         var roomAbove = anchorBox.y;
  99.         var roomBelow = totalHeight - anchorBox.y - anchorBox.height;
  100.  
  101.         if (roomAbove > roomBelow) {
  102.             // Positioning above the anchor.
  103.             if (anchorBox.y > newElementPosition.height + arrowHeight + borderRadius)
  104.                 newElementPosition.y = anchorBox.y - newElementPosition.height - arrowHeight;
  105.             else {
  106.                 newElementPosition.y = borderRadius * 2;
  107.                 newElementPosition.height = anchorBox.y - borderRadius * 2 - arrowHeight;
  108.             }
  109.             verticalAlignment = "bottom";
  110.         } else {
  111.             // Positioning below the anchor.
  112.             newElementPosition.y = anchorBox.y + anchorBox.height + arrowHeight;
  113.             if (newElementPosition.y + newElementPosition.height + arrowHeight - borderWidth >= totalHeight)
  114.                 newElementPosition.height = totalHeight - anchorBox.y - anchorBox.height - borderRadius * 2 - arrowHeight;
  115.             // Align arrow.
  116.             verticalAlignment = "top";
  117.         }
  118.  
  119.         var horizontalAlignment;
  120.         if (anchorBox.x + newElementPosition.width < totalWidth) {
  121.             newElementPosition.x = Math.max(borderRadius, anchorBox.x - borderRadius - arrowOffset);
  122.             horizontalAlignment = "left";
  123.         } else if (newElementPosition.width + borderRadius * 2 < totalWidth) {
  124.             newElementPosition.x = totalWidth - newElementPosition.width - borderRadius;
  125.             horizontalAlignment = "right";
  126.             // Position arrow accurately.
  127.             var arrowRightPosition = Math.max(0, totalWidth - anchorBox.x - anchorBox.width - borderRadius - arrowOffset);
  128.             arrowRightPosition += anchorBox.width / 2;
  129.             this._popupArrowElement.style.right = arrowRightPosition + "px";
  130.         } else {
  131.             newElementPosition.x = borderRadius;
  132.             newElementPosition.width = totalWidth - borderRadius * 2;
  133.             newElementPosition.height += scrollerWidth;
  134.             horizontalAlignment = "left";
  135.             if (verticalAlignment === "bottom")
  136.                 newElementPosition.y -= scrollerWidth;
  137.             // Position arrow accurately.
  138.             this._popupArrowElement.style.left = Math.max(0, anchorBox.x - borderRadius * 2 - arrowOffset) + "px";
  139.             this._popupArrowElement.style.left += anchorBox.width / 2;
  140.         }
  141.  
  142.         this.element.className = "popover " + verticalAlignment + "-" + horizontalAlignment + "-arrow";
  143.         this.element.positionAt(newElementPosition.x - borderWidth, newElementPosition.y - borderWidth);
  144.         this.element.style.width = newElementPosition.width + borderWidth * 2 + "px";
  145.         this.element.style.height = newElementPosition.height + borderWidth * 2 + "px";
  146.     }
  147. }
  148.  
  149. WebInspector.PopoverHelper = function(panelElement, getAnchor, showPopup, showOnClick, onHide)
  150. {
  151.     this._panelElement = panelElement;
  152.     this._getAnchor = getAnchor;
  153.     this._showPopup = showPopup;
  154.     this._showOnClick = showOnClick;
  155.     this._onHide = onHide;
  156.     panelElement.addEventListener("mousedown", this._mouseDown.bind(this), false);
  157.     panelElement.addEventListener("mousemove", this._mouseMove.bind(this), false);
  158. }
  159.  
  160. WebInspector.PopoverHelper.prototype = {
  161.     _mouseDown: function(event)
  162.     {
  163.         this._killHidePopupTimer();
  164.         this._handleMouseAction(event, true);
  165.     },
  166.  
  167.     _mouseMove: function(event)
  168.     {
  169.         // Pretend that nothing has happened.
  170.         if (this._hoverElement === event.target || (this._hoverElement && this._hoverElement.isAncestor(event.target)))
  171.             return;
  172.  
  173.         // User has 500ms to reach the popup.
  174.         if (this._popup && !this._hidePopupTimer) {
  175.             var self = this;
  176.             function doHide()
  177.             {
  178.                 self._hidePopup();
  179.                 delete self._hidePopupTimer;
  180.             }
  181.             this._hidePopupTimer = setTimeout(doHide, 500);
  182.         }
  183.  
  184.         this._handleMouseAction(event);
  185.     },
  186.  
  187.     _handleMouseAction: function(event, isMouseDown)
  188.     {
  189.         this._resetHoverTimer();
  190.  
  191.         this._hoverElement = this._getAnchor(event.target);
  192.         if (!this._hoverElement)
  193.             return;
  194.  
  195.         const toolTipDelay = isMouseDown ? 0 : (this._popup ? 600 : 1000);
  196.         this._hoverTimer = setTimeout(this._mouseHover.bind(this, this._hoverElement), toolTipDelay);
  197.     },
  198.  
  199.     _resetHoverTimer: function()
  200.     {
  201.         if (this._hoverTimer) {
  202.             clearTimeout(this._hoverTimer);
  203.             delete this._hoverTimer;
  204.         }
  205.     },
  206.  
  207.     hidePopup: function()
  208.     {
  209.         this._resetHoverTimer();
  210.         this._hidePopup();
  211.     },
  212.  
  213.     _hidePopup: function()
  214.     {
  215.         if (!this._popup)
  216.             return;
  217.  
  218.         if (this._onHide)
  219.             this._onHide();
  220.  
  221.         this._popup.hide();
  222.         delete this._popup;
  223.     },
  224.  
  225.     _mouseHover: function(element)
  226.     {
  227.         delete this._hoverTimer;
  228.  
  229.         this._popup = this._showPopup(element);
  230.         if (this._popup)
  231.             this._popup.contentElement.addEventListener("mousemove", this._killHidePopupTimer.bind(this), true);
  232.     },
  233.  
  234.     _killHidePopupTimer: function()
  235.     {
  236.         if (this._hidePopupTimer) {
  237.             clearTimeout(this._hidePopupTimer);
  238.             delete this._hidePopupTimer;
  239.  
  240.             // We know that we reached the popup, but we might have moved over other elements.
  241.             // Discard pending command.
  242.             this._resetHoverTimer();
  243.         }
  244.     }
  245. }
  246.