summaryrefslogtreecommitdiffstats
path: root/WebCore/page/inspector/inspector.js
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/page/inspector/inspector.js')
-rw-r--r--WebCore/page/inspector/inspector.js1186
1 files changed, 1186 insertions, 0 deletions
diff --git a/WebCore/page/inspector/inspector.js b/WebCore/page/inspector/inspector.js
new file mode 100644
index 0000000..a9f5fcf
--- /dev/null
+++ b/WebCore/page/inspector/inspector.js
@@ -0,0 +1,1186 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Matt Lilek (pewtermoose@gmail.com).
+ *
+ * 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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.
+ */
+
+var Preferences = {
+ ignoreWhitespace: true,
+ showUserAgentStyles: true,
+ maxInlineTextChildLength: 80,
+ maxTextSearchResultLength: 80,
+ showInheritedComputedStyleProperties: false,
+ showMissingLocalizedStrings: false
+}
+
+var WebInspector = {
+ resources: [],
+ resourceURLMap: {},
+ backForwardList: [],
+ searchResultsHeight: 100,
+ localizedStrings: {},
+ missingLocalizedStrings: {},
+
+ get consolePanel()
+ {
+ if (!this._consolePanel)
+ this._consolePanel = new WebInspector.ConsolePanel();
+
+ return this._consolePanel;
+ },
+
+ get networkPanel()
+ {
+ if (!this._networkPanel)
+ this._networkPanel = new WebInspector.NetworkPanel();
+
+ return this._networkPanel;
+ },
+
+ get currentBackForwardIndex()
+ {
+ if (this._currentBackForwardIndex === undefined)
+ this._currentBackForwardIndex = -1;
+
+ return this._currentBackForwardIndex;
+ },
+
+ set currentBackForwardIndex(x)
+ {
+ if (this._currentBackForwardIndex === x)
+ return;
+
+ this._currentBackForwardIndex = x;
+ this.updateBackForwardButtons();
+ },
+
+ get currentFocusElement()
+ {
+ return this._currentFocusElement;
+ },
+
+ set currentFocusElement(x)
+ {
+ if (!x || this._currentFocusElement === x)
+ return;
+
+ if (this._currentFocusElement) {
+ this._currentFocusElement.removeStyleClass("focused");
+ this._currentFocusElement.addStyleClass("blurred");
+ if (this._currentFocusElement.blurred)
+ this._currentFocusElement.blurred();
+ }
+
+ this._currentFocusElement = x;
+
+ if (x) {
+ x.addStyleClass("focused");
+ x.removeStyleClass("blurred");
+ if (this._currentFocusElement.focused)
+ this._currentFocusElement.focused();
+ }
+ },
+
+ get currentPanel()
+ {
+ return this._currentPanel;
+ },
+
+ set currentPanel(x)
+ {
+ if (this._currentPanel === x)
+ return;
+
+ if (this._currentPanel)
+ this._currentPanel.hide();
+
+ this._currentPanel = x;
+
+ if (x)
+ x.show();
+ },
+
+ get attached()
+ {
+ return this._attached;
+ },
+
+ set attached(x)
+ {
+ if (this._attached === x)
+ return;
+
+ this._attached = x;
+
+ var body = document.body;
+ if (x) {
+ InspectorController.attach();
+ body.removeStyleClass("detached");
+ body.addStyleClass("attached");
+ } else {
+ InspectorController.detach();
+ body.removeStyleClass("attached");
+ body.addStyleClass("detached");
+ }
+ },
+
+ get showingSearchResults()
+ {
+ return this._showingSearchResults;
+ },
+
+ set showingSearchResults(x)
+ {
+ if (this._showingSearchResults === x)
+ return;
+
+ this._showingSearchResults = x;
+
+ var resultsContainer = document.getElementById("searchResults");
+ var searchResultsResizer = document.getElementById("searchResultsResizer");
+
+ if (x) {
+ resultsContainer.removeStyleClass("hidden");
+ searchResultsResizer.removeStyleClass("hidden");
+
+ var animations = [
+ {element: resultsContainer, end: {top: 0}},
+ {element: searchResultsResizer, end: {top: WebInspector.searchResultsHeight - 3}},
+ {element: document.getElementById("panels"), end: {top: WebInspector.searchResultsHeight}}
+ ];
+
+ WebInspector.animateStyle(animations, 250);
+ } else {
+ searchResultsResizer.addStyleClass("hidden");
+
+ var animations = [
+ {element: resultsContainer, end: {top: -WebInspector.searchResultsHeight}},
+ {element: searchResultsResizer, end: {top: 0}},
+ {element: document.getElementById("panels"), end: {top: 0}}
+ ];
+
+ var animationFinished = function()
+ {
+ resultsContainer.addStyleClass("hidden");
+ resultsContainer.removeChildren();
+ delete this.searchResultsTree;
+ };
+
+ WebInspector.animateStyle(animations, 250, animationFinished);
+ }
+ }
+}
+
+WebInspector.loaded = function()
+{
+ var platform = InspectorController.platform();
+ document.body.addStyleClass("platform-" + platform);
+
+ this.fileOutline = new TreeOutline(document.getElementById("list"));
+ this.fileOutline.expandTreeElementsWhenArrowing = true;
+
+ this.statusOutline = new TreeOutline(document.getElementById("status"));
+ this.statusOutline.expandTreeElementsWhenArrowing = true;
+
+ this.resourceCategories = {
+ documents: new WebInspector.ResourceCategory(WebInspector.UIString("documents"), "documents"),
+ stylesheets: new WebInspector.ResourceCategory(WebInspector.UIString("stylesheets"), "stylesheets"),
+ images: new WebInspector.ResourceCategory(WebInspector.UIString("images"), "images"),
+ scripts: new WebInspector.ResourceCategory(WebInspector.UIString("scripts"), "scripts"),
+ fonts: new WebInspector.ResourceCategory(WebInspector.UIString("fonts"), "fonts"),
+ databases: new WebInspector.ResourceCategory(WebInspector.UIString("databases"), "databases"),
+ other: new WebInspector.ResourceCategory(WebInspector.UIString("other"), "other")
+ };
+
+ this.Tips = {
+ ResourceNotCompressed: {id: 0, message: WebInspector.UIString("You could save bandwidth by having your web server compress this transfer with gzip or zlib.")}
+ };
+
+ this.Warnings = {
+ IncorrectMIMEType: {id: 0, message: WebInspector.UIString("Resource interpreted as %s but transferred with MIME type %s.")}
+ };
+
+ this.consoleListItem = new WebInspector.ConsoleStatusTreeElement(WebInspector.consolePanel);
+ this.statusOutline.appendChild(this.consoleListItem);
+
+ this.networkListItem = new WebInspector.StatusTreeElement(WebInspector.UIString("Network"), "network", WebInspector.networkPanel);
+ this.statusOutline.appendChild(this.networkListItem);
+
+ this.resourceCategories.documents.listItem.expand();
+
+ this.currentFocusElement = document.getElementById("sidebar");
+
+ this.addMainEventListeners(document);
+
+ window.addEventListener("unload", this.windowUnload.bind(this), true);
+ window.addEventListener("resize", this.windowResize.bind(this), true);
+
+ document.addEventListener("mousedown", this.changeFocus.bind(this), true);
+ document.addEventListener("focus", this.changeFocus.bind(this), true);
+ document.addEventListener("keydown", this.documentKeyDown.bind(this), true);
+ document.addEventListener("beforecopy", this.documentCanCopy.bind(this), true);
+ document.addEventListener("copy", this.documentCopy.bind(this), true);
+
+ document.getElementById("back").title = WebInspector.UIString("Show previous panel.");
+ document.getElementById("forward").title = WebInspector.UIString("Show next panel.");
+
+ document.getElementById("search").setAttribute("placeholder", WebInspector.UIString("Search"));
+
+ document.getElementById("back").addEventListener("click", this.back.bind(this), true);
+ document.getElementById("forward").addEventListener("click", this.forward.bind(this), true);
+ this.updateBackForwardButtons();
+
+ document.getElementById("attachToggle").addEventListener("click", this.toggleAttach.bind(this), true);
+
+ document.getElementById("sidebarResizeWidget").addEventListener("mousedown", this.sidebarResizerDragStart, true);
+ document.getElementById("sidebarResizer").addEventListener("mousedown", this.sidebarResizerDragStart, true);
+ document.getElementById("searchResultsResizer").addEventListener("mousedown", this.searchResultsResizerDragStart, true);
+
+ if (platform === "mac-leopard")
+ document.getElementById("toolbar").addEventListener("mousedown", this.toolbarDragStart, true);
+
+ document.body.addStyleClass("detached");
+
+ InspectorController.loaded();
+}
+
+var windowLoaded = function()
+{
+ var localizedStringsURL = InspectorController.localizedStringsURL();
+ if (localizedStringsURL) {
+ var localizedStringsScriptElement = document.createElement("script");
+ localizedStringsScriptElement.addEventListener("load", WebInspector.loaded.bind(WebInspector), false);
+ localizedStringsScriptElement.type = "text/javascript";
+ localizedStringsScriptElement.src = localizedStringsURL;
+ document.getElementsByTagName("head").item(0).appendChild(localizedStringsScriptElement);
+ } else
+ WebInspector.loaded();
+
+ window.removeEventListener("load", windowLoaded, false);
+ delete windowLoaded;
+};
+
+window.addEventListener("load", windowLoaded, false);
+
+WebInspector.windowUnload = function(event)
+{
+ InspectorController.windowUnloading();
+}
+
+WebInspector.windowResize = function(event)
+{
+ if (this.currentPanel && this.currentPanel.resize)
+ this.currentPanel.resize();
+}
+
+WebInspector.windowFocused = function(event)
+{
+ if (event.target.nodeType === Node.DOCUMENT_NODE)
+ document.body.removeStyleClass("inactive");
+}
+
+WebInspector.windowBlured = function(event)
+{
+ if (event.target.nodeType === Node.DOCUMENT_NODE)
+ document.body.addStyleClass("inactive");
+}
+
+WebInspector.changeFocus = function(event)
+{
+ var nextFocusElement;
+
+ var current = event.target;
+ while (current) {
+ if (current.nodeName.toLowerCase() === "input")
+ nextFocusElement = current;
+ current = current.parentNode;
+ }
+
+ if (!nextFocusElement)
+ nextFocusElement = event.target.firstParentWithClass("focusable");
+
+ this.currentFocusElement = nextFocusElement;
+}
+
+WebInspector.documentClick = function(event)
+{
+ var anchor = event.target.firstParentOrSelfWithNodeName("a");
+ if (!anchor || !anchor.hasStyleClass("webkit-html-resource-link"))
+ return;
+
+ if (WebInspector.showResourceForURL(anchor.getAttribute("href"))) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+}
+
+WebInspector.documentKeyDown = function(event)
+{
+ if (!this.currentFocusElement)
+ return;
+ if (this.currentFocusElement.handleKeyEvent)
+ this.currentFocusElement.handleKeyEvent(event);
+ else if (this.currentFocusElement.id && this.currentFocusElement.id.length && WebInspector[this.currentFocusElement.id + "KeyDown"])
+ WebInspector[this.currentFocusElement.id + "KeyDown"](event);
+}
+
+WebInspector.documentCanCopy = function(event)
+{
+ if (!this.currentFocusElement)
+ return;
+ // Calling preventDefault() will say "we support copying, so enable the Copy menu".
+ if (this.currentFocusElement.handleCopyEvent)
+ event.preventDefault();
+ else if (this.currentFocusElement.id && this.currentFocusElement.id.length && WebInspector[this.currentFocusElement.id + "Copy"])
+ event.preventDefault();
+}
+
+WebInspector.documentCopy = function(event)
+{
+ if (!this.currentFocusElement)
+ return;
+ if (this.currentFocusElement.handleCopyEvent)
+ this.currentFocusElement.handleCopyEvent(event);
+ else if (this.currentFocusElement.id && this.currentFocusElement.id.length && WebInspector[this.currentFocusElement.id + "Copy"])
+ WebInspector[this.currentFocusElement.id + "Copy"](event);
+}
+
+WebInspector.sidebarKeyDown = function(event)
+{
+ var nextSelectedElement;
+
+ if (this.fileOutline.selectedTreeElement) {
+ if (!this.fileOutline.handleKeyEvent(event) && event.keyIdentifier === "Down" && !event.altKey) {
+ var nextSelectedElement = this.statusOutline.children[0];
+ while (nextSelectedElement && !nextSelectedElement.selectable)
+ nextSelectedElement = nextSelectedElement.traverseNextTreeElement(false);
+ }
+ } else if (this.statusOutline.selectedTreeElement) {
+ if (!this.statusOutline.handleKeyEvent(event) && event.keyIdentifier === "Up" && !event.altKey) {
+ var nextSelectedElement = this.fileOutline.children[0];
+ var lastSelectable = null;
+
+ while (nextSelectedElement) {
+ if (nextSelectedElement.selectable)
+ lastSelectable = nextSelectedElement;
+ nextSelectedElement = nextSelectedElement.traverseNextTreeElement(false);
+ }
+
+ nextSelectedElement = lastSelectable;
+ }
+ }
+
+ if (nextSelectedElement) {
+ nextSelectedElement.reveal();
+ nextSelectedElement.select();
+
+ event.preventDefault();
+ event.stopPropagation();
+ }
+}
+
+WebInspector.sidebarCopy = function(event)
+{
+ event.clipboardData.clearData();
+ event.preventDefault();
+
+ var selectedElement = this.fileOutline.selectedTreeElement;
+ if (!selectedElement || !selectedElement.representedObject || !selectedElement.representedObject.url)
+ return;
+
+ event.clipboardData.setData("URL", this.fileOutline.selectedTreeElement.representedObject.url);
+}
+
+WebInspector.mainKeyDown = function(event)
+{
+ if (this.currentPanel && this.currentPanel.handleKeyEvent)
+ this.currentPanel.handleKeyEvent(event);
+}
+
+WebInspector.mainCopy = function(event)
+{
+ if (this.currentPanel && this.currentPanel.handleCopyEvent)
+ this.currentPanel.handleCopyEvent(event);
+}
+
+WebInspector.searchResultsKeyDown = function(event)
+{
+ if (this.searchResultsTree)
+ this.searchResultsTree.handleKeyEvent(event);
+}
+
+WebInspector.animateStyle = function(animations, duration, callback, complete)
+{
+ if (complete === undefined)
+ complete = 0;
+ var slice = (1000 / 30); // 30 frames per second
+
+ var defaultUnit = "px";
+ var propertyUnit = {opacity: ""};
+
+ for (var i = 0; i < animations.length; ++i) {
+ var animation = animations[i];
+ var element = null;
+ var start = null;
+ var current = null;
+ var end = null;
+ for (key in animation) {
+ if (key === "element")
+ element = animation[key];
+ else if (key === "start")
+ start = animation[key];
+ else if (key === "current")
+ current = animation[key];
+ else if (key === "end")
+ end = animation[key];
+ }
+
+ if (!element || !end)
+ continue;
+
+ var computedStyle = element.ownerDocument.defaultView.getComputedStyle(element);
+ if (!start) {
+ start = {};
+ for (key in end)
+ start[key] = parseInt(computedStyle.getPropertyValue(key));
+ animation.start = start;
+ } else if (complete == 0)
+ for (key in start)
+ element.style.setProperty(key, start[key] + (key in propertyUnit ? propertyUnit[key] : defaultUnit));
+
+ if (!current) {
+ current = {};
+ for (key in start)
+ current[key] = start[key];
+ animation.current = current;
+ }
+
+ function cubicInOut(t, b, c, d)
+ {
+ if ((t/=d/2) < 1) return c/2*t*t*t + b;
+ return c/2*((t-=2)*t*t + 2) + b;
+ }
+
+ var style = element.style;
+ for (key in end) {
+ var startValue = start[key];
+ var currentValue = current[key];
+ var endValue = end[key];
+ if ((complete + slice) < duration) {
+ var delta = (endValue - startValue) / (duration / slice);
+ var newValue = cubicInOut(complete, startValue, endValue - startValue, duration);
+ style.setProperty(key, newValue + (key in propertyUnit ? propertyUnit[key] : defaultUnit));
+ current[key] = newValue;
+ } else {
+ style.setProperty(key, endValue + (key in propertyUnit ? propertyUnit[key] : defaultUnit));
+ }
+ }
+ }
+
+ if (complete < duration)
+ setTimeout(WebInspector.animateStyle, slice, animations, duration, callback, complete + slice);
+ else if (callback)
+ callback();
+}
+
+WebInspector.toggleAttach = function()
+{
+ this.attached = !this.attached;
+}
+
+WebInspector.toolbarDragStart = function(event)
+{
+ var toolbar = document.getElementById("toolbar");
+ if (event.target !== toolbar || WebInspector.attached)
+ return;
+
+ toolbar.lastScreenX = event.screenX;
+ toolbar.lastScreenY = event.screenY;
+
+ document.addEventListener("mousemove", WebInspector.toolbarDrag, true);
+ document.addEventListener("mouseup", WebInspector.toolbarDragEnd, true);
+ document.body.style.cursor = "default";
+
+ event.preventDefault();
+}
+
+WebInspector.toolbarDragEnd = function(event)
+{
+ var toolbar = document.getElementById("toolbar");
+ delete toolbar.lastScreenX;
+ delete toolbar.lastScreenY;
+
+ document.removeEventListener("mousemove", WebInspector.toolbarDrag, true);
+ document.removeEventListener("mouseup", WebInspector.toolbarDragEnd, true);
+ document.body.style.removeProperty("cursor");
+
+ event.preventDefault();
+}
+
+WebInspector.toolbarDrag = function(event)
+{
+ var toolbar = document.getElementById("toolbar");
+
+ var x = event.screenX - toolbar.lastScreenX;
+ var y = event.screenY - toolbar.lastScreenY;
+
+ toolbar.lastScreenX = event.screenX;
+ toolbar.lastScreenY = event.screenY;
+
+ // We cannot call window.moveBy here because it restricts the movement of the window
+ // at the edges.
+ InspectorController.moveByUnrestricted(x, y);
+
+ event.preventDefault();
+}
+
+WebInspector.sidebarResizerDragStart = function(event)
+{
+ WebInspector.elementDragStart(document.getElementById("sidebar"), WebInspector.sidebarResizerDrag, WebInspector.sidebarResizerDragEnd, event, "col-resize");
+}
+
+WebInspector.sidebarResizerDragEnd = function(event)
+{
+ WebInspector.elementDragEnd(document.getElementById("sidebar"), WebInspector.sidebarResizerDrag, WebInspector.sidebarResizerDragEnd, event);
+}
+
+WebInspector.sidebarResizerDrag = function(event)
+{
+ var x = event.pageX;
+
+ // FIXME: We can should come up with a better hueristic for constraining the size of the sidebar.
+ var newWidth = Number.constrain(x, 100, window.innerWidth - 100);
+
+ document.getElementById("sidebar").style.width = newWidth + "px";
+ document.getElementById("sidebarResizer").style.left = (newWidth - 3) + "px";
+ document.getElementById("main").style.left = newWidth + "px";
+ document.getElementById("toolbarButtons").style.left = newWidth + "px";
+
+ if (WebInspector.currentPanel && WebInspector.currentPanel.resize)
+ WebInspector.currentPanel.resize();
+
+ event.preventDefault();
+}
+
+WebInspector.searchResultsResizerDragStart = function(event)
+{
+ WebInspector.elementDragStart(document.getElementById("searchResults"), WebInspector.searchResultsResizerDrag, WebInspector.searchResultsResizerDragEnd, event, "row-resize");
+}
+
+WebInspector.searchResultsResizerDragEnd = function(event)
+{
+ WebInspector.elementDragEnd(document.getElementById("searchResults"), WebInspector.searchResultsResizerDrag, WebInspector.searchResultsResizerDragEnd, event);
+}
+
+WebInspector.searchResultsResizerDrag = function(event)
+{
+ var y = event.pageY - document.getElementById("main").offsetTop;
+ var newHeight = Number.constrain(y, 100, window.innerHeight - 100);
+
+ WebInspector.searchResultsHeight = newHeight;
+
+ document.getElementById("searchResults").style.height = WebInspector.searchResultsHeight + "px";
+ document.getElementById("panels").style.top = newHeight + "px";
+ document.getElementById("searchResultsResizer").style.top = (newHeight - 3) + "px";
+
+ event.preventDefault();
+}
+
+WebInspector.elementDragStart = function(element, dividerDrag, elementDragEnd, event, cursor)
+{
+ if (WebInspector.draggingElement)
+ return elementDragEnd(event);
+
+ WebInspector.draggingElement = true;
+
+ document.addEventListener("mousemove", dividerDrag, true);
+ document.addEventListener("mouseup", elementDragEnd, true);
+ document.body.style.cursor = cursor;
+
+ event.preventDefault();
+}
+
+WebInspector.elementDragEnd = function(element, dividerDrag, elementDragEnd, event)
+{
+ document.removeEventListener("mousemove", dividerDrag, true);
+ document.removeEventListener("mouseup", elementDragEnd, true);
+ document.body.style.removeProperty("cursor");
+
+ delete WebInspector.draggingElement;
+
+ event.preventDefault();
+}
+
+WebInspector.back = function()
+{
+ if (this.currentBackForwardIndex <= 0) {
+ console.error("Can't go back from index " + this.currentBackForwardIndex);
+ return;
+ }
+
+ this.navigateToPanel(this.backForwardList[--this.currentBackForwardIndex], null, true);
+}
+
+WebInspector.forward = function()
+{
+ if (this.currentBackForwardIndex >= this.backForwardList.length - 1) {
+ console.error("Can't go forward from index " + this.currentBackForwardIndex);
+ return;
+ }
+
+ this.navigateToPanel(this.backForwardList[++this.currentBackForwardIndex], null, true);
+}
+
+WebInspector.updateBackForwardButtons = function()
+{
+ var index = this.currentBackForwardIndex;
+
+ document.getElementById("back").disabled = index <= 0;
+ document.getElementById("forward").disabled = index >= this.backForwardList.length - 1;
+}
+
+WebInspector.showConsole = function()
+{
+ this.navigateToPanel(WebInspector.consolePanel);
+}
+
+WebInspector.showTimeline = function()
+{
+ this.navigateToPanel(WebInspector.networkPanel);
+}
+
+WebInspector.addResource = function(resource)
+{
+ this.resources.push(resource);
+
+ if (resource.mainResource)
+ this.mainResource = resource;
+
+ if (resource.url) {
+ this.resourceURLMap[resource.url] = resource;
+ this.networkPanel.addResourceToTimeline(resource);
+ }
+}
+
+WebInspector.removeResource = function(resource)
+{
+ resource.detach();
+
+ resource.category.removeResource(resource);
+
+ if (resource.url)
+ delete this.resourceURLMap[resource.url];
+
+ var resourcesLength = this.resources.length;
+ for (var i = 0; i < resourcesLength; ++i) {
+ if (this.resources[i] === resource) {
+ this.resources.splice(i, 1);
+ break;
+ }
+ }
+}
+
+WebInspector.clearResources = function()
+{
+ for (var category in this.resourceCategories)
+ this.resourceCategories[category].removeAllResources();
+ this.resources = [];
+ this.backForwardList = [];
+ this.currentBackForwardIndex = -1;
+ delete this.mainResource;
+}
+
+WebInspector.clearDatabaseResources = function()
+{
+ this.resourceCategories.databases.removeAllResources();
+}
+
+WebInspector.resourceURLChanged = function(resource, oldURL)
+{
+ delete this.resourceURLMap[oldURL];
+ this.resourceURLMap[resource.url] = resource;
+}
+
+WebInspector.addMessageToConsole = function(msg)
+{
+ this.consolePanel.addMessage(msg);
+ switch (msg.level) {
+ case WebInspector.ConsoleMessage.MessageLevel.Warning:
+ ++this.consoleListItem.warnings;
+ break;
+ case WebInspector.ConsoleMessage.MessageLevel.Error:
+ ++this.consoleListItem.errors;
+ break;
+ }
+}
+
+WebInspector.clearConsoleMessages = function()
+{
+ this.consolePanel.clearMessages();
+ this.consoleListItem.warnings = this.consoleListItem.errors = 0;
+}
+
+WebInspector.clearNetworkTimeline = function()
+{
+ if (this._networkPanel)
+ this._networkPanel.clearTimeline();
+}
+
+WebInspector.drawLoadingPieChart = function(canvas, percent) {
+ var g = canvas.getContext("2d");
+ var darkColor = "rgb(122, 168, 218)";
+ var lightColor = "rgb(228, 241, 251)";
+ var cx = 8;
+ var cy = 8;
+ var r = 7;
+
+ g.beginPath();
+ g.arc(cx, cy, r, 0, Math.PI * 2, false);
+ g.closePath();
+
+ g.lineWidth = 1;
+ g.strokeStyle = darkColor;
+ g.fillStyle = lightColor;
+ g.fill();
+ g.stroke();
+
+ var startangle = -Math.PI / 2;
+ var endangle = startangle + (percent * Math.PI * 2);
+
+ g.beginPath();
+ g.moveTo(cx, cy);
+ g.arc(cx, cy, r, startangle, endangle, false);
+ g.closePath();
+
+ g.fillStyle = darkColor;
+ g.fill();
+}
+
+WebInspector.updateFocusedNode = function(node)
+{
+ if (!node)
+ // FIXME: Should we deselect if null is passed in?
+ return;
+
+ for (var i = 0; i < this.resourceCategories.documents.resources.length; ++i) {
+ var resource = this.resourceCategories.documents.resources[i];
+ if (resource.documentNode !== node.ownerDocument)
+ continue;
+
+ this.navigateToPanel(resource.panel, "dom");
+ resource.panel.focusedDOMNode = node;
+
+ this.currentFocusElement = document.getElementById("main");
+
+ break;
+ }
+}
+
+WebInspector.resourceForURL = function(url)
+{
+ for (var resourceURL in this.resourceURLMap) {
+ if (resourceURL.hasSubstring(url))
+ return this.resourceURLMap[resourceURL];
+ }
+
+ return null;
+}
+
+WebInspector.showResourceForURL = function(url)
+{
+ var resource = this.resourceForURL(url);
+ if (!resource)
+ return false;
+
+ this.navigateToResource(resource);
+ return true;
+}
+
+WebInspector.linkifyURL = function(url, linkText, classes, isExternal)
+{
+ if (linkText === undefined)
+ linkText = url.escapeHTML();
+ classes = (classes === undefined) ? "" : classes + " ";
+ classes += isExternal ? "webkit-html-external-link" : "webkit-html-resource-link";
+ var link = "<a href=\"" + url + "\" class=\"" + classes + "\" title=\"" + url + "\" target=\"_blank\">" + linkText + "</a>";
+ return link;
+}
+
+WebInspector.addMainEventListeners = function(doc)
+{
+ doc.defaultView.addEventListener("focus", function(event) { WebInspector.windowFocused(event) }, true);
+ doc.defaultView.addEventListener("blur", function(event) { WebInspector.windowBlured(event) }, true);
+ doc.addEventListener("click", function(event) { WebInspector.documentClick(event) }, true);
+}
+
+WebInspector.performSearch = function(query)
+{
+ if (!query || !query.length) {
+ this.showingSearchResults = false;
+ return;
+ }
+
+ var resultsContainer = document.getElementById("searchResults");
+ resultsContainer.removeChildren();
+
+ var isXPath = query.indexOf("/") !== -1;
+
+ var xpathQuery;
+ if (isXPath)
+ xpathQuery = query;
+ else {
+ var escapedQuery = query.escapeCharacters("'");
+ xpathQuery = "//*[contains(name(),'" + escapedQuery + "') or contains(@*,'" + escapedQuery + "')] | //text()[contains(.,'" + escapedQuery + "')] | //comment()[contains(.,'" + escapedQuery + "')]";
+ }
+
+ var resourcesToSearch = [].concat(this.resourceCategories.documents.resources, this.resourceCategories.stylesheets.resources, this.resourceCategories.scripts.resources, this.resourceCategories.other.resources);
+
+ var files = [];
+ for (var i = 0; i < resourcesToSearch.length; ++i) {
+ var resource = resourcesToSearch[i];
+
+ var sourceResults = [];
+ if (!isXPath && "source" in resource.panel.views) {
+ resource.panel.setupSourceFrameIfNeeded();
+ sourceResults = InspectorController.search(resource.panel.views.source.frameElement.contentDocument, query);
+ }
+
+ var domResults = [];
+ const searchResultsProperty = "__includedInInspectorSearchResults";
+ function addNodesToDOMResults(nodes, length, getItem)
+ {
+ for (var i = 0; i < length; ++i) {
+ var node = getItem(nodes, i);
+ if (searchResultsProperty in node)
+ continue;
+ node[searchResultsProperty] = true;
+ domResults.push(node);
+ }
+ }
+
+ function cleanUpDOMResultsNodes()
+ {
+ for (var i = 0; i < domResults.length; ++i)
+ delete domResults[i][searchResultsProperty];
+ }
+
+ if (resource.category === this.resourceCategories.documents) {
+ var doc = resource.documentNode;
+ try {
+ var result = Document.prototype.evaluate.call(doc, xpathQuery, doc, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE);
+ addNodesToDOMResults(result, result.snapshotLength, function(l, i) { return l.snapshotItem(i); });
+ } catch(err) {
+ // ignore any exceptions. the query might be malformed, but we allow that.
+ }
+
+ var result = Document.prototype.querySelectorAll.call(doc, query);
+ addNodesToDOMResults(result, result.length, function(l, i) { return l.item(i); });
+
+ cleanUpDOMResultsNodes();
+ }
+
+ if ((!sourceResults || !sourceResults.length) && !domResults.length)
+ continue;
+
+ files.push({resource: resource, sourceResults: sourceResults, domResults: domResults});
+ }
+
+ if (!files.length)
+ return;
+
+ this.showingSearchResults = true;
+
+ var fileList = document.createElement("ol");
+ fileList.className = "outline-disclosure";
+ resultsContainer.appendChild(fileList);
+
+ this.searchResultsTree = new TreeOutline(fileList);
+ this.searchResultsTree.expandTreeElementsWhenArrowing = true;
+
+ var sourceResultSelected = function(element)
+ {
+ var selection = window.getSelection();
+ selection.removeAllRanges();
+ selection.addRange(element.representedObject.range);
+
+ WebInspector.navigateToPanel(element.representedObject.panel, "source");
+ element.representedObject.line.scrollIntoViewIfNeeded(true);
+ element.listItemElement.scrollIntoViewIfNeeded(false);
+ }
+
+ var domResultSelected = function(element)
+ {
+ WebInspector.navigateToPanel(element.representedObject.panel, "dom");
+ element.representedObject.panel.focusedDOMNode = element.representedObject.node;
+ element.listItemElement.scrollIntoViewIfNeeded(false);
+ }
+
+ for (var i = 0; i < files.length; ++i) {
+ var file = files[i];
+
+ var fileItem = new TreeElement(file.resource.displayName, {}, true);
+ fileItem.expanded = true;
+ fileItem.selectable = false;
+ this.searchResultsTree.appendChild(fileItem);
+
+ if (file.sourceResults && file.sourceResults.length) {
+ for (var j = 0; j < file.sourceResults.length; ++j) {
+ var range = file.sourceResults[j];
+
+ var line = range.startContainer;
+ while (line.parentNode && line.nodeName.toLowerCase() != "tr")
+ line = line.parentNode;
+ var lineRange = file.resource.panel.views.source.frameElement.contentDocument.createRange();
+ lineRange.selectNodeContents(line);
+
+ // Don't include any error bubbles in the search result
+ var end = line.lastChild.lastChild;
+ if (end.nodeName.toLowerCase() == "div" && end.hasStyleClass("webkit-html-message-bubble")) {
+ while (end && end.nodeName.toLowerCase() == "div" && end.hasStyleClass("webkit-html-message-bubble"))
+ end = end.previousSibling;
+ lineRange.setEndAfter(end);
+ }
+
+ var beforeRange = file.resource.panel.views.source.frameElement.contentDocument.createRange();
+ beforeRange.setStart(lineRange.startContainer, lineRange.startOffset);
+ beforeRange.setEnd(range.startContainer, range.startOffset);
+
+ var afterRange = file.resource.panel.views.source.frameElement.contentDocument.createRange();
+ afterRange.setStart(range.endContainer, range.endOffset);
+ afterRange.setEnd(lineRange.endContainer, lineRange.endOffset);
+
+ var beforeText = beforeRange.toString().trimLeadingWhitespace();
+ var text = range.toString();
+ var afterText = afterRange.toString().trimTrailingWhitespace();
+
+ var length = beforeText.length + text.length + afterText.length;
+ if (length > Preferences.maxTextSearchResultLength) {
+ var beforeAfterLength = (Preferences.maxTextSearchResultLength - text.length) / 2;
+ if (beforeText.length > beforeAfterLength)
+ beforeText = "\u2026" + beforeText.substr(-beforeAfterLength);
+ if (afterText.length > beforeAfterLength)
+ afterText = afterText.substr(0, beforeAfterLength) + "\u2026";
+ }
+
+ var title = "<div class=\"selection selected\"></div>";
+ if (j == 0)
+ title += "<div class=\"search-results-section\">" + WebInspector.UIString("Source") + "</div>";
+ title += beforeText.escapeHTML() + "<span class=\"search-matched-string\">" + text.escapeHTML() + "</span>" + afterText.escapeHTML();
+ var item = new TreeElement(title, {panel: file.resource.panel, line: line, range: range}, false);
+ item.onselect = sourceResultSelected;
+ fileItem.appendChild(item);
+ }
+ }
+
+ if (file.domResults.length) {
+ for (var j = 0; j < file.domResults.length; ++j) {
+ var node = file.domResults[j];
+ var title = "<div class=\"selection selected\"></div>";
+ if (j == 0)
+ title += "<div class=\"search-results-section\">" + WebInspector.UIString("DOM") + "</div>";
+ title += nodeTitleInfo.call(node).title;
+ var item = new TreeElement(title, {panel: file.resource.panel, node: node}, false);
+ item.onselect = domResultSelected;
+ fileItem.appendChild(item);
+ }
+ }
+ }
+}
+
+WebInspector.navigateToResource = function(resource)
+{
+ this.navigateToPanel(resource.panel);
+}
+
+WebInspector.navigateToPanel = function(panel, view, fromBackForwardAction)
+{
+ if (this.currentPanel === panel) {
+ if (panel && view)
+ panel.currentView = view;
+ return;
+ }
+
+ if (!fromBackForwardAction) {
+ var oldIndex = this.currentBackForwardIndex;
+ if (oldIndex >= 0)
+ this.backForwardList.splice(oldIndex + 1, this.backForwardList.length - oldIndex);
+ this.currentBackForwardIndex++;
+ this.backForwardList.push(panel);
+ }
+
+ this.currentPanel = panel;
+ if (panel && view)
+ panel.currentView = view;
+}
+
+WebInspector.UIString = function(string)
+{
+ if (string in this.localizedStrings)
+ string = this.localizedStrings[string];
+ else {
+ if (!(string in this.missingLocalizedStrings)) {
+ console.error("Localized string \"" + string + "\" not found.");
+ this.missingLocalizedStrings[string] = true;
+ }
+
+ if (Preferences.showMissingLocalizedStrings)
+ string += " (not localized)";
+ }
+
+ return String.vsprintf(string, Array.prototype.slice.call(arguments, 1));
+}
+
+WebInspector.StatusTreeElement = function(title, iconClass, panel)
+{
+ TreeElement.call(this, "<span class=\"title only\">" + title + "</span><span class=\"icon " + iconClass + "\"></span>", null, false);
+ this.panel = panel;
+}
+
+WebInspector.StatusTreeElement.prototype = {
+ onselect: function()
+ {
+ var selectedElement = WebInspector.fileOutline.selectedTreeElement;
+ if (selectedElement)
+ selectedElement.deselect();
+ if (this.panel)
+ WebInspector.navigateToPanel(this.panel);
+ },
+
+ ondeselect: function()
+ {
+ if (this.panel)
+ this.panel.hide();
+ }
+}
+
+WebInspector.StatusTreeElement.prototype.__proto__ = TreeElement.prototype;
+
+WebInspector.ConsoleStatusTreeElement = function(panel)
+{
+ WebInspector.StatusTreeElement.call(this, WebInspector.UIString("Console"), "console", panel);
+}
+
+WebInspector.ConsoleStatusTreeElement.prototype = {
+ get warnings()
+ {
+ if (!("_warnings" in this))
+ this._warnings = 0;
+
+ return this._warnings;
+ },
+
+ set warnings(x)
+ {
+ if (this._warnings === x)
+ return;
+
+ this._warnings = x;
+
+ this._updateTitle();
+ },
+
+ get errors()
+ {
+ if (!("_errors" in this))
+ this._errors = 0;
+
+ return this._errors;
+ },
+
+ set errors(x)
+ {
+ if (this._errors === x)
+ return;
+
+ this._errors = x;
+
+ this._updateTitle();
+ },
+
+ _updateTitle: function()
+ {
+ var title = "<span class=\"title";
+ if (!this.warnings && !this.errors)
+ title += " only";
+ title += "\">" + WebInspector.UIString("Console") + "</span><span class=\"icon console\"></span>";
+
+ if (this.warnings || this.errors) {
+ title += "<span class=\"info\">";
+ if (this.errors) {
+ title += this.errors + " error";
+ if (this.errors > 1)
+ title += "s";
+ }
+ if (this.warnings) {
+ if (this.errors)
+ title += ", ";
+ title += this.warnings + " warning";
+ if (this.warnings > 1)
+ title += "s";
+ }
+ title += "</span>";
+ }
+
+ this.title = title;
+ }
+}
+
+WebInspector.ConsoleStatusTreeElement.prototype.__proto__ = WebInspector.StatusTreeElement.prototype;
+
+// This table maps MIME types to the Resource.Types which are valid for them.
+// The following line:
+// "text/html": {0: 1},
+// means that text/html is a valid MIME type for resources that have type
+// WebInspector.Resource.Type.Document (which has a value of 0).
+WebInspector.MIMETypes = {
+ "text/html": {0: true},
+ "text/xml": {0: true},
+ "text/plain": {0: true},
+ "application/xhtml+xml": {0: true},
+ "text/css": {1: true},
+ "text/xsl": {1: true},
+ "image/jpeg": {2: true},
+ "image/png": {2: true},
+ "image/gif": {2: true},
+ "image/bmp": {2: true},
+ "image/x-icon": {2: true},
+ "image/x-xbitmap": {2: true},
+ "font/ttf": {3: true},
+ "font/opentype": {3: true},
+ "application/x-font-type1": {3: true},
+ "application/x-font-ttf": {3: true},
+ "application/x-truetype-font": {3: true},
+ "text/javascript": {4: true},
+ "text/ecmascript": {4: true},
+ "application/javascript": {4: true},
+ "application/ecmascript": {4: true},
+ "application/x-javascript": {4: true},
+ "text/javascript1.1": {4: true},
+ "text/javascript1.2": {4: true},
+ "text/javascript1.3": {4: true},
+ "text/jscript": {4: true},
+ "text/livescript": {4: true},
+}