[Pkg-mozext-commits] [firebug] 18/82: Issue 5873: Closure inspector DOM panel integration

David Prévot taffit at moszumanska.debian.org
Mon Mar 31 22:45:37 UTC 2014


This is an automated email from the git hooks/post-receive script.

taffit pushed a commit to tag fbtest-1.11.2
in repository firebug.

commit 59c0339b223dd703a426a3ee3a11d16c44dceb33
Author: Simon Lindholm <simon.lindholm10 at gmail.com>
Date:   Tue Dec 18 01:29:39 2012 +0100

    Issue 5873: Closure inspector DOM panel integration
---
 extension/content/firebug/chrome/reps.js           |  32 +++++++
 .../content/firebug/console/closureInspector.js    |  83 ++++++++++++++++-
 extension/content/firebug/dom/domPanel.js          | 103 +++++++++++++++++----
 extension/content/firebug/js/watchPanel.js         |   3 +-
 extension/content/firebug/lib/options.js           |   2 +-
 extension/defaults/preferences/firebug.js          |   1 +
 extension/locale/en-US/firebug.properties          |  15 ++-
 extension/skin/classic/console.css                 |   3 +
 8 files changed, 218 insertions(+), 24 deletions(-)

diff --git a/extension/content/firebug/chrome/reps.js b/extension/content/firebug/chrome/reps.js
index dd9df92..ed3bfe0 100644
--- a/extension/content/firebug/chrome/reps.js
+++ b/extension/content/firebug/chrome/reps.js
@@ -3320,6 +3320,37 @@ FirebugReps.ErrorCopy = function(message)
     this.message = message;
 };
 
+//********************************************************************************************** //
+
+FirebugReps.ClosureScope = domplate(Firebug.Rep,
+{
+    tag: OBJECTBOX({_repObject: "$object"}, "$object|getTitle"),
+
+    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+    className: "scope",
+
+    getTitle: function(object)
+    {
+        var scope = Object.getPrototypeOf(object).scope;
+        var type = scope.type, title;
+        if (type === "declarative")
+            title = Locale.$STR("firebug.reps.declarativeScope");
+        else if (type === "object")
+            title = Locale.$STR("firebug.reps.objectScope");
+        else if (type === "with")
+            title = Locale.$STR("firebug.reps.withScope");
+        else
+            title = "<unknown scope \"" + type + "\">"; // shouldn't happen
+        return title;
+    },
+
+    supportsObject: function(object, type)
+    {
+        return ClosureInspector.isScopeWrapper(object);
+    }
+});
+
 // ********************************************************************************************* //
 
 FirebugReps.OptimizedAway = domplate(Firebug.Rep,
@@ -3377,6 +3408,7 @@ Firebug.registerRep(
     FirebugReps.NamedNodeMap,
     FirebugReps.Reference,
     FirebugReps.EventLog,
+    FirebugReps.ClosureScope,
     FirebugReps.OptimizedAway
 );
 
diff --git a/extension/content/firebug/console/closureInspector.js b/extension/content/firebug/console/closureInspector.js
index af04315..94730ee 100644
--- a/extension/content/firebug/console/closureInspector.js
+++ b/extension/content/firebug/console/closureInspector.js
@@ -18,6 +18,7 @@ function(Obj, Firebug, Wrapper) {
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
+const ScopeProxy = function() {};
 const OptimizedAway = Object.create(null);
 Object.freeze(OptimizedAway);
 
@@ -123,6 +124,7 @@ var ClosureInspector =
                 names.push("constructor");
             }
 
+            // XXX keep a Map of scopes, and take the highest container of the first one or the (first) deepest one or something
             for (var i = 0; i < names.length; ++i)
             {
                 // We assume that the first own property, or the first
@@ -344,7 +346,86 @@ var ClosureInspector =
         return Proxy.create(handler);
     },
 
-    extendLanguageSyntax: function (expr, win, context)
+    getScopeWrapper: function(obj, win, context, isScope)
+    {
+        var scope;
+        try
+        {
+            if (isScope)
+                scope = Object.getPrototypeOf(obj).scope.parent;
+            else
+                scope = this.getEnvironmentForObject(win, obj, context);
+            if (!scope || !this.scopeIsInteresting(scope))
+                return;
+        }
+        catch (exc)
+        {
+            if (FBTrace.DBG_COMMANDLINE)
+                FBTrace.sysout("ClosureInspector; getScopeWrapper failed", exc);
+            return;
+        }
+
+        var dbg = this.getInactiveDebuggerForContext(context);
+        var dwin = dbg.addDebuggee(win);
+
+        var scopeDataHolder = Object.create(ScopeProxy.prototype);
+        scopeDataHolder.scope = scope;
+
+        var names, namesSet;
+        var lazyCreateNames = function()
+        {
+            lazyCreateNames = function() {};
+            names = scope.names();
+            namesSet = new Set;
+            for (var i = 0; i < names.length; ++i)
+                namesSet.add(names[i]);
+        };
+
+        var self = this;
+        return Proxy.create({
+            desc: function(name)
+            {
+                if (!this.has(name))
+                    return;
+                return {
+                    get: function() {
+                        var dval = self.getVariableOrOptimizedAway(scope, name);
+                        if (self.isSimple(dval))
+                            return dval;
+                        var uwWin = Wrapper.getContentView(win);
+                        return self.unwrap(uwWin, dwin, dval);
+                    },
+                    set: function(value) {
+                        var dval = dwin.makeDebuggeeValue(value);
+                        scope.setVariable(name, dval);
+                    }
+                };
+            },
+            has: function(name)
+            {
+                lazyCreateNames();
+                return namesSet.has(name);
+            },
+            hasOwn: function(name) { return this.has(name); },
+            getOwnPropertyDescriptor: function(name) { return this.desc(name); },
+            getPropertyDescriptor: function(name) { return this.desc(name); },
+            keys: function()
+            {
+                lazyCreateNames();
+                return names;
+            },
+            enumerate: function() { return this.keys(); },
+            getOwnPropertyNames: function() { return this.keys(); },
+            getPropertyNames: function() { return this.keys(); }
+        }, scopeDataHolder);
+    },
+
+    isScopeWrapper: function(obj)
+    {
+        return obj instanceof ScopeProxy;
+    },
+
+    extendLanguageSyntax: function(expr, win, context)
     {
         var fname = "__fb_scopedVars";
 
diff --git a/extension/content/firebug/dom/domPanel.js b/extension/content/firebug/dom/domPanel.js
index eb0a25d..1829162 100644
--- a/extension/content/firebug/dom/domPanel.js
+++ b/extension/content/firebug/dom/domPanel.js
@@ -16,6 +16,7 @@ define([
     "firebug/lib/string",
     "firebug/lib/array",
     "firebug/lib/persist",
+    "firebug/console/closureInspector",
     "firebug/dom/toggleBranch",
     "firebug/lib/system",
     "firebug/chrome/menu",
@@ -25,8 +26,8 @@ define([
     "firebug/dom/domModule",
     "firebug/console/autoCompleter"
 ],
-function(Obj, Firebug, Domplate, FirebugReps, Locale, Events, Wrapper,
-    SourceLink, StackFrame, Dom, Css, Search, Str, Arr, Persist, ToggleBranch, System, Menu) {
+function(Obj, Firebug, Domplate, FirebugReps, Locale, Events, Wrapper, SourceLink, StackFrame,
+    Dom, Css, Search, Str, Arr, Persist, ClosureInspector, ToggleBranch, System, Menu) {
 
 with (Domplate) {
 
@@ -440,6 +441,8 @@ Firebug.DOMBasePanel.prototype = Obj.extend(Firebug.Panel,
         var proto = [];
         var domHandlers = [];
 
+        var isScope = ClosureInspector.isScopeWrapper(object);
+
         try
         {
             // Special case for "arguments", which is not enumerable by for...in statement.
@@ -543,44 +546,47 @@ Firebug.DOMBasePanel.prototype = Obj.extend(Firebug.Panel,
                 var ordinal = parseInt(name);
                 if (ordinal || ordinal == 0)
                 {
-                    this.addMember(object, "ordinal", ordinals, name, val, level, 0, context);
+                    this.addMember(object, "ordinal", ordinals, name, val, level, 0, context, isScope);
                 }
                 else if (typeof(val) == "function")
                 {
                     if (isClassFunction(val))
                     {
                         if (Dom.isDOMMember(object, name))
-                            this.addMember(object, "domClass", domClasses, name, val, level, domMembers[name], context);
+                            this.addMember(object, "domClass", domClasses, name, val, level, domMembers[name], context, isScope);
                         else
-                            this.addMember(object, "userClass", userClasses, name, val, level, 0, context);
+                            this.addMember(object, "userClass", userClasses, name, val, level, 0, context, isScope);
                     }
                     else if (Dom.isDOMMember(object, name))
                     {
-                        this.addMember(object, "domFunction", domFuncs, name, val, level, domMembers[name], context);
+                        this.addMember(object, "domFunction", domFuncs, name, val, level, domMembers[name], context, isScope);
                     }
                     else if (!Firebug.showUserFuncs && Firebug.showInlineEventHandlers)
                     {
-                        this.addMember(object, "userFunction", domHandlers, name, val, level, 0, context);
+                        this.addMember(object, "userFunction", domHandlers, name, val, level, 0, context, isScope);
                     }
                     else
                     {
-                        this.addMember(object, "userFunction", userFuncs, name, val, level, 0, context);
+                        this.addMember(object, "userFunction", userFuncs, name, val, level, 0, context, isScope);
                     }
                 }
                 else
                 {
                     if (isPrototype(name))
-                        this.addMember(object, "proto", proto, name, val, level, 0, context);
+                        this.addMember(object, "proto", proto, name, val, level, 0, context, isScope);
                     else if (Dom.isDOMMember(object, name))
-                        this.addMember(object, "dom", domProps, name, val, level, domMembers[name], context);
+                        this.addMember(object, "dom", domProps, name, val, level, domMembers[name], context, isScope);
                     else if (Dom.isDOMConstant(object, name))
-                        this.addMember(object, "dom", domConstants, name, val, level, 0, context);
+                        this.addMember(object, "dom", domConstants, name, val, level, 0, context, isScope);
                     else if (Dom.isInlineEventHandler(name))
-                        this.addMember(object, "user", domHandlers, name, val, level, 0, context);
+                        this.addMember(object, "user", domHandlers, name, val, level, 0, context, isScope);
                     else
-                        this.addMember(object, "user", userProps, name, val, level, 0, context);
+                        this.addMember(object, "user", userProps, name, val, level, 0, context, isScope);
                 }
             }
+
+            if (isScope || (typeof object === "function" && Firebug.showClosures && context))
+                this.maybeAddClosureMember(object, "proto", proto, level, context, isScope);
         }
         catch (exc)
         {
@@ -675,7 +681,7 @@ Firebug.DOMBasePanel.prototype = Obj.extend(Firebug.Panel,
         }
     },
 
-    addMemberInternal: function(object, type, props, name, value, level, order, context)
+    addMemberInternal: function(object, type, props, name, value, level, order, context, parentIsScope)
     {
         // Do this first in case a call to instanceof (= QI, for XPCOM things) reveals contents.
         var rep = Firebug.getRep(value);
@@ -690,6 +696,18 @@ Firebug.DOMBasePanel.prototype = Obj.extend(Firebug.Panel,
              (valueType == "object" && value != null) ||
              (valueType == "string" && value.length > Firebug.stringCropLength));
 
+        // Special case for closure inspection.
+        if (!hasChildren && valueType === "function" && Firebug.showClosures && context)
+        {
+            try
+            {
+                var win = context.baseWindow || context.window;
+                ClosureInspector.getEnvironmentForObject(win, value, context);
+                hasChildren = true;
+            }
+            catch (e) {}
+        }
+
         // Special case for "arguments", which is not enumerable by for...in statement
         // and so, Obj.hasProperties always returns false.
         hasChildren = hasChildren || (!!value && isArguments(value));
@@ -726,7 +744,7 @@ Firebug.DOMBasePanel.prototype = Obj.extend(Firebug.Panel,
             prefix: "",
             readOnly: (descriptor && !descriptor.writable && !descriptor.set),
             // XXX should probably move the tests from getContextMenuItems here
-            deletable: !(descriptor && !descriptor.configurable)
+            deletable: (!parentIsScope && !(descriptor && !descriptor.configurable))
         };
 
         // The context doesn't have to be specified (e.g. in case of Watch panel that is based
@@ -734,7 +752,7 @@ Firebug.DOMBasePanel.prototype = Obj.extend(Firebug.Panel,
         if (context)
         {
             // xxxHonza: Support for object change not implemented yet.
-            member.breakable = !hasChildren;
+            member.breakable = !hasChildren && !parentIsScope;
 
             var breakpoints = context.dom.breakpoints;
             var bp = breakpoints.findBreakpoint(object, name);
@@ -777,6 +795,38 @@ Firebug.DOMBasePanel.prototype = Obj.extend(Firebug.Panel,
         return member;
     },
 
+    // Add the magic "(closure)" property.
+    maybeAddClosureMember: function(object, type, props, level, context, isScope)
+    {
+        var win = context.baseWindow || context.window;
+        var wrapper = ClosureInspector.getScopeWrapper(object, win, context, isScope);
+        if (!wrapper)
+            return;
+
+        var name = (isScope ? Locale.$STR("dom.scopeParentName") : Locale.$STR("dom.scopeName"));
+        var rep = Firebug.getRep(wrapper);
+        var tag = rep.shortTag ? rep.shortTag : rep.tag;
+
+        var member = {
+            object: object,
+            name: name,
+            value: wrapper,
+            type: type,
+            rowClass: "memberRow-" + type,
+            open: "",
+            order: 0,
+            level: level,
+            indent: level*16,
+            hasChildren: true,
+            tag: tag,
+            prefix: "",
+            readOnly: true,
+            deletable: false,
+            ignoredPath: true
+        };
+        props.push(member);
+    },
+
     // recursion starts with offset=0, level=0
     expandMembers: function (members, toggles, offset, level, context)
     {
@@ -976,6 +1026,14 @@ Firebug.DOMBasePanel.prototype = Obj.extend(Firebug.Panel,
     {
         var member = row.domObject, name = member.name;
 
+        // Fake "(closure)" properties.
+        if (member.ignoredPath)
+            return ["", ""];
+
+        // Closure variables.
+        if (ClosureInspector.isScopeWrapper(member.object))
+            return [".%", name];
+
         // Ordinals.
         if (name.match(/^[\d]+$/))
             return ["", "["+name+"]"];
@@ -1404,6 +1462,8 @@ Firebug.DOMBasePanel.prototype = Obj.extend(Firebug.Panel,
                     return;
                 }
 
+                // XXX This is wrong with closures, but I haven't noticed anything
+                // break and I don't know how to fix, so let's just leave it...
                 for (var i = 0; i < newPath.length; ++i)
                 {
                     var name = newPath[i];
@@ -1492,6 +1552,7 @@ Firebug.DOMBasePanel.prototype = Obj.extend(Firebug.Panel,
         options.add("showDOMFuncs");
         options.add("showDOMConstants");
         options.add("showInlineEventHandlers");
+        options.add("showClosures");
         options.add("showOwnProperties");
         options.add("showEnumerableProperties");
 
@@ -1503,7 +1564,7 @@ Firebug.DOMBasePanel.prototype = Obj.extend(Firebug.Panel,
     {
         return [
             Menu.optionMenu("ShowUserProps", "showUserProps",
-                "dom.option.tip.Show User Props"),
+                "dom.option.tip.Show_User_Props"),
             Menu.optionMenu("ShowUserFuncs", "showUserFuncs",
                 "dom.option.tip.Show_User_Funcs"),
             Menu.optionMenu("ShowDOMProps", "showDOMProps",
@@ -1514,6 +1575,8 @@ Firebug.DOMBasePanel.prototype = Obj.extend(Firebug.Panel,
                 "dom.option.tip.Show_DOM_Constants"),
             Menu.optionMenu("ShowInlineEventHandlers", "showInlineEventHandlers",
                 "ShowInlineEventHandlersTooltip"),
+            Menu.optionMenu("ShowClosures", "showClosures",
+                "dom.option.tip.Show_Closures"),
             "-",
             Menu.optionMenu("ShowOwnProperties", "showOwnProperties",
                 "ShowOwnPropertiesTooltip"),
@@ -1534,7 +1597,7 @@ Firebug.DOMBasePanel.prototype = Obj.extend(Firebug.Panel,
 
         var items = [];
 
-        if (row && row.domObject)
+        if (row && row.domObject && !row.domObject.ignoredPath)
         {
             var member = row.domObject;
             var rowName = member.name;
@@ -1882,6 +1945,8 @@ function getPropertyDescriptor(object, propName)
 
 function getRowName(row)
 {
+    // XXX This can return not only property names but also just descriptive ones,
+    // like "(closure)", and indeed the collapse remembering logic relies on that.
     var labelNode = row.getElementsByClassName("memberLabelCell").item(0);
     return labelNode.textContent;
 }
@@ -1911,7 +1976,7 @@ function getParentRow(row)
     }
 }
 
-// Return an array of JS parts that build up (and uniquely identify) a row
+// Return an array of parts that uniquely identifies a row (not always all JavaScript)
 function getPath(row)
 {
     var name = getRowName(row);
diff --git a/extension/content/firebug/js/watchPanel.js b/extension/content/firebug/js/watchPanel.js
index 8b74c21..aa29044 100644
--- a/extension/content/firebug/js/watchPanel.js
+++ b/extension/content/firebug/js/watchPanel.js
@@ -365,14 +365,13 @@ Firebug.WatchPanel.prototype = Obj.extend(Firebug.DOMBasePanel.prototype,
             return;
 
         var row = Dom.getAncestorByClass(target, "memberRow");
-        if (!row) 
+        if (!row || row.domObject.ignoredPath)
             return;
 
         var path = this.getPropertyPath(row);
         if (!path || !path.length)
             return;
 
-
         // Ignore top level variables in the Watch panel.
         if (panel.name == "watches" && path.length == 1)
             return;
diff --git a/extension/content/firebug/lib/options.js b/extension/content/firebug/lib/options.js
index f1155f8..47bd02f 100644
--- a/extension/content/firebug/lib/options.js
+++ b/extension/content/firebug/lib/options.js
@@ -62,7 +62,7 @@ const prefNames =  // XXXjjb TODO distribute to modules
     // DOM
     "showUserProps", "showUserFuncs", "showDOMProps", "showDOMFuncs", "showDOMConstants",
     "ObjectShortIteratorMax", "showEnumerableProperties", "showOwnProperties",
-    "showInlineEventHandlers",
+    "showInlineEventHandlers", "showClosures",
 
     // Layout
     "showRulers",
diff --git a/extension/defaults/preferences/firebug.js b/extension/defaults/preferences/firebug.js
index ecf0d48..969de18 100644
--- a/extension/defaults/preferences/firebug.js
+++ b/extension/defaults/preferences/firebug.js
@@ -103,6 +103,7 @@ pref("extensions.firebug.showDOMProps", true);
 pref("extensions.firebug.showDOMFuncs", false);
 pref("extensions.firebug.showDOMConstants", false);
 pref("extensions.firebug.showInlineEventHandlers", false);
+pref("extensions.firebug.showClosures", false);
 pref("extensions.firebug.ObjectShortIteratorMax", 3);
 pref("extensions.firebug.showEnumerableProperties", true);
 pref("extensions.firebug.showOwnProperties", false);
diff --git a/extension/locale/en-US/firebug.properties b/extension/locale/en-US/firebug.properties
index 48c459a..2d53464 100644
--- a/extension/locale/en-US/firebug.properties
+++ b/extension/locale/en-US/firebug.properties
@@ -222,6 +222,17 @@ html.tip.Break_On_Element_Removal=Stop JavaScript execution when the element is
 # or collapse it.
 html.label.Expand/Contract_All=Expand/Contract All
 html.tip.Expand/Contract_All=Expand/collapse all the children recursively
+# LOCALIZATION NOTE (dom.scopeName): Used within the DOM panel to name the fake property that
+# contains the innermost closure scope of a function.
+dom.scopeName=(closure)
+# LOCALIZATION NOTE (dom.scopeParentName): Used within the DOM panel to name the fake property
+# that contains the parent of a closure scope.
+dom.scopeParentName=(parent scope)
+# LOCALIZATION NOTE (firebug.reps.declarativeScope, firebug.reps.objectScope, firebug.reps.withScope):
+# Labels shown to describe different types of closure scopes.
+firebug.reps.declarativeScope=[declarative scope]
+firebug.reps.objectScope=[object scope]
+firebug.reps.withScope=[with scope]
 # LOCALIZATION NOTE (firebug.reps.optimizedAway): Label shown to denote a closure variable that has
 # been optimized away.
 firebug.reps.optimizedAway=(optimized away)
@@ -371,8 +382,10 @@ ShowDOMFuncs=Show DOM Functions
 dom.option.tip.Show_DOM_Funcs=Show functions specified inside the DOM
 ShowDOMConstants=Show DOM Constants
 dom.option.tip.Show_DOM_Constants=Show constants specified inside the DOM
+ShowClosures=Show Closures
+dom.option.tip.Show_Closures=Show the closures associated with various functions (activates the debugger)
 ShowInlineEventHandlers=Show Inline Event Handlers
-ShowInlineEventHandlersTooltip=Show available inline event handlers, that are not associated with a function
+ShowInlineEventHandlersTooltip=Show available inline event handlers that are not associated with functions
 ShowOwnProperties=Show Own Properties Only
 ShowOwnPropertiesTooltip=Don't show prototype chain
 ShowEnumerableProperties=Show Enumerable Properties Only
diff --git a/extension/skin/classic/console.css b/extension/skin/classic/console.css
index 18ba6b5..e713648 100644
--- a/extension/skin/classic/console.css
+++ b/extension/skin/classic/console.css
@@ -166,6 +166,9 @@
     color: #787878;
 }
 
+.objectBox-scope {
+    color: #707070;
+}
 .objectBox-optimizedAway {
     color: #909090;
 }

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-mozext/firebug.git



More information about the Pkg-mozext-commits mailing list