1
/* See license.txt for terms of usage */
3
FBL.ns(function() { with (FBL) {
5
// ************************************************************************************************
8
const jsdIStackFrame = CI("jsdIStackFrame");
10
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
12
const insertSliceSize = 18;
13
const insertInterval = 40;
20
// We are forced to ignore Java-related variables, because
21
// trying to access them causes browser freeze
32
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
35
TR({class: "memberRow $member.open $member.type\\Row", $hasChildren: "$member.hasChildren",
36
level: "$member.level"},
37
TD({class: "memberLabelCell", style: "padding-left: $member.indent\\px"},
38
DIV({class: "memberLabel $member.type\\Label"}, "$member.name")
40
TD({class: "memberValueCell"},
41
TAG("$member.tag", {object: "$member.value"})
46
TR({class: "watchNewRow", level: 0},
47
TD({class: "watchEditCell", colspan: 2},
48
DIV({class: "watchEditBox"},
60
const DirTablePlate = domplate(Firebug.Rep,
63
TABLE({class: "domTable", cellpadding: 0, cellspacing: 0, onclick: "$onClick"},
66
FOR("member", "$object|memberIterator", RowTag)
71
TABLE({class: "domTable", cellpadding: 0, cellspacing: 0,
72
_toggles: "$toggles", _domPanel: "$domPanel", onclick: "$onClick"},
80
TABLE({class: "domTable", cellpadding: 0, cellspacing: 0,
81
_toggles: "$toggles", _domPanel: "$domPanel", onclick: "$onClick"},
88
FOR("member", "$members", RowTag),
90
memberIterator: function(object, level)
92
return getMembers(object, level);
95
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
97
onClick: function(event)
99
if (!isLeftClick(event))
102
var row = getAncestorByClass(event.target, "memberRow");
103
var label = getAncestorByClass(event.target, "memberLabel");
104
if (label && hasClass(row, "hasChildren"))
106
var row = label.parentNode.parentNode;
111
var object = Firebug.getRepObject(event.target);
112
if (typeof(object) == "function")
114
FirebugChrome.select(object, "script");
117
else if (event.detail == 2 && !object)
119
var panel = row.parentNode.parentNode.domPanel;
122
var rowValue = panel.getRowPropertyValue(row);
123
if (typeof(rowValue) == "boolean")
124
panel.setPropertyValue(row, !rowValue);
126
panel.editProperty(row);
134
toggleRow: function(row)
136
var level = parseInt(row.getAttribute("level"));
137
var toggles = row.parentNode.parentNode.toggles;
139
if (hasClass(row, "opened"))
141
removeClass(row, "opened");
145
var path = getPath(row);
147
// Remove the path from the toggle tree
148
for (var i = 0; i < path.length; ++i)
150
if (i == path.length-1)
151
delete toggles[path[i]];
153
toggles = toggles[path[i]];
157
var rowTag = this.rowTag;
158
var tbody = row.parentNode;
160
setTimeout(function()
162
for (var firstRow = row.nextSibling; firstRow; firstRow = row.nextSibling)
164
if (parseInt(firstRow.getAttribute("level")) <= level)
167
tbody.removeChild(firstRow);
169
}, row.insertTimeout ? row.insertTimeout : 0);
173
setClass(row, "opened");
177
var path = getPath(row);
179
// Mark the path in the toggle tree
180
for (var i = 0; i < path.length; ++i)
183
if ( toggles.hasOwnProperty(name) )
184
toggles = toggles[name];
186
toggles = toggles[name] = {};
190
var value = row.lastChild.firstChild.repObject;
191
var members = getMembers(value, level+1);
193
var rowTag = this.rowTag;
197
while (members.length)
199
setTimeout(function(slice, isLast)
201
if (lastRow.parentNode)
202
lastRow = rowTag.insertRows({members: slice}, lastRow)[1];
205
delete row.insertTimeout;
206
}, delay, members.splice(0, insertSliceSize), !members.length);
208
delay += insertInterval;
211
row.insertTimeout = delay;
216
const ToolboxPlate = domplate(
219
DIV({class: "watchToolbox", _domPanel: "$domPanel", onclick: "$onClick"},
220
IMG({class: "watchDeleteButton closeButton", src: "blank.gif"})
223
onClick: function(event)
225
var toolbox = event.currentTarget;
226
toolbox.domPanel.deleteWatch(toolbox.watchRow);
230
// ************************************************************************************************
232
function DOMBasePanel() {}
234
DOMBasePanel.prototype = extend(Firebug.Panel,
236
tag: DirTablePlate.tableTag,
238
rebuild: function(update, scrollTop)
240
var members = getMembers(this.selection);
241
expandMembers(members, this.toggles, 0, 0);
243
this.showMembers(members, update, scrollTop);
246
showMembers: function(members, update, scrollTop)
248
// If we are still in the midst of inserting rows, cancel all pending
249
// insertions here - this is a big speedup when stepping in the debugger
252
for (var i = 0; i < this.timeouts.length; ++i)
253
this.context.clearTimeout(this.timeouts[i]);
254
delete this.timeouts;
258
return this.showEmptyMembers();
260
var panelNode = this.panelNode;
261
var priorScrollTop = scrollTop == undefined ? panelNode.scrollTop : scrollTop;
263
// If we are asked to "update" the current view, then build the new table
264
// offscreen and swap it in when it's done
265
var offscreen = update && panelNode.firstChild;
266
var dest = offscreen ? this.document : panelNode;
268
var table = this.tag.replace({domPanel: this, toggles: this.toggles}, dest);
269
var tbody = table.lastChild;
270
var rowTag = DirTablePlate.rowTag;
272
// Insert the first slice immediately
273
var slice = members.splice(0, insertSliceSize);
274
rowTag.insertRows({members: slice}, tbody.lastChild);
279
while (members.length)
281
timeouts.push(this.context.setTimeout(function(slice)
283
rowTag.insertRows({members: slice}, tbody.lastChild);
285
if ((panelNode.scrollHeight+panelNode.offsetHeight) >= priorScrollTop)
286
panelNode.scrollTop = priorScrollTop;
287
}, delay, members.splice(0, insertSliceSize)));
289
delay += insertInterval;
294
timeouts.push(this.context.setTimeout(function()
296
if (panelNode.firstChild)
297
panelNode.replaceChild(table, panelNode.firstChild);
299
panelNode.appendChild(table);
301
// Scroll back to where we were before
302
panelNode.scrollTop = priorScrollTop;
307
timeouts.push(this.context.setTimeout(function()
309
panelNode.scrollTop = scrollTop == undefined ? 0 : scrollTop;
316
showEmptyMembers: function()
318
FirebugReps.Warning.tag.replace({object: "NoMembersWarning"}, this.panelNode);
321
findPathObject: function(object)
324
for (var i = 0; i < this.objectPath.length; ++i)
326
if (this.getPathObject(i) == object)
333
getPathObject: function(index)
335
var object = this.objectPath[index];
336
if (object instanceof Property)
337
return object.getObject();
342
getRowObject: function(row)
344
var object = getRowOwnerObject(row);
345
return object ? object : this.selection;
348
getRowPropertyValue: function(row)
350
var object = this.getRowObject(row);
353
var propName = getRowName(row);
355
if (object instanceof jsdIStackFrame)
356
return Firebug.Debugger.evaluate(propName, this.context);
358
return object[propName];
362
copyProperty: function(row)
364
var value = this.getRowPropertyValue(row);
365
copyToClipboard(value);
368
editProperty: function(row, editValue)
370
if (hasClass(row, "watchNewRow"))
371
Firebug.Editor.startEditing(row, "");
372
else if (hasClass(row, "watchRow"))
373
Firebug.Editor.startEditing(row, getRowName(row));
376
var object = this.getRowObject(row);
377
this.context.thisValue = object;
381
var propValue = this.getRowPropertyValue(row);
383
var type = typeof(propValue);
384
if (type == "undefined" || type == "number" || type == "boolean")
385
editValue = propValue;
386
else if (type == "string")
387
editValue = "\"" + escapeJS(propValue) + "\"";
388
else if (propValue == null)
390
else if (object instanceof Window || object instanceof jsdIStackFrame)
391
editValue = getRowName(row);
393
editValue = "this." + getRowName(row);
397
Firebug.Editor.startEditing(row, editValue);
401
deleteProperty: function(row)
403
if (hasClass(row, "watchRow"))
404
this.deleteWatch(row);
407
var object = getRowOwnerObject(row);
409
object = this.selection;
413
var name = getRowName(row);
429
setPropertyValue: function(row, value)
431
var name = getRowName(row);
435
var object = this.getRowObject(row);
436
if (object && !(object instanceof jsdIStackFrame))
440
object[name] = Firebug.CommandLine.evaluate(value, this.context, null, object);
446
// If the value doesn't parse, then just store it as a string. Some users will
447
// not realize they're supposed to enter a JavaScript expression and just type
449
object[name] = value;
457
else if (this.context.stopped)
461
Firebug.CommandLine.evaluate(name+"="+value, this.context);
467
// See catch block above...
468
object[name] = value;
481
highlightRow: function(row)
483
if (this.highlightedRow)
484
cancelClassTimed(this.highlightedRow, "jumpHighlight", this.context);
486
this.highlightedRow = row;
489
setClassTimed(row, "jumpHighlight", this.context);
492
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
495
initialize: function()
497
this.objectPath = [];
498
this.propertyPath = [];
503
Firebug.Panel.initialize.apply(this, arguments);
506
destroy: function(state)
508
var view = this.viewPath[this.pathIndex];
509
if (view && this.panelNode.scrollTop)
510
view.scrollTop = this.panelNode.scrollTop;
512
state.pathIndex = this.pathIndex;
513
state.viewPath = this.viewPath;
514
state.propertyPath = this.propertyPath;
515
if (this.propertyPath.length > 0 && !this.propertyPath[1])
516
state.firstSelection = persistObject(this.getPathObject(1), this.context);
518
Firebug.Panel.destroy.apply(this, arguments);
521
show: function(state)
523
if (this.context.loaded && !this.selection)
531
this.viewPath = state.viewPath;
532
this.propertyPath = state.propertyPath;
534
var selectObject = defaultObject = this.getDefaultSelection();
536
if (state.firstSelection)
538
var restored = state.firstSelection(this.context);
541
selectObject = restored;
542
this.objectPath = [defaultObject, restored];
545
this.objectPath = [defaultObject];
548
this.objectPath = [defaultObject];
550
if (this.propertyPath.length > 1)
552
for (var i = 1; i < this.propertyPath.length; ++i)
554
var name = this.propertyPath[i];
558
var object = selectObject;
561
selectObject = object[name];
570
this.objectPath.push(new Property(object, name));
574
// If we can't access a property, just stop
575
this.viewPath.splice(i);
576
this.propertyPath.splice(i);
577
this.objectPath.splice(i);
578
selectObject = this.getPathObject(this.objectPath.length-1);
584
var selection = state.pathIndex <= this.objectPath.length-1
585
? this.getPathObject(state.pathIndex)
586
: this.getPathObject(this.objectPath.length-1);
588
this.select(selection);
594
var view = this.viewPath[this.pathIndex];
595
if (view && this.panelNode.scrollTop)
596
view.scrollTop = this.panelNode.scrollTop;
599
supportsObject: function(object)
604
if (typeof(object) == "undefined")
606
else if (object instanceof SourceLink)
609
return 1; // just agree to support everything but not agressively.
617
updateSelection: function(object)
619
var previousIndex = this.pathIndex;
620
var previousView = previousIndex == -1 ? null : this.viewPath[previousIndex];
622
var newPath = this.pathToAppend;
623
delete this.pathToAppend;
625
var pathIndex = this.findPathObject(object);
626
if (newPath || pathIndex == -1)
632
// Remove everything after the point where we are inserting, so we
633
// essentially replace it with the new path
636
if (this.panelNode.scrollTop)
637
previousView.scrollTop = this.panelNode.scrollTop;
639
this.objectPath.splice(previousIndex+1);
640
this.propertyPath.splice(previousIndex+1);
641
this.viewPath.splice(previousIndex+1);
644
var value = this.getPathObject(previousIndex);
645
for (var i = 0; i < newPath.length; ++i)
647
var name = newPath[i];
652
this.objectPath.push(new Property(object, name));
653
this.propertyPath.push(name);
654
this.viewPath.push({toggles: this.toggles, scrollTop: 0});
661
var win = this.context.window;
665
this.objectPath = [win];
666
this.propertyPath = [null];
667
this.viewPath = [{toggles: this.toggles, scrollTop: 0}];
672
this.objectPath = [win, object];
673
this.propertyPath = [null, null];
675
{toggles: {}, scrollTop: 0},
676
{toggles: this.toggles, scrollTop: 0}
681
this.panelNode.scrollTop = 0;
686
this.pathIndex = pathIndex;
688
var view = this.viewPath[pathIndex];
689
this.toggles = view.toggles;
691
// Persist the current scroll location
692
if (previousView && this.panelNode.scrollTop)
693
previousView.scrollTop = this.panelNode.scrollTop;
695
this.rebuild(false, view.scrollTop);
700
getObjectPath: function(object)
702
return this.objectPath;
705
getDefaultSelection: function()
707
return this.context.window;
710
updateOption: function(name, value)
712
const optionMap = {showUserProps: 1, showUserFuncs: 1, showDOMProps: 1,
713
showDOMFuncs: 1, showDOMConstants: 1};
714
if (name in optionMap)
718
getOptionsMenuItems: function()
721
optionMenu("ShowUserProps", "showUserProps"),
722
optionMenu("ShowUserFuncs", "showUserFuncs"),
723
optionMenu("ShowDOMProps", "showDOMProps"),
724
optionMenu("ShowDOMFuncs", "showDOMFuncs"),
725
optionMenu("ShowDOMConstants", "showDOMConstants"),
727
{label: "Refresh", command: bindFixed(this.rebuild, this, true) }
731
getContextMenuItems: function(object, target)
733
var row = getAncestorByClass(target, "memberRow");
739
var rowName = getRowName(row);
740
var rowObject = this.getRowObject(row);
741
var rowValue = this.getRowPropertyValue(row);
743
var isWatch = hasClass(row, "watchRow");
744
var isStackFrame = rowObject instanceof jsdIStackFrame;
746
if (typeof(rowValue) == "string" || typeof(rowValue) == "number")
748
// Functions already have a copy item in their context menu
752
command: bindFixed(this.copyProperty, this, row) }
758
{label: isWatch ? "EditWatch" : (isStackFrame ? "EditVariable" : "EditProperty"),
759
command: bindFixed(this.editProperty, this, row) }
762
if (isWatch || (!isStackFrame && !isDOMMember(rowObject, rowName)))
765
{label: isWatch ? "DeleteWatch" : "DeleteProperty",
766
command: bindFixed(this.deleteProperty, this, row) }
773
{label: "Refresh", command: bindFixed(this.rebuild, this, true) }
779
getEditor: function(target, value)
782
this.editor = new DOMEditor(this.document);
788
// ************************************************************************************************
790
var DOMMainPanel = Firebug.DOMPanel = function () {};
792
Firebug.DOMPanel.DirTable = DirTablePlate;
794
DOMMainPanel.prototype = extend(DOMBasePanel.prototype,
796
selectRow: function(row, target)
799
target = row.lastChild.firstChild;
801
if (!target || !target.repObject)
804
this.pathToAppend = getPath(row);
806
// If the object is inside an array, look up its index
807
var valueBox = row.lastChild.firstChild;
808
if (hasClass(valueBox, "objectBox-array"))
810
var arrayIndex = FirebugReps.Arr.getItemIndex(target);
811
this.pathToAppend.push(arrayIndex);
814
// Make sure we get a fresh status path for the object, since otherwise
815
// it might find the object in the existing path and not refresh it
816
this.context.chrome.clearStatusPath();
818
this.select(target.repObject, true);
821
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
823
onClick: function(event)
825
var repNode = Firebug.getRepNode(event.target);
828
var row = getAncestorByClass(event.target, "memberRow");
831
this.selectRow(row, repNode);
837
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
842
statusSeparator: ">",
844
initialize: function()
846
this.onClick = bind(this.onClick, this);
848
DOMBasePanel.prototype.initialize.apply(this, arguments);
851
initializeNode: function(oldPanelNode)
853
this.panelNode.addEventListener("click", this.onClick, false);
856
destroyNode: function()
858
this.panelNode.removeEventListener("click", this.onClick, false);
861
search: function(text, visit)
865
delete this.currentSearch;
866
this.highlightRow(null);
870
if (visit && this.currentSearch && this.currentSearch.currentNode)
872
Firebug.Search.clear(this.context);
873
this.selectRow(this.currentSearch.currentNode);
874
delete this.currentSearch;
880
if (this.currentSearch && text == this.currentSearch.text)
881
row = this.currentSearch.findNext(true);
884
function findRow(node) { return getAncestorByClass(node, "memberRow"); }
885
this.currentSearch = new TextSearch(this.panelNode, findRow);
886
row = this.currentSearch.find(text);
893
Firebug.Search.clear(this.context);
895
delete this.currentSearch;
899
var sel = this.document.defaultView.getSelection();
900
sel.removeAllRanges();
901
sel.addRange(this.currentSearch.range);
903
scrollIntoCenterView(row, this.panelNode);
905
this.highlightRow(row);
915
// ************************************************************************************************
917
function DOMSidePanel() {}
919
DOMSidePanel.prototype = extend(DOMBasePanel.prototype,
921
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
928
// ************************************************************************************************
930
function WatchPanel() {}
932
WatchPanel.prototype = extend(DOMBasePanel.prototype,
934
tag: DirTablePlate.watchTag,
938
this.updateSelection(this.selection);
941
showEmptyMembers: function()
943
this.tag.replace({domPanel: this, toggles: {}}, this.panelNode);
946
addWatch: function(expression)
951
this.watches.splice(0, 0, expression);
955
removeWatch: function(expression)
960
var index = this.watches.indexOf(expression);
962
this.watches.splice(index, 1);
965
editNewWatch: function(value)
967
var watchNewRow = getElementByClass(this.panelNode, "watchNewRow");
969
this.editProperty(watchNewRow, value);
972
setWatchValue: function(row, value)
974
var rowIndex = getWatchRowIndex(row);
975
this.watches[rowIndex] = value;
979
deleteWatch: function(row)
981
var rowIndex = getWatchRowIndex(row);
982
this.watches.splice(rowIndex, 1);
985
this.context.setTimeout(bindFixed(function()
987
this.showToolbox(null);
991
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
993
showToolbox: function(row)
995
var toolbox = this.getToolbox();
998
if (hasClass(row, "editing"))
1001
toolbox.watchRow = row;
1003
var offset = getClientOffset(row);
1004
toolbox.style.top = offset.y + "px";
1005
this.panelNode.appendChild(toolbox);
1009
delete toolbox.watchRow;
1010
if (toolbox.parentNode)
1011
toolbox.parentNode.removeChild(toolbox);
1015
getToolbox: function()
1018
this.toolbox = ToolboxPlate.tag.replace({domPanel: this}, this.document);
1020
return this.toolbox;
1023
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1025
onMouseDown: function(event)
1027
var watchNewRow = getAncestorByClass(event.target, "watchNewRow");
1030
this.editProperty(watchNewRow);
1035
onMouseOver: function(event)
1037
var watchRow = getAncestorByClass(event.target, "watchRow");
1039
this.showToolbox(watchRow);
1042
onMouseOut: function(event)
1044
if (isAncestor(event.relatedTarget, this.getToolbox()))
1047
var watchRow = getAncestorByClass(event.relatedTarget, "watchRow");
1049
this.showToolbox(null);
1052
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1057
parentPanel: "script",
1059
initialize: function()
1061
this.onMouseDown = bind(this.onMouseDown, this);
1062
this.onMouseOver = bind(this.onMouseOver, this);
1063
this.onMouseOut = bind(this.onMouseOut, this);
1065
DOMBasePanel.prototype.initialize.apply(this, arguments);
1068
destroy: function(state)
1070
state.watches = this.watches;
1072
Firebug.Panel.destroy.apply(this, arguments);
1075
show: function(state)
1078
this.watches = state.watches;
1081
initializeNode: function(oldPanelNode)
1083
this.panelNode.addEventListener("mousedown", this.onMouseDown, false);
1084
this.panelNode.addEventListener("mouseover", this.onMouseOver, false);
1085
this.panelNode.addEventListener("mouseout", this.onMouseOut, false);
1088
destroyNode: function()
1090
this.panelNode.removeEventListener("mousedown", this.onMouseDown, false);
1091
this.panelNode.removeEventListener("mouseover", this.onMouseOver, false);
1092
this.panelNode.removeEventListener("mouseout", this.onMouseOut, false);
1100
updateSelection: function(object)
1102
var frame = this.context.currentFrame;
1104
var newFrame = frame && frame.script != this.lastScript;
1108
this.lastScript = frame.script;
1115
for (var i = 0; i < this.watches.length; ++i)
1117
var expr = this.watches[i];
1122
value = Firebug.CommandLine.evaluate(expr, this.context);
1126
if (exc instanceof this.context.window.Error)
1127
value = new ErrorCopy(exc.message);
1129
value = new ErrorCopy(exc+"");
1132
addMember("watch", members, expr, value, 0);
1138
var thisVar = frame.thisValue.getWrappedValue();
1139
addMember("user", members, "this", thisVar, 0);
1141
var listValue = {value: null}, lengthValue = {value: 0};
1142
frame.scope.getProperties(listValue, lengthValue);
1144
var props = [], funcs = [];
1145
for (var i = 0; i < lengthValue.value; ++i)
1147
var prop = listValue.value[i];
1148
var name = prop.name.getWrappedValue();
1149
if (ignoreVars[name] == 1)
1152
var value = prop.value.getWrappedValue();
1153
if (typeof(value) == "function")
1154
addMember("userFunction", funcs, name, value, 0);
1156
addMember("user", props, name, value, 0);
1159
function sortName(a, b) { return a.name > b.name ? 1 : -1; }
1161
props.sort(sortName);
1162
members.push.apply(members, props);
1164
funcs.sort(sortName);
1165
members.push.apply(members, funcs);
1168
expandMembers(members, this.toggles, 0, 0);
1169
this.showMembers(members, !newFrame);
1173
// ************************************************************************************************
1176
function DOMEditor(doc)
1178
this.box = this.tag.replace({}, doc, this);
1179
this.input = this.box;
1181
this.tabNavigation = false;
1182
this.tabCompletion = true;
1183
this.completeAsYouType = false;
1184
this.fixedWidth = true;
1186
this.autoCompleter = Firebug.CommandLine.autoCompleter;
1189
DOMEditor.prototype = domplate(Firebug.InlineEditor.prototype,
1191
tag: INPUT({class: "fixedWidthEditor", type: "text",
1192
oninput: "$onInput", onkeypress: "$onKeyPress"}),
1194
endEditing: function(target, value, cancel)
1196
// XXXjoe Kind of hackish - fix me
1197
delete this.panel.context.thisValue;
1199
if (cancel || value == "")
1202
var row = getAncestorByClass(target, "memberRow");
1204
this.panel.addWatch(value);
1205
else if (hasClass(row, "watchRow"))
1206
this.panel.setWatchValue(row, value);
1208
this.panel.setPropertyValue(row, value);
1212
// ************************************************************************************************
1215
function getMembers(object, level)
1220
var ordinals = [], userProps = [], userClasses = [], userFuncs = [],
1221
domProps = [], domFuncs = [], domConstants = [];
1225
var domMembers = getDOMMembers(object);
1227
for (var name in object)
1229
if (ignoreVars[name] == 1) // javascript.options.strict says ignoreVars is undefined.
1239
// Sometimes we get exceptions trying to access certain members
1242
var ordinal = parseInt(name);
1243
if (ordinal || ordinal == 0)
1245
addMember("ordinal", ordinals, name, val, level);
1247
else if (typeof(val) == "function")
1249
if (isClassFunction(val))
1250
addMember("userClass", userClasses, name, val, level);
1251
else if (name in domMembers)
1252
addMember("domFunction", domFuncs, name, val, level, domMembers[name]);
1254
addMember("userFunction", userFuncs, name, val, level);
1258
if (name in domMembers)
1259
addMember("dom", domProps, name, val, level, domMembers[name]);
1260
else if (name in domConstantMap)
1261
addMember("dom", domConstants, name, val, level);
1263
addMember("user", userProps, name, val, level);
1269
// Sometimes we get exceptions just from trying to iterate the members
1270
// of certain objects, like StorageList, but don't let that gum up the works
1274
function sortName(a, b) { return a.name > b.name ? 1 : -1; }
1275
function sortOrder(a, b) { return a.order > b.order ? 1 : -1; }
1279
members.push.apply(members, ordinals);
1281
if (Firebug.showUserProps)
1283
userProps.sort(sortName);
1284
members.push.apply(members, userProps);
1287
if (Firebug.showUserFuncs)
1289
userClasses.sort(sortName);
1290
members.push.apply(members, userClasses);
1292
userFuncs.sort(sortName);
1293
members.push.apply(members, userFuncs);
1296
if (Firebug.showDOMProps)
1298
domProps.sort(sortOrder);
1299
members.push.apply(members, domProps);
1302
if (Firebug.showDOMFuncs)
1304
domFuncs.sort(sortName);
1305
members.push.apply(members, domFuncs);
1308
if (Firebug.showDOMConstants)
1309
members.push.apply(members, domConstants);
1314
function expandMembers(members, toggles, offset, level)
1317
for (var i = offset; i < members.length; ++i)
1319
var member = members[i];
1320
if (member.level > level)
1323
if ( toggles.hasOwnProperty(member.name) )
1325
member.open = "opened"; // member.level <= level && member.name in toggles.
1327
var newMembers = getMembers(member.value, level+1); // sets newMembers.level to level+1
1329
var args = [i+1, 0];
1330
args.push.apply(args, newMembers);
1331
members.splice.apply(members, args);
1333
expanded += newMembers.length;
1334
var memberToggles = toggles[member.name];
1335
// if member.name == 'prototype', then toggles gets confused and we go into infinite loop XXXjjb
1336
if (typeof(memberToggles) != 'object')
1338
i += newMembers.length + expandMembers(members, memberToggles, i+1, level+1);
1345
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1347
function isClassFunction(fn)
1351
for (var name in fn.prototype)
1357
function hasProperties(ob)
1361
for (var name in ob)
1367
function addMember(type, props, name, value, level, order)
1369
var valueType = typeof(value);
1370
var hasChildren = hasProperties(value) && !(value instanceof ErrorCopy) &&
1371
(valueType == "function" || (valueType == "object" && value != null)
1372
|| (valueType == "string" && value.length > Firebug.stringCropLength));
1374
var rep = Firebug.getRep(value);
1375
var tag = rep.shortTag ? rep.shortTag : rep.tag;
1381
rowClass: "memberRow-"+type,
1386
hasChildren: hasChildren,
1391
function getWatchRowIndex(row)
1394
for (; row && hasClass(row, "watchRow"); row = row.previousSibling)
1399
function getRowName(row)
1401
return row.firstChild.textContent;
1404
function getRowValue(row)
1406
return row.lastChild.firstChild.repObject;
1409
function getRowOwnerObject(row)
1411
var parentRow = getParentRow(row);
1413
return getRowValue(parentRow);
1416
function getParentRow(row)
1418
var level = parseInt(row.getAttribute("level"))-1;
1419
for (row = row.previousSibling; row; row = row.previousSibling)
1421
if (parseInt(row.getAttribute("level")) == level)
1426
function getPath(row)
1428
var name = getRowName(row);
1431
var level = parseInt(row.getAttribute("level"))-1;
1432
for (row = row.previousSibling; row; row = row.previousSibling)
1434
if (parseInt(row.getAttribute("level")) == level)
1436
var name = getRowName(row);
1437
path.splice(0, 0, name);
1446
// ************************************************************************************************
1448
Firebug.registerPanel(DOMMainPanel);
1449
Firebug.registerPanel(DOMSidePanel);
1450
Firebug.registerPanel(WatchPanel);
1452
// ************************************************************************************************