diff options
Diffstat (limited to 'Source/WebInspectorUI/UserInterface/Popover.js')
-rw-r--r-- | Source/WebInspectorUI/UserInterface/Popover.js | 482 |
1 files changed, 0 insertions, 482 deletions
diff --git a/Source/WebInspectorUI/UserInterface/Popover.js b/Source/WebInspectorUI/UserInterface/Popover.js deleted file mode 100644 index e9b84bd63..000000000 --- a/Source/WebInspectorUI/UserInterface/Popover.js +++ /dev/null @@ -1,482 +0,0 @@ -/* - * Copyright (C) 2013 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -WebInspector.Popover = function(delegate) { - WebInspector.Object.call(this); - - this.delegate = delegate; - this._edge = null; - this._frame = new WebInspector.Rect; - this._content = null; - this._targetFrame = new WebInspector.Rect; - this._preferredEdges = null; - - this._contentNeedsUpdate = false; - - this._element = document.createElement("div"); - this._element.className = WebInspector.Popover.StyleClassName; - this._canvasId = "popover-" + (WebInspector.Popover.canvasId++); - this._element.style.backgroundImage = "-webkit-canvas(" + this._canvasId + ")"; - this._element.addEventListener("transitionend", this, true); - - this._container = this._element.appendChild(document.createElement("div")); - this._container.className = "container"; -}; - -WebInspector.Popover.StyleClassName = "popover"; -WebInspector.Popover.FadeOutClassName = "fade-out"; -WebInspector.Popover.canvasId = 0; -WebInspector.Popover.CornerRadius = 5; -WebInspector.Popover.MinWidth = 40; -WebInspector.Popover.MinHeight = 40; -WebInspector.Popover.ShadowPadding = 5; -WebInspector.Popover.ContentPadding = 5; -WebInspector.Popover.AnchorSize = new WebInspector.Size(22, 11); -WebInspector.Popover.ShadowEdgeInsets = new WebInspector.EdgeInsets(WebInspector.Popover.ShadowPadding); - -WebInspector.Popover.prototype = { - constructor: WebInspector.Popover, - - // Public - - get element() - { - return this._element; - }, - - get frame() - { - return this._frame; - }, - - get visible() - { - return this._element.parentNode === document.body && !this._element.classList.contains(WebInspector.Popover.FadeOutClassName); - }, - - set frame(frame) - { - this._element.style.left = frame.origin.x + "px"; - this._element.style.top = frame.origin.y + "px"; - this._element.style.width = frame.size.width + "px"; - this._element.style.height = frame.size.height + "px"; - this._element.style.backgroundSize = frame.size.width + "px " + frame.size.height + "px"; - this._frame = frame; - }, - - set content(content) - { - if (content === this._content) - return; - - this._content = content; - - this._contentNeedsUpdate = true; - - if (this.visible) - this._update(); - }, - - update: function() - { - if (!this.visible) - return; - - var previouslyFocusedElement = document.activeElement; - - this._contentNeedsUpdate = true; - this._update(); - - if (previouslyFocusedElement) - previouslyFocusedElement.focus(); - }, - - /** - * @param {WebInspector.Rect} targetFrame - * @param {WebInspector.RectEdge}[] preferredEdges - */ - present: function(targetFrame, preferredEdges) - { - this._targetFrame = targetFrame; - this._preferredEdges = preferredEdges; - - if (!this._content) - return; - - window.addEventListener("mousedown", this, true); - window.addEventListener("scroll", this, true); - - this._update(); - }, - - dismiss: function() - { - if (this._element.parentNode !== document.body) - return; - - window.removeEventListener("mousedown", this, true); - window.removeEventListener("scroll", this, true); - - this._element.classList.add(WebInspector.Popover.FadeOutClassName); - - if (this.delegate && typeof this.delegate.willDismissPopover === "function") - this.delegate.willDismissPopover(this); - }, - - handleEvent: function(event) - { - switch (event.type) { - case "mousedown": - case "scroll": - if (!this._element.contains(event.target)) - this.dismiss(); - break; - case "transitionend": - document.body.removeChild(this._element); - this._element.classList.remove(WebInspector.Popover.FadeOutClassName); - this._container.textContent = ""; - if (this.delegate && typeof this.delegate.didDismissPopover === "function") - this.delegate.didDismissPopover(this); - break; - } - }, - - // Private - - _update: function() - { - var targetFrame = this._targetFrame; - var preferredEdges = this._preferredEdges; - - // Ensure our element is on display so that its metrics can be resolved - // or interrupt any pending transition to remove it from display. - if (this._element.parentNode !== document.body) - document.body.appendChild(this._element); - else - this._element.classList.remove(WebInspector.Popover.FadeOutClassName); - - if (this._contentNeedsUpdate) { - // Reset CSS properties on element so that the element may be sized to fit its content. - this._element.style.removeProperty("left"); - this._element.style.removeProperty("top"); - this._element.style.removeProperty("width"); - this._element.style.removeProperty("height"); - if (this._edge !== null) - this._element.classList.remove(this._cssClassNameForEdge()); - - // Add the content in place of the wrapper to get the raw metrics. - this._element.replaceChild(this._content, this._container); - - // Get the ideal size for the popover to fit its content. - var popoverBounds = this._element.getBoundingClientRect(); - this._preferredSize = new WebInspector.Size(Math.ceil(popoverBounds.width), Math.ceil(popoverBounds.height)); - } - - // The frame of the window with a little inset to make sure we have room for shadows. - var containerFrame = new WebInspector.Rect(0, 0, window.innerWidth, window.innerHeight); - containerFrame = containerFrame.inset(WebInspector.Popover.ShadowEdgeInsets); - - // Work out the metrics for all edges. - var metrics = new Array(preferredEdges.length); - for (var edgeName in WebInspector.RectEdge) { - var edge = WebInspector.RectEdge[edgeName]; - var item = { - edge: edge, - metrics: this._bestMetricsForEdge(this._preferredSize, targetFrame, containerFrame, edge) - }; - var preferredIndex = preferredEdges.indexOf(edge); - if (preferredIndex !== -1) - metrics[preferredIndex] = item; - else - metrics.push(item); - } - - function area(size) - { - return size.width * size.height; - } - - // Find if any of those fit better than the frame for the preferred edge. - var bestEdge = metrics[0].edge; - var bestMetrics = metrics[0].metrics; - for (var i = 1; i < metrics.length; i++) { - var itemMetrics = metrics[i].metrics; - if (area(itemMetrics.contentSize) > area(bestMetrics.contentSize)) { - bestEdge = metrics[i].edge; - bestMetrics = itemMetrics; - } - } - - var anchorPoint; - var bestFrame = bestMetrics.frame; - - this.frame = bestFrame; - this._edge = bestEdge; - - if (this.frame === WebInspector.Rect.ZERO_RECT) { - // The target for the popover is offscreen. - this.dismiss(); - } else { - switch (bestEdge) { - case WebInspector.RectEdge.MIN_X: // Displayed on the left of the target, arrow points right. - anchorPoint = new WebInspector.Point(bestFrame.size.width - WebInspector.Popover.ShadowPadding, targetFrame.midY() - bestFrame.minY()); - break; - case WebInspector.RectEdge.MAX_X: // Displayed on the right of the target, arrow points left. - anchorPoint = new WebInspector.Point(WebInspector.Popover.ShadowPadding, targetFrame.midY() - bestFrame.minY()); - break; - case WebInspector.RectEdge.MIN_Y: // Displayed above the target, arrow points down. - anchorPoint = new WebInspector.Point(targetFrame.midX() - bestFrame.minX(), bestFrame.size.height - WebInspector.Popover.ShadowPadding); - break; - case WebInspector.RectEdge.MAX_Y: // Displayed below the target, arrow points up. - anchorPoint = new WebInspector.Point(targetFrame.midX() - bestFrame.minX(), WebInspector.Popover.ShadowPadding); - break; - } - - this._element.classList.add(this._cssClassNameForEdge()); - - this._drawBackground(bestEdge, anchorPoint); - - // Make sure content is centered in case either of the dimension is smaller than the minimal bounds. - if (this._preferredSize.width < WebInspector.Popover.MinWidth || this._preferredSize.height < WebInspector.Popover.MinHeight) - this._container.classList.add("center"); - else - this._container.classList.remove("center"); - } - - // Wrap the content in the container so that it's located correctly. - if (this._contentNeedsUpdate) { - this._container.textContent = ""; - this._element.replaceChild(this._container, this._content); - this._container.appendChild(this._content); - } - - this._contentNeedsUpdate = false; - }, - - _cssClassNameForEdge: function() - { - switch (this._edge) { - case WebInspector.RectEdge.MIN_X: // Displayed on the left of the target, arrow points right. - return "arrow-right"; - case WebInspector.RectEdge.MAX_X: // Displayed on the right of the target, arrow points left. - return "arrow-left"; - case WebInspector.RectEdge.MIN_Y: // Displayed above the target, arrow points down. - return "arrow-down"; - case WebInspector.RectEdge.MAX_Y: // Displayed below the target, arrow points up. - return "arrow-up"; - } - console.error("Unknown edge."); - return "arrow-up"; - }, - - _drawBackground: function(edge, anchorPoint) - { - var scaleFactor = window.devicePixelRatio; - - var width = this._frame.size.width; - var height = this._frame.size.height; - var scaledWidth = width * scaleFactor; - var scaledHeight = height * scaleFactor; - - // Create a scratch canvas so we can draw the popover that will later be drawn into - // the final context with a shadow. - var scratchCanvas = document.createElement("canvas"); - scratchCanvas.width = scaledWidth; - scratchCanvas.height = scaledHeight; - - var ctx = scratchCanvas.getContext("2d"); - ctx.scale(scaleFactor, scaleFactor); - - // Bounds of the path don't take into account the arrow, but really only the tight bounding box - // of the content contained within the frame. - var bounds; - var arrowHeight = WebInspector.Popover.AnchorSize.height; - switch (edge) { - case WebInspector.RectEdge.MIN_X: // Displayed on the left of the target, arrow points right. - bounds = new WebInspector.Rect(0, 0, width - arrowHeight, height); - break; - case WebInspector.RectEdge.MAX_X: // Displayed on the right of the target, arrow points left. - bounds = new WebInspector.Rect(arrowHeight, 0, width - arrowHeight, height); - break; - case WebInspector.RectEdge.MIN_Y: // Displayed above the target, arrow points down. - bounds = new WebInspector.Rect(0, 0, width, height - arrowHeight); - break; - case WebInspector.RectEdge.MAX_Y: // Displayed below the target, arrow points up. - bounds = new WebInspector.Rect(0, arrowHeight, width, height - arrowHeight); - break; - } - - bounds = bounds.inset(WebInspector.Popover.ShadowEdgeInsets); - - // Clip the frame. - ctx.fillStyle = "black"; - this._drawFrame(ctx, bounds, edge, anchorPoint); - ctx.clip(); - - // Gradient fill, top-to-bottom. - var fillGradient = ctx.createLinearGradient(0, 0, 0, height); - fillGradient.addColorStop(0, "rgba(255, 255, 255, 0.95)"); - fillGradient.addColorStop(1, "rgba(235, 235, 235, 0.95)"); - ctx.fillStyle = fillGradient; - ctx.fillRect(0, 0, width, height); - - // Stroke. - ctx.strokeStyle = "rgba(0, 0, 0, 0.25)"; - ctx.lineWidth = 2; - this._drawFrame(ctx, bounds, edge, anchorPoint); - ctx.stroke(); - - // Draw the popover into the final context with a drop shadow. - var finalContext = document.getCSSCanvasContext("2d", this._canvasId, scaledWidth, scaledHeight); - - finalContext.clearRect(0, 0, scaledWidth, scaledHeight); - - finalContext.shadowOffsetX = 1; - finalContext.shadowOffsetY = 1; - finalContext.shadowBlur = 5; - finalContext.shadowColor = "rgba(0, 0, 0, 0.5)"; - - finalContext.drawImage(scratchCanvas, 0, 0, scaledWidth, scaledHeight); - }, - - _bestMetricsForEdge: function(preferredSize, targetFrame, containerFrame, edge) - { - var x, y; - var width = preferredSize.width + (WebInspector.Popover.ShadowPadding * 2) + (WebInspector.Popover.ContentPadding * 2); - var height = preferredSize.height + (WebInspector.Popover.ShadowPadding * 2) + (WebInspector.Popover.ContentPadding * 2); - var arrowLength = WebInspector.Popover.AnchorSize.height; - - switch (edge) { - case WebInspector.RectEdge.MIN_X: // Displayed on the left of the target, arrow points right. - width += arrowLength; - x = targetFrame.origin.x - width + WebInspector.Popover.ShadowPadding; - y = targetFrame.origin.y - (height - targetFrame.size.height) / 2; - break; - case WebInspector.RectEdge.MAX_X: // Displayed on the right of the target, arrow points left. - width += arrowLength; - x = targetFrame.origin.x + targetFrame.size.width - WebInspector.Popover.ShadowPadding; - y = targetFrame.origin.y - (height - targetFrame.size.height) / 2; - break; - case WebInspector.RectEdge.MIN_Y: // Displayed above the target, arrow points down. - height += arrowLength; - x = targetFrame.origin.x - (width - targetFrame.size.width) / 2; - y = targetFrame.origin.y - height + WebInspector.Popover.ShadowPadding; - break; - case WebInspector.RectEdge.MAX_Y: // Displayed below the target, arrow points up. - height += arrowLength; - x = targetFrame.origin.x - (width - targetFrame.size.width) / 2; - y = targetFrame.origin.y + targetFrame.size.height - WebInspector.Popover.ShadowPadding; - break; - } - - if (edge === WebInspector.RectEdge.MIN_X || edge === WebInspector.RectEdge.MAX_X) { - if (y < containerFrame.minY()) - y = containerFrame.minY(); - if (y + height > containerFrame.maxY()) - y = containerFrame.maxY() - height; - } else { - if (x < containerFrame.minX()) - x = containerFrame.minX(); - if (x + width > containerFrame.maxX()) - x = containerFrame.maxX() - width; - } - - var preferredFrame = new WebInspector.Rect(x, y, width, height); - var bestFrame = preferredFrame.intersectionWithRect(containerFrame); - - width = bestFrame.size.width - (WebInspector.Popover.ShadowPadding * 2); - height = bestFrame.size.height - (WebInspector.Popover.ShadowPadding * 2); - - switch (edge) { - case WebInspector.RectEdge.MIN_X: // Displayed on the left of the target, arrow points right. - case WebInspector.RectEdge.MAX_X: // Displayed on the right of the target, arrow points left. - width -= arrowLength; - break; - case WebInspector.RectEdge.MIN_Y: // Displayed above the target, arrow points down. - case WebInspector.RectEdge.MAX_Y: // Displayed below the target, arrow points up. - height -= arrowLength; - break; - } - - return { - frame: bestFrame, - contentSize: new WebInspector.Size(width, height) - }; - }, - - _drawFrame: function(ctx, bounds, anchorEdge, anchorPoint) - { - var r = WebInspector.Popover.CornerRadius; - var arrowHalfLength = WebInspector.Popover.AnchorSize.width / 2; - - ctx.beginPath(); - switch (anchorEdge) { - case WebInspector.RectEdge.MIN_X: // Displayed on the left of the target, arrow points right. - ctx.moveTo(bounds.maxX(), bounds.minY() + r); - ctx.lineTo(bounds.maxX(), anchorPoint.y - arrowHalfLength); - ctx.lineTo(anchorPoint.x, anchorPoint.y); - ctx.lineTo(bounds.maxX(), anchorPoint.y + arrowHalfLength); - ctx.arcTo(bounds.maxX(), bounds.maxY(), bounds.minX(), bounds.maxY(), r); - ctx.arcTo(bounds.minX(), bounds.maxY(), bounds.minX(), bounds.minY(), r); - ctx.arcTo(bounds.minX(), bounds.minY(), bounds.maxX(), bounds.minY(), r); - ctx.arcTo(bounds.maxX(), bounds.minY(), bounds.maxX(), bounds.maxY(), r); - break; - case WebInspector.RectEdge.MAX_X: // Displayed on the right of the target, arrow points left. - ctx.moveTo(bounds.minX(), bounds.maxY() - r); - ctx.lineTo(bounds.minX(), anchorPoint.y + arrowHalfLength); - ctx.lineTo(anchorPoint.x, anchorPoint.y); - ctx.lineTo(bounds.minX(), anchorPoint.y - arrowHalfLength); - ctx.arcTo(bounds.minX(), bounds.minY(), bounds.maxX(), bounds.minY(), r); - ctx.arcTo(bounds.maxX(), bounds.minY(), bounds.maxX(), bounds.maxY(), r); - ctx.arcTo(bounds.maxX(), bounds.maxY(), bounds.minX(), bounds.maxY(), r); - ctx.arcTo(bounds.minX(), bounds.maxY(), bounds.minX(), bounds.minY(), r); - break; - case WebInspector.RectEdge.MIN_Y: // Displayed above the target, arrow points down. - ctx.moveTo(bounds.maxX() - r, bounds.maxY()); - ctx.lineTo(anchorPoint.x + arrowHalfLength, bounds.maxY()); - ctx.lineTo(anchorPoint.x, anchorPoint.y); - ctx.lineTo(anchorPoint.x - arrowHalfLength, bounds.maxY()); - ctx.arcTo(bounds.minX(), bounds.maxY(), bounds.minX(), bounds.minY(), r); - ctx.arcTo(bounds.minX(), bounds.minY(), bounds.maxX(), bounds.minY(), r); - ctx.arcTo(bounds.maxX(), bounds.minY(), bounds.maxX(), bounds.maxY(), r); - ctx.arcTo(bounds.maxX(), bounds.maxY(), bounds.minX(), bounds.maxY(), r); - break; - case WebInspector.RectEdge.MAX_Y: // Displayed below the target, arrow points up. - ctx.moveTo(bounds.minX() + r, bounds.minY()); - ctx.lineTo(anchorPoint.x - arrowHalfLength, bounds.minY()); - ctx.lineTo(anchorPoint.x, anchorPoint.y); - ctx.lineTo(anchorPoint.x + arrowHalfLength, bounds.minY()); - ctx.arcTo(bounds.maxX(), bounds.minY(), bounds.maxX(), bounds.maxY(), r); - ctx.arcTo(bounds.maxX(), bounds.maxY(), bounds.minX(), bounds.maxY(), r); - ctx.arcTo(bounds.minX(), bounds.maxY(), bounds.minX(), bounds.minY(), r); - ctx.arcTo(bounds.minX(), bounds.minY(), bounds.maxX(), bounds.minY(), r); - break; - } - ctx.closePath(); - } - -}; - -WebInspector.Popover.prototype.__proto__ = WebInspector.Object.prototype; |