diff options
author | tc@google.com <tc@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-08 22:19:09 +0000 |
---|---|---|
committer | tc@google.com <tc@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-08 22:19:09 +0000 |
commit | a0de6f0ff1da1a860cd5b492d45aecc6654afa99 (patch) | |
tree | a7e05b2b217b504691ff7b0a2670556133027c9a /chrome/tools | |
parent | ed3d6fff0d4d3ff157e78961a9c3d2d59bffe853 (diff) | |
download | chromium_src-a0de6f0ff1da1a860cd5b492d45aecc6654afa99.zip chromium_src-a0de6f0ff1da1a860cd5b492d45aecc6654afa99.tar.gz chromium_src-a0de6f0ff1da1a860cd5b492d45aecc6654afa99.tar.bz2 |
Enable the startup reference test and check in a reference build on linux.
The reference build is a scons Release build cut at r15674.
Review URL: http://codereview.chromium.org/116002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15689 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/tools')
179 files changed, 27723 insertions, 0 deletions
diff --git a/chrome/tools/test/reference_build/chrome_linux/chrome b/chrome/tools/test/reference_build/chrome_linux/chrome Binary files differnew file mode 100755 index 0000000..d9c91bf --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/chrome diff --git a/chrome/tools/test/reference_build/chrome_linux/chrome.pak b/chrome/tools/test/reference_build/chrome_linux/chrome.pak Binary files differnew file mode 100644 index 0000000..a1b28e3 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/chrome.pak diff --git a/chrome/tools/test/reference_build/chrome_linux/locales/da.pak b/chrome/tools/test/reference_build/chrome_linux/locales/da.pak Binary files differnew file mode 100644 index 0000000..0a47477 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/locales/da.pak diff --git a/chrome/tools/test/reference_build/chrome_linux/locales/en-US.pak b/chrome/tools/test/reference_build/chrome_linux/locales/en-US.pak Binary files differnew file mode 100644 index 0000000..22ba218 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/locales/en-US.pak diff --git a/chrome/tools/test/reference_build/chrome_linux/locales/he.pak b/chrome/tools/test/reference_build/chrome_linux/locales/he.pak Binary files differnew file mode 100644 index 0000000..a3ac813 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/locales/he.pak diff --git a/chrome/tools/test/reference_build/chrome_linux/locales/zh-TW.pak b/chrome/tools/test/reference_build/chrome_linux/locales/zh-TW.pak Binary files differnew file mode 100644 index 0000000..9d564c5 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/locales/zh-TW.pak diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Breakpoint.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Breakpoint.js new file mode 100644 index 0000000..8611cf5 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Breakpoint.js @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2008 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. ``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 + * 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.Breakpoint = function(url, line, sourceID) +{ + this.url = url; + this.line = line; + this.sourceID = sourceID; + this._enabled = true; +} + +WebInspector.Breakpoint.prototype = { + get enabled() + { + return this._enabled; + }, + + set enabled(x) + { + if (this._enabled === x) + return; + + this._enabled = x; + + if (this._enabled) + this.dispatchEventToListeners("enabled"); + else + this.dispatchEventToListeners("disabled"); + } +} + +WebInspector.Breakpoint.prototype.__proto__ = WebInspector.Object.prototype; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/BreakpointsSidebarPane.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/BreakpointsSidebarPane.js new file mode 100644 index 0000000..2b8f3cd --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/BreakpointsSidebarPane.js @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2008 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. ``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 + * 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.BreakpointsSidebarPane = function() +{ + WebInspector.SidebarPane.call(this, WebInspector.UIString("Breakpoints")); + + this.breakpoints = []; + + this.emptyElement = document.createElement("div"); + this.emptyElement.className = "info"; + this.emptyElement.textContent = WebInspector.UIString("No Breakpoints"); + + this.bodyElement.appendChild(this.emptyElement); +} + +WebInspector.BreakpointsSidebarPane.prototype = { + addBreakpoint: function(breakpoint) + { + this.breakpoints.push(breakpoint); + breakpoint.addEventListener("enabled", this._breakpointEnableChanged, this); + breakpoint.addEventListener("disabled", this._breakpointEnableChanged, this); + + // FIXME: add to the breakpoints UI. + + if (!InspectorController.debuggerEnabled() || !breakpoint.sourceID) + return; + + if (breakpoint.enabled) + InspectorController.addBreakpoint(breakpoint.sourceID, breakpoint.line); + }, + + removeBreakpoint: function(breakpoint) + { + this.breakpoints.remove(breakpoint); + breakpoint.removeEventListener("enabled", null, this); + breakpoint.removeEventListener("disabled", null, this); + + // FIXME: remove from the breakpoints UI. + + if (!InspectorController.debuggerEnabled() || !breakpoint.sourceID) + return; + + InspectorController.removeBreakpoint(breakpoint.sourceID, breakpoint.line); + }, + + _breakpointEnableChanged: function(event) + { + var breakpoint = event.target; + + // FIXME: change the breakpoint checkbox state in the UI. + + if (!InspectorController.debuggerEnabled() || !breakpoint.sourceID) + return; + + if (breakpoint.enabled) + InspectorController.addBreakpoint(breakpoint.sourceID, breakpoint.line); + else + InspectorController.removeBreakpoint(breakpoint.sourceID, breakpoint.line); + } +} + +WebInspector.BreakpointsSidebarPane.prototype.__proto__ = WebInspector.SidebarPane.prototype; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/CallStackSidebarPane.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/CallStackSidebarPane.js new file mode 100644 index 0000000..a2c8bed --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/CallStackSidebarPane.js @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2008 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. ``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 + * 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.CallStackSidebarPane = function() +{ + WebInspector.SidebarPane.call(this, WebInspector.UIString("Call Stack")); +} + +WebInspector.CallStackSidebarPane.prototype = { + update: function(callFrame, sourceIDMap) + { + this.bodyElement.removeChildren(); + + this.placards = []; + delete this._selectedCallFrame; + + if (!callFrame) { + var infoElement = document.createElement("div"); + infoElement.className = "info"; + infoElement.textContent = WebInspector.UIString("Not Paused"); + this.bodyElement.appendChild(infoElement); + return; + } + + var title; + var subtitle; + var scriptOrResource; + + do { + switch (callFrame.type) { + case "function": + title = callFrame.functionName || WebInspector.UIString("(anonymous function)"); + break; + case "program": + title = WebInspector.UIString("(program)"); + break; + } + + scriptOrResource = sourceIDMap[callFrame.sourceID]; + subtitle = WebInspector.displayNameForURL(scriptOrResource.sourceURL || scriptOrResource.url); + + if (callFrame.line > 0) { + if (subtitle) + subtitle += ":" + callFrame.line; + else + subtitle = WebInspector.UIString("line %d", callFrame.line); + } + + var placard = new WebInspector.Placard(title, subtitle); + placard.callFrame = callFrame; + + placard.element.addEventListener("click", this._placardSelected.bind(this), false); + + this.placards.push(placard); + this.bodyElement.appendChild(placard.element); + + callFrame = callFrame.caller; + } while (callFrame); + }, + + get selectedCallFrame() + { + return this._selectedCallFrame; + }, + + set selectedCallFrame(x) + { + if (this._selectedCallFrame === x) + return; + + this._selectedCallFrame = x; + + for (var i = 0; i < this.placards.length; ++i) { + var placard = this.placards[i]; + placard.selected = (placard.callFrame === this._selectedCallFrame); + } + + this.dispatchEventToListeners("call frame selected"); + }, + + _placardSelected: function(event) + { + var placardElement = event.target.enclosingNodeOrSelfWithClass("placard"); + this.selectedCallFrame = placardElement.placard.callFrame; + } +} + +WebInspector.CallStackSidebarPane.prototype.__proto__ = WebInspector.SidebarPane.prototype; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Console.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Console.js new file mode 100644 index 0000000..ba879a0 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Console.js @@ -0,0 +1,937 @@ +/* + * Copyright (C) 2007, 2008 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. + * 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. + */ + +WebInspector.Console = function() +{ + this.messages = []; + + WebInspector.View.call(this, document.getElementById("console")); + + this.messagesElement = document.getElementById("console-messages"); + this.messagesElement.addEventListener("selectstart", this._messagesSelectStart.bind(this), false); + this.messagesElement.addEventListener("click", this._messagesClicked.bind(this), true); + + this.promptElement = document.getElementById("console-prompt"); + this.promptElement.handleKeyEvent = this._promptKeyDown.bind(this); + this.prompt = new WebInspector.TextPrompt(this.promptElement, this.completions.bind(this), " .=:[({;"); + + this.toggleButton = document.getElementById("console-status-bar-item"); + this.toggleButton.title = WebInspector.UIString("Show console."); + this.toggleButton.addEventListener("click", this._toggleButtonClicked.bind(this), false); + + this.clearButton = document.getElementById("clear-console-status-bar-item"); + this.clearButton.title = WebInspector.UIString("Clear console log."); + this.clearButton.addEventListener("click", this._clearButtonClicked.bind(this), false); + + this.topGroup = new WebInspector.ConsoleGroup(null, 0); + this.messagesElement.insertBefore(this.topGroup.element, this.promptElement); + this.groupLevel = 0; + this.currentGroup = this.topGroup; + + document.getElementById("main-status-bar").addEventListener("mousedown", this._startStatusBarDragging.bind(this), true); +} + +WebInspector.Console.prototype = { + show: function() + { + if (this._animating || this.visible) + return; + + WebInspector.View.prototype.show.call(this); + + this._animating = true; + + this.toggleButton.addStyleClass("toggled-on"); + this.toggleButton.title = WebInspector.UIString("Hide console."); + + document.body.addStyleClass("console-visible"); + + var anchoredItems = document.getElementById("anchored-status-bar-items"); + + var animations = [ + {element: document.getElementById("main"), end: {bottom: this.element.offsetHeight}}, + {element: document.getElementById("main-status-bar"), start: {"padding-left": anchoredItems.offsetWidth - 1}, end: {"padding-left": 0}}, + {element: document.getElementById("other-console-status-bar-items"), start: {opacity: 0}, end: {opacity: 1}} + ]; + + var consoleStatusBar = document.getElementById("console-status-bar"); + consoleStatusBar.insertBefore(anchoredItems, consoleStatusBar.firstChild); + + function animationFinished() + { + if ("updateStatusBarItems" in WebInspector.currentPanel) + WebInspector.currentPanel.updateStatusBarItems(); + WebInspector.currentFocusElement = this.promptElement; + delete this._animating; + } + + WebInspector.animateStyle(animations, window.event && window.event.shiftKey ? 2000 : 250, animationFinished.bind(this)); + + if (!this.prompt.isCaretInsidePrompt()) + this.prompt.moveCaretToEndOfPrompt(); + }, + + hide: function() + { + if (this._animating || !this.visible) + return; + + WebInspector.View.prototype.hide.call(this); + + this._animating = true; + + this.toggleButton.removeStyleClass("toggled-on"); + this.toggleButton.title = WebInspector.UIString("Show console."); + + if (this.element === WebInspector.currentFocusElement || this.element.isAncestor(WebInspector.currentFocusElement)) + WebInspector.currentFocusElement = WebInspector.previousFocusElement; + + var anchoredItems = document.getElementById("anchored-status-bar-items"); + + // Temporally set properties and classes to mimic the post-animation values so panels + // like Elements in their updateStatusBarItems call will size things to fit the final location. + document.getElementById("main-status-bar").style.setProperty("padding-left", (anchoredItems.offsetWidth - 1) + "px"); + document.body.removeStyleClass("console-visible"); + if ("updateStatusBarItems" in WebInspector.currentPanel) + WebInspector.currentPanel.updateStatusBarItems(); + document.body.addStyleClass("console-visible"); + + var animations = [ + {element: document.getElementById("main"), end: {bottom: 0}}, + {element: document.getElementById("main-status-bar"), start: {"padding-left": 0}, end: {"padding-left": anchoredItems.offsetWidth - 1}}, + {element: document.getElementById("other-console-status-bar-items"), start: {opacity: 1}, end: {opacity: 0}} + ]; + + function animationFinished() + { + var mainStatusBar = document.getElementById("main-status-bar"); + mainStatusBar.insertBefore(anchoredItems, mainStatusBar.firstChild); + mainStatusBar.style.removeProperty("padding-left"); + document.body.removeStyleClass("console-visible"); + delete this._animating; + } + + WebInspector.animateStyle(animations, window.event && window.event.shiftKey ? 2000 : 250, animationFinished.bind(this)); + }, + + addMessage: function(msg) + { + if (msg instanceof WebInspector.ConsoleMessage && !(msg instanceof WebInspector.ConsoleCommandResult)) { + msg.totalRepeatCount = msg.repeatCount; + msg.repeatDelta = msg.repeatCount; + + var messageRepeated = false; + + if (msg.isEqual && msg.isEqual(this.previousMessage)) { + // Because sometimes we get a large number of repeated messages and sometimes + // we get them one at a time, we need to know the difference between how many + // repeats we used to have and how many we have now. + msg.repeatDelta -= this.previousMessage.totalRepeatCount; + + if (!isNaN(this.repeatCountBeforeCommand)) + msg.repeatCount -= this.repeatCountBeforeCommand; + + if (!this.commandSincePreviousMessage) { + // Recreate the previous message element to reset the repeat count. + var messagesElement = this.currentGroup.messagesElement; + messagesElement.removeChild(messagesElement.lastChild); + messagesElement.appendChild(msg.toMessageElement()); + + messageRepeated = true; + } + } else + delete this.repeatCountBeforeCommand; + + // Increment the error or warning count + switch (msg.level) { + case WebInspector.ConsoleMessage.MessageLevel.Warning: + WebInspector.warnings += msg.repeatDelta; + break; + case WebInspector.ConsoleMessage.MessageLevel.Error: + WebInspector.errors += msg.repeatDelta; + break; + } + + // Add message to the resource panel + if (msg.url in WebInspector.resourceURLMap) { + msg.resource = WebInspector.resourceURLMap[msg.url]; + if (WebInspector.panels.resources) + WebInspector.panels.resources.addMessageToResource(msg.resource, msg); + } + + this.commandSincePreviousMessage = false; + this.previousMessage = msg; + + if (messageRepeated) + return; + } else if (msg instanceof WebInspector.ConsoleCommand) { + if (this.previousMessage) { + this.commandSincePreviousMessage = true; + this.repeatCountBeforeCommand = this.previousMessage.totalRepeatCount; + } + } + + this.messages.push(msg); + + if (msg.level === WebInspector.ConsoleMessage.MessageLevel.EndGroup) { + if (this.groupLevel < 1) + return; + + this.groupLevel--; + + this.currentGroup = this.currentGroup.parentGroup; + } else { + if (msg.level === WebInspector.ConsoleMessage.MessageLevel.StartGroup) { + this.groupLevel++; + + var group = new WebInspector.ConsoleGroup(this.currentGroup, this.groupLevel); + this.currentGroup.messagesElement.appendChild(group.element); + this.currentGroup = group; + } + + this.currentGroup.addMessage(msg); + } + + this.promptElement.scrollIntoView(false); + }, + + clearMessages: function(clearInspectorController) + { + if (clearInspectorController) + InspectorController.clearMessages(); + if (WebInspector.panels.resources) + WebInspector.panels.resources.clearMessages(); + + this.messages = []; + + this.groupLevel = 0; + this.currentGroup = this.topGroup; + this.topGroup.messagesElement.removeChildren(); + + WebInspector.errors = 0; + WebInspector.warnings = 0; + + delete this.commandSincePreviousMessage; + delete this.repeatCountBeforeCommand; + delete this.previousMessage; + }, + + completions: function(wordRange, bestMatchOnly) + { + // Pass less stop characters to rangeOfWord so the range will be a more complete expression. + const expressionStopCharacters = " =:{;"; + var expressionRange = wordRange.startContainer.rangeOfWord(wordRange.startOffset, expressionStopCharacters, this.promptElement, "backward"); + var expressionString = expressionRange.toString(); + var lastIndex = expressionString.length - 1; + + var dotNotation = (expressionString[lastIndex] === "."); + var bracketNotation = (expressionString[lastIndex] === "["); + + if (dotNotation || bracketNotation) + expressionString = expressionString.substr(0, lastIndex); + + var prefix = wordRange.toString(); + if (!expressionString && !prefix) + return; + + var result; + if (expressionString) { + try { + result = this._evalInInspectedWindow(expressionString); + } catch(e) { + // Do nothing, the prefix will be considered a window property. + } + } else { + // There is no expressionString, so the completion should happen against global properties. + // Or if the debugger is paused, against properties in scope of the selected call frame. + if (WebInspector.panels.scripts && WebInspector.panels.scripts.paused) + result = WebInspector.panels.scripts.variablesInScopeForSelectedCallFrame(); + else + result = InspectorController.inspectedWindow(); + } + + if (bracketNotation) { + if (prefix.length && prefix[0] === "'") + var quoteUsed = "'"; + else + var quoteUsed = "\""; + } + + var results = []; + var properties = Object.sortedProperties(result); + for (var i = 0; i < properties.length; ++i) { + var property = properties[i]; + + if (dotNotation && !/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(property)) + continue; + + if (bracketNotation) { + if (!/^[0-9]+$/.test(property)) + property = quoteUsed + property.escapeCharacters(quoteUsed + "\\") + quoteUsed; + property += "]"; + } + + if (property.length < prefix.length) + continue; + if (property.indexOf(prefix) !== 0) + continue; + + results.push(property); + if (bestMatchOnly) + break; + } + + return results; + }, + + _toggleButtonClicked: function() + { + this.visible = !this.visible; + }, + + _clearButtonClicked: function() + { + this.clearMessages(true); + }, + + _messagesSelectStart: function(event) + { + if (this._selectionTimeout) + clearTimeout(this._selectionTimeout); + + this.prompt.clearAutoComplete(); + + function moveBackIfOutside() + { + delete this._selectionTimeout; + if (!this.prompt.isCaretInsidePrompt() && window.getSelection().isCollapsed) + this.prompt.moveCaretToEndOfPrompt(); + this.prompt.autoCompleteSoon(); + } + + this._selectionTimeout = setTimeout(moveBackIfOutside.bind(this), 100); + }, + + _messagesClicked: function(event) + { + var link = event.target.enclosingNodeOrSelfWithNodeName("a"); + if (!link || !link.representedNode) + return; + + WebInspector.updateFocusedNode(link.representedNode); + event.stopPropagation(); + event.preventDefault(); + }, + + _promptKeyDown: function(event) + { + switch (event.keyIdentifier) { + case "Enter": + this._enterKeyPressed(event); + return; + } + + this.prompt.handleKeyEvent(event); + }, + + _startStatusBarDragging: function(event) + { + if (!this.visible || event.target !== document.getElementById("main-status-bar")) + return; + + WebInspector.elementDragStart(document.getElementById("main-status-bar"), this._statusBarDragging.bind(this), this._endStatusBarDragging.bind(this), event, "row-resize"); + + this._statusBarDragOffset = event.pageY - this.element.totalOffsetTop; + + event.stopPropagation(); + }, + + _statusBarDragging: function(event) + { + var mainElement = document.getElementById("main"); + + var height = window.innerHeight - event.pageY + this._statusBarDragOffset; + height = Number.constrain(height, Preferences.minConsoleHeight, window.innerHeight - mainElement.totalOffsetTop - Preferences.minConsoleHeight); + + mainElement.style.bottom = height + "px"; + this.element.style.height = height + "px"; + + event.preventDefault(); + event.stopPropagation(); + }, + + _endStatusBarDragging: function(event) + { + WebInspector.elementDragEnd(event); + + delete this._statusBarDragOffset; + + event.stopPropagation(); + }, + + _evalInInspectedWindow: function(expression) + { + if (WebInspector.panels.scripts && WebInspector.panels.scripts.paused) + return WebInspector.panels.scripts.evaluateInSelectedCallFrame(expression); + + var inspectedWindow = InspectorController.inspectedWindow(); + if (!inspectedWindow._inspectorCommandLineAPI) { + inspectedWindow.eval("window._inspectorCommandLineAPI = { \ + $: function() { return document.getElementById.apply(document, arguments) }, \ + $$: function() { return document.querySelectorAll.apply(document, arguments) }, \ + $x: function(xpath, context) { \ + var nodes = []; \ + try { \ + var doc = context || document; \ + var results = doc.evaluate(xpath, doc, null, XPathResult.ANY_TYPE, null); \ + var node; \ + while (node = results.iterateNext()) nodes.push(node); \ + } catch (e) {} \ + return nodes; \ + }, \ + dir: function() { return console.dir.apply(console, arguments) }, \ + dirxml: function() { return console.dirxml.apply(console, arguments) }, \ + keys: function(o) { var a = []; for (k in o) a.push(k); return a; }, \ + values: function(o) { var a = []; for (k in o) a.push(o[k]); return a; }, \ + profile: function() { return console.profile.apply(console, arguments) }, \ + profileEnd: function() { return console.profileEnd.apply(console, arguments) } \ + };"); + + inspectedWindow._inspectorCommandLineAPI.clear = InspectorController.wrapCallback(this.clearMessages.bind(this)); + } + + // Surround the expression in with statements to inject our command line API so that + // the window object properties still take more precedent than our API functions. + expression = "with (window._inspectorCommandLineAPI) { with (window) { " + expression + " } }"; + + return inspectedWindow.eval(expression); + }, + + _enterKeyPressed: function(event) + { + if (event.altKey) + return; + + event.preventDefault(); + event.stopPropagation(); + + this.prompt.clearAutoComplete(true); + + var str = this.prompt.text; + if (!str.length) + return; + + var commandMessage = new WebInspector.ConsoleCommand(str); + this.addMessage(commandMessage); + + var result; + var exception = false; + try { + result = this._evalInInspectedWindow(str); + } catch(e) { + result = e; + exception = true; + } + + this.prompt.history.push(str); + this.prompt.historyOffset = 0; + this.prompt.text = ""; + + this.addMessage(new WebInspector.ConsoleCommandResult(result, exception, commandMessage)); + }, + + _format: function(output, forceObjectFormat) + { + var type = (forceObjectFormat ? "object" : Object.type(output, InspectorController.inspectedWindow())); + + // We don't perform any special formatting on these types, so we just + // pass them through the simple _formatvalue function. + var undecoratedTypes = { + "undefined": 1, + "null": 1, + "boolean": 1, + "number": 1, + "date": 1, + "function": 1, + }; + + var formatter; + if (forceObjectFormat) + formatter = "_formatobject"; + else if (type in undecoratedTypes) + formatter = "_formatvalue"; + else { + formatter = "_format" + type; + if (!(formatter in this)) { + formatter = "_formatobject"; + type = "object"; + } + } + + var span = document.createElement("span"); + span.addStyleClass("console-formatted-" + type); + this[formatter](output, span); + return span; + }, + + _formatvalue: function(val, elem) + { + elem.appendChild(document.createTextNode(val)); + }, + + _formatstring: function(str, elem) + { + elem.appendChild(document.createTextNode("\"" + str + "\"")); + }, + + _formatregexp: function(re, elem) + { + var formatted = String(re).replace(/([\\\/])/g, "\\$1").replace(/\\(\/[gim]*)$/, "$1").substring(1); + elem.appendChild(document.createTextNode(formatted)); + }, + + _formatarray: function(arr, elem) + { + elem.appendChild(document.createTextNode("[")); + for (var i = 0; i < arr.length; ++i) { + elem.appendChild(this._format(arr[i])); + if (i < arr.length - 1) + elem.appendChild(document.createTextNode(", ")); + } + elem.appendChild(document.createTextNode("]")); + }, + + _formatnode: function(node, elem) + { + var treeOutline = new WebInspector.ElementsTreeOutline(); + treeOutline.rootDOMNode = node; + treeOutline.element.addStyleClass("outline-disclosure"); + if (!treeOutline.children[0].hasChildren) + treeOutline.element.addStyleClass("single-node"); + elem.appendChild(treeOutline.element); + }, + + _formatobject: function(obj, elem) + { + elem.appendChild(new WebInspector.ObjectPropertiesSection(obj, null, null, null, true).element); + }, + + _formaterror: function(obj, elem) + { + var messageElement = document.createElement("span"); + messageElement.className = "error-message"; + messageElement.textContent = obj.name + ": " + obj.message; + elem.appendChild(messageElement); + + if (obj.sourceURL) { + var urlElement = document.createElement("a"); + urlElement.className = "webkit-html-resource-link"; + urlElement.href = obj.sourceURL; + urlElement.lineNumber = obj.line; + urlElement.preferredPanel = "scripts"; + + if (obj.line > 0) + urlElement.textContent = WebInspector.displayNameForURL(obj.sourceURL) + ":" + obj.line; + else + urlElement.textContent = WebInspector.displayNameForURL(obj.sourceURL); + + elem.appendChild(document.createTextNode(" (")); + elem.appendChild(urlElement); + elem.appendChild(document.createTextNode(")")); + } + }, +} + +WebInspector.Console.prototype.__proto__ = WebInspector.View.prototype; + +WebInspector.ConsoleMessage = function(source, level, line, url, groupLevel, repeatCount) +{ + this.source = source; + this.level = level; + this.line = line; + this.url = url; + this.groupLevel = groupLevel; + this.repeatCount = repeatCount; + + switch (this.level) { + case WebInspector.ConsoleMessage.MessageLevel.Trace: + var span = document.createElement("span"); + span.addStyleClass("console-formatted-trace"); + var stack = Array.prototype.slice.call(arguments, 6); + var funcNames = stack.map(function(f) { + return f || WebInspector.UIString("(anonymous function)"); + }); + span.appendChild(document.createTextNode(funcNames.join("\n"))); + this.formattedMessage = span; + break; + case WebInspector.ConsoleMessage.MessageLevel.Object: + this.formattedMessage = this._format(["%O", arguments[6]]); + break; + default: + this.formattedMessage = this._format(Array.prototype.slice.call(arguments, 6)); + break; + } + + // This is used for inline message bubbles in SourceFrames, or other plain-text representations. + this.message = this.formattedMessage.textContent; +} + +WebInspector.ConsoleMessage.prototype = { + isErrorOrWarning: function() + { + return (this.level === WebInspector.ConsoleMessage.MessageLevel.Warning || this.level === WebInspector.ConsoleMessage.MessageLevel.Error); + }, + + _format: function(parameters) + { + var formattedResult = document.createElement("span"); + + if (!parameters.length) + return formattedResult; + + function formatForConsole(obj) + { + return WebInspector.console._format(obj); + } + + function formatAsObjectForConsole(obj) + { + return WebInspector.console._format(obj, true); + } + + if (Object.type(parameters[0], InspectorController.inspectedWindow()) === "string") { + var formatters = {} + for (var i in String.standardFormatters) + formatters[i] = String.standardFormatters[i]; + + // Firebug uses %o for formatting objects. + formatters.o = formatForConsole; + // Firebug allows both %i and %d for formatting integers. + formatters.i = formatters.d; + // Support %O to force object formating, instead of the type-based %o formatting. + formatters.O = formatAsObjectForConsole; + + function append(a, b) + { + if (!(b instanceof Node)) + a.appendChild(WebInspector.linkifyStringAsFragment(b.toString())); + else + a.appendChild(b); + return a; + } + + var result = String.format(parameters[0], parameters.slice(1), formatters, formattedResult, append); + formattedResult = result.formattedResult; + parameters = result.unusedSubstitutions; + if (parameters.length) + formattedResult.appendChild(document.createTextNode(" ")); + } + + for (var i = 0; i < parameters.length; ++i) { + if (typeof parameters[i] === "string") + formattedResult.appendChild(WebInspector.linkifyStringAsFragment(parameters[i])); + else + formattedResult.appendChild(formatForConsole(parameters[i])); + + if (i < parameters.length - 1) + formattedResult.appendChild(document.createTextNode(" ")); + } + + return formattedResult; + }, + + toMessageElement: function() + { + if (this.propertiesSection) + return this.propertiesSection.element; + + var element = document.createElement("div"); + element.message = this; + element.className = "console-message"; + + switch (this.source) { + case WebInspector.ConsoleMessage.MessageSource.HTML: + element.addStyleClass("console-html-source"); + break; + case WebInspector.ConsoleMessage.MessageSource.WML: + element.addStyleClass("console-wml-source"); + break; + case WebInspector.ConsoleMessage.MessageSource.XML: + element.addStyleClass("console-xml-source"); + break; + case WebInspector.ConsoleMessage.MessageSource.JS: + element.addStyleClass("console-js-source"); + break; + case WebInspector.ConsoleMessage.MessageSource.CSS: + element.addStyleClass("console-css-source"); + break; + case WebInspector.ConsoleMessage.MessageSource.Other: + element.addStyleClass("console-other-source"); + break; + } + + switch (this.level) { + case WebInspector.ConsoleMessage.MessageLevel.Tip: + element.addStyleClass("console-tip-level"); + break; + case WebInspector.ConsoleMessage.MessageLevel.Log: + element.addStyleClass("console-log-level"); + break; + case WebInspector.ConsoleMessage.MessageLevel.Warning: + element.addStyleClass("console-warning-level"); + break; + case WebInspector.ConsoleMessage.MessageLevel.Error: + element.addStyleClass("console-error-level"); + break; + case WebInspector.ConsoleMessage.MessageLevel.StartGroup: + element.addStyleClass("console-group-title-level"); + } + + if (this.elementsTreeOutline) { + element.addStyleClass("outline-disclosure"); + element.appendChild(this.elementsTreeOutline.element); + return element; + } + + if (this.repeatCount > 1) { + var messageRepeatCountElement = document.createElement("span"); + messageRepeatCountElement.className = "bubble"; + messageRepeatCountElement.textContent = this.repeatCount; + + element.appendChild(messageRepeatCountElement); + element.addStyleClass("repeated-message"); + } + + if (this.url && this.url !== "undefined") { + var urlElement = document.createElement("a"); + urlElement.className = "console-message-url webkit-html-resource-link"; + urlElement.href = this.url; + urlElement.lineNumber = this.line; + + if (this.source === WebInspector.ConsoleMessage.MessageSource.JS) + urlElement.preferredPanel = "scripts"; + + if (this.line > 0) + urlElement.textContent = WebInspector.displayNameForURL(this.url) + ":" + this.line; + else + urlElement.textContent = WebInspector.displayNameForURL(this.url); + + element.appendChild(urlElement); + } + + var messageTextElement = document.createElement("span"); + messageTextElement.className = "console-message-text"; + messageTextElement.appendChild(this.formattedMessage); + element.appendChild(messageTextElement); + + return element; + }, + + toString: function() + { + var sourceString; + switch (this.source) { + case WebInspector.ConsoleMessage.MessageSource.HTML: + sourceString = "HTML"; + break; + case WebInspector.ConsoleMessage.MessageSource.WML: + sourceString = "WML"; + break; + case WebInspector.ConsoleMessage.MessageSource.XML: + sourceString = "XML"; + break; + case WebInspector.ConsoleMessage.MessageSource.JS: + sourceString = "JS"; + break; + case WebInspector.ConsoleMessage.MessageSource.CSS: + sourceString = "CSS"; + break; + case WebInspector.ConsoleMessage.MessageSource.Other: + sourceString = "Other"; + break; + } + + var levelString; + switch (this.level) { + case WebInspector.ConsoleMessage.MessageLevel.Tip: + levelString = "Tip"; + break; + case WebInspector.ConsoleMessage.MessageLevel.Log: + levelString = "Log"; + break; + case WebInspector.ConsoleMessage.MessageLevel.Warning: + levelString = "Warning"; + break; + case WebInspector.ConsoleMessage.MessageLevel.Error: + levelString = "Error"; + break; + case WebInspector.ConsoleMessage.MessageLevel.Object: + levelString = "Object"; + break; + case WebInspector.ConsoleMessage.MessageLevel.Trace: + levelString = "Trace"; + break; + case WebInspector.ConsoleMessage.MessageLevel.StartGroup: + levelString = "Start Group"; + break; + case WebInspector.ConsoleMessage.MessageLevel.EndGroup: + levelString = "End Group"; + break; + } + + return sourceString + " " + levelString + ": " + this.formattedMessage.textContent + "\n" + this.url + " line " + this.line; + }, + + isEqual: function(msg, disreguardGroup) + { + if (!msg) + return false; + + var ret = (this.source == msg.source) + && (this.level == msg.level) + && (this.line == msg.line) + && (this.url == msg.url) + && (this.message == msg.message); + + return (disreguardGroup ? ret : (ret && (this.groupLevel == msg.groupLevel))); + } +} + +// Note: Keep these constants in sync with the ones in Console.h +WebInspector.ConsoleMessage.MessageSource = { + HTML: 0, + WML: 1, + XML: 2, + JS: 3, + CSS: 4, + Other: 5 +} + +WebInspector.ConsoleMessage.MessageLevel = { + Tip: 0, + Log: 1, + Warning: 2, + Error: 3, + Object: 4, + Trace: 5, + StartGroup: 6, + EndGroup: 7 +} + +WebInspector.ConsoleCommand = function(command) +{ + this.command = command; +} + +WebInspector.ConsoleCommand.prototype = { + toMessageElement: function() + { + var element = document.createElement("div"); + element.command = this; + element.className = "console-user-command"; + + var commandTextElement = document.createElement("span"); + commandTextElement.className = "console-message-text"; + commandTextElement.textContent = this.command; + element.appendChild(commandTextElement); + + return element; + } +} + +WebInspector.ConsoleCommandResult = function(result, exception, originatingCommand) +{ + var level = (exception ? WebInspector.ConsoleMessage.MessageLevel.Error : WebInspector.ConsoleMessage.MessageLevel.Log); + var message = (exception ? String(result) : result); + var line = (exception ? result.line : -1); + var url = (exception ? result.sourceURL : null); + + WebInspector.ConsoleMessage.call(this, WebInspector.ConsoleMessage.MessageSource.JS, level, line, url, null, 1, message); + + this.originatingCommand = originatingCommand; +} + +WebInspector.ConsoleCommandResult.prototype = { + toMessageElement: function() + { + var element = WebInspector.ConsoleMessage.prototype.toMessageElement.call(this); + element.addStyleClass("console-user-command-result"); + return element; + } +} + +WebInspector.ConsoleCommandResult.prototype.__proto__ = WebInspector.ConsoleMessage.prototype; + +WebInspector.ConsoleGroup = function(parentGroup, level) +{ + this.parentGroup = parentGroup; + this.level = level; + + var element = document.createElement("div"); + element.className = "console-group"; + element.group = this; + this.element = element; + + var messagesElement = document.createElement("div"); + messagesElement.className = "console-group-messages"; + element.appendChild(messagesElement); + this.messagesElement = messagesElement; +} + +WebInspector.ConsoleGroup.prototype = { + addMessage: function(msg) + { + var element = msg.toMessageElement(); + + if (msg.level === WebInspector.ConsoleMessage.MessageLevel.StartGroup) { + this.messagesElement.parentNode.insertBefore(element, this.messagesElement); + element.addEventListener("click", this._titleClicked.bind(this), true); + } else + this.messagesElement.appendChild(element); + + if (element.previousSibling && msg.originatingCommand && element.previousSibling.command === msg.originatingCommand) + element.previousSibling.addStyleClass("console-adjacent-user-command-result"); + }, + + _titleClicked: function(event) + { + var groupTitleElement = event.target.enclosingNodeOrSelfWithClass("console-group-title-level"); + if (groupTitleElement) { + var groupElement = groupTitleElement.enclosingNodeOrSelfWithClass("console-group"); + if (groupElement) + if (groupElement.hasStyleClass("collapsed")) + groupElement.removeStyleClass("collapsed"); + else + groupElement.addStyleClass("collapsed"); + groupTitleElement.scrollIntoViewIfNeeded(true); + } + + event.stopPropagation(); + event.preventDefault(); + } +} diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/DataGrid.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/DataGrid.js new file mode 100644 index 0000000..2fcb08c --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/DataGrid.js @@ -0,0 +1,885 @@ +/* + * Copyright (C) 2008 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. ``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 + * 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.DataGrid = function(columns) +{ + this.element = document.createElement("div"); + this.element.className = "data-grid"; + this.element.tabIndex = 0; + this.element.addEventListener("keydown", this._keyDown.bind(this), false); + + this._headerTable = document.createElement("table"); + this._headerTable.className = "header"; + + this._dataTable = document.createElement("table"); + this._dataTable.className = "data"; + + this._dataTable.addEventListener("mousedown", this._mouseDownInDataTable.bind(this), true); + this._dataTable.addEventListener("click", this._clickInDataTable.bind(this), true); + + var scrollContainer = document.createElement("div"); + scrollContainer.className = "data-container"; + scrollContainer.appendChild(this._dataTable); + + this.element.appendChild(this._headerTable); + this.element.appendChild(scrollContainer); + + var headerRow = document.createElement("tr"); + var columnGroup = document.createElement("colgroup"); + var columnCount = 0; + + for (var columnIdentifier in columns) { + var column = columns[columnIdentifier]; + if (column.disclosure) + this.disclosureColumnIdentifier = columnIdentifier; + + var col = document.createElement("col"); + if (column.width) + col.style.width = column.width; + columnGroup.appendChild(col); + + var cell = document.createElement("th"); + cell.className = columnIdentifier + "-column"; + cell.columnIdentifier = columnIdentifier; + + var div = document.createElement("div"); + div.textContent = column.title; + cell.appendChild(div); + + if (column.sort) { + cell.addStyleClass("sort-" + column.sort); + this._sortColumnCell = cell; + } + + if (column.sortable) { + cell.addEventListener("click", this._clickInHeaderCell.bind(this), false); + cell.addStyleClass("sortable"); + } + + headerRow.appendChild(cell); + + ++columnCount; + } + + columnGroup.span = columnCount; + + var cell = document.createElement("th"); + cell.className = "corner"; + headerRow.appendChild(cell); + + this._headerTable.appendChild(columnGroup); + this.headerTableBody.appendChild(headerRow); + + var fillerRow = document.createElement("tr"); + fillerRow.className = "filler"; + + for (var i = 0; i < columnCount; ++i) { + var cell = document.createElement("td"); + fillerRow.appendChild(cell); + } + + this._dataTable.appendChild(columnGroup.cloneNode(true)); + this.dataTableBody.appendChild(fillerRow); + + this.columns = columns || {}; + this.children = []; + this.selectedNode = null; + this.expandNodesWhenArrowing = false; + this.root = true; + this.hasChildren = false; + this.expanded = true; + this.revealed = true; + this.selected = false; + this.dataGrid = this; + this.indentWidth = 15; +} + +WebInspector.DataGrid.prototype = { + get sortColumnIdentifier() + { + if (!this._sortColumnCell) + return null; + return this._sortColumnCell.columnIdentifier; + }, + + get sortOrder() + { + if (!this._sortColumnCell || this._sortColumnCell.hasStyleClass("sort-ascending")) + return "ascending"; + if (this._sortColumnCell.hasStyleClass("sort-descending")) + return "descending"; + return null; + }, + + get headerTableBody() + { + if ("_headerTableBody" in this) + return this._headerTableBody; + + this._headerTableBody = this._headerTable.getElementsByTagName("tbody")[0]; + if (!this._headerTableBody) { + this._headerTableBody = this.element.ownerDocument.createElement("tbody"); + this._headerTable.insertBefore(this._headerTableBody, this._headerTable.tFoot); + } + + return this._headerTableBody; + }, + + get dataTableBody() + { + if ("_dataTableBody" in this) + return this._dataTableBody; + + this._dataTableBody = this._dataTable.getElementsByTagName("tbody")[0]; + if (!this._dataTableBody) { + this._dataTableBody = this.element.ownerDocument.createElement("tbody"); + this._dataTable.insertBefore(this._dataTableBody, this._dataTable.tFoot); + } + + return this._dataTableBody; + }, + + appendChild: function(child) + { + this.insertChild(child, this.children.length); + }, + + insertChild: function(child, index) + { + if (!child) + throw("insertChild: Node can't be undefined or null."); + if (child.parent === this) + throw("insertChild: Node is already a child of this node."); + + if (child.parent) + child.parent.removeChild(child); + + this.children.splice(index, 0, child); + this.hasChildren = true; + + child.parent = this; + child.dataGrid = this.dataGrid; + child._recalculateSiblings(index); + + delete child._depth; + delete child._revealed; + delete child._attached; + + var current = child.children[0]; + while (current) { + current.dataGrid = this.dataGrid; + delete current._depth; + delete current._revealed; + delete current._attached; + current = current.traverseNextNode(false, child, true); + } + + if (this.expanded) + child._attach(); + }, + + removeChild: function(child) + { + if (!child) + throw("removeChild: Node can't be undefined or null."); + if (child.parent !== this) + throw("removeChild: Node is not a child of this node."); + + child.deselect(); + + this.children.remove(child, true); + + if (child.previousSibling) + child.previousSibling.nextSibling = child.nextSibling; + if (child.nextSibling) + child.nextSibling.previousSibling = child.previousSibling; + + child.dataGrid = null; + child.parent = null; + child.nextSibling = null; + child.previousSibling = null; + + if (this.children.length <= 0) + this.hasChildren = false; + }, + + removeChildren: function() + { + for (var i = 0; i < this.children.length; ++i) { + var child = this.children[i]; + child.deselect(); + child._detach(); + + child.dataGrid = null; + child.parent = null; + child.nextSibling = null; + child.previousSibling = null; + } + + this.children = []; + this.hasChildren = false; + }, + + removeChildrenRecursive: function() + { + var childrenToRemove = this.children; + + var child = this.children[0]; + while (child) { + if (child.children.length) + childrenToRemove = childrenToRemove.concat(child.children); + child = child.traverseNextNode(false, this, true); + } + + for (var i = 0; i < childrenToRemove.length; ++i) { + var child = childrenToRemove[i]; + child.deselect(); + child._detach(); + + child.children = []; + child.dataGrid = null; + child.parent = null; + child.nextSibling = null; + child.previousSibling = null; + } + + this.children = []; + }, + + handleKeyEvent: function(event) + { + if (!this.selectedNode || event.shiftKey || event.metaKey || event.ctrlKey) + return false; + + var handled = false; + var nextSelectedNode; + if (event.keyIdentifier === "Up" && !event.altKey) { + nextSelectedNode = this.selectedNode.traversePreviousNode(true); + while (nextSelectedNode && !nextSelectedNode.selectable) + nextSelectedNode = nextSelectedNode.traversePreviousNode(!this.expandTreeNodesWhenArrowing); + handled = nextSelectedNode ? true : false; + } else if (event.keyIdentifier === "Down" && !event.altKey) { + nextSelectedNode = this.selectedNode.traverseNextNode(true); + while (nextSelectedNode && !nextSelectedNode.selectable) + nextSelectedNode = nextSelectedNode.traverseNextNode(!this.expandTreeNodesWhenArrowing); + handled = nextSelectedNode ? true : false; + } else if (event.keyIdentifier === "Left") { + if (this.selectedNode.expanded) { + if (event.altKey) + this.selectedNode.collapseRecursively(); + else + this.selectedNode.collapse(); + handled = true; + } else if (this.selectedNode.parent && !this.selectedNode.parent.root) { + handled = true; + if (this.selectedNode.parent.selectable) { + nextSelectedNode = this.selectedNode.parent; + handled = nextSelectedNode ? true : false; + } else if (this.selectedNode.parent) + this.selectedNode.parent.collapse(); + } + } else if (event.keyIdentifier === "Right") { + if (!this.selectedNode.revealed) { + this.selectedNode.reveal(); + handled = true; + } else if (this.selectedNode.hasChildren) { + handled = true; + if (this.selectedNode.expanded) { + nextSelectedNode = this.selectedNode.children[0]; + handled = nextSelectedNode ? true : false; + } else { + if (event.altKey) + this.selectedNode.expandRecursively(); + else + this.selectedNode.expand(); + } + } + } + + if (nextSelectedNode) { + nextSelectedNode.reveal(); + nextSelectedNode.select(); + } + + if (handled) { + event.preventDefault(); + event.stopPropagation(); + } + + return handled; + }, + + expand: function() + { + // This is the root, do nothing. + }, + + collapse: function() + { + // This is the root, do nothing. + }, + + reveal: function() + { + // This is the root, do nothing. + }, + + dataGridNodeFromEvent: function(event) + { + var rowElement = event.target.enclosingNodeOrSelfWithNodeName("tr"); + return rowElement._dataGridNode; + }, + + dataGridNodeFromPoint: function(x, y) + { + var node = this._dataTable.ownerDocument.elementFromPoint(x, y); + var rowElement = node.enclosingNodeOrSelfWithNodeName("tr"); + return rowElement._dataGridNode; + }, + + _keyDown: function(event) + { + this.handleKeyEvent(event); + }, + + _clickInHeaderCell: function(event) + { + var cell = event.target.enclosingNodeOrSelfWithNodeName("th"); + if (!cell || !cell.columnIdentifier || !cell.hasStyleClass("sortable")) + return; + + var sortOrder = this.sortOrder; + + if (this._sortColumnCell) { + this._sortColumnCell.removeStyleClass("sort-ascending"); + this._sortColumnCell.removeStyleClass("sort-descending"); + } + + if (cell == this._sortColumnCell) { + if (sortOrder == "ascending") + sortOrder = "descending"; + else + sortOrder = "ascending"; + } + + this._sortColumnCell = cell; + + cell.addStyleClass("sort-" + sortOrder); + + this.dispatchEventToListeners("sorting changed"); + }, + + _mouseDownInDataTable: function(event) + { + var gridNode = this.dataGridNodeFromEvent(event); + if (!gridNode || !gridNode.selectable) + return; + + if (gridNode.isEventWithinDisclosureTriangle(event)) + return; + + if (event.metaKey) { + if (gridNode.selected) + gridNode.deselect(); + else + gridNode.select(); + } else + gridNode.select(); + }, + + _clickInDataTable: function(event) + { + var gridNode = this.dataGridNodeFromEvent(event); + if (!gridNode || !gridNode.hasChildren) + return; + + if (!gridNode.isEventWithinDisclosureTriangle(event)) + return; + + if (gridNode.expanded) { + if (event.altKey) + gridNode.collapseRecursively(); + else + gridNode.collapse(); + } else { + if (event.altKey) + gridNode.expandRecursively(); + else + gridNode.expand(); + } + } +} + +WebInspector.DataGrid.prototype.__proto__ = WebInspector.Object.prototype; + +WebInspector.DataGridNode = function(data, hasChildren) +{ + this._expanded = false; + this._selected = false; + this._shouldRefreshChildren = true; + this._data = data || {}; + this.hasChildren = hasChildren || false; + this.children = []; + this.dataGrid = null; + this.parent = null; + this.previousSibling = null; + this.nextSibling = null; + this.disclosureToggleWidth = 10; +} + +WebInspector.DataGridNode.prototype = { + selectable: true, + + get element() + { + if (this._element) + return this._element; + + if (!this.dataGrid) + return null; + + this._element = document.createElement("tr"); + this._element._dataGridNode = this; + + if (this.hasChildren) + this._element.addStyleClass("parent"); + if (this.expanded) + this._element.addStyleClass("expanded"); + if (this.selected) + this._element.addStyleClass("selected"); + if (this.revealed) + this._element.addStyleClass("revealed"); + + for (var columnIdentifier in this.dataGrid.columns) { + var cell = this.createCell(columnIdentifier); + this._element.appendChild(cell); + } + + return this._element; + }, + + get data() + { + return this._data; + }, + + set data(x) + { + this._data = x || {}; + this.refresh(); + }, + + get revealed() + { + if ("_revealed" in this) + return this._revealed; + + var currentAncestor = this.parent; + while (currentAncestor && !currentAncestor.root) { + if (!currentAncestor.expanded) { + this._revealed = false; + return false; + } + + currentAncestor = currentAncestor.parent; + } + + this._revealed = true; + return true; + }, + + set hasChildren(x) + { + if (this._hasChildren === x) + return; + + this._hasChildren = x; + + if (!this._element) + return; + + if (this._hasChildren) + { + this._element.addStyleClass("parent"); + if (this.expanded) + this._element.addStyleClass("expanded"); + } + else + { + this._element.removeStyleClass("parent"); + this._element.removeStyleClass("expanded"); + } + }, + + get hasChildren() + { + return this._hasChildren; + }, + + set revealed(x) + { + if (this._revealed === x) + return; + + this._revealed = x; + + if (this._element) { + if (this._revealed) + this._element.addStyleClass("revealed"); + else + this._element.removeStyleClass("revealed"); + } + + for (var i = 0; i < this.children.length; ++i) + this.children[i].revealed = x && this.expanded; + }, + + get depth() + { + if ("_depth" in this) + return this._depth; + if (this.parent && !this.parent.root) + this._depth = this.parent.depth + 1; + else + this._depth = 0; + return this._depth; + }, + + get shouldRefreshChildren() + { + return this._shouldRefreshChildren; + }, + + set shouldRefreshChildren(x) + { + this._shouldRefreshChildren = x; + if (x && this.expanded) + this.expand(); + }, + + get selected() + { + return this._selected; + }, + + set selected(x) + { + if (x) + this.select(); + else + this.deselect(); + }, + + get expanded() + { + return this._expanded; + }, + + set expanded(x) + { + if (x) + this.expand(); + else + this.collapse(); + }, + + refresh: function() + { + if (!this._element || !this.dataGrid) + return; + + this._element.removeChildren(); + + for (var columnIdentifier in this.dataGrid.columns) { + var cell = this.createCell(columnIdentifier); + this._element.appendChild(cell); + } + }, + + createCell: function(columnIdentifier) + { + var cell = document.createElement("td"); + cell.className = columnIdentifier + "-column"; + + var div = document.createElement("div"); + div.textContent = this.data[columnIdentifier]; + cell.appendChild(div); + + if (columnIdentifier === this.dataGrid.disclosureColumnIdentifier) { + cell.addStyleClass("disclosure"); + if (this.depth) + cell.style.setProperty("padding-left", (this.depth * this.dataGrid.indentWidth) + "px"); + } + + return cell; + }, + + // Share these functions with DataGrid. They are written to work with a DataGridNode this object. + appendChild: WebInspector.DataGrid.prototype.appendChild, + insertChild: WebInspector.DataGrid.prototype.insertChild, + removeChild: WebInspector.DataGrid.prototype.removeChild, + removeChildren: WebInspector.DataGrid.prototype.removeChildren, + removeChildrenRecursive: WebInspector.DataGrid.prototype.removeChildrenRecursive, + + _recalculateSiblings: function(myIndex) + { + if (!this.parent) + return; + + var previousChild = (myIndex > 0 ? this.parent.children[myIndex - 1] : null); + + if (previousChild) { + previousChild.nextSibling = this; + this.previousSibling = previousChild; + } else + this.previousSibling = null; + + var nextChild = this.parent.children[myIndex + 1]; + + if (nextChild) { + nextChild.previousSibling = this; + this.nextSibling = nextChild; + } else + this.nextSibling = null; + }, + + collapse: function() + { + if (this._element) + this._element.removeStyleClass("expanded"); + + this._expanded = false; + + for (var i = 0; i < this.children.length; ++i) + this.children[i].revealed = false; + + this.dispatchEventToListeners("collapsed"); + }, + + collapseRecursively: function() + { + var item = this; + while (item) { + if (item.expanded) + item.collapse(); + item = item.traverseNextNode(false, this, true); + } + }, + + expand: function() + { + if (!this.hasChildren || this.expanded) + return; + + if (this.revealed && !this._shouldRefreshChildren) + for (var i = 0; i < this.children.length; ++i) + this.children[i].revealed = true; + + if (this._shouldRefreshChildren) { + for (var i = 0; i < this.children.length; ++i) + this.children[i]._detach(); + + this.dispatchEventToListeners("populate"); + + if (this._attached) { + for (var i = 0; i < this.children.length; ++i) { + var child = this.children[i]; + if (this.revealed) + child.revealed = true; + child._attach(); + } + } + + delete this._shouldRefreshChildren; + } + + if (this._element) + this._element.addStyleClass("expanded"); + + this._expanded = true; + + this.dispatchEventToListeners("expanded"); + }, + + expandRecursively: function() + { + var item = this; + while (item) { + item.expand(); + item = item.traverseNextNode(false, this); + } + }, + + reveal: function() + { + var currentAncestor = this.parent; + while (currentAncestor && !currentAncestor.root) { + if (!currentAncestor.expanded) + currentAncestor.expand(); + currentAncestor = currentAncestor.parent; + } + + this.element.scrollIntoViewIfNeeded(false); + + this.dispatchEventToListeners("revealed"); + }, + + select: function(supressSelectedEvent) + { + if (!this.dataGrid || !this.selectable || this.selected) + return; + + if (this.dataGrid.selectedNode) + this.dataGrid.selectedNode.deselect(); + + this._selected = true; + this.dataGrid.selectedNode = this; + + if (this._element) + this._element.addStyleClass("selected"); + + if (!supressSelectedEvent) + this.dispatchEventToListeners("selected"); + }, + + deselect: function(supressDeselectedEvent) + { + if (!this.dataGrid || this.dataGrid.selectedNode !== this || !this.selected) + return; + + this._selected = false; + this.dataGrid.selectedNode = null; + + if (this._element) + this._element.removeStyleClass("selected"); + + if (!supressDeselectedEvent) + this.dispatchEventToListeners("deselected"); + }, + + traverseNextNode: function(skipHidden, stayWithin, dontPopulate, info) + { + if (!dontPopulate && this.hasChildren) + this.dispatchEventToListeners("populate"); + + if (info) + info.depthChange = 0; + + var node = (!skipHidden || this.revealed) ? this.children[0] : null; + if (node && (!skipHidden || this.expanded)) { + if (info) + info.depthChange = 1; + return node; + } + + if (this === stayWithin) + return null; + + node = (!skipHidden || this.revealed) ? this.nextSibling : null; + if (node) + return node; + + node = this; + while (node && !node.root && !((!skipHidden || node.revealed) ? node.nextSibling : null) && node.parent !== stayWithin) { + if (info) + info.depthChange -= 1; + node = node.parent; + } + + if (!node) + return null; + + return (!skipHidden || node.revealed) ? node.nextSibling : null; + }, + + traversePreviousNode: function(skipHidden, dontPopulate) + { + var node = (!skipHidden || this.revealed) ? this.previousSibling : null; + if (!dontPopulate && node && node.hasChildren) + node.dispatchEventToListeners("populate"); + + while (node && ((!skipHidden || (node.revealed && node.expanded)) ? node.children[node.children.length - 1] : null)) { + if (!dontPopulate && node.hasChildren) + node.dispatchEventToListeners("populate"); + node = ((!skipHidden || (node.revealed && node.expanded)) ? node.children[node.children.length - 1] : null); + } + + if (node) + return node; + + if (!this.parent || this.parent.root) + return null; + + return this.parent; + }, + + isEventWithinDisclosureTriangle: function(event) + { + if (!this.hasChildren) + return false; + var cell = event.target.enclosingNodeOrSelfWithNodeName("td"); + if (!cell.hasStyleClass("disclosure")) + return false; + var computedLeftPadding = window.getComputedStyle(cell).getPropertyCSSValue("padding-left").getFloatValue(CSSPrimitiveValue.CSS_PX); + var left = cell.totalOffsetLeft + computedLeftPadding; + return event.pageX >= left && event.pageX <= left + this.disclosureToggleWidth; + }, + + _attach: function() + { + if (!this.dataGrid || this._attached) + return; + + this._attached = true; + + var nextNode = null; + var previousNode = this.traversePreviousNode(true, true); + if (previousNode && previousNode.element.parentNode && previousNode.element.nextSibling) + var nextNode = previousNode.element.nextSibling; + if (!nextNode) + nextNode = this.dataGrid.dataTableBody.lastChild; + this.dataGrid.dataTableBody.insertBefore(this.element, nextNode); + + if (this.expanded) + for (var i = 0; i < this.children.length; ++i) + this.children[i]._attach(); + }, + + _detach: function() + { + if (!this._attached) + return; + + this._attached = false; + + if (this._element && this._element.parentNode) + this._element.parentNode.removeChild(this._element); + + for (var i = 0; i < this.children.length; ++i) + this.children[i]._detach(); + } +} + +WebInspector.DataGridNode.prototype.__proto__ = WebInspector.Object.prototype; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Database.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Database.js new file mode 100644 index 0000000..ef42e15 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Database.js @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2007, 2008 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. + * 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. + */ + +WebInspector.Database = function(database, domain, name, version) +{ + this.database = database; + this.domain = domain; + this.name = name; + this.version = version; +} + +WebInspector.Database.prototype = { + get database() + { + return this._database; + }, + + set database(x) + { + if (this._database === x) + return; + this._database = x; + }, + + get name() + { + return this._name; + }, + + set name(x) + { + if (this._name === x) + return; + this._name = x; + }, + + get version() + { + return this._version; + }, + + set version(x) + { + if (this._version === x) + return; + this._version = x; + }, + + get domain() + { + return this._domain; + }, + + set domain(x) + { + if (this._domain === x) + return; + this._domain = x; + }, + + get displayDomain() + { + return WebInspector.Resource.prototype.__lookupGetter__("displayDomain").call(this); + }, + + get tableNames() + { + return InspectorController.databaseTableNames(this.database).sort(); + } +} diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/DatabaseQueryView.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/DatabaseQueryView.js new file mode 100644 index 0000000..122707f --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/DatabaseQueryView.js @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2008 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. ``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 + * 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.DatabaseQueryView = function(database) +{ + WebInspector.View.call(this); + + this.database = database; + + this.element.addStyleClass("storage-view"); + this.element.addStyleClass("query"); + this.element.tabIndex = 0; + + this.element.addEventListener("selectstart", this._selectStart.bind(this), false); + + this.promptElement = document.createElement("div"); + this.promptElement.className = "database-query-prompt"; + this.promptElement.appendChild(document.createElement("br")); + this.promptElement.handleKeyEvent = this._promptKeyDown.bind(this); + this.element.appendChild(this.promptElement); + + this.prompt = new WebInspector.TextPrompt(this.promptElement, this.completions.bind(this), " "); +} + +WebInspector.DatabaseQueryView.prototype = { + show: function(parentElement) + { + WebInspector.View.prototype.show.call(this, parentElement); + + function moveBackIfOutside() + { + if (!this.prompt.isCaretInsidePrompt() && window.getSelection().isCollapsed) + this.prompt.moveCaretToEndOfPrompt(); + } + + setTimeout(moveBackIfOutside.bind(this), 0); + }, + + completions: function(wordRange, bestMatchOnly) + { + var prefix = wordRange.toString().toLowerCase(); + if (!prefix.length) + return; + + var results = []; + + function accumulateMatches(textArray) + { + if (bestMatchOnly && results.length) + return; + for (var i = 0; i < textArray.length; ++i) { + var text = textArray[i].toLowerCase(); + if (text.length < prefix.length) + continue; + if (text.indexOf(prefix) !== 0) + continue; + results.push(textArray[i]); + if (bestMatchOnly) + return; + } + } + + accumulateMatches(this.database.tableNames.map(function(name) { return name + " " })); + accumulateMatches(["SELECT ", "FROM ", "WHERE ", "LIMIT ", "DELETE FROM ", "CREATE ", "DROP ", "TABLE ", "INDEX ", "UPDATE ", "INSERT INTO ", "VALUES ("]); + + return results; + }, + + _promptKeyDown: function(event) + { + switch (event.keyIdentifier) { + case "Enter": + this._enterKeyPressed(event); + return; + } + + this.prompt.handleKeyEvent(event); + }, + + _selectStart: function(event) + { + if (this._selectionTimeout) + clearTimeout(this._selectionTimeout); + + this.prompt.clearAutoComplete(); + + function moveBackIfOutside() + { + delete this._selectionTimeout; + if (!this.prompt.isCaretInsidePrompt() && window.getSelection().isCollapsed) + this.prompt.moveCaretToEndOfPrompt(); + this.prompt.autoCompleteSoon(); + } + + this._selectionTimeout = setTimeout(moveBackIfOutside.bind(this), 100); + }, + + _enterKeyPressed: function(event) + { + event.preventDefault(); + event.stopPropagation(); + + this.prompt.clearAutoComplete(true); + + var query = this.prompt.text; + if (!query.length) + return; + + this.prompt.history.push(query); + this.prompt.historyOffset = 0; + this.prompt.text = ""; + + function queryTransaction(tx) + { + tx.executeSql(query, null, InspectorController.wrapCallback(this._queryFinished.bind(this, query)), InspectorController.wrapCallback(this._executeSqlError.bind(this, query))); + } + + this.database.database.transaction(InspectorController.wrapCallback(queryTransaction.bind(this)), InspectorController.wrapCallback(this._queryError.bind(this, query))); + }, + + _queryFinished: function(query, tx, result) + { + var dataGrid = WebInspector.panels.databases.dataGridForResult(result); + dataGrid.element.addStyleClass("inline"); + this._appendQueryResult(query, dataGrid.element); + + if (query.match(/^create /i) || query.match(/^drop table /i)) + WebInspector.panels.databases.updateDatabaseTables(this.database); + }, + + _queryError: function(query, error) + { + if (error.code == 1) + var message = error.message; + else if (error.code == 2) + var message = WebInspector.UIString("Database no longer has expected version."); + else + var message = WebInspector.UIString("An unexpected error %s occured.", error.code); + + this._appendQueryResult(query, message, "error"); + }, + + _executeSqlError: function(query, tx, error) + { + this._queryError(query, error); + }, + + _appendQueryResult: function(query, result, resultClassName) + { + var element = document.createElement("div"); + element.className = "database-user-query"; + + var commandTextElement = document.createElement("span"); + commandTextElement.className = "database-query-text"; + commandTextElement.textContent = query; + element.appendChild(commandTextElement); + + var resultElement = document.createElement("div"); + resultElement.className = "database-query-result"; + + if (resultClassName) + resultElement.addStyleClass(resultClassName); + + if (typeof result === "string" || result instanceof String) + resultElement.textContent = result; + else if (result && result.nodeName) + resultElement.appendChild(result); + + if (resultElement.childNodes.length) + element.appendChild(resultElement); + + this.element.insertBefore(element, this.promptElement); + this.promptElement.scrollIntoView(false); + } +} + +WebInspector.DatabaseQueryView.prototype.__proto__ = WebInspector.View.prototype; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/DatabaseTableView.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/DatabaseTableView.js new file mode 100644 index 0000000..bbca9d0 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/DatabaseTableView.js @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2008 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. ``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 + * 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.DatabaseTableView = function(database, tableName) +{ + WebInspector.View.call(this); + + this.database = database; + this.tableName = tableName; + + this.element.addStyleClass("storage-view"); + this.element.addStyleClass("table"); + + this.refreshButton = document.createElement("button"); + this.refreshButton.title = WebInspector.UIString("Refresh"); + this.refreshButton.className = "refresh-storage-status-bar-item status-bar-item"; + this.refreshButton.addEventListener("click", this._refreshButtonClicked.bind(this), false); +} + +WebInspector.DatabaseTableView.prototype = { + show: function(parentElement) + { + WebInspector.View.prototype.show.call(this, parentElement); + this.update(); + }, + + get statusBarItems() + { + return [this.refreshButton]; + }, + + update: function() + { + function queryTransaction(tx) + { + tx.executeSql("SELECT * FROM " + this.tableName, null, InspectorController.wrapCallback(this._queryFinished.bind(this)), InspectorController.wrapCallback(this._queryError.bind(this))); + } + + this.database.database.transaction(InspectorController.wrapCallback(queryTransaction.bind(this)), InspectorController.wrapCallback(this._queryError.bind(this))); + }, + + _queryFinished: function(tx, result) + { + this.element.removeChildren(); + + var dataGrid = WebInspector.panels.databases.dataGridForResult(result); + if (!dataGrid) { + var emptyMsgElement = document.createElement("div"); + emptyMsgElement.className = "storage-table-empty"; + emptyMsgElement.textContent = WebInspector.UIString("The “%s”\ntable is empty.", this.tableName); + this.element.appendChild(emptyMsgElement); + return; + } + + this.element.appendChild(dataGrid.element); + }, + + _queryError: function(tx, error) + { + this.element.removeChildren(); + + var errorMsgElement = document.createElement("div"); + errorMsgElement.className = "storage-table-error"; + errorMsgElement.textContent = WebInspector.UIString("An error occurred trying to\nread the “%s” table.", this.tableName); + this.element.appendChild(errorMsgElement); + }, + + _refreshButtonClicked: function(event) + { + this.update(); + } +} + +WebInspector.DatabaseTableView.prototype.__proto__ = WebInspector.View.prototype; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/DatabasesPanel.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/DatabasesPanel.js new file mode 100644 index 0000000..4644b3b --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/DatabasesPanel.js @@ -0,0 +1,526 @@ +/* + * Copyright (C) 2007, 2008 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. + * 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. + */ + +WebInspector.DatabasesPanel = function(database) +{ + WebInspector.Panel.call(this); + + this.sidebarElement = document.createElement("div"); + this.sidebarElement.id = "databases-sidebar"; + this.sidebarElement.className = "sidebar"; + this.element.appendChild(this.sidebarElement); + + this.sidebarResizeElement = document.createElement("div"); + this.sidebarResizeElement.className = "sidebar-resizer-vertical"; + this.sidebarResizeElement.addEventListener("mousedown", this._startSidebarDragging.bind(this), false); + this.element.appendChild(this.sidebarResizeElement); + + this.sidebarTreeElement = document.createElement("ol"); + this.sidebarTreeElement.className = "sidebar-tree"; + this.sidebarElement.appendChild(this.sidebarTreeElement); + + this.sidebarTree = new TreeOutline(this.sidebarTreeElement); + + this.databasesListTreeElement = new WebInspector.SidebarSectionTreeElement(WebInspector.UIString("DATABASES"), {}, true); + this.sidebarTree.appendChild(this.databasesListTreeElement); + this.databasesListTreeElement.expand(); + + this.localStorageListTreeElement = new WebInspector.SidebarSectionTreeElement(WebInspector.UIString("LOCAL STORAGE"), {}, true); + this.sidebarTree.appendChild(this.localStorageListTreeElement); + this.localStorageListTreeElement.expand(); + + this.sessionStorageListTreeElement = new WebInspector.SidebarSectionTreeElement(WebInspector.UIString("SESSION STORAGE"), {}, true); + this.sidebarTree.appendChild(this.sessionStorageListTreeElement); + this.sessionStorageListTreeElement.expand(); + + this.storageViews = document.createElement("div"); + this.storageViews.id = "storage-views"; + this.element.appendChild(this.storageViews); + + this.storageViewStatusBarItemsContainer = document.createElement("div"); + this.storageViewStatusBarItemsContainer.id = "storage-view-status-bar-items"; + + this.reset(); +} + +WebInspector.DatabasesPanel.prototype = { + toolbarItemClass: "databases", + + get toolbarItemLabel() + { + return WebInspector.UIString("Databases"); + }, + + get statusBarItems() + { + return [this.storageViewStatusBarItemsContainer]; + }, + + show: function() + { + WebInspector.Panel.prototype.show.call(this); + this._updateSidebarWidth(); + }, + + reset: function() + { + if (this._databases) { + var databasesLength = this._databases.length; + for (var i = 0; i < databasesLength; ++i) { + var database = this._databases[i]; + + delete database._tableViews; + delete database._queryView; + } + } + + this._databases = []; + + if (this._domStorage) { + var domStorageLength = this._domStorage.length; + for (var i = 0; i < domStorageLength; ++i) { + var domStorage = this._domStorage[i]; + + delete domStorage._domStorageView; + } + } + + this._domStorage = []; + + this.databasesListTreeElement.removeChildren(); + this.localStorageListTreeElement.removeChildren(); + this.sessionStorageListTreeElement.removeChildren(); + this.storageViews.removeChildren(); + + this.storageViewStatusBarItemsContainer.removeChildren(); + }, + + handleKeyEvent: function(event) + { + this.sidebarTree.handleKeyEvent(event); + }, + + addDatabase: function(database) + { + this._databases.push(database); + + var databaseTreeElement = new WebInspector.DatabaseSidebarTreeElement(database); + database._databasesTreeElement = databaseTreeElement; + this.databasesListTreeElement.appendChild(databaseTreeElement); + }, + + addDOMStorage: function(domStorage) + { + this._domStorage.push(domStorage); + var domStorageTreeElement = new WebInspector.DOMStorageSidebarTreeElement(domStorage); + domStorage._domStorageTreeElement = domStorageTreeElement; + if (domStorage.isLocalStorage) + this.localStorageListTreeElement.appendChild(domStorageTreeElement); + else + this.sessionStorageListTreeElement.appendChild(domStorageTreeElement); + }, + + showDatabase: function(database, tableName) + { + if (!database) + return; + + if (this.visibleView) + this.visibleView.hide(); + + var view; + if (tableName) { + if (!("_tableViews" in database)) + database._tableViews = {}; + view = database._tableViews[tableName]; + if (!view) { + view = new WebInspector.DatabaseTableView(database, tableName); + database._tableViews[tableName] = view; + } + } else { + view = database._queryView; + if (!view) { + view = new WebInspector.DatabaseQueryView(database); + database._queryView = view; + } + } + + view.show(this.storageViews); + + this.visibleView = view; + + this.storageViewStatusBarItemsContainer.removeChildren(); + var statusBarItems = view.statusBarItems; + for (var i = 0; i < statusBarItems.length; ++i) + this.storageViewStatusBarItemsContainer.appendChild(statusBarItems[i]); + }, + + showDOMStorage: function(domStorage) + { + if (!domStorage) + return; + + if (this.visibleView) + this.visibleView.hide(); + + var view; + view = domStorage._domStorageView; + if (!view) { + view = new WebInspector.DOMStorageItemsView(domStorage); + domStorage._domStorageView = view; + } + + view.show(this.storageViews); + + this.visibleView = view; + + this.storageViewStatusBarItemsContainer.removeChildren(); + var statusBarItems = view.statusBarItems; + for (var i = 0; i < statusBarItems.length; ++i) + this.storageViewStatusBarItemsContainer.appendChild(statusBarItems[i]); + }, + + closeVisibleView: function() + { + if (this.visibleView) + this.visibleView.hide(); + delete this.visibleView; + }, + + updateDatabaseTables: function(database) + { + if (!database || !database._databasesTreeElement) + return; + + database._databasesTreeElement.shouldRefreshChildren = true; + + if (!("_tableViews" in database)) + return; + + var tableNamesHash = {}; + var tableNames = database.tableNames; + var tableNamesLength = tableNames.length; + for (var i = 0; i < tableNamesLength; ++i) + tableNamesHash[tableNames[i]] = true; + + for (var tableName in database._tableViews) { + if (!(tableName in tableNamesHash)) { + if (this.visibleView === database._tableViews[tableName]) + this.closeVisibleView(); + delete database._tableViews[tableName]; + } + } + }, + + dataGridForResult: function(result) + { + if (!result.rows.length) + return null; + + var columns = {}; + + var rows = result.rows; + for (var columnIdentifier in rows.item(0)) { + var column = {}; + column.width = columnIdentifier.length; + column.title = columnIdentifier; + + columns[columnIdentifier] = column; + } + + var nodes = []; + var length = rows.length; + for (var i = 0; i < length; ++i) { + var data = {}; + + var row = rows.item(i); + for (var columnIdentifier in row) { + // FIXME: (Bug 19439) We should specially format SQL NULL here + // (which is represented by JavaScript null here, and turned + // into the string "null" by the String() function). + var text = String(row[columnIdentifier]); + data[columnIdentifier] = text; + if (text.length > columns[columnIdentifier].width) + columns[columnIdentifier].width = text.length; + } + + var node = new WebInspector.DataGridNode(data, false); + node.selectable = false; + nodes.push(node); + } + + var totalColumnWidths = 0; + for (var columnIdentifier in columns) + totalColumnWidths += columns[columnIdentifier].width; + + // Calculate the percentage width for the columns. + const minimumPrecent = 5; + var recoupPercent = 0; + for (var columnIdentifier in columns) { + var width = columns[columnIdentifier].width; + width = Math.round((width / totalColumnWidths) * 100); + if (width < minimumPrecent) { + recoupPercent += (minimumPrecent - width); + width = minimumPrecent; + } + + columns[columnIdentifier].width = width; + } + + // Enforce the minimum percentage width. + while (recoupPercent > 0) { + for (var columnIdentifier in columns) { + if (columns[columnIdentifier].width > minimumPrecent) { + --columns[columnIdentifier].width; + --recoupPercent; + if (!recoupPercent) + break; + } + } + } + + // Change the width property to a string suitable for a style width. + for (var columnIdentifier in columns) + columns[columnIdentifier].width += "%"; + + var dataGrid = new WebInspector.DataGrid(columns); + var length = nodes.length; + for (var i = 0; i < length; ++i) + dataGrid.appendChild(nodes[i]); + + return dataGrid; + }, + + dataGridForDOMStorage: function(domStorage) + { + if (!domStorage.length) + return null; + + var columns = {}; + columns[0] = {}; + columns[1] = {}; + columns[0].title = WebInspector.UIString("Key"); + columns[0].width = columns[0].title.length; + columns[1].title = WebInspector.UIString("Value"); + columns[1].width = columns[0].title.length; + + var nodes = []; + + var length = domStorage.length; + for (index = 0; index < domStorage.length; index++) { + var data = {}; + + var key = String(domStorage.key(index)); + data[0] = key; + if (key.length > columns[0].width) + columns[0].width = key.length; + + var value = String(domStorage.getItem(key)); + data[1] = value; + if (value.length > columns[1].width) + columns[1].width = value.length; + var node = new WebInspector.DataGridNode(data, false); + node.selectable = true; + nodes.push(node); + } + + var totalColumnWidths = columns[0].width + columns[1].width; + width = Math.round((columns[0].width * 100) / totalColumnWidths); + const minimumPrecent = 10; + if (width < minimumPrecent) + width = minimumPrecent; + if (width > 100 - minimumPrecent) + width = 100 - minimumPrecent; + columns[0].width = width; + columns[1].width = 100 - width; + columns[0].width += "%"; + columns[1].width += "%"; + + var dataGrid = new WebInspector.DOMStorageDataGrid(columns); + var length = nodes.length; + for (var i = 0; i < length; ++i) + dataGrid.appendChild(nodes[i]); + if (length > 0) + nodes[0].selected = true; + return dataGrid; + }, + + _startSidebarDragging: function(event) + { + WebInspector.elementDragStart(this.sidebarResizeElement, this._sidebarDragging.bind(this), this._endSidebarDragging.bind(this), event, "col-resize"); + }, + + _sidebarDragging: function(event) + { + this._updateSidebarWidth(event.pageX); + + event.preventDefault(); + }, + + _endSidebarDragging: function(event) + { + WebInspector.elementDragEnd(event); + }, + + _updateSidebarWidth: function(width) + { + if (this.sidebarElement.offsetWidth <= 0) { + // The stylesheet hasn't loaded yet or the window is closed, + // so we can't calculate what is need. Return early. + return; + } + + if (!("_currentSidebarWidth" in this)) + this._currentSidebarWidth = this.sidebarElement.offsetWidth; + + if (typeof width === "undefined") + width = this._currentSidebarWidth; + + width = Number.constrain(width, Preferences.minSidebarWidth, window.innerWidth / 2); + + this._currentSidebarWidth = width; + + this.sidebarElement.style.width = width + "px"; + this.storageViews.style.left = width + "px"; + this.storageViewStatusBarItemsContainer.style.left = width + "px"; + this.sidebarResizeElement.style.left = (width - 3) + "px"; + } +} + +WebInspector.DatabasesPanel.prototype.__proto__ = WebInspector.Panel.prototype; + +WebInspector.DatabaseSidebarTreeElement = function(database) +{ + this.database = database; + + WebInspector.SidebarTreeElement.call(this, "database-sidebar-tree-item", "", "", database, true); + + this.refreshTitles(); +} + +WebInspector.DatabaseSidebarTreeElement.prototype = { + onselect: function() + { + WebInspector.panels.databases.showDatabase(this.database); + }, + + oncollapse: function() + { + // Request a refresh after every collapse so the next + // expand will have an updated table list. + this.shouldRefreshChildren = true; + }, + + onpopulate: function() + { + this.removeChildren(); + + var tableNames = this.database.tableNames; + var tableNamesLength = tableNames.length; + for (var i = 0; i < tableNamesLength; ++i) + this.appendChild(new WebInspector.SidebarDatabaseTableTreeElement(this.database, tableNames[i])); + }, + + get mainTitle() + { + return this.database.name; + }, + + set mainTitle(x) + { + // Do nothing. + }, + + get subtitle() + { + return this.database.displayDomain; + }, + + set subtitle(x) + { + // Do nothing. + } +} + +WebInspector.DatabaseSidebarTreeElement.prototype.__proto__ = WebInspector.SidebarTreeElement.prototype; + +WebInspector.SidebarDatabaseTableTreeElement = function(database, tableName) +{ + this.database = database; + this.tableName = tableName; + + WebInspector.SidebarTreeElement.call(this, "database-table-sidebar-tree-item small", tableName, "", null, false); +} + +WebInspector.SidebarDatabaseTableTreeElement.prototype = { + onselect: function() + { + WebInspector.panels.databases.showDatabase(this.database, this.tableName); + } +} + +WebInspector.SidebarDatabaseTableTreeElement.prototype.__proto__ = WebInspector.SidebarTreeElement.prototype; + +WebInspector.DOMStorageSidebarTreeElement = function(domStorage) +{ + + this.domStorage = domStorage; + + WebInspector.SidebarTreeElement.call(this, "domstorage-sidebar-tree-item", domStorage, "", null, false); + + this.refreshTitles(); +} + +WebInspector.DOMStorageSidebarTreeElement.prototype = { + onselect: function() + { + WebInspector.panels.databases.showDOMStorage(this.domStorage); + }, + + get mainTitle() + { + return this.domStorage.domain; + }, + + set mainTitle(x) + { + // Do nothing. + }, + + get subtitle() + { + return ""; //this.database.displayDomain; + }, + + set subtitle(x) + { + // Do nothing. + } +} + +WebInspector.DOMStorageSidebarTreeElement.prototype.__proto__ = WebInspector.SidebarTreeElement.prototype; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/DebuggerConsole.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/DebuggerConsole.js new file mode 100644 index 0000000..0ba3b28 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/DebuggerConsole.js @@ -0,0 +1,173 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview Helper functions and objects for the JS debugger UI. + * @see debugger.html + */ + +/** + * Document load listener. + */ +function onLoad() { + var debuggerConsole = new DebuggerConsole(); + DebuggerIPC.init(debuggerConsole); + DebugShell.initDebugShell(debuggerConsole); + debuggerConsole.focusOnCommandLine(); +} + +/** + * @constructor + */ +function DebuggerConsole() +{ + this._output = document.getElementById("output"); + + var input = document.getElementById("command-line-text"); + var self = this; + input.addEventListener( + 'keydown', + function(e) { + return self._onInputKeyDown(e); + }, + true); + input.addEventListener( + 'keypress', + function(e) { + return self._onInputKeyPress(e); + }, + true); + this._commandLineInput = input; + + // command object stores command-line history state. + this._command = { + history: [], + history_index: 0, + pending: null + }; +}; + +DebuggerConsole.prototype = { + /** + * Sets focus to command-line-text element. + */ + focusOnCommandLine: function() { + this._commandLineInput.focus(); + }, + + /** + * Called by chrome code when there's output to display. + * @param {string} txt + */ + appendText: function(txt) + { + this._output.appendChild(document.createTextNode(txt)); + this._output.appendChild(document.createElement('br')); + document.body.scrollTop = document.body.scrollHeight; + }, + + /** + * Called by chrome code to set the current state as to whether the debugger + * is stopped at a breakpoint or is running. + * @param {boolean} isBroken + */ + setDebuggerBreak: function(isBroken) + { + var out = this._output; + if (isBroken) { + out.style.color = "black"; + this.focusOnCommandLine(); + } else { + out.style.color = "gray"; + } + }, + + /** + * Execute a debugger command, add it to the command history and display it in + * the output window. + * @param {string} str + */ + executeCommand: function(str) { + this.appendText("$ " + str); + // Sends message to DebuggerContents.HandleCommand. + if (DebugShell.singleton) { + DebugShell.singleton.command(str); + } else { + this.appendText("FAILED to send the command as DebugShell is null"); + } + + this._command.history.push(str); + this._command.history_index = this._command.history.length; + this._command.pending = null; + }, + + + /** + * Display the previous history item in the given text field. + * @param {HTMLInputElement} field + */ + selectPreviousCommand_: function(field) { + var command = this._command; + if (command.history_index > 0) { + // Remember the current field value as a pending command if we're at the + // end (it's something the user typed in). + if (command.history_index == command.history.length) + command.pending = field.value; + command.history_index--; + field.value = command.history[command.history_index]; + field.select(); + } + }, + + /** + * Display the next history item in the given text field. + * @param {HTMLInputElement} field + */ + selectNextCommand_: function(field) { + var command = this._command; + if (command.history_index < command.history.length) { + command.history_index++; + if (command.history_index == command.history.length) { + field.value = command.pending || ""; + } else { + field.value = command.history[command.history_index]; + } + field.select(); + } + }, + + /** + * command-line-text's onkeydown handler. + * @param {KeyboardEvent} e + * @return {boolean} + */ + _onInputKeyDown: function (e) { + var field = e.target; + var key = e.keyCode; + if (key == 38) { // up arrow + this.selectPreviousCommand_(field); + return false; + } else if (key == 40) { // down arrow + this.selectNextCommand_(field); + return false; + } + return true; + }, + + /** + * command-line-text's onkeypress handler. + * @param {KeyboardEvent} e + * @return {boolean} + */ + _onInputKeyPress: function (e) { + var field = e.target; + var key = e.keyCode; + if (key == 13) { // enter + this.executeCommand(field.value); + field.value = ""; + return false; + } + return true; + } +}; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/DebuggerIPC.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/DebuggerIPC.js new file mode 100644 index 0000000..15835fc --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/DebuggerIPC.js @@ -0,0 +1,109 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview Implementation of debugger inter-process communication. + * Debugger UI can send messages to the DebuggerHost object living in + * Chrome browser process. The messages are either processed by DebuggerHost + * itself or trigger IPC message(such as break, evaluate script etc) from + * browser process to the renderer where the v8 instance being debugged + * will process them. + */ + +var DebuggerIPC = {}; + +/** + * Set up default debugger UI. + * @param {DebuggerPanel|DebuggerConsole} debuggerUI + */ +DebuggerIPC.init = function(debuggerUI) { + DebuggerIPC.debuggerUI = debuggerUI; +} + +/** + * Sends JSON message to DebuggerHost. + * @param {Array.<Object>} nameAndArguments + */ +DebuggerIPC.sendMessage = function(nameAndArguments) { + //alert("DebuggerIPC.sendMessage " + nameAndArguments); + dprint("DebuggerIPC.callMethod([" + nameAndArguments + "])"); + // convert all arguments to strings + // TODO(yurys): extend chrome.send to accept array of any value + // objects not only strings + for (var i = 0; i < nameAndArguments.length; i++) { + if (typeof nameAndArguments[i] != "string") { + nameAndArguments[i] = "" + nameAndArguments[i]; + } + } + + chrome.send("DebuggerHostMessage", nameAndArguments); +}; + +/** + * Handles messages from DebuggerHost. + * @param {Object} msg An object representing the message. + */ +DebuggerIPC.onMessageReceived = function(msg) { + //alert("DebuggerIPC.onMessageReceived " + msg.event); + var ui = DebuggerIPC.debuggerUI; + dprint("onMessageReceived: " + (msg && msg.event)); + if (msg.type == "event") { + if (msg.event == "setDebuggerBreak") { + var val = msg.body.argument; + ui.setDebuggerBreak(val); + } else if (msg.event == "appendText") { + var text = msg.body.text; + ui.appendText(text); + } else if (msg.event == "focusOnCommandLine") { + dprint("focusOnCommandLine event received"); + // messages to DebugShell + } else if (msg.event == "initDebugShell") { + // DebugShell.initDebugShell(); + dprint(msg.event + " done"); + } else if (msg.event == "on_attach") { + if (DebugShell.singleton) { + var args = msg.body.arguments; + if (!args || args.length != 1) { + dprint(msg.event + " failed: invalid arguments"); + return; + } + var title = args[0]; + DebugShell.singleton.on_attach(title); + dprint(msg.event + " done"); + } else { + dprint(msg.event + " failed: DebugShell.singleton == null"); + } + } else if (msg.event == "on_disconnect") { + if (DebugShell.singleton) { + DebugShell.singleton.on_disconnect(); + dprint(msg.event + " done"); + } else { + dprint(msg.event + " failed: DebugShell.singleton == null"); + } + } else if (msg.event == "exit") { + if (DebugShell.singleton) { + DebugShell.singleton.exit(); + dprint(msg.event + " done"); + } else { + dprint(msg.event + " failed: DebugShell.singleton == null"); + } + } else if (msg.event == "response") { + if (DebugShell.singleton) { + var args = msg.body.arguments; + if (!args || args.length != 1) { + dprint(msg.event + " failed: invalid argument"); + return; + } + DebugShell.singleton.response(args[0]); + dprint(msg.event + " done"); + } else { + ui.appendText(msg.event + " failed: DebugShell.singleton == null"); + } + } else { + ui.appendText("Unknown event: " + msg.event); + } + } else { + ui.appendText("Unknown message type: " + msg.type); + } +}; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/DebuggerPanel.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/DebuggerPanel.js new file mode 100644 index 0000000..bb059ac --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/DebuggerPanel.js @@ -0,0 +1,201 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview WebInspector panel representing command line debugger. + */ + +/** + * Command line debugger panel. + * @constructor + * @extends {WebInspector.Panel} + */ +WebInspector.DebuggerPanel = function() +{ + WebInspector.Panel.call(this); + + this.contentElement = document.createElement("div"); + this.contentElement.id = "debugger-content"; + + var table = document.createElement("table"); + table.id = 'outer'; + var tr = document.createElement("tr"); + this._output = document.createElement("td"); + this._output.id = "output"; + this._output.valign = "bottom"; + this.appendText("Chrome JavaScript Debugger"); + this.appendText("Type 'help' for a list of commands."); + + tr.appendChild(this._output); + table.appendChild(tr); + this.contentElement.appendChild(table); + + + var commandLine = document.createElement("div"); + commandLine.id = "command-line"; + var input = document.createElement("input"); + input.id = "command-line-text"; + input.addEventListener('keydown', this._onInputKeyDown.bind(this), true); + input.addEventListener('keypress', this._onInputKeyPress.bind(this), true); + input.type = "text"; + this.commandLineInput_ = input; + + commandLine.appendChild(input); + this.contentElement.appendChild(commandLine); + + // command object stores command-line history state. + this._command = { + history: [], + history_index: 0, + pending: null + }; + + this.element.appendChild(this.contentElement); + p('DebuggerPanel created'); +}; + +WebInspector.DebuggerPanel.prototype = { + toolbarItemClass: "debugger", + + get toolbarItemLabel() + { + return "Debugger"; //WebInspector.UIString("Debugger"); + }, + + show: function() + { + WebInspector.Panel.prototype.show.call(this); + this.focusOnCommandLine(); + }, + + /** + * Sets focus to command-line-text element. + */ + focusOnCommandLine: function() + { + if (this.visible) { + this.commandLineInput_.focus(); + } + }, + + /** + * Called by chrome code when there's output to display. + * @param {string} txt + */ + appendText: function(txt) + { + this._output.appendChild(document.createTextNode(txt)); + this._output.appendChild(document.createElement('br')); + }, + + /** + * Called by chrome code to set the current state as to whether the debugger + * is stopped at a breakpoint or is running. + * @param {boolean} isBroken + */ + setDebuggerBreak: function(isBroken) + { + var out = this._output; + if (isBroken) { + out.style.color = "black"; + this.focusOnCommandLine(); + } else { + out.style.color = "gray"; + } + }, + + /** + * Execute a debugger command, add it to the command history and display + * it in the output window. + * @param {string} str + */ + executeCommand: function(str) + { + this.appendText("$ " + str); + // Sends message to DebuggerContents.HandleCommand. + if (DebugShell.singleton) { + DebugShell.singleton.command(str); + } else { + this.appendText("FAILED to send the command as DebugShell is null"); + } + + this._command.history.push(str); + this._command.history_index = this._command.history.length; + this._command.pending = null; + }, + + /** + * Display the previous history item in the given text field. + * @param {HTMLInputElement} field + */ + _selectPreviousCommand: function(field) + { + var command = this._command; + if (command.history_index > 0) { + // Remember the current field value as a pending command if we're at the + // end (it's something the user typed in). + if (command.history_index == command.history.length) + command.pending = field.value; + command.history_index--; + field.value = command.history[command.history_index]; + field.select(); + } + }, + + /** + * Display the next history item in the given text field. + * @param {HTMLInputElement} field + */ + _selectNextCommand: function(field) + { + var command = this._command; + if (command.history_index < command.history.length) { + command.history_index++; + if (command.history_index == command.history.length) { + field.value = command.pending || ""; + } else { + field.value = command.history[command.history_index]; + } + field.select(); + } + }, + + /** + * command-line-text's onkeydown handler. + * @param {KeyboardEvent} e + * @return {boolean} + */ + _onInputKeyDown: function (e) + { + var field = e.target; + var key = e.keyCode; + if (key == 38) { // up arrow + this._selectPreviousCommand(field); + return false; + } else if (key == 40) { // down arrow + this._selectNextCommand(field); + return false; + } + return true; + }, + + /** + * command-line-text's onkeypress handler. + * @param {KeyboardEvent} e + * @return {boolean} + */ + _onInputKeyPress: function (e) + { + var field = e.target; + var key = e.keyCode; + if (key == 13) { // enter + this.executeCommand(field.value); + field.value = ""; + return false; + } + return true; + } +}; + +WebInspector.DebuggerPanel.prototype.__proto__ = WebInspector.Panel.prototype; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/DebuggerShell.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/DebuggerShell.js new file mode 100644 index 0000000..907dce7 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/DebuggerShell.js @@ -0,0 +1,1458 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview Shell objects and global helper functions for Chrome + * automation shell / debugger. This file is loaded into the global namespace + * of the interactive shell, so users can simply call global functions + * directly. + */ + +// TODO(erikkay): look into how this can be split up into multiple files +// It's currently loaded explicitly by Chrome, so maybe I need an "include" +// or "source" builtin to allow a core source file to reference multiple +// sub-files. + +/** + * Sequence number of the DebugCommand. + */ +DebugCommand.next_seq_ = 0; + +/** + * Command messages to be sent to the debugger. + * @constructor + */ +function DebugCommand(str) { + this.command = undefined; + // first, strip off of the leading word as the command + var argv = str.split(' '); + this.user_command = argv.shift(); + // the rest of the string is argv to the command + str = argv.join(' '); + if (DebugCommand.aliases[this.user_command]) + this.user_command = DebugCommand.aliases[this.user_command]; + if (this.parseArgs_(str) == 1) + this.type = "request"; + if (this.command == undefined) + this.command = this.user_command; +}; + +// Mapping of some control characters to avoid the \uXXXX syntax for most +// commonly used control cahracters. +const ctrlCharMap_ = { + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '"' : '\\"', + '\\': '\\\\' +}; + +// Regular expression matching ", \ and control characters (0x00 - 0x1F) +// globally. +const ctrlCharMatch_ = /["\\\\\x00-\x1F]/g; + +/** + * Convert a String to its JSON representation. + * @param {String} value - String to be converted + * @return {String} JSON formatted String + */ +DebugCommand.stringToJSON = function(value) { + // Check for" , \ and control characters (0x00 - 0x1F). + if (ctrlCharMatch_.test(value)) { + // Replace ", \ and control characters (0x00 - 0x1F). + return '"' + value.replace(ctrlCharMatch_, function (char) { + // Use charmap if possible. + var mapped = ctrlCharMap_[char]; + if (mapped) return mapped; + mapped = char.charCodeAt(); + // Convert control character to unicode escape sequence. + var dig1 = (Math.floor(mapped / 16)); + var dig2 = (mapped % 16) + return '\\u00' + dig1.toString(16) + dig2.toString(16); + }) + + '"'; + } + + // Simple string with no special characters. + return '"' + value + '"'; +}; + +/** + * @return {bool} True if x is an integer. + */ +DebugCommand.isInt = function(x) { + var y = parseInt(x); + if (isNaN(y)) + return false; + return x == y && x.toString() == y.toString(); +}; + +/** + * @return {float} log base 10 of num + */ +DebugCommand.log10 = function(num) { + return Math.log(num)/Math.log(10); +}; + +/** + * Take an object and encode it (non-recursively) as a JSON dict. + * @param {Object} obj - object to encode + */ +DebugCommand.toJSON = function(obj) { + // TODO(erikkay): use a real JSON library + var json = '{'; + for (var key in obj) { + if (json.length > 1) + json += ","; + var val = obj[key]; + if (!DebugCommand.isInt(val)) { + val = DebugCommand.stringToJSON(val.toString()); + } + json += '"' + key + '":' + val; + } + json += '}'; + return json; +}; + +/** + * Encode the DebugCommand object into the V8 debugger JSON protocol format. + */ +DebugCommand.prototype.toJSONProtocol = function() { + // TODO(erikkay): use a real JSON library + var json = '{'; + json += '"seq":"' + this.seq; + json += '","type":"' + this.type; + json += '","command":"' + this.command + '"'; + if (this.arguments) { + json += ',"arguments":' + DebugCommand.toJSON(this.arguments); + } + json += '}' + return json; +} + +/** + * Encode the contents of this message and send it to the debugger. + * @param {Object} tab - tab being debugged. This is an internal + * Chrome object. + */ +DebugCommand.prototype.sendToDebugger = function(tab) { + this.seq = DebugCommand.next_seq_++; + str = this.toJSONProtocol(); + dprint("sending: " + str); + tab.sendToDebugger(str); +}; + +DebugCommand.trim = function(str) { + return str.replace(/^\s*/, '').replace(/\s*$/, ''); +}; + +/** + * Strip off a trailing parameter after a ':'. As the identifier for the + * source can contain ':' characters (e.g. 'http://www....) something after + * a ':' is only considered a parameter if it is numeric. + * @return {Array} two element array, the trimmed string and the parameter, + * or -1 if no parameter + */ +DebugCommand.stripTrailingParameter = function(str, opt_separator) { + var sep = opt_separator || ':'; + var index = str.lastIndexOf(sep); + // If a separator character if found strip if numeric. + if (index != -1) { + var value = parseInt(str.substring(index + 1, str.length), 10); + if (isNaN(value) || value < 0) { + return [str, -1]; + } + str = str.substring(0, index); + return [str, value]; + } + return [str, -1]; +}; + +/** + * Format source and location strings based on source location input data. + * @param {Object} script - script information object + * @param {String} source - source code for the current location + * @param {int} line - line number (0-based) + * @param {String} func - function name + * @return {array} [location(string), source line(string), line number(int)] + */ +DebugCommand.getSourceLocation = function(script, source, line, func) { + // source line is 0-based, we present as 1-based + line++; + + // TODO(erikkay): take column into account as well + if (source) + source = "" + line + ": " + source; + var location = ''; + if (func) { + location = func + ", "; + } + location += script ? script.name : '[no source]'; + return [location, source, line]; +}; + +/** + * Aliases for debugger commands. + */ +DebugCommand.aliases = { + 'b': 'break', + 'bi': 'break_info', + 'br': 'break', + 'bt': 'backtrace', + 'c': 'continue', + 'f': 'frame', + 'h': 'help', + '?': 'help', + 'ls': 'source', + 'n': 'next', + 'p': 'print', + 's': 'step', + 'so': 'stepout', +}; + +/** + * Parses arguments to "args" and "locals" command, and initializes + * the underlying DebugCommand (which is a frame request). + * @see DebugCommand.commands + * @param {string} str The arguments to be parsed. + * @return -1 for usage error, 1 for success + */ +DebugCommand.prototype.parseArgsAndLocals_ = function(str) { + this.command = "frame"; + return str.length ? -1 : 1; +}; + +/** + * Parses arguments to "break_info" command, and executes it. + * "break_info" has an optional argument, which is the breakpoint + * identifier. + * @see DebugCommand.commands + * @param {string} str - The arguments to be parsed. + * @return -1 for usage error, 0 for success + */ +DebugCommand.prototype.parseBreakInfo_ = function(str) { + this.type = "shell"; + + // Array of breakpoints to be printed by this command + // (default to all breakpoints) + var breakpointsToPrint = shell_.breakpoints; + + if (str.length > 0) { + // User specified an invalid breakpoint (not a number) + if (!str.match(/^\s*\d+\s*$/)) + return -1; // invalid usage + + // Check that the specified breakpoint identifier exists + var id = parseInt(str); + var info = shell_.breakpoints[id]; + if (!info) { + print("Error: Invalid breakpoint"); + return 0; // success (of sorts) + } + breakpointsToPrint = [info]; + } else { + // breakpointsToPrint.length isn't accurate, because of + // deletions + var num_breakpoints = 0; + for (var i in breakpointsToPrint) num_breakpoints++; + + print("Num breakpoints: " + num_breakpoints); + } + + DebugShell.printBreakpoints_(breakpointsToPrint); + + return 0; // success +} + +/** + * Parses arguments to "step" command. + * @see DebugCommand.commands + * @param {string} str The arguments to be parsed. + * @return -1 for usage error, 1 for success + */ +DebugCommand.prototype.parseStep_ = function(str, opt_stepaction) { + this.command = "continue"; + action = opt_stepaction || "in"; + this.arguments = {"stepaction" : action} + if (str.length) { + count = parseInt(str); + if (count > 0) { + this.arguments["stepcount"] = count; + } else { + return -1; + } + } + return 1; +}; + +/** + * Parses arguments to "step" command. + * @see DebugCommand.commands + * @param {string} str The arguments to be parsed. + * @return -1 for usage error, 1 for success + */ +DebugCommand.prototype.parseStepOut_ = function(str) { + return this.parseStep_(str, "out"); +}; + +/** + * Parses arguments to "next" command. + * @see DebugCommand.commands + * @param {string} str The arguments to be parsed. + * @return -1 for usage error, 1 for success + */ +DebugCommand.prototype.parseNext_ = function(str) { + return this.parseStep_(str, "next"); +}; + +/** + * Parse the arguments to "print" command. + * @see DebugCommand.commands + * @param {string} str The arguments to be parsed. + * @return 1 - always succeeds + */ +DebugCommand.prototype.parsePrint_ = function(str) { + this.command = "evaluate"; + this.arguments = { "expression" : str }; + // If the page is in the running state, then we force the expression to + // evaluate in the global context to avoid evaluating in a random context. + if (shell_.running) + this.arguments["global"] = true; + return 1; +}; + +/** + * Handle the response to a "print" command and display output to user. + * @param {ProtocolPacket} evaluate_response - the V8 debugger response object + */ +DebugCommand.responsePrint_ = function(evaluate_response) { + body = evaluate_response.body(); + if (body['text'] != undefined) { + print(body['text']); + } else { + // TODO(erikkay): is "text" ever not set? + print("can't print response"); + } +}; + +/** + * Parse the arguments to "dir" command. + * @see DebugCommand.commands + * @param {string} str The arguments to be parsed. + * @return 1 - always succeeds + */ +DebugCommand.prototype.parseDir_ = function(str) { + this.command = "evaluate"; + this.arguments = { "expression" : str }; + // If the page is in the running state, then we force the expression to + // evaluate in the global context to avoid evaluating in a random context. + if (shell_.running) + this.arguments["global"] = true; + return 1; +}; + +/** + * Handle the response to a "dir" command and display output to user. + * @see http://wiki/Main/V8Debugger + * @param {ProtocolPacket} evaluate_response - the V8 debugger response object + */ +DebugCommand.responseDir_ = function(evaluate_response) { + var body = evaluate_response.body(); + if (body.properties) { + print(body.properties.length + ' properties'); + for (var n in body.properties) { + var property_info = body.properties[n].name; + property_info += ': '; + var value = evaluate_response.lookup(body.properties[n].ref); + if (value && value.type) { + property_info += value.type; + } else { + property_info += '<no type>'; + } + property_info += ' (#'; + property_info += body.properties[n].ref; + property_info += '#)'; + print(property_info); + } + } +}; + +/** + * Parses arguments to "break" command. See DebugCommand.commands below + * for syntax details. + * @see DebugCommand.commands + * @param {string} str The arguments to be parsed. + * @return -1 for usage error, 1 for success, 0 for handled internally + */ +DebugCommand.prototype.parseBreak_ = function(str) { + function stripTrailingParameter() { + var ret = DebugCommand.stripTrailingParameter(str, ':'); + str = ret[0]; + return ret[1]; + } + + if (str.length == 0) { + this.command = "break"; + return 1; + } else { + var parts = str.split(/\s+/); + var condition = null; + if (parts.length > 1) { + str = parts.shift(); + condition = parts.join(" "); + } + + this.command = "setbreakpoint"; + + // Locate ...[:line[:column]] if present. + var line = -1; + var column = -1; + line = stripTrailingParameter(); + if (line != -1) { + line -= 1; + var l = stripTrailingParameter(); + if (l != -1) { + column = line; + line = l - 1; + } + } + + if (line == -1 && column == -1) { + this.arguments = { 'type' : 'function', + 'target' : str }; + } else { + var script = shell_.matchScript(str, line); + if (script) { + this.arguments = { 'type' : 'script', + 'target' : script.name }; + } else { + this.arguments = { 'type' : 'function', + 'target' : str }; + } + this.arguments.line = line; + if (column != -1) + this.arguments.position = column; + } + if (condition) + this.arguments.condition = condition; + } + return 1; +}; + +/** + * Handle the response to a "break" command and display output to user. + * @param {ResponsePacket} setbreakpoint_response - the V8 debugger response + * object + */ +DebugCommand.responseBreak_ = function(setbreakpoint_response) { + var body = setbreakpoint_response.body(); + var info = new BreakpointInfo( + parseInt(body.breakpoint), + setbreakpoint_response.command.arguments.type, + setbreakpoint_response.command.arguments.target, + setbreakpoint_response.command.arguments.line, + setbreakpoint_response.command.arguments.position, + setbreakpoint_response.command.arguments.condition); + shell_.addedBreakpoint(info); +}; + +/** + * Parses arguments to "backtrace" command. See DebugCommand.commands below + * for syntax details. + * @see DebugCommand.commands + * @param {string} str The arguments to be parsed. + * @return -1 for usage error, 1 for success + */ + DebugCommand.prototype.parseBacktrace_ = function(str) { + if (str.length > 0) { + var parts = str.split(/\s+/); + var non_empty_parts = parts.filter(function(s) { return s.length > 0; }); + // We need exactly two arguments. + if (non_empty_parts.length != 2) { + return -1; + } + var from = parseInt(non_empty_parts[0], 10); + var to = parseInt(non_empty_parts[1], 10); + // The two arguments have to be integers. + if (from != non_empty_parts[0] || to != non_empty_parts[1]) { + return -1; + } + this.arguments = { 'fromFrame': from, 'toFrame': to + 1 }; + } else { + // Default to fetching the first 10 frames. + this.arguments = { 'fromFrame': 0, 'toFrame': 10 }; + } + return 1; +}; + +/** + * Handle the response to a "backtrace" command and display output to user. + * @param {ResponsePacket} backtrace_response - the V8 debugger response object + */ +DebugCommand.responseBacktrace_ = function(backtrace_response) { + body = backtrace_response.body(); + if (body && body.totalFrames) { + print('Frames #' + body.fromFrame + ' to #' + (body.toFrame - 1) + + ' of ' + body.totalFrames + ":"); + for (var i = 0; i < body.frames.length; i++) { + print(body.frames[i].text); + } + } else { + print("unimplemented (sorry)"); + } +}; + + +/** + * Parses arguments to "clear" command. See DebugCommand.commands below + * for syntax details. + * @see DebugCommand.commands + * @param {string} str The arguments to be parsed. + * @return -1 for usage error, 1 for success + */ +DebugCommand.prototype.parseClearCommand_ = function(str) { + this.command = "clearbreakpoint"; + if (str.length > 0) { + var i = parseInt(str, 10); + if (i != str) { + return -1; + } + this.arguments = { 'breakpoint': i }; + } + return 1; +} + +/** + * Handle the response to a "clear" command and display output to user. + * @param {ResponsePacket} clearbreakpoint_response - the V8 debugger response + * object + */ +DebugCommand.responseClear_ = function(clearbreakpoint_response) { + var body = clearbreakpoint_response.body(); + shell_.clearedBreakpoint(parseInt(msg.command.arguments.breakpoint)); +} + + +/** + * Parses arguments to "continue" command. See DebugCommand.commands below + * for syntax details. + * @see DebugCommand.commands + * @param {string} str The arguments to be parsed. + * @return -1 for usage error, 1 for success + */ +DebugCommand.prototype.parseContinueCommand_ = function(str) { + this.command = "continue"; + if (str.length > 0) { + return -1; + } + return 1; +} + +/** + * Parses arguments to "frame" command. See DebugCommand.commands below + * for syntax details. + * @see DebugCommand.commands + * @param {string} str The arguments to be parsed. + * @return -1 for usage error, 1 for success + */ +DebugCommand.prototype.parseFrame_ = function(str) { + if (str.length > 0) { + var i = parseInt(str, 10); + if (i != str) { + return -1; + } + this.arguments = { 'number': i }; + } + return 1; +}; + +/** + * Handle the response to a "frame" command and display output to user. + * @param {ResponsePacket} frame_response - the V8 debugger response object + */ +DebugCommand.responseFrame_ = function(frame_response) { + var body = frame_response.body(); + var func = frame_response.lookup(body.func.ref); + loc = DebugCommand.getSourceLocation(func.script, + body.sourceLineText, body.line, func.name); + print("#" + (body.index <= 9 ? '0' : '') + body.index + " " + loc[0]); + print(loc[1]); + shell_.current_frame = body.index; + shell_.current_line = loc[2]; + shell_.current_script = func.script; +}; + +/** + * Handle the response to a "args" command and display output to user. + * @param {ProtocolPacket} frame_response - the V8 debugger response object (for + * "frame" command) + */ +DebugCommand.responseArgs_ = function(frame_response) { + var body = frame_response.body(); + DebugCommand.printVariables_(body.arguments, frame_response); +} + +/** + * Handle the response to a "locals" command and display output to user. + * @param {Object} msg - the V8 debugger response object (for "frame" command) + */ +DebugCommand.responseLocals_ = function(frame_response) { + var body = frame_response.body(); + DebugCommand.printVariables_(body.locals, frame_response); +} + +DebugCommand.printVariables_ = function(variables, protocol_packet) { + for (var i = 0; i < variables.length; i++) { + print(variables[i].name + " = " + + DebugCommand.toPreviewString_(protocol_packet.lookup(variables[i].value.ref))); + } +} + +DebugCommand.toPreviewString_ = function(value) { + // TODO(ericroman): pretty print arrays and objects, recursively. + // TODO(ericroman): truncate length of preview if too long? + if (value.type == "string") { + // Wrap the string in quote marks and JS-escape + return DebugCommand.stringToJSON(value.text); + } + return value.text; +} + +/** + * Parses arguments to "scripts" command. + * @see DebugCommand.commands + * @param {string} str - The arguments to be parsed. + * @return -1 for usage error, 1 for success + */ +DebugCommand.prototype.parseScripts_ = function(str) { + return 1 +}; + +/** + * Handle the response to a "scripts" command and display output to user. + * @param {ResponsePacket} scripts_response - the V8 debugger response object + */ +DebugCommand.responseScripts_ = function(scripts_response) { + scripts = scripts_response.body(); + shell_.scripts = []; + for (var i in scripts) { + var script = scripts[i]; + + // Add this script to the internal list of scripts. + shell_.scripts.push(script); + + // Print result if this response was the result of a user command. + if (scripts_response.command.from_user) { + var name = script.name; + if (name) { + if (script.lineOffset > 0) { + print(name + " (lines " + script.lineOffset + "-" + + (script.lineOffset + script.lineCount - 1) + ")"); + } else { + print(name + " (lines " + script.lineCount + ")"); + } + } else { + // For unnamed scripts (typically eval) display some source. + var sourceStart = script.sourceStart; + if (sourceStart.length > 40) + sourceStart = sourceStart.substring(0, 37) + '...'; + print("[unnamed] (source:\"" + sourceStart + "\")"); + } + } + } +}; + +/** + * Parses arguments to "source" command. + * @see DebugCommand.commands + * @param {string} str - The arguments to be parsed. + * @return -1 for usage error, 1 for success + */ +DebugCommand.prototype.parseSource_ = function(str) { + this.arguments = {}; + if (this.current_frame > 0) + this.arguments.frame = this.current_frame; + if (str.length) { + var args = str.split(" "); + if (args.length == 1) { + // with 1 argument n, we print 10 lines starting at n + var num = parseInt(args[0]); + if (num > 0) { + this.arguments.fromLine = num - 1; + this.arguments.toLine = this.arguments.fromLine + 10; + } else { + return -1; + } + } else if (args.length == 2) { + // with 2 arguments x and y, we print from line x to line x + y + var from = parseInt(args[0]); + var len = parseInt(args[1]); + if (from > 0 && len > 0) { + this.arguments.fromLine = from - 1; + this.arguments.toLine = this.arguments.fromLine + len; + } else { + return -1; + } + } else { + return -1; + } + if (this.arguments.fromLine < 0) + return -1; + if (this.arguments.toLine <= this.arguments.fromLine) + return -1; + } else if (shell_.current_line > 0) { + // with no arguments, we print 11 lines with the current line as the center + this.arguments.fromLine = + Math.max(0, shell_.current_line - 6); + this.arguments.toLine = this.arguments.fromLine + 11; + } + return 1; +}; + +/** + * Handle the response to a "source" command and display output to user. + * @param {ProtocolPacket} source_response - the V8 debugger response object + */ +DebugCommand.responseSource_ = function(source_response) { + var body = source_response.body(); + var from_line = parseInt(body.fromLine) + 1; + var source = body.source; + var lines = source.split('\n'); + var maxdigits = 1 + Math.floor(DebugCommand.log10(from_line + lines.length)) + for (var num in lines) { + // there's an extra newline at the end + if (num >= (lines.length - 1) && lines[num].length == 0) + break; + spacer = maxdigits - (1 + Math.floor(DebugCommand.log10(from_line))) + var line = ""; + if (from_line == shell_.current_line) { + for (var i = 0; i < (maxdigits + 2); i++) + line += ">"; + } else { + for (var i = 0; i < spacer; i++) + line += " "; + line += from_line + ": "; + } + line += lines[num]; + print(line); + from_line++; + } +}; + +/** + * Parses arguments to "help" command. See DebugCommand.commands below + * for syntax details. + * @see DebugCommand.commands + * @param {string} str The arguments to be parsed. + * @return 0 for handled internally + */ +DebugCommand.parseHelp_ = function(str) { + DebugCommand.help(str); + return 0; +}; + +/** + * Takes argument and evaluates it in the context of the shell to allow commands + * to be escaped to the outer shell. Used primarily for development purposes. + * @see DebugCommand.commands + * @param {string} str The expression to be evaluated + * @return 0 for handled internally + */ +DebugCommand.parseShell_ = function(str) { + print(eval(str)); + return 0; +} + +DebugCommand.parseShellDebug_ = function(str) { + shell_.debug = !shell_.debug; + if (shell_.debug) { + print("shell debugging enabled"); + } else { + print("shell debugging disabled"); + } + return 0; +} + +/** + * Parses a user-entered command string. + * @param {string} str The arguments to be parsed. + */ +DebugCommand.prototype.parseArgs_ = function(str) { + if (str.length) + str = DebugCommand.trim(str); + var cmd = DebugCommand.commands[this.user_command]; + if (cmd) { + var parse = cmd['parse']; + if (parse == undefined) { + print('>>>can\'t find parse func for ' + this.user_command); + this.type = "error"; + } else { + var ret = parse.call(this, str); + if (ret > 0) { + // Command gererated a debugger request. + this.type = "request"; + } else if (ret == 0) { + // Command handeled internally. + this.type = "handled"; + } else if (ret < 0) { + // Command error. + this.type = "handled"; + DebugCommand.help(this.user_command); + } + } + } else { + this.type = "handled"; + print('unknown command: ' + this.user_command); + DebugCommand.help(); + } +}; + +/** + * Displays command help or all help. + * @param {string} opt_str Which command to print help for. + */ +DebugCommand.help = function(opt_str) { + if (opt_str) { + var cmd = DebugCommand.commands[opt_str]; + var usage = cmd.usage; + print('usage: ' + usage); + // Print additional details for the command. + if (cmd.help) { + print(cmd.help); + } + } else { + if (shell_.running) { + print('Status: page is running'); + } else { + print('Status: page is paused'); + } + print('Available commands:'); + for (var key in DebugCommand.commands) { + var cmd = DebugCommand.commands[key]; + if (!cmd['hidden'] && (!shell_.running || cmd['while_running'])) { + var usage = cmd.usage; + print(' ' + usage); + } + } + } +}; + +/** + * Valid commands, their argument parser and their associated usage text. + */ +DebugCommand.commands = { + 'args': { 'parse': DebugCommand.prototype.parseArgsAndLocals_, + 'usage': 'args', + 'help': 'summarize the arguments to the current function.', + 'response': DebugCommand.responseArgs_ }, + 'break': { 'parse': DebugCommand.prototype.parseBreak_, + 'response': DebugCommand.responseBreak_, + 'usage': 'break [location] <condition>', + 'help': 'location is one of <function> | <script:function> | <script:line> | <script:line:pos>', + 'while_running': true }, + 'break_info': { 'parse': DebugCommand.prototype.parseBreakInfo_, + 'usage': 'break_info [breakpoint #]', + 'help': 'list the current breakpoints, or the details on a single one', + 'while_running': true }, + 'backtrace': { 'parse': DebugCommand.prototype.parseBacktrace_, + 'response': DebugCommand.responseBacktrace_, + 'usage': 'backtrace [from frame #] [to frame #]' }, + 'clear': { 'parse': DebugCommand.prototype.parseClearCommand_, + 'response': DebugCommand.responseClear_, + 'usage': 'clear <breakpoint #>', + 'while_running': true }, + 'continue': { 'parse': DebugCommand.prototype.parseContinueCommand_, + 'usage': 'continue' }, + 'dir': { 'parse': DebugCommand.prototype.parseDir_, + 'response': DebugCommand.responseDir_, + 'usage': 'dir <expression>', + 'while_running': true }, + 'frame': { 'parse': DebugCommand.prototype.parseFrame_, + 'response': DebugCommand.responseFrame_, + 'usage': 'frame <frame #>' }, + 'help': { 'parse': DebugCommand.parseHelp_, + 'usage': 'help [command]', + 'while_running': true }, + 'locals': { 'parse': DebugCommand.prototype.parseArgsAndLocals_, + 'usage': 'locals', + 'help': 'summarize the local variables for current frame', + 'response': DebugCommand.responseLocals_ }, + 'next': { 'parse': DebugCommand.prototype.parseNext_, + 'usage': 'next' } , + 'print': { 'parse': DebugCommand.prototype.parsePrint_, + 'response': DebugCommand.responsePrint_, + 'usage': 'print <expression>', + 'while_running': true }, + 'scripts': { 'parse': DebugCommand.prototype.parseScripts_, + 'response': DebugCommand.responseScripts_, + 'usage': 'scripts', + 'while_running': true }, + 'source': { 'parse': DebugCommand.prototype.parseSource_, + 'response': DebugCommand.responseSource_, + 'usage': 'source [from line] | [<from line> <num lines>]' }, + 'step': { 'parse': DebugCommand.prototype.parseStep_, + 'usage': 'step' }, + 'stepout': { 'parse': DebugCommand.prototype.parseStepOut_, + 'usage': 'stepout' }, + // local eval for debugging - remove this later + 'shell': { 'parse': DebugCommand.parseShell_, + 'usage': 'shell <expression>', + 'while_running': true, + 'hidden': true }, + 'shelldebug': { 'parse': DebugCommand.parseShellDebug_, + 'usage': 'shelldebug', + 'while_running': true, + 'hidden': true }, +}; + + +/** + * Debug shell using the new JSON protocol + * @param {Object} tab - which tab is to be debugged. This is an internal + * Chrome object. + * @constructor + */ +function DebugShell(tab) { + this.tab = tab; + this.tab.attach(); + this.ready = true; + this.running = true; + this.current_command = undefined; + this.pending_commands = []; + // The auto continue flag is used to indicate whether the JavaScript execution + // should automatically continue after a break event and the processing of + // pending commands. This is used to make it possible for the user to issue + // commands, e.g. setting break points, without making an explicit break. In + // this case the debugger will silently issue a forced break issue the command + // and silently continue afterwards. + this.auto_continue = false; + this.debug = false; + this.current_line = -1; + this.current_pos = -1; + this.current_frame = 0; + this.current_script = undefined; + this.scripts = []; + + // Mapping of breakpoints id --> info. + // Must use numeric keys. + this.breakpoints = []; +}; + +DebugShell.prototype.set_ready = function(ready) { + if (ready != this.ready) { + this.ready = ready; + ChromeNode.setDebuggerReady(this.ready); + } +}; + +DebugShell.prototype.set_running = function(running) { + if (running != this.running) { + this.running = running; + ChromeNode.setDebuggerBreak(!this.running); + } +}; + +/** + * Execute a constructed DebugCommand object if possible, otherwise pend. + * @param cmd {DebugCommand} - command to execute + */ +DebugShell.prototype.process_command = function(cmd) { + dprint("Running: " + (this.running ? "yes" : "no")); + + // The "break" commands needs to be handled seperatly + if (cmd.command == "break") { + if (this.running) { + // Schedule a break. + print("Stopping JavaScript execution..."); + this.tab.debugBreak(false); + } else { + print("JavaScript execution already stopped."); + } + return; + } + + // If page is running an break needs to be issued. + if (this.running) { + // Some requests are not valid when the page is running. + var cmd_info = DebugCommand.commands[cmd.user_command]; + if (!cmd_info['while_running']) { + print(cmd.user_command + " can only be run while paused"); + return; + } + + // Add the command as pending before scheduling a break. + this.pending_commands.push(cmd); + dprint("pending command: " + cmd.toJSONProtocol()); + + // Schedule a forced break and enable auto continue. + this.tab.debugBreak(true); + this.auto_continue = true; + this.set_ready(false); + return; + } + + // If waiting for a response add command as pending otherwise send the + // command. + if (this.current_command) { + this.pending_commands.push(cmd); + dprint("pending command: " + cmd.toJSONProtocol()); + } else { + this.current_command = cmd; + cmd.sendToDebugger(this.tab); + this.set_ready(false); + } +}; + +/** + * Handle a break event from the debugger. + * @param msg {ResponsePacket} - break_event protocol message to handle + */ +DebugShell.prototype.event_break = function(break_event) { + this.current_frame = 0; + this.set_running(false); + var body = break_event.body(); + if (body) { + this.current_script = body.script; + var loc = DebugCommand.getSourceLocation(body.script, + body.sourceLineText, body.sourceLine, body.invocationText); + var location = loc[0]; + var source = loc[1]; + this.current_line = loc[2]; + if (body.breakpoints) { + // Always disable auto continue if a real break point is hit. + this.auto_continue = false; + var breakpoints = body.breakpoints; + print("paused at breakpoint " + breakpoints.join(",") + ": " + + location); + for (var i = 0; i < breakpoints.length; i++) + this.didHitBreakpoint(parseInt(breakpoints[i])); + } else if (body.scriptData == "") { + print("paused"); + } else { + // step, stepout, next, "break" and a "debugger" line in the code + // are all treated the same (they're not really distinguishable anyway) + if (location != this.last_break_location) { + // We only print the location (function + script) when it changes, + // so as we step, you only see the source line when you transition + // to a new script and/or function. Also if auto continue is enables + // don't print the break location. + if (!this.auto_continue) + print(location); + } + } + // Print th current source line unless auto continue is enabled. + if (source && !this.auto_continue) + print(source); + this.last_break_location = location; + } + if (!this.auto_continue) + this.set_ready(true); +}; + +/** + * Handle an exception event from the debugger. + * @param msg {ResponsePacket} - exception_event protocol message to handle + */ +DebugShell.prototype.event_exception = function(exception_event) { + this.set_running(false); + this.set_ready(true); + var body = exception_event.body(); + if (body) { + if (body["uncaught"]) { + print("uncaught exception " + body["exception"].text); + } else { + print("paused at exception " + body["exception"].text); + } + } +}; + +DebugShell.prototype.matchScript = function(script_match, line) { + var script = null; + // In the v8 debugger, all scripts have a name, line offset and line count + // Script names are usually URLs which are a pain to have to type again and + // again, so we match the tail end of the script name. This makes it easy + // to type break foo.js:23 rather than + // http://www.foo.com/bar/baz/quux/test/foo.js:23. In addition to the tail + // of the name we also look at the lines the script cover. If there are + // several scripts with the same tail including the requested line we match + // the first one encountered. + // TODO(sgjesse) Find how to handle several matching scripts. + var candidate_scripts = []; + for (var i in this.scripts) { + if (this.scripts[i].name && + this.scripts[i].name.indexOf(script_match) >= 0) { + candidate_scripts.push(this.scripts[i]); + } + } + for (var i in candidate_scripts) { + var s = candidate_scripts[i]; + var from = s.lineOffset; + var to = from + s.lineCount; + if (from <= line && line < to) { + script = s; + break; + } + } + if (script) + return script; + else + return null; +} + +// The Chrome Subshell interface requires: +// prompt(), command(), response(), exit() and on_disconnect() + +/** + * Called by Chrome Shell to get a prompt string to display. + */ +DebugShell.prototype.prompt = function() { + if (this.current_command) + return ''; + if (!this.running) + return 'v8(paused)> '; + else + return 'v8(running)> '; +}; + +/** + * Called by Chrome Shell when command input has been received from the user. + */ +DebugShell.prototype.command = function(str) { + if (this.tab) { + str = DebugCommand.trim(str); + if (str.length) { + var cmd = new DebugCommand(str); + cmd.from_user = true; + if (cmd.type == "request") + this.process_command(cmd); + } + } else { + print(">>not connected to a tab"); + } +}; + +/** + * Called by Chrome Shell when a response to a previous command has been + * received. + * @param {Object} msg Message object. + */ +DebugShell.prototype.response = function(msg) { + dprint("received: " + (msg && msg.type)); + var response; + try { + response = new ProtocolPackage(msg); + } catch (error) { + print(error.toString(), str); + return; + } + if (response.type() == "event") { + ev = response.event(); + if (ev == "break") { + this.event_break(response); + } else if (ev == "exception") { + this.event_exception(response); + } + } else if (response.type() == "response") { + if (response.requestSeq() != undefined) { + if (!this.current_command || this.current_command.seq != response.requestSeq()){ + throw("received response to unknown command " + str); + } + } else { + // TODO(erikkay): should we reject these when they happen? + print(">>no request_seq in response " + str); + } + var cmd = DebugCommand.commands[this.current_command.user_command] + response.command = this.current_command; + this.current_command = null + this.set_running(response.running()); + if (!response.success()) { + print(response.message()); + } else { + var handler = cmd['response']; + if (handler != undefined) { + handler.call(this, response); + } + } + this.set_ready(true); + } + + // Process next pending command if any. + if (this.pending_commands.length) { + this.process_command(this.pending_commands.shift()); + } else if (this.auto_continue) { + // If no more pending commands and auto continue is active issue a continue command. + this.auto_continue = false; + this.process_command(new DebugCommand("continue")); + } +}; + +/** + * Called when a breakpoint has been set. + * @param {BreakpointInfo} info - details of breakpoint set. + */ +DebugShell.prototype.addedBreakpoint = function(info) { + print("set breakpoint #" + info.id); + this.breakpoints[info.id] = info; +} + +/** + * Called when a breakpoint has been cleared. + * @param {int} id - the breakpoint number that was cleared. + */ +DebugShell.prototype.clearedBreakpoint = function(id) { + assertIsNumberType(id, "clearedBreakpoint called with invalid id"); + + print("cleared breakpoint #" + id); + delete this.breakpoints[id]; +} + +/** + * Called when a breakpoint has been reached. + * @param {int} id - the breakpoint number that was hit. + */ +DebugShell.prototype.didHitBreakpoint = function(id) { + assertIsNumberType(id, "didHitBreakpoint called with invalid id"); + + var info = this.breakpoints[id]; + if (!info) + throw "Could not find breakpoint #" + id; + + info.hit_count ++; +} + +/** + * Print a summary of the specified breakpoints. + * + * @param {Array<BreakpointInfo>} breakpointsToPrint - List of breakpoints. The + * index is unused (id is determined from the info). + */ +DebugShell.printBreakpoints_ = function(breakpoints) { + // TODO(ericroman): this would look much nicer if we could output as an HTML + // table. I tried outputting as formatted text table, but this looks aweful + // once it triggers wrapping (which is very likely if the target is a script) + + // Output as a comma separated list of key=value + for (var i in breakpoints) { + var b = breakpoints[i]; + var props = ["id", "hit_count", "type", "target", "line", "position", + "condition"]; + var propertyList = []; + for (var i = 0; i < props.length; i++) { + var prop = props[i]; + var val = b[prop]; + if (val != undefined) + propertyList.push(prop + "=" + val); + } + print(propertyList.join(", ")); + } +} + +/** + * Called by Chrome Shell when the outer shell is detaching from debugging + * this tab. + */ +DebugShell.prototype.exit = function() { + if (this.tab) { + this.tab.detach(); + this.tab = null; + } +}; + +/** + * Called by the Chrome Shell when the tab that the shell is debugging + * have attached. + */ +DebugShell.prototype.on_attach = function(title) { + if (!title) + title = "Untitled"; + print('attached to ' + title); + // on attach, we update our current script list + var cmd = new DebugCommand("scripts"); + cmd.from_user = false; + this.process_command(cmd); +}; + + +/** + * Called by the Chrome Shell when the tab that the shell is debugging + * went away. + */ +DebugShell.prototype.on_disconnect = function() { + print(">>lost connection to tab"); + this.tab = null; +}; + + +/** + * Protocol packages send from the debugger. + * @param {string} json - raw protocol packet as JSON string. + * @constructor + */ +function ProtocolPackage(msg) { + this.packet_ = msg; + this.refs_ = []; + if (this.packet_.refs) { + for (var i = 0; i < this.packet_.refs.length; i++) { + this.refs_[this.packet_.refs[i].handle] = this.packet_.refs[i]; + } + } +} + + +/** + * Get the packet type. + * @return {String} the packet type + */ +ProtocolPackage.prototype.type = function() { + return this.packet_.type; +} + + +/** + * Get the packet event. + * @return {Object} the packet event + */ +ProtocolPackage.prototype.event = function() { + return this.packet_.event; +} + + +/** + * Get the packet request sequence. + * @return {number} the packet request sequence + */ +ProtocolPackage.prototype.requestSeq = function() { + return this.packet_.request_seq; +} + + +/** + * Get the packet request sequence. + * @return {number} the packet request sequence + */ +ProtocolPackage.prototype.running = function() { + return this.packet_.running ? true : false; +} + + +ProtocolPackage.prototype.success = function() { + return this.packet_.success ? true : false; +} + + +ProtocolPackage.prototype.message = function() { + return this.packet_.message; +} + + +ProtocolPackage.prototype.body = function() { + return this.packet_.body; +} + + +ProtocolPackage.prototype.lookup = function(handle) { + return this.refs_[handle]; +} + + +/** + * Structure that holds the details about a breakpoint. + * @constructor + * + * @param {int} id - breakpoint number + * @param {string} type - "script" or "function" + * @param {string} target - either a function name, or script url + * @param {int} line - line number in the script, or undefined + * @param {int} position - column in the script, or undefined + * @param {string} condition - boolean expression, or undefined + */ +function BreakpointInfo(id, type, target, line, position, condition) { + this.id = id; + this.type = type; + this.target = target; + + if (line != undefined) + this.line = line; + if (position != undefined) + this.position = position; + if (condition != undefined) + this.condition = condition; + + this.hit_count = 0; + + // Check that the id is numeric, otherwise will run into problems later + assertIsNumberType(this.id, "id is not a number"); +} + +var shell_ = null; +DebugShell.initDebugShell = function(debuggerUI) { + if (!DebugShell.singleton) { + DebugShell.ui = debuggerUI; + DebugShell.singleton = new DebugShell(TabNode); + shell_ = DebugShell.singleton; + + // enable debug output + //shell_.debug = true; + } +}; + +/** + * Print debugging message when DebugShell's debug flag is true. + */ +function dprint(str) { + if (shell_ && shell_.debug) { + print(str); + } +}; + +/** + * Helper that throws error if x is not a number + * @param x {object} - object to test type of + * @param error_message {string} - error to throw on failure + */ +function assertIsNumberType(x, error_message) { + if (typeof x != "number") + throw error_message; +} + +////////////////////// migration staff ////////////////////////// +// This file was copied from chrome\browser\debugger\resources\debugger_shell.js + +function print(txt) { + var ui = DebugShell.ui; + if (ui) { + ui.appendText(txt); + } +} + +var TabNode = { + debugBreak: function(force) { + DebuggerIPC.sendMessage(["debugBreak", force]); + }, + attach: function() { + DebuggerIPC.sendMessage(["attach"]); + }, + detach: function() { + // TODO(yurys): send this from DebugHandler when it's being destroyed? + DebuggerIPC.sendMessage(["detach"]); + }, + sendToDebugger: function(str) { + DebuggerIPC.sendMessage(["sendToDebugger", str]); + } +}; + +var ChromeNode = { + setDebuggerReady: function(isReady) { + DebuggerIPC.sendMessage(["setDebuggerReady", isReady]); + }, + setDebuggerBreak: function(isBreak) { + var ui = DebugShell.ui; + if (ui) { + ui.setDebuggerBreak(isBreak); + } + DebuggerIPC.sendMessage(["setDebuggerBreak", isBreak]); + } +}; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ElementsPanel.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ElementsPanel.js new file mode 100644 index 0000000..3c9be54 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ElementsPanel.js @@ -0,0 +1,1206 @@ +/* + * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008 Matt Lilek <webkit@mattlilek.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. + */ + +WebInspector.ElementsPanel = function() +{ + WebInspector.Panel.call(this); + + this.element.addStyleClass("elements"); + + this.contentElement = document.createElement("div"); + this.contentElement.id = "elements-content"; + this.contentElement.className = "outline-disclosure"; + + this.treeOutline = new WebInspector.ElementsTreeOutline(); + this.treeOutline.panel = this; + this.treeOutline.includeRootDOMNode = false; + this.treeOutline.selectEnabled = true; + + this.treeOutline.focusedNodeChanged = function(forceUpdate) + { + if (this.panel.visible && WebInspector.currentFocusElement !== document.getElementById("search")) + WebInspector.currentFocusElement = document.getElementById("main-panels"); + + this.panel.updateBreadcrumb(forceUpdate); + + for (var pane in this.panel.sidebarPanes) + this.panel.sidebarPanes[pane].needsUpdate = true; + + this.panel.updateStyles(true); + this.panel.updateMetrics(); + this.panel.updateProperties(); + + if (InspectorController.searchingForNode()) { + InspectorController.toggleNodeSearch(); + this.panel.nodeSearchButton.removeStyleClass("toggled-on"); + } + }; + + this.contentElement.appendChild(this.treeOutline.element); + + this.crumbsElement = document.createElement("div"); + this.crumbsElement.className = "crumbs"; + this.crumbsElement.addEventListener("mousemove", this._mouseMovedInCrumbs.bind(this), false); + this.crumbsElement.addEventListener("mouseout", this._mouseMovedOutOfCrumbs.bind(this), false); + + this.sidebarPanes = {}; + this.sidebarPanes.styles = new WebInspector.StylesSidebarPane(); + this.sidebarPanes.metrics = new WebInspector.MetricsSidebarPane(); + this.sidebarPanes.properties = new WebInspector.PropertiesSidebarPane(); + + this.sidebarPanes.styles.onexpand = this.updateStyles.bind(this); + this.sidebarPanes.metrics.onexpand = this.updateMetrics.bind(this); + this.sidebarPanes.properties.onexpand = this.updateProperties.bind(this); + + this.sidebarPanes.styles.expanded = true; + + this.sidebarPanes.styles.addEventListener("style edited", this._stylesPaneEdited, this); + this.sidebarPanes.styles.addEventListener("style property toggled", this._stylesPaneEdited, this); + this.sidebarPanes.metrics.addEventListener("metrics edited", this._metricsPaneEdited, this); + + this.sidebarElement = document.createElement("div"); + this.sidebarElement.id = "elements-sidebar"; + + this.sidebarElement.appendChild(this.sidebarPanes.styles.element); + this.sidebarElement.appendChild(this.sidebarPanes.metrics.element); + this.sidebarElement.appendChild(this.sidebarPanes.properties.element); + + this.sidebarResizeElement = document.createElement("div"); + this.sidebarResizeElement.className = "sidebar-resizer-vertical"; + this.sidebarResizeElement.addEventListener("mousedown", this.rightSidebarResizerDragStart.bind(this), false); + + this.nodeSearchButton = document.createElement("button"); + this.nodeSearchButton.title = WebInspector.UIString("Select an element in the page to inspect it."); + this.nodeSearchButton.id = "node-search-status-bar-item"; + this.nodeSearchButton.className = "status-bar-item"; + this.nodeSearchButton.addEventListener("click", this._nodeSearchButtonClicked.bind(this), false); + + this.searchingForNode = false; + + this.element.appendChild(this.contentElement); + this.element.appendChild(this.sidebarElement); + this.element.appendChild(this.sidebarResizeElement); + + this._mutationMonitoredWindows = []; + this._nodeInsertedEventListener = InspectorController.wrapCallback(this._nodeInserted.bind(this)); + this._nodeRemovedEventListener = InspectorController.wrapCallback(this._nodeRemoved.bind(this)); + this._contentLoadedEventListener = InspectorController.wrapCallback(this._contentLoaded.bind(this)); + + this.reset(); +} + +WebInspector.ElementsPanel.prototype = { + toolbarItemClass: "elements", + + get toolbarItemLabel() + { + return WebInspector.UIString("Elements"); + }, + + get statusBarItems() + { + return [this.nodeSearchButton, this.crumbsElement]; + }, + + updateStatusBarItems: function() + { + this.updateBreadcrumbSizes(); + }, + + show: function() + { + WebInspector.Panel.prototype.show.call(this); + this.sidebarResizeElement.style.right = (this.sidebarElement.offsetWidth - 3) + "px"; + this.updateBreadcrumb(); + this.treeOutline.updateSelection(); + if (this.recentlyModifiedNodes.length) + this._updateModifiedNodes(); + }, + + hide: function() + { + WebInspector.Panel.prototype.hide.call(this); + + WebInspector.hoveredDOMNode = null; + + if (InspectorController.searchingForNode()) { + InspectorController.toggleNodeSearch(); + this.nodeSearchButton.removeStyleClass("toggled-on"); + } + }, + + resize: function() + { + this.treeOutline.updateSelection(); + this.updateBreadcrumbSizes(); + }, + + reset: function() + { + this.rootDOMNode = null; + this.focusedDOMNode = null; + + WebInspector.hoveredDOMNode = null; + + if (InspectorController.searchingForNode()) { + InspectorController.toggleNodeSearch(); + this.nodeSearchButton.removeStyleClass("toggled-on"); + } + + this.recentlyModifiedNodes = []; + this.unregisterAllMutationEventListeners(); + + delete this.currentQuery; + this.searchCanceled(); + + var inspectedWindow = InspectorController.inspectedWindow(); + if (!inspectedWindow || !inspectedWindow.document) + return; + + if (!inspectedWindow.document.firstChild) { + function contentLoaded() + { + inspectedWindow.document.removeEventListener("DOMContentLoaded", contentLoadedCallback, false); + + this.reset(); + } + + var contentLoadedCallback = InspectorController.wrapCallback(contentLoaded.bind(this)); + inspectedWindow.document.addEventListener("DOMContentLoaded", contentLoadedCallback, false); + return; + } + + // If the window isn't visible, return early so the DOM tree isn't built + // and mutation event listeners are not added. + if (!InspectorController.isWindowVisible()) + return; + + this.registerMutationEventListeners(inspectedWindow); + + var inspectedRootDocument = inspectedWindow.document; + this.rootDOMNode = inspectedRootDocument; + + var canidateFocusNode = inspectedRootDocument.body || inspectedRootDocument.documentElement; + if (canidateFocusNode) { + this.treeOutline.suppressSelectHighlight = true; + this.focusedDOMNode = canidateFocusNode; + this.treeOutline.suppressSelectHighlight = false; + + if (this.treeOutline.selectedTreeElement) + this.treeOutline.selectedTreeElement.expand(); + } + }, + + includedInSearchResultsPropertyName: "__includedInInspectorSearchResults", + + searchCanceled: function() + { + if (this._searchResults) { + const searchResultsProperty = this.includedInSearchResultsPropertyName; + for (var i = 0; i < this._searchResults.length; ++i) { + var node = this._searchResults[i]; + + // Remove the searchResultsProperty since there might be an unfinished search. + delete node[searchResultsProperty]; + + var treeElement = this.treeOutline.findTreeElement(node); + if (treeElement) + treeElement.highlighted = false; + } + } + + WebInspector.updateSearchMatchesCount(0, this); + + if (this._currentSearchChunkIntervalIdentifier) { + clearInterval(this._currentSearchChunkIntervalIdentifier); + delete this._currentSearchChunkIntervalIdentifier; + } + + this._currentSearchResultIndex = 0; + this._searchResults = []; + }, + + performSearch: function(query) + { + // Call searchCanceled since it will reset everything we need before doing a new search. + this.searchCanceled(); + + const whitespaceTrimmedQuery = query.trimWhitespace(); + if (!whitespaceTrimmedQuery.length) + return; + + var tagNameQuery = whitespaceTrimmedQuery; + var attributeNameQuery = whitespaceTrimmedQuery; + var startTagFound = (tagNameQuery.indexOf("<") === 0); + var endTagFound = (tagNameQuery.lastIndexOf(">") === (tagNameQuery.length - 1)); + + if (startTagFound || endTagFound) { + var tagNameQueryLength = tagNameQuery.length; + tagNameQuery = tagNameQuery.substring((startTagFound ? 1 : 0), (endTagFound ? (tagNameQueryLength - 1) : tagNameQueryLength)); + } + + // Check the tagNameQuery is it is a possibly valid tag name. + if (!/^[a-zA-Z0-9\-_:]+$/.test(tagNameQuery)) + tagNameQuery = null; + + // Check the attributeNameQuery is it is a possibly valid tag name. + if (!/^[a-zA-Z0-9\-_:]+$/.test(attributeNameQuery)) + attributeNameQuery = null; + + const escapedQuery = query.escapeCharacters("'"); + const escapedTagNameQuery = (tagNameQuery ? tagNameQuery.escapeCharacters("'") : null); + const escapedWhitespaceTrimmedQuery = whitespaceTrimmedQuery.escapeCharacters("'"); + const searchResultsProperty = this.includedInSearchResultsPropertyName; + + var updatedMatchCountOnce = false; + var matchesCountUpdateTimeout = null; + + function updateMatchesCount() + { + WebInspector.updateSearchMatchesCount(this._searchResults.length, this); + matchesCountUpdateTimeout = null; + updatedMatchCountOnce = true; + } + + function updateMatchesCountSoon() + { + if (!updatedMatchCountOnce) + return updateMatchesCount.call(this); + if (matchesCountUpdateTimeout) + return; + // Update the matches count every half-second so it doesn't feel twitchy. + matchesCountUpdateTimeout = setTimeout(updateMatchesCount.bind(this), 500); + } + + function addNodesToResults(nodes, length, getItem) + { + if (!length) + return; + + for (var i = 0; i < length; ++i) { + var node = getItem.call(nodes, i); + // Skip this node if it already has the property. + if (searchResultsProperty in node) + continue; + + if (!this._searchResults.length) { + this._currentSearchResultIndex = 0; + this.focusedDOMNode = node; + } + + node[searchResultsProperty] = true; + this._searchResults.push(node); + + // Highlight the tree element to show it matched the search. + // FIXME: highlight the substrings in text nodes and attributes. + var treeElement = this.treeOutline.findTreeElement(node); + if (treeElement) + treeElement.highlighted = true; + } + + updateMatchesCountSoon.call(this); + } + + function matchExactItems(doc) + { + matchExactId.call(this, doc); + matchExactClassNames.call(this, doc); + matchExactTagNames.call(this, doc); + matchExactAttributeNames.call(this, doc); + } + + function matchExactId(doc) + { + const result = doc.__proto__.getElementById.call(doc, whitespaceTrimmedQuery); + addNodesToResults.call(this, result, (result ? 1 : 0), function() { return this }); + } + + function matchExactClassNames(doc) + { + const result = doc.__proto__.getElementsByClassName.call(doc, whitespaceTrimmedQuery); + addNodesToResults.call(this, result, result.length, result.item); + } + + function matchExactTagNames(doc) + { + if (!tagNameQuery) + return; + const result = doc.__proto__.getElementsByTagName.call(doc, tagNameQuery); + addNodesToResults.call(this, result, result.length, result.item); + } + + function matchExactAttributeNames(doc) + { + if (!attributeNameQuery) + return; + const result = doc.__proto__.querySelectorAll.call(doc, "[" + attributeNameQuery + "]"); + addNodesToResults.call(this, result, result.length, result.item); + } + + function matchPartialTagNames(doc) + { + if (!tagNameQuery) + return; + const result = doc.__proto__.evaluate.call(doc, "//*[contains(name(), '" + escapedTagNameQuery + "')]", doc, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE); + addNodesToResults.call(this, result, result.snapshotLength, result.snapshotItem); + } + + function matchStartOfTagNames(doc) + { + if (!tagNameQuery) + return; + const result = doc.__proto__.evaluate.call(doc, "//*[starts-with(name(), '" + escapedTagNameQuery + "')]", doc, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE); + addNodesToResults.call(this, result, result.snapshotLength, result.snapshotItem); + } + + function matchPartialTagNamesAndAttributeValues(doc) + { + if (!tagNameQuery) { + matchPartialAttributeValues.call(this, doc); + return; + } + + const result = doc.__proto__.evaluate.call(doc, "//*[contains(name(), '" + escapedTagNameQuery + "') or contains(@*, '" + escapedQuery + "')]", doc, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE); + addNodesToResults.call(this, result, result.snapshotLength, result.snapshotItem); + } + + function matchPartialAttributeValues(doc) + { + const result = doc.__proto__.evaluate.call(doc, "//*[contains(@*, '" + escapedQuery + "')]", doc, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE); + addNodesToResults.call(this, result, result.snapshotLength, result.snapshotItem); + } + + function matchStyleSelector(doc) + { + const result = doc.__proto__.querySelectorAll.call(doc, whitespaceTrimmedQuery); + addNodesToResults.call(this, result, result.length, result.item); + } + + function matchPlainText(doc) + { + const result = doc.__proto__.evaluate.call(doc, "//text()[contains(., '" + escapedQuery + "')] | //comment()[contains(., '" + escapedQuery + "')]", doc, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE); + addNodesToResults.call(this, result, result.snapshotLength, result.snapshotItem); + } + + function matchXPathQuery(doc) + { + const result = doc.__proto__.evaluate.call(doc, whitespaceTrimmedQuery, doc, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE); + addNodesToResults.call(this, result, result.snapshotLength, result.snapshotItem); + } + + function finishedSearching() + { + // Remove the searchResultsProperty now that the search is finished. + for (var i = 0; i < this._searchResults.length; ++i) + delete this._searchResults[i][searchResultsProperty]; + } + + const mainFrameDocument = InspectorController.inspectedWindow().document; + const searchDocuments = [mainFrameDocument]; + + if (tagNameQuery && startTagFound && endTagFound) + const searchFunctions = [matchExactTagNames, matchPlainText]; + else if (tagNameQuery && startTagFound) + const searchFunctions = [matchStartOfTagNames, matchPlainText]; + else if (tagNameQuery && endTagFound) { + // FIXME: we should have a matchEndOfTagNames search function if endTagFound is true but not startTagFound. + // This requires ends-with() support in XPath, WebKit only supports starts-with() and contains(). + const searchFunctions = [matchPartialTagNames, matchPlainText]; + } else if (whitespaceTrimmedQuery === "//*" || whitespaceTrimmedQuery === "*") { + // These queries will match every node. Matching everything isn't useful and can be slow for large pages, + // so limit the search functions list to plain text and attribute matching. + const searchFunctions = [matchPartialAttributeValues, matchPlainText]; + } else + const searchFunctions = [matchExactItems, matchStyleSelector, matchPartialTagNamesAndAttributeValues, matchPlainText, matchXPathQuery]; + + // Find all frames, iframes and object elements to search their documents. + const querySelectorAllFunction = InspectorController.inspectedWindow().Document.prototype.querySelectorAll; + const subdocumentResult = querySelectorAllFunction.call(mainFrameDocument, "iframe, frame, object"); + + for (var i = 0; i < subdocumentResult.length; ++i) { + var element = subdocumentResult.item(i); + if (element.contentDocument) + searchDocuments.push(element.contentDocument); + } + + const panel = this; + var documentIndex = 0; + var searchFunctionIndex = 0; + var chunkIntervalIdentifier = null; + + // Split up the work into chunks so we don't block the UI thread while processing. + + function processChunk() + { + var searchDocument = searchDocuments[documentIndex]; + var searchFunction = searchFunctions[searchFunctionIndex]; + + if (++searchFunctionIndex > searchFunctions.length) { + searchFunction = searchFunctions[0]; + searchFunctionIndex = 0; + + if (++documentIndex > searchDocuments.length) { + if (panel._currentSearchChunkIntervalIdentifier === chunkIntervalIdentifier) + delete panel._currentSearchChunkIntervalIdentifier; + clearInterval(chunkIntervalIdentifier); + finishedSearching.call(panel); + return; + } + + searchDocument = searchDocuments[documentIndex]; + } + + if (!searchDocument || !searchFunction) + return; + + try { + searchFunction.call(panel, searchDocument); + } catch(err) { + // ignore any exceptions. the query might be malformed, but we allow that. + } + } + + processChunk(); + + chunkIntervalIdentifier = setInterval(processChunk, 25); + this._currentSearchChunkIntervalIdentifier = chunkIntervalIdentifier; + }, + + jumpToNextSearchResult: function() + { + if (!this._searchResults || !this._searchResults.length) + return; + if (++this._currentSearchResultIndex >= this._searchResults.length) + this._currentSearchResultIndex = 0; + this.focusedDOMNode = this._searchResults[this._currentSearchResultIndex]; + }, + + jumpToPreviousSearchResult: function() + { + if (!this._searchResults || !this._searchResults.length) + return; + if (--this._currentSearchResultIndex < 0) + this._currentSearchResultIndex = (this._searchResults.length - 1); + this.focusedDOMNode = this._searchResults[this._currentSearchResultIndex]; + }, + + inspectedWindowCleared: function(window) + { + if (InspectorController.isWindowVisible()) + this.updateMutationEventListeners(window); + }, + + _addMutationEventListeners: function(monitoredWindow) + { + monitoredWindow.document.addEventListener("DOMNodeInserted", this._nodeInsertedEventListener, true); + monitoredWindow.document.addEventListener("DOMNodeRemoved", this._nodeRemovedEventListener, true); + if (monitoredWindow.frameElement) + monitoredWindow.addEventListener("DOMContentLoaded", this._contentLoadedEventListener, true); + }, + + _removeMutationEventListeners: function(monitoredWindow) + { + if (monitoredWindow.frameElement) + monitoredWindow.removeEventListener("DOMContentLoaded", this._contentLoadedEventListener, true); + if (!monitoredWindow.document) + return; + monitoredWindow.document.removeEventListener("DOMNodeInserted", this._nodeInsertedEventListener, true); + monitoredWindow.document.removeEventListener("DOMNodeRemoved", this._nodeRemovedEventListener, true); + }, + + updateMutationEventListeners: function(monitoredWindow) + { + this._addMutationEventListeners(monitoredWindow); + }, + + registerMutationEventListeners: function(monitoredWindow) + { + if (!monitoredWindow || this._mutationMonitoredWindows.indexOf(monitoredWindow) !== -1) + return; + this._mutationMonitoredWindows.push(monitoredWindow); + if (InspectorController.isWindowVisible()) + this._addMutationEventListeners(monitoredWindow); + }, + + unregisterMutationEventListeners: function(monitoredWindow) + { + if (!monitoredWindow || this._mutationMonitoredWindows.indexOf(monitoredWindow) === -1) + return; + this._mutationMonitoredWindows.remove(monitoredWindow); + this._removeMutationEventListeners(monitoredWindow); + }, + + unregisterAllMutationEventListeners: function() + { + for (var i = 0; i < this._mutationMonitoredWindows.length; ++i) + this._removeMutationEventListeners(this._mutationMonitoredWindows[i]); + this._mutationMonitoredWindows = []; + }, + + get rootDOMNode() + { + return this.treeOutline.rootDOMNode; + }, + + set rootDOMNode(x) + { + this.treeOutline.rootDOMNode = x; + }, + + get focusedDOMNode() + { + return this.treeOutline.focusedDOMNode; + }, + + set focusedDOMNode(x) + { + this.treeOutline.focusedDOMNode = x; + }, + + _contentLoaded: function(event) + { + this.recentlyModifiedNodes.push({node: event.target, parent: event.target.defaultView.frameElement, replaced: true}); + if (this.visible) + this._updateModifiedNodesSoon(); + }, + + _nodeInserted: function(event) + { + this.recentlyModifiedNodes.push({node: event.target, parent: event.relatedNode, inserted: true}); + if (this.visible) + this._updateModifiedNodesSoon(); + }, + + _nodeRemoved: function(event) + { + this.recentlyModifiedNodes.push({node: event.target, parent: event.relatedNode, removed: true}); + if (this.visible) + this._updateModifiedNodesSoon(); + }, + + _updateModifiedNodesSoon: function() + { + if ("_updateModifiedNodesTimeout" in this) + return; + this._updateModifiedNodesTimeout = setTimeout(this._updateModifiedNodes.bind(this), 0); + }, + + _updateModifiedNodes: function() + { + if ("_updateModifiedNodesTimeout" in this) { + clearTimeout(this._updateModifiedNodesTimeout); + delete this._updateModifiedNodesTimeout; + } + + var updatedParentTreeElements = []; + var updateBreadcrumbs = false; + + for (var i = 0; i < this.recentlyModifiedNodes.length; ++i) { + var replaced = this.recentlyModifiedNodes[i].replaced; + var parent = this.recentlyModifiedNodes[i].parent; + if (!parent) + continue; + + var parentNodeItem = this.treeOutline.findTreeElement(parent, null, null, objectsAreSame); + if (parentNodeItem && !parentNodeItem.alreadyUpdatedChildren) { + parentNodeItem.updateChildren(replaced); + parentNodeItem.alreadyUpdatedChildren = true; + updatedParentTreeElements.push(parentNodeItem); + } + + if (!updateBreadcrumbs && (objectsAreSame(this.focusedDOMNode, parent) || isAncestorIncludingParentFrames(this.focusedDOMNode, parent))) + updateBreadcrumbs = true; + } + + for (var i = 0; i < updatedParentTreeElements.length; ++i) + delete updatedParentTreeElements[i].alreadyUpdatedChildren; + + this.recentlyModifiedNodes = []; + + if (updateBreadcrumbs) + this.updateBreadcrumb(true); + }, + + _stylesPaneEdited: function() + { + this.sidebarPanes.metrics.needsUpdate = true; + this.updateMetrics(); + }, + + _metricsPaneEdited: function() + { + this.sidebarPanes.styles.needsUpdate = true; + this.updateStyles(true); + }, + + _mouseMovedInCrumbs: function(event) + { + var nodeUnderMouse = document.elementFromPoint(event.pageX, event.pageY); + var crumbElement = nodeUnderMouse.enclosingNodeOrSelfWithClass("crumb"); + + WebInspector.hoveredDOMNode = (crumbElement ? crumbElement.representedObject : null); + + if ("_mouseOutOfCrumbsTimeout" in this) { + clearTimeout(this._mouseOutOfCrumbsTimeout); + delete this._mouseOutOfCrumbsTimeout; + } + }, + + _mouseMovedOutOfCrumbs: function(event) + { + var nodeUnderMouse = document.elementFromPoint(event.pageX, event.pageY); + if (nodeUnderMouse.isDescendant(this.crumbsElement)) + return; + + WebInspector.hoveredDOMNode = null; + + this._mouseOutOfCrumbsTimeout = setTimeout(this.updateBreadcrumbSizes.bind(this), 1000); + }, + + updateBreadcrumb: function(forceUpdate) + { + if (!this.visible) + return; + + var crumbs = this.crumbsElement; + + var handled = false; + var foundRoot = false; + var crumb = crumbs.firstChild; + while (crumb) { + if (objectsAreSame(crumb.representedObject, this.rootDOMNode)) + foundRoot = true; + + if (foundRoot) + crumb.addStyleClass("dimmed"); + else + crumb.removeStyleClass("dimmed"); + + if (objectsAreSame(crumb.representedObject, this.focusedDOMNode)) { + crumb.addStyleClass("selected"); + handled = true; + } else { + crumb.removeStyleClass("selected"); + } + + crumb = crumb.nextSibling; + } + + if (handled && !forceUpdate) { + // We don't need to rebuild the crumbs, but we need to adjust sizes + // to reflect the new focused or root node. + this.updateBreadcrumbSizes(); + return; + } + + crumbs.removeChildren(); + + var panel = this; + + function selectCrumbFunction(event) + { + var crumb = event.currentTarget; + if (crumb.hasStyleClass("collapsed")) { + // Clicking a collapsed crumb will expose the hidden crumbs. + if (crumb === panel.crumbsElement.firstChild) { + // If the focused crumb is the first child, pick the farthest crumb + // that is still hidden. This allows the user to expose every crumb. + var currentCrumb = crumb; + while (currentCrumb) { + var hidden = currentCrumb.hasStyleClass("hidden"); + var collapsed = currentCrumb.hasStyleClass("collapsed"); + if (!hidden && !collapsed) + break; + crumb = currentCrumb; + currentCrumb = currentCrumb.nextSibling; + } + } + + panel.updateBreadcrumbSizes(crumb); + } else { + // Clicking a dimmed crumb or double clicking (event.detail >= 2) + // will change the root node in addition to the focused node. + if (event.detail >= 2 || crumb.hasStyleClass("dimmed")) + panel.rootDOMNode = crumb.representedObject.parentNode; + panel.focusedDOMNode = crumb.representedObject; + } + + event.preventDefault(); + } + + foundRoot = false; + for (var current = this.focusedDOMNode; current; current = parentNodeOrFrameElement(current)) { + if (current.nodeType === Node.DOCUMENT_NODE) + continue; + + if (objectsAreSame(current, this.rootDOMNode)) + foundRoot = true; + + var crumb = document.createElement("span"); + crumb.className = "crumb"; + crumb.representedObject = current; + crumb.addEventListener("mousedown", selectCrumbFunction, false); + + var crumbTitle; + switch (current.nodeType) { + case Node.ELEMENT_NODE: + crumbTitle = current.nodeName.toLowerCase(); + + var nameElement = document.createElement("span"); + nameElement.textContent = crumbTitle; + crumb.appendChild(nameElement); + + var idAttribute = current.getAttribute("id"); + if (idAttribute) { + var idElement = document.createElement("span"); + crumb.appendChild(idElement); + + var part = "#" + idAttribute; + crumbTitle += part; + idElement.appendChild(document.createTextNode(part)); + + // Mark the name as extra, since the ID is more important. + nameElement.className = "extra"; + } + + var classAttribute = current.getAttribute("class"); + if (classAttribute) { + var classes = classAttribute.split(/\s+/); + var foundClasses = {}; + + if (classes.length) { + var classesElement = document.createElement("span"); + classesElement.className = "extra"; + crumb.appendChild(classesElement); + + for (var i = 0; i < classes.length; ++i) { + var className = classes[i]; + if (className && !(className in foundClasses)) { + var part = "." + className; + crumbTitle += part; + classesElement.appendChild(document.createTextNode(part)); + foundClasses[className] = true; + } + } + } + } + + break; + + case Node.TEXT_NODE: + if (isNodeWhitespace.call(current)) + crumbTitle = WebInspector.UIString("(whitespace)"); + else + crumbTitle = WebInspector.UIString("(text)"); + break + + case Node.COMMENT_NODE: + crumbTitle = "<!-->"; + break; + + case Node.DOCUMENT_TYPE_NODE: + crumbTitle = "<!DOCTYPE>"; + break; + + default: + crumbTitle = current.nodeName.toLowerCase(); + } + + if (!crumb.childNodes.length) { + var nameElement = document.createElement("span"); + nameElement.textContent = crumbTitle; + crumb.appendChild(nameElement); + } + + crumb.title = crumbTitle; + + if (foundRoot) + crumb.addStyleClass("dimmed"); + if (objectsAreSame(current, this.focusedDOMNode)) + crumb.addStyleClass("selected"); + if (!crumbs.childNodes.length) + crumb.addStyleClass("end"); + + crumbs.appendChild(crumb); + } + + if (crumbs.hasChildNodes()) + crumbs.lastChild.addStyleClass("start"); + + this.updateBreadcrumbSizes(); + }, + + updateBreadcrumbSizes: function(focusedCrumb) + { + if (!this.visible) + return; + + if (document.body.offsetWidth <= 0) { + // The stylesheet hasn't loaded yet or the window is closed, + // so we can't calculate what is need. Return early. + return; + } + + var crumbs = this.crumbsElement; + if (!crumbs.childNodes.length || crumbs.offsetWidth <= 0) + return; // No crumbs, do nothing. + + // A Zero index is the right most child crumb in the breadcrumb. + var selectedIndex = 0; + var focusedIndex = 0; + var selectedCrumb; + + var i = 0; + var crumb = crumbs.firstChild; + while (crumb) { + // Find the selected crumb and index. + if (!selectedCrumb && crumb.hasStyleClass("selected")) { + selectedCrumb = crumb; + selectedIndex = i; + } + + // Find the focused crumb index. + if (crumb === focusedCrumb) + focusedIndex = i; + + // Remove any styles that affect size before + // deciding to shorten any crumbs. + if (crumb !== crumbs.lastChild) + crumb.removeStyleClass("start"); + if (crumb !== crumbs.firstChild) + crumb.removeStyleClass("end"); + + crumb.removeStyleClass("compact"); + crumb.removeStyleClass("collapsed"); + crumb.removeStyleClass("hidden"); + + crumb = crumb.nextSibling; + ++i; + } + + // Restore the start and end crumb classes in case they got removed in coalesceCollapsedCrumbs(). + // The order of the crumbs in the document is opposite of the visual order. + crumbs.firstChild.addStyleClass("end"); + crumbs.lastChild.addStyleClass("start"); + + function crumbsAreSmallerThanContainer() + { + var rightPadding = 20; + var errorWarningElement = document.getElementById("error-warning-count"); + if (!WebInspector.console.visible && errorWarningElement) + rightPadding += errorWarningElement.offsetWidth; + return ((crumbs.totalOffsetLeft + crumbs.offsetWidth + rightPadding) < window.innerWidth); + } + + if (crumbsAreSmallerThanContainer()) + return; // No need to compact the crumbs, they all fit at full size. + + var BothSides = 0; + var AncestorSide = -1; + var ChildSide = 1; + + function makeCrumbsSmaller(shrinkingFunction, direction, significantCrumb) + { + if (!significantCrumb) + significantCrumb = (focusedCrumb || selectedCrumb); + + if (significantCrumb === selectedCrumb) + var significantIndex = selectedIndex; + else if (significantCrumb === focusedCrumb) + var significantIndex = focusedIndex; + else { + var significantIndex = 0; + for (var i = 0; i < crumbs.childNodes.length; ++i) { + if (crumbs.childNodes[i] === significantCrumb) { + significantIndex = i; + break; + } + } + } + + function shrinkCrumbAtIndex(index) + { + var shrinkCrumb = crumbs.childNodes[index]; + if (shrinkCrumb && shrinkCrumb !== significantCrumb) + shrinkingFunction(shrinkCrumb); + if (crumbsAreSmallerThanContainer()) + return true; // No need to compact the crumbs more. + return false; + } + + // Shrink crumbs one at a time by applying the shrinkingFunction until the crumbs + // fit in the container or we run out of crumbs to shrink. + if (direction) { + // Crumbs are shrunk on only one side (based on direction) of the signifcant crumb. + var index = (direction > 0 ? 0 : crumbs.childNodes.length - 1); + while (index !== significantIndex) { + if (shrinkCrumbAtIndex(index)) + return true; + index += (direction > 0 ? 1 : -1); + } + } else { + // Crumbs are shrunk in order of descending distance from the signifcant crumb, + // with a tie going to child crumbs. + var startIndex = 0; + var endIndex = crumbs.childNodes.length - 1; + while (startIndex != significantIndex || endIndex != significantIndex) { + var startDistance = significantIndex - startIndex; + var endDistance = endIndex - significantIndex; + if (startDistance >= endDistance) + var index = startIndex++; + else + var index = endIndex--; + if (shrinkCrumbAtIndex(index)) + return true; + } + } + + // We are not small enough yet, return false so the caller knows. + return false; + } + + function coalesceCollapsedCrumbs() + { + var crumb = crumbs.firstChild; + var collapsedRun = false; + var newStartNeeded = false; + var newEndNeeded = false; + while (crumb) { + var hidden = crumb.hasStyleClass("hidden"); + if (!hidden) { + var collapsed = crumb.hasStyleClass("collapsed"); + if (collapsedRun && collapsed) { + crumb.addStyleClass("hidden"); + crumb.removeStyleClass("compact"); + crumb.removeStyleClass("collapsed"); + + if (crumb.hasStyleClass("start")) { + crumb.removeStyleClass("start"); + newStartNeeded = true; + } + + if (crumb.hasStyleClass("end")) { + crumb.removeStyleClass("end"); + newEndNeeded = true; + } + + continue; + } + + collapsedRun = collapsed; + + if (newEndNeeded) { + newEndNeeded = false; + crumb.addStyleClass("end"); + } + } else + collapsedRun = true; + crumb = crumb.nextSibling; + } + + if (newStartNeeded) { + crumb = crumbs.lastChild; + while (crumb) { + if (!crumb.hasStyleClass("hidden")) { + crumb.addStyleClass("start"); + break; + } + crumb = crumb.previousSibling; + } + } + } + + function compact(crumb) + { + if (crumb.hasStyleClass("hidden")) + return; + crumb.addStyleClass("compact"); + } + + function collapse(crumb, dontCoalesce) + { + if (crumb.hasStyleClass("hidden")) + return; + crumb.addStyleClass("collapsed"); + crumb.removeStyleClass("compact"); + if (!dontCoalesce) + coalesceCollapsedCrumbs(); + } + + function compactDimmed(crumb) + { + if (crumb.hasStyleClass("dimmed")) + compact(crumb); + } + + function collapseDimmed(crumb) + { + if (crumb.hasStyleClass("dimmed")) + collapse(crumb); + } + + if (!focusedCrumb) { + // When not focused on a crumb we can be biased and collapse less important + // crumbs that the user might not care much about. + + // Compact child crumbs. + if (makeCrumbsSmaller(compact, ChildSide)) + return; + + // Collapse child crumbs. + if (makeCrumbsSmaller(collapse, ChildSide)) + return; + + // Compact dimmed ancestor crumbs. + if (makeCrumbsSmaller(compactDimmed, AncestorSide)) + return; + + // Collapse dimmed ancestor crumbs. + if (makeCrumbsSmaller(collapseDimmed, AncestorSide)) + return; + } + + // Compact ancestor crumbs, or from both sides if focused. + if (makeCrumbsSmaller(compact, (focusedCrumb ? BothSides : AncestorSide))) + return; + + // Collapse ancestor crumbs, or from both sides if focused. + if (makeCrumbsSmaller(collapse, (focusedCrumb ? BothSides : AncestorSide))) + return; + + if (!selectedCrumb) + return; + + // Compact the selected crumb. + compact(selectedCrumb); + if (crumbsAreSmallerThanContainer()) + return; + + // Collapse the selected crumb as a last resort. Pass true to prevent coalescing. + collapse(selectedCrumb, true); + }, + + updateStyles: function(forceUpdate) + { + var stylesSidebarPane = this.sidebarPanes.styles; + if (!stylesSidebarPane.expanded || !stylesSidebarPane.needsUpdate) + return; + + stylesSidebarPane.update(this.focusedDOMNode, null, forceUpdate); + stylesSidebarPane.needsUpdate = false; + }, + + updateMetrics: function() + { + var metricsSidebarPane = this.sidebarPanes.metrics; + if (!metricsSidebarPane.expanded || !metricsSidebarPane.needsUpdate) + return; + + metricsSidebarPane.update(this.focusedDOMNode); + metricsSidebarPane.needsUpdate = false; + }, + + updateProperties: function() + { + var propertiesSidebarPane = this.sidebarPanes.properties; + if (!propertiesSidebarPane.expanded || !propertiesSidebarPane.needsUpdate) + return; + + propertiesSidebarPane.update(this.focusedDOMNode); + propertiesSidebarPane.needsUpdate = false; + }, + + handleKeyEvent: function(event) + { + this.treeOutline.handleKeyEvent(event); + }, + + handleCopyEvent: function(event) + { + // Don't prevent the normal copy if the user has a selection. + if (!window.getSelection().isCollapsed) + return; + + switch (this.focusedDOMNode.nodeType) { + case Node.ELEMENT_NODE: + var data = this.focusedDOMNode.outerHTML; + break; + + case Node.COMMENT_NODE: + var data = "<!--" + this.focusedDOMNode.nodeValue + "-->"; + break; + + default: + case Node.TEXT_NODE: + var data = this.focusedDOMNode.nodeValue; + } + + event.clipboardData.clearData(); + event.preventDefault(); + + if (data) + event.clipboardData.setData("text/plain", data); + }, + + rightSidebarResizerDragStart: function(event) + { + WebInspector.elementDragStart(this.sidebarElement, this.rightSidebarResizerDrag.bind(this), this.rightSidebarResizerDragEnd.bind(this), event, "col-resize"); + }, + + rightSidebarResizerDragEnd: function(event) + { + WebInspector.elementDragEnd(event); + }, + + rightSidebarResizerDrag: function(event) + { + var x = event.pageX; + var newWidth = Number.constrain(window.innerWidth - x, Preferences.minElementsSidebarWidth, window.innerWidth * 0.66); + + this.sidebarElement.style.width = newWidth + "px"; + this.contentElement.style.right = newWidth + "px"; + this.sidebarResizeElement.style.right = (newWidth - 3) + "px"; + + this.treeOutline.updateSelection(); + + event.preventDefault(); + }, + + _nodeSearchButtonClicked: function(event) + { + InspectorController.toggleNodeSearch(); + + if (InspectorController.searchingForNode()) + this.nodeSearchButton.addStyleClass("toggled-on"); + else + this.nodeSearchButton.removeStyleClass("toggled-on"); + } +} + +WebInspector.ElementsPanel.prototype.__proto__ = WebInspector.Panel.prototype; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ElementsTreeOutline.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ElementsTreeOutline.js new file mode 100644 index 0000000..16e31b8 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ElementsTreeOutline.js @@ -0,0 +1,626 @@ +/* + * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008 Matt Lilek <webkit@mattlilek.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. + */ + +WebInspector.ElementsTreeOutline = function() { + this.element = document.createElement("ol"); + this.element.addEventListener("mousedown", this._onmousedown.bind(this), false); + this.element.addEventListener("dblclick", this._ondblclick.bind(this), false); + this.element.addEventListener("mousemove", this._onmousemove.bind(this), false); + this.element.addEventListener("mouseout", this._onmouseout.bind(this), false); + + TreeOutline.call(this, this.element); + + this.includeRootDOMNode = true; + this.selectEnabled = false; + this.rootDOMNode = null; + this.focusedDOMNode = null; +} + +WebInspector.ElementsTreeOutline.prototype = { + get rootDOMNode() + { + return this._rootDOMNode; + }, + + set rootDOMNode(x) + { + if (objectsAreSame(this._rootDOMNode, x)) + return; + + this._rootDOMNode = x; + + this.update(); + }, + + get focusedDOMNode() + { + return this._focusedDOMNode; + }, + + set focusedDOMNode(x) + { + if (objectsAreSame(this._focusedDOMNode, x)) { + this.revealAndSelectNode(x); + return; + } + + this._focusedDOMNode = x; + + this.revealAndSelectNode(x); + + // The revealAndSelectNode() method might find a different element if there is inlined text, + // and the select() call would change the focusedDOMNode and reenter this setter. So to + // avoid calling focusedNodeChanged() twice, first check if _focusedDOMNode is the same + // node as the one passed in. + if (objectsAreSame(this._focusedDOMNode, x)) { + this.focusedNodeChanged(); + + if (x && !this.suppressSelectHighlight) { + InspectorController.highlightDOMNode(x); + + if ("_restorePreviousHighlightNodeTimeout" in this) + clearTimeout(this._restorePreviousHighlightNodeTimeout); + + function restoreHighlightToHoveredNode() + { + var hoveredNode = WebInspector.hoveredDOMNode; + if (hoveredNode) + InspectorController.highlightDOMNode(hoveredNode); + else + InspectorController.hideDOMNodeHighlight(); + } + + this._restorePreviousHighlightNodeTimeout = setTimeout(restoreHighlightToHoveredNode, 2000); + } + } + }, + + update: function() + { + this.removeChildren(); + + if (!this.rootDOMNode) + return; + + var treeElement; + if (this.includeRootDOMNode) { + treeElement = new WebInspector.ElementsTreeElement(this.rootDOMNode); + treeElement.selectable = this.selectEnabled; + this.appendChild(treeElement); + } else { + // FIXME: this could use findTreeElement to reuse a tree element if it already exists + var node = (Preferences.ignoreWhitespace ? firstChildSkippingWhitespace.call(this.rootDOMNode) : this.rootDOMNode.firstChild); + while (node) { + treeElement = new WebInspector.ElementsTreeElement(node); + treeElement.selectable = this.selectEnabled; + this.appendChild(treeElement); + node = Preferences.ignoreWhitespace ? nextSiblingSkippingWhitespace.call(node) : node.nextSibling; + } + } + + this.updateSelection(); + }, + + updateSelection: function() + { + if (!this.selectedTreeElement) + return; + var element = this.treeOutline.selectedTreeElement; + element.updateSelection(); + }, + + focusedNodeChanged: function(forceUpdate) {}, + + findTreeElement: function(node, isAncestor, getParent, equal) + { + if (typeof isAncestor === "undefined") + isAncestor = isAncestorIncludingParentFrames; + if (typeof getParent === "undefined") + getParent = parentNodeOrFrameElement; + if (typeof equal === "undefined") + equal = objectsAreSame; + + var treeElement = TreeOutline.prototype.findTreeElement.call(this, node, isAncestor, getParent, equal); + if (!treeElement && node.nodeType === Node.TEXT_NODE) { + // The text node might have been inlined if it was short, so try to find the parent element. + treeElement = TreeOutline.prototype.findTreeElement.call(this, node.parentNode, isAncestor, getParent, equal); + } + + return treeElement; + }, + + revealAndSelectNode: function(node) + { + if (!node) + return; + + var treeElement = this.findTreeElement(node); + if (!treeElement) + return; + + treeElement.reveal(); + treeElement.select(); + }, + + _treeElementFromEvent: function(event) + { + var root = this.element; + + // We choose this X coordinate based on the knowledge that our list + // items extend nearly to the right edge of the outer <ol>. + var x = root.totalOffsetLeft + root.offsetWidth - 20; + + var y = event.pageY; + + // Our list items have 1-pixel cracks between them vertically. We avoid + // the cracks by checking slightly above and slightly below the mouse + // and seeing if we hit the same element each time. + var elementUnderMouse = this.treeElementFromPoint(x, y); + var elementAboveMouse = this.treeElementFromPoint(x, y - 2); + var element; + if (elementUnderMouse === elementAboveMouse) + element = elementUnderMouse; + else + element = this.treeElementFromPoint(x, y + 2); + + return element; + }, + + _ondblclick: function(event) + { + var element = this._treeElementFromEvent(event); + + if (!element || !element.ondblclick) + return; + + element.ondblclick(element, event); + }, + + _onmousedown: function(event) + { + var element = this._treeElementFromEvent(event); + + if (!element || element.isEventWithinDisclosureTriangle(event)) + return; + + element.select(); + }, + + _onmousemove: function(event) + { + if (this._previousHoveredElement) { + this._previousHoveredElement.hovered = false; + delete this._previousHoveredElement; + } + + var element = this._treeElementFromEvent(event); + if (element && !element.elementCloseTag) { + element.hovered = true; + this._previousHoveredElement = element; + } + + WebInspector.hoveredDOMNode = (element && !element.elementCloseTag ? element.representedObject : null); + }, + + _onmouseout: function(event) + { + var nodeUnderMouse = document.elementFromPoint(event.pageX, event.pageY); + if (nodeUnderMouse.isDescendant(this.element)) + return; + + if (this._previousHoveredElement) { + this._previousHoveredElement.hovered = false; + delete this._previousHoveredElement; + } + + WebInspector.hoveredDOMNode = null; + } +} + +WebInspector.ElementsTreeOutline.prototype.__proto__ = TreeOutline.prototype; + +WebInspector.ElementsTreeElement = function(node) +{ + var hasChildren = node.contentDocument || (Preferences.ignoreWhitespace ? (firstChildSkippingWhitespace.call(node) ? true : false) : node.hasChildNodes()); + var titleInfo = nodeTitleInfo.call(node, hasChildren, WebInspector.linkifyURL); + + if (titleInfo.hasChildren) + this.whitespaceIgnored = Preferences.ignoreWhitespace; + + // The title will be updated in onattach. + TreeElement.call(this, "", node, titleInfo.hasChildren); +} + +WebInspector.ElementsTreeElement.prototype = { + get highlighted() + { + return this._highlighted; + }, + + set highlighted(x) + { + if (this._highlighted === x) + return; + + this._highlighted = x; + + if (this.listItemElement) { + if (x) + this.listItemElement.addStyleClass("highlighted"); + else + this.listItemElement.removeStyleClass("highlighted"); + } + }, + + get hovered() + { + return this._hovered; + }, + + set hovered(x) + { + if (this._hovered === x) + return; + + this._hovered = x; + + if (this.listItemElement) { + if (x) { + this.updateSelection(); + this.listItemElement.addStyleClass("hovered"); + } else + this.listItemElement.removeStyleClass("hovered"); + } + }, + + updateSelection: function() + { + var listItemElement = this.listItemElement; + if (!listItemElement) + return; + + if (document.body.offsetWidth <= 0) { + // The stylesheet hasn't loaded yet or the window is closed, + // so we can't calculate what is need. Return early. + return; + } + + if (!this.selectionElement) { + this.selectionElement = document.createElement("div"); + this.selectionElement.className = "selection selected"; + listItemElement.insertBefore(this.selectionElement, listItemElement.firstChild); + } + + this.selectionElement.style.height = listItemElement.offsetHeight + "px"; + }, + + onattach: function() + { + this.listItemElement.addEventListener("mousedown", this.onmousedown.bind(this), false); + + if (this._highlighted) + this.listItemElement.addStyleClass("highlighted"); + + if (this._hovered) { + this.updateSelection(); + this.listItemElement.addStyleClass("hovered"); + } + + this._updateTitle(); + + this._preventFollowingLinksOnDoubleClick(); + }, + + _preventFollowingLinksOnDoubleClick: function() + { + var links = this.listItemElement.querySelectorAll("li > .webkit-html-tag > .webkit-html-attribute > .webkit-html-external-link, li > .webkit-html-tag > .webkit-html-attribute > .webkit-html-resource-link"); + if (!links) + return; + + for (var i = 0; i < links.length; ++i) + links[i].preventFollowOnDoubleClick = true; + }, + + onpopulate: function() + { + if (this.children.length || this.whitespaceIgnored !== Preferences.ignoreWhitespace) + return; + + this.whitespaceIgnored = Preferences.ignoreWhitespace; + + this.updateChildren(); + }, + + updateChildren: function(fullRefresh) + { + if (fullRefresh) { + var selectedTreeElement = this.treeOutline.selectedTreeElement; + if (selectedTreeElement && selectedTreeElement.hasAncestor(this)) + this.select(); + this.removeChildren(); + } + + var treeElement = this; + var treeChildIndex = 0; + + function updateChildrenOfNode(node) + { + var treeOutline = treeElement.treeOutline; + var child = (Preferences.ignoreWhitespace ? firstChildSkippingWhitespace.call(node) : node.firstChild); + while (child) { + var currentTreeElement = treeElement.children[treeChildIndex]; + if (!currentTreeElement || !objectsAreSame(currentTreeElement.representedObject, child)) { + // Find any existing element that is later in the children list. + var existingTreeElement = null; + for (var i = (treeChildIndex + 1); i < treeElement.children.length; ++i) { + if (objectsAreSame(treeElement.children[i].representedObject, child)) { + existingTreeElement = treeElement.children[i]; + break; + } + } + + if (existingTreeElement && existingTreeElement.parent === treeElement) { + // If an existing element was found and it has the same parent, just move it. + var wasSelected = existingTreeElement.selected; + treeElement.removeChild(existingTreeElement); + treeElement.insertChild(existingTreeElement, treeChildIndex); + if (wasSelected) + existingTreeElement.select(); + } else { + // No existing element found, insert a new element. + var newElement = new WebInspector.ElementsTreeElement(child); + newElement.selectable = treeOutline.selectEnabled; + treeElement.insertChild(newElement, treeChildIndex); + } + } + + child = Preferences.ignoreWhitespace ? nextSiblingSkippingWhitespace.call(child) : child.nextSibling; + ++treeChildIndex; + } + } + + // Remove any tree elements that no longer have this node (or this node's contentDocument) as their parent. + for (var i = (this.children.length - 1); i >= 0; --i) { + if ("elementCloseTag" in this.children[i]) + continue; + + var currentChild = this.children[i]; + var currentNode = currentChild.representedObject; + var currentParentNode = currentNode.parentNode; + + if (objectsAreSame(currentParentNode, this.representedObject)) + continue; + if (this.representedObject.contentDocument && objectsAreSame(currentParentNode, this.representedObject.contentDocument)) + continue; + + var selectedTreeElement = this.treeOutline.selectedTreeElement; + if (selectedTreeElement && (selectedTreeElement === currentChild || selectedTreeElement.hasAncestor(currentChild))) + this.select(); + + this.removeChildAtIndex(i); + + if (this.treeOutline.panel && currentNode.contentDocument) + this.treeOutline.panel.unregisterMutationEventListeners(currentNode.contentDocument.defaultView); + } + + if (this.representedObject.contentDocument) + updateChildrenOfNode(this.representedObject.contentDocument); + updateChildrenOfNode(this.representedObject); + + var lastChild = this.children[this.children.length - 1]; + if (this.representedObject.nodeType == Node.ELEMENT_NODE && (!lastChild || !lastChild.elementCloseTag)) { + var title = "<span class=\"webkit-html-tag close\"></" + this.representedObject.nodeName.toLowerCase().escapeHTML() + "></span>"; + var item = new TreeElement(title, null, false); + item.selectable = false; + item.elementCloseTag = true; + this.appendChild(item); + } + }, + + onexpand: function() + { + this.treeOutline.updateSelection(); + + if (this.treeOutline.panel && this.representedObject.contentDocument) + this.treeOutline.panel.registerMutationEventListeners(this.representedObject.contentDocument.defaultView); + }, + + oncollapse: function() + { + this.treeOutline.updateSelection(); + }, + + onreveal: function() + { + if (this.listItemElement) + this.listItemElement.scrollIntoViewIfNeeded(false); + }, + + onselect: function() + { + this.treeOutline.focusedDOMNode = this.representedObject; + this.updateSelection(); + }, + + onmousedown: function(event) + { + if (this._editing) + return; + + // Prevent selecting the nearest word on double click. + if (event.detail >= 2) + event.preventDefault(); + }, + + ondblclick: function(treeElement, event) + { + if (this._editing) + return; + + if (this._startEditing(event)) + return; + + if (this.treeOutline.panel) { + this.treeOutline.rootDOMNode = this.parent.representedObject; + this.treeOutline.focusedDOMNode = this.representedObject; + } + + if (this.hasChildren && !this.expanded) + this.expand(); + }, + + _startEditing: function(event) + { + if (this.treeOutline.focusedDOMNode != this.representedObject) + return; + + if (this.representedObject.nodeType != Node.ELEMENT_NODE && this.representedObject.nodeType != Node.TEXT_NODE) + return false; + + var textNode = event.target.enclosingNodeOrSelfWithClass("webkit-html-text-node"); + if (textNode) + return this._startEditingTextNode(textNode); + + var attribute = event.target.enclosingNodeOrSelfWithClass("webkit-html-attribute"); + if (attribute) + return this._startEditingAttribute(attribute, event); + + return false; + }, + + _startEditingAttribute: function(attribute, event) + { + if (WebInspector.isBeingEdited(attribute)) + return true; + + var attributeNameElement = attribute.getElementsByClassName("webkit-html-attribute-name")[0]; + if (!attributeNameElement) + return false; + + var attributeName = attributeNameElement.innerText; + + function removeZeroWidthSpaceRecursive(node) + { + if (node.nodeType === Node.TEXT_NODE) { + node.nodeValue = node.nodeValue.replace(/\u200B/g, ""); + return; + } + + if (node.nodeType !== Node.ELEMENT_NODE) + return; + + for (var child = node.firstChild; child; child = child.nextSibling) + removeZeroWidthSpaceRecursive(child); + } + + // Remove zero-width spaces that were added by nodeTitleInfo. + removeZeroWidthSpaceRecursive(attribute); + + this._editing = true; + + WebInspector.startEditing(attribute, this._attributeEditingCommitted.bind(this), this._editingCancelled.bind(this), attributeName); + window.getSelection().setBaseAndExtent(event.target, 0, event.target, 1); + + return true; + }, + + _startEditingTextNode: function(textNode) + { + if (WebInspector.isBeingEdited(textNode)) + return true; + + this._editing = true; + + WebInspector.startEditing(textNode, this._textNodeEditingCommitted.bind(this), this._editingCancelled.bind(this)); + window.getSelection().setBaseAndExtent(textNode, 0, textNode, 1); + + return true; + }, + + _attributeEditingCommitted: function(element, newText, oldText, attributeName) + { + delete this._editing; + + var parseContainerElement = document.createElement("span"); + parseContainerElement.innerHTML = "<span " + newText + "></span>"; + var parseElement = parseContainerElement.firstChild; + if (!parseElement || !parseElement.hasAttributes()) { + editingCancelled(element, context); + return; + } + + var foundOriginalAttribute = false; + for (var i = 0; i < parseElement.attributes.length; ++i) { + var attr = parseElement.attributes[i]; + foundOriginalAttribute = foundOriginalAttribute || attr.name === attributeName; + InspectorController.inspectedWindow().Element.prototype.setAttribute.call(this.representedObject, attr.name, attr.value); + } + + if (!foundOriginalAttribute) + InspectorController.inspectedWindow().Element.prototype.removeAttribute.call(this.representedObject, attributeName); + + this._updateTitle(); + + this.treeOutline.focusedNodeChanged(true); + }, + + _textNodeEditingCommitted: function(element, newText) + { + delete this._editing; + + var textNode; + if (this.representedObject.nodeType == Node.ELEMENT_NODE) { + // We only show text nodes inline in elements if the element only + // has a single child, and that child is a text node. + textNode = this.representedObject.firstChild; + } else if (this.representedObject.nodeType == Node.TEXT_NODE) + textNode = this.representedObject; + + textNode.nodeValue = newText; + this._updateTitle(); + }, + + _editingCancelled: function(element, context) + { + delete this._editing; + + this._updateTitle(); + }, + + _updateTitle: function() + { + var title = nodeTitleInfo.call(this.representedObject, this.hasChildren, WebInspector.linkifyURL).title; + this.title = "<span class=\"highlight\">" + title + "</span>"; + delete this.selectionElement; + this.updateSelection(); + this._preventFollowingLinksOnDoubleClick(); + }, +} + +WebInspector.ElementsTreeElement.prototype.__proto__ = TreeElement.prototype; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/FontView.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/FontView.js new file mode 100644 index 0000000..4e1c931 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/FontView.js @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2007, 2008 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. + * 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. + */ + +WebInspector.FontView = function(resource) +{ + WebInspector.ResourceView.call(this, resource); + + this.element.addStyleClass("font"); + + var uniqueFontName = "WebInspectorFontPreview" + this.resource.identifier; + + this.fontStyleElement = document.createElement("style"); + this.fontStyleElement.textContent = "@font-face { font-family: \"" + uniqueFontName + "\"; src: url(" + this.resource.url + "); }"; + document.getElementsByTagName("head").item(0).appendChild(this.fontStyleElement); + + this.fontPreviewElement = document.createElement("div"); + this.fontPreviewElement.className = "preview"; + this.contentElement.appendChild(this.fontPreviewElement); + + this.fontPreviewElement.style.setProperty("font-family", uniqueFontName, null); + this.fontPreviewElement.innerHTML = "ABCDEFGHIJKLM<br>NOPQRSTUVWXYZ<br>abcdefghijklm<br>nopqrstuvwxyz<br>1234567890"; + + this.updateFontPreviewSize(); +} + +WebInspector.FontView.prototype = { + show: function(parentElement) + { + WebInspector.ResourceView.prototype.show.call(this, parentElement); + this.updateFontPreviewSize(); + }, + + resize: function() + { + this.updateFontPreviewSize(); + }, + + updateFontPreviewSize: function () + { + if (!this.fontPreviewElement || !this.visible) + return; + + this.fontPreviewElement.removeStyleClass("preview"); + + var measureFontSize = 50; + this.fontPreviewElement.style.setProperty("position", "absolute", null); + this.fontPreviewElement.style.setProperty("font-size", measureFontSize + "px", null); + this.fontPreviewElement.style.removeProperty("height"); + + var height = this.fontPreviewElement.offsetHeight; + var width = this.fontPreviewElement.offsetWidth; + + var containerWidth = this.contentElement.offsetWidth; + + // Subtract some padding. This should match the padding in the CSS plus room for the scrollbar. + containerWidth -= 40; + + if (!height || !width || !containerWidth) { + this.fontPreviewElement.style.removeProperty("font-size"); + this.fontPreviewElement.style.removeProperty("position"); + this.fontPreviewElement.addStyleClass("preview"); + return; + } + + var lineCount = this.fontPreviewElement.getElementsByTagName("br").length + 1; + var realLineHeight = Math.floor(height / lineCount); + var fontSizeLineRatio = measureFontSize / realLineHeight; + var widthRatio = containerWidth / width; + var finalFontSize = Math.floor(realLineHeight * widthRatio * fontSizeLineRatio) - 1; + + this.fontPreviewElement.style.setProperty("font-size", finalFontSize + "px", null); + this.fontPreviewElement.style.setProperty("height", this.fontPreviewElement.offsetHeight + "px", null); + this.fontPreviewElement.style.removeProperty("position"); + + this.fontPreviewElement.addStyleClass("preview"); + } +} + +WebInspector.FontView.prototype.__proto__ = WebInspector.ResourceView.prototype; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ImageView.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ImageView.js new file mode 100644 index 0000000..001ffdd --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ImageView.js @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2007, 2008 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. + * 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. + */ + +WebInspector.ImageView = function(resource) +{ + WebInspector.ResourceView.call(this, resource); + + this.element.addStyleClass("image"); + + var container = document.createElement("div"); + container.className = "image"; + this.contentElement.appendChild(container); + + this.imagePreviewElement = document.createElement("img"); + this.imagePreviewElement.setAttribute("src", this.resource.url); + + container.appendChild(this.imagePreviewElement); + + container = document.createElement("div"); + container.className = "info"; + this.contentElement.appendChild(container); + + var imageNameElement = document.createElement("h1"); + imageNameElement.className = "title"; + imageNameElement.textContent = this.resource.displayName; + container.appendChild(imageNameElement); + + var infoListElement = document.createElement("dl"); + infoListElement.className = "infoList"; + + var imageProperties = [ + { name: WebInspector.UIString("Dimensions"), value: WebInspector.UIString("%d × %d", this.imagePreviewElement.naturalWidth, this.imagePreviewElement.height) }, + { name: WebInspector.UIString("File size"), value: Number.bytesToString(this.resource.contentLength, WebInspector.UIString.bind(WebInspector)) }, + { name: WebInspector.UIString("MIME type"), value: this.resource.mimeType } + ]; + + var listHTML = ''; + for (var i = 0; i < imageProperties.length; ++i) + listHTML += "<dt>" + imageProperties[i].name + "</dt><dd>" + imageProperties[i].value + "</dd>"; + + infoListElement.innerHTML = listHTML; + container.appendChild(infoListElement); +} + +WebInspector.ImageView.prototype = { + +} + +WebInspector.ImageView.prototype.__proto__ = WebInspector.ResourceView.prototype; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/back.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/back.png Binary files differnew file mode 100644 index 0000000..9363960 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/back.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/checker.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/checker.png Binary files differnew file mode 100644 index 0000000..8349908 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/checker.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/clearConsoleButtons.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/clearConsoleButtons.png Binary files differnew file mode 100644 index 0000000..140a4fb --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/clearConsoleButtons.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/closeButtons.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/closeButtons.png Binary files differnew file mode 100644 index 0000000..28158a4 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/closeButtons.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/consoleButtons.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/consoleButtons.png Binary files differnew file mode 100644 index 0000000..fb5f0897 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/consoleButtons.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/database.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/database.png Binary files differnew file mode 100644 index 0000000..339efa6 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/database.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/databaseTable.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/databaseTable.png Binary files differnew file mode 100644 index 0000000..3718708 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/databaseTable.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/databasesIcon.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/databasesIcon.png Binary files differnew file mode 100644 index 0000000..79c7bb3 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/databasesIcon.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/debuggerContinue.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/debuggerContinue.png Binary files differnew file mode 100644 index 0000000..d90a855 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/debuggerContinue.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/debuggerPause.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/debuggerPause.png Binary files differnew file mode 100644 index 0000000..97f958a --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/debuggerPause.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/debuggerStepInto.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/debuggerStepInto.png Binary files differnew file mode 100644 index 0000000..277f126 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/debuggerStepInto.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/debuggerStepOut.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/debuggerStepOut.png Binary files differnew file mode 100644 index 0000000..3032e32 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/debuggerStepOut.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/debuggerStepOver.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/debuggerStepOver.png Binary files differnew file mode 100644 index 0000000..7d47245 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/debuggerStepOver.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/disclosureTriangleSmallDown.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/disclosureTriangleSmallDown.png Binary files differnew file mode 100644 index 0000000..cffc835 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/disclosureTriangleSmallDown.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/disclosureTriangleSmallDownBlack.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/disclosureTriangleSmallDownBlack.png Binary files differnew file mode 100644 index 0000000..4b49c13 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/disclosureTriangleSmallDownBlack.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/disclosureTriangleSmallDownWhite.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/disclosureTriangleSmallDownWhite.png Binary files differnew file mode 100644 index 0000000..aebae12 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/disclosureTriangleSmallDownWhite.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/disclosureTriangleSmallRight.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/disclosureTriangleSmallRight.png Binary files differnew file mode 100644 index 0000000..a3102ea --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/disclosureTriangleSmallRight.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/disclosureTriangleSmallRightBlack.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/disclosureTriangleSmallRightBlack.png Binary files differnew file mode 100644 index 0000000..2c45859 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/disclosureTriangleSmallRightBlack.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/disclosureTriangleSmallRightDown.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/disclosureTriangleSmallRightDown.png Binary files differnew file mode 100644 index 0000000..035c069 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/disclosureTriangleSmallRightDown.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/disclosureTriangleSmallRightDownBlack.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/disclosureTriangleSmallRightDownBlack.png Binary files differnew file mode 100644 index 0000000..86f67bd --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/disclosureTriangleSmallRightDownBlack.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/disclosureTriangleSmallRightDownWhite.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/disclosureTriangleSmallRightDownWhite.png Binary files differnew file mode 100644 index 0000000..972d794 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/disclosureTriangleSmallRightDownWhite.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/disclosureTriangleSmallRightWhite.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/disclosureTriangleSmallRightWhite.png Binary files differnew file mode 100644 index 0000000..a10168f --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/disclosureTriangleSmallRightWhite.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/dockButtons.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/dockButtons.png Binary files differnew file mode 100644 index 0000000..4b01d66 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/dockButtons.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/elementsIcon.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/elementsIcon.png Binary files differnew file mode 100644 index 0000000..fde3db9 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/elementsIcon.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/enableButtons.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/enableButtons.png Binary files differnew file mode 100644 index 0000000..facee60 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/enableButtons.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/errorIcon.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/errorIcon.png Binary files differnew file mode 100644 index 0000000..c697263 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/errorIcon.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/errorMediumIcon.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/errorMediumIcon.png Binary files differnew file mode 100644 index 0000000..6ca32bb --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/errorMediumIcon.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/excludeButtons.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/excludeButtons.png Binary files differnew file mode 100644 index 0000000..f1c53a9 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/excludeButtons.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/focusButtons.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/focusButtons.png Binary files differnew file mode 100644 index 0000000..47eaa04 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/focusButtons.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/forward.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/forward.png Binary files differnew file mode 100644 index 0000000..ad70f3e --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/forward.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/glossyHeader.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/glossyHeader.png Binary files differnew file mode 100644 index 0000000..6cbefb7 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/glossyHeader.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/glossyHeaderPressed.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/glossyHeaderPressed.png Binary files differnew file mode 100644 index 0000000..1153506 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/glossyHeaderPressed.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/glossyHeaderSelected.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/glossyHeaderSelected.png Binary files differnew file mode 100644 index 0000000..71d5af6 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/glossyHeaderSelected.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/glossyHeaderSelectedPressed.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/glossyHeaderSelectedPressed.png Binary files differnew file mode 100644 index 0000000..7047dbe --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/glossyHeaderSelectedPressed.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/goArrow.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/goArrow.png Binary files differnew file mode 100644 index 0000000..f318a56 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/goArrow.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/graphLabelCalloutLeft.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/graphLabelCalloutLeft.png Binary files differnew file mode 100644 index 0000000..6426dbd --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/graphLabelCalloutLeft.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/graphLabelCalloutRight.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/graphLabelCalloutRight.png Binary files differnew file mode 100644 index 0000000..8c87eae --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/graphLabelCalloutRight.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/largerResourcesButtons.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/largerResourcesButtons.png Binary files differnew file mode 100644 index 0000000..caf3f14 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/largerResourcesButtons.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/nodeSearchButtons.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/nodeSearchButtons.png Binary files differnew file mode 100644 index 0000000..0599bd4 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/nodeSearchButtons.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/paneBottomGrow.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/paneBottomGrow.png Binary files differnew file mode 100644 index 0000000..d55b865 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/paneBottomGrow.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/paneBottomGrowActive.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/paneBottomGrowActive.png Binary files differnew file mode 100644 index 0000000..ef3f259 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/paneBottomGrowActive.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/paneGrowHandleLine.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/paneGrowHandleLine.png Binary files differnew file mode 100644 index 0000000..4eaf61b --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/paneGrowHandleLine.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/pauseOnExceptionButtons.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/pauseOnExceptionButtons.png Binary files differnew file mode 100644 index 0000000..a4dd33a --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/pauseOnExceptionButtons.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/percentButtons.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/percentButtons.png Binary files differnew file mode 100644 index 0000000..2635b24 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/percentButtons.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/profileGroupIcon.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/profileGroupIcon.png Binary files differnew file mode 100644 index 0000000..44616d4 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/profileGroupIcon.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/profileIcon.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/profileIcon.png Binary files differnew file mode 100644 index 0000000..8008f9b --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/profileIcon.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/profileSmallIcon.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/profileSmallIcon.png Binary files differnew file mode 100644 index 0000000..7935520 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/profileSmallIcon.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/profilesIcon.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/profilesIcon.png Binary files differnew file mode 100644 index 0000000..ecd5b04 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/profilesIcon.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/profilesSilhouette.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/profilesSilhouette.png Binary files differnew file mode 100644 index 0000000..42bb966 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/profilesSilhouette.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/recordButtons.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/recordButtons.png Binary files differnew file mode 100644 index 0000000..3676154 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/recordButtons.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/reloadButtons.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/reloadButtons.png Binary files differnew file mode 100644 index 0000000..1e45671 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/reloadButtons.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/resourceCSSIcon.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/resourceCSSIcon.png Binary files differnew file mode 100644 index 0000000..aead6a7 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/resourceCSSIcon.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/resourceDocumentIcon.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/resourceDocumentIcon.png Binary files differnew file mode 100644 index 0000000..1683a09 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/resourceDocumentIcon.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/resourceDocumentIconSmall.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/resourceDocumentIconSmall.png Binary files differnew file mode 100644 index 0000000..468ced9 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/resourceDocumentIconSmall.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/resourceJSIcon.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/resourceJSIcon.png Binary files differnew file mode 100644 index 0000000..9ef6ed0 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/resourceJSIcon.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/resourcePlainIcon.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/resourcePlainIcon.png Binary files differnew file mode 100644 index 0000000..0ed37b6 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/resourcePlainIcon.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/resourcePlainIconSmall.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/resourcePlainIconSmall.png Binary files differnew file mode 100644 index 0000000..0fa967d --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/resourcePlainIconSmall.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/resourcesIcon.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/resourcesIcon.png Binary files differnew file mode 100644 index 0000000..982424d --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/resourcesIcon.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/resourcesSizeGraphIcon.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/resourcesSizeGraphIcon.png Binary files differnew file mode 100644 index 0000000..e60dbe5 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/resourcesSizeGraphIcon.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/resourcesTimeGraphIcon.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/resourcesTimeGraphIcon.png Binary files differnew file mode 100644 index 0000000..c6953e9 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/resourcesTimeGraphIcon.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/scriptsIcon.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/scriptsIcon.png Binary files differnew file mode 100644 index 0000000..213b31e --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/scriptsIcon.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/scriptsSilhouette.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/scriptsSilhouette.png Binary files differnew file mode 100644 index 0000000..206396f --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/scriptsSilhouette.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/searchSmallBlue.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/searchSmallBlue.png Binary files differnew file mode 100644 index 0000000..9c990f4 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/searchSmallBlue.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/searchSmallBrightBlue.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/searchSmallBrightBlue.png Binary files differnew file mode 100644 index 0000000..b1d8055 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/searchSmallBrightBlue.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/searchSmallGray.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/searchSmallGray.png Binary files differnew file mode 100644 index 0000000..4f3c068 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/searchSmallGray.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/searchSmallWhite.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/searchSmallWhite.png Binary files differnew file mode 100644 index 0000000..85f430d --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/searchSmallWhite.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/segment.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/segment.png Binary files differnew file mode 100644 index 0000000..759266e --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/segment.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/segmentEnd.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/segmentEnd.png Binary files differnew file mode 100644 index 0000000..72672ff --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/segmentEnd.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/segmentHover.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/segmentHover.png Binary files differnew file mode 100644 index 0000000..c5017f4 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/segmentHover.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/segmentHoverEnd.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/segmentHoverEnd.png Binary files differnew file mode 100644 index 0000000..d51363d --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/segmentHoverEnd.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/segmentSelected.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/segmentSelected.png Binary files differnew file mode 100644 index 0000000..c92f584 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/segmentSelected.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/segmentSelectedEnd.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/segmentSelectedEnd.png Binary files differnew file mode 100644 index 0000000..be5e0852 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/segmentSelectedEnd.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/splitviewDimple.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/splitviewDimple.png Binary files differnew file mode 100644 index 0000000..584ffd4 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/splitviewDimple.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/splitviewDividerBackground.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/splitviewDividerBackground.png Binary files differnew file mode 100644 index 0000000..1120a7f --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/splitviewDividerBackground.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/statusbarBackground.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/statusbarBackground.png Binary files differnew file mode 100644 index 0000000..b466a49 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/statusbarBackground.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/statusbarBottomBackground.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/statusbarBottomBackground.png Binary files differnew file mode 100644 index 0000000..fb5c9e4 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/statusbarBottomBackground.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/statusbarButtons.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/statusbarButtons.png Binary files differnew file mode 100644 index 0000000..e8090cb --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/statusbarButtons.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/statusbarMenuButton.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/statusbarMenuButton.png Binary files differnew file mode 100644 index 0000000..9b3abdd --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/statusbarMenuButton.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/statusbarMenuButtonSelected.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/statusbarMenuButtonSelected.png Binary files differnew file mode 100644 index 0000000..8189c43 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/statusbarMenuButtonSelected.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/statusbarResizerHorizontal.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/statusbarResizerHorizontal.png Binary files differnew file mode 100644 index 0000000..56deeab --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/statusbarResizerHorizontal.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/statusbarResizerVertical.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/statusbarResizerVertical.png Binary files differnew file mode 100644 index 0000000..7fc145277 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/statusbarResizerVertical.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelineHollowPillBlue.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelineHollowPillBlue.png Binary files differnew file mode 100644 index 0000000..c7c273b --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelineHollowPillBlue.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelineHollowPillGray.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelineHollowPillGray.png Binary files differnew file mode 100644 index 0000000..9ff37ef --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelineHollowPillGray.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelineHollowPillGreen.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelineHollowPillGreen.png Binary files differnew file mode 100644 index 0000000..cc5a8f3 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelineHollowPillGreen.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelineHollowPillOrange.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelineHollowPillOrange.png Binary files differnew file mode 100644 index 0000000..08a81e4 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelineHollowPillOrange.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelineHollowPillPurple.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelineHollowPillPurple.png Binary files differnew file mode 100644 index 0000000..565a05c --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelineHollowPillPurple.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelineHollowPillRed.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelineHollowPillRed.png Binary files differnew file mode 100644 index 0000000..c3a1b9b --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelineHollowPillRed.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelineHollowPillYellow.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelineHollowPillYellow.png Binary files differnew file mode 100644 index 0000000..780045b --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelineHollowPillYellow.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelinePillBlue.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelinePillBlue.png Binary files differnew file mode 100644 index 0000000..c897faa --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelinePillBlue.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelinePillGray.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelinePillGray.png Binary files differnew file mode 100644 index 0000000..2128896 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelinePillGray.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelinePillGreen.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelinePillGreen.png Binary files differnew file mode 100644 index 0000000..9b66125 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelinePillGreen.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelinePillOrange.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelinePillOrange.png Binary files differnew file mode 100644 index 0000000..dd944fb --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelinePillOrange.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelinePillPurple.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelinePillPurple.png Binary files differnew file mode 100644 index 0000000..21b96f7 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelinePillPurple.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelinePillRed.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelinePillRed.png Binary files differnew file mode 100644 index 0000000..f5e213b --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelinePillRed.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelinePillYellow.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelinePillYellow.png Binary files differnew file mode 100644 index 0000000..ae2a5a23 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/timelinePillYellow.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/tipBalloon.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/tipBalloon.png Binary files differnew file mode 100644 index 0000000..4cdf738 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/tipBalloon.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/tipBalloonBottom.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/tipBalloonBottom.png Binary files differnew file mode 100644 index 0000000..3317a5a --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/tipBalloonBottom.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/tipIcon.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/tipIcon.png Binary files differnew file mode 100644 index 0000000..8ca6124 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/tipIcon.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/tipIconPressed.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/tipIconPressed.png Binary files differnew file mode 100644 index 0000000..443e410 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/tipIconPressed.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/toolbarItemSelected.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/toolbarItemSelected.png Binary files differnew file mode 100644 index 0000000..bd681f18 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/toolbarItemSelected.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/treeDownTriangleBlack.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/treeDownTriangleBlack.png Binary files differnew file mode 100644 index 0000000..0821112 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/treeDownTriangleBlack.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/treeDownTriangleWhite.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/treeDownTriangleWhite.png Binary files differnew file mode 100644 index 0000000..1667b51 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/treeDownTriangleWhite.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/treeRightTriangleBlack.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/treeRightTriangleBlack.png Binary files differnew file mode 100644 index 0000000..90de820 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/treeRightTriangleBlack.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/treeRightTriangleWhite.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/treeRightTriangleWhite.png Binary files differnew file mode 100644 index 0000000..2b6a82f --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/treeRightTriangleWhite.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/treeUpTriangleBlack.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/treeUpTriangleBlack.png Binary files differnew file mode 100644 index 0000000..ef69dbc --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/treeUpTriangleBlack.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/treeUpTriangleWhite.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/treeUpTriangleWhite.png Binary files differnew file mode 100644 index 0000000..43ce4be --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/treeUpTriangleWhite.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/userInputIcon.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/userInputIcon.png Binary files differnew file mode 100644 index 0000000..325023f --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/userInputIcon.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/userInputPreviousIcon.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/userInputPreviousIcon.png Binary files differnew file mode 100644 index 0000000..068d572 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/userInputPreviousIcon.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/warningIcon.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/warningIcon.png Binary files differnew file mode 100644 index 0000000..d5e4c82 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/warningIcon.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/warningMediumIcon.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/warningMediumIcon.png Binary files differnew file mode 100644 index 0000000..291e111 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/warningMediumIcon.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/warningsErrors.png b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/warningsErrors.png Binary files differnew file mode 100644 index 0000000..878b593 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Images/warningsErrors.png diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/MetricsSidebarPane.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/MetricsSidebarPane.js new file mode 100644 index 0000000..a22a000 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/MetricsSidebarPane.js @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2007 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. + * 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. + */ + +WebInspector.MetricsSidebarPane = function() +{ + WebInspector.SidebarPane.call(this, WebInspector.UIString("Metrics")); +} + +WebInspector.MetricsSidebarPane.prototype = { + update: function(node) + { + var body = this.bodyElement; + + body.removeChildren(); + + if (node) + this.node = node; + else + node = this.node; + + if (!node || !node.ownerDocument.defaultView) + return; + + var style; + if (node.nodeType === Node.ELEMENT_NODE) + style = node.ownerDocument.defaultView.getComputedStyle(node); + if (!style) + return; + + var metricsElement = document.createElement("div"); + metricsElement.className = "metrics"; + + function createBoxPartElement(style, name, side, suffix) + { + var propertyName = (name !== "position" ? name + "-" : "") + side + suffix; + var value = style.getPropertyValue(propertyName); + if (value === "" || (name !== "position" && value === "0px")) + value = "\u2012"; + else if (name === "position" && value === "auto") + value = "\u2012"; + value = value.replace(/px$/, ""); + + var element = document.createElement("div"); + element.className = side; + element.textContent = value; + element.addEventListener("dblclick", this.startEditing.bind(this, element, name, propertyName), false); + return element; + } + + // Display types for which margin is ignored. + var noMarginDisplayType = { + "table-cell": true, + "table-column": true, + "table-column-group": true, + "table-footer-group": true, + "table-header-group": true, + "table-row": true, + "table-row-group": true + }; + + // Display types for which padding is ignored. + var noPaddingDisplayType = { + "table-column": true, + "table-column-group": true, + "table-footer-group": true, + "table-header-group": true, + "table-row": true, + "table-row-group": true + }; + + // Position types for which top, left, bottom and right are ignored. + var noPositionType = { + "static": true + }; + + var boxes = ["content", "padding", "border", "margin", "position"]; + var boxLabels = [WebInspector.UIString("content"), WebInspector.UIString("padding"), WebInspector.UIString("border"), WebInspector.UIString("margin"), WebInspector.UIString("position")]; + var previousBox; + for (var i = 0; i < boxes.length; ++i) { + var name = boxes[i]; + + if (name === "margin" && noMarginDisplayType[style.display]) + continue; + if (name === "padding" && noPaddingDisplayType[style.display]) + continue; + if (name === "position" && noPositionType[style.position]) + continue; + + var boxElement = document.createElement("div"); + boxElement.className = name; + + if (name === "content") { + var width = style.width.replace(/px$/, ""); + var widthElement = document.createElement("span"); + widthElement.textContent = width; + widthElement.addEventListener("dblclick", this.startEditing.bind(this, widthElement, "width", "width"), false); + + var height = style.height.replace(/px$/, ""); + var heightElement = document.createElement("span"); + heightElement.textContent = height; + heightElement.addEventListener("dblclick", this.startEditing.bind(this, heightElement, "height", "height"), false); + + boxElement.appendChild(widthElement); + boxElement.appendChild(document.createTextNode(" \u00D7 ")); + boxElement.appendChild(heightElement); + } else { + var suffix = (name === "border" ? "-width" : ""); + + var labelElement = document.createElement("div"); + labelElement.className = "label"; + labelElement.textContent = boxLabels[i]; + boxElement.appendChild(labelElement); + + boxElement.appendChild(createBoxPartElement.call(this, style, name, "top", suffix)); + boxElement.appendChild(document.createElement("br")); + boxElement.appendChild(createBoxPartElement.call(this, style, name, "left", suffix)); + + if (previousBox) + boxElement.appendChild(previousBox); + + boxElement.appendChild(createBoxPartElement.call(this, style, name, "right", suffix)); + boxElement.appendChild(document.createElement("br")); + boxElement.appendChild(createBoxPartElement.call(this, style, name, "bottom", suffix)); + } + + previousBox = boxElement; + } + + metricsElement.appendChild(previousBox); + body.appendChild(metricsElement); + }, + + startEditing: function(targetElement, box, styleProperty) + { + if (WebInspector.isBeingEdited(targetElement)) + return; + + var context = { box: box, styleProperty: styleProperty }; + + WebInspector.startEditing(targetElement, this.editingCommitted.bind(this), this.editingCancelled.bind(this), context); + }, + + editingCancelled: function(element, context) + { + this.update(); + }, + + editingCommitted: function(element, userInput, previousContent, context) + { + if (userInput === previousContent) + return this.editingCancelled(element, context); // nothing changed, so cancel + + if (context.box !== "position" && (!userInput || userInput === "\u2012")) + userInput = "0px"; + else if (context.box === "position" && (!userInput || userInput === "\u2012")) + userInput = "auto"; + + // Append a "px" unit if the user input was just a number. + if (/^\d+$/.test(userInput)) + userInput += "px"; + + this.node.style.setProperty(context.styleProperty, userInput, ""); + + this.dispatchEventToListeners("metrics edited"); + + this.update(); + } +} + +WebInspector.MetricsSidebarPane.prototype.__proto__ = WebInspector.SidebarPane.prototype; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Object.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Object.js new file mode 100644 index 0000000..80202b0 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Object.js @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2008 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. ``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 + * 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.Object = function() { +} + +WebInspector.Object.prototype = { + addEventListener: function(eventType, listener, thisObject) { + if (!("_listeners" in this)) + this._listeners = {}; + if (!(eventType in this._listeners)) + this._listeners[eventType] = []; + this._listeners[eventType].push({ thisObject: thisObject, listener: listener }); + }, + + removeEventListener: function(eventType, listener, thisObject) { + if (!("_listeners" in this) || !(eventType in this._listeners)) + return; + var listeners = this._listeners[eventType]; + for (var i = 0; i < listeners.length; ++i) { + if (listener && listeners[i].listener === listener && listeners[i].thisObject === thisObject) + listeners.splice(i, 1); + else if (!listener && thisObject && listeners[i].thisObject === thisObject) + listeners.splice(i, 1); + } + + if (!listeners.length) + delete this._listeners[eventType]; + }, + + dispatchEventToListeners: function(eventType) { + if (!("_listeners" in this) || !(eventType in this._listeners)) + return; + + var stoppedPropagation = false; + + function stopPropagation() + { + stoppedPropagation = true; + } + + function preventDefault() + { + this.defaultPrevented = true; + } + + var event = {target: this, type: eventType, defaultPrevented: false}; + event.stopPropagation = stopPropagation.bind(event); + event.preventDefault = preventDefault.bind(event); + + var listeners = this._listeners[eventType]; + for (var i = 0; i < listeners.length; ++i) { + listeners[i].listener.call(listeners[i].thisObject, event); + if (stoppedPropagation) + break; + } + + return event.defaultPrevented; + } +} diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ObjectPropertiesSection.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ObjectPropertiesSection.js new file mode 100644 index 0000000..ab6ac55 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ObjectPropertiesSection.js @@ -0,0 +1,276 @@ +/* + * Copyright (C) 2008 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. ``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 + * 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.ObjectPropertiesSection = function(object, title, subtitle, emptyPlaceholder, ignoreHasOwnProperty, extraProperties, treeElementConstructor) +{ + if (!title) { + title = Object.describe(object); + if (title.match(/Prototype$/)) { + title = title.replace(/Prototype$/, ""); + if (!subtitle) + subtitle = WebInspector.UIString("Prototype"); + } + } + + this.emptyPlaceholder = (emptyPlaceholder || WebInspector.UIString("No Properties")); + this.object = object; + this.ignoreHasOwnProperty = ignoreHasOwnProperty; + this.extraProperties = extraProperties; + this.treeElementConstructor = treeElementConstructor || WebInspector.ObjectPropertyTreeElement; + this.editable = true; + + WebInspector.PropertiesSection.call(this, title, subtitle); +} + +WebInspector.ObjectPropertiesSection.prototype = { + onpopulate: function() + { + this.update(); + }, + + update: function() + { + var properties = []; + for (var prop in this.object) + properties.push(prop); + if (this.extraProperties) + for (var prop in this.extraProperties) + properties.push(prop); + properties.sort(); + + this.propertiesTreeOutline.removeChildren(); + + for (var i = 0; i < properties.length; ++i) { + var object = this.object; + var propertyName = properties[i]; + if (this.extraProperties && propertyName in this.extraProperties) + object = this.extraProperties; + if (propertyName === "__treeElementIdentifier") + continue; + if (!this.ignoreHasOwnProperty && "hasOwnProperty" in object && !object.hasOwnProperty(propertyName)) + continue; + this.propertiesTreeOutline.appendChild(new this.treeElementConstructor(object, propertyName)); + } + + if (!this.propertiesTreeOutline.children.length) { + var title = "<div class=\"info\">" + this.emptyPlaceholder + "</div>"; + var infoElement = new TreeElement(title, null, false); + this.propertiesTreeOutline.appendChild(infoElement); + } + } +} + +WebInspector.ObjectPropertiesSection.prototype.__proto__ = WebInspector.PropertiesSection.prototype; + +WebInspector.ObjectPropertyTreeElement = function(parentObject, propertyName) +{ + this.parentObject = parentObject; + this.propertyName = propertyName; + + // Pass an empty title, the title gets made later in onattach. + TreeElement.call(this, "", null, false); +} + +WebInspector.ObjectPropertyTreeElement.prototype = { + safePropertyValue: function(object, propertyName) + { + if (object["__lookupGetter__"] && object.__lookupGetter__(propertyName)) + return; + return object[propertyName]; + }, + + onpopulate: function() + { + if (this.children.length && !this.shouldRefreshChildren) + return; + + this.removeChildren(); + + var childObject = this.safePropertyValue(this.parentObject, this.propertyName); + var properties = Object.sortedProperties(childObject); + for (var i = 0; i < properties.length; ++i) { + var propertyName = properties[i]; + if (propertyName === "__treeElementIdentifier") + continue; + this.appendChild(new this.treeOutline.section.treeElementConstructor(childObject, propertyName)); + } + }, + + ondblclick: function(element, event) + { + this.startEditing(); + }, + + onattach: function() + { + this.update(); + }, + + update: function() + { + var childObject = this.safePropertyValue(this.parentObject, this.propertyName); + var isGetter = ("__lookupGetter__" in this.parentObject && this.parentObject.__lookupGetter__(this.propertyName)); + + var nameElement = document.createElement("span"); + nameElement.className = "name"; + nameElement.textContent = this.propertyName; + + this.valueElement = document.createElement("span"); + this.valueElement.className = "value"; + if (!isGetter) { + this.valueElement.textContent = Object.describe(childObject, true); + } else { + // FIXME: this should show something like "getter" (bug 16734). + this.valueElement.textContent = "\u2014"; // em dash + this.valueElement.addStyleClass("dimmed"); + } + + this.listItemElement.removeChildren(); + + this.listItemElement.appendChild(nameElement); + this.listItemElement.appendChild(document.createTextNode(": ")); + this.listItemElement.appendChild(this.valueElement); + + var hasSubProperties = false; + var type = typeof childObject; + if (childObject && (type === "object" || type === "function")) { + for (subPropertyName in childObject) { + if (subPropertyName === "__treeElementIdentifier") + continue; + hasSubProperties = true; + break; + } + } + + this.hasChildren = hasSubProperties; + }, + + updateSiblings: function() + { + if (this.parent.root) + this.treeOutline.section.update(); + else + this.parent.shouldRefreshChildren = true; + }, + + startEditing: function() + { + if (WebInspector.isBeingEdited(this.valueElement) || !this.treeOutline.section.editable) + return; + + var context = { expanded: this.expanded }; + + // Lie about our children to prevent expanding on double click and to collapse subproperties. + this.hasChildren = false; + + this.listItemElement.addStyleClass("editing-sub-part"); + + WebInspector.startEditing(this.valueElement, this.editingCommitted.bind(this), this.editingCancelled.bind(this), context); + }, + + editingEnded: function(context) + { + this.listItemElement.scrollLeft = 0; + this.listItemElement.removeStyleClass("editing-sub-part"); + if (context.expanded) + this.expand(); + }, + + editingCancelled: function(element, context) + { + this.update(); + this.editingEnded(context); + }, + + editingCommitted: function(element, userInput, previousContent, context) + { + if (userInput === previousContent) + return this.editingCancelled(element, context); // nothing changed, so cancel + + this.applyExpression(userInput, true); + + this.editingEnded(context); + }, + + evaluateExpression: function(expression) + { + // Evaluate in the currently selected call frame if the debugger is paused. + // Otherwise evaluate in against the inspected window. + if (WebInspector.panels.scripts && WebInspector.panels.scripts.paused && this.treeOutline.section.editInSelectedCallFrameWhenPaused) + return WebInspector.panels.scripts.evaluateInSelectedCallFrame(expression, false); + return InspectorController.inspectedWindow().eval(expression); + }, + + applyExpression: function(expression, updateInterface) + { + var expressionLength = expression.trimWhitespace().length; + + if (!expressionLength) { + // The user deleted everything, so try to delete the property. + delete this.parentObject[this.propertyName]; + + if (updateInterface) { + if (this.propertyName in this.parentObject) { + // The property was not deleted, so update. + this.update(); + } else { + // The property was deleted, so remove this tree element. + this.parent.removeChild(this); + } + } + + return; + } + + try { + // Surround the expression in parenthesis so the result of the eval is the result + // of the whole expression not the last potential sub-expression. + var result = this.evaluateExpression("(" + expression + ")"); + + // Store the result in the property. + this.parentObject[this.propertyName] = result; + } catch(e) { + try { + // Try to update as a string + var result = this.evaluateExpression("\"" + expression.escapeCharacters("\"") + "\""); + + // Store the result in the property. + this.parentObject[this.propertyName] = result; + } catch(e) { + // The expression failed so don't change the value. So just update and return. + if (updateInterface) + this.update(); + return; + } + } + + if (updateInterface) { + // Call updateSiblings since their value might be based on the value that just changed. + this.updateSiblings(); + } + } +} + +WebInspector.ObjectPropertyTreeElement.prototype.__proto__ = TreeElement.prototype; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Panel.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Panel.js new file mode 100644 index 0000000..5046f6b --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Panel.js @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2007, 2008 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. + * 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. + */ + +WebInspector.Panel = function() +{ + WebInspector.View.call(this); + + this.element.addStyleClass("panel"); +} + +WebInspector.Panel.prototype = { + get toolbarItem() + { + if (this._toolbarItem) + return this._toolbarItem; + + // Sample toolbar item as markup: + // <button class="toolbar-item resources toggleable"> + // <div class="toolbar-icon"></div> + // <div class="toolbar-label">Resources</div> + // </button> + + this._toolbarItem = document.createElement("button"); + this._toolbarItem.className = "toolbar-item toggleable"; + this._toolbarItem.panel = this; + + if ("toolbarItemClass" in this) + this._toolbarItem.addStyleClass(this.toolbarItemClass); + + var iconElement = document.createElement("div"); + iconElement.className = "toolbar-icon"; + this._toolbarItem.appendChild(iconElement); + + if ("toolbarItemLabel" in this) { + var labelElement = document.createElement("div"); + labelElement.className = "toolbar-label"; + labelElement.textContent = this.toolbarItemLabel; + this._toolbarItem.appendChild(labelElement); + } + + return this._toolbarItem; + }, + + show: function() + { + WebInspector.View.prototype.show.call(this); + + var statusBarItems = this.statusBarItems; + if (statusBarItems) { + this._statusBarItemContainer = document.createElement("div"); + for (var i = 0; i < statusBarItems.length; ++i) + this._statusBarItemContainer.appendChild(statusBarItems[i]); + document.getElementById("main-status-bar").appendChild(this._statusBarItemContainer); + } + + if ("_toolbarItem" in this) + this._toolbarItem.addStyleClass("toggled-on"); + + WebInspector.currentFocusElement = document.getElementById("main-panels"); + }, + + hide: function() + { + WebInspector.View.prototype.hide.call(this); + + if (this._statusBarItemContainer && this._statusBarItemContainer.parentNode) + this._statusBarItemContainer.parentNode.removeChild(this._statusBarItemContainer); + delete this._statusBarItemContainer; + if ("_toolbarItem" in this) + this._toolbarItem.removeStyleClass("toggled-on"); + }, + + attach: function() + { + if (!this.element.parentNode) + document.getElementById("main-panels").appendChild(this.element); + }, + + searchCanceled: function(startingNewSearch) + { + if (this._searchResults) { + for (var i = 0; i < this._searchResults.length; ++i) { + var view = this._searchResults[i]; + if (view.searchCanceled) + view.searchCanceled(); + delete view.currentQuery; + } + } + + WebInspector.updateSearchMatchesCount(0, this); + + if (this._currentSearchChunkIntervalIdentifier) { + clearInterval(this._currentSearchChunkIntervalIdentifier); + delete this._currentSearchChunkIntervalIdentifier; + } + + this._totalSearchMatches = 0; + this._currentSearchResultIndex = 0; + this._searchResults = []; + }, + + performSearch: function(query) + { + // Call searchCanceled since it will reset everything we need before doing a new search. + this.searchCanceled(true); + + var searchableViews = this.searchableViews; + if (!searchableViews || !searchableViews.length) + return; + + var parentElement = this.viewsContainerElement; + var visibleView = this.visibleView; + var sortFuction = this.searchResultsSortFunction; + + var matchesCountUpdateTimeout = null; + + function updateMatchesCount() + { + WebInspector.updateSearchMatchesCount(this._totalSearchMatches, this); + matchesCountUpdateTimeout = null; + } + + function updateMatchesCountSoon() + { + if (matchesCountUpdateTimeout) + return; + // Update the matches count every half-second so it doesn't feel twitchy. + matchesCountUpdateTimeout = setTimeout(updateMatchesCount.bind(this), 500); + } + + function finishedCallback(view, searchMatches) + { + if (!searchMatches) + return; + + this._totalSearchMatches += searchMatches; + this._searchResults.push(view); + + if (sortFuction) + this._searchResults.sort(sortFuction); + + if (this.searchMatchFound) + this.searchMatchFound(view, searchMatches); + + updateMatchesCountSoon.call(this); + + if (view === visibleView) + view.jumpToFirstSearchResult(); + } + + var i = 0; + var panel = this; + var boundFinishedCallback = finishedCallback.bind(this); + var chunkIntervalIdentifier = null; + + // Split up the work into chunks so we don't block the + // UI thread while processing. + + function processChunk() + { + var view = searchableViews[i]; + + if (++i >= searchableViews.length) { + if (panel._currentSearchChunkIntervalIdentifier === chunkIntervalIdentifier) + delete panel._currentSearchChunkIntervalIdentifier; + clearInterval(chunkIntervalIdentifier); + } + + if (!view) + return; + + if (view.element.parentNode !== parentElement && view.element.parentNode && parentElement) + view.detach(); + + view.currentQuery = query; + view.performSearch(query, boundFinishedCallback); + } + + processChunk(); + + chunkIntervalIdentifier = setInterval(processChunk, 25); + this._currentSearchChunkIntervalIdentifier = chunkIntervalIdentifier; + }, + + jumpToNextSearchResult: function() + { + if (!this.showView || !this._searchResults || !this._searchResults.length) + return; + + var showFirstResult = false; + + this._currentSearchResultIndex = this._searchResults.indexOf(this.visibleView); + if (this._currentSearchResultIndex === -1) { + this._currentSearchResultIndex = 0; + showFirstResult = true; + } + + var currentView = this._searchResults[this._currentSearchResultIndex]; + + if (currentView.showingLastSearchResult()) { + if (++this._currentSearchResultIndex >= this._searchResults.length) + this._currentSearchResultIndex = 0; + currentView = this._searchResults[this._currentSearchResultIndex]; + showFirstResult = true; + } + + if (currentView !== this.visibleView) + this.showView(currentView); + + if (showFirstResult) + currentView.jumpToFirstSearchResult(); + else + currentView.jumpToNextSearchResult(); + }, + + jumpToPreviousSearchResult: function() + { + if (!this.showView || !this._searchResults || !this._searchResults.length) + return; + + var showLastResult = false; + + this._currentSearchResultIndex = this._searchResults.indexOf(this.visibleView); + if (this._currentSearchResultIndex === -1) { + this._currentSearchResultIndex = 0; + showLastResult = true; + } + + var currentView = this._searchResults[this._currentSearchResultIndex]; + + if (currentView.showingFirstSearchResult()) { + if (--this._currentSearchResultIndex < 0) + this._currentSearchResultIndex = (this._searchResults.length - 1); + currentView = this._searchResults[this._currentSearchResultIndex]; + showLastResult = true; + } + + if (currentView !== this.visibleView) + this.showView(currentView); + + if (showLastResult) + currentView.jumpToLastSearchResult(); + else + currentView.jumpToPreviousSearchResult(); + } +} + +WebInspector.Panel.prototype.__proto__ = WebInspector.View.prototype; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/PanelEnablerView.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/PanelEnablerView.js new file mode 100644 index 0000000..6ec565b --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/PanelEnablerView.js @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2008 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. ``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 + * 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.PanelEnablerView = function(identifier, headingText, disclaimerText, buttonTitle) +{ + WebInspector.View.call(this); + + this.element.addStyleClass("panel-enabler-view"); + this.element.addStyleClass(identifier); + + this.contentElement = document.createElement("div"); + this.contentElement.className = "panel-enabler-view-content"; + this.element.appendChild(this.contentElement); + + this.imageElement = document.createElement("img"); + this.contentElement.appendChild(this.imageElement); + + this.choicesForm = document.createElement("form"); + this.contentElement.appendChild(this.choicesForm); + + this.headerElement = document.createElement("h1"); + this.headerElement.textContent = headingText; + this.choicesForm.appendChild(this.headerElement); + + this.disclaimerElement = document.createElement("div"); + this.disclaimerElement.className = "panel-enabler-disclaimer"; + this.disclaimerElement.textContent = disclaimerText; + this.choicesForm.appendChild(this.disclaimerElement); + + this.enableButton = document.createElement("button"); + this.enableButton.setAttribute("type", "button"); + this.enableButton.textContent = buttonTitle; + this.enableButton.addEventListener("click", this._enableButtonCicked.bind(this), false); + this.choicesForm.appendChild(this.enableButton); + + window.addEventListener("resize", this._windowResized.bind(this), true); +} + +WebInspector.PanelEnablerView.prototype = { + _enableButtonCicked: function() + { + this.dispatchEventToListeners("enable clicked"); + }, + + _windowResized: function() + { + this.imageElement.removeStyleClass("hidden"); + + if (this.element.offsetWidth < (this.choicesForm.offsetWidth + this.imageElement.offsetWidth)) + this.imageElement.addStyleClass("hidden"); + } +} + +WebInspector.PanelEnablerView.prototype.__proto__ = WebInspector.View.prototype; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Placard.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Placard.js new file mode 100644 index 0000000..69a168e --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Placard.js @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2008 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. ``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 + * 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.Placard = function(title, subtitle) +{ + this.element = document.createElement("div"); + this.element.className = "placard"; + this.element.placard = this; + + this.titleElement = document.createElement("div"); + this.titleElement.className = "title"; + + this.subtitleElement = document.createElement("div"); + this.subtitleElement.className = "subtitle"; + + this.element.appendChild(this.subtitleElement); + this.element.appendChild(this.titleElement); + + this.title = title; + this.subtitle = subtitle; + this.selected = false; +} + +WebInspector.Placard.prototype = { + get title() + { + return this._title; + }, + + set title(x) + { + if (this._title === x) + return; + this._title = x; + this.titleElement.textContent = x; + }, + + get subtitle() + { + return this._subtitle; + }, + + set subtitle(x) + { + if (this._subtitle === x) + return; + this._subtitle = x; + this.subtitleElement.innerHTML = x; + }, + + get selected() + { + return this._selected; + }, + + set selected(x) + { + if (x) + this.select(); + else + this.deselect(); + }, + + select: function() + { + if (this._selected) + return; + this._selected = true; + this.element.addStyleClass("selected"); + }, + + deselect: function() + { + if (!this._selected) + return; + this._selected = false; + this.element.removeStyleClass("selected"); + }, + + toggleSelected: function() + { + this.selected = !this.selected; + } +} diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ProfileView.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ProfileView.js new file mode 100644 index 0000000..d00733c --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ProfileView.js @@ -0,0 +1,580 @@ +/* + * Copyright (C) 2008 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. ``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 + * 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.ProfileView = function(profile) +{ + WebInspector.View.call(this); + + this.element.addStyleClass("profile-view"); + + this.showSelfTimeAsPercent = true; + this.showTotalTimeAsPercent = true; + this.showAverageTimeAsPercent = true; + + var columns = { "self": { title: WebInspector.UIString("Self"), width: "72px", sort: "descending", sortable: true }, + "total": { title: WebInspector.UIString("Total"), width: "72px", sortable: true }, + "average": { title: WebInspector.UIString("Average"), width: "72px", sortable: true }, + "calls": { title: WebInspector.UIString("Calls"), width: "54px", sortable: true }, + "function": { title: WebInspector.UIString("Function"), disclosure: true, sortable: true } }; + + this.dataGrid = new WebInspector.DataGrid(columns); + this.dataGrid.addEventListener("sorting changed", this._sortData, this); + this.dataGrid.element.addEventListener("mousedown", this._mouseDownInDataGrid.bind(this), true); + this.element.appendChild(this.dataGrid.element); + + this.viewSelectElement = document.createElement("select"); + this.viewSelectElement.className = "status-bar-item"; + this.viewSelectElement.addEventListener("change", this._changeView.bind(this), false); + this.view = "Heavy"; + + var heavyViewOption = document.createElement("option"); + heavyViewOption.label = WebInspector.UIString("Heavy (Bottom Up)"); + var treeViewOption = document.createElement("option"); + treeViewOption.label = WebInspector.UIString("Tree (Top Down)"); + this.viewSelectElement.appendChild(heavyViewOption); + this.viewSelectElement.appendChild(treeViewOption); + + this.percentButton = document.createElement("button"); + this.percentButton.className = "percent-time-status-bar-item status-bar-item"; + this.percentButton.addEventListener("click", this._percentClicked.bind(this), false); + + this.focusButton = document.createElement("button"); + this.focusButton.title = WebInspector.UIString("Focus selected function."); + this.focusButton.className = "focus-profile-node-status-bar-item status-bar-item"; + this.focusButton.disabled = true; + this.focusButton.addEventListener("click", this._focusClicked.bind(this), false); + + this.excludeButton = document.createElement("button"); + this.excludeButton.title = WebInspector.UIString("Exclude selected function."); + this.excludeButton.className = "exclude-profile-node-status-bar-item status-bar-item"; + this.excludeButton.disabled = true; + this.excludeButton.addEventListener("click", this._excludeClicked.bind(this), false); + + this.resetButton = document.createElement("button"); + this.resetButton.title = WebInspector.UIString("Restore all functions."); + this.resetButton.className = "reset-profile-status-bar-item status-bar-item hidden"; + this.resetButton.addEventListener("click", this._resetClicked.bind(this), false); + + this.profile = profile; + + this.profileDataGridTree = this.bottomUpProfileDataGridTree; + this.profileDataGridTree.sort(WebInspector.ProfileDataGridTree.propertyComparator("selfTime", false)); + + this.refresh(); + + this._updatePercentButton(); +} + +WebInspector.ProfileView.prototype = { + get statusBarItems() + { + return [this.viewSelectElement, this.percentButton, this.focusButton, this.excludeButton, this.resetButton]; + }, + + get profile() + { + return this._profile; + }, + + set profile(profile) + { + this._profile = profile; + }, + + get bottomUpProfileDataGridTree() + { + if (!this._bottomUpProfileDataGridTree) + this._bottomUpProfileDataGridTree = new WebInspector.BottomUpProfileDataGridTree(this, this.profile.head); + return this._bottomUpProfileDataGridTree; + }, + + get topDownProfileDataGridTree() + { + if (!this._topDownProfileDataGridTree) + this._topDownProfileDataGridTree = new WebInspector.TopDownProfileDataGridTree(this, this.profile.head); + return this._topDownProfileDataGridTree; + }, + + get currentTree() + { + return this._currentTree; + }, + + set currentTree(tree) + { + this._currentTree = tree; + this.refresh(); + }, + + get topDownTree() + { + if (!this._topDownTree) { + this._topDownTree = WebInspector.TopDownTreeFactory.create(this.profile.head); + this._sortProfile(this._topDownTree); + } + + return this._topDownTree; + }, + + get bottomUpTree() + { + if (!this._bottomUpTree) { + this._bottomUpTree = WebInspector.BottomUpTreeFactory.create(this.profile.head); + this._sortProfile(this._bottomUpTree); + } + + return this._bottomUpTree; + }, + + hide: function() + { + WebInspector.View.prototype.hide.call(this); + this._currentSearchResultIndex = -1; + }, + + refresh: function() + { + var selectedProfileNode = this.dataGrid.selectedNode ? this.dataGrid.selectedNode.profileNode : null; + + this.dataGrid.removeChildren(); + + var children = this.profileDataGridTree.children; + var count = children.length; + + for (var index = 0; index < count; ++index) + this.dataGrid.appendChild(children[index]); + + if (selectedProfileNode && selectedProfileNode._dataGridNode) + selectedProfileNode._dataGridNode.selected = true; + }, + + refreshVisibleData: function() + { + var child = this.dataGrid.children[0]; + while (child) { + child.refresh(); + child = child.traverseNextNode(false, null, true); + } + }, + + refreshShowAsPercents: function() + { + this._updatePercentButton(); + this.refreshVisibleData(); + }, + + searchCanceled: function() + { + if (this._searchResults) { + for (var i = 0; i < this._searchResults.length; ++i) { + var profileNode = this._searchResults[i].profileNode; + + delete profileNode._searchMatchedSelfColumn; + delete profileNode._searchMatchedTotalColumn; + delete profileNode._searchMatchedCallsColumn; + delete profileNode._searchMatchedFunctionColumn; + + if (profileNode._dataGridNode) + profileNode._dataGridNode.refresh(); + } + } + + delete this._searchFinishedCallback; + this._currentSearchResultIndex = -1; + this._searchResults = []; + }, + + performSearch: function(query, finishedCallback) + { + // Call searchCanceled since it will reset everything we need before doing a new search. + this.searchCanceled(); + + query = query.trimWhitespace(); + + if (!query.length) + return; + + this._searchFinishedCallback = finishedCallback; + + var greaterThan = (query.indexOf(">") === 0); + var lessThan = (query.indexOf("<") === 0); + var equalTo = (query.indexOf("=") === 0 || ((greaterThan || lessThan) && query.indexOf("=") === 1)); + var percentUnits = (query.lastIndexOf("%") === (query.length - 1)); + var millisecondsUnits = (query.length > 2 && query.lastIndexOf("ms") === (query.length - 2)); + var secondsUnits = (!millisecondsUnits && query.lastIndexOf("s") === (query.length - 1)); + + var queryNumber = parseFloat(query); + if (greaterThan || lessThan || equalTo) { + if (equalTo && (greaterThan || lessThan)) + queryNumber = parseFloat(query.substring(2)); + else + queryNumber = parseFloat(query.substring(1)); + } + + var queryNumberMilliseconds = (secondsUnits ? (queryNumber * 1000) : queryNumber); + + // Make equalTo implicitly true if it wasn't specified there is no other operator. + if (!isNaN(queryNumber) && !(greaterThan || lessThan)) + equalTo = true; + + function matchesQuery(/*ProfileDataGridNode*/ profileDataGridNode) + { + delete profileDataGridNode._searchMatchedSelfColumn; + delete profileDataGridNode._searchMatchedTotalColumn; + delete profileDataGridNode._searchMatchedAverageColumn; + delete profileDataGridNode._searchMatchedCallsColumn; + delete profileDataGridNode._searchMatchedFunctionColumn; + + if (percentUnits) { + if (lessThan) { + if (profileDataGridNode.selfPercent < queryNumber) + profileDataGridNode._searchMatchedSelfColumn = true; + if (profileDataGridNode.totalPercent < queryNumber) + profileDataGridNode._searchMatchedTotalColumn = true; + if (profileDataGridNode.averagePercent < queryNumberMilliseconds) + profileDataGridNode._searchMatchedAverageColumn = true; + } else if (greaterThan) { + if (profileDataGridNode.selfPercent > queryNumber) + profileDataGridNode._searchMatchedSelfColumn = true; + if (profileDataGridNode.totalPercent > queryNumber) + profileDataGridNode._searchMatchedTotalColumn = true; + if (profileDataGridNode.averagePercent < queryNumberMilliseconds) + profileDataGridNode._searchMatchedAverageColumn = true; + } + + if (equalTo) { + if (profileDataGridNode.selfPercent == queryNumber) + profileDataGridNode._searchMatchedSelfColumn = true; + if (profileDataGridNode.totalPercent == queryNumber) + profileDataGridNode._searchMatchedTotalColumn = true; + if (profileDataGridNode.averagePercent < queryNumberMilliseconds) + profileDataGridNode._searchMatchedAverageColumn = true; + } + } else if (millisecondsUnits || secondsUnits) { + if (lessThan) { + if (profileDataGridNode.selfTime < queryNumberMilliseconds) + profileDataGridNode._searchMatchedSelfColumn = true; + if (profileDataGridNode.totalTime < queryNumberMilliseconds) + profileDataGridNode._searchMatchedTotalColumn = true; + if (profileDataGridNode.averageTime < queryNumberMilliseconds) + profileDataGridNode._searchMatchedAverageColumn = true; + } else if (greaterThan) { + if (profileDataGridNode.selfTime > queryNumberMilliseconds) + profileDataGridNode._searchMatchedSelfColumn = true; + if (profileDataGridNode.totalTime > queryNumberMilliseconds) + profileDataGridNode._searchMatchedTotalColumn = true; + if (profileDataGridNode.averageTime > queryNumberMilliseconds) + profileDataGridNode._searchMatchedAverageColumn = true; + } + + if (equalTo) { + if (profileDataGridNode.selfTime == queryNumberMilliseconds) + profileDataGridNode._searchMatchedSelfColumn = true; + if (profileDataGridNode.totalTime == queryNumberMilliseconds) + profileDataGridNode._searchMatchedTotalColumn = true; + if (profileDataGridNode.averageTime == queryNumberMilliseconds) + profileDataGridNode._searchMatchedAverageColumn = true; + } + } else { + if (equalTo && profileDataGridNode.numberOfCalls == queryNumber) + profileDataGridNode._searchMatchedCallsColumn = true; + if (greaterThan && profileDataGridNode.numberOfCalls > queryNumber) + profileDataGridNode._searchMatchedCallsColumn = true; + if (lessThan && profileDataGridNode.numberOfCalls < queryNumber) + profileDataGridNode._searchMatchedCallsColumn = true; + } + + if (profileDataGridNode.functionName.hasSubstring(query, true) || profileDataGridNode.url.hasSubstring(query, true)) + profileDataGridNode._searchMatchedFunctionColumn = true; + + if (profileDataGridNode._searchMatchedSelfColumn || + profileDataGridNode._searchMatchedTotalColumn || + profileDataGridNode._searchMatchedAverageColumn || + profileDataGridNode._searchMatchedCallsColumn || + profileDataGridNode._searchMatchedFunctionColumn); + { + profileDataGridNode.refresh(); + return true; + } + + return false; + } + + var current = this.dataGrid; + var ancestors = []; + var nextIndexes = []; + var startIndex = 0; + + while (current) { + var children = current.children; + var childrenLength = children.length; + + if (startIndex >= childrenLength) { + current = ancestors.pop(); + startIndex = nextIndexes.pop(); + continue; + } + + for (var i = startIndex; i < childrenLength; ++i) { + var child = children[i]; + + if (matchesQuery(child)) { + if (child._dataGridNode) { + // The child has a data grid node already, no need to remember the ancestors. + this._searchResults.push({ profileNode: child }); + } else { + var ancestorsCopy = [].concat(ancestors); + ancestorsCopy.push(current); + this._searchResults.push({ profileNode: child, ancestors: ancestorsCopy }); + } + } + + if (child.children.length) { + ancestors.push(current); + nextIndexes.push(i + 1); + current = child; + startIndex = 0; + break; + } + + if (i === (childrenLength - 1)) { + current = ancestors.pop(); + startIndex = nextIndexes.pop(); + } + } + } + + finishedCallback(this, this._searchResults.length); + }, + + jumpToFirstSearchResult: function() + { + if (!this._searchResults || !this._searchResults.length) + return; + this._currentSearchResultIndex = 0; + this._jumpToSearchResult(this._currentSearchResultIndex); + }, + + jumpToLastSearchResult: function() + { + if (!this._searchResults || !this._searchResults.length) + return; + this._currentSearchResultIndex = (this._searchResults.length - 1); + this._jumpToSearchResult(this._currentSearchResultIndex); + }, + + jumpToNextSearchResult: function() + { + if (!this._searchResults || !this._searchResults.length) + return; + if (++this._currentSearchResultIndex >= this._searchResults.length) + this._currentSearchResultIndex = 0; + this._jumpToSearchResult(this._currentSearchResultIndex); + }, + + jumpToPreviousSearchResult: function() + { + if (!this._searchResults || !this._searchResults.length) + return; + if (--this._currentSearchResultIndex < 0) + this._currentSearchResultIndex = (this._searchResults.length - 1); + this._jumpToSearchResult(this._currentSearchResultIndex); + }, + + showingFirstSearchResult: function() + { + return (this._currentSearchResultIndex === 0); + }, + + showingLastSearchResult: function() + { + return (this._searchResults && this._currentSearchResultIndex === (this._searchResults.length - 1)); + }, + + _jumpToSearchResult: function(index) + { + var searchResult = this._searchResults[index]; + if (!searchResult) + return; + + var profileNode = this._searchResults[index].profileNode; + if (!profileNode._dataGridNode && searchResult.ancestors) { + var ancestors = searchResult.ancestors; + for (var i = 0; i < ancestors.length; ++i) { + var ancestorProfileNode = ancestors[i]; + var gridNode = ancestorProfileNode._dataGridNode; + if (gridNode) + gridNode.expand(); + } + + // No need to keep the ancestors around. + delete searchResult.ancestors; + } + + gridNode = profileNode._dataGridNode; + if (!gridNode) + return; + + gridNode.reveal(); + gridNode.select(); + }, + + _changeView: function(event) + { + if (!event || !this.profile) + return; + + if (event.target.selectedIndex == 1 && this.view == "Heavy") { + this.profileDataGridTree = this.topDownProfileDataGridTree; + this._sortProfile(); + this.view = "Tree"; + } else if (event.target.selectedIndex == 0 && this.view == "Tree") { + this.profileDataGridTree = this.bottomUpProfileDataGridTree; + this._sortProfile(); + this.view = "Heavy"; + } + + if (!this.currentQuery || !this._searchFinishedCallback || !this._searchResults) + return; + + // The current search needs to be performed again. First negate out previous match + // count by calling the search finished callback with a negative number of matches. + // Then perform the search again the with same query and callback. + this._searchFinishedCallback(this, -this._searchResults.length); + this.performSearch(this.currentQuery, this._searchFinishedCallback); + }, + + _percentClicked: function(event) + { + var currentState = this.showSelfTimeAsPercent && this.showTotalTimeAsPercent && this.showAverageTimeAsPercent; + this.showSelfTimeAsPercent = !currentState; + this.showTotalTimeAsPercent = !currentState; + this.showAverageTimeAsPercent = !currentState; + this.refreshShowAsPercents(); + }, + + _updatePercentButton: function() + { + if (this.showSelfTimeAsPercent && this.showTotalTimeAsPercent && this.showAverageTimeAsPercent) { + this.percentButton.title = WebInspector.UIString("Show absolute total and self times."); + this.percentButton.addStyleClass("toggled-on"); + } else { + this.percentButton.title = WebInspector.UIString("Show total and self times as percentages."); + this.percentButton.removeStyleClass("toggled-on"); + } + }, + + _focusClicked: function(event) + { + if (!this.dataGrid.selectedNode) + return; + + this.resetButton.removeStyleClass("hidden"); + this.profileDataGridTree.focus(this.dataGrid.selectedNode); + this.refresh(); + this.refreshVisibleData(); + }, + + _excludeClicked: function(event) + { + var selectedNode = this.dataGrid.selectedNode + + if (!selectedNode) + return; + + selectedNode.deselect(); + + this.resetButton.removeStyleClass("hidden"); + this.profileDataGridTree.exclude(selectedNode); + this.refresh(); + this.refreshVisibleData(); + }, + + _resetClicked: function(event) + { + this.resetButton.addStyleClass("hidden"); + this.profileDataGridTree.restore(); + this.refresh(); + this.refreshVisibleData(); + }, + + _dataGridNodeSelected: function(node) + { + this.focusButton.disabled = false; + this.excludeButton.disabled = false; + }, + + _dataGridNodeDeselected: function(node) + { + this.focusButton.disabled = true; + this.excludeButton.disabled = true; + }, + + _sortData: function(event) + { + this._sortProfile(this.profile); + }, + + _sortProfile: function() + { + var sortAscending = this.dataGrid.sortOrder === "ascending"; + var sortColumnIdentifier = this.dataGrid.sortColumnIdentifier; + var sortProperty = { + "average": "averageTime", + "self": "selfTime", + "total": "totalTime", + "calls": "numberOfCalls", + "function": "functionName" + }[sortColumnIdentifier]; + + this.profileDataGridTree.sort(WebInspector.ProfileDataGridTree.propertyComparator(sortProperty, sortAscending)); + + this.refresh(); + }, + + _mouseDownInDataGrid: function(event) + { + if (event.detail < 2) + return; + + var cell = event.target.enclosingNodeOrSelfWithNodeName("td"); + if (!cell || (!cell.hasStyleClass("total-column") && !cell.hasStyleClass("self-column") && !cell.hasStyleClass("average-column"))) + return; + + if (cell.hasStyleClass("total-column")) + this.showTotalTimeAsPercent = !this.showTotalTimeAsPercent; + else if (cell.hasStyleClass("self-column")) + this.showSelfTimeAsPercent = !this.showSelfTimeAsPercent; + else if (cell.hasStyleClass("average-column")) + this.showAverageTimeAsPercent = !this.showAverageTimeAsPercent; + + this.refreshShowAsPercents(); + + event.preventDefault(); + event.stopPropagation(); + } +} + +WebInspector.ProfileView.prototype.__proto__ = WebInspector.View.prototype; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ProfilesPanel.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ProfilesPanel.js new file mode 100644 index 0000000..413246c --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ProfilesPanel.js @@ -0,0 +1,502 @@ +/* + * Copyright (C) 2008 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. ``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 + * 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. + */ + +const UserInitiatedProfileName = "org.webkit.profiles.user-initiated"; + +WebInspector.ProfilesPanel = function() +{ + WebInspector.Panel.call(this); + + this.element.addStyleClass("profiles"); + + var panelEnablerHeading = WebInspector.UIString("You need to enable profiling before you can use the Profiles panel."); + var panelEnablerDisclaimer = WebInspector.UIString("Enabling profiling will make scripts run slower."); + var panelEnablerButton = WebInspector.UIString("Enable Profiling"); + this.panelEnablerView = new WebInspector.PanelEnablerView("profiles", panelEnablerHeading, panelEnablerDisclaimer, panelEnablerButton); + this.panelEnablerView.addEventListener("enable clicked", this._enableProfiling, this); + + this.element.appendChild(this.panelEnablerView.element); + + this.sidebarElement = document.createElement("div"); + this.sidebarElement.id = "profiles-sidebar"; + this.sidebarElement.className = "sidebar"; + this.element.appendChild(this.sidebarElement); + + this.sidebarResizeElement = document.createElement("div"); + this.sidebarResizeElement.className = "sidebar-resizer-vertical"; + this.sidebarResizeElement.addEventListener("mousedown", this._startSidebarDragging.bind(this), false); + this.element.appendChild(this.sidebarResizeElement); + + this.sidebarTreeElement = document.createElement("ol"); + this.sidebarTreeElement.className = "sidebar-tree"; + this.sidebarElement.appendChild(this.sidebarTreeElement); + + this.sidebarTree = new TreeOutline(this.sidebarTreeElement); + + this.profileViews = document.createElement("div"); + this.profileViews.id = "profile-views"; + this.element.appendChild(this.profileViews); + + this.enableToggleButton = document.createElement("button"); + this.enableToggleButton.className = "enable-toggle-status-bar-item status-bar-item"; + this.enableToggleButton.addEventListener("click", this._toggleProfiling.bind(this), false); + + this.recordButton = document.createElement("button"); + this.recordButton.title = WebInspector.UIString("Start profiling."); + this.recordButton.id = "record-profile-status-bar-item"; + this.recordButton.className = "status-bar-item"; + this.recordButton.addEventListener("click", this._recordClicked.bind(this), false); + + this.recording = false; + + this.profileViewStatusBarItemsContainer = document.createElement("div"); + this.profileViewStatusBarItemsContainer.id = "profile-view-status-bar-items"; + + this.reset(); +} + +WebInspector.ProfilesPanel.prototype = { + toolbarItemClass: "profiles", + + get toolbarItemLabel() + { + return WebInspector.UIString("Profiles"); + }, + + get statusBarItems() + { + return [this.enableToggleButton, this.recordButton, this.profileViewStatusBarItemsContainer]; + }, + + show: function() + { + WebInspector.Panel.prototype.show.call(this); + this._updateSidebarWidth(); + if (this._shouldPopulateProfiles) + this._populateProfiles(); + }, + + populateInterface: function() + { + if (this.visible) + this._populateProfiles(); + else + this._shouldPopulateProfiles = true; + }, + + profilerWasEnabled: function() + { + this.reset(); + this.populateInterface(); + }, + + profilerWasDisabled: function() + { + this.reset(); + }, + + reset: function() + { + if (this._profiles) { + var profiledLength = this._profiles.length; + for (var i = 0; i < profiledLength; ++i) { + var profile = this._profiles[i]; + delete profile._profileView; + } + } + + delete this.currentQuery; + this.searchCanceled(); + + this._profiles = []; + this._profilesIdMap = {}; + this._profileGroups = {}; + this._profileGroupsForLinks = {} + + this.sidebarTreeElement.removeStyleClass("some-expandable"); + + this.sidebarTree.removeChildren(); + this.profileViews.removeChildren(); + + this.profileViewStatusBarItemsContainer.removeChildren(); + + this._updateInterface(); + }, + + handleKeyEvent: function(event) + { + this.sidebarTree.handleKeyEvent(event); + }, + + addProfile: function(profile) + { + this._profiles.push(profile); + this._profilesIdMap[profile.uid] = profile; + + var sidebarParent = this.sidebarTree; + var small = false; + var alternateTitle; + + if (profile.title.indexOf(UserInitiatedProfileName) !== 0) { + if (!(profile.title in this._profileGroups)) + this._profileGroups[profile.title] = []; + + var group = this._profileGroups[profile.title]; + group.push(profile); + + if (group.length === 2) { + // Make a group TreeElement now that there are 2 profiles. + group._profilesTreeElement = new WebInspector.ProfileGroupSidebarTreeElement(profile.title); + + // Insert at the same index for the first profile of the group. + var index = this.sidebarTree.children.indexOf(group[0]._profilesTreeElement); + this.sidebarTree.insertChild(group._profilesTreeElement, index); + + // Move the first profile to the group. + var selected = group[0]._profilesTreeElement.selected; + this.sidebarTree.removeChild(group[0]._profilesTreeElement); + group._profilesTreeElement.appendChild(group[0]._profilesTreeElement); + if (selected) { + group[0]._profilesTreeElement.select(); + group[0]._profilesTreeElement.reveal(); + } + + group[0]._profilesTreeElement.small = true; + group[0]._profilesTreeElement.mainTitle = WebInspector.UIString("Run %d", 1); + + this.sidebarTreeElement.addStyleClass("some-expandable"); + } + + if (group.length >= 2) { + sidebarParent = group._profilesTreeElement; + alternateTitle = WebInspector.UIString("Run %d", group.length); + small = true; + } + } + + var profileTreeElement = new WebInspector.ProfileSidebarTreeElement(profile); + profileTreeElement.small = small; + if (alternateTitle) + profileTreeElement.mainTitle = alternateTitle; + profile._profilesTreeElement = profileTreeElement; + + sidebarParent.appendChild(profileTreeElement); + }, + + showProfile: function(profile) + { + if (!profile) + return; + + if (this.visibleView) + this.visibleView.hide(); + + var view = this.profileViewForProfile(profile); + + view.show(this.profileViews); + + profile._profilesTreeElement.select(true); + profile._profilesTreeElement.reveal(); + + this.visibleView = view; + + this.profileViewStatusBarItemsContainer.removeChildren(); + + var statusBarItems = view.statusBarItems; + for (var i = 0; i < statusBarItems.length; ++i) + this.profileViewStatusBarItemsContainer.appendChild(statusBarItems[i]); + }, + + showView: function(view) + { + this.showProfile(view.profile); + }, + + profileViewForProfile: function(profile) + { + if (!profile) + return null; + if (!profile._profileView) + profile._profileView = new WebInspector.ProfileView(profile); + return profile._profileView; + }, + + showProfileById: function(uid) + { + this.showProfile(this._profilesIdMap[uid]); + }, + + closeVisibleView: function() + { + if (this.visibleView) + this.visibleView.hide(); + delete this.visibleView; + }, + + displayTitleForProfileLink: function(title) + { + title = unescape(title); + if (title.indexOf(UserInitiatedProfileName) === 0) { + title = WebInspector.UIString("Profile %d", title.substring(UserInitiatedProfileName.length + 1)); + } else { + if (!(title in this._profileGroupsForLinks)) + this._profileGroupsForLinks[title] = 0; + + groupNumber = ++this._profileGroupsForLinks[title]; + + if (groupNumber >= 2) + title += " " + WebInspector.UIString("Run %d", groupNumber); + } + + return title; + }, + + get searchableViews() + { + var views = []; + + const visibleView = this.visibleView; + if (visibleView && visibleView.performSearch) + views.push(visibleView); + + var profilesLength = this._profiles.length; + for (var i = 0; i < profilesLength; ++i) { + var view = this.profileViewForProfile(this._profiles[i]); + if (!view.performSearch || view === visibleView) + continue; + views.push(view); + } + + return views; + }, + + searchMatchFound: function(view, matches) + { + view.profile._profilesTreeElement.searchMatches = matches; + }, + + searchCanceled: function(startingNewSearch) + { + WebInspector.Panel.prototype.searchCanceled.call(this, startingNewSearch); + + if (!this._profiles) + return; + + for (var i = 0; i < this._profiles.length; ++i) { + var profile = this._profiles[i]; + profile._profilesTreeElement.searchMatches = 0; + } + }, + + setRecordingProfile: function(isProfiling) + { + this.recording = isProfiling; + + if (isProfiling) { + this.recordButton.addStyleClass("toggled-on"); + this.recordButton.title = WebInspector.UIString("Stop profiling."); + } else { + this.recordButton.removeStyleClass("toggled-on"); + this.recordButton.title = WebInspector.UIString("Start profiling."); + } + }, + + _updateInterface: function() + { + if (InspectorController.profilerEnabled()) { + this.enableToggleButton.title = WebInspector.UIString("Profiling enabled. Click to disable."); + this.enableToggleButton.addStyleClass("toggled-on"); + this.recordButton.removeStyleClass("hidden"); + this.profileViewStatusBarItemsContainer.removeStyleClass("hidden"); + this.panelEnablerView.visible = false; + } else { + this.enableToggleButton.title = WebInspector.UIString("Profiling disabled. Click to enable."); + this.enableToggleButton.removeStyleClass("toggled-on"); + this.recordButton.addStyleClass("hidden"); + this.profileViewStatusBarItemsContainer.addStyleClass("hidden"); + this.panelEnablerView.visible = true; + } + }, + + _recordClicked: function() + { + this.recording = !this.recording; + + if (this.recording) + InspectorController.startProfiling(); + else + InspectorController.stopProfiling(); + }, + + _enableProfiling: function() + { + if (InspectorController.profilerEnabled()) + return; + this._toggleProfiling(); + }, + + _toggleProfiling: function() + { + if (InspectorController.profilerEnabled()) + InspectorController.disableProfiler(); + else + InspectorController.enableProfiler(); + }, + + _populateProfiles: function() + { + if (this.sidebarTree.children.length) + return; + + var profiles = InspectorController.profiles(); + var profilesLength = profiles.length; + for (var i = 0; i < profilesLength; ++i) { + var profile = profiles[i]; + this.addProfile(profile); + } + + if (this.sidebarTree.children[0]) + this.sidebarTree.children[0].select(); + + delete this._shouldPopulateProfiles; + }, + + _startSidebarDragging: function(event) + { + WebInspector.elementDragStart(this.sidebarResizeElement, this._sidebarDragging.bind(this), this._endSidebarDragging.bind(this), event, "col-resize"); + }, + + _sidebarDragging: function(event) + { + this._updateSidebarWidth(event.pageX); + + event.preventDefault(); + }, + + _endSidebarDragging: function(event) + { + WebInspector.elementDragEnd(event); + }, + + _updateSidebarWidth: function(width) + { + if (this.sidebarElement.offsetWidth <= 0) { + // The stylesheet hasn't loaded yet or the window is closed, + // so we can't calculate what is need. Return early. + return; + } + + if (!("_currentSidebarWidth" in this)) + this._currentSidebarWidth = this.sidebarElement.offsetWidth; + + if (typeof width === "undefined") + width = this._currentSidebarWidth; + + width = Number.constrain(width, Preferences.minSidebarWidth, window.innerWidth / 2); + + this._currentSidebarWidth = width; + + this.sidebarElement.style.width = width + "px"; + this.profileViews.style.left = width + "px"; + this.profileViewStatusBarItemsContainer.style.left = width + "px"; + this.sidebarResizeElement.style.left = (width - 3) + "px"; + } +} + +WebInspector.ProfilesPanel.prototype.__proto__ = WebInspector.Panel.prototype; + +WebInspector.ProfileSidebarTreeElement = function(profile) +{ + this.profile = profile; + + if (this.profile.title.indexOf(UserInitiatedProfileName) === 0) + this._profileNumber = this.profile.title.substring(UserInitiatedProfileName.length + 1); + + WebInspector.SidebarTreeElement.call(this, "profile-sidebar-tree-item", "", "", profile, false); + + this.refreshTitles(); +} + +WebInspector.ProfileSidebarTreeElement.prototype = { + onselect: function() + { + WebInspector.panels.profiles.showProfile(this.profile); + }, + + get mainTitle() + { + if (this._mainTitle) + return this._mainTitle; + if (this.profile.title.indexOf(UserInitiatedProfileName) === 0) + return WebInspector.UIString("Profile %d", this._profileNumber); + return this.profile.title; + }, + + set mainTitle(x) + { + this._mainTitle = x; + this.refreshTitles(); + }, + + get subtitle() + { + // There is no subtitle. + }, + + set subtitle(x) + { + // Can't change subtitle. + }, + + set searchMatches(matches) + { + if (!matches) { + if (!this.bubbleElement) + return; + this.bubbleElement.removeStyleClass("search-matches"); + this.bubbleText = ""; + return; + } + + this.bubbleText = matches; + this.bubbleElement.addStyleClass("search-matches"); + } +} + +WebInspector.ProfileSidebarTreeElement.prototype.__proto__ = WebInspector.SidebarTreeElement.prototype; + +WebInspector.ProfileGroupSidebarTreeElement = function(title, subtitle) +{ + WebInspector.SidebarTreeElement.call(this, "profile-group-sidebar-tree-item", title, subtitle, null, true); +} + +WebInspector.ProfileGroupSidebarTreeElement.prototype = { + onselect: function() + { + WebInspector.panels.profiles.showProfile(this.children[this.children.length - 1].profile); + } +} + +WebInspector.ProfileGroupSidebarTreeElement.prototype.__proto__ = WebInspector.SidebarTreeElement.prototype; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/PropertiesSection.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/PropertiesSection.js new file mode 100644 index 0000000..a4b2fba --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/PropertiesSection.js @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2007 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. + * 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. + */ + +WebInspector.PropertiesSection = function(title, subtitle) +{ + this.element = document.createElement("div"); + this.element.className = "section"; + + this.headerElement = document.createElement("div"); + this.headerElement.className = "header"; + + this.titleElement = document.createElement("div"); + this.titleElement.className = "title"; + + this.subtitleElement = document.createElement("div"); + this.subtitleElement.className = "subtitle"; + + this.headerElement.appendChild(this.subtitleElement); + this.headerElement.appendChild(this.titleElement); + + this.headerElement.addEventListener("click", this.toggleExpanded.bind(this), false); + + this.propertiesElement = document.createElement("ol"); + this.propertiesElement.className = "properties"; + this.propertiesTreeOutline = new TreeOutline(this.propertiesElement); + this.propertiesTreeOutline.section = this; + + this.element.appendChild(this.headerElement); + this.element.appendChild(this.propertiesElement); + + this.title = title; + this.subtitle = subtitle; + this._expanded = false; +} + +WebInspector.PropertiesSection.prototype = { + get title() + { + return this._title; + }, + + set title(x) + { + if (this._title === x) + return; + this._title = x; + + if (x instanceof Node) { + this.titleElement.removeChildren(); + this.titleElement.appendChild(x); + } else + this.titleElement.textContent = x; + }, + + get subtitle() + { + return this._subtitle; + }, + + set subtitle(x) + { + if (this._subtitle === x) + return; + this._subtitle = x; + this.subtitleElement.innerHTML = x; + }, + + get expanded() + { + return this._expanded; + }, + + set expanded(x) + { + if (x) + this.expand(); + else + this.collapse(); + }, + + get populated() + { + return this._populated; + }, + + set populated(x) + { + this._populated = x; + if (!x && this.onpopulate && this._expanded) { + this.onpopulate(this); + this._populated = true; + } + }, + + expand: function() + { + if (this._expanded) + return; + this._expanded = true; + this.element.addStyleClass("expanded"); + + if (!this._populated && this.onpopulate) { + this.onpopulate(this); + this._populated = true; + } + }, + + collapse: function() + { + if (!this._expanded) + return; + this._expanded = false; + this.element.removeStyleClass("expanded"); + }, + + toggleExpanded: function() + { + this.expanded = !this.expanded; + } +} diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/PropertiesSidebarPane.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/PropertiesSidebarPane.js new file mode 100644 index 0000000..70db805 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/PropertiesSidebarPane.js @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2007 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. + * 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. + */ + +WebInspector.PropertiesSidebarPane = function() +{ + WebInspector.SidebarPane.call(this, WebInspector.UIString("Properties")); +} + +WebInspector.PropertiesSidebarPane.prototype = { + update: function(object) + { + var body = this.bodyElement; + + body.removeChildren(); + + this.sections = []; + + if (!object) + return; + + for (var prototype = object; prototype; prototype = prototype.__proto__) { + var section = new WebInspector.ObjectPropertiesSection(prototype); + this.sections.push(section); + body.appendChild(section.element); + } + } +} + +WebInspector.PropertiesSidebarPane.prototype.__proto__ = WebInspector.SidebarPane.prototype; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Resource.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Resource.js new file mode 100644 index 0000000..058f232 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Resource.js @@ -0,0 +1,625 @@ +/* + * Copyright (C) 2007, 2008 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. + * 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. + */ + +WebInspector.Resource = function(requestHeaders, url, domain, path, lastPathComponent, identifier, mainResource, cached) +{ + this.identifier = identifier; + + this.startTime = -1; + this.endTime = -1; + this.mainResource = mainResource; + this.requestHeaders = requestHeaders; + this.url = url; + this.domain = domain; + this.path = path; + this.lastPathComponent = lastPathComponent; + this.cached = cached; + + this.category = WebInspector.resourceCategories.other; +} + +// Keep these in sync with WebCore::InspectorResource::Type +WebInspector.Resource.Type = { + Document: 0, + Stylesheet: 1, + Image: 2, + Font: 3, + Script: 4, + XHR: 5, + Other: 6, + + isTextType: function(type) + { + return (type === this.Document) || (type === this.Stylesheet) || (type === this.Script) || (type === this.XHR); + }, + + toString: function(type) + { + switch (type) { + case this.Document: + return WebInspector.UIString("document"); + case this.Stylesheet: + return WebInspector.UIString("stylesheet"); + case this.Image: + return WebInspector.UIString("image"); + case this.Font: + return WebInspector.UIString("font"); + case this.Script: + return WebInspector.UIString("script"); + case this.XHR: + return WebInspector.UIString("XHR"); + case this.Other: + default: + return WebInspector.UIString("other"); + } + } +} + +WebInspector.Resource.prototype = { + get url() + { + return this._url; + }, + + set url(x) + { + if (this._url === x) + return; + + var oldURL = this._url; + this._url = x; + + // FIXME: We should make the WebInspector object listen for the "url changed" event. + // Then resourceURLChanged can be removed. + WebInspector.resourceURLChanged(this, oldURL); + + this.dispatchEventToListeners("url changed"); + }, + + get domain() + { + return this._domain; + }, + + set domain(x) + { + if (this._domain === x) + return; + this._domain = x; + }, + + get lastPathComponent() + { + return this._lastPathComponent; + }, + + set lastPathComponent(x) + { + if (this._lastPathComponent === x) + return; + this._lastPathComponent = x; + this._lastPathComponentLowerCase = x ? x.toLowerCase() : null; + }, + + get displayName() + { + var title = this.lastPathComponent; + if (!title) + title = this.displayDomain; + if (!title && this.url) + title = this.url.trimURL(WebInspector.mainResource ? WebInspector.mainResource.domain : ""); + if (title === "/") + title = this.url; + return title; + }, + + get displayDomain() + { + // WebInspector.Database calls this, so don't access more than this.domain. + if (this.domain && (!WebInspector.mainResource || (WebInspector.mainResource && this.domain !== WebInspector.mainResource.domain))) + return this.domain; + return ""; + }, + + get startTime() + { + return this._startTime || -1; + }, + + set startTime(x) + { + if (this._startTime === x) + return; + + this._startTime = x; + + if (WebInspector.panels.resources) + WebInspector.panels.resources.refreshResource(this); + }, + + get responseReceivedTime() + { + return this._responseReceivedTime || -1; + }, + + set responseReceivedTime(x) + { + if (this._responseReceivedTime === x) + return; + + this._responseReceivedTime = x; + + if (WebInspector.panels.resources) + WebInspector.panels.resources.refreshResource(this); + }, + + get endTime() + { + return this._endTime || -1; + }, + + set endTime(x) + { + if (this._endTime === x) + return; + + this._endTime = x; + + if (WebInspector.panels.resources) + WebInspector.panels.resources.refreshResource(this); + }, + + get duration() + { + if (this._endTime === -1 || this._startTime === -1) + return -1; + return this._endTime - this._startTime; + }, + + get latency() + { + if (this._responseReceivedTime === -1 || this._startTime === -1) + return -1; + return this._responseReceivedTime - this._startTime; + }, + + get contentLength() + { + return this._contentLength || 0; + }, + + set contentLength(x) + { + if (this._contentLength === x) + return; + + this._contentLength = x; + + if (WebInspector.panels.resources) + WebInspector.panels.resources.refreshResource(this); + }, + + get expectedContentLength() + { + return this._expectedContentLength || 0; + }, + + set expectedContentLength(x) + { + if (this._expectedContentLength === x) + return; + this._expectedContentLength = x; + }, + + get finished() + { + return this._finished; + }, + + set finished(x) + { + if (this._finished === x) + return; + + this._finished = x; + + if (x) { + this._checkTips(); + this._checkWarnings(); + this.dispatchEventToListeners("finished"); + } + }, + + get failed() + { + return this._failed; + }, + + set failed(x) + { + this._failed = x; + }, + + get category() + { + return this._category; + }, + + set category(x) + { + if (this._category === x) + return; + + var oldCategory = this._category; + if (oldCategory) + oldCategory.removeResource(this); + + this._category = x; + + if (this._category) + this._category.addResource(this); + + if (WebInspector.panels.resources) { + WebInspector.panels.resources.refreshResource(this); + WebInspector.panels.resources.recreateViewForResourceIfNeeded(this); + } + }, + + get mimeType() + { + return this._mimeType; + }, + + set mimeType(x) + { + if (this._mimeType === x) + return; + + this._mimeType = x; + }, + + get type() + { + return this._type; + }, + + set type(x) + { + if (this._type === x) + return; + + this._type = x; + + switch (x) { + case WebInspector.Resource.Type.Document: + this.category = WebInspector.resourceCategories.documents; + break; + case WebInspector.Resource.Type.Stylesheet: + this.category = WebInspector.resourceCategories.stylesheets; + break; + case WebInspector.Resource.Type.Script: + this.category = WebInspector.resourceCategories.scripts; + break; + case WebInspector.Resource.Type.Image: + this.category = WebInspector.resourceCategories.images; + break; + case WebInspector.Resource.Type.Font: + this.category = WebInspector.resourceCategories.fonts; + break; + case WebInspector.Resource.Type.XHR: + this.category = WebInspector.resourceCategories.xhr; + break; + case WebInspector.Resource.Type.Other: + default: + this.category = WebInspector.resourceCategories.other; + break; + } + }, + + get documentNode() { + if ("identifier" in this) + return InspectorController.getResourceDocumentNode(this.identifier); + return null; + }, + + get requestHeaders() + { + if (this._requestHeaders === undefined) + this._requestHeaders = {}; + return this._requestHeaders; + }, + + set requestHeaders(x) + { + if (this._requestHeaders === x) + return; + + this._requestHeaders = x; + delete this._sortedRequestHeaders; + + this.dispatchEventToListeners("requestHeaders changed"); + }, + + get sortedRequestHeaders() + { + if (this._sortedRequestHeaders !== undefined) + return this._sortedRequestHeaders; + + this._sortedRequestHeaders = []; + for (var key in this.requestHeaders) + this._sortedRequestHeaders.push({header: key, value: this.requestHeaders[key]}); + this._sortedRequestHeaders.sort(function(a,b) { return a.header.localeCompare(b.header) }); + + return this._sortedRequestHeaders; + }, + + get responseHeaders() + { + if (this._responseHeaders === undefined) + this._responseHeaders = {}; + return this._responseHeaders; + }, + + set responseHeaders(x) + { + if (this._responseHeaders === x) + return; + + this._responseHeaders = x; + delete this._sortedResponseHeaders; + + this.dispatchEventToListeners("responseHeaders changed"); + }, + + get sortedResponseHeaders() + { + if (this._sortedResponseHeaders !== undefined) + return this._sortedResponseHeaders; + + this._sortedResponseHeaders = []; + for (var key in this.responseHeaders) + this._sortedResponseHeaders.push({header: key, value: this.responseHeaders[key]}); + this._sortedResponseHeaders.sort(function(a,b) { return a.header.localeCompare(b.header) }); + + return this._sortedResponseHeaders; + }, + + get scripts() + { + if (!("_scripts" in this)) + this._scripts = []; + return this._scripts; + }, + + addScript: function(script) + { + if (!script) + return; + this.scripts.unshift(script); + script.resource = this; + }, + + removeAllScripts: function() + { + if (!this._scripts) + return; + + for (var i = 0; i < this._scripts.length; ++i) { + if (this._scripts[i].resource === this) + delete this._scripts[i].resource; + } + + delete this._scripts; + }, + + removeScript: function(script) + { + if (!script) + return; + + if (script.resource === this) + delete script.resource; + + if (!this._scripts) + return; + + this._scripts.remove(script); + }, + + get errors() + { + return this._errors || 0; + }, + + set errors(x) + { + this._errors = x; + }, + + get warnings() + { + return this._warnings || 0; + }, + + set warnings(x) + { + this._warnings = x; + }, + + get tips() + { + if (!("_tips" in this)) + this._tips = {}; + return this._tips; + }, + + _addTip: function(tip) + { + if (tip.id in this.tips) + return; + + this.tips[tip.id] = tip; + + // FIXME: Re-enable this code once we have a scope bar in the Console. + // Otherwise, we flood the Console with too many tips. + /* + var msg = new WebInspector.ConsoleMessage(WebInspector.ConsoleMessage.MessageSource.Other, + WebInspector.ConsoleMessage.MessageLevel.Tip, -1, this.url, null, 1, tip.message); + WebInspector.console.addMessage(msg); + */ + }, + + _checkTips: function() + { + for (var tip in WebInspector.Tips) + this._checkTip(WebInspector.Tips[tip]); + }, + + _checkTip: function(tip) + { + var addTip = false; + switch (tip.id) { + case WebInspector.Tips.ResourceNotCompressed.id: + addTip = this._shouldCompress(); + break; + } + + if (addTip) + this._addTip(tip); + }, + + _shouldCompress: function() + { + return WebInspector.Resource.Type.isTextType(this.type) + && this.domain + && !("Content-Encoding" in this.responseHeaders) + && this.contentLength !== undefined + && this.contentLength >= 512; + }, + + _mimeTypeIsConsistentWithType: function() + { + if (typeof this.type === "undefined" + || this.type === WebInspector.Resource.Type.Other + || this.type === WebInspector.Resource.Type.XHR) + return true; + + if (this.mimeType in WebInspector.MIMETypes) + return this.type in WebInspector.MIMETypes[this.mimeType]; + + return true; + }, + + _checkWarnings: function() + { + for (var warning in WebInspector.Warnings) + this._checkWarning(WebInspector.Warnings[warning]); + }, + + _checkWarning: function(warning) + { + var addWarning = false; + var msg; + switch (warning.id) { + case WebInspector.Warnings.IncorrectMIMEType.id: + if (!this._mimeTypeIsConsistentWithType()) + msg = new WebInspector.ConsoleMessage(WebInspector.ConsoleMessage.MessageSource.Other, + WebInspector.ConsoleMessage.MessageLevel.Warning, -1, this.url, null, 1, + String.sprintf(WebInspector.Warnings.IncorrectMIMEType.message, + WebInspector.Resource.Type.toString(this.type), this.mimeType)); + break; + } + + if (msg) + WebInspector.console.addMessage(msg); + } +} + +WebInspector.Resource.prototype.__proto__ = WebInspector.Object.prototype; + +WebInspector.Resource.CompareByStartTime = function(a, b) +{ + if (a.startTime < b.startTime) + return -1; + if (a.startTime > b.startTime) + return 1; + return 0; +} + +WebInspector.Resource.CompareByResponseReceivedTime = function(a, b) +{ + if (a.responseReceivedTime === -1 && b.responseReceivedTime !== -1) + return 1; + if (a.responseReceivedTime !== -1 && b.responseReceivedTime === -1) + return -1; + if (a.responseReceivedTime < b.responseReceivedTime) + return -1; + if (a.responseReceivedTime > b.responseReceivedTime) + return 1; + return 0; +} + +WebInspector.Resource.CompareByEndTime = function(a, b) +{ + if (a.endTime === -1 && b.endTime !== -1) + return 1; + if (a.endTime !== -1 && b.endTime === -1) + return -1; + if (a.endTime < b.endTime) + return -1; + if (a.endTime > b.endTime) + return 1; + return 0; +} + +WebInspector.Resource.CompareByDuration = function(a, b) +{ + if (a.duration < b.duration) + return -1; + if (a.duration > b.duration) + return 1; + return 0; +} + +WebInspector.Resource.CompareByLatency = function(a, b) +{ + if (a.latency < b.latency) + return -1; + if (a.latency > b.latency) + return 1; + return 0; +} + +WebInspector.Resource.CompareBySize = function(a, b) +{ + if (a.contentLength < b.contentLength) + return -1; + if (a.contentLength > b.contentLength) + return 1; + return 0; +} diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ResourceCategory.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ResourceCategory.js new file mode 100644 index 0000000..fc508d0 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ResourceCategory.js @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2007, 2008 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. + * 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. + */ + +WebInspector.ResourceCategory = function(title, name) +{ + this.name = name; + this.title = title; + this.resources = []; +} + +WebInspector.ResourceCategory.prototype = { + toString: function() + { + return this.title; + }, + + addResource: function(resource) + { + var a = resource; + var resourcesLength = this.resources.length; + for (var i = 0; i < resourcesLength; ++i) { + var b = this.resources[i]; + if (a._lastPathComponentLowerCase && b._lastPathComponentLowerCase) + if (a._lastPathComponentLowerCase < b._lastPathComponentLowerCase) + break; + else if (a.name && b.name) + if (a.name < b.name) + break; + } + + this.resources.splice(i, 0, resource); + }, + + removeResource: function(resource) + { + this.resources.remove(resource, true); + }, + + removeAllResources: function(resource) + { + this.resources = []; + } +} diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ResourceView.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ResourceView.js new file mode 100644 index 0000000..b480362 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ResourceView.js @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2007, 2008 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. + * 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. + */ + +WebInspector.ResourceView = function(resource) +{ + WebInspector.View.call(this); + + this.element.addStyleClass("resource-view"); + + this.resource = resource; + + this.headersElement = document.createElement("div"); + this.headersElement.className = "resource-view-headers"; + this.element.appendChild(this.headersElement); + + this.contentElement = document.createElement("div"); + this.contentElement.className = "resource-view-content"; + this.element.appendChild(this.contentElement); + + this.headersListElement = document.createElement("ol"); + this.headersListElement.className = "outline-disclosure"; + this.headersElement.appendChild(this.headersListElement); + + this.headersTreeOutline = new TreeOutline(this.headersListElement); + this.headersTreeOutline.expandTreeElementsWhenArrowing = true; + + this.urlTreeElement = new TreeElement("", null, false); + this.urlTreeElement.selectable = false; + this.headersTreeOutline.appendChild(this.urlTreeElement); + + this.requestHeadersTreeElement = new TreeElement("", null, true); + this.requestHeadersTreeElement.expanded = false; + this.requestHeadersTreeElement.selectable = false; + this.headersTreeOutline.appendChild(this.requestHeadersTreeElement); + + this.responseHeadersTreeElement = new TreeElement("", null, true); + this.responseHeadersTreeElement.expanded = false; + this.responseHeadersTreeElement.selectable = false; + this.headersTreeOutline.appendChild(this.responseHeadersTreeElement); + + this.headersVisible = true; + + resource.addEventListener("url changed", this._refreshURL, this); + resource.addEventListener("requestHeaders changed", this._refreshRequestHeaders, this); + resource.addEventListener("responseHeaders changed", this._refreshResponseHeaders, this); + + this._refreshURL(); + this._refreshRequestHeaders(); + this._refreshResponseHeaders(); +} + +WebInspector.ResourceView.prototype = { + get headersVisible() + { + return this._headersVisible; + }, + + set headersVisible(x) + { + if (x === this._headersVisible) + return; + + this._headersVisible = x; + + if (x) + this.element.addStyleClass("headers-visible"); + else + this.element.removeStyleClass("headers-visible"); + }, + + attach: function() + { + if (!this.element.parentNode) { + var parentElement = (document.getElementById("resource-views") || document.getElementById("script-resource-views")); + if (parentElement) + parentElement.appendChild(this.element); + } + }, + + _refreshURL: function() + { + this.urlTreeElement.title = this.resource.url.escapeHTML(); + }, + + _refreshRequestHeaders: function() + { + this._refreshHeaders(WebInspector.UIString("Request Headers"), this.resource.sortedRequestHeaders, this.requestHeadersTreeElement); + }, + + _refreshResponseHeaders: function() + { + this._refreshHeaders(WebInspector.UIString("Response Headers"), this.resource.sortedResponseHeaders, this.responseHeadersTreeElement); + }, + + _refreshHeaders: function(title, headers, headersTreeElement) + { + headersTreeElement.removeChildren(); + + var length = headers.length; + headersTreeElement.title = title.escapeHTML() + "<span class=\"header-count\">" + WebInspector.UIString(" (%d)", length) + "</span>"; + headersTreeElement.hidden = !length; + + var length = headers.length; + for (var i = 0; i < length; ++i) { + var title = "<div class=\"header-name\">" + headers[i].header.escapeHTML() + ":</div>"; + title += "<div class=\"header-value\">" + headers[i].value.escapeHTML() + "</div>" + + var headerTreeElement = new TreeElement(title, null, false); + headerTreeElement.selectable = false; + headersTreeElement.appendChild(headerTreeElement); + } + } +} + +WebInspector.ResourceView.prototype.__proto__ = WebInspector.View.prototype; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ResourcesPanel.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ResourcesPanel.js new file mode 100644 index 0000000..e02baf3 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ResourcesPanel.js @@ -0,0 +1,1649 @@ +/* + * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008 Anthony Ricaud (rik24d@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. + */ + +WebInspector.ResourcesPanel = function() +{ + WebInspector.Panel.call(this); + + this.element.addStyleClass("resources"); + + this.viewsContainerElement = document.createElement("div"); + this.viewsContainerElement.id = "resource-views"; + this.element.appendChild(this.viewsContainerElement); + + this.containerElement = document.createElement("div"); + this.containerElement.id = "resources-container"; + this.containerElement.addEventListener("scroll", this._updateDividersLabelBarPosition.bind(this), false); + this.element.appendChild(this.containerElement); + + this.sidebarElement = document.createElement("div"); + this.sidebarElement.id = "resources-sidebar"; + this.sidebarElement.className = "sidebar"; + this.containerElement.appendChild(this.sidebarElement); + + this.sidebarResizeElement = document.createElement("div"); + this.sidebarResizeElement.className = "sidebar-resizer-vertical"; + this.sidebarResizeElement.addEventListener("mousedown", this._startSidebarDragging.bind(this), false); + this.element.appendChild(this.sidebarResizeElement); + + this.containerContentElement = document.createElement("div"); + this.containerContentElement.id = "resources-container-content"; + this.containerElement.appendChild(this.containerContentElement); + + this.summaryElement = document.createElement("div"); + this.summaryElement.id = "resources-summary"; + this.containerContentElement.appendChild(this.summaryElement); + + this.resourcesGraphsElement = document.createElement("div"); + this.resourcesGraphsElement.id = "resources-graphs"; + this.containerContentElement.appendChild(this.resourcesGraphsElement); + + this.dividersElement = document.createElement("div"); + this.dividersElement.id = "resources-dividers"; + this.containerContentElement.appendChild(this.dividersElement); + + this.dividersLabelBarElement = document.createElement("div"); + this.dividersLabelBarElement.id = "resources-dividers-label-bar"; + this.containerContentElement.appendChild(this.dividersLabelBarElement); + + this.summaryGraphElement = document.createElement("canvas"); + this.summaryGraphElement.setAttribute("width", "450"); + this.summaryGraphElement.setAttribute("height", "38"); + this.summaryGraphElement.id = "resources-summary-graph"; + this.summaryElement.appendChild(this.summaryGraphElement); + + this.legendElement = document.createElement("div"); + this.legendElement.id = "resources-graph-legend"; + this.summaryElement.appendChild(this.legendElement); + + this.sidebarTreeElement = document.createElement("ol"); + this.sidebarTreeElement.className = "sidebar-tree"; + this.sidebarElement.appendChild(this.sidebarTreeElement); + + this.sidebarTree = new TreeOutline(this.sidebarTreeElement); + + var timeGraphItem = new WebInspector.SidebarTreeElement("resources-time-graph-sidebar-item", WebInspector.UIString("Time")); + timeGraphItem.onselect = this._graphSelected.bind(this); + + var transferTimeCalculator = new WebInspector.ResourceTransferTimeCalculator(); + var transferDurationCalculator = new WebInspector.ResourceTransferDurationCalculator(); + + timeGraphItem.sortingOptions = [ + { name: WebInspector.UIString("Sort by Start Time"), sortingFunction: WebInspector.ResourceSidebarTreeElement.CompareByAscendingStartTime, calculator: transferTimeCalculator }, + { name: WebInspector.UIString("Sort by Response Time"), sortingFunction: WebInspector.ResourceSidebarTreeElement.CompareByAscendingResponseReceivedTime, calculator: transferTimeCalculator }, + { name: WebInspector.UIString("Sort by End Time"), sortingFunction: WebInspector.ResourceSidebarTreeElement.CompareByAscendingEndTime, calculator: transferTimeCalculator }, + { name: WebInspector.UIString("Sort by Duration"), sortingFunction: WebInspector.ResourceSidebarTreeElement.CompareByDescendingDuration, calculator: transferDurationCalculator }, + { name: WebInspector.UIString("Sort by Latency"), sortingFunction: WebInspector.ResourceSidebarTreeElement.CompareByDescendingLatency, calculator: transferDurationCalculator }, + ]; + + timeGraphItem.selectedSortingOptionIndex = 1; + + var sizeGraphItem = new WebInspector.SidebarTreeElement("resources-size-graph-sidebar-item", WebInspector.UIString("Size")); + sizeGraphItem.onselect = this._graphSelected.bind(this); + + var transferSizeCalculator = new WebInspector.ResourceTransferSizeCalculator(); + sizeGraphItem.sortingOptions = [ + { name: WebInspector.UIString("Sort by Size"), sortingFunction: WebInspector.ResourceSidebarTreeElement.CompareByDescendingSize, calculator: transferSizeCalculator }, + ]; + + sizeGraphItem.selectedSortingOptionIndex = 0; + + this.graphsTreeElement = new WebInspector.SidebarSectionTreeElement(WebInspector.UIString("GRAPHS"), {}, true); + this.sidebarTree.appendChild(this.graphsTreeElement); + + this.graphsTreeElement.appendChild(timeGraphItem); + this.graphsTreeElement.appendChild(sizeGraphItem); + this.graphsTreeElement.expand(); + + this.resourcesTreeElement = new WebInspector.SidebarSectionTreeElement(WebInspector.UIString("RESOURCES"), {}, true); + this.sidebarTree.appendChild(this.resourcesTreeElement); + + this.resourcesTreeElement.expand(); + + this.largerResourcesButton = document.createElement("button"); + this.largerResourcesButton.id = "resources-larger-resources-status-bar-item"; + this.largerResourcesButton.className = "status-bar-item toggled-on"; + this.largerResourcesButton.title = WebInspector.UIString("Use small resource rows."); + this.largerResourcesButton.addEventListener("click", this._toggleLargerResources.bind(this), false); + + this.sortingSelectElement = document.createElement("select"); + this.sortingSelectElement.className = "status-bar-item"; + this.sortingSelectElement.addEventListener("change", this._changeSortingFunction.bind(this), false); + + this.reset(); + + timeGraphItem.select(); +} + +WebInspector.ResourcesPanel.prototype = { + toolbarItemClass: "resources", + + get toolbarItemLabel() + { + return WebInspector.UIString("Resources"); + }, + + get statusBarItems() + { + return [this.largerResourcesButton, this.sortingSelectElement]; + }, + + show: function() + { + WebInspector.Panel.prototype.show.call(this); + + this._updateDividersLabelBarPosition(); + this._updateSidebarWidth(); + this.refreshIfNeeded(); + + var visibleView = this.visibleView; + if (visibleView) { + visibleView.headersVisible = true; + visibleView.show(this.viewsContainerElement); + } + + // Hide any views that are visible that are not this panel's current visible view. + // This can happen when a ResourceView is visible in the Scripts panel then switched + // to the this panel. + var resourcesLength = this._resources.length; + for (var i = 0; i < resourcesLength; ++i) { + var resource = this._resources[i]; + var view = resource._resourcesView; + if (!view || view === visibleView) + continue; + view.visible = false; + } + }, + + resize: function() + { + this._updateGraphDividersIfNeeded(); + + var visibleView = this.visibleView; + if (visibleView && "resize" in visibleView) + visibleView.resize(); + }, + + get searchableViews() + { + var views = []; + + const visibleView = this.visibleView; + if (visibleView && visibleView.performSearch) + views.push(visibleView); + + var resourcesLength = this._resources.length; + for (var i = 0; i < resourcesLength; ++i) { + var resource = this._resources[i]; + if (!resource._resourcesTreeElement) + continue; + var resourceView = this.resourceViewForResource(resource); + if (!resourceView.performSearch || resourceView === visibleView) + continue; + views.push(resourceView); + } + + return views; + }, + + get searchResultsSortFunction() + { + const resourceTreeElementSortFunction = this.sortingFunction; + + function sortFuction(a, b) + { + return resourceTreeElementSortFunction(a.resource._resourcesTreeElement, b.resource._resourcesTreeElement); + } + + return sortFuction; + }, + + searchMatchFound: function(view, matches) + { + view.resource._resourcesTreeElement.searchMatches = matches; + }, + + searchCanceled: function(startingNewSearch) + { + WebInspector.Panel.prototype.searchCanceled.call(this, startingNewSearch); + + if (startingNewSearch || !this._resources) + return; + + for (var i = 0; i < this._resources.length; ++i) { + var resource = this._resources[i]; + if (resource._resourcesTreeElement) + resource._resourcesTreeElement.updateErrorsAndWarnings(); + } + }, + + performSearch: function(query) + { + for (var i = 0; i < this._resources.length; ++i) { + var resource = this._resources[i]; + if (resource._resourcesTreeElement) + resource._resourcesTreeElement.resetBubble(); + } + + WebInspector.Panel.prototype.performSearch.call(this, query); + }, + + get visibleView() + { + if (this.visibleResource) + return this.visibleResource._resourcesView; + return null; + }, + + get calculator() + { + return this._calculator; + }, + + set calculator(x) + { + if (!x || this._calculator === x) + return; + + this._calculator = x; + this._calculator.reset(); + + this._staleResources = this._resources; + this.refresh(); + }, + + get sortingFunction() + { + return this._sortingFunction; + }, + + set sortingFunction(x) + { + this._sortingFunction = x; + this._sortResourcesIfNeeded(); + }, + + get needsRefresh() + { + return this._needsRefresh; + }, + + set needsRefresh(x) + { + if (this._needsRefresh === x) + return; + + this._needsRefresh = x; + + if (x) { + if (this.visible && !("_refreshTimeout" in this)) + this._refreshTimeout = setTimeout(this.refresh.bind(this), 500); + } else { + if ("_refreshTimeout" in this) { + clearTimeout(this._refreshTimeout); + delete this._refreshTimeout; + } + } + }, + + refreshIfNeeded: function() + { + if (this.needsRefresh) + this.refresh(); + }, + + refresh: function() + { + this.needsRefresh = false; + + var staleResourcesLength = this._staleResources.length; + var boundariesChanged = false; + + for (var i = 0; i < staleResourcesLength; ++i) { + var resource = this._staleResources[i]; + if (!resource._resourcesTreeElement) { + // Create the resource tree element and graph. + resource._resourcesTreeElement = new WebInspector.ResourceSidebarTreeElement(resource); + resource._resourcesTreeElement._resourceGraph = new WebInspector.ResourceGraph(resource); + + this.resourcesTreeElement.appendChild(resource._resourcesTreeElement); + this.resourcesGraphsElement.appendChild(resource._resourcesTreeElement._resourceGraph.graphElement); + } + + resource._resourcesTreeElement.refresh(); + + if (this.calculator.updateBoundaries(resource)) + boundariesChanged = true; + } + + if (boundariesChanged) { + // The boundaries changed, so all resource graphs are stale. + this._staleResources = this._resources; + staleResourcesLength = this._staleResources.length; + } + + for (var i = 0; i < staleResourcesLength; ++i) + this._staleResources[i]._resourcesTreeElement._resourceGraph.refresh(this.calculator); + + this._staleResources = []; + + this._updateGraphDividersIfNeeded(); + this._sortResourcesIfNeeded(); + this._updateSummaryGraph(); + }, + + reset: function() + { + this.closeVisibleResource(); + + this.containerElement.scrollTop = 0; + + delete this.currentQuery; + this.searchCanceled(); + + if (this._calculator) + this._calculator.reset(); + + if (this._resources) { + var resourcesLength = this._resources.length; + for (var i = 0; i < resourcesLength; ++i) { + var resource = this._resources[i]; + + resource.warnings = 0; + resource.errors = 0; + + delete resource._resourcesTreeElement; + delete resource._resourcesView; + } + } + + this._resources = []; + this._staleResources = []; + + this.resourcesTreeElement.removeChildren(); + this.viewsContainerElement.removeChildren(); + this.resourcesGraphsElement.removeChildren(); + this.legendElement.removeChildren(); + + this._updateGraphDividersIfNeeded(true); + + this._drawSummaryGraph(); // draws an empty graph + }, + + addResource: function(resource) + { + this._resources.push(resource); + this.refreshResource(resource); + }, + + removeResource: function(resource) + { + if (this.visibleView === resource._resourcesView) + this.closeVisibleResource(); + + this._resources.remove(resource, true); + + if (resource._resourcesTreeElement) { + this.resourcesTreeElement.removeChild(resource._resourcesTreeElement); + this.resourcesGraphsElement.removeChild(resource._resourcesTreeElement._resourceGraph.graphElement); + } + + resource.warnings = 0; + resource.errors = 0; + + delete resource._resourcesTreeElement; + delete resource._resourcesView; + + this._adjustScrollPosition(); + }, + + addMessageToResource: function(resource, msg) + { + if (!resource) + return; + + switch (msg.level) { + case WebInspector.ConsoleMessage.MessageLevel.Warning: + resource.warnings += msg.repeatDelta; + break; + case WebInspector.ConsoleMessage.MessageLevel.Error: + resource.errors += msg.repeatDelta; + break; + } + + if (!this.currentQuery && resource._resourcesTreeElement) + resource._resourcesTreeElement.updateErrorsAndWarnings(); + + var view = this.resourceViewForResource(resource); + if (view.addMessage) + view.addMessage(msg); + }, + + clearMessages: function() + { + var resourcesLength = this._resources.length; + for (var i = 0; i < resourcesLength; ++i) { + var resource = this._resources[i]; + resource.warnings = 0; + resource.errors = 0; + + if (!this.currentQuery && resource._resourcesTreeElement) + resource._resourcesTreeElement.updateErrorsAndWarnings(); + + var view = resource._resourcesView; + if (!view || !view.clearMessages) + continue; + view.clearMessages(); + } + }, + + refreshResource: function(resource) + { + this._staleResources.push(resource); + this.needsRefresh = true; + }, + + recreateViewForResourceIfNeeded: function(resource) + { + if (!resource || !resource._resourcesView) + return; + + var newView = this._createResourceView(resource); + if (newView.prototype === resource._resourcesView.prototype) + return; + + resource.warnings = 0; + resource.errors = 0; + + if (!this.currentQuery && resource._resourcesTreeElement) + resource._resourcesTreeElement.updateErrorsAndWarnings(); + + var oldView = resource._resourcesView; + + resource._resourcesView.detach(); + delete resource._resourcesView; + + resource._resourcesView = newView; + + newView.headersVisible = oldView.headersVisible; + + if (oldView.visible && oldView.element.parentNode) + newView.show(oldView.element.parentNode); + }, + + showResource: function(resource, line) + { + if (!resource) + return; + + this.containerElement.addStyleClass("viewing-resource"); + + if (this.visibleResource && this.visibleResource._resourcesView) + this.visibleResource._resourcesView.hide(); + + var view = this.resourceViewForResource(resource); + view.headersVisible = true; + view.show(this.viewsContainerElement); + + if (line) { + if (view.revealLine) + view.revealLine(line); + if (view.highlightLine) + view.highlightLine(line); + } + + if (resource._resourcesTreeElement) { + resource._resourcesTreeElement.reveal(); + resource._resourcesTreeElement.select(true); + } + + this.visibleResource = resource; + + this._updateSidebarWidth(); + }, + + showView: function(view) + { + if (!view) + return; + this.showResource(view.resource); + }, + + closeVisibleResource: function() + { + this.containerElement.removeStyleClass("viewing-resource"); + this._updateDividersLabelBarPosition(); + + if (this.visibleResource && this.visibleResource._resourcesView) + this.visibleResource._resourcesView.hide(); + delete this.visibleResource; + + if (this._lastSelectedGraphTreeElement) + this._lastSelectedGraphTreeElement.select(true); + + this._updateSidebarWidth(); + }, + + resourceViewForResource: function(resource) + { + if (!resource) + return null; + if (!resource._resourcesView) + resource._resourcesView = this._createResourceView(resource); + return resource._resourcesView; + }, + + sourceFrameForResource: function(resource) + { + var view = this.resourceViewForResource(resource); + if (!view) + return null; + + if (!view.setupSourceFrameIfNeeded) + return null; + + // Setting up the source frame requires that we be attached. + if (!this.element.parentNode) + this.attach(); + + view.setupSourceFrameIfNeeded(); + return view.sourceFrame; + }, + + handleKeyEvent: function(event) + { + this.sidebarTree.handleKeyEvent(event); + }, + + _makeLegendElement: function(label, value, color) + { + var legendElement = document.createElement("label"); + legendElement.className = "resources-graph-legend-item"; + + if (color) { + var swatch = document.createElement("canvas"); + swatch.className = "resources-graph-legend-swatch"; + swatch.setAttribute("width", "13"); + swatch.setAttribute("height", "24"); + + legendElement.appendChild(swatch); + + this._drawSwatch(swatch, color); + } + + var labelElement = document.createElement("div"); + labelElement.className = "resources-graph-legend-label"; + legendElement.appendChild(labelElement); + + var headerElement = document.createElement("div"); + var headerElement = document.createElement("div"); + headerElement.className = "resources-graph-legend-header"; + headerElement.textContent = label; + labelElement.appendChild(headerElement); + + var valueElement = document.createElement("div"); + valueElement.className = "resources-graph-legend-value"; + valueElement.textContent = value; + labelElement.appendChild(valueElement); + + return legendElement; + }, + + _sortResourcesIfNeeded: function() + { + var sortedElements = [].concat(this.resourcesTreeElement.children); + sortedElements.sort(this.sortingFunction); + + var sortedElementsLength = sortedElements.length; + for (var i = 0; i < sortedElementsLength; ++i) { + var treeElement = sortedElements[i]; + if (treeElement === this.resourcesTreeElement.children[i]) + continue; + + var wasSelected = treeElement.selected; + this.resourcesTreeElement.removeChild(treeElement); + this.resourcesTreeElement.insertChild(treeElement, i); + if (wasSelected) + treeElement.select(true); + + var graphElement = treeElement._resourceGraph.graphElement; + this.resourcesGraphsElement.insertBefore(graphElement, this.resourcesGraphsElement.children[i]); + } + }, + + _updateGraphDividersIfNeeded: function(force) + { + if (!this.visible) { + this.needsRefresh = true; + return; + } + + if (document.body.offsetWidth <= 0) { + // The stylesheet hasn't loaded yet or the window is closed, + // so we can't calculate what is need. Return early. + return; + } + + var dividerCount = Math.round(this.dividersElement.offsetWidth / 64); + var slice = this.calculator.boundarySpan / dividerCount; + if (!force && this._currentDividerSlice === slice) + return; + + this._currentDividerSlice = slice; + + this.dividersElement.removeChildren(); + this.dividersLabelBarElement.removeChildren(); + + for (var i = 1; i <= dividerCount; ++i) { + var divider = document.createElement("div"); + divider.className = "resources-divider"; + if (i === dividerCount) + divider.addStyleClass("last"); + divider.style.left = ((i / dividerCount) * 100) + "%"; + + this.dividersElement.appendChild(divider.cloneNode()); + + var label = document.createElement("div"); + label.className = "resources-divider-label"; + if (!isNaN(slice)) + label.textContent = this.calculator.formatValue(slice * i); + divider.appendChild(label); + + this.dividersLabelBarElement.appendChild(divider); + } + }, + + _fadeOutRect: function(ctx, x, y, w, h, a1, a2) + { + ctx.save(); + + var gradient = ctx.createLinearGradient(x, y, x, y + h); + gradient.addColorStop(0.0, "rgba(0, 0, 0, " + (1.0 - a1) + ")"); + gradient.addColorStop(0.8, "rgba(0, 0, 0, " + (1.0 - a2) + ")"); + gradient.addColorStop(1.0, "rgba(0, 0, 0, 1.0)"); + + ctx.globalCompositeOperation = "destination-out"; + + ctx.fillStyle = gradient; + ctx.fillRect(x, y, w, h); + + ctx.restore(); + }, + + _drawSwatch: function(canvas, color) + { + var ctx = canvas.getContext("2d"); + + function drawSwatchSquare() { + ctx.fillStyle = color; + ctx.fillRect(0, 0, 13, 13); + + var gradient = ctx.createLinearGradient(0, 0, 13, 13); + gradient.addColorStop(0.0, "rgba(255, 255, 255, 0.2)"); + gradient.addColorStop(1.0, "rgba(255, 255, 255, 0.0)"); + + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 13, 13); + + gradient = ctx.createLinearGradient(13, 13, 0, 0); + gradient.addColorStop(0.0, "rgba(0, 0, 0, 0.2)"); + gradient.addColorStop(1.0, "rgba(0, 0, 0, 0.0)"); + + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 13, 13); + + ctx.strokeStyle = "rgba(0, 0, 0, 0.6)"; + ctx.strokeRect(0.5, 0.5, 12, 12); + } + + ctx.clearRect(0, 0, 13, 24); + + drawSwatchSquare(); + + ctx.save(); + + ctx.translate(0, 25); + ctx.scale(1, -1); + + drawSwatchSquare(); + + ctx.restore(); + + this._fadeOutRect(ctx, 0, 13, 13, 13, 0.5, 0.0); + }, + + _drawSummaryGraph: function(segments) + { + if (!this.summaryGraphElement) + return; + + if (!segments || !segments.length) { + segments = [{color: "white", value: 1}]; + this._showingEmptySummaryGraph = true; + } else + delete this._showingEmptySummaryGraph; + + // Calculate the total of all segments. + var total = 0; + for (var i = 0; i < segments.length; ++i) + total += segments[i].value; + + // Calculate the percentage of each segment, rounded to the nearest percent. + var percents = segments.map(function(s) { return Math.max(Math.round(100 * s.value / total), 1) }); + + // Calculate the total percentage. + var percentTotal = 0; + for (var i = 0; i < percents.length; ++i) + percentTotal += percents[i]; + + // Make sure our percentage total is not greater-than 100, it can be greater + // if we rounded up for a few segments. + while (percentTotal > 100) { + for (var i = 0; i < percents.length && percentTotal > 100; ++i) { + if (percents[i] > 1) { + --percents[i]; + --percentTotal; + } + } + } + + // Make sure our percentage total is not less-than 100, it can be less + // if we rounded down for a few segments. + while (percentTotal < 100) { + for (var i = 0; i < percents.length && percentTotal < 100; ++i) { + ++percents[i]; + ++percentTotal; + } + } + + var ctx = this.summaryGraphElement.getContext("2d"); + + var x = 0; + var y = 0; + var w = 450; + var h = 19; + var r = (h / 2); + + function drawPillShadow() + { + // This draws a line with a shadow that is offset away from the line. The line is stroked + // twice with different X shadow offsets to give more feathered edges. Later we erase the + // line with destination-out 100% transparent black, leaving only the shadow. This only + // works if nothing has been drawn into the canvas yet. + + ctx.beginPath(); + ctx.moveTo(x + 4, y + h - 3 - 0.5); + ctx.lineTo(x + w - 4, y + h - 3 - 0.5); + ctx.closePath(); + + ctx.save(); + + ctx.shadowBlur = 2; + ctx.shadowColor = "rgba(0, 0, 0, 0.5)"; + ctx.shadowOffsetX = 3; + ctx.shadowOffsetY = 5; + + ctx.strokeStyle = "white"; + ctx.lineWidth = 1; + + ctx.stroke(); + + ctx.shadowOffsetX = -3; + + ctx.stroke(); + + ctx.restore(); + + ctx.save(); + + ctx.globalCompositeOperation = "destination-out"; + ctx.strokeStyle = "rgba(0, 0, 0, 1)"; + ctx.lineWidth = 1; + + ctx.stroke(); + + ctx.restore(); + } + + function drawPill() + { + // Make a rounded rect path. + ctx.beginPath(); + ctx.moveTo(x, y + r); + ctx.lineTo(x, y + h - r); + ctx.quadraticCurveTo(x, y + h, x + r, y + h); + ctx.lineTo(x + w - r, y + h); + ctx.quadraticCurveTo(x + w, y + h, x + w, y + h - r); + ctx.lineTo(x + w, y + r); + ctx.quadraticCurveTo(x + w, y, x + w - r, y); + ctx.lineTo(x + r, y); + ctx.quadraticCurveTo(x, y, x, y + r); + ctx.closePath(); + + // Clip to the rounded rect path. + ctx.save(); + ctx.clip(); + + // Fill the segments with the associated color. + var previousSegmentsWidth = 0; + for (var i = 0; i < segments.length; ++i) { + var segmentWidth = Math.round(w * percents[i] / 100); + ctx.fillStyle = segments[i].color; + ctx.fillRect(x + previousSegmentsWidth, y, segmentWidth, h); + previousSegmentsWidth += segmentWidth; + } + + // Draw the segment divider lines. + ctx.lineWidth = 1; + for (var i = 1; i < 20; ++i) { + ctx.beginPath(); + ctx.moveTo(x + (i * Math.round(w / 20)) + 0.5, y); + ctx.lineTo(x + (i * Math.round(w / 20)) + 0.5, y + h); + ctx.closePath(); + + ctx.strokeStyle = "rgba(0, 0, 0, 0.2)"; + ctx.stroke(); + + ctx.beginPath(); + ctx.moveTo(x + (i * Math.round(w / 20)) + 1.5, y); + ctx.lineTo(x + (i * Math.round(w / 20)) + 1.5, y + h); + ctx.closePath(); + + ctx.strokeStyle = "rgba(255, 255, 255, 0.2)"; + ctx.stroke(); + } + + // Draw the pill shading. + var lightGradient = ctx.createLinearGradient(x, y, x, y + (h / 1.5)); + lightGradient.addColorStop(0.0, "rgba(220, 220, 220, 0.6)"); + lightGradient.addColorStop(0.4, "rgba(220, 220, 220, 0.2)"); + lightGradient.addColorStop(1.0, "rgba(255, 255, 255, 0.0)"); + + var darkGradient = ctx.createLinearGradient(x, y + (h / 3), x, y + h); + darkGradient.addColorStop(0.0, "rgba(0, 0, 0, 0.0)"); + darkGradient.addColorStop(0.8, "rgba(0, 0, 0, 0.2)"); + darkGradient.addColorStop(1.0, "rgba(0, 0, 0, 0.5)"); + + ctx.fillStyle = darkGradient; + ctx.fillRect(x, y, w, h); + + ctx.fillStyle = lightGradient; + ctx.fillRect(x, y, w, h); + + ctx.restore(); + } + + ctx.clearRect(x, y, w, (h * 2)); + + drawPillShadow(); + drawPill(); + + ctx.save(); + + ctx.translate(0, (h * 2) + 1); + ctx.scale(1, -1); + + drawPill(); + + ctx.restore(); + + this._fadeOutRect(ctx, x, y + h + 1, w, h, 0.5, 0.0); + }, + + _updateSummaryGraph: function() + { + var graphInfo = this.calculator.computeSummaryValues(this._resources); + + var categoryOrder = ["documents", "stylesheets", "images", "scripts", "xhr", "fonts", "other"]; + var categoryColors = {documents: {r: 47, g: 102, b: 236}, stylesheets: {r: 157, g: 231, b: 119}, images: {r: 164, g: 60, b: 255}, scripts: {r: 255, g: 121, b: 0}, xhr: {r: 231, g: 231, b: 10}, fonts: {r: 255, g: 82, b: 62}, other: {r: 186, g: 186, b: 186}}; + var fillSegments = []; + + this.legendElement.removeChildren(); + + for (var i = 0; i < categoryOrder.length; ++i) { + var category = categoryOrder[i]; + var size = graphInfo.categoryValues[category]; + if (!size) + continue; + + var color = categoryColors[category]; + var colorString = "rgb(" + color.r + ", " + color.g + ", " + color.b + ")"; + + var fillSegment = {color: colorString, value: size}; + fillSegments.push(fillSegment); + + var legendLabel = this._makeLegendElement(WebInspector.resourceCategories[category].title, this.calculator.formatValue(size), colorString); + this.legendElement.appendChild(legendLabel); + } + + if (graphInfo.total) { + var totalLegendLabel = this._makeLegendElement(WebInspector.UIString("Total"), this.calculator.formatValue(graphInfo.total)); + totalLegendLabel.addStyleClass("total"); + this.legendElement.appendChild(totalLegendLabel); + } + + this._drawSummaryGraph(fillSegments); + }, + + _updateDividersLabelBarPosition: function() + { + var scrollTop = this.containerElement.scrollTop; + var dividersTop = (scrollTop < this.summaryElement.offsetHeight ? this.summaryElement.offsetHeight : scrollTop); + this.dividersElement.style.top = scrollTop + "px"; + this.dividersLabelBarElement.style.top = dividersTop + "px"; + }, + + _graphSelected: function(treeElement) + { + if (this._lastSelectedGraphTreeElement) + this._lastSelectedGraphTreeElement.selectedSortingOptionIndex = this.sortingSelectElement.selectedIndex; + + this._lastSelectedGraphTreeElement = treeElement; + + this.sortingSelectElement.removeChildren(); + for (var i = 0; i < treeElement.sortingOptions.length; ++i) { + var sortingOption = treeElement.sortingOptions[i]; + var option = document.createElement("option"); + option.label = sortingOption.name; + option.sortingFunction = sortingOption.sortingFunction; + option.calculator = sortingOption.calculator; + this.sortingSelectElement.appendChild(option); + } + + this.sortingSelectElement.selectedIndex = treeElement.selectedSortingOptionIndex; + this._changeSortingFunction(); + + this.closeVisibleResource(); + this.containerElement.scrollTop = 0; + }, + + _toggleLargerResources: function() + { + if (!this.resourcesTreeElement._childrenListNode) + return; + + this.resourcesTreeElement.smallChildren = !this.resourcesTreeElement.smallChildren; + + if (this.resourcesTreeElement.smallChildren) { + this.resourcesGraphsElement.addStyleClass("small"); + this.largerResourcesButton.title = WebInspector.UIString("Use large resource rows."); + this.largerResourcesButton.removeStyleClass("toggled-on"); + this._adjustScrollPosition(); + } else { + this.resourcesGraphsElement.removeStyleClass("small"); + this.largerResourcesButton.title = WebInspector.UIString("Use small resource rows."); + this.largerResourcesButton.addStyleClass("toggled-on"); + } + }, + + _adjustScrollPosition: function() + { + // Prevent the container from being scrolled off the end. + if ((this.containerElement.scrollTop + this.containerElement.offsetHeight) > this.sidebarElement.offsetHeight) + this.containerElement.scrollTop = (this.sidebarElement.offsetHeight - this.containerElement.offsetHeight); + }, + + _changeSortingFunction: function() + { + var selectedOption = this.sortingSelectElement[this.sortingSelectElement.selectedIndex]; + this.sortingFunction = selectedOption.sortingFunction; + this.calculator = selectedOption.calculator; + }, + + _createResourceView: function(resource) + { + switch (resource.category) { + case WebInspector.resourceCategories.documents: + case WebInspector.resourceCategories.stylesheets: + case WebInspector.resourceCategories.scripts: + case WebInspector.resourceCategories.xhr: + return new WebInspector.SourceView(resource); + case WebInspector.resourceCategories.images: + return new WebInspector.ImageView(resource); + case WebInspector.resourceCategories.fonts: + return new WebInspector.FontView(resource); + default: + return new WebInspector.ResourceView(resource); + } + }, + + _startSidebarDragging: function(event) + { + WebInspector.elementDragStart(this.sidebarResizeElement, this._sidebarDragging.bind(this), this._endSidebarDragging.bind(this), event, "col-resize"); + }, + + _sidebarDragging: function(event) + { + this._updateSidebarWidth(event.pageX); + + event.preventDefault(); + }, + + _endSidebarDragging: function(event) + { + WebInspector.elementDragEnd(event); + }, + + _updateSidebarWidth: function(width) + { + if (this.sidebarElement.offsetWidth <= 0) { + // The stylesheet hasn't loaded yet or the window is closed, + // so we can't calculate what is need. Return early. + return; + } + + if (!("_currentSidebarWidth" in this)) + this._currentSidebarWidth = this.sidebarElement.offsetWidth; + + if (typeof width === "undefined") + width = this._currentSidebarWidth; + + width = Number.constrain(width, Preferences.minSidebarWidth, window.innerWidth / 2); + + this._currentSidebarWidth = width; + + if (this.visibleResource) { + this.containerElement.style.width = width + "px"; + this.sidebarElement.style.removeProperty("width"); + } else { + this.sidebarElement.style.width = width + "px"; + this.containerElement.style.removeProperty("width"); + } + + this.containerContentElement.style.left = width + "px"; + this.viewsContainerElement.style.left = width + "px"; + this.sidebarResizeElement.style.left = (width - 3) + "px"; + + this._updateGraphDividersIfNeeded(); + + var visibleView = this.visibleView; + if (visibleView && "resize" in visibleView) + visibleView.resize(); + } +} + +WebInspector.ResourcesPanel.prototype.__proto__ = WebInspector.Panel.prototype; + +WebInspector.ResourceCalculator = function() +{ +} + +WebInspector.ResourceCalculator.prototype = { + computeSummaryValues: function(resources) + { + var total = 0; + var categoryValues = {}; + + var resourcesLength = resources.length; + for (var i = 0; i < resourcesLength; ++i) { + var resource = resources[i]; + var value = this._value(resource); + if (typeof value === "undefined") + continue; + if (!(resource.category.name in categoryValues)) + categoryValues[resource.category.name] = 0; + categoryValues[resource.category.name] += value; + total += value; + } + + return {categoryValues: categoryValues, total: total}; + }, + + computeBarGraphPercentages: function(resource) + { + return {start: 0, middle: 0, end: (this._value(resource) / this.boundarySpan) * 100}; + }, + + computeBarGraphLabels: function(resource) + { + const label = this.formatValue(this._value(resource)); + var tooltip = label; + if (resource.cached) + tooltip = WebInspector.UIString("%s (from cache)", tooltip); + return {left: label, right: label, tooltip: tooltip}; + }, + + get boundarySpan() + { + return this.maximumBoundary - this.minimumBoundary; + }, + + updateBoundaries: function(resource) + { + this.minimumBoundary = 0; + + var value = this._value(resource); + if (typeof this.maximumBoundary === "undefined" || value > this.maximumBoundary) { + this.maximumBoundary = value; + return true; + } + + return false; + }, + + reset: function() + { + delete this.minimumBoundary; + delete this.maximumBoundary; + }, + + _value: function(resource) + { + return 0; + }, + + formatValue: function(value) + { + return value.toString(); + } +} + +WebInspector.ResourceTimeCalculator = function(startAtZero) +{ + WebInspector.ResourceCalculator.call(this); + this.startAtZero = startAtZero; +} + +WebInspector.ResourceTimeCalculator.prototype = { + computeSummaryValues: function(resources) + { + var resourcesByCategory = {}; + var resourcesLength = resources.length; + for (var i = 0; i < resourcesLength; ++i) { + var resource = resources[i]; + if (!(resource.category.name in resourcesByCategory)) + resourcesByCategory[resource.category.name] = []; + resourcesByCategory[resource.category.name].push(resource); + } + + var earliestStart; + var latestEnd; + var categoryValues = {}; + for (var category in resourcesByCategory) { + resourcesByCategory[category].sort(WebInspector.Resource.CompareByTime); + categoryValues[category] = 0; + + var segment = {start: -1, end: -1}; + + var categoryResources = resourcesByCategory[category]; + var resourcesLength = categoryResources.length; + for (var i = 0; i < resourcesLength; ++i) { + var resource = categoryResources[i]; + if (resource.startTime === -1 || resource.endTime === -1) + continue; + + if (typeof earliestStart === "undefined") + earliestStart = resource.startTime; + else + earliestStart = Math.min(earliestStart, resource.startTime); + + if (typeof latestEnd === "undefined") + latestEnd = resource.endTime; + else + latestEnd = Math.max(latestEnd, resource.endTime); + + if (resource.startTime <= segment.end) { + segment.end = Math.max(segment.end, resource.endTime); + continue; + } + + categoryValues[category] += segment.end - segment.start; + + segment.start = resource.startTime; + segment.end = resource.endTime; + } + + // Add the last segment + categoryValues[category] += segment.end - segment.start; + } + + return {categoryValues: categoryValues, total: latestEnd - earliestStart}; + }, + + computeBarGraphPercentages: function(resource) + { + if (resource.startTime !== -1) + var start = ((resource.startTime - this.minimumBoundary) / this.boundarySpan) * 100; + else + var start = 0; + + if (resource.responseReceivedTime !== -1) + var middle = ((resource.responseReceivedTime - this.minimumBoundary) / this.boundarySpan) * 100; + else + var middle = (this.startAtZero ? start : 100); + + if (resource.endTime !== -1) + var end = ((resource.endTime - this.minimumBoundary) / this.boundarySpan) * 100; + else + var end = (this.startAtZero ? middle : 100); + + if (this.startAtZero) { + end -= start; + middle -= start; + start = 0; + } + + return {start: start, middle: middle, end: end}; + }, + + computeBarGraphLabels: function(resource) + { + var leftLabel = ""; + if (resource.latency > 0) + leftLabel = this.formatValue(resource.latency); + + var rightLabel = ""; + if (resource.responseReceivedTime !== -1 && resource.endTime !== -1) + rightLabel = this.formatValue(resource.endTime - resource.responseReceivedTime); + + if (leftLabel && rightLabel) { + var total = this.formatValue(resource.duration); + var tooltip = WebInspector.UIString("%s latency, %s download (%s total)", leftLabel, rightLabel, total); + } else if (leftLabel) + var tooltip = WebInspector.UIString("%s latency", leftLabel); + else if (rightLabel) + var tooltip = WebInspector.UIString("%s download", rightLabel); + + if (resource.cached) + tooltip = WebInspector.UIString("%s (from cache)", tooltip); + + return {left: leftLabel, right: rightLabel, tooltip: tooltip}; + }, + + updateBoundaries: function(resource) + { + var didChange = false; + + var lowerBound; + if (this.startAtZero) + lowerBound = 0; + else + lowerBound = this._lowerBound(resource); + + if (lowerBound !== -1 && (typeof this.minimumBoundary === "undefined" || lowerBound < this.minimumBoundary)) { + this.minimumBoundary = lowerBound; + didChange = true; + } + + var upperBound = this._upperBound(resource); + if (upperBound !== -1 && (typeof this.maximumBoundary === "undefined" || upperBound > this.maximumBoundary)) { + this.maximumBoundary = upperBound; + didChange = true; + } + + return didChange; + }, + + formatValue: function(value) + { + return Number.secondsToString(value, WebInspector.UIString.bind(WebInspector)); + }, + + _lowerBound: function(resource) + { + return 0; + }, + + _upperBound: function(resource) + { + return 0; + }, +} + +WebInspector.ResourceTimeCalculator.prototype.__proto__ = WebInspector.ResourceCalculator.prototype; + +WebInspector.ResourceTransferTimeCalculator = function() +{ + WebInspector.ResourceTimeCalculator.call(this, false); +} + +WebInspector.ResourceTransferTimeCalculator.prototype = { + formatValue: function(value) + { + return Number.secondsToString(value, WebInspector.UIString.bind(WebInspector)); + }, + + _lowerBound: function(resource) + { + return resource.startTime; + }, + + _upperBound: function(resource) + { + return resource.endTime; + } +} + +WebInspector.ResourceTransferTimeCalculator.prototype.__proto__ = WebInspector.ResourceTimeCalculator.prototype; + +WebInspector.ResourceTransferDurationCalculator = function() +{ + WebInspector.ResourceTimeCalculator.call(this, true); +} + +WebInspector.ResourceTransferDurationCalculator.prototype = { + formatValue: function(value) + { + return Number.secondsToString(value, WebInspector.UIString.bind(WebInspector)); + }, + + _upperBound: function(resource) + { + return resource.duration; + } +} + +WebInspector.ResourceTransferDurationCalculator.prototype.__proto__ = WebInspector.ResourceTimeCalculator.prototype; + +WebInspector.ResourceTransferSizeCalculator = function() +{ + WebInspector.ResourceCalculator.call(this); +} + +WebInspector.ResourceTransferSizeCalculator.prototype = { + _value: function(resource) + { + return resource.contentLength; + }, + + formatValue: function(value) + { + return Number.bytesToString(value, WebInspector.UIString.bind(WebInspector)); + } +} + +WebInspector.ResourceTransferSizeCalculator.prototype.__proto__ = WebInspector.ResourceCalculator.prototype; + +WebInspector.ResourceSidebarTreeElement = function(resource) +{ + this.resource = resource; + + this.createIconElement(); + + WebInspector.SidebarTreeElement.call(this, "resource-sidebar-tree-item", "", "", resource); + + this.refreshTitles(); +} + +WebInspector.ResourceSidebarTreeElement.prototype = { + onattach: function() + { + WebInspector.SidebarTreeElement.prototype.onattach.call(this); + + this._listItemNode.addStyleClass("resources-category-" + this.resource.category.name); + }, + + onselect: function() + { + WebInspector.panels.resources.showResource(this.resource); + }, + + get mainTitle() + { + return this.resource.displayName; + }, + + set mainTitle(x) + { + // Do nothing. + }, + + get subtitle() + { + var subtitle = this.resource.displayDomain; + + if (this.resource.path && this.resource.lastPathComponent) { + var lastPathComponentIndex = this.resource.path.lastIndexOf("/" + this.resource.lastPathComponent); + if (lastPathComponentIndex != -1) + subtitle += this.resource.path.substring(0, lastPathComponentIndex); + } + + return subtitle; + }, + + set subtitle(x) + { + // Do nothing. + }, + + createIconElement: function() + { + var previousIconElement = this.iconElement; + + if (this.resource.category === WebInspector.resourceCategories.images) { + var previewImage = document.createElement("img"); + previewImage.className = "image-resource-icon-preview"; + previewImage.src = this.resource.url; + + this.iconElement = document.createElement("div"); + this.iconElement.className = "icon"; + this.iconElement.appendChild(previewImage); + } else { + this.iconElement = document.createElement("img"); + this.iconElement.className = "icon"; + } + + if (previousIconElement) + previousIconElement.parentNode.replaceChild(this.iconElement, previousIconElement); + }, + + refresh: function() + { + this.refreshTitles(); + + if (!this._listItemNode.hasStyleClass("resources-category-" + this.resource.category.name)) { + this._listItemNode.removeMatchingStyleClasses("resources-category-\\w+"); + this._listItemNode.addStyleClass("resources-category-" + this.resource.category.name); + + this.createIconElement(); + } + }, + + resetBubble: function() + { + this.bubbleText = ""; + this.bubbleElement.removeStyleClass("search-matches"); + this.bubbleElement.removeStyleClass("warning"); + this.bubbleElement.removeStyleClass("error"); + }, + + set searchMatches(matches) + { + this.resetBubble(); + + if (!matches) + return; + + this.bubbleText = matches; + this.bubbleElement.addStyleClass("search-matches"); + }, + + updateErrorsAndWarnings: function() + { + this.resetBubble(); + + if (this.resource.warnings || this.resource.errors) + this.bubbleText = (this.resource.warnings + this.resource.errors); + + if (this.resource.warnings) + this.bubbleElement.addStyleClass("warning"); + + if (this.resource.errors) + this.bubbleElement.addStyleClass("error"); + } +} + +WebInspector.ResourceSidebarTreeElement.CompareByAscendingStartTime = function(a, b) +{ + return WebInspector.Resource.CompareByStartTime(a.resource, b.resource) + || WebInspector.Resource.CompareByEndTime(a.resource, b.resource) + || WebInspector.Resource.CompareByResponseReceivedTime(a.resource, b.resource); +} + +WebInspector.ResourceSidebarTreeElement.CompareByAscendingResponseReceivedTime = function(a, b) +{ + return WebInspector.Resource.CompareByResponseReceivedTime(a.resource, b.resource) + || WebInspector.Resource.CompareByStartTime(a.resource, b.resource) + || WebInspector.Resource.CompareByEndTime(a.resource, b.resource); +} + +WebInspector.ResourceSidebarTreeElement.CompareByAscendingEndTime = function(a, b) +{ + return WebInspector.Resource.CompareByEndTime(a.resource, b.resource) + || WebInspector.Resource.CompareByStartTime(a.resource, b.resource) + || WebInspector.Resource.CompareByResponseReceivedTime(a.resource, b.resource); +} + +WebInspector.ResourceSidebarTreeElement.CompareByDescendingDuration = function(a, b) +{ + return -1 * WebInspector.Resource.CompareByDuration(a.resource, b.resource); +} + +WebInspector.ResourceSidebarTreeElement.CompareByDescendingLatency = function(a, b) +{ + return -1 * WebInspector.Resource.CompareByLatency(a.resource, b.resource); +} + +WebInspector.ResourceSidebarTreeElement.CompareByDescendingSize = function(a, b) +{ + return -1 * WebInspector.Resource.CompareBySize(a.resource, b.resource); +} + +WebInspector.ResourceSidebarTreeElement.prototype.__proto__ = WebInspector.SidebarTreeElement.prototype; + +WebInspector.ResourceGraph = function(resource) +{ + this.resource = resource; + + this._graphElement = document.createElement("div"); + this._graphElement.className = "resources-graph-side"; + this._graphElement.addEventListener("mouseover", this.refreshLabelPositions.bind(this), false); + + if (resource.cached) + this._graphElement.addStyleClass("resource-cached"); + + this._barAreaElement = document.createElement("div"); + this._barAreaElement.className = "resources-graph-bar-area hidden"; + this._graphElement.appendChild(this._barAreaElement); + + this._barLeftElement = document.createElement("div"); + this._barLeftElement.className = "resources-graph-bar waiting"; + this._barAreaElement.appendChild(this._barLeftElement); + + this._barRightElement = document.createElement("div"); + this._barRightElement.className = "resources-graph-bar"; + this._barAreaElement.appendChild(this._barRightElement); + + this._labelLeftElement = document.createElement("div"); + this._labelLeftElement.className = "resources-graph-label waiting"; + this._barAreaElement.appendChild(this._labelLeftElement); + + this._labelRightElement = document.createElement("div"); + this._labelRightElement.className = "resources-graph-label"; + this._barAreaElement.appendChild(this._labelRightElement); + + this._graphElement.addStyleClass("resources-category-" + resource.category.name); +} + +WebInspector.ResourceGraph.prototype = { + get graphElement() + { + return this._graphElement; + }, + + refreshLabelPositions: function() + { + this._labelLeftElement.style.removeProperty("left"); + this._labelLeftElement.style.removeProperty("right"); + this._labelLeftElement.removeStyleClass("before"); + this._labelLeftElement.removeStyleClass("hidden"); + + this._labelRightElement.style.removeProperty("left"); + this._labelRightElement.style.removeProperty("right"); + this._labelRightElement.removeStyleClass("after"); + this._labelRightElement.removeStyleClass("hidden"); + + const labelPadding = 10; + const rightBarWidth = (this._barRightElement.offsetWidth - labelPadding); + const leftBarWidth = ((this._barLeftElement.offsetWidth - this._barRightElement.offsetWidth) - labelPadding); + + var labelBefore = (this._labelLeftElement.offsetWidth > leftBarWidth); + var labelAfter = (this._labelRightElement.offsetWidth > rightBarWidth); + + if (labelBefore) { + if ((this._graphElement.offsetWidth * (this._percentages.start / 100)) < (this._labelLeftElement.offsetWidth + 10)) + this._labelLeftElement.addStyleClass("hidden"); + this._labelLeftElement.style.setProperty("right", (100 - this._percentages.start) + "%"); + this._labelLeftElement.addStyleClass("before"); + } else { + this._labelLeftElement.style.setProperty("left", this._percentages.start + "%"); + this._labelLeftElement.style.setProperty("right", (100 - this._percentages.middle) + "%"); + } + + if (labelAfter) { + if ((this._graphElement.offsetWidth * ((100 - this._percentages.end) / 100)) < (this._labelRightElement.offsetWidth + 10)) + this._labelRightElement.addStyleClass("hidden"); + this._labelRightElement.style.setProperty("left", this._percentages.end + "%"); + this._labelRightElement.addStyleClass("after"); + } else { + this._labelRightElement.style.setProperty("left", this._percentages.middle + "%"); + this._labelRightElement.style.setProperty("right", (100 - this._percentages.end) + "%"); + } + }, + + refresh: function(calculator) + { + var percentages = calculator.computeBarGraphPercentages(this.resource); + var labels = calculator.computeBarGraphLabels(this.resource); + + this._percentages = percentages; + + this._barAreaElement.removeStyleClass("hidden"); + + if (!this._graphElement.hasStyleClass("resources-category-" + this.resource.category.name)) { + this._graphElement.removeMatchingStyleClasses("resources-category-\\w+"); + this._graphElement.addStyleClass("resources-category-" + this.resource.category.name); + } + + this._barLeftElement.style.setProperty("left", percentages.start + "%"); + this._barLeftElement.style.setProperty("right", (100 - percentages.end) + "%"); + + this._barRightElement.style.setProperty("left", percentages.middle + "%"); + this._barRightElement.style.setProperty("right", (100 - percentages.end) + "%"); + + this._labelLeftElement.textContent = labels.left; + this._labelRightElement.textContent = labels.right; + + var tooltip = (labels.tooltip || ""); + this._barLeftElement.title = tooltip; + this._labelLeftElement.title = tooltip; + this._labelRightElement.title = tooltip; + this._barRightElement.title = tooltip; + } +} diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ScopeChainSidebarPane.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ScopeChainSidebarPane.js new file mode 100644 index 0000000..157cee9 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ScopeChainSidebarPane.js @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2008 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. ``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 + * 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.ScopeChainSidebarPane = function() +{ + WebInspector.SidebarPane.call(this, WebInspector.UIString("Scope Variables")); +} + +WebInspector.ScopeChainSidebarPane.prototype = { + update: function(callFrame) + { + this.bodyElement.removeChildren(); + + this.sections = []; + this.callFrame = callFrame; + + if (!callFrame) { + var infoElement = document.createElement("div"); + infoElement.className = "info"; + infoElement.textContent = WebInspector.UIString("Not Paused"); + this.bodyElement.appendChild(infoElement); + return; + } + + if (!callFrame._expandedProperties) { + // FIXME: fix this when https://bugs.webkit.org/show_bug.cgi?id=19410 is fixed. + // The callFrame is a JSInspectedObjectWrapper, so we are not allowed to assign + // an object created in the Inspector's context to that object. So create an + // Object from the inspectedWindow. + var inspectedWindow = InspectorController.inspectedWindow(); + callFrame._expandedProperties = new inspectedWindow.Object; + } + + var foundLocalScope = false; + var scopeChain = callFrame.scopeChain; + for (var i = 0; i < scopeChain.length; ++i) { + var scopeObject = scopeChain[i]; + var title = null; + var subtitle = Object.describe(scopeObject, true); + var emptyPlaceholder = null; + var localScope = false; + var extraProperties = null; + + if (Object.prototype.toString.call(scopeObject) === "[object JSActivation]") { + if (!foundLocalScope) { + extraProperties = { "this": callFrame.thisObject }; + title = WebInspector.UIString("Local"); + } else + title = WebInspector.UIString("Closure"); + emptyPlaceholder = WebInspector.UIString("No Variables"); + subtitle = null; + foundLocalScope = true; + localScope = true; + } else if (i === (scopeChain.length - 1)) + title = WebInspector.UIString("Global"); + else if (foundLocalScope && scopeObject instanceof InspectorController.inspectedWindow().Element) + title = WebInspector.UIString("Event Target"); + else if (foundLocalScope && scopeObject instanceof InspectorController.inspectedWindow().Document) + title = WebInspector.UIString("Event Document"); + else if (!foundLocalScope && !localScope) + title = WebInspector.UIString("With Block"); + + if (!title || title === subtitle) + subtitle = null; + + var section = new WebInspector.ObjectPropertiesSection(scopeObject, title, subtitle, emptyPlaceholder, true, extraProperties, WebInspector.ScopeVariableTreeElement); + section.editInSelectedCallFrameWhenPaused = true; + section.pane = this; + + if (!foundLocalScope || localScope) + section.expanded = true; + + this.sections.push(section); + this.bodyElement.appendChild(section.element); + } + } +} + +WebInspector.ScopeChainSidebarPane.prototype.__proto__ = WebInspector.SidebarPane.prototype; + +WebInspector.ScopeVariableTreeElement = function(parentObject, propertyName) +{ + WebInspector.ObjectPropertyTreeElement.call(this, parentObject, propertyName); +} + +WebInspector.ScopeVariableTreeElement.prototype = { + onattach: function() + { + WebInspector.ObjectPropertyTreeElement.prototype.onattach.call(this); + if (this.hasChildren && this.propertyIdentifier in this.treeOutline.section.pane.callFrame._expandedProperties) + this.expand(); + }, + + onexpand: function() + { + this.treeOutline.section.pane.callFrame._expandedProperties[this.propertyIdentifier] = true; + }, + + oncollapse: function() + { + delete this.treeOutline.section.pane.callFrame._expandedProperties[this.propertyIdentifier]; + }, + + get propertyIdentifier() + { + if ("_propertyIdentifier" in this) + return this._propertyIdentifier; + var section = this.treeOutline.section; + this._propertyIdentifier = section.title + ":" + (section.subtitle ? section.subtitle + ":" : "") + this.propertyPath; + return this._propertyIdentifier; + }, + + get propertyPath() + { + if ("_propertyPath" in this) + return this._propertyPath; + + var current = this; + var result; + + do { + if (result) + result = current.propertyName + "." + result; + else + result = current.propertyName; + current = current.parent; + } while (current && !current.root); + + this._propertyPath = result; + return result; + } +} + +WebInspector.ScopeVariableTreeElement.prototype.__proto__ = WebInspector.ObjectPropertyTreeElement.prototype; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Script.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Script.js new file mode 100644 index 0000000..46502a6 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Script.js @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2008 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. ``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 + * 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.Script = function(sourceID, sourceURL, source, startingLine, errorLine, errorMessage) +{ + this.sourceID = sourceID; + this.sourceURL = sourceURL; + this.source = source; + this.startingLine = startingLine; + this.errorLine = errorLine; + this.errorMessage = errorMessage; +} + +WebInspector.Script.prototype = { +} diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ScriptView.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ScriptView.js new file mode 100644 index 0000000..124190c --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ScriptView.js @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2008 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. ``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 + * 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.ScriptView = function(script) +{ + WebInspector.View.call(this); + + this.element.addStyleClass("script-view"); + + this.script = script; + + this._frameNeedsSetup = true; + this._sourceFrameSetup = false; + + this.sourceFrame = new WebInspector.SourceFrame(null, this._addBreakpoint.bind(this)); + + this.element.appendChild(this.sourceFrame.element); +} + +WebInspector.ScriptView.prototype = { + show: function(parentElement) + { + WebInspector.View.prototype.show.call(this, parentElement); + this.setupSourceFrameIfNeeded(); + }, + + hide: function() + { + WebInspector.View.prototype.hide.call(this); + this._currentSearchResultIndex = -1; + }, + + setupSourceFrameIfNeeded: function() + { + if (!this._frameNeedsSetup) + return; + + this.attach(); + + if (!InspectorController.addSourceToFrame("text/javascript", this.script.source, this.sourceFrame.element)) + return; + + delete this._frameNeedsSetup; + + this.sourceFrame.addEventListener("syntax highlighting complete", this._syntaxHighlightingComplete, this); + this.sourceFrame.syntaxHighlightJavascript(); + }, + + attach: function() + { + if (!this.element.parentNode) + document.getElementById("script-resource-views").appendChild(this.element); + }, + + _addBreakpoint: function(line) + { + var breakpoint = new WebInspector.Breakpoint(this.script.sourceURL, line, this.script.sourceID); + WebInspector.panels.scripts.addBreakpoint(breakpoint); + }, + + // The follow methods are pulled from SourceView, since they are + // generic and work with ScriptView just fine. + + revealLine: WebInspector.SourceView.prototype.revealLine, + highlightLine: WebInspector.SourceView.prototype.highlightLine, + addMessage: WebInspector.SourceView.prototype.addMessage, + clearMessages: WebInspector.SourceView.prototype.clearMessages, + searchCanceled: WebInspector.SourceView.prototype.searchCanceled, + performSearch: WebInspector.SourceView.prototype.performSearch, + jumpToFirstSearchResult: WebInspector.SourceView.prototype.jumpToFirstSearchResult, + jumpToLastSearchResult: WebInspector.SourceView.prototype.jumpToLastSearchResult, + jumpToNextSearchResult: WebInspector.SourceView.prototype.jumpToNextSearchResult, + jumpToPreviousSearchResult: WebInspector.SourceView.prototype.jumpToPreviousSearchResult, + showingFirstSearchResult: WebInspector.SourceView.prototype.showingFirstSearchResult, + showingLastSearchResult: WebInspector.SourceView.prototype.showingLastSearchResult, + _jumpToSearchResult: WebInspector.SourceView.prototype._jumpToSearchResult, + _sourceFrameSetupFinished: WebInspector.SourceView.prototype._sourceFrameSetupFinished, + _syntaxHighlightingComplete: WebInspector.SourceView.prototype._syntaxHighlightingComplete +} + +WebInspector.ScriptView.prototype.__proto__ = WebInspector.View.prototype; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ScriptsPanel.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ScriptsPanel.js new file mode 100644 index 0000000..c738d9e --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ScriptsPanel.js @@ -0,0 +1,841 @@ +/* + * Copyright (C) 2008 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. ``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 + * 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.ScriptsPanel = function() +{ + WebInspector.Panel.call(this); + + this.element.addStyleClass("scripts"); + + this.topStatusBar = document.createElement("div"); + this.topStatusBar.className = "status-bar"; + this.topStatusBar.id = "scripts-status-bar"; + this.element.appendChild(this.topStatusBar); + + this.backButton = document.createElement("button"); + this.backButton.className = "status-bar-item"; + this.backButton.id = "scripts-back"; + this.backButton.title = WebInspector.UIString("Show the previous script resource."); + this.backButton.disabled = true; + this.backButton.appendChild(document.createElement("img")); + this.backButton.addEventListener("click", this._goBack.bind(this), false); + this.topStatusBar.appendChild(this.backButton); + + this.forwardButton = document.createElement("button"); + this.forwardButton.className = "status-bar-item"; + this.forwardButton.id = "scripts-forward"; + this.forwardButton.title = WebInspector.UIString("Show the next script resource."); + this.forwardButton.disabled = true; + this.forwardButton.appendChild(document.createElement("img")); + this.forwardButton.addEventListener("click", this._goForward.bind(this), false); + this.topStatusBar.appendChild(this.forwardButton); + + this.filesSelectElement = document.createElement("select"); + this.filesSelectElement.className = "status-bar-item"; + this.filesSelectElement.id = "scripts-files"; + this.filesSelectElement.addEventListener("change", this._changeVisibleFile.bind(this), false); + this.topStatusBar.appendChild(this.filesSelectElement); + + this.functionsSelectElement = document.createElement("select"); + this.functionsSelectElement.className = "status-bar-item"; + this.functionsSelectElement.id = "scripts-functions"; + + // FIXME: append the functions select element to the top status bar when it is implemented. + // this.topStatusBar.appendChild(this.functionsSelectElement); + + this.sidebarButtonsElement = document.createElement("div"); + this.sidebarButtonsElement.id = "scripts-sidebar-buttons"; + this.topStatusBar.appendChild(this.sidebarButtonsElement); + + this.pauseButton = document.createElement("button"); + this.pauseButton.className = "status-bar-item"; + this.pauseButton.id = "scripts-pause"; + this.pauseButton.title = WebInspector.UIString("Pause script execution."); + this.pauseButton.disabled = true; + this.pauseButton.appendChild(document.createElement("img")); + this.pauseButton.addEventListener("click", this._togglePause.bind(this), false); + this.sidebarButtonsElement.appendChild(this.pauseButton); + + this.stepOverButton = document.createElement("button"); + this.stepOverButton.className = "status-bar-item"; + this.stepOverButton.id = "scripts-step-over"; + this.stepOverButton.title = WebInspector.UIString("Step over next function call."); + this.stepOverButton.disabled = true; + this.stepOverButton.addEventListener("click", this._stepOverClicked.bind(this), false); + this.stepOverButton.appendChild(document.createElement("img")); + this.sidebarButtonsElement.appendChild(this.stepOverButton); + + this.stepIntoButton = document.createElement("button"); + this.stepIntoButton.className = "status-bar-item"; + this.stepIntoButton.id = "scripts-step-into"; + this.stepIntoButton.title = WebInspector.UIString("Step into next function call."); + this.stepIntoButton.disabled = true; + this.stepIntoButton.addEventListener("click", this._stepIntoClicked.bind(this), false); + this.stepIntoButton.appendChild(document.createElement("img")); + this.sidebarButtonsElement.appendChild(this.stepIntoButton); + + this.stepOutButton = document.createElement("button"); + this.stepOutButton.className = "status-bar-item"; + this.stepOutButton.id = "scripts-step-out"; + this.stepOutButton.title = WebInspector.UIString("Step out of current function."); + this.stepOutButton.disabled = true; + this.stepOutButton.addEventListener("click", this._stepOutClicked.bind(this), false); + this.stepOutButton.appendChild(document.createElement("img")); + this.sidebarButtonsElement.appendChild(this.stepOutButton); + + this.debuggerStatusElement = document.createElement("div"); + this.debuggerStatusElement.id = "scripts-debugger-status"; + this.sidebarButtonsElement.appendChild(this.debuggerStatusElement); + + this.viewsContainerElement = document.createElement("div"); + this.viewsContainerElement.id = "script-resource-views"; + + this.sidebarElement = document.createElement("div"); + this.sidebarElement.id = "scripts-sidebar"; + + this.sidebarResizeElement = document.createElement("div"); + this.sidebarResizeElement.className = "sidebar-resizer-vertical"; + this.sidebarResizeElement.addEventListener("mousedown", this._startSidebarResizeDrag.bind(this), false); + + this.sidebarResizeWidgetElement = document.createElement("div"); + this.sidebarResizeWidgetElement.id = "scripts-sidebar-resizer-widget"; + this.sidebarResizeWidgetElement.addEventListener("mousedown", this._startSidebarResizeDrag.bind(this), false); + this.topStatusBar.appendChild(this.sidebarResizeWidgetElement); + + this.sidebarPanes = {}; + this.sidebarPanes.callstack = new WebInspector.CallStackSidebarPane(); + this.sidebarPanes.scopechain = new WebInspector.ScopeChainSidebarPane(); + this.sidebarPanes.breakpoints = new WebInspector.BreakpointsSidebarPane(); + + for (var pane in this.sidebarPanes) + this.sidebarElement.appendChild(this.sidebarPanes[pane].element); + + // FIXME: remove the following line of code when the Breakpoints pane has content. + this.sidebarElement.removeChild(this.sidebarPanes.breakpoints.element); + + this.sidebarPanes.callstack.expanded = true; + this.sidebarPanes.callstack.addEventListener("call frame selected", this._callFrameSelected, this); + + this.sidebarPanes.scopechain.expanded = true; + + var panelEnablerHeading = WebInspector.UIString("You need to enable debugging before you can use the Scripts panel."); + var panelEnablerDisclaimer = WebInspector.UIString("Enabling debugging will make scripts run slower."); + var panelEnablerButton = WebInspector.UIString("Enable Debugging"); + + this.panelEnablerView = new WebInspector.PanelEnablerView("scripts", panelEnablerHeading, panelEnablerDisclaimer, panelEnablerButton); + this.panelEnablerView.addEventListener("enable clicked", this._enableDebugging, this); + + this.element.appendChild(this.panelEnablerView.element); + this.element.appendChild(this.viewsContainerElement); + this.element.appendChild(this.sidebarElement); + this.element.appendChild(this.sidebarResizeElement); + + this.enableToggleButton = document.createElement("button"); + this.enableToggleButton.className = "enable-toggle-status-bar-item status-bar-item"; + this.enableToggleButton.addEventListener("click", this._toggleDebugging.bind(this), false); + + this.pauseOnExceptionButton = document.createElement("button"); + this.pauseOnExceptionButton.id = "scripts-pause-on-exceptions-status-bar-item"; + this.pauseOnExceptionButton.className = "status-bar-item"; + this.pauseOnExceptionButton.addEventListener("click", this._togglePauseOnExceptions.bind(this), false); + + this._breakpointsURLMap = {}; + + this.reset(); +} + +WebInspector.ScriptsPanel.prototype = { + toolbarItemClass: "scripts", + + get toolbarItemLabel() + { + return WebInspector.UIString("Scripts"); + }, + + get statusBarItems() + { + return [this.enableToggleButton, this.pauseOnExceptionButton]; + }, + + get paused() + { + return this._paused; + }, + + show: function() + { + WebInspector.Panel.prototype.show.call(this); + this.sidebarResizeElement.style.right = (this.sidebarElement.offsetWidth - 3) + "px"; + + if (this.visibleView) { + if (this.visibleView instanceof WebInspector.ResourceView) + this.visibleView.headersVisible = false; + this.visibleView.show(this.viewsContainerElement); + } + + // Hide any views that are visible that are not this panel's current visible view. + // This can happen when a ResourceView is visible in the Resources panel then switched + // to the this panel. + for (var sourceID in this._sourceIDMap) { + var scriptOrResource = this._sourceIDMap[sourceID]; + var view = this._sourceViewForScriptOrResource(scriptOrResource); + if (!view || view === this.visibleView) + continue; + view.visible = false; + } + }, + + get searchableViews() + { + var views = []; + + const visibleView = this.visibleView; + if (visibleView && visibleView.performSearch) { + visibleView.alreadySearching = true; + views.push(visibleView); + } + + for (var sourceID in this._sourceIDMap) { + var scriptOrResource = this._sourceIDMap[sourceID]; + var view = this._sourceViewForScriptOrResource(scriptOrResource); + if (!view || !view.performSearch || view.alreadySearching) + continue; + + view.alreadySearching = true; + views.push(view); + } + + for (var i = 0; i < views.length; ++i) + delete views[i].alreadySearching; + + return views; + }, + + addScript: function(sourceID, sourceURL, source, startingLine, errorLine, errorMessage) + { + var script = new WebInspector.Script(sourceID, sourceURL, source, startingLine, errorLine, errorMessage); + + if (sourceURL in WebInspector.resourceURLMap) { + var resource = WebInspector.resourceURLMap[sourceURL]; + resource.addScript(script); + } + + if (sourceURL in this._breakpointsURLMap && sourceID) { + var breakpoints = this._breakpointsURLMap[sourceURL]; + var breakpointsLength = breakpoints.length; + for (var i = 0; i < breakpointsLength; ++i) { + var breakpoint = breakpoints[i]; + if (startingLine <= breakpoint.line) { + breakpoint.sourceID = sourceID; + if (breakpoint.enabled) + InspectorController.addBreakpoint(breakpoint.sourceID, breakpoint.line); + } + } + } + + if (sourceID) + this._sourceIDMap[sourceID] = (resource || script); + + this._addScriptToFilesMenu(script); + }, + + addBreakpoint: function(breakpoint) + { + this.sidebarPanes.breakpoints.addBreakpoint(breakpoint); + + var sourceFrame; + if (breakpoint.url) { + if (!(breakpoint.url in this._breakpointsURLMap)) + this._breakpointsURLMap[breakpoint.url] = []; + this._breakpointsURLMap[breakpoint.url].unshift(breakpoint); + + if (breakpoint.url in WebInspector.resourceURLMap) { + var resource = WebInspector.resourceURLMap[breakpoint.url]; + sourceFrame = this._sourceFrameForScriptOrResource(resource); + } + } + + if (breakpoint.sourceID && !sourceFrame) { + var object = this._sourceIDMap[breakpoint.sourceID] + sourceFrame = this._sourceFrameForScriptOrResource(object); + } + + if (sourceFrame) + sourceFrame.addBreakpoint(breakpoint); + }, + + removeBreakpoint: function(breakpoint) + { + this.sidebarPanes.breakpoints.removeBreakpoint(breakpoint); + + var sourceFrame; + if (breakpoint.url && breakpoint.url in this._breakpointsURLMap) { + var breakpoints = this._breakpointsURLMap[breakpoint.url]; + breakpoints.remove(breakpoint); + if (!breakpoints.length) + delete this._breakpointsURLMap[breakpoint.url]; + + if (breakpoint.url in WebInspector.resourceURLMap) { + var resource = WebInspector.resourceURLMap[breakpoint.url]; + sourceFrame = this._sourceFrameForScriptOrResource(resource); + } + } + + if (breakpoint.sourceID && !sourceFrame) { + var object = this._sourceIDMap[breakpoint.sourceID] + sourceFrame = this._sourceFrameForScriptOrResource(object); + } + + if (sourceFrame) + sourceFrame.removeBreakpoint(breakpoint); + }, + + evaluateInSelectedCallFrame: function(code, updateInterface) + { + var selectedCallFrame = this.sidebarPanes.callstack.selectedCallFrame; + if (!this._paused || !selectedCallFrame) + return; + if (typeof updateInterface === "undefined") + updateInterface = true; + var result = selectedCallFrame.evaluate(code); + if (updateInterface) + this.sidebarPanes.scopechain.update(selectedCallFrame); + return result; + }, + + variablesInScopeForSelectedCallFrame: function() + { + var selectedCallFrame = this.sidebarPanes.callstack.selectedCallFrame; + if (!this._paused || !selectedCallFrame) + return {}; + + var result = {}; + var scopeChain = selectedCallFrame.scopeChain; + for (var i = 0; i < scopeChain.length; ++i) { + var scopeObject = scopeChain[i]; + for (var property in scopeObject) + result[property] = true; + } + + return result; + }, + + debuggerPaused: function() + { + this._paused = true; + this._waitingToPause = false; + this._stepping = false; + + this._updateDebuggerButtons(); + + var callStackPane = this.sidebarPanes.callstack; + var currentFrame = InspectorController.currentCallFrame(); + callStackPane.update(currentFrame, this._sourceIDMap); + callStackPane.selectedCallFrame = currentFrame; + + WebInspector.currentPanel = this; + window.focus(); + }, + + debuggerResumed: function() + { + this._paused = false; + this._waitingToPause = false; + this._stepping = false; + + this._clearInterface(); + }, + + debuggerWasEnabled: function() + { + this.reset(); + }, + + debuggerWasDisabled: function() + { + this.reset(); + }, + + reset: function() + { + this.visibleView = null; + + delete this.currentQuery; + this.searchCanceled(); + + if (!InspectorController.debuggerEnabled()) { + this._paused = false; + this._waitingToPause = false; + this._stepping = false; + } + + this._clearInterface(); + + this._backForwardList = []; + this._currentBackForwardIndex = -1; + this._updateBackAndForwardButtons(); + + this._scriptsForURLsInFilesSelect = {}; + this.filesSelectElement.removeChildren(); + this.functionsSelectElement.removeChildren(); + this.viewsContainerElement.removeChildren(); + + if (this._sourceIDMap) { + for (var sourceID in this._sourceIDMap) { + var object = this._sourceIDMap[sourceID]; + if (object instanceof WebInspector.Resource) + object.removeAllScripts(); + } + } + + this._sourceIDMap = {}; + }, + + get visibleView() + { + return this._visibleView; + }, + + set visibleView(x) + { + if (this._visibleView === x) + return; + + if (this._visibleView) + this._visibleView.hide(); + + this._visibleView = x; + + if (x) + x.show(this.viewsContainerElement); + }, + + canShowResource: function(resource) + { + return resource && resource.scripts.length && InspectorController.debuggerEnabled(); + }, + + showScript: function(script, line) + { + this._showScriptOrResource(script, line, true); + }, + + showResource: function(resource, line) + { + this._showScriptOrResource(resource, line, true); + }, + + showView: function(view) + { + if (!view) + return; + this._showScriptOrResource((view.resource || view.script)); + }, + + scriptViewForScript: function(script) + { + if (!script) + return null; + if (!script._scriptView) + script._scriptView = new WebInspector.ScriptView(script); + return script._scriptView; + }, + + sourceFrameForScript: function(script) + { + var view = this.scriptViewForScript(script); + if (!view) + return null; + + // Setting up the source frame requires that we be attached. + if (!this.element.parentNode) + this.attach(); + + view.setupSourceFrameIfNeeded(); + return view.sourceFrame; + }, + + _sourceViewForScriptOrResource: function(scriptOrResource) + { + if (scriptOrResource instanceof WebInspector.Resource) { + if (!WebInspector.panels.resources) + return null; + return WebInspector.panels.resources.resourceViewForResource(scriptOrResource); + } + if (scriptOrResource instanceof WebInspector.Script) + return this.scriptViewForScript(scriptOrResource); + }, + + _sourceFrameForScriptOrResource: function(scriptOrResource) + { + if (scriptOrResource instanceof WebInspector.Resource) { + if (!WebInspector.panels.resources) + return null; + return WebInspector.panels.resources.sourceFrameForResource(scriptOrResource); + } + if (scriptOrResource instanceof WebInspector.Script) + return this.sourceFrameForScript(scriptOrResource); + }, + + _showScriptOrResource: function(scriptOrResource, line, shouldHighlightLine, fromBackForwardAction) + { + if (!scriptOrResource) + return; + + var view; + if (scriptOrResource instanceof WebInspector.Resource) { + if (!WebInspector.panels.resources) + return null; + view = WebInspector.panels.resources.resourceViewForResource(scriptOrResource); + view.headersVisible = false; + + if (scriptOrResource.url in this._breakpointsURLMap) { + var sourceFrame = this._sourceFrameForScriptOrResource(scriptOrResource); + if (sourceFrame && !sourceFrame.breakpoints.length) { + var breakpoints = this._breakpointsURLMap[scriptOrResource.url]; + var breakpointsLength = breakpoints.length; + for (var i = 0; i < breakpointsLength; ++i) + sourceFrame.addBreakpoint(breakpoints[i]); + } + } + } else if (scriptOrResource instanceof WebInspector.Script) + view = this.scriptViewForScript(scriptOrResource); + + if (!view) + return; + + if (!fromBackForwardAction) { + var oldIndex = this._currentBackForwardIndex; + if (oldIndex >= 0) + this._backForwardList.splice(oldIndex + 1, this._backForwardList.length - oldIndex); + + // Check for a previous entry of the same object in _backForwardList. + // If one is found, remove it and update _currentBackForwardIndex to match. + var previousEntryIndex = this._backForwardList.indexOf(scriptOrResource); + if (previousEntryIndex !== -1) { + this._backForwardList.splice(previousEntryIndex, 1); + --this._currentBackForwardIndex; + } + + this._backForwardList.push(scriptOrResource); + ++this._currentBackForwardIndex; + + this._updateBackAndForwardButtons(); + } + + this.visibleView = view; + + if (line) { + if (view.revealLine) + view.revealLine(line); + if (view.highlightLine && shouldHighlightLine) + view.highlightLine(line); + } + + var option; + if (scriptOrResource instanceof WebInspector.Script) { + option = scriptOrResource.filesSelectOption; + console.assert(option); + } else { + var url = scriptOrResource.url; + var script = this._scriptsForURLsInFilesSelect[url]; + if (script) + option = script.filesSelectOption; + } + + if (option) + this.filesSelectElement.selectedIndex = option.index; + }, + + _addScriptToFilesMenu: function(script) + { + if (script.resource && this._scriptsForURLsInFilesSelect[script.sourceURL]) + return; + + this._scriptsForURLsInFilesSelect[script.sourceURL] = script; + + var select = this.filesSelectElement; + + var option = document.createElement("option"); + option.representedObject = (script.resource || script); + option.text = (script.sourceURL ? WebInspector.displayNameForURL(script.sourceURL) : WebInspector.UIString("(program)")); + + function optionCompare(a, b) + { + var aTitle = a.text.toLowerCase(); + var bTitle = b.text.toLowerCase(); + if (aTitle < bTitle) + return -1; + else if (aTitle > bTitle) + return 1; + + var aSourceID = a.representedObject.sourceID; + var bSourceID = b.representedObject.sourceID; + if (aSourceID < bSourceID) + return -1; + else if (aSourceID > bSourceID) + return 1; + return 0; + } + + var insertionIndex = insertionIndexForObjectInListSortedByFunction(option, select.childNodes, optionCompare); + if (insertionIndex < 0) + select.appendChild(option); + else + select.insertBefore(option, select.childNodes.item(insertionIndex)); + + script.filesSelectOption = option; + + // Call _showScriptOrResource if the option we just appended ended up being selected. + // This will happen for the first item added to the menu. + if (select.options[select.selectedIndex] === option) + this._showScriptOrResource(option.representedObject); + }, + + _clearCurrentExecutionLine: function() + { + if (this._executionSourceFrame) + this._executionSourceFrame.executionLine = 0; + delete this._executionSourceFrame; + }, + + _callFrameSelected: function() + { + this._clearCurrentExecutionLine(); + + var callStackPane = this.sidebarPanes.callstack; + var currentFrame = callStackPane.selectedCallFrame; + if (!currentFrame) + return; + + this.sidebarPanes.scopechain.update(currentFrame); + + var scriptOrResource = this._sourceIDMap[currentFrame.sourceID]; + this._showScriptOrResource(scriptOrResource, currentFrame.line); + + this._executionSourceFrame = this._sourceFrameForScriptOrResource(scriptOrResource); + if (this._executionSourceFrame) + this._executionSourceFrame.executionLine = currentFrame.line; + }, + + _changeVisibleFile: function(event) + { + var select = this.filesSelectElement; + this._showScriptOrResource(select.options[select.selectedIndex].representedObject); + }, + + _startSidebarResizeDrag: function(event) + { + WebInspector.elementDragStart(this.sidebarElement, this._sidebarResizeDrag.bind(this), this._endSidebarResizeDrag.bind(this), event, "col-resize"); + + if (event.target === this.sidebarResizeWidgetElement) + this._dragOffset = (event.target.offsetWidth - (event.pageX - event.target.totalOffsetLeft)); + else + this._dragOffset = 0; + }, + + _endSidebarResizeDrag: function(event) + { + WebInspector.elementDragEnd(event); + + delete this._dragOffset; + }, + + _sidebarResizeDrag: function(event) + { + var x = event.pageX + this._dragOffset; + var newWidth = Number.constrain(window.innerWidth - x, Preferences.minScriptsSidebarWidth, window.innerWidth * 0.66); + + this.sidebarElement.style.width = newWidth + "px"; + this.sidebarButtonsElement.style.width = newWidth + "px"; + this.viewsContainerElement.style.right = newWidth + "px"; + this.sidebarResizeWidgetElement.style.right = newWidth + "px"; + this.sidebarResizeElement.style.right = (newWidth - 3) + "px"; + + event.preventDefault(); + }, + + _updatePauseOnExceptionsButton: function() + { + if (InspectorController.pauseOnExceptions()) { + this.pauseOnExceptionButton.title = WebInspector.UIString("Don't pause on exceptions."); + this.pauseOnExceptionButton.addStyleClass("toggled-on"); + } else { + this.pauseOnExceptionButton.title = WebInspector.UIString("Pause on exceptions."); + this.pauseOnExceptionButton.removeStyleClass("toggled-on"); + } + }, + + _updateDebuggerButtons: function() + { + if (InspectorController.debuggerEnabled()) { + this.enableToggleButton.title = WebInspector.UIString("Debugging enabled. Click to disable."); + this.enableToggleButton.addStyleClass("toggled-on"); + this.pauseOnExceptionButton.removeStyleClass("hidden"); + this.panelEnablerView.visible = false; + } else { + this.enableToggleButton.title = WebInspector.UIString("Debugging disabled. Click to enable."); + this.enableToggleButton.removeStyleClass("toggled-on"); + this.pauseOnExceptionButton.addStyleClass("hidden"); + this.panelEnablerView.visible = true; + } + + this._updatePauseOnExceptionsButton(); + + if (this._paused) { + this.pauseButton.addStyleClass("paused"); + + this.pauseButton.disabled = false; + this.stepOverButton.disabled = false; + this.stepIntoButton.disabled = false; + this.stepOutButton.disabled = false; + + this.debuggerStatusElement.textContent = WebInspector.UIString("Paused"); + } else { + this.pauseButton.removeStyleClass("paused"); + + this.pauseButton.disabled = this._waitingToPause; + this.stepOverButton.disabled = true; + this.stepIntoButton.disabled = true; + this.stepOutButton.disabled = true; + + if (this._waitingToPause) + this.debuggerStatusElement.textContent = WebInspector.UIString("Pausing"); + else if (this._stepping) + this.debuggerStatusElement.textContent = WebInspector.UIString("Stepping"); + else + this.debuggerStatusElement.textContent = ""; + } + }, + + _updateBackAndForwardButtons: function() + { + this.backButton.disabled = this._currentBackForwardIndex <= 0; + this.forwardButton.disabled = this._currentBackForwardIndex >= (this._backForwardList.length - 1); + }, + + _clearInterface: function() + { + this.sidebarPanes.callstack.update(null); + this.sidebarPanes.scopechain.update(null); + + this._clearCurrentExecutionLine(); + this._updateDebuggerButtons(); + }, + + _goBack: function() + { + if (this._currentBackForwardIndex <= 0) { + console.error("Can't go back from index " + this._currentBackForwardIndex); + return; + } + + this._showScriptOrResource(this._backForwardList[--this._currentBackForwardIndex], null, false, true); + this._updateBackAndForwardButtons(); + }, + + _goForward: function() + { + if (this._currentBackForwardIndex >= this._backForwardList.length - 1) { + console.error("Can't go forward from index " + this._currentBackForwardIndex); + return; + } + + this._showScriptOrResource(this._backForwardList[++this._currentBackForwardIndex], null, false, true); + this._updateBackAndForwardButtons(); + }, + + _enableDebugging: function() + { + if (InspectorController.debuggerEnabled()) + return; + this._toggleDebugging(); + }, + + _toggleDebugging: function() + { + this._paused = false; + this._waitingToPause = false; + this._stepping = false; + + if (InspectorController.debuggerEnabled()) + InspectorController.disableDebugger(); + else + InspectorController.enableDebugger(); + }, + + _togglePauseOnExceptions: function() + { + InspectorController.setPauseOnExceptions(!InspectorController.pauseOnExceptions()); + this._updatePauseOnExceptionsButton(); + }, + + _togglePause: function() + { + if (this._paused) { + this._paused = false; + this._waitingToPause = false; + InspectorController.resumeDebugger(); + } else { + this._stepping = false; + this._waitingToPause = true; + InspectorController.pauseInDebugger(); + } + + this._clearInterface(); + }, + + _stepOverClicked: function() + { + this._paused = false; + this._stepping = true; + + this._clearInterface(); + + InspectorController.stepOverStatementInDebugger(); + }, + + _stepIntoClicked: function() + { + this._paused = false; + this._stepping = true; + + this._clearInterface(); + + InspectorController.stepIntoStatementInDebugger(); + }, + + _stepOutClicked: function() + { + this._paused = false; + this._stepping = true; + + this._clearInterface(); + + InspectorController.stepOutOfFunctionInDebugger(); + } +} + +WebInspector.ScriptsPanel.prototype.__proto__ = WebInspector.Panel.prototype; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/SidebarPane.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/SidebarPane.js new file mode 100644 index 0000000..af9e5f9 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/SidebarPane.js @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2007 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. + * 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. + */ + +WebInspector.SidebarPane = function(title) +{ + this.element = document.createElement("div"); + this.element.className = "pane"; + + this.titleElement = document.createElement("div"); + this.titleElement.className = "title"; + this.titleElement.addEventListener("click", this.toggleExpanded.bind(this), false); + + this.bodyElement = document.createElement("div"); + this.bodyElement.className = "body"; + + this.element.appendChild(this.titleElement); + this.element.appendChild(this.bodyElement); + + this.title = title; + this.growbarVisible = false; + this.expanded = false; +} + +WebInspector.SidebarPane.prototype = { + get title() + { + return this._title; + }, + + set title(x) + { + if (this._title === x) + return; + this._title = x; + this.titleElement.textContent = x; + }, + + get growbarVisible() + { + return this._growbarVisible; + }, + + set growbarVisible(x) + { + if (this._growbarVisible === x) + return; + + this._growbarVisible = x; + + if (x && !this._growbarElement) { + this._growbarElement = document.createElement("div"); + this._growbarElement.className = "growbar"; + this.element.appendChild(this._growbarElement); + } else if (!x && this._growbarElement) { + if (this._growbarElement.parentNode) + this._growbarElement.parentNode(this._growbarElement); + delete this._growbarElement; + } + }, + + get expanded() + { + return this._expanded; + }, + + set expanded(x) + { + if (x) + this.expand(); + else + this.collapse(); + }, + + expand: function() + { + if (this._expanded) + return; + this._expanded = true; + this.element.addStyleClass("expanded"); + if (this.onexpand) + this.onexpand(this); + }, + + collapse: function() + { + if (!this._expanded) + return; + this._expanded = false; + this.element.removeStyleClass("expanded"); + if (this.oncollapse) + this.oncollapse(this); + }, + + toggleExpanded: function() + { + this.expanded = !this.expanded; + } +} + +WebInspector.SidebarPane.prototype.__proto__ = WebInspector.Object.prototype; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/SidebarTreeElement.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/SidebarTreeElement.js new file mode 100644 index 0000000..c08b0ef --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/SidebarTreeElement.js @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2008 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. ``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 + * 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.SidebarSectionTreeElement = function(title, representedObject, hasChildren) +{ + TreeElement.call(this, title.escapeHTML(), representedObject || {}, hasChildren); +} + +WebInspector.SidebarSectionTreeElement.prototype = { + selectable: false, + + get smallChildren() + { + return this._smallChildren; + }, + + set smallChildren(x) + { + if (this._smallChildren === x) + return; + + this._smallChildren = x; + + if (this._smallChildren) + this._childrenListNode.addStyleClass("small"); + else + this._childrenListNode.removeStyleClass("small"); + }, + + onattach: function() + { + this._listItemNode.addStyleClass("sidebar-tree-section"); + }, + + onreveal: function() + { + if (this.listItemElement) + this.listItemElement.scrollIntoViewIfNeeded(false); + } +} + +WebInspector.SidebarSectionTreeElement.prototype.__proto__ = TreeElement.prototype; + +WebInspector.SidebarTreeElement = function(className, title, subtitle, representedObject, hasChildren) +{ + TreeElement.call(this, "", representedObject || {}, hasChildren); + + if (hasChildren) { + this.disclosureButton = document.createElement("button"); + this.disclosureButton.className = "disclosure-button"; + } + + if (!this.iconElement) { + this.iconElement = document.createElement("img"); + this.iconElement.className = "icon"; + } + + this.statusElement = document.createElement("div"); + this.statusElement.className = "status"; + + this.titlesElement = document.createElement("div"); + this.titlesElement.className = "titles"; + + this.titleElement = document.createElement("span"); + this.titleElement.className = "title"; + this.titlesElement.appendChild(this.titleElement); + + this.subtitleElement = document.createElement("span"); + this.subtitleElement.className = "subtitle"; + this.titlesElement.appendChild(this.subtitleElement); + + this.className = className; + this.mainTitle = title; + this.subtitle = subtitle; +} + +WebInspector.SidebarTreeElement.prototype = { + get small() + { + return this._small; + }, + + set small(x) + { + this._small = x; + + if (this._listItemNode) { + if (this._small) + this._listItemNode.addStyleClass("small"); + else + this._listItemNode.removeStyleClass("small"); + } + }, + + get mainTitle() + { + return this._mainTitle; + }, + + set mainTitle(x) + { + this._mainTitle = x; + this.refreshTitles(); + }, + + get subtitle() + { + return this._subtitle; + }, + + set subtitle(x) + { + this._subtitle = x; + this.refreshTitles(); + }, + + get bubbleText() + { + return this._bubbleText; + }, + + set bubbleText(x) + { + if (!this.bubbleElement) { + this.bubbleElement = document.createElement("div"); + this.bubbleElement.className = "bubble"; + this.statusElement.appendChild(this.bubbleElement); + } + + this._bubbleText = x; + this.bubbleElement.textContent = x; + }, + + refreshTitles: function() + { + var mainTitle = this.mainTitle; + if (this.titleElement.textContent !== mainTitle) + this.titleElement.textContent = mainTitle; + + var subtitle = this.subtitle; + if (subtitle) { + if (this.subtitleElement.textContent !== subtitle) + this.subtitleElement.textContent = subtitle; + this.titlesElement.removeStyleClass("no-subtitle"); + } else + this.titlesElement.addStyleClass("no-subtitle"); + }, + + isEventWithinDisclosureTriangle: function(event) + { + return event.target === this.disclosureButton; + }, + + onattach: function() + { + this._listItemNode.addStyleClass("sidebar-tree-item"); + + if (this.className) + this._listItemNode.addStyleClass(this.className); + + if (this.small) + this._listItemNode.addStyleClass("small"); + + if (this.hasChildren && this.disclosureButton) + this._listItemNode.appendChild(this.disclosureButton); + + this._listItemNode.appendChild(this.iconElement); + this._listItemNode.appendChild(this.statusElement); + this._listItemNode.appendChild(this.titlesElement); + }, + + onreveal: function() + { + if (this._listItemNode) + this._listItemNode.scrollIntoViewIfNeeded(false); + } +} + +WebInspector.SidebarTreeElement.prototype.__proto__ = TreeElement.prototype; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/SourceFrame.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/SourceFrame.js new file mode 100644 index 0000000..1ab321f --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/SourceFrame.js @@ -0,0 +1,703 @@ +/* + * Copyright (C) 2008 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. ``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 + * 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.SourceFrame = function(element, addBreakpointDelegate) +{ + this.messages = []; + this.breakpoints = []; + + this.addBreakpointDelegate = addBreakpointDelegate; + + this.element = element || document.createElement("iframe"); + this.element.addStyleClass("source-view-frame"); + this.element.setAttribute("viewsource", "true"); + + this.element.addEventListener("load", this._loaded.bind(this), false); +} + +WebInspector.SourceFrame.prototype = { + get executionLine() + { + return this._executionLine; + }, + + set executionLine(x) + { + if (this._executionLine === x) + return; + + var previousLine = this._executionLine; + this._executionLine = x; + + this._updateExecutionLine(previousLine); + }, + + get autoSizesToFitContentHeight() + { + return this._autoSizesToFitContentHeight; + }, + + set autoSizesToFitContentHeight(x) + { + if (this._autoSizesToFitContentHeight === x) + return; + + this._autoSizesToFitContentHeight = x; + + if (this._autoSizesToFitContentHeight) { + this._windowResizeListener = this._windowResized.bind(this); + window.addEventListener("resize", this._windowResizeListener, false); + this.sizeToFitContentHeight(); + } else { + this.element.style.removeProperty("height"); + if (this.element.contentDocument) + this.element.contentDocument.body.removeStyleClass("webkit-height-sized-to-fit"); + window.removeEventListener("resize", this._windowResizeListener, false); + delete this._windowResizeListener; + } + }, + + sourceRow: function(lineNumber) + { + if (!lineNumber || !this.element.contentDocument) + return; + + var table = this.element.contentDocument.getElementsByTagName("table")[0]; + if (!table) + return; + + var rows = table.rows; + + // Line numbers are a 1-based index, but the rows collection is 0-based. + --lineNumber; + + return rows[lineNumber]; + }, + + lineNumberForSourceRow: function(sourceRow) + { + // Line numbers are a 1-based index, but the rows collection is 0-based. + var lineNumber = 0; + while (sourceRow) { + ++lineNumber; + sourceRow = sourceRow.previousSibling; + } + + return lineNumber; + }, + + revealLine: function(lineNumber) + { + var row = this.sourceRow(lineNumber); + if (row) + row.scrollIntoViewIfNeeded(true); + }, + + addBreakpoint: function(breakpoint) + { + this.breakpoints.push(breakpoint); + breakpoint.addEventListener("enabled", this._breakpointEnableChanged, this); + breakpoint.addEventListener("disabled", this._breakpointEnableChanged, this); + this._addBreakpointToSource(breakpoint); + }, + + removeBreakpoint: function(breakpoint) + { + this.breakpoints.remove(breakpoint); + breakpoint.removeEventListener("enabled", null, this); + breakpoint.removeEventListener("disabled", null, this); + this._removeBreakpointFromSource(breakpoint); + }, + + addMessage: function(msg) + { + // Don't add the message if there is no message or valid line or if the msg isn't an error or warning. + if (!msg.message || msg.line <= 0 || !msg.isErrorOrWarning()) + return; + this.messages.push(msg); + this._addMessageToSource(msg); + }, + + clearMessages: function() + { + this.messages = []; + + if (!this.element.contentDocument) + return; + + var bubbles = this.element.contentDocument.querySelectorAll(".webkit-html-message-bubble"); + if (!bubbles) + return; + + for (var i = 0; i < bubbles.length; ++i) { + var bubble = bubbles[i]; + bubble.parentNode.removeChild(bubble); + } + }, + + sizeToFitContentHeight: function() + { + if (this.element.contentDocument) { + this.element.style.setProperty("height", this.element.contentDocument.body.offsetHeight + "px"); + this.element.contentDocument.body.addStyleClass("webkit-height-sized-to-fit"); + } + }, + + _highlightLineEnds: function(event) + { + event.target.parentNode.removeStyleClass("webkit-highlighted-line"); + }, + + highlightLine: function(lineNumber) + { + var sourceRow = this.sourceRow(lineNumber); + if (!sourceRow) + return; + var line = sourceRow.getElementsByClassName('webkit-line-content')[0]; + // Trick to reset the animation if the user clicks on the same link + // Using a timeout to avoid coalesced style updates + line.style.setProperty("-webkit-animation-name", "none"); + setTimeout(function () { + line.style.removeProperty("-webkit-animation-name"); + sourceRow.addStyleClass("webkit-highlighted-line"); + }, 0); + }, + + _loaded: function() + { + WebInspector.addMainEventListeners(this.element.contentDocument); + this.element.contentDocument.addEventListener("mousedown", this._documentMouseDown.bind(this), true); + this.element.contentDocument.addEventListener("webkitAnimationEnd", this._highlightLineEnds.bind(this), false); + + var headElement = this.element.contentDocument.getElementsByTagName("head")[0]; + if (!headElement) { + headElement = this.element.contentDocument.createElement("head"); + this.element.contentDocument.documentElement.insertBefore(headElement, this.element.contentDocument.documentElement.firstChild); + } + + var styleElement = this.element.contentDocument.createElement("style"); + headElement.appendChild(styleElement); + + // Add these style rules here since they are specific to the Inspector. They also behave oddly and not + // all properties apply if added to view-source.css (becuase it is a user agent sheet.) + var styleText = ".webkit-line-number { background-repeat: no-repeat; background-position: right 1px; }\n"; + styleText += ".webkit-breakpoint .webkit-line-number { color: white; background-image: -webkit-canvas(breakpoint); }\n"; + styleText += ".webkit-breakpoint-disabled .webkit-line-number { color: white; background-image: -webkit-canvas(breakpoint-disabled); }\n"; + styleText += ".webkit-execution-line .webkit-line-number { color: transparent; background-image: -webkit-canvas(program-counter); }\n"; + styleText += ".webkit-breakpoint.webkit-execution-line .webkit-line-number { color: transparent; background-image: -webkit-canvas(breakpoint-program-counter); }\n"; + styleText += ".webkit-breakpoint-disabled.webkit-execution-line .webkit-line-number { color: transparent; background-image: -webkit-canvas(breakpoint-disabled-program-counter); }\n"; + styleText += ".webkit-execution-line .webkit-line-content { background-color: rgb(171, 191, 254); outline: 1px solid rgb(64, 115, 244); }\n"; + styleText += ".webkit-height-sized-to-fit { overflow-y: hidden }\n"; + styleText += ".webkit-line-content { background-color: white; }\n"; + styleText += "@-webkit-keyframes fadeout {from {background-color: rgb(255, 255, 120);} to { background-color: white;}}\n"; + styleText += ".webkit-highlighted-line .webkit-line-content { background-color: rgb(255, 255, 120); -webkit-animation: 'fadeout' 2s 500ms}\n"; + styleText += ".webkit-javascript-comment { color: rgb(0, 116, 0); }\n"; + styleText += ".webkit-javascript-keyword { color: rgb(170, 13, 145); }\n"; + styleText += ".webkit-javascript-number { color: rgb(28, 0, 207); }\n"; + styleText += ".webkit-javascript-string, .webkit-javascript-regexp { color: rgb(196, 26, 22); }\n"; + + styleElement.textContent = styleText; + + this._needsProgramCounterImage = true; + this._needsBreakpointImages = true; + + this.element.contentWindow.Element.prototype.addStyleClass = Element.prototype.addStyleClass; + this.element.contentWindow.Element.prototype.removeStyleClass = Element.prototype.removeStyleClass; + this.element.contentWindow.Element.prototype.removeMatchingStyleClasses = Element.prototype.removeMatchingStyleClasses; + this.element.contentWindow.Element.prototype.hasStyleClass = Element.prototype.hasStyleClass; + this.element.contentWindow.Node.prototype.enclosingNodeOrSelfWithNodeName = Node.prototype.enclosingNodeOrSelfWithNodeName; + this.element.contentWindow.Node.prototype.enclosingNodeOrSelfWithNodeNameInArray = Node.prototype.enclosingNodeOrSelfWithNodeNameInArray; + + this._addExistingMessagesToSource(); + this._addExistingBreakpointsToSource(); + this._updateExecutionLine(); + if (this._executionLine) + this.revealLine(this._executionLine); + + if (this.autoSizesToFitContentHeight) + this.sizeToFitContentHeight(); + }, + + _windowResized: function(event) + { + if (!this._autoSizesToFitContentHeight) + return; + this.sizeToFitContentHeight(); + }, + + _documentMouseDown: function(event) + { + if (!event.target.hasStyleClass("webkit-line-number")) + return; + + var sourceRow = event.target.enclosingNodeOrSelfWithNodeName("tr"); + if (sourceRow._breakpointObject) + sourceRow._breakpointObject.enabled = !sourceRow._breakpointObject.enabled; + else if (this.addBreakpointDelegate) + this.addBreakpointDelegate(this.lineNumberForSourceRow(sourceRow)); + }, + + _breakpointEnableChanged: function(event) + { + var breakpoint = event.target; + var sourceRow = this.sourceRow(breakpoint.line); + if (!sourceRow) + return; + + sourceRow.addStyleClass("webkit-breakpoint"); + + if (breakpoint.enabled) + sourceRow.removeStyleClass("webkit-breakpoint-disabled"); + else + sourceRow.addStyleClass("webkit-breakpoint-disabled"); + }, + + _updateExecutionLine: function(previousLine) + { + if (previousLine) { + var sourceRow = this.sourceRow(previousLine); + if (sourceRow) + sourceRow.removeStyleClass("webkit-execution-line"); + } + + if (!this._executionLine) + return; + + this._drawProgramCounterImageIfNeeded(); + + var sourceRow = this.sourceRow(this._executionLine); + if (sourceRow) + sourceRow.addStyleClass("webkit-execution-line"); + }, + + _addExistingBreakpointsToSource: function() + { + var length = this.breakpoints.length; + for (var i = 0; i < length; ++i) + this._addBreakpointToSource(this.breakpoints[i]); + }, + + _addBreakpointToSource: function(breakpoint) + { + var sourceRow = this.sourceRow(breakpoint.line); + if (!sourceRow) + return; + + this._drawBreakpointImagesIfNeeded(); + + sourceRow._breakpointObject = breakpoint; + + sourceRow.addStyleClass("webkit-breakpoint"); + if (!breakpoint.enabled) + sourceRow.addStyleClass("webkit-breakpoint-disabled"); + }, + + _removeBreakpointFromSource: function(breakpoint) + { + var sourceRow = this.sourceRow(breakpoint.line); + if (!sourceRow) + return; + + delete sourceRow._breakpointObject; + + sourceRow.removeStyleClass("webkit-breakpoint"); + sourceRow.removeStyleClass("webkit-breakpoint-disabled"); + }, + + _incrementMessageRepeatCount: function(msg, repeatDelta) + { + if (!msg._resourceMessageLineElement) + return; + + if (!msg._resourceMessageRepeatCountElement) { + var repeatedElement = document.createElement("span"); + msg._resourceMessageLineElement.appendChild(repeatedElement); + msg._resourceMessageRepeatCountElement = repeatedElement; + } + + msg.repeatCount += repeatDelta; + msg._resourceMessageRepeatCountElement.textContent = WebInspector.UIString(" (repeated %d times)", msg.repeatCount); + }, + + _addExistingMessagesToSource: function() + { + var length = this.messages.length; + for (var i = 0; i < length; ++i) + this._addMessageToSource(this.messages[i]); + }, + + _addMessageToSource: function(msg) + { + var row = this.sourceRow(msg.line); + if (!row) + return; + + var cell = row.cells[1]; + if (!cell) + return; + + var messageBubbleElement = cell.lastChild; + if (!messageBubbleElement || messageBubbleElement.nodeType !== Node.ELEMENT_NODE || !messageBubbleElement.hasStyleClass("webkit-html-message-bubble")) { + messageBubbleElement = this.element.contentDocument.createElement("div"); + messageBubbleElement.className = "webkit-html-message-bubble"; + cell.appendChild(messageBubbleElement); + } + + if (!row.messages) + row.messages = []; + + for (var i = 0; i < row.messages.length; ++i) { + if (row.messages[i].isEqual(msg, true)) { + this._incrementMessageRepeatCount(row.messages[i], msg.repeatDelta); + return; + } + } + + row.messages.push(msg); + + var imageURL; + switch (msg.level) { + case WebInspector.ConsoleMessage.MessageLevel.Error: + messageBubbleElement.addStyleClass("webkit-html-error-message"); + imageURL = "Images/errorIcon.png"; + break; + case WebInspector.ConsoleMessage.MessageLevel.Warning: + messageBubbleElement.addStyleClass("webkit-html-warning-message"); + imageURL = "Images/warningIcon.png"; + break; + } + + var messageLineElement = this.element.contentDocument.createElement("div"); + messageLineElement.className = "webkit-html-message-line"; + messageBubbleElement.appendChild(messageLineElement); + + // Create the image element in the Inspector's document so we can use relative image URLs. + var image = document.createElement("img"); + image.src = imageURL; + image.className = "webkit-html-message-icon"; + + // Adopt the image element since it wasn't created in element's contentDocument. + image = this.element.contentDocument.adoptNode(image); + messageLineElement.appendChild(image); + messageLineElement.appendChild(this.element.contentDocument.createTextNode(msg.message)); + + msg._resourceMessageLineElement = messageLineElement; + }, + + _drawProgramCounterInContext: function(ctx, glow) + { + if (glow) + ctx.save(); + + ctx.beginPath(); + ctx.moveTo(17, 2); + ctx.lineTo(19, 2); + ctx.lineTo(19, 0); + ctx.lineTo(21, 0); + ctx.lineTo(26, 5.5); + ctx.lineTo(21, 11); + ctx.lineTo(19, 11); + ctx.lineTo(19, 9); + ctx.lineTo(17, 9); + ctx.closePath(); + ctx.fillStyle = "rgb(142, 5, 4)"; + + if (glow) { + ctx.shadowBlur = 4; + ctx.shadowColor = "rgb(255, 255, 255)"; + ctx.shadowOffsetX = -1; + ctx.shadowOffsetY = 0; + } + + ctx.fill(); + ctx.fill(); // Fill twice to get a good shadow and darker anti-aliased pixels. + + if (glow) + ctx.restore(); + }, + + _drawProgramCounterImageIfNeeded: function() + { + if (!this._needsProgramCounterImage || !this.element.contentDocument) + return; + + var ctx = this.element.contentDocument.getCSSCanvasContext("2d", "program-counter", 26, 11); + ctx.clearRect(0, 0, 26, 11); + this._drawProgramCounterInContext(ctx, true); + + delete this._needsProgramCounterImage; + }, + + _drawBreakpointImagesIfNeeded: function() + { + if (!this._needsBreakpointImages || !this.element.contentDocument) + return; + + function drawBreakpoint(ctx, disabled) + { + ctx.beginPath(); + ctx.moveTo(0, 2); + ctx.lineTo(2, 0); + ctx.lineTo(21, 0); + ctx.lineTo(26, 5.5); + ctx.lineTo(21, 11); + ctx.lineTo(2, 11); + ctx.lineTo(0, 9); + ctx.closePath(); + ctx.fillStyle = "rgb(1, 142, 217)"; + ctx.strokeStyle = "rgb(0, 103, 205)"; + ctx.lineWidth = 3; + ctx.fill(); + ctx.save(); + ctx.clip(); + ctx.stroke(); + ctx.restore(); + + if (!disabled) + return; + + ctx.save(); + ctx.globalCompositeOperation = "destination-out"; + ctx.fillStyle = "rgba(0, 0, 0, 0.5)"; + ctx.fillRect(0, 0, 26, 11); + ctx.restore(); + } + + var ctx = this.element.contentDocument.getCSSCanvasContext("2d", "breakpoint", 26, 11); + ctx.clearRect(0, 0, 26, 11); + drawBreakpoint(ctx); + + var ctx = this.element.contentDocument.getCSSCanvasContext("2d", "breakpoint-program-counter", 26, 11); + ctx.clearRect(0, 0, 26, 11); + drawBreakpoint(ctx); + ctx.clearRect(20, 0, 6, 11); + this._drawProgramCounterInContext(ctx, true); + + var ctx = this.element.contentDocument.getCSSCanvasContext("2d", "breakpoint-disabled", 26, 11); + ctx.clearRect(0, 0, 26, 11); + drawBreakpoint(ctx, true); + + var ctx = this.element.contentDocument.getCSSCanvasContext("2d", "breakpoint-disabled-program-counter", 26, 11); + ctx.clearRect(0, 0, 26, 11); + drawBreakpoint(ctx, true); + ctx.clearRect(20, 0, 6, 11); + this._drawProgramCounterInContext(ctx, true); + + delete this._needsBreakpointImages; + }, + + syntaxHighlightJavascript: function() + { + var table = this.element.contentDocument.getElementsByTagName("table")[0]; + if (!table) + return; + + function deleteContinueFlags(cell) + { + if (!cell) + return; + delete cell._commentContinues; + delete cell._singleQuoteStringContinues; + delete cell._doubleQuoteStringContinues; + delete cell._regexpContinues; + } + + function createSpan(content, className) + { + var span = document.createElement("span"); + span.className = className; + span.appendChild(document.createTextNode(content)); + return span; + } + + function generateFinder(regex, matchNumber, className) + { + return function(str) { + var match = regex.exec(str); + if (!match) + return null; + previousMatchLength = match[matchNumber].length; + return createSpan(match[matchNumber], className); + }; + } + + var findNumber = generateFinder(/^(-?(\d+\.?\d*([eE][+-]\d+)?|0[xX]\h+|Infinity)|NaN)(?:\W|$)/, 1, "webkit-javascript-number"); + var findKeyword = generateFinder(/^(null|true|false|break|case|catch|const|default|finally|for|instanceof|new|var|continue|function|return|void|delete|if|this|do|while|else|in|switch|throw|try|typeof|with|debugger|class|enum|export|extends|import|super|get|set)(?:\W|$)/, 1, "webkit-javascript-keyword"); + var findSingleLineString = generateFinder(/^"(?:[^"\\]|\\.)*"|^'([^'\\]|\\.)*'/, 0, "webkit-javascript-string"); // " this quote keeps Xcode happy + var findMultilineCommentStart = generateFinder(/^\/\*.*$/, 0, "webkit-javascript-comment"); + var findMultilineCommentEnd = generateFinder(/^.*?\*\//, 0, "webkit-javascript-comment"); + var findMultilineSingleQuoteStringStart = generateFinder(/^'(?:[^'\\]|\\.)*\\$/, 0, "webkit-javascript-string"); + var findMultilineSingleQuoteStringEnd = generateFinder(/^(?:[^'\\]|\\.)*?'/, 0, "webkit-javascript-string"); + var findMultilineDoubleQuoteStringStart = generateFinder(/^"(?:[^"\\]|\\.)*\\$/, 0, "webkit-javascript-string"); + var findMultilineDoubleQuoteStringEnd = generateFinder(/^(?:[^"\\]|\\.)*?"/, 0, "webkit-javascript-string"); + var findMultilineRegExpEnd = generateFinder(/^(?:[^\/\\]|\\.)*?\/([gim]{0,3})/, 0, "webkit-javascript-regexp"); + var findSingleLineComment = generateFinder(/^\/\/.*|^\/\*.*?\*\//, 0, "webkit-javascript-comment"); + + function findMultilineRegExpStart(str) + { + var match = /^\/(?:[^\/\\]|\\.)*\\$/.exec(str); + if (!match || !/\\|\$|\.[\?\*\+]|[^\|]\|[^\|]/.test(match[0])) + return null; + var node = createSpan(match[0], "webkit-javascript-regexp"); + previousMatchLength = match[0].length; + return node; + } + + function findSingleLineRegExp(str) + { + var match = /^(\/(?:[^\/\\]|\\.)*\/([gim]{0,3}))(.?)/.exec(str); + if (!match || !(match[2].length > 0 || /\\|\$|\.[\?\*\+]|[^\|]\|[^\|]/.test(match[1]) || /\.|;|,/.test(match[3]))) + return null; + var node = createSpan(match[1], "webkit-javascript-regexp"); + previousMatchLength = match[1].length; + return node; + } + + function syntaxHighlightJavascriptLine(line, prevLine) + { + var messageBubble = line.lastChild; + if (messageBubble && messageBubble.nodeType === Node.ELEMENT_NODE && messageBubble.hasStyleClass("webkit-html-message-bubble")) + line.removeChild(messageBubble); + else + messageBubble = null; + + var code = line.textContent; + + while (line.firstChild) + line.removeChild(line.firstChild); + + var token; + var tmp = 0; + var i = 0; + previousMatchLength = 0; + + if (prevLine) { + if (prevLine._commentContinues) { + if (!(token = findMultilineCommentEnd(code))) { + token = createSpan(code, "webkit-javascript-comment"); + line._commentContinues = true; + } + } else if (prevLine._singleQuoteStringContinues) { + if (!(token = findMultilineSingleQuoteStringEnd(code))) { + token = createSpan(code, "webkit-javascript-string"); + line._singleQuoteStringContinues = true; + } + } else if (prevLine._doubleQuoteStringContinues) { + if (!(token = findMultilineDoubleQuoteStringEnd(code))) { + token = createSpan(code, "webkit-javascript-string"); + line._doubleQuoteStringContinues = true; + } + } else if (prevLine._regexpContinues) { + if (!(token = findMultilineRegExpEnd(code))) { + token = createSpan(code, "webkit-javascript-regexp"); + line._regexpContinues = true; + } + } + if (token) { + i += previousMatchLength ? previousMatchLength : code.length; + tmp = i; + line.appendChild(token); + } + } + + for ( ; i < code.length; ++i) { + var codeFragment = code.substr(i); + var prevChar = code[i - 1]; + token = findSingleLineComment(codeFragment); + if (!token) { + if ((token = findMultilineCommentStart(codeFragment))) + line._commentContinues = true; + else if (!prevChar || /^\W/.test(prevChar)) { + token = findNumber(codeFragment, code[i - 1]) || + findKeyword(codeFragment, code[i - 1]) || + findSingleLineString(codeFragment) || + findSingleLineRegExp(codeFragment); + if (!token) { + if (token = findMultilineSingleQuoteStringStart(codeFragment)) + line._singleQuoteStringContinues = true; + else if (token = findMultilineDoubleQuoteStringStart(codeFragment)) + line._doubleQuoteStringContinues = true; + else if (token = findMultilineRegExpStart(codeFragment)) + line._regexpContinues = true; + } + } + } + + if (token) { + if (tmp !== i) + line.appendChild(document.createTextNode(code.substring(tmp, i))); + line.appendChild(token); + i += previousMatchLength - 1; + tmp = i + 1; + } + } + + if (tmp < code.length) + line.appendChild(document.createTextNode(code.substring(tmp, i))); + + if (messageBubble) + line.appendChild(messageBubble); + } + + var i = 0; + var rows = table.rows; + var rowsLength = rows.length; + var previousCell = null; + var previousMatchLength = 0; + var sourceFrame = this; + + // Split up the work into chunks so we don't block the + // UI thread while processing. + + function processChunk() + { + for (var end = Math.min(i + 10, rowsLength); i < end; ++i) { + var row = rows[i]; + if (!row) + continue; + var cell = row.cells[1]; + if (!cell) + continue; + syntaxHighlightJavascriptLine(cell, previousCell); + if (i < (end - 1)) + deleteContinueFlags(previousCell); + previousCell = cell; + } + + if (i >= rowsLength && processChunkInterval) { + deleteContinueFlags(previousCell); + clearInterval(processChunkInterval); + + sourceFrame.dispatchEventToListeners("syntax highlighting complete"); + } + } + + processChunk(); + + var processChunkInterval = setInterval(processChunk, 25); + } +} + +WebInspector.SourceFrame.prototype.__proto__ = WebInspector.Object.prototype; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/SourceView.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/SourceView.js new file mode 100644 index 0000000..ce90dc8 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/SourceView.js @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2007, 2008 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. + * 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. + */ + +WebInspector.SourceView = function(resource) +{ + // Set the sourceFrame first since WebInspector.ResourceView will set headersVisible + // and our override of headersVisible needs the sourceFrame. + this.sourceFrame = new WebInspector.SourceFrame(null, this._addBreakpoint.bind(this)); + + WebInspector.ResourceView.call(this, resource); + + resource.addEventListener("finished", this._resourceLoadingFinished, this); + + this.element.addStyleClass("source"); + + this._frameNeedsSetup = true; + + this.contentElement.appendChild(this.sourceFrame.element); + + var gutterElement = document.createElement("div"); + gutterElement.className = "webkit-line-gutter-backdrop"; + this.element.appendChild(gutterElement); +} + +WebInspector.SourceView.prototype = { + set headersVisible(x) + { + if (x === this._headersVisible) + return; + + var superSetter = WebInspector.ResourceView.prototype.__lookupSetter__("headersVisible"); + if (superSetter) + superSetter.call(this, x); + + this.sourceFrame.autoSizesToFitContentHeight = x; + }, + + show: function(parentElement) + { + WebInspector.ResourceView.prototype.show.call(this, parentElement); + this.setupSourceFrameIfNeeded(); + }, + + hide: function() + { + WebInspector.View.prototype.hide.call(this); + this._currentSearchResultIndex = -1; + }, + + resize: function() + { + if (this.sourceFrame.autoSizesToFitContentHeight) + this.sourceFrame.sizeToFitContentHeight(); + }, + + detach: function() + { + WebInspector.ResourceView.prototype.detach.call(this); + + // FIXME: We need to mark the frame for setup on detach because the frame DOM is cleared + // when it is removed from the document. Is this a bug? + this._frameNeedsSetup = true; + this._sourceFrameSetup = false; + }, + + setupSourceFrameIfNeeded: function() + { + if (!this._frameNeedsSetup) + return; + + this.attach(); + + if (!InspectorController.addResourceSourceToFrame(this.resource.identifier, this.sourceFrame.element)) + return; + + delete this._frameNeedsSetup; + + if (this.resource.type === WebInspector.Resource.Type.Script) { + this.sourceFrame.addEventListener("syntax highlighting complete", this._syntaxHighlightingComplete, this); + this.sourceFrame.syntaxHighlightJavascript(); + } else + this._sourceFrameSetupFinished(); + }, + + _resourceLoadingFinished: function(event) + { + this._frameNeedsSetup = true; + this._sourceFrameSetup = false; + if (this.visible) + this.setupSourceFrameIfNeeded(); + this.resource.removeEventListener("finished", this._resourceLoadingFinished, this); + }, + + _addBreakpoint: function(line) + { + var sourceID = null; + var closestStartingLine = 0; + var scripts = this.resource.scripts; + for (var i = 0; i < scripts.length; ++i) { + var script = scripts[i]; + if (script.startingLine <= line && script.startingLine >= closestStartingLine) { + closestStartingLine = script.startingLine; + sourceID = script.sourceID; + } + } + + if (WebInspector.panels.scripts) { + var breakpoint = new WebInspector.Breakpoint(this.resource.url, line, sourceID); + WebInspector.panels.scripts.addBreakpoint(breakpoint); + } + }, + + // The rest of the methods in this prototype need to be generic enough to work with a ScriptView. + // The ScriptView prototype pulls these methods into it's prototype to avoid duplicate code. + + searchCanceled: function() + { + this._currentSearchResultIndex = -1; + this._searchResults = []; + delete this._delayedFindSearchMatches; + }, + + performSearch: function(query, finishedCallback) + { + // Call searchCanceled since it will reset everything we need before doing a new search. + this.searchCanceled(); + + var lineQueryRegex = /(^|\s)(?:#|line:\s*)(\d+)(\s|$)/i; + var lineQueryMatch = query.match(lineQueryRegex); + if (lineQueryMatch) { + var lineToSearch = parseInt(lineQueryMatch[2]); + + // If there was a space before and after the line query part, replace with a space. + // Otherwise replace with an empty string to eat the prefix or postfix space. + var lineQueryReplacement = (lineQueryMatch[1] && lineQueryMatch[3] ? " " : ""); + var filterlessQuery = query.replace(lineQueryRegex, lineQueryReplacement); + } + + this._searchFinishedCallback = finishedCallback; + + function findSearchMatches(query, finishedCallback) + { + if (isNaN(lineToSearch)) { + // Search the whole document since there was no line to search. + this._searchResults = (InspectorController.search(this.sourceFrame.element.contentDocument, query) || []); + } else { + var sourceRow = this.sourceFrame.sourceRow(lineToSearch); + if (sourceRow) { + if (filterlessQuery) { + // There is still a query string, so search for that string in the line. + this._searchResults = (InspectorController.search(sourceRow, filterlessQuery) || []); + } else { + // Match the whole line, since there was no remaining query string to match. + var rowRange = this.sourceFrame.element.contentDocument.createRange(); + rowRange.selectNodeContents(sourceRow); + this._searchResults = [rowRange]; + } + } + + // Attempt to search for the whole query, just incase it matches a color like "#333". + var wholeQueryMatches = InspectorController.search(this.sourceFrame.element.contentDocument, query); + if (wholeQueryMatches) + this._searchResults = this._searchResults.concat(wholeQueryMatches); + } + + if (this._searchResults) + finishedCallback(this, this._searchResults.length); + } + + if (!this._sourceFrameSetup) { + // The search is performed in _sourceFrameSetupFinished by calling _delayedFindSearchMatches. + this._delayedFindSearchMatches = findSearchMatches.bind(this, query, finishedCallback); + this.setupSourceFrameIfNeeded(); + return; + } + + findSearchMatches.call(this, query, finishedCallback); + }, + + jumpToFirstSearchResult: function() + { + if (!this._searchResults || !this._searchResults.length) + return; + this._currentSearchResultIndex = 0; + this._jumpToSearchResult(this._currentSearchResultIndex); + }, + + jumpToLastSearchResult: function() + { + if (!this._searchResults || !this._searchResults.length) + return; + this._currentSearchResultIndex = (this._searchResults.length - 1); + this._jumpToSearchResult(this._currentSearchResultIndex); + }, + + jumpToNextSearchResult: function() + { + if (!this._searchResults || !this._searchResults.length) + return; + if (++this._currentSearchResultIndex >= this._searchResults.length) + this._currentSearchResultIndex = 0; + this._jumpToSearchResult(this._currentSearchResultIndex); + }, + + jumpToPreviousSearchResult: function() + { + if (!this._searchResults || !this._searchResults.length) + return; + if (--this._currentSearchResultIndex < 0) + this._currentSearchResultIndex = (this._searchResults.length - 1); + this._jumpToSearchResult(this._currentSearchResultIndex); + }, + + showingFirstSearchResult: function() + { + return (this._currentSearchResultIndex === 0); + }, + + showingLastSearchResult: function() + { + return (this._searchResults && this._currentSearchResultIndex === (this._searchResults.length - 1)); + }, + + revealLine: function(lineNumber) + { + this.setupSourceFrameIfNeeded(); + this.sourceFrame.revealLine(lineNumber); + }, + + highlightLine: function(lineNumber) + { + this.setupSourceFrameIfNeeded(); + this.sourceFrame.highlightLine(lineNumber); + }, + + addMessage: function(msg) + { + this.sourceFrame.addMessage(msg); + }, + + clearMessages: function() + { + this.sourceFrame.clearMessages(); + }, + + _jumpToSearchResult: function(index) + { + var foundRange = this._searchResults[index]; + if (!foundRange) + return; + + var selection = this.sourceFrame.element.contentWindow.getSelection(); + selection.removeAllRanges(); + selection.addRange(foundRange); + + if (foundRange.startContainer.scrollIntoViewIfNeeded) + foundRange.startContainer.scrollIntoViewIfNeeded(true); + else if (foundRange.startContainer.parentNode) + foundRange.startContainer.parentNode.scrollIntoViewIfNeeded(true); + }, + + _sourceFrameSetupFinished: function() + { + this._sourceFrameSetup = true; + if (this._delayedFindSearchMatches) { + this._delayedFindSearchMatches(); + delete this._delayedFindSearchMatches; + } + }, + + _syntaxHighlightingComplete: function(event) + { + this._sourceFrameSetupFinished(); + this.sourceFrame.removeEventListener("syntax highlighting complete", null, this); + } +} + +WebInspector.SourceView.prototype.__proto__ = WebInspector.ResourceView.prototype; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/StylesSidebarPane.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/StylesSidebarPane.js new file mode 100644 index 0000000..c30444b --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/StylesSidebarPane.js @@ -0,0 +1,927 @@ +/* + * Copyright (C) 2007 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. + * 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. + */ + +WebInspector.StylesSidebarPane = function() +{ + WebInspector.SidebarPane.call(this, WebInspector.UIString("Styles")); +} + +WebInspector.StylesSidebarPane.prototype = { + update: function(node, editedSection, forceUpdate) + { + var refresh = false; + + if (forceUpdate) + delete this.node; + + if (!forceUpdate && (!node || node === this.node)) + refresh = true; + + if (node && node.nodeType === Node.TEXT_NODE && node.parentNode) + node = node.parentNode; + + if (node && node.nodeType !== Node.ELEMENT_NODE) + node = null; + + if (node) + this.node = node; + else + node = this.node; + + var body = this.bodyElement; + if (!refresh || !node) { + body.removeChildren(); + this.sections = []; + } + + if (!node) + return; + + var styleRules = []; + + if (refresh) { + for (var i = 0; i < this.sections.length; ++i) { + var section = this.sections[i]; + if (section.computedStyle) + section.styleRule.style = node.ownerDocument.defaultView.getComputedStyle(node); + var styleRule = { section: section, style: section.styleRule.style, computedStyle: section.computedStyle }; + styleRules.push(styleRule); + } + } else { + var computedStyle = node.ownerDocument.defaultView.getComputedStyle(node); + styleRules.push({ computedStyle: true, selectorText: WebInspector.UIString("Computed Style"), style: computedStyle, editable: false }); + + var nodeName = node.nodeName.toLowerCase(); + for (var i = 0; i < node.attributes.length; ++i) { + var attr = node.attributes[i]; + if (attr.style) { + var attrStyle = { style: attr.style, editable: false }; + attrStyle.subtitle = WebInspector.UIString("element’s “%s” attribute", attr.name); + attrStyle.selectorText = nodeName + "[" + attr.name; + if (attr.value.length) + attrStyle.selectorText += "=" + attr.value; + attrStyle.selectorText += "]"; + styleRules.push(attrStyle); + } + } + + if (node.style && (node.style.length || Object.hasProperties(node.style.__disabledProperties))) { + var inlineStyle = { selectorText: WebInspector.UIString("Inline Style Attribute"), style: node.style }; + inlineStyle.subtitle = WebInspector.UIString("element’s “%s” attribute", "style"); + styleRules.push(inlineStyle); + } + + var matchedStyleRules = node.ownerDocument.defaultView.getMatchedCSSRules(node, "", !Preferences.showUserAgentStyles); + if (matchedStyleRules) { + // Add rules in reverse order to match the cascade order. + for (var i = (matchedStyleRules.length - 1); i >= 0; --i) { + var rule = matchedStyleRules[i]; + styleRules.push({ style: rule.style, selectorText: rule.selectorText, parentStyleSheet: rule.parentStyleSheet }); + } + } + } + + function deleteDisabledProperty(style, name) + { + if (!style || !name) + return; + if (style.__disabledPropertyValues) + delete style.__disabledPropertyValues[name]; + if (style.__disabledPropertyPriorities) + delete style.__disabledPropertyPriorities[name]; + if (style.__disabledProperties) + delete style.__disabledProperties[name]; + } + + var usedProperties = {}; + var disabledComputedProperties = {}; + var priorityUsed = false; + + // Walk the style rules and make a list of all used and overloaded properties. + for (var i = 0; i < styleRules.length; ++i) { + var styleRule = styleRules[i]; + if (styleRule.computedStyle) + continue; + + styleRule.usedProperties = {}; + + var style = styleRule.style; + for (var j = 0; j < style.length; ++j) { + var name = style[j]; + + if (!priorityUsed && style.getPropertyPriority(name).length) + priorityUsed = true; + + // If the property name is already used by another rule then this rule's + // property is overloaded, so don't add it to the rule's usedProperties. + if (!(name in usedProperties)) + styleRule.usedProperties[name] = true; + + if (name === "font") { + // The font property is not reported as a shorthand. Report finding the individual + // properties so they are visible in computed style. + // FIXME: remove this when http://bugs.webkit.org/show_bug.cgi?id=15598 is fixed. + styleRule.usedProperties["font-family"] = true; + styleRule.usedProperties["font-size"] = true; + styleRule.usedProperties["font-style"] = true; + styleRule.usedProperties["font-variant"] = true; + styleRule.usedProperties["font-weight"] = true; + styleRule.usedProperties["line-height"] = true; + } + + // Delete any disabled properties, since the property does exist. + // This prevents it from showing twice. + deleteDisabledProperty(style, name); + deleteDisabledProperty(style, style.getPropertyShorthand(name)); + } + + // Add all the properties found in this style to the used properties list. + // Do this here so only future rules are affect by properties used in this rule. + for (var name in styleRules[i].usedProperties) + usedProperties[name] = true; + + // Remember all disabled properties so they show up in computed style. + if (style.__disabledProperties) + for (var name in style.__disabledProperties) + disabledComputedProperties[name] = true; + } + + if (priorityUsed) { + // Walk the properties again and account for !important. + var foundPriorityProperties = []; + + // Walk in reverse to match the order !important overrides. + for (var i = (styleRules.length - 1); i >= 0; --i) { + if (styleRules[i].computedStyle) + continue; + + var style = styleRules[i].style; + var uniqueProperties = getUniqueStyleProperties(style); + for (var j = 0; j < uniqueProperties.length; ++j) { + var name = uniqueProperties[j]; + if (style.getPropertyPriority(name).length) { + if (!(name in foundPriorityProperties)) + styleRules[i].usedProperties[name] = true; + else + delete styleRules[i].usedProperties[name]; + foundPriorityProperties[name] = true; + } else if (name in foundPriorityProperties) + delete styleRules[i].usedProperties[name]; + } + } + } + + if (refresh) { + // Walk the style rules and update the sections with new overloaded and used properties. + for (var i = 0; i < styleRules.length; ++i) { + var styleRule = styleRules[i]; + var section = styleRule.section; + if (styleRule.computedStyle) + section.disabledComputedProperties = disabledComputedProperties; + section._usedProperties = (styleRule.usedProperties || usedProperties); + section.update((section === editedSection) || styleRule.computedStyle); + } + } else { + // Make a property section for each style rule. + for (var i = 0; i < styleRules.length; ++i) { + var styleRule = styleRules[i]; + var subtitle = styleRule.subtitle; + delete styleRule.subtitle; + + var computedStyle = styleRule.computedStyle; + delete styleRule.computedStyle; + + var ruleUsedProperties = styleRule.usedProperties; + delete styleRule.usedProperties; + + var editable = styleRule.editable; + delete styleRule.editable; + + // Default editable to true if it was omitted. + if (typeof editable === "undefined") + editable = true; + + var section = new WebInspector.StylePropertiesSection(styleRule, subtitle, computedStyle, (ruleUsedProperties || usedProperties), editable); + if (computedStyle) + section.disabledComputedProperties = disabledComputedProperties; + section.pane = this; + + if (Preferences.styleRulesExpandedState && section.identifier in Preferences.styleRulesExpandedState) + section.expanded = Preferences.styleRulesExpandedState[section.identifier]; + else if (computedStyle) + section.collapse(true); + else + section.expand(true); + + body.appendChild(section.element); + this.sections.push(section); + } + } + } +} + +WebInspector.StylesSidebarPane.prototype.__proto__ = WebInspector.SidebarPane.prototype; + +WebInspector.StylePropertiesSection = function(styleRule, subtitle, computedStyle, usedProperties, editable) +{ + WebInspector.PropertiesSection.call(this, styleRule.selectorText); + + this.styleRule = styleRule; + this.computedStyle = computedStyle; + this.editable = (editable && !computedStyle); + + // Prevent editing the user agent and user rules. + var isUserAgent = this.styleRule.parentStyleSheet && !this.styleRule.parentStyleSheet.ownerNode && !this.styleRule.parentStyleSheet.href; + var isUser = this.styleRule.parentStyleSheet && this.styleRule.parentStyleSheet.ownerNode && this.styleRule.parentStyleSheet.ownerNode.nodeName == '#document'; + if (isUserAgent || isUser) + this.editable = false; + + this._usedProperties = usedProperties; + + if (computedStyle) { + this.element.addStyleClass("computed-style"); + + if (Preferences.showInheritedComputedStyleProperties) + this.element.addStyleClass("show-inherited"); + + var showInheritedLabel = document.createElement("label"); + var showInheritedInput = document.createElement("input"); + showInheritedInput.type = "checkbox"; + showInheritedInput.checked = Preferences.showInheritedComputedStyleProperties; + + var computedStyleSection = this; + var showInheritedToggleFunction = function(event) { + Preferences.showInheritedComputedStyleProperties = showInheritedInput.checked; + if (Preferences.showInheritedComputedStyleProperties) + computedStyleSection.element.addStyleClass("show-inherited"); + else + computedStyleSection.element.removeStyleClass("show-inherited"); + event.stopPropagation(); + }; + + showInheritedLabel.addEventListener("click", showInheritedToggleFunction, false); + + showInheritedLabel.appendChild(showInheritedInput); + showInheritedLabel.appendChild(document.createTextNode(WebInspector.UIString("Show inherited"))); + this.subtitleElement.appendChild(showInheritedLabel); + } else { + if (!subtitle) { + if (this.styleRule.parentStyleSheet && this.styleRule.parentStyleSheet.href) { + var url = this.styleRule.parentStyleSheet.href; + subtitle = WebInspector.linkifyURL(url, WebInspector.displayNameForURL(url)); + this.subtitleElement.addStyleClass("file"); + } else if (isUserAgent) + subtitle = WebInspector.UIString("user agent stylesheet"); + else if (isUser) + subtitle = WebInspector.UIString("user stylesheet"); + else + subtitle = WebInspector.UIString("inline stylesheet"); + } + + this.subtitle = subtitle; + } + + this.identifier = styleRule.selectorText; + if (this.subtitle) + this.identifier += ":" + this.subtitleElement.textContent; +} + +WebInspector.StylePropertiesSection.prototype = { + get usedProperties() + { + return this._usedProperties || {}; + }, + + set usedProperties(x) + { + this._usedProperties = x; + this.update(); + }, + + expand: function(dontRememberState) + { + WebInspector.PropertiesSection.prototype.expand.call(this); + if (dontRememberState) + return; + + if (!Preferences.styleRulesExpandedState) + Preferences.styleRulesExpandedState = {}; + Preferences.styleRulesExpandedState[this.identifier] = true; + }, + + collapse: function(dontRememberState) + { + WebInspector.PropertiesSection.prototype.collapse.call(this); + if (dontRememberState) + return; + + if (!Preferences.styleRulesExpandedState) + Preferences.styleRulesExpandedState = {}; + Preferences.styleRulesExpandedState[this.identifier] = false; + }, + + isPropertyInherited: function(property) + { + if (!this.computedStyle || !this._usedProperties) + return false; + // These properties should always show for Computed Style. + var alwaysShowComputedProperties = { "display": true, "height": true, "width": true }; + return !(property in this.usedProperties) && !(property in alwaysShowComputedProperties) && !(property in this.disabledComputedProperties); + }, + + isPropertyOverloaded: function(property, shorthand) + { + if (this.computedStyle || !this._usedProperties) + return false; + + var used = (property in this.usedProperties); + if (used || !shorthand) + return !used; + + // Find out if any of the individual longhand properties of the shorthand + // are used, if none are then the shorthand is overloaded too. + var longhandProperties = getLonghandProperties(this.styleRule.style, property); + for (var j = 0; j < longhandProperties.length; ++j) { + var individualProperty = longhandProperties[j]; + if (individualProperty in this.usedProperties) + return false; + } + + return true; + }, + + update: function(full) + { + if (full || this.computedStyle) { + this.propertiesTreeOutline.removeChildren(); + this.populated = false; + } else { + var child = this.propertiesTreeOutline.children[0]; + while (child) { + child.overloaded = this.isPropertyOverloaded(child.name, child.shorthand); + child = child.traverseNextTreeElement(false, null, true); + } + } + }, + + onpopulate: function() + { + var style = this.styleRule.style; + + var foundShorthands = {}; + var uniqueProperties = getUniqueStyleProperties(style); + var disabledProperties = style.__disabledPropertyValues || {}; + + for (var name in disabledProperties) + uniqueProperties.push(name); + + uniqueProperties.sort(); + + for (var i = 0; i < uniqueProperties.length; ++i) { + var name = uniqueProperties[i]; + var disabled = name in disabledProperties; + if (!disabled && this.disabledComputedProperties && !(name in this.usedProperties) && name in this.disabledComputedProperties) + disabled = true; + + var shorthand = !disabled ? style.getPropertyShorthand(name) : null; + + if (shorthand && shorthand in foundShorthands) + continue; + + if (shorthand) { + foundShorthands[shorthand] = true; + name = shorthand; + } + + var isShorthand = (shorthand ? true : false); + var inherited = this.isPropertyInherited(name); + var overloaded = this.isPropertyOverloaded(name, isShorthand); + + var item = new WebInspector.StylePropertyTreeElement(style, name, isShorthand, inherited, overloaded, disabled); + this.propertiesTreeOutline.appendChild(item); + } + } +} + +WebInspector.StylePropertiesSection.prototype.__proto__ = WebInspector.PropertiesSection.prototype; + +WebInspector.StylePropertyTreeElement = function(style, name, shorthand, inherited, overloaded, disabled) +{ + this.style = style; + this.name = name; + this.shorthand = shorthand; + this._inherited = inherited; + this._overloaded = overloaded; + this._disabled = disabled; + + // Pass an empty title, the title gets made later in onattach. + TreeElement.call(this, "", null, shorthand); +} + +WebInspector.StylePropertyTreeElement.prototype = { + get inherited() + { + return this._inherited; + }, + + set inherited(x) + { + if (x === this._inherited) + return; + this._inherited = x; + this.updateState(); + }, + + get overloaded() + { + return this._overloaded; + }, + + set overloaded(x) + { + if (x === this._overloaded) + return; + this._overloaded = x; + this.updateState(); + }, + + get disabled() + { + return this._disabled; + }, + + set disabled(x) + { + if (x === this._disabled) + return; + this._disabled = x; + this.updateState(); + }, + + get priority() + { + if (this.disabled && this.style.__disabledPropertyPriorities && this.name in this.style.__disabledPropertyPriorities) + return this.style.__disabledPropertyPriorities[this.name]; + return (this.shorthand ? getShorthandPriority(this.style, this.name) : this.style.getPropertyPriority(this.name)); + }, + + get value() + { + if (this.disabled && this.style.__disabledPropertyValues && this.name in this.style.__disabledPropertyValues) + return this.style.__disabledPropertyValues[this.name]; + return (this.shorthand ? getShorthandValue(this.style, this.name) : this.style.getPropertyValue(this.name)); + }, + + onattach: function() + { + this.updateTitle(); + }, + + updateTitle: function() + { + // "Nicknames" for some common values that are easier to read. + var valueNicknames = { + "rgb(0, 0, 0)": "black", + "#000": "black", + "#000000": "black", + "rgb(255, 255, 255)": "white", + "#fff": "white", + "#ffffff": "white", + "#FFF": "white", + "#FFFFFF": "white", + "rgba(0, 0, 0, 0)": "transparent", + "rgb(255, 0, 0)": "red", + "rgb(0, 255, 0)": "lime", + "rgb(0, 0, 255)": "blue", + "rgb(255, 255, 0)": "yellow", + "rgb(255, 0, 255)": "magenta", + "rgb(0, 255, 255)": "cyan" + }; + + var priority = this.priority; + var value = this.value; + var htmlValue = value; + + if (priority && !priority.length) + delete priority; + if (priority) + priority = "!" + priority; + + if (value) { + var urls = value.match(/url\([^)]+\)/); + if (urls) { + for (var i = 0; i < urls.length; ++i) { + var url = urls[i].substring(4, urls[i].length - 1); + htmlValue = htmlValue.replace(urls[i], "url(" + WebInspector.linkifyURL(url) + ")"); + } + } else { + if (value in valueNicknames) + htmlValue = valueNicknames[value]; + htmlValue = htmlValue.escapeHTML(); + } + } else + htmlValue = value = ""; + + this.updateState(); + + var enabledCheckboxElement = document.createElement("input"); + enabledCheckboxElement.className = "enabled-button"; + enabledCheckboxElement.type = "checkbox"; + enabledCheckboxElement.checked = !this.disabled; + enabledCheckboxElement.addEventListener("change", this.toggleEnabled.bind(this), false); + + var nameElement = document.createElement("span"); + nameElement.className = "name"; + nameElement.textContent = this.name; + + var valueElement = document.createElement("span"); + valueElement.className = "value"; + valueElement.innerHTML = htmlValue; + + if (priority) { + var priorityElement = document.createElement("span"); + priorityElement.className = "priority"; + priorityElement.textContent = priority; + } + + this.listItemElement.removeChildren(); + + // Append the checkbox for root elements of an editable section. + if (this.treeOutline.section && this.treeOutline.section.editable && this.parent.root) + this.listItemElement.appendChild(enabledCheckboxElement); + this.listItemElement.appendChild(nameElement); + this.listItemElement.appendChild(document.createTextNode(": ")); + this.listItemElement.appendChild(valueElement); + + if (priorityElement) { + this.listItemElement.appendChild(document.createTextNode(" ")); + this.listItemElement.appendChild(priorityElement); + } + + this.listItemElement.appendChild(document.createTextNode(";")); + + if (value) { + // FIXME: this only covers W3C and CSS 16 valid color names + var colors = value.match(/((rgb|hsl)a?\([^)]+\))|(#[0-9a-fA-F]{6})|(#[0-9a-fA-F]{3})|aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|purple|red|silver|teal|white|yellow/g); + if (colors) { + var colorsLength = colors.length; + for (var i = 0; i < colorsLength; ++i) { + var swatchElement = document.createElement("span"); + swatchElement.className = "swatch"; + swatchElement.style.setProperty("background-color", colors[i]); + this.listItemElement.appendChild(swatchElement); + } + } + } + + this.tooltip = this.name + ": " + (valueNicknames[value] || value) + (priority ? " " + priority : ""); + }, + + updateAll: function(updateAllRules) + { + if (updateAllRules && this.treeOutline.section && this.treeOutline.section.pane) + this.treeOutline.section.pane.update(null, this.treeOutline.section); + else if (this.treeOutline.section) + this.treeOutline.section.update(true); + else + this.updateTitle(); // FIXME: this will not show new properties. But we don't hit his case yet. + }, + + toggleEnabled: function(event) + { + var disabled = !event.target.checked; + + if (disabled) { + if (!this.style.__disabledPropertyValues || !this.style.__disabledPropertyPriorities) { + var inspectedWindow = InspectorController.inspectedWindow(); + this.style.__disabledProperties = new inspectedWindow.Object; + this.style.__disabledPropertyValues = new inspectedWindow.Object; + this.style.__disabledPropertyPriorities = new inspectedWindow.Object; + } + + this.style.__disabledPropertyValues[this.name] = this.value; + this.style.__disabledPropertyPriorities[this.name] = this.priority; + + if (this.shorthand) { + var longhandProperties = getLonghandProperties(this.style, this.name); + for (var i = 0; i < longhandProperties.length; ++i) { + this.style.__disabledProperties[longhandProperties[i]] = true; + this.style.removeProperty(longhandProperties[i]); + } + } else { + this.style.__disabledProperties[this.name] = true; + this.style.removeProperty(this.name); + } + } else { + this.style.setProperty(this.name, this.value, this.priority); + delete this.style.__disabledProperties[this.name]; + delete this.style.__disabledPropertyValues[this.name]; + delete this.style.__disabledPropertyPriorities[this.name]; + } + + // Set the disabled property here, since the code above replies on it not changing + // until after the value and priority are retrieved. + this.disabled = disabled; + + if (this.treeOutline.section && this.treeOutline.section.pane) + this.treeOutline.section.pane.dispatchEventToListeners("style property toggled"); + + this.updateAll(true); + }, + + updateState: function() + { + if (!this.listItemElement) + return; + + if (this.style.isPropertyImplicit(this.name) || this.value === "initial") + this.listItemElement.addStyleClass("implicit"); + else + this.listItemElement.removeStyleClass("implicit"); + + if (this.inherited) + this.listItemElement.addStyleClass("inherited"); + else + this.listItemElement.removeStyleClass("inherited"); + + if (this.overloaded) + this.listItemElement.addStyleClass("overloaded"); + else + this.listItemElement.removeStyleClass("overloaded"); + + if (this.disabled) + this.listItemElement.addStyleClass("disabled"); + else + this.listItemElement.removeStyleClass("disabled"); + }, + + onpopulate: function() + { + // Only populate once and if this property is a shorthand. + if (this.children.length || !this.shorthand) + return; + + var longhandProperties = getLonghandProperties(this.style, this.name); + for (var i = 0; i < longhandProperties.length; ++i) { + var name = longhandProperties[i]; + + if (this.treeOutline.section) { + var inherited = this.treeOutline.section.isPropertyInherited(name); + var overloaded = this.treeOutline.section.isPropertyOverloaded(name); + } + + var item = new WebInspector.StylePropertyTreeElement(this.style, name, false, inherited, overloaded); + this.appendChild(item); + } + }, + + ondblclick: function(element, event) + { + this.startEditing(event.target); + }, + + startEditing: function(selectElement) + { + // FIXME: we don't allow editing of longhand properties under a shorthand right now. + if (this.parent.shorthand) + return; + + if (WebInspector.isBeingEdited(this.listItemElement) || (this.treeOutline.section && !this.treeOutline.section.editable)) + return; + + var context = { expanded: this.expanded, hasChildren: this.hasChildren }; + + // Lie about our children to prevent expanding on double click and to collapse shorthands. + this.hasChildren = false; + + if (!selectElement) + selectElement = this.listItemElement; + + this.listItemElement.handleKeyEvent = this.editingKeyDown.bind(this); + + WebInspector.startEditing(this.listItemElement, this.editingCommitted.bind(this), this.editingCancelled.bind(this), context); + window.getSelection().setBaseAndExtent(selectElement, 0, selectElement, 1); + }, + + editingKeyDown: function(event) + { + var arrowKeyPressed = (event.keyIdentifier === "Up" || event.keyIdentifier === "Down"); + var pageKeyPressed = (event.keyIdentifier === "PageUp" || event.keyIdentifier === "PageDown"); + if (!arrowKeyPressed && !pageKeyPressed) + return; + + var selection = window.getSelection(); + if (!selection.rangeCount) + return; + + var selectionRange = selection.getRangeAt(0); + if (selectionRange.commonAncestorContainer !== this.listItemElement && !selectionRange.commonAncestorContainer.isDescendant(this.listItemElement)) + return; + + const styleValueDelimeters = " \t\n\"':;,/()"; + var wordRange = selectionRange.startContainer.rangeOfWord(selectionRange.startOffset, styleValueDelimeters, this.listItemElement); + var wordString = wordRange.toString(); + var replacementString = wordString; + + var matches = /(.*?)(-?\d+(?:\.\d+)?)(.*)/.exec(wordString); + if (matches && matches.length) { + var prefix = matches[1]; + var number = parseFloat(matches[2]); + var suffix = matches[3]; + + // If the number is near zero or the number is one and the direction will take it near zero. + var numberNearZero = (number < 1 && number > -1); + if (number === 1 && event.keyIdentifier === "Down") + numberNearZero = true; + else if (number === -1 && event.keyIdentifier === "Up") + numberNearZero = true; + + if (numberNearZero && event.altKey && arrowKeyPressed) { + if (event.keyIdentifier === "Down") + number = Math.ceil(number - 1); + else + number = Math.floor(number + 1); + } else { + // Jump by 10 when shift is down or jump by 0.1 when near zero or Alt/Option is down. + // Also jump by 10 for page up and down, or by 100 if shift is held with a page key. + var changeAmount = 1; + if (event.shiftKey && pageKeyPressed) + changeAmount = 100; + else if (event.shiftKey || pageKeyPressed) + changeAmount = 10; + else if (event.altKey || numberNearZero) + changeAmount = 0.1; + + if (event.keyIdentifier === "Down" || event.keyIdentifier === "PageDown") + changeAmount *= -1; + + // Make the new number and constrain it to a precision of 6, this matches numbers the engine returns. + // Use the Number constructor to forget the fixed precision, so 1.100000 will print as 1.1. + number = Number((number + changeAmount).toFixed(6)); + } + + replacementString = prefix + number + suffix; + } else { + // FIXME: this should cycle through known keywords for the current property name. + return; + } + + var replacementTextNode = document.createTextNode(replacementString); + + wordRange.deleteContents(); + wordRange.insertNode(replacementTextNode); + + var finalSelectionRange = document.createRange(); + finalSelectionRange.setStart(replacementTextNode, 0); + finalSelectionRange.setEnd(replacementTextNode, replacementString.length); + + selection.removeAllRanges(); + selection.addRange(finalSelectionRange); + + event.preventDefault(); + event.handled = true; + + if (!this.originalCSSText) { + // Remember the rule's original CSS text, so it can be restored + // if the editing is canceled and before each apply. + this.originalCSSText = getStyleTextWithShorthands(this.style); + } else { + // Restore the original CSS text before applying user changes. This is needed to prevent + // new properties from sticking around if the user adds one, then removes it. + this.style.cssText = this.originalCSSText; + } + + this.applyStyleText(this.listItemElement.textContent); + }, + + editingEnded: function(context) + { + this.hasChildren = context.hasChildren; + if (context.expanded) + this.expand(); + delete this.listItemElement.handleKeyEvent; + delete this.originalCSSText; + }, + + editingCancelled: function(element, context) + { + if (this.originalCSSText) { + this.style.cssText = this.originalCSSText; + + if (this.treeOutline.section && this.treeOutline.section.pane) + this.treeOutline.section.pane.dispatchEventToListeners("style edited"); + + this.updateAll(); + } else + this.updateTitle(); + + this.editingEnded(context); + }, + + editingCommitted: function(element, userInput, previousContent, context) + { + this.editingEnded(context); + + if (userInput === previousContent) + return; // nothing changed, so do nothing else + + this.applyStyleText(userInput, true); + }, + + applyStyleText: function(styleText, updateInterface) + { + var styleTextLength = styleText.trimWhitespace().length; + + // Create a new element to parse the user input CSS. + var parseElement = document.createElement("span"); + parseElement.setAttribute("style", styleText); + + var tempStyle = parseElement.style; + if (tempStyle.length || !styleTextLength) { + // The input was parsable or the user deleted everything, so remove the + // original property from the real style declaration. If this represents + // a shorthand remove all the longhand properties. + if (this.shorthand) { + var longhandProperties = getLonghandProperties(this.style, this.name); + for (var i = 0; i < longhandProperties.length; ++i) + this.style.removeProperty(longhandProperties[i]); + } else + this.style.removeProperty(this.name); + } + + if (!styleTextLength) { + if (updateInterface) { + // The user deleted the everything, so remove the tree element and update. + if (this.treeOutline.section && this.treeOutline.section.pane) + this.treeOutline.section.pane.update(); + this.parent.removeChild(this); + } + return; + } + + if (!tempStyle.length) { + // The user typed something, but it didn't parse. Just abort and restore + // the original title for this property. + if (updateInterface) + this.updateTitle(); + return; + } + + // Iterate of the properties on the test element's style declaration and + // add them to the real style declaration. We take care to move shorthands. + var foundShorthands = {}; + var uniqueProperties = getUniqueStyleProperties(tempStyle); + for (var i = 0; i < uniqueProperties.length; ++i) { + var name = uniqueProperties[i]; + var shorthand = tempStyle.getPropertyShorthand(name); + + if (shorthand && shorthand in foundShorthands) + continue; + + if (shorthand) { + var value = getShorthandValue(tempStyle, shorthand); + var priority = getShorthandPriority(tempStyle, shorthand); + foundShorthands[shorthand] = true; + } else { + var value = tempStyle.getPropertyValue(name); + var priority = tempStyle.getPropertyPriority(name); + } + + // Set the property on the real style declaration. + this.style.setProperty((shorthand || name), value, priority); + } + + if (this.treeOutline.section && this.treeOutline.section.pane) + this.treeOutline.section.pane.dispatchEventToListeners("style edited"); + + if (updateInterface) + this.updateAll(true); + } +} + +WebInspector.StylePropertyTreeElement.prototype.__proto__ = TreeElement.prototype; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/TextPrompt.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/TextPrompt.js new file mode 100644 index 0000000..61e1b52db --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/TextPrompt.js @@ -0,0 +1,312 @@ +/* + * Copyright (C) 2008 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. + * 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. + */ + +WebInspector.TextPrompt = function(element, completions, stopCharacters) +{ + this.element = element; + this.completions = completions; + this.completionStopCharacters = stopCharacters; + this.history = []; + this.historyOffset = 0; +} + +WebInspector.TextPrompt.prototype = { + get text() + { + return this.element.textContent; + }, + + set text(x) + { + if (!x) { + // Append a break element instead of setting textContent to make sure the selection is inside the prompt. + this.element.removeChildren(); + this.element.appendChild(document.createElement("br")); + } else + this.element.textContent = x; + + this.moveCaretToEndOfPrompt(); + }, + + handleKeyEvent: function(event) + { + switch (event.keyIdentifier) { + case "Up": + this._upKeyPressed(event); + break; + case "Down": + this._downKeyPressed(event); + break; + case "U+0009": // Tab + this._tabKeyPressed(event); + break; + case "Right": + if (!this.acceptAutoComplete()) + this.autoCompleteSoon(); + break; + default: + this.clearAutoComplete(); + this.autoCompleteSoon(); + break; + } + }, + + acceptAutoComplete: function() + { + if (!this.autoCompleteElement || !this.autoCompleteElement.parentNode) + return false; + + var text = this.autoCompleteElement.textContent; + var textNode = document.createTextNode(text); + this.autoCompleteElement.parentNode.replaceChild(textNode, this.autoCompleteElement); + delete this.autoCompleteElement; + + var finalSelectionRange = document.createRange(); + finalSelectionRange.setStart(textNode, text.length); + finalSelectionRange.setEnd(textNode, text.length); + + var selection = window.getSelection(); + selection.removeAllRanges(); + selection.addRange(finalSelectionRange); + + return true; + }, + + clearAutoComplete: function(includeTimeout) + { + if (includeTimeout && "_completeTimeout" in this) { + clearTimeout(this._completeTimeout); + delete this._completeTimeout; + } + + if (!this.autoCompleteElement) + return; + + if (this.autoCompleteElement.parentNode) + this.autoCompleteElement.parentNode.removeChild(this.autoCompleteElement); + delete this.autoCompleteElement; + + if (!this._userEnteredRange || !this._userEnteredText) + return; + + this._userEnteredRange.deleteContents(); + + var userTextNode = document.createTextNode(this._userEnteredText); + this._userEnteredRange.insertNode(userTextNode); + + var selectionRange = document.createRange(); + selectionRange.setStart(userTextNode, this._userEnteredText.length); + selectionRange.setEnd(userTextNode, this._userEnteredText.length); + + var selection = window.getSelection(); + selection.removeAllRanges(); + selection.addRange(selectionRange); + + delete this._userEnteredRange; + delete this._userEnteredText; + }, + + autoCompleteSoon: function() + { + if (!("_completeTimeout" in this)) + this._completeTimeout = setTimeout(this.complete.bind(this, true), 250); + }, + + complete: function(auto) + { + this.clearAutoComplete(true); + + var selection = window.getSelection(); + if (!selection.rangeCount) + return; + + var selectionRange = selection.getRangeAt(0); + if (!selectionRange.commonAncestorContainer.isDescendant(this.element)) + return; + if (auto && !this.isCaretAtEndOfPrompt()) + return; + + var wordPrefixRange = selectionRange.startContainer.rangeOfWord(selectionRange.startOffset, this.completionStopCharacters, this.element, "backward"); + var completions = this.completions(wordPrefixRange, auto); + + if (!completions || !completions.length) + return; + + var fullWordRange = document.createRange(); + fullWordRange.setStart(wordPrefixRange.startContainer, wordPrefixRange.startOffset); + fullWordRange.setEnd(selectionRange.endContainer, selectionRange.endOffset); + + if (completions.length === 1 || selection.isCollapsed || auto) { + var completionText = completions[0]; + } else { + var currentText = fullWordRange.toString(); + + var foundIndex = null; + for (var i = 0; i < completions.length; ++i) { + if (completions[i] === currentText) + foundIndex = i; + } + + if (foundIndex === null || (foundIndex + 1) >= completions.length) + var completionText = completions[0]; + else + var completionText = completions[foundIndex + 1]; + } + + var wordPrefixLength = wordPrefixRange.toString().length; + + this._userEnteredRange = fullWordRange; + this._userEnteredText = fullWordRange.toString(); + + fullWordRange.deleteContents(); + + var finalSelectionRange = document.createRange(); + + if (auto) { + var prefixText = completionText.substring(0, wordPrefixLength); + var suffixText = completionText.substring(wordPrefixLength); + + var prefixTextNode = document.createTextNode(prefixText); + fullWordRange.insertNode(prefixTextNode); + + this.autoCompleteElement = document.createElement("span"); + this.autoCompleteElement.className = "auto-complete-text"; + this.autoCompleteElement.textContent = suffixText; + + prefixTextNode.parentNode.insertBefore(this.autoCompleteElement, prefixTextNode.nextSibling); + + finalSelectionRange.setStart(prefixTextNode, wordPrefixLength); + finalSelectionRange.setEnd(prefixTextNode, wordPrefixLength); + } else { + var completionTextNode = document.createTextNode(completionText); + fullWordRange.insertNode(completionTextNode); + + if (completions.length > 1) + finalSelectionRange.setStart(completionTextNode, wordPrefixLength); + else + finalSelectionRange.setStart(completionTextNode, completionText.length); + + finalSelectionRange.setEnd(completionTextNode, completionText.length); + } + + selection.removeAllRanges(); + selection.addRange(finalSelectionRange); + }, + + isCaretInsidePrompt: function() + { + return this.element.isInsertionCaretInside(); + }, + + isCaretAtEndOfPrompt: function() + { + var selection = window.getSelection(); + if (!selection.rangeCount || !selection.isCollapsed) + return false; + + var selectionRange = selection.getRangeAt(0); + var node = selectionRange.startContainer; + if (node !== this.element && !node.isDescendant(this.element)) + return false; + + if (node.nodeType === Node.TEXT_NODE && selectionRange.startOffset < node.nodeValue.length) + return false; + + var foundNextText = false; + while (node) { + if (node.nodeType === Node.TEXT_NODE && node.nodeValue.length) { + if (foundNextText) + return false; + foundNextText = true; + } + + node = node.traverseNextNode(false, this.element); + } + + return true; + }, + + moveCaretToEndOfPrompt: function() + { + var selection = window.getSelection(); + var selectionRange = document.createRange(); + + var offset = this.element.childNodes.length; + selectionRange.setStart(this.element, offset); + selectionRange.setEnd(this.element, offset); + + selection.removeAllRanges(); + selection.addRange(selectionRange); + }, + + _tabKeyPressed: function(event) + { + event.preventDefault(); + event.stopPropagation(); + + this.complete(); + }, + + _upKeyPressed: function(event) + { + event.preventDefault(); + event.stopPropagation(); + + if (this.historyOffset == this.history.length) + return; + + this.clearAutoComplete(true); + + if (this.historyOffset == 0) + this.tempSavedCommand = this.text; + + ++this.historyOffset; + this.text = this.history[this.history.length - this.historyOffset]; + }, + + _downKeyPressed: function(event) + { + event.preventDefault(); + event.stopPropagation(); + + if (this.historyOffset == 0) + return; + + this.clearAutoComplete(true); + + --this.historyOffset; + + if (this.historyOffset == 0) { + this.text = this.tempSavedCommand; + delete this.tempSavedCommand; + return; + } + + this.text = this.history[this.history.length - this.historyOffset]; + } +} diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/View.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/View.js new file mode 100644 index 0000000..632a61ae --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/View.js @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2008 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. ``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 + * 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.View = function(element) +{ + this.element = element || document.createElement("div"); + this._visible = false; +} + +WebInspector.View.prototype = { + get visible() + { + return this._visible; + }, + + set visible(x) + { + if (this._visible === x) + return; + + if (x) + this.show(); + else + this.hide(); + }, + + show: function(parentElement) + { + this._visible = true; + if (parentElement && parentElement !== this.element.parentNode) { + this.detach(); + parentElement.appendChild(this.element); + } + if (!this.element.parentNode && this.attach) + this.attach(); + this.element.addStyleClass("visible"); + }, + + hide: function() + { + this.element.removeStyleClass("visible"); + this._visible = false; + }, + + detach: function() + { + if (this.element.parentNode) + this.element.parentNode.removeChild(this.element); + } +} + +WebInspector.View.prototype.__proto__ = WebInspector.Object.prototype; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/base.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/base.js new file mode 100644 index 0000000..8f029a1 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/base.js @@ -0,0 +1,1015 @@ +// Copyright 2006 Google 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: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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 THE COPYRIGHT HOLDERS AND 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 THE +// COPYRIGHT OWNER OR 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. + +// NOTE: This file has been changed from the one on doctype. The following +// changes were made: +// - Removed goog.globalEval because it calls eval() which is not allowed from +// inside v8 extensions. If we ever need to use globalEval, we will need to +// find a way to work around this problem. +// - Remove Function.prototype.apply() emulation for the same reason. This one +// is useless anyway because V8 supports apply() natively. + +/** + * @fileoverview Bootstrap for the Google JS Library + */ + +/** + * @define {boolean} Overridden to true by the compiler when + * --mark_as_compiled is specified. + */ +var COMPILED = true; + + +/** + * Base namespace for the Google JS library. Checks to see goog is + * already defined in the current scope before assigning to prevent + * clobbering if base.js is loaded more than once. + */ +var goog = {}; // Check to see if already defined in current scope + + +/** + * Reference to the global context. In most cases this will be 'window'. + */ +goog.global = this; + + +/** + * Indicates whether or not we can call 'eval' directly to eval code in the + * global scope. Set to a Boolean by the first call to goog.globalEval (which + * empirically tests whether eval works for globals). @see goog.globalEval + * @type {boolean?} + * @private + */ +goog.evalWorksForGlobals_ = null; + + +/** + * Creates object stubs for a namespace. When present in a file, goog.provide + * also indicates that the file defines the indicated object. + * @param {string} name name of the object that this file defines. + */ +goog.provide = function(name) { + if (!COMPILED) { + // Ensure that the same namespace isn't provided twice. This is intended + // to teach new developers that 'goog.provide' is effectively a variable + // declaration. And when JSCompiler transforms goog.provide into a real + // variable declaration, the compiled JS should work the same as the raw + // JS--even when the raw JS uses goog.provide incorrectly. + if (goog.getObjectByName(name) && !goog.implicitNamespaces_[name]) { + throw 'Namespace "' + name + '" already declared.'; + } + + var namespace = name; + while ((namespace = namespace.substr(0, namespace.lastIndexOf('.')))) { + goog.implicitNamespaces_[namespace] = true; + } + } + + goog.exportPath_(name); +}; + + +if (!COMPILED) { + /** + * Namespaces implicitly defined by goog.provide. For example, + * goog.provide('goog.events.Event') implicitly declares + * that 'goog' and 'goog.events' must be namespaces. + * + * @type {Object} + * @private + */ + goog.implicitNamespaces_ = {}; +} + + +/** + * Builds an object structure for the provided namespace path, + * ensuring that names that already exist are not overwritten. For + * example: + * "a.b.c" -> a = {};a.b={};a.b.c={}; + * Used by goog.provide and goog.exportSymbol. + * @param {string} name name of the object that this file defines. + * @param {Object} opt_object the object to expose at the end of the path. + * @private + */ +goog.exportPath_ = function(name, opt_object) { + var parts = name.split('.'); + var cur = goog.global; + var part; + + // Internet Explorer exhibits strange behavior when throwing errors from + // methods externed in this manner. See the testExportSymbolExceptions in + // base_test.html for an example. + if (!(parts[0] in cur) && cur.execScript) { + cur.execScript('var ' + parts[0]); + } + + // Parentheses added to eliminate strict JS warning in Firefox. + while ((part = parts.shift())) { + if (!parts.length && goog.isDef(opt_object)) { + // last part and we have an object; use it + cur[part] = opt_object; + } else if (cur[part]) { + cur = cur[part]; + } else { + cur = cur[part] = {}; + } + } +}; + + +/** + * Returns an object based on its fully qualified name + * @param {string} name The fully qualified name. + * @return {Object?} The object or, if not found, null. + */ +goog.getObjectByName = function(name) { + var parts = name.split('.'); + var cur = goog.global; + for (var part; part = parts.shift(); ) { + if (cur[part]) { + cur = cur[part]; + } else { + return null; + } + } + return cur; +}; + + +/** + * Globalizes a whole namespace, such as goog or goog.lang. + * + * @param {Object} obj The namespace to globalize. + * @param {Object} opt_global The object to add the properties to. + * @deprecated Properties may be explicitly exported to the global scope, but + * this should no longer be done in bulk. + */ +goog.globalize = function(obj, opt_global) { + var global = opt_global || goog.global; + for (var x in obj) { + global[x] = obj[x]; + } +}; + + +/** + * Adds a dependency from a file to the files it requires. + * @param {string} relPath The path to the js file. + * @param {Array} provides An array of strings with the names of the objects + * this file provides. + * @param {Array} requires An array of strings with the names of the objects + * this file requires. + */ +goog.addDependency = function(relPath, provides, requires) { + if (!COMPILED) { + var provide, require; + var path = relPath.replace(/\\/g, '/'); + var deps = goog.dependencies_; + for (var i = 0; provide = provides[i]; i++) { + deps.nameToPath[provide] = path; + if (!(path in deps.pathToNames)) { + deps.pathToNames[path] = {}; + } + deps.pathToNames[path][provide] = true; + } + for (var j = 0; require = requires[j]; j++) { + if (!(path in deps.requires)) { + deps.requires[path] = {}; + } + deps.requires[path][require] = true; + } + } +}; + + +/** + * Implements a system for the dynamic resolution of dependencies + * that works in parallel with the BUILD system. + * @param {string} rule Rule to include, in the form goog.package.part. + */ +goog.require = function(rule) { + + // if the object already exists we do not need do do anything + if (!COMPILED) { + if (goog.getObjectByName(rule)) { + return; + } + var path = goog.getPathFromDeps_(rule); + if (path) { + goog.included_[path] = true; + goog.writeScripts_(); + } else { + // NOTE(nicksantos): We could throw an error, but this would break + // legacy users that depended on this failing silently. Instead, the + // compiler should warn us when there are invalid goog.require calls. + } + } +}; + + +/** + * Path for included scripts + * @type {string} + */ +goog.basePath = ''; + + +/** + * Null function used for default values of callbacks, etc. + * @type {Function} + */ +goog.nullFunction = function() {}; + + +/** + * When defining a class Foo with an abstract method bar(), you can do: + * + * Foo.prototype.bar = goog.abstractMethod + * + * Now if a subclass of Foo fails to override bar(), an error + * will be thrown when bar() is invoked. + * + * Note: This does not take the name of the function to override as + * an argument because that would make it more difficult to obfuscate + * our JavaScript code. + * + * @throws {Error} when invoked to indicate the method should be + * overridden. + */ +goog.abstractMethod = function() { + throw Error('unimplemented abstract method'); +}; + + +if (!COMPILED) { + /** + * Object used to keep track of urls that have already been added. This + * record allows the prevention of circular dependencies. + * @type {Object} + * @private + */ + goog.included_ = {}; + + + /** + * This object is used to keep track of dependencies and other data that is + * used for loading scripts + * @private + * @type {Object} + */ + goog.dependencies_ = { + pathToNames: {}, // 1 to many + nameToPath: {}, // 1 to 1 + requires: {}, // 1 to many + visited: {}, // used when resolving dependencies to prevent us from + // visiting the file twice + written: {} // used to keep track of script files we have written + }; + + + /** + * Tries to detect the base path of the base.js script that bootstraps + * Google JS Library + * @private + */ + goog.findBasePath_ = function() { + var doc = goog.global.document; + if (typeof doc == 'undefined') { + return; + } + if (goog.global.GOOG_BASE_PATH) { + goog.basePath = goog.global.GOOG_BASE_PATH; + return; + } else { + goog.global.GOOG_BASE_PATH = null; + } + var scripts = doc.getElementsByTagName('script'); + for (var script, i = 0; script = scripts[i]; i++) { + var src = script.src; + var l = src.length; + if (src.substr(l - 7) == 'base.js') { + goog.basePath = src.substr(0, l - 7); + return; + } + } + }; + + + /** + * Writes a script tag if, and only if, that script hasn't already been added + * to the document. (Must be called at execution time) + * @param {string} src Script source. + * @private + */ + goog.writeScriptTag_ = function(src) { + var doc = goog.global.document; + if (typeof doc != 'undefined' && + !goog.dependencies_.written[src]) { + goog.dependencies_.written[src] = true; + doc.write('<script type="text/javascript" src="' + + src + '"></' + 'script>'); + } + }; + + + /** + * Resolves dependencies based on the dependencies added using addDependency + * and calls writeScriptTag_ in the correct order. + * @private + */ + goog.writeScripts_ = function() { + // the scripts we need to write this time + var scripts = []; + var seenScript = {}; + var deps = goog.dependencies_; + + function visitNode(path) { + if (path in deps.written) { + return; + } + + // we have already visited this one. We can get here if we have cyclic + // dependencies + if (path in deps.visited) { + if (!(path in seenScript)) { + seenScript[path] = true; + scripts.push(path); + } + return; + } + + deps.visited[path] = true; + + if (path in deps.requires) { + for (var requireName in deps.requires[path]) { + visitNode(deps.nameToPath[requireName]); + } + } + + if (!(path in seenScript)) { + seenScript[path] = true; + scripts.push(path); + } + } + + for (var path in goog.included_) { + if (!deps.written[path]) { + visitNode(path); + } + } + + for (var i = 0; i < scripts.length; i++) { + if (scripts[i]) { + goog.writeScriptTag_(goog.basePath + scripts[i]); + } else { + throw Error('Undefined script input'); + } + } + }; + + + /** + * Looks at the dependency rules and tries to determine the script file that + * fulfills a particular rule. + * @param {string} rule In the form goog.namespace.Class or project.script. + * @return {string?} Url corresponding to the rule, or null. + * @private + */ + goog.getPathFromDeps_ = function(rule) { + if (rule in goog.dependencies_.nameToPath) { + return goog.dependencies_.nameToPath[rule]; + } else { + return null; + } + }; + + goog.findBasePath_(); + goog.writeScriptTag_(goog.basePath + 'deps.js'); +} + + + +//============================================================================== +// Language Enhancements +//============================================================================== + + +/** + * This is a "fixed" version of the typeof operator. It differs from the typeof + * operator in such a way that null returns 'null' and arrays return 'array'. + * @param {*} value The value to get the type of. + * @return {string} The name of the type. + */ +goog.typeOf = function(value) { + var s = typeof value; + if (s == 'object') { + if (value) { + // We cannot use constructor == Array or instanceof Array because + // different frames have different Array objects. In IE6, if the iframe + // where the array was created is destroyed, the array loses its + // prototype. Then dereferencing val.splice here throws an exception, so + // we can't use goog.isFunction. Calling typeof directly returns 'unknown' + // so that will work. In this case, this function will return false and + // most array functions will still work because the array is still + // array-like (supports length and []) even though it has lost its + // prototype. Custom object cannot have non enumerable length and + // NodeLists don't have a slice method. + if (typeof value.length == 'number' && + typeof value.splice != 'undefined' && + !goog.propertyIsEnumerable_(value, 'length')) { + return 'array'; + } + + // IE in cross-window calls does not correctly marshal the function type + // (it appears just as an object) so we cannot use just typeof val == + // 'function'. However, if the object has a call property, it is a + // function. + if (typeof value.call != 'undefined') { + return 'function'; + } + } else { + return 'null'; + } + + // In Safari typeof nodeList returns function. We would like to return + // object for those and we can detect an invalid function by making sure that + // the function object has a call method + } else if (s == 'function' && typeof value.call == 'undefined') { + return 'object'; + } + return s; +}; + +if (Object.prototype.propertyIsEnumerable) { + /** + * Safe way to test whether a property is enumarable. It allows testing + * for enumarable on objects where 'propertyIsEnumerable' is overridden or + * does not exist (like DOM nodes in IE). + * @param {Object} object The object to test if the property is enumerable. + * @param {string} propName The property name to check for. + * @return {boolean} True if the property is enumarable. + * @private + */ + goog.propertyIsEnumerable_ = function(object, propName) { + return Object.prototype.propertyIsEnumerable.call(object, propName); + }; +} else { + /** + * Safe way to test whether a property is enumarable. It allows testing + * for enumarable on objects where 'propertyIsEnumerable' is overridden or + * does not exist (like DOM nodes in IE). + * @param {Object} object The object to test if the property is enumerable. + * @param {string} propName The property name to check for. + * @return {boolean} True if the property is enumarable. + * @private + */ + goog.propertyIsEnumerable_ = function(object, propName) { + // KJS in Safari 2 is not ECMAScript compatible and lacks crucial methods + // such as propertyIsEnumerable. We therefore use a workaround. + // Does anyone know a more efficient work around? + if (propName in object) { + for (var key in object) { + if (key == propName) { + return true; + } + } + } + return false; + }; +} + +/** + * Returns true if the specified value is not |undefined|. + * WARNING: Do not use this to test if an object has a property. Use the in + * operator instead. + * @param {*} val Variable to test. + * @return {boolean} Whether variable is defined. + */ +goog.isDef = function(val) { + return typeof val != 'undefined'; +}; + + +/** + * Returns true if the specified value is |null| + * @param {*} val Variable to test. + * @return {boolean} Whether variable is null. + */ +goog.isNull = function(val) { + return val === null; +}; + + +/** + * Returns true if the specified value is defined and not null + * @param {*} val Variable to test. + * @return {boolean} Whether variable is defined and not null. + */ +goog.isDefAndNotNull = function(val) { + return goog.isDef(val) && !goog.isNull(val); +}; + + +/** + * Returns true if the specified value is an array + * @param {*} val Variable to test. + * @return {boolean} Whether variable is an array. + */ +goog.isArray = function(val) { + return goog.typeOf(val) == 'array'; +}; + + +/** + * Returns true if the object looks like an array. To qualify as array like + * the value needs to be either a NodeList or an object with a Number length + * property. + * @param {*} val Variable to test. + * @return {boolean} Whether variable is an array. + */ +goog.isArrayLike = function(val) { + var type = goog.typeOf(val); + return type == 'array' || type == 'object' && typeof val.length == 'number'; +}; + + +/** + * Returns true if the object looks like a Date. To qualify as Date-like + * the value needs to be an object and have a getFullYear() function. + * @param {*} val Variable to test. + * @return {boolean} Whether variable is a like a Date. + */ +goog.isDateLike = function(val) { + return goog.isObject(val) && typeof val.getFullYear == 'function'; +}; + + +/** + * Returns true if the specified value is a string + * @param {*} val Variable to test. + * @return {boolean} Whether variable is a string. + */ +goog.isString = function(val) { + return typeof val == 'string'; +}; + + +/** + * Returns true if the specified value is a boolean + * @param {*} val Variable to test. + * @return {boolean} Whether variable is boolean. + */ +goog.isBoolean = function(val) { + return typeof val == 'boolean'; +}; + + +/** + * Returns true if the specified value is a number + * @param {*} val Variable to test. + * @return {boolean} Whether variable is a number. + */ +goog.isNumber = function(val) { + return typeof val == 'number'; +}; + + +/** + * Returns true if the specified value is a function + * @param {*} val Variable to test. + * @return {boolean} Whether variable is a function. + */ +goog.isFunction = function(val) { + return goog.typeOf(val) == 'function'; +}; + + +/** + * Returns true if the specified value is an object. This includes arrays + * and functions. + * @param {*} val Variable to test. + * @return {boolean} Whether variable is an object. + */ +goog.isObject = function(val) { + var type = goog.typeOf(val); + return type == 'object' || type == 'array' || type == 'function'; +}; + + +/** + * Adds a hash code field to an object. The hash code is unique for the + * given object. + * @param {Object} obj The object to get the hash code for. + * @return {number} The hash code for the object. + */ +goog.getHashCode = function(obj) { + // In IE, DOM nodes do not extend Object so they do not have this method. + // we need to check hasOwnProperty because the proto might have this set. + + if (obj.hasOwnProperty && obj.hasOwnProperty(goog.HASH_CODE_PROPERTY_)) { + return obj[goog.HASH_CODE_PROPERTY_]; + } + if (!obj[goog.HASH_CODE_PROPERTY_]) { + obj[goog.HASH_CODE_PROPERTY_] = ++goog.hashCodeCounter_; + } + return obj[goog.HASH_CODE_PROPERTY_]; +}; + + +/** + * Removes the hash code field from an object. + * @param {Object} obj The object to remove the field from. + */ +goog.removeHashCode = function(obj) { + // DOM nodes in IE are not instance of Object and throws exception + // for delete. Instead we try to use removeAttribute + if ('removeAttribute' in obj) { + obj.removeAttribute(goog.HASH_CODE_PROPERTY_); + } + /** @preserveTry */ + try { + delete obj[goog.HASH_CODE_PROPERTY_]; + } catch (ex) { + } +}; + + +/** + * {String} Name for hash code property + * @private + */ +goog.HASH_CODE_PROPERTY_ = 'goog_hashCode_'; + + +/** + * @type {number} Counter for hash codes. + * @private + */ +goog.hashCodeCounter_ = 0; + + +/** + * Clone an object/array (recursively) + * @param {Object} proto Object to clone. + * @return {Object} Clone of x;. + */ +goog.cloneObject = function(proto) { + var type = goog.typeOf(proto); + if (type == 'object' || type == 'array') { + if (proto.clone) { + return proto.clone(); + } + var clone = type == 'array' ? [] : {}; + for (var key in proto) { + clone[key] = goog.cloneObject(proto[key]); + } + return clone; + } + + return proto; +}; + + +/** + * Partially applies this function to a particular 'this object' and zero or + * more arguments. The result is a new function with some arguments of the first + * function pre-filled and the value of |this| 'pre-specified'.<br><br> + * + * Remaining arguments specified at call-time are appended to the pre- + * specified ones.<br><br> + * + * Also see: {@link #partial}.<br><br> + * + * Note that bind and partial are optimized such that repeated calls to it do + * not create more than one function object, so there is no additional cost for + * something like:<br> + * + * <pre>var g = bind(f, obj); + * var h = partial(g, 1, 2, 3); + * var k = partial(h, a, b, c);</pre> + * + * Usage: + * <pre>var barMethBound = bind(myFunction, myObj, 'arg1', 'arg2'); + * barMethBound('arg3', 'arg4');</pre> + * + * @param {Function} fn A function to partially apply. + * @param {Object} self Specifies the object which |this| should point to + * when the function is run. If the value is null or undefined, it will + * default to the global object. + * @param {Object} var_args Additional arguments that are partially + * applied to the function. + * + * @return {Function} A partially-applied form of the function bind() was + * invoked as a method of. + */ +goog.bind = function(fn, self, var_args) { + var boundArgs = fn.boundArgs_; + + if (arguments.length > 2) { + var args = Array.prototype.slice.call(arguments, 2); + if (boundArgs) { + args.unshift.apply(args, boundArgs); + } + boundArgs = args; + } + + self = fn.boundSelf_ || self; + fn = fn.boundFn_ || fn; + + var newfn; + var context = self || goog.global; + + if (boundArgs) { + newfn = function() { + // Combine the static args and the new args into one big array + var args = Array.prototype.slice.call(arguments); + args.unshift.apply(args, boundArgs); + return fn.apply(context, args); + } + } else { + newfn = function() { + return fn.apply(context, arguments); + } + } + + newfn.boundArgs_ = boundArgs; + newfn.boundSelf_ = self; + newfn.boundFn_ = fn; + + return newfn; +}; + + +/** + * Like bind(), except that a 'this object' is not required. Useful when the + * target function is already bound. + * + * Usage: + * var g = partial(f, arg1, arg2); + * g(arg3, arg4); + * + * @param {Function} fn A function to partially apply. + * @param {Object} var_args Additional arguments that are partially + * applied to fn. + * @return {Function} A partially-applied form of the function bind() was + * invoked as a method of. + */ +goog.partial = function(fn, var_args) { + var args = Array.prototype.slice.call(arguments, 1); + args.unshift(fn, null); + return goog.bind.apply(null, args); +}; + + +/** + * Copies all the members of a source object to a target object. + * This is deprecated. Use goog.object.extend instead. + * @param {Object} target Target. + * @param {Object} source Source. + * @deprecated + */ +goog.mixin = function(target, source) { + for (var x in source) { + target[x] = source[x]; + } + + // For IE the for-in-loop does not contain any properties that are not + // enumerable on the prototype object (for example, isPrototypeOf from + // Object.prototype) but also it will not include 'replace' on objects that + // extend String and change 'replace' (not that it is common for anyone to + // extend anything except Object). +}; + + +/** + * A simple wrapper for new Date().getTime(). + * + * @return {number} An integer value representing the number of milliseconds + * between midnight, January 1, 1970 and the current time. + */ +goog.now = Date.now || (function() { + return new Date().getTime(); +}); + + +/** + * Abstract implementation of goog.getMsg for use with localized messages + * @param {string} str Translatable string, places holders in the form.{$foo} + * @param {Object} opt_values Map of place holder name to value. + */ +goog.getMsg = function(str, opt_values) { + var values = opt_values || {}; + for (var key in values) { + str = str.replace(new RegExp('\\{\\$' + key + '\\}', 'gi'), values[key]); + } + return str; +}; + + +/** + * Exposes an unobfuscated global namespace path for the given object. + * Note that fields of the exported object *will* be obfuscated, + * unless they are exported in turn via this function or + * goog.exportProperty + * + * <p>Also handy for making public items that are defined in anonymous + * closures. + * + * ex. goog.exportSymbol('Foo', Foo); + * + * ex. goog.exportSymbol('public.path.Foo.staticFunction', + * Foo.staticFunction); + * public.path.Foo.staticFunction(); + * + * ex. goog.exportSymbol('public.path.Foo.prototype.myMethod', + * Foo.prototype.myMethod); + * new public.path.Foo().myMethod(); + * + * @param {string} publicPath Unobfuscated name to export. + * @param {Object} object Object the name should point to. + */ +goog.exportSymbol = function(publicPath, object) { + goog.exportPath_(publicPath, object); +}; + + +/** + * Exports a property unobfuscated into the object's namespace. + * ex. goog.exportProperty(Foo, 'staticFunction', Foo.staticFunction); + * ex. goog.exportProperty(Foo.prototype, 'myMethod', Foo.prototype.myMethod); + * @param {Object} object Object whose static property is being exported. + * @param {string} publicName Unobfuscated name to export. + * @param {Object} symbol Object the name should point to. + */ +goog.exportProperty = function(object, publicName, symbol) { + object[publicName] = symbol; +}; + + + +//============================================================================== +// Extending Function +//============================================================================== + + +/** + * An alias to the {@link goog.bind()} global function. + * + * Usage: + * var g = f.bind(obj, arg1, arg2); + * g(arg3, arg4); + * + * @param {Object} self Specifies the object to which |this| should point + * when the function is run. If the value is null or undefined, it will + * default to the global object. + * @param {Object} var_args Additional arguments that are partially + * applied to fn. + * @return {Function} A partially-applied form of the Function on which bind() + * was invoked as a method. + * @deprecated + */ +Function.prototype.bind = function(self, var_args) { + if (arguments.length > 1) { + var args = Array.prototype.slice.call(arguments, 1); + args.unshift(this, self); + return goog.bind.apply(null, args); + } else { + return goog.bind(this, self); + } +}; + + +/** + * An alias to the {@link goog.partial()} global function. + * + * Usage: + * var g = f.partial(arg1, arg2); + * g(arg3, arg4); + * + * @param {Object} var_args Additional arguments that are partially + * applied to fn. + * @return {Function} A partially-applied form of the function partial() was + * invoked as a method of. + * @deprecated + */ +Function.prototype.partial = function(var_args) { + var args = Array.prototype.slice.call(arguments); + args.unshift(this, null); + return goog.bind.apply(null, args); +}; + + +/** + * Inherit the prototype methods from one constructor into another. + * + * Usage: + * <pre> + * function ParentClass(a, b) { } + * ParentClass.prototype.foo = function(a) { } + * + * function ChildClass(a, b, c) { + * ParentClass.call(this, a, b); + * } + * + * ChildClass.inherits(ParentClass); + * + * var child = new ChildClass('a', 'b', 'see'); + * child.foo(); // works + * </pre> + * + * In addition, a superclass' implementation of a method can be invoked + * as follows: + * + * <pre> + * ChildClass.prototype.foo = function(a) { + * ChildClass.superClass_.foo.call(this, a); + * // other code + * }; + * </pre> + * + * @param {Function} parentCtor Parent class. + */ +Function.prototype.inherits = function(parentCtor) { + goog.inherits(this, parentCtor); +}; + + +/** + * Static variant of Function.prototype.inherits. + * @param {Function} childCtor Child class. + * @param {Function} parentCtor Parent class. + */ +goog.inherits = function(childCtor, parentCtor) { + /** @constructor */ + function tempCtor() {}; + tempCtor.prototype = parentCtor.prototype; + childCtor.superClass_ = parentCtor.prototype; + childCtor.prototype = new tempCtor(); + childCtor.prototype.constructor = childCtor; +}; + + +/** + * Mixes in an object's properties and methods into the callee's prototype. + * Basically mixin based inheritance, thus providing an alternative method for + * adding properties and methods to a class' prototype. + * + * <pre> + * function X() {} + * X.mixin({ + * one: 1, + * two: 2, + * three: 3, + * doit: function() { return this.one + this.two + this.three; } + * }); + * + * function Y() { } + * Y.mixin(X.prototype); + * Y.prototype.four = 15; + * Y.prototype.doit2 = function() { return this.doit() + this.four; } + * }); + * + * // or + * + * function Y() { } + * Y.inherits(X); + * Y.mixin({ + * one: 10, + * four: 15, + * doit2: function() { return this.doit() + this.four; } + * }); + * </pre> + * + * @param {Object} source from which to copy properties. + * @see goog.mixin + * @deprecated + */ +Function.prototype.mixin = function(source) { + goog.mixin(this.prototype, source); +}; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/debugger.css b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/debugger.css new file mode 100644 index 0000000..ed9df2f --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/debugger.css @@ -0,0 +1,35 @@ +/** + * Style for javascript debugger. See debugger.html. + */ + +html,body { + margin: 0px; + padding: 0px; + height: 100%; +} +#output { + font-family: monospace; + background-color: #ffffff; + min-height: 100%; +} +#outer { + height: 100%; + width: 100%; + white-space: pre-wrap; + padding: 0px 0px 24px 0px; +} +#command-line { + bottom: 0px; + /* not quite sure why this 5px is necessary */ + right: 5px; + left: 0px; + position: fixed; + padding: 0px; + margin: 0px; +} +#command-line-text { + height: 20px; + display: block; + width: 100%; + font-family: monospace; +} diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/debugger.html b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/debugger.html new file mode 100644 index 0000000..f6bb917 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/debugger.html @@ -0,0 +1,31 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" + "http://www.w3.org/TR/html4/strict.dtd"> +<html> +<!-- + The UI for the javascript debugger window. +--> + <head> + <title>JavaScript Debugger</title> + <meta http-equiv="Content-Type" content="text/html; charset=UTF8" /> + <link rel="stylesheet" href="debugger.css" type="text/css" /> + <script type="text/javascript" src="DebuggerConsole.js"></script> + <script type="text/javascript" src="DebuggerIPC.js"></script> + <script type="text/javascript" src="DebuggerShell.js"></script> + </head> + + <body onload="onLoad();"> + + <table id='outer'> + <tr> + <td valign='bottom' id='output'>Chrome JavaScript Debugger<br />Type 'help' for a list of commands.<br /></td> + </tr> + </table> + + <div id='command-line'> + <!-- TODO(erikkay) - use addEventListener instead --> + <input id='command-line-text' + type="text" /> + </div> + + </body> +</html> diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/debugger_agent.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/debugger_agent.js new file mode 100644 index 0000000..4454b83 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/debugger_agent.js @@ -0,0 +1,1069 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview Provides communication interface to remote v8 debugger. See + * protocol decription at http://code.google.com/p/v8/wiki/DebuggerProtocol + */ +goog.provide('devtools.DebuggerAgent'); + + +/** + * @constructor + */ +devtools.DebuggerAgent = function() { + RemoteDebuggerAgent.DebuggerOutput = + goog.bind(this.handleDebuggerOutput_, this); + + /** + * Mapping from script id to script info. + * @type {Object} + */ + this.parsedScripts_ = null; + + /** + * Mapping from the request id to the devtools.BreakpointInfo for the + * breakpoints whose v8 ids are not set yet. These breakpoints are waiting for + * 'setbreakpoint' responses to learn their ids in the v8 debugger. + * @see #handleSetBreakpointResponse_ + * @type {Object} + */ + this.requestNumberToBreakpointInfo_ = null; + + /** + * Information on current stack top frame. + * See JavaScriptCallFrame.idl. + * @type {?devtools.CallFrame} + */ + this.currentCallFrame_ = null; + + /** + * Whether to stop in the debugger on the exceptions. + * @type {boolean} + */ + this.pauseOnExceptions_ = true; + + /** + * Mapping: request sequence number->callback. + * @type {Object} + */ + this.requestSeqToCallback_ = null; +}; + + +/** + * Resets debugger agent to its initial state. + */ + devtools.DebuggerAgent.prototype.reset = function() { + this.parsedScripts_ = {}; + this.requestNumberToBreakpointInfo_ = {}; + this.currentCallFrame_ = null; + this.requestSeqToCallback_ = {}; +}; + + +/** + * Asynchronously requests for all parsed script sources. Response will be + * processed in handleScriptsResponse_. + */ +devtools.DebuggerAgent.prototype.requestScripts = function() { + var cmd = new devtools.DebugCommand('scripts', { + 'includeSource': true + }); + devtools.DebuggerAgent.sendCommand_(cmd); + // Force v8 execution so that it gets to processing the requested command. + devtools.tools.evaluateJavaScript('javascript:void(0)'); +}; + + +/** + * Tells the v8 debugger to stop on as soon as possible. + */ +devtools.DebuggerAgent.prototype.pauseExecution = function() { + RemoteDebuggerAgent.DebugBreak(); +}; + + +/** + * @param {number} sourceId Id of the script fot the breakpoint. + * @param {number} line Number of the line for the breakpoint. + */ +devtools.DebuggerAgent.prototype.addBreakpoint = function(sourceId, line) { + var script = this.parsedScripts_[sourceId]; + if (!script) { + return; + } + + line = devtools.DebuggerAgent.webkitToV8LineNumber_(line); + + var breakpointInfo = script.getBreakpointInfo(line); + if (breakpointInfo) { + return; + } + + breakpointInfo = new devtools.BreakpointInfo(sourceId, line); + script.addBreakpointInfo(breakpointInfo); + + var cmd = new devtools.DebugCommand('setbreakpoint', { + 'type': 'scriptId', + 'target': sourceId, + 'line': line + }); + + this.requestNumberToBreakpointInfo_[cmd.getSequenceNumber()] = breakpointInfo; + + devtools.DebuggerAgent.sendCommand_(cmd); +}; + + +/** + * @param {number} sourceId Id of the script fot the breakpoint. + * @param {number} line Number of the line for the breakpoint. + */ +devtools.DebuggerAgent.prototype.removeBreakpoint = function(sourceId, line) { + var script = this.parsedScripts_[sourceId]; + if (!script) { + return; + } + + line = devtools.DebuggerAgent.webkitToV8LineNumber_(line); + + var breakpointInfo = script.getBreakpointInfo(line); + script.removeBreakpointInfo(breakpointInfo); + breakpointInfo.markAsRemoved(); + + var id = breakpointInfo.getV8Id(); + + // If we don't know id of this breakpoint in the v8 debugger we cannot send + // 'clearbreakpoint' request. In that case it will be removed in + // 'setbreakpoint' response handler when we learn the id. + if (id != -1) { + this.requestClearBreakpoint_(id); + } +}; + + +/** + * Tells the v8 debugger to step into the next statement. + */ +devtools.DebuggerAgent.prototype.stepIntoStatement = function() { + this.stepCommand_('in'); +}; + + +/** + * Tells the v8 debugger to step out of current function. + */ +devtools.DebuggerAgent.prototype.stepOutOfFunction = function() { + this.stepCommand_('out'); +}; + + +/** + * Tells the v8 debugger to step over the next statement. + */ +devtools.DebuggerAgent.prototype.stepOverStatement = function() { + this.stepCommand_('next'); +}; + + +/** + * Tells the v8 debugger to continue execution after it has been stopped on a + * breakpoint or an exception. + */ +devtools.DebuggerAgent.prototype.resumeExecution = function() { + var cmd = new devtools.DebugCommand('continue'); + devtools.DebuggerAgent.sendCommand_(cmd); +}; + + +/** + * @return {boolean} True iff the debugger will pause execution on the + * exceptions. + */ +devtools.DebuggerAgent.prototype.pauseOnExceptions = function() { + return this.pauseOnExceptions_; +}; + + +/** + * Tells whether to pause in the debugger on the exceptions or not. + * @param {boolean} value True iff execution should be stopped in the debugger + * on the exceptions. + */ +devtools.DebuggerAgent.prototype.setPauseOnExceptions = function(value) {
+ this.pauseOnExceptions_ = value; +}; + + +/** + * Current stack top frame. + * @return {devtools.CallFrame} + */ +devtools.DebuggerAgent.prototype.getCurrentCallFrame = function() { + return this.currentCallFrame_; +}; + + +/** + * Sends 'evaluate' request to the debugger. + * @param {Object} arguments Request arguments map. + * @param {function(devtools.DebuggerMessage)} callback Callback to be called + * when response is received. + */ +devtools.DebuggerAgent.prototype.requestEvaluate = function( + arguments, callback) { + var cmd = new devtools.DebugCommand('evaluate', arguments); + devtools.DebuggerAgent.sendCommand_(cmd); + this.requestSeqToCallback_[cmd.getSequenceNumber()] = callback; +}; + + +/** + * Sends 'lookup' request for each unresolved property of the object. When + * response is received the properties will be changed with their resolved + * values. + * @param {Object} object Object whose properties should be resolved. + * @param {function(devtools.DebuggerMessage)} Callback to be called when all + * children are resolved. + */ +devtools.DebuggerAgent.prototype.resolveChildren = function(object, callback) { + var handles = []; + var names = []; + for (var name in object) { + var value = object[name]; + if (goog.isObject(value) && 'ref' in value) { + handles.push(value.ref); + names.push(name); + } + } + if (handles.length == 0) { + callback(object); + return; + } + this.requestLookup_(handles, function(msg) { + var handleToObject = msg.getBody(); + for (var i = 0; i < names.length; i++) { + var name = names[i]; + var jsonObj = handleToObject[object[name].ref] + object[name] = devtools.DebuggerAgent.formatValue_(jsonObj, msg); + } + callback(object); + }); +}; + + +/** + * Removes specified breakpoint from the v8 debugger. + * @param {number} breakpointId Id of the breakpoint in the v8 debugger. + */ +devtools.DebuggerAgent.prototype.requestClearBreakpoint_ = function( + breakpointId) { + var cmd = new devtools.DebugCommand('clearbreakpoint', { + 'breakpoint': breakpointId + }); + devtools.DebuggerAgent.sendCommand_(cmd); +}; + + +/** + * Sends 'backtrace' request to v8. + */ +devtools.DebuggerAgent.prototype.requestBacktrace_ = function() { + var cmd = new devtools.DebugCommand('backtrace'); + devtools.DebuggerAgent.sendCommand_(cmd); +}; + + +/** + * Sends command to v8 debugger. + * @param {devtools.DebugCommand} cmd Command to execute. + */ +devtools.DebuggerAgent.sendCommand_ = function(cmd) { + RemoteDebuggerCommandExecutor.DebuggerCommand(cmd.toJSONProtocol()); +}; + + +/** + * Tells the v8 debugger to make the next execution step. + * @param {string} action 'in', 'out' or 'next' action. + */ +devtools.DebuggerAgent.prototype.stepCommand_ = function(action) { + var cmd = new devtools.DebugCommand('continue', { + 'stepaction': action, + 'stepcount': 1 + }); + devtools.DebuggerAgent.sendCommand_(cmd); +}; + + +/** + * Sends 'lookup' request to v8. + * @param {number} handle Handle to the object to lookup. + */ +devtools.DebuggerAgent.prototype.requestLookup_ = function(handles, callback) { + var cmd = new devtools.DebugCommand('lookup', { + 'handles': handles + }); + devtools.DebuggerAgent.sendCommand_(cmd); + this.requestSeqToCallback_[cmd.getSequenceNumber()] = callback; +}; + + +/** + * Handles output sent by v8 debugger. The output is either asynchronous event + * or response to a previously sent request. See protocol definitioun for more + * details on the output format. + * @param {string} output + */ +devtools.DebuggerAgent.prototype.handleDebuggerOutput_ = function(output) { + var msg; + try { + msg = new devtools.DebuggerMessage(output); + } catch(e) { + debugPrint('Failed to handle debugger reponse:\n' + e); + throw e; + } + + + if (msg.getType() == 'event') { + if (msg.getEvent() == 'break') { + this.handleBreakEvent_(msg); + } else if (msg.getEvent() == 'exception') { + this.handleExceptionEvent_(msg); + } else if (msg.getEvent() == 'afterCompile') { + this.handleAfterCompileEvent_(msg); + } + } else if (msg.getType() == 'response') { + if (msg.getCommand() == 'scripts') { + this.handleScriptsResponse_(msg); + } else if (msg.getCommand() == 'setbreakpoint') { + this.handleSetBreakpointResponse_(msg); + } else if (msg.getCommand() == 'clearbreakpoint') { + this.handleClearBreakpointResponse_(msg); + } else if (msg.getCommand() == 'backtrace') { + this.handleBacktraceResponse_(msg); + } else if (msg.getCommand() == 'lookup') { + this.invokeCallbackForResponse_(msg); + } else if (msg.getCommand() == 'evaluate') { + this.invokeCallbackForResponse_(msg); + } + } +}; + + +/** + * @param {devtools.DebuggerMessage} msg + */ +devtools.DebuggerAgent.prototype.handleBreakEvent_ = function(msg) { + var body = msg.getBody(); + + var line = devtools.DebuggerAgent.v8ToWwebkitLineNumber_(body.sourceLine); + this.currentCallFrame_ = new devtools.CallFrame(); + this.currentCallFrame_.sourceID = body.script.id; + this.currentCallFrame_.line = line; + this.currentCallFrame_.script = body.script; + this.requestBacktrace_(); +}; + + +/** + * @param {devtools.DebuggerMessage} msg + */ +devtools.DebuggerAgent.prototype.handleExceptionEvent_ = function(msg) { + var body = msg.getBody(); + debugPrint('Uncaught exception in ' + body.script.name + ':' + + body.sourceLine + '\n' + body.sourceLineText); + if (this.pauseOnExceptions_) { + var body = msg.getBody(); + + var sourceId = -1; + // The exception may happen in native code in which case there is no script. + if (body.script) { + sourceId = body.script.id; + } + + var line = devtools.DebuggerAgent.v8ToWwebkitLineNumber_(body.sourceLine); + + this.currentCallFrame_ = new devtools.CallFrame(); + this.currentCallFrame_.sourceID = sourceId; + this.currentCallFrame_.line = line; + this.currentCallFrame_.script = body.script; + this.requestBacktrace_(); + } else { + this.resumeExecution(); + } +}; + + +/** + * @param {devtools.DebuggerMessage} msg + */ +devtools.DebuggerAgent.prototype.handleScriptsResponse_ = function(msg) { + var scripts = msg.getBody(); + for (var i = 0; i < scripts.length; i++) { + var script = scripts[i]; + + // We may already have received the info in an afterCompile event. + if (script.id in this.parsedScripts_) { + continue; + } + this.addScriptInfo_(script); + } +}; + + +/** + * @param {devtools.DebuggerMessage} msg + */ +devtools.DebuggerAgent.prototype.handleSetBreakpointResponse_ = function(msg) { + var requestSeq = msg.getRequestSeq(); + var breakpointInfo = this.requestNumberToBreakpointInfo_[requestSeq]; + if (!breakpointInfo) { + // TODO(yurys): handle this case + return; + } + delete this.requestNumberToBreakpointInfo_[requestSeq]; + if (!msg.isSuccess()) { + // TODO(yurys): handle this case + return; + } + var idInV8 = msg.getBody().breakpoint; + breakpointInfo.setV8Id(idInV8); + + if (breakpointInfo.isRemoved()) { + this.requestClearBreakpoint_(idInV8); + } +}; + + +/** + * @param {devtools.DebuggerMessage} msg + */ +devtools.DebuggerAgent.prototype.handleAfterCompileEvent_ = function(msg) { + var script = msg.getBody().script; + this.addScriptInfo_(script); +}; + + +/** + * Adds the script info to the local cache. This method assumes that the script + * is not in the cache yet. + * @param {Object} script Script json object from the debugger message. + */ +devtools.DebuggerAgent.prototype.addScriptInfo_ = function(script) { + this.parsedScripts_[script.id] = new devtools.ScriptInfo( + script.id, script.lineOffset); + WebInspector.parsedScriptSource( + script.id, script.name, script.source, script.lineOffset); +}; + + +/** + * @param {devtools.DebuggerMessage} msg + */ +devtools.DebuggerAgent.prototype.handleClearBreakpointResponse_ = function( + msg) { + // Do nothing. +}; + + +/** + * Handles response to 'backtrace' command. + * @param {devtools.DebuggerMessage} msg + */ +devtools.DebuggerAgent.prototype.handleBacktraceResponse_ = function(msg) { + if (!this.currentCallFrame_) { + return; + } + + var script = this.currentCallFrame_.script; + + var callerFrame = null; + var f = null; + var frames = msg.getBody().frames; + for (var i = frames.length - 1; i>=0; i--) { + var nextFrame = frames[i]; + var f = devtools.DebuggerAgent.formatCallFrame_(nextFrame, script, msg); + f.frameNumber = i; + f.caller = callerFrame; + callerFrame = f; + } + + this.currentCallFrame_ = f; + + WebInspector.pausedScript(); + DevToolsHost.activateWindow(); +}; + + +/** + * Handles response to a command by invoking its callback (if any). + * @param {devtools.DebuggerMessage} msg + */ +devtools.DebuggerAgent.prototype.invokeCallbackForResponse_ = function(msg) { + var callback = this.requestSeqToCallback_[msg.getRequestSeq()]; + if (!callback) { + // It may happend if reset was called. + return; + } + delete this.requestSeqToCallback_[msg.getRequestSeq()]; + callback(msg); +}; + + +devtools.DebuggerAgent.prototype.evaluateInCallFrame_ = function(expression) { +}; + + +/** + * @param {Object} stackFrame Frame json object from 'backtrace' response. + * @param {Object} script Script json object from 'break' event. + * @param {devtools.DebuggerMessage} msg Parsed 'backtrace' response. + * @return {!devtools.CallFrame} Object containing information related to the + * call frame in the format expected by ScriptsPanel and its panes. + */ +devtools.DebuggerAgent.formatCallFrame_ = function(stackFrame, script, msg) { + var sourceId = script.id; + var func = msg.lookup(stackFrame.func.ref); + var funcScript = msg.lookup(func.script.ref); + if (funcScript && 'id' in funcScript) { + sourceId = funcScript.id; + } + + var funcName = devtools.DebuggerAgent.formatFunctionCall_(stackFrame, msg); + + var scope = {}; + + // Add arguments. + devtools.DebuggerAgent.valuesArrayToMap_(stackFrame.arguments, scope, msg); + + // Add local variables. + devtools.DebuggerAgent.valuesArrayToMap_(stackFrame.locals, scope, msg); + + var thisObject = msg.lookup(stackFrame.receiver.ref); + // Add variable with name 'this' to the scope. + scope['this'] = devtools.DebuggerAgent.formatObject_(thisObject, msg); + + var line = devtools.DebuggerAgent.v8ToWwebkitLineNumber_(stackFrame.line); + var result = new devtools.CallFrame(); + result.sourceID = sourceId; + result.line = line; + result.type = 'function'; + result.functionName = funcName; + result.localScope = scope; + result.scopeChain = [scope]; + result.thisObject = thisObject; + return result; +}; + + +/** + * Returns user-friendly representation of the function call from the stack + * frame. + * @param {Object} stackFrame Frame json object from 'backtrace' response. + * @return {!string} Function name with argument values. + */ +devtools.DebuggerAgent.formatFunctionCall_ = function(stackFrame, msg) { + var func = msg.lookup(stackFrame.func.ref); + return func.name || func.inferredName || '(anonymous function)'; +}; + + +/** + * Converts an object from the debugger response to the format understandable + * by ScriptsPanel. + * @param {Object} object An object from the debugger protocol response. + * @param {devtools.DebuggerMessage} msg Parsed debugger response. + * @return {!Object} Object describing 'object' in the format expected by + * ScriptsPanel and its panes. + */ +devtools.DebuggerAgent.formatObject_ = function(object, msg) { + var result = {}; + devtools.DebuggerAgent.formatObjectProperties_(object, msg, result); + return { 'value': result }; +}; + + +/** + * Converts a function from the debugger response to the format understandable + * by ScriptsPanel. + * @param {Object} func Function object from the debugger protocol response. + * @param {devtools.DebuggerMessage} msg Parsed debugger response. + * @return {!Object} Object describing 'func' in the format expected by + * ScriptsPanel and its panes. + */ +devtools.DebuggerAgent.formatFunction_ = function(func, msg) { + var result = {}; + devtools.DebuggerAgent.formatObjectProperties_(func, msg, result); + result.name = func.name; + + var holder = function() {}; + holder.value = result; + return holder; +}; + + +/** + * Collects properties for an object from the debugger response. + * @param {Object} object An object from the debugger protocol response. + * @param {devtools.DebuggerMessage} msg Parsed debugger response. + * @param {Object} result A map to put the properties in. + */ +devtools.DebuggerAgent.formatObjectProperties_ = function(object, + msg, result) { + devtools.DebuggerAgent.propertiesToMap_(object.properties, result, msg); + result.protoObject = devtools.DebuggerAgent.formatObjectReference_( + object.protoObject, msg); + result.prototypeObject = devtools.DebuggerAgent.formatObjectReference_( + object.prototypeObject, msg); + result.constructorFunction = devtools.DebuggerAgent.formatObjectReference_( + object.constructorFunction, msg); +}; + + +/** + * For each property in 'properties' puts its name and user-friendly value into + * 'map'. + * @param {Array.<Object>} properties Receiver properties array from 'backtrace' + * response. + * @param {Object} map Result holder. + * @param {devtools.DebuggerMessage} msg Parsed 'backtrace' response. + */ +devtools.DebuggerAgent.propertiesToMap_ = function(properties, map, msg) { + for (var j = 0; j < properties.length; j++) { + var nextValue = properties[j]; + map[nextValue.name] = devtools.DebuggerAgent.formatObjectReference_( + nextValue, msg); + } +}; + + +/** + * For each property in 'array' puts its name and user-friendly value into + * 'map'. Each object referenced from the array is expected to be included in + * the message. + * @param {Array.<Object>} array Arguments or locals array from 'backtrace' + * response. + * @param {Object} map Result holder. + * @param {devtools.DebuggerMessage} msg Parsed 'backtrace' response. + */ +devtools.DebuggerAgent.valuesArrayToMap_ = function(array, map, msg) { + for (var j = 0; j < array.length; j++) { + var nextValue = array[j]; + + var object = msg.lookup(nextValue.value.ref); + var val = object ? + devtools.DebuggerAgent.formatValue_(object, msg) : + '<unresolved ref: ' + nextValue.value.ref + '>'; + map[nextValue.name] = val; + } +}; + + +/** + * TODO(yurys): we should merge all this formatting code with the one for + * elements tree. + * @param {Object} object An object reference from the debugger response. + * @param {devtools.DebuggerMessage} msg Parsed debugger response. + * @return {*} The reference representation expected by ScriptsPanel. + */ +devtools.DebuggerAgent.formatObjectReference_ = function(objectRef, msg) { + if (!('ref' in objectRef)) { + return objectRef; + } + var object = msg.lookup(objectRef.ref); + if (!object) { + return objectRef; + } + switch (object.type) { + case 'number': + case 'string': + case 'boolean': + return object.value; + case 'undefined': + return undefined; + case 'null': + return null; + case 'function': { + var result = function() {}; + result.ref = objectRef.ref; + return result; + } + case 'object': + return objectRef; + default: + return objectRef; + }; +}; + + +/** + * @param {Object} object An object from the debugger response. + * @param {devtools.DebuggerMessage} msg Parsed debugger response. + * @return {*} The value representation expected by ScriptsPanel. + */ +devtools.DebuggerAgent.formatValue_ = function(object, msg) { + if (!object) { + return object; + } + switch (object.type) { + case 'number': + case 'string': + case 'boolean': + return object.value; + case 'undefined': + return undefined; + case 'null': + return null; + case 'function': + return devtools.DebuggerAgent.formatFunction_(object, msg); + case 'object': + return devtools.DebuggerAgent.formatObject_(object, msg); + default: + return '<invalid value>'; + }; +}; + + +devtools.DebuggerAgent.formatObjectReference_old = function(objectRef, msg) { + if (!objectRef.ref) { + return 'illegal ref'; + } + + var object = msg.lookup(objectRef.ref); + if (!object) { + return '{ref: ' + objectRef.ref + '}'; + } + + if ('value' in object) { + return object.value; + } + return '[' + object.type + ']'; +}; + + +/** + * Converts line number from Web Inspector UI(1-based) to v8(0-based). + * @param {number} line Resource line number in Web Inspector UI. + * @return {number} The line number in v8. + */ +devtools.DebuggerAgent.webkitToV8LineNumber_ = function(line) { + return line - 1; +}; + + +/** + * Converts line number from v8(0-based) to Web Inspector UI(1-based). + * @param {number} line Resource line number in v8. + * @return {number} The line number in Web Inspector. + */ +devtools.DebuggerAgent.v8ToWwebkitLineNumber_ = function(line) { + return line + 1; +}; + + +/** + * @param {number} scriptId Id of the script. + * @param {number} lineOffset First line 0-based offset in the containing + * document. + * @constructor + */ +devtools.ScriptInfo = function(scriptId, lineOffset) { + this.scriptId_ = scriptId; + this.lineOffset_ = lineOffset; + + this.lineToBreakpointInfo_ = {}; +}; + + +/** + * @return {number} + */ +devtools.ScriptInfo.prototype.getLineOffset = function() { + return this.lineOffset_; +}; + + +/** + * @param {number} line 0-based line number in the script. + * @return {?devtools.BreakpointInfo} Information on a breakpoint at the + * specified line in the script or undefined if there is no breakpoint at + * that line. + */ +devtools.ScriptInfo.prototype.getBreakpointInfo = function(line) { + return this.lineToBreakpointInfo_[line]; +}; + + +/** + * Adds breakpoint info to the script. + * @param {devtools.BreakpointInfo} breakpoint + */ +devtools.ScriptInfo.prototype.addBreakpointInfo = function(breakpoint) { + this.lineToBreakpointInfo_[breakpoint.getLine()] = breakpoint; +}; + + +/** + * @param {devtools.BreakpointInfo} breakpoint Breakpoint info to be removed. + */ +devtools.ScriptInfo.prototype.removeBreakpointInfo = function(breakpoint) { + var line = breakpoint.getLine(); + delete this.lineToBreakpointInfo_[line]; +}; + + + +/** + * @param {number} scriptId Id of the owning script. + * @param {number} line Breakpoint 0-based line number in the containing script. + * @constructor + */ +devtools.BreakpointInfo = function(sourceId, line) { + this.sourceId_ = sourceId; + this.line_ = line; + this.v8id_ = -1; + this.removed_ = false; +}; + + +/** + * @return {number} + */ +devtools.BreakpointInfo.prototype.getSourceId = function(n) { + return this.sourceId_; +}; + + +/** + * @return {number} + */ +devtools.BreakpointInfo.prototype.getLine = function(n) { + return this.line_; +}; + + +/** + * @return {number} Unique identifier of this breakpoint in the v8 debugger. + */ +devtools.BreakpointInfo.prototype.getV8Id = function(n) { + return this.v8id_; +}; + + +/** + * Sets id of this breakpoint in the v8 debugger. + * @param {number} id + */ +devtools.BreakpointInfo.prototype.setV8Id = function(id) { + this.v8id_ = id; +}; + + +/** + * Marks this breakpoint as removed from the front-end. + */ +devtools.BreakpointInfo.prototype.markAsRemoved = function() { + this.removed_ = true; +}; + + +/** + * @return {boolean} Whether this breakpoint has been removed from the + * front-end. + */ +devtools.BreakpointInfo.prototype.isRemoved = function() { + return this.removed_; +}; + + +/** + * Call stack frame data. + * @construnctor + */ +devtools.CallFrame = function() { + this.sourceID = null; + this.line = null; + this.type = 'function'; + this.functionName = null; + this.caller = null; + this.localScope = null; + this.scopeChain = []; + this.thisObject = {}; + this.frameNumber = null; +}; + + +/** + * This method is called by + * WebInspector.ScriptsPanel.evaluateInSelectedCallFrame. This method issues + * asynchronous evaluate request. + * @param {string} expression An expression to be evaluated in the context of + * this call frame. + * @return {string} User message that the expression is being evaluated. + */ +devtools.CallFrame.prototype.evaluate = function(expression) { + devtools.tools.getDebuggerAgent().requestEvaluate({ + 'expression': expression, + 'frame': this.frameNumber, + 'global': false, + 'disable_break': false + }, + devtools.CallFrame.handleEvaluateResponse_); + return 'evaluating...'; +}; + + +/** + * Handles 'evaluate' response for a call frame + * @param {devtools.DebuggerMessage} response + */ +devtools.CallFrame.handleEvaluateResponse_ = function(response) { + var body = response.getBody(); + var value = devtools.DebuggerAgent.formatValue_(body); + WebInspector.addMessageToConsole(new WebInspector.ConsoleCommandResult( + value, false /* exception */, null /* commandMessage */)); +}; + + +/** + * JSON based commands sent to v8 debugger. + * @param {string} command Name of the command to execute. + * @param {Object} opt_arguments Command-specific arguments map. + * @constructor + */ +devtools.DebugCommand = function(command, opt_arguments) { + this.command_ = command; + this.type_ = 'request'; + this.seq_ = ++devtools.DebugCommand.nextSeq_; + if (opt_arguments) { + this.arguments_ = opt_arguments; + } +}; + + +/** + * Next unique number to be used as debugger request sequence number. + * @type {number} + */ +devtools.DebugCommand.nextSeq_ = 1; + + +/** + * @return {number} + */ +devtools.DebugCommand.prototype.getSequenceNumber = function() { + return this.seq_; +}; + + +/** + * @return {string} + */ +devtools.DebugCommand.prototype.toJSONProtocol = function() { + var json = { + 'seq': this.seq_, + 'type': this.type_, + 'command': this.command_ + } + if (this.arguments_) { + json.arguments = this.arguments_; + } + return goog.json.serialize(json); +}; + + + +/** + * JSON messages sent from v8 debugger. See protocol definition for more + * details: http://code.google.com/p/v8/wiki/DebuggerProtocol + * @param {string} msg Raw protocol packet as JSON string. + * @constructor + */ +devtools.DebuggerMessage = function(msg) { + var jsExpression = '[' + msg + '][0]'; + this.packet_ = eval(jsExpression); + this.refs_ = []; + if (this.packet_.refs) { + for (var i = 0; i < this.packet_.refs.length; i++) { + this.refs_[this.packet_.refs[i].handle] = this.packet_.refs[i]; + } + } +}; + + +/** + * @return {string} The packet type. + */ +devtools.DebuggerMessage.prototype.getType = function() { + return this.packet_.type; +}; + + +/** + * @return {?string} The packet event if the message is an event. + */ +devtools.DebuggerMessage.prototype.getEvent = function() { + return this.packet_.event; +}; + + +/** + * @return {?string} The packet command if the message is a response to a + * command. + */ +devtools.DebuggerMessage.prototype.getCommand = function() { + return this.packet_.command; +}; + + +/** + * @return {number} The packet request sequence. + */ +devtools.DebuggerMessage.prototype.getRequestSeq = function() { + return this.packet_.request_seq; +}; + + +/** + * @return {number} Whether the v8 is running after processing the request. + */ +devtools.DebuggerMessage.prototype.isRunning = function() { + return this.packet_.running ? true : false; +}; + + +/** + * @return {boolean} Whether the request succeeded. + */ +devtools.DebuggerMessage.prototype.isSuccess = function() { + return this.packet_.success ? true : false; +}; + + +/** + * @return {string} + */ +devtools.DebuggerMessage.prototype.getMessage = function() { + return this.packet_.message; +}; + + +/** + * @return {Object} Parsed message body json. + */ +devtools.DebuggerMessage.prototype.getBody = function() { + return this.packet_.body; +}; + + +/** + * @param {number} handle Object handle. + * @return {?Object} Returns the object with the handle if it was sent in this + * message(some objects referenced by handles may be missing in the message). + */ +devtools.DebuggerMessage.prototype.lookup = function(handle) { + return this.refs_[handle]; +}; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/devtools.html b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/devtools.html new file mode 100644 index 0000000..3176bea --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/devtools.html @@ -0,0 +1,117 @@ +<!-- +Copyright (c) 2009 The Chromium Authors. All rights reserved. + +This is the Chromium version of the WebInspector. This html file serves +as a deployment descriptor and specifies which js libraries to include into the +app. Once the "main" frontend method that is building WebInspector +from the js building blocks is extracted, we will be able have different +implementations of it for Chromium and WebKit. That would allow us for +example not to create WebKit Database tab and remove corresponding js files +from here. Longer term we would like to employ closure + basic js compilation. +That way js libraries would know their dependencies and js compiler would be +able to compile them into a single file. After that this HTML file will +include single <script src='fe-compiled.js'> and will become upstreamable. + +Copyright (C) 2006, 2007, 2008 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. +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. +--> +<!DOCTYPE html> +<html> +<head> + <meta http-equiv="content-type" content="text/html; charset=utf-8"> + <link rel="stylesheet" type="text/css" href="inspector.css"> + <script type="text/javascript" src="base.js"></script> + <script type="text/javascript" src="json.js"></script> + <script type="text/javascript" src="utilities.js"></script> + <script type="text/javascript" src="treeoutline.js"></script> + <script type="text/javascript" src="devtools_callback.js"></script> + <script type="text/javascript" src="debugger_agent.js"></script> + <script type="text/javascript" src="dom_agent.js"></script> + <script type="text/javascript" src="net_agent.js"></script> + <script type="text/javascript" src="inspector_controller.js"></script> + <script type="text/javascript" src="inspector_controller_impl.js"></script> + <script type="text/javascript" src="inspector.js"></script> + <script type="text/javascript" src="Object.js"></script> + <script type="text/javascript" src="TextPrompt.js"></script> + <script type="text/javascript" src="Placard.js"></script> + <script type="text/javascript" src="View.js"></script> + <script type="text/javascript" src="Console.js"></script> + <script type="text/javascript" src="Resource.js"></script> + <script type="text/javascript" src="ResourceCategory.js"></script> + <script type="text/javascript" src="Database.js"></script> + <script type="text/javascript" src="DOMStorage.js"></script> + <script type="text/javascript" src="DOMStorageItemsView.js"></script> + <script type="text/javascript" src="DataGrid.js"></script> + <script type="text/javascript" src="DOMStorageDataGrid.js"></script> + <script type="text/javascript" src="Script.js"></script> + <script type="text/javascript" src="Breakpoint.js"></script> + <script type="text/javascript" src="SidebarPane.js"></script> + <script type="text/javascript" src="ElementsTreeOutline.js"></script> + <script type="text/javascript" src="SidebarTreeElement.js"></script> + <script type="text/javascript" src="PropertiesSection.js"></script> + <script type="text/javascript" src="ObjectPropertiesSection.js"></script> + <script type="text/javascript" src="BreakpointsSidebarPane.js"></script> + <script type="text/javascript" src="CallStackSidebarPane.js"></script> + <script type="text/javascript" src="ScopeChainSidebarPane.js"></script> + <script type="text/javascript" src="MetricsSidebarPane.js"></script> + <script type="text/javascript" src="PropertiesSidebarPane.js"></script> + <script type="text/javascript" src="StylesSidebarPane.js"></script> + <script type="text/javascript" src="Panel.js"></script> + <script type="text/javascript" src="PanelEnablerView.js"></script> + <script type="text/javascript" src="ElementsPanel.js"></script> + <script type="text/javascript" src="ResourcesPanel.js"></script> + <script type="text/javascript" src="ScriptsPanel.js"></script> + <script type="text/javascript" src="DatabasesPanel.js"></script> + <script type="text/javascript" src="ProfilesPanel.js"></script> + <script type="text/javascript" src="ResourceView.js"></script> + <script type="text/javascript" src="SourceFrame.js"></script> + <script type="text/javascript" src="SourceView.js"></script> + <script type="text/javascript" src="FontView.js"></script> + <script type="text/javascript" src="ImageView.js"></script> + <script type="text/javascript" src="DatabaseTableView.js"></script> + <script type="text/javascript" src="DatabaseQueryView.js"></script> + <script type="text/javascript" src="ScriptView.js"></script> + <script type="text/javascript" src="ProfileView.js"></script> + <script type="text/javascript" src="devtools.js"></script> + <script type="text/javascript" src="devtools_host_stub.js"></script> +</head> +<body class="detached"> + <div id="toolbar"> + <div class="toolbar-item close"><button id="close-button"></button></div> + <div class="toolbar-item flexable-space"></div> + <div class="toolbar-item hidden" id="search-results-matches"></div> + <div class="toolbar-item"><input id="search" type="search" incremental results="0"><div id="search-toolbar-label" class="toolbar-label"></div></div> + </div> + <div id="main"> + <div id="main-panels" tabindex="0"></div> + <div id="main-status-bar" class="status-bar"><div id="anchored-status-bar-items"><button id="dock-status-bar-item" class="status-bar-item toggled"></button><button id="console-status-bar-item" class="status-bar-item"></button><div id="error-warning-count" class="hidden"></div></div></div> + </div> + <div id="console"> + <div id="console-messages"><div id="console-prompt"><br></div></div> + <div id="console-status-bar" class="status-bar"><div id="other-console-status-bar-items"><button id="clear-console-status-bar-item" class="status-bar-item"></button></div></div> + </div> +</body> +</html> diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/devtools.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/devtools.js new file mode 100644 index 0000000..107a8ea --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/devtools.js @@ -0,0 +1,707 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview Tools is a main class that wires all components of the + * DevTools frontend together. It is also responsible for overriding existing + * WebInspector functionality while it is getting upstreamed into WebCore. + */ +goog.provide('devtools.Tools'); + +goog.require('devtools.DebuggerAgent'); +goog.require('devtools.DomAgent'); +goog.require('devtools.NetAgent'); + +devtools.ToolsAgent = function() { + RemoteToolsAgent.DidEvaluateJavaScript = devtools.Callback.processCallback; + RemoteToolsAgent.DidExecuteUtilityFunction = + devtools.Callback.processCallback; + RemoteToolsAgent.UpdateFocusedNode = + goog.bind(this.updateFocusedNode, this); + RemoteToolsAgent.FrameNavigate = + goog.bind(this.frameNavigate, this); + RemoteToolsAgent.AddMessageToConsole = + goog.bind(this.addMessageToConsole, this); + this.debuggerAgent_ = new devtools.DebuggerAgent(); + this.domAgent_ = new devtools.DomAgent(); + this.netAgent_ = new devtools.NetAgent(); +}; + + +/** + * Resets tools agent to its initial state. + */ +devtools.ToolsAgent.prototype.reset = function() { + this.domAgent_.reset(); + this.netAgent_.reset(); + this.debuggerAgent_.reset(); + + this.domAgent_.getDocumentElementAsync(); + this.debuggerAgent_.requestScripts(); +}; + + +/** + * @param {string} script Script exression to be evaluated in the context of the + * inspected page. + * @param {function(string):undefined} callback Function to call with the + * result. + */ +devtools.ToolsAgent.prototype.evaluateJavaScript = function(script, callback) { + var callbackId = devtools.Callback.wrap(callback); + RemoteToolsAgent.EvaluateJavaScript(callbackId, script); +}; + + +/** + * @return {devtools.DebuggerAgent} Debugger agent instance. + */ +devtools.ToolsAgent.prototype.getDebuggerAgent = function() { + return this.debuggerAgent_; +}; + +/** + * DomAgent accessor. + * @return {devtools.DomAgent} Dom agent instance. + */ +devtools.ToolsAgent.prototype.getDomAgent = function() { + return this.domAgent_; +}; + + +/** + * NetAgent accessor. + * @return {devtools.NetAgent} Net agent instance. + */ +devtools.ToolsAgent.prototype.getNetAgent = function() { + return this.netAgent_; +}; + + +/** + * @see tools_agent.h + */ +devtools.ToolsAgent.prototype.updateFocusedNode = function(nodeId) { + var node = this.domAgent_.getNodeForId(nodeId); + WebInspector.updateFocusedNode(node); +}; + + +/** + * @param {string} url Url frame navigated to. + * @param {bool} topLevel True iff top level navigation occurred. + * @see tools_agent.h + */ +devtools.ToolsAgent.prototype.frameNavigate = function(url, topLevel) { + if (topLevel) { + this.reset(); + WebInspector.reset(); + } +}; + + +/** + * @param {Object} message Message object to add. + * @see tools_agent.h + */ +devtools.ToolsAgent.prototype.addMessageToConsole = function(message) { + var console = WebInspector.console; + if (console) { + console.addMessage(new WebInspector.ConsoleMessage( + message.source, message.level, message.line, message.sourceId, + undefined, 1, message.text)); + } +}; + + +/** + * Evaluates js expression. + * @param {string} expr + */ +devtools.ToolsAgent.prototype.evaluate = function(expr) { + RemoteToolsAgent.evaluate(expr); +}; + + +/** + * Prints string to the inspector console or shows alert if the console doesn't + * exist. + * @param {string} text + */ +function debugPrint(text) { + var console = WebInspector.console; + if (console) { + console.addMessage(new WebInspector.ConsoleMessage( + '', undefined, 1, '', undefined, 1, text)); + } else { + alert(text); + } +} + + +/** + * Global instance of the tools agent. + * @type {devtools.ToolsAgent} + */ +devtools.tools = null; + + +var context = {}; // Used by WebCore's inspector routines. + + +/////////////////////////////////////////////////////////////////////////////// +// Here and below are overrides to existing WebInspector methods only. +// TODO(pfeldman): Patch WebCore and upstream changes. +var oldLoaded = WebInspector.loaded; +WebInspector.loaded = function() { + devtools.tools = new devtools.ToolsAgent(); + devtools.tools.reset(); + + Preferences.ignoreWhitespace = false; + oldLoaded.call(this); + + DevToolsHost.loaded(); +}; + + +var webkitUpdateChildren = + WebInspector.ElementsTreeElement.prototype.updateChildren; + + +/** + * @override + */ +WebInspector.ElementsTreeElement.prototype.updateChildren = function() { + var self = this; + devtools.tools.getDomAgent().getChildNodesAsync(this.representedObject, + function() { + webkitUpdateChildren.call(self); + }); +}; + + +/** + * @override + */ +WebInspector.ElementsPanel.prototype.performSearch = function(query) { + this.searchCanceled(); + devtools.tools.getDomAgent().performSearch(query, + goog.bind(this.performSearchCallback_, this)); +}; + + +WebInspector.ElementsPanel.prototype.performSearchCallback_ = function(nodes) { + for (var i = 0; i < nodes.length; ++i) { + var treeElement = this.treeOutline.findTreeElement(nodes[i]); + if (treeElement) + treeElement.highlighted = true; + } + + if (nodes.length) { + this.currentSearchResultIndex_ = 0; + this.focusedDOMNode = nodes[0]; + } + + this.searchResultCount_ = nodes.length; +}; + + +/** + * @override + */ +WebInspector.ElementsPanel.prototype.searchCanceled = function() { + this.currentSearchResultIndex_ = 0; + this.searchResultCount_ = 0; + devtools.tools.getDomAgent().searchCanceled( + goog.bind(this.searchCanceledCallback_, this)); +}; + + +WebInspector.ElementsPanel.prototype.searchCanceledCallback_ = function(nodes) { + for (var i = 0; i < nodes.length; i++) { + var treeElement = this.treeOutline.findTreeElement(nodes[i]); + if (treeElement) + treeElement.highlighted = false; + } +}; + + +/** + * @override + */ +WebInspector.ElementsPanel.prototype.jumpToNextSearchResult = function() { + if (!this.searchResultCount_) + return; + + if (++this.currentSearchResultIndex_ >= this.searchResultCount_) + this.currentSearchResultIndex_ = 0; + + this.focusedDOMNode = devtools.tools.getDomAgent(). + getSearchResultNode(this.currentSearchResultIndex_); +}; + + +/** + * @override + */ +WebInspector.ElementsPanel.prototype.jumpToPreviousSearchResult = function() { + if (!this.searchResultCount_) + return; + + if (--this.currentSearchResultIndex_ < 0) + this.currentSearchResultIndex_ = this.searchResultCount_ - 1; + + this.focusedDOMNode = devtools.tools.getDomAgent(). + getSearchResultNode(this.currentSearchResultIndex_); +}; + + +/** + * @override + */ +WebInspector.Console.prototype._evalInInspectedWindow = function(expr) { + return devtools.tools.evaluate(expr); +}; + + +/** + * @override + */ +WebInspector.ElementsPanel.prototype.updateStyles = function(forceUpdate) { + var stylesSidebarPane = this.sidebarPanes.styles; + if (!stylesSidebarPane.expanded || !stylesSidebarPane.needsUpdate) { + return; + } + this.invokeWithStyleSet_(function(node) { + stylesSidebarPane.needsUpdate = !!node; + stylesSidebarPane.update(node, null, forceUpdate); + }); +}; + + +/** + * @override + */ +WebInspector.ElementsPanel.prototype.updateMetrics = function() { + var metricsSidebarPane = this.sidebarPanes.metrics; + if (!metricsSidebarPane.expanded || !metricsSidebarPane.needsUpdate) { + return; + } + this.invokeWithStyleSet_(function(node) { + metricsSidebarPane.needsUpdate = !!node; + metricsSidebarPane.update(node); + }); +}; + + +/** + * Temporarily sets style fetched from the inspectable tab to the currently + * focused node, invokes updateUI callback and clears the styles. + * @param {function(Node):undefined} updateUI Callback to call while styles are + * set. + */ +WebInspector.ElementsPanel.prototype.invokeWithStyleSet_ = + function(updateUI) { + var node = this.focusedDOMNode; + if (node && node.nodeType === Node.TEXT_NODE && node.parentNode) + node = node.parentNode; + + if (node && node.nodeType == Node.ELEMENT_NODE) { + var callback = function(stylesStr) { + var styles = goog.json.parse(stylesStr); + if (!styles.computedStyle) { + return; + } + node.setStyles(styles.computedStyle, styles.inlineStyle, + styles.styleAttributes, styles.matchedCSSRules); + updateUI(node); + node.clearStyles(); + }; + devtools.tools.getDomAgent().getNodeStylesAsync( + node, + !Preferences.showUserAgentStyles, + callback); + } else { + updateUI(null); + } +}; + + +/** + * @override + */ +WebInspector.MetricsSidebarPane.prototype.editingCommitted = + function(element, userInput, previousContent, context) { + if (userInput === previousContent) { + // nothing changed, so cancel + return this.editingCancelled(element, context); + } + + if (context.box !== "position" && (!userInput || userInput === "\u2012")) { + userInput = "0px"; + } else if (context.box === "position" && + (!userInput || userInput === "\u2012")) { + userInput = "auto"; + } + + // Append a "px" unit if the user input was just a number. + if (/^\d+$/.test(userInput)) { + userInput += "px"; + } + devtools.tools.getDomAgent().setStylePropertyAsync( + this.node, + context.styleProperty, + userInput, + WebInspector.updateStylesAndMetrics_); +}; + + +/** + * @override + */ +WebInspector.PropertiesSidebarPane.prototype.update = function(object) { + var body = this.bodyElement; + body.removeChildren(); + + this.sections = []; + + if (!object) { + return; + } + + + var self = this; + devtools.tools.getDomAgent().getNodePrototypesAsync(object.id_, + function(json) { + // Get array of prototype user-friendly names. + var prototypes = goog.json.parse(json); + for (var i = 0; i < prototypes.length; ++i) { + var prototype = {}; + prototype.id_ = object.id_; + prototype.protoDepth_ = i; + var section = new WebInspector.SidebarObjectPropertiesSection( + prototype, + prototypes[i]); + self.sections.push(section); + body.appendChild(section.element); + } + }); +}; + + +/** + * Our implementation of ObjectPropertiesSection for Elements tab. + * @constructor + */ +WebInspector.SidebarObjectPropertiesSection = function(object, title) { + WebInspector.ObjectPropertiesSection.call(this, object, title, + null /* subtitle */, null /* emptyPlaceholder */, + null /* ignoreHasOwnProperty */, null /* extraProperties */, + WebInspector.SidebarObjectPropertyTreeElement /* treeElementConstructor */ + ); +}; +goog.inherits(WebInspector.SidebarObjectPropertiesSection, + WebInspector.ObjectPropertiesSection); + + +/** + * @override + */ +WebInspector.SidebarObjectPropertiesSection.prototype.onpopulate = function() { + var nodeId = this.object.id_; + var protoDepth = this.object.protoDepth_; + var path = []; + devtools.tools.getDomAgent().getNodePropertiesAsync(nodeId, path, protoDepth, + goog.partial(WebInspector.didGetNodePropertiesAsync_, + this.propertiesTreeOutline, + this.treeElementConstructor, + nodeId, + path)); +}; + + +/** + * Our implementation of ObjectPropertyTreeElement for Elements tab. + * @constructor + */ +WebInspector.SidebarObjectPropertyTreeElement = function(parentObject, + propertyName) { + WebInspector.ObjectPropertyTreeElement.call(this, parentObject, + propertyName); +}; +goog.inherits(WebInspector.SidebarObjectPropertyTreeElement, + WebInspector.ObjectPropertyTreeElement); + + +/** + * @override + */ +WebInspector.SidebarObjectPropertyTreeElement.prototype.onpopulate = + function() { + var nodeId = this.parentObject.devtools$$nodeId_; + var path = this.parentObject.devtools$$path_.slice(0); + path.push(this.propertyName); + devtools.tools.getDomAgent().getNodePropertiesAsync(nodeId, path, -1, + goog.partial( + WebInspector.didGetNodePropertiesAsync_, + this, + this.treeOutline.section.treeElementConstructor, + nodeId, path)); +}; + + +/** + * This override is necessary for starting highlighting after the resource + * was added into the frame. + * @override + */ +WebInspector.SourceView.prototype.setupSourceFrameIfNeeded = function() { + if (!this._frameNeedsSetup) { + return; + } + + this.attach(); + + var self = this; + var identifier = this.resource.identifier; + var element = this.sourceFrame.element; + var netAgent = devtools.tools.getNetAgent(); + + netAgent.getResourceContentAsync(identifier, function(source) { + var resource = netAgent.getResource(identifier); + if (InspectorController.addSourceToFrame(resource.mimeType, source, + element)) { + delete self._frameNeedsSetup; + if (resource.type === WebInspector.Resource.Type.Script) { + self.sourceFrame.addEventListener('syntax highlighting complete', + self._syntaxHighlightingComplete, self); + self.sourceFrame.syntaxHighlightJavascript(); + } else { + self._sourceFrameSetupFinished(); + } + } + }); + return true; +}; + + +/** + * Dummy object used during properties inspection. + * @see WebInspector.didGetNodePropertiesAsync_ + */ +WebInspector.dummyObject_ = { 'foo' : 'bar' }; + + +/** + * Dummy function used during properties inspection. + * @see WebInspector.didGetNodePropertiesAsync_ + */ +WebInspector.dummyFunction_ = function() {}; + + +/** + * Callback function used with the getNodeProperties. + */ +WebInspector.didGetNodePropertiesAsync_ = function(treeOutline, constructor, + nodeId, path, json) { + var props = goog.json.parse(json); + var properties = []; + var obj = {}; + obj.devtools$$nodeId_ = nodeId; + obj.devtools$$path_ = path; + for (var i = 0; i < props.length; i += 3) { + var type = props[i]; + var name = props[i + 1]; + var value = props[i + 2]; + properties.push(name); + if (type == 'object') { + // fake object is going to be replaced on expand. + obj[name] = WebInspector.dummyObject_; + } else if (type == 'function') { + // fake function is going to be replaced on expand. + obj[name] = WebInspector.dummyFunction_; + } else { + obj[name] = value; + } + } + properties.sort(); + + treeOutline.removeChildren(); + + for (var i = 0; i < properties.length; ++i) { + var propertyName = properties[i]; + treeOutline.appendChild(new constructor(obj, propertyName)); + } +}; + + +/** + * Replace WebKit method with our own implementation to use our call stack + * representation. Original method uses Object.prototype.toString.call to + * learn if scope object is a JSActivation which doesn't work in Chrome. + */ +WebInspector.ScopeChainSidebarPane.prototype.update = function(callFrame) { + this.bodyElement.removeChildren(); + + this.sections = []; + this.callFrame = callFrame; + + if (!callFrame) { + var infoElement = document.createElement('div'); + infoElement.className = 'info'; + infoElement.textContent = WebInspector.UIString('Not Paused'); + this.bodyElement.appendChild(infoElement); + return; + } + + if (!callFrame._expandedProperties) { + callFrame._expandedProperties = {}; + } + + var scopeObject = callFrame.localScope; + var title = WebInspector.UIString('Local'); + var subtitle = Object.describe(scopeObject, true); + var emptyPlaceholder = null; + var extraProperties = null; + + var section = new WebInspector.ObjectPropertiesSection(scopeObject, title, + subtitle, emptyPlaceholder, true, extraProperties, + WebInspector.ScopeChainSidebarPane.TreeElement); + section.editInSelectedCallFrameWhenPaused = true; + section.pane = this; + + section.expanded = true; + + this.sections.push(section); + this.bodyElement.appendChild(section.element); +}; + + +/** + * Custom implementation of TreeElement that asynchronously resolves children + * using the debugger agent. + * @constructor + */ +WebInspector.ScopeChainSidebarPane.TreeElement = function(parentObject, + propertyName) { + WebInspector.ScopeVariableTreeElement.call(this, parentObject, propertyName); +} +WebInspector.ScopeChainSidebarPane.TreeElement.inherits( + WebInspector.ScopeVariableTreeElement); + + +/** + * @override + */ +WebInspector.ScopeChainSidebarPane.TreeElement.prototype.onpopulate = + function() { + var obj = this.parentObject[this.propertyName].value; + devtools.tools.getDebuggerAgent().resolveChildren(obj, + goog.bind(this.didResolveChildren_, this)); +}; + + +/** + * Callback function used with the resolveChildren. + */ +WebInspector.ScopeChainSidebarPane.TreeElement.prototype.didResolveChildren_ = + function(object) { + this.removeChildren(); + + var constructor = this.treeOutline.section.treeElementConstructor; + for (var name in object) { + this.appendChild(new constructor(object, name)); + } +}; + + +/**
+ * @override + */ +WebInspector.StylePropertyTreeElement.prototype.toggleEnabled = + function(event) { + var enabled = event.target.checked; + devtools.tools.getDomAgent().toggleNodeStyleAsync( + this.style, + enabled, + this.name, + WebInspector.updateStylesAndMetrics_); +}; + + +/** + * @override + */ +WebInspector.StylePropertyTreeElement.prototype.applyStyleText = function( + styleText, updateInterface) { + devtools.tools.getDomAgent().applyStyleTextAsync(this.style, this.name, + styleText, + function() { + if (updateInterface) { + WebInspector.updateStylesAndMetrics_(); + } + }); +}; + + +/** + * Forces update of styles and metrics sidebar panes. + */ +WebInspector.updateStylesAndMetrics_ = function() { + WebInspector.panels.elements.sidebarPanes.metrics.needsUpdate = true; + WebInspector.panels.elements.updateMetrics(); + WebInspector.panels.elements.sidebarPanes.styles.needsUpdate = true; + WebInspector.panels.elements.updateStyles(true); +}; + + +/** + * This function overrides standard searchableViews getters to perform search + * only in the current view (other views are loaded asynchronously, no way to + * search them yet). + */ +WebInspector.searchableViews_ = function() { + var views = []; + const visibleView = this.visibleView; + if (visibleView && visibleView.performSearch) { + views.push(visibleView); + } + return views; +}; + + +/** + * @override + */ +WebInspector.ResourcesPanel.prototype.__defineGetter__( + 'searchableViews', + WebInspector.searchableViews_); + + +/** + * @override + */ +WebInspector.ScriptsPanel.prototype.__defineGetter__( + 'searchableViews', + WebInspector.searchableViews_); + + +/** + * @override + */ +WebInspector.Console.prototype._evalInInspectedWindow = function(expression) { + if (WebInspector.panels.scripts.paused) + return WebInspector.panels.scripts.evaluateInSelectedCallFrame(expression); + + var console = this; + devtools.tools.evaluateJavaScript(expression, function(response) { + // TODO(yurys): send exception information along with the response + var exception = false; + console.addMessage(new WebInspector.ConsoleCommandResult( + response, exception, null /* commandMessage */)); + }); + // TODO(yurys): refactor WebInspector.Console so that the result is added into + // the command log message. + return 'evaluating...'; +}; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/devtools_callback.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/devtools_callback.js new file mode 100644 index 0000000..f252861 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/devtools_callback.js @@ -0,0 +1,57 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview Generic callback manager. + */ +goog.provide('devtools.Callback'); + + +/** + * Generic callback support as a singleton object. + * @constructor + */ +devtools.Callback = function() { + this.lastCallbackId_ = 1; + this.callbacks_ = {}; +}; + + +/** + * Assigns id to a callback. + * @param {Function} callback Callback to assign id to. + * @return {number} Callback id. + */ +devtools.Callback.prototype.wrap = function(callback) { + var callbackId = this.lastCallbackId_++; + this.callbacks_[callbackId] = callback || function() {}; + return callbackId; +}; + + +/** + * Executes callback with the given id. + * @param {callbackId} callbackId Id of a callback to call. + */ +devtools.Callback.prototype.processCallback = function(callbackId, + opt_vararg) { + var args = Array.prototype.slice.call(arguments, 1); + var callback = this.callbacks_[callbackId]; + callback.apply(null, args); + delete this.callbacks_[callbackId]; +}; + + +/** + * @type {devtools.Callback} Callback support singleton. + * @private + */ +devtools.Callback.INSTANCE_ = new devtools.Callback(); + +devtools.Callback.wrap = goog.bind( + devtools.Callback.INSTANCE_.wrap, + devtools.Callback.INSTANCE_); +devtools.Callback.processCallback = goog.bind( + devtools.Callback.INSTANCE_.processCallback, + devtools.Callback.INSTANCE_); diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/devtools_host_stub.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/devtools_host_stub.js new file mode 100644 index 0000000..d91ed1b --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/devtools_host_stub.js @@ -0,0 +1,255 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview These stubs emulate backend functionality and allows + * DevTools frontend to function as a standalone web app. + */ + +/** + * @constructor + */ +RemoteDebuggerAgentStub = function() { +}; + +RemoteDebuggerAgentStub.prototype.DebugAttach = function() { +}; + +RemoteDebuggerAgentStub.prototype.DebugDetach = function() { +}; + +RemoteDebuggerAgentStub.prototype.DebugCommand = function() { +}; + +RemoteDebuggerAgentStub.prototype.DebugBreak = function() { +}; + + +/** + * @constructor + */ +RemoteDomAgentStub = function() { +}; + + +RemoteDomAgentStub.sendDocumentElement_ = function() { + RemoteDomAgent.SetDocumentElement([ + 1, // id + 1, // type = Node.ELEMENT_NODE, + 'HTML', // nodeName + '', // nodeValue + ['foo','bar'], // attributes + 2, // childNodeCount + ]); +}; + + +RemoteDomAgentStub.sendChildNodes_ = function(id) { + if (id == 1) { + RemoteDomAgent.SetChildNodes(id, + [ + [ + 2, // id + 1, // type = Node.ELEMENT_NODE, + 'DIV', // nodeName + '', // nodeValue + ['foo','bar'], // attributes + 1, // childNodeCount + ], + [ + 3, // id + 3, // type = Node.TEXT_NODE, + '', // nodeName + 'Text', // nodeValue + ] + ]); + } else if (id == 2) { + RemoteDomAgent.SetChildNodes(id, + [ + [ + 4, // id + 1, // type = Node.ELEMENT_NODE, + 'span', // nodeName + '', // nodeValue + ['foo','bar'], // attributes + 0, // childNodeCount + ] + ]); + } +}; + + +RemoteDomAgentStub.prototype.GetDocumentElement = function(callId) { + setTimeout(function() { + RemoteDomAgentStub.sendDocumentElement_(); + }, 0); +}; + + +RemoteDomAgentStub.prototype.GetChildNodes = function(callId, id) { + setTimeout(function() { + RemoteDomAgentStub.sendChildNodes_(id); + RemoteDomAgent.DidGetChildNodes(callId); + }, 0); +}; + + +RemoteDomAgentStub.prototype.SetAttribute = function(callId) { + setTimeout(function() { + RemoteDomAgent.DidApplyDomChange(callId, true); + }, 0); +}; + + +RemoteDomAgentStub.prototype.RemoveAttribute = function(callId) { + setTimeout(function() { + RemoteDomAgent.DidApplyDomChange(callId, true); + }, 0); +}; + + +RemoteDomAgentStub.prototype.SetTextNodeValue = function(callId) { + setTimeout(function() { + RemoteDomAgent.DidApplyDomChange(callId, true); + }, 0); +}; + + +RemoteDomAgentStub.prototype.PerformSearch = function(callId, query) { + setTimeout(function() { + RemoteDomAgent.DidPerformSearch(callId, [1]); + }, 0); +}; + + +RemoteDomAgentStub.prototype.DiscardBindings = function() { +}; + + +/** + * @constructor + */ +RemoteToolsAgentStub = function() { +}; + + +RemoteToolsAgentStub.prototype.HideDOMNodeHighlight = function() { +}; + + +RemoteToolsAgentStub.prototype.HighlightDOMNode = function() { +}; + + +RemoteToolsAgentStub.prototype.evaluate = function(expr) { + window.eval(expr); +}; + +RemoteToolsAgentStub.prototype.EvaluateJavaScript = function(callId, script) { + setTimeout(function() { + var result = eval(script); + RemoteToolsAgent.DidEvaluateJavaScript(callId, result); + }, 0); +}; + + +RemoteToolsAgentStub.prototype.ExecuteUtilityFunction = function(callId, + functionName, nodeId, args) { + setTimeout(function() { + var result = []; + if (functionName == 'getProperties') { + result = [ + 'undefined', 'undefined_key', undefined, + 'string', 'string_key', 'value', + 'function', 'func', undefined, + 'array', 'array_key', [10], + 'object', 'object_key', undefined, + 'boolean', 'boolean_key', true, + 'number', 'num_key', 911, + 'date', 'date_key', new Date() ]; + } else if (functionName == 'getPrototypes') { + result = ['Proto1', 'Proto2', 'Proto3']; + } else if (functionName == 'getStyles') { + result = { + 'computedStyle' : [0, '0px', '0px', null, null, null, ['display', false, false, '', 'none']], + 'inlineStyle' : [1, '0px', '0px', null, null, null, ['display', false, false, '', 'none']], + 'styleAttributes' : { + attr: [2, '0px', '0px', null, null, null, ['display', false, false, '', 'none']] + }, + 'matchedCSSRules' : [ + { 'selector' : 'S', + 'style' : [3, '0px', '0px', null, null, null, ['display', false, false, '', 'none']], + 'parentStyleSheet' : { 'href' : 'http://localhost', + 'ownerNodeName' : 'DIV' } + } + ] + }; + } else if (functionName == 'toggleNodeStyle' || + functionName == 'applyStyleText' || + functionName == 'setStyleProperty') { + alert(functionName + '(' + nodeId + ', ' + args + ')'); + } else { + alert('Unexpected utility function:' + functionName); + } + RemoteToolsAgent.DidExecuteUtilityFunction(callId, + goog.json.serialize(result), ''); + }, 0); +}; + + +RemoteToolsAgentStub.prototype.GetNodePrototypes = function(callId, nodeId) { + setTimeout(function() { + RemoteToolsAgent.DidGetNodePrototypes(callId, + goog.json.serialize()); + }, 0); +}; + + +RemoteToolsAgentStub.prototype.ClearConsoleMessages = function() { +}; + + +/** + * @constructor + */ +RemoteDebuggerCommandExecutorStub = function() { +}; + + +RemoteDebuggerCommandExecutorStub.prototype.DebuggerCommand = function() { +}; + + +/** + * @constructor + */ +RemoteNetAgentStub = function() { +}; + + +/** + * @constructor + */ +DevToolsHostStub = function() { +}; + + +DevToolsHostStub.prototype.loaded = function() { + RemoteDomAgentStub.sendDocumentElement_(); + RemoteDomAgentStub.sendChildNodes_(1); + RemoteDomAgentStub.sendChildNodes_(2); + devtools.tools.updateFocusedNode(4); + devtools.tools.addMessageToConsole('message', 'source', 3); +}; + + +if (!window['DevToolsHost']) { + window['RemoteDebuggerAgent'] = new RemoteDebuggerAgentStub(); + window['RemoteDebuggerCommandExecutor'] = + new RemoteDebuggerCommandExecutorStub(); + window['RemoteDomAgent'] = new RemoteDomAgentStub(); + window['RemoteNetAgent'] = new RemoteNetAgentStub(); + window['RemoteToolsAgent'] = new RemoteToolsAgentStub(); + window['DevToolsHost'] = new DevToolsHostStub(); +} diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/dom_agent.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/dom_agent.js new file mode 100644 index 0000000..09ea809 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/dom_agent.js @@ -0,0 +1,1023 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview Dom and DomNode are used to represent remote DOM in the + * web inspector. + */ +goog.provide('devtools.DomAgent'); +goog.provide('devtools.DomDocument'); +goog.provide('devtools.DomNode'); + +goog.require('devtools.Callback'); + + +/** + * Defines indexes for the node payload properties. + */ +devtools.PayloadIndex = { + ID : 0, + TYPE : 1, + NAME : 2, + VALUE : 3, + ATTRS : 4, + HAS_CHILDREN : 5, + CHILD_NODES : 6 +}; + + +/** + * Creates document node in a given document based on a given payload data. + * @param {devtools.Doc} doc Document to create node in. + * @param {Array.<Object>} payload Data to build node based upon. + * @constructor + */ +devtools.DomNode = function(doc, payload) { + this.ownerDocument = doc; + + this.id_ = payload[devtools.PayloadIndex.ID]; + this.nodeType = payload[devtools.PayloadIndex.TYPE]; + this.nodeName = payload[devtools.PayloadIndex.NAME]; + this.nodeValue_ = payload[devtools.PayloadIndex.VALUE]; + this.textContent = this.nodeValue; + + this.attributes = []; + this.attributesMap_ = {}; + if (payload.length > devtools.PayloadIndex.ATTRS) { + this.setAttributesPayload_(payload[devtools.PayloadIndex.ATTRS]); + } + + this.childNodesCount_ = payload[devtools.PayloadIndex.HAS_CHILDREN]; + this.children = null; + + this.nextSibling = null; + this.prevSibling = null; + this.firstChild = null; + this.parentNode = null; + + this.disabledStyleProperties_ = {}; + + if (payload.length > devtools.PayloadIndex.CHILD_NODES) { + // Has children payloads + this.setChildrenPayload_( + payload[devtools.PayloadIndex.CHILD_NODES]); + } + + this.computedStyle_ = null; + this.style = null; + this.matchedCSSRules_ = []; +}; + + +/** + * Overrides for getters and setters. + */ +devtools.DomNode.prototype = { + get nodeValue() { + return this.nodeValue_; + }, + + set nodeValue(value) { + if (this.nodeType != Node.TEXT_NODE) { + return; + } + var self = this; + this.ownerDocument.domAgent_.setTextNodeValueAsync(this, value, + function() { + self.nodeValue_ = value; + self.textContent = value; + }); + } +}; + + +/** + * Sets attributes for a given node based on a given attrs payload. + * @param {Array.<string>} attrs Attribute key-value pairs to set. + * @private + */ +devtools.DomNode.prototype.setAttributesPayload_ = function(attrs) { + for (var i = 0; i < attrs.length; i += 2) { + this.addAttribute_(attrs[i], attrs[i + 1]); + } +}; + + +/** + * @return True iff node has attributes. + */ +devtools.DomNode.prototype.hasAttributes = function() { + return this.attributes.length > 0; +}; + + +/** + * @return True iff node has child nodes. + */ +devtools.DomNode.prototype.hasChildNodes = function() { + return this.childNodesCount_ > 0; +}; + + +/** + * Inserts child node into this node after a given anchor. + * @param {devtools.DomNode} prev Node to insert child after. + * @param {Array.<Object>} payload Child node data. + * @private + */ +devtools.DomNode.prototype.insertChild_ = function(prev, payload) { + var node = new devtools.DomNode(this.ownerDocument, payload); + if (!prev) { + // First node + this.children = [ node ]; + } else { + this.children.splice(this.children.indexOf(prev) + 1, 0, node); + } + this.renumber_(); + return node; +}; + + +/** + * Removes child node from this node. + * @param {devtools.DomNode} node Node to remove. + * @private + */ +devtools.DomNode.prototype.removeChild_ = function(node) { + this.children.splice(this.children.indexOf(node), 1); + node.parentNode = null; + this.renumber_(); +}; + + +/** + * Sets children for this node based on the given payload. + * @param {Array.<Object>} payload Data for children. + * @private + */ +devtools.DomNode.prototype.setChildrenPayload_ = function(payloads) { + this.children = []; + for (var i = 0; i < payloads.length; ++i) { + var payload = payloads[i]; + var node = new devtools.DomNode(this.ownerDocument, payload); + this.children.push(node); + } + this.renumber_(); +}; + + +/** + * Normalizes prev/next/parent/firstChild links for this node's children. + * @private + */ +devtools.DomNode.prototype.renumber_ = function() { + this.childNodesCount_ = this.children.length; + if (this.childNodesCount_ == 0) { + this.firstChild = null; + return; + } + this.firstChild = this.children[0]; + for (var i = 0; i < this.childNodesCount_; ++i) { + var child = this.children[i]; + child.nextSibling = i + 1 < this.childNodesCount_ ? + this.children[i + 1] : null; + child.prevSibling = i - 1 >= 0 ? this.children[i - 1] : null; + child.parentNode = this; + } +}; + + +/** + * Returns attribute value. + * @param {string} name Attribute name to get value for. + * @return {string} Attribute value. + */ +devtools.DomNode.prototype.getAttribute = function(name) { + var attr = this.attributesMap_[name]; + return attr ? attr.value : undefined; +}; + + +/** + * Sends 'set attribute' command to the remote agent. + * @param {string} name Attribute name to set value for. + * @param {string} value Attribute value to set. + */ +devtools.DomNode.prototype.setAttribute = function(name, value) { + var self = this; + this.ownerDocument.domAgent_.setAttributeAsync(this, name, value, + function() { + var attr = self.attributesMap_[name]; + if (attr) { + attr.value = value; + } else { + attr = self.addAttribute_(name, value); + } + }); +}; + + +/** + * Creates an attribute-like object and adds it to the object. + * @param {string} name Attribute name to set value for. + * @param {string} value Attribute value to set. + */ +devtools.DomNode.prototype.addAttribute_ = function(name, value) { + var attr = { + 'name': name, + 'value': value, + node_: this + }; + + this.attributesMap_[name] = attr; + this.attributes.push(attr); +}; + + +/** + * Sends 'remove attribute' command to the remote agent. + * @param {string} name Attribute name to set value for. + */ +devtools.DomNode.prototype.removeAttribute = function(name) { + var self = this; + this.ownerDocument.domAgent_.removeAttributeAsync(this, name, function() { + delete self.attributesMap_[name]; + for (var i = 0; i < self.attributes.length; ++i) { + if (self.attributes[i].name == name) { + self.attributes.splice(i, 1); + break; + } + } + }); +}; + + +/** + * Makes available the following methods and properties: + * - node.style property + * - node.document.defaultView.getComputedStyles(node) + * - node.document.defaultView.getMatchedCSSRules(node, ...) + * - style attribute of node's attributes + * @param {string} computedStyle is a cssText of result of getComputedStyle(). + * @param {string} inlineStyle is a style.cssText (defined in the STYLE + * attribute). + * @param {Object} styleAttributes represents 'style' property + * of attributes. + * @param {Array.<object>} matchedCSSRules represents result of the + * getMatchedCSSRules(node, '', authorOnly). Each elemet consists of: + * selector, rule.style.cssText[, rule.parentStyleSheet.href + * [, rule.parentStyleSheet.ownerNode.nodeName]]. + */ +devtools.DomNode.prototype.setStyles = function(computedStyle, inlineStyle, + styleAttributes, matchedCSSRules) { + this.computedStyle_ = this.makeStyle_(computedStyle); + this.style = this.makeStyle_(inlineStyle); + + for (var name in styleAttributes) { + if (this.attributesMap_[name]) { + this.attributesMap_[name].style = + this.makeStyle_(styleAttributes[name]); + } + } + + this.matchedCSSRules_ = []; + for (var i = 0; i < matchedCSSRules.length; i++) { + var descr = matchedCSSRules[i]; + + var rule = {}; + rule.selectorText = descr['selector']; + rule.style = this.makeStyle_(descr['style']); + + if (descr['parentStyleSheet']) { + var parentStyleMock = {}; + parentStyleMock.href = descr['parentStyleSheet']['href']; + var nodeName = descr['parentStyleSheet']['ownerNodeName']; + if (nodeName) { + parentStyleMock.ownerNode = { + 'nodeName': nodeName + }; + } + rule.parentStyleSheet = parentStyleMock; + } + this.matchedCSSRules_.push(rule); + } +}; + + +/** + * Creates a style declaration. + * @param {payload} payload + * @return {devtools.CSSStyleDeclaration:undefined} + * @see devtools.CSSStyleDeclaration + */ +devtools.DomNode.prototype.makeStyle_ = function(payload) { + var style = new devtools.CSSStyleDeclaration(payload); + style.nodeId_ = this.id_; + return style; +}; + + +/** + * Remove references to the style information to release + * resources when styles are not going to be used. + * @see setStyles. + */ +devtools.DomNode.prototype.clearStyles = function() { + this.computedStyle = null; + this.style = null; + for (var name in this.attributesMap_) { + this.attributesMap_[name].style = null; + } + this.matchedCSSRules_ = null; +}; + + +/** + * Remote Dom document abstraction. + * @param {devtools.DomAgent} domAgent owner agent. + * @param {devtools.DomWindow} defaultView owner window. + * @constructor. + */ +devtools.DomDocument = function(domAgent, defaultView) { + devtools.DomNode.call(this, null, + [ + 0, // id + 9, // type = Node.DOCUMENT_NODE, + '', // nodeName + '', // nodeValue + [], // attributes + 0, // childNodeCount + ]); + this.listeners_ = {}; + this.domAgent_ = domAgent; + this.defaultView = defaultView; +}; +goog.inherits(devtools.DomDocument, devtools.DomNode); + + +/** + * Adds event listener to the Dom. + * @param {string} name Event name. + * @param {function(Event):undefined} callback Listener callback. + * @param {bool} useCapture Listener's useCapture settings. + */ +devtools.DomDocument.prototype.addEventListener = + function(name, callback, useCapture) { + var listeners = this.listeners_[name]; + if (!listeners) { + listeners = []; + this.listeners_[name] = listeners; + } + listeners.push(callback); +}; + + +/** + * Removes event listener from the Dom. + * @param {string} name Event name. + * @param {function(Event):undefined} callback Listener callback. + * @param {bool} useCapture Listener's useCapture settings. + */ +devtools.DomDocument.prototype.removeEventListener = + function(name, callback, useCapture) { + var listeners = this.listeners_[name]; + if (!listeners) { + return; + } + var index = listeners.indexOf(callback); + if (index != -1) { + listeners.splice(index, 1); + } +}; + + +/** + * Fires Dom event to the listeners for given event type. + * @param {string} name Event type. + * @param {Event} event Event to fire. + * @private + */ +devtools.DomDocument.prototype.fireDomEvent_ = function(name, event) { + var listeners = this.listeners_[name]; + if (!listeners) { + return; + } + for (var i = 0; i < listeners.length; ++i) { + listeners[i](event); + } +}; + + + +/** + * Simulation of inspected DOMWindow. + * @param {devtools.DomAgent} domAgent owner agent. + * @constructor + */ +devtools.DomWindow = function(domAgent) { + this.document = new devtools.DomDocument(domAgent, this); +}; + +/** + * Represents DOM Node class. + */ +devtools.DomWindow.prototype.__defineGetter__('Node', function() { + return devtools.DomNode; +}); + +/** + * Represents DOM Element class. + * @constructor + */ +devtools.DomWindow.prototype.__defineGetter__('Element', function() { + return devtools.DomNode; +}); + + +/** + * See usages in ScopeChainSidebarPane.js where it's called as + * constructor. + */ +devtools.DomWindow.prototype.Object = function() { +}; + + +/** + * Simulates the DOM interface for styles. + * @param {devtools.DomNode} node + * @return {CSSStyleDescription} + */ +devtools.DomWindow.prototype.getComputedStyle = function(node) { + return node.computedStyle_; +}; + + +/** + * Simulates the DOM interface for styles. + * @param {devtools.DomNode} nodeStyles + * @param {string} pseudoElement assumed to be empty string. + * @param {boolean} authorOnly assumed to be equal to authorOnly argument of + * getNodeStylesAsync. + * @return {CSSStyleDescription} + */ +devtools.DomWindow.prototype.getMatchedCSSRules = function(node, + pseudoElement, authorOnly) { + return node.matchedCSSRules_; +}; + + +/** + * Creates DomAgent Js representation. + * @constructor + */ +devtools.DomAgent = function() { + RemoteDomAgent.DidGetChildNodes = + devtools.Callback.processCallback; + RemoteDomAgent.DidPerformSearch = + devtools.Callback.processCallback; + RemoteDomAgent.DidApplyDomChange = + devtools.Callback.processCallback; + RemoteDomAgent.DidRemoveAttribute = + devtools.Callback.processCallback; + RemoteDomAgent.DidSetTextNodeValue = + devtools.Callback.processCallback; + RemoteDomAgent.AttributesUpdated = + goog.bind(this.attributesUpdated, this); + RemoteDomAgent.SetDocumentElement = + goog.bind(this.setDocumentElement, this); + RemoteDomAgent.SetChildNodes = + goog.bind(this.setChildNodes, this); + RemoteDomAgent.HasChildrenUpdated = + goog.bind(this.hasChildrenUpdated, this); + RemoteDomAgent.ChildNodeInserted = + goog.bind(this.childNodeInserted, this); + RemoteDomAgent.ChildNodeRemoved = + goog.bind(this.childNodeRemoved, this); + + /** + * Top-level (and the only) document. + * @type {devtools.DomWindow} + * @private + */ + this.window_ = null; + + /** + * Id to node mapping. + * @type {Object} + * @private + */ + this.idToDomNode_ = null; + + /** + * @type {Array.<number>} Node ids for search results. + * @private + */ + this.searchResults_ = null; +}; + + +/** + * Resets dom agent to its initial state. + */ +devtools.DomAgent.prototype.reset = function() { + this.window_ = new devtools.DomWindow(this); + this.idToDomNode_ = { 0 : this.getDocument() }; + this.searchResults_ = []; +}; + + +/** + * @return {devtools.DomWindow} Window for the top level (and the only) document. + */ +devtools.DomAgent.prototype.getWindow = function() { + return this.window_; +}; + + +/** + * @return {devtools.DomDocument} A document of the top level window. + */ +devtools.DomAgent.prototype.getDocument = function() { + return this.window_.document; +}; + + +/** + * Requests that the document element is sent from the agent. + */ +devtools.DomAgent.prototype.getDocumentElementAsync = function() { + if (this.getDocument().documentElement) { + return; + } + RemoteDomAgent.GetDocumentElement(); +}; + + +/** + * Asynchronously fetches children from the element with given id. + * @param {devtools.DomNode} parent Element to get children for. + * @param {function(devtools.DomNode):undefined} opt_callback Callback with + * the result. + */ +devtools.DomAgent.prototype.getChildNodesAsync = function(parent, + opt_callback) { + var children = parent.children; + if (children && opt_callback) { + opt_callback(children); + return; + } + var mycallback = function() { + if (opt_callback) { + opt_callback(parent.children); + } + }; + var callId = devtools.Callback.wrap(mycallback); + RemoteDomAgent.GetChildNodes(callId, parent.id_); +}; + + +/** + * Sends 'set attribute' command to the remote agent. + * @param {devtools.DomNode} node Node to change. + * @param {string} name Attribute name to set value for. + * @param {string} value Attribute value to set. + * @param {function():undefined} opt_callback Callback on success. + */ +devtools.DomAgent.prototype.setAttributeAsync = function(node, name, value, + callback) { + var mycallback = goog.bind(this.didApplyDomChange_, this, node, callback); + RemoteDomAgent.SetAttribute(devtools.Callback.wrap(mycallback), + node.id_, name, value); +}; + + +/** + * Sends 'remove attribute' command to the remote agent. + * @param {devtools.DomNode} node Node to change. + * @param {string} name Attribute name to set value for. + * @param {function():undefined} opt_callback Callback on success. + */ +devtools.DomAgent.prototype.removeAttributeAsync = function(node, name, + callback) { + var mycallback = goog.bind(this.didApplyDomChange_, this, node, callback); + RemoteDomAgent.RemoveAttribute(devtools.Callback.wrap(mycallback), + node.id_, name); +}; + + +/** + * Sends 'set text node value' command to the remote agent. + * @param {devtools.DomNode} node Node to change. + * @param {string} text Text value to set. + * @param {function():undefined} opt_callback Callback on success. + */ +devtools.DomAgent.prototype.setTextNodeValueAsync = function(node, text, + callback) { + var mycallback = goog.bind(this.didApplyDomChange_, this, node, callback); + RemoteDomAgent.SetTextNodeValue(devtools.Callback.wrap(mycallback), + node.id_, text); +}; + + +/** + * Universal callback wrapper for edit dom operations. + * @param {devtools.DomNode} node Node to apply local changes on. + * @param {Function} callback Post-operation call. + * @param {boolean} success True iff operation has completed successfully. + */ +devtools.DomAgent.prototype.didApplyDomChange_ = function(node, + callback, success) { + if (!success) { + return; + } + callback(); + var elem = WebInspector.panels.elements.treeOutline.findTreeElement(node); + if (elem) { + elem._updateTitle(); + } +}; + + +/** + * @see DomAgentDelegate. + * {@inheritDoc}. + */ +devtools.DomAgent.prototype.attributesUpdated = function(nodeId, attrsArray) { + var node = this.idToDomNode_[nodeId]; + node.setAttributesPayload_(attrsArray); +}; + + +/** + * Returns node for id. + * @param {number} nodeId Id to get node for. + * @return {devtools.DomNode} Node with given id. + */ +devtools.DomAgent.prototype.getNodeForId = function(nodeId) { + return this.idToDomNode_[nodeId]; +}; + + +/** + * @see DomAgentDelegate. + * {@inheritDoc}. + */ +devtools.DomAgent.prototype.setDocumentElement = function(payload) { + var doc = this.getDocument(); + if (doc.documentElement) { + this.reset(); + doc = this.getDocument(); + } + this.setChildNodes(0, [payload]); + doc.documentElement = doc.firstChild; + doc.documentElement.ownerDocument = doc; + WebInspector.panels.elements.reset(); +}; + + +/** + * @see DomAgentDelegate. + * {@inheritDoc}. + */ +devtools.DomAgent.prototype.setChildNodes = function(parentId, payloads) { + var parent = this.idToDomNode_[parentId]; + if (parent.children) { + return; + } + parent.setChildrenPayload_(payloads); + this.bindNodes_(parent.children); +}; + + +/** + * Binds nodes to ids recursively. + * @param {Array.<devtools.DomNode>} children Nodes to bind. + */ +devtools.DomAgent.prototype.bindNodes_ = function(children) { + for (var i = 0; i < children.length; ++i) { + var child = children[i]; + this.idToDomNode_[child.id_] = child; + if (child.children) { + this.bindNodes_(child.children); + } + } +}; + + +/** + * @see DomAgentDelegate. + * {@inheritDoc}. + */ +devtools.DomAgent.prototype.hasChildrenUpdated = function(nodeId, newValue) { + var node = this.idToDomNode_[nodeId]; + var outline = WebInspector.panels.elements.treeOutline; + var treeElement = outline.findTreeElement(node); + if (treeElement) { + treeElement.hasChildren = newValue; + treeElement.whitespaceIgnored = Preferences.ignoreWhitespace; + } +}; + + +/** + * @see DomAgentDelegate. + * {@inheritDoc}. + */ +devtools.DomAgent.prototype.childNodeInserted = function( + parentId, prevId, payload) { + var parent = this.idToDomNode_[parentId]; + var prev = this.idToDomNode_[prevId]; + var node = parent.insertChild_(prev, payload); + this.idToDomNode_[node.id_] = node; + var event = { target : node, relatedNode : parent }; + this.getDocument().fireDomEvent_('DOMNodeInserted', event); +}; + + +/** + * @see DomAgentDelegate. + * {@inheritDoc}. + */ +devtools.DomAgent.prototype.childNodeRemoved = function( + parentId, nodeId) { + var parent = this.idToDomNode_[parentId]; + var node = this.idToDomNode_[nodeId]; + parent.removeChild_(node); + var event = { target : node, relatedNode : parent }; + this.getDocument().fireDomEvent_('DOMNodeRemoved', event); + delete this.idToDomNode_[nodeId]; +}; + + +/** + * @see DomAgentDelegate. + * {@inheritDoc}. + */ +devtools.DomAgent.prototype.performSearch = function(query, callback) { + this.searchResults_ = []; + RemoteDomAgent.PerformSearch( + devtools.Callback.wrap( + goog.bind(this.performSearchCallback_, this, callback, + this.searchResults_)), + query); +}; + + +/** + * Invokes callback for nodes that needs to clear highlighting. + * @param {function(Array.<devtools.DomNode>)} callback to accept the result. + */ +devtools.DomAgent.prototype.searchCanceled = function(callback) { + if (!this.searchResults_) + return; + + var nodes = []; + for (var i = 0; i < this.searchResults_.length; ++i) { + var nodeId = this.searchResults_[i]; + var node = this.idToDomNode_[nodeId]; + nodes.push(node); + } + + callback(nodes); + this.searchResults_ = null; +}; + + +/** + * Invokes callback for each node that needs to gain highlighting. + * @param {function(Array.<devtools.DomNode>)} callback to accept the result. + * @param {Array.<number>} searchResults to be populated. + * @param {Array.<number>} nodeIds Ids to highlight. + */ +devtools.DomAgent.prototype.performSearchCallback_ = function(callback, + searchResults, nodeIds) { + + if (this.searchResults_ !== searchResults) + return; // another search has requested and this results are obsolete + + var nodes = []; + + for (var i = 0; i < nodeIds.length; ++i) { + var node = this.idToDomNode_[nodeIds[i]]; + searchResults.push(nodeIds[i]); + nodes.push(node); + } + + callback(nodes); +}; + + +/** + * Returns a node by index from the actual search results + * (last performSearch). + * @param {number} index in the results. + * @return {devtools.DomNode} + */ +devtools.DomAgent.prototype.getSearchResultNode = function(index) { + return this.idToDomNode_[this.searchResults_[index]]; +}; + + +/** + * Returns all properties of the given node. + * @param {number} nodeId Node to get properties for. + * @param {Array.<string>} path Path to the object. + * @param {number} protoDepth Depth to the exact proto level. + * @param {function(string):undefined} callback Function to call with the + * result. + */ +devtools.DomAgent.prototype.getNodePropertiesAsync = function(nodeId, + path, protoDepth, callback) { + var callbackId = this.utilityFunctionCallbackWrapper_(callback); + RemoteToolsAgent.ExecuteUtilityFunction(callbackId, + 'getProperties', nodeId, + goog.json.serialize([path, protoDepth])); +}; + + +/** + * Returns prototype chain for a given node. + * @param {number} nodeId Node to get prototypes for. + * @param {Function} callback. + */ +devtools.DomAgent.prototype.getNodePrototypesAsync = function(nodeId, + callback) { + var callbackId = this.utilityFunctionCallbackWrapper_(callback); + RemoteToolsAgent.ExecuteUtilityFunction(callbackId, + 'getPrototypes', nodeId, '[]'); +}; + + +/** + * Returns styles for given node. + * @param {devtools.DomNode} node Node to get prototypes for. + * @param {boolean} authorOnly Returns only author styles if true. + * @param {Function} callback. + */ +devtools.DomAgent.prototype.getNodeStylesAsync = function(node, + authorOnly, callback) { + var callbackId = this.utilityFunctionCallbackWrapper_(callback); + RemoteToolsAgent.ExecuteUtilityFunction(callbackId, + 'getStyles', + node.id_, + goog.json.serialize([authorOnly])); +}; + + +/** + * Toggles style with given id on/off. + * @param {devtools.CSSStyleDeclaration} style Style to toggle. + * @param {boolean} enabled True if style should be enabled. + * @param {string} name Style name. + * @param {Function} callback. + */ +devtools.DomAgent.prototype.toggleNodeStyleAsync = function( + style, enabled, name, callback) { + var callbackId = this.utilityFunctionCallbackWrapper_(callback); + RemoteToolsAgent.ExecuteUtilityFunction(callbackId, + 'toggleNodeStyle', + style.nodeId_, + goog.json.serialize([style.id_, enabled, name])); +}; + + +/** + * Applies new text to a style. + * @param {devtools.CSSStyleDeclaration} style Style to edit. + * @param {string} name Property name to edit. + * @param {string} styleText Text to set the style from. + * @param {Function} callback. + */ +devtools.DomAgent.prototype.applyStyleTextAsync = function( + style, name, styleText, callback) { + var callbackId = this.utilityFunctionCallbackWrapper_(callback); + RemoteToolsAgent.ExecuteUtilityFunction( + callbackId, + 'applyStyleText', + style.nodeId_, + goog.json.serialize([style.id_, name, styleText])); +}; + + +/** + * Sets style property with given name to a value. + * @param {devtools.DomNode} node Node to edit style for. + * @param {string} name Property name to edit. + * @param {string} value New value. + * @param {Function} callback. + */ +devtools.DomAgent.prototype.setStylePropertyAsync = function( + node, name, value, callback) { + var callbackId = this.utilityFunctionCallbackWrapper_(callback); + RemoteToolsAgent.ExecuteUtilityFunction( + callbackId, + 'setStyleProperty', + node.id_, + goog.json.serialize([name, value])); +}; + + +/** + * Dumps exception if something went wrong in ExecuteUtilityFunction. + * @param {Function} callback Callback to wrap. + * @return {number} Callback id. + */ +devtools.DomAgent.prototype.utilityFunctionCallbackWrapper_ = + function(callback) { + var mycallback = function(result, exception) { + if (exception && exception.length) { + debugPrint('Exception in ExecuteUtilityFunction styles:' + exception); + return; + } + callback(result); + }; + return devtools.Callback.wrap(mycallback); +}; + + +/** + * Represents remote CSSStyleDeclaration for using in StyleSidebarPane. + * @param {id, Array<Object>} payload built by inject's getStyle from the + * injected js. + * @constructor + */ +devtools.CSSStyleDeclaration = function(payload) { + this.id_ = payload[0]; + this.width = payload[1]; + this.height = payload[2]; + this.__disabledProperties = payload[3]; + this.__disabledPropertyValues = payload[4]; + this.__disabledPropertyPriorities = payload[5]; + + this.length = payload.length - 6; + this.priority_ = {}; + this.implicit_ = {}; + this.shorthand_ = {}; + this.value_ = {}; + + for (var i = 6; i < payload.length; ++i) { + var p = payload[i]; + var name = p[0]; + + this.priority_[name] = p[1]; + this.implicit_[name] = p[2]; + this.shorthand_[name] = p[3]; + this.value_[name] = p[4]; + + this[i - 6] = name; + } +}; + + +/** + * @param {string} name of a CSS property. + * @return {string} + */ +devtools.CSSStyleDeclaration.prototype.getPropertyValue = function(name) { + return this.value_[name] || ''; +}; + + +/** + * @param {string} name of a CSS property. + * @return {string} 'important' | ''. + */ +devtools.CSSStyleDeclaration.prototype.getPropertyPriority = function(name) { + return this.priority_[name] || ''; +}; + + +/** + * @param {string} name of a CSS property. + * @return {string} shorthand name or '' + */ +devtools.CSSStyleDeclaration.prototype.getPropertyShorthand = function(name) { + return this.shorthand_[name] || ''; +}; + + +/** + * @param {string} name of a CSS property. + * @return {boolean} + */ +devtools.CSSStyleDeclaration.prototype.isPropertyImplicit = function(name) { + return !!this.implicit_[name]; +}; + + +function firstChildSkippingWhitespace() { + return this.firstChild; +} + + +function onlyTextChild() { + if (!this.children) { + return null; + } else if (this.children.length == 1 && + this.children[0].nodeType == Node.TEXT_NODE) { + return this.children[0]; + } else { + return null; + } +} diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/inject.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/inject.js new file mode 100644 index 0000000..83c94d5 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/inject.js @@ -0,0 +1,464 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview Javascript that is being injected into the inspectable page + * while debugging. + */ +goog.require('goog.json'); +goog.provide('devtools.Injected'); + + +/** + * Main injected object. + * @constructor. + */ +devtools.Injected = function() { + /** + * Unique style id generator. + * @type {number} + * @private + */ + this.lastStyleId_ = 1; + + /** + * This array is not unused as it may seem. It stores references to the + * styles so that they could be found for future editing. + * @type {Array<CSSStyleDeclaration>} + * @private + */ + this.styles_ = []; +}; + + +/** + * Returns array of properties for a given node on a given path. + * @param {Node} node Node to get property value for. + * @param {Array.<string>} path Path to the nested object. + * @param {number} protoDepth Depth of the actual proto to inspect. + * @return {Array.<Object>} Array where each property is represented + * by the tree entries [{string} type, {string} name, {Object} value]. + */ +devtools.Injected.prototype.getProperties = function(node, path, protoDepth) { + var result = []; + var obj = node; + + // Follow the path. + for (var i = 0; obj && i < path.length; ++i) { + obj = obj[path[i]]; + } + + if (!obj) { + return []; + } + + // Get to the necessary proto layer. + for (var i = 0; obj && i < protoDepth; ++i) { + obj = obj.__proto__; + } + + if (!obj) { + return []; + } + + // Go over properties, prepare results. + for (var name in obj) { + if (protoDepth != -1 && 'hasOwnProperty' in obj && + !obj.hasOwnProperty(name)) { + continue; + } + var type = typeof obj[name]; + result.push(type); + result.push(name); + if (type == 'string') { + var str = obj[name]; + result.push(str.length > 99 ? str.substr(0, 99) + '...' : str); + } else if (type != 'object' && type != 'array' && + type != 'function') { + result.push(obj[name]); + } else { + result.push(undefined); + } + } + return result; +}; + + +/** + * Returns array of prototypes for a given node. + * @param {Node} node Node to get prorotypes for. + * @return {Array<string>} Array of proto names. + */ +devtools.Injected.prototype.getPrototypes = function(node) { + var result = []; + for (var prototype = node; prototype; prototype = prototype.__proto__) { + var description = Object.prototype.toString.call(prototype); + result.push(description.replace(/^\[object (.*)\]$/i, '$1')); + } + return result; +}; + + +/** + * Returns style information that is used in devtools.js. + * @param {Node} node Node to get prorotypes for. + * @param {boolean} authorOnly Determines whether only author styles need to + * be added. + * @return {string} Style collection descriptor. + */ +devtools.Injected.prototype.getStyles = function(node, authorOnly) { + if (!node.nodeType == Node.ELEMENT_NODE) { + return {}; + } + var matchedRules = window.getMatchedCSSRules(node, '', false); + var matchedCSSRulesObj = []; + for (var i = 0; matchedRules && i < matchedRules.length; ++i) { + var rule = matchedRules[i]; + var parentStyleSheet = rule.parentStyleSheet; + var isUserAgent = parentStyleSheet && !parentStyleSheet.ownerNode && + !parentStyleSheet.href; + var isUser = parentStyleSheet && parentStyleSheet.ownerNode && + parentStyleSheet.ownerNode.nodeName == '#document'; + + var style = this.serializeStyle_(rule.style, !isUserAgent && !isUser); + var ruleValue = { + 'selector' : rule.selectorText, + 'style' : style + }; + if (parentStyleSheet) { + ruleValue['parentStyleSheet'] = { + 'href' : parentStyleSheet.href, + 'ownerNodeName' : parentStyleSheet.ownerNode ? + parentStyleSheet.ownerNode.name : null + }; + } + matchedCSSRulesObj.push(ruleValue); + } + + var attributeStyles = {}; + var attributes = node.attributes; + for (var i = 0; attributes && i < attributes.length; ++i) { + if (attributes[i].style) { + attributeStyles[attributes[i].name] = + this.serializeStyle_(attributes[i].style, true); + } + } + var result = { + 'inlineStyle' : this.serializeStyle_(node.style, true), + 'computedStyle' : this.serializeStyle_( + window.getComputedStyle(node, '')), + 'matchedCSSRules' : matchedCSSRulesObj, + 'styleAttributes' : attributeStyles + }; + return result; +}; + + +/** + * Returns style decoration object for given id. + * @param {Node} node Node to get prorotypes for. + * @param {number} id Style id. + * @return {Object} Style object. + * @private + */ +devtools.Injected.prototype.getStyleForId_ = function(node, id) { + var matchedRules = window.getMatchedCSSRules(node, '', false); + for (var i = 0; matchedRules && i < matchedRules.length; ++i) { + var rule = matchedRules[i]; + if (rule.style.__id == id) { + return rule.style; + } + } + var attributes = node.attributes; + for (var i = 0; attributes && i < attributes.length; ++i) { + if (attributes[i].style && attributes[i].style.__id == id) { + return attributes[i].style; + } + } + if (node.style.__id == id) { + return node.style; + } + return null; +}; + + + + +/** + * Converts given style into serializable object. + * @param {CSSStyleDeclaration} style Style to serialize. + * @param {boolean} opt_bind Determins whether this style should be bound. + * @return {Array<Object>} Serializable object. + * @private + */ +devtools.Injected.prototype.serializeStyle_ = function(style, opt_bind) { + if (!style) { + return []; + } + var id = style.__id; + if (opt_bind && !id) { + id = style.__id = this.lastStyleId_++; + this.styles_.push(style); + } + var result = [ + id, + style.width, + style.height, + style.__disabledProperties, + style.__disabledPropertyValues, + style.__disabledPropertyPriorities + ]; + for (var i = 0; i < style.length; ++i) { + var name = style[i]; + result.push([ + name, + style.getPropertyPriority(name), + style.isPropertyImplicit(name), + style.getPropertyShorthand(name), + style.getPropertyValue(name) + ]); + } + return result; +}; + + +/** + * Toggles style with given id on/off. + * @param {Node} node Node to get prorotypes for. + * @param {number} styleId Id of style to toggle. + * @param {boolean} enabled Determines value to toggle to, + * @param {string} name Name of the property. + */ +devtools.Injected.prototype.toggleNodeStyle = function(node, styleId, enabled, + name) { + var style = this.getStyleForId_(node, styleId); + if (!style) { + return false; + } + + if (!enabled) { + if (!style.__disabledPropertyValues || + !style.__disabledPropertyPriorities) { + style.__disabledProperties = {}; + style.__disabledPropertyValues = {}; + style.__disabledPropertyPriorities = {}; + } + + style.__disabledPropertyValues[name] = style.getPropertyValue(name); + style.__disabledPropertyPriorities[name] = style.getPropertyPriority(name); + + if (style.getPropertyShorthand(name)) { + var longhandProperties = this.getLonghandProperties_(style, name); + for (var i = 0; i < longhandProperties.length; ++i) { + style.__disabledProperties[longhandProperties[i]] = true; + style.removeProperty(longhandProperties[i]); + } + } else { + style.__disabledProperties[name] = true; + style.removeProperty(name); + } + } else if (style.__disabledProperties && + style.__disabledProperties[name]) { + var value = style.__disabledPropertyValues[name]; + var priority = style.__disabledPropertyPriorities[name]; + style.setProperty(name, value, priority); + + delete style.__disabledProperties[name]; + delete style.__disabledPropertyValues[name]; + delete style.__disabledPropertyPriorities[name]; + } + return true; +}; + + +/** + * Applies given text to a style. + * @param {Node} node Node to get prorotypes for. + * @param {number} styleId Id of style to toggle. + * @param {string} name Style element name. + * @param {string} styleText New style text. + * @return {boolean} True iff style has been edited successfully. + */ +devtools.Injected.prototype.applyStyleText = function(node, styleId, + name, styleText) { + var style = this.getStyleForId_(node, styleId); + if (!style) { + return false; + } + + var styleTextLength = this.trimWhitespace_(styleText).length; + + // Create a new element to parse the user input CSS. + var parseElement = document.createElement("span"); + parseElement.setAttribute("style", styleText); + + var tempStyle = parseElement.style; + if (tempStyle.length || !styleTextLength) { + // The input was parsable or the user deleted everything, so remove the + // original property from the real style declaration. If this represents + // a shorthand remove all the longhand properties. + if (style.getPropertyShorthand(name)) { + var longhandProperties = this.getLonghandProperties_(style, name); + for (var i = 0; i < longhandProperties.length; ++i) { + style.removeProperty(longhandProperties[i]); + } + } else { + style.removeProperty(name); + } + } + if (!tempStyle.length) { + // The user typed something, but it didn't parse. Just abort and restore + // the original title for this property. + return false; + } + + // Iterate of the properties on the test element's style declaration and + // add them to the real style declaration. We take care to move shorthands. + var foundShorthands = {}; + var uniqueProperties = this.getUniqueStyleProperties_(tempStyle); + for (var i = 0; i < uniqueProperties.length; ++i) { + var name = uniqueProperties[i]; + var shorthand = tempStyle.getPropertyShorthand(name); + + if (shorthand && shorthand in foundShorthands) { + continue; + } + + if (shorthand) { + var value = this.getShorthandValue_(tempStyle, shorthand); + var priority = this.getShorthandPriority_(tempStyle, shorthand); + foundShorthands[shorthand] = true; + } else { + var value = tempStyle.getPropertyValue(name); + var priority = tempStyle.getPropertyPriority(name); + } + // Set the property on the real style declaration. + style.setProperty((shorthand || name), value, priority); + } + return true; +}; + + +/** + * Sets style property with given name to a value. + * @param {Node} node Node to get prorotypes for. + * @param {string} name Style element name. + * @param {string} value Value. + * @return {boolean} True iff style has been edited successfully. + */ +devtools.Injected.prototype.setStyleProperty = function(node, + name, value) { + node.style.setProperty(name, value, ""); + return true; +}; + + +/** + * Taken from utilities.js as is for injected evaluation. + */ +devtools.Injected.prototype.getLonghandProperties_ = function(style, + shorthandProperty) { + var properties = []; + var foundProperties = {}; + + for (var i = 0; i < style.length; ++i) { + var individualProperty = style[i]; + if (individualProperty in foundProperties || + style.getPropertyShorthand(individualProperty) != shorthandProperty) { + continue; + } + foundProperties[individualProperty] = true; + properties.push(individualProperty); + } + return properties; +}; + + +/** + * Taken from utilities.js as is for injected evaluation. + */ +devtools.Injected.prototype.getShorthandValue_ = function(style, + shorthandProperty) { + var value = style.getPropertyValue(shorthandProperty); + if (!value) { + // Some shorthands (like border) return a null value, so compute a + // shorthand value. + // FIXME: remove this when http://bugs.webkit.org/show_bug.cgi?id=15823 + // is fixed. + + var foundProperties = {}; + for (var i = 0; i < style.length; ++i) { + var individualProperty = style[i]; + if (individualProperty in foundProperties || + style.getPropertyShorthand(individualProperty) !== + shorthandProperty) { + continue; + } + + var individualValue = style.getPropertyValue(individualProperty); + if (style.isPropertyImplicit(individualProperty) || + individualValue === "initial") { + continue; + } + + foundProperties[individualProperty] = true; + + if (!value) { + value = ""; + } else if (value.length) { + value += " "; + } + value += individualValue; + } + } + return value; +}; + + +/** + * Taken from utilities.js as is for injected evaluation. + */ +devtools.Injected.prototype.getShorthandPriority_ = function(style, + shorthandProperty) { + var priority = style.getPropertyPriority(shorthandProperty); + if (!priority) { + for (var i = 0; i < style.length; ++i) { + var individualProperty = style[i]; + if (style.getPropertyShorthand(individualProperty) !== + shorthandProperty) { + continue; + } + priority = style.getPropertyPriority(individualProperty); + break; + } + } + return priority; +}; + + +/** + * Taken from utilities.js as is for injected evaluation. + */ +devtools.Injected.prototype.trimWhitespace_ = function(str) { + return str.replace(/^[\s\xA0]+|[\s\xA0]+$/g, ''); +}; + + +/** + * Taken from utilities.js as is for injected evaluation. + */ +devtools.Injected.prototype.getUniqueStyleProperties_ = function(style) { + var properties = []; + var foundProperties = {}; + + for (var i = 0; i < style.length; ++i) { + var property = style[i]; + if (property in foundProperties) { + continue; + } + foundProperties[property] = true; + properties.push(property); + } + return properties; +}; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/inspector.css b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/inspector.css new file mode 100644 index 0000000..c808437 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/inspector.css @@ -0,0 +1,3081 @@ +/* + * Copyright (C) 2006, 2007, 2008 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. + * 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. + */ + +body { + cursor: default; + height: 100%; + width: 100%; + overflow: hidden; + font-family: Lucida Grande, sans-serif; + font-size: 10px; + margin: 0; + -webkit-text-size-adjust: none; + -webkit-user-select: none; +} + +* { + -webkit-box-sizing: border-box; +} + +:focus { + outline: none; +} + +input[type="search"]:focus, input[type="text"]:focus { + outline: auto 5px -webkit-focus-ring-color; +} + +iframe, a img { + border: none; +} + +img { + -webkit-user-drag: none; +} + +.hidden { + display: none !important; +} + +#toolbar { + position: absolute; + top: 0; + left: 0; + right: 0; + height: 56px; + display: -webkit-box; + padding: 0 5px; + background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(191, 191, 191)), to(rgb(151, 151, 151))); + border-bottom: 1px solid rgb(80, 80, 80); + -webkit-box-orient: horizontal; + -webkit-background-origin: padding; + -webkit-background-clip: padding; +} + +body.inactive #toolbar { + background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(233, 233, 233)), to(rgb(207, 207, 207))); + border-bottom: 1px solid rgb(64%, 64%, 64%); +} + +body.detached.platform-mac-leopard #toolbar { + background: transparent !important; +} + +body.attached #toolbar { + height: 34px; + border-top: 1px solid rgb(100, 100, 100); + cursor: row-resize; + padding-left: 0; +} + +body.attached.inactive #toolbar { + border-top: 1px solid rgb(64%, 64%, 64%); +} + +.toolbar-item { + display: -webkit-box; + padding: 4px 6px; + margin: 0; + background-color: transparent; + border-style: none; + border-color: transparent; + -webkit-box-orient: vertical; + -webkit-box-align: center; + -webkit-box-pack: end; +} + +.toolbar-item.toggleable.toggled-on { + border-width: 0 2px 0 2px; + padding: 4px 4px; + -webkit-border-image: url(Images/toolbarItemSelected.png) 0 2 0 2; +} + +.toolbar-item.flexable-space { + -webkit-box-flex: 1; + visibility: hidden; +} + +.toolbar-item input { + margin-bottom: 8px; +} + +.toolbar-icon { + display: inline-block; + width: 32px; + height: 32px; + -webkit-background-size: 100% auto; +} + +body.attached .toolbar-icon { + width: 24px; + height: 24px; + vertical-align: middle; +} + +.toolbar-item:active .toolbar-icon { + background-position: 0 32px; +} + +body.attached .toolbar-item:active .toolbar-icon { + background-position: 0 24px; +} + +.toolbar-label { + font-size: 11px; + font-family: Lucida Grande, sans-serif; + text-shadow: rgba(255, 255, 255, 0.5) 0 1px 0; +} + +.toolbar-item.toggleable:active .toolbar-label { + text-shadow: none; +} + +body.attached .toolbar-label { + display: inline-block; + vertical-align: middle; + margin-left: 3px; +} + +body.attached #search-toolbar-label { + display: none; +} + +#search { + width: 205px; + font-size: 16px; + margin-bottom: 5px; +} + +body.attached #search { + font-size: 11px; + margin-bottom: 8px; +} + +#search-results-matches { + font-size: 11px; + text-shadow: rgba(255, 255, 255, 0.5) 0 1px 0; + margin-bottom: 22px; +} + +body.attached #search-results-matches { + margin-bottom: 6px; +} + +.toolbar-item.elements .toolbar-icon { + background-image: url(Images/elementsIcon.png); +} + +.toolbar-item.resources .toolbar-icon { + background-image: url(Images/resourcesIcon.png); +} + +.toolbar-item.scripts .toolbar-icon { + background-image: url(Images/scriptsIcon.png); +} + +.toolbar-item.databases .toolbar-icon { + background-image: url(Images/databasesIcon.png); +} + +.toolbar-item.profiles .toolbar-icon { + background-image: url(Images/profilesIcon.png); +} + +#close-button { + width: 14px; + height: 14px; + background-image: url(Images/closeButtons.png); + background-position: 0 0; + background-color: transparent; + border: 0 none transparent; + margin: 5px 0; +} + +#close-button:hover { + background-position: 14px 0; +} + +#close-button:active { + background-position: 28px 0; +} + +body.detached .toolbar-item.close { + display: none; +} + +#main { + position: absolute; + z-index: 1; + top: 56px; + left: 0; + right: 0; + bottom: 0; + overflow: hidden; + background-color: white; +} + +body.attached #main { + top: 34px; +} + +#main-panels { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 23px; + overflow: hidden; +} + +#main-status-bar { + position: absolute; + bottom: 0; + left: 0; + right: 0; +} + +body.console-visible #main-status-bar { + height: 24px; + background-image: url(Images/statusbarResizerVertical.png), url(Images/statusbarBackground.png); + background-repeat: no-repeat, repeat-x; + background-position: right center, center; + cursor: row-resize; +} + +body.console-visible #main-status-bar * { + cursor: default; +} + +body.console-visible #main-panels { + bottom: 24px; +} + +.status-bar { + background-color: rgb(235, 235, 235); + background-image: url(Images/statusbarBackground.png); + background-repeat: repeat-x; + white-space: nowrap; + height: 23px; + overflow: hidden; + z-index: 12; +} + +.status-bar > div { + display: inline-block; + vertical-align: top; +} + +.status-bar-item { + display: inline-block; + height: 24px; + padding: 0; + margin-left: -1px; + margin-right: 0; + vertical-align: top; + border: 0 transparent none; + background-color: transparent; +} + +.status-bar-item:active { + position: relative; + z-index: 200; +} + +button.status-bar-item { + width: 32px; + background-image: url(Images/statusbarButtons.png); + background-position: 0 0; +} + +button.status-bar-item:active { + background-position: 32px 0; +} + +button.status-bar-item:disabled { + opacity: 0.5; + background-position: 0 0 !important; +} + +select.status-bar-item { + min-width: 48px; + border-width: 0 17px 0 2px; + padding: 0 2px 0 6px; + font-weight: bold; + color: rgb(48, 48, 48); + text-shadow: rgba(255, 255, 255, 0.75) 0 1px 0; + -webkit-border-image: url(Images/statusbarMenuButton.png) 0 17 0 2; + -webkit-border-radius: 0; + -webkit-appearance: none; +} + +select.status-bar-item:active { + color: black; + -webkit-border-image: url(Images/statusbarMenuButtonSelected.png) 0 17 0 2; +} + +#dock-status-bar-item { + background-image: url(Images/dockButtons.png); +} + +body.attached #dock-status-bar-item:active { + background-position: 32px 0; +} + +body.detached #dock-status-bar-item { + background-position: 0 24px; +} + +body.detached #dock-status-bar-item.toggled-on:active { + background-position: 32px 24px; +} + +#console-status-bar-item { + background-image: url(Images/consoleButtons.png); +} + +#console-status-bar-item:active { + background-position: 32px 0; +} + +#console-status-bar-item.toggled-on { + background-position: 0 24px; +} + +#console-status-bar-item.toggled-on:active { + background-position: 32px 24px; +} + +#clear-console-status-bar-item { + background-image: url(Images/clearConsoleButtons.png); +} + +#clear-console-status-bar-item:active { + background-position: 32px 0; +} + +#error-warning-count { + position: absolute; + right: 16px; + top: 0; + cursor: pointer; + padding: 6px 2px; + font-size: 10px; + height: 19px; +} + +#error-warning-count:hover { + border-bottom: 1px solid rgb(96, 96, 96); +} + +#error-count::before { + content: url(Images/errorIcon.png); + width: 10px; + height: 10px; + vertical-align: -1px; + margin-right: 2px; +} + +#error-count + #warning-count { + margin-left: 6px; +} + +#warning-count::before { + content: url(Images/warningIcon.png); + width: 10px; + height: 10px; + vertical-align: -1px; + margin-right: 2px; +} + +#console { + display: none; + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 200px; + background-color: white; + background-image: url(Images/statusbarBottomBackground.png); + background-repeat: repeat-x; + background-position: bottom; +} + +body.console-visible #console { + display: block; +} + +#console-status-bar { + position: absolute; + bottom: 0; + left: 0; + right: 0; + background: none; +} + +#console-messages { + position: absolute; + z-index: 0; + top: 0; + left: 0; + right: 0; + bottom: 23px; + font-size: 10px; + font-family: Monaco, Lucida Console, monospace; + padding: 2px 0; + overflow-y: overlay; + -webkit-user-select: text; + -webkit-text-size-adjust: auto; +} + +#console-prompt { + position: relative; + padding: 1px 22px 1px 24px; + min-height: 16px; + white-space: pre-wrap; + -webkit-user-modify: read-write-plaintext-only; +} + +#console-prompt::before { + background-image: url(Images/userInputIcon.png); +} + +.console-user-command-result.console-log-level::before { + background-image: url(Images/userInputResultIcon.png); +} + +.console-message, .console-user-command { + position: relative; + border-bottom: 1px solid rgb(240, 240, 240); + padding: 1px 22px 1px 24px; + min-height: 16px; +} + +.console-adjacent-user-command-result { + border-bottom: none; +} + +.console-adjacent-user-command-result + .console-user-command-result.console-log-level::before { + background-image: none; +} + +.console-message::before, .console-user-command::before, #console-prompt::before, .console-group-title-level::before { + position: absolute; + display: block; + content: ""; + left: 7px; + top: 0.8em; + width: 10px; + height: 10px; + margin-top: -5px; + -webkit-user-select: none; +} + +.console-message .bubble { + display: inline-block; + height: 14px; + background-color: rgb(128, 151, 189); + vertical-align: middle; + white-space: nowrap; + padding: 1px 4px; + margin-top: -2px; + margin-right: 4px; + text-align: left; + font-size: 11px; + font-family: Helvetia, Arial, sans-serif; + font-weight: bold; + text-shadow: none; + color: white; + -webkit-border-radius: 7px; +} + +.console-message-text { + white-space: pre-wrap; +} + +.repeated-message { + padding-left: 6px; +} + +.repeated-message.console-error-level::before, .repeated-message.console-warning-level:before { + visibility: hidden; +} + +.console-group .console-group > .console-group-messages { + margin-left: 16px; +} + +.console-group-title-level { + font-weight: bold; +} + +.console-group-title-level::before { + background-image: url(Images/disclosureTriangleSmallDown.png); + top: 0.6em; + width: 11px; + height: 12px; +} + +.console-group.collapsed .console-group-title-level::before { + background-image: url(Images/disclosureTriangleSmallRight.png); +} + +.console-group.collapsed > .console-group-messages { + display: none; +} + +.console-error-level .console-message-text { + color: red; +} + +.console-error-level::before { + background-image: url(Images/errorIcon.png); +} + +.console-warning-level::before { + background-image: url(Images/warningIcon.png); +} + +.console-user-command .console-message { + margin-left: -24px; + padding-right: 0; + border-bottom: none; +} + +.console-user-command::before { + background-image: url(Images/userInputPreviousIcon.png); +} + +.console-user-command > .console-message-text { + color: rgb(0, 128, 255); +} + +#console-messages a { + color: rgb(33%, 33%, 33%); + cursor: pointer; +} + +#console-messages a:hover { + color: rgb(15%, 15%, 15%); +} + +.console-message-url { + float: right; +} + +.console-group-messages .section { + margin: 0 0 0 12px !important; +} + +.console-group-messages .section .header { + padding: 0 8px 0 0; + background-image: none; + border: none; + min-height: 0; +} + +.console-group-messages .section .header::before { + position: absolute; + top: 1px; + left: 1px; + width: 8px; + height: 8px; + content: url(Images/treeRightTriangleBlack.png); +} + +.console-group-messages .section.expanded .header::before { + content: url(Images/treeDownTriangleBlack.png); +} + +.console-group-messages .section .header .title { + color: black; + font-weight: normal; +} + +.console-group-messages .section .properties li .info { + padding-top: 0; + padding-bottom: 0; + color: rgb(60%, 60%, 60%); +} + +.console-group-messages .outline-disclosure { + padding-left: 0; +} + +.console-group-messages .outline-disclosure > ol { + padding: 0 0 0 12px !important; +} + +.console-group-messages .outline-disclosure, .console-group-messages .outline-disclosure ol { + font-size: inherit; + line-height: 1em; +} + +.console-group-messages .outline-disclosure.single-node li { + padding-left: 2px; +} + +.console-group-messages .outline-disclosure li .selection { + margin-left: -6px; + margin-right: -6px; +} + +.console-formatted-object, .console-formatted-node { + position: relative; + display: inline-block; + vertical-align: top; +} + +.console-formatted-object .section, .console-formatted-node .section { + position: static; +} + +.console-formatted-object .properties, .console-formatted-node .properties { + padding-left: 0 !important; +} + +.error-message { + color: red; +} + +.auto-complete-text { + color: rgb(128, 128, 128); + -webkit-user-select: none; + -webkit-user-modify: read-only; +} + +.panel { + display: none; + overflow: hidden; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; +} + +.panel.visible { + display: block; +} + +.resource-view { + display: none; + overflow: hidden; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + overflow: hidden; +} + +.resource-view.visible { + display: block; +} + +.resource-view.headers-visible { + overflow-y: auto; + overflow-x: hidden; +} + +.resource-view-headers { + display: none; + padding: 6px; + border-bottom: 1px solid rgb(64%, 64%, 64%); + background-color: white; + -webkit-user-select: text; +} + +.resource-view-headers .outline-disclosure .parent { + -webkit-user-select: none; + font-weight: bold; +} + +.resource-view.headers-visible .resource-view-headers { + display: block; +} + +.resource-view-headers .outline-disclosure .children li { + white-space: nowrap; +} + +.resource-view-headers .outline-disclosure li.expanded .header-count { + display: none; +} + +.resource-view-headers .outline-disclosure .header-name { + color: rgb(33%, 33%, 33%); + display: inline-block; + width: 105px; + text-align: right; + margin-right: 0.5em; + font-weight: bold; + vertical-align: top; + overflow: hidden; + text-overflow: ellipsis; +} + +.resource-view-headers .outline-disclosure .header-value { + display: inline-block; + white-space: normal; + word-break: break-word; + vertical-align: top; + margin-right: 100px; +} + +.resource-view .resource-view-content { + position: absolute; + top: 0; + right: 0; + left: 0; + bottom: 0; +} + +.resource-view.headers-visible .resource-view-content { + position: relative; + top: auto; + right: auto; + left: auto; + bottom: auto; +} + +.resource-view.headers-visible .source-view-frame { + height: auto; + vertical-align: top; +} + +.webkit-line-gutter-backdrop { + /* Keep this in sync with view-source.css (.webkit-line-gutter-backdrop) */ + width: 31px; + background-color: rgb(240, 240, 240); + border-right: 1px solid rgb(187, 187, 187); + position: absolute; + z-index: -1; + left: 0; + top: 0; + height: 100% +} + +.resource-view.font .resource-view-content { + font-size: 60px; + white-space: pre-wrap; + word-wrap: break-word; + text-align: center; + padding: 15px; +} + +.resource-view.image .resource-view-content > .image { + padding: 20px 20px 10px 20px; + text-align: center; +} + +.resource-view.image .resource-view-content > .info { + padding-bottom: 10px; + font-size: 11px; + -webkit-user-select: text; +} + +.resource-view.image img { + max-width: 100%; + max-height: 1000px; + background-image: url(Images/checker.png); + -webkit-box-shadow: 0px 5px 10px rgba(0, 0, 0, 0.5); + -webkit-user-select: text; + -webkit-user-drag: auto; +} + +.resource-view.image .title { + text-align: center; + font-size: 13px; +} + +.resource-view.image .infoList { + margin: 0; +} + +.resource-view.image .infoList dt { + font-weight: bold; + display: inline-block; + width: 50%; + text-align: right; + color: rgb(76, 76, 76); +} + +.resource-view.image .infoList dd { + display: inline-block; + padding-left: 8px; + width: 50%; + text-align: left; + margin: 0; +} + +.resource-view.image .infoList dd::after { + white-space: pre; + content: "\A"; +} + +#elements-content { + display: block; + overflow: auto; + padding: 0; + position: absolute; + top: 0; + left: 0; + right: 225px; + bottom: 0; +} + +#elements-sidebar { + position: absolute; + top: 0; + right: 0; + bottom: 0; + width: 225px; + background-color: rgb(245, 245, 245); + border-left: 1px solid rgb(64%, 64%, 64%); + cursor: default; + overflow: auto; +} + +.crumbs { + display: inline-block; + font-size: 11px; + line-height: 19px; + text-shadow: rgba(255, 255, 255, 0.75) 0 1px 0; + color: rgb(20, 20, 20); + margin-left: -1px; + padding-right: 12px; +} + +.crumbs .crumb { + height: 24px; + border-width: 0 12px 0 2px; + -webkit-border-image: url(Images/segment.png) 0 12 0 2; + margin-right: -12px; + padding-left: 18px; + padding-right: 2px; + white-space: nowrap; + line-height: 23px; + float: right; +} + +.crumbs .crumb.collapsed > * { + display: none; +} + +.crumbs .crumb.collapsed::before { + content: "\2026"; + font-weight: bold; +} + +.crumbs .crumb.compact .extra { + display: none; +} + +.crumbs .crumb.dimmed { + color: rgba(0, 0, 0, 0.45); +} + +.crumbs .crumb.start { + padding-left: 7px; +} + +.crumbs .crumb.end { + border-width: 0 2px 0 2px; + padding-right: 6px; + -webkit-border-image: url(Images/segmentEnd.png) 0 2 0 2; +} + +.crumbs .crumb.selected { + -webkit-border-image: url(Images/segmentSelected.png) 0 12 0 2; + color: black; + text-shadow: rgba(255, 255, 255, 0.5) 0 1px 0; +} + +.crumbs .crumb.selected:hover { + -webkit-border-image: url(Images/segmentSelected.png) 0 12 0 2; +} + +.crumbs .crumb.selected.end, .crumbs .crumb.selected.end:hover { + -webkit-border-image: url(Images/segmentSelectedEnd.png) 0 2 0 2; +} + +.crumbs .crumb:hover { + -webkit-border-image: url(Images/segmentHover.png) 0 12 0 2; + color: black; +} + +.crumbs .crumb.dimmed:hover { + -webkit-border-image: url(Images/segmentHover.png) 0 12 0 2; + color: rgba(0, 0, 0, 0.75); +} + +.crumbs .crumb.end:hover { + -webkit-border-image: url(Images/segmentHoverEnd.png) 0 2 0 2; +} + +.outline-disclosure li.hovered:not(.selected) .selection { + display: block; + left: 3px; + right: 3px; + background-color: rgba(56, 121, 217, 0.1); + -webkit-border-radius: 5px; +} + +.outline-disclosure li.highlighted .highlight { + background-color: rgb(255, 230, 179); + -webkit-border-radius: 4px; + padding-bottom: 2px; + margin-bottom: -2px; +} + +.outline-disclosure li.selected.highlighted .highlight { + background-color: transparent; + padding-bottom: 0; + margin-bottom: 0; +} + +.outline-disclosure li .selection { + display: none; + position: absolute; + left: 0; + right: 0; + height: 15px; + z-index: -1; +} + +.outline-disclosure li.selected .selection { + display: block; + background-color: rgb(212, 212, 212); +} + +:focus .outline-disclosure li.selected .selection { + background-color: rgb(56, 121, 217); +} + +.outline-disclosure > ol { + position: relative; + padding: 2px 6px !important; + margin: 0; + color: black; + cursor: default; + min-width: 100%; +} + +.outline-disclosure, .outline-disclosure ol { + list-style-type: none; + font-size: 11px; + -webkit-padding-start: 12px; + margin: 0; +} + +.outline-disclosure li { + padding: 0 0 2px 14px; + margin-top: 1px; + margin-bottom: 1px; + word-wrap: break-word; + text-indent: -2px +} + +:focus .outline-disclosure li.selected { + color: white; +} + +:focus .outline-disclosure li.selected * { + color: inherit; +} + +.outline-disclosure li.parent { + text-indent: -12px +} + +.outline-disclosure li .webkit-html-tag.close { + margin-left: -12px; +} + +.outline-disclosure li.parent::before { + content: url(Images/treeRightTriangleBlack.png); + float: left; + width: 8px; + height: 8px; + margin-top: 1px; + padding-right: 2px; +} + +.outline-disclosure li.parent::before { + content: url(Images/treeRightTriangleBlack.png); +} + +:focus .outline-disclosure li.parent.selected::before { + content: url(Images/treeRightTriangleWhite.png); +} + +.outline-disclosure li.parent.expanded::before { + content: url(Images/treeDownTriangleBlack.png); +} + +:focus .outline-disclosure li.parent.expanded.selected::before { + content: url(Images/treeDownTriangleWhite.png); +} + +.outline-disclosure ol.children { + display: none; +} + +.outline-disclosure ol.children.expanded { + display: block; +} + +.webkit-html-comment { + /* Keep this in sync with view-source.css (.webkit-html-comment) */ + color: rgb(35, 110, 37); +} + +.webkit-html-tag { + /* Keep this in sync with view-source.css (.webkit-html-tag) */ + color: rgb(136, 18, 128); +} + +.webkit-html-doctype { + /* Keep this in sync with view-source.css (.webkit-html-doctype) */ + color: rgb(192, 192, 192); +} + +.webkit-html-attribute-name { + /* Keep this in sync with view-source.css (.webkit-html-attribute-name) */ + color: rgb(153, 69, 0); +} + +.webkit-html-attribute-value { + /* Keep this in sync with view-source.css (.webkit-html-attribute-value) */ + color: rgb(26, 26, 166); +} + +.webkit-html-external-link, .webkit-html-resource-link { + /* Keep this in sync with view-source.css (.webkit-html-external-link, .webkit-html-resource-link) */ + color: #00e; +} + +.webkit-html-external-link { + /* Keep this in sync with view-source.css (.webkit-html-external-link) */ + text-decoration: none; +} + +.webkit-html-external-link:hover { + /* Keep this in sync with view-source.css (.webkit-html-external-link:hover) */ + text-decoration: underline; +} + +.placard { + position: relative; + margin-top: 1px; + padding: 3px 8px 4px 18px; + min-height: 18px; + white-space: nowrap; +} + +.placard:nth-of-type(2n) { + background-color: rgb(234, 243, 255); +} + +.placard.selected { + border-top: 1px solid rgb(145, 160, 192); + background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(162, 177, 207)), to(rgb(120, 138, 177))); + -webkit-background-origin: padding; + -webkit-background-clip: padding; +} + +:focus .placard.selected { + border-top: 1px solid rgb(68, 128, 200); + background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(92, 147, 213)), to(rgb(21, 83, 170))); +} + +body.inactive .placard.selected { + border-top: 1px solid rgb(151, 151, 151); + background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(180, 180, 180)), to(rgb(138, 138, 138))); +} + +.placard .title { + color: black; + font-weight: normal; + word-wrap: break-word; + white-space: normal; +} + +.placard.selected .title { + color: white; + font-weight: bold; +} + +.placard .subtitle { + float: right; + font-size: 10px; + margin-left: 5px; + max-width: 55%; + color: rgba(0, 0, 0, 0.7); + text-overflow: ellipsis; + overflow: hidden; +} + +.placard.selected .subtitle { + color: rgba(255, 255, 255, 0.7); +} + +.placard .subtitle a { + color: inherit; +} + +.section { + position: relative; + margin-top: 1px; +} + +.section:nth-last-of-type(1) { + margin-bottom: 1px; +} + +.section .header { + padding: 2px 8px 4px 18px; + border-top: 1px solid rgb(145, 160, 192); + background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(162, 177, 207)), to(rgb(120, 138, 177))); + min-height: 18px; + white-space: nowrap; + -webkit-background-origin: padding; + -webkit-background-clip: padding; +} + +.section .header::before { + position: absolute; + top: 4px; + left: 7px; + width: 8px; + height: 8px; + content: url(Images/treeRightTriangleWhite.png); +} + +.section.expanded .header::before { + content: url(Images/treeDownTriangleWhite.png); +} + +.section .header .title { + color: white; + font-weight: bold; + word-wrap: break-word; + white-space: normal; +} + +.section .header label { + display: none; +} + +.section.expanded .header label { + display: inline; +} + +.section .header input[type=checkbox] { + height: 10px; + width: 10px; + margin-left: 0; + margin-top: 0; + margin-bottom: 0; + vertical-align: 2px; +} + +.section .header .subtitle { + float: right; + font-size: 10px; + margin-left: 5px; + max-width: 55%; + color: rgba(255, 255, 255, 0.7); + text-overflow: ellipsis; + overflow: hidden; +} + +.section .header .subtitle a { + color: inherit; +} + +.section .properties { + display: none; + margin: 0; + padding: 2px 6px 3px; + list-style: none; + background-color: white; +} + +.section.expanded .properties { + display: block; +} + +.section .properties li { + margin-left: 12px; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + -webkit-user-select: text; + cursor: auto; +} + +.section .properties li.parent { + margin-left: 1px; +} + +.section .properties ol { + display: none; + margin: 0; + -webkit-padding-start: 12px; + list-style: none; +} + +.section .properties ol.expanded { + display: block; +} + +.section .properties li.parent::before { + content: url(Images/treeRightTriangleBlack.png); + opacity: 0.75; + float: left; + width: 8px; + height: 8px; + margin-top: 0; + padding-right: 3px; + -webkit-user-select: none; + cursor: default; +} + +.section .properties li.parent.expanded::before { + content: url(Images/treeDownTriangleBlack.png); + margin-top: 1px; +} + +.section .properties li .info { + padding-top: 4px; + padding-bottom: 3px; +} + +.editing { + -webkit-user-select: text; + -webkit-box-shadow: rgba(0, 0, 0, .5) 3px 3px 4px; + outline: 1px solid rgb(66%, 66%, 66%) !important; + background-color: white; + -webkit-user-modify: read-write-plaintext-only; + text-overflow: clip; + padding-left: 2px; + margin-left: -2px; + padding-right: 2px; + margin-right: -2px; + margin-bottom: -1px; + padding-bottom: 1px; + opacity: 1.0 !important; +} + +.editing, .editing * { + color: black !important; + text-decoration: none !important; +} + +.section .properties li.editing { + margin-left: 10px; + text-overflow: clip; +} + +li.editing .swatch, li.editing .enabled-button { + display: none !important; +} + +.section .properties li.editing-sub-part { + padding: 3px 6px 8px 18px; + margin: -3px -6px -8px -6px; + text-overflow: clip; +} + +.section .properties .overloaded, .section .properties .disabled { + text-decoration: line-through; +} + +.section.computed-style .properties .disabled { + text-decoration: none; + opacity: 0.5; +} + +.section .properties .implicit, .section .properties .inherited { + opacity: 0.5; +} + +.section:not(.show-inherited) .properties .inherited { + display: none; +} + +.section .properties .enabled-button { + display: none; + float: right; + font-size: 10px; + margin: 0 0 0 4px; + vertical-align: top; + position: relative; + z-index: 1; +} + +.section:hover .properties .enabled-button { + display: block; +} + +.section .properties .name { + color: rgb(136, 19, 145); +} + +.section .properties .value.dimmed { + color: rgb(100, 100, 100); +} + +.section .properties .number { + color: blue; +} + +.section .properties .priority { + color: rgb(128, 0, 0); +} + +.section .properties .keyword { + color: rgb(136, 19, 79); +} + +.section .properties .color { + color: rgb(118, 15, 21); +} + +.swatch { + display: inline-block; + vertical-align: baseline; + margin-left: 4px; + margin-bottom: -1px; + width: 1em; + height: 1em; + border: 1px solid rgb(180, 180, 180); +} + +.pane:not(.expanded) + .pane, .pane:first-of-type { + margin-top: -1px; +} + +.pane > .title { + background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(243, 243, 243)), color-stop(0.05, rgb(243, 243, 243)), color-stop(0.05, rgb(230, 230, 230)), to(rgb(209, 209, 209))); + height: 20px; + padding: 0 5px; + border-top: 1px solid rgb(189, 189, 189); + border-bottom: 1px solid rgb(189, 189, 189); + font-weight: bold; + font-size: 12px; + line-height: 18px; + color: rgb(110, 110, 110); + text-shadow: white 0 1px 0; + -webkit-background-origin: padding; + -webkit-background-clip: padding; +} + +.pane > .title:active { + background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(231, 231, 231)), color-stop(0.05, rgb(231, 231, 231)), color-stop(0.05, rgb(207, 207, 207)), to(rgb(186, 186, 186))); + border-top: 1px solid rgb(178, 178, 178); + border-bottom: 1px solid rgb(178, 178, 178); +} + +.pane > .title::before { + content: url(Images/disclosureTriangleSmallRightBlack.png); + float: left; + width: 11px; + height: 12px; + margin-right: 2px; + margin-top: 1px; +} + +.pane.expanded > .title::before { + content: url(Images/disclosureTriangleSmallDownBlack.png); +} + +.pane > .body { + position: relative; + display: none; + background-color: white; + overflow-y: auto; + overflow-x: hidden; +} + +.pane > .body .info { + text-align: center; + font-style: italic; + font-size: 10px; + padding: 6px; + color: gray; +} + +.pane.expanded > .body, .pane.expanded > .growbar { + display: block; +} + +.pane.expanded:nth-last-of-type(1) { + border-bottom: 1px solid rgb(189, 189, 189); +} + +.pane > .growbar { + display: none; + background-image: url(Images/paneGrowHandleLine.png), url(Images/paneBottomGrow.png); + background-repeat: no-repeat, repeat-x; + background-position: center center, bottom; + height: 5px; +} + +.metrics { + padding: 8px; + font-size: 10px; + text-align: center; + white-space: nowrap; +} + +.metrics .label { + position: absolute; + margin-top: -10px; + font-size: 9px; + color: grey; + background-color: white; + margin-left: 3px; + padding-left: 2px; + padding-right: 2px; +} + +.metrics .position { + border: 1px rgb(66%, 66%, 66%) dotted; + display: inline-block; + text-align: center; + padding: 3px; + margin: 3px; +} + +.metrics .margin { + border: 1px dashed; + display: inline-block; + text-align: center; + vertical-align: middle; + padding: 3px; + margin: 3px; +} + +.metrics .border { + border: 1px black solid; + display: inline-block; + text-align: center; + vertical-align: middle; + padding: 3px; + margin: 3px; +} + +.metrics .padding { + border: 1px grey dashed; + display: inline-block; + text-align: center; + vertical-align: middle; + padding: 3px; + margin: 3px; +} + +.metrics .content { + position: static; + border: 1px grey solid; + display: inline-block; + text-align: center; + vertical-align: middle; + padding: 3px; + margin: 3px; + min-width: 80px; + text-align: center; + overflow: visible; +} + +.metrics .content span { + display: inline-block; +} + +.metrics .editing { + position: relative; + z-index: 100; +} + +.metrics .left { + display: inline-block; + vertical-align: middle; +} + +.metrics .right { + display: inline-block; + vertical-align: middle; +} + +.metrics .top { + display: inline-block; +} + +.metrics .bottom { + display: inline-block; +} + +.sidebar { + position: absolute; + top: 0; + left: 0; + bottom: 0; + width: 200px; + overflow-y: auto; + overflow-x: hidden; + background-color: rgb(214, 221, 229); + border-right: 1px solid rgb(64%, 64%, 64%); +} + +body.inactive .sidebar { + background-color: rgb(232, 232, 232); +} + +.database-sidebar-tree-item .icon { + content: url(Images/database.png); +} + +.database-table-sidebar-tree-item .icon { + content: url(Images/databaseTable.png); +} + +.domstorage-sidebar-tree-item .icon { + content: url(Images/domStorage.png); +} + +#storage-views { + position: absolute; + top: 0; + right: 0; + left: 200px; + bottom: 0; +} + +.storage-view { + display: none; + overflow: hidden; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; +} + +.storage-view.visible { + display: block; +} + +.storage-view.table { + overflow: hidden; +} + +.storage-view.table .data-grid { + border: none; + height: 100%; +} + +.storage-view.table .storage-table-empty, .storage-view.table .storage-table-error { + position: absolute; + top: 0; + bottom: 25%; + left: 0; + right: 0; + font-size: 24px; + color: rgb(75%, 75%, 75%); + margin-top: auto; + margin-bottom: auto; + height: 50px; + line-height: 26px; + text-align: center; + font-weight: bold; + padding: 10px; + white-space: pre-wrap; +} + +.storage-view.table .storage-table-error { + color: rgb(66%, 33%, 33%); +} + +.data-grid { + position: relative; + border: 1px solid #aaa; +} + +.data-grid .highlight { + background-color: rgb(255, 230, 179); +} + +.data-grid tr.selected .highlight { + background-color: transparent; +} + +.data-grid table { + table-layout: fixed; + border-spacing: 0; + border-collapse: collapse; + width: 100%; + font-size: 10px; + font-family: Lucida Grande, sans-serif; +} + +.data-grid .data-container { + position: absolute; + top: 16px; + bottom: 0; + left: 0; + right: 0; + padding-right: 14px; + overflow-x: hidden; + overflow-y: overlay; + background-image: -webkit-gradient(linear, left top, left bottom, from(white), color-stop(0.5, white), color-stop(0.5, rgb(234, 243, 255)), to(rgb(234, 243, 255))); + -webkit-background-size: 1px 32px; +} + +.data-grid.inline .data-container { + position: static; +} + +.data-grid th { + text-align: left; + background-image: url(Images/glossyHeader.png); + background-repeat: repeat-x; + border-right: 1px solid rgb(179, 179, 179); + border-bottom: 1px solid rgb(179, 179, 179); + height: 15px; + font-weight: normal; + vertical-align: middle; + padding: 0 4px; + white-space: nowrap; +} + +.data-grid th.corner { + width: 15px; + border-right: 0 none transparent; +} + +.data-grid tr.filler { + display: table-row !important; + height: auto !important; +} + +.data-grid tr.filler td { + height: auto !important; + padding: 0 !important; +} + +.data-grid table.data { + position: absolute; + left: 0; + top: 0; + right: 16px; + bottom: 0; + height: 100%; + border-top: 0 none transparent; + background-image: -webkit-gradient(linear, left top, left bottom, from(white), color-stop(0.5, white), color-stop(0.5, rgb(234, 243, 255)), to(rgb(234, 243, 255))); + -webkit-background-size: 1px 32px; +} + +.data-grid.inline table.data { + position: static; +} + +.data-grid table.data tr { + display: none; +} + +.data-grid table.data tr.revealed { + display: table-row; +} + +.data-grid td { + vertical-align: top; + height: 12px; + padding: 2px 4px; + white-space: nowrap; + border-right: 1px solid #aaa; + -webkit-user-select: text; +} + +.data-grid td > div, .data-grid th > div { + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; +} + +.data-grid th.sortable div { + position: relative; +} + +.data-grid th.sortable:active { + background-image: url(Images/glossyHeaderPressed.png); +} + +.data-grid th.sort-ascending, .data-grid th.sort-descending { + border-right: 1px solid rgb(107, 140, 196); + border-bottom: 1px solid rgb(107, 140, 196); + background-image: url(Images/glossyHeaderSelected.png); + background-repeat: repeat-x; +} + +.data-grid th.sortable.sort-ascending:active, .data-grid th.sortable.sort-descending:active { + background-image: url(Images/glossyHeaderSelectedPressed.png); +} + +.data-grid th.sort-ascending div::after { + position: absolute; + top: 0; + right: 0; + width: 8px; + height: 8px; + content: url(Images/treeUpTriangleBlack.png); +} + +.data-grid th.sort-descending div::after { + position: absolute; + top: 0; + right: 0; + margin-top: 1px; + width: 8px; + height: 8px; + content: url(Images/treeDownTriangleBlack.png); +} + +body.inactive .data-grid th.sort-ascending, body.inactive .data-grid th.sort-descending { + background-image: url(Images/glossyHeader.png); + border-right: 1px solid rgb(179, 179, 179); + border-bottom: 1px solid rgb(179, 179, 179); +} + +.data-grid tr.parent td.disclosure::before { + float: left; + content: url(Images/treeRightTriangleBlack.png); + width: 8px; + height: 8px; + margin-right: 2px; + -webkit-user-select: none; +} + +.data-grid tr.expanded td.disclosure::before { + content: url(Images/treeDownTriangleBlack.png); + width: 8px; + height: 8px; + margin-top: 1px; +} + +.data-grid tr.selected { + background-color: rgb(212, 212, 212); + color: inherit; +} + +.data-grid:focus tr.selected { + background-color: rgb(56, 121, 217); + color: white; +} + +.data-grid:focus tr.parent.selected td.disclosure::before { + content: url(Images/treeRightTriangleWhite.png); +} + +.data-grid:focus tr.expanded.selected td.disclosure::before { + content: url(Images/treeDownTriangleWhite.png); +} + +.data-grid tr:not(.parent) td.disclosure { + text-indent: 10px; +} + +.storage-view.query { + font-size: 10px; + font-family: Monaco, Lucida Console, monospace; + padding: 2px 0; + overflow-y: overlay; + overflow-x: hidden; + -webkit-text-size-adjust: auto; +} + +.database-query-prompt { + position: relative; + padding: 1px 22px 1px 24px; + min-height: 16px; + white-space: pre-wrap; + -webkit-user-modify: read-write-plaintext-only; + -webkit-user-select: text; +} + +.database-user-query::before, .database-query-prompt::before, .database-query-result::before { + position: absolute; + display: block; + content: ""; + left: 7px; + top: 0.8em; + width: 10px; + height: 10px; + margin-top: -5px; + -webkit-user-select: none; +} + +.database-query-prompt::before { + background-image: url(Images/userInputIcon.png); +} + +.database-user-query { + position: relative; + border-bottom: 1px solid rgb(245, 245, 245); + padding: 1px 22px 1px 24px; + min-height: 16px; +} + +.database-user-query::before { + background-image: url(Images/userInputPreviousIcon.png); +} + +.database-query-text { + color: rgb(0, 128, 255); + -webkit-user-select: text; +} + +.database-query-result { + position: relative; + padding: 1px 22px 1px 24px; + min-height: 16px; + margin-left: -24px; + padding-right: 0; +} + +.database-query-result.error { + color: red; + -webkit-user-select: text; +} + +.database-query-result.error::before { + background-image: url(Images/errorIcon.png); +} + +.panel-enabler-view { + z-index: 1000; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: white; + font-size: 13px; + text-align: center; + overflow-x: hidden; + overflow-y: overlay; + display: none; +} + +.panel-enabler-view.visible { + display: block; +} + +.panel-enabler-view .panel-enabler-view-content { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + max-height: 390px; + margin: auto; + white-space: nowrap; +} + +.panel-enabler-view h1 { + color: rgb(110, 116, 128); + font-size: 16px; + line-height: 20px; + font-weight: normal; + margin-top: 0; +} + +.panel-enabler-disclaimer { + font-size: 10px; + color: rgb(110, 116, 128); + margin-bottom: 12px; +} + +.panel-enabler-disclaimer:empty { + display: none; +} + +.panel-enabler-view img { + height: 100%; + min-height: 200px; + max-width: 100%; + top: 0; + bottom: 0; + padding: 20px 0 20px 20px; + margin: auto; + vertical-align: middle; +} + +.panel-enabler-view img.hidden { + display: initial !important; + width: 0; +} + +.panel-enabler-view form { + display: inline-block; + vertical-align: middle; + width: 330px; + margin: 0; + padding: 15px; + white-space: normal; +} + +.panel-enabler-view label { + position: relative; + display: block; + text-align: left; + margin-left: 50px; + margin-bottom: 6px; + line-height: 18px; + word-break: break-word; +} + +.panel-enabler-view button { + font-size: 13px; + margin: 6px 0 0 0; + padding: 3px 20px; + color: rgb(6, 6, 6); + height: 24px; + background-color: transparent; + border: 1px solid rgb(165, 165, 165); + background-color: rgb(237, 237, 237); + background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(252, 252, 252)), to(rgb(223, 223, 223))); + -webkit-border-radius: 12px; + -webkit-appearance: none; +} + +.panel-enabler-view button:active { + background-color: rgb(215, 215, 215); + background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(194, 194, 194)), to(rgb(239, 239, 239))); +} + +body.inactive .panel-enabler-view button, .panel-enabler-view button:disabled { + color: rgb(130, 130, 130); + border-color: rgb(212, 212, 212); + background-color: rgb(239, 239, 239); + background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(250, 250, 250)), to(rgb(235, 235, 235))); +} + +.panel-enabler-view.scripts img { + content: url(Images/scriptsSilhouette.png); +} + +.panel-enabler-view.profiles img { + content: url(Images/profilesSilhouette.png); +} + +button.enable-toggle-status-bar-item { + background-image: url(Images/enableButtons.png); +} + +button.enable-toggle-status-bar-item:active { + background-position: 32px 0; +} + +button.enable-toggle-status-bar-item.toggled-on { + background-position: 0 24px; +} + +button.enable-toggle-status-bar-item.toggled-on:active { + background-position: 32px 24px; +} + +#scripts-pause-on-exceptions-status-bar-item { + background-image: url(Images/pauseOnExceptionButtons.png); +} + +#scripts-pause-on-exceptions-status-bar-item:active { + background-position: 32px 0; +} + +#scripts-pause-on-exceptions-status-bar-item.toggled-on { + background-position: 0 24px; +} + +#scripts-pause-on-exceptions-status-bar-item.toggled-on:active { + background-position: 32px 24px; +} + +#scripts-status-bar { + position: absolute; + top: -1px; + left: 0; + right: 0; + height: 24px; +} + +#scripts-files { + max-width: 250px; +} + +#scripts-functions { + max-width: 150px; +} + +#scripts-status-bar .status-bar-item img { + margin-top: 2px; +} + +#scripts-back img { + content: url(Images/back.png); +} + +#scripts-forward img { + content: url(Images/forward.png); +} + +#scripts-pause img { + content: url(Images/debuggerPause.png); +} + +#scripts-pause.paused img { + content: url(Images/debuggerContinue.png); +} + +#scripts-step-over img { + content: url(Images/debuggerStepOver.png); +} + +#scripts-step-into img { + content: url(Images/debuggerStepInto.png); +} + +#scripts-step-out img { + content: url(Images/debuggerStepOut.png); +} + +#scripts-debugger-status { + position: absolute; + line-height: 24px; + top: 0; + right: 8px; +} + +#scripts-sidebar-resizer-widget { + position: absolute; + top: 0; + bottom: 0; + right: 225px; + width: 16px; + cursor: col-resize; + background-image: url(Images/statusbarResizerHorizontal.png); + background-repeat: no-repeat; + background-position: center; +} + +#scripts-sidebar-buttons { + position: absolute; + right: 0; + top: 0; + bottom: 0; + width: 225px; + overflow: hidden; + border-left: 1px solid rgb(64%, 64%, 64%); +} + +#script-resource-views { + display: block; + overflow: auto; + padding: 0; + position: absolute; + top: 23px; + left: 0; + right: 225px; + bottom: 0; +} + +.script-view { + display: none; + overflow: hidden; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; +} + +.script-view.visible { + display: block; +} + +#scripts-sidebar { + position: absolute; + top: 23px; + right: 0; + bottom: 0; + width: 225px; + background-color: rgb(245, 245, 245); + border-left: 1px solid rgb(64%, 64%, 64%); + cursor: default; + overflow: auto; +} + +#resources-larger-resources-status-bar-item { + background-image: url(Images/largerResourcesButtons.png); +} + +#resources-larger-resources-status-bar-item:active { + background-position: 32px 0; +} + +#resources-larger-resources-status-bar-item.toggled-on { + background-position: 0 24px; +} + +#resources-larger-resources-status-bar-item.toggled-on:active { + background-position: 32px 24px; +} + +#resources-container { + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + border-right: 0 none transparent; + overflow-y: auto; + overflow-x: hidden; +} + +#resources-container.viewing-resource { + right: auto; + width: 200px; + border-right: 1px solid rgb(64%, 64%, 64%); +} + +#resources-container.viewing-resource #resources-sidebar { + width: 100%; + border-right: 0 none transparent; +} + +#resources-sidebar { + min-height: 100%; + bottom: auto; + overflow: visible; +} + +#resources-container-content { + position: absolute; + top: 0; + right: 0; + left: 200px; + min-height: 100%; +} + +#resources-container.viewing-resource #resources-container-content { + display: none; +} + +#resources-summary { + position: absolute; + padding-top: 20px; + top: 0; + left: 0; + right: 0; + height: 93px; + margin-left: -1px; + border-left: 1px solid rgb(102, 102, 102); + background-color: rgb(101, 111, 130); + background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 0)), to(rgba(0, 0, 0, 0.5))); + background-repeat: repeat-x; + background-position: bottom; + text-align: center; + text-shadow: black 0 1px 1px; + white-space: nowrap; + color: white; + -webkit-background-size: 1px 6px; + -webkit-background-origin: padding; + -webkit-background-clip: padding; +} + +#resources-graph-legend { + margin-top: -10px; + padding-left: 15px; +} + +.resources-graph-legend-item { + display: inline-block; + font-weight: bold; + margin-right: 15px; + vertical-align: top; +} + +.resources-graph-legend-item.total { + margin-left: 10px; +} + +.resources-graph-legend-label { + display: inline-block; + text-align: left; +} + +.resources-graph-legend-header { + font-size: 12px; +} + +.resources-graph-legend-value { + font-size: 10px; +} + +.resources-graph-legend-swatch { + vertical-align: top; + margin-top: 1px; + margin-right: 3px; +} + +#resources-dividers { + position: absolute; + left: 0; + right: 0; + height: 100%; + top: 0; + z-index: -100; +} + +#resources-dividers-label-bar { + position: absolute; + top: 93px; + left: 0px; + right: 0; + background-color: rgba(255, 255, 255, 0.8); + background-clip: padding; + border-bottom: 1px solid rgba(0, 0, 0, 0.3); + height: 20px; + z-index: 200; +} + +.resources-divider { + position: absolute; + width: 1px; + top: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.1); +} + +.resources-divider.last { + background-color: transparent; +} + +.resources-divider-label { + position: absolute; + top: 4px; + right: 3px; + font-size: 9px; + color: rgb(50%, 50%, 50%); + white-space: nowrap; +} + +.resources-graph-label { + position: absolute; + top: 0; + bottom: 0; + margin: auto -7px; + height: 13px; + line-height: 13px; + font-size: 9px; + color: rgba(0, 0, 0, 0.75); + text-shadow: rgba(255, 255, 255, 0.25) 1px 0 0, rgba(255, 255, 255, 0.25) -1px 0 0, rgba(255, 255, 255, 0.333) 0 1px 0, rgba(255, 255, 255, 0.25) 0 -1px 0; + z-index: 150; + overflow: hidden; + text-align: center; + font-weight: bold; + opacity: 0; + -webkit-transition: opacity 250ms ease-in-out; +} + +.resources-graph-side:hover .resources-graph-label { + opacity: 1; +} + +.resources-graph-label:empty { + display: none; +} + +.resources-graph-label.waiting { + margin-right: 5px; +} + +.resources-graph-label.before { + color: rgba(0, 0, 0, 0.7); + text-shadow: none; + text-align: right; + margin-right: 2px; +} + +.resources-graph-label.before::after { + padding-left: 2px; + height: 6px; + content: url(Images/graphLabelCalloutLeft.png); +} + +.resources-graph-label.after { + color: rgba(0, 0, 0, 0.7); + text-shadow: none; + text-align: left; + margin-left: 2px; +} + +.resources-graph-label.after::before { + padding-right: 2px; + height: 6px; + content: url(Images/graphLabelCalloutRight.png); +} + +.resources-graph-bar { + position: absolute; + top: 0; + bottom: 0; + margin: auto -7px; + border-width: 6px 7px; + height: 13px; + min-width: 14px; + opacity: 0.65; + -webkit-border-image: url(Images/timelinePillGray.png) 6 7 6 7; +} + +.resources-graph-bar.waiting { + opacity: 0.35; +} + +.resource-cached .resources-graph-bar { + -webkit-border-image: url(Images/timelineHollowPillGray.png) 6 7 6 7; +} + +.resources-category-documents .resources-graph-bar { + -webkit-border-image: url(Images/timelinePillBlue.png) 6 7 6 7; +} + +.resources-category-documents.resource-cached .resources-graph-bar { + -webkit-border-image: url(Images/timelineHollowPillBlue.png) 6 7 6 7; +} + +.resources-category-stylesheets .resources-graph-bar { + -webkit-border-image: url(Images/timelinePillGreen.png) 6 7 6 7; +} + +.resources-category-stylesheets.resource-cached .resources-graph-bar { + -webkit-border-image: url(Images/timelineHollowPillGreen.png) 6 7 6 7; +} + +.resources-category-images .resources-graph-bar { + -webkit-border-image: url(Images/timelinePillPurple.png) 6 7 6 7; +} + +.resources-category-images.resource-cached .resources-graph-bar { + -webkit-border-image: url(Images/timelineHollowPillPurple.png) 6 7 6 7; +} + +.resources-category-fonts .resources-graph-bar { + -webkit-border-image: url(Images/timelinePillRed.png) 6 7 6 7; +} + +.resources-category-fonts.resource-cached .resources-graph-bar { + -webkit-border-image: url(Images/timelineHollowPillRed.png) 6 7 6 7; +} + +.resources-category-scripts .resources-graph-bar { + -webkit-border-image: url(Images/timelinePillOrange.png) 6 7 6 7; +} + +.resources-category-scripts.resource-cached .resources-graph-bar { + -webkit-border-image: url(Images/timelineHollowPillOrange.png) 6 7 6 7; +} + +.resources-category-xhr .resources-graph-bar { + -webkit-border-image: url(Images/timelinePillYellow.png) 6 7 6 7; +} + +.resources-category-xhr.resource-cached .resources-graph-bar { + -webkit-border-image: url(Images/timelineHollowPillYellow.png) 6 7 6 7; +} + +.tip-button { + background-image: url(Images/tipIcon.png); + border: none; + width: 16px; + height: 16px; + float: right; + background-color: transparent; + margin-top: 1px; +} + +.tip-button:active { + background-image: url(Images/tipIconPressed.png); +} + +.tip-balloon { + position: absolute; + left: 145px; + top: -5px; + z-index: 1000; + border-width: 51px 15px 18px 37px; + -webkit-border-image: url(Images/tipBalloon.png) 51 15 18 37; + width: 265px; +} + +.tip-balloon.bottom { + position: absolute; + left: 145px; + top: auto; + bottom: -7px; + z-index: 1000; + border-width: 18px 15px 51px 37px; + -webkit-border-image: url(Images/tipBalloonBottom.png) 18 15 51 37; +} + +.tip-balloon-content { + margin-top: -40px; + margin-bottom: -2px; + margin-left: 2px; +} + +.tip-balloon.bottom .tip-balloon-content { + margin-top: -10px; + margin-bottom: -35px; +} + +#resource-views { + position: absolute; + top: 0; + right: 0; + left: 200px; + bottom: 0; +} + +.source-view-frame { + width: 100%; + height: 100%; +} + +.sidebar-resizer-vertical { + position: absolute; + top: 0; + bottom: 0; + width: 5px; + z-index: 500; + cursor: col-resize; +} + +.sidebar-tree, .sidebar-tree .children { + position: relative; + padding: 0; + margin: 0; + list-style: none; + font-size: 11px; +} + +.sidebar-tree-section { + position: relative; + height: 18px; + padding: 4px 10px 6px 10px; + white-space: nowrap; + margin-top: 1px; + color: rgb(92, 110, 129); + font-weight: bold; + text-shadow: rgba(255, 255, 255, 0.75) 0 1px 0; +} + +.sidebar-tree-item { + position: relative; + height: 36px; + padding: 0 5px 0 5px; + white-space: nowrap; + margin-top: 1px; + line-height: 34px; + border-top: 1px solid transparent; +} + +.sidebar-tree .children { + display: none; +} + +.sidebar-tree .children.expanded { + display: block; +} + +.sidebar-tree-section + .children > .sidebar-tree-item { + padding-left: 10px !important; +} + +.sidebar-tree-section + .children.small > .sidebar-tree-item { + padding-left: 17px !important; +} + +.sidebar-tree > .children > .sidebar-tree-item { + padding-left: 37px; +} + +.sidebar-tree > .children > .children > .sidebar-tree-item { + padding-left: 37px; +} + +.sidebar-tree.hide-disclosure-buttons > .children { + display: none; +} + +.sidebar-tree > .children.hide-disclosure-buttons > .children { + display: none; +} + +.sidebar-tree.some-expandable:not(.hide-disclosure-buttons) > .sidebar-tree-item:not(.parent) .icon { + margin-left: 16px; +} + +.sidebar-tree-item .disclosure-button { + float: left; + width: 16px; + height: 100%; + border: 0; + background-color: transparent; + background-image: url(Images/disclosureTriangleSmallRight.png); + background-repeat: no-repeat; + background-position: center; + -webkit-apearance: none; +} + +.sidebar-tree.hide-disclosure-buttons .sidebar-tree-item .disclosure-button { + display: none; +} + +body.inactive .sidebar-tree-item .disclosure-button { + background-image: url(Images/disclosureTriangleSmallRightBlack.png); +} + +body.inactive .sidebar-tree-item.expanded .disclosure-button { + background-image: url(Images/disclosureTriangleSmallDownBlack.png); +} + +body.inactive .sidebar-tree-item .disclosure-button:active { + background-image: url(Images/disclosureTriangleSmallRightDownBlack.png); +} + +.sidebar-tree-item.selected .disclosure-button { + background-image: url(Images/disclosureTriangleSmallRightWhite.png) !important; +} + +.sidebar-tree-item.expanded .disclosure-button { + background-image: url(Images/disclosureTriangleSmallDown.png); +} + +.sidebar-tree-item.selected.expanded .disclosure-button { + background-image: url(Images/disclosureTriangleSmallDownWhite.png) !important; +} + +.sidebar-tree-item.selected .disclosure-button:active { + background-image: url(Images/disclosureTriangleSmallRightDownWhite.png) !important; +} + +.sidebar-tree-item .disclosure-button:active { + background-image: url(Images/disclosureTriangleSmallRightDown.png); +} + +.sidebar-tree-item .icon { + float: left; + width: 32px; + height: 32px; + margin-top: 1px; + margin-right: 3px; +} + +.sidebar-tree-item .status { + float: right; + height: 16px; + margin-top: 9px; + margin-left: 4px; + line-height: 1em; +} + +.sidebar-tree-item .status:empty { + display: none; +} + +.sidebar-tree-item .status .bubble { + display: inline-block; + height: 14px; + min-width: 16px; + margin-top: 1px; + background-color: rgb(128, 151, 189); + vertical-align: middle; + white-space: nowrap; + padding: 1px 4px; + text-align: center; + font-size: 11px; + font-family: Helvetia, Arial, sans-serif; + font-weight: bold; + text-shadow: none; + color: white; + -webkit-border-radius: 7px; +} + +.sidebar-tree-item .status .bubble:empty { + display: none; +} + +.sidebar-tree-item.selected .status .bubble { + background-color: white !important; + color: rgb(132, 154, 190) !important; +} + +:focus .sidebar-tree-item.selected .status .bubble { + color: rgb(36, 98, 172) !important; +} + +body.inactive .sidebar-tree-item.selected .status .bubble { + color: rgb(159, 159, 159) !important; +} + +.sidebar-tree.small .sidebar-tree-item, .sidebar-tree .children.small .sidebar-tree-item, .sidebar-tree-item.small, .small .resources-graph-side { + height: 20px; +} + +.sidebar-tree.small .sidebar-tree-item .icon, .sidebar-tree .children.small .sidebar-tree-item .icon, .sidebar-tree-item.small .icon { + width: 16px; + height: 16px; +} + +.sidebar-tree.small .sidebar-tree-item .status, .sidebar-tree .children.small .sidebar-tree-item .status, .sidebar-tree-item.small .status { + margin-top: 1px; +} + +.sidebar-tree-item.selected { + color: white; + border-top: 1px solid rgb(145, 160, 192); + background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(162, 177, 207)), to(rgb(120, 138, 177))); + text-shadow: rgba(0, 0, 0, 0.33) 0 1px 0; + font-weight: bold; + -webkit-background-origin: padding; + -webkit-background-clip: padding; +} + +:focus .sidebar-tree-item.selected { + border-top: 1px solid rgb(68, 128, 200); + background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(92, 147, 213)), to(rgb(21, 83, 170))); +} + +body.inactive .sidebar-tree-item.selected { + border-top: 1px solid rgb(151, 151, 151); + background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(180, 180, 180)), to(rgb(138, 138, 138))); +} + +.sidebar-tree-item .titles { + position: relative; + top: 5px; + line-height: 11px; + padding-bottom: 1px; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; +} + +.sidebar-tree-item .titles.no-subtitle { + top: 10px; +} + +.sidebar-tree.small .sidebar-tree-item .titles, .sidebar-tree .children.small .sidebar-tree-item .titles, .sidebar-tree-item.small .titles { + top: 2px; + line-height: normal; +} + +.sidebar-tree:not(.small) .sidebar-tree-item:not(.small) .title::after, .sidebar-tree .children:not(.small) .sidebar-tree-item .title::after { + content: "\A"; + white-space: pre; +} + +.sidebar-tree-item .subtitle { + font-size: 9px; + color: rgba(0, 0, 0, 0.7); +} + +.sidebar-tree.small .sidebar-tree-item .subtitle, .sidebar-tree .children.small .sidebar-tree-item .subtitle, .sidebar-tree-item.small .subtitle { + display: none; +} + +.sidebar-tree-item.selected .subtitle { + color: rgba(255, 255, 255, 0.9); +} + +#resources-graphs { + position: absolute; + left: 0; + right: 0; + max-height: 100%; + top: 112px; +} + +.resources-graph-side { + position: relative; + height: 36px; + padding: 0 5px; + white-space: nowrap; + margin-top: 1px; + border-top: 1px solid transparent; + overflow: hidden; +} + +.resources-graph-bar-area { + position: absolute; + top: 0; + bottom: 0; + right: 8px; + left: 9px; +} + +#resources-container:not(.viewing-resource) .resource-sidebar-tree-item:nth-of-type(2n) { + background-color: rgba(0, 0, 0, 0.05); +} + +#resources-container:not(.viewing-resource) .resources-graph-side:nth-of-type(2n) { + background-color: rgba(0, 0, 0, 0.05); +} + +.resources-time-graph-sidebar-item .icon { + content: url(Images/resourcesTimeGraphIcon.png); +} + +.resources-size-graph-sidebar-item .icon { + content: url(Images/resourcesSizeGraphIcon.png); +} + +.resources-size-graph-sidebar-item .icon { + content: url(Images/resourcesSizeGraphIcon.png); +} + +.resource-sidebar-tree-item .icon { + content: url(Images/resourcePlainIcon.png); +} + +.children.small .resource-sidebar-tree-item .icon { + content: url(Images/resourcePlainIconSmall.png); +} + +.resource-sidebar-tree-item.resources-category-documents .icon { + content: url(Images/resourceDocumentIcon.png); +} + +.children.small .resource-sidebar-tree-item.resources-category-documents .icon { + content: url(Images/resourceDocumentIconSmall.png); +} + +.resource-sidebar-tree-item.resources-category-stylesheets .icon { + content: url(Images/resourceCSSIcon.png); +} + +.children.small .resource-sidebar-tree-item.resources-category-stylesheets .icon { + content: url(Images/resourceDocumentIconSmall.png); +} + +.resource-sidebar-tree-item.resources-category-images .icon { + position: relative; + background-image: url(Images/resourcePlainIcon.png); + background-repeat: no-repeat; + content: ""; +} + +.resource-sidebar-tree-item.resources-category-images .image-resource-icon-preview { + position: absolute; + margin: auto; + top: 3px; + bottom: 4px; + left: 5px; + right: 5px; + max-width: 18px; + max-height: 21px; + min-width: 1px; + min-height: 1px; +} + +.children.small .resource-sidebar-tree-item.resources-category-images .icon { + background-image: url(Images/resourcePlainIconSmall.png); + content: ""; +} + +.children.small .resource-sidebar-tree-item.resources-category-images .image-resource-icon-preview { + top: 2px; + bottom: 1px; + left: 3px; + right: 3px; + max-width: 8px; + max-height: 11px; +} + +.resource-sidebar-tree-item.resources-category-fonts .icon { + content: url(Images/resourcePlainIcon.png); +} + +.children.small .resource-sidebar-tree-item.resources-category-fonts .icon { + content: url(Images/resourcePlainIconSmall.png); +} + +.resource-sidebar-tree-item.resources-category-scripts .icon { + content: url(Images/resourceJSIcon.png); +} + +.children.small .resource-sidebar-tree-item.resources-category-scripts .icon { + content: url(Images/resourceDocumentIconSmall.png); +} + +.resource-sidebar-tree-item.resources-category-xhr .icon { + content: url(Images/resourcePlainIcon.png); +} + +.children.small .resource-sidebar-tree-item.resources-category-xhr .icon { + content: url(Images/resourceDocumentIconSmall.png); +} + +.bubble.warning, .console-warning-level .bubble { + background-color: rgb(232, 164, 0) !important; +} + +.bubble.error, .console-error-level .bubble { + background-color: rgb(216, 35, 35) !important; +} + +.bubble.search-matches { + background-image: url(Images/searchSmallWhite.png); + background-repeat: no-repeat; + background-position: 3px 2px; + padding-left: 13px !important; +} + +.sidebar-tree-item.selected .bubble.search-matches { + background-image: url(Images/searchSmallBlue.png); +} + +:focus .sidebar-tree-item.selected .bubble.search-matches { + background-image: url(Images/searchSmallBrightBlue.png); +} + +body.inactive .sidebar-tree-item.selected .bubble.search-matches { + background-image: url(Images/searchSmallGray.png); +} + +/* Profiler Style */ + +#profile-views { + position: absolute; + top: 0; + right: 0; + left: 200px; + bottom: 0; +} + +#profile-view-status-bar-items { + position: absolute; + top: 0; + bottom: 0; + left: 200px; + overflow: hidden; + border-left: 1px solid rgb(184, 184, 184); + margin-left: -1px; +} + +.profile-sidebar-tree-item .icon { + content: url(Images/profileIcon.png); +} + +.profile-sidebar-tree-item.small .icon { + content: url(Images/profileSmallIcon.png); +} + +.profile-group-sidebar-tree-item .icon { + content: url(Images/profileGroupIcon.png); +} + +.profile-view { + display: none; + overflow: hidden; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; +} + +.profile-view.visible { + display: block; +} + +.profile-view .data-grid { + border: none; + height: 100%; +} + +.profile-view .data-grid th.average-column { + text-align: center; +} + +.profile-view .data-grid td.average-column { + text-align: right; +} + +.profile-view .data-grid th.self-column { + text-align: center; +} + +.profile-view .data-grid td.self-column { + text-align: right; +} + +.profile-view .data-grid th.total-column { + text-align: center; +} + +.profile-view .data-grid td.total-column { + text-align: right; +} + +.profile-view .data-grid .calls-column { + text-align: center; +} + +.profile-node-file { + float: right; + color: gray; + margin-top: -1px; +} + +.data-grid tr.selected .profile-node-file { + color: rgb(33%, 33%, 33%); +} + +.data-grid:focus tr.selected .profile-node-file { + color: white; +} + +#record-profile-status-bar-item { + background-image: url(Images/recordButtons.png); +} + +#record-profile-status-bar-item:active { + background-position: 32px 0; +} + +#record-profile-status-bar-item.toggled-on { + background-position: 0 24px; +} + +#record-profile-status-bar-item.toggled-on:active { + background-position: 32px 24px; +} + +#node-search-status-bar-item { + background-image: url(Images/nodeSearchButtons.png); +} + +#node-search-status-bar-item:active { + background-position: 32px 0; +} + +#node-search-status-bar-item.toggled-on { + background-position: 0 24px; +} + +#node-search-status-bar-item.toggled-on:active { + background-position: 32px 24px; +} + +.percent-time-status-bar-item { + background-image: url(Images/percentButtons.png) !important; +} + +.percent-time-status-bar-item:active { + background-position: 32px 0; +} + +.percent-time-status-bar-item.toggled-on { + background-position: 0 24px; +} + +.percent-time-status-bar-item.toggled-on:active { + background-position: 32px 24px; +} + +.focus-profile-node-status-bar-item { + background-image: url(Images/focusButtons.png) !important; +} + +.focus-profile-node-status-bar-item:active { + background-position: 32px 0; +} + +.exclude-profile-node-status-bar-item { + background-image: url(Images/excludeButtons.png) !important; +} + +.exclude-profile-node-status-bar-item:active { + background-position: 32px 0; +} + +.reset-profile-status-bar-item { + background-image: url(Images/reloadButtons.png) !important; +} + +.reset-profile-status-bar-item:active { + background-position: 32px 0; +} + +.delete-storage-status-bar-item { + background-image: url(Images/excludeButtons.png) !important; +} + +.delete-storage-status-bar-item:active { + background-position: 32px 0; +} + +#storage-view-status-bar-items { + position: absolute; + top: 0; + bottom: 0; + left: 200px; + overflow: hidden; + border-left: 1px solid rgb(184, 184, 184); + margin-left: -1px; +} + +.refresh-storage-status-bar-item { + background-image: url(Images/reloadButtons.png) !important; +} + +.refresh-storage-status-bar-item:active { + background-position: 32px 0; +} + +#storage-view-status-bar-items { + position: absolute; + top: 0; + bottom: 0; + left: 200px; + overflow: hidden; + border-left: 1px solid rgb(184, 184, 184); + margin-left: -1px; +} diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/inspector.html b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/inspector.html new file mode 100644 index 0000000..184bb45 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/inspector.html @@ -0,0 +1,97 @@ +<!-- +Copyright (C) 2006, 2007, 2008 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. +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. +--> +<!DOCTYPE html> +<html> +<head> + <meta http-equiv="content-type" content="text/html; charset=utf-8"> + <link rel="stylesheet" type="text/css" href="inspector.css"> + <script type="text/javascript" src="utilities.js"></script> + <script type="text/javascript" src="treeoutline.js"></script> + <script type="text/javascript" src="inspector.js"></script> + <script type="text/javascript" src="Object.js"></script> + <script type="text/javascript" src="TextPrompt.js"></script> + <script type="text/javascript" src="Placard.js"></script> + <script type="text/javascript" src="View.js"></script> + <script type="text/javascript" src="Console.js"></script> + <script type="text/javascript" src="Resource.js"></script> + <script type="text/javascript" src="ResourceCategory.js"></script> + <script type="text/javascript" src="Database.js"></script> + <script type="text/javascript" src="DOMStorage.js"></script> + <script type="text/javascript" src="DOMStorageItemsView.js"></script> + <script type="text/javascript" src="DataGrid.js"></script> + <script type="text/javascript" src="DOMStorageDataGrid.js"></script> + <script type="text/javascript" src="Script.js"></script> + <script type="text/javascript" src="Breakpoint.js"></script> + <script type="text/javascript" src="SidebarPane.js"></script> + <script type="text/javascript" src="ElementsTreeOutline.js"></script> + <script type="text/javascript" src="SidebarTreeElement.js"></script> + <script type="text/javascript" src="PropertiesSection.js"></script> + <script type="text/javascript" src="ObjectPropertiesSection.js"></script> + <script type="text/javascript" src="BreakpointsSidebarPane.js"></script> + <script type="text/javascript" src="CallStackSidebarPane.js"></script> + <script type="text/javascript" src="ScopeChainSidebarPane.js"></script> + <script type="text/javascript" src="MetricsSidebarPane.js"></script> + <script type="text/javascript" src="PropertiesSidebarPane.js"></script> + <script type="text/javascript" src="StylesSidebarPane.js"></script> + <script type="text/javascript" src="Panel.js"></script> + <script type="text/javascript" src="PanelEnablerView.js"></script> + <script type="text/javascript" src="ElementsPanel.js"></script> + <script type="text/javascript" src="ResourcesPanel.js"></script> + <script type="text/javascript" src="ScriptsPanel.js"></script> + <script type="text/javascript" src="DatabasesPanel.js"></script> + <script type="text/javascript" src="ProfilesPanel.js"></script> + <script type="text/javascript" src="ResourceView.js"></script> + <script type="text/javascript" src="SourceFrame.js"></script> + <script type="text/javascript" src="SourceView.js"></script> + <script type="text/javascript" src="FontView.js"></script> + <script type="text/javascript" src="ImageView.js"></script> + <script type="text/javascript" src="DatabaseTableView.js"></script> + <script type="text/javascript" src="DatabaseQueryView.js"></script> + <script type="text/javascript" src="ScriptView.js"></script> + <script type="text/javascript" src="ProfileDataGridTree.js"></script> + <script type="text/javascript" src="BottomUpProfileDataGridTree.js"></script> + <script type="text/javascript" src="TopDownProfileDataGridTree.js"></script> + <script type="text/javascript" src="ProfileView.js"></script> +</head> +<body class="detached"> + <div id="toolbar"> + <div class="toolbar-item close"><button id="close-button"></button></div> + <div class="toolbar-item flexable-space"></div> + <div class="toolbar-item hidden" id="search-results-matches"></div> + <div class="toolbar-item"><input id="search" type="search" incremental results="0"><div id="search-toolbar-label" class="toolbar-label"></div></div> + </div> + <div id="main"> + <div id="main-panels" tabindex="0"></div> + <div id="main-status-bar" class="status-bar"><div id="anchored-status-bar-items"><button id="dock-status-bar-item" class="status-bar-item toggled"></button><button id="console-status-bar-item" class="status-bar-item"></button><div id="error-warning-count" class="hidden"></div></div></div> + </div> + <div id="console"> + <div id="console-messages"><div id="console-prompt"><br></div></div> + <div id="console-status-bar" class="status-bar"><div id="other-console-status-bar-items"><button id="clear-console-status-bar-item" class="status-bar-item"></button></div></div> + </div> +</body> +</html> diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/inspector.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/inspector.js new file mode 100644 index 0000000..633dee5 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/inspector.js @@ -0,0 +1,1283 @@ +/* + * Copyright (C) 2006, 2007, 2008 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, + minConsoleHeight: 75, + minSidebarWidth: 100, + minElementsSidebarWidth: 200, + minScriptsSidebarWidth: 200, + showInheritedComputedStyleProperties: false, + styleRulesExpandedState: {}, + showMissingLocalizedStrings: false +} + +var WebInspector = { + resources: [], + resourceURLMap: {}, + missingLocalizedStrings: {}, + + get previousFocusElement() + { + return this._previousFocusElement; + }, + + get currentFocusElement() + { + return this._currentFocusElement; + }, + + set currentFocusElement(x) + { + if (this._currentFocusElement !== x) + this._previousFocusElement = this._currentFocusElement; + this._currentFocusElement = x; + + if (this._currentFocusElement) { + this._currentFocusElement.focus(); + + // Make a caret selection inside the new element if there isn't a range selection and + // there isn't already a caret selection inside. + var selection = window.getSelection(); + if (selection.isCollapsed && !this._currentFocusElement.isInsertionCaretInside()) { + var selectionRange = document.createRange(); + selectionRange.setStart(this._currentFocusElement, 0); + selectionRange.setEnd(this._currentFocusElement, 0); + + selection.removeAllRanges(); + selection.addRange(selectionRange); + } + } else if (this._previousFocusElement) + this._previousFocusElement.blur(); + }, + + get currentPanel() + { + return this._currentPanel; + }, + + set currentPanel(x) + { + if (this._currentPanel === x) + return; + + if (this._currentPanel) + this._currentPanel.hide(); + + this._currentPanel = x; + + this.updateSearchLabel(); + + if (x) { + x.show(); + + if (this.currentQuery) { + if (x.performSearch) { + function performPanelSearch() + { + this.updateSearchMatchesCount(); + + x.currentQuery = this.currentQuery; + x.performSearch(this.currentQuery); + } + + // Perform the search on a timeout so the panel switches fast. + setTimeout(performPanelSearch.bind(this), 0); + } else { + // Update to show Not found for panels that can't be searched. + this.updateSearchMatchesCount(); + } + } + } + }, + + get attached() + { + return this._attached; + }, + + set attached(x) + { + if (this._attached === x) + return; + + this._attached = x; + + this.updateSearchLabel(); + + var dockToggleButton = document.getElementById("dock-status-bar-item"); + var body = document.body; + + if (x) { + InspectorController.attach(); + body.removeStyleClass("detached"); + body.addStyleClass("attached"); + dockToggleButton.title = WebInspector.UIString("Undock into separate window."); + } else { + InspectorController.detach(); + body.removeStyleClass("attached"); + body.addStyleClass("detached"); + dockToggleButton.title = WebInspector.UIString("Dock to main window."); + } + }, + + get errors() + { + return this._errors || 0; + }, + + set errors(x) + { + x = Math.max(x, 0); + + if (this._errors === x) + return; + this._errors = x; + this._updateErrorAndWarningCounts(); + }, + + get warnings() + { + return this._warnings || 0; + }, + + set warnings(x) + { + x = Math.max(x, 0); + + if (this._warnings === x) + return; + this._warnings = x; + this._updateErrorAndWarningCounts(); + }, + + _updateErrorAndWarningCounts: function() + { + var errorWarningElement = document.getElementById("error-warning-count"); + if (!errorWarningElement) + return; + + if (!this.errors && !this.warnings) { + errorWarningElement.addStyleClass("hidden"); + return; + } + + errorWarningElement.removeStyleClass("hidden"); + + errorWarningElement.removeChildren(); + + if (this.errors) { + var errorElement = document.createElement("span"); + errorElement.id = "error-count"; + errorElement.textContent = this.errors; + errorWarningElement.appendChild(errorElement); + } + + if (this.warnings) { + var warningsElement = document.createElement("span"); + warningsElement.id = "warning-count"; + warningsElement.textContent = this.warnings; + errorWarningElement.appendChild(warningsElement); + } + + if (this.errors) { + if (this.warnings) { + if (this.errors == 1) { + if (this.warnings == 1) + errorWarningElement.title = WebInspector.UIString("%d error, %d warning", this.errors, this.warnings); + else + errorWarningElement.title = WebInspector.UIString("%d error, %d warnings", this.errors, this.warnings); + } else if (this.warnings == 1) + errorWarningElement.title = WebInspector.UIString("%d errors, %d warning", this.errors, this.warnings); + else + errorWarningElement.title = WebInspector.UIString("%d errors, %d warnings", this.errors, this.warnings); + } else if (this.errors == 1) + errorWarningElement.title = WebInspector.UIString("%d error", this.errors); + else + errorWarningElement.title = WebInspector.UIString("%d errors", this.errors); + } else if (this.warnings == 1) + errorWarningElement.title = WebInspector.UIString("%d warning", this.warnings); + else if (this.warnings) + errorWarningElement.title = WebInspector.UIString("%d warnings", this.warnings); + else + errorWarningElement.title = null; + }, + + get hoveredDOMNode() + { + return this._hoveredDOMNode; + }, + + set hoveredDOMNode(x) + { + if (objectsAreSame(this._hoveredDOMNode, x)) + return; + + this._hoveredDOMNode = x; + + if (this._hoveredDOMNode) + this._updateHoverHighlightSoon(this.showingDOMNodeHighlight ? 50 : 500); + else + this._updateHoverHighlight(); + }, + + _updateHoverHighlightSoon: function(delay) + { + if ("_updateHoverHighlightTimeout" in this) + clearTimeout(this._updateHoverHighlightTimeout); + this._updateHoverHighlightTimeout = setTimeout(this._updateHoverHighlight.bind(this), delay); + }, + + _updateHoverHighlight: function() + { + if ("_updateHoverHighlightTimeout" in this) { + clearTimeout(this._updateHoverHighlightTimeout); + delete this._updateHoverHighlightTimeout; + } + + if (this._hoveredDOMNode) { + InspectorController.highlightDOMNode(this._hoveredDOMNode); + this.showingDOMNodeHighlight = true; + } else { + InspectorController.hideDOMNodeHighlight(); + this.showingDOMNodeHighlight = false; + } + } +} + +WebInspector.loaded = function() +{ + var platform = InspectorController.platform(); + document.body.addStyleClass("platform-" + platform); + + this.console = new WebInspector.Console(); + + this.panels = {}; + var hiddenPanels = (InspectorController.hiddenPanels() || "").split(','); + if (hiddenPanels.indexOf("elements") === -1) + this.panels.elements = new WebInspector.ElementsPanel(); + if (hiddenPanels.indexOf("resources") === -1) + this.panels.resources = new WebInspector.ResourcesPanel(); + if (hiddenPanels.indexOf("scripts") === -1) + this.panels.scripts = new WebInspector.ScriptsPanel(); + if (hiddenPanels.indexOf("profiles") === -1) + this.panels.profiles = new WebInspector.ProfilesPanel(); + if (hiddenPanels.indexOf("databases") === -1) + this.panels.databases = new WebInspector.DatabasesPanel(); + + var toolbarElement = document.getElementById("toolbar"); + var previousToolbarItem = toolbarElement.children[0]; + + for (var panelName in this.panels) { + var panel = this.panels[panelName]; + var panelToolbarItem = panel.toolbarItem; + panelToolbarItem.addEventListener("click", this._toolbarItemClicked.bind(this)); + if (previousToolbarItem) + toolbarElement.insertBefore(panelToolbarItem, previousToolbarItem.nextSibling); + else + toolbarElement.insertBefore(panelToolbarItem, toolbarElement.firstChild); + previousToolbarItem = panelToolbarItem; + } + + this.currentPanel = this.panels.elements; + + 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"), + xhr: new WebInspector.ResourceCategory(WebInspector.UIString("XHR"), "xhr"), + fonts: new WebInspector.ResourceCategory(WebInspector.UIString("Fonts"), "fonts"), + 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.addMainEventListeners(document); + + window.addEventListener("unload", this.windowUnload.bind(this), true); + window.addEventListener("resize", this.windowResize.bind(this), true); + + document.addEventListener("focus", this.focusChanged.bind(this), true); + document.addEventListener("keydown", this.documentKeyDown.bind(this), true); + document.addEventListener("keyup", this.documentKeyUp.bind(this), true); + document.addEventListener("beforecopy", this.documentCanCopy.bind(this), true); + document.addEventListener("copy", this.documentCopy.bind(this), true); + + var mainPanelsElement = document.getElementById("main-panels"); + mainPanelsElement.handleKeyEvent = this.mainKeyDown.bind(this); + mainPanelsElement.handleKeyUpEvent = this.mainKeyUp.bind(this); + mainPanelsElement.handleCopyEvent = this.mainCopy.bind(this); + + // Focus the mainPanelsElement in a timeout so it happens after the initial focus, + // so it doesn't get reset to the first toolbar button. This initial focus happens + // on Mac when the window is made key and the WebHTMLView becomes the first responder. + setTimeout(function() { WebInspector.currentFocusElement = mainPanelsElement }, 0); + + var dockToggleButton = document.getElementById("dock-status-bar-item"); + dockToggleButton.addEventListener("click", this.toggleAttach.bind(this), false); + + if (this.attached) + dockToggleButton.title = WebInspector.UIString("Undock into separate window."); + else + dockToggleButton.title = WebInspector.UIString("Dock to main window."); + + var errorWarningCount = document.getElementById("error-warning-count"); + errorWarningCount.addEventListener("click", this.console.show.bind(this.console), false); + this._updateErrorAndWarningCounts(); + + var searchField = document.getElementById("search"); + searchField.addEventListener("keydown", this.searchKeyDown.bind(this), false); + searchField.addEventListener("keyup", this.searchKeyUp.bind(this), false); + searchField.addEventListener("search", this.performSearch.bind(this), false); // when the search is emptied + + document.getElementById("toolbar").addEventListener("mousedown", this.toolbarDragStart, true); + document.getElementById("close-button").addEventListener("click", this.close, true); + + 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.focusChanged = function(event) +{ + this.currentFocusElement = event.target; +} + +WebInspector.setAttachedWindow = function(attached) +{ + this.attached = attached; +} + +WebInspector.close = function(event) +{ + InspectorController.closeWindow(); +} + +WebInspector.documentClick = function(event) +{ + var anchor = event.target.enclosingNodeOrSelfWithNodeName("a"); + if (!anchor) + return; + + // Prevent the link from navigating, since we don't do any navigation by following links normally. + event.preventDefault(); + + function followLink() + { + // FIXME: support webkit-html-external-link links here. + if (anchor.href in WebInspector.resourceURLMap) { + if (anchor.hasStyleClass("webkit-html-external-link")) { + anchor.removeStyleClass("webkit-html-external-link"); + anchor.addStyleClass("webkit-html-resource-link"); + } + + WebInspector.showResourceForURL(anchor.href, anchor.lineNumber, anchor.preferredPanel); + } else { + var profileStringRegEx = new RegExp("webkit-profile://.+/([0-9]+)"); + var profileString = profileStringRegEx.exec(anchor.href); + if (profileString) + WebInspector.showProfileById(profileString[1]) + } + } + + if (WebInspector.followLinkTimeout) + clearTimeout(WebInspector.followLinkTimeout); + + if (anchor.preventFollowOnDoubleClick) { + // Start a timeout if this is the first click, if the timeout is canceled + // before it fires, then a double clicked happened or another link was clicked. + if (event.detail === 1) + WebInspector.followLinkTimeout = setTimeout(followLink, 333); + return; + } + + followLink(); +} + +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); + + if (!event.handled) { + var isMac = InspectorController.platform().indexOf("mac-") === 0; + + switch (event.keyIdentifier) { + case "U+001B": // Escape key + this.console.visible = !this.console.visible; + event.preventDefault(); + break; + + case "U+0046": // F key + if (isMac) + var isFindKey = event.metaKey && !event.ctrlKey && !event.altKey && !event.shiftKey; + else + var isFindKey = event.ctrlKey && !event.metaKey && !event.altKey && !event.shiftKey; + + if (isFindKey) { + var searchField = document.getElementById("search"); + searchField.focus(); + searchField.select(); + event.preventDefault(); + } + + break; + + case "U+0047": // G key + if (isMac) + var isFindAgainKey = event.metaKey && !event.ctrlKey && !event.altKey; + else + var isFindAgainKey = event.ctrlKey && !event.metaKey && !event.altKey; + + if (isFindAgainKey) { + if (event.shiftKey) { + if (this.currentPanel.jumpToPreviousSearchResult) + this.currentPanel.jumpToPreviousSearchResult(); + } else if (this.currentPanel.jumpToNextSearchResult) + this.currentPanel.jumpToNextSearchResult(); + event.preventDefault(); + } + + break; + } + } +} + +WebInspector.documentKeyUp = function(event) +{ + if (!this.currentFocusElement || !this.currentFocusElement.handleKeyUpEvent) + return; + this.currentFocusElement.handleKeyUpEvent(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.mainKeyDown = function(event) +{ + if (this.currentPanel && this.currentPanel.handleKeyEvent) + this.currentPanel.handleKeyEvent(event); +} + +WebInspector.mainKeyUp = function(event) +{ + if (this.currentPanel && this.currentPanel.handleKeyUpEvent) + this.currentPanel.handleKeyUpEvent(event); +} + +WebInspector.mainCopy = function(event) +{ + if (this.currentPanel && this.currentPanel.handleCopyEvent) + this.currentPanel.handleCopyEvent(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.updateSearchLabel = function() +{ + if (!this.currentPanel) + return; + + var newLabel = WebInspector.UIString("Search %s", this.currentPanel.toolbarItemLabel); + if (this.attached) + document.getElementById("search").setAttribute("placeholder", newLabel); + else { + document.getElementById("search").removeAttribute("placeholder"); + document.getElementById("search-toolbar-label").textContent = newLabel; + } +} + +WebInspector.toggleAttach = function() +{ + this.attached = !this.attached; +} + +WebInspector.toolbarDragStart = function(event) +{ + if (!WebInspector.attached && InspectorController.platform() !== "mac-leopard") + return; + + var target = event.target; + if (target.hasStyleClass("toolbar-item") && target.hasStyleClass("toggleable")) + return; + + var toolbar = document.getElementById("toolbar"); + if (target !== toolbar && !target.hasStyleClass("toolbar-item")) + return; + + toolbar.lastScreenX = event.screenX; + toolbar.lastScreenY = event.screenY; + + WebInspector.elementDragStart(toolbar, WebInspector.toolbarDrag, WebInspector.toolbarDragEnd, event, (WebInspector.attached ? "row-resize" : "default")); +} + +WebInspector.toolbarDragEnd = function(event) +{ + var toolbar = document.getElementById("toolbar"); + + WebInspector.elementDragEnd(event); + + delete toolbar.lastScreenX; + delete toolbar.lastScreenY; +} + +WebInspector.toolbarDrag = function(event) +{ + var toolbar = document.getElementById("toolbar"); + + if (WebInspector.attached) { + var height = window.innerHeight - (event.screenY - toolbar.lastScreenY); + + InspectorController.setAttachedWindowHeight(height); + } else { + var x = event.screenX - toolbar.lastScreenX; + var y = event.screenY - toolbar.lastScreenY; + + // We cannot call window.moveBy here because it restricts the movement + // of the window at the edges. + InspectorController.moveByUnrestricted(x, y); + } + + toolbar.lastScreenX = event.screenX; + toolbar.lastScreenY = event.screenY; + + event.preventDefault(); +} + +WebInspector.elementDragStart = function(element, dividerDrag, elementDragEnd, event, cursor) +{ + if (this._elementDraggingEventListener || this._elementEndDraggingEventListener) + this.elementDragEnd(event); + + this._elementDraggingEventListener = dividerDrag; + this._elementEndDraggingEventListener = elementDragEnd; + + document.addEventListener("mousemove", dividerDrag, true); + document.addEventListener("mouseup", elementDragEnd, true); + + document.body.style.cursor = cursor; + + event.preventDefault(); +} + +WebInspector.elementDragEnd = function(event) +{ + document.removeEventListener("mousemove", this._elementDraggingEventListener, true); + document.removeEventListener("mouseup", this._elementEndDraggingEventListener, true); + + document.body.style.removeProperty("cursor"); + + delete this._elementDraggingEventListener; + delete this._elementEndDraggingEventListener; + + event.preventDefault(); +} + +WebInspector.showConsole = function() +{ + this.console.show(); +} + +WebInspector.showElementsPanel = function() +{ + this.currentPanel = this.panels.elements; +} + +WebInspector.showResourcesPanel = function() +{ + this.currentPanel = this.panels.resources; +} + +WebInspector.showScriptsPanel = function() +{ + this.currentPanel = this.panels.scripts; +} + +WebInspector.showProfilesPanel = function() +{ + this.currentPanel = this.panels.profiles; +} + +WebInspector.showDatabasesPanel = function() +{ + this.currentPanel = this.panels.databases; +} + +WebInspector.addResource = function(resource) +{ + this.resources.push(resource); + this.resourceURLMap[resource.url] = resource; + + if (resource.mainResource) { + this.mainResource = resource; + this.panels.elements.reset(); + } + + if (this.panels.resources) + this.panels.resources.addResource(resource); +} + +WebInspector.removeResource = function(resource) +{ + resource.category.removeResource(resource); + delete this.resourceURLMap[resource.url]; + + this.resources.remove(resource, true); + + if (this.panels.resources) + this.panels.resources.removeResource(resource); +} + +WebInspector.addDatabase = function(database) +{ + this.panels.databases.addDatabase(database); +} + +WebInspector.addDOMStorage = function(domStorage) +{ + this.panels.databases.addDOMStorage(domStorage); +} + +WebInspector.debuggerWasEnabled = function() +{ + this.panels.scripts.debuggerWasEnabled(); +} + +WebInspector.debuggerWasDisabled = function() +{ + this.panels.scripts.debuggerWasDisabled(); +} + +WebInspector.profilerWasEnabled = function() +{ + this.panels.profiles.profilerWasEnabled(); +} + +WebInspector.profilerWasDisabled = function() +{ + this.panels.profiles.profilerWasDisabled(); +} + +WebInspector.parsedScriptSource = function(sourceID, sourceURL, source, startingLine) +{ + this.panels.scripts.addScript(sourceID, sourceURL, source, startingLine); +} + +WebInspector.failedToParseScriptSource = function(sourceURL, source, startingLine, errorLine, errorMessage) +{ + this.panels.scripts.addScript(null, sourceURL, source, startingLine, errorLine, errorMessage); +} + +WebInspector.pausedScript = function() +{ + this.panels.scripts.debuggerPaused(); +} + +WebInspector.resumedScript = function() +{ + this.panels.scripts.debuggerResumed(); +} + +WebInspector.populateInterface = function() +{ + for (var panelName in this.panels) { + var panel = this.panels[panelName]; + if ("populateInterface" in panel) + panel.populateInterface(); + } +} + +WebInspector.reset = function() +{ + for (var panelName in this.panels) { + var panel = this.panels[panelName]; + if ("reset" in panel) + panel.reset(); + } + + for (var category in this.resourceCategories) + this.resourceCategories[category].removeAllResources(); + + this.resources = []; + this.resourceURLMap = {}; + this.hoveredDOMNode = null; + + delete this.mainResource; + + this.console.clearMessages(); +} + +WebInspector.inspectedWindowCleared = function(inspectedWindow) +{ + this.panels.elements.inspectedWindowCleared(inspectedWindow); +} + +WebInspector.resourceURLChanged = function(resource, oldURL) +{ + delete this.resourceURLMap[oldURL]; + this.resourceURLMap[resource.url] = resource; +} + +WebInspector.addMessageToConsole = function(msg) +{ + this.console.addMessage(msg); +} + +WebInspector.addProfile = function(profile) +{ + this.panels.profiles.addProfile(profile); +} + +WebInspector.setRecordingProfile = function(isProfiling) +{ + this.panels.profiles.setRecordingProfile(isProfiling); +} + +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; + + this.currentPanel = this.panels.elements; + this.panels.elements.focusedDOMNode = node; +} + +WebInspector.displayNameForURL = function(url) +{ + if (!url) + return ""; + var resource = this.resourceURLMap[url]; + if (resource) + return resource.displayName; + return url.trimURL(WebInspector.mainResource ? WebInspector.mainResource.domain : ""); +} + +WebInspector.resourceForURL = function(url) +{ + if (url in this.resourceURLMap) + return this.resourceURLMap[url]; + + // No direct match found. Search for resources that contain + // a substring of the URL. + for (var resourceURL in this.resourceURLMap) { + if (resourceURL.hasSubstring(url)) + return this.resourceURLMap[resourceURL]; + } + + return null; +} + +WebInspector.showResourceForURL = function(url, line, preferredPanel) +{ + var resource = this.resourceForURL(url); + if (!resource) + return false; + + if (preferredPanel && preferredPanel in WebInspector.panels) { + var panel = this.panels[preferredPanel]; + if (!("showResource" in panel)) + panel = null; + else if ("canShowResource" in panel && !panel.canShowResource(resource)) + panel = null; + } + + this.currentPanel = panel || this.panels.resources; + if (!this.currentPanel) + return false; + this.currentPanel.showResource(resource, line); + return true; +} + +WebInspector.linkifyStringAsFragment = function(string) +{ + var container = document.createDocumentFragment(); + var linkStringRegEx = new RegExp("(?:[a-zA-Z][a-zA-Z0-9+.-]{2,}://|www\\.)[\\w$\\-_+*'=\\|/\\\\(){}[\\]%@&#~,:;.!?]{2,}[\\w$\\-_+*=\\|/\\\\({%@&#~]"); + + while (string) { + var linkString = linkStringRegEx.exec(string); + if (!linkString) + break; + + linkString = linkString[0]; + var title = linkString; + var linkIndex = string.indexOf(linkString); + var nonLink = string.substring(0, linkIndex); + container.appendChild(document.createTextNode(nonLink)); + + var profileStringRegEx = new RegExp("webkit-profile://(.+)/[0-9]+"); + var profileStringMatches = profileStringRegEx.exec(title); + var profileTitle; + if (profileStringMatches) + profileTitle = profileStringMatches[1]; + if (profileTitle) + title = WebInspector.panels.profiles.displayTitleForProfileLink(profileTitle); + + var realURL = (linkString.indexOf("www.") === 0 ? "http://" + linkString : linkString); + container.appendChild(WebInspector.linkifyURLAsNode(realURL, title, null, (realURL in WebInspector.resourceURLMap))); + string = string.substring(linkIndex + linkString.length, string.length); + } + + if (string) + container.appendChild(document.createTextNode(string)); + + return container; +} + +WebInspector.showProfileById = function(uid) { + WebInspector.showProfilesPanel(); + WebInspector.panels.profiles.showProfileById(uid); +} + +WebInspector.linkifyURLAsNode = function(url, linkText, classes, isExternal) +{ + if (!linkText) + linkText = url; + classes = (classes ? classes + " " : ""); + classes += isExternal ? "webkit-html-external-link" : "webkit-html-resource-link"; + + var a = document.createElement("a"); + a.href = url; + a.className = classes; + a.title = url; + a.target = "_blank"; + a.textContent = linkText; + + return a; +} + +WebInspector.linkifyURL = function(url, linkText, classes, isExternal) +{ + // Use the DOM version of this function so as to avoid needing to escape attributes. + // FIXME: Get rid of linkifyURL entirely. + return WebInspector.linkifyURLAsNode(url, linkText, classes, isExternal).outerHTML; +} + +WebInspector.addMainEventListeners = function(doc) +{ + doc.defaultView.addEventListener("focus", this.windowFocused.bind(this), true); + doc.defaultView.addEventListener("blur", this.windowBlured.bind(this), true); + doc.addEventListener("click", this.documentClick.bind(this), true); +} + +WebInspector.searchKeyDown = function(event) +{ + if (event.keyIdentifier !== "Enter") + return; + + // Call preventDefault since this was the Enter key. This prevents a "search" event + // from firing for key down. We handle the Enter key on key up in searchKeyUp. This + // stops performSearch from being called twice in a row. + event.preventDefault(); +} + +WebInspector.searchKeyUp = function(event) +{ + if (event.keyIdentifier !== "Enter") + return; + + // Select all of the text so the user can easily type an entirely new query. + event.target.select(); + + // Only call performSearch if the Enter key was pressed. Otherwise the search + // performance is poor because of searching on every key. The search field has + // the incremental attribute set, so we still get incremental searches. + this.performSearch(event); +} + +WebInspector.performSearch = function(event) +{ + var query = event.target.value; + var forceSearch = event.keyIdentifier === "Enter"; + + if (!query || !query.length || (!forceSearch && query.length < 3)) { + delete this.currentQuery; + + for (var panelName in this.panels) { + var panel = this.panels[panelName]; + if (panel.currentQuery && panel.searchCanceled) + panel.searchCanceled(); + delete panel.currentQuery; + } + + this.updateSearchMatchesCount(); + + return; + } + + if (query === this.currentPanel.currentQuery && this.currentPanel.currentQuery === this.currentQuery) { + // When this is the same query and a forced search, jump to the next + // search result for a good user experience. + if (forceSearch && this.currentPanel.jumpToNextSearchResult) + this.currentPanel.jumpToNextSearchResult(); + return; + } + + this.currentQuery = query; + + this.updateSearchMatchesCount(); + + if (!this.currentPanel.performSearch) + return; + + this.currentPanel.currentQuery = query; + this.currentPanel.performSearch(query); +} + +WebInspector.updateSearchMatchesCount = function(matches, panel) +{ + if (!panel) + panel = this.currentPanel; + + panel.currentSearchMatches = matches; + + if (panel !== this.currentPanel) + return; + + if (!this.currentPanel.currentQuery) { + document.getElementById("search-results-matches").addStyleClass("hidden"); + return; + } + + if (matches) { + if (matches === 1) + var matchesString = WebInspector.UIString("1 match"); + else + var matchesString = WebInspector.UIString("%d matches", matches); + } else + var matchesString = WebInspector.UIString("Not Found"); + + var matchesToolbarElement = document.getElementById("search-results-matches"); + matchesToolbarElement.removeStyleClass("hidden"); + matchesToolbarElement.textContent = matchesString; +} + +WebInspector.UIString = function(string) +{ + if (window.localizedStrings && string in window.localizedStrings) + string = window.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.isBeingEdited = function(element) +{ + return element.__editing; +} + +WebInspector.startEditing = function(element, committedCallback, cancelledCallback, context) +{ + if (element.__editing) + return; + element.__editing = true; + + var oldText = element.textContent; + var oldHandleKeyEvent = element.handleKeyEvent; + + element.addStyleClass("editing"); + + var oldTabIndex = element.tabIndex; + if (element.tabIndex < 0) + element.tabIndex = 0; + + function blurEventListener() { + editingCommitted.call(element); + } + + function cleanUpAfterEditing() { + delete this.__editing; + + this.removeStyleClass("editing"); + this.tabIndex = oldTabIndex; + this.scrollTop = 0; + this.scrollLeft = 0; + + this.handleKeyEvent = oldHandleKeyEvent; + element.removeEventListener("blur", blurEventListener, false); + + if (element === WebInspector.currentFocusElement || element.isAncestor(WebInspector.currentFocusElement)) + WebInspector.currentFocusElement = WebInspector.previousFocusElement; + } + + function editingCancelled() { + this.innerText = oldText; + + cleanUpAfterEditing.call(this); + + cancelledCallback(this, context); + } + + function editingCommitted() { + cleanUpAfterEditing.call(this); + + committedCallback(this, this.textContent, oldText, context); + } + + element.handleKeyEvent = function(event) { + if (oldHandleKeyEvent) + oldHandleKeyEvent(event); + if (event.handled) + return; + + if (event.keyIdentifier === "Enter") { + editingCommitted.call(element); + event.preventDefault(); + } else if (event.keyCode === 27) { // Escape key + editingCancelled.call(element); + event.preventDefault(); + event.handled = true; + } + } + + element.addEventListener("blur", blurEventListener, false); + + WebInspector.currentFocusElement = element; +} + +WebInspector._toolbarItemClicked = function(event) +{ + var toolbarItem = event.currentTarget; + this.currentPanel = toolbarItem.panel; +} + +// 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}, +} diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/inspector_controller.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/inspector_controller.js new file mode 100644 index 0000000..09238e2 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/inspector_controller.js @@ -0,0 +1,400 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview Stub implementation of the InspectorController API. + * This stub class is supposed to make front-end a standalone WebApp + * that can be implemented/refactored in isolation from the Web browser + * backend. Clients need to subclass it in order to wire calls to the + * non-stub backends. + */ +goog.provide('devtools.InspectorController'); + + +/** + * Creates inspector controller stub instance. + * @constructor. + */ +devtools.InspectorController = function() { + /** + * @type {boolean} + */ + this.searchingForNode_ = false; + + /** + * @type {boolean} + */ + this.windowVisible_ = true; + + /** + * @type {number} + */ + this.attachedWindowHeight_ = 0; + + /** + * @type {boolean} + */ + this.debuggerEnabled_ = true; + + /** + * @type {boolean} + */ + this.profilerEnabled_ = true; +}; + + +/** + * Wraps javascript callback. + * @param {function():undefined} func The callback to wrap. + * @return {function():undefined} Callback wrapper. + */ +devtools.InspectorController.prototype.wrapCallback = function f(func) { + // Just return as is. + return func; +}; + + +/** + * @return {boolean} True iff inspector window is currently visible. + */ +devtools.InspectorController.prototype.isWindowVisible = function() { + return this.windowVisible_; +}; + + +/** + * @return {string} Platform identifier. + */ +devtools.InspectorController.prototype.platform = function() { + return 'windows'; +}; + + +/** + * Closes inspector window. + */ +devtools.InspectorController.prototype.closeWindow = function() { + this.windowVisible_ = false; +}; + + +/** + * Attaches frontend to the backend. + */ +devtools.InspectorController.prototype.attach = function() { +}; + + +/** + * Detaches frontend from the backend. + */ +devtools.InspectorController.prototype.detach = function() { +}; + + +/** + * Clears console message log in the backend. + */ +devtools.InspectorController.prototype.clearMessages = function() { +}; + + +/** + * Returns true iff browser is currently in the search for node mode. + * @return {boolean} True is currently searching for a node. + */ +devtools.InspectorController.prototype.searchingForNode = function() { + return this.searchingForNode_; +}; + + +/** + * Initiates search for a given query starting on a given row. + * @param {number} sourceRow Row to start searching from. + * @param {string} query Query string for search for. + */ +devtools.InspectorController.prototype.search = function(sourceRow, query) { +}; + + +/** + * Toggles node search mode on/off. + */ +devtools.InspectorController.prototype.toggleNodeSearch = function() { + this.searchingForNode_ = !this.searchingForNode_; +}; + + +/** + * Sets the inspector window height while in the attached mode. + * @param {number} height Window height being set. + */ +devtools.InspectorController.prototype.setAttachedWindowHeight = + function(height) { + this.attachedWindowHeight_ = height; +}; + + +/** + * Moves window by the given offset. + * @param {number} x X offset. + * @param {number} y Y offset. + */ +devtools.InspectorController.prototype.moveByUnrestricted = function(x, y) { +}; + + +/** + * Adds resource with given identifier into the given iframe element. + * @param {number} identifier Identifier of the resource to add into the frame. + * @param {Element} element Element to add resource content to. + */ +devtools.InspectorController.prototype.addResourceSourceToFrame = + function(identifier, element) { + return false; +}; + + +/** + * Adds given source of a given mimeType into the given iframe element. + * @param {string} mimeType MIME type of the content to be added. + * @param {string} source String content to be added. + * @param {Element} element Element to add resource content to. + */ +devtools.InspectorController.prototype.addSourceToFrame = + function(mimeType, source, element) { + return false; +}; + + +/** + * Returns document node corresponding to the resource with given id. + * @return {Node} Node containing the resource. + */ +devtools.InspectorController.prototype.getResourceDocumentNode = + function(identifier) { + return undefined; +}; + + +/** + * Highlights the given node on the page. + * @param {Node} node Node to highlight. + */ +devtools.InspectorController.prototype.highlightDOMNode = function(node) { + // Does nothing in stub. +}; + + +/** + * Clears current highlight. + */ +devtools.InspectorController.prototype.hideDOMNodeHighlight = function() { + // Does nothing in stub. +}; + + +/** + * @return {window} Inspectable window instance. + */ +devtools.InspectorController.prototype.inspectedWindow = function() { + return window; +}; + + +/** + * Notifies backend that the frontend has been successfully loaded. + */ +devtools.InspectorController.prototype.loaded = function() { + // Does nothing in stub. +}; + + +/** + * @return {string} Url of the i18n-ed strings map. + */ +devtools.InspectorController.prototype.localizedStringsURL = function() { + return undefined; +}; + + +/** + * @return {boolean} True iff window is currently unloading. + */ +devtools.InspectorController.prototype.windowUnloading = function() { + return false; +}; + + +/** + * @return {string} Identifiers of the panels that should be hidden. + */ +devtools.InspectorController.prototype.hiddenPanels = function() { + return ''; +}; + + +/** + * @return {boolean} True iff debugger is enabled. + */ +devtools.InspectorController.prototype.debuggerEnabled = function() { + return this.debuggerEnabled_; +}; + + +/** + * Enables debugger. + */ +devtools.InspectorController.prototype.enableDebugger = function() { + this.debuggerEnabled_ = true; +}; + + +/** + * Disables debugger. + */ +devtools.InspectorController.prototype.disableDebugger = function() { + this.debuggerEnabled_ = false; +}; + + +/** + * Adds breakpoint to the given line of the source with given ID. + * @param {string} sourceID Source Id to add breakpoint to. + * @param {number} line Line number to add breakpoint to. + */ +devtools.InspectorController.prototype.addBreakpoint = + function(sourceID, line) { +}; + + +/** + * Removes breakpoint from the given line of the source with given ID. + * @param {string} sourceID Source Id to remove breakpoint from. + * @param {number} line Line number to remove breakpoint from. + */ +devtools.InspectorController.prototype.removeBreakpoint = + function(sourceID, line) { +}; + + +/** + * Tells backend to pause in the debugger. + */ +devtools.InspectorController.prototype.pauseInDebugger = function() { + // Does nothing in stub. +}; + + +/** + * @return {boolean} True iff the debugger will pause execution on the + * exceptions. + */ +devtools.InspectorController.prototype.pauseOnExceptions = function() { + // Does nothing in stub. + return false; +}; + + +/** + * Tells whether to pause in the debugger on the exceptions or not. + * @param {boolean} value True iff execution should be stopped in the debugger + * on the exceptions. + */ +devtools.InspectorController.prototype.setPauseOnExceptions = function(value) {
+};
+
+ +/** + * Tells backend to resume execution. + */ +devtools.InspectorController.prototype.resumeDebugger = function() { +}; + + +/** + * @return {boolean} True iff profiler is enabled. + */ +devtools.InspectorController.prototype.profilerEnabled = function() { + return true; +}; + + +/** + * Enables profiler. + */ +devtools.InspectorController.prototype.enableProfiler = function() { + this.profilerEnabled_ = true; +}; + + +/** + * Disables profiler. + */ +devtools.InspectorController.prototype.disableProfiler = function() { + this.profilerEnabled_ = false; +}; + + +/** + * Returns given callframe while on a debugger break. + * @return {Object} Current call frame. + */ +devtools.InspectorController.prototype.currentCallFrame = function() { + return undefined; +}; + + +/** + * Tells backend to start collecting profiler data. + */ +devtools.InspectorController.prototype.startProfiling = function() { +}; + + +/** + * Tells backend to stop collecting profiler data. + */ +devtools.InspectorController.prototype.stopProfiling = function() { +}; + + +/** + * @return {Array.<Object>} Profile snapshots array. + */ +devtools.InspectorController.prototype.profiles = function() { + return []; +}; + + +/** + * @return {Array.<string>} Database table names available offline. + */ +devtools.InspectorController.prototype.databaseTableNames = + function(database) { + return []; +}; + + +/** + * Tells backend to step into the function in debugger. + */ +devtools.InspectorController.prototype.stepIntoStatementInDebugger = + function() { +}; + + +/** + * Tells backend to step out of the function in debugger. + */ +devtools.InspectorController.prototype.stepOutOfFunctionInDebugger = + function() {}; + + +/** + * Tells backend to step over the statement in debugger. + */ +devtools.InspectorController.prototype.stepOverStatementInDebugger = + function() { +}; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/inspector_controller_impl.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/inspector_controller_impl.js new file mode 100644 index 0000000..45abbe2 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/inspector_controller_impl.js @@ -0,0 +1,148 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview DevTools' implementation of the InspectorController API. + */ +goog.require('devtools.InspectorController'); + +goog.provide('devtools.InspectorControllerImpl'); + +devtools.InspectorControllerImpl = function() { + devtools.InspectorController.call(this); + this.frame_element_id_ = 1; +}; +goog.inherits(devtools.InspectorControllerImpl, + devtools.InspectorController); + + +/** + * {@inheritDoc}. + */ +devtools.InspectorController.prototype.clearMessages = function() { + RemoteToolsAgent.ClearConsoleMessages(); +}; + + +/** + * {@inheritDoc}. + */ +devtools.InspectorControllerImpl.prototype.hiddenPanels = function() { + return 'profiles,databases'; +}; + + +/** + * {@inheritDoc}. + */ +devtools.InspectorController.prototype.search = function(sourceRow, query) { + return DevToolsHost.search(sourceRow, query); +}; + + +/** + * {@inheritDoc}. + */ +devtools.InspectorControllerImpl.prototype.addSourceToFrame = + function(mimeType, source, element) { + return DevToolsHost.addSourceToFrame(mimeType, source, element); +}; + + +/** + * {@inheritDoc}. + */ +devtools.InspectorControllerImpl.prototype.hideDOMNodeHighlight = function() { + RemoteToolsAgent.HideDOMNodeHighlight(); +}; + + +/** + * {@inheritDoc}. + */ +devtools.InspectorControllerImpl.prototype.highlightDOMNode = + function(hoveredNode) { + RemoteToolsAgent.HighlightDOMNode(hoveredNode.id_); +}; + + +/** + * {@inheritDoc}. + */ +devtools.InspectorControllerImpl.prototype.inspectedWindow = function() { + return devtools.tools.getDomAgent().getWindow(); +}; + + +/** + * @override + */ +devtools.InspectorControllerImpl.prototype.debuggerEnabled = function() { + return true; +}; + + +devtools.InspectorControllerImpl.prototype.currentCallFrame = function() { + return devtools.tools.getDebuggerAgent().getCurrentCallFrame(); +}; + + +devtools.InspectorControllerImpl.prototype.addBreakpoint = function( + sourceID, line) { + devtools.tools.getDebuggerAgent().addBreakpoint(sourceID, line); +}; + + +devtools.InspectorControllerImpl.prototype.removeBreakpoint = function( + sourceID, line) { + devtools.tools.getDebuggerAgent().removeBreakpoint(sourceID, line); +}; + + +devtools.InspectorController.prototype.pauseInDebugger = function() { + devtools.tools.getDebuggerAgent().pauseExecution(); +}; + + +devtools.InspectorControllerImpl.prototype.resumeDebugger = function() { + devtools.tools.getDebuggerAgent().resumeExecution(); +}; + + +devtools.InspectorControllerImpl.prototype.stepIntoStatementInDebugger = + function() { + devtools.tools.getDebuggerAgent().stepIntoStatement(); +}; + + +devtools.InspectorControllerImpl.prototype.stepOutOfFunctionInDebugger = + function() { + devtools.tools.getDebuggerAgent().stepOutOfFunction(); +}; + + +devtools.InspectorControllerImpl.prototype.stepOverStatementInDebugger = + function() { + devtools.tools.getDebuggerAgent().stepOverStatement(); +}; + + +/** + * @override + */ +devtools.InspectorControllerImpl.prototype.pauseOnExceptions = function() { + return devtools.tools.getDebuggerAgent().pauseOnExceptions(); +}; + + +/** + * @override + */ +devtools.InspectorControllerImpl.prototype.setPauseOnExceptions = function( + value) { + return devtools.tools.getDebuggerAgent().setPauseOnExceptions(value); +}; + + +var InspectorController = new devtools.InspectorControllerImpl(); diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/json.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/json.js new file mode 100644 index 0000000..252e4ac --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/json.js @@ -0,0 +1,328 @@ +// Copyright 2006 Google 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: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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 THE COPYRIGHT HOLDERS AND 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 THE +// COPYRIGHT OWNER OR 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. + +// NOTE: This file has been changed from the one on doctype. The following +// changes were made: +// - Modified unsafeParse() to use new Function() instead of eval() because eval +// is not allowed inside v8 extensions. +// - Modified parse() to delegate to unsafeParse() instead of calling eval() +// directly. + +/** + * @fileoverview JSON utility functions + */ + + + +goog.provide('goog.json'); +goog.provide('goog.json.Serializer'); + + +/** + * Tests if a string is an invalid JSON string. This only ensures that we are + * not using any invalid characters + * @param {string} s The string to test. + * @return {boolean} True if the input is a valid JSON string. + * @private + */ +goog.json.isValid_ = function(s) { + // All empty whitespace is not valid. + if (/^\s*$/.test(s)) { + return false; + } + + // This is taken from http://www.json.org/json2.js which is released to the + // public domain. + // Changes: We dissallow \u2028 Line separator and \u2029 Paragraph separator + // inside strings. We also treat \u2028 and \u2029 as whitespace which they + // are in the RFC but IE and Safari does not match \s to these so we need to + // include them in the reg exps in all places where whitespace is allowed. + + // Parsing happens in three stages. In the first stage, we run the text + // against regular expressions that look for non-JSON patterns. We are + // especially concerned with '()' and 'new' because they can cause invocation, + // and '=' because it can cause mutation. But just to be safe, we want to + // reject all unexpected forms. + + // We split the first stage into 4 regexp operations in order to work around + // crippling inefficiencies in IE's and Safari's regexp engines. First we + // replace all backslash pairs with '@' (a non-JSON character). Second, we + // replace all simple value tokens with ']' characters. Third, we delete all + // open brackets that follow a colon or comma or that begin the text. Finally, + // we look to see that the remaining characters are only whitespace or ']' or + // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. + + // Don't make these static since they have the global flag. + var backslashesRe = /\\["\\\/bfnrtu]/g; + var simpleValuesRe = + /"[^"\\\n\r\u2028\u2029\x00-\x1f\x7f-\x9f]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g; + var openBracketsRe = /(?:^|:|,)(?:[\s\u2028\u2029]*\[)+/g; + var remainderRe = /^[\],:{}\s\u2028\u2029]*$/; + + return remainderRe.test(s.replace(backslashesRe, '@'). + replace(simpleValuesRe, ']'). + replace(openBracketsRe, '')); +}; + + +/** + * Parses a JSON string and returns the result. This throws an exception if + * the string is an invalid JSON string. + * + * If the user agent has built in support for parsing JSON (using + * <code>String.prototype.parseJSON</code>) that will be used. + * + * Note that this is very slow on large strings. If you trust the source of + * the string then you should use unsafeParse instead. + * + * @param {string} s The JSON string to parse. + * @return {Object} The object generated from the JSON string. + */ +goog.json.parse = function(s) { + s = String(s); + if (typeof s.parseJSON == 'function') { + return s.parseJSON(); + } + if (goog.json.isValid_(s)) { + /** @preserveTry */ + try { + return goog.json.unsafeParse(s); + } catch (ex) { + } + } + throw Error('Invalid JSON string: ' + s); +}; + + +/** + * Parses a JSON string and returns the result. This uses eval so it is open + * to security issues and it should only be used if you trust the source. + * + * @param {string} s The JSON string to parse. + * @return {Object} The object generated from the JSON string. + */ +goog.json.unsafeParse = function(s) { + // This is lame. V8 disallows direct access to eval() in extensions (see: + // v8::internal::Parser::ParseLeftHandSideExpression()). So we must use this + // nasty hack instead. + return new Function('return ('+ s + ')')(); +}; + + +/** + * Instance of the serializer object. + * @type {goog.json.Serializer} + * @private + */ +goog.json.serializer_ = null; + + +/** + * Serializes an object or a value to a JSON string. + * + * If the user agent has built in support for serializing JSON (using + * <code>Object.prototype.toJSONString</code>) that will be used. + * + * @param {Object} object The object to serialize. + * @throws Error if there are loops in the object graph. + * @return {string} A JSON string representation of the input. + */ +goog.json.serialize = function(object) { + if (!goog.json.serializer_) { + goog.json.serializer_ = new goog.json.Serializer; + } + return goog.json.serializer_.serialize(object); +}; + + + +/** + * Class that is used to serialize JSON objects to a string. + * @constructor + */ +goog.json.Serializer = function() { +}; + + +/** + * Serializes an object or a value to a JSON string. + * + * If the user agent has built in support for serializing JSON (using + * <code>Object.prototype.toJSONString</code>) that will be used. + * + * @param {Object?} object The object to serialize. + * @throws Error if there are loops in the object graph. + * @return {string} A JSON string representation of the input. + */ +goog.json.Serializer.prototype.serialize = function(object) { + // null and undefined cannot have properties. (null == undefined) + if (object != null && typeof object.toJSONString == 'function') { + return object.toJSONString(); + } + var sb = []; + this.serialize_(object, sb); + return sb.join(''); +}; + + +/** + * Serializes a generic value to a JSON string + * @private + * @param {Object?} object The object to serialize. + * @param {Array} sb Array used as a string builder. + * @throws Error if there are loops in the object graph. + */ +goog.json.Serializer.prototype.serialize_ = function(object, sb) { + switch (typeof object) { + case 'string': + this.serializeString_(object, sb); + break; + case 'number': + this.serializeNumber_(object, sb); + break; + case 'boolean': + sb.push(object); + break; + case 'undefined': + sb.push('null'); + break; + case 'object': + if (object == null) { + sb.push('null'); + break; + } + if (goog.isArray(object)) { + this.serializeArray_(object, sb); + break; + } + // should we allow new String, new Number and new Boolean to be treated + // as string, number and boolean? Most implementations do not and the + // need is not very big + this.serializeObject_(object, sb); + break; + default: + throw Error('Unknown type: ' + typeof object); + } +}; + + +/** + * Character mappings used internally for goog.string.quote + * @private + * @type {Object} + */ +goog.json.Serializer.charToJsonCharCache_ = { + '\"': '\\"', + '\\': '\\\\', + '/': '\\/', + '\b': '\\b', + '\f': '\\f', + '\n': '\\n', + '\r': '\\r', + '\t': '\\t', + + '\x0B': '\\u000b' // '\v' is not supported in JScript +}; + + +/** + * Serializes a string to a JSON string + * @private + * @param {string} s The string to serialize. + * @param {Array} sb Array used as a string builder. + */ +goog.json.Serializer.prototype.serializeString_ = function(s, sb) { + // The official JSON implementation does not work with international + // characters. + sb.push('"', s.replace(/[\\\"\x00-\x1f\x80-\uffff]/g, function(c) { + // caching the result improves performance by a factor 2-3 + if (c in goog.json.Serializer.charToJsonCharCache_) { + return goog.json.Serializer.charToJsonCharCache_[c]; + } + + var cc = c.charCodeAt(0); + var rv = '\\u'; + if (cc < 16) { + rv += '000'; + } else if (cc < 256) { + rv += '00'; + } else if (cc < 4096) { // \u1000 + rv += '0'; + } + return goog.json.Serializer.charToJsonCharCache_[c] = rv + cc.toString(16); + }), '"'); +}; + + +/** + * Serializes a number to a JSON string + * @private + * @param {number} n The number to serialize. + * @param {Array} sb Array used as a string builder. + */ +goog.json.Serializer.prototype.serializeNumber_ = function(n, sb) { + sb.push(isFinite(n) && !isNaN(n) ? n : 'null'); +}; + + +/** + * Serializes an array to a JSON string + * @private + * @param {Array} arr The array to serialize. + * @param {Array} sb Array used as a string builder. + */ +goog.json.Serializer.prototype.serializeArray_ = function(arr, sb) { + var l = arr.length; + sb.push('['); + var sep = ''; + for (var i = 0; i < l; i++) { + sb.push(sep) + this.serialize_(arr[i], sb); + sep = ','; + } + sb.push(']'); +}; + + +/** + * Serializes an object to a JSON string + * @private + * @param {Object} obj The object to serialize. + * @param {Array} sb Array used as a string builder. + */ +goog.json.Serializer.prototype.serializeObject_ = function(obj, sb) { + sb.push('{'); + var sep = ''; + for (var key in obj) { + sb.push(sep); + this.serializeString_(key, sb); + sb.push(':'); + this.serialize_(obj[key], sb); + sep = ','; + } + sb.push('}'); +}; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/net_agent.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/net_agent.js new file mode 100644 index 0000000..64ef4a6 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/net_agent.js @@ -0,0 +1,140 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview 'Net' manages resources along with the corresponding + * HTTP requests and responses. + * web inspector. + */ +goog.provide('devtools.NetAgent'); + +devtools.NetAgent = function() { + this.resources_ = {}; + this.id_for_url_ = {}; + + RemoteNetAgent.GetResourceContentResult = + devtools.Callback.processCallback; + RemoteNetAgent.WillSendRequest = + goog.bind(this.willSendRequest, this); + RemoteNetAgent.DidReceiveResponse = + goog.bind(this.didReceiveResponse, this); + RemoteNetAgent.DidFinishLoading = + goog.bind(this.didFinishLoading, this); +}; + + +/** + * Resets dom agent to its initial state. + */ +devtools.NetAgent.prototype.reset = function() { + this.resources_ = {}; + this.id_for_url_ = {}; +}; + + +/** + * Returns resource object for given identifier. + * @param {number} identifier Identifier to get resource for. + * @return {WebInspector.Resouce} Resulting resource. + */ +devtools.NetAgent.prototype.getResource = function(identifier) { + return this.resources_[identifier]; +}; + + +/** + * Asynchronously queries for the resource content. + * @param {number} identifier Resource identifier. + * @param {function(string):undefined} opt_callback Callback to call when + * result is available. + */ +devtools.NetAgent.prototype.getResourceContentAsync = function(identifier, + opt_callback) { + var resource = this.resources_[identifier]; + if (!resource) { + return; + } + var mycallback = function(content) { + if (opt_callback) { + opt_callback(content); + } + }; + RemoteNetAgent.GetResourceContent( + devtools.Callback.wrap(mycallback), identifier, resource.url); +}; + + +/** + * @see NetAgentDelegate. + * {@inheritDoc}. + */ +devtools.NetAgent.prototype.willSendRequest = function(identifier, request) { + // Resource object is already created. + var resource = this.resources_[identifier]; + if (resource) { + return; + } + + var mainResource = false; + var cached = false; + var resource = new WebInspector.Resource(request.requestHeaders, + request.url, request.domain, request.path, request.lastPathComponent, + identifier, mainResource, cached); + resource.startTime = request.startTime; + WebInspector.addResource(resource); + this.resources_[identifier] = resource; + this.id_for_url_[request.url] = identifier; +}; + + +/** + * @see NetAgentDelegate. + * {@inheritDoc}. + */ +devtools.NetAgent.prototype.didReceiveResponse = function(identifier, response) { + var resource = this.resources_[identifier]; + if (!resource) { + return; + } + + resource.expectedContentLength = response.expectedContentLength; + resource.responseStatusCode = response.responseStatusCode; + resource.responseHeaders = response.responseHeaders; + resource.mimeType = response.mimeType; + resource.suggestedFilename = response.suggestedFilename; + var mimeType = response.mimeType; + if (mimeType.indexOf('image/') == 0) { + resource.type = WebInspector.Resource.Type.Image; + } else if (mimeType.indexOf('text/html') == 0) { + resource.type = WebInspector.Resource.Type.Document; + } else if (mimeType.indexOf('script') != -1 || + resource.url.indexOf('.js') == resource.url.length - 3) { + resource.type = WebInspector.Resource.Type.Script; + } else if (mimeType.indexOf('text/css') == 0) { + resource.type = WebInspector.Resource.Type.Stylesheet; + } else { + resource.type = WebInspector.Resource.Type.Other; + } + resource.responseReceivedTime = response.responseReceivedTime; +}; + + +/** + * @see NetAgentDelegate. + * {@inheritDoc}. + */ +devtools.NetAgent.prototype.didFinishLoading = function(identifier, value) { + // When loading main resource we are only getting the didFinishLoading + // that is happening after the reset. Replay previous commands here. + this.willSendRequest(identifier, value); + this.didReceiveResponse(identifier, value); + + var resource = this.resources_[identifier]; + if (!resource) { + return; + } + resource.endTime = value.endTime; + resource.finished = true; + resource.failed = !!value.errorCode; +}; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/treeoutline.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/treeoutline.js new file mode 100644 index 0000000..579e7fb --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/treeoutline.js @@ -0,0 +1,846 @@ +/* + * Copyright (C) 2007 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. + * 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. + */ + +function TreeOutline(listNode) +{ + this.children = []; + this.selectedTreeElement = null; + this._childrenListNode = listNode; + this._childrenListNode.removeChildren(); + this._knownTreeElements = []; + this._treeElementsExpandedState = []; + this.expandTreeElementsWhenArrowing = false; + this.root = true; + this.hasChildren = false; + this.expanded = true; + this.selected = false; + this.treeOutline = this; +} + +TreeOutline._knownTreeElementNextIdentifier = 1; + +TreeOutline._appendChild = function(child) +{ + if (!child) + throw("child can't be undefined or null"); + + var lastChild = this.children[this.children.length - 1]; + if (lastChild) { + lastChild.nextSibling = child; + child.previousSibling = lastChild; + } else { + child.previousSibling = null; + child.nextSibling = null; + } + + this.children.push(child); + this.hasChildren = true; + child.parent = this; + child.treeOutline = this.treeOutline; + child.treeOutline._rememberTreeElement(child); + + var current = child.children[0]; + while (current) { + current.treeOutline = this.treeOutline; + current.treeOutline._rememberTreeElement(current); + current = current.traverseNextTreeElement(false, child, true); + } + + if (child.hasChildren && child.treeOutline._treeElementsExpandedState[child.identifier] !== undefined) + child.expanded = child.treeOutline._treeElementsExpandedState[child.identifier]; + + if (!this._childrenListNode) { + this._childrenListNode = this.treeOutline._childrenListNode.ownerDocument.createElement("ol"); + this._childrenListNode.parentTreeElement = this; + this._childrenListNode.addStyleClass("children"); + if (this.hidden) + this._childrenListNode.addStyleClass("hidden"); + } + + child._attach(); +} + +TreeOutline._insertChild = function(child, index) +{ + if (!child) + throw("child can't be undefined or null"); + + var previousChild = (index > 0 ? this.children[index - 1] : null); + if (previousChild) { + previousChild.nextSibling = child; + child.previousSibling = previousChild; + } else { + child.previousSibling = null; + } + + var nextChild = this.children[index]; + if (nextChild) { + nextChild.previousSibling = child; + child.nextSibling = nextChild; + } else { + child.nextSibling = null; + } + + this.children.splice(index, 0, child); + this.hasChildren = true; + child.parent = this; + child.treeOutline = this.treeOutline; + child.treeOutline._rememberTreeElement(child); + + var current = child.children[0]; + while (current) { + current.treeOutline = this.treeOutline; + current.treeOutline._rememberTreeElement(current); + current = current.traverseNextTreeElement(false, child, true); + } + + if (child.hasChildren && child.treeOutline._treeElementsExpandedState[child.identifier] !== undefined) + child.expanded = child.treeOutline._treeElementsExpandedState[child.identifier]; + + if (!this._childrenListNode) { + this._childrenListNode = this.treeOutline._childrenListNode.ownerDocument.createElement("ol"); + this._childrenListNode.parentTreeElement = this; + this._childrenListNode.addStyleClass("children"); + if (this.hidden) + this._childrenListNode.addStyleClass("hidden"); + } + + child._attach(); +} + +TreeOutline._removeChildAtIndex = function(childIndex) +{ + if (childIndex < 0 || childIndex >= this.children.length) + throw("childIndex out of range"); + + var child = this.children[childIndex]; + this.children.splice(childIndex, 1); + + child.deselect(); + + if (child.previousSibling) + child.previousSibling.nextSibling = child.nextSibling; + if (child.nextSibling) + child.nextSibling.previousSibling = child.previousSibling; + + if (child.treeOutline) { + child.treeOutline._forgetTreeElement(child); + child.treeOutline._forgetChildrenRecursive(child); + } + + child._detach(); + child.treeOutline = null; + child.parent = null; + child.nextSibling = null; + child.previousSibling = null; +} + +TreeOutline._removeChild = function(child) +{ + if (!child) + throw("child can't be undefined or null"); + + var childIndex = this.children.indexOf(child); + if (childIndex === -1) + throw("child not found in this node's children"); + + TreeOutline._removeChildAtIndex.call(this, childIndex); +} + +TreeOutline._removeChildren = function() +{ + for (var i = 0; i < this.children.length; ++i) { + var child = this.children[i]; + child.deselect(); + + if (child.treeOutline) { + child.treeOutline._forgetTreeElement(child); + child.treeOutline._forgetChildrenRecursive(child); + } + + child._detach(); + child.treeOutline = null; + child.parent = null; + child.nextSibling = null; + child.previousSibling = null; + } + + this.children = []; +} + +TreeOutline._removeChildrenRecursive = function() +{ + var childrenToRemove = this.children; + + var child = this.children[0]; + while (child) { + if (child.children.length) + childrenToRemove = childrenToRemove.concat(child.children); + child = child.traverseNextTreeElement(false, this, true); + } + + for (var i = 0; i < childrenToRemove.length; ++i) { + var child = childrenToRemove[i]; + child.deselect(); + if (child.treeOutline) + child.treeOutline._forgetTreeElement(child); + child._detach(); + child.children = []; + child.treeOutline = null; + child.parent = null; + child.nextSibling = null; + child.previousSibling = null; + } + + this.children = []; +} + +TreeOutline.prototype._rememberTreeElement = function(element) +{ + if (!this._knownTreeElements[element.identifier]) + this._knownTreeElements[element.identifier] = []; + + // check if the element is already known + var elements = this._knownTreeElements[element.identifier]; + if (elements.indexOf(element) !== -1) + return; + + // add the element + elements.push(element); +} + +TreeOutline.prototype._forgetTreeElement = function(element) +{ + if (this._knownTreeElements[element.identifier]) + this._knownTreeElements[element.identifier].remove(element, true); +} + +TreeOutline.prototype._forgetChildrenRecursive = function(parentElement) +{ + var child = parentElement.children[0]; + while (child) { + this._forgetTreeElement(child); + child = child.traverseNextTreeElement(false, this, true); + } +} + +TreeOutline.prototype.findTreeElement = function(representedObject, isAncestor, getParent, equal) +{ + if (!representedObject) + return null; + + if (!equal) + equal = function(a, b) { return a === b }; + + if ("__treeElementIdentifier" in representedObject) { + // If this representedObject has a tree element identifier, and it is a known TreeElement + // in our tree we can just return that tree element. + var elements = this._knownTreeElements[representedObject.__treeElementIdentifier]; + if (elements) { + for (var i = 0; i < elements.length; ++i) + if (equal(elements[i].representedObject, representedObject)) + return elements[i]; + } + } + + if (!isAncestor || !(isAncestor instanceof Function) || !getParent || !(getParent instanceof Function)) + return null; + + // The representedObject isn't know, so we start at the top of the tree and work down to find the first + // tree element that represents representedObject or one of its ancestors. + var item; + var found = false; + for (var i = 0; i < this.children.length; ++i) { + item = this.children[i]; + if (equal(item.representedObject, representedObject) || isAncestor(item.representedObject, representedObject)) { + found = true; + break; + } + } + + if (!found) + return null; + + // Make sure the item that we found is connected to the root of the tree. + // Build up a list of representedObject's ancestors that aren't already in our tree. + var ancestors = []; + var currentObject = representedObject; + while (currentObject) { + ancestors.unshift(currentObject); + if (equal(currentObject, item.representedObject)) + break; + currentObject = getParent(currentObject); + } + + // For each of those ancestors we populate them to fill in the tree. + for (var i = 0; i < ancestors.length; ++i) { + // Make sure we don't call findTreeElement with the same representedObject + // again, to prevent infinite recursion. + if (equal(ancestors[i], representedObject)) + continue; + // FIXME: we could do something faster than findTreeElement since we will know the next + // ancestor exists in the tree. + item = this.findTreeElement(ancestors[i], isAncestor, getParent, equal); + if (item && item.onpopulate) + item.onpopulate(item); + } + + // Now that all the ancestors are populated, try to find the representedObject again. This time + // without the isAncestor and getParent functions to prevent an infinite recursion if it isn't found. + return this.findTreeElement(representedObject, null, null, equal); +} + +TreeOutline.prototype.treeElementFromPoint = function(x, y) +{ + var node = this._childrenListNode.ownerDocument.elementFromPoint(x, y); + var listNode = node.enclosingNodeOrSelfWithNodeNameInArray(["ol", "li"]); + if (listNode) + return listNode.parentTreeElement || listNode.treeElement; + return null; +} + +TreeOutline.prototype.handleKeyEvent = function(event) +{ + if (!this.selectedTreeElement || event.shiftKey || event.metaKey || event.ctrlKey) + return false; + + var handled = false; + var nextSelectedElement; + if (event.keyIdentifier === "Up" && !event.altKey) { + nextSelectedElement = this.selectedTreeElement.traversePreviousTreeElement(true); + while (nextSelectedElement && !nextSelectedElement.selectable) + nextSelectedElement = nextSelectedElement.traversePreviousTreeElement(!this.expandTreeElementsWhenArrowing); + handled = nextSelectedElement ? true : false; + } else if (event.keyIdentifier === "Down" && !event.altKey) { + nextSelectedElement = this.selectedTreeElement.traverseNextTreeElement(true); + while (nextSelectedElement && !nextSelectedElement.selectable) + nextSelectedElement = nextSelectedElement.traverseNextTreeElement(!this.expandTreeElementsWhenArrowing); + handled = nextSelectedElement ? true : false; + } else if (event.keyIdentifier === "Left") { + if (this.selectedTreeElement.expanded) { + if (event.altKey) + this.selectedTreeElement.collapseRecursively(); + else + this.selectedTreeElement.collapse(); + handled = true; + } else if (this.selectedTreeElement.parent && !this.selectedTreeElement.parent.root) { + handled = true; + if (this.selectedTreeElement.parent.selectable) { + nextSelectedElement = this.selectedTreeElement.parent; + handled = nextSelectedElement ? true : false; + } else if (this.selectedTreeElement.parent) + this.selectedTreeElement.parent.collapse(); + } + } else if (event.keyIdentifier === "Right") { + if (!this.selectedTreeElement.revealed()) { + this.selectedTreeElement.reveal(); + handled = true; + } else if (this.selectedTreeElement.hasChildren) { + handled = true; + if (this.selectedTreeElement.expanded) { + nextSelectedElement = this.selectedTreeElement.children[0]; + handled = nextSelectedElement ? true : false; + } else { + if (event.altKey) + this.selectedTreeElement.expandRecursively(); + else + this.selectedTreeElement.expand(); + } + } + } + + if (nextSelectedElement) { + nextSelectedElement.reveal(); + nextSelectedElement.select(); + } + + if (handled) { + event.preventDefault(); + event.stopPropagation(); + } + + return handled; +} + +TreeOutline.prototype.expand = function() +{ + // this is the root, do nothing +} + +TreeOutline.prototype.collapse = function() +{ + // this is the root, do nothing +} + +TreeOutline.prototype.revealed = function() +{ + return true; +} + +TreeOutline.prototype.reveal = function() +{ + // this is the root, do nothing +} + +TreeOutline.prototype.appendChild = TreeOutline._appendChild; +TreeOutline.prototype.insertChild = TreeOutline._insertChild; +TreeOutline.prototype.removeChild = TreeOutline._removeChild; +TreeOutline.prototype.removeChildAtIndex = TreeOutline._removeChildAtIndex; +TreeOutline.prototype.removeChildren = TreeOutline._removeChildren; +TreeOutline.prototype.removeChildrenRecursive = TreeOutline._removeChildrenRecursive; + +function TreeElement(title, representedObject, hasChildren) +{ + this._title = title; + this.representedObject = (representedObject || {}); + + if (this.representedObject.__treeElementIdentifier) + this.identifier = this.representedObject.__treeElementIdentifier; + else { + this.identifier = TreeOutline._knownTreeElementNextIdentifier++; + this.representedObject.__treeElementIdentifier = this.identifier; + } + + this._hidden = false; + this.expanded = false; + this.selected = false; + this.hasChildren = hasChildren; + this.children = []; + this.treeOutline = null; + this.parent = null; + this.previousSibling = null; + this.nextSibling = null; + this._listItemNode = null; +} + +TreeElement.prototype = { + selectable: true, + arrowToggleWidth: 10, + + get listItemElement() { + return this._listItemNode; + }, + + get childrenListElement() { + return this._childrenListNode; + }, + + get title() { + return this._title; + }, + + set title(x) { + this._title = x; + if (this._listItemNode) + this._listItemNode.innerHTML = x; + }, + + get tooltip() { + return this._tooltip; + }, + + set tooltip(x) { + this._tooltip = x; + if (this._listItemNode) + this._listItemNode.title = x ? x : ""; + }, + + get hasChildren() { + return this._hasChildren; + }, + + set hasChildren(x) { + if (this._hasChildren === x) + return; + + this._hasChildren = x; + + if (!this._listItemNode) + return; + + if (x) + this._listItemNode.addStyleClass("parent"); + else { + this._listItemNode.removeStyleClass("parent"); + this.collapse(); + } + }, + + get hidden() { + return this._hidden; + }, + + set hidden(x) { + if (this._hidden === x) + return; + + this._hidden = x; + + if (x) { + if (this._listItemNode) + this._listItemNode.addStyleClass("hidden"); + if (this._childrenListNode) + this._childrenListNode.addStyleClass("hidden"); + } else { + if (this._listItemNode) + this._listItemNode.removeStyleClass("hidden"); + if (this._childrenListNode) + this._childrenListNode.removeStyleClass("hidden"); + } + }, + + get shouldRefreshChildren() { + return this._shouldRefreshChildren; + }, + + set shouldRefreshChildren(x) { + this._shouldRefreshChildren = x; + if (x && this.expanded) + this.expand(); + } +} + +TreeElement.prototype.appendChild = TreeOutline._appendChild; +TreeElement.prototype.insertChild = TreeOutline._insertChild; +TreeElement.prototype.removeChild = TreeOutline._removeChild; +TreeElement.prototype.removeChildAtIndex = TreeOutline._removeChildAtIndex; +TreeElement.prototype.removeChildren = TreeOutline._removeChildren; +TreeElement.prototype.removeChildrenRecursive = TreeOutline._removeChildrenRecursive; + +TreeElement.prototype._attach = function() +{ + if (!this._listItemNode || this.parent._shouldRefreshChildren) { + if (this._listItemNode && this._listItemNode.parentNode) + this._listItemNode.parentNode.removeChild(this._listItemNode); + + this._listItemNode = this.treeOutline._childrenListNode.ownerDocument.createElement("li"); + this._listItemNode.treeElement = this; + this._listItemNode.innerHTML = this._title; + this._listItemNode.title = this._tooltip ? this._tooltip : ""; + + if (this.hidden) + this._listItemNode.addStyleClass("hidden"); + if (this.hasChildren) + this._listItemNode.addStyleClass("parent"); + if (this.expanded) + this._listItemNode.addStyleClass("expanded"); + if (this.selected) + this._listItemNode.addStyleClass("selected"); + + this._listItemNode.addEventListener("mousedown", TreeElement.treeElementSelected, false); + this._listItemNode.addEventListener("click", TreeElement.treeElementToggled, false); + this._listItemNode.addEventListener("dblclick", TreeElement.treeElementDoubleClicked, false); + + if (this.onattach) + this.onattach(this); + } + + var nextSibling = null; + if (this.nextSibling && this.nextSibling._listItemNode && this.nextSibling._listItemNode.parentNode === this.parent._childrenListNode) + nextSibling = this.nextSibling._listItemNode; + this.parent._childrenListNode.insertBefore(this._listItemNode, nextSibling); + if (this._childrenListNode) + this.parent._childrenListNode.insertBefore(this._childrenListNode, this._listItemNode.nextSibling); + if (this.selected) + this.select(); + if (this.expanded) + this.expand(); +} + +TreeElement.prototype._detach = function() +{ + if (this._listItemNode && this._listItemNode.parentNode) + this._listItemNode.parentNode.removeChild(this._listItemNode); + if (this._childrenListNode && this._childrenListNode.parentNode) + this._childrenListNode.parentNode.removeChild(this._childrenListNode); +} + +TreeElement.treeElementSelected = function(event) +{ + var element = event.currentTarget; + if (!element || !element.treeElement || !element.treeElement.selectable) + return; + + if (element.treeElement.isEventWithinDisclosureTriangle(event)) + return; + + element.treeElement.select(); +} + +TreeElement.treeElementToggled = function(event) +{ + var element = event.currentTarget; + if (!element || !element.treeElement) + return; + + if (!element.treeElement.isEventWithinDisclosureTriangle(event)) + return; + + if (element.treeElement.expanded) { + if (event.altKey) + element.treeElement.collapseRecursively(); + else + element.treeElement.collapse(); + } else { + if (event.altKey) + element.treeElement.expandRecursively(); + else + element.treeElement.expand(); + } +} + +TreeElement.treeElementDoubleClicked = function(event) +{ + var element = event.currentTarget; + if (!element || !element.treeElement) + return; + + if (element.treeElement.ondblclick) + element.treeElement.ondblclick(element.treeElement, event); + else if (element.treeElement.hasChildren && !element.treeElement.expanded) + element.treeElement.expand(); +} + +TreeElement.prototype.collapse = function() +{ + if (this._listItemNode) + this._listItemNode.removeStyleClass("expanded"); + if (this._childrenListNode) + this._childrenListNode.removeStyleClass("expanded"); + + this.expanded = false; + if (this.treeOutline) + this.treeOutline._treeElementsExpandedState[this.identifier] = true; + + if (this.oncollapse) + this.oncollapse(this); +} + +TreeElement.prototype.collapseRecursively = function() +{ + var item = this; + while (item) { + if (item.expanded) + item.collapse(); + item = item.traverseNextTreeElement(false, this, true); + } +} + +TreeElement.prototype.expand = function() +{ + if (!this.hasChildren || (this.expanded && !this._shouldRefreshChildren && this._childrenListNode)) + return; + + if (this.treeOutline && (!this._childrenListNode || this._shouldRefreshChildren)) { + if (this._childrenListNode && this._childrenListNode.parentNode) + this._childrenListNode.parentNode.removeChild(this._childrenListNode); + + this._childrenListNode = this.treeOutline._childrenListNode.ownerDocument.createElement("ol"); + this._childrenListNode.parentTreeElement = this; + this._childrenListNode.addStyleClass("children"); + + if (this.hidden) + this._childrenListNode.addStyleClass("hidden"); + + if (this.onpopulate) + this.onpopulate(this); + + for (var i = 0; i < this.children.length; ++i) + this.children[i]._attach(); + + delete this._shouldRefreshChildren; + } + + if (this._listItemNode) { + this._listItemNode.addStyleClass("expanded"); + if (this._childrenListNode && this._childrenListNode.parentNode != this._listItemNode.parentNode) + this.parent._childrenListNode.insertBefore(this._childrenListNode, this._listItemNode.nextSibling); + } + + if (this._childrenListNode) + this._childrenListNode.addStyleClass("expanded"); + + this.expanded = true; + if (this.treeOutline) + this.treeOutline._treeElementsExpandedState[this.identifier] = true; + + if (this.onexpand) + this.onexpand(this); +} + +TreeElement.prototype.expandRecursively = function(maxDepth) +{ + var item = this; + var info = {}; + var depth = 0; + + // The Inspector uses TreeOutlines to represents object properties, so recursive expansion + // in some case can be infinite, since JavaScript objects can hold circular references. + // So default to a recursion cap of 3 levels, since that gives fairly good results. + if (typeof maxDepth === "undefined" || typeof maxDepth === "null") + maxDepth = 3; + + while (item) { + if (depth < maxDepth) + item.expand(); + item = item.traverseNextTreeElement(false, this, (depth >= maxDepth), info); + depth += info.depthChange; + } +} + +TreeElement.prototype.hasAncestor = function(ancestor) { + if (!ancestor) + return false; + + var currentNode = this.parent; + while (currentNode) { + if (ancestor === currentNode) + return true; + currentNode = currentNode.parent; + } + + return false; +} + +TreeElement.prototype.reveal = function() +{ + var currentAncestor = this.parent; + while (currentAncestor && !currentAncestor.root) { + if (!currentAncestor.expanded) + currentAncestor.expand(); + currentAncestor = currentAncestor.parent; + } + + if (this.onreveal) + this.onreveal(this); +} + +TreeElement.prototype.revealed = function() +{ + var currentAncestor = this.parent; + while (currentAncestor && !currentAncestor.root) { + if (!currentAncestor.expanded) + return false; + currentAncestor = currentAncestor.parent; + } + + return true; +} + +TreeElement.prototype.select = function(supressOnSelect) +{ + if (!this.treeOutline || !this.selectable || this.selected) + return; + + if (this.treeOutline.selectedTreeElement) + this.treeOutline.selectedTreeElement.deselect(); + + this.selected = true; + this.treeOutline.selectedTreeElement = this; + if (this._listItemNode) + this._listItemNode.addStyleClass("selected"); + + if (this.onselect && !supressOnSelect) + this.onselect(this); +} + +TreeElement.prototype.deselect = function(supressOnDeselect) +{ + if (!this.treeOutline || this.treeOutline.selectedTreeElement !== this || !this.selected) + return; + + this.selected = false; + this.treeOutline.selectedTreeElement = null; + if (this._listItemNode) + this._listItemNode.removeStyleClass("selected"); + + if (this.ondeselect && !supressOnDeselect) + this.ondeselect(this); +} + +TreeElement.prototype.traverseNextTreeElement = function(skipHidden, stayWithin, dontPopulate, info) +{ + if (!dontPopulate && this.hasChildren && this.onpopulate) + this.onpopulate(this); + + if (info) + info.depthChange = 0; + + var element = skipHidden ? (this.revealed() ? this.children[0] : null) : this.children[0]; + if (element && (!skipHidden || (skipHidden && this.expanded))) { + if (info) + info.depthChange = 1; + return element; + } + + if (this === stayWithin) + return null; + + element = skipHidden ? (this.revealed() ? this.nextSibling : null) : this.nextSibling; + if (element) + return element; + + element = this; + while (element && !element.root && !(skipHidden ? (element.revealed() ? element.nextSibling : null) : element.nextSibling) && element.parent !== stayWithin) { + if (info) + info.depthChange -= 1; + element = element.parent; + } + + if (!element) + return null; + + return (skipHidden ? (element.revealed() ? element.nextSibling : null) : element.nextSibling); +} + +TreeElement.prototype.traversePreviousTreeElement = function(skipHidden, dontPopulate) +{ + var element = skipHidden ? (this.revealed() ? this.previousSibling : null) : this.previousSibling; + if (!dontPopulate && element && element.hasChildren && element.onpopulate) + element.onpopulate(element); + + while (element && (skipHidden ? (element.revealed() && element.expanded ? element.children[element.children.length - 1] : null) : element.children[element.children.length - 1])) { + if (!dontPopulate && element.hasChildren && element.onpopulate) + element.onpopulate(element); + element = (skipHidden ? (element.revealed() && element.expanded ? element.children[element.children.length - 1] : null) : element.children[element.children.length - 1]); + } + + if (element) + return element; + + if (!this.parent || this.parent.root) + return null; + + return this.parent; +} + +TreeElement.prototype.isEventWithinDisclosureTriangle = function(event) +{ + var left = this._listItemNode.totalOffsetLeft; + return event.pageX >= left && event.pageX <= left + this.arrowToggleWidth && this.hasChildren; +} diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/utilities.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/utilities.js new file mode 100644 index 0000000..8fb50e2 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/utilities.js @@ -0,0 +1,1136 @@ +/* + * Copyright (C) 2007 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. + * 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. + */ + +Object.type = function(obj, win) +{ + if (obj === null) + return "null"; + + var type = typeof obj; + if (type !== "object" && type !== "function") + return type; + + win = win || window; + + if (obj instanceof win.Node) + return "node"; + if (obj instanceof win.String) + return "string"; + if (obj instanceof win.Array) + return "array"; + if (obj instanceof win.Boolean) + return "boolean"; + if (obj instanceof win.Number) + return "number"; + if (obj instanceof win.Date) + return "date"; + if (obj instanceof win.RegExp) + return "regexp"; + if (obj instanceof win.Error) + return "error"; + return type; +} + +Object.hasProperties = function(obj) +{ + if (typeof obj === "undefined" || typeof obj === "null") + return false; + for (var name in obj) + return true; + return false; +} + +Object.describe = function(obj, abbreviated) +{ + var type1 = Object.type(obj); + var type2 = Object.prototype.toString.call(obj).replace(/^\[object (.*)\]$/i, "$1"); + + switch (type1) { + case "object": + case "node": + return type2; + case "array": + return "[" + obj.toString() + "]"; + case "string": + if (obj.length > 100) + return "\"" + obj.substring(0, 100) + "\u2026\""; + return "\"" + obj + "\""; + case "function": + var objectText = String(obj); + if (!/^function /.test(objectText)) + objectText = (type2 == "object") ? type1 : type2; + else if (abbreviated) + objectText = /.*/.exec(obj)[0].replace(/ +$/g, ""); + return objectText; + case "regexp": + return String(obj).replace(/([\\\/])/g, "\\$1").replace(/\\(\/[gim]*)$/, "$1").substring(1); + default: + return String(obj); + } +} + +Object.sortedProperties = function(obj) +{ + var properties = []; + for (var prop in obj) + properties.push(prop); + properties.sort(); + return properties; +} + +Function.prototype.bind = function(thisObject) +{ + var func = this; + var args = Array.prototype.slice.call(arguments, 1); + return function() { return func.apply(thisObject, args.concat(Array.prototype.slice.call(arguments, 0))) }; +} + +Node.prototype.rangeOfWord = function(offset, stopCharacters, stayWithinNode, direction) +{ + var startNode; + var startOffset = 0; + var endNode; + var endOffset = 0; + + if (!stayWithinNode) + stayWithinNode = this; + + if (!direction || direction === "backward" || direction === "both") { + var node = this; + while (node) { + if (node === stayWithinNode) { + if (!startNode) + startNode = stayWithinNode; + break; + } + + if (node.nodeType === Node.TEXT_NODE) { + var start = (node === this ? (offset - 1) : (node.nodeValue.length - 1)); + for (var i = start; i >= 0; --i) { + if (stopCharacters.indexOf(node.nodeValue[i]) !== -1) { + startNode = node; + startOffset = i + 1; + break; + } + } + } + + if (startNode) + break; + + node = node.traversePreviousNode(false, stayWithinNode); + } + + if (!startNode) { + startNode = stayWithinNode; + startOffset = 0; + } + } else { + startNode = this; + startOffset = offset; + } + + if (!direction || direction === "forward" || direction === "both") { + node = this; + while (node) { + if (node === stayWithinNode) { + if (!endNode) + endNode = stayWithinNode; + break; + } + + if (node.nodeType === Node.TEXT_NODE) { + var start = (node === this ? offset : 0); + for (var i = start; i < node.nodeValue.length; ++i) { + if (stopCharacters.indexOf(node.nodeValue[i]) !== -1) { + endNode = node; + endOffset = i; + break; + } + } + } + + if (endNode) + break; + + node = node.traverseNextNode(false, stayWithinNode); + } + + if (!endNode) { + endNode = stayWithinNode; + endOffset = stayWithinNode.nodeType === Node.TEXT_NODE ? stayWithinNode.nodeValue.length : stayWithinNode.childNodes.length; + } + } else { + endNode = this; + endOffset = offset; + } + + var result = this.ownerDocument.createRange(); + result.setStart(startNode, startOffset); + result.setEnd(endNode, endOffset); + + return result; +} + +Element.prototype.removeStyleClass = function(className) +{ + // Test for the simple case before using a RegExp. + if (this.className === className) { + this.className = ""; + return; + } + + this.removeMatchingStyleClasses(className.escapeForRegExp()); +} + +Element.prototype.removeMatchingStyleClasses = function(classNameRegex) +{ + var regex = new RegExp("(^|\\s+)" + classNameRegex + "($|\\s+)"); + if (regex.test(this.className)) + this.className = this.className.replace(regex, " "); +} + +Element.prototype.addStyleClass = function(className) +{ + if (className && !this.hasStyleClass(className)) + this.className += (this.className.length ? " " + className : className); +} + +Element.prototype.hasStyleClass = function(className) +{ + if (!className) + return false; + // Test for the simple case before using a RegExp. + if (this.className === className) + return true; + var regex = new RegExp("(^|\\s)" + className.escapeForRegExp() + "($|\\s)"); + return regex.test(this.className); +} + +Node.prototype.enclosingNodeOrSelfWithNodeNameInArray = function(nameArray) +{ + for (var node = this; node && !objectsAreSame(node, this.ownerDocument); node = node.parentNode) + for (var i = 0; i < nameArray.length; ++i) + if (node.nodeName.toLowerCase() === nameArray[i].toLowerCase()) + return node; + return null; +} + +Node.prototype.enclosingNodeOrSelfWithNodeName = function(nodeName) +{ + return this.enclosingNodeOrSelfWithNodeNameInArray([nodeName]); +} + +Node.prototype.enclosingNodeOrSelfWithClass = function(className) +{ + for (var node = this; node && !objectsAreSame(node, this.ownerDocument); node = node.parentNode) + if (node.nodeType === Node.ELEMENT_NODE && node.hasStyleClass(className)) + return node; + return null; +} + +Node.prototype.enclosingNodeWithClass = function(className) +{ + if (!this.parentNode) + return null; + return this.parentNode.enclosingNodeOrSelfWithClass(className); +} + +Element.prototype.query = function(query) +{ + return this.ownerDocument.evaluate(query, this, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; +} + +Element.prototype.removeChildren = function() +{ + while (this.firstChild) + this.removeChild(this.firstChild); +} + +Element.prototype.isInsertionCaretInside = function() +{ + var selection = window.getSelection(); + if (!selection.rangeCount || !selection.isCollapsed) + return false; + var selectionRange = selection.getRangeAt(0); + return selectionRange.startContainer === this || selectionRange.startContainer.isDescendant(this); +} + +Element.prototype.__defineGetter__("totalOffsetLeft", function() +{ + var total = 0; + for (var element = this; element; element = element.offsetParent) + total += element.offsetLeft; + return total; +}); + +Element.prototype.__defineGetter__("totalOffsetTop", function() +{ + var total = 0; + for (var element = this; element; element = element.offsetParent) + total += element.offsetTop; + return total; +}); + +Element.prototype.firstChildSkippingWhitespace = firstChildSkippingWhitespace; +Element.prototype.lastChildSkippingWhitespace = lastChildSkippingWhitespace; + +Node.prototype.isWhitespace = isNodeWhitespace; +Node.prototype.nodeTypeName = nodeTypeName; +Node.prototype.displayName = nodeDisplayName; +Node.prototype.contentPreview = nodeContentPreview; +Node.prototype.isAncestor = isAncestorNode; +Node.prototype.isDescendant = isDescendantNode; +Node.prototype.firstCommonAncestor = firstCommonNodeAncestor; +Node.prototype.nextSiblingSkippingWhitespace = nextSiblingSkippingWhitespace; +Node.prototype.previousSiblingSkippingWhitespace = previousSiblingSkippingWhitespace; +Node.prototype.traverseNextNode = traverseNextNode; +Node.prototype.traversePreviousNode = traversePreviousNode; +Node.prototype.onlyTextChild = onlyTextChild; + +String.prototype.hasSubstring = function(string, caseInsensitive) +{ + if (!caseInsensitive) + return this.indexOf(string) !== -1; + return this.match(new RegExp(string.escapeForRegExp(), "i")); +} + +String.prototype.escapeCharacters = function(chars) +{ + var foundChar = false; + for (var i = 0; i < chars.length; ++i) { + if (this.indexOf(chars.charAt(i)) !== -1) { + foundChar = true; + break; + } + } + + if (!foundChar) + return this; + + var result = ""; + for (var i = 0; i < this.length; ++i) { + if (chars.indexOf(this.charAt(i)) !== -1) + result += "\\"; + result += this.charAt(i); + } + + return result; +} + +String.prototype.escapeForRegExp = function() +{ + return this.escapeCharacters("^[]{}()\\.$*+?|"); +} + +String.prototype.escapeHTML = function() +{ + return this.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">"); +} + +String.prototype.collapseWhitespace = function() +{ + return this.replace(/[\s\xA0]+/g, " "); +} + +String.prototype.trimLeadingWhitespace = function() +{ + return this.replace(/^[\s\xA0]+/g, ""); +} + +String.prototype.trimTrailingWhitespace = function() +{ + return this.replace(/[\s\xA0]+$/g, ""); +} + +String.prototype.trimWhitespace = function() +{ + return this.replace(/^[\s\xA0]+|[\s\xA0]+$/g, ""); +} + +String.prototype.trimURL = function(baseURLDomain) +{ + var result = this.replace(new RegExp("^http[s]?:\/\/", "i"), ""); + if (baseURLDomain) + result = result.replace(new RegExp("^" + baseURLDomain.escapeForRegExp(), "i"), ""); + return result; +} + +function getStyleTextWithShorthands(style) +{ + var cssText = ""; + var foundProperties = {}; + for (var i = 0; i < style.length; ++i) { + var individualProperty = style[i]; + var shorthandProperty = style.getPropertyShorthand(individualProperty); + var propertyName = (shorthandProperty || individualProperty); + + if (propertyName in foundProperties) + continue; + + if (shorthandProperty) { + var value = getShorthandValue(style, shorthandProperty); + var priority = getShorthandPriority(style, shorthandProperty); + } else { + var value = style.getPropertyValue(individualProperty); + var priority = style.getPropertyPriority(individualProperty); + } + + foundProperties[propertyName] = true; + + cssText += propertyName + ": " + value; + if (priority) + cssText += " !" + priority; + cssText += "; "; + } + + return cssText; +} + +function getShorthandValue(style, shorthandProperty) +{ + var value = style.getPropertyValue(shorthandProperty); + if (!value) { + // Some shorthands (like border) return a null value, so compute a shorthand value. + // FIXME: remove this when http://bugs.webkit.org/show_bug.cgi?id=15823 is fixed. + + var foundProperties = {}; + for (var i = 0; i < style.length; ++i) { + var individualProperty = style[i]; + if (individualProperty in foundProperties || style.getPropertyShorthand(individualProperty) !== shorthandProperty) + continue; + + var individualValue = style.getPropertyValue(individualProperty); + if (style.isPropertyImplicit(individualProperty) || individualValue === "initial") + continue; + + foundProperties[individualProperty] = true; + + if (!value) + value = ""; + else if (value.length) + value += " "; + value += individualValue; + } + } + return value; +} + +function getShorthandPriority(style, shorthandProperty) +{ + var priority = style.getPropertyPriority(shorthandProperty); + if (!priority) { + for (var i = 0; i < style.length; ++i) { + var individualProperty = style[i]; + if (style.getPropertyShorthand(individualProperty) !== shorthandProperty) + continue; + priority = style.getPropertyPriority(individualProperty); + break; + } + } + return priority; +} + +function getLonghandProperties(style, shorthandProperty) +{ + var properties = []; + var foundProperties = {}; + + for (var i = 0; i < style.length; ++i) { + var individualProperty = style[i]; + if (individualProperty in foundProperties || style.getPropertyShorthand(individualProperty) !== shorthandProperty) + continue; + foundProperties[individualProperty] = true; + properties.push(individualProperty); + } + + return properties; +} + +function getUniqueStyleProperties(style) +{ + var properties = []; + var foundProperties = {}; + + for (var i = 0; i < style.length; ++i) { + var property = style[i]; + if (property in foundProperties) + continue; + foundProperties[property] = true; + properties.push(property); + } + + return properties; +} + +function isNodeWhitespace() +{ + if (!this || this.nodeType !== Node.TEXT_NODE) + return false; + if (!this.nodeValue.length) + return true; + return this.nodeValue.match(/^[\s\xA0]+$/); +} + +function nodeTypeName() +{ + if (!this) + return "(unknown)"; + + switch (this.nodeType) { + case Node.ELEMENT_NODE: return "Element"; + case Node.ATTRIBUTE_NODE: return "Attribute"; + case Node.TEXT_NODE: return "Text"; + case Node.CDATA_SECTION_NODE: return "Character Data"; + case Node.ENTITY_REFERENCE_NODE: return "Entity Reference"; + case Node.ENTITY_NODE: return "Entity"; + case Node.PROCESSING_INSTRUCTION_NODE: return "Processing Instruction"; + case Node.COMMENT_NODE: return "Comment"; + case Node.DOCUMENT_NODE: return "Document"; + case Node.DOCUMENT_TYPE_NODE: return "Document Type"; + case Node.DOCUMENT_FRAGMENT_NODE: return "Document Fragment"; + case Node.NOTATION_NODE: return "Notation"; + } + + return "(unknown)"; +} + +function nodeDisplayName() +{ + if (!this) + return ""; + + switch (this.nodeType) { + case Node.DOCUMENT_NODE: + return "Document"; + + case Node.ELEMENT_NODE: + var name = "<" + this.nodeName.toLowerCase(); + + if (this.hasAttributes()) { + var value = this.getAttribute("id"); + if (value) + name += " id=\"" + value + "\""; + value = this.getAttribute("class"); + if (value) + name += " class=\"" + value + "\""; + if (this.nodeName.toLowerCase() === "a") { + value = this.getAttribute("name"); + if (value) + name += " name=\"" + value + "\""; + value = this.getAttribute("href"); + if (value) + name += " href=\"" + value + "\""; + } else if (this.nodeName.toLowerCase() === "img") { + value = this.getAttribute("src"); + if (value) + name += " src=\"" + value + "\""; + } else if (this.nodeName.toLowerCase() === "iframe") { + value = this.getAttribute("src"); + if (value) + name += " src=\"" + value + "\""; + } else if (this.nodeName.toLowerCase() === "input") { + value = this.getAttribute("name"); + if (value) + name += " name=\"" + value + "\""; + value = this.getAttribute("type"); + if (value) + name += " type=\"" + value + "\""; + } else if (this.nodeName.toLowerCase() === "form") { + value = this.getAttribute("action"); + if (value) + name += " action=\"" + value + "\""; + } + } + + return name + ">"; + + case Node.TEXT_NODE: + if (isNodeWhitespace.call(this)) + return "(whitespace)"; + return "\"" + this.nodeValue + "\""; + + case Node.COMMENT_NODE: + return "<!--" + this.nodeValue + "-->"; + + case Node.DOCUMENT_TYPE_NODE: + var docType = "<!DOCTYPE " + this.nodeName; + if (this.publicId) { + docType += " PUBLIC \"" + this.publicId + "\""; + if (this.systemId) + docType += " \"" + this.systemId + "\""; + } else if (this.systemId) + docType += " SYSTEM \"" + this.systemId + "\""; + if (this.internalSubset) + docType += " [" + this.internalSubset + "]"; + return docType + ">"; + } + + return this.nodeName.toLowerCase().collapseWhitespace(); +} + +function nodeContentPreview() +{ + if (!this || !this.hasChildNodes || !this.hasChildNodes()) + return ""; + + var limit = 0; + var preview = ""; + + // always skip whitespace here + var currentNode = traverseNextNode.call(this, true, this); + while (currentNode) { + if (currentNode.nodeType === Node.TEXT_NODE) + preview += currentNode.nodeValue.escapeHTML(); + else + preview += nodeDisplayName.call(currentNode).escapeHTML(); + + currentNode = traverseNextNode.call(currentNode, true, this); + + if (++limit > 4) { + preview += "…"; // ellipsis + break; + } + } + + return preview.collapseWhitespace(); +} + +function objectsAreSame(a, b) +{ + // FIXME: Make this more generic so is works with any wrapped object, not just nodes. + // This function is used to compare nodes that might be JSInspectedObjectWrappers, since + // JavaScript equality is not true for JSInspectedObjectWrappers of the same node wrapped + // with different global ExecStates, we use isSameNode to compare them. + if (a === b) + return true; + if (!a || !b) + return false; + if (a.isSameNode && b.isSameNode) + return a.isSameNode(b); + return false; +} + +function isAncestorNode(ancestor) +{ + if (!this || !ancestor) + return false; + + var currentNode = ancestor.parentNode; + while (currentNode) { + if (objectsAreSame(this, currentNode)) + return true; + currentNode = currentNode.parentNode; + } + + return false; +} + +function isDescendantNode(descendant) +{ + return isAncestorNode.call(descendant, this); +} + +function firstCommonNodeAncestor(node) +{ + if (!this || !node) + return; + + var node1 = this.parentNode; + var node2 = node.parentNode; + + if ((!node1 || !node2) || !objectsAreSame(node1, node2)) + return null; + + while (node1 && node2) { + if (!node1.parentNode || !node2.parentNode) + break; + if (!objectsAreSame(node1, node2)) + break; + + node1 = node1.parentNode; + node2 = node2.parentNode; + } + + return node1; +} + +function nextSiblingSkippingWhitespace() +{ + if (!this) + return; + var node = this.nextSibling; + while (node && node.nodeType === Node.TEXT_NODE && isNodeWhitespace.call(node)) + node = node.nextSibling; + return node; +} + +function previousSiblingSkippingWhitespace() +{ + if (!this) + return; + var node = this.previousSibling; + while (node && node.nodeType === Node.TEXT_NODE && isNodeWhitespace.call(node)) + node = node.previousSibling; + return node; +} + +function firstChildSkippingWhitespace() +{ + if (!this) + return; + var node = this.firstChild; + while (node && node.nodeType === Node.TEXT_NODE && isNodeWhitespace.call(node)) + node = nextSiblingSkippingWhitespace.call(node); + return node; +} + +function lastChildSkippingWhitespace() +{ + if (!this) + return; + var node = this.lastChild; + while (node && node.nodeType === Node.TEXT_NODE && isNodeWhitespace.call(node)) + node = previousSiblingSkippingWhitespace.call(node); + return node; +} + +function traverseNextNode(skipWhitespace, stayWithin) +{ + if (!this) + return; + + var node = skipWhitespace ? firstChildSkippingWhitespace.call(this) : this.firstChild; + if (node) + return node; + + if (stayWithin && objectsAreSame(this, stayWithin)) + return null; + + node = skipWhitespace ? nextSiblingSkippingWhitespace.call(this) : this.nextSibling; + if (node) + return node; + + node = this; + while (node && !(skipWhitespace ? nextSiblingSkippingWhitespace.call(node) : node.nextSibling) && (!stayWithin || !node.parentNode || !objectsAreSame(node.parentNode, stayWithin))) + node = node.parentNode; + if (!node) + return null; + + return skipWhitespace ? nextSiblingSkippingWhitespace.call(node) : node.nextSibling; +} + +function traversePreviousNode(skipWhitespace, stayWithin) +{ + if (!this) + return; + if (stayWithin && objectsAreSame(this, stayWithin)) + return null; + var node = skipWhitespace ? previousSiblingSkippingWhitespace.call(this) : this.previousSibling; + while (node && (skipWhitespace ? lastChildSkippingWhitespace.call(node) : node.lastChild) ) + node = skipWhitespace ? lastChildSkippingWhitespace.call(node) : node.lastChild; + if (node) + return node; + return this.parentNode; +} + +function onlyTextChild(ignoreWhitespace) +{ + if (!this) + return null; + + var firstChild = ignoreWhitespace ? firstChildSkippingWhitespace.call(this) : this.firstChild; + if (!firstChild || firstChild.nodeType !== Node.TEXT_NODE) + return null; + + var sibling = ignoreWhitespace ? nextSiblingSkippingWhitespace.call(firstChild) : firstChild.nextSibling; + return sibling ? null : firstChild; +} + +function nodeTitleInfo(hasChildren, linkify) +{ + var info = {title: "", hasChildren: hasChildren}; + + switch (this.nodeType) { + case Node.DOCUMENT_NODE: + info.title = "Document"; + break; + + case Node.ELEMENT_NODE: + info.title = "<span class=\"webkit-html-tag\"><" + this.nodeName.toLowerCase().escapeHTML(); + + if (this.hasAttributes()) { + for (var i = 0; i < this.attributes.length; ++i) { + var attr = this.attributes[i]; + info.title += " <span class=\"webkit-html-attribute\"><span class=\"webkit-html-attribute-name\">" + attr.name.escapeHTML() + "</span>=​\""; + + var value = attr.value; + if (linkify && (attr.name === "src" || attr.name === "href")) { + var value = value.replace(/([\/;:\)\]\}])/g, "$1\u200B"); + info.title += linkify(attr.value, value, "webkit-html-attribute-value", this.nodeName.toLowerCase() == "a"); + } else { + var value = value.escapeHTML(); + value = value.replace(/([\/;:\)\]\}])/g, "$1​"); + info.title += "<span class=\"webkit-html-attribute-value\">" + value + "</span>"; + } + info.title += "\"</span>"; + } + } + info.title += "></span>​"; + + // If this element only has a single child that is a text node, + // just show that text and the closing tag inline rather than + // create a subtree for them + + var textChild = onlyTextChild.call(this, Preferences.ignoreWhitespace); + var showInlineText = textChild && textChild.textContent.length < Preferences.maxInlineTextChildLength; + + if (showInlineText) { + info.title += "<span class=\"webkit-html-text-node\">" + textChild.nodeValue.escapeHTML() + "</span>​<span class=\"webkit-html-tag\"></" + this.nodeName.toLowerCase().escapeHTML() + "></span>"; + info.hasChildren = false; + } + break; + + case Node.TEXT_NODE: + if (isNodeWhitespace.call(this)) + info.title = "(whitespace)"; + else + info.title = "\"<span class=\"webkit-html-text-node\">" + this.nodeValue.escapeHTML() + "</span>\""; + break + + case Node.COMMENT_NODE: + info.title = "<span class=\"webkit-html-comment\"><!--" + this.nodeValue.escapeHTML() + "--></span>"; + break; + + case Node.DOCUMENT_TYPE_NODE: + info.title = "<span class=\"webkit-html-doctype\"><!DOCTYPE " + this.nodeName; + if (this.publicId) { + info.title += " PUBLIC \"" + this.publicId + "\""; + if (this.systemId) + info.title += " \"" + this.systemId + "\""; + } else if (this.systemId) + info.title += " SYSTEM \"" + this.systemId + "\""; + if (this.internalSubset) + info.title += " [" + this.internalSubset + "]"; + info.title += "></span>"; + break; + default: + info.title = this.nodeName.toLowerCase().collapseWhitespace().escapeHTML(); + } + + return info; +} + +function getDocumentForNode(node) { + return node.nodeType == Node.DOCUMENT_NODE ? node : node.ownerDocument; +} + +function parentNodeOrFrameElement(node) { + var parent = node.parentNode; + if (parent) + return parent; + + return getDocumentForNode(node).defaultView.frameElement; +} + +function isAncestorIncludingParentFrames(a, b) { + if (objectsAreSame(a, b)) + return false; + for (var node = b; node; node = getDocumentForNode(node).defaultView.frameElement) + if (objectsAreSame(a, node) || isAncestorNode.call(a, node)) + return true; + return false; +} + +Number.secondsToString = function(seconds, formatterFunction, higherResolution) +{ + if (!formatterFunction) + formatterFunction = String.sprintf; + + var ms = seconds * 1000; + if (higherResolution && ms < 1000) + return formatterFunction("%.3fms", ms); + else if (ms < 1000) + return formatterFunction("%.0fms", ms); + + if (seconds < 60) + return formatterFunction("%.2fs", seconds); + + var minutes = seconds / 60; + if (minutes < 60) + return formatterFunction("%.1fmin", minutes); + + var hours = minutes / 60; + if (hours < 24) + return formatterFunction("%.1fhrs", hours); + + var days = hours / 24; + return formatterFunction("%.1f days", days); +} + +Number.bytesToString = function(bytes, formatterFunction) +{ + if (!formatterFunction) + formatterFunction = String.sprintf; + + if (bytes < 1024) + return formatterFunction("%.0fB", bytes); + + var kilobytes = bytes / 1024; + if (kilobytes < 1024) + return formatterFunction("%.2fKB", kilobytes); + + var megabytes = kilobytes / 1024; + return formatterFunction("%.3fMB", megabytes); +} + +Number.constrain = function(num, min, max) +{ + if (num < min) + num = min; + else if (num > max) + num = max; + return num; +} + +HTMLTextAreaElement.prototype.moveCursorToEnd = function() +{ + var length = this.value.length; + this.setSelectionRange(length, length); +} + +Array.prototype.remove = function(value, onlyFirst) +{ + if (onlyFirst) { + var index = this.indexOf(value); + if (index !== -1) + this.splice(index, 1); + return; + } + + var length = this.length; + for (var i = 0; i < length; ++i) { + if (this[i] === value) + this.splice(i, 1); + } +} + +function insertionIndexForObjectInListSortedByFunction(anObject, aList, aFunction) +{ + // indexOf returns (-lowerBound - 1). Taking (-result - 1) works out to lowerBound. + return (-indexOfObjectInListSortedByFunction(anObject, aList, aFunction) - 1); +} + +function indexOfObjectInListSortedByFunction(anObject, aList, aFunction) +{ + var first = 0; + var last = aList.length - 1; + var floor = Math.floor; + var mid, c; + + while (first <= last) { + mid = floor((first + last) / 2); + c = aFunction(anObject, aList[mid]); + + if (c > 0) + first = mid + 1; + else if (c < 0) + last = mid - 1; + else { + // Return the first occurance of an item in the list. + while (mid > 0 && aFunction(anObject, aList[mid - 1]) === 0) + mid--; + first = mid; + break; + } + } + + // By returning 1 less than the negative lower search bound, we can reuse this function + // for both indexOf and insertionIndexFor, with some simple arithmetic. + return (-first - 1); +} + +String.sprintf = function(format) +{ + return String.vsprintf(format, Array.prototype.slice.call(arguments, 1)); +} + +String.tokenizeFormatString = function(format) +{ + var tokens = []; + var substitutionIndex = 0; + + function addStringToken(str) + { + tokens.push({ type: "string", value: str }); + } + + function addSpecifierToken(specifier, precision, substitutionIndex) + { + tokens.push({ type: "specifier", specifier: specifier, precision: precision, substitutionIndex: substitutionIndex }); + } + + var index = 0; + for (var precentIndex = format.indexOf("%", index); precentIndex !== -1; precentIndex = format.indexOf("%", index)) { + addStringToken(format.substring(index, precentIndex)); + index = precentIndex + 1; + + if (format[index] === "%") { + addStringToken("%"); + ++index; + continue; + } + + if (!isNaN(format[index])) { + // The first character is a number, it might be a substitution index. + var number = parseInt(format.substring(index)); + while (!isNaN(format[index])) + ++index; + // If the number is greater than zero and ends with a "$", + // then this is a substitution index. + if (number > 0 && format[index] === "$") { + substitutionIndex = (number - 1); + ++index; + } + } + + var precision = -1; + if (format[index] === ".") { + // This is a precision specifier. If no digit follows the ".", + // then the precision should be zero. + ++index; + precision = parseInt(format.substring(index)); + if (isNaN(precision)) + precision = 0; + while (!isNaN(format[index])) + ++index; + } + + addSpecifierToken(format[index], precision, substitutionIndex); + + ++substitutionIndex; + ++index; + } + + addStringToken(format.substring(index)); + + return tokens; +} + +String.standardFormatters = { + d: function(substitution) + { + substitution = parseInt(substitution); + return !isNaN(substitution) ? substitution : 0; + }, + + f: function(substitution, token) + { + substitution = parseFloat(substitution); + if (substitution && token.precision > -1) + substitution = substitution.toFixed(token.precision); + return !isNaN(substitution) ? substitution : (token.precision > -1 ? Number(0).toFixed(token.precision) : 0); + }, + + s: function(substitution) + { + return substitution; + }, +}; + +String.vsprintf = function(format, substitutions) +{ + return String.format(format, substitutions, String.standardFormatters, "", function(a, b) { return a + b; }).formattedResult; +} + +String.format = function(format, substitutions, formatters, initialValue, append) +{ + if (!format || !substitutions || !substitutions.length) + return { formattedResult: append(initialValue, format), unusedSubstitutions: substitutions }; + + function prettyFunctionName() + { + return "String.format(\"" + format + "\", \"" + substitutions.join("\", \"") + "\")"; + } + + function warn(msg) + { + console.warn(prettyFunctionName() + ": " + msg); + } + + function error(msg) + { + console.error(prettyFunctionName() + ": " + msg); + } + + var result = initialValue; + var tokens = String.tokenizeFormatString(format); + var usedSubstitutionIndexes = {}; + + for (var i = 0; i < tokens.length; ++i) { + var token = tokens[i]; + + if (token.type === "string") { + result = append(result, token.value); + continue; + } + + if (token.type !== "specifier") { + error("Unknown token type \"" + token.type + "\" found."); + continue; + } + + if (token.substitutionIndex >= substitutions.length) { + // If there are not enough substitutions for the current substitutionIndex + // just output the format specifier literally and move on. + error("not enough substitution arguments. Had " + substitutions.length + " but needed " + (token.substitutionIndex + 1) + ", so substitution was skipped."); + result = append(result, "%" + (token.precision > -1 ? token.precision : "") + token.specifier); + continue; + } + + usedSubstitutionIndexes[token.substitutionIndex] = true; + + if (!(token.specifier in formatters)) { + // Encountered an unsupported format character, treat as a string. + warn("unsupported format character \u201C" + token.specifier + "\u201D. Treating as a string."); + result = append(result, substitutions[token.substitutionIndex]); + continue; + } + + result = append(result, formatters[token.specifier](substitutions[token.substitutionIndex], token)); + } + + var unusedSubstitutions = []; + for (var i = 0; i < substitutions.length; ++i) { + if (i in usedSubstitutionIndexes) + continue; + unusedSubstitutions.push(substitutions[i]); + } + + return { formattedResult: result, unusedSubstitutions: unusedSubstitutions }; +} diff --git a/chrome/tools/test/reference_build/chrome_linux/themes/default.pak b/chrome/tools/test/reference_build/chrome_linux/themes/default.pak Binary files differnew file mode 100644 index 0000000..73914be --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/themes/default.pak |