WebInspector.Popover = function(popoverHelper)
{
this.element = document.createElement("div");
this.element.className = "popover custom-popup-vertical-scroll custom-popup-horizontal-scroll";
this._popupArrowElement = document.createElement("div");
this._popupArrowElement.className = "arrow";
this.element.appendChild(this._popupArrowElement);
this._contentDiv = document.createElement("div");
this._contentDiv.className = "content";
this._visible = false;
this._popoverHelper = popoverHelper;
}
WebInspector.Popover.prototype = {
show: function(contentElement, anchor, preferredWidth, preferredHeight)
{
if (this._disposed)
return;
this.contentElement = contentElement;
if (WebInspector.Popover._popoverElement)
document.body.removeChild(WebInspector.Popover._popoverElement);
WebInspector.Popover._popoverElement = this.element;
this.contentElement.positionAt(0, 0);
document.body.appendChild(this.contentElement);
preferredWidth = preferredWidth || this.contentElement.offsetWidth;
preferredHeight = preferredHeight || this.contentElement.offsetHeight;
this._contentDiv.appendChild(this.contentElement);
this.element.appendChild(this._contentDiv);
document.body.appendChild(this.element);
this._positionElement(anchor, preferredWidth, preferredHeight);
this._visible = true;
if (this._popoverHelper)
contentElement.addEventListener("mousemove", this._popoverHelper._killHidePopoverTimer.bind(this._popoverHelper), true);
},
hide: function()
{
if (WebInspector.Popover._popoverElement) {
delete WebInspector.Popover._popoverElement;
document.body.removeChild(this.element);
}
this._visible = false;
},
get visible()
{
return this._visible;
},
get disposed()
{
return this._disposed;
},
dispose: function()
{
if (this.visible)
this.hide();
this._disposed = true;
},
setCanShrink: function(canShrink)
{
this._hasFixedHeight = !canShrink;
this._contentDiv.addStyleClass("fixed-height");
},
_positionElement: function(anchorElement, preferredWidth, preferredHeight)
{
const borderWidth = 25;
const scrollerWidth = this._hasFixedHeight ? 0 : 11;
const arrowHeight = 15;
const arrowOffset = 10;
const borderRadius = 10;
preferredWidth = Math.max(preferredWidth, 50);
const totalWidth = window.innerWidth;
const totalHeight = window.innerHeight;
var anchorBox = anchorElement.boxInWindow(window);
var newElementPosition = { x: 0, y: 0, width: preferredWidth + scrollerWidth, height: preferredHeight };
var verticalAlignment;
var roomAbove = anchorBox.y;
var roomBelow = totalHeight - anchorBox.y - anchorBox.height;
if (roomAbove > roomBelow) {
if (anchorBox.y > newElementPosition.height + arrowHeight + borderRadius)
newElementPosition.y = anchorBox.y - newElementPosition.height - arrowHeight;
else {
newElementPosition.y = borderRadius;
newElementPosition.height = anchorBox.y - borderRadius * 2 - arrowHeight;
if (this._hasFixedHeight && newElementPosition.height < preferredHeight) {
newElementPosition.y = borderRadius;
newElementPosition.height = preferredHeight;
}
}
verticalAlignment = "bottom";
} else {
newElementPosition.y = anchorBox.y + anchorBox.height + arrowHeight;
if (newElementPosition.y + newElementPosition.height + arrowHeight - borderWidth >= totalHeight) {
newElementPosition.height = totalHeight - anchorBox.y - anchorBox.height - borderRadius * 2 - arrowHeight;
if (this._hasFixedHeight && newElementPosition.height < preferredHeight) {
newElementPosition.y = totalHeight - preferredHeight - borderRadius;
newElementPosition.height = preferredHeight;
}
}
verticalAlignment = "top";
}
var horizontalAlignment;
if (anchorBox.x + newElementPosition.width < totalWidth) {
newElementPosition.x = Math.max(borderRadius, anchorBox.x - borderRadius - arrowOffset);
horizontalAlignment = "left";
} else if (newElementPosition.width + borderRadius * 2 < totalWidth) {
newElementPosition.x = totalWidth - newElementPosition.width - borderRadius;
horizontalAlignment = "right";
var arrowRightPosition = Math.max(0, totalWidth - anchorBox.x - anchorBox.width - borderRadius - arrowOffset);
arrowRightPosition += anchorBox.width / 2;
arrowRightPosition = Math.min(arrowRightPosition, newElementPosition.width - borderRadius - arrowOffset);
this._popupArrowElement.style.right = arrowRightPosition + "px";
} else {
newElementPosition.x = borderRadius;
newElementPosition.width = totalWidth - borderRadius * 2;
newElementPosition.height += scrollerWidth;
horizontalAlignment = "left";
if (verticalAlignment === "bottom")
newElementPosition.y -= scrollerWidth;
this._popupArrowElement.style.left = Math.max(0, anchorBox.x - borderRadius * 2 - arrowOffset) + "px";
this._popupArrowElement.style.left += anchorBox.width / 2;
}
this.element.className = "popover custom-popup-vertical-scroll custom-popup-horizontal-scroll " + verticalAlignment + "-" + horizontalAlignment + "-arrow";
this.element.positionAt(newElementPosition.x - borderWidth, newElementPosition.y - borderWidth);
this.element.style.width = newElementPosition.width + borderWidth * 2 + "px";
this.element.style.height = newElementPosition.height + borderWidth * 2 + "px";
}
}
WebInspector.PopoverHelper = function(panelElement, getAnchor, showPopover, onHide, disableOnClick)
{
this._panelElement = panelElement;
this._getAnchor = getAnchor;
this._showPopover = showPopover;
this._onHide = onHide;
this._disableOnClick = !!disableOnClick;
panelElement.addEventListener("mousedown", this._mouseDown.bind(this), false);
panelElement.addEventListener("mousemove", this._mouseMove.bind(this), false);
panelElement.addEventListener("mouseout", this._mouseOut.bind(this), false);
this.setTimeout(1000);
}
WebInspector.PopoverHelper.prototype = {
setTimeout: function(timeout)
{
this._timeout = timeout;
},
_mouseDown: function(event)
{
if (this._disableOnClick)
this.hidePopover();
else {
this._killHidePopoverTimer();
this._handleMouseAction(event, true);
}
},
_mouseMove: function(event)
{
if (event.target.isSelfOrDescendant(this._hoverElement))
return;
this._startHidePopoverTimer();
this._handleMouseAction(event, false);
},
_mouseOut: function(event)
{
if (event.target === this._hoverElement)
this._startHidePopoverTimer();
},
_startHidePopoverTimer: function()
{
if (!this._popover || this._hidePopoverTimer)
return;
function doHide()
{
this._hidePopover();
delete this._hidePopoverTimer;
}
this._hidePopoverTimer = setTimeout(doHide.bind(this), this._timeout / 2);
},
_handleMouseAction: function(event, isMouseDown)
{
this._resetHoverTimer();
if (event.which && this._disableOnClick)
return;
this._hoverElement = this._getAnchor(event.target, event);
if (!this._hoverElement)
return;
const toolTipDelay = isMouseDown ? 0 : (this._popup ? this._timeout * 0.6 : this._timeout);
this._hoverTimer = setTimeout(this._mouseHover.bind(this, this._hoverElement), toolTipDelay);
},
_resetHoverTimer: function()
{
if (this._hoverTimer) {
clearTimeout(this._hoverTimer);
delete this._hoverTimer;
}
},
isPopoverVisible: function()
{
return !!this._popover;
},
hidePopover: function()
{
this._resetHoverTimer();
this._hidePopover();
},
_hidePopover: function()
{
if (!this._popover)
return;
if (this._onHide)
this._onHide();
this._popover.dispose();
delete this._popover;
this._hoverElement = null;
},
_mouseHover: function(element)
{
delete this._hoverTimer;
this._hidePopover();
this._popover = new WebInspector.Popover(this);
this._showPopover(element, this._popover);
},
_killHidePopoverTimer: function()
{
if (this._hidePopoverTimer) {
clearTimeout(this._hidePopoverTimer);
delete this._hidePopoverTimer;
this._resetHoverTimer();
}
}
}