зеркало из https://github.com/mozilla/gecko-dev.git
backout bugs 586514, 573102, 585195. a=bsmedberg
This commit is contained in:
Родитель
06e3d2ec5c
Коммит
1a5a502390
|
@ -63,17 +63,6 @@ XPCOMUtils.defineLazyServiceGetter(this, "sss",
|
|||
"@mozilla.org/content/style-sheet-service;1",
|
||||
"nsIStyleSheetService");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "PropertyPanel", function () {
|
||||
var obj = {};
|
||||
try {
|
||||
Cu.import("resource://gre/modules/PropertyPanel.jsm", obj);
|
||||
} catch (err) {
|
||||
Cu.reportError(err);
|
||||
}
|
||||
return obj.PropertyPanel;
|
||||
});
|
||||
|
||||
|
||||
function LogFactory(aMessagePrefix)
|
||||
{
|
||||
function log(aMessage) {
|
||||
|
@ -2490,38 +2479,25 @@ JSTerm.prototype = {
|
|||
{
|
||||
return this.context.get().QueryInterface(Ci.nsIDOMWindowInternal);
|
||||
},
|
||||
/**
|
||||
* Evaluates a string in the sandbox. The string is currently wrapped by a
|
||||
* with(window) { aString } construct, see bug 574033.
|
||||
*
|
||||
* @param string aString
|
||||
* String to evaluate in the sandbox.
|
||||
* @returns something
|
||||
* The result of the evaluation.
|
||||
*/
|
||||
evalInSandbox: function JST_evalInSandbox(aString)
|
||||
{
|
||||
let execStr = "with(window) {" + aString + "}";
|
||||
return Cu.evalInSandbox(execStr, this.sandbox, "default", "HUD Console", 1);
|
||||
},
|
||||
|
||||
|
||||
execute: function JST_execute(aExecuteString)
|
||||
{
|
||||
// attempt to execute the content of the inputNode
|
||||
aExecuteString = aExecuteString || this.inputNode.value;
|
||||
if (!aExecuteString) {
|
||||
var str = aExecuteString || this.inputNode.value;
|
||||
if (!str) {
|
||||
this.console.log("no value to execute");
|
||||
return;
|
||||
}
|
||||
|
||||
this.writeOutput(aExecuteString, true);
|
||||
this.writeOutput(str, true);
|
||||
|
||||
try {
|
||||
var result = this.evalInSandbox(aExecuteString);
|
||||
var execStr = "with(window) {" + str + "}";
|
||||
var result =
|
||||
Cu.evalInSandbox(execStr, this.sandbox, "default", "HUD Console", 1);
|
||||
|
||||
if (result || result === false) {
|
||||
this.writeOutputJS(aExecuteString, result);
|
||||
if (result || result === false || result === " ") {
|
||||
this.writeOutput(result, false);
|
||||
}
|
||||
else if (result === undefined) {
|
||||
this.writeOutput("undefined", false);
|
||||
|
@ -2531,122 +2507,17 @@ JSTerm.prototype = {
|
|||
}
|
||||
}
|
||||
catch (ex) {
|
||||
this.console.error(ex);
|
||||
if (ex) {
|
||||
this.console.error(ex);
|
||||
}
|
||||
}
|
||||
|
||||
this.history.push(aExecuteString);
|
||||
this.history.push(str);
|
||||
this.historyIndex++;
|
||||
this.historyPlaceHolder = this.history.length;
|
||||
this.inputNode.value = "";
|
||||
},
|
||||
|
||||
/**
|
||||
* Opens a new PropertyPanel. The panel has two buttons: "Update" reexecutes
|
||||
* the passed aEvalString and places the result inside of the tree. The other
|
||||
* button closes the panel.
|
||||
*
|
||||
* @param string aEvalString
|
||||
* String that was used to eval the aOutputObject. Used as title
|
||||
* and to update the tree content.
|
||||
* @param object aOutputObject
|
||||
* Object to display/inspect inside of the tree.
|
||||
* @param nsIDOMNode aAnchor
|
||||
* A node to popup the panel next to (using "after_pointer").
|
||||
* @returns object the created and opened propertyPanel.
|
||||
*/
|
||||
openPropertyPanel: function JST_openPropertyPanel(aEvalString, aOutputObject,
|
||||
aAnchor)
|
||||
{
|
||||
let self = this;
|
||||
let propPanel;
|
||||
// The property panel has two buttons:
|
||||
// 1. `Update`: reexecutes the string executed on the command line. The
|
||||
// result will be inspected by this panel.
|
||||
// 2. `Close`: destroys the panel.
|
||||
let buttons = [];
|
||||
|
||||
// If there is a evalString passed to this function, then add a `Update`
|
||||
// button to the panel so that the evalString can be reexecuted to update
|
||||
// the content of the panel.
|
||||
if (aEvalString !== null) {
|
||||
buttons.push({
|
||||
label: HUDService.getStr("update.button"),
|
||||
accesskey: HUDService.getStr("update.accesskey"),
|
||||
oncommand: function () {
|
||||
try {
|
||||
var result = self.evalInSandbox(aEvalString);
|
||||
|
||||
if (result !== undefined) {
|
||||
// TODO: This updates the value of the tree.
|
||||
// However, the states of opened nodes is not saved.
|
||||
// See bug 586246.
|
||||
propPanel.treeView.data = result;
|
||||
}
|
||||
}
|
||||
catch (ex) {
|
||||
self.console.error(ex);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
buttons.push({
|
||||
label: HUDService.getStr("close.button"),
|
||||
accesskey: HUDService.getStr("close.accesskey"),
|
||||
oncommand: function () {
|
||||
propPanel.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
let doc = self.parentNode.ownerDocument;
|
||||
let parent = doc.getElementById("mainPopupSet");
|
||||
let title = (aEvalString
|
||||
? HUDService.getFormatStr("jsPropertyInspectTitle", [aEvalString])
|
||||
: HUDService.getStr("jsPropertyTitle"));
|
||||
propPanel = new PropertyPanel(parent, doc, title, aOutputObject, buttons);
|
||||
|
||||
let panel = propPanel.panel;
|
||||
panel.openPopup(aAnchor, "after_pointer", 0, 0, false, false);
|
||||
panel.sizeTo(200, 400);
|
||||
return propPanel;
|
||||
},
|
||||
|
||||
/**
|
||||
* Writes a JS object to the JSTerm outputNode. If the user clicks on the
|
||||
* written object, openPropertyPanel is called to open up a panel to inspect
|
||||
* the object.
|
||||
*
|
||||
* @param string aEvalString
|
||||
* String that was evaluated to get the aOutputObject.
|
||||
* @param object aOutputObject
|
||||
* Object to be written to the outputNode.
|
||||
*/
|
||||
writeOutputJS: function JST_writeOutputJS(aEvalString, aOutputObject)
|
||||
{
|
||||
let lastGroupNode = HUDService.appendGroupIfNecessary(this.outputNode,
|
||||
Date.now());
|
||||
var node = this.elementFactory("div");
|
||||
node.setAttribute("class", "jsterm-output-line");
|
||||
|
||||
var self = this;
|
||||
var link = this.elementFactory("a");
|
||||
link.setAttribute("href", "javascript:");
|
||||
link.setAttribute("aria-haspopup", "true");
|
||||
link.onclick = function() {
|
||||
self.openPropertyPanel(aEvalString, aOutputObject, link);
|
||||
}
|
||||
|
||||
// TODO: format the aOutputObject and don't just use the
|
||||
// aOuputObject.toString() function: [object object] -> Object {prop, ...}
|
||||
// See bug 586249.
|
||||
let textNode = this.textFactory(aOutputObject);
|
||||
link.appendChild(textNode);
|
||||
node.appendChild(link);
|
||||
|
||||
lastGroupNode.appendChild(node);
|
||||
node.scrollIntoView(false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Writes a message to the HUD that originates from the interactive
|
||||
* JavaScript console.
|
||||
|
|
|
@ -46,7 +46,6 @@ include $(DEPTH)/config/autoconf.mk
|
|||
MODULE = hudservice
|
||||
|
||||
EXTRA_JS_MODULES = HUDService.jsm \
|
||||
PropertyPanel.jsm \
|
||||
$(NULL)
|
||||
|
||||
ifdef ENABLE_TESTS
|
||||
|
|
|
@ -1,504 +0,0 @@
|
|||
/* -*- Mode: js2; js2-basic-offset: 2; indent-tabs-mode: nil; -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is DevTools (HeadsUpDisplay) Console Code
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Rob Campbell <rcampbell@mozilla.com>
|
||||
* Julian Viereck <jviereck@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
var EXPORTED_SYMBOLS = ["PropertyPanel", "PropertyTreeView"];
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//// Helper for PropertyTreeView
|
||||
|
||||
const TYPE_OBJECT = 0, TYPE_FUNCTION = 1, TYPE_ARRAY = 2, TYPE_OTHER = 3;
|
||||
|
||||
/**
|
||||
* Figures out the type of aObject and the string to display in the tree.
|
||||
*
|
||||
* @param object aObject
|
||||
* The object to operate on.
|
||||
* @returns object
|
||||
* A object with the form:
|
||||
* {
|
||||
* type: TYPE_OBJECT || TYPE_FUNCTION || TYPE_ARRAY || TYPE_OTHER,
|
||||
* display: string for displaying the object in the tree
|
||||
* }
|
||||
*/
|
||||
function presentableValueFor(aObject)
|
||||
{
|
||||
if (aObject === null || aObject === undefined) {
|
||||
return {
|
||||
type: TYPE_OTHER,
|
||||
display: aObject === undefined ? "undefined" : "null"
|
||||
};
|
||||
}
|
||||
|
||||
let presentable;
|
||||
switch (aObject.constructor && aObject.constructor.name) {
|
||||
case "Array":
|
||||
return {
|
||||
type: TYPE_ARRAY,
|
||||
display: "Array"
|
||||
};
|
||||
|
||||
case "String":
|
||||
return {
|
||||
type: TYPE_OTHER,
|
||||
display: "\"" + aObject + "\""
|
||||
};
|
||||
|
||||
case "Date":
|
||||
case "RegExp":
|
||||
case "Number":
|
||||
case "Boolean":
|
||||
return {
|
||||
type: TYPE_OTHER,
|
||||
display: aObject
|
||||
};
|
||||
|
||||
case "Function":
|
||||
presentable = aObject.toString();
|
||||
return {
|
||||
type: TYPE_FUNCTION,
|
||||
display: presentable.substring(0, presentable.indexOf(')') + 1)
|
||||
};
|
||||
|
||||
default:
|
||||
presentable = aObject.toString();
|
||||
let m = /^\[object (\S+)\]/.exec(presentable);
|
||||
let display;
|
||||
|
||||
return {
|
||||
type: TYPE_OBJECT,
|
||||
display: m ? m[1] : "Object"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of property name value pairs for the tree.
|
||||
*
|
||||
* @param object aObject
|
||||
* The object to get properties for.
|
||||
* @returns array of object
|
||||
* Objects have the name, value, display, type, children properties.
|
||||
*/
|
||||
function namesAndValuesOf(aObject)
|
||||
{
|
||||
let pairs = [];
|
||||
let value, presentable;
|
||||
|
||||
for (var propName in aObject) {
|
||||
try {
|
||||
value = aObject[propName];
|
||||
presentable = presentableValueFor(value);
|
||||
}
|
||||
catch (ex) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let pair = {};
|
||||
pair.name = propName;
|
||||
pair.display = propName + ": " + presentable.display;
|
||||
pair.type = presentable.type;
|
||||
pair.value = value;
|
||||
|
||||
// Convert the pair.name to a number for later sorting.
|
||||
pair.nameNumber = parseFloat(pair.name)
|
||||
if (isNaN(pair.nameNumber)) {
|
||||
pair.nameNumber = false;
|
||||
}
|
||||
|
||||
pairs.push(pair);
|
||||
}
|
||||
|
||||
pairs.sort(function(a, b)
|
||||
{
|
||||
// Sort numbers.
|
||||
if (a.nameNumber !== false && b.nameNumber === false) {
|
||||
return -1;
|
||||
}
|
||||
else if (a.nameNumber === false && b.nameNumber !== false) {
|
||||
return 1;
|
||||
}
|
||||
else if (a.nameNumber !== false && b.nameNumber !== false) {
|
||||
return a.nameNumber - b.nameNumber;
|
||||
}
|
||||
// Sort string.
|
||||
else if (a.name < b.name) {
|
||||
return -1;
|
||||
}
|
||||
else if (a.name > b.name) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
|
||||
return pairs;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//// 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
|
||||
*/
|
||||
var PropertyTreeView = function() {
|
||||
this._rows = [];
|
||||
};
|
||||
|
||||
PropertyTreeView.prototype = {
|
||||
|
||||
/**
|
||||
* Stores the visible rows of the tree.
|
||||
*/
|
||||
_rows: null,
|
||||
|
||||
/**
|
||||
* Stores the nsITreeBoxObject for this tree.
|
||||
*/
|
||||
_treeBox: null,
|
||||
|
||||
/**
|
||||
* Use this setter to update the content of the tree.
|
||||
*
|
||||
* @param object aObject
|
||||
* The new object to be displayed in the tree.
|
||||
* @returns void
|
||||
*/
|
||||
set data(aObject) {
|
||||
let oldLen = this._rows.length;
|
||||
this._rows = this.getChildItems(aObject, true);
|
||||
if (this._treeBox) {
|
||||
this._treeBox.beginUpdateBatch();
|
||||
if (oldLen) {
|
||||
this._treeBox.rowCountChanged(0, -oldLen);
|
||||
}
|
||||
this._treeBox.rowCountChanged(0, this._rows.length);
|
||||
this._treeBox.endUpdateBatch();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Generates the child items for the treeView of a given aItem. If there is
|
||||
* already a children property on the aItem, this cached one is returned.
|
||||
*
|
||||
* @param object aItem
|
||||
* An item of the tree's elements to generate the children for.
|
||||
* @param boolean aRootElement
|
||||
* If set, aItem is handled as an JS object and not as an item
|
||||
* element of the tree.
|
||||
* @returns array of objects
|
||||
* Child items of aItem.
|
||||
*/
|
||||
getChildItems: function(aItem, aRootElement)
|
||||
{
|
||||
// If item.children is an array, then the children has already been
|
||||
// computed and can get returned directly.
|
||||
// Skip this checking if aRootElement is true. It could happen, that aItem
|
||||
// is passed as ({children:[1,2,3]}) which would be true, although these
|
||||
// "kind" of children has no value/type etc. data as needed to display in
|
||||
// the tree. As the passed ({children:[1,2,3]}) are instanceof
|
||||
// itsWindow.Array and not this modules's global Array
|
||||
// aItem.children instanceof Array can't be true, but for saftey the
|
||||
// !aRootElement is kept here.
|
||||
if (!aRootElement && aItem && aItem.children instanceof Array) {
|
||||
return aItem.children;
|
||||
}
|
||||
|
||||
let pairs;
|
||||
let newPairLevel;
|
||||
|
||||
if (!aRootElement) {
|
||||
newPairLevel = aItem.level + 1;
|
||||
aItem = aItem.value;
|
||||
}
|
||||
else {
|
||||
newPairLevel = 0;
|
||||
}
|
||||
|
||||
pairs = namesAndValuesOf(aItem);
|
||||
|
||||
for each (var pair in pairs) {
|
||||
pair.level = newPairLevel;
|
||||
pair.isOpened = false;
|
||||
pair.children = pair.type == TYPE_OBJECT || pair.type == TYPE_FUNCTION ||
|
||||
pair.type == TYPE_ARRAY;
|
||||
}
|
||||
|
||||
return pairs;
|
||||
},
|
||||
|
||||
/** nsITreeView interface implementation **/
|
||||
|
||||
selection: null,
|
||||
|
||||
get rowCount() { return this._rows.length; },
|
||||
setTree: function(treeBox) { this._treeBox = treeBox; },
|
||||
getCellText: function(idx, column) { return this._rows[idx].display; },
|
||||
getLevel: function(idx) { return this._rows[idx].level; },
|
||||
isContainer: function(idx) { return !!this._rows[idx].children; },
|
||||
isContainerOpen: function(idx) { return this._rows[idx].isOpened; },
|
||||
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)
|
||||
{
|
||||
var thisLevel = this.getLevel(idx);
|
||||
return this._rows.slice(after + 1).some(function (r) r.level == thisLevel);
|
||||
},
|
||||
|
||||
toggleOpenState: function(idx)
|
||||
{
|
||||
var item = this._rows[idx];
|
||||
if (!item.children) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._treeBox.beginUpdateBatch();
|
||||
if (item.isOpened) {
|
||||
item.isOpened = 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);
|
||||
}
|
||||
}
|
||||
else {
|
||||
item.isOpened = true;
|
||||
|
||||
var toInsert = this.getChildItems(item);
|
||||
item.children = toInsert;
|
||||
this._rows.splice.apply(this._rows, [idx + 1, 0].concat(toInsert));
|
||||
|
||||
this._treeBox.rowCountChanged(idx + 1, toInsert.length);
|
||||
}
|
||||
this._treeBox.invalidateRow(idx);
|
||||
this._treeBox.endUpdateBatch();
|
||||
},
|
||||
|
||||
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, column, prop) { },
|
||||
getCellProperties: function(idx, column, prop) { },
|
||||
getColumnProperties: function(column, element, prop) { },
|
||||
|
||||
setCellValue: function(row, col, value) { },
|
||||
setCellText: function(row, col, value) { },
|
||||
drop: function(index, orientation, dataTransfer) { },
|
||||
canDrop: function(index, orientation, dataTransfer) { return false; }
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//// 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.
|
||||
*
|
||||
* @param nsIDOMNode aParent
|
||||
* Parent node to append the created panel to.
|
||||
* @param nsIDOMDocument aDocument
|
||||
* Document to create the new nodes on.
|
||||
* @param string aTitle
|
||||
* Title for the panel.
|
||||
* @param string aObject
|
||||
* Object to display in the tree.
|
||||
* @param array of objects aButtons
|
||||
* Array with buttons to display at the bottom of the panel.
|
||||
*/
|
||||
function PropertyPanel(aParent, aDocument, aTitle, aObject, aButtons)
|
||||
{
|
||||
// Create the underlying panel
|
||||
this.panel = createElement(aDocument, "panel", {
|
||||
label: aTitle,
|
||||
titlebar: "normal",
|
||||
noautofocus: "true",
|
||||
noautohide: "true"
|
||||
});
|
||||
|
||||
// Create the tree.
|
||||
let tree = this.tree = createElement(aDocument, "tree", { flex: 1 });
|
||||
|
||||
let treecols = aDocument.createElement("treecols");
|
||||
appendChild(aDocument, treecols, "treecol", {
|
||||
primary: "true",
|
||||
flex: 1
|
||||
});
|
||||
tree.appendChild(treecols);
|
||||
|
||||
tree.appendChild(aDocument.createElement("treechildren"));
|
||||
this.panel.appendChild(tree);
|
||||
|
||||
// Create the footer.
|
||||
let footer = createElement(aDocument, "hbox", { align: "end" });
|
||||
appendChild(aDocument, footer, "spacer", { flex: 1 });
|
||||
|
||||
// The footer can have butttons.
|
||||
if (aButtons) {
|
||||
aButtons.forEach(function(button) {
|
||||
let buttonNode = appendChild(aDocument, footer, "button", {
|
||||
label: button.label,
|
||||
accesskey: button.accesskey || ""
|
||||
});
|
||||
button.dom = buttonNode;
|
||||
buttonNode.addEventListener("command", button.oncommand, false);
|
||||
});
|
||||
|
||||
this.panel.addEventListener("popuphidden", function onPopupHide(e)
|
||||
{
|
||||
event.target.removeEventListener("popuphidden", arguments.callee, false);
|
||||
aButtons.forEach(function(button) {
|
||||
button.dom.removeEventListener("command", button.oncommand, false);
|
||||
});
|
||||
}, false);
|
||||
}
|
||||
|
||||
appendChild(aDocument, 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the PropertyPanel. This closes the poped up panel and removes
|
||||
* it from the browser DOM.
|
||||
*
|
||||
* @returns void
|
||||
*/
|
||||
PropertyPanel.prototype.destroy = function PP_destroy()
|
||||
{
|
||||
this.panel.hidePopup();
|
||||
this.panel.parentNode.removeChild(this.panel);
|
||||
this.panel = null;
|
||||
this.treeView = null;
|
||||
this.tree = null;
|
||||
}
|
|
@ -385,7 +385,7 @@ function testJSInputAndOutputStyling() {
|
|||
"JS input node is of the CSS class 'jsterm-input-line'");
|
||||
|
||||
let jsOutputNode = outputChildren[2];
|
||||
isnot(jsOutputNode.childNodes[0].textContent.indexOf("4"), -1,
|
||||
isnot(jsOutputNode.childNodes[0].nodeValue.indexOf("4"), -1,
|
||||
"JS output node contains '4'");
|
||||
isnot(jsOutputNode.getAttribute("class").indexOf("jsterm-output-line"), -1,
|
||||
"JS output node is of the CSS class 'jsterm-output-line'");
|
||||
|
@ -624,52 +624,10 @@ function testExecutionScope()
|
|||
is(/location;/.test(outputChildren[1].childNodes[0].nodeValue), true,
|
||||
"'location;' written to output");
|
||||
|
||||
isnot(outputChildren[2].childNodes[0].textContent.indexOf(TEST_URI), -1,
|
||||
isnot(outputChildren[2].childNodes[0].nodeValue.indexOf(TEST_URI), -1,
|
||||
"command was executed in the window scope");
|
||||
}
|
||||
|
||||
function testPropertyPanel()
|
||||
{
|
||||
var HUD = HUDService.hudWeakReferences[hudId].get();
|
||||
var jsterm = HUD.jsterm;
|
||||
|
||||
let propPanel = jsterm.openPropertyPanel("Test", [
|
||||
1,
|
||||
/abc/,
|
||||
null,
|
||||
undefined,
|
||||
function test() {},
|
||||
{}
|
||||
]);
|
||||
is (propPanel.treeView.rowCount, 6, "six elements shown in propertyPanel");
|
||||
propPanel.destroy();
|
||||
|
||||
propPanel = jsterm.openPropertyPanel("Test2", {
|
||||
"0.02": 0,
|
||||
"0.01": 1,
|
||||
"02": 2,
|
||||
"1": 3,
|
||||
"11": 4,
|
||||
"1.2": 5,
|
||||
"1.1": 6,
|
||||
"foo": 7,
|
||||
"bar": 8
|
||||
});
|
||||
is (propPanel.treeView.rowCount, 9, "nine elements shown in propertyPanel");
|
||||
|
||||
let treeRows = propPanel.treeView._rows;
|
||||
is (treeRows[0].display, "0.01: 1", "1. element is okay");
|
||||
is (treeRows[1].display, "0.02: 0", "2. element is okay");
|
||||
is (treeRows[2].display, "1: 3", "3. element is okay");
|
||||
is (treeRows[3].display, "1.1: 6", "4. element is okay");
|
||||
is (treeRows[4].display, "1.2: 5", "5. element is okay");
|
||||
is (treeRows[5].display, "02: 2", "6. element is okay");
|
||||
is (treeRows[6].display, "11: 4", "7. element is okay");
|
||||
is (treeRows[7].display, "bar: 8", "8. element is okay");
|
||||
is (treeRows[8].display, "foo: 7", "9. element is okay");
|
||||
propPanel.destroy();
|
||||
}
|
||||
|
||||
function testIteration() {
|
||||
var id = "foo";
|
||||
var it = cs.displayStore(id);
|
||||
|
@ -920,7 +878,6 @@ function test() {
|
|||
testCompletion();
|
||||
testPropertyProvider();
|
||||
testJSInputExpand();
|
||||
testPropertyPanel();
|
||||
testNet();
|
||||
});
|
||||
}, false);
|
||||
|
|
|
@ -36,22 +36,5 @@ localConsole=Local Console
|
|||
btnClear=Clear Console
|
||||
tipClear=Clear the console output
|
||||
stringFilter=Filter
|
||||
close.button=Close
|
||||
close.accesskey=C
|
||||
update.button=Update
|
||||
update.accesskey=U
|
||||
# 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
|
||||
jsPropertyInspectTitle=Inspect: %S
|
||||
copyCmd.label=Copy
|
||||
copyCmd.accesskey=C
|
||||
|
|
|
@ -168,11 +168,3 @@
|
|||
padding: 1px 0px;
|
||||
-moz-box-align: center;
|
||||
}
|
||||
|
||||
.hud-console-filter-toolbar:-moz-system-metric(windows-default-theme) {
|
||||
background: -moz-linear-gradient(top, #f2f7fd 0, #e9f2fc 12px, #e3eefb 12px, #e3eefb 100%);
|
||||
border-top: 1px solid #fff;
|
||||
border-bottom: 2px solid ThreeDShadow;
|
||||
-moz-appearance: none !important;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче