From cbdcc5cc548d337db299c9a2ccaf3d6844d5ae7f Mon Sep 17 00:00:00 2001 From: Victor Porof Date: Sun, 4 Nov 2012 01:01:05 +0200 Subject: [PATCH] Bug 794823 - Refactor and move the debugger's PropertyView in shared, so that it can replace PropertyPanel.jsm soon, r=past, msucan --HG-- rename : browser/devtools/debugger/VariablesView.jsm => browser/devtools/shared/VariablesView.jsm --- .../devtools/debugger/debugger-controller.js | 6 +- browser/devtools/debugger/debugger.css | 6 + browser/devtools/debugger/test/Makefile.in | 1 + .../test/browser_dbg_propertyview-data.js | 485 ++++++++++++++++++ .../{debugger => shared}/VariablesView.jsm | 164 +++++- .../themes/gnomestripe/devtools/debugger.css | 4 +- .../themes/pinstripe/devtools/debugger.css | 4 +- .../themes/winstripe/devtools/debugger.css | 4 +- 8 files changed, 661 insertions(+), 13 deletions(-) create mode 100644 browser/devtools/debugger/test/browser_dbg_propertyview-data.js rename browser/devtools/{debugger => shared}/VariablesView.jsm (89%) diff --git a/browser/devtools/debugger/debugger-controller.js b/browser/devtools/debugger/debugger-controller.js index d9ee09e36c6..0006079bd88 100644 --- a/browser/devtools/debugger/debugger-controller.js +++ b/browser/devtools/debugger/debugger-controller.js @@ -660,9 +660,9 @@ StackFrames.prototype = { // Add the variable's __proto__. if (prototype.type != "null") { - aVar.addProperties({ "__proto__ ": { value: prototype } }); + aVar.addProperty("__proto__", { value: prototype }); // Expansion handlers must be set after the properties are added. - this._addExpander(aVar.get("__proto__ "), prototype); + this._addExpander(aVar.get("__proto__"), prototype); } aVar.fetched = true; @@ -734,6 +734,7 @@ SourceScripts.prototype = { * Connect to the current thread client. */ connect: function SS_connect() { + dumpn("SourceScripts is connecting..."); this.debuggerClient.addListener("newScript", this._onNewScript); this.debuggerClient.addListener("newGlobal", this._onNewGlobal); this._handleTabNavigation(); @@ -746,6 +747,7 @@ SourceScripts.prototype = { if (!this.activeThread) { return; } + dumpn("SourceScripts is disconnecting..."); this.debuggerClient.removeListener("newScript", this._onNewScript); this.debuggerClient.removeListener("newGlobal", this._onNewGlobal); }, diff --git a/browser/devtools/debugger/debugger.css b/browser/devtools/debugger/debugger.css index 3f434ac569f..0ec0c6ca8f6 100644 --- a/browser/devtools/debugger/debugger.css +++ b/browser/devtools/debugger/debugger.css @@ -63,6 +63,12 @@ display: -moz-box; } +.scope[non-header] > .title, +.variable[non-header] > .title, +.property[non-header] > .title { + display: none; +} + /** * Variables and properties searching */ diff --git a/browser/devtools/debugger/test/Makefile.in b/browser/devtools/debugger/test/Makefile.in index 3caa83704c8..556491c823a 100644 --- a/browser/devtools/debugger/test/Makefile.in +++ b/browser/devtools/debugger/test/Makefile.in @@ -33,6 +33,7 @@ MOCHITEST_BROWSER_TESTS = \ browser_dbg_propertyview-09.js \ browser_dbg_propertyview-10.js \ browser_dbg_propertyview-edit.js \ + browser_dbg_propertyview-data.js \ browser_dbg_propertyview-filter-01.js \ browser_dbg_propertyview-filter-02.js \ browser_dbg_propertyview-filter-03.js \ diff --git a/browser/devtools/debugger/test/browser_dbg_propertyview-data.js b/browser/devtools/debugger/test/browser_dbg_propertyview-data.js new file mode 100644 index 00000000000..3d17f407b34 --- /dev/null +++ b/browser/devtools/debugger/test/browser_dbg_propertyview-data.js @@ -0,0 +1,485 @@ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Make sure that the property view correctly populates itself. + */ + +var gPane = null; +var gTab = null; +var gDebugger = null; +var gVariablesView = null; +var gScope = null; +var gVariable = null; + +function test() +{ + debug_tab_pane(TAB1_URL, function(aTab, aDebuggee, aPane) { + gTab = aTab; + gPane = aPane; + gDebugger = gPane.contentWindow; + gVariablesView = gDebugger.DebuggerView.Variables; + + testVariablesView(); + }); +} + +function testVariablesView() +{ + let arr = [ + 42, + true, + "nasu", + undefined, + null, + [0, 1, 2], + { prop1: 9, prop2: 8 } + ]; + + let obj = { + "p0": 42, + "p1": true, + "p2": "nasu", + "p3": undefined, + "p4": null, + "p5": [3, 4, 5], + "p6": { prop1: 7, prop2: 6 }, + get p7() { return arr; }, + set p8(value) { arr[0] = value } + }; + + let test = { + someProp0: 42, + someProp1: true, + someProp2: "nasu", + someProp3: undefined, + someProp4: null, + someProp5: arr, + someProp6: obj, + get someProp7() { return arr; }, + set someProp7(value) { arr[0] = value } + }; + + gVariablesView.rawObject = test; + + testHierarchy(); + testHeader(); + testFirstLevelContents(); + testSecondLevelContents(); + testThirdLevelContents(); + testIntegrity(arr, obj); + + closeDebuggerAndFinish(); +} + +function testHierarchy() { + is(gVariablesView._currHierarchy.size(), 13, + "There should be 1 scope, 1 var, 1 proto, 8 props, 1 getter and 1 setter."); + + gScope = gVariablesView._currHierarchy.get(""); + gVariable = gVariablesView._currHierarchy.get("."); + + is(gVariablesView._store.size(), 1, + "There should be only one scope in the view"); + is(gScope._store.size(), 1, + "There should be only one variable in the scope"); + is(gVariable._store.size(), 9, + "There should be 1 __proto__ and 8 properties in the variable"); +} + +function testHeader() { + is(gScope.header, false, + "The scope title header should be hidden"); + is(gVariable.header, false, + "The variable title header should be hidden"); + + gScope.showHeader(); + gVariable.showHeader(); + + is(gScope.header, true, + "The scope title header should now be visible"); + is(gVariable.header, true, + "The variable title header should now be visible"); + + gScope.hideHeader(); + gVariable.hideHeader(); + + is(gScope.header, false, + "The scope title header should now be hidden"); + is(gVariable.header, false, + "The variable title header should now be hidden"); +} + +function testFirstLevelContents() { + let someProp0 = gVariable.get("someProp0"); + let someProp1 = gVariable.get("someProp1"); + let someProp2 = gVariable.get("someProp2"); + let someProp3 = gVariable.get("someProp3"); + let someProp4 = gVariable.get("someProp4"); + let someProp5 = gVariable.get("someProp5"); + let someProp6 = gVariable.get("someProp6"); + let someProp7 = gVariable.get("someProp7"); + let __proto__ = gVariable.get("__proto__"); + + is(someProp0.visible, true, "The first property visible state is correct."); + is(someProp1.visible, true, "The second property visible state is correct."); + is(someProp2.visible, true, "The third property visible state is correct."); + is(someProp3.visible, true, "The fourth property visible state is correct."); + is(someProp4.visible, true, "The fifth property visible state is correct."); + is(someProp5.visible, true, "The sixth property visible state is correct."); + is(someProp6.visible, true, "The seventh property visible state is correct."); + is(someProp7.visible, true, "The eight property visible state is correct."); + is(__proto__.visible, true, "The __proto__ property visible state is correct."); + + is(someProp0.expanded, false, "The first property expanded state is correct."); + is(someProp1.expanded, false, "The second property expanded state is correct."); + is(someProp2.expanded, false, "The third property expanded state is correct."); + is(someProp3.expanded, false, "The fourth property expanded state is correct."); + is(someProp4.expanded, false, "The fifth property expanded state is correct."); + is(someProp5.expanded, false, "The sixth property expanded state is correct."); + is(someProp6.expanded, false, "The seventh property expanded state is correct."); + is(someProp7.expanded, true, "The eight property expanded state is correct."); + is(__proto__.expanded, false, "The __proto__ property expanded state is correct."); + + is(someProp0.header, true, "The first property header state is correct."); + is(someProp1.header, true, "The second property header state is correct."); + is(someProp2.header, true, "The third property header state is correct."); + is(someProp3.header, true, "The fourth property header state is correct."); + is(someProp4.header, true, "The fifth property header state is correct."); + is(someProp5.header, true, "The sixth property header state is correct."); + is(someProp6.header, true, "The seventh property header state is correct."); + is(someProp7.header, true, "The eight property header state is correct."); + is(__proto__.header, true, "The __proto__ property header state is correct."); + + is(someProp0.twisty, false, "The first property twisty state is correct."); + is(someProp1.twisty, false, "The second property twisty state is correct."); + is(someProp2.twisty, false, "The third property twisty state is correct."); + is(someProp3.twisty, false, "The fourth property twisty state is correct."); + is(someProp4.twisty, false, "The fifth property twisty state is correct."); + is(someProp5.twisty, true, "The sixth property twisty state is correct."); + is(someProp6.twisty, true, "The seventh property twisty state is correct."); + is(someProp7.twisty, true, "The eight property twisty state is correct."); + is(__proto__.twisty, true, "The __proto__ property twisty state is correct."); + + is(someProp0.name, "someProp0", "The first property name is correct."); + is(someProp1.name, "someProp1", "The second property name is correct."); + is(someProp2.name, "someProp2", "The third property name is correct."); + is(someProp3.name, "someProp3", "The fourth property name is correct."); + is(someProp4.name, "someProp4", "The fifth property name is correct."); + is(someProp5.name, "someProp5", "The sixth property name is correct."); + is(someProp6.name, "someProp6", "The seventh property name is correct."); + is(someProp7.name, "someProp7", "The eight property name is correct."); + is(__proto__.name, "__proto__", "The __proto__ property name is correct."); + + is(someProp0.value, 42, "The first property value is correct."); + is(someProp1.value, true, "The second property value is correct."); + is(someProp2.value, "nasu", "The third property value is correct."); + is(someProp3.value.type, "undefined", "The fourth property value is correct."); + is(someProp4.value.type, "null", "The fifth property value is correct."); + is(someProp5.value.type, "object", "The sixth property value type is correct."); + is(someProp5.value.class, "Array", "The sixth property value class is correct."); + is(someProp6.value.type, "object", "The seventh property value type is correct."); + is(someProp6.value.class, "Object", "The seventh property value class is correct."); + is(someProp7.value, null, "The eight property value is correct."); + isnot(someProp7.getter, null, "The eight property getter is correct."); + isnot(someProp7.setter, null, "The eight property setter is correct."); + is(someProp7.getter.type, "object", "The eight property getter type is correct."); + is(someProp7.getter.class, "Function", "The eight property getter class is correct."); + is(someProp7.setter.type, "object", "The eight property setter type is correct."); + is(someProp7.setter.class, "Function", "The eight property setter class is correct."); + is(__proto__.value.type, "object", "The __proto__ property value type is correct."); + is(__proto__.value.class, "Object", "The __proto__ property value class is correct."); + + + someProp0.expand(); + someProp1.expand(); + someProp2.expand(); + someProp3.expand(); + someProp4.expand(); + someProp7.expand(); + + ok(!someProp0.get("__proto__"), "Number primitives should not have a prototype"); + ok(!someProp1.get("__proto__"), "Boolean primitives should not have a prototype"); + ok(!someProp2.get("__proto__"), "String literals should not have a prototype"); + ok(!someProp3.get("__proto__"), "Undefined values should not have a prototype"); + ok(!someProp4.get("__proto__"), "Null values should not have a prototype"); + ok(!someProp7.get("__proto__"), "Getter properties should not have a prototype"); +} + +function testSecondLevelContents() { + let someProp5 = gVariable.get("someProp5"); + + is(someProp5._store.size(), 0, "No properties should be in someProp5 before expanding"); + someProp5.expand(); + is(someProp5._store.size(), 9, "Some properties should be in someProp5 before expanding"); + + let arrayItem0 = someProp5.get("0"); + let arrayItem1 = someProp5.get("1"); + let arrayItem2 = someProp5.get("2"); + let arrayItem3 = someProp5.get("3"); + let arrayItem4 = someProp5.get("4"); + let arrayItem5 = someProp5.get("5"); + let arrayItem6 = someProp5.get("6"); + let __proto__ = someProp5.get("__proto__"); + + is(arrayItem0.visible, true, "The first array item visible state is correct."); + is(arrayItem1.visible, true, "The second array item visible state is correct."); + is(arrayItem2.visible, true, "The third array item visible state is correct."); + is(arrayItem3.visible, true, "The fourth array item visible state is correct."); + is(arrayItem4.visible, true, "The fifth array item visible state is correct."); + is(arrayItem5.visible, true, "The sixth array item visible state is correct."); + is(arrayItem6.visible, true, "The seventh array item visible state is correct."); + is(__proto__.visible, true, "The __proto__ property visible state is correct."); + + is(arrayItem0.expanded, false, "The first array item expanded state is correct."); + is(arrayItem1.expanded, false, "The second array item expanded state is correct."); + is(arrayItem2.expanded, false, "The third array item expanded state is correct."); + is(arrayItem3.expanded, false, "The fourth array item expanded state is correct."); + is(arrayItem4.expanded, false, "The fifth array item expanded state is correct."); + is(arrayItem5.expanded, false, "The sixth array item expanded state is correct."); + is(arrayItem6.expanded, false, "The seventh array item expanded state is correct."); + is(__proto__.expanded, false, "The __proto__ property expanded state is correct."); + + is(arrayItem0.header, true, "The first array item header state is correct."); + is(arrayItem1.header, true, "The second array item header state is correct."); + is(arrayItem2.header, true, "The third array item header state is correct."); + is(arrayItem3.header, true, "The fourth array item header state is correct."); + is(arrayItem4.header, true, "The fifth array item header state is correct."); + is(arrayItem5.header, true, "The sixth array item header state is correct."); + is(arrayItem6.header, true, "The seventh array item header state is correct."); + is(__proto__.header, true, "The __proto__ property header state is correct."); + + is(arrayItem0.twisty, false, "The first array item twisty state is correct."); + is(arrayItem1.twisty, false, "The second array item twisty state is correct."); + is(arrayItem2.twisty, false, "The third array item twisty state is correct."); + is(arrayItem3.twisty, false, "The fourth array item twisty state is correct."); + is(arrayItem4.twisty, false, "The fifth array item twisty state is correct."); + is(arrayItem5.twisty, true, "The sixth array item twisty state is correct."); + is(arrayItem6.twisty, true, "The seventh array item twisty state is correct."); + is(__proto__.twisty, true, "The __proto__ property twisty state is correct."); + + is(arrayItem0.name, "0", "The first array item name is correct."); + is(arrayItem1.name, "1", "The second array item name is correct."); + is(arrayItem2.name, "2", "The third array item name is correct."); + is(arrayItem3.name, "3", "The fourth array item name is correct."); + is(arrayItem4.name, "4", "The fifth array item name is correct."); + is(arrayItem5.name, "5", "The sixth array item name is correct."); + is(arrayItem6.name, "6", "The seventh array item name is correct."); + is(__proto__.name, "__proto__", "The __proto__ property name is correct."); + + is(arrayItem0.value, 42, "The first array item value is correct."); + is(arrayItem1.value, true, "The second array item value is correct."); + is(arrayItem2.value, "nasu", "The third array item value is correct."); + is(arrayItem3.value.type, "undefined", "The fourth array item value is correct."); + is(arrayItem4.value.type, "null", "The fifth array item value is correct."); + is(arrayItem5.value.type, "object", "The sixth array item value type is correct."); + is(arrayItem5.value.class, "Array", "The sixth array item value class is correct."); + is(arrayItem6.value.type, "object", "The seventh array item value type is correct."); + is(arrayItem6.value.class, "Object", "The seventh array item value class is correct."); + is(__proto__.value.type, "object", "The __proto__ property value type is correct."); + is(__proto__.value.class, "Array", "The __proto__ property value class is correct."); + + + let someProp6 = gVariable.get("someProp6"); + + is(someProp6._store.size(), 0, "No properties should be in someProp6 before expanding"); + someProp6.expand(); + is(someProp6._store.size(), 10, "Some properties should be in someProp6 before expanding"); + + let objectItem0 = someProp6.get("p0"); + let objectItem1 = someProp6.get("p1"); + let objectItem2 = someProp6.get("p2"); + let objectItem3 = someProp6.get("p3"); + let objectItem4 = someProp6.get("p4"); + let objectItem5 = someProp6.get("p5"); + let objectItem6 = someProp6.get("p6"); + let objectItem7 = someProp6.get("p7"); + let objectItem8 = someProp6.get("p8"); + let __proto__ = someProp6.get("__proto__"); + + is(objectItem0.visible, true, "The first object item visible state is correct."); + is(objectItem1.visible, true, "The second object item visible state is correct."); + is(objectItem2.visible, true, "The third object item visible state is correct."); + is(objectItem3.visible, true, "The fourth object item visible state is correct."); + is(objectItem4.visible, true, "The fifth object item visible state is correct."); + is(objectItem5.visible, true, "The sixth object item visible state is correct."); + is(objectItem6.visible, true, "The seventh object item visible state is correct."); + is(objectItem7.visible, true, "The eight object item visible state is correct."); + is(objectItem8.visible, true, "The ninth object item visible state is correct."); + is(__proto__.visible, true, "The __proto__ property visible state is correct."); + + is(objectItem0.expanded, false, "The first object item expanded state is correct."); + is(objectItem1.expanded, false, "The second object item expanded state is correct."); + is(objectItem2.expanded, false, "The third object item expanded state is correct."); + is(objectItem3.expanded, false, "The fourth object item expanded state is correct."); + is(objectItem4.expanded, false, "The fifth object item expanded state is correct."); + is(objectItem5.expanded, false, "The sixth object item expanded state is correct."); + is(objectItem6.expanded, false, "The seventh object item expanded state is correct."); + is(objectItem7.expanded, true, "The eight object item expanded state is correct."); + is(objectItem8.expanded, true, "The ninth object item expanded state is correct."); + is(__proto__.expanded, false, "The __proto__ property expanded state is correct."); + + is(objectItem0.header, true, "The first object item header state is correct."); + is(objectItem1.header, true, "The second object item header state is correct."); + is(objectItem2.header, true, "The third object item header state is correct."); + is(objectItem3.header, true, "The fourth object item header state is correct."); + is(objectItem4.header, true, "The fifth object item header state is correct."); + is(objectItem5.header, true, "The sixth object item header state is correct."); + is(objectItem6.header, true, "The seventh object item header state is correct."); + is(objectItem7.header, true, "The eight object item header state is correct."); + is(objectItem8.header, true, "The ninth object item header state is correct."); + is(__proto__.header, true, "The __proto__ property header state is correct."); + + is(objectItem0.twisty, false, "The first object item twisty state is correct."); + is(objectItem1.twisty, false, "The second object item twisty state is correct."); + is(objectItem2.twisty, false, "The third object item twisty state is correct."); + is(objectItem3.twisty, false, "The fourth object item twisty state is correct."); + is(objectItem4.twisty, false, "The fifth object item twisty state is correct."); + is(objectItem5.twisty, true, "The sixth object item twisty state is correct."); + is(objectItem6.twisty, true, "The seventh object item twisty state is correct."); + is(objectItem7.twisty, true, "The eight object item twisty state is correct."); + is(objectItem8.twisty, true, "The ninth object item twisty state is correct."); + is(__proto__.twisty, true, "The __proto__ property twisty state is correct."); + + is(objectItem0.name, "p0", "The first object item name is correct."); + is(objectItem1.name, "p1", "The second object item name is correct."); + is(objectItem2.name, "p2", "The third object item name is correct."); + is(objectItem3.name, "p3", "The fourth object item name is correct."); + is(objectItem4.name, "p4", "The fifth object item name is correct."); + is(objectItem5.name, "p5", "The sixth object item name is correct."); + is(objectItem6.name, "p6", "The seventh object item name is correct."); + is(objectItem7.name, "p7", "The eight seventh object item name is correct."); + is(objectItem8.name, "p8", "The ninth seventh object item name is correct."); + is(__proto__.name, "__proto__", "The __proto__ property name is correct."); + + is(objectItem0.value, 42, "The first object item value is correct."); + is(objectItem1.value, true, "The second object item value is correct."); + is(objectItem2.value, "nasu", "The third object item value is correct."); + is(objectItem3.value.type, "undefined", "The fourth object item value is correct."); + is(objectItem4.value.type, "null", "The fifth object item value is correct."); + is(objectItem5.value.type, "object", "The sixth object item value type is correct."); + is(objectItem5.value.class, "Array", "The sixth object item value class is correct."); + is(objectItem6.value.type, "object", "The seventh object item value type is correct."); + is(objectItem6.value.class, "Object", "The seventh object item value class is correct."); + is(objectItem7.value, null, "The eight object item value is correct."); + isnot(objectItem7.getter, null, "The eight object item getter is correct."); + isnot(objectItem7.setter, null, "The eight object item setter is correct."); + is(objectItem7.setter.type, "undefined", "The eight object item setter type is correct."); + is(objectItem7.getter.type, "object", "The eight object item getter type is correct."); + is(objectItem7.getter.class, "Function", "The eight object item getter class is correct."); + is(objectItem8.value, null, "The ninth object item value is correct."); + isnot(objectItem8.getter, null, "The ninth object item getter is correct."); + isnot(objectItem8.setter, null, "The ninth object item setter is correct."); + is(objectItem8.getter.type, "undefined", "The eight object item getter type is correct."); + is(objectItem8.setter.type, "object", "The ninth object item setter type is correct."); + is(objectItem8.setter.class, "Function", "The ninth object item setter class is correct."); + is(__proto__.value.type, "object", "The __proto__ property value type is correct."); + is(__proto__.value.class, "Object", "The __proto__ property value class is correct."); +} + +function testThirdLevelContents() { + (function() { + let someProp5 = gVariable.get("someProp5"); + let arrayItem5 = someProp5.get("5"); + let arrayItem6 = someProp5.get("6"); + + is(arrayItem5._store.size(), 0, "No properties should be in arrayItem5 before expanding"); + arrayItem5.expand(); + is(arrayItem5._store.size(), 5, "Some properties should be in arrayItem5 before expanding"); + + is(arrayItem6._store.size(), 0, "No properties should be in arrayItem6 before expanding"); + arrayItem6.expand(); + is(arrayItem6._store.size(), 3, "Some properties should be in arrayItem6 before expanding"); + + let arraySubItem0 = arrayItem5.get("0"); + let arraySubItem1 = arrayItem5.get("1"); + let arraySubItem2 = arrayItem5.get("2"); + let objectSubItem0 = arrayItem6.get("prop1"); + let objectSubItem1 = arrayItem6.get("prop2"); + + is(arraySubItem0.value, 0, "The first array sub-item value is correct."); + is(arraySubItem1.value, 1, "The second array sub-item value is correct."); + is(arraySubItem2.value, 2, "The third array sub-item value is correct."); + + is(objectSubItem0.value, 9, "The first object sub-item value is correct."); + is(objectSubItem1.value, 8, "The second object sub-item value is correct."); + + let array__proto__ = arrayItem5.get("__proto__"); + let object__proto__ = arrayItem6.get("__proto__"); + + ok(array__proto__, "The array should have a __proto__ property"); + ok(object__proto__, "The object should have a __proto__ property"); + })(); + + (function() { + let someProp6 = gVariable.get("someProp6"); + let objectItem5 = someProp6.get("p5"); + let objectItem6 = someProp6.get("p6"); + + is(objectItem5._store.size(), 0, "No properties should be in objectItem5 before expanding"); + objectItem5.expand(); + is(objectItem5._store.size(), 5, "Some properties should be in objectItem5 before expanding"); + + is(objectItem6._store.size(), 0, "No properties should be in objectItem6 before expanding"); + objectItem6.expand(); + is(objectItem6._store.size(), 3, "Some properties should be in objectItem6 before expanding"); + + let arraySubItem0 = objectItem5.get("0"); + let arraySubItem1 = objectItem5.get("1"); + let arraySubItem2 = objectItem5.get("2"); + let objectSubItem0 = objectItem6.get("prop1"); + let objectSubItem1 = objectItem6.get("prop2"); + + is(arraySubItem0.value, 3, "The first array sub-item value is correct."); + is(arraySubItem1.value, 4, "The second array sub-item value is correct."); + is(arraySubItem2.value, 5, "The third array sub-item value is correct."); + + is(objectSubItem0.value, 7, "The first object sub-item value is correct."); + is(objectSubItem1.value, 6, "The second object sub-item value is correct."); + + let array__proto__ = objectItem5.get("__proto__"); + let object__proto__ = objectItem6.get("__proto__"); + + ok(array__proto__, "The array should have a __proto__ property"); + ok(object__proto__, "The object should have a __proto__ property"); + })(); +} + +function testIntegrity(arr, obj) { + is(arr[0], 42, "The first array item should not have changed"); + is(arr[1], true, "The second array item should not have changed"); + is(arr[2], "nasu", "The third array item should not have changed"); + is(arr[3], undefined, "The fourth array item should not have changed"); + is(arr[4], null, "The fifth array item should not have changed"); + ok(arr[5] instanceof Array, "The sixth array item should be an Array"); + is(arr[5][0], 0, "The sixth array item should not have changed"); + is(arr[5][1], 1, "The sixth array item should not have changed"); + is(arr[5][2], 2, "The sixth array item should not have changed"); + ok(arr[6] instanceof Object, "The seventh array item should be an Object"); + is(arr[6].prop1, 9, "The seventh array item should not have changed"); + is(arr[6].prop2, 8, "The seventh array item should not have changed"); + + is(obj.p0, 42, "The first object property should not have changed"); + is(obj.p1, true, "The first object property should not have changed"); + is(obj.p2, "nasu", "The first object property should not have changed"); + is(obj.p3, undefined, "The first object property should not have changed"); + is(obj.p4, null, "The first object property should not have changed"); + ok(obj.p5 instanceof Array, "The sixth object property should be an Array"); + is(obj.p5[0], 3, "The sixth object property should not have changed"); + is(obj.p5[1], 4, "The sixth object property should not have changed"); + is(obj.p5[2], 5, "The sixth object property should not have changed"); + ok(obj.p6 instanceof Object, "The seventh object property should be an Object"); + is(obj.p6.prop1, 7, "The seventh object property should not have changed"); + is(obj.p6.prop2, 6, "The seventh object property should not have changed"); +} + +registerCleanupFunction(function() { + removeTab(gTab); + gPane = null; + gTab = null; + gDebugger = null; + gVariablesView = null; + gScope = null; + gVariable = null; +}); diff --git a/browser/devtools/debugger/VariablesView.jsm b/browser/devtools/shared/VariablesView.jsm similarity index 89% rename from browser/devtools/debugger/VariablesView.jsm rename to browser/devtools/shared/VariablesView.jsm index 468d132d7bb..91b286c4ec8 100644 --- a/browser/devtools/debugger/VariablesView.jsm +++ b/browser/devtools/shared/VariablesView.jsm @@ -38,6 +38,18 @@ function VariablesView(aParentNode) { } VariablesView.prototype = { + /** + * Helper setter for populating this container with a raw object. + * + * @param object aData + * The raw object to display. You can only provide this object + * if you want the variables view to work in sync mode. + */ + set rawObject(aObject) { + this.empty(); + this.addScope().addVar().populate(aObject); + }, + /** * Adds a scope to contain any inspected variables. * @@ -46,12 +58,13 @@ VariablesView.prototype = { * @return Scope * The newly created Scope instance. */ - addScope: function VV_addScope(aName) { + addScope: function VV_addScope(aName = "") { this._removeEmptyNotice(); let scope = new Scope(this, aName); this._store.set(scope.id, scope); this._currHierarchy.set(aName, scope); + scope.header = !!aName; return scope; }, @@ -382,7 +395,7 @@ Scope.prototype = { * @return Variable * The newly created Variable instance, null if it already exists. */ - addVar: function S_addVar(aName, aDescriptor = {}) { + addVar: function S_addVar(aName = "", aDescriptor = {}) { if (this._store.has(aName)) { return null; } @@ -390,6 +403,7 @@ Scope.prototype = { let variable = new Variable(this, aName, aDescriptor); this._store.set(aName, variable); this._variablesView._currHierarchy.set(variable._absoluteName, variable); + variable.header = !!aName; return variable; }, @@ -486,6 +500,24 @@ Scope.prototype = { } }, + /** + * Shows the scope's title header. + */ + showHeader: function S_showHeader() { + this._target.removeAttribute("non-header"); + this._isHeaderVisible = true; + }, + + /** + * Hides the scope's title header. + * This action will automatically expand the scope. + */ + hideHeader: function S_hideHeader() { + this.expand(); + this._target.setAttribute("non-header", ""); + this._isHeaderVisible = false; + }, + /** * Shows the scope's expand/collapse arrow. */ @@ -514,6 +546,12 @@ Scope.prototype = { */ get expanded() this._isExpanded, + /** + * Gets the header visibility state. + * @return boolean + */ + get header() this._isHeaderVisible, + /** * Gets the twisty visibility state. * @return boolean @@ -532,6 +570,12 @@ Scope.prototype = { */ set expanded(aFlag) aFlag ? this.expand() : this.collapse(), + /** + * Sets the header visibility state. + * @param boolean aFlag + */ + set header(aFlag) aFlag ? this.showHeader() : this.hideHeader(), + /** * Sets the twisty visibility state. * @param boolean aFlag @@ -760,11 +804,13 @@ Scope.prototype = { ownerView: null, eval: null, + fetched: false, _committed: false, _locked: false, _isShown: true, _isExpanded: false, _wasToggled: false, + _isHeaderVisible: true, _isArrowVisible: true, _isMatch: true, _store: null, @@ -823,7 +869,7 @@ create({ constructor: Variable, proto: Scope.prototype }, { * @return Property * The newly created Property instance, null if it already exists. */ - addProperty: function V_addProperty(aName, aDescriptor = {}) { + addProperty: function V_addProperty(aName = "", aDescriptor = {}) { if (this._store.has(aName)) { return null; } @@ -831,6 +877,7 @@ create({ constructor: Variable, proto: Scope.prototype }, { let property = new Property(this, aName, aDescriptor); this._store.set(aName, property); this._variablesView._currHierarchy.set(property._absoluteName, property); + property.header = !!aName; return property; }, @@ -860,6 +907,88 @@ create({ constructor: Variable, proto: Scope.prototype }, { } }, + /** + * Populates this variable to contain all the properties of an object. + * + * @param object aObject + * The raw object you want to display. + */ + populate: function V_populate(aObject) { + // Retrieve the properties only once. + if (this.fetched) { + return; + } + + // Sort all of the properties before adding them. + let sortedPropertyNames = Object.getOwnPropertyNames(aObject).sort(); + let prototype = Object.getPrototypeOf(aObject); + + // Add all the variable properties. + for (let name of sortedPropertyNames) { + let descriptor = Object.getOwnPropertyDescriptor(aObject, name); + if (descriptor.get || descriptor.set) { + this._addRawNonValueProperty(name, descriptor); + } else { + this._addRawValueProperty(name, descriptor, aObject[name]); + } + } + // Add the variable's __proto__. + if (prototype) { + this._addRawValueProperty("__proto__", {}, prototype); + } + + this.fetched = true; + }, + + /** + * Adds a property for this variable based on a raw value descriptor. + * + * @param string aName + * The property's name. + * @param object aDescriptor + * Specifies the exact property descriptor as returned by a call to + * Object.getOwnPropertyDescriptor. + * @param object aValue + * The raw property value you want to display. + */ + _addRawValueProperty: function V__addRawValueProperty(aName, aDescriptor, aValue) { + let descriptor = Object.create(aDescriptor); + descriptor.value = VariablesView.getGrip(aValue); + + let propertyItem = this.addProperty(aName, descriptor); + + // Add an 'onexpand' callback for the property, lazily handling + // the addition of new child properties. + if (!VariablesView.isPrimitive(descriptor)) { + propertyItem.onexpand = this.populate.bind(propertyItem, aValue); + } + + return propertyItem; + }, + + /** + * Adds a property for this variable based on a getter/setter descriptor. + * + * @param string aName + * The property's name. + * @param object aDescriptor + * Specifies the exact property descriptor as returned by a call to + * Object.getOwnPropertyDescriptor. + */ + _addRawNonValueProperty: function V__addRawNonValueProperty(aName, aDescriptor) { + let descriptor = Object.create(aDescriptor); + descriptor.get = VariablesView.getGrip(aDescriptor.get); + descriptor.set = VariablesView.getGrip(aDescriptor.set); + + let propertyItem = this.addProperty(aName, descriptor); + return propertyItem; + }, + + /** + * Returns this variable's value from the descriptor if available, + */ + get value() this._initialDescriptor.value, + /** * Returns this variable's getter from the descriptor if available, */ @@ -961,8 +1090,8 @@ create({ constructor: Variable, proto: Scope.prototype }, { this.hideArrow(); } if (aDescriptor.get || aDescriptor.set) { - this.addProperty("get ", { value: aDescriptor.get }); - this.addProperty("set ", { value: aDescriptor.set }); + this.addProperty("get", { value: aDescriptor.get }); + this.addProperty("set", { value: aDescriptor.set }); this.expand(true); separatorLabel.hidden = true; valueLabel.hidden = true; @@ -1299,6 +1428,31 @@ VariablesView.isPrimitive = function VV_isPrimitive(aDescriptor) { return false; }; +/** + * Returns a standard grip for a value. + * + * @param any aValue + * The raw value to get a grip for. + * @return any + * The value's grip. + */ +VariablesView.getGrip = function VV_getGrip(aValue) { + if (aValue === undefined) { + return { type: "undefined" }; + } + if (aValue === null) { + return { type: "null" }; + } + if (typeof aValue == "object" || typeof aValue == "function") { + if (aValue.constructor) { + return { type: "object", class: aValue.constructor.name }; + } else { + return { type: "object", class: "Object" }; + } + } + return aValue; +}; + /** * Returns a custom formatted property string for a grip. * diff --git a/browser/themes/gnomestripe/devtools/debugger.css b/browser/themes/gnomestripe/devtools/debugger.css index b913d1f62e5..5bbf63b05d5 100644 --- a/browser/themes/gnomestripe/devtools/debugger.css +++ b/browser/themes/gnomestripe/devtools/debugger.css @@ -229,7 +229,7 @@ -moz-padding-start: 6px; } -.variable > .details { +.variable:not([non-header]) > .details { -moz-margin-start: 10px; } @@ -256,7 +256,7 @@ -moz-padding-start: 6px; } -.property > .details { +.property:not([non-header]) > .details { -moz-margin-start: 10px; } diff --git a/browser/themes/pinstripe/devtools/debugger.css b/browser/themes/pinstripe/devtools/debugger.css index b3d5decdf33..b6ae3c5a0e4 100644 --- a/browser/themes/pinstripe/devtools/debugger.css +++ b/browser/themes/pinstripe/devtools/debugger.css @@ -231,7 +231,7 @@ -moz-padding-start: 6px; } -.variable > .details { +.variable:not([non-header]) > .details { -moz-margin-start: 10px; } @@ -258,7 +258,7 @@ -moz-padding-start: 6px; } -.property > .details { +.property:not([non-header]) > .details { -moz-margin-start: 10px; } diff --git a/browser/themes/winstripe/devtools/debugger.css b/browser/themes/winstripe/devtools/debugger.css index 4e7b30f24b5..078c8161f74 100644 --- a/browser/themes/winstripe/devtools/debugger.css +++ b/browser/themes/winstripe/devtools/debugger.css @@ -237,7 +237,7 @@ -moz-padding-start: 6px; } -.variable > .details { +.variable:not([non-header]) > .details { -moz-margin-start: 10px; } @@ -264,7 +264,7 @@ -moz-padding-start: 6px; } -.property > .details { +.property:not([non-header]) > .details { -moz-margin-start: 10px; }