diff options
author | Ben Murdoch <benm@google.com> | 2009-08-11 17:01:47 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2009-08-11 18:21:02 +0100 |
commit | 0bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5 (patch) | |
tree | 2943df35f62d885c89d01063cc528dd73b480fea /WebCore/inspector/front-end | |
parent | 7e7a70bfa49a1122b2597a1e6367d89eb4035eca (diff) | |
download | external_webkit-0bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5.zip external_webkit-0bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5.tar.gz external_webkit-0bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5.tar.bz2 |
Merge in WebKit r47029.
Diffstat (limited to 'WebCore/inspector/front-end')
67 files changed, 4658 insertions, 894 deletions
diff --git a/WebCore/inspector/front-end/Breakpoint.js b/WebCore/inspector/front-end/Breakpoint.js index 8611cf5..347df60 100644 --- a/WebCore/inspector/front-end/Breakpoint.js +++ b/WebCore/inspector/front-end/Breakpoint.js @@ -29,6 +29,7 @@ WebInspector.Breakpoint = function(url, line, sourceID) this.line = line; this.sourceID = sourceID; this._enabled = true; + this._sourceText = ""; } WebInspector.Breakpoint.prototype = { @@ -48,6 +49,28 @@ WebInspector.Breakpoint.prototype = { this.dispatchEventToListeners("enabled"); else this.dispatchEventToListeners("disabled"); + }, + + get sourceText() + { + return this._sourceText; + }, + + set sourceText(text) + { + this._sourceText = text; + this.dispatchEventToListeners("text-changed"); + }, + + get label() + { + var displayName = (this.url ? WebInspector.displayNameForURL(this.url) : WebInspector.UIString("(program)")); + return displayName + ":" + this.line; + }, + + get id() + { + return this.sourceID + ":" + this.line; } } diff --git a/WebCore/inspector/front-end/BreakpointsSidebarPane.js b/WebCore/inspector/front-end/BreakpointsSidebarPane.js index 2b8f3cd..14f8c06 100644 --- a/WebCore/inspector/front-end/BreakpointsSidebarPane.js +++ b/WebCore/inspector/front-end/BreakpointsSidebarPane.js @@ -27,7 +27,10 @@ WebInspector.BreakpointsSidebarPane = function() { WebInspector.SidebarPane.call(this, WebInspector.UIString("Breakpoints")); - this.breakpoints = []; + this.breakpoints = {}; + + this.listElement = document.createElement("ol"); + this.listElement.className = "breakpoint-list"; this.emptyElement = document.createElement("div"); this.emptyElement.className = "info"; @@ -39,11 +42,21 @@ WebInspector.BreakpointsSidebarPane = function() WebInspector.BreakpointsSidebarPane.prototype = { addBreakpoint: function(breakpoint) { - this.breakpoints.push(breakpoint); + if (this.breakpoints[breakpoint.id]) + return; + + this.breakpoints[breakpoint.id] = breakpoint; + breakpoint.addEventListener("enabled", this._breakpointEnableChanged, this); breakpoint.addEventListener("disabled", this._breakpointEnableChanged, this); + breakpoint.addEventListener("text-changed", this._breakpointTextChanged, this); - // FIXME: add to the breakpoints UI. + this._appendBreakpointElement(breakpoint); + + if (this.emptyElement.parentElement) { + this.bodyElement.removeChild(this.emptyElement); + this.bodyElement.appendChild(this.listElement); + } if (!InspectorController.debuggerEnabled() || !breakpoint.sourceID) return; @@ -52,13 +65,73 @@ WebInspector.BreakpointsSidebarPane.prototype = { InspectorController.addBreakpoint(breakpoint.sourceID, breakpoint.line); }, + _appendBreakpointElement: function(breakpoint) + { + function checkboxClicked() + { + breakpoint.enabled = !breakpoint.enabled; + } + + function labelClicked() + { + var script = WebInspector.panels.scripts.scriptOrResourceForID(breakpoint.sourceID); + if (script) + WebInspector.panels.scripts.showScript(script, breakpoint.line); + } + + var breakpointElement = document.createElement("li"); + breakpoint._breakpointListElement = breakpointElement; + breakpointElement._breakpointObject = breakpoint; + + var checkboxElement = document.createElement("input"); + checkboxElement.className = "checkbox-elem"; + checkboxElement.type = "checkbox"; + checkboxElement.checked = breakpoint.enabled; + checkboxElement.addEventListener("click", checkboxClicked, false); + breakpointElement.appendChild(checkboxElement); + + var labelElement = document.createElement("a"); + labelElement.textContent = breakpoint.label; + labelElement.addEventListener("click", labelClicked, false); + breakpointElement.appendChild(labelElement); + + var sourceTextElement = document.createElement("div"); + sourceTextElement.textContent = breakpoint.sourceText; + sourceTextElement.className = "source-text"; + breakpointElement.appendChild(sourceTextElement); + + var currentElement = this.listElement.firstChild; + while (currentElement) { + var currentBreak = currentElement._breakpointObject; + if (currentBreak.url > breakpoint.url) { + this.listElement.insertBefore(breakpointElement, currentElement); + return; + } else if (currentBreak.url == breakpoint.url && currentBreak.line > breakpoint.line) { + this.listElement.insertBefore(breakpointElement, currentElement); + return; + } + currentElement = currentElement.nextSibling; + } + this.listElement.appendChild(breakpointElement); + }, + removeBreakpoint: function(breakpoint) { - this.breakpoints.remove(breakpoint); + if (!this.breakpoints[breakpoint.id]) + return; + delete this.breakpoints[breakpoint.id]; + breakpoint.removeEventListener("enabled", null, this); breakpoint.removeEventListener("disabled", null, this); + breakpoint.removeEventListener("text-changed", null, this); - // FIXME: remove from the breakpoints UI. + var element = breakpoint._breakpointListElement; + element.parentElement.removeChild(element); + + if (!this.listElement.firstChild) { + this.bodyElement.removeChild(this.listElement); + this.bodyElement.appendChild(this.emptyElement); + } if (!InspectorController.debuggerEnabled() || !breakpoint.sourceID) return; @@ -70,7 +143,8 @@ WebInspector.BreakpointsSidebarPane.prototype = { { var breakpoint = event.target; - // FIXME: change the breakpoint checkbox state in the UI. + var checkbox = breakpoint._breakpointListElement.firstChild; + checkbox.checked = breakpoint.enabled; if (!InspectorController.debuggerEnabled() || !breakpoint.sourceID) return; @@ -79,6 +153,14 @@ WebInspector.BreakpointsSidebarPane.prototype = { InspectorController.addBreakpoint(breakpoint.sourceID, breakpoint.line); else InspectorController.removeBreakpoint(breakpoint.sourceID, breakpoint.line); + }, + + _breakpointTextChanged: function(event) + { + var breakpoint = event.target; + + var sourceTextElement = breakpoint._breakpointListElement.firstChild.nextSibling.nextSibling; + sourceTextElement.textContent = breakpoint.sourceText; } } diff --git a/WebCore/inspector/front-end/CallStackSidebarPane.js b/WebCore/inspector/front-end/CallStackSidebarPane.js index a2c8bed..c08cc7a 100644 --- a/WebCore/inspector/front-end/CallStackSidebarPane.js +++ b/WebCore/inspector/front-end/CallStackSidebarPane.js @@ -26,6 +26,16 @@ WebInspector.CallStackSidebarPane = function() { WebInspector.SidebarPane.call(this, WebInspector.UIString("Call Stack")); + + this._shortcuts = {}; + + var shortcut = WebInspector.KeyboardShortcut.makeKey(WebInspector.KeyboardShortcut.KeyCodes.Period, + WebInspector.KeyboardShortcut.Modifiers.Ctrl); + this._shortcuts[shortcut] = this._selectNextCallFrameOnStack.bind(this); + + var shortcut = WebInspector.KeyboardShortcut.makeKey(WebInspector.KeyboardShortcut.KeyCodes.Comma, + WebInspector.KeyboardShortcut.Modifiers.Ctrl); + this._shortcuts[shortcut] = this._selectPreviousCallFrameOnStack.bind(this); } WebInspector.CallStackSidebarPane.prototype = { @@ -100,6 +110,53 @@ WebInspector.CallStackSidebarPane.prototype = { this.dispatchEventToListeners("call frame selected"); }, + handleKeyEvent: function(event) + { + var shortcut = WebInspector.KeyboardShortcut.makeKeyFromEvent(event); + var handler = this._shortcuts[shortcut]; + if (handler) { + handler(event); + event.preventDefault(); + event.handled = true; + } + }, + + _selectNextCallFrameOnStack: function() + { + var index = this._selectedCallFrameIndex(); + if (index == -1) + return; + this._selectedPlacardByIndex(index + 1); + }, + + _selectPreviousCallFrameOnStack: function() + { + var index = this._selectedCallFrameIndex(); + if (index == -1) + return; + this._selectedPlacardByIndex(index - 1); + }, + + _selectedPlacardByIndex: function(index) + { + if (index < 0 || index >= this.placards.length) + return; + var placard = this.placards[index]; + this.selectedCallFrame = placard.callFrame + }, + + _selectedCallFrameIndex: function() + { + if (!this._selectedCallFrame) + return -1; + for (var i = 0; i < this.placards.length; ++i) { + var placard = this.placards[i]; + if (placard.callFrame === this._selectedCallFrame) + return i; + } + return -1; + }, + _placardSelected: function(event) { var placardElement = event.target.enclosingNodeOrSelfWithClass("placard"); diff --git a/WebCore/inspector/front-end/Callback.js b/WebCore/inspector/front-end/Callback.js new file mode 100644 index 0000000..8ae7f95 --- /dev/null +++ b/WebCore/inspector/front-end/Callback.js @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2009 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. + * * Neither the name of Google Inc. 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 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. + */ + +WebInspector.Callback = function() +{ + this._lastCallbackId = 1; + this._callbacks = {}; +} + +WebInspector.Callback.prototype = { + wrap: function(callback) + { + var callbackId = this._lastCallbackId++; + this._callbacks[callbackId] = callback || function() {}; + return callbackId; + }, + + 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]; + } +} + +WebInspector.Callback._INSTANCE = new WebInspector.Callback(); +WebInspector.Callback.wrap = WebInspector.Callback._INSTANCE.wrap.bind(WebInspector.Callback._INSTANCE); +WebInspector.Callback.processCallback = WebInspector.Callback._INSTANCE.processCallback.bind(WebInspector.Callback._INSTANCE); diff --git a/WebCore/inspector/front-end/ChangesView.js b/WebCore/inspector/front-end/ChangesView.js new file mode 100644 index 0000000..802fdba --- /dev/null +++ b/WebCore/inspector/front-end/ChangesView.js @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2009 Joseph Pecoraro + * + * 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.ChangesView = function(drawer) +{ + WebInspector.View.call(this); + this.element.innerHTML = "<div style=\"bottom:25%;color:rgb(192,192,192);font-size:12px;height:65px;left:0px;margin:auto;position:absolute;right:0px;text-align:center;top:0px;\"><h1>Not Implemented Yet</h1></div>"; + + this.drawer = drawer; + + this.clearButton = document.createElement("button"); + this.clearButton.id = "clear-changes-status-bar-item"; + this.clearButton.title = WebInspector.UIString("Clear changes log."); + this.clearButton.className = "status-bar-item"; + this.clearButton.addEventListener("click", this._clearButtonClicked.bind(this), false); + + this.toggleChangesButton = document.getElementById("changes-status-bar-item"); + this.toggleChangesButton.title = WebInspector.UIString("Show changes view."); + this.toggleChangesButton.addEventListener("click", this._toggleChangesButtonClicked.bind(this), false); + var anchoredStatusBar = document.getElementById("anchored-status-bar-items"); + anchoredStatusBar.appendChild(this.toggleChangesButton); +} + +WebInspector.ChangesView.prototype = { + _clearButtonClicked: function() + { + // Not Implemented Yet + }, + + _toggleChangesButtonClicked: function() + { + this.drawer.visibleView = this; + }, + + attach: function(mainElement, statusBarElement) + { + mainElement.appendChild(this.element); + statusBarElement.appendChild(this.clearButton); + }, + + show: function() + { + this.toggleChangesButton.addStyleClass("toggled-on"); + this.toggleChangesButton.title = WebInspector.UIString("Hide changes view."); + }, + + hide: function() + { + this.toggleChangesButton.removeStyleClass("toggled-on"); + this.toggleChangesButton.title = WebInspector.UIString("Show changes view."); + } +} + +WebInspector.ChangesView.prototype.__proto__ = WebInspector.View.prototype; diff --git a/WebCore/inspector/front-end/Color.js b/WebCore/inspector/front-end/Color.js new file mode 100644 index 0000000..7968ee4 --- /dev/null +++ b/WebCore/inspector/front-end/Color.js @@ -0,0 +1,671 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009 Joseph Pecoraro + * + * 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.Color = function(str) +{ + this.value = str; + this.parse(); +} + +WebInspector.Color.prototype = { + get shorthex() + { + if ("_short" in this) + return this._short; + + if (!this.simple) + return null; + + var hex = this.hex; + if (hex.charAt(0) === hex.charAt(1) && hex.charAt(2) === hex.charAt(3) && hex.charAt(4) === hex.charAt(5)) + this._short = hex.charAt(0) + hex.charAt(2) + hex.charAt(4); + else + this._short = hex; + + return this._short; + }, + + get hex() + { + if (!this.simple) + return null; + + return this._hex; + }, + + set hex(x) + { + this._hex = x; + }, + + get rgb() + { + if ("_rgb" in this) + return this._rgb; + + if (this.simple) + this._rgb = this.hexToRgb(this.hex); + else { + var rgba = this.rgba; + this._rgb = [rgba[0], rgba[1], rgba[2]]; + } + + return this._rgb; + }, + + set rgb(x) + { + this._rgb = x; + }, + + get hsl() + { + if ("_hsl" in this) + return this._hsl; + + this._hsl = this.rgbToHsl(this.rgb); + return this._hsl; + }, + + set hsl(x) + { + this._hsl = x; + }, + + get nickname() + { + if (typeof this._nickname !== "undefined") // would be set on parse if there was a nickname + return this._nickname; + else + return null; + }, + + set nickname(x) + { + this._nickname = x; + }, + + get rgba() + { + return this._rgba; + }, + + set rgba(x) + { + this._rgba = x; + }, + + get hsla() + { + return this._hsla; + }, + + set hsla(x) + { + this._hsla = x; + }, + + hasShortHex: function() + { + var shorthex = this.shorthex; + return (shorthex && shorthex.length === 3); + }, + + toRgb: function() + { + return "rgb(" + this.rgb.join(", ") + ")"; + }, + + toHsl: function() + { + var hsl = this.hsl; + return "hsl(" + hsl[0] + ", " + hsl[1] + "%, " + hsl[2] + "%)"; + }, + + toShortHex: function() + { + return "#" + this.shorthex; + }, + + toHex: function() + { + return "#" + this.hex; + }, + + toRgba: function() + { + return "rgba(" + this.rgba.join(", ") + ")"; + }, + + toHsla: function() + { + var hsla = this.hsla; + return "hsla(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%, " + hsla[3] + ")"; + }, + + toNickname: function() + { + return this.nickname; + }, + + rgbToHex: function(rgb) + { + var r = parseInt(rgb[0]).toString(16); + var g = parseInt(rgb[1]).toString(16); + var b = parseInt(rgb[2]).toString(16); + if (r.length === 1) + r = "0" + r; + if (g.length === 1) + g = "0" + g; + if (b.length === 1) + b = "0" + b; + + return (r + g + b).toUpperCase(); + }, + + hexToRgb: function(hex) + { + var r = parseInt(hex.substring(0,2), 16); + var g = parseInt(hex.substring(2,4), 16); + var b = parseInt(hex.substring(4,6), 16); + + return [r, g, b]; + }, + + rgbToHsl: function(rgb) + { + var r = parseInt(rgb[0]) / 255; + var g = parseInt(rgb[1]) / 255; + var b = parseInt(rgb[2]) / 255; + var max = Math.max(r, g, b); + var min = Math.min(r, g, b); + var diff = max - min; + var add = max + min; + + if (min === max) + var h = 0; + else if (r === max) + var h = ((60 * (g - b) / diff) + 360) % 360; + else if (g === max) + var h = (60 * (b - r) / diff) + 120; + else + var h = (60 * (r - g) / diff) + 240; + + var l = 0.5 * add; + + if (l === 0) + var s = 0; + else if (l === 1) + var s = 1; + else if (l <= 0.5) + var s = diff / add; + else + var s = diff / (2 - add); + + h = Math.round(h); + s = Math.round(s*100); + l = Math.round(l*100); + + return [h, s, l]; + }, + + hslToRgb: function(hsl) + { + var h = parseFloat(hsl[0]) / 360; + var s = parseFloat(hsl[1]) / 100; + var l = parseFloat(hsl[2]) / 100; + + if (l <= 0.5) + var q = l * (1 + s); + else + var q = l + s - (l * s); + + var p = 2 * l - q; + + var tr = h + (1 / 3); + var tg = h; + var tb = h - (1 / 3); + + var r = Math.round(hueToRgb(p, q, tr) * 255); + var g = Math.round(hueToRgb(p, q, tg) * 255); + var b = Math.round(hueToRgb(p, q, tb) * 255); + return [r, g, b]; + + function hueToRgb(p, q, h) { + if (h < 0) + h += 1; + else if (h > 1) + h -= 1; + + if ((h * 6) < 1) + return p + (q - p) * h * 6; + else if ((h * 2) < 1) + return q; + else if ((h * 3) < 2) + return p + (q - p) * ((2 / 3) - h) * 6; + else + return p; + } + }, + + rgbaToHsla: function(rgba) + { + var alpha = rgba[3]; + var hsl = this.rgbToHsl(rgba) + hsl.push(alpha); + return hsl; + }, + + hslaToRgba: function(hsla) + { + var alpha = hsla[3]; + var rgb = this.hslToRgb(hsla); + rgb.push(alpha); + return rgb; + }, + + parse: function() + { + // Special Values - Advanced but Must Be Parsed First - transparent + var value = this.value.toLowerCase().replace(/%|\s+/g, ""); + if (value in WebInspector.Color.AdvancedNickNames) { + this.mode = "nickname"; + var set = WebInspector.Color.AdvancedNickNames[value]; + this.simple = false; + this.rgba = set[0]; + this.hsla = set[1]; + this.nickname = set[2]; + this.alpha = set[0][3]; + return; + } + + // Simple - #hex, rgb(), nickname, hsl() + var simple = /^(?:#([0-9a-f]{3,6})|rgb\(([^)]+)\)|(\w+)|hsl\(([^)]+)\))$/i; + var match = this.value.match(simple); + if (match) { + this.simple = true; + + if (match[1]) { // hex + var hex = match[1].toUpperCase(); + if (hex.length === 3) { + this.mode = "shorthex"; + this.hex = hex.charAt(0) + hex.charAt(0) + hex.charAt(1) + hex.charAt(1) + hex.charAt(2) + hex.charAt(2); + } else { + this.mode = "hex"; + this.hex = hex; + } + } else if (match[2]) { // rgb + this.mode = "rgb"; + var rgb = match[2].split(/\s*,\s*/); + this.rgb = rgb; + this.hex = this.rgbToHex(rgb); + } else if (match[3]) { // nickname + var nickname = match[3].toLowerCase(); + if (nickname in WebInspector.Color.Nicknames) { + this.mode = "nickname"; + this.hex = WebInspector.Color.Nicknames[nickname]; + } else // unknown name + throw("unknown color name"); + } else if (match[4]) { // hsl + this.mode = "hsl"; + var hsl = match[4].replace(/%g/, "").split(/\s*,\s*/); + this.hsl = hsl; + this.rgb = this.hslToRgb(hsl); + this.hex = this.rgbToHex(this.rgb); + } + + // Fill in the values if this is a known hex color + var hex = this.hex; + if (hex && hex in WebInspector.Color.HexTable) { + var set = WebInspector.Color.HexTable[hex]; + this.rgb = set[0]; + this.hsl = set[1]; + this.nickname = set[2]; + } + + return; + } + + // Advanced - rgba(), hsla() + var advanced = /^(?:rgba\(([^)]+)\)|hsla\(([^)]+)\))$/; + match = this.value.match(advanced); + if (match) { + this.simple = false; + if (match[1]) { // rgba + this.mode = "rgba"; + this.rgba = match[1].split(/\s*,\s*/); + this.hsla = this.rgbaToHsla(this.rgba); + this.alpha = this.rgba[3]; + } else if (match[2]) { // hsla + this.mode = "hsla"; + this.hsla = match[2].replace(/%/g, "").split(/\s*,\s*/); + this.rgba = this.hslaToRgba(this.hsla); + this.alpha = this.hsla[3]; + } + + return; + } + + // Could not parse as a valid color + throw("could not parse color"); + } +} + +// Simple Values: [rgb, hsl, nickname] +WebInspector.Color.HexTable = { + "000000": [[0, 0, 0], [0, 0, 0], "black"], + "000080": [[0, 0, 128], [240, 100, 25], "navy"], + "00008B": [[0, 0, 139], [240, 100, 27], "darkBlue"], + "0000CD": [[0, 0, 205], [240, 100, 40], "mediumBlue"], + "0000FF": [[0, 0, 255], [240, 100, 50], "blue"], + "006400": [[0, 100, 0], [120, 100, 20], "darkGreen"], + "008000": [[0, 128, 0], [120, 100, 25], "green"], + "008080": [[0, 128, 128], [180, 100, 25], "teal"], + "008B8B": [[0, 139, 139], [180, 100, 27], "darkCyan"], + "00BFFF": [[0, 191, 255], [195, 100, 50], "deepSkyBlue"], + "00CED1": [[0, 206, 209], [181, 100, 41], "darkTurquoise"], + "00FA9A": [[0, 250, 154], [157, 100, 49], "mediumSpringGreen"], + "00FF00": [[0, 255, 0], [120, 100, 50], "lime"], + "00FF7F": [[0, 255, 127], [150, 100, 50], "springGreen"], + "00FFFF": [[0, 255, 255], [180, 100, 50], "cyan"], + "191970": [[25, 25, 112], [240, 64, 27], "midnightBlue"], + "1E90FF": [[30, 144, 255], [210, 100, 56], "dodgerBlue"], + "20B2AA": [[32, 178, 170], [177, 70, 41], "lightSeaGreen"], + "228B22": [[34, 139, 34], [120, 61, 34], "forestGreen"], + "2E8B57": [[46, 139, 87], [146, 50, 36], "seaGreen"], + "2F4F4F": [[47, 79, 79], [180, 25, 25], "darkSlateGray"], + "32CD32": [[50, 205, 50], [120, 61, 50], "limeGreen"], + "3CB371": [[60, 179, 113], [147, 50, 47], "mediumSeaGreen"], + "40E0D0": [[64, 224, 208], [174, 72, 56], "turquoise"], + "4169E1": [[65, 105, 225], [225, 73, 57], "royalBlue"], + "4682B4": [[70, 130, 180], [207, 44, 49], "steelBlue"], + "483D8B": [[72, 61, 139], [248, 39, 39], "darkSlateBlue"], + "48D1CC": [[72, 209, 204], [178, 60, 55], "mediumTurquoise"], + "4B0082": [[75, 0, 130], [275, 100, 25], "indigo"], + "556B2F": [[85, 107, 47], [82, 39, 30], "darkOliveGreen"], + "5F9EA0": [[95, 158, 160], [182, 25, 50], "cadetBlue"], + "6495ED": [[100, 149, 237], [219, 79, 66], "cornflowerBlue"], + "66CDAA": [[102, 205, 170], [160, 51, 60], "mediumAquaMarine"], + "696969": [[105, 105, 105], [0, 0, 41], "dimGray"], + "6A5ACD": [[106, 90, 205], [248, 53, 58], "slateBlue"], + "6B8E23": [[107, 142, 35], [80, 60, 35], "oliveDrab"], + "708090": [[112, 128, 144], [210, 13, 50], "slateGray"], + "778899": [[119, 136, 153], [210, 14, 53], "lightSlateGray"], + "7B68EE": [[123, 104, 238], [249, 80, 67], "mediumSlateBlue"], + "7CFC00": [[124, 252, 0], [90, 100, 49], "lawnGreen"], + "7FFF00": [[127, 255, 0], [90, 100, 50], "chartreuse"], + "7FFFD4": [[127, 255, 212], [160, 100, 75], "aquamarine"], + "800000": [[128, 0, 0], [0, 100, 25], "maroon"], + "800080": [[128, 0, 128], [300, 100, 25], "purple"], + "808000": [[128, 128, 0], [60, 100, 25], "olive"], + "808080": [[128, 128, 128], [0, 0, 50], "gray"], + "87CEEB": [[135, 206, 235], [197, 71, 73], "skyBlue"], + "87CEFA": [[135, 206, 250], [203, 92, 75], "lightSkyBlue"], + "8A2BE2": [[138, 43, 226], [271, 76, 53], "blueViolet"], + "8B0000": [[139, 0, 0], [0, 100, 27], "darkRed"], + "8B008B": [[139, 0, 139], [300, 100, 27], "darkMagenta"], + "8B4513": [[139, 69, 19], [25, 76, 31], "saddleBrown"], + "8FBC8F": [[143, 188, 143], [120, 25, 65], "darkSeaGreen"], + "90EE90": [[144, 238, 144], [120, 73, 75], "lightGreen"], + "9370D8": [[147, 112, 219], [260, 60, 65], "mediumPurple"], + "9400D3": [[148, 0, 211], [282, 100, 41], "darkViolet"], + "98FB98": [[152, 251, 152], [120, 93, 79], "paleGreen"], + "9932CC": [[153, 50, 204], [280, 61, 50], "darkOrchid"], + "9ACD32": [[154, 205, 50], [80, 61, 50], "yellowGreen"], + "A0522D": [[160, 82, 45], [19, 56, 40], "sienna"], + "A52A2A": [[165, 42, 42], [0, 59, 41], "brown"], + "A9A9A9": [[169, 169, 169], [0, 0, 66], "darkGray"], + "ADD8E6": [[173, 216, 230], [195, 53, 79], "lightBlue"], + "ADFF2F": [[173, 255, 47], [84, 100, 59], "greenYellow"], + "AFEEEE": [[175, 238, 238], [180, 65, 81], "paleTurquoise"], + "B0C4DE": [[176, 196, 222], [214, 41, 78], "lightSteelBlue"], + "B0E0E6": [[176, 224, 230], [187, 52, 80], "powderBlue"], + "B22222": [[178, 34, 34], [0, 68, 42], "fireBrick"], + "B8860B": [[184, 134, 11], [43, 89, 38], "darkGoldenRod"], + "BA55D3": [[186, 85, 211], [288, 59, 58], "mediumOrchid"], + "BC8F8F": [[188, 143, 143], [0, 25, 65], "rosyBrown"], + "BDB76B": [[189, 183, 107], [56, 38, 58], "darkKhaki"], + "C0C0C0": [[192, 192, 192], [0, 0, 75], "silver"], + "C71585": [[199, 21, 133], [322, 81, 43], "mediumVioletRed"], + "CD5C5C": [[205, 92, 92], [0, 53, 58], "indianRed"], + "CD853F": [[205, 133, 63], [30, 59, 53], "peru"], + "D2691E": [[210, 105, 30], [25, 75, 47], "chocolate"], + "D2B48C": [[210, 180, 140], [34, 44, 69], "tan"], + "D3D3D3": [[211, 211, 211], [0, 0, 83], "lightGrey"], + "D87093": [[219, 112, 147], [340, 60, 65], "paleVioletRed"], + "D8BFD8": [[216, 191, 216], [300, 24, 80], "thistle"], + "DA70D6": [[218, 112, 214], [302, 59, 65], "orchid"], + "DAA520": [[218, 165, 32], [43, 74, 49], "goldenRod"], + "DC143C": [[237, 164, 61], [35, 83, 58], "crimson"], + "DCDCDC": [[220, 220, 220], [0, 0, 86], "gainsboro"], + "DDA0DD": [[221, 160, 221], [300, 47, 75], "plum"], + "DEB887": [[222, 184, 135], [34, 57, 70], "burlyWood"], + "E0FFFF": [[224, 255, 255], [180, 100, 94], "lightCyan"], + "E6E6FA": [[230, 230, 250], [240, 67, 94], "lavender"], + "E9967A": [[233, 150, 122], [15, 72, 70], "darkSalmon"], + "EE82EE": [[238, 130, 238], [300, 76, 72], "violet"], + "EEE8AA": [[238, 232, 170], [55, 67, 80], "paleGoldenRod"], + "F08080": [[240, 128, 128], [0, 79, 72], "lightCoral"], + "F0E68C": [[240, 230, 140], [54, 77, 75], "khaki"], + "F0F8FF": [[240, 248, 255], [208, 100, 97], "aliceBlue"], + "F0FFF0": [[240, 255, 240], [120, 100, 97], "honeyDew"], + "F0FFFF": [[240, 255, 255], [180, 100, 97], "azure"], + "F4A460": [[244, 164, 96], [28, 87, 67], "sandyBrown"], + "F5DEB3": [[245, 222, 179], [39, 77, 83], "wheat"], + "F5F5DC": [[245, 245, 220], [60, 56, 91], "beige"], + "F5F5F5": [[245, 245, 245], [0, 0, 96], "whiteSmoke"], + "F5FFFA": [[245, 255, 250], [150, 100, 98], "mintCream"], + "F8F8FF": [[248, 248, 255], [240, 100, 99], "ghostWhite"], + "FA8072": [[250, 128, 114], [6, 93, 71], "salmon"], + "FAEBD7": [[250, 235, 215], [34, 78, 91], "antiqueWhite"], + "FAF0E6": [[250, 240, 230], [30, 67, 94], "linen"], + "FAFAD2": [[250, 250, 210], [60, 80, 90], "lightGoldenRodYellow"], + "FDF5E6": [[253, 245, 230], [39, 85, 95], "oldLace"], + "FF0000": [[255, 0, 0], [0, 100, 50], "red"], + "FF00FF": [[255, 0, 255], [300, 100, 50], "magenta"], + "FF1493": [[255, 20, 147], [328, 100, 54], "deepPink"], + "FF4500": [[255, 69, 0], [16, 100, 50], "orangeRed"], + "FF6347": [[255, 99, 71], [9, 100, 64], "tomato"], + "FF69B4": [[255, 105, 180], [330, 100, 71], "hotPink"], + "FF7F50": [[255, 127, 80], [16, 100, 66], "coral"], + "FF8C00": [[255, 140, 0], [33, 100, 50], "darkOrange"], + "FFA07A": [[255, 160, 122], [17, 100, 74], "lightSalmon"], + "FFA500": [[255, 165, 0], [39, 100, 50], "orange"], + "FFB6C1": [[255, 182, 193], [351, 100, 86], "lightPink"], + "FFC0CB": [[255, 192, 203], [350, 100, 88], "pink"], + "FFD700": [[255, 215, 0], [51, 100, 50], "gold"], + "FFDAB9": [[255, 218, 185], [28, 100, 86], "peachPuff"], + "FFDEAD": [[255, 222, 173], [36, 100, 84], "navajoWhite"], + "FFE4B5": [[255, 228, 181], [38, 100, 85], "moccasin"], + "FFE4C4": [[255, 228, 196], [33, 100, 88], "bisque"], + "FFE4E1": [[255, 228, 225], [6, 100, 94], "mistyRose"], + "FFEBCD": [[255, 235, 205], [36, 100, 90], "blanchedAlmond"], + "FFEFD5": [[255, 239, 213], [37, 100, 92], "papayaWhip"], + "FFF0F5": [[255, 240, 245], [340, 100, 97], "lavenderBlush"], + "FFF5EE": [[255, 245, 238], [25, 100, 97], "seaShell"], + "FFF8DC": [[255, 248, 220], [48, 100, 93], "cornsilk"], + "FFFACD": [[255, 250, 205], [54, 100, 90], "lemonChiffon"], + "FFFAF0": [[255, 250, 240], [40, 100, 97], "floralWhite"], + "FFFAFA": [[255, 250, 250], [0, 100, 99], "snow"], + "FFFF00": [[255, 255, 0], [60, 100, 50], "yellow"], + "FFFFE0": [[255, 255, 224], [60, 100, 94], "lightYellow"], + "FFFFF0": [[255, 255, 240], [60, 100, 97], "ivory"], + "FFFFFF": [[255, 255, 255], [0, 100, 100], "white"] +}; + +// Simple Values +WebInspector.Color.Nicknames = { + "aliceblue": "F0F8FF", + "antiquewhite": "FAEBD7", + "aqua": "00FFFF", + "aquamarine": "7FFFD4", + "azure": "F0FFFF", + "beige": "F5F5DC", + "bisque": "FFE4C4", + "black": "000000", + "blanchedalmond": "FFEBCD", + "blue": "0000FF", + "blueviolet": "8A2BE2", + "brown": "A52A2A", + "burlywood": "DEB887", + "cadetblue": "5F9EA0", + "chartreuse": "7FFF00", + "chocolate": "D2691E", + "coral": "FF7F50", + "cornflowerblue": "6495ED", + "cornsilk": "FFF8DC", + "crimson": "DC143C", + "cyan": "00FFFF", + "darkblue": "00008B", + "darkcyan": "008B8B", + "darkgoldenrod": "B8860B", + "darkgray": "A9A9A9", + "darkgreen": "006400", + "darkkhaki": "BDB76B", + "darkmagenta": "8B008B", + "darkolivegreen": "556B2F", + "darkorange": "FF8C00", + "darkorchid": "9932CC", + "darkred": "8B0000", + "darksalmon": "E9967A", + "darkseagreen": "8FBC8F", + "darkslateblue": "483D8B", + "darkslategray": "2F4F4F", + "darkturquoise": "00CED1", + "darkviolet": "9400D3", + "deeppink": "FF1493", + "deepskyblue": "00BFFF", + "dimgray": "696969", + "dodgerblue": "1E90FF", + "firebrick": "B22222", + "floralwhite": "FFFAF0", + "forestgreen": "228B22", + "fuchsia": "FF00FF", + "gainsboro": "DCDCDC", + "ghostwhite": "F8F8FF", + "gold": "FFD700", + "goldenrod": "DAA520", + "gray": "808080", + "green": "008000", + "greenyellow": "ADFF2F", + "honeydew": "F0FFF0", + "hotpink": "FF69B4", + "indianred": "CD5C5C", + "indigo": "4B0082", + "ivory": "FFFFF0", + "khaki": "F0E68C", + "lavender": "E6E6FA", + "lavenderblush": "FFF0F5", + "lawngreen": "7CFC00", + "lemonchiffon": "FFFACD", + "lightblue": "ADD8E6", + "lightcoral": "F08080", + "lightcyan": "E0FFFF", + "lightgoldenrodyellow": "FAFAD2", + "lightgreen": "90EE90", + "lightgrey": "D3D3D3", + "lightpink": "FFB6C1", + "lightsalmon": "FFA07A", + "lightseagreen": "20B2AA", + "lightskyblue": "87CEFA", + "lightslategray": "778899", + "lightsteelblue": "B0C4DE", + "lightyellow": "FFFFE0", + "lime": "00FF00", + "limegreen": "32CD32", + "linen": "FAF0E6", + "magenta": "FF00FF", + "maroon": "800000", + "mediumaquamarine": "66CDAA", + "mediumblue": "0000CD", + "mediumorchid": "BA55D3", + "mediumpurple": "9370D8", + "mediumseagreen": "3CB371", + "mediumslateblue": "7B68EE", + "mediumspringgreen": "00FA9A", + "mediumturquoise": "48D1CC", + "mediumvioletred": "C71585", + "midnightblue": "191970", + "mintcream": "F5FFFA", + "mistyrose": "FFE4E1", + "moccasin": "FFE4B5", + "navajowhite": "FFDEAD", + "navy": "000080", + "oldlace": "FDF5E6", + "olive": "808000", + "olivedrab": "6B8E23", + "orange": "FFA500", + "orangered": "FF4500", + "orchid": "DA70D6", + "palegoldenrod": "EEE8AA", + "palegreen": "98FB98", + "paleturquoise": "AFEEEE", + "palevioletred": "D87093", + "papayawhip": "FFEFD5", + "peachpuff": "FFDAB9", + "peru": "CD853F", + "pink": "FFC0CB", + "plum": "DDA0DD", + "powderblue": "B0E0E6", + "purple": "800080", + "red": "FF0000", + "rosybrown": "BC8F8F", + "royalblue": "4169E1", + "saddlebrown": "8B4513", + "salmon": "FA8072", + "sandybrown": "F4A460", + "seagreen": "2E8B57", + "seashell": "FFF5EE", + "sienna": "A0522D", + "silver": "C0C0C0", + "skyblue": "87CEEB", + "slateblue": "6A5ACD", + "slategray": "708090", + "snow": "FFFAFA", + "springgreen": "00FF7F", + "steelblue": "4682B4", + "tan": "D2B48C", + "teal": "008080", + "thistle": "D8BFD8", + "tomato": "FF6347", + "turquoise": "40E0D0", + "violet": "EE82EE", + "wheat": "F5DEB3", + "white": "FFFFFF", + "whitesmoke": "F5F5F5", + "yellow": "FFFF00", + "yellowgreen": "9ACD32" +}; + +// Advanced Values [rgba, hsla, nickname] +WebInspector.Color.AdvancedNickNames = { + "transparent": [[0, 0, 0, 0], [0, 0, 0, 0], "transparent"], + "rgba(0,0,0,0)": [[0, 0, 0, 0], [0, 0, 0, 0], "transparent"], + "hsla(0,0,0,0)": [[0, 0, 0, 0], [0, 0, 0, 0], "transparent"], +}; diff --git a/WebCore/inspector/front-end/Console.js b/WebCore/inspector/front-end/ConsoleView.js index 65cc7d0..6851eea 100644 --- a/WebCore/inspector/front-end/Console.js +++ b/WebCore/inspector/front-end/ConsoleView.js @@ -1,5 +1,6 @@ /* * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2009 Joseph Pecoraro * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,11 +27,16 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -WebInspector.Console = function() +WebInspector.ConsoleView = function(drawer) { + WebInspector.View.call(this, document.getElementById("console-view")); + this.messages = []; + this.drawer = drawer; - WebInspector.View.call(this, document.getElementById("console")); + 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.messagesElement = document.getElementById("console-messages"); this.messagesElement.addEventListener("selectstart", this._messagesSelectStart.bind(this), false); @@ -40,103 +46,49 @@ WebInspector.Console = function() 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.toggleConsoleButton = document.getElementById("console-status-bar-item"); + this.toggleConsoleButton.title = WebInspector.UIString("Show console."); + this.toggleConsoleButton.addEventListener("click", this._toggleConsoleButtonClicked.bind(this), false); - this._animating = true; + var anchoredStatusBar = document.getElementById("anchored-status-bar-items"); + anchoredStatusBar.appendChild(this.toggleConsoleButton); - 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.ConsoleView.prototype = { + _toggleConsoleButtonClicked: function() + { + this.drawer.visibleView = this; + }, - WebInspector.animateStyle(animations, window.event && window.event.shiftKey ? 2000 : 250, animationFinished.bind(this)); + attach: function(mainElement, statusBarElement) + { + mainElement.appendChild(this.element); + statusBarElement.appendChild(this.clearButton); + }, + show: function() + { + this.toggleConsoleButton.addStyleClass("toggled-on"); + this.toggleConsoleButton.title = WebInspector.UIString("Hide console."); if (!this.prompt.isCaretInsidePrompt()) this.prompt.moveCaretToEndOfPrompt(); }, - hide: function() + afterShow: 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.currentFocusElement = this.promptElement; + }, - WebInspector.animateStyle(animations, window.event && window.event.shiftKey ? 2000 : 250, animationFinished.bind(this)); + hide: function() + { + this.toggleConsoleButton.removeStyleClass("toggled-on"); + this.toggleConsoleButton.title = WebInspector.UIString("Show console."); }, addMessage: function(msg) @@ -198,7 +150,7 @@ WebInspector.Console.prototype = { this.messages.push(msg); - if (msg.level === WebInspector.ConsoleMessage.MessageLevel.EndGroup) { + if (msg.type === WebInspector.ConsoleMessage.MessageType.EndGroup) { if (this.groupLevel < 1) return; @@ -206,7 +158,7 @@ WebInspector.Console.prototype = { this.currentGroup = this.currentGroup.parentGroup; } else { - if (msg.level === WebInspector.ConsoleMessage.MessageLevel.StartGroup) { + if (msg.type === WebInspector.ConsoleMessage.MessageType.StartGroup) { this.groupLevel++; var group = new WebInspector.ConsoleGroup(this.currentGroup, this.groupLevel); @@ -241,7 +193,7 @@ WebInspector.Console.prototype = { delete this.previousMessage; }, - completions: function(wordRange, bestMatchOnly) + completions: function(wordRange, bestMatchOnly, completionsReadyCallback) { // Pass less stop characters to rangeOfWord so the range will be a more complete expression. const expressionStopCharacters = " =:{;"; @@ -259,22 +211,11 @@ WebInspector.Console.prototype = { 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(); - } + var reportCompletions = this._reportCompletions.bind(this, bestMatchOnly, completionsReadyCallback, dotNotation, bracketNotation, prefix); + this._evalInInspectedWindow(expressionString, reportCompletions); + }, + _reportCompletions: function(bestMatchOnly, completionsReadyCallback, dotNotation, bracketNotation, prefix, result) { if (bracketNotation) { if (prefix.length && prefix[0] === "'") var quoteUsed = "'"; @@ -283,7 +224,17 @@ WebInspector.Console.prototype = { } var results = []; - var properties = Object.sortedProperties(result); + var properties = Object.properties(result); + if (!dotNotation && !bracketNotation && result._inspectorCommandLineAPI) { + var commandLineAPI = Object.properties(result._inspectorCommandLineAPI); + for (var i = 0; i < commandLineAPI.length; ++i) { + var property = commandLineAPI[i]; + if (property.charAt(0) !== "_") + properties.push(property); + } + } + properties.sort(); + for (var i = 0; i < properties.length; ++i) { var property = properties[i]; @@ -305,13 +256,7 @@ WebInspector.Console.prototype = { if (bestMatchOnly) break; } - - return results; - }, - - _toggleButtonClicked: function() - { - this.visible = !this.visible; + setTimeout(completionsReadyCallback, 0, results); }, _clearButtonClicked: function() @@ -359,47 +304,17 @@ WebInspector.Console.prototype = { this.prompt.handleKeyEvent(event); }, - _startStatusBarDragging: function(event) + _evalInInspectedWindow: function(expression, callback) { - if (!this.visible || event.target !== document.getElementById("main-status-bar")) + if (WebInspector.panels.scripts && WebInspector.panels.scripts.paused) { + WebInspector.panels.scripts.evaluateInSelectedCallFrame(expression, false, callback); 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(); + } + this.doEvalInWindow(expression, callback); }, - _evalInInspectedWindow: function(expression) + _ensureCommandLineAPIInstalled: function(inspectedWindow) { - 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) }, \ @@ -416,20 +331,79 @@ WebInspector.Console.prototype = { }, \ 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; }, \ + keys: function(o) { var a = []; for (var k in o) a.push(k); return a; }, \ + values: function(o) { var a = []; for (var 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) } \ + profileEnd: function() { return console.profileEnd.apply(console, arguments) }, \ + _inspectedNodes: [], \ + get $0() { return _inspectorCommandLineAPI._inspectedNodes[0] }, \ + get $1() { return _inspectorCommandLineAPI._inspectedNodes[1] }, \ + get $2() { return _inspectorCommandLineAPI._inspectedNodes[2] }, \ + get $3() { return _inspectorCommandLineAPI._inspectedNodes[3] }, \ + get $4() { return _inspectorCommandLineAPI._inspectedNodes[4] } \ };"); inspectedWindow._inspectorCommandLineAPI.clear = InspectorController.wrapCallback(this.clearMessages.bind(this)); + inspectedWindow._inspectorCommandLineAPI.inspect = InspectorController.wrapCallback(inspectObject.bind(this)); + + function inspectObject(o) + { + if (arguments.length === 0) + return; + + InspectorController.inspectedWindow().console.log(o); + if (Object.type(o, InspectorController.inspectedWindow()) === "node") { + WebInspector.showElementsPanel(); + WebInspector.panels.elements.treeOutline.revealAndSelectNode(o); + } else { + switch (Object.describe(o)) { + case "Database": + WebInspector.showDatabasesPanel(); + WebInspector.panels.databases.selectDatabase(o); + break; + case "Storage": + WebInspector.showDatabasesPanel(); + WebInspector.panels.databases.selectDOMStorage(o); + break; + } + } + } + } + }, + + addInspectedNode: function(node) + { + var inspectedWindow = InspectorController.inspectedWindow(); + this._ensureCommandLineAPIInstalled(inspectedWindow); + var inspectedNodes = inspectedWindow._inspectorCommandLineAPI._inspectedNodes; + inspectedNodes.unshift(node); + if (inspectedNodes.length >= 5) + inspectedNodes.pop(); + }, + + doEvalInWindow: function(expression, callback) + { + if (!expression) { + // There is no expression, so the completion should happen against global properties. + expression = "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); + var self = this; + function delayedEvaluation() + { + var inspectedWindow = InspectorController.inspectedWindow(); + self._ensureCommandLineAPIInstalled(inspectedWindow); + try { + callback(inspectedWindow.eval(expression)); + } catch (e) { + callback(e, true); + } + } + setTimeout(delayedEvaluation, 0); }, _enterKeyPressed: function(event) @@ -449,25 +423,26 @@ WebInspector.Console.prototype = { 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; + var self = this; + function printResult(result, exception) + { + self.prompt.history.push(str); + self.prompt.historyOffset = 0; + self.prompt.text = ""; + self.addMessage(new WebInspector.ConsoleCommandResult(result, exception, commandMessage)); } - - this.prompt.history.push(str); - this.prompt.historyOffset = 0; - this.prompt.text = ""; - - this.addMessage(new WebInspector.ConsoleCommandResult(result, exception, commandMessage)); + this._evalInInspectedWindow(str, printResult); }, _format: function(output, forceObjectFormat) { - var type = (forceObjectFormat ? "object" : Object.type(output, InspectorController.inspectedWindow())); + var inspectedWindow = InspectorController.inspectedWindow(); + if (forceObjectFormat) + var type = "object"; + else if (output instanceof inspectedWindow.NodeList) + var type = "array"; + else + var type = Object.type(output, inspectedWindow); // We don't perform any special formatting on these types, so we just // pass them through the simple _formatvalue function. @@ -538,7 +513,7 @@ WebInspector.Console.prototype = { _formatobject: function(obj, elem) { - elem.appendChild(new WebInspector.ObjectPropertiesSection(obj, null, null, null, true).element); + elem.appendChild(new WebInspector.ObjectPropertiesSection(new WebInspector.ObjectProxy(obj), Object.describe(obj, true), null, null, true).element); }, _formaterror: function(obj, elem) @@ -564,28 +539,29 @@ WebInspector.Console.prototype = { elem.appendChild(urlElement); elem.appendChild(document.createTextNode(")")); } - }, + } } -WebInspector.Console.prototype.__proto__ = WebInspector.View.prototype; +WebInspector.ConsoleView.prototype.__proto__ = WebInspector.View.prototype; -WebInspector.ConsoleMessage = function(source, level, line, url, groupLevel, repeatCount) +WebInspector.ConsoleMessage = function(source, type, level, line, url, groupLevel, repeatCount) { this.source = source; + this.type = type; this.level = level; this.line = line; this.url = url; this.groupLevel = groupLevel; this.repeatCount = repeatCount; - if (arguments.length > 6) - this.setMessageBody(Array.prototype.slice.call(arguments, 6)); + if (arguments.length > 7) + this.setMessageBody(Array.prototype.slice.call(arguments, 7)); } WebInspector.ConsoleMessage.prototype = { setMessageBody: function(args) { - switch (this.level) { - case WebInspector.ConsoleMessage.MessageLevel.Trace: + switch (this.type) { + case WebInspector.ConsoleMessage.MessageType.Trace: var span = document.createElement("span"); span.addStyleClass("console-formatted-trace"); var stack = Array.prototype.slice.call(args); @@ -595,7 +571,7 @@ WebInspector.ConsoleMessage.prototype = { span.appendChild(document.createTextNode(funcNames.join("\n"))); this.formattedMessage = span; break; - case WebInspector.ConsoleMessage.MessageLevel.Object: + case WebInspector.ConsoleMessage.MessageType.Object: this.formattedMessage = this._format(["%O", args[0]]); break; default: @@ -713,8 +689,10 @@ WebInspector.ConsoleMessage.prototype = { case WebInspector.ConsoleMessage.MessageLevel.Error: element.addStyleClass("console-error-level"); break; - case WebInspector.ConsoleMessage.MessageLevel.StartGroup: - element.addStyleClass("console-group-title-level"); + } + + if (this.type === WebInspector.ConsoleMessage.MessageType.StartGroup) { + element.addStyleClass("console-group-title"); } if (this.elementsTreeOutline) { @@ -781,6 +759,25 @@ WebInspector.ConsoleMessage.prototype = { break; } + var typeString; + switch (this.type) { + case WebInspector.ConsoleMessage.MessageType.Log: + typeString = "Log"; + break; + case WebInspector.ConsoleMessage.MessageType.Object: + typeString = "Object"; + break; + case WebInspector.ConsoleMessage.MessageType.Trace: + typeString = "Trace"; + break; + case WebInspector.ConsoleMessage.MessageType.StartGroup: + typeString = "Start Group"; + break; + case WebInspector.ConsoleMessage.MessageType.EndGroup: + typeString = "End Group"; + break; + } + var levelString; switch (this.level) { case WebInspector.ConsoleMessage.MessageLevel.Tip: @@ -795,21 +792,9 @@ WebInspector.ConsoleMessage.prototype = { 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; + return sourceString + " " + typeString + " " + levelString + ": " + this.formattedMessage.textContent + "\n" + this.url + " line " + this.line; }, isEqual: function(msg, disreguardGroup) @@ -818,6 +803,7 @@ WebInspector.ConsoleMessage.prototype = { return false; var ret = (this.source == msg.source) + && (this.type == msg.type) && (this.level == msg.level) && (this.line == msg.line) && (this.url == msg.url) @@ -837,15 +823,19 @@ WebInspector.ConsoleMessage.MessageSource = { Other: 5 } +WebInspector.ConsoleMessage.MessageType = { + Log: 0, + Object: 1, + Trace: 2, + StartGroup: 3, + EndGroup: 4 +} + WebInspector.ConsoleMessage.MessageLevel = { Tip: 0, Log: 1, Warning: 2, - Error: 3, - Object: 4, - Trace: 5, - StartGroup: 6, - EndGroup: 7 + Error: 3 } WebInspector.ConsoleCommand = function(command) @@ -876,7 +866,7 @@ WebInspector.ConsoleCommandResult = function(result, exception, originatingComma 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); + WebInspector.ConsoleMessage.call(this, WebInspector.ConsoleMessage.MessageSource.JS, WebInspector.ConsoleMessage.MessageType.Log, level, line, url, null, 1, message); this.originatingCommand = originatingCommand; } @@ -913,7 +903,7 @@ WebInspector.ConsoleGroup.prototype = { { var element = msg.toMessageElement(); - if (msg.level === WebInspector.ConsoleMessage.MessageLevel.StartGroup) { + if (msg.type === WebInspector.ConsoleMessage.MessageType.StartGroup) { this.messagesElement.parentNode.insertBefore(element, this.messagesElement); element.addEventListener("click", this._titleClicked.bind(this), true); } else @@ -925,7 +915,7 @@ WebInspector.ConsoleGroup.prototype = { _titleClicked: function(event) { - var groupTitleElement = event.target.enclosingNodeOrSelfWithClass("console-group-title-level"); + var groupTitleElement = event.target.enclosingNodeOrSelfWithClass("console-group-title"); if (groupTitleElement) { var groupElement = groupTitleElement.enclosingNodeOrSelfWithClass("console-group"); if (groupElement) diff --git a/WebCore/inspector/front-end/DOMAgent.js b/WebCore/inspector/front-end/DOMAgent.js new file mode 100644 index 0000000..5aacd41 --- /dev/null +++ b/WebCore/inspector/front-end/DOMAgent.js @@ -0,0 +1,724 @@ +/* + * Copyright (C) 2009 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. + * * Neither the name of Google Inc. 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 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. + */ + +WebInspector.DOMNode = function(doc, payload) { + this.ownerDocument = doc; + + this._id = payload.id; + this.nodeType = payload.nodeType; + this.nodeName = payload.nodeName; + this._nodeValue = payload.nodeValue; + this.textContent = this.nodeValue; + + this.attributes = []; + this._attributesMap = {}; + if (payload.attributes) + this._setAttributesPayload(payload.attributes); + + this._childNodeCount = payload.childNodeCount; + this.children = null; + + this.nextSibling = null; + this.prevSibling = null; + this.firstChild = null; + this.parentNode = null; + + if (payload.childNodes) + this._setChildrenPayload(payload.childNodes); + + this._computedStyle = null; + this.style = null; + this._matchedCSSRules = []; +} + +WebInspector.DOMNode.prototype = { + hasAttributes: function() + { + return this.attributes.length > 0; + }, + + hasChildNodes: function() { + return this._childNodeCount > 0; + }, + + get nodeValue() { + return this._nodeValue; + }, + + set nodeValue(value) { + if (this.nodeType != Node.TEXT_NODE) + return; + var self = this; + var callback = function() + { + self._nodeValue = value; + self.textContent = value; + }; + this.ownerDocument._domAgent.setTextNodeValueAsync(this, value, callback); + }, + + getAttribute: function(name) + { + var attr = this._attributesMap[name]; + return attr ? attr.value : undefined; + }, + + setAttribute: function(name, value) + { + var self = this; + var callback = function() + { + var attr = self._attributesMap[name]; + if (attr) + attr.value = value; + else + attr = self._addAttribute(name, value); + }; + this.ownerDocument._domAgent.setAttributeAsync(this, name, value, callback); + }, + + removeAttribute: function(name) + { + var self = this; + var callback = 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; + } + } + }; + this.ownerDocument._domAgent.removeAttributeAsync(this, name, callback); + }, + + _setAttributesPayload: function(attrs) + { + for (var i = 0; i < attrs.length; i += 2) + this._addAttribute(attrs[i], attrs[i + 1]); + }, + + _insertChild: function(prev, payload) + { + var node = new WebInspector.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; + }, + + removeChild_: function(node) + { + this.children.splice(this.children.indexOf(node), 1); + node.parentNode = null; + this._renumber(); + }, + + _setChildrenPayload: function(payloads) + { + this.children = []; + for (var i = 0; i < payloads.length; ++i) { + var payload = payloads[i]; + var node = new WebInspector.DOMNode(this.ownerDocument, payload); + this.children.push(node); + } + this._renumber(); + }, + + _renumber: function() + { + this._childNodeCount = this.children.length; + if (this._childNodeCount == 0) { + this.firstChild = null; + return; + } + this.firstChild = this.children[0]; + for (var i = 0; i < this._childNodeCount; ++i) { + var child = this.children[i]; + child.nextSibling = i + 1 < this._childNodeCount ? this.children[i + 1] : null; + child.prevSibling = i - 1 >= 0 ? this.children[i - 1] : null; + child.parentNode = this; + } + }, + + _addAttribute: function(name, value) + { + var attr = { + "name": name, + "value": value, + "_node": this + }; + this._attributesMap[name] = attr; + this.attributes.push(attr); + }, + + _setStyles: function(computedStyle, inlineStyle, styleAttributes, matchedCSSRules) + { + this._computedStyle = new WebInspector.CSSStyleDeclaration(computedStyle); + this.style = new WebInspector.CSSStyleDeclaration(inlineStyle); + + for (var name in styleAttributes) { + if (this._attributesMap[name]) + this._attributesMap[name].style = new WebInspector.CSSStyleDeclaration(styleAttributes[name]); + } + + this._matchedCSSRules = []; + for (var i = 0; i < matchedCSSRules.length; i++) + this._matchedCSSRules.push(WebInspector.CSSStyleDeclaration.parseRule(matchedCSSRules[i])); + }, + + _clearStyles: function() + { + this.computedStyle = null; + this.style = null; + for (var name in this._attributesMap) + this._attributesMap[name].style = null; + this._matchedCSSRules = null; + } +} + +WebInspector.DOMDocument = function(domAgent, defaultView) +{ + WebInspector.DOMNode.call(this, null, + { + id: 0, + nodeType: Node.DOCUMENT_NODE, + nodeName: "", + nodeValue: "", + attributes: [], + childNodeCount: 0 + }); + this._listeners = {}; + this._domAgent = domAgent; + this.defaultView = defaultView; +} + +WebInspector.DOMDocument.prototype = { + + addEventListener: function(name, callback, useCapture) + { + var listeners = this._listeners[name]; + if (!listeners) { + listeners = []; + this._listeners[name] = listeners; + } + listeners.push(callback); + }, + + 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); + }, + + _fireDomEvent: function(name, event) + { + var listeners = this._listeners[name]; + if (!listeners) + return; + + for (var i = 0; i < listeners.length; ++i) + listeners[i](event); + } +} + +WebInspector.DOMDocument.prototype.__proto__ = WebInspector.DOMNode.prototype; + + +WebInspector.DOMWindow = function(domAgent) +{ + this._domAgent = domAgent; +} + +WebInspector.DOMWindow.prototype = { + get document() + { + return this._domAgent.document; + }, + + get Node() + { + return WebInspector.DOMNode; + }, + + get Element() + { + return WebInspector.DOMNode; + }, + + Object: function() + { + }, + + getComputedStyle: function(node) + { + return node._computedStyle; + }, + + getMatchedCSSRules: function(node, pseudoElement, authorOnly) + { + return node._matchedCSSRules; + } +} + +WebInspector.DOMAgent = function() { + this._window = new WebInspector.DOMWindow(this); + this._idToDOMNode = null; + this.document = null; + + // Install onpopulate handler. This is a temporary measure. + // TODO: add this code into the original updateChildren once domAgent + // becomes primary source of DOM information. + // TODO2: update ElementsPanel to not track embedded iframes - it is already being handled + // in the agent backend. + var domAgent = this; + var originalUpdateChildren = WebInspector.ElementsTreeElement.prototype.updateChildren; + WebInspector.ElementsTreeElement.prototype.updateChildren = function() + { + domAgent.getChildNodesAsync(this.representedObject, originalUpdateChildren.bind(this)); + }; + + // Mute console handle to avoid crash on selection change. + // TODO: Re-implement inspectorConsoleAPI to work in a serialized way and remove this workaround. + WebInspector.Console.prototype.addInspectedNode = function() + { + }; + + // Whitespace is ignored in InspectorDOMAgent already -> no need to filter. + // TODO: Either remove all of its usages or push value into the agent backend. + Preferences.ignoreWhitespace = false; +} + +WebInspector.DOMAgent.prototype = { + get inspectedWindow() + { + return this._window; + }, + + 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 = WebInspector.Callback.wrap(mycallback); + InspectorController.getChildNodes(callId, parent._id); + }, + + setAttributeAsync: function(node, name, value, callback) + { + var mycallback = this._didApplyDomChange.bind(this, node, callback); + InspectorController.setAttribute(WebInspector.Callback.wrap(mycallback), node._id, name, value); + }, + + removeAttributeAsync: function(node, name, callback) + { + var mycallback = this._didApplyDomChange.bind(this, node, callback); + InspectorController.removeAttribute(WebInspector.Callback.wrap(mycallback), node._id, name); + }, + + setTextNodeValueAsync: function(node, text, callback) + { + var mycallback = this._didApplyDomChange.bind(this, node, callback); + InspectorController.setTextNodeValue(WebInspector.Callback.wrap(mycallback), node._id, text); + }, + + _didApplyDomChange: function(node, callback, success) + { + if (!success) + return; + callback(); + // TODO(pfeldman): Fix this hack. + var elem = WebInspector.panels.elements.treeOutline.findTreeElement(node); + if (elem) { + elem._updateTitle(); + } + }, + + _attributesUpdated: function(nodeId, attrsArray) + { + var node = this._idToDOMNode[nodeId]; + node._setAttributesPayload(attrsArray); + }, + + getNodeForId: function(nodeId) { + return this._idToDOMNode[nodeId]; + }, + + _setDocumentElement: function(payload) + { + this.document = new WebInspector.DOMDocument(this, this._window); + this._idToDOMNode = { 0 : this.document }; + this._setChildNodes(0, [payload]); + this.document.documentElement = this.document.firstChild; + this.document.documentElement.ownerDocument = this.document; + WebInspector.panels.elements.reset(); + }, + + _setChildNodes: function(parentId, payloads) + { + var parent = this._idToDOMNode[parentId]; + if (parent.children) { + return; + } + parent._setChildrenPayload(payloads); + this._bindNodes(parent.children); + }, + + _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); + } + }, + + _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; + } + }, + + _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.document._fireDomEvent("DOMNodeInserted", event); + }, + + _childNodeRemoved: function(parentId, nodeId) + { + var parent = this._idToDOMNode[parentId]; + var node = this._idToDOMNode[nodeId]; + parent.removeChild_(node); + var event = { target : node, relatedNode : parent }; + this.document._fireDomEvent("DOMNodeRemoved", event); + delete this._idToDOMNode[nodeId]; + } +} + +WebInspector.CSSStyleDeclaration = function(payload) { + this._id = payload.id; + this.width = payload.width; + this.height = payload.height; + this.__disabledProperties = payload.__disabledProperties; + this.__disabledPropertyValues = payload.__disabledPropertyValues; + this.__disabledPropertyPriorities = payload.__disabledPropertyPriorities; + this.uniqueStyleProperties = payload.uniqueStyleProperties; + this._shorthandValues = payload.shorthandValues; + this._propertyMap = {}; + this._longhandProperties = {}; + this.length = payload.properties.length; + + for (var i = 0; i < this.length; ++i) { + var property = payload.properties[i]; + var name = property.name; + this[i] = name; + this._propertyMap[name] = property; + } + + // Index longhand properties. + for (var i = 0; i < this.uniqueStyleProperties.length; ++i) { + var name = this.uniqueStyleProperties[i]; + var property = this._propertyMap[name]; + if (property.shorthand) { + var longhands = this._longhandProperties[property.shorthand]; + if (!longhands) { + longhands = []; + this._longhandProperties[property.shorthand] = longhands; + } + longhands.push(name); + } + } +} + +WebInspector.CSSStyleDeclaration.parseStyle = function(payload) +{ + return new WebInspector.CSSStyleDeclaration(payload); +} + +WebInspector.CSSStyleDeclaration.parseRule = function(payload) +{ + var rule = {}; + rule._id = payload.id; + rule.selectorText = payload.selectorText; + rule.style = new WebInspector.CSSStyleDeclaration(payload.style); + rule.style.parentRule = rule; + rule.isUserAgent = payload.isUserAgent; + rule.isUser = payload.isUser; + if (payload.parentStyleSheet) + rule.parentStyleSheet = { href: payload.parentStyleSheet.href }; + + return rule; +} + +WebInspector.CSSStyleDeclaration.prototype = { + getPropertyValue: function(name) + { + var property = this._propertyMap[name]; + return property ? property.value : ""; + }, + + getPropertyPriority: function(name) + { + var property = this._propertyMap[name]; + return property ? property.priority : ""; + }, + + getPropertyShorthand: function(name) + { + var property = this._propertyMap[name]; + return property ? property.shorthand : ""; + }, + + isPropertyImplicit: function(name) + { + var property = this._propertyMap[name]; + return property ? property.implicit : ""; + }, + + styleTextWithShorthands: function() + { + var cssText = ""; + var foundProperties = {}; + for (var i = 0; i < this.length; ++i) { + var individualProperty = this[i]; + var shorthandProperty = this.getPropertyShorthand(individualProperty); + var propertyName = (shorthandProperty || individualProperty); + + if (propertyName in foundProperties) + continue; + + if (shorthandProperty) { + var value = this.getPropertyValue(shorthandProperty); + var priority = this.getShorthandPriority(shorthandProperty); + } else { + var value = this.getPropertyValue(individualProperty); + var priority = this.getPropertyPriority(individualProperty); + } + + foundProperties[propertyName] = true; + + cssText += propertyName + ": " + value; + if (priority) + cssText += " !" + priority; + cssText += "; "; + } + + return cssText; + }, + + getLonghandProperties: function(name) + { + return this._longhandProperties[name] || []; + }, + + getShorthandValue: function(shorthandProperty) + { + return this._shorthandValues[shorthandProperty]; + }, + + getShorthandPriority: function(shorthandProperty) + { + var priority = this.getPropertyPriority(shorthandProperty); + if (priority) + return priority; + + var longhands = this._longhandProperties[shorthandProperty]; + return longhands ? this.getPropertyPriority(longhands[0]) : null; + } +} + +WebInspector.attributesUpdated = function() +{ + this.domAgent._attributesUpdated.apply(this.domAgent, arguments); +} + +WebInspector.setDocumentElement = function() +{ + this.domAgent._setDocumentElement.apply(this.domAgent, arguments); +} + +WebInspector.setChildNodes = function() +{ + this.domAgent._setChildNodes.apply(this.domAgent, arguments); +} + +WebInspector.hasChildrenUpdated = function() +{ + this.domAgent._hasChildrenUpdated.apply(this.domAgent, arguments); +} + +WebInspector.childNodeInserted = function() +{ + this.domAgent._childNodeInserted.apply(this.domAgent, arguments); + this._childNodeInserted.bind(this); +} + +WebInspector.childNodeRemoved = function() +{ + this.domAgent._childNodeRemoved.apply(this.domAgent, arguments); + this._childNodeRemoved.bind(this); +} + +WebInspector.didGetChildNodes = WebInspector.Callback.processCallback; +WebInspector.didPerformSearch = WebInspector.Callback.processCallback; +WebInspector.didApplyDomChange = WebInspector.Callback.processCallback; +WebInspector.didRemoveAttribute = WebInspector.Callback.processCallback; +WebInspector.didSetTextNodeValue = WebInspector.Callback.processCallback; + +// Temporary methods for DOMAgent migration. +WebInspector.wrapNodeWithStyles = function(node, styles) +{ + var windowStub = new WebInspector.DOMWindow(null); + var docStub = new WebInspector.DOMDocument(null, windowStub); + var payload = {}; + payload.nodeType = node.nodeType; + payload.nodeName = node.nodeName; + payload.nodeValue = node.nodeValue; + payload.attributes = []; + payload.childNodeCount = 0; + + for (var i = 0; i < node.attributes.length; ++i) { + var attr = node.attributes[i]; + payload.attributes.push(attr.name); + payload.attributes.push(attr.value); + } + var nodeStub = new WebInspector.DOMNode(docStub, payload); + nodeStub._setStyles(styles.computedStyle, styles.inlineStyle, styles.styleAttributes, styles.matchedCSSRules); + return nodeStub; +} + +// Temporary methods that will be dispatched via InspectorController into the injected context. +InspectorController.getStyles = function(nodeId, authorOnly, callback) +{ + setTimeout(function() { + callback(InjectedScript.getStyles(nodeId, authorOnly)); + }, 0) +} + +InspectorController.getComputedStyle = function(nodeId, callback) +{ + setTimeout(function() { + callback(InjectedScript.getComputedStyle(nodeId)); + }, 0) +} + +InspectorController.getInlineStyle = function(nodeId, callback) +{ + setTimeout(function() { + callback(InjectedScript.getInlineStyle(nodeId)); + }, 0) +} + +InspectorController.applyStyleText = function(styleId, styleText, propertyName, callback) +{ + setTimeout(function() { + callback(InjectedScript.applyStyleText(styleId, styleText, propertyName)); + }, 0) +} + +InspectorController.setStyleText = function(style, cssText, callback) +{ + setTimeout(function() { + callback(InjectedScript.setStyleText(style, cssText)); + }, 0) +} + +InspectorController.toggleStyleEnabled = function(styleId, propertyName, disabled, callback) +{ + setTimeout(function() { + callback(InjectedScript.toggleStyleEnabled(styleId, propertyName, disabled)); + }, 0) +} + +InspectorController.applyStyleRuleText = function(ruleId, newContent, selectedNode, callback) +{ + setTimeout(function() { + callback(InjectedScript.applyStyleRuleText(ruleId, newContent, selectedNode)); + }, 0) +} + +InspectorController.addStyleSelector = function(newContent, callback) +{ + setTimeout(function() { + callback(InjectedScript.addStyleSelector(newContent)); + }, 0) +} + +InspectorController.setStyleProperty = function(styleId, name, value, callback) { + setTimeout(function() { + callback(InjectedScript.setStyleProperty(styleId, name, value)); + }, 0) +} + +InspectorController.getPrototypes = function(objectProxy, callback) { + setTimeout(function() { + callback(InjectedScript.getPrototypes(objectProxy)); + }, 0) +} + +InspectorController.getProperties = function(objectProxy, ignoreHasOwnProperty, callback) { + setTimeout(function() { + callback(InjectedScript.getProperties(objectProxy, ignoreHasOwnProperty)); + }, 0) +} + +InspectorController.setPropertyValue = function(objectProxy, propertyName, expression, callback) { + setTimeout(function() { + callback(InjectedScript.setPropertyValue(objectProxy, propertyName, expression)); + }, 0) +} + diff --git a/WebCore/inspector/front-end/DOMStorageDataGrid.js b/WebCore/inspector/front-end/DOMStorageDataGrid.js index 9946415..0326bc7 100644 --- a/WebCore/inspector/front-end/DOMStorageDataGrid.js +++ b/WebCore/inspector/front-end/DOMStorageDataGrid.js @@ -38,39 +38,93 @@ WebInspector.DOMStorageDataGrid.prototype = { return; this._startEditing(event); }, - + + _startEditingColumnOfDataGridNode: function(node, column) + { + this._editing = true; + this._editingNode = node; + this._editingNode.select(); + WebInspector.panels.databases._unregisterStorageEventListener(); + + var element = this._editingNode._element.children[column]; + WebInspector.startEditing(element, this._editingCommitted.bind(this), this._editingCancelled.bind(this), element.textContent); + window.getSelection().setBaseAndExtent(element, 0, element, 1); + }, + _startEditing: function(event) { var element = event.target.enclosingNodeOrSelfWithNodeName("td"); if (!element) return; + this._editingNode = this.dataGridNodeFromEvent(event); - if (!this._editingNode) - return; + if (!this._editingNode) { + if (!this.creationNode) + return; + this._editingNode = this.creationNode; + } + + // Force editing the "Key" column when editing the creation node + if (this._editingNode.isCreationNode) + return this._startEditingColumnOfDataGridNode(this._editingNode, 0); + this._editing = true; - + WebInspector.panels.databases._unregisterStorageEventListener(); WebInspector.startEditing(element, this._editingCommitted.bind(this), this._editingCancelled.bind(this), element.textContent); window.getSelection().setBaseAndExtent(element, 0, element, 1); }, - - _editingCommitted: function(element, newText) + + _editingCommitted: function(element, newText, oldText, context, moveDirection) { - if (element.hasStyleClass("0-column")) - columnIdentifier = 0; - else - columnIdentifier = 1; - textBeforeEditing = this._editingNode.data[columnIdentifier]; + var columnIdentifier = (element.hasStyleClass("0-column") ? 0 : 1); + var textBeforeEditing = this._editingNode.data[columnIdentifier]; + var currentEditingNode = this._editingNode; + + function moveToNextIfNeeded(wasChange) { + if (!moveDirection) + return; + + if (moveDirection === "forward") { + if (currentEditingNode.isCreationNode && columnIdentifier === 0 && !wasChange) + return; + + if (columnIdentifier === 0) + return this._startEditingColumnOfDataGridNode(currentEditingNode, 1); + + var nextDataGridNode = currentEditingNode.traverseNextNode(true, null, true); + if (nextDataGridNode) + return this._startEditingColumnOfDataGridNode(nextDataGridNode, 0); + if (currentEditingNode.isCreationNode && wasChange) { + addCreationNode(false); + return this._startEditingColumnOfDataGridNode(this.creationNode, 0); + } + return; + } + + if (moveDirection === "backward") { + if (columnIdentifier === 1) + return this._startEditingColumnOfDataGridNode(currentEditingNode, 0); + var nextDataGridNode = currentEditingNode.traversePreviousNode(true, null, true); + + if (nextDataGridNode) + return this._startEditingColumnOfDataGridNode(nextDataGridNode, 1); + return; + } + } + if (textBeforeEditing == newText) { this._editingCancelled(element); + moveToNextIfNeeded.call(this, false); return; } - + var domStorage = WebInspector.panels.databases.visibleView.domStorage.domStorage; if (domStorage) { if (columnIdentifier == 0) { if (domStorage.getItem(newText) != null) { element.textContent = this._editingNode.data[0]; this._editingCancelled(element); + moveToNextIfNeeded.call(this, false); return; } domStorage.removeItem(this._editingNode.data[0]); @@ -81,19 +135,27 @@ WebInspector.DOMStorageDataGrid.prototype = { this._editingNode.data[1] = newText; } } - + + if (this._editingNode.isCreationNode) + this.addCreationNode(false); + this._editingCancelled(element); + moveToNextIfNeeded.call(this, true); }, - + _editingCancelled: function(element, context) { delete this._editing; this._editingNode = null; + WebInspector.panels.databases._registerStorageEventListener(); }, - + deleteSelectedRow: function() { var node = this.selectedNode; + if (this.selectedNode.isCreationNode) + return; + var domStorage = WebInspector.panels.databases.visibleView.domStorage.domStorage; if (node && domStorage) domStorage.removeItem(node.data[0]); diff --git a/WebCore/inspector/front-end/DOMStorageItemsView.js b/WebCore/inspector/front-end/DOMStorageItemsView.js index 912573e..fad6e3c 100644 --- a/WebCore/inspector/front-end/DOMStorageItemsView.js +++ b/WebCore/inspector/front-end/DOMStorageItemsView.js @@ -75,6 +75,7 @@ WebInspector.DOMStorageItemsView.prototype = { else { this._dataGrid = dataGrid; this.element.appendChild(dataGrid.element); + this._dataGrid.updateWidths(); this.deleteButton.removeStyleClass("hidden"); } } @@ -89,6 +90,12 @@ WebInspector.DOMStorageItemsView.prototype = { this.deleteButton.addStyleClass("hidden"); } }, + + resize: function() + { + if (this._dataGrid) + this._dataGrid.updateWidths(); + }, _deleteButtonClicked: function(event) { diff --git a/WebCore/inspector/front-end/DataGrid.js b/WebCore/inspector/front-end/DataGrid.js index 2fcb08c..42e001c 100644 --- a/WebCore/inspector/front-end/DataGrid.js +++ b/WebCore/inspector/front-end/DataGrid.js @@ -89,7 +89,8 @@ WebInspector.DataGrid = function(columns) cell.className = "corner"; headerRow.appendChild(cell); - this._headerTable.appendChild(columnGroup); + this._headerTableColumnGroup = columnGroup; + this._headerTable.appendChild(this._headerTableColumnGroup); this.headerTableBody.appendChild(headerRow); var fillerRow = document.createElement("tr"); @@ -99,8 +100,9 @@ WebInspector.DataGrid = function(columns) var cell = document.createElement("td"); fillerRow.appendChild(cell); } - - this._dataTable.appendChild(columnGroup.cloneNode(true)); + + this._dataTableColumnGroup = columnGroup.cloneNode(true); + this._dataTable.appendChild(this._dataTableColumnGroup); this.dataTableBody.appendChild(fillerRow); this.columns = columns || {}; @@ -114,6 +116,8 @@ WebInspector.DataGrid = function(columns) this.selected = false; this.dataGrid = this; this.indentWidth = 15; + this.resizers = []; + this.columnWidthsInitialized = false; } WebInspector.DataGrid.prototype = { @@ -160,6 +164,75 @@ WebInspector.DataGrid.prototype = { return this._dataTableBody; }, + + // Updates the widths of the table, including the positions of the column + // resizers. + // + // IMPORTANT: This function MUST be called once after the element of the + // DataGrid is attached to its parent element and every subsequent time the + // width of the parent element is changed in order to make it possible to + // resize the columns. + // + // If this function is not called after the DataGrid is attached to its + // parent element, then the DataGrid's columns will not be resizable. + updateWidths: function() + { + var headerTableColumns = this._headerTableColumnGroup.children; + + var left = 0; + var tableWidth = this._dataTable.offsetWidth; + var numColumns = headerTableColumns.length; + + if (!this.columnWidthsInitialized) { + // Give all the columns initial widths now so that during a resize, + // when the two columns that get resized get a percent value for + // their widths, all the other columns already have percent values + // for their widths. + for (var i = 0; i < numColumns; i++) { + var columnWidth = this.headerTableBody.rows[0].cells[i].offsetWidth; + var percentWidth = ((columnWidth / tableWidth) * 100) + "%"; + this._headerTableColumnGroup.children[i].style.width = percentWidth; + this._dataTableColumnGroup.children[i].style.width = percentWidth; + } + this.columnWidthsInitialized = true; + } + + // Make n - 1 resizers for n columns. + for (var i = 0; i < numColumns - 1; i++) { + var resizer = this.resizers[i]; + + if (!resizer) { + // This is the first call to updateWidth, so the resizers need + // to be created. + resizer = document.createElement("div"); + resizer.addStyleClass("data-grid-resizer"); + // This resizer is associated with the column to its right. + resizer.rightNeighboringColumnID = i + 1; + resizer.addEventListener("mousedown", this._startResizerDragging.bind(this), false); + this.element.appendChild(resizer); + this.resizers[i] = resizer; + } + + // Get the width of the cell in the first (and only) row of the + // header table in order to determine the width of the column, since + // it is not possible to query a column for its width. + left += this.headerTableBody.rows[0].cells[i].offsetWidth; + + resizer.style.left = left + "px"; + } + }, + + addCreationNode: function(hasChildren) + { + if (this.creationNode) + this.creationNode.makeNormal(); + + var emptyData = {}; + for (var column in this.columns) + emptyData[column] = ''; + this.creationNode = new WebInspector.CreationDataGridNode(emptyData, hasChildren); + this.appendChild(this.creationNode); + }, appendChild: function(child) { @@ -429,7 +502,63 @@ WebInspector.DataGrid.prototype = { else gridNode.expand(); } - } + }, + + _startResizerDragging: function(event) + { + this.currentResizer = event.target; + if (!this.currentResizer.rightNeighboringColumnID) + return; + WebInspector.elementDragStart(this.lastResizer, this._resizerDragging.bind(this), + this._endResizerDragging.bind(this), event, "col-resize"); + }, + + _resizerDragging: function(event) + { + var resizer = this.currentResizer; + if (!resizer) + return; + + // Constrain the dragpoint to be within the containing div of the + // datagrid. + var dragPoint = event.clientX - this.element.totalOffsetLeft; + // Constrain the dragpoint to be within the space made up by the + // column directly to the left and the column directly to the right. + var leftEdgeOfPreviousColumn = 0; + var firstRowCells = this.headerTableBody.rows[0].cells; + for (var i = 0; i < resizer.rightNeighboringColumnID - 1; i++) + leftEdgeOfPreviousColumn += firstRowCells[i].offsetWidth; + + var rightEdgeOfNextColumn = leftEdgeOfPreviousColumn + firstRowCells[resizer.rightNeighboringColumnID - 1].offsetWidth + firstRowCells[resizer.rightNeighboringColumnID].offsetWidth; + + // Give each column some padding so that they don't disappear. + var leftMinimum = leftEdgeOfPreviousColumn + this.ColumnResizePadding; + var rightMaximum = rightEdgeOfNextColumn - this.ColumnResizePadding; + + dragPoint = Number.constrain(dragPoint, leftMinimum, rightMaximum); + + resizer.style.left = (dragPoint - this.CenterResizerOverBorderAdjustment) + "px"; + + var percentLeftColumn = (((dragPoint - leftEdgeOfPreviousColumn) / this._dataTable.offsetWidth) * 100) + "%"; + this._headerTableColumnGroup.children[resizer.rightNeighboringColumnID - 1].style.width = percentLeftColumn; + this._dataTableColumnGroup.children[resizer.rightNeighboringColumnID - 1].style.width = percentLeftColumn; + + var percentRightColumn = (((rightEdgeOfNextColumn - dragPoint) / this._dataTable.offsetWidth) * 100) + "%"; + this._headerTableColumnGroup.children[resizer.rightNeighboringColumnID].style.width = percentRightColumn; + this._dataTableColumnGroup.children[resizer.rightNeighboringColumnID].style.width = percentRightColumn; + + event.preventDefault(); + }, + + _endResizerDragging: function(event) + { + WebInspector.elementDragEnd(event); + this.currentResizer = null; + }, + + ColumnResizePadding: 10, + + CenterResizerOverBorderAdjustment: 3, } WebInspector.DataGrid.prototype.__proto__ = WebInspector.Object.prototype; @@ -883,3 +1012,19 @@ WebInspector.DataGridNode.prototype = { } WebInspector.DataGridNode.prototype.__proto__ = WebInspector.Object.prototype; + +WebInspector.CreationDataGridNode = function(data, hasChildren) +{ + WebInspector.DataGridNode.call(this, data, hasChildren); + this.isCreationNode = true; +} + +WebInspector.CreationDataGridNode.prototype = { + makeNormal: function() + { + delete this.isCreationNode; + delete this.makeNormal; + } +} + +WebInspector.CreationDataGridNode.prototype.__proto__ = WebInspector.DataGridNode.prototype; diff --git a/WebCore/inspector/front-end/DatabaseQueryView.js b/WebCore/inspector/front-end/DatabaseQueryView.js index 122707f..429c2c3 100644 --- a/WebCore/inspector/front-end/DatabaseQueryView.js +++ b/WebCore/inspector/front-end/DatabaseQueryView.js @@ -58,7 +58,7 @@ WebInspector.DatabaseQueryView.prototype = { setTimeout(moveBackIfOutside.bind(this), 0); }, - completions: function(wordRange, bestMatchOnly) + completions: function(wordRange, bestMatchOnly, completionsReadyCallback) { var prefix = wordRange.toString().toLowerCase(); if (!prefix.length) @@ -85,7 +85,7 @@ WebInspector.DatabaseQueryView.prototype = { 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; + completionsReadyCallback(results); }, _promptKeyDown: function(event) @@ -157,7 +157,7 @@ WebInspector.DatabaseQueryView.prototype = { 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); + var message = WebInspector.UIString("An unexpected error %s occurred.", error.code); this._appendQueryResult(query, message, "error"); }, diff --git a/WebCore/inspector/front-end/DatabasesPanel.js b/WebCore/inspector/front-end/DatabasesPanel.js index 4644b3b..a31e3ff 100644 --- a/WebCore/inspector/front-end/DatabasesPanel.js +++ b/WebCore/inspector/front-end/DatabasesPanel.js @@ -1,5 +1,6 @@ /* * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2009 Joseph Pecoraro * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -85,6 +86,7 @@ WebInspector.DatabasesPanel.prototype = { { WebInspector.Panel.prototype.show.call(this); this._updateSidebarWidth(); + this._registerStorageEventListener(); }, reset: function() @@ -101,6 +103,8 @@ WebInspector.DatabasesPanel.prototype = { this._databases = []; + this._unregisterStorageEventListener(); + if (this._domStorage) { var domStorageLength = this._domStorage.length; for (var i = 0; i < domStorageLength; ++i) { @@ -145,6 +149,32 @@ WebInspector.DatabasesPanel.prototype = { this.sessionStorageListTreeElement.appendChild(domStorageTreeElement); }, + selectDatabase: function(db) + { + var database; + for (var i = 0, len = this._databases.length; i < len; ++i) { + database = this._databases[i]; + if ( db === database.database ) { + this.showDatabase(database); + database._databasesTreeElement.select(); + return; + } + } + }, + + selectDOMStorage: function(s) + { + var isLocalStorage = (s === InspectorController.inspectedWindow().localStorage); + for (var i = 0, len = this._domStorage.length; i < len; ++i) { + var storage = this._domStorage[i]; + if ( isLocalStorage === storage.isLocalStorage ) { + this.showDOMStorage(storage); + storage._domStorageTreeElement.select(); + return; + } + } + }, + showDatabase: function(database, tableName) { if (!database) @@ -175,7 +205,7 @@ WebInspector.DatabasesPanel.prototype = { this.visibleView = view; this.storageViewStatusBarItemsContainer.removeChildren(); - var statusBarItems = view.statusBarItems; + var statusBarItems = view.statusBarItems || []; for (var i = 0; i < statusBarItems.length; ++i) this.storageViewStatusBarItemsContainer.appendChild(statusBarItems[i]); }, @@ -332,7 +362,7 @@ WebInspector.DatabasesPanel.prototype = { var nodes = []; var length = domStorage.length; - for (index = 0; index < domStorage.length; index++) { + for (var index = 0; index < domStorage.length; index++) { var data = {}; var key = String(domStorage.key(index)); @@ -365,10 +395,58 @@ WebInspector.DatabasesPanel.prototype = { var length = nodes.length; for (var i = 0; i < length; ++i) dataGrid.appendChild(nodes[i]); + dataGrid.addCreationNode(false); if (length > 0) nodes[0].selected = true; return dataGrid; }, + + resize: function() + { + var visibleView = this.visibleView; + if (visibleView && "resize" in visibleView) + visibleView.resize(); + }, + + _registerStorageEventListener: function() + { + var inspectedWindow = InspectorController.inspectedWindow(); + if (!inspectedWindow || !inspectedWindow.document) + return; + + this._storageEventListener = InspectorController.wrapCallback(this._storageEvent.bind(this)); + inspectedWindow.addEventListener("storage", this._storageEventListener, true); + }, + + _unregisterStorageEventListener: function() + { + if (!this._storageEventListener) + return; + + var inspectedWindow = InspectorController.inspectedWindow(); + if (!inspectedWindow || !inspectedWindow.document) + return; + + inspectedWindow.removeEventListener("storage", this._storageEventListener, true); + delete this._storageEventListener; + }, + + _storageEvent: function(event) + { + if (!this._domStorage) + return; + + var isLocalStorage = (event.storageArea === InspectorController.inspectedWindow().localStorage); + var domStorageLength = this._domStorage.length; + for (var i = 0; i < domStorageLength; ++i) { + var domStorage = this._domStorage[i]; + if (isLocalStorage === domStorage.isLocalStorage) { + var view = domStorage._domStorageView; + if (this.visibleView && view === this.visibleView) + domStorage._domStorageView.update(); + } + } + }, _startSidebarDragging: function(event) { @@ -409,6 +487,10 @@ WebInspector.DatabasesPanel.prototype = { this.storageViews.style.left = width + "px"; this.storageViewStatusBarItemsContainer.style.left = width + "px"; this.sidebarResizeElement.style.left = (width - 3) + "px"; + + var visibleView = this.visibleView; + if (visibleView && "resize" in visibleView) + visibleView.resize(); } } diff --git a/WebCore/inspector/front-end/Drawer.js b/WebCore/inspector/front-end/Drawer.js new file mode 100644 index 0000000..23dc483 --- /dev/null +++ b/WebCore/inspector/front-end/Drawer.js @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2009 Joseph Pecoraro + * + * 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.Drawer = function() +{ + WebInspector.View.call(this, document.getElementById("drawer")); + + this.mainStatusBar = document.getElementById("main-status-bar"); + this.mainStatusBar.addEventListener("mousedown", this._startStatusBarDragging.bind(this), true); + this.viewStatusBar = document.getElementById("other-drawer-status-bar-items"); +} + +WebInspector.Drawer.prototype = { + get visibleView() + { + return this._visibleView; + }, + + set visibleView(x) + { + if (this._visibleView === x) { + this.visible = !this.visible; + return; + } + + var firstTime = !this._visibleView; + if (this._visibleView) + this._visibleView.hide(); + + this._visibleView = x; + + if (x && !firstTime) { + this._safelyRemoveChildren(); + this.viewStatusBar.removeChildren(); // optimize this? call old.detach() + x.attach(this.element, this.viewStatusBar); + x.show(); + this.visible = true; + } + }, + + show: function() + { + if (this._animating || this.visible) + return; + + if (this.visibleView) + this.visibleView.show(); + + WebInspector.View.prototype.show.call(this); + + this._animating = true; + + document.body.addStyleClass("drawer-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-drawer-status-bar-items"), start: {opacity: 0}, end: {opacity: 1}} + ]; + + var consoleStatusBar = document.getElementById("drawer-status-bar"); + consoleStatusBar.insertBefore(anchoredItems, consoleStatusBar.firstChild); + + function animationFinished() + { + if ("updateStatusBarItems" in WebInspector.currentPanel) + WebInspector.currentPanel.updateStatusBarItems(); + if (this.visibleView.afterShow) + this.visibleView.afterShow(); + delete this._animating; + } + + WebInspector.animateStyle(animations, window.event && window.event.shiftKey ? 2000 : 250, animationFinished.bind(this)); + }, + + hide: function() + { + if (this._animating || !this.visible) + return; + + WebInspector.View.prototype.hide.call(this); + + if (this.visibleView) + this.visibleView.hide(); + + this._animating = true; + + 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("drawer-visible"); + if ("updateStatusBarItems" in WebInspector.currentPanel) + WebInspector.currentPanel.updateStatusBarItems(); + document.body.addStyleClass("drawer-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-drawer-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("drawer-visible"); + delete this._animating; + } + + WebInspector.animateStyle(animations, window.event && window.event.shiftKey ? 2000 : 250, animationFinished.bind(this)); + }, + + _safelyRemoveChildren: function() + { + var child = this.element.firstChild; + while (child) { + if (child.id !== "drawer-status-bar") { + var moveTo = child.nextSibling; + this.element.removeChild(child); + child = moveTo; + } else + child = child.nextSibling; + } + }, + + _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(); + } +} + +WebInspector.Drawer.prototype.__proto__ = WebInspector.View.prototype; diff --git a/WebCore/inspector/front-end/ElementsPanel.js b/WebCore/inspector/front-end/ElementsPanel.js index 3c9be54..ffa0000 100644 --- a/WebCore/inspector/front-end/ElementsPanel.js +++ b/WebCore/inspector/front-end/ElementsPanel.js @@ -1,6 +1,7 @@ /* * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. * Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com> + * Copyright (C) 2009 Joseph Pecoraro * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -60,6 +61,7 @@ WebInspector.ElementsPanel = function() InspectorController.toggleNodeSearch(); this.panel.nodeSearchButton.removeStyleClass("toggled-on"); } + WebInspector.console.addInspectedNode(this._focusedDOMNode); }; this.contentElement.appendChild(this.treeOutline.element); @@ -95,7 +97,7 @@ WebInspector.ElementsPanel = function() this.sidebarResizeElement.className = "sidebar-resizer-vertical"; this.sidebarResizeElement.addEventListener("mousedown", this.rightSidebarResizerDragStart.bind(this), false); - this.nodeSearchButton = document.createElement("button"); + this.nodeSearchButton = this.createStatusBarButton(); 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"; @@ -112,6 +114,9 @@ WebInspector.ElementsPanel = function() this._nodeRemovedEventListener = InspectorController.wrapCallback(this._nodeRemoved.bind(this)); this._contentLoadedEventListener = InspectorController.wrapCallback(this._contentLoaded.bind(this)); + this.stylesheet = null; + this.styles = {}; + this.reset(); } @@ -179,7 +184,7 @@ WebInspector.ElementsPanel.prototype = { delete this.currentQuery; this.searchCanceled(); - var inspectedWindow = InspectorController.inspectedWindow(); + var inspectedWindow = Preferences.useDOMAgent ? WebInspector.domAgent.inspectedWindow : InspectorController.inspectedWindow(); if (!inspectedWindow || !inspectedWindow.document) return; @@ -516,6 +521,121 @@ WebInspector.ElementsPanel.prototype = { this.updateMutationEventListeners(window); }, + renameSelector: function(oldIdentifier, newIdentifier, oldSelector, newSelector) + { + // TODO: Implement Shifting the oldSelector, and its contents to a newSelector + }, + + addStyleChange: function(identifier, style, property) + { + if (!style.parentRule) + return; + + var selector = style.parentRule.selectorText; + if (!this.styles[identifier]) + this.styles[identifier] = {}; + + if (!this.styles[identifier][selector]) + this.styles[identifier][selector] = {}; + + if (!this.styles[identifier][selector][property]) + WebInspector.styleChanges += 1; + + this.styles[identifier][selector][property] = style.getPropertyValue(property); + }, + + removeStyleChange: function(identifier, style, property) + { + if (!style.parentRule) + return; + + var selector = style.parentRule.selectorText; + if (!this.styles[identifier] || !this.styles[identifier][selector]) + return; + + if (this.styles[identifier][selector][property]) { + delete this.styles[identifier][selector][property]; + WebInspector.styleChanges -= 1; + } + }, + + generateStylesheet: function() + { + if (!WebInspector.styleChanges) + return; + + // Merge Down to Just Selectors + var mergedSelectors = {}; + for (var identifier in this.styles) { + for (var selector in this.styles[identifier]) { + if (!mergedSelectors[selector]) + mergedSelectors[selector] = this.styles[identifier][selector]; + else { // merge on selector + var merge = {}; + for (var property in mergedSelectors[selector]) + merge[property] = mergedSelectors[selector][property]; + for (var property in this.styles[identifier][selector]) { + if (!merge[property]) + merge[property] = this.styles[identifier][selector][property]; + else { // merge on property within a selector, include comment to notify user + var value1 = merge[property]; + var value2 = this.styles[identifier][selector][property]; + + if (value1 === value2) + merge[property] = [value1]; + else if (Object.type(value1) === "array") + merge[property].push(value2); + else + merge[property] = [value1, value2]; + } + } + mergedSelectors[selector] = merge; + } + } + } + + var builder = []; + builder.push("/**"); + builder.push(" * Inspector Generated Stylesheet"); // UIString? + builder.push(" */\n"); + + var indent = " "; + function displayProperty(property, value, comment) { + if (comment) + return indent + "/* " + property + ": " + value + "; */"; + else + return indent + property + ": " + value + ";"; + } + + for (var selector in mergedSelectors) { + var psuedoStyle = mergedSelectors[selector]; + var properties = Object.properties(psuedoStyle); + if (properties.length) { + builder.push(selector + " {"); + for (var i = 0; i < properties.length; ++i) { + var property = properties[i]; + var value = psuedoStyle[property]; + if (Object.type(value) !== "array") + builder.push(displayProperty(property, value)); + else { + if (value.length === 1) + builder.push(displayProperty(property, value) + " /* merged from equivalent edits */"); // UIString? + else { + builder.push(indent + "/* There was a Conflict... There were Multiple Edits for '" + property + "' */"); // UIString? + for (var j = 0; j < value.length; ++j) + builder.push(displayProperty(property, value, true)); + } + } + } + builder.push("}\n"); + } + } + + WebInspector.showConsole(); + var result = builder.join("\n"); + InspectorController.inspectedWindow().console.log(result); + }, + _addMutationEventListeners: function(monitoredWindow) { monitoredWindow.document.addEventListener("DOMNodeInserted", this._nodeInsertedEventListener, true); @@ -913,7 +1033,7 @@ WebInspector.ElementsPanel.prototype = { { var rightPadding = 20; var errorWarningElement = document.getElementById("error-warning-count"); - if (!WebInspector.console.visible && errorWarningElement) + if (!WebInspector.drawer.visible && errorWarningElement) rightPadding += errorWarningElement.offsetWidth; return ((crumbs.totalOffsetLeft + crumbs.offsetWidth + rightPadding) < window.innerWidth); } diff --git a/WebCore/inspector/front-end/ElementsTreeOutline.js b/WebCore/inspector/front-end/ElementsTreeOutline.js index 2da2f10..ef53209 100644 --- a/WebCore/inspector/front-end/ElementsTreeOutline.js +++ b/WebCore/inspector/front-end/ElementsTreeOutline.js @@ -1,6 +1,7 @@ /* * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. * Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com> + * Copyright (C) 2009 Joseph Pecoraro * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -255,6 +256,9 @@ WebInspector.ElementsTreeElement = function(node) // The title will be updated in onattach. TreeElement.call(this, "", node, titleInfo.hasChildren); + + if (this.representedObject.nodeType == Node.ELEMENT_NODE) + this._canAddAttributes = true; } WebInspector.ElementsTreeElement.prototype = { @@ -296,9 +300,36 @@ WebInspector.ElementsTreeElement.prototype = { this.listItemElement.addStyleClass("hovered"); } else this.listItemElement.removeStyleClass("hovered"); + if (this._canAddAttributes) + this.toggleNewAttributeButton(); } }, + toggleNewAttributeButton: function() + { + function removeWhenEditing(event) + { + if (this._addAttributeElement && this._addAttributeElement.parentNode) + this._addAttributeElement.parentNode.removeChild(this._addAttributeElement); + delete this._addAttributeElement; + } + + if (!this._addAttributeElement && this._hovered && !this._editing) { + var span = document.createElement("span"); + span.className = "add-attribute"; + span.textContent = "\u2026"; + span.addEventListener("dblclick", removeWhenEditing.bind(this), false); + this._addAttributeElement = span; + + var tag = this.listItemElement.getElementsByClassName("webkit-html-tag")[0]; + this._insertInLastAttributePosition(tag, span); + } else if (!this._hovered && this._addAttributeElement) { + if (this._addAttributeElement.parentNode) + this._addAttributeElement.parentNode.removeChild(this._addAttributeElement); + delete this._addAttributeElement; + } + }, + updateSelection: function() { var listItemElement = this.listItemElement; @@ -483,7 +514,7 @@ WebInspector.ElementsTreeElement.prototype = { if (this._editing) return; - if (this._startEditing(event)) + if (this._startEditing(event, treeElement)) return; if (this.treeOutline.panel) { @@ -495,7 +526,20 @@ WebInspector.ElementsTreeElement.prototype = { this.expand(); }, - _startEditing: function(event) + _insertInLastAttributePosition: function(tag, node) + { + if (tag.getElementsByClassName("webkit-html-attribute").length > 0) + tag.insertBefore(node, tag.lastChild); + else { + var nodeName = tag.textContent.match(/^<(.*?)>$/)[1]; + tag.textContent = ''; + tag.appendChild(document.createTextNode('<'+nodeName)); + tag.appendChild(node); + tag.appendChild(document.createTextNode('>')); + } + }, + + _startEditing: function(event, treeElement) { if (this.treeOutline.focusedDOMNode != this.representedObject) return; @@ -509,12 +553,51 @@ WebInspector.ElementsTreeElement.prototype = { var attribute = event.target.enclosingNodeOrSelfWithClass("webkit-html-attribute"); if (attribute) - return this._startEditingAttribute(attribute, event); + return this._startEditingAttribute(attribute, event.target); + + var newAttribute = event.target.enclosingNodeOrSelfWithClass("add-attribute"); + if (newAttribute) + return this._addNewAttribute(treeElement.listItemElement); return false; }, - _startEditingAttribute: function(attribute, event) + _addNewAttribute: function(listItemElement) + { + var attr = document.createElement("span"); + attr.className = "webkit-html-attribute"; + attr.style.marginLeft = "2px"; // overrides the .editing margin rule + attr.style.marginRight = "2px"; // overrides the .editing margin rule + var name = document.createElement("span"); + name.className = "webkit-html-attribute-name new-attribute"; + name.textContent = " "; + var value = document.createElement("span"); + value.className = "webkit-html-attribute-value"; + attr.appendChild(name); + attr.appendChild(value); + + var tag = listItemElement.getElementsByClassName("webkit-html-tag")[0]; + this._insertInLastAttributePosition(tag, attr); + return this._startEditingAttribute(attr, attr); + }, + + _triggerEditAttribute: function(attributeName) + { + var attributeElements = this.listItemElement.getElementsByClassName("webkit-html-attribute-name"); + for (var i = 0, len = attributeElements.length; i < len; ++i) { + if (attributeElements[i].textContent === attributeName) { + for (var elem = attributeElements[i].nextSibling; elem; elem = elem.nextSibling) { + if (elem.nodeType !== Node.ELEMENT_NODE) + continue; + + if (elem.hasStyleClass("webkit-html-attribute-value")) + return this._startEditingAttribute(attributeElements[i].parentNode, elem); + } + } + } + }, + + _startEditingAttribute: function(attribute, elementForSelection) { if (WebInspector.isBeingEdited(attribute)) return true; @@ -545,7 +628,7 @@ WebInspector.ElementsTreeElement.prototype = { this._editing = true; WebInspector.startEditing(attribute, this._attributeEditingCommitted.bind(this), this._editingCancelled.bind(this), attributeName); - window.getSelection().setBaseAndExtent(event.target, 0, event.target, 1); + window.getSelection().setBaseAndExtent(elementForSelection, 0, elementForSelection, 1); return true; }, @@ -563,15 +646,56 @@ WebInspector.ElementsTreeElement.prototype = { return true; }, - _attributeEditingCommitted: function(element, newText, oldText, attributeName) + _attributeEditingCommitted: function(element, newText, oldText, attributeName, moveDirection) { delete this._editing; + // Before we do anything, determine where we should move + // next based on the current element's settings + var moveToAttribute; + var newAttribute; + if (moveDirection) { + var found = false; + var attributes = this.representedObject.attributes; + for (var i = 0, len = attributes.length; i < len; ++i) { + if (attributes[i].name === attributeName) { + found = true; + if (moveDirection === "backward" && i > 0) + moveToAttribute = attributes[i - 1].name; + else if (moveDirection === "forward" && i < attributes.length - 1) + moveToAttribute = attributes[i + 1].name; + else if (moveDirection === "forward" && i === attributes.length - 1) + newAttribute = true; + } + } + + if (!found && moveDirection === "backward") + moveToAttribute = attributes[attributes.length - 1].name; + else if (!found && moveDirection === "forward" && !/^\s*$/.test(newText)) + newAttribute = true; + } + + function moveToNextAttributeIfNeeded() { + if (moveToAttribute) + this._triggerEditAttribute(moveToAttribute); + else if (newAttribute) + this._addNewAttribute(this.listItemElement); + } + var parseContainerElement = document.createElement("span"); parseContainerElement.innerHTML = "<span " + newText + "></span>"; var parseElement = parseContainerElement.firstChild; - if (!parseElement || !parseElement.hasAttributes()) { - this._editingCancelled(element, context); + + if (!parseElement) { + this._editingCancelled(element, attributeName); + moveToNextAttributeIfNeeded.call(this); + return; + } + + if (!parseElement.hasAttributes()) { + InspectorController.inspectedWindow().Element.prototype.removeAttribute.call(this.representedObject, attributeName); + this._updateTitle(); + moveToNextAttributeIfNeeded.call(this); return; } @@ -579,7 +703,9 @@ WebInspector.ElementsTreeElement.prototype = { 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); + try { + InspectorController.inspectedWindow().Element.prototype.setAttribute.call(this.representedObject, attr.name, attr.value); + } catch(e) {} // ignore invalid attribute (innerHTML doesn't throw errors, but this can) } if (!foundOriginalAttribute) @@ -588,6 +714,8 @@ WebInspector.ElementsTreeElement.prototype = { this._updateTitle(); this.treeOutline.focusedNodeChanged(true); + + moveToNextAttributeIfNeeded.call(this); }, _textNodeEditingCommitted: function(element, newText) diff --git a/WebCore/inspector/front-end/Images/clearConsoleButtonGlyph.png b/WebCore/inspector/front-end/Images/clearConsoleButtonGlyph.png Binary files differnew file mode 100644 index 0000000..b1f9465 --- /dev/null +++ b/WebCore/inspector/front-end/Images/clearConsoleButtonGlyph.png diff --git a/WebCore/inspector/front-end/Images/clearConsoleButtons.png b/WebCore/inspector/front-end/Images/clearConsoleButtons.png Binary files differdeleted file mode 100644 index 140a4fb..0000000 --- a/WebCore/inspector/front-end/Images/clearConsoleButtons.png +++ /dev/null diff --git a/WebCore/inspector/front-end/Images/consoleButtonGlyph.png b/WebCore/inspector/front-end/Images/consoleButtonGlyph.png Binary files differnew file mode 100644 index 0000000..d10d43c --- /dev/null +++ b/WebCore/inspector/front-end/Images/consoleButtonGlyph.png diff --git a/WebCore/inspector/front-end/Images/consoleButtons.png b/WebCore/inspector/front-end/Images/consoleButtons.png Binary files differdeleted file mode 100644 index fb5f089..0000000 --- a/WebCore/inspector/front-end/Images/consoleButtons.png +++ /dev/null diff --git a/WebCore/inspector/front-end/Images/dockButtonGlyph.png b/WebCore/inspector/front-end/Images/dockButtonGlyph.png Binary files differnew file mode 100644 index 0000000..7052f4b --- /dev/null +++ b/WebCore/inspector/front-end/Images/dockButtonGlyph.png diff --git a/WebCore/inspector/front-end/Images/dockButtons.png b/WebCore/inspector/front-end/Images/dockButtons.png Binary files differdeleted file mode 100644 index 4b01d66..0000000 --- a/WebCore/inspector/front-end/Images/dockButtons.png +++ /dev/null diff --git a/WebCore/inspector/front-end/Images/enableButtons.png b/WebCore/inspector/front-end/Images/enableButtons.png Binary files differdeleted file mode 100644 index facee60..0000000 --- a/WebCore/inspector/front-end/Images/enableButtons.png +++ /dev/null diff --git a/WebCore/inspector/front-end/Images/enableOutlineButtonGlyph.png b/WebCore/inspector/front-end/Images/enableOutlineButtonGlyph.png Binary files differnew file mode 100644 index 0000000..85e0bd6 --- /dev/null +++ b/WebCore/inspector/front-end/Images/enableOutlineButtonGlyph.png diff --git a/WebCore/inspector/front-end/Images/enableSolidButtonGlyph.png b/WebCore/inspector/front-end/Images/enableSolidButtonGlyph.png Binary files differnew file mode 100644 index 0000000..25b2e96 --- /dev/null +++ b/WebCore/inspector/front-end/Images/enableSolidButtonGlyph.png diff --git a/WebCore/inspector/front-end/Images/excludeButtonGlyph.png b/WebCore/inspector/front-end/Images/excludeButtonGlyph.png Binary files differnew file mode 100644 index 0000000..5128576 --- /dev/null +++ b/WebCore/inspector/front-end/Images/excludeButtonGlyph.png diff --git a/WebCore/inspector/front-end/Images/excludeButtons.png b/WebCore/inspector/front-end/Images/excludeButtons.png Binary files differdeleted file mode 100644 index f1c53a9..0000000 --- a/WebCore/inspector/front-end/Images/excludeButtons.png +++ /dev/null diff --git a/WebCore/inspector/front-end/Images/focusButtonGlyph.png b/WebCore/inspector/front-end/Images/focusButtonGlyph.png Binary files differnew file mode 100644 index 0000000..b71807c --- /dev/null +++ b/WebCore/inspector/front-end/Images/focusButtonGlyph.png diff --git a/WebCore/inspector/front-end/Images/focusButtons.png b/WebCore/inspector/front-end/Images/focusButtons.png Binary files differdeleted file mode 100644 index 47eaa04..0000000 --- a/WebCore/inspector/front-end/Images/focusButtons.png +++ /dev/null diff --git a/WebCore/inspector/front-end/Images/largerResourcesButtonGlyph.png b/WebCore/inspector/front-end/Images/largerResourcesButtonGlyph.png Binary files differnew file mode 100644 index 0000000..71256d6 --- /dev/null +++ b/WebCore/inspector/front-end/Images/largerResourcesButtonGlyph.png diff --git a/WebCore/inspector/front-end/Images/largerResourcesButtons.png b/WebCore/inspector/front-end/Images/largerResourcesButtons.png Binary files differdeleted file mode 100644 index caf3f14..0000000 --- a/WebCore/inspector/front-end/Images/largerResourcesButtons.png +++ /dev/null diff --git a/WebCore/inspector/front-end/Images/nodeSearchButtonGlyph.png b/WebCore/inspector/front-end/Images/nodeSearchButtonGlyph.png Binary files differnew file mode 100644 index 0000000..faf5df2 --- /dev/null +++ b/WebCore/inspector/front-end/Images/nodeSearchButtonGlyph.png diff --git a/WebCore/inspector/front-end/Images/nodeSearchButtons.png b/WebCore/inspector/front-end/Images/nodeSearchButtons.png Binary files differdeleted file mode 100644 index 0599bd4..0000000 --- a/WebCore/inspector/front-end/Images/nodeSearchButtons.png +++ /dev/null diff --git a/WebCore/inspector/front-end/Images/pauseOnExceptionButtonGlyph.png b/WebCore/inspector/front-end/Images/pauseOnExceptionButtonGlyph.png Binary files differnew file mode 100644 index 0000000..c3cec5f --- /dev/null +++ b/WebCore/inspector/front-end/Images/pauseOnExceptionButtonGlyph.png diff --git a/WebCore/inspector/front-end/Images/pauseOnExceptionButtons.png b/WebCore/inspector/front-end/Images/pauseOnExceptionButtons.png Binary files differdeleted file mode 100644 index a4dd33a..0000000 --- a/WebCore/inspector/front-end/Images/pauseOnExceptionButtons.png +++ /dev/null diff --git a/WebCore/inspector/front-end/Images/percentButtonGlyph.png b/WebCore/inspector/front-end/Images/percentButtonGlyph.png Binary files differnew file mode 100644 index 0000000..0ace3b7 --- /dev/null +++ b/WebCore/inspector/front-end/Images/percentButtonGlyph.png diff --git a/WebCore/inspector/front-end/Images/percentButtons.png b/WebCore/inspector/front-end/Images/percentButtons.png Binary files differdeleted file mode 100644 index 2635b24..0000000 --- a/WebCore/inspector/front-end/Images/percentButtons.png +++ /dev/null diff --git a/WebCore/inspector/front-end/Images/recordButtonGlyph.png b/WebCore/inspector/front-end/Images/recordButtonGlyph.png Binary files differnew file mode 100644 index 0000000..bfdad1a --- /dev/null +++ b/WebCore/inspector/front-end/Images/recordButtonGlyph.png diff --git a/WebCore/inspector/front-end/Images/recordButtons.png b/WebCore/inspector/front-end/Images/recordButtons.png Binary files differdeleted file mode 100644 index 3676154..0000000 --- a/WebCore/inspector/front-end/Images/recordButtons.png +++ /dev/null diff --git a/WebCore/inspector/front-end/Images/recordToggledButtonGlyph.png b/WebCore/inspector/front-end/Images/recordToggledButtonGlyph.png Binary files differnew file mode 100644 index 0000000..2c22f87 --- /dev/null +++ b/WebCore/inspector/front-end/Images/recordToggledButtonGlyph.png diff --git a/WebCore/inspector/front-end/Images/reloadButtonGlyph.png b/WebCore/inspector/front-end/Images/reloadButtonGlyph.png Binary files differnew file mode 100644 index 0000000..28e047a --- /dev/null +++ b/WebCore/inspector/front-end/Images/reloadButtonGlyph.png diff --git a/WebCore/inspector/front-end/Images/reloadButtons.png b/WebCore/inspector/front-end/Images/reloadButtons.png Binary files differdeleted file mode 100644 index 1e45671..0000000 --- a/WebCore/inspector/front-end/Images/reloadButtons.png +++ /dev/null diff --git a/WebCore/inspector/front-end/Images/resourcesSilhouette.png b/WebCore/inspector/front-end/Images/resourcesSilhouette.png Binary files differnew file mode 100644 index 0000000..9c8bb53 --- /dev/null +++ b/WebCore/inspector/front-end/Images/resourcesSilhouette.png diff --git a/WebCore/inspector/front-end/Images/undockButtonGlyph.png b/WebCore/inspector/front-end/Images/undockButtonGlyph.png Binary files differnew file mode 100644 index 0000000..eed2b65 --- /dev/null +++ b/WebCore/inspector/front-end/Images/undockButtonGlyph.png diff --git a/WebCore/inspector/front-end/InjectedScript.js b/WebCore/inspector/front-end/InjectedScript.js new file mode 100644 index 0000000..4611b48 --- /dev/null +++ b/WebCore/inspector/front-end/InjectedScript.js @@ -0,0 +1,516 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2009 Joseph Pecoraro + * + * 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 InjectedScript = { + _styles: {}, + _styleRules: {}, + _lastStyleId: 0, + _lastStyleRuleId: 0 +}; + +InjectedScript.getStyles = function(nodeId, authorOnly) +{ + var node = InjectedScript._nodeForId(nodeId); + if (!node) + return false; + var matchedRules = InjectedScript._window().getMatchedCSSRules(node, "", authorOnly); + var matchedCSSRules = []; + for (var i = 0; matchedRules && i < matchedRules.length; ++i) + matchedCSSRules.push(InjectedScript._serializeRule(matchedRules[i])); + + var styleAttributes = {}; + var attributes = node.attributes; + for (var i = 0; attributes && i < attributes.length; ++i) { + if (attributes[i].style) + styleAttributes[attributes[i].name] = InjectedScript._serializeStyle(attributes[i].style, true); + } + var result = {}; + result.inlineStyle = InjectedScript._serializeStyle(node.style, true); + result.computedStyle = InjectedScript._serializeStyle(InjectedScript._window().getComputedStyle(node)); + result.matchedCSSRules = matchedCSSRules; + result.styleAttributes = styleAttributes; + return result; +} + +InjectedScript.getComputedStyle = function(nodeId) +{ + var node = InjectedScript._nodeForId(nodeId); + if (!node) + return false; + return InjectedScript._serializeStyle(InjectedScript._window().getComputedStyle(node)); +} + +InjectedScript.getInlineStyle = function(nodeId) +{ + var node = InjectedScript._nodeForId(nodeId); + if (!node) + return false; + return InjectedScript._serializeStyle(node.style, true); +} + +InjectedScript.applyStyleText = function(styleId, styleText, propertyName) +{ + var style = InjectedScript._styles[styleId]; + if (!style) + return false; + + var styleTextLength = 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(propertyName)) { + var longhandProperties = InjectedScript._getLonghandProperties(style, propertyName); + for (var i = 0; i < longhandProperties.length; ++i) + style.removeProperty(longhandProperties[i]); + } else + style.removeProperty(propertyName); + } + + if (!tempStyle.length) + 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 changedProperties = []; + var uniqueProperties = InjectedScript._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 = InjectedScript._getShorthandValue(tempStyle, shorthand); + var priority = InjectedScript._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); + changedProperties.push(shorthand || name); + } + return [InjectedScript._serializeStyle(style, true), changedProperties]; +} + +InjectedScript.setStyleText = function(style, cssText) +{ + style.cssText = cssText; +} + +InjectedScript.toggleStyleEnabled = function(styleId, propertyName, disabled) +{ + var style = InjectedScript._styles[styleId]; + if (!style) + return false; + + if (disabled) { + if (!style.__disabledPropertyValues || !style.__disabledPropertyPriorities) { + var inspectedWindow = InjectedScript._window(); + style.__disabledProperties = new inspectedWindow.Object; + style.__disabledPropertyValues = new inspectedWindow.Object; + style.__disabledPropertyPriorities = new inspectedWindow.Object; + } + + style.__disabledPropertyValues[propertyName] = style.getPropertyValue(propertyName); + style.__disabledPropertyPriorities[propertyName] = style.getPropertyPriority(propertyName); + + if (style.getPropertyShorthand(propertyName)) { + var longhandProperties = InjectedScript._getLonghandProperties(style, propertyName); + for (var i = 0; i < longhandProperties.length; ++i) { + style.__disabledProperties[longhandProperties[i]] = true; + style.removeProperty(longhandProperties[i]); + } + } else { + style.__disabledProperties[propertyName] = true; + style.removeProperty(propertyName); + } + } else if (style.__disabledProperties && style.__disabledProperties[propertyName]) { + var value = style.__disabledPropertyValues[propertyName]; + var priority = style.__disabledPropertyPriorities[propertyName]; + + style.setProperty(propertyName, value, priority); + delete style.__disabledProperties[propertyName]; + delete style.__disabledPropertyValues[propertyName]; + delete style.__disabledPropertyPriorities[propertyName]; + } + return InjectedScript._serializeStyle(style, true); +} + +InjectedScript.applyStyleRuleText = function(ruleId, newContent, selectedNode) +{ + var rule = InjectedScript._styleRules[ruleId]; + if (!rule) + return false; + + try { + var stylesheet = rule.parentStyleSheet; + stylesheet.addRule(newContent); + var newRule = stylesheet.cssRules[stylesheet.cssRules.length - 1]; + newRule.style.cssText = rule.style.cssText; + + var parentRules = stylesheet.cssRules; + for (var i = 0; i < parentRules.length; ++i) { + if (parentRules[i] === rule) { + rule.parentStyleSheet.removeRule(i); + break; + } + } + + var nodes = selectedNode.ownerDocument.querySelectorAll(newContent); + for (var i = 0; i < nodes.length; ++i) { + if (nodes[i] === selectedNode) { + return [InjectedScript._serializeRule(newRule), true]; + } + } + return [InjectedScript._serializeRule(newRule), false]; + } catch(e) { + // Report invalid syntax. + return false; + } +} + +InjectedScript.addStyleSelector = function(newContent) +{ + var stylesheet = InjectedScript.stylesheet; + if (!stylesheet) { + var inspectedDocument = InjectedScript._window().document; + var head = inspectedDocument.getElementsByTagName("head")[0]; + var styleElement = inspectedDocument.createElement("style"); + styleElement.type = "text/css"; + head.appendChild(styleElement); + stylesheet = inspectedDocument.styleSheets[inspectedDocument.styleSheets.length - 1]; + InjectedScript.stylesheet = stylesheet; + } + + try { + stylesheet.addRule(newContent); + } catch (e) { + // Invalid Syntax for a Selector + return false; + } + + return InjectedScript._serializeRule(stylesheet.cssRules[stylesheet.cssRules.length - 1]); +} + +InjectedScript.setStyleProperty = function(styleId, name, value) { + var style = InjectedScript._styles[styleId]; + if (!style) + return false; + + style.setProperty(name, value, ""); + return true; +} + +InjectedScript._serializeRule = function(rule) +{ + var parentStyleSheet = rule.parentStyleSheet; + + var ruleValue = {}; + ruleValue.selectorText = rule.selectorText; + if (parentStyleSheet) { + ruleValue.parentStyleSheet = {}; + ruleValue.parentStyleSheet.href = parentStyleSheet.href; + } + ruleValue.isUserAgent = parentStyleSheet && !parentStyleSheet.ownerNode && !parentStyleSheet.href; + ruleValue.isUser = parentStyleSheet && parentStyleSheet.ownerNode && parentStyleSheet.ownerNode.nodeName == "#document"; + + // Bind editable scripts only. + var doBind = !ruleValue.isUserAgent && !ruleValue.isUser; + ruleValue.style = InjectedScript._serializeStyle(rule.style, doBind); + + if (doBind) { + if (!rule._id) { + rule._id = InjectedScript._lastStyleRuleId++; + InjectedScript._styleRules[rule._id] = rule; + } + ruleValue.id = rule._id; + } + return ruleValue; +} + +InjectedScript._serializeStyle = function(style, doBind) +{ + var result = {}; + result.width = style.width; + result.height = style.height; + result.__disabledProperties = style.__disabledProperties; + result.__disabledPropertyValues = style.__disabledPropertyValues; + result.__disabledPropertyPriorities = style.__disabledPropertyPriorities; + result.properties = []; + result.shorthandValues = {}; + var foundShorthands = {}; + for (var i = 0; i < style.length; ++i) { + var property = {}; + var name = style[i]; + property.name = name; + property.priority = style.getPropertyPriority(name); + property.implicit = style.isPropertyImplicit(name); + var shorthand = style.getPropertyShorthand(name); + property.shorthand = shorthand; + if (shorthand && !(shorthand in foundShorthands)) { + foundShorthands[shorthand] = true; + result.shorthandValues[shorthand] = InjectedScript._getShorthandValue(style, shorthand); + } + property.value = style.getPropertyValue(name); + result.properties.push(property); + } + result.uniqueStyleProperties = InjectedScript._getUniqueStyleProperties(style); + + if (doBind) { + if (!style._id) { + style._id = InjectedScript._lastStyleId++; + InjectedScript._styles[style._id] = style; + } + result.id = style._id; + } + return result; +} + +InjectedScript._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; +} + + +InjectedScript._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; +} + +InjectedScript._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; +} + +InjectedScript._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; +} + +InjectedScript.getPrototypes = function(nodeId) +{ + var node = InjectedScript._nodeForId(nodeId); + if (!node) + return false; + + var result = []; + for (var prototype = node; prototype; prototype = prototype.__proto__) { + var title = Object.describe(prototype); + if (title.match(/Prototype$/)) { + title = title.replace(/Prototype$/, ""); + } + result.push(title); + } + return result; +} + +InjectedScript.getProperties = function(objectProxy, ignoreHasOwnProperty) +{ + var object = InjectedScript._resolveObject(objectProxy); + if (!object) + return false; + + var properties = []; + // Go over properties, prepare results. + for (var propertyName in object) { + if (!ignoreHasOwnProperty && "hasOwnProperty" in object && !object.hasOwnProperty(propertyName)) + continue; + + //TODO: remove this once object becomes really remote. + if (propertyName === "__treeElementIdentifier") + continue; + var property = {}; + property.name = propertyName; + var isGetter = object["__lookupGetter__"] && object.__lookupGetter__(propertyName); + if (!property.isGetter) { + var childObject = object[propertyName]; + property.type = typeof childObject; + property.textContent = Object.describe(childObject, true); + property.parentObjectProxy = objectProxy; + var parentPath = objectProxy.path.slice(); + property.childObjectProxy = { + objectId : objectProxy.objectId, + path : parentPath.splice(parentPath.length, 0, propertyName), + protoDepth : objectProxy.protoDepth + }; + if (childObject && (property.type === "object" || property.type === "function")) { + for (var subPropertyName in childObject) { + if (propertyName === "__treeElementIdentifier") + continue; + property.hasChildren = true; + break; + } + } + } else { + // FIXME: this should show something like "getter" (bug 16734). + property.textContent = "\u2014"; // em dash + property.isGetter = true; + } + properties.push(property); + } + return properties; +} + +InjectedScript.setPropertyValue = function(objectProxy, propertyName, expression) +{ + var object = InjectedScript._resolveObject(objectProxy); + if (!object) + return false; + + var expressionLength = expression.length; + if (!expressionLength) { + delete object[propertyName]; + return !(propertyName in object); + } + + 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. + + // There is a regression introduced here: eval is now happening against global object, + // not call frame while on a breakpoint. + // TODO: bring evaluation against call frame back. + var result = InjectedScript._window().eval("(" + expression + ")"); + // Store the result in the property. + object[propertyName] = result; + return true; + } catch(e) { + try { + var result = InjectedScript._window().eval("\"" + expression.escapeCharacters("\"") + "\""); + object[propertyName] = result; + return true; + } catch(e) { + return false; + } + } +} + +InjectedScript._resolveObject = function(objectProxy) +{ + var object = InjectedScript._objectForId(objectProxy.objectId); + var path = objectProxy.path; + var protoDepth = objectProxy.protoDepth; + + // Follow the property path. + for (var i = 0; object && i < path.length; ++i) + object = object[path[i]]; + + // Get to the necessary proto layer. + for (var i = 0; object && i < protoDepth; ++i) + object = object.__proto__; + + return object; +} + +InjectedScript._window = function() +{ + // TODO: replace with 'return window;' once this script is injected into + // the page's context. + return InspectorController.inspectedWindow(); +} + +InjectedScript._nodeForId = function(nodeId) +{ + // TODO: replace with node lookup in the InspectorDOMAgent once DOMAgent nodes are used. + return nodeId; +} + +InjectedScript._objectForId = function(objectId) +{ + // TODO: replace with node lookups for node ids and evaluation result lookups for the rest of ids. + return objectId; +} diff --git a/WebCore/inspector/front-end/KeyboardShortcut.js b/WebCore/inspector/front-end/KeyboardShortcut.js new file mode 100644 index 0000000..ed28a48 --- /dev/null +++ b/WebCore/inspector/front-end/KeyboardShortcut.js @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009 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: + * + * 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.KeyboardShortcut = function() +{ +}; + +/** + * Constants for encoding modifier key set as a bit mask. + * @see #_makeKeyFromCodeAndModifiers + */ +WebInspector.KeyboardShortcut.Modifiers = { + None: 0, // Constant for empty modifiers set. + Shift: 1, + Ctrl: 2, + Alt: 4, + Meta: 8 // Command key on Mac, Win key on other platforms. +}; + +WebInspector.KeyboardShortcut.KeyCodes = { + Esc: 27, + Space: 32, + PageUp: 33, // also NUM_NORTH_EAST + PageDown: 34, // also NUM_SOUTH_EAST + End: 35, // also NUM_SOUTH_WEST + Home: 36, // also NUM_NORTH_WEST + Left: 37, // also NUM_WEST + Up: 38, // also NUM_NORTH + Right: 39, // also NUM_EAST + Down: 40, // also NUM_SOUTH + F1: 112, + F2: 113, + F3: 114, + F4: 115, + F5: 116, + F6: 117, + F7: 118, + F8: 119, + F9: 120, + F10: 121, + F11: 122, + F12: 123, + Semicolon: 186, // ; + Comma: 188, // , + Period: 190, // . + Slash: 191, // / + Apostrophe: 192, // ` + SingleQuote: 222, // ' +}; + +/** + * Creates a number encoding keyCode in the lower 8 bits and modifiers mask in the higher 8 bits. + * It is usefull for matching pressed keys. + * @param {number} keyCode Code of the key. + * @param {number} optModifiers Optional list of modifiers passed as additional paramerters. + */ +WebInspector.KeyboardShortcut.makeKey = function(keyCode, optModifiers) +{ + var modifiers = WebInspector.KeyboardShortcut.Modifiers.None; + for (var i = 1; i < arguments.length; i++) + modifiers |= arguments[i]; + return WebInspector.KeyboardShortcut._makeKeyFromCodeAndModifiers(keyCode, modifiers); +}; + +WebInspector.KeyboardShortcut.makeKeyFromEvent = function(keyboardEvent) +{ + var modifiers = WebInspector.KeyboardShortcut.Modifiers.None; + if (keyboardEvent.shiftKey) + modifiers |= WebInspector.KeyboardShortcut.Modifiers.Shift; + if (keyboardEvent.ctrlKey) + modifiers |= WebInspector.KeyboardShortcut.Modifiers.Ctrl; + if (keyboardEvent.altKey) + modifiers |= WebInspector.KeyboardShortcut.Modifiers.Alt; + if (keyboardEvent.metaKey) + modifiers |= WebInspector.KeyboardShortcut.Modifiers.Meta; + return WebInspector.KeyboardShortcut._makeKeyFromCodeAndModifiers(keyboardEvent.keyCode, modifiers); +}; + +WebInspector.KeyboardShortcut._makeKeyFromCodeAndModifiers = function(keyCode, modifiers) +{ + return (keyCode & 255) | (modifiers << 8); +}; diff --git a/WebCore/inspector/front-end/MetricsSidebarPane.js b/WebCore/inspector/front-end/MetricsSidebarPane.js index a22a000..8712dcd 100644 --- a/WebCore/inspector/front-end/MetricsSidebarPane.js +++ b/WebCore/inspector/front-end/MetricsSidebarPane.js @@ -29,6 +29,7 @@ WebInspector.MetricsSidebarPane = function() { WebInspector.SidebarPane.call(this, WebInspector.UIString("Metrics")); + this._inlineStyleId = null; } WebInspector.MetricsSidebarPane.prototype = { @@ -46,12 +47,28 @@ WebInspector.MetricsSidebarPane.prototype = { if (!node || !node.ownerDocument.defaultView) return; - var style; - if (node.nodeType === Node.ELEMENT_NODE) - style = node.ownerDocument.defaultView.getComputedStyle(node); - if (!style) + if (node.nodeType !== Node.ELEMENT_NODE) return; + var self = this; + var callback = function(stylePayload) { + if (!stylePayload) + return; + var style = WebInspector.CSSStyleDeclaration.parseStyle(stylePayload); + self._update(node, body, style); + }; + InspectorController.getComputedStyle(node, callback); + + var inlineStyleCallback = function(stylePayload) { + if (!stylePayload) + return; + self._inlineStyleId = stylePayload.id; + }; + InspectorController.getInlineStyle(node, inlineStyleCallback); + }, + + _update: function(node, body, style) + { var metricsElement = document.createElement("div"); metricsElement.className = "metrics"; @@ -184,11 +201,14 @@ WebInspector.MetricsSidebarPane.prototype = { if (/^\d+$/.test(userInput)) userInput += "px"; - this.node.style.setProperty(context.styleProperty, userInput, ""); - - this.dispatchEventToListeners("metrics edited"); - - this.update(); + var self = this; + var callback = function(success) { + if (!success) + return; + self.dispatchEventToListeners("metrics edited"); + self.update(); + }; + InspectorController.setStyleProperty(this._inlineStyleId, context.styleProperty, userInput, callback); } } diff --git a/WebCore/inspector/front-end/ObjectPropertiesSection.js b/WebCore/inspector/front-end/ObjectPropertiesSection.js index ab6ac55..9b03940 100644 --- a/WebCore/inspector/front-end/ObjectPropertiesSection.js +++ b/WebCore/inspector/front-end/ObjectPropertiesSection.js @@ -1,5 +1,6 @@ /* * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2009 Joseph Pecoraro * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -25,15 +26,6 @@ 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; @@ -52,42 +44,80 @@ WebInspector.ObjectPropertiesSection.prototype = { update: function() { - var properties = []; - for (var prop in this.object) - properties.push(prop); + var self = this; + var callback = function(properties) { + if (!properties) + return; + self._update(properties); + }; + InspectorController.getProperties(this.object, this.ignoreHasOwnProperty, callback); + }, + + _update: function(properties) + { if (this.extraProperties) for (var prop in this.extraProperties) - properties.push(prop); - properties.sort(); + properties.push(new WebInspector.ObjectPropertyProxy(prop, this.extraProperties[prop])); + properties.sort(this._displaySort); 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)); - } + for (var i = 0; i < properties.length; ++i) + this.propertiesTreeOutline.appendChild(new this.treeElementConstructor(properties[i])); if (!this.propertiesTreeOutline.children.length) { var title = "<div class=\"info\">" + this.emptyPlaceholder + "</div>"; var infoElement = new TreeElement(title, null, false); this.propertiesTreeOutline.appendChild(infoElement); } + }, + + _displaySort: function(propertyA, propertyB) { + var a = propertyA.name; + var b = propertyB.name; + + // if used elsewhere make sure to + // - convert a and b to strings (not needed here, properties are all strings) + // - check if a == b (not needed here, no two properties can be the same) + + var diff = 0; + var chunk = /^\d+|^\D+/; + var chunka, chunkb, anum, bnum; + while (diff === 0) { + if (!a && b) + return -1; + if (!b && a) + return 1; + chunka = a.match(chunk)[0]; + chunkb = b.match(chunk)[0]; + anum = !isNaN(chunka); + bnum = !isNaN(chunkb); + if (anum && !bnum) + return -1; + if (bnum && !anum) + return 1; + if (anum && bnum) { + diff = chunka - chunkb; + if (diff === 0 && chunka.length !== chunkb.length) { + if (!+chunka && !+chunkb) // chunks are strings of all 0s (special case) + return chunka.length - chunkb.length; + else + return chunkb.length - chunka.length; + } + } else if (chunka !== chunkb) + return (chunka < chunkb) ? -1 : 1; + a = a.substring(chunka.length); + b = b.substring(chunkb.length); + } + return diff; } } WebInspector.ObjectPropertiesSection.prototype.__proto__ = WebInspector.PropertiesSection.prototype; -WebInspector.ObjectPropertyTreeElement = function(parentObject, propertyName) +WebInspector.ObjectPropertyTreeElement = function(property) { - this.parentObject = parentObject; - this.propertyName = propertyName; + this.property = property; // Pass an empty title, the title gets made later in onattach. TreeElement.call(this, "", null, false); @@ -106,16 +136,18 @@ WebInspector.ObjectPropertyTreeElement.prototype = { if (this.children.length && !this.shouldRefreshChildren) return; - this.removeChildren(); + var self = this; + var callback = function(properties) { + self.removeChildren(); + if (!properties) + return; - 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)); - } + properties.sort(self._displaySort); + for (var i = 0; i < properties.length; ++i) { + self.appendChild(new self.treeOutline.section.treeElementConstructor(properties[i])); + } + }; + InspectorController.getProperties(this.property.childObjectProxy, false, callback); }, ondblclick: function(element, event) @@ -130,41 +162,22 @@ WebInspector.ObjectPropertyTreeElement.prototype = { 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; + nameElement.textContent = this.property.name; 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.valueElement.textContent = this.property.textContent; + if (this.property.isGetter) + 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; + this.hasChildren = this.property.hasChildren; }, updateSiblings: function() @@ -214,62 +227,27 @@ WebInspector.ObjectPropertyTreeElement.prototype = { 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); - } - } + expression = expression.trimWhitespace(); + var expressionLength = expression.length; + var self = this; + var callback = function(success) { + if (!updateInterface) + return; - return; - } + if (!success) + self.update(); - 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 (!expressionLength) { + // The property was deleted, so remove this tree element. + self.parent.removeChild(this); + } else { + // Call updateSiblings since their value might be based on the value that just changed. + self.updateSiblings(); } - } - - if (updateInterface) { - // Call updateSiblings since their value might be based on the value that just changed. - this.updateSiblings(); - } + }; + InspectorController.setPropertyValue(this.property.parentObjectProxy, this.property.name, expression.trimWhitespace(), callback); } } diff --git a/WebCore/inspector/front-end/ObjectProxy.js b/WebCore/inspector/front-end/ObjectProxy.js new file mode 100644 index 0000000..fa7816e --- /dev/null +++ b/WebCore/inspector/front-end/ObjectProxy.js @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2009 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. + * * Neither the name of Google Inc. 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 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. + */ + +WebInspector.ObjectProxy = function(objectId, path, protoDepth) +{ + this.objectId = objectId; + this.path = path || []; + this.protoDepth = protoDepth || 0; +} + +WebInspector.ObjectPropertyProxy = function(name, object) +{ + this.name = name; + this.type = "object"; + this.hasChildren = true; + this.textContent = Object.describe(object, true); + this.childObjectProxy = new WebInspector.ObjectProxy(object); +} diff --git a/WebCore/inspector/front-end/Panel.js b/WebCore/inspector/front-end/Panel.js index 5046f6b..3e2212c 100644 --- a/WebCore/inspector/front-end/Panel.js +++ b/WebCore/inspector/front-end/Panel.js @@ -66,6 +66,18 @@ WebInspector.Panel.prototype = { return this._toolbarItem; }, + createStatusBarButton: function() + { + var button = document.createElement("button"); + var glyph = document.createElement("div"); + glyph.className = "glyph"; + button.appendChild(glyph); + var glyphShadow = document.createElement("div"); + glyphShadow.className = "glyph shadow"; + button.appendChild(glyphShadow); + return button; + }, + show: function() { WebInspector.View.prototype.show.call(this); diff --git a/WebCore/inspector/front-end/ProfileView.js b/WebCore/inspector/front-end/ProfileView.js index d00733c..2517bd2 100644 --- a/WebCore/inspector/front-end/ProfileView.js +++ b/WebCore/inspector/front-end/ProfileView.js @@ -148,11 +148,23 @@ WebInspector.ProfileView.prototype = { return this._bottomUpTree; }, + show: function(parentElement) + { + WebInspector.View.prototype.show.call(this, parentElement); + this.dataGrid.updateWidths(); + }, + hide: function() { WebInspector.View.prototype.hide.call(this); this._currentSearchResultIndex = -1; }, + + resize: function() + { + if (this.dataGrid) + this.dataGrid.updateWidths(); + }, refresh: function() { @@ -166,8 +178,8 @@ WebInspector.ProfileView.prototype = { for (var index = 0; index < count; ++index) this.dataGrid.appendChild(children[index]); - if (selectedProfileNode && selectedProfileNode._dataGridNode) - selectedProfileNode._dataGridNode.selected = true; + if (selectedProfileNode) + selectedProfileNode.selected = true; }, refreshVisibleData: function() @@ -196,8 +208,7 @@ WebInspector.ProfileView.prototype = { delete profileNode._searchMatchedCallsColumn; delete profileNode._searchMatchedFunctionColumn; - if (profileNode._dataGridNode) - profileNode._dataGridNode.refresh(); + profileNode.refresh(); } } @@ -313,7 +324,7 @@ WebInspector.ProfileView.prototype = { profileDataGridNode._searchMatchedTotalColumn || profileDataGridNode._searchMatchedAverageColumn || profileDataGridNode._searchMatchedCallsColumn || - profileDataGridNode._searchMatchedFunctionColumn); + profileDataGridNode._searchMatchedFunctionColumn) { profileDataGridNode.refresh(); return true; @@ -322,48 +333,14 @@ WebInspector.ProfileView.prototype = { return false; } - var current = this.dataGrid; - var ancestors = []; - var nextIndexes = []; - var startIndex = 0; + var current = this.profileDataGridTree.children[0]; while (current) { - var children = current.children; - var childrenLength = children.length; - - if (startIndex >= childrenLength) { - current = ancestors.pop(); - startIndex = nextIndexes.pop(); - continue; + if (matchesQuery(current)) { + this._searchResults.push({ profileNode: current }); } - 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(); - } - } + current = current.traverseNextNode(false, null, false); } finishedCallback(this, this._searchResults.length); @@ -419,26 +396,9 @@ WebInspector.ProfileView.prototype = { 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(); + var profileNode = searchResult.profileNode; + profileNode.reveal(); + profileNode.select(); }, _changeView: function(event) diff --git a/WebCore/inspector/front-end/ProfilesPanel.js b/WebCore/inspector/front-end/ProfilesPanel.js index aafc306..c8b948a 100644 --- a/WebCore/inspector/front-end/ProfilesPanel.js +++ b/WebCore/inspector/front-end/ProfilesPanel.js @@ -59,11 +59,11 @@ WebInspector.ProfilesPanel = function() this.profileViews.id = "profile-views"; this.element.appendChild(this.profileViews); - this.enableToggleButton = document.createElement("button"); + this.enableToggleButton = this.createStatusBarButton(); 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 = this.createStatusBarButton(); this.recordButton.title = WebInspector.UIString("Start profiling."); this.recordButton.id = "record-profile-status-bar-item"; this.recordButton.className = "status-bar-item"; @@ -266,8 +266,10 @@ WebInspector.ProfilesPanel.prototype = { groupNumber = ++this._profileGroupsForLinks[title]; - if (groupNumber >= 2) - title += " " + WebInspector.UIString("Run %d", groupNumber); + if (groupNumber > 2) + // The title is used in the console message announcing that a profile has started so it gets + // incremented twice as often as it's displayed + title += " " + WebInspector.UIString("Run %d", groupNumber / 2); } return title; @@ -322,6 +324,13 @@ WebInspector.ProfilesPanel.prototype = { this.recordButton.title = WebInspector.UIString("Start profiling."); } }, + + resize: function() + { + var visibleView = this.visibleView; + if (visibleView && "resize" in visibleView) + visibleView.resize(); + }, _updateInterface: function() { @@ -422,6 +431,10 @@ WebInspector.ProfilesPanel.prototype = { this.profileViews.style.left = width + "px"; this.profileViewStatusBarItemsContainer.style.left = width + "px"; this.sidebarResizeElement.style.left = (width - 3) + "px"; + + var visibleView = this.visibleView; + if (visibleView && "resize" in visibleView) + visibleView.resize(); } } diff --git a/WebCore/inspector/front-end/PropertiesSidebarPane.js b/WebCore/inspector/front-end/PropertiesSidebarPane.js index 70db805..2d32137 100644 --- a/WebCore/inspector/front-end/PropertiesSidebarPane.js +++ b/WebCore/inspector/front-end/PropertiesSidebarPane.js @@ -43,11 +43,21 @@ WebInspector.PropertiesSidebarPane.prototype = { 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); - } + var self = this; + var callback = function(prototypes) { + var body = self.bodyElement; + body.removeChildren(); + self.sections = []; + + // Get array of prototype user-friendly names. + for (var i = 0; i < prototypes.length; ++i) { + var prototype = new WebInspector.ObjectProxy(object, [], i); + var section = new WebInspector.ObjectPropertiesSection(prototype, prototypes[i], WebInspector.UIString("Prototype")); + self.sections.push(section); + body.appendChild(section.element); + } + }; + InspectorController.getPrototypes(object, callback); } } diff --git a/WebCore/inspector/front-end/Resource.js b/WebCore/inspector/front-end/Resource.js index 058f232..bcb7b2a 100644 --- a/WebCore/inspector/front-end/Resource.js +++ b/WebCore/inspector/front-end/Resource.js @@ -341,12 +341,6 @@ WebInspector.Resource.prototype = { } }, - get documentNode() { - if ("identifier" in this) - return InspectorController.getResourceDocumentNode(this.identifier); - return null; - }, - get requestHeaders() { if (this._requestHeaders === undefined) @@ -489,7 +483,8 @@ WebInspector.Resource.prototype = { // 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.ConsoleMessage.MessageType.Log, WebInspector.ConsoleMessage.MessageLevel.Tip, + -1, this.url, null, 1, tip.message); WebInspector.console.addMessage(msg); */ }, @@ -549,6 +544,7 @@ WebInspector.Resource.prototype = { case WebInspector.Warnings.IncorrectMIMEType.id: if (!this._mimeTypeIsConsistentWithType()) msg = new WebInspector.ConsoleMessage(WebInspector.ConsoleMessage.MessageSource.Other, + WebInspector.ConsoleMessage.MessageType.Log, WebInspector.ConsoleMessage.MessageLevel.Warning, -1, this.url, null, 1, String.sprintf(WebInspector.Warnings.IncorrectMIMEType.message, WebInspector.Resource.Type.toString(this.type), this.mimeType)); diff --git a/WebCore/inspector/front-end/ResourcesPanel.js b/WebCore/inspector/front-end/ResourcesPanel.js index 04d998e..fb43551 100644 --- a/WebCore/inspector/front-end/ResourcesPanel.js +++ b/WebCore/inspector/front-end/ResourcesPanel.js @@ -1,6 +1,6 @@ /* * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2008 Anthony Ricaud (rik24d@gmail.com) + * Copyright (C) 2008, 2009 Anthony Ricaud <rik@webkit.org> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,6 +33,10 @@ WebInspector.ResourcesPanel = function() this.element.addStyleClass("resources"); + this.filterBarElement = document.createElement("div"); + this.filterBarElement.id = "resources-filter"; + this.element.appendChild(this.filterBarElement); + this.viewsContainerElement = document.createElement("div"); this.viewsContainerElement.id = "resource-views"; this.element.appendChild(this.viewsContainerElement); @@ -126,7 +130,7 @@ WebInspector.ResourcesPanel = function() this.resourcesTreeElement.expand(); - var panelEnablerHeading = WebInspector.UIString("You need to enable resource tracking to use the this panel."); + var panelEnablerHeading = WebInspector.UIString("You need to enable resource tracking to use this panel."); var panelEnablerDisclaimer = WebInspector.UIString("Enabling resource tracking will reload the page and make page loading slower."); var panelEnablerButton = WebInspector.UIString("Enable resource tracking"); @@ -135,11 +139,11 @@ WebInspector.ResourcesPanel = function() this.element.appendChild(this.panelEnablerView.element); - this.enableToggleButton = document.createElement("button"); + this.enableToggleButton = this.createStatusBarButton(); this.enableToggleButton.className = "enable-toggle-status-bar-item status-bar-item"; this.enableToggleButton.addEventListener("click", this._toggleResourceTracking.bind(this), false); - this.largerResourcesButton = document.createElement("button"); + this.largerResourcesButton = this.createStatusBarButton(); 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."); @@ -149,6 +153,24 @@ WebInspector.ResourcesPanel = function() this.sortingSelectElement.className = "status-bar-item"; this.sortingSelectElement.addEventListener("change", this._changeSortingFunction.bind(this), false); + var createFilterElement = function (category) { + var categoryElement = document.createElement("li"); + categoryElement.category = category; + categoryElement.addStyleClass(category); + var label = WebInspector.UIString("All"); + if (WebInspector.resourceCategories[category]) + label = WebInspector.resourceCategories[category].title; + categoryElement.appendChild(document.createTextNode(label)); + categoryElement.addEventListener("click", this._updateFilter.bind(this), false); + this.filterBarElement.appendChild(categoryElement); + return categoryElement; + }; + + var allElement = createFilterElement.call(this, "all"); + this.filter(allElement.category); + for (var i = 0; i < this.categoryOrder.length; i++) + createFilterElement.call(this, this.categoryOrder[i]); + this.reset(); timeGraphItem.select(); @@ -157,6 +179,31 @@ WebInspector.ResourcesPanel = function() WebInspector.ResourcesPanel.prototype = { toolbarItemClass: "resources", + categoryOrder: ["documents", "stylesheets", "images", "scripts", "xhr", "fonts", "other"], + + filter: function (category) { + if (this._filterCategory && this._filterCategory === category) + return; + + if (this._filterCategory) { + var filterElement = this.filterBarElement.getElementsByClassName(this._filterCategory)[0]; + filterElement.removeStyleClass("selected"); + var oldClass = "filter-" + this._filterCategory; + this.resourcesTreeElement.childrenListElement.removeStyleClass(oldClass); + this.resourcesGraphsElement.removeStyleClass(oldClass); + } + this._filterCategory = category; + var filterElement = this.filterBarElement.getElementsByClassName(this._filterCategory)[0]; + filterElement.addStyleClass("selected"); + var newClass = "filter-" + this._filterCategory; + this.resourcesTreeElement.childrenListElement.addStyleClass(newClass); + this.resourcesGraphsElement.addStyleClass(newClass); + }, + + _updateFilter: function (e) { + this.filter(e.target.category); + }, + get toolbarItemLabel() { return WebInspector.UIString("Resources"); @@ -957,14 +1004,13 @@ WebInspector.ResourcesPanel.prototype = { { 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]; + for (var i = 0; i < this.categoryOrder.length; ++i) { + var category = this.categoryOrder[i]; var size = graphInfo.categoryValues[category]; if (!size) continue; @@ -1453,6 +1499,12 @@ WebInspector.ResourceSidebarTreeElement.prototype = { { WebInspector.SidebarTreeElement.prototype.onattach.call(this); + var link = document.createElement("a"); + link.href = this.resource.url; + link.className = "invisible"; + while (this._listItemNode.firstChild) + link.appendChild(this._listItemNode.firstChild); + this._listItemNode.appendChild(link); this._listItemNode.addStyleClass("resources-category-" + this.resource.category.name); }, @@ -1460,6 +1512,11 @@ WebInspector.ResourceSidebarTreeElement.prototype = { { WebInspector.panels.resources.showResource(this.resource); }, + + ondblclick: function(treeElement, event) + { + InspectorController.inspectedWindow().open(this.resource.url); + }, get mainTitle() { diff --git a/WebCore/inspector/front-end/ScopeChainSidebarPane.js b/WebCore/inspector/front-end/ScopeChainSidebarPane.js index 157cee9..a293fa0 100644 --- a/WebCore/inspector/front-end/ScopeChainSidebarPane.js +++ b/WebCore/inspector/front-end/ScopeChainSidebarPane.js @@ -85,7 +85,7 @@ WebInspector.ScopeChainSidebarPane.prototype = { if (!title || title === subtitle) subtitle = null; - var section = new WebInspector.ObjectPropertiesSection(scopeObject, title, subtitle, emptyPlaceholder, true, extraProperties, WebInspector.ScopeVariableTreeElement); + var section = new WebInspector.ObjectPropertiesSection(new WebInspector.ObjectProxy(scopeObject), title, subtitle, emptyPlaceholder, true, extraProperties, WebInspector.ScopeVariableTreeElement); section.editInSelectedCallFrameWhenPaused = true; section.pane = this; @@ -100,9 +100,9 @@ WebInspector.ScopeChainSidebarPane.prototype = { WebInspector.ScopeChainSidebarPane.prototype.__proto__ = WebInspector.SidebarPane.prototype; -WebInspector.ScopeVariableTreeElement = function(parentObject, propertyName) +WebInspector.ScopeVariableTreeElement = function(property) { - WebInspector.ObjectPropertyTreeElement.call(this, parentObject, propertyName); + WebInspector.ObjectPropertyTreeElement.call(this, property); } WebInspector.ScopeVariableTreeElement.prototype = { @@ -142,9 +142,9 @@ WebInspector.ScopeVariableTreeElement.prototype = { do { if (result) - result = current.propertyName + "." + result; + result = current.property.name + "." + result; else - result = current.propertyName; + result = current.property.name; current = current.parent; } while (current && !current.root); diff --git a/WebCore/inspector/front-end/Script.js b/WebCore/inspector/front-end/Script.js index 46502a6..e6413a9 100644 --- a/WebCore/inspector/front-end/Script.js +++ b/WebCore/inspector/front-end/Script.js @@ -31,6 +31,19 @@ WebInspector.Script = function(sourceID, sourceURL, source, startingLine, errorL this.startingLine = startingLine; this.errorLine = errorLine; this.errorMessage = errorMessage; + + // if no URL, look for "//@ sourceURL=" decorator + // note that this sourceURL comment decorator is behavior that FireBug added + // in it's 1.1 release as noted in the release notes: + // http://fbug.googlecode.com/svn/branches/firebug1.1/docs/ReleaseNotes_1.1.txt + if (!sourceURL) { + // use of [ \t] rather than \s is to prevent \n from matching + var pattern = /^\s*\/\/[ \t]*@[ \t]*sourceURL[ \t]*=[ \t]*(\S+).*$/m; + var match = pattern.exec(source); + + if (match) + this.sourceURL = WebInspector.UIString("(program): %s", match[1]); + } } WebInspector.Script.prototype = { diff --git a/WebCore/inspector/front-end/ScriptsPanel.js b/WebCore/inspector/front-end/ScriptsPanel.js index 7af9292..0058374 100644 --- a/WebCore/inspector/front-end/ScriptsPanel.js +++ b/WebCore/inspector/front-end/ScriptsPanel.js @@ -56,6 +56,7 @@ WebInspector.ScriptsPanel = function() this.filesSelectElement.className = "status-bar-item"; this.filesSelectElement.id = "scripts-files"; this.filesSelectElement.addEventListener("change", this._changeVisibleFile.bind(this), false); + this.filesSelectElement.handleKeyEvent = this.handleKeyEvent.bind(this); this.topStatusBar.appendChild(this.filesSelectElement); this.functionsSelectElement = document.createElement("select"); @@ -132,13 +133,11 @@ WebInspector.ScriptsPanel = function() 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; + this.sidebarPanes.breakpoints.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."); @@ -152,17 +151,50 @@ WebInspector.ScriptsPanel = function() this.element.appendChild(this.sidebarElement); this.element.appendChild(this.sidebarResizeElement); - this.enableToggleButton = document.createElement("button"); + this.enableToggleButton = this.createStatusBarButton(); 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 = this.createStatusBarButton(); 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._shortcuts = {}; + + var isMac = InspectorController.platform().indexOf("mac-") === 0; + var platformSpecificModifier = isMac ? WebInspector.KeyboardShortcut.Modifiers.Meta : WebInspector.KeyboardShortcut.Modifiers.Ctrl; + + // Continue. + var handler = this.pauseButton.click.bind(this.pauseButton); + var shortcut = WebInspector.KeyboardShortcut.makeKey(WebInspector.KeyboardShortcut.KeyCodes.F8); + this._shortcuts[shortcut] = handler; + var shortcut = WebInspector.KeyboardShortcut.makeKey(WebInspector.KeyboardShortcut.KeyCodes.Slash, platformSpecificModifier); + this._shortcuts[shortcut] = handler; + + // Step over. + var handler = this.stepOverButton.click.bind(this.stepOverButton); + var shortcut = WebInspector.KeyboardShortcut.makeKey(WebInspector.KeyboardShortcut.KeyCodes.F10); + this._shortcuts[shortcut] = handler; + var shortcut = WebInspector.KeyboardShortcut.makeKey(WebInspector.KeyboardShortcut.KeyCodes.SingleQuote, platformSpecificModifier); + this._shortcuts[shortcut] = handler; + + // Step into. + var handler = this.stepIntoButton.click.bind(this.stepIntoButton); + var shortcut = WebInspector.KeyboardShortcut.makeKey(WebInspector.KeyboardShortcut.KeyCodes.F11); + this._shortcuts[shortcut] = handler; + var shortcut = WebInspector.KeyboardShortcut.makeKey(WebInspector.KeyboardShortcut.KeyCodes.Semicolon, platformSpecificModifier); + this._shortcuts[shortcut] = handler; + + // Step out. + var handler = this.stepOutButton.click.bind(this.stepOutButton); + var shortcut = WebInspector.KeyboardShortcut.makeKey(WebInspector.KeyboardShortcut.KeyCodes.F11, WebInspector.KeyboardShortcut.Modifiers.Shift); + this._shortcuts[shortcut] = handler; + var shortcut = WebInspector.KeyboardShortcut.makeKey(WebInspector.KeyboardShortcut.KeyCodes.Semicolon, WebInspector.KeyboardShortcut.Modifiers.Shift, platformSpecificModifier); + this._shortcuts[shortcut] = handler; + this.reset(); } @@ -206,7 +238,7 @@ WebInspector.ScriptsPanel.prototype = { view.visible = false; } if (this._attachDebuggerWhenShown) { - InspectorController.enableDebuggerFromFrontend(false); + InspectorController.enableDebugger(false); delete this._attachDebuggerWhenShown; } }, @@ -265,6 +297,11 @@ WebInspector.ScriptsPanel.prototype = { this._addScriptToFilesMenu(script); }, + scriptOrResourceForID: function(id) + { + return this._sourceIDMap[id]; + }, + addBreakpoint: function(breakpoint) { this.sidebarPanes.breakpoints.addBreakpoint(breakpoint); @@ -316,33 +353,53 @@ WebInspector.ScriptsPanel.prototype = { sourceFrame.removeBreakpoint(breakpoint); }, - evaluateInSelectedCallFrame: function(code, updateInterface) + evaluateInSelectedCallFrame: function(code, updateInterface, callback) { 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; + + var self = this; + function updatingCallbackWrapper(result, exception) + { + callback(result, exception); + if (updateInterface) + self.sidebarPanes.scopechain.update(selectedCallFrame); + } + this.doEvalInCallFrame(selectedCallFrame, code, updatingCallbackWrapper); }, - variablesInScopeForSelectedCallFrame: function() + doEvalInCallFrame: function(callFrame, code, callback) { - var selectedCallFrame = this.sidebarPanes.callstack.selectedCallFrame; - if (!this._paused || !selectedCallFrame) - return {}; + var panel = this; + function delayedEvaluation() + { + if (!code) { + // Evaluate into properties in scope of the selected call frame. + callback(panel._variablesInScope(callFrame)); + return; + } + try { + callback(callFrame.evaluate(code)); + } catch (e) { + callback(e, true); + } + } + setTimeout(delayedEvaluation, 0); + }, + _variablesInScope: function(callFrame) + { var result = {}; - var scopeChain = selectedCallFrame.scopeChain; + var scopeChain = callFrame.scopeChain; for (var i = 0; i < scopeChain.length; ++i) { var scopeObject = scopeChain[i]; for (var property in scopeObject) result[property] = true; } - return result; }, @@ -375,7 +432,7 @@ WebInspector.ScriptsPanel.prototype = { attachDebuggerWhenShown: function() { if (this.element.parentElement) { - InspectorController.enableDebuggerFromFrontend(false); + InspectorController.enableDebugger(false); } else { this._attachDebuggerWhenShown = true; } @@ -467,6 +524,19 @@ WebInspector.ScriptsPanel.prototype = { this._showScriptOrResource((view.resource || view.script)); }, + handleKeyEvent: function(event) + { + var shortcut = WebInspector.KeyboardShortcut.makeKeyFromEvent(event); + var handler = this._shortcuts[shortcut]; + if (handler) { + handler(event); + event.preventDefault(); + event.handled = true; + } else { + this.sidebarPanes.callstack.handleKeyEvent(event); + } + }, + scriptViewForScript: function(script) { if (!script) @@ -796,7 +866,7 @@ WebInspector.ScriptsPanel.prototype = { if (InspectorController.debuggerEnabled()) InspectorController.disableDebugger(true); else - InspectorController.enableDebuggerFromFrontend(!!optionalAlways); + InspectorController.enableDebugger(!!optionalAlways); }, _togglePauseOnExceptions: function() diff --git a/WebCore/inspector/front-end/SourceFrame.js b/WebCore/inspector/front-end/SourceFrame.js index 18d9073..930eb16 100644 --- a/WebCore/inspector/front-end/SourceFrame.js +++ b/WebCore/inspector/front-end/SourceFrame.js @@ -27,6 +27,7 @@ WebInspector.SourceFrame = function(element, addBreakpointDelegate) { this.messages = []; this.breakpoints = []; + this._shortcuts = {}; this.addBreakpointDelegate = addBreakpointDelegate; @@ -199,8 +200,16 @@ WebInspector.SourceFrame.prototype = { { WebInspector.addMainEventListeners(this.element.contentDocument); this.element.contentDocument.addEventListener("mousedown", this._documentMouseDown.bind(this), true); + this.element.contentDocument.addEventListener("keydown", this._documentKeyDown.bind(this), true); + this.element.contentDocument.addEventListener("keyup", WebInspector.documentKeyUp.bind(WebInspector), true); this.element.contentDocument.addEventListener("webkitAnimationEnd", this._highlightLineEnds.bind(this), false); + // Register 'eval' shortcut. + var isMac = InspectorController.platform().indexOf("mac-") === 0; + var platformSpecificModifier = isMac ? WebInspector.KeyboardShortcut.Modifiers.Meta : WebInspector.KeyboardShortcut.Modifiers.Ctrl; + var shortcut = WebInspector.KeyboardShortcut.makeKey(69 /* 'E' */, platformSpecificModifier | WebInspector.KeyboardShortcut.Modifiers.Shift); + this._shortcuts[shortcut] = this._evalSelectionInCallFrame.bind(this); + var headElement = this.element.contentDocument.getElementsByTagName("head")[0]; if (!headElement) { headElement = this.element.contentDocument.createElement("head"); @@ -286,6 +295,36 @@ WebInspector.SourceFrame.prototype = { this.addBreakpointDelegate(this.lineNumberForSourceRow(sourceRow)); }, + _documentKeyDown: function(event) + { + var shortcut = WebInspector.KeyboardShortcut.makeKeyFromEvent(event); + var handler = this._shortcuts[shortcut]; + if (handler) { + handler(event); + event.preventDefault(); + } else { + WebInspector.documentKeyDown(event); + } + }, + + _evalSelectionInCallFrame: function(event) + { + if (!WebInspector.panels.scripts || !WebInspector.panels.scripts.paused) + return; + + var selection = this.element.contentWindow.getSelection(); + if (!selection.rangeCount) + return; + + var expression = selection.getRangeAt(0).toString().trimWhitespace(); + WebInspector.panels.scripts.evaluateInSelectedCallFrame(expression, false, function(result, exception) { + WebInspector.showConsole(); + var commandMessage = new WebInspector.ConsoleCommand(expression); + WebInspector.console.addMessage(commandMessage); + WebInspector.console.addMessage(new WebInspector.ConsoleCommandResult(result, exception, commandMessage)); + }); + }, + _breakpointEnableChanged: function(event) { var breakpoint = event.target; @@ -332,6 +371,8 @@ WebInspector.SourceFrame.prototype = { if (!sourceRow) return; + breakpoint.sourceText = sourceRow.getElementsByClassName('webkit-line-content')[0].textContent; + this._drawBreakpointImagesIfNeeded(); sourceRow._breakpointObject = breakpoint; diff --git a/WebCore/inspector/front-end/SourceView.js b/WebCore/inspector/front-end/SourceView.js index 7510c8c..97a5bd5 100644 --- a/WebCore/inspector/front-end/SourceView.js +++ b/WebCore/inspector/front-end/SourceView.js @@ -104,8 +104,11 @@ WebInspector.SourceView.prototype = { { delete this._frameNeedsSetup; this.sourceFrame.removeEventListener("content loaded", this._contentLoaded, this); - - if (this.resource.type === WebInspector.Resource.Type.Script) { + + if (this.resource.type === WebInspector.Resource.Type.Script + || this.resource.mimeType === 'application/json' + || this.resource.mimeType === 'application/javascript' + || /\.js(on)?$/.test(this.resource.lastPathComponent) ) { this.sourceFrame.addEventListener("syntax highlighting complete", this._syntaxHighlightingComplete, this); this.sourceFrame.syntaxHighlightJavascript(); } else diff --git a/WebCore/inspector/front-end/StylesSidebarPane.js b/WebCore/inspector/front-end/StylesSidebarPane.js index c30444b..8a3a67f 100644 --- a/WebCore/inspector/front-end/StylesSidebarPane.js +++ b/WebCore/inspector/front-end/StylesSidebarPane.js @@ -1,5 +1,6 @@ /* * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2009 Joseph Pecoraro * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -62,14 +63,33 @@ WebInspector.StylesSidebarPane.prototype = { if (!node) return; + var self = this; + var callback = function(styles) { + if (!styles) + return; + var nodeWrapper = WebInspector.wrapNodeWithStyles(node, styles); + self._update(refresh, body, nodeWrapper, editedSection, forceUpdate); + }; + InspectorController.getStyles(node, !Preferences.showUserAgentStyles, callback); + }, + + _update: function(refresh, body, node, editedSection, forceUpdate) + { + if (!refresh) { + body.removeChildren(); + this.sections = []; + } + var styleRules = []; if (refresh) { for (var i = 0; i < this.sections.length; ++i) { var section = this.sections[i]; + if (section._blank) + continue; if (section.computedStyle) section.styleRule.style = node.ownerDocument.defaultView.getComputedStyle(node); - var styleRule = { section: section, style: section.styleRule.style, computedStyle: section.computedStyle }; + var styleRule = { section: section, style: section.styleRule.style, computedStyle: section.computedStyle, rule: section.rule }; styleRules.push(styleRule); } } else { @@ -90,8 +110,9 @@ WebInspector.StylesSidebarPane.prototype = { } } - if (node.style && (node.style.length || Object.hasProperties(node.style.__disabledProperties))) { - var inlineStyle = { selectorText: WebInspector.UIString("Inline Style Attribute"), style: node.style }; + // Always Show element's Style Attributes + if (node.nodeType === Node.ELEMENT_NODE) { + var inlineStyle = { selectorText: WebInspector.UIString("Style Attribute"), style: node.style, isAttribute: true }; inlineStyle.subtitle = WebInspector.UIString("element’s “%s” attribute", "style"); styleRules.push(inlineStyle); } @@ -101,7 +122,7 @@ WebInspector.StylesSidebarPane.prototype = { // 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 }); + styleRules.push({ style: rule.style, selectorText: rule.selectorText, parentStyleSheet: rule.parentStyleSheet, rule: rule }); } } } @@ -127,6 +148,8 @@ WebInspector.StylesSidebarPane.prototype = { var styleRule = styleRules[i]; if (styleRule.computedStyle) continue; + if (styleRule.section && styleRule.section.noAffect) + continue; styleRule.usedProperties = {}; @@ -181,7 +204,7 @@ WebInspector.StylesSidebarPane.prototype = { continue; var style = styleRules[i].style; - var uniqueProperties = getUniqueStyleProperties(style); + var uniqueProperties = style.uniqueStyleProperties; for (var j = 0; j < uniqueProperties.length; ++j) { var name = uniqueProperties[j]; if (style.getPropertyPriority(name).length) { @@ -222,6 +245,9 @@ WebInspector.StylesSidebarPane.prototype = { var editable = styleRule.editable; delete styleRule.editable; + var isAttribute = styleRule.isAttribute; + delete styleRule.isAttribute; + // Default editable to true if it was omitted. if (typeof editable === "undefined") editable = true; @@ -235,13 +261,49 @@ WebInspector.StylesSidebarPane.prototype = { section.expanded = Preferences.styleRulesExpandedState[section.identifier]; else if (computedStyle) section.collapse(true); + else if (isAttribute && styleRule.style.length === 0) + section.collapse(true); else section.expand(true); body.appendChild(section.element); this.sections.push(section); } + + this.addBlankSection(); } + }, + + addBlankSection: function() + { + var blankSection = new WebInspector.BlankStylePropertiesSection(); + blankSection.pane = this; + + this.bodyElement.insertBefore(blankSection.element, this.bodyElement.firstChild.nextSibling.nextSibling); // 0 is computed, 1 is element.style + var computed = this.sections.shift(); + var elementStyle = this.sections.shift(); + this.sections.unshift(blankSection); + this.sections.unshift(elementStyle); + this.sections.unshift(computed); + }, + + appropriateSelectorForNode: function() + { + var node = this.node; + if (!node) + return; + + if (node.id) + return "#" + node.id; + + if (node.className) + return "." + node.className.replace(/\s+/, "."); + + var nodeName = node.nodeName.toLowerCase(); + if (nodeName === "input" && node.type) + return nodeName + "[type=\"" + node.type + "\"]"; + + return nodeName; } } @@ -250,14 +312,19 @@ WebInspector.StylesSidebarPane.prototype.__proto__ = WebInspector.SidebarPane.pr WebInspector.StylePropertiesSection = function(styleRule, subtitle, computedStyle, usedProperties, editable) { WebInspector.PropertiesSection.call(this, styleRule.selectorText); + this.titleElement.addEventListener("click", function(e) { e.stopPropagation(); }, false); + this.titleElement.addEventListener("dblclick", this._dblclickSelector.bind(this), false); + this.element.addEventListener("dblclick", this._dblclickEmptySpace.bind(this), false); this.styleRule = styleRule; + this.rule = this.styleRule.rule; 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'; + var isUserAgent = this.styleRule.isUserAgent; + var isUser = this.styleRule.isUser; + if (isUserAgent || isUser) this.editable = false; @@ -299,6 +366,8 @@ WebInspector.StylePropertiesSection = function(styleRule, subtitle, computedStyl subtitle = WebInspector.UIString("user agent stylesheet"); else if (isUser) subtitle = WebInspector.UIString("user stylesheet"); + else if (this.styleRule.parentStyleSheet === WebInspector.panels.elements.stylesheet) + subtitle = WebInspector.UIString("via inspector"); else subtitle = WebInspector.UIString("inline stylesheet"); } @@ -308,7 +377,7 @@ WebInspector.StylePropertiesSection = function(styleRule, subtitle, computedStyl this.identifier = styleRule.selectorText; if (this.subtitle) - this.identifier += ":" + this.subtitleElement.textContent; + this.identifier += ":" + this.subtitleElement.textContent; } WebInspector.StylePropertiesSection.prototype = { @@ -325,6 +394,9 @@ WebInspector.StylePropertiesSection.prototype = { expand: function(dontRememberState) { + if (this._blank) + return; + WebInspector.PropertiesSection.prototype.expand.call(this); if (dontRememberState) return; @@ -347,7 +419,7 @@ WebInspector.StylePropertiesSection.prototype = { isPropertyInherited: function(property) { - if (!this.computedStyle || !this._usedProperties) + if (!this.computedStyle || !this._usedProperties || this.noAffect) return false; // These properties should always show for Computed Style. var alwaysShowComputedProperties = { "display": true, "height": true, "width": true }; @@ -356,7 +428,7 @@ WebInspector.StylePropertiesSection.prototype = { isPropertyOverloaded: function(property, shorthand) { - if (this.computedStyle || !this._usedProperties) + if (this.computedStyle || !this._usedProperties || this.noAffect) return false; var used = (property in this.usedProperties); @@ -365,7 +437,7 @@ WebInspector.StylePropertiesSection.prototype = { // 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); + var longhandProperties = this.styleRule.style.getLonghandProperties(property); for (var j = 0; j < longhandProperties.length; ++j) { var individualProperty = longhandProperties[j]; if (individualProperty in this.usedProperties) @@ -375,6 +447,11 @@ WebInspector.StylePropertiesSection.prototype = { return true; }, + isInspectorStylesheet: function() + { + return (this.styleRule.parentStyleSheet === WebInspector.panels.elements.stylesheet); + }, + update: function(full) { if (full || this.computedStyle) { @@ -387,6 +464,11 @@ WebInspector.StylePropertiesSection.prototype = { child = child.traverseNextTreeElement(false, null, true); } } + + if (this._afterUpdate) { + this._afterUpdate(this); + delete this._afterUpdate; + } }, onpopulate: function() @@ -394,7 +476,7 @@ WebInspector.StylePropertiesSection.prototype = { var style = this.styleRule.style; var foundShorthands = {}; - var uniqueProperties = getUniqueStyleProperties(style); + var uniqueProperties = style.uniqueStyleProperties; var disabledProperties = style.__disabledPropertyValues || {}; for (var name in disabledProperties) @@ -422,16 +504,224 @@ WebInspector.StylePropertiesSection.prototype = { var inherited = this.isPropertyInherited(name); var overloaded = this.isPropertyOverloaded(name, isShorthand); - var item = new WebInspector.StylePropertyTreeElement(style, name, isShorthand, inherited, overloaded, disabled); + var item = new WebInspector.StylePropertyTreeElement(this.styleRule, style, name, isShorthand, inherited, overloaded, disabled); this.propertiesTreeOutline.appendChild(item); } + }, + + findTreeElementWithName: function(name) + { + var treeElement = this.propertiesTreeOutline.children[0]; + while (treeElement) { + if (treeElement.name === name) + return treeElement; + treeElement = treeElement.traverseNextTreeElement(true, null, true); + } + return null; + }, + + addNewBlankProperty: function() + { + var item = new WebInspector.StylePropertyTreeElement(this.styleRule, this.styleRule.style, "", false, false, false, false); + this.propertiesTreeOutline.appendChild(item); + item.listItemElement.textContent = ""; + item._newProperty = true; + return item; + }, + + _dblclickEmptySpace: function(event) + { + this.expand(); + this.addNewBlankProperty().startEditing(); + }, + + _dblclickSelector: function(event) + { + if (!this.editable) + return; + + if (!this.rule && this.propertiesTreeOutline.children.length === 0) { + this.expand(); + this.addNewBlankProperty().startEditing(); + return; + } + + if (!this.rule) + return; + + this.startEditingSelector(); + event.stopPropagation(); + }, + + startEditingSelector: function() + { + var element = this.titleElement; + if (WebInspector.isBeingEdited(element)) + return; + + var context = this.styleRule.selectorText; + WebInspector.startEditing(this.titleElement, this.editingSelectorCommitted.bind(this), this.editingSelectorCancelled.bind(this), context); + window.getSelection().setBaseAndExtent(element, 0, element, 1); + }, + + editingSelectorCommitted: function(element, newContent, oldContent, context, moveDirection) + { + function moveToNextIfNeeded() { + if (!moveDirection || moveDirection !== "forward") + return; + + this.expand(); + if (this.propertiesTreeOutline.children.length === 0) + this.addNewBlankProperty().startEditing(); + else { + var item = this.propertiesTreeOutline.children[0] + item.startEditing(item.valueElement); + } + } + + if (newContent === oldContent) + return moveToNextIfNeeded.call(this); + + var self = this; + var callback = function(result) { + if (!result) { + // Invalid Syntax for a Selector + self.editingSelectorCancelled(element, context); + moveToNextIfNeeded.call(self); + return; + } + + var newRulePayload = result[0]; + var doesAffectSelectedNode = result[1]; + if (!doesAffectSelectedNode) { + self.noAffect = true; + self.element.addStyleClass("no-affect"); + } else { + delete self.noAffect; + self.element.removeStyleClass("no-affect"); + } + + var newRule = WebInspector.CSSStyleDeclaration.parseRule(newRulePayload); + self.rule = newRule; + self.styleRule = { section: self, style: newRule.style, selectorText: newRule.selectorText, parentStyleSheet: newRule.parentStyleSheet, rule: newRule }; + var oldIdentifier = this.identifier; + self.identifier = newRule.selectorText + ":" + self.subtitleElement.textContent; + self.pane.update(null, true); + WebInspector.panels.elements.renameSelector(oldIdentifier, this.identifier, oldContent, newContent); + moveToNextIfNeeded.call(self); + }; + + InspectorController.applyStyleRuleText(this.rule._id, newContent, this.pane.node, callback); + }, + + editingSelectorCancelled: function(element, context) + { + element.textContent = context; + }, + + _doesSelectorAffectSelectedNode: function(selector) + { + var selectedNode = this.pane.node; + var nodes = selectedNode.ownerDocument.querySelectorAll(selector); + for (var i = 0; i < nodes.length; ++i) { + if (nodes[i] === selectedNode) + return true; + } + + return false; } } WebInspector.StylePropertiesSection.prototype.__proto__ = WebInspector.PropertiesSection.prototype; -WebInspector.StylePropertyTreeElement = function(style, name, shorthand, inherited, overloaded, disabled) +WebInspector.BlankStylePropertiesSection = function() { + WebInspector.PropertiesSection.call(this, WebInspector.UIString("Double-Click to Add"), null); + + this._blank = true; + this._dblclickListener = this._dblclick.bind(this); + this.element.addStyleClass("blank-section"); + this.titleElement.addStyleClass("blank-title"); + this.titleElement.addEventListener("click", function(e) { e.stopPropagation(); }, false); + this.titleElement.addEventListener("dblclick", this._dblclickListener, false); +} + +WebInspector.BlankStylePropertiesSection.prototype = { + _dblclick: function(event) + { + this.startEditing(); + }, + + startEditing: function() + { + var element = this.titleElement; + if (WebInspector.isBeingEdited(element)) + return; + + this.titleElement.textContent = this.pane.appropriateSelectorForNode(); + this.titleElement.removeStyleClass("blank-title"); + WebInspector.startEditing(this.titleElement, this.editingCommitted.bind(this), this.editingCancelled.bind(this), ""); + window.getSelection().setBaseAndExtent(element, 0, element, 1); + }, + + editingCancelled: function() + { + this.titleElement.textContent = WebInspector.UIString("Double-Click to Add"); + this.titleElement.addStyleClass("blank-title"); + }, + + editingCommitted: function(element, newContent, oldContent, context) + { + var self = this; + var callback = function(styleRule) { + if (!styleRule) { + // Invalid Syntax for a Selector + self.editingCancelled(); + return; + } + self.makeNormal(WebInspector.CSSStyleDeclaration.parseRule(styleRule)); + + if (!self._doesSelectorAffectSelectedNode(newContent)) { + self.noAffect = true; + self.element.addStyleClass("no-affect"); + } + + self.subtitleElement.textContent = WebInspector.UIString("via inspector"); + self.expand(); + + self.pane.addBlankSection(); + self.addNewBlankProperty().startEditing(); + }; + InspectorController.addStyleSelector(newContent, callback); + }, + + makeNormal: function(styleRule) + { + this.titleElement.removeEventListener("dblclick", this._dblclickListener, false); + this.titleElement.addEventListener("dblclick", this._dblclickSelector.bind(this), false); + this.element.addEventListener("dblclick", this._dblclickEmptySpace.bind(this), false); + this.element.removeStyleClass("blank-section"); + delete this._blank; + delete this._dblclick; + delete this.startEditing; + delete this.editingCancelled; + delete this.editingCommitted; + delete this._dblclickListener; + delete this.makeNormal; + this.styleRule = styleRule; + this.rule = styleRule.rule; + this.computedStyle = false; + this.editable = true; + this.identifier = styleRule.selectorText + ":inspector"; + // leftovers are: this.noAffect if applicable + } +} + +WebInspector.BlankStylePropertiesSection.prototype.__proto__ = WebInspector.StylePropertiesSection.prototype; + +WebInspector.StylePropertyTreeElement = function(styleRule, style, name, shorthand, inherited, overloaded, disabled) +{ + this._styleRule = styleRule; this.style = style; this.name = name; this.shorthand = shorthand; @@ -487,14 +777,14 @@ WebInspector.StylePropertyTreeElement.prototype = { { 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)); + return (this.shorthand ? this.style.getShorthandPriority(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)); + return (this.shorthand ? this.style.getShorthandValue(this.name) : this.style.getPropertyValue(this.name)); }, onattach: function() @@ -558,10 +848,12 @@ WebInspector.StylePropertyTreeElement.prototype = { var nameElement = document.createElement("span"); nameElement.className = "name"; nameElement.textContent = this.name; + this.nameElement = nameElement; var valueElement = document.createElement("span"); valueElement.className = "value"; valueElement.innerHTML = htmlValue; + this.valueElement = valueElement; if (priority) { var priorityElement = document.createElement("span"); @@ -587,7 +879,8 @@ WebInspector.StylePropertyTreeElement.prototype = { 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); + 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|transparent/g); + var swatch; if (colors) { var colorsLength = colors.length; for (var i = 0; i < colorsLength; ++i) { @@ -595,6 +888,72 @@ WebInspector.StylePropertyTreeElement.prototype = { swatchElement.className = "swatch"; swatchElement.style.setProperty("background-color", colors[i]); this.listItemElement.appendChild(swatchElement); + swatch = swatchElement; + } + } + + // Rotate through Color Representations by Clicking on the Swatch + // Simple: rgb -> hsl -> nickname? -> shorthex? -> hex -> ... + // Advanced: rgba -> hsla -> nickname? -> ... + if (colors && colors.length === 1) { + var color = new WebInspector.Color(htmlValue); + swatch.addEventListener("click", changeColorDisplay, false); + swatch.addEventListener("dblclick", function(event) { + event.stopPropagation(); + }, false); + + var mode = color.mode; + var valueElement = this.valueElement; + function changeColorDisplay(event) { + + function changeTo(newMode, content) { + mode = newMode; + valueElement.textContent = content; + } + + switch (mode) { + case "rgb": + changeTo("hsl", color.toHsl()); + break; + + case "shorthex": + changeTo("hex", color.toHex()); + break; + + case "hex": + changeTo("rgb", color.toRgb()); + break; + + case "nickname": + if (color.simple) { + if (color.hasShortHex()) + changeTo("shorthex", color.toShortHex()); + else + changeTo("hex", color.toHex()); + } else + changeTo("rgba", color.toRgba()); + break; + + case "hsl": + if (color.nickname) + changeTo("nickname", color.toNickname()); + else if (color.hasShortHex()) + changeTo("shorthex", color.toShortHex()); + else + changeTo("hex", color.toHex()); + break; + + case "rgba": + changeTo("hsla", color.toHsla()); + break; + + case "hsla": + if (color.nickname) + changeTo("nickname", color.toNickname()); + else + changeTo("rgba", color.toRgba()); + break; + } } } } @@ -616,42 +975,24 @@ WebInspector.StylePropertyTreeElement.prototype = { { 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; + var self = this; + var callback = function(newPayload) { + if (!newPayload) + return; - 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]; - } + self.style = WebInspector.CSSStyleDeclaration.parseStyle(newPayload); + self._styleRule.style = self.style; - // 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; + // Set the disabled property here, since the code above replies on it not changing + // until after the value and priority are retrieved. + self.disabled = disabled; - if (this.treeOutline.section && this.treeOutline.section.pane) - this.treeOutline.section.pane.dispatchEventToListeners("style property toggled"); + if (self.treeOutline.section && self.treeOutline.section.pane) + self.treeOutline.section.pane.dispatchEventToListeners("style property toggled"); - this.updateAll(true); + self.updateAll(true); + }; + InspectorController.toggleStyleEnabled(this.style._id, this.name, disabled, callback); }, updateState: function() @@ -686,7 +1027,7 @@ WebInspector.StylePropertyTreeElement.prototype = { if (this.children.length || !this.shorthand) return; - var longhandProperties = getLonghandProperties(this.style, this.name); + var longhandProperties = this.style.getLonghandProperties(this.name); for (var i = 0; i < longhandProperties.length; ++i) { var name = longhandProperties[i]; @@ -695,7 +1036,7 @@ WebInspector.StylePropertyTreeElement.prototype = { var overloaded = this.treeOutline.section.isPropertyOverloaded(name); } - var item = new WebInspector.StylePropertyTreeElement(this.style, name, false, inherited, overloaded); + var item = new WebInspector.StylePropertyTreeElement(this._styleRule, this.style, name, false, inherited, overloaded); this.appendChild(item); } }, @@ -703,6 +1044,7 @@ WebInspector.StylePropertyTreeElement.prototype = { ondblclick: function(element, event) { this.startEditing(event.target); + event.stopPropagation(); }, startEditing: function(selectElement) @@ -809,11 +1151,11 @@ WebInspector.StylePropertyTreeElement.prototype = { 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); + this.originalCSSText = this.style.styleTextWithShorthands(); } 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; + InspectorController.setStyleText(this.style, this.originalCSSText); } this.applyStyleText(this.listItemElement.textContent); @@ -830,8 +1172,10 @@ WebInspector.StylePropertyTreeElement.prototype = { editingCancelled: function(element, context) { - if (this.originalCSSText) { - this.style.cssText = this.originalCSSText; + if (this._newProperty) + this.treeOutline.removeChild(this); + else if (this.originalCSSText) { + InspectorController.setStyleText(this.style, this.originalCSSText); if (this.treeOutline.section && this.treeOutline.section.pane) this.treeOutline.section.pane.dispatchEventToListeners("style edited"); @@ -843,84 +1187,114 @@ WebInspector.StylePropertyTreeElement.prototype = { this.editingEnded(context); }, - editingCommitted: function(element, userInput, previousContent, context) + editingCommitted: function(element, userInput, previousContent, context, moveDirection) { this.editingEnded(context); - if (userInput === previousContent) - return; // nothing changed, so do nothing else + // Determine where to move to before making changes + var newProperty, moveToPropertyName, moveToSelector; + var moveTo = (moveDirection === "forward" ? this.nextSibling : this.previousSibling); + if (moveTo) + moveToPropertyName = moveTo.name; + else if (moveDirection === "forward") + newProperty = true; + else if (moveDirection === "backward" && this.treeOutline.section.rule) + moveToSelector = true; + + // Make the Changes and trigger the moveToNextCallback after updating + var blankInput = /^\s*$/.test(userInput); + if (userInput !== previousContent || (this._newProperty && blankInput)) { // only if something changed, or adding a new style and it was blank + this.treeOutline.section._afterUpdate = moveToNextCallback.bind(this, this._newProperty, !blankInput); + this.applyStyleText(userInput, true); + } else + moveToNextCallback(this._newProperty, false, this.treeOutline.section, false); - this.applyStyleText(userInput, true); + // The Callback to start editing the next property + function moveToNextCallback(alreadyNew, valueChanged, section) { + if (!moveDirection) + return; + + // User just tabbed through without changes + if (moveTo && moveTo.parent) { + moveTo.startEditing(moveTo.valueElement); + return; + } + + // User has made a change then tabbed, wiping all the original treeElements, + // recalculate the new treeElement for the same property we were going to edit next + if (moveTo && !moveTo.parent) { + var treeElement = section.findTreeElementWithName(moveToPropertyName); + if (treeElement) + treeElement.startEditing(treeElement.valueElement); + return; + } + + // Create a new attribute in this section + if (newProperty) { + if (alreadyNew && !valueChanged) + return; + + var item = section.addNewBlankProperty(); + item.startEditing(); + return; + } + + if (moveToSelector) + section.startEditingSelector(); + } }, applyStyleText: function(styleText, updateInterface) { + var section = this.treeOutline.section; + var elementsPanel = WebInspector.panels.elements; 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(); + // The user deleted everything, so remove the tree element and update. + if (!this._newProperty) + delete section._afterUpdate; + if (section && section.pane) + section.pane.update(); this.parent.removeChild(this); + elementsPanel.removeStyleChange(section.identifier, this.style, this.name); } 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); + var self = this; + var callback = function(result) { + if (!result) { + // The user typed something, but it didn't parse. Just abort and restore + // the original title for this property. If this was a new attribute and + // we couldn't parse, then just remove it. + if (self._newProperty) { + self.parent.removeChild(self); + return; + } + if (updateInterface) + self.updateTitle(); + return; } - // Set the property on the real style declaration. - this.style.setProperty((shorthand || name), value, priority); - } + var newPayload = result[0]; + var changedProperties = result[1]; + elementsPanel.removeStyleChange(section.identifier, self.style, self.name); - if (this.treeOutline.section && this.treeOutline.section.pane) - this.treeOutline.section.pane.dispatchEventToListeners("style edited"); + self.style = WebInspector.CSSStyleDeclaration.parseStyle(newPayload); + for (var i = 0; i < changedProperties.length; ++i) + elementsPanel.addStyleChange(section.identifier, self.style, changedProperties[i]); + self._styleRule.style = self.style; + if (section && section.pane) + section.pane.dispatchEventToListeners("style edited"); - if (updateInterface) - this.updateAll(true); + if (updateInterface) + self.updateAll(true); + + if (!self.rule) + WebInspector.panels.elements.treeOutline.update(); + }; + InspectorController.applyStyleText(this.style._id, styleText.trimWhitespace(), this.name, callback); } } diff --git a/WebCore/inspector/front-end/TextPrompt.js b/WebCore/inspector/front-end/TextPrompt.js index 61e1b52..5ff774f 100644 --- a/WebCore/inspector/front-end/TextPrompt.js +++ b/WebCore/inspector/front-end/TextPrompt.js @@ -66,6 +66,7 @@ WebInspector.TextPrompt.prototype = { this._tabKeyPressed(event); break; case "Right": + case "End": if (!this.acceptAutoComplete()) this.autoCompleteSoon(); break; @@ -140,7 +141,6 @@ WebInspector.TextPrompt.prototype = { complete: function(auto) { this.clearAutoComplete(true); - var selection = window.getSelection(); if (!selection.rangeCount) return; @@ -150,17 +150,24 @@ WebInspector.TextPrompt.prototype = { return; if (auto && !this.isCaretAtEndOfPrompt()) return; - var wordPrefixRange = selectionRange.startContainer.rangeOfWord(selectionRange.startOffset, this.completionStopCharacters, this.element, "backward"); - var completions = this.completions(wordPrefixRange, auto); + this.completions(wordPrefixRange, auto, this._completionsReady.bind(this, selection, auto, wordPrefixRange)); + }, + _completionsReady: function(selection, auto, originalWordPrefixRange, completions) + { if (!completions || !completions.length) return; + var selectionRange = selection.getRangeAt(0); + var fullWordRange = document.createRange(); - fullWordRange.setStart(wordPrefixRange.startContainer, wordPrefixRange.startOffset); + fullWordRange.setStart(originalWordPrefixRange.startContainer, originalWordPrefixRange.startOffset); fullWordRange.setEnd(selectionRange.endContainer, selectionRange.endOffset); + if (originalWordPrefixRange.toString() + selectionRange.toString() != fullWordRange.toString()) + return; + if (completions.length === 1 || selection.isCollapsed || auto) { var completionText = completions[0]; } else { @@ -178,7 +185,7 @@ WebInspector.TextPrompt.prototype = { var completionText = completions[foundIndex + 1]; } - var wordPrefixLength = wordPrefixRange.toString().length; + var wordPrefixLength = originalWordPrefixRange.toString().length; this._userEnteredRange = fullWordRange; this._userEnteredText = fullWordRange.toString(); diff --git a/WebCore/inspector/front-end/WebKit.qrc b/WebCore/inspector/front-end/WebKit.qrc index 76a925b..c39c95b 100644 --- a/WebCore/inspector/front-end/WebKit.qrc +++ b/WebCore/inspector/front-end/WebKit.qrc @@ -4,24 +4,32 @@ <file>BottomUpProfileDataGridTree.js</file> <file>Breakpoint.js</file> <file>BreakpointsSidebarPane.js</file> + <file>Callback.js</file> <file>CallStackSidebarPane.js</file> - <file>Console.js</file> + <file>ChangesView.js</file> + <file>Color.js</file> + <file>ConsoleView.js</file> <file>Database.js</file> <file>DatabaseQueryView.js</file> <file>DatabasesPanel.js</file> <file>DatabaseTableView.js</file> <file>DataGrid.js</file> + <file>DOMAgent.js</file> <file>DOMStorage.js</file> <file>DOMStorageDataGrid.js</file> <file>DOMStorageItemsView.js</file> + <file>Drawer.js</file> <file>ElementsPanel.js</file> <file>ElementsTreeOutline.js</file> <file>FontView.js</file> <file>ImageView.js</file> + <file>InjectedScript.js</file> <file>inspector.js</file> + <file>KeyboardShortcut.js</file> <file>MetricsSidebarPane.js</file> <file>Object.js</file> <file>ObjectPropertiesSection.js</file> + <file>ObjectProxy.js</file> <file>Panel.js</file> <file>PanelEnablerView.js</file> <file>Placard.js</file> @@ -51,9 +59,9 @@ <file>inspector.css</file> <file>Images/back.png</file> <file>Images/checker.png</file> - <file>Images/clearConsoleButtons.png</file> + <file>Images/clearConsoleButtonGlyph.png</file> <file>Images/closeButtons.png</file> - <file>Images/consoleButtons.png</file> + <file>Images/consoleButtonGlyph.png</file> <file>Images/database.png</file> <file>Images/databasesIcon.png</file> <file>Images/databaseTable.png</file> @@ -71,14 +79,15 @@ <file>Images/disclosureTriangleSmallRightDownBlack.png</file> <file>Images/disclosureTriangleSmallRightDownWhite.png</file> <file>Images/disclosureTriangleSmallRightWhite.png</file> - <file>Images/dockButtons.png</file> + <file>Images/dockButtonGlyph.png</file> <file>Images/domStorage.png</file> <file>Images/elementsIcon.png</file> - <file>Images/enableButtons.png</file> + <file>Images/enableOutlineButtonGlyph.png</file> + <file>Images/enableSolidButtonGlyph.png</file> <file>Images/errorIcon.png</file> <file>Images/errorMediumIcon.png</file> - <file>Images/excludeButtons.png</file> - <file>Images/focusButtons.png</file> + <file>Images/excludeButtonGlyph.png</file> + <file>Images/focusButtonGlyph.png</file> <file>Images/forward.png</file> <file>Images/glossyHeader.png</file> <file>Images/glossyHeaderPressed.png</file> @@ -87,21 +96,22 @@ <file>Images/goArrow.png</file> <file>Images/graphLabelCalloutLeft.png</file> <file>Images/graphLabelCalloutRight.png</file> - <file>Images/largerResourcesButtons.png</file> - <file>Images/nodeSearchButtons.png</file> + <file>Images/largerResourcesButtonGlyph.png</file> + <file>Images/nodeSearchButtonGlyph.png</file> <file>Images/paneBottomGrow.png</file> <file>Images/paneBottomGrowActive.png</file> <file>Images/paneGrowHandleLine.png</file> - <file>Images/pauseOnExceptionButtons.png</file> - <file>Images/percentButtons.png</file> + <file>Images/pauseOnExceptionButtonGlyph.png</file> + <file>Images/percentButtonGlyph.png</file> <file>Images/profileGroupIcon.png</file> <file>Images/profileIcon.png</file> <file>Images/profilesIcon.png</file> <file>Images/profileSmallIcon.png</file> <file>Images/profilesSilhouette.png</file> <file>Images/radioDot.png</file> - <file>Images/recordButtons.png</file> - <file>Images/reloadButtons.png</file> + <file>Images/recordButtonGlyph.png</file> + <file>Images/recordToggledButtonGlyph.png</file> + <file>Images/reloadButtonGlyph.png</file> <file>Images/resourceCSSIcon.png</file> <file>Images/resourceDocumentIcon.png</file> <file>Images/resourceDocumentIconSmall.png</file> @@ -109,6 +119,7 @@ <file>Images/resourcePlainIcon.png</file> <file>Images/resourcePlainIconSmall.png</file> <file>Images/resourcesIcon.png</file> + <file>Images/resourcesSilhouette.png</file> <file>Images/resourcesSizeGraphIcon.png</file> <file>Images/resourcesTimeGraphIcon.png</file> <file>Images/scriptsIcon.png</file> @@ -157,6 +168,7 @@ <file>Images/treeRightTriangleWhite.png</file> <file>Images/treeUpTriangleBlack.png</file> <file>Images/treeUpTriangleWhite.png</file> + <file>Images/undockButtonGlyph.png</file> <file>Images/userInputIcon.png</file> <file>Images/userInputPreviousIcon.png</file> <file>Images/userInputResultIcon.png</file> diff --git a/WebCore/inspector/front-end/inspector.css b/WebCore/inspector/front-end/inspector.css index 2653781..51d626a 100644 --- a/WebCore/inspector/front-end/inspector.css +++ b/WebCore/inspector/front-end/inspector.css @@ -1,5 +1,6 @@ /* * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2009 Anthony Ricaud <rik@webkit.org> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -259,7 +260,7 @@ body.attached #main { right: 0; } -body.console-visible #main-status-bar { +body.drawer-visible #main-status-bar { height: 24px; background-image: url(Images/statusbarResizerVertical.png), url(Images/statusbarBackground.png); background-repeat: no-repeat, repeat-x; @@ -267,11 +268,11 @@ body.console-visible #main-status-bar { cursor: row-resize; } -body.console-visible #main-status-bar * { +body.drawer-visible #main-status-bar * { cursor: default; } -body.console-visible #main-panels { +body.drawer-visible #main-panels { bottom: 24px; } @@ -306,14 +307,39 @@ body.console-visible #main-panels { z-index: 200; } +.glyph { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.75); + z-index: 1; +} + +.glyph.shadow { + top: 1px; + background-color: white !important; + z-index: 0; +} + button.status-bar-item { + position: relative; width: 32px; background-image: url(Images/statusbarButtons.png); background-position: 0 0; } button.status-bar-item:active { - background-position: 32px 0; + background-position: 32px 0 !important; +} + +button.status-bar-item .glyph.shadow { + background-color: rgba(255, 255, 255, 0.33) !important; +} + +button.status-bar-item.toggled-on .glyph { + background-color: rgb(66, 129, 235); } button.status-bar-item:disabled { @@ -338,47 +364,31 @@ select.status-bar-item:active { -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; +#dock-status-bar-item .glyph { + -webkit-mask-image: url(Images/undockButtonGlyph.png); } -body.detached #dock-status-bar-item.toggled-on:active { - background-position: 32px 24px; +body.detached #dock-status-bar-item .glyph { + -webkit-mask-image: url(Images/dockButtonGlyph.png); } -#console-status-bar-item { - background-image: url(Images/consoleButtons.png); +#console-status-bar-item .glyph { + -webkit-mask-image: url(Images/consoleButtonGlyph.png); } -#console-status-bar-item:active { - background-position: 32px 0; +#clear-console-status-bar-item .glyph { + -webkit-mask-image: url(Images/clearConsoleButtonGlyph.png); } -#console-status-bar-item.toggled-on { - background-position: 0 24px; +#changes-status-bar-item .glyph { + -webkit-mask-image: url(Images/consoleButtonGlyph.png); /* TODO: Needs Image for Changes Toggle Button */ } -#console-status-bar-item.toggled-on:active { - background-position: 32px 24px; +#clear-changes-status-bar-item .glyph { + -webkit-mask-image: url(Images/clearConsoleButtonGlyph.png); } -#clear-console-status-bar-item { - background-image: url(Images/clearConsoleButtons.png); -} - -#clear-console-status-bar-item:active { - background-position: 32px 0; -} - -#error-warning-count { +#count-items { position: absolute; right: 16px; top: 0; @@ -388,10 +398,22 @@ body.detached #dock-status-bar-item.toggled-on:active { height: 19px; } -#error-warning-count:hover { +#changes-count, #error-warning-count { + display: inline; +} + +#error-warning-count:hover, #changes-count:hover { border-bottom: 1px solid rgb(96, 96, 96); } +#style-changes-count::before { + content: url(Images/styleIcon.png); /* TODO: Needs Image for Style Changes Icon */ + width: 10px; + height: 10px; + vertical-align: -1px; + margin-right: 2px; +} + #error-count::before { content: url(Images/errorIcon.png); width: 10px; @@ -399,8 +421,8 @@ body.detached #dock-status-bar-item.toggled-on:active { vertical-align: -1px; margin-right: 2px; } - -#error-count + #warning-count { + +#changes-count + #error-warning-count, #error-count + #warning-count { margin-left: 6px; } @@ -412,7 +434,7 @@ body.detached #dock-status-bar-item.toggled-on:active { margin-right: 2px; } -#console { +#drawer { display: none; position: absolute; bottom: 0; @@ -425,11 +447,11 @@ body.detached #dock-status-bar-item.toggled-on:active { background-position: bottom; } -body.console-visible #console { +body.drawer-visible #drawer { display: block; } -#console-status-bar { +#drawer-status-bar { position: absolute; bottom: 0; left: 0; @@ -444,8 +466,8 @@ body.console-visible #console { left: 0; right: 0; bottom: 23px; - font-size: 10px; - font-family: Monaco, Lucida Console, monospace; + font-size: initial; + font-family: monospace; padding: 2px 0; overflow-y: overlay; -webkit-user-select: text; @@ -483,7 +505,7 @@ body.console-visible #console { background-image: none; } -.console-message::before, .console-user-command::before, #console-prompt::before, .console-group-title-level::before { +.console-message::before, .console-user-command::before, #console-prompt::before, .console-group-title::before { position: absolute; display: block; content: ""; @@ -529,18 +551,18 @@ body.console-visible #console { margin-left: 16px; } -.console-group-title-level { +.console-group-title { font-weight: bold; } -.console-group-title-level::before { +.console-group-title::before { background-image: url(Images/disclosureTriangleSmallDown.png); top: 0.6em; width: 11px; height: 12px; } -.console-group.collapsed .console-group-title-level::before { +.console-group.collapsed .console-group-title::before { background-image: url(Images/disclosureTriangleSmallRight.png); } @@ -644,6 +666,10 @@ body.console-visible #console { margin-right: -6px; } +.console-group-messages .add-attribute { + display: none; +} + .console-formatted-object, .console-formatted-node { position: relative; display: inline-block; @@ -768,6 +794,11 @@ body.console-visible #console { vertical-align: top; } +.invisible { + color: inherit; + text-decoration: none; +} + .webkit-line-gutter-backdrop { /* Keep this in sync with view-source.css (.webkit-line-gutter-backdrop) */ width: 31px; @@ -1090,6 +1121,11 @@ body.console-visible #console { text-decoration: underline; } +.add-attribute { + margin-left: 1px; + margin-right: 1px; +} + .placard { position: relative; margin-top: 1px; @@ -1168,6 +1204,10 @@ body.inactive .placard.selected { -webkit-background-clip: padding; } +.section.no-affect .header { + background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(167, 167, 167)), to(rgb(123, 123, 123))) +} + .section .header::before { position: absolute; top: 4px; @@ -1177,6 +1217,10 @@ body.inactive .placard.selected { content: url(Images/treeRightTriangleWhite.png); } +.section.blank-section .header::before { + display: none; +} + .section.expanded .header::before { content: url(Images/treeDownTriangleWhite.png); } @@ -1188,6 +1232,10 @@ body.inactive .placard.selected { white-space: normal; } +.section .header .title.blank-title { + font-style: italic; +} + .section .header label { display: none; } @@ -1225,6 +1273,15 @@ body.inactive .placard.selected { padding: 2px 6px 3px; list-style: none; background-color: white; + min-height: 18px; +} + +.section.no-affect .properties li { + opacity: 0.5; +} + +.section.no-affect .properties li.editing { + opacity: 1.0; } .section.expanded .properties { @@ -1810,9 +1867,18 @@ body.inactive .data-grid th.sort-ascending, body.inactive .data-grid th.sort-des text-indent: 10px; } +.data-grid-resizer { + position: absolute; + top: 0; + bottom: 0; + width: 5px; + z-index: 500; + cursor: col-resize; +} + .storage-view.query { - font-size: 10px; - font-family: Monaco, Lucida Console, monospace; + font-size: initial; + font-family: monospace; padding: 2px 0; overflow-y: overlay; overflow-x: hidden; @@ -2006,7 +2072,7 @@ body.inactive .panel-enabler-view button, .panel-enabler-view button:disabled { } .panel-enabler-view.resources img { - content: url(Images/scriptsSilhouette.png); + content: url(Images/resourcesSilhouette.png); } .panel-enabler-view.scripts img { @@ -2017,36 +2083,16 @@ body.inactive .panel-enabler-view button, .panel-enabler-view button:disabled { 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); +button.enable-toggle-status-bar-item .glyph { + -webkit-mask-image: url(Images/enableOutlineButtonGlyph.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; +button.enable-toggle-status-bar-item.toggled-on .glyph { + -webkit-mask-image: url(Images/enableSolidButtonGlyph.png); } -#scripts-pause-on-exceptions-status-bar-item.toggled-on:active { - background-position: 32px 24px; +#scripts-pause-on-exceptions-status-bar-item .glyph { + -webkit-mask-image: url(Images/pauseOnExceptionButtonGlyph.png); } #scripts-status-bar { @@ -2163,25 +2209,54 @@ button.enable-toggle-status-bar-item.toggled-on:active { overflow: auto; } -#resources-larger-resources-status-bar-item { - background-image: url(Images/largerResourcesButtons.png); +#resources-larger-resources-status-bar-item .glyph { + -webkit-mask-image: url(Images/largerResourcesButtonGlyph.png); } -#resources-larger-resources-status-bar-item:active { - background-position: 32px 0; +#resources-filter { + height: 24px; + padding: 2px 10px 0; + background: -webkit-gradient(linear, left top, left bottom, from(rgb(233, 233, 233)), to(rgb(207, 207, 207))); + border-bottom: 1px solid rgb(177, 177, 177); + overflow: hidden; } -#resources-larger-resources-status-bar-item.toggled-on { - background-position: 0 24px; +#resources-filter li { + display: inline-block; + margin: 1px 1px 0 0; + padding: 0 6px 3px; + font-size: 12px; + line-height: 12px; + font-weight: bold; + color: rgb(40, 40, 40); + border: 1px solid transparent; + border-bottom: 0; + background: transparent; + -webkit-border-radius: 8px; + text-shadow: rgba(255, 255, 255, 0.5) 1px 1px 0; +} + +#resources-filter li.selected, #resources-filter li:hover, #resources-filter li:active { + color: white; + text-shadow: rgb(80, 80, 80) 1px 1px 1px; + background: rgba(20, 20, 20, 0.4); + border-color: rgba(20, 20, 20, 0.2); + -webkit-box-shadow: 0 1px 0px rgba(255, 255, 255, 0.5); } -#resources-larger-resources-status-bar-item.toggled-on:active { - background-position: 32px 24px; +#resources-filter li:hover { + background: rgba(20, 20, 20, 0.4); + border-color: transparent; + -webkit-box-shadow: none; +} + +#resources-filter li:active { + background: rgba(20, 20, 20, 0.6); } #resources-container { position: absolute; - top: 0; + top: 24px; left: 0; bottom: 0; right: 0; @@ -2386,6 +2461,22 @@ button.enable-toggle-status-bar-item.toggled-on:active { -webkit-border-image: url(Images/timelinePillGray.png) 6 7 6 7; } +.resources-category-documents, .resources-category-stylesheets, .resources-category-images, +.resources-category-scripts, .resources-category-xhr, .resources-category-fonts, .resources-category-other { + display: none; +} + +.filter-all .resources-category-documents, .filter-documents .resources-category-documents, +.filter-all .resources-category-stylesheets, .filter-stylesheets .resources-category-stylesheets, +.filter-all .resources-category-images, .filter-images .resources-category-images, +.filter-all .resources-category-scripts, .filter-scripts .resources-category-scripts, +.filter-all .resources-category-xhr, .filter-xhr .resources-category-xhr, +.filter-all .resources-category-fonts, .filter-fonts .resources-category-fonts, +.filter-all .resources-category-other, .filter-other .resources-category-other, +.resource-sidebar-tree-item.selected { + display: list-item; +} + .resources-graph-bar.waiting { opacity: 0.35; } @@ -2489,7 +2580,7 @@ button.enable-toggle-status-bar-item.toggled-on:active { #resource-views { position: absolute; - top: 0; + top: 24px; right: 0; left: 200px; bottom: 0; @@ -2509,6 +2600,10 @@ button.enable-toggle-status-bar-item.toggled-on:active { cursor: col-resize; } +.resources .sidebar-resizer-vertical { + top: 24px; +} + .sidebar-tree, .sidebar-tree .children { position: relative; padding: 0; @@ -2995,84 +3090,40 @@ body.inactive .sidebar-tree-item.selected .bubble.search-matches { 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; +button.enable-toggle-status-bar-item .glyph { } -#node-search-status-bar-item { - background-image: url(Images/nodeSearchButtons.png); +#record-profile-status-bar-item .glyph { + -webkit-mask-image: url(Images/recordButtonGlyph.png); } -#node-search-status-bar-item:active { - background-position: 32px 0; +#record-profile-status-bar-item.toggled-on .glyph { + -webkit-mask-image: url(Images/recordToggledButtonGlyph.png); + background-color: rgb(216, 0, 0); } -#node-search-status-bar-item.toggled-on { - background-position: 0 24px; +#node-search-status-bar-item .glyph { + -webkit-mask-image: url(Images/nodeSearchButtonGlyph.png); } -#node-search-status-bar-item.toggled-on:active { - background-position: 32px 24px; +.percent-time-status-bar-item .glyph { + -webkit-mask-image: url(Images/percentButtonGlyph.png); } -.percent-time-status-bar-item { - background-image: url(Images/percentButtons.png) !important; +.focus-profile-node-status-bar-item .glyph { + -webkit-mask-image: url(Images/focusButtonGlyph.png); } -.percent-time-status-bar-item:active { - background-position: 32px 0; +.exclude-profile-node-status-bar-item .glyph { + -webkit-mask-image: url(Images/excludeButtonGlyph.png); } -.percent-time-status-bar-item.toggled-on { - background-position: 0 24px; +.reset-profile-status-bar-item .glyph { + -webkit-mask-image: url(Images/reloadButtonGlyph.png); } -.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; +.delete-storage-status-bar-item .glyph { + -webkit-mask-image: url(Images/excludeButtonGlyph.png); } #storage-view-status-bar-items { @@ -3102,3 +3153,41 @@ body.inactive .sidebar-tree-item.selected .bubble.search-matches { border-left: 1px solid rgb(184, 184, 184); margin-left: -1px; } + +ol.breakpoint-list { + -webkit-padding-start: 2px; + list-style: none; + margin: 0; +} + +.breakpoint-list li { + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + margin: 4px 0; +} + +.breakpoint-list .checkbox-elem { + font-size: 10px; + margin: 0 4px; + vertical-align: top; + position: relative; + z-index: 1; +} + +.breakpoint-list .source-text { + font-family: monospace; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + margin: 2px 0 0px 20px; +} + +.breakpoint-list a { + color: rgb(33%, 33%, 33%); + cursor: pointer; +} + +.breakpoint-list a:hover { + color: rgb(15%, 15%, 15%); +} diff --git a/WebCore/inspector/front-end/inspector.html b/WebCore/inspector/front-end/inspector.html index 184bb45..a3dc407 100644 --- a/WebCore/inspector/front-end/inspector.html +++ b/WebCore/inspector/front-end/inspector.html @@ -34,10 +34,14 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. <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="KeyboardShortcut.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="Callback.js"></script> + <script type="text/javascript" src="Drawer.js"></script> + <script type="text/javascript" src="ChangesView.js"></script> + <script type="text/javascript" src="ConsoleView.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> @@ -51,12 +55,14 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. <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="ObjectProxy.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="Color.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> @@ -77,6 +83,8 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. <script type="text/javascript" src="BottomUpProfileDataGridTree.js"></script> <script type="text/javascript" src="TopDownProfileDataGridTree.js"></script> <script type="text/javascript" src="ProfileView.js"></script> + <script type="text/javascript" src="DOMAgent.js"></script> + <script type="text/javascript" src="InjectedScript.js"></script> </head> <body class="detached"> <div id="toolbar"> @@ -86,12 +94,12 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. <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 id="main-panels" tabindex="0" spellcheck="false"></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"><div class="glyph"></div><div class="glyph shadow"></div></button><button id="console-status-bar-item" class="status-bar-item"><div class="glyph"></div><div class="glyph shadow"></div></button><button id="changes-status-bar-item" class="status-bar-item hidden"></button><div id="count-items"><div id="changes-count" class="hidden"></div><div id="error-warning-count" class="hidden"></div></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 id="drawer"> + <div id="console-view"><div id="console-messages"><div id="console-prompt" spellcheck="false"><br></div></div></div> + <div id="drawer-status-bar" class="status-bar"><div id="other-drawer-status-bar-items"><button id="clear-console-status-bar-item" class="status-bar-item"><div class="glyph"></div><div class="glyph shadow"></div></button></div></div> </div> </body> </html> diff --git a/WebCore/inspector/front-end/inspector.js b/WebCore/inspector/front-end/inspector.js index 9d5bac0..aa21a86 100644 --- a/WebCore/inspector/front-end/inspector.js +++ b/WebCore/inspector/front-end/inspector.js @@ -1,6 +1,7 @@ /* * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. * Copyright (C) 2007 Matt Lilek (pewtermoose@gmail.com). + * Copyright (C) 2009 Joseph Pecoraro * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -37,7 +38,8 @@ var Preferences = { minScriptsSidebarWidth: 200, showInheritedComputedStyleProperties: false, styleRulesExpandedState: {}, - showMissingLocalizedStrings: false + showMissingLocalizedStrings: false, + useDOMAgent: false } var WebInspector = { @@ -117,6 +119,26 @@ var WebInspector = { } } } + + for (var panelName in WebInspector.panels) { + if (WebInspector.panels[panelName] == x) + InspectorController.storeLastActivePanel(panelName); + } + }, + + _createPanels: function() + { + 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(); }, get attached() @@ -231,6 +253,53 @@ var WebInspector = { errorWarningElement.title = null; }, + get styleChanges() + { + return this._styleChanges; + }, + + set styleChanges(x) + { + x = Math.max(x, 0); + + if (this._styleChanges === x) + return; + this._styleChanges = x; + this._updateChangesCount(); + }, + + _updateChangesCount: function() + { + // TODO: Remove immediate return when enabling the Changes Panel + return; + + var changesElement = document.getElementById("changes-count"); + if (!changesElement) + return; + + if (!this.styleChanges) { + changesElement.addStyleClass("hidden"); + return; + } + + changesElement.removeStyleClass("hidden"); + changesElement.removeChildren(); + + if (this.styleChanges) { + var styleChangesElement = document.createElement("span"); + styleChangesElement.id = "style-changes-count"; + styleChangesElement.textContent = this.styleChanges; + changesElement.appendChild(styleChangesElement); + } + + if (this.styleChanges) { + if (this.styleChanges === 1) + changesElement.title = WebInspector.UIString("%d style change", this.styleChanges); + else + changesElement.title = WebInspector.UIString("%d style changes", this.styleChanges); + } + }, + get hoveredDOMNode() { return this._hoveredDOMNode; @@ -278,27 +347,37 @@ WebInspector.loaded = function() var platform = InspectorController.platform(); document.body.addStyleClass("platform-" + platform); - this.console = new WebInspector.Console(); + this.drawer = new WebInspector.Drawer(); + this.console = new WebInspector.ConsoleView(this.drawer); + // TODO: Uncomment when enabling the Changes Panel + // this.changes = new WebInspector.ChangesView(this.drawer); + // TODO: Remove class="hidden" from inspector.html on button#changes-status-bar-item + this.drawer.visibleView = this.console; + + if (Preferences.useDOMAgent) + this.domAgent = new WebInspector.DOMAgent(); + + 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.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(); + this._createPanels(); var toolbarElement = document.getElementById("toolbar"); var previousToolbarItem = toolbarElement.children[0]; + this.panelOrder = []; for (var panelName in this.panels) { var panel = this.panels[panelName]; var panelToolbarItem = panel.toolbarItem; + this.panelOrder.push(panel); panelToolbarItem.addEventListener("click", this._toolbarItemClicked.bind(this)); if (previousToolbarItem) toolbarElement.insertBefore(panelToolbarItem, previousToolbarItem.nextSibling); @@ -307,18 +386,6 @@ WebInspector.loaded = function() 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.")} }; @@ -357,9 +424,15 @@ WebInspector.loaded = function() 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); + errorWarningCount.addEventListener("click", this.showConsole.bind(this), false); this._updateErrorAndWarningCounts(); + this.styleChanges = 0; + // TODO: Uncomment when enabling the Changes Panel + // var changesElement = document.getElementById("changes-count"); + // changesElement.addEventListener("click", this.showChanges.bind(this), false); + // this._updateErrorAndWarningCounts(); + var searchField = document.getElementById("search"); searchField.addEventListener("keydown", this.searchKeyDown.bind(this), false); searchField.addEventListener("keyup", this.searchKeyUp.bind(this), false); @@ -368,7 +441,7 @@ WebInspector.loaded = function() document.getElementById("toolbar").addEventListener("mousedown", this.toolbarDragStart, true); document.getElementById("close-button").addEventListener("click", this.close, true); - InspectorController.loaded(); + InspectorController.loaded(Preferences.useDOMAgent); } var windowLoaded = function() @@ -488,7 +561,7 @@ WebInspector.documentKeyDown = function(event) switch (event.keyIdentifier) { case "U+001B": // Escape key - this.console.visible = !this.console.visible; + this.drawer.visible = !this.drawer.visible; event.preventDefault(); break; @@ -523,6 +596,36 @@ WebInspector.documentKeyDown = function(event) } break; + + case "U+005B": // [ key + if (isMac) + var isRotateLeft = event.metaKey && !event.shiftKey && !event.ctrlKey && !event.altKey; + else + var isRotateLeft = event.ctrlKey && !event.shiftKey && !event.metaKey && !event.altKey; + + if (isRotateLeft) { + var index = this.panelOrder.indexOf(this.currentPanel); + index = (index === 0) ? this.panelOrder.length - 1 : index - 1; + this.panelOrder[index].toolbarItem.click(); + event.preventDefault(); + } + + break; + + case "U+005D": // ] key + if (isMac) + var isRotateRight = event.metaKey && !event.shiftKey && !event.ctrlKey && !event.altKey; + else + var isRotateRight = event.ctrlKey && !event.shiftKey && !event.metaKey && !event.altKey; + + if (isRotateRight) { + var index = this.panelOrder.indexOf(this.currentPanel); + index = (index + 1) % this.panelOrder.length; + this.panelOrder[index].toolbarItem.click(); + event.preventDefault(); + } + + break; } } } @@ -588,6 +691,7 @@ WebInspector.animateStyle = function(animations, duration, callback, complete) var start = null; var current = null; var end = null; + var key = null; for (key in animation) { if (key === "element") element = animation[key]; @@ -749,7 +853,12 @@ WebInspector.elementDragEnd = function(event) WebInspector.showConsole = function() { - this.console.show(); + this.drawer.visibleView = this.console; +} + +WebInspector.showChanges = function() +{ + this.drawer.visibleView = this.changes; } WebInspector.showElementsPanel = function() @@ -979,6 +1088,7 @@ WebInspector.addMessageToConsole = function(payload) { var consoleMessage = new WebInspector.ConsoleMessage( payload.source, + payload.type, payload.level, payload.line, payload.url, @@ -1277,6 +1387,7 @@ WebInspector.startEditing = function(element, committedCallback, cancelledCallba var oldText = element.textContent; var oldHandleKeyEvent = element.handleKeyEvent; + var moveDirection = ""; element.addStyleClass("editing"); @@ -1314,7 +1425,7 @@ WebInspector.startEditing = function(element, committedCallback, cancelledCallba function editingCommitted() { cleanUpAfterEditing.call(this); - committedCallback(this, this.textContent, oldText, context); + committedCallback(this, this.textContent, oldText, context, moveDirection); } element.handleKeyEvent = function(event) { @@ -1330,7 +1441,8 @@ WebInspector.startEditing = function(element, committedCallback, cancelledCallba editingCancelled.call(element); event.preventDefault(); event.handled = true; - } + } else if (event.keyIdentifier === "U+0009") // Tab key + moveDirection = (event.shiftKey ? "backward" : "forward"); } element.addEventListener("blur", blurEventListener, false); diff --git a/WebCore/inspector/front-end/utilities.js b/WebCore/inspector/front-end/utilities.js index 8fb50e2..eec0b87 100644 --- a/WebCore/inspector/front-end/utilities.js +++ b/WebCore/inspector/front-end/utilities.js @@ -38,7 +38,7 @@ Object.type = function(obj, win) win = win || window; if (obj instanceof win.Node) - return "node"; + return (obj.nodeType === undefined ? type : "node"); if (obj instanceof win.String) return "string"; if (obj instanceof win.Array) @@ -94,15 +94,19 @@ Object.describe = function(obj, abbreviated) } } -Object.sortedProperties = function(obj) +Object.properties = function(obj) { var properties = []; for (var prop in obj) properties.push(prop); - properties.sort(); return properties; } +Object.sortedProperties = function(obj, sortFunc) +{ + return Object.properties(obj).sort(sortFunc); +} + Function.prototype.bind = function(thisObject) { var func = this; @@ -381,113 +385,6 @@ String.prototype.trimURL = function(baseURLDomain) 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) |