зеркало из https://github.com/mozilla/gecko-dev.git
bug 843094 - Remove the PropertyPanel; r=msucan
This commit is contained in:
Родитель
994b767e33
Коммит
5a6d714476
|
@ -21,7 +21,6 @@ const Cu = Components.utils;
|
|||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
Cu.import("resource:///modules/PropertyPanel.jsm");
|
||||
Cu.import("resource:///modules/source-editor.jsm");
|
||||
Cu.import("resource:///modules/devtools/LayoutHelpers.jsm");
|
||||
Cu.import("resource:///modules/devtools/scratchpad-manager.jsm");
|
||||
|
|
|
@ -11,7 +11,6 @@ include $(DEPTH)/config/autoconf.mk
|
|||
|
||||
EXTRA_JS_MODULES = \
|
||||
HUDService.jsm \
|
||||
PropertyPanel.jsm \
|
||||
NetworkPanel.jsm \
|
||||
WebConsolePanel.jsm \
|
||||
$(NULL)
|
||||
|
|
|
@ -1,501 +0,0 @@
|
|||
/* -*- Mode: js2; js2-basic-offset: 2; indent-tabs-mode: nil; -*- */
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "WebConsoleUtils",
|
||||
"resource://gre/modules/devtools/WebConsoleUtils.jsm");
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["PropertyPanel", "PropertyTreeView"];
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//// PropertyTreeView.
|
||||
|
||||
/**
|
||||
* This is an implementation of the nsITreeView interface. For comments on the
|
||||
* interface properties, see the documentation:
|
||||
* https://developer.mozilla.org/en/XPCOM_Interface_Reference/nsITreeView
|
||||
*/
|
||||
this.PropertyTreeView = function() {
|
||||
this._rows = [];
|
||||
this._objectActors = [];
|
||||
};
|
||||
|
||||
PropertyTreeView.prototype = {
|
||||
/**
|
||||
* Stores the visible rows of the tree.
|
||||
* @private
|
||||
*/
|
||||
_rows: null,
|
||||
|
||||
/**
|
||||
* Stores the nsITreeBoxObject for this tree.
|
||||
* @private
|
||||
*/
|
||||
_treeBox: null,
|
||||
|
||||
/**
|
||||
* Track known object actor IDs. We clean these when the panel is
|
||||
* destroyed/cleaned up.
|
||||
*
|
||||
* @private
|
||||
* @type array
|
||||
*/
|
||||
_objectActors: null,
|
||||
|
||||
/**
|
||||
* Map fake object actors to their IDs. This is used when we inspect local
|
||||
* objects.
|
||||
* @private
|
||||
* @type Object
|
||||
*/
|
||||
_localObjectActors: null,
|
||||
|
||||
_releaseObject: null,
|
||||
_objectPropertiesProvider: null,
|
||||
|
||||
/**
|
||||
* Use this setter to update the content of the tree.
|
||||
*
|
||||
* @param object aData
|
||||
* A meta object that holds information about the object you want to
|
||||
* display in the property panel. Object properties:
|
||||
* - object:
|
||||
* This is the raw object you want to display. You can only provide
|
||||
* this object if you want the property panel to work in sync mode.
|
||||
* - objectProperties:
|
||||
* An array that holds information on the remote object being
|
||||
* inspected. Each element in this array describes each property in the
|
||||
* remote object. See WebConsoleUtils.inspectObject() for details.
|
||||
* - objectPropertiesProvider:
|
||||
* A function that is invoked when a new object is needed. This is
|
||||
* called when the user tries to expand an inspectable property. The
|
||||
* callback must take four arguments:
|
||||
* - actorID:
|
||||
* The object actor ID from which we request the properties.
|
||||
* - callback:
|
||||
* The callback function to be invoked when the remote object is
|
||||
* received. This function takes one argument: the array of
|
||||
* descriptors for each property in the object represented by the
|
||||
* actor.
|
||||
* - releaseObject:
|
||||
* Function to invoke when an object actor should be released. The
|
||||
* function must take one argument: the object actor ID.
|
||||
*/
|
||||
set data(aData) {
|
||||
let oldLen = this._rows.length;
|
||||
|
||||
this.cleanup();
|
||||
|
||||
if (!aData) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aData.objectPropertiesProvider) {
|
||||
this._objectPropertiesProvider = aData.objectPropertiesProvider;
|
||||
this._releaseObject = aData.releaseObject;
|
||||
this._propertiesToRows(aData.objectProperties, 0);
|
||||
this._rows = aData.objectProperties;
|
||||
}
|
||||
else if (aData.object) {
|
||||
this._localObjectActors = Object.create(null);
|
||||
this._rows = this._inspectObject(aData.object);
|
||||
}
|
||||
else {
|
||||
throw new Error("First argument must have an objectActor or an " +
|
||||
"object property!");
|
||||
}
|
||||
|
||||
if (this._treeBox) {
|
||||
this._treeBox.beginUpdateBatch();
|
||||
if (oldLen) {
|
||||
this._treeBox.rowCountChanged(0, -oldLen);
|
||||
}
|
||||
this._treeBox.rowCountChanged(0, this._rows.length);
|
||||
this._treeBox.endUpdateBatch();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Update a remote object so it can be used with the tree view. This method
|
||||
* adds properties to each array element.
|
||||
*
|
||||
* @private
|
||||
* @param array aObject
|
||||
* The remote object you want prepared for use with the tree view.
|
||||
* @param number aLevel
|
||||
* The level you want to give to each property in the remote object.
|
||||
*/
|
||||
_propertiesToRows: function PTV__propertiesToRows(aObject, aLevel)
|
||||
{
|
||||
aObject.forEach(function(aItem) {
|
||||
aItem._level = aLevel;
|
||||
aItem._open = false;
|
||||
aItem._children = null;
|
||||
|
||||
if (this._releaseObject) {
|
||||
["value", "get", "set"].forEach(function(aProp) {
|
||||
let val = aItem[aProp];
|
||||
if (val && val.actor) {
|
||||
this._objectActors.push(val.actor);
|
||||
if (typeof val.displayString == "object" &&
|
||||
val.displayString.type == "longString") {
|
||||
this._objectActors.push(val.displayString.actor);
|
||||
}
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
}, this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Inspect a local object.
|
||||
*
|
||||
* @private
|
||||
* @param object aObject
|
||||
* The object you want to inspect.
|
||||
* @return array
|
||||
* The array of properties, each being described in a way that is
|
||||
* usable by the tree view.
|
||||
*/
|
||||
_inspectObject: function PTV__inspectObject(aObject)
|
||||
{
|
||||
this._objectPropertiesProvider = this._localPropertiesProvider.bind(this);
|
||||
let children =
|
||||
WebConsoleUtils.inspectObject(aObject, this._localObjectGrip.bind(this));
|
||||
this._propertiesToRows(children, 0);
|
||||
return children;
|
||||
},
|
||||
|
||||
/**
|
||||
* Make a local fake object actor for the given object.
|
||||
*
|
||||
* @private
|
||||
* @param object aObject
|
||||
* The object to make an actor for.
|
||||
* @return object
|
||||
* The fake actor grip that represents the given object.
|
||||
*/
|
||||
_localObjectGrip: function PTV__localObjectGrip(aObject)
|
||||
{
|
||||
let grip = WebConsoleUtils.getObjectGrip(aObject);
|
||||
grip.actor = "obj" + gSequenceId();
|
||||
this._localObjectActors[grip.actor] = aObject;
|
||||
return grip;
|
||||
},
|
||||
|
||||
/**
|
||||
* A properties provider for when the user inspects local objects (not remote
|
||||
* ones).
|
||||
*
|
||||
* @private
|
||||
* @param string aActor
|
||||
* The ID of the object actor you want.
|
||||
* @param function aCallback
|
||||
* The function you want to receive the list of properties.
|
||||
*/
|
||||
_localPropertiesProvider:
|
||||
function PTV__localPropertiesProvider(aActor, aCallback)
|
||||
{
|
||||
let object = this._localObjectActors[aActor];
|
||||
let properties =
|
||||
WebConsoleUtils.inspectObject(object, this._localObjectGrip.bind(this));
|
||||
aCallback(properties);
|
||||
},
|
||||
|
||||
/** nsITreeView interface implementation **/
|
||||
|
||||
selection: null,
|
||||
|
||||
get rowCount() { return this._rows.length; },
|
||||
setTree: function(treeBox) { this._treeBox = treeBox; },
|
||||
getCellText: function PTV_getCellText(idx, column)
|
||||
{
|
||||
let row = this._rows[idx];
|
||||
return row.name + ": " + WebConsoleUtils.getPropertyPanelValue(row);
|
||||
},
|
||||
getLevel: function(idx) {
|
||||
return this._rows[idx]._level;
|
||||
},
|
||||
isContainer: function(idx) {
|
||||
return typeof this._rows[idx].value == "object" && this._rows[idx].value &&
|
||||
this._rows[idx].value.inspectable;
|
||||
},
|
||||
isContainerOpen: function(idx) {
|
||||
return this._rows[idx]._open;
|
||||
},
|
||||
isContainerEmpty: function(idx) { return false; },
|
||||
isSeparator: function(idx) { return false; },
|
||||
isSorted: function() { return false; },
|
||||
isEditable: function(idx, column) { return false; },
|
||||
isSelectable: function(row, col) { return true; },
|
||||
|
||||
getParentIndex: function(idx)
|
||||
{
|
||||
if (this.getLevel(idx) == 0) {
|
||||
return -1;
|
||||
}
|
||||
for (var t = idx - 1; t >= 0; t--) {
|
||||
if (this.isContainer(t)) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
},
|
||||
|
||||
hasNextSibling: function(idx, after)
|
||||
{
|
||||
let thisLevel = this.getLevel(idx);
|
||||
return this._rows.slice(after + 1).some(function (r) r._level == thisLevel);
|
||||
},
|
||||
|
||||
toggleOpenState: function(idx)
|
||||
{
|
||||
let item = this._rows[idx];
|
||||
if (!this.isContainer(idx)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (item._open) {
|
||||
this._treeBox.beginUpdateBatch();
|
||||
item._open = false;
|
||||
|
||||
var thisLevel = item._level;
|
||||
var t = idx + 1, deleteCount = 0;
|
||||
while (t < this._rows.length && this.getLevel(t++) > thisLevel) {
|
||||
deleteCount++;
|
||||
}
|
||||
|
||||
if (deleteCount) {
|
||||
this._rows.splice(idx + 1, deleteCount);
|
||||
this._treeBox.rowCountChanged(idx + 1, -deleteCount);
|
||||
}
|
||||
this._treeBox.invalidateRow(idx);
|
||||
this._treeBox.endUpdateBatch();
|
||||
}
|
||||
else {
|
||||
let levelUpdate = true;
|
||||
let callback = function _onRemoteResponse(aProperties) {
|
||||
this._treeBox.beginUpdateBatch();
|
||||
if (levelUpdate) {
|
||||
this._propertiesToRows(aProperties, item._level + 1);
|
||||
item._children = aProperties;
|
||||
}
|
||||
|
||||
this._rows.splice.apply(this._rows, [idx + 1, 0].concat(item._children));
|
||||
|
||||
this._treeBox.rowCountChanged(idx + 1, item._children.length);
|
||||
this._treeBox.invalidateRow(idx);
|
||||
this._treeBox.endUpdateBatch();
|
||||
item._open = true;
|
||||
}.bind(this);
|
||||
|
||||
if (!item._children) {
|
||||
this._objectPropertiesProvider(item.value.actor, callback);
|
||||
}
|
||||
else {
|
||||
levelUpdate = false;
|
||||
callback(item._children);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getImageSrc: function(idx, column) { },
|
||||
getProgressMode : function(idx,column) { },
|
||||
getCellValue: function(idx, column) { },
|
||||
cycleHeader: function(col, elem) { },
|
||||
selectionChanged: function() { },
|
||||
cycleCell: function(idx, column) { },
|
||||
performAction: function(action) { },
|
||||
performActionOnCell: function(action, index, column) { },
|
||||
performActionOnRow: function(action, row) { },
|
||||
getRowProperties: function(idx) { return ""; },
|
||||
getCellProperties: function(idx, column) { return ""; },
|
||||
getColumnProperties: function(column, element) { return ""; },
|
||||
|
||||
setCellValue: function(row, col, value) { },
|
||||
setCellText: function(row, col, value) { },
|
||||
drop: function(index, orientation, dataTransfer) { },
|
||||
canDrop: function(index, orientation, dataTransfer) { return false; },
|
||||
|
||||
/**
|
||||
* Cleanup the property tree view.
|
||||
*/
|
||||
cleanup: function PTV_cleanup()
|
||||
{
|
||||
if (this._releaseObject) {
|
||||
this._objectActors.forEach(this._releaseObject);
|
||||
delete this._objectPropertiesProvider;
|
||||
delete this._releaseObject;
|
||||
}
|
||||
if (this._localObjectActors) {
|
||||
delete this._localObjectActors;
|
||||
delete this._objectPropertiesProvider;
|
||||
}
|
||||
|
||||
this._rows = [];
|
||||
this._objectActors = [];
|
||||
},
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//// Helper for creating the panel.
|
||||
|
||||
/**
|
||||
* Creates a DOMNode and sets all the attributes of aAttributes on the created
|
||||
* element.
|
||||
*
|
||||
* @param nsIDOMDocument aDocument
|
||||
* Document to create the new DOMNode.
|
||||
* @param string aTag
|
||||
* Name of the tag for the DOMNode.
|
||||
* @param object aAttributes
|
||||
* Attributes set on the created DOMNode.
|
||||
* @returns nsIDOMNode
|
||||
*/
|
||||
function createElement(aDocument, aTag, aAttributes)
|
||||
{
|
||||
let node = aDocument.createElement(aTag);
|
||||
for (var attr in aAttributes) {
|
||||
node.setAttribute(attr, aAttributes[attr]);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new DOMNode and appends it to aParent.
|
||||
*
|
||||
* @param nsIDOMDocument aDocument
|
||||
* Document to create the new DOMNode.
|
||||
* @param nsIDOMNode aParent
|
||||
* A parent node to append the created element.
|
||||
* @param string aTag
|
||||
* Name of the tag for the DOMNode.
|
||||
* @param object aAttributes
|
||||
* Attributes set on the created DOMNode.
|
||||
* @returns nsIDOMNode
|
||||
*/
|
||||
function appendChild(aDocument, aParent, aTag, aAttributes)
|
||||
{
|
||||
let node = createElement(aDocument, aTag, aAttributes);
|
||||
aParent.appendChild(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//// PropertyPanel
|
||||
|
||||
/**
|
||||
* Creates a new PropertyPanel.
|
||||
*
|
||||
* @see PropertyTreeView
|
||||
* @param nsIDOMNode aParent
|
||||
* Parent node to append the created panel to.
|
||||
* @param string aTitle
|
||||
* Title for the panel.
|
||||
* @param string aObject
|
||||
* Object to display in the tree. For details about this object please
|
||||
* see the PropertyTreeView constructor in this file.
|
||||
* @param array of objects aButtons
|
||||
* Array with buttons to display at the bottom of the panel.
|
||||
*/
|
||||
this.PropertyPanel = function PropertyPanel(aParent, aTitle, aObject, aButtons)
|
||||
{
|
||||
let document = aParent.ownerDocument;
|
||||
|
||||
// Create the underlying panel
|
||||
this.panel = createElement(document, "panel", {
|
||||
label: aTitle,
|
||||
titlebar: "normal",
|
||||
noautofocus: "true",
|
||||
noautohide: "true",
|
||||
close: "true",
|
||||
});
|
||||
|
||||
// Create the tree.
|
||||
let tree = this.tree = createElement(document, "tree", {
|
||||
flex: 1,
|
||||
hidecolumnpicker: "true"
|
||||
});
|
||||
|
||||
let treecols = document.createElement("treecols");
|
||||
appendChild(document, treecols, "treecol", {
|
||||
primary: "true",
|
||||
flex: 1,
|
||||
hideheader: "true",
|
||||
ignoreincolumnpicker: "true"
|
||||
});
|
||||
tree.appendChild(treecols);
|
||||
|
||||
tree.appendChild(document.createElement("treechildren"));
|
||||
this.panel.appendChild(tree);
|
||||
|
||||
// Create the footer.
|
||||
let footer = createElement(document, "hbox", { align: "end" });
|
||||
appendChild(document, footer, "spacer", { flex: 1 });
|
||||
|
||||
// The footer can have butttons.
|
||||
let self = this;
|
||||
if (aButtons) {
|
||||
aButtons.forEach(function(button) {
|
||||
let buttonNode = appendChild(document, footer, "button", {
|
||||
label: button.label,
|
||||
accesskey: button.accesskey || "",
|
||||
class: button.class || "",
|
||||
});
|
||||
buttonNode.addEventListener("command", button.oncommand, false);
|
||||
});
|
||||
}
|
||||
|
||||
appendChild(document, footer, "resizer", { dir: "bottomend" });
|
||||
this.panel.appendChild(footer);
|
||||
|
||||
aParent.appendChild(this.panel);
|
||||
|
||||
// Create the treeView object.
|
||||
this.treeView = new PropertyTreeView();
|
||||
this.treeView.data = aObject;
|
||||
|
||||
// Set the treeView object on the tree view. This has to be done *after* the
|
||||
// panel is shown. This is because the tree binding must be attached first.
|
||||
this.panel.addEventListener("popupshown", function onPopupShow()
|
||||
{
|
||||
self.panel.removeEventListener("popupshown", onPopupShow, false);
|
||||
self.tree.view = self.treeView;
|
||||
}, false);
|
||||
|
||||
this.panel.addEventListener("popuphidden", function onPopupHide()
|
||||
{
|
||||
self.panel.removeEventListener("popuphidden", onPopupHide, false);
|
||||
self.destroy();
|
||||
}, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the PropertyPanel. This closes the panel and removes it from the
|
||||
* browser DOM.
|
||||
*/
|
||||
PropertyPanel.prototype.destroy = function PP_destroy()
|
||||
{
|
||||
this.treeView.data = null;
|
||||
this.panel.parentNode.removeChild(this.panel);
|
||||
this.treeView = null;
|
||||
this.panel = null;
|
||||
this.tree = null;
|
||||
}
|
||||
|
||||
|
||||
function gSequenceId()
|
||||
{
|
||||
return gSequenceId.n++;
|
||||
}
|
||||
gSequenceId.n = 0;
|
|
@ -23,7 +23,7 @@ let initialString = longString.substring(0,
|
|||
tempScope.DebuggerServer.LONG_STRING_INITIAL_LENGTH);
|
||||
|
||||
let inputValues = [
|
||||
// [showsPropertyPanel?, input value, expected output format,
|
||||
// [showsVariablesView?, input value, expected output format,
|
||||
// print() output, console API output, optional console API test]
|
||||
|
||||
// 0
|
||||
|
@ -132,7 +132,7 @@ function testNext() {
|
|||
function testGen() {
|
||||
let cpos = pos;
|
||||
|
||||
let showsPropertyPanel = inputValues[cpos][0];
|
||||
let showsVariablesView = inputValues[cpos][0];
|
||||
let inputValue = inputValues[cpos][1];
|
||||
let expectedOutput = inputValues[cpos][2];
|
||||
|
||||
|
@ -224,35 +224,35 @@ function testGen() {
|
|||
// Test click on output.
|
||||
let eventHandlerID = eventHandlers.length + 1;
|
||||
|
||||
let propertyPanelShown = function(aEvent, aView, aOptions) {
|
||||
let variablesViewShown = function(aEvent, aView, aOptions) {
|
||||
if (aOptions.label.indexOf(expectedOutput) == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
HUD.jsterm.off("variablesview-open", propertyPanelShown);
|
||||
HUD.jsterm.off("variablesview-open", variablesViewShown);
|
||||
|
||||
eventHandlers[eventHandlerID] = null;
|
||||
|
||||
ok(showsPropertyPanel,
|
||||
"the property panel shown for inputValues[" + cpos + "]");
|
||||
ok(showsVariablesView,
|
||||
"the variables view shown for inputValues[" + cpos + "]");
|
||||
|
||||
popupShown[cpos] = true;
|
||||
|
||||
if (showsPropertyPanel) {
|
||||
if (showsVariablesView) {
|
||||
executeSoon(subtestNext);
|
||||
}
|
||||
};
|
||||
|
||||
HUD.jsterm.on("variablesview-open", propertyPanelShown);
|
||||
HUD.jsterm.on("variablesview-open", variablesViewShown);
|
||||
|
||||
eventHandlers.push(propertyPanelShown);
|
||||
eventHandlers.push(variablesViewShown);
|
||||
|
||||
// Send the mousedown, mouseup and click events to check if the property
|
||||
// panel opens.
|
||||
// Send the mousedown, mouseup and click events to check if the variables
|
||||
// view opens.
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" }, messageBody, window);
|
||||
EventUtils.sendMouseEvent({ type: "click" }, messageBody, window);
|
||||
|
||||
if (showsPropertyPanel) {
|
||||
if (showsVariablesView) {
|
||||
yield; // wait for the panel to open if we need to.
|
||||
}
|
||||
|
||||
|
@ -276,7 +276,7 @@ function testEnd() {
|
|||
|
||||
for (let i = 0; i < inputValues.length; i++) {
|
||||
if (inputValues[i][0] && !popupShown[i]) {
|
||||
ok(false, "the property panel failed to show for inputValues[" + i + "]");
|
||||
ok(false, "the variables view failed to show for inputValues[" + i + "]");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,8 +27,6 @@ function consoleOpened(HUD) {
|
|||
let result = win.gen1.next();
|
||||
let completion = JSPropertyProvider(win, "gen1.");
|
||||
is(completion, null, "no matches for gen1");
|
||||
ok(!WCU.isObjectInspectable(win.gen1),
|
||||
"gen1 is not inspectable");
|
||||
|
||||
is(result+1, win.gen1.next(), "gen1.next() did not execute");
|
||||
|
||||
|
@ -36,8 +34,6 @@ function consoleOpened(HUD) {
|
|||
|
||||
completion = JSPropertyProvider(win, "gen2.");
|
||||
is(completion, null, "no matches for gen2");
|
||||
ok(!WCU.isObjectInspectable(win.gen2),
|
||||
"gen2 is not inspectable");
|
||||
|
||||
is((result/2+1)*2, win.gen2.next(),
|
||||
"gen2.next() did not execute");
|
||||
|
@ -48,8 +44,6 @@ function consoleOpened(HUD) {
|
|||
|
||||
completion = JSPropertyProvider(win, "iter1.");
|
||||
is(completion, null, "no matches for iter1");
|
||||
ok(!WCU.isObjectInspectable(win.iter1),
|
||||
"iter1 is not inspectable");
|
||||
|
||||
result = win.iter1.next();
|
||||
is(result[0], "baz", "iter1.next() [0] is correct");
|
||||
|
@ -57,14 +51,10 @@ function consoleOpened(HUD) {
|
|||
|
||||
completion = JSPropertyProvider(content, "iter2.");
|
||||
is(completion, null, "no matches for iter2");
|
||||
ok(!WCU.isObjectInspectable(win.iter2),
|
||||
"iter2 is not inspectable");
|
||||
|
||||
completion = JSPropertyProvider(win, "window.");
|
||||
ok(completion, "matches available for window");
|
||||
ok(completion.matches.length, "matches available for window (length)");
|
||||
ok(WCU.isObjectInspectable(win),
|
||||
"window is inspectable");
|
||||
|
||||
jsterm.clearOutput();
|
||||
|
||||
|
|
|
@ -34,13 +34,11 @@ function consoleOpened(aHud) {
|
|||
|
||||
ok(popup.isOpen, "popup is open");
|
||||
|
||||
// |props| values, and the following properties:
|
||||
// expected properties:
|
||||
// __defineGetter__ __defineSetter__ __lookupGetter__ __lookupSetter__
|
||||
// constructor hasOwnProperty isPrototypeOf propertyIsEnumerable
|
||||
// toLocaleString toSource toString unwatch valueOf watch.
|
||||
let props = WCU.inspectObject(content.wrappedJSObject.document.body,
|
||||
function() { });
|
||||
is(popup.itemCount, 14 + props.length, "popup.itemCount is correct");
|
||||
ok(popup.itemCount >= 14, "popup.itemCount is correct");
|
||||
|
||||
popup._panel.addEventListener("popuphidden", autocompletePopupHidden, false);
|
||||
|
||||
|
|
|
@ -1066,7 +1066,6 @@ xpicleanup@BIN_SUFFIX@
|
|||
modules/PluginProvider.jsm
|
||||
modules/PluralForm.jsm
|
||||
modules/PopupNotifications.jsm
|
||||
modules/PropertyPanel.jsm
|
||||
modules/reflect.jsm
|
||||
modules/Services.jsm
|
||||
modules/services-common/async.js
|
||||
|
|
|
@ -11,12 +11,6 @@
|
|||
# A good criteria is the language in which you'd find the best
|
||||
# documentation on web development on the web.
|
||||
|
||||
# LOCALIZATION NOTE (propertyPanel.updateButton.label): Used in the Property
|
||||
# Panel that is opened by the Scratchpad window when inspecting an object. This
|
||||
# is the Update button label.
|
||||
propertyPanel.updateButton.label=Update
|
||||
propertyPanel.updateButton.accesskey=U
|
||||
|
||||
# LOCALIZATION NOTE (export.fileOverwriteConfirmation): This is displayed when
|
||||
# the user attempts to save to an already existing file.
|
||||
export.fileOverwriteConfirmation=File exists. Overwrite?
|
||||
|
|
|
@ -34,28 +34,7 @@ update.button=Update
|
|||
update.accesskey=U
|
||||
cmd.commandkey=k
|
||||
webConsoleCmd.accesskey=W
|
||||
# LOCALIZATION NOTE FOR `jsPropertyTitle` AND `jsPropertyInspectTitle`:
|
||||
#
|
||||
# The "PropertyPanel" is used to display a JS object to the user.
|
||||
# If it is clear which object is being inspected (e.g., window, document object)
|
||||
# the title of the panel is based on the `jsPropertyInspectTitle` string.
|
||||
# If it isn't clear which object is being inspected, the `jsPropertyTitle` string
|
||||
# gets used. This can be the case when the user logs an object to the WebConsole
|
||||
# output using the console.log(aObjectToInspect) method.
|
||||
#
|
||||
# You can find a screenshot of the PropertyPanel here:
|
||||
# https://bug585030.bugzilla.mozilla.org/attachment.cgi?id=464034
|
||||
jsPropertyTitle=Object Inspector
|
||||
# LOCALIZATION NOTE (jsPropertyInspectTitle):
|
||||
#
|
||||
# The %S is replaced by the evaluated code the user clicked on in the console.
|
||||
#
|
||||
# Example: The user executed `window.document` in the WebConsole. The `document`
|
||||
# object is written to the output. If the user clicks on the `document` output
|
||||
# in the console, a PropertyPanel will show up. The title of the PropertyPanel
|
||||
# is set to `Inspect: window.document` because the clicked `document` object was
|
||||
# evaluated based on the `window.document` string.
|
||||
jsPropertyInspectTitle=Inspect: %S
|
||||
|
||||
# LOCALIZATION NOTE (timestampFormat): %1$02S = hours (24-hour clock),
|
||||
# %2$02S = minutes, %3$02S = seconds, %4$03S = milliseconds.
|
||||
timestampFormat=%02S:%02S:%02S.%03S
|
||||
|
|
|
@ -213,143 +213,6 @@ this.WebConsoleUtils = {
|
|||
return aSourceURL;
|
||||
},
|
||||
|
||||
/**
|
||||
* Format the jsterm execution result based on its type.
|
||||
*
|
||||
* @param mixed aResult
|
||||
* The evaluation result object you want displayed.
|
||||
* @return string
|
||||
* The string that can be displayed.
|
||||
*/
|
||||
formatResult: function WCU_formatResult(aResult)
|
||||
{
|
||||
let output = "";
|
||||
let type = this.getResultType(aResult);
|
||||
|
||||
switch (type) {
|
||||
case "string":
|
||||
output = this.formatResultString(aResult);
|
||||
break;
|
||||
case "boolean":
|
||||
case "date":
|
||||
case "error":
|
||||
case "number":
|
||||
case "regexp":
|
||||
try {
|
||||
output = aResult + "";
|
||||
}
|
||||
catch (ex) {
|
||||
output = ex;
|
||||
}
|
||||
break;
|
||||
case "null":
|
||||
case "undefined":
|
||||
output = type;
|
||||
break;
|
||||
default:
|
||||
try {
|
||||
if (aResult.toSource) {
|
||||
output = aResult.toSource();
|
||||
}
|
||||
if (!output || output == "({})") {
|
||||
output = aResult + "";
|
||||
}
|
||||
}
|
||||
catch (ex) {
|
||||
output = ex;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return output + "";
|
||||
},
|
||||
|
||||
/**
|
||||
* Format a string for output.
|
||||
*
|
||||
* @param string aString
|
||||
* The string you want to display.
|
||||
* @return string
|
||||
* The string that can be displayed.
|
||||
*/
|
||||
formatResultString: function WCU_formatResultString(aString)
|
||||
{
|
||||
function isControlCode(c) {
|
||||
// See http://en.wikipedia.org/wiki/C0_and_C1_control_codes
|
||||
// C0 is 0x00-0x1F, C1 is 0x80-0x9F (inclusive).
|
||||
// We also include DEL (U+007F) and NBSP (U+00A0), which are not strictly
|
||||
// in C1 but border it.
|
||||
return (c <= 0x1F) || (0x7F <= c && c <= 0xA0);
|
||||
}
|
||||
|
||||
function replaceFn(aMatch, aType, aHex) {
|
||||
// Leave control codes escaped, but unescape the rest of the characters.
|
||||
let c = parseInt(aHex, 16);
|
||||
return isControlCode(c) ? aMatch : String.fromCharCode(c);
|
||||
}
|
||||
|
||||
let output = uneval(aString).replace(/\\(x)([0-9a-fA-F]{2})/g, replaceFn)
|
||||
.replace(/\\(u)([0-9a-fA-F]{4})/g, replaceFn);
|
||||
|
||||
return output;
|
||||
},
|
||||
|
||||
/**
|
||||
* Determine if an object can be inspected or not.
|
||||
*
|
||||
* @param mixed aObject
|
||||
* The object you want to check if it can be inspected.
|
||||
* @return boolean
|
||||
* True if the object is inspectable or false otherwise.
|
||||
*/
|
||||
isObjectInspectable: function WCU_isObjectInspectable(aObject)
|
||||
{
|
||||
let isEnumerable = false;
|
||||
|
||||
// Skip Iterators and Generators.
|
||||
if (this.isIteratorOrGenerator(aObject)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
for (let p in aObject) {
|
||||
isEnumerable = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (ex) {
|
||||
// Proxy objects can lack an enumerable method.
|
||||
}
|
||||
|
||||
return isEnumerable && typeof(aObject) != "string";
|
||||
},
|
||||
|
||||
/**
|
||||
* Determine the type of the jsterm execution result.
|
||||
*
|
||||
* @param mixed aResult
|
||||
* The evaluation result object you want to check.
|
||||
* @return string
|
||||
* Constructor name or type: string, number, boolean, regexp, date,
|
||||
* function, object, null, undefined...
|
||||
*/
|
||||
getResultType: function WCU_getResultType(aResult)
|
||||
{
|
||||
let type = aResult === null ? "null" : typeof aResult;
|
||||
try {
|
||||
if (type == "object" && aResult.constructor && aResult.constructor.name) {
|
||||
type = aResult.constructor.name + "";
|
||||
}
|
||||
}
|
||||
catch (ex) {
|
||||
// Prevent potential exceptions in page-provided objects from taking down
|
||||
// the Web Console. If the constructor.name is a getter that throws, or
|
||||
// something else bad happens.
|
||||
}
|
||||
|
||||
return type.toLowerCase();
|
||||
},
|
||||
|
||||
/**
|
||||
* Tells if the given function is native or not.
|
||||
*
|
||||
|
@ -458,133 +321,6 @@ this.WebConsoleUtils = {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Inspect the properties of the given object. For each property a descriptor
|
||||
* object is created. The descriptor gives you information about the property
|
||||
* name, value, type, getter and setter. When the property value references
|
||||
* another object you get a wrapper that holds information about that object.
|
||||
*
|
||||
* @see this.inspectObjectProperty
|
||||
* @param object aObject
|
||||
* The object you want to inspect.
|
||||
* @param function aObjectWrapper
|
||||
* The function that creates wrappers for property values which
|
||||
* reference other objects. This function must take one argument, the
|
||||
* object to wrap, and it must return an object grip that gives
|
||||
* information about the referenced object.
|
||||
* @return array
|
||||
* An array of property descriptors.
|
||||
*/
|
||||
inspectObject: function WCU_inspectObject(aObject, aObjectWrapper)
|
||||
{
|
||||
let properties = [];
|
||||
let isDOMDocument = aObject instanceof Ci.nsIDOMDocument;
|
||||
let deprecated = ["width", "height", "inputEncoding"];
|
||||
|
||||
for (let name in aObject) {
|
||||
// See bug 632275: skip deprecated properties.
|
||||
if (isDOMDocument && deprecated.indexOf(name) > -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
properties.push(this.inspectObjectProperty(aObject, name, aObjectWrapper));
|
||||
}
|
||||
|
||||
return properties.sort(this.propertiesSort);
|
||||
},
|
||||
|
||||
/**
|
||||
* A helper method that creates a property descriptor for the provided object,
|
||||
* properly formatted for sending in a protocol response.
|
||||
*
|
||||
* The property value can reference other objects. Since actual objects cannot
|
||||
* be sent to the client, we need to send simple object grips - descriptors
|
||||
* for those objects. This is why you need to give an object wrapper function
|
||||
* that creates object grips.
|
||||
*
|
||||
* @param string aProperty
|
||||
* Property name for which we have the descriptor.
|
||||
* @param object aObject
|
||||
* The object that the descriptor is generated for.
|
||||
* @param function aObjectWrapper
|
||||
* This function is given the property value. Whatever the function
|
||||
* returns is used as the representation of the property value.
|
||||
* @return object
|
||||
* The property descriptor formatted for sending to the client.
|
||||
*/
|
||||
inspectObjectProperty:
|
||||
function WCU_inspectObjectProperty(aObject, aProperty, aObjectWrapper)
|
||||
{
|
||||
let descriptor = this.getPropertyDescriptor(aObject, aProperty) || {};
|
||||
|
||||
let result = { name: aProperty };
|
||||
result.configurable = descriptor.configurable;
|
||||
result.enumerable = descriptor.enumerable;
|
||||
result.writable = descriptor.writable;
|
||||
if (descriptor.value !== undefined) {
|
||||
result.value = this.createValueGrip(descriptor.value, aObjectWrapper);
|
||||
}
|
||||
else if (descriptor.get) {
|
||||
let gotValue = false;
|
||||
if (this.isNativeFunction(descriptor.get)) {
|
||||
try {
|
||||
result.value = this.createValueGrip(aObject[aProperty], aObjectWrapper);
|
||||
gotValue = true;
|
||||
} catch (e) {}
|
||||
}
|
||||
if (!gotValue) {
|
||||
result.get = this.createValueGrip(descriptor.get, aObjectWrapper);
|
||||
result.set = this.createValueGrip(descriptor.set, aObjectWrapper);
|
||||
}
|
||||
}
|
||||
|
||||
// There are cases with properties that have no value and no getter. For
|
||||
// example window.screen.width.
|
||||
if (result.value === undefined && result.get === undefined) {
|
||||
try {
|
||||
result.value = this.createValueGrip(aObject[aProperty], aObjectWrapper);
|
||||
}
|
||||
catch (ex) {
|
||||
// This can throw when security restrictions prevent us from reading
|
||||
// the value.
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* Make an object grip for the given object. An object grip of the simplest
|
||||
* form with minimal information about the given object is returned. This
|
||||
* method is usually combined with other functions that add further state
|
||||
* information and object ID such that, later, the client is able to retrieve
|
||||
* more information about the object being represented by this grip.
|
||||
*
|
||||
* @param object aObject
|
||||
* The object you want to create a grip for.
|
||||
* @return object
|
||||
* The object grip.
|
||||
*/
|
||||
getObjectGrip: function WCU_getObjectGrip(aObject)
|
||||
{
|
||||
let className = null;
|
||||
let type = typeof aObject;
|
||||
|
||||
let result = {
|
||||
"type": type,
|
||||
"className": this.getObjectClassName(aObject),
|
||||
"displayString": this.formatResult(aObject),
|
||||
"inspectable": this.isObjectInspectable(aObject),
|
||||
};
|
||||
|
||||
if (type == "function") {
|
||||
result.functionName = this.getFunctionName(aObject);
|
||||
result.functionArguments = this.getFunctionArguments(aObject);
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a grip for the given value. If the value is an object,
|
||||
* an object wrapper will be created.
|
||||
|
@ -686,45 +422,6 @@ this.WebConsoleUtils = {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Make a string representation for an object actor grip.
|
||||
*
|
||||
* @param object aGrip
|
||||
* The object grip received from the server.
|
||||
* @param boolean [aFormatString=false]
|
||||
* Optional boolean that tells if you want strings to be unevaled or
|
||||
* not.
|
||||
* @return string
|
||||
* The object grip converted to a string.
|
||||
*/
|
||||
objectActorGripToString: function WCU_objectActorGripToString(aGrip, aFormatString)
|
||||
{
|
||||
// Primitives like strings and numbers are not sent as objects.
|
||||
// But null and undefined are sent as objects with the type property
|
||||
// telling which type of value we have. We also have long strings which are
|
||||
// sent using the LongStringActor.
|
||||
|
||||
let type = typeof(aGrip);
|
||||
if (type == "string" ||
|
||||
(aGrip && type == "object" && aGrip.type == "longString")) {
|
||||
let str = type == "string" ? aGrip : aGrip.initial;
|
||||
if (aFormatString) {
|
||||
return this.formatResultString(str);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
if (aGrip && type == "object") {
|
||||
if (aGrip.displayString && typeof aGrip.displayString == "object" &&
|
||||
aGrip.displayString.type == "longString") {
|
||||
return aGrip.displayString.initial;
|
||||
}
|
||||
return aGrip.displayString || aGrip.className || aGrip.type || type;
|
||||
}
|
||||
|
||||
return aGrip + "";
|
||||
},
|
||||
|
||||
/**
|
||||
* Helper function to deduce the name of the provided function.
|
||||
*
|
||||
|
@ -759,28 +456,6 @@ this.WebConsoleUtils = {
|
|||
return name;
|
||||
},
|
||||
|
||||
/**
|
||||
* Helper function to deduce the arguments of the provided function.
|
||||
*
|
||||
* @param funtion aFunction
|
||||
* The function whose name will be returned.
|
||||
* @return array
|
||||
* Function arguments.
|
||||
*/
|
||||
getFunctionArguments: function WCF_getFunctionArguments(aFunction)
|
||||
{
|
||||
let args = [];
|
||||
try {
|
||||
let str = (aFunction.toString() || aFunction.toSource()) + "";
|
||||
let argsString = (str.match(REGEX_MATCH_FUNCTION_ARGS) || [])[1];
|
||||
if (argsString) {
|
||||
args = argsString.split(/\s*,\s*/);
|
||||
}
|
||||
}
|
||||
catch (ex) { }
|
||||
return args;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the object class name. For example, the |window| object has the Window
|
||||
* class name (based on [object Window]).
|
||||
|
@ -821,49 +496,6 @@ this.WebConsoleUtils = {
|
|||
return className;
|
||||
},
|
||||
|
||||
/**
|
||||
* Determine the string to display as a property value in the property panel.
|
||||
*
|
||||
* @param object aActor
|
||||
* Object actor grip.
|
||||
* @return string
|
||||
* Property value as suited for the property panel.
|
||||
*/
|
||||
getPropertyPanelValue: function WCU_getPropertyPanelValue(aActor)
|
||||
{
|
||||
if (aActor.get) {
|
||||
return "Getter";
|
||||
}
|
||||
|
||||
let val = aActor.value;
|
||||
if (typeof val == "string") {
|
||||
return this.formatResultString(val);
|
||||
}
|
||||
|
||||
if (typeof val != "object" || !val) {
|
||||
return val;
|
||||
}
|
||||
|
||||
if (val.type == "longString") {
|
||||
return this.formatResultString(val.initial) + "\u2026";
|
||||
}
|
||||
|
||||
if (val.type == "function" && val.functionName) {
|
||||
return "function " + val.functionName + "(" +
|
||||
val.functionArguments.join(", ") + ")";
|
||||
}
|
||||
if (val.type == "object" && val.className) {
|
||||
return val.className;
|
||||
}
|
||||
|
||||
if (val.displayString && typeof val.displayString == "object" &&
|
||||
val.displayString.type == "longString") {
|
||||
return val.displayString.initial;
|
||||
}
|
||||
|
||||
return val.displayString || val.type;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if the given value is a grip with an actor.
|
||||
*
|
||||
|
@ -1663,23 +1295,6 @@ this.JSTermHelpers = function JSTermHelpers(aOwner)
|
|||
aOwner.helperResult = { type: "help" };
|
||||
};
|
||||
|
||||
/**
|
||||
* Inspects the passed aObject. This is done by opening the PropertyPanel.
|
||||
*
|
||||
* @param object aObject
|
||||
* Object to inspect.
|
||||
*/
|
||||
aOwner.sandbox.inspect = function JSTH_inspect(aObject)
|
||||
{
|
||||
let dbgObj = aOwner.makeDebuggeeValue(aObject);
|
||||
let grip = aOwner.createValueGrip(dbgObj);
|
||||
aOwner.helperResult = {
|
||||
type: "inspectObject",
|
||||
input: aOwner.evalInput,
|
||||
object: grip,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Prints aObject to the output.
|
||||
*
|
||||
|
|
Загрузка…
Ссылка в новой задаче